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;
32 std::array<FF, NUM_ELEMENTS> _data;
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 // Contribution 3
229 auto contribution_3 = lagrange_first * z_perm;
230 expected_values[2] = contribution_3;
231
232 validate_relation_execution<Relation>(expected_values, input_elements, parameters);
233 };
234 run_test(/*random_inputs=*/false);
235 run_test(/*random_inputs=*/true);
236};
237
239{
240 const auto run_test = [](bool random_inputs) {
242 using SumcheckArrayOfValuesOverSubrelations = typename Relation::SumcheckArrayOfValuesOverSubrelations;
243
244 const InputElements input_elements = random_inputs ? InputElements::get_random() : InputElements::get_special();
245 const auto& w_1 = input_elements.w_l;
246 const auto& w_2 = input_elements.w_r;
247 const auto& w_3 = input_elements.w_o;
248 const auto& w_4 = input_elements.w_4;
249 const auto& w_1_shift = input_elements.w_l_shift;
250 const auto& q_delta_range = input_elements.q_delta_range;
251
252 auto delta_1 = w_2 - w_1;
253 auto delta_2 = w_3 - w_2;
254 auto delta_3 = w_4 - w_3;
255 auto delta_4 = w_1_shift - w_4;
256
257 auto contribution_1 = delta_1 * (delta_1 - 1) * (delta_1 - 2) * (delta_1 - 3);
258 auto contribution_2 = delta_2 * (delta_2 - 1) * (delta_2 - 2) * (delta_2 - 3);
259 auto contribution_3 = delta_3 * (delta_3 - 1) * (delta_3 - 2) * (delta_3 - 3);
260 auto contribution_4 = delta_4 * (delta_4 - 1) * (delta_4 - 2) * (delta_4 - 3);
261
262 SumcheckArrayOfValuesOverSubrelations expected_values;
263
264 expected_values[0] = contribution_1 * q_delta_range;
265 expected_values[1] = contribution_2 * q_delta_range;
266 expected_values[2] = contribution_3 * q_delta_range;
267 expected_values[3] = contribution_4 * q_delta_range;
268
269 const auto parameters = RelationParameters<FF>::get_random();
270
271 validate_relation_execution<Relation>(expected_values, input_elements, parameters);
272 };
273 run_test(/*random_inputs=*/false);
274 run_test(/*random_inputs=*/true);
275};
276
278{
279 const auto run_test = [](bool random_inputs) {
281 using SumcheckArrayOfValuesOverSubrelations = typename Relation::SumcheckArrayOfValuesOverSubrelations;
282
283 const InputElements input_elements = random_inputs ? InputElements::get_random() : InputElements::get_special();
284
285 const auto& x_1 = input_elements.w_r;
286 const auto& y_1 = input_elements.w_o;
287
288 const auto& x_2 = input_elements.w_l_shift;
289 const auto& y_2 = input_elements.w_4_shift;
290 const auto& x_3 = input_elements.w_r_shift;
291 const auto& y_3 = input_elements.w_o_shift;
292
293 // In the EllipticRelation, q_l is interpreted as q_sign and can be +1 or -1. Here we explicitly set it to -1
294 // (arbitrary, could also be +1) because the relation algebra makes use of the assumption that q_sign^2 = 1.
295 // This allows writing the simplified constraint algebra in this test in a more straightforward way.
296 input_elements.q_l = FF(-1);
297 const auto& q_sign = input_elements.q_l;
298 const auto& q_elliptic = input_elements.q_elliptic;
299 const auto& q_is_double = input_elements.q_m;
300
301 SumcheckArrayOfValuesOverSubrelations expected_values;
302 // Compute x/y coordinate identities
303 {
304 auto y_diff = (q_sign * y_2 - y_1);
305 auto x_diff = (x_2 - x_1);
306 auto x_diff_sqr = x_diff * x_diff;
307 auto lambda = y_diff / x_diff;
308 auto lambda_sqr = lambda * lambda;
309
310 // Contribution (1) point addition, x-coordinate check
311 // Formula: x3 = lambda^2 - (x1 + x2)
312 // lambda = (y2 - y1) / (x2 - x1)
313 // Constraint: (x3 - lambda^2 + (x1 + x2)) * (x2 - x1)^2 = 0
314 auto x_add_identity = (x_3 - lambda_sqr + (x_1 + x_2)) * x_diff_sqr;
315
316 // Contribution (2) point addition, y-coordinate check
317 // Formula: y3 = lambda * (x1 - x3) - y1
318 // Constraint: (y3 - lambda * (x1 - x3) + y1) * (x2 - x1) = 0
319 auto y_add_identity = (y_3 - lambda * (x_1 - x_3) + y_1) * x_diff;
320
321 // N.B. the relation uses the equivalence x1^3 === y1^2 - curve_b to reduce degree by 1 so we must do the
322 // same here
323 const auto curve_b = EllipticRelationImpl<FF>::get_curve_b();
324 auto y1_sqr = (y_1 * y_1);
325 auto x_pow_4 = (y1_sqr - curve_b) * x_1; // curve equation substitution
326 lambda_sqr = x_pow_4 * 9 / (y1_sqr * 4);
327 lambda = (x_1 * x_1 * 3) / (y_1 * 2);
328
329 // Contribution (3) point doubling, x-coordinate check
330 // Formula: x3 = lambda^2 - 2*x1
331 // lambda = (3*x1 * x1) / (2*y1)
332 // Constraint: (x3 - lambda^2 + 2*x1) * (2*y1) = 0
333 auto x_double_identity = (x_3 - lambda_sqr + x_1 * 2) * (y1_sqr * 4);
334
335 // Contribution (4) point doubling, y-coordinate check
336 // Formula: y3 = lambda * (x1 - x3) - y1
337 // Constraint: (y3 - lambda * (x1 - x3) + y1) * (2*y1) * FF(-1) = 0
338 // N.B. multiply by -1 to match form used for efficient accumulation in relation
339 auto y_double_identity = (y_3 - lambda * (x_1 - x_3) + y_1) * (y_1 * 2) * FF(-1);
340
341 // Combine addition and doubling subidentities, each scaled by q_is_double
342 expected_values[0] = (x_add_identity * (-q_is_double + 1) + (x_double_identity * q_is_double)) * q_elliptic;
343 expected_values[1] = (y_add_identity * (-q_is_double + 1) + (y_double_identity * q_is_double)) * q_elliptic;
344 }
345
346 const auto parameters = RelationParameters<FF>::get_random();
347
348 validate_relation_execution<Relation>(expected_values, input_elements, parameters);
349 };
350 run_test(/*random_inputs=*/false);
351 run_test(/*random_inputs=*/true);
352};
353
355{
356 const auto run_test = [](bool random_inputs) {
358 using SumcheckArrayOfValuesOverSubrelations = typename Relation::SumcheckArrayOfValuesOverSubrelations;
359
360 const InputElements input_elements = random_inputs ? InputElements::get_random() : InputElements::get_special();
361 const auto& w_1 = input_elements.w_l;
362 const auto& w_2 = input_elements.w_r;
363 const auto& w_3 = input_elements.w_o;
364 const auto& w_4 = input_elements.w_4;
365 const auto& w_1_shift = input_elements.w_l_shift;
366 const auto& w_2_shift = input_elements.w_r_shift;
367 const auto& w_3_shift = input_elements.w_o_shift;
368 const auto& w_4_shift = input_elements.w_4_shift;
369
370 const auto& q_2 = input_elements.q_r;
371 const auto& q_3 = input_elements.q_o;
372 const auto& q_4 = input_elements.q_4;
373 const auto& q_m = input_elements.q_m;
374 const auto& q_nnf = input_elements.q_nnf;
375
376 constexpr FF LIMB_SIZE(uint256_t(1) << 68);
377 constexpr FF SUBLIMB_SHIFT(uint256_t(1) << 14);
378 constexpr FF SUBLIMB_SHIFT_2(SUBLIMB_SHIFT * SUBLIMB_SHIFT);
379 constexpr FF SUBLIMB_SHIFT_3(SUBLIMB_SHIFT_2 * SUBLIMB_SHIFT);
380 constexpr FF SUBLIMB_SHIFT_4(SUBLIMB_SHIFT_3 * SUBLIMB_SHIFT);
381
382 SumcheckArrayOfValuesOverSubrelations expected_values;
383
384 // [(w_1 * w_2_shift) + (w_1_shift * w_2)] * LIMB_SIZE + (w_1_shift * w_2_shift) - (w_3 + w_4)
385 auto nnf_gate_1 = (w_1 * w_2_shift + w_1_shift * w_2) * LIMB_SIZE;
386 nnf_gate_1 += (w_1_shift * w_2_shift);
387 nnf_gate_1 -= (w_3 + w_4);
388
389 // [(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)
390 auto nnf_gate_2 = (w_1 * w_4 + w_2 * w_3 - w_3_shift) * LIMB_SIZE;
391 nnf_gate_2 -= w_4_shift;
392 nnf_gate_2 += w_1 * w_2_shift + w_1_shift * w_2;
393
394 // [(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)
395 auto nnf_gate_3 = (w_1 * w_2_shift + w_1_shift * w_2) * LIMB_SIZE;
396 nnf_gate_3 += (w_1_shift * w_2_shift);
397 nnf_gate_3 += w_4;
398 nnf_gate_3 -= (w_3_shift + w_4_shift);
399
400 auto limb_accumulator_1 = w_1 + w_2 * SUBLIMB_SHIFT + w_3 * SUBLIMB_SHIFT_2 + w_1_shift * SUBLIMB_SHIFT_3 +
401 w_2_shift * SUBLIMB_SHIFT_4 - w_4;
402
403 auto limb_accumulator_2 = w_3 + w_4 * SUBLIMB_SHIFT + w_1_shift * SUBLIMB_SHIFT_2 +
404 w_2_shift * SUBLIMB_SHIFT_3 + w_3_shift * SUBLIMB_SHIFT_4 - w_4_shift;
405
406 // Multiply each subidentity by its corresponding selector product
407 nnf_gate_1 *= (q_2 * q_3);
408 nnf_gate_2 *= (q_2 * q_4);
409 nnf_gate_3 *= (q_2 * q_m);
410 limb_accumulator_1 *= (q_3 * q_4);
411 limb_accumulator_2 *= (q_3 * q_m);
412
413 auto non_native_field_identity = nnf_gate_1 + nnf_gate_2 + nnf_gate_3;
414 auto limb_accumulator_identity = limb_accumulator_1 + limb_accumulator_2;
415
416 expected_values[0] = non_native_field_identity + limb_accumulator_identity;
417 expected_values[0] *= q_nnf;
418
419 const auto parameters = RelationParameters<FF>::get_random();
420
421 validate_relation_execution<Relation>(expected_values, input_elements, parameters);
422 };
423 run_test(/*random_inputs=*/false);
424 run_test(/*random_inputs=*/true);
425};
426
428{
429 const auto run_test = [](bool random_inputs) {
431 using SumcheckArrayOfValuesOverSubrelations = typename Relation::SumcheckArrayOfValuesOverSubrelations;
432
433 const InputElements input_elements = random_inputs ? InputElements::get_random() : InputElements::get_special();
434 const auto& w_1 = input_elements.w_l;
435 const auto& w_2 = input_elements.w_r;
436 const auto& w_3 = input_elements.w_o;
437 const auto& w_4 = input_elements.w_4;
438 const auto& w_1_shift = input_elements.w_l_shift;
439 const auto& w_2_shift = input_elements.w_r_shift;
440 const auto& w_3_shift = input_elements.w_o_shift;
441 const auto& w_4_shift = input_elements.w_4_shift;
442
443 const auto& q_1 = input_elements.q_l;
444 const auto& q_2 = input_elements.q_r;
445 const auto& q_3 = input_elements.q_o;
446 const auto& q_4 = input_elements.q_4;
447 const auto& q_m = input_elements.q_m;
448 const auto& q_c = input_elements.q_c;
449 const auto& q_memory = input_elements.q_memory;
450
451 const auto parameters = RelationParameters<FF>::get_random();
452 const auto& eta = parameters.eta;
453 const auto& eta_two = parameters.eta_two;
454 const auto& eta_three = parameters.eta_three;
455
456 SumcheckArrayOfValuesOverSubrelations expected_values;
457
461 auto memory_record_check = w_3 * eta_three;
462 memory_record_check += w_2 * eta_two;
463 memory_record_check += w_1 * eta;
464 memory_record_check += q_c;
465 auto partial_record_check = memory_record_check; // used in RAM consistency check
466 memory_record_check = memory_record_check - w_4;
467
471 auto index_delta = w_1_shift - w_1;
472 auto record_delta = w_4_shift - w_4;
473
474 auto index_is_monotonically_increasing = index_delta * index_delta - index_delta;
475
476 // auto adjacent_values_match_if_adjacent_indices_match = (FF(1) - index_delta) * record_delta;
477 auto adjacent_values_match_if_adjacent_indices_match = (index_delta * FF(-1) + FF(1)) * record_delta;
478
479 expected_values[1] = adjacent_values_match_if_adjacent_indices_match * (q_1 * q_2);
480 expected_values[2] = index_is_monotonically_increasing * (q_1 * q_2);
481 auto ROM_consistency_check_identity = memory_record_check * (q_1 * q_2);
482
486 auto access_type = (w_4 - partial_record_check); // will be 0 or 1 for honest Prover
487 auto access_check = access_type * access_type - access_type; // check value is 0 or 1
488
489 auto next_gate_access_type = w_3_shift * eta_three;
490 next_gate_access_type += w_2_shift * eta_two;
491 next_gate_access_type += w_1_shift * eta;
492 next_gate_access_type = w_4_shift - next_gate_access_type;
493
494 auto value_delta = w_3_shift - w_3;
495 auto adjacent_values_match_if_adjacent_indices_match_and_next_access_is_a_read_operation =
496 (index_delta * FF(-1) + FF(1)) * value_delta * (next_gate_access_type * FF(-1) + FF(1));
497
498 // We can't apply the RAM consistency check identity on the final entry in the sorted list (the wires in the
499 // next gate would make the identity fail). We need to validate that its 'access type' bool is correct. Can't do
500 // with an arithmetic gate because of the `eta` factors. We need to check that the *next* gate's access type is
501 // correct, to cover this edge case
502 auto next_gate_access_type_is_boolean = next_gate_access_type * next_gate_access_type - next_gate_access_type;
503
504 // Putting it all together...
505 expected_values[3] =
506 adjacent_values_match_if_adjacent_indices_match_and_next_access_is_a_read_operation * (q_3);
507 expected_values[4] = index_is_monotonically_increasing * (q_3);
508 expected_values[5] = next_gate_access_type_is_boolean * (q_3);
509 auto RAM_consistency_check_identity = access_check * (q_3);
510
514 memory_record_check *= (q_1 * q_m);
515
519 auto timestamp_delta = w_2_shift - w_2;
520 auto RAM_timestamp_check_identity = (index_delta * FF(-1) + FF(1)) * timestamp_delta - w_3;
521 RAM_timestamp_check_identity *= (q_1 * q_4);
522
526 auto memory_identity = ROM_consistency_check_identity;
527 memory_identity += RAM_timestamp_check_identity;
528 memory_identity += memory_record_check;
529 memory_identity += RAM_consistency_check_identity;
530
531 expected_values[0] = memory_identity;
532 expected_values[0] *= q_memory;
533 expected_values[1] *= q_memory;
534 expected_values[2] *= q_memory;
535 expected_values[3] *= q_memory;
536 expected_values[4] *= q_memory;
537 expected_values[5] *= q_memory;
538
539 validate_relation_execution<Relation>(expected_values, input_elements, parameters);
540 };
541 run_test(/*random_inputs=*/false);
542 run_test(/*random_inputs=*/true);
543};
544
546{
547 const auto run_test = []([[maybe_unused]] bool random_inputs) {
549 using SumcheckArrayOfValuesOverSubrelations = typename Relation::SumcheckArrayOfValuesOverSubrelations;
550 const InputElements input_elements = random_inputs ? InputElements::get_random() : InputElements::get_special();
551
552 const auto& w_1 = input_elements.w_l;
553 const auto& w_2 = input_elements.w_r;
554 const auto& w_3 = input_elements.w_o;
555 const auto& w_4 = input_elements.w_4;
556 const auto& w_1_shift = input_elements.w_l_shift;
557 const auto& w_2_shift = input_elements.w_r_shift;
558 const auto& w_3_shift = input_elements.w_o_shift;
559 const auto& w_4_shift = input_elements.w_4_shift;
560 const auto& q_1 = input_elements.q_l;
561 const auto& q_2 = input_elements.q_r;
562 const auto& q_3 = input_elements.q_o;
563 const auto& q_4 = input_elements.q_4;
564 const auto& q_poseidon2_external = input_elements.q_poseidon2_external;
565 SumcheckArrayOfValuesOverSubrelations expected_values;
566
567 // add round constants
568 auto s1 = w_1 + q_1;
569 auto s2 = w_2 + q_2;
570 auto s3 = w_3 + q_3;
571 auto s4 = w_4 + q_4;
572
573 // apply s-box round
574 auto u1 = s1 * s1;
575 u1 *= u1;
576 u1 *= s1;
577 auto u2 = s2 * s2;
578 u2 *= u2;
579 u2 *= s2;
580 auto u3 = s3 * s3;
581 u3 *= u3;
582 u3 *= s3;
583 auto u4 = s4 * s4;
584 u4 *= u4;
585 u4 *= s4;
586
587 // matrix mul v = M_E * u with 14 additions
588 auto t0 = u1 + u2; // u_1 + u_2
589 auto t1 = u3 + u4; // u_3 + u_4
590 auto t2 = u2 + u2; // 2u_2
591 t2 += t1; // 2u_2 + u_3 + u_4
592 auto t3 = u4 + u4; // 2u_4
593 t3 += t0; // u_1 + u_2 + 2u_4
594 auto v4 = t1 + t1;
595 v4 += v4;
596 v4 += t3; // u_1 + u_2 + 4u_3 + 6u_4
597 auto v2 = t0 + t0;
598 v2 += v2;
599 v2 += t2; // 4u_1 + 6u_2 + u_3 + u_4
600 auto v1 = t3 + v2; // 5u_1 + 7u_2 + u_3 + 3u_4
601 auto v3 = t2 + v4; // u_1 + 3u_2 + 5u_3 + 7u_4
602
603 // output is { v1, v2, v3, v4 }
604
605 expected_values[0] = q_poseidon2_external * (v1 - w_1_shift);
606 expected_values[1] = q_poseidon2_external * (v2 - w_2_shift);
607 expected_values[2] = q_poseidon2_external * (v3 - w_3_shift);
608 expected_values[3] = q_poseidon2_external * (v4 - w_4_shift);
609
610 const auto parameters = RelationParameters<FF>::get_random();
611 validate_relation_execution<Relation>(expected_values, input_elements, parameters);
612
613 // validate_relation_execution<Relation>(expected_values, input_elements, parameters);
614 };
615 run_test(/*random_inputs=*/false);
616 run_test(/*random_inputs=*/true);
617};
618
620{
621 const auto run_test = []([[maybe_unused]] bool random_inputs) {
623 using SumcheckArrayOfValuesOverSubrelations = typename Relation::SumcheckArrayOfValuesOverSubrelations;
624 const InputElements input_elements = random_inputs ? InputElements::get_random() : InputElements::get_special();
625
626 const auto& w_1 = input_elements.w_l;
627 const auto& w_2 = input_elements.w_r;
628 const auto& w_3 = input_elements.w_o;
629 const auto& w_4 = input_elements.w_4;
630 const auto& w_1_shift = input_elements.w_l_shift;
631 const auto& w_2_shift = input_elements.w_r_shift;
632 const auto& w_3_shift = input_elements.w_o_shift;
633 const auto& w_4_shift = input_elements.w_4_shift;
634 const auto& q_1 = input_elements.q_l;
635 const auto& q_poseidon2_internal = input_elements.q_poseidon2_internal;
636 SumcheckArrayOfValuesOverSubrelations expected_values;
637
638 // add round constants on only first element
639 auto v1 = w_1 + q_1;
640
641 // apply s-box to only first element
642 auto u1 = v1 * v1;
643 u1 *= u1;
644 u1 *= v1;
645
646 // multiply with internal matrix
647 // Uses D_i - 1 values: result[i] = (D_i - 1) * x[i] + sum = D_i * x[i] + (sum of other elements)
648 auto sum = u1 + w_2 + w_3 + w_4;
650 t0 += sum;
652 t1 += sum;
654 t2 += sum;
656 t3 += sum;
657
658 expected_values[0] = q_poseidon2_internal * (t0 - w_1_shift);
659 expected_values[1] = q_poseidon2_internal * (t1 - w_2_shift);
660 expected_values[2] = q_poseidon2_internal * (t2 - w_3_shift);
661 expected_values[3] = q_poseidon2_internal * (t3 - w_4_shift);
662
663 const auto parameters = RelationParameters<FF>::get_random();
664 validate_relation_execution<Relation>(expected_values, input_elements, parameters);
665
666 // validate_relation_execution<Relation>(expected_values, input_elements, parameters);
667 };
668 run_test(/*random_inputs=*/false);
669 run_test(/*random_inputs=*/true);
670};
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:155
field< Bn254FrParams > fr
Definition fr.hpp:155
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_minus_one
constexpr field invert() const noexcept
static field random_element(numeric::RNG *engine=nullptr) noexcept