Python SDK (embedded mode)
mintid-verifier-sdk: a frozen public surface, one decision entrypoint, five infrastructure ports — and a proof engine pinned inside the wheel.
The public surface
Package mintid-verifier-sdk, import name verifier_core. Python ≥ 3.12. The Rust proof engine ships compiled inside the wheel at a build-time pin — a supported installation cannot end up with a substituted or mismatched engine.
One decision entrypoint, five ports. Everything importable is listed in the block on the right; everything else under verifier_core is internal and may change without notice.
This surface is frozen and test-enforced: a CI test imports exactly this list and fails when it grows or drifts. Changes follow semver — surface or semantics change is a major version.
The entrypoint
You supply infrastructure, never policy:
| Port | Production implementation | Your freedom |
|---|---|---|
ChainReader | ChainClient over your RPC node(s) + trust-anchor header source | which nodes — never whether reads are proven |
NonceStore | bundled SqliteNonceStore (crash-durable, synchronous=FULL) | swap the backend if it keeps atomic exactly-once consume |
ProofVerifier | the wheel's pinned engine | none — implementations must reject any proof not bound to the exact challenge |
DecisionLog | JsonlDecisionLog (or your store over DecisionRecord) | where records go — never what they contain |
| clock | you pass now_unix | a skewed clock only makes you more rejecting |
Issuing challenges
The policy digest commits to the whole canonical body — tampering with any part of the challenge breaks the proof binding (condition 5).
Chain access
ChainClient splits trust into two ports on purpose:
StateQueryPort— any RPC node, assumed malicious. Every answer carries an ics23 proof.TrustedHeaderSource— your trust anchor. The bundledTrustAnchorHeaderSourcereads an operator-designated node (your own node): suitable when you run the node you point it at. Backing this port with a full light client against untrusted peers is on the roadmap; never point the anchor at an arbitrary public RPC.
Absence is never trusted: if a node claims a record doesn't exist, the read fails closed (UnprovenAbsenceError → state_unproven).
Retention (what you keep, all of it)
Exactly one DecisionRecord per decision, accept or reject: session_id, accepted, reason_code, bound_context_digest (32 bytes), decided_at_unix. Serialization emits exactly these keys; tests assert field-set equality. Presentations, proof bytes and claim values are never persisted — treat any schema extension as a privacy review.