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
16 use super::sha2::{ch, maj, Word};
17 use crate::{c, polyfill::ChunksFixed};
18 use core::{convert::TryInto, num::Wrapping};
19
20 pub const BLOCK_LEN: usize = 512 / 8;
21 pub const CHAINING_LEN: usize = 160 / 8;
22 pub const OUTPUT_LEN: usize = 160 / 8;
23 const CHAINING_WORDS: usize = CHAINING_LEN / 4;
24
25 type W32 = Wrapping<u32>;
26
27 // FIPS 180-4 4.1.1
28 #[inline]
parity(x: W32, y: W32, z: W32) -> W3229 fn parity(x: W32, y: W32, z: W32) -> W32 {
30 x ^ y ^ z
31 }
32
33 type State = [W32; CHAINING_WORDS];
34 const ROUNDS: usize = 80;
35
block_data_order( state: &mut super::State, data: *const u8, num: c::size_t, )36 pub(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 = unsafe { &mut state.as32 };
42 let state: &mut State = (&mut state[..CHAINING_WORDS]).try_into().unwrap();
43 let data = data as *const [<W32 as Word>::InputBytes; 16];
44 let blocks = unsafe { core::slice::from_raw_parts(data, num) };
45 *state = block_data_order_(*state, blocks)
46 }
47
48 #[inline]
49 #[rustfmt::skip]
block_data_order_(mut H: State, M: &[[<W32 as Word>::InputBytes; 16]]) -> State50 fn 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 W: &[[W32; 20]; 4] = W.chunks_fixed();
67 let (a, b, c, d, e) = step3(a, b, c, d, e, W[0], Wrapping(0x5a827999), ch);
68 let (a, b, c, d, e) = step3(a, b, c, d, e, W[1], Wrapping(0x6ed9eba1), parity);
69 let (a, b, c, d, e) = step3(a, b, c, d, e, W[2], Wrapping(0x8f1bbcdc), maj);
70 let (a, b, c, d, e) = step3(a, b, c, d, e, W[3], Wrapping(0xca62c1d6), parity);
71
72 // FIPS 180-4 6.1.2 Step 4
73 H[0] += a;
74 H[1] += b;
75 H[2] += c;
76 H[3] += d;
77 H[4] += e;
78 }
79
80 H
81 }
82
83 #[inline(always)]
step3( mut a: W32, mut b: W32, mut c: W32, mut d: W32, mut e: W32, W: [W32; 20], k: W32, f: impl Fn(W32, W32, W32) -> W32, ) -> (W32, W32, W32, W32, W32)84 fn step3(
85 mut a: W32,
86 mut b: W32,
87 mut c: W32,
88 mut d: W32,
89 mut e: W32,
90 W: [W32; 20],
91 k: W32,
92 f: impl Fn(W32, W32, W32) -> W32,
93 ) -> (W32, W32, W32, W32, W32) {
94 for W_t in W.iter() {
95 let T = rotl(a, 5) + f(b, c, d) + e + k + W_t;
96 e = d;
97 d = c;
98 c = rotl(b, 30);
99 b = a;
100 a = T;
101 }
102 (a, b, c, d, e)
103 }
104
105 #[inline(always)]
rotl(x: W32, n: u32) -> W32106 fn rotl(x: W32, n: u32) -> W32 {
107 Wrapping(x.0.rotate_left(n))
108 }
109