jwp-receipts: typed claims, key discovery, and a second binding class #84

Merged
dcharlot merged 1 commit from wai/receipt-classes-and-key-discovery into main 2026-09-10 12:21:02 -04:00
Owner

Three holes in the receipt layer, all surfaced by the #80 survey and verified against this file.

1. The receipt answers one question (§2.4.3). group and object say what was delivered, by whom, at what energy cost. Three other bodies now issue per-object signed artifacts answering different questions over the same objects — a lawful-basis declaration bound to a media service (ABNT NBR 25608 §8.8), a transparency-log inclusion proof (RFC 9942 COSE Receipts), and a recovered-binding assertion (C2PA soft binding). Rather than grow a field set per question, kind: "claim" carries a class discriminator and a class-scoped body on the same chain.

The rules are about refusal: a verifier MUST reject a class it does not know rather than ignore it; the class MUST NOT be inferred from the body's shape; where a claim and a delivery receipt disagree the verifier MUST reject rather than choose; and a claim carries the authority of its signer and no more — class says what is asserted, never that it is true.

2. Every signature presumed the verifier already held the key (§7). signer_pubkey rides in the receipt, which makes a signature checkable but not trustworthy — a forger supplies a key as easily as a signature. For a party who was never on the delivery path that presumption fails, and every guarantee in §6 fails with it.

Adds a REQUIRED signer_locator (cert-uri / trust-record / did), borrowing the design ITU-T H.274's dsci SEI already uses rather than inventing a third shape. A verifier that cannot resolve it MUST report "signature-valid, identity-unconfirmed" — a materially weaker statement that MUST NOT be reported as verification. The locator MUST be inside the signed payload: one a relay can rewrite is one an attacker can rewrite.

3. A receipt did not survive normal distribution (§8). The hard binding is BLAKE3 over envelope bytes, destroyed by any transcode, remux or platform re-encode. Those are not attacks — they are what distribution does. With one binding class, a re-encode left no recovery path at all.

Adds an explicitly weaker second class (soft binding + resolution endpoint), with the ancestor rule at its centre: a recovered receipt attests the ancestor the object was derived from, not the object in hand. An implementation that cannot express that distinction MUST NOT implement soft binding — a recovery presented as a hard binding is worse than no recovery, because it launders a transformation nobody attested.

No new cryptography, no new transport.

🤖 Generated with Claude Code

Three holes in the receipt layer, all surfaced by the #80 survey and verified against this file. **1. The receipt answers one question (§2.4.3).** `group` and `object` say *what was delivered, by whom, at what energy cost*. Three other bodies now issue per-object signed artifacts answering different questions over the same objects — a lawful-basis declaration bound to a media service (ABNT NBR 25608 §8.8), a transparency-log inclusion proof (RFC 9942 COSE Receipts), and a recovered-binding assertion (C2PA soft binding). Rather than grow a field set per question, `kind: "claim"` carries a **class discriminator** and a class-scoped body on the same chain. The rules are about refusal: a verifier MUST reject a class it does not know rather than ignore it; the class MUST NOT be inferred from the body's shape; where a claim and a delivery receipt disagree the verifier MUST reject rather than choose; and **a claim carries the authority of its signer and no more** — `class` says what is asserted, never that it is true. **2. Every signature presumed the verifier already held the key (§7).** `signer_pubkey` rides in the receipt, which makes a signature checkable but not trustworthy — a forger supplies a key as easily as a signature. For a party who was never on the delivery path that presumption fails, and every guarantee in §6 fails with it. Adds a REQUIRED `signer_locator` (cert-uri / trust-record / did), borrowing the design ITU-T H.274's `dsci` SEI already uses rather than inventing a third shape. A verifier that cannot resolve it MUST report **"signature-valid, identity-unconfirmed"** — a materially weaker statement that MUST NOT be reported as verification. The locator MUST be inside the signed payload: one a relay can rewrite is one an attacker can rewrite. **3. A receipt did not survive normal distribution (§8).** The hard binding is BLAKE3 over envelope bytes, destroyed by any transcode, remux or platform re-encode. Those are not attacks — they are what distribution does. With one binding class, a re-encode left no recovery path at all. Adds an explicitly weaker second class (soft binding + resolution endpoint), with **the ancestor rule** at its centre: a recovered receipt attests *the ancestor the object was derived from*, not the object in hand. An implementation that cannot express that distinction MUST NOT implement soft binding — a recovery presented as a hard binding is worse than no recovery, because it launders a transformation nobody attested. No new cryptography, no new transport. 🤖 Generated with [Claude Code](https://claude.com/claude-code)
jwp-receipts: typed claims, key discovery, and a second binding class
Some checks failed
no-vanity-metrics / Scan committed Markdown for vanity metrics (pull_request) Successful in 3s
standards workspaces build + test / aac-rs (pull_request) Successful in 31s
standards workspaces build + test / eoc-rs (pull_request) Successful in 1m48s
standards workspaces build + test / joule-code-rs (pull_request) Successful in 36s
standards workspaces build + test / jcp-rs (pull_request) Successful in 1m13s
standards workspaces build + test / proof-rs (pull_request) Failing after 13s
standards workspaces build + test / jouleclaw-rs (pull_request) Successful in 2m8s
standards workspaces build + test / joulecontract-rs (pull_request) Successful in 36s
standards workspaces build + test / sandbox-rs (pull_request) Successful in 2m0s
standards workspaces build + test / map-rs (pull_request) Successful in 30s
standards workspaces build + test / mesh-rs (pull_request) Successful in 30s
standards workspaces build + test / openpay (pull_request) Successful in 1m10s
standards workspaces build + test / smart-byte-rs (pull_request) Successful in 2m31s
standards workspaces build + test / arl-rs (pull_request) Successful in 9m13s
standards workspaces build + test / joule-ui-rs (pull_request) Successful in 9m22s
standards workspaces build + test / jouledesk-rs (pull_request) Successful in 9m3s
standards workspaces build + test / joulehook-rs (pull_request) Successful in 9m34s
standards workspaces build + test / sense-rs (pull_request) Successful in 8m49s
46d7518fa7
Three holes, all in the receipt layer, all found by the landscape survey and
verified against this file.

1. THE RECEIPT ANSWERS ONE QUESTION (§2.4.3). `group` and `object` say what was
   delivered, by whom, at what energy cost. Three other bodies now issue
   per-object signed artifacts answering different questions over the same
   objects: a lawful-basis declaration bound to a media service (ABNT NBR 25608
   §8.8), a transparency-log inclusion proof (RFC 9942 COSE Receipts), and a
   recovered-binding assertion (C2PA soft binding). Rather than grow a field set
   per question, `kind: "claim"` carries a class discriminator and a class-scoped
   body on the same chain.

   The rules are about refusal, not carriage: a verifier MUST reject a class it
   does not know rather than ignore it; the class MUST NOT be inferred from the
   body's shape; where a claim and a delivery receipt disagree the verifier MUST
   reject rather than choose; and a claim carries the authority of its signer and
   no more — `class` says what is asserted, never that it is true.

2. EVERY SIGNATURE PRESUMED THE VERIFIER ALREADY HELD THE KEY (§7). `signer_pubkey`
   rides in the receipt, which makes the signature checkable but not trustworthy —
   a forger supplies a key as easily as a signature. For a party who was never on
   the delivery path that presumption fails, and every guarantee in §6 fails with
   it. Adds a REQUIRED `signer_locator` (cert-uri / trust-record / did), borrowing
   the design H.274's `dsci` SEI already uses rather than inventing a third shape.

   A verifier that cannot resolve it MUST report "signature-valid,
   identity-unconfirmed" — a materially weaker statement that MUST NOT be
   reported as verification. The locator MUST be inside the signed payload: one a
   relay can rewrite is one an attacker can rewrite.

3. A RECEIPT DID NOT SURVIVE NORMAL DISTRIBUTION (§8). The hard binding is BLAKE3
   over envelope bytes, destroyed by any transcode, remux or platform re-encode.
   Those are not attacks; they are what distribution does. With one binding class
   a re-encode left no recovery path: receipt intact, object no longer matching,
   nothing connecting them.

   Adds an explicitly weaker second class — a soft binding computed from the
   samples plus a resolution endpoint — with the ancestor rule as its centre: a
   recovered receipt attests THE ANCESTOR the object was derived from, not the
   object in hand, and an implementation that cannot express that distinction
   MUST NOT implement soft binding at all. A recovery presented as a hard binding
   is worse than no recovery, because it launders a transformation nobody
   attested.

No new cryptography and no new transport. §1 already anticipated a MoQT object
header as a carrier, which is the slot #80 §4.4 identifies.

Co-Authored-By: Claude Opus 5 <[email protected]>
dcharlot force-pushed wai/receipt-classes-and-key-discovery from 46d7518fa7
Some checks failed
no-vanity-metrics / Scan committed Markdown for vanity metrics (pull_request) Successful in 3s
standards workspaces build + test / aac-rs (pull_request) Successful in 31s
standards workspaces build + test / eoc-rs (pull_request) Successful in 1m48s
standards workspaces build + test / joule-code-rs (pull_request) Successful in 36s
standards workspaces build + test / jcp-rs (pull_request) Successful in 1m13s
standards workspaces build + test / proof-rs (pull_request) Failing after 13s
standards workspaces build + test / jouleclaw-rs (pull_request) Successful in 2m8s
standards workspaces build + test / joulecontract-rs (pull_request) Successful in 36s
standards workspaces build + test / sandbox-rs (pull_request) Successful in 2m0s
standards workspaces build + test / map-rs (pull_request) Successful in 30s
standards workspaces build + test / mesh-rs (pull_request) Successful in 30s
standards workspaces build + test / openpay (pull_request) Successful in 1m10s
standards workspaces build + test / smart-byte-rs (pull_request) Successful in 2m31s
standards workspaces build + test / arl-rs (pull_request) Successful in 9m13s
standards workspaces build + test / joule-ui-rs (pull_request) Successful in 9m22s
standards workspaces build + test / jouledesk-rs (pull_request) Successful in 9m3s
standards workspaces build + test / joulehook-rs (pull_request) Successful in 9m34s
standards workspaces build + test / sense-rs (pull_request) Successful in 8m49s
to 0058478ad0
Some checks failed
standards workspaces build + test / aac-rs (pull_request) Successful in 32s
standards workspaces build + test / joule-code-rs (pull_request) Successful in 36s
no-vanity-metrics / Scan committed Markdown for vanity metrics (pull_request) Successful in 3s
standards workspaces build + test / jouleclaw-rs (pull_request) Successful in 2m13s
standards workspaces build + test / joulecontract-rs (pull_request) Successful in 35s
standards workspaces build + test / map-rs (pull_request) Successful in 30s
standards workspaces build + test / eoc-rs (pull_request) Successful in 1m47s
standards workspaces build + test / mesh-rs (pull_request) Successful in 26s
standards workspaces build + test / jcp-rs (pull_request) Successful in 1m13s
standards workspaces build + test / openpay (pull_request) Successful in 1m16s
WAI conformance / cargo-class corpora · linux-arm64 (pull_request) Successful in 37s
WAI conformance / cross-arch byte-equality · linux-arm64 (pull_request) Successful in 16s
standards workspaces build + test / proof-rs (pull_request) Successful in 1m15s
standards workspaces build + test / sandbox-rs (pull_request) Successful in 2m0s
standards workspaces build + test / smart-byte-rs (pull_request) Successful in 2m32s
WAI conformance / cargo-class corpora · linux (pull_request) Successful in 31s
WAI conformance / cross-arch byte-equality · linux (pull_request) Successful in 14s
WAI conformance / C2PA manifest emission · signed, read back, validated (pull_request) Successful in 41s
standards workspaces build + test / arl-rs (pull_request) Successful in 9m6s
standards workspaces build + test / joule-ui-rs (pull_request) Successful in 9m56s
standards workspaces build + test / jouledesk-rs (pull_request) Successful in 10m28s
standards workspaces build + test / joulehook-rs (pull_request) Successful in 9m47s
standards workspaces build + test / sense-rs (pull_request) Successful in 10m9s
WAI conformance / cargo-class corpora · macos (pull_request) Successful in 2m56s
WAI conformance / cross-arch byte-equality · macos (pull_request) Successful in 34s
WAI conformance / cargo-class corpora · windows (pull_request) Has been cancelled
WAI conformance / cross-arch byte-equality · windows (pull_request) Has been cancelled
2026-09-10 10:26:05 -04:00
Compare
Sign in to join this conversation.
No reviewers
No labels
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set

Reference
Transaction-Science/open-standards!84
No description provided.