use crate::{
sponge::RescueSponge, Permutation, RescueError, RescueParameter, RescueVector, CRHF_RATE,
};
use ark_crypto_primitives::sponge::{
CryptographicSponge, FieldBasedCryptographicSponge, SpongeExt,
};
use ark_std::{borrow::Borrow, marker::PhantomData, string::ToString, vec::Vec};
use jf_crhf::CRHF;
use jf_utils::pad_with_zeros;
#[derive(Debug, Clone)]
pub struct RescueCRHF<F: RescueParameter> {
sponge: RescueSponge<F, CRHF_RATE>,
}
impl<F: RescueParameter> RescueCRHF<F> {
pub fn sponge_with_bit_padding(input: &[F], num_outputs: usize) -> Vec<F> {
let mut padded = input.to_vec();
padded.push(F::one());
pad_with_zeros(&mut padded, CRHF_RATE);
Self::sponge_no_padding(padded.as_slice(), num_outputs)
.expect("Bug in JF Primitives : bad padding of input for FSKS construction")
}
pub fn sponge_with_zero_padding(input: &[F], num_outputs: usize) -> Vec<F> {
let mut padded = input.to_vec();
pad_with_zeros(&mut padded, CRHF_RATE);
Self::sponge_no_padding(padded.as_slice(), num_outputs)
.expect("Bug in JF Primitives : bad padding of input for FSKS construction")
}
pub fn sponge_no_padding(input: &[F], num_output: usize) -> Result<Vec<F>, RescueError> {
if input.len() % CRHF_RATE != 0 {
return Err(RescueError::ParameterError(
"Rescue sponge Error : input to sponge hashing function is not multiple of RATE."
.to_string(),
));
}
let mut r = Self {
sponge: RescueSponge::from_state(RescueVector::zero(), &Permutation::default()),
};
r.sponge.absorb(&input);
Ok(r.sponge.squeeze_native_field_elements(num_output))
}
}
#[derive(Debug, Clone)]
pub struct FixedLengthRescueCRHF<
F: RescueParameter,
const INPUT_LEN: usize,
const OUTPUT_LEN: usize,
>(PhantomData<F>);
impl<F: RescueParameter, const INPUT_LEN: usize, const OUTPUT_LEN: usize> CRHF
for FixedLengthRescueCRHF<F, INPUT_LEN, OUTPUT_LEN>
{
type Input = [F; INPUT_LEN];
type Output = [F; OUTPUT_LEN];
type Error = RescueError;
fn evaluate<T: Borrow<Self::Input>>(input: T) -> Result<Self::Output, Self::Error> {
let mut output = [F::zero(); OUTPUT_LEN];
let res = match INPUT_LEN % CRHF_RATE {
0 => RescueCRHF::<F>::sponge_no_padding(input.borrow(), OUTPUT_LEN)?,
_ => RescueCRHF::<F>::sponge_with_zero_padding(input.borrow(), OUTPUT_LEN),
};
if res.len() != OUTPUT_LEN {
return Err(RescueError::ParameterError(
"Unexpected rescue sponge return length".to_string(),
));
}
output.copy_from_slice(&res[..]);
Ok(output)
}
}
#[derive(Debug, Clone)]
pub struct VariableLengthRescueCRHF<F: RescueParameter, const OUTPUT_LEN: usize>(PhantomData<F>);
impl<F: RescueParameter, const OUTPUT_LEN: usize> CRHF for VariableLengthRescueCRHF<F, OUTPUT_LEN> {
type Input = Vec<F>;
type Output = [F; OUTPUT_LEN];
type Error = RescueError;
fn evaluate<T: Borrow<Self::Input>>(input: T) -> Result<Self::Output, Self::Error> {
let mut output = [F::zero(); OUTPUT_LEN];
let res = RescueCRHF::<F>::sponge_with_bit_padding(input.borrow(), OUTPUT_LEN);
if res.len() != OUTPUT_LEN {
return Err(RescueError::ParameterError(
"Unexpected rescue sponge return length".to_string(),
));
}
output.copy_from_slice(&res[..]);
Ok(output)
}
}