11use crate :: FieldColumn ;
2- use ark_ff:: { batch_inversion, FftField , Zero } ;
2+ use ark_ff:: { batch_inversion, FftField , Field , Zero } ;
33use ark_poly:: univariate:: DensePolynomial ;
44use ark_poly:: {
55 DenseUVPolynomial , EvaluationDomain , Evaluations , GeneralEvaluationDomain , Polynomial ,
@@ -60,90 +60,105 @@ impl<F: FftField> Domains<F> {
6060#[ derive( Clone ) ]
6161pub struct Domain < F : FftField > {
6262 pub domains : Domains < F > ,
63- pub hiding : bool ,
63+ pub zk_rows : usize ,
6464 pub capacity : usize ,
6565 pub not_last_row : FieldColumn < F > ,
6666 pub l_first : FieldColumn < F > ,
6767 pub l_last : FieldColumn < F > ,
68- zk_rows_vanishing_poly : Option < DensePolynomial < F > > ,
68+ zk_rows_prod : DensePolynomial < F > ,
6969}
7070
7171impl < F : FftField > Domain < F > {
7272 pub fn new ( n : usize , hiding : bool ) -> Self {
73+ if hiding {
74+ Self :: with_zk_rows ( n, ZK_ROWS )
75+ } else {
76+ Self :: with_zk_rows ( n, 0 )
77+ }
78+ }
79+
80+ pub fn with_zk_rows ( n : usize , zk_rows : usize ) -> Self {
7381 let domains = Domains :: new ( n) ;
7482 let domain_size = domains. x1 . size ( ) ;
75- let domain_capacity = if hiding {
76- domain_size - ZK_ROWS
77- } else {
78- domain_size
79- } ;
80- let last_row_index = domain_capacity - 1 ;
83+ let capacity = domain_size - zk_rows;
84+ let last_row_index = capacity - 1 ;
8185
8286 let l_first = l_i ( 0 , domain_size) ;
8387 let l_first = domains. column_from_evals ( l_first, 0 ) ;
8488 let l_last = l_i ( last_row_index, domain_size) ;
8589 let l_last = domains. column_from_evals ( l_last, 0 ) ;
86- let not_last_row = vanishes_on_row ( last_row_index, domains. x1 ) ;
87- let not_last_row = domains. column_from_poly ( not_last_row) ;
8890
89- let zk_rows_vanishing_poly = hiding. then ( || vanishes_on_last_3_rows ( domains. x1 ) ) ;
91+ let ( zk_rows_prod, last_row) = compute_row_polys ( domains. x1 , zk_rows) . unwrap ( ) ;
92+ let not_last_row = domains. column_from_poly ( last_row) ;
9093
9194 Self {
9295 domains,
93- hiding ,
94- capacity : domain_capacity ,
96+ zk_rows ,
97+ capacity,
9598 not_last_row,
9699 l_first,
97100 l_last,
98- zk_rows_vanishing_poly ,
101+ zk_rows_prod ,
99102 }
100103 }
101104
102- pub fn divide_by_vanishing_poly ( & self , poly : & DensePolynomial < F > ) -> DensePolynomial < F > {
103- let ( quotient, remainder) = if self . hiding {
104- let exclude_zk_rows = poly * self . zk_rows_vanishing_poly . as_ref ( ) . unwrap ( ) ;
105- exclude_zk_rows. divide_by_vanishing_poly ( self . domains . x1 )
105+ pub fn is_hiding ( & self ) -> bool {
106+ self . zk_rows != 0
107+ }
108+
109+ pub fn compute_quotient ( & self , poly : & DensePolynomial < F > ) -> Option < DensePolynomial < F > > {
110+ let ( q, r) = self . div_by_z_with_remainder ( poly) ;
111+ r. is_zero ( ) . then_some ( q)
112+ }
113+
114+ fn div_by_z_with_remainder (
115+ & self ,
116+ p : & DensePolynomial < F > ,
117+ ) -> ( DensePolynomial < F > , DensePolynomial < F > ) {
118+ let dividend = if self . is_hiding ( ) {
119+ & ( p * & self . zk_rows_prod )
106120 } else {
107- poly . divide_by_vanishing_poly ( self . domains . x1 )
121+ p
108122 } ;
109- assert ! ( remainder. is_zero( ) ) ; //TODO error-handling
110- quotient
123+ dividend. divide_by_vanishing_poly ( self . domains . x1 )
111124 }
112125
113- pub ( crate ) fn column ( & self , mut values : Vec < F > , hidden : bool ) -> FieldColumn < F > {
126+ fn _column ( & self , mut values : Vec < F > , public : bool ) -> FieldColumn < F > {
114127 let payload_len = values. len ( ) ;
115- debug_assert ! ( payload_len <= self . capacity) ;
116- values. resize ( self . capacity , F :: zero ( ) ) ;
117- if self . hiding && hidden && !cfg ! ( feature = "test-vectors" ) {
118- values. resize_with (
119- self . domains . x1 . size ( ) ,
120- || F :: rand ( & mut getrandom_or_panic ( ) ) ,
121- ) ;
128+ assert ! ( payload_len <= self . capacity) ;
129+ let no_blinding = !self . is_hiding ( ) || public || cfg ! ( feature = "test-vectors" ) ;
130+ if no_blinding {
131+ values. resize ( self . domain_size ( ) , F :: zero ( ) ) ;
122132 } else {
123- values. resize ( self . domains . x1 . size ( ) , F :: zero ( ) ) ;
133+ values. resize ( self . capacity , F :: zero ( ) ) ;
134+ let rng = & mut getrandom_or_panic ( ) ;
135+ values. resize_with ( self . domain_size ( ) , || F :: rand ( rng) ) ;
124136 }
125137 self . domains . column_from_evals ( values, payload_len)
126138 }
127139
128- pub fn private_column ( & self , values : Vec < F > ) -> FieldColumn < F > {
129- self . column ( values, true )
140+ pub fn column ( & self , values : Vec < F > ) -> FieldColumn < F > {
141+ self . _column ( values, false )
130142 }
131143
132- // public column
133- pub fn public_column ( & self , evals : Vec < F > ) -> FieldColumn < F > {
134- self . column ( evals, false )
135- }
136-
137- pub fn omega ( & self ) -> F {
138- self . domains . x1 . group_gen ( )
144+ pub fn public_column ( & self , values : Vec < F > ) -> FieldColumn < F > {
145+ self . _column ( values, true )
139146 }
140147
141148 pub fn domain ( & self ) -> GeneralEvaluationDomain < F > {
142149 self . domains . x1
143150 }
144151
152+ pub fn domain_size ( & self ) -> usize {
153+ self . domain ( ) . size ( )
154+ }
155+
156+ pub fn omega ( & self ) -> F {
157+ self . domain ( ) . group_gen ( )
158+ }
159+
145160 pub fn evaluate ( & self , zeta : F ) -> EvaluatedDomain < F > {
146- EvaluatedDomain :: new ( self . domain ( ) , zeta, self . hiding )
161+ EvaluatedDomain :: new ( self . domain ( ) , zeta, self . zk_rows )
147162 }
148163}
149164
@@ -153,30 +168,35 @@ fn l_i<F: FftField>(i: usize, n: usize) -> Vec<F> {
153168 l_i
154169}
155170
156- // (x - w^i)
157- fn vanishes_on_row < F : FftField > (
158- i : usize ,
159- domain : GeneralEvaluationDomain < F > ,
160- ) -> DensePolynomial < F > {
161- assert ! ( i < domain. size( ) ) ;
162- let w = domain. group_gen ( ) ;
163- let wi = w. pow ( & [ i as u64 ] ) ;
164- let wi = DensePolynomial :: from_coefficients_slice ( & [ wi] ) ;
165- let x = DensePolynomial :: from_coefficients_slice ( & [ F :: zero ( ) , F :: one ( ) ] ) ;
166- & x - & wi
171+ /// For the generator `w = domain.group_gen()` of a domain of size `N`, returns `w^{N-1}, w^{N-2}, ..., w^0 = 1`.
172+ fn elements_rev < F : FftField , D : EvaluationDomain < F > > ( domain : D ) -> impl Iterator < Item = F > {
173+ let w_inv = domain. group_gen_inv ( ) ;
174+ debug_assert_eq ! ( w_inv * domain. group_gen( ) , F :: one( ) ) ; // w^{n-1} = w^{-1}
175+ ark_std:: iter:: successors ( Some ( w_inv) , move |wi| ( !wi. is_one ( ) ) . then ( || w_inv * wi) )
176+ }
177+
178+ /// `Z(c) = X - c`
179+ fn z < F : Field > ( c : F ) -> DensePolynomial < F > {
180+ DensePolynomial :: from_coefficients_vec ( vec ! [ -c, F :: one( ) ] )
181+ }
182+
183+ fn one < F : Field > ( ) -> DensePolynomial < F > {
184+ DensePolynomial :: from_coefficients_vec ( vec ! [ F :: one( ) ] )
167185}
168186
169- // (x - w^{n - 3}) * (x - w^{n - 2}) * (x - w^{n - 1})
170- fn vanishes_on_last_3_rows < F : FftField > ( domain : GeneralEvaluationDomain < F > ) -> DensePolynomial < F > {
171- let w = domain. group_gen ( ) ;
172- let n3 = ( domain. size ( ) - ZK_ROWS ) as u64 ;
173- let w3 = w. pow ( & [ n3] ) ;
174- let w2 = w3 * w;
175- let w1 = w2 * w;
176- assert_eq ! ( w1, domain. group_gen_inv( ) ) ;
177- let x = DensePolynomial :: from_coefficients_slice ( & [ F :: zero ( ) , F :: one ( ) ] ) ; // X
178- let c = |a : F | DensePolynomial :: from_coefficients_slice ( & [ a] ) ;
179- & ( & ( & x - & c ( w3) ) * & ( & x - & c ( w2) ) ) * & ( & x - & c ( w1) )
187+ /// For a domain of size `N`, returns `(Z(X), (X - w^{N - zk_rows - 1}))`,
188+ /// where `Z(X) = (X - w^{N-1}) * (X - w^{N-2}) * ... * (X - w^{N - zk_rows})`.
189+ fn compute_row_polys < F : FftField , D : EvaluationDomain < F > > (
190+ domain : D ,
191+ zk_rows : usize ,
192+ ) -> Option < ( DensePolynomial < F > , DensePolynomial < F > ) > {
193+ if domain. size ( ) < zk_rows + 1 {
194+ return None ;
195+ }
196+ let mut wis = elements_rev ( domain) . map ( |wi| z ( wi) ) ;
197+ let zk_rows_prod = wis. by_ref ( ) . take ( zk_rows) . fold ( one ( ) , |acc, x| acc * x) ;
198+ let last_row = wis. by_ref ( ) . next ( ) . unwrap ( ) ;
199+ Some ( ( zk_rows_prod, last_row) )
180200}
181201
182202pub struct EvaluatedDomain < F : FftField > {
@@ -188,8 +208,7 @@ pub struct EvaluatedDomain<F: FftField> {
188208}
189209
190210impl < F : FftField > EvaluatedDomain < F > {
191- pub fn new ( domain : GeneralEvaluationDomain < F > , z : F , hiding : bool ) -> Self {
192- let k = if hiding { ZK_ROWS } else { 0 } ;
211+ pub fn new ( domain : GeneralEvaluationDomain < F > , z : F , zk_rows : usize ) -> Self {
193212 let mut z_n = z; // z^n, n=2^d - domain size, so squarings only
194213 for _ in 0 ..domain. log_size_of_group ( ) {
195214 z_n. square_in_place ( ) ;
@@ -200,15 +219,15 @@ impl<F: FftField> EvaluatedDomain<F> {
200219 let mut wi = domain. group_gen_inv ( ) ;
201220 // Vanishing polynomial of zk rows: prod = (z - w^{n-1})...(z - w^{n-k})
202221 let mut prod = F :: one ( ) ;
203- for _ in 0 ..k {
222+ for _ in 0 ..zk_rows {
204223 prod *= z - wi;
205224 wi *= domain. group_gen_inv ( ) ;
206225 }
207226 // z - w^{n-(k+1)}}
208227 let not_last_row = z - wi;
209228
210229 // w^{k+1}
211- let wj = domain. group_gen ( ) . pow ( [ ( k + 1 ) as u64 ] ) ;
230+ let wj = domain. group_gen ( ) . pow ( [ ( zk_rows + 1 ) as u64 ] ) ;
212231
213232 let mut inv = [ z_n_minus_one, z - F :: one ( ) , wj * z - F :: one ( ) ] ;
214233 batch_inversion ( & mut inv) ;
@@ -238,12 +257,12 @@ impl<F: FftField> EvaluatedDomain<F> {
238257
239258#[ cfg( test) ]
240259mod tests {
260+ use super :: * ;
241261 use ark_ed_on_bls12_381_bandersnatch:: Fq ;
242- use ark_poly:: Polynomial ;
262+ use ark_ff:: One ;
263+ use ark_poly:: Radix2EvaluationDomain ;
243264 use ark_std:: { test_rng, UniformRand } ;
244265
245- use crate :: domain:: Domain ;
246-
247266 fn _test_evaluated_domain ( hiding : bool ) {
248267 let rng = & mut test_rng ( ) ;
249268
@@ -260,6 +279,34 @@ mod tests {
260279 ) ;
261280 }
262281
282+ #[ test]
283+ fn test_domain_zk_rows ( ) {
284+ let log_n = 4 ;
285+ let n = 1 << log_n;
286+ let domain = Radix2EvaluationDomain :: < Fq > :: new ( n) . unwrap ( ) ;
287+ let w = domain. group_gen ( ) ;
288+ let ( zk_rows_prod, last_row) = compute_row_polys ( domain, 0 ) . unwrap ( ) ;
289+ assert_eq ! ( zk_rows_prod, one( ) ) ;
290+ assert_eq ! ( last_row, z( domain. group_gen_inv( ) ) ) ;
291+
292+ let zk_rows = 3 ;
293+ let ( zk_rows_prod, last_row) = compute_row_polys ( domain, zk_rows) . unwrap ( ) ;
294+ assert_eq ! ( zk_rows_prod. degree( ) , zk_rows) ;
295+ let last_row_index = n - ( zk_rows + 1 ) ;
296+ assert_eq ! ( last_row, z( w. pow( [ last_row_index as u64 ] ) ) ) ;
297+
298+ let zk_rows = n - 1 ;
299+ let ( zk_rows_prod, last_row) = compute_row_polys ( domain, zk_rows) . unwrap ( ) ;
300+ assert_eq ! ( last_row, z( Fq :: one( ) ) ) ;
301+ assert_eq ! (
302+ zk_rows_prod * last_row,
303+ domain. vanishing_polynomial( ) . into( )
304+ ) ;
305+
306+ let zk_rows = n;
307+ assert ! ( compute_row_polys( domain, zk_rows) . is_none( ) ) ;
308+ }
309+
263310 #[ test]
264311 fn test_evaluated_domain ( ) {
265312 _test_evaluated_domain ( false ) ;
0 commit comments