func ECDSAPublicKeyToString(key ecdsa.PublicKey) string { x := key.X.Bytes() y := key.Y.Bytes() sha := util.SHA256(append(append([]byte{0x04}, x...), y...)) // should it be 0x04? ripe := ripemd160.New().Sum(sha) ripesha := util.SHA256(ripe) ripedoublesha := util.SHA256(ripesha) head := ripedoublesha[0:3] final := append(ripe, head...) i := new(big.Int) i.SetBytes(final) var b []byte return string(base58.EncodeBig(b, i)) }
func (service *NameService) NameReservation(r *http.Request, args *NameReservationArgs, reply *NameReservationReply) error { log := service.log.New("cmp", "api_name") key, err := service.srv.DB.GetKey(args.Alias) if err != nil { return err } if key == nil { return errors.New("can't find the key") } tx, random := transaction.NewNameReservation(args.Name) hash, err := service.srv.DB.GetPreviousEnvelopeHashForPublicKey(&key.PublicKey) if err != nil { log.Error("error while preparing transaction", "err", err) } txe := transaction.NewEnvelope(hash, tx) txe.Sign(key) reply.Id = hex.EncodeToString(txe.Hash()) reply.Random = hex.EncodeToString(random) // We save sha(random+name)=txhash to scraps to be able to find // the transaction hash by random and number during allocation service.srv.DB.PutScrap(util.SHA256(append(random, []byte(args.Name)...)), txe.Hash()) service.srv.Router.Pub(txe, "/transaction") return nil }
func NewNameReservation(name string) (*NameReservation, []byte) { buf := make([]byte, 4) rand.Read(buf) return &NameReservation{ Version: NAME_RESERVATION_VERSION, Hashed: util.SHA256(append([]byte(name), buf...))}, buf }
func NewNameReservation(name string, publicKey *ecdsa.PublicKey) (txn *NameReservation, random []byte) { buf := make([]byte, 4) rand.Read(buf) return &NameReservation{ Version: NAME_RESERVATION_VERSION, Hashed: util.SHA256(append([]byte(name), buf...)), PublicKey: []byte(keys.ECDSAPublicKeyToString(*publicKey))}, buf }
func isValidReservation(reservation *transaction.Envelope, alloc *transaction.Envelope) bool { allocT := alloc.Transaction.(*transaction.NameAllocation) switch reservation.Transaction.(type) { case *transaction.NameReservation: tx1 := reservation.Transaction.(*transaction.NameReservation) return bytes.Compare(util.SHA256(append([]byte(allocT.Name), allocT.Rand...)), tx1.Hashed) == 0 default: return false } }
func (*KeyAuth) Valid(b []byte) bool { var data [][]byte dec := gob.NewDecoder(bytes.NewBuffer(b)) dec.Decode(&data) publicKey, err := keys.DecodeECDSAPublicKey(data[0]) if err != nil { panic(err) // TODO: better error handling } r := new(big.Int) s := new(big.Int) r.SetBytes(data[1]) s.SetBytes(data[2]) return ecdsa.Verify(publicKey, util.SHA256(data[0]), r, s) }
func (a *KeyAuth) Marshal() []byte { key, err := keys.EncodeECDSAPublicKey(&a.key.PublicKey) if err != nil { panic(err) // TODO: better error handling } sigR, sigS, err := ecdsa.Sign(rand.Reader, a.key, util.SHA256(key)) if err != nil { panic(err) // TODO: better error handling } var buf bytes.Buffer enc := gob.NewEncoder(&buf) enc.Encode([][]byte{key, sigR.Bytes(), sigS.Bytes()}) return buf.Bytes() }
func Server(srv *context.T) { log := srv.Log.New("cmp", "dht") ch := srv.Router.Sub("/dht/join") tch := srv.Router.Sub("/transaction/mem") och := srv.Router.Sub("/git/object") keyAuth, err := newKeyAuth() if err != nil { log.Crit("can't generate node key", "err", err) os.Exit(1) } id, err := wendy.NodeIDFromBytes(util.SHA256(keyAuth.Marshal())) log = log.New("own_node", id) if err != nil { log15.Crit("error preparing node id", "err", err) os.Exit(0) } hostname := strings.Split(srv.Config.Network.Hostname, ":")[0] node := wendy.NewNode(id, "127.0.0.1", hostname, "localhost", srv.Config.Network.Port) cluster := wendy.NewCluster(node, keyAuth) cluster.SetLogLevel(wendy.LogLevelError) cluster.RegisterCallback(&GitchainApp{cluster: cluster, log: log.New(), srv: srv}) go cluster.Listen() defer cluster.Stop() log.Info("node started") for i := range srv.Config.Network.Join { log.Info("scheduling a connection", "addr", srv.Config.Network.Join[i]) srv.Router.Pub(srv.Config.Network.Join[i], "/dht/join") } loop: select { case addri := <-ch: if addr, ok := addri.(string); ok { log.Debug("received a request to join the cluster", "addr", addr) addr := strings.Split(addr, ":") port := 31000 if len(addr) == 2 { port, err = strconv.Atoi(addr[1]) if err != nil { log.Error("invalid port number", "addr", addr, "port", addr[1], "err", err) goto loop } } err = cluster.Join(addr[0], port) if err != nil { log.Error("can't join cluster", "addr", addr, "err", err) goto loop } } case txei := <-tch: if txe, ok := txei.(*transaction.Envelope); ok { log.Debug("received transaction", "txn", txe) if err = broadcast(cluster, txe, MSG_TRANSACTION); err != nil { log.Error("error broadcasting a transaction message", "txn", txe, "err", err) } else { log.Debug("broadcasted transaction", "txn", txe) } } case obji := <-och: if obj, ok := obji.(git.Object); ok { id, err := wendy.NodeIDFromBytes(util.SHA256(obj.Hash())) if err != nil { log15.Error("error preparing msg id for a git object", "obj", obj, "err", err) } else { msg := cluster.NewMessage(MSG_REGULAR|MSG_OBJECT, id, git.ObjectToBytes(obj)) if err = cluster.Send(msg); err != nil { log.Error("error sending git object", "obj", obj, "err", err) } } } } goto loop }
func (e *Envelope) Hash() types.Hash { return util.SHA256(append(append(e.Transaction.Hash(), e.PreviousEnvelopeHash...), e.NextPublicKey...)) }
func NameRegistrar(srv *context.T) { log := srv.Log.New("cmp", "name") ch := srv.Router.Sub("/block/last") loop: select { case blki := <-ch: if blk, ok := blki.(*block.Block); ok { processPendingAllocations(srv, log) for i := range blk.Transactions { tx0 := blk.Transactions[i] tx := tx0.Transaction switch tx.(type) { case *transaction.NameAllocation: log.Debug("processing name allocation transaction", "txn", tx0) tx1 := tx.(*transaction.NameAllocation) // 1. find the reservation // 1.1. check if it was done with this server and there's a reference // in scrap records reservation, err := srv.DB.GetScrap(util.SHA256(append(tx1.Rand, []byte(tx1.Name)...))) var reservationTx *transaction.Envelope if reservation == nil || err != nil { // 1.2 no scrap found, so try searching throughout database curBlock, err := srv.DB.GetLastBlock() if err != nil { log.Error("can't find last block during name allocation attempt") break } for curBlock != nil { for i := range curBlock.Transactions { if isValidReservation(curBlock.Transactions[i], tx0) { reservationTx = curBlock.Transactions[i] } } h := curBlock.PreviousBlockHash curBlock, err = srv.DB.GetBlock(h) if err != nil { log.Error("can't find block during name allocation attempt", "txn", h, "err", err) break } } } else { blk, err := srv.DB.GetTransactionBlock(reservation) if err != nil { log.Error("can't find block for name reservation", "txn", reservationTx, "err", err) break } for i := range blk.Transactions { if isValidReservation(blk.Transactions[i], tx0) { reservationTx = blk.Transactions[i] break } } } if reservationTx == nil { log.Error("can't find corresponding name reservation for allocation", "txn", tx0) break } // 2. verify its maturity confirmations, err := srv.DB.GetTransactionConfirmations(reservationTx.Hash()) if err != nil { log.Error("can't compute number of confirmations for reservation", "txn", reservationTx.Hash(), "err", err) break } if confirmations >= RESERVATION_CONFIRMATIONS_REQUIRED { // this reservation is confirmed srv.DB.PutRepository(repository.NewRepository(tx1.Name, repository.PENDING, tx0.Hash())) log.Info("created pending repository", "repo", tx1.Name, "alloc_txn", tx0.Hash()) } else { // this allocation is wasted as the distance is not long enough } default: // ignore all other transactions } } } } goto loop }