1// Copyright 2015-2016 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::sha2::{ch, maj, Word};
17use crate::c;
18use core::num::Wrapping;
19
20pub const BLOCK_LEN: usize = 512 / 8;
21pub const CHAINING_LEN: usize = 160 / 8;
22pub const OUTPUT_LEN: usize = 160 / 8;
23const CHAINING_WORDS: usize = CHAINING_LEN / 4;
24
25type W32 = Wrapping<u32>;
26
27// FIPS 180-4 4.1.1
28#[inline]
29fn parity(x: W32, y: W32, z: W32) -> W32 {
30 x ^ y ^ z
31}
32
33type State = [W32; CHAINING_WORDS];
34const ROUNDS: usize = 80;
35
36pub(super) extern "C" fn block_data_order(
37 state: &mut super::State,
38 data: *const u8,
39 num: c::size_t,
40) {
41 let state: &mut [Wrapping; 8] = unsafe { &mut state.as32 };
42 let state: &mut State = (&mut state[..CHAINING_WORDS]).try_into().unwrap();
43 let data: *const [[u8; 4]; 16] = data.cast::<[<W32 as Word>::InputBytes; 16]>();
44 let blocks: &[[[u8; 4]; 16]] = unsafe { core::slice::from_raw_parts(data, len:num) };
45 *state = block_data_order_(*state, M:blocks)
46}
47
48#[inline]
49#[rustfmt::skip]
50fn block_data_order_(mut H: State, M: &[[<W32 as Word>::InputBytes; 16]]) -> State {
51 for M in M {
52 // FIPS 180-4 6.1.2 Step 1
53 let mut W: [W32; ROUNDS] = [W32::ZERO; ROUNDS];
54 for t in 0..16 {
55 W[t] = W32::from_be_bytes(M[t]);
56 }
57 for t in 16..ROUNDS {
58 let wt = W[t - 3] ^ W[t - 8] ^ W[t - 14] ^ W[t - 16];
59 W[t] = rotl(wt, 1);
60 }
61
62 // FIPS 180-4 6.1.2 Step 2
63 let [a, b, c, d, e] = H;
64
65 // FIPS 180-4 6.1.2 Step 3 with constants and functions from FIPS 180-4 {4.1.1, 4.2.1}
66 let (a, b, c, d, e) = step3(a, b, c, d, e, &W, 0, Wrapping(0x5a827999), ch);
67 let (a, b, c, d, e) = step3(a, b, c, d, e, &W, 20, Wrapping(0x6ed9eba1), parity);
68 let (a, b, c, d, e) = step3(a, b, c, d, e, &W, 40, Wrapping(0x8f1bbcdc), maj);
69 let (a, b, c, d, e) = step3(a, b, c, d, e, &W, 60, Wrapping(0xca62c1d6), parity);
70
71 // FIPS 180-4 6.1.2 Step 4
72 H[0] += a;
73 H[1] += b;
74 H[2] += c;
75 H[3] += d;
76 H[4] += e;
77 }
78
79 H
80}
81
82#[inline(always)]
83fn step3(
84 mut a: W32,
85 mut b: W32,
86 mut c: W32,
87 mut d: W32,
88 mut e: W32,
89 W: &[W32; 80],
90 t: usize,
91 k: W32,
92 f: impl Fn(W32, W32, W32) -> W32,
93) -> (W32, W32, W32, W32, W32) {
94 let W: &[Wrapping] = &W[t..(t + 20)];
95 for W_t: &Wrapping in W.iter() {
96 let T: Wrapping = rotl(x:a, n:5) + f(b, c, d) + e + k + W_t;
97 e = d;
98 d = c;
99 c = rotl(x:b, n:30);
100 b = a;
101 a = T;
102 }
103 (a, b, c, d, e)
104}
105
106#[inline(always)]
107fn rotl(x: W32, n: u32) -> W32 {
108 Wrapping(x.0.rotate_left(n))
109}
110