wai.live.watermark: forensic watermark session records, matched and disclosed one at a time (L14) #358
Loading…
Reference in a new issue
No description provided.
Delete branch "wai/live-watermark"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
L14 of the live and interactive program:
wai.live.watermark, a WAI record of forensic A/B watermark sessions (ETSI TS 104 002), bound to room grants, Lane A only.What is in it
wai/extensions/forensic-watermark.md: the extension. It registers the recordwai.live.watermarkand has three records:WWS1, the session record. The edge that chose the variants signs it when the session ends. It holds: the room; the content (owner and media kind); the span; the KIDs of the content keys; the token by its SHA-256; the token'swmvndandwmpatlen; how the edge had the pattern (in the clear, decrypted, or derived); bitmaps of the positions it sequenced and the variant at each; counts of sequenced and unmarked segments; a salted binding to the session's grant and principal; the region where the record is kept; andexpires.WWQ1, the recovered sequence. The claimant signs it. It holds theknownandbitsbitmaps (positions left out are erasures), the span, the vendor, the copy's digest and the claimant's key.WWD1, the disclosure. The room authority signs it. It opens one session's binding, for one sequence.The spec also covers: how a WAI verifier reads the TS's token (§4); retention and privacy (§6); the matching rule (§7); verification (§9); where the documents disagree (§10); 20 reason codes (§11).
wai-rs: the modulelive_watermark(featurelive_watermark = ["live_room"], no new dependency). It has its own deterministic-CBOR reader (RFC 8949 §4.2.1) and reads the COSE_Mac0 and COSE_Sign1 structures of RFC 9052. It also adds:live_watermark::corpusand the binwai_live_watermark_vectors gen|verify;tests/live_watermark.rs, which checks that the corpus regenerates byte for byte, that every case gets its outcome, and that §11 equalsReason::ALL;The corpus
wai/live-conformance/watermark/vectors.json:WRE1record;Every reason of §11 appears at least once.
wai/live-conformance/live_watermark_verify.py: the second implementation, written from the spec text. It shares no code with wai-rs. It reads rooms withlive_rooms_verify.py, signatures withclaim-conformance/_ed25519.py, and tokens with its own CBOR reader.Wiring:
wai-conformance.yml, after the e2ee step, with apaths:entry for the extension;REGISTRY.md: the record and the magicsWWS1,WWQ1andWWD1;codecs/registry.rsand the regenerated export (registry/capabilities.json,vocab/v2.ttl);live/watermark;Design decisions and why
wai.live.watermarkand the file isforensic-watermark.md. The record belongs to the live family: it is bound to room grants, the room clock, the region pin and the room authority's key log. It is registered the waywai.live.moderationis.sub. In indirect mode it carries a vendorwmid, which can be an account identifier.exp, a token can be presented again to get segments marked with its pattern.SHA-256(token)and restates only what matching needs: vendor,patlen, source and the embedded bits. The token travels beside the record only to the parties that check it.patlenand source agree with the record, and for a clear pattern thatbitsequals pattern ANDserved; and that the session's span is inside the token's window.binding = SHA-256("wai:live-watermark-binding"‖0x01‖salt‖grant digest‖principal). The edge draws the salt per session and gives the opening (salt, grant digest, principal) to the room authority. The edge must not keep the opening once the authority holds it.grant_unknown,grant_wrong_principal,outside_grant_window).patlenare equal and the spans meet.matched(exactly one agrees),no_matchorambiguous_match, with each candidate's first disagreement (unservedordiffers) and the number of positions stated.served: position −1 and contingency (TS §5.7.5.1), sequencing disabled (§5.3), and positions at or beyondwmpatlen.WWD1for one session and one signed sequence, only beforeexpires.not_protected). That ties the session towai.video.keysrelease decisions without naming the licence or the viewer.e2ee_room, read in §9.1 step 2: magic, length, room and the authority's signature. The reason: the AEAD authenticates the full track name, group and object (confidentiality §4.1, §4.7), so an edge cannot serve a variant track's object as the viewer's track. One object per MOQT location means one track cannot carry per-subscriber objects. And the member's application holds the plaintext.live/watermark, notlive/relay, registered in jwp-receipts §7.5. With no origin, the signer must be a room key.region, which must be inside the room's pin when the pin is non-empty (region_not_pinned). This extension extends the live-rooms §3.7 pin to session records.expiresmust be at or after the session's end, and within the room'sretention_dayswhen that is non-zero (retention_exceeded).expiresis refused (disclosure_expired).token_reused. This is the framing defence.algvalues: HMAC 256/256 is read as COSE_Mac0 and ES256 as COSE_Sign1.wmpatlenare served unsequenced.token_malformed. A form they allow that this revision does not read (a floating-point date, an untagged or nested CWT, another algorithm, an unknown header label) istoken_unsupported.wmt_key.Checks run
Cargo was run on the build host through
~/kani-logs/remote/rb. The light checks were run locally. All of these are after mergingorigin/main(L7b #351 and others) into the branch.cargo test --locked --no-default-features --features live_watermark --lib live_watermark::cargo test --locked --no-default-features --features live_watermark --test live_watermarkwai_live_watermark_vectors verify ../live-conformance/watermarkcargo test --locked --no-default-features --lib codecs::registrycargo test --locked --no-default-features --test cli_registrycargo run --no-default-features --bin wai -- registry export(with--pull), then--checkcargo test --locked --no-default-features --features neural_int,video_int,audio_int,world_int,splat_int --test int_kernels_vectors every_decoded_output_states_a_sha256cargo clippy --locked --no-default-features --features live_watermark --all-targetslive_watermark*,codecs/registry.rsandtests/int_kernels_vectors.rs. Two found earlier were fixed. The crate's other notes predate this branch.python3 -I live-conformance/live_watermark_verify.py live-conformance/watermarkpython3 -I live_rooms_verify.py roomscheck-tests-in-ci.py,check-workflow-concurrency.sh,check-spec-refs.py,check-wai-section-refs.py,check-no-vanity-metrics.sh,test-public-text-checks.sh,check-comparative-prose.sh,check-orphan-sources.py--locked; no dependency was addedFalsifications
Each was run after committing. Each was applied to the build host's copy and restored after.
check_session:tests/live_watermark.rsexits 101. The generator assertssessions vector region_not_pinned, andevery_case_gets_its_stated_outcomefails.vectors.jsonchanged: exits 101 (differ ["vectors.json"], and the case's outcome fails).token_reusedrow dropped from §11:the_extension_lists_the_reasonsexits 101.verify_disclosure: exits 101.live_watermark_verify.pyexits 1. Every built-in mutation fails, and every dropped check is caught by a named vector.What is NOT done
WWS1records. joule-moq-relay does not sequence variants.WAI_NAME_DENYLIST; CI runs it. The text names no company; the TS is cited by identifier only.🤖 Generated with Claude Code