[NOD-876] Replace ecc with go-secp256k1 for public keys (#670)

* Replace ecc with go-secp256k1 in txscript

* Replace ecc with go-secp256k1 in util and cmd

* Replace ecc.Multiset with secp256k1.MultiSet
This commit is contained in:
Elichai Turkel
2020-03-26 17:03:39 +02:00
committed by GitHub
parent e000e10738
commit f80908fb4e
19 changed files with 326 additions and 202 deletions

View File

@@ -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,

View File

@@ -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

View File

@@ -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: <x (32 bytes)><y (32 bytes)>.
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)
}

View File

@@ -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
}

View File

@@ -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
}

View File

@@ -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 {

View File

@@ -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 {

6
go.mod
View File

@@ -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

12
go.sum
View File

@@ -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=

View File

@@ -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
}

View File

@@ -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 {

View File

@@ -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

View File

@@ -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()

View File

@@ -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")

View File

@@ -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)
}

View File

@@ -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 {

View File

@@ -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 {

View File

@@ -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()
}

View File

@@ -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)