use digest::Digest;
use crate::extensions::ext_slice_u8::ExtSliceU8;
use crate::utils::rot32;
pub struct Lookup3 {}
impl Lookup3 {
#[inline]
#[rustfmt::skip]
const fn mix(mut states: [u32; 3]) -> [u32; 3] {
states[0] = states[0].wrapping_sub(states[2]); states[0] ^= rot32(states[2], 4); states[2] = states[2].wrapping_add(states[1]);
states[1] = states[1].wrapping_sub(states[0]); states[1] ^= rot32(states[0], 6); states[0] = states[0].wrapping_add(states[2]);
states[2] = states[2].wrapping_sub(states[1]); states[2] ^= rot32(states[1], 8); states[1] = states[1].wrapping_add(states[0]);
states[0] = states[0].wrapping_sub(states[2]); states[0] ^= rot32(states[2],16); states[2] = states[2].wrapping_add(states[1]);
states[1] = states[1].wrapping_sub(states[0]); states[1] ^= rot32(states[0],19); states[0] = states[0].wrapping_add(states[2]);
states[2] = states[2].wrapping_sub(states[1]); states[2] ^= rot32(states[1], 4); states[1] = states[1].wrapping_add(states[0]);
states
}
#[inline]
#[rustfmt::skip]
const fn r#final(mut states: [u32; 3]) -> [u32; 3] {
states[2] ^= states[1]; states[2] = states[2].wrapping_sub(rot32(states[1],14));
states[0] ^= states[2]; states[0] = states[0].wrapping_sub(rot32(states[2],11));
states[1] ^= states[0]; states[1] = states[1].wrapping_sub(rot32(states[0],25));
states[2] ^= states[1]; states[2] = states[2].wrapping_sub(rot32(states[1],16));
states[0] ^= states[2]; states[0] = states[0].wrapping_sub(rot32(states[2],04));
states[1] ^= states[0]; states[1] = states[1].wrapping_sub(rot32(states[0],14));
states[2] ^= states[1]; states[2] = states[2].wrapping_sub(rot32(states[1],24));
states
}
pub fn hash_word(mut data: &[u32], seed1: u32, seed2: Option<u32>) -> (u32, Option<u32>) {
let starting_length = data.len() as u32;
let initial_state = 0xdeadbeef + ((starting_length) << 2) + seed1;
let mut states = [initial_state, initial_state, initial_state];
if let Some(seed) = seed2 {
states[2] = states[2].wrapping_add(seed);
}
while data.len() > 3 {
states[0] = states[0].wrapping_add(data[0]);
states[1] = states[1].wrapping_add(data[1]);
states[2] = states[2].wrapping_add(data[2]);
states = Self::mix(states);
data = &data[3..];
}
if data.len() == 3 {
states[2] = states[2].wrapping_add(data[2])
}
if (2..=3).contains(&data.len()) {
states[1] = states[1].wrapping_add(data[1])
}
if (1..=3).contains(&data.len()) {
states[2] = states[2].wrapping_add(data[0]);
states = Self::r#final(states);
}
(states[2], seed2.map(|_| states[1]))
}
#[cfg(target_endian = "little")]
#[rustfmt::skip]
pub fn hash_little(mut data: &[u8], seed1: u32, seed2: Option<u32>) -> (u32, Option<u32>) {
let initial_state = 0xdeadbeef + (data.len() as u32) + seed1;
let mut states = [initial_state, initial_state, initial_state];
if let Some(seed2) = seed2 {
states[2] = states[2].wrapping_add(seed2)
}
while data.len() > 12 {
states[0] = states[0].wrapping_add(data[4 * 0..].read_u32_le());
states[1] = states[1].wrapping_add(data[4 * 1..].read_u32_le());
states[2] = states[2].wrapping_add(data[4 * 2..].read_u32_le());
states = Self::mix(states);
data = &data[4 * 3..];
}
match data.len() {
12 => { states[2] = states[2].wrapping_add(data[4 * 2..].read_u32_le()); states[1] = states[1].wrapping_add(data[4 * 1..].read_u32_le()); states[0] = states[0].wrapping_add(data[4 * 0..].read_u32_le()); }
11 => { states[2] = states[2].wrapping_add(data[4 * 2..].read_u32_le() & 0xffffff); states[1] = states[1].wrapping_add(data[4 * 1..].read_u32_le()); states[0] = states[0].wrapping_add(data[4 * 0..].read_u32_le()); }
10 => { states[2] = states[2].wrapping_add(data[4 * 2..].read_u32_le() & 0xffff); states[1] = states[1].wrapping_add(data[4 * 1..].read_u32_le()); states[0] = states[0].wrapping_add(data[4 * 0..].read_u32_le()); }
09 => { states[2] = states[2].wrapping_add(data[4 * 2..].read_u32_le() & 0xff); states[1] = states[1].wrapping_add(data[4 * 1..].read_u32_le()); states[0] = states[0].wrapping_add(data[4 * 0..].read_u32_le()); }
08 => { states[1] = states[1].wrapping_add(data[4 * 1..].read_u32_le()); states[0] = states[0].wrapping_add(data[4 * 0..].read_u32_le()); }
07 => { states[1] = states[1].wrapping_add(data[4 * 1..].read_u32_le() & 0xffffff); states[0] = states[0].wrapping_add(data[4 * 0..].read_u32_le()); }
06 => { states[1] = states[1].wrapping_add(data[4 * 1..].read_u32_le() & 0xffff); states[0] = states[0].wrapping_add(data[4 * 0..].read_u32_le()); }
05 => { states[1] = states[1].wrapping_add(data[4 * 1..].read_u32_le() & 0xff); states[0] = states[0].wrapping_add(data[4 * 0..].read_u32_le()); }
04 => { states[0] = states[0].wrapping_add(data[4 * 0..].read_u32_le()); }
03 => { states[0] = states[0].wrapping_add(data[4 * 0..].read_u32_le() & 0xffffff); }
02 => { states[0] = states[0].wrapping_add(data[4 * 0..].read_u32_le() & 0xffff); }
01 => { states[0] = states[0].wrapping_add(data[4 * 0..].read_u32_le() & 0xff); }
0 => return (states[2], seed2.map(|_| states[1])),
_ => unreachable!(),
}
states = Self::r#final(states);
(states[2], seed2.map(|_| states[1]))
}
#[cfg(not(target_endian = "little"))]
#[rustfmt::skip]
pub fn hash_little(mut data: &[u8], seed1: u32, seed2: Option<u32>) -> (u32, Option<u32>) {
let initial_state = 0xdeadbeef + (data.len() as u32) + seed1;
let mut states = [initial_state, initial_state, initial_state];
if let Some(seed2) = seed2 {
states[2] = states[2].wrapping_add(seed2)
}
while data.len() > 12 {
states[0] = states[0] .wrapping_add(data[0] as u32);
states[0] = states[0] .wrapping_add((data[1] as u32) << 8);
states[0] = states[0] .wrapping_add((data[2] as u32) << 16);
states[0] = states[0] .wrapping_add((data[3] as u32) << 24);
states[1] = states[1] .wrapping_add(data[4] as u32);
states[1] = states[1] .wrapping_add((data[5] as u32) << 8);
states[1] = states[1] .wrapping_add((data[6] as u32) << 16);
states[1] = states[1] .wrapping_add((data[7] as u32) << 24);
states[2] = states[2] .wrapping_add(data[8] as u32);
states[2] = states[2] .wrapping_add((data[9] as u32) << 8);
states[2] = states[2] .wrapping_add((data[10] as u32) << 16);
states[2] = states[2] .wrapping_add((data[11] as u32) << 24);
states = Self::mix(states);
data = &data[4 * 3..];
}
if data.len() == 12 { states[2] = states[2].wrapping_add((data[11] as u32) << 24); }
if (11..=12).contains(&data.len()) { states[2] = states[2].wrapping_add((data[10] as u32) << 16); }
if (10..=12).contains(&data.len()) { states[2] = states[2].wrapping_add((data[9] as u32) << 8); }
if (09..=12).contains(&data.len()) { states[2] = states[2].wrapping_add(data[8] as u32); }
if (08..=12).contains(&data.len()) { states[1] = states[1].wrapping_add((data[7] as u32) << 24); }
if (07..=12).contains(&data.len()) { states[1] = states[1].wrapping_add((data[6] as u32) << 16); }
if (06..=12).contains(&data.len()) { states[1] = states[1].wrapping_add((data[5] as u32) << 8); }
if (05..=12).contains(&data.len()) { states[1] = states[1].wrapping_add(data[4] as u32); }
if (04..=12).contains(&data.len()) { states[0] = states[0].wrapping_add((data[3] as u32) << 24); }
if (03..=12).contains(&data.len()) { states[0] = states[0].wrapping_add((data[2] as u32) << 16); }
if (02..=12).contains(&data.len()) { states[0] = states[0].wrapping_add((data[1] as u32) << 8); }
if (01..=12).contains(&data.len()) { states[0] = states[0].wrapping_add(data[0] as u32); }
if data.len() == 00 { return (states[2], seed2.map(|_| states[1])); }
states = Self::r#final(states);
(states[2], seed2.map(|_| states[1]))
}
#[cfg(target_endian = "big")]
#[rustfmt::skip]
fn hash_big(mut data: &[u8], seed1: u32, seed2: Option<u32>) -> (u32, Option<u32>) {
let initial_state = 0xdeadbeef + (data.len() as u32) + seed1;
let mut states = [initial_state, initial_state, initial_state];
if let Some(seed2) = seed2 {
states[2] = states[2].wrapping_add(seed2)
}
while data.len() > 12 {
states[0] = states[0].wrapping_add(data[4 * 0..].read_u32_be());
states[1] = states[1].wrapping_add(data[4 * 1..].read_u32_be());
states[2] = states[2].wrapping_add(data[4 * 2..].read_u32_be());
states = Self::mix(states);
data = &data[4 * 3..];
}
match data.len() {
12 => { states[2] = states[2].wrapping_add(data[4 * 2..].read_u32_be()); states[1] = states[1].wrapping_add(data[4 * 1..].read_u32_be()); states[0] = states[0].wrapping_add(data[4 * 0..].read_u32_be()); }
11 => { states[2] = states[2].wrapping_add(data[4 * 2..].read_u32_be() & 0xffffff00); states[1] = states[1].wrapping_add(data[4 * 1..].read_u32_be()); states[0] = states[0].wrapping_add(data[4 * 0..].read_u32_be()); }
10 => { states[2] = states[2].wrapping_add(data[4 * 2..].read_u32_be() & 0xffff0000); states[1] = states[1].wrapping_add(data[4 * 1..].read_u32_be()); states[0] = states[0].wrapping_add(data[4 * 0..].read_u32_be()); }
09 => { states[2] = states[2].wrapping_add(data[4 * 2..].read_u32_be() & 0xff000000); states[1] = states[1].wrapping_add(data[4 * 1..].read_u32_be()); states[0] = states[0].wrapping_add(data[4 * 0..].read_u32_be()); }
08 => { states[1] = states[1].wrapping_add(data[4 * 1..].read_u32_be()); states[0] = states[0].wrapping_add(data[4 * 0..].read_u32_be()); }
07 => { states[1] = states[1].wrapping_add(data[4 * 1..].read_u32_be() & 0xffffff00); states[0] = states[0].wrapping_add(data[4 * 0..].read_u32_be()); }
06 => { states[1] = states[1].wrapping_add(data[4 * 1..].read_u32_be() & 0xffff0000); states[0] = states[0].wrapping_add(data[4 * 0..].read_u32_be()); }
05 => { states[1] = states[1].wrapping_add(data[4 * 1..].read_u32_be() & 0xff000000); states[0] = states[0].wrapping_add(data[4 * 0..].read_u32_be()); }
04 => { states[0] = states[0].wrapping_add(data[4 * 0..].read_u32_be()); }
03 => { states[0] = states[0].wrapping_add(data[4 * 0..].read_u32_be() & 0xffffff00); }
02 => { states[0] = states[0].wrapping_add(data[4 * 0..].read_u32_be() & 0xffff0000); }
01 => { states[0] = states[0].wrapping_add(data[4 * 0..].read_u32_be() & 0xff000000); }
00 => return (states[2], seed2.map(|_| states[1])),
_ => unreachable!(),
}
states = Self::r#final(states);
(states[2], seed2.map(|_| states[1]))
}
#[cfg(not(target_endian = "big"))]
#[rustfmt::skip]
fn hash_big(mut data: &[u8], seed1: u32, seed2: Option<u32>) -> (u32, Option<u32>) {
let initial_state = 0xdeadbeef + (data.len() as u32) + seed1;
let mut states = [initial_state, initial_state, initial_state];
if let Some(seed2) = seed2 {
states[2] = states[2].wrapping_add(seed2)
}
while data.len() > 12 {
states[0] = states[0].wrapping_add((data[00] as u32) << 24);
states[0] = states[0].wrapping_add((data[01] as u32) << 16);
states[0] = states[0].wrapping_add((data[02] as u32) << 08);
states[0] = states[0].wrapping_add((data[03] as u32));
states[1] = states[0].wrapping_add((data[04] as u32) << 24);
states[1] = states[0].wrapping_add((data[05] as u32) << 16);
states[1] = states[0].wrapping_add((data[06] as u32) << 08);
states[1] = states[0].wrapping_add((data[07] as u32));
states[2] = states[0].wrapping_add((data[08] as u32) << 24);
states[2] = states[0].wrapping_add((data[09] as u32) << 16);
states[2] = states[0].wrapping_add((data[10] as u32) << 08);
states[2] = states[0].wrapping_add((data[11] as u32));
states = Self::mix(states);
data = &data[4 * 3..];
}
if data.len() == 12 { states[2] = states[2].wrapping_add((data[11] as u32)); }
if (11..=12).contains(&data.len()) { states[2] = states[2].wrapping_add((data[10] as u32) << 08); }
if (10..=12).contains(&data.len()) { states[2] = states[2].wrapping_add((data[09] as u32) << 16); }
if (09..=12).contains(&data.len()) { states[2] = states[2].wrapping_add((data[08] as u32) << 24); }
if (08..=12).contains(&data.len()) { states[1] = states[1].wrapping_add((data[07] as u32)); }
if (07..=12).contains(&data.len()) { states[1] = states[1].wrapping_add((data[06] as u32) << 08); }
if (06..=12).contains(&data.len()) { states[1] = states[1].wrapping_add((data[05] as u32) << 16); }
if (05..=12).contains(&data.len()) { states[1] = states[1].wrapping_add((data[04] as u32) << 24); }
if (04..=12).contains(&data.len()) { states[0] = states[0].wrapping_add((data[03] as u32)); }
if (03..=12).contains(&data.len()) { states[0] = states[0].wrapping_add((data[02] as u32) << 08); }
if (02..=12).contains(&data.len()) { states[0] = states[0].wrapping_add((data[01] as u32) << 16); }
if (01..=12).contains(&data.len()) { states[0] = states[0].wrapping_add((data[00] as u32) << 24); }
if data.len() == 00 { return (states[2], seed2.map(|_| states[1])); }
states = Self::r#final(states);
(states[2], seed2.map(|_| states[1]))
}
}
#[cfg(test)]
mod tests {
use super::*;
#[cfg(target_endian = "little")]
#[test]
fn test_hash_little() {
let str = b"hello world";
let (hash, _) = Lookup3::hash_little(str, 0, None);
assert_eq!(hash, 0x4AA94E65)
}
#[cfg(not(target_endian = "little"))]
#[test]
fn test_hash_little() {
let str = b"hello world";
let (hash, _) = Lookup3::hash_little(str, 0, None);
assert_eq!(hash, 0x4AA94E65)
}
#[test]
#[ignore = "Don't have a way to properly test this hash method. Don't have any big-endian machines"]
#[cfg(target_endian = "big")]
#[test]
fn test_hash_big() {
let str = b"hello world";
let (hash, _) = Lookup3::hash_big(str, 0, None);
assert_eq!(hash, 0xF1DFDD63)
}
#[test]
#[ignore = "Don't have a way to properly test this hash method. Don't have any big-endian machines"]
#[cfg(not(target_endian = "big"))]
#[test]
fn test_hash_big() {
let str = b"hello world";
let (hash, _) = Lookup3::hash_big(str, 0, None);
assert_eq!(hash, 0xC7CE1547)
}
}