WAI Packaging for the MOQT Streaming Format Transaction Science
TBD (owner confirms at submission)
Web and Internet Transport Media Over QUIC MoQ MSF packaging receipts learned codecs This document specifies how WAI envelopes are carried as a packaging of the MOQT Streaming Format (MSF) over Media over QUIC Transport (MOQT). A WAI envelope names the decoding capability its payload needs and a fallback, and can name, by SHA-256 digest, the parameter set a learned decoder must hold to decode it. This document defines the MSF packaging value "wai", in which every MOQT object is exactly one WAI envelope. It defines track-level catalog fields that declare a track's capabilities, the parameter sets its objects pin, by digest, and the reproducibility tier of each. It defines a staged form in which a base and its refinement layers travel on separate tracks. It defines a receipts track that carries an Ed25519-signed Merkle commitment to each MOQT group's objects, and an object property that carries an object's receipt commitment. It also registers the media type application/wai. About This Document The source of this document is kept with the WAI specification it draws on, in the directory wai/ietf of . The WAI extension texts it restates are cited as informative references in .
Introduction MOQT moves objects, in groups, on tracks, and orders them by priority; it does not say what an object means. MSF says what objects mean: its catalog names, for each track, a "packaging" that fixes how the track's objects are encapsulated, and a sibling document can add a packaging value together with the catalog fields it needs . WAI is a container and capability-dispatch format. A WAI envelope carries a manifest and a payload. The manifest names the capability a receiver needs to decode the payload, a fallback capability for a receiver that lacks it, and, for a capability that decodes against a parameter set (for example the weights of a learned decoder), a pin: the SHA-256 digest of that set. A receiver that cannot verify the pin does not decode the payload against another set. WAI defines no transport. This document defines how WAI envelopes are carried as MSF objects. Its aims are:
  • A receiver can decide before it subscribes whether it can decode a track: which capabilities the track's objects use, which parameter sets they pin, by digest, and which reproducibility tier each is offered at ().
  • A receiver can establish that each object it received is the one the publisher's key committed to, at that MOQT group and object, and can account for an object it did not receive ().
  • A relay needs no knowledge of WAI. Every rule here uses MOQT's own objects, groups, priorities, properties and delivery timeouts, and a relay treats every payload as opaque, as requires.
This document changes nothing in MOQT or MSF. It defines no transport and no codec.
Conventions and Definitions The key words "MUST", "MUST NOT", "REQUIRED", "SHALL", "SHALL NOT", "SHOULD", "SHOULD NOT", "RECOMMENDED", "NOT RECOMMENDED", "MAY", and "OPTIONAL" in this document are to be interpreted as described in BCP 14 when, and only when, they appear in all capitals, as shown here. Section numbers of and are those of the revisions referenced. Where a later revision of either moves or changes what is cited, that revision governs and the citation is what changes.
Envelope:
A WAI container in the form of , beginning with the four bytes "WAI1".
Capability:
A string naming how a payload is decoded, such as "wai.image.png" or "wai.neural.int_hyper". Capabilities are registered by , Section 5.
Parameter set:
Every byte, other than the payload, that a capability's decode reads and that its output depends on: networks, entropy tables, normative constants. A receiver holds it; an envelope never carries it.
Pin:
A manifest member that names a parameter set by the SHA-256 digest of its bytes ().
Tier:
A reproducibility guarantee of a decode ().
Publisher, receiver, relay:
The MOQT original publisher of a track; an endpoint that subscribes to a track and decodes its objects; and an MOQT relay.
Stage set:
A base and the refinement layers that improve it, delivered as staged delivery ().
Link hash:
The identity of a group receipt ().
In byte layouts, "||" is concatenation; u8, u32_be and u64_be are unsigned integers of 1, 4 and 8 bytes in network byte order; u32_le is a 4-byte unsigned integer in little-endian order; a string is u32_be(length) || its UTF-8 bytes; and a quoted domain string such as "moq-jwp:object\x01" is its ASCII bytes followed by the single byte that \x01 denotes. BLAKE3 is the 32-byte output of the BLAKE3 hash , and SHA-256 is that of . Digests written in JSON are 64 lowercase hexadecimal digits.
MSF Extension All of the specifications, requirements and terminology defined in apply to implementations of this extension unless explicitly noted otherwise in this document. Tracks of the packaging defined here can share a catalog, and a render group, with tracks of any other packaging.
The WAI Envelope
Layout
  • A reader MUST refuse bytes whose first four are not "WAI1" (0x57 0x41 0x49 0x31).
  • The manifest is a JSON object in UTF-8, serialized with no insignificant whitespace. No member name occurs twice in one object, at any depth. A member that must be an integer is written as one: digits, with a minus sign only before a non-zero value, and no fraction or exponent.
  • The payload's interpretation is fixed by the capability that decodes it () and, for a capability that decodes against a parameter set, by that set.
  • A reader MUST NOT refuse a manifest for its size while it is at most 2^27 bytes long, nests arrays and objects at most 127 deep (the manifest object counting as one), and holds at most 2^22 JSON values. It MAY refuse a larger one, from man_len alone for its length, before it reads it.
Section 7.1 also defines a multi-rendition container, "WAI2". This document carries "WAI1" envelopes only.
Manifest The members this document reads are:
wai:
The version, "1.0". A reader refuses an unknown major version and accepts an unknown minor one. A reader ignores a member it does not understand.
model_requirement.capability:
The capability that decodes the payload.
model_requirement.fallback:
A capability a receiver MAY decode the payload with if it lacks the first, or if the pin does not resolve for the first; or null, in which case the envelope is inert without the first.
conditioning.prior:
OPTIONAL. The pin () of the parameter set the payload was coded against. It applies to whichever of the capability and the fallback decodes the payload.
intent:
"replicate" states that every conforming receiver reconstructs the source as the capability's tier promises ().
refines:
Present exactly when the capability is refinement-only: what the payload refines ().
security:
OPTIONAL. Whether the payload is encrypted, as Section 6 defines. The capability and the pin always describe the plaintext.
Capability Dispatch A receiver dispatches an envelope as follows:
  1. If the major version in "wai" is unknown, refuse the envelope.
  2. Let cap be the capability. If the receiver can decode cap, cap is dispatchable, and either no pin applies to cap or the pin resolves for cap (), decode the payload with cap, against the verified parameter set, and stop. A pin that does not resolve makes cap unsupported for this envelope; keep its reason.
  3. Otherwise, if the fallback is not null and step 2's conditions hold for it, decode with the fallback and stop; keep a pin's reason if it does not resolve.
  4. Otherwise the envelope is inert at this receiver. Report the reason kept at step 2, else the one kept at step 3, else "missing_capability".
A capability is dispatchable unless Section 4 registers it as something a receiver does not decode on its own: a candidate, a companion-only, a refinement-only, a record or a derivation string. A string does not register is dispatchable by a receiver that has a decoder for it. A pin that does not resolve is never a reason to decode against another parameter set: a learned decode against the wrong parameters yields plausible output, not an error.
Parameter-Set Pins A pin is a JSON object: Pin Members
MemberPresenceMeaning
idREQUIRED, stringA name for people. A receiver MUST NOT select or accept a parameter set by it.
sha256REQUIRED, stringThe SHA-256 of the parameter set in its form, as 64 lowercase hexadecimal digits.
determinismREQUIRED, stringHow the decode is made reproducible, in words.
formOPTIONAL, stringThe form the digest is computed over (below).
tierOPTIONAL, stringThe tier the sender claims: "decode-equivalence", "entropy-consistency" or "none".
A member of a pin with another JSON type makes the manifest malformed. A null optional member is an absent one. With form absent, sha256 is the SHA-256 of the one file that holds the set; that is admissible only for a capability registers with a one-file set. With form "wai.prior.set", sha256 is the SHA-256 of the set's listing. The listing has one line per file: the file's SHA-256 as 64 lowercase hexadecimal digits, two spaces, the file's path below the set's root, and a line feed. A path is one or more segments joined by "/"; a segment begins with one of A-Z, a-z, 0-9, "_" and "-", continues with those and ".", and does not end with ".". Lines are in strictly ascending order of their paths as byte strings; no two paths are equal once A-Z are mapped to a-z, and no path followed by "/" begins another. The listing has at least one line and nothing else. registers further forms. A receiver that is to decode through a capability to which a pin applies MUST verify the pin first. The pin resolves when the receiver holds a parameter set whose digest, in the pin's form, equals sha256: for "wai.prior.set", a listing with that digest together with every file it names, each with the digest its line gives. Nothing else satisfies a pin: not a matching id, and not a set in another form whose unpacked parameters compare equal. A pin that does not resolve is refused with the first of these reasons that applies:
  1. "pin_malformed": sha256 is not 64 lowercase hexadecimal digits.
  2. "form_not_registered": form names no registered form.
  3. "form_unreadable": the receiver has no reader for the form.
  4. "form_required": form is absent and the capability is not registered with a one-file set.
  5. "prior_revoked" or "prior_not_authorised": the receiver holds a key log and refuses the set under it, as Section 3.1 specifies. A receiver that holds no key log skips this check.
  6. "prior_not_held": the receiver holds no set with that digest ("digest_superseded" where it holds the set that the pin's optional supersedes member names).
  7. "set_malformed": the listing breaks a rule above.
  8. "part_mismatch": a file the listing names is missing, unreadable, or has another digest.
A pinned decode MUST read its parameters only from the set it verified; a decode that needs a file the set lacks is refused ("set_incomplete") and is treated as a pin that did not resolve. A refused pin makes its capability unsupported for that envelope; it is not a reason to decode anyway.
Determinism Tiers A learned decode evaluated in floating point does not in general reproduce its output across devices. WAI names two reproducibility guarantees :
entropy-consistency:
The entropy decode reproduces byte for byte on every conforming receiver: the decoded symbols have a portable hash. The reconstruction to the final medium can differ between conforming receivers.
decode-equivalence:
The whole decode, to the final medium, reproduces byte for byte on every conforming receiver: the reconstructed samples have a portable hash. The capability's registration specifies the decode in integer or fixed-point arithmetic, entropy stage and synthesis alike.
"none" claims neither. The tiers are ordered none < entropy-consistency < decode-equivalence. A tier is a property of a capability as registered: gives each capability a registry class, and the class gives the tier. A pin's tier above its capability's does not conform ("tier_exceeds_class"), and a receiver MUST NOT rely on it. A receiver reads a tier token it does not recognize as "none". An envelope with intent "replicate" over a learned capability MUST be over a capability registered at decode-equivalence, with a pin that declares decode-equivalence; entropy-consistency MUST NOT back "replicate". A tier covers the medium a receiver emits: a receiver that alters the decoded medium (for example with a post-decode filter) MUST NOT claim the tier for the result. At the time of writing, registers "wai.neural.int_synth", "wai.neural.int_hyper", "wai.video.int_hyper", "wai.audio.int_codec", "wai.splat.int_codec" and "wai.neural.int_mlicpp" at decode-equivalence, and "wai.image.jpegai" at entropy-consistency. This list is informative; the registry governs.
Catalog
Packaging Values This specification extends the allowed packaging values defined in with two entries: Packaging Values
NameValueReference
WAIwaiThis document
WAI receiptswai-receipts
Every track whose objects are WAI envelopes MUST declare packaging "wai". On such a track:
  • every object MUST be exactly one whole envelope. An object that holds part of an envelope, or more than one, is not this packaging;
  • the object boundary MUST be the envelope boundary, so that the receipt's commitment to an object () and MOQT's object identity are the same unit;
  • a receiver that does not recognize the packaging value "wai" MUST NOT attempt to interpret the objects. MSF's rule that a parser ignores fields it does not understand covers unknown fields, not unknown packaging values.
Track Fields This specification adds the following track-level catalog fields for tracks with packaging "wai". They are custom fields under ; their "wai_" prefix keeps them from colliding with fields MSF defines. Track Fields
FieldNameRequiredJSON TypeDefinition
Capabilitieswai_capabilitiesYesArray of String
Determinismwai_determinismNoString
Pinned parameter setswai_priorsNoArray of Object
Receiptswai_receiptsYesBoolean
Receipt aliaswai_receipt_aliasCond.Number
Receipts trackwai_receipts_trackCond.String
Stagewai_stagedCond.Object
Capabilities wai_capabilities lists every capability that an object on the track names as its capability or as its fallback. The list MUST be exhaustive for the track: its purpose is to let a receiver decide before subscribing whether it can decode what it is about to receive. A receiver MUST NOT subscribe on the assumption that an undeclared capability will not appear. A receiver MUST treat an object whose envelope names, as the capability it is about to dispatch to, a capability the list does not hold as a protocol error, and MUST NOT fall back silently.
Determinism wai_determinism is the weakest tier () that any object on the track claims, not the strongest. Absent means no tier is claimed. A receiver reads a value it does not recognize as "none". The field helps a receiver choose a track; the tier a receiver claims for an object is the one its own decode earns.
Receipts Fields
wai_receipts:
Whether the track's objects are covered by receipts (). A receiver reads an absent value as false.
wai_receipt_alias:
An integer from 0 to 2^53-1, written as an integer: the track_alias that the track's receipts sign (). MOQT's own Track Alias is chosen per session, by each hop (), so past the first hop it is not the number the receipts sign. Two tracks of a catalog MUST NOT carry the same value.
wai_receipts_track:
The name, in this track's namespace, of the track of packaging "wai-receipts" that carries this track's receipts (). Two tracks of a catalog MUST NOT name the same receipts track.
A track of a stage set that declares wai_receipts true MUST carry wai_receipt_alias and wai_receipts_track (). On another track both are OPTIONAL; a receiver finds a track's receipts chain and receipts track by them. A clone () inherits every field of its parent but its name, so a clone of a track that declares receipts MUST override both.
Pinned Parameter Sets A track MAY state, in wai_priors, the pins its objects carry. A receiver can then tell before it subscribes whether it holds the parameter sets the track needs, and at which tier each is offered. ", "form": "wai.prior.set", "tier": "decode-equivalence" } ] ]]> Members of a wai_priors Entry
MemberPresenceMeaning
capabilityREQUIRED, stringA capability the track's wai_capabilities lists.
sha256REQUIRED, stringA pin's sha256: 64 lowercase hexadecimal digits.
formOPTIONAL, stringThe pin's form. Absent, or null, where the pin declares none.
tierOPTIONAL, stringThe tier the publisher offers the set at. Advisory.
An entry lists a pin for a capability when its capability is that capability, its sha256 is the pin's, and its form is the pin's (both absent, or the same string). A member of an entry that this document does not define is ignored.
Reading.
wai_priors, where present and not null, is an array of objects, each with the members above of their types, each capability one that the track's wai_capabilities lists, and no two with the same capability, sha256 and form. A receiver that reads anything else refuses the track ("catalog_priors_malformed") and does not subscribe to it. A tier this document does not define is read as "none".
Exhaustive.
Where a track carries wai_priors, the publisher MUST list in it every pin that its objects carry. An object breaks the catalog when:
  1. it carries a pin that no entry lists for its capability or for its fallback; or
  2. an entry names its capability, or its fallback (when not null), and the object carries no pin, or carries a pin that no entry lists for that capability.
A publisher whose objects' pin can decode through the fallback SHOULD list the set for the fallback as well.
Mismatch.
A receiver checks each object of such a track against the track's wai_priors before it dispatches the object. An object that breaks the catalog is refused ("catalog_prior_mismatch"), and the track is refused with it: the receiver dispatches no further object of the track, and MAY unsubscribe from it. The catalog never stands in for the envelope. A receiver verifies an object's pin () whether or not the catalog lists it; an entry never satisfies a pin, never supplies a pin the envelope lacks, and never changes which set a decode reads.
Tier.
A listed tier is advisory. A publisher MUST NOT list a tier above the one the capability's registry class gives. A receiver MUST NOT claim a tier on the strength of a listed tier: the tier it claims for an object is the one its own decode earns (). A listed tier that differs from the tier an object's pin states is not a mismatch.
Staged Tracks WAI's staged delivery sends a base first and refinement layers after it; a receiver presents the base, and applies each layer that arrives in time. Each layer is a WAI envelope whose capability is refinement-only and whose manifest names, in refines, what it refines. A stage set is carried as one track per layer: a base track, which carries the set's bases, and a layer track for each layer index k, which carries the layers of index k. A receiver chooses its stage by the tracks it subscribes to; a relay forwards tracks and never reads an envelope. Each track of a set MUST carry, in its catalog entry, a wai_staged object:
set:
A non-empty string, the same on every track of the set.
layer:
An integer from 0 to 255: 0 on a base track, k on a track that carries layer k.
lead_ms:
On a layer track of a live set, an integer from 0 to 2^53-1: the time before a unit's presentation by which the layer must arrive to be applied to it. null on a base track. A receiver ignores it when isLive is false.
A set's extent is the tracks present: layers 0 to the highest layer a track of the set states. More than one track MAY carry one layer, as renditions of it, each with a receipts chain of its own. A publisher puts on a track of layer k only envelopes whose refines.layer is k, and on a base track only envelopes with no refines; a receiver applies a layer by its own refines, whichever track it came on. A layer track's wai_capabilities lists refinement capabilities, so a receiver that does not implement staged delivery finds them unsupported and has no reason to subscribe. The tracks of a set MUST share one namespace, one isLive () and one renderGroup (), present on each and written as an integer. Every entry of a track's depends () MUST name a track of the catalog in the track's namespace; the depends of a track of layer k MUST name at least one track of the set at each layer below k and none at k or above, and a base track's MUST NOT name a track of the set. A layer track MUST NOT carry altGroup, temporalId or spatialId (, , ); an altGroup MAY group the base tracks of alternative sets. Every track of a set that declares wai_receipts true carries its own wai_receipt_alias and receipts track (). A receiver checks each set's entries in this order, stops at the first check that fails, and treats the layer tracks of a set that fails as absent (its base tracks remain tracks of packaging "wai"):
  1. wai_staged has its three members, of their types and ranges; packaging is "wai"; isLive is a boolean; the track's name is a string and its namespace absent or a string, and no other track has that namespace and name; renderGroup, if present, is an integer below 2^64; depends, if present, is an array of strings ("staged-malformed").
  2. The set has a track at each layer from 0 to its highest ("staged-set-incomplete").
  3. The depends rules above hold ("staged-depends").
  4. The tracks share one namespace, one isLive and one renderGroup, present on each, and no layer track carries altGroup, temporalId or spatialId ("staged-grouping").
  5. On a live set, lead_ms is an integer on every layer track and null on every base track ("staged-lead").
  6. Every wai_receipt_alias of the catalog is an integer from 0 to 2^53-1; each track of the set that declares receipts carries an alias and names a receipts track of packaging "wai-receipts" in its namespace; and no other track carries that alias or names that receipts track ("staged-receipts").
A track that declares no namespace inherits the catalog track's (). A checker that does not know the catalog track's namespace refuses a set that mixes declared and inherited namespaces ("staged-malformed"). Groups and objects. On a live track each group MUST carry exactly one object, which travels in a subgroup of its own (). A group of one object is complete when its object is, so its group receipt is signed before the object is sent. Group and object identifiers of different tracks need not align: refines names what a layer refines. Priority. The base track's publisher priority () MUST be strictly below every layer track's, and the priority of a track of layer k MUST be no greater than that of any track of a layer above k. This holds for each track's DEFAULT_PUBLISHER_PRIORITY () and for every subgroup that sets its own. A receipts track's priority is its media track's. A subscriber that wants the publisher's order SHOULD give its requests for a set's tracks one subscriber priority. Delivery timeouts. A publisher SHOULD set a live layer object's OBJECT_DELIVERY_TIMEOUT () to no more than its slack: the time from publication to the presentation of the last unit the object covers, less the layer's lead_ms, less the publisher's estimate of the path. An object whose slack is zero or less cannot arrive in time, and the publisher MAY withhold it. A publisher MUST NOT set on a base track a delivery timeout of either kind shorter than the time from a base's publication to the presentation of its last unit. A delivery timeout releases bandwidth hop by hop; it is not an end-to-end deadline, and whether a layer is late is decided by the receiver, as specifies. Capping. A receiver caps its stage by subscribing to the base tracks, to the tracks of layers 1 to n, and to their receipts tracks, and to no others. A relay MUST NOT read an envelope to cap layers.
Receipts
Overview A publisher that declares wai_receipts true commits to every object of a track, group by group. For each MOQT group it computes each object's content hash, builds a Merkle tree over them, and signs the root and the group's metadata with its Ed25519 key : the group receipt. Each object has an object receipt that carries its Merkle inclusion proof. Group receipts form a chain for each publisher key and receipt alias: each names the link hash of the one before. The receipts of group g travel as one object in group g of the track's receipts track (), so that a receiver can verify the tracks it subscribes to without the receipts of others, and can account for an object it did not receive. The rules here are those of for the binary form that this carriage uses. That document also defines a JSON form, signed claims and key discovery, which this document does not need.
Content Hash envelope is the object's payload: the whole envelope, from "WAI1" to the last payload byte, with nothing inserted or reframed.
Merkle Tree A group's objects are its leaves, in MOQT Object ID order, starting at 0. An object's leaf takes the first form below when its receipt carries no energy label, and the second when it does (): When a level has an odd number of nodes, its last node is duplicated to make a pair. The root is the single node at the top; the root of an empty group is 32 zero bytes. Since an object receipt's object_id is both its MOQT Object ID () and its leaf index (), a publisher that declares receipts numbers each group's objects from 0, without gaps. joules_micro is the energy, in microjoules, that producing the object took, and 0 is the unmetered marker, never a figure of zero joules. origin is a UTF-8 label of where the object was produced.
Energy Class Encoding An energy figure's acquisition class says how the figure was obtained . Where a receipt signs it, the class is one tag byte followed by its evidence: Acquisition Classes
TagClassFollowed by
0unmeterednothing
1HwShunt (legacy)nothing
2ModelBasednothing
3Estimatornothing
4OnChipCounteru32_be(relative_ppm) || u64_be(window_us) || u8(filtering: 0 unknown, 1 off, 2 on)
5CalibratedInstrumentu32_be(relative_ppm) || u64_be(window_us) || u32_be(len) || calibration reference, UTF-8
relative_ppm is the standard relative uncertainty of the figure in parts per million, and window_us the integration window in microseconds. A class in a receipt is valid only when: tag 0 stands beside a zero figure and every other tag beside a non-zero one; tag 1 does not appear (it is accepted only in receipts that predate the labels); and for tags 4 and 5, relative_ppm and window_us are both non-zero and figure x relative_ppm is at least 288676, the least uncertainty a whole number of microjoules can carry. The classes are ordered, strongest first: CalibratedInstrument, OnChipCounter, HwShunt, ModelBased, Estimator.
Group Signature The publisher signs, with pure Ed25519 , one of two signing payloads: group_start and group_end are timestamps of the form of . signer_id names the signer; a receiver reads nothing from it unless it can confirm it by a means outside this document. The labelled payload signs the link to the parent group; the legacy payload does not. A labelled group's class is the one its objects compose to:
  • if an object with a non-zero figure carries no label, the group MUST be signed in the legacy form;
  • if no object has a non-zero figure, the class is tag 0 and the coverage 0;
  • otherwise the class is the weakest of the objects' classes among those with a non-zero figure, and the coverage is 1 exactly when some object's figure is zero. For a hardware class (tag 4 or 5), relative_ppm is at least the ceiling of (sum of figure_i x relative_ppm_i) / (sum of figure_i), and window_us is the longest of the objects'. A tag-4 total's filtering state is the objects' common one, or 0. A tag-5 total needs one calibration reference shared by every object, or the group is signed in the legacy form.
Link Hash signing_payload is the payload of the form the group was signed in. A group's parent is the link hash of the previous group of its chain, or none for the first. A legacy group's link hash does not cover its parent link, which the legacy payload does not sign.
Binary Forms The first 19 bytes of group_bin, the signing domain, give its form. Every field's length is known when the bytes are read in order. Bit i of direction_bits is 1 when the node at level i is the right child. An object receipt inside receipts_bin takes the group's track_alias and group_id. A reader reads exactly the bytes it is given and refuses them as "malformed" at the first of these that holds: the magic is not "WJR1"; the signing domain is neither of ; the bytes end before a field, or bytes follow the last object; a string is not UTF-8; a class tag is not one of or its evidence does not read; a coverage byte, parent flag or filtering byte is out of range; a parent flag of 0 is followed by bytes that are not zero; or leaf_version is neither 1 nor 2. The form is canonical: a receipt has one binary form, and a writer reproduces the bytes it read.
The Receipts Track A receipts track has packaging "wai-receipts" and is named by its media track's wai_receipts_track. Each media track has a receipts track of its own.
  • Group g of a receipts track carries one object, the receipts_bin of group g of its media track: its group receipt and object receipts. The publisher publishes it no later than that group's first object.
  • A receipt is about one MOQT object. The group receipt in group g of a receipts track has group_id g; each object receipt in it has that group_id and, as object_id, the MOQT Object ID of its object; its publisher_key is the publisher's key and its track_alias the media track's wai_receipt_alias. A receiver refuses a receipt that breaks this ("moqt_mismatch") before it verifies its signature, and holds nothing of it.
  • A receipts track has no delivery timeout of either kind: the publisher sets none, and a subscriber sets none on its subscription (, ). Its publisher priority is its media track's.
  • Its objects are receipts, not envelopes; 's object rules do not apply to them.
A receiver learns the publisher's key by a means outside this document: configuration, the session in which it subscribed, or key discovery as Section 7 specifies.
Verification A receiver verifies each group receipt and each object receipt it uses in these steps, in order:
  1. Read. The receipts_bin reads (); otherwise "malformed". A labelled group's class reads and is valid with the group alone: tag 1 does not appear, tag 0 stands exactly beside a zero total with coverage 0, and a hardware class meets the floor of ; otherwise "group_label_invalid".
  2. Signature. The publisher key and the signature pass, in order: the key is the one encoding of its point that allows; the key's point is not of small order; S is less than L; R is not of small order; and the cofactorless equation holds: the point S*B - k*A, with k = SHA-512(R || A || M) mod L over the bytes of R and A as the signature and key give them, encodes to R byte for byte. A key that fails one of the first two checks is "bad_signer_key"; a signature that fails a later one is "signature_verify_failed". These checks fix what leaves to the verifier, so that every conforming receiver accepts the same signatures. The receiver then holds a verified root.
  3. Chain. Chains are kept per (publisher key, track_alias). With no group of the chain held, a group with no parent starts it. A group whose parent is the head's link hash extends it. A group already admitted, offered again with the same bytes, passes and changes nothing. A second group with no parent, or one whose parent is the link hash of a group of the chain other than its head, is "chain_break". A group whose parent the receiver does not hold is "parent_not_held": the receiver MAY hold it while it recovers the parent, by a FETCH () of the receipts track, and MUST NOT accept it until then. A legacy group whose group_id does not exceed its chain head's is "group_id_not_increasing".
  4. Content hash. For an object the receiver received, the content hash of its bytes () equals the object receipt's; otherwise "content_hash_mismatch".
  5. Inclusion. A labelled object receipt's class is valid (); otherwise "object_label_invalid". leaf_index is below leaf_count, the proof holds exactly ceil(log2(leaf_count)) siblings (none for one leaf), direction_bits equals leaf_index, and object_id equals leaf_index; otherwise "proof_position_mismatch". The object's leaf, in the form its leaf_version gives, walked up the proof, reaches the verified root; otherwise "inclusion_proof_failed".
  6. Accept. The object's bytes are bound to the publisher key at (track_alias, group_id, object_id). Where its leaf is labelled, its figure, class and origin are bound with them; otherwise they are the publisher's unsigned statements.
A rejection at steps 1 to 5 is a hard failure for the object. A receiver MUST NOT accept a partial verification, such as a valid proof against an unverified root. An object receipt checked by steps 1, 2, 3 and 5 for an object the receiver did not receive is "inclusion-verified": the publisher signed an object with that content hash at that position. A receiver MUST report it as such, and MUST NOT report it, or anything read from it, as delivered, or dispatch on it. A receiver that holds an accepted object receipt for every leaf of a group MUST check that their figures sum to the group's total ("group_total_mismatch"), and, for a labelled group, that the group's class, coverage and uncertainty are those its objects compose to (). Holding and joining. A receiver that holds groups for missing parents MUST state a finite bound on what it holds: per chain, and across all its chains, since any key makes a chain. Past the bound it refuses what it holds ("parent_not_recovered") and re-anchors the chain at the next validly signed group whose group_id exceeds the head's. A receiver that subscribes to a live track after its first group () anchors each chain at the first validly signed group it receives. An anchor establishes only that the key signed that group; a receiver MUST report a chain it anchored as anchored, with the anchor's group_id, and MUST NOT report the groups the anchor skipped as verified. Section 3 specifies how the groups of such a gap, fetched later, are admitted as history.
The WAI_RECEIPT Object Property An object on a track of packaging "wai" MAY carry its receipt commitment as an MOQT Object Property (), WAI_RECEIPT. Its value is: vi64 is the variable-length integer of . acquisition is the class name of ("ModelBased", "Estimator", "OnChipCounter", "CalibratedInstrument", or "HwShunt"), or empty; acquisition_evidence is, for tags 4 and 5, the evidence that follows the tag byte, and empty otherwise; group_receipt is the link hash of the group receipt covering the object. The publisher MUST place the property inside Immutable Properties (), which no relay may change or remove.
  • A receiver refuses a value that ends early, has bytes after group_receipt, or whose acquisition is not UTF-8 ("property_invalid").
  • A non-zero joules_micro MUST be accompanied by acquisition. A zero joules_micro is the unmetered marker: acquisition and acquisition_evidence MUST be empty, and a receiver MUST NOT present it as zero joules. acquisition_evidence MUST be non-empty for OnChipCounter and CalibratedInstrument and empty for every other class. A receiver MUST discard a property that breaks this item ("property_invalid").
  • No signature covers the property. A receiver MUST NOT report its class as signed unless the class, evidence and figure equal those in the object's labelled leaf, once the object receipt is accepted against the group receipt group_receipt names; where they differ, the receiver MUST discard the property ("property_disagrees").
  • A relay MUST forward the property unchanged.
  • The property rides on its object and is lost with it; the receipts track carries the receipts of an object that is not delivered. Absence of the property is not evidence that an object has no receipt.
Until a type is assigned (), a track of packaging "wai" carries the property as type 0x3A41, from the range sets aside for an application's own use. Another application can give that type another meaning, so a receiver reads it only on a track of packaging "wai".
Relays An MOQT relay forwards tracks of packaging "wai" and "wai-receipts" as it forwards any track, their payloads opaque (). It needs no knowledge of this document and verifies no receipt: the receiver verifies every receipt itself. A relay that does not forward an object, because a delivery timeout passed or at its discretion, still forwards the receipts track's objects, which are separate MOQT objects. A relay that verifies receipts before forwarding them is permitted, and Section 4 states what it must preserve.
The codecs Parameter The optional codecs parameter of application/wai () lists the capabilities a sequence of objects uses, in the form of . Its WAI elements follow this grammar : A cap is a capability string without its leading "wai.". In an alt, the first cap is a capability a receiver can select, and each "+cap" is one whose payload is applied with it. The element lists every capability that any object it describes may dispatch to or apply. An element that begins with "wai", in any case, MUST match the grammar. Section 4 gives the remaining rules.
Implementation Status (Note to the RFC Editor: please remove this section before publication, as describes.) One open-source implementation family exists, in the repository named in the note at the start of this document, under the Apache License 2.0:
  • "wai-rs", the WAI reference library: the envelope, dispatch and pin verification (), the tier rules, the catalog check of staged tracks and the reading and check of wai_priors (), and a receipts verifier ().
  • "joule-moq", an MOQT implementation of : the receipts track in its binary form, receipt chains per key and alias, the WAI_RECEIPT property at type 0x3A41 inside Immutable Properties, and a test relay that drops late objects and still forwards their receipts. A browser receiver built on it refuses an object whose capability its track does not declare.
  • Conformance corpora for the catalog checks, wai_priors, the receipts and the property. Each is checked by the library and by an independent verifier, written in Python from the specification text, that shares no code with the library.
Not implemented at the time of writing: no publisher in the implementation writes wai_priors, and the browser receiver does not read it (it dispatches no capability that decodes against a parameter set); no receiver reads wai_determinism; and no type is assigned for WAI_RECEIPT.
Security Considerations This document relies on MOQT for transport security: QUIC protects each hop. The receipts of add integrity from the publisher to the receiver across relays; they add no confidentiality.
Receipt Keys Each group receipt has one signer, the publisher key in it. Forging one requires the private key or a break of Ed25519. A valid signature shows that a key signed; it does not show whose key it is. A receiver MUST NOT present a receipt as the publisher's unless it holds the key as the publisher's by a means it trusts (configuration, the session, or key discovery as Section 7 specifies). Publishers MUST generate keys with a cryptographically secure random number generator and MUST NOT use one key for distinct publisher identities. The strict verification of step 2 refuses keys of small order, under which a signature can verify without any private key, and makes every conforming receiver accept the same signatures. A compromised key can sign any group; rotation and revocation are outside this document.
Replay A group receipt binds the publisher key, track_alias and group_id under its signature, and an object receipt is bound to its leaf position, so neither can be moved to another track, group or position without detection. The receipts-track rule of binds each receipt to the MOQT group and object it is carried for. Chains are kept per key and track. The labelled payload signs the link to the parent group; the legacy payload does not, so in a legacy chain anyone on the path can rewrite the link, and the rule that a legacy group's group_id exceeds its head's is the only order that chain signs. A relay can drop a legacy group and rewrite the next one's link to hide the gap; only the labelled payload rules that out. An anchor () proves nothing about the groups before it: a relay can withhold groups, or offer a joining receiver an old group that is validly signed. A receiver reports anchors and gaps, and MAY refuse a live group whose group_end is older than a freshness window it states; it applies such a window only to the live edge, never to history it fetches.
Relay Transparency A relay forwards payloads without reading them. It cannot alter an envelope without changing its content hash, nor alter a receipt without breaking its signature. It can drop, delay or withhold objects, whole groups of a receipts track, or whole tracks; the receipts of make an undelivered object accountable, as inclusion-verified, but they do not make delivery happen. The WAI_RECEIPT property is not signed. Immutable Properties forbid a relay to change it, but a receiver cannot detect a relay that breaks that rule from the property alone, which is why lets a receiver report its class only when it matches a signed leaf. A relay sees what MOQT exposes: track names, catalogs (unless they are encrypted), object sizes, timing and properties, including WAI_RECEIPT.
Catalog Integrity Receipts do not cover the catalog. Where the catalog is not protected end to end, an on-path party able to rewrite it can misdeclare a track's capabilities, tiers or pinned parameter sets. The envelope remains the authority: a receiver verifies every pin before it decodes (), and an object that breaks wai_priors refuses its track (), so a misdeclared catalog leads to refusal, not to a decode against the wrong parameters. A listed tier is advisory and confers nothing.
Parameter Sets A learned decoder run against parameters other than the ones a payload was coded against produces plausible but wrong output, with no error. The pin makes the parameter set part of what the receiver checks, by digest. A receiver that decodes from bytes other than the ones it verified (for example by reading a file again after checking it) loses that protection; a receiver SHOULD decode from the very bytes it verified.
Resource Consumption A receiver bounds what it parses and holds: the manifest limits of ; a bound on the receipts it holds for missing parents (); and the bounds of Section 2 on decoded payloads. A receiver SHOULD check a receipts_bin's object count, and a Merkle proof's sibling count, against the bytes that remain before it allocates anything for them.
Privacy Receipts carry the publisher key, a signer label, origin labels, timestamps and energy figures in cleartext, and a receipts track is visible to every relay that forwards it. They reveal when and where objects were produced, and what producing them cost. A publisher can send the unmetered marker in place of a figure and an empty origin. A deployment that needs these hidden from relays encrypts the receipts track's objects end to end, for example with ; the receipts then commit to the bytes carried.
IANA Considerations
MSF Packaging Values This document requests no IANA action for the packaging values "wai" and "wai-receipts". lists its allowed packaging values in its own text () and creates no registry for them, and this document extends that list (), as other MSF packaging documents do.
MOQ Properties This document requests that IANA register the following entry in the "MOQ Properties" registry established by , with a type from the range 0x80 to 0x37FF, whose registration policy is Specification Required: WAI_RECEIPT Property
TypeNameScopeSpecification
TBD (odd)WAI_RECEIPTObject of this document
The type is odd, since the value is a byte sequence (). Until a type is assigned, implementations use 0x3A41, from the range 0x3800 to 0x3FFF that reserves for application-specific use; no registration is possible in that range, and none is requested for it.
Media Type application/wai This document requests that IANA register the media type application/wai in the "Media Types" registry, in the standards tree, as provides for a registration made by an IETF document.
Type name:
application
Subtype name:
wai
Required parameters:
N/A
Optional parameters:
codecs, as of this document defines.
Encoding considerations:
binary
Security considerations:
See of this document. A WAI object names the decoder its payload needs and does not carry executable code.
Interoperability considerations:
An object is a "WAI1" envelope () or a "WAI2" envelope ( Section 7.1). A reader refuses an unknown major version.
Published specification:
This document, and .
Applications that use this media type:
Media publishers, relays, caches and players that carry WAI envelopes over MOQT or HTTP.
Fragment identifier considerations:
None defined by this document.
Additional information:
Deprecated alias names for this type: N/A Magic number(s): 57 41 49 31 ("WAI1") or 57 41 49 32 ("WAI2") at offset 0 File extension(s): .wai Macintosh file type code(s): N/A
Person and email address to contact for further information:
The author of this document.
Intended usage:
COMMON
Restrictions on usage:
N/A
Author:
See the Author's Address section of this document.
Change controller:
IETF
Capability Strings This document creates no registry for capability strings or tier names. registers them under its own registry policy.
References Normative References Media over QUIC Transport MOQT Streaming Format WAI v1.0: Web AI Media Transport and Execution Draft Standard, open-standards repository, wai/SPEC.md The BLAKE3 Hashing Framework Secure Hash Standard (SHS) National Institute of Standards and Technology Key words for use in RFCs to Indicate Requirement Levels Ambiguity of Uppercase vs Lowercase in RFC 2119 Key Words Edwards-Curve Digital Signature Algorithm (EdDSA) The JavaScript Object Notation (JSON) Data Interchange Format Date and Time on the Internet: Timestamps Augmented BNF for Syntax Specifications: ABNF The 'Codecs' and 'Profiles' Parameters for "Bucket" Media Types Media Type Specifications and Registration Procedures Informative References CMSF- a CMAF compliant implementation of MOQT Streaming Format End-to-End Secure Objects for Media over QUIC Transport Improving Awareness of Running Code: The Implementation Status Section WAI Extension: MoQ Streaming Format open-standards repository, wai/extensions/moq-streaming-format.md WAI Extension: JWP Receipt Chain open-standards repository, wai/extensions/jwp-receipts.md WAI Extension: Determinism Tiers for Neural Decode open-standards repository, wai/extensions/determinism-tiers.md WAI Extension: Prior Carriage open-standards repository, wai/extensions/prior-carriage.md WAI Extension: Staged Delivery open-standards repository, wai/extensions/staged-delivery.md WAI Extension: Energy Measurement open-standards repository, wai/extensions/energy-measurement.md WAI Extension: HTTP Delivery open-standards repository, wai/extensions/http-delivery.md
Catalog Example A live catalog with a stage set (a base track and one layer track, each with its receipts track) and an on-demand track of a learned image capability that states its pinned parameter set. The digest is a placeholder. An object on "pictures" is a WAI envelope whose capability is "wai.neural.int_hyper", whose fallback is "wai.image.png", and whose pin names the listed set. A receiver that holds that set decodes the learned payload; one that does not falls back to PNG. An object whose pin named another set would refuse the track.
Refusal Reasons Refusal Reasons
ReasonRaised by
missing_capability
pin_malformed, form_not_registered, form_unreadable, form_required, prior_revoked, prior_not_authorised, prior_not_held, digest_superseded, set_malformed, part_mismatch, set_incomplete
tier_exceeds_class
catalog_priors_malformed, catalog_prior_mismatch
staged-malformed, staged-set-incomplete, staged-depends, staged-grouping, staged-lead, staged-receipts
moqt_mismatch
malformed, group_label_invalid, bad_signer_key, signature_verify_failed, chain_break, parent_not_held, parent_not_recovered, group_id_not_increasing, content_hash_mismatch, object_label_invalid, proof_position_mismatch, inclusion_proof_failed, group_total_mismatch
property_invalid, property_disagrees
Correspondence with the WAI Texts This document restates, for carriage over MOQT, parts of the WAI specification and its extensions. Where this document and the cited text differ, the difference is a defect in one of them. Correspondence
This documentWAI text
, Sections 2 and 3
Section 4
Section 3.1;
Sections 2 and 3
, Sections 3 and 4
Section 4.2
Section 4.1
to Sections 2, 2.7 and 3; Sections 2.3 and 2.7
Section 5
, Sections 3 and 4