1use constant_time_eq::constant_time_eq;
2
3use crate::{HashError, MAX_HASH_OUTPUT_SIZE};
4
5#[derive(Copy, Clone)]
9#[cfg_attr(feature = "zeroize", derive(zeroize::Zeroize))]
10pub(crate) struct Bytes<const N: usize> {
11 pub(crate) bytes: [u8; N],
12 pub(crate) length: u16,
13}
14
15impl<const N: usize> Bytes<N> {
16 #[inline]
17 pub(crate) fn new() -> Bytes<N> {
18 assert!(N <= u16::MAX as usize);
19 return Bytes {
20 bytes: [0u8; N],
21 length: 0,
22 };
23 }
24
25 #[inline]
26 pub fn len(&self) -> usize {
27 return self.length as usize;
28 }
29
30 #[inline]
31 pub(crate) fn with_length(length: usize) -> Bytes<N> {
32 assert!(N <= u16::MAX as usize && length <= u16::MAX as usize);
33 assert!(length <= N, "length exceeds capacity");
34 return Bytes {
35 bytes: [0u8; N],
36 length: length as u16,
37 };
38 }
39
40 #[inline]
41 pub(crate) fn push(&mut self, byte: u8) {
42 assert!(self.length as usize + 1 <= N);
43 self.bytes[self.length as usize] = byte;
44 self.length += 1;
45 }
46
47 #[inline]
48 pub(crate) fn append(&mut self, data: &[u8]) {
49 assert!(self.length as usize + data.len() <= N);
50 self.bytes[self.length as usize..data.len() + self.length as usize].copy_from_slice(data);
51 self.length += data.len() as u16;
52 }
53}
54
55impl<const N: usize, const L: usize> From<[u8; L]> for Bytes<N> {
56 #[inline]
57 fn from(data: [u8; L]) -> Self {
58 const {
59 assert!(L <= N);
60 }
61
62 let mut bytes = [0u8; N];
63 bytes[..L].copy_from_slice(&data);
64
65 Bytes {
66 bytes,
67 length: L as u16,
68 }
69 }
70}
71
72impl<const N: usize, const L: usize> From<&[u8; L]> for Bytes<N> {
73 #[inline]
74 fn from(data: &[u8; L]) -> Self {
75 const {
76 assert!(L <= N);
77 }
78
79 let mut bytes = [0u8; N];
80 bytes[..L].copy_from_slice(data);
81
82 Bytes {
83 bytes,
84 length: L as u16,
85 }
86 }
87}
88
89impl<const N: usize> PartialEq for Bytes<N> {
90 #[inline]
91 fn eq(&self, other: &Self) -> bool {
92 constant_time_eq(self, other)
93 }
94}
95
96impl<const N: usize> Eq for Bytes<N> {}
97
98impl<const N: usize> core::ops::Deref for Bytes<N> {
99 type Target = [u8];
100 fn deref(&self) -> &[u8] {
101 &self.bytes[..self.length as usize]
102 }
103}
104
105impl<const N: usize> AsMut<[u8]> for Bytes<N> {
106 #[inline]
107 fn as_mut(&mut self) -> &mut [u8] {
108 &mut self.bytes[..self.length as usize]
109 }
110}
111
112#[derive(Copy, Clone)]
116#[repr(transparent)]
117#[cfg_attr(feature = "zeroize", derive(zeroize::Zeroize))]
118pub struct Hash(pub(crate) Bytes<MAX_HASH_OUTPUT_SIZE>);
119
120macro_rules! impl_bytes {
122 ($name:ident($inner:ty)) => {
123 impl $name {
124 #[inline]
125 pub fn len(&self) -> usize {
126 self.0.len()
127 }
128 }
129
130 impl AsRef<[u8]> for $name {
131 #[inline]
132 fn as_ref(&self) -> &[u8] {
133 self.0.as_ref()
134 }
135 }
136
137 impl core::ops::Deref for $name {
138 type Target = [u8];
139 fn deref(&self) -> &[u8] {
140 &self.0
141 }
142 }
143
144 impl AsMut<[u8]> for $name {
145 #[inline]
146 fn as_mut(&mut self) -> &mut [u8] {
147 self.0.as_mut()
148 }
149 }
150
151 impl PartialEq for $name {
152 #[inline]
153 fn eq(&self, other: &Self) -> bool {
154 self.0 == other.0
155 }
156 }
157
158 impl Eq for $name {}
159 };
160}
161
162impl_bytes!(Hash(Bytes<MAX_HASH_OUTPUT_SIZE>));
163
164impl<const L: usize> From<[u8; L]> for Hash {
165 #[inline]
166 fn from(bytes: [u8; L]) -> Self {
167 const {
168 assert!(L <= MAX_HASH_OUTPUT_SIZE);
169 }
170
171 return Hash(Bytes::<MAX_HASH_OUTPUT_SIZE>::from(bytes));
172 }
173}
174
175impl<const L: usize> From<&[u8; L]> for Hash {
176 #[inline]
177 fn from(bytes: &[u8; L]) -> Self {
178 const {
179 assert!(L <= MAX_HASH_OUTPUT_SIZE);
180 }
181
182 return Hash(Bytes::<MAX_HASH_OUTPUT_SIZE>::from(bytes));
183 }
184}
185
186impl TryFrom<&[u8]> for Hash {
187 type Error = HashError;
188
189 #[inline]
190 fn try_from(bytes: &[u8]) -> Result<Self, Self::Error> {
191 if bytes.len() > MAX_HASH_OUTPUT_SIZE {
192 return Err(HashError::TooLong);
193 }
194
195 let mut buffer = Bytes::<MAX_HASH_OUTPUT_SIZE>::new();
196 buffer.append(bytes);
197 return Ok(Hash(buffer));
198 }
199}