#!/usr/bin/env python3 """Clean-room verifier for the CAIN-42 E31 (Universal Proof-of-Governance) evidence bundle. Imports nothing from CAIN. Needs only `cryptography`. Written from the published formats: * canonical JSON: sorted keys, no whitespace, ASCII escapes, integers only (floats and non-ASCII refused) * domain digest: sha256(canonical({"domain": D, "body": body})); signature: Ed25519 over the hex digest text * E8 kernel evidence: sha256(canonical({"domain": D_E8, **entry_without_hash})) (flat form) * transparency log: RFC 6962 leaf/node hashing; inclusion verified per RFC 9162 section 2.1.3.2 It checks every example proof against the published trust anchors (never against keys inside a proof), recomputes the five enforcement layers itself, and must REJECT every proof in MALICIOUS_PROOFS.json. python3 verify_e31.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 D_PROOF = "CAIN42/E31-GOVERNANCE-PROOF/v1" D_ACTION = "CAIN42/E31-PROOF-CARRYING-ACTION/v1" D_FAILURE = "CAIN42/E31-FAILURE-PROOF/v1" D_LOG_HEAD = "CAIN42/E31-PROOF-LOG-HEAD/v1" D_WITNESS = "CAIN42/E31-WITNESS-STATEMENT/v1" D_CERT = "CAIN42/E31-GOVERNANCE-CERTIFICATE/v1" D_MANIFEST = "CAIN42/E31-GOVERNABILITY-MANIFEST/v1" D_COVERAGE = "CAIN42/E31-COVERAGE-PROOF/v1" D_UGR = "CAIN42/E31-UNIVERSAL-GOVERNANCE-RECEIPT/v1" D_POSTCONDITION = "CAIN42/E31-POSTCONDITION-OBSERVATION/v1" D_UAR = "CAIN42/E30-UNIVERSAL-ACTION-RECEIPT/v1" D_UMA = "CAIN42/E30-UNIVERSAL-MACHINE-ACTION/v1" D_E28 = "CAIN42/E28-GOVERNANCE-RECEIPT/v1" D_E25 = "CAIN42/E25-EXECUTION-RECEIPT/v1" D_E8 = "CAIN42/E8-KERNEL-EVIDENCE/v1" D_MASTER = "CAIN42/E31-MASTER/v1" ACTION_FIELDS = ("protocol", "operation", "destination", "parameters_digest", "amount", "tool", "identity", "capability", "model", "runtime", "delegation", "policy", "context", "authority", "timestamp", "nonce") LAYERS = ("DECISION", "AUTHORIZATION", "ENFORCEMENT", "EXECUTION", "OUTCOME") STATES = ("PROPOSED", "EVALUATED", "AUTHORIZED", "COMMITTED", "EXECUTED", "VERIFIED", "PARTIALLY_VERIFIED", "REVOKED", "EXPIRED", "SUPERSEDED", "FAILED_VERIFICATION", "UNKNOWN") FAILURE_CLASSES = ("AUTHORIZATION_DENIED", "AUTHORIZATION_EXPIRED", "AUTHORIZATION_REVOKED", "POLICY_CONFLICT", "INSUFFICIENT_AUTHORITY", "CAPABILITY_MISMATCH", "IDENTITY_FAILURE", "PROVENANCE_FAILURE", "STALE_CONTEXT", "STALE_TRAJECTORY", "ENFORCEMENT_UNAVAILABLE", "PROOF_INVALID", "POSTCONDITION_FAILURE", "VERIFIER_DISAGREEMENT", "UNKNOWN_STATE") MAX_TTL = 86_400_000 BENCH_TARGETS = {"proof_mutation": 100, "evidence_integrity": 100, "verifier_disagreement": 100, "replay_revocation": 100, "cross_domain": 100, "enforcement_binding": 100, "protocol_conformance": 100, "authority_laws": 100, "policy_portability": 100} class Bad(Exception): pass def _chk(o, path="$"): if isinstance(o, bool) or o is None or isinstance(o, int): return if isinstance(o, float): raise Bad(f"float at {path}") if isinstance(o, str): if not o.isascii(): raise Bad(f"non-ascii at {path}") return if isinstance(o, list): for i, v in enumerate(o): _chk(v, f"{path}[{i}]") return if isinstance(o, dict): for k, v in o.items(): if not isinstance(k, str) or not k.isascii(): raise Bad(f"key at {path}") _chk(v, f"{path}.{k}") return raise Bad(f"type at {path}") def cj(o) -> bytes: _chk(o) return json.dumps(o, sort_keys=True, separators=(",", ":"), ensure_ascii=True).encode() def dg(domain, body) -> str: return hashlib.sha256(cj({"domain": domain, "body": body})).hexdigest() def flat(domain, body) -> str: if "domain" in body: raise Bad("flat body carries its own domain") return hashlib.sha256(cj({"domain": domain, **body})).hexdigest() def sig_ok(pub, sig, domain, body) -> bool: try: ed25519.Ed25519PublicKey.from_public_bytes(base64.b64decode(pub)).verify(base64.b64decode(sig), dg(domain, body).encode()) return True except (InvalidSignature, ValueError, TypeError, Bad): return False def kid(pub) -> str: return hashlib.sha256(base64.b64decode(pub)).hexdigest()[:16] def leaf(b: bytes) -> bytes: return hashlib.sha256(b"\x00" + b).digest() def node(a: bytes, b: bytes) -> bytes: return hashlib.sha256(b"\x01" + a + b).digest() def mroot(ls): """RFC 6962 MTH over already-hashed leaves.""" if not ls: return hashlib.sha256(b"").digest() if len(ls) == 1: return ls[0] k = 1 while k * 2 < len(ls): k *= 2 return node(mroot(ls[:k]), mroot(ls[k:])) def incl_ok(leaf_hash: bytes, index: int, size: int, path, root: bytes) -> bool: """RFC 9162 2.1.3.2, written independently.""" if index >= size: return False fn, sn, r = index, size - 1, leaf_hash for p in path: if sn == 0: return False if fn % 2 == 1 or fn == sn: r = node(p, r) if fn % 2 == 0: while fn != 0 and fn % 2 == 0: fn //= 2 sn //= 2 else: r = node(r, p) fn //= 2 sn //= 2 return sn == 0 and r == root class C: def __init__(self): self.checks, self.passed, self.problems = 0, 0, [] def check(self, name, ok, detail=""): self.checks += 1 if ok: self.passed += 1 else: self.problems.append(f"{name}: {detail}"[:300]) def load(d: Path, n: str): return json.loads((d / n).read_text()) # ------------------------------------------------------------------------------------------------ proof checks def layers(att, an): out = {k: "UNKNOWN" for k in LAYERS} u, r28, r25, e8 = att.get("uar"), att.get("e28_receipt"), att.get("e25_receipt"), att.get("e8_entry") if u: out["DECISION"] = ("VERIFIED" if u["body"]["decision"] == "ALLOW" else "NOT_VERIFIED") if \ sig_ok(an["uar"], u["signature_b64"], D_UAR, u["body"]) else "FAILED" if r28: out["AUTHORIZATION"] = ("VERIFIED" if r28["body"]["authorization_result"] == "ALLOW" else "NOT_VERIFIED") \ if sig_ok(an["e28"], r28["signature_b64"], D_E28, r28["body"]) else "FAILED" if e8 is not None and r28: body = {k: v for k, v in e8.items() if k != "entry_hash"} ok = flat(D_E8, body) == e8["entry_hash"] and e8["entry_hash"] in r28["body"]["evidence_references"] out["ENFORCEMENT"] = ("VERIFIED" if e8["decision"] == "COMMITTED" else "NOT_VERIFIED") if ok else "FAILED" if r25: linked = e8 is None or e8["entry_hash"] in (r25["body"].get("kernel_evidence") or []) out["EXECUTION"] = ("VERIFIED" if r25["body"]["status"] == "EXECUTED" else "NOT_VERIFIED") if \ sig_ok(an["e25"], r25["signature_b64"], D_E25, r25["body"]) and linked else "FAILED" pc = att.get("postcondition") if pc: ok = pc["observer_pub"] in an.get("observers", []) and \ sig_ok(pc["observer_pub"], pc["signature_b64"], D_POSTCONDITION, pc["body"]) out["OUTCOME"] = {"MET": "VERIFIED", "NOT_MET": "NOT_VERIFIED"}.get(pc["body"]["result"], "UNKNOWN") \ if ok else "FAILED" return out def proof_problems(proof, att, an, action): """Every reason this proof must be rejected; empty list = accepted. Never raises.""" bad = [] try: b = proof["body"] hd = b["header"] if (hd["schema"], hd["version"], hd["alg"], hd["hash"], hd["canonicalization"], hd["domain"]) != ( "cain.gip.governance-proof", "1.0", "Ed25519", "SHA-256", "cain-json-v1", D_PROOF): bad.append("header") k = an["proof_kids"].get(hd["kid"]) if not k or kid(k["pub"]) != hd["kid"]: bad.append("kid") elif k.get("retired_at") is not None and b["validity"]["issued_at"] >= k["retired_at"]: bad.append("retired_key") if dg(D_PROOF, b) != proof["proof_hash"] or proof["proof_id"] != "gp_" + proof["proof_hash"][:32]: bad.append("proof_hash") if not k or not sig_ok(k["pub"], proof["signature_b64"], D_PROOF, b): bad.append("signature") if b["grants_authority"] is not False or b["authority_granted"] != "NONE": bad.append("authority") if not 0 < b["validity"]["expires_at"] - b["validity"]["issued_at"] <= MAX_TTL: bad.append("validity") if b["status"] not in STATES or b["lifecycle"] != list(STATES[:len(b["lifecycle"])]): bad.append("status") if action is not None: if sorted(action) != sorted(ACTION_FIELDS) or dg(D_ACTION, action) != b["action"]["binding"]: bad.append("action_binding") u, r28, r25, e8 = att["uar"], att["e28_receipt"], att["e25_receipt"], att["e8_entry"] rb = r28["body"] if dg(D_UAR, u["body"]) != u["hash"] or u["hash"] != b["evidence"]["uar_hash"] or \ dg(D_UMA, u["uma"]) != u["body"]["uma_digest"] or \ u["body"]["authorized_digest"] != b["action"]["uma_authorized_digest"] or \ u["body"]["identity"] != b["subject"]["execution_identity"] or \ u["body"]["e28_receipt"] != r28["receipt_hash"]: bad.append("uar") if dg(D_E28, rb) != r28["receipt_hash"] or r28["receipt_hash"] != b["evidence"]["e28_receipt_hash"]: bad.append("e28") for sect, f in (("authority", "authority_digest"), ("policy", "policy_digest"), ("context", "context_digest"), ("risk", "risk_digest"), ("authority", "delegation_digest"), ("action", "action_digest"), ("subject", "identity_digest")): if b[sect][f] != rb[f]: bad.append(f"binding.{f}") if rb["execution_identity"] != b["subject"]["execution_identity"] or \ rb["transaction_nonce"] != b["authorization"]["nonce"]: bad.append("e28_identity_or_nonce") if dg(D_E25, r25["body"]) != r25["receipt_hash"] or r25["receipt_hash"] != b["execution"]["e25_receipt_hash"] \ or r25["body"]["result_hash"] != b["execution"]["result_hash"]: bad.append("e25") if action is not None and r25["body"]["what"]["parameters_digest"] != action["parameters_digest"]: bad.append("parameters") e8b = {k2: v for k2, v in e8.items() if k2 != "entry_hash"} if flat(D_E8, e8b) != e8["entry_hash"] or e8["entry_hash"] != b["enforcement"]["e8_entry_hash"] or \ e8["action_hash"] != b["enforcement"]["e8_action_hash"]: bad.append("e8") root = mroot([bytes.fromhex(x) for x in (u["hash"], r28["receipt_hash"], r25["receipt_hash"], e8["entry_hash"])]).hex() if root != b["evidence"]["evidence_root"]: bad.append("evidence_root") lay = layers(att, an) if any(b["layers_claimed"][x] == "VERIFIED" and lay[x] != "VERIFIED" for x in LAYERS): bad.append("layers_overclaimed") for x in LAYERS[:4]: if lay[x] != "VERIFIED": bad.append(f"layer.{x}") if lay["OUTCOME"] == "FAILED": bad.append("outcome_forged") except (KeyError, TypeError, ValueError, AttributeError, Bad) as e: bad.append(f"malformed:{type(e).__name__}") return bad def main() -> int: d = Path(sys.argv[1]) if len(sys.argv) > 1 else Path(".") c = C() try: ex = load(d, "PROOF_EXAMPLES.json") anchors = load(d, "TRUST_ANCHORS.json")["anchor_sets"] log = load(d, "TRANSPARENCY_LOG.json") mal = load(d, "MALICIOUS_PROOFS.json") e2e = load(d, "END_TO_END.json") except (OSError, ValueError, KeyError) as x: print(json.dumps({"result": "ERROR", "checks": 0, "passed": 0, "problems": [str(x)]})) return 2 # ---- example proofs for i, e in enumerate(ex["proofs"]): an = anchors[e["anchor_set"]] p = proof_problems(e["proof"], e["attachments"], an, e["action"]) c.check(f"proof[{i}].accepted", not p, p) lay = layers(e["attachments"], an) for k in LAYERS[:4]: c.check(f"proof[{i}].layer.{k}", lay[k] == "VERIFIED", lay[k]) c.check(f"proof[{i}].outcome_not_assumed", lay["OUTCOME"] in ("VERIFIED", "UNKNOWN") and (lay["OUTCOME"] == "VERIFIED") == ("postcondition" in e["attachments"]), lay["OUTCOME"]) c.check(f"proof[{i}].no_authority", e["proof"]["body"]["grants_authority"] is False, "authority") # the receipts' own signatures (a verifier must not trust the proof's word for them) u = e["attachments"]["uar"] c.check(f"proof[{i}].uar_signature", sig_ok(an["uar"], u["signature_b64"], D_UAR, u["body"]), "sig") r28 = e["attachments"]["e28_receipt"] c.check(f"proof[{i}].e28_signature", sig_ok(an["e28"], r28["signature_b64"], D_E28, r28["body"]), "sig") r25 = e["attachments"]["e25_receipt"] c.check(f"proof[{i}].e25_signature", sig_ok(an["e25"], r25["signature_b64"], D_E25, r25["body"]), "sig") # ---- deliberately malicious proofs: every one must be rejected classes = set() for i, m in enumerate(mal["proofs"]): an = anchors[m["anchor_set"]] p = proof_problems(m["proof"], m["attachments"], an, m.get("action")) c.check(f"malicious[{i}].{m['class']}.rejected", bool(p), f"{m['mutation']} accepted") classes.add(m["class"]) for i, o in enumerate(mal["objects"]): k2, ob = o["class"], o["object"] if k2 == "revocation": st = [e for e in load(d, "TRANSPARENCY_LOG.json")["entries"] if e["proof_id"] == ob["proof_id"]] final = st[-1]["data"].get("to", st[-1]["data"].get("status")) if st else None rejected = final in ("REVOKED", "SUPERSEDED") elif k2 == "certificate": b = ob["certificate"]["body"] rejected = not (sig_ok(ob["issuer_pub"], ob["certificate"]["signature_b64"], D_CERT, b) and ob["certificate"]["certificate_id"] == "gc_" + dg(D_CERT, b)[:32]) elif k2 == "coverage": dims = ob["body"]["dimensions"] rejected = not sig_ok(ob["pub"], ob["signature_b64"], D_COVERAGE, ob["body"]) or \ ob["body"]["universal"] != all(v["class"] == "ENFORCED" for v in dims.values()) elif k2 == "conformance": exp = "NONE" for g in ("G0", "G1", "G2", "G3", "G4", "G5", "G6", "G7", "G8"): if ob["results"].get(g) is True: exp = g else: break rejected = ob["level"] != exp else: rejected = False c.check(f"malicious_object[{i}].{k2}.rejected", rejected, o["mutation"]) classes.add(k2) need = {"signature", "digest", "policy", "authority", "identity", "evidence", "timestamp", "nonce", "delegation", "execution", "outcome", "revocation", "certificate", "coverage", "conformance"} c.check("malicious.classes", need <= classes, sorted(need - classes)) # ---- failure proofs for i, f in enumerate(ex["failures"]): an = anchors[f["anchor_set"]] b = f["failure"]["body"] k = an["proof_kids"].get(b["kid"], {}) c.check(f"failure[{i}].signature", dg(D_FAILURE, b) == f["failure"]["failure_hash"] and sig_ok(k.get("pub", ""), f["failure"]["signature_b64"], D_FAILURE, b), "sig") c.check(f"failure[{i}].class", b["failure_class"] in FAILURE_CLASSES, b["failure_class"]) c.check(f"failure[{i}].not_allow", b["decision"] != "ALLOW", b["decision"]) u = f["failure"]["uar"] c.check(f"failure[{i}].uar", u is None or (sig_ok(an["uar"], u["signature_b64"], D_UAR, u["body"]) and u["body"]["decision"] != "ALLOW" and u["hash"] == b["uar_hash"]), "uar") # ---- transparency log an = anchors[log["anchor_set"]] ents = log["entries"] leaves = [leaf(cj(e)) for e in ents] c.check("log.indices", all(e["index"] == i for i, e in enumerate(ents)), "index") head = log["head"] c.check("log.head_signature", sig_ok(an["log"], head["signature_b64"], D_LOG_HEAD, head["body"]), "sig") c.check("log.root", mroot(leaves).hex() == head["body"]["root"] and head["body"]["size"] == len(leaves), "root") for pid, inc in log["inclusions"].items(): c.check(f"log.inclusion.{pid[:12]}", incl_ok(leaf(cj(inc["entry"])), inc["index"], inc["size"], [bytes.fromhex(x) for x in inc["path"]], bytes.fromhex(head["body"]["root"])) and inc["entry"] == ents[inc["index"]], "inclusion") status = {} for e in ents: status[e["proof_id"]] = e["data"]["status"] if e["kind"] == "REGISTER" else e["data"]["to"] for pid, st in log["expected_status"].items(): c.check(f"log.status.{pid[:12]}", status.get(pid) == st, f"{status.get(pid)} != {st}") # ---- receipts, witnesses, certificate, coverage, handshake, conformance x = load(d, "GOVERNANCE_OBJECTS.json") an = anchors[x["anchor_set"]] for i, r in enumerate(x["universal_governance_receipts"]): k = an["proof_kids"].get(r["kid"], {}) c.check(f"ugr[{i}].signature", sig_ok(k.get("pub", ""), r["signature_b64"], D_UGR, r["body"]) and dg(D_UGR, r["body"]) == r["hash"], "sig") c.check(f"ugr[{i}].evidence_not_authority", r["body"]["authority"] == "NONE" and r["body"]["is_evidence"], "authority") for i, s in enumerate(x["witness_statements"]): c.check(f"witness[{i}].signature", sig_ok(s["pub"], s["signature_b64"], D_WITNESS, s["body"]), "sig") c.check(f"witness[{i}].valid", s["body"]["verdict"] == "VALID", s["body"]["verdict"]) cert = x["certificate"] cb = cert["certificate"]["body"] c.check("certificate.signature", sig_ok(cert["issuer_pub"], cert["certificate"]["signature_b64"], D_CERT, cb) and cert["certificate"]["certificate_id"] == "gc_" + dg(D_CERT, cb)[:32], "sig") c.check("certificate.expires", cb["not_after"] > cb["not_before"], "validity") c.check("certificate.not_authority", cb["grants_authority"] is False and cb["authority"] == "NONE", "authority") c.check("certificate.limitations", len(cb["limitations"]) >= 1, "limitations") c.check("certificate.refused_as_authorization", cert["as_authorization"].startswith("REFUSED"), cert["as_authorization"]) cv = x["coverage_proof"] c.check("coverage.signature", sig_ok(cv["pub"], cv["signature_b64"], D_COVERAGE, cv["body"]), "sig") dims = cv["body"]["dimensions"] c.check("coverage.15_dimensions", len(dims) == 15, len(dims)) c.check("coverage.universal_consistent", cv["body"]["universal"] == all(v["class"] == "ENFORCED" for v in dims.values()), "universal") c.check("coverage.not_universal", cv["body"]["universal"] is False, "claims universal control") for k2, v in dims.items(): c.check(f"coverage.{k2}.basis", bool(v["basis"]), "no basis") for name, m in x["handshakes"].items(): c.check(f"handshake.{name}.signature", sig_ok(m["pub"], m["signature_b64"], D_MANIFEST, m["body"]), "sig") for p, v in m["body"]["properties"].items(): if v["basis"] == "declaration": c.check(f"handshake.{name}.{p}.declaration_capped", v["class"] in ("OBSERVED", "MONITORED", "BYPASSABLE", "UNKNOWN"), v["class"]) conf = x["conformance"] levels = ["G0", "G1", "G2", "G3", "G4", "G5", "G6", "G7", "G8"] exp = "NONE" for g in levels: if conf["results"].get(g) is True: exp = g else: break c.check("conformance.level_consistent", conf["level"] == exp, f"{conf['level']} != {exp}") # ---- end to end, bench, invariants, mutation, scale, threat model c.check("e2e.ok", e2e["ok"] is True, "e2e") c.check("e2e.steps", len(e2e["steps"]) == 27, len(e2e["steps"])) for s in e2e["steps"]: c.check(f"e2e.{s['step']}", s["ok"] is True, s) bench = load(d, "SECURITY_RESULTS.json") c.check("bench.all_held", bench["held"] == bench["scenarios"], f"{bench['held']}/{bench['scenarios']}") c.check("bench.at_least_500", bench["scenarios"] >= 500, bench["scenarios"]) c.check("bench.ids_distinct", len({r["id"] for r in bench["rows"]}) == bench["scenarios"], "dups") for cat, t in BENCH_TARGETS.items(): n = sum(1 for r in bench["rows"] if r["category"] == cat) c.check(f"bench.category.{cat}", n >= t, f"{n}<{t}") for r in bench["rows"]: c.check(f"bench.row.{r['id']}", r["held"] is True, r["detail"][:80]) inv = load(d, "INVARIANTS.json") c.check("invariants.at_least_200", inv["total"] >= 200, inv["total"]) c.check("invariants.all_hold", inv["passed"] == inv["total"], [r["id"] for r in inv["rows"] if not r["ok"]][:5]) ids = {r["id"] for r in inv["rows"]} c.check("invariants.30_laws", all(f"E31-L{i}" in ids for i in range(1, 31)), "laws") mut = load(d, "MUTATION_RESULTS.json") c.check("mutation.all_killed", mut["killed"] == mut["mutants"] and not mut["survived"], mut["survived"]) c.check("mutation.at_least_10", mut["mutants"] >= 10, mut["mutants"]) sc = load(d, "SCALE_RESULTS.json") c.check("scale.synthetic_label", "SYNTHETIC" in sc["classification"], "label") got = {(r["dimension"], r["size"]) for r in sc["rows"]} for need_row in [("agents", n) for n in (10, 100, 1000, 10000, 100000)] + \ [("proofs", n) for n in (1000, 10000, 100000, 1000000)] + \ [("trust_domains", n) for n in (1, 10, 100, 1000)]: c.check(f"scale.{need_row[0]}.{need_row[1]}", need_row in got, "missing") for r in sc["rows"]: c.check(f"scale.{r['dimension']}.{r['size']}.no_failures", r["failures"] == 0, r["failures"]) tm = load(d, "THREAT_MODEL.json") c.check("threat_model.no_failed", all(t["status"] != "FAILED" for t in tm["threats"]), "failed threat") c.check("threat_model.untested_disclosed", tm["not_tested"] == [t["threat"] for t in tm["threats"] if t["status"] == "NOT TESTED"], "hidden") ts = load(d, "TYPESCRIPT_SDK_RESULTS.json") c.check("typescript_sdk.intact", ts.get("result") == "INTACT", ts) c.check("typescript_sdk.detects_tamper", ts.get("tamper_result") == "BROKEN", ts) lim = load(d, "KNOWN_LIMITATIONS.json") c.check("limitations.published", len(lim["limitations"]) >= 8, len(lim["limitations"])) cl = load(d, "E31_PUBLIC_CLAIMS.json") for k2 in cl["claims"]: c.check(f"claim.{k2['id']}", all((d / f).exists() for f in k2["evidence"]), k2["evidence"]) # ---- integrity sums = {} for line in (d / "SHA256SUMS").read_text().splitlines(): hx, name = line.split(" ", 1) sums[name] = hx for name, hx in sorted(sums.items()): c.check(f"sha256.{name}", hashlib.sha256((d / name).read_bytes()).hexdigest() == hx, "hash") sig = load(d, "SIGNATURE.json") c.check("signature.files", sig["files"] == sums, "files") c.check("signature.master_digest", sig["master"]["hashes_digest"] == hashlib.sha256(cj(sig["files"])).hexdigest(), "digest") c.check("signature.valid", sig_ok(sig["signer_public_key_b64"], sig["signature_b64"], D_MASTER, sig["master"]), "sig") out = {"verifier": "verify_e31.py", "imports_cain": False, "checks": c.checks, "passed": c.passed, "result": "INTACT" if c.passed == c.checks else "BROKEN", "problems": c.problems[:50]} print(json.dumps(out)) return 0 if out["result"] == "INTACT" else 1 if __name__ == "__main__": sys.exit(main())