Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 6 additions & 5 deletions crypto/ckd/child_key_derivation.go
Original file line number Diff line number Diff line change
Expand Up @@ -16,8 +16,8 @@ import (

"github.com/bnb-chain/tss-lib/common"
"github.com/bnb-chain/tss-lib/crypto"
"github.com/btcsuite/btcd/btcec"
"github.com/btcsuite/btcutil/base58"
"github.com/btcsuite/btcd/btcec/v2"
"github.com/btcsuite/btcd/btcutil/base58"
"golang.org/x/crypto/ripemd160"
)

Expand Down Expand Up @@ -105,14 +105,15 @@ func NewExtendedKeyFromString(key string, curve elliptic.Curve) (*ExtendedKey, e

var pubKey ecdsa.PublicKey

if c, ok := curve.(*btcec.KoblitzCurve); ok {
if _, ok := curve.(*btcec.KoblitzCurve); ok {
// Ensure the public key parses correctly and is actually on the
// secp256k1 curve.
pk, err := btcec.ParsePubKey(keyData, c)
pk, err := btcec.ParsePubKey(keyData)
if err != nil {
return nil, err
}
pubKey = ecdsa.PublicKey(*pk)
pubKey = *pk.ToECDSA()
pubKey.Curve = curve
} else {
px, py := elliptic.Unmarshal(curve, keyData)
pubKey = ecdsa.PublicKey{
Expand Down
34 changes: 33 additions & 1 deletion crypto/ckd/child_key_derivation_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,9 +10,41 @@ import (
"testing"

. "github.com/bnb-chain/tss-lib/crypto/ckd"
"github.com/btcsuite/btcd/btcec"
"github.com/bnb-chain/tss-lib/tss"
"github.com/btcsuite/btcd/btcec/v2"
)

func TestLegacyPublicDerivationHierarchy(t *testing.T) {
// Captured with btcec at c26ffa870fd8. Pin both the serialized xpub and
// the accumulated scalar used to adjust existing signing shares.
const master = "xpub661MyMwAqRbcFtXgS5sYJABqqG9YLmC4Q1Rdap9gSE8NqtwybGhePY2gZ29ESFjqJoCu1Rupje8YtGqsefD265TMg7usUDFdp6W1EGMcet8"
const wantChild = "xpub6CYmVEgeUykCausT5DuGF88T5ygofv63uKA287sVoASqgavVhNXxVWCrGQQReXBjyMGkURetqftCVhMrAzLoCUcbP46o4sibtt3LisHMKkC"
const wantDelta = "5cf748ee8bf3158bd5f642c0cab22fbf9e3148181497b3e85386ebe4d4819620"
curve := tss.S256()
root, err := NewExtendedKeyFromString(master, curve)
if err != nil {
t.Fatal(err)
}
if root.PublicKey.Curve != curve || !curve.IsOnCurve(root.X, root.Y) {
t.Fatal("parsed key did not preserve the ECDSA public key contract")
}
curveCopy := *btcec.S256()
withCurveCopy, err := NewExtendedKeyFromString(master, &curveCopy)
if err != nil {
t.Fatal(err)
}
if withCurveCopy.Curve != &curveCopy || withCurveCopy.String() != master {
t.Fatal("parsed key did not retain the supplied curve instance")
}
delta, child, err := DeriveChildKeyFromHierarchy([]uint32{12, 209, 3}, root, curve.Params().N, curve)
if err != nil {
t.Fatal(err)
}
if child.String() != wantChild || delta.Text(16) != wantDelta {
t.Fatalf("hierarchy differs from legacy output: child %s, delta %x", child, delta)
}
}

func TestPublicDerivation(t *testing.T) {
// port from https://github.com/btcsuite/btcutil/blob/master/hdkeychain/extendedkey_test.go
// The public extended keys for test vectors in [BIP32].
Expand Down
64 changes: 64 additions & 0 deletions crypto/ecpoint_compatibility_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
package crypto_test

import (
"encoding/hex"
"encoding/json"
"math/big"
"testing"

"github.com/bnb-chain/tss-lib/crypto"
"github.com/bnb-chain/tss-lib/tss"
)

// These ordinary public-point outputs were captured with the legacy btcec
// dependency at c26ffa870fd8 before migrating to btcec/v2.
func TestSecp256k1LegacyPointCompatibility(t *testing.T) {
curve := tss.S256()
point := crypto.ScalarBaseMult(curve, big.NewInt(42))
added, err := point.Add(crypto.ScalarBaseMult(curve, big.NewInt(17)))
if err != nil {
t.Fatal(err)
}
for _, test := range []struct {
name string
point *crypto.ECPoint
x, y string
}{
{"base multiply", point, "fe8d1eb1bcb3432b1db5833ff5f2226d9cb5e65cee430558c18ed3a3c86ce1af", "7b158f244cd0de2134ac7c1d371cffbfae4db40801a2572e531c573cda9b5b4"},
{"add", added, "7635ca72d7e8432c338ec53cd12220bc01c48685e24f7dc8c602a7746998e435", "91b649609489d613d1d5e590f78e6d74ecfc061d57048bad9e76f302c5b9c61"},
{"multiply", point.ScalarMult(big.NewInt(17)), "13a5fa6920629fd9f14541b803f64baa67f043fbc883ea787722de0f68d8fbe5", "76cd800492f816f4b7b8c2c55d3a4022d9498094932406fc6d2159c7eb06ac70"},
} {
t.Run(test.name, func(t *testing.T) {
if test.point == nil || test.point.X().Text(16) != test.x || test.point.Y().Text(16) != test.y {
t.Fatal("point differs from legacy output")
}
pub := test.point.ToECDSAPubKey()
if pub.Curve != curve || pub.X.Cmp(test.point.X()) != 0 || pub.Y.Cmp(test.point.Y()) != 0 {
t.Fatal("ECDSA public key conversion changed")
}
})
}

const legacyJSON = `{"Curve":"secp256k1","Coords":[115136800820456833737994126771386015026287095034625623644186278108926690779567,3479535755779840016334846590594739014278212596066547564422106861430200972724]}`
const legacyGob = "2100000002fe8d1eb1bcb3432b1db5833ff5f2226d9cb5e65cee430558c18ed3a3c86ce1af210000000207b158f244cd0de2134ac7c1d371cffbfae4db40801a2572e531c573cda9b5b4"
encoded, err := json.Marshal(point)
if err != nil || string(encoded) != legacyJSON {
t.Fatalf("JSON differs from legacy output: %s, %v", encoded, err)
}
var fromJSON crypto.ECPoint
if err := json.Unmarshal([]byte(legacyJSON), &fromJSON); err != nil || !point.Equals(&fromJSON) {
t.Fatalf("legacy JSON could not be restored: %v", err)
}
encoded, err = point.GobEncode()
if err != nil || hex.EncodeToString(encoded) != legacyGob {
t.Fatalf("Gob differs from legacy output: %x, %v", encoded, err)
}
legacyBytes, err := hex.DecodeString(legacyGob)
if err != nil {
t.Fatal(err)
}
var fromGob crypto.ECPoint
if err := fromGob.GobDecode(legacyBytes); err != nil || !point.Equals(&fromGob) {
t.Fatalf("legacy Gob could not be restored: %v", err)
}
}
6 changes: 3 additions & 3 deletions crypto/ecpoint_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ import (
"reflect"
"testing"

"github.com/btcsuite/btcd/btcec"
"github.com/btcsuite/btcd/btcec/v2"
"github.com/stretchr/testify/assert"

. "github.com/bnb-chain/tss-lib/crypto"
Expand Down Expand Up @@ -146,10 +146,10 @@ func TestS256EcpointJsonSerialization(t *testing.T) {

pubKeyBytes, err := hex.DecodeString("03935336acb03b2b801d8f8ac5e92c56c4f6e93319901fdfffba9d340a874e2879")
assert.NoError(t, err)
pbk, err := btcec.ParsePubKey(pubKeyBytes, btcec.S256())
pbk, err := btcec.ParsePubKey(pubKeyBytes)
assert.NoError(t, err)

point, err := NewECPoint(ec, pbk.X, pbk.Y)
point, err := NewECPoint(ec, pbk.X(), pbk.Y())
assert.NoError(t, err)
bz, err := json.Marshal(point)
assert.NoError(t, err)
Expand Down
69 changes: 69 additions & 0 deletions ecdsa/keygen/save_data_compatibility_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
package keygen_test

import (
"bytes"
"encoding/gob"
"encoding/hex"
"encoding/json"
"io/ioutil"
"math/big"
"testing"

"github.com/bnb-chain/tss-lib/crypto"
"github.com/bnb-chain/tss-lib/ecdsa/keygen"
"github.com/bnb-chain/tss-lib/tss"
)

func TestLegacySaveDataSerialization(t *testing.T) {
point := crypto.ScalarBaseMult(tss.S256(), big.NewInt(42))
want := keygen.LocalPartySaveData{
Ks: []*big.Int{big.NewInt(1)}, BigXj: []*crypto.ECPoint{point}, ECDSAPub: point,
}
legacyJSON, err := ioutil.ReadFile("testdata/save_data_legacy_btcec.json")
if err != nil {
t.Fatal(err)
}
encoded, err := json.Marshal(want)
if err != nil || !bytes.Equal(encoded, bytes.TrimSpace(legacyJSON)) {
t.Fatalf("save-data JSON differs from legacy output: %v", err)
}
legacyHex, err := ioutil.ReadFile("testdata/save_data_legacy_btcec.gob.hex")
if err != nil {
t.Fatal(err)
}
legacyGob, err := hex.DecodeString(string(bytes.TrimSpace(legacyHex)))
if err != nil {
t.Fatal(err)
}
for _, format := range []string{"json", "gob"} {
t.Run(format, func(t *testing.T) {
var restored keygen.LocalPartySaveData
var err error
if format == "json" {
err = json.Unmarshal(legacyJSON, &restored)
} else {
err = gob.NewDecoder(bytes.NewReader(legacyGob)).Decode(&restored)
}
if err != nil {
t.Fatal(err)
}
if len(restored.Ks) != 1 || restored.Ks[0].Cmp(big.NewInt(1)) != 0 ||
len(restored.BigXj) != 1 || !point.Equals(restored.BigXj[0]) || !point.Equals(restored.ECDSAPub) {
t.Fatal("restored save data differs from legacy output")
}
if !tss.SameCurve(restored.BigXj[0].Curve(), tss.S256()) || !tss.SameCurve(restored.ECDSAPub.Curve(), tss.S256()) {
t.Fatal("restored save-data points lost their curve registration")
}
if format == "gob" {
var buf bytes.Buffer
if err := gob.NewEncoder(&buf).Encode(restored); err != nil {
t.Fatal(err)
}
var roundTrip keygen.LocalPartySaveData
if err := gob.NewDecoder(&buf).Decode(&roundTrip); err != nil || !point.Equals(roundTrip.ECDSAPub) {
t.Fatalf("save-data Gob round trip failed: %v", err)
}
}
})
}
}
12 changes: 12 additions & 0 deletions ecdsa/keygen/testdata/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
The `save_data_legacy_btcec` files contain a synthetic `LocalPartySaveData`
value encoded at commit `86bd1a3` with the original btcec dependency
`github.com/btcsuite/btcd@v0.0.0-20190629003639-c26ffa870fd8`, using Go 1.26.0.
They contain no signing secrets. The value has `Ks = [1]`, `BigXj = [42*G]`,
and `ECDSAPub = 42*G`; all other fields have their zero values. The Gob file
is hex-encoded for reviewability.

These fixed fixtures check that the btcec/v2 migration can read previously
saved JSON and Gob data. The test also checks unchanged JSON output and a
new Gob round trip. Exact Gob stream bytes can depend on type registration
order, so only the point's custom Gob payload is compared byte for byte in
the crypto package.
1 change: 1 addition & 0 deletions ecdsa/keygen/testdata/save_data_legacy_btcec.gob.hex
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
ff967f030101124c6f63616c5061727479536176654461746101ff80000109010e4c6f63616c507265506172616d7301ff8200010c4c6f63616c5365637265747301ff8a0001024b7301ff8c0001074e54696c64656a01ff8c00010348316a01ff8c00010348326a01ff8c000105426967586a01ff9000010b5061696c6c696572504b7301ff92000108454344534150756201ff8e0000006eff810301010e4c6f63616c507265506172616d7301ff82000108010a5061696c6c696572534b01ff840001074e54696c64656901ff8800010348316901ff8800010348326901ff88000105416c70686101ff880001044265746101ff880001015001ff880001015101ff880000003eff830301010a507269766174654b657901ff8400010301095075626c69634b657901ff860001074c616d6264614e01ff880001045068694e01ff880000001eff85030101095075626c69634b657901ff8600010101014e01ff880000000aff87050102ff940000002fff890301010c4c6f63616c5365637265747301ff8a0001020102586901ff880001075368617265494401ff8800000019ff8b0201010a5b5d2a6269672e496e7401ff8c0001ff88000020ff8f020101115b5d2a63727970746f2e4543506f696e7401ff900001ff8e00000aff8d050102ff9600000024ff91020101155b5d2a7061696c6c6965722e5075626c69634b657901ff920001ff860000ffa5ff8001000100010102020104014a2100000002fe8d1eb1bcb3432b1db5833ff5f2226d9cb5e65cee430558c18ed3a3c86ce1af210000000207b158f244cd0de2134ac7c1d371cffbfae4db40801a2572e531c573cda9b5b4024a2100000002fe8d1eb1bcb3432b1db5833ff5f2226d9cb5e65cee430558c18ed3a3c86ce1af210000000207b158f244cd0de2134ac7c1d371cffbfae4db40801a2572e531c573cda9b5b400
1 change: 1 addition & 0 deletions ecdsa/keygen/testdata/save_data_legacy_btcec.json
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
{"PaillierSK":null,"NTildei":null,"H1i":null,"H2i":null,"Alpha":null,"Beta":null,"P":null,"Q":null,"Xi":null,"ShareID":null,"Ks":[1],"NTildej":null,"H1j":null,"H2j":null,"BigXj":[{"Curve":"secp256k1","Coords":[115136800820456833737994126771386015026287095034625623644186278108926690779567,3479535755779840016334846590594739014278212596066547564422106861430200972724]}],"PaillierPKs":null,"ECDSAPub":{"Curve":"secp256k1","Coords":[115136800820456833737994126771386015026287095034625623644186278108926690779567,3479535755779840016334846590594739014278212596066547564422106861430200972724]}}
2 changes: 1 addition & 1 deletion ecdsa/signing/local_party_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ import (
"sync/atomic"
"testing"

"github.com/btcsuite/btcd/btcec"
"github.com/btcsuite/btcd/btcec/v2"
"github.com/ipfs/go-log"
"github.com/stretchr/testify/assert"

Expand Down
10 changes: 7 additions & 3 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -5,19 +5,22 @@ go 1.25.7
toolchain go1.26.8

require (
github.com/btcsuite/btcd v0.0.0-20190629003639-c26ffa870fd8
github.com/btcsuite/btcutil v0.0.0-20190425235716-9e5f4b9a998d
github.com/btcsuite/btcd v0.24.2
github.com/btcsuite/btcd/btcec/v2 v2.2.0
github.com/btcsuite/btcd/btcutil v1.1.5
github.com/hashicorp/go-multierror v1.0.0
github.com/ipfs/go-log v0.0.1
github.com/otiai10/primes v0.0.0-20180210170552-f6d2a1ba97c4
github.com/pkg/errors v0.8.1
github.com/stretchr/testify v1.3.0
github.com/stretchr/testify v1.8.4
golang.org/x/crypto v0.52.0
google.golang.org/protobuf v1.33.0
)

require (
github.com/btcsuite/btcd/chaincfg/chainhash v1.1.0 // indirect
github.com/davecgh/go-spew v1.1.1 // indirect
github.com/decred/dcrd/dcrec/secp256k1/v4 v4.0.1 // indirect
github.com/gogo/protobuf v1.2.1 // indirect
github.com/hashicorp/errwrap v1.0.0 // indirect
github.com/mattn/go-colorable v0.1.2 // indirect
Expand All @@ -27,4 +30,5 @@ require (
github.com/pmezard/go-difflib v1.0.0 // indirect
github.com/whyrusleeping/go-logging v0.0.0-20170515211332-0457bb6b88fc // indirect
golang.org/x/sys v0.45.0 // indirect
gopkg.in/yaml.v3 v3.0.1 // indirect
)
Loading
Loading