lllv_core/
capsule.rs

1#[cfg(not(feature = "std"))]
2use alloc::vec::Vec;
3#[cfg(feature = "std")]
4use std::vec::Vec;
5
6use crate::{
7    errors::LllvError,
8    header::{CapsuleFlags, CapsuleHeader},
9    version::HEADER_LEN,
10};
11use blake3::hash;
12use ed25519_dalek::{Signature, Signer, SigningKey, VerifyingKey};
13
14#[derive(Clone, Debug)]
15pub struct Capsule {
16    pub header: CapsuleHeader,
17    pub payload: Vec<u8>,
18}
19
20impl Capsule {
21    pub fn create(
22        dim: u16,
23        payload: &[u8],
24        flags: CapsuleFlags,
25        sk: &SigningKey,
26    ) -> Result<Self, LllvError> {
27        let cid = *hash(payload).as_bytes();
28        #[cfg(feature = "std")]
29        let ts_ms = (std::time::SystemTime::now()
30            .duration_since(std::time::UNIX_EPOCH)
31            .unwrap()
32            .as_millis()) as u64;
33        #[cfg(not(feature = "std"))]
34        let ts_ms = 0u64; // TODO: usar clock externo em no_std
35        let len = u32::try_from(payload.len()).map_err(|_| LllvError::MismatchedLengths)?;
36        let mut header = CapsuleHeader::empty(dim, flags, cid, len, ts_ms);
37
38        // sign(header_without_sig || payload)
39        let mut to_sign = Vec::with_capacity(HEADER_LEN - 64 + payload.len());
40        to_sign.extend_from_slice(&header.to_bytes_wo_sig());
41        to_sign.extend_from_slice(payload);
42
43        let sig: Signature = sk.sign(&to_sign);
44        header.sig.copy_from_slice(&sig.to_bytes());
45
46        Ok(Self {
47            header,
48            payload: payload.to_vec(),
49        })
50    }
51
52    pub fn to_bytes(&self) -> Vec<u8> {
53        let mut v = Vec::with_capacity(HEADER_LEN + self.payload.len());
54        v.extend_from_slice(&self.header.to_bytes());
55        v.extend_from_slice(&self.payload);
56        v
57    }
58
59    pub fn from_bytes(raw: &[u8]) -> Result<Self, LllvError> {
60        let header = CapsuleHeader::from_bytes(raw)?;
61        let payload = raw[HEADER_LEN..].to_vec();
62        if payload.len() != header.len as usize {
63            return Err(LllvError::MismatchedLengths);
64        }
65        Ok(Self { header, payload })
66    }
67
68    /// Verifica **integridade** (CID cobre payload). Não verifica autoria.
69    pub fn verify_cid(&self) -> Result<(), LllvError> {
70        let cid_now = *hash(&self.payload).as_bytes();
71        if cid_now != self.header.cid {
72            return Err(LllvError::BadSignature);
73        }
74        Ok(())
75    }
76
77    /// Verifica **integridade e autenticidade** com a chave pública.
78    pub fn verify_with(&self, pk: &VerifyingKey) -> Result<(), LllvError> {
79        self.verify_cid()?;
80        let mut to_verify = Vec::with_capacity(HEADER_LEN - 64 + self.payload.len());
81        to_verify.extend_from_slice(&self.header.to_bytes_wo_sig());
82        to_verify.extend_from_slice(&self.payload);
83
84        let sig = ed25519_dalek::Signature::from_bytes(&self.header.sig);
85        pk.verify_strict(&to_verify, &sig)
86            .map_err(|_| LllvError::BadSignature)
87    }
88
89    #[deprecated(
90        since = "0.1.0",
91        note = "use verify_with(&pk) para autenticidade ou verify_cid() para integridade"
92    )]
93    pub fn verify(&self) -> Result<(), LllvError> {
94        self.verify_cid()
95    }
96}