Barretenberg
The ZK-SNARK library at the core of Aztec
Loading...
Searching...
No Matches
ultra_relation_consistency.test.cpp
Go to the documentation of this file.
1
25#include <gtest/gtest.h>
26
27using namespace bb;
28
29using FF = fr;
31 static constexpr size_t NUM_ELEMENTS = 45;
33
35 {
36 InputElements result;
37 std::generate(result._data.begin(), result._data.end(), [] { return FF::random_element(); });
38 return result;
39 }
40
41 static InputElements get_special() // use non-random values
42 {
43 InputElements result;
44 FF idx = 0;
45 std::generate(result._data.begin(), result._data.end(), [&] {
46 idx += FF(1);
47 return idx;
48 });
49 return result;
50 }
51
52 FF& q_c = std::get<0>(_data);
53 FF& q_l = std::get<1>(_data);
54 FF& q_r = std::get<2>(_data);
55 FF& q_o = std::get<3>(_data);
56 FF& q_4 = std::get<4>(_data);
57 FF& q_m = std::get<5>(_data);
70 FF& id_1 = std::get<18>(_data);
71 FF& id_2 = std::get<19>(_data);
72 FF& id_3 = std::get<20>(_data);
73 FF& id_4 = std::get<21>(_data);
80 FF& w_l = std::get<28>(_data);
81 FF& w_r = std::get<29>(_data);
82 FF& w_o = std::get<30>(_data);
83 FF& w_4 = std::get<31>(_data);
94};
95
96class UltraRelationConsistency : public testing::Test {
97 public:
98 template <typename Relation>
100 const typename Relation::SumcheckArrayOfValuesOverSubrelations& expected_values,
101 const InputElements& input_elements,
102 const auto& parameters)
103 {
105 std::fill(accumulator.begin(), accumulator.end(), FF(0));
106 Relation::accumulate(accumulator, input_elements, parameters, 1);
107 EXPECT_EQ(accumulator, expected_values);
108 };
109};
110
112{
113 const auto run_test = [](bool random_inputs, const FF& q_arith_value = FF::random_element()) {
115 using SumcheckArrayOfValuesOverSubrelations = typename Relation::SumcheckArrayOfValuesOverSubrelations;
116
117 InputElements input_elements = random_inputs ? InputElements::get_random() : InputElements::get_special();
118 const auto& w_1 = input_elements.w_l;
119 const auto& w_1_shift = input_elements.w_l_shift;
120 const auto& w_2 = input_elements.w_r;
121 const auto& w_3 = input_elements.w_o;
122 const auto& w_4 = input_elements.w_4;
123 const auto& w_4_shift = input_elements.w_4_shift;
124 const auto& q_m = input_elements.q_m;
125 const auto& q_l = input_elements.q_l;
126 const auto& q_r = input_elements.q_r;
127 const auto& q_o = input_elements.q_o;
128 const auto& q_4 = input_elements.q_4;
129 const auto& q_c = input_elements.q_c;
130
131 // Set specific q_arith value to enable testing different modes of the arithmetic relation
132 input_elements.q_arith = q_arith_value;
133 const auto& q_arith = input_elements.q_arith;
134
135 SumcheckArrayOfValuesOverSubrelations expected_values;
136 static const FF neg_half = FF(-2).invert();
137
138 FF contribution_1 = FF(0);
139 FF contribution_2 = FF(0);
140 if (q_arith == FF(1)) {
141 // Contribution 1
142 contribution_1 = (q_m * w_2 * w_1) + (q_l * w_1) + (q_r * w_2) + (q_o * w_3) + (q_4 * w_4) + q_c;
143
144 // Contribution 2: None
145 } else if (q_arith == FF(2)) {
146 // Contribution 1
147 contribution_1 = (q_m * w_2 * w_1);
148 contribution_1 += ((q_l * w_1) + (q_r * w_2) + (q_o * w_3) + (q_4 * w_4) + w_4_shift + q_c) * FF(2);
149
150 // Contribution 2: None
151 } else if (q_arith == FF(3)) {
152 // Contribution 1
153 contribution_1 = (q_l * w_1) + (q_r * w_2) + (q_o * w_3) + (q_4 * w_4) + q_c;
154 contribution_1 += w_4_shift * FF(2);
155 contribution_1 *= FF(3);
156
157 // Contribution 2
158 contribution_2 = (w_1 + w_4 - w_1_shift + q_m) * FF(6);
159 } else {
160 // Contribution 1
161 contribution_1 = (q_arith - 3) * (q_m * w_2 * w_1) * neg_half;
162 contribution_1 += (q_l * w_1) + (q_r * w_2) + (q_o * w_3) + (q_4 * w_4) + q_c;
163 contribution_1 += (q_arith - 1) * w_4_shift;
164 contribution_1 *= q_arith;
165
166 // Contribution 2
167 contribution_2 = (w_1 + w_4 - w_1_shift + q_m);
168 contribution_2 *= (q_arith - 2) * (q_arith - 1) * q_arith;
169 }
170
171 expected_values[0] = contribution_1;
172 expected_values[1] = contribution_2;
173
174 const auto parameters = RelationParameters<FF>::get_random();
175
176 validate_relation_execution<Relation>(expected_values, input_elements, parameters);
177 };
178 run_test(/*random_inputs=*/false);
179 run_test(/*random_inputs=*/true);
180 run_test(/*random_inputs=*/true, /*q_arith_value=*/FF(1));
181 run_test(/*random_inputs=*/true, /*q_arith_value=*/FF(2));
182 run_test(/*random_inputs=*/true, /*q_arith_value=*/FF(3));
183};
184
186{
187 const auto run_test = [](bool random_inputs) {
189 using SumcheckArrayOfValuesOverSubrelations = typename Relation::SumcheckArrayOfValuesOverSubrelations;
190
191 const InputElements input_elements = random_inputs ? InputElements::get_random() : InputElements::get_special();
192 const auto& w_1 = input_elements.w_l;
193 const auto& w_2 = input_elements.w_r;
194 const auto& w_3 = input_elements.w_o;
195 const auto& w_4 = input_elements.w_4;
196 const auto& sigma_1 = input_elements.sigma_1;
197 const auto& sigma_2 = input_elements.sigma_2;
198 const auto& sigma_3 = input_elements.sigma_3;
199 const auto& sigma_4 = input_elements.sigma_4;
200 const auto& id_1 = input_elements.id_1;
201 const auto& id_2 = input_elements.id_2;
202 const auto& id_3 = input_elements.id_3;
203 const auto& id_4 = input_elements.id_4;
204 const auto& z_perm = input_elements.z_perm;
205 const auto& z_perm_shift = input_elements.z_perm_shift;
206 const auto& lagrange_first = input_elements.lagrange_first;
207 const auto& lagrange_last = input_elements.lagrange_last;
208
209 SumcheckArrayOfValuesOverSubrelations expected_values;
210
211 const auto parameters = RelationParameters<FF>::get_random();
212 const auto& beta = parameters.beta;
213 const auto& gamma = parameters.gamma;
214 const auto& public_input_delta = parameters.public_input_delta;
215
216 // Contribution 1
217 auto contribution_1 = (z_perm + lagrange_first) * (w_1 + id_1 * beta + gamma) * (w_2 + id_2 * beta + gamma) *
218 (w_3 + id_3 * beta + gamma) * (w_4 + id_4 * beta + gamma) -
219 (z_perm_shift + lagrange_last * public_input_delta) * (w_1 + sigma_1 * beta + gamma) *
220 (w_2 + sigma_2 * beta + gamma) * (w_3 + sigma_3 * beta + gamma) *
221 (w_4 + sigma_4 * beta + gamma);
222 expected_values[0] = contribution_1;
223
224 // Contribution 2
225 auto contribution_2 = z_perm_shift * lagrange_last;
226 expected_values[1] = contribution_2;
227
228 validate_relation_execution<Relation>(expected_values, input_elements, parameters);
229 };
230 run_test(/*random_inputs=*/false);
231 run_test(/*random_inputs=*/true);
232};
233
235{
236 const auto run_test = [](bool random_inputs) {
238 using SumcheckArrayOfValuesOverSubrelations = typename Relation::SumcheckArrayOfValuesOverSubrelations;
239
240 const InputElements input_elements = random_inputs ? InputElements::get_random() : InputElements::get_special();
241 const auto& w_1 = input_elements.w_l;
242 const auto& w_2 = input_elements.w_r;
243 const auto& w_3 = input_elements.w_o;
244 const auto& w_4 = input_elements.w_4;
245 const auto& w_1_shift = input_elements.w_l_shift;
246 const auto& q_delta_range = input_elements.q_delta_range;
247
248 auto delta_1 = w_2 - w_1;
249 auto delta_2 = w_3 - w_2;
250 auto delta_3 = w_4 - w_3;
251 auto delta_4 = w_1_shift - w_4;
252
253 auto contribution_1 = delta_1 * (delta_1 - 1) * (delta_1 - 2) * (delta_1 - 3);
254 auto contribution_2 = delta_2 * (delta_2 - 1) * (delta_2 - 2) * (delta_2 - 3);
255 auto contribution_3 = delta_3 * (delta_3 - 1) * (delta_3 - 2) * (delta_3 - 3);
256 auto contribution_4 = delta_4 * (delta_4 - 1) * (delta_4 - 2) * (delta_4 - 3);
257
258 SumcheckArrayOfValuesOverSubrelations expected_values;
259
260 expected_values[0] = contribution_1 * q_delta_range;
261 expected_values[1] = contribution_2 * q_delta_range;
262 expected_values[2] = contribution_3 * q_delta_range;
263 expected_values[3] = contribution_4 * q_delta_range;
264
265 const auto parameters = RelationParameters<FF>::get_random();
266
267 validate_relation_execution<Relation>(expected_values, input_elements, parameters);
268 };
269 run_test(/*random_inputs=*/false);
270 run_test(/*random_inputs=*/true);
271};
272
274{
275 const auto run_test = [](bool random_inputs) {
277 using SumcheckArrayOfValuesOverSubrelations = typename Relation::SumcheckArrayOfValuesOverSubrelations;
278
279 const InputElements input_elements = random_inputs ? InputElements::get_random() : InputElements::get_special();
280
281 const auto& x_1 = input_elements.w_r;
282 const auto& y_1 = input_elements.w_o;
283
284 const auto& x_2 = input_elements.w_l_shift;
285 const auto& y_2 = input_elements.w_4_shift;
286 const auto& x_3 = input_elements.w_r_shift;
287 const auto& y_3 = input_elements.w_o_shift;
288
289 // In the EllipticRelation, q_l is interpreted as q_sign and can be +1 or -1. Here we explicitly set it to -1
290 // (arbitrary, could also be +1) because the relation algebra makes use of the assumption that q_sign^2 = 1.
291 // This allows writing the simplified constraint algebra in this test in a more straightforward way.
292 input_elements.q_l = FF(-1);
293 const auto& q_sign = input_elements.q_l;
294 const auto& q_elliptic = input_elements.q_elliptic;
295 const auto& q_is_double = input_elements.q_m;
296
297 SumcheckArrayOfValuesOverSubrelations expected_values;
298 // Compute x/y coordinate identities
299 {
300 auto y_diff = (q_sign * y_2 - y_1);
301 auto x_diff = (x_2 - x_1);
302 auto x_diff_sqr = x_diff * x_diff;
303 auto lambda = y_diff / x_diff;
304 auto lambda_sqr = lambda * lambda;
305
306 // Contribution (1) point addition, x-coordinate check
307 // Formula: x3 = lambda^2 - (x1 + x2)
308 // lambda = (y2 - y1) / (x2 - x1)
309 // Constraint: (x3 - lambda^2 + (x1 + x2)) * (x2 - x1)^2 = 0
310 auto x_add_identity = (x_3 - lambda_sqr + (x_1 + x_2)) * x_diff_sqr;
311
312 // Contribution (2) point addition, y-coordinate check
313 // Formula: y3 = lambda * (x1 - x3) - y1
314 // Constraint: (y3 - lambda * (x1 - x3) + y1) * (x2 - x1) = 0
315 auto y_add_identity = (y_3 - lambda * (x_1 - x_3) + y_1) * x_diff;
316
317 // N.B. the relation uses the equivalence x1^3 === y1^2 - curve_b to reduce degree by 1 so we must do the
318 // same here
319 const auto curve_b = EllipticRelationImpl<FF>::get_curve_b();
320 auto y1_sqr = (y_1 * y_1);
321 auto x_pow_4 = (y1_sqr - curve_b) * x_1; // curve equation substitution
322 lambda_sqr = x_pow_4 * 9 / (y1_sqr * 4);
323 lambda = (x_1 * x_1 * 3) / (y_1 * 2);
324
325 // Contribution (3) point doubling, x-coordinate check
326 // Formula: x3 = lambda^2 - 2*x1
327 // lambda = (3*x1 * x1) / (2*y1)
328 // Constraint: (x3 - lambda^2 + 2*x1) * (2*y1) = 0
329 auto x_double_identity = (x_3 - lambda_sqr + x_1 * 2) * (y1_sqr * 4);
330
331 // Contribution (4) point doubling, y-coordinate check
332 // Formula: y3 = lambda * (x1 - x3) - y1
333 // Constraint: (y3 - lambda * (x1 - x3) + y1) * (2*y1) * FF(-1) = 0
334 // N.B. multiply by -1 to match form used for efficient accumulation in relation
335 auto y_double_identity = (y_3 - lambda * (x_1 - x_3) + y_1) * (y_1 * 2) * FF(-1);
336
337 // Combine addition and doubling subidentities, each scaled by q_is_double
338 expected_values[0] = (x_add_identity * (-q_is_double + 1) + (x_double_identity * q_is_double)) * q_elliptic;
339 expected_values[1] = (y_add_identity * (-q_is_double + 1) + (y_double_identity * q_is_double)) * q_elliptic;
340 }
341
342 const auto parameters = RelationParameters<FF>::get_random();
343
344 validate_relation_execution<Relation>(expected_values, input_elements, parameters);
345 };
346 run_test(/*random_inputs=*/false);
347 run_test(/*random_inputs=*/true);
348};
349
351{
352 const auto run_test = [](bool random_inputs) {
354 using SumcheckArrayOfValuesOverSubrelations = typename Relation::SumcheckArrayOfValuesOverSubrelations;
355
356 const InputElements input_elements = random_inputs ? InputElements::get_random() : InputElements::get_special();
357 const auto& w_1 = input_elements.w_l;
358 const auto& w_2 = input_elements.w_r;
359 const auto& w_3 = input_elements.w_o;
360 const auto& w_4 = input_elements.w_4;
361 const auto& w_1_shift = input_elements.w_l_shift;
362 const auto& w_2_shift = input_elements.w_r_shift;
363 const auto& w_3_shift = input_elements.w_o_shift;
364 const auto& w_4_shift = input_elements.w_4_shift;
365
366 const auto& q_2 = input_elements.q_r;
367 const auto& q_3 = input_elements.q_o;
368 const auto& q_4 = input_elements.q_4;
369 const auto& q_m = input_elements.q_m;
370 const auto& q_nnf = input_elements.q_nnf;
371
372 constexpr FF LIMB_SIZE(uint256_t(1) << 68);
373 constexpr FF SUBLIMB_SHIFT(uint256_t(1) << 14);
374 constexpr FF SUBLIMB_SHIFT_2(SUBLIMB_SHIFT * SUBLIMB_SHIFT);
375 constexpr FF SUBLIMB_SHIFT_3(SUBLIMB_SHIFT_2 * SUBLIMB_SHIFT);
376 constexpr FF SUBLIMB_SHIFT_4(SUBLIMB_SHIFT_3 * SUBLIMB_SHIFT);
377
378 SumcheckArrayOfValuesOverSubrelations expected_values;
379
380 // [(w_1 * w_2_shift) + (w_1_shift * w_2)] * LIMB_SIZE + (w_1_shift * w_2_shift) - (w_3 + w_4)
381 auto nnf_gate_1 = (w_1 * w_2_shift + w_1_shift * w_2) * LIMB_SIZE;
382 nnf_gate_1 += (w_1_shift * w_2_shift);
383 nnf_gate_1 -= (w_3 + w_4);
384
385 // [(w_1 * w_4) + (w_2 * w_3) - w_3_shift] * LIMB_SIZE - w_4_shift + (w_1 * w_2_shift) + (w_1_shift * w_2)
386 auto nnf_gate_2 = (w_1 * w_4 + w_2 * w_3 - w_3_shift) * LIMB_SIZE;
387 nnf_gate_2 -= w_4_shift;
388 nnf_gate_2 += w_1 * w_2_shift + w_1_shift * w_2;
389
390 // [(w_1 * w_2_shift) + (w_1_shift * w_2)] * LIMB_SIZE + (w_1_shift * w_2_shift) + w_4 - (w_3_shift + w_4_shift)
391 auto nnf_gate_3 = (w_1 * w_2_shift + w_1_shift * w_2) * LIMB_SIZE;
392 nnf_gate_3 += (w_1_shift * w_2_shift);
393 nnf_gate_3 += w_4;
394 nnf_gate_3 -= (w_3_shift + w_4_shift);
395
396 auto limb_accumulator_1 = w_1 + w_2 * SUBLIMB_SHIFT + w_3 * SUBLIMB_SHIFT_2 + w_1_shift * SUBLIMB_SHIFT_3 +
397 w_2_shift * SUBLIMB_SHIFT_4 - w_4;
398
399 auto limb_accumulator_2 = w_3 + w_4 * SUBLIMB_SHIFT + w_1_shift * SUBLIMB_SHIFT_2 +
400 w_2_shift * SUBLIMB_SHIFT_3 + w_3_shift * SUBLIMB_SHIFT_4 - w_4_shift;
401
402 // Multiply each subidentity by its corresponding selector product
403 nnf_gate_1 *= (q_2 * q_3);
404 nnf_gate_2 *= (q_2 * q_4);
405 nnf_gate_3 *= (q_2 * q_m);
406 limb_accumulator_1 *= (q_3 * q_4);
407 limb_accumulator_2 *= (q_3 * q_m);
408
409 auto non_native_field_identity = nnf_gate_1 + nnf_gate_2 + nnf_gate_3;
410 auto limb_accumulator_identity = limb_accumulator_1 + limb_accumulator_2;
411
412 expected_values[0] = non_native_field_identity + limb_accumulator_identity;
413 expected_values[0] *= q_nnf;
414
415 const auto parameters = RelationParameters<FF>::get_random();
416
417 validate_relation_execution<Relation>(expected_values, input_elements, parameters);
418 };
419 run_test(/*random_inputs=*/false);
420 run_test(/*random_inputs=*/true);
421};
422
424{
425 const auto run_test = [](bool random_inputs) {
427 using SumcheckArrayOfValuesOverSubrelations = typename Relation::SumcheckArrayOfValuesOverSubrelations;
428
429 const InputElements input_elements = random_inputs ? InputElements::get_random() : InputElements::get_special();
430 const auto& w_1 = input_elements.w_l;
431 const auto& w_2 = input_elements.w_r;
432 const auto& w_3 = input_elements.w_o;
433 const auto& w_4 = input_elements.w_4;
434 const auto& w_1_shift = input_elements.w_l_shift;
435 const auto& w_2_shift = input_elements.w_r_shift;
436 const auto& w_3_shift = input_elements.w_o_shift;
437 const auto& w_4_shift = input_elements.w_4_shift;
438
439 const auto& q_1 = input_elements.q_l;
440 const auto& q_2 = input_elements.q_r;
441 const auto& q_3 = input_elements.q_o;
442 const auto& q_4 = input_elements.q_4;
443 const auto& q_m = input_elements.q_m;
444 const auto& q_c = input_elements.q_c;
445 const auto& q_memory = input_elements.q_memory;
446
447 const auto parameters = RelationParameters<FF>::get_random();
448 const auto& eta = parameters.eta;
449 const auto& eta_two = parameters.eta_two;
450 const auto& eta_three = parameters.eta_three;
451
452 SumcheckArrayOfValuesOverSubrelations expected_values;
453
457 auto memory_record_check = w_3 * eta_three;
458 memory_record_check += w_2 * eta_two;
459 memory_record_check += w_1 * eta;
460 memory_record_check += q_c;
461 auto partial_record_check = memory_record_check; // used in RAM consistency check
462 memory_record_check = memory_record_check - w_4;
463
467 auto index_delta = w_1_shift - w_1;
468 auto record_delta = w_4_shift - w_4;
469
470 auto index_is_monotonically_increasing = index_delta * index_delta - index_delta;
471
472 // auto adjacent_values_match_if_adjacent_indices_match = (FF(1) - index_delta) * record_delta;
473 auto adjacent_values_match_if_adjacent_indices_match = (index_delta * FF(-1) + FF(1)) * record_delta;
474
475 expected_values[1] = adjacent_values_match_if_adjacent_indices_match * (q_1 * q_2);
476 expected_values[2] = index_is_monotonically_increasing * (q_1 * q_2);
477 auto ROM_consistency_check_identity = memory_record_check * (q_1 * q_2);
478
482 auto access_type = (w_4 - partial_record_check); // will be 0 or 1 for honest Prover
483 auto access_check = access_type * access_type - access_type; // check value is 0 or 1
484
485 auto next_gate_access_type = w_3_shift * eta_three;
486 next_gate_access_type += w_2_shift * eta_two;
487 next_gate_access_type += w_1_shift * eta;
488 next_gate_access_type = w_4_shift - next_gate_access_type;
489
490 auto value_delta = w_3_shift - w_3;
491 auto adjacent_values_match_if_adjacent_indices_match_and_next_access_is_a_read_operation =
492 (index_delta * FF(-1) + FF(1)) * value_delta * (next_gate_access_type * FF(-1) + FF(1));
493
494 // We can't apply the RAM consistency check identity on the final entry in the sorted list (the wires in the
495 // next gate would make the identity fail). We need to validate that its 'access type' bool is correct. Can't do
496 // with an arithmetic gate because of the `eta` factors. We need to check that the *next* gate's access type is
497 // correct, to cover this edge case
498 auto next_gate_access_type_is_boolean = next_gate_access_type * next_gate_access_type - next_gate_access_type;
499
500 // Putting it all together...
501 expected_values[3] =
502 adjacent_values_match_if_adjacent_indices_match_and_next_access_is_a_read_operation * (q_3);
503 expected_values[4] = index_is_monotonically_increasing * (q_3);
504 expected_values[5] = next_gate_access_type_is_boolean * (q_3);
505 auto RAM_consistency_check_identity = access_check * (q_3);
506
510 memory_record_check *= (q_1 * q_m);
511
515 auto timestamp_delta = w_2_shift - w_2;
516 auto RAM_timestamp_check_identity = (index_delta * FF(-1) + FF(1)) * timestamp_delta - w_3;
517 RAM_timestamp_check_identity *= (q_1 * q_4);
518
522 auto memory_identity = ROM_consistency_check_identity;
523 memory_identity += RAM_timestamp_check_identity;
524 memory_identity += memory_record_check;
525 memory_identity += RAM_consistency_check_identity;
526
527 expected_values[0] = memory_identity;
528 expected_values[0] *= q_memory;
529 expected_values[1] *= q_memory;
530 expected_values[2] *= q_memory;
531 expected_values[3] *= q_memory;
532 expected_values[4] *= q_memory;
533 expected_values[5] *= q_memory;
534
535 validate_relation_execution<Relation>(expected_values, input_elements, parameters);
536 };
537 run_test(/*random_inputs=*/false);
538 run_test(/*random_inputs=*/true);
539};
540
542{
543 const auto run_test = []([[maybe_unused]] bool random_inputs) {
545 using SumcheckArrayOfValuesOverSubrelations = typename Relation::SumcheckArrayOfValuesOverSubrelations;
546 const InputElements input_elements = random_inputs ? InputElements::get_random() : InputElements::get_special();
547
548 const auto& w_1 = input_elements.w_l;
549 const auto& w_2 = input_elements.w_r;
550 const auto& w_3 = input_elements.w_o;
551 const auto& w_4 = input_elements.w_4;
552 const auto& w_1_shift = input_elements.w_l_shift;
553 const auto& w_2_shift = input_elements.w_r_shift;
554 const auto& w_3_shift = input_elements.w_o_shift;
555 const auto& w_4_shift = input_elements.w_4_shift;
556 const auto& q_1 = input_elements.q_l;
557 const auto& q_2 = input_elements.q_r;
558 const auto& q_3 = input_elements.q_o;
559 const auto& q_4 = input_elements.q_4;
560 const auto& q_poseidon2_external = input_elements.q_poseidon2_external;
561 SumcheckArrayOfValuesOverSubrelations expected_values;
562
563 // add round constants
564 auto s1 = w_1 + q_1;
565 auto s2 = w_2 + q_2;
566 auto s3 = w_3 + q_3;
567 auto s4 = w_4 + q_4;
568
569 // apply s-box round
570 auto u1 = s1 * s1;
571 u1 *= u1;
572 u1 *= s1;
573 auto u2 = s2 * s2;
574 u2 *= u2;
575 u2 *= s2;
576 auto u3 = s3 * s3;
577 u3 *= u3;
578 u3 *= s3;
579 auto u4 = s4 * s4;
580 u4 *= u4;
581 u4 *= s4;
582
583 // matrix mul v = M_E * u with 14 additions
584 auto t0 = u1 + u2; // u_1 + u_2
585 auto t1 = u3 + u4; // u_3 + u_4
586 auto t2 = u2 + u2; // 2u_2
587 t2 += t1; // 2u_2 + u_3 + u_4
588 auto t3 = u4 + u4; // 2u_4
589 t3 += t0; // u_1 + u_2 + 2u_4
590 auto v4 = t1 + t1;
591 v4 += v4;
592 v4 += t3; // u_1 + u_2 + 4u_3 + 6u_4
593 auto v2 = t0 + t0;
594 v2 += v2;
595 v2 += t2; // 4u_1 + 6u_2 + u_3 + u_4
596 auto v1 = t3 + v2; // 5u_1 + 7u_2 + u_3 + 3u_4
597 auto v3 = t2 + v4; // u_1 + 3u_2 + 5u_3 + 7u_4
598
599 // output is { v1, v2, v3, v4 }
600
601 expected_values[0] = q_poseidon2_external * (v1 - w_1_shift);
602 expected_values[1] = q_poseidon2_external * (v2 - w_2_shift);
603 expected_values[2] = q_poseidon2_external * (v3 - w_3_shift);
604 expected_values[3] = q_poseidon2_external * (v4 - w_4_shift);
605
606 const auto parameters = RelationParameters<FF>::get_random();
607 validate_relation_execution<Relation>(expected_values, input_elements, parameters);
608
609 // validate_relation_execution<Relation>(expected_values, input_elements, parameters);
610 };
611 run_test(/*random_inputs=*/false);
612 run_test(/*random_inputs=*/true);
613};
614
616{
617 const auto run_test = []([[maybe_unused]] bool random_inputs) {
619 using SumcheckArrayOfValuesOverSubrelations = typename Relation::SumcheckArrayOfValuesOverSubrelations;
620 const InputElements input_elements = random_inputs ? InputElements::get_random() : InputElements::get_special();
621
622 const auto& w_1 = input_elements.w_l;
623 const auto& w_2 = input_elements.w_r;
624 const auto& w_3 = input_elements.w_o;
625 const auto& w_4 = input_elements.w_4;
626 const auto& w_1_shift = input_elements.w_l_shift;
627 const auto& w_2_shift = input_elements.w_r_shift;
628 const auto& w_3_shift = input_elements.w_o_shift;
629 const auto& w_4_shift = input_elements.w_4_shift;
630 const auto& q_1 = input_elements.q_l;
631 const auto& q_poseidon2_internal = input_elements.q_poseidon2_internal;
632 SumcheckArrayOfValuesOverSubrelations expected_values;
633
634 // add round constants on only first element
635 auto v1 = w_1 + q_1;
636
637 // apply s-box to only first element
638 auto u1 = v1 * v1;
639 u1 *= u1;
640 u1 *= v1;
641
642 // multiply with internal matrix
643 auto sum = u1 + w_2 + w_3 + w_4;
645 t0 += sum;
647 t1 += sum;
649 t2 += sum;
651 t3 += sum;
652
653 expected_values[0] = q_poseidon2_internal * (t0 - w_1_shift);
654 expected_values[1] = q_poseidon2_internal * (t1 - w_2_shift);
655 expected_values[2] = q_poseidon2_internal * (t2 - w_3_shift);
656 expected_values[3] = q_poseidon2_internal * (t3 - w_4_shift);
657
658 const auto parameters = RelationParameters<FF>::get_random();
659 validate_relation_execution<Relation>(expected_values, input_elements, parameters);
660
661 // validate_relation_execution<Relation>(expected_values, input_elements, parameters);
662 };
663 run_test(/*random_inputs=*/false);
664 run_test(/*random_inputs=*/true);
665};
static void validate_relation_execution(const typename Relation::SumcheckArrayOfValuesOverSubrelations &expected_values, const InputElements &input_elements, const auto &parameters)
static constexpr FF get_curve_b()
A wrapper for Relations to expose methods used by the Sumcheck prover or verifier to add the contribu...
ArrayOfValues< FF, RelationImpl::SUBRELATION_PARTIAL_LENGTHS > SumcheckArrayOfValuesOverSubrelations
Entry point for Barretenberg command-line interface.
Definition api.hpp:5
TEST_F(IPATest, ChallengesAreZero)
Definition ipa.test.cpp:185
field< Bn254FrParams > fr
Definition fr.hpp:174
Inner sum(Cont< Inner, Args... > const &in)
Definition container.hpp:70
constexpr decltype(auto) get(::tuplet::tuple< T... > &&t) noexcept
Definition tuple.hpp:13
static InputElements get_special()
std::array< FF, NUM_ELEMENTS > _data
static constexpr size_t NUM_ELEMENTS
static InputElements get_random()
static RelationParameters get_random()
static constexpr std::array< FF, t > internal_matrix_diagonal
constexpr field invert() const noexcept
static field random_element(numeric::RNG *engine=nullptr) noexcept