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#[derive(Clone)]
7#[cfg_attr(feature = "zeroize", derive(zeroize::Zeroize, zeroize::ZeroizeOnDrop))]
8pub struct Bytes<const N: usize> {
9    bytes: [u8; N],
10    length: u16,
11}
12
13impl<const N: usize> Bytes<N> {
14    #[inline]
15    pub(crate) fn new() -> Bytes<N> {
16        assert!(N <= u16::MAX as usize);
17        return Bytes {
18            bytes: [0u8; N],
19            length: 0,
20        };
21    }
22
23    #[inline]
24    pub fn len(&self) -> usize {
25        return self.length as usize;
26    }
27
28    #[inline]
29    pub(crate) fn with_length(length: usize) -> Bytes<N> {
30        assert!(N <= u16::MAX as usize && length <= u16::MAX as usize);
31        assert!(length <= N, "length exceeds capacity");
32        return Bytes {
33            bytes: [0u8; N],
34            length: length as u16,
35        };
36    }
37
38    pub(crate) fn push(&mut self, byte: u8) {
39        assert!(self.length as usize + 1 <= N);
40        self.bytes[self.length as usize] = byte;
41        self.length += 1;
42    }
43
44    pub(crate) fn append(&mut self, data: &[u8]) {
45        assert!(self.length as usize + data.len() <= N);
46        self.bytes[self.length as usize..data.len() + self.length as usize].copy_from_slice(data);
47        self.length += data.len() as u16;
48    }
49}
50
51impl<const N: usize> PartialEq for Bytes<N> {
52    #[inline]
53    fn eq(&self, other: &Self) -> bool {
54        constant_time_eq(self.as_ref(), other.as_ref())
55    }
56}
57
58impl<const N: usize> Eq for Bytes<N> {}
59
60impl<const N: usize> AsRef<[u8]> for Bytes<N> {
61    #[inline]
62    fn as_ref(&self) -> &[u8] {
63        &self.bytes[..self.length as usize]
64    }
65}
66
67impl<const N: usize> AsMut<[u8]> for Bytes<N> {
68    #[inline]
69    fn as_mut(&mut self) -> &mut [u8] {
70        &mut self.bytes[..self.length as usize]
71    }
72}
73
74/// A stack-allocated bytes buffer.
75/// Use [`Self::as_ref`] to get the bytes as a `&[u8]` and [`Self::as_mut`] to get the bytes as a `&mut [u8]`.
76/// Comparing `Hash` is a constant-time operation.
77#[derive(Clone)]
78#[repr(transparent)]
79#[cfg_attr(feature = "zeroize", derive(zeroize::Zeroize, zeroize::ZeroizeOnDrop))]
80pub struct Hash(pub(crate) Bytes<64>);
81
82/// A stack-allocated bytes buffer.
83/// Use [`Self::as_ref`] to get the bytes as a `&[u8]` and [`Self::as_mut`] to get the bytes as a `&mut [u8]`.
84/// Comparing `Tag` is a constant-time operation.
85#[derive(Clone)]
86#[repr(transparent)]
87#[cfg_attr(feature = "zeroize", derive(zeroize::Zeroize, zeroize::ZeroizeOnDrop))]
88pub struct Tag(pub(crate) Bytes<32>);
89
90/// implement the required public methods for `Type` to be used as a bytes buffer.
91macro_rules! impl_bytes {
92    ($name:ident($inner:ty)) => {
93        impl $name {
94            #[inline]
95            pub fn len(&self) -> usize {
96                self.0.len()
97            }
98        }
99
100        impl AsRef<[u8]> for $name {
101            #[inline]
102            fn as_ref(&self) -> &[u8] {
103                self.0.as_ref()
104            }
105        }
106
107        impl AsMut<[u8]> for $name {
108            #[inline]
109            fn as_mut(&mut self) -> &mut [u8] {
110                self.0.as_mut()
111            }
112        }
113
114        impl PartialEq for $name {
115            #[inline]
116            fn eq(&self, other: &Self) -> bool {
117                self.0 == other.0
118            }
119        }
120
121        impl Eq for $name {}
122    };
123}
124
125impl_bytes!(Tag(Bytes<32>));
126impl_bytes!(Hash(Bytes<64>));