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
- Variables
- func ComputeAttestationPayload(domain AttestationDomain, subjectID, commitmentRoot [32]byte, epoch uint64) [32]byte
- func DetectEquivocation(a, b *QuantumAttestation) bool
- func KeyCommitDigest(r *KeyRecord) [32]byte
- func VerifyBridgeAttestation(groupPubKey []byte, bt BridgeTransfer, sig []byte) bool
- type AppNetwork
- type AttestationDomain
- type Block
- func (b *Block) Accept(ctx context.Context) error
- func (b *Block) Bytes() []byte
- func (b *Block) ChoicesStatus() choices.Status
- func (b *Block) Height() uint64
- func (b *Block) ID() ids.ID
- func (b *Block) Marshal() []byte
- func (b *Block) Parent() ids.ID
- func (b *Block) ParentID() ids.ID
- func (b *Block) Publish()
- func (b *Block) Reject(ctx context.Context) error
- func (b *Block) SetStatus(status choices.Status)
- func (b *Block) Status() uint8
- func (b *Block) Timestamp() time.Time
- func (b *Block) Verify(ctx context.Context) error
- func (b *Block) Write(database.Database) error
- type BridgeReleaseRequest
- type BridgeTransfer
- type BridgeTransferAttestation
- type Caller
- type CeremonyInfo
- type CeremonyRecord
- type ChainPermissions
- type Client
- func (c *Client) GetAddress(ctx context.Context, keyID string) ([]byte, error)
- func (c *Client) GetCeremony(ctx context.Context, ceremonyID string) (*CeremonyInfo, error)
- func (c *Client) GetInfo(ctx context.Context) (*ThresholdInfo, error)
- func (c *Client) GetKey(ctx context.Context, keyID string) (*KeyInfo, error)
- func (c *Client) GetPublicKey(ctx context.Context, keyID string) ([]byte, error)
- func (c *Client) GetQuota(ctx context.Context) (*QuotaInfo, error)
- func (c *Client) GetStats(ctx context.Context) (*NetworkStats, error)
- func (c *Client) Health(ctx context.Context) (map[string]interface{}, error)
- func (c *Client) ListCeremonies(ctx context.Context) ([]CeremonyInfo, error)
- func (c *Client) ListKeys(ctx context.Context) ([]KeyInfo, error)
- func (c *Client) StateRoot(ctx context.Context) (string, error)
- type CrossChainMPCRequest
- type ECDSASignature
- type EpochBeaconAttestation
- type FHEService
- type Factory
- type GPUBackend
- func (g *GPUBackend) CeremonyApply(desc *GPUMPCVMRoundDescriptor, ceremonyOps []GPUCeremonyOp, ...) (applied uint32, err error)
- func (g *GPUBackend) ContributionApply(desc *GPUMPCVMRoundDescriptor, contributionOps []GPUContributionOp, ...) (applied uint32, err error)
- func (g *GPUBackend) IsAvailable() bool
- func (g *GPUBackend) KeyShareApply(desc *GPUMPCVMRoundDescriptor, ceremonies []GPUCeremony, ...) (roundAdvance, finalized, failed uint32, err error)
- func (g *GPUBackend) MPCTransition(desc *GPUMPCVMRoundDescriptor, ceremonies []GPUCeremony, ...) (*GPUMPCVMTransitionResult, error)
- type GPUBackendKind
- type GPUCeremony
- type GPUCeremonyOp
- type GPUContribution
- type GPUContributionOp
- type GPUKeyShare
- type GPUMPCVMRoundDescriptor
- type GPUMPCVMState
- type GPUMPCVMTransitionResult
- type Genesis
- type GetCeremonyParams
- type GetChainPermissionsParams
- type GetKeyParams
- type GetQuotaParams
- type KeyInfo
- type KeyRecord
- type MPCService
- type MessageRouter
- type NetworkStats
- type Operation
- type OracleCommitAttestation
- type PartyInfo
- type ProtocolExecutor
- func (pe *ProtocolExecutor) CreateHandler(ctx context.Context, sessionID string, startFunc protocol.StartFunc) (*protocol.Handler, error)
- func (pe *ProtocolExecutor) Live() int
- func (pe *ProtocolExecutor) RemoveHandler(sessionID string)
- func (pe *ProtocolExecutor) RunCMPKeygen(ctx context.Context, sessionID string, selfID party.ID, ...) (*cmpconfig.Config, error)
- func (pe *ProtocolExecutor) RunCMPSign(ctx context.Context, sessionID string, config *cmpconfig.Config, ...) (*ECDSASignature, error)
- type QuantumAttestation
- type QuotaInfo
- type RPCError
- type RPCRequest
- type RPCResponse
- type SessionCompleteAttestation
- type State
- func (s *State) Ceremonies() ([]*CeremonyRecord, error)
- func (s *State) GetCeremony(id string) (*CeremonyRecord, error)
- func (s *State) GetKey(keyID string) (*KeyRecord, error)
- func (s *State) GetShare(keyID string) ([]byte, error)
- func (s *State) HasKey(keyID string) (bool, error)
- func (s *State) HasShare(keyID string) (bool, error)
- func (s *State) HoldRoot(root [32]byte)
- func (s *State) Keys() ([]*KeyRecord, error)
- func (s *State) PutCeremony(c *CeremonyRecord) error
- func (s *State) PutKey(r *KeyRecord) error
- func (s *State) PutShare(keyID string, share []byte) error
- func (s *State) ReadRoot() error
- func (s *State) Root() [32]byte
- func (s *State) WriteRoot(root [32]byte) error
- type ThresholdConfig
- type ThresholdInfo
- type ThresholdService
- type VM
- func (vm *VM) Address(keyID string) ([]byte, error)
- func (vm *VM) AdmitUserTx(paid uint64) error
- func (vm *VM) AttestBridgeTransfer(ctx context.Context, by Caller, keyID string, bt BridgeTransfer) (*BridgeTransferAttestation, error)
- func (vm *VM) AttestEpochBeacon(ctx context.Context, by Caller, keyID string, epoch uint64, ...) (*QuantumAttestation, error)
- func (vm *VM) AttestNFTOwnership(ctx context.Context, by Caller, keyID string, claim ownership.Claim) (*ownership.Attestation, error)
- func (vm *VM) AttestOracleCommit(ctx context.Context, by Caller, keyID string, requestID [32]byte, kind uint8, ...) (*QuantumAttestation, error)
- func (vm *VM) AttestSessionComplete(ctx context.Context, by Caller, keyID string, sessionID [32]byte, ...) (*QuantumAttestation, error)
- func (vm *VM) BuildBlock(ctx context.Context) (vmchain.Block, error)
- func (vm *VM) Ceremonies() ([]*CeremonyRecord, error)
- func (vm *VM) Ceremony(id string) (*CeremonyRecord, error)
- func (vm *VM) Committee(ctx context.Context, height uint64) ([]party.ID, error)
- func (vm *VM) Connected(ctx context.Context, nodeID ids.NodeID, nodeVersion *vmchain.VersionInfo) error
- func (vm *VM) CreateHandlers(ctx context.Context) (map[string]http.Handler, error)
- func (vm *VM) CreateStaticHandlers(ctx context.Context) (map[string]http.Handler, error)
- func (vm *VM) CrossChainRequest(ctx context.Context, chainID ids.ID, requestID uint32, deadline time.Time, ...) error
- func (vm *VM) CrossChainRequestFailed(ctx context.Context, chainID ids.ID, requestID uint32, appErr *warp.Error) error
- func (vm *VM) CrossChainResponse(ctx context.Context, chainID ids.ID, requestID uint32, response []byte) error
- func (vm *VM) Disconnected(ctx context.Context, nodeID ids.NodeID) error
- func (vm *VM) Fee() fee.Policy
- func (vm *VM) GetBlock(ctx context.Context, id ids.ID) (vmchain.Block, error)
- func (vm *VM) GetBlockIDAtHeight(ctx context.Context, height uint64) (ids.ID, error)
- func (vm *VM) Gossip(ctx context.Context, nodeID ids.NodeID, msg []byte) error
- func (vm *VM) HealthCheck(ctx context.Context) (vmchain.HealthResult, error)
- func (vm *VM) Initialize(ctx context.Context, init vmcore.Init) error
- func (vm *VM) Key(keyID string) (*KeyRecord, error)
- func (vm *VM) Keys() ([]*KeyRecord, error)
- func (vm *VM) LastAccepted(ctx context.Context) (ids.ID, error)
- func (vm *VM) NewHTTPHandler(ctx context.Context) (http.Handler, error)
- func (vm *VM) ParseBlock(ctx context.Context, bytes []byte) (vmchain.Block, error)
- func (vm *VM) Policy() quorum.Policy
- func (vm *VM) PublicKey(keyID string) ([]byte, error)
- func (vm *VM) Request(ctx context.Context, nodeID ids.NodeID, requestID uint32, deadline time.Time, ...) error
- func (vm *VM) RequestBridgeRelease(ctx context.Context, by Caller, req BridgeReleaseRequest) (*BridgeTransferAttestation, error)
- func (vm *VM) RequestFailed(ctx context.Context, nodeID ids.NodeID, requestID uint32, appErr *warp.Error) error
- func (vm *VM) RequestSignature(ctx context.Context, by Caller, keyID string, messageHash []byte) (*Operation, error)
- func (vm *VM) Response(ctx context.Context, nodeID ids.NodeID, requestID uint32, response []byte) error
- func (vm *VM) SetPreference(ctx context.Context, id ids.ID) error
- func (vm *VM) SetState(ctx context.Context, state uint32) error
- func (vm *VM) Shutdown(ctx context.Context) error
- func (vm *VM) StartKeygen(ctx context.Context, keyID string, by Caller) (*Operation, error)
- func (vm *VM) StartKeygenWithPolicy(ctx context.Context, keyID string, policy quorum.Policy, by Caller) (*Operation, error)
- func (vm *VM) StateRoot() [32]byte
- func (vm *VM) VerifyAttestation(a *QuantumAttestation) error
- func (vm *VM) Version(ctx context.Context) (string, error)
- func (vm *VM) WaitForEvent(ctx context.Context) (vmcore.Message, error)
Constants ¶
const ( OpTypeKeygen = "keygen" OpTypeSign = "sign" )
Operation kinds recorded on M-Chain.
const ( RPCErrorInvalidRequest = -32600 RPCErrorMethodNotFound = -32601 RPCErrorInvalidParams = -32602 RPCErrorInternal = -32603 RPCErrorQuotaExceeded = -32003 RPCErrorCeremonyNotFound = -32004 RPCErrorKeyNotFound = -32005 )
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.
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 ¶
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") ErrStaleParent = errors.New("mpcvm: parent block is not this node's applied state") ErrBlockTooLarge = errors.New("mpcvm: block carries more operations than a block may") ErrFutureBlock = errors.New("mpcvm: block timestamp is too far ahead of this node's clock") )
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") )
var ( ErrKeyExists = errors.New("mpcvm: key already registered") ErrUnknownKey = errors.New("mpcvm: key not registered") ErrCeremonyExists = errors.New("mpcvm: ceremony already recorded") ErrPolicyMismatch = errors.New("mpcvm: key policy does not match its participant set") ErrRootMismatch = errors.New("mpcvm: post-state root mismatch") )
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") ErrQuotaExceeded = errors.New("mpcvm: signing quota exceeded") )
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).
var VMID = constants.MPCVMID
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
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 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.
const DomainNFTOwnership AttestationDomain = ownership.Domain
DomainNFTOwnership registers the ownership domain with the attestation domain registry. The name and the separator both come from chains/ownership, which is also what every verifier hashes — one constant, so M and its verifiers cannot drift into signing and checking different bytes.
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 ¶
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) ChoicesStatus ¶
func (*Block) Marshal ¶ added in v1.7.4
Marshal encodes the block (excluding the derived ID_) to canonical wire.
Encoding cannot fail. A builder writes into a buffer it sized itself, so there is no input for which this returns half a block — which is why it returns bytes rather than bytes and an error nobody could produce and every caller discarded.
func (*Block) Publish ¶ added in v1.7.35
func (b *Block) Publish()
Publish makes the block's root current and releases the ceremonies it carried. It runs after the commit, so the root this node reports is one that is on disk and a ceremony leaves the staging queue only once the block recording it is durable.
func (*Block) Verify ¶
Verify re-checks the proposed transition against this validator's own state. It mutates nothing: a rejected block must leave state untouched.
func (*Block) Write ¶ added in v1.7.35
Write folds the block's operations into the registry and the ceremony log, and stages the root they reach.
The root check used to run AFTER every key and ceremony had already been written, so refusing here left exactly the disagreeing state it refuses to persist — and the duplicate guards in PutKey and PutCeremony then made that block permanently unacceptable, wedging the chain at that height. Now nothing is durable until the check has passed and the whole block commits.
type BridgeReleaseRequest ¶ added in v1.7.4
type BridgeReleaseRequest struct {
// 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 Caller ¶ added in v1.7.25
type Caller struct {
// contains filtered or unexported fields
}
Caller is a chain whose identity the TRANSPORT authenticated.
It cannot be built from a request body. The only constructor takes the chain id the transport supplies, so "who is asking" is never a field the asker writes about itself. A name in a payload is a claim, and a claim its own subject authored proves nothing — the same reason a node's ownership attestation is read out of M-Chain consensus state and not out of the node's own config, where its operator could write whatever it liked.
The zero Caller holds no permissions and can do nothing, so a path that forgets to authenticate fails closed rather than silently acquiring rights.
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
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 reads one M-Chain node over its JSON-RPC endpoint: the custody registry, the ceremony log, the state root, and what the node itself is.
func NewClient ¶
NewClient builds a client bound to one endpoint, identifying itself as chainID for the RPCs that report per-chain quota.
func (*Client) GetAddress ¶
GetAddress retrieves the address for a key ID
func (*Client) GetCeremony ¶ added in v1.7.10
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) GetPublicKey ¶
GetPublicKey retrieves the public key for a key ID
func (*Client) GetStats ¶
func (c *Client) GetStats(ctx context.Context) (*NetworkStats, error)
GetStats retrieves this node's ceremony counters.
func (*Client) ListCeremonies ¶ added in v1.7.10
func (c *Client) ListCeremonies(ctx context.Context) ([]CeremonyInfo, error)
ListCeremonies reads the whole ceremony log.
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
type ECDSASignature ¶
ECDSASignature is a threshold ECDSA signature in the one encoding M-Chain stores and every verifier reads: r(32) ‖ s(32) ‖ v(1).
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 Factory ¶
type Factory struct{}
The value is held by TestVMID_Bytes and TestVMID_IsCanonicalAndStable, which compare it to the literal bytes and to the CB58 the plugin binary is named after.
It used to also carry `var _ = map[bool]struct{}{VMID == ids.ID{...}: {}}`, labelled a compile-time assertion. It is not one: a map literal with a single non-constant key compiles whatever the key evaluates to — only a DUPLICATE constant key is a compile error. So it held for every possible value of VMID, including a wrong one, while reading as proof. A check that cannot fail is worse than no check, because it stops anyone writing the one that can. Factory creates M-Chain VM instances.
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 {
}
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
CeremonyRoot [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
RoundAdvanceCount uint32
Epoch uint64
NowNs uint64
CeremonyRoot [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 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.
type MPCService ¶
type MPCService interface {
ThresholdService
// RequestSignature asks the custody committee for keyID to threshold-sign
// messageHash on behalf of the AUTHENTICATED caller. It returns when the ceremony
// has produced a signature that verifies under the registered group key.
RequestSignature(ctx context.Context, by Caller, 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, by Caller, req BridgeReleaseRequest) (*BridgeTransferAttestation, error)
// AttestOracleCommit produces a threshold attestation over an oracle
// read/write commitment for requestingChain.
AttestOracleCommit(ctx context.Context, by Caller, 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, by Caller, 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, by Caller, 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 party it addresses, or broadcasts it to the
// whole ceremony when To is empty.
Send(msg *protocol.Message) error
// Receive yields messages addressed to this party.
Receive() <-chan *protocol.Message
}
MessageRouter carries one ceremony's protocol messages between parties. It never interprets them: the cryptography is the threshold library's, the delivery is the router's, and neither knows the other's business.
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
}
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 ProtocolExecutor ¶
type ProtocolExecutor struct {
// contains filtered or unexported fields
}
ProtocolExecutor drives threshold protocols to completion over a router.
func NewProtocolExecutor ¶
func NewProtocolExecutor(workerPool *pool.Pool, logger log.Logger) *ProtocolExecutor
NewProtocolExecutor creates a new protocol executor.
func (*ProtocolExecutor) CreateHandler ¶
func (pe *ProtocolExecutor) CreateHandler( ctx context.Context, sessionID string, startFunc protocol.StartFunc, ) (*protocol.Handler, error)
CreateHandler starts one ceremony and registers it under sessionID.
func (*ProtocolExecutor) Live ¶ added in v1.7.35
func (pe *ProtocolExecutor) Live() int
Live reports how many ceremonies this executor is driving. It is what a leaked handler shows up in.
func (*ProtocolExecutor) RemoveHandler ¶
func (pe *ProtocolExecutor) RemoveHandler(sessionID string)
RemoveHandler stops a ceremony and forgets it. Idempotent.
func (*ProtocolExecutor) RunCMPKeygen ¶
func (pe *ProtocolExecutor) RunCMPKeygen( ctx context.Context, sessionID string, selfID party.ID, participants []party.ID, threshold int, router MessageRouter, ) (*cmpconfig.Config, error)
RunCMPKeygen runs one distributed key generation to completion. threshold is the polynomial degree t, never the signer count: see quorum.Policy.Degree.
func (*ProtocolExecutor) RunCMPSign ¶
func (pe *ProtocolExecutor) RunCMPSign( ctx context.Context, sessionID string, config *cmpconfig.Config, signers []party.ID, messageHash []byte, router MessageRouter, ) (*ECDSASignature, error)
RunCMPSign runs one signing ceremony to completion and returns the canonical Ethereum r‖s‖v encoding.
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
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 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 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
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) Ceremonies ¶ added in v1.7.10
func (s *State) Ceremonies() ([]*CeremonyRecord, error)
Ceremonies returns every recorded ceremony in id order.
func (*State) GetCeremony ¶ added in v1.7.10
func (s *State) GetCeremony(id string) (*CeremonyRecord, error)
GetCeremony reads a recorded ceremony.
func (*State) HasShare ¶ added in v1.7.10
HasShare reports whether this node participates in keyID's committee.
func (*State) HoldRoot ¶ added in v1.7.35
HoldRoot makes a committed root current. It runs after the commit, so the root this node reports is always one that is on disk.
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
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.
It is the ONLY writer of the key registry. There was a second — a ReplaceKey that overwrote a record in place for a resharing path that does not exist — and a second writer into a registry whose whole value is "this binding never moves" is a rebinding waiting for its first caller.
func (*State) PutShare ¶ added in v1.7.10
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) ReadRoot ¶ added in v1.7.35
ReadRoot puts the committed root back, discarding an advance that belonged to a block whose writes were discarded.
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"`
// SessionTimeout is the wall clock one ceremony gets before it is abandoned.
//
// It is the only session knob. There were three more — a global concurrency
// cap, a per-chain concurrency cap and a per-block operation cap — and not
// one of them was ever read. The last was the dangerous one: a block-size
// bound is a consensus rule, and had it been read where it looks like it
// belongs, two validators configured differently would have reached
// opposite verdicts on the same block. It is a constant now
// (maxOpsPerBlock), where an operator cannot move it.
SessionTimeout time.Duration `json:"sessionTimeout"`
// DailySigningQuota overrides a chain's own DailySigningLimit, by chain
// name. It is per-node rate limiting, not consensus: refusing to START a
// ceremony is local, and a ceremony that completes is verified by everyone
// on its own evidence.
DailySigningQuota map[string]uint64 `json:"dailySigningQuota"`
// AuthorizedChains is the custody permission table, keyed by the operator's
// label for a chain. Authorization binds to the entry's ChainID; see
// caller.go.
AuthorizedChains map[string]*ChainPermissions `json:"authorizedChains"`
}
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"`
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 the AUTHENTICATED caller.
StartKeygen(ctx context.Context, keyID string, by Caller) (*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, by Caller) (*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) AdmitUserTx ¶ added in v1.7.35
AdmitUserTx is the refusal itself, so "M-Chain takes no user transactions" is a value that can be exercised rather than a comment.
func (*VM) AttestBridgeTransfer ¶
func (vm *VM) AttestBridgeTransfer( ctx context.Context, by Caller, 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, by Caller, keyID string, epoch uint64, previousRef [32]byte, ) (*QuantumAttestation, error)
AttestEpochBeacon creates a threshold attestation for epoch beacon randomness.
func (*VM) AttestNFTOwnership ¶ added in v1.7.16
func (vm *VM) AttestNFTOwnership( ctx context.Context, by Caller, keyID string, claim ownership.Claim, ) (*ownership.Attestation, error)
AttestNFTOwnership threshold-signs an ownership claim and returns it in the portable, self-describing form a verifier consumes — the claim, the quorum that signed, and the group key, so verification needs no callback to M.
The claim's Block is used as the attestation epoch. That makes the temporal binding exactly the block the ownership read was taken at, which gives equivocation a precise meaning: two different facts about one node at one block are contradictory and slashable (DetectEquivocation), while re-attesting the same node at a LATER block is the legitimate way ownership changes hands.
func (*VM) AttestOracleCommit ¶
func (vm *VM) AttestOracleCommit( ctx context.Context, by Caller, 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, by Caller, 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 ¶
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
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 *vmchain.VersionInfo) error
Connected implements the common.VM interface
func (*VM) CreateHandlers ¶
CreateHandlers implements the common.VM interface
func (*VM) CreateStaticHandlers ¶
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 ¶
Disconnected implements the common.VM interface
func (*VM) Fee ¶ added in v1.7.35
Fee is what M-Chain charges to admit a user transaction, which is nothing, because it admits none: it is a committee-driven service VM, and keygen and signing requests reach it from validators through consensus rather than from a mempool. Initialize pins the closed sentinel and the node's boot-time nodefee.Validate reads it back through here.
There was also a gateUserTx() wrapper, described as the gate every user-callable entry MUST route through. Nothing routed through it, because M-Chain has no user-callable entry — a refusal nobody can reach is a statement, and this is where the statement belongs.
func (*VM) GetBlockIDAtHeight ¶
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 ¶
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.
It is also where a ceremony message becomes attributable. The threshold library carries the sender in the message body and does not authenticate it — it is written for an authenticated channel and expects its transport to supply that. This is the transport. The p2p layer authenticated nodeID, and party.ID IS the NodeID string on this chain, so a message whose From names a different party is one peer speaking as another. Delivering it would let any node that can reach this method inject rounds as any committee member: enough to abort every custody ceremony on demand, and enough to make the protocol's identifiable abort name an honest validator for it.
func (*VM) HealthCheck ¶
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 ¶
Initialize implements the chain.ChainVM interface
func (*VM) LastAccepted ¶
LastAccepted implements the chain.ChainVM interface
func (*VM) NewHTTPHandler ¶
NewHTTPHandler returns HTTP handlers for the VM
func (*VM) ParseBlock ¶
ParseBlock implements the chain.ChainVM interface
func (*VM) PublicKey ¶ added in v1.7.10
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, by Caller, 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, by Caller, 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) SetPreference ¶
SetPreference implements the chain.ChainVM interface
func (*VM) Shutdown ¶
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 ¶
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, by Caller) (*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
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) WaitForEvent ¶
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.
Source Files
¶
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
Command plugin serves the M-Chain VM to a Lux node.
|
Command plugin serves the M-Chain VM to a Lux node. |
|
Package fhe provides GPU-accelerated FHE operations for ThresholdVM.
|
Package fhe provides GPU-accelerated FHE operations for ThresholdVM. |
|
Package types defines the data types of the ThresholdVM substrate.
|
Package types defines the data types of the ThresholdVM substrate. |