live-conformance/watermark/vectors.json from wai_live_watermark_vectors, and live_watermark_verify.py, written from the extension's text, which agrees on every vector, fails every mutated copy and catches a verifier that leaves out any one of its checks. Co-Authored-By: Claude Opus 5.5 <[email protected]>
3.8 KiB
live-conformance/watermark — forensic watermark sessions
The corpus of extensions/forensic-watermark.md §12,
in one file, vectors.json: three rooms, ETSI TS 104 002 watermark tokens, lists of WWS1
session records with or without their tokens, WWQ1 recovered sequences matched against
records, and WWD1 disclosures, each with the outcome the extension gives it.
rooms: each room'sWRD1descriptor, itsWRG1grants, its key-log head (ornull) and itsWRE1confidentiality record (ornull), as hexadecimal;broadcast(an origin whose key log lists two edges withlive/watermark, a relay withlive/relayalone and a revoked edge; region pinDE,FR; retention 30 days),keyless(no origin; its clock is its edge) ande2ee(end-to-end encrypted). A vector names its room and may carry aroom_override, whose members replace the room's.tokens: each token's bytes, read by §4.2:readwith what it gives (§4.3:cwt_tag,alg,vendor,patlen,source, the clearpatternornull,iat,exp,nbf), orrefusewithtoken_malformedortoken_unsupported.sessions: a list of records, eachrecordwith itstokenornull, verified by §9.1:acceptwith each record's facts (itsdigest,edge,owner,media,kids, span,vendor,source,patlen, the number of positionsserved,segments,unmarked,region,expires, and itstoken's facts ornull), orrefusewith thereasonand the placeat:descriptor,key_log,grantand itsindex,confidentiality, orsessionand itsindex.matches: the records and asequence, by §9.2:matchedorunmatched(withno_matchorambiguous_match), and thematch: the sequence's digest, the positions itstated, eachcandidate(itsindex,digest, whether itagrees, and itsfirstdisagreement, apositionandunservedordiffers), and the matchedsessionornull; orrefuseatsequence(or at a record).disclosures: onerecordwith itstoken, asequenceand adisclosure, by §9.3:acceptwith itsfacts(itsdigest, thesession's, thesequence's, thegrant, theprincipal, the positionsstated, andtoken_given), orrefusewith thereasonandat.
A verifier that reaches another outcome, reason, place or fact does not conform.
Provenance. Generated here: wai_live_watermark_vectors gen writes vectors.json from
records authored in code, from fixed seeds. Every key is SHA-256 of a fixed label and an
index (principals lists them); every pattern, salt, KID and copy digest is SHA-256 of a label
and an index; every time is a constant (the rooms' t0 is 2026-10-18T00:00:00Z); every origin
is an .example name (RFC 2606); and Ed25519 signing is deterministic (RFC 8032), so the file
is the same bytes on every machine. The tokens are COSE_Mac0 under HMAC 256/256 keyed by
wmt_key, which no verifier checks (§4.4); an encrypted pattern is a COSE_Encrypt0 or
COSE_Encrypt of the right shape whose bytes no verifier opens. Nothing here was recorded from
a deployment.
Checks. wai_live_watermark_vectors verify and tests/live_watermark.rs (wai-rs, feature
live_watermark) regenerate the file byte for byte and give every vector its outcome; the
generator asserts that every reason of §11 appears. ../live_watermark_verify.py is the
second implementation, written from the extension's text: it shares no code with wai-rs, reads
rooms with ../live_rooms_verify.py, reads tokens with a CBOR reader of its own, mutates
copies of the corpus and requires each to fail, and drops each of its own checks in turn and
requires the corpus to catch the weakened verifier.
python3 -I live_watermark_verify.py watermark