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
26#include <gtest/gtest.h>
27
28using namespace bb;
29
30using FF = fr;
31
32// Test inputs: the generator-emitted AllEntities<FF> for UltraFlavor — std::array<FF,
33// NUM_ALL_ENTITIES> storage with EntityId-keyed access and named-method accessors. Replaces a
34// hand-written 45-tuple mock that pre-dated the logderiv-lookup arithmetisation.
36
37static InputElements get_random_inputs()
38{
40 for (FF& slot : result.data) {
42 }
43 return result;
44}
45
46static InputElements get_special_inputs() // use non-random values: data[i] = i + 1
47{
49 FF idx = 0;
50 for (FF& slot : result.data) {
51 idx += FF(1);
52 slot = idx;
53 }
54 return result;
55}
56
57class UltraRelationConsistency : public testing::Test {
58 public:
59 template <typename Relation>
61 const typename Relation::SumcheckArrayOfValuesOverSubrelations& expected_values,
62 const InputElements& input_elements,
63 const auto& parameters)
64 {
66 std::fill(accumulator.begin(), accumulator.end(), FF(0));
67 Relation::accumulate(accumulator, input_elements, parameters, 1);
68 EXPECT_EQ(accumulator, expected_values);
69 };
70};
71
73{
74 const auto run_test = [](bool random_inputs, const FF& q_arith_value = FF::random_element()) {
76 using SumcheckArrayOfValuesOverSubrelations = typename Relation::SumcheckArrayOfValuesOverSubrelations;
77
78 InputElements input_elements = random_inputs ? get_random_inputs() : get_special_inputs();
79 const auto& w_1 = input_elements.w_l();
80 const auto& w_1_shift = input_elements.w_l_shift();
81 const auto& w_2 = input_elements.w_r();
82 const auto& w_3 = input_elements.w_o();
83 const auto& w_4 = input_elements.w_4();
84 const auto& w_4_shift = input_elements.w_4_shift();
85 const auto& q_m = input_elements.q_m();
86 const auto& q_l = input_elements.q_l();
87 const auto& q_r = input_elements.q_r();
88 const auto& q_o = input_elements.q_o();
89 const auto& q_4 = input_elements.q_4();
90 const auto& q_c = input_elements.q_c();
91
92 // Set specific q_arith value to enable testing different modes of the arithmetic relation
93 input_elements[InputElements::EntityId::q_arith] = q_arith_value;
94 const auto& q_arith = input_elements.q_arith();
95
96 SumcheckArrayOfValuesOverSubrelations expected_values;
97 static const FF neg_half = FF(-2).invert();
98
99 FF contribution_1 = FF(0);
100 FF contribution_2 = FF(0);
101 if (q_arith == FF(1)) {
102 // Contribution 1
103 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;
104
105 // Contribution 2: None
106 } else if (q_arith == FF(2)) {
107 // Contribution 1
108 contribution_1 = (q_m * w_2 * w_1);
109 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);
110
111 // Contribution 2: None
112 } else if (q_arith == FF(3)) {
113 // Contribution 1
114 contribution_1 = (q_l * w_1) + (q_r * w_2) + (q_o * w_3) + (q_4 * w_4) + q_c;
115 contribution_1 += w_4_shift * FF(2);
116 contribution_1 *= FF(3);
117
118 // Contribution 2
119 contribution_2 = (w_1 + w_4 - w_1_shift + q_m) * FF(6);
120 } else {
121 // Contribution 1
122 contribution_1 = (q_arith - 3) * (q_m * w_2 * w_1) * neg_half;
123 contribution_1 += (q_l * w_1) + (q_r * w_2) + (q_o * w_3) + (q_4 * w_4) + q_c;
124 contribution_1 += (q_arith - 1) * w_4_shift;
125 contribution_1 *= q_arith;
126
127 // Contribution 2
128 contribution_2 = (w_1 + w_4 - w_1_shift + q_m);
129 contribution_2 *= (q_arith - 2) * (q_arith - 1) * q_arith;
130 }
131
132 expected_values[0] = contribution_1;
133 expected_values[1] = contribution_2;
134
135 const auto parameters = RelationParameters<FF>::get_random();
136
137 validate_relation_execution<Relation>(expected_values, input_elements, parameters);
138 };
139 run_test(/*random_inputs=*/false);
140 run_test(/*random_inputs=*/true);
141 run_test(/*random_inputs=*/true, /*q_arith_value=*/FF(1));
142 run_test(/*random_inputs=*/true, /*q_arith_value=*/FF(2));
143 run_test(/*random_inputs=*/true, /*q_arith_value=*/FF(3));
144};
145
147{
148 const auto run_test = [](bool random_inputs) {
150 using SumcheckArrayOfValuesOverSubrelations = typename Relation::SumcheckArrayOfValuesOverSubrelations;
151
152 const InputElements input_elements = random_inputs ? get_random_inputs() : get_special_inputs();
153 const auto& w_1 = input_elements.w_l();
154 const auto& w_2 = input_elements.w_r();
155 const auto& w_3 = input_elements.w_o();
156 const auto& w_4 = input_elements.w_4();
157 const auto& sigma_1 = input_elements.sigma_1();
158 const auto& sigma_2 = input_elements.sigma_2();
159 const auto& sigma_3 = input_elements.sigma_3();
160 const auto& sigma_4 = input_elements.sigma_4();
161 const auto& id_1 = input_elements.id_1();
162 const auto& id_2 = input_elements.id_2();
163 const auto& id_3 = input_elements.id_3();
164 const auto& id_4 = input_elements.id_4();
165 const auto& z_perm = input_elements.z_perm();
166 const auto& z_perm_shift = input_elements.z_perm_shift();
167 const auto& lagrange_first = input_elements.lagrange_first();
168 const auto& lagrange_last = input_elements.lagrange_last();
169
170 SumcheckArrayOfValuesOverSubrelations expected_values;
171
172 const auto parameters = RelationParameters<FF>::get_random();
173 const auto& beta = parameters.beta;
174 const auto& gamma = parameters.gamma;
175 const auto& public_input_delta = parameters.public_input_delta;
176
177 // Contribution 1
178 auto contribution_1 = (z_perm + lagrange_first) * (w_1 + id_1 * beta + gamma) * (w_2 + id_2 * beta + gamma) *
179 (w_3 + id_3 * beta + gamma) * (w_4 + id_4 * beta + gamma) -
180 (z_perm_shift + lagrange_last * public_input_delta) * (w_1 + sigma_1 * beta + gamma) *
181 (w_2 + sigma_2 * beta + gamma) * (w_3 + sigma_3 * beta + gamma) *
182 (w_4 + sigma_4 * beta + gamma);
183 expected_values[0] = contribution_1;
184
185 // Contribution 2
186 auto contribution_2 = z_perm_shift * lagrange_last;
187 expected_values[1] = contribution_2;
188
189 // Contribution 3
190 auto contribution_3 = lagrange_first * z_perm;
191 expected_values[2] = contribution_3;
192
193 validate_relation_execution<Relation>(expected_values, input_elements, parameters);
194 };
195 run_test(/*random_inputs=*/false);
196 run_test(/*random_inputs=*/true);
197};
198
200{
201 const auto run_test = [](bool random_inputs) {
203 using SumcheckArrayOfValuesOverSubrelations = typename Relation::SumcheckArrayOfValuesOverSubrelations;
204
205 const InputElements input_elements = random_inputs ? get_random_inputs() : get_special_inputs();
206 const auto& w_1 = input_elements.w_l();
207 const auto& w_2 = input_elements.w_r();
208 const auto& w_3 = input_elements.w_o();
209 const auto& w_4 = input_elements.w_4();
210 const auto& w_1_shift = input_elements.w_l_shift();
211 const auto& q_delta_range = input_elements.q_delta_range();
212
213 auto delta_1 = w_2 - w_1;
214 auto delta_2 = w_3 - w_2;
215 auto delta_3 = w_4 - w_3;
216 auto delta_4 = w_1_shift - w_4;
217
218 auto contribution_1 = delta_1 * (delta_1 - 1) * (delta_1 - 2) * (delta_1 - 3);
219 auto contribution_2 = delta_2 * (delta_2 - 1) * (delta_2 - 2) * (delta_2 - 3);
220 auto contribution_3 = delta_3 * (delta_3 - 1) * (delta_3 - 2) * (delta_3 - 3);
221 auto contribution_4 = delta_4 * (delta_4 - 1) * (delta_4 - 2) * (delta_4 - 3);
222
223 SumcheckArrayOfValuesOverSubrelations expected_values;
224
225 expected_values[0] = contribution_1 * q_delta_range;
226 expected_values[1] = contribution_2 * q_delta_range;
227 expected_values[2] = contribution_3 * q_delta_range;
228 expected_values[3] = contribution_4 * q_delta_range;
229
230 const auto parameters = RelationParameters<FF>::get_random();
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 // Non-const: the test writes `q_l = -1` below to set q_sign explicitly.
245 InputElements input_elements = random_inputs ? get_random_inputs() : get_special_inputs();
246
247 const auto& x_1 = input_elements.w_r();
248 const auto& y_1 = input_elements.w_o();
249
250 const auto& x_2 = input_elements.w_l_shift();
251 const auto& y_2 = input_elements.w_4_shift();
252 const auto& x_3 = input_elements.w_r_shift();
253 const auto& y_3 = input_elements.w_o_shift();
254
255 // In the EllipticRelation, q_l is interpreted as q_sign and can be +1 or -1. Here we explicitly set it to -1
256 // (arbitrary, could also be +1) because the relation algebra makes use of the assumption that q_sign^2 = 1.
257 // This allows writing the simplified constraint algebra in this test in a more straightforward way.
258 input_elements[InputElements::EntityId::q_l] = FF(-1);
259 const auto& q_sign = input_elements.q_l();
260 const auto& q_elliptic = input_elements.q_elliptic();
261 const auto& q_is_double = input_elements.q_m();
262
263 SumcheckArrayOfValuesOverSubrelations expected_values;
264 // Compute x/y coordinate identities
265 {
266 auto y_diff = (q_sign * y_2 - y_1);
267 auto x_diff = (x_2 - x_1);
268 auto x_diff_sqr = x_diff * x_diff;
269 auto lambda = y_diff / x_diff;
270 auto lambda_sqr = lambda * lambda;
271
272 // Contribution (1) point addition, x-coordinate check
273 // Formula: x3 = lambda^2 - (x1 + x2)
274 // lambda = (y2 - y1) / (x2 - x1)
275 // Constraint: (x3 - lambda^2 + (x1 + x2)) * (x2 - x1)^2 = 0
276 auto x_add_identity = (x_3 - lambda_sqr + (x_1 + x_2)) * x_diff_sqr;
277
278 // Contribution (2) point addition, y-coordinate check
279 // Formula: y3 = lambda * (x1 - x3) - y1
280 // Constraint: (y3 - lambda * (x1 - x3) + y1) * (x2 - x1) = 0
281 auto y_add_identity = (y_3 - lambda * (x_1 - x_3) + y_1) * x_diff;
282
283 // N.B. the relation uses the equivalence x1^3 === y1^2 - curve_b to reduce degree by 1 so we must do the
284 // same here
285 const auto curve_b = EllipticRelationImpl<FF>::get_curve_b();
286 auto y1_sqr = (y_1 * y_1);
287 auto x_pow_4 = (y1_sqr - curve_b) * x_1; // curve equation substitution
288 lambda_sqr = x_pow_4 * 9 / (y1_sqr * 4);
289 lambda = (x_1 * x_1 * 3) / (y_1 * 2);
290
291 // Contribution (3) point doubling, x-coordinate check
292 // Formula: x3 = lambda^2 - 2*x1
293 // lambda = (3*x1 * x1) / (2*y1)
294 // Constraint: (x3 - lambda^2 + 2*x1) * (2*y1) = 0
295 auto x_double_identity = (x_3 - lambda_sqr + x_1 * 2) * (y1_sqr * 4);
296
297 // Contribution (4) point doubling, y-coordinate check
298 // Formula: y3 = lambda * (x1 - x3) - y1
299 // Constraint: (y3 - lambda * (x1 - x3) + y1) * (2*y1) * FF(-1) = 0
300 // N.B. multiply by -1 to match form used for efficient accumulation in relation
301 auto y_double_identity = (y_3 - lambda * (x_1 - x_3) + y_1) * (y_1 * 2) * FF(-1);
302
303 // Combine addition and doubling subidentities, each scaled by q_is_double
304 expected_values[0] = (x_add_identity * (-q_is_double + 1) + (x_double_identity * q_is_double)) * q_elliptic;
305 expected_values[1] = (y_add_identity * (-q_is_double + 1) + (y_double_identity * q_is_double)) * q_elliptic;
306 }
307
308 const auto parameters = RelationParameters<FF>::get_random();
309
310 validate_relation_execution<Relation>(expected_values, input_elements, parameters);
311 };
312 run_test(/*random_inputs=*/false);
313 run_test(/*random_inputs=*/true);
314};
315
317{
318 const auto run_test = [](bool random_inputs) {
320 using SumcheckArrayOfValuesOverSubrelations = typename Relation::SumcheckArrayOfValuesOverSubrelations;
321
322 const InputElements input_elements = random_inputs ? get_random_inputs() : get_special_inputs();
323 const auto& w_1 = input_elements.w_l();
324 const auto& w_2 = input_elements.w_r();
325 const auto& w_3 = input_elements.w_o();
326 const auto& w_4 = input_elements.w_4();
327 const auto& w_1_shift = input_elements.w_l_shift();
328 const auto& w_2_shift = input_elements.w_r_shift();
329 const auto& w_3_shift = input_elements.w_o_shift();
330 const auto& w_4_shift = input_elements.w_4_shift();
331
332 const auto& q_2 = input_elements.q_r();
333 const auto& q_3 = input_elements.q_o();
334 const auto& q_4 = input_elements.q_4();
335 const auto& q_m = input_elements.q_m();
336 const auto& q_nnf = input_elements.q_nnf();
337
338 constexpr FF LIMB_SIZE(uint256_t(1) << 68);
339 constexpr FF SUBLIMB_SHIFT(uint256_t(1) << 14);
340 constexpr FF SUBLIMB_SHIFT_2(SUBLIMB_SHIFT * SUBLIMB_SHIFT);
341 constexpr FF SUBLIMB_SHIFT_3(SUBLIMB_SHIFT_2 * SUBLIMB_SHIFT);
342 constexpr FF SUBLIMB_SHIFT_4(SUBLIMB_SHIFT_3 * SUBLIMB_SHIFT);
343
344 SumcheckArrayOfValuesOverSubrelations expected_values;
345
346 // [(w_1 * w_2_shift) + (w_1_shift * w_2)] * LIMB_SIZE + (w_1_shift * w_2_shift) - (w_3 + w_4)
347 auto nnf_gate_1 = (w_1 * w_2_shift + w_1_shift * w_2) * LIMB_SIZE;
348 nnf_gate_1 += (w_1_shift * w_2_shift);
349 nnf_gate_1 -= (w_3 + w_4);
350
351 // [(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)
352 auto nnf_gate_2 = (w_1 * w_4 + w_2 * w_3 - w_3_shift) * LIMB_SIZE;
353 nnf_gate_2 -= w_4_shift;
354 nnf_gate_2 += w_1 * w_2_shift + w_1_shift * w_2;
355
356 // [(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)
357 auto nnf_gate_3 = (w_1 * w_2_shift + w_1_shift * w_2) * LIMB_SIZE;
358 nnf_gate_3 += (w_1_shift * w_2_shift);
359 nnf_gate_3 += w_4;
360 nnf_gate_3 -= (w_3_shift + w_4_shift);
361
362 auto limb_accumulator_1 = w_1 + w_2 * SUBLIMB_SHIFT + w_3 * SUBLIMB_SHIFT_2 + w_1_shift * SUBLIMB_SHIFT_3 +
363 w_2_shift * SUBLIMB_SHIFT_4 - w_4;
364
365 auto limb_accumulator_2 = w_3 + w_4 * SUBLIMB_SHIFT + w_1_shift * SUBLIMB_SHIFT_2 +
366 w_2_shift * SUBLIMB_SHIFT_3 + w_3_shift * SUBLIMB_SHIFT_4 - w_4_shift;
367
368 // Multiply each subidentity by its corresponding selector product
369 nnf_gate_1 *= (q_2 * q_3);
370 nnf_gate_2 *= (q_2 * q_4);
371 nnf_gate_3 *= (q_2 * q_m);
372 limb_accumulator_1 *= (q_3 * q_4);
373 limb_accumulator_2 *= (q_3 * q_m);
374
375 auto non_native_field_identity = nnf_gate_1 + nnf_gate_2 + nnf_gate_3;
376 auto limb_accumulator_identity = limb_accumulator_1 + limb_accumulator_2;
377
378 expected_values[0] = non_native_field_identity + limb_accumulator_identity;
379 expected_values[0] *= q_nnf;
380
381 const auto parameters = RelationParameters<FF>::get_random();
382
383 validate_relation_execution<Relation>(expected_values, input_elements, parameters);
384 };
385 run_test(/*random_inputs=*/false);
386 run_test(/*random_inputs=*/true);
387};
388
390{
391 const auto run_test = [](bool random_inputs) {
393 using SumcheckArrayOfValuesOverSubrelations = typename Relation::SumcheckArrayOfValuesOverSubrelations;
394
395 const InputElements input_elements = random_inputs ? get_random_inputs() : get_special_inputs();
396 const auto& w_1 = input_elements.w_l();
397 const auto& w_2 = input_elements.w_r();
398 const auto& w_3 = input_elements.w_o();
399 const auto& w_4 = input_elements.w_4();
400 const auto& w_1_shift = input_elements.w_l_shift();
401 const auto& w_2_shift = input_elements.w_r_shift();
402 const auto& w_3_shift = input_elements.w_o_shift();
403 const auto& w_4_shift = input_elements.w_4_shift();
404
405 const auto& q_1 = input_elements.q_l();
406 const auto& q_2 = input_elements.q_r();
407 const auto& q_3 = input_elements.q_o();
408 const auto& q_4 = input_elements.q_4();
409 const auto& q_m = input_elements.q_m();
410 const auto& q_c = input_elements.q_c();
411 const auto& q_memory = input_elements.q_memory();
412
413 const auto parameters = RelationParameters<FF>::get_random();
414 const auto& eta = parameters.eta;
415 const auto& eta_two = parameters.eta_two;
416 const auto& eta_three = parameters.eta_three;
417 const auto& rom_logup_gamma = parameters.rom_logup_gamma;
418
419 SumcheckArrayOfValuesOverSubrelations expected_values;
420
424 auto memory_record_check = w_3 * eta_three;
425 memory_record_check += w_2 * eta_two;
426 memory_record_check += w_1 * eta;
427 memory_record_check += q_c;
428 auto partial_record_check = memory_record_check; // used in RAM consistency check
429 memory_record_check = memory_record_check - w_4;
430
434 auto index_delta = w_1_shift - w_1;
435 auto record_delta = w_4_shift - w_4;
436
437 auto index_is_monotonically_increasing = index_delta * index_delta - index_delta;
438
439 // auto adjacent_values_match_if_adjacent_indices_match = (FF(1) - index_delta) * record_delta;
440 auto adjacent_values_match_if_adjacent_indices_match = (index_delta * FF(-1) + FF(1)) * record_delta;
441
442 expected_values[1] = adjacent_values_match_if_adjacent_indices_match * (q_1 * q_2);
443 expected_values[2] = index_is_monotonically_increasing * (q_1 * q_2);
444 auto ROM_consistency_check_identity = memory_record_check * (q_1 * q_2);
445
449 auto access_type = (w_4 - partial_record_check); // will be 0 or 1 for honest Prover
450 auto access_check = access_type * access_type - access_type; // check value is 0 or 1
451
452 auto next_gate_access_type = w_3_shift * eta_three;
453 next_gate_access_type += w_2_shift * eta_two;
454 next_gate_access_type += w_1_shift * eta;
455 next_gate_access_type = w_4_shift - next_gate_access_type;
456
457 auto value_delta = w_3_shift - w_3;
458 auto adjacent_values_match_if_adjacent_indices_match_and_next_access_is_a_read_operation =
459 (index_delta * FF(-1) + FF(1)) * value_delta * (next_gate_access_type * FF(-1) + FF(1));
460
461 // We can't apply the RAM consistency check identity on the final entry in the sorted list (the wires in the
462 // next gate would make the identity fail). We need to validate that its 'access type' bool is correct. Can't do
463 // with an arithmetic gate because of the `eta` factors. We need to check that the *next* gate's access type is
464 // correct, to cover this edge case
465 auto next_gate_access_type_is_boolean = next_gate_access_type * next_gate_access_type - next_gate_access_type;
466
467 // Putting it all together...
468 expected_values[3] =
469 adjacent_values_match_if_adjacent_indices_match_and_next_access_is_a_read_operation * (q_3);
470 expected_values[4] = index_is_monotonically_increasing * (q_3);
471 expected_values[5] = next_gate_access_type_is_boolean * (q_3);
472 auto RAM_consistency_check_identity = access_check * (q_3);
473
477 memory_record_check *= (q_1 * q_m);
478
482 auto timestamp_delta = w_2_shift - w_2;
483 auto RAM_timestamp_check_identity = (index_delta * FF(-1) + FF(1)) * timestamp_delta - w_3;
484 RAM_timestamp_check_identity *= (q_1 * q_4);
485
489 auto memory_identity = ROM_consistency_check_identity;
490 memory_identity += RAM_timestamp_check_identity;
491 memory_identity += memory_record_check;
492 memory_identity += RAM_consistency_check_identity;
493
494 expected_values[0] = memory_identity;
495 expected_values[0] *= q_memory;
496 expected_values[1] *= q_memory;
497 expected_values[2] *= q_memory;
498 expected_values[3] *= q_memory;
499 expected_values[4] *= q_memory;
500 expected_values[5] *= q_memory;
501
505 auto q_logup_table = q_2 * (q_1 * FF(-1) + FF(1));
506 auto q_logup_read = q_4 * (q_1 * FF(-1) + FF(1));
507 auto denom = rom_logup_gamma + w_1 + w_2 * eta + q_c * eta_two;
508 // Subrelation 6: inverse correctness (per-row).
509 expected_values[6] = q_memory * (q_logup_table + q_logup_read) * (w_4 * denom - FF(1));
510 // Subrelation 7: LogUp sum (linearly dependent, no scaling factor).
511 expected_values[7] = q_memory * (q_logup_read - q_logup_table * w_3) * w_4;
512
513 validate_relation_execution<Relation>(expected_values, input_elements, parameters);
514 };
515 run_test(/*random_inputs=*/false);
516 run_test(/*random_inputs=*/true);
517};
518
520{
521 const auto run_test = []([[maybe_unused]] bool random_inputs) {
523 using SumcheckArrayOfValuesOverSubrelations = typename Relation::SumcheckArrayOfValuesOverSubrelations;
524 const InputElements input_elements = random_inputs ? get_random_inputs() : get_special_inputs();
525
526 const auto& w_1 = input_elements.w_l();
527 const auto& w_2 = input_elements.w_r();
528 const auto& w_3 = input_elements.w_o();
529 const auto& w_4 = input_elements.w_4();
530 const auto& w_1_shift = input_elements.w_l_shift();
531 const auto& w_2_shift = input_elements.w_r_shift();
532 const auto& w_3_shift = input_elements.w_o_shift();
533 const auto& w_4_shift = input_elements.w_4_shift();
534 const auto& q_1 = input_elements.q_l();
535 const auto& q_2 = input_elements.q_r();
536 const auto& q_3 = input_elements.q_o();
537 const auto& q_4 = input_elements.q_4();
538 const auto& q_poseidon2_external = input_elements.q_poseidon2_external();
539 SumcheckArrayOfValuesOverSubrelations expected_values;
540
541 // add round constants
542 auto s1 = w_1 + q_1;
543 auto s2 = w_2 + q_2;
544 auto s3 = w_3 + q_3;
545 auto s4 = w_4 + q_4;
546
547 // apply s-box round
548 auto u1 = s1 * s1;
549 u1 *= u1;
550 u1 *= s1;
551 auto u2 = s2 * s2;
552 u2 *= u2;
553 u2 *= s2;
554 auto u3 = s3 * s3;
555 u3 *= u3;
556 u3 *= s3;
557 auto u4 = s4 * s4;
558 u4 *= u4;
559 u4 *= s4;
560
561 // matrix mul v = M_E * u with 14 additions
562 auto t0 = u1 + u2; // u_1 + u_2
563 auto t1 = u3 + u4; // u_3 + u_4
564 auto t2 = u2 + u2; // 2u_2
565 t2 += t1; // 2u_2 + u_3 + u_4
566 auto t3 = u4 + u4; // 2u_4
567 t3 += t0; // u_1 + u_2 + 2u_4
568 auto v4 = t1 + t1;
569 v4 += v4;
570 v4 += t3; // u_1 + u_2 + 4u_3 + 6u_4
571 auto v2 = t0 + t0;
572 v2 += v2;
573 v2 += t2; // 4u_1 + 6u_2 + u_3 + u_4
574 auto v1 = t3 + v2; // 5u_1 + 7u_2 + u_3 + 3u_4
575 auto v3 = t2 + v4; // u_1 + 3u_2 + 5u_3 + 7u_4
576
577 // output is { v1, v2, v3, v4 }
578
579 expected_values[0] = q_poseidon2_external * (v1 - w_1_shift);
580 expected_values[1] = q_poseidon2_external * (v2 - w_2_shift);
581 expected_values[2] = q_poseidon2_external * (v3 - w_3_shift);
582 expected_values[3] = q_poseidon2_external * (v4 - w_4_shift);
583
584 const auto parameters = RelationParameters<FF>::get_random();
585 validate_relation_execution<Relation>(expected_values, input_elements, parameters);
586
587 // validate_relation_execution<Relation>(expected_values, input_elements, parameters);
588 };
589 run_test(/*random_inputs=*/false);
590 run_test(/*random_inputs=*/true);
591};
592
594{
595 const auto run_test = []([[maybe_unused]] bool random_inputs) {
597 using SumcheckArrayOfValuesOverSubrelations = typename Relation::SumcheckArrayOfValuesOverSubrelations;
598 const InputElements input_elements = random_inputs ? get_random_inputs() : get_special_inputs();
599
600 const auto& w_1 = input_elements.w_l();
601 const auto& w_2 = input_elements.w_r();
602 const auto& w_3 = input_elements.w_o();
603 const auto& w_4 = input_elements.w_4();
604 const auto& w_1_shift = input_elements.w_l_shift();
605 const auto& w_2_shift = input_elements.w_r_shift();
606 const auto& w_3_shift = input_elements.w_o_shift();
607 const auto& w_4_shift = input_elements.w_4_shift();
608 const auto& q_1 = input_elements.q_l();
609 const auto& q_poseidon2_internal = input_elements.q_poseidon2_internal();
610 SumcheckArrayOfValuesOverSubrelations expected_values;
611
612 // add round constants on only first element
613 auto v1 = w_1 + q_1;
614
615 // apply s-box to only first element
616 auto u1 = v1 * v1;
617 u1 *= u1;
618 u1 *= v1;
619
620 // multiply with internal matrix
621 // Uses D_i - 1 values: result[i] = (D_i - 1) * x[i] + sum = D_i * x[i] + (sum of other elements)
622 auto sum = u1 + w_2 + w_3 + w_4;
624 t0 += sum;
626 t1 += sum;
628 t2 += sum;
630 t3 += sum;
631
632 expected_values[0] = q_poseidon2_internal * (t0 - w_1_shift);
633 expected_values[1] = q_poseidon2_internal * (t1 - w_2_shift);
634 expected_values[2] = q_poseidon2_internal * (t2 - w_3_shift);
635 expected_values[3] = q_poseidon2_internal * (t3 - w_4_shift);
636
637 const auto parameters = RelationParameters<FF>::get_random();
638 validate_relation_execution<Relation>(expected_values, input_elements, parameters);
639
640 // validate_relation_execution<Relation>(expected_values, input_elements, parameters);
641 };
642 run_test(/*random_inputs=*/false);
643 run_test(/*random_inputs=*/true);
644};
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:160
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
std::byte * data
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
UltraFlavor_Generated::AllEntities< FF > InputElements
VectorField result