| #![allow(clippy::many_single_char_names)] |
| use crate::consts::BLOCK_LEN; |
| use core::convert::TryInto; |
| |
| #[inline(always)] |
| fn shl(v: [u32; 4], o: u32) -> [u32; 4] { |
| [v[0] >> o, v[1] >> o, v[2] >> o, v[3] >> o] |
| } |
| |
| #[inline(always)] |
| fn shr(v: [u32; 4], o: u32) -> [u32; 4] { |
| [v[0] << o, v[1] << o, v[2] << o, v[3] << o] |
| } |
| |
| #[inline(always)] |
| fn or(a: [u32; 4], b: [u32; 4]) -> [u32; 4] { |
| [a[0] | b[0], a[1] | b[1], a[2] | b[2], a[3] | b[3]] |
| } |
| |
| #[inline(always)] |
| fn xor(a: [u32; 4], b: [u32; 4]) -> [u32; 4] { |
| [a[0] ^ b[0], a[1] ^ b[1], a[2] ^ b[2], a[3] ^ b[3]] |
| } |
| |
| #[inline(always)] |
| fn add(a: [u32; 4], b: [u32; 4]) -> [u32; 4] { |
| [ |
| a[0].wrapping_add(b[0]), |
| a[1].wrapping_add(b[1]), |
| a[2].wrapping_add(b[2]), |
| a[3].wrapping_add(b[3]), |
| ] |
| } |
| |
| fn sha256load(v2: [u32; 4], v3: [u32; 4]) -> [u32; 4] { |
| [v3[3], v2[0], v2[1], v2[2]] |
| } |
| |
| fn sha256swap(v0: [u32; 4]) -> [u32; 4] { |
| [v0[2], v0[3], v0[0], v0[1]] |
| } |
| |
| fn sha256msg1(v0: [u32; 4], v1: [u32; 4]) -> [u32; 4] { |
| // sigma 0 on vectors |
| #[inline] |
| fn sigma0x4(x: [u32; 4]) -> [u32; 4] { |
| let t1 = or(shl(x, 7), shr(x, 25)); |
| let t2 = or(shl(x, 18), shr(x, 14)); |
| let t3 = shl(x, 3); |
| xor(xor(t1, t2), t3) |
| } |
| |
| add(v0, sigma0x4(sha256load(v0, v1))) |
| } |
| |
| fn sha256msg2(v4: [u32; 4], v3: [u32; 4]) -> [u32; 4] { |
| macro_rules! sigma1 { |
| ($a:expr) => { |
| $a.rotate_right(17) ^ $a.rotate_right(19) ^ ($a >> 10) |
| }; |
| } |
| |
| let [x3, x2, x1, x0] = v4; |
| let [w15, w14, _, _] = v3; |
| |
| let w16 = x0.wrapping_add(sigma1!(w14)); |
| let w17 = x1.wrapping_add(sigma1!(w15)); |
| let w18 = x2.wrapping_add(sigma1!(w16)); |
| let w19 = x3.wrapping_add(sigma1!(w17)); |
| |
| [w19, w18, w17, w16] |
| } |
| |
| fn sha256_digest_round_x2(cdgh: [u32; 4], abef: [u32; 4], wk: [u32; 4]) -> [u32; 4] { |
| macro_rules! big_sigma0 { |
| ($a:expr) => { |
| ($a.rotate_right(2) ^ $a.rotate_right(13) ^ $a.rotate_right(22)) |
| }; |
| } |
| macro_rules! big_sigma1 { |
| ($a:expr) => { |
| ($a.rotate_right(6) ^ $a.rotate_right(11) ^ $a.rotate_right(25)) |
| }; |
| } |
| macro_rules! bool3ary_202 { |
| ($a:expr, $b:expr, $c:expr) => { |
| $c ^ ($a & ($b ^ $c)) |
| }; |
| } // Choose, MD5F, SHA1C |
| macro_rules! bool3ary_232 { |
| ($a:expr, $b:expr, $c:expr) => { |
| ($a & $b) ^ ($a & $c) ^ ($b & $c) |
| }; |
| } // Majority, SHA1M |
| |
| let [_, _, wk1, wk0] = wk; |
| let [a0, b0, e0, f0] = abef; |
| let [c0, d0, g0, h0] = cdgh; |
| |
| // a round |
| let x0 = big_sigma1!(e0) |
| .wrapping_add(bool3ary_202!(e0, f0, g0)) |
| .wrapping_add(wk0) |
| .wrapping_add(h0); |
| let y0 = big_sigma0!(a0).wrapping_add(bool3ary_232!(a0, b0, c0)); |
| let (a1, b1, c1, d1, e1, f1, g1, h1) = ( |
| x0.wrapping_add(y0), |
| a0, |
| b0, |
| c0, |
| x0.wrapping_add(d0), |
| e0, |
| f0, |
| g0, |
| ); |
| |
| // a round |
| let x1 = big_sigma1!(e1) |
| .wrapping_add(bool3ary_202!(e1, f1, g1)) |
| .wrapping_add(wk1) |
| .wrapping_add(h1); |
| let y1 = big_sigma0!(a1).wrapping_add(bool3ary_232!(a1, b1, c1)); |
| let (a2, b2, _, _, e2, f2, _, _) = ( |
| x1.wrapping_add(y1), |
| a1, |
| b1, |
| c1, |
| x1.wrapping_add(d1), |
| e1, |
| f1, |
| g1, |
| ); |
| |
| [a2, b2, e2, f2] |
| } |
| |
| fn schedule(v0: [u32; 4], v1: [u32; 4], v2: [u32; 4], v3: [u32; 4]) -> [u32; 4] { |
| let t1 = sha256msg1(v0, v1); |
| let t2 = sha256load(v2, v3); |
| let t3 = add(t1, t2); |
| sha256msg2(t3, v3) |
| } |
| |
| macro_rules! rounds4 { |
| ($abef:ident, $cdgh:ident, $rest:expr, $i:expr) => {{ |
| let t1 = add($rest, crate::consts::K32X4[$i]); |
| $cdgh = sha256_digest_round_x2($cdgh, $abef, t1); |
| let t2 = sha256swap(t1); |
| $abef = sha256_digest_round_x2($abef, $cdgh, t2); |
| }}; |
| } |
| |
| macro_rules! schedule_rounds4 { |
| ( |
| $abef:ident, $cdgh:ident, |
| $w0:expr, $w1:expr, $w2:expr, $w3:expr, $w4:expr, |
| $i: expr |
| ) => {{ |
| $w4 = schedule($w0, $w1, $w2, $w3); |
| rounds4!($abef, $cdgh, $w4, $i); |
| }}; |
| } |
| |
| /// Process a block with the SHA-256 algorithm. |
| fn sha256_digest_block_u32(state: &mut [u32; 8], block: &[u32; 16]) { |
| let mut abef = [state[0], state[1], state[4], state[5]]; |
| let mut cdgh = [state[2], state[3], state[6], state[7]]; |
| |
| // Rounds 0..64 |
| let mut w0 = [block[3], block[2], block[1], block[0]]; |
| let mut w1 = [block[7], block[6], block[5], block[4]]; |
| let mut w2 = [block[11], block[10], block[9], block[8]]; |
| let mut w3 = [block[15], block[14], block[13], block[12]]; |
| let mut w4; |
| |
| rounds4!(abef, cdgh, w0, 0); |
| rounds4!(abef, cdgh, w1, 1); |
| rounds4!(abef, cdgh, w2, 2); |
| rounds4!(abef, cdgh, w3, 3); |
| schedule_rounds4!(abef, cdgh, w0, w1, w2, w3, w4, 4); |
| schedule_rounds4!(abef, cdgh, w1, w2, w3, w4, w0, 5); |
| schedule_rounds4!(abef, cdgh, w2, w3, w4, w0, w1, 6); |
| schedule_rounds4!(abef, cdgh, w3, w4, w0, w1, w2, 7); |
| schedule_rounds4!(abef, cdgh, w4, w0, w1, w2, w3, 8); |
| schedule_rounds4!(abef, cdgh, w0, w1, w2, w3, w4, 9); |
| schedule_rounds4!(abef, cdgh, w1, w2, w3, w4, w0, 10); |
| schedule_rounds4!(abef, cdgh, w2, w3, w4, w0, w1, 11); |
| schedule_rounds4!(abef, cdgh, w3, w4, w0, w1, w2, 12); |
| schedule_rounds4!(abef, cdgh, w4, w0, w1, w2, w3, 13); |
| schedule_rounds4!(abef, cdgh, w0, w1, w2, w3, w4, 14); |
| schedule_rounds4!(abef, cdgh, w1, w2, w3, w4, w0, 15); |
| |
| let [a, b, e, f] = abef; |
| let [c, d, g, h] = cdgh; |
| |
| state[0] = state[0].wrapping_add(a); |
| state[1] = state[1].wrapping_add(b); |
| state[2] = state[2].wrapping_add(c); |
| state[3] = state[3].wrapping_add(d); |
| state[4] = state[4].wrapping_add(e); |
| state[5] = state[5].wrapping_add(f); |
| state[6] = state[6].wrapping_add(g); |
| state[7] = state[7].wrapping_add(h); |
| } |
| |
| pub fn compress(state: &mut [u32; 8], blocks: &[[u8; 64]]) { |
| let mut block_u32 = [0u32; BLOCK_LEN]; |
| // since LLVM can't properly use aliasing yet it will make |
| // unnecessary state stores without this copy |
| let mut state_cpy = *state; |
| for block in blocks { |
| for (o, chunk) in block_u32.iter_mut().zip(block.chunks_exact(4)) { |
| *o = u32::from_be_bytes(chunk.try_into().unwrap()); |
| } |
| sha256_digest_block_u32(&mut state_cpy, &block_u32); |
| } |
| *state = state_cpy; |
| } |