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.
245 lines
13 KiB
Python
245 lines
13 KiB
Python
#!/usr/bin/env python3
|
|
# Test harness for the FRI VERIFIER sub-component (port spec section 5, component (d)). Runs:
|
|
# 1. CONFORMANCE (the real gate): the ground-truth extractor (pq-stark/fri-extractor) ran the pinned
|
|
# Plonky3 p3-fri 0.4.3-succinct PROVER to emit real FRI proofs over known low-degree polynomials
|
|
# and confirmed the pinned p3-fri VERIFIER accepts them. This reference reproduces the ACCEPT for
|
|
# every genuine proof and REJECTS four tamper variants per case: a corrupted opened value, a
|
|
# corrupted MMCS sibling digest, a wrong fold challenge (beta), and a non-matching final polynomial.
|
|
# 2. a perm + two-adic-generator sanity check tying the ground truth to the CONFIRMED Poseidon2
|
|
# permutation (component (b)) and component (a)'s two-adic generators (this closes the [VERIFY] on
|
|
# twoAdicGenerator: the fold's coset points come out right only if the generators match Plonky3).
|
|
# 3. cross-language agreement: Python vs Node vs Java produce byte-identical per-query FOLDED values
|
|
# (three independent implementations of the F_{p^4} fold arithmetic) and identical accept/reject flags.
|
|
# Writes ../results/kat-results-fri-verify.json and exits non-zero on any failure.
|
|
#
|
|
# ============================ HONEST SCOPE ============================
|
|
# This confirms the FOLD + OPENING relations (verify_query) against the pinned p3-fri. Within this KAT the
|
|
# betas and query indices are taken as INPUTS (from the pinned p3-fri challenger in the extractor). The
|
|
# transcript BINDING that derives them in-circuit is component (f) (the duplex-sponge challenger), now
|
|
# CONFIRMED separately (test_challenger.py), whose derived betas/indices close the loop into this
|
|
# verify_query. So even with the FRI relation (d) AND the challenger (f) confirmed, the top-level 0x0AE8
|
|
# stays FAIL-CLOSED on the AIR (component (e), StarkConstraints=UNAVAILABLE): ACCEPT is unreachable and
|
|
# computePrecompile returns EMPTY for every input. DO NOT ACTIVATE.
|
|
|
|
import json
|
|
import os
|
|
import subprocess
|
|
import sys
|
|
from shutil import which
|
|
|
|
HERE = os.path.dirname(os.path.abspath(__file__))
|
|
sys.path.insert(0, HERE)
|
|
|
|
import fri_verify_reference as R # noqa: E402
|
|
|
|
RESULTS = os.path.normpath(os.path.join(HERE, "..", "results", "kat-results-fri-verify.json"))
|
|
GROUND_TRUTH = os.path.join(HERE, "fri_ground_truth.json")
|
|
|
|
_pass = 0
|
|
_fail = 0
|
|
_notes = []
|
|
|
|
|
|
def check(name, cond):
|
|
global _pass, _fail
|
|
if cond:
|
|
_pass += 1
|
|
else:
|
|
_fail += 1
|
|
print(f"FAIL {name}")
|
|
|
|
|
|
# ---- 1/2. conformance (accept genuine, reject tampered) + sanity -----------------------------------
|
|
def conformance():
|
|
gt = R.load_ground_truth()
|
|
check("sanity.perm_zeros", R.M.permute([0] * 16) == gt["perm_zeros"])
|
|
for b in range(28):
|
|
check(f"sanity.gen.{b}", R.F.two_adic_generator(b) == gt["two_adic_generators"][b])
|
|
for case in gt["cases"]:
|
|
check(f"accept.{case['name']}", R.verify_case(case))
|
|
check(f"reject.sibling.{case['name']}", not R.verify_case(case, "sibling"))
|
|
check(f"reject.proof.{case['name']}", not R.verify_case(case, "proof"))
|
|
check(f"reject.beta.{case['name']}", not R.verify_case(case, "beta"))
|
|
check(f"reject.final.{case['name']}", not R.verify_case(case, "final"))
|
|
_notes.append(f"CONFORMANCE: {len(gt['cases'])} FRI proofs from the pinned p3-fri 0.4.3-succinct "
|
|
f"prover accepted; 4 tamper variants each rejected (opening, MMCS proof, beta, final poly)")
|
|
|
|
|
|
# ---- 3. cross-language agreement (Python vs Node vs Java) -------------------------------------------
|
|
def canonicalize(v):
|
|
def ia(x):
|
|
return [int(e) for e in x]
|
|
|
|
def ia2(x):
|
|
return [ia(e) for e in x]
|
|
|
|
return {
|
|
"permZeros": ia(v["permZeros"]),
|
|
"twoAdicGenerators": ia(v["twoAdicGenerators"]),
|
|
"cases": [
|
|
{
|
|
"name": c["name"],
|
|
"logBlowup": int(c["logBlowup"]),
|
|
"logMaxHeight": int(c["logMaxHeight"]),
|
|
"numQueries": int(c["numQueries"]),
|
|
"folded": ia2(c["folded"]),
|
|
"finalPoly": ia(c["finalPoly"]),
|
|
"accept": bool(c["accept"]),
|
|
"rejectSibling": bool(c["rejectSibling"]),
|
|
"rejectProof": bool(c["rejectProof"]),
|
|
"rejectBeta": bool(c["rejectBeta"]),
|
|
"rejectFinal": bool(c["rejectFinal"]),
|
|
}
|
|
for c in v["cases"]
|
|
],
|
|
}
|
|
|
|
|
|
def cross_language():
|
|
py = canonicalize(R.shared_vectors())
|
|
# every Python-side flag must hold, and each query's folded value must equal the final poly
|
|
for c in py["cases"]:
|
|
check(f"py.accept.{c['name']}", c["accept"])
|
|
check(f"py.rejects.{c['name']}",
|
|
c["rejectSibling"] and c["rejectProof"] and c["rejectBeta"] and c["rejectFinal"])
|
|
check(f"py.folded_eq_final.{c['name']}", all(fe == c["finalPoly"] for fe in c["folded"]))
|
|
langs = {"python": py}
|
|
|
|
node = which("node")
|
|
if node:
|
|
try:
|
|
out = subprocess.run(
|
|
[node, os.path.join(HERE, "fri_verify_reference.mjs")],
|
|
capture_output=True, text=True, timeout=180, check=True,
|
|
).stdout.strip()
|
|
langs["node"] = canonicalize(json.loads(out))
|
|
except Exception as e: # noqa: BLE001
|
|
_notes.append(f"node cross-check unavailable: {e}")
|
|
else:
|
|
_notes.append("node not found on PATH; node cross-check skipped")
|
|
|
|
javac = which("javac")
|
|
java = which("java")
|
|
if javac and java:
|
|
try:
|
|
subprocess.run(
|
|
[javac, "-d", os.path.join(HERE, "out"),
|
|
os.path.join(HERE, "FriVerifySelfTest.java")],
|
|
capture_output=True, text=True, timeout=180, check=True,
|
|
)
|
|
out = subprocess.run(
|
|
[java, "-cp", os.path.join(HERE, "out"), "FriVerifySelfTest", "--emit", GROUND_TRUTH],
|
|
capture_output=True, text=True, timeout=120, check=True,
|
|
).stdout.strip()
|
|
langs["java"] = canonicalize(json.loads(out))
|
|
except Exception as e: # noqa: BLE001
|
|
_notes.append(f"java cross-check unavailable: {e}")
|
|
else:
|
|
_notes.append("javac/java not found on PATH; java cross-check skipped")
|
|
|
|
for name, data in langs.items():
|
|
if name == "python":
|
|
continue
|
|
check(f"crosslang.{name}.agree", data == py)
|
|
_notes.append("cross-language implementations compared: " + ", ".join(sorted(langs)))
|
|
return sorted(langs)
|
|
|
|
|
|
def main():
|
|
conformance()
|
|
langs = cross_language()
|
|
|
|
report = {
|
|
"component": "FRI low-degree test / query verification over BabyBear (port spec component (d))",
|
|
"precompile": "0x0000000000000000000000000000000000000ae8",
|
|
"scope": "port spec section 5; the FRI verifier's FOLD + OPENING relations (verify_query / "
|
|
"verify_challenges): arity-2 folding in F_{p^4}, per-layer MMCS openings against the "
|
|
"commit-phase roots, down to a single constant equal to the committed final polynomial.",
|
|
"validates": "CONFORMANCE: real FRI proofs emitted by the pinned Plonky3 p3-fri 0.4.3-succinct "
|
|
"PROVER (and accepted by its own verifier) are re-verified byte-for-byte by this "
|
|
"reference (accept), and four tamper variants are rejected (corrupted opened value, "
|
|
"corrupted MMCS sibling digest, wrong fold challenge beta, non-matching final poly); "
|
|
"Python/Node/Java produce byte-identical per-query folded values.",
|
|
"does_not_validate": "the SP1 recursion-AIR constraint evaluation (component (e)), which supplies "
|
|
"the reduced openings and is UN-PORTED. Within THIS FRI KAT the betas / query "
|
|
"indices are supplied as inputs; deriving them in-circuit is component (f) (the "
|
|
"duplex-sponge challenger), now CONFIRMED separately (test_challenger.py), whose "
|
|
"derived betas/indices close the loop into this verify_query.",
|
|
"top_level_verifier": "unchanged, still FAIL-CLOSED (returns EMPTY for every input). Even with the FRI "
|
|
"fold+opening (d) and the challenger (f) confirmed, "
|
|
"StarkConstraints.evaluateAtZeta=UNAVAILABLE (component (e)), so verify() never "
|
|
"reaches ACCEPT and computePrecompile returns EMPTY. ACCEPT is unreachable. DO NOT ACTIVATE.",
|
|
"confirmed_config": {
|
|
"folding_arity": 2,
|
|
"sibling_rule": "index_sibling = index ^ 1, index_pair = index >> 1 (p3-fri verifier.rs)",
|
|
"num_fold_rounds": "log_max_height - log_blowup (final poly is a single F_{p^4} CONSTANT)",
|
|
"log_max_height": "commit_phase_commits.len() + log_blowup",
|
|
"commit_phase_mmcs": "ExtensionMmcs<Val,Challenge,ValMmcs> over the CONFIRMED FieldMerkleTreeMmcs "
|
|
"(component (c)); a commit-phase leaf is a pair of F_{p^4} evals flattened to "
|
|
"8 BabyBear coords, hashed by the PaddingFreeSponge",
|
|
"coset_point": "x = two_adic_generator(log_max_height)^reverse_bits_len(index, log_max_height), "
|
|
"in F_{p^4}; the sibling point is -x (two_adic_generator(1))",
|
|
"fold_relation": "folded = e0 + (beta - x0) * (e1 - e0) / (x1 - x0) (linear interpolation through "
|
|
"beta), plus reduced_openings[log_folded_height+1] injected before each fold",
|
|
"final_poly_check": "every query's folded constant must equal proof.final_poly",
|
|
},
|
|
"confirmed_by_kat": [
|
|
"CONFIRMED arity-2 fold (sibling=index^1, index_pair=index>>1) vs p3-fri verifier.rs",
|
|
"CONFIRMED num_fold_rounds = log_max_height - log_blowup; final poly is a single F_{p^4} constant",
|
|
"CONFIRMED reverse_bits_len index-to-coset-point mapping (x = g^rev(index))",
|
|
"CONFIRMED two_adic_generator(bits) matches Plonky3 (the fold coset points are correct)",
|
|
"CONFIRMED the F_{p^4} non-residue W = 11 is Plonky3's (the EF fold arithmetic reproduces the fold)",
|
|
"CONFIRMED the ExtensionMmcs flatten (each F_{p^4} eval -> 4 base coords, pair -> 8) + base MMCS open",
|
|
],
|
|
"cross_language": langs,
|
|
"conformance": {
|
|
"status": "CONFIRMED (real known-answer test PASSED: accept genuine + reject tampered)",
|
|
"method": "pq-stark/fri-extractor (a Rust binary depending on the pinned crates; lockfile "
|
|
"checksums matched) ran p3_fri::prover::prove over known low-degree codewords with the "
|
|
"seed_from_u64(1) Poseidon2, then p3_fri::verifier::{verify_shape_and_sample_challenges,"
|
|
"verify_challenges} to confirm the library accepts; its output is fri_ground_truth.json",
|
|
"cases": [c["name"] for c in R.load_ground_truth()["cases"]],
|
|
},
|
|
"pinned_conformance_target": {
|
|
"revision": "Succinct Plonky3 fork, crates.io version 0.4.3-succinct",
|
|
"p3_fri_checksum": "5cbc4965ee488f3247867b7ec4bb005b8afa72cb0d461a4dcb1387ecab6426d5",
|
|
"p3_challenger_checksum": "b6a908924d43e4cfb93fb41c8346cac211b70314385a9037e9241f5b7f3eaf77",
|
|
"p3_dft_checksum": "be6408b10a2c27eb13a7d5580c546c2179a8dc7dbc10a990657311891f9b41c0",
|
|
"p3_commit_checksum": "50acacc7219fce6c01db938f82c1b21b5e7133990b7fff861f91534aeb569419",
|
|
"found_in": "aerenew/zk-circuits/*/Cargo.lock and aerenew/rollup-evm-validity/*/Cargo.lock",
|
|
},
|
|
"flags": [
|
|
"[VERIFY]->CONFIRMED here: arity-2 fold, num_fold_rounds, reverse-bits mapping, "
|
|
"two_adic_generator, W=11 (all exercised by the accept-KAT over the pinned p3-fri proof)",
|
|
"[MEASURE] conformance against a REAL exported SP1 v6.1.0 inner proof's FRI section (needs the "
|
|
"exported proof + the AIR reduced-openings, component (e))",
|
|
"component (f) transcript binding is now CONFIRMED (Challenger.spongePorted=true; the derived "
|
|
"betas/indices close the loop into this verify_query, see test_challenger.py). The top level "
|
|
"stays fail-closed on the AIR (component (e), StarkConstraints=UNAVAILABLE)",
|
|
],
|
|
"notes": _notes,
|
|
"passed": _pass,
|
|
"failed": _fail,
|
|
"total": _pass + _fail,
|
|
}
|
|
os.makedirs(os.path.dirname(RESULTS), exist_ok=True)
|
|
with open(RESULTS, "w") as f:
|
|
json.dump(report, f, indent=2)
|
|
|
|
print("\n=== FRI verifier (low-degree test) KAT ===")
|
|
print(f"cross-language: {', '.join(langs)}")
|
|
for nnote in _notes:
|
|
print(f"note: {nnote}")
|
|
print(f"PASS={_pass} FAIL={_fail} TOTAL={_pass + _fail}")
|
|
print(f"results -> {RESULTS}")
|
|
if _fail != 0:
|
|
print("FRI_VERIFY_KAT_FAILED")
|
|
sys.exit(1)
|
|
print("CONFORMANCE to Plonky3 FRI verify: CONFIRMED (real KAT PASSED vs p3-fri 0.4.3-succinct; "
|
|
"accept genuine + reject tampered). Top level stays fail-closed on the AIR (component (e)).")
|
|
print("FRI_VERIFY_CONFORMANCE_OK")
|
|
|
|
|
|
if __name__ == "__main__":
|
|
main()
|