lllv_core/
header.rs

1use crate::{
2    errors::LllvError,
3    version::{CAP_MAGIC, CAP_VER, HEADER_LEN},
4};
5
6#[derive(Copy, Clone, Debug, PartialEq)]
7pub struct CapsuleHeader {
8    pub magic: u16,    // 2
9    pub ver: u8,       // 1
10    pub flags: u8,     // 1
11    pub ts_ms: u64,    // 8
12    pub cid: [u8; 32], // 32 (blake3(payload))
13    pub dim: u16,      // 2
14    pub len: u32,      // 4 (payload bytes)
15    pub sig: [u8; 64], // 64 (ed25519(header_wo_sig||payload))
16}
17
18bitflags::bitflags! {
19    #[derive(Default)]
20    pub struct CapsuleFlags: u8 {
21        const NONE       = 0b0000_0000;
22        const ENCRYPTED  = 0b0000_0001; // payload = nonce(12) || ciphertext
23        const RECEIPTREQ = 0b0000_0010; // reserva
24    }
25}
26
27impl CapsuleHeader {
28    pub fn empty(dim: u16, flags: CapsuleFlags, cid: [u8; 32], len: u32, ts_ms: u64) -> Self {
29        Self {
30            magic: CAP_MAGIC,
31            ver: CAP_VER,
32            flags: flags.bits(),
33            ts_ms,
34            cid,
35            dim,
36            len,
37            sig: [0u8; 64],
38        }
39    }
40
41    pub fn to_bytes_wo_sig(&self) -> [u8; HEADER_LEN - 64] {
42        let mut out = [0u8; HEADER_LEN - 64];
43        let mut i = 0usize;
44        out[i..i + 2].copy_from_slice(&self.magic.to_le_bytes());
45        i += 2;
46        out[i..i + 1].copy_from_slice(&[self.ver]);
47        i += 1;
48        out[i..i + 1].copy_from_slice(&[self.flags]);
49        i += 1;
50        out[i..i + 8].copy_from_slice(&self.ts_ms.to_le_bytes());
51        i += 8;
52        out[i..i + 32].copy_from_slice(&self.cid);
53        i += 32;
54        out[i..i + 2].copy_from_slice(&self.dim.to_le_bytes());
55        i += 2;
56        out[i..i + 4].copy_from_slice(&self.len.to_le_bytes());
57        i += 4;
58        debug_assert_eq!(i, HEADER_LEN - 64);
59        out
60    }
61
62    pub fn to_bytes(&self) -> [u8; HEADER_LEN] {
63        let mut out = [0u8; HEADER_LEN];
64        let (head, tail) = out.split_at_mut(HEADER_LEN - 64);
65        head.copy_from_slice(&self.to_bytes_wo_sig());
66        tail.copy_from_slice(&self.sig);
67        out
68    }
69
70    pub fn from_bytes(raw: &[u8]) -> Result<Self, LllvError> {
71        if raw.len() < HEADER_LEN {
72            return Err(LllvError::InvalidHeaderLen);
73        }
74        let mut i = 0usize;
75        let magic = u16::from_le_bytes(raw[i..i + 2].try_into().unwrap());
76        i += 2;
77        let ver = raw[i];
78        i += 1;
79        let flags = raw[i];
80        i += 1;
81        let ts_ms = u64::from_le_bytes(raw[i..i + 8].try_into().unwrap());
82        i += 8;
83        let mut cid = [0u8; 32];
84        cid.copy_from_slice(&raw[i..i + 32]);
85        i += 32;
86        let dim = u16::from_le_bytes(raw[i..i + 2].try_into().unwrap());
87        i += 2;
88        let len = u32::from_le_bytes(raw[i..i + 4].try_into().unwrap());
89        i += 4;
90        let mut sig = [0u8; 64];
91        sig.copy_from_slice(&raw[i..i + 64]);
92
93        if magic != CAP_MAGIC {
94            return Err(LllvError::InvalidMagic);
95        }
96        if ver != CAP_VER {
97            return Err(LllvError::InvalidVersion);
98        }
99
100        Ok(Self {
101            magic,
102            ver,
103            flags,
104            ts_ms,
105            cid,
106            dim,
107            len,
108            sig,
109        })
110    }
111}