AIP-22: dated stage records for stages 1 to 3b on testnet 28001 (quorum threshold, per-scheme intervals, post-quantum validator identity, key rotation under an id), with their negative controls; stage-0 measurement replaces the NOT MEASURED row

This commit is contained in:
Aere Network 2026-09-23 19:41:55 +03:00
parent c94b3f5c06
commit f4db867d80

View File

@ -53,7 +53,7 @@ Measured constants used throughout, with source:
| Falcon-512 verify | 0.068 ms median (Bouncy Castle, validator-class host); 0.092 ms median, 0.215 ms p95 (rehearsal host) | **measured** (`audit-package-pq-consensus/evidence/EVIDENCE-INDEX.md`, `falconbench-bouncycastle.txt`; `consensus-pqc/ancora-v2/README.md`) |
| Falcon-512 sign | 0.60 ms median | **measured** (same evidence index) |
| SLH-DSA-SHA2-128s sign on the consensus thread | 0.3 to 0.7 s per signature with the JDK digest (1.4 to 2.7 s before) | **measured** 2026-09-04 on chain 2800 (findings register) |
| SLH-DSA-SHA2-128s verify | [NOT MEASURED in milliseconds in this repository]; gas proxy 350,000 against 40,000 for Falcon-512, ratio 8.75 | **spec** of the live precompiles (CIFRE #5) |
| SLH-DSA-SHA2-128s verify | 0.669 ms median, 1.494 ms p95 on a 2-vCPU reader host with the fleet's jars (Falcon-512 on the same host and path: 0.367 ms median, ratio 1.8); 0.966 ms median on a laptop (ratio 2.9); the gas proxy (350,000 against 40,000, ratio 8.75) is not a time proxy on the consensus path | **measured** 2026-09-22 (`consensus-pqc/aip22-treapta0/REZULTATE.md`, `SealSchemeBench.java` on `SealSchemes`, negative control 30 of 30 refused) |
| from-genesis import rate with ten peers | ~1,300 blocks per second | **measured** 2026-09-11 (findings register) |
| anchor cycle on the live chain (anchor parent + anchor) | 1.33 to 2.00 s against 0.565 s for an ordinary block | **measured** 2026-09-04 and 2026-09-05 (findings register) |
| FRI proof, production parameters (log_blowup 1, 100 queries, 2^20 rows) | 639,032 B content, 655,044 B on disk; generation 6.1 to 7.1 s single thread on a laptop; verification 80 to 91 ms | **measured** 2026-08-25 (`strategie/agregare-pq/DOVADA-FRI-MASURATA-2026-08-24.md`); the FRI component only, not a Falcon arithmetization |
@ -175,7 +175,7 @@ Once every anchor is a quorum certificate, a proof that "every anchor in `[a, b]
### 8. Sync: what a from-genesis node verifies, and the cost
Per block: the hash chain (one keccak of the header, already done), the proposer check, and after `H_hdr` one Falcon verification (0.068 to 0.092 ms median measured, 0.215 ms p95). Per Falcon anchor (every 32 blocks): up to N Falcon verifications, 0.7 ms median to 2.2 ms p95 at N = 10; per hybrid anchor (every 128): additionally up to N SLH-DSA verifications, [NOT MEASURED in ms; by the gas proxy about 8.75 x 0.068 = 0.6 ms each, 6 ms per anchor, **estimate**]. Amortized per block: about 0.02 ms (Falcon at 32) plus about 0.05 ms (SLH-DSA at 128, estimate), against a measured import budget of about 0.77 ms per block (1,300 blocks per second with ten peers, 2026-09-11); the post-quantum verification is therefore under 10% of import time by this estimate, and the SLH-DSA figure must be measured before the claim is repeated. The whole history's anchors have been walked once by the independent Nethermind-derived watcher (134,954 anchors, 2026-09-08, operating notes), so the verification of every certificate ever produced is a measured, repeatable operation, not a projection. Memory: the AIP-21 side store holds about 7 kB per block for ten seals over a 256-block window (AIP-21); a syncing reader does not need it.
Per block: the hash chain (one keccak of the header, already done), the proposer check, and after `H_hdr` one Falcon verification (0.068 to 0.092 ms median measured on validator-class hosts in July, 0.215 ms p95; 0.367 ms median on a 2-vCPU reader host on 2026-09-22). Per Falcon anchor (every 32 blocks): up to N Falcon verifications, 0.7 ms median to 3.7 ms at N = 10 depending on the host; per hybrid anchor (every 128): additionally up to N SLH-DSA verifications, **measured** 2026-09-22 at 0.669 ms median (1.494 ms p95) each on the 2-vCPU reader host with the fleet's jars, so about 6.7 ms per hybrid anchor. Amortized per block: about 0.02 to 0.12 ms (Falcon at 32) plus about 0.05 ms (SLH-DSA at 128), against a measured import budget of about 0.77 ms per block (1,300 blocks per second with ten peers, 2026-09-11); the post-quantum verification is therefore under 10% of import time on the measured host. The earlier gas-proxy estimate (8.75 x Falcon) overstated the ratio: on the consensus path (JDK digest) SLH-DSA verification costs 1.8 times a Falcon verification on the same host. The whole history's anchors have been walked once by the independent Nethermind-derived watcher (134,954 anchors, 2026-09-08, operating notes), so the verification of every certificate ever produced is a measured, repeatable operation, not a projection. Memory: the AIP-21 side store holds about 7 kB per block for ten seals over a 256-block window (AIP-21); a syncing reader does not need it.
**Liveness at K = Q.** A proposer builds the certificate for `parent(A)` from the commit seals it heard. A proposer that finalized `parent(A)` through its own QBFT round holds at least Q of them by construction (a commit counts only with a valid seal since 17,250,000). A proposer that imported `parent(A)` by block gossip or sync, or that restarted and lost its seal store (the store is node-local and volatile; findings register, 2026-09-03 and 2026-09-05), cannot build it and its round times out; the next proposer in rotation takes the anchor. Measured before this AIP, at K = 6 with 8 to 9 seals attached: 12 of 12 anchors at round 0 (2026-09-05); 10 of 10 Falcon seals verified on every validator's AIP-21 record (2026-09-22). The round-0 rate at K = Q is [NOT MEASURED] and is Stage 1's testnet gate.
@ -233,6 +233,40 @@ Nothing described here exists at the Created date. Planned artifacts, each landi
Activation heights on chain 2800 are the founder's (AIP-19 acceptance per stage); the disk delta (+8.7 GB per node per year at Stage 2, +11.6 GB at Stage 5) is stated to the founder with the fleet's measured margin at that date; the SLH-DSA verification time, the round-0 rate at K = Q, the validator-to-validator bandwidth and the Falcon arithmetization are the measurements that precede, respectively, section 8's claim, Stage 1, any set growth beyond 21 with SLH-DSA in the header, and section 7.
## Stage records (dated; the Status and Ratification rows above are unchanged by them)
**2026-09-22, stage 0, measurement 1 (SLH-DSA verification time):** see the constants table; recorded in the repository under `consensus-pqc/aip22-treapta0/`.
**2026-09-22 22:48Z, stage 1 started on testnet 28001 (K = Q = 4 of 5):** the step `2988864:4` was appended to the per-scheme minimum schedule of all six nodes that judge headers on chain 28001 (four Besu-derived validators and the read node on one host, the Nethermind-derived validator on another), one node at a time with at least 120 s and one anchor between restarts; every node caught the tip within about 20 s and carries the step in its live process environment. The Besu-derived client's threshold guard accepted the step with its quorum-or-above warning: "K reaches 4 at height 2988864; quorum for 5 validators is 4 and N - f is 4 ... the margin under the fault budget is 0", which is the liveness tax of section 8 stated by the code. Baseline before the step, measured the same hour on 40 anchors at K = 3: 40 of 40 at round 0, parent-to-anchor cycle 2.33 s mean (the testnet host is loaded; chain 2800 measured 1.80 s on 20 anchors in the same hour).
**2026-09-22 23:21Z, stage 1 proven on testnet 28001 (K = Q = 4 of 5):** over the seven anchors above H = 2,988,864, seven of seven were produced at round 0 (100%, parent-to-anchor cycle 2.29 s mean on the loaded host); the public verifier (`verify-anchor.mjs`, the tool this package ships) accepted all seven, each carrying 4 to 5 Falcon-512 and 4 to 5 SLH-DSA seals with one anchor carrying exactly the four-of-five minimum per scheme; a negative control that demanded six seals of five validators from H refused all seven; and both clients held identical hashes for all seven anchors (the Nethermind-derived validator on its local RPC and the Besu-derived nodes on the public door). Stage 2 (per-scheme intervals) is implemented in both clients with matched conformance vectors and negative controls; nothing here is on chain 2800.
**2026-09-23 10:13Z, stage 2 armed on testnet 28001 for H_I = 3,070,656:** all six nodes that judge headers carry `3070656:32` in the anchor-interval schedule and `3070656:falcon-512/32+slh-dsa-sha2-128s/128` in the scheme schedule, each switched in one restart with the house guards: the five Besu-derived nodes on a distribution built from the fleet's laboratory tree (the three consensus modules' regression 1,091 probes, 0 failed; against the live distribution exactly the seven stage-2 classes differ, none is missing), the Nethermind-derived validator on a binary built on its host (no type of the live binary missing). The public verifier reads the new grammar (a scheme named at the parent's step but off its own grid is surplus: verified, not required at K; a scheme not named at all is refused) and gave the same result as before on both chains ahead of H_I (20 of 20 on 2800, 6 of 6 on 28001).
**2026-09-23 12:07Z, stage 2 proven on testnet 28001 (H_I = 3,070,656):** over the 11 anchors from H_I to the tip (3,070,656 to 3,070,976), the three on the 128 grid (3,070,656, 3,070,784, 3,070,912) were hybrid (four Falcon-512 and four SLH-DSA-SHA2-128s seals each) and the eight between them Falcon-only (five Falcon-512 seals); eleven of eleven were produced at round 0 (parent-to-anchor cycle 1.00 s mean); the public verifier with the stage-2 schedule accepted all eleven; a negative control running the same verifier with the schedule in force before H_I (SLH-DSA required at every anchor) refused exactly the eight Falcon-only anchors ("missing scheme slh-dsa-sha2-128s") and accepted the three hybrid ones; the Nethermind-derived validator held identical hashes for all eleven; the block rhythm was unchanged (0.566 s before, 0.563 s after). Not measured, and stated: the behaviour of a node left without the stage at H_I (the testnet has none). The public verifier with per-scheme intervals and the stage-3 identity translation is published in the `aere-node` package and on the site the same hour; chain 2800 verifies 20 of 20 with it, unchanged. Nothing of stage 2 is on chain 2800.
**2026-09-23 13:33:49Z, stage 3 rehearsed on testnet 28001 (H_id = 3,080,010), with two defects of the Nethermind-derived client found and repaired the same hour:** the v3 epoch of the testnet (five rows, each binding exactly the Falcon-512 key, the SLH-DSA key and the address of the live key manifest, checked row by row; registry hash `0xd19eef4a...`, pinned in every node's configuration) was published in the testnet's manifest index before H_id, and the public verifier finds it there, verifies it in full (every proof of possession, every ECDSA link, the Merkle registry hash) and requires its keys to equal the keys that sign. At H_id the validator list in `extraData` changed from the five ECDSA addresses (block 3,080,009) to the five post-quantum ids (block 3,080,010), and `coinbase` became an id. Defect 1, found by reading the code at 12:48Z, before H_id: the Nethermind-derived client's anchor rule and producer compared the registry's classical address of a seal's index with the parent's list, which holds ids from H_id, so it would have refused every anchor after H_id; repaired (the index's address translated into the identity of the parent's height, as the Besu-derived client does) and switched at 12:51Z. Defect 2, found on the chain: that client reset its message-author check at every height to the validator set of its environment, in addresses, so from H_id it dropped every Besu message as "not in the validator set", stopped sealing, and its round-0 slot expired at every rotation: 1.546 s per block from 13:34 to 13:48Z against 0.564 before (the proof over [H_id, H_id + 500] reports it: OPEN, four proposers, rhythm ratio 2.741, kept dated). Repaired (the environment set translated into ids from H_id) and switched at 13:48:50Z. After the repair, over [3,080,800, 3,081,300]: all five ids proposed exactly 100 blocks each, both clients held identical hashes for every block from H_id - 1 to 3,081,300 (1,292 of 1,292, the degraded window included), the rhythm ratio was 1.000, the public verifier run as a stranger (no variables) accepted 20 of 20 anchors with the v3 link, and the same verifier with the identity switched off refused all 20 ("keys not in validator set"). A vote carried an id: validator 0 proposed the removal of validator 3's id, block 3,082,048 carries `[id, drop]` in its vote element, the vote alone has no majority and the set stayed five ids, and after the vote was discarded the next block of validator 0 carries none; both clients agree on those blocks. Not measured, and stated: the behaviour of a node left without stage 3 at H_id. The Besu-derived client and the public verifier also carry stage 3b (the keys that seal read from the v3 epoch in force from a height H_k, with a startup continuity guard and the ECDSA link inherited by id), proven with the shared vectors and negative controls, deployed nowhere; the local signing key by height (stage 3b-ii) is next.
**2026-09-23 16:37Z, stage 3b proven on testnet 28001: a validator's keys rotated under its id at B2 = 3,097,600.** From H_k = 3,080,010 (the bindHeight of the switch epoch) the keys that seal are read from the v3 epoch in force, in both clients and in the public verifier; a startup guard in each client refuses to start unless the epoch at H_k carries exactly the keys of the existing registries (10 keys of 5 rows, verified on all six nodes), so the switch changed no key. A node's own signing key and index are derived the same way: a validator holds its current key and its NEXT keys as files, and from each height it signs with the key its row carries in the epoch in force there, at that row's index; a second startup guard refuses to start a validator registered in an epoch from H_k whose key it does not hold, because it would otherwise go silent at that epoch with every configuration check green. The rotation: a new PROBA key pair (Falcon-512 and SLH-DSA-SHA2-128s) for validator 2 was generated on its own host by the registry tool (owner-only files, nothing private printed); its row in the epoch bound at B2 keeps the id `0xe7e6b4d3...`, carries the new keys with their proofs of possession, and carries a rotation signed by each previous key over the new row hash; the other four rows keep their keys, with possession re-proven for the new bindHeight. The epoch's registry hash `0xb5847f46...` is identical in the Besu-derived strict loader and in the independent JavaScript implementation, which also refuses the same epoch without its predecessor (REG3-09, the rotated row then reads as a new id) and with the rotation signature corrupted (REG3-12). All six nodes were armed before B2 (five Besu-derived on a distribution that loses no class of the live one, the Nethermind-derived validator on a binary built on its host), validator 2 with its next keys; the epoch and the `keysFrom` mark were published in the testnet's manifest index the same hour. Over [B2 - 1, B2 + 500]: the validator set was the same five ids at B2 - 1, B2 and B2 + 500; both clients held identical hashes for all 502 blocks; the rhythm was 0.565 s per block before and 0.568 after; the public verifier run as a stranger (no variables) found the epoch and the mark in the published index and accepted 15 of 15 anchors; and the NEGATIVE CONTROL, the same verifier on a copy of the published manifests without the epoch bound at B2, refused validator 2's Falcon seal as invalid on 12 of the 15 anchors (the other three did not carry that validator's seal), so the seals after B2 are made with the rotated key and nothing else verifies them. Not measured, and stated: the behaviour of a node left without the epoch at B2 (the testnet has none), and a rotation on chain 2800, which means new keys and a founder decision.
**2026-09-23, stage 3 foundation: the registry v3 forms, pinned.** Section 3.2 names a "canonical serialization"; the bytes are now fixed, identically, in the Besu-derived client (`PqRegistryV3`), the Nethermind-derived client (`PqRegistryV3`) and a third, independent JavaScript implementation, and pinned by 19 shared conformance vectors (two valid epochs, the second rotating one validator's keys under its id; seventeen refusals, each differing from a valid manifest in one field with the signatures re-made over that field, one per refusal code `AERE-PQC-REG3-01` to `-16`):
```
row pre-image = "AERE-PQ-ROW-3" || u8(3) || u64be(chainId) || u64be(bindHeight) || u32be(count)
|| u32be(index) || id(20) || u8(nKeys)
|| per key, ascending scheme wire id (falcon-512 = 1, slh-dsa-sha2-128s = 2):
u8(wireId) || u32be(len pk) || pk || u32be(len pop) || pop
|| u8(hasTransport) [|| transport(20)]
row hash = keccak256(row pre-image) (rotation and ecdsa are not part of it)
Merkle node = keccak256(0x01 || left || right); an odd node is paired with itself
registry hash = keccak256("AERE-PQ-REGISTRY-3" || u64be(chainId) || u64be(bindHeight) || u32be(count) || root)
pop message = keccak256(the pre-image of section 3.2's pop row) signed by that key
rotate message = keccak256("AERE-PQ-ROTATE-3" || new row hash) signed by every previous key of the id
ecdsa claim = keccak256(0x19 || 0x00 || low20(keccak256("AERE-PQ-CLAIM-1" || u64be(chainId))) || row hash)
```
Two refinements to the text above, recorded rather than silently applied: the Merkle inner node carries the tag byte `0x01`, so an inner node can never be presented as a row hash; and a membership proof is valid only for an index below `count`, because with the odd node paired with itself the path of the last row of an odd-sized tree would otherwise also prove the index `count` (both clients and the JavaScript tool refuse it, and a probe in each asserts the refusal). Negative controls: in the Besu-derived client, removing the rotation rule, the id-derivation rule or the index bound each turns its probes red with the probes run (and the untouched source green); in the Nethermind-derived client, removing the rotation rule turns 2 of its 3 probes red and removing the index bound 1 of 3 (untouched: 3 of 3 green); in the JavaScript tool the same three plantings are caught by 2, 2 and 1 vectors. Nothing of stage 3 is wired into consensus yet: the set translation at `H_id`, authorship by row, `coinbase` and votes by id, and the forwarding predicate are the next parts, and the v3 epoch of testnet 28001 needs the PROBA keys on its hosts to sign possession, claim and rotation.
## Errata
None.