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
//! §3.2–3.4 — the three packet headers.
//!
//! Every packet opens with `type: u8, version: u8`, and **all multi-byte
//! header fields are little-endian** (§3.1, ruling 64). That is exactly
//! three fields across the whole grammar — `sender_index`,
//! `receiver_index` and `counter` — because everything else in every
//! header is a single byte.
//!
//! Little-endian is why these are `#[derive(Packed)]` structs with plain
//! `u32` / `u64` fields: packtool packs raw integers little-endian, so
//! **the derive is the encoder**. No field is an `[u8; N]`, and no
//! per-field byte-order conversion is written by hand anywhere in this
//! module — there is no site for one to be wrong at. §5.2's msg1
//! timestamp is the crate's one big-endian integer pair and it lives in
//! [`super::payload`], which is not a header.
//!
//! # The asymmetry, stated because no compile check catches it
//!
//! [`RespHeader`] carries `sender_index` **then** `receiver_index`;
//! [`DataHeader`] carries `receiver_index` **only**. A `DataHeader` whose
//! `u32` is filled from *our* index instead of the peer's routes every
//! packet to the wrong session and produces no type error.
use Packed;
use crateconstants;
/// §3.2's `type(1) ‖ version(1) ‖ sender_index(4)` — 6 bytes.
///
/// `sender_index` is the initiator's random nonzero `u32` index (§17.3).
/// **This type enforces nothing about it**: §17.3's nonzero rule is a
/// *minting* rule, and a header that rejected index 0 would have put a
/// table invariant in the packet layer.
pub
/// §3.3's `type(1) ‖ version(1) ‖ sender_index(4) ‖ receiver_index(4)` —
/// 10 bytes.
pub
/// §3.4's `type(1) ‖ version(1) ‖ receiver_index(4) ‖ counter(8)` — 14
/// bytes.
///
/// **These 14 bytes are the AEAD associated data, verbatim.** The receive
/// path hands the AEAD the received bytes, never a re-encode of a decoded
/// header — see [`super::Inbound::Data`].
pub
// ═══════════════════════════════════════════════════════════════════════
// §3.5's size table, executed
// ═══════════════════════════════════════════════════════════════════════
//
// packtool's layout is the one source of each header's size; these tie it
// to the spec's table. A field added, removed, widened or narrowed fails
// the BUILD. Slice 0's assertions already tie `INIT_HEADER_LEN` into
// `INIT_PACKET_LEN` and thence into `MAX_DATAGRAM` and `MAX_PLAINTEXT`, so
// all three lengths are now pinned end-to-end from the packtool layout up
// to the MTU.
const _: = assert!;
const _: = assert!;
const _: = assert!;
// §3.4's AD rule depends on this and a reader should not have to
// re-derive it: header ‖ ciphertext ‖ tag exactly fills one datagram at
// the maximum plaintext.
const _: = assert!;