# AIP-23: AERE Proof Protocol (a portable, verifiable statement + on-chain finality envelope) ## Preamble | Field | Value | | --- | --- | | AIP | 23 | | Title | AERE Proof Protocol (portable verifiable-statement envelope with optional post-quantum on-chain finality) | | Author | Aere Network Foundation | | Type | Standards Track | | Category | Interface | | Status | Draft (describes the envelope AERE tools already emit; the reference verifier is published with this AIP) | | Created | 2026-09-26 | | Requires | AIP-15 (anchor certificate under the block hash), AIP-21 (per-block PQ seal record) | | Supersedes | None | | Superseded-By | None | | Ratification | Not ratified; open standard, reference verifier `aere-node/tools/verify-proof.mjs`, conformance vectors in `aere-node/tools/proof-vectors/` | ## Abstract AERE already emits proofs from several surfaces (Proof of Software attestations, Cloud audit-log notarization, the anchor certificate) and they share one shape without ever having been named: a structured **statement**, a **statementHash** (the SHA-256 of the statement's canonical text), an optional producer **signature**, and an optional on-chain **notarization** whose finality becomes post-quantum once an AERE anchor with a post-quantum validator certificate (AIP-15) covers the state that records it. This AIP names that shape the **AERE Proof Protocol**, fixes it so anyone can produce and verify it without trusting the producer, and publishes a reference verifier and conformance vectors. The claim it makes checkable is narrow and concrete: a stranger can verify what a system stated, and when the chain first saw it, against a chain state certified post-quantum, without trusting the producer or the RPC endpoint they read through. ## Motivation Today the same envelope is re-described in each tool (Proof of Software's `attestation.json`, the gateway's `/v1/proof`, the audit export). A third party who wants to verify an AERE proof has to read the source each time. Fixing one envelope and one open verifier turns "AERE can verify post-quantum" into "anyone can verify against AERE", which is the only version of the claim that survives a hostile reading. Non-goals: this AIP does **not** define new cryptography, a new chain rule, or a new contract. It fixes the *interface* of proofs that already exist. Signature schemes are referenced (hybrid ECDSA + ML-DSA via `@aere/pq-sign`), not redefined. ## Specification ### 1. The envelope A proof is a JSON object: ``` { "v": 1, "kind": "aere-proof-of--attestation", "statement": { "v": 1, "kind": "aere-proof-of-", ...type-specific fields..., "createdAt": "" }, "statementHash": "0x<64 hex>", "signature": { "scheme": "ml-dsa-65", "publicKey": "", "signature": "" } | null, "notarization": { "txHash": "0x..", "block": , "firstSeenAt": , "contract": "0x..", "chainId": 2800 } | null } ``` - `statement` is the payload: what happened. Its `kind` names the proof type (`aere-proof-of-software`, `aere-proof-of-data`, `aere-proof-of-ai`, `aere-proof-of-execution`, `aere-proof-of-identity`, `aere-proof-of-compliance`, ...). The type-specific fields are that type's business; the protocol constrains only the envelope. - `statementHash` binds the statement. - `signature` (optional) is the producer's signature over the canonical statement text. - `notarization` (optional) records that `statementHash` was written to the on-chain notary. It is a claim of the producer; a verifier does not take it on trust (section 4). ### 2. Canonical text and statementHash The canonical text of a statement is **`JSON.stringify(statement)`** with keys in insertion order, exactly as written into the envelope (this is what Proof of Software already does; do not re-sort keys, do not reformat). `statementHash` is ``` statementHash = "0x" + hex( SHA-256( utf8( JSON.stringify(statement) ) ) ) ``` A verifier recomputes the SHA-256 over the exact `statement` sub-object as serialized and requires equality. (SHA-256 rather than keccak: it is the digest Proof of Software has emitted since 1.0.0 and the one software-attestation tooling speaks; the on-chain notary stores whatever 32-byte value it is handed.) ### 3. Signature (optional) If present, the signature is over the **canonical statement text** (section 2), not over the envelope. The reference verifier checks an `ml-dsa-{44,65,87}` signature with `node:crypto` (OpenSSL 3.5) when the public key is present; the full hybrid ECDSA + ML-DSA form is verified by `@aere/pq-sign`. A signature the reference verifier cannot check is reported `UNMEASURED`, never silently passed. ### 4. On-chain finality (optional) `statementHash` is notarized by calling `notarize(bytes32)` on the AERE notary contract (chain 2800, `0x4aB392c4Aca7D9D4C16c0b60a9514c5025bd58c7`; permissionless, no owner). The contract records, once, the **time** of the block in which the hash was first seen: `firstSeen[h] = block.timestamp` (unix seconds, `proofOf(bytes32) -> uint64`). It does not record a block number; the block that holds the first sighting is found from the contract's `Notarized` event. A verifier establishes finality from a certified state, not from what an endpoint says: 1. the chain's most recent anchor is verified: every post-quantum seal of its certificate is checked against the published key manifests, and the certificate is bound under the anchor's hash (AIP-15; this is what `aere-node/tools/verify-anchor.mjs` does); 2. the header of the anchor's parent is re-encoded in its on-chain form and must hash to the parent hash those seals signed; 3. that header's state root anchors a Merkle-Patricia proof (`eth_getProof`) of the notary's account, whose code hash must be the notary's runtime code hash (`0x8eaa924081e9718fcee05ae64fadaa1815437ebbbcef5b87317c5879050452ce`), and of the storage slot `firstSeen[statementHash]` (slot `keccak256(statementHash || uint256(0))`); 4. the slot's value is the first-seen time. An empty slot, proven absent, means not notarized as of that certified state. The endpoint only carries data: a header, a proof node or a value it altered would not match the hash the certificate signed. The first-seen block, located through the endpoint's logs, is reported as such and is not part of what is certified. Levels: | level | meaning | | --- | --- | | `not-notarized` | the certified state holds no entry for the hash (proven absent) | | `pending` | the endpoint reports a notarization after the certified state; the next anchor will cover it | | `post-quantum` | the certified state records the hash with its first-seen time; changing that record would require forging the certificate of an anchor at or above it | The most recent anchor is used, not the anchor right after the first sighting, because the record never changes once written (a second `notarize` of the same hash leaves it as it is) and the endpoint's state window may not reach an old block. ### 5. Verification levels and verdict A verifier reports each level that is **present** in the envelope, and a verdict: 1. **form**: the envelope has `statement` (object) and `statementHash` (`0x` + 64 hex). 2. **integrity**: section 2 holds. 3. **signature**: present ? verified or `UNMEASURED` : absent. 4. **finality**: (the envelope claims a notarization, or an endpoint is given) ? the section-4 levels : absent. A claimed notarization that the certified state does not hold is a failure. `VALID` iff every present level passed; `PARTIAL` if a present level is `UNMEASURED` or `pending`; `INVALID` if any present level failed. A verifier that cannot go `INVALID` cannot be trusted: the conformance suite plants failures and requires each to be caught. ## Rationale - **One envelope, many kinds.** The protocol constrains only what every proof needs (a statement, its hash, an optional signature, an optional notarization); each kind keeps its own fields. A verifier that knows no kind can still check levels 1, 2 and 4. - **SHA-256 over the canonical text.** It is what Proof of Software already emits, and it keeps the envelope checkable with the standard library of any language; the notary is agnostic to the digest. - **Finality from a certified state, not from an endpoint.** Reading `proofOf` through an RPC endpoint and calling the result post-quantum because the covering anchor carries a certificate would make the endpoint the trust anchor. Binding a storage proof to a header whose hash the verified certificate signed moves the trust to the certificate, which is what the anchor is for. - **The most recent anchor.** The notary's record is write-once, so the most recent certified state is as good as the one right after the first sighting, and it is the one an endpoint can still prove (state windows are finite). ## Backwards Compatibility Envelopes that Proof of Software and the Cloud gateway already emit are valid envelopes under this AIP; nothing they produce changes. A draft of the reference verifier (2026-09-26, not published) read the notary's value as a block number and reported the covering anchor post-quantum from the presence of a certificate; it is replaced by the verifier described here. ## Security Considerations - **What is certified.** That the statementHash was recorded by the notary, with its first-seen time, in a state covered by a post-quantum validator certificate. Not certified: the truth of the statement (that is the producer's word, or its signature's); the first-seen block number (located through logs); anything about the producer's identity unless the signature level passed. - **Notarization is permissionless.** Anyone can notarize any hash; a first-seen time proves that the statement existed at that time, not who wrote it. Authorship is the signature level's job. - **The certificate's trust** is the validator set's and the published key manifests': a verifier that trusts the manifests it downloads trusts their publisher, and `aere-node/tools/verify-anchor.mjs` checks the manifests' self-consistency and the validators' own bindings to their keys. - **An endpoint** can refuse to answer or answer late (reported `UNMEASURED`), but it cannot make an altered header, proof node or value pass: each is bound by hash to what the certificate signed. - **Signatures** a verifier cannot check are `UNMEASURED`, never `PASSED`. ## Reference Implementation and On-Chain Deployment - AERE notary: chain 2800 `0x4aB392c4Aca7D9D4C16c0b60a9514c5025bd58c7`; public testnet 28001 `0x70099E62735500AA2F85B60C518551a57B202d54` (the same runtime code, code hash in section 4). - `aere-node/tools/verify-proof.mjs`: the verifier (Node, `node:crypto` and `@noble/hashes`); for the finality level it runs `aere-node/tools/verify-anchor.mjs`, published beside it, and reads the anchor it verified from its `ANCHOR_REPORT` output, so the certificate check exists in one place. `node verify-proof.mjs [--rpc ] [--chain 2800|28001] [--json]`. - `aere-node/tools/proof-vectors/`: envelopes with their expected verdicts, a real Proof-of-Software attestation among them, and one notarized on the public testnet 28001. ### Measured status (2026-09-27) - Levels 1 to 3: the verifier reproduces the statementHash of a real attestation; a changed statement, a changed statementHash and a missing statementHash each give `INVALID`. - Finality, end to end on the public testnet 28001, where a notary with the same runtime code was deployed for this purpose (`0x70099E62735500AA2F85B60C518551a57B202d54`): a statement about the published AIP-22 conformance corpus was notarized at block 3,618,722, and the verifier reports it `post-quantum` from the state of the parent of the most recent anchor, with its first-seen time. Through an endpoint that alters the parent header's state root, a node of the storage proof, or the value `proofOf` returns, and with a certificate altered on the way to the anchor check, the verdict is `INVALID` in the first, second and fourth cases and unaffected by the third (the value is read from the proof, not from the call); an address that holds another contract is refused by its code hash. With a check removed in a copy of the verifier (the header binding, the code hash, the node hash, the anchor verdict), the corresponding case no longer gives the expected verdict, four of four. - On chain 2800 nothing is notarized yet; there the verifier proves the absence of a hash from the certified state. ### Adoption path The value is in external implementations: once other tools emit this envelope and other verifiers check it, AERE becomes a common verification layer rather than one more product. Concretely: the verifier and vectors are published with this AIP, the SDKs gain a `verify` command that wraps the verifier, and the conformance vectors are the compatibility contract. ## Errata None. ## Post-Acceptance Outcome Record Not accepted; nothing to record. ## Copyright Copyright and related rights waived via CC0.