1macro_rules! blake2_impl {
2 (
3 $name:ident, $alg_name:expr, $word:ident, $vec:ident, $bytes:ident,
4 $block_size:ident, $R1:expr, $R2:expr, $R3:expr, $R4:expr, $IV:expr,
5 $vardoc:expr, $doc:expr,
6 ) => {
7 #[derive(Clone)]
8 #[doc=$vardoc]
9 pub struct $name {
10 h: [$vec; 2],
11 t: u64,
12 #[cfg(feature = "reset")]
13 h0: [$vec; 2],
14 }
15
16 impl $name {
17 #[inline(always)]
18 fn iv0() -> $vec {
19 $vec::new($IV[0], $IV[1], $IV[2], $IV[3])
20 }
21 #[inline(always)]
22 fn iv1() -> $vec {
23 $vec::new($IV[4], $IV[5], $IV[6], $IV[7])
24 }
25
26 pub fn new_with_params(
28 salt: &[u8],
29 persona: &[u8],
30 key_size: usize,
31 output_size: usize,
32 ) -> Self {
33 assert!(key_size <= $bytes::to_usize());
34 assert!(output_size <= $bytes::to_usize());
35
36 let length = $bytes::to_usize() / 4;
38 assert!(salt.len() <= length);
39 assert!(persona.len() <= length);
40
41 let mut p = [0 as $word; 8];
43 p[0] = 0x0101_0000 ^ ((key_size as $word) << 8) ^ (output_size as $word);
44
45 if salt.len() < length {
47 let mut padded_salt =
48 GenericArray::<u8, <$bytes as Div<U4>>::Output>::default();
49 for i in 0..salt.len() {
50 padded_salt[i] = salt[i];
51 }
52 p[4] = $word::from_le_bytes(padded_salt[0..length / 2].try_into().unwrap());
53 p[5] = $word::from_le_bytes(
54 padded_salt[length / 2..padded_salt.len()]
55 .try_into()
56 .unwrap(),
57 );
58 } else {
59 p[4] = $word::from_le_bytes(salt[0..salt.len() / 2].try_into().unwrap());
60 p[5] =
61 $word::from_le_bytes(salt[salt.len() / 2..salt.len()].try_into().unwrap());
62 }
63
64 if persona.len() < length {
66 let mut padded_persona =
67 GenericArray::<u8, <$bytes as Div<U4>>::Output>::default();
68 for i in 0..persona.len() {
69 padded_persona[i] = persona[i];
70 }
71 p[6] = $word::from_le_bytes(padded_persona[0..length / 2].try_into().unwrap());
72 p[7] = $word::from_le_bytes(
73 padded_persona[length / 2..padded_persona.len()]
74 .try_into()
75 .unwrap(),
76 );
77 } else {
78 p[6] = $word::from_le_bytes(persona[0..length / 2].try_into().unwrap());
79 p[7] = $word::from_le_bytes(
80 persona[length / 2..persona.len()].try_into().unwrap(),
81 );
82 }
83
84 let h = [
85 Self::iv0() ^ $vec::new(p[0], p[1], p[2], p[3]),
86 Self::iv1() ^ $vec::new(p[4], p[5], p[6], p[7]),
87 ];
88 $name {
89 #[cfg(feature = "reset")]
90 h0: h.clone(),
91 h,
92 t: 0,
93 }
94 }
95
96 fn finalize_with_flag(
97 &mut self,
98 final_block: &GenericArray<u8, $block_size>,
99 flag: $word,
100 out: &mut Output<Self>,
101 ) {
102 self.compress(final_block, !0, flag);
103 let buf = [self.h[0].to_le(), self.h[1].to_le()];
104 out.copy_from_slice(buf.as_bytes())
105 }
106
107 fn compress(&mut self, block: &Block<Self>, f0: $word, f1: $word) {
108 use $crate::consts::SIGMA;
109
110 #[cfg_attr(not(feature = "size_opt"), inline(always))]
111 fn quarter_round(v: &mut [$vec; 4], rd: u32, rb: u32, m: $vec) {
112 v[0] = v[0].wrapping_add(v[1]).wrapping_add(m.from_le());
113 v[3] = (v[3] ^ v[0]).rotate_right_const(rd);
114 v[2] = v[2].wrapping_add(v[3]);
115 v[1] = (v[1] ^ v[2]).rotate_right_const(rb);
116 }
117
118 #[cfg_attr(not(feature = "size_opt"), inline(always))]
119 fn shuffle(v: &mut [$vec; 4]) {
120 v[1] = v[1].shuffle_left_1();
121 v[2] = v[2].shuffle_left_2();
122 v[3] = v[3].shuffle_left_3();
123 }
124
125 #[cfg_attr(not(feature = "size_opt"), inline(always))]
126 fn unshuffle(v: &mut [$vec; 4]) {
127 v[1] = v[1].shuffle_right_1();
128 v[2] = v[2].shuffle_right_2();
129 v[3] = v[3].shuffle_right_3();
130 }
131
132 #[cfg_attr(not(feature = "size_opt"), inline(always))]
133 fn round(v: &mut [$vec; 4], m: &[$word; 16], s: &[usize; 16]) {
134 quarter_round(v, $R1, $R2, $vec::gather(m, s[0], s[2], s[4], s[6]));
135 quarter_round(v, $R3, $R4, $vec::gather(m, s[1], s[3], s[5], s[7]));
136
137 shuffle(v);
138 quarter_round(v, $R1, $R2, $vec::gather(m, s[8], s[10], s[12], s[14]));
139 quarter_round(v, $R3, $R4, $vec::gather(m, s[9], s[11], s[13], s[15]));
140 unshuffle(v);
141 }
142
143 let mut m: [$word; 16] = Default::default();
144 let n = core::mem::size_of::<$word>();
145 for (v, chunk) in m.iter_mut().zip(block.chunks_exact(n)) {
146 *v = $word::from_ne_bytes(chunk.try_into().unwrap());
147 }
148 let h = &mut self.h;
149
150 let t0 = self.t as $word;
151 let t1 = match $bytes::to_u8() {
152 64 => 0,
153 32 => (self.t >> 32) as $word,
154 _ => unreachable!(),
155 };
156
157 let mut v = [
158 h[0],
159 h[1],
160 Self::iv0(),
161 Self::iv1() ^ $vec::new(t0, t1, f0, f1),
162 ];
163
164 round(&mut v, &m, &SIGMA[0]);
165 round(&mut v, &m, &SIGMA[1]);
166 round(&mut v, &m, &SIGMA[2]);
167 round(&mut v, &m, &SIGMA[3]);
168 round(&mut v, &m, &SIGMA[4]);
169 round(&mut v, &m, &SIGMA[5]);
170 round(&mut v, &m, &SIGMA[6]);
171 round(&mut v, &m, &SIGMA[7]);
172 round(&mut v, &m, &SIGMA[8]);
173 round(&mut v, &m, &SIGMA[9]);
174 if $bytes::to_u8() == 64 {
175 round(&mut v, &m, &SIGMA[0]);
176 round(&mut v, &m, &SIGMA[1]);
177 }
178
179 h[0] = h[0] ^ (v[0] ^ v[2]);
180 h[1] = h[1] ^ (v[1] ^ v[3]);
181 }
182 }
183
184 impl HashMarker for $name {}
185
186 impl BlockSizeUser for $name {
187 type BlockSize = $block_size;
188 }
189
190 impl BufferKindUser for $name {
191 type BufferKind = Lazy;
192 }
193
194 impl UpdateCore for $name {
195 #[inline]
196 fn update_blocks(&mut self, blocks: &[Block<Self>]) {
197 for block in blocks {
198 self.t += block.len() as u64;
199 self.compress(block, 0, 0);
200 }
201 }
202 }
203
204 impl OutputSizeUser for $name {
205 type OutputSize = $bytes;
206 }
207
208 impl VariableOutputCore for $name {
209 const TRUNC_SIDE: TruncSide = TruncSide::Left;
210
211 #[inline]
212 fn new(output_size: usize) -> Result<Self, InvalidOutputSize> {
213 if output_size > Self::OutputSize::USIZE {
214 return Err(InvalidOutputSize);
215 }
216 Ok(Self::new_with_params(&[], &[], 0, output_size))
217 }
218
219 #[inline]
220 fn finalize_variable_core(
221 &mut self,
222 buffer: &mut Buffer<Self>,
223 out: &mut Output<Self>,
224 ) {
225 self.t += buffer.get_pos() as u64;
226 let block = buffer.pad_with_zeros();
227 self.finalize_with_flag(block, 0, out);
228 }
229 }
230
231 #[cfg(feature = "reset")]
232 impl Reset for $name {
233 fn reset(&mut self) {
234 self.h = self.h0;
235 self.t = 0;
236 }
237 }
238
239 impl AlgorithmName for $name {
240 #[inline]
241 fn write_alg_name(f: &mut fmt::Formatter<'_>) -> fmt::Result {
242 f.write_str($alg_name)
243 }
244 }
245
246 impl fmt::Debug for $name {
247 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
248 f.write_str(concat!(stringify!($name), " { ... }"))
249 }
250 }
251 };
252}
253
254macro_rules! blake2_mac_impl {
255 (
256 $name:ident, $hash:ty, $max_size:ty, $doc:expr
257 ) => {
258 #[derive(Clone)]
259 #[doc=$doc]
260 pub struct $name<OutSize>
261 where
262 OutSize: ArrayLength<u8> + IsLessOrEqual<$max_size>,
263 LeEq<OutSize, $max_size>: NonZero,
264 {
265 core: $hash,
266 buffer: LazyBuffer<<$hash as BlockSizeUser>::BlockSize>,
267 #[cfg(feature = "reset")]
268 key_block: Key<Self>,
269 _out: PhantomData<OutSize>,
270 }
271
272 impl<OutSize> $name<OutSize>
273 where
274 OutSize: ArrayLength<u8> + IsLessOrEqual<$max_size>,
275 LeEq<OutSize, $max_size>: NonZero,
276 {
277 #[inline]
283 pub fn new_with_salt_and_personal(
284 key: &[u8],
285 salt: &[u8],
286 persona: &[u8],
287 ) -> Result<Self, InvalidLength> {
288 let kl = key.len();
289 let bs = <$hash as BlockSizeUser>::BlockSize::USIZE;
290 let qbs = bs / 4;
291 if kl > bs || salt.len() > qbs || persona.len() > qbs {
292 return Err(InvalidLength);
293 }
294 let mut padded_key = Block::<$hash>::default();
295 padded_key[..kl].copy_from_slice(key);
296 Ok(Self {
297 core: <$hash>::new_with_params(salt, persona, key.len(), OutSize::USIZE),
298 buffer: LazyBuffer::new(&padded_key),
299 #[cfg(feature = "reset")]
300 key_block: {
301 let mut t = Key::<Self>::default();
302 t[..kl].copy_from_slice(key);
303 t
304 },
305 _out: PhantomData,
306 })
307 }
308 }
309
310 impl<OutSize> KeySizeUser for $name<OutSize>
311 where
312 OutSize: ArrayLength<u8> + IsLessOrEqual<$max_size>,
313 LeEq<OutSize, $max_size>: NonZero,
314 {
315 type KeySize = $max_size;
316 }
317
318 impl<OutSize> KeyInit for $name<OutSize>
319 where
320 OutSize: ArrayLength<u8> + IsLessOrEqual<$max_size>,
321 LeEq<OutSize, $max_size>: NonZero,
322 {
323 #[inline]
324 fn new(key: &Key<Self>) -> Self {
325 Self::new_from_slice(key).expect("Key has correct length")
326 }
327
328 #[inline]
329 fn new_from_slice(key: &[u8]) -> Result<Self, InvalidLength> {
330 let kl = key.len();
331 if kl > <Self as KeySizeUser>::KeySize::USIZE {
332 return Err(InvalidLength);
333 }
334 let mut padded_key = Block::<$hash>::default();
335 padded_key[..kl].copy_from_slice(key);
336 Ok(Self {
337 core: <$hash>::new_with_params(&[], &[], key.len(), OutSize::USIZE),
338 buffer: LazyBuffer::new(&padded_key),
339 #[cfg(feature = "reset")]
340 key_block: {
341 let mut t = Key::<Self>::default();
342 t[..kl].copy_from_slice(key);
343 t
344 },
345 _out: PhantomData,
346 })
347 }
348 }
349
350 impl<OutSize> Update for $name<OutSize>
351 where
352 OutSize: ArrayLength<u8> + IsLessOrEqual<$max_size>,
353 LeEq<OutSize, $max_size>: NonZero,
354 {
355 #[inline]
356 fn update(&mut self, input: &[u8]) {
357 let Self { core, buffer, .. } = self;
358 buffer.digest_blocks(input, |blocks| core.update_blocks(blocks));
359 }
360 }
361
362 impl<OutSize> OutputSizeUser for $name<OutSize>
363 where
364 OutSize: ArrayLength<u8> + IsLessOrEqual<$max_size> + 'static,
365 LeEq<OutSize, $max_size>: NonZero,
366 {
367 type OutputSize = OutSize;
368 }
369
370 impl<OutSize> FixedOutput for $name<OutSize>
371 where
372 OutSize: ArrayLength<u8> + IsLessOrEqual<$max_size> + 'static,
373 LeEq<OutSize, $max_size>: NonZero,
374 {
375 #[inline]
376 fn finalize_into(mut self, out: &mut Output<Self>) {
377 let Self { core, buffer, .. } = &mut self;
378 let mut full_res = Default::default();
379 core.finalize_variable_core(buffer, &mut full_res);
380 out.copy_from_slice(&full_res[..OutSize::USIZE]);
381 }
382 }
383
384 #[cfg(feature = "reset")]
385 impl<OutSize> Reset for $name<OutSize>
386 where
387 OutSize: ArrayLength<u8> + IsLessOrEqual<$max_size>,
388 LeEq<OutSize, $max_size>: NonZero,
389 {
390 fn reset(&mut self) {
391 self.core.reset();
392 let kl = self.key_block.len();
393 let mut padded_key = Block::<$hash>::default();
394 padded_key[..kl].copy_from_slice(&self.key_block);
395 self.buffer = LazyBuffer::new(&padded_key);
396 }
397 }
398
399 #[cfg(feature = "reset")]
400 impl<OutSize> FixedOutputReset for $name<OutSize>
401 where
402 OutSize: ArrayLength<u8> + IsLessOrEqual<$max_size>,
403 LeEq<OutSize, $max_size>: NonZero,
404 {
405 #[inline]
406 fn finalize_into_reset(&mut self, out: &mut Output<Self>) {
407 let Self { core, buffer, .. } = self;
408 let mut full_res = Default::default();
409 core.finalize_variable_core(buffer, &mut full_res);
410 out.copy_from_slice(&full_res[..OutSize::USIZE]);
411 self.reset();
412 }
413 }
414
415 impl<OutSize> MacMarker for $name<OutSize>
416 where
417 OutSize: ArrayLength<u8> + IsLessOrEqual<$max_size>,
418 LeEq<OutSize, $max_size>: NonZero,
419 {
420 }
421
422 impl<OutSize> fmt::Debug for $name<OutSize>
423 where
424 OutSize: ArrayLength<u8> + IsLessOrEqual<$max_size>,
425 LeEq<OutSize, $max_size>: NonZero,
426 {
427 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
428 write!(f, "{}{} {{ ... }}", stringify!($name), OutSize::USIZE)
429 }
430 }
431 };
432}