#[derive(Copy, Clone)]
pub struct HashConfig {
pub salt: u64,
p: u64
}
pub fn to_vec_u8(data: &[u64]) -> Vec<u8> {
let mut v: Vec<u8> = vec![];
for val in data {
v.extend_from_slice(&val.to_le_bytes());
}
v
}
fn splitmix64(mut x: u64) -> u64 {
x = x.wrapping_add(0x9e3779b97f4a7c15);
x = (x ^ (x >> 30)).wrapping_mul(0xbf58476d1ce4e5b9);
x = (x ^ (x >> 27)).wrapping_mul(0x94d049bb133111eb);
x ^ (x >> 31)
}
fn pow_mod(mut a: u64, mut e: u64, m: u64) -> u64 {
let mut r: u64 = 1;
while e > 0 {
if e & 1 == 1 {
r = ((r as u128 * a as u128) % m as u128) as u64;
}
a = ((a as u128 * a as u128) % m as u128) as u64;
e >>= 1;
}
r
}
fn inverse_mod(a: u64, p: u64) -> u64 {
pow_mod(a, p - 2, p)
}
fn seed_from_data(data: &[u64], salt: u64) -> u64 {
let mut seed: u64 = 0x9e3779b97f4a7c15 ^ salt;
for &x in data {
seed = seed.wrapping_add(x);
seed = splitmix64(seed);
}
seed
}
fn interpolate(
points: Vec<(u64, u64)>,
x: [u64; 5],
k: u8,
p: u64
) -> [u64; 5] {
let mut evals: [u64; 5] = [0; 5];
for (idx, x_val) in x.iter().enumerate() {
if idx > k as usize {
break;
}
let mut eval: u128 = 0;
for point in points.iter() {
let mut basis: u128 = point.1 as u128;
for point_ in points.iter() {
if point_ == point {
continue;
}
basis *= ((p as i128 + *x_val as i128 - point.0 as i128) % p as i128) as u128;
basis %= p as u128;
basis *= inverse_mod(
((point_.0 as i128 - point.0 as i128) % p as i128) as u64,
p
) as u128;
basis %= p as u128;
}
eval = (eval + basis) % p as u128;
}
evals[idx] = eval as u64;
}
evals
}
fn x_vals(data: &Vec<u64>) -> Vec<(u64, u64)> {
data.iter()
.enumerate()
.map(|(i, y)| (i as u64, *y))
.collect()
}
fn x_vec(data: &Vec<u64>, k: u8, p: u64, salt: u64) -> [u64; 5] {
let seed = seed_from_data(&data[0..], salt);
let mut out: [u64; 5] = [0; 5];
out[0] = splitmix64(seed) % p;
out[1] = splitmix64(out[0]) % p;
out[2] = splitmix64(out[1]) % p;
if k >= 4 {out[3] = splitmix64(out[2]) % p;}
if k == 5 {out[4] = splitmix64(out[3]) % p;}
out
}
pub fn hex(bytes: Vec<u8>) -> String {
bytes.iter().map(|b| format!("{:02x}", b)).collect()
}
pub fn str_to_vec_i64(s: &str) -> Vec<u64> {
let bytes = s.as_bytes();
let mut out = Vec::with_capacity((bytes.len() + 7) / 8);
let mut i = 0;
while i < bytes.len() {
let mut arr = [0u8; 8];
let end = (i + 8).min(bytes.len());
arr[..end - i].copy_from_slice(&bytes[i..end]);
out.push(u64::from_le_bytes(arr));
i += 8;
}
out
}
impl HashConfig {
pub fn _hash<const K: usize>(self, s: &Vec<u64>) -> [u64; 5] {
interpolate(
x_vals(s),
x_vec(s, K as u8, self.p, self.salt),
K as u8,
self.p
)
}
pub fn hash122(self, s: &Vec<u64>) -> Vec<u8> {
to_vec_u8(&self._hash::<4>(s)[0..2])
}
pub fn hash183(self, s: &Vec<u64>) -> Vec<u8> {
to_vec_u8(&self._hash::<4>(s)[0..3])
}
pub fn hash244(self, s: &Vec<u64>) -> Vec<u8> {
to_vec_u8(&self._hash::<4>(s)[0..4])
}
pub fn hash305(self, s: &Vec<u64>) -> Vec<u8> {
to_vec_u8(&self._hash::<4>(s))
}
pub fn new(salt: u64) -> HashConfig {
HashConfig {
p: (1 << 61) - 1,
salt
}
}
}