Self-Verifiable Retention Chain for Payment Receipts
draft-hopley-x402-retention-chain-07
This document is an Internet-Draft (I-D).
Anyone may submit an I-D to the IETF.
This I-D is not endorsed by the IETF and has no formal standing in the
IETF standards process.
| Document | Type | Active Internet-Draft (individual) | |
|---|---|---|---|
| Author | MR CHRISTOPHER HOPLEY | ||
| Last updated | 2026-06-25 | ||
| RFC stream | (None) | ||
| Intended RFC status | (None) | ||
| Formats | |||
| Stream | Stream state | (No stream defined) | |
| Consensus boilerplate | Unknown | ||
| RFC Editor Note | (None) | ||
| IESG | IESG state | I-D Exists | |
| Telechat date | (None) | ||
| Responsible AD | (None) | ||
| Send notices to | (None) |
draft-hopley-x402-retention-chain-07
Independent Submission C. Hopley
Internet-Draft AlgoVoi
Intended status: Informational 25 June 2026
Expires: 25 December 2026
Self-Verifiable Retention Chain for Payment Receipts
draft-hopley-x402-retention-chain-07
Abstract
This document specifies eight cryptographic constructions for
self-verifiable agentic payment records. The first, the Retention
Chain Reference (retention_chain_ref), enables tamper-evident audit
chains linking payment receipts without requiring external
infrastructure. The second, the Payment Action Lifecycle, defines
a content-addressed model for the exactly-once execution of payment
actions, including an action reference primitive (action_ref) and a
per-state transition hash (transition_hash) with a provable SKIP-on-
retry idempotency guarantee. The third, the Settlement-Action
Binding (binding_ref), binds a settled payment to the verified agent
action it paid for and to the retention chain entry recording it, so
that a settlement attestation proves not only that a payment occurred
but which verified action it corresponds to. The fourth, the Policy
Binding (policy_bound_ref), binds a content-addressed snapshot of the
governing policy to an existing binding or chain reference, so that a
decision is verifiable against the exact policy version that admitted
it and a policy rotation is detectable by recomputation. The fifth,
the Compliance Gate Binding (gate_ref), binds a categorical
ALLOW/REFER/DENY compliance verdict and a no-PII payer reference to a
policy or binding reference, so that a screening decision is provably
tied to the policy in force when it was made and carries no personal
data in the bound record. The sixth, the Pre-Payment Decision
Chain (guardrail_ref), composes an agent identity reference, a spend
authority reference, and the policy in force into one recomputable
pre-payment ALLOW/DENY decision. The seventh, Post-Decision
Execution Evidence (execution_ref), binds an executed action to the
exact decision that authorized it, so the recorded execution is
provably consistent with the decision and not merely correlated with
an agent identity. The eighth, Cross-Party Authority Delegation
(delegation_ref), binds a delegation of authority from one party to
another and chains hand-offs, so a verifier can confirm that authority
did not widen across an organizational boundary. All
constructions use only SHA-256 and the JSON Canonicalization Scheme
(JCS, RFC 8785),
and are verifiable by any party holding the relevant receipts without
contacting the issuer. The constructions satisfy the transaction
recording and audit trail obligations of MiCA Article 80, DORA
Article 14, and AMLR Article 56.
Status of This Memo
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 25 December 2026.
Copyright Notice
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.
Table of Contents
1. Introduction
2. Terminology
3. Preimage Schema
4. Chain Reference Computation
4.1. JCS Canonicalization
4.2. SHA-256 Digest
4.3. Output Encoding
5. Chain Construction Rules
5.1. Genesis Record
5.2. Subsequent Records
6. Verification Procedure
6.1. Single-Link Verification
6.2. Sequence Verification
7. Payment Action Lifecycle
7.1. Action Reference
7.2. Transition Hash
7.3. Lifecycle States
7.4. Exactly-Once Guarantee (SKIP-on-retry)
7.5. Input Validation Rules
7.6. Settlement-Action Binding
7.7. Policy Binding
7.8. Compliance Gate Binding
7.9. Pre-Payment Decision Chain
7.10. Post-Decision Execution Evidence
8. Conformance Vectors
8.1. Retention Chain Vectors: Test Inputs
8.2. Retention Chain Vectors: Vector 0 -- Genesis
8.3. Retention Chain Vectors: Vector 1 -- Chain Link
8.4. Retention Chain Vectors: Vector 2 -- Chain Link
8.5. Lifecycle Vectors: Action Reference
8.6. Lifecycle Vectors: State Transitions
8.7. Lifecycle Vectors: SKIP-on-retry Idempotency
8.8. Adversarial Boundary Vectors
8.9. Settlement-Action Binding Vectors
8.10. Policy Binding Vectors
8.11. Compliance Gate Binding Vectors
8.12. Pre-Payment Decision Chain Vectors
8.13. Post-Decision Execution Evidence Vectors
9. Regulatory Applicability
9.1. MiCA Article 80
9.2. DORA Article 14
9.3. AMLR Article 56
10. Security Considerations
10.1. Collision Resistance
10.2. Subset Auditability
10.3. Chain Truncation
10.4. Issuer Isolation
10.5. Exactly-Once Security Properties
11. IANA Considerations
12. References
12.1. Normative References
12.2. Informative References
Author's Address
1. Introduction
Agentic payment systems that operate under MiCA, DORA, or AMLR are
required to maintain tamper-evident records of every payment
transaction and to make those records available for regulatory audit
on demand. Existing approaches rely on centralised audit logs, which
introduce availability risk and require auditors to trust the
operator's infrastructure.
This document specifies two constructions that together cover the
full lifecycle of a regulated agentic payment:
1. The Retention Chain Reference links receipts into a verifiable
audit chain. Any party holding receipts can verify chain
integrity without contacting the issuer.
2. The Payment Action Lifecycle assigns a stable, content-addressed
identity (action_ref) to each payment action, and a per-state
digest (transition_hash) to each lifecycle stage. The
construction provides a provable SKIP-on-retry guarantee: a
re-presented identical transition request reproduces the prior
transition_hash byte-for-byte and cannot constitute a second
effect.
Both constructions require only:
o A SHA-256 implementation (available in every standard library).
o A JCS canonicalization implementation (RFC 8785).
o The receipts and/or transition records themselves.
The constructions are designed for use with x402 payment receipts
[X402] but are not limited to that protocol. The preimage schemas
use only primitive JSON types (integer and string), making them
compatible with any receipt format that can supply the required
fields.
2. Terminology
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.
chain_seq:
A non-negative integer identifying the position of a receipt in
an issuer's sequence. The genesis receipt has chain_seq = 0.
Each subsequent receipt increments chain_seq by 1.
issuer_id:
A non-empty string uniquely identifying the receipt issuer within
the deployment. Issuers SHOULD use URN or DID syntax.
receipt_hash:
The SHA-256 digest of a payment receipt, encoded as the string
"sha256:" followed by 64 lowercase hexadecimal characters.
prev_receipt_hash:
The receipt_hash of the immediately preceding receipt in the
issuer's chain. MUST be the empty string "" for the genesis
record (chain_seq = 0).
retention_chain_ref:
The output of the chain reference computation defined in
Section 4. Encoded as the string "sha256:" followed by 64
lowercase hexadecimal characters.
action_ref:
A content-addressed identifier for a payment action, computed
as the SHA-256 digest of the JCS canonical form of the action's
identity preimage (Section 7.1). Encoded as 64 lowercase
hexadecimal characters (no "sha256:" prefix). MUST NOT change
across any state of the action's lifecycle.
transition_hash:
A content-addressed digest of a payment action's state at a
specific lifecycle stage, computed as the SHA-256 digest of the
JCS canonical form of the transition preimage (Section 7.2).
Encoded as 64 lowercase hexadecimal characters (no "sha256:"
prefix).
timestamp_ms:
A non-negative integer representing a point in time as
milliseconds since the Unix epoch (1970-01-01T00:00:00Z).
Implementations MUST NOT represent timestamps as RFC 3339
strings, floating-point values, booleans, or null.
JCS:
JSON Canonicalization Scheme as defined in RFC 8785.
3. Preimage Schema
The preimage is a JSON object with exactly four fields. When
serialised using JCS (Section 4.1), the fields appear in the
following lexicographic order:
chain_seq (integer, non-negative)
issuer_id (string, non-empty)
prev_receipt_hash (string, "sha256:<64-hex>" or "")
receipt_hash (string, "sha256:<64-hex>")
Implementations MUST NOT include additional fields in the preimage.
Implementations MUST NOT omit any of the four fields.
Field constraints:
o chain_seq MUST be a non-negative integer. Floating-point
representations are not permitted.
o issuer_id MUST be a non-empty string.
o prev_receipt_hash MUST be "" when chain_seq = 0, and MUST be a
valid receipt_hash string (as defined above) when chain_seq > 0.
o receipt_hash MUST match the pattern "sha256:[0-9a-f]{64}".
Uppercase hexadecimal characters are not permitted.
4. Chain Reference Computation
4.1. JCS Canonicalization
The preimage object MUST be serialised using the JSON
Canonicalization Scheme [RFC8785]. JCS produces a deterministic
byte sequence by:
o Sorting object keys lexicographically by Unicode code point.
o Serialising numbers without insignificant leading zeros or
trailing decimals.
o Encoding strings using minimum-length Unicode escape sequences.
o Omitting all insignificant whitespace.
For the four-field preimage defined in Section 3, the keys in
lexicographic order are:
chain_seq, issuer_id, prev_receipt_hash, receipt_hash
Example canonical form for the genesis vector (Section 8.2):
{"chain_seq":0,"issuer_id":"algovoi:test",
"prev_receipt_hash":"","receipt_hash":"sha256:24c3e22bc6ece631
e4524e3beeb904553fbb1cd6fd124e1cb3c68a9a277ba23a"}
(Line breaks above are for readability only; the actual canonical
form contains no whitespace between tokens.)
4.2. SHA-256 Digest
The SHA-256 digest [FIPS180-4] MUST be computed over the UTF-8
encoding of the JCS canonical byte sequence produced in Section 4.1.
The result is a 32-byte (256-bit) digest.
4.3. Output Encoding
The retention_chain_ref is the string formed by concatenating the
literal prefix "sha256:" with the lowercase hexadecimal encoding of
the 32-byte SHA-256 digest. The result is always exactly 71
characters: 7 prefix characters followed by 64 hexadecimal
characters.
Pseudocode:
preimage = {
"chain_seq": chain_seq,
"issuer_id": issuer_id,
"prev_receipt_hash": prev_receipt_hash,
"receipt_hash": receipt_hash,
}
canonical_bytes = JCS(preimage)
digest = SHA256(canonical_bytes)
retention_chain_ref = "sha256:" + hex(digest)
5. Chain Construction Rules
5.1. Genesis Record
The first receipt in an issuer's chain MUST satisfy:
o chain_seq = 0
o prev_receipt_hash = ""
Implementations MUST reject a genesis record whose prev_receipt_hash
is non-empty.
5.2. Subsequent Records
Each subsequent receipt MUST satisfy:
o chain_seq = (previous chain_seq) + 1
o prev_receipt_hash = receipt_hash of the immediately preceding
receipt (NOT the preceding retention_chain_ref)
The chain links via receipt_hash values, not via
retention_chain_ref values. This design allows an auditor who holds
a receipt but not its chain reference to reconstruct chain linkage
from the receipts alone.
6. Verification Procedure
6.1. Single-Link Verification
To verify a single retention_chain_ref:
1. Extract chain_seq, issuer_id, prev_receipt_hash, and
receipt_hash from the receipt under examination.
2. Check field constraints as defined in Section 3. Fail if any
constraint is violated.
3. Compute retention_chain_ref as defined in Section 4.
4. Compare the computed value to the retention_chain_ref stored in
or alongside the receipt.
5. The link is valid if and only if the values are identical.
6.2. Sequence Verification
To verify a contiguous sequence of N receipts R[0], R[1], ...,
R[N-1]:
1. Verify R[0] as a single link per Section 6.1.
2. For each i in 1..N-1:
a. Verify R[i] as a single link per Section 6.1.
b. Check that R[i].chain_seq = R[i-1].chain_seq + 1.
c. Check that R[i].prev_receipt_hash = R[i-1].receipt_hash.
3. The sequence is valid if and only if all per-link verifications
pass and all adjacency checks pass.
An auditor holding a non-contiguous subset of receipts MAY verify
each individual link independently. The subset does not constitute
a complete chain audit but does demonstrate that each held receipt
is internally consistent.
7. Payment Action Lifecycle
This section specifies the content-addressed model for the exactly-
once execution of payment actions. It defines two primitives:
action_ref (the stable identity of an action across its lifecycle)
and transition_hash (the state-specific digest for each lifecycle
stage).
7.1. Action Reference
An action_ref uniquely identifies a payment action. It is computed
as the SHA-256 digest of the JCS canonical form of the following
four-field identity preimage:
action_type (string, non-empty)
agent_id (string, non-empty)
scope (string, non-empty)
timestamp_ms (integer, non-negative)
JCS lexicographic key order:
action_type, agent_id, scope, timestamp_ms
Pseudocode:
identity = {
"action_type": action_type,
"agent_id": agent_id,
"scope": scope,
"timestamp_ms": timestamp_ms,
}
canonical_bytes = JCS(identity)
action_ref = hex(SHA256(canonical_bytes))
The action_ref is encoded as 64 lowercase hexadecimal characters
with no prefix. Implementations MUST NOT include the "sha256:"
prefix used by retention_chain_ref and receipt_hash.
The action_ref MUST remain constant across all lifecycle states of
the action. It serves as the binding key that connects every
transition_hash for a given action.
7.2. Transition Hash
A transition_hash records the state of a payment action at a
specific lifecycle stage. It is computed as the SHA-256 digest of
the JCS canonical form of the following five-field transition
preimage:
action_ref (string, 64 lowercase hex chars)
authority_verified_at_ms (integer, non-negative)
revocation_check_at_ms (integer, non-negative)
state (string, non-empty)
transition_timestamp_ms (integer, non-negative)
JCS lexicographic key order:
action_ref, authority_verified_at_ms, revocation_check_at_ms,
state, transition_timestamp_ms
Pseudocode:
transition = {
"action_ref": action_ref,
"authority_verified_at_ms": authority_verified_at_ms,
"revocation_check_at_ms": revocation_check_at_ms,
"state": state,
"transition_timestamp_ms": transition_timestamp_ms,
}
canonical_bytes = JCS(transition)
transition_hash = hex(SHA256(canonical_bytes))
The transition_hash is encoded as 64 lowercase hexadecimal
characters with no prefix.
7.3. Lifecycle States
Three lifecycle states are defined:
PENDING:
The action has been initiated and is awaiting settlement.
COMMITTED:
The action has settled. This is the "once" in exactly-once:
a COMMITTED transition_hash is the authoritative proof of
settlement.
REVERSED:
The action has been reversed following a COMMITTED transition.
Because the state field is load-bearing in the JCS preimage, each
lifecycle state produces a distinct transition_hash even when all
other fields are identical. Implementations MUST NOT treat
transition_hash values from different states as interchangeable.
7.4. Exactly-Once Guarantee (SKIP-on-retry)
The SKIP-on-retry invariant is a consequence of the deterministic
JCS+SHA-256 construction: if two calls to the transition_hash
computation use identical values for all five preimage fields, they
MUST produce identical output.
Therefore: a payment processor that re-presents an identical
transition request (same action_ref, same state, same timestamps)
MUST produce the same transition_hash as the original. The retry
is byte-identical to the first attempt; it cannot constitute a
second effect.
Implementations MUST NOT introduce randomness, a nonce, or a
wall-clock re-sampling into the transition preimage. Doing so
would break the idempotency guarantee.
This guarantee is content-addressed and requires no session state,
no idempotency-key registry, and no coordination between retrying
parties. Any party holding the original transition_hash can verify
a retry by recomputing the hash from the five fields.
7.5. Input Validation Rules
Implementations MUST enforce the following constraints before
computing any hash defined in this section. A violation MUST cause
the computation to be rejected; implementations MUST NOT silently
accept or coerce invalid inputs.
Timestamp fields (timestamp_ms, transition_timestamp_ms,
authority_verified_at_ms, revocation_check_at_ms):
o MUST be a non-negative integer JSON value.
o MUST NOT be a string (including RFC 3339 date-time strings).
o MUST NOT be a floating-point value, a boolean, or null.
The action_ref field in a transition preimage:
o MUST be exactly 64 characters in length.
o MUST consist entirely of lowercase hexadecimal characters
([0-9a-f]).
String fields (agent_id, action_type, scope, state):
o MUST be non-empty strings.
o MUST NOT be null.
These constraints are load-bearing: violating any of them alters
the JCS canonical form and therefore the computed hash. Accepting
an invalid input silently would cause the implementation to compute
a hash for a different logical object than intended.
7.6. Settlement-Action Binding
A settlement attestation proves that a payment occurred. On its own
it does not prove which verified agent action the payment
corresponds to, nor that the correspondence is recorded in a
tamper-evident chain. The Settlement-Action Binding closes this
post-settlement accountability gap.
A binding_ref is computed as the SHA-256 digest of the JCS canonical
form of the following four-field binding preimage:
action_ref (string, 64 lowercase hex chars)
retention_chain_ref (string, "sha256:" + 64 lowercase hex chars)
settlement_ref (string, 64 lowercase hex chars)
transition_hash (string, 64 lowercase hex chars)
The four fields are, respectively: the action identity (Section
7.1); the retention chain entry recording the action (Section 4);
the content hash of the settlement attestation receipt
([SETTLEMENT-ATTESTATION]); and the COMMITTED transition for the
action (Sections 7.2, 7.3).
JCS lexicographic key order:
action_ref, retention_chain_ref, settlement_ref, transition_hash
Pseudocode:
binding = {
"action_ref": action_ref,
"retention_chain_ref": retention_chain_ref,
"settlement_ref": settlement_ref,
"transition_hash": transition_hash,
}
canonical_bytes = JCS(binding)
binding_ref = "sha256:" + hex(SHA256(canonical_bytes))
The binding_ref is emitted with the "sha256:" prefix, consistent
with retention_chain_ref. No new hashing primitive is introduced:
the binding is JCS + SHA-256 over four references already defined by
this document and [SETTLEMENT-ATTESTATION].
The following invariants hold and MUST be preserved by any
conformant implementation:
o Stability: an identical four-field preimage reproduces the same
binding_ref byte-for-byte.
o Settlement-binding: changing settlement_ref changes binding_ref.
A settlement cannot be re-pointed to another action's record.
o Action-binding: changing action_ref changes binding_ref. An
action cannot claim another identity's settlement.
o State-binding: changing transition_hash changes binding_ref.
Only the exact COMMITTED transition (Section 7.3) binds; a
PENDING or REVERSED transition_hash yields a distinct binding_ref,
so a non-committed state cannot be presented as settled-bound.
o Chain-binding: changing retention_chain_ref changes binding_ref.
The chain position recording the record is load-bearing.
Because action_ref and transition_hash derive from
epoch-millisecond-integer preimages (Section 7.5, Rule on
timestamps), an implementation that admits an RFC 3339 string
timestamp upstream computes a different action_ref and therefore a
different binding_ref; it cannot reproduce the binding bytes of a
conformant implementation.
The binding_ref MAY itself be carried in an HTTP request that is
signed using HTTP Message Signatures (RFC 9421); the construction of
that signing base is specified informatively in
[I-D.hopley-x402-rfc9421-binding]. The signature and the binding
are independent checks: a valid signature does not imply a correct
binding, and a correct binding does not imply a valid signature.
7.7. Policy Binding
A binding_ref (Section 7.6) or a retention_chain_ref (Section 4)
proves which verified action settled and that the record is chained.
Neither proves which policy, or ruleset, was in force when the action
was admitted. The Policy Binding closes this gap: it binds a
content-addressed snapshot of the governing policy to an existing
reference, so that a decision is verifiable against the exact policy
version that produced it and a policy rotation is detectable by
recomputation.
The policy reference (policy_ref) is the SHA-256 digest of the JCS
canonical form of the policy document. The policy document is any
JCS-serialisable object (for example an AML ruleset, a mandate, or a
governance profile):
policy_ref = "sha256:" + hex(SHA256(JCS(policy_document)))
The policy binding (policy_bound_ref) is computed as the SHA-256
digest of the JCS canonical form of the following two-field preimage:
policy_ref (string, "sha256:" + 64 lowercase hex chars)
subject_ref (string, "sha256:" + 64 lowercase hex chars)
subject_ref is any content-addressed reference defined by this
document that the policy is bound to: a Settlement-Action binding_ref
(Section 7.6) or a retention_chain_ref (Section 4), of any version.
It is imported by hash only, so the construction is identical across
versions and never depends on which layer produced the reference.
JCS lexicographic key order:
policy_ref, subject_ref
Pseudocode:
policy_ref = "sha256:" + hex(SHA256(JCS(policy_document)))
bound = {
"policy_ref": policy_ref,
"subject_ref": subject_ref,
}
canonical_bytes = JCS(bound)
policy_bound_ref = "sha256:" + hex(SHA256(canonical_bytes))
The policy_bound_ref is emitted with the "sha256:" prefix, consistent
with binding_ref and retention_chain_ref. No new hashing primitive
is introduced, and no construction defined elsewhere in this document
is modified: the policy binding is JCS + SHA-256 over a policy
snapshot and one existing reference, imported by hash.
The following invariants hold and MUST be preserved by any conformant
implementation:
o Stability: an identical (policy_ref, subject_ref) preimage
reproduces the same policy_bound_ref byte-for-byte.
o Snapshot-binding: changing the policy document changes policy_ref
and therefore policy_bound_ref.
o Rotation-detection: a policy P and a rotated policy P' yield
distinct policy_bound_ref values for the same subject_ref. A
record sealed under P fails recomputation under P', so a policy
rotation between decision and verification is detectable.
o Subject-binding: changing subject_ref changes policy_bound_ref.
A policy decision cannot be re-pointed to another action's record.
o Key-order-invariance: JCS canonicalisation absorbs the key order
of the policy document, so policy_ref is independent of how the
policy is serialised.
7.8. Compliance Gate Binding
A policy_bound_ref (Section 7.7), a binding_ref (Section 7.6), or a
retention_chain_ref (Section 4) records what settled, under which
policy, and in what chain. None records the compliance decision
itself. The Compliance Gate Binding closes this gap: it binds a
categorical screening verdict, together with a payer reference that
carries no personal data, to one of those references, so that an
ALLOW, REFER, or DENY decision is verifiable against the exact policy
or action it was made for, and a policy rotation between decision and
verification is detectable by recomputation.
The payer reference (payer_ref) is the SHA-256 digest of the JCS
canonical form of a two-field preimage. The cleartext address is
never emitted; only its digest appears:
address (string, the screened account or wallet address)
network (string, the network the address belongs to)
payer_ref = "sha256:" + hex(SHA256(JCS({address, network})))
The verdict is a closed enumeration with exactly three members:
"ALLOW", "REFER", "DENY"
REFER is byte-distinct from DENY: a referral obligation (for example
a suspicious-activity report) is not a refusal, and the two MUST NOT
collapse to one value.
The gate binding (gate_ref) is computed as the SHA-256 digest of the
JCS canonical form of the following three-field preimage:
payer_ref (string, "sha256:" + 64 lowercase hex chars)
subject_ref (string, "sha256:" + 64 lowercase hex chars)
verdict (string, one of "ALLOW", "REFER", "DENY")
subject_ref is any content-addressed reference defined by this
document that the decision is bound to: a policy_bound_ref
(Section 7.7), a Settlement-Action binding_ref (Section 7.6), or a
retention_chain_ref (Section 4), of any version. It is imported by
hash only.
JCS lexicographic key order:
payer_ref, subject_ref, verdict
Pseudocode:
payer_ref = "sha256:" + hex(SHA256(JCS({
"address": address,
"network": network,
})))
bound = {
"payer_ref": payer_ref,
"subject_ref": subject_ref,
"verdict": verdict,
}
canonical_bytes = JCS(bound)
gate_ref = "sha256:" + hex(SHA256(canonical_bytes))
The gate_ref is emitted with the "sha256:" prefix, consistent with
the other references in this document. No new hashing primitive is
introduced, and no construction defined elsewhere in this document is
modified. The binding is content-addressed; this document defines no
signature over gate_ref.
The following invariants hold and MUST be preserved by any conformant
implementation:
o No-PII: payer_ref is a digest, so the cleartext address does not
appear in payer_ref or in gate_ref.
o Verdict-binding: the three verdicts over an identical
(payer_ref, subject_ref) yield three distinct gate_ref values.
o Closed-enumeration: a verdict outside {"ALLOW","REFER","DENY"}
MUST be rejected, not hashed.
o Policy-binding: when subject_ref is a policy_bound_ref, a verdict
sealed under policy P yields a different gate_ref under a rotated
policy P', so a policy rotation between decision and verification
is detectable.
o Subject-binding: changing subject_ref changes gate_ref. A
decision cannot be re-pointed to another subject's record.
7.9. Pre-Payment Decision Chain
Sections 7.6 through 7.8 bind a settled action, the policy in force,
and a compliance verdict. A payment agent also makes a decision
BEFORE it executes a payment: whether the spend is permitted, given
the agent's identity, the spending authority, and the policy. The
Pre-Payment Decision Chain composes that decision from three
content-addressed references into one recomputable guardrail_ref.
An agent identity reference (passport_ref) is the SHA-256 digest of
the JCS canonical form of:
agent_id, issuer, scope, validity_window (all strings)
A spend authority reference (mandate_ref) is the SHA-256 digest of
the JCS canonical form of:
cap, payer, period, revocation_state (all strings)
The pre-payment decision (guardrail_ref) binds the agent, the
authority, the policy in force (policy_bound_ref, Section 7.7), and
the categorical verdict:
agent_ref ("sha256:" + 64 lowercase hex; the passport_ref)
mandate_ref ("sha256:" + 64 lowercase hex)
policy_bound_ref ("sha256:" + 64 lowercase hex; Section 7.7)
verdict (string; "ALLOW" or "DENY")
JCS lexicographic key order:
agent_ref, mandate_ref, policy_bound_ref, verdict
Pseudocode:
decision = {
"agent_ref": agent_ref,
"mandate_ref": mandate_ref,
"policy_bound_ref": policy_bound_ref,
"verdict": verdict,
}
guardrail_ref = "sha256:" + hex(SHA256(JCS(decision)))
No new hashing primitive is introduced: the decision is JCS +
SHA-256 over references already defined by this document and the
identity and authority references above.
The following invariants hold and MUST be preserved by any
conformant implementation:
o Stability: an identical preimage reproduces guardrail_ref
byte-for-byte.
o Agent-binding: changing agent_ref changes guardrail_ref. A
decision made for one agent cannot be re-attributed to another.
o Authority-binding: changing mandate_ref changes guardrail_ref. A
decision checked against one spend authority cannot be presented
as made against another.
o Policy-binding: changing policy_bound_ref changes guardrail_ref.
An ALLOW made under one policy snapshot does not recompute under a
rotated policy (Section 7.7).
o Verdict-binding: an ALLOW and a DENY over the same three
references yield distinct guardrail_refs; a verdict cannot be
silently flipped.
o Composition: passport_ref, mandate_ref, and policy_bound_ref are
each independently recomputable from their own preimages, so the
whole chain is verifiable end-to-end with no issuer contact and no
registry lookup.
The guardrail_ref MAY itself be carried in an HTTP request signed
using HTTP Message Signatures (RFC 9421); the signature and the
decision are independent checks, as in Section 7.6.
The byte-level conformance artifact is the Apache-2.0
spend_decision_chain_v1 set in the AlgoVoi JCS conformance corpus
[ALGOVOI-VECTORS] (Section 8.12), which reproduces this chain for
both ALLOW and DENY from the raw identity, authority, and policy
inputs.
7.10. Post-Decision Execution Evidence
Section 7.9 binds a pre-payment decision (guardrail_ref) from the
agent identity, the spend authority, and the policy in force. That
decision authorizes an action; it does not, on its own, record what
the agent then DID, nor bind the recorded execution back to the
decision that authorized it. A reference that proves only the
identity of an executed action (Section 7.1) establishes
correlation with an agent, not consistency with a decision. Post-
Decision Execution Evidence closes that gap with a single content-
addressed reference, execution_ref, that binds an executed action to
the exact decision that authorized it.
The execution evidence reference (execution_ref) is the SHA-256
digest of the JCS canonical form of:
decision_ref ("sha256:" + 64 lowercase hex; the guardrail_ref
of Section 7.9, the decision that authorized the
execution)
action_type (string; what was executed)
scope (string; the scope it executed under)
outcome (string; closed set, below)
executed_at_ms (integer epoch milliseconds; the integer epoch-millisecond
rule of Section 7.5; hashed as an integer, never a
converted string)
outcome is a closed set of four values:
COMMITTED the action committed exactly once
SKIPPED a duplicate of an already-committed action, suppressed
FAILED the action did not complete
REVERSED a previously committed action was reversed
JCS lexicographic key order:
action_type, decision_ref, executed_at_ms, outcome, scope
Pseudocode:
execution = {
"decision_ref": decision_ref,
"action_type": action_type,
"scope": scope,
"outcome": outcome,
"executed_at_ms": executed_at_ms,
}
execution_ref = "sha256:" + hex(SHA256(JCS(execution)))
No new hashing primitive is introduced: the reference is JCS +
SHA-256 over the decision reference defined in Section 7.9 plus the
four execution fields above. executed_at_ms is hashed as an integer
epoch-millisecond value, not a converted string; an implementation
that hashes a string timestamp produces a different execution_ref and
is non-conformant.
No agent identifier appears in the preimage. The agent is already
bound inside decision_ref (through agent_ref, Section 7.9), so
execution_ref carries no personal data of its own.
The following invariants hold and MUST be preserved by any
conformant implementation:
o Stability: an identical preimage reproduces execution_ref
byte-for-byte.
o Decision-binding: changing decision_ref changes execution_ref. An
execution recorded under one decision cannot be re-attributed to
another. This is the consistency property: the evidence is bound
to the decision that authorized it, not merely to an identity.
o Outcome-binding: a COMMITTED and a REVERSED over the same decision
and action yield distinct execution_refs; an outcome cannot be
silently changed.
o Time-binding: changing executed_at_ms changes execution_ref.
o Composition: decision_ref is itself recomputable from its own
preimage (Section 7.9), which composes from passport_ref,
mandate_ref, and policy_bound_ref, so the whole keystone is
verifiable end-to-end with no issuer contact:
passport_ref -> mandate_ref -> policy_bound_ref
-> guardrail_ref (decision) -> execution_ref (execution)
A composite trust verdict (trust_query_ref, defined in
draft-hopley-x402-composite-trust-query) MAY
assess the ordered list of these references, including
execution_ref, so a single verdict spans identity through
execution.
An execution_ref MAY be carried as an entry in a signed, hash-linked
evidence chain (Section 7.1) under entry type "execution_evidence",
so that a sequence of executions is tamper-evident and offline-
verifiable under the document's chain rules.
7.11. Cross-Party Authority Delegation
Sections 7.9 and 7.10 bind a single agent's decision and the execution
that followed it. Authority is frequently not exercised by the agent
that was granted it: one party delegates a slice of its authority to
another party's agent, which then builds its own keystone under that
delegation and executes. A receipt of the executed action proves what
happened; it does not prove that the executing party stayed within the
authority delegated to it, nor that the hand-off was between the
intended parties inside the window the delegator allowed. Cross-Party
Authority Delegation closes that gap with a content-addressed
reference, delegation_ref, that binds one hand-off of authority and
chains hand-offs into a tamper-evident sequence.
The delegation reference (delegation_ref) is the SHA-256 digest of the
JCS canonical form of:
delegate_id (string; the party receiving the authority)
delegator_id (string; the party granting the authority)
not_after_ms (integer epoch milliseconds; end of the
validity window; Section 6 Substrate Rule for
integer-millisecond timestamps applies)
not_before_ms (integer epoch milliseconds; start of the
validity window)
prev_delegation_ref ("" for a root delegation, or the
"sha256:"-prefixed delegation_ref of the prior
hand-off, which chains delegations)
scope (string; the authority delegated)
JCS lexicographic key order:
delegate_id, delegator_id, not_after_ms, not_before_ms,
prev_delegation_ref, scope
Pseudocode:
delegation = {
"delegate_id": delegate_id,
"delegator_id": delegator_id,
"not_after_ms": not_after_ms,
"not_before_ms": not_before_ms,
"prev_delegation_ref": prev_delegation_ref,
"scope": scope,
}
delegation_ref = "sha256:" + hex(SHA256(JCS(delegation)))
No new hashing primitive is introduced: the reference is JCS + SHA-256
over the six fields above. not_before_ms and not_after_ms are hashed
as integer epoch-millisecond values, not converted strings; an
implementation that hashes a string timestamp produces a different
delegation_ref and is non-conformant. not_after_ms MUST be greater
than not_before_ms.
The following invariants hold and MUST be preserved by any conformant
implementation:
o Stability: an identical preimage reproduces delegation_ref
byte-for-byte, including under reordering of the envelope keys,
which JCS canonicalizes.
o Tamper-binding: changing the delegated scope, either validity
bound, or either party changes delegation_ref. A delegation cannot
be silently widened, extended, or re-pointed to a different
delegate.
o Chain integrity: prev_delegation_ref binds each hand-off to the one
before it. In a chain of delegations the prev_delegation_ref of
each link MUST equal the computed delegation_ref of the prior link;
a broken or forged link is detectable offline:
delegation_ref(A->B) -> delegation_ref(B->C) -> ...
o Authority composition: because the executed action (Section 7.10),
the decision that authorized it (Section 7.9), and the delegation
that conferred the authority are each content-addressed and
recomputable, a verifier MAY check, with no issuer contact, that
authority did not widen across the party boundary: that the executed
scope is contained within the decision scope, the decision scope
within the delegated scope, that the delegate named by one hand-off
is the delegator of the next, and that the execution time falls
within the delegation's validity window. This is the authorization
property a receipt alone cannot establish: that the executing party
stayed within what was delegated to it, end to end across the
boundary.
A delegation_ref MAY be carried as an entry in a signed, hash-linked
evidence chain (Section 7.1) under entry type "delegation", so that a
sequence of hand-offs is tamper-evident and offline-verifiable under
the document's chain rules.
8. Conformance Vectors
Implementations MUST produce the hash values in Sections 8.2
through 8.7 and Sections 8.9 through 8.11 for the given inputs. The
adversarial vectors in Section 8.8 MUST be rejected as specified. An
extended
vector set covering multi-issuer isolation, sequence-gap detection,
and the full set of adversarial boundaries is published at:
https://github.com/chopmob-cloud/algovoi-jcs-conformance-vectors
8.1. Retention Chain Vectors: Test Inputs
The following receipt_hash values are used across Sections 8.2
through 8.4. Each is the SHA-256 digest of the UTF-8 encoding of
the literal string shown:
receipt_0: SHA-256("receipt_0") =
sha256:24c3e22bc6ece631e4524e3beeb904553fbb1cd6fd124e1cb3c6
8a9a277ba23a
receipt_1: SHA-256("receipt_1") =
sha256:55d4a60cbf6928423fd1cd0e06f7cccd98011e9064240a3fd24f
7c6bbae8266a
receipt_2: SHA-256("receipt_2") =
sha256:08a132f9262230f24640a591c60a08e756d313dbf15ff578b4c1
0fdd30120a4a
issuer_id = "algovoi:test" for all three vectors.
8.2. Retention Chain Vectors: Vector 0 -- Genesis
Input:
chain_seq: 0
issuer_id: "algovoi:test"
prev_receipt_hash: ""
receipt_hash: sha256:24c3e22bc6ece631e4524e3beeb904553fbb1
cd6fd124e1cb3c68a9a277ba23a
JCS canonical form (UTF-8, no whitespace):
{"chain_seq":0,"issuer_id":"algovoi:test","prev_receipt_hash":
"","receipt_hash":"sha256:24c3e22bc6ece631e4524e3beeb904553fbb1
cd6fd124e1cb3c68a9a277ba23a"}
Expected retention_chain_ref:
sha256:f15a1dcd03cc039204dff24619ff4815ad041ad8796b94f59d5225
2043d0d08f
8.3. Retention Chain Vectors: Vector 1 -- Chain Link
Input:
chain_seq: 1
issuer_id: "algovoi:test"
prev_receipt_hash: sha256:24c3e22bc6ece631e4524e3beeb904553fbb1
cd6fd124e1cb3c68a9a277ba23a
receipt_hash: sha256:55d4a60cbf6928423fd1cd0e06f7cccd98011
e9064240a3fd24f7c6bbae8266a
Expected retention_chain_ref:
sha256:7114dc39543710bf26d0a5825acddd915ffd51fb5b14503024f70f
da403053d9
8.4. Retention Chain Vectors: Vector 2 -- Chain Link
Input:
chain_seq: 2
issuer_id: "algovoi:test"
prev_receipt_hash: sha256:55d4a60cbf6928423fd1cd0e06f7cccd98011
e9064240a3fd24f7c6bbae8266a
receipt_hash: sha256:08a132f9262230f24640a591c60a08e756d31
3dbf15ff578b4c10fdd30120a4a
Expected retention_chain_ref:
sha256:d3bddca79477e6003cb6ef199897bffed185f5d785b4e7333f9b05
85b2b81144
8.5. Lifecycle Vectors: Action Reference
The following fixed identity preimage is used throughout Sections
8.5 through 8.7:
agent_id: "agent_alpha"
action_type: "payment"
scope: "vauban:stark_settlement"
timestamp_ms: 1716494400000
JCS canonical form (keys in lexicographic order):
{"action_type":"payment","agent_id":"agent_alpha",
"scope":"vauban:stark_settlement","timestamp_ms":1716494400000}
Expected action_ref (64 lowercase hex, no prefix):
7528529a8be2044488e603b7913efaa4f83620dbcc63010d4a1478cf7e9a473c
This action_ref is stable and MUST be reproduced identically for
the PENDING, COMMITTED, and REVERSED transition vectors in
Section 8.6.
8.6. Lifecycle Vectors: State Transitions
All three transition vectors use the action_ref from Section 8.5.
Implementations MUST produce distinct transition_hash values for
each state.
Vector: PENDING
action_ref: 7528529a8be2044488e603b7913efaa4f836
20dbcc63010d4a1478cf7e9a473c
state: "PENDING"
transition_timestamp_ms: 1716494400000
authority_verified_at_ms: 1716494400500
revocation_check_at_ms: 1716494400800
Expected transition_hash:
0957638b64c790292c11d90e9ae15576a6454f37f23a0aade222acf9e2ea18b0
Vector: COMMITTED
action_ref: 7528529a8be2044488e603b7913efaa4f836
20dbcc63010d4a1478cf7e9a473c
state: "COMMITTED"
transition_timestamp_ms: 1716494500000
authority_verified_at_ms: 1716494500300
revocation_check_at_ms: 1716494500500
Expected transition_hash:
f49faa7c4f82bd842705374311f5f6af073826539d519d0b65de3263258eac5f
Vector: REVERSED
action_ref: 7528529a8be2044488e603b7913efaa4f836
20dbcc63010d4a1478cf7e9a473c
state: "REVERSED"
transition_timestamp_ms: 1716494600000
authority_verified_at_ms: 1716494600300
revocation_check_at_ms: 1716494600500
Expected transition_hash:
681a6026dbbac7555c46282eaf617d3f02560925ed8b44c31e3c854fcfc1f613
8.7. Lifecycle Vectors: SKIP-on-retry Idempotency
A re-presented COMMITTED transition with fields identical to the
COMMITTED vector in Section 8.6 MUST reproduce the same
transition_hash:
action_ref: 7528529a8be2044488e603b7913efaa4f836
20dbcc63010d4a1478cf7e9a473c
state: "COMMITTED"
transition_timestamp_ms: 1716494500000
authority_verified_at_ms: 1716494500300
revocation_check_at_ms: 1716494500500
Expected transition_hash (MUST equal the COMMITTED value above):
f49faa7c4f82bd842705374311f5f6af073826539d519d0b65de3263258eac5f
An implementation that produces a different value for this input
has introduced non-determinism into the transition preimage and
MUST be considered non-conformant.
8.8. Adversarial Boundary Vectors
The following inputs MUST be rejected by a conformant
implementation. For each vector, the reject_reason states the
violated constraint from Section 7.5.
adv-001 -- RFC 3339 string timestamp
transition_timestamp_ms: "2026-06-09T00:00:00Z" (string)
reject_reason: timestamp_ms MUST be a non-negative integer;
string values are not permitted.
adv-002 -- Negative timestamp
authority_verified_at_ms: -1 (negative integer)
reject_reason: timestamp_ms MUST be non-negative.
adv-003 -- Boolean timestamp
revocation_check_at_ms: true (boolean)
reject_reason: timestamp_ms MUST be an integer; booleans are
not permitted.
adv-004 -- Malformed action_ref (non-hex characters)
action_ref: "gggggggg..." (64 chars, not lowercase hex)
reject_reason: action_ref MUST consist entirely of lowercase
hexadecimal characters [0-9a-f].
adv-005 -- Short action_ref
action_ref: "abcd1234" (8 chars)
reject_reason: action_ref MUST be exactly 64 characters.
adv-006 -- Empty state
state: ""
reject_reason: state MUST be a non-empty string.
All inputs in the extended adversarial vector set (published at the
URL in Section 8) produce byte-identical JCS canonicalization
across 8 independent RFC 8785 implementations, confirming that
these are reproducible, real inputs that MUST be rejected at the
validation layer rather than the canonicalization layer.
8.9. Settlement-Action Binding Vectors
These vectors exercise the binding_ref of Section 7.6. All six
share the following component references:
action_ref =
7528529a8be2044488e603b7913efaa4f83620dbcc63010d4a1478cf7e9
a473c
transition_hash (COMMITTED) =
f49faa7c4f82bd842705374311f5f6af073826539d519d0b65de3263258e
ac5f
settlement_ref =
0ead75bfe7fc74cc0421124903e56cb5c5006d02c393231a1d5f260fa87e
96d3
retention_chain_ref =
sha256:d23aeb006c5f3db9dd96315916410393904f56c4c871593065eb7
3b783fff35f
Vector sab-v1-001 (reference) -- the binding of the four references
above:
binding_ref =
sha256:7dc4a2bf62b3c5eabd10fc875ff7fc10f188666f15838c4a51464
cc72e80f6ca
Vector sab-v1-002 (stability) -- the identical preimage re-presented
MUST reproduce sab-v1-001 byte-for-byte:
binding_ref == sab-v1-001
Vector sab-v1-003 (settlement-binding) -- settlement_ref replaced by
0ead... -> e7777a9a77a9c3f02339594395bfb2620e07edc62d3dcb48c4f2e82a
8c37a1c4, all other fields unchanged. MUST differ from sab-v1-001:
binding_ref =
sha256:cf6eb49236702195b0a8b960929ffa993d38d3ddbbb302a1f68f3
2e54bab23ca
Vector sab-v1-004 (action-binding) -- action_ref replaced by
57e861cb0929fe602823a15e2bc5a5587f0b9c3bd39147baa49819dd014c56a6,
all other fields unchanged. MUST differ from sab-v1-001:
binding_ref =
sha256:0bae722c5489179921d8cb3e747f9457d42036f50642fab0e8617
ec89d41d5c2
Vector sab-v1-005 (state-binding) -- transition_hash replaced by the
PENDING transition
0957638b64c790292c11d90e9ae15576a6454f37f23a0aade222acf9e2ea18b0,
all other fields unchanged. MUST differ from sab-v1-001:
binding_ref =
sha256:d1d3b29e5d081f091376f886bfd11f0bb85034df7e6104a1726ed
3929dfa2af3
Vector sab-v1-006 (chain-binding) -- retention_chain_ref replaced by
sha256:43f888f00ea70e38fb8e38c205219b3fff51a90c62197d890b9f270f0f8
1fe42, all other fields unchanged. MUST differ from sab-v1-001:
binding_ref =
sha256:c9cb63c77330d7a3bd9f6252ffe7f3b5d967d4594984cf2120f80
b146dc43d76
All six binding_ref values reproduce byte-for-byte across eight
independent RFC 8785 implementations.
8.10. Policy Binding Vectors
These vectors exercise the policy_bound_ref of Section 7.7. The
subject_ref is the binding_ref of vector sab-v1-001 (Section 8.9):
subject_ref =
sha256:7dc4a2bf62b3c5eabd10fc875ff7fc10
f188666f15838c4a51464cc72e80f6ca
Two policy documents are used. Policy P:
{"policy_id": "aml.transfer", "version": 1, "max_amount": 1000,
"deny_jurisdictions": ["XX"]}
and the rotated policy P':
{"policy_id": "aml.transfer", "version": 2,
"max_amount": 100000, "deny_jurisdictions": []}
Their policy_ref values (Section 7.7):
policy_ref(P) =
sha256:acc943b05fa8e8096e5b313288bc4f91
9cc2661f167c833770509a53049afa1c
policy_ref(P') =
sha256:858fd6694716f503448ea89da802c0c2
942e2619938f126d0088cb4ba9af5d35
Vector pb-v1-001 (reference) -- policy_bound_ref binding policy_ref(P)
to the subject_ref above:
policy_bound_ref =
sha256:aaee2091799f376ee8cac802ea4920fe
aa4eca52950488a3e047ff82e6959a21
Vector pb-v1-002 (rotation) -- policy_ref(P') bound to the same
subject_ref. MUST differ from pb-v1-001, demonstrating that a record
sealed under policy P does not verify under the rotated policy P':
policy_bound_ref =
sha256:e6629ede721146e62ce148fc25c52b79
a58103a7476784397b328809e0f027e2
Vector pb-v1-003 (key-order-invariance) -- policy P re-serialised
with its keys in a different order MUST reproduce policy_ref(P), and
therefore pb-v1-001, byte-for-byte.
The policy_ref and policy_bound_ref values reproduce byte-for-byte
across the Python and TypeScript reference implementations.
8.11. Compliance Gate Binding Vectors
These vectors exercise the gate_ref of Section 7.8. The subject_ref
is the policy_bound_ref pb-v1-001 of Section 8.10 (policy P bound to
the binding_ref of vector sab-v1-001):
subject_ref =
sha256:aaee2091799f376ee8cac802ea4920fe
aa4eca52950488a3e047ff82e6959a21
The payer reference is computed from a screened address and its
network; the cleartext address does not appear in the result:
address = "0x00000000000000000000000000000000DEADBEEF"
network = "base"
payer_ref =
sha256:8637798158677e9aa7d218d81713db9a
f656e2f28a5bcce97b4f2a73286f5765
Vector cg-v1-001 (ALLOW) -- gate_ref binding the ALLOW verdict to the
payer_ref and subject_ref above:
gate_ref =
sha256:43d8d8cb0ba6ccbd3c36167a28075a3f
d5b8858ce0414f6871a22a96f86f96a5
Vector cg-v1-002 (REFER) -- the REFER verdict over the same payer_ref
and subject_ref. MUST differ from cg-v1-001:
gate_ref =
sha256:9a25b3d9d9c1ff4ba1c9c1da66668c59
caf8164d4a081df30826c007d9b6b845
Vector cg-v1-003 (DENY) -- the DENY verdict over the same payer_ref
and subject_ref. MUST differ from cg-v1-001 and cg-v1-002:
gate_ref =
sha256:bff6375120c2ea003a7ae18a05cb1468
e91cd787cb910a4b593f7fb7be2e1c6c
Vector cg-v1-004 (policy rotation) -- the ALLOW verdict and the same
payer_ref, but with subject_ref set to pb-v1-002 of Section 8.10 (the
same subject under the rotated policy P'). MUST differ from
cg-v1-001, demonstrating that a verdict made under policy P does not
verify under P':
gate_ref =
sha256:d4a1f0f4581dd078df2c1d0ed1ffb253
ca8ecdd454179f02894fd5a1e9401247
A verdict outside {"ALLOW","REFER","DENY"}, and a malformed
subject_ref or payer_ref, MUST be rejected, not hashed.
The payer_ref and gate_ref values reproduce byte-for-byte across the
Python and TypeScript reference implementations.
8.12. Pre-Payment Decision Chain Vectors
The spend_decision_chain_v1 set recomputes passport_ref, mandate_ref,
and policy_bound_ref from raw fields, shows each equals the published
output of its own lite set and is the reference the decision binds,
and recomputes guardrail_ref for ALLOW and DENY.
Reference values (recomputed 2026-06-23, rfc8785 + SHA-256):
passport_ref sha256:b3594e33998af01bd1ad208172c5c1ac586daa8c7
5781379f034d97e50b1a9be
mandate_ref sha256:a4f8cb5ee09b29478ac1cc2f468d66e16d3d25f7a2
29a31d22ad521e11d04d35
policy_bound_ref sha256:aaee2091799f376ee8cac802ea4920feaa4eca5295
0488a3e047ff82e6959a21
guardrail_ref sha256:2a444c629892f44fde1bd004aba9be01dd6cc7fe25
(ALLOW) 1eecdd545b82dca9f0bf97
guardrail_ref sha256:792a5b43e9df0fc460d6bf99d6357afafbdcf910ef
(DENY) 1e81a340e3581bc27109cf
These values are reproduced byte-for-byte by independent Python and
Node implementations and by a clean-box install of the published
Apache-2.0 packages.
8.13. Post-Decision Execution Evidence Vectors
The execution_ref_v1 set recomputes execution_ref over the exact
decision_ref produced by Section 7.9, for the COMMITTED, SKIPPED,
FAILED, and REVERSED outcomes, and shows each field is byte-load-
bearing (including rejection of a string-format timestamp). The
keystone_v1 composition then recomputes the full chain end-to-end and
caps it with a trust_query_ref over the ordered references, including
execution_ref.
Reference values (recomputed 2026-06-24, rfc8785 + SHA-256):
decision_ref sha256:2a444c629892f44fde1bd004aba9be01dd6cc7fe25
(ALLOW; 7.9) 1eecdd545b82dca9f0bf97
execution_ref sha256:f6e2bfc15b085ed51c4c972de81d1c6b00f4e55b27
(COMMITTED) 2e2aa12e56bb7c521fc65a
trust_query_ref sha256:18fb601a08c71eb6bed11e1c117f33bdc0ada6d635
(full keystone) ea9bb9cca15e8410ce7ebd
The execution_ref preimage for the COMMITTED value above is
{decision_ref (ALLOW), action_type "payment", scope "bilateral",
outcome "COMMITTED", executed_at_ms 1716460800000}. The trust_query_ref
assesses the ordered chain [passport_ref, mandate_ref, policy_bound_ref,
decision_ref, execution_ref] with trust_outcome "TRUSTED".
These values are reproduced byte-for-byte by independent Python and
Node implementations, by the execution_ref_v1 and keystone_v1 sets in
the AlgoVoi JCS conformance corpus [ALGOVOI-VECTORS], and by a clean-
box install of the published Apache-2.0 algovoi-execution-ref package
on algovoi-substrate v0 and v1.
8.14. Cross-Party Delegation Vectors
The delegation_ref_v1 set recomputes delegation_ref from raw fields,
shows a two-link chain (A->B then B->C) in which the
prev_delegation_ref of the second link equals the computed
delegation_ref of the first, detects tamper across the scope,
validity, delegate, and chain-link families, and rejects a malformed
(string-format) validity bound.
Reference values (recomputed 2026-06-25, rfc8785 + SHA-256):
delegation_ref sha256:4e59d4d1fcee3e2fa6a9be3cfa905b4bc09e5746a4
(root; A->B) 0c1dab96c277c4e10d3276
delegation_ref sha256:91329d2887d8eb879cef066c36418245266116b527
(chain; B->C) 58c386246fdb927d34494a
The root delegation_ref preimage is {delegate_id
"did:web:agent-1.example", delegator_id "did:web:org.example",
not_after_ms 1716498000000, not_before_ms 1716494400000,
prev_delegation_ref "", scope "payments:usdc:<=100"}. The chain
link's prev_delegation_ref is the root value above, so the two links
form a tamper-evident A->B->C sequence.
These values are reproduced byte-for-byte by independent Python and
Node implementations, by the delegation_ref_v1 set in the AlgoVoi JCS
conformance corpus [ALGOVOI-VECTORS], and by a clean-box install of
the published Apache-2.0 algovoi-delegation-ref package.
9. Regulatory Applicability
9.1. MiCA Article 80
MiCA Article 80 requires crypto-asset service providers to maintain
records of all transactions in a manner that permits reconstruction
of each transaction. The constructions in this document satisfy
this requirement:
o The retention chain embeds a tamper-evident linkage directly
into each receipt (Section 4). Any individual receipt can be
verified in isolation (Section 6.1); any contiguous sequence
can be verified as a complete audit trail (Section 6.2).
o The Payment Action Lifecycle (Section 7) provides a stable,
content-addressed identity for each transaction (action_ref)
and a verifiable state record for each lifecycle stage
(transition_hash), satisfying the reconstruction requirement
for the full lifecycle of each transaction.
o No issuer infrastructure is required for verification.
9.2. DORA Article 14
DORA Article 14 requires financial entities to maintain audit logs
of ICT-related incidents and operational transactions with integrity
guarantees. The constructions provide:
o Cryptographic ordering (chain_seq) that prevents receipt
insertion or reordering without detection.
o Hash linkage that makes deletion of any receipt in a sequence
detectable by the holder of adjacent receipts.
o Issuer isolation (issuer_id field) that partitions chains by
operational entity.
o The exactly-once guarantee (Section 7.4) provides a verifiable
record that each operational transaction was executed at most
once, supporting ICT incident reconstruction.
9.3. AMLR Article 56
AMLR Article 56 requires obliged entities to retain records of
financial transactions for a period of at least five years and to
ensure those records are available to competent authorities. The
retention chain satisfies the integrity dimension of this
requirement: a competent authority holding a set of receipts can
verify their integrity without requesting further data from the
obliged entity, reducing audit friction and eliminating the
possibility of post-hoc record manipulation by the issuer. The
transition_hash provides an additional integrity primitive: an
authority can verify that a COMMITTED transition was not
subsequently altered by recomputing the hash from the five fields.
10. Security Considerations
10.1. Collision Resistance
The security of both constructions depends on the collision
resistance of SHA-256. As of the date of this document, no
practical collision attack against SHA-256 is known. Preimage
lengths vary with field values but are always well above the
threshold at which length-extension attacks become relevant.
10.2. Subset Auditability
An auditor holding only a non-contiguous subset of receipts can
verify each held link individually but cannot detect gaps in the
sequence. To detect gaps, the auditor MUST obtain a complete
contiguous range and apply sequence verification (Section 6.2).
Issuers SHOULD provide receipts in complete contiguous sequences to
auditors.
10.3. Chain Truncation
An issuer could present a chain that begins at chain_seq > 0 and
claim it is complete. Auditors SHOULD verify that the chain begins
with a genesis record (chain_seq = 0, prev_receipt_hash = "") unless
they have independent evidence of the chain's starting point.
10.4. Issuer Isolation
The issuer_id field is included in the preimage to prevent cross-
issuer chain forgery: a receipt from issuer A with a given
receipt_hash cannot be substituted for a receipt from issuer B with
the same receipt_hash. Issuers MUST use distinct, non-guessable
issuer_id values within any deployment.
10.5. Exactly-Once Security Properties
The SKIP-on-retry guarantee (Section 7.4) is a consequence of
determinism, not of access control. It provides a verifiable
proof that a retry is byte-identical to the original, but it does
not prevent an attacker who controls the preimage inputs from
constructing a different transition with a different timestamp.
The action_ref binding property prevents replay under a different
agent identity: an identical state+timestamps tuple under a
different action_ref produces a different transition_hash. This
means a transition_hash is bound to exactly one action_ref.
The input validation rules in Section 7.5 are security-critical.
An implementation that accepts an RFC 3339 string as a timestamp
will compute a different transition_hash than one that enforces the
integer constraint, breaking cross-implementation interoperability
and the exactly-once guarantee.
11. IANA Considerations
This document has no IANA actions.
12. References
12.1. Normative References
[FIPS180-4]
National Institute of Standards and Technology, "Secure
Hash Standard (SHS)", FIPS PUB 180-4, August 2015.
[RFC2119] Bradner, S., "Key words for use in RFCs to Indicate
Requirement Levels", BCP 14, RFC 2119,
DOI 10.17487/RFC2119, March 1997.
[RFC8174] Leiba, B., "Ambiguity of Uppercase vs Lowercase in
RFC 2119 Key Words", BCP 14, RFC 8174,
DOI 10.17487/RFC8174, May 2017.
[RFC8785] Rundgren, A., Jordan, B., and S. Erdtman, "JSON
Canonicalization Scheme (JCS)", RFC 8785,
DOI 10.17487/RFC8785, June 2020.
[SETTLEMENT-ATTESTATION]
Hopley, C., "Settlement Attestation for x402 Payments",
Work in Progress, Internet-Draft,
draft-hopley-x402-settlement-attestation, 2026.
12.2. Informative References
[I-D.hopley-x402-rfc9421-binding]
Hopley, C., "RFC 9421 Signing-Base Binding for x402
Receipts", Work in Progress, Internet-Draft,
draft-hopley-x402-rfc9421-binding, 2026.
[VECTORS] Hopley, C., "AlgoVoi JCS Conformance Vectors",
chopmob-cloud/algovoi-jcs-conformance-vectors, June 2026,
<https://github.com/chopmob-cloud/
algovoi-jcs-conformance-vectors>.
[X402] x402 Working Group, "x402 HTTP Payment Protocol",
Work in Progress, 2026.
Author's Address
C. Hopley
AlgoVoi
United Kingdom
Email: chopmob@gmail.com