#![cfg_attr(not(feature = "std"), no_std)]
#![deny(
const_err,
future_incompatible,
missing_docs,
non_shorthand_field_patterns,
renamed_and_removed_lints,
rust_2018_idioms,
stable_features,
trivial_casts,
trivial_numeric_casts,
unused,
variant_size_differences,
warnings
)]
#![forbid(unsafe_code)]
use ark_ff::{FpParameters, PrimeField};
use ark_std::vec;
use ark_std::vec::Vec;
#[cfg(feature = "r1cs")]
pub mod constraints;
mod absorb;
pub use absorb::*;
pub mod poseidon;
#[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::Params::MODULUS_BITS as usize) {
panic!("num_bits is greater than the capacity of the field.")
}
};
F::Params::CAPACITY 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 nonnative_bits_le: Vec<bool> = bits_window[..num_bits].to_vec();
bits_window = &bits_window[num_bits..];
let nonnative_bytes = nonnative_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(nonnative_bytes.as_slice()));
}
output
}
pub trait CryptographicSponge: Clone {
type Parameters;
fn new(params: &Self::Parameters) -> 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::Parameters) -> Self;
fn into_state(self) -> Self::State;
}