SPECIFICATION · AXIA.RECEIPT.V1
Verification Receipt (axia.receipt.v1)
Frozen normative specification of the Axia verification receipt: canonical payload, encoding, lifecycle semantics, and signature scope.
0. Status
This document is FROZEN. The on-the-wire receipt format described here is part of the public protocol surface. Any breaking change to the canonical payload, encoding, or signature scope MUST be released as a new profile identifier (e.g. axia.receipt.v2) and MUST NOT reuse axia.receipt.v1.
1. Definition
A verification receipt is a notarized observation produced by an Axia verifier at a specific point in time, recording the lifecycle state of an identity and signing key, the confidence band of the verification, and an optional Merkle checkpoint binding.
A receipt is NOT a claim of factual accuracy of the underlying content. It is a cryptographic statement of the form: "At time T, the verifier observed state S for content C, and signed that observation."
2. Fields
2.1 Wire schema
2.2 Encoding rules
- All hash and key material MUST be lowercase hexadecimal.
- verified_at MUST be UTC, expressed in RFC 3339 with the Z suffix and millisecond precision.
- checkpoint_root MUST be either a 64-character hex SHA-256 or the JSON null. Empty string MUST NOT appear in the wire form.
- Receipt JSON SHOULD be served with stable key ordering, but verifiers MUST rebuild the canonical payload from fields, not re-serialize the document.
3. Canonical payload
3.1 Form
The canonical payload is a single UTF-8 string built by joining the following fields in this exact order with the ASCII pipe character | (0x7C):
Where checkpoint_root_or_empty is the lowercase hex root if present, or the empty string if the receipt's checkpoint_root is null.
3.2 Null handling
Only checkpoint_root may be null. When null, the canonical form contributes an empty segment between the surrounding pipes (i.e. ...|none|). Verifiers MUST NOT emit the literal string "null".
3.3 Byte-perfect example
3.4 Hashing
The receipt's payload_hash MUST equal SHA-256 of the canonical payload's UTF-8 byte representation, encoded as 64-character lowercase hexadecimal.
4. Signature scope
The Ed25519 signature in signature MUST be computed over the raw bytes of payload_hash (32 bytes, the binary SHA-256 digest), NOT over the JSON document or the canonical payload string.
Verifiers MUST NOT include in the signed payload any of the following:
- Mutable database fields (e.g. trust score, ranking, observation counts).
- Joined enrichment data (publisher display name, domain WHOIS, etc.).
- UI-derived strings or human-readable labels.
- Anything that is not part of the seven canonical-payload fields.
This scoping decision is intentional: a receipt commits exclusively to a minimal, machine-stable provenance state.
5. Lifecycle semantics
5.1 Temporal trust
A receipt encodes state at time of verification. A receipt that was valid when produced remains cryptographically valid forever, but the underlying lifecycle may change. Verifiers and consuming UIs SHOULD distinguish:
- Cryptographically valid — receipt signature verifies against its embedded public key.
- Currently trusted — the identity and key referenced by the receipt are still active at the moment of consumption.
5.2 Status semantics
- identity_status = active — the publishing identity was governed and not revoked at verified_at.
- identity_status = revoked — the identity had been revoked before verified_at.
- identity_status = anonymous — the content was signed without an identity binding.
- key_status = active — the signing key was the current active key at verified_at.
- key_status = rotated — the key was still recognized but a successor existed.
- key_status = revoked — the key had been explicitly revoked.
6. Verification procedure
- Reject if profile is present and not axia.receipt.v1.
- Reject if algorithm is present and not ed25519.
- Rebuild the canonical payload string from fields per §3.1.
- Compute SHA-256 of the canonical payload bytes; compare to payload_hash. Reject on mismatch.
- Decode signature, public_key, payload_hash from hex.
- Ed25519-verify signature over the 32-byte payload_hash using public_key.
- Return the verification outcome and the rebuilt canonical payload hash.
The reference implementation lives in protocol/sdk/core.ts and is published as @axia/receipt-verify.
7. Test vectors
Conformance test vectors are published under /protocol/test-vectors/receipt-v1/ and MUST all pass for any implementation claiming compatibility:
- valid-active.json — fully active identity and key.
- valid-rotated.json — key rotated after signing; receipt still valid.
- revoked-identity.json — identity revoked at verification time.
- revoked-key.json — key revoked at verification time.
- tampered-payload.json — payload_hash mutated; verification MUST fail.
- malformed.json — missing fields; verification MUST fail with malformed_receipt.
8. Disclaimers
A receipt verifies provenance and signing history. It does not determine the factual accuracy of the underlying content, the human authorship of the content, or the absence of AI involvement. Implementations and consuming UIs MUST NOT use receipt data to assert any of those properties.