use std::str::FromStr;
use crate::hasher::{byte_size, HasherError, HashingFunction};
use num_bigint::BigInt;
use num_traits::Num as _;
use tiny_keccak::{Hasher as KeccakHasherTrait, Keccak};
use super::super::Hasher;
#[derive(Debug, Clone)]
pub struct KeccakHasher {
block_size_bits: usize,
}
impl Hasher for KeccakHasher {
fn get_name(&self) -> HashingFunction {
HashingFunction::Keccak256
}
fn hash(&self, data: Vec<String>) -> Result<String, HasherError> {
let mut output = [0u8; 32];
let mut keccak = Keccak::v256();
if data.is_empty() {
keccak.update(&[]);
} else if data.len() == 1 {
let no_prefix = data[0].strip_prefix("0x").unwrap_or(&data[0]);
keccak.update(&hex::decode(no_prefix)?);
} else {
let mut result: Vec<u8> = Vec::new();
for e in data.iter() {
let bigint = if e.starts_with("0x") || e.starts_with("0X") {
BigInt::from_str_radix(&e[2..], 16).unwrap()
} else {
BigInt::from_str(e).unwrap()
};
let hex = format!("{:0>64}", bigint.to_str_radix(16));
let bytes = hex::decode(hex).unwrap();
result.extend(bytes);
}
keccak.update(&result);
}
keccak.finalize(&mut output);
Ok(format!("0x{:0>64}", hex::encode(output)))
}
fn is_element_size_valid(&self, element: &str) -> Result<bool, HasherError> {
let size = byte_size(element);
if size <= self.block_size_bits {
Ok(true)
} else {
Err(HasherError::InvalidElementSize {
element_size: size,
block_size_bits: self.block_size_bits,
})
}
}
fn hash_single(&self, data: &str) -> Result<String, HasherError> {
self.hash(vec![data.to_string()])
}
fn get_genesis(&self) -> Result<String, HasherError> {
let genesis_str = "brave new world";
let hex = format!("0x{}", hex::encode(genesis_str));
self.hash_single(&hex)
}
fn get_block_size_bits(&self) -> usize {
self.block_size_bits
}
}
impl KeccakHasher {
pub fn new() -> Self {
Self {
block_size_bits: 256,
}
}
}
impl Default for KeccakHasher {
fn default() -> Self {
Self::new()
}
}