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>
141 lines
4.8 KiB
Python
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())
|