use crate::convert::Convert;
use std::default::Default;
use std::hash::{Hasher};
use arrayref::*;
use const_random::const_random;
const DEFAULT_KEYS: [u64;2] = [const_random!(u64), const_random!(u64)];
const PAD : u128 = 0xF0E1_D2C3_B4A5_9687_7869_5A4B_3C2D_1E0F;
#[derive(Debug, Clone)]
pub struct AHasher {
buffer: [u64; 2],
}
impl Default for AHasher {
#[inline]
fn default() -> AHasher {
AHasher { buffer: DEFAULT_KEYS }
}
}
impl AHasher {
pub fn new_with_keys(key0: u64, key1: u64) -> AHasher {
AHasher { buffer: [key0, key1] }
}
}
impl Hasher for AHasher {
#[inline]
fn write_u8(&mut self, i: u8) {
self.write_u128(i as u128);
}
#[inline]
fn write_u16(&mut self, i: u16) {
self.write_u128(i as u128);
}
#[inline]
fn write_u32(&mut self, i: u32) {
self.write_u128(i as u128);
}
#[inline]
fn write_u128(&mut self, i: u128) {
self.buffer = aeshash(self.buffer.convert(),i).convert();
}
#[inline]
fn write_usize(&mut self, i: usize) {
self.write_u64(i as u64);
}
#[inline]
fn write_u64(&mut self, i: u64) {
self.write_u128(i as u128);
}
#[inline]
fn write(&mut self, input: &[u8]) {
let mut data = input;
let length = data.len() as u64;
self.buffer[1] ^= length;
if data.len() >= 8 {
if data.len() >= 16 {
while data.len() > 32 {
let (block, rest) = data.split_at(16);
let block: u128 = (*as_array!(block, 16)).convert();
self.buffer = aeshash(self.buffer.convert(),block).convert();
data = rest;
}
let block = (*array_ref!(data, 0, 16)).convert();
self.buffer = aeshash(self.buffer.convert(),block).convert();
let block = (*array_ref!(data, data.len()-16, 16)).convert();
self.buffer = aeshash(self.buffer.convert(),block).convert();
} else {
let block: [u64; 2] = [(*array_ref!(data, 0, 8)).convert(),
(*array_ref!(data, data.len()-8, 8)).convert()];
self.buffer = aeshash(self.buffer.convert(),block.convert()).convert();
}
} else {
if data.len() >= 2 {
if data.len() >= 4 {
let block: [u32; 2] = [(*array_ref!(data, 0, 4)).convert(),
(*array_ref!(data, data.len()-4, 4)).convert()];
let block: [u64;2] = [block[1] as u64, block[0] as u64];
self.buffer = aeshash(self.buffer.convert(),block.convert()).convert()
} else {
let block: [u16; 2] = [(*array_ref!(data, 0, 2)).convert(),
(*array_ref!(data, data.len()-2, 2)).convert()];
let block: u32 = block.convert();
self.buffer = aeshash(self.buffer.convert(), block as u128).convert();
}
} else {
if data.len() > 0 {
self.buffer = aeshash(self.buffer.convert(), data[0] as u128).convert();
}
}
}
}
#[inline]
fn finish(&self) -> u64 {
let result: [u64; 2] = aeshash(aeshash(self.buffer.convert(), PAD), PAD).convert();
result[0] }
}
#[cfg(all(any(target_arch = "x86", target_arch = "x86_64"), target_feature = "aes"))]
#[inline(always)]
fn aeshash(value: u128, xor: u128) -> u128 {
use std::mem::transmute;
#[cfg(target_arch = "x86")]
use core::arch::x86::*;
#[cfg(target_arch = "x86_64")]
use std::arch::x86_64::*;
unsafe {
let value = transmute(value);
transmute(_mm_aesdec_si128(value, transmute(xor)))
}
}
#[cfg(test)]
mod tests {
use std::collections::HashMap;
use std::hash::{BuildHasherDefault};
use crate::convert::Convert;
use crate::aes_hash::*;
#[test]
fn test_builder() {
let mut map = HashMap::<u32, u64, BuildHasherDefault<AHasher>>::default();
map.insert(1, 3);
}
#[test]
fn test_default() {
let hasher_a = AHasher::default();
assert_ne!(0, hasher_a.buffer[0]);
assert_ne!(0, hasher_a.buffer[1]);
assert_ne!(hasher_a.buffer[0], hasher_a.buffer[1]);
let hasher_b = AHasher::default();
assert_eq!(hasher_a.buffer[0], hasher_b.buffer[0]);
assert_eq!(hasher_a.buffer[1], hasher_b.buffer[1]);
}
#[test]
fn test_hash() {
let mut result: [u64; 2] = [0x6c62272e07bb0142, 0x62b821756295c58d];
let value: [u64; 2] = [1 << 32, 0xFEDCBA9876543210];
result = aeshash(value.convert(), result.convert()).convert();
result = aeshash(result.convert(), result.convert()).convert();
let mut result2: [u64; 2] = [0x6c62272e07bb0142, 0x62b821756295c58d];
let value2: [u64; 2] = [1, 0xFEDCBA9876543210];
result2 = aeshash(value2.convert(), result2.convert()).convert();
result2 = aeshash(result2.convert(), result.convert()).convert();
let result: [u8; 16] = result.convert();
let result2: [u8; 16] = result2.convert();
assert_ne!(hex::encode(result), hex::encode(result2));
}
#[test]
fn test_conversion() {
let input: &[u8] = "dddddddd".as_bytes();
let bytes: u64 = as_array!(input, 8).convert();
assert_eq!(bytes, 0x6464646464646464);
}
}