Skip to main content

rns_embedded_core/
packet.rs

1use crate::{EmbeddedError, EmbeddedResult};
2use alloc::vec::Vec;
3
4const MAGIC: &[u8; 4] = b"RNE1";
5const VERSION: u8 = 0x01;
6const HEADER_LEN: usize = 14;
7pub const MAX_PAYLOAD_BYTES: usize = 1024 * 1024;
8
9#[derive(Debug, Clone, Eq, PartialEq)]
10pub struct PacketFrame {
11    pub kind: u8,
12    pub sequence: u32,
13    pub payload: Vec<u8>,
14}
15
16impl PacketFrame {
17    pub fn new(kind: u8, sequence: u32, payload: Vec<u8>) -> EmbeddedResult<Self> {
18        if payload.is_empty() || payload.len() > MAX_PAYLOAD_BYTES {
19            return Err(EmbeddedError::InvalidInput);
20        }
21        Ok(Self { kind, sequence, payload })
22    }
23}
24
25pub fn encode_frame(frame: &PacketFrame) -> EmbeddedResult<Vec<u8>> {
26    if frame.payload.is_empty() || frame.payload.len() > MAX_PAYLOAD_BYTES {
27        return Err(EmbeddedError::InvalidInput);
28    }
29    let payload_len_u32 =
30        u32::try_from(frame.payload.len()).map_err(|_| EmbeddedError::InvalidInput)?;
31
32    let mut out = Vec::with_capacity(HEADER_LEN + frame.payload.len());
33    out.extend_from_slice(MAGIC);
34    out.push(VERSION);
35    out.push(frame.kind);
36    out.extend_from_slice(&frame.sequence.to_le_bytes());
37    out.extend_from_slice(&payload_len_u32.to_le_bytes());
38    out.extend_from_slice(&frame.payload);
39    Ok(out)
40}
41
42pub fn decode_frame(bytes: &[u8]) -> EmbeddedResult<PacketFrame> {
43    if bytes.len() < HEADER_LEN {
44        return Err(EmbeddedError::InvalidInput);
45    }
46    if &bytes[0..4] != MAGIC {
47        return Err(EmbeddedError::IntegrityFailure);
48    }
49    if bytes[4] != VERSION {
50        return Err(EmbeddedError::Unsupported);
51    }
52    let kind = bytes[5];
53    let sequence = u32::from_le_bytes([bytes[6], bytes[7], bytes[8], bytes[9]]);
54    let payload_len = u32::from_le_bytes([bytes[10], bytes[11], bytes[12], bytes[13]]);
55    let payload_len = usize::try_from(payload_len).map_err(|_| EmbeddedError::InvalidInput)?;
56    if payload_len == 0 || payload_len > MAX_PAYLOAD_BYTES {
57        return Err(EmbeddedError::InvalidInput);
58    }
59    if bytes.len() != HEADER_LEN + payload_len {
60        return Err(EmbeddedError::InvalidInput);
61    }
62    let payload = bytes[HEADER_LEN..].to_vec();
63    PacketFrame::new(kind, sequence, payload)
64}
65
66#[cfg(test)]
67mod tests {
68    use super::{decode_frame, encode_frame, PacketFrame};
69    use serde::Deserialize;
70
71    #[derive(Debug, Deserialize)]
72    struct PacketFixture {
73        id: String,
74        kind: u8,
75        sequence: u32,
76        payload_hex: String,
77        encoded_hex: String,
78    }
79
80    #[test]
81    fn fixture_vectors_roundtrip() {
82        let fixtures: Vec<PacketFixture> = serde_json::from_str(include_str!(
83            "../../../../docs/fixtures/embedded/native_packet_vectors.json"
84        ))
85        .expect("fixture json parse");
86        for fixture in fixtures {
87            let payload = hex::decode(&fixture.payload_hex).expect("payload hex");
88            let expected = hex::decode(&fixture.encoded_hex).expect("encoded hex");
89
90            let frame = PacketFrame::new(fixture.kind, fixture.sequence, payload.clone())
91                .expect("frame init");
92            let encoded = encode_frame(&frame).expect("encode");
93            assert_eq!(encoded, expected, "fixture {} encode mismatch", fixture.id);
94
95            let decoded = decode_frame(&expected).expect("decode");
96            assert_eq!(decoded.kind, fixture.kind, "fixture {} kind mismatch", fixture.id);
97            assert_eq!(
98                decoded.sequence, fixture.sequence,
99                "fixture {} sequence mismatch",
100                fixture.id
101            );
102            assert_eq!(decoded.payload, payload, "fixture {} payload mismatch", fixture.id);
103        }
104    }
105
106    #[test]
107    fn rejects_truncated_frame() {
108        let bytes = vec![0_u8; 8];
109        assert!(decode_frame(&bytes).is_err());
110    }
111}