Skip to main content

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)

Source distribution for odin-ope 0.9.0
File Size Uploaded
odin_ope-0.9.0.tar.gz 16.9 kB Details

Built distribution (wheel)

Table of built distributions (wheels) for odin-ope 0.9.0
File Interpreter ABI Platform
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

Release history Release notifications | RSS feed

This release

0.9.0 This release

2 release files

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page