mpcvm

package
v1.7.13 Latest Latest
Warning

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

Go to latest
Published: Jul 30, 2026 License: BSD-3-Clause Imports: 48 Imported by: 0

README

mpcvm — M-Chain

M-Chain is the MPC threshold-custody chain. chains/mpcvm is its VM: a plugin-loaded chain.ChainVM with genesis, validators, block production and replicated state.

It exists to hold the keys that custody bridged assets on external chains, and to do that on-chain instead of in an off-chain signer cluster.

  • vmID mpcvm = constants.MPCVMID, CB58 qCURact1n41FcoNBch8iMVBwc9AWie48D118ZNJ5tBdWrvryS. The plugin binary's filename must be that CB58 — that is how the node resolves a CreateChainTx's vmID to an implementation. A vmID is an immutable one-way door once a chain is created with it; TestVMID_IsCanonicalAndStable pins it and lists every declaration that must move together.
  • Genesis chain. M-Chain is in the P-Chain chain set at height 0 on every network (genesis/configs/*/mchain.json), tracked by validators from boot — not created later by a CreateChainTx someone has to remember to submit.
  • Per LP-134 / LP-7050 there is no T-Chain and no teleportvm: teleport IS bridgevm (B-Chain, LP-6000), and the FHE half of the retired ThresholdVM is fhevm (F-Chain, LP-8200). Any identifier still naming "T-Chain" or "ThresholdVM-as-a-chain" is stale.

The quorum, and why it is spelled "3-of-5"

A threshold policy has two numbers that differ by one, and confusing them is the defining failure mode of this domain:

meaning where it appears
K signers required operator language, runbooks, genesis policy
t polynomial degree = K−1 cmp.Keygen, frost.Keygen, stored configs

Passing an operator's 3 where a library wants t builds a 4-of-5 key. Nothing errors; three custodians simply cannot sign, and for a key that already holds funds the only fix is a resharing ceremony with parties that may no longer exist.

So M-Chain never carries a bare threshold number. Genesis states "policy": "3-of-5", it decodes to a quorum.Policy, and the degree is obtained only by calling Policy.Degree(). luxfi/threshold/pkg/quorum is the one place K and t are allowed to meet.

M-Chain additionally requires 2K > N (types.HasUniqueQuorum). CGGMP21 is unforgeable against up to N−1 corruptions, so 2-of-5 is cryptographically sound; but with two disjoint quorums, two halves of the committee could authorise contradictory releases of the same funds.

The policy must also fit the network's validator set — the committee IS the validator set, so N cannot exceed the validators that exist to hold shares. TestMChainPolicyIsSatisfiableByTheGenesisValidatorSet in the node repo enforces it.

What is on-chain and what is not

replicated in the state root contents
c/ consensus yes yes key registry, ceremony log, blocks, height index
n/ node-private no no this validator's secret key shares

The registry holds only public values — policy, participants, group public key, custody address. A share never enters consensus state. State is written the moment each fact becomes true, so a crash cannot lose the record of who holds the funds, and Initialize resumes the accepted tip rather than recomputing genesis.

Blocks are verified, not trusted

  • A sign operation carries the signature; Verify re-checks it against the group public key already in the registry. A proposer cannot fabricate one without forging ECDSA, and a validator that sat out the ceremony still verifies the result.
  • A keygen operation carries a proof of possession by the new group key over its own registration. That rules out registering a key you do not control. The declared degree is bound separately, by participants cross-checking the record against their own share — one honest participant is enough to reject a mis-declared key.
  • Every block carries its post-state root. Verify recomputes it, so two validators that would diverge cannot both accept.

Leaderless and permissionless

Ceremony ids are derived from the task — H(tag ‖ keyID ‖ digest ‖ sorted signers) — so every validator converges on the same ceremony with no announce round and no coordinator. The signing quorum is likewise a pure function of the task, so all nodes agree on which K sign without an election.

The committee is the chain's own validator set. Joining the signing ring is joining the validator set: no allowlist, no operator registry, no admin-gated key ceremony.

Proof

TestBridgeCustody_ThreeOfFive runs five VMs over the real gossip transport: a real CGGMP21 DKG at degree 2, exactly three of five sign, two decline, the signature verifies under the group key, and a block carrying it is verified and accepted by all five — including the two that never touched the ceremony — with every node ending on the same state root.

Layout

path role
vm.go chain.ChainVM: Initialize/resume, BuildBlock, custody API
custody.go ceremony lifecycle — DKG, signing, quorum selection, staging
state.go persisted state: registry, ceremony log, roots, share store
block.go the verified state transition
wire.go native-ZAP struct-is-wire encodings
transport.go gossip router (production) + in-process mesh (tests)
executor.go drives luxfi/threshold protocol handlers
types/ shared ceremony state machine and the 2K > N custody floor
fhe/ TFHE helpers retained for the F-Chain handoff

Documentation

Overview

service.go carves the (currently single, overloaded) threshold VM into three orthogonal SERVICE surfaces — ThresholdService, MPCService, FHEService — per LP-134 / LP-7050. This is the "separate what the primitive IS from where it is APPLIED" decomposition (Hammock-driven composition, not inheritance).

It changes NO behavior and NO genesis: the interfaces are carved directly from the methods *VM already implements, and *VM is asserted to satisfy all three at the bottom of this file (the compatibility bridge). The physical VM split — moving each surface's implementation onto its own package (github.com/luxfi/chains/mpcvm implementing MPCService, .../fhevm implementing FHEService) behind these exact interfaces — is the follow-up; until then the one *VM backs all three surfaces and the M-Chain / F-Chain runtime adapters (runtime/{m,f}_chain_adapter.go) delegate to it.

Layering mirrors the primitive-library stack that already exists upstream (github.com/luxfi/threshold is consumed by github.com/luxfi/mpc; FHE ⊥ MPC):

  • ThresholdService — PURE threshold primitives: DKG, committee formation, key/committee lookup. The substrate the other two consume. Owns no custody, no bridge business logic, no FHE.
  • MPCService — threshold SIGNING, bridge-custody attestation. CONSUMES ThresholdService committees to produce signatures/attestations over cross-chain subjects. This is M-Chain's surface (LP-7100).
  • FHEService — confidential compute / encrypted state. CONSUMES ThresholdService key/decryption committees; owns FHE jobs and threshold-decrypt. This is F-Chain's surface (LP-8200).

mpcvm itself remains a LIBRARY: there is no T-Chain, no teleportvm.

Package mpcvm implements the shared threshold VM substrate — a LIBRARY, not a chain — consumed by M-Chain (MPC: CGGMP21/FROST/Pulsar-general threshold signing for bridge custody of external wallets, LP-7100) and F-Chain (FHE: TFHE compute / threshold decrypt, LP-8200). Per LP-134 / LP-7050 there is NO T-Chain and NO teleportvm; teleport IS bridgevm (B-Chain, LP-6000). Any live identifier still naming "T-Chain" or "ThresholdVM-as-a-chain" is stale. See ../README.md.

Index

Constants

View Source
const (
	OpTypeKeygen = "keygen"
	OpTypeSign   = "sign"
)

Operation kinds recorded on M-Chain.

View Source
const (
	RPCErrorInvalidRequest   = -32600
	RPCErrorMethodNotFound   = -32601
	RPCErrorInvalidParams    = -32602
	RPCErrorInternal         = -32603
	RPCErrorUnauthorized     = -32002
	RPCErrorQuotaExceeded    = -32003
	RPCErrorCeremonyNotFound = -32004
	RPCErrorKeyNotFound      = -32005
	RPCErrorProtocolNotFound = -32006
)

Error codes. Only codes this server can actually return are declared: a published code that nothing emits reads as a contract to callers who then write dead branches against it.

View Source
const KindCGGMP21 = "cggmp21"

KindCGGMP21 names the threshold-ECDSA protocol used for bridge custody of external wallets. It is the value stored in KeyRecord.Kind.

Variables

View Source
var (
	ErrInvalidOperation = errors.New("mpcvm: invalid operation")
	ErrBadArtifact      = errors.New("mpcvm: ceremony artifact does not verify")
	ErrQuorumTooSmall   = errors.New("mpcvm: signer set smaller than the key's policy requires")
)
View Source
var (
	ErrNoCommittee    = errors.New("mpcvm: no validator committee available")
	ErrNotParticipant = errors.New("mpcvm: this node is not in the ceremony committee")
	ErrNotInQuorum    = errors.New("mpcvm: this node is not in this task's signing quorum")
	ErrPolicyTooLarge = errors.New("mpcvm: policy requires more parties than the committee has")
)
View Source
var (
	ErrKeyExists      = errors.New("mpcvm: key already registered")
	ErrUnknownKey     = errors.New("mpcvm: key not registered")
	ErrCeremonyExists = errors.New("mpcvm: ceremony already recorded")
	ErrShareNotHeld   = errors.New("mpcvm: this node holds no share for that key")
	ErrPolicyMismatch = errors.New("mpcvm: key policy does not match its participant set")
	ErrRootMismatch   = errors.New("mpcvm: post-state root mismatch")
)
View Source
var (
	Version = &version.Semantic{
		Major: 1,
		Minor: 0,
		Patch: 0,
	}

	// Errors this VM owns. Everything about a KEY (unknown, already registered,
	// share not held) is state.go's vocabulary and is not restated here: two
	// spellings of "no such key" is one spelling too many.
	ErrInvalidThreshold  = errors.New("mpcvm: invalid threshold configuration")
	ErrUnauthorizedChain = errors.New("mpcvm: unauthorized chain")
	ErrQuotaExceeded     = errors.New("mpcvm: signing quota exceeded")
)
View Source
var ErrGPUNotAvailable = errors.New("mpcvm: GPU backend not available (no plugin dlopened)")

ErrGPUNotAvailable is returned by GPUBackend methods when no plugin was resolved at init() time. Callers check this to fall back to the CPU reference (the protocol/ + executor.go state machine, which is unchanged by this bridge).

VMID identifies M-Chain: MPC threshold signing and bridge custody of external wallets (LP-7100). It is constants.MPCVMID and nothing else.

A vmID is an immutable one-way door: it is baked into the CreateChainTx at genesis, it is the plugin binary's filename, and it is what the P-Chain stores forever. Every declaration of it must agree, so there is exactly one — this alias — and it points at the single source of truth in luxfi/constants.

This VM previously declared a private `thresholdvm` literal here that matched no other declaration in the stack. Per LP-7050 the thresholdvm package was split into mpcvm (M-Chain) and fhevm (F-Chain); "ThresholdVM" and "mvm" are stale names. constants.MPCVMID, node/genesis/builder/registry.go and node/node/vms.go all say mpcvm.

Functions

func ComputeAttestationPayload

func ComputeAttestationPayload(domain AttestationDomain, subjectID, commitmentRoot [32]byte, epoch uint64) [32]byte

ComputeAttestationPayload computes the payload to be signed for an attestation

func DetectEquivocation

func DetectEquivocation(a, b *QuantumAttestation) bool

DetectEquivocation checks if two attestations represent equivocation (slashable) Two attestations are equivocating if they have the same domain, subject, and epoch but different commitment roots

func KeyCommitDigest added in v1.7.10

func KeyCommitDigest(r *KeyRecord) [32]byte

KeyCommitDigest is the message a newly generated group key signs to prove possession of itself. Binding the policy, the participant set and the group key together means a proposer cannot register a key under a policy or a committee other than the one the ceremony actually ran with and still produce a verifying proof.

What this proves and what it does not: a valid proof-of-possession shows that whoever produced it can sign under GroupPublicKey, which rules out a proposer registering a public key it does not control (rogue-key registration). It does NOT by itself prove the declared degree — a single party holding the whole secret could also sign. Degree is established by the participant cross-check in Block.Verify: a validator that holds a share for this key compares the record against its own config and rejects a mismatch, so one honest participant is enough to stop a mis-declared key.

func NewLocalMesh added in v1.7.10

func NewLocalMesh(parties []party.ID) *localMesh

NewLocalMesh builds an in-process bus over a fixed committee.

func VerifyBridgeAttestation

func VerifyBridgeAttestation(groupPubKey []byte, bt BridgeTransfer, sig []byte) bool

VerifyBridgeAttestation is B's gate: it returns true iff sig is a valid threshold signature by the group key over THIS transfer's domain-bound digest. Accepts r‖s (64) or r‖s‖v (65). No interaction with M — a threshold ECDSA signature verifies exactly like a single-key one.

Types

type AppNetwork

type AppNetwork interface {
	// Broadcast reliably gossips an app message to the chain's validators.
	Broadcast(ctx context.Context, msg []byte) error
	// SendTo sends an app message to a single validator.
	SendTo(ctx context.Context, nodeID ids.NodeID, msg []byte) error
}

AppNetwork is the minimal consensus-gossip send capability the gossipRouter needs. The VM implements it over the node AppSender it receives at Initialize. Kept as an interface so this file imports no node packages and stays unit-testable.

type AttestationDomain

type AttestationDomain string

AttestationDomain defines the domain for a threshold attestation

const (
	// DomainOracleWrite attests to external write request commitments
	DomainOracleWrite AttestationDomain = "oracle/write"
	// DomainOracleRead attests to external read request commitments
	DomainOracleRead AttestationDomain = "oracle/read"
	// DomainSessionComplete attests to session completion (output hash + oracle obs + receipts root)
	DomainSessionComplete AttestationDomain = "session/complete"
	// DomainEpochBeacon attests to epoch beacon signatures for randomness
	DomainEpochBeacon AttestationDomain = "epoch/beacon"
)
const DomainBridgeTransfer AttestationDomain = "bridge/transfer"

DomainBridgeTransfer registers the bridge domain with the attestation domain registry so QuantumAttestation-style tooling recognises it.

type BLSHandler

type BLSHandler struct{}

BLSHandler implements ProtocolHandler for BLS threshold signatures

func (*BLSHandler) Keygen

func (h *BLSHandler) Keygen(ctx context.Context, partyID party.ID, partyIDs []party.ID, threshold int) (KeyShare, error)

func (*BLSHandler) Name

func (h *BLSHandler) Name() Protocol

func (*BLSHandler) Refresh

func (h *BLSHandler) Refresh(ctx context.Context, share KeyShare) (KeyShare, error)

func (*BLSHandler) Reshare

func (h *BLSHandler) Reshare(ctx context.Context, share KeyShare, newPartyIDs []party.ID, newThreshold int) (KeyShare, error)

func (*BLSHandler) Sign

func (h *BLSHandler) Sign(ctx context.Context, share KeyShare, message []byte, signers []party.ID) (Signature, error)

func (*BLSHandler) SupportedCurves

func (h *BLSHandler) SupportedCurves() []string

func (*BLSHandler) Verify

func (h *BLSHandler) Verify(pubKey []byte, message []byte, signature Signature) (bool, error)

type Block

type Block struct {
	ID_            ids.ID
	ParentID_      ids.ID
	BlockHeight    uint64
	BlockTimestamp int64
	// StateRoot is the root AFTER applying Operations. Every validator
	// recomputes it; a proposer that applied something different is rejected.
	StateRoot  [32]byte
	Operations []*Operation
	// contains filtered or unexported fields
}

Block is one M-Chain block.

func (*Block) Accept

func (b *Block) Accept(ctx context.Context) error

Accept applies the transition and durably records it. Verify has already run, so every precondition holds; anything that fails here is an I/O fault, not a validation failure, and must not be swallowed — a block the engine believes is accepted but whose state was not written is exactly the divergence the state root exists to catch.

func (*Block) Bytes

func (b *Block) Bytes() []byte

Bytes returns the block's canonical wire encoding.

func (*Block) ChoicesStatus

func (b *Block) ChoicesStatus() choices.Status

func (*Block) Height

func (b *Block) Height() uint64

func (*Block) ID

func (b *Block) ID() ids.ID

func (*Block) Marshal added in v1.7.4

func (b *Block) Marshal() ([]byte, error)

Marshal encodes the block (excluding the derived ID_) to canonical wire.

func (*Block) Parent

func (b *Block) Parent() ids.ID

func (*Block) ParentID

func (b *Block) ParentID() ids.ID

func (*Block) Reject

func (b *Block) Reject(ctx context.Context) error

Reject drops a block. State was never touched, so there is nothing to undo.

func (*Block) SetStatus

func (b *Block) SetStatus(status choices.Status)

func (*Block) Status

func (b *Block) Status() uint8

func (*Block) Timestamp

func (b *Block) Timestamp() time.Time

func (*Block) Verify

func (b *Block) Verify(ctx context.Context) error

Verify re-checks the proposed transition against this validator's own state. It mutates nothing: a rejected block must leave state untouched.

type BridgeReleaseRequest added in v1.7.4

type BridgeReleaseRequest struct {
	RequestingChain string `json:"requestingChain"` // authorised chain id in M's permission table (e.g. "B-Chain")
	// KeyID names the custody key that must sign. It is REQUIRED: there is no
	// "active key" for a request to fall back to, because a fallback means the
	// chain, not the requester, chose which vault to spend from — and a key
	// rotation would silently redirect releases to a different custody address.
	KeyID      string   `json:"keyId"`
	SrcChainID uint32   `json:"srcChainId"`
	DstChainID uint32   `json:"dstChainId"`
	Asset      [32]byte `json:"asset"`
	Amount     uint64   `json:"amount"`
	Recipient  [20]byte `json:"recipient"`
	Nonce      uint64   `json:"nonce"`
}

BridgeReleaseRequest is the clean, self-contained request B hands M to authorise a cross-chain release. It carries exactly the fields that bind the release (both chain ids, asset, amount, recipient, per-route nonce) plus the M-Chain routing context (which authorised chain is asking, and which custody key must sign). Everything the digest commits to travels here; nothing else can be minted from the resulting attestation.

type BridgeTransfer

type BridgeTransfer struct {
	SrcChainID uint32   `json:"srcChainId"` // source network id
	DstChainID uint32   `json:"dstChainId"` // destination network id
	Asset      [32]byte `json:"asset"`      // canonical asset id
	Amount     uint64   `json:"amount"`     // units locked on source == minted on dest
	Recipient  [20]byte `json:"recipient"`  // destination recipient (20-byte account)
	Nonce      uint64   `json:"nonce"`      // per-route monotonic nonce (replay guard)
}

BridgeTransfer is the domain-bound message B commits to on lock and M signs as its attestation. Field layout is fixed so the digest is canonical across validators and across the B/M boundary.

func (BridgeTransfer) Digest

func (bt BridgeTransfer) Digest() [32]byte

Digest is the canonical, domain-separated signing preimage for a transfer.

type BridgeTransferAttestation

type BridgeTransferAttestation struct {
	Transfer    BridgeTransfer `json:"transfer"`
	Digest      [32]byte       `json:"digest"`
	Signature   []byte         `json:"signature"`   // secp256k1 r(32)‖s(32)‖v(1)
	GroupPubKey []byte         `json:"groupPubKey"` // 33-byte compressed group key
	Signers     []party.ID     `json:"signers"`     // the quorum that signed
	KeyID       string         `json:"keyId"`
	// CeremonyID is this attestation's entry in M-Chain's replicated ceremony
	// log — the audit handle that turns "B was handed a signature" into "B can
	// point at the consensus record that produced it".
	CeremonyID string `json:"ceremonyId"`
	CreatedAt  int64  `json:"createdAt"`
}

BridgeTransferAttestation is M's threshold signature over a transfer, plus the context B needs to verify it. Self-describing so B (or a relayer) can verify without re-querying M.

type CGGMP21Handler

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

CGGMP21Handler implements ProtocolHandler for CGGMP21/CMP

func (*CGGMP21Handler) Keygen

func (h *CGGMP21Handler) Keygen(ctx context.Context, partyID party.ID, partyIDs []party.ID, threshold int) (KeyShare, error)

func (*CGGMP21Handler) Name

func (h *CGGMP21Handler) Name() Protocol

func (*CGGMP21Handler) Refresh

func (h *CGGMP21Handler) Refresh(ctx context.Context, share KeyShare) (KeyShare, error)

func (*CGGMP21Handler) Reshare

func (h *CGGMP21Handler) Reshare(ctx context.Context, share KeyShare, newPartyIDs []party.ID, newThreshold int) (KeyShare, error)

func (*CGGMP21Handler) SetExecutor

func (h *CGGMP21Handler) SetExecutor(executor *ProtocolExecutor)

SetExecutor sets the protocol executor for the handler

func (*CGGMP21Handler) SetMessageRouter

func (h *CGGMP21Handler) SetMessageRouter(router MessageRouter)

SetMessageRouter sets the message router for multi-party communication

func (*CGGMP21Handler) Sign

func (h *CGGMP21Handler) Sign(ctx context.Context, share KeyShare, message []byte, signers []party.ID) (Signature, error)

func (*CGGMP21Handler) SupportedCurves

func (h *CGGMP21Handler) SupportedCurves() []string

func (*CGGMP21Handler) Verify

func (h *CGGMP21Handler) Verify(pubKey []byte, message []byte, signature Signature) (bool, error)

type CMPKeyShare

type CMPKeyShare struct {
	Config *cmpconfig.Config
}

CMPKeyShare wraps cmpconfig.Config to implement KeyShare.

func (*CMPKeyShare) Generation

func (s *CMPKeyShare) Generation() uint64

Generation returns the key generation number.

func (*CMPKeyShare) PartyID

func (s *CMPKeyShare) PartyID() party.ID

PartyID returns this party's ID.

func (*CMPKeyShare) Protocol

func (s *CMPKeyShare) Protocol() Protocol

Protocol returns which protocol this share is for.

func (*CMPKeyShare) PublicKey

func (s *CMPKeyShare) PublicKey() []byte

PublicKey returns the group public key.

func (*CMPKeyShare) Serialize

func (s *CMPKeyShare) Serialize() ([]byte, error)

Serialize converts the share to bytes for storage.

func (*CMPKeyShare) Threshold

func (s *CMPKeyShare) Threshold() int

Threshold returns the threshold t.

func (*CMPKeyShare) TotalParties

func (s *CMPKeyShare) TotalParties() int

TotalParties returns total parties n.

type CeremonyInfo added in v1.7.10

type CeremonyInfo struct {
	CeremonyID string `json:"ceremonyId"`
	Kind       string `json:"kind"` // keygen | sign
	KeyID      string `json:"keyId"`
	Digest     string `json:"digest"`    // 0x-hex, 32 bytes
	Signature  string `json:"signature"` // 0x-hex, 65 bytes r‖s‖v
	R          string `json:"r,omitempty"`
	S          string `json:"s,omitempty"`
	V          int    `json:"v,omitempty"`
	// Signers is the participating quorum, canonically ordered.
	Signers         []string `json:"signers"`
	RequestingChain string   `json:"requestingChain,omitempty"`
	Height          uint64   `json:"height,omitempty"`
}

CeremonyInfo is one ceremony as the chain records it: what was signed, by whom, and the signature it produced. It is the shape returned both by a ceremony that just ran and by a lookup in the replicated ceremony log, so a caller parses one thing.

Height is 0 for a ceremony that has completed but whose block has not been accepted yet — the signature is valid, it just has no place in history yet.

type CeremonyRecord added in v1.7.10

type CeremonyRecord struct {
	// ID is the derived ceremony id — H(tag ‖ keyID ‖ digest ‖ sorted signers).
	// Derived, not announced: every validator computing the same task lands on
	// the same id with no coordination round and no coordinator.
	ID string
	// Kind is the operation: OpTypeKeygen or OpTypeSign.
	Kind string
	// KeyID is the custody key the ceremony created or used.
	KeyID string
	// Digest is the 32-byte message that was signed (sign ceremonies) or the
	// key-commit digest (keygen ceremonies).
	Digest []byte
	// Signers are the parties that participated, in canonical order.
	Signers []party.ID
	// Artifact is the ceremony's verifiable output: for a sign ceremony the
	// 65-byte r‖s‖v signature; for a keygen ceremony the proof-of-possession
	// over KeyCommitDigest.
	Artifact []byte
	// RequestingChain names the chain that asked for this ceremony (B-Chain for
	// bridge custody). Empty for locally initiated ceremonies.
	RequestingChain string
	// Height is the M-Chain height at which the ceremony was recorded.
	Height uint64
}

CeremonyRecord is the replicated record of one completed ceremony. It is the audit trail: which key, over which digest, by which signers, producing what.

type ChainPermissions

type ChainPermissions struct {
	ChainID           string   `json:"chainId"`
	ChainName         string   `json:"chainName"`
	CanSign           bool     `json:"canSign"`           // Can request signatures
	CanKeygen         bool     `json:"canKeygen"`         // Can request new key generation
	CanReshare        bool     `json:"canReshare"`        // Can request key resharing
	AllowedKeyTypes   []string `json:"allowedKeyTypes"`   // secp256k1, ed25519, etc.
	MaxSigningSize    int      `json:"maxSigningSize"`    // Max message size to sign
	RequirePreHash    bool     `json:"requirePreHash"`    // Require pre-hashed messages
	DailySigningLimit uint64   `json:"dailySigningLimit"` // Override global quota
}

ChainPermissions defines what a chain can do with MPC services

type Client

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

Client provides access to mpcvm services. Per LP-134, this serves M-Chain (MPC mode) and F-Chain (FHE mode); legacy T-Chain MPC routes here.

func NewClient

func NewClient(endpoint, chainID string) *Client

NewClient creates a new T-Chain client

func (*Client) GetAddress

func (c *Client) GetAddress(ctx context.Context, keyID string) ([]byte, error)

GetAddress retrieves the address for a key ID

func (*Client) GetCeremony added in v1.7.10

func (c *Client) GetCeremony(ctx context.Context, ceremonyID string) (*CeremonyInfo, error)

GetCeremony reads one recorded ceremony from replicated state.

func (*Client) GetInfo

func (c *Client) GetInfo(ctx context.Context) (*ThresholdInfo, error)

GetInfo retrieves M-Chain information.

func (*Client) GetKey

func (c *Client) GetKey(ctx context.Context, keyID string) (*KeyInfo, error)

GetKey retrieves one custody key's record.

func (*Client) GetProtocolInfo

func (c *Client) GetProtocolInfo(ctx context.Context, protocol string) (*ProtocolInfo, error)

GetProtocolInfo retrieves info for a specific protocol

func (*Client) GetProtocols

func (c *Client) GetProtocols(ctx context.Context) ([]ProtocolInfo, error)

GetProtocols retrieves all supported protocols

func (*Client) GetPublicKey

func (c *Client) GetPublicKey(ctx context.Context, keyID string) ([]byte, error)

GetPublicKey retrieves the public key for a key ID

func (*Client) GetQuota

func (c *Client) GetQuota(ctx context.Context) (*QuotaInfo, error)

GetQuota retrieves quota information for this chain

func (*Client) GetStats

func (c *Client) GetStats(ctx context.Context) (*NetworkStats, error)

GetStats retrieves T-Chain statistics

func (*Client) Health

func (c *Client) Health(ctx context.Context) (map[string]interface{}, error)

Health retrieves M-Chain health status.

func (*Client) Keygen

func (c *Client) Keygen(ctx context.Context, req KeygenRequest) (*KeygenResponse, error)

Keygen runs a distributed key generation and returns when the key exists. There is no status to poll afterwards: the ceremony either produced a registered key or returned an error.

func (*Client) ListCeremonies added in v1.7.10

func (c *Client) ListCeremonies(ctx context.Context) ([]CeremonyInfo, error)

ListCeremonies reads the whole ceremony log.

func (*Client) ListKeys

func (c *Client) ListKeys(ctx context.Context) ([]KeyInfo, error)

ListKeys lists every registered custody key.

func (*Client) Sign

func (c *Client) Sign(ctx context.Context, req SignRequest) (*CeremonyInfo, error)

Sign runs a threshold signing ceremony and returns the finished signature.

The call blocks for the duration of the ceremony. The returned CeremonyID is the durable handle: GetCeremony re-reads the same signature from replicated state once the block carrying it is accepted.

func (*Client) StateRoot added in v1.7.10

func (c *Client) StateRoot(ctx context.Context) (string, error)

StateRoot returns the chain's custody state root — the value two validators compare to know whether they agree about custody.

type CoronaHandler

type CoronaHandler struct{}

CoronaHandler implements ProtocolHandler for post-quantum threshold signatures

func (*CoronaHandler) Keygen

func (h *CoronaHandler) Keygen(ctx context.Context, partyID party.ID, partyIDs []party.ID, threshold int) (KeyShare, error)

func (*CoronaHandler) Name

func (h *CoronaHandler) Name() Protocol

func (*CoronaHandler) Refresh

func (h *CoronaHandler) Refresh(ctx context.Context, share KeyShare) (KeyShare, error)

func (*CoronaHandler) Reshare

func (h *CoronaHandler) Reshare(ctx context.Context, share KeyShare, newPartyIDs []party.ID, newThreshold int) (KeyShare, error)

func (*CoronaHandler) Sign

func (h *CoronaHandler) Sign(ctx context.Context, share KeyShare, message []byte, signers []party.ID) (Signature, error)

func (*CoronaHandler) SupportedCurves

func (h *CoronaHandler) SupportedCurves() []string

func (*CoronaHandler) Verify

func (h *CoronaHandler) Verify(pubKey []byte, message []byte, signature Signature) (bool, error)

type CrossChainMPCRequest

type CrossChainMPCRequest struct {
	Type            string `json:"type"` // sign, keygen, reshare
	RequestingChain string `json:"requestingChain"`
	KeyID           string `json:"keyId"`
	KeyType         string `json:"keyType,omitempty"`
	MessageHash     []byte `json:"messageHash,omitempty"`
	MessageType     string `json:"messageType,omitempty"`
}

CrossChainMPCRequest is the request format for cross-chain MPC operations

func (*CrossChainMPCRequest) Marshal added in v1.7.4

func (r *CrossChainMPCRequest) Marshal() ([]byte, error)

type ECDSASignature

type ECDSASignature struct {
	R []byte
	S []byte
	V byte
}

ECDSASignature wraps ECDSA signature from threshold library.

type EpochBeaconAttestation

type EpochBeaconAttestation struct {
	Epoch       uint64   `json:"epoch"`
	Randomness  [32]byte `json:"randomness"`
	PreviousRef [32]byte `json:"previousRef"`
}

EpochBeaconAttestation contains details for epoch beacon attestations

type FHEService

type FHEService interface {
	ThresholdService
}

FHEService is the F-Chain surface: confidential compute over encrypted state. It CONSUMES ThresholdService key/decryption committees; it owns FHE jobs and threshold-decrypt. The FHE execution primitives live in the fhe/ subpackage (fhe.FHEAccelerator); this interface is the chain-facing surface the physical fhevm package will implement in the follow-up split. Kept minimal and honest: today the single *VM exposes the ThresholdService substrate that F-Chain's FHE runtime consumes, so FHEService embeds it and the FHE-execution methods are added as the fhevm package is carved out.

type FROSTKeyShare

type FROSTKeyShare struct {
	Config *frostconfig.Config
}

FROSTKeyShare wraps frostconfig.Config to implement KeyShare.

func (*FROSTKeyShare) Generation

func (s *FROSTKeyShare) Generation() uint64

Generation returns the key generation number.

func (*FROSTKeyShare) PartyID

func (s *FROSTKeyShare) PartyID() party.ID

PartyID returns this party's ID.

func (*FROSTKeyShare) Protocol

func (s *FROSTKeyShare) Protocol() Protocol

Protocol returns which protocol this share is for.

func (*FROSTKeyShare) PublicKey

func (s *FROSTKeyShare) PublicKey() []byte

PublicKey returns the group public key.

func (*FROSTKeyShare) Serialize

func (s *FROSTKeyShare) Serialize() ([]byte, error)

Serialize converts the share to bytes for storage.

func (*FROSTKeyShare) Threshold

func (s *FROSTKeyShare) Threshold() int

Threshold returns the threshold t.

func (*FROSTKeyShare) TotalParties

func (s *FROSTKeyShare) TotalParties() int

TotalParties returns total parties n.

type Factory

type Factory struct{}

Factory creates M-Chain VM instances.

func (*Factory) New

func (f *Factory) New(log.Logger) (interface{}, error)

New returns a new M-Chain VM. Everything that needs configuration or a database is set up in Initialize; a Factory-built VM holds no state.

type GPUBackend

type GPUBackend struct {
	Kind GPUBackendKind
	Path string // dlopen'd library path, for diagnostics
	// contains filtered or unexported fields
}

GPUBackend is the resolved plugin substrate. Zero value = not available.

func Backend

func Backend() *GPUBackend

Backend returns the resolved GPU plugin. nil means no plugin was loaded.

func (*GPUBackend) CeremonyApply

func (g *GPUBackend) CeremonyApply(
	desc *GPUMPCVMRoundDescriptor,
	ceremonyOps []GPUCeremonyOp,
	ceremonies []GPUCeremony,
) (applied uint32, err error)

CeremonyApply applies ceremony begin/cancel ops to the ceremony table. Contribution slots are not touched (callers passing nil contribution_ops get the lean ceremony-admin dispatch).

ceremonies is the open-addressed ceremony hash table (must be a power-of-2 length on the device-side; the Go caller owns the buffer). The kernel mutates it in place; the round descriptor's CeremonyOpCount tells the kernel how many ops to consume from ceremonyOps.

next_contribution_id_in is the substrate's monotonically increasing contribution-id counter at the start of the round; the kernel doesn't advance it on the ceremony-only path but the parameter is part of the shared launcher signature.

func (*GPUBackend) ContributionApply

func (g *GPUBackend) ContributionApply(
	desc *GPUMPCVMRoundDescriptor,
	contributionOps []GPUContributionOp,
	ceremonies []GPUCeremony,
	contributions []GPUContribution,
	nextContributionID uint64,
) (applied uint32, err error)

ContributionApply applies contribution payloads to the contribution table. Ceremony slots are not touched (callers passing nil ceremonyOps get the lean contribution-only dispatch). Uses the same ceremony_apply kernel because the dedup-and-write path is the same on the device side; only the op stream differs.

func (*GPUBackend) IsAvailable

func (g *GPUBackend) IsAvailable() bool

IsAvailable reports whether the bridge has a usable plugin with at least the ceremony_apply and ceremony_sweep launchers resolved. compute_leaves and compose_root are required for MPCTransition but are checked per-method to allow partial GPU coverage when a plugin ships fewer symbols (e.g. an early Vulkan port).

func (*GPUBackend) KeyShareApply

func (g *GPUBackend) KeyShareApply(
	desc *GPUMPCVMRoundDescriptor,
	ceremonies []GPUCeremony,
	keyShares []GPUKeyShare,
	contributions []GPUContribution,
	nextShareID uint64,
) (roundAdvance, finalized, failed uint32, err error)

KeyShareApply runs the per-slot fan-out sweep that advances ceremonies, finalizes keygens (assigning canonical share_ids), and times out expired ceremonies. Backed by lux_<X>_mpcvm_ceremony_sweep.

On DKG finalize, fresh KeyShare slots are written into keyShares with the share_data_len matching the scheme (Frost=65, CGGMP21=65, Corona=256). next_share_id_in seeds the prefix-sum scheme that gives every finalized share a deterministic share_id.

func (*GPUBackend) MPCTransition

func (g *GPUBackend) MPCTransition(
	desc *GPUMPCVMRoundDescriptor,
	ceremonies []GPUCeremony,
	keyShares []GPUKeyShare,
	contributions []GPUContribution,
	state *GPUMPCVMState,
) (*GPUMPCVMTransitionResult, error)

MPCTransition runs the per-leaf keccak pass and the canonical-order fold pass, producing the round's MPCVMTransitionResult and advancing the substrate state. This is the composition of compute_leaves and compose_root — one substrate state transition per call.

Returns the result envelope written by compose_root. The substrate state in `state` is also updated in place (cur_epoch, now_ns, counts, all four roots).

type GPUBackendKind

type GPUBackendKind uint8

GPUBackendKind is the resolved plugin family. Matches the dlopen probe order in backend.go: cuda → hip → metal → vulkan → webgpu.

const (
	GPUBackendNone   GPUBackendKind = 0
	GPUBackendCUDA   GPUBackendKind = 1
	GPUBackendHIP    GPUBackendKind = 2
	GPUBackendMetal  GPUBackendKind = 3
	GPUBackendVulkan GPUBackendKind = 4
	GPUBackendWebGPU GPUBackendKind = 5
)

func (GPUBackendKind) String

func (k GPUBackendKind) String() string

String returns the launcher prefix used in symbol resolution.

type GPUCeremony

type GPUCeremony struct {
	CeremonyID         uint64
	StartedAtNs        uint64
	DeadlineNs         uint64
	ParticipantsBitmap uint64
	Kind               uint32
	Round              uint32
	Threshold          uint32
	TotalParticipants  uint32
	Status             uint32
	ContributionCount  uint32
	Subject            [32]byte
	CeremonySeed       [32]byte
	// contains filtered or unexported fields
}

GPUCeremony is the on-GPU ceremony state. 128 bytes, __align__(16). The GPU prefix distinguishes the wire mirror from the domain-level Ceremony types in protocols.go / runtime/. ONLY the GPU bridge ever touches these.

type GPUCeremonyOp

type GPUCeremonyOp struct {
	CeremonyID        uint64
	DeadlineNs        uint64
	Kind              uint32
	CeremonyKind      uint32
	Threshold         uint32
	TotalParticipants uint32
	Subject           [32]byte
	CeremonySeed      [32]byte
}

GPUCeremonyOp is one inbound ceremony op (begin/cancel). 96 bytes.

type GPUContribution

type GPUContribution struct {
	ContributionID uint64
	CeremonyID     uint64
	HolderAddr     uint64
	Round          uint32
	HolderIndex    uint32
	PayloadLen     uint32
	Status         uint32
	Payload        [384]byte
	Pad0           uint64
}

GPUContribution is the on-GPU contribution record. 432 bytes, __align__(16).

type GPUContributionOp

type GPUContributionOp struct {
	CeremonyID  uint64
	HolderAddr  uint64
	Round       uint32
	HolderIndex uint32
	PayloadLen  uint32
	Pad0        uint32
	Payload     [384]byte
}

GPUContributionOp is one inbound contribution payload. 416 bytes.

type GPUKeyShare

type GPUKeyShare struct {
	ShareID      uint64
	CeremonyID   uint64
	HolderAddr   uint64
	Scheme       uint32
	HolderIndex  uint32
	ShareDataLen uint32
	Occupied     uint32
	ShareData    [320]byte
	Pad0         uint64
}

GPUKeyShare is the on-GPU key share record. 368 bytes, __align__(16).

type GPUMPCVMRoundDescriptor

type GPUMPCVMRoundDescriptor struct {
	ChainID             uint64
	Round               uint64
	TimestampNs         uint64
	Epoch               uint64
	Mode                uint32
	CeremonyOpCount     uint32
	ContributionOpCount uint32
	ClosingFlag         uint32
	Pad0                uint32
	Pad1                uint32
	Pad2                uint64
	ParentStateRoot     [32]byte
}

GPUMPCVMRoundDescriptor describes one round's input envelope. 96 bytes.

type GPUMPCVMState

type GPUMPCVMState struct {
	CurrentEpoch           uint64
	NowNs                  uint64
	ActiveCeremonyCount    uint32
	FinalizedCeremonyCount uint32
	FailedCeremonyCount    uint32
	KeyShareCount          uint32
	CeremonyRoot           [32]byte
	KeyShareRoot           [32]byte
	ContributionRoot       [32]byte
	MPCVMStateRoot         [32]byte
}

GPUMPCVMState is the on-GPU substrate state. 160 bytes, __align__(16).

type GPUMPCVMTransitionResult

type GPUMPCVMTransitionResult struct {
	Status                 uint32
	CeremonyApplyCount     uint32
	ContributionApplyCount uint32
	FinalizedThisRound     uint32
	FailedThisRound        uint32
	ActiveCeremonyCount    uint32
	KeyShareCount          uint32
	RoundAdvanceCount      uint32
	Epoch                  uint64
	NowNs                  uint64
	CeremonyRoot           [32]byte
	KeyShareRoot           [32]byte
	ContributionRoot       [32]byte
	MPCVMStateRoot         [32]byte
}

GPUMPCVMTransitionResult is the transition envelope written by compose_root. 176 bytes.

type Genesis

type Genesis struct {
	Timestamp int64         `json:"timestamp"`
	Policy    quorum.Policy `json:"policy,omitempty"`
}

Genesis represents the genesis state.

Policy is here rather than only in each node's config file because the chain's quorum must be the same value on every validator: a policy that lives per-node can differ per-node, and the first symptom is a key whose declared quorum is not the quorum it was generated with. An absent or malformed policy leaves the config default in place (see Initialize).

type GetCeremonyParams added in v1.7.10

type GetCeremonyParams struct {
	CeremonyID string `json:"ceremonyId"`
}

GetCeremonyParams contains parameters for reading one ceremony.

type GetChainPermissionsParams

type GetChainPermissionsParams struct {
	ChainID string `json:"chainId"`
}

GetChainPermissionsParams contains parameters for getting chain permissions

type GetKeyParams

type GetKeyParams struct {
	KeyID string `json:"keyId"`
}

GetKeyParams contains parameters for getting a key.

type GetProtocolInfoParams

type GetProtocolInfoParams struct {
	Protocol string `json:"protocol"`
}

GetProtocolInfoParams contains parameters for getting protocol info

type GetQuotaParams

type GetQuotaParams struct {
	ChainID string `json:"chainId"`
}

GetQuotaParams contains parameters for getting quota

type KeyInfo

type KeyInfo struct {
	KeyID string `json:"keyId"`
	Kind  string `json:"kind"` // threshold protocol that generated it, e.g. cggmp21
	// Policy is the operator form, "3-of-5". Degree is the polynomial degree
	// (K-1) it was generated with, reported so the two can be checked against
	// each other rather than inferred.
	Policy         string   `json:"policy"`
	Degree         int      `json:"degree"`
	GroupPublicKey string   `json:"groupPublicKey"` // 0x-hex, 33-byte compressed
	Address        string   `json:"address"`        // 0x-hex, 20-byte custody address
	Participants   []string `json:"participants"`
	Generation     uint64   `json:"generation"`
	CreatedHeight  uint64   `json:"createdHeight"`
}

KeyInfo is a custody key's replicated public record. It carries no secret and no per-node bookkeeping: every field here is identical on every validator.

type KeyRecord added in v1.7.10

type KeyRecord struct {
	KeyID string
	// Kind is the threshold protocol that generated the key (cggmp21, frost,
	// ...). A key is bound to its protocol: cross-scheme reuse of a share is
	// prohibited (LP-4700), and Kind is what enforces the binding at signing.
	Kind string
	// Policy is the quorum in operator form: K signers of N parties. The
	// polynomial degree the protocol was parameterised with is Policy.Degree(),
	// derived — never stored independently, because two stored numbers can
	// disagree and one cannot.
	Policy quorum.Policy
	// Participants are the parties holding a share, in canonical (sorted) order
	// so every validator hashes the same bytes. len(Participants) == Policy.N.
	Participants []party.ID
	// GroupPublicKey is the compressed secp256k1 point (33 bytes) that
	// signatures verify under.
	GroupPublicKey []byte
	// Address is the 20-byte Ethereum-style address of GroupPublicKey — the
	// external-chain custody address that actually holds bridged funds.
	Address []byte
	// Generation increments on each resharing/refresh of the same public key.
	Generation uint64
	// CreatedHeight is the M-Chain height at which the key was registered.
	CreatedHeight uint64
}

KeyRecord is the replicated, public record of one custody key.

It is deliberately share-free: the group public key and the policy are everything a validator needs to check a signature and everything B-Chain needs to know who the custodian is. The share that produced it lives in node state and never leaves the node that generated it.

func (*KeyRecord) Degree added in v1.7.10

func (r *KeyRecord) Degree() int

Degree returns the polynomial degree this key was generated with. It is the value to hand to cmp/frost, and it is derived from the policy at the one boundary that is allowed to convert between k and t.

func (*KeyRecord) Validate added in v1.7.10

func (r *KeyRecord) Validate() error

Validate checks the record's internal consistency. A record that fails this must never be admitted to consensus state, because every later signature check trusts these fields.

type KeyShare

type KeyShare interface {
	// PublicKey returns the group public key
	PublicKey() []byte

	// PartyID returns this party's ID
	PartyID() party.ID

	// Threshold returns the threshold t
	Threshold() int

	// TotalParties returns total parties n
	TotalParties() int

	// Generation returns the key generation number
	Generation() uint64

	// Protocol returns which protocol this share is for
	Protocol() Protocol

	// Serialize converts the share to bytes for storage
	Serialize() ([]byte, error)
}

KeyShare represents a threshold key share (abstract)

type KeygenParams

type KeygenParams struct {
	KeyID       string `json:"keyId"`
	RequestedBy string `json:"requestedBy"` // Chain ID; must be authorised to keygen
	// Policy is the quorum in operator form, "3-of-5". Omit it to use the
	// chain's default. It is deliberately not a pair of numbers: a caller
	// cannot express the quorum ambiguously, and the polynomial degree is
	// derived from it inside the ceremony rather than passed alongside it.
	Policy quorum.Policy `json:"policy,omitempty"`
}

KeygenParams contains parameters for key generation.

type KeygenRequest

type KeygenRequest struct {
	KeyID string `json:"keyId"`
	// Policy is the quorum in operator form, "3-of-5". Empty means the chain's
	// default.
	Policy string `json:"policy,omitempty"`
}

KeygenRequest contains parameters for key generation.

type KeygenResponse

type KeygenResponse struct {
	Ceremony CeremonyInfo `json:"ceremony"`
	Key      KeyInfo      `json:"key"`
}

KeygenResponse is a COMPLETED key generation.

type KeygenResult

type KeygenResult struct {
	Ceremony CeremonyInfo `json:"ceremony"`
	Key      KeyInfo      `json:"key"`
}

KeygenResult is a COMPLETED key generation: the ceremony that ran and the key it registered. There is no status to poll — a keygen that returns has a key, and one that fails returns an error.

type LSSHandler

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

LSSHandler implements ProtocolHandler for LSS

func (*LSSHandler) Keygen

func (h *LSSHandler) Keygen(ctx context.Context, partyID party.ID, partyIDs []party.ID, threshold int) (KeyShare, error)

func (*LSSHandler) Name

func (h *LSSHandler) Name() Protocol

func (*LSSHandler) Refresh

func (h *LSSHandler) Refresh(ctx context.Context, share KeyShare) (KeyShare, error)

func (*LSSHandler) Reshare

func (h *LSSHandler) Reshare(ctx context.Context, share KeyShare, newPartyIDs []party.ID, newThreshold int) (KeyShare, error)

func (*LSSHandler) Sign

func (h *LSSHandler) Sign(ctx context.Context, share KeyShare, message []byte, signers []party.ID) (Signature, error)

func (*LSSHandler) SupportedCurves

func (h *LSSHandler) SupportedCurves() []string

func (*LSSHandler) Verify

func (h *LSSHandler) Verify(pubKey []byte, message []byte, signature Signature) (bool, error)

type LSSKeyShare

type LSSKeyShare struct {
	Config *lssconfig.Config
}

LSSKeyShare wraps lssconfig.Config to implement KeyShare.

func (*LSSKeyShare) Generation

func (s *LSSKeyShare) Generation() uint64

Generation returns the key generation number.

func (*LSSKeyShare) PartyID

func (s *LSSKeyShare) PartyID() party.ID

PartyID returns this party's ID.

func (*LSSKeyShare) Protocol

func (s *LSSKeyShare) Protocol() Protocol

Protocol returns which protocol this share is for.

func (*LSSKeyShare) PublicKey

func (s *LSSKeyShare) PublicKey() []byte

PublicKey returns the group public key.

func (*LSSKeyShare) Serialize

func (s *LSSKeyShare) Serialize() ([]byte, error)

Serialize converts the share to bytes for storage.

func (*LSSKeyShare) Threshold

func (s *LSSKeyShare) Threshold() int

Threshold returns the threshold t.

func (*LSSKeyShare) TotalParties

func (s *LSSKeyShare) TotalParties() int

TotalParties returns total parties n.

type MPCService

type MPCService interface {
	ThresholdService

	// RequestSignature asks the custody committee for keyID to threshold-sign
	// messageHash on behalf of requestingChain. It returns when the ceremony
	// has produced a signature that verifies under the registered group key.
	RequestSignature(ctx context.Context, requestingChain, keyID string, messageHash []byte) (*Operation, error)

	// Ceremony returns one recorded ceremony — the replicated, durable evidence
	// that a signature was produced, including the signature. Ceremonies
	// returns the whole log.
	Ceremony(id string) (*CeremonyRecord, error)
	Ceremonies() ([]*CeremonyRecord, error)

	// StateRoot is the value two validators compare to know whether they agree
	// about custody.
	StateRoot() [32]byte

	// RequestBridgeRelease is the B→M seam: a bridge release request in, a
	// threshold-signed self-describing attestation out.
	RequestBridgeRelease(ctx context.Context, req BridgeReleaseRequest) (*BridgeTransferAttestation, error)

	// AttestOracleCommit produces a threshold attestation over an oracle
	// read/write commitment for requestingChain.
	AttestOracleCommit(ctx context.Context, requestingChain, keyID string, requestID [32]byte, kind uint8, commitRoot [32]byte, epoch uint64) (*QuantumAttestation, error)

	// AttestSessionComplete attests that a bridge/custody session finished with
	// the given output/oracle/receipts roots.
	AttestSessionComplete(ctx context.Context, requestingChain, keyID string, sessionID [32]byte, outputHash, oracleRoot, receiptsRoot [32]byte, epoch uint64) (*QuantumAttestation, error)

	// AttestEpochBeacon produces the per-epoch beacon attestation.
	AttestEpochBeacon(ctx context.Context, requestingChain, keyID string, epoch uint64, previousRef [32]byte) (*QuantumAttestation, error)

	// VerifyAttestation verifies a QuantumAttestation against this node's
	// custody registry.
	VerifyAttestation(attestation *QuantumAttestation) error
}

MPCService is the M-Chain surface: threshold signing and bridge-custody attestation. It CONSUMES ThresholdService committees to sign / attest over cross-chain subjects. Owns no FHE.

type MessageRouter

type MessageRouter interface {
	// Send sends a message to the specified party (or broadcasts if To is empty)
	Send(msg *protocol.Message) error
	// Receive returns a channel for receiving incoming messages
	Receive() <-chan *protocol.Message
}

MessageRouter defines the interface for routing MPC messages between parties.

type NetworkStats

type NetworkStats struct {
	TotalSignatures   uint64            `json:"totalSignatures"`
	TotalKeygens      uint64            `json:"totalKeygens"`
	StagedCeremonies  int               `json:"stagedCeremonies"`
	SignaturesByChain map[string]uint64 `json:"signaturesByChain"`
}

NetworkStats counts what this node did: ceremonies it completed, and the ceremonies it has finished but not yet gotten into a block.

type Operation

type Operation struct {
	Type string
	// CeremonyID is derived from (keyID, digest, signer set) — never announced
	// by a coordinator. It is the ceremony log's primary key.
	CeremonyID string
	KeyID      string
	// RequestingChain names the chain that asked for this ceremony. Empty when
	// the ceremony was initiated on M-Chain itself.
	RequestingChain string
	// Digest is the 32 bytes the ceremony signed: the caller's message digest
	// for a sign, the key-commit digest for a keygen.
	Digest []byte
	// Artifact is the 65-byte r‖s‖v secp256k1 signature the ceremony produced.
	Artifact []byte
	// Signers is the participating set, canonically ordered.
	Signers []party.ID
	// Key is the registration carried by a keygen operation; nil otherwise.
	Key       *KeyRecord
	Timestamp int64
}

Operation is one verifiable state transition.

Key is non-nil exactly when Type is OpTypeKeygen: the operation carries the registration it is asking consensus to make, so there is no second place a key record can enter state.

type OracleCommitAttestation

type OracleCommitAttestation struct {
	RequestID   [32]byte `json:"requestId"`
	Kind        uint8    `json:"kind"` // 0 = write, 1 = read
	Root        [32]byte `json:"root"`
	RecordCount uint32   `json:"recordCount"`
}

OracleCommitAttestation contains details for oracle commit attestations

type PartyInfo

type PartyInfo struct {
	// PartyID and NodeID are the same value in two spellings — party.ID IS the
	// NodeID string — and both are reported so a caller reading either column
	// needs no side table to join them.
	PartyID string `json:"partyId"`
	NodeID  string `json:"nodeId"`
	IsLocal bool   `json:"isLocal"`
}

PartyInfo contains party information.

type Protocol

type Protocol string

Protocol represents a threshold signing protocol

const (
	// ECDSA Threshold Protocols
	ProtocolLSS     Protocol = "lss"     // Lux Secret Sharing - optimized for Lux
	ProtocolCGGMP21 Protocol = "cggmp21" // Canetti-Gennaro-Goldfeder-Makriyannis-Peled 2021

	// BLS Threshold (for validators)
	ProtocolBLS Protocol = "bls" // BLS threshold signatures

	// Post-Quantum Threshold
	ProtocolCorona Protocol = "corona" // Post-quantum lattice-based threshold

	// Experimental
	ProtocolFrost Protocol = "frost" // FROST (Flexible Round-Optimized Schnorr Threshold)
	ProtocolEDDSA Protocol = "eddsa" // EdDSA threshold (Ed25519)
)

type ProtocolConfig

type ProtocolConfig struct {
	Protocol     Protocol        `json:"protocol"`
	Threshold    int             `json:"threshold"`    // t: number of parties required
	TotalParties int             `json:"totalParties"` // n: total parties
	Curve        string          `json:"curve"`        // secp256k1, ed25519, bls12-381, etc.
	Options      ProtocolOptions `json:"options"`
}

ProtocolConfig contains configuration for a specific protocol

type ProtocolExecutor

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

ProtocolExecutor manages MPC protocol execution using the threshold library. It provides the bridge between ThresholdVM session management and the actual MPC protocol implementations.

func NewProtocolExecutor

func NewProtocolExecutor(workerPool *pool.Pool, logger log.Logger) *ProtocolExecutor

NewProtocolExecutor creates a new protocol executor.

func (*ProtocolExecutor) AcceptMessage

func (pe *ProtocolExecutor) AcceptMessage(sessionID string, msg *protocol.Message) error

AcceptMessage routes an incoming message to the appropriate handler.

func (*ProtocolExecutor) CMPKeygenStartFunc

func (pe *ProtocolExecutor) CMPKeygenStartFunc(
	selfID party.ID,
	participants []party.ID,
	threshold int,
) protocol.StartFunc

CMPKeygenStartFunc returns a StartFunc for CMP key generation.

func (*ProtocolExecutor) CMPRefreshStartFunc

func (pe *ProtocolExecutor) CMPRefreshStartFunc(config *cmpconfig.Config) protocol.StartFunc

CMPRefreshStartFunc returns a StartFunc for CMP key refresh.

func (*ProtocolExecutor) CMPSignStartFunc

func (pe *ProtocolExecutor) CMPSignStartFunc(
	config *cmpconfig.Config,
	signers []party.ID,
	messageHash []byte,
) protocol.StartFunc

CMPSignStartFunc returns a StartFunc for CMP signing.

func (*ProtocolExecutor) CreateHandler

func (pe *ProtocolExecutor) CreateHandler(
	ctx context.Context,
	sessionID string,
	startFunc protocol.StartFunc,
) (*protocol.Handler, error)

CreateHandler creates a new protocol handler for a session.

func (*ProtocolExecutor) FROSTKeygenStartFunc

func (pe *ProtocolExecutor) FROSTKeygenStartFunc(
	selfID party.ID,
	participants []party.ID,
	threshold int,
) protocol.StartFunc

FROSTKeygenStartFunc returns a StartFunc for FROST key generation.

func (*ProtocolExecutor) FROSTKeygenTaprootStartFunc

func (pe *ProtocolExecutor) FROSTKeygenTaprootStartFunc(
	selfID party.ID,
	participants []party.ID,
	threshold int,
) protocol.StartFunc

FROSTKeygenTaprootStartFunc returns a StartFunc for FROST Taproot key generation.

func (*ProtocolExecutor) FROSTRefreshStartFunc

func (pe *ProtocolExecutor) FROSTRefreshStartFunc(
	config *frostconfig.Config,
	participants []party.ID,
) protocol.StartFunc

FROSTRefreshStartFunc returns a StartFunc for FROST key refresh.

func (*ProtocolExecutor) FROSTSignStartFunc

func (pe *ProtocolExecutor) FROSTSignStartFunc(
	config *frostconfig.Config,
	signers []party.ID,
	messageHash []byte,
) protocol.StartFunc

FROSTSignStartFunc returns a StartFunc for FROST signing.

func (*ProtocolExecutor) GetHandler

func (pe *ProtocolExecutor) GetHandler(sessionID string) (*protocol.Handler, bool)

GetHandler retrieves an active handler by session ID.

func (*ProtocolExecutor) LSSKeygenStartFunc

func (pe *ProtocolExecutor) LSSKeygenStartFunc(
	selfID party.ID,
	participants []party.ID,
	threshold int,
) protocol.StartFunc

LSSKeygenStartFunc returns a StartFunc for LSS key generation.

func (*ProtocolExecutor) LSSRefreshStartFunc

func (pe *ProtocolExecutor) LSSRefreshStartFunc(config *lssconfig.Config) protocol.StartFunc

LSSRefreshStartFunc returns a StartFunc for LSS key refresh.

func (*ProtocolExecutor) LSSReshareStartFunc

func (pe *ProtocolExecutor) LSSReshareStartFunc(
	config *lssconfig.Config,
	newParticipants []party.ID,
	newThreshold int,
) protocol.StartFunc

LSSReshareStartFunc returns a StartFunc for LSS resharing.

func (*ProtocolExecutor) LSSSignStartFunc

func (pe *ProtocolExecutor) LSSSignStartFunc(
	config *lssconfig.Config,
	signers []party.ID,
	messageHash []byte,
) protocol.StartFunc

LSSSignStartFunc returns a StartFunc for LSS signing.

func (*ProtocolExecutor) RemoveHandler

func (pe *ProtocolExecutor) RemoveHandler(sessionID string)

RemoveHandler removes a handler from active tracking.

func (*ProtocolExecutor) RunCMPKeygen

func (pe *ProtocolExecutor) RunCMPKeygen(
	ctx context.Context,
	sessionID string,
	selfID party.ID,
	participants []party.ID,
	threshold int,
	messageRouter MessageRouter,
) (*cmpconfig.Config, error)

RunCMPKeygen executes a complete CMP key generation protocol.

func (*ProtocolExecutor) RunCMPRefresh

func (pe *ProtocolExecutor) RunCMPRefresh(
	ctx context.Context,
	sessionID string,
	config *cmpconfig.Config,
	messageRouter MessageRouter,
) (*cmpconfig.Config, error)

RunCMPRefresh executes a complete CMP key refresh protocol.

func (*ProtocolExecutor) RunCMPSign

func (pe *ProtocolExecutor) RunCMPSign(
	ctx context.Context,
	sessionID string,
	config *cmpconfig.Config,
	signers []party.ID,
	messageHash []byte,
	messageRouter MessageRouter,
) (*ECDSASignature, error)

RunCMPSign executes a complete CMP signing protocol.

func (*ProtocolExecutor) RunFROSTKeygen

func (pe *ProtocolExecutor) RunFROSTKeygen(
	ctx context.Context,
	sessionID string,
	selfID party.ID,
	participants []party.ID,
	threshold int,
	messageRouter MessageRouter,
) (*frostconfig.Config, error)

RunFROSTKeygen executes a complete FROST key generation protocol.

func (*ProtocolExecutor) RunLSSKeygen

func (pe *ProtocolExecutor) RunLSSKeygen(
	ctx context.Context,
	sessionID string,
	selfID party.ID,
	participants []party.ID,
	threshold int,
	messageRouter MessageRouter,
) (*lssconfig.Config, error)

RunLSSKeygen executes a complete LSS key generation protocol. This is a convenience method that creates a handler and waits for completion. For multi-party scenarios, use CreateHandler and manage message routing manually.

func (*ProtocolExecutor) RunLSSSign

func (pe *ProtocolExecutor) RunLSSSign(
	ctx context.Context,
	sessionID string,
	config *lssconfig.Config,
	signers []party.ID,
	messageHash []byte,
	messageRouter MessageRouter,
) (*ECDSASignature, error)

RunLSSSign executes a complete LSS signing protocol.

type ProtocolHandler

type ProtocolHandler interface {
	// Keygen generates a new threshold key
	Keygen(ctx context.Context, partyID party.ID, partyIDs []party.ID, threshold int) (KeyShare, error)

	// Sign creates a threshold signature
	Sign(ctx context.Context, share KeyShare, message []byte, signers []party.ID) (Signature, error)

	// Verify verifies a threshold signature
	Verify(pubKey []byte, message []byte, signature Signature) (bool, error)

	// Reshare reshares the key to a new set of parties
	Reshare(ctx context.Context, share KeyShare, newPartyIDs []party.ID, newThreshold int) (KeyShare, error)

	// Refresh refreshes the key shares without changing the public key
	Refresh(ctx context.Context, share KeyShare) (KeyShare, error)

	// Name returns the protocol name
	Name() Protocol

	// SupportedCurves returns the curves this protocol supports
	SupportedCurves() []string
}

ProtocolHandler defines the interface for all threshold protocols. Real implementations are in github.com/luxfi/threshold (LSS, CMP, FROST). Use ProtocolExecutor in executor.go for actual protocol execution.

type ProtocolInfo

type ProtocolInfo struct {
	Name            string   `json:"name"`
	Description     string   `json:"description"`
	SupportedCurves []string `json:"supportedCurves"`
	KeySize         int      `json:"keySize"`
	SignatureSize   int      `json:"signatureSize"`
	IsPostQuantum   bool     `json:"isPostQuantum"`
	SupportsReshare bool     `json:"supportsReshare"`
	SupportsRefresh bool     `json:"supportsRefresh"`
}

ProtocolInfo contains protocol information

func GetProtocolInfo

func GetProtocolInfo() []ProtocolInfo

GetProtocolInfo returns information about all supported protocols

type ProtocolOptions

type ProtocolOptions struct {
	// LSS Options
	LSSGeneration uint64 `json:"lssGeneration,omitempty"` // LSS generation number

	// CGGMP21 Options
	CMPPrecompute bool `json:"cmpPrecompute,omitempty"` // Enable precomputation for faster signing

	// BLS Options
	BLSScheme string `json:"blsScheme,omitempty"` // basic, min-pk, min-sig

	// Corona Options
	CoronaSecurityLevel int `json:"coronaSecurityLevel,omitempty"` // 128, 192, 256

	// General Options
	TimeoutSeconds int  `json:"timeoutSeconds,omitempty"`
	RetryOnFailure bool `json:"retryOnFailure,omitempty"`
}

ProtocolOptions contains protocol-specific options

type ProtocolRegistry

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

ProtocolRegistry manages available protocols

func NewProtocolRegistry

func NewProtocolRegistry(workerPool *pool.Pool) *ProtocolRegistry

NewProtocolRegistry creates a new protocol registry

func (*ProtocolRegistry) Available

func (r *ProtocolRegistry) Available() []Protocol

Available returns all available protocols

func (*ProtocolRegistry) Get

func (r *ProtocolRegistry) Get(protocol Protocol) (ProtocolHandler, error)

Get retrieves a protocol handler

func (*ProtocolRegistry) Register

func (r *ProtocolRegistry) Register(handler ProtocolHandler)

Register adds a protocol handler

type QuantumAttestation

type QuantumAttestation struct {
	// Domain specifies what is being attested (oracle/write, session/complete, etc.)
	Domain AttestationDomain `json:"domain"`

	// AttestationID is a unique identifier for this attestation
	AttestationID [32]byte `json:"attestationId"`

	// SubjectID is the ID of what is being attested (request_id, session_id, epoch number)
	SubjectID [32]byte `json:"subjectId"`

	// CommitmentRoot is the Merkle root being attested
	CommitmentRoot [32]byte `json:"commitmentRoot"`

	// Epoch in which this attestation was created
	Epoch uint64 `json:"epoch"`

	// Timestamp when attestation was created
	Timestamp time.Time `json:"timestamp"`

	// KeyID of the custody key that signed.
	KeyID string `json:"keyId"`

	// CeremonyID is the ceremony that produced Signature — the primary key of
	// the replicated ceremony log, so an attestation handed to another chain
	// can be looked up and re-checked against M-Chain state.
	CeremonyID string `json:"ceremonyId"`

	// Policy is the key's quorum in operator form ("3-of-5"). It is what
	// VerifyAttestation checks Signers against; a bare threshold number would
	// be ambiguous between signer count and polynomial degree.
	Policy quorum.Policy `json:"policy"`

	// Signers are the parties that participated, canonically ordered.
	Signers []party.ID `json:"signers"`

	// Signature is the 65-byte r‖s‖v threshold signature over the attestation
	// payload — the same encoding every ceremony artifact uses.
	Signature []byte `json:"signature"`
}

QuantumAttestation represents a threshold attestation over a commitment.

type QuotaInfo

type QuotaInfo struct {
	ChainID    string `json:"chainId"`
	DailyLimit uint64 `json:"dailyLimit"`
	UsedToday  uint64 `json:"usedToday"`
	Remaining  uint64 `json:"remaining"`
	ResetTime  int64  `json:"resetTime"`
}

QuotaInfo contains quota information

type RPCError

type RPCError struct {
	Code    int         `json:"code"`
	Message string      `json:"message"`
	Data    interface{} `json:"data,omitempty"`
}

RPCError represents a JSON-RPC error

func (*RPCError) Error

func (e *RPCError) Error() string

Error implements the error interface

type RPCRequest

type RPCRequest struct {
	JSONRPC string          `json:"jsonrpc"`
	ID      interface{}     `json:"id"`
	Method  string          `json:"method"`
	Params  json.RawMessage `json:"params"`
}

RPCRequest represents a JSON-RPC request

type RPCResponse

type RPCResponse struct {
	JSONRPC string      `json:"jsonrpc"`
	ID      interface{} `json:"id"`
	Result  interface{} `json:"result,omitempty"`
	Error   *RPCError   `json:"error,omitempty"`
}

RPCResponse represents a JSON-RPC response

type SchnorrSignature

type SchnorrSignature struct {
	R []byte
	Z []byte
}

SchnorrSignature wraps Schnorr signature from FROST.

type SessionCompleteAttestation

type SessionCompleteAttestation struct {
	SessionID    [32]byte `json:"sessionId"`
	OutputHash   [32]byte `json:"outputHash"`
	OracleRoot   [32]byte `json:"oracleRoot"`
	ReceiptsRoot [32]byte `json:"receiptsRoot"`
	StepCount    uint32   `json:"stepCount"`
}

SessionCompleteAttestation contains details for session completion attestations

type SignParams

type SignParams struct {
	KeyID string `json:"keyId"`
	// MessageHash is the exact 32 bytes to sign, hex encoded. M-Chain does not
	// hash on the caller's behalf: the caller owns its signing domain, and a
	// chain that re-hashed would sign a preimage nobody authorised.
	MessageHash     string `json:"messageHash"`
	RequestingChain string `json:"requestingChain"`
}

SignParams contains parameters for signing.

type SignRequest

type SignRequest struct {
	KeyID string `json:"keyId"`
	// MessageHash is the exact 32 bytes to sign. The caller owns its signing
	// domain; M-Chain signs what it is given and never re-hashes.
	MessageHash []byte `json:"messageHash"`
}

SignRequest contains parameters for signing.

type Signature

type Signature interface {
	// Bytes returns the raw signature bytes
	Bytes() []byte

	// R returns R component (for ECDSA)
	R() *big.Int

	// S returns S component (for ECDSA)
	S() *big.Int

	// V returns recovery ID (for ECDSA/Ethereum)
	V() byte

	// Protocol returns which protocol created this signature
	Protocol() Protocol
}

Signature represents a threshold signature (abstract)

type State added in v1.7.10

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

State is M-Chain's persisted state over one database. It owns the encoding and the root; it does not know what a ceremony means.

State is not safe for concurrent use; the VM holds it under its own lock. That is deliberate — a state machine with its own internal locking invites callers to interleave reads and writes across a transition and observe a half-applied block.

func NewState added in v1.7.10

func NewState(db database.Database, chainID ids.ID) (*State, error)

NewState opens state over db, resuming from whatever is already persisted. chainID seeds the genesis root so two different chains running the same operations do not produce the same root.

func (*State) BlockIDAtHeight added in v1.7.10

func (s *State) BlockIDAtHeight(height uint64) (ids.ID, error)

BlockIDAtHeight resolves a height to its accepted block id. This is the height index the engine relies on across restarts, so it is persisted rather than held in a map that empties on reboot.

func (*State) Ceremonies added in v1.7.10

func (s *State) Ceremonies() ([]*CeremonyRecord, error)

Ceremonies returns every recorded ceremony in id order.

func (*State) GetBlock added in v1.7.10

func (s *State) GetBlock(id ids.ID) ([]byte, error)

GetBlock reads a persisted block's bytes.

func (*State) GetCeremony added in v1.7.10

func (s *State) GetCeremony(id string) (*CeremonyRecord, error)

GetCeremony reads a recorded ceremony.

func (*State) GetKey added in v1.7.10

func (s *State) GetKey(keyID string) (*KeyRecord, error)

GetKey reads a registered custody key.

func (*State) GetShare added in v1.7.10

func (s *State) GetShare(keyID string) ([]byte, error)

GetShare reads this node's secret share for keyID.

func (*State) HasKey added in v1.7.10

func (s *State) HasKey(keyID string) (bool, error)

HasKey reports whether a key id is registered.

func (*State) HasShare added in v1.7.10

func (s *State) HasShare(keyID string) (bool, error)

HasShare reports whether this node participates in keyID's committee.

func (*State) Keys added in v1.7.10

func (s *State) Keys() ([]*KeyRecord, error)

Keys returns every registered custody key in key-id order.

func (*State) LastAccepted added in v1.7.10

func (s *State) LastAccepted() (id ids.ID, found bool, err error)

LastAccepted returns the persisted accepted tip. found is false on a fresh database, which is the caller's signal to install genesis.

func (*State) PutBlock added in v1.7.10

func (s *State) PutBlock(id ids.ID, height uint64, raw []byte) error

PutBlock persists an accepted block and its height index entry.

func (*State) PutCeremony added in v1.7.10

func (s *State) PutCeremony(c *CeremonyRecord) error

PutCeremony records a completed ceremony. Ceremony ids are derived from (key, digest, signer set), so a repeat id means a genuine replay of an identical task and is rejected: recording it twice would double-count a bridge release.

func (*State) PutKey added in v1.7.10

func (s *State) PutKey(r *KeyRecord) error

PutKey registers a custody key. Registration is once-only: a key id is a permanent binding to a group public key, and silently rebinding it would let a later ceremony redirect custody of live funds. Rotation is a new Generation of the same record via ReplaceKey, never a fresh PutKey.

func (*State) PutShare added in v1.7.10

func (s *State) PutShare(keyID string, share []byte) error

PutShare stores this node's secret key share for keyID.

This is the one secret M-Chain writes to disk, and it is written under the node/ prefix so it is structurally outside consensus state and outside Root(). The trust model is the validator's own disk — the same place its staking key lives. A node that loses this cannot sign for keyID and must be re-shared in; a node that leaks it has leaked one share, which is below the policy's corruption bound unless K-1 others leak too.

func (*State) ReplaceKey added in v1.7.10

func (s *State) ReplaceKey(r *KeyRecord) error

ReplaceKey overwrites an existing key record — the resharing/refresh path, where the group public key is unchanged but the shares and generation move.

func (*State) Root added in v1.7.10

func (s *State) Root() [32]byte

Root returns the current state root.

func (*State) SetLastAccepted added in v1.7.10

func (s *State) SetLastAccepted(id ids.ID, root [32]byte) error

SetLastAccepted records the accepted tip and the root that came with it, in that order: the root is durable before the tip that claims it, so a crash between the two leaves a tip whose root is already stored rather than a tip pointing at a root that was never written.

type ThresholdConfig

type ThresholdConfig struct {
	// Policy is the default signing policy for keys created on this chain,
	// written the way operators say it: "7-of-10" — seven of ten parties must
	// cooperate to produce one signature.
	//
	// It is deliberately NOT a bare number. A field called `threshold: 7` is
	// read as the signer count by operators and as the polynomial degree by
	// every threshold library, and those differ by one; a config that meant
	// 7-of-10 and was read as a degree produces an 8-of-10 key, silently. The
	// operator form cannot be misread, and the degree is derived from it at one
	// place (quorum.Policy.Degree) at the keygen boundary.
	Policy quorum.Policy `json:"policy"`

	// Session Configuration
	SessionTimeout      time.Duration `json:"sessionTimeout"`      // Max wall-clock for one ceremony
	MaxActiveSessions   int           `json:"maxActiveSessions"`   // Max concurrent ceremonies
	MaxSessionsPerChain int           `json:"maxSessionsPerChain"` // Max concurrent ceremonies per requesting chain
	MaxOpsPerBlock      int           `json:"maxOpsPerBlock"`      // Max operations in one block

	// Quota Configuration (daily limits)
	DailySigningQuota map[string]uint64 `json:"dailySigningQuota"` // ChainID -> daily signing limit

	// Authorized Chains that can request MPC services
	AuthorizedChains map[string]*ChainPermissions `json:"authorizedChains"`

	// Key Management
	KeyRotationPeriod time.Duration `json:"keyRotationPeriod"` // How often to rotate keys
	MaxKeyAge         time.Duration `json:"maxKeyAge"`         // Maximum age of a key before forced rotation
}

ThresholdConfig contains VM configuration.

type ThresholdInfo

type ThresholdInfo struct {
	Version          string   `json:"version"`
	NodeID           string   `json:"nodeId"`
	ChainID          string   `json:"chainId"`
	PartyID          string   `json:"partyId"`
	Policy           string   `json:"policy"` // default quorum, "3-of-5"
	AuthorizedChains []string `json:"authorizedChains"`
	TotalKeys        int      `json:"totalKeys"`
	SharesHeld       int      `json:"sharesHeld"`
	StagedCeremonies int      `json:"stagedCeremonies"`
	StateRoot        string   `json:"stateRoot"`
}

ThresholdInfo describes one M-Chain node: what the chain agrees on (policy, authorized chains, key count, state root) and what is true of THIS node (party id, shares held, staged ceremonies). The two are reported separately because conflating them is how an operator concludes the chain is broken when in fact this one validator holds no share.

type ThresholdService

type ThresholdService interface {
	// StartKeygen runs a distributed key-generation ceremony for keyID under
	// the chain's default policy, attributed to requestedBy.
	StartKeygen(ctx context.Context, keyID, requestedBy string) (*Operation, error)

	// StartKeygenWithPolicy runs DKG under an explicit k-of-n policy. The
	// polynomial degree is derived from the policy, never passed alongside it.
	StartKeygenWithPolicy(ctx context.Context, keyID string, policy quorum.Policy, requestedBy string) (*Operation, error)

	// Policy returns the chain's default signing policy.
	Policy() quorum.Policy

	// Committee returns the ceremony party set at a P-Chain height: this
	// chain's validators. Joining the signing ring is joining the validator
	// set — there is no separate operator registry.
	Committee(ctx context.Context, height uint64) ([]party.ID, error)

	// Key returns one custody key's replicated public record; Keys returns all
	// of them.
	Key(keyID string) (*KeyRecord, error)
	Keys() ([]*KeyRecord, error)

	// PublicKey returns the compressed group public key for keyID.
	PublicKey(keyID string) ([]byte, error)

	// Address returns the external-chain custody address derived from keyID's
	// group public key.
	Address(keyID string) ([]byte, error)
}

ThresholdService is the pure threshold-primitive surface — the substrate M-Chain (MPC) and F-Chain (FHE) both consume. It is distributed key generation, committee formation, and lookup of the artifacts those ceremonies produce. It deliberately excludes signing-for-custody (MPCService) and FHE execution (FHEService).

Every ceremony method takes a context and returns the COMPLETED ceremony's operation: a ceremony either finished (and its verifiable artifact is in hand) or it failed. There is no third "in progress" state to poll, because a handle to an unfinished ceremony is a handle to state that only one node has.

type VM

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

VM implements the Threshold VM for MPC-as-a-service

func (*VM) Address added in v1.7.10

func (vm *VM) Address(keyID string) ([]byte, error)

Address returns a custody key's external-chain address.

func (*VM) AttestBridgeTransfer

func (vm *VM) AttestBridgeTransfer(
	ctx context.Context,
	requestingChain string,
	keyID string,
	bt BridgeTransfer,
) (*BridgeTransferAttestation, error)

AttestBridgeTransfer produces a threshold attestation over a bridge transfer: compute the domain-bound digest, run the ceremony across the committee, and return the self-describing attestation B verifies.

The ceremony is complete when this returns — the signature is in the returned operation, and the same signature is recorded in the replicated ceremony log under op.CeremonyID once the block carrying it is accepted. B can therefore verify immediately (VerifyBridgeAttestation, no interaction) and audit later (Ceremony(id), against consensus state).

func (*VM) AttestEpochBeacon

func (vm *VM) AttestEpochBeacon(
	ctx context.Context,
	requestingChain string,
	keyID string,
	epoch uint64,
	previousRef [32]byte,
) (*QuantumAttestation, error)

AttestEpochBeacon creates a threshold attestation for epoch beacon randomness.

func (*VM) AttestOracleCommit

func (vm *VM) AttestOracleCommit(
	ctx context.Context,
	requestingChain string,
	keyID string,
	requestID [32]byte,
	kind uint8,
	commitRoot [32]byte,
	epoch uint64,
) (*QuantumAttestation, error)

AttestOracleCommit creates a threshold attestation for an oracle commitment.

func (*VM) AttestSessionComplete

func (vm *VM) AttestSessionComplete(
	ctx context.Context,
	requestingChain string,
	keyID string,
	sessionID [32]byte,
	outputHash [32]byte,
	oracleRoot [32]byte,
	receiptsRoot [32]byte,
	epoch uint64,
) (*QuantumAttestation, error)

AttestSessionComplete creates a threshold attestation for session completion.

func (*VM) BuildBlock

func (vm *VM) BuildBlock(ctx context.Context) (chain.Block, error)

BuildBlock implements the chain.ChainVM interface

func (*VM) Ceremonies added in v1.7.10

func (vm *VM) Ceremonies() ([]*CeremonyRecord, error)

Ceremonies returns the whole ceremony log.

func (*VM) Ceremony added in v1.7.10

func (vm *VM) Ceremony(id string) (*CeremonyRecord, error)

Ceremony returns a recorded ceremony — the durable, replicated evidence that a signature was produced, including the signature itself.

func (*VM) Committee added in v1.7.10

func (vm *VM) Committee(ctx context.Context, height uint64) ([]party.ID, error)

Committee returns the ceremony party set: every validator of this chain at the given P-Chain height, in canonical order.

party.ID is the NodeID string, so the mapping from a signer back to the peer that runs it is the exact inverse with no side table to drift out of sync. Canonical ordering makes the set order-independent, which is what lets every validator derive the same ceremony id without exchanging one.

func (*VM) Connected

func (vm *VM) Connected(ctx context.Context, nodeID ids.NodeID, nodeVersion *chain.VersionInfo) error

Connected implements the common.VM interface

func (*VM) CreateHandlers

func (vm *VM) CreateHandlers(ctx context.Context) (map[string]http.Handler, error)

CreateHandlers implements the common.VM interface

func (*VM) CreateStaticHandlers

func (vm *VM) CreateStaticHandlers(ctx context.Context) (map[string]http.Handler, error)

CreateStaticHandlers implements the common.VM interface

func (*VM) CrossChainRequest

func (vm *VM) CrossChainRequest(ctx context.Context, chainID ids.ID, requestID uint32, deadline time.Time, request []byte) error

CrossChainRequest implements the common.VM interface. This is how another chain (B-Chain for bridge custody) asks M-Chain for a ceremony.

The ceremony runs to completion here and its result is staged for the next block; the requester reads the outcome from the ceremony log, which is replicated, rather than from a reply that only this node would remember.

func (*VM) CrossChainRequestFailed

func (vm *VM) CrossChainRequestFailed(ctx context.Context, chainID ids.ID, requestID uint32, appErr *warp.Error) error

CrossChainRequestFailed implements the common.VM interface

func (*VM) CrossChainResponse

func (vm *VM) CrossChainResponse(ctx context.Context, chainID ids.ID, requestID uint32, response []byte) error

CrossChainResponse implements the common.VM interface

func (*VM) Disconnected

func (vm *VM) Disconnected(ctx context.Context, nodeID ids.NodeID) error

Disconnected implements the common.VM interface

func (*VM) FeePolicy

func (vm *VM) FeePolicy() fee.Policy

FeePolicy exposes the chain's declared fee policy for diagnostics and the boot-time Validate gate.

func (*VM) GetBlock

func (vm *VM) GetBlock(ctx context.Context, id ids.ID) (chain.Block, error)

GetBlock implements the chain.ChainVM interface

func (*VM) GetBlockIDAtHeight

func (vm *VM) GetBlockIDAtHeight(ctx context.Context, height uint64) (ids.ID, error)

GetBlockIDAtHeight implements the chain.HeightIndexedChainVM interface. The index is persisted, so it survives a restart — a purely in-memory height map answers "not found" for every accepted block after a reboot.

func (*VM) Gossip

func (vm *VM) Gossip(ctx context.Context, nodeID ids.NodeID, msg []byte) error

Gossip implements the common.VM interface. It is the single receive path for cross-validator MPC: every ceremony message (broadcast or directed) arrives here as app-gossip, is decoded to (sessionID, protocol.Message) and handed to the ceremony's router. Messages that arrive before our own router for that ceremony is registered are buffered and drained on register, so no round-one broadcast is lost to a start-order race.

func (*VM) HealthCheck

func (vm *VM) HealthCheck(ctx context.Context) (chain.HealthResult, error)

HealthCheck implements the common.VM interface.

Health is "can this node read its own state", not "does this node hold a key". M-Chain is a custody REGISTRY first and a signer second: a validator that holds no share still serves reads and still verifies every block, so gating health on key material would take healthy nodes out of rotation for doing their job correctly. What a share-less node cannot do — contribute a partial signature — is visible in sharesHeld.

func (*VM) Initialize

func (vm *VM) Initialize(
	ctx context.Context,
	init vmcore.Init,
) error

Initialize implements the chain.ChainVM interface

func (*VM) Key added in v1.7.10

func (vm *VM) Key(keyID string) (*KeyRecord, error)

Key returns a registered custody key's public record.

func (*VM) Keys added in v1.7.10

func (vm *VM) Keys() ([]*KeyRecord, error)

Keys returns every registered custody key.

func (*VM) LastAccepted

func (vm *VM) LastAccepted(ctx context.Context) (ids.ID, error)

LastAccepted implements the chain.ChainVM interface

func (*VM) NewHTTPHandler

func (vm *VM) NewHTTPHandler(ctx context.Context) (http.Handler, error)

NewHTTPHandler returns HTTP handlers for the VM

func (*VM) ParseBlock

func (vm *VM) ParseBlock(ctx context.Context, bytes []byte) (chain.Block, error)

ParseBlock implements the chain.ChainVM interface

func (*VM) Policy added in v1.7.10

func (vm *VM) Policy() quorum.Policy

Policy returns the chain's default signing policy.

func (*VM) PublicKey added in v1.7.10

func (vm *VM) PublicKey(keyID string) ([]byte, error)

PublicKey returns a custody key's compressed group public key.

func (*VM) Request

func (vm *VM) Request(ctx context.Context, nodeID ids.NodeID, requestID uint32, deadline time.Time, request []byte) error

Request implements the common.VM interface

func (*VM) RequestBridgeRelease added in v1.7.4

func (vm *VM) RequestBridgeRelease(ctx context.Context, req BridgeReleaseRequest) (*BridgeTransferAttestation, error)

RequestBridgeRelease is THE B→M seam: B calls this with a release request and gets back a threshold-signed, self-describing attestation. M computes the domain-bound digest, threshold-signs it across the committee, and returns the signature plus the group key and quorum B needs to verify — no callback to M. B's gate on the return value is VerifyBridgeAttestation.

The signature is a standard secp256k1 ECDSA signature over the domain-bound digest, so a destination-chain gateway contract verifies it exactly like a single-key signature (ecrecover to the custody address).

func (*VM) RequestFailed

func (vm *VM) RequestFailed(ctx context.Context, nodeID ids.NodeID, requestID uint32, appErr *warp.Error) error

RequestFailed implements the common.VM interface

func (*VM) RequestSignature

func (vm *VM) RequestSignature(ctx context.Context, requestingChain, keyID string, messageHash []byte) (*Operation, error)

RequestSignature produces a threshold signature over messageHash with a registered custody key and stages it for the next block.

func (*VM) Response

func (vm *VM) Response(ctx context.Context, nodeID ids.NodeID, requestID uint32, response []byte) error

Response implements the common.VM interface

func (*VM) RunKeygen added in v1.7.10

func (vm *VM) RunKeygen(ctx context.Context, keyID string, policy quorum.Policy, requestingChain string) (*Operation, error)

RunKeygen generates a custody key across the committee and stages its registration for the next block.

The ceremony is: distributed key generation (no dealer — no party ever holds the whole secret), then a threshold signature by the fresh group key over its own registration digest. That second step is the proof of possession: it demonstrates the committee really can sign with the key it is registering, so a key that would be dead on arrival never reaches the registry, and a proposer cannot register a public key it does not control.

Every participant runs this and stages an identical operation. Non-blocking on the caller's behalf is the caller's business; this returns when the ceremony is done.

func (*VM) RunSign added in v1.7.10

func (vm *VM) RunSign(ctx context.Context, keyID string, digest []byte, requestingChain string) (*Operation, error)

RunSign produces a threshold signature over digest with a registered custody key and stages it for the next block.

digest must be the exact 32 bytes to sign. M-Chain does not hash on the caller's behalf: the caller knows its own signing domain (an Ethereum tx hash, a bridge release digest), and a chain that re-hashes would produce signatures over a preimage the caller never authorised.

func (*VM) SetPreference

func (vm *VM) SetPreference(ctx context.Context, id ids.ID) error

SetPreference implements the chain.ChainVM interface

func (*VM) SetState

func (vm *VM) SetState(ctx context.Context, state uint32) error

SetState implements the common.VM interface

func (*VM) Shutdown

func (vm *VM) Shutdown(ctx context.Context) error

Shutdown implements the common.VM interface.

Nothing is flushed here. Every durable fact — registered keys, recorded ceremonies, key shares, the accepted tip — is written at the moment it becomes true, not at shutdown. A VM that persists its registry only on a clean shutdown loses it to any crash, kill or power cut, which for a custody chain means losing the record of who holds the funds.

func (*VM) StartKeygen

func (vm *VM) StartKeygen(ctx context.Context, keyID, requestedBy string) (*Operation, error)

StartKeygen generates a custody key using the chain's default policy.

func (*VM) StartKeygenWithPolicy added in v1.7.10

func (vm *VM) StartKeygenWithPolicy(ctx context.Context, keyID string, policy quorum.Policy, requestedBy string) (*Operation, error)

StartKeygenWithPolicy generates a custody key under an explicit k-of-n policy.

The policy is a quorum.Policy, not a pair of ints, so a caller cannot express the quorum ambiguously: "3-of-5" is the only spelling, and the polynomial degree is derived from it inside RunKeygen.

func (*VM) StateRoot added in v1.7.10

func (vm *VM) StateRoot() [32]byte

StateRoot returns the current state root — the value two validators compare to know whether they agree about custody.

func (*VM) VerifyAttestation

func (vm *VM) VerifyAttestation(a *QuantumAttestation) error

VerifyAttestation checks an attestation against this node's registry: the domain is one M-Chain issues, the quorum satisfies the key's policy, and the signature verifies under the registered group key over the recomputed payload.

It uses the same verifyGroupSignature that block.go uses to admit a ceremony to state, so an attestation cannot pass here under a rule that a block would have rejected.

func (*VM) Version

func (vm *VM) Version(ctx context.Context) (string, error)

Version implements the common.VM interface

func (*VM) WaitForEvent

func (vm *VM) WaitForEvent(ctx context.Context) (vmcore.Message, error)

WaitForEvent blocks until this VM has work for the engine.

M-Chain is demand-driven: it builds a block only when a ceremony has completed and staged an operation. Returning eagerly would spin the engine (the flood loop in chains/manager.go); blocking forever would mean a completed ceremony never reaches a block unless some other chain happened to wake the builder.

Directories

Path Synopsis
Package cert provides the QuasarCertLane registration and certificate-subject binding logic shared by M-Chain and F-Chain.
Package cert provides the QuasarCertLane registration and certificate-subject binding logic shared by M-Chain and F-Chain.
cmd
plugin command
Package fhe provides GPU-accelerated FHE operations for ThresholdVM.
Package fhe provides GPU-accelerated FHE operations for ThresholdVM.
protocol
cggmp21
Package cggmp21 declares the M-Chain CGGMP21 protocol surface.
Package cggmp21 declares the M-Chain CGGMP21 protocol surface.
corona_general
Package corona_general declares the M-Chain general-purpose Corona (Module-LWE) threshold protocol surface.
Package corona_general declares the M-Chain general-purpose Corona (Module-LWE) threshold protocol surface.
frost
Package frost declares the M-Chain FROST protocol surface.
Package frost declares the M-Chain FROST protocol surface.
tfhe_keygen
Package tfhe_keygen declares the cross-chain TFHE bootstrap-key generation surface.
Package tfhe_keygen declares the cross-chain TFHE bootstrap-key generation surface.
Package runtime defines the adapter contracts the host chains (M-Chain and F-Chain) implement to plug into the ThresholdVM substrate.
Package runtime defines the adapter contracts the host chains (M-Chain and F-Chain) implement to plug into the ThresholdVM substrate.
Package types defines the data types of the ThresholdVM substrate.
Package types defines the data types of the ThresholdVM substrate.

Jump to

Keyboard shortcuts

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