Skip to content
Merged
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
2 changes: 1 addition & 1 deletion cmd/mpcium/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ import (
)

const (
Version = "0.3.5"
Version = "0.4.0"
DefaultBackupPeriodSeconds = 300 // (5 minutes)
)

Expand Down
2 changes: 1 addition & 1 deletion e2e/cmd/generate-preparams/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ import (
"path/filepath"
"time"

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

const numNodes = 3
Expand Down
5 changes: 3 additions & 2 deletions e2e/go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ module github.com/fystack/mpcium/e2e
go 1.25.8

require (
github.com/bnb-chain/tss-lib/v2 v2.0.2
github.com/bnb-chain/tss-lib/v3 v3.0.1
github.com/dgraph-io/badger/v4 v4.9.0
github.com/fystack/mpcium v0.0.0-00010101000000-000000000000
github.com/google/uuid v1.6.0
Expand All @@ -15,6 +15,7 @@ require (

require (
filippo.io/age v1.3.1 // indirect
filippo.io/bigmod v0.1.0 // indirect
filippo.io/hpke v0.4.0 // indirect
github.com/agl/ed25519 v0.0.0-20200225211852-fd4d107ace12 // indirect
github.com/armon/go-metrics v0.4.1 // indirect
Expand Down Expand Up @@ -104,4 +105,4 @@ replace github.com/fystack/mpcium => ../

replace github.com/agl/ed25519 => github.com/binance-chain/edwards25519 v0.0.0-20200305024217-f36fc4b53d43

replace github.com/bnb-chain/tss-lib/v2 => github.com/fystack/tss-lib/v2 v2.0.3
replace github.com/bnb-chain/tss-lib/v3 => github.com/fystack/tss-lib/v3 v3.0.1
85 changes: 4 additions & 81 deletions e2e/go.sum

Large diffs are not rendered by default.

8 changes: 4 additions & 4 deletions examples/hdwallet/eddsa/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,8 +11,8 @@ import (
"syscall"
"time"

tsscrypto "github.com/bnb-chain/tss-lib/v2/crypto"
"github.com/bnb-chain/tss-lib/v2/tss"
tsscrypto "github.com/bnb-chain/tss-lib/v3/crypto"
"github.com/bnb-chain/tss-lib/v3/tss"
"github.com/btcsuite/btcutil/base58"
"github.com/decred/dcrd/dcrec/edwards/v2"
"github.com/fystack/mpcium/pkg/ckdutil"
Expand Down Expand Up @@ -413,8 +413,8 @@ func deriveChildPublicKeyEd25519ViaTSS(masterPubKey []byte, chainCodeHex string,

childPub := edwards.PublicKey{
Curve: tss.Edwards(),
X: childKey.PublicKey.X(),
Y: childKey.PublicKey.Y(),
X: childKey.PublicKey.X,
Y: childKey.PublicKey.Y,
}

return childPub.SerializeCompressed(), nil
Expand Down
5 changes: 3 additions & 2 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ require (
github.com/aws/aws-sdk-go-v2/config v1.32.7
github.com/aws/aws-sdk-go-v2/credentials v1.19.7
github.com/aws/aws-sdk-go-v2/service/kms v1.49.5
github.com/bnb-chain/tss-lib/v2 v2.0.2
github.com/bnb-chain/tss-lib/v3 v3.0.1
github.com/btcsuite/btcd v0.25.0
github.com/btcsuite/btcd/btcec/v2 v2.3.6
github.com/btcsuite/btcutil v1.0.2
Expand All @@ -28,6 +28,7 @@ require (
)

require (
filippo.io/bigmod v0.1.0 // indirect
filippo.io/hpke v0.4.0 // indirect
github.com/agl/ed25519 v0.0.0-20200225211852-fd4d107ace12 // indirect
github.com/armon/go-metrics v0.4.1 // indirect
Expand Down Expand Up @@ -103,4 +104,4 @@ require (

replace github.com/agl/ed25519 => github.com/binance-chain/edwards25519 v0.0.0-20200305024217-f36fc4b53d43

replace github.com/bnb-chain/tss-lib/v2 => github.com/fystack/tss-lib/v2 v2.0.3
replace github.com/bnb-chain/tss-lib/v3 => github.com/fystack/tss-lib/v3 v3.0.1
85 changes: 4 additions & 81 deletions go.sum

Large diffs are not rendered by default.

8 changes: 4 additions & 4 deletions pkg/ckdutil/child_derivation_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,8 @@ import (
"encoding/hex"
"testing"

tsscrypto "github.com/bnb-chain/tss-lib/v2/crypto"
"github.com/bnb-chain/tss-lib/v2/tss"
tsscrypto "github.com/bnb-chain/tss-lib/v3/crypto"
"github.com/bnb-chain/tss-lib/v3/tss"
"github.com/btcsuite/btcd/btcec/v2"
"github.com/decred/dcrd/dcrec/edwards/v2"
"github.com/fystack/mpcium/pkg/mpc"
Expand Down Expand Up @@ -42,7 +42,7 @@ func TestEd25519StandaloneMatchesTSS(t *testing.T) {
_, tssChild, err := ckd.Derive("wallet-ed25519-test", masterPoint, path, tss.Edwards())
require.NoErrorf(t, err, "tss derivation failed at index %d", i)

tssPub := edwards.PublicKey{Curve: curve, X: tssChild.PublicKey.X(), Y: tssChild.PublicKey.Y()}
tssPub := edwards.PublicKey{Curve: curve, X: tssChild.PublicKey.X, Y: tssChild.PublicKey.Y}
require.Equalf(t, tssPub.SerializeCompressed(), localChild, "pubkey mismatch at index %d", i)
}
}
Expand Down Expand Up @@ -73,7 +73,7 @@ func TestSecp256k1StandaloneMatchesTSS(t *testing.T) {
_, tssChild, err := ckd.Derive("wallet-secp-test", masterPoint, path, tss.S256())
require.NoErrorf(t, err, "tss derivation failed at index %d", i)

tssChildBytes := serializeCompressed(tssChild.PublicKey.X(), tssChild.PublicKey.Y())
tssChildBytes := serializeCompressed(tssChild.PublicKey.X, tssChild.PublicKey.Y)
require.Equalf(t, tssChildBytes, localChild, "pubkey mismatch at index %d", i)
}
}
71 changes: 71 additions & 0 deletions pkg/ckdutil/golden_compat_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
package ckdutil

import (
"encoding/hex"
"testing"

tsscrypto "github.com/bnb-chain/tss-lib/v3/crypto"
"github.com/bnb-chain/tss-lib/v3/tss"
"github.com/btcsuite/btcd/btcec/v2"
"github.com/decred/dcrd/dcrec/edwards/v2"
"github.com/fystack/mpcium/pkg/mpc"
"github.com/stretchr/testify/require"
)

// goldenChainCode is a fixed chain code used to make the derivation outputs below
// fully deterministic and independent of any wallet state.
const goldenChainCode = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f"

// TestCKDGoldenVectors pins the exact compressed child public keys produced by
// mpc.CKD.Derive for a fixed master key (curve generator G), chain code and set
// of BIP32 paths.
//
// Why this test exists:
// Child wallet addresses are derived deterministically from the master public
// key + chain code via tss-lib's CKD. A change in the tss-lib CKD algorithm
// (for example the modulo-N reduction of IL that was introduced in the v2->v3
// bump for Edwards curves) silently changes every derived address, which would
// make funds sent to previously-advertised addresses unspendable. These golden
// vectors were captured against github.com/fystack/tss-lib/v3 v3.0.1. If a
// future dependency bump changes any value here, this test MUST fail so the
// address-compatibility impact is reviewed explicitly rather than shipped
// silently.
func TestCKDGoldenVectors(t *testing.T) {
ckd, err := mpc.NewCKDFromHex(goldenChainCode)
require.NoError(t, err)

t.Run("secp256k1", func(t *testing.T) {
s := btcec.S256()
master, err := tsscrypto.NewECPoint(s, s.Params().Gx, s.Params().Gy)
require.NoError(t, err)

cases := map[string][]uint32{
"0250390820cfe4ddbba5f230b99288b194177e928896802d5b3a745339ed55805f": {44, 60, 0, 0, 0},
"02c8c491ebdaa1b7576cc3b72c457dad089e954a45f0e2d1b4006600cd72085194": {44, 60, 0, 0, 7},
}
for want, path := range cases {
_, ek, err := ckd.Derive("golden-secp", master, path, tss.S256())
require.NoErrorf(t, err, "derive path %v", path)
got := hex.EncodeToString(serializeCompressed(ek.PublicKey.X, ek.PublicKey.Y))
require.Equalf(t, want, got, "secp256k1 child pubkey drift at path %v", path)
}
})

t.Run("ed25519", func(t *testing.T) {
e := edwards.Edwards()
master, err := tsscrypto.NewECPoint(e, e.Params().Gx, e.Params().Gy)
require.NoError(t, err)

cases := map[string][]uint32{
"cf7d5569333be69b5488e36dd2ee07cd7f4b068a287638d02a1958cd64011a64": {44, 501, 0, 0},
"1b36b2acad34ac48134cd6f1fce6e1e9be975e6f33dfc39888aaee23e4918d6c": {44, 501, 7, 0},
}
for want, path := range cases {
_, ek, err := ckd.Derive("golden-eddsa", master, path, tss.Edwards())
require.NoErrorf(t, err, "derive path %v", path)
pk := edwards.PublicKey{Curve: e, X: ek.PublicKey.X, Y: ek.PublicKey.Y}
got := hex.EncodeToString(pk.SerializeCompressed())
require.Equalf(t, want, got, "ed25519 child pubkey drift at path %v", path)
}
})
}
46 changes: 42 additions & 4 deletions pkg/eventconsumer/event_consumer.go
Original file line number Diff line number Diff line change
Expand Up @@ -159,6 +159,15 @@

walletID := msg.WalletID

// Bind this ceremony's ZK proofs to a session-unique nonce, derived from the
// already-verified initiator request so every node computes the same value
// without a coordination round.
sessionNonce, err := mpc.SessionNonceFromInitiator(mpc.NonceDomainKeygen, &msg)
if err != nil {
ec.handleKeygenSessionError(walletID, err, "Failed to derive session nonce", natMsg)

Check failure on line 167 in pkg/eventconsumer/event_consumer.go

View check run for this annotation

SonarQubeCloud / SonarCloud Code Analysis

Define a constant instead of duplicating this literal "Failed to derive session nonce" 4 times.

See more on https://sonarcloud.io/project/issues?id=fystack_mpcium&issues=AaCB92F4YM2c8CCdS-kA&open=AaCB92F4YM2c8CCdS-kA&pullRequest=164
return
}

// Attempt to get previously stored wallet creation result (if any) by the wallet ID
storedWalletCreationResult, storedWalletCreationResultError := ec.node.GetWalletCreationResult(walletID)

Expand Down Expand Up @@ -194,18 +203,24 @@
}
defer ec.removeSession(walletID, "keygen")

ecdsaSession, err := ec.node.CreateKeyGenSession(mpc.SessionTypeECDSA, walletID, ec.mpcThreshold, ec.genKeyResultQueue)
ecdsaSession, err := ec.node.CreateKeyGenSession(mpc.SessionTypeECDSA, walletID, ec.mpcThreshold, ec.genKeyResultQueue, sessionNonce)
if err != nil {
ec.handleKeygenSessionError(walletID, err, "Failed to create ECDSA key generation session", natMsg)
return
}
eddsaSession, err := ec.node.CreateKeyGenSession(mpc.SessionTypeEDDSA, walletID, ec.mpcThreshold, ec.genKeyResultQueue)
eddsaSession, err := ec.node.CreateKeyGenSession(mpc.SessionTypeEDDSA, walletID, ec.mpcThreshold, ec.genKeyResultQueue, sessionNonce)
if err != nil {
ec.handleKeygenSessionError(walletID, err, "Failed to create EdDSA key generation session", natMsg)
return
}
ecdsaSession.Init()
eddsaSession.Init()
if err := ecdsaSession.Init(); err != nil {
ec.handleKeygenSessionError(walletID, err, "Failed to initialize ECDSA key generation session", natMsg)
return
}
if err := eddsaSession.Init(); err != nil {
ec.handleKeygenSessionError(walletID, err, "Failed to initialize EdDSA key generation session", natMsg)
return
}

ctxEcdsa, doneEcdsa := context.WithCancel(baseCtx)
ctxEddsa, doneEddsa := context.WithCancel(baseCtx)
Expand Down Expand Up @@ -436,6 +451,19 @@
return
}

sessionNonce, err := mpc.SessionNonceFromInitiator(mpc.NonceDomainSigning, &msg)
if err != nil {
ec.handleSigningSessionError(
msg.WalletID,
msg.TxID,
msg.NetworkInternalCode,
err,
"Failed to derive session nonce",
natMsg,
)
return
}

var session mpc.SigningSession
idempotentKey := composeSigningIdempotentKey(msg.TxID, natMsg)
resultTopic := event.SigningResultSubject(natMsg.Header.Get(event.ClientIDHeader))
Expand All @@ -451,6 +479,7 @@
ec.signingResultQueue,
msg.DerivationPath,
idempotentKey,
sessionNonce,
)
case types.KeyTypeEd25519:
session, sessionErr = ec.node.CreateSigningSession(
Expand All @@ -462,6 +491,7 @@
ec.signingResultQueue,
msg.DerivationPath,
idempotentKey,
sessionNonce,
)
default:
sessionErr = fmt.Errorf("unsupported key type: %v", msg.KeyType)
Expand Down Expand Up @@ -676,6 +706,13 @@
return
}

sessionNonce, err := mpc.SessionNonceFromInitiator(mpc.NonceDomainReshare, &msg)
if err != nil {
logger.Error("Failed to derive session nonce", err)
ec.handleReshareSessionError(msg.SessionID, walletID, keyType, msg.NewThreshold, err, "Failed to derive session nonce", natMsg)
return
}

createSession := func(isNewPeer bool) (mpc.ReshareSession, error) {
return ec.node.CreateReshareSession(
sessionType,
Expand All @@ -684,6 +721,7 @@
msg.NodeIDs,
isNewPeer,
ec.reshareResultQueue,
sessionNonce,
)
}

Expand Down
2 changes: 1 addition & 1 deletion pkg/identity/identity.go
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ import (
"syscall"

"filippo.io/age"
"github.com/bnb-chain/tss-lib/v2/tss"
"github.com/bnb-chain/tss-lib/v3/tss"
"golang.org/x/term"

"github.com/fystack/mpcium/pkg/common/pathutil"
Expand Down
34 changes: 21 additions & 13 deletions pkg/mpc/ckd.go
Original file line number Diff line number Diff line change
@@ -1,16 +1,17 @@
package mpc

import (
"crypto/ecdsa"
"crypto/elliptic"
"encoding/hex"
"errors"
"fmt"
"math/big"

"github.com/bnb-chain/tss-lib/v2/crypto"
"github.com/bnb-chain/tss-lib/v2/crypto/ckd"
ecdsaKeygen "github.com/bnb-chain/tss-lib/v2/ecdsa/keygen"
eddsaKeygen "github.com/bnb-chain/tss-lib/v2/eddsa/keygen"
"github.com/bnb-chain/tss-lib/v3/crypto"
"github.com/bnb-chain/tss-lib/v3/crypto/ckd"
ecdsaKeygen "github.com/bnb-chain/tss-lib/v3/ecdsa/keygen"
eddsaKeygen "github.com/bnb-chain/tss-lib/v3/eddsa/keygen"
"github.com/btcsuite/btcd/chaincfg"
)

Expand Down Expand Up @@ -69,7 +70,12 @@ func (c *CKD) Derive(walletID string, masterPub *crypto.ECPoint, path []uint32,
func (c *CKD) derivingPubkeyFromPath(masterPub *crypto.ECPoint, chainCode []byte, path []uint32, ec elliptic.Curve) (*big.Int, *ckd.ExtendedKey, error) {
net := &chaincfg.MainNetParams
parent := &ckd.ExtendedKey{
PublicKey: masterPub,
// tss-lib v3 changed ExtendedKey.PublicKey from *crypto.ECPoint to ecdsa.PublicKey.
PublicKey: ecdsa.PublicKey{
Curve: masterPub.Curve(),
X: masterPub.X(),
Y: masterPub.Y(),
},
Depth: 0,
ChildIndex: 0,
ChainCode: chainCode,
Expand All @@ -85,15 +91,16 @@ func (c *CKD) derivingPubkeyFromPath(masterPub *crypto.ECPoint, chainCode []byte
}

// ECDSAUpdateSinglePublicKeyAndAdjustBigXj updates ECDSA public key and BigXj.
func (c *CKD) ECDSAUpdateSinglePublicKeyAndAdjustBigXj(delta *big.Int, key *ecdsaKeygen.LocalPartySaveData, childPk *crypto.ECPoint, ec elliptic.Curve) error {
func (c *CKD) ECDSAUpdateSinglePublicKeyAndAdjustBigXj(delta *big.Int, key *ecdsaKeygen.LocalPartySaveData, childPk ecdsa.PublicKey, ec elliptic.Curve) error {
if key == nil {
return ErrNilKey
}
if childPk == nil {
return ErrNilPoint
childPoint, err := crypto.NewECPoint(ec, childPk.X, childPk.Y)
if err != nil {
return fmt.Errorf("invalid child public key: %w", err)
}
gDelta := crypto.ScalarBaseMult(ec, delta)
key.ECDSAPub = childPk
key.ECDSAPub = childPoint
for i := range key.BigXj {
updated, err := key.BigXj[i].Add(gDelta)
if err != nil {
Expand All @@ -105,15 +112,16 @@ func (c *CKD) ECDSAUpdateSinglePublicKeyAndAdjustBigXj(delta *big.Int, key *ecds
}

// EDDSAUpdateSinglePublicKeyAndAdjustBigXj updates EdDSA public key and BigXj.
func (c *CKD) EDDSAUpdateSinglePublicKeyAndAdjustBigXj(delta *big.Int, key *eddsaKeygen.LocalPartySaveData, childPk *crypto.ECPoint, ec elliptic.Curve) error {
func (c *CKD) EDDSAUpdateSinglePublicKeyAndAdjustBigXj(delta *big.Int, key *eddsaKeygen.LocalPartySaveData, childPk ecdsa.PublicKey, ec elliptic.Curve) error {
if key == nil {
return ErrNilKey
}
if childPk == nil {
return ErrNilPoint
childPoint, err := crypto.NewECPoint(ec, childPk.X, childPk.Y)
if err != nil {
return fmt.Errorf("invalid child public key: %w", err)
}
gDelta := crypto.ScalarBaseMult(ec, delta)
key.EDDSAPub = childPk
key.EDDSAPub = childPoint
for i := range key.BigXj {
updated, err := key.BigXj[i].Add(gDelta)
if err != nil {
Expand Down
Loading
Loading