mirror of
https://github.com/luxfi/chains.git
synced 2026-09-24 00:26:00 +00:00
H1 — shielded-tx ProofVerifier was classical-only (groth16/plonk) and fail-closed only via all-zero dummy VKs; real bn254 VKs would re-enable a CRQC-forgeable shield/unshield mint/steal path. Add ZConfig.StrictPQ and a single gate refuseClassicalUnderStrictPQ(proofType) called at the top of VerifyTransactionProof AND per-tx in the GPU batch path (which verifies groth16 inline, bypassing VerifyTransactionProof). Under strict-PQ only "stark" is accepted — wired to precompile/starkfri (cSHAKE256/Goldilocks FRI, fail-closed until the prover binds), public inputs bound to the tx's nullifiers+commitments. loadVerifyingKeys now ERRORS on a non-dummy bn254 VK under strict-PQ (explicit fail-closed, not implicit dummy-keys). The remaining prover work (p3q_prove C ABI + shielded/ML-DSA AIR) is tracked as a code comment; shielded value is effectively disabled on strict-PQ chains until it lands — the correct no-classical-fallback posture. H2 — Groth16/PLONK precompiles (0x80/0x81) were registered unconditionally and Run([]byte) has no AccessibleState to call RefuseUnderStrictPQ. RegisterZKPrecompiles(registry, strictPQ) now omits Groth16/PLONK on strict-PQ chains (registering STARK 0x82 + fail-closed Halo2/Nova stubs only) so 0x80/0x81 fail closed by absence; non-strict chains keep them as an optional building block (kept, not deleted). CrossChainZKVerifier gains StrictPQ that refuses routing Groth16/PLONK while still routing STARK. H4 — verifyPLONK computed a self-cancelling pairing, discarded the result, ignored public inputs, and returned valid for ANY >=544-byte blob (total bypass). Now fails closed (errPLONKVerifierIncomplete) after structural parsing — NEVER universal-accepts. Groth16/bn254/PLONK remain present-but-gated; STARK/FRI (P3Q) is the only accepted proof path on strict-PQ chains. Tests: strict-PQ refuses groth16/plonk/bulletproofs (direct + GPU-batch); real-VK-load errors; STARK fails-closed unbound and accepts bound with nullifier+commitment-bound public inputs; non-strict path unchanged; strict registry omits classical + keeps STARK; cross-chain strict refuses classical; PLONK never universal-accepts. H-02 regression updated to the new wired-STARK fail-closed behavior.