nym_sphinx_params/
packet_sizes.rs1use crate::PacketType;
5#[cfg(feature = "outfox")]
6use nym_sphinx_types::{MIN_PACKET_SIZE, MIX_PARAMS_LEN, OUTFOX_PACKET_OVERHEAD};
7#[cfg(feature = "sphinx")]
8use nym_sphinx_types::{PAYLOAD_OVERHEAD_SIZE, header::HEADER_SIZE};
9use serde::{Deserialize, Serialize};
10use std::cmp::Ordering;
11
12use std::fmt::{Debug, Display, Formatter};
13use std::str::FromStr;
14use thiserror::Error;
15
16#[cfg(feature = "sphinx")]
18const SPHINX_PACKET_OVERHEAD: usize = HEADER_SIZE + PAYLOAD_OVERHEAD_SIZE;
19
20#[cfg(feature = "sphinx")]
27const ACK_IV_SIZE: usize = 16;
28
29#[cfg(feature = "sphinx")]
30const ACK_PACKET_SIZE: usize = ACK_IV_SIZE + crate::FRAG_ID_LEN + SPHINX_PACKET_OVERHEAD;
31#[cfg(feature = "sphinx")]
32const REGULAR_PACKET_SIZE: usize = 2 * 1024 + SPHINX_PACKET_OVERHEAD;
33#[cfg(feature = "sphinx")]
34const EXTENDED_PACKET_SIZE_8: usize = 8 * 1024 + SPHINX_PACKET_OVERHEAD;
35#[cfg(feature = "sphinx")]
36const EXTENDED_PACKET_SIZE_16: usize = 16 * 1024 + SPHINX_PACKET_OVERHEAD;
37#[cfg(feature = "sphinx")]
38const EXTENDED_PACKET_SIZE_32: usize = 32 * 1024 + SPHINX_PACKET_OVERHEAD;
39
40#[cfg(feature = "outfox")]
41const OUTFOX_ACK_PACKET_SIZE: usize = MIN_PACKET_SIZE + OUTFOX_PACKET_OVERHEAD;
42#[cfg(feature = "outfox")]
43const OUTFOX_REGULAR_PACKET_SIZE: usize = 2 * 1024 + OUTFOX_PACKET_OVERHEAD;
44
45#[derive(Debug, Error)]
46pub enum InvalidPacketSize {
47 #[error("{received} is not a valid packet size tag")]
48 UnknownPacketTag { received: u8 },
49
50 #[error("{received} is not a valid extended packet size variant")]
51 UnknownExtendedPacketVariant { received: String },
52
53 #[error("{received} does not correspond with any known packet size")]
54 UnknownPacketSize { received: usize },
55}
56
57#[repr(u8)]
58#[derive(Clone, Copy, PartialEq, Eq, Default, Serialize, Deserialize)]
59pub enum PacketSize {
60 #[default]
62 #[serde(rename = "regular")]
63 RegularPacket = 1,
64
65 #[serde(rename = "ack")]
67 AckPacket = 2,
68
69 #[serde(rename = "extended32")]
71 ExtendedPacket32 = 3,
72
73 #[serde(rename = "extended8")]
75 ExtendedPacket8 = 4,
76
77 #[serde(rename = "extended16")]
79 ExtendedPacket16 = 5,
80
81 #[serde(rename = "outfox_regular")]
82 OutfoxRegularPacket = 6,
83
84 #[serde(rename = "outfox_ack")]
86 OutfoxAckPacket = 7,
87}
88
89impl PartialOrd for PacketSize {
90 fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
91 Some(self.cmp(other))
93 }
94}
95
96impl Ord for PacketSize {
97 fn cmp(&self, other: &Self) -> Ordering {
98 self.size().cmp(&other.size())
100 }
101}
102
103impl FromStr for PacketSize {
104 type Err = InvalidPacketSize;
105
106 fn from_str(s: &str) -> Result<Self, Self::Err> {
107 match s {
108 "regular" => Ok(Self::RegularPacket),
109 "ack" => Ok(Self::AckPacket),
110 "extended8" => Ok(Self::ExtendedPacket8),
111 "extended16" => Ok(Self::ExtendedPacket16),
112 "extended32" => Ok(Self::ExtendedPacket32),
113 "outfox_regular" => Ok(Self::OutfoxRegularPacket),
114 "outfox_ack" => Ok(Self::OutfoxAckPacket),
115 s => Err(InvalidPacketSize::UnknownExtendedPacketVariant {
116 received: s.to_string(),
117 }),
118 }
119 }
120}
121
122impl Display for PacketSize {
123 fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
124 match self {
125 PacketSize::RegularPacket => write!(f, "regular"),
126 PacketSize::AckPacket => write!(f, "ack"),
127 PacketSize::ExtendedPacket32 => write!(f, "extended32"),
128 PacketSize::ExtendedPacket8 => write!(f, "extended8"),
129 PacketSize::ExtendedPacket16 => write!(f, "extended16"),
130 PacketSize::OutfoxRegularPacket => write!(f, "outfox_regular"),
131 PacketSize::OutfoxAckPacket => write!(f, "outfox_ack"),
132 }
133 }
134}
135
136impl Debug for PacketSize {
137 fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
138 let name = self.to_string();
139 let size = self.size();
140 let plaintext = self.plaintext_size();
141
142 write!(f, "{name} ({size} bytes / {plaintext} plaintext)")
143 }
144}
145
146impl TryFrom<u8> for PacketSize {
147 type Error = InvalidPacketSize;
148
149 fn try_from(value: u8) -> Result<Self, Self::Error> {
150 match value {
151 _ if value == (PacketSize::RegularPacket as u8) => Ok(Self::RegularPacket),
152 _ if value == (PacketSize::AckPacket as u8) => Ok(Self::AckPacket),
153 _ if value == (PacketSize::ExtendedPacket8 as u8) => Ok(Self::ExtendedPacket8),
154 _ if value == (PacketSize::ExtendedPacket16 as u8) => Ok(Self::ExtendedPacket16),
155 _ if value == (PacketSize::ExtendedPacket32 as u8) => Ok(Self::ExtendedPacket32),
156 _ if value == (PacketSize::OutfoxRegularPacket as u8) => Ok(Self::OutfoxRegularPacket),
157 _ if value == (PacketSize::OutfoxAckPacket as u8) => Ok(Self::OutfoxAckPacket),
158 v => Err(InvalidPacketSize::UnknownPacketTag { received: v }),
159 }
160 }
161}
162
163impl PacketSize {
164 pub const fn size(self) -> usize {
165 #[allow(unreachable_patterns)]
166 match self {
167 #[cfg(feature = "sphinx")]
168 PacketSize::RegularPacket => REGULAR_PACKET_SIZE,
169 #[cfg(feature = "sphinx")]
170 PacketSize::AckPacket => ACK_PACKET_SIZE,
171 #[cfg(feature = "sphinx")]
172 PacketSize::ExtendedPacket8 => EXTENDED_PACKET_SIZE_8,
173 #[cfg(feature = "sphinx")]
174 PacketSize::ExtendedPacket16 => EXTENDED_PACKET_SIZE_16,
175 #[cfg(feature = "sphinx")]
176 PacketSize::ExtendedPacket32 => EXTENDED_PACKET_SIZE_32,
177 #[cfg(feature = "outfox")]
178 PacketSize::OutfoxRegularPacket => OUTFOX_REGULAR_PACKET_SIZE,
179 #[cfg(feature = "outfox")]
180 PacketSize::OutfoxAckPacket => OUTFOX_ACK_PACKET_SIZE,
181 _ => 0,
182 }
183 }
184
185 pub const fn header_size(&self) -> usize {
186 #[allow(unreachable_patterns)]
187 match self {
188 #[cfg(feature = "sphinx")]
189 PacketSize::RegularPacket
190 | PacketSize::AckPacket
191 | PacketSize::ExtendedPacket8
192 | PacketSize::ExtendedPacket16
193 | PacketSize::ExtendedPacket32 => HEADER_SIZE,
194 #[cfg(feature = "outfox")]
195 PacketSize::OutfoxRegularPacket | PacketSize::OutfoxAckPacket => MIX_PARAMS_LEN,
196 _ => 0,
197 }
198 }
199
200 pub const fn payload_overhead(&self) -> usize {
201 #[allow(unreachable_patterns)]
202 match self {
203 #[cfg(feature = "sphinx")]
204 PacketSize::RegularPacket
205 | PacketSize::AckPacket
206 | PacketSize::ExtendedPacket8
207 | PacketSize::ExtendedPacket16
208 | PacketSize::ExtendedPacket32 => PAYLOAD_OVERHEAD_SIZE,
209 #[cfg(feature = "outfox")]
210 PacketSize::OutfoxRegularPacket | PacketSize::OutfoxAckPacket => {
211 OUTFOX_PACKET_OVERHEAD - MIX_PARAMS_LEN }
213 _ => 0,
214 }
215 }
216
217 pub const fn plaintext_size(self) -> usize {
218 self.size() - self.header_size() - self.payload_overhead()
219 }
220
221 pub const fn payload_size(self) -> usize {
222 self.size() - self.header_size()
223 }
224
225 pub fn get_type(size: usize) -> Result<Self, InvalidPacketSize> {
226 if PacketSize::RegularPacket.size() == size {
227 Ok(PacketSize::RegularPacket)
228 } else if PacketSize::AckPacket.size() == size {
229 Ok(PacketSize::AckPacket)
230 } else if PacketSize::ExtendedPacket8.size() == size {
231 Ok(PacketSize::ExtendedPacket8)
232 } else if PacketSize::ExtendedPacket16.size() == size {
233 Ok(PacketSize::ExtendedPacket16)
234 } else if PacketSize::ExtendedPacket32.size() == size {
235 Ok(PacketSize::ExtendedPacket32)
236 } else if PacketSize::OutfoxRegularPacket.size() == size
237 || PacketSize::OutfoxRegularPacket.size() == size + 6
238 {
239 Ok(PacketSize::OutfoxRegularPacket)
240 } else if PacketSize::OutfoxAckPacket.size() == size {
241 Ok(PacketSize::OutfoxAckPacket)
242 } else {
243 Err(InvalidPacketSize::UnknownPacketSize { received: size })
244 }
245 }
246
247 pub fn is_extended_size(&self) -> bool {
248 match self {
249 PacketSize::RegularPacket
250 | PacketSize::AckPacket
251 | PacketSize::OutfoxAckPacket
252 | PacketSize::OutfoxRegularPacket => false,
253 PacketSize::ExtendedPacket8
254 | PacketSize::ExtendedPacket16
255 | PacketSize::ExtendedPacket32 => true,
256 }
257 }
258
259 pub fn as_extended_size(self) -> Option<Self> {
260 if self.is_extended_size() {
261 Some(self)
262 } else {
263 None
264 }
265 }
266
267 pub fn get_type_from_plaintext(
268 plaintext_size: usize,
269 packet_type: PacketType,
270 ) -> Result<Self, InvalidPacketSize> {
271 #[allow(unreachable_patterns)]
272 let overhead = match packet_type {
273 #[cfg(feature = "sphinx")]
274 PacketType::Mix => SPHINX_PACKET_OVERHEAD,
275 #[cfg(feature = "outfox")]
276 PacketType::Outfox => OUTFOX_PACKET_OVERHEAD,
277 _ => 0,
278 };
279 let packet_size = plaintext_size + overhead;
280 Self::get_type(packet_size)
281 }
282}
283
284#[cfg(test)]
285mod tests {
286 use super::*;
287 use crate::AckEncryptionAlgorithm;
288 use nym_crypto::symmetric::stream_cipher::IvSizeUser;
289
290 #[test]
291 fn ack_iv_size_assertion() {
292 let iv_size = AckEncryptionAlgorithm::iv_size();
293 assert_eq!(iv_size, ACK_IV_SIZE);
294 }
295}