use crate::{
core::actually_used_field::ActuallyUsedField,
utils::{
crypto::{
key::RESCUE_KEY_COUNT,
rescue_desc::{RescueArg, RescueDesc},
},
matrix::Matrix,
},
};
use std::ops::IndexMut;
#[derive(Debug)]
pub struct RescuePrimeHash<F: ActuallyUsedField, T: RescueArg<F>> {
desc: RescueDesc<F, T>,
pub rate: usize,
pub digest_len: usize,
}
impl<F: ActuallyUsedField, T: RescueArg<F>> RescuePrimeHash<F, T> {
pub fn new() -> Self {
RescuePrimeHash {
desc: RescueDesc::new_hash_desc(12, 5),
rate: 7,
digest_len: RESCUE_KEY_COUNT,
}
}
pub fn digest(&self, mut message: Vec<T>) -> [T; RESCUE_KEY_COUNT] {
message.push(T::from(F::ONE));
if message.len() % self.rate != 0 {
message.extend(vec![
T::from(F::ZERO);
self.rate - (message.len() % self.rate)
]);
}
let mut state = Matrix::new((self.desc.m, 1), T::from(F::ZERO));
message.chunks(self.rate).for_each(|chunk| {
chunk.iter().copied().enumerate().for_each(|(i, s)| {
*state.index_mut((i, 0)) = *state.index_mut((i, 0)) + s;
});
state = self.desc.permute(&state);
});
state
.into_iter()
.take(self.digest_len)
.collect::<Vec<T>>()
.try_into()
.unwrap_or_else(|v: Vec<T>| {
panic!(
"Expected a Vec of length {} (found {})",
self.digest_len,
v.len()
)
})
}
}
impl<F: ActuallyUsedField, T: RescueArg<F>> Default for RescuePrimeHash<F, T> {
fn default() -> Self {
Self::new()
}
}