1// Copyright 2015-2025 Brian Smith.
2// Copyright 2016 Simon Sapin.
3//
4// Permission to use, copy, modify, and/or distribute this software for any
5// purpose with or without fee is hereby granted, provided that the above
6// copyright notice and this permission notice appear in all copies.
7//
8// THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHORS DISCLAIM ALL WARRANTIES
9// WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
10// MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY
11// SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
12// WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
13// OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
14// CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
15
16use super::{
17 sha2::{
18 fallback::{ch, maj, Word},
19 State32,
20 },
21 BlockLen, OutputLen,
22};
23use crate::polyfill::slice::{self, AsChunks};
24use core::{mem::size_of, num::Wrapping};
25
26pub(super) const BLOCK_LEN: BlockLen = BlockLen::_512;
27pub const CHAINING_LEN: usize = 160 / 8;
28pub(super) const OUTPUT_LEN: OutputLen = OutputLen::_160;
29const CHAINING_WORDS: usize = CHAINING_LEN / 4;
30
31type W32 = Wrapping<u32>;
32
33// FIPS 180-4 4.1.1
34#[inline]
35fn parity(x: W32, y: W32, z: W32) -> W32 {
36 x ^ y ^ z
37}
38
39type State = [W32; CHAINING_WORDS];
40const ROUNDS: usize = 80;
41
42pub fn sha1_block_data_order(state: &mut State32, data: AsChunks<u8, { BLOCK_LEN.into() }>) {
43 // The unwrap won't fail because `CHAINING_WORDS` is smaller than the
44 // length.
45 let state: &mut State = (&mut state[..CHAINING_WORDS]).try_into().unwrap();
46 // SAFETY: The caller guarantees that this is called with data pointing to `num`
47 // `BLOCK_LEN`-long blocks.
48 *state = block_data_order(*state, M:data)
49}
50
51#[inline]
52#[rustfmt::skip]
53fn block_data_order(
54 mut H: [W32; CHAINING_WORDS],
55 M: AsChunks<u8, { BLOCK_LEN.into() }>,
56) -> [W32; CHAINING_WORDS]
57{
58 for M in M {
59 let (M, remainder): (AsChunks<u8, {size_of::<W32>()}>, &[u8]) = slice::as_chunks(M);
60 debug_assert!(remainder.is_empty());
61
62 // FIPS 180-4 6.1.2 Step 1
63 let mut W: [W32; ROUNDS] = [W32::ZERO; ROUNDS];
64 W.iter_mut().zip(M).for_each(|(Wt, Mt)| {
65 *Wt = W32::from_be_bytes(*Mt);
66 });
67 for t in 16..ROUNDS {
68 let wt = W[t - 3] ^ W[t - 8] ^ W[t - 14] ^ W[t - 16];
69 W[t] = rotl(wt, 1);
70 }
71
72 // FIPS 180-4 6.1.2 Step 2
73 let [a, b, c, d, e] = H;
74
75 // FIPS 180-4 6.1.2 Step 3 with constants and functions from FIPS 180-4 {4.1.1, 4.2.1}
76 let (a, b, c, d, e) = step3(a, b, c, d, e, &W, 0, Wrapping(0x5a827999), ch);
77 let (a, b, c, d, e) = step3(a, b, c, d, e, &W, 20, Wrapping(0x6ed9eba1), parity);
78 let (a, b, c, d, e) = step3(a, b, c, d, e, &W, 40, Wrapping(0x8f1bbcdc), maj);
79 let (a, b, c, d, e) = step3(a, b, c, d, e, &W, 60, Wrapping(0xca62c1d6), parity);
80
81 // FIPS 180-4 6.1.2 Step 4
82 H[0] += a;
83 H[1] += b;
84 H[2] += c;
85 H[3] += d;
86 H[4] += e;
87 }
88
89 H
90}
91
92#[inline(always)]
93fn step3(
94 mut a: W32,
95 mut b: W32,
96 mut c: W32,
97 mut d: W32,
98 mut e: W32,
99 W: &[W32; 80],
100 t: usize,
101 k: W32,
102 f: impl Fn(W32, W32, W32) -> W32,
103) -> (W32, W32, W32, W32, W32) {
104 let W: &[Wrapping] = &W[t..(t + 20)];
105 for W_t: &Wrapping in W.iter() {
106 let T: Wrapping = rotl(x:a, n:5) + f(b, c, d) + e + k + W_t;
107 e = d;
108 d = c;
109 c = rotl(x:b, n:30);
110 b = a;
111 a = T;
112 }
113 (a, b, c, d, e)
114}
115
116#[inline(always)]
117fn rotl(x: W32, n: u32) -> W32 {
118 Wrapping(x.0.rotate_left(n))
119}
120