aere-docs/AERE-PQ-AGGREGATE.md
Aere Network e4cead319d Initial public release
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.
2026-07-20 01:01:36 +03:00

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.