1use super::Digest;
14
15const K32: [u32; 64] = [
18 0x428a_2f98,
19 0x7137_4491,
20 0xb5c0_fbcf,
21 0xe9b5_dba5,
22 0x3956_c25b,
23 0x59f1_11f1,
24 0x923f_82a4,
25 0xab1c_5ed5,
26 0xd807_aa98,
27 0x1283_5b01,
28 0x2431_85be,
29 0x550c_7dc3,
30 0x72be_5d74,
31 0x80de_b1fe,
32 0x9bdc_06a7,
33 0xc19b_f174,
34 0xe49b_69c1,
35 0xefbe_4786,
36 0x0fc1_9dc6,
37 0x240c_a1cc,
38 0x2de9_2c6f,
39 0x4a74_84aa,
40 0x5cb0_a9dc,
41 0x76f9_88da,
42 0x983e_5152,
43 0xa831_c66d,
44 0xb003_27c8,
45 0xbf59_7fc7,
46 0xc6e0_0bf3,
47 0xd5a7_9147,
48 0x06ca_6351,
49 0x1429_2967,
50 0x27b7_0a85,
51 0x2e1b_2138,
52 0x4d2c_6dfc,
53 0x5338_0d13,
54 0x650a_7354,
55 0x766a_0abb,
56 0x81c2_c92e,
57 0x9272_2c85,
58 0xa2bf_e8a1,
59 0xa81a_664b,
60 0xc24b_8b70,
61 0xc76c_51a3,
62 0xd192_e819,
63 0xd699_0624,
64 0xf40e_3585,
65 0x106a_a070,
66 0x19a4_c116,
67 0x1e37_6c08,
68 0x2748_774c,
69 0x34b0_bcb5,
70 0x391c_0cb3,
71 0x4ed8_aa4a,
72 0x5b9c_ca4f,
73 0x682e_6ff3,
74 0x748f_82ee,
75 0x78a5_636f,
76 0x84c8_7814,
77 0x8cc7_0208,
78 0x90be_fffa,
79 0xa450_6ceb,
80 0xbef9_a3f7,
81 0xc671_78f2,
82];
83
84const K64: [u64; 80] = [
87 0x428a_2f98_d728_ae22,
88 0x7137_4491_23ef_65cd,
89 0xb5c0_fbcf_ec4d_3b2f,
90 0xe9b5_dba5_8189_dbbc,
91 0x3956_c25b_f348_b538,
92 0x59f1_11f1_b605_d019,
93 0x923f_82a4_af19_4f9b,
94 0xab1c_5ed5_da6d_8118,
95 0xd807_aa98_a303_0242,
96 0x1283_5b01_4570_6fbe,
97 0x2431_85be_4ee4_b28c,
98 0x550c_7dc3_d5ff_b4e2,
99 0x72be_5d74_f27b_896f,
100 0x80de_b1fe_3b16_96b1,
101 0x9bdc_06a7_25c7_1235,
102 0xc19b_f174_cf69_2694,
103 0xe49b_69c1_9ef1_4ad2,
104 0xefbe_4786_384f_25e3,
105 0x0fc1_9dc6_8b8c_d5b5,
106 0x240c_a1cc_77ac_9c65,
107 0x2de9_2c6f_592b_0275,
108 0x4a74_84aa_6ea6_e483,
109 0x5cb0_a9dc_bd41_fbd4,
110 0x76f9_88da_8311_53b5,
111 0x983e_5152_ee66_dfab,
112 0xa831_c66d_2db4_3210,
113 0xb003_27c8_98fb_213f,
114 0xbf59_7fc7_beef_0ee4,
115 0xc6e0_0bf3_3da8_8fc2,
116 0xd5a7_9147_930a_a725,
117 0x06ca_6351_e003_826f,
118 0x1429_2967_0a0e_6e70,
119 0x27b7_0a85_46d2_2ffc,
120 0x2e1b_2138_5c26_c926,
121 0x4d2c_6dfc_5ac4_2aed,
122 0x5338_0d13_9d95_b3df,
123 0x650a_7354_8baf_63de,
124 0x766a_0abb_3c77_b2a8,
125 0x81c2_c92e_47ed_aee6,
126 0x9272_2c85_1482_353b,
127 0xa2bf_e8a1_4cf1_0364,
128 0xa81a_664b_bc42_3001,
129 0xc24b_8b70_d0f8_9791,
130 0xc76c_51a3_0654_be30,
131 0xd192_e819_d6ef_5218,
132 0xd699_0624_5565_a910,
133 0xf40e_3585_5771_202a,
134 0x106a_a070_32bb_d1b8,
135 0x19a4_c116_b8d2_d0c8,
136 0x1e37_6c08_5141_ab53,
137 0x2748_774c_df8e_eb99,
138 0x34b0_bcb5_e19b_48a8,
139 0x391c_0cb3_c5c9_5a63,
140 0x4ed8_aa4a_e341_8acb,
141 0x5b9c_ca4f_7763_e373,
142 0x682e_6ff3_d6b2_b8a3,
143 0x748f_82ee_5def_b2fc,
144 0x78a5_636f_4317_2f60,
145 0x84c8_7814_a1f0_ab72,
146 0x8cc7_0208_1a64_39ec,
147 0x90be_fffa_2363_1e28,
148 0xa450_6ceb_de82_bde9,
149 0xbef9_a3f7_b2c6_7915,
150 0xc671_78f2_e372_532b,
151 0xca27_3ece_ea26_619c,
152 0xd186_b8c7_21c0_c207,
153 0xeada_7dd6_cde0_eb1e,
154 0xf57d_4f7f_ee6e_d178,
155 0x06f0_67aa_7217_6fba,
156 0x0a63_7dc5_a2c8_98a6,
157 0x113f_9804_bef9_0dae,
158 0x1b71_0b35_131c_471b,
159 0x28db_77f5_2304_7d84,
160 0x32ca_ab7b_40c7_2493,
161 0x3c9e_be0a_15c9_bebc,
162 0x431d_67c4_9c10_0d4c,
163 0x4cc5_d4be_cb3e_42b6,
164 0x597f_299c_fc65_7e2a,
165 0x5fcb_6fab_3ad6_faec,
166 0x6c44_198c_4a47_5817,
167];
168
169#[inline]
170fn compress32(state: &mut [u32; 8], block: &[u8; 64]) {
171 let mut schedule = [0u32; 64];
172 for (i, chunk) in block.chunks_exact(4).enumerate() {
173 schedule[i] = u32::from_be_bytes(chunk.try_into().unwrap());
174 }
175 for word_idx in 16..64 {
176 let sigma0 = schedule[word_idx - 15].rotate_right(7)
177 ^ schedule[word_idx - 15].rotate_right(18)
178 ^ (schedule[word_idx - 15] >> 3);
179 let sigma1 = schedule[word_idx - 2].rotate_right(17)
180 ^ schedule[word_idx - 2].rotate_right(19)
181 ^ (schedule[word_idx - 2] >> 10);
182 schedule[word_idx] = schedule[word_idx - 16]
183 .wrapping_add(sigma0)
184 .wrapping_add(schedule[word_idx - 7])
185 .wrapping_add(sigma1);
186 }
187
188 let mut a_reg = state[0];
189 let mut b_reg = state[1];
190 let mut c_reg = state[2];
191 let mut d_reg = state[3];
192 let mut e_reg = state[4];
193 let mut f_reg = state[5];
194 let mut g_reg = state[6];
195 let mut h_reg = state[7];
196
197 for (round_idx, &schedule_word) in schedule.iter().enumerate() {
198 let sigma1 = e_reg.rotate_right(6) ^ e_reg.rotate_right(11) ^ e_reg.rotate_right(25);
199 let choose = (e_reg & f_reg) ^ ((!e_reg) & g_reg);
200 let temp1 = h_reg
201 .wrapping_add(sigma1)
202 .wrapping_add(choose)
203 .wrapping_add(K32[round_idx])
204 .wrapping_add(schedule_word);
205 let sigma0 = a_reg.rotate_right(2) ^ a_reg.rotate_right(13) ^ a_reg.rotate_right(22);
206 let majority = (a_reg & b_reg) ^ (a_reg & c_reg) ^ (b_reg & c_reg);
207 let temp2 = sigma0.wrapping_add(majority);
208
209 h_reg = g_reg;
210 g_reg = f_reg;
211 f_reg = e_reg;
212 e_reg = d_reg.wrapping_add(temp1);
213 d_reg = c_reg;
214 c_reg = b_reg;
215 b_reg = a_reg;
216 a_reg = temp1.wrapping_add(temp2);
217 }
218
219 state[0] = state[0].wrapping_add(a_reg);
220 state[1] = state[1].wrapping_add(b_reg);
221 state[2] = state[2].wrapping_add(c_reg);
222 state[3] = state[3].wrapping_add(d_reg);
223 state[4] = state[4].wrapping_add(e_reg);
224 state[5] = state[5].wrapping_add(f_reg);
225 state[6] = state[6].wrapping_add(g_reg);
226 state[7] = state[7].wrapping_add(h_reg);
227}
228
229#[inline]
230fn compress64(state: &mut [u64; 8], block: &[u8; 128]) {
231 let mut schedule = [0u64; 80];
232 for (i, chunk) in block.chunks_exact(8).enumerate() {
233 schedule[i] = u64::from_be_bytes(chunk.try_into().unwrap());
234 }
235 for word_idx in 16..80 {
236 let sigma0 = schedule[word_idx - 15].rotate_right(1)
237 ^ schedule[word_idx - 15].rotate_right(8)
238 ^ (schedule[word_idx - 15] >> 7);
239 let sigma1 = schedule[word_idx - 2].rotate_right(19)
240 ^ schedule[word_idx - 2].rotate_right(61)
241 ^ (schedule[word_idx - 2] >> 6);
242 schedule[word_idx] = schedule[word_idx - 16]
243 .wrapping_add(sigma0)
244 .wrapping_add(schedule[word_idx - 7])
245 .wrapping_add(sigma1);
246 }
247
248 let mut a_reg = state[0];
249 let mut b_reg = state[1];
250 let mut c_reg = state[2];
251 let mut d_reg = state[3];
252 let mut e_reg = state[4];
253 let mut f_reg = state[5];
254 let mut g_reg = state[6];
255 let mut h_reg = state[7];
256
257 for (round_idx, &schedule_word) in schedule.iter().enumerate() {
258 let sigma1 = e_reg.rotate_right(14) ^ e_reg.rotate_right(18) ^ e_reg.rotate_right(41);
259 let choose = (e_reg & f_reg) ^ ((!e_reg) & g_reg);
260 let temp1 = h_reg
261 .wrapping_add(sigma1)
262 .wrapping_add(choose)
263 .wrapping_add(K64[round_idx])
264 .wrapping_add(schedule_word);
265 let sigma0 = a_reg.rotate_right(28) ^ a_reg.rotate_right(34) ^ a_reg.rotate_right(39);
266 let majority = (a_reg & b_reg) ^ (a_reg & c_reg) ^ (b_reg & c_reg);
267 let temp2 = sigma0.wrapping_add(majority);
268
269 h_reg = g_reg;
270 g_reg = f_reg;
271 f_reg = e_reg;
272 e_reg = d_reg.wrapping_add(temp1);
273 d_reg = c_reg;
274 c_reg = b_reg;
275 b_reg = a_reg;
276 a_reg = temp1.wrapping_add(temp2);
277 }
278
279 state[0] = state[0].wrapping_add(a_reg);
280 state[1] = state[1].wrapping_add(b_reg);
281 state[2] = state[2].wrapping_add(c_reg);
282 state[3] = state[3].wrapping_add(d_reg);
283 state[4] = state[4].wrapping_add(e_reg);
284 state[5] = state[5].wrapping_add(f_reg);
285 state[6] = state[6].wrapping_add(g_reg);
286 state[7] = state[7].wrapping_add(h_reg);
287}
288
289#[derive(Clone)]
290struct Sha2_32Core {
291 state: [u32; 8],
292 block: [u8; 64],
293 pos: usize,
294 bit_len: u64,
295}
296
297impl Sha2_32Core {
298 fn new(iv: [u32; 8]) -> Self {
299 Self {
300 state: iv,
301 block: [0u8; 64],
302 pos: 0,
303 bit_len: 0,
304 }
305 }
306
307 fn update(&mut self, mut data: &[u8]) {
308 while !data.is_empty() {
309 let take = (64 - self.pos).min(data.len());
310 self.block[self.pos..self.pos + take].copy_from_slice(&data[..take]);
311 self.pos += take;
312 data = &data[take..];
313
314 if self.pos == 64 {
315 compress32(&mut self.state, &self.block);
316 self.block = [0u8; 64];
317 self.pos = 0;
318 self.bit_len = self.bit_len.wrapping_add(512);
319 }
320 }
321 }
322
323 fn finalize<const OUT: usize>(mut self) -> [u8; OUT] {
324 self.bit_len = self.bit_len.wrapping_add((self.pos as u64) * 8);
325 self.block[self.pos] = 0x80;
326 self.pos += 1;
327
328 if self.pos > 56 {
329 self.block[self.pos..].fill(0);
330 compress32(&mut self.state, &self.block);
331 self.block = [0u8; 64];
332 self.pos = 0;
333 }
334
335 self.block[self.pos..56].fill(0);
336 self.block[56..].copy_from_slice(&self.bit_len.to_be_bytes());
337 compress32(&mut self.state, &self.block);
338
339 let mut full = [0u8; 32];
340 for (chunk, word) in full.chunks_exact_mut(4).zip(self.state.iter()) {
341 chunk.copy_from_slice(&word.to_be_bytes());
342 }
343 let mut out = [0u8; OUT];
344 out.copy_from_slice(&full[..OUT]);
345 out
346 }
347
348 fn finalize_into_reset<const OUT: usize>(&mut self, out: &mut [u8; OUT]) {
349 self.bit_len = self.bit_len.wrapping_add((self.pos as u64) * 8);
350 self.block[self.pos] = 0x80;
351 self.pos += 1;
352
353 if self.pos > 56 {
354 self.block[self.pos..].fill(0);
355 compress32(&mut self.state, &self.block);
356 self.block = [0u8; 64];
357 self.pos = 0;
358 }
359
360 self.block[self.pos..56].fill(0);
361 self.block[56..].copy_from_slice(&self.bit_len.to_be_bytes());
362 compress32(&mut self.state, &self.block);
363
364 let mut full = [0u8; 32];
365 for (chunk, word) in full.chunks_exact_mut(4).zip(self.state.iter()) {
366 chunk.copy_from_slice(&word.to_be_bytes());
367 }
368 out.copy_from_slice(&full[..OUT]);
369
370 self.zeroize();
371 }
372
373 fn zeroize(&mut self) {
374 crate::ct::zeroize_slice(self.state.as_mut_slice());
375 crate::ct::zeroize_slice(self.block.as_mut_slice());
376 self.pos = 0;
377 self.bit_len = 0;
378 }
379}
380
381#[derive(Clone)]
382struct Sha2_64Core {
383 state: [u64; 8],
384 block: [u8; 128],
385 pos: usize,
386 bit_len: u128,
387}
388
389impl Sha2_64Core {
390 fn new(iv: [u64; 8]) -> Self {
391 Self {
392 state: iv,
393 block: [0u8; 128],
394 pos: 0,
395 bit_len: 0,
396 }
397 }
398
399 fn update(&mut self, mut data: &[u8]) {
400 while !data.is_empty() {
401 let take = (128 - self.pos).min(data.len());
402 self.block[self.pos..self.pos + take].copy_from_slice(&data[..take]);
403 self.pos += take;
404 data = &data[take..];
405
406 if self.pos == 128 {
407 compress64(&mut self.state, &self.block);
408 self.block = [0u8; 128];
409 self.pos = 0;
410 self.bit_len = self.bit_len.wrapping_add(1024);
411 }
412 }
413 }
414
415 fn finalize<const OUT: usize>(mut self) -> [u8; OUT] {
416 self.bit_len = self.bit_len.wrapping_add((self.pos as u128) * 8);
417 self.block[self.pos] = 0x80;
418 self.pos += 1;
419
420 if self.pos > 112 {
421 self.block[self.pos..].fill(0);
422 compress64(&mut self.state, &self.block);
423 self.block = [0u8; 128];
424 self.pos = 0;
425 }
426
427 self.block[self.pos..112].fill(0);
428 self.block[112..].copy_from_slice(&self.bit_len.to_be_bytes());
429 compress64(&mut self.state, &self.block);
430
431 let mut full = [0u8; 64];
432 for (chunk, word) in full.chunks_exact_mut(8).zip(self.state.iter()) {
433 chunk.copy_from_slice(&word.to_be_bytes());
434 }
435 let mut out = [0u8; OUT];
436 out.copy_from_slice(&full[..OUT]);
437 out
438 }
439
440 fn finalize_into_reset<const OUT: usize>(&mut self, out: &mut [u8; OUT]) {
441 self.bit_len = self.bit_len.wrapping_add((self.pos as u128) * 8);
442 self.block[self.pos] = 0x80;
443 self.pos += 1;
444
445 if self.pos > 112 {
446 self.block[self.pos..].fill(0);
447 compress64(&mut self.state, &self.block);
448 self.block = [0u8; 128];
449 self.pos = 0;
450 }
451
452 self.block[self.pos..112].fill(0);
453 self.block[112..].copy_from_slice(&self.bit_len.to_be_bytes());
454 compress64(&mut self.state, &self.block);
455
456 let mut full = [0u8; 64];
457 for (chunk, word) in full.chunks_exact_mut(8).zip(self.state.iter()) {
458 chunk.copy_from_slice(&word.to_be_bytes());
459 }
460 out.copy_from_slice(&full[..OUT]);
461
462 self.zeroize();
463 }
464
465 fn zeroize(&mut self) {
466 crate::ct::zeroize_slice(self.state.as_mut_slice());
467 crate::ct::zeroize_slice(self.block.as_mut_slice());
468 self.pos = 0;
469 self.bit_len = 0;
470 }
471}
472
473macro_rules! define_sha2_32 {
474 ($name:ident, $out_len:expr, $iv:expr) => {
475 #[derive(Clone)]
476 pub struct $name {
477 inner: Sha2_32Core,
478 }
479
480 impl Default for $name {
481 fn default() -> Self {
482 Self::new()
483 }
484 }
485
486 impl $name {
487 pub const BLOCK_LEN: usize = 64;
488 pub const OUTPUT_LEN: usize = $out_len;
489
490 #[must_use]
491 pub fn new() -> Self {
492 Self {
493 inner: Sha2_32Core::new($iv),
494 }
495 }
496
497 pub fn update(&mut self, data: &[u8]) {
498 self.inner.update(data);
499 }
500
501 #[must_use]
502 pub fn finalize(self) -> [u8; $out_len] {
503 self.inner.finalize::<$out_len>()
504 }
505
506 #[must_use]
507 pub fn digest(data: &[u8]) -> [u8; $out_len] {
508 let mut h = Self::new();
509 h.update(data);
510 h.finalize()
511 }
512 }
513
514 impl Digest for $name {
515 const BLOCK_LEN: usize = 64;
516 const OUTPUT_LEN: usize = $out_len;
517
518 fn new() -> Self {
519 Self::new()
520 }
521
522 fn update(&mut self, data: &[u8]) {
523 self.inner.update(data);
524 }
525
526 fn finalize_into(self, out: &mut [u8]) {
527 assert_eq!(out.len(), $out_len, "wrong digest length");
528 out.copy_from_slice(&self.inner.finalize::<$out_len>());
529 }
530
531 fn finalize_reset(&mut self, out: &mut [u8]) {
532 let out: &mut [u8; $out_len] = out.try_into().expect("wrong digest length");
533 self.inner.finalize_into_reset::<$out_len>(out);
534 }
535
536 fn zeroize(&mut self) {
537 self.inner.zeroize();
538 }
539 }
540 };
541}
542
543macro_rules! define_sha2_64 {
544 ($name:ident, $out_len:expr, $iv:expr) => {
545 #[derive(Clone)]
546 pub struct $name {
547 inner: Sha2_64Core,
548 }
549
550 impl Default for $name {
551 fn default() -> Self {
552 Self::new()
553 }
554 }
555
556 impl $name {
557 pub const BLOCK_LEN: usize = 128;
558 pub const OUTPUT_LEN: usize = $out_len;
559
560 #[must_use]
561 pub fn new() -> Self {
562 Self {
563 inner: Sha2_64Core::new($iv),
564 }
565 }
566
567 pub fn update(&mut self, data: &[u8]) {
568 self.inner.update(data);
569 }
570
571 #[must_use]
572 pub fn finalize(self) -> [u8; $out_len] {
573 self.inner.finalize::<$out_len>()
574 }
575
576 #[must_use]
577 pub fn digest(data: &[u8]) -> [u8; $out_len] {
578 let mut h = Self::new();
579 h.update(data);
580 h.finalize()
581 }
582 }
583
584 impl Digest for $name {
585 const BLOCK_LEN: usize = 128;
586 const OUTPUT_LEN: usize = $out_len;
587
588 fn new() -> Self {
589 Self::new()
590 }
591
592 fn update(&mut self, data: &[u8]) {
593 self.inner.update(data);
594 }
595
596 fn finalize_into(self, out: &mut [u8]) {
597 assert_eq!(out.len(), $out_len, "wrong digest length");
598 out.copy_from_slice(&self.inner.finalize::<$out_len>());
599 }
600
601 fn finalize_reset(&mut self, out: &mut [u8]) {
602 let out: &mut [u8; $out_len] = out.try_into().expect("wrong digest length");
603 self.inner.finalize_into_reset::<$out_len>(out);
604 }
605
606 fn zeroize(&mut self) {
607 self.inner.zeroize();
608 }
609 }
610 };
611}
612
613define_sha2_32!(
615 Sha224,
616 28,
617 [
618 0xc105_9ed8,
619 0x367c_d507,
620 0x3070_dd17,
621 0xf70e_5939,
622 0xffc0_0b31,
623 0x6858_1511,
624 0x64f9_8fa7,
625 0xbefa_4fa4,
626 ]
627);
628
629define_sha2_32!(
631 Sha256,
632 32,
633 [
634 0x6a09_e667,
635 0xbb67_ae85,
636 0x3c6e_f372,
637 0xa54f_f53a,
638 0x510e_527f,
639 0x9b05_688c,
640 0x1f83_d9ab,
641 0x5be0_cd19,
642 ]
643);
644
645define_sha2_64!(
647 Sha384,
648 48,
649 [
650 0xcbbb_9d5d_c105_9ed8,
651 0x629a_292a_367c_d507,
652 0x9159_015a_3070_dd17,
653 0x152f_ecd8_f70e_5939,
654 0x6733_2667_ffc0_0b31,
655 0x8eb4_4a87_6858_1511,
656 0xdb0c_2e0d_64f9_8fa7,
657 0x47b5_481d_befa_4fa4,
658 ]
659);
660
661define_sha2_64!(
663 Sha512,
664 64,
665 [
666 0x6a09_e667_f3bc_c908,
667 0xbb67_ae85_84ca_a73b,
668 0x3c6e_f372_fe94_f82b,
669 0xa54f_f53a_5f1d_36f1,
670 0x510e_527f_ade6_82d1,
671 0x9b05_688c_2b3e_6c1f,
672 0x1f83_d9ab_fb41_bd6b,
673 0x5be0_cd19_137e_2179,
674 ]
675);
676
677define_sha2_64!(
679 Sha512_224,
680 28,
681 [
682 0x8c3d_37c8_1954_4da2,
683 0x73e1_9966_89dc_d4d6,
684 0x1dfa_b7ae_32ff_9c82,
685 0x679d_d514_582f_9fcf,
686 0x0f6d_2b69_7bd4_4da8,
687 0x77e3_6f73_04c4_8942,
688 0x3f9d_85a8_6a1d_36c8,
689 0x1112_e6ad_91d6_92a1,
690 ]
691);
692
693define_sha2_64!(
695 Sha512_256,
696 32,
697 [
698 0x2231_2194_fc2b_f72c,
699 0x9f55_5fa3_c84c_64c2,
700 0x2393_b86b_6f53_b151,
701 0x9638_7719_5940_eabd,
702 0x9628_3ee2_a88e_ffe3,
703 0xbe5e_1e25_5386_3992,
704 0x2b01_99fc_2c85_b8aa,
705 0x0eb7_2ddc_81c5_2ca2,
706 ]
707);
708
709#[cfg(test)]
710mod tests {
711 use super::*;
712
713 fn hex(bytes: &[u8]) -> String {
714 let mut out = String::with_capacity(bytes.len() * 2);
715 for b in bytes {
716 use core::fmt::Write;
717 let _ = write!(&mut out, "{b:02x}");
718 }
719 out
720 }
721
722 #[test]
723 fn sha224_empty() {
724 assert_eq!(
725 hex(&Sha224::digest(b"")),
726 "d14a028c2a3a2bc9476102bb288234c415a2b01f828ea62ac5b3e42f"
727 );
728 }
729
730 #[test]
731 fn sha224_abc_streaming() {
732 let mut h = Sha224::new();
733 h.update(b"a");
734 h.update(b"b");
735 h.update(b"c");
736 assert_eq!(
737 hex(&h.finalize()),
738 "23097d223405d8228642a477bda255b32aadbce4bda0b3f7e36c9da7"
739 );
740 }
741
742 #[test]
743 fn sha256_empty() {
744 assert_eq!(
745 hex(&Sha256::digest(b"")),
746 "e3b0c44298fc1c149afbf4c8996fb924".to_owned() + "27ae41e4649b934ca495991b7852b855"
747 );
748 }
749
750 #[test]
751 fn sha256_abc_streaming() {
752 let mut h = Sha256::new();
753 h.update(b"a");
754 h.update(b"b");
755 h.update(b"c");
756 assert_eq!(
757 hex(&h.finalize()),
758 "ba7816bf8f01cfea414140de5dae2223".to_owned() + "b00361a396177a9cb410ff61f20015ad"
759 );
760 }
761
762 #[test]
763 fn sha384_empty() {
764 assert_eq!(
765 hex(&Sha384::digest(b"")),
766 "38b060a751ac96384cd9327eb1b1e36a".to_owned()
767 + "21fdb71114be07434c0cc7bf63f6e1da"
768 + "274edebfe76f65fbd51ad2f14898b95b"
769 );
770 }
771
772 #[test]
773 fn sha384_abc_streaming() {
774 let mut h = Sha384::new();
775 h.update(b"a");
776 h.update(b"b");
777 h.update(b"c");
778 assert_eq!(
779 hex(&h.finalize()),
780 "cb00753f45a35e8bb5a03d699ac65007".to_owned()
781 + "272c32ab0eded1631a8b605a43ff5bed"
782 + "8086072ba1e7cc2358baeca134c825a7"
783 );
784 }
785
786 #[test]
787 fn sha512_empty() {
788 assert_eq!(
789 hex(&Sha512::digest(b"")),
790 "cf83e1357eefb8bdf1542850d66d8007".to_owned()
791 + "d620e4050b5715dc83f4a921d36ce9ce"
792 + "47d0d13c5d85f2b0ff8318d2877eec2f"
793 + "63b931bd47417a81a538327af927da3e"
794 );
795 }
796
797 #[test]
798 fn sha512_abc_streaming() {
799 let mut h = Sha512::new();
800 h.update(b"a");
801 h.update(b"b");
802 h.update(b"c");
803 assert_eq!(
804 hex(&h.finalize()),
805 "ddaf35a193617abacc417349ae204131".to_owned()
806 + "12e6fa4e89a97ea20a9eeee64b55d39a"
807 + "2192992a274fc1a836ba3c23a3feebbd"
808 + "454d4423643ce80e2a9ac94fa54ca49f"
809 );
810 }
811
812 #[test]
813 fn sha512_224_empty() {
814 assert_eq!(
815 hex(&Sha512_224::digest(b"")),
816 "6ed0dd02806fa89e25de060c19d3ac86cabb87d6a0ddd05c333b84f4"
817 );
818 }
819
820 #[test]
821 fn sha512_224_abc_streaming() {
822 let mut h = Sha512_224::new();
823 h.update(b"a");
824 h.update(b"b");
825 h.update(b"c");
826 assert_eq!(
827 hex(&h.finalize()),
828 "4634270f707b6a54daae7530460842e20e37ed265ceee9a43e8924aa"
829 );
830 }
831
832 #[test]
833 fn sha512_256_empty() {
834 assert_eq!(
835 hex(&Sha512_256::digest(b"")),
836 "c672b8d1ef56ed28ab87c3622c511406".to_owned() + "9bdd3ad7b8f9737498d0c01ecef0967a"
837 );
838 }
839
840 #[test]
841 fn sha512_256_abc_streaming() {
842 let mut h = Sha512_256::new();
843 h.update(b"a");
844 h.update(b"b");
845 h.update(b"c");
846 assert_eq!(
847 hex(&h.finalize()),
848 "53048e2681941ef99b2e29b76b4c7dab".to_owned() + "e4c2d0c634fc6d46e0e2f13107e7af23"
849 );
850 }
851
852 #[test]
853 fn sha256_matches_openssl() {
854 let msg = b"The quick brown fox jumps over the lazy dog";
855 let Some(expected) = crate::test_utils::run_openssl(&["dgst", "-sha256", "-binary"], msg) else {
856 return;
857 };
858 assert_eq!(Sha256::digest(msg).as_slice(), expected.as_slice());
859 }
860
861 #[test]
862 fn sha224_matches_openssl() {
863 let msg = b"The quick brown fox jumps over the lazy dog";
864 let Some(expected) = crate::test_utils::run_openssl(&["dgst", "-sha224", "-binary"], msg) else {
865 return;
866 };
867 assert_eq!(Sha224::digest(msg).as_slice(), expected.as_slice());
868 }
869
870 #[test]
871 fn sha384_matches_openssl() {
872 let msg = b"The quick brown fox jumps over the lazy dog";
873 let Some(expected) = crate::test_utils::run_openssl(&["dgst", "-sha384", "-binary"], msg) else {
874 return;
875 };
876 assert_eq!(Sha384::digest(msg).as_slice(), expected.as_slice());
877 }
878
879 #[test]
880 fn sha512_matches_openssl() {
881 let msg = b"The quick brown fox jumps over the lazy dog";
882 let Some(expected) = crate::test_utils::run_openssl(&["dgst", "-sha512", "-binary"], msg) else {
883 return;
884 };
885 assert_eq!(Sha512::digest(msg).as_slice(), expected.as_slice());
886 }
887
888 #[test]
889 fn sha512_224_matches_openssl() {
890 let msg = b"The quick brown fox jumps over the lazy dog";
891 let Some(expected) = crate::test_utils::run_openssl(&["dgst", "-sha512-224", "-binary"], msg)
892 else {
893 return;
894 };
895 assert_eq!(Sha512_224::digest(msg).as_slice(), expected.as_slice());
896 }
897
898 #[test]
899 fn sha512_256_matches_openssl() {
900 let msg = b"The quick brown fox jumps over the lazy dog";
901 let Some(expected) = crate::test_utils::run_openssl(&["dgst", "-sha512-256", "-binary"], msg)
902 else {
903 return;
904 };
905 assert_eq!(Sha512_256::digest(msg).as_slice(), expected.as_slice());
906 }
907}