aere-research/pq-stark/test_mmcs_babybear.py
Aere Network 4a0b48588c 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:02:30 +03:00

291 lines
15 KiB
Python

#!/usr/bin/env python3
# Test harness for the MMCS (Mixed Matrix Commitment Scheme) sub-component (port spec section 4,
# component (c)). Runs:
# 1. self-consistency: commit to each matrix batch, open EVERY valid leaf index, and confirm the
# authentication path recomputes the committed root; confirm a tampered proof / opening fails,
# 2. structural invariants: digest = 8 field elements; proof length = log2_ceil(max_height);
# openings are the rows at the reduced index in original matrix order,
# 3. cross-language agreement: Python vs Node vs Java produce byte-identical roots, openings, proofs,
# and primitive hash/compress outputs on a shared case set (three independent implementations),
# 4. CONFORMANCE: the root, openings, and proof reproduce real known-answer vectors emitted by
# executing the pinned p3-merkle-tree / p3-symmetric / p3-commit 0.4.3-succinct crates (via the
# ground-truth extractor), and verify_batch accepts the emitted openings and rejects tampered ones.
# Writes ../results/kat-results-mmcs-babybear.json and exits non-zero on any failure.
#
# ============================ HONEST SCOPE (CONFIRMED 2026-07-19) ============================
# This validates the MMCS construction LOGIC AND its conformance to Plonky3. The construction is the
# exact SP1 inner config (PaddingFreeSponge<Perm,16,8,8> hasher, TruncatedPermutation<Perm,2,8,16>
# compressor, FieldMerkleTreeMmcs<...,8>), verbatim from p3-merkle-tree's own mmcs.rs tests, over the
# CONFIRMED Poseidon2-BabyBear permutation. The "two wrong copies agree" trap is closed: the roots /
# openings / proofs reproduce real vectors extracted from the exact pinned crates (checksums matched),
# and the extractor's permute([0;16]) equals the confirmed Poseidon2 "zeros" vector, proving it uses
# the same permutation this reference does.
# What is still NOT validated: the FULL STARK verifier. The duplex-sponge challenger (f), the FRI
# folding/consistency arithmetic (d), and the SP1 recursion-AIR (e) are un-ported, so the top-level
# 0x0AE8 precompile stays fail-closed (returns EMPTY for every input) regardless of this component.
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 mmcs_babybear_reference as R # noqa: E402
RESULTS = os.path.normpath(os.path.join(HERE, "..", "results", "kat-results-mmcs-babybear.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. self-consistency + structural invariants -------------------------------------------------
def self_consistency():
for case in R.CONFORMANCE_CASES:
mats = R._case_matrices(case)
dims = R._case_dims(case)
root, pdata = R.commit(mats)
max_height = max(m.height for m in mats)
log_max = R._log2_ceil(max_height)
# open EVERY valid leaf index; the path must recompute the root
for q in range(max_height):
openings, proof = R.open_batch(q, pdata)
check(f"self.{case['name']}.digest8", all(len(d) == 8 for d in proof))
check(f"self.{case['name']}.prooflen", len(proof) == log_max)
check(f"self.{case['name']}.openrows",
all(len(o) == m.width for o, m in zip(openings, mats)))
check(f"self.{case['name']}.verify.{q}", R.verify_batch(root, dims, q, openings, proof))
# tamper the opening -> must fail
bad = [list(o) for o in openings]
bad[0] = list(bad[0])
bad[0][0] = (bad[0][0] + 1) % R.P
check(f"self.{case['name']}.tamper_open.{q}",
not R.verify_batch(root, dims, q, bad, proof))
# tamper a proof sibling -> must fail
badpf = [list(d) for d in proof]
badpf[0] = list(badpf[0])
badpf[0][0] = (badpf[0][0] + 1) % R.P
check(f"self.{case['name']}.tamper_proof.{q}",
not R.verify_batch(root, dims, q, openings, badpf))
# a wrong root must fail
wrong_root = list(root)
wrong_root[0] = (wrong_root[0] + 1) % R.P
op0, pf0 = R.open_batch(0, pdata)
check(f"self.{case['name']}.wrong_root", not R.verify_batch(wrong_root, dims, 0, op0, pf0))
_notes.append("self-consistency: every valid leaf opens to a path that recomputes the root; "
"tampered openings / proof siblings / roots all fail (all 6 cases)")
# ---- 4. CONFORMANCE: reproduce the pinned-library known-answer vectors ------------------------------
def conformance():
passed, total = R.conformance_kats()
check("conformance.perm_zeros", R.permute([0] * 16) == R.PERM_ZEROS)
for name, expected in R.PRIM_KATS.items():
if name == 'hash_item_5':
got = R.hash_item(5)
elif name == 'hash_slice_2':
got = R.hash_slice([1, 2])
elif name == 'hash_slice_3':
got = R.hash_slice([1, 2, 3])
elif name == 'hash_slice_8':
got = R.hash_slice(list(range(1, 9)))
elif name == 'hash_slice_9':
got = R.hash_slice(list(range(1, 10)))
elif name == 'compress_h2_h3':
got = R.compress2to1(R.hash_slice([1, 2]), R.hash_slice([1, 2, 3]))
check(f"conformance.prim.{name}", got == expected)
for case in R.CONFORMANCE_CASES:
mats = R._case_matrices(case)
root, pdata = R.commit(mats)
openings, proof = R.open_batch(case["index"], pdata)
dims = R._case_dims(case)
check(f"conformance.{case['name']}.root", root == case["root"])
check(f"conformance.{case['name']}.openings", openings == case["openings"])
check(f"conformance.{case['name']}.proof", proof == case["proof"])
check(f"conformance.{case['name']}.verify",
R.verify_batch(case["root"], dims, case["index"], case["openings"], case["proof"]))
_notes.append(f"CONFORMANCE: {passed}/{total} known-answer checks (perm sanity + 6 primitive KATs "
f"+ 6 MMCS cases: root/openings/proof/verify_accept/tamper_reject) reproduced exactly "
f"from p3-merkle-tree / p3-symmetric / p3-commit 0.4.3-succinct")
# ---- 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 {
"constants": {k: int(x) for k, x in v["constants"].items()},
"permZeros": ia(v["permZeros"]),
"prim": {k: ia(x) for k, x in v["prim"].items()},
"cases": [
{
"name": c["name"],
"index": int(c["index"]),
"root": ia(c["root"]),
"openings": ia2(c["openings"]),
"proof": ia2(c["proof"]),
"rootMatch": bool(c["rootMatch"]),
"openingsMatch": bool(c["openingsMatch"]),
"proofMatch": bool(c["proofMatch"]),
"verifyOk": bool(c["verifyOk"]),
}
for c in v["cases"]
],
}
def cross_language():
py = canonicalize(R.shared_vectors())
# every Python-side conformance flag must be true (self-check before comparing languages)
check("py.all.rootMatch", all(c["rootMatch"] for c in py["cases"]))
check("py.all.proofMatch", all(c["proofMatch"] for c in py["cases"]))
check("py.all.verifyOk", all(c["verifyOk"] for c in py["cases"]))
langs = {"python": py}
node = which("node")
if node:
try:
out = subprocess.run(
[node, os.path.join(HERE, "mmcs_babybear_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, "MmcsBabyBearSelfTest.java")],
capture_output=True, text=True, timeout=180, check=True,
)
out = subprocess.run(
[java, "-cp", os.path.join(HERE, "out"), "MmcsBabyBearSelfTest", "--emit"],
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():
self_consistency()
conformance()
langs = cross_language()
report = {
"component": "Mixed Matrix Commitment Scheme (MMCS) over BabyBear (port spec component (c))",
"precompile": "0x0000000000000000000000000000000000000ae8",
"scope": "port spec section 4; the FieldMerkleTreeMmcs (Merkle-tree vector commitment) that "
"FRI (d) and the trace commitment are built on. Exact SP1 inner config: "
"PaddingFreeSponge<Perm,16,8,8> hasher, TruncatedPermutation<Perm,2,8,16> compressor, "
"FieldMerkleTreeMmcs<Packing,Packing,MyHash,MyCompress,8> (digest = 8 BabyBear elems).",
"validates": "SELF-CONSISTENCY + CONFORMANCE: every valid leaf opens to an authentication path "
"that recomputes the committed root; tampered openings / proof siblings / roots "
"fail; Python/Node/Java produce byte-identical roots/openings/proofs; AND the "
"root/openings/proof reproduce real known-answer vectors extracted from the pinned "
"p3-merkle-tree / p3-symmetric / p3-commit 0.4.3-succinct crates (the 'two wrong "
"copies agree' trap is closed).",
"does_not_validate": "the FULL STARK verifier. Only component (c) (the MMCS) is confirmed. The "
"duplex-sponge challenger (f), FRI folding/consistency (d), and the SP1 "
"recursion-AIR (e) are un-ported; conformance against a real exported SP1 "
"commitment root is a further [MEASURE] step (needs an exported proof).",
"top_level_verifier": "unchanged, still fail-closed (returns EMPTY for every input). Mmcs.available "
"is now true (the commitment scheme is confirmed), but the challenger/FRI/AIR "
"are still un-ported (Challenger.spongePorted=false, StarkConstraints=UNAVAILABLE), "
"so the top level still returns EMPTY and ACCEPT is unreachable.",
"construction": {
"hasher": "PaddingFreeSponge<Perm, WIDTH=16, RATE=8, OUT=8> (overwrite-mode, padding-free)",
"compressor": "TruncatedPermutation<Perm, N=2, CHUNK=8, WIDTH=16> (permute(l||r)[0:8])",
"digest_elems": 8,
"leaf_hash": "hash concatenated rows of all matrices at the current (padded) height",
"mixed_height": "tallest-first; pad each layer to a power of two with the zero digest; inject "
"shorter matrices' hashed rows via compress([node, rows_digest]) at the layer "
"whose padded length equals their next_power_of_two height",
},
"cross_language": langs,
"conformance": {
"status": "CONFIRMED (real known-answer test PASSED)",
"method": "the exact pinned crates were executed via cargo (lockfile checksums matched) to "
"commit to known matrix batches and emit roots + open_batch openings/proofs; this "
"reference reproduces every value exactly and its verify_batch accepts them",
"cases": [c["name"] for c in R.CONFORMANCE_CASES],
},
"pinned_conformance_target": {
"revision": "Succinct Plonky3 fork, crates.io version 0.4.3-succinct",
"p3_merkle_tree_checksum": "d5703d9229d52a8c09970e4d722c3a8b4d37e688c306c3a1c03b872efcd204e6",
"p3_symmetric_checksum": "9047ce85c086a9b3f118e10078f10636f7bfeed5da871a04da0b61400af8793a",
"p3_commit_checksum": "50acacc7219fce6c01db938f82c1b21b5e7133990b7fff861f91534aeb569419",
"p3_matrix_checksum": "75c3f150ceb90e09539413bf481e618d05ee19210b4e467d2902eb82d2e15281",
"found_in": "aerenew/zk-circuits/*/Cargo.lock and aerenew/rollup-evm-validity/*/Cargo.lock",
},
"confirmed": [
"CONFIRMED SP1 inner config: PaddingFreeSponge<_,16,8,8> / TruncatedPermutation<_,2,8,16> / "
"FieldMerkleTreeMmcs<...,8> (verbatim from p3-merkle-tree mmcs.rs tests)",
"CONFIRMED tree build: tallest-first, power-of-two padding with zero digest, mixed-height "
"injection (compress_and_inject) matches p3-merkle-tree merkle_tree.rs",
"CONFIRMED verify_batch: group-by-padded-height, index-parity ordering, inject at matching "
"layer, matches p3-merkle-tree mmcs.rs",
"CONFORMANCE KAT PASSED: 6 MMCS cases (single power-of-two, single non-power-of-two, column "
"vector, and 3 mixed-height batches incl. a default-zero-digest sibling) reproduced exactly",
],
"flags": [
"[MEASURE] conformance against a real exported SP1 v6.1.0 commitment root (the trace / FRI "
"matrices from an actual proof) is a further step; it needs an exported proof + the challenger",
],
"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=== MMCS-BabyBear (FieldMerkleTreeMmcs) 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}")
print("CONFORMANCE to Plonky3 MMCS: CONFIRMED (real KAT PASSED vs p3-merkle-tree / p3-symmetric / "
"p3-commit 0.4.3-succinct; checksums matched)")
if _fail != 0:
print("MMCS_BABYBEAR_KAT_FAILED")
sys.exit(1)
print("MMCS_BABYBEAR_CONFORMANCE_OK")
if __name__ == "__main__":
main()