The public history carried kat/__pycache__/mlkem768_reference.cpython-314.pyc, a compiled Python artifact embedding the operator's absolute local path. Text secret scanners do not read compiled binaries, which is exactly how it slipped through, and removing it from the tip would have left it reachable through the old root commits. So this repository is republished from a single clean root. This root also carries, from the previously unpublished line of work: - corrected LICENSE year, LICENSING.md, VERIFY-POLICY.md, and CITATIONS-UNRESOLVED.md remeasured 2026-08-11 (101 paths, README aligned) - O-018: run_consensus_verification.py ran 19 of 29 models and reported PASS; it now runs all 29, and computemarket_smt.py gains resolveByTimeout / reclaimUnsettled cases plus a negative control - O-006: the word 'audited' removed from next to Bouncy Castle, twice, after a concurrent edit resurrected it - O-014: prior art named and dated - Algorand's native falcon_verify shipped about ten months before AERE's precompiles; the primacy claim is withdrawn where it was implied - bench/ scripts parametrized so they actually run for an outsider (the earlier textual sanitization left $STAGING unexpanded inside Python strings) - AIP-2/AIP-3 errata with measured figures, spec remeasurements at 2026-08-01, and the spec-zk-stack retractions (owner is an operational key, not the Foundation; 'maximally sound' withdrawn; aggregator V1 deprecated) The redacted bench-host environment files from the sanitized line are kept exactly as published; the unredacted local variants are not carried.
11 KiB
FRI verifier over BabyBear: config + fold/opening relation + conformance KAT (component (d), 0x0AE8)
Scope caveat (2026-07-19 finding). "Plonky3/SP1" wording below means Plonky3
0.4.3-succinct(Aere's OWN BabyBear + FRI STARK stack). It does NOT mean the pinned SP1 6.1.0, which is a Hypercube release whose inner recursion proof uses BaseFold, NOT FRI. This FRI low-degree test does not apply to SP1 6.1.0 at all; it is conformance-confirmed for a BabyBear + FRI STARK verifier (Aere's own Plonky3 circuits), not for an SP1 6.1.0 verifier. See../../docs/AERE-STARK-SP1-RECURSION-AIR-PORT-SPEC-SUMMARY.md.
Date: 2026-07-19. Status: FRI config CONFIRMED-FROM-SOURCE; fold + opening relation (verify_query) IMPLEMENTED; real conformance KAT PASSED (accept genuine + reject tampered).
This records the exact FRI low-degree test Plonky3/SP1 use over BabyBear, traced from the pinned
p3-fri source, the fold + opening relation the verifier checks, and the real known-answer test that
confirms conformance. The top-level precompile 0x0AE8 stays FAIL-CLOSED (returns EMPTY for every input)
regardless: this component being confirmed does not port the duplex-sponge Fiat-Shamir challenger
(component (f)) that binds the transcript, nor the SP1 recursion-AIR (component (e)).
Pinned target (exact, checksum-matched)
The FRI verifier is p3_fri::verifier from p3-fri, its commit-phase MMCS is ExtensionMmcs from
p3-commit wrapping the CONFIRMED FieldMerkleTreeMmcs (component (c)), and the challenger used to
emit the ground truth is DuplexChallenger from p3-challenger. All crates.io version
0.4.3-succinct (the Succinct Plonky3 fork), the revision pinned in the repo's Cargo.lock files:
p3-fri0.4.3-succinct, sha2565cbc4965ee488f3247867b7ec4bb005b8afa72cb0d461a4dcb1387ecab6426d5p3-challenger0.4.3-succinct, sha256b6a908924d43e4cfb93fb41c8346cac211b70314385a9037e9241f5b7f3eaf77p3-dft0.4.3-succinct, sha256be6408b10a2c27eb13a7d5580c546c2179a8dc7dbc10a990657311891f9b41c0p3-commit0.4.3-succinct, sha25650acacc7219fce6c01db938f82c1b21b5e7133990b7fff861f91534aeb569419
Found in aerenew/zk-circuits/*/Cargo.lock and aerenew/rollup-evm-validity/*/Cargo.lock. A fresh
cargo build of the extractor (below) resolved the SAME checksums, so the crates executed are
byte-identical to the ones the AERE prover pins.
The confirmed FRI config (traced from p3-fri source)
FriConfig (p3-fri config.rs) has exactly four fields:
{ log_blowup, num_queries, proof_of_work_bits, mmcs }. Traced from verifier.rs:
- Folding arity is 2 (hard-coded): each layer opens the sibling pair
(index, index ^ 1)and foldsindex_pair = index >> 1. The comment inproof.rssays a non-2 arity would need multiple siblings; this pinned version is arity 2. log_max_height = commit_phase_commits.len() + log_blowup. The commit phase runs forlog_max_height - log_blowuplayers (for log_folded_height in (log_blowup..log_max_height).rev()inprover.rscommit_phase), sonum_fold_rounds = log_max_height - log_blowup.- The FINAL polynomial is a single CONSTANT
final_poly: F(F = the challenge field EF). Folding runs all the way down; after the last fold the remainingblowup()evaluations are all equal, and the verifier checksfolded_eval == final_polyfor EVERY query (verify_challenges). (The source comment notes it "could become Vec<...> if generalized to support non-constant final polynomials"; in this pinned version it is a constant, solog_final_poly_len = 0.) - The commit-phase MMCS is
ExtensionMmcs<Val, Challenge, ValMmcs>(the FRI codewords live in the degree-4 extension EF =BinomialExtensionField<BabyBear, 4>). Each commit-phase leaf is a PAIR of EF evaluations;ExtensionMmcs::verify_batchflattens each EF element to its 4 base coords (as_base_slice) and concatenates, so a leaf is 8 BabyBear coords, a single width-8 row of a height-2^log_folded_heighttree, checked by the CONFIRMED baseFieldMerkleTreeMmcs::verify_batch(component (c)). - Proof-of-work / grinding (
proof_of_work_bits,check_witness) is part of the transcript phase (verify_shape_and_sample_challenges), i.e. component (f); it is NOT part of the per-query fold + opening relation this component ports. num_queries,log_blowup,proof_of_work_bitsare proximity/soundness parameters read from the frozen SP1 config; the values are a [MEASURE] against a real exported proof (see the port spec). The KAT here exercises several (log_blowup, log_max_height, num_queries) shapes to validate the relation independently of the exact frozen numbers.
The fold + opening relation (p3-fri verify_query, ported)
For one query at index (from verifier.rs verify_query, reproduced exactly by the references and by
Fri.verifyQuery in the precompile):
folded_eval = 0 in EF
x = two_adic_generator(log_max_height)^reverse_bits_len(index, log_max_height) # coset point, in EF
for each layer (log_folded_height = log_max_height-1 down to log_blowup):
folded_eval += reduced_openings[log_folded_height + 1] # the injected input opening at this height
index_sibling = index ^ 1; index_pair = index >> 1
evals = [folded_eval, folded_eval]; evals[index_sibling % 2] = sibling_value # the opened sibling
MMCS.verify_batch(commit_layer, dims={width:2(EF)->8(base), height:2^log_folded_height},
index_pair, [evals flattened to 8 base coords], opening_proof) # component (c)
xs = [x, x]; xs[index_sibling % 2] *= two_adic_generator(1) # the sibling point is -x
folded_eval = evals[0] + (beta - xs[0]) * (evals[1] - evals[0]) / (xs[1] - xs[0]) # interpolate at beta
index = index_pair; x = x^2
return folded_eval # verify_challenges checks this == final_poly for every query
two_adic_generator(bits)forbits <= 27is the BabyBear base generator embedded in EF (confirmed fromp3-baby-bear extension.rs ext_two_adic_generator), soxis a base-field element embedded in EF;two_adic_generator(1) = -1(the order-2 root). The arithmetic uses F_{p^4} (component (a)).- The reduced openings come from the input polynomials in a full STARK (component (e)); for a
standalone single-codeword low-degree test they are zero except
reduced_openings[log_max_height] = codeword_value_at_index, which the extractor emits asro_top.
Montgomery / canonical note
Field elements are serialized as canonical u32 (PrimeField32::as_canonical_u32 for base coords). The
F_{p^4} fold arithmetic is canonical (component (a)); the Montgomery R^{-1} factor lives entirely
inside the Poseidon2 internal layer (component (b), resolved there) and does not surface in the FRI or
MMCS layers. As a cross-check, the extractor's permute([0;16]) (emitted as perm_zeros) equals the
confirmed Poseidon2 "zeros" vector, and the extractor's two_adic_generator(bits) for bits 0..=27
equals component (a)'s twoAdicGenerator(bits) (this is what makes the fold's coset points come out
right, closing the old [VERIFY] on the generator).
How the KAT vectors were obtained (primary source)
A small Rust extractor (pq-stark/fri-extractor, main.rs + Cargo.toml + Cargo.lock) depending on
the pinned crates was compiled and run (cargo 1.97.0). It builds the exact SP1 inner FRI config
(BabyBear + BinomialExtensionField<_,4> + the seed_from_u64(1) Poseidon2 permutation +
FieldMerkleTreeMmcs + ExtensionMmcs + DuplexChallenger<_,_,16,8>), constructs genuinely
low-degree codewords (an RS/LDE of a random low-degree polynomial via Radix2Dit, bit-reversed), runs
p3_fri::prover::prove to emit a real FriProof, then runs
p3_fri::verifier::{verify_shape_and_sample_challenges, verify_challenges} to confirm the pinned
LIBRARY itself accepts. It emits everything the reference verifier needs (commit-phase roots, betas,
query indices, reduced openings, per-query per-layer sibling values + MMCS opening proofs, final poly),
each field element as canonical u32. The output (pq-stark/fri_ground_truth.json) is the authoritative
source. Three FRI cases are emitted:
| case | log_blowup | log_max_height | num_queries | fold layers |
|---|---|---|---|---|
| blowup1_h6_q4 | 1 | 6 | 4 | 5 |
| blowup2_h7_q5 | 2 | 7 | 5 | 5 |
| blowup1_h8_q6 | 1 | 8 | 6 | 7 |
Conformance KAT (real known-answer test, executed from the pinned crates)
The reference (fri_verify_reference.py, .mjs, standalone FriVerifySelfTest.java, and
Fri.verifyQuery in the precompile) re-verifies each emitted proof:
- ACCEPT: every query's MMCS openings pass AND every query's folded constant equals
final_poly. - REJECT (four tamper variants per case): a corrupted opened value (breaks the MMCS opening), a
corrupted MMCS sibling digest (breaks the opening), a wrong fold challenge
beta(breaks the interpolation sofolded != final_poly, i.e. a wrong fold), and a non-matchingfinal_poly(the final-poly check, the mechanism that catches a non-low-degree witness).
Result (ran 2026-07-19):
python test_fri_verify.py-> PASS=55 FAIL=0 (sanity perm + 28 generators; 3 cases x (accept + 4 rejects); Python + Node + Java byte-identical per-query folded values; recorded in../results/kat-results-fri-verify.json).java FriVerifySelfTest fri_ground_truth.json-> PASS=44 FAIL=0.- The PRECOMPILE's own
Sp1StarkVerifierPrecompiledContract.Fri.verifyQuery(driven directly) reproduces accept + reject for all 3 cases (15/15), so the wired code, not just the parallel references, is conformant.
Status summary
- FRI config: CONFIRMED-FROM-SOURCE (arity 2; num_fold_rounds = log_max_height - log_blowup; constant final poly; ExtensionMmcs-over-FieldMerkleTreeMmcs commit phase; traced from p3-fri 0.4.3-succinct; checksums matched Cargo.lock).
- Fold + opening relation (verify_query): IMPLEMENTED (Python/Node/Java +
Fri.verifyQuery). - Conformance KAT: PASSED (3 real FRI proofs accepted, 4 tamper variants each rejected; three-language byte-identical; the precompile's own method also conformant).
- Closed by this KAT (were
[VERIFY]): arity-2 fold, num_fold_rounds, reverse-bits index-to-coset-point mapping,two_adic_generator(bits)= Plonky3's, and the F_{p^4} non-residueW = 11= Plonky3's (the EF fold arithmetic reproduces the interpolation). Fri.foldRelationConfirmed= true (the fold + opening relation is confirmed conformant).[MEASURE]remaining: conformance against a REAL exported SP1 v6.1.0 inner proof's FRI section (needs the exported proof + the challenger, component (f)) and the AIR reduced openings (component (e)).- Top-level 0x0AE8: still FAIL-CLOSED (EMPTY for every input). The duplex-sponge challenger
(
Challenger.spongePorted = false, component (f)) that derives the betas/indices/grinding, and the SP1 recursion-AIR (StarkConstraints= UNAVAILABLE, component (e)) that supplies the reduced openings, are un-ported, soFri.checkQuerycannot be driven and returns UNAVAILABLE. ACCEPT is unreachable. DO NOT ACTIVATE.