The same open-standards posture that turned JCR-1 into a standard
(three independent implementations agreeing byte-for-byte across
canonical CBOR + COSE_Sign1), now applied to policy receipts. A
policy receipt is a real spec, not a Rust house format.
## What ships
- conformance/vectors-policy.json — 3 vectors spanning the
decision space: Allow with named rule, Explicit deny with named
rule, and No-matching-allow (deny-by-default). Each carries the
receipt JSON, the canonical signed-core CBOR hex, and the
COSE_Sign1 envelope hex.
- conformance/verify.py — Python verifier (cbor2 + cryptography
only). Re-encodes each canonical core, signs a fresh envelope
under the same seed, asserts byte-equal against committed hex.
- conformance/verify.go — Go verifier (stdlib only, no go.mod).
From-scratch RFC 8949 §4.2.1 length-first CBOR encoder + COSE
reader. Stdlib crypto/ed25519 verifies the envelope.
- conformance/README.md — vector descriptions, regeneration
procedure, scope.
- examples/gen_policy_vectors.rs — Rust regenerator. Run with a
path argument to write the vectors JSON; argument-less prints
to stdout for inspection.
- Embedded POLICY_VECTORS_JSON const + the
policy_vectors_match_committed_conformance regression test in
src/lib.rs — a drifting Rust producer fails BEFORE the Python
and Go verifiers ever run.
## Cross-implementation verification
All three implementations cross-verified locally on the same vectors:
Rust (cargo test policy_vectors_match_committed_conformance): pass
Python (python3 verify.py): pass on 3/3 vectors
Go (go run verify.go): pass on 3/3 vectors
Same seed JCR-1 uses for cascade-receipt vectors, so a third party
can cross-validate both receipt families under a single test key.
## Workspace
102 crates, 2,533 lib tests pass (+1 for the conformance regression),
0 failures.
112 lines
3.6 KiB
Python
112 lines
3.6 KiB
Python
#!/usr/bin/env python3
|
|
"""Independent Python verifier for JouleClaw policy-receipt vectors.
|
|
|
|
Reproduces (a) the canonical CBOR signed core and (b) the COSE_Sign1
|
|
envelope for every vector in `vectors-policy.json` and confirms they
|
|
match the bytes the Rust producer wrote.
|
|
|
|
No JouleClaw dependency — uses only `cbor2`, `cryptography`, and the
|
|
stdlib. Three independent implementations (Rust + Python + Go) MUST
|
|
produce bit-identical bytes for every vector.
|
|
|
|
Requires:
|
|
pip install cbor2 cryptography
|
|
|
|
Usage:
|
|
python3 verify.py [path/to/vectors-policy.json]
|
|
"""
|
|
|
|
from __future__ import annotations
|
|
|
|
import json
|
|
import sys
|
|
from pathlib import Path
|
|
|
|
try:
|
|
import cbor2
|
|
except ImportError:
|
|
sys.exit("cbor2 not installed. Try: pip install cbor2")
|
|
|
|
try:
|
|
from cryptography.hazmat.primitives.asymmetric.ed25519 import (
|
|
Ed25519PrivateKey,
|
|
Ed25519PublicKey,
|
|
)
|
|
from cryptography.hazmat.primitives.serialization import Encoding, PublicFormat
|
|
except ImportError:
|
|
sys.exit("cryptography not installed. Try: pip install cryptography")
|
|
|
|
|
|
def canonical_cbor(value):
|
|
"""RFC 8949 §4.2.1 core deterministic encoding — length-first map keys."""
|
|
return cbor2.dumps(value, canonical=True)
|
|
|
|
|
|
def cose_sign1_envelope(core: bytes, signing_key: Ed25519PrivateKey, steward: str) -> bytes:
|
|
"""Construct a COSE_Sign1 envelope (RFC 9052) over `core`.
|
|
|
|
Mirrors `jouleclaw_jcr1::cose_sign1_envelope` byte-for-byte.
|
|
"""
|
|
protected = cbor2.dumps({1: -8, 4: steward.encode("utf-8")}, canonical=True)
|
|
sig_structure = cbor2.dumps(
|
|
["Signature1", protected, b"", core], canonical=True
|
|
)
|
|
signature = signing_key.sign(sig_structure)
|
|
envelope = cbor2.dumps(
|
|
cbor2.CBORTag(18, [protected, {}, core, signature]), canonical=True
|
|
)
|
|
return envelope
|
|
|
|
|
|
def verify_one(v, signing_key: Ed25519PrivateKey, pub: Ed25519PublicKey) -> None:
|
|
n = v["n"]
|
|
receipt = v["receipt"]
|
|
expected_core_hex = v["signed_core_cbor_hex"]
|
|
expected_env_hex = v["cose_sign1_hex"]
|
|
|
|
# Reproduce the canonical signed core.
|
|
got_core = canonical_cbor(receipt)
|
|
got_core_hex = got_core.hex()
|
|
if got_core_hex != expected_core_hex:
|
|
print(f"vector {n}: CORE MISMATCH")
|
|
print(f" expected: {expected_core_hex[:120]}...")
|
|
print(f" got: {got_core_hex[:120]}...")
|
|
sys.exit(1)
|
|
|
|
# Reproduce the COSE_Sign1 envelope.
|
|
steward = receipt["steward"]
|
|
got_env = cose_sign1_envelope(got_core, signing_key, steward)
|
|
got_env_hex = got_env.hex()
|
|
if got_env_hex != expected_env_hex:
|
|
print(f"vector {n}: ENVELOPE MISMATCH")
|
|
print(f" expected: {expected_env_hex[:120]}...")
|
|
print(f" got: {got_env_hex[:120]}...")
|
|
sys.exit(1)
|
|
|
|
print(f"vector {n}: ✓ {v['description']}")
|
|
|
|
|
|
def main() -> None:
|
|
path = Path(sys.argv[1] if len(sys.argv) > 1 else "vectors-policy.json")
|
|
doc = json.loads(path.read_text())
|
|
seed_hex = doc["test_key"]["ed25519_seed_hex"]
|
|
signing_key = Ed25519PrivateKey.from_private_bytes(bytes.fromhex(seed_hex))
|
|
pub = signing_key.public_key()
|
|
declared_pub_hex = doc["test_key"]["ed25519_public_raw_hex"]
|
|
got_pub_hex = pub.public_bytes(Encoding.Raw, PublicFormat.Raw).hex()
|
|
if got_pub_hex != declared_pub_hex:
|
|
sys.exit(
|
|
f"public key mismatch: declared {declared_pub_hex}, got {got_pub_hex}"
|
|
)
|
|
|
|
print(f"JouleClaw policy-receipt conformance — {len(doc['vectors'])} vectors")
|
|
print(f"schema_id: {doc['schema_id']}")
|
|
print()
|
|
for v in doc["vectors"]:
|
|
verify_one(v, signing_key, pub)
|
|
print()
|
|
print(f"all {len(doc['vectors'])} vectors verified.")
|
|
|
|
|
|
if __name__ == "__main__":
|
|
main()
|