mpc

package
v0.4.0 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Sep 8, 2026 License: Apache-2.0 Imports: 47 Imported by: 0

Documentation

Index

Constants

View Source
const (
	KEYGEN1               = "KGRound1Message"
	KEYGEN2aUnicast       = "KGRound2Message1"
	KEYGEN2b              = "KGRound2Message2"
	KEYGEN3               = "KGRound3Message"
	KEYSIGN1aUnicast      = "SignRound1Message1"
	KEYSIGN1b             = "SignRound1Message2"
	KEYSIGN2Unicast       = "SignRound2Message"
	KEYSIGN3              = "SignRound3Message"
	KEYSIGN4              = "SignRound4Message"
	KEYSIGN5              = "SignRound5Message"
	KEYSIGN6              = "SignRound6Message"
	KEYSIGN7              = "SignRound7Message"
	KEYSIGN8              = "SignRound8Message"
	KEYSIGN9              = "SignRound9Message"
	KEYRESHARING1Unicast  = "DGRound1Message"
	KEYRESHARING2aUnicast = "DGRound2Message1"
	KEYRESHARING2bUnicast = "DGRound2Message2"
	KEYRESHARING3aUnicast = "DGRound3Message1"
	KEYRESHARING3b        = "DGRound3Message2"
	KEYRESHARING4a        = "DGRound4Message1"
	KEYRESHARING4bUnicast = "DGRound4Message2"

	TSSKEYGENROUNDS  = 4
	TSSKEYSIGNROUNDS = 10
)
View Source
const (
	EDDSA_KEYGEN1            = "KGRound1Message"
	EDDSA_KEYGEN2aUnicast    = "KGRound2Message1"
	EDDSA_KEYGEN2b           = "KGRound2Message2"
	EDDSA_KEYSIGN1           = "SignRound1Message"
	EDDSA_KEYSIGN2           = "SignRound2Message"
	EDDSA_KEYSIGN3           = "SignRound3Message"
	EDDSA_RESHARING1         = "DGRound1Message"
	EDDSA_RESHARING2         = "DGRound2Message"
	EDDSA_RESHARING3aUnicast = "DGRound3Message1"
	EDDSA_RESHARING3bUnicast = "DGRound3Message2"
	EDDSA_RESHARING4         = "DGRound4Message"

	EDDSA_TSSKEYGENROUNDS  = 3
	EDDSA_TSSKEYSIGNROUNDS = 3
	EDDSA_RESHARINGROUNDS  = 4
)
View Source
const (
	ECDHExchangeTopic   = "ecdh:exchange"
	ECDHExchangeTimeout = 2 * time.Minute
)
View Source
const (
	PurposeKeygen  string = "keygen"
	PurposeSign    string = "sign"
	PurposeReshare string = "reshare"

	BackwardCompatibleVersion int = 0
	DefaultVersion            int = 1
)
View Source
const (
	TypeGenerateWalletResultFmt = "mpc.mpc_keygen_result.%s"
	TypeReshareWalletResultFmt  = "mpc.mpc_reshare_result.%s"
	TypeSigningResultFmt        = "mpc.mpc_signing_result.%s"

	SessionTypeECDSA SessionType = "session_ecdsa"
	SessionTypeEDDSA SessionType = "session_eddsa"

	// PeerReadyTimeout is the max time to wait for all peers to confirm
	// their subscriptions are active before starting the protocol.
	PeerReadyTimeout = 10 * time.Second
	// PeerReadyPollInterval is how often to retry the readiness check.
	PeerReadyPollInterval = 300 * time.Millisecond
)
View Source
const (
	ReadinessCheckPeriod = 1 * time.Second
)

Variables

View Source
var (
	ErrInvalidChainCode = errors.New("invalid chain code length")
	ErrNilKey           = errors.New("key cannot be nil")
	ErrNilPoint         = errors.New("point cannot be nil")
)
View Source
var (
	ErrNotEnoughParticipants = errors.New("Not enough participants to sign")
	ErrNotInParticipantList  = errors.New("Node is not in the participant list")
)
View Source
var ErrNilSessionNonce = errors.New("session nonce is required")

ErrNilSessionNonce is returned when a session is built without the nonce that GG20 session binding requires.

Functions

func ComposeReadyKey

func ComposeReadyKey(nodeID string) string

func IsReshareRound added in v0.3.0

func IsReshareRound(roundMsg string) bool

func NewECDHSession added in v0.3.2

func NewECDHSession(
	nodeID string,
	peerIDs []string,
	pubSub messaging.PubSub,
	identityStore identity.Store,
) *ecdhSession

func NewECDSAReshareSession added in v0.3.0

func NewECDSAReshareSession(
	walletID string,
	pubSub messaging.PubSub,
	direct messaging.DirectMessaging,
	participantPeerIDs []string,
	selfID *tss.PartyID,
	oldPartyIDs []*tss.PartyID,
	newPartyIDs []*tss.PartyID,
	threshold int,
	newThreshold int,
	preParams *keygen.LocalPreParams,
	kvstore kvstore.KVStore,
	keyinfoStore keyinfo.Store,
	resultQueue messaging.MessageQueue,
	identityStore identity.Store,
	newPeerIDs []string,
	isNewParty bool,
	version int,
	sessionNonce *big.Int,
) *ecdsaReshareSession

func NewEDDSAReshareSession added in v0.3.0

func NewEDDSAReshareSession(
	walletID string,
	pubSub messaging.PubSub,
	direct messaging.DirectMessaging,
	participantPeerIDs []string,
	selfID *tss.PartyID,
	oldPartyIDs []*tss.PartyID,
	newPartyIDs []*tss.PartyID,
	threshold int,
	newThreshold int,
	kvstore kvstore.KVStore,
	keyinfoStore keyinfo.Store,
	resultQueue messaging.MessageQueue,
	identityStore identity.Store,
	newPeerIDs []string,
	isNewParty bool,
	version int,
	sessionNonce *big.Int,
) *eddsaReshareSession

func NewRegistry

func NewRegistry(
	nodeID string,
	peerNodeIDs []string,
	consulKV infra.ConsulKV,
	directMessaging messaging.DirectMessaging,
	pubSub messaging.PubSub,
	identityStore identity.Store,
) *registry

func SessionNonceFromInitiator added in v0.4.0

func SessionNonceFromInitiator(domain NonceDomain, msg types.InitiatorMessage) (*big.Int, error)

SessionNonceFromInitiator derives the per-ceremony nonce that tss-lib v3 mixes into the SSID of every ZK proof, binding the proofs to this exact ceremony and preventing cross-session proof replay.

It is SHA-256(domain || 0x1f || initiatorPayload), where initiatorPayload is the exact byte string the initiator signed (msg.Raw()). Every node independently verifies the same signed request, so every node derives an identical nonce with no extra coordination round; the domain tag keeps keygen, signing and resharing nonces disjoint.

Per-ceremony uniqueness comes from the initiator payload:

  • keygen: the wallet ID
  • signing: key type + wallet ID + network + tx ID + tx + derivation path
  • reshare: the full resharing request, including its session ID

Note: a keygen retried for the same wallet ID re-derives the same nonce. That still binds proofs across distinct concurrent ceremonies (the property GG20 needs); strict per-attempt uniqueness would require a nonce field in the signed keygen request.

Types

type CKD added in v0.3.4

type CKD struct {
	// contains filtered or unexported fields
}

CKD handles Child Key Derivation (ENV-based)

func NewCKDFromHex added in v0.3.4

func NewCKDFromHex(hexStr string) (*CKD, error)

NewCKDFromHex creates CKD from a hex-encoded chain code string (32 bytes).

func (*CKD) Derive added in v0.3.4

func (c *CKD) Derive(walletID string, masterPub *crypto.ECPoint, path []uint32, curve elliptic.Curve) (*big.Int, *ckd.ExtendedKey, error)

Derive derives a child key from the master public key using the given path. Uses standard BIP32 derivation: same master key + same path = same child key. Each level in the path automatically gets its own chain code via HMAC(parent_chain_code, pubkey || index).

func (*CKD) ECDSAUpdateSinglePublicKeyAndAdjustBigXj added in v0.3.4

func (c *CKD) ECDSAUpdateSinglePublicKeyAndAdjustBigXj(delta *big.Int, key *ecdsaKeygen.LocalPartySaveData, childPk ecdsa.PublicKey, ec elliptic.Curve) error

ECDSAUpdateSinglePublicKeyAndAdjustBigXj updates ECDSA public key and BigXj.

func (*CKD) EDDSAUpdateSinglePublicKeyAndAdjustBigXj added in v0.3.4

func (c *CKD) EDDSAUpdateSinglePublicKeyAndAdjustBigXj(delta *big.Int, key *eddsaKeygen.LocalPartySaveData, childPk ecdsa.PublicKey, ec elliptic.Curve) error

EDDSAUpdateSinglePublicKeyAndAdjustBigXj updates EdDSA public key and BigXj.

func (*CKD) GetMasterChainCode added in v0.3.4

func (c *CKD) GetMasterChainCode() []byte

GetMasterChainCode returns a copy of the chain code.

type ECDHSession added in v0.3.2

type ECDHSession interface {
	ListenKeyExchange() error
	BroadcastPublicKey() error
	RemovePeer(peerID string)
	GetReadyPeersCount() int
	ErrChan() <-chan error
	Close() error
	OnKeyExchangeComplete(callback func())
}

type GetRoundFunc

type GetRoundFunc func(msg []byte, partyID *tss.PartyID, isBroadcast bool) (RoundInfo, error)

type ID

type ID string

type KeyComposerFn

type KeyComposerFn func(id string) string

type KeyGenSession added in v0.3.0

type KeyGenSession interface {
	Session

	Init() error
	GenerateKey(done func())
	GetPubKeyResult() []byte
	WaitForPeersReady() error
}

type KeyType

type KeyType string
const (
	KeyTypeSecp256k1 KeyType = "secp256k1"
	KeyTypeEd25519   KeyType = "ed25519"
)

type Node

type Node struct {
	// contains filtered or unexported fields
}

func NewNode

func NewNode(
	nodeID string,
	peerIDs []string,
	pubSub messaging.PubSub,
	direct messaging.DirectMessaging,
	kvstore kvstore.KVStore,
	keyinfoStore keyinfo.Store,
	peerRegistry PeerRegistry,
	identityStore identity.Store,
	ckd *CKD,
) *Node

func (*Node) Close

func (p *Node) Close()

func (*Node) CreateKeyGenSession

func (p *Node) CreateKeyGenSession(
	sessionType SessionType,
	walletID string,
	threshold int,
	resultQueue messaging.MessageQueue,
	sessionNonce *big.Int,
) (KeyGenSession, error)

func (*Node) CreateReshareSession added in v0.3.0

func (p *Node) CreateReshareSession(
	sessionType SessionType,
	walletID string,
	newThreshold int,
	newPeerIDs []string,
	isNewPeer bool,
	resultQueue messaging.MessageQueue,
	sessionNonce *big.Int,
) (ReshareSession, error)

func (*Node) CreateSigningSession

func (p *Node) CreateSigningSession(
	sessionType SessionType,
	walletID string,
	txID string,
	networkInternalCode string,
	resultTopic string,
	resultQueue messaging.MessageQueue,
	derivationPath []uint32,
	idempotentKey string,
	sessionNonce *big.Int,
) (SigningSession, error)

func (*Node) GetWalletCreationResult added in v0.4.0

func (p *Node) GetWalletCreationResult(walletID string) ([]byte, error)

func (*Node) ID

func (p *Node) ID() string

func (*Node) StoreWalletCreationResult added in v0.4.0

func (p *Node) StoreWalletCreationResult(walletID string, result []byte) error

type NonceDomain added in v0.4.0

type NonceDomain string

NonceDomain is a domain-separation tag folded into a session nonce so a nonce derived for one ceremony type can never be valid in another.

const (
	NonceDomainKeygen  NonceDomain = "mpcium/ssid-nonce/keygen/v1"
	NonceDomainSigning NonceDomain = "mpcium/ssid-nonce/signing/v1"
	NonceDomainReshare NonceDomain = "mpcium/ssid-nonce/reshare/v1"
)

type PeerRegistry

type PeerRegistry interface {
	Ready() error
	ArePeersReady() bool
	AreMajorityReady() bool
	WatchPeersReady()
	// Resign is called by the node when it is going to shutdown
	Resign() error
	GetReadyPeersCount() int64
	GetReadyPeersCountExcludeSelf() int64
	GetReadyPeersIncludeSelf() []string // get ready peers include self
	GetTotalPeersCount() int64

	OnPeerConnected(callback func(peerID string))
	OnPeerDisconnected(callback func(peerID string))
	OnPeerReConnected(callback func(peerID string))
}

type ReshareSession added in v0.3.0

type ReshareSession interface {
	Session
	Init() error
	Reshare(done func())
	GetPubKeyResult() []byte
	GetLegacyCommitteePeers() []string
	WaitForPeersReady() error
	Stop()
}

type RoundInfo

type RoundInfo struct {
	Index         int
	RoundMsg      string
	MsgIdentifier string
}

func GetEcdsaMsgRound

func GetEcdsaMsgRound(msg []byte, partyID *tss.PartyID, isBroadcast bool) (RoundInfo, error)

func GetEddsaMsgRound

func GetEddsaMsgRound(msg []byte, partyID *tss.PartyID, isBroadcast bool) (RoundInfo, error)

type Session

type Session interface {
	ListenToIncomingMessageAsync()
	ListenToPeersAsync(peerIDs []string)
	ErrChan() <-chan error
}

type SessionType

type SessionType string

type SigningSession

type SigningSession interface {
	Session

	Init(tx *big.Int) error
	Sign(onSuccess func(data []byte))
	// WaitForPeersReady verifies all peers have their subscriptions active
	// before starting the protocol. Replaces the fragile warmup sleep.
	WaitForPeersReady() error
	// Stop signals the session to terminate, allowing Sign() goroutines to exit.
	Stop()
	// Close cleans up subscriptions and sensitive data.
	Close() error
}

type TopicComposer

type TopicComposer struct {
	ComposeBroadcastTopic func() string
	ComposeDirectTopic    func(fromID string, toID string) string
}

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL