aere-docs/AERE-STARK-FRI-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

77 lines
5.8 KiB
Markdown

# Component (d) FRI verifier for Aere STARK-verify port (0x0AE8): summary
> **Scope caveat (2026-07-19 finding).** This FRI verifier is conformance-confirmed against Plonky3
> `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), and its inner recursion proof uses **BaseFold,
> not FRI**, so this FRI low-degree test (one of the two largest confirmed pieces) does NOT apply to
> SP1 6.1.0 at all and this work does not verify SP1 6.1.0 proofs. 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. Outcome: the FRI FOLD + OPENING relation (verify_query, the low-degree test) is
IMPLEMENTED and CONFORMANCE-CONFIRMED against the pinned Plonky3 p3-fri 0.4.3-succinct via a real KAT
(accept genuine + reject tampered). The top-level precompile 0x0AE8 STAYS FAIL-CLOSED.
## 1. Confirmed FRI config (traced from pinned p3-fri 0.4.3-succinct source)
Read from the cargo cache of `p3-fri` (checksum 5cbc4965..., matches repo Cargo.lock):
- Folding arity 2 (hard-coded): sibling = index ^ 1, index_pair = index >> 1 (verifier.rs verify_query).
- FriConfig fields: { log_blowup, num_queries, proof_of_work_bits, mmcs } (config.rs).
- log_max_height = commit_phase_commits.len() + log_blowup; num_fold_rounds = log_max_height - log_blowup.
- Final polynomial is a SINGLE F_{p^4} CONSTANT (final_poly: F); verify_challenges checks folded == final
for every query. (log_final_poly_len = 0 in this pinned version.)
- Commit-phase MMCS = ExtensionMmcs<Val, Challenge=BinomialExtensionField<BabyBear,4>, ValMmcs> over the
CONFIRMED FieldMerkleTreeMmcs (component (c)). A leaf is a PAIR of F_{p^4} evals flattened to 8 BabyBear
coords (ExtensionMmcs::verify_batch, as_base_slice per element), a width-8 row of height 2^log_folded_height.
- Grinding (proof_of_work_bits / check_witness) is in the transcript phase (verify_shape_and_sample_challenges),
i.e. component (f), NOT part of the per-query fold+opening relation.
- Fold: x = two_adic_generator(log_max_height)^reverse_bits_len(index, log_max_height) in F_{p^4}; sibling
point = x * two_adic_generator(1) = -x; folded = e0 + (beta - x0)*(e1 - e0)/(x1 - x0); plus
reduced_openings[log_folded_height+1] injected before each fold.
## 2. What I implemented
- Ground-truth extractor `pqc-fork/pq-stark/fri-extractor/` (Rust, depends on pinned p3-fri/p3-challenger/
p3-dft/p3-commit/p3-merkle-tree/p3-poseidon2/... =0.4.3-succinct; lockfile checksums matched). Builds the
exact SP1 inner FRI config with the seed_from_u64(1) Poseidon2, constructs genuinely low-degree codewords,
runs p3_fri::prover::prove to emit real FriProofs, and runs p3_fri::verifier::{verify_shape_and_sample_
challenges, verify_challenges} to confirm the LIBRARY accepts. Emits fri_ground_truth.json (roots, betas,
query indices, reduced openings, per-query per-layer sibling values + MMCS proofs, final poly, all canonical
u32) plus perm_zeros + two_adic_generators sanity anchors. 3 cases (blowup 1/2, height 6/7/8, 4/5/6 queries).
- FRI verifier reference (verify_query / verify_challenges) in 3 languages, reusing the CONFIRMED sub-components
(F_{p^4} = component (a), MMCS verifyBatch = component (c), Poseidon2 = component (b)):
`fri_verify_reference.py`, `fri_verify_reference.mjs`, standalone `FriVerifySelfTest.java`.
- Wired into the fail-closed Java precompile: `Fri.verifyQuery` (+ `Fri.reverseBitsLen`, `Fri.foldRelationConfirmed
= true`) in Sp1StarkVerifierPrecompiledContract.java, using the existing BabyBearExt4 / Mmcs.verifyBatch /
BabyBear.twoAdicGenerator. `Fri.checkQuery` kept GATED (returns UNAVAILABLE).
- Harness `test_fri_verify.py` -> writes `../results/kat-results-fri-verify.json`. Spec `spec-fri-babybear.md`.
Updated port spec + pq-stark README.
## 3. Conformance KAT result: PASSED (accept + reject)
- `python test_fri_verify.py` -> PASS=55 FAIL=0: sanity (perm_zeros == confirmed Poseidon2 zeros; 28 two-adic
generators == component (a)); 3 cases each ACCEPT the genuine p3-fri proof and REJECT four tampers (corrupted
opened value, corrupted MMCS sibling digest, wrong beta/fold, non-matching final poly); Python + Node + Java
produce BYTE-IDENTICAL per-query folded values.
- `java FriVerifySelfTest fri_ground_truth.json` -> PASS=44 FAIL=0.
- The PRECOMPILE's own `Sp1StarkVerifierPrecompiledContract.Fri.verifyQuery`, driven directly against the ground
truth, reproduces accept + reject for all 3 cases (15/15). So the wired code, not just parallel references, is
conformant (no "two wrong copies agree").
Closed by this KAT (were [VERIFY]): arity-2 fold; num_fold_rounds = log_max_height - log_blowup + constant final
poly; reverse_bits_len coset mapping; two_adic_generator(bits) == Plonky3's; F_{p^4} non-residue W = 11 == Plonky3's.
## 4. Top level stays FAIL-CLOSED (verified)
- Challenger.spongePorted = false (component (f) un-ported) and StarkConstraints.evaluateAtZeta returns
UNAVAILABLE (component (e) un-ported): verify() returns UNAVAILABLE at stage 4, never reaches ACCEPT.
- computePrecompile returns VERIFIED only on ACCEPT, else Bytes.EMPTY -> EMPTY for every input.
- The FRI fold+opening takes betas/indices/reduced-openings as INPUTS; deriving them trustlessly is component
(f) (the duplex-sponge challenger), so Fri.checkQuery stays gated (UNAVAILABLE). WireReader also does not parse
the commit-phase roots/openings. DO NOT ACTIVATE banner intact. Precompile compiles clean (Besu stubs, javac exit 0).
## 5. Scope boundary (unchanged)
On-chain ZK verifiers on Aere remain classical BN254 Groth16 until the whole verifier is real, audited, and
founder-activated. This is one more component of a multi-week port. Rust compiled only in a scratch/temp dir; no
live infra touched.