use ark_ff::PrimeField;
#[cfg(not(feature = "std"))]
use ark_std::vec::Vec;
#[cfg(feature = "constraints")]
pub mod constraints;
mod absorb;
pub use absorb::*;
pub mod rescue;
pub mod poseidon;
pub mod merlin;
#[cfg(test)]
mod test;
#[derive(Clone, Copy, Eq, PartialEq)]
pub enum FieldElementSize {
Full,
Truncated(usize),
}
impl FieldElementSize {
pub(crate) fn num_bits<F: PrimeField>(&self) -> usize {
if let FieldElementSize::Truncated(num_bits) = self {
if *num_bits > (F::MODULUS_BIT_SIZE as usize) {
panic!("num_bits is greater than the capacity of the field.")
}
*num_bits
} else {
(F::MODULUS_BIT_SIZE - 1) as usize
}
}
pub fn sum<F: PrimeField>(elements: &[Self]) -> usize {
elements.iter().map(|item| item.num_bits::<F>()).sum()
}
}
pub(crate) fn squeeze_field_elements_with_sizes_default_impl<F: PrimeField>(
sponge: &mut impl CryptographicSponge,
sizes: &[FieldElementSize],
) -> Vec<F> {
if sizes.len() == 0 {
return Vec::new();
}
let mut total_bits = 0usize;
for size in sizes {
total_bits += size.num_bits::<F>();
}
let bits = sponge.squeeze_bits(total_bits);
let mut bits_window = bits.as_slice();
let mut output = Vec::with_capacity(sizes.len());
for size in sizes {
let num_bits = size.num_bits::<F>();
let emulated_bits_le: Vec<bool> = bits_window[..num_bits].to_vec();
bits_window = &bits_window[num_bits..];
let emulated_bytes = emulated_bits_le
.chunks(8)
.map(|bits| {
let mut byte = 0u8;
for (i, &bit) in bits.into_iter().enumerate() {
if bit {
byte += 1 << i;
}
}
byte
})
.collect::<Vec<_>>();
output.push(F::from_le_bytes_mod_order(emulated_bytes.as_slice()));
}
output
}
pub trait CryptographicSponge: Clone {
type Config;
fn new(params: &Self::Config) -> Self;
fn absorb(&mut self, input: &impl Absorb);
fn squeeze_bytes(&mut self, num_bytes: usize) -> Vec<u8>;
fn squeeze_bits(&mut self, num_bits: usize) -> Vec<bool>;
fn squeeze_field_elements_with_sizes<F: PrimeField>(
&mut self,
sizes: &[FieldElementSize],
) -> Vec<F> {
squeeze_field_elements_with_sizes_default_impl(self, sizes)
}
fn squeeze_field_elements<F: PrimeField>(&mut self, num_elements: usize) -> Vec<F> {
self.squeeze_field_elements_with_sizes::<F>(
vec![FieldElementSize::Full; num_elements].as_slice(),
)
}
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
}
}
pub trait FieldBasedCryptographicSponge<CF: PrimeField>: CryptographicSponge {
fn squeeze_native_field_elements(&mut self, num_elements: usize) -> Vec<CF>;
fn squeeze_native_field_elements_with_sizes(&mut self, sizes: &[FieldElementSize]) -> Vec<CF> {
let mut all_full_sizes = true;
for size in sizes {
if *size != FieldElementSize::Full {
all_full_sizes = false;
break;
}
}
if all_full_sizes {
self.squeeze_native_field_elements(sizes.len())
} else {
squeeze_field_elements_with_sizes_default_impl(self, sizes)
}
}
}
pub trait SpongeExt: CryptographicSponge {
type State: Clone;
fn from_state(state: Self::State, params: &Self::Config) -> Self;
fn into_state(self) -> Self::State;
}
#[derive(Clone, Debug)]
pub enum DuplexSpongeMode {
Absorbing {
next_absorb_index: usize,
},
Squeezing {
next_squeeze_index: usize,
},
}