Metadata-Version: 2.4
Name: marturia-verify
Version: 0.3.0
Summary: Standalone verifier for Marturia cryptographic audit receipts plus production HTTP SDK (marturia_sdk) — including EU AI Act Article 14 human-oversight receipts.
Author: Gabriel Gaul
License: MIT
Project-URL: Homepage, https://marturia.dev
Project-URL: Documentation, https://marturia.dev/docs/verify
Project-URL: Source, https://github.com/Seppapath/CarpenterClaw/tree/main/marturia-verify
Project-URL: Issues, https://github.com/Seppapath/CarpenterClaw/issues
Keywords: marturia,audit,cryptographic-receipts,ed25519,transparency-log,observability,ai-agent-audit
Classifier: Development Status :: 4 - Beta
Classifier: Intended Audience :: Developers
Classifier: License :: OSI Approved :: MIT License
Classifier: Operating System :: OS Independent
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3 :: Only
Classifier: Programming Language :: Python :: 3.10
Classifier: Programming Language :: Python :: 3.11
Classifier: Programming Language :: Python :: 3.12
Classifier: Topic :: Security :: Cryptography
Classifier: Topic :: System :: Logging
Requires-Python: >=3.10
Description-Content-Type: text/markdown
Requires-Dist: cryptography>=42.0
Requires-Dist: httpx>=0.27
Provides-Extra: dev
Requires-Dist: pytest>=7.0; extra == "dev"
Requires-Dist: pytest-cov>=4.0; extra == "dev"
Requires-Dist: pytest-asyncio>=0.23; extra == "dev"
Requires-Dist: respx>=0.21; extra == "dev"

# marturia-verify

Standalone verifier for [Marturia](https://marturia.dev) cryptographic audit receipts.

Anyone holding a Marturia receipt and the issuing tenant's public key can verify the receipt **without trusting the Marturia infrastructure that issued it**. That's the point: cryptographic testimony you can audit independently.

## Install

```bash
pip install marturia-verify
```

The only runtime dependency is `cryptography`.

## CLI

```bash
# Verify a single receipt
marturia-verify --receipt receipt.json --pubkey tenant.pub
# → VALID: signature valid; receipt_hash matches; sequence 42 of tenant 12

# Verify a contiguous chain
marturia-verify --chain receipts.json --pubkey tenant.pub
# → VALID: chain valid: 27 receipt(s), seq 1..27

# Public key inline as hex
marturia-verify --receipt receipt.json --pubkey-hex 4f3a...64hex...

# Quiet mode (one-line output)
marturia-verify --chain receipts.json --pubkey tenant.pub --quiet
```

Exit code: `0` on success, `1` on any verification failure.

## Library API

```python
from marturia_verify import verify_receipt, verify_chain

# Single receipt
result = verify_receipt(receipt_dict, public_key_bytes)
if not result.valid:
    raise RuntimeError(result.reason)

# Chain — public_key must match the signing key for every receipt in the
# chain. If your chain crosses a key rotation, split it at the boundary
# and verify each segment with its own public key.
chain_result = verify_chain(receipts, public_key_bytes)
print(chain_result)  # VerifyResult(valid=True, reason=..., receipt_seq=27)
```

Both functions return a `VerifyResult` — a frozen dataclass with `.valid`, `.reason`, `.receipt_seq`, `.tenant_id`. It's also truthy/falsy, so `if not result:` works.

## Receipt format

A Marturia receipt is a JSON object with these fields:

| Field | Type | Notes |
|---|---|---|
| `payload_canonical_bytes` | hex or base64 string | The exact bytes that were signed. NOT the deserialised payload — the canonical-JSON-encoded version with sorted keys, no whitespace, embedded schema/meta. |
| `tenant_id` | int | The Marturia tenant the receipt belongs to. Bound into the hash. |
| `receipt_seq` | int | Per-tenant monotonic sequence (1, 2, 3, ...). Bound into the hash. |
| `prev_hash` | hex string or null | SHA-256 of the previous receipt in this tenant's chain. `null` when `receipt_seq == 1`. |
| `receipt_hash` | hex string | `sha256(prev_hash || payload_bytes || tenant_id_str || seq_str)`. The verifier recomputes this and rejects on mismatch. |
| `signature` | hex string | Ed25519 signature of `receipt_hash`, raw 64 bytes hex-encoded. |
| `kid` | string (optional) | Signing key ID at signature time. Informational. |

## What this verifier checks

For each receipt:

1. All required fields are present
2. The public key, signature, and stored `receipt_hash` are well-formed
3. The recomputed `receipt_hash` matches the stored one (catches body modification)
4. The Ed25519 signature verifies against the public key (catches forgery)

For a chain (`verify_chain`):

5. `receipt_seq` is contiguous ascending with no gaps
6. Each receipt's `prev_hash` matches the previous receipt's `receipt_hash` (catches insertion / reordering / removal)

What it does NOT check:

- **Witness cosignatures** on Merkle roots — those are a separate transparency layer (see Marturia design doc 05). This package verifies the per-tenant chain; cosignature verification will land in a future release.
- **Plan / billing / authorisation** — that's enforced at issuance time, not in the receipt itself.

## Why this exists

> Every other observability vendor stores audit logs in a database they alone control. They could rewrite history and you'd never know. Marturia signs each event into a hash-chained ledger using a per-tenant Ed25519 key. The chain itself is rolled into Merkle roots that can be cosigned by independent witness peers — including your own customers, your own auditors, or third-party witnesses you trust. **A compromised Marturia operator cannot forge history if any single witness cosigner is honest.**
>
> This package is the public verifier — anyone can check any receipt without our cooperation. That's the whole moat: cryptographic testimony you don't have to take our word for.

## Versioning

The receipt format is `_schema_v: 1` (visible in the `payload_canonical_bytes` payload). When Marturia eventually bumps to schema v2, this package will keep reading v1 receipts forever (they're permanent evidence) and add v2 support in a new minor release.

## License

MIT.
