DataUpdate + AggregatedSig) that verifies unmodified on Solana, EVM, and Starknet.
The round
Each round is anchored by itscanonicalTimestamp — the off-chain unix time (seconds) at which the value was produced. The timestamp is part of the signed message and is also an input to node selection, so it cannot be altered without invalidating the signature.
Rounds are pull-native — they run on demand:
DataUpdate — the signed payload
ADataUpdate is the signed result of one round. It is self-contained: everything verification needs is in the struct or derivable from it.
| Field | Meaning |
|---|---|
jobId | keccak256("MOLPHA_JOB_V1" || owner || apiConfigHash) — commits the payload to a specific job config |
registryVersion | The immutable node-set snapshot the signature was produced against |
signaturesRequired | The quorum threshold for this update |
value | The signed result — a 32-byte big-endian word, encoding job-defined |
canonicalTimestamp | Off-chain unix time (seconds) the value was produced; also a node-selection input |
DataUpdate / SchnorrSignature in Solidity, Cairo, and Rust) live in each verifier reference: Solana, EVM, Starknet.
The signed message
The aggregate signature covers:signersBitmapis inside the message — the exact signer set is bound into the signature, not chosen after the fact.- No
chainId— the same signature is valid on every supported chain.
AggregatedSig — one signature from many signers
Molpha uses PoP-Schnorr aggregation over secp256k1: plain-sum Schnorr with mandatory proof-of-possession at node registration. The aggregate verification key is always the plain elliptic-curve sum of the actual signers’ keys — there are no MuSig2 delinearization coefficients and no global precomputed aggregate key. The full verification math is in Cryptography. The signature payload carries three components —signature (the aggregate Schnorr scalar s), commitment (the Ethereum-style address of the nonce point R), and signersBitmap.
Signers bitmap
Participation is a 256-bit bitmap: biti-1 is set iff the 1-based node index i signed. A registry holds at most 256 nodes, so one word always suffices. popcount(signersBitmap) is the signer count, which must be at least signaturesRequired.
The bitmap is part of the signed message above — the signer set is committed by the signature itself, and every signer must additionally fall inside the deterministic selection set for the round.
Consumption
On Solana, the payload can be written to the job’sFeed account via the permissionless submit_data_update instruction. A new value is only accepted if its canonical_timestamp is strictly greater than the stored one (monotonic freshness). On EVM and Starknet, your contract calls verify() and applies its own freshness policy. See the guides for each path.