open-standards/wai/live-conformance/messaging/README.md
Transaction Science d07295fdc3 live-messaging: the independent verifier, written from the extension's text
live_messaging_verify.py reads descriptors with live_rooms_verify.py, Key IDs,
keys, AES-GCM and plaintexts with e2ee_verify.py, and implements the rest:
every record, the receipts-track object of jwp-receipts' binary form, a
conversation entry by entry, what a principal is owed, and calls. It agrees
with wai-rs on every vector, fails every mutated copy of the corpus, and
catches each of its own checks dropped. The corpus gains receipt-level and
plaintext-level controls, a conversation under AES_256_GCM_SHA512_128, and
history requests that state whether the requester is admitted (§9.3).

Co-Authored-By: Claude Opus 5.5 <[email protected]>
2026-10-26 10:48:48 -04:00

78 lines
5.4 KiB
Markdown

# live-conformance/messaging — conversations and calls
The corpus of [`extensions/live-messaging.md`](../../extensions/live-messaging.md) §13:
conversations on end-to-end encrypted rooms of [live-rooms](../../extensions/live-rooms.md) as a
history store's log holds them (epoch statements, sealed messages with their receipts, and
acknowledgements), what principals are owed of a log, calls, and every record of the extension
on its own.
**Conformance.** A conforming verifier reaches, for every vector, the outcome it states:
- each of `conversations`, given its `input` (`descriptor`, `record`, `statement`, the
`secrets` of the epochs it opens, and the `entries` in the log's order, each at its
`position`; §11.1): its refusal, `reason` and `at` (§11.2), or the view of §11.5: every
epoch with its roster; every message at its position with its `author`, `group`, `link`
(none where its receipts do not read) and `outcome` (`accepted`, `sealed`, or the reason
§11.3 refuses it), and for an accepted one its `kind`, `t`, `target` and `retracted_by`, a
text's or a reply's `status`, current `text`, `edits` and `reactions`, and a text's
`replies`; every acknowledgement's `outcome`; and `acknowledged`, the last group each member
acknowledged delivered and read of each author;
- each of `history` (§9.3): the content positions the requester is `owed` of the named
conversation's log from position `from`, given whether it is `admitted`, or `refused`;
- each of `calls` (§10): its refusal, `reason` and `at`, or each invitation's `callee`, `t`,
`deadline`, `state` and the `at` of its answer;
- each of `records` (§2): `ok`, or the reason the record is refused when it is read alone,
checked to name `room` and verified under `key`.
`about` says what each vector is, and is not checked.
**Provenance.** Generated here: `wai_live_messaging_vectors gen` writes `vectors.json` from
conversations and calls authored in code, from fixed seeds. Each key is SHA-256 of
`wai:live-messaging/corpus/key`, a zero byte and the principal's index (`principals` lists their
public keys). Each epoch's application secret is SHA-256 of `wai:live-messaging/corpus/secret`,
a zero byte, the generation and the epoch: it stands where an MLS exporter gives one, the
boundary confidentiality §14 draws, so the corpus runs no MLS; every message is sealed under it by
confidentiality §4, in the suite the conversation's record names. In a conversation's log, the
position before each epoch statement is left empty, where a store holds the GroupInfo or commit
that opened it; a verifier is not given handshake messages (§11.1). Ed25519 and AES-GCM under a
fixed key and nonce are deterministic, so the file is the same bytes on every machine. The
generator asserts that the reference reaches the outcome written for every message and
acknowledgement, and that the corpus gives every reason of §12, before it writes. No recorded
data.
## Layout
`vectors.json`: `principals` (informative), `key_seed`, `secret_seed`, `conversations`,
`history`, `calls` and `records`.
- `conversation`: alice creates the group; bob and carol join. A thread on alice's root with
two replies; reactions, one retracted; edits of the root and of a reply; a text retracted;
acknowledgements of delivery and reading, and one of each refusal of §8; then one message
refused for each content reason of §11.3 steps 8 to 12, each a control of one defect; and a
padded message.
- `removal`: a message before any epoch statement; bob removed, his message after the removal
refused `sender_not_member` while his earlier one stands; dave joining later at bob's old
leaf; one message refused for each reason of §11.3 steps 3 to 7: a stale epoch, another's
leaf, an empty leaf, properties that do not read, no Key ID, a gap, receipts in the legacy
form, of another key, naming a parent not held, naming none, with two objects, a changed
signature, a total beside the unmetered marker, another position, another root, a payload
changed after it was signed, a payload sealed under another secret, an inner digest that is
not the payload's, and a plaintext that does not read.
- `sealed_reader`: a verifier without epoch 1's secret: its message is `sealed`, and its
acknowledgement is checked.
- `suite_256`: a conversation under `AES_256_GCM_SHA512_128`.
- refused: the descriptor's signature; no confidentiality record; a record's suite, its MLS
suite, a recorded room; each rule of the statement; and each rule of §7.3.
- `history`: against `removal`, a member from the start, bob from the start and from his
removal, carol from a later position, dave, eve never admitted and eve admitted and waiting
for her Welcome, and alice past the log's end.
- `calls`: a call between two principals accepted; a call among four in which one accepts, one
declines and one is missed by the clock's answer; a call cancelled; one still ringing; and one
refused for each reason of §10.1 to §10.3.
- `records`: each of the seven records as signed, then cut, renamed, of another version,
extended, read beside another room, checked under another key, and with its signature changed.
The second implementation, `../live_messaging_verify.py`, reads descriptors with
`../live_rooms_verify.py` and Key IDs, keys, AES-GCM and plaintexts with `../e2ee_verify.py`,
and implements the rest from the extension's text; it also mutates copies of the corpus and
drops each of its own checks in turn, and requires the corpus to catch each one.