barretenberg
Loading...
Searching...
No Matches
plookup_widget_impl.hpp
1#pragma once
2
3#include "barretenberg/common/map.hpp"
4#include "barretenberg/common/mem.hpp"
5#include "barretenberg/plonk/proof_system/proving_key/proving_key.hpp"
6#include "barretenberg/polynomials/iterate_over_domain.hpp"
7#include "barretenberg/polynomials/polynomial_arithmetic.hpp"
8#include "barretenberg/transcript/transcript.hpp"
9#include <cstddef>
10
11namespace proof_system::plonk {
12
13template <const size_t num_roots_cut_out_of_vanishing_polynomial>
14ProverPlookupWidget<num_roots_cut_out_of_vanishing_polynomial>::ProverPlookupWidget(proving_key* input_key)
15 : ProverRandomWidget(input_key)
16{}
17
18template <const size_t num_roots_cut_out_of_vanishing_polynomial>
19ProverPlookupWidget<num_roots_cut_out_of_vanishing_polynomial>::ProverPlookupWidget(const ProverPlookupWidget& other)
20 : ProverRandomWidget(other)
21{}
22
23template <const size_t num_roots_cut_out_of_vanishing_polynomial>
24ProverPlookupWidget<num_roots_cut_out_of_vanishing_polynomial>::ProverPlookupWidget(ProverPlookupWidget&& other)
25 : ProverRandomWidget(other)
26{}
27
28template <const size_t num_roots_cut_out_of_vanishing_polynomial>
29ProverPlookupWidget<num_roots_cut_out_of_vanishing_polynomial>& ProverPlookupWidget<
30 num_roots_cut_out_of_vanishing_polynomial>::operator=(const ProverPlookupWidget& other)
31{
32 ProverRandomWidget::operator=(other);
33 return *this;
34}
35
36template <const size_t num_roots_cut_out_of_vanishing_polynomial>
37ProverPlookupWidget<num_roots_cut_out_of_vanishing_polynomial>& ProverPlookupWidget<
38 num_roots_cut_out_of_vanishing_polynomial>::operator=(ProverPlookupWidget&& other)
39{
40 ProverRandomWidget::operator=(other);
41 return *this;
42}
53template <const size_t num_roots_cut_out_of_vanishing_polynomial>
56{
57 auto s_accum(key->polynomial_store.get("s_1_lagrange"));
58 auto const& s_2 = key->polynomial_store.get("s_2_lagrange");
59 auto const& s_3 = key->polynomial_store.get("s_3_lagrange");
60 auto const& s_4 = key->polynomial_store.get("s_4_lagrange");
61
62 // Get challenge η
63 const auto eta = fr::serialize_from_buffer(transcript.get_challenge("eta", 0).begin());
64
65 // Construct s = s_1 + η*s_2 + η²*s_3 + η³*s_4 via Horner, i.e. s = s_1 + η(s_2 + η(s_3 + η*s_4))
66 // Note: we store 's' in the memory allocated for s_1
67 ITERATE_OVER_DOMAIN_START(key->small_domain);
68 fr T0 = s_4[i];
69 T0 *= eta;
70 T0 += s_3[i];
71 T0 *= eta;
72 T0 += s_2[i];
73 T0 *= eta;
74 s_accum[i] += T0;
75 ITERATE_OVER_DOMAIN_END;
76
77 // To make the plookup honest-verifier zero-knowledge, we need to ensure that the witness polynomials
78 // look uniformly random. Since the `s` polynomial needs evaluation at 2 points in UltraPLONK, we need
79 // to add a degree-2 random polynomial to `s`. Alternatively, we can add 3 random scalars in the lagrange basis
80 // of `s`. Concretely, we wish to do this:
81 // s'(X) = s(X) + (r0 + r1.X + r2.X^2)
82 // In lagrange basis, suppose the coefficients of `s` are (s1, s2, s3, ..., s{n-k}) where `k` is the number
83 // of roots cut out of the vanishing polynomial Z_H(X) = X^n - 1.
84 // Thus, writing `s` into the usual coefficient form, we will have
85 // s(X) = s1.L_1(X) + s2.L_2(X) + ... + s{n-k}.L_{n-k}(X)
86 // Now, the coefficients of lagrange bases (L_{n-k+1}, ..., L_{n}) are empty. We can use them to add randomness
87 // into `s`. Since we wish to add 3 random scalars, we need k >= 3. In our case, we have set
88 // num_roots_cut_out_of_vanishing_polynomial = 4. Thus, we can add 3 random scalars as (s{n-k}, s{n-k+1},
89 // s{n-k+2}).
90 const size_t s_randomness = 3;
91 ASSERT(s_randomness < num_roots_cut_out_of_vanishing_polynomial);
92 for (size_t k = 0; k < s_randomness; ++k) {
93 s_accum[((key->circuit_size - num_roots_cut_out_of_vanishing_polynomial) + 1 + k)] = fr::random_element();
94 }
95
96 // Save the lagrange base representation of s
97 polynomial s_lagrange(s_accum, key->small_domain.size);
98 key->polynomial_store.put("s_lagrange", std::move(s_lagrange));
99
100 // Compute the monomial coefficient representation of s
101 s_accum.ifft(key->small_domain);
102 key->polynomial_store.put("s", std::move(s_accum));
103}
104
122template <const size_t num_roots_cut_out_of_vanishing_polynomial>
125{
126 const size_t n = key->circuit_size;
127
128 // Note: z_lookup ultimately is only only size 'n' but we allow 'n+1' for convenience
129 // essentially as scratch space in the calculation to follow
130 polynomial z_lookup(key->circuit_size + 1);
131
132 // Allocate 4 length n 'accumulators'. accumulators[0] points to the 1th index of
133 // z_lookup and will be used to construct z_lookup (lagrange base) in place. The
134 // remaining 3 are needed only locally in the construction of z_lookup. Note that
135 // beyond this calculation we need only the monomial and coset FFT forms of z_lookup,
136 // so z_lookup in lagrange base will not be added to the store.
137 std::shared_ptr<void> accumulators_ptrs[4];
138 fr* accumulators[4];
139 // Note: accumulators[0][i] = z[i + 1]
140 accumulators[0] = &z_lookup[1];
141 for (size_t k = 1; k < 4; ++k) {
142 accumulators_ptrs[k] = get_mem_slab(n * sizeof(fr));
143 accumulators[k] = (fr*)accumulators_ptrs[k].get();
144 }
145
146 auto s_lagrange = key->polynomial_store.get("s_lagrange");
147 auto column_1_step_size = key->polynomial_store.get("q_2_lagrange");
148 auto column_2_step_size = key->polynomial_store.get("q_m_lagrange");
149 auto column_3_step_size = key->polynomial_store.get("q_c_lagrange");
150
151 fr eta = fr::serialize_from_buffer(transcript.get_challenge("eta").begin());
152 fr eta_sqr = eta.sqr();
153 fr eta_cube = eta_sqr * eta;
154
155 fr beta = fr::serialize_from_buffer(transcript.get_challenge("beta").begin());
156 fr gamma = fr::serialize_from_buffer(transcript.get_challenge("beta", 1).begin());
157
158 // Grab coefficient refs.
159 std::array<std::shared_ptr<fr[]>, 4> lagrange_base_tables_ptr{
160 key->polynomial_store.get("table_value_1_lagrange").data(),
161 key->polynomial_store.get("table_value_2_lagrange").data(),
162 key->polynomial_store.get("table_value_3_lagrange").data(),
163 key->polynomial_store.get("table_value_4_lagrange").data(),
164 };
165 auto lagrange_base_tables = map(lagrange_base_tables_ptr, [](auto& e) { return e.get(); });
166
167 auto lookup_selector = key->polynomial_store.get("table_type_lagrange");
168 auto lookup_index_selector = key->polynomial_store.get("q_3_lagrange");
169
170 std::array<std::shared_ptr<fr[]>, 3> lagrange_base_wires_ptr{
171 key->polynomial_store.get("w_1_lagrange").data(),
172 key->polynomial_store.get("w_2_lagrange").data(),
173 key->polynomial_store.get("w_3_lagrange").data(),
174 };
175 auto lagrange_base_wires = map(lagrange_base_wires_ptr, [](auto& e) { return e.get(); });
176
177 const fr beta_constant = beta + fr(1); // (1 + β)
178 const fr gamma_beta_constant = gamma * beta_constant; // γ(1 + β)
179
180 // Step 1: Compute polynomials f, t and s and incorporate them into terms that are ultimately needed
181 // to construct the grand product polynomial Z_lookup(X):
182 // Note 1: In what follows, 't' is associated with table values (and is not to be confused with the
183 // quotient polynomial, also refered to as 't' elsewhere). Polynomial 's' is the sorted concatenation
184 // of the witnesses and the table values.
185 // Note 2: Evaluation at Xω is indicated explicitly, e.g. 'p(Xω)'; evaluation at X is simply omitted, e.g. 'p'
186 //
187 // 1a. Compute f, then set accumulators[0] = (q_lookup*f + γ), where
188 //
189 // f = (w_1 + q_2*w_1(Xω)) + η(w_2 + q_m*w_2(Xω)) + η²(w_3 + q_c*w_3(Xω)) + η³q_index.
190 // Note that q_2, q_m, and q_c are just the selectors from Standard Plonk that have been repurposed
191 // in the context of the plookup gate to represent 'shift' values. For example, setting each of the
192 // q_* in f to 2^8 facilitates operations on 32-bit values via four operations on 8-bit values. See
193 // Ultra documentation for details.
194 //
195 // 1b. Compute t, then set accumulators[1] = (t + βt(Xω) + γ(1 + β)), where t = t_1 + ηt_2 + η²t_3 + η³t_4
196 //
197 // 1c. Set accumulators[2] = (1 + β)
198 //
199 // 1d. Compute s, then set accumulators[3] = (s + βs(Xω) + γ(1 + β)), where s = s_1 + ηs_2 + η²s_3 + η³s_4
200 //
201 parallel_for(key->small_domain.num_threads, [&](size_t j) {
202 fr T0;
203
204 size_t start = j * key->small_domain.thread_size;
205 size_t end = (j + 1) * key->small_domain.thread_size;
206
207 // Note: block_mask is used for efficient modulus, i.e. i % N := i & (N-1), for N = 2^k
208 const size_t block_mask = key->small_domain.size - 1;
209
210 // Initialize 't(X)' to be used in an expression of the form t(X) + β*t(Xω)
211 fr next_table = lagrange_base_tables[0][start] + lagrange_base_tables[1][start] * eta +
212 lagrange_base_tables[2][start] * eta_sqr + lagrange_base_tables[3][start] * eta_cube;
213 for (size_t i = start; i < end; ++i) {
214 // Compute i'th element of f via Horner (see definition of f above)
215 T0 = lookup_index_selector[i];
216 T0 *= eta;
217 T0 += lagrange_base_wires[2][(i + 1) & block_mask] * column_3_step_size[i];
218 T0 += lagrange_base_wires[2][i];
219 T0 *= eta;
220 T0 += lagrange_base_wires[1][(i + 1) & block_mask] * column_2_step_size[i];
221 T0 += lagrange_base_wires[1][i];
222 T0 *= eta;
223 T0 += lagrange_base_wires[0][(i + 1) & block_mask] * column_1_step_size[i];
224 T0 += lagrange_base_wires[0][i];
225 T0 *= lookup_selector[i];
226
227 // Set i'th element of polynomial q_lookup*f + γ
228 accumulators[0][i] = T0;
229 accumulators[0][i] += gamma;
230
231 // Compute i'th element of t via Horner
232 T0 = lagrange_base_tables[3][(i + 1) & block_mask];
233 T0 *= eta;
234 T0 += lagrange_base_tables[2][(i + 1) & block_mask];
235 T0 *= eta;
236 T0 += lagrange_base_tables[1][(i + 1) & block_mask];
237 T0 *= eta;
238 T0 += lagrange_base_tables[0][(i + 1) & block_mask];
239
240 // Set i'th element of polynomial (t + βt(Xω) + γ(1 + β))
241 accumulators[1][i] = T0 * beta + next_table;
242 next_table = T0;
243 accumulators[1][i] += gamma_beta_constant;
244
245 // Set value of this accumulator to (1 + β)
246 accumulators[2][i] = beta_constant;
247
248 // Set i'th element of polynomial (s + βs(Xω) + γ(1 + β))
249 accumulators[3][i] = s_lagrange[size_t(i + 1) & (size_t)block_mask];
250 accumulators[3][i] *= beta;
251 accumulators[3][i] += s_lagrange[(size_t)i];
252 accumulators[3][i] += gamma_beta_constant;
253 }
254 });
255
256 // Step 2: Compute the constituent product components of Z_lookup(X).
257 // Let ∏ := Prod_{k<j}. Let f_k, t_k and s_k now represent the k'th component of the polynomials f,t and s
258 // defined above. We compute the following four product polynomials needed to construct the grand product
259 // Z_lookup(X).
260 // 1. accumulators[0][j] = ∏ (q_lookup*f_k + γ)
261 // 2. accumulators[1][j] = ∏ (t_k + βt_{k+1} + γ(1 + β))
262 // 3. accumulators[2][j] = ∏ (1 + β)
263 // 4. accumulators[3][j] = ∏ (s_k + βs_{k+1} + γ(1 + β))
264 // Note: This is a small multithreading bottleneck, as we have only 4 parallelizable processes.
265 parallel_for(4, [&](size_t i) {
266 fr* coeffs = &accumulators[i][0];
267 for (size_t j = 0; j < key->small_domain.size - 1; ++j) {
268 coeffs[j + 1] *= coeffs[j];
269 }
270 });
271
272 // Step 3: Combine the accumulator product elements to construct Z_lookup(X).
273 //
274 // ∏ (1 + β) ⋅ ∏ (q_lookup*f_k + γ) ⋅ ∏ (t_k + βt_{k+1} + γ(1 + β))
275 // Z_lookup(g^j) = --------------------------------------------------------------------------
276 // ∏ (s_k + βs_{k+1} + γ(1 + β))
277 //
278 // Note: Montgomery batch inversion is used to efficiently compute the coefficients of Z_lookup
279 // rather than peforming n individual inversions. I.e. we first compute the double product P_n:
280 //
281 // P_n := ∏_{j<n} ∏_{k<j} S_k, where S_k = (s_k + βs_{k+1} + γ(1 + β))
282 //
283 // and then compute the inverse on P_n. Then we work back to front to obtain terms of the form
284 // 1/∏_{k<i} S_i that appear in Z_lookup, using the fact that P_i/P_{i+1} = 1/∏_{k<i} S_i. (Note
285 // that once we have 1/P_n, we can compute 1/P_{n-1} as (1/P_n) * ∏_{k<n} S_i, and
286 // so on).
287 //
288 // Compute Z_lookup using Montgomery batch inversion
289 // Note: This loop sets the values of z_lookup[i] for i = 1,...,(n-1), (Recall accumulators[0][i] = z_lookup[i +
290 // 1])
291 parallel_for(key->small_domain.num_threads, [&](size_t j) {
292 const size_t start = j * key->small_domain.thread_size;
293 // Set 'end' so its max value is (n-1) thus max value for 'i' is n-2 (N.B. accumulators[0][n-2] =
294 // z_lookup[n-1])
295 const size_t end = (j == key->small_domain.num_threads - 1) ? (j + 1) * key->small_domain.thread_size - 1
296 : (j + 1) * key->small_domain.thread_size;
297
298 // Compute <Z_lookup numerator> * ∏_{j<i}∏_{k<j}S_k
299 fr inversion_accumulator = fr::one();
300 for (size_t i = start; i < end; ++i) {
301 accumulators[0][i] *= accumulators[2][i];
302 accumulators[0][i] *= accumulators[1][i];
303 accumulators[0][i] *= inversion_accumulator;
304 inversion_accumulator *= accumulators[3][i];
305 }
306 inversion_accumulator = inversion_accumulator.invert(); // invert
307 // Compute [Z_lookup numerator] * ∏_{j<i}∏_{k<j}S_k / ∏_{j<i+1}∏_{k<j}S_k = <Z_lookup numerator> /
308 // ∏_{k<i}S_k
309 for (size_t i = end - 1; i != start - 1; --i) {
310
311 // N.B. accumulators[0][i] = z_lookup[i + 1]
312 // We can avoid fully reducing z_lookup[i + 1] as the inverse fft will take care of that for us
313 accumulators[0][i] *= inversion_accumulator;
314 inversion_accumulator *= accumulators[3][i];
315 }
316 });
317 z_lookup[0] = fr::one();
318
319 // Since `z_plookup` needs to be evaluated at 2 points in UltraPLONK, we need to add a degree-2 random
320 // polynomial to `z_lookup` to make it "look" uniformly random. Alternatively, we can just add 3
321 // random scalars into the lagrange form of `z_lookup`, rationale for which similar to that explained
322 // for `s` polynomial.
323 const size_t z_randomness = 3;
324 ASSERT(z_randomness < num_roots_cut_out_of_vanishing_polynomial);
325 for (size_t k = 0; k < z_randomness; ++k) {
326 // Blinding:
327 z_lookup[((n - num_roots_cut_out_of_vanishing_polynomial) + 1 + k)] = fr::random_element();
328 }
329
330 // Compute and add monomial form of z_lookup to the polynomial store
331 z_lookup.ifft(key->small_domain);
332 key->polynomial_store.put("z_lookup", std::move(z_lookup));
333}
334
343template <const size_t num_roots_cut_out_of_vanishing_polynomial>
345 transcript::StandardTranscript& transcript, const size_t round_number, work_queue& queue)
346{
347 if (round_number == 2) {
348 compute_sorted_list_polynomial(transcript);
349 const polynomial& s = key->polynomial_store.get("s");
350
351 // Commit to s:
352 queue.add_to_queue({
353 .work_type = work_queue::WorkType::SCALAR_MULTIPLICATION,
354 .mul_scalars = s.data(),
355 .tag = "S",
356 .constant = key->circuit_size,
357 .index = 0,
358 });
359
360 // Compute the coset FFT of 's' for use in quotient poly construction
361 queue.add_to_queue({
362 .work_type = work_queue::WorkType::FFT,
363 .mul_scalars = nullptr,
364 .tag = "s",
365 .constant = barretenberg::fr(0),
366 .index = 0,
367 });
368
369 return;
370 }
371 if (round_number == 3) {
372 compute_grand_product_polynomial(transcript);
373 const polynomial& z = key->polynomial_store.get("z_lookup");
374
375 // Commit to z_lookup:
376 queue.add_to_queue({
377 .work_type = work_queue::WorkType::SCALAR_MULTIPLICATION,
378 .mul_scalars = z.data(),
379 .tag = "Z_LOOKUP",
380 .constant = key->circuit_size,
381 .index = 0,
382 });
383
384 // Compute the coset FFT of 'z_lookup' for use in quotient poly construction
385 queue.add_to_queue({
386 .work_type = work_queue::WorkType::FFT,
387 .mul_scalars = nullptr,
388 .tag = "z_lookup",
389 .constant = barretenberg::fr(0),
390 .index = 0,
391 });
392
393 return;
394 }
395}
396
419template <const size_t num_roots_cut_out_of_vanishing_polynomial>
421 const fr& alpha_base, const transcript::StandardTranscript& transcript)
422{
423 auto z_lookup_fft = key->polynomial_store.get("z_lookup_fft");
424
425 fr eta = fr::serialize_from_buffer(transcript.get_challenge("eta").begin());
426 fr alpha = fr::serialize_from_buffer(transcript.get_challenge("alpha").begin());
427 fr beta = fr::serialize_from_buffer(transcript.get_challenge("beta").begin());
428 fr gamma = fr::serialize_from_buffer(transcript.get_challenge("beta", 1).begin());
429
430 std::array<std::shared_ptr<fr[]>, 3> wire_ffts_ptr{
431 key->polynomial_store.get("w_1_fft").data(),
432 key->polynomial_store.get("w_2_fft").data(),
433 key->polynomial_store.get("w_3_fft").data(),
434 };
435 auto wire_ffts = map(wire_ffts_ptr, [](auto& e) { return e.get(); });
436
437 auto s_fft = key->polynomial_store.get("s_fft");
438
439 std::array<std::shared_ptr<fr[]>, 4> table_ffts_ptr{
440 key->polynomial_store.get("table_value_1_fft").data(),
441 key->polynomial_store.get("table_value_2_fft").data(),
442 key->polynomial_store.get("table_value_3_fft").data(),
443 key->polynomial_store.get("table_value_4_fft").data(),
444 };
445 auto table_ffts = map(table_ffts_ptr, [](auto& e) { return e.get(); });
446
447 auto column_1_step_size = key->polynomial_store.get("q_2_fft");
448 auto column_2_step_size = key->polynomial_store.get("q_m_fft");
449 auto column_3_step_size = key->polynomial_store.get("q_c_fft");
450
451 auto lookup_fft = key->polynomial_store.get("table_type_fft");
452 auto lookup_index_fft = key->polynomial_store.get("q_3_fft");
453
454 const fr gamma_beta_constant = gamma * (fr(1) + beta); // γ(1 + β)
455
456 // FIXME something weird happens here when this is run with wasm. The first access gives you a wrong hash
457 // of lagrange_1_fft. The second and third are the correct hashes of lagrange_1_fft.
458 // Since the second value ("l_1") is used in the algorithm, the test passes.
459 // However, if you comment out the following line, suddenly "l_1" becomes the "1st" access
460 // which is incorrect, and hence the proof fails for wasm.
461 auto l_1 = key->polynomial_store.get("lagrange_1_fft");
462 // delta_factor = [γ(1 + β)]^{n-k}
463 const fr delta_factor = gamma_beta_constant.pow(key->small_domain.size - num_roots_cut_out_of_vanishing_polynomial);
464 const fr alpha_sqr = alpha.sqr();
465
466 const fr beta_constant = beta + fr(1); // (1 + β)
467
468 const size_t block_mask = key->large_domain.size - 1;
469
470 // Add to the quotient polynomial the components associated with z_lookup
471 parallel_for(key->large_domain.num_threads, [&](size_t j) {
472 const size_t start = j * key->large_domain.thread_size;
473 const size_t end = (j + 1) * key->large_domain.thread_size;
474
475 fr T0;
476 fr T1;
477 fr denominator;
478 fr numerator;
479
480 // Initialize first four t(X) = t_table(X) for expression t + βt(Xω) + γ(1 + β)
481 std::array<fr, 4> next_ts;
482 for (size_t i = 0; i < 4; ++i) {
483 next_ts[i] = table_ffts[3][(start + i) & block_mask];
484 next_ts[i] *= eta;
485 next_ts[i] += table_ffts[2][(start + i) & block_mask];
486 next_ts[i] *= eta;
487 next_ts[i] += table_ffts[1][(start + i) & block_mask];
488 next_ts[i] *= eta;
489 next_ts[i] += table_ffts[0][(start + i) & block_mask];
490 }
491 for (size_t i = start; i < end; ++i) {
492 // Set T0 = f := (w_1 + q_2*w_1(Xω)) + η(w_2 + q_m*w_2(Xω)) + η²(w_3 + q_c*w_3(Xω)) + η³q_index
493 T0 = lookup_index_fft[i];
494 T0 *= eta;
495 T0 += wire_ffts[2][(i + 4) & block_mask] * column_3_step_size[i];
496 T0 += wire_ffts[2][i];
497 T0 *= eta;
498 T0 += wire_ffts[1][(i + 4) & block_mask] * column_2_step_size[i];
499 T0 += wire_ffts[1][i];
500 T0 *= eta;
501 T0 += wire_ffts[0][(i + 4) & block_mask] * column_1_step_size[i];
502 T0 += wire_ffts[0][i];
503
504 // Set numerator = q_lookup*f + γ
505 numerator = T0;
506 numerator *= lookup_fft[i];
507 numerator += gamma;
508
509 // Set T0 = t(Xω) := t_1(Xω) + ηt_2(Xω) + η²t_3(Xω) + η³t_4(Xω)
510 T0 = table_ffts[3][(i + 4) & block_mask];
511 T0 *= eta;
512 T0 += table_ffts[2][(i + 4) & block_mask];
513 T0 *= eta;
514 T0 += table_ffts[1][(i + 4) & block_mask];
515 T0 *= eta;
516 T0 += table_ffts[0][(i + 4) & block_mask];
517
518 // Set T1 = (t + βt(Xω) + γ(1 + β))
519 T1 = beta;
520 T1 *= T0;
521 T1 += next_ts[i & 0x03UL];
522 T1 += gamma_beta_constant;
523
524 // Set t(X) = t(Xω) for the next time around
525 next_ts[i & 0x03UL] = T0;
526
527 // numerator = (q_lookup*f + γ) * (t + βt(Xω) + γ(1 + β)) * (1 + β)
528 numerator *= T1;
529 numerator *= beta_constant;
530
531 // Set denominator = (s + βs(Xω) + γ(1 + β))
532 denominator = s_fft[(i + 4) & block_mask];
533 denominator *= beta;
534 denominator += s_fft[i];
535 denominator += gamma_beta_constant;
536
537 // Set T0 = αL_1(X)
538 T0 = l_1[i] * alpha;
539 // Set T1 = α²L_{n-k}(X) = α²L_1(Xω^{-(n-k)+1}) = α²L_1(Xω^{k+1}), k = num roots cut out of Z_H
540 T1 = l_1[(i + 4 + 4 * num_roots_cut_out_of_vanishing_polynomial) & block_mask] * alpha_sqr;
541
542 // Set numerator = z_lookup(X)*[(q_lookup*f + γ) * (t + βt(Xω) + γ(1 + β)) * (1 + β)] + (z_lookup -
543 // 1)*αL_1(X)
544 numerator += T0;
545 numerator *= z_lookup_fft[i];
546 numerator -= T0;
547
548 // Set denominator = z_lookup(Xω)*(s + βs(Xω) + γ(1 + β)) - [z_lookup(Xω) - [γ(1 + β)]^{n-k}]*α²L_{n-k}(X)
549 denominator -= T1;
550 denominator *= z_lookup_fft[(i + 4) & block_mask];
551 denominator += T1 * delta_factor;
552
553 // Combine into quotient polynomial contribution
554 // T0 = z_lookup(X)*[(q_lookup*f + γ) * (t + βt(Xω) + γ(1 + β)) * (1 + β)] + (z_lookup - 1)*αL_1(X) ...
555 // - z_lookup(Xω)*(s + βs(Xω) + γ(1 + β)) + [z_lookup(Xω) - [γ(1 + β)]^{n-k}]*α²L_{n-k}(X)
556 T0 = numerator - denominator;
557 // key->quotient_large[i] += T0 * alpha_base; // CODY: Luke did this while documenting
558 key->quotient_polynomial_parts[i >> key->small_domain.log2_size][i & (key->circuit_size - 1)] +=
559 T0 * alpha_base;
560 }
561 });
562 return alpha_base * alpha.sqr() * alpha;
563}
564
565// ###
566
567template <typename Field, typename Group, typename Transcript, const size_t num_roots_cut_out_of_vanishing_polynomial>
568VerifierPlookupWidget<Field, Group, Transcript, num_roots_cut_out_of_vanishing_polynomial>::VerifierPlookupWidget()
569{}
570
588template <typename Field, typename Group, typename Transcript, const size_t num_roots_cut_out_of_vanishing_polynomial>
590 compute_quotient_evaluation_contribution(typename Transcript::Key* key,
591 const Field& alpha_base,
592 const Transcript& transcript,
593 Field& quotient_numerator_eval)
594{
595
596 std::array<Field, 3> wire_evaluations{
597 transcript.get_field_element("w_1"),
598 transcript.get_field_element("w_2"),
599 transcript.get_field_element("w_3"),
600 };
601 std::array<Field, 3> shifted_wire_evaluations{
602 transcript.get_field_element("w_1_omega"),
603 transcript.get_field_element("w_2_omega"),
604 transcript.get_field_element("w_3_omega"),
605 };
606
607 std::array<Field, 4> table_evaluations{
608 transcript.get_field_element("table_value_1"),
609 transcript.get_field_element("table_value_2"),
610 transcript.get_field_element("table_value_3"),
611 transcript.get_field_element("table_value_4"),
612 };
613
614 std::array<Field, 4> shifted_table_evaluations{
615 transcript.get_field_element("table_value_1_omega"),
616 transcript.get_field_element("table_value_2_omega"),
617 transcript.get_field_element("table_value_3_omega"),
618 transcript.get_field_element("table_value_4_omega"),
619 };
620
621 Field column_1_step_size = transcript.get_field_element("q_2");
622 Field column_2_step_size = transcript.get_field_element("q_m");
623 Field column_3_step_size = transcript.get_field_element("q_c");
624 Field table_type_eval = transcript.get_field_element("table_type");
625 Field table_index_eval = transcript.get_field_element("q_3");
626
627 Field s_eval = transcript.get_field_element("s");
628 Field shifted_s_eval = transcript.get_field_element("s_omega");
629
630 Field z_eval = transcript.get_field_element("z_lookup");
631 Field shifted_z_eval = transcript.get_field_element("z_lookup_omega");
632
633 Field z = transcript.get_challenge_field_element("z");
634 Field alpha = transcript.get_challenge_field_element("alpha", 0);
635 Field beta = transcript.get_challenge_field_element("beta", 0);
636 Field gamma = transcript.get_challenge_field_element("beta", 1);
637 Field eta = transcript.get_challenge_field_element("eta", 0);
638 Field l_numerator = key->z_pow_n - Field(1);
639
640 l_numerator *= key->domain.domain_inverse;
641 Field l_1 = l_numerator / (z - Field(1));
642
643 // Compute evaluation L_end(z) = L_{n-k}(z) using ω^{-(n - k) + 1} = ω^{k + 1} where
644 // k = num roots cut out of Z_H
645 Field l_end_root = (num_roots_cut_out_of_vanishing_polynomial & 1) ? key->domain.root.sqr() : key->domain.root;
646 for (size_t i = 0; i < num_roots_cut_out_of_vanishing_polynomial / 2; ++i) {
647 l_end_root *= key->domain.root.sqr();
648 }
649 Field l_end = l_numerator / ((z * l_end_root) - Field(1)); // L_{n-k}(z)
650
651 const Field one(1);
652 const Field gamma_beta_constant = gamma * (one + beta); // γ(1 + β)
653
654 // [γ(1 + β)]^{n-k}
655 const Field delta_factor = gamma_beta_constant.pow(key->domain.domain - num_roots_cut_out_of_vanishing_polynomial);
656
657 const Field alpha_sqr = alpha.sqr();
658
659 const Field beta_constant = beta + one; // (1 + β)
660
661 Field T0;
662 Field T1;
663 Field denominator;
664 Field numerator;
665
666 // Set f_eval = f(z) := (w_1(z) + q_2*w_1(zω)) + η(w_2(z) + q_m*w_2(zω)) + η²(w_3(z) + q_c*w_3(zω)) + η³q_index(z)
667 Field f_eval = table_index_eval;
668 f_eval *= eta;
669 f_eval += shifted_wire_evaluations[2] * column_3_step_size;
670 f_eval += wire_evaluations[2];
671 f_eval *= eta;
672 f_eval += shifted_wire_evaluations[1] * column_2_step_size;
673 f_eval += wire_evaluations[1];
674 f_eval *= eta;
675 f_eval += shifted_wire_evaluations[0] * column_1_step_size;
676 f_eval += wire_evaluations[0];
677
678 // Set table_eval = t(z)
679 Field table_eval = table_evaluations[3];
680 table_eval *= eta;
681 table_eval += table_evaluations[2];
682 table_eval *= eta;
683 table_eval += table_evaluations[1];
684 table_eval *= eta;
685 table_eval += table_evaluations[0];
686
687 // Set numerator = q_index(z)*f(z) + γ
688 numerator = f_eval * table_type_eval;
689 numerator += gamma;
690
691 // Set T0 = t(zω)
692 T0 = shifted_table_evaluations[3];
693 T0 *= eta;
694 T0 += shifted_table_evaluations[2];
695 T0 *= eta;
696 T0 += shifted_table_evaluations[1];
697 T0 *= eta;
698 T0 += shifted_table_evaluations[0];
699
700 // Set T1 = t(z) + βt(zω) + γ(β + 1)
701 T1 = beta;
702 T1 *= T0;
703 T1 += table_eval;
704 T1 += gamma_beta_constant;
705
706 // Set numerator = (q_index*f(z) + γ) * (t(z) + βt(zω) + γ(β + 1)) * (β + 1)
707 numerator *= T1;
708 numerator *= beta_constant;
709
710 // Set denominator = s(z) + βs(zω) + γ(β + 1)
711 denominator = shifted_s_eval;
712 denominator *= beta;
713 denominator += s_eval;
714 denominator += gamma_beta_constant;
715
716 // Set T0 = αL_1(z), T1 = α²L_end(z)
717 T0 = l_1 * alpha;
718 T1 = l_end * alpha_sqr;
719
720 // Set numerator = z_lookup(z)*[(q_index*f(z) + γ) * (t(z) + βt(zω) + γ(β + 1)) * (β + 1)] + ...
721 // (z_lookup(z) - 1)*αL_1(z)
722 numerator += T0;
723 numerator *= z_eval;
724 numerator -= T0;
725
726 // Set denominator = z_lookup(zω)*[s(z) + βs(zω) + γ(1 + β)] - [z_lookup(zω) - [γ(1 + β)]^{n-k}]*α²L_end(z)
727 denominator -= T1;
728 denominator *= shifted_z_eval;
729 denominator += T1 * delta_factor;
730
731 // Set T0 = z_lookup(z)*[(q_index*f(z) + γ) * (t(z) + βt(zω) + γ(β + 1)) * (β + 1)] + (z_lookup(z) - 1)*αL_1(z) ...
732 // - z_lookup(zω)*[s(z) + βs(zω) + γ(1 + β)] + [z_lookup(zω) - [γ(1 + β)]^{n-k}]*α²L_end(z)
733 T0 = numerator - denominator;
734 quotient_numerator_eval += T0 * alpha_base;
735 return alpha_base * alpha.sqr() * alpha;
736} // namespace proof_system::plonk
737
738template <typename Field, typename Group, typename Transcript, const size_t num_roots_cut_out_of_vanishing_polynomial>
740 append_scalar_multiplication_inputs(typename Transcript::Key*,
741 const Field& alpha_base,
742 const Transcript& transcript,
743 std::map<std::string, Field>&)
744{
745 Field alpha = transcript.get_challenge_field_element("alpha");
746 return alpha_base * alpha.sqr() * alpha;
747}
748
749template class VerifierPlookupWidget<barretenberg::fr,
752
753} // namespace proof_system::plonk
Definition: affine_element.hpp:11
Definition: plookup_widget.hpp:29
Definition: plookup_widget.hpp:9
Definition: work_queue.hpp:11
Definition: transcript_wrappers.hpp:13
std::array< uint8_t, PRNG_OUTPUT_SIZE > get_challenge(const std::string &challenge_name, const size_t idx=0) const
Definition: transcript.cpp:308
std::shared_ptr< void > get_mem_slab(size_t size)
Definition: slab_allocator.cpp:214
Definition: widget.bench.cpp:13
BBERG_INLINE constexpr field sqr() const noexcept
Definition: field_impl.hpp:61