aere-node/SPEC.md
Aere Network 44dbc1bc06 Point 47: the unified protocol specification, SPEC.md
One document from which a third party can implement a client that follows chain
2800 without reading our code: chain parameters, QBFT with the full extraData
layout and what the block hash does and does not cover, the post-quantum anchor
rules with exact pre-images and the follower configuration, precompile formats
with the message in the middle and variable signature lengths, fee rules with
their historical windows, sync requirements including the genesis-set ceiling,
and the formal models with their honest boundaries.

Every normative statement carries a file citation, a [MEASURED <date>] marker
with the command, or [NOT MEASURED]. Section 8 documents twelve dated
divergences a syncing client will meet on the real chain (the 2138451 transition
value that must not be corrected, the base-fee lapse window, the anchor disarmed
window, the threshold window, the retired falcon.forkBlock rule), because a spec
that hides history cannot sync anyone. Section 9 lists ten things this spec
cannot state from published sources, by name, rather than papering over them.
2026-08-25 00:57:53 +03:00

60 KiB

Aere Network chain 2800: full protocol specification

Version: 1.0.0, written 2026-08-25. Scope: everything a third party needs to implement a client that follows chain 2800 from block 0 to the live head and validates what the network validates, without reading Aere source code. It specifies the follower (validation) protocol completely; it describes seal production only where a follower must understand it to validate.

0. Conventions, and how every statement here is grounded

Every normative statement in this document carries one of three markers:

  • (source: path): the statement is checkable against a file published in this bundle (or, where explicitly said, in the public Aere repositories). The file is the authority; if this document and the file ever disagree, the file wins and the disagreement is a bug in this document.
  • [MEASURED yyyy-mm-dd]: the statement is an observation of the live chain or of a real run, made on that date, with the method stated. A measurement describes the chain as it was on that date; it is not a promise about later heights.
  • [NOT MEASURED]: the statement could not be established from the published sources and is flagged rather than guessed. Section 9 collects all of these.

Where two sources of truth diverge, the divergence itself is specified, with dates, in section 8. This chain has several such places and a client that "corrects" any of them will fail to follow the chain. Read section 8 before implementing anything.

Number formatting: heights are written with commas for readability (13,014,000); in code and configuration they are plain digits. All hashes are lower-case hex. "H" always means the anchor activation height 13,014,000. No statement in this document uses the phrase "no block finalizes without a post-quantum quorum"; the defensible claim is narrower and is stated exactly in section 3.1.

Primary sources in this bundle:

Topic File
Genesis, byte for byte as the fleet runs it genesis.json
Operator instructions, follower configuration RUN-A-NODE.md
Client changes vs upstream Besu patches/0001..0005, precompiles/, anchor/
Falcon validator registries registries/
NIST test vectors for the precompiles vectors/
From-genesis import proof and its measured boundaries IMPORT-PROOF-STARE-2026-08-15.md
Formal verification runner and models ../aere-research/formal-consensus/

1. Chain parameters

1.1 Identity

Parameter Value Ground
Chain id 2800 (0xaf0) (source: genesis.json config.chainId)
Network id 2800 (source: RUN-A-NODE.md, --network-id=2800)
Genesis file sha256 361709dccec4e9fc85be5aec33b30b58a55dc53424087d84c1ad11bd1d944c24 (source: RUN-A-NODE.md; hash of the published file with LF line endings)
Block 0 hash 0xd86d57a899cbfa580669f0e1c7cd4ae5f525247c3c823f8f75df176a0c5d7f1a [MEASURED 2026-08-03, eth_getBlockByNumber("0x0") against a from-genesis node and both public endpoints; recorded in RUN-A-NODE.md]
Consensus QBFT (Hyperledger Besu implementation) (source: genesis.json config.qbft)
Native token AERE, 18 decimals, total genesis supply 2,800,000,000 (source: genesis.json alloc; the six balances sum to 2.8e27 wei)

The block 0 hash covers every consensus-relevant field of genesis.json including the state root of the six alloc accounts, so matching it is the complete genesis check (source: RUN-A-NODE.md, "Check that you are on the right chain").

The comment strings inside alloc are not consensus data, are read by no client, and two of them are textually wrong; they are published unaltered because the file is published byte for byte as the fleet holds it. See section 8, D7 (source: RUN-A-NODE.md, "A note on the comment fields").

1.2 Genesis header fields

(source: genesis.json)

Field Value
timestamp 0x69fbd960
gasLimit 0x1fffffffffffff
difficulty 0x1
mixHash 0x63746963616c2062797a616e74696e65206661756c7420746f6c6572616e6365 (the fixed BFT mix hash; constant on every block)
coinbase 0x0000000000000000000000000000000000000000
nonce 0x0
extraData QBFT extra data (section 2.3) carrying vanity of 32 zero bytes and the three genesis validators

Genesis validator set, decoded from extraData (source: genesis.json):

0xb5e768cb3117ea25175f51aa956b48691025c2a8
0xf73bbbd26a82dbc769066550d8d4585eab2fc00d
0x4bf6f91d84b37454544279cba152581ed6820044

The genesis validator set has N=3, so its QBFT quorum is 2. This matters to a from-genesis follower because of the anchor threshold guard: see section 6.4.

1.3 EVM fork schedule

(source: genesis.json config)

Fork Activation
Homestead through London, Shanghai block 0 / time 0 (all pre-London blocks fields are 0, shanghaiTime 0)
Cancun timestamp 1780189051
Prague timestamp 1780189051 (same instant as Cancun)
Osaka timestamp 1780220351
futureEips (the Aere milestone) timestamp 1783820272

The futureEips milestone is NOT upstream Besu's futureEips. Upstream bases it on the unreleased Amsterdam definition (Block Access Lists, a different state-root committer). Chain 2800 isolates it on the Osaka definition, and additionally activates in that same fork (a) the five Aere post-quantum precompiles (section 4) and (b) EIP-2935 historical block hashes, which performs one system state write per block into the ring-buffer contract at 0x0000F90827F1C53a10cb7A02335B175320002935 from the activation block onward (source: patches/0005-aere-eip2935-futureeips.patch, header). A client that carries the standard Osaka rules, the five precompiles and the EIP-2935 write from this milestone computes the fleet's state roots; a client that carries upstream's Amsterdam-based futureEips does not.

The first block at or after futureEipsTime is block 9,189,161 [MEASURED 2026-08-15, real from-genesis sync of a build without patch 0005 stopped at exactly that height with failed persisting block due to stateroot mismatch; recorded in IMPORT-PROOF-STARE-2026-08-15.md and patches/0005 header].

Patch 0001 additionally repoints the futureEips precompile registry from the Cancun set to the full Osaka set, which is a behaviour change beyond the five new precompiles (source: README.md, "The patch").

1.4 Block period and the transition every reader must not "fix"

(source: genesis.json)

  • config.qbft.blockperiodseconds = 1, epochlength = 30000, requesttimeoutseconds = 4.
  • config.transitions.qbft[0] = { "block": 2138451, "xblockperiodmilliseconds": 500 }: from that height the target block period is 500 ms.

The configured transition height 2,138,451 does not match the measured chain. Sampling header timestamps on the public endpoints puts the actual rate change just after block 2,137,652: twenty-block spans take 20 s from 2,137,600, 15 s from 2,137,656, 12 s from 2,137,657 and a flat 10 s from 2,137,700 onward [MEASURED, recorded in RUN-A-NODE.md, "A number in this file that the chain does not agree with"]. The configured value is roughly eight hundred blocks late.

Normative consequence: ship 2138451, exactly as the fleet does. The field only governs how fast a proposer may seal; it has no effect on a node that follows, and a from-genesis sync carrying this exact value imported the blocks on both sides of both numbers with zero rejections [MEASURED 2026-08-03, sync run in RUN-A-NODE.md]. A genesis file "corrected" to 2137652 hashes differently, will never peer, and any coordinated change to the live value would be a consensus infrastructure change. Answer "2,137,652" to the question "when did the chain accelerate"; answer "2138451" to the question "what does the live configuration say"; never merge the two.

1.5 pqRegistryHash in the genesis config

(source: genesis.json config.pqRegistryHash)

block 13014000  hash 0xa96ac96dcd4f1671aec8b6063cee17a3341314c92e1dd2623bc6500b7e28b0cb
block 13600000  hash 0x5e6ac058b22beaa895469671308548dfd44fbaa9ca7ea30b3dafa950c359b9b3

This is a height-keyed schedule of canonical registry hashes (computation defined in section 3.6). A node compares the canonical hash of the Falcon registry it actually loaded against the entry active at its head and refuses to start on a mismatch (AERE-PQC-REG-MISMATCH-01); heights below the first entry are unenforced, so nothing historical is invalidated (source: anchor/consensus/common/.../PqRegistryHash.java, class javadoc). The guard runs at startup, not per block; a per-block header rule for the same binding does not exist today (source: same file, "WHAT THIS CLASS DOES NOT DO").


2. Consensus: QBFT

2.1 Engine and parameters

Chain 2800 runs QBFT as implemented in Hyperledger Besu at upstream commit d2032017bb3b8cb215a97303980a1e4a643f7180 (source: README.md, "The patch"; that commit is the base of every patch in this bundle and the commit named in the artifact running on the validators). This specification does not restate the QBFT message protocol (PREPREPARE / PREPARE / COMMIT / ROUND-CHANGE); it is upstream Besu behaviour at that commit. What is specified here is everything Aere adds, changes, or that a follower must check.

  • Block period: section 1.4. Empty blocks are produced continuously; the chain does not pause when there are no transactions.
  • Difficulty is the constant 1 on every block, enforced by a ConstantFieldValidationRule in the QBFT header ruleset (source: anchor/consensus/qbft/.../QbftBlockHeaderValidationRulesetFactory.java, the rule at the line registering "Difficulty" ... UInt256.ONE). Total difficulty is therefore height + 1, and the longest chain is the heaviest.
  • Epoch length 30000: pending validator votes reset each epoch (upstream QBFT semantics; parameter in genesis.json).
  • Validator set changes are made by the standard QBFT voting mechanism (the vote element of extraData, section 2.3). The set had 3 validators at genesis (source: genesis.json), and the live chain seals with nine validators, seven until 2026-08-09 (source: RUN-A-NODE.md, "What the two bootnodes are"). The block-by-block vote history is on the chain itself and is not restated here.

2.2 Quorum

The QBFT commit quorum is ceil(2N/3): 2 at N=3, 5 at N=7, 6 at N=9. This is the value the formal models prove is the exact safety threshold (quorum intersection greater than f for all N, and the negative control shows a majority quorum forks) (source: ../aere-research/formal-consensus/qbft_safety_smt.py, property L1, and ../aere-research/formal-consensus/RULEAZA-TOT.md). Fault tolerance at N=9 is f=2.

2.3 The extraData structure, with the Aere sixth element

extraData is an RLP list. Layout (source: anchor/consensus/qbft/src/main/java/org/hyperledger/besu/consensus/qbft/QbftExtraDataCodec.java):

Index Element Encoding
0 vanityData exactly 32 bytes. Historically arbitrary (the client writes a version string); at anchor heights from H it carries the anchor digest D (section 3.3)
1 validators RLP list of 20-byte addresses
2 vote empty RLP list when no vote; else RLP[recipient(20 bytes), voteValue] with the add/drop byte values defined in upstream Besu's Vote class
3 round int scalar
4 committedSeals RLP list of ECDSA (secp256k1) commit signatures
5 falconSeals (Aere, optional) RLP list of [validatorIndex intScalar, signature bytes] pairs; present ONLY in the stored-header encoding and ONLY when non-empty

Three encodings exist, and which elements they carry is consensus-critical (source: same file, encode(...)):

  • ALL (stored header): all six elements; element 5 omitted when the certificate is empty.
  • EXCLUDE_COMMIT_SEALS (the ECDSA commit-seal signing pre-image): round kept, committedSeals written as an empty list, falconSeals omitted.
  • EXCLUDE_COMMIT_SEALS_AND_ROUND_NUMBER (the block-hash pre-image): round forced to 0, committedSeals an empty list, falconSeals omitted.

The block hash is computed over a RE-ENCODE of the DECODED extraData in the EXCLUDE_COMMIT_SEALS_AND_ROUND_NUMBER form, not over the stored bytes. Consequences a client must implement and must not "fix":

  1. The ECDSA commit seals, the round number, and the entire Falcon certificate are NOT covered by the block hash. Stripping or replacing the certificate leaves the hash unchanged (it is caught by validation instead: section 3.4).
  2. Two correct neighbours can legally store different extraData bytes for the same block hash: every node assembles its final header locally from the commits it heard. Measured on the live chain: over 200 consecutive headers read simultaneously from two Aere RPC nodes with identical block hashes 200/200, the ECDSA seal ORDER differed on 68 headers and the seal SET differed on 11 (source: anchor/consensus/common/.../PqAnchor.java, class javadoc, which cites this measurement as the reason the anchor's design is what it is). A client must never treat byte-equality of stored extraData across peers as a validity criterion.

The upstream hashing routine itself (BftBlockHashing) is not part of this bundle's overlay; the property was verified by reproducing, byte for byte, the live node's reported hash for two real chain-2800 headers from the re-encoding described above [MEASURED 2026-08-02, model recorded in the repository's consensus-pqc/dovezi-preimagine-element6-2026-08-02/ evidence set; see also section 9, G2].

2.4 Decoder strictness (Aere change, applies at every height)

Upstream Besu ends the extraData decode with a lenient list-leave that silently discards trailing content. Chain 2800's client makes two changes, both consensus-relevant to anyone re-implementing the codec (source: QbftExtraDataCodec.java, decodeRaw, the two commented gates):

  1. Strict leave: any bytes left over in the outer list after the known elements is a decode error, so a header that smuggles extra content after the certificate does not share a hash with a clean header.
  2. Canonical round trip: the decoded structure re-encoded in ALL form must reproduce the received bytes exactly, or the header is rejected. This closes, among other shapes, the "explicit empty Falcon list" ambiguity: an empty certificate must be OMITTED, and a header that carries an explicit empty list is non-canonical and rejected. Every header any Aere or stock Besu node ever produced round-trips unchanged, so the whole pre-anchor history still decodes.

2.5 What QBFT header validation on chain 2800 checks, and one thing it does not

The QBFT ruleset validates ancestry, timestamp, gas usage and gas-limit bounds, the constant difficulty, mixHash, coinbase, the validator set and the ECDSA commit seals, plus the Aere rules of section 3. It does not recompute the EIP-1559 base fee at import: Besu's BaseFeeMarketBlockHeaderGasPriceValidationRule is registered only by the Clique and Merge rulesets, not by QBFT, upstream or in this fork [MEASURED 2026-08-02, by reading the ruleset factory and grepping consensus/; recorded in RUN-A-NODE.md, "Which Besu", and in ../../docs-level runbook history]. The base fee is ratified through the quorum's commit seals over the block hash, which commits to it. Section 5 states what this means for a client that DOES validate base fees.


3. The post-quantum certificate anchor

3.1 The claim, stated exactly

From block 13,014,000, every 32nd header of chain 2800 (an "anchor block") carries a certificate of validator Falcon-512 seals over its parent, and the anchor block's keccak block hash covers a 32-byte commitment to that certificate. The enforced minimum number of valid seals is a height schedule: 0 from 13,014,000 (warm-up), 3 from 13,034,000 (f+1 of nine; enforced on the fleet since 2026-08-14), and 6 of 9 from block 14,961,456 (a full 2f+1 quorum, the same count QBFT itself requires) (source: anchor/README.md, "Scope boundary"; RUN-A-NODE.md, the anchor section).

The defensible sentence, and the only form this document endorses: every 32nd block does not finalize without a certificate of at least six of nine valid Falcon-512 validator seals under its hash (three, before block 14,961,456; see the schedule and the historical windows). Blocks between anchors carry no Falcon seals and are finalized by ECDSA alone. Consensus (proposal, identity, transport, per-block finality) is classical secp256k1 ECDSA; the anchor is a binding, not a replacement, and "post-quantum consensus" without this qualification overstates (source: anchor/README.md). None of this code has been audited by a third party (source: anchor/README.md, "What is not proven here").

The threat model is retroactive rewriting (the long-range / posterior-corruption attack), not "harvest now, decrypt later", which does not apply to signatures. Peer-reviewed treatment of the threat: Azouvi, Danezis, Nikolaenko, "Winkle", IACR 2019/1440, AFT 2020; the quantum framing and this particular defence are Aere's own (source: anchor/README.md, which also places the design against the four known mitigation families and states what it does NOT claim, including slashable safety).

Security property bought by the interval: an adversary holding every classical validator key and no Falcon key can rewrite at most the tail since the last anchor, so fork depth <= 32 blocks (about 16 seconds); rewriting anything below an anchor changes that anchor's parent hash, forces the anchor to be reproduced, and reproducing it requires Falcon signatures the adversary does not have. History below H remains protected by ECDSA alone, permanently (source: anchor/consensus/common/.../PqAnchorConfig.java, interval javadoc; anchor/README.md).

3.2 Activation is by node configuration, not by genesis, and that is a real caveat

All anchor parameters are read from JVM system properties (BESU_OPTS), with environment-variable twins, not from the genesis file. There is no consensus binding on these values: two nodes configured with different H or different K schedules disagree about which headers are valid. The code says this about itself and logs it at every armed start (source: PqAnchorConfig.java, class javadoc "HONEST LIMITATION" and the ARMED log line). The published follower configuration in RUN-A-NODE.md is therefore normative for anyone joining the network, and this section specifies exactly those values.

The canonical follower configuration (source: RUN-A-NODE.md, "The configuration a follower passes"):

-Daere.basefee.floor.forkBlock=10141734
-Daere.basefee.floor.value=1000000000
-Daere.pq.chainId=2800
-Daere.pq.anchorBlock=13014000
-Daere.pq.anchorInterval=32
-Daere.pq.anchor.maxSeals=9
-Daere.pq.anchorMinSeals=13014000:0,13034000:3,14961456:6
-Daere.pq.anchor.minSealsCeiling=1
-Daere.falcon.anchor.address=0x5214F0e53899Dad805ef3AdF0624F5e49d2a5EB5
-Daere.falcon.anchor.block=13889290
-Daere.falcon.manifest=<registries>/manifest-13600000.json
-Daere.falcon.registry.history=<registries>/manifest-13014000.json,<registries>/registru-2800-v2-13600000.properties

Configuration loading is fail-closed on PRESENCE: if no aere.pq.* name is set at all, the node behaves exactly like stock Besu (the anchor never activates); if at least one is set, every field is read strictly and any fault refuses startup with code AERE-PQC-ANCHOR-CONF-01, except through the aere.pq.anchor.disable brake (source: PqAnchorConfig.java, fromSystemConfiguration). The loader also refuses an armed schedule whose highest effective K is zero (AERE-PQC-ANCHOR-CONF-01/minSealsFloor), and a proposer seal cap below the highest scheduled K (source: same file).

Semantics of each parameter (source: PqAnchorConfig.java):

  • aere.pq.anchorBlock (H): below H both anchor rules return true before decoding anything; the historical chain is untouched.
  • aere.pq.anchorInterval (32): anchor heights are counted FROM H: (n - 13014000) % 32 == 0, equivalently n mod 32 == 16. H itself is an anchor height. Between anchor heights the rules judge nothing.
  • aere.pq.anchorMinSeals: height:K steps, floor semantics via floorEntry(height); a step must exist exactly at H; steps below H refuse.
  • aere.pq.anchor.minSealsCeiling: effective K is min(scheduled, ceiling). The ceiling can only lower K, never raise it (proved: ../aere-research/formal-consensus/pqanchor_ceiling_monotonicity_smt.py). Why a follower sets 1: section 6.4.
  • aere.pq.anchor.maxSeals: proposer-side cap on how many seals are WRITTEN. K is a floor, not a cap: a proposer includes every eligible seal it heard in time, so real anchor headers carry more than K (measured seal counts at K=3, N=7: 42 blocks with 4 seals, 36 with 5, 5 with 6; a Falcon-512 seal is 666 bytes) (source: PqAnchorConfig.java, PROPERTY_MAX_SEALS javadoc, measurement dated 2026-08-07). Real anchor blocks carry three to nine seals (source: RUN-A-NODE.md).
  • aere.pq.anchor.disable: local emergency de-arm; both rules off on this node; per-block disarm announcement keeps shouting. Local on purpose: a halted chain cannot deliver an on-chain change.
  • aere.pq.chainId: enters the D and M pre-images (domain separation from the proving chain 442807, which runs the same binaries and may run the same keys).
  • aere.falcon.manifest + aere.falcon.anchor.address/anchor.block: head registry wiring; aere.falcon.registry.history: every earlier registry, never pruned (a from-genesis node verifies every block ever produced) (source: registries/README.md, RUN-A-NODE.md).
  • aere.falcon.forkBlock: a validator-side legacy per-block rule; see section 8, D6. A follower leaves it unset.

An armed node refuses to start in any sync mode other than FULL (PqAnchorSyncModeGuard, REQUIRED_MODE = "FULL") (source: anchor/consensus/common/.../PqAnchorSyncModeGuard.java), because under light validation modes the seals rule does not run.

3.3 The two pre-images and the certificate encoding

(source: anchor/consensus/common/.../PqAnchor.java; these are exact and normative)

D = keccak256( RLP[ "AERE-PQ-ANCHOR-1", chainId, parentNumber, parentHash, C ] )
M = keccak256( RLP[ "AERE-PQ-COMMIT-1", chainId, blockNumber,  blockHash      ] )
C = RLP[ [idx, sig], [idx, sig], ... ]      indices STRICTLY INCREASING
  • The domain labels are exactly 16 ASCII bytes each, written as RLP byte strings. chainId, parentNumber, blockNumber are RLP long scalars; the hashes are 32-byte strings.
  • D occupies all 32 bytes of the anchor block's vanityData: no magic, no version byte, no padding. Format versioning is by activation height, not by an in-band byte.
  • The certificate C carried by anchor block N attests to N's PARENT: each seal's signature is a Falcon-512 signature over M = commitMessage(chainId, N-1, hash(N-1)). M is a function of the block hash, deliberately not of the QBFT commit hash (which includes the round), so any node holding the parent header can recompute it with no state and no round memory.
  • C is hashed into D IN THE ORDER CARRIED, and both validation rules require strictly increasing indices, so for every accepted header "the order given" and "sorted" are the same list. Strictly increasing indices also make duplicate indices unrepresentable (the "repeat one seal to inflate k" attack is excluded by the grammar).
  • The certificate is CARRIED (element 5 of extraData, outside the hash); only its 32-byte digest D (element 0, vanityData) is under keccak. Change one byte of the certificate and D no longer matches; strip the certificate entirely and the hash is unchanged but validation rejects the header (digest of the empty certificate differs, and the seal count is below K).
  • Seal signature bytes are in Bouncy Castle's Falcon signature encoding, (0x30+logn) || nonce(40) || compressedSignature (0x39 leading byte for Falcon-512); a seal is 666 bytes (source: verification call in anchor/consensus/common/.../FalconSealSupport.java (BC FalconSigner.verifySignature over the 32-byte M), encoding stated in precompiles/AereFalconSupport.java javadoc; length measured in PqAnchorConfig.java javadoc). Falcon signatures are variable-length by nature; the RLP byte string carries the exact length.

At H itself the parent predates the scheme, the certificate is legitimately EMPTY, and vanityData carries the digest of the empty certificate; K=0 makes that acceptable only during the warm-up step (source: anchor/consensus/qbft/.../PqAnchorSealsRule.java, the k == 0 branch).

3.4 What an armed node rejects: the validation rules

Registered in the QBFT header ruleset alongside the classical rules (source: anchor/consensus/qbft/.../QbftBlockHeaderValidationRulesetFactory.java; registration is itself tested with a measured negative control, QbftAnchorRuleWiringTest, because Besu wraps detached rules in lambdas that hide them from reflection):

R1, PqAnchorDigestRule (detached, runs in light validation; twin PqAnchorDigestAttachedRule carries the same verdict on the attached path so it survives SKIP_DETACHED import):

  1. Below H, or at a non-anchor height, or when the height is inside the disarmed historical window: accept (window handling in section 8, D4).
  2. vanityData must be exactly 32 bytes; the certificate's indices must be strictly increasing (inside the disarmed window: distinct and non-negative suffices); recompute D' = anchorDigest(chainId, N-1, header.parentHash, carried certificate) and require D' == vanityData. Any mismatch, and any undecodable extraData, rejects: the exception path returns false, not true (source: anchor/consensus/qbft/.../PqAnchorDigestRule.java).

R2, PqAnchorSealsRule (attached; needs the parent and state, runs on the import path). In order (source: anchor/consensus/qbft/.../PqAnchorSealsRule.java, validate):

  1. Below H or non-anchor height: accept. Inside the disarmed historical window: accept as written after checking the certificate still decodes with distinct non-negative indices.
  2. The supplied parent must be the parent the header names (number N-1, matching hash), else reject.
  3. Decode extraData (strict codec, section 2.4); let k = number of carried seals.
  4. Compute the required threshold: required = min(schedule at N, emergency ceiling); inside the threshold-only historical window, required = min(required, 1) where 1 is the measured floor that was actually in force (section 8, D5).
  5. k < required rejects.
  6. Indices not acceptable (strictly increasing; window relaxation as above) rejects.
  7. k == 0 accepts here (only reachable when required == 0; R1 has already bound the digest of the empty certificate).
  8. For each seal: resolve index -> validator address in the registry AT THE PARENT's height (N-1); an unbound index rejects; an address not in the PARENT block's validator set rejects; two indices resolving to one address rejects; a Falcon-512 verification failure of the signature over M rejects. Registry resolution at the parent height is exact and has a one-block boundary case at H: a registry bound at exactly parentNumber + 1 answers for the parent, because the schedule binds inclusively from H while seals commit to H-1. Without this alignment a from-genesis node rejects the first anchor; with it, nothing else changes [MEASURED 2026-08-15, from-genesis import; boundary and negative control recorded in IMPORT-PROOF-STARE-2026-08-15.md].
  9. Any exception during checking rejects (fail-closed).

PqRegistryBindingRule and PqEmergencyShoutRule are also registered: the former is part of the registry-binding machinery, the latter only logs (it makes a disarmed-but-configured node shout at every block) (source: QbftBlockHeaderValidationRulesetFactory.java).

FalconSealValidationRule (the legacy per-block rule) retires at H: its first statement accepts any header at number >= legacyFalconRuleRetirementBlock(), which equals H whenever the anchor is configured. Exactly one of the two regimes is in force at any height (source: PqAnchorConfig.java, legacyFalconRuleRetirementBlock; anchor/consensus/qbft/.../FalconSealValidationRule.java). See section 8, D6 for why this matters historically.

The rejection is a real import failure: on a live test network the log sequence is PqAnchorSealsRule ... REJECTED then MainnetBlockValidator | Invalid block then InvalidBlockException then sync-target disconnect [MEASURED 2026-08-06, armed test network, recorded in the repository's consensus-pqc/controale-finale-2026-08-06/ evidence; 12 of 12 stripped-certificate headers rejected on the 4-node rehearsal network, source: anchor/README.md, "What is proven"].

3.5 The Falcon validator registries

(source: registries/README.md, files in registries/)

A node cannot validate any anchor block without the registries: it imports fine to 13,014,000 and then refuses every anchor with AERE-PQC-REG-BLOCK-01, deliberately and fail-closed, because seal indices cannot be mapped to validator addresses.

File Bind height Keys Role sha256
manifest-13014000.json 13,014,000 7 registry in force from the first anchor; carried in history 006b1b3fb814ed84622539160956263faca7c0b76585c22f2e8acb926c0bcb7f
registru-2800-v2-13600000.properties 13,600,000 9 nine-validator registry from the set expansion; carried in history c9a215d294e106f69fb2f16e3af21f9787523969e4b7260a3098f4b2cf458059
manifest-13600000.json 13,600,000 9 head registry, passed as aere.falcon.manifest 23736b7d4ba1d3213496f8b5a5f756d5c958b08efebdeb1329b24d7dfa45fb6e

Each JSON manifest carries formatVersion (2), chainId (2800), bindHeight, count, and rows keyed "0".."count-1", each row holding:

  • pk: the validator's Falcon-512 public key, stored as the raw h polynomial, 896 bytes (NOT the 897-byte standard encoding with its one-byte header; the header is absent in these files) (source: PqRegistryHash.java, FALCON_512_PK_LENGTH javadoc);
  • addr: the validator's chain-2800 address;
  • pop: a Falcon proof of possession signed by the row's own key;
  • claim: an ECDSA signature by the validator's own account key, the half a registry writer cannot forge, closing row re-binding and row swapping.

No private key material exists in these files. Provenance of the published bytes: each file was read from three independently operated validator hosts and produced the same sha256 on all three (source: registries/README.md).

Registry rotation is height-scheduled and every height has exactly one registry (proved: ../aere-research/formal-consensus/registry_rotation_coverage_smt.py and registry_index_binding_smt.py). The head registry is additionally pinned by an on-chain anchor contract at 0x5214F0e53899Dad805ef3AdF0624F5e49d2a5EB5 from block 13,889,290 (source: RUN-A-NODE.md, follower configuration; the contract's own interface is not specified in this bundle, see section 9, G6).

3.6 The canonical registry hash

(source: anchor/consensus/common/.../PqRegistryHash.java; exact and normative)

v1 pre-image (domain AERE-PQ-REGISTRY-1):

"AERE-PQ-REGISTRY-1"          18 bytes ASCII
uint64be(chainId)              8 bytes
uint32be(count)                4 bytes
for i in 0..count-1:
    uint32be(i)                4 bytes
    uint8(addressBound?1:0)    1 byte
    address                   20 bytes, only when address-bound
    uint32be(len(publicKey))   4 bytes
    publicKey                 len bytes

v2 pre-image (domain AERE-PQ-REGISTRY-2; address binding mandatory; adds uint64be(bindHeight) after chainId, and per row appends length-prefixed possession and claim proofs). The canonical hash is keccak256 of the pre-image, rendered as 64 lower-case hex digits without 0x. The proofs are INSIDE the hash so that stripping them yields a different registry with a different hash, and the two domains ensure a v1 file can never satisfy a v2 schedule entry. The pqRegistryHash values in genesis.json (section 1.5) are hashes under this scheme; index, chainId and bindHeight are all inside the pre-image, so row permutation, cross-chain reuse and height re-binding all change the hash.

Registry loading is strict: count must be present, indices exactly 0..count-1 with no gap and no extra, address binding all-or-nothing, hex even-length and strictly hexadecimal; an ambiguous file refuses rather than hashes (source: PqRegistryHash.java, Registry javadoc).

3.7 Guards a validator-capable build enforces at startup

Stated because a third-party implementation that produces blocks needs them, and a follower needs to know they exist:

  • PqAnchorThresholdGuard: refuses to arm a seal threshold at or above the QBFT quorum of the CURRENT validator set (a proposer could never gather it), and refuses any threshold above N - f = 7 at N=9 (source: anchor/consensus/common/.../PqAnchorThresholdGuard.java; anchor/README.md; RUN-A-NODE.md, "Why the seal-threshold ceiling"). The refusal code is AERE-PQC-THRESHOLD-01, and it is the reason a from-genesis follower needs the ceiling (section 6.4).
  • The min-seals floor, the max-seals cap check, and the fail-closed loader (section 3.2).
  • Emergency options exist as first-class command-line options --Xaere-pq-anchor-disarm and --Xaere-pq-anchor-min-seals-max layered onto the same properties, command line winning (source: anchor/app/.../AerePqEmergencyOptions.java, PqAnchorConfig.java javadoc).

4. Precompiles

4.1 The five mainnet precompiles

Activated on mainnet at block 9,189,161 (the futureEips milestone, section 1.3) (source: README.md; sources in precompiles/, installed by patches/0001).

Address Algorithm Standard Gas Input Output
0x0AE1 Falcon-512 verify NIST Falcon round 3 40,000 flat pk(897) || sm 32-byte word: ...01 valid, ...00 invalid
0x0AE2 Falcon-1024 verify NIST Falcon round 3 75,000 flat pk(1793) || sm same
0x0AE3 ML-DSA-44 verify FIPS 204 55,000 flat pk(1312) || sig(2420) || message same
0x0AE4 SLH-DSA-SHA2-128s verify FIPS 205 350,000 flat pk(32) || sig(7856) || message same
0x0AE5 SHAKE256 XOF FIPS 202 60 + 12 per 32-byte word of (input data + output) 32-byte big-endian outLen word, then data outLen bytes

(gas and lengths: source: precompiles/Falcon512PrecompiledContract.java, Falcon1024PrecompiledContract.java, MLDSA44PrecompiledContract.java, SLHDSA128sPrecompiledContract.java, SHAKE256PrecompiledContract.java)

Verification precompiles never revert on malformed input; they return the 32-byte zero word. A too-short input (size <= pk length for Falcon; size < pk+sig for the fixed-length pair) returns invalid (source: the computePrecompile methods).

4.2 Falcon input framing, exactly (the message sits in the MIDDLE)

(source: precompiles/AereFalconSupport.java; normative, and the single most common integration mistake)

input = pk || sm
pk    = (0x00 + logn) || packed_h        897 bytes (Falcon-512, logn=9, header 0x09)
                                        1793 bytes (Falcon-1024, logn=10, header 0x0A)
sm    = sigLen(2, big-endian) || nonce(40) || message || esig
esig  = (0x20 + logn) || compressedSignature      (0x29 for Falcon-512, 0x2A for Falcon-1024)
sigLen == len(esig)

This is the NIST reference signed-message convention. The message is between the nonce and the signature, NOT appended after a detached signature; a caller that places the message at the end gets a clean 0 for a perfectly valid signature and the precompile looks dead. Falcon signatures are compressed and therefore VARIABLE length (614 and 616 bytes were measured for two signatures by the same key), so sigLen must be read per call, never hard-coded [MEASURED 2026-08-09, recorded in the repository operating notes; framing itself: source as above]. The precompile checks the pk header byte, the esig header byte, and the length arithmetic, and answers invalid on any mismatch. Internally the verifier is Bouncy Castle; no cryptography is reimplemented (source: AereFalconSupport.java).

For 0x0AE3 and 0x0AE4 the NIST sm = signature || message convention applies with the fixed signature lengths in the table; the remainder of the input after pk || sig is the message.

0x0AE5 reads a 32-byte big-endian output length (values above 65,536 are capped to 65,536; a nonzero high 28 bytes also caps; input shorter than 32 bytes returns empty output) and returns the SHAKE256 XOF of the remaining bytes at that length (source: precompiles/SHAKE256PrecompiledContract.java).

4.3 Testnet-only precompiles: NOT on mainnet

0x0AE6 (ML-KEM-768 deterministic encapsulation, FIPS 203, gas 60,000) and 0x0AE7 (Falcon HashToPoint SHAKE256 rejection sampler, gas 60 + 12/word) exist in patches/0002 and are testnet only. A mainnet node must NOT apply patch 0002. The live-chain verification script asserts their ABSENCE from mainnet as a falsifiable check (source: README.md; scripts/verify-live-precompiles.mjs).

4.4 Verification against the live chain

node scripts/verify-live-precompiles.mjs runs 13 checks (NIST KAT/ACVP vectors from vectors/, every signature check paired with a tampered negative control, plus the two absence checks); 13/13 passed against rpc.aere.network at block 10,566,696 [MEASURED 2026-07-20, output recorded in README.md]. The BN254 zero-knowledge verifiers used elsewhere in the Aere stack are classical and Shor-breakable, and are never described as quantum-safe (source: README.md, scope boundary). 0x100 P-256 verify (RIP-7951) is also live and classical; it is upstream Besu, not part of this fork (source: README.md; format not specified here, see section 9, G7).


5. Fee rules

5.1 EIP-1559 with an Aere floor

London is active from block 0 (source: genesis.json). Upstream Besu's LondonFeeMarket carries a default base-fee floor of 7 wei, which is why the pre-fork steady state of this mostly-empty chain was ~7 wei (source: patches/0004-aere-basefee-floor.patch, visible in the diff context, DEFAULT_BASEFEE_FLOOR = Wei.of(7L)).

From block 10,141,734 chain 2800 clamps the computed EIP-1559 base fee to max(computed, 1_000_000_000) wei (1 Gwei). The clamp sits on all three return paths of computeBaseFee, which Besu uses for BOTH production and validation, and is gated by the two system properties (aere.basefee.floor.forkBlock, aere.basefee.floor.value); with them unset the patch is a byte-for-byte no-op (source: patches/0004-aere-basefee-floor.patch). A block's baseFeePerGas is the real consensused header value; there is no display shim on the public endpoints since the floor went live.

5.2 What a follower must and must not enforce

  • Besu's QBFT ruleset does not recompute the base fee at import (section 2.5), so a Besu-derived follower needs the patch only to COMPUTE what the network computes (and to propose correctly if it ever proposed); it will import the chain either way. That is a finding about a missing upstream rule, not a licence to skip the patch (source: RUN-A-NODE.md, "Which Besu").
  • A client that DOES validate baseFeePerGas at import (the second Aere client, Nethermind-based, does) MUST implement the floor as a VALIDATION rule with one historical exception window, or it cannot sync: see section 8, D3. Inside the window the header's own baseFeePerGas is accepted as given; outside it the floor is enforced normally, so a NEW violation still stops the client (source: aere-client2/src/Nethermind/Nethermind.Core/AereFloorLapse.cs in the public Aere repositories; the file is not part of this bundle).
  • Why the window cannot be a calculation rule: inside it the base fee is NOT a function of the parent header. Producers with and without the floor alternated by round winner (block 12,978,617 is 875,000,000 wei, its child 12,978,618 is 1,000,000,000), so no deterministic recomputation can reproduce the sequence (source: AereFloorLapse.cs javadoc).
  • --min-gas-price is a local mempool policy, not consensus; the Foundation nodes run it at zero (source: RUN-A-NODE.md).

6. Sync requirements: what a third-party client must implement to follow the chain

This section is the checklist. Each item names where its details live.

6.1 Identity and history

  1. Ship genesis.json byte for byte (sha256 in section 1.1); verify your block 0 equals 0xd86d57a8...c5d7f1a. Ship the configured QBFT transition 2138451 unchanged (section 1.4).
  2. Implement the EVM fork schedule of section 1.3, including the Aere futureEips semantics: Osaka-based ruleset, the five precompiles of section 4, and the EIP-2935 per-block system write, all from block 9,189,161. A build missing any of these diverges on state root at exactly that height [MEASURED 2026-08-15, IMPORT-PROOF-STARE-2026-08-15.md].
  3. Implement the base-fee floor from 10,141,734 (section 5), with the D3 window if you validate base fees.
  4. Implement QBFT header validation with the Aere extraData codec exactly as in sections 2.3 and 2.4 (strict leave, canonical round trip, optional sixth element), the constant difficulty 1, and the hash pre-image that excludes round, ECDSA seals and the Falcon certificate.
  5. Implement the anchor rules of section 3 from height 13,014,000, with the registries of section 3.5 and the historical windows of section 8 (D4, D5). Without the windows a from-genesis sync stops at 13,267,824 and cannot proceed; without the parent-height registry alignment it stops at 13,014,000.

6.2 Sync mode

Full sync from block 0 is the mode that verifies the published history, and it is what the anchor requires: an armed node refuses any lighter mode at startup (section 3.2). Snap sync against a QBFT chain trusts a peer for the state and verifies far less (source: RUN-A-NODE.md). The Foundation fleet runs BONSAI storage; storage format is a local choice, not consensus.

6.3 Peering

Discovery needs a bootnode enode. Bootnodes are deliberately not published in this bundle; a current enode is provided by mail (office@aere.network, subject "bootnode") until a dedicated public bootnode exists (source: RUN-A-NODE.md). Both discovery UDP and p2p TCP must be open in both directions. The bootnodes are full nodes outside the validator set, Foundation-operated, and their liveness at any moment is only provable by your own net_peerCount (source: RUN-A-NODE.md).

6.4 The genesis-set threshold problem, and the published answer

A node syncing from block 0 starts INTO the genesis validator set (N=3, quorum 2). The anchor threshold guard (section 3.7) refuses to arm K=3 or K=6 against that set, so a from-genesis follower with the published schedule cannot start at all without one more setting. The published answer is aere.pq.anchor.minSealsCeiling=1, which lowers the EFFECTIVE seal-count floor to quorum(3) - 1 = 1 WITHOUT editing the schedule (source: RUN-A-NODE.md, "Why the seal-threshold ceiling").

State the consequence honestly, because it is a real weakening of one check on the follower: with the ceiling at 1, the follower's seal-COUNT requirement is 1 at every height, not 3 or 6. What is NOT weakened: every anchor must still carry a digest that binds its certificate under the block hash, indices must still be strictly increasing, every carried seal is still Falcon-verified against the height-correct registry, and eligibility in the parent's validator set is still enforced. Real anchor blocks carry 3 to 9 seals, so all of history imports cleanly. The seal-count floor is a proposer-liveness property relative to the current set, not a history-verification property; a validator, which starts into the full set, does not set the ceiling (source: RUN-A-NODE.md). An implementation that instead makes its threshold guard aware of the validator set it will have at the evaluated HEIGHT (rather than at startup) can enforce the full schedule end to end; the published Besu-based package does not do this today [NOT MEASURED: no such implementation exists to compare against].

6.5 Facts a syncing client will observe, so they are expectations rather than surprises

  • Blocks are almost all empty; the chain advances ~2 blocks/second after the rate change.
  • Between anchor heights, headers carry no Falcon element (extraData 634 bytes at N=9); at anchor heights they carry element 5 and a digest in vanityData (2,516+ bytes) [MEASURED 2026-08-09 on the live chain; recorded in the repository operating notes; sizes are descriptive, not normative].
  • Stored extraData for the same block can differ between peers (section 2.3); only the hash pre-image is canonical.
  • The full from-genesis import of exactly this bundle's patches reached the live tip (height 14,088,211) and followed it, with zero anchor rejections and zero state mismatches, after the two historical windows and the H boundary alignment were carried; the consensus test suites stood at 641 tests, 0 failures, with negative controls run in all four directions on the windows [MEASURED 2026-08-16, run and controls recorded in IMPORT-PROOF-STARE-2026-08-15.md].
  • The EIP-4788 (Cancun) beacon-roots system call targets a contract with no code on chain 2800, so it is a per-block no-op that Besu reports at ERROR level in its log; state is unaffected. A client must not treat the empty beacon-roots contract as an error in its own sync [MEASURED 2026-08-07, finding D-153 in the repository's findings register; not restated in any bundle file, see section 9, G8].

7. Formal models: what is proven, where, and the limits

The machine-checked models live in ../aere-research/formal-consensus/ (SMT, z3; runner run_consensus_verification.py) and, for TLA+/TLC, in the repository directory formal-tla/ (not part of this bundle). Method rule throughout: no result counts as a proof unless its negative control was RUN and produced the predicted violation (SAT model or TLC trace) (source: ../aere-research/formal-consensus/RULEAZA-TOT.md).

Suite status [MEASURED 2026-08-24, python run_consensus_verification.py, Windows, z3 4.16.0]: 35 models, 35 pass (14 consensus + 11 contract + 10 application), 282 PROVED + 149 CEX-FOUND, 0 FAILED, ~39 s wall (source: RULEAZA-TOT.md).

Consensus properties proven, with tool and scale (source: RULEAZA-TOT.md and the repository document strategie/VERIFICARE-FORMALA-2026-08-24.md):

Property Tool / N Model
Agreement (no two different blocks finalize at one height) SMT parametric N=4..16 plus UNBOUNDED quorum-intersection arithmetic (2q > N for all N); TLC at N=4 qbft_safety_smt.py, QBFT.tla
Quorum threshold is exactly ceil(2N/3) (N=9 gives 6) SMT unbounded qbft_safety_smt.py (L1), pqfinality_smt.py (Q0)
Equivocation: <= f Byzantine double-signers cannot break agreement SMT N=4..16; TLC qbft_safety_smt.py (L2), QBFT.tla
Round-change locking: a view change cannot finalize a different value SMT N=4..13; TLC N=4 qbft_locking_smt.py, qbft_safety_smt.py (L3)
Liveness post-GST: within f+1 rounds an honest proposer commits SMT N=4..7 qbft_liveness_smt.py
Network partitions: no split-brain in any split; the minority side cannot commit; progress returns on heal SMT parametric N=9 + unbounded; TLC N=4 EXHAUSTIVE (6 configs, 0 states left in queue) partition_safety_smt.py, QBFTPartition.tla
PQ anchor certificate acceptance is fail-closed (quorum, root, size, domain, rotation gates each individually load-bearing) SMT N=9 pqfinality_smt.py, anchor_blocking_quorum_smt.py
A round change on an anchor height cannot yield two different valid certificates; uniqueness comes from binding to the FINALIZED block, not from K (K=3 alone admits two, shown SAT) SMT N=9 anchor_viewchange_smt.py
Emergency ceiling only lowers K SMT pqanchor_ceiling_monotonicity_smt.py
Registry rotation covers every height exactly once; index binding SMT registry_rotation_coverage_smt.py, registry_index_binding_smt.py

The honest boundary, stated as prominently as the results (source: RULEAZA-TOT.md, "Granita cinstita"; VERIFICARE-FORMALA-2026-08-24.md):

  • Model checking is not a complete proof. TLC exhausts only the stated finite configuration (partitions at N=4, single height). The full QBFT.tla model does NOT terminate in local budgets; what exists there is a partial explicit-state witness (9.35 million states, no violation, N=4 round 0), not a verification.
  • Parametric SMT proves the property for THAT N (9), plus unbounded arithmetic for the quorum-intersection core. No mechanized induction over all executions at arbitrary N (Coq/Isabelle/TLAPS) exists.
  • The models verify the DESIGN's combinatorics, not the Java bytecode or the EVM. The design-to- binary gap has historically been caught only by importing real blocks, never by a form check.
  • Cryptographic primitives (keccak injectivity, Falcon verification soundness) are modeled as trusted, not re-proved.
  • Liveness results assume partial synchrony (post-GST); asynchronous liveness is impossible (FLP) and is not claimed.
  • Nothing in the formal results implies "post-quantum consensus" per block; the anchor is additive (section 3.1).

8. Known divergences, historical windows, and corrections. Normative.

Every entry here is something a naive implementation gets wrong. Each carries its dates and its ground. D3, D4 and D5 are MANDATORY for a from-genesis sync; the rest are mandatory knowledge.

D1. The sub-second transition: configured 2138451, measured 2,137,652. Ship the configured value; report the measured one. Full statement in section 1.4. Both numbers appear in public Aere material historically; the wrong lesson is to pick one and "fix" the other (source: RUN-A-NODE.md; measurement dated there).

D2. Genesis qbft.startBlock folklore. Any Aere document giving 2,138,451 as "when the chain accelerated" is quoting configuration, not measurement; the acceleration is at 2,137,652 [MEASURED, section 1.4]. The genesis file the fleet runs is identical on all nine validators (sha256 361709dcce...) and is not to be touched.

D3. Base-fee floor lapse, blocks 12,978,617 to 13,087,959 inclusive. On 2026-08-09 the validators lost the floor system properties for about sixteen hours (a configuration rewrite dropped them); producers with and without the floor alternated. Inside this range a validating client accepts the header's baseFeePerGas as given; outside it, the floor holds from 10,141,734. Bounds were established by exhaustive scan after a binary search returned a wrong answer (12,978,949; the violation predicate is intermittent, hence non-monotone), and the true lower bound was found by the second client refusing to sync past 12,978,617. The 500 blocks before the window and the 2,000 blocks after it contain zero violations (source: aere-client2/src/Nethermind/Nethermind.Core/AereFloorLapse.cs, public Aere repositories; measurements dated 2026-08-09..11 in that file's javadoc). Besu-derived followers import this range regardless (section 5.2); clients that validate base fees need the window.

D4. Anchor disarmed window, blocks 13,267,824 to 13,268,944 inclusive: 36 anchor heights, relaxation EVERYTHING. On 2026-08-10 all nine validators restarted within minutes; no node held seals, the next anchor height could not be proposed, and the chain stopped for nine minutes. The fleet-wide emergency measure switched the anchor rules off; the canonical headers produced meanwhile carry the client version string in vanityData (no digest) although a certificate is attached, and their certificate indices are in arrival order rather than sorted. Inside this window a validating client accepts the header as written, EXCEPT that the certificate must still decode and must still carry distinct non-negative indices (distinctness is the anti-inflation property and is never relaxed). Bounds are fixed in code so the window cannot widen at runtime, and producers never consult it, so it is closed by construction. Bounds were measured by decoding every anchor height from H to 14,077,000 one by one (25,252 heights), not searched (source: anchor/consensus/common/.../PqAnchorLapse.java, first window; IMPORT-PROOF-STARE-2026-08-15.md).

D5. Anchor threshold-lowered window, blocks 13,268,976 to 13,890,544 inclusive: 19,425 anchor heights, relaxation THRESHOLD_ONLY, floor 1. After the D4 incident the rules were restored with the emergency seal ceiling lowered (raising the threshold back in one step had stopped the chain a second time). Every header in this range binds its digest and carries sorted indices; 2,926 of the 19,425 anchor heights carry fewer seals than the schedule asks, the fewest being 1. Inside the window the required count is min(schedule, 1); nothing else is relaxed, and every carried seal is still verified. The measured floor is 1, never 0: an empty certificate is NOT accepted where one was required (source: PqAnchorLapse.java, second window). This window is also why the schedule step 13034000:3 reads "enforced since 2026-08-14" in prose: the step was configured earlier, but the effective minimum was held at 1 by the ceiling until the window's end (source: anchor/README.md; PqAnchorLapse.java).

D6. Correction of 2026-08-19 (repository finding D-235): aere.falcon.forkBlock=14050000 armed a RETIRED rule and changed no enforcement. The fleet was configured on 2026-08-15 with that value, intended as a per-block blocking Falcon quorum, and public material said so. In the shipped code the rule it arms (FalconSealValidationRule) retires at the anchor activation height 13,014,000 in favour of the anchor rules (PqAnchorConfig.legacyFalconRuleRetirementBlock), so at 14,050,000 it was already inert. The chain itself confirms it: blocks between anchors carry no Falcon seals, which a per-block rule would have rejected. The earlier public statement that from 14,050,000 every block required a 2f+1 Falcon quorum to finalize is WITHDRAWN; nothing changed at that height (source: anchor/README.md, correction paragraph; RUN-A-NODE.md, correction paragraph; code: FalconSealValidationRule.java, PqAnchorConfig.java). A follower leaves aere.falcon.forkBlock unset; set or unset, it gates nothing above H.

D7. Genesis alloc comment strings are wrong and published anyway. The dash characters are mangled (a historical encoding accident) and the 1,400,000,000 AERE account is labelled "Mining Reserve" although chain 2800 has no mining and never has (it is the staking and emissions reserve). No client reads these strings; they stay because the file is published byte for byte as the fleet holds it (source: RUN-A-NODE.md).

D8. The H boundary registry alignment (one block, exactly). The seals rule resolves the registry at the PARENT's height; the registry schedule binds inclusively from H; therefore at the first anchor the lookup at H-1 must be answered by the registry bound at exactly H, and the boundary is exactly one block wide (two or more blocks below the schedule changes nothing). The first public build lacked this and rejected the first real anchor with "certificate carries index 0, which the registry does not bind"; the fix carries a dedicated test with a run negative control (source: IMPORT-PROOF-STARE-2026-08-15.md; the test PqParentHeightAlignmentTest in anchor/).

D9. K schedule steps and their real dates. 13014000:0 (warm-up; the first anchor's certificate is legitimately empty), 13034000:3 (f+1 of nine; effectively in force from 2026-08-14, see D5), 14961456:6 (2f+1, in force from 2026-08-21) (source: RUN-A-NODE.md, anchor/README.md). "Certificate of f+1 validators" and "quorum certificate" are different claims; before 14,961,456 only the former is true, and calling K=3 a quorum is a counting error anyone will catch (source: anchor/README.md, "Terminology, used precisely").

D10. Anchors described as "universal since block 13,889,296". Both RUN-A-NODE.md and anchor/README.md carry this phrase for the certificate. Its precise operational definition (what exactly changed at that height, as distinct from the D5 window ending at 13,890,544 and the on-chain registry pin at 13,889,290) is not stated in any bundle file [NOT MEASURED; flagged in section 9, G5]. Implementations need no rule keyed to 13,889,296; the windows of D4/D5 plus the schedule are sufficient to sync [MEASURED 2026-08-16, the full import of IMPORT-PROOF-STARE-2026-08-15.md used exactly those].

D11. The Cellframe counterexample governs how the anchor may be described. "No public chain has a block hash covering a post-quantum validator certificate" is FALSE as stated: Cellframe's ESBoCS signs block candidates with keys resolving to Dilithium/Falcon/SPHINCS+ and hashes the block with signatures attached. The defensible sentence is: no public chain has a post-quantum validator certificate under the block hash that is PROVEN AND INDEPENDENTLY VERIFIABLE, and this bundle is the "proven and verifiable" half of that sentence (source: anchor/README.md, "One claim we retracted, on purpose").

D12. Validator-set size statements are dated. Seven validators until 2026-08-09, nine since (source: RUN-A-NODE.md). Registry rotation heights (13,014,000 seven keys; 13,600,000 nine keys) are the authoritative in-protocol trace of the expansion (source: registries/README.md).


9. What this specification cannot state from the published sources

Honest list, for completion in a later revision. An implementer hitting one of these should treat the gap as real rather than assume.

  • G1. Bootnode enodes. Deliberately unpublished; obtainable by mail (section 6.3). A third-party implementation cannot discover peers from this bundle alone.
  • G2. The upstream QBFT hashing and commit-seal plumbing. BftBlockHashing, BftBlockHeaderFunctions, BlockHeaderValidator and HeaderValidationMode are upstream files not carried in the overlay; the hash pre-image statement in section 2.3 is supported by the codec comments, by the encoding types, and by byte-exact reproduction of live block hashes on two real headers, but the upstream call sites themselves must be read at commit d2032017 to be cited line by line. Similarly, which validation MODE each entry path (gossip NewBlock, full-sync import, header download) applies has been proven on the import path only (source: the NEMASURAT list in the repository document consensus-pqc/CE-DEVINE-INVALID-LA-ANCORA-2026-08-07.md).
  • G3. The exact byte values of the QBFT vote add/drop constants. Defined in upstream Vote (referenced by the codec); not restated here rather than quoted from memory.
  • G4. Per-block gas accounting beyond the precompiles. The chain follows the Osaka gas schedule of upstream Besu at d2032017; this bundle does not enumerate it, and neither does this document.
  • G5. The precise definition of "universal since 13,889,296" (D10), and the interface of the on-chain registry anchor contract at 0x5214F0e53899Dad805ef3AdF0624F5e49d2a5EB5 (section 3.5): the follower configuration names it, but its ABI, storage layout and exact role at block 13,889,290 are not specified in any bundle file.
  • G6. The validator (seal-production) configuration. aere.falcon.key, aere.falcon.attachBlock, aere.falcon.attach*, aere.falcon.validatorCount drive seal production only and are deliberately outside this follower specification; their live values on the fleet are not published (source: RUN-A-NODE.md names them; nothing publishes values).
  • G7. The 0x100 P-256 (RIP-7951) input/output format. Live and classical, upstream Besu; not specified in this bundle.
  • G8. The EIP-4788 no-code observation (section 6.5) rests on a dated repository finding (D-153, 2026-08-07), not on a bundle file; a bundle-resident statement (or a fixture proving the no-op) does not exist yet.
  • G9. Whether a certificate reused by an adversary for its one permitted fork block passes eligibility in every corner case was argued from code and never executed as a run (source: CE-DEVINE-INVALID-LA-ANCORA-2026-08-07.md, NEMASURAT item 8).
  • G10. Anything about the chain after 2026-08-25. Every measured statement carries its date; the live schedule, set size, and head move. The registries directory and the follower configuration are the values current at publication.

End of specification. Corrections to this document are made by editing it in the repository and republishing the bundle; the underlying files it cites are never edited to match the document.