use crate::ternary::{
bigint::{binary_representation::U8Repr, endianness::BigEndian, error::Error as ConversionError, I384, T242, T243},
sponge::Sponge,
HASH_LENGTH,
};
use bee_ternary::{Btrit, Trits, T1B1};
use tiny_keccak::{Hasher, Keccak};
#[derive(Clone)]
pub struct Kerl {
keccak: Keccak,
binary_state: I384<BigEndian, U8Repr>,
ternary_state: T243<Btrit>,
}
impl Default for Kerl {
fn default() -> Self {
Self {
keccak: Keccak::v384(),
binary_state: Default::default(),
ternary_state: Default::default(),
}
}
}
impl Kerl {
pub fn new() -> Self {
Self::default()
}
}
#[derive(Debug)]
pub enum Error {
NotMultipleOfHashLength,
TernaryBinaryConversion(ConversionError),
}
impl From<ConversionError> for Error {
fn from(error: ConversionError) -> Self {
Error::TernaryBinaryConversion(error)
}
}
impl Sponge for Kerl {
type Error = Error;
fn reset(&mut self) {
self.keccak = Keccak::v384();
}
fn absorb(&mut self, input: &Trits) -> Result<(), Self::Error> {
if input.len() % HASH_LENGTH != 0 {
return Err(Error::NotMultipleOfHashLength);
}
for trits_chunk in input.chunks(HASH_LENGTH) {
self.ternary_state.copy_from(trits_chunk);
self.binary_state = self.ternary_state.clone().into_t242().into();
self.keccak.update(&self.binary_state[..]);
}
Ok(())
}
fn squeeze_into(&mut self, buf: &mut Trits<T1B1>) -> Result<(), Self::Error> {
if buf.len() % HASH_LENGTH != 0 {
return Err(Error::NotMultipleOfHashLength);
}
for trit_chunk in buf.chunks_mut(HASH_LENGTH) {
let mut keccak = Keccak::v384();
std::mem::swap(&mut self.keccak, &mut keccak);
keccak.finalize(&mut self.binary_state[..]);
let ternary_value = T242::from_i384_ignoring_mst(self.binary_state).into_t243();
trit_chunk.copy_from(&ternary_value);
self.binary_state.not_inplace();
self.keccak.update(&self.binary_state[..]);
}
Ok(())
}
}