use super::Lookup2;
use core::cmp::min;
use digest::{Digest, FixedOutput, Output, Update};
#[deprecated = "Use [`Hash3`] for better performance while maintaining portability"]
#[derive(Default)]
pub struct Hash;
impl Lookup2<Hash> {
pub fn digest_unchecked(data: &[u8]) -> u32 {
let hash = Lookup2::<Hash>::digest(data);
u32::from_le_bytes(hash[..].try_into().unwrap())
}
#[inline]
pub(crate) const fn add_u32_le(acc: u32, b1: u8, b2: u8, b3: u8, b4: u8) -> u32 {
acc.wrapping_add(b1 as u32)
.wrapping_add((b2 as u32) << 8)
.wrapping_add((b3 as u32) << 16)
.wrapping_add((b4 as u32) << 24)
}
#[inline]
pub(crate) const fn add_msb(acc: u32, b1: u8, mask: u8) -> u32 {
acc.wrapping_add((b1 as u32) << mask)
}
#[inline]
pub(crate) const fn add_lsb(acc: u32, b1: u8) -> u32 {
acc.wrapping_add(b1 as u32)
}
}
impl Update for Lookup2<Hash> {
#[rustfmt::skip]
fn update(&mut self, mut data: &[u8]) {
self.total_length += data.len();
if self.rem_offset > 0 {
let remaining = min(12_u8.saturating_sub(self.rem_offset) as usize, data.len());
self.rem[self.rem_offset as usize..remaining + self.rem_offset as usize].copy_from_slice(&data[..remaining]);
self.rem_offset += remaining as u8;
data = &data[remaining..];
if self.rem_offset < 12 { return;}
self.state[0] = Self::add_u32_le(self.state[0], self.rem[0], self.rem[1], self.rem[02], self.rem[03] );
self.state[1] = Self::add_u32_le(self.state[1], self.rem[4], self.rem[5], self.rem[06], self.rem[07] );
self.state[2] = Self::add_u32_le(self.state[2], self.rem[8], self.rem[9], self.rem[10], self.rem[11] );
self.state = Self::mix(self.state);
self.rem_offset = 0;
}
while data.len() >= 12 {
self.state[0] = Self::add_u32_le(self.state[0], data[0], data[1], data[02], data[03]);
self.state[1] = Self::add_u32_le(self.state[1], data[4], data[5], data[06], data[07]);
self.state[2] = Self::add_u32_le(self.state[2], data[8], data[9], data[10], data[11]);
self.state = Self::mix(self.state);
data = &data[12..];
}
self.rem[self.rem_offset as usize..self.rem_offset as usize + data.len()].copy_from_slice(data);
self.rem_offset += data.len() as u8
}
}
impl FixedOutput for Lookup2<Hash> {
#[rustfmt::skip]
fn finalize_into(mut self, out: &mut Output<Self>) {
self.state[2] = self.state[2].wrapping_add(self.total_length as u32);
if self.rem_offset == 11 { self.state[2] = Self::add_msb(self.state[2], self.rem[10], 24); }
if self.rem_offset >= 10 { self.state[2] = Self::add_msb(self.state[2], self.rem[09], 16); }
if self.rem_offset >= 09 { self.state[2] = Self::add_msb(self.state[2], self.rem[08], 08); }
if self.rem_offset >= 08 { self.state[1] = Self::add_msb(self.state[1], self.rem[07], 24); }
if self.rem_offset >= 07 { self.state[1] = Self::add_msb(self.state[1], self.rem[06], 16); }
if self.rem_offset >= 06 { self.state[1] = Self::add_msb(self.state[1], self.rem[05], 08); }
if self.rem_offset >= 05 { self.state[1] = Self::add_lsb(self.state[1], self.rem[04]); }
if self.rem_offset >= 04 { self.state[0] = Self::add_msb(self.state[0], self.rem[03], 24); }
if self.rem_offset >= 03 { self.state[0] = Self::add_msb(self.state[0], self.rem[02], 16); }
if self.rem_offset >= 02 { self.state[0] = Self::add_msb(self.state[0], self.rem[01], 08); }
if self.rem_offset >= 01 { self.state[0] = Self::add_lsb(self.state[0], self.rem[00]); }
self.state = Self::mix(self.state);
out.copy_from_slice(&self.state[2].to_le_bytes())
}
}