use crate::meta_ext::Hasher;
use crate::prelude::*;
use blake2::{Blake2b, Digest};
use core::hash::Hasher as _;
pub fn hash<I: AsRef<[u8]>>(hasher: &Hasher, input: I) -> Vec<u8> {
let mut input = input.as_ref();
let mut data = vec![];
if input.starts_with(b"0x") {
data.append(&mut hex::decode(&input[2..]).expect("hex string"));
input = data.as_ref();
};
match hasher {
Hasher::Blake2_128 => Blake2b::digest(input).as_slice().to_vec(),
Hasher::Blake2_256 => unimplemented!(),
Hasher::Blake2_128Concat => [Blake2b::digest(input).as_slice(), input].concat(),
Hasher::Twox128 => twox_hash(&input),
Hasher::Twox256 => unimplemented!(),
Hasher::Twox64Concat => twox_hash_concat(input),
Hasher::Identity => input.into(),
}
}
fn twox_hash_concat(input: &[u8]) -> Vec<u8> {
let mut dest = [0; 8];
let mut h = twox_hash::XxHash64::with_seed(0);
h.write(input);
let r = h.finish();
dest.copy_from_slice(&r.to_le_bytes());
[dest.as_ref(), input].concat()
}
fn twox_hash(input: &[u8]) -> Vec<u8> {
let mut dest: [u8; 16] = [0; 16];
let mut h0 = twox_hash::XxHash64::with_seed(0);
let mut h1 = twox_hash::XxHash64::with_seed(1);
h0.write(input);
h1.write(input);
let r0 = h0.finish();
let r1 = h1.finish();
let (first, last) = dest.split_at_mut(8);
first.copy_from_slice(&r0.to_le_bytes());
last.copy_from_slice(&r1.to_le_bytes());
dest.into()
}
#[cfg(test)]
mod tests {
use super::*;
use hex_literal::hex;
#[test]
fn hash_blake_hex() {
let out1 = hash(&Hasher::Blake2_128, "0x68656c6c6f");
let out2 = hash(&Hasher::Blake2_128, hex!("68656c6c6f"));
assert_eq!(out1, out2,);
}
}