Skip to content

VeritasActa/commitment-receipts

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

1 Commit
 
 
 
 
 
 
 
 

Repository files navigation

Commitment-Based Receipts

Selective-disclosure extension for draft-farley-acta-signed-receipts. Demonstrates SHA-256 field commitments, algorithm-agile signing, chain integrity without openings, and composition with longfellow-zk/libzk for privacy-preserving principal bindings.

Conceptually aligned with SD-JWT (salt-hash selective disclosure for JWTs), adapted for chained audit logs rather than bearer tokens.

The problem

An AI agent's audit trail records what happened. A regulator needs to verify the trail is intact. But revealing the full trail also reveals internal operations, business logic, and potentially personal data.

Today's receipt format signs cleartext fields. Anyone who holds a receipt sees everything: principal, action, resource, decision, policy. The only privacy primitive is the VOPRF issuer-blind nullifier, which hides the signer's identity but not the signed content.

This is a structural tension between two requirements:

  • EU AI Act Article 12: Log everything. Complete, tamper-evident records.
  • GDPR data minimization: Reveal only what is necessary for the purpose.

Cleartext receipts satisfy Article 12 but violate minimization. Omitting fields satisfies minimization but violates Article 12.

The architecture: committed fields with selective disclosure

Each receipt field is independently committed using SHA-256:

commitment = SHA-256(salt || field_value)

The salt is prepended (following the SD-JWT convention) so the commitment is domain-separated by random bytes before any attacker-controlled value bytes.

The receipt payload contains only the commitments, never cleartext:

{
  "type": "scopeblind.receipt.committed.v1",
  "commitments": {
    "principal":  "a8f3c9d2...",
    "action":     "7b2e1d4f...",
    "resource":   "4c9a3f88...",
    "decision":   "e1b7f2a3...",
    "context":    "d5c8e9f1...",
    "policy_id":  "9d4e6abc..."
  },
  "sequence": 47,
  "timestamp": "2026-04-22T14:30:00Z",
  "previousReceiptHash": "sha256:...",
  "signature": "ed25519:...",
  "publicKey": "ed25519:..."
}

Selective disclosure

To reveal a field to an auditor, the receipt owner provides the cleartext value and its salt. The auditor verifies:

SHA-256(salt || disclosed_value) == commitment

If the hash matches, the disclosed value is authentic. Other fields remain committed.

This is designed to address both requirements simultaneously:

  • Article 12: Complete records exist (all fields are committed and chain-linked). The chain is tamper-evident and verifiable without openings.
  • GDPR minimization: Only the fields the auditor needs are disclosed. The rest remain cryptographically hidden.

Why SHA-256 and not BBS+?

BBS+ signatures provide native selective disclosure but are pairing-based (BLS12-381) and not post-quantum resistant. SHA-256 commitments:

  • Are post-quantum safe (128-bit security against quantum attacks).
  • Decouple selective disclosure from the signature scheme entirely.
  • Work with any outer signature (Ed25519 today, ML-DSA tomorrow).
  • Have no exotic dependencies (every platform has SHA-256).

ZK migration path

SHA-256 commitments support selective disclosure (opening individual fields). If future use cases require arithmetic proofs over committed values without opening them (e.g., "prove the committed timestamp is within business hours without revealing the exact time"), the commitment primitive can migrate to Poseidon2 or Pedersen commitments without changing the receipt envelope structure.

Algorithm agility

The outer signature covers the commitment vector. The signature scheme is structurally independent of the commitment layer. Swapping Ed25519 for ML-DSA (FIPS 204) changes one function call without touching the commitment structure, chain logic, or disclosure mechanism.

Composition with libzk

draft-google-cfrg-libzk proves properties of existing credentials (mdoc, JWT, W3C VC) without revealing the credential. The two drafts compose at the commitment layer:

  1. The receipt's commitment_principal commits to the holder's identity.
  2. Instead of opening the commitment with a cleartext principal, the holder provides a libzk proof that the committed value satisfies a predicate (e.g., "age >= 18 AND EU resident").
  3. The verifier checks:
    • (a) libzk proof is valid (libzk verifier)
    • (b) proof's context binding matches this receipt's hash (anti-replay)
    • (c) proof attests the committed principal satisfies the predicate
    • (d) receipt signature is valid over the full commitment vector
    • (e) receipt chain is intact

Context binding (anti-replay)

A valid libzk proof must be bound to the specific receipt it was created for. Otherwise, an attacker could extract a proof from one receipt and replay it in another. The proof's public inputs should include the receipt's commitment vector hash, so the verifier can confirm the proof was generated for this exact receipt.

Curve independence

No in-circuit signature verification is required. The receipt's signing curve (Ed25519 or ML-DSA) and libzk's proving curve (ECDSA-P256 for existing credentials) are completely independent. The binding is a hash-layer reference, not a curve-layer operation.

Salt management

Per-field salts are derived deterministically via HMAC-SHA256:

salt = HMAC-SHA256(masterSecret, "commitment-receipt:{sequence}:{fieldName}")

The receipt owner stores one master secret, not individual salts. The master secret MUST be stored securely and separately from the receipts.

Threat model

  • Master secret compromise: all historical salts are derivable, making all past commitments openable. Equivalent to retroactive cleartext. Mitigation: hardware-backed key storage (HSM, TPM, Secure Enclave).
  • Individual salt leak: only that specific field of that specific receipt becomes openable. No cascading exposure.
  • Master secret loss: all commitments become permanently unopenable. This is a feature for GDPR erasure (see below) but a severe hazard if unintentional. Mitigation: key backup procedures.

Future versions may support forward-secret salt derivation (per-epoch key rotation via HKDF) so that compromise of the current key does not expose historical salts.

GDPR Article 17 (right to erasure)

When a data subject invokes the right to erasure:

  1. Destroy the master secret (or the per-subject derivation key).
  2. All commitments for that subject become permanently unopenable.
  3. The chain remains intact and verifiable (chain hashes are over commitments, not cleartext).
  4. An auditor can verify: "a receipt existed at this position with a valid signature and chain link, but its contents are cryptographically irrecoverable."

This is a structural guarantee, not an operational promise.

Running the demo

cd examples/commitment-receipts
npm install
npm run demo

The demo creates a chain of 3 committed receipts, verifies chain integrity without revealing any field values, demonstrates selective disclosure to a simulated auditor, demonstrates tamper detection when a false value is claimed, and stubs in the libzk proof binding surface with context binding for anti-replay.

Trade-offs

Property Cleartext receipts Committed receipts
Receipt size ~200-400 bytes ~500-700 bytes (32-byte hash per field)
Verification Single-pass Two-pass (signature + openings)
Debugging Inspect receipt directly Need salts to inspect contents
Privacy None (all fields visible) Full (selective disclosure per field)
PQ safety (commitments) N/A Yes (SHA-256)
PQ safety (signature) Depends on scheme Depends on scheme (decoupled)
Salt management None Must protect master secret
GDPR erasure Delete data Destroy master secret (provable)

Both modes should coexist. Cleartext is the right default for the Transparent tier. Committed mode is for Auditable and High-Assurance tiers where privacy-preserving compliance is required.

Relationship to draft-farley-acta-signed-receipts

This is an optional commitment envelope for the receipt format. The next revision of the draft will define commitment mode as an opt-in extension alongside the existing cleartext format. The wire format, chain structure, and verification semantics are fully backwards compatible.

License

Apache-2.0

About

Commitment-based selective-disclosure receipts. SHA-256 field commitments, algorithm-agile signing, chain integrity, SD-JWT-aligned salt-hash pattern, libzk composition surface.

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

 
 
 

Contributors