Aere Network public source. Everything here can be checked against the live chain (chain id 2800, https://rpc.aere.network). Scope note, stated up front rather than buried: consensus on chain 2800 is classical secp256k1 ECDSA QBFT. The post-quantum work in this repository is at the signature, precompile, account and transport layers. Nothing here makes the consensus post-quantum, and no document in it should be read as claiming so.
211 lines
12 KiB
Markdown
211 lines
12 KiB
Markdown
# AerePQAggregate: constant-cost t-of-n post-quantum committee authorization
|
|
|
|
Status: on-chain verifier and ERC-7579 module BUILT and TESTED against a mock SP1 gateway.
|
|
Off-chain SP1 aggregation circuit NOT implemented, [MEASURE], research frontier.
|
|
|
|
Scope: account and authorization layer only. This changes nothing about Aere Network
|
|
consensus, which stays classical ECDSA QBFT. What is post-quantum here is the AUTHORITY
|
|
that approves a message, not the block production.
|
|
|
|
Contracts:
|
|
- `contracts/contracts/mpc/AerePQAggregateVerifier.sol`
|
|
- `contracts/contracts/modular/AerePQAggregateModule.sol`
|
|
- Test: `contracts/test/AerePQAggregate.test.js` (17 passing)
|
|
|
|
---
|
|
|
|
## 1. The problem this answers
|
|
|
|
NIST post-quantum signatures are large. An ML-DSA-65 signature is about 3,300 bytes, an
|
|
ML-DSA-44 signature about 2,420 bytes, an SLH-DSA-128s signature about 7,856 bytes. A t-of-n
|
|
committee that authorizes on-chain by supplying t independent PQC signatures therefore pays,
|
|
on-chain, for t signature verifications plus t large calldata blobs. That cost is LINEAR in t
|
|
and, under a per-transaction gas ceiling (Aere Network keeps Fusaka's EIP-7825 cap of 2^24 gas),
|
|
it bounds how large a committee can practically authorize in one transaction. This is the same
|
|
economic wall that motivates EIP-7932 (transaction-level signature abstraction for large or
|
|
alternative signature schemes): post-quantum signatures do not fit the classical fixed-size
|
|
signature budget.
|
|
|
|
`AereThresholdPQCRegistry` (already in this repo) takes the honest linear path: it verifies t
|
|
INDEPENDENT PQC signatures on-chain through Aere Network's live precompiles. Every leg is a real
|
|
NIST PQC signature, the t-of-n participation is proven on-chain, and the cost is linear in t.
|
|
|
|
`AerePQAggregate` takes the succinct path. It moves the t (up to n) signature verifications OFF
|
|
the chain, into a zero-knowledge virtual machine (the SP1 zkVM), and verifies ONE small proof
|
|
on-chain. The on-chain cost becomes INDEPENDENT of the committee size n.
|
|
|
|
---
|
|
|
|
## 2. The scheme
|
|
|
|
### Off-chain (the SP1 aggregation circuit, [MEASURE], NOT implemented here)
|
|
|
|
A relying party commits, once, to a committee: a `root` (a binding commitment to the exact n
|
|
authorized PQC public keys, for example a Merkle root over the canonically ordered keys or the
|
|
keccak256 of the canonical key list), a threshold `t`, a size `n`, and a `scheme`.
|
|
|
|
To authorize a 32-byte `messageDigest`, an off-chain prover runs the aggregation guest program
|
|
inside the SP1 zkVM with:
|
|
- PRIVATE witness: the n committed public keys, and at least t PQC signatures over `messageDigest`.
|
|
- The circuit MUST, inside the zkVM:
|
|
1. recompute `root` from the witnessed keys (and abort if it does not match the committed root),
|
|
2. verify each of the counted signatures against a DISTINCT committed key over `messageDigest`,
|
|
using the scheme's real verification algorithm,
|
|
3. never double-count a key (distinctness by committed index),
|
|
4. output the PUBLIC values below.
|
|
- PUBLIC output (the fixed 192-byte layout the on-chain verifier decodes):
|
|
`abi.encode(bytes32 committeeRoot, uint256 threshold, uint256 committeeSize, uint256 scheme,
|
|
bytes32 messageDigest, uint256 validCount)`
|
|
where `validCount` is the number of distinct valid signatures the circuit verified, and must be
|
|
at least `threshold`.
|
|
|
|
The proof is succinct: its size and its on-chain verification cost are fixed by the SP1 verifier,
|
|
independent of n and of how many signatures the circuit checked internally.
|
|
|
|
### On-chain (BUILT and TESTED here)
|
|
|
|
`AerePQAggregateVerifier`:
|
|
1. `registerCommittee(root, t, n, scheme)` stores the committee. The n public keys are NOT stored
|
|
on-chain (storing them would reintroduce the O(n) cost the design removes); `root` is the sole
|
|
on-chain commitment to them. Permissionless, no admin, holds no funds.
|
|
2. `verifyAggregate(committeeId, messageDigest, publicValues, proofBytes)` binds the proof's public
|
|
values to the registered committee and to the caller's claimed message, then makes a SINGLE
|
|
`verifyProof` call to the deployed SP1 verifier gateway. It is fail-closed: it rejects unless
|
|
ALL hold:
|
|
- the committee is registered,
|
|
- `publicValues.committeeRoot == committee.root` (the sole authority binding),
|
|
- `publicValues.threshold / committeeSize / scheme == committee.{threshold,size,scheme}`
|
|
(defense in depth),
|
|
- `publicValues.messageDigest == messageDigest` (the caller's claimed message),
|
|
- `publicValues.validCount >= committee.threshold`,
|
|
- the SP1 proof verifies against the pinned circuit vkey (`verifyProof` REVERTS on an invalid
|
|
proof).
|
|
3. `tryVerifyAggregate(...)` is the non-reverting variant (returns bool) used by the ERC-4337 and
|
|
ERC-7579 validation paths, which SHOULD return a failure code rather than revert.
|
|
4. `recordAggregate(...)` verifies (strict) and records an on-chain provenance attestation.
|
|
|
|
The circuit is pinned. `AGGREGATE_PROGRAM_VKEY` is fixed at construction, so a registrant cannot
|
|
substitute a different circuit: every committee is proven by the same audited program through the
|
|
same immutable gateway. Deploy one verifier per circuit (for example one for the ML-DSA-65
|
|
aggregation program).
|
|
|
|
The deployed SP1 verifier gateway on Aere Network mainnet (chain 2800) is the canonical Succinct
|
|
gateway at `0x9ca479C8c52C0EbB4599319a36a5a017BCC70628`, the same gateway the parallel-execution
|
|
validity contracts and the zk light clients already call.
|
|
|
|
---
|
|
|
|
## 3. The gas argument: constant vs linear in n
|
|
|
|
The verifier does NO per-member work on-chain. There is no loop over keys, no per-signature
|
|
precompile call, no per-member calldata. It reads a fixed committee record, compares six words of
|
|
public values, and makes one `verifyProof` call. The cost is therefore fixed by the SP1 verifier
|
|
and independent of n.
|
|
|
|
Measured in the test suite (`recordAggregate`, mock gateway):
|
|
|
|
| committee size n | gas used |
|
|
| ---------------- | -------- |
|
|
| 5 | 61,799 |
|
|
| 1,000,000 | 61,823 |
|
|
|
|
n grew by 200,000x; gas moved by 24 (the calldata encoding of the larger integer, which is
|
|
O(log n), not O(n)). A linear on-chain t-of-n PQC verifier pays tens of thousands of gas PER
|
|
signature (the marginal precompile verify cost for ML-DSA-44 is about 55,000 gas, before calldata),
|
|
so at even a modest committee it hits the per-transaction gas ceiling; the aggregate path does not.
|
|
|
|
(The gas figures above are for the mock gateway. The REAL SP1 Groth16/Plonk verifier is more
|
|
expensive per call but still CONSTANT in n; the constant-vs-linear conclusion is what the on-chain
|
|
design guarantees. The absolute real-gateway number is [MEASURE].)
|
|
|
|
---
|
|
|
|
## 4. ERC-4337 and ERC-7579 portability
|
|
|
|
The authorization is exposed two ways.
|
|
|
|
- ERC-4337 authorization path. `messageDigest` is the userOpHash, so the aggregate proof is bound
|
|
to one exact operation. The account nonce inside the userOpHash makes the authorization
|
|
non-replayable at the account layer, so the verifier itself needs no separate replay nonce.
|
|
|
|
- ERC-7579 validator module. `AerePQAggregateModule` implements the type-1 validator surface from
|
|
the ERC-7579 standard (OpenZeppelin `interfaces/draft-IERC7579.sol` `IERC7579Validator`):
|
|
`onInstall` / `onUninstall` / `isModuleType`, `validateUserOp(PackedUserOperation, bytes32)`
|
|
returning the ERC-4337 code (0 success, 1 failure), and `isValidSignatureWithSender(address,
|
|
bytes32, bytes)` returning the ERC-1271 magic value `0x1626ba7e` on success. An account is bound
|
|
to a committee at install time; the module then validates each userOp (and each ERC-1271
|
|
signature) by asking the verifier whether the committee signed the digest. Both paths are
|
|
fail-closed and never revert on a bad or malformed signature, per the validator SHOULD.
|
|
|
|
Because ERC-7579 is a chain-agnostic modular-account standard, the SAME module can be installed on
|
|
a Safe (via the Safe7579 adapter), a Kernel, or a Nexus account on ANY EVM chain, and the verifier
|
|
it points at can be deployed on that chain against that chain's SP1 gateway. The rule "a t-of-n
|
|
post-quantum committee approved this userOp" then travels with the account across chains.
|
|
|
|
[VERIFY] The module assumes the account has already stripped any validator-routing prefix (ERC-7579
|
|
stacks select the validator by an address carried in the userOp nonce key, or in some stacks a
|
|
prefix on the signature) before calling the module, matching the OpenZeppelin `AccountERC7579`
|
|
dispatcher. Confirm the exact unwrapping and the PackedUserOperation field layout against the
|
|
specific account implementation you deploy under (Safe7579 / Kernel / Nexus).
|
|
|
|
---
|
|
|
|
## 5. Bank28 custody use case
|
|
|
|
Bank28 is a non-custodial neobank stack. A treasury or custody account can be governed by a t-of-n
|
|
committee of post-quantum keys (for example 3-of-5 ML-DSA-65 signers held on separate HSMs or
|
|
devices). With `AereThresholdPQCRegistry` the account pays on-chain for t independent PQC
|
|
verifications each time it moves funds, and the committee size is bounded by the per-transaction
|
|
gas ceiling. With `AerePQAggregate`:
|
|
- the committee can be large (institutional custody often wants a big quorum: many independent
|
|
approvers, several of them offline) because on-chain cost does not grow with n,
|
|
- each fund movement is one small proof, so gas and calldata are predictable and flat,
|
|
- the account is a standard ERC-7579 modular account with the validator module installed, so it
|
|
works with existing bundler and wallet infrastructure and is portable across the chains Bank28
|
|
settles on,
|
|
- the authority is quantum-durable: a quantum adversary that can forge ECDSA still cannot authorize
|
|
a movement without the committee's PQC private keys, because the underlying legs are NIST PQC
|
|
signatures proven in the zkVM.
|
|
|
|
Scope note: this authorizes ACCOUNT actions. It is not custody advice and it does not make Aere
|
|
Network consensus post-quantum. Bank28 must still follow its lawful KYC/AML obligations; this is an
|
|
authorization primitive, not a compliance control.
|
|
|
|
---
|
|
|
|
## 6. Honest status
|
|
|
|
BUILT and TESTED (this repo):
|
|
- `AerePQAggregateVerifier.sol`: committee registry, public-input binding scheme, fail-closed
|
|
strict and non-reverting verification, constant-cost single `verifyProof` call, provenance
|
|
recording.
|
|
- `AerePQAggregateModule.sol`: ERC-7579 type-1 validator module wrapping the verifier for the
|
|
ERC-4337 and ERC-1271 paths.
|
|
- 17 passing Hardhat tests against `MockSp1Verifier`, the same deployed-gateway test double used by
|
|
`AereComputeMarketV3` and the zk light clients. Its `verifyProof` REVERTS on an invalid proof,
|
|
so the fail-closed path is exercised exactly as against the production gateway. Tests cover: a
|
|
valid proof authorizes; an invalid proof rejects fail-closed; a wrong-message-digest proof
|
|
rejects; a wrong-committee-root proof rejects; below-threshold rejects; threshold/size/scheme
|
|
mismatch and malformed public values reject; unknown committee rejects; gas is constant across
|
|
n = 5 vs n = 1,000,000; and the module returns the correct ERC-4337 code and ERC-1271 magic value
|
|
on valid inputs and fails closed (without reverting) on invalid or malformed ones.
|
|
|
|
NOT implemented, [MEASURE], research frontier:
|
|
- The OFF-CHAIN SP1 aggregation guest circuit. Verifying n PQC signatures against the committee root
|
|
inside a zkVM and emitting the public values is real cryptographic engineering that is NOT in this
|
|
repository. The on-chain verifier is proven against a mock gateway that asserts the bound public
|
|
values; a real end-to-end system additionally needs the real circuit and a real SP1 proof.
|
|
- Verifying Falcon inside a zkVM is HARD: Falcon signature verification touches FFT over the ring
|
|
and, in reference implementations, floating-point Gaussian sampling paths, which are expensive and
|
|
delicate to make deterministic and constraint-friendly in a zkVM. ML-DSA (FIPS 204, Dilithium
|
|
lineage) is integer-arithmetic and modular-reduction based, with no floating point, so
|
|
ML-DSA-65 aggregation is the TRACTABLE FIRST TARGET. The pinned scheme constant in the verifier
|
|
reflects this (`SCHEME_MLDSA65 = 5`). A Falcon aggregation circuit is a later, separate verifier
|
|
deployment with its own pinned vkey.
|
|
- The real end-to-end proving cost and latency, and the real-gateway on-chain verify gas, are
|
|
[MEASURE] and depend on the circuit implementation.
|
|
|
|
Do NOT claim the aggregation works end-to-end. The claim that IS supported by this repository: the
|
|
on-chain verification and portability rail is built and fail-closed, and its cost is provably
|
|
constant in the committee size n.
|