Skip to main content

crypto/
bytes.rs

1use constant_time_eq::constant_time_eq;
2
3/// A fixed-capacity, stack-allocated bytes buffer of capacity `N`.
4/// Use [`Self::as_ref`] to get the bytes as a `&[u8]` and [`Self::as_mut`] to get the bytes as a `&mut [u8]`.
5/// Comparing `Bytes` is a constant-time operation.
6#[cfg_attr(feature = "zeroize", derive(zeroize::Zeroize, zeroize::ZeroizeOnDrop))]
7pub struct Bytes<const N: usize> {
8    bytes: [u8; N],
9    length: u16,
10}
11
12impl<const N: usize> Bytes<N> {
13    #[inline]
14    pub(crate) fn new() -> Bytes<N> {
15        assert!(N <= u16::MAX as usize);
16        return Bytes {
17            bytes: [0u8; N],
18            length: 0,
19        };
20    }
21
22    #[inline]
23    pub(crate) fn with_length(length: usize) -> Bytes<N> {
24        assert!(N <= u16::MAX as usize && length <= u16::MAX as usize);
25        assert!(length <= N, "length exceeds capacity");
26        return Bytes {
27            bytes: [0u8; N],
28            length: length as u16,
29        };
30    }
31
32    #[inline]
33    pub fn len(&self) -> usize {
34        return self.length as usize;
35    }
36
37    pub(crate) fn push(&mut self, byte: u8) {
38        assert!(self.length as usize + 1 <= N);
39        self.bytes[self.length as usize] = byte;
40        self.length += 1;
41    }
42
43    pub(crate) fn append(&mut self, data: &[u8]) {
44        assert!(self.length as usize + data.len() <= N);
45        self.bytes[self.length as usize..data.len() + self.length as usize].copy_from_slice(data);
46        self.length += data.len() as u16;
47    }
48}
49
50impl<const N: usize> PartialEq for Bytes<N> {
51    #[inline]
52    fn eq(&self, other: &Self) -> bool {
53        constant_time_eq(self.as_ref(), other.as_ref())
54    }
55}
56
57impl<const N: usize> Eq for Bytes<N> {}
58
59impl<const N: usize> AsRef<[u8]> for Bytes<N> {
60    #[inline]
61    fn as_ref(&self) -> &[u8] {
62        &self.bytes[..self.length as usize]
63    }
64}
65
66impl<const N: usize> AsMut<[u8]> for Bytes<N> {
67    #[inline]
68    fn as_mut(&mut self) -> &mut [u8] {
69        &mut self.bytes[..self.length as usize]
70    }
71}