open-standards/wai/extensions/transparency.md
Transaction Science 72e3300752 wai: key discovery, signing authority and module revocation
jwp-receipts §7: a did:web signer_id names a web origin, which publishes
a key log at /.well-known/wai-keys: revisions signed by a root key that
pre-commits to its successor, listing the origin's keys, the authorities
each holds, and whether each is active, retired or revoked. A verifier
that has anchored the origin, pinned or fetched, confirms an accepted
receipt, claim or module grant against the log offline, and reports the
outcome beside the item's own verdict, never in it. Hardware-class
energy, lawful-basis and pre-emption authorities are confirmed only
under a pinned anchor. Revocation refuses every item under a revoked key.

§7.9 authorises decoder and reconstruct modules, and pinned parameter
sets, by SHA-256 digest through signed module grants from the sink's
module origins, revokes them by digest in the key log, and bounds how
long a revoked module keeps running by grant_max_s + status_max_age_s,
under ceilings of 86400 s and 3600 s. Every failure, offline included,
leaves the module not held and dispatch falls back.

wai-rs gains signer_id (ungated) and key_log (feature key_discovery),
the wai_signer_vectors and wai-keys binaries, and the signer-conformance
corpus with an independent Python verifier. The reference meters and
the world demo sign under labels. A section-reference guard checks that
every section SPEC.md or an extension cites in another of them exists.

This commit is the stream as merged onto link 14. The commits after it
reconcile it with the parameter-set pin and the energy reports.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
2026-10-01 07:12:20 -04:00

123 lines
6 KiB
Markdown

# WAI Extension: Transparency Emission
> Status: Draft. Adds an **external encoding** for WAI receipts so a party with
> no WAI tooling can check them, and a registration profile so a receipt's
> existence is independently witnessed. Strictly **additive**: the JWP receipt
> chain is unchanged, and nothing here replaces it.
> Keywords **MUST**, **MUST NOT**, **SHOULD**, **MAY** are RFC 2119/8174.
## 1. What is actually missing
Not verifiability. An Ed25519 signature over a group Merkle root is checkable by
anyone holding the publisher key, and [`jwp-receipts`](jwp-receipts.md) §3
specifies exactly how. Three properties are missing, and none of them is a
signature property:
- **Non-equivocation.** Nothing prevents a publisher showing one receipt chain to
one party and a different chain to another. Both verify.
- **Independent timestamping.** A receipt says when the publisher says it was
made.
- **Detectability of suppression.** A receipt that was never shown to anyone
leaves no trace of its absence.
These are log properties, not envelope properties, and they are why this
extension exists.
## 2. The move, and its shape
The family already owns both halves: a transparency log with consistency proofs
exists, and JCR-1 (deterministic CBOR + COSE_Sign1, RFC 9052) is already the
canonical receipt envelope across sibling standards. What nothing in the family
has is a **standardised external encoding** that an outside auditor's
off-the-shelf tooling can verify with no bespoke verifier.
So the sequence is: bring WAI's receipts onto JCR-1 as its siblings already are,
then emit in the standardised encodings on top.
- A WAI receipt **SHOULD** be expressible as a JCR-1 envelope. This is alignment
with the family, not a new format.
- An implementation **MAY** additionally emit an RFC 9942 (COSE Receipts)
encoding of a group receipt, and **MAY** use the RFC 9995 COSE Hash Envelope
form where the payload is carried by hash rather than by value.
- These emissions are **additional encodings of the same facts**. An implementation
**MUST NOT** let the JWP chain and an emitted encoding disagree, and where they
do, the JWP chain is authoritative and the emission is in error.
## 3. What is registered, and what is not
SCITT registers per-artifact Signed Statements over an HTTP API. WAI emits
per-object receipts at media-group cadence. These cadences do not match, and
forcing them together would put a registration round-trip in the per-object path.
- An implementation **MUST NOT** register per-object receipts individually.
- An implementation **SHOULD** register the **group** receipt, or periodic
checkpoints over the receipt chain, leaving the per-object receipt exactly
where it is.
- Registration **MUST NOT** be a precondition for a receipt being valid. An
unregistered receipt is a receipt whose existence is unwitnessed, not a receipt
that is wrong.
- A registration **MAY** be recorded on the receipt chain as a `log-inclusion`
claim ([`jwp-receipts`](jwp-receipts.md) §2.4.7): its subject is the registered
receipt's link hash, and its body carries the Transparency Service's receipt
verbatim with the profile it was registered against. Accepting that claim is
not verifying the inclusion (§6).
- An origin that publishes a key log ([`jwp-receipts`](jwp-receipts.md) §7)
**SHOULD** register each revision as it registers group receipts. A fork in
the log is then visible to every Relying Party that checks the log, not only
to one that happened to hold both branches. The registration witnesses a
revision; it does not anchor the origin (§6).
The checking party is the **Relying Party** in the terminology of the SCITT
architecture; this extension uses that term rather than coining another.
## 4. The hash-algorithm constraint
RFC 9995's `payload_hash_alg` takes an identifier from the COSE Algorithms
registry. **BLAKE3 — which `jwp-receipts` §2.1 uses throughout — does not appear
in that registry.**
This is a real constraint, not a detail to be waved through:
- An implementation **MUST NOT** emit a COSE Hash Envelope naming BLAKE3 by an
unregistered or invented identifier. An identifier a Relying Party cannot
resolve defeats the entire purpose of emitting in a standard encoding.
- Until a registration exists, an implementation **MUST** either omit the hash
envelope form, or carry a **second digest** under a registered algorithm
alongside the BLAKE3 commitment, stating plainly that the two cover the same
bytes.
- A dual-hash carry **MUST NOT** be presented as evidence that BLAKE3 is
registered.
Registering BLAKE3 in the COSE Algorithms registry is a separate action with its
own process, and this extension does not assume its outcome.
## 5. Stage discipline
The referenced work is at mixed maturity, and an implementation **MUST NOT**
present any of it as more settled than it is:
| document | status |
|---|---|
| SCITT architecture (RFC 9943) | Standards Track, published |
| COSE Receipts (RFC 9942) | Standards Track, published |
| COSE Hash Envelope (RFC 9995) | published |
| SCRAPI (registration/resolution API) | approved, in the RFC Editor queue |
| a concrete log profile | Working Group Last Call — **not ratified** |
An implementation **MUST NOT** describe the log profile as ratified, and
**SHOULD** state which profile it registered against, since a Relying Party
cannot check a proof without knowing the log's rules.
## 6. What this does not do
- It does **not** replace the JWP receipt chain, and it does **not** move the
per-object commitment anywhere.
- It does **not** make registration a trust anchor. A Transparency Service
witnesses that a receipt existed at a time; it does not attest that the receipt
is true, and an implementation **MUST NOT** report registration as
verification.
- It does **not** solve key discovery. [`jwp-receipts`](jwp-receipts.md) §7
does, for a signer that names its web origin and publishes its keys there. A
log entry naming a key the Relying Party cannot confirm under that section is
still unconfirmed, and registering a key-log revision witnesses it without
anchoring the origin.