What a Receipt Proves, and What It Does Not
Most writing about AI verification stays at the level of promises. This post goes one level down. It walks through the artifact Cyberian issues for each inference, shows the three checks a third party can run on it without contacting us or the operator, and then states precisely what passing those checks establishes and what it does not.
The boundary matters as much as the mechanics. A verification artifact that overstates its own reach is worse than none, because it invites reliance where none is warranted.
The receipt
A receipt is a small structured record, not a log file. Conceptually it carries these fields:
{
"receipt_id": "rcpt_9f2a...c71d",
"issued_at": "2026-06-04T14:22:08Z",
"assurance_level": "independent spot-check",
"model_id": "BAAI/bge-large-en-v1.5",
"model_digest": "sha256:4b1e...a9f0",
"runtime": "onnxruntime, CPU, pinned options",
"input_digest": "sha256:e7c3...11b8",
"output_digest": "sha256:0d54...8aa2",
"batch_root": "9c84...f3e1",
"inclusion_path": ["..."],
"executor_id": "node_47",
"attestor_signature": "3045...be90"
}
Field names and values here are illustrative; the published schema is authoritative. Reading it:
model_digest,input_digestandoutput_digestare SHA-256 digests of the exact model artifact, the exact input and the exact output. A one-bit change in any of them produces an unrelated digest.model_idis a human-readable label. It is not the fact;model_digestis. More on that below.batch_rootcommits many jobs from the same batch to a single value, andinclusion_pathproves that this job is one of them.assurance_levelrecords how strongly this job was checked, which matters for what the receipt can claim.executor_ididentifies the party that ran the model.attestor_signatureis applied by a different party, the attestor, which did not run it.
That last separation is the rule the whole design rests on: the party that executes is never the party that attests.
Three checks anyone can run offline
Verification needs only three things: the receipt, the output you received, and the attestor's public key. It does not require network access to Cyberian, cooperation from the operator, or trust in either.
1. The output you hold is the output that was attested
Recompute the digest of the output bytes and compare it with the receipt:
import hashlib
def output_matches(output_bytes: bytes, receipt: dict) -> bool:
digest = "sha256:" + hashlib.sha256(output_bytes).hexdigest()
return digest == receipt["output_digest"]
If this fails, the output you hold is not the output the receipt covers. It was altered, substituted or re-serialized along the way.
Digests are computed over a canonical byte encoding. For structured outputs such as embedding vectors, the encoding, meaning byte order, float width and serialization format, is part of the specification. Two logically equal outputs serialized differently will not match, and that is intended: the check is about the exact bytes, not about similarity.
2. The job belongs to the committed batch
The leaf for this job is the digest of its canonical record. Walk the inclusion path from that leaf to the root and compare:
import hashlib
def sha256(data: bytes) -> bytes:
return hashlib.sha256(data).digest()
def included_in_batch(leaf_hash: bytes, path: list, batch_root: bytes) -> bool:
# path is a list of (sibling_hash, side) pairs, side is "left" or "right"
node = leaf_hash
for sibling, side in path:
node = sha256(sibling + node) if side == "left" else sha256(node + sibling)
return node == batch_root
If this fails, the job was not part of what the attestor committed to for that batch.
Merkle conventions differ between systems, most importantly in whether leaves and interior nodes are hashed with distinct prefixes, which prevents an interior node from being passed off as a leaf. The specification fixes the convention. The logic above is the same either way.
3. The attestation is authentic
Verify the attestor's signature over the canonical encoding of every other field, using the attestor's published public key:
def attestation_is_authentic(receipt: dict, attestor_public_key) -> bool:
signed_fields = {k: v for k, v in receipt.items() if k != "attestor_signature"}
message = canonical_encode(signed_fields) # encoding defined by the spec
signature = bytes.fromhex(receipt["attestor_signature"])
return verify(attestor_public_key, signature, message) # algorithm per the published key
If this fails, the receipt was not issued by the attestor, or it was modified after it was.
Everything in this check depends on where the public key came from. A key delivered alongside the receipt proves nothing, because whoever forged the receipt could forge the key with it. The key has to come from a trust anchor you can reach independently of both the receipt and the operator.
What passing all three establishes
Together, the three checks establish that:
- the output you hold is byte for byte the output the receipt describes;
- that output, bound to a specific model digest and a specific input digest, was committed as part of a specific batch;
- the binding was signed by the attestor rather than the executor, and nothing in it has changed since.
That is integrity and attribution of a commitment. In the vocabulary of an earlier post, it establishes that the record is unaltered. Integrity, completeness and truth are separated properly in Three properties of an AI evidence record.
A perfectly signed commitment to a false claim still verifies.
What independent re-execution adds
Signature and inclusion checks cannot, on their own, establish that the declared model on the declared input actually produces the declared output. That property comes from the attestor doing the work again.
In the configuration live today, the attestor re-executes an unpredictable sample of each job on its own infrastructure and compares the result with the committed output. Where the execution path is bit-reproducible, such as inference pinned to CPU, the comparison is exact. Where floating-point nondeterminism makes bit equality unrealistic, the comparison uses a tolerance instead.
Two consequences follow, and both should be stated plainly.
Sampled re-execution is economic deterrence, not proof of every step. The executor cannot predict which work will be re-checked, so cheating anywhere risks detection. That makes cheating a losing bet, not an impossible one.
And the strength of a receipt's claim about truth depends on the assurance level of the job it came from, which is why the receipt records that level. Integrity is established identically for every receipt. Truth is established to the degree the assurance level states.
What a receipt does not establish
For engineers the boundary is sharper than the one usually drawn for buyers:
- That the model is the one you meant. A receipt proves a model digest. The
model_idlabel is only as reliable as your mapping from names to digests. If you care which model ran, keep your own record of the digests you approved and compare against it. - That the output is correct. A receipt faithfully binds what the model produced, errors included. It makes no claim about accuracy, fairness or fitness for purpose.
- That every inference was receipted. A job never submitted for verification has no receipt. Completeness is a property of how receipts are required in a workflow, not of any single receipt.
- That the data stayed confidential. Receipts carry digests, not content, but re-execution means the attestor processes the work it samples, under contract. If confidentiality is the requirement, this is not the property that provides it.
- Anything about policy. Whether the decision should have been made at all is a question for a different layer.
Why the artifact stays small
It would be easy to make a receipt say more: attach explanations, confidence scores, policy verdicts. Every one of those additions would be a claim the receipt cannot itself substantiate. The receipt stays small so that each field in it is something a third party can check without trusting anyone, and nothing in it asks for trust it has not earned.
The compliance-and-risk framing of this same idea — why a self-kept log stops being evidence exactly when you need it — is in the companion essay You Have Logs. Logs Can Be Edited.