use crate::sponge::{
field_cast, squeeze_field_elements_with_sizes_default_impl, Absorb, CryptographicSponge,
DuplexSpongeMode, FieldBasedCryptographicSponge, FieldElementSize, SpongeExt,
};
use ark_ff::{BigInteger, PrimeField};
use ark_serialize::{CanonicalDeserialize, CanonicalSerialize};
use ark_std::any::TypeId;
#[cfg(not(feature = "std"))]
use ark_std::vec::Vec;
use num_bigint::BigUint;
#[cfg(feature = "constraints")]
pub mod constraints;
#[derive(Clone, Debug, CanonicalSerialize, CanonicalDeserialize)]
pub struct RescueConfig<F: PrimeField> {
pub rounds: usize,
pub alpha: u64,
pub alpha_inv: BigUint,
pub arc: Vec<Vec<F>>,
pub mds: Vec<Vec<F>>,
pub rate: usize,
pub capacity: usize,
}
#[derive(Clone)]
pub struct RescueSponge<F: PrimeField> {
pub parameters: RescueConfig<F>,
pub state: Vec<F>,
pub mode: DuplexSpongeMode,
}
impl<F: PrimeField> RescueSponge<F> {
fn apply_s_box(&self, state: &mut [F], round: usize) {
if (round % 2) == 0 {
for elem in state {
*elem = elem.pow(self.parameters.alpha_inv.to_u64_digits());
}
} else {
for elem in state {
*elem = elem.pow([self.parameters.alpha]);
}
}
}
fn apply_arc(&self, state: &mut [F], round_number: usize) {
for (i, state_elem) in state.iter_mut().enumerate() {
state_elem.add_assign(&self.parameters.arc[round_number][i]);
}
}
fn apply_mds(&self, state: &mut [F]) {
let mut new_state = Vec::new();
for i in 0..state.len() {
let mut cur = F::zero();
for (j, state_elem) in state.iter().enumerate() {
let term = state_elem.mul(&self.parameters.mds[i][j]);
cur.add_assign(&term);
}
new_state.push(cur);
}
state.clone_from_slice(&new_state[..state.len()])
}
fn permute(&mut self) {
let mut state = self.state.clone();
assert_eq!(self.parameters.rounds * 2 + 1, self.parameters.arc.len());
self.apply_arc(&mut state, 0);
for (round, _round_key) in self.parameters.arc[1..].iter().enumerate() {
self.apply_s_box(&mut state, round);
self.apply_mds(&mut state);
self.apply_arc(&mut state, round + 1);
}
self.state = state;
}
fn absorb_internal(&mut self, mut rate_start_index: usize, elements: &[F]) {
let mut remaining_elements = elements;
loop {
if rate_start_index + remaining_elements.len() <= self.parameters.rate {
for (i, element) in remaining_elements.iter().enumerate() {
self.state[self.parameters.capacity + i + rate_start_index] += element;
}
self.mode = DuplexSpongeMode::Absorbing {
next_absorb_index: rate_start_index + remaining_elements.len(),
};
return;
}
let num_elements_absorbed = self.parameters.rate - rate_start_index;
for (i, element) in remaining_elements
.iter()
.enumerate()
.take(num_elements_absorbed)
{
self.state[self.parameters.capacity + i + rate_start_index] += element;
}
self.permute();
remaining_elements = &remaining_elements[num_elements_absorbed..];
rate_start_index = 0;
}
}
fn squeeze_internal(&mut self, mut rate_start_index: usize, output: &mut [F]) {
let mut output_remaining = output;
loop {
if rate_start_index + output_remaining.len() <= self.parameters.rate {
output_remaining.clone_from_slice(
&self.state[self.parameters.capacity + rate_start_index
..(self.parameters.capacity + output_remaining.len() + rate_start_index)],
);
self.mode = DuplexSpongeMode::Squeezing {
next_squeeze_index: rate_start_index + output_remaining.len(),
};
return;
}
let num_elements_squeezed = self.parameters.rate - rate_start_index;
output_remaining[..num_elements_squeezed].clone_from_slice(
&self.state[self.parameters.capacity + rate_start_index
..(self.parameters.capacity + num_elements_squeezed + rate_start_index)],
);
if output_remaining.len() != self.parameters.rate {
self.permute();
}
output_remaining = &mut output_remaining[num_elements_squeezed..];
rate_start_index = 0;
}
}
}
impl<F: PrimeField> RescueConfig<F> {
pub fn new(
rounds: usize,
alpha: u64,
alpha_inv: BigUint,
mds: Vec<Vec<F>>,
arc: Vec<Vec<F>>,
rate: usize,
capacity: usize,
) -> Self {
assert_eq!(arc.len(), 2 * rounds + 1);
for item in &arc {
assert_eq!(item.len(), rate + capacity);
}
assert_eq!(mds.len(), rate + capacity);
for item in &mds {
assert_eq!(item.len(), rate + capacity);
}
Self {
rounds,
alpha,
alpha_inv,
mds,
arc,
rate,
capacity,
}
}
}
impl<F: PrimeField> CryptographicSponge for RescueSponge<F> {
type Config = RescueConfig<F>;
fn new(parameters: &Self::Config) -> Self {
let state = vec![F::zero(); parameters.rate + parameters.capacity];
let mode = DuplexSpongeMode::Absorbing {
next_absorb_index: 0,
};
Self {
parameters: parameters.clone(),
state,
mode,
}
}
fn absorb(&mut self, input: &impl Absorb) {
let elems: Vec<F> = input.to_sponge_field_elements_as_vec::<F>();
if elems.is_empty() {
return;
}
match self.mode {
DuplexSpongeMode::Absorbing { next_absorb_index } => {
let mut absorb_index = next_absorb_index;
if absorb_index == self.parameters.rate {
self.permute();
absorb_index = 0;
}
self.absorb_internal(absorb_index, elems.as_slice());
}
DuplexSpongeMode::Squeezing {
next_squeeze_index: _,
} => {
self.permute();
self.absorb_internal(0, elems.as_slice());
}
};
}
fn squeeze_bytes(&mut self, num_bytes: usize) -> Vec<u8> {
let usable_bytes = ((F::MODULUS_BIT_SIZE - 1) / 8) as usize;
let num_elements = num_bytes.div_ceil(usable_bytes);
let src_elements = self.squeeze_native_field_elements(num_elements);
let mut bytes: Vec<u8> = Vec::with_capacity(usable_bytes * num_elements);
for elem in &src_elements {
let elem_bytes = elem.into_bigint().to_bytes_le();
bytes.extend_from_slice(&elem_bytes[..usable_bytes]);
}
bytes.truncate(num_bytes);
bytes
}
fn squeeze_bits(&mut self, num_bits: usize) -> Vec<bool> {
let usable_bits = (F::MODULUS_BIT_SIZE - 1) as usize;
let num_elements = num_bits.div_ceil(usable_bits);
let src_elements = self.squeeze_native_field_elements(num_elements);
let mut bits: Vec<bool> = Vec::with_capacity(usable_bits * num_elements);
for elem in &src_elements {
let elem_bits = elem.into_bigint().to_bits_le();
bits.extend_from_slice(&elem_bits[..usable_bits]);
}
bits.truncate(num_bits);
bits
}
fn squeeze_field_elements_with_sizes<F2: PrimeField>(
&mut self,
sizes: &[FieldElementSize],
) -> Vec<F2> {
if F::characteristic() == F2::characteristic() {
let mut buf = Vec::with_capacity(sizes.len());
field_cast(
&self.squeeze_native_field_elements_with_sizes(sizes),
&mut buf,
)
.unwrap();
buf
} else {
squeeze_field_elements_with_sizes_default_impl(self, sizes)
}
}
fn squeeze_field_elements<F2: PrimeField>(&mut self, num_elements: usize) -> Vec<F2> {
if TypeId::of::<F>() == TypeId::of::<F2>() {
let result = self.squeeze_native_field_elements(num_elements);
let mut cast = Vec::with_capacity(result.len());
field_cast(&result, &mut cast).unwrap();
cast
} else {
self.squeeze_field_elements_with_sizes::<F2>(
vec![FieldElementSize::Full; num_elements].as_slice(),
)
}
}
}
impl<F: PrimeField> FieldBasedCryptographicSponge<F> for RescueSponge<F> {
fn squeeze_native_field_elements(&mut self, num_elements: usize) -> Vec<F> {
let mut squeezed_elems = vec![F::zero(); num_elements];
match self.mode {
DuplexSpongeMode::Absorbing {
next_absorb_index: _,
} => {
self.permute();
self.squeeze_internal(0, &mut squeezed_elems);
}
DuplexSpongeMode::Squeezing { next_squeeze_index } => {
let mut squeeze_index = next_squeeze_index;
if squeeze_index == self.parameters.rate {
self.permute();
squeeze_index = 0;
}
self.squeeze_internal(squeeze_index, &mut squeezed_elems);
}
};
squeezed_elems
}
}
#[derive(Clone)]
pub struct RescueSpongeState<F: PrimeField> {
state: Vec<F>,
mode: DuplexSpongeMode,
}
impl<CF: PrimeField> SpongeExt for RescueSponge<CF> {
type State = RescueSpongeState<CF>;
fn from_state(state: Self::State, params: &Self::Config) -> Self {
let mut sponge = Self::new(params);
sponge.mode = state.mode;
sponge.state = state.state;
sponge
}
fn into_state(self) -> Self::State {
Self::State {
state: self.state,
mode: self.mode,
}
}
}