Metadata-Version: 2.4
Name: sanad-verify
Version: 0.1.0
Summary: Offline verification library for Sanad Sign attestations — Ed25519 + CycloneDX + SHA-256 hash chain. India's sovereign attestation rail.
Author-email: COGNOSHIFT PRIVATE LIMITED <support@cognoshift.in>
License: Apache-2.0
Project-URL: Homepage, https://sanad.cognoshift.in
Project-URL: Repository, https://github.com/anupam9091/cognoshift-sentinel
Project-URL: Documentation, https://sanad.cognoshift.in/registry
Project-URL: Issues, https://github.com/anupam9091/cognoshift-sentinel/issues
Keywords: sbom,verification,ed25519,cyclonedx,attestation,sigstore,cert-in,audit,india,sanad,cognoshift
Classifier: Development Status :: 3 - Alpha
Classifier: Intended Audience :: Developers
Classifier: Intended Audience :: Legal Industry
Classifier: License :: OSI Approved :: Apache Software License
Classifier: Operating System :: OS Independent
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3.9
Classifier: Programming Language :: Python :: 3.10
Classifier: Programming Language :: Python :: 3.11
Classifier: Programming Language :: Python :: 3.12
Classifier: Programming Language :: Python :: 3.13
Classifier: Topic :: Security :: Cryptography
Classifier: Topic :: Software Development :: Libraries :: Python Modules
Classifier: Topic :: System :: Archiving :: Packaging
Requires-Python: >=3.9
Description-Content-Type: text/markdown
License-File: LICENSE
Requires-Dist: cryptography>=41
Dynamic: license-file

# 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`](https://www.npmjs.com/package/@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

```bash
pip install sanad-verify
```

Only runtime dependency: [`cryptography`](https://cryptography.io/).
Supports Python 3.9+.

## Verify a single attestation

```python
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`):

```python
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:

```python
verify_chain(rows, genesis="MY_PRIVATE_GENESIS")
```

## How verification works

1. **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.
2. **Hash** the canonical string with SHA-256. This is the `sbom_hash`.
3. **Verify** the Ed25519 signature over the hex-encoded `sbom_hash`, using
   the public key stored on the row (SPKI format, base64-decoded from DER).
4. **Chain replay:** for every row in the tenant's ledger, recompute
   `SHA-256(event_hash || previous_chain_hash)` and match against the stored
   `chain_hash`. `previous_chain_hash` is `GENESIS` for 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.
