Some checks failed
no-vanity-metrics / Scan committed Markdown for vanity metrics (pull_request) Successful in 3s
no-vanity-metrics / WAI public text names no comparison (pull_request) Successful in 4s
no-vanity-metrics / WAI public text names no company or product (pull_request) Successful in 3s
standards workspaces build + test / arl-rs (pull_request) Successful in 1m16s
standards workspaces build + test / eoc-rs (pull_request) Successful in 2m9s
standards workspaces build + test / jcp-rs (pull_request) Successful in 1m32s
standards workspaces build + test / joule-ui-rs (pull_request) Successful in 1m11s
standards workspaces build + test / joulehook-rs (pull_request) Successful in 1m13s
standards workspaces build + test / proof-rs (pull_request) Successful in 1m16s
standards workspaces build + test / sense-rs (pull_request) Successful in 1m13s
standards workspaces build + test / sandbox-rs (pull_request) Successful in 2m21s
standards workspaces build + test / smart-byte-rs (pull_request) Successful in 4m6s
WAI conformance / v2 vocabulary · manifests validate as stated (pull_request) Successful in 17s
WAI conformance / cargo-class corpora · linux (pull_request) Successful in 7m25s
WAI conformance / delivery telemetry · CMCD and CMSD against an independent library (pull_request) Successful in 8s
WAI conformance / cross-arch byte-equality · linux (pull_request) Successful in 25s
WAI conformance / C2PA manifest emission · signed, read back, validated (pull_request) Successful in 46s
WAI energy receipts / energy receipts · linux (pull_request) Successful in 1m53s
wai-pack / wai-pack · does this change touch it (pull_request) Successful in 4s
WAI section references / cited sections exist (pull_request) Successful in 10s
WAI mbt2018_mean integer decode (regenerated vectors) / regenerate mbt2018_mean integer vectors → Rust decode, required (pull_request) Successful in 4m30s
wai-web reach builds / wai-web reach · does this change touch it (pull_request) Successful in 4s
WAI conformance / independent verifiers · claims, JWP, key discovery and integer payloads (Python) (pull_request) Successful in 14m56s
workflow hygiene / every workflow supersedes its own queue (pull_request) Successful in 5s
wai-web wasm32 / wai-web wasm32 build · corpus, menu and writers (pull_request) Successful in 2m48s
wai-pack / wai-pack · linux (pull_request) Successful in 1m6s
wai-pack / wai-pack · the floor through a media prober (pull_request) Successful in 23s
wai-pack / wai-pack · independent verifier (Python) (pull_request) Successful in 2m4s
wai-pack / wai-pack · dependency licences (pull_request) Successful in 1m23s
wai-web reach builds / wai-web reach builds · the package of record, every output as recorded (pull_request) Successful in 2m44s
wai-web reach builds / wai-web reach builds · this tree's wai-web, every rung on its engine line (pull_request) Successful in 4m1s
standards workspaces build + test / jouleclaw-rs (pull_request) Successful in 4m36s
standards workspaces build + test / aac-rs (pull_request) Successful in 1m48s
standards workspaces build + test / joule-code-rs (pull_request) Successful in 47s
standards workspaces build + test / joulecontract-rs (pull_request) Successful in 30s
standards workspaces build + test / map-rs (pull_request) Successful in 29s
standards workspaces build + test / mesh-rs (pull_request) Successful in 28s
standards workspaces build + test / openpay (pull_request) Successful in 1m30s
WAI conformance / cargo-class corpora · linux-arm64 (pull_request) Successful in 5m46s
WAI conformance / cross-arch byte-equality · linux-arm64 (pull_request) Successful in 24s
WAI energy receipts / energy receipts · linux-arm64 (pull_request) Successful in 1m54s
wai-pack / wai-pack · linux-arm64 (pull_request) Successful in 1m6s
standards workspaces build + test / jouledesk-rs (pull_request) Successful in 2m52s
standards workspaces build + test / macOS energy backends (pull_request) Failing after 4m59s
WAI conformance / cargo-class corpora · macos (pull_request) Successful in 10m6s
WAI conformance / cross-arch byte-equality · macos (pull_request) Successful in 29s
WAI energy receipts / energy receipts · macos (pull_request) Successful in 3m14s
wai-pack / wai-pack · macos (pull_request) Successful in 2m12s
The reach receipt workloads verified a receipt copied from the site, written by wai_prov before its signer id became a label: it named a domain under did:web, which signer_ids_are_labels refuses (jwp-receipts §7.1, §7.8). wai_prov gains --carry <receipt.json>: it measures nothing, carries each step's figure and label from an earlier receipt for the same lineage, and signs them with its published test seed (0x70 x 32) under its label did:example:wai-prov. It refuses a receipt that does not verify or whose steps are not this run's (operations, input and output hashes, work), and writes no report. The vector is regenerated with it: the envelope is unchanged, the figures are the ones wai_prov first measured for these bytes, and carrying the receipt onto itself writes both files again byte for byte. The vector's README states how it is made and the command. Co-Authored-By: Claude Opus 5.5 <[email protected]>
105 lines
5.2 KiB
Markdown
105 lines
5.2 KiB
Markdown
# WAI Extension: Asset Provenance
|
|
|
|
> Status: Draft. Lever 4 — content-addressing + receipts + measured
|
|
> energy for content that cannot be reduced to instructions. WAI does not
|
|
> reconstruct the asset; it carries the opaque bytes and a signed,
|
|
> energy-accounted lineage. Conformance is **content-hash-equivalence**
|
|
> (recompute, compare) + signature validity. Reference impl: the
|
|
> `provenance` feature of `wai-rs`; tooling: `wai_prov`; live sink:
|
|
> wai.transaction.science/provenance.
|
|
Keywords **MUST**, **MUST NOT**, **SHOULD**, **MAY** are RFC 2119/8174.
|
|
|
|
## 1. Scope and model
|
|
|
|
A `wai.asset.provenance` object is **not a content capability** — it is a
|
|
JWP receipt profile *about* a carried asset, the way `jwp-receipts` is.
|
|
The asset itself declares an ordinary capability (`wai.image.jpeg`,
|
|
`wai.audio.flac`, …) and WAI carries it unchanged; the provenance receipt
|
|
adds three things the carried bytes do not have on their own:
|
|
|
|
1. **Tamper-evidence** — the asset is content-addressed
|
|
([`asset_content_hash`], BLAKE3 over the complete WAI envelope); a
|
|
verifier recomputes it and compares.
|
|
2. **Lineage** — an ordered chain of processing **steps**, each binding
|
|
its input and output content hashes, signed as one group.
|
|
3. **Energy accounting** — each step carries its measured/declared
|
|
microjoules; the receipt totals them.
|
|
|
|
This is the "verifies whatever it carries" half of the thesis, for the
|
|
content the reconstruct half cannot touch. WAI never decodes the asset —
|
|
a sink hands the bytes to whatever native element renders that media.
|
|
|
|
In scope: the step model, the `AssetReceipt` group, the verification
|
|
obligations. Out of scope: a transport; a capture device; the asset's own
|
|
codec (it is opaque here).
|
|
|
|
## 2. The step
|
|
|
|
A `ProvStep` is one transformation in the asset's lineage:
|
|
|
|
| field | meaning |
|
|
|---|---|
|
|
| `op` | operation, e.g. `"origin.synthesize"`, `"encode.jpeg"`, `"derive.thumbnail"` |
|
|
| `input_hash` | content hash of the input (all-zero for an originating step) |
|
|
| `output_hash` | content hash of the output |
|
|
| `work` | exact deterministic work (pixels, samples) |
|
|
| `joules_micro` | measured/carried microjoules; `0` is the unmetered marker, never 0 J ([energy-measurement](energy-measurement.md) §2) |
|
|
|
|
Step content hash:
|
|
`BLAKE3("wai:prov-step\x01" || op_len | op | input | output | work | joules)`.
|
|
|
|
## 3. The receipt (`AssetReceipt`)
|
|
|
|
A JWP group: the asset's content hash is the identity, the per-step
|
|
hashes are the Merkle leaves (JWP's exact `moq-jwp:merkle-{leaf,node}`
|
|
domains), and one Ed25519 signature covers a profile payload carrying the
|
|
asset hash, the declared `media` + `capability`, the Merkle root, the
|
|
step chain, and the total joules. It chains across edits via
|
|
`parent_receipt_hash`, like the worlds / audio / haptic / splat receipts.
|
|
|
|
## 4. Conformance
|
|
|
|
> A conforming verifier MUST: (a) recompute the asset's content hash and
|
|
> require it equal the receipt's `asset_hash`; (b) require the step chain
|
|
> be linked — each step's `input_hash` equals the previous step's
|
|
> `output_hash`, and the final `output_hash` equals `asset_hash`; (c)
|
|
> recompute the Merkle root from the step hashes; (d) verify the Ed25519
|
|
> signature as SPEC §7 *Signatures* requires. A failure at any point is a failure — the asset is reported
|
|
> unverified, never "probably fine".
|
|
|
|
There is no tolerance parameter: the content hash matches or it does not.
|
|
|
|
## 5. Energy is measured, never invented
|
|
|
|
`joules_micro` per step is **carried** from a meter, exactly as the other
|
|
receipts carry it: `wai_prov` measures the real CPU energy of each encode
|
|
(IOReport via macmon, no sudo) and signs the figure. An unmetered step
|
|
carries the unmetered marker `0`, which a reader presents as unmetered and never
|
|
totals as zero joules. The receipt never derives energy it did not measure.
|
|
|
|
Each step's figure carries its acquisition class as an optional label
|
|
([energy-measurement](energy-measurement.md) §2.8), because the steps of one
|
|
lineage can be metered by different parties in different ways. A labelled step
|
|
binds its class into its leaf hash; a step with no label keeps its legacy leaf
|
|
and its figure is unlabelled. `wai_prov` labels each encode it measures
|
|
`OnChipCounter`, with its declared uncertainty, and records an encode whose
|
|
measurement fails the §4 ratio or the power reader's liveness (§3.1) as
|
|
unmetered, and writes a measurement report for each step it measured
|
|
(energy-measurement §6). With `--carry` it measures nothing: it carries each
|
|
figure, and its label, from an earlier receipt for the same lineage, which must
|
|
verify and whose steps must have the same operations, hashes and work, and writes
|
|
no report. `total_joules_micro` carries no class of its own, and a
|
|
total over steps that include an unmetered one covers only the measured steps
|
|
(`Partial`).
|
|
|
|
## Appendix
|
|
|
|
The reconstruct classes prove WAI can ship a world, a sound, a body, a
|
|
volume as instructions and have every sink rebuild them identically.
|
|
Provenance proves the complement: for the photograph that is just a
|
|
photograph, WAI still adds something a bare file cannot — a tamper-evident
|
|
identity, a signed lineage, and an honest energy ledger — without ever
|
|
pretending to understand the pixels. Carries whatever it can reconstruct;
|
|
verifies whatever it carries.
|
|
|
|
[`asset_content_hash`]: ../wai-rs/src/world/mod.rs
|