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: not started, auditors: [], date: YYYY-MM-DD }
3// external_1: { status: not started, auditors: [], date: YYYY-MM-DD }
4// external_2: { status: not started, auditors: [], date: YYYY-MM-DD }
5// =====================
6
7#pragma once
10#include <type_traits>
11
12namespace bb {
13
58template <typename FF>
59template <typename Accumulator, typename AllEntities, typename Parameters>
60Accumulator ECCVMSetRelationImpl<FF>::compute_grand_product_numerator(const AllEntities& in, const Parameters& params)
61{
62 using View = typename Accumulator::View;
63
64 const auto& precompute_round = View(in.precompute_round);
65 const auto precompute_round2 = precompute_round + precompute_round;
66 const auto precompute_round4 = precompute_round2 + precompute_round2;
67
68 const auto& gamma = params.gamma;
69 const auto& beta = params.beta;
70 const auto& beta_sqr = params.beta_sqr;
71 const auto& beta_cube = params.beta_cube;
72 const auto& precompute_pc = View(in.precompute_pc);
73 const auto& precompute_select = View(in.precompute_select);
74
87 // OPTIMIZE(@zac-williamson #2226) optimize degrees
88
89 Accumulator numerator(1); // degree-0
90 {
91 const auto& s0 = View(in.precompute_s1hi);
92 const auto& s1 = View(in.precompute_s1lo);
93
94 auto wnaf_slice = s0 + s0;
95 wnaf_slice += wnaf_slice;
96 wnaf_slice += s1;
97
98 const auto wnaf_slice_input0 = wnaf_slice + gamma + precompute_pc * beta + precompute_round4 * beta_sqr;
99 numerator *= wnaf_slice_input0; // degree-1
100 }
101 {
102 const auto& s0 = View(in.precompute_s2hi);
103 const auto& s1 = View(in.precompute_s2lo);
104
105 auto wnaf_slice = s0 + s0;
106 wnaf_slice += wnaf_slice;
107 wnaf_slice += s1;
108
109 const auto wnaf_slice_input1 = wnaf_slice + gamma + precompute_pc * beta + (precompute_round4 + 1) * beta_sqr;
110 numerator *= wnaf_slice_input1; // degree-2
111 }
112 {
113 const auto& s0 = View(in.precompute_s3hi);
114 const auto& s1 = View(in.precompute_s3lo);
115
116 auto wnaf_slice = s0 + s0;
117 wnaf_slice += wnaf_slice;
118 wnaf_slice += s1;
119
120 const auto wnaf_slice_input2 = wnaf_slice + gamma + precompute_pc * beta + (precompute_round4 + 2) * beta_sqr;
121 numerator *= wnaf_slice_input2; // degree-3
122 }
123 {
124 const auto& s0 = View(in.precompute_s4hi);
125 const auto& s1 = View(in.precompute_s4lo);
126
127 auto wnaf_slice = s0 + s0;
128 wnaf_slice += wnaf_slice;
129 wnaf_slice += s1;
130 const auto wnaf_slice_input3 = wnaf_slice + gamma + precompute_pc * beta + (precompute_round4 + 3) * beta_sqr;
131 numerator *= wnaf_slice_input3; // degree-4
132 }
133 {
134 // skew product if relevant
135 const auto& skew = View(in.precompute_skew);
136 const auto& precompute_point_transition = View(in.precompute_point_transition);
137 const auto skew_input =
138 precompute_point_transition * (skew + gamma + precompute_pc * beta + (precompute_round4 + 4) * beta_sqr) +
139 (-precompute_point_transition + 1);
140 numerator *= skew_input; // degree-5
141 }
142 {
143 const auto& eccvm_set_permutation_delta = params.eccvm_set_permutation_delta;
144 // if `precompute_select == 1`, don't change the numerator. if it is 0, then to get the grand product argument
145 // to work (as we have zero-padded the rows of the MSM table), we must multiply by
146 // `eccvm_set_permutation_delta` == (γ)·(γ + β²)·(γ + 2β²)·(γ + 3β²)
147 numerator *= precompute_select * (-eccvm_set_permutation_delta + 1) + eccvm_set_permutation_delta; // degree-7
148 }
149
163 {
164 const auto& table_x = View(in.precompute_tx);
165 const auto& table_y = View(in.precompute_ty);
166
167 const auto& precompute_skew = View(in.precompute_skew);
168 const auto negative_inverse_seven = []() {
169 if constexpr (std::same_as<FF, grumpkin::fr>) {
170 static constexpr FF negative_inverse_seven = FF(-7).invert();
171 return negative_inverse_seven;
172 } else {
173 FF negative_inverse_seven = FF(-7).invert();
174 return negative_inverse_seven;
175 }
176 };
177 auto adjusted_skew =
178 precompute_skew * negative_inverse_seven(); // `precompute_skew` ∈ {0, 7}, `adjusted_skew`∈ {0, -1}
179
180 const auto& wnaf_scalar_sum = View(in.precompute_scalar_sum);
181 const auto w0 = convert_to_wnaf<Accumulator>(View(in.precompute_s1hi), View(in.precompute_s1lo));
182 const auto w1 = convert_to_wnaf<Accumulator>(View(in.precompute_s2hi), View(in.precompute_s2lo));
183 const auto w2 = convert_to_wnaf<Accumulator>(View(in.precompute_s3hi), View(in.precompute_s3lo));
184 const auto w3 = convert_to_wnaf<Accumulator>(View(in.precompute_s4hi), View(in.precompute_s4lo));
185
186 auto row_slice = w0;
187 row_slice += row_slice;
188 row_slice += row_slice;
189 row_slice += row_slice;
190 row_slice += row_slice;
191 row_slice += w1;
192 row_slice += row_slice;
193 row_slice += row_slice;
194 row_slice += row_slice;
195 row_slice += row_slice;
196 row_slice += w2;
197 row_slice += row_slice;
198 row_slice += row_slice;
199 row_slice += row_slice;
200 row_slice += row_slice;
201 row_slice += w3; // row_slice = 2^12 w_0 + 2^8 w_1 + 2^4 w_2 + 2^0 w_3
202
203 auto scalar_sum_full = wnaf_scalar_sum + wnaf_scalar_sum;
204 scalar_sum_full += scalar_sum_full;
205 scalar_sum_full += scalar_sum_full;
206 scalar_sum_full += scalar_sum_full;
207 scalar_sum_full += scalar_sum_full;
208 scalar_sum_full += scalar_sum_full;
209 scalar_sum_full += scalar_sum_full;
210 scalar_sum_full += scalar_sum_full;
211 scalar_sum_full += scalar_sum_full;
212 scalar_sum_full += scalar_sum_full;
213 scalar_sum_full += scalar_sum_full;
214 scalar_sum_full += scalar_sum_full;
215 scalar_sum_full += scalar_sum_full;
216 scalar_sum_full += scalar_sum_full;
217 scalar_sum_full += scalar_sum_full;
218 scalar_sum_full += scalar_sum_full;
219 scalar_sum_full +=
220 row_slice + adjusted_skew; // scalar_sum_full = 2^16 * wnaf_scalar_sum + row_slice + adjusted_skew
221
222 auto precompute_point_transition = View(in.precompute_point_transition);
223
224 auto point_table_init_read =
225 (precompute_pc + table_x * beta + table_y * beta_sqr + scalar_sum_full * beta_cube);
226 point_table_init_read =
227 precompute_point_transition * (point_table_init_read + gamma) + (-precompute_point_transition + 1);
228
229 numerator *= point_table_init_read; // degree-9
230 }
248 {
249 const auto& lagrange_first = View(in.lagrange_first);
250 const auto& partial_msm_transition_shift = View(in.msm_transition_shift);
251 const auto msm_transition_shift = (-lagrange_first + 1) * partial_msm_transition_shift;
252 const auto& msm_pc_shift = View(in.msm_pc_shift);
253
254 const auto& msm_x_shift = View(in.msm_accumulator_x_shift);
255 const auto& msm_y_shift = View(in.msm_accumulator_y_shift);
256 const auto& msm_size = View(in.msm_size_of_msm);
257
258 // msm_transition = 1 when a row BEGINS a new msm
259 //
260 // row msm tx acc.x acc.y pc msm_size
261 // i 0 no no no yes
262 // i+1 1 yes yes yes no
263 //
264 // at row i we are at the final row of the current msm
265 // at row i the value of `msm_size` = size of current msm
266 // at row i + 1 we have the final accumulated value of the msm computation
267 // at row i + 1 we have updated `pc` to be `(pc at start of msm) + msm_count`
268 // at row i + 1 q_msm_transtiion = 1
269
270 auto msm_result_write = msm_pc_shift + msm_x_shift * beta + msm_y_shift * beta_sqr + msm_size * beta_cube;
271
272 // msm_result_write = degree 2
273 msm_result_write = msm_transition_shift * (msm_result_write + gamma) + (-msm_transition_shift + 1);
274 numerator *= msm_result_write; // degree-11
275 }
276 return numerator;
277}
278
279template <typename FF>
280template <typename Accumulator, typename AllEntities, typename Parameters>
281Accumulator ECCVMSetRelationImpl<FF>::compute_grand_product_denominator(const AllEntities& in, const Parameters& params)
282{
283 using View = typename Accumulator::View;
284
285 // OPTIMIZE(@zac-williamson). The degree of this contribution is 17! makes overall relation degree 19.
286 // Can potentially optimize by refining the algebra.
287 const auto& gamma = params.gamma;
288 const auto& beta = params.beta;
289 const auto& beta_sqr = params.beta_sqr;
290 const auto& beta_cube = params.beta_cube;
291 const auto& msm_pc = View(in.msm_pc);
292 const auto& msm_count = View(in.msm_count);
293 const auto& msm_round = View(in.msm_round);
294
300 Accumulator denominator(1); // degree-0
301 {
302 const auto& add1 = View(in.msm_add1);
303 const auto& msm_slice1 = View(in.msm_slice1);
304
305 auto wnaf_slice_output1 =
306 add1 * (msm_slice1 + gamma + (msm_pc - msm_count) * beta + msm_round * beta_sqr) + (-add1 + 1);
307 denominator *= wnaf_slice_output1; // degree-2
308 }
309 {
310 const auto& add2 = View(in.msm_add2);
311 const auto& msm_slice2 = View(in.msm_slice2);
312
313 auto wnaf_slice_output2 =
314 add2 * (msm_slice2 + gamma + (msm_pc - msm_count - 1) * beta + msm_round * beta_sqr) + (-add2 + 1);
315 denominator *= wnaf_slice_output2; // degree-4
316 }
317 {
318 const auto& add3 = View(in.msm_add3);
319 const auto& msm_slice3 = View(in.msm_slice3);
320
321 auto wnaf_slice_output3 =
322 add3 * (msm_slice3 + gamma + (msm_pc - msm_count - 2) * beta + msm_round * beta_sqr) + (-add3 + 1);
323 denominator *= wnaf_slice_output3; // degree-6
324 }
325 {
326 const auto& add4 = View(in.msm_add4);
327 const auto& msm_slice4 = View(in.msm_slice4);
328 auto wnaf_slice_output4 =
329 add4 * (msm_slice4 + gamma + (msm_pc - msm_count - 3) * beta + msm_round * beta_sqr) + (-add4 + 1);
330 denominator *= wnaf_slice_output4; // degree-8
331 }
332
343 {
344 const auto& transcript_pc = View(in.transcript_pc);
345
346 const auto& transcript_Px = View(in.transcript_Px);
347 const auto& transcript_Py = View(in.transcript_Py);
348 const auto& z1 = View(in.transcript_z1);
349 const auto& z2 = View(in.transcript_z2);
350 const auto& z1_zero = View(in.transcript_z1zero);
351 const auto& z2_zero = View(in.transcript_z2zero);
352 const auto& base_infinity = View(in.transcript_base_infinity);
353 const auto& transcript_mul = View(in.transcript_mul);
354
355 const auto& lookup_first = (-z1_zero + 1);
356 const auto& lookup_second = (-z2_zero + 1);
357 FF cube_root_unity = FF(bb::fq::cube_root_of_unity());
358
359 auto transcript_input1 =
360 transcript_pc + transcript_Px * beta + transcript_Py * beta_sqr + z1 * beta_cube; // degree = 1
361 auto transcript_input2 = (transcript_pc - 1) + transcript_Px * cube_root_unity * beta -
362 transcript_Py * beta_sqr + z2 * beta_cube; // degree = 2
363
364 // The following diagram expresses a fingerprint of part of the tuple. It does not include `transcript_pc` and
365 // has not weighted the X and Y with beta and beta_sqr respectively. The point is nonetheless to show exactly
366 // when a tuple is added to the multiset: iff it corresponds to a non-trivial (128-bit) scalar mul. If neither
367 // z1 nor z2 are zero, then we implicitly add _two_ tuples to the multiset.
368 //
369 // | q_mul | z2_zero | z1_zero | base_infinity | partial lookup |
370 // | ----- | ------- | ------- | ------------- |----------------------- |
371 // | 0 | - | - | - | 1 |
372 // | 1 | 0 | 0 | 0 | 1 |
373 // | 1 | 0 | 1 | 0 | X + gamma |
374 // | 1 | 1 | 0 | 0 | Y + gamma |
375 // | 1 | 1 | 1 | 0 | (X + gamma)(Y + gamma) |
376 // | 1 | 0 | 0 | 1 | 1 |
377 // | 1 | 0 | 1 | 1 | 1 |
378 // | 1 | 1 | 0 | 1 | 1 |
379 // | 1 | 1 | 1 | 1 | 1 |
380 transcript_input1 = (transcript_input1 + gamma) * lookup_first + (-lookup_first + 1); // degree 2
381 transcript_input2 = (transcript_input2 + gamma) * lookup_second + (-lookup_second + 1); // degree 3
382
383 // transcript_product = degree 6
384 auto transcript_product = (transcript_input1 * transcript_input2) * (-base_infinity + 1) + base_infinity;
385
386 // point_table_init_write = degree 7
387 auto point_table_init_write = transcript_mul * transcript_product + (-transcript_mul + 1);
388 denominator *= point_table_init_write; // degree 17
389 }
405 {
406 const auto& transcript_pc_shift = View(in.transcript_pc_shift);
407 const auto& transcript_msm_x = View(in.transcript_msm_x);
408 const auto& transcript_msm_y = View(in.transcript_msm_y);
409 const auto& transcript_msm_transition = View(in.transcript_msm_transition);
410 const auto& transcript_msm_count = View(in.transcript_msm_count);
411 const auto& z1_zero = View(in.transcript_z1zero);
412 const auto& z2_zero = View(in.transcript_z2zero);
413 const auto& transcript_mul = View(in.transcript_mul);
414 const auto& base_infinity = View(in.transcript_base_infinity);
415
416 // do not add to count if point at infinity!
417 auto full_msm_count =
418 transcript_msm_count + transcript_mul * ((-z1_zero + 1) + (-z2_zero + 1)) * (-base_infinity + 1);
419 // msm_result_read = degree 2
420 auto msm_result_read =
421 transcript_pc_shift + transcript_msm_x * beta + transcript_msm_y * beta_sqr + full_msm_count * beta_cube;
422 msm_result_read = transcript_msm_transition * (msm_result_read + gamma) + (-transcript_msm_transition + 1);
423 denominator *= msm_result_read; // degree-20
424 }
425 return denominator;
426}
427
438template <typename FF>
439template <typename ContainerOverSubrelations, typename AllEntities, typename Parameters>
440void ECCVMSetRelationImpl<FF>::accumulate(ContainerOverSubrelations& accumulator,
441 const AllEntities& in,
442 const Parameters& params,
443 const FF& scaling_factor)
444{
445 using Accumulator = typename std::tuple_element_t<0, ContainerOverSubrelations>;
446 using View = typename Accumulator::View;
447 using ShortView = typename std::tuple_element_t<1, ContainerOverSubrelations>::View;
448
449 // degree-11
450 Accumulator numerator_evaluation = compute_grand_product_numerator<Accumulator>(in, params);
451
452 // degree-20
453 Accumulator denominator_evaluation = compute_grand_product_denominator<Accumulator>(in, params);
454
455 const auto& lagrange_first = View(in.lagrange_first);
456 const auto& lagrange_last = View(in.lagrange_last);
457 const auto& lagrange_last_short = ShortView(in.lagrange_last);
458
459 const auto& z_perm = View(in.z_perm);
460 const auto& z_perm_shift = View(in.z_perm_shift);
461 const auto& z_perm_shift_short = ShortView(in.z_perm_shift);
462
463 // degree-21
464 std::get<0>(accumulator) +=
465 ((z_perm + lagrange_first) * numerator_evaluation - (z_perm_shift + lagrange_last) * denominator_evaluation) *
466 scaling_factor;
467
468 // Contribution (2)
469 std::get<1>(accumulator) += lagrange_last_short * z_perm_shift_short * scaling_factor;
470}
471} // namespace bb
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.
typename Flavor::FF FF
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