Some checks failed
joule-code conformance gate / Build + round-trip C1-C4 vectors (pull_request) Successful in 3m1s
joule-moq-room room service / joule-moq-room · does this change touch it (pull_request) Successful in 4s
joule-moq-web browser client / joule-moq-web · does this change touch it (pull_request) Successful in 6s
wai-web reach builds / wai-web reach · does this change touch it (pull_request) Successful in 5s
joule-code conformance gate / joule-moq-ingest, every target (pull_request) Successful in 1m27s
standards workspaces build + test / which workspaces this change touches (pull_request) Successful in 6s
joule-code conformance gate / joule-moq-relay, every target (pull_request) Successful in 2m15s
wai cross-architecture byte-equality / does this change touch it (pull_request) Successful in 5s
WAI conformance / does this change touch it (pull_request) Successful in 5s
WAI energy receipts / does this change touch it (pull_request) Successful in 4s
WAI HTTP delivery / WAI HTTP · does this change touch it (pull_request) Successful in 4s
WAI HTTP delivery / HTTP corpus · falsify mutations 0/3 (pull_request) Has been skipped
WAI HTTP delivery / HTTP corpus · falsify mutations 1/3 (pull_request) Has been skipped
WAI HTTP delivery / HTTP corpus · falsify mutations 2/3 (pull_request) Has been skipped
WAI HTTP delivery / HTTP corpus · falsify patches 0/3 (pull_request) Has been skipped
WAI HTTP delivery / HTTP corpus · falsify patches 1/3 (pull_request) Has been skipped
WAI HTTP delivery / HTTP corpus · falsify patches 2/3 (pull_request) Has been skipped
wai-pack / wai-pack · does this change touch it (pull_request) Successful in 5s
wai-quantum studio and desktop / does this change touch it (pull_request) Successful in 4s
wai-web wasm32 / does this change touch it (pull_request) Successful in 5s
repository checks / lockfiles, tests in CI, workflow hygiene, spec and section references, public text (pull_request) Successful in 54s
wai-web reach builds / wai-web reach builds · the package of record, every output as recorded (pull_request) Successful in 2m51s
wai cross-architecture byte-equality / linux-x86_64 (pull_request) Successful in 31s
wai-web reach builds / wai-web reach builds · this tree's wai-web, every rung on its engine line (pull_request) Successful in 4m29s
WAI conformance / quantum core and corpus under wasm32-wasip2 (wasmtime) (pull_request) Successful in 2m28s
WAI conformance / cross-arch byte-equality · linux (pull_request) Successful in 32s
WAI energy receipts / energy receipts · linux (pull_request) Successful in 10m0s
wai-pack / wai-pack · linux (pull_request) Successful in 1m31s
wai-quantum studio and desktop / studio · browser (pull_request) Successful in 2m36s
WAI conformance / cargo-class corpora · linux (pull_request) Successful in 19m4s
wai-web wasm32 / wai-web wasm32 build · corpus, menu and writers (pull_request) Successful in 4m3s
joule-moq-room room service / joule-moq-room, every target (pull_request) Successful in 1m58s
wai cross-architecture byte-equality / linux-aarch64 (pull_request) Successful in 40s
joule-moq-web browser client / joule-moq-web · browser end-to-end (macos) (pull_request) Successful in 9m28s
WAI conformance / v2 vocabulary · manifests validate as stated (pull_request) Successful in 51s
standards workspaces build + test / joule-code-rs (joule-code/joule-code-rs, joule-code-rs, linux-arm64, true) (pull_request) Failing after 4m46s
WAI conformance / delivery telemetry · CMCD and CMSD against an independent library (pull_request) Successful in 23s
WAI conformance / cross-arch byte-equality · linux-arm64 (pull_request) Successful in 50s
WAI conformance / C2PA manifest emission · signed, read back, validated (pull_request) Successful in 2m22s
standards workspaces build + test / macOS energy backends (pull_request) Successful in 8m59s
wai cross-architecture byte-equality / macos-arm64 (reference) (pull_request) Successful in 25s
WAI energy receipts / energy receipts · linux-arm64 (pull_request) Successful in 9m22s
WAI HTTP delivery / HTTP corpus · every patch and mutation in exactly one shard (pull_request) Successful in 8s
WAI conformance / cargo-class corpora · linux-arm64 (pull_request) Successful in 19m25s
WAI HTTP delivery / HTTP corpus · verified both ways, and the differential (pull_request) Successful in 3m48s
wai-pack / wai-pack · linux-arm64 (pull_request) Successful in 2m22s
WAI HTTP delivery / cache rules · controls and labelled caches (pull_request) Successful in 3m9s
wai-pack / wai-pack · the floor through a media prober (pull_request) Successful in 36s
wai-pack / wai-pack · dependency licences (pull_request) Successful in 1m13s
WAI conformance / cargo-class corpora · macos (pull_request) Successful in 16m51s
wai-pack / wai-pack · independent verifier (Python) (pull_request) Successful in 4m45s
WAI conformance / cross-arch byte-equality · macos (pull_request) Successful in 1m9s
WAI conformance / independent verifiers · claims, JWP, key discovery and integer payloads (Python) (pull_request) Successful in 27m13s
WAI conformance / codec wrappers · fuzz smoke, text decode limits, C entry points, provenance, the semantic path (pull_request) Successful in 50s
WAI energy receipts / energy receipts · macos (pull_request) Successful in 4m43s
wai-pack / wai-pack · macos (pull_request) Successful in 1m7s
wai-quantum studio and desktop / desktop app · macos (pull_request) Successful in 2m4s
The Internet-Draft (xml2rfc v3 source and its text rendering) for WAI as an MSF packaging: the "wai" and "wai-receipts" packaging values; the envelope, dispatch with fallback, the parameter-set pin by SHA-256 and the determinism tiers; catalog fields wai_capabilities, wai_determinism, wai_priors, the receipts fields and wai_staged; the receipts track (WJR1), its verification and the WAI_RECEIPT object property; the codecs parameter; security and IANA considerations (WAI_RECEIPT requested from the Specification Required range, 0x3A41 meanwhile; no action for the packaging values; application/wai registered). 36 pages; idnits 3.3.0 reports only the three normative references to Internet-Drafts. Not submitted, and the NMSF comment is not sent: both are the owner's decision. Author email is a placeholder until the owner confirms it. Co-Authored-By: Claude Opus 5.5 <[email protected]>
1601 lines
85 KiB
XML
1601 lines
85 KiB
XML
<?xml version="1.0" encoding="UTF-8"?>
|
|
<!--
|
|
Source of draft-charlot-moq-wai-packaging-00, in xml2rfc v3.
|
|
Render: xml2rfc --text --html draft-charlot-moq-wai-packaging-00.xml
|
|
Status: NOT submitted. Submission is the owner's decision.
|
|
Author contact: the email address is a placeholder until the owner confirms it at
|
|
submission.
|
|
-->
|
|
<rfc xmlns:xi="http://www.w3.org/2001/XInclude"
|
|
version="3"
|
|
category="info"
|
|
docName="draft-charlot-moq-wai-packaging-00"
|
|
ipr="trust200902"
|
|
submissionType="IETF"
|
|
tocInclude="true"
|
|
tocDepth="3"
|
|
sortRefs="true"
|
|
symRefs="true">
|
|
|
|
<front>
|
|
<title abbrev="WAI Packaging for MSF">WAI Packaging for the MOQT Streaming Format</title>
|
|
<seriesInfo name="Internet-Draft" value="draft-charlot-moq-wai-packaging-00"/>
|
|
<author fullname="David Charlot" initials="D." surname="Charlot">
|
|
<organization>Transaction Science</organization>
|
|
<address>
|
|
<email>TBD (owner confirms at submission)</email>
|
|
</address>
|
|
</author>
|
|
<date year="2026" month="October" day="21"/>
|
|
<area>Web and Internet Transport</area>
|
|
<workgroup>Media Over QUIC</workgroup>
|
|
<keyword>MoQ</keyword>
|
|
<keyword>MSF</keyword>
|
|
<keyword>packaging</keyword>
|
|
<keyword>receipts</keyword>
|
|
<keyword>learned codecs</keyword>
|
|
|
|
<abstract>
|
|
<t>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.</t>
|
|
</abstract>
|
|
|
|
<note removeInRFC="true">
|
|
<name>About This Document</name>
|
|
<t>The source of this document is kept with the WAI specification it
|
|
draws on, in the directory wai/ietf of
|
|
<eref target="https://git.transaction.science/Transaction-Science/open-standards"/>.
|
|
The WAI extension texts it restates are cited as informative references
|
|
in <xref target="correspondence"/>.</t>
|
|
</note>
|
|
</front>
|
|
|
|
<middle>
|
|
|
|
<section anchor="intro">
|
|
<name>Introduction</name>
|
|
<t>MOQT <xref target="MOQT"/> moves objects, in groups, on tracks, and
|
|
orders them by priority; it does not say what an object means. MSF
|
|
<xref target="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 <xref target="CMSF"/>.</t>
|
|
<t>WAI <xref target="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.</t>
|
|
<t>This document defines how WAI envelopes are carried as MSF objects. Its
|
|
aims are:</t>
|
|
<ul>
|
|
<li>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
|
|
(<xref target="catalog"/>).</li>
|
|
<li>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 (<xref target="receipts"/>).</li>
|
|
<li>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 <xref target="MOQT" section="7.8"/>
|
|
requires.</li>
|
|
</ul>
|
|
<t>This document changes nothing in MOQT or MSF. It defines no transport
|
|
and no codec.</t>
|
|
</section>
|
|
|
|
<section anchor="conventions">
|
|
<name>Conventions and Definitions</name>
|
|
<t>The key words "<bcp14>MUST</bcp14>", "<bcp14>MUST NOT</bcp14>",
|
|
"<bcp14>REQUIRED</bcp14>", "<bcp14>SHALL</bcp14>", "<bcp14>SHALL
|
|
NOT</bcp14>", "<bcp14>SHOULD</bcp14>", "<bcp14>SHOULD NOT</bcp14>",
|
|
"<bcp14>RECOMMENDED</bcp14>", "<bcp14>NOT RECOMMENDED</bcp14>",
|
|
"<bcp14>MAY</bcp14>", and "<bcp14>OPTIONAL</bcp14>" in this document are
|
|
to be interpreted as described in BCP 14 <xref target="RFC2119"/>
|
|
<xref target="RFC8174"/> when, and only when, they appear in all capitals,
|
|
as shown here.</t>
|
|
<t>Section numbers of <xref target="MOQT"/> and <xref target="MSF"/> 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.</t>
|
|
<dl newline="false" spacing="normal">
|
|
<dt>Envelope:</dt>
|
|
<dd>A WAI container in the form of <xref target="layout"/>, beginning
|
|
with the four bytes "WAI1".</dd>
|
|
<dt>Capability:</dt>
|
|
<dd>A string naming how a payload is decoded, such as
|
|
"wai.image.png" or "wai.neural.int_hyper". Capabilities are registered
|
|
by <xref target="WAI"/>, Section 5.</dd>
|
|
<dt>Parameter set:</dt>
|
|
<dd>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.</dd>
|
|
<dt>Pin:</dt>
|
|
<dd>A manifest member that names a parameter set by the SHA-256 digest
|
|
of its bytes (<xref target="pins"/>).</dd>
|
|
<dt>Tier:</dt>
|
|
<dd>A reproducibility guarantee of a decode
|
|
(<xref target="tiers"/>).</dd>
|
|
<dt>Publisher, receiver, relay:</dt>
|
|
<dd>The MOQT original publisher of a track; an endpoint that subscribes
|
|
to a track and decodes its objects; and an MOQT relay.</dd>
|
|
<dt>Stage set:</dt>
|
|
<dd>A base and the refinement layers that improve it, delivered as
|
|
staged delivery (<xref target="staged"/>).</dd>
|
|
<dt>Link hash:</dt>
|
|
<dd>The identity of a group receipt (<xref target="link"/>).</dd>
|
|
</dl>
|
|
<t>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
|
|
<xref target="BLAKE3"/>, and SHA-256 is that of <xref target="SHS"/>.
|
|
Digests written in JSON are 64 lowercase hexadecimal digits.</t>
|
|
</section>
|
|
|
|
<section anchor="msf-extension">
|
|
<name>MSF Extension</name>
|
|
<t>All of the specifications, requirements and terminology defined in
|
|
<xref target="MSF"/> 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.</t>
|
|
</section>
|
|
|
|
<section anchor="envelope">
|
|
<name>The WAI Envelope</name>
|
|
|
|
<section anchor="layout">
|
|
<name>Layout</name>
|
|
<artwork><![CDATA[
|
|
+--------+---------+---------------+-------------+---------+
|
|
| "WAI1" | man_len | manifest | payload_len | payload |
|
|
| 4 B | u32_le | man_len bytes | u32_le | |
|
|
+--------+---------+---------------+-------------+---------+
|
|
]]></artwork>
|
|
<ul>
|
|
<li>A reader <bcp14>MUST</bcp14> refuse bytes whose first four are
|
|
not "WAI1" (0x57 0x41 0x49 0x31).</li>
|
|
<li>The manifest is a JSON object <xref target="RFC8259"/> 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.</li>
|
|
<li>The payload's interpretation is fixed by the capability that
|
|
decodes it (<xref target="dispatch"/>) and, for a capability that
|
|
decodes against a parameter set, by that set.</li>
|
|
<li>A reader <bcp14>MUST NOT</bcp14> 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 <bcp14>MAY</bcp14> refuse a larger one, from man_len
|
|
alone for its length, before it reads it.</li>
|
|
</ul>
|
|
<t><xref target="WAI"/> Section 7.1 also defines a multi-rendition
|
|
container, "WAI2". This document carries "WAI1" envelopes only.</t>
|
|
</section>
|
|
|
|
<section anchor="manifest">
|
|
<name>Manifest</name>
|
|
<t>The members this document reads are:</t>
|
|
<dl newline="true" spacing="normal">
|
|
<dt>wai:</dt>
|
|
<dd>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.</dd>
|
|
<dt>model_requirement.capability:</dt>
|
|
<dd>The capability that decodes the payload.</dd>
|
|
<dt>model_requirement.fallback:</dt>
|
|
<dd>A capability a receiver <bcp14>MAY</bcp14> 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.</dd>
|
|
<dt>conditioning.prior:</dt>
|
|
<dd><bcp14>OPTIONAL</bcp14>. The pin (<xref target="pins"/>) of the parameter set the
|
|
payload was coded against. It applies to whichever of the capability
|
|
and the fallback decodes the payload.</dd>
|
|
<dt>intent:</dt>
|
|
<dd>"replicate" states that every conforming receiver reconstructs the
|
|
source as the capability's tier promises (<xref target="tiers"/>).</dd>
|
|
<dt>refines:</dt>
|
|
<dd>Present exactly when the capability is refinement-only: what the
|
|
payload refines (<xref target="staged"/>).</dd>
|
|
<dt>security:</dt>
|
|
<dd><bcp14>OPTIONAL</bcp14>. Whether the payload is encrypted, as
|
|
<xref target="WAI"/> Section 6 defines. The capability and the pin
|
|
always describe the plaintext.</dd>
|
|
</dl>
|
|
</section>
|
|
|
|
<section anchor="dispatch">
|
|
<name>Capability Dispatch</name>
|
|
<t>A receiver dispatches an envelope as follows:</t>
|
|
<ol>
|
|
<li>If the major version in "wai" is unknown, refuse the envelope.</li>
|
|
<li>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 (<xref target="pins"/>), 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.</li>
|
|
<li>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.</li>
|
|
<li>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".</li>
|
|
</ol>
|
|
<t>A capability is dispatchable unless <xref target="WAI"/> 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 <xref target="WAI"/> 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.</t>
|
|
</section>
|
|
|
|
<section anchor="pins">
|
|
<name>Parameter-Set Pins</name>
|
|
<t>A pin is a JSON object:</t>
|
|
<table>
|
|
<name>Pin Members</name>
|
|
<thead>
|
|
<tr><th>Member</th><th>Presence</th><th>Meaning</th></tr>
|
|
</thead>
|
|
<tbody>
|
|
<tr><td>id</td><td><bcp14>REQUIRED</bcp14>, string</td><td>A name for people. A
|
|
receiver <bcp14>MUST NOT</bcp14> select or accept a parameter set by
|
|
it.</td></tr>
|
|
<tr><td>sha256</td><td><bcp14>REQUIRED</bcp14>, string</td><td>The SHA-256 of the
|
|
parameter set in its form, as 64 lowercase hexadecimal
|
|
digits.</td></tr>
|
|
<tr><td>determinism</td><td><bcp14>REQUIRED</bcp14>, string</td><td>How the decode is
|
|
made reproducible, in words.</td></tr>
|
|
<tr><td>form</td><td><bcp14>OPTIONAL</bcp14>, string</td><td>The form the digest is
|
|
computed over (below).</td></tr>
|
|
<tr><td>tier</td><td><bcp14>OPTIONAL</bcp14>, string</td><td>The tier the sender
|
|
claims: "decode-equivalence", "entropy-consistency" or
|
|
"none".</td></tr>
|
|
</tbody>
|
|
</table>
|
|
<t>A member of a pin with another JSON type makes the manifest
|
|
malformed. A null optional member is an absent one.</t>
|
|
<t>With form absent, sha256 is the SHA-256 of the one file that holds
|
|
the set; that is admissible only for a capability <xref target="WAI"/>
|
|
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.
|
|
<xref target="WAI-PRIOR"/> registers further forms.</t>
|
|
<t>A receiver that is to decode through a capability to which a pin
|
|
applies <bcp14>MUST</bcp14> 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:</t>
|
|
<ol>
|
|
<li>"pin_malformed": sha256 is not 64 lowercase hexadecimal
|
|
digits.</li>
|
|
<li>"form_not_registered": form names no registered form.</li>
|
|
<li>"form_unreadable": the receiver has no reader for the form.</li>
|
|
<li>"form_required": form is absent and the capability is not
|
|
registered with a one-file set.</li>
|
|
<li>"prior_revoked" or "prior_not_authorised": the receiver holds a key
|
|
log and refuses the set under it, as <xref target="WAI"/> Section 3.1
|
|
specifies. A receiver that holds no key log skips this check.</li>
|
|
<li>"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).</li>
|
|
<li>"set_malformed": the listing breaks a rule above.</li>
|
|
<li>"part_mismatch": a file the listing names is missing, unreadable,
|
|
or has another digest.</li>
|
|
</ol>
|
|
<t>A pinned decode <bcp14>MUST</bcp14> 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.</t>
|
|
</section>
|
|
|
|
<section anchor="tiers">
|
|
<name>Determinism Tiers</name>
|
|
<t>A learned decode evaluated in floating point does not in general
|
|
reproduce its output across devices. WAI names two reproducibility
|
|
guarantees <xref target="WAI-TIERS"/>:</t>
|
|
<dl newline="true" spacing="normal">
|
|
<dt>entropy-consistency:</dt>
|
|
<dd>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.</dd>
|
|
<dt>decode-equivalence:</dt>
|
|
<dd>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.</dd>
|
|
</dl>
|
|
<t>"none" claims neither. The tiers are ordered none <
|
|
entropy-consistency < decode-equivalence. A tier is a property of a
|
|
capability as registered: <xref target="WAI"/> 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
|
|
<bcp14>MUST NOT</bcp14> rely on it. A receiver reads a tier token it
|
|
does not recognize as "none".</t>
|
|
<t>An envelope with intent "replicate" over a learned capability
|
|
<bcp14>MUST</bcp14> be over a capability registered at
|
|
decode-equivalence, with a pin that declares decode-equivalence;
|
|
entropy-consistency <bcp14>MUST NOT</bcp14> back "replicate". A tier
|
|
covers the medium a receiver emits: a receiver that alters the decoded
|
|
medium (for example with a post-decode filter) <bcp14>MUST NOT</bcp14>
|
|
claim the tier for the result.</t>
|
|
<t>At the time of writing, <xref target="WAI"/> 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.</t>
|
|
</section>
|
|
</section>
|
|
|
|
<section anchor="catalog">
|
|
<name>Catalog</name>
|
|
|
|
<section anchor="packaging">
|
|
<name>Packaging Values</name>
|
|
<t>This specification extends the allowed packaging values defined in
|
|
<xref target="MSF" section="5.2.4"/> with two entries:</t>
|
|
<table>
|
|
<name>Packaging Values</name>
|
|
<thead>
|
|
<tr><th>Name</th><th>Value</th><th>Reference</th></tr>
|
|
</thead>
|
|
<tbody>
|
|
<tr><td>WAI</td><td>wai</td><td>This document</td></tr>
|
|
<tr><td>WAI receipts</td><td>wai-receipts</td><td><xref target="receipts-track"/></td></tr>
|
|
</tbody>
|
|
</table>
|
|
<t>Every track whose objects are WAI envelopes <bcp14>MUST</bcp14>
|
|
declare packaging "wai". On such a track:</t>
|
|
<ul>
|
|
<li>every object <bcp14>MUST</bcp14> be exactly one whole envelope. An
|
|
object that holds part of an envelope, or more than one, is not this
|
|
packaging;</li>
|
|
<li>the object boundary <bcp14>MUST</bcp14> be the envelope boundary, so
|
|
that the receipt's commitment to an object (<xref target="receipts"/>)
|
|
and MOQT's object identity are the same unit;</li>
|
|
<li>a receiver that does not recognize the packaging value "wai"
|
|
<bcp14>MUST NOT</bcp14> attempt to interpret the objects. MSF's rule
|
|
that a parser ignores fields it does not understand covers unknown
|
|
fields, not unknown packaging values.</li>
|
|
</ul>
|
|
</section>
|
|
|
|
<section anchor="fields">
|
|
<name>Track Fields</name>
|
|
<t>This specification adds the following track-level catalog fields for
|
|
tracks with packaging "wai". They are custom fields under
|
|
<xref target="MSF" section="5"/>; their "wai_" prefix keeps them from
|
|
colliding with fields MSF defines.</t>
|
|
<table>
|
|
<name>Track Fields</name>
|
|
<thead>
|
|
<tr><th>Field</th><th>Name</th><th>Required</th><th>JSON Type</th><th>Definition</th></tr>
|
|
</thead>
|
|
<tbody>
|
|
<tr><td>Capabilities</td><td>wai_capabilities</td><td>Yes</td><td>Array of String</td><td><xref target="f-caps"/></td></tr>
|
|
<tr><td>Determinism</td><td>wai_determinism</td><td>No</td><td>String</td><td><xref target="f-det"/></td></tr>
|
|
<tr><td>Pinned parameter sets</td><td>wai_priors</td><td>No</td><td>Array of Object</td><td><xref target="priors"/></td></tr>
|
|
<tr><td>Receipts</td><td>wai_receipts</td><td>Yes</td><td>Boolean</td><td><xref target="f-receipts"/></td></tr>
|
|
<tr><td>Receipt alias</td><td>wai_receipt_alias</td><td>Cond.</td><td>Number</td><td><xref target="f-receipts"/></td></tr>
|
|
<tr><td>Receipts track</td><td>wai_receipts_track</td><td>Cond.</td><td>String</td><td><xref target="f-receipts"/></td></tr>
|
|
<tr><td>Stage</td><td>wai_staged</td><td>Cond.</td><td>Object</td><td><xref target="staged"/></td></tr>
|
|
</tbody>
|
|
</table>
|
|
|
|
<section anchor="f-caps">
|
|
<name>Capabilities</name>
|
|
<t>wai_capabilities lists every capability that an object on the track
|
|
names as its capability or as its fallback. The list
|
|
<bcp14>MUST</bcp14> 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 <bcp14>MUST NOT</bcp14> subscribe on the
|
|
assumption that an undeclared capability will not appear. A receiver
|
|
<bcp14>MUST</bcp14> 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 <bcp14>MUST NOT</bcp14> fall back
|
|
silently.</t>
|
|
</section>
|
|
|
|
<section anchor="f-det">
|
|
<name>Determinism</name>
|
|
<t>wai_determinism is the weakest tier (<xref target="tiers"/>) 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.</t>
|
|
</section>
|
|
|
|
<section anchor="f-receipts">
|
|
<name>Receipts Fields</name>
|
|
<dl newline="true" spacing="normal">
|
|
<dt>wai_receipts:</dt>
|
|
<dd>Whether the track's objects are covered by receipts
|
|
(<xref target="receipts"/>). A receiver reads an absent value as
|
|
false.</dd>
|
|
<dt>wai_receipt_alias:</dt>
|
|
<dd>An integer from 0 to 2^53-1, written as an integer: the
|
|
track_alias that the track's receipts sign
|
|
(<xref target="signature"/>). MOQT's own Track Alias is chosen per
|
|
session, by each hop (<xref target="MOQT" section="3.1.3"/>), so past
|
|
the first hop it is not the number the receipts sign. Two tracks of a
|
|
catalog <bcp14>MUST NOT</bcp14> carry the same value.</dd>
|
|
<dt>wai_receipts_track:</dt>
|
|
<dd>The name, in this track's namespace, of the track of packaging
|
|
"wai-receipts" that carries this track's receipts
|
|
(<xref target="receipts-track"/>). Two tracks of a catalog
|
|
<bcp14>MUST NOT</bcp14> name the same receipts track.</dd>
|
|
</dl>
|
|
<t>A track of a stage set that declares wai_receipts true
|
|
<bcp14>MUST</bcp14> carry wai_receipt_alias and wai_receipts_track
|
|
(<xref target="staged"/>). On another track both are
|
|
<bcp14>OPTIONAL</bcp14>; a receiver finds a track's receipts chain
|
|
and receipts track by them. A clone
|
|
(<xref target="MSF" section="5.1.6"/>) inherits every field of its
|
|
parent but its name, so a clone of a track that declares receipts
|
|
<bcp14>MUST</bcp14> override both.</t>
|
|
</section>
|
|
</section>
|
|
|
|
<section anchor="priors">
|
|
<name>Pinned Parameter Sets</name>
|
|
<t>A track <bcp14>MAY</bcp14> 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.</t>
|
|
<sourcecode type="json"><![CDATA[
|
|
"wai_priors": [
|
|
{ "capability": "wai.neural.int_hyper",
|
|
"sha256": "<64 lowercase hexadecimal digits>",
|
|
"form": "wai.prior.set",
|
|
"tier": "decode-equivalence" }
|
|
]
|
|
]]></sourcecode>
|
|
<table>
|
|
<name>Members of a wai_priors Entry</name>
|
|
<thead>
|
|
<tr><th>Member</th><th>Presence</th><th>Meaning</th></tr>
|
|
</thead>
|
|
<tbody>
|
|
<tr><td>capability</td><td><bcp14>REQUIRED</bcp14>, string</td><td>A capability the
|
|
track's wai_capabilities lists.</td></tr>
|
|
<tr><td>sha256</td><td><bcp14>REQUIRED</bcp14>, string</td><td>A pin's sha256: 64
|
|
lowercase hexadecimal digits.</td></tr>
|
|
<tr><td>form</td><td><bcp14>OPTIONAL</bcp14>, string</td><td>The pin's form. Absent,
|
|
or null, where the pin declares none.</td></tr>
|
|
<tr><td>tier</td><td><bcp14>OPTIONAL</bcp14>, string</td><td>The tier the publisher
|
|
offers the set at. Advisory.</td></tr>
|
|
</tbody>
|
|
</table>
|
|
<t>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.</t>
|
|
<dl newline="true" spacing="normal">
|
|
<dt>Reading.</dt>
|
|
<dd>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".</dd>
|
|
<dt>Exhaustive.</dt>
|
|
<dd>
|
|
<t>Where a track carries wai_priors, the publisher
|
|
<bcp14>MUST</bcp14> list in it every pin that its objects carry. An
|
|
object breaks the catalog when:</t>
|
|
<ol>
|
|
<li>it carries a pin that no entry lists for its capability or for
|
|
its fallback; or</li>
|
|
<li>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.</li>
|
|
</ol>
|
|
<t>A publisher whose objects' pin can decode through the fallback
|
|
<bcp14>SHOULD</bcp14> list the set for the fallback as well.</t>
|
|
</dd>
|
|
<dt>Mismatch.</dt>
|
|
<dd>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
|
|
<bcp14>MAY</bcp14> unsubscribe from it. The catalog never stands in for
|
|
the envelope. A receiver verifies an object's pin
|
|
(<xref target="pins"/>) 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.</dd>
|
|
<dt>Tier.</dt>
|
|
<dd>A listed tier is advisory. A publisher <bcp14>MUST NOT</bcp14> list
|
|
a tier above the one the capability's registry class gives. A receiver
|
|
<bcp14>MUST NOT</bcp14> claim a tier on the strength of a listed tier:
|
|
the tier it claims for an object is the one its own decode earns
|
|
(<xref target="tiers"/>). A listed tier that differs from the tier an
|
|
object's pin states is not a mismatch.</dd>
|
|
</dl>
|
|
</section>
|
|
|
|
<section anchor="staged">
|
|
<name>Staged Tracks</name>
|
|
<t>WAI's staged delivery <xref target="WAI-STAGED"/> 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.</t>
|
|
<t>Each track of a set <bcp14>MUST</bcp14> carry, in its catalog entry, a
|
|
wai_staged object:</t>
|
|
<sourcecode type="json"><![CDATA[
|
|
"wai_staged": { "set": "cam1", "layer": 1, "lead_ms": 40 }
|
|
]]></sourcecode>
|
|
<dl newline="true" spacing="normal">
|
|
<dt>set:</dt>
|
|
<dd>A non-empty string, the same on every track of the set.</dd>
|
|
<dt>layer:</dt>
|
|
<dd>An integer from 0 to 255: 0 on a base track, k on a track that
|
|
carries layer k.</dd>
|
|
<dt>lead_ms:</dt>
|
|
<dd>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.</dd>
|
|
</dl>
|
|
<t>A set's extent is the tracks present: layers 0 to the highest layer a
|
|
track of the set states. More than one track <bcp14>MAY</bcp14> 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.</t>
|
|
<t>The tracks of a set <bcp14>MUST</bcp14> share one namespace, one
|
|
isLive (<xref target="MSF" section="5.2.7"/>) and one renderGroup
|
|
(<xref target="MSF" section="5.2.11"/>), present on each and written as
|
|
an integer. Every entry of a track's depends
|
|
(<xref target="MSF" section="5.2.14"/>) <bcp14>MUST</bcp14> name a track
|
|
of the catalog in the track's namespace; the depends of a track of layer
|
|
k <bcp14>MUST</bcp14> name at least one track of the set at each layer
|
|
below k and none at k or above, and a base track's <bcp14>MUST
|
|
NOT</bcp14> name a track of the set. A layer track <bcp14>MUST
|
|
NOT</bcp14> carry altGroup, temporalId or spatialId
|
|
(<xref target="MSF" section="5.2.12"/>, <xref target="MSF" section="5.2.16"/>,
|
|
<xref target="MSF" section="5.2.17"/>); an altGroup <bcp14>MAY</bcp14>
|
|
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 (<xref target="f-receipts"/>).</t>
|
|
<t>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"):</t>
|
|
<ol>
|
|
<li>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").</li>
|
|
<li>The set has a track at each layer from 0 to its highest
|
|
("staged-set-incomplete").</li>
|
|
<li>The depends rules above hold ("staged-depends").</li>
|
|
<li>The tracks share one namespace, one isLive and one renderGroup,
|
|
present on each, and no layer track carries altGroup, temporalId or
|
|
spatialId ("staged-grouping").</li>
|
|
<li>On a live set, lead_ms is an integer on every layer track and null
|
|
on every base track ("staged-lead").</li>
|
|
<li>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").</li>
|
|
</ol>
|
|
<t>A track that declares no namespace inherits the catalog track's
|
|
(<xref target="MSF" section="5.2.2"/>). A checker that does not know the
|
|
catalog track's namespace refuses a set that mixes declared and
|
|
inherited namespaces ("staged-malformed").</t>
|
|
<t>Groups and objects. On a live track each group <bcp14>MUST</bcp14>
|
|
carry exactly one object, which travels in a subgroup of its own
|
|
(<xref target="MOQT" section="2.2"/>). 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.</t>
|
|
<t>Priority. The base track's publisher priority
|
|
(<xref target="MOQT" section="5.1"/>) <bcp14>MUST</bcp14> be strictly
|
|
below every layer track's, and the priority of a track of layer k
|
|
<bcp14>MUST</bcp14> be no greater than that of any track of a layer above
|
|
k. This holds for each track's DEFAULT_PUBLISHER_PRIORITY
|
|
(<xref target="MOQT" section="10.4"/>) 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 <bcp14>SHOULD</bcp14> give its requests
|
|
for a set's tracks one subscriber priority.</t>
|
|
<t>Delivery timeouts. A publisher <bcp14>SHOULD</bcp14> set a live layer
|
|
object's OBJECT_DELIVERY_TIMEOUT (<xref target="MOQT" section="5.2"/>) 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 <bcp14>MAY</bcp14> withhold it.
|
|
A publisher <bcp14>MUST NOT</bcp14> 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
|
|
<xref target="WAI-STAGED"/> specifies.</t>
|
|
<t>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 <bcp14>MUST NOT</bcp14> read an envelope to cap
|
|
layers.</t>
|
|
</section>
|
|
</section>
|
|
|
|
<section anchor="receipts">
|
|
<name>Receipts</name>
|
|
|
|
<section anchor="receipts-overview">
|
|
<name>Overview</name>
|
|
<t>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 <xref target="RFC8032"/>: 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 (<xref target="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.</t>
|
|
<t>The rules here are those of <xref target="WAI-JWP"/> 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.</t>
|
|
</section>
|
|
|
|
<section anchor="content-hash">
|
|
<name>Content Hash</name>
|
|
<artwork><![CDATA[
|
|
content_hash = BLAKE3("moq-jwp:object\x01" || envelope)
|
|
]]></artwork>
|
|
<t>envelope is the object's payload: the whole envelope, from "WAI1" to
|
|
the last payload byte, with nothing inserted or reframed.</t>
|
|
</section>
|
|
|
|
<section anchor="merkle">
|
|
<name>Merkle Tree</name>
|
|
<t>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
|
|
(<xref target="energy-class"/>):</t>
|
|
<artwork><![CDATA[
|
|
leaf_v1 = BLAKE3("moq-jwp:merkle-leaf\x01" || content_hash)
|
|
leaf_v2 = BLAKE3("moq-jwp:merkle-leaf\x02" || content_hash
|
|
|| u64_be(joules_micro) || class
|
|
|| u32_be(len(origin)) || origin)
|
|
node = BLAKE3("moq-jwp:merkle-node\x01" || left || right)
|
|
]]></artwork>
|
|
<t>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 (<xref target="receipts-track"/>) and its leaf
|
|
index (<xref target="verification"/>), 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.</t>
|
|
</section>
|
|
|
|
<section anchor="energy-class">
|
|
<name>Energy Class Encoding</name>
|
|
<t>An energy figure's acquisition class says how the figure was
|
|
obtained <xref target="WAI-ENERGY"/>. Where a receipt signs it, the class
|
|
is one tag byte followed by its evidence:</t>
|
|
<table>
|
|
<name>Acquisition Classes</name>
|
|
<thead>
|
|
<tr><th>Tag</th><th>Class</th><th>Followed by</th></tr>
|
|
</thead>
|
|
<tbody>
|
|
<tr><td>0</td><td>unmetered</td><td>nothing</td></tr>
|
|
<tr><td>1</td><td>HwShunt (legacy)</td><td>nothing</td></tr>
|
|
<tr><td>2</td><td>ModelBased</td><td>nothing</td></tr>
|
|
<tr><td>3</td><td>Estimator</td><td>nothing</td></tr>
|
|
<tr><td>4</td><td>OnChipCounter</td><td>u32_be(relative_ppm) || u64_be(window_us) || u8(filtering: 0 unknown, 1 off, 2 on)</td></tr>
|
|
<tr><td>5</td><td>CalibratedInstrument</td><td>u32_be(relative_ppm) || u64_be(window_us) || u32_be(len) || calibration reference, UTF-8</td></tr>
|
|
</tbody>
|
|
</table>
|
|
<t>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.</t>
|
|
</section>
|
|
|
|
<section anchor="signature">
|
|
<name>Group Signature</name>
|
|
<t>The publisher signs, with pure Ed25519 <xref target="RFC8032"/>, one
|
|
of two signing payloads:</t>
|
|
<artwork><![CDATA[
|
|
legacy = "moq-jwp:group-sign\x01"
|
|
|| u64_be(track_alias) ; the track's wai_receipt_alias
|
|
|| u64_be(group_id) ; the MOQT Group ID
|
|
|| merkle_root ; 32 bytes
|
|
|| u64_be(leaf_count) ; objects in the group
|
|
|| u64_be(total_joules_micro) ; sum over the group's objects
|
|
|| string(group_start) ; RFC 3339, first object
|
|
|| string(group_end) ; RFC 3339, last object
|
|
|| publisher_key ; 32 bytes, Ed25519 public key
|
|
|| string(signer_id) ; identity label
|
|
|
|
labelled = "moq-jwp:group-sign\x02"
|
|
|| (the fields of legacy after its domain, in order)
|
|
|| class ; the total's class
|
|
|| u8(coverage) ; 0 Whole, 1 Partial
|
|
|| u8(has_parent) || parent ; 1 and the parent's link hash,
|
|
; or 0 and 32 zero bytes
|
|
]]></artwork>
|
|
<t>group_start and group_end are timestamps of the form of
|
|
<xref target="RFC3339"/>. signer_id names the signer; a receiver reads
|
|
nothing from it unless it can confirm it by a means outside this
|
|
document.</t>
|
|
<t>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:</t>
|
|
<ul>
|
|
<li>if an object with a non-zero figure carries no label, the group
|
|
<bcp14>MUST</bcp14> be signed in the legacy form;</li>
|
|
<li>if no object has a non-zero figure, the class is tag 0 and the
|
|
coverage 0;</li>
|
|
<li>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.</li>
|
|
</ul>
|
|
<section anchor="link">
|
|
<name>Link Hash</name>
|
|
<artwork><![CDATA[
|
|
canonical_bytes = signing_payload || signature ; 64-byte signature
|
|
link_hash = BLAKE3("moq-jwp:receipt-link\x01" || canonical_bytes)
|
|
]]></artwork>
|
|
<t>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.</t>
|
|
</section>
|
|
</section>
|
|
|
|
<section anchor="binary">
|
|
<name>Binary Forms</name>
|
|
<artwork><![CDATA[
|
|
group_bin = canonical_bytes ; labelled form
|
|
| canonical_bytes ; legacy form
|
|
|| u8(has_parent) || parent ; parent: 32 bytes
|
|
|
|
object_body = u64_be(object_id)
|
|
|| content_hash ; 32 bytes
|
|
|| u64_be(joules_micro)
|
|
|| string(origin)
|
|
|| u8(n) || sibling x n ; 32 bytes each, leaf up
|
|
|| u64_be(direction_bits)
|
|
|| u64_be(leaf_index)
|
|
|| u8(leaf_version) ; 1 leaf_v1, 2 leaf_v2
|
|
|| class ; leaf_version 2 only
|
|
|
|
receipts_bin = "WJR1"
|
|
|| group_bin
|
|
|| u32_be(count)
|
|
|| object_body x count
|
|
]]></artwork>
|
|
<t>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.</t>
|
|
<t>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 <xref target="signature"/>; 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 <xref target="energy-class"/> 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.</t>
|
|
</section>
|
|
|
|
<section anchor="receipts-track">
|
|
<name>The Receipts Track</name>
|
|
<t>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.</t>
|
|
<ul>
|
|
<li>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.</li>
|
|
<li>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.</li>
|
|
<li>A receipts track has no delivery timeout of either kind: the
|
|
publisher sets none, and a subscriber sets none on its subscription
|
|
(<xref target="MOQT" section="9.20.3"/>,
|
|
<xref target="MOQT" section="9.20.4"/>). Its publisher priority is its
|
|
media track's.</li>
|
|
<li>Its objects are receipts, not envelopes; <xref target="packaging"/>'s
|
|
object rules do not apply to them.</li>
|
|
</ul>
|
|
<t>A receiver learns the publisher's key by a means outside this
|
|
document: configuration, the session in which it subscribed, or key
|
|
discovery as <xref target="WAI-JWP"/> Section 7 specifies.</t>
|
|
</section>
|
|
|
|
<section anchor="verification">
|
|
<name>Verification</name>
|
|
<t>A receiver verifies each group receipt and each object receipt it
|
|
uses in these steps, in order:</t>
|
|
<ol>
|
|
<li>Read. The receipts_bin reads (<xref target="binary"/>); 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
|
|
<xref target="energy-class"/>; otherwise "group_label_invalid".</li>
|
|
<li>Signature. The publisher key and the signature pass, in order:
|
|
the key is the one encoding of its point that
|
|
<xref target="RFC8032" section="5.1.3"/> 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
|
|
<xref target="RFC8032"/> leaves to the verifier, so that every
|
|
conforming receiver accepts the same signatures. The receiver then
|
|
holds a verified root.</li>
|
|
<li>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 <bcp14>MAY</bcp14> hold it while it
|
|
recovers the parent, by a FETCH (<xref target="MOQT" section="3.2"/>)
|
|
of the receipts track, and <bcp14>MUST NOT</bcp14> accept it until
|
|
then. A legacy group whose group_id does not exceed its chain head's
|
|
is "group_id_not_increasing".</li>
|
|
<li>Content hash. For an object the receiver received, the content
|
|
hash of its bytes (<xref target="content-hash"/>) equals the object
|
|
receipt's; otherwise "content_hash_mismatch".</li>
|
|
<li>Inclusion. A labelled object receipt's class is valid
|
|
(<xref target="energy-class"/>); 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".</li>
|
|
<li>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.</li>
|
|
</ol>
|
|
<t>A rejection at steps 1 to 5 is a hard failure for the object. A
|
|
receiver <bcp14>MUST NOT</bcp14> accept a partial verification, such as
|
|
a valid proof against an unverified root.</t>
|
|
<t>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
|
|
<bcp14>MUST</bcp14> report it as such, and <bcp14>MUST NOT</bcp14>
|
|
report it, or anything read from it, as delivered, or dispatch on
|
|
it.</t>
|
|
<t>A receiver that holds an accepted object receipt for every leaf of a
|
|
group <bcp14>MUST</bcp14> 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
|
|
(<xref target="signature"/>).</t>
|
|
<t>Holding and joining. A receiver that holds groups for missing parents
|
|
<bcp14>MUST</bcp14> 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
|
|
(<xref target="MOQT" section="3.5"/>) anchors each chain at the first
|
|
validly signed group it receives. An anchor establishes only that the
|
|
key signed that group; a receiver <bcp14>MUST</bcp14> report a chain it
|
|
anchored as anchored, with the anchor's group_id, and <bcp14>MUST
|
|
NOT</bcp14> report the groups the anchor skipped as verified.
|
|
<xref target="WAI-JWP"/> Section 3 specifies how the groups of such a
|
|
gap, fetched later, are admitted as history.</t>
|
|
</section>
|
|
|
|
<section anchor="property">
|
|
<name>The WAI_RECEIPT Object Property</name>
|
|
<t>An object on a track of packaging "wai" <bcp14>MAY</bcp14> carry its
|
|
receipt commitment as an MOQT Object Property
|
|
(<xref target="MOQT" section="8.4"/>), WAI_RECEIPT. Its value is:</t>
|
|
<artwork><![CDATA[
|
|
value = content_hash ; 32 bytes
|
|
|| vi64(joules_micro)
|
|
|| vi64(len) || acquisition ; UTF-8 class name, or empty
|
|
|| vi64(len) || acquisition_evidence
|
|
|| group_receipt ; 32 bytes
|
|
]]></artwork>
|
|
<t>vi64 is the variable-length integer of
|
|
<xref target="MOQT" section="8.1"/>. acquisition is the class name of
|
|
<xref target="energy-class"/> ("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
|
|
<bcp14>MUST</bcp14> place the property inside Immutable Properties
|
|
(<xref target="MOQT" section="10.7"/>), which no relay may change or
|
|
remove.</t>
|
|
<ul>
|
|
<li>A receiver refuses a value that ends early, has bytes after
|
|
group_receipt, or whose acquisition is not UTF-8
|
|
("property_invalid").</li>
|
|
<li>A non-zero joules_micro <bcp14>MUST</bcp14> be accompanied by
|
|
acquisition. A zero joules_micro is the unmetered marker:
|
|
acquisition and acquisition_evidence <bcp14>MUST</bcp14> be empty, and
|
|
a receiver <bcp14>MUST NOT</bcp14> present it as zero joules.
|
|
acquisition_evidence <bcp14>MUST</bcp14> be non-empty for
|
|
OnChipCounter and CalibratedInstrument and empty for every other
|
|
class. A receiver <bcp14>MUST</bcp14> discard a property that breaks
|
|
this item ("property_invalid").</li>
|
|
<li>No signature covers the property. A receiver <bcp14>MUST
|
|
NOT</bcp14> 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 <bcp14>MUST</bcp14> discard the
|
|
property ("property_disagrees").</li>
|
|
<li>A relay <bcp14>MUST</bcp14> forward the property unchanged.</li>
|
|
<li>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.</li>
|
|
</ul>
|
|
<t>Until a type is assigned (<xref target="iana-property"/>), a track of
|
|
packaging "wai" carries the property as type 0x3A41, from the range
|
|
<xref target="MOQT" section="8.4"/> 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".</t>
|
|
</section>
|
|
|
|
<section anchor="relays">
|
|
<name>Relays</name>
|
|
<t>An MOQT relay forwards tracks of packaging "wai" and "wai-receipts"
|
|
as it forwards any track, their payloads opaque
|
|
(<xref target="MOQT" section="7.8"/>). 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 <xref target="WAI-JWP"/>
|
|
Section 4 states what it must preserve.</t>
|
|
</section>
|
|
</section>
|
|
|
|
<section anchor="codecs">
|
|
<name>The codecs Parameter</name>
|
|
<t>The optional codecs parameter of application/wai
|
|
(<xref target="iana-media-type"/>) lists the capabilities a sequence of
|
|
objects uses, in the form of <xref target="RFC6381"/>. Its WAI elements
|
|
follow this grammar <xref target="RFC5234"/>:</t>
|
|
<sourcecode type="abnf"><![CDATA[
|
|
wai-element = wai-prefix "." alt *( "|" alt )
|
|
wai-prefix = "wai1" / "wai2"
|
|
alt = cap *( "+" cap )
|
|
cap = 1*lcalnum 1*( "." 1*( lcalnum / "_" ) )
|
|
lcalnum = %x61-7A / %x30-39
|
|
]]></sourcecode>
|
|
<t>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, <bcp14>MUST</bcp14> match
|
|
the grammar. <xref target="WAI-HTTP"/> Section 4 gives the remaining
|
|
rules.</t>
|
|
</section>
|
|
|
|
<section anchor="implementation-status">
|
|
<name>Implementation Status</name>
|
|
<t>(Note to the RFC Editor: please remove this section before
|
|
publication, as <xref target="RFC7942"/> describes.)</t>
|
|
<t>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:</t>
|
|
<ul>
|
|
<li>"wai-rs", the WAI reference library: the envelope, dispatch and
|
|
pin verification (<xref target="envelope"/>), the tier rules, the
|
|
catalog check of staged tracks and the reading and check of wai_priors
|
|
(<xref target="catalog"/>), and a receipts verifier
|
|
(<xref target="receipts"/>).</li>
|
|
<li>"joule-moq", an MOQT implementation of
|
|
<xref target="MOQT"/>: 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.</li>
|
|
<li>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.</li>
|
|
</ul>
|
|
<t>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.</t>
|
|
</section>
|
|
|
|
<section anchor="security">
|
|
<name>Security Considerations</name>
|
|
<t>This document relies on MOQT <xref target="MOQT"/> for transport
|
|
security: QUIC protects each hop. The receipts of
|
|
<xref target="receipts"/> add integrity from the publisher to the
|
|
receiver across relays; they add no confidentiality.</t>
|
|
|
|
<section anchor="sec-keys">
|
|
<name>Receipt Keys</name>
|
|
<t>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
|
|
<bcp14>MUST NOT</bcp14> 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 <xref target="WAI-JWP"/> Section 7
|
|
specifies). Publishers <bcp14>MUST</bcp14> generate keys with a
|
|
cryptographically secure random number generator and <bcp14>MUST
|
|
NOT</bcp14> use one key for distinct publisher identities. The strict
|
|
verification of <xref target="verification"/> 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.</t>
|
|
</section>
|
|
|
|
<section anchor="sec-replay">
|
|
<name>Replay</name>
|
|
<t>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
|
|
<xref target="receipts-track"/> binds each receipt to the MOQT group and
|
|
object it is carried for.</t>
|
|
<t>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.</t>
|
|
<t>An anchor (<xref target="verification"/>) 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 <bcp14>MAY</bcp14> 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.</t>
|
|
</section>
|
|
|
|
<section anchor="sec-relays">
|
|
<name>Relay Transparency</name>
|
|
<t>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
|
|
<xref target="receipts"/> make an undelivered object accountable, as
|
|
inclusion-verified, but they do not make delivery happen.</t>
|
|
<t>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
|
|
<xref target="property"/> lets a receiver report its class only when it
|
|
matches a signed leaf.</t>
|
|
<t>A relay sees what MOQT exposes: track names, catalogs (unless they
|
|
are encrypted), object sizes, timing and properties, including
|
|
WAI_RECEIPT.</t>
|
|
</section>
|
|
|
|
<section anchor="sec-catalog">
|
|
<name>Catalog Integrity</name>
|
|
<t>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
|
|
(<xref target="pins"/>), and an object that breaks wai_priors refuses
|
|
its track (<xref target="priors"/>), so a misdeclared catalog leads to
|
|
refusal, not to a decode against the wrong parameters. A listed tier is
|
|
advisory and confers nothing.</t>
|
|
</section>
|
|
|
|
<section anchor="sec-params">
|
|
<name>Parameter Sets</name>
|
|
<t>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 <bcp14>SHOULD</bcp14> decode from
|
|
the very bytes it verified.</t>
|
|
</section>
|
|
|
|
<section anchor="sec-resources">
|
|
<name>Resource Consumption</name>
|
|
<t>A receiver bounds what it parses and holds: the manifest limits of
|
|
<xref target="layout"/>; a bound on the receipts it holds for missing
|
|
parents (<xref target="verification"/>); and the bounds of
|
|
<xref target="WAI"/> Section 2 on decoded payloads. A receiver
|
|
<bcp14>SHOULD</bcp14> 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.</t>
|
|
</section>
|
|
|
|
<section anchor="sec-privacy">
|
|
<name>Privacy</name>
|
|
<t>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
|
|
<xref target="SECURE-OBJECTS"/>; the receipts then commit to the bytes
|
|
carried.</t>
|
|
</section>
|
|
</section>
|
|
|
|
<section anchor="iana">
|
|
<name>IANA Considerations</name>
|
|
|
|
<section anchor="iana-packaging">
|
|
<name>MSF Packaging Values</name>
|
|
<t>This document requests no IANA action for the packaging values "wai"
|
|
and "wai-receipts". <xref target="MSF"/> lists its allowed packaging
|
|
values in its own text (<xref target="MSF" section="5.2.4"/>) and
|
|
creates no registry for them, and this document extends that list
|
|
(<xref target="packaging"/>), as other MSF packaging documents do.</t>
|
|
</section>
|
|
|
|
<section anchor="iana-property">
|
|
<name>MOQ Properties</name>
|
|
<t>This document requests that IANA register the following entry in the
|
|
"MOQ Properties" registry established by
|
|
<xref target="MOQT" section="16.8"/>, with a type from the range
|
|
0x80 to 0x37FF, whose registration policy is Specification Required:</t>
|
|
<table>
|
|
<name>WAI_RECEIPT Property</name>
|
|
<thead>
|
|
<tr><th>Type</th><th>Name</th><th>Scope</th><th>Specification</th></tr>
|
|
</thead>
|
|
<tbody>
|
|
<tr><td>TBD (odd)</td><td>WAI_RECEIPT</td><td>Object</td><td><xref target="property"/> of this document</td></tr>
|
|
</tbody>
|
|
</table>
|
|
<t>The type is odd, since the value is a byte sequence
|
|
(<xref target="MOQT" section="8.3"/>). Until a type is assigned,
|
|
implementations use 0x3A41, from the range 0x3800 to 0x3FFF that
|
|
<xref target="MOQT" section="8.4"/> reserves for application-specific
|
|
use; no registration is possible in that range, and none is
|
|
requested for it.</t>
|
|
</section>
|
|
|
|
<section anchor="iana-media-type">
|
|
<name>Media Type application/wai</name>
|
|
<t>This document requests that IANA register the media type
|
|
application/wai in the "Media Types" registry, in the standards tree,
|
|
as <xref target="RFC6838"/> provides for a registration made by an IETF
|
|
document.</t>
|
|
<dl newline="false" spacing="normal">
|
|
<dt>Type name:</dt><dd>application</dd>
|
|
<dt>Subtype name:</dt><dd>wai</dd>
|
|
<dt>Required parameters:</dt><dd>N/A</dd>
|
|
<dt>Optional parameters:</dt><dd>codecs, as <xref target="codecs"/>
|
|
of this document defines.</dd>
|
|
<dt>Encoding considerations:</dt><dd>binary</dd>
|
|
<dt>Security considerations:</dt><dd>See
|
|
<xref target="security"/> of this document. A WAI object names the
|
|
decoder its payload needs and does not carry executable code.</dd>
|
|
<dt>Interoperability considerations:</dt><dd>An object is a "WAI1"
|
|
envelope (<xref target="layout"/>) or a "WAI2" envelope
|
|
(<xref target="WAI"/> Section 7.1). A reader refuses an unknown major
|
|
version.</dd>
|
|
<dt>Published specification:</dt><dd>This document, and
|
|
<xref target="WAI"/>.</dd>
|
|
<dt>Applications that use this media type:</dt><dd>Media publishers,
|
|
relays, caches and players that carry WAI envelopes over MOQT or
|
|
HTTP.</dd>
|
|
<dt>Fragment identifier considerations:</dt><dd>None defined by this
|
|
document.</dd>
|
|
<dt>Additional information:</dt>
|
|
<dd>
|
|
<t>Deprecated alias names for this type: N/A</t>
|
|
<t>Magic number(s): 57 41 49 31 ("WAI1") or 57 41 49 32 ("WAI2")
|
|
at offset 0</t>
|
|
<t>File extension(s): .wai</t>
|
|
<t>Macintosh file type code(s): N/A</t>
|
|
</dd>
|
|
<dt>Person and email address to contact for further
|
|
information:</dt><dd>The author of this document.</dd>
|
|
<dt>Intended usage:</dt><dd>COMMON</dd>
|
|
<dt>Restrictions on usage:</dt><dd>N/A</dd>
|
|
<dt>Author:</dt><dd>See the Author's Address section of this
|
|
document.</dd>
|
|
<dt>Change controller:</dt><dd>IETF</dd>
|
|
</dl>
|
|
</section>
|
|
|
|
<section anchor="iana-none">
|
|
<name>Capability Strings</name>
|
|
<t>This document creates no registry for capability strings or tier
|
|
names. <xref target="WAI"/> registers them under its own registry
|
|
policy.</t>
|
|
</section>
|
|
</section>
|
|
</middle>
|
|
|
|
<back>
|
|
<references>
|
|
<name>References</name>
|
|
<references>
|
|
<name>Normative References</name>
|
|
|
|
<reference anchor="MOQT" target="https://datatracker.ietf.org/doc/html/draft-ietf-moq-transport-22">
|
|
<front>
|
|
<title>Media over QUIC Transport</title>
|
|
<author/>
|
|
<date year="2026" month="October" day="1"/>
|
|
</front>
|
|
<seriesInfo name="Internet-Draft" value="draft-ietf-moq-transport-22"/>
|
|
</reference>
|
|
|
|
<reference anchor="MSF" target="https://datatracker.ietf.org/doc/html/draft-ietf-moq-msf-01">
|
|
<front>
|
|
<title>MOQT Streaming Format</title>
|
|
<author/>
|
|
<date year="2026" month="June" day="2"/>
|
|
</front>
|
|
<seriesInfo name="Internet-Draft" value="draft-ietf-moq-msf-01"/>
|
|
</reference>
|
|
|
|
<reference anchor="WAI" target="https://git.transaction.science/Transaction-Science/open-standards/src/branch/main/wai/SPEC.md">
|
|
<front>
|
|
<title>WAI v1.0: Web AI Media Transport and Execution</title>
|
|
<author/>
|
|
<date year="2026" month="October"/>
|
|
</front>
|
|
<refcontent>Draft Standard, open-standards repository, wai/SPEC.md</refcontent>
|
|
</reference>
|
|
|
|
<reference anchor="BLAKE3" target="https://datatracker.ietf.org/doc/html/draft-aumasson-blake3-00">
|
|
<front>
|
|
<title>The BLAKE3 Hashing Framework</title>
|
|
<author/>
|
|
<date year="2024" month="July"/>
|
|
</front>
|
|
<seriesInfo name="Internet-Draft" value="draft-aumasson-blake3-00"/>
|
|
</reference>
|
|
|
|
<reference anchor="SHS" target="https://doi.org/10.6028/NIST.FIPS.180-4">
|
|
<front>
|
|
<title>Secure Hash Standard (SHS)</title>
|
|
<author><organization>National Institute of Standards and Technology</organization></author>
|
|
<date year="2015" month="August"/>
|
|
</front>
|
|
<seriesInfo name="FIPS PUB" value="180-4"/>
|
|
<seriesInfo name="DOI" value="10.6028/NIST.FIPS.180-4"/>
|
|
</reference>
|
|
|
|
<reference anchor="RFC2119" target="https://www.rfc-editor.org/info/rfc2119">
|
|
<front>
|
|
<title>Key words for use in RFCs to Indicate Requirement Levels</title>
|
|
<author/>
|
|
<date year="1997" month="March"/>
|
|
</front>
|
|
<seriesInfo name="BCP" value="14"/>
|
|
<seriesInfo name="RFC" value="2119"/>
|
|
<seriesInfo name="DOI" value="10.17487/RFC2119"/>
|
|
</reference>
|
|
|
|
<reference anchor="RFC8174" target="https://www.rfc-editor.org/info/rfc8174">
|
|
<front>
|
|
<title>Ambiguity of Uppercase vs Lowercase in RFC 2119 Key Words</title>
|
|
<author/>
|
|
<date year="2017" month="May"/>
|
|
</front>
|
|
<seriesInfo name="BCP" value="14"/>
|
|
<seriesInfo name="RFC" value="8174"/>
|
|
<seriesInfo name="DOI" value="10.17487/RFC8174"/>
|
|
</reference>
|
|
|
|
<reference anchor="RFC8032" target="https://www.rfc-editor.org/info/rfc8032">
|
|
<front>
|
|
<title>Edwards-Curve Digital Signature Algorithm (EdDSA)</title>
|
|
<author/>
|
|
<date year="2017" month="January"/>
|
|
</front>
|
|
<seriesInfo name="RFC" value="8032"/>
|
|
<seriesInfo name="DOI" value="10.17487/RFC8032"/>
|
|
</reference>
|
|
|
|
<reference anchor="RFC8259" target="https://www.rfc-editor.org/info/rfc8259">
|
|
<front>
|
|
<title>The JavaScript Object Notation (JSON) Data Interchange Format</title>
|
|
<author/>
|
|
<date year="2017" month="December"/>
|
|
</front>
|
|
<seriesInfo name="STD" value="90"/>
|
|
<seriesInfo name="RFC" value="8259"/>
|
|
<seriesInfo name="DOI" value="10.17487/RFC8259"/>
|
|
</reference>
|
|
|
|
<reference anchor="RFC3339" target="https://www.rfc-editor.org/info/rfc3339">
|
|
<front>
|
|
<title>Date and Time on the Internet: Timestamps</title>
|
|
<author/>
|
|
<date year="2002" month="July"/>
|
|
</front>
|
|
<seriesInfo name="RFC" value="3339"/>
|
|
<seriesInfo name="DOI" value="10.17487/RFC3339"/>
|
|
</reference>
|
|
|
|
<reference anchor="RFC5234" target="https://www.rfc-editor.org/info/rfc5234">
|
|
<front>
|
|
<title>Augmented BNF for Syntax Specifications: ABNF</title>
|
|
<author/>
|
|
<date year="2008" month="January"/>
|
|
</front>
|
|
<seriesInfo name="STD" value="68"/>
|
|
<seriesInfo name="RFC" value="5234"/>
|
|
<seriesInfo name="DOI" value="10.17487/RFC5234"/>
|
|
</reference>
|
|
|
|
<reference anchor="RFC6381" target="https://www.rfc-editor.org/info/rfc6381">
|
|
<front>
|
|
<title>The 'Codecs' and 'Profiles' Parameters for "Bucket" Media Types</title>
|
|
<author/>
|
|
<date year="2011" month="August"/>
|
|
</front>
|
|
<seriesInfo name="RFC" value="6381"/>
|
|
<seriesInfo name="DOI" value="10.17487/RFC6381"/>
|
|
</reference>
|
|
|
|
<reference anchor="RFC6838" target="https://www.rfc-editor.org/info/rfc6838">
|
|
<front>
|
|
<title>Media Type Specifications and Registration Procedures</title>
|
|
<author/>
|
|
<date year="2013" month="January"/>
|
|
</front>
|
|
<seriesInfo name="BCP" value="13"/>
|
|
<seriesInfo name="RFC" value="6838"/>
|
|
<seriesInfo name="DOI" value="10.17487/RFC6838"/>
|
|
</reference>
|
|
</references>
|
|
|
|
<references>
|
|
<name>Informative References</name>
|
|
|
|
<reference anchor="CMSF" target="https://datatracker.ietf.org/doc/html/draft-ietf-moq-cmsf-01">
|
|
<front>
|
|
<title>CMSF- a CMAF compliant implementation of MOQT Streaming Format</title>
|
|
<author/>
|
|
<date year="2026" month="June" day="3"/>
|
|
</front>
|
|
<seriesInfo name="Internet-Draft" value="draft-ietf-moq-cmsf-01"/>
|
|
</reference>
|
|
|
|
<reference anchor="SECURE-OBJECTS" target="https://datatracker.ietf.org/doc/html/draft-ietf-moq-secure-objects-01">
|
|
<front>
|
|
<title>End-to-End Secure Objects for Media over QUIC Transport</title>
|
|
<author/>
|
|
<date year="2026"/>
|
|
</front>
|
|
<seriesInfo name="Internet-Draft" value="draft-ietf-moq-secure-objects-01"/>
|
|
</reference>
|
|
|
|
<reference anchor="RFC7942" target="https://www.rfc-editor.org/info/rfc7942">
|
|
<front>
|
|
<title>Improving Awareness of Running Code: The Implementation Status Section</title>
|
|
<author/>
|
|
<date year="2016" month="July"/>
|
|
</front>
|
|
<seriesInfo name="BCP" value="205"/>
|
|
<seriesInfo name="RFC" value="7942"/>
|
|
<seriesInfo name="DOI" value="10.17487/RFC7942"/>
|
|
</reference>
|
|
|
|
<reference anchor="WAI-MOQ" target="https://git.transaction.science/Transaction-Science/open-standards/src/branch/main/wai/extensions/moq-streaming-format.md">
|
|
<front>
|
|
<title>WAI Extension: MoQ Streaming Format</title>
|
|
<author/>
|
|
<date year="2026" month="October"/>
|
|
</front>
|
|
<refcontent>open-standards repository, wai/extensions/moq-streaming-format.md</refcontent>
|
|
</reference>
|
|
|
|
<reference anchor="WAI-JWP" target="https://git.transaction.science/Transaction-Science/open-standards/src/branch/main/wai/extensions/jwp-receipts.md">
|
|
<front>
|
|
<title>WAI Extension: JWP Receipt Chain</title>
|
|
<author/>
|
|
<date year="2026" month="October"/>
|
|
</front>
|
|
<refcontent>open-standards repository, wai/extensions/jwp-receipts.md</refcontent>
|
|
</reference>
|
|
|
|
<reference anchor="WAI-TIERS" target="https://git.transaction.science/Transaction-Science/open-standards/src/branch/main/wai/extensions/determinism-tiers.md">
|
|
<front>
|
|
<title>WAI Extension: Determinism Tiers for Neural Decode</title>
|
|
<author/>
|
|
<date year="2026" month="October"/>
|
|
</front>
|
|
<refcontent>open-standards repository, wai/extensions/determinism-tiers.md</refcontent>
|
|
</reference>
|
|
|
|
<reference anchor="WAI-PRIOR" target="https://git.transaction.science/Transaction-Science/open-standards/src/branch/main/wai/extensions/prior-carriage.md">
|
|
<front>
|
|
<title>WAI Extension: Prior Carriage</title>
|
|
<author/>
|
|
<date year="2026" month="October"/>
|
|
</front>
|
|
<refcontent>open-standards repository, wai/extensions/prior-carriage.md</refcontent>
|
|
</reference>
|
|
|
|
<reference anchor="WAI-STAGED" target="https://git.transaction.science/Transaction-Science/open-standards/src/branch/main/wai/extensions/staged-delivery.md">
|
|
<front>
|
|
<title>WAI Extension: Staged Delivery</title>
|
|
<author/>
|
|
<date year="2026" month="October"/>
|
|
</front>
|
|
<refcontent>open-standards repository, wai/extensions/staged-delivery.md</refcontent>
|
|
</reference>
|
|
|
|
<reference anchor="WAI-ENERGY" target="https://git.transaction.science/Transaction-Science/open-standards/src/branch/main/wai/extensions/energy-measurement.md">
|
|
<front>
|
|
<title>WAI Extension: Energy Measurement</title>
|
|
<author/>
|
|
<date year="2026" month="October"/>
|
|
</front>
|
|
<refcontent>open-standards repository, wai/extensions/energy-measurement.md</refcontent>
|
|
</reference>
|
|
|
|
<reference anchor="WAI-HTTP" target="https://git.transaction.science/Transaction-Science/open-standards/src/branch/main/wai/extensions/http-delivery.md">
|
|
<front>
|
|
<title>WAI Extension: HTTP Delivery</title>
|
|
<author/>
|
|
<date year="2026" month="October"/>
|
|
</front>
|
|
<refcontent>open-standards repository, wai/extensions/http-delivery.md</refcontent>
|
|
</reference>
|
|
</references>
|
|
</references>
|
|
|
|
<section anchor="example">
|
|
<name>Catalog Example</name>
|
|
<t>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.</t>
|
|
<sourcecode type="json"><![CDATA[
|
|
{ "version": 1,
|
|
"tracks": [
|
|
{ "namespace": "example/cam1", "name": "cam1/base",
|
|
"packaging": "wai", "isLive": true, "targetLatency": 300,
|
|
"role": "video", "renderGroup": 1,
|
|
"wai_capabilities": ["wai.video.int_motion"],
|
|
"wai_determinism": "decode-equivalence",
|
|
"wai_receipts": true, "wai_receipt_alias": 7,
|
|
"wai_receipts_track": "cam1/base/receipts",
|
|
"wai_staged": { "set": "cam1", "layer": 0,
|
|
"lead_ms": null } },
|
|
{ "namespace": "example/cam1", "name": "cam1/L1",
|
|
"packaging": "wai", "isLive": true, "targetLatency": 300,
|
|
"role": "video", "renderGroup": 1, "depends": ["cam1/base"],
|
|
"wai_capabilities": ["wai.video.int_refine"],
|
|
"wai_determinism": "decode-equivalence",
|
|
"wai_receipts": true, "wai_receipt_alias": 8,
|
|
"wai_receipts_track": "cam1/L1/receipts",
|
|
"wai_staged": { "set": "cam1", "layer": 1, "lead_ms": 20 } },
|
|
{ "namespace": "example/cam1", "name": "cam1/base/receipts",
|
|
"packaging": "wai-receipts", "isLive": true },
|
|
{ "namespace": "example/cam1", "name": "cam1/L1/receipts",
|
|
"packaging": "wai-receipts", "isLive": true },
|
|
{ "namespace": "example/net", "name": "pictures",
|
|
"packaging": "wai", "isLive": false, "role": "video",
|
|
"wai_capabilities": ["wai.neural.int_hyper",
|
|
"wai.image.png"],
|
|
"wai_determinism": "decode-equivalence",
|
|
"wai_priors": [
|
|
{ "capability": "wai.neural.int_hyper",
|
|
"sha256":
|
|
"a1a1a1a1a1a1a1a1a1a1a1a1a1a1a1a1a1a1a1a1a1a1a1a1a1a1a1a1a1a1a1a1",
|
|
"form": "wai.prior.set", "tier": "decode-equivalence" } ],
|
|
"wai_receipts": true, "wai_receipt_alias": 9,
|
|
"wai_receipts_track": "pictures/receipts" },
|
|
{ "namespace": "example/net", "name": "pictures/receipts",
|
|
"packaging": "wai-receipts", "isLive": false } ] }
|
|
]]></sourcecode>
|
|
<t>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.</t>
|
|
</section>
|
|
|
|
<section anchor="reasons">
|
|
<name>Refusal Reasons</name>
|
|
<table>
|
|
<name>Refusal Reasons</name>
|
|
<thead>
|
|
<tr><th>Reason</th><th>Raised by</th></tr>
|
|
</thead>
|
|
<tbody>
|
|
<tr><td>missing_capability</td><td><xref target="dispatch"/></td></tr>
|
|
<tr><td>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</td><td><xref target="pins"/></td></tr>
|
|
<tr><td>tier_exceeds_class</td><td><xref target="tiers"/></td></tr>
|
|
<tr><td>catalog_priors_malformed, catalog_prior_mismatch</td><td><xref target="priors"/></td></tr>
|
|
<tr><td>staged-malformed, staged-set-incomplete, staged-depends, staged-grouping, staged-lead, staged-receipts</td><td><xref target="staged"/></td></tr>
|
|
<tr><td>moqt_mismatch</td><td><xref target="receipts-track"/></td></tr>
|
|
<tr><td>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</td><td><xref target="verification"/></td></tr>
|
|
<tr><td>property_invalid, property_disagrees</td><td><xref target="property"/></td></tr>
|
|
</tbody>
|
|
</table>
|
|
</section>
|
|
|
|
<section anchor="correspondence">
|
|
<name>Correspondence with the WAI Texts</name>
|
|
<t>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.</t>
|
|
<table>
|
|
<name>Correspondence</name>
|
|
<thead>
|
|
<tr><th>This document</th><th>WAI text</th></tr>
|
|
</thead>
|
|
<tbody>
|
|
<tr><td><xref target="layout"/>, <xref target="manifest"/></td><td><xref target="WAI"/> Sections 2 and 3</td></tr>
|
|
<tr><td><xref target="dispatch"/></td><td><xref target="WAI"/> Section 4</td></tr>
|
|
<tr><td><xref target="pins"/></td><td><xref target="WAI"/> Section 3.1; <xref target="WAI-PRIOR"/></td></tr>
|
|
<tr><td><xref target="tiers"/></td><td><xref target="WAI-TIERS"/> Sections 2 and 3</td></tr>
|
|
<tr><td><xref target="packaging"/>, <xref target="fields"/></td><td><xref target="WAI-MOQ"/> Sections 3 and 4</td></tr>
|
|
<tr><td><xref target="priors"/></td><td><xref target="WAI-MOQ"/> Section 4.2</td></tr>
|
|
<tr><td><xref target="staged"/></td><td><xref target="WAI-MOQ"/> Section 4.1</td></tr>
|
|
<tr><td><xref target="content-hash"/> to <xref target="verification"/></td><td><xref target="WAI-JWP"/> Sections 2, 2.7 and 3; <xref target="WAI-ENERGY"/> Sections 2.3 and 2.7</td></tr>
|
|
<tr><td><xref target="property"/></td><td><xref target="WAI-MOQ"/> Section 5</td></tr>
|
|
<tr><td><xref target="codecs"/>, <xref target="iana-media-type"/></td><td><xref target="WAI-HTTP"/> Sections 3 and 4</td></tr>
|
|
</tbody>
|
|
</table>
|
|
</section>
|
|
</back>
|
|
</rfc>
|