| Internet-Draft | AI Attestation Receipts | July 2026 |
| Chueayen | Expires 24 January 2027 | [Page] |
This document specifies the on-the-wire format of an attestation receipt produced by an AI enforcement gateway at the moment it decides whether a large-language-model (LLM) call is permitted. A receipt binds that decision to a specific request under a published Ed25519 public key, so that a party who does not trust the gateway can still verify offline what was decided. The format is deliberately minimal, a fixed set of fields and a version-selected signature suite, chosen for the smallest possible independent verifier. It is intended for settings in which an operator-controlled log is not, on its own, sufficient evidence of the enforcement decision.¶
This Internet-Draft is submitted in full conformance with the provisions of BCP 78 and BCP 79.¶
Internet-Drafts are working documents of the Internet Engineering Task Force (IETF). Note that other groups may also distribute working documents as Internet-Drafts. The list of current Internet-Drafts is at https://datatracker.ietf.org/drafts/current/.¶
Internet-Drafts are draft documents valid for a maximum of six months and may be updated, replaced, or obsoleted by other documents at any time. It is inappropriate to use Internet-Drafts as reference material or to cite them other than as "work in progress."¶
This Internet-Draft will expire on 24 January 2027.¶
Copyright (c) 2026 IETF Trust and the persons identified as the document authors. All rights reserved.¶
This document is subject to BCP 78 and the IETF Trust's Legal Provisions Relating to IETF Documents (https://trustee.ietf.org/license-info) in effect on the date of publication of this document. Please review these documents carefully, as they describe your rights and restrictions with respect to this document.¶
AI systems that take or influence consequential actions are increasingly deployed in regulated settings. When such a decision is later questioned, the party being questioned is frequently also the party that produced the record of the decision. A log an operator controls does not, on its own, let an independent reviewer confirm what a model was asked and what the enforcement layer decided.¶
This document defines a compact receipt that an enforcement gateway signs at the moment it decides whether an LLM call proceeds. The receipt is verifiable offline by any holder of the issuer's public key, so the verifier need not trust the issuer's infrastructure at verification time.¶
Related work exists. [I-D.marques-asqav-compliance-receipts] defines a compliance profile of signed action receipts for AI agents, and [I-D.farley-acta-signed-receipts] defines signed decision receipts for machine-to-machine access control. This document is narrower: it specifies a minimal, fixed twelve-field receipt for the LLM enforcement-gateway case, with a version-selected signature suite, chosen for the smallest possible verifier.¶
The key words "MUST", "MUST NOT", "REQUIRED", "SHALL", "SHALL NOT", "SHOULD", "SHOULD NOT", "RECOMMENDED", "NOT RECOMMENDED", "MAY", and "OPTIONAL" in this document are to be interpreted as described in BCP 14 [RFC2119] [RFC8174] when, and only when, they appear in all capitals, as shown here.¶
A receipt is a single JSON object [RFC8259] with exactly the following top-level fields. Receipts MUST NOT contain additional top-level fields in this version. Verifiers MUST reject receipts containing unknown top-level fields.¶
| Field | Type | Description |
|---|---|---|
| v | integer | Format version. MUST be 1. |
| attestation_id | string | UUID version 4, unique per receipt. |
| trace_id | string | Issuer-assigned identifier for the LLM call. |
| org_id | string | Identifier of the subject organisation. |
| request_hash | string | SHA-256 hex digest of the canonicalised request body. 64 lowercase hex characters. |
| model | string | Provider-qualified model identifier. |
| outcome | string | One of the values in Section 3. |
| policy_applied | array | Lexicographically sorted array of ASCII policy identifiers. |
| cost_prevented_eur | number | Issuer estimate of spend avoided by a BLOCKED or SUPPRESSED outcome. Non-negative. MUST be 0 when not computed. |
| timestamp | string | RFC 3339 datetime with an explicit timezone offset. |
| public_key | string | base64url-encoded raw 32-byte Ed25519 public key, no padding. |
| signature | string | base64url-encoded 64-byte Ed25519 signature, no padding. Omitted from the canonical payload. |
The outcome field MUST be one of:¶
Enforcement passed all policies; the request proceeded to the provider.¶
Enforcement blocked the request before invoking the provider.¶
Enforcement detected a runaway condition and suppressed the call.¶
A synonym of ALLOWED retained for backward compatibility. New issuers SHOULD emit ALLOWED.¶
The canonical payload is produced by:¶
Removing the signature field, if present.¶
Serialising the remaining fields to JSON with all object keys sorted lexicographically and no whitespace between tokens.¶
Encoding the result as UTF-8, with non-ASCII characters emitted literally as UTF-8 and never as \uXXXX escapes (see Section 4.3).¶
Serialising every integer-valued number, including a float such as 1.0, as an integer with no decimal point or trailing zero, and every other number as the shortest decimal representation that round-trips to the same value.¶
A number whose shortest representation requires exponential notation, meaning a magnitude below 1e-4 or at or above 1e21, is outside the range that implementations serialise identically, because they disagree on exponent formatting. An issuer MUST NOT sign such a value directly; where one would arise it MUST first be rounded to a value inside the safe range, as a cost estimate is rounded to two decimal places. This canonicalisation aligns in intent with the JSON Canonicalization Scheme [RFC8785] but does not adopt its number serialisation; a later version may do so for full determinism across the exponential range.¶
The version field v identifies the complete cryptographic suite, not only the field format. In version 1 the suite is Ed25519 [RFC8032] over the canonical payload. The issuer signs the canonical payload bytes and places the base64url-encoded signature, without padding, in the signature field.¶
A verifier MUST select the signature algorithm from v and MUST NOT infer it from the length or contents of the signature field. A future version of this format may define a post-quantum suite; a verifier that does not implement the suite named by v MUST reject the receipt rather than guess.¶
The request_hash field is the SHA-256 digest, encoded as 64 lowercase hexadecimal characters, of the request body serialised by the canonicalisation of Section 4, including its number rule. This matters here in particular: a request body routinely carries non-integer sampling parameters such as temperature or top_p, so an issuer whose requests can contain numbers in the exponential range (see Section 4) SHOULD round them before hashing. The digest is computed over the request body as received from the caller, before any redaction, so that a verifier holding the original request can reproduce it independently. A verifier that does not hold the original request treats request_hash as an opaque commitment.¶
Strings MUST be serialised as literal UTF-8. Escaping non-ASCII characters as \uXXXX produces different canonical bytes and MUST NOT be done; only the escapes required by [RFC8259] are permitted. This rule exists because mainstream JSON serialisers disagree by default: some escape non-ASCII, some do not, and a receipt signed under one convention fails verification under the other while appearing valid within the issuer's own runtime. Issuers and verifiers MUST both emit literal UTF-8.¶
A verifier holding the issuer's trusted public key:¶
Confirms all required fields are present and no unknown fields exist.¶
Verifies the signature over the canonical bytes using the suite named by v and the trusted public key.¶
A verifier MUST reject a receipt whose embedded public_key does not match the public key it independently trusts for the issuer. Verifying only against the embedded key proves integrity, not issuer identity.¶
A receipt proves that the holder of the issuer's private key signed the stated enforcement decision over the stated request hash at the stated time. It does not, on its own, prove issuer identity; that requires the verifier to pin the issuer's public key out of band. A verifier that checks a receipt only against the public_key embedded in that receipt proves internal integrity but not that the receipt came from the expected issuer.¶
Receipts contain no plaintext prompt or response, only a SHA-256 request hash, so a receipt discloses no request content. A verifier cannot recover the request from a receipt, and a leaked receipt therefore does not expose prompt or response data.¶
Ed25519 is not post-quantum secure. An adversary with a cryptographically relevant quantum computer could forge signatures under an issuer key that was active before migration, which matters where audit retention, for example five to ten years, intersects that horizon. Two properties bound this. First, the SHA-256 request binding, and any receipt chain built on SHA-256, remain quantum-resilient tamper anchors, so a verifier can still detect alteration of past receipts. Second, because the version field selects the whole suite (see Section 4.1), a later version can introduce a post-quantum signature suite without changing the receipt structure, and receipts signed under different suites remain distinguishable by version. This document does not define such a suite.¶
This document has no IANA actions. A future revision may request registration of a media type for the receipt object.¶
Open-source reference verifiers implementing this format are published as "aqta-verify-receipt" on PyPI and npm.¶