1use crate::ChannelId;
4use alloc::vec::Vec;
5
6pub const DERIVATION_VERSION_0: u8 = 0;
8
9pub const FRAME_OVERHEAD: usize = 200;
11
12pub const MAX_FRAME_LEN: usize = 1_000_000;
17
18#[derive(Debug, thiserror::Error, Clone, Copy, PartialEq, Eq, Hash)]
20pub enum FrameDecodingError {
21 #[error("Frame data too large: {0} bytes")]
23 DataTooLarge(usize),
24 #[error("Frame data too short: {0} bytes")]
26 DataTooShort(usize),
27 #[error("Invalid frame id")]
29 InvalidId,
30 #[error("Invalid frame number")]
32 InvalidNumber,
33 #[error("Invalid frame data length")]
35 InvalidDataLength,
36}
37
38#[derive(Debug, thiserror::Error, Clone, Copy, PartialEq, Eq, Hash)]
40pub enum FrameParseError {
41 #[error("Frame decoding error: {0}")]
43 FrameDecodingError(FrameDecodingError),
44 #[error("No frames to parse")]
46 NoFrames,
47 #[error("Unsupported derivation version")]
49 UnsupportedVersion,
50 #[error("Frame data length mismatch")]
52 DataLengthMismatch,
53 #[error("No frames decoded")]
55 NoFramesDecoded,
56}
57
58#[derive(Debug, Clone, PartialEq, Eq, Default)]
68pub struct Frame {
69 pub id: ChannelId,
71 pub number: u16,
73 pub data: Vec<u8>,
75 pub is_last: bool,
77}
78
79impl Frame {
80 pub const fn new(id: ChannelId, number: u16, data: Vec<u8>, is_last: bool) -> Self {
82 Self { id, number, data, is_last }
83 }
84
85 pub fn encode(&self) -> Vec<u8> {
87 let mut encoded = Vec::with_capacity(16 + 2 + 4 + self.data.len() + 1);
88 encoded.extend_from_slice(&self.id);
89 encoded.extend_from_slice(&self.number.to_be_bytes());
90 encoded.extend_from_slice(&(self.data.len() as u32).to_be_bytes());
91 encoded.extend_from_slice(&self.data);
92 encoded.push(self.is_last as u8);
93 encoded
94 }
95
96 pub fn decode(encoded: &[u8]) -> Result<(usize, Self), FrameDecodingError> {
98 const BASE_FRAME_LEN: usize = 16 + 2 + 4 + 1;
99
100 if encoded.len() < BASE_FRAME_LEN {
101 return Err(FrameDecodingError::DataTooShort(encoded.len()));
102 }
103
104 let id = encoded[..16].try_into().map_err(|_| FrameDecodingError::InvalidId)?;
105 let number = u16::from_be_bytes(
106 encoded[16..18].try_into().map_err(|_| FrameDecodingError::InvalidNumber)?,
107 );
108 let data_len = u32::from_be_bytes(
109 encoded[18..22].try_into().map_err(|_| FrameDecodingError::InvalidDataLength)?,
110 ) as usize;
111
112 if data_len > MAX_FRAME_LEN || data_len >= encoded.len() - (BASE_FRAME_LEN - 1) {
113 return Err(FrameDecodingError::DataTooLarge(data_len));
114 }
115
116 let data = encoded[22..22 + data_len].to_vec();
117 let is_last = encoded[22 + data_len] == 1;
118 Ok((BASE_FRAME_LEN + data_len, Self { id, number, data, is_last }))
119 }
120
121 pub fn parse_frame(data: &[u8], start: usize) -> Result<(usize, Self), FrameDecodingError> {
124 let (frame_len, frame) = Self::decode(&data[start..])?;
125 Ok((frame_len, frame))
126 }
127
128 pub fn parse_frames(encoded: &[u8]) -> Result<Vec<Self>, FrameParseError> {
137 if encoded.is_empty() {
138 return Err(FrameParseError::NoFrames);
139 }
140 if encoded[0] != DERIVATION_VERSION_0 {
141 return Err(FrameParseError::UnsupportedVersion);
142 }
143
144 let data = &encoded[1..];
145 let mut frames = Vec::new();
146 let mut offset = 0;
147 while offset < data.len() {
148 let (frame_length, frame) =
149 Self::decode(&data[offset..]).map_err(FrameParseError::FrameDecodingError)?;
150 frames.push(frame);
151 offset += frame_length;
152 }
153
154 if offset != data.len() {
155 return Err(FrameParseError::DataLengthMismatch);
156 }
157 if frames.is_empty() {
158 return Err(FrameParseError::NoFramesDecoded);
159 }
160
161 Ok(frames)
162 }
163
164 pub fn size(&self) -> usize {
168 self.data.len() + FRAME_OVERHEAD
169 }
170}
171
172#[cfg(test)]
173mod test {
174 use super::*;
175 use alloc::vec;
176
177 #[test]
178 fn test_encode_frame_roundtrip() {
179 let frame = Frame { id: [0xFF; 16], number: 0xEE, data: vec![0xDD; 50], is_last: true };
180
181 let (_, frame_decoded) = Frame::decode(&frame.encode()).unwrap();
182 assert_eq!(frame, frame_decoded);
183 }
184
185 #[test]
186 fn test_data_too_short() {
187 let frame = Frame { id: [0xFF; 16], number: 0xEE, data: vec![0xDD; 22], is_last: true };
188 let err = Frame::decode(&frame.encode()[..22]).unwrap_err();
189 assert_eq!(err, FrameDecodingError::DataTooShort(22));
190 }
191
192 #[test]
193 fn test_decode_exceeds_max_data_len() {
194 let frame = Frame {
195 id: [0xFF; 16],
196 number: 0xEE,
197 data: vec![0xDD; MAX_FRAME_LEN + 1],
198 is_last: true,
199 };
200 let err = Frame::decode(&frame.encode()).unwrap_err();
201 assert_eq!(err, FrameDecodingError::DataTooLarge(MAX_FRAME_LEN + 1));
202 }
203
204 #[test]
205 fn test_decode_malicious_data_len() {
206 let frame = Frame { id: [0xFF; 16], number: 0xEE, data: vec![0xDD; 50], is_last: true };
207 let mut encoded = frame.encode();
208 let data_len = (encoded.len() - 22) as u32;
209 encoded[18..22].copy_from_slice(&data_len.to_be_bytes());
210
211 let err = Frame::decode(&encoded).unwrap_err();
212 assert_eq!(err, FrameDecodingError::DataTooLarge(encoded.len() - 22_usize));
213
214 let valid_data_len = (encoded.len() - 23) as u32;
215 encoded[18..22].copy_from_slice(&valid_data_len.to_be_bytes());
216 let (_, frame_decoded) = Frame::decode(&encoded).unwrap();
217 assert_eq!(frame, frame_decoded);
218 }
219
220 #[test]
221 fn test_decode_many() {
222 let frame = Frame { id: [0xFF; 16], number: 0xEE, data: vec![0xDD; 50], is_last: true };
223 let mut bytes = Vec::new();
224 bytes.extend_from_slice(&[DERIVATION_VERSION_0]);
225 (0..5).for_each(|_| {
226 bytes.extend_from_slice(&frame.encode());
227 });
228
229 let frames = Frame::parse_frames(bytes.as_slice()).unwrap();
230 assert_eq!(frames.len(), 5);
231 (0..5).for_each(|i| {
232 assert_eq!(frames[i], frame);
233 });
234 }
235}