mod batched;
mod unrolled;
pub use batched::{BatchHasher, BATCH_SIZE};
pub use unrolled::UnrolledCurlP81;
use crate::ternary::{sponge::Sponge, HASH_LENGTH};
use bee_ternary::{Btrit, TritBuf, Trits};
use std::{
convert::Infallible,
ops::{Deref, DerefMut},
};
const STATE_LENGTH: usize = HASH_LENGTH * 3;
const HALF_STATE_LENGTH: usize = STATE_LENGTH / 2;
const TRUTH_TABLE: [Btrit; 9] = [
Btrit::PlusOne,
Btrit::Zero,
Btrit::NegOne,
Btrit::PlusOne,
Btrit::NegOne,
Btrit::Zero,
Btrit::NegOne,
Btrit::PlusOne,
Btrit::Zero,
];
#[derive(Copy, Clone)]
pub enum CurlPRounds {
Rounds27 = 27,
Rounds81 = 81,
}
pub struct CurlP {
rounds: CurlPRounds,
state: TritBuf,
work_state: TritBuf,
}
impl CurlP {
pub fn new(rounds: CurlPRounds) -> Self {
Self {
rounds,
state: TritBuf::zeros(STATE_LENGTH),
work_state: TritBuf::zeros(STATE_LENGTH),
}
}
fn transform(&mut self) {
#[inline]
unsafe fn truth_table_get(state: &Trits, p: usize, q: usize) -> Btrit {
#[allow(clippy::cast_sign_loss)] *TRUTH_TABLE
.get_unchecked((3 * (state.get_unchecked(q) as i8 + 1) + (state.get_unchecked(p) as i8 + 1)) as usize)
}
#[inline]
unsafe fn substitution_box(input: &Trits, output: &mut Trits) {
output.set_unchecked(0, truth_table_get(input, 0, HALF_STATE_LENGTH));
for state_index in 0..HALF_STATE_LENGTH {
let left_idx = HALF_STATE_LENGTH - state_index;
let right_idx = STATE_LENGTH - state_index - 1;
let state_index_2 = 2 * state_index;
output.set_unchecked(state_index_2 + 1, truth_table_get(input, left_idx, right_idx));
output.set_unchecked(state_index_2 + 2, truth_table_get(input, right_idx, left_idx - 1));
}
}
let (lhs, rhs) = (&mut self.state, &mut self.work_state);
for _ in 0..self.rounds as usize {
unsafe {
substitution_box(lhs, rhs);
}
std::mem::swap(lhs, rhs);
}
}
}
impl Sponge for CurlP {
type Error = Infallible;
fn reset(&mut self) {
self.state.fill(Btrit::Zero);
}
fn absorb(&mut self, input: &Trits) -> Result<(), Self::Error> {
for chunk in input.chunks(HASH_LENGTH) {
self.state[0..chunk.len()].copy_from(chunk);
self.transform();
}
Ok(())
}
fn squeeze_into(&mut self, buf: &mut Trits) -> Result<(), Self::Error> {
for chunk in buf.chunks_mut(HASH_LENGTH) {
chunk.copy_from(&self.state[0..chunk.len()]);
self.transform()
}
Ok(())
}
}
pub struct CurlP27(CurlP);
impl CurlP27 {
pub fn new() -> Self {
Self(CurlP::new(CurlPRounds::Rounds27))
}
}
impl Default for CurlP27 {
fn default() -> Self {
CurlP27::new()
}
}
impl Deref for CurlP27 {
type Target = CurlP;
fn deref(&self) -> &Self::Target {
&self.0
}
}
impl DerefMut for CurlP27 {
fn deref_mut(&mut self) -> &mut Self::Target {
&mut self.0
}
}
pub struct CurlP81(CurlP);
impl CurlP81 {
pub fn new() -> Self {
Self(CurlP::new(CurlPRounds::Rounds81))
}
}
impl Default for CurlP81 {
fn default() -> Self {
CurlP81::new()
}
}
impl Deref for CurlP81 {
type Target = CurlP;
fn deref(&self) -> &Self::Target {
&self.0
}
}
impl DerefMut for CurlP81 {
fn deref_mut(&mut self) -> &mut Self::Target {
&mut self.0
}
}