DEV Community

Cover image for Cryptographic Proof That Your LLM Never Saw Real Data
CloakLLM
CloakLLM

Posted on

Cryptographic Proof That Your LLM Never Saw Real Data

Cryptographic Proof That Your LLM Never Saw Real Data

Every PII protection tool makes the same promise: "We sanitized it before sending." But promises aren't proof. When a regulator asks you to demonstrate that patient names never reached OpenAI's servers, "trust us" isn't an answer.

We just shipped CloakLLM v0.3.2 with cryptographic attestation - Ed25519-signed certificates that mathematically prove sanitization happened. Here's how it works, why it matters, and how to use it.


The Problem: Trust Without Verification

Most PII middleware operates on trust. You install it, it sanitizes prompts, and you believe it did its job. Your audit log says "sanitized 3 entities at 14:30:00." But that log is just text. Anyone with file access can edit it. Nothing ties the log entry to the actual data that was processed.

This creates three gaps:

Gap 1: No proof of execution. Your compliance team can show the tool is installed. They can't prove it was running when a specific prompt was sent.

Gap 2: No tamper evidence on individual operations. Hash-chained audit logs prove the chain wasn't modified after the fact. But they don't prove what was sanitized - only that something was logged.

Gap 3: No cross-system verification. If a downstream execution layer wants to confirm that PII was handled before it processes an action, there's no machine-readable artifact to check.

The EU AI Act (Article 12, enforcement begins August 2, 2026) requires audit logs that regulators can mathematically verify. Gap 2 is the one that will fail an audit.


The Solution: Sanitization Certificates

Starting in v0.3.2, every sanitize() call can produce an Ed25519-signed certificate. The certificate contains:

  • Input hash - SHA-256 of the original text (proves what was processed)
  • Output hash - SHA-256 of the sanitized text (proves what was produced)
  • Entity count - how many PII entities were detected
  • Categories - breakdown by type (EMAIL: 2, PERSON: 1, SSN: 1)
  • Detection passes - which detection methods ran (regex, NER, LLM)
  • Mode - tokenize (reversible) or redact (irreversible)
  • Timestamp - ISO 8601
  • Key ID - identifies which signing key produced the certificate
  • Nonce - UUID4 preventing replay attacks
  • Signature - Ed25519 signature over the canonical JSON of all fields above

The certificate is attached to the token map returned by sanitize(). It's also hashed into the audit log entry, binding the certificate to the chain.


How It Works

Step 1: Generate a Signing Key

from cloakllm import DeploymentKeyPair

keypair = DeploymentKeyPair.generate()
keypair.save("./keys/signing_key.json")
Enter fullscreen mode Exit fullscreen mode

This produces an Ed25519 keypair. The private key signs certificates. The public key verifies them. You generate it once per deployment and keep the private key secure.

Step 2: Configure the Shield

from cloakllm import Shield, ShieldConfig

shield = Shield(ShieldConfig(
    attestation_key=keypair
))
Enter fullscreen mode Exit fullscreen mode

Or load from a file:

shield = Shield(ShieldConfig(
    attestation_key_path="./keys/signing_key.json"
))
Enter fullscreen mode Exit fullscreen mode

Or from an environment variable:

export CLOAKLLM_SIGNING_KEY_PATH=./keys/signing_key.json
Enter fullscreen mode Exit fullscreen mode

Step 3: Sanitize and Get the Certificate

sanitized, token_map = shield.sanitize(
    "Email john@acme.com about Sarah Johnson's medical records"
)

cert = token_map.certificate
Enter fullscreen mode Exit fullscreen mode

The certificate now contains a signed attestation of what happened. You can serialize it:

cert_dict = cert.to_dict()
# {
#   "version": "1.0",
#   "timestamp": "2026-03-15T10:30:00Z",
#   "input_hash": "sha256:9f86d081...",
#   "output_hash": "sha256:a3f2b1c4...",
#   "entity_count": 3,
#   "categories": {"EMAIL": 1, "PERSON": 1, "MEDICAL": 1},
#   "detection_passes": ["regex", "ner"],
#   "mode": "tokenize",
#   "key_id": "ed25519:7b2a...",
#   "nonce": "a1b2c3d4-e5f6-...",
#   "signature": "base64:..."
# }
Enter fullscreen mode Exit fullscreen mode

Step 4: Verify

Anyone with the public key can verify:

assert cert.verify(keypair.public_key)
assert shield.verify_certificate(cert)
Enter fullscreen mode Exit fullscreen mode

If a single byte of the certificate has been modified, verification fails. The signature covers a canonical JSON serialization of all fields, so field reordering doesn't break verification.


Batch Attestation with Merkle Trees

Single-text certificates are straightforward. But what about sanitize_batch() with 50 texts? You don't want 50 separate certificates - that's expensive and hard to manage.

CloakLLM uses Merkle trees for batch attestation. Instead of hashing each text individually into the certificate, we compute:

  1. A Merkle root of input hashes - one hash representing all original texts
  2. A Merkle root of output hashes - one hash representing all sanitized texts

The batch certificate contains these two roots instead of individual hashes. One signature covers the entire batch.

texts = [
    "Email john@acme.com",
    "SSN 123-45-6789",
    "Call Sarah at 555-0100"
]
sanitized_texts, token_map = shield.sanitize_batch(texts)

cert = token_map.certificate        # single certificate for entire batch
merkle_tree = token_map.merkle_tree  # Merkle tree with proofs
Enter fullscreen mode Exit fullscreen mode

To verify that a specific text was part of the batch:

import hashlib
from cloakllm import MerkleTree

leaf = hashlib.sha256(texts[0].encode()).hexdigest()
proof = merkle_tree["input"].proof(0)
assert MerkleTree.verify_proof(leaf, proof, merkle_tree["input"].root)
Enter fullscreen mode Exit fullscreen mode

This is the same data structure used in blockchain systems and certificate transparency logs. It lets you prove the inclusion of a single item without revealing the others.


Cross-Language Verification

Certificates are fully portable between Python and JavaScript. The canonical JSON serialization and Ed25519 signature format are identical in both SDKs.

Sign in Python:

from cloakllm import Shield, ShieldConfig, DeploymentKeyPair

keypair = DeploymentKeyPair.generate()
shield = Shield(ShieldConfig(attestation_key=keypair))
sanitized, token_map = shield.sanitize("Email john@acme.com")
cert_dict = token_map.certificate.to_dict()
public_key_hex = keypair.public_key_hex
Enter fullscreen mode Exit fullscreen mode

Verify in JavaScript:

const { SanitizationCertificate, DeploymentKeyPair } = require('cloakllm');

const cert = SanitizationCertificate.fromDict(certDict);
const publicKey = DeploymentKeyPair.fromPublicKeyHex(publicKeyHex);
assert(cert.verify(publicKey));
Enter fullscreen mode Exit fullscreen mode

This matters for architectures where the sanitization layer and the verification layer run in different languages or services.


Why Ed25519?

We chose Ed25519 over RSA or ECDSA for three reasons:

  1. Deterministic signatures. Same input always produces the same signature. No nonce-related vulnerabilities.
  2. Small keys and signatures. 32-byte public key, 64-byte signature. Certificates stay compact.
  3. Fast. Ed25519 verification is roughly 60x faster than RSA-2048 for single-signature verification.

The JavaScript SDK uses Node.js built-in crypto module - zero additional dependencies. The Python SDK supports either pynacl or cryptography as an optional dependency.

pip install cloakllm[attestation]  # installs pynacl
Enter fullscreen mode Exit fullscreen mode

What This Means for EU AI Act Compliance

Article 12 of the EU AI Act requires that high-risk AI systems maintain logs enabling traceability of how the system operates. Enforcement begins August 2, 2026. Non-compliance can result in fines up to 7% of global annual revenue.

CloakLLM's audit chain already provides hash-linked logs. Attestation certificates add a stronger guarantee: each sanitization operation is individually signed, and the signature binds the operation's inputs, outputs, and metadata into a single tamper-evident artifact.

For an auditor, this means:

  • Existence proof - the certificate proves a sanitization operation occurred at a specific time
  • Integrity proof - the signature proves the certificate hasn't been modified
  • Content proof - the input/output hashes prove what was processed, without revealing the actual PII
  • Batch proof - Merkle proofs demonstrate individual text inclusion without exposing the full batch

What This Means for Execution Governance

There's an emerging architectural pattern in agentic AI systems: execution boundaries that decide whether a proposed action is allowed to proceed. These boundaries evaluate intent, authority, and system state before committing an action.

Sanitization certificates add a data-layer signal to this decision. An execution boundary can now ask: "Was the input to this reasoning step provably sanitized?" and verify the answer cryptographically - without trusting the sanitization layer itself.

This is the difference between a policy that says "PII must be removed" and an architecture that enforces it with mathematical proof.


Try It

pip install cloakllm[attestation]==0.3.2
npm install cloakllm@0.3.2
Enter fullscreen mode Exit fullscreen mode

Generate a key, configure the shield, and every sanitize() call produces a signed certificate. The certificate is attached to the token map, hashed into the audit log, and verifiable in any language.

Full documentation: cloakllm.dev
Source: github.com/cloakllm/CloakLLM


CloakLLM is open source (MIT). Built by Ziv Chen.

Top comments (0)