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(Copy, Clone)]
7pub(crate) struct Bytes<const N: usize> {
8    pub(crate) bytes: [u8; N],
9    pub(crate) 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 fn len(&self) -> usize {
24        return self.length as usize;
25    }
26
27    #[inline]
28    pub(crate) fn with_length(length: usize) -> Bytes<N> {
29        assert!(N <= u16::MAX as usize && length <= u16::MAX as usize);
30        assert!(length <= N, "length exceeds capacity");
31        return Bytes {
32            bytes: [0u8; N],
33            length: length as u16,
34        };
35    }
36
37    #[inline]
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    #[inline]
45    pub(crate) fn append(&mut self, data: &[u8]) {
46        assert!(self.length as usize + data.len() <= N);
47        self.bytes[self.length as usize..data.len() + self.length as usize].copy_from_slice(data);
48        self.length += data.len() as u16;
49    }
50}
51
52impl<const N: usize, const L: usize> From<[u8; L]> for Bytes<N> {
53    #[inline]
54    fn from(data: [u8; L]) -> Self {
55        const {
56            assert!(L <= N);
57        }
58
59        let mut bytes = [0u8; N];
60        bytes[..L].copy_from_slice(&data);
61
62        Bytes {
63            bytes,
64            length: L as u16,
65        }
66    }
67}
68
69impl<const N: usize, const L: usize> From<&[u8; L]> for Bytes<N> {
70    #[inline]
71    fn from(data: &[u8; L]) -> Self {
72        const {
73            assert!(L <= N);
74        }
75
76        let mut bytes = [0u8; N];
77        bytes[..L].copy_from_slice(data);
78
79        Bytes {
80            bytes,
81            length: L as u16,
82        }
83    }
84}
85
86impl<const N: usize> PartialEq for Bytes<N> {
87    #[inline]
88    fn eq(&self, other: &Self) -> bool {
89        constant_time_eq(&self, &other)
90    }
91}
92
93impl<const N: usize> Eq for Bytes<N> {}
94
95impl<const N: usize> core::ops::Deref for Bytes<N> {
96    type Target = [u8];
97    fn deref(&self) -> &[u8] {
98        &self.bytes[..self.length as usize]
99    }
100}
101
102impl<const N: usize> AsMut<[u8]> for Bytes<N> {
103    #[inline]
104    fn as_mut(&mut self) -> &mut [u8] {
105        &mut self.bytes[..self.length as usize]
106    }
107}
108
109/// A stack-allocated bytes buffer.
110/// Use [`Self::as_ref`] to get the bytes as a `&[u8]` and [`Self::as_mut`] to get the bytes as a `&mut [u8]`.
111/// Comparing `Hash` is a constant-time operation.
112#[derive(Copy, Clone)]
113#[repr(transparent)]
114pub struct Hash(pub(crate) Bytes<64>);
115
116/// implement the required public methods for `Type` to be used as a bytes buffer.
117macro_rules! impl_bytes {
118    ($name:ident($inner:ty)) => {
119        impl $name {
120            #[inline]
121            pub fn len(&self) -> usize {
122                self.0.len()
123            }
124        }
125
126        impl AsRef<[u8]> for $name {
127            #[inline]
128            fn as_ref(&self) -> &[u8] {
129                self.0.as_ref()
130            }
131        }
132
133        impl core::ops::Deref for $name {
134            type Target = [u8];
135            fn deref(&self) -> &[u8] {
136                &self.0
137            }
138        }
139
140        impl AsMut<[u8]> for $name {
141            #[inline]
142            fn as_mut(&mut self) -> &mut [u8] {
143                self.0.as_mut()
144            }
145        }
146
147        impl PartialEq for $name {
148            #[inline]
149            fn eq(&self, other: &Self) -> bool {
150                self.0 == other.0
151            }
152        }
153
154        impl Eq for $name {}
155    };
156}
157
158impl_bytes!(Hash(Bytes<64>));