research/examples/verify_output_provenance.py
Meanwhile Research c8a04e144b Initial public release: capability-licensing reference implementation + reproducible claim demos
Clean-room reference implementation (Ed25519 certificate chain, AES-256-GCM
envelope, three-rung revocation ladder, crypto-erasure) with runnable examples
and 36 tests that reproduce each demonstrated claim on stand-in payloads.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-19 16:31:58 +10:00

141 lines
4.8 KiB
Python

#!/usr/bin/env python3
"""Claim 2: output provenance binding.
Bind an output to the certificates of its composition (weight-source and
context-source axes), verify the binding VALID while the composition is
intact, and show it flips to INVALID when a referenced certificate is
revoked or crypto-erased. Also show a tampered output fails the digest check.
"""
import sys
from pathlib import Path
sys.path.insert(0, str(Path(__file__).resolve().parents[1] / "src"))
from capability_licensing import (
AXIS_CONTEXT_SOURCE,
AXIS_WEIGHT_SOURCE,
CertificateAuthority,
RevocationList,
RUNG_CRYPTO_ERASURE,
bind_output,
verify_output_provenance,
)
failures = []
def check(label: str, condition: bool, evidence: str) -> None:
marker = "ok " if condition else "FAIL"
print(f" [{marker}] {label}")
print(f" {evidence}")
if not condition:
failures.append(label)
def main() -> int:
print("=== Claim 2: output provenance bound to composition certificates ===\n")
authority = CertificateAuthority()
root = authority.create_root("Reference Root Authority")
organisation = authority.issue_organisation(root.serial, "Reference Research Organisation")
weight_source, weight_key = authority.issue_capability(
organisation.serial,
"summarisation-adapter (weight-source)",
claims={"axis": AXIS_WEIGHT_SOURCE, "grant": "research demonstration only"},
)
context_source, _context_key = authority.issue_capability(
organisation.serial,
"licensed-reference-corpus (context-source)",
claims={"axis": AXIS_CONTEXT_SOURCE, "grant": "research demonstration only"},
)
print(f" weight-source certificate: {weight_source.serial}")
print(f" context-source certificate: {context_source.serial}")
output = (
b"Stand-in generated output: a three-paragraph summary of the supplied "
b"reference material, produced by the licensed summarisation adapter."
)
record = bind_output(
output,
sources=[
(AXIS_WEIGHT_SOURCE, weight_source),
(AXIS_CONTEXT_SOURCE, context_source),
],
signer_certificate=weight_source,
signer_private_key=weight_key,
)
print(f" output bound: sha256 {record.output_sha256[:16]}..., "
f"signed by {record.signer_serial}\n")
registry = authority.registry()
revocations = RevocationList()
# 1. Intact composition verifies VALID.
intact = verify_output_provenance(
output, record, registry, [organisation], [root], revocations
)
print(" checks performed on the intact composition:")
for item in intact.checks:
print(f" - {item}")
check(
"intact composition verifies VALID",
intact.valid,
f"result: {'VALID' if intact.valid else 'INVALID'} - {intact.reason}",
)
# 2. Tampered output fails the digest binding.
tampered_output = output + b" [edited after the fact]"
tampered = verify_output_provenance(
tampered_output, record, registry, [organisation], [root], revocations
)
check(
"tampered output fails the digest binding",
not tampered.valid and "does not match the bound digest" in tampered.reason,
f"result: INVALID - {tampered.reason}",
)
# 3. Revoke the context-source certificate: the SAME record now verifies
# INVALID. Provenance is a live claim against authority state.
revocations.revoke(context_source.serial, "context licence terminated")
revoked = verify_output_provenance(
output, record, registry, [organisation], [root], revocations
)
check(
"after revoking the context-source certificate, verification is INVALID",
not revoked.valid and "revoked" in revoked.reason,
f"result: INVALID - {revoked.reason}",
)
revocations.reinstate(context_source.serial)
# 4. Crypto-erase the weight-source capability: INVALID again, and the
# ledger records the strongest rung.
revocations.revoke(
weight_source.serial,
"capability unit crypto-erased by the authority",
rung=RUNG_CRYPTO_ERASURE,
)
erased = verify_output_provenance(
output, record, registry, [organisation], [root], revocations
)
check(
"after crypto-erasure of the weight-source capability, verification is INVALID",
not erased.valid and "crypto-erasure" in erased.reason,
f"result: INVALID - {erased.reason}",
)
print()
if failures:
print(f"RESULT: FAIL - {len(failures)} check(s) did not behave as claimed")
return 1
print(
"RESULT: PASS - the binding verifies for an intact composition and is "
"INVALID for a tampered output or a revoked/erased source certificate"
)
return 0
if __name__ == "__main__":
sys.exit(main())