Network Working Group D. Borthwick Internet-Draft InsumerAPI Intended status: Informational 27 September 2026 Expires: 31 March 2027 Wallet State Attestation: Signed Booleans about On-Chain State draft-borthwick-wallet-state-attestation-01 Abstract This document defines Wallet State Attestation: a primitive in which an issuer reads on-chain state for a wallet address, evaluates one or more operator-defined conditions, and returns a cryptographically signed boolean (or structured fact profile) that any verifier can check offline using a published JWKS endpoint. The primitive enables condition-based access decisions without identity presentation, credential exchange, or contact with the issuer at verification time beyond a copy of its published key set and the documentation that accompanies it. This document describes the request and response surface, the signing algorithm posture, the JWKS discovery pattern, and the security and privacy considerations of the primitive. It does not define a new wire protocol; rather, it profiles existing IETF building blocks (JWT, JWKS, JOSE) for the wallet-state- attestation use case. 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 31 March 2027. Copyright Notice Copyright (c) 2026 IETF Trust and the persons identified as the document authors. All rights reserved. Borthwick Expires 31 March 2027 [Page 1] Internet-Draft Wallet State Attestation September 2026 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. Code Components extracted from this document must include Revised BSD License text as described in Section 4.e of the Trust Legal Provisions and are provided without warranty as described in the Revised BSD License. Table of Contents 1. Introduction . . . . . . . . . . . . . . . . . . . . . . . . 3 1.1. Motivation . . . . . . . . . . . . . . . . . . . . . . . 3 1.2. Position Relative to Identity Primitives . . . . . . . . 3 1.3. Position Relative to Credentials . . . . . . . . . . . . 3 1.4. Position Relative to Other Documents . . . . . . . . . . 4 1.5. Use Cases . . . . . . . . . . . . . . . . . . . . . . . . 5 2. Terminology . . . . . . . . . . . . . . . . . . . . . . . . . 5 3. Architecture Overview . . . . . . . . . . . . . . . . . . . . 7 4. Request Shape . . . . . . . . . . . . . . . . . . . . . . . . 8 5. Response Shape . . . . . . . . . . . . . . . . . . . . . . . 9 6. Signing Algorithm . . . . . . . . . . . . . . . . . . . . . . 11 6.1. Signing Schemes . . . . . . . . . . . . . . . . . . . . . 12 6.2. Signature Encoding and Additional Algorithms . . . . . . 13 6.3. Companion Signatures . . . . . . . . . . . . . . . . . . 13 7. JWKS Discovery . . . . . . . . . . . . . . . . . . . . . . . 16 8. JWT Format . . . . . . . . . . . . . . . . . . . . . . . . . 17 9. Optional Merkle Proofs . . . . . . . . . . . . . . . . . . . 19 10. Security Considerations . . . . . . . . . . . . . . . . . . . 19 10.1. Single-Issuer Architecture . . . . . . . . . . . . . . . 20 10.2. Freshness Anchors and Replay Considerations . . . . . . 20 10.3. Refuse-on-Observation-Failure . . . . . . . . . . . . . 21 10.4. What This Primitive Does Not Protect Against . . . . . . 21 10.5. Algorithm Agility . . . . . . . . . . . . . . . . . . . 21 11. Privacy Considerations . . . . . . . . . . . . . . . . . . . 22 11.1. Boolean by Default . . . . . . . . . . . . . . . . . . . 22 11.2. Merkle Mode Trade-Off . . . . . . . . . . . . . . . . . 22 11.3. No Identity Attributes . . . . . . . . . . . . . . . . . 23 11.4. Wallet Address Handling . . . . . . . . . . . . . . . . 23 11.5. Awareness of Observation . . . . . . . . . . . . . . . . 23 12. Verification Procedure . . . . . . . . . . . . . . . . . . . 23 13. What This Is Not . . . . . . . . . . . . . . . . . . . . . . 25 14. IANA Considerations . . . . . . . . . . . . . . . . . . . . . 26 15. References . . . . . . . . . . . . . . . . . . . . . . . . . 26 15.1. Normative References . . . . . . . . . . . . . . . . . . 26 15.2. Informative References . . . . . . . . . . . . . . . . . 27 Changes from -00 . . . . . . . . . . . . . . . . . . . . . . . . 28 Acknowledgments . . . . . . . . . . . . . . . . . . . . . . . . . 30 Borthwick Expires 31 March 2027 [Page 2] Internet-Draft Wallet State Attestation September 2026 Author's Address . . . . . . . . . . . . . . . . . . . . . . . . 30 1. Introduction 1.1. Motivation Existing access-control primitives --- OAuth 2.0 [RFC6749], OIDC [OIDC-CORE], SAML, and the broader credential-presentation family --- answer the question "who is this user?" by accepting a presented artifact (token, assertion, credential) from a holder. Wallet State Attestation answers a different question: "does this wallet currently satisfy a specified condition over on-chain state?" The holder presents nothing. An issuer reads canonical on-chain state for a specified wallet address, evaluates the operator-defined condition, and returns a signed boolean. Verifiers check the signature offline using a published JWKS endpoint. This is a distinct primitive from identity verification, credential issuance, or holder-presentation flows. It belongs in a parallel category --- what this document terms wallet-state-attestation --- alongside, not within, the existing credential-presentation stack. 1.2. Position Relative to Identity Primitives OAuth and OIDC prove who a subject is. Wallet State Attestation proves what a wallet currently holds, owns, or has been attested to in on-chain state. These are complementary, not competing. A system may use OAuth to authenticate a human or service principal, then call a wallet-state attestation issuer to verify that a wallet associated with that principal satisfies an on-chain condition. The two primitives operate on different subjects (identity vs. wallet state) and answer different questions. 1.3. Position Relative to Credentials Wallet State Attestation is *not* a Verifiable Credential (W3C VC) [VC-DATA-MODEL], an mDoc / ISO/IEC 18013-5 mobile document, an eIDAS attestation, a SAML assertion, or an OIDC ID token. These are credential-presentation primitives: an authority issues a credential, the holder presents it, the verifier checks the issuer's signature over the holder's presented bytes. Borthwick Expires 31 March 2027 [Page 3] Internet-Draft Wallet State Attestation September 2026 Wallet State Attestation does not involve credential presentation. The holder does not present anything. The issuer pulls public on- chain state directly, evaluates a condition, and signs the result. The signed payload is an observation about external state, not a credential about the holder's identity. This document treats the credential / VC / eIDAS / SAML stack as adjacent prior art for explicit non-conflation purposes. See Section 13 ("What This Is Not") for the full enumeration. 1.4. Position Relative to Other Documents Wallet State Attestation is referenced or adopted in the following public artifacts (all informative; see References): * *Knowledge Context Protocol (KCP) RFC-0004* [KCP-0004] --- defines an attestation_url / attestation_jwks mechanism in KCP YAML manifests for verifying agent eligibility before access. The pattern is mechanism-agnostic; wallet state attestation is one valid implementation shape. * *Verifiable Intent (VI) environment.* constraint family* [VI-ENVIRONMENT] --- defines an environmental constraint family for autonomous-mode (L3) execution in agent commerce, establishing family-wide vocabulary (attestation_url, max_attestation_age), composition rules, and IANA registry mechanics for individual constraint types. The wallet-state-attestation primitive is the reference implementation shape used by VI's environment.wallet_state constraint type. * *Agent Governance Vocabulary* [AGV] --- defines wallet_state as a foundation-layer signal type with named production issuers. * *Open Agent Trust Registry (OATR)* [OATR] --- third-party trust registry of attestation issuers, including wallet-state- attestation issuers. * *Draft ERC-8210 Agent Assurance Protocol* [ERC-8210] --- proposed IRiskHook verification taxonomy identifies wallet state attestation as the representative shape for pre-commitment eligibility verification (one of three categories in the verification framework, alongside post-hoc resolution evidence and behavioral reputation). * *Universal Commerce Protocol (UCP) identity-linking* [UCP-IDENTITY] --- wallet attestation acknowledged as a reserved extensibility point for future non-OAuth identity-mechanism types. Borthwick Expires 31 March 2027 [Page 4] Internet-Draft Wallet State Attestation September 2026 Wallet state attestation is *not* dependent on or normatively related to any of these documents. They are listed as evidence of adoption and as informative context for readers seeking to understand where the primitive is in use. 1.5. Use Cases Common deployments of wallet state attestation include: * *Condition-based access* --- gating API access, content access, or commerce flows on whether a specified wallet holds a specified token, NFT, or attested status at request time, without exposing actual balance or transaction history. * *Agent-to-agent trust verification* --- autonomous agents verifying counterparty wallet state (holdings, attested compliance status, etc.) before transaction execution. * *Compliance gating* --- verifying on-chain compliance attestations (KYC status from external attestors, country attestations, sanctions clearance) against a wallet without the verifier receiving any identity attribute beyond the boolean it asked for (Section 11.3). * *Pre-commitment eligibility* --- agent commerce protocols verifying that an agent wallet satisfies pre-conditions (sufficient stake, sufficient balance, attested status) before contract commitment. The primitive is read-only and does not interact with chain state beyond observation. Implementations issue attestations on demand; attestations are short-lived and expire (typically thirty minutes; see Section 5). 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. The following terms are used throughout this document: *Issuer* --- The party that reads on-chain state, evaluates conditions, and signs the resulting attestation. The issuer is the sole signer of attestations within its declared scope (see Section 10.1). Borthwick Expires 31 March 2027 [Page 5] Internet-Draft Wallet State Attestation September 2026 *Holder* --- The wallet whose on-chain state is observed. The holder does not present anything in this primitive; the issuer reads chain state directly. The holder need not be aware of any individual attestation. *Verifier* --- The party that consumes the attestation, checks the signature against the issuer's published JWKS, and acts on the result. *Condition* --- An operator-defined predicate over wallet state. Examples include: "balance of token T at address A is greater than or equal to value V", "wallet A owns NFT N", "wallet A has a valid on- chain attestation of type T from attestor X". *Attestation* --- The signed payload returned by the issuer in response to a request. Distinguish explicitly from a credential (which is presented by a holder), from a JWT claim in the credential sense (which carries identity information), and from a VC (which is issued by an authority over a holder's presented identity). An attestation in this document's sense is an issuer-signed observation about public on-chain state. *Fact profile* --- A multi-condition, multi-dimension attestation payload consisting of a structured collection of condition results, organized by dimension and covered by a single issuer signature. A fact profile is signed as one object under the algorithms of this document; its detailed format is not specified here. Used for richer wallet-state queries where a single boolean is insufficient. Distinguish explicitly from a "trust score" or "reputation rating" --- a fact profile contains observed evidence organized by dimension, not an opinion or aggregate. *Block reference* --- Chain-specific freshness evidence included in every attestation. EVM chains MUST include block number and block timestamp. XRPL MUST include ledger index and, where available, ledger hash. Solana MUST include slot. Bitcoin MUST include block height and block hash (chain-tip evidence; see Section 9 for Bitcoin- specific considerations). Any other chain family MUST include the reference the issuer documents for it. *Condition hash* --- A SHA-256 hash of the JSON serialization of the evaluated condition, with member names sorted as [RFC8785] sorts them and no insignificant whitespace, represented as a 0x-prefixed lowercase hexadecimal string, included in the response for tamper- evidence over the condition itself. Borthwick Expires 31 March 2027 [Page 6] Internet-Draft Wallet State Attestation September 2026 3. Architecture Overview The primitive operates as a three-step pipeline: *read -> evaluate -> sign*. 1. The issuer receives a request specifying a wallet address, a chain identifier, and one or more conditions. 2. The issuer reads canonical on-chain state for the specified wallet at or near the current chain tip. The issuer selects the block and reports it in the block reference. 3. The issuer evaluates each condition against the observed state. 4. The issuer signs the result and returns the attestation. The evaluation is *deterministic*: the same condition evaluated against the same chain state at the same block produces the same per- condition result. A verifier can independently re-derive each result by reading the same chain state and applying the same condition logic, exactly where the block reference names the state that was read (an EVM block, an XRPL ledger) and to within the anchor where the reference is a tip marker or a floor, as the issuer documents per chain family. The attestation identifier, the attestedAt timestamp, and the signature value differ from one issuance to the next. The primitive is *read-only*: the issuer does not modify chain state, does not request a wallet signature from the holder, and does not custody any assets. The issuer is a passive reader of public chain state. For each chain referenced in the request, the issuer captures a block reference (block number and block timestamp for EVM chains; ledger index and, where available, ledger hash for XRPL; slot for Solana; block height and block hash for Bitcoin; for any other chain family, the reference the issuer documents) at attestation time. The block reference is carried inside each per-condition result and is therefore covered by the issuer's signature. If a required chain observation cannot be acquired, the issuer MUST NOT sign the attestation; see Section 10.3. This document does not specify how the issuer reads chain state (RPC routing, indexer choice, archive node selection), how it manages signing keys (HSM, software, federated), or how it handles chain- specific edge cases (reorgs, finality, data availability). These are implementation concerns, deliberately left out of scope. Borthwick Expires 31 March 2027 [Page 7] Internet-Draft Wallet State Attestation September 2026 4. Request Shape A request is a JSON object with the following structure: { "wallet": "
", "conditions": [ { "type": "", "chainId": "", "...": "" } ], "format": "jwt", "proof": "merkle" } *wallet* --- A chain-specific address string. EVM addresses use the standard 0x-prefixed hexadecimal form. Solana addresses use base58. XRPL addresses use the r-address format. Bitcoin addresses MAY use any standard format (P2PKH, P2SH, bech32 / SegWit, bech32m / Taproot). Because one request can span several chains, an implementation MAY reserve wallet for one address family and carry the others in chain-specific members (e.g., solanaWallet, xrplWallet, bitcoinWallet). *chainId* --- A chain identifier, carried by each condition whose type is not bound to a single chain, so that one request can span several chains. EVM chains use the numeric EIP-155 chain identifier (the reference part of a CAIP-2 identifier [CAIP-2]), expressible as integer (e.g., 1 for Ethereum mainnet) or string. Non-EVM chains use a string identifier naming the chain (for example solana, xrpl, bitcoin). *conditions* --- A list of one or more condition objects. Each has a type field discriminating the condition category, and type-specific fields specifying the parameters of that category. This document does not enumerate all possible condition types. Common categories include token balance evaluation, NFT ownership evaluation, on-chain attestation reference (e.g., reference to an Ethereum Attestation Service entry), and identity-registry membership evaluation. Implementations MAY define additional condition types. *format* --- OPTIONAL. When "jwt", the response additionally carries the attestation as an RFC 7519 JWT (Section 8). When omitted, the response is the JSON format of Section 5 alone. Borthwick Expires 31 March 2027 [Page 8] Internet-Draft Wallet State Attestation September 2026 *proof* --- OPTIONAL. Requests a cryptographic proof layer. When omitted, no proof is requested. Value: "merkle" (where supported by the underlying chain; returns [EIP-1186] Merkle storage proofs anchored to the block header). 5. Response Shape A response contains a signed attestation object together with the signature and key identifier. The signed attestation object has the following structure: { "id": "", "pass": true, "results": [ { "condition": 0, "label": "", "type": "", "chainId": "", "met": true, "evaluatedCondition": { /* condition object */ }, "conditionHash": "0x", "blockNumber": "", "blockTimestamp": "" } ], "attestedAt": "" } The signature is computed over signed bytes derived from this object under the signing scheme that the transmitted kid selects (Section 6). The signature, the key identifier (kid), expiry timestamp (expiresAt), and any deployment-specific wrappers are transmitted alongside the signed object but are NOT part of the signed bytes. Nor is any member of the transmitted attestation object other than id, pass, results, and attestedAt: an issuer MAY add informational members there (for example, counts of met and unmet conditions), and they are unsigned. Note that the signed object does not in general name the wallet: the requester knows which wallet it asked about, but a party that receives a JSON-format attestation second-hand cannot bind it to a wallet from the signed bytes alone (some condition types carry the address inside evaluatedCondition). The JWT format names the wallet in its sub claim (Section 8). A typical wire response carries the signed object plus these adjacent fields: Borthwick Expires 31 March 2027 [Page 9] Internet-Draft Wallet State Attestation September 2026 { "attestation": { /* signed object above */ "expiresAt": "" }, "sig": "", "kid": "", "pqSig": "", "pqKid": "" } Field semantics (signed object): *id* --- An opaque attestation identifier. Implementation-specific format. Useful for correlation, logging, and replay detection. It is covered by the signature. *pass* --- The aggregate result. Default semantics: logical AND of all per-condition met values. Operators MAY specify alternate combination logic in extensions. *results* --- An array of per-condition result objects. Each MUST include the per-condition met boolean, the condition type, the verbatim evaluatedCondition (as it was evaluated, after any normalization), and the conditionHash (SHA-256 of the UTF-8 JSON serialization of evaluatedCondition with member names sorted as [RFC8785] sorts them (by UTF-16 code units) and no insignificant whitespace, as a 0x-prefixed lowercase hexadecimal string). The evaluatedCondition object is flat: its member values are strings, numbers, booleans, or null, never objects or arrays, so that sorting its member names fully determines the serialization; strings and numbers are serialized as in the bare scheme of Section 6.1. A verifier MUST recompute conditionHash from the transmitted evaluatedCondition and MUST reject the result as altered if the two differ. Each result MUST include chain-specific freshness evidence: blockNumber and blockTimestamp for EVM chains; ledgerIndex and (where available) ledgerHash for XRPL; slot for Solana; blockHeight and blockHash for Bitcoin; for any other chain family, the reference the issuer documents for it. All such freshness fields are inside the signed results array and are therefore covered by the issuer's signature. Implementations MAY include additional informational fields (condition index, label, etc.) echoed from the request. *attestedAt* --- ISO 8601 timestamp of when the attestation was signed. Field semantics (adjacent, unsigned): Borthwick Expires 31 March 2027 [Page 10] Internet-Draft Wallet State Attestation September 2026 *expiresAt* --- ISO 8601 timestamp of when the attestation expires. Verifiers SHOULD check expiry (step 6 of Section 12). Recommended default: thirty minutes after attestedAt. Implementations MAY use shorter expiries; longer expiries SHOULD be justified by the use case. expiresAt is transmitted with the attestation but is not part of the signed payload; verifiers concerned with tamper-evidence over the expiry SHOULD use the JWT format (Section 8), where exp is a signed claim. *kid* --- Key identifier (RFC 7517) for the public key used to sign this attestation. Verifiers use this to look up the appropriate public key in the issuer's JWKS. kid is transmitted alongside the signed payload but is not part of the signed bytes. The kid selects both the verification key and the signing scheme (Section 6.1); verifiers resolve it against the issuer's published JWKS as described in Section 7. The JWT format embeds kid in the protected header where it is covered by the JWT signature. *sig* --- The signature. Default: ECDSA P-256 signature over the signed bytes defined in Section 6, in P1363 (raw R || S) format, base64-encoded with the standard alphabet and padding (Section 4 of [RFC4648]). *pqSig*, *pqKid* --- OPTIONAL. A companion signature under a second algorithm and the identifier of the key that produced it (Section 6.3). When present they are additive: sig and kid are unchanged by their presence, and a verifier that does not implement companion verification ignores them. The signature scope includes the evaluatedCondition and conditionHash fields nested inside results, ensuring the signature is tamper- evident over both the result and the condition that produced it. 6. Signing Algorithm The default signing algorithm is *ECDSA with P-256 curve and SHA-256 (ES256)* per [RFC7518]. The signed bytes are produced under one of the signing schemes in Section 6.1. An issuer MAY additionally attach a companion signature under a second algorithm (Section 6.3). Borthwick Expires 31 March 2027 [Page 11] Internet-Draft Wallet State Attestation September 2026 6.1. Signing Schemes This document defines two signing schemes. The type of message a verifier holds is evident from its shape (an attestation of Section 5 carries pass and results; a fact profile does not); the kid transmitted with it selects both the verification key and the signing scheme. The issuer's documentation states, for each kid it publishes, which scheme that kid selects and, for the domain- separated scheme, the domain tag. Verifiers MUST determine the scheme from the kid, MUST NOT assume that an issuer uses a single scheme, and MUST NOT verify an attestation under any scheme other than the one its kid selects. A single public key MAY be published under more than one kid, so that one key serves more than one scheme. An issuer that signs more than one type of message under the domain- separated scheme MUST use a distinct domain tag for each type, and a verifier MUST NOT accept an attestation under a kid that the issuer documents for a different type of message. Signing schemes apply to the JSON format of Section 5. In the JWT format (Section 8) the signed bytes are the JWS Signing Input [RFC7515] of the JWT [RFC7519], whatever scheme the kid would select in the JSON format; there the kid selects the verification key (and, through its JWKS entry, the algorithm) but no scheme. *Bare scheme.* The signed bytes are the JSON serialization of an object carrying exactly the four members of the signed object, in the order id, pass, results, attestedAt, with no insignificant whitespace, encoded as UTF-8. Inside results, every member of every result object, including the members of evaluatedCondition, is serialized in the order in which it was transmitted, and array element order is preserved. Nothing inside the signed bytes of this scheme is re-sorted: the sorting of member names described in Section 5 applies only to the computation of conditionHash. Strings and numbers are serialized as the ECMAScript JSON.stringify function serializes them, which for well-formed Unicode strings and finite numbers is also the serialization of primitive values specified by [RFC8785]. The signed bytes are not transmitted as such; a verifier reconstructs them from the transmitted response. Under the bare scheme a verifier therefore MUST use a JSON parser that preserves the order of object members, and MUST omit from the reconstruction every member of the transmitted attestation object other than the four named above. *Domain-separated scheme.* The signed bytes are the concatenation of (1) a domain tag, (2) a single line feed character (U+000A), and (3) the canonical serialization of a JSON object carrying the member v (the scheme version, the integer 2 for the scheme defined here) Borthwick Expires 31 March 2027 [Page 12] Internet-Draft Wallet State Attestation September 2026 together with the four members of the signed object (id, pass, results, attestedAt). The canonical serialization is the JSON Canonicalization Scheme [RFC8785]: member names sorted at every level of nesting, array element order preserved, no insignificant whitespace, and strings and numbers serialized as that document specifies. (RFC 8785 requires well-formed Unicode strings; an issuer MUST NOT sign a string that is not.) Because the member names are sorted, a verifier needs no order-preserving parser under this scheme. The domain tag is an ASCII string, fixed by the issuer, that identifies the message type and the scheme version. It binds a signature to its message type, so that a signature produced over one type of message cannot be presented as a signature over another. An issuer using this scheme SHOULD carry numeric quantities inside the signed object (thresholds, amounts, ratios) as decimal strings and SHOULD confine JSON numbers to small integers, so that the signed bytes do not depend on any implementation's floating-point number formatting and can be reproduced exactly in any language. The signed bytes are encoded as UTF-8. Signed bytes are stable per kid. An issuer introducing a new scheme MUST do so under a new kid and MUST NOT change the signed bytes produced under a kid it has already published. Attestations signed under an earlier scheme therefore remain verifiable, unchanged, by verifiers deployed before the new scheme existed. 6.2. Signature Encoding and Additional Algorithms The signature output is the raw P1363 (R || S) representation of the ECDSA signature, base64-encoded (88 characters for P-256). Implementations producing DER-encoded ECDSA signatures MUST convert to P1363 before transmission. Implementations MAY support additional algorithms (ES384, EdDSA / Ed25519). Algorithm selection is encoded in the JWKS entry indexed by kid. Verifiers MUST NOT verify a signature under an algorithm other than the one the selected JWKS entry implies (its alg, and the key type and curve it carries). 6.3. Companion Signatures An issuer MAY attach to an attestation a companion signature produced under a second algorithm, for example a post-quantum signature algorithm. A companion signature is additive: it changes neither the signed object, nor the signed bytes defined in Section 6.1, nor the values of sig and kid. A verifier that does not implement companion verification ignores the companion fields and is otherwise unaffected. Borthwick Expires 31 March 2027 [Page 13] Internet-Draft Wallet State Attestation September 2026 In the JSON format the companion is carried in two adjacent fields: pqSig, the companion signature, base64-encoded with the standard alphabet and padding (Section 4 of [RFC4648]), and pqKid, the key identifier of the companion key in the issuer's JWKS. The companion signature is computed over the concatenation of (1) a companion domain tag, (2) a single line feed character (U+000A), and (3) the exact signed bytes that the attestation's kid selects under Section 6.1, encoded as UTF-8. A verifier therefore reuses the bytes it has already reconstructed for the primary signature. The companion domain tag is distinct from any domain tag used by a signing scheme and is documented by the issuer for each pqKid it publishes. The companion algorithm defined by this document is ML-DSA-65 [FIPS204]. Signatures are produced as in Algorithm 2 of [FIPS204] (ML-DSA.Sign, not the pre-hash variant) with an empty context string; these are the parameters that [RFC9964] specifies for JOSE. The companion key is published in the issuer's JWKS (Section 7 of this document) as an AKP key, the key type defined by [RFC9964]. In the JWT format (Section 8) the companion is a sibling token, pqJwt, returned beside the ES256 JWT: a JWS in compact serialization [RFC7515] whose protected header carries alg ML-DSA-65 and the companion kid, and whose claims are the same as those of the ES256 JWT. No companion domain tag is used in the JWT format: pqJwt is verified over its own JWS signing input. A verifier that checks pqJwt MUST also confirm that its payload and the ES256 JWT's payload carry the identical claim set: the same member names and, for every member, a deeply equal JSON value (objects compared without regard to member order, arrays in order, numbers by value). Any difference, whether a changed value, a missing member, or an extra member on either side, makes the companion refuted. Byte-identical payload segments satisfy this trivially, but a verifier MUST NOT require byte-for-byte equality, since two serializers may order members differently. The companion then vouches for every claim a relying party reads from the ES256 JWT, and cannot be transplanted from another attestation. Borthwick Expires 31 March 2027 [Page 14] Internet-Draft Wallet State Attestation September 2026 A verifier that implements companion verification MUST report the companion result as a verdict separate from the primary signature result, with one of four values: _verified_ (transmitted, and verifies under the key that pqKid selects; in the JWT format, also carrying the same claim set as the ES256 JWT); _refuted_ (transmitted, and either fails verification under that key or, in the JWT format, carries a different claim set); _absent_ (no companion was transmitted, that is, no pqSig in the JSON format and no pqJwt in the JWT format); or _unverifiable_ (transmitted, but the verifier could not check it). Unverifiable records a gap in the verifier's knowledge; refuted records positive evidence of alteration. A verifier determines the verdict by the first of these that applies: 1. No companion was transmitted: absent. 2. The attestation's own kid is missing, or is one the verifier has never met, so the signed bytes the companion covers cannot be reconstructed: unverifiable. A verifier MUST NOT substitute the signed bytes of another scheme for a kid it does not know, since that could only produce a false refutation. 3. pqKid resolves to no JWKS entry, resolves to a key of the wrong type, or names a companion key the issuer documents for a different type of message; or pqSig is transmitted without pqKid; or the verifier has no implementation of the algorithm: unverifiable. A verifier applies no companion domain tag other than the one pqKid names, so a pqKid of the wrong type leaves it nothing it is entitled to check. 4. Otherwise the companion signature is checked, and in the JWT format the claim sets are compared: verified or refuted. An attestation whose own kid the verifier knows but the issuer documents for a different type of message reaches this step with well-defined signed bytes, and its companion is checked against them; a relabelled artifact is therefore never unverifiable. Item 2, and the relabelling case of item 4, concern the signed bytes of the JSON format. In the JWT format the companion is a JWS over its own signing input and is bound to the ES256 JWT by its claim set, so it is evaluated whether or not the JWT's kid selects a key; a genuine pqJwt beside a JWT whose kid the verifier cannot place is reported verified while the JWT's own signature verdict is unverifiable. In the JWT format, a pqJwt that does not parse as a compact JWS, or whose protected header lacks either the companion algorithm or a kid, is malformed and is refuted, since the header is covered by the companion signature and the issuer always emits both; this rule is Borthwick Expires 31 March 2027 [Page 15] Internet-Draft Wallet State Attestation September 2026 applied before item 3 of the list. A refuted companion MUST cause the attestation to be rejected. An unverifiable companion MUST NOT be treated as verified. Whether an absent or unverifiable companion causes rejection is a matter of verifier policy: a verifier MAY require a verified companion from a date of its own choosing, and it MUST judge that date by its own clock at the time of verification, never by a timestamp carried in the attestation. A verifier reading an attestation after the fact, as a record rather than for a live decision, MUST NOT refuse it for lacking a companion; it reports the absence. 7. JWKS Discovery The issuer publishes its public key set at a discoverable HTTPS endpoint following [RFC7517]. A commonly used path is /.well-known/ jwks.json, under the well-known URI prefix of [RFC8615]; this document does not register that path. Each JWKS entry MUST include kid, kty, and alg, together with the public key parameters that its key type requires: crv, x, and y for an elliptic curve key (kty EC, [RFC7518]); pub for an Algorithm Key Pair key (kty AKP, [RFC9964]); and correspondingly for any other key type. A JWKS MAY therefore hold keys of more than one key type, and verifiers MUST NOT require the parameters of one key type on an entry of another. Issuers MAY publish multiple active keys simultaneously, to support key rotation, more than one signing scheme (Section 6.1), or companion signatures (Section 6.3). An issuer adding entries of a new key type to an existing JWKS SHOULD append them after the existing entries, so that the position of every existing entry is unchanged for deployed verifiers. Key selection: verifiers MUST select the verification key by the transmitted kid, never by position in the JWKS and never by default. If the kid is missing, or resolves to no entry in the JWKS available to the verifier, the verifier MUST NOT accept the attestation and MUST NOT substitute any other key, including the first entry in the JWKS or a key built into the verifier. Such an attestation is _unverifiable_, which is distinct from _refuted_: a refuted attestation carries a signature that fails under the key its kid selects, whereas nothing has been shown about the signature of an unverifiable one. Verifiers SHOULD report the two outcomes distinctly. Neither outcome is a successful verification. Key rotation: when the issuer rotates signing keys, the new public key MUST be published in JWKS before the issuer signs any attestation with the corresponding private key. Retired public keys SHOULD remain published in JWKS for a duration at least equal to the longest possible outstanding attestation expiry (typically the default Borthwick Expires 31 March 2027 [Page 16] Internet-Draft Wallet State Attestation September 2026 thirty-minute window). An issuer MAY instead retain every key it has ever published, under its original kid, so that an attestation kept as a record remains checkable for as long as anyone holds it; retention does not extend an attestation's validity, which its expiry still governs. Relying parties that keep attestations as records SHOULD keep a copy of the JWKS with them. Because JWKS documents are cached, by verifiers and by intermediaries, different verifiers can hold different versions of an issuer's JWKS for up to the cache lifetime after it changes. During that interval a verifier holding the earlier version will find that a newly introduced kid resolves to no entry; the attestation is then unverifiable, not refuted, as described above. A verifier that meets an unknown kid MAY refresh its copy of the JWKS and retry. Verifiers SHOULD cache the JWKS according to the HTTP cache headers the issuer publishes, and MAY be supplied with a copy of the JWKS out of band instead of fetching it. The cache lifetime an issuer sets bounds how quickly a newly published kid becomes visible to verifiers; an issuer SHOULD document it. 8. JWT Format When format is "jwt", the response additionally carries the attestation as an RFC 7519 JWT, in a jwt member beside the members of the JSON format (Section 5). Protected header: {"alg": "ES256", "typ": "JWT", "kid": ""} per [RFC7519]. The kid in the protected header is covered by the JWT signature. Standard claims: * iss --- issuer identifier (e.g., the issuer's base URL) * sub --- the wallet address a condition in the request evaluated. When the conditions span several address families, the issuer documents which family's wallet sub names; a wallet the request supplied but no condition evaluated is not named. * jti --- JWT identifier (typically the attestation id) * iat --- issuance timestamp (Unix seconds) * exp --- expiry timestamp (Unix seconds) Custom claims carrying the attestation payload: Borthwick Expires 31 March 2027 [Page 17] Internet-Draft Wallet State Attestation September 2026 * pass --- aggregate result * results --- per-condition result array * conditionHash --- array of per-condition conditionHash values, in results order * blockNumber --- chain block reference (typically the first result's blockNumber, where chain-homogeneous) * blockTimestamp --- chain block timestamp (typically the first result's blockTimestamp) The JWT signature is computed by the issuer using the corresponding private key. Verifiers verify using any standard JWT library that supports ES256 and JWKS discovery. When the issuer attaches a companion signature, the JWT format carries it as the sibling token pqJwt (Section 6.3); the ES256 JWT is unchanged by its presence. The JWT format provides signed coverage of exp and kid (via standard claim and protected header, respectively); deployments requiring tamper-evident expiry or signed key-identifier binding SHOULD use the JWT format rather than the JSON format described in Section 5. A response in the JWT format carries the token beside the JSON-format members, so a verifier may hold both. A relying party that reads claims from the JWT MUST have verified the JWT itself; verifying the JSON-format attestation beside it is not a substitute, because the two are separately signed. A verifier handed both SHOULD verify the JWT as well as the attestation, and report the JWT's outcome as its own verdict: its signature under the same kid as the response, its results under step 4 of Section 12, its companion under Section 6.3, and that it is the token of this attestation (its kid equals the response's kid, jti equals id, and pass, results, and exp equal the attestation's pass, results, and expiresAt truncated to whole seconds). A transmitted JWT that fails any of these rejects the response: a relying party cannot tell which of the two it will be shown. The correspondence check does not cover sub, which the JSON- format attestation does not carry; the wallet named in sub is vouched for by the JWT's own signature alone. A JWT MAY also be presented on its own; it is then a complete attestation, verified as Section 12 describes for the JWT format, without the correspondence check. Borthwick Expires 31 March 2027 [Page 18] Internet-Draft Wallet State Attestation September 2026 9. Optional Merkle Proofs When proof is "merkle" and the underlying chain supports Merkle storage proofs (typically EVM chains for storage-slot-mappable conditions), the response MAY include [EIP-1186] Merkle storage proofs anchored to the block header for each per-condition result. Merkle proofs permit trustless verification: a verifier can independently check the Merkle proof against the block reference without trusting the issuer's evaluation. When a Merkle proof is included (proof.available is true in the per-result proof object), the proof object MUST include the block reference and the proof nodes needed to check the proven value against that block's state root (for a storage-slot proof, including the storage slot path). Not all conditions or chains support Merkle proofs. Implementations MUST indicate proof availability per result and MAY return proof.available: false with a reason field when proof generation is unsupported for the condition or chain (e.g., NFT ownership conditions, non-storage-slot-mappable conditions, non-EVM chains). *Privacy trade-off:* Merkle proofs reveal raw on-chain values (e.g., the actual token balance). When no proof is requested, the wallet's balance is not returned. Operators MUST consider whether the trustlessness benefit of Merkle proofs is worth the privacy cost in each deployment. Bitcoin, XRPL, and Solana have different state-proof models and may not support Merkle proofs in the [EIP-1186] sense. Implementations targeting those chains MAY define chain-appropriate proof shapes or MAY return proof.available: false. For Bitcoin specifically: the UTXO model does not permit reproducible balance-at-block queries. Bitcoin implementations anchor the attestation to the chain tip (block height + block hash) at observation time as the cryptographically-bound freshness evidence appropriate to the UTXO model. The blockHeight and blockHash are covered by the issuer's signature inside the result and bind the observation to a recent chain tip rather than to a specific block's historical state. Issuers MUST refuse to sign Bitcoin attestations when the chain-tip lookup fails; see Section 10.3. 10. Security Considerations Borthwick Expires 31 March 2027 [Page 19] Internet-Draft Wallet State Attestation September 2026 10.1. Single-Issuer Architecture This document describes a single-issuer attestation primitive. The issuer is the sole signer of attestations within its declared scope. This is a deliberate design choice for several reasons: 1. *Deterministic signature surface.* Verifiers can independently re-derive an attestation's results from chain state without resolving issuer trust hierarchies, federation policies, or multi-party signing logic. 2. *No re-signing or wrapping.* This document defines no re-signing, aggregation under a wrapper signature, or repackaging of attestations by any party other than the issuer; a wrapper or aggregate signature confers no authority, and a verifier accepts no signature other than the issuer's own (its primary signature, and any companion or JWT signature the issuer itself produced, Section 6.3 and Section 8). The original observation's signature is the authoritative artifact end-to-end. 3. *Unambiguous attribution.* For audit, dispute resolution, and accountability, the issuer is unambiguously identified by the JWKS endpoint and signing key. Multi-issuer federation, key delegation, cross-issuer attestation aggregation, and threshold signing are explicitly out of scope for this document. Future Internet-Drafts MAY define such mechanisms as separate primitives, but they are distinct from the single-issuer wallet-state attestation defined here. 10.2. Freshness Anchors and Replay Considerations The cryptographically-bound freshness anchors are the block reference inside each per-condition result and the attestedAt timestamp in the outer signed payload (the iat claim in the JWT format). Both are covered by the issuer's signature. Verifiers requiring strict tamper-evident freshness derive their policy from these signed anchors (e.g., "reject if attestedAt is older than thirty minutes", or "reject if blockTimestamp is older than sixty seconds"). The expiresAt field is an issuer-provided TTL hint, transmitted alongside the attestation but outside the signed payload in the JSON format described in Section 5. Because expiresAt is unsigned in the JSON format, a verifier that relies on it SHOULD confirm that it is no later than the signed attestedAt plus the issuer's documented validity window, and SHOULD reject the attestation as altered otherwise. Deployments requiring tamper-evident expiry SHOULD use the JWT format described in Section 8, where exp is a signed claim. Borthwick Expires 31 March 2027 [Page 20] Internet-Draft Wallet State Attestation September 2026 For replay-sensitive deployments, implementations MAY include a nonce binding or audience binding in custom JWT claims (when the JWT format is used). This document does not normatively specify these extensions; deployments requiring replay protection beyond freshness checking SHOULD define them explicitly in their integration profile. 10.3. Refuse-on-Observation-Failure Issuers MUST refuse to sign an attestation when any required observation fails: chain-tip lookup, balance query, on-chain attestation registry lookup, or any other data source the condition depends on. A successfully signed attestation therefore implies that all underlying observations were acquired against a current chain reference at attestation time. Partial or degraded observations MUST NOT be signed. Verifiers MAY cross-check the included block reference against an independent chain source if the deployment requires it. 10.4. What This Primitive Does Not Protect Against * *Chain-level reorganizations after attestation.* If a chain reorgs after an attestation has been signed, the historical state observed in the attestation may no longer be canonical. Operators handling this concern SHOULD use chains with strong finality, SHOULD use sufficiently old block references, or SHOULD include reorg-handling logic in their verification flow. * *Off-chain state changes.* This primitive observes on-chain state only. It does not attest to off-chain identity, off-chain agreements, or off-chain commitments. * *Malicious issuer.* A compromised or malicious issuer could sign false attestations. This is mitigated by: (a) JWKS publication of signing keys, (b) optional Merkle proofs for trustless verification (where supported), (c) condition hashes for tamper- evidence over the evaluated logic, and (d) deterministic re- derivation by independent verifiers. 10.5. Algorithm Agility The default ES256 algorithm is widely supported and provides 128-bit security. Implementations supporting additional algorithms MUST include the algorithm in the JWKS entry indexed by kid. Verifiers MUST check the algorithm before verifying. Borthwick Expires 31 March 2027 [Page 21] Internet-Draft Wallet State Attestation September 2026 Algorithm migration: when the cryptographic landscape changes (e.g., post-quantum migration), this document provides two paths, and an issuer can use either or both. _Rotation_: the issuer publishes a key for the new algorithm in JWKS under a new kid and begins signing with it; verifiers that do not support the new algorithm can no longer verify new attestations. _Composition_: the issuer continues to sign with the existing algorithm and attaches a companion signature under the new algorithm (Section 6.3). Composition leaves the existing signature, its signed bytes, and its key unchanged, so deployed verifiers that ignore unrecognized members keep working, and each verifier adopts the new algorithm on its own schedule by choosing the date from which it requires a verified companion. Composition is an application of post-quantum/traditional hybrid signing, for which [RFC9794] gives terminology. In the JSON format a companion signature covers the same signed bytes as the primary signature, so an attacker must defeat both algorithms to forge an attestation that is accepted by a relying party requiring both signatures to verify. In the JWT format the two tokens are signed separately, and the same property holds when the verifier requires their claim sets to be identical, as Section 6.3 requires: an attacker who defeats only the primary algorithm then cannot alter any claim without the companion refuting it. Under either path the protocol surface remains stable. 11. Privacy Considerations 11.1. Boolean by Default The default response mode returns the result of condition evaluation, not the wallet's balance. A verifier learns whether a wallet satisfies a condition (e.g., "holds at least 100 USDC") without being told the balance itself. An issuer MAY return public reference values that the evaluation used (for example, a token's total supply); it SHOULD NOT return a value from which the wallet's balance can be derived unless the caller requested proof mode. This is the privacy-preserving default and SHOULD be used unless specific deployment requirements justify a less-private mode. 11.2. Merkle Mode Trade-Off When proof is "merkle", raw on-chain values are revealed for trustless verification. Operators MUST consider the privacy implications of revealing actual balances or asset holdings in each deployment. Borthwick Expires 31 March 2027 [Page 22] Internet-Draft Wallet State Attestation September 2026 11.3. No Identity Attributes The primitive handles no identity attributes: no name, document, contact, or account data is collected, signed, or transmitted. The one identifier it handles is the wallet address (Section 11.4), which is public on the chain but persistent, and so may be personal data where it can be linked to a natural person. The signed output is a boolean about a condition; where the condition itself concerns a person (for example, a KYC or jurisdiction attestation issued by a third party), the boolean relates to that person even though no attribute is disclosed, and deployers should handle it as information about that person. The results echo operator-provided text (label, and the condition parameters in evaluatedCondition); operators SHOULD NOT place identity attributes in them. 11.4. Wallet Address Handling The wallet address is the subject of the query but is public information on the underlying chain. Issuers SHOULD NOT log or retain wallet addresses beyond what is required for service delivery, abuse prevention, and operational integrity. Implementations targeting privacy-conscious deployments SHOULD document their address-handling policy. 11.5. Awareness of Observation This primitive observes public chain state without holder participation. The holder is not required to consent to nor be aware of any individual attestation, consistent with the public nature of blockchain state. Deployers operating in regulated or consumer- facing contexts SHOULD consider whether their deployment context requires additional transparency mechanisms; such mechanisms are out of scope for this document. 12. Verification Procedure This section collects the checks of the preceding sections into one procedure for the JSON format, naming the verdict at each branch. Steps 1 to 4 are REQUIRED; steps 5 and 6 are RECOMMENDED; step 7 is OPTIONAL. A verifier SHOULD report each step's outcome separately rather than as one boolean, so that a relying party can apply its own policy to the recommended and optional steps. 1. *Select the key and scheme.* Read the transmitted kid. If it is absent, or resolves to no entry in the JWKS available to the verifier, stop: the signature verdict is _unverifiable_ (Section 7). Do not substitute any other key. If the kid resolves but the issuer documents it for a different type of Borthwick Expires 31 March 2027 [Page 23] Internet-Draft Wallet State Attestation September 2026 message, stop: the artifact is relabelled, and the signature verdict is _refuted_. Otherwise the kid selects the key, the algorithm (the JWKS entry's alg and key type), and the signing scheme with its domain tag (Section 6.1). 2. *Reconstruct the signed bytes* from the transmitted attestation object under the selected scheme: under the bare scheme, exactly the members id, pass, results, and attestedAt in that order, every nested member in transmitted order, no whitespace, UTF-8; under the domain-separated scheme, the domain tag, a line feed, and the RFC 8785 serialization of the object {v, id, pass, results, attestedAt} with v equal to the scheme version. Members of the transmitted object other than the four named are not part of the signed bytes. 3. *Verify the primary signature*: decode sig (standard base64, P1363), and verify it under the selected algorithm over the signed bytes. Failure is _refuted_; the attestation is rejected. 4. *Recompute each condition hash*: for every result, serialize evaluatedCondition with member names sorted and no whitespace (Section 5), hash it, and compare with the transmitted conditionHash. A mismatch marks the result as altered; the attestation is rejected. 5. *Check freshness* against the signed anchors (attestedAt and each result's block reference) under the verifier's own policy (Section 10.2), and reject identifiers already seen if replay protection is required. 6. *Check expiry*: reject if the current time is past expiresAt, and, because expiresAt is unsigned in this format, reject as altered an expiresAt later than the signed attestedAt plus the issuer's documented validity window (Section 10.2). A verifier MAY allow a small clock skew. 7. *Check the companion*, if one is transmitted, in the order given in Section 6.3, and report one of verified, refuted, absent, or unverifiable as its own verdict. Refuted rejects the attestation; absent and unverifiable are subject to the verifier's own policy. Borthwick Expires 31 March 2027 [Page 24] Internet-Draft Wallet State Attestation September 2026 After a stop at step 1, the verifier reports the signature verdict it reached and the companion verdict of Section 6.3; steps 4 to 6 need no key: step 4 MUST, and steps 5 and 6 SHOULD, still be performed and reported; a step the verifier did not perform is reported as not performed, never as passed; a verifier whose report has no separate state for an unperformed step reports it as failed with a reason that says it was not performed. The attestation is rejected whenever the signature verdict is not verified. In the JWT format, steps 1 to 3 are performed by a JWS library over the token's own signing input, with the library pinned to the algorithm the selected JWKS entry implies rather than to the token's own alg header (the kid still selects the key, and step 1's rules for a missing, unknown, or wrong-type kid still apply), step 4 applies to the results claim, expiry is the signed exp claim, and the companion is pqJwt bound by the full claim set (Section 6.3). A verifier holding both formats of the same attestation also verifies the token beside the attestation as Section 8 describes. Issuers SHOULD publish test vectors covering, at least: a genuine attestation under each scheme they use; a tampered condition, a tampered signature, and a tampered condition hash; a missing and an unknown kid; and, where companions are used, a genuine, a tampered, and a mislabelled companion. A verifier that reproduces the published verdicts on such a set has evidence of interoperability that reading this document alone cannot give. 13. What This Is Not This section explicitly enumerates adjacent primitives that wallet state attestation is *not*, to prevent conflation: * *Not a Verifiable Credential (W3C VC) [VC-DATA-MODEL].* VCs are issued by an authority, presented by a holder, and verified against the holder's presented bytes. Wallet state attestations are pulled by the issuer from public chain state without holder presentation. * *Not an mDoc or eIDAS attestation.* mDocs (ISO/IEC 18013-5) are pre-issued, batched, and stored by the holder for later presentation. Wallet state attestations are issued on demand, are short-lived, and are not stored by the holder. * *Not a SAML assertion or OIDC ID token.* These primitives carry identity claims about a user. Wallet state attestations carry observations about wallet state, with no identity attribute (Section 11.3). Borthwick Expires 31 March 2027 [Page 25] Internet-Draft Wallet State Attestation September 2026 * *Not a reputation score, trust score, or credit rating.* A wallet state attestation contains observed facts (boolean results, optionally with structured fact profiles). It does not contain opinions, scores, ratings, or aggregated judgments. A separate primitive built on top of wallet state attestations might produce a score; this primitive does not. * *Not a settlement attestation, delivery attestation, or transaction proof.* Wallet state attestation is read-only state observation at observation time. It does not attest to action confirmation, transaction completion, or delivery of goods or services. * *Not an oracle in the price-feed sense.* This primitive observes specific wallet state on demand for a specific request; it does not publish continuous data streams or aggregate market data. These distinctions are essential to keeping wallet state attestation as a distinct primitive in the agent-commerce, condition-based- access, and verification ecosystems. 14. IANA Considerations This document has no IANA actions. 15. References 15.1. Normative References [FIPS204] National Institute of Standards and Technology, "Module- Lattice-Based Digital Signature Standard", NIST FIPS 204, DOI 10.6028/NIST.FIPS.204, August 2024, . [RFC2119] Bradner, S., "Key words for use in RFCs to Indicate Requirement Levels", BCP 14, RFC 2119, DOI 10.17487/RFC2119, March 1997, . [RFC4648] Josefsson, S., "The Base16, Base32, and Base64 Data Encodings", RFC 4648, DOI 10.17487/RFC4648, October 2006, . [RFC7515] Jones, M., Bradley, J., and N. Sakimura, "JSON Web Signature (JWS)", RFC 7515, DOI 10.17487/RFC7515, May 2015, . Borthwick Expires 31 March 2027 [Page 26] Internet-Draft Wallet State Attestation September 2026 [RFC7517] Jones, M., "JSON Web Key (JWK)", RFC 7517, DOI 10.17487/RFC7517, May 2015, . [RFC7518] Jones, M., "JSON Web Algorithms (JWA)", RFC 7518, DOI 10.17487/RFC7518, May 2015, . [RFC7519] Jones, M., Bradley, J., and N. Sakimura, "JSON Web Token (JWT)", RFC 7519, DOI 10.17487/RFC7519, May 2015, . [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, . [RFC9964] Prorock, M. and O. Steele, "ML-DSA for JSON Object Signing and Encryption (JOSE) and CBOR Object Signing and Encryption (COSE)", RFC 9964, DOI 10.17487/RFC9964, May 2026, . 15.2. Informative References [AGV] "Agent Governance Vocabulary", n.d., . [CAIP-2] "Chain Agnostic Improvement Proposal 2: Blockchain ID Specification", n.d., . [EIP-1186] "Ethereum Improvement Proposal 1186: RPC-Method to get Merkle Proofs", n.d., . [ERC-8210] "Draft Ethereum Improvement Proposal 8210: Agent Assurance Protocol", n.d., . [KCP-0004] "Knowledge Context Protocol RFC-0004: Trust, Provenance, and Compliance", n.d., . Borthwick Expires 31 March 2027 [Page 27] Internet-Draft Wallet State Attestation September 2026 [OATR] "Open Agent Trust Registry", n.d., . [OIDC-CORE] Sakimura, N., Bradley, J., Jones, M., de Medeiros, B., and C. Mortimore, "OpenID Connect Core 1.0", n.d., . [RFC6749] Hardt, D., Ed., "The OAuth 2.0 Authorization Framework", RFC 6749, DOI 10.17487/RFC6749, October 2012, . [RFC8615] Nottingham, M., "Well-Known Uniform Resource Identifiers (URIs)", RFC 8615, DOI 10.17487/RFC8615, May 2019, . [RFC9794] Driscoll, F., Parsons, M., and B. Hale, "Terminology for Post-Quantum Traditional Hybrid Schemes", RFC 9794, DOI 10.17487/RFC9794, June 2025, . [UCP-IDENTITY] "Universal Commerce Protocol: Identity Linking", n.d., . [VC-DATA-MODEL] Sporny, M., "Verifiable Credentials Data Model", n.d., . [VI-ENVIRONMENT] Borthwick, D. and M. Msebenzi, "Verifiable Intent --- environment.* Constraint Family", May 2026, . Changes from -00 This revision extends the format in two ways, restates the request shape, and states the existing format more precisely. Nothing an issuer signs changes: the signature over every attestation issued under -00 verifies under this revision exactly as before. Where a verifier built from this revision behaves differently from one built from -00, the difference is listed in the last two items or, for the added scheme and the correspondence check, in the item that introduces it. Borthwick Expires 31 March 2027 [Page 28] Internet-Draft Wallet State Attestation September 2026 * Section 6 now has subsections and defines two signing schemes selected by kid: the bare scheme and a domain-separated scheme based on [RFC8785]. It states that signed bytes are stable per kid, that one key may be published under several kid values, that the schemes apply to the JSON format, that the signed bytes are reconstructed from the transmitted object under the bare scheme with every member in transmitted order, and that sorting of member names applies to conditionHash alone. * New Section 6.3 defines optional companion signatures under a second algorithm (ML-DSA-65), carried as pqSig and pqKid in the JSON format and as pqJwt in the JWT format, bound in the JWT format by the full claim set, with four reported verdicts and the order in which they are determined. Section 10.5 describes composition alongside rotation as a path for algorithm migration. * New Section 12 collects the checks into one numbered procedure, names the verdict at each branch, states what is reported after a stop, maps the procedure onto the JWT format, and recommends that issuers publish test vectors. * Section 7 states the required JWK members per key type, so that a JWKS can hold elliptic curve and AKP keys together; the key selection rule (by kid, never by position or default; a missing or unknown kid is unverifiable, reported distinctly from refuted); that an issuer may retain published keys permanently; guidance on cached JWKS documents, including that a verifier MAY hold a copy of the JWKS supplied out of band and MAY refresh and retry on an unknown kid; and that new key types are appended after existing entries. Caching is stated in terms of the issuer's published headers, without a figure. * Section 5 states that members of the transmitted attestation object other than the four signed members are unsigned, that the signed object does not in general name the wallet, that evaluatedCondition is flat, the base64 alphabet, and the serialization used for conditionHash. Section 4: chainId is carried by each condition; format and proof are top-level members; the chain-family lists are open-ended. Section 8: the JWT is carried beside the JSON format; sub is the wallet a condition evaluated; a relying party that reads claims from the JWT verifies the JWT itself; a correspondence check between the two formats is given. * Statements made more precise: a fact profile is covered by a single signature; the XRPL ledger hash is included where available; the evaluation, rather than the attestation, is deterministic, and re-derivation is exact where the block Borthwick Expires 31 March 2027 [Page 29] Internet-Draft Wallet State Attestation September 2026 reference names the state read; the issuer selects the anchored block; the contents of a proof object are stated for proofs that are not storage-slot proofs; id is signed and usable for replay detection; iat is the JWT counterpart of attestedAt; format and proof are omitted rather than set to "json" or "none"; checking expiry is RECOMMENDED, consistent with Section 12. The Abstract states that verification needs no contact with the issuer beyond a copy of its published key set and documentation. Section 11.1 states that the default mode does not return the balance and may return public reference values the evaluation used. Section 11.3 names the one identifier the primitive handles, the wallet address, and how a boolean about a person is to be treated; Section 1.5 is aligned with it. Section 10.1 states that a wrapper signature confers no authority. * References: added [FIPS204], [RFC4648], [RFC7515], [RFC8615], [RFC9964] and [RFC9794]; [RFC8785] is normative; [RFC8615] takes the place of RFC 5785; one informative URL is updated. * Verifier behaviour that differs from a verifier built from -00: a missing or unknown kid is not accepted and no other key is substituted; a kid documented for a different type of message is not accepted; conditionHash is recomputed, and a mismatch causes rejection; a refuted companion causes rejection; a transmitted JWT that fails verification or does not correspond to the attestation beside it rejects the response; a verifier relying on the unsigned expiresAt checks it against the signed attestedAt. In each case the verifier accepts less. * Requirements stated more loosely than in -00: checking expiry is RECOMMENDED rather than required (Section 5, consistent with Section 12); verifier caching of the JWKS is a SHOULD rather than a MUST, and the -00 recommendation of a one-hour maximum cache lifetime is not carried forward (Section 7); an XRPL ledger hash is included where available rather than always (Section 2). The issuer selects the anchored block; the -00 option of a caller- specified block is not carried forward (Section 3). A verifier built from this revision also verifies attestations under the domain-separated scheme and accepts a JWKS that holds more than one key type, neither of which a verifier built from -00 does. Acknowledgments The author thanks the IETF community for ongoing discussion of attestation primitives in the agentic and wallet-state space. Author's Address Borthwick Expires 31 March 2027 [Page 30] Internet-Draft Wallet State Attestation September 2026 Douglas Borthwick InsumerAPI New Canaan, CT United States of America Email: douglas@insumermodel.com Borthwick Expires 31 March 2027 [Page 31]