molpha-verifier crate all implement it identically.
The verification pipeline
The message has no
chainId, so one signature is valid on every chain. Payload fields and encoding are described in Attestations.
Node selection
Each round, a pseudo-random subset of the registry version’s nodes (the selection set) is eligible to sign. It is derived only from values in the payload and the registry snapshot, so every verifier reproduces it independently.nodeCountandredundancyBufferare those of the payload’sregistryVersion. Changing the buffer publishes a new registry version, so selection for an existing version never changes.- The buffer widens the eligible set so a round can reach its quorum when some selected nodes are offline.
- Selection reads only whole seconds. All rounds of one source and registry version within the same second share one selection set.
- The caller does not choose the timestamp; the gateway stamps it. See Security model for what that does and does not protect.
Derivation algorithm
deriveWithoutReplacement(selectionSeed, nodeCount, groupSize) samples without replacement:
- PRF:
keccak256(seed ‖ SELECTION_DOMAIN ‖ counter). Each 256-bit digest yields eight big-endianuint32limbs. - Bias rejection: a limb is rejected when
limb ≥ floor((2³² − 1) / nodeCount) · nodeCount. An accepted limb maps tolimb % nodeCount, skipping positions already chosen. - Complement path: when
groupSize > nodeCount / 2, the algorithm samples thenodeCount − groupSizeexcluded nodes and complements the mask.
verify cost on Starknet is not strictly linear in signer count.
Bitmaps
Bit
i is the node at 0-based index i of the registry version. A registry holds at most 256 nodes, one 256-bit word.
Plain-sum aggregation
Molpha aggregates Schnorr signatures over secp256k1 by plain summation, with mandatory proof of possession at registration. It is not MuSig2: there are no delinearization coefficients and no precomputed aggregate key. The verification key for a round is the sum of the actual signers’ public keys, recomputed by the verifier from the registry snapshot. The signer set cannot be forged:signersBitmapis inside the signed message, so the signature commits to exactly which keys took part.- A valid aggregate over keys that did not all contribute would require breaking the discrete logarithm, given that every key has a proof of possession.
- Signers must fall inside the selection set, so registered nodes cannot sign rounds they were not selected for.
Proof of possession
Plain-sum aggregation is open to rogue-key attacks unless every key is proven to belong to its registrant. Each chain checks a Schnorr proof of possession before a key enters any registry snapshot.
The Solana labels are raw ASCII, not hashed. On Solana a signing key can be registered only once (
Secp256k1KeyClaim). EVM and Starknet reject a zero signature or commitment, off-curve keys and s >= Q.
The proof binds one deployment, so nodes produce one proof per chain. Proof of possession is checked only at registration, never in verify, so attestation signatures stay chain-agnostic.
Domain separators
The first three are identical in every implementation. Solana uses its own proof-of-possession labels, shown above. The Solana program also uses raw ASCII labels for epoch tickets (
MOLPHA_TICKET_V1, MOLPHA_TICKET_ID_V1, MOLPHA_DISPATCH_V1); see Epoch settlement.
The off-chain round
The node network and the gateways run the signing session: nonce commitments, message transport and retries. Whatever the transport, a verifier accepts only an aggregate that:- covers
(value, sourceId, registryVersion, signaturesRequired, timestamp, signersBitmap)underMOLPHA_MESSAGE_V1; - comes from at least
signaturesRequiredsigners, all inside the selection set; - is a plain-sum aggregate over exactly the keys in
signersBitmap.