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.
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
ConstantFieldValidationRulein 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":
- 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).
- 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):
- 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.
- Canonical round trip: the decoded structure re-encoded in
ALLform 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, equivalentlyn mod 32 == 16. H itself is an anchor height. Between anchor heights the rules judge nothing.aere.pq.anchorMinSeals:height:Ksteps, floor semantics viafloorEntry(height); a step must exist exactly at H; steps below H refuse.aere.pq.anchor.minSealsCeiling: effective K ismin(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_SEALSjavadoc, 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,blockNumberare 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 inanchor/consensus/common/.../FalconSealSupport.java(BCFalconSigner.verifySignatureover the 32-byte M), encoding stated inprecompiles/AereFalconSupport.javajavadoc; length measured inPqAnchorConfig.javajavadoc). 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):
- 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).
- 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 requireD' == 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):
- 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.
- The supplied parent must be the parent the header names (number N-1, matching hash), else reject.
- Decode extraData (strict codec, section 2.4); let k = number of carried seals.
- 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). k < requiredrejects.- Indices not acceptable (strictly increasing; window relaxation as above) rejects.
k == 0accepts here (only reachable when required == 0; R1 has already bound the digest of the empty certificate).- For each seal: resolve
index -> validator addressin 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 exactlyparentNumber + 1answers 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 inIMPORT-PROOF-STARE-2026-08-15.md]. - 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 rawhpolynomial, 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_LENGTHjavadoc);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 isAERE-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-disarmand--Xaere-pq-anchor-min-seals-maxlayered onto the same properties, command line winning (source:anchor/app/.../AerePqEmergencyOptions.java,PqAnchorConfig.javajavadoc).
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
baseFeePerGasat 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 ownbaseFeePerGasis 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.csin 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.csjavadoc). --min-gas-priceis 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
- Ship
genesis.jsonbyte for byte (sha256 in section 1.1); verify your block 0 equals0xd86d57a8...c5d7f1a. Ship the configured QBFT transition 2138451 unchanged (section 1.4). - 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]. - Implement the base-fee floor from 10,141,734 (section 5), with the D3 window if you validate base fees.
- 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.
- 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.tlamodel 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,BlockHeaderValidatorandHeaderValidationModeare 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 commitd2032017to 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 documentconsensus-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.validatorCountdrive seal production only and are deliberately outside this follower specification; their live values on the fleet are not published (source:RUN-A-NODE.mdnames them; nothing publishes values). - G7. The
0x100P-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.