1use alloc::{format, string::ToString, vec::Vec};
23
24use crate::{
25 circuits::{argument::ArgumentType, gate::GateType},
26 collections::HashMap,
27};
28use ark_ff::Field;
29use core::{
30 fmt::Display,
31 iter::{Cloned, Skip, Take},
32 ops::Range,
33 slice::Iter,
34};
35use serde::{Deserialize, Serialize};
36
37#[derive(Debug, Default, Serialize, Deserialize, Clone)]
44pub struct Alphas<F> {
45 next_power: u32,
48 mapping: HashMap<ArgumentType, (u32, u32)>,
50 alphas: Option<Vec<F>>,
53}
54
55impl<F: Field> Alphas<F> {
56 pub fn register(&mut self, ty: ArgumentType, powers: u32) {
60 if self.alphas.is_some() {
61 panic!("you cannot register new constraints once initialized with a field element");
62 }
63
64 let ty = if matches!(ty, ArgumentType::Gate(_)) {
67 ArgumentType::Gate(GateType::Zero)
69 } else {
70 ty
71 };
72
73 if self.mapping.insert(ty, (self.next_power, powers)).is_some() {
74 panic!("cannot re-register {ty:?}");
75 }
76
77 self.next_power = self
78 .next_power
79 .checked_add(powers)
80 .expect("too many powers of alphas were registered");
81 }
82
83 pub fn get_exponents(
86 &self,
87 ty: ArgumentType,
88 num: u32,
89 ) -> MustConsumeIterator<Range<u32>, u32> {
90 let ty = if matches!(ty, ArgumentType::Gate(_)) {
91 ArgumentType::Gate(GateType::Zero)
92 } else {
93 ty
94 };
95
96 let range = self
97 .mapping
98 .get(&ty)
99 .unwrap_or_else(|| panic!("constraint {ty:?} was not registered"));
100
101 if num > range.1 {
102 panic!(
103 "you asked for {num} exponents, but only registered {} for {:?}",
104 range.1, ty
105 );
106 }
107
108 let start = range.0;
109 let end = start + num;
110
111 MustConsumeIterator {
112 inner: start..end,
113 debug_info: ty,
114 }
115 }
116
117 pub fn instantiate(&mut self, alpha: F) {
120 let mut last_power = F::one();
121 let mut alphas = Vec::with_capacity(self.next_power as usize);
122 alphas.push(F::one());
123 for _ in 1..self.next_power {
124 last_power *= alpha;
125 alphas.push(last_power);
126 }
127 self.alphas = Some(alphas);
128 }
129
130 pub fn get_alphas(
132 &self,
133 ty: ArgumentType,
134 num: u32,
135 ) -> MustConsumeIterator<Cloned<Take<Skip<Iter<'_, F>>>>, F> {
136 let ty = if matches!(ty, ArgumentType::Gate(_)) {
137 ArgumentType::Gate(GateType::Zero)
138 } else {
139 ty
140 };
141
142 let range = self
143 .mapping
144 .get(&ty)
145 .unwrap_or_else(|| panic!("constraint {ty:?} was not registered"));
146
147 if num > range.1 {
148 panic!(
149 "you asked for {num} alphas, but only {} are available for {:?}",
150 range.1, ty
151 );
152 }
153
154 match &self.alphas {
155 None => panic!("you must call instantiate with an actual field element first"),
156 Some(alphas) => {
157 let alphas_range = alphas
158 .iter()
159 .skip(range.0 as usize)
160 .take(num as usize)
161 .cloned();
162 MustConsumeIterator {
163 inner: alphas_range,
164 debug_info: ty,
165 }
166 }
167 }
168 }
169}
170
171impl<T> Display for Alphas<T> {
172 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
173 for arg in [
174 ArgumentType::Gate(GateType::Zero),
175 ArgumentType::Permutation,
176 ] {
178 let name = if matches!(arg, ArgumentType::Gate(_)) {
179 "gates".to_string()
180 } else {
181 format!("{arg:?}")
182 };
183 let range = self
184 .mapping
185 .get(&arg)
186 .expect("you need to register all arguments before calling display");
187 writeln!(
188 f,
189 "* **{}**. Offset starts at {} and {} powers of $\\alpha$ are used",
190 name, range.0, range.1
191 )?;
192 }
193
194 Ok(())
195 }
196}
197
198#[derive(Debug)]
202pub struct MustConsumeIterator<I, T>
203where
204 I: Iterator<Item = T>,
205 T: core::fmt::Display,
206{
207 inner: I,
208 debug_info: ArgumentType,
209}
210
211impl<I, T> Iterator for MustConsumeIterator<I, T>
212where
213 I: Iterator<Item = T>,
214 T: core::fmt::Display,
215{
216 type Item = I::Item;
217 fn next(&mut self) -> Option<Self::Item> {
218 self.inner.next()
219 }
220}
221
222impl<I, T> Drop for MustConsumeIterator<I, T>
223where
224 I: Iterator<Item = T>,
225 T: core::fmt::Display,
226{
227 fn drop(&mut self) {
228 if let Some(v) = self.inner.next() {
229 #[cfg(feature = "std")]
230 if std::thread::panicking() {
231 eprintln!("the registered number of powers of alpha for {:?} is too large, you haven't used alpha^{} (absolute power of alpha)", self.debug_info,
232 v);
233 return;
234 }
235 panic!("the registered number of powers of alpha for {:?} is too large, you haven't used alpha^{} (absolute power of alpha)", self.debug_info,
236 v);
237 }
238 }
239}
240
241#[cfg(all(test, feature = "prover"))]
244mod tests {
245 use super::*;
246 use crate::circuits::gate::GateType;
247 use mina_curves::pasta::{Fp, Vesta};
248 use mina_poseidon::pasta::FULL_ROUNDS;
249 use std::{fs, path::Path};
250
251 #[test]
254 fn incorrect_alpha_powers() {
255 let mut alphas = Alphas::<Fp>::default();
256 alphas.register(ArgumentType::Gate(GateType::Poseidon), 3);
257
258 let mut powers = alphas.get_exponents(ArgumentType::Gate(GateType::Poseidon), 3);
259 assert_eq!(powers.next(), Some(0));
260 assert_eq!(powers.next(), Some(1));
261 assert_eq!(powers.next(), Some(2));
262
263 alphas.register(ArgumentType::Permutation, 3);
264 let mut powers = alphas.get_exponents(ArgumentType::Permutation, 3);
265
266 assert_eq!(powers.next(), Some(3));
267 assert_eq!(powers.next(), Some(4));
268 assert_eq!(powers.next(), Some(5));
269 }
270
271 #[test]
272 #[should_panic]
273 fn register_after_instantiating() {
274 let mut alphas = Alphas::<Fp>::default();
275 alphas.instantiate(Fp::from(1));
276 alphas.register(ArgumentType::Gate(GateType::Poseidon), 3);
277 }
278
279 #[test]
280 #[should_panic]
281 fn didnt_use_all_alpha_powers() {
282 let mut alphas = Alphas::<Fp>::default();
283 alphas.register(ArgumentType::Permutation, 7);
284 let mut powers = alphas.get_exponents(ArgumentType::Permutation, 3);
285 powers.next();
286 }
287
288 #[test]
289 #[should_panic]
290 fn registered_alpha_powers_for_some_constraint_twice() {
291 let mut alphas = Alphas::<Fp>::default();
292 alphas.register(ArgumentType::Gate(GateType::Poseidon), 2);
293 alphas.register(ArgumentType::Gate(GateType::ForeignFieldMul), 3);
294 }
295
296 #[test]
297 fn powers_of_alpha() {
298 let mut alphas = Alphas::default();
299 alphas.register(ArgumentType::Gate(GateType::Poseidon), 4);
300 let mut powers = alphas.get_exponents(ArgumentType::Gate(GateType::Poseidon), 4);
301
302 assert_eq!(powers.next(), Some(0));
303 assert_eq!(powers.next(), Some(1));
304 assert_eq!(powers.next(), Some(2));
305 assert_eq!(powers.next(), Some(3));
306
307 let alpha = Fp::from(2);
308 alphas.instantiate(alpha);
309
310 let mut alphas = alphas.get_alphas(ArgumentType::Gate(GateType::Poseidon), 4);
311 assert_eq!(alphas.next(), Some(1.into()));
312 assert_eq!(alphas.next(), Some(2.into()));
313 assert_eq!(alphas.next(), Some(4.into()));
314 assert_eq!(alphas.next(), Some(8.into()));
315 }
316
317 use crate::{
320 circuits::{gate::CircuitGate, wires::Wire},
321 linearization::expr_linearization,
322 prover_index::testing::new_index_for_test,
323 };
324
325 #[test]
326 fn get_alphas_for_spec() {
327 let gates = vec![CircuitGate::<Fp>::zero(Wire::for_row(0)); 2];
328 let index = new_index_for_test::<FULL_ROUNDS, Vesta>(gates, 0);
329 let (_linearization, powers_of_alpha) =
330 expr_linearization::<Fp>(Some(&index.cs.feature_flags), true);
331 let manifest_dir = std::env::var("CARGO_MANIFEST_DIR").unwrap();
333 let spec_path = Path::new(&manifest_dir)
334 .join("..")
335 .join("book")
336 .join("specifications")
337 .join("kimchi")
338 .join("template.md");
339
340 let spec = fs::read_to_string(spec_path).unwrap();
341 if !spec.contains(&powers_of_alpha.to_string()) {
342 panic!(
343 "the specification of kimchi must contain the following paragraph:\n\n{powers_of_alpha}\n\n"
344 );
345 }
346 }
347}