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