1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
//! The control-frame prefixes a 1:1 sealed conversation is carried on.
//!
//! A frame's type is the reserved prefix its content begins with. The six
//! here are the ones both ends of a pair speak: everything needed to
//! establish a session, carry sealed payloads over it, and confirm it came
//! up. They live in this crate because a leaf node emits and parses them
//! with a different MLS implementation than the engine, and two ends that
//! disagree about a prefix byte do not have a conversation at all.
//!
//! # What is not here
//!
//! The engine reserves many more: connection lifecycle, group frames, relay
//! answers, presence, the sealed rich body, document sync. None of them
//! reach a leaf node, and the registry that gates them is engine
//! machinery. The split is deliberately "what a pair needs" rather than
//! "every prefix", because the second would put group and relay vocabulary
//! into a crate that builds for a part with 1536 KB of flash.
//!
//! # The registry still lives in the engine
//!
//! Naming a prefix here does **not** reserve it. Reservation is the
//! `INTERNAL_PREFIXES` array in `offline-protocol`, which drives refusal of
//! application content that begins with one, and which is generated from the
//! same macro invocation that names these. Adding a prefix to this module
//! without adding it there registers nothing.
/// Carries a key package payload, JSON, signed on the control plane.
///
/// This is the only channel by which capabilities are advertised, which is
/// why a device that cannot mint one is served the protocol floor forever.
pub const KEY_PACKAGE: &str = "__MLS_KEY_PKG__";
/// Carries an MLS Welcome, JSON, signed on the control plane.
///
/// The MLS bytes inside are a JSON byte array rather than base64, unlike
/// every group frame.
pub const WELCOME: &str = "__MLS_WELCOME__";
/// Carries a sealed payload: the compact envelope in base64, or the JSON
/// envelope that is the permanent floor.
///
/// This is a data-plane frame. It carries no control-plane signature,
/// because MLS authenticates its own sender and a second signature would
/// state on the outside what the AEAD already proves on the inside.
pub const ENCRYPTED: &str = "__MLS_ENC__";
/// Asks a peer to confirm it holds a working session. Empty body, signed.
pub const SESSION_CONFIRM_PROBE: &str = "__MLS_CONFIRM_PROBE__";
/// Answers [`SESSION_CONFIRM_PROBE`]. Empty body, signed.
pub const SESSION_CONFIRM_ACK: &str = "__MLS_CONFIRM_ACK__";
/// A confirmation that travels **inside** an [`ENCRYPTED`] envelope and
/// never on the wire as a frame of its own.
///
/// Its whole purpose is to be a group-aware decrypt. A peer that created a
/// session of its own confirms only on a successful decrypt, so a plaintext
/// acknowledgement leaves it unconfirmed no matter how many times it is
/// sent. The receiver consumes this marker and never surfaces it.
pub const SESSION_CONFIRM_ENCRYPTED: &str = "__MLS_ENC_CONFIRM__";