1use self::{
22 dynstate::DynState,
23 sha2::{SHA256_BLOCK_LEN, SHA512_BLOCK_LEN},
24};
25use crate::{
26 bits::{BitLength, FromByteLen as _},
27 cpu, debug, error,
28 polyfill::{self, slice, sliceutil},
29};
30use core::num::Wrapping;
31
32pub(crate) use self::finish_error::FinishError;
33
34mod dynstate;
35mod sha1;
36mod sha2;
37
38#[derive(Clone)]
39pub(crate) struct BlockContext {
40 state: DynState,
41
42 completed_bytes: u64,
46
47 pub algorithm: &'static Algorithm,
49}
50
51impl BlockContext {
52 pub(crate) fn new(algorithm: &'static Algorithm) -> Self {
53 Self {
54 state: algorithm.initial_state.clone(),
55 completed_bytes: 0,
56 algorithm,
57 }
58 }
59
60 pub(crate) fn update<'i>(&mut self, input: &'i [u8], cpu_features: cpu::Features) -> &'i [u8] {
63 let (completed_bytes, leftover) = self.block_data_order(input, cpu_features);
64 self.completed_bytes = self
69 .completed_bytes
70 .saturating_add(polyfill::u64_from_usize(completed_bytes));
71 leftover
72 }
73
74 pub(crate) fn try_finish(
80 mut self,
81 block: &mut [u8; MAX_BLOCK_LEN],
82 num_pending: usize,
83 cpu_features: cpu::Features,
84 ) -> Result<Digest, FinishError> {
85 let completed_bits = self
86 .completed_bytes
87 .checked_add(polyfill::u64_from_usize(num_pending))
88 .ok_or_else(|| {
89 InputTooLongError::new(self.completed_bytes)
91 })
92 .and_then(BitLength::from_byte_len)
93 .map_err(FinishError::input_too_long)?;
94
95 let block_len = self.algorithm.block_len();
96 let block = &mut block[..block_len];
97
98 let padding = match block.get_mut(num_pending..) {
99 Some([separator, padding @ ..]) => {
100 *separator = 0x80;
101 padding
102 }
103 unreachable => {
105 return Err(FinishError::pending_not_a_partial_block(
106 unreachable.as_deref(),
107 ));
108 }
109 };
110
111 let padding = match padding
112 .len()
113 .checked_sub(self.algorithm.block_len.len_len())
114 {
115 Some(_) => padding,
116 None => {
117 padding.fill(0);
118 let (completed_bytes, leftover) = self.block_data_order(block, cpu_features);
119 debug_assert_eq!((completed_bytes, leftover.len()), (block_len, 0));
120 &mut block[..]
123 }
124 };
125
126 let (to_zero, len) = padding.split_at_mut(padding.len() - 8);
127 to_zero.fill(0);
128 len.copy_from_slice(&completed_bits.to_be_bytes());
129
130 let (completed_bytes, leftover) = self.block_data_order(block, cpu_features);
131 debug_assert_eq!((completed_bytes, leftover.len()), (block_len, 0));
132
133 Ok(Digest {
134 algorithm: self.algorithm,
135 value: self.state.format_output(),
136 })
137 }
138
139 #[must_use]
140 fn block_data_order<'d>(
141 &mut self,
142 data: &'d [u8],
143 cpu_features: cpu::Features,
144 ) -> (usize, &'d [u8]) {
145 (self.algorithm.block_data_order)(&mut self.state, data, cpu_features)
146 }
147}
148
149pub(crate) type InputTooLongError = error::InputTooLongError<u64>;
150
151cold_exhaustive_error! {
152 enum finish_error::FinishError {
153 input_too_long => InputTooLong(InputTooLongError),
154 pending_not_a_partial_block_inner => PendingNotAPartialBlock(usize),
155 }
156}
157
158impl FinishError {
159 #[cold]
160 #[inline(never)]
161 fn pending_not_a_partial_block(padding: Option<&[u8]>) -> Self {
162 match padding {
163 None => Self::pending_not_a_partial_block_inner(0),
164 Some(padding) => Self::pending_not_a_partial_block_inner(padding.len()),
165 }
166 }
167}
168
169#[derive(Clone)]
187pub struct Context {
188 block: BlockContext,
189 pending: [u8; MAX_BLOCK_LEN],
191
192 num_pending: usize,
194}
195
196impl Context {
197 pub fn new(algorithm: &'static Algorithm) -> Self {
199 Self {
200 block: BlockContext::new(algorithm),
201 pending: [0u8; MAX_BLOCK_LEN],
202 num_pending: 0,
203 }
204 }
205
206 pub(crate) fn clone_from(block: &BlockContext) -> Self {
207 Self {
208 block: block.clone(),
209 pending: [0u8; MAX_BLOCK_LEN],
210 num_pending: 0,
211 }
212 }
213
214 pub fn update(&mut self, data: &[u8]) {
216 let cpu_features = cpu::features();
217
218 let block_len = self.block.algorithm.block_len();
219 let buffer = &mut self.pending[..block_len];
220
221 let to_digest = if self.num_pending == 0 {
222 data
223 } else {
224 let buffer_to_fill = match buffer.get_mut(self.num_pending..) {
225 Some(buffer_to_fill) => buffer_to_fill,
226 None => {
227 unreachable!();
229 }
230 };
231 sliceutil::overwrite_at_start(buffer_to_fill, data);
232 match slice::split_at_checked(data, buffer_to_fill.len()) {
233 Some((just_copied, to_digest)) => {
234 debug_assert_eq!(buffer_to_fill.len(), just_copied.len());
235 debug_assert_eq!(self.num_pending + just_copied.len(), block_len);
236 let leftover = self.block.update(buffer, cpu_features);
237 debug_assert_eq!(leftover.len(), 0);
238 self.num_pending = 0;
239 to_digest
240 }
241 None => {
242 self.num_pending += data.len();
243 debug_assert!(self.num_pending < block_len);
245 return;
246 }
247 }
248 };
249
250 let leftover = self.block.update(to_digest, cpu_features);
251 sliceutil::overwrite_at_start(buffer, leftover);
252 self.num_pending = leftover.len();
253 debug_assert!(self.num_pending < block_len);
254 }
255
256 pub fn finish(self) -> Digest {
261 let cpu = cpu::features();
262 self.try_finish(cpu)
263 .map_err(error::erase::<InputTooLongError>)
264 .unwrap()
265 }
266
267 pub(crate) fn try_finish(
268 mut self,
269 cpu_features: cpu::Features,
270 ) -> Result<Digest, InputTooLongError> {
271 self.block
272 .try_finish(&mut self.pending, self.num_pending, cpu_features)
273 .map_err(|err| match err {
274 FinishError::InputTooLong(i) => i,
275 FinishError::PendingNotAPartialBlock(_) => {
276 unreachable!()
278 }
279 })
280 }
281
282 #[inline(always)]
284 pub fn algorithm(&self) -> &'static Algorithm {
285 self.block.algorithm
286 }
287}
288
289pub fn digest(algorithm: &'static Algorithm, data: &[u8]) -> Digest {
305 let cpu = cpu::features();
306 Digest::compute_from(algorithm, data, cpu)
307 .map_err(error::erase::<InputTooLongError>)
308 .unwrap()
309}
310
311#[derive(Clone, Copy)]
315pub struct Digest {
316 value: Output,
317 algorithm: &'static Algorithm,
318}
319
320impl Digest {
321 pub(crate) fn compute_from(
322 algorithm: &'static Algorithm,
323 data: &[u8],
324 cpu: cpu::Features,
325 ) -> Result<Self, InputTooLongError> {
326 let mut ctx = Context::new(algorithm);
327 ctx.update(data);
328 ctx.try_finish(cpu)
329 }
330
331 #[inline(always)]
333 pub fn algorithm(&self) -> &'static Algorithm {
334 self.algorithm
335 }
336}
337
338impl AsRef<[u8]> for Digest {
339 #[inline(always)]
340 fn as_ref(&self) -> &[u8] {
341 &self.value.0[..self.algorithm.output_len()]
342 }
343}
344
345impl core::fmt::Debug for Digest {
346 fn fmt(&self, fmt: &mut core::fmt::Formatter) -> core::fmt::Result {
347 write!(fmt, "{:?}:", self.algorithm)?;
348 debug::write_hex_bytes(fmt, self.as_ref())
349 }
350}
351
352pub struct Algorithm {
354 output_len: OutputLen,
355 chaining_len: usize,
356 block_len: BlockLen,
357
358 block_data_order: for<'d> fn(
362 state: &mut DynState,
363 data: &'d [u8],
364 cpu_features: cpu::Features,
365 ) -> (usize, &'d [u8]),
366
367 initial_state: DynState,
368
369 id: AlgorithmID,
370}
371
372#[derive(Debug, Eq, PartialEq)]
373enum AlgorithmID {
374 SHA1,
375 SHA256,
376 SHA384,
377 SHA512,
378 SHA512_256,
379}
380
381impl PartialEq for Algorithm {
382 fn eq(&self, other: &Self) -> bool {
383 self.id == other.id
384 }
385}
386
387impl Eq for Algorithm {}
388
389derive_debug_via_id!(Algorithm);
390
391impl Algorithm {
392 pub fn block_len(&self) -> usize {
394 self.block_len.into()
395 }
396
397 pub fn chaining_len(&self) -> usize {
405 self.chaining_len
406 }
407
408 pub fn output_len(&self) -> usize {
410 self.output_len.into()
411 }
412}
413
414pub static SHA1_FOR_LEGACY_USE_ONLY: Algorithm = Algorithm {
418 output_len: sha1::OUTPUT_LEN,
419 chaining_len: sha1::CHAINING_LEN,
420 block_len: sha1::BLOCK_LEN,
421 block_data_order: dynstate::sha1_block_data_order,
422 initial_state: DynState::new32([
423 Wrapping(0x67452301u32),
424 Wrapping(0xefcdab89u32),
425 Wrapping(0x98badcfeu32),
426 Wrapping(0x10325476u32),
427 Wrapping(0xc3d2e1f0u32),
428 Wrapping(0),
429 Wrapping(0),
430 Wrapping(0),
431 ]),
432 id: AlgorithmID::SHA1,
433};
434
435pub static SHA256: Algorithm = Algorithm {
439 output_len: OutputLen::_256,
440 chaining_len: SHA256_OUTPUT_LEN,
441 block_len: SHA256_BLOCK_LEN,
442 block_data_order: dynstate::sha256_block_data_order,
443 initial_state: DynState::new32([
444 Wrapping(0x6a09e667u32),
445 Wrapping(0xbb67ae85u32),
446 Wrapping(0x3c6ef372u32),
447 Wrapping(0xa54ff53au32),
448 Wrapping(0x510e527fu32),
449 Wrapping(0x9b05688cu32),
450 Wrapping(0x1f83d9abu32),
451 Wrapping(0x5be0cd19u32),
452 ]),
453 id: AlgorithmID::SHA256,
454};
455
456pub static SHA384: Algorithm = Algorithm {
460 output_len: OutputLen::_384,
461 chaining_len: SHA512_OUTPUT_LEN,
462 block_len: SHA512_BLOCK_LEN,
463 block_data_order: dynstate::sha512_block_data_order,
464 initial_state: DynState::new64([
465 Wrapping(0xcbbb9d5dc1059ed8),
466 Wrapping(0x629a292a367cd507),
467 Wrapping(0x9159015a3070dd17),
468 Wrapping(0x152fecd8f70e5939),
469 Wrapping(0x67332667ffc00b31),
470 Wrapping(0x8eb44a8768581511),
471 Wrapping(0xdb0c2e0d64f98fa7),
472 Wrapping(0x47b5481dbefa4fa4),
473 ]),
474 id: AlgorithmID::SHA384,
475};
476
477pub static SHA512: Algorithm = Algorithm {
481 output_len: OutputLen::_512,
482 chaining_len: SHA512_OUTPUT_LEN,
483 block_len: SHA512_BLOCK_LEN,
484 block_data_order: dynstate::sha512_block_data_order,
485 initial_state: DynState::new64([
486 Wrapping(0x6a09e667f3bcc908),
487 Wrapping(0xbb67ae8584caa73b),
488 Wrapping(0x3c6ef372fe94f82b),
489 Wrapping(0xa54ff53a5f1d36f1),
490 Wrapping(0x510e527fade682d1),
491 Wrapping(0x9b05688c2b3e6c1f),
492 Wrapping(0x1f83d9abfb41bd6b),
493 Wrapping(0x5be0cd19137e2179),
494 ]),
495 id: AlgorithmID::SHA512,
496};
497
498pub static SHA512_256: Algorithm = Algorithm {
506 output_len: OutputLen::_256,
507 chaining_len: SHA512_OUTPUT_LEN,
508 block_len: SHA512_BLOCK_LEN,
509 block_data_order: dynstate::sha512_block_data_order,
510 initial_state: DynState::new64([
511 Wrapping(0x22312194fc2bf72c),
512 Wrapping(0x9f555fa3c84c64c2),
513 Wrapping(0x2393b86b6f53b151),
514 Wrapping(0x963877195940eabd),
515 Wrapping(0x96283ee2a88effe3),
516 Wrapping(0xbe5e1e2553863992),
517 Wrapping(0x2b0199fc2c85b8aa),
518 Wrapping(0x0eb72ddc81c52ca2),
519 ]),
520 id: AlgorithmID::SHA512_256,
521};
522
523#[derive(Clone, Copy)]
524struct Output([u8; MAX_OUTPUT_LEN]);
525
526pub const MAX_BLOCK_LEN: usize = BlockLen::MAX.into();
529
530pub const MAX_OUTPUT_LEN: usize = OutputLen::MAX.into();
533
534pub const MAX_CHAINING_LEN: usize = MAX_OUTPUT_LEN;
537
538#[inline]
539fn format_output<T, F, const N: usize>(input: [Wrapping<T>; sha2::CHAINING_WORDS], f: F) -> Output
540where
541 F: Fn(T) -> [u8; N],
542 T: Copy,
543{
544 let mut output = Output([0; MAX_OUTPUT_LEN]);
545 output
546 .0
547 .chunks_mut(N)
548 .zip(input.iter().copied().map(|Wrapping(w)| f(w)))
549 .for_each(|(o, i)| {
550 o.copy_from_slice(&i);
551 });
552 output
553}
554
555pub const SHA1_OUTPUT_LEN: usize = sha1::OUTPUT_LEN.into();
557
558pub const SHA256_OUTPUT_LEN: usize = OutputLen::_256.into();
560
561pub const SHA384_OUTPUT_LEN: usize = OutputLen::_384.into();
563
564pub const SHA512_OUTPUT_LEN: usize = OutputLen::_512.into();
566
567pub const SHA512_256_OUTPUT_LEN: usize = OutputLen::_256.into();
569
570#[derive(Clone, Copy)]
571enum BlockLen {
572 _512 = 512 / 8,
573 _1024 = 1024 / 8, }
575
576impl BlockLen {
577 const MAX: Self = Self::_1024;
578 #[inline(always)]
579 const fn into(self) -> usize {
580 self as usize
581 }
582
583 #[inline(always)]
584 const fn len_len(self) -> usize {
585 let len_len = match self {
586 BlockLen::_512 => LenLen::_64,
587 BlockLen::_1024 => LenLen::_128,
588 };
589 len_len as usize
590 }
591}
592
593#[derive(Clone, Copy)]
594enum LenLen {
595 _64 = 64 / 8,
596 _128 = 128 / 8,
597}
598
599#[derive(Clone, Copy)]
600enum OutputLen {
601 _160 = 160 / 8,
602 _256 = 256 / 8,
603 _384 = 384 / 8,
604 _512 = 512 / 8, }
606
607impl OutputLen {
608 const MAX: Self = Self::_512;
609
610 #[inline(always)]
611 const fn into(self) -> usize {
612 self as usize
613 }
614}
615
616#[cfg(test)]
617mod tests {
618 mod max_input {
619 extern crate alloc;
620 use super::super::super::digest;
621 use crate::polyfill::u64_from_usize;
622 use alloc::vec;
623
624 macro_rules! max_input_tests {
625 ( $algorithm_name:ident ) => {
626 mod $algorithm_name {
627 use super::super::super::super::digest;
628
629 #[test]
630 fn max_input_test() {
631 super::max_input_test(&digest::$algorithm_name);
632 }
633
634 #[test]
635 #[should_panic]
636 fn too_long_input_test_block() {
637 super::too_long_input_test_block(&digest::$algorithm_name);
638 }
639
640 #[test]
641 #[should_panic]
642 fn too_long_input_test_byte() {
643 super::too_long_input_test_byte(&digest::$algorithm_name);
644 }
645 }
646 };
647 }
648
649 fn max_input_test(alg: &'static digest::Algorithm) {
650 let mut context = nearly_full_context(alg);
651 let next_input = vec![0u8; alg.block_len() - 1];
652 context.update(&next_input);
653 let _ = context.finish(); }
655
656 fn too_long_input_test_block(alg: &'static digest::Algorithm) {
657 let mut context = nearly_full_context(alg);
658 let next_input = vec![0u8; alg.block_len()];
659 context.update(&next_input);
660 let _ = context.finish(); }
662
663 fn too_long_input_test_byte(alg: &'static digest::Algorithm) {
664 let mut context = nearly_full_context(alg);
665 let next_input = vec![0u8; alg.block_len() - 1];
666 context.update(&next_input);
667 context.update(&[0]);
668 let _ = context.finish(); }
670
671 fn nearly_full_context(alg: &'static digest::Algorithm) -> digest::Context {
672 let max_bytes = 1u64 << (64 - 3);
676 let max_blocks = max_bytes / u64_from_usize(alg.block_len());
677 let completed_bytes = (max_blocks - 1) * u64_from_usize(alg.block_len());
678 digest::Context {
679 block: digest::BlockContext {
680 state: alg.initial_state.clone(),
681 completed_bytes,
682 algorithm: alg,
683 },
684 pending: [0u8; digest::MAX_BLOCK_LEN],
685 num_pending: 0,
686 }
687 }
688
689 max_input_tests!(SHA1_FOR_LEGACY_USE_ONLY);
690 max_input_tests!(SHA256);
691 max_input_tests!(SHA384);
692 max_input_tests!(SHA512);
693 }
694}