mpc

package
v1.0.2 Latest Latest
Warning

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

Go to latest
Published: Apr 15, 2026 License: Apache-2.0 Imports: 42 Imported by: 0

Documentation

Index

Constants

View Source
const (
	// DKG pair-setup rounds (Bob initiates, Alice responds)
	DklsDKGRound1 = "dkls_dkg_r1" // Bob → Alice  (Bob's random seed)
	DklsDKGRound2 = "dkls_dkg_r2" // Alice → Bob  (commitment + Alice's seed)
	DklsDKGRound3 = "dkls_dkg_r3" // Bob → Alice  (Bob's Schnorr proof)
	DklsDKGRound4 = "dkls_dkg_r4" // Alice → Bob  (Alice's revealed proof)
	DklsDKGRound5 = "dkls_dkg_r5" // Bob → Alice  (seed-OT round 1)
	DklsDKGRound6 = "dkls_dkg_r6" // Alice → Bob  (seed-OT round 2)
	DklsDKGRound7 = "dkls_dkg_r7" // Bob → Alice  (seed-OT round 3)
	DklsDKGRound8 = "dkls_dkg_r8" // Alice → Bob  (seed-OT round 4)
	DklsDKGRound9 = "dkls_dkg_r9" // Bob → Alice  (seed-OT round 5)

	// Signing rounds (Alice initiates)
	DklsSignRound1 = "dkls_sign_r1" // Alice → Bob  (Alice's random seed)
	DklsSignRound2 = "dkls_sign_r2" // Bob → Alice  (Bob's sign output)
	DklsSignRound3 = "dkls_sign_r3" // Alice → Bob  (Alice's sign message)

	// Refresh rounds (Alice initiates)
	DklsRefreshRound1 = "dkls_refresh_r1" // Alice → Bob  (Alice's addend k_A)
	DklsRefreshRound2 = "dkls_refresh_r2" // Bob → Alice  (Bob's addend + seed-OT r1)
	DklsRefreshRound3 = "dkls_refresh_r3" // Alice → Bob  (seed-OT r2)
	DklsRefreshRound4 = "dkls_refresh_r4" // Bob → Alice  (seed-OT r3)
	DklsRefreshRound5 = "dkls_refresh_r5" // Alice → Bob  (seed-OT r4)
	DklsRefreshRound6 = "dkls_refresh_r6" // Bob → Alice  (seed-OT r5)
)

ECDSA message-type constants for DKLS19 protocol messages. These are embedded in MpcMsg.MsgType so the receiver can route the payload to the correct protocol.Iterator instance.

View Source
const (
	// FROST DKG rounds
	FrostDKGRound1    = "frost_dkg_r1"     // all → all  (each participant's Round1 broadcast)
	FrostDKGRound1P2P = "frost_dkg_r1_p2p" // each → each (unicast Shamir share)
	FrostDKGRound2    = "frost_dkg_r2"     // all → all  (Round2 broadcast)

	// FROST signing rounds
	FrostSignRound1 = "frost_sign_r1" // all → all  (each signer's commitment)
	FrostSignRound2 = "frost_sign_r2" // all → all  (each signer's partial signature)

	// FROST resharing rounds
	FrostReshareRound1 = "frost_reshare_r1" // old → all  (old committee's round-1 outputs)
	FrostReshareRound2 = "frost_reshare_r2" // old → each  (refreshed Shamir shares)
	FrostReshareRound3 = "frost_reshare_r3" // new → all  (new committee acknowledgements)
)

EDDSA message-type constants for FROST protocol messages. These are embedded in MpcMsg.MsgType so the receiver can route the payload to the correct FROST participant instance.

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 DklsDKGRoundCount = 9

DklsDKGRoundCount is the number of rounds in a DKLS19 DKG pair-setup.

View Source
const DklsRefreshRoundCount = 6

DklsRefreshRoundCount is the number of rounds in a DKLS19 refresh session.

View Source
const DklsSignRoundCount = 3

DklsSignRoundCount is the number of rounds in a DKLS19 signing session.

View Source
const FrostDKGRoundCount = 2

FrostDKGRoundCount is the number of broadcast rounds in FROST DKG.

View Source
const FrostReshareRoundCount = 3

FrostReshareRoundCount is the number of rounds in FROST resharing.

View Source
const FrostSignRoundCount = 2

FrostSignRoundCount is the number of rounds in FROST signing.

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

Functions

func ComposeReadyKey

func ComposeReadyKey(nodeID string) string

func NewECDHSession

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

func NewECDSAReshareSession

func NewECDSAReshareSession(
	walletID string,
	nodeID string,
	oldPeerIDs []string,
	newPeerIDs []string,
	oldThreshold int,
	newThreshold int,
	pubSub messaging.PubSub,
	direct messaging.DirectMessaging,
	kvstore kvstore.KVStore,
	keyinfoStore keyinfo.Store,
	resultQueue messaging.MessageQueue,
	identityStore identity.Store,
	isNewPeer bool,
	oldVersion int,
) *ecdsaReshareSession

NewECDSAReshareSession constructs an ECDSA refresh session. All members of the new committee must call this; old-committee-only members may skip.

func NewEDDSAReshareSession

func NewEDDSAReshareSession(
	walletID string,
	nodeID string,
	oldPeerIDs []string,
	newPeerIDs []string,
	oldThreshold int,
	newThreshold int,
	pubSub messaging.PubSub,
	direct messaging.DirectMessaging,
	kvstore kvstore.KVStore,
	keyinfoStore keyinfo.Store,
	resultQueue messaging.MessageQueue,
	identityStore identity.Store,
	isNewPeer bool,
	oldVersion int,
) *eddsaReshareSession

NewEDDSAReshareSession constructs an EdDSA reshare session.

func NewRegistry

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

Types

type CKD

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

CKD handles Child Key Derivation (BIP32-style, curve-agnostic).

func NewCKDFromHex

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

NewCKDFromHex creates a CKD from a hex-encoded 32-byte chain code string.

func (*CKD) DeriveForCurve

func (c *CKD) DeriveForCurve(walletID string, pubKeyBytes []byte, path []uint32, curve *curves.Curve) (curves.Scalar, curves.Point, error)

DeriveForCurve derives a BIP32-style child scalar tweak and child public key from the given public key bytes and derivation path, using the kryptology curves.Scalar / curves.Point types.

pubKeyBytes may be:

  • 32 bytes → Ed25519 compressed point
  • 33 bytes → secp256k1 compressed point
  • 64 bytes → uncompressed X‖Y (secp256k1 stored without 0x04 prefix)
  • 65 bytes → uncompressed 0x04‖X‖Y (secp256k1)

Returns (totalTweak, childPublicKey, error). For ECDSA (secp256k1): only Alice adds the tweak to her signing share. For EdDSA (Ed25519): only the signer with participant ID 1 adds the tweak.

func (*CKD) GetMasterChainCode

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

GetMasterChainCode returns a copy of the chain code.

type DklsPairData

type DklsPairData struct {
	AliceMsg []byte `json:"alice,omitempty"` // encoded *protocol.Message from AliceDkg.Result
	BobMsg   []byte `json:"bob,omitempty"`   // encoded *protocol.Message from BobDkg.Result
}

DklsPairData holds one node's DKLS19 DKG output for a single signing pair. Exactly one of AliceMsg / BobMsg is set, depending on the node's role.

type ECDHSession

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

type ECDSAKeygenData

type ECDSAKeygenData struct {
	// GroupPublicKey is the secp256k1 group public key Q = x·G (64-byte X‖Y).
	GroupPublicKey []byte `json:"groupPublicKey"`

	// NodeIDs is the sorted list of all participant node IDs.
	// Position i (0-indexed) corresponds to FROST participant ID i+1.
	NodeIDs []string `json:"nodeIDs"`

	// ShamirShare is this node's raw Shamir share from FROST DKG.
	ShamirShare *sharing.ShamirShare `json:"shamirShare"`

	// Pairs maps pairKey(alice,bob) → per-pair DKLS19 DKG output.
	Pairs map[string]*DklsPairData `json:"pairs"`
}

ECDSAKeygenData is the per-wallet data persisted in BadgerDB after ECDSA keygen.

type EDDSAKeygenData

type EDDSAKeygenData struct {
	// GroupPublicKey is the Ed25519 group public key (32-byte compressed point).
	GroupPublicKey []byte `json:"groupPublicKey"`
	// NodeIDs is the sorted list of all participant node IDs.
	// Position i (0-indexed) corresponds to FROST participant ID i+1.
	NodeIDs []string `json:"nodeIDs"`
	// SkShareBytes is this node's FROST secret key share (32-byte scalar).
	SkShareBytes []byte `json:"skShare"`
	// VkShareBytes is this node's FROST verification key share (32-byte compressed point).
	VkShareBytes []byte `json:"vkShare"`
	// Threshold is t (signing requires t+1 participants).
	Threshold int `json:"threshold"`
}

EDDSAKeygenData is the per-wallet data persisted in BadgerDB after EdDSA keygen.

type EDDSAReshareSession

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

EDDSAReshareSession is the interface exposed to node.go.

type ID

type ID string

type KeyComposerFn

type KeyComposerFn func(id string) string

type KeyGenSession

type KeyGenSession interface {
	Session

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

KeyGenSession is the interface exposed to node.go.

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,
) (KeyGenSession, error)

func (*Node) CreateReshareSession

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

func (*Node) CreateSigningSession

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

func (*Node) ID

func (p *Node) ID() string

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

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

ReshareSession is the interface exposed to node.go.

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() error
	Stop()
	Close() error
}

SigningSession is the interface exposed to node.go.

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