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 {
27 type Parameters;
29
30 fn sample_parameters() -> Self::Parameters;
31
32 fn new_with_parameters(params: &Self::Parameters) -> Self;
34
35 fn new() -> Self {
37 let parameters = Self::sample_parameters();
38 Self::new_with_parameters(¶meters)
39 }
40
41 fn absorb_native_field_elements<T: ToConstraintField<F>>(&mut self, elements: &[T]);
43
44 fn absorb_nonnative_field_elements<Target: PrimeField>(&mut self, elements: impl IntoIterator<Item = Target>);
46
47 fn absorb_bytes(&mut self, elements: &[u8]) {
49 let capacity = F::size_in_bits() - 1;
50 let mut bits = Vec::<bool>::with_capacity(elements.len() * 8);
51 for elem in elements {
52 bits.extend_from_slice(&[
53 elem & 128 != 0,
54 elem & 64 != 0,
55 elem & 32 != 0,
56 elem & 16 != 0,
57 elem & 8 != 0,
58 elem & 4 != 0,
59 elem & 2 != 0,
60 elem & 1 != 0,
61 ]);
62 }
63 let elements = bits
64 .chunks(capacity)
65 .map(|bits| F::from_bigint(F::BigInteger::from_bits_be(bits).unwrap()).unwrap())
66 .collect::<SmallVec<[F; 10]>>();
67
68 self.absorb_native_field_elements(&elements);
69 }
70
71 fn squeeze_native_field_elements(&mut self, num: usize) -> SmallVec<[F; 10]>;
73
74 fn squeeze_nonnative_field_elements<Target: PrimeField>(&mut self, num: usize) -> SmallVec<[Target; 10]>;
76
77 fn squeeze_short_nonnative_field_elements<Target: PrimeField>(&mut self, num: usize) -> SmallVec<[Target; 10]>;
79
80 fn squeeze_short_nonnative_field_element<Target: PrimeField>(&mut self) -> Target {
82 self.squeeze_short_nonnative_field_elements(1)[0]
83 }
84}
85
86#[derive(PartialEq, Eq, Clone, Debug)]
88pub enum DuplexSpongeMode {
89 Absorbing {
91 next_absorb_index: usize,
93 },
94 Squeezing {
96 next_squeeze_index: usize,
98 },
99}
100
101pub(crate) mod nonnative_params {
102 #[macro_export]
107 macro_rules! overhead {
108 ($x:expr, $num_bits:expr) => {{
109 use snarkvm_utilities::ToBits;
110 let num = $x;
111 let num_bits = $num_bits;
112 num.to_bigint().write_bits_be(num_bits);
113 let mut skipped_bits = 0;
114 for b in num_bits.iter() {
115 if *b == false {
116 skipped_bits += 1;
117 } else {
118 break;
119 }
120 }
121
122 let mut is_power_of_2 = true;
123 for b in num_bits.iter().skip(skipped_bits + 1) {
124 if *b == true {
125 is_power_of_2 = false;
126 }
127 }
128
129 let result = if is_power_of_2 { num_bits.len() - skipped_bits } else { num_bits.len() - skipped_bits + 1 };
130
131 num_bits.clear();
133
134 result
135 }};
136 }
137
138 #[derive(Clone, Debug)]
140 pub struct NonNativeFieldParams {
141 pub num_limbs: usize,
144
145 pub bits_per_limb: usize,
147 }
148
149 #[must_use]
152 pub const fn get_params(
153 target_field_size: usize,
154 base_field_size: usize,
155 optimization_type: OptimizationType,
156 ) -> NonNativeFieldParams {
157 let (num_of_limbs, limb_size) = find_parameters(base_field_size, target_field_size, optimization_type);
158 NonNativeFieldParams { num_limbs: num_of_limbs, bits_per_limb: limb_size }
159 }
160
161 #[derive(Clone, Copy, Debug, PartialEq, Eq)]
162 pub enum OptimizationType {
164 Constraints,
166 Weight,
168 }
169
170 pub const fn find_parameters(
172 base_field_prime_length: usize,
173 target_field_prime_bit_length: usize,
174 optimization_type: OptimizationType,
175 ) -> (usize, usize) {
176 let mut found = false;
177 let mut min_cost = 0usize;
178 let mut min_cost_limb_size = 0usize;
179 let mut min_cost_num_of_limbs = 0usize;
180
181 let surfeit = 10;
182 let mut max_limb_size = (base_field_prime_length - 1 - surfeit - 1) / 2 - 1;
183 if max_limb_size > target_field_prime_bit_length {
184 max_limb_size = target_field_prime_bit_length;
185 }
186 let mut limb_size = 1;
187
188 while limb_size <= max_limb_size {
189 let num_of_limbs = target_field_prime_bit_length.div_ceil(limb_size);
190
191 let group_size = (base_field_prime_length - 1 - surfeit - 1 - 1 - limb_size).div_ceil(limb_size);
192 let num_of_groups = (2 * num_of_limbs - 1).div_ceil(group_size);
193
194 let mut this_cost = 0;
195
196 match optimization_type {
197 OptimizationType::Constraints => {
198 this_cost += 2 * num_of_limbs - 1;
199 }
200 OptimizationType::Weight => {
201 this_cost += 6 * num_of_limbs * num_of_limbs;
202 }
203 };
204
205 match optimization_type {
206 OptimizationType::Constraints => {
207 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;
211 }
213 OptimizationType::Weight => {
214 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
218 + num_of_groups
219 + 6 * num_of_groups
220 + (num_of_groups - 1) * (2 * limb_size + surfeit) * 4
221 + 2; }
223 };
224
225 if !found || this_cost < min_cost {
226 found = true;
227 min_cost = this_cost;
228 min_cost_limb_size = limb_size;
229 min_cost_num_of_limbs = num_of_limbs;
230 }
231
232 limb_size += 1;
233 }
234
235 (min_cost_num_of_limbs, min_cost_limb_size)
236 }
237}