1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
use crate::Error;
#[cfg(not(feature = "with_serde"))]
use alloc::vec::Vec;
#[cfg(not(feature = "with_serde"))]
use binary_sv2::binary_codec_sv2;
use binary_sv2::{Deserialize, Serialize, U24};
use const_sv2::{AEAD_MAC_LEN, SV2_FRAME_CHUNK_SIZE};
use core::convert::TryInto;

/// Abstraction for a SV2 Frame Header.
#[derive(Debug, Serialize, Deserialize, Copy, Clone)]
pub struct Header {
    extension_type: u16, // TODO use specific type?
    msg_type: u8,        // TODO use specific type?
    msg_length: U24,
}

impl Default for Header {
    fn default() -> Self {
        Header {
            extension_type: 0,
            msg_type: 0,
            // converting 0_32 into a U24 never panic
            msg_length: 0_u32.try_into().unwrap(),
        }
    }
}

impl Header {
    pub const LEN_OFFSET: usize = const_sv2::SV2_FRAME_HEADER_LEN_OFFSET;
    pub const LEN_SIZE: usize = const_sv2::SV2_FRAME_HEADER_LEN_END;
    pub const LEN_END: usize = Self::LEN_OFFSET + Self::LEN_SIZE;

    pub const SIZE: usize = const_sv2::SV2_FRAME_HEADER_SIZE;

    /// Construct a `Header` from ray bytes
    #[inline]
    pub fn from_bytes(bytes: &[u8]) -> Result<Self, Error> {
        if bytes.len() < Self::SIZE {
            return Err(Error::UnexpectedHeaderLength(
                (Self::SIZE - bytes.len()) as isize,
            ));
        };

        let extension_type = u16::from_le_bytes([bytes[0], bytes[1]]);
        let msg_type = bytes[2];
        let msg_length = u32::from_le_bytes([bytes[3], bytes[4], bytes[5], 0]);

        Ok(Self {
            extension_type,
            msg_type,
            // Converting and u32 with the most significant byte set to 0 to and U24 never panic
            msg_length: msg_length.try_into().unwrap(),
        })
    }

    /// Get the payload length
    #[allow(clippy::len_without_is_empty)]
    #[inline]
    pub fn len(&self) -> usize {
        let inner: u32 = self.msg_length.into();
        inner as usize
    }

    /// Construct a `Header` from payload length, type and extension type.
    #[inline]
    pub fn from_len(len: u32, message_type: u8, extension_type: u16) -> Option<Header> {
        Some(Self {
            extension_type,
            msg_type: message_type,
            msg_length: len.try_into().ok()?,
        })
    }

    /// Get the `Header` message type.
    pub fn msg_type(&self) -> u8 {
        self.msg_type
    }

    /// Get the `Header` extension type.
    pub fn ext_type(&self) -> u16 {
        self.extension_type
    }

    /// Check if `Header` represents a channel message
    pub fn channel_msg(&self) -> bool {
        let mask = 0b0000_0000_0000_0001;
        self.extension_type & mask == self.extension_type
    }

    /// Calculate the length of the encrypted `Header`
    pub fn encrypted_len(&self) -> usize {
        let len = self.len();
        let mut chunks = len / (SV2_FRAME_CHUNK_SIZE - AEAD_MAC_LEN);
        if len % (SV2_FRAME_CHUNK_SIZE - AEAD_MAC_LEN) != 0 {
            chunks += 1;
        }
        let mac_len = chunks * AEAD_MAC_LEN;
        len + mac_len
    }
}

pub struct NoiseHeader {}

impl NoiseHeader {
    pub const SIZE: usize = const_sv2::ENCRYPTED_SV2_FRAME_HEADER_SIZE;
    pub const LEN_OFFSET: usize = const_sv2::NOISE_FRAME_HEADER_LEN_OFFSET;
    pub const HEADER_SIZE: usize = const_sv2::NOISE_FRAME_HEADER_SIZE;
}