@@ -173,6 +173,78 @@ pub struct ConstraintSystem<F: FftField> {
173
173
pub lookup_selectors : Vec < E < F , D < F > > > ,
174
174
}
175
175
176
+ /// Shifts represent the shifts required in the permutation argument of PLONK
177
+ struct Shifts < F > {
178
+ /// The coefficients k that create a coset when multiplied with the generator of our domain.
179
+ shifts : [ F ; PERMUTS ] ,
180
+ /// A matrix that maps all cells coordinates {col, row} to their shifted field element.
181
+ /// For example the cell {col:2, row:1} will map to omega * k2,
182
+ /// which lives in map[2][1]
183
+ map : [ Vec < F > ; PERMUTS ] ,
184
+ }
185
+
186
+ impl < F > Shifts < F >
187
+ where
188
+ F : FftField + SquareRootField ,
189
+ {
190
+ /// Generates the shifts for a given domain
191
+ pub fn new ( domain : & D < F > ) -> Self {
192
+ let mut shifts = [ F :: zero ( ) ; PERMUTS ] ;
193
+
194
+ // first shift is the identity
195
+ shifts[ 0 ] = F :: one ( ) ;
196
+
197
+ // sample the other shifts
198
+ let mut i: u32 = 7 ;
199
+ for idx in 1 ..( PERMUTS ) {
200
+ let mut o = Self :: sample ( & domain, & mut i) ;
201
+ while shifts. iter ( ) . filter ( |& r| o == * r) . count ( ) > 0 {
202
+ o = Self :: sample ( & domain, & mut i) ;
203
+ }
204
+ shifts[ idx] = o;
205
+ }
206
+
207
+ // create a map of cells to their shifted value
208
+ let map: [ Vec < F > ; PERMUTS ] =
209
+ array_init ( |i| domain. elements ( ) . map ( |elm| shifts[ i] * & elm) . collect ( ) ) ;
210
+
211
+ //
212
+ Self { shifts, map }
213
+ }
214
+
215
+ /// sample coordinate shifts deterministically
216
+ fn sample ( domain : & D < F > , i : & mut u32 ) -> F {
217
+ let mut h = Blake2b :: new ( ) ;
218
+ h. update (
219
+ & {
220
+ * i += 1 ;
221
+ * i
222
+ }
223
+ . to_be_bytes ( ) ,
224
+ ) ;
225
+ let mut r = F :: from_random_bytes ( & h. finalize ( ) [ ..31 ] ) . unwrap ( ) ;
226
+ while r. legendre ( ) . is_qnr ( ) == false || domain. evaluate_vanishing_polynomial ( r) . is_zero ( ) {
227
+ let mut h = Blake2b :: new ( ) ;
228
+ h. update (
229
+ & {
230
+ * i += 1 ;
231
+ * i
232
+ }
233
+ . to_be_bytes ( ) ,
234
+ ) ;
235
+ r = F :: from_random_bytes ( & h. finalize ( ) [ ..31 ] ) . unwrap ( ) ;
236
+ }
237
+ r
238
+ }
239
+
240
+ /// Returns the field element that represents a position
241
+ fn cell_to_field ( & self , & Wire { row, col } : & Wire ) -> F {
242
+ self . map [ col] [ row]
243
+ }
244
+ }
245
+
246
+ ///
247
+
176
248
/// Returns the end of the circuit, which is used for introducing zero-knowledge in the permutation polynomial
177
249
pub fn zk_w3 < F : FftField > ( domain : D < F > ) -> F {
178
250
domain. group_gen . pow ( & [ domain. size - 3 ] )
@@ -252,17 +324,14 @@ impl<F: FftField + SquareRootField> ConstraintSystem<F> {
252
324
253
325
// +3 on gates.len() here to ensure that we have room for the zero-knowledge entries of the permutation polynomial
254
326
// see https://minaprotocol.com/blog/a-more-efficient-approach-to-zero-knowledge-for-plonk
327
+ // TODO: hardcode this value somewhere
255
328
let domain = EvaluationDomains :: < F > :: create ( gates. len ( ) + 3 ) ?;
256
329
assert ! ( domain. d1. size > 3 ) ;
257
330
258
331
// pre-compute all the elements
259
332
let mut sid = domain. d1 . elements ( ) . map ( |elm| elm) . collect :: < Vec < _ > > ( ) ;
260
333
261
- // sample the coordinate shifts
262
- // TODO(mimoo): should we check that the shifts are all different?
263
- let shift = Self :: sample_shifts ( & domain. d1 , PERMUTS - 1 ) ;
264
- let shift: [ F ; PERMUTS ] = array_init ( |i| if i == 0 { F :: one ( ) } else { shift[ i - 1 ] } ) ;
265
-
334
+ // pad the rows: add zero gates to reach the domain size
266
335
let n = domain. d1 . size ( ) ;
267
336
let mut padding = ( gates. len ( ) ..n)
268
337
. map ( |i| {
@@ -277,15 +346,17 @@ impl<F: FftField + SquareRootField> ConstraintSystem<F> {
277
346
. collect ( ) ;
278
347
gates. append ( & mut padding) ;
279
348
280
- let s : [ std :: vec :: Vec < F > ; PERMUTS ] =
281
- array_init ( |i| domain . d1 . elements ( ) . map ( |elm| shift [ i ] * & elm ) . collect ( ) ) ;
282
- let mut sigmal1 = s . clone ( ) ;
349
+ // sample the coordinate shifts
350
+ // TODO(mimoo): should we check that the shifts are all different?
351
+ let shifts = Shifts :: new ( & domain . d1 ) ;
283
352
284
353
// compute permutation polynomials
354
+ let mut sigmal1: [ Vec < F > ; PERMUTS ] =
355
+ array_init ( |_| vec ! [ F :: zero( ) ; domain. d1. size as usize ] ) ;
356
+
285
357
for ( row, gate) in gates. iter ( ) . enumerate ( ) {
286
- for col in 0 ..PERMUTS {
287
- let wire = gate. wires [ col] ;
288
- sigmal1[ col] [ row] = s[ wire. col ] [ wire. row ] ;
358
+ for ( cell, sigma) in gate. wires . iter ( ) . zip ( sigmal1. iter_mut ( ) ) {
359
+ sigma[ row] = shifts. cell_to_field ( cell) ;
289
360
}
290
361
}
291
362
@@ -497,7 +568,7 @@ impl<F: FftField + SquareRootField> ConstraintSystem<F> {
497
568
zkpm,
498
569
vanishes_on_last_4_rows,
499
570
gates,
500
- shift,
571
+ shift : shifts . shifts ,
501
572
endo,
502
573
fr_sponge_params,
503
574
} )
@@ -540,44 +611,6 @@ impl<F: FftField + SquareRootField> ConstraintSystem<F> {
540
611
return Ok ( ( ) ) ;
541
612
}
542
613
543
- /// sample coordinate shifts deterministically
544
- pub fn sample_shift ( domain : & D < F > , i : & mut u32 ) -> F {
545
- let mut h = Blake2b :: new ( ) ;
546
- h. update (
547
- & {
548
- * i += 1 ;
549
- * i
550
- }
551
- . to_be_bytes ( ) ,
552
- ) ;
553
- let mut r = F :: from_random_bytes ( & h. finalize ( ) [ ..31 ] ) . unwrap ( ) ;
554
- while r. legendre ( ) . is_qnr ( ) == false || domain. evaluate_vanishing_polynomial ( r) . is_zero ( ) {
555
- let mut h = Blake2b :: new ( ) ;
556
- h. update (
557
- & {
558
- * i += 1 ;
559
- * i
560
- }
561
- . to_be_bytes ( ) ,
562
- ) ;
563
- r = F :: from_random_bytes ( & h. finalize ( ) [ ..31 ] ) . unwrap ( ) ;
564
- }
565
- r
566
- }
567
-
568
- pub fn sample_shifts ( domain : & D < F > , len : usize ) -> Vec < F > {
569
- let mut i: u32 = 7 ;
570
- let mut shifts = Vec :: with_capacity ( len) ;
571
- while shifts. len ( ) < len {
572
- let mut o = Self :: sample_shift ( & domain, & mut i) ;
573
- while shifts. iter ( ) . filter ( |& r| o == * r) . count ( ) > 0 {
574
- o = Self :: sample_shift ( & domain, & mut i)
575
- }
576
- shifts. push ( o)
577
- }
578
- shifts
579
- }
580
-
581
614
/// evaluate witness polynomials over domains
582
615
pub fn evaluate ( & self , w : & [ DP < F > ; COLUMNS ] , z : & DP < F > ) -> WitnessOverDomains < F > {
583
616
// compute shifted witness polynomials
0 commit comments