mod transform;
mod u256;
use u256::U256;
use crate::{
encoding::ternary::{Btrit, TritBuf, Trits},
hashes::ternary::{curl_p::SpongeDirection, HASH_LENGTH},
};
pub struct CurlP {
p: [U256; 3],
n: [U256; 3],
direction: SpongeDirection,
}
impl Default for CurlP {
fn default() -> Self {
Self {
p: Default::default(),
n: Default::default(),
direction: SpongeDirection::Absorb,
}
}
}
impl CurlP {
fn squeeze_aux(&mut self, hash: &mut Trits) {
if let SpongeDirection::Squeeze = self.direction {
self.transform();
}
self.direction = SpongeDirection::Squeeze;
for i in 0..HASH_LENGTH {
let trit = unsafe { core::mem::transmute::<i8, Btrit>(self.p[0].bit(i) - self.n[0].bit(i)) };
hash.set(i, trit);
}
}
fn transform(&mut self) {
transform::transform(&mut self.p, &mut self.n)
}
pub fn new() -> Self {
Self::default()
}
pub fn reset(&mut self) {
*self = Self::new();
}
pub fn absorb(&mut self, input: &Trits) {
assert!(
!(input.is_empty() || input.len() % HASH_LENGTH != 0),
"trits slice length must be multiple of {}",
HASH_LENGTH
);
if let SpongeDirection::Squeeze = self.direction {
panic!("absorb after squeeze");
}
for chunk in input.chunks(HASH_LENGTH) {
let mut p = U256::default();
let mut n = U256::default();
for (i, trit) in chunk.iter().enumerate() {
match trit {
Btrit::PlusOne => p.set_bit(i),
Btrit::Zero => (),
Btrit::NegOne => n.set_bit(i),
}
}
self.p[0] = p;
self.n[0] = n;
self.transform();
}
}
fn squeeze_into(&mut self, buf: &mut Trits) {
assert_eq!(buf.len() % HASH_LENGTH, 0, "Invalid squeeze length");
for chunk in buf.chunks_mut(HASH_LENGTH) {
self.squeeze_aux(chunk);
}
}
pub fn squeeze(&mut self) -> TritBuf {
let mut output = TritBuf::zeros(HASH_LENGTH);
self.squeeze_into(&mut output);
output
}
pub fn digest_into(&mut self, input: &Trits, buf: &mut Trits) {
self.absorb(input);
self.squeeze_into(buf);
self.reset();
}
pub fn digest(&mut self, input: &Trits) -> TritBuf {
self.absorb(input);
let output = self.squeeze();
self.reset();
output
}
}