jwp-receipts: typed claims, key discovery, and a second binding class #84
1 changed files with 129 additions and 0 deletions
|
|
@ -27,6 +27,14 @@ In scope:
|
|||
parent-receipt linkage for cross-hop preservation.
|
||||
- Verifier behaviour, relay preservation requirements, and conformance
|
||||
test vectors.
|
||||
- A typed **claim** receipt (§2.4.3) so statements other than delivery —
|
||||
energy, task fidelity, lawful basis, log inclusion, recovered binding —
|
||||
ride the same chain without growing a field set per question.
|
||||
- **Key discovery** (§7): where a signer's key is authoritatively
|
||||
published, so a party who was never on the delivery path can do more
|
||||
than check that a signature is internally consistent.
|
||||
- **Binding recovery** (§8): a second, explicitly weaker binding class
|
||||
for objects whose bytes changed in normal distribution.
|
||||
|
||||
Out of scope:
|
||||
|
||||
|
|
@ -154,6 +162,60 @@ Required fields:
|
|||
| `origin` | string | Datacenter / origin label. |
|
||||
| `merkle_proof` | object | Inclusion proof: `{ "siblings": [32 B hex, …], "direction_bits": u64, "leaf_index": u64 }`. `direction_bits` bit `i` is `1` iff the current node at level `i` is the right child. |
|
||||
|
||||
#### 2.4.3. `kind: "claim"` (typed claim receipt)
|
||||
|
||||
`group` and `object` answer one question — *what was delivered, by whom,
|
||||
at what energy cost*. Three other bodies now issue per-object 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, §8). Each is a signed
|
||||
statement about an object that is not a delivery statement.
|
||||
|
||||
Rather than grow a field set per question, a `claim` receipt carries a
|
||||
**class discriminator** and a class-scoped body, and links into the same
|
||||
chain as `group` and `object`.
|
||||
|
||||
Required fields:
|
||||
|
||||
| field | type | meaning |
|
||||
|---|---|---|
|
||||
| `kind` | string | MUST equal `"claim"`. |
|
||||
| `class` | string | Registered class identifier; see the table below. |
|
||||
| `subject` | 32 B hex | `content_hash` (§2.1) of the object the claim is about. |
|
||||
| `body` | object | Class-scoped payload. Its shape is fixed by `class` and by nothing else. |
|
||||
| `signer_pubkey` | 32 B hex | Ed25519 verifying key per RFC 8032. |
|
||||
| `signer_id` | string | Bound identity string. |
|
||||
| `sig` | 64 B hex | Ed25519 signature over the canonical bytes of the receipt with `sig` removed, under domain `"moq-jwp:claim\x01"`. |
|
||||
| `parent_receipt_hash` | 32 B hex or `null` | As §2.4.1. |
|
||||
|
||||
Classes defined here:
|
||||
|
||||
| `class` | body asserts | signer is |
|
||||
|---|---|---|
|
||||
| `energy` | a measured energy figure with its acquisition class, per [energy-measurement](energy-measurement.md) | whoever performed the measurement |
|
||||
| `task-fidelity` | a claim tuple per [task-fidelity](task-fidelity.md) §2 | whoever ran the test |
|
||||
| `lawful-basis` | the basis on which the sink's observations may be processed | the service operator |
|
||||
| `log-inclusion` | inclusion of a prior receipt in an append-only log | the log operator |
|
||||
| `binding-recovery` | a binding recovered after the hard binding was destroyed (§8) | the resolver |
|
||||
|
||||
Rules:
|
||||
|
||||
- A verifier **MUST** reject a `claim` whose `class` it does not know.
|
||||
Ignoring an unknown claim is not the same as accepting the object
|
||||
without it, and silently discarding a class a publisher thought
|
||||
load-bearing is the failure this rule exists to prevent.
|
||||
- The `class` **MUST NOT** be inferred from the body's shape.
|
||||
- A `claim` **MUST NOT** restate a field that `group` or `object`
|
||||
already carries for the same subject. Where both exist and disagree,
|
||||
a verifier **MUST** reject rather than choose.
|
||||
- The signer of a `claim` **MAY** differ from the object's publisher —
|
||||
that is the point of the class. A verifier **MUST NOT** treat a
|
||||
claim signature as evidence about delivery, or a delivery signature
|
||||
as evidence about a claim.
|
||||
- A `claim` carries the authority of its signer and no more. `class`
|
||||
says what is being asserted; it never says the assertion is true.
|
||||
|
||||
### 2.5. Worked example
|
||||
|
||||
Manifest JSON (group receipt, formatted for readability — wire form
|
||||
|
|
@ -465,3 +527,70 @@ multi-signer container; the v1.0 wire format remains a strict subset.
|
|||
`joules_total` are unit-of-energy fields, not unit-of-account
|
||||
fields. Conversion to currency, carbon, or grid-mix CO₂ is
|
||||
performed by downstream aggregators and is not normative here.
|
||||
|
||||
## 7. Key discovery (REQUIRED for a standalone verifier)
|
||||
|
||||
Every signature in this extension is verified against `signer_pubkey`,
|
||||
carried in the receipt. That makes the receipt self-describing and the
|
||||
signature checkable — but it does not make it *trustworthy*: a forger
|
||||
supplies a key as easily as a signature. Until now WAI has presumed the
|
||||
verifier already holds the right key by some means outside the
|
||||
specification. For a party who was never on the delivery path, that
|
||||
presumption fails, and every guarantee in §6 fails with it.
|
||||
|
||||
A receipt **MUST** carry a `signer_locator` object naming where the
|
||||
signer's key is authoritatively published:
|
||||
|
||||
| field | type | meaning |
|
||||
|---|---|---|
|
||||
| `scheme` | string | `"cert-uri"`, `"trust-record"`, or `"did"`. |
|
||||
| `value` | string | The URI, trust-record identifier, or DID. |
|
||||
|
||||
This follows the design ITU-T H.274's `dsci` SEI uses for the same
|
||||
problem — a certificate URI or an ISO/IEC 21617-1 trust-record URI —
|
||||
rather than inventing a third shape.
|
||||
|
||||
- A verifier **MUST NOT** treat `signer_pubkey` as authoritative merely
|
||||
because a signature over it validates. It **MUST** resolve
|
||||
`signer_locator` and confirm the key, or report the receipt as
|
||||
**signature-valid, identity-unconfirmed**, which is a materially
|
||||
weaker statement and **MUST NOT** be reported as verification.
|
||||
- A verifier that cannot resolve the locator **MUST NOT** fail closed on
|
||||
that ground alone if it holds the key by prior arrangement; it
|
||||
**MUST** record which path it used.
|
||||
- `signer_locator` **MUST** be inside the signed payload. A locator a
|
||||
relay can rewrite is a locator an attacker can rewrite.
|
||||
|
||||
## 8. Binding recovery (the second binding class)
|
||||
|
||||
§2.1 binds a receipt to an object by BLAKE3 over the envelope bytes.
|
||||
That is a **hard binding**, and it is destroyed by any change to those
|
||||
bytes — a transcode, a remux, a platform re-encode. Those are not
|
||||
attacks; they are what normal distribution does.
|
||||
|
||||
WAI has exactly one binding class, so today a re-encode leaves no
|
||||
recovery path at all: the receipt is intact, the object no longer
|
||||
matches it, and nothing connects them.
|
||||
|
||||
A second class is therefore defined, and it is deliberately weaker:
|
||||
|
||||
- A publisher **MAY** additionally register a **soft binding** — a
|
||||
derived descriptor computed from the samples rather than the bytes,
|
||||
which survives re-encoding — together with a `resolution_endpoint`
|
||||
at which a receipt may be recovered from that descriptor.
|
||||
- The algorithm **MUST** be named from a public registry and **MUST
|
||||
NOT** be described only as a vendor name. C2PA's soft-binding
|
||||
algorithm registry is a usable list.
|
||||
- A receipt recovered by soft binding **MUST** be reported as a
|
||||
`claim` of class `binding-recovery`, never as a hard binding.
|
||||
- **The ancestor rule.** A recovered receipt attests **the ancestor**
|
||||
from which the object in hand was derived — not the object in hand.
|
||||
A verifier **MUST** state this when reporting a recovered binding.
|
||||
Any implementation that cannot express the 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.
|
||||
|
||||
Soft binding does not repair the hard binding, and this section does not
|
||||
claim it does. It supplies a path where there was none, at a stated and
|
||||
strictly lower grade.
|
||||
|
|
|
|||
Loading…
Reference in a new issue