| Filename | Latest commit message | Latest commit date |
|---|---|---|
|
|
||
| .. | ||
| .gitattributes | ||
| chain_differential.py | ||
| chain_gap_differential.py | ||
| jwp_verify.py | ||
| README.md | ||
| vectors.json | ||
jwp-conformance
Conformance for the labelled forms of the JWP delivery receipts
(§2.2–§2.4.2, §3, §3.3 and §5.7) and their binary form (§2.7, §5.12), for the WAI_RECEIPT property's readings
(moq-streaming-format §5), and for the receipt
chain per (signer_pubkey, track_alias) and an object checked by inclusion alone (§3
step 3, §4.4, §5.9 and §6.1): 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; a property
read as signed only where a signed statement restates it; one chain for each key and
track; and an object whose receipt is checked without its envelope reported as
inclusion-verified, never as delivered.
Provenance. Generated here by wai_jwp_vectors, from fixed seeds (below). No media.
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. |
chain_gap_differential.py |
Signs genuine chains of up to 90 groups and delivers them shuffled, withheld and released stale, walked back and forward, with rewritten legacy links and forks the key signs, and, on half of them, to a verifier that joins, holds a bound of groups, or both, with receipts lost outright or the chain joined mid-stream; requires the two verifiers to agree on every one. |
chain_differential.py |
Signs receipt chains the corpus does not hold — two keys, two tracks, both payloads, genuine links, replays with and without a rewritten link, forks, gaps, links across tracks and keys, bad signatures, group_id up, equal and down, group_end around the clock, guard and bound on and off — and requires wai_jwp_vectors verdicts and jwp_verify.py verdicts to agree on every one. |
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 |
chain |
group receipts in the order a verifier receives them, whether §6.1's group_id guard is on for labelled groups (it is always on for legacy ones), and §6.1's freshness bound (now, max_age_s, max_skew_s) or null; optionally recovery (§3 step 3): whether the verifier joins, and max_held, the count of groups it holds live for each chain's missing parents, or null for none; with a count, max_history, the count it holds as history for each chain, inside the gaps its anchors left, and max_total, the count it holds across every chain |
for each group in order, accept (§3 steps 1–3 against the chain of its key and track, whose head it then becomes, or the head offered again), accept again (a group the chain admitted before, the same bytes, which changes nothing), accept anchor (it anchors a joined or re-anchored chain), accept history (inside a gap an anchor left, linking forward from the group before it or back from the group after it), or a rejection at its §3 step; the verifier holds every group it accepted, so a fork is chain_break and a gap parent_not_held; a group whose signed group_id is below the chain's live edge (the highest of a group that verified and arrived fresh) is exempt from the freshness bound. With holding, a held group's outcome is what became of it: accepted when its parent arrived, or when it filled a gap, parent_not_recovered when a bound was passed, or parent_not_held if still held at the end |
inclusion |
a group receipt and an object receipt, with no envelope | accept with the evidence inclusion-verified (§3 steps 1, 2 and 5, step 4 not run; §4.4), or a rejection at a §3 step |
binary |
bytes (hexadecimal) and their form: receipts (a group's receipts, §2.7.3), group or object (one standing alone) |
read with each receipt's members in the JSON form and, for a group, its link hash over the bytes as received (§2.7.4's reading, §3 step 1's and step 4's reading of the members, and the bytes written again identical), or reject with malformed at its §3 step, or the reason §3 step 1 gives the members |
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. Chains (vector v6_per_track_chain
and its neighbours): one key's base track and layer track, three chained labelled groups
each, offered alone and interleaved; a track's second group without its first; a parent
on another track; a track's first group offered again after its second, which changes
nothing, a fork from a held group, a gap beside the head, and the head offered again; another key on the same track; the
group_id guard off, on, and compared within a track, and always on for a legacy group;
a legacy history replayed after one rewritten link, once and in a loop, and a labelled
replay; receipts chained per key across tracks; group_end at the clock, with an
offset, at the window's edge, stale, ahead of the clock, stale with no bound, a stale
group behind the live edge, which fills a gap, a gap of seventy groups, and a stale
group whose rewritten link earns it nothing; a previous group of another track or key;
and a group whose signature fails, which heads nothing. Recovery (§3 step 3): a parent
fetched after its children, which are held and released; a receipt lost with and without
holding, the chain re-anchoring past it and regaining the held groups and the lost one
as history; a re-anchor that may not move behind its head; a verifier that joins
mid-stream, at the chain's first group, and on a legacy chain, with history behind its
anchor where the anchor is labelled; a stale group that may not anchor; a gap fetched in
ascending order after a re-anchor, each group linking forward from the one before; a
joiner's fill in ascending order, held as history outside the live bound and released
back from the anchor, within its history bound and past it; a joiner's fetch from the
chain's first group, whose null parent is the chain's start, held as history and
released back from the anchor, and a second start and a fork once that gap is closed; and the total held across
two tracks, passed by one; a group offered again after the head moved on, and a
joiner's anchor delivered a second time, which change nothing. Objects checked without their envelopes: a dropped layer object and a labelled
one, which verify by inclusion, and a forged group, a rewritten content hash and a moved
position, which do not. The binary form (§2.7, §5.12): a live track's group of one object, the
mixed and labelled groups with every label tag and their proofs, a group with no
object, a legacy group and an object standing alone, each read and written again
byte for byte; and the bytes that do not read, each refused malformed at its step,
with one whose members §3 step 1 refuses.
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
python3 chain_differential.py ../wai-rs/target/debug/wai_jwp_vectors --n 3000 --seed 1
python3 chain_gap_differential.py ../wai-rs/target/debug/wai_jwp_vectors --n 400 --seed 1
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.