diff --git a/.idea/codeStyles/Project.xml b/.idea/codeStyles/Project.xml
index 58f744ec..700e416d 100644
--- a/.idea/codeStyles/Project.xml
+++ b/.idea/codeStyles/Project.xml
@@ -6,7 +6,6 @@
-
diff --git a/crypto/ckd/child_key_derivation.go b/crypto/ckd/child_key_derivation.go
index 422cffed..56702f6c 100644
--- a/crypto/ckd/child_key_derivation.go
+++ b/crypto/ckd/child_key_derivation.go
@@ -4,7 +4,6 @@ package ckd
import (
"bytes"
- "crypto/ecdsa"
"crypto/elliptic"
"crypto/hmac"
"crypto/sha256"
@@ -22,7 +21,7 @@ import (
)
type ExtendedKey struct {
- ecdsa.PublicKey
+ PublicKey *crypto.ECPoint
Depth uint8
ChildIndex uint32
ChainCode []byte // 32 bytes
@@ -70,7 +69,7 @@ func (k *ExtendedKey) String() string {
serializedBytes = append(serializedBytes, k.ParentFP...)
serializedBytes = append(serializedBytes, childNumBytes[:]...)
serializedBytes = append(serializedBytes, k.ChainCode...)
- pubKeyBytes := serializeCompressed(k.PublicKey.X, k.PublicKey.Y)
+ pubKeyBytes := serializeCompressed(k.PublicKey.X(), k.PublicKey.Y())
serializedBytes = append(serializedBytes, pubKeyBytes...)
checkSum := doubleHashB(serializedBytes)[:4]
@@ -103,24 +102,23 @@ func NewExtendedKeyFromString(key string, curve elliptic.Curve) (*ExtendedKey, e
chainCode := payload[13:45]
keyData := payload[45:78]
- var pubKey ecdsa.PublicKey
+ var pubKey *crypto.ECPoint
+ var err error
if c, ok := curve.(*btcec.KoblitzCurve); ok {
pk, err := btcec.ParsePubKey(keyData)
if err != nil {
return nil, err
}
- pubKey = ecdsa.PublicKey{
- Curve: c,
- X: pk.X(),
- Y: pk.Y(),
+ pubKey, err = crypto.NewECPoint(c, pk.X(), pk.Y())
+ if err != nil {
+ return nil, err
}
} else {
px, py := elliptic.Unmarshal(curve, keyData)
- pubKey = ecdsa.PublicKey{
- Curve: curve,
- X: px,
- Y: py,
+ pubKey, err = crypto.NewECPoint(curve, px, py)
+ if err != nil {
+ return nil, err
}
}
@@ -208,13 +206,9 @@ func DeriveChildKey(index uint32, pk *ExtendedKey, curve elliptic.Curve) (*big.I
return nil, nil, errors.New("cannot derive key beyond max depth")
}
- cryptoPk, err := crypto.NewECPoint(curve, pk.X, pk.Y)
- if err != nil {
- common.Logger.Error("error getting pubkey from extendedkey")
- return nil, nil, err
- }
+ cryptoPk := pk.PublicKey
- pkPublicKeyBytes := serializeCompressed(pk.X, pk.Y)
+ pkPublicKeyBytes := serializeCompressed(pk.PublicKey.X(), pk.PublicKey.Y())
data := make([]byte, 37)
copy(data, pkPublicKeyBytes)
@@ -227,7 +221,9 @@ func DeriveChildKey(index uint32, pk *ExtendedKey, curve elliptic.Curve) (*big.I
il := ilr[:32]
childChainCode := ilr[32:]
ilNum := new(big.Int).SetBytes(il)
+ ilNum = ilNum.Mod(ilNum, curve.Params().N)
+ var err error
if ilNum.Cmp(curve.Params().N) >= 0 || ilNum.Sign() == 0 {
// falling outside of the valid range for curve private keys
err = errors.New("invalid derived key")
@@ -248,7 +244,7 @@ func DeriveChildKey(index uint32, pk *ExtendedKey, curve elliptic.Curve) (*big.I
}
childPk := &ExtendedKey{
- PublicKey: *childCryptoPk.ToECDSAPubKey(),
+ PublicKey: childCryptoPk,
Depth: pk.Depth + 1,
ChildIndex: index,
ChainCode: childChainCode,
diff --git a/crypto/ckd/child_key_derivation_test.go b/crypto/ckd/child_key_derivation_test.go
index 6511e4ef..fa1a8408 100644
--- a/crypto/ckd/child_key_derivation_test.go
+++ b/crypto/ckd/child_key_derivation_test.go
@@ -7,10 +7,19 @@
package ckd_test
import (
+ "crypto/elliptic"
+ "crypto/rand"
+ "math/big"
"testing"
+ "github.com/bnb-chain/tss-lib/v2/common"
+ "github.com/bnb-chain/tss-lib/v2/crypto"
+ "github.com/bnb-chain/tss-lib/v2/crypto/ckd"
. "github.com/bnb-chain/tss-lib/v2/crypto/ckd"
"github.com/btcsuite/btcd/btcec/v2"
+ "github.com/btcsuite/btcd/chaincfg"
+ "github.com/decred/dcrd/dcrec/edwards/v2"
+ "github.com/stretchr/testify/assert"
)
func TestPublicDerivation(t *testing.T) {
@@ -130,3 +139,69 @@ tests:
}
}
}
+
+func TestEddsaPublicDerivation(t *testing.T) {
+ prikey := common.GetRandomPositiveInt(rand.Reader, edwards.Edwards().N)
+ pubkey := crypto.ScalarBaseMult(edwards.Edwards(), prikey)
+
+ chainCode := make([]byte, 32)
+ max32b := new(big.Int).Lsh(new(big.Int).SetUint64(1), 256)
+ max32b = new(big.Int).Sub(max32b, new(big.Int).SetUint64(1))
+ fillBytes(common.GetRandomPositiveInt(rand.Reader, max32b), chainCode)
+
+ il, extendedChildPk, errorDerivation := derivingPubkeyFromPath(pubkey, chainCode, []uint32{12, 209, 3}, edwards.Edwards())
+ assert.NoErrorf(t, errorDerivation, "there should not be an error deriving the child public key")
+
+ keyDerivationDelta := il
+
+ childPrivkey := new(big.Int).Add(prikey, keyDerivationDelta)
+ childPrivkey.Mod(childPrivkey, edwards.Edwards().N)
+
+ sk, pk, err := edwards.PrivKeyFromScalar(common.PadToLengthBytesInPlace(childPrivkey.Bytes()[:], 32))
+ assert.NoError(t, err)
+ assert.Equal(t, pk.X, extendedChildPk.PublicKey.X())
+
+ data := big.NewInt(200).Bytes()
+
+ r, s, err := edwards.Sign(sk, data)
+ assert.NoError(t, err, "sign should not throw an error")
+
+ pubk := edwards.PublicKey{
+ Curve: edwards.Edwards(),
+ X: extendedChildPk.PublicKey.X(),
+ Y: extendedChildPk.PublicKey.Y(),
+ }
+ ok := edwards.Verify(&pubk, data, r, s)
+ assert.True(t, ok)
+ assert.NoError(t, err)
+}
+
+func derivingPubkeyFromPath(masterPub *crypto.ECPoint, chainCode []byte, path []uint32, ec elliptic.Curve) (*big.Int, *ckd.ExtendedKey, error) {
+ net := &chaincfg.MainNetParams
+ extendedParentPk := &ckd.ExtendedKey{
+ PublicKey: masterPub,
+ Depth: 0,
+ ChildIndex: 0,
+ ChainCode: chainCode[:],
+ ParentFP: []byte{0x00, 0x00, 0x00, 0x00},
+ Version: net.HDPrivateKeyID[:],
+ }
+
+ return ckd.DeriveChildKeyFromHierarchy(path, extendedParentPk, ec.Params().N, ec)
+}
+
+func fillBytes(x *big.Int, buf []byte) []byte {
+ b := x.Bytes()
+ if len(b) > len(buf) {
+ panic("buffer too small")
+ }
+ offset := len(buf) - len(b)
+ for i := range buf {
+ if i < offset {
+ buf[i] = 0
+ } else {
+ buf[i] = b[i-offset]
+ }
+ }
+ return buf
+}
diff --git a/crypto/mta/range_proof.go b/crypto/mta/range_proof.go
index dfd43257..1c5b3a0e 100644
--- a/crypto/mta/range_proof.go
+++ b/crypto/mta/range_proof.go
@@ -141,15 +141,6 @@ func (pf *RangeProofAlice) Verify(ec elliptic.Curve, pk *paillier.PublicKey, NTi
if pf.S2.Cmp(q) == -1 {
return false
}
- if pf.S.Cmp(one) == 0 {
- return false
- }
- if pf.Z.Cmp(one) == 0 {
- return false
- }
- if pf.S1.Cmp(pf.S2) == 0 {
- return false
- }
// 3.
if pf.S1.Cmp(q3) == 1 {
diff --git a/crypto/vss/feldman_vss.go b/crypto/vss/feldman_vss.go
index 347af09c..74d549dc 100644
--- a/crypto/vss/feldman_vss.go
+++ b/crypto/vss/feldman_vss.go
@@ -93,7 +93,7 @@ func Create(ec elliptic.Curve, threshold int, secret *big.Int, indexes []*big.In
}
func (share *Share) Verify(ec elliptic.Curve, threshold int, vs Vs) bool {
- if share.Threshold != threshold || vs == nil || len(vs) != threshold+1 {
+ if share.Threshold != threshold || vs == nil {
return false
}
var err error
diff --git a/ecdsa/signing/key_derivation_util.go b/ecdsa/signing/key_derivation_util.go
index 668d9d4f..54a9909b 100644
--- a/ecdsa/signing/key_derivation_util.go
+++ b/ecdsa/signing/key_derivation_util.go
@@ -3,7 +3,6 @@
package signing
import (
- "crypto/ecdsa"
"crypto/elliptic"
"math/big"
@@ -15,15 +14,11 @@ import (
"github.com/btcsuite/btcd/chaincfg"
)
-func UpdatePublicKeyAndAdjustBigXj(keyDerivationDelta *big.Int, keys []keygen.LocalPartySaveData, extendedChildPk *ecdsa.PublicKey, ec elliptic.Curve) error {
+func UpdatePublicKeyAndAdjustBigXj(keyDerivationDelta *big.Int, keys []keygen.LocalPartySaveData, extendedChildPk *crypto.ECPoint, ec elliptic.Curve) error {
var err error
gDelta := crypto.ScalarBaseMult(ec, keyDerivationDelta)
for k := range keys {
- keys[k].ECDSAPub, err = crypto.NewECPoint(ec, extendedChildPk.X, extendedChildPk.Y)
- if err != nil {
- common.Logger.Errorf("error creating new extended child public key")
- return err
- }
+ keys[k].ECDSAPub = extendedChildPk
// Suppose X_j has shamir shares X_j0, X_j1, ..., X_jn
// So X_j + D has shamir shares X_j0 + D, X_j1 + D, ..., X_jn + D
for j := range keys[k].BigXj {
@@ -38,16 +33,9 @@ func UpdatePublicKeyAndAdjustBigXj(keyDerivationDelta *big.Int, keys []keygen.Lo
}
func derivingPubkeyFromPath(masterPub *crypto.ECPoint, chainCode []byte, path []uint32, ec elliptic.Curve) (*big.Int, *ckd.ExtendedKey, error) {
- // build ecdsa key pair
- pk := ecdsa.PublicKey{
- Curve: ec,
- X: masterPub.X(),
- Y: masterPub.Y(),
- }
-
net := &chaincfg.MainNetParams
extendedParentPk := &ckd.ExtendedKey{
- PublicKey: pk,
+ PublicKey: masterPub,
Depth: 0,
ChildIndex: 0,
ChainCode: chainCode[:],
diff --git a/ecdsa/signing/local_party_test.go b/ecdsa/signing/local_party_test.go
index 33f41dc5..cab4a580 100644
--- a/ecdsa/signing/local_party_test.go
+++ b/ecdsa/signing/local_party_test.go
@@ -246,7 +246,7 @@ func TestE2EWithHDKeyDerivation(t *testing.T) {
keyDerivationDelta := il
- err = UpdatePublicKeyAndAdjustBigXj(keyDerivationDelta, keys, &extendedChildPk.PublicKey, btcec.S256())
+ err = UpdatePublicKeyAndAdjustBigXj(keyDerivationDelta, keys, extendedChildPk.PublicKey, btcec.S256())
assert.NoErrorf(t, err, "there should not be an error setting the derived keys")
// PHASE: signing
diff --git a/eddsa/signing/key_derivation_util.go b/eddsa/signing/key_derivation_util.go
new file mode 100644
index 00000000..21142412
--- /dev/null
+++ b/eddsa/signing/key_derivation_util.go
@@ -0,0 +1,44 @@
+// Copyright © 2021 Swingby
+
+package signing
+
+import (
+ "crypto/elliptic"
+ "math/big"
+
+ "github.com/bnb-chain/tss-lib/v2/common"
+ "github.com/bnb-chain/tss-lib/v2/crypto"
+ "github.com/bnb-chain/tss-lib/v2/crypto/ckd"
+ "github.com/bnb-chain/tss-lib/v2/eddsa/keygen"
+)
+
+func UpdatePublicKeyAndAdjustBigXj(keyDerivationDelta *big.Int, keys []keygen.LocalPartySaveData, extendedChildPk *crypto.ECPoint, ec elliptic.Curve) error {
+ var err error
+ gDelta := crypto.ScalarBaseMult(ec, keyDerivationDelta)
+ for k := range keys {
+ keys[k].EDDSAPub = extendedChildPk
+ // Suppose X_j has shamir shares X_j0, X_j1, ..., X_jn
+ // So X_j + D has shamir shares X_j0 + D, X_j1 + D, ..., X_jn + D
+ for j := range keys[k].BigXj {
+ keys[k].BigXj[j], err = keys[k].BigXj[j].Add(gDelta)
+ if err != nil {
+ common.Logger.Errorf("error in delta operation")
+ return err
+ }
+ }
+ }
+ return nil
+}
+
+func derivingPubkeyFromPath(masterPub *crypto.ECPoint, chainCode []byte, path []uint32, ec elliptic.Curve) (*big.Int, *ckd.ExtendedKey, error) {
+ extendedParentPk := &ckd.ExtendedKey{
+ PublicKey: masterPub,
+ Depth: 0,
+ ChildIndex: 0,
+ ChainCode: chainCode[:],
+ ParentFP: []byte{0x00, 0x00, 0x00, 0x00},
+ Version: []byte{0x02, 0xe8, 0xda, 0x54},
+ }
+
+ return ckd.DeriveChildKeyFromHierarchy(path, extendedParentPk, ec.Params().N, ec)
+}
diff --git a/eddsa/signing/local_party.go b/eddsa/signing/local_party.go
index 52e474dc..0d96aa77 100644
--- a/eddsa/signing/local_party.go
+++ b/eddsa/signing/local_party.go
@@ -61,8 +61,9 @@ type (
// round 3
r *big.Int
- ssid []byte
- ssidNonce *big.Int
+ ssid []byte
+ ssidNonce *big.Int
+ keyDerivationDelta *big.Int
}
)
@@ -100,6 +101,42 @@ func NewLocalParty(
return p
}
+func NewLocalPartyWithKDD(
+ msg *big.Int,
+ params *tss.Parameters,
+ key keygen.LocalPartySaveData,
+ keyDerivationDelta *big.Int,
+ out chan<- tss.Message,
+ end chan<- *common.SignatureData,
+ fullBytesLen ...int,
+) tss.Party {
+ partyCount := len(params.Parties().IDs())
+ p := &LocalParty{
+ BaseParty: new(tss.BaseParty),
+ params: params,
+ keys: keygen.BuildLocalSaveDataSubset(key, params.Parties().IDs()),
+ temp: localTempData{},
+ data: &common.SignatureData{},
+ out: out,
+ end: end,
+ }
+ // msgs init
+ p.temp.signRound1Messages = make([]tss.ParsedMessage, partyCount)
+ p.temp.signRound2Messages = make([]tss.ParsedMessage, partyCount)
+ p.temp.signRound3Messages = make([]tss.ParsedMessage, partyCount)
+ p.temp.keyDerivationDelta = keyDerivationDelta
+
+ // temp data init
+ p.temp.m = msg
+ if len(fullBytesLen) > 0 {
+ p.temp.fullBytesLen = fullBytesLen[0]
+ } else {
+ p.temp.fullBytesLen = 0
+ }
+ p.temp.cjs = make([]*big.Int, partyCount)
+ return p
+}
+
func (p *LocalParty) FirstRound() tss.Round {
return newRound1(p.params, &p.keys, p.data, &p.temp, p.out, p.end)
}
diff --git a/eddsa/signing/local_party_test.go b/eddsa/signing/local_party_test.go
index a2c573e8..b5e9b878 100644
--- a/eddsa/signing/local_party_test.go
+++ b/eddsa/signing/local_party_test.go
@@ -7,6 +7,7 @@
package signing
import (
+ "crypto/rand"
"encoding/hex"
"fmt"
"math/big"
@@ -248,3 +249,135 @@ signing:
}
}
}
+
+func TestE2EConcurrentWithHDDerive(t *testing.T) {
+ setUp("info")
+
+ threshold := testThreshold
+
+ // PHASE: load keygen fixtures
+ keys, signPIDs, err := keygen.LoadKeygenTestFixturesRandomSet(testThreshold+1, testParticipants)
+ assert.NoError(t, err, "should load keygen fixtures")
+ assert.Equal(t, testThreshold+1, len(keys))
+ assert.Equal(t, testThreshold+1, len(signPIDs))
+
+ chainCode := make([]byte, 32)
+ max32b := new(big.Int).Lsh(new(big.Int).SetUint64(1), 256)
+ max32b = new(big.Int).Sub(max32b, new(big.Int).SetUint64(1))
+ fillBytes(common.GetRandomPositiveInt(rand.Reader, max32b), chainCode)
+
+ il, extendedChildPk, errorDerivation := derivingPubkeyFromPath(keys[0].EDDSAPub, chainCode, []uint32{12, 209, 3}, edwards.Edwards())
+ assert.NoErrorf(t, errorDerivation, "there should not be an error deriving the child public key")
+
+ keyDerivationDelta := il
+
+ err = UpdatePublicKeyAndAdjustBigXj(keyDerivationDelta, keys, extendedChildPk.PublicKey, edwards.Edwards())
+ assert.NoErrorf(t, err, "there should not be an error setting the derived keys")
+
+ p2pCtx := tss.NewPeerContext(signPIDs)
+ parties := make([]*LocalParty, 0, len(signPIDs))
+
+ errCh := make(chan *tss.Error, len(signPIDs))
+ outCh := make(chan tss.Message, len(signPIDs))
+ endCh := make(chan *common.SignatureData, len(signPIDs))
+
+ updater := test.SharedPartyUpdater
+
+ msg, _ := hex.DecodeString("00f163ee51bcaeff9cdff5e0e3c1a646abd19885fffbab0b3b4236e0cf95c9f5")
+ // init the parties
+ for i := 0; i < len(signPIDs); i++ {
+ params := tss.NewParameters(tss.Edwards(), p2pCtx, signPIDs[i], len(signPIDs), threshold)
+ P := NewLocalPartyWithKDD(new(big.Int).SetBytes(msg), params, keys[i], keyDerivationDelta, outCh, endCh, len(msg)).(*LocalParty)
+ parties = append(parties, P)
+ go func(P *LocalParty) {
+ if err := P.Start(); err != nil {
+ errCh <- err
+ }
+ }(P)
+ }
+
+ var ended int32
+signing:
+ for {
+ select {
+ case err := <-errCh:
+ common.Logger.Errorf("Error: %s", err)
+ assert.FailNow(t, err.Error())
+ break signing
+
+ case msg := <-outCh:
+ dest := msg.GetTo()
+ if dest == nil {
+ for _, P := range parties {
+ if P.PartyID().Index == msg.GetFrom().Index {
+ continue
+ }
+ go updater(P, msg, errCh)
+ }
+ } else {
+ if dest[0].Index == msg.GetFrom().Index {
+ t.Fatalf("party %d tried to send a message to itself (%d)", dest[0].Index, msg.GetFrom().Index)
+ }
+ go updater(parties[dest[0].Index], msg, errCh)
+ }
+
+ case <-endCh:
+ atomic.AddInt32(&ended, 1)
+ if atomic.LoadInt32(&ended) == int32(len(signPIDs)) {
+ t.Logf("Done. Received signature data from %d participants", ended)
+ R := parties[0].temp.r
+
+ // BEGIN check s correctness
+ sumS := parties[0].temp.si
+ for i, p := range parties {
+ if i == 0 {
+ continue
+ }
+
+ var tmpSumS [32]byte
+ edwards25519.ScMulAdd(&tmpSumS, sumS, bigIntToEncodedBytes(big.NewInt(1)), p.temp.si)
+ sumS = &tmpSumS
+ }
+ fmt.Printf("S: %s\n", encodedBytesToBigInt(sumS).String())
+ fmt.Printf("R: %s\n", R.String())
+ // END check s correctness
+
+ // BEGIN EDDSA verify
+ pkX, pkY := keys[0].EDDSAPub.X(), keys[0].EDDSAPub.Y()
+ pk := edwards.PublicKey{
+ Curve: tss.Edwards(),
+ X: pkX,
+ Y: pkY,
+ }
+
+ newSig, err := edwards.ParseSignature(parties[0].data.Signature)
+ if err != nil {
+ println("new sig error, ", err.Error())
+ }
+
+ ok := edwards.Verify(&pk, msg, newSig.R, newSig.S)
+ assert.True(t, ok, "eddsa verify must pass")
+ t.Log("EDDSA signing test done.")
+ // END EDDSA verify
+
+ break signing
+ }
+ }
+ }
+}
+
+func fillBytes(x *big.Int, buf []byte) []byte {
+ b := x.Bytes()
+ if len(b) > len(buf) {
+ panic("buffer too small")
+ }
+ offset := len(buf) - len(b)
+ for i := range buf {
+ if i < offset {
+ buf[i] = 0
+ } else {
+ buf[i] = b[i-offset]
+ }
+ }
+ return buf
+}
diff --git a/eddsa/signing/round_1.go b/eddsa/signing/round_1.go
index 63d40f6c..9f6a1f6c 100644
--- a/eddsa/signing/round_1.go
+++ b/eddsa/signing/round_1.go
@@ -98,7 +98,14 @@ func (round *round1) prepare() error {
xi := round.key.Xi
ks := round.key.Ks
-
+ if round.temp.keyDerivationDelta != nil {
+ // adding the key derivation delta to the xi's
+ // Suppose x has shamir shares x_0, x_1, ..., x_n
+ // So x + D has shamir shares x_0 + D, x_1 + D, ..., x_n + D
+ mod := common.ModInt(round.Params().EC().Params().N)
+ xi = mod.Add(round.temp.keyDerivationDelta, xi)
+ round.key.Xi = xi
+ }
if round.Threshold()+1 > len(ks) {
return fmt.Errorf("t+1=%d is not satisfied by the key count of %d", round.Threshold()+1, len(ks))
}