evidencevault-verify
Offline, dependency-light verification of EvidenceVault certificates — for third
parties, auditors, and courts. pip install evidencevault-verify gives you a CLI and a
Python library that verify a certificate's cryptographic and structural integrity using
only its public artifacts, with zero network access.
This is a faithful Python port of the EvidenceVault TypeScript verifier
(tools/cert-verify + packages/verify-core + packages/shared). It produces
byte-identical canonicalization and hashes and the same pass/fail verdicts as the
reference cert-verify tool — proven by a cross-validation test suite that diffs the two
verifiers against real deployed certificates.
What it verifies
For each certificate, exactly the checks the TypeScript verifier reports:
| Check | Meaning |
|---|---|
identityMatches |
The payload's cert_id / issuing_tenant_id match what you asked for |
canonicalHashMatches |
RFC 8785 JCS canonicalization of the payload → SHA-256 → unpadded base64url equals signatures.canonical_payload_sha256 |
ed25519Valid |
Ed25519 signature over the canonical payload bytes (key resolved through the tenant registry, incl. time-bounded agent subkey certificates) |
mlDsa65Valid |
ML-DSA-65 (FIPS 204) post-quantum co-signature |
slhDsaSha2128fValid |
SLH-DSA-SHA2-128f (FIPS 205) post-quantum co-signature |
merkleInclusionValid |
RFC 6962 inclusion proof (0x00 leaf / 0x01 node) binds the claimed leaf to source_evidence_merkle_root — null when no proof is present |
withinValidity |
issued_at <= now < expires_at |
dualSignatureValid |
Licensee co-signature for dual-signed classes: licensee credential present, platform-certified, verified and in-window — null when neither present nor required, fail-closed when required but missing |
predicatesValid |
Every declared predicate certificate exists, has status issued, and is within validity — fail-closed when predicates are declared but unresolved |
otsAnchorPresent / otsProofFound |
An OpenTimestamps .ots proof is present and non-empty (Bitcoin confirmation is delegated to the ots CLI via --ots-cli) |
A certificate is ok only when all mandatory checks pass and no optional check is false
— the identical conjunction the TypeScript verifier uses.
Both post-quantum families are required (a break in one family cannot forge a
certificate on its own), and both signatures were produced by
@noble/post-quantum (FIPS 204 / FIPS
205 final). See Post-quantum interoperability below.
Install
pip install evidencevault-verify
Requires Python 3.10+. Dependencies (all pure-Python or pip-wheel, no native OQS build):
cryptography (Ed25519), dilithium-py (ML-DSA-65), slh-dsa (SLH-DSA-SHA2-128f).
CLI
# Verify from a directory of public artifacts
evidencevault-verify --cert-id cert_01KY7HNX7T89K8HNNC17PBK3YD \
--tenant-id tnt_demo \
--dir ./bundle
# Verify from a self-contained bundle (base64-embedded files)
evidencevault-verify --cert-id <id> --tenant-id <tnt> --bundle ./bundle.json
# Machine-readable output
evidencevault-verify --cert-id <id> --tenant-id <tnt> --dir ./bundle --json
# Also run Bitcoin-tier OpenTimestamps confirmation (requires `ots` on PATH)
evidencevault-verify --cert-id <id> --tenant-id <tnt> --dir ./bundle --ots-cli
Output (byte-identical to the reference cert-verify):
✓ cert_01KY7HNX7T89K8HNNC17PBK3YD — {"tenantRegistryFound":true,...,"otsProofFound":true}
Exit code 0 when the certificate is valid, 1 when it is not, 2 on a usage error.
Library API
from evidencevault_verify import verify_certificate, DirSource
result = verify_certificate(DirSource("./bundle"), "cert_01KY7HNX...", "tnt_demo")
print(result.ok) # overall verdict
print(result.checks.ed25519_valid) # individual checks (snake_case attributes)
print(result.checks.ml_dsa65_valid)
print(result.checks.slh_dsa_sha2_128f_valid)
print(result.checks.to_ts_dict()) # exact camelCase check map the CLI prints
for err in result.errors:
print(err)
Convenience wrappers: verify_certificate_from_dir(base_dir, cert_id, tenant_id) and
verify_certificate_from_bundle(bundle_path, cert_id, tenant_id). Pass now=<datetime>
to any of them to verify against a fixed time instead of the current clock.
verify_certificate accepts any object with a read(relative_path) -> bytes | None
method (the ArtifactSource protocol), so you can back it with a directory
(DirSource), an in-memory bundle (BundleSource), or your own storage.
Artifact layout
Identical to the reference cert-verify. In --dir mode the base directory contains:
public/tenants/<tenant_id>.json # tenant public key registry (trust root)
public/certificates/<cert_id>.json # existence records (for predicate resolution)
certificates/<cert_id>/payload.json # the signed certificate payload
certificates/<cert_id>/signatures.json # Ed25519 + hybrid PQC signature block
certificates/<cert_id>/merkle-proof.json # optional RFC 6962 inclusion proof
certificates/<cert_id>/cert.ots # optional OpenTimestamps proof
In --bundle mode a single JSON file carries every file above as base64-encoded bytes.
Both modes contact no network and read no EvidenceVault infrastructure.
Post-quantum interoperability
The load-bearing risk in a Python port is whether a Python PQC library can verify
signatures produced by @noble/post-quantum. It can — proven against the real
signatures on the shipped campaign certificates:
- ML-DSA-65 →
dilithium-py(pure-Python FIPS 204).ML_DSA_65.verify(pubkey, msg, sig)accepts @noble's signature and rejects a tampered message. - SLH-DSA-SHA2-128f →
slh-dsa(pure-Python FIPS 205). Verified with the pure variant and an empty context string (PublicKey.from_digest(pubkey, slhdsa.sha2_128f).verify_pure(msg, sig)), which is what@noble'sslh_dsa_sha2_128f.signproduces. Note: the pre-hashedverifyvariant does not accept these signatures — pure is required.
Both libraries are pure-Python (no WASM, no native liboqs build), which keeps the verifier
portable and easy to audit. The interop is asserted for every campaign certificate in
tests/test_pqc_interop.py.
Note on
quantcryptandliboqs:quantcryptwas evaluated first but on some platforms it has no pre-built wheel and its source build JIT-downloads PQClean from GitHub at runtime — unsuitable for an offline court tool.liboqs/oqsrequires a CMake/C build of liboqs. The pure-Pythondilithium-py+slh-dsapair verifies the same@noblesignatures with none of that friction, so it is the chosen dependency set.
Cross-validation (the correctness proof)
tests/test_cross_validation.py runs the Python verifier and the reference TypeScript
cert-verify against the same real certificates and asserts their check maps are
equal, field-for-field. Where a Node toolchain is present the TS verifier is run live
and diffed; the pure-Python assertions (all-green verdict, canonical-hash parity, PQC
interop, fail-closed tampering) run unconditionally.
pip install -e ".[test]"
pytest
For the operator: publishing to PyPI
The package is ready to publish. This repository does not publish it (that needs the operator's PyPI credentials). To publish:
cd tools/evidencevault-verify-py
python -m build # produces dist/*.tar.gz and dist/*.whl
twine upload dist/* # requires your PyPI API token
Run twine check dist/* first to validate the metadata.
License
MIT — see LICENSE.
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file evidencevault_verify-2.0.0.tar.gz.
File metadata
- Download URL: evidencevault_verify-2.0.0.tar.gz
- Upload date:
- Size: 28.7 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via:
twine/6.2.0 CPython/3.12.13
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
8169a765c38a47e31459d06eb94629665fd0b41cd7f9e9e822a28d9391c7dcf9
|
|
| MD5 |
df3548526d5c76f7ee8ce51a169474aa
|
|
| BLAKE2b-256 |
f00e5960e996b7c119c441ccdba23cfd4aef43ace3b72932931757880ed22f3c
|
File details
Details for the file evidencevault_verify-2.0.0-py3-none-any.whl.
File metadata
- Download URL: evidencevault_verify-2.0.0-py3-none-any.whl
- Upload date:
- Size: 25.7 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via:
twine/6.2.0 CPython/3.12.13
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
007a6e6aeaed0b2de557a34b139e2eeaf11fda34abd9829e9422df7938125bb5
|
|
| MD5 |
2518ca92662761fa75c3ede24e6d2993
|
|
| BLAKE2b-256 |
a32d530645225603b15de1326841e79465eea15c217c49d291c10699d1846b2e
|