Offline verification library for Sanad Sign attestations — Ed25519 + CycloneDX + SHA-256 hash chain. India's sovereign attestation rail.
Project description
sanad-verify (Python)
Offline verification library for Sanad Sign attestations. Byte-for-byte
compatible with the reference Node SDK — a signature produced by
@cognoshift/sanad-sbom
verifies here, and vice versa.
Built for CERT-In empanelled auditors, security reviewers, regulators, and internal compliance teams who live in Python.
Install
pip install sanad-verify
Only runtime dependency: cryptography.
Supports Python 3.9+.
Verify a single attestation
import requests
from sanad_verify import verify_attestation
row = requests.get("https://sanad.cognoshift.in/api/sign/registry/<id>").json()
result = verify_attestation({
"sbom": row["sbom"],
"signature": row["signature"],
"public_key": row["public_key"],
"sbom_hash": row["sbom_hash"], # optional — recomputed regardless
})
print(result["valid"]) # True / False
print(result["signature_valid"]) # Ed25519 check
print(result["hash_match"]) # claimed vs recomputed SHA-256
print(result["computed_hash"]) # 'a3f5…'
Replay the hash chain
Given all attestations for a tenant (ordered ascending by created_at, id):
from sanad_verify import verify_chain
result = verify_chain(rows)
print(result["valid"]) # True when chain is intact
print(result["break_at"]) # id of first broken row, or None
print(result["first_mismatch"]) # detailed diagnostic
The genesis constant is SANAD_SIGN_GENESIS_2026 (exported as GENESIS).
For a private deployment with a different genesis:
verify_chain(rows, genesis="MY_PRIVATE_GENESIS")
How verification works
- Canonicalize the SBOM — recursive sort of object keys, arrays preserve order, compact separators, UTF-8 preserved. Matches the subset of RFC 8785 JCS that CycloneDX exercises.
- Hash the canonical string with SHA-256. This is the
sbom_hash. - Verify the Ed25519 signature over the hex-encoded
sbom_hash, using the public key stored on the row (SPKI format, base64-decoded from DER). - Chain replay: for every row in the tenant's ledger, recompute
SHA-256(event_hash || previous_chain_hash)and match against the storedchain_hash.previous_chain_hashisGENESISfor the first entry.
All four steps are deterministic. This library and the Node reference implementation produce identical output; either can verify attestations signed by the other.
Typing
The package ships a py.typed marker, so mypy / pyright / pylance pick up
the full function signatures automatically.
License
Apache-2.0 — free for commercial audit use.
Project details
Release history Release notifications | RSS feed
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 sanad_verify-0.1.0.tar.gz.
File metadata
- Download URL: sanad_verify-0.1.0.tar.gz
- Upload date:
- Size: 5.4 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.12.10
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
7e2ec0ca6b0d50996f89fb7c03ab8899813732536a0306f259b88b44441b66a6
|
|
| MD5 |
c031602b0aabfcfca3f82885ddf6a911
|
|
| BLAKE2b-256 |
bb3cc9dea9f778f4439b1d3c975b784eda299d58f87d06a6a9e061d150e95622
|
File details
Details for the file sanad_verify-0.1.0-py3-none-any.whl.
File metadata
- Download URL: sanad_verify-0.1.0-py3-none-any.whl
- Upload date:
- Size: 5.7 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.12.10
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
513b27a78e15f007fa73239ebbc8da867624a5259ea3dc386052bb7e31d11a31
|
|
| MD5 |
f7b40dc022b3a3f4551a9a8cbe72c45f
|
|
| BLAKE2b-256 |
663bb19617c6eceff36f38f49fc1688d3c3dffabe5735c5b1a729a86c486bc8f
|