From f4e62ae5bcc7a0ef7baccc61e6e3e959196c891a Mon Sep 17 00:00:00 2001 From: Zachary James Williamson Date: Mon, 25 Mar 2024 21:41:50 +0000 Subject: [PATCH] refactor(bb): removed powers of eta in lookup and auxiliary relations (#4695) We previously were using powers of the plookup "eta" challenge in our lookup and auxiliary relations, to construct random linear combinations. With protogalaxy, this becomes inefficient as each challenge is represented by a degree-1 Univariate polynomial. i.e. eta^3 is degree-3, while a completely independent challenge is degree-1. Usages of eta^2 and eta^3 have been replaced with new challenges eta_two and eta_three Now that the `CircuitChecker` uses relations, we update these as appropriately but also have to change `stdlib_plonk_recursion_tests` to construct and verify full proof as the widgets do not reflect changes on `eta` --------- Co-authored-by: maramihali --- .../circuit_checker/ultra_circuit_checker.cpp | 37 +++++++--- .../circuit_checker/ultra_circuit_checker.hpp | 5 +- .../honk/proof_system/types/proof.hpp | 2 +- .../protogalaxy/combiner.test.cpp | 39 +++++------ .../protogalaxy/protogalaxy.test.cpp | 16 +++-- .../protogalaxy/protogalaxy_prover.cpp | 2 + .../protogalaxy/protogalaxy_verifier.cpp | 2 + .../relations/auxiliary_relation.hpp | 68 +++++++++---------- .../relations/lookup_relation.hpp | 36 +++++----- .../relations/relation_parameters.hpp | 12 +++- .../ultra_relation_consistency.test.cpp | 30 ++++---- .../protogalaxy_recursive_verifier.cpp | 7 +- .../verifier/recursive_verifier_instance.hpp | 4 ++ .../verifier/ultra_recursive_verifier.cpp | 4 +- .../verifier/verifier.test.cpp | 20 ++++-- .../goblin_ultra_flavor.hpp | 64 ++++++++--------- .../grand_product_library.test.cpp | 16 +++-- .../stdlib_circuit_builders/ultra_flavor.hpp | 67 ++++++++---------- .../ultra_recursive_flavor.hpp | 2 +- .../instance/prover_instance.test.cpp | 12 ++-- .../goblin_ultra_transcript.test.cpp | 2 +- .../barretenberg/ultra_honk/oink_prover.cpp | 10 ++- .../barretenberg/ultra_honk/oink_verifier.cpp | 6 +- .../ultra_honk/relation_correctness.test.cpp | 12 +++- .../barretenberg/ultra_honk/sumcheck.test.cpp | 7 +- .../ultra_honk/ultra_transcript.test.cpp | 2 +- 26 files changed, 265 insertions(+), 219 deletions(-) diff --git a/barretenberg/cpp/src/barretenberg/circuit_checker/ultra_circuit_checker.cpp b/barretenberg/cpp/src/barretenberg/circuit_checker/ultra_circuit_checker.cpp index afe06392009..ea9ab77c13d 100644 --- a/barretenberg/cpp/src/barretenberg/circuit_checker/ultra_circuit_checker.cpp +++ b/barretenberg/cpp/src/barretenberg/circuit_checker/ultra_circuit_checker.cpp @@ -68,6 +68,8 @@ bool UltraCircuitChecker::check_block(Builder& builder, auto values = init_empty_values(); Params params; params.eta = memory_data.eta; // used in Auxiliary relation for RAM/ROM consistency + params.eta_two = memory_data.eta_two; + params.eta_three = memory_data.eta_three; // Perform checks on each gate defined in the builder bool result = true; @@ -179,10 +181,11 @@ void UltraCircuitChecker::populate_values( } }; - // A lambda function for computing a memory record term of the form w3 * eta^3 + w2 * eta^2 + w1 * eta - auto compute_memory_record_term = [](const FF& w_1, const FF& w_2, const FF& w_3, const FF& eta) { - return ((w_3 * eta + w_2) * eta + w_1) * eta; - }; + // A lambda function for computing a memory record term of the form w3 * eta_three + w2 * eta_two + w1 * eta + auto compute_memory_record_term = + [](const FF& w_1, const FF& w_2, const FF& w_3, const FF& eta, const FF& eta_two, FF& eta_three) { + return (w_3 * eta_three + w_2 * eta_two + w_1 * eta); + }; // Set wire values. Wire 4 is treated specially since it may contain memory records values.w_l = builder.get_variable(block.w_l()[idx]); @@ -191,9 +194,13 @@ void UltraCircuitChecker::populate_values( // Note: memory_data contains indices into the block to which RAM/ROM gates were added so we need to check that we // are indexing into the correct block before updating the w_4 value. if (block.has_ram_rom && memory_data.read_record_gates.contains(idx)) { - values.w_4 = compute_memory_record_term(values.w_l, values.w_r, values.w_o, memory_data.eta); + values.w_4 = compute_memory_record_term( + values.w_l, values.w_r, values.w_o, memory_data.eta, memory_data.eta_two, memory_data.eta_three); } else if (block.has_ram_rom && memory_data.write_record_gates.contains(idx)) { - values.w_4 = compute_memory_record_term(values.w_l, values.w_r, values.w_o, memory_data.eta) + FF::one(); + values.w_4 = + compute_memory_record_term( + values.w_l, values.w_r, values.w_o, memory_data.eta, memory_data.eta_two, memory_data.eta_three) + + FF::one(); } else { values.w_4 = builder.get_variable(block.w_4()[idx]); } @@ -204,12 +211,20 @@ void UltraCircuitChecker::populate_values( values.w_r_shift = builder.get_variable(block.w_r()[idx + 1]); values.w_o_shift = builder.get_variable(block.w_o()[idx + 1]); if (block.has_ram_rom && memory_data.read_record_gates.contains(idx + 1)) { - values.w_4_shift = - compute_memory_record_term(values.w_l_shift, values.w_r_shift, values.w_o_shift, memory_data.eta); + values.w_4_shift = compute_memory_record_term(values.w_l_shift, + values.w_r_shift, + values.w_o_shift, + memory_data.eta, + memory_data.eta_two, + memory_data.eta_three); } else if (block.has_ram_rom && memory_data.write_record_gates.contains(idx + 1)) { - values.w_4_shift = - compute_memory_record_term(values.w_l_shift, values.w_r_shift, values.w_o_shift, memory_data.eta) + - FF::one(); + values.w_4_shift = compute_memory_record_term(values.w_l_shift, + values.w_r_shift, + values.w_o_shift, + memory_data.eta, + memory_data.eta_two, + memory_data.eta_three) + + FF::one(); } else { values.w_4_shift = builder.get_variable(block.w_4()[idx + 1]); } diff --git a/barretenberg/cpp/src/barretenberg/circuit_checker/ultra_circuit_checker.hpp b/barretenberg/cpp/src/barretenberg/circuit_checker/ultra_circuit_checker.hpp index 4e4ae0d32ac..39a92d46819 100644 --- a/barretenberg/cpp/src/barretenberg/circuit_checker/ultra_circuit_checker.hpp +++ b/barretenberg/cpp/src/barretenberg/circuit_checker/ultra_circuit_checker.hpp @@ -132,7 +132,10 @@ class UltraCircuitChecker { * @brief Struct for managing memory record data for ensuring RAM/ROM correctness */ struct MemoryCheckData { - FF eta = FF::random_element(); // randomness for constructing wire 4 mem records + // randomness for constructing wire 4 mem records + FF eta = FF::random_element(); + FF eta_two = FF::random_element(); + FF eta_three = FF::random_element(); std::unordered_set read_record_gates; // row indices for gates containing RAM/ROM read mem record std::unordered_set write_record_gates; // row indices for gates containing RAM/ROM write mem record diff --git a/barretenberg/cpp/src/barretenberg/honk/proof_system/types/proof.hpp b/barretenberg/cpp/src/barretenberg/honk/proof_system/types/proof.hpp index 2c9ea4e3a3b..a20111a69be 100644 --- a/barretenberg/cpp/src/barretenberg/honk/proof_system/types/proof.hpp +++ b/barretenberg/cpp/src/barretenberg/honk/proof_system/types/proof.hpp @@ -5,7 +5,7 @@ namespace bb { -using HonkProof = std::vector; +using HonkProof = std::vector; // this can be fr? template using StdlibProof = std::vector>; diff --git a/barretenberg/cpp/src/barretenberg/protogalaxy/combiner.test.cpp b/barretenberg/cpp/src/barretenberg/protogalaxy/combiner.test.cpp index 4c5d2bc763f..bafae22398f 100644 --- a/barretenberg/cpp/src/barretenberg/protogalaxy/combiner.test.cpp +++ b/barretenberg/cpp/src/barretenberg/protogalaxy/combiner.test.cpp @@ -51,22 +51,23 @@ TEST(Protogalaxy, CombinerOn2Instances) } ProverInstances instances{ instance_data }; - instances.alphas.fill(bb::Univariate(FF(0))); // focus on the arithmetic relation only + instances.alphas.fill(bb::Univariate(FF(0))); // focus on the arithmetic relation only auto pow_polynomial = PowPolynomial(std::vector{ 2 }); auto result = prover.compute_combiner(instances, pow_polynomial); - auto expected_result = Univariate(std::array{ 87706, - 13644570, - 76451738, - 226257946, - static_cast(500811930), - static_cast(937862426), - static_cast(1575158170), - static_cast(2450447898), - static_cast(3601480346), - static_cast(5066004250), - static_cast(6881768346), - static_cast(9086521370), - static_cast(11718012058) }); + auto expected_result = Univariate(std::array{ + 87706, + 13644570, + 76451738, + 226257946, + static_cast(500811930), + static_cast(937862426), + static_cast(1575158170), + static_cast(2450447898), + static_cast(3601480346), + static_cast(5066004250), + static_cast(6881768346), + static_cast(9086521370), + }); EXPECT_EQ(result, expected_result); } else { std::vector> instance_data(NUM_INSTANCES); @@ -84,7 +85,7 @@ TEST(Protogalaxy, CombinerOn2Instances) } ProverInstances instances{ instance_data }; - instances.alphas.fill(bb::Univariate(FF(0))); // focus on the arithmetic relation only + instances.alphas.fill(bb::Univariate(FF(0))); // focus on the arithmetic relation only const auto create_add_gate = [](auto& polys, const size_t idx, FF w_l, FF w_r) { polys.w_l[idx] = w_l; @@ -133,7 +134,7 @@ TEST(Protogalaxy, CombinerOn2Instances) auto pow_polynomial = PowPolynomial(std::vector{ 2 }); auto result = prover.compute_combiner(instances, pow_polynomial); auto expected_result = - Univariate(std::array{ 0, 0, 12, 36, 72, 120, 180, 252, 336, 432, 540, 660, 792 }); + Univariate(std::array{ 0, 0, 12, 36, 72, 120, 180, 252, 336, 432, 540, 660 }); EXPECT_EQ(result, expected_result); } @@ -175,7 +176,7 @@ TEST(Protogalaxy, CombinerOn4Instances) } ProverInstances instances{ instance_data }; - instances.alphas.fill(bb::Univariate(FF(0))); // focus on the arithmetic relation only + instances.alphas.fill(bb::Univariate(FF(0))); // focus on the arithmetic relation only zero_all_selectors(instances[0]->prover_polynomials); zero_all_selectors(instances[1]->prover_polynomials); @@ -184,9 +185,9 @@ TEST(Protogalaxy, CombinerOn4Instances) auto pow_polynomial = PowPolynomial(std::vector{ 2 }); auto result = prover.compute_combiner(instances, pow_polynomial); - std::array zeroes; + std::array zeroes; std::fill(zeroes.begin(), zeroes.end(), 0); - auto expected_result = Univariate(zeroes); + auto expected_result = Univariate(zeroes); EXPECT_EQ(result, expected_result); }; run_test(); diff --git a/barretenberg/cpp/src/barretenberg/protogalaxy/protogalaxy.test.cpp b/barretenberg/cpp/src/barretenberg/protogalaxy/protogalaxy.test.cpp index 1124bfdec23..453e0d844d7 100644 --- a/barretenberg/cpp/src/barretenberg/protogalaxy/protogalaxy.test.cpp +++ b/barretenberg/cpp/src/barretenberg/protogalaxy/protogalaxy.test.cpp @@ -119,10 +119,14 @@ template class ProtoGalaxyTests : public testing::Test { auto instance = std::make_shared(builder); instance->relation_parameters.eta = FF::random_element(); + instance->relation_parameters.eta_two = FF::random_element(); + instance->relation_parameters.eta_three = FF::random_element(); instance->relation_parameters.beta = FF::random_element(); instance->relation_parameters.gamma = FF::random_element(); - instance->proving_key->compute_sorted_accumulator_polynomials(instance->relation_parameters.eta); + instance->proving_key->compute_sorted_accumulator_polynomials(instance->relation_parameters.eta, + instance->relation_parameters.eta_two, + instance->relation_parameters.eta_three); if constexpr (IsGoblinFlavor) { instance->proving_key->compute_logderivative_inverse(instance->relation_parameters); } @@ -219,13 +223,12 @@ template class ProtoGalaxyTests : public testing::Test { static void test_combiner_quotient() { auto compressed_perturbator = FF(2); // F(\alpha) in the paper - auto combiner = - bb::Univariate(std::array{ 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32 }); + auto combiner = bb::Univariate(std::array{ 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31 }); auto combiner_quotient = ProtoGalaxyProver::compute_combiner_quotient(compressed_perturbator, combiner); // K(i) = (G(i) - ( L_0(i) * F(\alpha)) / Z(i), i = {2,.., 13} for ProverInstances::NUM = 2 // K(i) = (G(i) - (1 - i) * F(\alpha)) / i * (i - 1) - auto expected_evals = bb::Univariate(std::array{ + auto expected_evals = bb::Univariate(std::array{ (FF(22) - (FF(1) - FF(2)) * compressed_perturbator) / (FF(2) * FF(2 - 1)), (FF(23) - (FF(1) - FF(3)) * compressed_perturbator) / (FF(3) * FF(3 - 1)), (FF(24) - (FF(1) - FF(4)) * compressed_perturbator) / (FF(4) * FF(4 - 1)), @@ -236,7 +239,6 @@ template class ProtoGalaxyTests : public testing::Test { (FF(29) - (FF(1) - FF(9)) * compressed_perturbator) / (FF(9) * FF(9 - 1)), (FF(30) - (FF(1) - FF(10)) * compressed_perturbator) / (FF(10) * FF(10 - 1)), (FF(31) - (FF(1) - FF(11)) * compressed_perturbator) / (FF(11) * FF(11 - 1)), - (FF(32) - (FF(1) - FF(12)) * compressed_perturbator) / (FF(12) * FF(12 - 1)), }); for (size_t idx = 2; idx < 7; idx++) { @@ -263,7 +265,7 @@ template class ProtoGalaxyTests : public testing::Test { ProverInstances instances{ { instance1, instance2 } }; ProtoGalaxyProver::combine_relation_parameters(instances); - bb::Univariate expected_eta{ { 1, 3, 5, 7, 9, 11, 13, 15, 17, 19, 21, 23 } }; + bb::Univariate expected_eta{ { 1, 3, 5, 7, 9, 11, 13, 15, 17, 19, 21 } }; EXPECT_EQ(instances.relation_parameters.eta, expected_eta); } @@ -285,7 +287,7 @@ template class ProtoGalaxyTests : public testing::Test { ProverInstances instances{ { instance1, instance2 } }; ProtoGalaxyProver::combine_alpha(instances); - bb::Univariate expected_alpha{ { 2, 4, 6, 8, 10, 12, 14, 16, 18, 20, 22, 24, 26 } }; + bb::Univariate expected_alpha{ { 2, 4, 6, 8, 10, 12, 14, 16, 18, 20, 22, 24 } }; for (const auto& alpha : instances.alphas) { EXPECT_EQ(alpha, expected_alpha); } diff --git a/barretenberg/cpp/src/barretenberg/protogalaxy/protogalaxy_prover.cpp b/barretenberg/cpp/src/barretenberg/protogalaxy/protogalaxy_prover.cpp index d7774878347..a1cb41cef73 100644 --- a/barretenberg/cpp/src/barretenberg/protogalaxy/protogalaxy_prover.cpp +++ b/barretenberg/cpp/src/barretenberg/protogalaxy/protogalaxy_prover.cpp @@ -121,6 +121,8 @@ std::shared_ptr ProtoGalaxyProver_{ combined_relation_parameters.eta.evaluate(challenge), + combined_relation_parameters.eta_two.evaluate(challenge), + combined_relation_parameters.eta_three.evaluate(challenge), combined_relation_parameters.beta.evaluate(challenge), combined_relation_parameters.gamma.evaluate(challenge), combined_relation_parameters.public_input_delta.evaluate(challenge), diff --git a/barretenberg/cpp/src/barretenberg/protogalaxy/protogalaxy_verifier.cpp b/barretenberg/cpp/src/barretenberg/protogalaxy/protogalaxy_verifier.cpp index 9d6eb95e88f..b47ba04a292 100644 --- a/barretenberg/cpp/src/barretenberg/protogalaxy/protogalaxy_verifier.cpp +++ b/barretenberg/cpp/src/barretenberg/protogalaxy/protogalaxy_verifier.cpp @@ -146,6 +146,8 @@ std::shared_ptr ProtoGalaxyVerifier_relation_parameters.eta * lagranges[inst_idx]; + expected_parameters.eta_two += instance->relation_parameters.eta_two * lagranges[inst_idx]; + expected_parameters.eta_three += instance->relation_parameters.eta_three * lagranges[inst_idx]; expected_parameters.beta += instance->relation_parameters.beta * lagranges[inst_idx]; expected_parameters.gamma += instance->relation_parameters.gamma * lagranges[inst_idx]; expected_parameters.public_input_delta += diff --git a/barretenberg/cpp/src/barretenberg/relations/auxiliary_relation.hpp b/barretenberg/cpp/src/barretenberg/relations/auxiliary_relation.hpp index 0e97cb1ded2..745508d1415 100644 --- a/barretenberg/cpp/src/barretenberg/relations/auxiliary_relation.hpp +++ b/barretenberg/cpp/src/barretenberg/relations/auxiliary_relation.hpp @@ -41,12 +41,12 @@ template class AuxiliaryRelationImpl { }; static constexpr std::array TOTAL_LENGTH_ADJUSTMENTS{ - 6, // auxiliary sub-relation - 6, // ROM consistency sub-relation 1 - 6, // ROM consistency sub-relation 2 - 6, // RAM consistency sub-relation 1 - 6, // RAM consistency sub-relation 2 - 6 // RAM consistency sub-relation 3 + 1, // auxiliary sub-relation + 1, // ROM consistency sub-relation 1 + 1, // ROM consistency sub-relation 2 + 1, // RAM consistency sub-relation 1 + 1, // RAM consistency sub-relation 2 + 1 // RAM consistency sub-relation 3 }; /** @@ -96,6 +96,8 @@ template class AuxiliaryRelationImpl { using ParameterView = GetParameterView; const auto& eta = ParameterView(params.eta); + const auto& eta_two = ParameterView(params.eta_two); + const auto& eta_three = ParameterView(params.eta_three); auto w_1 = View(in.w_l); auto w_2 = View(in.w_r); @@ -186,13 +188,13 @@ template class AuxiliaryRelationImpl { * * t: `timestamp` of memory cell being accessed (used for RAM, set to 0 for ROM) * * v: `value` of memory cell being accessed * * a: `access` type of record. read: 0 = read, 1 = write - * * r: `record` of memory cell. record = access + index * eta + timestamp * eta^2 + value * eta^3 + * * r: `record` of memory cell. record = access + index * eta + timestamp * η₂ + value * η₃ * * A ROM memory record contains a tuple of the following fields: * * i: `index` of memory cell being accessed * * v: `value1` of memory cell being accessed (ROM tables can store up to 2 values per index) * * v2:`value2` of memory cell being accessed (ROM tables can store up to 2 values per index) - * * r: `record` of memory cell. record = index * eta + value2 * eta^2 + value1 * eta^3 + * * r: `record` of memory cell. record = index * eta + value2 * η₂ + value1 * η₃ * * When performing a read/write access, the values of i, t, v, v2, a, r are stored in the following wires + * selectors, depending on whether the gate is a RAM read/write or a ROM read @@ -210,21 +212,19 @@ template class AuxiliaryRelationImpl { /** * Memory Record Check * Partial degree: 1 - * Total degree: 4 + * Total degree: 2 * * A ROM/ROM access gate can be evaluated with the identity: * - * qc + w1 \eta + w2 \eta^2 + w3 \eta^3 - w4 = 0 + * qc + w1 \eta + w2 η₂ + w3 η₃ - w4 = 0 * * For ROM gates, qc = 0 */ - auto memory_record_check = w_3 * eta; - memory_record_check += w_2; - memory_record_check *= eta; - memory_record_check += w_1; - memory_record_check *= eta; + auto memory_record_check = w_3 * eta_three; + memory_record_check += w_2 * eta_two; + memory_record_check += w_1 * eta; memory_record_check += q_c; - auto partial_record_check = memory_record_check; // used in RAM consistency check; deg 1 or 4 + auto partial_record_check = memory_record_check; // used in RAM consistency check; deg 1 or 2 memory_record_check = memory_record_check - w_4; /** @@ -253,13 +253,13 @@ template class AuxiliaryRelationImpl { adjacent_values_match_if_adjacent_indices_match * (q_1 * q_2) * (q_aux * scaling_factor); // deg 5 std::get<2>(accumulators) += index_is_monotonically_increasing * (q_1 * q_2) * (q_aux * scaling_factor); // deg 5 - auto ROM_consistency_check_identity = memory_record_check * (q_1 * q_2); // deg 3 or 7 + auto ROM_consistency_check_identity = memory_record_check * (q_1 * q_2); // deg 3 or 4 /** * RAM Consistency Check * * The 'access' type of the record is extracted with the expression `w_4 - partial_record_check` - * (i.e. for an honest Prover `w1 * eta + w2 * eta^2 + w3 * eta^3 - w4 = access`. + * (i.e. for an honest Prover `w1 * η + w2 * η₂ + w3 * η₃ - w4 = access`. * This is validated by requiring `access` to be boolean * * For two adjacent entries in the sorted list if _both_ @@ -273,22 +273,20 @@ template class AuxiliaryRelationImpl { * N.B. it is the responsibility of the circuit writer to ensure that every RAM cell is initialized * with a WRITE operation. */ - auto access_type = (w_4 - partial_record_check); // will be 0 or 1 for honest Prover; deg 1 or 4 - auto access_check = access_type * access_type - access_type; // check value is 0 or 1; deg 2 or 8 + auto access_type = (w_4 - partial_record_check); // will be 0 or 1 for honest Prover; deg 1 or 2 + auto access_check = access_type * access_type - access_type; // check value is 0 or 1; deg 2 or 4 // TODO(https://github.com/AztecProtocol/barretenberg/issues/757): If we sorted in - // reverse order we could re-use `partial_record_check` 1 - ((w3' * eta + w2') * eta + w1') * eta - // deg 1 or 4 - auto next_gate_access_type = w_3_shift * eta; - next_gate_access_type += w_2_shift; - next_gate_access_type *= eta; - next_gate_access_type += w_1_shift; - next_gate_access_type *= eta; + // reverse order we could re-use `partial_record_check` 1 - (w3' * eta_three + w2' * eta_two + w1' * + // eta) deg 1 or 2 + auto next_gate_access_type = w_3_shift * eta_three; + next_gate_access_type += w_2_shift * eta_two; + next_gate_access_type += w_1_shift * eta; next_gate_access_type = w_4_shift - next_gate_access_type; auto value_delta = w_3_shift - w_3; auto adjacent_values_match_if_adjacent_indices_match_and_next_access_is_a_read_operation = - (index_delta * FF(-1) + FF(1)) * value_delta * (next_gate_access_type * FF(-1) + FF(1)); // deg 3 or 6 + (index_delta * FF(-1) + FF(1)) * value_delta * (next_gate_access_type * FF(-1) + FF(1)); // deg 3 or 4 // We can't apply the RAM consistency check identity on the final entry in the sorted list (the wires in the // next gate would make the identity fail). We need to validate that its 'access type' bool is correct. Can't @@ -300,11 +298,11 @@ template class AuxiliaryRelationImpl { // Putting it all together... std::get<3>(accumulators) += adjacent_values_match_if_adjacent_indices_match_and_next_access_is_a_read_operation * (q_arith) * - (q_aux * scaling_factor); // deg 5 or 8 + (q_aux * scaling_factor); // deg 5 or 6 std::get<4>(accumulators) += index_is_monotonically_increasing * (q_arith) * (q_aux * scaling_factor); // deg 4 std::get<5>(accumulators) += next_gate_access_type_is_boolean * (q_arith) * (q_aux * scaling_factor); // deg 4 or 6 - auto RAM_consistency_check_identity = access_check * (q_arith); // deg 3 or 9 + auto RAM_consistency_check_identity = access_check * (q_arith); // deg 3 or 5 /** * RAM Timestamp Consistency Check @@ -324,14 +322,14 @@ template class AuxiliaryRelationImpl { * The complete RAM/ROM memory identity * Partial degree: */ - auto memory_identity = ROM_consistency_check_identity; // deg 3 or 6 + auto memory_identity = ROM_consistency_check_identity; // deg 3 or 4 memory_identity += RAM_timestamp_check_identity * (q_4 * q_1); // deg 4 - memory_identity += memory_record_check * (q_m * q_1); // deg 3 or 6 - memory_identity += RAM_consistency_check_identity; // deg 3 or 9 + memory_identity += memory_record_check * (q_m * q_1); // deg 3 or 4 + memory_identity += RAM_consistency_check_identity; // deg 3 or 5 - // (deg 3 or 9) + (deg 4) + (deg 3) + // (deg 3 or 5) + (deg 4) + (deg 3) auto auxiliary_identity = memory_identity + non_native_field_identity + limb_accumulator_identity; - auxiliary_identity *= (q_aux * scaling_factor); // deg 4 or 10 + auxiliary_identity *= (q_aux * scaling_factor); // deg 5 or 6 std::get<0>(accumulators) += auxiliary_identity; }; }; diff --git a/barretenberg/cpp/src/barretenberg/relations/lookup_relation.hpp b/barretenberg/cpp/src/barretenberg/relations/lookup_relation.hpp index c4d1e9342ad..a9a4bd3fb47 100644 --- a/barretenberg/cpp/src/barretenberg/relations/lookup_relation.hpp +++ b/barretenberg/cpp/src/barretenberg/relations/lookup_relation.hpp @@ -28,7 +28,7 @@ template class LookupRelationImpl { }; static constexpr std::array TOTAL_LENGTH_ADJUSTMENTS{ - 6, // grand product construction sub-relation + 4, // grand product construction sub-relation 0 // left-shiftable polynomial sub-relation }; /** @@ -67,8 +67,8 @@ template class LookupRelationImpl { const auto& beta = ParameterView(params.beta); const auto& gamma = ParameterView(params.gamma); const auto& eta = ParameterView(params.eta); - const auto eta_sqr = eta * eta; - const auto eta_cube = eta_sqr * eta; + const auto& eta_two = ParameterView(params.eta_two); + const auto& eta_three = ParameterView(params.eta_three); const auto one_plus_beta = beta + FF(1); const auto gamma_by_one_plus_beta = gamma * one_plus_beta; @@ -97,24 +97,24 @@ template class LookupRelationImpl { auto column_3_step_size = View(in.q_c); auto q_lookup = View(in.q_lookup); - // (w_1 + q_2*w_1_shift) + η(w_2 + q_m*w_2_shift) + η²(w_3 + q_c*w_3_shift) + η³q_index. - // deg 2 or 4 + // (w_1 + q_2*w_1_shift) + η(w_2 + q_m*w_2_shift) + η₂(w_3 + q_c*w_3_shift) + η₃q_index. + // deg 2 or 3 auto wire_accum = (w_1 + column_1_step_size * w_1_shift) + (w_2 + column_2_step_size * w_2_shift) * eta + - (w_3 + column_3_step_size * w_3_shift) * eta_sqr + table_index * eta_cube; + (w_3 + column_3_step_size * w_3_shift) * eta_two + table_index * eta_three; - // t_1 + ηt_2 + η²t_3 + η³t_4 - // deg 1 or 4 - auto table_accum = table_1 + table_2 * eta + table_3 * eta_sqr + table_4 * eta_cube; + // t_1 + ηt_2 + η₂t_3 + η₃t_4 + // deg 1 or 2 + auto table_accum = table_1 + table_2 * eta + table_3 * eta_two + table_4 * eta_three; - // t_1_shift + ηt_2_shift + η²t_3_shift + η³t_4_shift - // deg 4 + // t_1_shift + ηt_2_shift + η₂t_3_shift + η₃t_4_shift + // deg 1 or 2 auto table_accum_shift = - table_1_shift + table_2_shift * eta + table_3_shift * eta_sqr + table_4_shift * eta_cube; + table_1_shift + table_2_shift * eta + table_3_shift * eta_two + table_4_shift * eta_three; - auto tmp = (q_lookup * wire_accum + gamma); // deg 2 or 4 - tmp *= (table_accum + table_accum_shift * beta + gamma_by_one_plus_beta); // 1 or 5 - tmp *= one_plus_beta; // deg 1 - return tmp; // deg 4 or 10 + auto tmp = (q_lookup * wire_accum + gamma); // deg 3 or 4 + tmp *= (table_accum + table_accum_shift * beta + gamma_by_one_plus_beta); // 1 or 3 + tmp *= one_plus_beta; // deg 0 or 1 + return tmp; // deg 4 or 8 } /** @@ -186,10 +186,10 @@ template class LookupRelationImpl { auto lagrange_first = View(in.lagrange_first); auto lagrange_last = View(in.lagrange_last); - const auto lhs = compute_grand_product_numerator(in, params); // deg 4 or 10 + const auto lhs = compute_grand_product_numerator(in, params); // deg 4 or 8 const auto rhs = compute_grand_product_denominator(in, params); // deg 1 or 2 - // (deg 5 or 11) - (deg 3 or 5) + // (deg 5 or 9) - (deg 3 or 5) const auto tmp = lhs * (z_lookup + lagrange_first) - rhs * (z_lookup_shift + lagrange_last * grand_product_delta); std::get<0>(accumulators) += tmp * scaling_factor; diff --git a/barretenberg/cpp/src/barretenberg/relations/relation_parameters.hpp b/barretenberg/cpp/src/barretenberg/relations/relation_parameters.hpp index b6b71fed365..70573ad8626 100644 --- a/barretenberg/cpp/src/barretenberg/relations/relation_parameters.hpp +++ b/barretenberg/cpp/src/barretenberg/relations/relation_parameters.hpp @@ -15,7 +15,9 @@ template struct RelationParameters { static constexpr int NUM_BINARY_LIMBS_IN_GOBLIN_TRANSLATOR = 4; static constexpr int NUM_NATIVE_LIMBS_IN_GOBLIN_TRANSLATOR = 1; static constexpr int NUM_CHALLENGE_POWERS_IN_GOBLIN_TRANSLATOR = 4; - T eta = T(0); // Lookup + T eta = T(0); // Lookup + Aux Memory + T eta_two = T(0); // Lookup + Aux Memory + T eta_three = T(0); // Lookup + Aux Memory T beta = T(0); // Permutation + Lookup T gamma = T(0); // Permutation + Lookup T public_input_delta = T(0); // Permutation @@ -38,13 +40,17 @@ template struct RelationParameters { { T(0), T(0), T(0), T(0), T(0) }, { T(0), T(0), T(0), T(0), T(0) } } }; - static constexpr int NUM_TO_FOLD = 5; - auto get_to_fold() { return RefArray{ eta, beta, gamma, public_input_delta, lookup_grand_product_delta }; } + auto get_to_fold() + { + return RefArray{ eta, eta_two, eta_three, beta, gamma, public_input_delta, lookup_grand_product_delta }; + } static RelationParameters get_random() { RelationParameters result; result.eta = T::random_element(); + result.eta_two = T::random_element(); + result.eta_three = T::random_element(); result.beta = T::random_element(); result.beta_sqr = result.beta * result.beta; result.beta_cube = result.beta_sqr * result.beta; diff --git a/barretenberg/cpp/src/barretenberg/relations/ultra_relation_consistency.test.cpp b/barretenberg/cpp/src/barretenberg/relations/ultra_relation_consistency.test.cpp index 79e7349d6b8..0406f82bcef 100644 --- a/barretenberg/cpp/src/barretenberg/relations/ultra_relation_consistency.test.cpp +++ b/barretenberg/cpp/src/barretenberg/relations/ultra_relation_consistency.test.cpp @@ -248,6 +248,8 @@ TEST_F(UltraRelationConsistency, LookupRelation) const auto parameters = RelationParameters::get_random(); const auto eta = parameters.eta; + const auto eta_two = parameters.eta_two; + const auto eta_three = parameters.eta_three; const auto beta = parameters.beta; const auto gamma = parameters.gamma; auto grand_product_delta = parameters.lookup_grand_product_delta; @@ -255,15 +257,13 @@ TEST_F(UltraRelationConsistency, LookupRelation) // Extract the extended edges for manual computation of relation contribution auto one_plus_beta = FF::one() + beta; auto gamma_by_one_plus_beta = gamma * one_plus_beta; - auto eta_sqr = eta * eta; - auto eta_cube = eta_sqr * eta; auto wire_accum = (w_1 + column_1_step_size * w_1_shift) + (w_2 + column_2_step_size * w_2_shift) * eta + - (w_3 + column_3_step_size * w_3_shift) * eta_sqr + table_index * eta_cube; + (w_3 + column_3_step_size * w_3_shift) * eta_two + table_index * eta_three; - auto table_accum = table_1 + table_2 * eta + table_3 * eta_sqr + table_4 * eta_cube; + auto table_accum = table_1 + table_2 * eta + table_3 * eta_two + table_4 * eta_three; auto table_accum_shift = - table_1_shift + table_2_shift * eta + table_3_shift * eta_sqr + table_4_shift * eta_cube; + table_1_shift + table_2_shift * eta + table_3_shift * eta_two + table_4_shift * eta_three; // Contribution 1 auto contribution_1 = (z_lookup + lagrange_first) * (q_lookup * wire_accum + gamma) * @@ -417,6 +417,8 @@ TEST_F(UltraRelationConsistency, AuxiliaryRelation) const auto parameters = RelationParameters::get_random(); const auto& eta = parameters.eta; + const auto& eta_two = parameters.eta_two; + const auto& eta_three = parameters.eta_three; SumcheckArrayOfValuesOverSubrelations expected_values; /** @@ -463,12 +465,9 @@ TEST_F(UltraRelationConsistency, AuxiliaryRelation) /** * Memory Record Check */ - auto memory_record_check = w_3; - memory_record_check *= eta; - memory_record_check += w_2; - memory_record_check *= eta; - memory_record_check += w_1; - memory_record_check *= eta; + auto memory_record_check = w_3 * eta_three; + memory_record_check += w_2 * eta_two; + memory_record_check += w_1 * eta; memory_record_check += q_c; auto partial_record_check = memory_record_check; // used in RAM consistency check memory_record_check = memory_record_check - w_4; @@ -494,12 +493,9 @@ TEST_F(UltraRelationConsistency, AuxiliaryRelation) auto access_type = (w_4 - partial_record_check); // will be 0 or 1 for honest Prover auto access_check = access_type * access_type - access_type; // check value is 0 or 1 - auto next_gate_access_type = w_3_shift; - next_gate_access_type *= eta; - next_gate_access_type += w_2_shift; - next_gate_access_type *= eta; - next_gate_access_type += w_1_shift; - next_gate_access_type *= eta; + auto next_gate_access_type = w_3_shift * eta_three; + next_gate_access_type += w_2_shift * eta_two; + next_gate_access_type += w_1_shift * eta; next_gate_access_type = w_4_shift - next_gate_access_type; auto value_delta = w_3_shift - w_3; diff --git a/barretenberg/cpp/src/barretenberg/stdlib/honk_recursion/verifier/protogalaxy_recursive_verifier.cpp b/barretenberg/cpp/src/barretenberg/stdlib/honk_recursion/verifier/protogalaxy_recursive_verifier.cpp index 6fd55434863..f1b50360f94 100644 --- a/barretenberg/cpp/src/barretenberg/stdlib/honk_recursion/verifier/protogalaxy_recursive_verifier.cpp +++ b/barretenberg/cpp/src/barretenberg/stdlib/honk_recursion/verifier/protogalaxy_recursive_verifier.cpp @@ -50,7 +50,8 @@ void ProtoGalaxyRecursiveVerifier_::receive_and_finalise_inst } // Get challenge for sorted list batching and wire four memory records commitment - auto eta = transcript->template get_challenge(domain_separator + "_eta"); + auto [eta, eta_two, eta_three] = transcript->template get_challenges( + domain_separator + "_eta", domain_separator + "_eta_two", domain_separator + "_eta_three"); witness_commitments.sorted_accum = transcript->template receive_from_prover(domain_separator + "_" + labels.sorted_accum); witness_commitments.w_4 = transcript->template receive_from_prover(domain_separator + "_" + labels.w_4); @@ -79,7 +80,7 @@ void ProtoGalaxyRecursiveVerifier_::receive_and_finalise_inst const FF lookup_grand_product_delta = compute_lookup_grand_product_delta(beta, gamma, inst->verification_key->circuit_size); inst->relation_parameters = - RelationParameters{ eta, beta, gamma, public_input_delta, lookup_grand_product_delta }; + RelationParameters{ eta, eta_two, eta_three, beta, gamma, public_input_delta, lookup_grand_product_delta }; // Get the relation separation challenges for (size_t idx = 0; idx < NUM_SUBRELATIONS - 1; idx++) { @@ -222,6 +223,8 @@ std::shared_ptr ProtoGalaxyRecursiveVerifi for (size_t inst_idx = 0; inst_idx < VerifierInstances::NUM; inst_idx++) { auto instance = instances[inst_idx]; expected_parameters.eta += instance->relation_parameters.eta * lagranges[inst_idx]; + expected_parameters.eta_two += instance->relation_parameters.eta_two * lagranges[inst_idx]; + expected_parameters.eta_three += instance->relation_parameters.eta_three * lagranges[inst_idx]; expected_parameters.beta += instance->relation_parameters.beta * lagranges[inst_idx]; expected_parameters.gamma += instance->relation_parameters.gamma * lagranges[inst_idx]; expected_parameters.public_input_delta += diff --git a/barretenberg/cpp/src/barretenberg/stdlib/honk_recursion/verifier/recursive_verifier_instance.hpp b/barretenberg/cpp/src/barretenberg/stdlib/honk_recursion/verifier/recursive_verifier_instance.hpp index 12a54f89169..16ccfe6c4e5 100644 --- a/barretenberg/cpp/src/barretenberg/stdlib/honk_recursion/verifier/recursive_verifier_instance.hpp +++ b/barretenberg/cpp/src/barretenberg/stdlib/honk_recursion/verifier/recursive_verifier_instance.hpp @@ -84,6 +84,8 @@ template class RecursiveVerifierInstance_ { challenge_idx++; } relation_parameters.eta = FF::from_witness(builder, instance->relation_parameters.eta); + relation_parameters.eta_two = FF::from_witness(builder, instance->relation_parameters.eta_two); + relation_parameters.eta_three = FF::from_witness(builder, instance->relation_parameters.eta_three); relation_parameters.beta = FF::from_witness(builder, instance->relation_parameters.beta); relation_parameters.gamma = FF::from_witness(builder, instance->relation_parameters.gamma); relation_parameters.public_input_delta = @@ -131,6 +133,8 @@ template class RecursiveVerifierInstance_ { } inst.relation_parameters.eta = relation_parameters.eta.get_value(); + inst.relation_parameters.eta_two = relation_parameters.eta_two.get_value(); + inst.relation_parameters.eta_three = relation_parameters.eta_three.get_value(); inst.relation_parameters.beta = relation_parameters.beta.get_value(); inst.relation_parameters.gamma = relation_parameters.gamma.get_value(); inst.relation_parameters.public_input_delta = relation_parameters.public_input_delta.get_value(); diff --git a/barretenberg/cpp/src/barretenberg/stdlib/honk_recursion/verifier/ultra_recursive_verifier.cpp b/barretenberg/cpp/src/barretenberg/stdlib/honk_recursion/verifier/ultra_recursive_verifier.cpp index 334ad876caf..cf97878c6d7 100644 --- a/barretenberg/cpp/src/barretenberg/stdlib/honk_recursion/verifier/ultra_recursive_verifier.cpp +++ b/barretenberg/cpp/src/barretenberg/stdlib/honk_recursion/verifier/ultra_recursive_verifier.cpp @@ -71,8 +71,10 @@ std::array UltraRecursiveVerifier_::ve } // Get challenge for sorted list batching and wire four memory records - auto eta = transcript->template get_challenge("eta"); + auto [eta, eta_two, eta_three] = transcript->template get_challenges("eta", "eta_two", "eta_three"); relation_parameters.eta = eta; + relation_parameters.eta_two = eta_two; + relation_parameters.eta_three = eta_three; // Get commitments to sorted list accumulator and fourth wire commitments.sorted_accum = transcript->template receive_from_prover(commitment_labels.sorted_accum); diff --git a/barretenberg/cpp/src/barretenberg/stdlib/plonk_recursion/verifier/verifier.test.cpp b/barretenberg/cpp/src/barretenberg/stdlib/plonk_recursion/verifier/verifier.test.cpp index 4223324ed25..ade9940d9dc 100644 --- a/barretenberg/cpp/src/barretenberg/stdlib/plonk_recursion/verifier/verifier.test.cpp +++ b/barretenberg/cpp/src/barretenberg/stdlib/plonk_recursion/verifier/verifier.test.cpp @@ -348,8 +348,14 @@ template class stdlib_verifier : public testing::Test { static void check_recursive_verification_circuit(OuterBuilder& outer_circuit, bool expected_result) { info("number of gates in recursive verification circuit = ", outer_circuit.get_num_gates()); - bool result = CircuitChecker::check(outer_circuit); + OuterComposer outer_composer; + auto prover = outer_composer.create_prover(outer_circuit); + auto verifier = outer_composer.create_verifier(outer_circuit); + auto proof = prover.construct_proof(); + auto result = verifier.verify_proof(proof); + // bool result = CircuitChecker::check(outer_circuit); EXPECT_EQ(result, expected_result); + static_cast(expected_result); auto g2_lines = srs::get_bn254_crs_factory()->get_verifier_crs()->get_precomputed_g2_lines(); EXPECT_EQ(check_recursive_proof_public_inputs(outer_circuit, g2_lines), true); } @@ -366,7 +372,13 @@ template class stdlib_verifier : public testing::Test { create_inner_circuit(builder, inputs); - bool result = CircuitChecker::check(builder); + InnerComposer inner_composer; + + auto prover = inner_composer.create_prover(builder); + auto verifier = inner_composer.create_verifier(builder); + auto proof = prover.construct_proof(); + auto result = verifier.verify_proof(proof); + EXPECT_EQ(result, true); } @@ -567,9 +579,9 @@ template class stdlib_verifier : public testing::Test { } }; -typedef testing::Types OuterCircuitTypes; +typedef testing::Types OuterComposerTypes; -TYPED_TEST_SUITE(stdlib_verifier, OuterCircuitTypes); +TYPED_TEST_SUITE(stdlib_verifier, OuterComposerTypes); HEAVY_TYPED_TEST(stdlib_verifier, test_inner_circuit) { diff --git a/barretenberg/cpp/src/barretenberg/stdlib_circuit_builders/goblin_ultra_flavor.hpp b/barretenberg/cpp/src/barretenberg/stdlib_circuit_builders/goblin_ultra_flavor.hpp index 192cdd12e39..4eb513ae5a5 100644 --- a/barretenberg/cpp/src/barretenberg/stdlib_circuit_builders/goblin_ultra_flavor.hpp +++ b/barretenberg/cpp/src/barretenberg/stdlib_circuit_builders/goblin_ultra_flavor.hpp @@ -280,6 +280,15 @@ class GoblinUltraFlavor { // The plookup wires that store plookup read data. auto get_table_column_wires() { return RefArray{ w_l, w_r, w_o }; }; + void compute_sorted_accumulator_polynomials(const FF& eta, const FF& eta_two, const FF& eta_three) + { + // Compute sorted witness-table accumulator + compute_sorted_list_accumulator(eta, eta_two, eta_three); + + // Finalize fourth wire polynomial by adding lookup memory records + add_plookup_memory_records_to_wire_4(eta, eta_two, eta_three); + } + /** * @brief Construct sorted list accumulator polynomial 's'. * @@ -291,33 +300,20 @@ class GoblinUltraFlavor { * @param eta random challenge * @return Polynomial */ - void compute_sorted_list_accumulator(const FF& eta) + void compute_sorted_list_accumulator(const FF& eta, const FF& eta_two, const FF& eta_three) { - const size_t circuit_size = this->circuit_size; - auto sorted_list_accumulator = Polynomial{ circuit_size }; + auto sorted_list_accumulator = Polynomial{ this->circuit_size }; // Construct s via Horner, i.e. s = s_1 + η(s_2 + η(s_3 + η*s_4)) - for (size_t i = 0; i < circuit_size; ++i) { - FF T0 = this->sorted_polynomials[3][i]; - T0 *= eta; - T0 += this->sorted_polynomials[2][i]; - T0 *= eta; - T0 += this->sorted_polynomials[1][i]; - T0 *= eta; - T0 += this->sorted_polynomials[0][i]; + for (size_t i = 0; i < this->circuit_size; ++i) { + FF T0 = sorted_polynomials[3][i] * eta_three; + T0 += sorted_polynomials[2][i] * eta_two; + T0 += sorted_polynomials[1][i] * eta; + T0 += sorted_polynomials[0][i]; sorted_list_accumulator[i] = T0; } - this->sorted_accum = sorted_list_accumulator.share(); - } - - void compute_sorted_accumulator_polynomials(const FF& eta) - { - // Compute sorted witness-table accumulator - this->compute_sorted_list_accumulator(eta); - - // Finalize fourth wire polynomial by adding lookup memory records - add_plookup_memory_records_to_wire_4(eta); + sorted_accum = sorted_list_accumulator.share(); } /** @@ -329,31 +325,25 @@ class GoblinUltraFlavor { * @tparam Flavor * @param eta challenge produced after commitment to first three wire polynomials */ - void add_plookup_memory_records_to_wire_4(const FF& eta) + void add_plookup_memory_records_to_wire_4(const FF& eta, const FF& eta_two, const FF& eta_three) { // The plookup memory record values are computed at the indicated indices as // w4 = w3 * eta^3 + w2 * eta^2 + w1 * eta + read_write_flag; // (See plookup_auxiliary_widget.hpp for details) - auto wires = this->get_wires(); + auto wires = get_wires(); // Compute read record values - for (const auto& gate_idx : this->memory_read_records) { - wires[3][gate_idx] += wires[2][gate_idx]; - wires[3][gate_idx] *= eta; - wires[3][gate_idx] += wires[1][gate_idx]; - wires[3][gate_idx] *= eta; - wires[3][gate_idx] += wires[0][gate_idx]; - wires[3][gate_idx] *= eta; + for (const auto& gate_idx : memory_read_records) { + wires[3][gate_idx] += wires[2][gate_idx] * eta_three; + wires[3][gate_idx] += wires[1][gate_idx] * eta_two; + wires[3][gate_idx] += wires[0][gate_idx] * eta; } // Compute write record values - for (const auto& gate_idx : this->memory_write_records) { - wires[3][gate_idx] += wires[2][gate_idx]; - wires[3][gate_idx] *= eta; - wires[3][gate_idx] += wires[1][gate_idx]; - wires[3][gate_idx] *= eta; - wires[3][gate_idx] += wires[0][gate_idx]; - wires[3][gate_idx] *= eta; + for (const auto& gate_idx : memory_write_records) { + wires[3][gate_idx] += wires[2][gate_idx] * eta_three; + wires[3][gate_idx] += wires[1][gate_idx] * eta_two; + wires[3][gate_idx] += wires[0][gate_idx] * eta; wires[3][gate_idx] += 1; } } diff --git a/barretenberg/cpp/src/barretenberg/stdlib_circuit_builders/grand_product_library.test.cpp b/barretenberg/cpp/src/barretenberg/stdlib_circuit_builders/grand_product_library.test.cpp index 55edddad961..7a2ef577349 100644 --- a/barretenberg/cpp/src/barretenberg/stdlib_circuit_builders/grand_product_library.test.cpp +++ b/barretenberg/cpp/src/barretenberg/stdlib_circuit_builders/grand_product_library.test.cpp @@ -228,9 +228,13 @@ template class GrandProductTests : public testing::Test { auto beta = FF::random_element(); auto gamma = FF::random_element(); auto eta = FF::random_element(); + auto eta_two = FF::random_element(); + auto eta_three = FF::random_element(); RelationParameters params{ .eta = eta, + .eta_two = eta_two, + .eta_three = eta_three, .beta = beta, .gamma = gamma, .public_input_delta = 1, @@ -267,8 +271,6 @@ template class GrandProductTests : public testing::Test { // ∏(s_k + βs_{k+1} + γ(1 + β)) // // in a way that is simple to read (but inefficient). See prover library method for more details. - const FF eta_sqr = eta.sqr(); - const FF eta_cube = eta_sqr * eta; std::array accumulators; for (size_t i = 0; i < 4; ++i) { @@ -280,22 +282,22 @@ template class GrandProductTests : public testing::Test { // Note: block_mask is used for efficient modulus, i.e. i % N := i & (N-1), for N = 2^k const size_t block_mask = circuit_size - 1; // Initialize 't(X)' to be used in an expression of the form t(X) + β*t(Xω) - FF table_i = tables[0][0] + tables[1][0] * eta + tables[2][0] * eta_sqr + tables[3][0] * eta_cube; + FF table_i = tables[0][0] + tables[1][0] * eta + tables[2][0] * eta_two + tables[3][0] * eta_three; for (size_t i = 0; i < circuit_size; ++i) { size_t shift_idx = (i + 1) & block_mask; // f = (w_1 + q_2*w_1(Xω)) + η(w_2 + q_m*w_2(Xω)) + η²(w_3 + q_c*w_3(Xω)) + η³q_index. FF f_i = (wires[0][i] + wires[0][shift_idx] * column_1_step_size[i]) + (wires[1][i] + wires[1][shift_idx] * column_2_step_size[i]) * eta + - (wires[2][i] + wires[2][shift_idx] * column_3_step_size[i]) * eta_sqr + - eta_cube * lookup_index_selector[i]; + (wires[2][i] + wires[2][shift_idx] * column_3_step_size[i]) * eta_two + + eta_three * lookup_index_selector[i]; // q_lookup * f + γ accumulators[0][i] = lookup_selector[i] * f_i + gamma; // t = t_1 + ηt_2 + η²t_3 + η³t_4 - FF table_i_plus_1 = tables[0][shift_idx] + eta * tables[1][shift_idx] + eta_sqr * tables[2][shift_idx] + - eta_cube * tables[3][shift_idx]; + FF table_i_plus_1 = tables[0][shift_idx] + eta * tables[1][shift_idx] + eta_two * tables[2][shift_idx] + + eta_three * tables[3][shift_idx]; // t + βt(Xω) + γ(1 + β) accumulators[1][i] = table_i + table_i_plus_1 * beta + gamma * (FF::one() + beta); diff --git a/barretenberg/cpp/src/barretenberg/stdlib_circuit_builders/ultra_flavor.hpp b/barretenberg/cpp/src/barretenberg/stdlib_circuit_builders/ultra_flavor.hpp index 99bc3ad94b9..1e29d4a5ccb 100644 --- a/barretenberg/cpp/src/barretenberg/stdlib_circuit_builders/ultra_flavor.hpp +++ b/barretenberg/cpp/src/barretenberg/stdlib_circuit_builders/ultra_flavor.hpp @@ -58,7 +58,7 @@ class UltraFlavor { static constexpr size_t MAX_PARTIAL_RELATION_LENGTH = compute_max_partial_relation_length(); static_assert(MAX_PARTIAL_RELATION_LENGTH == 6); static constexpr size_t MAX_TOTAL_RELATION_LENGTH = compute_max_total_relation_length(); - static_assert(MAX_TOTAL_RELATION_LENGTH == 12); + static_assert(MAX_TOTAL_RELATION_LENGTH == 11); static constexpr size_t NUM_SUBRELATIONS = compute_number_of_subrelations(); // For instances of this flavour, used in folding, we need a unique sumcheck batching challenge for each // subrelation. This is because using powers of alpha would increase the degree of Protogalaxy polynomial $G$ (the @@ -287,6 +287,15 @@ class UltraFlavor { // The plookup wires that store plookup read data. auto get_table_column_wires() { return RefArray{ w_l, w_r, w_o }; }; + void compute_sorted_accumulator_polynomials(const FF& eta, const FF& eta_two, const FF& eta_three) + { + // Compute sorted witness-table accumulator + compute_sorted_list_accumulator(eta, eta_two, eta_three); + + // Finalize fourth wire polynomial by adding lookup memory records + add_plookup_memory_records_to_wire_4(eta, eta_two, eta_three); + } + /** * @brief Construct sorted list accumulator polynomial 's'. * @@ -298,33 +307,19 @@ class UltraFlavor { * @param eta random challenge * @return Polynomial */ - void compute_sorted_list_accumulator(const FF& eta) + void compute_sorted_list_accumulator(const FF& eta, const FF& eta_two, const FF& eta_three) { - const size_t circuit_size = this->circuit_size; - - auto sorted_list_accumulator = Polynomial{ circuit_size }; + auto sorted_list_accumulator = Polynomial{ this->circuit_size }; // Construct s via Horner, i.e. s = s_1 + η(s_2 + η(s_3 + η*s_4)) - for (size_t i = 0; i < circuit_size; ++i) { - FF T0 = this->sorted_polynomials[3][i]; - T0 *= eta; - T0 += this->sorted_polynomials[2][i]; - T0 *= eta; - T0 += this->sorted_polynomials[1][i]; - T0 *= eta; - T0 += this->sorted_polynomials[0][i]; + for (size_t i = 0; i < this->circuit_size; ++i) { + FF T0 = sorted_polynomials[3][i] * eta_three; + T0 += sorted_polynomials[2][i] * eta_two; + T0 += sorted_polynomials[1][i] * eta; + T0 += sorted_polynomials[0][i]; sorted_list_accumulator[i] = T0; } - this->sorted_accum = sorted_list_accumulator.share(); - } - - void compute_sorted_accumulator_polynomials(const FF& eta) - { - // Compute sorted witness-table accumulator - this->compute_sorted_list_accumulator(eta); - - // Finalize fourth wire polynomial by adding lookup memory records - add_plookup_memory_records_to_wire_4(eta); + sorted_accum = sorted_list_accumulator.share(); } /** @@ -336,31 +331,25 @@ class UltraFlavor { * @tparam Flavor * @param eta challenge produced after commitment to first three wire polynomials */ - void add_plookup_memory_records_to_wire_4(const FF& eta) + void add_plookup_memory_records_to_wire_4(const FF& eta, const FF& eta_two, const FF& eta_three) { // The plookup memory record values are computed at the indicated indices as // w4 = w3 * eta^3 + w2 * eta^2 + w1 * eta + read_write_flag; // (See plookup_auxiliary_widget.hpp for details) - auto wires = this->get_wires(); + auto wires = get_wires(); // Compute read record values - for (const auto& gate_idx : this->memory_read_records) { - wires[3][gate_idx] += wires[2][gate_idx]; - wires[3][gate_idx] *= eta; - wires[3][gate_idx] += wires[1][gate_idx]; - wires[3][gate_idx] *= eta; - wires[3][gate_idx] += wires[0][gate_idx]; - wires[3][gate_idx] *= eta; + for (const auto& gate_idx : memory_read_records) { + wires[3][gate_idx] += wires[2][gate_idx] * eta_three; + wires[3][gate_idx] += wires[1][gate_idx] * eta_two; + wires[3][gate_idx] += wires[0][gate_idx] * eta; } // Compute write record values - for (const auto& gate_idx : this->memory_write_records) { - wires[3][gate_idx] += wires[2][gate_idx]; - wires[3][gate_idx] *= eta; - wires[3][gate_idx] += wires[1][gate_idx]; - wires[3][gate_idx] *= eta; - wires[3][gate_idx] += wires[0][gate_idx]; - wires[3][gate_idx] *= eta; + for (const auto& gate_idx : memory_write_records) { + wires[3][gate_idx] += wires[2][gate_idx] * eta_three; + wires[3][gate_idx] += wires[1][gate_idx] * eta_two; + wires[3][gate_idx] += wires[0][gate_idx] * eta; wires[3][gate_idx] += 1; } } diff --git a/barretenberg/cpp/src/barretenberg/stdlib_circuit_builders/ultra_recursive_flavor.hpp b/barretenberg/cpp/src/barretenberg/stdlib_circuit_builders/ultra_recursive_flavor.hpp index 85120696e25..bf220475341 100644 --- a/barretenberg/cpp/src/barretenberg/stdlib_circuit_builders/ultra_recursive_flavor.hpp +++ b/barretenberg/cpp/src/barretenberg/stdlib_circuit_builders/ultra_recursive_flavor.hpp @@ -81,7 +81,7 @@ template class UltraRecursiveFlavor_ { static constexpr size_t MAX_PARTIAL_RELATION_LENGTH = compute_max_partial_relation_length(); static_assert(MAX_PARTIAL_RELATION_LENGTH == 6); static constexpr size_t MAX_TOTAL_RELATION_LENGTH = compute_max_total_relation_length(); - static_assert(MAX_TOTAL_RELATION_LENGTH == 12); + static_assert(MAX_TOTAL_RELATION_LENGTH == 11); // BATCHED_RELATION_PARTIAL_LENGTH = algebraic degree of sumcheck relation *after* multiplying by the `pow_zeta` // random polynomial e.g. For \sum(x) [A(x) * B(x) + C(x)] * PowZeta(X), relation length = 2 and random relation diff --git a/barretenberg/cpp/src/barretenberg/sumcheck/instance/prover_instance.test.cpp b/barretenberg/cpp/src/barretenberg/sumcheck/instance/prover_instance.test.cpp index bd45fe665f0..c4f9a0966e7 100644 --- a/barretenberg/cpp/src/barretenberg/sumcheck/instance/prover_instance.test.cpp +++ b/barretenberg/cpp/src/barretenberg/sumcheck/instance/prover_instance.test.cpp @@ -59,23 +59,21 @@ template class InstanceTests : public testing::Test { // Get random challenge eta auto eta = FF::random_element(); + auto eta_two = FF::random_element(); + auto eta_three = FF::random_element(); auto sorted_list_polynomials = instance.proving_key->sorted_polynomials; // Method 1: computed sorted list accumulator polynomial using prover library method - instance.proving_key->compute_sorted_list_accumulator(eta); + instance.proving_key->compute_sorted_list_accumulator(eta, eta_two, eta_three); auto sorted_list_accumulator = instance.proving_key->sorted_accum; - // Method 2: Compute local sorted list accumulator simply and inefficiently - const FF eta_sqr = eta.sqr(); - const FF eta_cube = eta_sqr * eta; - // Compute s = s_1 + η*s_2 + η²*s_3 + η³*s_4 Polynomial sorted_list_accumulator_expected{ sorted_list_polynomials[0] }; for (size_t i = 0; i < instance.proving_key->circuit_size; ++i) { sorted_list_accumulator_expected[i] += sorted_list_polynomials[1][i] * eta + - sorted_list_polynomials[2][i] * eta_sqr + - sorted_list_polynomials[3][i] * eta_cube; + sorted_list_polynomials[2][i] * eta_two + + sorted_list_polynomials[3][i] * eta_three; } EXPECT_EQ(sorted_list_accumulator, sorted_list_accumulator_expected); diff --git a/barretenberg/cpp/src/barretenberg/ultra_honk/goblin_ultra_transcript.test.cpp b/barretenberg/cpp/src/barretenberg/ultra_honk/goblin_ultra_transcript.test.cpp index 82370a525e5..64d10ee0f25 100644 --- a/barretenberg/cpp/src/barretenberg/ultra_honk/goblin_ultra_transcript.test.cpp +++ b/barretenberg/cpp/src/barretenberg/ultra_honk/goblin_ultra_transcript.test.cpp @@ -60,7 +60,7 @@ class GoblinUltraTranscriptTests : public ::testing::Test { manifest_expected.add_entry(round, "ECC_OP_WIRE_4", frs_per_G); manifest_expected.add_entry(round, "CALLDATA", frs_per_G); manifest_expected.add_entry(round, "CALLDATA_READ_COUNTS", frs_per_G); - manifest_expected.add_challenge(round, "eta"); + manifest_expected.add_challenge(round, "eta", "eta_two", "eta_three"); round++; manifest_expected.add_entry(round, "SORTED_ACCUM", frs_per_G); diff --git a/barretenberg/cpp/src/barretenberg/ultra_honk/oink_prover.cpp b/barretenberg/cpp/src/barretenberg/ultra_honk/oink_prover.cpp index 1a8a8d123d0..b5a5047443b 100644 --- a/barretenberg/cpp/src/barretenberg/ultra_honk/oink_prover.cpp +++ b/barretenberg/cpp/src/barretenberg/ultra_honk/oink_prover.cpp @@ -98,8 +98,14 @@ template void OinkProver::execute_wire_commitment template void OinkProver::execute_sorted_list_accumulator_round() { - relation_parameters.eta = transcript->template get_challenge(domain_separator + "eta"); - proving_key->compute_sorted_accumulator_polynomials(relation_parameters.eta); + auto [eta, eta_two, eta_three] = transcript->template get_challenges( + domain_separator + "eta", domain_separator + "eta_two", domain_separator + "eta_three"); + relation_parameters.eta = eta; + relation_parameters.eta_two = eta_two; + relation_parameters.eta_three = eta_three; + + proving_key->compute_sorted_accumulator_polynomials( + relation_parameters.eta, relation_parameters.eta_two, relation_parameters.eta_three); // Commit to the sorted witness-table accumulator and the finalized (i.e. with memory records) fourth wire // polynomial witness_commitments.sorted_accum = commitment_key->commit(proving_key->sorted_accum); diff --git a/barretenberg/cpp/src/barretenberg/ultra_honk/oink_verifier.cpp b/barretenberg/cpp/src/barretenberg/ultra_honk/oink_verifier.cpp index a79e610c7a7..47c21e9bb42 100644 --- a/barretenberg/cpp/src/barretenberg/ultra_honk/oink_verifier.cpp +++ b/barretenberg/cpp/src/barretenberg/ultra_honk/oink_verifier.cpp @@ -82,9 +82,11 @@ template void OinkVerifier::execute_wire_commitme template void OinkVerifier::execute_sorted_list_accumulator_round() { // Get challenge for sorted list batching and wire four memory records - FF eta = transcript->template get_challenge(domain_separator + "eta"); + auto [eta, eta_two, eta_three] = transcript->template get_challenges( + domain_separator + "eta", domain_separator + "eta_two", domain_separator + "eta_three"); relation_parameters.eta = eta; - + relation_parameters.eta_two = eta_two; + relation_parameters.eta_three = eta_three; // Get commitments to sorted list accumulator and fourth wire witness_comms.sorted_accum = transcript->template receive_from_prover(domain_separator + comm_labels.sorted_accum); diff --git a/barretenberg/cpp/src/barretenberg/ultra_honk/relation_correctness.test.cpp b/barretenberg/cpp/src/barretenberg/ultra_honk/relation_correctness.test.cpp index 9a8f16b282b..7c21616cd32 100644 --- a/barretenberg/cpp/src/barretenberg/ultra_honk/relation_correctness.test.cpp +++ b/barretenberg/cpp/src/barretenberg/ultra_honk/relation_correctness.test.cpp @@ -267,10 +267,14 @@ TEST_F(UltraRelationCorrectnessTests, Ultra) // Generate eta, beta and gamma instance->relation_parameters.eta = FF::random_element(); + instance->relation_parameters.eta_two = FF::random_element(); + instance->relation_parameters.eta_three = FF::random_element(); instance->relation_parameters.beta = FF::random_element(); instance->relation_parameters.gamma = FF::random_element(); - instance->proving_key->compute_sorted_accumulator_polynomials(instance->relation_parameters.eta); + instance->proving_key->compute_sorted_accumulator_polynomials(instance->relation_parameters.eta, + instance->relation_parameters.eta_two, + instance->relation_parameters.eta_three); instance->proving_key->compute_grand_product_polynomials(instance->relation_parameters); instance->prover_polynomials = Flavor::ProverPolynomials(instance->proving_key); @@ -319,10 +323,14 @@ TEST_F(UltraRelationCorrectnessTests, GoblinUltra) // Generate eta, beta and gamma instance->relation_parameters.eta = FF::random_element(); + instance->relation_parameters.eta_two = FF::random_element(); + instance->relation_parameters.eta_three = FF::random_element(); instance->relation_parameters.beta = FF::random_element(); instance->relation_parameters.gamma = FF::random_element(); - instance->proving_key->compute_sorted_accumulator_polynomials(instance->relation_parameters.eta); + instance->proving_key->compute_sorted_accumulator_polynomials(instance->relation_parameters.eta, + instance->relation_parameters.eta_two, + instance->relation_parameters.eta_three); instance->proving_key->compute_logderivative_inverse(instance->relation_parameters); instance->proving_key->compute_grand_product_polynomials(instance->relation_parameters); instance->prover_polynomials = Flavor::ProverPolynomials(instance->proving_key); diff --git a/barretenberg/cpp/src/barretenberg/ultra_honk/sumcheck.test.cpp b/barretenberg/cpp/src/barretenberg/ultra_honk/sumcheck.test.cpp index 9bb65c3dec6..1ac3f6d5d10 100644 --- a/barretenberg/cpp/src/barretenberg/ultra_honk/sumcheck.test.cpp +++ b/barretenberg/cpp/src/barretenberg/ultra_honk/sumcheck.test.cpp @@ -151,10 +151,15 @@ TEST_F(SumcheckTestsRealCircuit, Ultra) // Generate eta, beta and gamma instance->relation_parameters.eta = FF::random_element(); + instance->relation_parameters.eta = FF::random_element(); + instance->relation_parameters.eta_two = FF::random_element(); + instance->relation_parameters.eta_three = FF::random_element(); instance->relation_parameters.beta = FF::random_element(); instance->relation_parameters.gamma = FF::random_element(); - instance->proving_key->compute_sorted_accumulator_polynomials(instance->relation_parameters.eta); + instance->proving_key->compute_sorted_accumulator_polynomials(instance->relation_parameters.eta, + instance->relation_parameters.eta_two, + instance->relation_parameters.eta_three); instance->proving_key->compute_grand_product_polynomials(instance->relation_parameters); instance->prover_polynomials = Flavor::ProverPolynomials(instance->proving_key); diff --git a/barretenberg/cpp/src/barretenberg/ultra_honk/ultra_transcript.test.cpp b/barretenberg/cpp/src/barretenberg/ultra_honk/ultra_transcript.test.cpp index cf1cc93c681..544bccaa11f 100644 --- a/barretenberg/cpp/src/barretenberg/ultra_honk/ultra_transcript.test.cpp +++ b/barretenberg/cpp/src/barretenberg/ultra_honk/ultra_transcript.test.cpp @@ -55,7 +55,7 @@ class UltraTranscriptTests : public ::testing::Test { manifest_expected.add_entry(round, "W_L", frs_per_G); manifest_expected.add_entry(round, "W_R", frs_per_G); manifest_expected.add_entry(round, "W_O", frs_per_G); - manifest_expected.add_challenge(round, "eta"); + manifest_expected.add_challenge(round, "eta", "eta_two", "eta_three"); round++; manifest_expected.add_entry(round, "SORTED_ACCUM", frs_per_G);