From d5ba78ba2b6bbd4a29e61ad2dbda2bea200774e3 Mon Sep 17 00:00:00 2001 From: Imran Siddique Date: Mon, 27 Jul 2026 17:37:48 -0700 Subject: [PATCH] feat(weight-custody-manifest): add the 30-second refuse-and-wipe demo refuse_and_wipe.py is the headline reproducible moment: the weight-decryption key refuses to release into an enclave running a tampered serving stack, and wipe-on-lapse zeroizes it (gone, not suspended) the moment custody lapses. Real WCM code, software (mock) attestation, no hardware. Featured at the top of the README and added to the CI offline-demo set. Co-Authored-By: Claude Opus 4.8 (1M context) --- .github/workflows/ci.yml | 3 + weight-custody-manifest/README.md | 16 ++- weight-custody-manifest/refuse_and_wipe.py | 141 +++++++++++++++++++++ 3 files changed, 158 insertions(+), 2 deletions(-) create mode 100644 weight-custody-manifest/refuse_and_wipe.py diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index bdde849..c1e782e 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -162,6 +162,9 @@ jobs: - name: Install the WCM SDK from PyPI run: python -m pip install -r requirements.txt + - name: Run the 30-second refuse-and-wipe demo + run: python refuse_and_wipe.py + - name: Run the end-to-end custody demo run: python open_model_e2e.py diff --git a/weight-custody-manifest/README.md b/weight-custody-manifest/README.md index 9bd824e..2023720 100644 --- a/weight-custody-manifest/README.md +++ b/weight-custody-manifest/README.md @@ -18,7 +18,19 @@ cd examples/weight-custody-manifest pip install -r requirements.txt # weight-custody-manifest>=0.19.0, Python 3.11+ ``` -The three offline demos need nothing else. `real_open_model.py` needs run-local extras (below). +The offline demos need nothing else. `real_open_model.py` needs run-local extras (below). + +--- + +## Start here: the 30-second demo + +`refuse_and_wipe.py` is the whole idea in two moments: the weight-decryption key **refuses** to release into an enclave running a tampered serving stack, and **wipe-on-lapse** zeroizes it the moment custody lapses (gone, not suspended). + +```bash +python refuse_and_wipe.py +``` + +The demos below go deeper on the same machinery. --- @@ -64,7 +76,7 @@ python real_open_model.py --local path/to/model.safetensors # skip the downloa ## What runs in CI -The three offline demos (`open_model_e2e.py`, `sovereign_self_custody.py`, `snp_replay.py`) run in CI against the published PyPI package and must exit 0. `real_open_model.py` is not in CI (it downloads a model). +The offline demos (`refuse_and_wipe.py`, `open_model_e2e.py`, `sovereign_self_custody.py`, `snp_replay.py`) run in CI against the published PyPI package and must exit 0. `real_open_model.py` is not in CI (it downloads a model). ## Reference diff --git a/weight-custody-manifest/refuse_and_wipe.py b/weight-custody-manifest/refuse_and_wipe.py new file mode 100644 index 0000000..0076289 --- /dev/null +++ b/weight-custody-manifest/refuse_and_wipe.py @@ -0,0 +1,141 @@ +"""The 30-second demo: the key refuses to release, and wipe-on-lapse zeroizes it. + +Two moments, real WCM code with a software (mock) attestation provider (no +hardware): + + 1. REFUSE - the KBS will not release the weight-decryption key into an enclave + running an unapproved serving stack. A silently modified fork gets nothing, + so the weights it holds stay encrypted. + 2. WIPE - once released, the key lives only for the attestation cadence. Miss + the re-attestation and the enclave zeroizes it. The key is gone, not + suspended, which bounds worst-case exposure to a single cadence window even + if every revocation signal is blocked. + + pip install weight-custody-manifest + python refuse_and_wipe.py +""" +from __future__ import annotations + +import hashlib +from datetime import datetime, timedelta, timezone + +from wcm import ( + Ed25519Signer, + EnclaveSession, + KeyBrokerService, + KeyWipedError, + SoftwareProvider, + WeightCustodyManifest, + generate_ed25519, +) + + +def sha256(data: bytes) -> str: + return "sha256:" + hashlib.sha256(data).hexdigest() + + +def banner(text: str) -> None: + print(f"\n{'=' * 64}\n{text}\n{'=' * 64}") + + +def build_manifest(weights_hash: str, serving: str, org: str) -> dict: + return { + "manifest_version": "0.1", + "weights_hash": weights_hash, + "builder": {"identity": org, "signing_key": "ed25519:demo"}, + "release_terms": { + "license": "Frontier-Model-License", + "permitted_derivatives": "fine-tune-only", + "derivatives": "fine-tune-only", + "permitted_environments": ["enterprise-governed-enclave"], + }, + "release_policy": { + "required_assurance_tier": "hardware-attested", + "trusted_time_source": "secure-tsc", + "required_hw_platform": ["amd-sev-snp", "nvidia-cc-gpu"], + "required_gpu_measurement": {"rim_pin": "nvidia-rim:golden"}, + "required_serving_image": { + "signer": "ed25519:demo", + "release_rule": "prefer-current", + "accepted_measurements": [{"measurement": serving, "status": "current"}], + }, + "attestation_revocation_check": "live-per-release, max-cache-age: short-window", + "revocation_authority": "builder-and-opaque-joint", + }, + "custody": { + "custodian": org, + "custodian_type": "customer-self-custody", + "kbs_image": {"measurement": sha256(b"reference-kbs-image"), "signer": "ed25519:demo"}, + "enclave_id": "did:example:enclave-01", + "attestation_cadence": "1h", + }, + "base_confidentiality": "gated-open", + "deployment_model": "builder-to-customer", + } + + +def main() -> None: + org = "frontier-labs" + builder, custodian = generate_ed25519(), generate_ed25519() + + weights_hash = sha256(b"") + approved = sha256(b"vllm-0.6.3 + policy-bundle-v2 (the builder-signed serving stack)") + + doc = build_manifest(weights_hash, approved, org) + manifest = WeightCustodyManifest.model_validate(doc) + manifest = manifest.with_signatures([ + Ed25519Signer(builder).sign(manifest.unsigned_dict(), role="builder", signer=org), + Ed25519Signer(custodian).sign(manifest.unsigned_dict(), role="custodian", signer=org), + ]) + + kbs = KeyBrokerService({weights_hash: b"the-weight-decryption-key"}) + + # -- Moment 1: REFUSE ------------------------------------------------------ + banner("1. A tampered enclave asks for the key. It gets nothing.") + tampered = sha256(b"vllm-0.6.3 + a BACKDOORED policy bundle") + challenge = kbs.issue_challenge() + bad_evidence = SoftwareProvider().produce( + challenge, + serving_image_measurement=tampered, # not what the builder signed + gpu_measurement="nvidia-rim:golden", + ) + decision = kbs.verify_and_release(manifest, bad_evidence) + print("serving stack : UNAPPROVED (a modified fork)") + print("key released :", decision.released) + print("why :", next(c.detail for c in decision.failures)) + print("-> the weights it holds stay encrypted. The fork cannot decrypt them.") + + # -- The approved enclave gets the key ------------------------------------- + banner("2. The approved enclave attests. The key releases.") + challenge = kbs.issue_challenge() + good_evidence = SoftwareProvider().produce( + challenge, + serving_image_measurement=approved, + gpu_measurement="nvidia-rim:golden", + ) + decision = kbs.verify_and_release(manifest, good_evidence) + print("serving stack : builder-signed and attested") + print("key released :", decision.released) + + # -- Moment 2: WIPE-ON-LAPSE ----------------------------------------------- + banner("3. Miss the re-attestation. The enclave zeroizes the key.") + t0 = datetime(2026, 1, 1, tzinfo=timezone.utc) + session = EnclaveSession.from_release(manifest, decision, now=lambda: t0) + print("cadence :", doc["custody"]["attestation_cadence"], + " time_floor:", session.time_floor.value) + session.use_key(now=t0) + print("served a request : key present") + later = t0 + timedelta(hours=1, minutes=1) # past the 1h window, no re-attest + try: + session.use_key(now=later) + print("served a request : key present") # not reached + except KeyWipedError: + print("re-attest missed : key ZEROIZED") + print("state :", session.state.value, "(gone, not suspended)") + print("-> worst-case exposure is one cadence window, even if revocation is blocked.") + + banner("Refuse. Release only on proof. Wipe on lapse.") + + +if __name__ == "__main__": + main()