Files
vm-core/tools/make_proofbundle_testvectors.py
2025-12-27 00:10:32 +00:00

100 lines
3.1 KiB
Python
Executable File

#!/usr/bin/env python3
"""
Generate ProofBundle conformance test vectors from a known-good bundle.
Usage:
python3 make_proofbundle_testvectors.py \\
/root/work/vaultmesh/proofbundle-sample.json \\
/root/work/vaultmesh/testvectors/proofbundle
This script takes a valid ProofBundle and creates:
- proofbundle-valid.json (copy of original with normalized bundle_id)
- proofbundle-tampered-body.json (timestamp modified without updating root_hash)
- proofbundle-tampered-root.json (wrong root_hash in a receipt)
- proofbundle-broken-chain.json (previous_hash mismatch)
"""
import copy
import json
import sys
from pathlib import Path
def load_bundle(path: Path) -> dict:
with path.open("r", encoding="utf-8") as f:
return json.load(f)
def save_bundle(bundle: dict, path: Path) -> None:
path.write_text(
json.dumps(bundle, indent=2, sort_keys=True, ensure_ascii=False),
encoding="utf-8",
)
print(f"[+] wrote {path}")
def make_valid(bundle: dict) -> dict:
"""Create a normalized copy as the valid reference."""
out = copy.deepcopy(bundle)
out["bundle_id"] = "pb-test-valid"
return out
def make_tampered_body(bundle: dict) -> dict:
"""Tamper a receipt's timestamp without updating root_hash."""
out = copy.deepcopy(bundle)
out["bundle_id"] = "pb-test-tampered-body"
receipts = out.get("chain", {}).get("receipts", [])
if len(receipts) >= 2:
# Modify the second receipt's timestamp (the root_hash will be wrong)
receipts[1]["timestamp"] = "2099-01-01T00:00:00.000Z"
return out
def make_tampered_root(bundle: dict) -> dict:
"""Replace a receipt's root_hash with a clearly wrong value."""
out = copy.deepcopy(bundle)
out["bundle_id"] = "pb-test-tampered-root"
receipts = out.get("chain", {}).get("receipts", [])
if receipts:
# Tamper the last receipt's root_hash
receipts[-1]["root_hash"] = "blake3:deadbeefdeadbeefdeadbeefdeadbeef"
return out
def make_broken_chain(bundle: dict) -> dict:
"""Break the chain linkage via previous_hash mismatch."""
out = copy.deepcopy(bundle)
out["bundle_id"] = "pb-test-broken-chain"
receipts = out.get("chain", {}).get("receipts", [])
if len(receipts) >= 2:
# Break linkage at receipt[1]
receipts[1]["previous_hash"] = "blake3:badcafebadcafebadcafebadcafebad0"
return out
def main():
if len(sys.argv) != 3:
print(
"Usage: make_proofbundle_testvectors.py INPUT_BUNDLE OUTPUT_DIR",
file=sys.stderr,
)
sys.exit(1)
src = Path(sys.argv[1])
dest_dir = Path(sys.argv[2])
dest_dir.mkdir(parents=True, exist_ok=True)
base = load_bundle(src)
save_bundle(make_valid(base), dest_dir / "proofbundle-valid.json")
save_bundle(make_tampered_body(base), dest_dir / "proofbundle-tampered-body.json")
save_bundle(make_tampered_root(base), dest_dir / "proofbundle-tampered-root.json")
save_bundle(make_broken_chain(base), dest_dir / "proofbundle-broken-chain.json")
print(f"\n[OK] Generated 4 test vectors in {dest_dir}")
if __name__ == "__main__":
main()