Two claim classes report on one energy figure without changing the receipt that seals it. `measurement` carries a bracket's values as integers with each bracket's liveness facts, the build and the power reader, and is accepted only against the receipt that carries its figure. `operating-point` records the requested, committed and delivered operating points and a prediction. The ratio, verdict and residual are derived by every reader, never stated. energy-measurement §6.2 gives the figure and the least declaration a report's integers support as exact integer formulas; wai-rs `energy_report` implements them with no floating-point arithmetic. §3.1 defines a live power reader: a rail must advance in two consecutive intervals, in at least five and in at least four of every five, over at least 300 ms. A frozen or held rail is refused rather than sealed under a hardware class. An unmetered `0` is never a figure of zero joules. A JWP object's figure, class and origin are bound into its Merkle leaf (`\x02`), and a labelled group payload signs the total's class, its coverage and the parent link. An object must sit at the position its inclusion proof walks, and group signatures follow the strict Ed25519 rule claims use. `jwp_delivery` and `energy_figure` implement this in wai-rs; joule-moq 0.2.0 builds and verifies both labelled forms. New corpus `jwp-conformance/` with `jwp_verify.py`, more claim vectors with the earlier ones pinned, and a CI job that runs claim_verify.py, differential.py and jwp_verify.py. Legacy receipts keep their bytes. External JWP implementations must adopt the `\x02` leaf and the labelled group payload before verifying objects or groups that use them. Co-Authored-By: Claude Opus 5.5 <[email protected]>
64 lines
4.2 KiB
Markdown
64 lines
4.2 KiB
Markdown
# jwp-conformance
|
||
|
||
Conformance for the labelled forms of the [JWP delivery receipts](../extensions/jwp-receipts.md)
|
||
(§2.2–§2.4.2, §3, §3.3 and §5.7) and for the `WAI_RECEIPT` property's readings
|
||
([moq-streaming-format](../extensions/moq-streaming-format.md) §5): an object's figure,
|
||
class and origin bound into its Merkle leaf; a group total's class signed under the
|
||
labelled group payload; the position an object's inclusion proof must walk; the group
|
||
total read from its objects; and a property read as signed only where a signed statement
|
||
restates it.
|
||
|
||
## Files
|
||
|
||
| file | what it is |
|
||
|---|---|
|
||
| `vectors.json` | The corpus, generated by `wai_jwp_vectors gen` in `wai-rs` (feature `receipt_claims`). `wai_jwp_vectors verify` requires a byte-identical regeneration and every declared outcome. |
|
||
| `jwp_verify.py` | A second verifier, written from the extension text, that shares no code with `wai-rs`. It takes BLAKE3, jwp-receipts §3.1 step 3's Ed25519 rule and the claim verifier from `../claim-conformance/claim_verify.py`, itself independent of `wai-rs`. |
|
||
|
||
## Procedures
|
||
|
||
Each vector names one procedure and declares one outcome.
|
||
|
||
| procedure | input | outcome |
|
||
|---|---|---|
|
||
| `leaf` | an object receipt | its leaf, in the form its label gives (§2.2) |
|
||
| `group` | a group receipt, and optionally the previous one held | `accept` with its link hash and signing payload (§2.3, §3 step 3), or a rejection at a §3 step |
|
||
| `object` | a group receipt, an object receipt and the envelope delivered | `accept` (§3 steps 1–5), or a rejection at a §3 step |
|
||
| `total` | a group receipt and the objects delivered with their envelopes | the total's reading — `unmetered`, `unlabelled`, `weakest` (a legacy group whose every non-zero part is labelled: a class name only), or `signed` (a labelled group's own class, `checked` against every object or `unchecked`) — or a rejection |
|
||
| `property` | a `WAI_RECEIPT` property, with the object, its group and its envelope, or with an `energy` claim | the property's reading — `unmetered`, `unsigned`, or `signed` with the class and the key that signed it (the group's for a leaf, the claim's for a claim) — or a rejection |
|
||
|
||
A rejection names its reason (§3.3), and its §3 step where it has one; the group total
|
||
and a property are not steps of §3.
|
||
|
||
## What the corpus holds
|
||
|
||
Leaves in both forms, the labelled one with tags 0, 2, 4 and 5. A group in the legacy
|
||
payload whose objects mix the forms, and a group in the labelled payload chained to it,
|
||
with their signing payloads, signatures and link hashes. Every way a label, a figure or
|
||
an origin can be restated, stripped or added, and which of them the legacy leaf leaves
|
||
unbound. Labels that break their rules in correctly built trees. Objects presented at
|
||
another object's position — including the duplicated last leaf of an odd level, and a
|
||
duplicate that would hide a weaker class from the total. Group labels that break their
|
||
rules, correctly signed; a `sign_version` other than 2; and group signatures the strict
|
||
Ed25519 rule refuses (`S` ≥ L, a key of small order, a key whose `y` is not reduced). Totals read from complete and incomplete holdings, a total that
|
||
does not match its parts, and labelled totals whose class, coverage, declared uncertainty
|
||
or window disagree with what their parts compose to. Properties that agree with, and
|
||
disagree with, a labelled leaf or an `energy` claim, including a claim signed by a key
|
||
other than the publisher's, which reads as signed by that key.
|
||
|
||
## Synthetic, and what it attests
|
||
|
||
Keys are Ed25519 from fixed 32-byte seeds — 0x11 the publisher, 0x22 the meter, 0x33 a
|
||
relay — and attest nothing. Envelopes, figures, origins and calibration references are invented, and
|
||
calibration references use a reserved example domain.
|
||
|
||
## Running
|
||
|
||
cargo run --no-default-features --features receipt_claims --bin wai_jwp_vectors -- verify ../jwp-conformance
|
||
python3 jwp_verify.py vectors.json
|
||
|
||
Both run in CI: the Rust verifier on every platform of the conformance matrix, the Python
|
||
one on the linux runner (`.github/workflows/wai-conformance.yml`). The Python verifier
|
||
needs the `cryptography` package. joule-code's `joule-moq` pins leaves, roots and
|
||
signatures from this corpus in its own tests, and its workflow re-runs when the corpus
|
||
changes.
|