diff --git a/blockdag/dag.go b/blockdag/dag.go index 8ed3af8c4..6d7db857f 100644 --- a/blockdag/dag.go +++ b/blockdag/dag.go @@ -6,7 +6,6 @@ package blockdag import ( "fmt" - "github.com/kaspanet/kaspad/ecc" "math" "sort" "sync" @@ -16,6 +15,7 @@ import ( "github.com/kaspanet/kaspad/util/subnetworkid" + "github.com/kaspanet/go-secp256k1" "github.com/kaspanet/kaspad/dagconfig" "github.com/kaspanet/kaspad/database" "github.com/kaspanet/kaspad/txscript" @@ -595,7 +595,7 @@ func (dag *BlockDAG) connectBlock(node *blockNode, } // calcMultiset returns the multiset of the UTXO of the given block with the given transactions. -func (node *blockNode) calcMultiset(dag *BlockDAG, transactions []*util.Tx, acceptanceData MultiBlockTxsAcceptanceData, selectedParentUTXO, pastUTXO UTXOSet) (*ecc.Multiset, error) { +func (node *blockNode) calcMultiset(dag *BlockDAG, transactions []*util.Tx, acceptanceData MultiBlockTxsAcceptanceData, selectedParentUTXO, pastUTXO UTXOSet) (*secp256k1.MultiSet, error) { ms, err := node.pastUTXOMultiSet(dag, acceptanceData, selectedParentUTXO) if err != nil { return nil, err @@ -615,10 +615,10 @@ func (node *blockNode) calcMultiset(dag *BlockDAG, transactions []*util.Tx, acce // parent, replaces all the selected parent outputs' blue score with // the block blue score and returns the result. func (node *blockNode) acceptedSelectedParentMultiset(dag *BlockDAG, - acceptanceData MultiBlockTxsAcceptanceData) (*ecc.Multiset, error) { + acceptanceData MultiBlockTxsAcceptanceData) (*secp256k1.MultiSet, error) { if node.isGenesis() { - return ecc.NewMultiset(ecc.S256()), nil + return secp256k1.NewMultiset(), nil } ms, err := dag.multisetStore.multisetByBlockNode(node.selectedParent) @@ -656,7 +656,7 @@ func (node *blockNode) acceptedSelectedParentMultiset(dag *BlockDAG, return ms, nil } -func (node *blockNode) pastUTXOMultiSet(dag *BlockDAG, acceptanceData MultiBlockTxsAcceptanceData, selectedParentUTXO UTXOSet) (*ecc.Multiset, error) { +func (node *blockNode) pastUTXOMultiSet(dag *BlockDAG, acceptanceData MultiBlockTxsAcceptanceData, selectedParentUTXO UTXOSet) (*secp256k1.MultiSet, error) { ms, err := node.acceptedSelectedParentMultiset(dag, acceptanceData) if err != nil { return nil, err @@ -684,7 +684,7 @@ func (node *blockNode) pastUTXOMultiSet(dag *BlockDAG, acceptanceData MultiBlock return ms, nil } -func addTxToMultiset(ms *ecc.Multiset, tx *wire.MsgTx, pastUTXO UTXOSet, blockBlueScore uint64) (*ecc.Multiset, error) { +func addTxToMultiset(ms *secp256k1.MultiSet, tx *wire.MsgTx, pastUTXO UTXOSet, blockBlueScore uint64) (*secp256k1.MultiSet, error) { isCoinbase := tx.IsCoinBase() if !isCoinbase { for _, txIn := range tx.TxIn { @@ -995,7 +995,7 @@ func (dag *BlockDAG) TxsAcceptedByBlockHash(blockHash *daghash.Hash) (MultiBlock // It returns the diff in the virtual block's UTXO set. // // This function MUST be called with the DAG state lock held (for writes). -func (dag *BlockDAG) applyDAGChanges(node *blockNode, newBlockUTXO UTXOSet, newBlockMultiset *ecc.Multiset, selectedParentAnticone []*blockNode) ( +func (dag *BlockDAG) applyDAGChanges(node *blockNode, newBlockUTXO UTXOSet, newBlockMultiset *secp256k1.MultiSet, selectedParentAnticone []*blockNode) ( virtualUTXODiff *UTXODiff, virtualTxsAcceptanceData MultiBlockTxsAcceptanceData, chainUpdates *chainUpdates, err error) { @@ -1069,7 +1069,7 @@ func (node *blockNode) diffFromTxs(pastUTXO UTXOSet, transactions []*util.Tx) (* // to save extra traversals it returns the transactions acceptance data, the compactFeeData // for the new block and its multiset. func (node *blockNode) verifyAndBuildUTXO(dag *BlockDAG, transactions []*util.Tx, fastAdd bool) ( - newBlockUTXO UTXOSet, txsAcceptanceData MultiBlockTxsAcceptanceData, newBlockFeeData compactFeeData, multiset *ecc.Multiset, err error) { + newBlockUTXO UTXOSet, txsAcceptanceData MultiBlockTxsAcceptanceData, newBlockFeeData compactFeeData, multiset *secp256k1.MultiSet, err error) { pastUTXO, selectedParentUTXO, txsAcceptanceData, err := dag.pastUTXO(node) if err != nil { @@ -1100,7 +1100,7 @@ func (node *blockNode) verifyAndBuildUTXO(dag *BlockDAG, transactions []*util.Tx return nil, nil, nil, nil, err } - calculatedMultisetHash := multiset.Hash() + calculatedMultisetHash := daghash.Hash(*multiset.Finalize()) if !calculatedMultisetHash.IsEqual(node.utxoCommitment) { str := fmt.Sprintf("block %s UTXO commitment is invalid - block "+ "header indicates %s, but calculated value is %s", node.hash, diff --git a/blockdag/mining.go b/blockdag/mining.go index 714164779..9b7ef095d 100644 --- a/blockdag/mining.go +++ b/blockdag/mining.go @@ -3,9 +3,10 @@ package blockdag import ( "bytes" "encoding/binary" - "github.com/kaspanet/kaspad/ecc" + "github.com/kaspanet/go-secp256k1" "github.com/kaspanet/kaspad/txscript" "github.com/kaspanet/kaspad/util" + "github.com/kaspanet/kaspad/util/daghash" "github.com/kaspanet/kaspad/wire" "time" ) @@ -47,7 +48,7 @@ func (dag *BlockDAG) BlockForMining(transactions []*util.Tx) (*wire.MsgBlock, er ParentHashes: dag.TipHashes(), HashMerkleRoot: hashMerkleTree.Root(), AcceptedIDMerkleRoot: acceptedIDMerkleRoot, - UTXOCommitment: multiset.Hash(), + UTXOCommitment: (*daghash.Hash)(multiset.Finalize()), Timestamp: blockTimestamp, Bits: requiredDifficulty, } @@ -59,7 +60,7 @@ func (dag *BlockDAG) BlockForMining(transactions []*util.Tx) (*wire.MsgBlock, er // built on top of the current tips, with the given transactions. // // This function MUST be called with the DAG state lock held (for reads). -func (dag *BlockDAG) NextBlockMultiset(transactions []*util.Tx) (*ecc.Multiset, error) { +func (dag *BlockDAG) NextBlockMultiset(transactions []*util.Tx) (*secp256k1.MultiSet, error) { pastUTXO, selectedParentUTXO, txsAcceptanceData, err := dag.pastUTXO(&dag.virtual.blockNode) if err != nil { return nil, err diff --git a/blockdag/multisetio.go b/blockdag/multisetio.go index e37d42d33..92810a830 100644 --- a/blockdag/multisetio.go +++ b/blockdag/multisetio.go @@ -2,27 +2,16 @@ package blockdag import ( "encoding/binary" - "github.com/kaspanet/kaspad/ecc" + "github.com/kaspanet/go-secp256k1" "io" - "math/big" ) const multisetPointSize = 32 -// serializeMultiset serializes an ECMH multiset. The serialization -// uses the following format: . -func serializeMultiset(w io.Writer, ms *ecc.Multiset) error { - x, y := ms.Point() - xBytes := make([]byte, multisetPointSize) - copy(xBytes, x.Bytes()) - yBytes := make([]byte, multisetPointSize) - copy(yBytes, y.Bytes()) - - err := binary.Write(w, byteOrder, xBytes) - if err != nil { - return err - } - err = binary.Write(w, byteOrder, yBytes) +// serializeMultiset serializes an ECMH multiset. +func serializeMultiset(w io.Writer, ms *secp256k1.MultiSet) error { + serialized := ms.Serialize() + err := binary.Write(w, byteOrder, serialized) if err != nil { return err } @@ -30,20 +19,11 @@ func serializeMultiset(w io.Writer, ms *ecc.Multiset) error { } // deserializeMultiset deserializes an EMCH multiset. -// See serializeMultiset for more details. -func deserializeMultiset(r io.Reader) (*ecc.Multiset, error) { - xBytes := make([]byte, multisetPointSize) - yBytes := make([]byte, multisetPointSize) - err := binary.Read(r, byteOrder, xBytes) +func deserializeMultiset(r io.Reader) (*secp256k1.MultiSet, error) { + serialized := &secp256k1.SerializedMultiSet{} + err := binary.Read(r, byteOrder, serialized[:]) if err != nil { return nil, err } - err = binary.Read(r, byteOrder, yBytes) - if err != nil { - return nil, err - } - var x, y big.Int - x.SetBytes(xBytes) - y.SetBytes(yBytes) - return ecc.NewMultisetFromPoint(ecc.S256(), &x, &y), nil + return secp256k1.DeserializeMultiSet(serialized) } diff --git a/blockdag/multisetstore.go b/blockdag/multisetstore.go index 93f0bb10c..d9a812176 100644 --- a/blockdag/multisetstore.go +++ b/blockdag/multisetstore.go @@ -2,8 +2,8 @@ package blockdag import ( "bytes" + "github.com/kaspanet/go-secp256k1" "github.com/kaspanet/kaspad/database" - "github.com/kaspanet/kaspad/ecc" "github.com/kaspanet/kaspad/util/daghash" "github.com/kaspanet/kaspad/util/locks" "github.com/pkg/errors" @@ -12,7 +12,7 @@ import ( type multisetStore struct { dag *BlockDAG new map[daghash.Hash]struct{} - loaded map[daghash.Hash]*ecc.Multiset + loaded map[daghash.Hash]secp256k1.MultiSet mtx *locks.PriorityMutex } @@ -20,12 +20,12 @@ func newMultisetStore(dag *BlockDAG) *multisetStore { return &multisetStore{ dag: dag, new: make(map[daghash.Hash]struct{}), - loaded: make(map[daghash.Hash]*ecc.Multiset), + loaded: make(map[daghash.Hash]secp256k1.MultiSet), } } -func (store *multisetStore) setMultiset(node *blockNode, ms *ecc.Multiset) { - store.loaded[*node.hash] = ms +func (store *multisetStore) setMultiset(node *blockNode, ms *secp256k1.MultiSet) { + store.loaded[*node.hash] = *ms store.addToNewBlocks(node.hash) } @@ -37,7 +37,7 @@ func multisetNotFoundError(blockHash *daghash.Hash) error { return errors.Errorf("Couldn't find multiset data for block %s", blockHash) } -func (store *multisetStore) multisetByBlockNode(node *blockNode) (*ecc.Multiset, error) { +func (store *multisetStore) multisetByBlockNode(node *blockNode) (*secp256k1.MultiSet, error) { ms, exists := store.multisetByBlockHash(node.hash) if !exists { return nil, multisetNotFoundError(node.hash) @@ -45,9 +45,9 @@ func (store *multisetStore) multisetByBlockNode(node *blockNode) (*ecc.Multiset, return ms, nil } -func (store *multisetStore) multisetByBlockHash(hash *daghash.Hash) (*ecc.Multiset, bool) { +func (store *multisetStore) multisetByBlockHash(hash *daghash.Hash) (*secp256k1.MultiSet, bool) { ms, ok := store.loaded[*hash] - return ms, ok + return &ms, ok } // flushToDB writes all new multiset data to the database. @@ -66,7 +66,7 @@ func (store *multisetStore) flushToDB(dbTx database.Tx) error { return multisetNotFoundError(&hash) } - err := serializeMultiset(w, ms) + err := serializeMultiset(w, &ms) if err != nil { return err } @@ -97,7 +97,7 @@ func (store *multisetStore) init(dbTx database.Tx) error { return err } - store.loaded[*hash] = ms + store.loaded[*hash] = *ms } return nil } diff --git a/blockdag/utxo_ecmh.go b/blockdag/utxo_ecmh.go index c2545f073..12ddd9f50 100644 --- a/blockdag/utxo_ecmh.go +++ b/blockdag/utxo_ecmh.go @@ -2,24 +2,26 @@ package blockdag import ( "bytes" - "github.com/kaspanet/kaspad/ecc" + "github.com/kaspanet/go-secp256k1" "github.com/kaspanet/kaspad/wire" ) -func addUTXOToMultiset(ms *ecc.Multiset, entry *UTXOEntry, outpoint *wire.Outpoint) (*ecc.Multiset, error) { +func addUTXOToMultiset(ms *secp256k1.MultiSet, entry *UTXOEntry, outpoint *wire.Outpoint) (*secp256k1.MultiSet, error) { w := &bytes.Buffer{} err := serializeUTXO(w, entry, outpoint) if err != nil { return nil, err } - return ms.Add(w.Bytes()), nil + ms.Add(w.Bytes()) + return ms, nil } -func removeUTXOFromMultiset(ms *ecc.Multiset, entry *UTXOEntry, outpoint *wire.Outpoint) (*ecc.Multiset, error) { +func removeUTXOFromMultiset(ms *secp256k1.MultiSet, entry *UTXOEntry, outpoint *wire.Outpoint) (*secp256k1.MultiSet, error) { w := &bytes.Buffer{} err := serializeUTXO(w, entry, outpoint) if err != nil { return nil, err } - return ms.Remove(w.Bytes()), nil + ms.Remove(w.Bytes()) + return ms, nil } diff --git a/blockdag/utxoset.go b/blockdag/utxoset.go index 9511f9610..f56f6801d 100644 --- a/blockdag/utxoset.go +++ b/blockdag/utxoset.go @@ -8,7 +8,7 @@ import ( "github.com/pkg/errors" - "github.com/kaspanet/kaspad/ecc" + "github.com/kaspanet/go-secp256k1" "github.com/kaspanet/kaspad/wire" ) @@ -485,7 +485,7 @@ func NewFullUTXOSet() *FullUTXOSet { // newFullUTXOSetFromUTXOCollection converts a utxoCollection to a FullUTXOSet func newFullUTXOSetFromUTXOCollection(collection utxoCollection) (*FullUTXOSet, error) { var err error - multiset := ecc.NewMultiset(ecc.S256()) + multiset := secp256k1.NewMultiset() for outpoint, utxoEntry := range collection { multiset, err = addUTXOToMultiset(multiset, utxoEntry, &outpoint) if err != nil { diff --git a/cmd/txsigner/txsigner.go b/cmd/txsigner/txsigner.go index 0606cdd9d..9c1f4dd11 100644 --- a/cmd/txsigner/txsigner.go +++ b/cmd/txsigner/txsigner.go @@ -4,7 +4,7 @@ import ( "bytes" "encoding/hex" "fmt" - "github.com/kaspanet/kaspad/ecc" + "github.com/kaspanet/go-secp256k1" "github.com/kaspanet/kaspad/txscript" "github.com/kaspanet/kaspad/util" "github.com/kaspanet/kaspad/wire" @@ -28,7 +28,11 @@ func main() { printErrorAndExit(err, "Failed to decode transaction") } - scriptPubKey, err := createScriptPubKey(privateKey.PubKey()) + pubkey, err := privateKey.SchnorrPublicKey() + if err != nil { + printErrorAndExit(err, "Failed to generate a public key") + } + scriptPubKey, err := createScriptPubKey(pubkey) if err != nil { printErrorAndExit(err, "Failed to create scriptPubKey") } @@ -46,10 +50,12 @@ func main() { fmt.Printf("Signed Transaction (hex): %s\n\n", serializedTransaction) } -func parsePrivateKey(privateKeyHex string) (*ecc.PrivateKey, error) { +func parsePrivateKey(privateKeyHex string) (*secp256k1.PrivateKey, error) { privateKeyBytes, err := hex.DecodeString(privateKeyHex) - privateKey, _ := ecc.PrivKeyFromBytes(ecc.S256(), privateKeyBytes) - return privateKey, err + if err != nil { + return nil, errors.Errorf("'%s' isn't a valid hex. err: '%s' ", privateKeyHex, err) + } + return secp256k1.DeserializePrivateKeyFromSlice(privateKeyBytes) } func parseTransaction(transactionHex string) (*wire.MsgTx, error) { @@ -62,8 +68,12 @@ func parseTransaction(transactionHex string) (*wire.MsgTx, error) { return &transaction, err } -func createScriptPubKey(publicKey *ecc.PublicKey) ([]byte, error) { - p2pkhAddress, err := util.NewAddressPubKeyHashFromPublicKey(publicKey.SerializeCompressed(), ActiveConfig().NetParams().Prefix) +func createScriptPubKey(publicKey *secp256k1.SchnorrPublicKey) ([]byte, error) { + serializedKey, err := publicKey.SerializeCompressed() + if err != nil { + return nil, err + } + p2pkhAddress, err := util.NewAddressPubKeyHashFromPublicKey(serializedKey, ActiveConfig().NetParams().Prefix) if err != nil { return nil, err } @@ -71,7 +81,7 @@ func createScriptPubKey(publicKey *ecc.PublicKey) ([]byte, error) { return scriptPubKey, err } -func signTransaction(transaction *wire.MsgTx, privateKey *ecc.PrivateKey, scriptPubKey []byte) error { +func signTransaction(transaction *wire.MsgTx, privateKey *secp256k1.PrivateKey, scriptPubKey []byte) error { for i, transactionInput := range transaction.TxIn { signatureScript, err := txscript.SignatureScript(transaction, i, scriptPubKey, txscript.SigHashAll, privateKey, true) if err != nil { diff --git a/go.mod b/go.mod index 0167db470..da1e37295 100644 --- a/go.mod +++ b/go.mod @@ -7,15 +7,15 @@ require ( github.com/btcsuite/websocket v0.0.0-20150119174127-31079b680792 github.com/btcsuite/winsvc v1.0.0 github.com/davecgh/go-spew v1.1.1 - github.com/golang/groupcache v0.0.0-20191002201903-404acd9df4cc github.com/golang/protobuf v1.3.2 // indirect + github.com/golang/snappy v0.0.1 // indirect github.com/jessevdk/go-flags v1.4.0 github.com/jrick/logrotate v1.0.0 + github.com/kaspanet/go-secp256k1 v0.0.0-20200326113007-add33b62838a github.com/kr/pretty v0.1.0 // indirect github.com/pkg/errors v0.9.1 github.com/syndtr/goleveldb v1.0.0 - golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550 - golang.org/x/net v0.0.0-20190620200207-3b0461eec859 // indirect + golang.org/x/crypto v0.0.0-20200323165209-0ec3e9974c59 golang.org/x/sys v0.0.0-20190426135247-a129542de9ae // indirect golang.org/x/text v0.3.2 // indirect gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127 // indirect diff --git a/go.sum b/go.sum index fc3e0c0dc..700a98e2b 100644 --- a/go.sum +++ b/go.sum @@ -8,19 +8,21 @@ github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/fsnotify/fsnotify v1.4.7 h1:IXs+QLmnXW2CcXuY+8Mzv/fWEsPGWxqefPtCP5CnV9I= github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo= -github.com/golang/groupcache v0.0.0-20191002201903-404acd9df4cc h1:55rEp52jU6bkyslZ1+C/7NGfpQsEc6pxGLAGDOctqbw= -github.com/golang/groupcache v0.0.0-20191002201903-404acd9df4cc/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= github.com/golang/protobuf v1.3.2 h1:6nsPYzhq5kReh6QImI3k5qWzO4PEbvbIW2cwSfR/6xs= github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= github.com/golang/snappy v0.0.0-20180518054509-2e65f85255db h1:woRePGFeVFfLKN/pOkfl+p/TAqKOfFu+7KPlMVpok/w= github.com/golang/snappy v0.0.0-20180518054509-2e65f85255db/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= +github.com/golang/snappy v0.0.1 h1:Qgr9rKW7uDUkrbSmQeiDsGa8SjGyCOGtuasMWwvp2P4= +github.com/golang/snappy v0.0.1/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= github.com/hpcloud/tail v1.0.0 h1:nfCOvKYfkgYP8hkirhJocXT2+zOD8yUNjXaWfTlyFKI= github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU= github.com/jessevdk/go-flags v1.4.0 h1:4IU2WS7AumrZ/40jfhf4QVDMsQwqA7VEHozFRrGARJA= github.com/jessevdk/go-flags v1.4.0/go.mod h1:4FA24M0QyGHXBuZZK/XkWh8h0e1EYbRYJSGM75WSRxI= github.com/jrick/logrotate v1.0.0 h1:lQ1bL/n9mBNeIXoTUoYRlK4dHuNJVofX9oWqBtPnSzI= github.com/jrick/logrotate v1.0.0/go.mod h1:LNinyqDIJnpAur+b8yyulnQw/wDuN1+BYKlTRt3OuAQ= +github.com/kaspanet/go-secp256k1 v0.0.0-20200326113007-add33b62838a h1:/7JHxqxFvfuUr+u8k8kZ4R8Gjyb0TZnvYXrMyGjEAN0= +github.com/kaspanet/go-secp256k1 v0.0.0-20200326113007-add33b62838a/go.mod h1:W9OcWBKzH8P/PN2WAUn9k2YmZG/Uc660WAL1NTS3G3M= github.com/kr/pretty v0.1.0 h1:L/CwN0zerZDmRFUapSPitk6f+Q3+0za1rQkzVuMiMFI= github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= @@ -39,11 +41,15 @@ github.com/syndtr/goleveldb v1.0.0/go.mod h1:ZVVdQEZoIme9iO1Ch2Jdy24qqXrMMOU6lpP golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550 h1:ObdrDkeb4kJdCP557AjRjq69pTHfNouLtWZG7j9rPN8= golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= +golang.org/x/crypto v0.0.0-20200323165209-0ec3e9974c59 h1:3zb4D3T4G8jdExgVU/95+vQXfpEPiMdCaZgmGVxjNHM= +golang.org/x/crypto v0.0.0-20200323165209-0ec3e9974c59/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= +golang.org/x/mod v0.1.1-0.20191105210325-c90efee705ee/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg= golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= golang.org/x/net v0.0.0-20190620200207-3b0461eec859 h1:R/3boaszxrf1GEUWTVDzSKVwLmSJpwZ1yqXm8j0v2QI= golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= @@ -53,6 +59,8 @@ golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.2 h1:tW2bmiBqwgJj/UpqtC8EpXEZVYOwU0yG4iWbprSVAcs= golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk= golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= +golang.org/x/tools v0.0.0-20200228224639-71482053b885/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127 h1:qIbj1fsPNlZgppZ+VLlY7N33q108Sa+fhmuc+sWQYwY= gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= diff --git a/mining/test_utils.go b/mining/test_utils.go index 359b559c2..132c38587 100644 --- a/mining/test_utils.go +++ b/mining/test_utils.go @@ -109,7 +109,7 @@ func PrepareBlockForTest(dag *blockdag.BlockDAG, params *dagconfig.Params, paren return nil, err } - template.Block.Header.UTXOCommitment = ms.Hash() + template.Block.Header.UTXOCommitment = (*daghash.Hash)(ms.Finalize()) } return template.Block, nil } diff --git a/txscript/opcode.go b/txscript/opcode.go index 32a4afd98..3821aade2 100644 --- a/txscript/opcode.go +++ b/txscript/opcode.go @@ -10,11 +10,11 @@ import ( "crypto/sha256" "encoding/binary" "fmt" + "github.com/kaspanet/go-secp256k1" "hash" "golang.org/x/crypto/ripemd160" - "github.com/kaspanet/kaspad/ecc" "github.com/kaspanet/kaspad/util/daghash" "github.com/kaspanet/kaspad/wire" ) @@ -2033,36 +2033,34 @@ func opcodeCheckSig(op *parsedOpcode, vm *Engine) error { script := vm.currentScript() // Generate the signature hash based on the signature hash type. - hash, err := calcSignatureHash(script, hashType, &vm.tx, vm.txIdx) + sigHash, err := calcSignatureHash(script, hashType, &vm.tx, vm.txIdx) if err != nil { vm.dstack.PushBool(false) return nil } - pubKey, err := ecc.ParsePubKey(pkBytes, ecc.S256()) + pubKey, err := secp256k1.DeserializeSchnorrPubKey(pkBytes) if err != nil { vm.dstack.PushBool(false) return nil } - - signature, err := ecc.ParseSignature(sigBytes) + signature, err := secp256k1.DeserializeSchnorrSignatureFromSlice(sigBytes) if err != nil { vm.dstack.PushBool(false) return nil } var valid bool + secpHash := secp256k1.Hash(*sigHash) if vm.sigCache != nil { - var sigHash daghash.Hash - copy(sigHash[:], hash) - valid = vm.sigCache.Exists(sigHash, signature, pubKey) - if !valid && signature.Verify(hash, pubKey) { - vm.sigCache.Add(sigHash, signature, pubKey) + valid = vm.sigCache.Exists(secpHash, signature, pubKey) + if !valid && pubKey.SchnorrVerify(&secpHash, signature) { + vm.sigCache.Add(secpHash, signature, pubKey) valid = true } } else { - valid = signature.Verify(hash, pubKey) + valid = pubKey.SchnorrVerify(&secpHash, signature) } if !valid && len(sigBytes) > 0 { @@ -2092,7 +2090,7 @@ func opcodeCheckSigVerify(op *parsedOpcode, vm *Engine) error { // the same signature multiple times when verifying a multisig. type parsedSigInfo struct { signature []byte - parsedSignature *ecc.Signature + parsedSignature *secp256k1.SchnorrSignature parsed bool } @@ -2204,7 +2202,7 @@ func opcodeCheckMultiSig(op *parsedOpcode, vm *Engine) error { signature := rawSig[:len(rawSig)-1] // Only parse and check the signature encoding once. - var parsedSig *ecc.Signature + var parsedSig *secp256k1.SchnorrSignature if !sigInfo.parsed { if err := vm.checkHashTypeEncoding(hashType); err != nil { return err @@ -2214,13 +2212,12 @@ func opcodeCheckMultiSig(op *parsedOpcode, vm *Engine) error { } // Parse the signature. - var err error - parsedSig, err = ecc.ParseSignature(signature) - + parsedSig, err = secp256k1.DeserializeSchnorrSignatureFromSlice(signature) sigInfo.parsed = true if err != nil { continue } + sigInfo.parsedSignature = parsedSig } else { // Skip to the next pubkey if the signature is invalid. @@ -2237,29 +2234,28 @@ func opcodeCheckMultiSig(op *parsedOpcode, vm *Engine) error { } // Parse the pubkey. - parsedPubKey, err := ecc.ParsePubKey(pubKey, ecc.S256()) + parsedPubKey, err := secp256k1.DeserializeSchnorrPubKey(pubKey) if err != nil { continue } // Generate the signature hash based on the signature hash type. - hash, err := calcSignatureHash(script, hashType, &vm.tx, vm.txIdx) + sigHash, err := calcSignatureHash(script, hashType, &vm.tx, vm.txIdx) if err != nil { return err } + secpHash := secp256k1.Hash(*sigHash) var valid bool if vm.sigCache != nil { - var sigHash daghash.Hash - copy(sigHash[:], hash) - valid = vm.sigCache.Exists(sigHash, parsedSig, parsedPubKey) - if !valid && parsedSig.Verify(hash, parsedPubKey) { - vm.sigCache.Add(sigHash, parsedSig, parsedPubKey) + valid = vm.sigCache.Exists(secpHash, parsedSig, parsedPubKey) + if !valid && parsedPubKey.SchnorrVerify(&secpHash, parsedSig) { + vm.sigCache.Add(secpHash, parsedSig, parsedPubKey) valid = true } } else { - valid = parsedSig.Verify(hash, parsedPubKey) + valid = parsedPubKey.SchnorrVerify(&secpHash, parsedSig) } if valid { diff --git a/txscript/script.go b/txscript/script.go index 849ea8487..f28a60dd8 100644 --- a/txscript/script.go +++ b/txscript/script.go @@ -285,7 +285,7 @@ func shallowCopyTx(tx *wire.MsgTx) wire.MsgTx { // CalcSignatureHash will, given a script and hash type for the current script // engine instance, calculate the signature hash to be used for signing and // verification. -func CalcSignatureHash(script []byte, hashType SigHashType, tx *wire.MsgTx, idx int) ([]byte, error) { +func CalcSignatureHash(script []byte, hashType SigHashType, tx *wire.MsgTx, idx int) (*daghash.Hash, error) { parsedScript, err := parseScript(script) if err != nil { return nil, errors.Errorf("cannot parse output script: %s", err) @@ -296,7 +296,7 @@ func CalcSignatureHash(script []byte, hashType SigHashType, tx *wire.MsgTx, idx // calcSignatureHash will, given a script and hash type for the current script // engine instance, calculate the signature hash to be used for signing and // verification. -func calcSignatureHash(script []parsedOpcode, hashType SigHashType, tx *wire.MsgTx, idx int) ([]byte, error) { +func calcSignatureHash(script []parsedOpcode, hashType SigHashType, tx *wire.MsgTx, idx int) (*daghash.Hash, error) { // The SigHashSingle signature type signs only the corresponding input // and output (the output with the same index number as the input). // @@ -367,7 +367,8 @@ func calcSignatureHash(script []parsedOpcode, hashType SigHashType, tx *wire.Msg wbuf := bytes.NewBuffer(make([]byte, 0, txCopy.SerializeSize()+4)) txCopy.Serialize(wbuf) binary.Write(wbuf, binary.LittleEndian, hashType) - return daghash.DoubleHashB(wbuf.Bytes()), nil + hash := daghash.DoubleHashH(wbuf.Bytes()) + return &hash, nil } // asSmallInt returns the passed opcode, which must be true according to diff --git a/txscript/sigcache.go b/txscript/sigcache.go index 88e9dedbc..d64d93167 100644 --- a/txscript/sigcache.go +++ b/txscript/sigcache.go @@ -5,10 +5,8 @@ package txscript import ( + "github.com/kaspanet/go-secp256k1" "sync" - - "github.com/kaspanet/kaspad/ecc" - "github.com/kaspanet/kaspad/util/daghash" ) // sigCacheEntry represents an entry in the SigCache. Entries within the @@ -18,8 +16,8 @@ import ( // match. In the occasion that two sigHashes collide, the newer sigHash will // simply overwrite the existing entry. type sigCacheEntry struct { - sig *ecc.Signature - pubKey *ecc.PublicKey + sig *secp256k1.SchnorrSignature + pubKey *secp256k1.SchnorrPublicKey } // SigCache implements an ECDSA signature verification cache with a randomized @@ -34,7 +32,7 @@ type sigCacheEntry struct { // if they've already been seen and verified within the mempool. type SigCache struct { sync.RWMutex - validSigs map[daghash.Hash]sigCacheEntry + validSigs map[secp256k1.Hash]sigCacheEntry maxEntries uint } @@ -45,7 +43,7 @@ type SigCache struct { // cache to exceed the max. func NewSigCache(maxEntries uint) *SigCache { return &SigCache{ - validSigs: make(map[daghash.Hash]sigCacheEntry, maxEntries), + validSigs: make(map[secp256k1.Hash]sigCacheEntry, maxEntries), maxEntries: maxEntries, } } @@ -55,7 +53,7 @@ func NewSigCache(maxEntries uint) *SigCache { // // NOTE: This function is safe for concurrent access. Readers won't be blocked // unless there exists a writer, adding an entry to the SigCache. -func (s *SigCache) Exists(sigHash daghash.Hash, sig *ecc.Signature, pubKey *ecc.PublicKey) bool { +func (s *SigCache) Exists(sigHash secp256k1.Hash, sig *secp256k1.SchnorrSignature, pubKey *secp256k1.SchnorrPublicKey) bool { s.RLock() defer s.RUnlock() entry, ok := s.validSigs[sigHash] @@ -70,7 +68,7 @@ func (s *SigCache) Exists(sigHash daghash.Hash, sig *ecc.Signature, pubKey *ecc. // // NOTE: This function is safe for concurrent access. Writers will block // simultaneous readers until function execution has concluded. -func (s *SigCache) Add(sigHash daghash.Hash, sig *ecc.Signature, pubKey *ecc.PublicKey) { +func (s *SigCache) Add(sigHash secp256k1.Hash, sig *secp256k1.SchnorrSignature, pubKey *secp256k1.SchnorrPublicKey) { s.Lock() defer s.Unlock() diff --git a/txscript/sigcache_test.go b/txscript/sigcache_test.go index d69d8667e..905fc0f7a 100644 --- a/txscript/sigcache_test.go +++ b/txscript/sigcache_test.go @@ -6,32 +6,35 @@ package txscript import ( "crypto/rand" + "github.com/kaspanet/go-secp256k1" "testing" - - "github.com/kaspanet/kaspad/ecc" - "github.com/kaspanet/kaspad/util/daghash" ) // genRandomSig returns a random message, a signature of the message under the // public key and the public key. This function is used to generate randomized // test data. -func genRandomSig() (*daghash.Hash, *ecc.Signature, *ecc.PublicKey, error) { - privKey, err := ecc.NewPrivateKey(ecc.S256()) +func genRandomSig() (*secp256k1.Hash, *secp256k1.SchnorrSignature, *secp256k1.SchnorrPublicKey, error) { + privKey, err := secp256k1.GeneratePrivateKey() if err != nil { return nil, nil, nil, err } - var msgHash daghash.Hash + msgHash := &secp256k1.Hash{} if _, err := rand.Read(msgHash[:]); err != nil { return nil, nil, nil, err } - sig, err := privKey.Sign(msgHash[:]) + sig, err := privKey.SchnorrSign(msgHash) if err != nil { return nil, nil, nil, err } - return &msgHash, sig, privKey.PubKey(), nil + pubkey, err := privKey.SchnorrPublicKey() + if err != nil { + return nil, nil, nil, err + } + + return msgHash, sig, pubkey, nil } // TestSigCacheAddExists tests the ability to add, and later check the @@ -42,15 +45,16 @@ func TestSigCacheAddExists(t *testing.T) { // Generate a random sigCache entry triplet. msg1, sig1, key1, err := genRandomSig() if err != nil { - t.Errorf("unable to generate random signature test data") + t.Fatalf("unable to generate random signature test data") } // Add the triplet to the signature cache. sigCache.Add(*msg1, sig1, key1) // The previously added triplet should now be found within the sigcache. - sig1Copy, _ := ecc.ParseSignature(sig1.Serialize()) - key1Copy, _ := ecc.ParsePubKey(key1.SerializeCompressed(), ecc.S256()) + sig1Copy := secp256k1.DeserializeSchnorrSignature(sig1.Serialize()) + key1Serialized, _ := key1.SerializeCompressed() + key1Copy, _ := secp256k1.DeserializeSchnorrPubKey(key1Serialized) if !sigCache.Exists(*msg1, sig1Copy, key1Copy) { t.Errorf("previously added item not found in signature cache") } @@ -73,8 +77,9 @@ func TestSigCacheAddEvictEntry(t *testing.T) { sigCache.Add(*msg, sig, key) - sigCopy, _ := ecc.ParseSignature(sig.Serialize()) - keyCopy, _ := ecc.ParsePubKey(key.SerializeCompressed(), ecc.S256()) + sigCopy := secp256k1.DeserializeSchnorrSignature(sig.Serialize()) + keySerialized, _ := key.SerializeCompressed() + keyCopy, _ := secp256k1.DeserializeSchnorrPubKey(keySerialized) if !sigCache.Exists(*msg, sigCopy, keyCopy) { t.Errorf("previously added item not found in signature" + "cache") @@ -102,8 +107,9 @@ func TestSigCacheAddEvictEntry(t *testing.T) { } // The entry added above should be found within the sigcache. - sigNewCopy, _ := ecc.ParseSignature(sigNew.Serialize()) - keyNewCopy, _ := ecc.ParsePubKey(keyNew.SerializeCompressed(), ecc.S256()) + sigNewCopy := secp256k1.DeserializeSchnorrSignature(sigNew.Serialize()) + keyNewSerialized, _ := keyNew.SerializeCompressed() + keyNewCopy, _ := secp256k1.DeserializeSchnorrPubKey(keyNewSerialized) if !sigCache.Exists(*msgNew, sigNewCopy, keyNewCopy) { t.Fatalf("previously added item not found in signature cache") } @@ -118,15 +124,16 @@ func TestSigCacheAddMaxEntriesZeroOrNegative(t *testing.T) { // Generate a random sigCache entry triplet. msg1, sig1, key1, err := genRandomSig() if err != nil { - t.Errorf("unable to generate random signature test data") + t.Fatalf("unable to generate random signature test data") } // Add the triplet to the signature cache. sigCache.Add(*msg1, sig1, key1) // The generated triplet should not be found. - sig1Copy, _ := ecc.ParseSignature(sig1.Serialize()) - key1Copy, _ := ecc.ParsePubKey(key1.SerializeCompressed(), ecc.S256()) + sig1Copy := secp256k1.DeserializeSchnorrSignature(sig1.Serialize()) + key1Serialized, _ := key1.SerializeCompressed() + key1Copy, _ := secp256k1.DeserializeSchnorrPubKey(key1Serialized) if sigCache.Exists(*msg1, sig1Copy, key1Copy) { t.Errorf("previously added signature found in sigcache, but" + "shouldn't have been") diff --git a/txscript/sign.go b/txscript/sign.go index 5358d3f2e..cfd8f63d8 100644 --- a/txscript/sign.go +++ b/txscript/sign.go @@ -5,29 +5,30 @@ package txscript import ( + "github.com/kaspanet/go-secp256k1" "github.com/pkg/errors" "github.com/kaspanet/kaspad/dagconfig" - "github.com/kaspanet/kaspad/ecc" "github.com/kaspanet/kaspad/util" "github.com/kaspanet/kaspad/wire" ) -// RawTxInSignature returns the serialized ECDSA signature for the input idx of +// RawTxInSignature returns the serialized Schnorr signature for the input idx of // the given transaction, with hashType appended to it. func RawTxInSignature(tx *wire.MsgTx, idx int, script []byte, - hashType SigHashType, key *ecc.PrivateKey) ([]byte, error) { + hashType SigHashType, key *secp256k1.PrivateKey) ([]byte, error) { hash, err := CalcSignatureHash(script, hashType, tx, idx) if err != nil { return nil, err } - signature, err := key.Sign(hash) + secpHash := secp256k1.Hash(*hash) + signature, err := key.SchnorrSign(&secpHash) if err != nil { return nil, errors.Errorf("cannot sign tx input: %s", err) } - return append(signature.Serialize(), byte(hashType)), nil + return append(signature.Serialize()[:], byte(hashType)), nil } // SignatureScript creates an input signature script for tx to spend KAS sent @@ -38,18 +39,24 @@ func RawTxInSignature(tx *wire.MsgTx, idx int, script []byte, // as the idx'th input. privKey is serialized in either a compressed or // uncompressed format based on compress. This format must match the same format // used to generate the payment address, or the script validation will fail. -func SignatureScript(tx *wire.MsgTx, idx int, script []byte, hashType SigHashType, privKey *ecc.PrivateKey, compress bool) ([]byte, error) { +func SignatureScript(tx *wire.MsgTx, idx int, script []byte, hashType SigHashType, privKey *secp256k1.PrivateKey, compress bool) ([]byte, error) { sig, err := RawTxInSignature(tx, idx, script, hashType, privKey) if err != nil { return nil, err } - pk := (*ecc.PublicKey)(&privKey.PublicKey) + pk, err := privKey.SchnorrPublicKey() + if err != nil { + return nil, err + } var pkData []byte if compress { - pkData = pk.SerializeCompressed() + pkData, err = pk.SerializeCompressed() } else { - pkData = pk.SerializeUncompressed() + pkData, err = pk.SerializeUncompressed() + } + if err != nil { + return nil, err } return NewScriptBuilder().AddData(sig).AddData(pkData).Script() @@ -159,14 +166,14 @@ func mergeScripts(dagParams *dagconfig.Params, tx *wire.MsgTx, idx int, // KeyDB is an interface type provided to SignTxOutput, it encapsulates // any user state required to get the private keys for an address. type KeyDB interface { - GetKey(util.Address) (*ecc.PrivateKey, bool, error) + GetKey(util.Address) (*secp256k1.PrivateKey, bool, error) } // KeyClosure implements KeyDB with a closure. -type KeyClosure func(util.Address) (*ecc.PrivateKey, bool, error) +type KeyClosure func(util.Address) (*secp256k1.PrivateKey, bool, error) // GetKey implements KeyDB by returning the result of calling the closure. -func (kc KeyClosure) GetKey(address util.Address) (*ecc.PrivateKey, +func (kc KeyClosure) GetKey(address util.Address) (*secp256k1.PrivateKey, bool, error) { return kc(address) } diff --git a/txscript/sign_test.go b/txscript/sign_test.go index e2162cd92..b75975685 100644 --- a/txscript/sign_test.go +++ b/txscript/sign_test.go @@ -6,29 +6,29 @@ package txscript import ( "fmt" + "github.com/kaspanet/go-secp256k1" "github.com/pkg/errors" "testing" "github.com/kaspanet/kaspad/dagconfig" - "github.com/kaspanet/kaspad/ecc" "github.com/kaspanet/kaspad/util" "github.com/kaspanet/kaspad/util/daghash" "github.com/kaspanet/kaspad/wire" ) type addressToKey struct { - key *ecc.PrivateKey + key *secp256k1.PrivateKey compressed bool } func mkGetKey(keys map[string]addressToKey) KeyDB { if keys == nil { - return KeyClosure(func(addr util.Address) (*ecc.PrivateKey, + return KeyClosure(func(addr util.Address) (*secp256k1.PrivateKey, bool, error) { return nil, false, errors.New("nope") }) } - return KeyClosure(func(addr util.Address) (*ecc.PrivateKey, + return KeyClosure(func(addr util.Address) (*secp256k1.PrivateKey, bool, error) { a2k, ok := keys[addr.EncodeAddress()] if !ok { @@ -139,17 +139,29 @@ func TestSignTxOutput(t *testing.T) { for _, hashType := range hashTypes { for i := range tx.TxIn { msg := fmt.Sprintf("%d:%d", hashType, i) - key, err := ecc.NewPrivateKey(ecc.S256()) + key, err := secp256k1.GeneratePrivateKey() if err != nil { - t.Errorf("failed to make privKey for %s: %v", + t.Errorf("failed to make privKey for %s: %s", msg, err) break } - pk := (*ecc.PublicKey)(&key.PublicKey). - SerializeUncompressed() + pubKey, err := key.SchnorrPublicKey() + if err != nil { + t.Errorf("failed to make a publickey for %s: %s", + key, err) + break + } + + uncompressedPubKey, err := pubKey.SerializeUncompressed() + if err != nil { + t.Errorf("failed to make a pubkey for %s: %s", + key, err) + break + } + address, err := util.NewAddressPubKeyHash( - util.Hash160(pk), util.Bech32PrefixKaspaTest) + util.Hash160(uncompressedPubKey), util.Bech32PrefixKaspaTest) if err != nil { t.Errorf("failed to make address for %s: %v", msg, err) @@ -176,17 +188,28 @@ func TestSignTxOutput(t *testing.T) { for _, hashType := range hashTypes { for i := range tx.TxIn { msg := fmt.Sprintf("%d:%d", hashType, i) - key, err := ecc.NewPrivateKey(ecc.S256()) + key, err := secp256k1.GeneratePrivateKey() if err != nil { - t.Errorf("failed to make privKey for %s: %v", + t.Errorf("failed to make privKey for %s: %s", msg, err) break } - pk := (*ecc.PublicKey)(&key.PublicKey). - SerializeUncompressed() + pubKey, err := key.SchnorrPublicKey() + if err != nil { + t.Errorf("failed to make a publickey for %s: %s", + key, err) + break + } + + uncompressedPubKey, err := pubKey.SerializeUncompressed() + if err != nil { + t.Errorf("failed to make a pubkey for %s: %s", + key, err) + break + } address, err := util.NewAddressPubKeyHash( - util.Hash160(pk), util.Bech32PrefixKaspaTest) + util.Hash160(uncompressedPubKey), util.Bech32PrefixKaspaTest) if err != nil { t.Errorf("failed to make address for %s: %v", msg, err) @@ -237,17 +260,29 @@ func TestSignTxOutput(t *testing.T) { for i := range tx.TxIn { msg := fmt.Sprintf("%d:%d", hashType, i) - key, err := ecc.NewPrivateKey(ecc.S256()) + key, err := secp256k1.GeneratePrivateKey() if err != nil { - t.Errorf("failed to make privKey for %s: %v", + t.Errorf("failed to make privKey for %s: %s", msg, err) break } - pk := (*ecc.PublicKey)(&key.PublicKey). - SerializeCompressed() + pubKey, err := key.SchnorrPublicKey() + if err != nil { + t.Errorf("failed to make a publickey for %s: %s", + key, err) + break + } + + compressedPubKey, err := pubKey.SerializeCompressed() + if err != nil { + t.Errorf("failed to make a pubkey for %s: %s", + key, err) + break + } + address, err := util.NewAddressPubKeyHash( - util.Hash160(pk), util.Bech32PrefixKaspaTest) + util.Hash160(compressedPubKey), util.Bech32PrefixKaspaTest) if err != nil { t.Errorf("failed to make address for %s: %v", msg, err) @@ -275,17 +310,29 @@ func TestSignTxOutput(t *testing.T) { for i := range tx.TxIn { msg := fmt.Sprintf("%d:%d", hashType, i) - key, err := ecc.NewPrivateKey(ecc.S256()) + key, err := secp256k1.GeneratePrivateKey() if err != nil { - t.Errorf("failed to make privKey for %s: %v", + t.Errorf("failed to make privKey for %s: %s", msg, err) break } - pk := (*ecc.PublicKey)(&key.PublicKey). - SerializeCompressed() + pubKey, err := key.SchnorrPublicKey() + if err != nil { + t.Errorf("failed to make a publickey for %s: %s", + key, err) + break + } + + compressedPubKey, err := pubKey.SerializeCompressed() + if err != nil { + t.Errorf("failed to make a pubkey for %s: %s", + key, err) + break + } + address, err := util.NewAddressPubKeyHash( - util.Hash160(pk), util.Bech32PrefixKaspaTest) + util.Hash160(compressedPubKey), util.Bech32PrefixKaspaTest) if err != nil { t.Errorf("failed to make address for %s: %v", msg, err) @@ -336,17 +383,29 @@ func TestSignTxOutput(t *testing.T) { for _, hashType := range hashTypes { for i := range tx.TxIn { msg := fmt.Sprintf("%d:%d", hashType, i) - key, err := ecc.NewPrivateKey(ecc.S256()) + key, err := secp256k1.GeneratePrivateKey() if err != nil { - t.Errorf("failed to make privKey for %s: %v", + t.Errorf("failed to make privKey for %s: %s", msg, err) break } - pk := (*ecc.PublicKey)(&key.PublicKey). - SerializeUncompressed() + pubKey, err := key.SchnorrPublicKey() + if err != nil { + t.Errorf("failed to make a publickey for %s: %s", + key, err) + break + } + + uncompressedPubKey, err := pubKey.SerializeUncompressed() + if err != nil { + t.Errorf("failed to make a pubkey for %s: %s", + key, err) + break + } + address, err := util.NewAddressPubKeyHash( - util.Hash160(pk), util.Bech32PrefixKaspaTest) + util.Hash160(uncompressedPubKey), util.Bech32PrefixKaspaTest) if err != nil { t.Errorf("failed to make address for %s: %v", msg, err) @@ -392,17 +451,29 @@ func TestSignTxOutput(t *testing.T) { for _, hashType := range hashTypes { for i := range tx.TxIn { msg := fmt.Sprintf("%d:%d", hashType, i) - key, err := ecc.NewPrivateKey(ecc.S256()) + key, err := secp256k1.GeneratePrivateKey() if err != nil { - t.Errorf("failed to make privKey for %s: %v", + t.Errorf("failed to make privKey for %s: %s", msg, err) break } - pk := (*ecc.PublicKey)(&key.PublicKey). - SerializeUncompressed() + pubKey, err := key.SchnorrPublicKey() + if err != nil { + t.Errorf("failed to make a publickey for %s: %s", + key, err) + break + } + + uncompressedPubKey, err := pubKey.SerializeUncompressed() + if err != nil { + t.Errorf("failed to make a pubkey for %s: %s", + key, err) + break + } + address, err := util.NewAddressPubKeyHash( - util.Hash160(pk), util.Bech32PrefixKaspaTest) + util.Hash160(uncompressedPubKey), util.Bech32PrefixKaspaTest) if err != nil { t.Errorf("failed to make address for %s: %v", msg, err) @@ -474,17 +545,29 @@ func TestSignTxOutput(t *testing.T) { for i := range tx.TxIn { msg := fmt.Sprintf("%d:%d", hashType, i) - key, err := ecc.NewPrivateKey(ecc.S256()) + key, err := secp256k1.GeneratePrivateKey() if err != nil { - t.Errorf("failed to make privKey for %s: %v", + t.Errorf("failed to make privKey for %s: %s", msg, err) break } - pk := (*ecc.PublicKey)(&key.PublicKey). - SerializeCompressed() + pubKey, err := key.SchnorrPublicKey() + if err != nil { + t.Errorf("failed to make a publickey for %s: %s", + key, err) + break + } + + compressedPubKey, err := pubKey.SerializeCompressed() + if err != nil { + t.Errorf("failed to make a pubkey for %s: %s", + key, err) + break + } + address, err := util.NewAddressPubKeyHash( - util.Hash160(pk), util.Bech32PrefixKaspaTest) + util.Hash160(compressedPubKey), util.Bech32PrefixKaspaTest) if err != nil { t.Errorf("failed to make address for %s: %v", msg, err) @@ -530,17 +613,29 @@ func TestSignTxOutput(t *testing.T) { for i := range tx.TxIn { msg := fmt.Sprintf("%d:%d", hashType, i) - key, err := ecc.NewPrivateKey(ecc.S256()) + key, err := secp256k1.GeneratePrivateKey() if err != nil { - t.Errorf("failed to make privKey for %s: %v", + t.Errorf("failed to make privKey for %s: %s", msg, err) break } - pk := (*ecc.PublicKey)(&key.PublicKey). - SerializeCompressed() + pubKey, err := key.SchnorrPublicKey() + if err != nil { + t.Errorf("failed to make a publickey for %s: %s", + key, err) + break + } + + compressedPubKey, err := pubKey.SerializeCompressed() + if err != nil { + t.Errorf("failed to make a pubkey for %s: %s", + key, err) + break + } + address, err := util.NewAddressPubKeyHash( - util.Hash160(pk), util.Bech32PrefixKaspaTest) + util.Hash160(compressedPubKey), util.Bech32PrefixKaspaTest) if err != nil { t.Errorf("failed to make address for %s: %v", msg, err) @@ -629,7 +724,7 @@ var coinbaseOutpoint = &wire.Outpoint{ // Pregenerated private key, with associated public key and scriptPubKeys // for the uncompressed and compressed hash160. var ( - privKeyD = []byte{0x6b, 0x0f, 0xd8, 0xda, 0x54, 0x22, 0xd0, 0xb7, + privKeyD = secp256k1.SerializedPrivateKey{0x6b, 0x0f, 0xd8, 0xda, 0x54, 0x22, 0xd0, 0xb7, 0xb4, 0xfc, 0x4e, 0x55, 0xd4, 0x88, 0x42, 0xb3, 0xa1, 0x65, 0xac, 0x70, 0x7f, 0x3d, 0xa4, 0x39, 0x5e, 0xcb, 0x3b, 0xb0, 0xd6, 0x0e, 0x06, 0x92} @@ -864,7 +959,7 @@ var sigScriptTests = []tstSigScript{ func TestSignatureScript(t *testing.T) { t.Parallel() - privKey, _ := ecc.PrivKeyFromBytes(ecc.S256(), privKeyD) + privKey, _ := secp256k1.DeserializePrivateKey(&privKeyD) nexttest: for i := range sigScriptTests { diff --git a/util/bloom/filter_test.go b/util/bloom/filter_test.go index 18832a3b6..350e2c084 100644 --- a/util/bloom/filter_test.go +++ b/util/bloom/filter_test.go @@ -221,8 +221,13 @@ func TestFilterInsertKey(t *testing.T) { } f := bloom.NewFilter(2, 0, 0.001, wire.BloomUpdateAll) - f.Add(wif.SerializePubKey()) - f.Add(util.Hash160(wif.SerializePubKey())) + serializedPubKey, err := wif.SerializePubKey() + if err != nil { + t.Errorf("TestFilterInsertKey SerializePubKey failed: %v", err) + return + } + f.Add(serializedPubKey) + f.Add(util.Hash160(serializedPubKey)) want, err := hex.DecodeString("038fc16b080000000000000001") if err != nil { diff --git a/util/wif.go b/util/wif.go index 0cb13e870..f199d5f53 100644 --- a/util/wif.go +++ b/util/wif.go @@ -6,7 +6,7 @@ package util import ( "bytes" - "github.com/kaspanet/kaspad/ecc" + "github.com/kaspanet/go-secp256k1" "github.com/kaspanet/kaspad/util/base58" "github.com/kaspanet/kaspad/util/daghash" "github.com/pkg/errors" @@ -30,7 +30,7 @@ const compressMagic byte = 0x01 // by calling NewWIF. type WIF struct { // PrivKey is the private key being imported or exported. - PrivKey *ecc.PrivateKey + PrivKey *secp256k1.PrivateKey // CompressPubKey specifies whether the address controlled by the // imported or exported private key was created by hashing a @@ -47,7 +47,7 @@ type WIF struct { // as a string encoded in the Wallet Import Format. The compress argument // specifies whether the address intended to be imported or exported was created // by serializing the public key compressed rather than uncompressed. -func NewWIF(privKey *ecc.PrivateKey, privateKeyID byte, compress bool) (*WIF, error) { +func NewWIF(privKey *secp256k1.PrivateKey, privateKeyID byte, compress bool) (*WIF, error) { return &WIF{privKey, compress, privateKeyID}, nil } @@ -85,12 +85,12 @@ func DecodeWIF(wif string) (*WIF, error) { // Length of base58 decoded WIF must be 32 bytes + an optional 1 byte // (0x01) if compressed, plus 1 byte for netID + 4 bytes of checksum. switch decodedLen { - case 1 + ecc.PrivKeyBytesLen + 1 + 4: + case 1 + secp256k1.SerializedPrivateKeySize + 1 + 4: if decoded[33] != compressMagic { return nil, ErrMalformedPrivateKey } compress = true - case 1 + ecc.PrivKeyBytesLen + 4: + case 1 + secp256k1.SerializedPrivateKeySize + 4: compress = false default: return nil, ErrMalformedPrivateKey @@ -101,9 +101,9 @@ func DecodeWIF(wif string) (*WIF, error) { // private key. var tosum []byte if compress { - tosum = decoded[:1+ecc.PrivKeyBytesLen+1] + tosum = decoded[:1+secp256k1.SerializedPrivateKeySize+1] } else { - tosum = decoded[:1+ecc.PrivKeyBytesLen] + tosum = decoded[:1+secp256k1.SerializedPrivateKeySize] } cksum := daghash.DoubleHashB(tosum)[:4] if !bytes.Equal(cksum, decoded[decodedLen-4:]) { @@ -111,8 +111,11 @@ func DecodeWIF(wif string) (*WIF, error) { } netID := decoded[0] - privKeyBytes := decoded[1 : 1+ecc.PrivKeyBytesLen] - privKey, _ := ecc.PrivKeyFromBytes(ecc.S256(), privKeyBytes) + privKeyBytes := decoded[1 : 1+secp256k1.SerializedPrivateKeySize] + privKey, err := secp256k1.DeserializePrivateKeyFromSlice(privKeyBytes) + if err != nil { + return nil, err + } return &WIF{privKey, compress, netID}, nil } @@ -124,7 +127,7 @@ func (w *WIF) String() string { // is one byte for the network, 32 bytes of private key, possibly one // extra byte if the pubkey is to be compressed, and finally four // bytes of checksum. - encodeLen := 1 + ecc.PrivKeyBytesLen + 4 + encodeLen := 1 + secp256k1.SerializedPrivateKeySize + 4 if w.CompressPubKey { encodeLen++ } @@ -133,7 +136,7 @@ func (w *WIF) String() string { a = append(a, w.netID) // Pad and append bytes manually, instead of using Serialize, to // avoid another call to make. - a = paddedAppend(ecc.PrivKeyBytesLen, a, w.PrivKey.D.Bytes()) + a = paddedAppend(secp256k1.SerializedPrivateKeySize, a, w.PrivKey.Serialize()[:]) if w.CompressPubKey { a = append(a, compressMagic) } @@ -145,8 +148,11 @@ func (w *WIF) String() string { // SerializePubKey serializes the associated public key of the imported or // exported private key in either a compressed or uncompressed format. The // serialization format chosen depends on the value of w.CompressPubKey. -func (w *WIF) SerializePubKey() []byte { - pk := (*ecc.PublicKey)(&w.PrivKey.PublicKey) +func (w *WIF) SerializePubKey() ([]byte, error) { + pk, err := w.PrivKey.SchnorrPublicKey() + if err != nil { + return nil, err + } if w.CompressPubKey { return pk.SerializeCompressed() } diff --git a/util/wif_test.go b/util/wif_test.go index f37459859..17396572d 100644 --- a/util/wif_test.go +++ b/util/wif_test.go @@ -7,24 +7,32 @@ package util_test import ( "testing" + "github.com/kaspanet/go-secp256k1" "github.com/kaspanet/kaspad/dagconfig" - "github.com/kaspanet/kaspad/ecc" . "github.com/kaspanet/kaspad/util" ) func TestEncodeDecodeWIF(t *testing.T) { - priv1, _ := ecc.PrivKeyFromBytes(ecc.S256(), []byte{ + priv1, err := secp256k1.DeserializePrivateKey(&secp256k1.SerializedPrivateKey{ 0x0c, 0x28, 0xfc, 0xa3, 0x86, 0xc7, 0xa2, 0x27, 0x60, 0x0b, 0x2f, 0xe5, 0x0b, 0x7c, 0xae, 0x11, 0xec, 0x86, 0xd3, 0xbf, 0x1f, 0xbe, 0x47, 0x1b, 0xe8, 0x98, 0x27, 0xe1, 0x9d, 0x72, 0xaa, 0x1d}) - priv2, _ := ecc.PrivKeyFromBytes(ecc.S256(), []byte{ + if err != nil { + t.Fatal(err) + } + + priv2, err := secp256k1.DeserializePrivateKey(&secp256k1.SerializedPrivateKey{ 0xdd, 0xa3, 0x5a, 0x14, 0x88, 0xfb, 0x97, 0xb6, 0xeb, 0x3f, 0xe6, 0xe9, 0xef, 0x2a, 0x25, 0x81, 0x4e, 0x39, 0x6f, 0xb5, 0xdc, 0x29, 0x5f, 0xe9, 0x94, 0xb9, 0x67, 0x89, 0xb2, 0x1a, 0x03, 0x98}) + if err != nil { + t.Fatal(err) + } + wif1, err := NewWIF(priv1, dagconfig.MainnetParams.PrivateKeyID, false) if err != nil { t.Fatal(err)