AIP-22: dated record, the public verifier checks the proposer seal on every recent header (stage 5), proven on testnet 28001 with two planted forgeries rejected

This commit is contained in:
Aere Network 2026-09-24 23:04:07 +03:00
parent b1f852bc52
commit 7f00c88a86

View File

@ -257,6 +257,8 @@ Activation heights on chain 2800 are the founder's (AIP-19 acceptance per stage)
**2026-09-23 22:05Z, stage 5 proven on testnet 28001 (H_hdr = 3,131,000).** At the crossing (21:48Z) the five proposers kept their turns on both sides (12 x 5 before, 13, 12, 12, 12, 12 after), 35 s for the 59 blocks before and 33 s for the 60 after, extraData from 416 to 812 bytes, zero refusals in either client. The rare case was provoked from outside: one Besu-derived validator restarted after H_hdr, and two blocks were finalized at round 1 (3,131,097 and 3,131,101), with the same hash in both clients. Over [H_hdr - 1, H_hdr + 500]: H_hdr armed in the environment of all six nodes (positive control on the same read, H_fin, six of six); both clients held identical hashes for all 502 blocks; read from the bytes, all 501 headers from H_hdr have an empty ECDSA seal element, seven elements, a proposer seal `[index, Falcon-512 signature]`, an empty certificate slot between anchors and a certificate at each of the 16 anchors, and the five coinbases map one-to-one onto five indexes (positive control of the decoder: the 64 headers below H_hdr carry at least four ECDSA seals and no element 6); the extraData of all 501 blocks is byte-identical between the two clients, so each writes the same canonical encoding (control of the method: 8 of the 40 blocks below H_hdr differ between clients, as locally gathered ECDSA seals legitimately do); all five ids proposed (101, 101, 100, 100, 99), the rhythm was 0.567 s per block before and 0.594 after, ratio 1.048 with the provoked restart inside the window; the published verifier in its default mode verified 15 of 15 anchors after H_hdr, while its previous form fails on the same chain ("the two most recent anchors are 1 apart"). NEGATIVE CONTROL OF THE METHOD: the proposer and rhythm measures on the known-bad window [3,080,010, 3,080,510] come out red (four proposers, ratio 2.741). A first run of the proof reported a failure of step 4 that belonged to the proof, not to the chain: it copied the verifier without `registry-v3.mjs`, which the verifier loads on a chain with v3 epochs; the harness now copies every module published beside the tool. Not measured, and stated: a forged header sent on the network (no testnet node can inject one; its refusal is proven by the planted controls in both clients).
**2026-09-24 20:00Z, the public verifier checks the proposer seal (stage 5).** `aere-node/tools/verify-anchor.mjs` gains a sixth step: on the most recent headers that carry element 6 (20 by default), it recomputes the proposal digest from the stored header (the `EXCLUDE_COMMIT_SEALS` form, round kept), the message `keccak256(RLP["AERE-PQ-PROPOSAL-1", chainId, height, round, digest])`, verifies the Falcon-512 signature against the key of the index in the published v3 epoch in force at that height, and requires that index's `id` to be the header's `coinbase`; each header is first re-encoded in the on-chain form and must reproduce the hash the endpoint reports, otherwise it is not judged. On testnet 28001, run exactly as the public instruction on the site says: 20 of 20 recent headers verified. Negative controls through a local proxy that alters only element 6 (outside both hashes): one byte of the signature flipped, and the index moved to another validator, each fail with the reason named; on chain 2800, where no header carries element 6, the step says stage 5 is not active and does not change the verdict (four of four).
**2026-09-23 22:10-22:35Z, stage 6 (equivocation evidence on chain) built and proven on testnet 28001.** First the framing was proven against the live Falcon-512 precompile before any contract was written: a consensus seal on the wire is `0x39 || nonce(40) || compressed` and becomes the precompile input `pk(897) || u16(len esig) || nonce || message || esig` with `esig = 0x29 || compressed`; the five real seals of an anchor certificate return 1, the same seals with one bit changed return 0, the same seals under another index's key return 0, and the specification's JavaScript verifier agrees on all fifteen cases. `PqEquivocationEvidence` (immutable, ownerless; its epochs and pins fixed at construction, a later epoch needs a new contract) takes the SIGNED PRE-IMAGE FIELDS of the two messages rather than the full upstream payloads (a seal binds only its pre-image, so nothing else in a payload could be checked; a stated deviation from the object as written in section 6), rebuilds both pre-images on chain exactly as the clients do, verifies both seals through `0x0AE1`, parses the v3 row pre-image for its chain, epoch, index, id and Falcon key, proves the row hash into the registry hash pinned for the epoch in force at the height, and records `(id, type, height, round)` once. Equivocation per type: PROPOSAL and PREPARE, same height and round and a different digest; COMMIT (the anchor form, which carries no round), same height and a different block hash; ROUND-CHANGE, same height and target round and a different prepared claim. The id is not re-derived from the key on chain: a rotated row keeps the id of its first registration, which the first form of the contract refused on the live epoch (row 2 of epoch 3,097,600); the id is inside the row hash, which the registry binds. On testnet 28001 the registry epochs were pinned only in genesis and in node configuration, so the two v3 epochs were pinned on chain in the same eleven-byte read-only getter as chain 2800's epochs, each reloaded and verified (possession proofs, rotation, ids) before its hash was written. Probes: locally, seven tests with a stand-in precompile (the pre-images, all four types recorded, each refusal by its reason, a rotated row accepted), and a negative control of six guards planted at run time (conflict, second seal, pin, chain id, epoch, domain), each red with the tests run. On chain 28001, with the live precompile: a DRILL instance (pre-images naming chain 28099 and an epoch of drill keys generated in memory for the run, so that no validator of 28001 or 2800 is named by a permanent record) recorded a PREPARE and a COMMIT equivocation, each sealed twice by one row with the clients' own signing code, at 322,404 and 303,103 gas, and refused, as calls, the same message twice, a second seal from another row, a Merkle path to another registry and a second submission; the REAL instance (chain 28001, the two v3 epochs) proves all five rows of the epoch in force, the rotated one included, and verifies the four seals of a live anchor certificate through the contract over the COMMIT-1 message the contract rebuilds, with the changed-bit control refused. The runtime code of both instances equals the compiled source with the immutable chain id masked, and the first form's code differs (control of the method). Not built in this pass, and stated: the second form of section 6 (two conflicting anchor headers) and any consequence, which stays a schedule 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`):