TL;DR
Enterprises can verify millions of Marturia receipts without checking every signature. Use Merkle-root verification for O(log N) proofs on any receipt, run full-chain replay only when required, and rely on statistical sampling for continuous assurance. A simple Python script plus a CI step keeps the entire tenant chain honest at production scale.

The verification problem at scale

A busy tenant can emit tens of thousands of receipts per day. Each receipt carries an Ed25519 signature, a SHA-256 hash link to its predecessor, and (when published) a Merkle root anchored on a public witness. Verifying one receipt is cheap; verifying every receipt for every tenant every day is not. The goal is to choose the right verification strategy for the risk tolerance and latency budget of the workload.

The cheap path: Merkle anchor verification

Once a Merkle root is published and witnessed, any receipt inside that batch can be proven with a short inclusion proof. The verifier only needs:

  1. The published root (already signed by the witness network).
  2. The receipt itself.
  3. The O(log N) sibling hashes that reconstruct the root.

This reduces the cost of proving any single receipt from O(N) to O(log N) and removes the need to re-verify every preceding receipt.

The thorough path: full-chain replay

Full replay walks the hash chain from the first receipt to the latest, checking:

Replay gives the strongest guarantee but scales linearly with the number of receipts. It is normally reserved for initial onboarding, regulatory audits, or when a sampling check flags an anomaly.

Sampling-based audit

Random spot-checks combined with Merkle-root verification deliver cryptographic assurance at low cost. Because every receipt is committed to a Merkle tree, an auditor can request a small random subset (for example 0.1 %) and still obtain a high probability of detecting any tampering that affects more than a few receipts. The remaining receipts are covered by the single root signature.

Python script for bulk verification

The example below uses the Marturia search API to fetch every receipt for a tenant, verifies each signature and hash link, and prints a concise report.

#!/usr/bin/env python3
import requests
import ed25519
import hashlib
import json
from datetime import datetime

TENANT = "acme-prod"
API = "https://api.marturia.dev/v1"
VERIFY_KEY = ed25519.VerifyingKey(open("tenant-acme.pub").read())

def fetch_all_receipts(tenant):
    receipts = []
    cursor = None
    while True:
        params = {"tenant": tenant, "limit": 1000}
        if cursor:
            params["cursor"] = cursor
        r = requests.get(f"{API}/receipts/search", params=params, timeout=30)
        r.raise_for_status()
        batch = r.json()["receipts"]
        receipts.extend(batch)
        cursor = r.json().get("next_cursor")
        if not cursor:
            break
    return receipts

def verify_receipt(r):
    sig = bytes.fromhex(r["signature"])
    msg = json.dumps(r["payload"], sort_keys=True).encode()
    try:
        VERIFY_KEY.verify(sig, msg)
    except ed25519.BadSignatureError:
        return False
    if r.get("prev_hash"):
        expected = hashlib.sha256(
            json.dumps(r["prev_payload"], sort_keys=True).encode()
        ).hexdigest()
        if expected != r["prev_hash"]:
            return False
    return True

def main():
    receipts = fetch_all_receipts(TENANT)
    failures = []
    for r in receipts:
        if not verify_receipt(r):
            failures.append(r["id"])
    print(f"Checked {len(receipts)} receipts at {datetime.utcnow().isoformat()}Z")
    if failures:
        print("FAILURES:", failures)
        exit(1)
    print("All receipts verified successfully")

if __name__ == "__main__":
    main()

Run the script from a scheduled job or CI pipeline; it exits non-zero on any failure so downstream steps can be blocked.

CI integration

Add the verification step to your audit-trail release pipeline:

# .github/workflows/audit.yml
- name: Verify tenant chain
  run: |
    python3 verify_tenant.py --tenant acme-prod --threshold 0.001
  env:
    MARTURIA_API_KEY: ${{ secrets.MARTURIA_API_KEY }}

Fail the build if the script reports any invalid receipt or if the sampled Merkle proofs do not reconstruct the published root.

Performance characteristics

Ed25519 verification runs at roughly 10 000 signatures per second on a single modern core. Verifying one million receipts therefore takes about 100 seconds of CPU time. Parallelizing across cores or machines reduces wall-clock time linearly. Merkle-proof verification is orders of magnitude faster because only the root signature and a logarithmic number of hashes are checked.

Trade-off diagram

Lowest cost
Statistical assurance

O(log N) per receipt

Highest assurance
O(N) cost

Sampling + Merkle root

Daily CI

Single Merkle proof

On-demand audit

Full chain replay

Regulatory exam

Production decision