Barretenberg
The ZK-SNARK library at the core of Aztec
Loading...
Searching...
No Matches
relation_failure.test.cpp
Go to the documentation of this file.
1
41#include <gtest/gtest.h>
42
43using namespace bb;
44
45namespace {
46
48using FF = typename Flavor::FF;
50
54struct ValidTranslatorState {
57};
58
66ValidTranslatorState build_valid_translator_state()
67{
68 const size_t full_circuit_size = Flavor::MINI_CIRCUIT_SIZE * Flavor::CONCATENATION_GROUP_SIZE;
70
73 ProverPolynomials& pp = key.proving_key->polynomials;
74
75 // Fill group wire polynomials with random 14-bit values in circuit region, random FF in masking rows
76 for (const auto& group : pp.get_groups_to_be_concatenated()) {
77 for (auto& poly : group) {
78 if (poly.is_empty()) {
79 continue;
80 }
81 for (size_t i = poly.start_index(); i < poly.end_index() - NUM_DISABLED_ROWS_IN_SUMCHECK; i++) {
82 poly.at(i) = engine.get_random_uint16() & ((1 << Flavor::MICRO_LIMB_BITS) - 1);
83 }
84 for (size_t i = poly.end_index() - NUM_DISABLED_ROWS_IN_SUMCHECK; i < poly.end_index(); i++) {
85 poly.at(i) = FF::random_element();
86 }
87 }
88 }
89
90 // Reallocate lagrange polynomials to full circuit size and compute them
91 pp.lagrange_first = typename Flavor::Polynomial(full_circuit_size);
92 pp.lagrange_last = typename Flavor::Polynomial(full_circuit_size);
93 pp.lagrange_real_last = typename Flavor::Polynomial(full_circuit_size);
94 pp.lagrange_masking = typename Flavor::Polynomial(full_circuit_size);
95
96 key.compute_lagrange_polynomials();
97 key.compute_extra_range_constraint_numerator();
98 key.compute_concatenated_polynomials();
99 key.compute_translator_range_constraint_ordered_polynomials();
100
101 // Compute grand product
103 compute_grand_product<Flavor, TranslatorPermutationRelation<FF>>(pp, params);
104
105 return { std::move(key), params };
106}
107
116ValidTranslatorState build_valid_accumulator_transfer_state()
117{
118 using BF = typename Flavor::BF;
119 using GroupElement = typename Flavor::GroupElement;
120
122
123 auto op_queue = std::make_shared<ECCOpQueue>();
124
125 // Add a no-op, then random start ops, then mixed ops, merge, more mixed ops, random end ops, final merge
126 op_queue->no_op_ultra_only();
127 for (size_t i = 0; i < Flavor::CircuitBuilder::NUM_RANDOM_OPS_START; i++) {
128 op_queue->random_op_ultra_only();
129 }
130 for (size_t i = 0; i < 50; i++) {
131 op_queue->add_accumulate(GroupElement::random_element(&engine));
132 op_queue->mul_accumulate(GroupElement::random_element(&engine), FF::random_element(&engine));
133 }
134 op_queue->eq_and_reset();
135 op_queue->merge();
136 for (size_t i = 0; i < 50; i++) {
137 op_queue->add_accumulate(GroupElement::random_element(&engine));
138 op_queue->mul_accumulate(GroupElement::random_element(&engine), FF::random_element(&engine));
139 }
140 op_queue->eq_and_reset();
141 for (size_t i = 0; i < Flavor::CircuitBuilder::NUM_RANDOM_OPS_END; i++) {
142 op_queue->random_op_ultra_only();
143 }
144 op_queue->merge(MergeSettings::APPEND, ECCOpQueue::OP_QUEUE_SIZE - op_queue->get_current_subtable_size());
145
146 const auto batching_challenge_v = BF::random_element(&engine);
147 const auto evaluation_input_x = BF::random_element(&engine);
148
149 auto circuit_builder = Flavor::CircuitBuilder(batching_challenge_v, evaluation_input_x, op_queue);
150 TranslatorProvingKey key(circuit_builder);
151
152 // Read accumulated_result from the witness (same as the prover does)
153 auto& pp = key.proving_key->polynomials;
155 params.accumulated_result = { pp.accumulators_binary_limbs_0[Flavor::RESULT_ROW],
156 pp.accumulators_binary_limbs_1[Flavor::RESULT_ROW],
157 pp.accumulators_binary_limbs_2[Flavor::RESULT_ROW],
158 pp.accumulators_binary_limbs_3[Flavor::RESULT_ROW] };
159
160 return { std::move(key), params };
161}
162
163} // anonymous namespace
164
165class TranslatorRelationFailureTests : public ::testing::Test {
166 protected:
168};
169
174TEST_F(TranslatorRelationFailureTests, PermutationFailsOnConcatenatedCorruption)
175{
176 auto [key, params] = build_valid_translator_state();
177 auto& pp = key.proving_key->polynomials;
178
179 // Baseline: permutation relation passes
180 auto baseline =
181 RelationChecker<Flavor>::check<TranslatorPermutationRelation<FF>>(pp, params, "TranslatorPermutationRelation");
182 EXPECT_TRUE(baseline.empty()) << "Baseline permutation should pass";
183
184 // Corrupt a non-masking position in block 1 of concatenated_range_constraints_0
185 // Block 1 starts at MINI_CIRCUIT_SIZE, position 1 within it is non-masking (start_index=1)
186 const size_t corrupt_pos = Flavor::MINI_CIRCUIT_SIZE + 1;
187 pp.concatenated_range_constraints_0.at(corrupt_pos) = FF::random_element();
188
189 // Re-compute grand product with corrupted data
190 compute_grand_product<Flavor, TranslatorPermutationRelation<FF>>(pp, params);
191
192 auto failures =
193 RelationChecker<Flavor>::check<TranslatorPermutationRelation<FF>>(pp, params, "TranslatorPermutationRelation");
194 EXPECT_FALSE(failures.empty()) << "Permutation should fail after concatenated corruption";
195}
196
201TEST_F(TranslatorRelationFailureTests, DeltaRangeFailsOnMaxValueCorruption)
202{
203 auto [key, params] = build_valid_translator_state();
204 auto& pp = key.proving_key->polynomials;
205
206 const size_t full_circuit_size = Flavor::MINI_CIRCUIT_SIZE * Flavor::CONCATENATION_GROUP_SIZE;
207
208 // Baseline: delta range passes
210 pp, params, "TranslatorDeltaRangeConstraintRelation");
211 EXPECT_TRUE(baseline.empty()) << "Baseline delta range should pass";
212
213 // The real_last position must hold exactly 2^14 - 1. Corrupt it to something else.
214 const size_t real_last_pos = full_circuit_size - Flavor::MAX_RANDOM_VALUES_PER_ORDERED - 1;
215 pp.ordered_range_constraints_0.at(real_last_pos) = FF(42);
216
218 pp, params, "TranslatorDeltaRangeConstraintRelation");
219 EXPECT_FALSE(failures.empty()) << "Delta range should fail when real_last position != 2^14 - 1";
220}
221
225TEST_F(TranslatorRelationFailureTests, PermutationFailsOnZPermCorruption)
226{
227 auto [key, params] = build_valid_translator_state();
228 auto& pp = key.proving_key->polynomials;
229
230 // Baseline: permutation relation passes
231 auto baseline =
232 RelationChecker<Flavor>::check<TranslatorPermutationRelation<FF>>(pp, params, "TranslatorPermutationRelation");
233 EXPECT_TRUE(baseline.empty()) << "Baseline permutation should pass";
234
235 // Corrupt z_perm at a position in the middle of the circuit
236 const size_t corrupt_pos = (Flavor::MINI_CIRCUIT_SIZE * 2) + 500;
237 pp.z_perm.at(corrupt_pos) = FF::random_element();
238 // Must also update the shifted view
239 pp.set_shifted();
240
241 auto failures =
242 RelationChecker<Flavor>::check<TranslatorPermutationRelation<FF>>(pp, params, "TranslatorPermutationRelation");
243 EXPECT_FALSE(failures.empty()) << "Permutation should fail after z_perm corruption";
244}
245
254TEST_F(TranslatorRelationFailureTests, DeltaRangeFailsOnOrderedMaskingBoundary)
255{
256 auto [key, params] = build_valid_translator_state();
257 auto& pp = key.proving_key->polynomials;
258
259 const size_t full_circuit_size = Flavor::MINI_CIRCUIT_SIZE * Flavor::CONCATENATION_GROUP_SIZE;
260
261 // Baseline: delta range passes
263 pp, params, "TranslatorDeltaRangeConstraintRelation");
264 EXPECT_TRUE(baseline.empty()) << "Baseline delta range should pass";
265
266 // Position circuit_size - MAX_RANDOM - 2 is the last row with delta enforcement active.
267 // The next row (real_last) holds 2^14 - 1. Setting this to 0 creates delta = 16383.
268 const size_t boundary_pos = full_circuit_size - Flavor::MAX_RANDOM_VALUES_PER_ORDERED - 2;
269 pp.ordered_range_constraints_0.at(boundary_pos) = FF(0);
270
272 pp, params, "TranslatorDeltaRangeConstraintRelation");
273 EXPECT_FALSE(failures.empty()) << "Delta range should fail at the masking boundary";
274}
275
280TEST_F(TranslatorRelationFailureTests, DeltaRangeFailsOnNegativeDelta)
281{
282 auto [key, params] = build_valid_translator_state();
283 auto& pp = key.proving_key->polynomials;
284
285 // Baseline: delta range passes
287 pp, params, "TranslatorDeltaRangeConstraintRelation");
288 EXPECT_TRUE(baseline.empty()) << "Baseline delta range should pass";
289
290 // Set ordered[pos] to be larger than ordered[pos+1], creating a negative delta at row pos.
291 // D = ordered[pos+1] - ordered[pos] becomes a huge field element (negative in the integers),
292 // which is not in {0,1,2,3}.
293 const size_t pos = 5000;
294 pp.ordered_range_constraints_0.at(pos) = pp.ordered_range_constraints_0[pos + 1] + FF(1);
295
297 pp, params, "TranslatorDeltaRangeConstraintRelation");
298 EXPECT_FALSE(failures.empty()) << "Delta range should fail on descending (negative delta) pair";
299}
300
305TEST_F(TranslatorRelationFailureTests, DeltaRangeFailsOnDeltaFour)
306{
307 auto [key, params] = build_valid_translator_state();
308 auto& pp = key.proving_key->polynomials;
309
310 // Baseline: delta range passes
312 pp, params, "TranslatorDeltaRangeConstraintRelation");
313 EXPECT_TRUE(baseline.empty()) << "Baseline delta range should pass";
314
315 // Pick a mid-range position and set it so the delta to the next row is exactly 4
316 const size_t pos = 3000;
317 FF next_val = pp.ordered_range_constraints_0[pos + 1];
318 pp.ordered_range_constraints_0.at(pos) = next_val - FF(4);
319
321 pp, params, "TranslatorDeltaRangeConstraintRelation");
322 EXPECT_FALSE(failures.empty()) << "Delta range should fail when delta is exactly 4";
323}
324
329TEST_F(TranslatorRelationFailureTests, DeltaRangeFailsOnFirstSortedValueTooLarge)
330{
331 auto [key, params] = build_valid_translator_state();
332 auto& pp = key.proving_key->polynomials;
333
334 // Baseline: delta range passes
336 pp, params, "TranslatorDeltaRangeConstraintRelation");
337 EXPECT_TRUE(baseline.empty()) << "Baseline delta range should pass";
338
339 // Position 0 is virtual zero (always 0). Position 1 is the first sorted value.
340 // Setting it to 100 creates delta = 100 from row 0, which violates D ∈ {0,1,2,3}.
341 pp.ordered_range_constraints_0.at(1) = FF(100);
342
344 pp, params, "TranslatorDeltaRangeConstraintRelation");
345 EXPECT_FALSE(failures.empty()) << "Delta range should fail when first sorted value > 3";
346}
347
352TEST_F(TranslatorRelationFailureTests, DeltaRangeFailsOnFifthOrderedPolyCorruption)
353{
354 auto [key, params] = build_valid_translator_state();
355 auto& pp = key.proving_key->polynomials;
356
357 // Baseline: delta range passes
359 pp, params, "TranslatorDeltaRangeConstraintRelation");
360 EXPECT_TRUE(baseline.empty()) << "Baseline delta range should pass";
361
362 // Corrupt ordered_range_constraints_4 at a mid position
363 const size_t pos = 2000;
364 pp.ordered_range_constraints_4.at(pos) = pp.ordered_range_constraints_4[pos - 1] + FF(100);
365
367 pp, params, "TranslatorDeltaRangeConstraintRelation");
368 EXPECT_FALSE(failures.empty()) << "Delta range should fail on 5th ordered poly corruption";
369}
370
375TEST_F(TranslatorRelationFailureTests, PermutationFailsOnOrderedCorruption)
376{
377 auto [key, params] = build_valid_translator_state();
378 auto& pp = key.proving_key->polynomials;
379
380 // Baseline: permutation relation passes
381 auto baseline =
382 RelationChecker<Flavor>::check<TranslatorPermutationRelation<FF>>(pp, params, "TranslatorPermutationRelation");
383 EXPECT_TRUE(baseline.empty()) << "Baseline permutation should pass";
384
385 // Corrupt a non-masking position in ordered_range_constraints_0 without recomputing z_perm
386 const size_t corrupt_pos = 500;
387 pp.ordered_range_constraints_0.at(corrupt_pos) = FF::random_element();
388
389 auto failures =
390 RelationChecker<Flavor>::check<TranslatorPermutationRelation<FF>>(pp, params, "TranslatorPermutationRelation");
391 EXPECT_FALSE(failures.empty()) << "Permutation should fail after ordered poly corruption";
392}
393
402TEST_F(TranslatorRelationFailureTests, InRangeValueInMaskingFlowsToOrderedTail)
403{
404 const size_t full_circuit_size = Flavor::MINI_CIRCUIT_SIZE * Flavor::CONCATENATION_GROUP_SIZE;
406
409 ProverPolynomials& pp = key.proving_key->polynomials;
410
411 // Fill wire polynomials with random 14-bit values (circuit) and random FF (masking)
412 for (const auto& group : pp.get_groups_to_be_concatenated()) {
413 for (auto& poly : group) {
414 if (poly.is_empty()) {
415 continue;
416 }
417 for (size_t i = poly.start_index(); i < poly.end_index() - NUM_DISABLED_ROWS_IN_SUMCHECK; i++) {
418 poly.at(i) = engine.get_random_uint16() & ((1 << Flavor::MICRO_LIMB_BITS) - 1);
419 }
420 for (size_t i = poly.end_index() - NUM_DISABLED_ROWS_IN_SUMCHECK; i < poly.end_index(); i++) {
421 poly.at(i) = FF::random_element();
422 }
423 }
424 }
425
426 // Place a known small in-range value at the first masking position of group[0][0]
427 // (p_x_low_limbs_range_constraint_0, block 0)
428 const FF sentinel(42);
429 auto groups = pp.get_groups_to_be_concatenated();
430 auto& target_wire = groups[0][0];
431 const size_t wire_masking_start = target_wire.end_index() - NUM_DISABLED_ROWS_IN_SUMCHECK;
432 target_wire.at(wire_masking_start) = sentinel;
433
434 // Reallocate lagrange polynomials
435 pp.lagrange_first = typename Flavor::Polynomial(full_circuit_size);
436 pp.lagrange_last = typename Flavor::Polynomial(full_circuit_size);
437 pp.lagrange_real_last = typename Flavor::Polynomial(full_circuit_size);
438 pp.lagrange_masking = typename Flavor::Polynomial(full_circuit_size);
439
440 key.compute_lagrange_polynomials();
441 key.compute_extra_range_constraint_numerator();
442 key.compute_concatenated_polynomials();
443
444 // After concatenation: group[0][0] maps to block 0 of concatenated_range_constraints_0
445 // Masking position in concatenated poly = 0 * MINI + wire_masking_start
446 const size_t concat_masking_pos = wire_masking_start; // block 0, so offset is 0
447 EXPECT_EQ(pp.concatenated_range_constraints_0[concat_masking_pos], sentinel)
448 << "Sentinel should appear at the correct concatenated position";
449
450 key.compute_translator_range_constraint_ordered_polynomials();
451
452 // The sentinel should now be in the contiguous masking tail of one of the ordered polys.
453 // split_concatenated_random_coefficients_to_ordered extracts from concat[0..3] in order:
454 // concat 0, block 0, rows [MINI-4, MINI) → first 4 values in random_values[]
455 // Our sentinel is random_values[0] (first extracted value from concat 0, block 0, first masking row).
456 //
457 // Distribution: 256 total values across 5 ordered polys.
458 // ordered[0] gets 52 values (256/5=51, remainder 1 → first poly gets +1).
459 // random_values[0] → ordered[0] at position circuit_size - 52.
460 bool found = false;
461 for (const auto& ord_poly : pp.get_ordered_range_constraints()) {
462 for (size_t pos = full_circuit_size - Flavor::MAX_RANDOM_VALUES_PER_ORDERED; pos < full_circuit_size; pos++) {
463 if (ord_poly[pos] == sentinel) {
464 found = true;
465 break;
466 }
467 }
468 if (found) {
469 break;
470 }
471 }
472 EXPECT_TRUE(found) << "Sentinel value 42 should appear in the ordered poly masking tail";
473
474 // Verify all relations still pass with an in-range value in the masking position
476 compute_grand_product<Flavor, TranslatorPermutationRelation<FF>>(pp, params);
477
478 auto perm_failures =
479 RelationChecker<Flavor>::check<TranslatorPermutationRelation<FF>>(pp, params, "TranslatorPermutationRelation");
480 EXPECT_TRUE(perm_failures.empty()) << "Permutation should pass with in-range masking value";
481
483 pp, params, "TranslatorDeltaRangeConstraintRelation");
484 EXPECT_TRUE(delta_failures.empty()) << "Delta range should pass with in-range masking value";
485}
486
491TEST_F(TranslatorRelationFailureTests, PermutationFailsOnExtraNumeratorCorruption)
492{
493 auto [key, params] = build_valid_translator_state();
494 auto& pp = key.proving_key->polynomials;
495
496 // Baseline: permutation relation passes
497 auto baseline =
498 RelationChecker<Flavor>::check<TranslatorPermutationRelation<FF>>(pp, params, "TranslatorPermutationRelation");
499 EXPECT_TRUE(baseline.empty()) << "Baseline permutation should pass";
500
501 // Corrupt a value in the extra range constraint numerator without recomputing z_perm
502 const size_t corrupt_pos = 5;
503 pp.ordered_extra_range_constraints_numerator.at(corrupt_pos) = FF::random_element();
504
505 auto failures =
506 RelationChecker<Flavor>::check<TranslatorPermutationRelation<FF>>(pp, params, "TranslatorPermutationRelation");
507 EXPECT_FALSE(failures.empty()) << "Permutation should fail after extra numerator corruption";
508}
509
510// ======================== Accumulator Transfer Relation ========================
511
516TEST_F(TranslatorRelationFailureTests, AccumulatorTransferFailsOnOddRowCorruption)
517{
518 auto [key, params] = build_valid_accumulator_transfer_state();
519 auto& pp = key.proving_key->polynomials;
520
521 // Baseline: accumulator transfer passes with real Horner-scheme accumulator values
523 pp, params, "TranslatorAccumulatorTransferRelation");
524 EXPECT_TRUE(baseline.empty()) << "Baseline accumulator transfer should pass";
525
526 // Corrupt accumulators_binary_limbs_0 at an interior odd row.
527 // Transfer checks acc[101] == acc[102]. Corrupting acc[101] breaks this.
528 pp.accumulators_binary_limbs_0.at(101) = FF::random_element();
529
531 pp, params, "TranslatorAccumulatorTransferRelation");
532 EXPECT_FALSE(failures.empty()) << "Accumulator transfer should fail after odd row corruption";
533}
534
539TEST_F(TranslatorRelationFailureTests, AccumulatorTransferFailsOnZeroInitCorruption)
540{
541 auto [key, params] = build_valid_accumulator_transfer_state();
542 auto& pp = key.proving_key->polynomials;
543
545 pp, params, "TranslatorAccumulatorTransferRelation");
546 EXPECT_TRUE(baseline.empty()) << "Baseline accumulator transfer should pass";
547
548 // Corrupt: set non-zero accumulator at the last minicircuit row (zero-init position 8187)
549 const size_t last_in_minicircuit = Flavor::MINI_CIRCUIT_SIZE - Flavor::NUM_MASKED_ROWS_END - 1;
550 pp.accumulators_binary_limbs_0.at(last_in_minicircuit) = FF(1);
551
553 pp, params, "TranslatorAccumulatorTransferRelation");
554 EXPECT_FALSE(failures.empty()) << "Accumulator transfer should fail when zero-init position is non-zero";
555}
556
561TEST_F(TranslatorRelationFailureTests, AccumulatorTransferFailsOnResultMismatch)
562{
563 auto [key, params] = build_valid_accumulator_transfer_state();
564 auto& pp = key.proving_key->polynomials;
565
567 pp, params, "TranslatorAccumulatorTransferRelation");
568 EXPECT_TRUE(baseline.empty()) << "Baseline accumulator transfer should pass";
569
570 // Perturb accumulated_result so it no longer matches the witness at RESULT_ROW
571 params.accumulated_result[0] += FF(1);
572
574 pp, params, "TranslatorAccumulatorTransferRelation");
575 EXPECT_FALSE(failures.empty()) << "Accumulator transfer should fail on result mismatch";
576}
577
588TEST_F(TranslatorRelationFailureTests, AccumulatorTransferPassesWithMaskingRegionValues)
589{
590 auto [key, params] = build_valid_accumulator_transfer_state();
591 auto& pp = key.proving_key->polynomials;
592
593 // Place non-zero values at start masking positions [RANDOMNESS_START, RESULT_ROW) = [2, 8)
594 for (size_t i = Flavor::RANDOMNESS_START; i < Flavor::RESULT_ROW; i++) {
595 pp.accumulators_binary_limbs_0.at(i) = FF::random_element();
596 pp.accumulators_binary_limbs_1.at(i) = FF::random_element();
597 pp.accumulators_binary_limbs_2.at(i) = FF::random_element();
598 pp.accumulators_binary_limbs_3.at(i) = FF::random_element();
599 }
600
601 // Place non-zero values at end masking positions [MINI - NUM_MASKED, MINI) = [8188, 8192)
602 const size_t end_mask_start = Flavor::MINI_CIRCUIT_SIZE - Flavor::NUM_MASKED_ROWS_END;
603 for (size_t i = end_mask_start; i < Flavor::MINI_CIRCUIT_SIZE; i++) {
604 pp.accumulators_binary_limbs_0.at(i) = FF::random_element();
605 pp.accumulators_binary_limbs_1.at(i) = FF::random_element();
606 pp.accumulators_binary_limbs_2.at(i) = FF::random_element();
607 pp.accumulators_binary_limbs_3.at(i) = FF::random_element();
608 }
609
610 // Relation should still pass — masking regions are excluded by selectors
612 pp, params, "TranslatorAccumulatorTransferRelation");
613 EXPECT_TRUE(failures.empty()) << "Accumulator transfer should pass even with arbitrary masking region values";
614}
615
620TEST_F(TranslatorRelationFailureTests, AccumulatorTransferFailsAtFirstTransferRow)
621{
622 auto [key, params] = build_valid_accumulator_transfer_state();
623 auto& pp = key.proving_key->polynomials;
624
626 pp, params, "TranslatorAccumulatorTransferRelation");
627 EXPECT_TRUE(baseline.empty()) << "Baseline accumulator transfer should pass";
628
629 // Row 9 is the first odd row where lagrange_odd_in_minicircuit = 1.
630 // Transfer checks acc[9] == acc[10]. Corrupting acc[9] breaks this.
631 const size_t first_transfer_row = Flavor::RESULT_ROW + 1;
632 pp.accumulators_binary_limbs_0.at(first_transfer_row) = FF::random_element();
633
635 pp, params, "TranslatorAccumulatorTransferRelation");
636 EXPECT_FALSE(failures.empty()) << "Accumulator transfer should fail at first transfer row";
637}
638
644TEST_F(TranslatorRelationFailureTests, AccumulatorTransferFailsAtLastTransferRow)
645{
646 auto [key, params] = build_valid_accumulator_transfer_state();
647 auto& pp = key.proving_key->polynomials;
648
650 pp, params, "TranslatorAccumulatorTransferRelation");
651 EXPECT_TRUE(baseline.empty()) << "Baseline accumulator transfer should pass";
652
653 // Row MINI - NUM_MASKED - 3 = 8185 is the last odd row before 8187 where transfer is enforced
654 const size_t last_transfer_row = Flavor::MINI_CIRCUIT_SIZE - Flavor::NUM_MASKED_ROWS_END - 3;
655 pp.accumulators_binary_limbs_0.at(last_transfer_row) = FF::random_element();
656
658 pp, params, "TranslatorAccumulatorTransferRelation");
659 EXPECT_FALSE(failures.empty()) << "Accumulator transfer should fail at last transfer row";
660}
661
667TEST_F(TranslatorRelationFailureTests, PermutationFailsOnConcatenatedBlockBoundaryCorruption)
668{
669 auto [key, params] = build_valid_translator_state();
670 auto& pp = key.proving_key->polynomials;
671
672 // Baseline: permutation relation passes
673 auto baseline =
674 RelationChecker<Flavor>::check<TranslatorPermutationRelation<FF>>(pp, params, "TranslatorPermutationRelation");
675 EXPECT_TRUE(baseline.empty()) << "Baseline permutation should pass";
676
677 // Position 0 of block 5 in concatenated_range_constraints_0.
678 // This is at index 5 * MINI_CIRCUIT_SIZE, which should be zero (below start_index of that block's wire).
679 const size_t block_boundary_pos = 5 * Flavor::MINI_CIRCUIT_SIZE;
680 EXPECT_EQ(pp.concatenated_range_constraints_0[block_boundary_pos], FF(0))
681 << "Block boundary should initially be zero";
682
683 pp.concatenated_range_constraints_0.at(block_boundary_pos) = FF(999);
684
685 // Re-compute grand product with corrupted data
686 compute_grand_product<Flavor, TranslatorPermutationRelation<FF>>(pp, params);
687
688 auto failures =
689 RelationChecker<Flavor>::check<TranslatorPermutationRelation<FF>>(pp, params, "TranslatorPermutationRelation");
690 EXPECT_FALSE(failures.empty()) << "Permutation should fail after block boundary corruption";
691}
static const size_t OP_QUEUE_SIZE
A container for the prover polynomials.
typename Curve::ScalarField FF
ECCVMCircuitBuilder CircuitBuilder
typename Curve::BaseField BF
bb::Polynomial< FF > Polynomial
typename G1::element GroupElement
A debugging utility for checking whether a set of polynomials satisfies the relations for a given Fla...
A wrapper for Relations to expose methods used by the Sumcheck prover or verifier to add the contribu...
group class. Represents an elliptic curve group element. Group is parametrised by Fq and Fr
Definition group.hpp:36
virtual uint16_t get_random_uint16()=0
typename ECCVMFlavor::ProverPolynomials ProverPolynomials
numeric::RNG & engine
RNG & get_debug_randomness(bool reset, std::uint_fast64_t seed)
Definition engine.cpp:217
std::filesystem::path bb_crs_path()
void init_file_crs_factory(const std::filesystem::path &path)
Entry point for Barretenberg command-line interface.
Definition api.hpp:5
TEST_F(IPATest, ChallengesAreZero)
Definition ipa.test.cpp:155
constexpr decltype(auto) get(::tuplet::tuple< T... > &&t) noexcept
Definition tuple.hpp:13
Container for parameters used by the grand product (permutation, lookup) Honk relations.
std::array< T, NUM_BINARY_LIMBS_IN_GOBLIN_TRANSLATOR > accumulated_result
static field random_element(numeric::RNG *engine=nullptr) noexcept