@@ -173,6 +173,78 @@ pub struct ConstraintSystem<F: FftField> {
173173 pub lookup_selectors : Vec < E < F , D < F > > > ,
174174}
175175
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+
176248/// Returns the end of the circuit, which is used for introducing zero-knowledge in the permutation polynomial
177249pub fn zk_w3 < F : FftField > ( domain : D < F > ) -> F {
178250 domain. group_gen . pow ( & [ domain. size - 3 ] )
@@ -252,17 +324,14 @@ impl<F: FftField + SquareRootField> ConstraintSystem<F> {
252324
253325 // +3 on gates.len() here to ensure that we have room for the zero-knowledge entries of the permutation polynomial
254326 // see https://minaprotocol.com/blog/a-more-efficient-approach-to-zero-knowledge-for-plonk
327+ // TODO: hardcode this value somewhere
255328 let domain = EvaluationDomains :: < F > :: create ( gates. len ( ) + 3 ) ?;
256329 assert ! ( domain. d1. size > 3 ) ;
257330
258331 // pre-compute all the elements
259332 let mut sid = domain. d1 . elements ( ) . map ( |elm| elm) . collect :: < Vec < _ > > ( ) ;
260333
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
266335 let n = domain. d1 . size ( ) ;
267336 let mut padding = ( gates. len ( ) ..n)
268337 . map ( |i| {
@@ -277,15 +346,17 @@ impl<F: FftField + SquareRootField> ConstraintSystem<F> {
277346 . collect ( ) ;
278347 gates. append ( & mut padding) ;
279348
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 ) ;
283352
284353 // compute permutation polynomials
354+ let mut sigmal1: [ Vec < F > ; PERMUTS ] =
355+ array_init ( |_| vec ! [ F :: zero( ) ; domain. d1. size as usize ] ) ;
356+
285357 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) ;
289360 }
290361 }
291362
@@ -497,7 +568,7 @@ impl<F: FftField + SquareRootField> ConstraintSystem<F> {
497568 zkpm,
498569 vanishes_on_last_4_rows,
499570 gates,
500- shift,
571+ shift : shifts . shifts ,
501572 endo,
502573 fr_sponge_params,
503574 } )
@@ -540,44 +611,6 @@ impl<F: FftField + SquareRootField> ConstraintSystem<F> {
540611 return Ok ( ( ) ) ;
541612 }
542613
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-
581614 /// evaluate witness polynomials over domains
582615 pub fn evaluate ( & self , w : & [ DP < F > ; COLUMNS ] , z : & DP < F > ) -> WitnessOverDomains < F > {
583616 // compute shifted witness polynomials
0 commit comments