use super::{GOLDEN_RATIO, Hash, Lookup2};
use crate::extensions::ext_slice_u8::ExtSliceU8;
use core::cmp::min;
use digest::{Digest, FixedOutput, Output, Update};
pub struct Hash3;
impl Lookup2<Hash3> {
pub fn digest_unchecked(data: &[u8]) -> u32 {
let hash = Lookup2::<Hash3>::digest(data);
u32::from_le_bytes(hash[..].try_into().unwrap())
}
}
impl Update for Lookup2<Hash3> {
#[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.state[0].wrapping_add(self.rem[0..].read_u32_le());
self.state[1] = self.state[1].wrapping_add(self.rem[4..].read_u32_le());
self.state[2] = self.state[2].wrapping_add(self.rem[8..].read_u32_le());
self.state = Self::mix(self.state);
self.rem_offset = 0;
}
while data.len() >= 12 {
self.state[0] = self.state[0].wrapping_add(data[0..].read_u32_le());
self.state[1] = self.state[1].wrapping_add(data[4..].read_u32_le());
self.state[2] = self.state[2].wrapping_add(data[8..].read_u32_le());
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<Hash3> {
#[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] = Lookup2::add_msb(self.state[2], self.rem[10], 24); }
if self.rem_offset >= 10 { self.state[2] = Lookup2::add_msb(self.state[2], self.rem[09], 16); }
if self.rem_offset >= 09 { self.state[2] = Lookup2::add_msb(self.state[2], self.rem[08], 08); }
if self.rem_offset >= 08 { self.state[1] = Lookup2::add_msb(self.state[1], self.rem[07], 24); }
if self.rem_offset >= 07 { self.state[1] = Lookup2::add_msb(self.state[1], self.rem[06], 16); }
if self.rem_offset >= 06 { self.state[1] = Lookup2::add_msb(self.state[1], self.rem[05], 08); }
if self.rem_offset >= 05 { self.state[1] = Lookup2::add_lsb(self.state[1], self.rem[04]); }
if self.rem_offset >= 04 { self.state[0] = Lookup2::add_msb(self.state[0], self.rem[03], 24); }
if self.rem_offset >= 03 { self.state[0] = Lookup2::add_msb(self.state[0], self.rem[02], 16); }
if self.rem_offset >= 02 { self.state[0] = Lookup2::add_msb(self.state[0], self.rem[01], 08); }
if self.rem_offset >= 01 { self.state[0] = Lookup2::add_lsb(self.state[0], self.rem[00]); }
self.state = Self::mix(self.state);
out.copy_from_slice(&self.state[2].to_le_bytes())
}
}