wai: every Ed25519 signature verified strictly, by one verifier (SPEC §7) #186

Merged
dcharlot merged 14 commits from wai/strict-ed25519 into main 2026-10-08 01:50:19 -04:00

2026-10-07

Transaction Science
Merge main (1cf132ec: audio provenance) into wai/strict-ed25519
Some checks failed
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 1m13s
standards workspaces build + test / eoc-rs (pull_request) Successful in 1m56s
standards workspaces build + test / jcp-rs (pull_request) Successful in 1m28s
standards workspaces build + test / joule-ui-rs (pull_request) Successful in 1m8s
standards workspaces build + test / joulehook-rs (pull_request) Successful in 1m10s
standards workspaces build + test / proof-rs (pull_request) Successful in 1m12s
standards workspaces build + test / sandbox-rs (pull_request) Successful in 2m15s
standards workspaces build + test / sense-rs (pull_request) Successful in 1m7s
standards workspaces build + test / smart-byte-rs (pull_request) Successful in 3m37s
wai cross-architecture byte-equality / linux-x86_64 (pull_request) Successful in 23s
WAI conformance / cargo-class corpora · linux (pull_request) Successful in 6m16s
WAI conformance / v2 vocabulary · manifests validate as stated (pull_request) Successful in 13s
WAI conformance / independent verifiers · claims, JWP, key discovery and integer payloads (Python) (pull_request) Successful in 12m3s
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 24s
WAI conformance / C2PA manifest emission · signed, read back, validated (pull_request) Successful in 46s
WAI energy receipts / energy receipts · linux (pull_request) Successful in 1m37s
WAI HTTP delivery / HTTP corpus · falsification and differential (pull_request) Successful in 1h14m19s
WAI HTTP delivery / cache rules · controls and labelled caches (pull_request) Successful in 1m2s
WAI JPEG-AI whole decode (pinned inputs, required) / fetch pinned JPEG-AI inputs → whole decode + pixel hash, required (pull_request) Successful in 1m1s
WAI neural sink gates / model-free refusals of the neural sink (pull_request) Successful in 1m6s
wai-pack / wai-pack · linux (pull_request) Failing after 12s
wai-pack / wai-pack · independent verifier (Python) (pull_request) Failing after 50s
wai-pack / wai-pack · the floor through a media prober (pull_request) Successful in 18s
wai-pack / wai-pack · dependency licences (pull_request) Failing after 1m9s
WAI section references / cited sections exist (pull_request) Successful in 11s
WAI mbt2018_mean integer decode (regenerated vectors) / regenerate mbt2018_mean integer vectors → Rust decode, required (pull_request) Successful in 4m6s
wai-web wasm32 / wai-web wasm32 build · corpus, menu and writers (pull_request) Successful in 1m59s
workflow hygiene / every workflow supersedes its own queue (pull_request) Successful in 4s
CHANGELOG: both v0.4.0 sections kept, the signature rule above the audio one.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
2026-10-07 21:30:21 -04:00
Transaction Science
Merge main (7ac6deca, nothing under wai/) into wai/strict-ed25519
Some checks failed
no-vanity-metrics / WAI public text names no comparison (pull_request) Has been cancelled
no-vanity-metrics / WAI public text names no company or product (pull_request) Has been cancelled
standards workspaces build + test / arl-rs (pull_request) Has been cancelled
standards workspaces build + test / eoc-rs (pull_request) Has been cancelled
standards workspaces build + test / jcp-rs (pull_request) Has been cancelled
standards workspaces build + test / joule-ui-rs (pull_request) Has been cancelled
standards workspaces build + test / joulehook-rs (pull_request) Has been cancelled
standards workspaces build + test / proof-rs (pull_request) Has been cancelled
standards workspaces build + test / sandbox-rs (pull_request) Has been cancelled
standards workspaces build + test / sense-rs (pull_request) Has been cancelled
standards workspaces build + test / smart-byte-rs (pull_request) Has been cancelled
WAI conformance / cargo-class corpora · linux (pull_request) Has been cancelled
WAI conformance / v2 vocabulary · manifests validate as stated (pull_request) Has been cancelled
WAI conformance / independent verifiers · claims, JWP, key discovery and integer payloads (Python) (pull_request) Has been cancelled
WAI conformance / delivery telemetry · CMCD and CMSD against an independent library (pull_request) Has been cancelled
WAI conformance / cross-arch byte-equality · linux (pull_request) Has been cancelled
WAI conformance / C2PA manifest emission · signed, read back, validated (pull_request) Has been cancelled
WAI energy receipts / energy receipts · linux (pull_request) Has been cancelled
WAI HTTP delivery / HTTP corpus · falsification and differential (pull_request) Has been cancelled
WAI HTTP delivery / cache rules · controls and labelled caches (pull_request) Has been cancelled
WAI JPEG-AI whole decode (pinned inputs, required) / fetch pinned JPEG-AI inputs → whole decode + pixel hash, required (pull_request) Has been cancelled
WAI neural sink gates / model-free refusals of the neural sink (pull_request) Has been cancelled
wai-pack / wai-pack · linux (pull_request) Has been cancelled
wai-pack / wai-pack · independent verifier (Python) (pull_request) Has been cancelled
wai-pack / wai-pack · the floor through a media prober (pull_request) Has been cancelled
wai-pack / wai-pack · dependency licences (pull_request) Has been cancelled
WAI section references / cited sections exist (pull_request) Has been cancelled
WAI mbt2018_mean integer decode (regenerated vectors) / regenerate mbt2018_mean integer vectors → Rust decode, required (pull_request) Has been cancelled
wai-web wasm32 / wai-web wasm32 build · corpus, menu and writers (pull_request) Has been cancelled
workflow hygiene / every workflow supersedes its own queue (pull_request) Has been cancelled
Co-Authored-By: Claude Opus 5.5 <[email protected]>
2026-10-07 15:35:12 -04:00
Transaction Science
wai-pack: the v1 receipts test reads the refused cases as refused
the_receipts_json_round_trips required every receipt of receipts/ to verify;
the three marked "signature": "refused" must not, and there are three.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
2026-10-07 15:12:59 -04:00
Transaction Science
jwp corpus: the weak-key cases go last, so the pre-branch prefix is unchanged
the_pre_branch_vectors_are_an_unchanged_prefix pins the first 83 vectors by
digest; the three new group cases sat inside them. They now follow the
recovery vectors, and every existing vector keeps its place and its bytes.
joule-moq's corpus test passes over the new ones.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
2026-10-07 15:01:30 -04:00
Transaction Science
SPEC §7 Signatures: the one Ed25519 rule, cited by the receipt extensions
Every Ed25519 signature WAI defines is verified strictly, in order: a canonical
key, a key not of small order, S < L, R not of small order, and the cofactorless
equation with R compared byte for byte. OER/2's chain signature keeps the rule
oer-receipts §5 settles. jwp-receipts §3.1 step 3, http-delivery's playlist
receipt and packaging's receipt cite it instead of restating it; the worlds,
avatars, feeds, spatial-audio, haptics, volumetric, score, film, provenance,
ternary and quantum receipt texts cite it where they name their signature.
CHANGELOG records the sweep.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
2026-10-07 14:39:04 -04:00
Transaction Science
2026-10-07 14:33:30 -04:00
Transaction Science
Leave wai-quantum on its own verifier; the rule goes back into wai-rs
wai-quantum belongs to another line of work that is shipping releases, and
moving it was not needed to put every signature check written in wai-rs on one
strict verifier. This undoes c37c3e9a and the quantum-ops part of 9b5854aa:
wai/wai-sig is gone, wai-rs/src/sig.rs is the rule again (under the `ed25519`
feature), and wai-quantum, its Cargo.toml and lock, every other workspace's
lock, the quantum-ops corpus and wai_quantum_ops_vectors are as main has them.
wai-quantum's lenient checks are reported to its owner instead.

The JWP, signer and packaging weak-key cases stay; they verify through
wai::sig. The two HTTP falsify patches are cut against wai-rs/src/sig.rs again,
and wai-http and wai-pack fire on claim-conformance/_ed25519.py, which their
Python verifiers read.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
2026-10-07 14:33:18 -04:00
Transaction Science
Corpora: weak-key cases in every receipt family's corpus
Each family whose corpus lacked them gets the three signatures a verifier that
checks only the equation accepts and WAI's rule refuses (wai_sig::forgeries):
the identity as the key with (R, S) = (B, 1), the identity spelled y = p + 1,
and R of small order under the base point. Every case is new; no existing
vector's expectation changes.

- jwp: group_signer_key_identity_forged, group_signer_key_identity_y_not_reduced
  (step 1, bad_signer_key), group_signature_r_small_order (step 2).
- signer: anchor_root_identity_forged, anchor_root_identity_y_not_reduced,
  anchor_root_signature_r_small_order (not anchored, key_log_signature_invalid).
- pack: mutations receipt-key-identity, receipt-key-identity-y-not-reduced,
  receipt-r-small-order (receipt-signature); receipts/ v1-key-identity,
  v1-key-identity-y-not-reduced, v1-r-small-order, marked "signature": "refused",
  which wai-pack and pack_verify.py now read.
- quantum-ops: cal_q3_ and job_bell_ key_identity, key_identity_y_not_reduced and
  r_small_order, "verifies": false, which wai_quantum_ops_vectors checks are
  refused and hash as pinned.

claim (signer_key_identity, signer_key_identity_y_not_reduced,
signature_r_small_order and others) and http (sig-key-identity, -long,
sig-r-small-order) had them already. OER/2 keeps its own rule.

PackageReceipt::signing_payload (v1) and the calibration and job receipts'
signing_payload are public, so a corpus generator can sign over them;
wai-quantum re-exports wai_sig beside ed25519_dalek.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
2026-10-07 10:16:21 -04:00
Transaction Science
wai-sig: the strict Ed25519 rule as its own crate, and wai-quantum on it
wai-quantum's receipts still checked signatures with VerifyingKey::from_bytes and
the lenient verify, and could not call wai::sig: wai depends on wai-quantum, not
the reverse. The rule moves out of wai-rs/src/sig.rs, unchanged, into the crate
wai/wai-sig, which both depend on; `wai::sig` re-exports it, so every call site
in wai-rs reads as before. wai-quantum's `_signing` feature brings it.

Its twelve verify paths now call wai_sig::verify_strict: the calibration, job,
mitigation, decode, compile and rearrange receipts, the QBOM and its labelled
form, the phasor, circuit, SPD and resource receipts, and every Labelled<R>.
Each module has a test that its receipts refuse the three forgeries a lenient
check accepts. assert_refuses_forgeries is public so both crates' tests use it.

Lockfiles: the path crate added to every workspace that builds wai or
wai-quantum (wai-rs, wai-quantum, wai-pack, wai-quantum-serve, wai-relay,
wai-spz-gen, wai-web). wai-pack's lock also moves wai-quantum 0.3.36 to 0.3.37,
which #176 left behind.

CI: wai-conformance runs wai-sig's tests on every leg; every workflow that
builds wai-rs or wai-quantum, and wai-http and wai-pack, which verify signatures
through it, fire on wai/wai-sig and on claim-conformance/_ed25519.py.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
2026-10-07 09:54:36 -04:00
Transaction Science
2026-10-07 09:22:45 -04:00
Transaction Science
Python verifiers: one strict Ed25519 rule, _ed25519.py
claim_verify.py made the key, order and range checks itself and left the equation
to `cryptography`; http_verify.py had its own RFC 8032 implementation; and
pack_verify.py called `cryptography` alone, which accepts a key of small order, a
second spelling of a key, and an R of small order. All three, and the JWP and
signer verifiers through claim_verify, now call claim-conformance/_ed25519.py,
written from RFC 8032 with the standard library (as http_verify's was): canonical
A of large order, S < L, R decoded and not of small order, and the cofactorless
equation with R compared byte for byte. It reports a bad key apart from a bad
signature, keeps http_verify's --mutate small-order-key and small-order-r, and
checks itself against RFC 8032's first two vectors and the three forgeries.

Every committed corpus verifies unchanged: no vector's expectation moves. The OER
reference keeps its own rule (oer-receipts §5).

Co-Authored-By: Claude Opus 5.5 <[email protected]>
2026-10-07 09:22:27 -04:00

2026-10-06

Transaction Science
sig::forgeries asserts only that a lenient check accepts each forgery
The strict refusal is the caller's to show, so a test of a signing site fails at
the site, not inside the constructor, when the rule lets one through. sig's own
test checks each forgery's refusal.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
2026-10-06 18:09:04 -04:00
Transaction Science
wai-rs: every Ed25519 check outside OER/2 goes through sig::verify_strict
Sixteen sites still decoded the key with VerifyingKey::from_bytes and checked
with the lenient verify, which accepts a key of small order (under the identity,
(R, S) = (B, 1) verifies over any message), a second spelling of a point (y = p + j
is reduced), and an R of small order. Each now calls crate::sig::verify_strict:
the video, SSAI, key-release, channel and package receipts (v1 and v2), the
provenance, ternary and the five media receipts, and the world's receipt, op
signature and container seal. A package names a bad key apart from a bad
signature under receipt-signature; an op's bad key is still BadActorKey.

claim_receipt's own copy of the rule (signer_key, verify_ed25519_strict) is
gone: claims, JWP groups and the key log call the same routine, and its key
test moved into sig.rs. sig builds under a new `ed25519` feature that is only
the dependency, which world and oer enable, so the helper exists exactly when
ed25519-dalek does and asks for nothing else.

sig::forgeries builds, for any signing payload, the three signatures a lenient
verifier accepts and the rule refuses; every moved site has a test that its
receipt refuses all three. oer.rs is untouched: OER/2's settled rule refuses
the same keys but not R of small order.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
2026-10-06 18:06:47 -04:00