Transparency log

Tamper-evident, even against us.

A signed receipt proves its own contents did not change. The transparency log proves something stronger: that the SET of receipts is append-only, that a specific receipt is in it, and that we did not quietly reorder or delete history. It is the same construction Certificate Transparency uses for the web's TLS certificates (RFC 6962).

How it works

Every signed receipt becomes a leaf in your organization's Merkle tree. The leaf isSHA-256(0x00 || event_id.integrity_hash), so it binds the receipt's identity to its content. A checkpoint(a Signed Tree Head) commits to the whole tree: its size, its root hash, an Ed25519 signature, and the hash of the previous checkpoint, so the sequence of heads is itself a tamper-evident chain.

  • Inclusion proof: a short audit path proving a receipt is committed under a given root.
  • Consistency proof: proof that a later root is an append-only extension of an earlier one, so nothing was rewritten in between.

Trees are per-organization, so tree size and ordering never leak across tenants. The Merkle math is the exact RFC 6962 construction, so a proof verifies with any standard CT verifier, not only ours.

The guarantee, precisely

The receipt's own Ed25519 signature proves its contents are unaltered. The log adds: your receipts form an append-only sequence, and any specific one is provably in it under a signed root. To make this hold even against Prova, save a checkpoint somewhere we do not control (your own storage, or a third-party witness). If we ever rewrote history, a consistency proof from your saved checkpoint to the current head would fail. That is the difference between “trust our database” and “the math does not lie.” We are precise about this: out of the box the log is append-only and signed; the external witness is what closes the last gap, and it is a one-line integration you control.

Trusted timestamp

A receipt binds when the decision happened (occurred_at) and when Prova signed it (received_at), but those are Prova attesting its own clock. An independent trusted timestamp binds a checkpoint to a time outside our control. Because every receipt has an inclusion proof into a checkpoint, one timestamp covers every receipt under that root. Opt-in and off by default, so a stock or air-gapped deploy is unchanged until you turn it on.

Two providers, one setting. Point PROVA_TSA_URL at an RFC 3161 Timestamp Authority (the eIDAS-style trusted timestamp an auditor recognizes), orPROVA_WITNESS_URL at an independent witness that co-signs the checkpoint with its own Ed25519 key. Each sealed checkpoint then carries its attestations on GET /api/v1/transparency/checkpoint.

# The checkpoint endpoint returns its trusted-time attestations.
curl "https://prova.cobound.dev/api/v1/transparency/checkpoint" \
  -H "Authorization: Bearer $PROVA_API_KEY"
#   -> { checkpoint, attestations: [ { kind: "rfc3161" | "witness", ... } ] }

# RFC 3161: the messageImprint is the checkpoint_hash. Verify the token against
# the TSA's published certificate chain, not against Prova.
openssl ts -verify -digest $CHECKPOINT_HASH -in token.tsr -CAfile tsa-ca.pem

# Witness: the co-signature is Ed25519 over the ASCII checkpoint_hash. Verify it
# against the witness's published public key, a party other than Prova.
echo "$WITNESS_SIG_HEX" | xxd -r -p > witness-sig.bin
printf '%s' "$CHECKPOINT_HASH" \
  | openssl pkeyutl -verify -pubin -inkey witness-pubkey.pem -rawin -sigfile witness-sig.bin

Verification is independent by construction: the RFC 3161 token checks against the TSA, the witness signature against the witness key, neither against Prova. This makes the time on a receipt provable, not merely asserted.

Verify a receipt

# 1. Seal the log (cron or on demand): append new receipts, sign a checkpoint.
curl -X POST https://prova.cobound.dev/api/v1/transparency/seal \
  -H "Authorization: Bearer $PROVA_API_KEY"

# 2. Get an inclusion proof for a receipt.
curl "https://prova.cobound.dev/api/v1/transparency/proof?event_id=$EVENT_ID" \
  -H "Authorization: Bearer $PROVA_API_KEY"
#   -> { leaf_index, leaf_hash, tree_size, root_hash, audit_path[], checkpoint }

# 3. Verify offline (RFC 6962): recompute the root from leaf_hash + audit_path,
#    check it equals checkpoint.root_hash, and verify the checkpoint signature
#    against the public key at /api/v1/keys/{key_id}. No need to trust Prova.

# 4. Later, prove nothing was rewritten between a saved checkpoint and now:
curl "https://prova.cobound.dev/api/v1/transparency/consistency?from=$OLD_SIZE&to=$NEW_SIZE" \
  -H "Authorization: Bearer $PROVA_API_KEY"

Reads (checkpoint, proof,consistency) need audit.read; sealing needs audit.ingest. Pull-triggered, with no background worker, so it runs the same on a managed deploy and air-gapped.

Why it matters

The signed receipt is the moat; the transparency log deepens it. A competitor can copy a dashboard. Reproducing an append-only, externally-witnessed, independently-verifiable log of every AI decision means re-architecting from the data model up. For the regulated buyer, it is the difference between an audit trail you are asked to trust and one a court could.