open-standards/wai/extensions/capture-binding.md
Transaction Science 3ad589b1b8 wai: a recording manifest states where the package is kept, held to the room's region pin
live-rooms §3.7 said the recording extension checks a recording's storage against the pin;
WRM1 now carries region and the verifier refuses one outside it (store_outside_region).
live-events §8.6, live-rooms §3.7 and capture-binding §1 point at live-recording.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
2026-10-17 10:33:36 -04:00

40 KiB
Raw Permalink Blame History

WAI Extension: Capture Binding

Status: Draft. Registers the record wai.capture.take: the binding of a device's full-quality master recording to a live room, so that the master, uploaded after the session, proves it is one continuous take committed while it was being captured. While it records, the device publishes rolling commitments to its master, take_commit events (live-events §4.12) in the room's event track, where they are stamped with the room clock and held by the relay and by every other participant. After the session the device uploads the master, resumably and by content address, the store records the upload in signed receipts, and the device signs a take manifest listing the chunks, their root, every commitment and the consent of every principal the master records. A verifier checks the manifest against the room's events and gives each claim its verdict: single-take, aligned, complete and publishable for each purpose. The reference case is a lesson or an audition, where the live call is low quality and the master is made on the performer's own device. No new transport: the commitments are events, and the mapping onto C2PA live video output is field semantics (§11). The reference implementation is the capture_take module of wai-rs (feature capture_take); the corpus is live-conformance/takes/, and its second implementation is live-conformance/capture_take_verify.py. Keywords MUST, MUST NOT, SHOULD, MAY are RFC 2119/8174.

Texts read for this revision: RFC 6962 §2.1 and RFC 9162 §2.1.4 (the Merkle tree hash and its consistency proofs); ISO/IEC 23000-19 (CMAF) and ISO/IEC 14496-12; and the C2PA Technical Specification, version 2.4: §13.2.1, §18.15, §18.25, §18.26, §18.28 and §19. A section number of that specification in this text is that version's.

1. Scope

In scope: how a device and a take bind to the principal they capture for, the take id, and what a record_start and record_stop pair brackets (§3); the chunks of a master and the tree over them (§4); the take_commit payload and the chain of a take's commitments (§5); the upload, by content address, and the store's signed receipts (§6); the take manifest (§7); the consent record (§8); verification of a take and the verdict of each claim (§9); the mapping from a room-clock instant to a position in the master, and its bound (§10); and the mapping of a take and its CMAF output onto C2PA live video (§11).

Out of scope: a transport; the master's codec and container (a take commits to its bytes, whatever they encode); how a store is operated; the room's own recording (live-recording); per-object receipts of the relay that witness when a commitment was seen (a later extension); and what a party does with a verdict.

Relationship to the core spec: wai.capture.take is a record (SPEC §5): a signed record a WAI tool emits and verifies. It names no payload format and is not dispatchable.

2. Terms

  • Room, room clock, principal, event, chain, grant, grant in effect, room key, merged order: as in live-events §2 and live-rooms §2, §9.2.
  • Device: the Ed25519 key (RFC 8032) of the device that captures. It takes part in the room under a grant (live-rooms §4) as a principal: it signs its take_commit events and its take manifest.
  • Master: the encoded recording the device makes, at the quality it captures.
  • Device clock: the clock the device stamps its capture with, in microseconds. Its epoch is the device's.
  • Offset: the room clock less the device clock, in microseconds, as the device measures it: a device-clock instant d is the room-clock instant d + offset.
  • Chunk: a contiguous run of the master's bytes (§4.1).
  • Take: one continuous capture on one device, answering one record_start (§3).
  • Store: the service the master is uploaded to, named by its Ed25519 key (§6).
  • Subject: a principal the master depicts or records.
  • Purpose: a use a subject consents to: live (1), record (2), distribute (4), train (8), each a bit of a purposes byte.
  • I and J: the room's commit_interval_ms and jitter_ms (live-rooms §3.7), each times 1000, in microseconds.

Integers are little-endian. A digest is SHA-256 (FIPS 180-4), 32 bytes. An event's digest is live-events §3.2's.

3. The device, its principal and the take

3.1 Binding a device to a principal

A device captures for one principal, which its grant names: the device's grant in effect binds it to principal P when the grant's attributes (live-rooms §4.4) hold the key subject whose value is P's key as 64 lowercase hexadecimal digits, or, when they hold no subject, when P is the device's own key. The room authority signs the grant, so the binding is the authority's statement that this device captures for P: a device can be a key of its own (one per room, live-events §11) and still capture for a principal its participants know.

A principal is marked a minor in a take when the device's grant that binds it holds the attribute minor with the value true, or when its consent record says so (§8.1).

3.2 The take id

A take is named by its take id, derived and never chosen: SHA-256 over the 18 bytes wai:capture-take (ASCII) and 0x01, then the room id, the device's key, and the digest of the record_start event the take answers. One record_start addressed to one device names one take.

3.3 What a take brackets

A take answers a control event (live-events §4.9) whose command is record_start and whose target is the device, sent by a principal with the record power (live-rooms §3.3, §9.2 step 5). Its start is that event. Its capture instant is the room-clock instant t + count_in_ms × 1000 of the start: the count-in fixes when capture begins, for every participant alike.

Its stop is the first control event in the merged order after the start whose command is record_stop and whose target is the device; a take need not have one. A second record_start to the same device before the stop starts another take.

The device's first commitment of the take opens it, in answer to the start; its last closes it, after the stop (§5.3). A room whose recording policy has mode 0 is never recorded, and no take in it is permitted (§9.1). The interval I and the jitter J a take is held to are the room's (live-rooms §3.7), so no device chooses its own.

4. Chunks and the take tree

4.1 Chunks

The device cuts its encoded master into chunks, by bytes or by duration, in the order the master's bytes run. Where the master is CMAF (ISO/IEC 23000-19), chunk 0 is the CMAF header followed by the first CMAF segment, and each later chunk is one CMAF segment, so that the header, whose edit lists could reorder what a segment presents, is committed with the first chunk. A chunk is described by 64 bytes, its descriptor:

offset size field meaning
0 8 index u64: the chunk's position in the master, from 0
8 8 start u64: the device-clock instant its capture begins
16 8 end u64: the device-clock instant its capture ends (exclusive)
24 8 len u64: its length in bytes, at least 1
32 32 hash the digest of its bytes

A chunk holds the encoded samples captured from start to end. Its capture range is the device's statement; the commitments fix it while the capture runs (§5), and the verdicts hold the device to it (§9.4).

4.2 The take tree

The take tree is the tree of staged-measurement Appendix C: RFC 6962's Merkle tree hash over SHA-256, its node that appendix's, over leaves of the take's own domain:

leaf = SHA-256("wai:take-leaf\x01" ‖ descriptor)        64-byte descriptor, §4.1
node = SHA-256("wai:out-node\x01" ‖ left ‖ right)        staged-measurement Appendix C

The root over the descriptors of chunks 0 to n − 1, n ≥ 1, is RFC 6962 §2.1's MTH: one leaf is itself; otherwise node(MTH(D[0:k]), MTH(D[k:n])), with k the largest power of two below n. No leaf is duplicated, so a root and its size fix the list of descriptors. The root over no chunk is 32 zero bytes. A commitment is a size and its root; as there, a root alone is not one. The leaf binds each chunk's index, its capture range, its length and its hash, so a commitment fixes when each chunk was captured as well as what it holds.

4.3 Consistency

A commitment (n, root′) extends (m, root) when the first m chunks under root′ are the chunks under root. The proof of it is RFC 9162 §2.1.4.1's consistency proof, the PROOF(m, D[n]) of RFC 6962 §2.1.2, a list of nodes, checked as RFC 9162 §2.1.4.2 checks one, with the node of §4.2 in place of its HASH(0x01 ‖ …). RFC 9162 leaves two cases to the caller, and this extension decides them: every commitment extends (0, zero), with an empty proof; and (m, root′) extends (m, root), with an empty proof, exactly when the roots are equal. Otherwise 0 < m < n and the proof is not empty.

A witness that holds only the previous commitment checks that the next extends it: the relay and every participant can check, while the take runs, that the device never rewrites what it has committed. A proof does not fix either size, as an audit path does not (staged-measurement Appendix C): a commitment states its size, and a verifier that holds the chunks recomputes every root under the size stated (§9.4).

5. Commitments

5.1 The take_commit payload

Every I while it captures, the device emits a take_commit event (live-events §4.12) in the room, on its own events track. Its payload:

field size meaning
take 32 the take id (§3.2)
n 4 u32: the commitment's number in the take, from 0
phase 1 1 open, 2 running, 3 close
prev 32 the digest of the take's commitment n − 1; 32 zero bytes when n is 0
first 8 u64: the index of the first chunk this commitment adds
size 8 u64: the chunks committed so far; this commitment adds chunks first to size − 1
root 32 the root over chunks 0 to size − 1 (§4.2)
offset 8 i64, two's complement: the offset (§2) the device measures at the event
proof_len 1 the number of nodes in proof, at most 64
proof 32 × proof_len that (size, root) extends the previous commitment (first, its root) (§4.3)

The fixed part is 126 bytes, so a proof of up to 28 nodes fits live-events' default max_payload of 1024. The chunk range it names, first to size − 1, is what a witness that missed the previous commitment still learns.

5.2 Reading a payload

A reader reads the payload in the order of §5.1 and refuses it as commit_malformed: when it ends before a field or holds bytes after proof; when phase is not 1, 2 or 3; when size is below first; when proof_len is above 64; or when size is 0 and root is not 32 zero bytes. A room verifier (live-rooms §9) carries the payload opaque, as live-events §4.12 has it; a take verifier reads it (§9.2).

5.3 The chain of a take's commitments

A take's commitments are the take_commit events of the device whose take is the take id, in the order of the device's chain. They form their own chain:

  • The opening commitment is the first: n 0, phase open, prev zero, first and size 0, and no proof. The device emits it when the start reaches it, before its capture begins.
  • Each later commitment n has n one above the previous one's, prev the previous one's digest, first the previous one's size, and phase running or close. It adds the chunks the device has completed since the previous one, perhaps none, and proves that its commitment extends the previous one (§4.3).
  • The closing commitment, phase close, is the last: after the stop, it adds the chunks captured up to the stop, and no commitment of the take follows it.

The chain needs nothing a witness does not hold: n and prev make a commitment that was not delivered a gap in the take, as live-events §6.2 makes it one in the device's chain, and the proof makes a rewritten history a commitment that does not extend.

6. Upload

6.1 Parts

After the session the device uploads its master to a store, chunk by chunk, each chunk a part: its index and its bytes, addressed by the chunk's hash. The upload is resumable: a part that did not arrive is sent again, and a part sent twice is the same part. A verifier fetches the parts from the store by hash and is given them as a list of (index, bytes) in the order it received them.

6.2 The upload receipt

The store records the upload's state in signed upload receipts, WUR1, one at each change of state:

offset size field meaning
0 4 magic WUR1 (ASCII)
4 1 version 1 in this revision
5 32 store the store's Ed25519 key
37 32 take the take id
69 8 seq u64: the receipt's position in the upload's chain, from 0
77 32 prev the digest of receipt seq − 1; 32 zero bytes when seq is 0
109 8 at u64: the store's clock, in microseconds since 1970-01-01T00:00:00Z
117 1 state 1 open, 2 progress, 3 resume, 4 sealed
118 8 held u64: the chunks the store holds, from index 0 with none missing
126 32 root the root over those chunks (§4.2), zero when held is 0
158 2 region ISO 3166-1 alpha-2: where the store keeps the chunks
160 64 sig Ed25519 by store

The digest of a receipt is SHA-256 over its bytes before sig. The signature is Ed25519 by store over the 17 bytes wai:take-upload (ASCII) and 0x01, followed by the bytes the digest covers, verified strictly (SPEC §7 Signatures).

A reader reads exactly the bytes it is given, as live-events §3.3 reads a record with WUR1 for WEV1: truncated, malformed or unknown_version.

6.3 The state machine

The receipts of an upload are a chain, and its states move only this way:

  • receipt 0 is open, with held 0;
  • progress: held above the previous receipt's, as parts arrive;
  • resume: held equal to the previous receipt's: an upload interrupted and resumed, which continues from the chunk at held;
  • sealed: held equal to the previous receipt's; the store holds the master, and no receipt follows.

A verifier, given the receipts in a list, checks each in the list's order and refuses at the first that fails, naming it by its index: the record reads (§6.2); its state is 1 to 4, its region two capitals A–Z, and its root zero when held is 0, otherwise upload_receipt_invalid; its store and take are the manifest's (§7), upload_receipt_invalid; its signature verifies (bad_key, bad_signature); its seq is its index, its prev the previous receipt's digest, its at not below the previous one's, its region receipt 0's, and its state one the list above allows after the previous receipt, otherwise upload_receipt_invalid; its held is at most the manifest's chunk count and its root the root over the manifest's first held chunks, otherwise upload_receipt_mismatch; and, where the room's recording policy pins regions (live-rooms §3.7), its region is one of them, otherwise store_outside_region.

6.4 The store

A room whose descriptor names an origin (live-rooms §5) names its stores in that origin's key log: a store's key is an entry of the head whose may_sign holds the authority capture/store (jwp-receipts §7.5) and whose status is not revoked. A verifier refuses a take whose store the head does not so list as store_not_listed. In a room with no origin the store is the one the manifest names, and its receipts are its statement alone.

7. The take manifest

7.1 Layout

When the upload is complete, the device signs a take manifest, WTM1:

field size meaning
magic 4 WTM1 (ASCII)
version 1 1 in this revision
room 32 the room id
device 32 the device's key, which signs the manifest
principal 32 the principal the take is captured for (§3.1)
start 32 the digest of the take's start (§3.3)
take 32 the take id (§3.2)
store 32 the store's key (§6)
claims 1 the claims the manifest makes: bit 0 single-take, bit 1 aligned, bit 2 complete
purposes 1 the purposes it claims the master publishable for (§2)
chunks 4 + 64 × n a u32 count n, then each chunk's descriptor (§4.1), in index order
root 32 the root over the n chunks (§4.2)
commits 4 + 32 × m a u32 count m, then the digest of each of the take's commitments, in the order of n
depicted 1 + 64 × k a u8 count k, then each subject: its key (32) and the digest of its consent record (32; zero for none) (§8)
sig 64 Ed25519 by device

The digest of a manifest is SHA-256 over its bytes before sig; its signature is Ed25519 by device over the 21 bytes wai:capture-manifest (ASCII) and 0x01, followed by the bytes the digest covers, verified strictly (SPEC §7 Signatures).

7.2 Reading and rules

A reader reads exactly the bytes it is given, as live-events §3.3 reads a record with WTM1 for WEV1 (truncated, malformed, unknown_version), and refuses a manifest that breaks any of these rules as manifest_invalid:

  • claims sets no bit above bit 2, and purposes none above bit 3;
  • n is at least 1, each chunk's index is its position in the list, and each len is at least 1;
  • root is the root over the chunks;
  • m is at least 1, and no digest is listed twice;
  • k is 1 to 32, the subjects' keys in strictly ascending byte order, and principal is one of them;
  • take is the take id of room, device and start (§3.2).

It then refuses a manifest whose room is not the room's as wrong_room, and one whose signature does not verify as bad_key or bad_signature.

The manifest lists every subject the master depicts or records, the take's principal among them, and binds each to its consent. A claim bit or a purpose bit states what the device claims; a verifier gives every claim its verdict whether the manifest makes it or not (§9.4).

A subject's consent is a signed record, WCN1:

offset size field meaning
0 4 magic WCN1 (ASCII)
4 1 version 1 in this revision
5 32 subject the subject's key
37 1 minor 1 when the subject is a minor, otherwise 0
38 32 guardian the key of the subject's guardian; 32 zero bytes for none
70 1 purposes the purposes consented to (§2)
71 32 room the room it is for; 32 zero bytes for any room
103 8 nbf u64: seconds since 1970-01-01T00:00:00Z from which it holds
111 8 exp u64: the second before which it holds
119 16 nonce distinguishes two consents with the same fields
135 64 sig Ed25519 by the guardian when guardian is not zero, by the subject otherwise

The digest of a consent is SHA-256 over its bytes before sig. The signature is over the 20 bytes wai:capture-consent (ASCII) and 0x01, followed by the bytes the digest covers, verified strictly (SPEC §7 Signatures): a minor's consent is the guardian's act, any other the subject's own.

8.2 Reading

A verifier, given consent records in a list, checks each in its order and refuses at the first that fails, naming it by its index: the record reads, as live-events §3.3 reads one with WCN1 for WEV1; it holds these rules, otherwise consent_invalid: minor is 0 or 1, guardian is zero when minor is 0, guardian is not subject, purposes is not 0 and sets no bit above bit 3, and nbf is below exp; and its signature verifies (bad_key, bad_signature). A record marked a minor with no guardian reads: it is a record no minor's consent can rest on (§9.4).

8.3 Revocation

A consent is revoked through the room authority's key log, as a grant is (live-rooms §5): its digest is added to the head's revoked_modules, which is append-only, so a revocation stays. A subject or guardian that withdraws consent asks the authority to list it. In a room whose descriptor names no origin no consent can be revoked, and a room that records subjects SHOULD name one.

9. Verification

9.1 Inputs and steps

A take verifier is given the room (a descriptor, grants, the head of the authority's key log or none, and the chains, as live-rooms §9.1), the take manifest, the parts (§6.1), the upload receipts, the consent records, and an evaluation instant at, in seconds since 1970-01-01T00:00:00Z: the time its verdicts are about. It runs these steps and stops at the first refusal, which it reports with the reason and where:

  1. The room (live-rooms §9): a refusal is the take's, at room, with the room's own place. A gap is not a refusal: the steps go on over the records the room verifier holds, and §9.4 says what a gap fails.
  2. The manifest (§7.2): at manifest.
  3. The take in the room (§9.2): at manifest, or at the record it names.
  4. The store (§6.4): at store. The receipts (§6.3): at the receipt's index.
  5. The consents (§8.2): at the record's index.
  6. The verdicts (§9.4).

9.2 The take in the room

Over the records the room verifier accepted, in the merged order (live-rooms §9.2), with each one's grant:

  1. The recording policy's mode is not 0: otherwise recording_not_permitted.
  2. The manifest's start is the digest of an accepted record that is a control event whose command is record_start and whose target is the manifest's device: otherwise take_unknown.
  3. Every accepted take_commit event of the device has a payload §5.2 reads: otherwise commit_malformed, at that record. Those whose take is the take id are the take's held commitments, in the device's chain order.
  4. At each held commitment, the device's grant in effect binds it to the manifest's principal (§3.1): otherwise device_not_bound, at that record.
  5. The held commitments are the manifest's commits, in its order, with those not held left out; a listed digest that is not held is the digest of no accepted record, and the room verifier reports a gap in the device's chain. Otherwise manifest_mismatch.

A commitment listed and not held is so a commitment the relay did not deliver, and the device's chain shows the gap; a manifest cannot list one the room holds out of its place, leave one out, or list one no gap can account for.

9.3 Mapping and timing

The take's clock mapping is the offset o of its opening commitment: a device-clock instant d maps to the room-clock instant d + o, computed without overflow (the reference computes in 128-bit integers). A chunk's mapped end is its end mapped. For each commitment, its t is the room-clock instant of its event; the capture instant, the start and the stop are §3.3's. Every comparison in this section is between room-clock instants, in microseconds.

9.4 The verdicts

Each claim holds, or fails with the first reason below that applies to it.

single-take holds when the master is one continuous take, every chunk of it committed while it was captured, and every part uploaded is the chunk committed at its index:

  1. delivery_gap: a commitment the manifest lists is not held.
  2. commit_chain_broken: the held commitments are not a chain of §5.3: the first is not an opening one, a later one's n, prev or first does not follow its predecessor, a later one is an opening one, or a commitment follows a closing one.
  3. root_not_extending: a commitment does not extend its predecessor (§4.3): its proof does not verify, a proof is given where §4.3 gives none, or a commitment that adds no chunk changes the root.
  4. take_not_closed: the last held commitment is not a closing one, or the take has no stop.
  5. manifest_not_committed: the manifest's chunk count is not the closing commitment's size, or, for a held commitment whose size is above 0, the root over the manifest's first size chunks is not its root.
  6. clock_unstable: a commitment's offset differs from o by more than J.
  7. capture_discontinuous: a chunk's start is not below its end, or a chunk's start is not the previous chunk's end.
  8. chunk_too_long: a chunk's end − start is above I.
  9. commit_early: the opening commitment's t is below the start's; the closing one's is below the stop's; or a commitment's t + J is below the mapped end of a chunk it adds (it committed a chunk before the chunk was captured).
  10. commit_late: a commitment's t is above the mapped end of a chunk it adds plus I plus J.
  11. Over the parts, in the order given, the first that is not the chunk committed at its index: chunk_extra when its index is not below the chunk count; chunk_reordered when its bytes' digest and length are another committed chunk's; chunk_altered otherwise.

By rules 8 and 10, every byte of the master was committed within 2 × I + J of its capture on the take's clock mapping, and by rule 6 that mapping held to within J throughout.

A part missing from the upload does not fail single-take: what was uploaded is what was committed, and the commitments verify. It fails complete. A party promised an unedited single take needs single-take and complete together: single-take alone holds of an upload that left chunks out.

aligned holds when capture began at the instant the count-in fixed:

  1. delivery_gap: the first commitment the manifest lists is not held.
  2. commit_chain_broken: the first held commitment is not an opening one.
  3. manifest_not_committed: no held commitment adds a chunk, or the root over the manifest's first size chunks is not the root of the first held commitment that does.
  4. misaligned: chunk 0's start, mapped, differs from the capture instant by more than J.

complete holds when the upload covers every committed chunk and the store sealed it: with s and r the size and root of the last held commitment,

  1. manifest_not_committed: s is 0, s is above the manifest's chunk count, or the root over the manifest's first s chunks is not r.
  2. chunk_missing: an index below s has no part whose bytes' digest and length are that chunk's.
  3. upload_not_sealed: the last receipt is not sealed, or its held is not s.

publishable for purpose p holds when every subject the manifest lists consented to the recording and to p. For each subject, in the manifest's order, the first that fails:

  1. consent_missing: its consent digest is zero, or no consent record given has it, or that record's subject is not this subject, or its room is neither zero nor the room id.
  2. guardian_missing: the subject is marked a minor (§3.1: by the record's minor, or, for the take's principal, by the minor attribute of the device's grant in effect at its first held commitment) and the record's guardian is zero.
  3. consent_revoked: the head's revoked_modules lists the record's digest (§8.3).
  4. consent_expired: the record does not hold (nbf ≤ s < exp) at the start's instant, s = ⌊(t0 + t) / 10^6⌋ of the start, or at at.
  5. purpose_not_consented: its purposes lack record, or lack p.

9.5 Outcome

A take verification gives one outcome:

  • refuse: the reason and where (§9.1).
  • verdicts: the verdict of single-take, aligned, complete, and publishable for each of the four purposes, each holds or its reason; and whether the manifest stands: every claim it makes, and publishable for every purpose it names, holds.

10. Dual-tier binding

The live tracks of the room and the master share the room clock: every event of the room has its t on it (live-events §3.1), and the take's mapping places the master on it (§9.3). A room-clock instant t within the take maps to the master:

  • the device-clock instant is d = t − o;
  • the chunk is the one whose start ≤ d < end;
  • the position is d − that chunk's start into the chunk, and d − chunk 0's start into the master.

An instant before chunk 0's mapped start or at or after the last chunk's mapped end is outside the master. A marker set on the live call at room time t (live-events §4.8) so lands at its instant in the master. The bound: where single-take and aligned hold, the mapping strays from the device's own clock mapping at any commitment by at most J (rule 6), and the master's start from the capture instant by at most J. The marker's t is its author's statement of the room clock (live-events §11), and a marker set by watching the live call lags what it marks by that call's own delay; a marker anchored to a live object (live-events §3.1) names the object instead, and a sink that knows that object's capture instant on the room clock maps that instant.

11. C2PA live video

This section maps a take, and a CMAF output of a room, onto the C2PA Technical Specification's live video provenance (§19 there). It is field semantics, and this revision implements none of it beyond the stream id: wai-rs has no CBOR or COSE encoder, and the C2PA signer c2pa_emit uses writes whole-asset manifests and fragmented BMFF manifests (one manifest in the initialization segment, a Merkle tree over the fragments), with no live video segment assertion, no session keys assertion and no Verifiable Segment Info. The take's commitments are the WAI side's witness; the C2PA output is what a C2PA validator reads, and each is checked on its own.

11.1 What maps to what

  • The stream. A take is one live video session. Its streamId (§19.3.2) is the take id's first 16 bytes as an RFC 9562 UUID of version 8: byte 6's high four bits set to 1000, byte 8's high two bits to 10, written in the 8-4-4-4-12 lowercase form. The corpus states it for each take.
  • The segments. Where the master is CMAF, chunk i holds the segment whose movie fragment the device numbers i + 1 in its mfhd sequence_number (ISO/IEC 14496-12), and that is the segment's sequenceNumber in both methods. Chunk 0 holds the initialization segment too (§4.1), with the C2PA Manifest Box §19.2.3 requires.
  • The hashes. A chunk's hash covers every byte of the chunk, its C2PA boxes included; the segment's c2pa.hash.bmff.v3 excludes them by §19's exclusions. The two are different digests of different spans.

11.2 Per-segment manifests (§19.3)

Each segment carries a C2PA Manifest Box in a uuid box, whose manifest holds a c2pa.hash.bmff.v3 over the segment and the assertion c2pa.livevideo.segment with sequenceNumber as above, streamId the take's, continuityMethod c2pa.manifestId, and previousManifestId the manifest identifier of chunk i − 1's segment. The initialization segment's manifest carries c2pa.actions.v2 whose first action is c2pa.created with the IPTC digital source type digitalCapture (§18.15.2).

Each segment's manifest MAY also carry the assertion science.transaction.wai.take, a map of take (the take id), room (the room id), device (the device's key) and commit (the digest of the device's last take_commit before the segment was written, absent before the first), each a byte string, so that a C2PA validator finds the room events that witness the take.

11.3 Verifiable Segment Info (§19.4)

  • The session key (§18.25, c2pa.session-keys, in the initialization segment's manifest): the device's key, as an OKP COSE_Key of curve Ed25519, EdDSA being among §13.2.1's algorithms, with kid the key's 32 bytes; minSequenceNumber 1; createdAt the opening commitment's instant, t0 + t; validityPeriod from then to the exp of the device's grant; and signerBinding, a COSE_Sign1 by the session key over the claim signer's end-entity certificate, as §18.25 has it. The device's key is then bound to the room by its grant and to the C2PA signer by the binding.
  • Each segment carries an emsg box of version 0, scheme_id_uri urn:c2pa:verifiable-segment-info, value fseg, presentation_time_delta 0, timescale and event_duration covering the segment, id the sequenceNumber, and message_data a COSE_Sign1_Tagged by the session key whose payload holds sequenceNumber, bmffHash (the segment's, excluding its C2PA emsg boxes, with no merkle field) and manifestId (§19.4.1, §19.4.2).
  • A COSE Sig_structure begins with the context string Signature1, and every message WAI signs begins with a wai: domain, so no signature of one is a signature of the other.

11.4 A room's CMAF output

A CMAF rendition a packager makes of a room's live tracks maps the same way, as its own live video session: its own streamId, its own session key, its own claim signer. That is the packager's provenance of its output, not the device's of its take.

11.5 AI disclosure and sustainability

  • AI disclosure (§18.28, c2pa.ai-disclosure). A take's manifest has no field for a trained model, and its C2PA output carries no c2pa.ai-disclosure: its source type is a digital capture. A CMAF output that carries captions a model produced (live-events §4.10, origin 2 or 3) discloses them: modelIdentifier is sha256: followed by the caption's model digest in lowercase hexadecimal; contentProfile humanOversightLevel is fully_autonomous for origin 2 and human_validated for 3; modelType is required and an event does not carry it, so an emitter writes the assertion only where it knows the model's type (§18.28's Table 12).
  • Sustainability (§18.26, c2pa.environmental-sustainability). An emitter writes energy_kwh only from a measured figure with its class, under energy-binding's rules, and never carbon_kgco2e or water_litres derived from a figure and a factor. A take carries no energy figure in this revision, so its output carries no such assertion.

12. Reasons

The codes this extension adds, each with where it is raised:

reason raised at
recording_not_permitted §9.2 step 1
take_unknown §9.2 step 2
commit_malformed §5.2, §9.2 step 3
device_not_bound §3.1, §9.2 step 4
manifest_invalid §7.2
manifest_mismatch §9.2 step 5
store_not_listed §6.4
upload_receipt_invalid §6.3
upload_receipt_mismatch §6.3
store_outside_region §6.3
consent_invalid §8.2
commit_chain_broken §9.4 single-take 2, aligned 2
root_not_extending §4.3, §9.4 single-take 3
take_not_closed §9.4 single-take 4
manifest_not_committed §9.4 single-take 5, aligned 3, complete 1
clock_unstable §9.4 single-take 6
capture_discontinuous §9.4 single-take 7
chunk_too_long §9.4 single-take 8
commit_early §9.4 single-take 9
commit_late §9.4 single-take 10
chunk_extra §9.4 single-take 11
chunk_reordered §9.4 single-take 11
chunk_altered §9.4 single-take 11
misaligned §9.4 aligned 4
chunk_missing §9.4 complete 2
upload_not_sealed §9.4 complete 3
consent_missing §9.4 publishable 1
guardian_missing §9.4 publishable 2
consent_revoked §9.4 publishable 3
consent_expired §9.4 publishable 4
purpose_not_consented §9.4 publishable 5

The first eleven are refusals; the rest are verdicts. A take verifier also raises every code a room verifier raises (live-rooms §11 and the live-events codes it lists), at room; truncated, malformed, unknown_version, bad_key and bad_signature for a manifest, a receipt or a consent record that does not read or whose signature fails; wrong_room for a manifest of another room; and delivery_gap as a verdict.

13. Conformance

live-conformance/takes/ holds the corpus, in one file, vectors.json, written from fixed seeds by wai_capture_take_vectors gen. Each vector is a room, a manifest, parts, receipts, consent records and an evaluation instant, with the outcome §9.5 gives them; one with verdicts also states the take id, its commitment count and digests, its size and root, its stream id (§11.1), and the master position of every marker of the room within the take (§10).

  • Good takes: a lesson take (the director's remote record_start with a count-in, the performer's chunks and commitments, the director's markers, record_stop, the upload and the manifest), whose every claim holds but publishable for train, which the performer did not consent to; the same take with an upload interrupted and resumed; and a minor's take under a guardian's consent.
  • Negatives, each a control of one defect: a commitment not delivered, a spliced chunk, a reordered one, an extra one never committed, a missing one (complete fails, single-take holds), a late commitment, a root that does not extend its predecessor, a capture that ignored the count-in, a consent missing, expired or revoked, a minor without a guardian, a device not bound to the principal; and every other reason of §12, with a manifest of another room and one whose signature fails.

A conforming verifier gives every vector the outcome, the reason, the place, the verdicts and the data the corpus states. wai_capture_take_vectors verify and the test tests/capture_take.rs check that the file regenerates byte for byte, that wai-rs gives every vector its outcome, that every reason of §12 appears in the corpus, and that §12 lists exactly the reference's codes. live-conformance/capture_take_verify.py is the second implementation, written from this text: it shares no code with wai-rs, verifies signatures with WAI's strict rule written from RFC 8032 (claim-conformance/_ed25519.py), verifies the room with the live-rooms corpus's own second implementation (live_rooms_verify.py, which verifies each event with live_events_verify.py), and gives every vector the same outcome; it also mutates copies of the corpus and requires every copy to fail.

14. Security and privacy considerations

  • The commitments are events: signed by the device, chained, stamped with the room clock and held by every participant. A relay can drop one, which the take's chain and the device's chain both show, but cannot alter one. A device that edits its master after committing it cannot upload the edit as its take: the edited chunk is not the committed one, and a history it rewrites does not extend what it committed.
  • A commitment's t is its author's statement (live-events §11). A device that pre-dates its commitments is held by the room's other records: its events take their place in the merged order among everyone's, and the per-hop receipts of a later extension witness when each was seen. The take's timing rules bound everything to the room clock from the start's instant on, within I and J.
  • The capture range of a chunk is the device's statement. The rules bind it to the room clock at every commitment (rules 6 to 10 of single-take) and to the count-in (aligned), so a device can neither stretch a chunk over time it did not capture nor commit a chunk before its capture ends; it can still capture something other than the room, which no commitment proves.
  • Content addressing makes a part its own check: a part whose bytes do not hash to its chunk's hash is not that chunk, whoever stored it.
  • The store's receipts state the upload's state machine; they cannot make a part the committed chunk, and a store's statement of held is checked against the manifest's chunks. The region pin binds where the store keeps the master, as the room's policy requires (live-rooms §3.7).
  • A consent is the subject's act, or a guardian's for a minor, and revocable through the key log as a grant is. publishable reads the head the caller gives: a revocation the head does not yet list is not seen. A minor is marked by the room authority in the device's grant, and by the record itself, so a minor's consent signed by the minor alone does not stand.
  • A take links the device's key, the principal it captures for and every subject's consent. A manifest names subjects by key; who a key is stays with the room authority and the store that keep the master. The master is personal data of everyone it records: the region pin and the room's retention_days (live-rooms §3.7) apply to it, and a consent's purposes and exp bound what may be done with it.