use super::{Permutation, RescueParameter, RescueVector};
use ark_crypto_primitives::sponge::{
Absorb, CryptographicSponge, FieldBasedCryptographicSponge, FieldElementSize, SpongeExt,
};
use ark_ff::PrimeField;
use ark_std::{vec, vec::Vec};
#[derive(Clone, Default, Debug)]
pub struct RescueSponge<F: RescueParameter, const RATE: usize> {
pub(crate) state: RescueVector<F>,
pub(crate) permutation: Permutation<F>,
}
impl<F: RescueParameter, const RATE: usize> SpongeExt for RescueSponge<F, RATE> {
type State = RescueVector<F>;
fn from_state(state: Self::State, permutation: &Self::Config) -> Self {
Self {
state,
permutation: permutation.clone(),
}
}
fn into_state(self) -> Self::State {
self.state
}
}
impl<T: RescueParameter + PrimeField, const RATE: usize> CryptographicSponge
for RescueSponge<T, RATE>
{
type Config = Permutation<T>;
fn new(permutation: &Self::Config) -> Self {
Self {
state: RescueVector::default(),
permutation: permutation.clone(),
}
}
fn absorb(&mut self, input: &impl Absorb) {
let input_field_elements = input.to_sponge_field_elements_as_vec();
input_field_elements.chunks(RATE).for_each(|chunk| {
self.state.add_assign_elems(chunk);
self.state = self.permutation.eval(&self.state)
});
}
fn squeeze_bytes(&mut self, _num_bytes: usize) -> Vec<u8> {
unimplemented!("Currently we only support squeezing native field elements!")
}
fn squeeze_bits(&mut self, _num_bits: usize) -> Vec<bool> {
unimplemented!("Currently we only support squeezing native field elements!")
}
fn squeeze_field_elements_with_sizes<F: PrimeField>(
&mut self,
_sizes: &[FieldElementSize],
) -> Vec<F> {
unimplemented!("Currently we only support squeezing native field elements!")
}
fn squeeze_field_elements<F: PrimeField>(&mut self, _num_elements: usize) -> Vec<F> {
unimplemented!("Currently we only support squeezing native field elements!")
}
fn fork(&self, domain: &[u8]) -> Self {
let mut new_sponge = self.clone();
let mut input = Absorb::to_sponge_bytes_as_vec(&domain.len());
input.extend_from_slice(domain);
new_sponge.absorb(&input);
new_sponge
}
}
impl<T: RescueParameter, const RATE: usize> FieldBasedCryptographicSponge<T>
for RescueSponge<T, RATE>
{
fn squeeze_native_field_elements(&mut self, num_elements: usize) -> Vec<T> {
let mut result = vec![];
let mut remaining = num_elements;
loop {
let extract = remaining.min(RATE);
result.extend_from_slice(&self.state.vec[0..extract]);
remaining -= extract;
if remaining == 0 {
break;
}
self.state = self.permutation.eval(&self.state)
}
result
}
fn squeeze_native_field_elements_with_sizes(&mut self, _sizes: &[FieldElementSize]) -> Vec<T> {
unimplemented!("Currently we only support squeezing native field elements!")
}
}
#[cfg(test)]
mod test {
use super::*;
use ark_bls12_381::Fr;
use ark_crypto_primitives::{
absorb, collect_sponge_bytes, collect_sponge_field_elements, sponge::AbsorbWithLength,
};
use ark_ff::{One, UniformRand};
use jf_utils::test_rng;
fn assert_different_encodings<F: RescueParameter, A: Absorb>(a: &A, b: &A) {
let bytes1 = a.to_sponge_bytes_as_vec();
let bytes2 = b.to_sponge_bytes_as_vec();
assert_ne!(bytes1, bytes2);
let sponge_param = Permutation::default();
let mut sponge1 = RescueSponge::<F, 3>::new(&sponge_param);
let mut sponge2 = RescueSponge::<F, 3>::new(&sponge_param);
sponge1.absorb(&a);
sponge2.absorb(&b);
assert_ne!(
sponge1.squeeze_native_field_elements(3),
sponge2.squeeze_native_field_elements(3)
);
}
#[test]
fn single_field_element() {
let mut rng = test_rng();
let elem1 = Fr::rand(&mut rng);
let elem2 = elem1 + Fr::one();
assert_different_encodings::<Fr, _>(&elem1, &elem2)
}
#[test]
fn list_with_constant_size_element() {
let mut rng = test_rng();
let lst1: Vec<_> = (0..1024 * 8).map(|_| Fr::rand(&mut rng)).collect();
let mut lst2 = lst1.to_vec();
lst2[3] += Fr::one();
assert_different_encodings::<Fr, _>(&lst1, &lst2)
}
struct VariableSizeList(Vec<u8>);
impl Absorb for VariableSizeList {
fn to_sponge_bytes(&self, dest: &mut Vec<u8>) {
self.0.to_sponge_bytes_with_length(dest)
}
fn to_sponge_field_elements<F: PrimeField>(&self, dest: &mut Vec<F>) {
self.0.to_sponge_field_elements_with_length(dest)
}
}
#[test]
fn list_with_nonconstant_size_element() {
let lst1 = vec![
VariableSizeList(vec![1u8, 2, 3, 4]),
VariableSizeList(vec![5, 6]),
];
let lst2 = vec![
VariableSizeList(vec![1u8, 2]),
VariableSizeList(vec![3, 4, 5, 6]),
];
assert_different_encodings::<Fr, _>(&lst1, &lst2);
}
#[test]
fn test_macros() {
let sponge_param = Permutation::default();
let mut sponge1 = RescueSponge::<Fr, 3>::new(&sponge_param);
sponge1.absorb(&vec![1u8, 2, 3, 4, 5, 6]);
sponge1.absorb(&Fr::from(114514u128));
let mut sponge2 = RescueSponge::<Fr, 3>::new(&sponge_param);
absorb!(&mut sponge2, vec![1u8, 2, 3, 4, 5, 6], Fr::from(114514u128));
let expected = sponge1.squeeze_native_field_elements(3);
let actual = sponge2.squeeze_native_field_elements(3);
assert_eq!(actual, expected);
let mut expected = Vec::new();
vec![6u8, 5, 4, 3, 2, 1].to_sponge_bytes(&mut expected);
Fr::from(42u8).to_sponge_bytes(&mut expected);
let actual = collect_sponge_bytes!(vec![6u8, 5, 4, 3, 2, 1], Fr::from(42u8));
assert_eq!(actual, expected);
let mut expected: Vec<Fr> = Vec::new();
vec![6u8, 5, 4, 3, 2, 1].to_sponge_field_elements(&mut expected);
Fr::from(42u8).to_sponge_field_elements(&mut expected);
let actual: Vec<Fr> =
collect_sponge_field_elements!(vec![6u8, 5, 4, 3, 2, 1], Fr::from(42u8));
assert_eq!(actual, expected);
}
}