hs1-siv 0.2.0-pre.0

Pure Rust implementation of the HS1-SIV Authenticated Encryption with Additional Data Cipher. Based on ChaCha.
Documentation
use super::{mask, poly_step, Array, Hasher, Hs1Params};
#[cfg(target_arch = "x86")]
use core::arch::x86::*;
#[cfg(target_arch = "x86_64")]
use core::arch::x86_64::*;

impl<P: Hs1Params> Hasher<P> {
    #[inline(always)]
    #[cfg(target_feature = "sse2")]
    pub(super) unsafe fn update_block_sse2(&mut self) -> &mut Self {
        assert!(usize::from(self.bytes) <= self.block_u8().len());

        #[inline(always)]
        unsafe fn nh_step(x: &[u32; 4], y: &[u32; 4]) -> __m128i {
            let x = x.as_ptr().cast::<__m128i>().read_unaligned();
            let y = y.as_ptr().cast::<__m128i>().read_unaligned();
            let xy = _mm_add_epi32(x, y);

            let a_b = _mm_shuffle_epi32::<0b00_01_00_00>(xy);
            let c_d = _mm_shuffle_epi32::<0b00_11_00_10>(xy);
            _mm_mul_epu32(a_b, c_d)
        }

        let m_ints = &self.block;

        let block16_count = usize::from(((self.bytes + 15) / 16).max(1));

        let mut nh: Array<__m128i, P::T> = Array::from_fn(|_| _mm_setzero_si128());
        for (i0, m_ints_i) in m_ints.chunks_exact(4).enumerate().take(block16_count) {
            for (nh_i, k_n_i_i) in nh.iter_mut().zip(self.k.nh.chunks_exact(4).skip(i0)) {
                let k_n_i_i = k_n_i_i.try_into().expect("exactly 4 elements");
                let m_ints_i = m_ints_i.try_into().expect("exactly 4 elements");
                let s = nh_step(k_n_i_i, m_ints_i);
                *nh_i = _mm_add_epi64(*nh_i, s);
            }
        }

        nh.iter()
            .map(|nh_i| {
                let &[ac, bd] = &*(nh_i as *const _ as *const [u64; 2]);
                ac.wrapping_add(bd)
            })
            .map(|nh_i| (nh_i.wrapping_add(u64::from(self.bytes) & mask(4))) & mask(60))
            .zip(self.k.poly.iter())
            .zip(self.h.iter_mut())
            .for_each(|((a_i, &k_p_i), h_i)| *h_i = poly_step(*h_i, a_i, k_p_i));

        self.bytes = 0;

        self
    }
}