1#![allow(clippy::int_plus_one)]
2
3use std::ops::Range;
4
5use ff::{Field, FromUniformBytes};
6use group::Curve;
7
8use super::{
9 circuit::{
10 Advice, Any, Assignment, Circuit, Column, ConstraintSystem, Fixed, FloorPlanner, Instance,
11 Selector,
12 },
13 evaluation::Evaluator,
14 permutation, Assigned, Challenge, Error, LagrangeCoeff, Polynomial, ProvingKey, VerifyingKey,
15};
16use crate::{
17 arithmetic::{parallelize, CurveAffine},
18 circuit::Value,
19 multicore::{IntoParallelIterator, ParallelIterator},
20 poly::{
21 batch_invert_assigned,
22 commitment::{Blind, Params},
23 EvaluationDomain,
24 },
25};
26
27pub(crate) fn create_domain<C, ConcreteCircuit>(
28 k: u32,
29 #[cfg(feature = "circuit-params")] params: ConcreteCircuit::Params,
30) -> (
31 EvaluationDomain<C::Scalar>,
32 ConstraintSystem<C::Scalar>,
33 ConcreteCircuit::Config,
34)
35where
36 C: CurveAffine,
37 ConcreteCircuit: Circuit<C::Scalar>,
38{
39 let mut cs = ConstraintSystem::default();
40 #[cfg(feature = "circuit-params")]
41 let config = ConcreteCircuit::configure_with_params(&mut cs, params);
42 #[cfg(not(feature = "circuit-params"))]
43 let config = ConcreteCircuit::configure(&mut cs);
44
45 let degree = cs.degree();
46
47 let domain = EvaluationDomain::new(degree as u32, k);
48
49 (domain, cs, config)
50}
51
52#[derive(Debug)]
54struct Assembly<F: Field> {
55 k: u32,
56 fixed: Vec<Polynomial<Assigned<F>, LagrangeCoeff>>,
57 permutation: permutation::keygen::Assembly,
58 selectors: Vec<Vec<bool>>,
59 usable_rows: Range<usize>,
61 _marker: std::marker::PhantomData<F>,
62}
63
64impl<F: Field> Assignment<F> for Assembly<F> {
65 fn enter_region<NR, N>(&mut self, _: N)
66 where
67 NR: Into<String>,
68 N: FnOnce() -> NR,
69 {
70 }
72
73 fn exit_region(&mut self) {
74 }
76
77 fn enable_selector<A, AR>(&mut self, _: A, selector: &Selector, row: usize) -> Result<(), Error>
78 where
79 A: FnOnce() -> AR,
80 AR: Into<String>,
81 {
82 if !self.usable_rows.contains(&row) {
83 return Err(Error::not_enough_rows_available(self.k));
84 }
85
86 self.selectors[selector.0][row] = true;
87
88 Ok(())
89 }
90
91 fn query_instance(&self, _: Column<Instance>, row: usize) -> Result<Value<F>, Error> {
92 if !self.usable_rows.contains(&row) {
93 return Err(Error::not_enough_rows_available(self.k));
94 }
95
96 Ok(Value::unknown())
98 }
99
100 fn assign_advice<'v>(
101 &mut self,
103 _: Column<Advice>,
105 _: usize,
106 _: Value<Assigned<F>>,
107 ) -> Value<&'v Assigned<F>> {
108 Value::unknown()
109 }
110
111 fn assign_fixed(&mut self, column: Column<Fixed>, row: usize, to: Assigned<F>) {
112 if !self.usable_rows.contains(&row) {
113 panic!(
114 "Assign Fixed {:?}",
115 Error::not_enough_rows_available(self.k)
116 );
117 }
118
119 *self
120 .fixed
121 .get_mut(column.index())
122 .and_then(|v| v.get_mut(row))
123 .unwrap_or_else(|| panic!("{:?}", Error::BoundsFailure)) = to;
124 }
125
126 fn copy(
127 &mut self,
128 left_column: Column<Any>,
129 left_row: usize,
130 right_column: Column<Any>,
131 right_row: usize,
132 ) {
133 if !self.usable_rows.contains(&left_row) || !self.usable_rows.contains(&right_row) {
134 panic!("{:?}", Error::not_enough_rows_available(self.k));
135 }
136
137 self.permutation
138 .copy(left_column, left_row, right_column, right_row)
139 .unwrap_or_else(|err| panic!("{err:?}"))
140 }
141
142 fn fill_from_row(
143 &mut self,
144 column: Column<Fixed>,
145 from_row: usize,
146 to: Value<Assigned<F>>,
147 ) -> Result<(), Error> {
148 if !self.usable_rows.contains(&from_row) {
149 return Err(Error::not_enough_rows_available(self.k));
150 }
151
152 let col = self
153 .fixed
154 .get_mut(column.index())
155 .ok_or(Error::BoundsFailure)?;
156
157 let filler = to.assign()?;
158 for row in self.usable_rows.clone().skip(from_row) {
159 col[row] = filler;
160 }
161
162 Ok(())
163 }
164
165 fn get_challenge(&self, _: Challenge) -> Value<F> {
166 Value::unknown()
167 }
168
169 fn annotate_column<A, AR>(&mut self, _annotation: A, _column: Column<Any>)
170 where
171 A: FnOnce() -> AR,
172 AR: Into<String>,
173 {
174 }
176
177 fn push_namespace<NR, N>(&mut self, _: N)
178 where
179 NR: Into<String>,
180 N: FnOnce() -> NR,
181 {
182 }
184
185 fn pop_namespace(&mut self, _: Option<String>) {
186 }
188}
189
190pub fn keygen_vk<'params, C, P, ConcreteCircuit>(
193 params: &P,
194 circuit: &ConcreteCircuit,
195) -> Result<VerifyingKey<C>, Error>
196where
197 C: CurveAffine,
198 P: Params<'params, C> + Sync,
199 ConcreteCircuit: Circuit<C::Scalar>,
200 C::Scalar: FromUniformBytes<64>,
201{
202 keygen_vk_custom(params, circuit, false)
203}
204
205pub fn keygen_vk_custom<'params, C, P, ConcreteCircuit>(
209 params: &P,
210 circuit: &ConcreteCircuit,
211 compress_selectors: bool,
212) -> Result<VerifyingKey<C>, Error>
213where
214 C: CurveAffine,
215 P: Params<'params, C> + Sync,
216 ConcreteCircuit: Circuit<C::Scalar>,
217 C::Scalar: FromUniformBytes<64>,
218{
219 let (domain, cs, config) = create_domain::<C, ConcreteCircuit>(
220 params.k(),
221 #[cfg(feature = "circuit-params")]
222 circuit.params(),
223 );
224
225 if (params.n() as usize) < cs.minimum_rows() {
226 return Err(Error::not_enough_rows_available(params.k()));
227 }
228
229 let mut assembly: Assembly<C::Scalar> = Assembly {
230 k: params.k(),
231 fixed: vec![domain.empty_lagrange_assigned(); cs.num_fixed_columns],
232 permutation: permutation::keygen::Assembly::new(params.n() as usize, &cs.permutation),
233 selectors: vec![vec![false; params.n() as usize]; cs.num_selectors],
234 usable_rows: 0..params.n() as usize - (cs.blinding_factors() + 1),
235 _marker: std::marker::PhantomData,
236 };
237
238 ConcreteCircuit::FloorPlanner::synthesize(
240 &mut assembly,
241 circuit,
242 config,
243 cs.constants.clone(),
244 )?;
245
246 let mut fixed = batch_invert_assigned(assembly.fixed);
247 let (cs, selector_polys) = if compress_selectors {
248 cs.compress_selectors(assembly.selectors.clone())
249 } else {
250 let selectors = std::mem::take(&mut assembly.selectors);
252 cs.directly_convert_selectors_to_fixed(selectors)
253 };
254 fixed.extend(
255 selector_polys
256 .into_iter()
257 .map(|poly| domain.lagrange_from_vec(poly)),
258 );
259
260 let permutation_vk = assembly
261 .permutation
262 .build_vk(params, &domain, &cs.permutation);
263
264 let fixed_commitments = (&fixed)
265 .into_par_iter()
266 .map(|poly| params.commit_lagrange(poly, Blind::default()).to_affine())
267 .collect();
268
269 Ok(VerifyingKey::from_parts(
270 domain,
271 fixed_commitments,
272 permutation_vk,
273 cs,
274 assembly.selectors,
275 compress_selectors,
276 ))
277}
278
279pub fn keygen_pk<'params, C, P, ConcreteCircuit>(
281 params: &P,
282 vk: VerifyingKey<C>,
283 circuit: &ConcreteCircuit,
284) -> Result<ProvingKey<C>, Error>
285where
286 C: CurveAffine,
287 C::Scalar: FromUniformBytes<64>,
288 P: Params<'params, C> + Sync,
289 ConcreteCircuit: Circuit<C::Scalar>,
290{
291 let compress_selectors = vk.compress_selectors;
292 keygen_pk_impl(params, Some(vk), circuit, compress_selectors)
293}
294
295pub fn keygen_pk2<'params, C, P, ConcreteCircuit>(
297 params: &P,
298 circuit: &ConcreteCircuit,
299 compress_selectors: bool,
300) -> Result<ProvingKey<C>, Error>
301where
302 C: CurveAffine,
303 C::Scalar: FromUniformBytes<64>,
304 P: Params<'params, C> + Sync,
305 ConcreteCircuit: Circuit<C::Scalar>,
306{
307 keygen_pk_impl(params, None, circuit, compress_selectors)
308}
309
310pub fn keygen_pk_impl<'params, C, P, ConcreteCircuit>(
314 params: &P,
315 vk: Option<VerifyingKey<C>>,
316 circuit: &ConcreteCircuit,
317 compress_selectors: bool,
318) -> Result<ProvingKey<C>, Error>
319where
320 C: CurveAffine,
321 C::Scalar: FromUniformBytes<64>,
322 P: Params<'params, C> + Sync,
323 ConcreteCircuit: Circuit<C::Scalar>,
324{
325 let (domain, cs, config) = create_domain::<C, ConcreteCircuit>(
326 params.k(),
327 #[cfg(feature = "circuit-params")]
328 circuit.params(),
329 );
330
331 if (params.n() as usize) < cs.minimum_rows() {
332 return Err(Error::not_enough_rows_available(params.k()));
333 }
334
335 let mut assembly: Assembly<C::Scalar> = Assembly {
336 k: params.k(),
337 fixed: vec![domain.empty_lagrange_assigned(); cs.num_fixed_columns],
338 permutation: permutation::keygen::Assembly::new(params.n() as usize, &cs.permutation),
339 selectors: vec![vec![false; params.n() as usize]; cs.num_selectors],
340 usable_rows: 0..params.n() as usize - (cs.blinding_factors() + 1),
341 _marker: std::marker::PhantomData,
342 };
343
344 ConcreteCircuit::FloorPlanner::synthesize(
346 &mut assembly,
347 circuit,
348 config,
349 cs.constants.clone(),
350 )?;
351
352 let mut fixed = batch_invert_assigned(assembly.fixed);
353 let (cs, selector_polys) = if compress_selectors {
354 cs.compress_selectors(assembly.selectors.clone())
355 } else {
356 let selectors = std::mem::take(&mut assembly.selectors);
357 cs.directly_convert_selectors_to_fixed(selectors)
358 };
359 fixed.extend(
360 selector_polys
361 .into_iter()
362 .map(|poly| domain.lagrange_from_vec(poly)),
363 );
364
365 let permutation_pk = assembly
366 .permutation
367 .clone()
368 .build_pk(params, &domain, &cs.permutation);
369
370 let vk = match vk {
371 Some(vk) => vk,
372 None => {
373 let permutation_vk = assembly
374 .permutation
375 .build_vk(params, &domain, &cs.permutation);
376
377 let fixed_commitments = (&fixed)
378 .into_par_iter()
379 .map(|poly| params.commit_lagrange(poly, Blind::default()).to_affine())
380 .collect();
381
382 VerifyingKey::from_parts(
383 domain,
384 fixed_commitments,
385 permutation_vk,
386 cs,
387 assembly.selectors,
388 compress_selectors,
389 )
390 }
391 };
392
393 let fixed_polys: Vec<_> = fixed
394 .iter()
395 .map(|poly| vk.domain.lagrange_to_coeff(poly.clone()))
396 .collect();
397
398 let mut l0 = vk.domain.empty_lagrange();
401 l0[0] = C::Scalar::ONE;
402 let l0 = vk.domain.lagrange_to_coeff(l0);
403
404 let mut l_blind = vk.domain.empty_lagrange();
407 for evaluation in l_blind[..].iter_mut().rev().take(vk.cs.blinding_factors()) {
408 *evaluation = C::Scalar::ONE;
409 }
410
411 let mut l_last = vk.domain.empty_lagrange();
414 l_last[params.n() as usize - vk.cs.blinding_factors() - 1] = C::Scalar::ONE;
415
416 let one = C::Scalar::ONE;
418 let mut l_active_row = vk.domain.empty_lagrange();
419 parallelize(&mut l_active_row, |values, start| {
420 for (i, value) in values.iter_mut().enumerate() {
421 let idx = i + start;
422 *value = one - (l_last[idx] + l_blind[idx]);
423 }
424 });
425
426 let l_last = vk.domain.lagrange_to_coeff(l_last);
427 let l_active_row = vk.domain.lagrange_to_coeff(l_active_row);
428
429 let ev = Evaluator::new(&vk.cs);
431
432 Ok(ProvingKey {
433 vk,
434 l0,
435 l_last,
436 l_active_row,
437 fixed_values: fixed,
438 fixed_polys,
439 permutation: permutation_pk,
440 ev,
441 })
442}