#!/usr/bin/env python3 """Clean-room verifier for the CAIN-42 Evolution 12 perception/evidence proof bundle. IMPORTS NO CAIN-42 CODE. Standard library plus `cryptography` (Ed25519). It checks every file against MANIFEST.json, the P1-P20 invariant matrix, the 30+-scenario bench (all contained), both signatures, the master module digests, the published schemas, and that no key material is present in the examples. It proves the bundle is intact and self-consistent. It does NOT prove the evidence governance is sound, that semantic truth is established, or that hardware attestation exists. Usage: python3 verify_e12.py """ from __future__ import annotations import base64 import hashlib import json import sys from pathlib import Path from cryptography.exceptions import InvalidSignature from cryptography.hazmat.primitives.asymmetric import ed25519 REQUIRED_SCHEMAS = ("ObservationEnvelope", "SourceAttestation", "EvidenceObject", "EvidenceIntegrity", "ModelAssertion", "IntentEvidenceBinding") FORBIDDEN = ("private_key", "private key", "-----begin", "secret_key", "password") def canon(o) -> bytes: return json.dumps(o, sort_keys=True, separators=(",", ":"), ensure_ascii=True).encode() def digest(domain: str, fields: dict) -> str: return hashlib.sha256(canon({"domain": domain, **fields})).hexdigest() def verify(pub_b64: str, sig_b64: str, domain: str, fields: dict) -> bool: try: ed25519.Ed25519PublicKey.from_public_bytes(base64.b64decode(pub_b64)).verify( base64.b64decode(sig_b64), digest(domain, fields).encode()) return True except (InvalidSignature, ValueError, TypeError): return False def main() -> int: if len(sys.argv) < 2: print("usage: python3 verify_e12.py ") return 2 d = Path(sys.argv[1]) problems: list = [] checks = 0 manifest = json.loads((d / "MANIFEST.json").read_text()) for name, want in manifest["files"].items(): checks += 1 if hashlib.sha256((d / name).read_bytes()).hexdigest() != want: problems.append(f"file {name}: sha256 mismatch") proof = json.loads((d / "CAIN42_EVOLUTION12_PROOF.json").read_text()) master = json.loads((d / "CAIN42_EVOLUTION12_MASTER_PROOF.json").read_text()) inv = proof.get("invariants") or {} ids = {x.get("id") for x in inv.get("checks", [])} checks += 1 if ids != {f"P{i}" for i in range(1, 21)}: problems.append(f"invariant ids {sorted(ids)} != P1..P20") for x in inv.get("checks", []): if not x.get("holds"): problems.append(f"invariant {x.get('id')} does not hold") checks += 1 if inv.get("all_hold") is not True or inv.get("failed"): problems.append("invariant matrix all_hold is not true") bench = proof.get("attack_bench") or {} checks += 1 if not (bench.get("all_contained") is True and bench.get("contained") == bench.get("total") and bench.get("total", 0) >= 30): problems.append("evidence bench is not fully contained with at least 30 scenarios") body = {k: v for k, v in proof.items() if k not in ("signature_b64", "signer_public_key_b64")} checks += 1 if not verify(proof.get("signer_public_key_b64", ""), proof.get("signature_b64", ""), "CAIN42/E12-PROOF/v1", body): problems.append("proof signature does not verify") mbody = {k: v for k, v in master.items() if k not in ("signature_b64", "signer_public_key_b64")} checks += 1 if not verify(master.get("signer_public_key_b64", ""), master.get("signature_b64", ""), "CAIN42/E12-MASTER/v1", mbody): problems.append("master signature does not verify") checks += 1 if master.get("modules") != {k: v["sha256"] for k, v in (proof.get("modules") or {}).items()}: problems.append("master module digests do not match the proof") checks += 1 if set(proof.get("schemas") or {}) != set(REQUIRED_SCHEMAS): problems.append("published schemas are incomplete") checks += 1 if any(f in (d / "EVIDENCE_EXAMPLES.json").read_text().lower() for f in FORBIDDEN): problems.append("examples contain key material") print(json.dumps({"bundle": str(d), "checks": checks, "problems": problems, "result": "INTACT" if not problems else "FAILED"}, indent=2)) return 0 if not problems else 1 if __name__ == "__main__": raise SystemExit(main())