use smallvec::SmallVec;
use snarkvm_fields::{PrimeField, ToConstraintField};
use snarkvm_utilities::FromBits;
use core::fmt::Debug;
pub trait AlgebraicSponge<F: PrimeField, const RATE: usize>: Clone + Debug {
type Parameters;
fn sample_parameters() -> Self::Parameters;
fn new_with_parameters(params: &Self::Parameters) -> Self;
fn new() -> Self {
let parameters = Self::sample_parameters();
Self::new_with_parameters(¶meters)
}
fn absorb_native_field_elements<T: ToConstraintField<F>>(&mut self, elements: &[T]);
fn absorb_nonnative_field_elements<Target: PrimeField>(&mut self, elements: impl IntoIterator<Item = Target>);
fn absorb_bytes(&mut self, elements: &[u8]) {
let capacity = F::size_in_bits() - 1;
let mut bits = Vec::<bool>::new();
for elem in elements {
bits.append(&mut vec![
elem & 128 != 0,
elem & 64 != 0,
elem & 32 != 0,
elem & 16 != 0,
elem & 8 != 0,
elem & 4 != 0,
elem & 2 != 0,
elem & 1 != 0,
]);
}
let elements = bits
.chunks(capacity)
.map(|bits| F::from_bigint(F::BigInteger::from_bits_be(bits).unwrap()).unwrap())
.collect::<SmallVec<[F; 10]>>();
self.absorb_native_field_elements(&elements);
}
fn squeeze_native_field_elements(&mut self, num: usize) -> SmallVec<[F; 10]>;
fn squeeze_nonnative_field_elements<Target: PrimeField>(&mut self, num: usize) -> SmallVec<[Target; 10]>;
fn squeeze_short_nonnative_field_elements<Target: PrimeField>(&mut self, num: usize) -> SmallVec<[Target; 10]>;
fn squeeze_short_nonnative_field_element<Target: PrimeField>(&mut self) -> Target {
self.squeeze_short_nonnative_field_elements(1)[0]
}
}
#[derive(PartialEq, Eq, Clone, Debug)]
pub enum DuplexSpongeMode {
Absorbing {
next_absorb_index: usize,
},
Squeezing {
next_squeeze_index: usize,
},
}
pub(crate) mod nonnative_params {
#[macro_export]
macro_rules! overhead {
($x:expr) => {{
use snarkvm_utilities::ToBits;
let num = $x;
let num_bits = num.to_bigint().to_bits_be();
let mut skipped_bits = 0;
for b in num_bits.iter() {
if *b == false {
skipped_bits += 1;
} else {
break;
}
}
let mut is_power_of_2 = true;
for b in num_bits.iter().skip(skipped_bits + 1) {
if *b == true {
is_power_of_2 = false;
}
}
if is_power_of_2 { num_bits.len() - skipped_bits } else { num_bits.len() - skipped_bits + 1 }
}};
}
#[derive(Clone, Debug)]
pub struct NonNativeFieldParams {
pub num_limbs: usize,
pub bits_per_limb: usize,
}
#[must_use]
pub const fn get_params(
target_field_size: usize,
base_field_size: usize,
optimization_type: OptimizationType,
) -> NonNativeFieldParams {
let (num_of_limbs, limb_size) = find_parameters(base_field_size, target_field_size, optimization_type);
NonNativeFieldParams { num_limbs: num_of_limbs, bits_per_limb: limb_size }
}
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub enum OptimizationType {
Constraints,
Weight,
}
pub const fn find_parameters(
base_field_prime_length: usize,
target_field_prime_bit_length: usize,
optimization_type: OptimizationType,
) -> (usize, usize) {
let mut found = false;
let mut min_cost = 0usize;
let mut min_cost_limb_size = 0usize;
let mut min_cost_num_of_limbs = 0usize;
let surfeit = 10;
let mut max_limb_size = (base_field_prime_length - 1 - surfeit - 1) / 2 - 1;
if max_limb_size > target_field_prime_bit_length {
max_limb_size = target_field_prime_bit_length;
}
let mut limb_size = 1;
while limb_size <= max_limb_size {
let num_of_limbs = (target_field_prime_bit_length + limb_size - 1) / limb_size;
let group_size = (base_field_prime_length - 1 - surfeit - 1 - 1 - limb_size + limb_size - 1) / limb_size;
let num_of_groups = (2 * num_of_limbs - 1 + group_size - 1) / group_size;
let mut this_cost = 0;
match optimization_type {
OptimizationType::Constraints => {
this_cost += 2 * num_of_limbs - 1;
}
OptimizationType::Weight => {
this_cost += 6 * num_of_limbs * num_of_limbs;
}
};
match optimization_type {
OptimizationType::Constraints => {
this_cost += target_field_prime_bit_length; this_cost += target_field_prime_bit_length + num_of_limbs; this_cost += num_of_groups + (num_of_groups - 1) * (limb_size * 2 + surfeit) + 1;
}
OptimizationType::Weight => {
this_cost += target_field_prime_bit_length * 3 + target_field_prime_bit_length; this_cost += target_field_prime_bit_length * 3 + target_field_prime_bit_length + num_of_limbs; this_cost += num_of_limbs * num_of_limbs + 2 * (2 * num_of_limbs - 1); this_cost += num_of_limbs
+ num_of_groups
+ 6 * num_of_groups
+ (num_of_groups - 1) * (2 * limb_size + surfeit) * 4
+ 2; }
};
if !found || this_cost < min_cost {
found = true;
min_cost = this_cost;
min_cost_limb_size = limb_size;
min_cost_num_of_limbs = num_of_limbs;
}
limb_size += 1;
}
(min_cost_num_of_limbs, min_cost_limb_size)
}
}