1#![allow(clippy::int_plus_one)]
2
3use std::ops::Range;
4
5use ff::Field;
6use group::Curve;
7
8use super::{
9 circuit::{
10 Advice, Any, Assignment, Circuit, Column, ConstraintSystem, Fixed, FloorPlanner, Instance,
11 Selector,
12 },
13 permutation, Assigned, Error, LagrangeCoeff, Polynomial, ProvingKey, VerifyingKey,
14};
15use crate::poly::{
16 commitment::{Blind, Params},
17 EvaluationDomain,
18};
19use crate::{arithmetic::CurveAffine, poly::batch_invert_assigned};
20
21pub(crate) fn create_domain<C, ConcreteCircuit>(
22 params: &Params<C>,
23) -> (
24 EvaluationDomain<C::Scalar>,
25 ConstraintSystem<C::Scalar>,
26 ConcreteCircuit::Config,
27)
28where
29 C: CurveAffine,
30 ConcreteCircuit: Circuit<C::Scalar>,
31{
32 let mut cs = ConstraintSystem::default();
33 let config = ConcreteCircuit::configure(&mut cs);
34
35 let degree = cs.degree();
36
37 let domain = EvaluationDomain::new(degree as u32, params.k);
38
39 (domain, cs, config)
40}
41
42#[derive(Debug)]
44struct Assembly<F: Field> {
45 k: u32,
46 fixed: Vec<Polynomial<Assigned<F>, LagrangeCoeff>>,
47 permutation: permutation::keygen::Assembly,
48 selectors: Vec<Vec<bool>>,
49 usable_rows: Range<usize>,
51 _marker: std::marker::PhantomData<F>,
52}
53
54impl<F: Field> Assignment<F> for Assembly<F> {
55 fn enter_region<NR, N>(&mut self, _: N)
56 where
57 NR: Into<String>,
58 N: FnOnce() -> NR,
59 {
60 }
62
63 fn exit_region(&mut self) {
64 }
66
67 fn enable_selector<A, AR>(&mut self, _: A, selector: &Selector, row: usize) -> Result<(), Error>
68 where
69 A: FnOnce() -> AR,
70 AR: Into<String>,
71 {
72 if !self.usable_rows.contains(&row) {
73 return Err(Error::not_enough_rows_available(self.k));
74 }
75
76 self.selectors[selector.0][row] = true;
77
78 Ok(())
79 }
80
81 fn query_instance(&self, _: Column<Instance>, row: usize) -> Result<Option<F>, Error> {
82 if !self.usable_rows.contains(&row) {
83 return Err(Error::not_enough_rows_available(self.k));
84 }
85
86 Ok(None)
88 }
89
90 fn assign_advice<V, VR, A, AR>(
91 &mut self,
92 _: A,
93 _: Column<Advice>,
94 _: usize,
95 _: V,
96 ) -> Result<(), Error>
97 where
98 V: FnOnce() -> Result<VR, Error>,
99 VR: Into<Assigned<F>>,
100 A: FnOnce() -> AR,
101 AR: Into<String>,
102 {
103 Ok(())
105 }
106
107 fn assign_fixed<V, VR, A, AR>(
108 &mut self,
109 _: A,
110 column: Column<Fixed>,
111 row: usize,
112 to: V,
113 ) -> Result<(), Error>
114 where
115 V: FnOnce() -> Result<VR, Error>,
116 VR: Into<Assigned<F>>,
117 A: FnOnce() -> AR,
118 AR: Into<String>,
119 {
120 if !self.usable_rows.contains(&row) {
121 return Err(Error::not_enough_rows_available(self.k));
122 }
123
124 *self
125 .fixed
126 .get_mut(column.index())
127 .and_then(|v| v.get_mut(row))
128 .ok_or(Error::BoundsFailure)? = to()?.into();
129
130 Ok(())
131 }
132
133 fn copy(
134 &mut self,
135 left_column: Column<Any>,
136 left_row: usize,
137 right_column: Column<Any>,
138 right_row: usize,
139 ) -> Result<(), Error> {
140 if !self.usable_rows.contains(&left_row) || !self.usable_rows.contains(&right_row) {
141 return Err(Error::not_enough_rows_available(self.k));
142 }
143
144 self.permutation
145 .copy(left_column, left_row, right_column, right_row)
146 }
147
148 fn fill_from_row(
149 &mut self,
150 column: Column<Fixed>,
151 from_row: usize,
152 to: Option<Assigned<F>>,
153 ) -> Result<(), Error> {
154 if !self.usable_rows.contains(&from_row) {
155 return Err(Error::not_enough_rows_available(self.k));
156 }
157
158 let col = self
159 .fixed
160 .get_mut(column.index())
161 .ok_or(Error::BoundsFailure)?;
162
163 for row in self.usable_rows.clone().skip(from_row) {
164 col[row] = to.ok_or(Error::Synthesis)?;
165 }
166
167 Ok(())
168 }
169
170 fn push_namespace<NR, N>(&mut self, _: N)
171 where
172 NR: Into<String>,
173 N: FnOnce() -> NR,
174 {
175 }
177
178 fn pop_namespace(&mut self, _: Option<String>) {
179 }
181}
182
183pub fn keygen_vk<C, ConcreteCircuit>(
185 params: &Params<C>,
186 circuit: &ConcreteCircuit,
187) -> Result<VerifyingKey<C>, Error>
188where
189 C: CurveAffine,
190 ConcreteCircuit: Circuit<C::Scalar>,
191{
192 let (domain, cs, config) = create_domain::<C, ConcreteCircuit>(params);
193
194 if (params.n as usize) < cs.minimum_rows() {
195 return Err(Error::not_enough_rows_available(params.k));
196 }
197
198 let mut assembly: Assembly<C::Scalar> = Assembly {
199 k: params.k,
200 fixed: vec![domain.empty_lagrange_assigned(); cs.num_fixed_columns],
201 permutation: permutation::keygen::Assembly::new(params.n as usize, &cs.permutation),
202 selectors: vec![vec![false; params.n as usize]; cs.num_selectors],
203 usable_rows: 0..params.n as usize - (cs.blinding_factors() + 1),
204 _marker: std::marker::PhantomData,
205 };
206
207 ConcreteCircuit::FloorPlanner::synthesize(
209 &mut assembly,
210 circuit,
211 config,
212 cs.constants.clone(),
213 )?;
214
215 let mut fixed = batch_invert_assigned(assembly.fixed);
216 let (cs, selector_polys) = cs.compress_selectors(assembly.selectors);
217 fixed.extend(
218 selector_polys
219 .into_iter()
220 .map(|poly| domain.lagrange_from_vec(poly)),
221 );
222
223 let permutation_vk = assembly
224 .permutation
225 .build_vk(params, &domain, &cs.permutation);
226
227 let fixed_commitments = fixed
228 .iter()
229 .map(|poly| params.commit_lagrange(poly, Blind::default()).to_affine())
230 .collect();
231
232 Ok(VerifyingKey {
233 domain,
234 fixed_commitments,
235 permutation: permutation_vk,
236 cs,
237 })
238}
239
240pub fn keygen_pk<C, ConcreteCircuit>(
242 params: &Params<C>,
243 vk: VerifyingKey<C>,
244 circuit: &ConcreteCircuit,
245) -> Result<ProvingKey<C>, Error>
246where
247 C: CurveAffine,
248 ConcreteCircuit: Circuit<C::Scalar>,
249{
250 let mut cs = ConstraintSystem::default();
251 let config = ConcreteCircuit::configure(&mut cs);
252
253 let cs = cs;
254
255 if (params.n as usize) < cs.minimum_rows() {
256 return Err(Error::not_enough_rows_available(params.k));
257 }
258
259 let mut assembly: Assembly<C::Scalar> = Assembly {
260 k: params.k,
261 fixed: vec![vk.domain.empty_lagrange_assigned(); cs.num_fixed_columns],
262 permutation: permutation::keygen::Assembly::new(params.n as usize, &cs.permutation),
263 selectors: vec![vec![false; params.n as usize]; cs.num_selectors],
264 usable_rows: 0..params.n as usize - (cs.blinding_factors() + 1),
265 _marker: std::marker::PhantomData,
266 };
267
268 ConcreteCircuit::FloorPlanner::synthesize(
270 &mut assembly,
271 circuit,
272 config,
273 cs.constants.clone(),
274 )?;
275
276 let mut fixed = batch_invert_assigned(assembly.fixed);
277 let (cs, selector_polys) = cs.compress_selectors(assembly.selectors);
278 fixed.extend(
279 selector_polys
280 .into_iter()
281 .map(|poly| vk.domain.lagrange_from_vec(poly)),
282 );
283
284 let fixed_polys: Vec<_> = fixed
285 .iter()
286 .map(|poly| vk.domain.lagrange_to_coeff(poly.clone()))
287 .collect();
288
289 let fixed_cosets = fixed_polys
290 .iter()
291 .map(|poly| vk.domain.coeff_to_extended(poly.clone()))
292 .collect();
293
294 let permutation_pk = assembly
295 .permutation
296 .build_pk(params, &vk.domain, &cs.permutation);
297
298 let mut l0 = vk.domain.empty_lagrange();
301 l0[0] = C::Scalar::one();
302 let l0 = vk.domain.lagrange_to_coeff(l0);
303 let l0 = vk.domain.coeff_to_extended(l0);
304
305 let mut l_blind = vk.domain.empty_lagrange();
308 for evaluation in l_blind[..].iter_mut().rev().take(cs.blinding_factors()) {
309 *evaluation = C::Scalar::one();
310 }
311 let l_blind = vk.domain.lagrange_to_coeff(l_blind);
312 let l_blind = vk.domain.coeff_to_extended(l_blind);
313
314 let mut l_last = vk.domain.empty_lagrange();
317 l_last[params.n as usize - cs.blinding_factors() - 1] = C::Scalar::one();
318 let l_last = vk.domain.lagrange_to_coeff(l_last);
319 let l_last = vk.domain.coeff_to_extended(l_last);
320
321 Ok(ProvingKey {
322 vk,
323 l0,
324 l_blind,
325 l_last,
326 fixed_values: fixed,
327 fixed_polys,
328 fixed_cosets,
329 permutation: permutation_pk,
330 })
331}