halo2_axiom/plonk/permutation/
prover.rs
1use ff::PrimeField;
2use group::{
3 ff::{BatchInvert, Field},
4 Curve,
5};
6use rand_core::RngCore;
7use std::iter::{self, ExactSizeIterator};
8
9use super::super::{circuit::Any, ChallengeBeta, ChallengeGamma, ChallengeX};
10use super::{Argument, ProvingKey};
11use crate::{
12 arithmetic::{eval_polynomial, parallelize, CurveAffine},
13 plonk::{self, Error},
14 poly::{
15 commitment::{Blind, Params},
16 Coeff, LagrangeCoeff, Polynomial, ProverQuery, Rotation,
17 },
18 transcript::{EncodedChallenge, TranscriptWrite},
19};
20
21pub(crate) struct CommittedSet<C: CurveAffine> {
22 pub(crate) permutation_product_poly: Polynomial<C::Scalar, Coeff>,
23 permutation_product_blind: Blind<C::Scalar>,
24}
25
26pub(crate) struct Committed<C: CurveAffine> {
27 pub(crate) sets: Vec<CommittedSet<C>>,
28}
29
30pub struct ConstructedSet<C: CurveAffine> {
31 permutation_product_poly: Polynomial<C::Scalar, Coeff>,
32 permutation_product_blind: Blind<C::Scalar>,
33}
34
35pub(crate) struct Constructed<C: CurveAffine> {
36 sets: Vec<ConstructedSet<C>>,
37}
38
39pub(crate) struct Evaluated<C: CurveAffine> {
40 constructed: Constructed<C>,
41}
42
43impl Argument {
44 #[allow(clippy::too_many_arguments)]
45 pub(in crate::plonk) fn commit<
46 'params,
47 C: CurveAffine,
48 P: Params<'params, C>,
49 E: EncodedChallenge<C>,
50 R: RngCore,
51 T: TranscriptWrite<C, E>,
52 >(
53 &self,
54 params: &P,
55 pk: &plonk::ProvingKey<C>,
56 pkey: &ProvingKey<C>,
57 advice: &[Polynomial<C::Scalar, LagrangeCoeff>],
58 fixed: &[Polynomial<C::Scalar, LagrangeCoeff>],
59 instance: &[Polynomial<C::Scalar, LagrangeCoeff>],
60 beta: ChallengeBeta<C>,
61 gamma: ChallengeGamma<C>,
62 mut rng: R,
63 transcript: &mut T,
64 ) -> Result<Committed<C>, Error> {
65 let domain = &pk.vk.domain;
66
67 assert!(pk.vk.cs_degree >= 3);
72 let chunk_len = pk.vk.cs_degree - 2;
73 let blinding_factors = pk.vk.cs.blinding_factors();
74
75 let mut deltaomega = C::Scalar::ONE;
77
78 let mut last_z = C::Scalar::ONE;
80
81 let mut sets = vec![];
82
83 for (columns, permutations) in self
84 .columns
85 .chunks(chunk_len)
86 .zip(pkey.permutations.chunks(chunk_len))
87 {
88 let mut modified_values = vec![C::Scalar::ONE; params.n() as usize];
97
98 for (&column, permuted_column_values) in columns.iter().zip(permutations.iter()) {
100 let values = match column.column_type() {
101 Any::Advice(_) => advice,
102 Any::Fixed => fixed,
103 Any::Instance => instance,
104 };
105 parallelize(&mut modified_values, |modified_values, start| {
106 for ((modified_values, value), permuted_value) in modified_values
107 .iter_mut()
108 .zip(values[column.index()][start..].iter())
109 .zip(permuted_column_values[start..].iter())
110 {
111 *modified_values *= &(*beta * permuted_value + &*gamma + value);
112 }
113 });
114 }
115
116 modified_values.batch_invert();
118
119 for &column in columns.iter() {
122 let omega = domain.get_omega();
123 let values = match column.column_type() {
124 Any::Advice(_) => advice,
125 Any::Fixed => fixed,
126 Any::Instance => instance,
127 };
128 parallelize(&mut modified_values, |modified_values, start| {
129 let mut deltaomega = deltaomega * &omega.pow_vartime([start as u64, 0, 0, 0]);
130 for (modified_values, value) in modified_values
131 .iter_mut()
132 .zip(values[column.index()][start..].iter())
133 {
134 *modified_values *= &(deltaomega * &*beta + &*gamma + value);
136 deltaomega *= ω
137 }
138 });
139 deltaomega *= &<C::Scalar as PrimeField>::DELTA;
140 }
141
142 let mut z = vec![last_z];
154 for row in 1..(params.n() as usize) {
155 let mut tmp = z[row - 1];
156
157 tmp *= &modified_values[row - 1];
158 z.push(tmp);
159 }
160 let mut z = domain.lagrange_from_vec(z);
161 for z in &mut z[params.n() as usize - blinding_factors..] {
163 *z = C::Scalar::random(&mut rng);
164 }
165 last_z = z[params.n() as usize - (blinding_factors + 1)];
167
168 let blind = Blind(C::Scalar::random(&mut rng));
169
170 let permutation_product_commitment_projective = params.commit_lagrange(&z, blind);
171 let permutation_product_blind = blind;
172 let z = domain.lagrange_to_coeff(z);
173 let permutation_product_poly = z.clone();
174
175 let permutation_product_commitment =
176 permutation_product_commitment_projective.to_affine();
177
178 transcript.write_point(permutation_product_commitment)?;
180
181 sets.push(CommittedSet {
182 permutation_product_poly,
183 permutation_product_blind,
184 });
185 }
186
187 Ok(Committed { sets })
188 }
189}
190
191impl<C: CurveAffine> Committed<C> {
192 pub(in crate::plonk) fn construct(self) -> Constructed<C> {
193 Constructed {
194 sets: self
195 .sets
196 .iter()
197 .map(|set| ConstructedSet {
198 permutation_product_poly: set.permutation_product_poly.clone(),
199 permutation_product_blind: set.permutation_product_blind,
200 })
201 .collect(),
202 }
203 }
204}
205
206impl<C: CurveAffine> super::ProvingKey<C> {
207 pub(in crate::plonk) fn open(
208 &self,
209 x: ChallengeX<C>,
210 ) -> impl Iterator<Item = ProverQuery<'_, C>> + Clone {
211 self.polys.iter().map(move |poly| ProverQuery {
212 point: *x,
213 poly,
214 blind: Blind::default(),
215 })
216 }
217
218 pub(in crate::plonk) fn evaluate<E: EncodedChallenge<C>, T: TranscriptWrite<C, E>>(
219 &self,
220 x: ChallengeX<C>,
221 transcript: &mut T,
222 ) -> Result<(), Error> {
223 for eval in self.polys.iter().map(|poly| eval_polynomial(poly, *x)) {
225 transcript.write_scalar(eval)?;
226 }
227
228 Ok(())
229 }
230}
231
232impl<C: CurveAffine> Constructed<C> {
233 pub(in crate::plonk) fn evaluate<E: EncodedChallenge<C>, T: TranscriptWrite<C, E>>(
234 self,
235 pk: &plonk::ProvingKey<C>,
236 x: ChallengeX<C>,
237 transcript: &mut T,
238 ) -> Result<Evaluated<C>, Error> {
239 let domain = &pk.vk.domain;
240 let blinding_factors = pk.vk.cs.blinding_factors();
241
242 {
243 let mut sets = self.sets.iter();
244
245 while let Some(set) = sets.next() {
246 let permutation_product_eval = eval_polynomial(&set.permutation_product_poly, *x);
247
248 let permutation_product_next_eval = eval_polynomial(
249 &set.permutation_product_poly,
250 domain.rotate_omega(*x, Rotation::next()),
251 );
252
253 for eval in iter::empty()
255 .chain(Some(&permutation_product_eval))
256 .chain(Some(&permutation_product_next_eval))
257 {
258 transcript.write_scalar(*eval)?;
259 }
260
261 if sets.len() > 0 {
265 let permutation_product_last_eval = eval_polynomial(
266 &set.permutation_product_poly,
267 domain.rotate_omega(*x, Rotation(-((blinding_factors + 1) as i32))),
268 );
269
270 transcript.write_scalar(permutation_product_last_eval)?;
271 }
272 }
273 }
274
275 Ok(Evaluated { constructed: self })
276 }
277}
278
279impl<C: CurveAffine> Evaluated<C> {
280 pub(in crate::plonk) fn open<'a>(
281 &'a self,
282 pk: &'a plonk::ProvingKey<C>,
283 x: ChallengeX<C>,
284 ) -> impl Iterator<Item = ProverQuery<'a, C>> + Clone {
285 let blinding_factors = pk.vk.cs.blinding_factors();
286 let x_next = pk.vk.domain.rotate_omega(*x, Rotation::next());
287 let x_last = pk
288 .vk
289 .domain
290 .rotate_omega(*x, Rotation(-((blinding_factors + 1) as i32)));
291
292 iter::empty()
293 .chain(self.constructed.sets.iter().flat_map(move |set| {
294 iter::empty()
295 .chain(Some(ProverQuery {
297 point: *x,
298 poly: &set.permutation_product_poly,
299 blind: set.permutation_product_blind,
300 }))
301 .chain(Some(ProverQuery {
302 point: x_next,
303 poly: &set.permutation_product_poly,
304 blind: set.permutation_product_blind,
305 }))
306 }))
307 .chain(
311 self.constructed
312 .sets
313 .iter()
314 .rev()
315 .skip(1)
316 .flat_map(move |set| {
317 Some(ProverQuery {
318 point: x_last,
319 poly: &set.permutation_product_poly,
320 blind: set.permutation_product_blind,
321 })
322 }),
323 )
324 }
325}