1use crate::FieldColumn;
2use ark_ff::{batch_inversion, FftField, Field, Zero};
3use ark_poly::univariate::DensePolynomial;
4use ark_poly::{
5 DenseUVPolynomial, EvaluationDomain, Evaluations, GeneralEvaluationDomain, Polynomial,
6};
7use ark_std::{vec, vec::Vec};
8use getrandom_or_panic::getrandom_or_panic;
9
10#[derive(Clone)]
12pub struct Domains<F: FftField> {
13 pub x1: GeneralEvaluationDomain<F>,
14 pub x4: GeneralEvaluationDomain<F>,
15}
16
17impl<F: FftField> Domains<F> {
18 fn new(n: usize) -> Self {
19 let x1 = GeneralEvaluationDomain::<F>::new(n)
20 .unwrap_or_else(|| panic!("No domain of size {}", n));
21 let x4 = GeneralEvaluationDomain::<F>::new(4 * n)
22 .unwrap_or_else(|| panic!("No domain of size {}", 4 * n));
23 Self { x1, x4 }
24 }
25
26 fn column_from_evals(&self, padded_evals: Vec<F>, payload_len: usize) -> FieldColumn<F> {
27 debug_assert_eq!(padded_evals.len(), self.x1.size());
28 let evals = Evaluations::from_vec_and_domain(padded_evals, self.x1);
29 let poly = evals.interpolate_by_ref();
30 let evals_4x = poly.evaluate_over_domain_by_ref(self.x4);
31 FieldColumn {
32 poly,
33 evals,
34 evals_4x,
35 payload_len,
36 }
37 }
38
39 fn column_from_poly(&self, poly: DensePolynomial<F>) -> FieldColumn<F> {
40 debug_assert!(poly.degree() + 1 <= self.x1.size());
41 let evals_4x = self.amplify(&poly);
42 let evals = evals_4x.evals.iter().step_by(4).cloned().collect();
43 let evals = Evaluations::from_vec_and_domain(evals, self.x1);
44 FieldColumn {
45 poly,
46 evals,
47 evals_4x,
48 payload_len: self.x1.size(),
49 }
50 }
51
52 fn amplify(&self, poly: &DensePolynomial<F>) -> Evaluations<F> {
54 poly.evaluate_over_domain_by_ref(self.x4)
55 }
56}
57
58#[derive(Clone)]
59pub struct Domain<F: FftField> {
60 pub domains: Domains<F>,
61 pub zk_rows: usize,
62 pub capacity: usize,
63 pub not_last_row: FieldColumn<F>,
64 pub l_first: FieldColumn<F>,
65 pub l_last: FieldColumn<F>,
66 zk_rows_prod: DensePolynomial<F>,
67 blinding: bool,
68}
69
70impl<F: FftField> Domain<F> {
71 pub fn no_zk(n: usize) -> Self {
73 Self::with_zk_rows(n, 0)
74 }
75
76 pub fn with_zk_rows(n: usize, zk_rows: usize) -> Self {
80 let domains = Domains::new(n);
81 let domain_size = domains.x1.size();
82 let capacity = domain_size - zk_rows;
83 let last_row_index = capacity - 1;
84
85 let l_first = l_i(0, domain_size);
86 let l_first = domains.column_from_evals(l_first, 0);
87 let l_last = l_i(last_row_index, domain_size);
88 let l_last = domains.column_from_evals(l_last, 0);
89
90 let (zk_rows_prod, last_row) = compute_row_polys(domains.x1, zk_rows);
91 let not_last_row = domains.column_from_poly(last_row);
92
93 Self {
94 domains,
95 zk_rows,
96 capacity,
97 not_last_row,
98 l_first,
99 l_last,
100 zk_rows_prod,
101 blinding: zk_rows != 0,
102 }
103 }
104
105 pub fn without_blinding(mut self) -> Self {
111 self.blinding = false;
112 self
113 }
114
115 #[cfg(test)]
116 pub const ZK_ROWS_TEST: usize = 3;
117
118 #[cfg(test)]
119 pub fn test_domain(n: usize, hiding: bool) -> Self {
120 if hiding {
121 Self::with_zk_rows(n, Self::ZK_ROWS_TEST)
122 } else {
123 Self::with_zk_rows(n, 0)
124 }
125 }
126
127 pub fn is_hiding(&self) -> bool {
128 self.zk_rows != 0
129 }
130
131 pub fn compute_quotient(&self, poly: &DensePolynomial<F>) -> Option<DensePolynomial<F>> {
132 let (q, r) = self.div_by_z_with_remainder(poly);
133 r.is_zero().then_some(q)
134 }
135
136 fn div_by_z_with_remainder(
137 &self,
138 p: &DensePolynomial<F>,
139 ) -> (DensePolynomial<F>, DensePolynomial<F>) {
140 let dividend = if self.is_hiding() {
141 &(p * &self.zk_rows_prod)
142 } else {
143 p
144 };
145 dividend.divide_by_vanishing_poly(self.domains.x1)
146 }
147
148 fn _column(&self, mut values: Vec<F>, public: bool) -> FieldColumn<F> {
149 let payload_len = values.len();
150 assert!(payload_len <= self.capacity);
151 if self.blinding && !public {
152 values.resize(self.capacity, F::zero());
153 let rng = &mut getrandom_or_panic();
154 values.resize_with(self.domain_size(), || F::rand(rng));
155 } else {
156 values.resize(self.domain_size(), F::zero());
157 }
158 self.domains.column_from_evals(values, payload_len)
159 }
160
161 pub fn column(&self, values: Vec<F>) -> FieldColumn<F> {
162 self._column(values, false)
163 }
164
165 pub fn public_column(&self, values: Vec<F>) -> FieldColumn<F> {
166 self._column(values, true)
167 }
168
169 pub fn domain(&self) -> GeneralEvaluationDomain<F> {
170 self.domains.x1
171 }
172
173 pub fn domain_size(&self) -> usize {
174 self.domain().size()
175 }
176
177 pub fn omega(&self) -> F {
178 self.domain().group_gen()
179 }
180
181 pub fn evaluate(&self, zeta: F) -> EvaluatedDomain<F> {
182 EvaluatedDomain::new(self.domain(), zeta, self.zk_rows)
183 }
184}
185
186fn l_i<F: FftField>(i: usize, n: usize) -> Vec<F> {
187 let mut l_i = vec![F::zero(); n];
188 l_i[i] = F::one();
189 l_i
190}
191
192fn elements_rev<F: FftField, D: EvaluationDomain<F>>(domain: D) -> impl Iterator<Item = F> {
194 let w_inv = domain.group_gen_inv();
195 debug_assert_eq!(w_inv * domain.group_gen(), F::one()); ark_std::iter::successors(Some(w_inv), move |wi| (!wi.is_one()).then(|| w_inv * wi))
197}
198
199fn z_poly<F: Field>(c: F) -> DensePolynomial<F> {
201 DensePolynomial::from_coefficients_vec(vec![-c, F::one()])
202}
203
204fn one<F: Field>() -> DensePolynomial<F> {
205 DensePolynomial::from_coefficients_vec(vec![F::one()])
206}
207
208fn compute_row_polys<F: FftField, D: EvaluationDomain<F>>(
212 domain: D,
213 zk_rows: usize,
214) -> (DensePolynomial<F>, DensePolynomial<F>) {
215 assert!(domain.size() >= 1 + zk_rows, "0 domain");
216 let ws_rev_iter = elements_rev(domain); let mut z_polys = ws_rev_iter.map(|wi| z_poly(wi));
218 let zk_rows_prod = z_polys.by_ref().take(zk_rows).fold(one(), |acc, x| acc * x);
219 let last_row = z_polys.next().unwrap();
220 (zk_rows_prod, last_row)
221}
222
223pub struct EvaluatedDomain<F: FftField> {
224 pub domain: GeneralEvaluationDomain<F>,
225 pub not_last_row: F,
226 pub l_first: F,
227 pub l_last: F,
228 pub vanishing_polynomial_inv: F,
229}
230
231impl<F: FftField> EvaluatedDomain<F> {
232 pub fn new(domain: GeneralEvaluationDomain<F>, z: F, zk_rows: usize) -> Self {
233 let mut z_n = z; for _ in 0..domain.log_size_of_group() {
235 z_n.square_in_place();
236 }
237 let z_n_minus_one = z_n - F::one(); let mut wi = domain.group_gen_inv();
241 let mut prod = F::one();
243 for _ in 0..zk_rows {
244 prod *= z - wi;
245 wi *= domain.group_gen_inv();
246 }
247 let not_last_row = z - wi;
249
250 let wj = domain.group_gen().pow([(zk_rows + 1) as u64]);
252
253 let mut inv = [z_n_minus_one, z - F::one(), wj * z - F::one()];
254 batch_inversion(&mut inv);
255
256 let vanishing_polynomial_inv = prod * inv[0];
257 let z_n_minus_one_div_n = z_n_minus_one * domain.size_inv();
258 let l_first = z_n_minus_one_div_n * inv[1];
259 let l_last = z_n_minus_one_div_n * inv[2];
260
261 Self {
262 domain,
263 not_last_row,
264 l_first,
265 l_last,
266 vanishing_polynomial_inv,
267 }
268 }
269
270 pub(crate) fn divide_by_vanishing_poly_in_zeta(&self, poly_in_zeta: F) -> F {
271 poly_in_zeta * self.vanishing_polynomial_inv
272 }
273
274 pub fn omega(&self) -> F {
275 self.domain.group_gen()
276 }
277}
278
279#[cfg(test)]
280mod tests {
281 use super::*;
282 use ark_ed_on_bls12_381_bandersnatch::Fq;
283 use ark_ff::One;
284 use ark_poly::Radix2EvaluationDomain;
285 use ark_std::{test_rng, UniformRand};
286
287 fn _test_evaluated_domain(hiding: bool) {
288 let rng = &mut test_rng();
289
290 let n = 1024;
292 let domain = Domain::test_domain(n, hiding);
293 let z = Fq::rand(rng);
294 let domain_eval = domain.evaluate(z);
295 assert_eq!(domain.l_first.poly.evaluate(&z), domain_eval.l_first);
296 assert_eq!(domain.l_last.poly.evaluate(&z), domain_eval.l_last);
297 assert_eq!(
298 domain.not_last_row.poly.evaluate(&z),
299 domain_eval.not_last_row
300 );
301 }
302
303 #[test]
304 #[should_panic(expected = "0 domain")]
305 fn test_domain_zk_rows() {
306 let log_n = 4;
307 let n = 1 << log_n;
308 let domain = Radix2EvaluationDomain::<Fq>::new(n).unwrap();
309 let w = domain.group_gen();
310 let (zk_rows_prod, last_row) = compute_row_polys(domain, 0);
311 assert_eq!(zk_rows_prod, one());
312 assert_eq!(last_row, z_poly(domain.group_gen_inv()));
313
314 let zk_rows = 3;
315 let (zk_rows_prod, last_row) = compute_row_polys(domain, zk_rows);
316 assert_eq!(zk_rows_prod.degree(), zk_rows);
317 let last_row_index = n - (zk_rows + 1);
318 assert_eq!(last_row, z_poly(w.pow([last_row_index as u64])));
319
320 let zk_rows = n - 1;
321 let (zk_rows_prod, last_row) = compute_row_polys(domain, zk_rows);
322 assert_eq!(last_row, z_poly(Fq::one()));
323 assert_eq!(
324 zk_rows_prod * last_row,
325 domain.vanishing_polynomial().into()
326 );
327
328 let zk_rows = n;
329 compute_row_polys(domain, zk_rows);
330 }
331
332 #[test]
333 fn test_evaluated_domain() {
334 _test_evaluated_domain(false);
335 _test_evaluated_domain(true);
336 }
337
338 #[test]
342 fn column_blinding() {
343 let n = 16;
344 let values = vec![Fq::one(); 4];
345
346 let domain = Domain::test_domain(n, true);
347 let col_1 = domain.column(values.clone());
348 let col_2 = domain.column(values.clone());
349 assert_ne!(col_1.poly, col_2.poly);
350
351 let capacity = domain.capacity;
352 let domain = domain.without_blinding();
353 assert_eq!(domain.capacity, capacity);
354 let col_1 = domain.column(values.clone());
355 let col_2 = domain.column(values);
356 assert_eq!(col_1.poly, col_2.poly);
357 }
358}