aere-docs/AERE-STARK-TRANSCRIPT-SUMMARY.md
Aere Network e4cead319d Initial public release
Aere Network public source. Everything here can be checked against the live
chain (chain id 2800, https://rpc.aere.network).

Scope note, stated up front rather than buried: consensus on chain 2800 is
classical secp256k1 ECDSA QBFT. The post-quantum work in this repository is at
the signature, precompile, account and transport layers. Nothing here makes the
consensus post-quantum, and no document in it should be read as claiming so.
2026-07-20 01:01:36 +03:00

6.3 KiB

Component (f): Fiat-Shamir transcript / Poseidon2 duplex challenger (0x0AE8) - CONFORMANCE-CONFIRMED

Scope caveat (2026-07-19 finding). This transcript is conformance-confirmed against Plonky3 p3-challenger / p3-fri 0.4.3-succinct (Aere's OWN BabyBear + FRI STARK stack), NOT against SP1 6.1.0. SP1 6.1.0 is a Hypercube release (KoalaBear multilinear: BaseFold + Jagged + sumcheck-zerocheck + LogUp-GKR), so FRI and DEEP-ALI do not apply to it and this skeleton does not verify SP1 6.1.0 proofs. (The duplex-challenger SHAPE carries over to SP1's Hypercube stack, but over the KoalaBear field with KoalaBear constants and a different observe/sample order.) Replacing the SP1 BN254 Groth16 wrap is a separate ~22 to 32 person-week retarget. See AERE-STARK-SP1-RECURSION-AIR-PORT-SPEC-SUMMARY.md.

Date: 2026-07-19. Precompile: Aere PQ STARK verifier at 0x0AE8. Scope: port-spec component (f).

Result headline

  • Transcript conformance KAT: PASSED (PASS=44 FAIL=0 across Python + Node + standalone Java; standalone ChallengerSelfTest PASS=31 including a driver fail-closed gate model).
  • It closed the FRI betas/indices loop that component (d) left open: transcript -> derived betas/indices -> confirmed Fri.verifyQuery ACCEPTs the real FRI ground-truth proof and REJECTs a tampered beta.
  • Challenger.spongePorted flipped true. Top level stays FAIL-CLOSED: StarkConstraints. evaluateAtZeta still returns UNAVAILABLE (component (e), the AIR, un-ported), gating ACCEPT before the query loop and before the single return ACCEPT. computePrecompile returns EMPTY for every input; ACCEPT is unreachable by construction. DO NOT ACTIVATE.

What was confirmed from pinned source (p3-challenger / p3-fri 0.4.3-succinct)

DuplexChallenger<BabyBear, Perm, WIDTH=16, RATE=8> (duplex_challenger.rs) + GrindingChallenger (grinding_challenger.rs), transcript order from p3-fri verifier.rs verify_shape_and_sample_challenges:

  • observe(felt): clear output buffer, push to input buffer, duplex when input buffer reaches RATE=8.
  • duplexing: overwrite the first input_buffer.len() (<=RATE) of 16 lanes, permute (confirmed Poseidon2), set output buffer = lanes [0..8).
  • sample: duplex if inputs buffered OR outputs empty, then Vec::pop (LIFO, from the END). An F_{p^4} sample = 4 sequential base pops [c0,c1,c2,c3] (sample_ext_element = sample_vec(4) then from_base_slice).
  • sample_bits(bits): LOW bits of as_canonical_u64 (confirmed LSB).
  • check_witness(pow_bits, witness): observe(witness) then sample_bits(pow_bits) == 0.
  • FRI transcript order: per commit -> observe 8-elem digest, sample beta (F_{p^4}); then observe final_poly (4 coords); then check_witness(pow_bits, pow_witness); then num_queries x sample_bits(log_max_height). log_max_height = commits.len() + log_blowup.

Montgomery/serialization: all arithmetic canonical (the confirmed Poseidon2 reference already carries the internal-layer R^-1 factor); the extractor emits as_canonical_u32 and as_base_slice coords, and the references reproduce them exactly.

Ground truth (executed the pinned crates)

pqc-fork/pq-stark/challenger-extractor/ (Cargo.toml + copied fri-extractor Cargo.lock, byte-identical pins) compiled and ran (target dir in scratch, no repo pollution, live infra untouched). It emits challenger_ground_truth.json with two blocks:

  1. duplex_kat: a fully-scripted observe/sample transcript -> base samples, F_{p^4} ext samples, sample_bits, the full 16-lane sponge state at a checkpoint, and a check_witness accept/reject table (real grinding witness accepts, fixed non-witnesses reject).
  2. fri_transcript: the SAME three FRI cases as fri_ground_truth.json, rebuilt (same seeds) so the commit_phase_commits / final_poly / pow_witness / betas / query_indices match; the references derive betas+indices+PoW-accept from (commits, final_poly, pow_witness) and match BOTH the extractor AND fri_ground_truth.json.

The references reproduce every value byte-for-byte (all 3 languages identical), and the derived betas/indices, fed to the confirmed Fri.verifyQuery, accept the real proof and reject a tampered beta.

Files added/changed

Added: challenger_reference.py, challenger_reference.mjs, ChallengerSelfTest.java, test_challenger.py, challenger-extractor/{Cargo.toml,Cargo.lock,src/main.rs}, challenger_ground_truth.json, ../results/kat-results-challenger.json.

Changed:

  • pqc-fork/precompiles/Sp1StarkVerifierPrecompiledContract.java: Challenger class rewritten as the confirmed duplex sponge over Poseidon2Bb.permute (observeField/sampleBaseField/sampleExtField/ sampleBits/checkWitnessField + byte-facing driver adapters); spongePorted = true; driver stage-4 comment clarifies the AIR gate; stale "spongePorted=false" docs updated. StarkConstraints. evaluateAtZeta UNCHANGED (still returns UNAVAILABLE at line ~1077).
  • docs/AERE-STARK-VERIFIER-PORT-SPEC.md: status header, section 5 note, section 7 rewritten (IMPLEMENTED + CONFORMANCE-CONFIRMED), section 9 table row (f), section 10 files.
  • pqc-fork/pq-stark/README.md: HONEST STATUS, sections (b)/(c)/(d) closings, new section (f), layout.
  • pqc-fork/pq-stark/test_fri_verify.py: descriptive notes updated (f now confirmed; loop closed).

Fail-closed proof

verify() control flow: ACCEPT requires stage 3 (PoW) AND stage 4 (AIR) AND stage 5 (queries) all pass. Stage 4 = StarkConstraints.evaluateAtZeta ALWAYS returns UNAVAILABLE (component (e) un-ported) and is checked (line 196) BEFORE the query loop and BEFORE the single return ACCEPT (line 228). So verify() returns UNAVAILABLE for every input reaching stage 4; computePrecompile returns EMPTY. Flipping spongePorted cannot create an ACCEPT path. Corroborated at runtime by ChallengerSelfTest.gateModel (driver.gate.ACCEPT_unreachable_for_every_input PASS). The precompile is not compiled here (it is applied via patch to a Besu build, no local Besu jar); the challenger algorithm is verified by the byte-identical standalone ChallengerSelfTest.

Remaining

Component (e), the SP1 recursion AIR (StarkConstraints, ~3-4 person-weeks, HARDEST), is the one remaining un-ported crypto-core component. Real exported SP1 v6.1.0 transcript order is [MEASURE]. On-chain ZK verifiers remain classical BN254 until all 6 components + integration + a real SP1-proof end-to-end KAT + audit + founder activation.