Barretenberg
The ZK-SNARK library at the core of Aztec
Loading...
Searching...
No Matches
ecc_set_relation_impl.hpp
Go to the documentation of this file.
1// === AUDIT STATUS ===
2// internal: { status: Complete, auditors: [Raju], commit: 2a49eb6 }
3// external_1: { status: not started, auditors: [], commit: }
4// external_2: { status: not started, auditors: [], commit: }
5// =====================
6
7#pragma once
10#include <type_traits>
11
12namespace bb {
13
69template <typename FF>
70template <typename Accumulator, typename AllEntities, typename Parameters>
71Accumulator ECCVMSetRelationImpl<FF>::compute_grand_product_numerator(const AllEntities& in, const Parameters& params)
72{
73 using View = typename Accumulator::View;
74
75 const auto& precompute_round = View(in.precompute_round);
76 const auto precompute_round2 = precompute_round + precompute_round;
77 const auto precompute_round4 = precompute_round2 + precompute_round2;
78
79 const auto& gamma = params.gamma;
80 const auto& beta = params.beta;
81 const auto& beta_sqr = params.beta_sqr;
82 const auto& beta_cube = params.beta_cube;
83 const auto& precompute_pc = View(in.precompute_pc);
84 const auto& precompute_select = View(in.precompute_select);
85
98 // OPTIMIZE(@zac-williamson #2226) optimize degrees
99
100 Accumulator numerator(1); // degree-0
101 {
102 const auto& s0 = View(in.precompute_s1hi);
103 const auto& s1 = View(in.precompute_s1lo);
104
105 auto wnaf_slice = s0 + s0;
106 wnaf_slice += wnaf_slice;
107 wnaf_slice += s1;
108
109 const auto wnaf_slice_input0 = wnaf_slice + gamma + precompute_pc * beta + precompute_round4 * beta_sqr;
110 numerator *= wnaf_slice_input0; // degree-1
111 }
112 {
113 const auto& s0 = View(in.precompute_s2hi);
114 const auto& s1 = View(in.precompute_s2lo);
115
116 auto wnaf_slice = s0 + s0;
117 wnaf_slice += wnaf_slice;
118 wnaf_slice += s1;
119
120 const auto wnaf_slice_input1 = wnaf_slice + gamma + precompute_pc * beta + (precompute_round4 + 1) * beta_sqr;
121 numerator *= wnaf_slice_input1; // degree-2
122 }
123 {
124 const auto& s0 = View(in.precompute_s3hi);
125 const auto& s1 = View(in.precompute_s3lo);
126
127 auto wnaf_slice = s0 + s0;
128 wnaf_slice += wnaf_slice;
129 wnaf_slice += s1;
130
131 const auto wnaf_slice_input2 = wnaf_slice + gamma + precompute_pc * beta + (precompute_round4 + 2) * beta_sqr;
132 numerator *= wnaf_slice_input2; // degree-3
133 }
134 {
135 const auto& s0 = View(in.precompute_s4hi);
136 const auto& s1 = View(in.precompute_s4lo);
137
138 auto wnaf_slice = s0 + s0;
139 wnaf_slice += wnaf_slice;
140 wnaf_slice += s1;
141 const auto wnaf_slice_input3 = wnaf_slice + gamma + precompute_pc * beta + (precompute_round4 + 3) * beta_sqr;
142 numerator *= wnaf_slice_input3; // degree-4
143 }
144 {
145 // skew product if relevant
146 const auto& skew = View(in.precompute_skew);
147 const auto& precompute_point_transition = View(in.precompute_point_transition);
148 const auto skew_input =
149 precompute_point_transition * (skew + gamma + precompute_pc * beta + (precompute_round4 + 4) * beta_sqr) +
150 (-precompute_point_transition + 1);
151 numerator *= skew_input; // degree-5
152 }
153 {
154 // in `EccvmProver` and `ECCVMVerifier`, we see that `eccvm_set_permutation_delta` is initially computed as
155 // (γ)·(γ + β²)·(γ + 2β²)·(γ + 3β²) and _then_ inverted. Therefore, `eccvm_set_permutation_delta` == 1 / (γ)·(γ
156 // + β²)·(γ + 2β²)·(γ
157 // + 3β²)
158 const auto& eccvm_set_permutation_delta = params.eccvm_set_permutation_delta;
159 // if `precompute_select == 1`, don't change the numerator. if it is 0, then to get the grand product argument
160 // to work (as we have zero-padded the rows of the MSM table), we must multiply by the inverse of the
161 // fingerprint of (0, 0, 0).
162 numerator *= precompute_select * (-eccvm_set_permutation_delta + 1) + eccvm_set_permutation_delta; // degree-7
163 }
164
178 {
179 const auto& table_x = View(in.precompute_tx);
180 const auto& table_y = View(in.precompute_ty);
181
182 const auto& precompute_skew = View(in.precompute_skew);
183 const auto negative_inverse_seven = []() {
184 if constexpr (std::same_as<FF, grumpkin::fr>) {
185 static constexpr FF negative_inverse_seven = FF(-7).invert();
186 return negative_inverse_seven;
187 } else {
188 FF negative_inverse_seven = FF(-7).invert();
189 return negative_inverse_seven;
190 }
191 };
192 auto adjusted_skew =
193 precompute_skew * negative_inverse_seven(); // `precompute_skew` ∈ {0, 7}, `adjusted_skew`∈ {0, -1}
194
195 const auto& wnaf_scalar_sum = View(in.precompute_scalar_sum);
196 const auto w0 = convert_to_wnaf<Accumulator>(View(in.precompute_s1hi), View(in.precompute_s1lo));
197 const auto w1 = convert_to_wnaf<Accumulator>(View(in.precompute_s2hi), View(in.precompute_s2lo));
198 const auto w2 = convert_to_wnaf<Accumulator>(View(in.precompute_s3hi), View(in.precompute_s3lo));
199 const auto w3 = convert_to_wnaf<Accumulator>(View(in.precompute_s4hi), View(in.precompute_s4lo));
200
201 auto row_slice = w0;
202 row_slice += row_slice;
203 row_slice += row_slice;
204 row_slice += row_slice;
205 row_slice += row_slice;
206 row_slice += w1;
207 row_slice += row_slice;
208 row_slice += row_slice;
209 row_slice += row_slice;
210 row_slice += row_slice;
211 row_slice += w2;
212 row_slice += row_slice;
213 row_slice += row_slice;
214 row_slice += row_slice;
215 row_slice += row_slice;
216 row_slice += w3; // row_slice = 2^12 w_0 + 2^8 w_1 + 2^4 w_2 + 2^0 w_3
217
218 auto scalar_sum_full = wnaf_scalar_sum + wnaf_scalar_sum;
219 scalar_sum_full += scalar_sum_full;
220 scalar_sum_full += scalar_sum_full;
221 scalar_sum_full += scalar_sum_full;
222 scalar_sum_full += scalar_sum_full;
223 scalar_sum_full += scalar_sum_full;
224 scalar_sum_full += scalar_sum_full;
225 scalar_sum_full += scalar_sum_full;
226 scalar_sum_full += scalar_sum_full;
227 scalar_sum_full += scalar_sum_full;
228 scalar_sum_full += scalar_sum_full;
229 scalar_sum_full += scalar_sum_full;
230 scalar_sum_full += scalar_sum_full;
231 scalar_sum_full += scalar_sum_full;
232 scalar_sum_full += scalar_sum_full;
233 scalar_sum_full += scalar_sum_full;
234 scalar_sum_full +=
235 row_slice + adjusted_skew; // scalar_sum_full = 2^16 * wnaf_scalar_sum + row_slice + adjusted_skew
236
237 auto precompute_point_transition = View(in.precompute_point_transition);
238
239 auto point_table_init_read =
240 (precompute_pc + table_x * beta + table_y * beta_sqr + scalar_sum_full * beta_cube);
241 point_table_init_read =
242 precompute_point_transition * (point_table_init_read + gamma) + (-precompute_point_transition + 1);
243
244 numerator *= point_table_init_read; // degree-9
245 }
263 {
264 const auto& lagrange_first = View(in.lagrange_first);
265 const auto& partial_msm_transition_shift = View(in.msm_transition_shift);
266 const auto msm_transition_shift = (-lagrange_first + 1) * partial_msm_transition_shift;
267 const auto& msm_pc_shift = View(in.msm_pc_shift);
268
269 const auto& msm_x_shift = View(in.msm_accumulator_x_shift);
270 const auto& msm_y_shift = View(in.msm_accumulator_y_shift);
271 const auto& msm_size = View(in.msm_size_of_msm);
272
273 // msm_transition = 1 when a row BEGINS a new msm
274 //
275 // row msm tx acc.x acc.y pc msm_size
276 // i 0 no no no yes
277 // i+1 1 yes yes yes no
278 //
279 // at row i we are at the final row of the current msm
280 // at row i the value of `msm_size` = size of current msm
281 // at row i + 1 we have the final accumulated value of the msm computation
282 // at row i + 1 we have updated `pc` to be `(pc at start of msm) + msm_count`
283 // at row i + 1 q_msm_transtiion = 1
284
285 auto msm_result_write = msm_pc_shift + msm_x_shift * beta + msm_y_shift * beta_sqr + msm_size * beta_cube;
286
287 // msm_result_write = degree 2
288 msm_result_write = msm_transition_shift * (msm_result_write + gamma) + (-msm_transition_shift + 1);
289 numerator *= msm_result_write; // degree-11
290 }
291 return numerator;
292}
293
294template <typename FF>
295template <typename Accumulator, typename AllEntities, typename Parameters>
296Accumulator ECCVMSetRelationImpl<FF>::compute_grand_product_denominator(const AllEntities& in, const Parameters& params)
297{
298 using View = typename Accumulator::View;
299
300 // OPTIMIZE(@zac-williamson). The degree of this contribution is 17! makes overall relation degree 19.
301 // Can potentially optimize by refining the algebra.
302 const auto& gamma = params.gamma;
303 const auto& beta = params.beta;
304 const auto& beta_sqr = params.beta_sqr;
305 const auto& beta_cube = params.beta_cube;
306 const auto& msm_pc = View(in.msm_pc);
307 const auto& msm_count = View(in.msm_count);
308 const auto& msm_round = View(in.msm_round);
309
315 Accumulator denominator(1); // degree-0
316 {
317 const auto& add1 = View(in.msm_add1);
318 const auto& msm_slice1 = View(in.msm_slice1);
319
320 auto wnaf_slice_output1 =
321 add1 * (msm_slice1 + gamma + (msm_pc - msm_count) * beta + msm_round * beta_sqr) + (-add1 + 1);
322 denominator *= wnaf_slice_output1; // degree-2
323 }
324 {
325 const auto& add2 = View(in.msm_add2);
326 const auto& msm_slice2 = View(in.msm_slice2);
327
328 auto wnaf_slice_output2 =
329 add2 * (msm_slice2 + gamma + (msm_pc - msm_count - 1) * beta + msm_round * beta_sqr) + (-add2 + 1);
330 denominator *= wnaf_slice_output2; // degree-4
331 }
332 {
333 const auto& add3 = View(in.msm_add3);
334 const auto& msm_slice3 = View(in.msm_slice3);
335
336 auto wnaf_slice_output3 =
337 add3 * (msm_slice3 + gamma + (msm_pc - msm_count - 2) * beta + msm_round * beta_sqr) + (-add3 + 1);
338 denominator *= wnaf_slice_output3; // degree-6
339 }
340 {
341 const auto& add4 = View(in.msm_add4);
342 const auto& msm_slice4 = View(in.msm_slice4);
343 auto wnaf_slice_output4 =
344 add4 * (msm_slice4 + gamma + (msm_pc - msm_count - 3) * beta + msm_round * beta_sqr) + (-add4 + 1);
345 denominator *= wnaf_slice_output4; // degree-8
346 }
347
358 {
359 const auto& transcript_pc = View(in.transcript_pc);
360
361 const auto& transcript_Px = View(in.transcript_Px);
362 const auto& transcript_Py = View(in.transcript_Py);
363 const auto& z1 = View(in.transcript_z1);
364 const auto& z2 = View(in.transcript_z2);
365 const auto& z1_zero = View(in.transcript_z1zero);
366 const auto& z2_zero = View(in.transcript_z2zero);
367 const auto& base_infinity = View(in.transcript_base_infinity);
368 const auto& transcript_mul = View(in.transcript_mul);
369
370 const auto& lookup_first = (-z1_zero + 1);
371 const auto& lookup_second = (-z2_zero + 1);
372 FF cube_root_unity = FF(bb::fq::cube_root_of_unity());
373
374 auto transcript_input1 =
375 transcript_pc + transcript_Px * beta + transcript_Py * beta_sqr + z1 * beta_cube; // degree = 1
376 auto transcript_input2 = (transcript_pc - 1) + transcript_Px * cube_root_unity * beta -
377 transcript_Py * beta_sqr + z2 * beta_cube; // degree = 2
378
379 // The following diagram expresses a fingerprint of part of the tuple. It does not include `transcript_pc` and
380 // has not weighted the X and Y with beta and beta_sqr respectively. The point is nonetheless to show exactly
381 // when a tuple is added to the multiset: iff it corresponds to a non-trivial (128-bit) scalar mul. If neither
382 // z1 nor z2 are zero, then we implicitly add _two_ tuples to the multiset.
383 //
384 // | q_mul | z2_zero | z1_zero | base_infinity | partial lookup |
385 // | ----- | ------- | ------- | ------------- |----------------------- |
386 // | 0 | - | - | - | 1 |
387 // | 1 | 0 | 0 | 0 | 1 |
388 // | 1 | 0 | 1 | 0 | X + gamma |
389 // | 1 | 1 | 0 | 0 | Y + gamma |
390 // | 1 | 1 | 1 | 0 | (X + gamma)(Y + gamma) |
391 // | 1 | 0 | 0 | 1 | 1 |
392 // | 1 | 0 | 1 | 1 | 1 |
393 // | 1 | 1 | 0 | 1 | 1 |
394 // | 1 | 1 | 1 | 1 | 1 |
395 transcript_input1 = (transcript_input1 + gamma) * lookup_first + (-lookup_first + 1); // degree 2
396 transcript_input2 = (transcript_input2 + gamma) * lookup_second + (-lookup_second + 1); // degree 3
397
398 // transcript_product = degree 6
399 auto transcript_product = (transcript_input1 * transcript_input2) * (-base_infinity + 1) + base_infinity;
400
401 // point_table_init_write = degree 7
402 auto point_table_init_write = transcript_mul * transcript_product + (-transcript_mul + 1);
403 denominator *= point_table_init_write; // degree 17
404 }
420 {
421 const auto& transcript_pc_shift = View(in.transcript_pc_shift);
422 const auto& transcript_msm_x = View(in.transcript_msm_x);
423 const auto& transcript_msm_y = View(in.transcript_msm_y);
424 const auto& transcript_msm_transition = View(in.transcript_msm_transition);
425 const auto& transcript_msm_count = View(in.transcript_msm_count);
426 const auto& z1_zero = View(in.transcript_z1zero);
427 const auto& z2_zero = View(in.transcript_z2zero);
428 const auto& transcript_mul = View(in.transcript_mul);
429 const auto& base_infinity = View(in.transcript_base_infinity);
430
431 // do not add to count if point at infinity!
432 auto full_msm_count =
433 transcript_msm_count + transcript_mul * ((-z1_zero + 1) + (-z2_zero + 1)) * (-base_infinity + 1);
434 // msm_result_read = degree 2
435 auto msm_result_read =
436 transcript_pc_shift + transcript_msm_x * beta + transcript_msm_y * beta_sqr + full_msm_count * beta_cube;
437 msm_result_read = transcript_msm_transition * (msm_result_read + gamma) + (-transcript_msm_transition + 1);
438 denominator *= msm_result_read; // degree-20
439 }
440 return denominator;
441}
442
453template <typename FF>
454template <typename ContainerOverSubrelations, typename AllEntities, typename Parameters>
455void ECCVMSetRelationImpl<FF>::accumulate(ContainerOverSubrelations& accumulator,
456 const AllEntities& in,
457 const Parameters& params,
458 const FF& scaling_factor)
459{
460 using Accumulator = typename std::tuple_element_t<0, ContainerOverSubrelations>;
461 using View = typename Accumulator::View;
462 using ShortView = typename std::tuple_element_t<1, ContainerOverSubrelations>::View;
463
464 // degree-11
465 Accumulator numerator_evaluation = compute_grand_product_numerator<Accumulator>(in, params);
466
467 // degree-20
468 Accumulator denominator_evaluation = compute_grand_product_denominator<Accumulator>(in, params);
469
470 const auto& lagrange_first = View(in.lagrange_first);
471 const auto& lagrange_last = View(in.lagrange_last);
472 const auto& lagrange_last_short = ShortView(in.lagrange_last);
473
474 const auto& z_perm = View(in.z_perm);
475 const auto& z_perm_shift = View(in.z_perm_shift);
476 const auto& z_perm_shift_short = ShortView(in.z_perm_shift);
477
478 // degree-21
479 std::get<0>(accumulator) +=
480 ((z_perm + lagrange_first) * numerator_evaluation - (z_perm_shift + lagrange_last) * denominator_evaluation) *
481 scaling_factor;
482
483 // Contribution (2)
484 std::get<1>(accumulator) += lagrange_last_short * z_perm_shift_short * scaling_factor;
485}
486} // namespace bb
bb::field< bb::Bn254FrParams > FF
Definition field.cpp:22
static Accumulator compute_grand_product_denominator(const AllEntities &in, const Parameters &params)
static Accumulator compute_grand_product_numerator(const AllEntities &in, const Parameters &params)
Performs multiset equality checks for the ECCVM. This faciliates "communication" between disjoint set...
static void accumulate(ContainerOverSubrelations &accumulator, const AllEntities &in, const Parameters &params, const FF &scaling_factor)
Expression for the standard arithmetic gate. @dbetails The relation is defined as C(in(X)....
Entry point for Barretenberg command-line interface.
Definition api.hpp:5
constexpr decltype(auto) get(::tuplet::tuple< T... > &&t) noexcept
Definition tuple.hpp:13
static constexpr field cube_root_of_unity()
constexpr field invert() const noexcept