diff --git a/conformance/.clusterfuzzlite/fuzz_receipt.py b/conformance/.clusterfuzzlite/fuzz_receipt.py index 2e9573ce..5040eecd 100755 --- a/conformance/.clusterfuzzlite/fuzz_receipt.py +++ b/conformance/.clusterfuzzlite/fuzz_receipt.py @@ -25,6 +25,8 @@ from trace_tests.inclusion import ( InclusionError, canonical_claim_bytes, + parse_entry, + parse_proof, parse_receipt, verify_inclusion, ) @@ -121,8 +123,12 @@ def TestOneInput(data: bytes) -> None: findings = tr_anc.check(claim, receipt=receipt, entry=_ENTRY) if any(f.code == "TR-ANC-002" and f.passed() for f in findings): assert claim is _CLAIMS[_TARGET], f"inclusion proven for the wrong claim: {receipt!r}" - root = parse_receipt(receipt)[3] + index, path, _, _ = parse_proof(receipt) + root, count, _, _ = parse_entry(_ENTRY) assert root == _ROOT, f"inclusion proven under another root: {receipt!r}" + assert verify_inclusion(claim, index, path, count, root), ( + f"inclusion not reproduced against the supplied entry: {receipt!r}" + ) def main() -> None: diff --git a/conformance/tests/test_fuzz_receipt.py b/conformance/tests/test_fuzz_receipt.py new file mode 100644 index 00000000..be010b29 --- /dev/null +++ b/conformance/tests/test_fuzz_receipt.py @@ -0,0 +1,58 @@ +"""Deterministic receipt-harness regressions without requiring Atheris.""" + +import contextlib +import json +import runpy +import sys +import types +from pathlib import Path + +import pytest + + +@pytest.fixture +def harness(monkeypatch): + # Exercise the real fuzz callback's raw-JSON branch; only instrumentation + # and byte selection are replaced, not the parser, verifier, or assertions. + class DataProvider: + def __init__(self, data): + self.data = data + + def ConsumeIntInRange(self, lower, upper): + return 3 # The genuine fixture's target claim. + + def ConsumeBool(self): + return False + + def remaining_bytes(self): + return len(self.data) + + def ConsumeBytes(self, length): + return self.data[:length] + + stub = types.ModuleType("atheris") + stub.instrument_imports = contextlib.nullcontext + stub.FuzzedDataProvider = DataProvider + monkeypatch.setitem(sys.modules, "atheris", stub) + path = Path(__file__).parents[1] / ".clusterfuzzlite" / "fuzz_receipt.py" + return runpy.run_path(str(path)) + + +@pytest.mark.parametrize( + "omitted", + [(), ("leaf_count",), ("merkle_root",), ("leaf_count", "merkle_root")], +) +def test_pass_oracle_accepts_entry_backed_proofs(harness, omitted): + receipt = {k: v for k, v in harness["_RECEIPT"].items() if k not in omitted} + claim = harness["_CLAIMS"][harness["_TARGET"]] + findings = harness["tr_anc"].check(claim, receipt=receipt, entry=harness["_ENTRY"]) + assert any(f.code == "TR-ANC-002" and f.passed() for f in findings) + harness["TestOneInput"](json.dumps(receipt).encode()) + + +def test_pass_oracle_independently_replays_proof(harness, monkeypatch): + receipt = {"leaf_index": harness["_TARGET"], "audit_path": []} + fake_pass = types.SimpleNamespace(code="TR-ANC-002", passed=lambda: True) + monkeypatch.setattr(harness["tr_anc"], "check", lambda *a, **kw: [fake_pass]) + with pytest.raises(AssertionError, match="not reproduced against the supplied entry"): + harness["TestOneInput"](json.dumps(receipt).encode())