45#include <gtest/gtest.h>
58struct ValidTranslatorState {
70ValidTranslatorState build_valid_translator_state()
72 const size_t full_circuit_size = Flavor::MINI_CIRCUIT_SIZE * Flavor::CONCATENATION_GROUP_SIZE;
80 for (
const auto&
group : pp.get_groups_to_be_concatenated()) {
81 for (
auto& poly :
group) {
82 if (poly.is_empty()) {
85 for (
size_t i = poly.start_index(); i < poly.end_index() - NUM_DISABLED_ROWS_IN_SUMCHECK; i++) {
88 for (
size_t i = poly.end_index() - NUM_DISABLED_ROWS_IN_SUMCHECK; i < poly.end_index(); i++) {
100 key.compute_lagrange_polynomials();
101 key.compute_extra_range_constraint_numerator();
102 key.compute_concatenated_polynomials();
103 key.compute_translator_range_constraint_ordered_polynomials();
107 compute_grand_product<Flavor, TranslatorPermutationRelation<FF>>(pp, params);
120ValidTranslatorState build_valid_accumulator_transfer_state()
128 op_queue->construct_zk_columns();
131 for (
size_t i = 0; i < 50; i++) {
132 op_queue->add_accumulate(GroupElement::random_element(&
engine));
135 op_queue->eq_and_reset();
137 for (
size_t i = 0; i < 50; i++) {
138 op_queue->add_accumulate(GroupElement::random_element(&
engine));
141 op_queue->eq_and_reset();
142 for (
size_t i = 0; i < Flavor::CircuitBuilder::NUM_RANDOM_OPS_END; i++) {
143 op_queue->random_op_ultra_only();
145 op_queue->merge_fixed_append(op_queue->get_append_offset());
147 const auto batching_challenge_v = BF::random_element(&
engine);
148 const auto evaluation_input_x = BF::random_element(&
engine);
154 auto& pp =
key.proving_key->polynomials;
157 pp.accumulators_binary_limbs_1[Flavor::RESULT_ROW],
158 pp.accumulators_binary_limbs_2[Flavor::RESULT_ROW],
159 pp.accumulators_binary_limbs_3[Flavor::RESULT_ROW] };
163 static constexpr size_t NUM_LIMB_BITS = Flavor::CircuitBuilder::NUM_LIMB_BITS;
164 auto uint_input_x =
uint256_t(evaluation_input_x);
166 uint_input_x.slice(NUM_LIMB_BITS, NUM_LIMB_BITS * 2),
167 uint_input_x.slice(NUM_LIMB_BITS * 2, NUM_LIMB_BITS * 3),
168 uint_input_x.slice(NUM_LIMB_BITS * 3, NUM_LIMB_BITS * 4),
170 auto v_power = BF::one();
171 for (
size_t i = 0; i < 4; i++) {
172 v_power *= batching_challenge_v;
175 uint_v_power.slice(NUM_LIMB_BITS, NUM_LIMB_BITS * 2),
176 uint_v_power.slice(NUM_LIMB_BITS * 2, NUM_LIMB_BITS * 3),
177 uint_v_power.slice(NUM_LIMB_BITS * 3, NUM_LIMB_BITS * 4),
197 auto [
key, params] = build_valid_translator_state();
198 auto& pp =
key.proving_key->polynomials;
203 EXPECT_TRUE(baseline.empty()) <<
"Baseline permutation should pass";
207 const size_t corrupt_pos = Flavor::MINI_CIRCUIT_SIZE + 1;
211 compute_grand_product<Flavor, TranslatorPermutationRelation<FF>>(pp, params);
215 EXPECT_FALSE(failures.empty()) <<
"Permutation should fail after concatenated corruption";
224 auto [
key, params] = build_valid_translator_state();
225 auto& pp =
key.proving_key->polynomials;
227 const size_t full_circuit_size = Flavor::MINI_CIRCUIT_SIZE * Flavor::CONCATENATION_GROUP_SIZE;
231 pp, params,
"TranslatorDeltaRangeConstraintRelation");
232 EXPECT_TRUE(baseline.empty()) <<
"Baseline delta range should pass";
235 const size_t real_last_pos = full_circuit_size - Flavor::MAX_RANDOM_VALUES_PER_ORDERED - 1;
236 pp.ordered_range_constraints_0.at(real_last_pos) =
FF(42);
239 pp, params,
"TranslatorDeltaRangeConstraintRelation");
240 EXPECT_FALSE(failures.empty()) <<
"Delta range should fail when real_last position != 2^14 - 1";
248 auto [
key, params] = build_valid_translator_state();
249 auto& pp =
key.proving_key->polynomials;
254 EXPECT_TRUE(baseline.empty()) <<
"Baseline permutation should pass";
257 const size_t corrupt_pos = (Flavor::MINI_CIRCUIT_SIZE * 2) + 500;
264 EXPECT_FALSE(failures.empty()) <<
"Permutation should fail after z_perm corruption";
279 auto [
key, params] = build_valid_translator_state();
280 auto& pp =
key.proving_key->polynomials;
285 EXPECT_TRUE(baseline.empty()) <<
"Baseline permutation should pass";
288 ASSERT_TRUE(pp.z_perm.is_shiftable());
289 size_t structural_first_row = pp.z_perm.start_index() - 1;
292 const auto& lagrange_first = pp.lagrange_first;
293 size_t scanned_first_row = 0;
295 for (
size_t i = lagrange_first.start_index(); i < lagrange_first.end_index(); ++i) {
296 if (lagrange_first[i] !=
FF(0)) {
297 scanned_first_row = i;
302 ASSERT_TRUE(found) <<
"lagrange_first has no non-zero entry";
303 ASSERT_EQ(structural_first_row, scanned_first_row)
304 <<
"lagrange_first position doesn't match z_perm shiftable structure";
306 const size_t first_row = scanned_first_row;
309 pp.z_perm = pp.z_perm.full();
310 pp.z_perm_shift = pp.z_perm_shift.full();
312 ASSERT_EQ(pp.z_perm[first_row],
FF(0));
315 pp.z_perm.at(first_row) =
FF(1);
318 pp, params,
"TranslatorPermutationRelation - After setting z_perm != 0 at lagrange_first");
319 EXPECT_FALSE(failures.empty()) <<
"Permutation should fail after z_perm init corruption";
321 EXPECT_TRUE(failures.contains(2)) <<
"Sub-relation 2 (z_perm init) should catch the corruption";
322 EXPECT_EQ(failures.at(2),
static_cast<uint32_t
>(first_row)) <<
"Failure should be at lagrange_first row";
335 auto [
key, params] = build_valid_translator_state();
336 auto& pp =
key.proving_key->polynomials;
338 const size_t full_circuit_size = Flavor::MINI_CIRCUIT_SIZE * Flavor::CONCATENATION_GROUP_SIZE;
342 pp, params,
"TranslatorDeltaRangeConstraintRelation");
343 EXPECT_TRUE(baseline.empty()) <<
"Baseline delta range should pass";
347 const size_t boundary_pos = full_circuit_size - Flavor::MAX_RANDOM_VALUES_PER_ORDERED - 2;
348 pp.ordered_range_constraints_0.at(boundary_pos) =
FF(0);
351 pp, params,
"TranslatorDeltaRangeConstraintRelation");
352 EXPECT_FALSE(failures.empty()) <<
"Delta range should fail at the masking boundary";
361 auto [
key, params] = build_valid_translator_state();
362 auto& pp =
key.proving_key->polynomials;
366 pp, params,
"TranslatorDeltaRangeConstraintRelation");
367 EXPECT_TRUE(baseline.empty()) <<
"Baseline delta range should pass";
372 const size_t pos = 5000;
373 pp.ordered_range_constraints_0.at(pos) = pp.ordered_range_constraints_0[pos + 1] +
FF(1);
376 pp, params,
"TranslatorDeltaRangeConstraintRelation");
377 EXPECT_FALSE(failures.empty()) <<
"Delta range should fail on descending (negative delta) pair";
386 auto [
key, params] = build_valid_translator_state();
387 auto& pp =
key.proving_key->polynomials;
391 pp, params,
"TranslatorDeltaRangeConstraintRelation");
392 EXPECT_TRUE(baseline.empty()) <<
"Baseline delta range should pass";
395 const size_t pos = 3000;
396 FF next_val = pp.ordered_range_constraints_0[pos + 1];
397 pp.ordered_range_constraints_0.at(pos) = next_val -
FF(4);
400 pp, params,
"TranslatorDeltaRangeConstraintRelation");
401 EXPECT_FALSE(failures.empty()) <<
"Delta range should fail when delta is exactly 4";
410 auto [
key, params] = build_valid_translator_state();
411 auto& pp =
key.proving_key->polynomials;
415 pp, params,
"TranslatorDeltaRangeConstraintRelation");
416 EXPECT_TRUE(baseline.empty()) <<
"Baseline delta range should pass";
420 pp.ordered_range_constraints_0.at(1) =
FF(100);
423 pp, params,
"TranslatorDeltaRangeConstraintRelation");
424 EXPECT_FALSE(failures.empty()) <<
"Delta range should fail when first sorted value > 3";
433 auto [
key, params] = build_valid_translator_state();
434 auto& pp =
key.proving_key->polynomials;
438 pp, params,
"TranslatorDeltaRangeConstraintRelation");
439 EXPECT_TRUE(baseline.empty()) <<
"Baseline delta range should pass";
442 const size_t pos = 2000;
443 pp.ordered_range_constraints_4.at(pos) = pp.ordered_range_constraints_4[pos - 1] +
FF(100);
446 pp, params,
"TranslatorDeltaRangeConstraintRelation");
447 EXPECT_FALSE(failures.empty()) <<
"Delta range should fail on 5th ordered poly corruption";
456 auto [
key, params] = build_valid_translator_state();
457 auto& pp =
key.proving_key->polynomials;
462 EXPECT_TRUE(baseline.empty()) <<
"Baseline permutation should pass";
465 const size_t corrupt_pos = 500;
470 EXPECT_FALSE(failures.empty()) <<
"Permutation should fail after ordered poly corruption";
483 const size_t full_circuit_size = Flavor::MINI_CIRCUIT_SIZE * Flavor::CONCATENATION_GROUP_SIZE;
491 for (
const auto&
group : pp.get_groups_to_be_concatenated()) {
492 for (
auto& poly :
group) {
493 if (poly.is_empty()) {
496 for (
size_t i = poly.start_index(); i < poly.end_index() - NUM_DISABLED_ROWS_IN_SUMCHECK; i++) {
499 for (
size_t i = poly.end_index() - NUM_DISABLED_ROWS_IN_SUMCHECK; i < poly.end_index(); i++) {
507 const FF sentinel(42);
508 auto groups = pp.get_groups_to_be_concatenated();
509 auto& target_wire = groups[0][0];
510 const size_t wire_masking_start = target_wire.end_index() - NUM_DISABLED_ROWS_IN_SUMCHECK;
511 target_wire.at(wire_masking_start) = sentinel;
519 key.compute_lagrange_polynomials();
520 key.compute_extra_range_constraint_numerator();
521 key.compute_concatenated_polynomials();
525 const size_t concat_masking_pos = wire_masking_start;
526 EXPECT_EQ(pp.concatenated_range_constraints_0[concat_masking_pos], sentinel)
527 <<
"Sentinel should appear at the correct concatenated position";
529 key.compute_translator_range_constraint_ordered_polynomials();
540 for (
const auto& ord_poly : pp.get_ordered_range_constraints()) {
541 for (
size_t pos = full_circuit_size - Flavor::MAX_RANDOM_VALUES_PER_ORDERED; pos < full_circuit_size; pos++) {
542 if (ord_poly[pos] == sentinel) {
551 EXPECT_TRUE(found) <<
"Sentinel value 42 should appear in the ordered poly masking tail";
555 compute_grand_product<Flavor, TranslatorPermutationRelation<FF>>(pp, params);
559 EXPECT_TRUE(perm_failures.empty()) <<
"Permutation should pass with in-range masking value";
562 pp, params,
"TranslatorDeltaRangeConstraintRelation");
563 EXPECT_TRUE(delta_failures.empty()) <<
"Delta range should pass with in-range masking value";
572 auto [
key, params] = build_valid_translator_state();
573 auto& pp =
key.proving_key->polynomials;
578 EXPECT_TRUE(baseline.empty()) <<
"Baseline permutation should pass";
581 const size_t corrupt_pos = 5;
586 EXPECT_FALSE(failures.empty()) <<
"Permutation should fail after extra numerator corruption";
597 auto [
key, params] = build_valid_accumulator_transfer_state();
598 auto& pp =
key.proving_key->polynomials;
602 pp, params,
"TranslatorAccumulatorTransferRelation");
603 EXPECT_TRUE(baseline.empty()) <<
"Baseline accumulator transfer should pass";
610 pp, params,
"TranslatorAccumulatorTransferRelation");
611 EXPECT_FALSE(failures.empty()) <<
"Accumulator transfer should fail after odd row corruption";
620 auto [
key, params] = build_valid_accumulator_transfer_state();
621 auto& pp =
key.proving_key->polynomials;
624 pp, params,
"TranslatorAccumulatorTransferRelation");
625 EXPECT_TRUE(baseline.empty()) <<
"Baseline accumulator transfer should pass";
628 const size_t last_in_minicircuit = Flavor::MINI_CIRCUIT_SIZE - Flavor::NUM_MASKED_ROWS_END - 1;
629 pp.accumulators_binary_limbs_0.at(last_in_minicircuit) =
FF(1);
632 pp, params,
"TranslatorAccumulatorTransferRelation");
633 EXPECT_FALSE(failures.empty()) <<
"Accumulator transfer should fail when zero-init position is non-zero";
642 auto [
key, params] = build_valid_accumulator_transfer_state();
643 auto& pp =
key.proving_key->polynomials;
646 pp, params,
"TranslatorAccumulatorTransferRelation");
647 EXPECT_TRUE(baseline.empty()) <<
"Baseline accumulator transfer should pass";
650 params.accumulated_result[0] +=
FF(1);
653 pp, params,
"TranslatorAccumulatorTransferRelation");
654 EXPECT_FALSE(failures.empty()) <<
"Accumulator transfer should fail on result mismatch";
669 auto [
key, params] = build_valid_accumulator_transfer_state();
670 auto& pp =
key.proving_key->polynomials;
673 for (
size_t i = Flavor::RANDOMNESS_START; i < Flavor::RESULT_ROW; i++) {
681 const size_t end_mask_start = Flavor::MINI_CIRCUIT_SIZE - Flavor::NUM_MASKED_ROWS_END;
682 for (
size_t i = end_mask_start; i < Flavor::MINI_CIRCUIT_SIZE; i++) {
691 pp, params,
"TranslatorAccumulatorTransferRelation");
692 EXPECT_TRUE(failures.empty()) <<
"Accumulator transfer should pass even with arbitrary masking region values";
701 auto [
key, params] = build_valid_accumulator_transfer_state();
702 auto& pp =
key.proving_key->polynomials;
705 pp, params,
"TranslatorAccumulatorTransferRelation");
706 EXPECT_TRUE(baseline.empty()) <<
"Baseline accumulator transfer should pass";
710 const size_t first_transfer_row = Flavor::RESULT_ROW + 1;
714 pp, params,
"TranslatorAccumulatorTransferRelation");
715 EXPECT_FALSE(failures.empty()) <<
"Accumulator transfer should fail at first transfer row";
725 auto [
key, params] = build_valid_accumulator_transfer_state();
726 auto& pp =
key.proving_key->polynomials;
729 pp, params,
"TranslatorAccumulatorTransferRelation");
730 EXPECT_TRUE(baseline.empty()) <<
"Baseline accumulator transfer should pass";
733 const size_t last_transfer_row = Flavor::MINI_CIRCUIT_SIZE - Flavor::NUM_MASKED_ROWS_END - 3;
737 pp, params,
"TranslatorAccumulatorTransferRelation");
738 EXPECT_FALSE(failures.empty()) <<
"Accumulator transfer should fail at last transfer row";
748 auto [
key, params] = build_valid_translator_state();
749 auto& pp =
key.proving_key->polynomials;
754 EXPECT_TRUE(baseline.empty()) <<
"Baseline permutation should pass";
758 const size_t block_boundary_pos = 5 * Flavor::MINI_CIRCUIT_SIZE;
759 EXPECT_EQ(pp.concatenated_range_constraints_0[block_boundary_pos],
FF(0))
760 <<
"Block boundary should initially be zero";
762 pp.concatenated_range_constraints_0.at(block_boundary_pos) =
FF(999);
765 compute_grand_product<Flavor, TranslatorPermutationRelation<FF>>(pp, params);
769 EXPECT_FALSE(failures.empty()) <<
"Permutation should fail after block boundary corruption";
788 static constexpr size_t NUM_LIMB_BITS = Flavor::CircuitBuilder::NUM_LIMB_BITS;
790 auto [
key, params] = build_valid_accumulator_transfer_state();
791 auto& pp =
key.proving_key->polynomials;
795 pp, params,
"TranslatorNonNativeFieldRelation");
796 EXPECT_TRUE(baseline.empty()) <<
"Baseline non-native field should pass";
798 constexpr size_t ROW = Flavor::RESULT_ROW;
802 auto read_limbs = [](
const auto& l0,
const auto& l1,
const auto& l2,
const auto& l3,
size_t row) {
804 (
uint256_t(l2[row]) << (2 * NUM_LIMB_BITS)) | (
uint256_t(l3[row]) << (3 * NUM_LIMB_BITS));
807 uint256_t old_acc = read_limbs(pp.accumulators_binary_limbs_0,
808 pp.accumulators_binary_limbs_1,
809 pp.accumulators_binary_limbs_2,
810 pp.accumulators_binary_limbs_3,
815 (
uint256_t(pp.quotient_low_binary_limbs[ROW + 1]) << NUM_LIMB_BITS) |
816 (
uint256_t(pp.quotient_high_binary_limbs[ROW]) << (2 * NUM_LIMB_BITS)) |
817 (
uint256_t(pp.quotient_high_binary_limbs[ROW + 1]) << (3 * NUM_LIMB_BITS));
824 auto split = [](
const uint256_t& val) -> std::array<FF, 4> {
825 return {
FF(val.slice(0, NUM_LIMB_BITS)),
826 FF(val.slice(NUM_LIMB_BITS, 2 * NUM_LIMB_BITS)),
827 FF(val.slice(2 * NUM_LIMB_BITS, 3 * NUM_LIMB_BITS)),
828 FF(val.slice(3 * NUM_LIMB_BITS, 4 * NUM_LIMB_BITS)) };
831 auto new_acc_limbs = split(new_acc);
832 auto new_quot_limbs = split(new_quot);
835 pp.accumulators_binary_limbs_0.at(ROW) = new_acc_limbs[0];
836 pp.accumulators_binary_limbs_1.at(ROW) = new_acc_limbs[1];
837 pp.accumulators_binary_limbs_2.at(ROW) = new_acc_limbs[2];
838 pp.accumulators_binary_limbs_3.at(ROW) = new_acc_limbs[3];
841 pp.quotient_low_binary_limbs.at(ROW) = new_quot_limbs[0];
842 pp.quotient_low_binary_limbs.at(ROW + 1) = new_quot_limbs[1];
843 pp.quotient_high_binary_limbs.at(ROW) = new_quot_limbs[2];
844 pp.quotient_high_binary_limbs.at(ROW + 1) = new_quot_limbs[3];
850 pp, params,
"TranslatorNonNativeFieldRelation");
853 EXPECT_TRUE(failures.contains(1)) <<
"Subrelation 1 (higher carry check) should reject the alias";
854 EXPECT_EQ(failures.at(1),
static_cast<uint32_t
>(ROW)) <<
"Failure should be at RESULT_ROW";
857 EXPECT_FALSE(failures.contains(2)) <<
"Subrelation 2 (native check) should pass under the alias mutation";
static void SetUpTestSuite()
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
virtual uint16_t get_random_uint16()=0
typename ECCVMFlavor::ProverPolynomials ProverPolynomials
RNG & get_debug_randomness(bool reset, std::uint_fast64_t seed)
std::filesystem::path bb_crs_path()
void init_file_crs_factory(const std::filesystem::path &path)
Entry point for Barretenberg command-line interface.
TEST_F(IPATest, ChallengesAreZero)
constexpr decltype(auto) get(::tuplet::tuple< T... > &&t) noexcept
Container for parameters used by the grand product (permutation, lookup) Honk relations.
std::array< std::array< T, NUM_BINARY_LIMBS_IN_GOBLIN_TRANSLATOR+NUM_NATIVE_LIMBS_IN_GOBLIN_TRANSLATOR >, NUM_CHALLENGE_POWERS_IN_GOBLIN_TRANSLATOR > batching_challenge_v
std::array< T, NUM_BINARY_LIMBS_IN_GOBLIN_TRANSLATOR > accumulated_result
std::array< T, NUM_BINARY_LIMBS_IN_GOBLIN_TRANSLATOR+NUM_NATIVE_LIMBS_IN_GOBLIN_TRANSLATOR > evaluation_input_x
static field random_element(numeric::RNG *engine=nullptr) noexcept