1use alloc::vec;
4use bytemuck::{Pod, PodCastError, Zeroable};
5use core::mem;
6use dryoc::classic::crypto_sign::crypto_sign_open;
7
8use crate::{Entry, Error, HeaderFlags, PublicKey, ENTRY_SIZE, HEADER_SIZE};
9
10#[derive(Clone, Copy, Debug, Pod, Zeroable)]
11#[repr(packed, C)]
12pub struct Header {
13 pub signature: [u8; 64],
15 pub public_key: [u8; 32],
17 pub blake3: [u8; 32],
19 pub count: u32,
21 pub flags: HeaderFlags,
23}
24
25impl Header {
26 pub fn new<'a>(data: &'a [u8], public_key: &PublicKey) -> Result<&'a Header, Error> {
28 let signed = data
30 .get(..mem::size_of::<Header>())
31 .ok_or(Error::Cast(PodCastError::SizeMismatch))?;
32
33 let mut verified = vec![0; signed.len() - 64];
35 crypto_sign_open(&mut verified, signed, public_key)?;
36
37 if verified.as_slice() != &signed[64..] {
39 return Err(Error::InvalidData);
40 }
41
42 let header: &Header = unsafe { Header::new_unchecked(signed)? };
44 if header.public_key != public_key.as_ref()[..] {
45 return Err(Error::InvalidKey);
46 }
47
48 Ok(header)
49 }
50
51 pub unsafe fn new_unchecked(data: &[u8]) -> Result<&Header, Error> {
53 Ok(bytemuck::try_from_bytes(data)?)
54 }
55
56 pub fn count(&self) -> u32 {
57 self.count
58 }
59
60 pub fn entries_size(&self) -> Result<usize, Error> {
62 (self.count as usize)
63 .checked_mul(ENTRY_SIZE)
64 .ok_or(Error::Overflow)
65 }
66
67 pub fn total_size(&self) -> Result<usize, Error> {
69 self.entries_size()?
70 .checked_add(HEADER_SIZE)
71 .ok_or(Error::Overflow)
72 }
73
74 pub fn entries<'a>(&self, data: &'a [u8]) -> Result<&'a [Entry], Error> {
76 let entries_size = self.entries_size()?;
77
78 let entries_data = data
79 .get(..entries_size)
80 .ok_or(Error::Cast(PodCastError::SizeMismatch))?;
81
82 let hash = {
83 let mut hasher = blake3::Hasher::new();
84 hasher.update_rayon(entries_data);
85 hasher.finalize()
86 };
87
88 if &self.blake3 != hash.as_bytes() {
89 return Err(Error::InvalidBlake3);
90 }
91
92 unsafe { Self::entries_unchecked(entries_data) }
93 }
94
95 pub unsafe fn entries_unchecked(data: &[u8]) -> Result<&[Entry], Error> {
97 Ok(bytemuck::try_cast_slice(data)?)
98 }
99}
100