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.
123 lines
7.8 KiB
Python
123 lines
7.8 KiB
Python
#!/usr/bin/env python3
|
|
# Conformance + cross-language harness for the Fiat-Shamir DUPLEX CHALLENGER (component (f)) of the PQ
|
|
# STARK-verify precompile 0x0AE8. It:
|
|
# 1. runs the Python challenger conformance KAT against the real ground truth emitted by the pinned
|
|
# p3-challenger / p3-fri 0.4.3-succinct crates (challenger-extractor -> challenger_ground_truth.json);
|
|
# 2. asserts Python, Node, and standalone Java produce byte-identical shared vectors (three
|
|
# independent implementations of observe / sample / sample_bits / check_witness);
|
|
# 3. closes the loop END TO END: derive the FRI betas + query indices FROM THE TRANSCRIPT, then feed
|
|
# them into the CONFIRMED FRI verify_query (component (d), fri_verify_reference) and confirm it
|
|
# ACCEPTS the real FRI ground-truth proof and REJECTS a tampered derived beta. This is
|
|
# transcript -> betas/indices -> FRI verify, the loop the FRI KAT left open.
|
|
#
|
|
# It writes ../results/kat-results-challenger.json. The top-level 0x0AE8 stays FAIL-CLOSED regardless
|
|
# (component (e), the AIR, is un-ported); this harness confirms component (f) only.
|
|
|
|
import json
|
|
import os
|
|
import subprocess
|
|
import sys
|
|
|
|
HERE = os.path.dirname(os.path.abspath(__file__))
|
|
RESULTS = os.path.join(HERE, "..", "results", "kat-results-challenger.json")
|
|
sys.path.insert(0, HERE)
|
|
|
|
import challenger_reference as C
|
|
import fri_verify_reference as FV # component (d), CONFIRMED
|
|
|
|
passed = 0
|
|
failed = 0
|
|
notes = []
|
|
|
|
|
|
def check(name, cond):
|
|
global passed, failed
|
|
if cond:
|
|
passed += 1
|
|
else:
|
|
failed += 1
|
|
notes.append("FAIL: " + name)
|
|
print(("PASS " if cond else "FAIL ") + name)
|
|
|
|
|
|
# ---- 1) Python conformance KAT ----
|
|
p, t, det = C.conformance_kats()
|
|
for d in det:
|
|
check("py." + d["check"], d["pass"])
|
|
|
|
# ---- 2) cross-language byte-identity ----
|
|
py = C.shared_vectors()
|
|
node = json.loads(subprocess.check_output(["node", os.path.join(HERE, "challenger_reference.mjs")]))
|
|
java_out = subprocess.check_output(
|
|
["java", "-cp", os.path.join(HERE, "out"), "ChallengerSelfTest", "--emit",
|
|
os.path.join(HERE, "challenger_ground_truth.json")],
|
|
cwd=HERE)
|
|
java = json.loads(java_out)
|
|
|
|
|
|
def norm(v):
|
|
return json.loads(json.dumps(v))
|
|
|
|
|
|
check("xlang.permZeros.py==node", norm(py["permZeros"]) == norm(node["permZeros"]))
|
|
check("xlang.permZeros.py==java", norm(py["permZeros"]) == norm(java["permZeros"]))
|
|
check("xlang.duplex.py==node", norm(py["duplex"]) == norm(node["duplex"]))
|
|
check("xlang.duplex.py==java", norm(py["duplex"]) == norm(java["duplex"]))
|
|
check("xlang.fri.py==node", norm(py["fri"]) == norm(node["fri"]))
|
|
check("xlang.fri.py==java", norm(py["fri"]) == norm(java["fri"]))
|
|
|
|
# ---- 3) end-to-end loop closure: transcript -> betas/indices -> CONFIRMED FRI verify_query ----
|
|
with open(os.path.join(HERE, "challenger_ground_truth.json")) as fp:
|
|
ch_gt = json.load(fp)
|
|
with open(os.path.join(HERE, "fri_ground_truth.json")) as fp:
|
|
fri_gt = json.load(fp)
|
|
fri_by_name = {c["name"]: c for c in fri_gt["cases"]}
|
|
|
|
for tc in ch_gt["fri_transcript"]:
|
|
name = tc["name"]
|
|
betas, indices, pow_accept = C.derive_fri_challenges(
|
|
tc["commit_phase_commits"], tc["final_poly"], tc["pow_witness"],
|
|
tc["pow_bits"], tc["log_blowup"], tc["num_queries"])
|
|
fc = fri_by_name[name]
|
|
# Build a FRI case that uses the TRANSCRIPT-DERIVED betas (indices already match fc queries).
|
|
check("e2e[%s].derived_indices==fri_gt" % name, indices == [q["index"] for q in fc["queries"]])
|
|
synthetic = {
|
|
"log_blowup": tc["log_blowup"],
|
|
"log_max_height": len(tc["commit_phase_commits"]) + tc["log_blowup"],
|
|
"commit_phase_commits": tc["commit_phase_commits"],
|
|
"final_poly": fc["final_poly"],
|
|
"betas": betas, # <-- derived in-circuit from the transcript
|
|
"num_queries": tc["num_queries"],
|
|
"queries": fc["queries"], # real openings from the confirmed FRI ground truth
|
|
}
|
|
# transcript -> derived betas/indices -> CONFIRMED FRI verify_query must ACCEPT the honest proof.
|
|
check("e2e[%s].fri_verify_accepts_with_derived_betas" % name, FV.verify_case(synthetic) is True)
|
|
# and a tampered derived beta must be REJECTED (soundness of the closed loop).
|
|
check("e2e[%s].fri_verify_rejects_tampered_beta" % name, FV.verify_case(synthetic, "beta") is False)
|
|
|
|
# ---- write results ----
|
|
total = passed + failed
|
|
result = {
|
|
"component": "Fiat-Shamir transcript / Poseidon2 DuplexChallenger (port spec component (f))",
|
|
"precompile": "0x0000000000000000000000000000000000000ae8",
|
|
"scope": "port spec section 7; the duplex-sponge challenger DuplexChallenger<BabyBear, Perm, WIDTH=16, RATE=8> and the GrindingChallenger check_witness: observe (overwrite-mode absorb), sample (squeeze, pop from the end of the rate buffer), sample_bits (low-bits query-index reduction), check_witness (observe witness then sample_bits==0). Wired behind the still-fail-closed top level.",
|
|
"validates": "CONFORMANCE: ground truth emitted by executing the pinned Plonky3 p3-challenger 0.4.3-succinct DuplexChallenger + GrindingChallenger (and the p3-fri verify_shape_and_sample_challenges transcript ORDER). (1) a fully-scripted observe/sample transcript reproduces every sampled base + F_{p^4} ext value, the full 16-lane sponge state, and a check_witness accept/reject table byte-for-byte; (2) the FRI betas + query indices + grinding acceptance are DERIVED from the transcript (commit_phase_commits + final_poly + pow_witness) and match the pinned p3-fri challenger AND the confirmed FRI ground truth; (3) END TO END: those derived betas/indices, fed into the CONFIRMED FRI verify_query (component (d)), accept the real FRI proof and reject a tampered beta. Python/Node/standalone-Java are byte-identical.",
|
|
"does_not_validate": "the SP1 recursion-AIR constraint evaluation (component (e)): the reduced openings, DEEP zeta/alpha challenges, quotient consistency, and vk binding. That is un-ported (StarkConstraints.evaluateAtZeta = UNAVAILABLE). A real exported SP1 v6.1.0 proof's transcript (vkey digest, trace/quotient commitments, opened values order) is still [MEASURE].",
|
|
"top_level_verifier": "unchanged, still FAIL-CLOSED (returns EMPTY for every input). Even with component (f) confirmed and Challenger.spongePorted flipped true, StarkConstraints.evaluateAtZeta returns UNAVAILABLE (component (e) un-ported), so verify() returns UNAVAILABLE before any query loop and computePrecompile returns EMPTY. ACCEPT is unreachable. DO NOT ACTIVATE.",
|
|
"confirmed_config": "DuplexChallenger<BabyBear, Poseidon2<BabyBear,...,16,7>, WIDTH=16, RATE=8>; Witness=BabyBear; Challenge=BinomialExtensionField<BabyBear,4>; sample pops from the END of the rate buffer (Vec::pop); sample_bits masks the LOW `bits` of as_canonical_u64; check_witness = observe(witness) then sample_bits(bits)==0.",
|
|
"pinned_conformance_target": "p3-challenger 0.4.3-succinct (duplex_challenger.rs, grinding_challenger.rs), transcript order p3-fri 0.4.3-succinct verifier.rs (verify_shape_and_sample_challenges), sponge = confirmed Poseidon2-BabyBear (component (b)); byte-identical to the repo Cargo.lock. Extractor: pq-stark/challenger-extractor -> pq-stark/challenger_ground_truth.json.",
|
|
"cross_language": "Python (challenger_reference.py), Node (challenger_reference.mjs), standalone Java (ChallengerSelfTest.java) emit byte-identical shared vectors.",
|
|
"flags": {"Challenger.spongePorted": True, "note": "flipped true: component (f) confirmed. StarkConstraints.evaluateAtZeta stays UNAVAILABLE (component (e)), so the top level stays fail-closed and ACCEPT is unreachable."},
|
|
"notes": notes,
|
|
"passed": passed,
|
|
"failed": failed,
|
|
"total": total,
|
|
}
|
|
os.makedirs(os.path.dirname(RESULTS), exist_ok=True)
|
|
with open(RESULTS, "w") as fp:
|
|
json.dump(result, fp, indent=1)
|
|
|
|
print("\nchallenger conformance: PASS=%d FAIL=%d TOTAL=%d" % (passed, failed, total))
|
|
print("results -> %s" % os.path.normpath(RESULTS))
|
|
sys.exit(0 if failed == 0 else 1)
|