The meters sampled the processor power a non-privileged reader reports and
sealed it OnChipCounter, but they never read the channel it comes from: on
macOS 27 the processor channels of IOReport's Energy Model group read zero for
an unprivileged reader, and the reader takes its power from another report it
selects. The liveness rule (energy-measurement §3.1) passed on the reported
samples, which move, while no counter was ever put to it.
energy_burst::PowerSource says what a reader's samples are. A Counter's
differences can seal OnChipCounter under §3.1, §4 and §2.3; a Reported power
is refused as OnChipCounter whatever its brackets show (Bracket::on_chip_figure,
on_chip_refusal) and seals ModelBased under the same bracket rules
(Bracket::figure). wai_meter, wai_video_meter, wai_world_meter,
wai_quantum_meter, wai_prov and wai_stage_measure --energy macmon now seal
ModelBased, naming the reader as the method; rapl:<domain> stays a counter.
energy-measurement §3.1 (the test is run on the counter), §2.9 and §7 say so,
and the extensions that described the meters' figures as on-chip readings are
corrected. No committed record changes class: the provenance vector's figures
are unlabelled and keep their bytes.
Also: the relay's powercap tests module after its impl, and platform-decode's
test helper uses is_multiple_of.
Co-Authored-By: Claude Opus 5.5 <[email protected]>
(cherry picked from commit 507f4cd9e1)
107 lines
5.4 KiB
Markdown
107 lines
5.4 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` brackets the CPU energy of each encode against
|
|
an idle baseline, from the processor power a non-privileged reader reports (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 brackets
|
|
`ModelBased`, because its samples are a power another program reports, not a
|
|
counter it reads and shows live ([energy-measurement](energy-measurement.md)
|
|
§3.1), and records an encode whose bracket fails the §4 ratio or the reported
|
|
power'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
|