snarkvm_algorithms/traits/
algebraic_sponge.rs1use smallvec::SmallVec;
17use snarkvm_fields::{PrimeField, ToConstraintField};
18use snarkvm_utilities::FromBits;
19
20use core::fmt::Debug;
21
22pub trait AlgebraicSponge<F: PrimeField, const RATE: usize>: Clone + Debug {
26 type Parameters;
28
29 fn sample_parameters() -> Self::Parameters;
30
31 fn new_with_parameters(params: &Self::Parameters) -> Self;
33
34 fn new() -> Self {
36 let parameters = Self::sample_parameters();
37 Self::new_with_parameters(¶meters)
38 }
39
40 fn absorb_native_field_elements<T: ToConstraintField<F>>(&mut self, elements: &[T]);
42
43 fn absorb_nonnative_field_elements<Target: PrimeField>(&mut self, elements: impl IntoIterator<Item = Target>);
45
46 fn absorb_bytes(&mut self, elements: &[u8]) {
48 let capacity = F::size_in_bits() - 1;
49 let mut bits = Vec::<bool>::with_capacity(elements.len() * 8);
50 for elem in elements {
51 bits.extend_from_slice(&[
52 elem & 128 != 0,
53 elem & 64 != 0,
54 elem & 32 != 0,
55 elem & 16 != 0,
56 elem & 8 != 0,
57 elem & 4 != 0,
58 elem & 2 != 0,
59 elem & 1 != 0,
60 ]);
61 }
62 let elements = bits
63 .chunks(capacity)
64 .map(|bits| F::from_bigint(F::BigInteger::from_bits_be(bits).unwrap()).unwrap())
65 .collect::<SmallVec<[F; 10]>>();
66
67 self.absorb_native_field_elements(&elements);
68 }
69
70 fn squeeze_native_field_elements(&mut self, num: usize) -> SmallVec<[F; 10]>;
72
73 fn squeeze_nonnative_field_elements<Target: PrimeField>(&mut self, num: usize) -> SmallVec<[Target; 10]>;
75
76 fn squeeze_short_nonnative_field_elements<Target: PrimeField>(&mut self, num: usize) -> SmallVec<[Target; 10]>;
78
79 fn squeeze_short_nonnative_field_element<Target: PrimeField>(&mut self) -> Target {
81 self.squeeze_short_nonnative_field_elements(1)[0]
82 }
83}
84
85#[derive(PartialEq, Eq, Clone, Debug)]
87pub enum DuplexSpongeMode {
88 Absorbing {
90 next_absorb_index: usize,
92 },
93 Squeezing {
95 next_squeeze_index: usize,
97 },
98}
99
100pub(crate) mod nonnative_params {
101 #[macro_export]
105 macro_rules! overhead {
106 ($x:expr, $num_bits:expr) => {{
107 use snarkvm_utilities::ToBits;
108 let num = $x;
109 let num_bits = $num_bits;
110 num.to_bigint().write_bits_be(num_bits);
111 let mut skipped_bits = 0;
112 for b in num_bits.iter() {
113 if *b == false {
114 skipped_bits += 1;
115 } else {
116 break;
117 }
118 }
119
120 let mut is_power_of_2 = true;
121 for b in num_bits.iter().skip(skipped_bits + 1) {
122 if *b == true {
123 is_power_of_2 = false;
124 }
125 }
126
127 let result = if is_power_of_2 { num_bits.len() - skipped_bits } else { num_bits.len() - skipped_bits + 1 };
128
129 num_bits.clear();
131
132 result
133 }};
134 }
135
136 #[derive(Clone, Debug)]
138 pub struct NonNativeFieldParams {
139 pub num_limbs: usize,
141
142 pub bits_per_limb: usize,
144 }
145
146 #[must_use]
148 pub const fn get_params(
149 target_field_size: usize,
150 base_field_size: usize,
151 optimization_type: OptimizationType,
152 ) -> NonNativeFieldParams {
153 let (num_of_limbs, limb_size) = find_parameters(base_field_size, target_field_size, optimization_type);
154 NonNativeFieldParams { num_limbs: num_of_limbs, bits_per_limb: limb_size }
155 }
156
157 #[derive(Clone, Copy, Debug, PartialEq, Eq)]
158 pub enum OptimizationType {
160 Constraints,
162 Weight,
164 }
165
166 pub const fn find_parameters(
168 base_field_prime_length: usize,
169 target_field_prime_bit_length: usize,
170 optimization_type: OptimizationType,
171 ) -> (usize, usize) {
172 let mut found = false;
173 let mut min_cost = 0usize;
174 let mut min_cost_limb_size = 0usize;
175 let mut min_cost_num_of_limbs = 0usize;
176
177 let surfeit = 10;
178 let mut max_limb_size = (base_field_prime_length - 1 - surfeit - 1) / 2 - 1;
179 if max_limb_size > target_field_prime_bit_length {
180 max_limb_size = target_field_prime_bit_length;
181 }
182 let mut limb_size = 1;
183
184 while limb_size <= max_limb_size {
185 let num_of_limbs = target_field_prime_bit_length.div_ceil(limb_size);
186
187 let group_size = (base_field_prime_length - 1 - surfeit - 1 - 1 - limb_size).div_ceil(limb_size);
188 let num_of_groups = (2 * num_of_limbs - 1).div_ceil(group_size);
189
190 let mut this_cost = 0;
191
192 match optimization_type {
193 OptimizationType::Constraints => {
194 this_cost += 2 * num_of_limbs - 1;
195 }
196 OptimizationType::Weight => {
197 this_cost += 6 * num_of_limbs * num_of_limbs;
198 }
199 };
200
201 match optimization_type {
202 OptimizationType::Constraints => {
203 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;
207 }
209 OptimizationType::Weight => {
210 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
214 + num_of_groups
215 + 6 * num_of_groups
216 + (num_of_groups - 1) * (2 * limb_size + surfeit) * 4
217 + 2; }
219 };
220
221 if !found || this_cost < min_cost {
222 found = true;
223 min_cost = this_cost;
224 min_cost_limb_size = limb_size;
225 min_cost_num_of_limbs = num_of_limbs;
226 }
227
228 limb_size += 1;
229 }
230
231 (min_cost_num_of_limbs, min_cost_limb_size)
232 }
233}