ODIN OPE (Open Proof Envelope)
Lightweight, production-grade primitives for verifiable AI↔AI / AI↔Human communication.
This package gives you deterministic canonical JSON, CID hashing, Ed25519 signatures,
and helpers to build/verify envelopes & export bundles used across the ODIN ecosystem.
- Deterministic canonical JSON → stable hashes and signatures
- CID:
sha256:<hex>computed over canonical bytes - Envelope signing: sign
"{cid}|{trace_id}|{ts}"with Ed25519 - Bundle signing: sign
"{bundle_cid}|{trace_id}|{exported_at}" - Signer backends: local seed (default). Optional extras for GCP KMS / AWS KMS / Azure KV.
Install
pip install odin-ope
# or with extras: pip install "odin-ope[gcpkms]" # etc.
Quick start
from odin_ope.signers import FileSigner
from odin_ope.envelope import build_envelope, sign_envelope
from odin_ope.verify import verify_envelope, build_jwks_for_signers
from odin_ope.bundle import build_bundle, sign_bundle, verify_bundle
# 1. Create a signer (Ed25519, deterministic seed for demo)
seed_b64u = "A"*43 # 32-byte Ed25519 seed as base64url (example placeholder)
signer = FileSigner(seed_b64u=seed_b64u) # kid derived from public key
# 2. Build and sign an envelope
payload = {"invoice_id": "INV-1", "amount": 100.25, "currency": "USD"}
env = build_envelope(payload, payload_type="openai.tooluse.invoice.v1", target_type="invoice.iso20022.v1")
signed_env = sign_envelope(env, signer)
# 3. Build JWKS and verify the envelope
jwks = build_jwks_for_signers([signer])
ok, reason = verify_envelope(signed_env, jwks)
assert ok, reason # (or use verify_envelope_or_raise for exceptions)
# 4. Create and sign a bundle
receipts = [
{"hop": 0, "receipt_hash": "h0", "prev_receipt_hash": None},
{"hop": 1, "receipt_hash": "h1", "prev_receipt_hash": "h0"}
]
bundle = build_bundle(trace_id=signed_env["trace_id"], receipts=receipts)
sig = sign_bundle(bundle, signer)
ok2, reason2 = verify_bundle(bundle, sig, jwks, kid=signer.kid)
assert ok2, reason2
See examples/end_to_end.py for a full, annotated script.
FAQ: Common errors
Q: ModuleNotFoundError: No module named 'odin_ope'
A: Make sure your PYTHONPATH includes the src directory, or install the package in editable mode: pip install -e .
Q: ValueError: Ed25519 seed must be 32 bytes
A: The seed for FileSigner must be a base64url-encoded string representing exactly 32 bytes.
Q: Envelope verification fails with cid_mismatch
A: The payload was likely modified after signing. Always verify before mutating envelopes.
Q: How do I generate a valid Ed25519 seed?
A: Use os.urandom(32) and encode with base64.urlsafe_b64encode(seed).rstrip(b'=').
Q: How do I run the tests?
A: PYTHONPATH=src pytest (or on Windows: $env:PYTHONPATH='src'; python -m pytest)
Reason Codes
| Code | Meaning |
|---|---|
| cid_mismatch | Payload hash changed after signing |
| missing_sig_or_kid | Envelope missing sender_sig or kid |
| kid_not_found | KID not present in supplied JWKS |
| signature_invalid | Signature verification failed |
| timestamp_skew | ts outside allowed skew window |
| schema_error | Structural or field validation error |
| not_yet_valid | not_before is in the future |
| expired | expires_at is in the past |
These map 1:1 to exception subclasses (see odin_ope.exceptions).
CLI
The package installs a odin-ope CLI:
odin-ope sign-envelope --payload payload.json --payload-type t --target-type tgt --seed <base64url-seed>
odin-ope verify-envelope --envelope env.json --jwks jwks.json --json --max-skew 300 --strict
Use --json for structured output and --no-skew to disable time skew checks.
Development
Install dev extras and run tests + type checking:
pip install -e .[dev]
pytest -q
mypy src/odin_ope
python scripts/gen_sbom.py --out sbom.json # generate CycloneDX SBOM
Programmatic version: import odin_ope; print(odin_ope.__version__).
\n+## Development
\n+Install dev extras and run tests + type checking:
\n+```
pip install -e .[dev]
pytest -q
mypy src/odin_ope
## Publishing
## Publishing
A GitHub Actions workflow is included (`.github/workflows/publish.yml`).
Create a repository, push, add `PYPI_API_TOKEN` secret, then tag a release like `v0.9.0`.
The workflow produces:
- Signed artifacts published to PyPI
- CycloneDX SBOM artifact (download from workflow run)
- Build provenance attestation (GitHub Attestations UI / API)
---
## License
Apache-2.0
Metadata
Release files for odin-ope 0.9.0
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | |
|---|---|---|---|
| odin_ope-0.9.0.tar.gz | 16.9 kB | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| odin_ope-0.9.0-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 32.3 kB
Release files / odin_ope-0.9.0.tar.gz
| Download URL | odin_ope-0.9.0.tar.gz |
|---|---|
| Size | 16.9 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
96575b727e418d1a4544c4dbd7a10ecd4c2a0c1b94a7fc630421012f8e5546cc
|
|
BLAKE2b-256 checksum How to use checksums |
44eb9008ecff71a917591b58019d8b957bbbbb95a66f2846bec45b4ade87d208
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/6.1.0 CPython/3.13.7
|
Release files / odin_ope-0.9.0-py3-none-any.whl
| Download URL | odin_ope-0.9.0-py3-none-any.whl |
|---|---|
| Size | 15.4 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
6f96cc3af5bb511d3b4e90269a0f5048c1d78f1118b7435eec312f4d8e773c34
|
|
BLAKE2b-256 checksum How to use checksums |
aa5dd2796487acda128af30881d0047f9c330f74f1a148840f27dda999d03301
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/6.1.0 CPython/3.13.7
|