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
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
//! Compile-time validity guard for Noise handshake patterns.
//!
//! A handshake [`Pattern`] is *well-formed* when every Diffie–Hellman token
//! operates on two keys that have already been transmitted by that point in
//! the message flow (Noise spec §7.3). A malformed pattern — e.g. one whose
//! first message performs `es` before the initiator has sent `e` — is a
//! **compile error**, not a runtime or interop failure.
//!
//! # How it works — rejection by absent impl
//!
//! The guard is a type-level fold over the pattern's pre-messages and
//! handshake messages. It threads a [`State`] — five type-level booleans:
//! which of the four keys (initiator/responder × ephemeral/static) have been
//! transmitted so far, plus whether the cipher has been keyed — applying one
//! [`Step`] per token:
//!
//! * `e`/`s` mark the *sending* party's ephemeral/static available — and,
//! because no party ever transmits the same key twice, require that it was
//! **not** yet available, catching a duplicated `e`/`s`.
//! * each DH token (`ee`/`es`/`se`/`ss`) has a single [`Step`] impl whose
//! input [`State`] pins the two keys it consumes to [`True`]. If the fold
//! reaches the token while either key is still [`False`], **no impl
//! matches** and the type check fails. The invalid case is rejected not by
//! a negative assertion but by the simple absence of a transition. Each DH
//! token also marks the cipher keyed.
//! * `psk` moves no key but marks the cipher keyed.
//!
//! Pre-messages run first from the all-`False` start state, then the
//! handshake messages continue from the resulting state — the *same* fold,
//! since a pre-message `<- s` (responder's static known up front) has the
//! same effect on availability as sending it. A DH token mistakenly placed
//! in a pre-message is rejected for free (nothing is available there yet).
//!
//! [`WellFormed`] ties it together: every DH token's keys must be available,
//! and the cipher must be [`Keyed`] by the end (a pattern that performs no DH
//! or `psk` — e.g. a lone `-> e` — would finalise with transport keys derived
//! only from the public protocol name, and is rejected). It is enforced two
//! ways: `assert_well_formed!` forces the check at a pattern's definition
//! site, and the [`Protocol`](super::Protocol) impl requires it, so an
//! ill-formed pattern can never parameterise a handshake.
use PhantomData;
use Pattern;
use ;
use ;
// ── Type-level booleans and availability state ───────────────────
/// Type-level boolean — the key has been transmitted.
;
/// Type-level boolean — the key has not been transmitted.
;
/// Availability state threaded through the fold: which of the four keys have
/// been transmitted so far, in the order initiator-ephemeral,
/// responder-ephemeral, initiator-static, responder-static — plus `CK`, whether
/// the cipher has been keyed by a DH or `psk` token at least once.
>);
/// The all-`False` starting state — nothing transmitted, cipher unkeyed.
type Start = ;
// ── Direction → sending party ────────────────────────────────────
/// The party that *sends* a message (or pre-message) of a given direction.
///
/// A `->` (`ToResponder`) line is sent by the initiator; a `<-`
/// (`ToInitiator`) line by the responder. The same mapping serves
/// pre-messages, where it names whose key is known up front.
// ── Per-token transition ─────────────────────────────────────────
/// One token's effect on the availability [`State`], given the sending party.
///
/// `e`/`s` set the sender's bit (and require it unset — no key is sent
/// twice); DH tokens require their two keys already set, encoded by pinning
/// those bits to [`True`] in the only impl; `psk` is the identity. A token
/// with no matching impl for the current state is what makes a malformed
/// pattern fail to compile.
// `e` — the sender transmits its ephemeral (and must not have already).
// Carries the cipher-keyed bit `CK` through unchanged.
// `s` — the sender transmits its static (and must not have already).
// Carries `CK` through unchanged.
// DH tokens — sender-independent; each consumes two already-transmitted keys
// and keys the cipher (`CK` -> `True`).
// `ee` = DH(initiator-e, responder-e): requires IE and RE.
// `es` = DH(initiator-e, responder-s): requires IE and RS.
// `se` = DH(initiator-s, responder-e): requires IS and RE.
// `ss` = DH(initiator-s, responder-s): requires IS and RS.
// `psk` mixes a pre-shared key: moves no DH key but keys the cipher.
// ── The fold: tokens within a message, messages within a pattern ─
/// Fold the tokens of a single message, threading the availability state.
/// Fold a list of messages (or pre-messages), threading the state across them.
// ── Finalisation: the cipher must be keyed ───────────────────────
/// Marker for a final fold [`State`] whose cipher has been keyed at least once
/// (`CK = True`).
///
/// [`WellFormed`] requires the state after the last handshake message to be
/// `Keyed`, so a pattern that performs no DH (`ee`/`es`/`se`/`ss`) and no `psk`
/// token — and would therefore finalise to a transport whose keys derive solely
/// from the public protocol-name hash — is rejected at compile time. (The bit
/// tracks "a DH or PSK occurred", which is intentionally narrower than the
/// engine's runtime keyed flag: it does not credit the extra `mix_key` an `E`
/// token performs in a PSK pattern, because every PSK pattern already carries a
/// `psk` token that keys.)
// ── The public guard ─────────────────────────────────────────────
/// A [`Pattern`] whose token sequence is valid (Noise spec §7.3): every DH
/// token consumes keys already transmitted, and no party sends the same
/// ephemeral or static twice.
///
/// Implemented automatically for every [`Pattern`] that passes the
/// compile-time fold described in the [module docs](self) — so a malformed
/// pattern simply does not implement it. The [`Protocol`](super::Protocol)
/// impl requires `WellFormed`, so an ill-formed pattern cannot reach a
/// handshake; use `assert_well_formed!` to surface the failure at the
/// pattern's own definition.
///
/// # Examples
///
/// A shipped pattern is well-formed:
///
/// ```
/// use hiss::noise::WellFormed;
/// fn assert_well_formed<P: WellFormed>() {}
/// assert_well_formed::<hiss::noise::pattern::IKpsk1>();
/// ```
///
/// A DH before its key is transmitted (`es` before the initiator's `e`) is
/// rejected at compile time:
///
/// ```compile_fail
/// use hiss::noise::{Cons, Message, Nil, Pattern, ToResponder, WellFormed, E, Es};
/// struct Bad;
/// impl Pattern for Bad {
/// const NAME: &'static str = "Bad";
/// const NUM_MESSAGES: usize = 1;
/// type PreMessages = Nil;
/// type Messages = Cons<Message<ToResponder, Cons<Es, Cons<E, Nil>>>, Nil>;
/// }
/// fn assert_well_formed<P: WellFormed>() {}
/// assert_well_formed::<Bad>(); // es has no key — does not compile
/// ```
///
/// A Diffie–Hellman token in a pre-message (nothing is transmitted there) is
/// rejected:
///
/// ```compile_fail
/// use hiss::noise::{Cons, Message, Nil, Pattern, ToInitiator, ToResponder, WellFormed, E, Es};
/// struct Bad;
/// impl Pattern for Bad {
/// const NAME: &'static str = "Bad";
/// const NUM_MESSAGES: usize = 1;
/// type PreMessages = Cons<Message<ToInitiator, Cons<Es, Nil>>, Nil>;
/// type Messages = Cons<Message<ToResponder, Cons<E, Nil>>, Nil>;
/// }
/// fn assert_well_formed<P: WellFormed>() {}
/// assert_well_formed::<Bad>();
/// ```
///
/// Sending the same ephemeral twice is rejected:
///
/// ```compile_fail
/// use hiss::noise::{Cons, Ee, Message, Nil, Pattern, ToInitiator, ToResponder, WellFormed, E};
/// struct Bad;
/// impl Pattern for Bad {
/// const NAME: &'static str = "Bad";
/// const NUM_MESSAGES: usize = 3;
/// type PreMessages = Nil;
/// // -> e / <- e, ee / -> e (initiator sends e twice)
/// type Messages = Cons<
/// Message<ToResponder, Cons<E, Nil>>,
/// Cons<
/// Message<ToInitiator, Cons<E, Cons<Ee, Nil>>>,
/// Cons<Message<ToResponder, Cons<E, Nil>>, Nil>,
/// >,
/// >;
/// }
/// fn assert_well_formed<P: WellFormed>() {}
/// assert_well_formed::<Bad>();
/// ```
///
/// A pattern that never keys the cipher (a lone `-> e` — no DH and no `psk`) is
/// rejected; it would otherwise finalise to a transport keyed only from the
/// public protocol-name hash:
///
/// ```compile_fail
/// use hiss::noise::{Cons, Message, Nil, Pattern, ToResponder, WellFormed, E};
/// struct Bad;
/// impl Pattern for Bad {
/// const NAME: &'static str = "Bad";
/// const NUM_MESSAGES: usize = 1;
/// type PreMessages = Nil;
/// // -> e (no DH, no psk — the cipher is never keyed)
/// type Messages = Cons<Message<ToResponder, Cons<E, Nil>>, Nil>;
/// }
/// fn assert_well_formed<P: WellFormed>() {}
/// assert_well_formed::<Bad>(); // never keyed — does not compile
/// ```
// ── Derived PSK modifier ─────────────────────────────────────────
/// A [`Pattern`]'s PSK modifier, derived from its `Messages` token list.
///
/// `HAS_PSK` is computed by the [`ContainsPsk`] fold rather than declared by
/// hand, so it cannot drift out of sync with the tokens. Because this is a
/// blanket impl, the value is not overridable. The handshake engine reads it
/// here to gate the extra `mix_key` on the `E` token in PSK patterns.
/// Assert at compile time that a [`Pattern`] is [`WellFormed`], reporting the
/// failure at the macro's call site (a pattern's definition) rather than at a
/// distant handshake call.
pub use assert_well_formed;