use super::sha2::{ch, maj, Word};
use crate::{c, polyfill::ChunksFixed};
use core::num::Wrapping;
pub const BLOCK_LEN: usize = 512 / 8;
pub const CHAINING_LEN: usize = 160 / 8;
pub const OUTPUT_LEN: usize = 160 / 8;
const CHAINING_WORDS: usize = CHAINING_LEN / 4;
type W32 = Wrapping<u32>;
#[inline]
fn parity(x: W32, y: W32, z: W32) -> W32 {
x ^ y ^ z
}
type State = [W32; CHAINING_WORDS];
const ROUNDS: usize = 80;
pub(super) extern "C" fn block_data_order(
state: &mut super::State,
data: *const u8,
num: c::size_t,
) {
let state = unsafe { &mut state.as32 };
let state: &mut State = (&mut state[..CHAINING_WORDS]).try_into().unwrap();
let data = data as *const [<W32 as Word>::InputBytes; 16];
let blocks = unsafe { core::slice::from_raw_parts(data, num) };
*state = block_data_order_(*state, blocks)
}
#[inline]
#[rustfmt::skip]
fn block_data_order_(mut H: State, M: &[[<W32 as Word>::InputBytes; 16]]) -> State {
for M in M {
let mut W: [W32; ROUNDS] = [W32::ZERO; ROUNDS];
for t in 0..16 {
W[t] = W32::from_be_bytes(M[t]);
}
for t in 16..ROUNDS {
let wt = W[t - 3] ^ W[t - 8] ^ W[t - 14] ^ W[t - 16];
W[t] = rotl(wt, 1);
}
let [a, b, c, d, e] = H;
let W: &[[W32; 20]; 4] = W.chunks_fixed();
let (a, b, c, d, e) = step3(a, b, c, d, e, W[0], Wrapping(0x5a827999), ch);
let (a, b, c, d, e) = step3(a, b, c, d, e, W[1], Wrapping(0x6ed9eba1), parity);
let (a, b, c, d, e) = step3(a, b, c, d, e, W[2], Wrapping(0x8f1bbcdc), maj);
let (a, b, c, d, e) = step3(a, b, c, d, e, W[3], Wrapping(0xca62c1d6), parity);
H[0] += a;
H[1] += b;
H[2] += c;
H[3] += d;
H[4] += e;
}
H
}
#[inline(always)]
fn 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) {
for W_t in W.iter() {
let T = rotl(a, 5) + f(b, c, d) + e + k + W_t;
e = d;
d = c;
c = rotl(b, 30);
b = a;
a = T;
}
(a, b, c, d, e)
}
#[inline(always)]
fn rotl(x: W32, n: u32) -> W32 {
Wrapping(x.0.rotate_left(n))
}