use core::arch::x86_64::*;
use super::K256;
#[target_feature(enable = "sha,sse2,ssse3,sse4.1")]
pub unsafe fn compress(state: &mut [u32; 8], blocks: &[u8]) {
debug_assert!(blocks.len().is_multiple_of(64));
let shuffle = _mm_set_epi64x(
0x0c0d_0e0f_0809_0a0bu64 as i64,
0x0405_0607_0001_0203u64 as i64,
);
let mut tmp = unsafe { _mm_loadu_si128(state.as_ptr() as *const __m128i) };
let mut state1 = unsafe { _mm_loadu_si128(state.as_ptr().add(4) as *const __m128i) };
tmp = _mm_shuffle_epi32(tmp, 0xb1); state1 = _mm_shuffle_epi32(state1, 0x1b); let mut state0 = _mm_alignr_epi8(tmp, state1, 8); state1 = _mm_blend_epi16(state1, tmp, 0xf0);
for block in blocks.chunks_exact(64) {
let save0 = state0;
let save1 = state1;
let mut m0 = _mm_shuffle_epi8(
unsafe { _mm_loadu_si128(block.as_ptr() as *const __m128i) },
shuffle,
);
let mut m1 = _mm_shuffle_epi8(
unsafe { _mm_loadu_si128(block.as_ptr().add(16) as *const __m128i) },
shuffle,
);
let mut m2 = _mm_shuffle_epi8(
unsafe { _mm_loadu_si128(block.as_ptr().add(32) as *const __m128i) },
shuffle,
);
let mut m3 = _mm_shuffle_epi8(
unsafe { _mm_loadu_si128(block.as_ptr().add(48) as *const __m128i) },
shuffle,
);
macro_rules! rounds {
($m:expr, $i:literal) => {{
let k = unsafe { _mm_loadu_si128(K256.as_ptr().add($i * 4) as *const __m128i) };
let mut w = _mm_add_epi32($m, k);
state1 = _mm_sha256rnds2_epu32(state1, state0, w);
w = _mm_shuffle_epi32(w, 0x0e);
state0 = _mm_sha256rnds2_epu32(state0, state1, w);
}};
}
macro_rules! schedule {
($a:expr, $b:expr, $c:expr, $d:expr) => {{
$a = _mm_sha256msg1_epu32($a, $b);
let t = _mm_alignr_epi8($d, $c, 4);
$a = _mm_add_epi32($a, t);
$a = _mm_sha256msg2_epu32($a, $d);
}};
}
rounds!(m0, 0);
rounds!(m1, 1);
rounds!(m2, 2);
rounds!(m3, 3);
schedule!(m0, m1, m2, m3);
rounds!(m0, 4);
schedule!(m1, m2, m3, m0);
rounds!(m1, 5);
schedule!(m2, m3, m0, m1);
rounds!(m2, 6);
schedule!(m3, m0, m1, m2);
rounds!(m3, 7);
schedule!(m0, m1, m2, m3);
rounds!(m0, 8);
schedule!(m1, m2, m3, m0);
rounds!(m1, 9);
schedule!(m2, m3, m0, m1);
rounds!(m2, 10);
schedule!(m3, m0, m1, m2);
rounds!(m3, 11);
schedule!(m0, m1, m2, m3);
rounds!(m0, 12);
schedule!(m1, m2, m3, m0);
rounds!(m1, 13);
schedule!(m2, m3, m0, m1);
rounds!(m2, 14);
schedule!(m3, m0, m1, m2);
rounds!(m3, 15);
state0 = _mm_add_epi32(state0, save0);
state1 = _mm_add_epi32(state1, save1);
}
tmp = _mm_shuffle_epi32(state0, 0x1b); state1 = _mm_shuffle_epi32(state1, 0xb1); state0 = _mm_blend_epi16(tmp, state1, 0xf0); state1 = _mm_alignr_epi8(state1, tmp, 8);
unsafe {
_mm_storeu_si128(state.as_mut_ptr() as *mut __m128i, state0);
_mm_storeu_si128(state.as_mut_ptr().add(4) as *mut __m128i, state1);
}
}