Server-side ed25519 receipt verifier
emem_verify_receiptVerify signed receipts server-side when the in-browser path is blocked or for audits. Rebuilds canonical preimage, checks ed25519 signature and Merkle proof, and reports why a receipt is invalid.
Instructions
Verify a signed receipt envelope server-side: rebuilds the canonical preimage under the rule the receipt's OWN preimage_version names (v2, current: tagged length-prefixed segments plus a segment binding the inclusion proof; v1: the same without that segment; absent/0: the legacy request_id | served_at | primitive | cells, | fact_cids, concatenation), runs ed25519 over the embedded pubkey + signature, and returns {valid, reason, failure_detail, signature_valid, merkle_proof_valid, signer_pubkey_b32, preimage_blake3_hex}. A RECEIPT IS BYTE-FOR-BYTE OR NOTHING: v2 binds the proof so it cannot be stripped in transit, and the cost of that is that any reshaping — dropping a field, re-keying it, summarising it — invalidates the signature by design and looks exactly like tampering. Use when the in-browser /verify path is blocked (CDN offline, agent runtime has no crypto) or when you want a server-side audit of a third-party receipt. Memory algebra: the verify operation (https://emem.dev/docs/model.html).
When to use: Pass a receipt object EXACTLY as returned by the read primitive, whole and unmodified (signature can be byte[] or sig_b32; pubkey can be byte[] or responder_pubkey_b32, the verifier tolerates those two spellings and nothing else). Do not omit merkle_proof, and do not reshape any field: under preimage_version 2 that returns signature_valid: false on data nobody tampered with. Exactly two omissions reach this failure rather than a 400: merkle_proof and preimage_version (whose absence deserialises to 0 and silently selects the v0 rule, so the inclusion proof still walks while the signature reads as forged). When this responder holds the cited fact it can tell reshaping from tampering and says so — reason: receipt_reshaped_after_signing with a failure_detail naming the field, instead of signature_invalid — but it never accepts such a receipt, and an offline verifier has no way to make that distinction at all. Optionally override pubkey_b32 to assert verification against a specific signer. Returns 200 with valid: false when the signature fails, never 4xx for a structurally-well-formed bad signature.
Example arguments: {"receipt":{"primitive":"recall","served_at":"2026-05-14T12:00:00Z","request_id":"req-1","cells":["damO.zb000.xUti.zde78"],"fact_cids":["qbq2dy7adyuvozs7s3gqg5jnpkcwq2duegltjyhbxsivuqbpjofq"],"signature":[1,2,3],"responder_pubkey":[4,5,6]}}
Input Schema
| Name | Required | Description | Default |
|---|---|---|---|
| facts | No | The fact value(s) you intend to rely on. Each is content-addressed and checked for membership in the receipt's `fact_cids`, so a genuine receipt presented beside a tampered fact answers `valid:false` / `fact_mismatch`. Omit it and only the signature is checked, which a doctored fact survives. | |
| receipt | Yes | The signed receipt envelope (as returned by any read primitive). Must carry primitive/served_at/request_id/cells/fact_cids and either `signature` byte[] + `responder_pubkey` byte[] or their b32 string forms. | |
| pubkey_b32 | No | Optional explicit responder pubkey (base32). When omitted, uses the receipt's embedded pubkey/responder fields. | |
| current_responder_epoch | No | The responder key epoch you currently trust, from `/v1/manifests`. Produces an advisory `key_epoch_advisory` comparison against the receipt's epoch; a mismatch is reported, never rejected. |