diff --git a/barretenberg/cpp/src/barretenberg/client_ivc/client_ivc.test.cpp b/barretenberg/cpp/src/barretenberg/client_ivc/client_ivc.test.cpp index 7058100adb24..d3be09ed1f29 100644 --- a/barretenberg/cpp/src/barretenberg/client_ivc/client_ivc.test.cpp +++ b/barretenberg/cpp/src/barretenberg/client_ivc/client_ivc.test.cpp @@ -337,6 +337,48 @@ TEST_F(ClientIVCTests, StructuredPrecomputedVKs) EXPECT_TRUE(ivc.prove_and_verify()); }; +/** + * @brief Perform accumulation with a structured trace and precomputed verification keys + * + */ +TEST_F(ClientIVCTests, VKIndependenceTest) +{ + const size_t MIN_NUM_CIRCUITS = 2; + // Folding more than 20 circuits requires to double the number of gates in Translator. + const size_t MAX_NUM_CIRCUITS = 20; + const size_t log2_num_gates = 5; // number of gates in baseline mocked circuit + + auto generate_vk = [&](size_t num_circuits) { + ClientIVC ivc{ { SMALL_TEST_STRUCTURE } }; + MockCircuitProducer circuit_producer; + for (size_t j = 0; j < num_circuits; ++j) { + auto circuit = circuit_producer.create_next_circuit(ivc, log2_num_gates); + ivc.accumulate(circuit); + } + ivc.prove(); + auto ivc_vk = ivc.get_vk(); + + // PCS verification keys will not match so set to null before comparing + ivc_vk.mega->pcs_verification_key = nullptr; + ivc_vk.eccvm->pcs_verification_key = nullptr; + ivc_vk.translator->pcs_verification_key = nullptr; + + return ivc_vk; + }; + + auto civc_vk_2 = generate_vk(MIN_NUM_CIRCUITS); + auto civc_vk_20 = generate_vk(MAX_NUM_CIRCUITS); + + // Check the equality of the Mega components of the ClientIVC VKeys. + EXPECT_EQ(*civc_vk_2.mega.get(), *civc_vk_20.mega.get()); + + // Check the equality of the ECCVM components of the ClientIVC VKeys. + EXPECT_EQ(*civc_vk_2.eccvm.get(), *civc_vk_20.eccvm.get()); + + // Check the equality of the Translator components of the ClientIVC VKeys. + EXPECT_EQ(*civc_vk_2.translator.get(), *civc_vk_20.translator.get()); +}; + /** * @brief Run a test using functions shared with the ClientIVC benchmark. * @details We do have this in addition to the above tests anyway so we can believe that the benchmark is running on diff --git a/barretenberg/cpp/src/barretenberg/eccvm/eccvm_composer.test.cpp b/barretenberg/cpp/src/barretenberg/eccvm/eccvm_composer.test.cpp index 448b00941558..e00a97bb14cb 100644 --- a/barretenberg/cpp/src/barretenberg/eccvm/eccvm_composer.test.cpp +++ b/barretenberg/cpp/src/barretenberg/eccvm/eccvm_composer.test.cpp @@ -98,6 +98,16 @@ TEST_F(ECCVMTests, BaseCase) ASSERT_TRUE(verified); } +TEST_F(ECCVMTests, BaseCaseFixedSize) +{ + ECCVMCircuitBuilder builder = generate_circuit(&engine); + ECCVMProver prover(builder, /*fixed_size = */ true); + ECCVMProof proof = prover.construct_proof(); + ECCVMVerifier verifier(prover.key); + bool verified = verifier.verify_proof(proof); + + ASSERT_TRUE(verified); +} TEST_F(ECCVMTests, EqFails) { @@ -114,6 +124,21 @@ TEST_F(ECCVMTests, EqFails) ASSERT_FALSE(verified); } +TEST_F(ECCVMTests, EqFailsFixedSize) +{ + auto builder = generate_circuit(&engine); + // Tamper with the eq op such that the expected value is incorect + builder.op_queue->add_erroneous_equality_op_for_testing(); + + builder.op_queue->num_transcript_rows++; + ECCVMProver prover(builder, /*fixed_size = */ true); + + ECCVMProof proof = prover.construct_proof(); + ECCVMVerifier verifier(prover.key); + bool verified = verifier.verify_proof(proof); + ASSERT_FALSE(verified); +} + TEST_F(ECCVMTests, CommittedSumcheck) { using Flavor = ECCVMFlavor; diff --git a/barretenberg/cpp/src/barretenberg/eccvm/eccvm_flavor.hpp b/barretenberg/cpp/src/barretenberg/eccvm/eccvm_flavor.hpp index 66855d0982dd..abfa36225051 100644 --- a/barretenberg/cpp/src/barretenberg/eccvm/eccvm_flavor.hpp +++ b/barretenberg/cpp/src/barretenberg/eccvm/eccvm_flavor.hpp @@ -45,6 +45,9 @@ class ECCVMFlavor { // Indicates that this flavor runs with ZK Sumcheck. static constexpr bool HasZK = true; + // Fixed size of the ECCVM circuits used in ClientIVC + static constexpr size_t ECCVM_FIXED_SIZE = 1UL << CONST_ECCVM_LOG_N; + static constexpr size_t NUM_WIRES = 85; // The number of multivariate polynomials on which a sumcheck prover sumcheck operates (including shifts). We often @@ -114,9 +117,6 @@ class ECCVMFlavor { lagrange_last); // column 2 DataType get_selectors() { return get_all(); }; - auto get_sigma_polynomials() { return RefArray{}; }; - auto get_id_polynomials() { return RefArray{}; }; - auto get_table_polynomials() { return RefArray{}; }; }; /** @@ -128,12 +128,7 @@ class ECCVMFlavor { z_perm, // column 0 lookup_inverses); // column 1 }; - - /** - * @brief Container for all witness polynomials used/constructed by the prover. - * @details Shifts are not included here since they do not occupy their own memory. - */ - template class WireEntities { + template class WireNonShiftedEntities { public: DEFINE_FLAVOR_MEMBERS(DataType, transcript_add, // column 0 @@ -195,32 +190,51 @@ class ECCVMFlavor { transcript_msm_infinity, // column 56 transcript_msm_x_inverse, // column 57 transcript_msm_count_zero_at_transition, // column 58 - transcript_msm_count_at_transition_inverse, // column 59 - transcript_mul, // column 60 - transcript_msm_count, // column 61 - transcript_accumulator_x, // column 62 - transcript_accumulator_y, // column 63 - precompute_scalar_sum, // column 64 - precompute_s1hi, // column 65 - precompute_dx, // column 66 - precompute_dy, // column 67 - precompute_tx, // column 68 - precompute_ty, // column 69 - msm_transition, // column 70 - msm_add, // column 71 - msm_double, // column 72 - msm_skew, // column 73 - msm_accumulator_x, // column 74 - msm_accumulator_y, // column 75 - msm_count, // column 76 - msm_round, // column 77 - msm_add1, // column 78 - msm_pc, // column 79 - precompute_pc, // column 80 - transcript_pc, // column 81 - precompute_round, // column 82 - transcript_accumulator_empty, // column 83 - precompute_select) // column 84 + transcript_msm_count_at_transition_inverse) // column 59 + }; + + /** + * @brief Container for all to-be-shifted witness polynomials excluding the accumulators used/constructed by the + * prover. + * @details Shifts are not included here since they do not occupy their own memory. + */ + template class WireToBeShiftedWithoutAccumulatorsEntities { + public: + DEFINE_FLAVOR_MEMBERS(DataType, + transcript_mul, // column 60 + transcript_msm_count, // column 61 + precompute_scalar_sum, // column 62 + precompute_s1hi, // column 63 + precompute_dx, // column 64 + precompute_dy, // column 65 + precompute_tx, // column 66 + precompute_ty, // column 67 + msm_transition, // column 68 + msm_add, // column 69 + msm_double, // column 70 + msm_skew, // column 71 + msm_accumulator_x, // column 72 + msm_accumulator_y, // column 73 + msm_count, // column 74 + msm_round, // column 75 + msm_add1, // column 76 + msm_pc, // column 77 + precompute_pc, // column 78 + transcript_pc, // column 79 + precompute_round, // column 80 + precompute_select) // column 81 + }; + + /** + * @brief Containter for transcript accumulators, they stand out as the only to-be-shifted wires that are always + * populated until the dyadic size of the circuit. + */ + template class WireToBeShiftedAccumulatorEntities { + public: + DEFINE_FLAVOR_MEMBERS(DataType, + transcript_accumulator_empty, // column 82 + transcript_accumulator_x, // column 83 + transcript_accumulator_y) // column 84 }; /** @@ -228,12 +242,29 @@ class ECCVMFlavor { * @details Shifts are not included here since they do not occupy their own memory. */ template - class WitnessEntities : public WireEntities, public DerivedWitnessEntities { + class WitnessEntities : public WireNonShiftedEntities, + public WireToBeShiftedWithoutAccumulatorsEntities, + public WireToBeShiftedAccumulatorEntities, + public DerivedWitnessEntities { public: - DEFINE_COMPOUND_GET_ALL(WireEntities, DerivedWitnessEntities) - auto get_wires() { return WireEntities::get_all(); }; - // The sorted concatenations of table and witness data needed for plookup. - auto get_sorted_polynomials() { return RefArray{}; }; + DEFINE_COMPOUND_GET_ALL(WireNonShiftedEntities, + WireToBeShiftedWithoutAccumulatorsEntities, + WireToBeShiftedAccumulatorEntities, + DerivedWitnessEntities) + auto get_wires() + { + return concatenate(WireNonShiftedEntities::get_all(), + WireToBeShiftedWithoutAccumulatorsEntities::get_all(), + WireToBeShiftedAccumulatorEntities::get_all()); + }; + + // Used to amortize the commitment time when the ECCVM size is fixed + auto get_accumulators() { return WireToBeShiftedAccumulatorEntities::get_all(); }; + auto get_wires_without_accumulators() + { + return concatenate(WireNonShiftedEntities::get_all(), + WireToBeShiftedWithoutAccumulatorsEntities::get_all()); + } }; /** @@ -244,29 +275,29 @@ class ECCVMFlavor { DEFINE_FLAVOR_MEMBERS(DataType, transcript_mul_shift, // column 0 transcript_msm_count_shift, // column 1 - transcript_accumulator_x_shift, // column 2 - transcript_accumulator_y_shift, // column 3 - precompute_scalar_sum_shift, // column 4 - precompute_s1hi_shift, // column 5 - precompute_dx_shift, // column 6 - precompute_dy_shift, // column 7 - precompute_tx_shift, // column 8 - precompute_ty_shift, // column 9 - msm_transition_shift, // column 10 - msm_add_shift, // column 11 - msm_double_shift, // column 12 - msm_skew_shift, // column 13 - msm_accumulator_x_shift, // column 14 - msm_accumulator_y_shift, // column 15 - msm_count_shift, // column 16 - msm_round_shift, // column 17 - msm_add1_shift, // column 18 - msm_pc_shift, // column 19 - precompute_pc_shift, // column 20 - transcript_pc_shift, // column 21 - precompute_round_shift, // column 22 - transcript_accumulator_empty_shift, // column 23 - precompute_select_shift, // column 24 + precompute_scalar_sum_shift, // column 2 + precompute_s1hi_shift, // column 3 + precompute_dx_shift, // column 4 + precompute_dy_shift, // column 5 + precompute_tx_shift, // column 6 + precompute_ty_shift, // column 7 + msm_transition_shift, // column 8 + msm_add_shift, // column 9 + msm_double_shift, // column 10 + msm_skew_shift, // column 11 + msm_accumulator_x_shift, // column 12 + msm_accumulator_y_shift, // column 13 + msm_count_shift, // column 14 + msm_round_shift, // column 15 + msm_add1_shift, // column 16 + msm_pc_shift, // column 17 + precompute_pc_shift, // column 18 + transcript_pc_shift, // column 19 + precompute_round_shift, // column 20 + precompute_select_shift, // column 21 + transcript_accumulator_empty_shift, // column 22 + transcript_accumulator_x_shift, // column 23 + transcript_accumulator_y_shift, // column 24 z_perm_shift); // column 25 }; @@ -276,29 +307,29 @@ class ECCVMFlavor { // NOTE: must match order of ShiftedEntities above! return RefArray{ entities.transcript_mul, // column 0 entities.transcript_msm_count, // column 1 - entities.transcript_accumulator_x, // column 2 - entities.transcript_accumulator_y, // column 3 - entities.precompute_scalar_sum, // column 4 - entities.precompute_s1hi, // column 5 - entities.precompute_dx, // column 6 - entities.precompute_dy, // column 7 - entities.precompute_tx, // column 8 - entities.precompute_ty, // column 9 - entities.msm_transition, // column 10 - entities.msm_add, // column 11 - entities.msm_double, // column 12 - entities.msm_skew, // column 13 - entities.msm_accumulator_x, // column 14 - entities.msm_accumulator_y, // column 15 - entities.msm_count, // column 16 - entities.msm_round, // column 17 - entities.msm_add1, // column 18 - entities.msm_pc, // column 19 - entities.precompute_pc, // column 20 - entities.transcript_pc, // column 21 - entities.precompute_round, // column 22 - entities.transcript_accumulator_empty, // column 23 - entities.precompute_select, // column 24 + entities.precompute_scalar_sum, // column 2 + entities.precompute_s1hi, // column 3 + entities.precompute_dx, // column 4 + entities.precompute_dy, // column 5 + entities.precompute_tx, // column 6 + entities.precompute_ty, // column 7 + entities.msm_transition, // column 8 + entities.msm_add, // column 9 + entities.msm_double, // column 10 + entities.msm_skew, // column 11 + entities.msm_accumulator_x, // column 12 + entities.msm_accumulator_y, // column 13 + entities.msm_count, // column 14 + entities.msm_round, // column 15 + entities.msm_add1, // column 16 + entities.msm_pc, // column 17 + entities.precompute_pc, // column 18 + entities.transcript_pc, // column 19 + entities.precompute_round, // column 20 + entities.precompute_select, // column 21 + entities.transcript_accumulator_empty, // column 22 + entities.transcript_accumulator_x, // column 23 + entities.transcript_accumulator_y, // column 24 entities.z_perm }; // column 25 } @@ -500,7 +531,7 @@ class ECCVMFlavor { table (reads come from msm_x/y3, msm_x/y4) * @return ProverPolynomials */ - ProverPolynomials(const CircuitBuilder& builder) + ProverPolynomials(const CircuitBuilder& builder, const bool fixed_size = false) { // compute rows for the three different sections of the ECCVM execution trace const auto transcript_rows = @@ -516,7 +547,15 @@ class ECCVMFlavor { const size_t num_rows = std::max({ point_table_rows.size(), msm_rows.size(), transcript_rows.size() }) + MASKING_OFFSET; const auto log_num_rows = static_cast(numeric::get_msb64(num_rows)); - const size_t dyadic_num_rows = 1UL << (log_num_rows + (1UL << log_num_rows == num_rows ? 0 : 1)); + + size_t dyadic_num_rows = 1UL << (log_num_rows + (1UL << log_num_rows == num_rows ? 0 : 1)); + + if ((fixed_size) && (ECCVM_FIXED_SIZE < dyadic_num_rows)) { + info("The ECCVM circuit size has exceeded the fixed upper bound"); + ASSERT(false); + } + + dyadic_num_rows = fixed_size ? ECCVM_FIXED_SIZE : dyadic_num_rows; for (auto& poly : get_to_be_shifted()) { poly = Polynomial{ /*memory size*/ dyadic_num_rows - 1, @@ -681,13 +720,24 @@ class ECCVMFlavor { // Expose constructors on the base class using Base = ProvingKey_; using Base::Base; + // Used to amortize the commitment time when `fixed_size` = true. + size_t real_size = 0; ProverPolynomials polynomials; // storage for all polynomials evaluated by the prover + // Constructor for dynamic size ProvingKey ProvingKey(const CircuitBuilder& builder) : Base(builder.get_circuit_subgroup_size(builder.get_estimated_num_finalized_gates()), 0) + , real_size(this->circuit_size) , polynomials(builder) {} + + // Constructor for fixed size ProvingKey + ProvingKey(const CircuitBuilder& builder, bool fixed_size) + : Base(ECCVM_FIXED_SIZE, 0) + , real_size(builder.get_circuit_subgroup_size(builder.get_estimated_num_finalized_gates())) + , polynomials(builder, fixed_size) + {} }; /** diff --git a/barretenberg/cpp/src/barretenberg/eccvm/eccvm_prover.cpp b/barretenberg/cpp/src/barretenberg/eccvm/eccvm_prover.cpp index d042cf5848f1..2de9bd40f492 100644 --- a/barretenberg/cpp/src/barretenberg/eccvm/eccvm_prover.cpp +++ b/barretenberg/cpp/src/barretenberg/eccvm/eccvm_prover.cpp @@ -13,10 +13,12 @@ namespace bb { ECCVMProver::ECCVMProver(CircuitBuilder& builder, + const bool fixed_size, const std::shared_ptr& transcript, const std::shared_ptr& ipa_transcript) : transcript(transcript) , ipa_transcript(ipa_transcript) + , fixed_size(fixed_size) { PROFILE_THIS_NAME("ECCVMProver(CircuitBuilder&)"); @@ -24,7 +26,7 @@ ECCVMProver::ECCVMProver(CircuitBuilder& builder, // ProvingKey/ProverPolynomials and update the model to reflect what's done in all other proving systems. // Construct the proving key; populates all polynomials except for witness polys - key = std::make_shared(builder); + key = fixed_size ? std::make_shared(builder, fixed_size) : std::make_shared(builder); key->commitment_key = std::make_shared(key->circuit_size); } @@ -45,10 +47,19 @@ void ECCVMProver::execute_preamble_round() */ void ECCVMProver::execute_wire_commitments_round() { - auto wire_polys = key->polynomials.get_wires(); - auto labels = commitment_labels.get_wires(); - for (size_t idx = 0; idx < wire_polys.size(); ++idx) { - transcript->send_to_verifier(labels[idx], key->commitment_key->commit(wire_polys[idx])); + // Commit to wires whose length is bounded by the real size of the ECCVM + for (const auto& [wire, label] : zip_view(key->polynomials.get_wires_without_accumulators(), + commitment_labels.get_wires_without_accumulators())) { + // TODO(https://github.com/AztecProtocol/barretenberg/issues/1240) Structured Polynomials in + // ECCVM/Translator/MegaZK + PolynomialSpan wire_span = wire; + transcript->send_to_verifier(label, key->commitment_key->commit(wire_span.subspan(0, key->real_size))); + } + + // The accumulators are populated until the 2^{CONST_ECCVM_LOG_N}, therefore we commit to a full-sized polynomial + for (const auto& [wire, label] : + zip_view(key->polynomials.get_accumulators(), commitment_labels.get_accumulators())) { + transcript->send_to_verifier(label, key->commitment_key->commit(wire)); } } @@ -58,6 +69,7 @@ void ECCVMProver::execute_wire_commitments_round() */ void ECCVMProver::execute_log_derivative_commitments_round() { + // Compute and add beta to relation parameters auto [beta, gamma] = transcript->template get_challenges("beta", "gamma"); @@ -95,6 +107,7 @@ void ECCVMProver::execute_grand_product_computation_round() */ void ECCVMProver::execute_relation_check_rounds() { + using Sumcheck = SumcheckProver; auto sumcheck = Sumcheck(key->circuit_size, transcript); @@ -199,8 +212,6 @@ void ECCVMProver::execute_pcs_rounds() // Produce another challenge passed as input to the translator verifier translation_batching_challenge_v = transcript->template get_challenge("Translation:batching_challenge"); - - vinfo("computed opening proof"); } ECCVMProof ECCVMProver::export_proof() diff --git a/barretenberg/cpp/src/barretenberg/eccvm/eccvm_prover.hpp b/barretenberg/cpp/src/barretenberg/eccvm/eccvm_prover.hpp index 4217b3818622..6a8a2b4e1793 100644 --- a/barretenberg/cpp/src/barretenberg/eccvm/eccvm_prover.hpp +++ b/barretenberg/cpp/src/barretenberg/eccvm/eccvm_prover.hpp @@ -30,6 +30,7 @@ class ECCVMProver { using SmallSubgroupIPA = SmallSubgroupIPAProver; explicit ECCVMProver(CircuitBuilder& builder, + const bool fixed_size = false, const std::shared_ptr& transcript = std::make_shared(), const std::shared_ptr& ipa_transcript = std::make_shared()); @@ -47,6 +48,8 @@ class ECCVMProver { std::shared_ptr transcript; std::shared_ptr ipa_transcript; + bool fixed_size; + TranslationEvaluations translation_evaluations; std::vector public_inputs; diff --git a/barretenberg/cpp/src/barretenberg/eccvm/eccvm_transcript.test.cpp b/barretenberg/cpp/src/barretenberg/eccvm/eccvm_transcript.test.cpp index be64494b5720..978c3b203e86 100644 --- a/barretenberg/cpp/src/barretenberg/eccvm/eccvm_transcript.test.cpp +++ b/barretenberg/cpp/src/barretenberg/eccvm/eccvm_transcript.test.cpp @@ -99,8 +99,6 @@ class ECCVMTranscriptTests : public ::testing::Test { manifest_expected.add_entry(round, "TRANSCRIPT_MSM_COUNT_AT_TRANSITION_INVERSE", frs_per_G); manifest_expected.add_entry(round, "TRANSCRIPT_MUL", frs_per_G); manifest_expected.add_entry(round, "TRANSCRIPT_MSM_COUNT", frs_per_G); - manifest_expected.add_entry(round, "TRANSCRIPT_ACCUMULATOR_X", frs_per_G); - manifest_expected.add_entry(round, "TRANSCRIPT_ACCUMULATOR_Y", frs_per_G); manifest_expected.add_entry(round, "PRECOMPUTE_SCALAR_SUM", frs_per_G); manifest_expected.add_entry(round, "PRECOMPUTE_S1HI", frs_per_G); manifest_expected.add_entry(round, "PRECOMPUTE_DX", frs_per_G); @@ -120,8 +118,10 @@ class ECCVMTranscriptTests : public ::testing::Test { manifest_expected.add_entry(round, "PRECOMPUTE_PC", frs_per_G); manifest_expected.add_entry(round, "TRANSCRIPT_PC", frs_per_G); manifest_expected.add_entry(round, "PRECOMPUTE_ROUND", frs_per_G); - manifest_expected.add_entry(round, "TRANSCRIPT_ACCUMULATOR_EMPTY", frs_per_G); manifest_expected.add_entry(round, "PRECOMPUTE_SELECT", frs_per_G); + manifest_expected.add_entry(round, "TRANSCRIPT_ACCUMULATOR_EMPTY", frs_per_G); + manifest_expected.add_entry(round, "TRANSCRIPT_ACCUMULATOR_X", frs_per_G); + manifest_expected.add_entry(round, "TRANSCRIPT_ACCUMULATOR_Y", frs_per_G); manifest_expected.add_challenge(round, "beta", "gamma"); round++; diff --git a/barretenberg/cpp/src/barretenberg/goblin/goblin.hpp b/barretenberg/cpp/src/barretenberg/goblin/goblin.hpp index be0fab4ad753..872b168f9605 100644 --- a/barretenberg/cpp/src/barretenberg/goblin/goblin.hpp +++ b/barretenberg/cpp/src/barretenberg/goblin/goblin.hpp @@ -176,7 +176,8 @@ class GoblinProver { PROFILE_THIS_NAME("Create ECCVMBuilder and ECCVMProver"); auto eccvm_builder = std::make_unique(op_queue); - eccvm_prover = std::make_unique(*eccvm_builder); + // As is it used in ClientIVC, we make it fixed size = 2^{CONST_ECCVM_LOG_N} + eccvm_prover = std::make_unique(*eccvm_builder, /*fixed_size =*/true); } { diff --git a/barretenberg/cpp/src/barretenberg/polynomials/polynomial.hpp b/barretenberg/cpp/src/barretenberg/polynomials/polynomial.hpp index 077bc78f85e5..d5888aa17106 100644 --- a/barretenberg/cpp/src/barretenberg/polynomials/polynomial.hpp +++ b/barretenberg/cpp/src/barretenberg/polynomials/polynomial.hpp @@ -36,13 +36,15 @@ template struct PolynomialSpan { ASSERT(index >= start_index && index < end_index()); return span[index - start_index]; } - PolynomialSpan subspan(size_t offset) + PolynomialSpan subspan(size_t offset, size_t length) { if (offset > span.size()) { // Return a null span return { 0, span.subspan(span.size()) }; } - return { start_index + offset, span.subspan(offset) }; + size_t new_length = std::min(length, span.size() - offset); + return { start_index + offset, span.subspan(offset, new_length) }; } + operator PolynomialSpan() const { return PolynomialSpan(start_index, span); } }; /** diff --git a/barretenberg/cpp/src/barretenberg/relations/ecc_vm/ecc_set_relation.hpp b/barretenberg/cpp/src/barretenberg/relations/ecc_vm/ecc_set_relation.hpp index 1a5aff693691..0ba2af3c281f 100644 --- a/barretenberg/cpp/src/barretenberg/relations/ecc_vm/ecc_set_relation.hpp +++ b/barretenberg/cpp/src/barretenberg/relations/ecc_vm/ecc_set_relation.hpp @@ -17,6 +17,13 @@ template class ECCVMSetRelationImpl { 3 // left-shiftable polynomial sub-relation }; + template inline static bool skip(const AllEntities& in) + { + // If z_perm == z_perm_shift, this implies that none of the wire values for the present input are involved in + // non-trivial copy constraints. + return (in.z_perm - in.z_perm_shift).is_zero(); + } + template static Accumulator convert_to_wnaf(const auto& s0, const auto& s1) { auto t = s0 + s0; diff --git a/barretenberg/cpp/src/barretenberg/translator_vm/translator_flavor.hpp b/barretenberg/cpp/src/barretenberg/translator_vm/translator_flavor.hpp index 02c9620009f1..2f2fff063ecc 100644 --- a/barretenberg/cpp/src/barretenberg/translator_vm/translator_flavor.hpp +++ b/barretenberg/cpp/src/barretenberg/translator_vm/translator_flavor.hpp @@ -22,7 +22,7 @@ namespace bb { class TranslatorFlavor { public: - static constexpr size_t mini_circuit_size = 2048; + static constexpr size_t mini_circuit_size = 8192; using CircuitBuilder = TranslatorCircuitBuilder; using Curve = curve::BN254; using PCS = KZG; @@ -40,7 +40,8 @@ class TranslatorFlavor { // Indicates that this flavor runs with ZK Sumcheck. static constexpr bool HasZK = true; - static constexpr size_t MINIMUM_MINI_CIRCUIT_SIZE = 2048; + // A minicircuit of such size allows for 10 rounds of folding (i.e. 20 circuits). + static constexpr size_t MINIMUM_MINI_CIRCUIT_SIZE = 8192; // The size of the circuit which is filled with non-zero values for most polynomials. Most relations (everything // except for Permutation and DeltaRangeConstraint) can be evaluated just on the first chunk diff --git a/barretenberg/cpp/src/barretenberg/translator_vm/translator_prover.cpp b/barretenberg/cpp/src/barretenberg/translator_vm/translator_prover.cpp index 71898f46fadd..72abe38015d2 100644 --- a/barretenberg/cpp/src/barretenberg/translator_vm/translator_prover.cpp +++ b/barretenberg/cpp/src/barretenberg/translator_vm/translator_prover.cpp @@ -45,11 +45,21 @@ void TranslatorProver::execute_preamble_round() */ void TranslatorProver::execute_wire_and_sorted_constraints_commitments_round() { - // Commit to all wire polynomials and ordered range constraint polynomials - auto wire_polys = key->proving_key->polynomials.get_wires_and_ordered_range_constraints(); - auto labels = commitment_labels.get_wires_and_ordered_range_constraints(); - for (size_t idx = 0; idx < wire_polys.size(); ++idx) { - transcript->send_to_verifier(labels[idx], key->proving_key->commitment_key->commit(wire_polys[idx])); + // Commit to all wire polynomials, note that the wire polynomials have at most `mini_circuit_dyadic_size` non-zero + // values. Therefore we could commit to a subspan of that size. + for (const auto& [wire, label] : + zip_view(key->proving_key->polynomials.get_wires(), commitment_labels.get_wires())) { + // TODO(https://github.com/AztecProtocol/barretenberg/issues/1240) Structured Polynomials in + // ECCVM/Translator/MegaZK + PolynomialSpan wire_span = wire; + transcript->send_to_verifier( + label, key->proving_key->commitment_key->commit(wire_span.subspan(0, key->mini_circuit_dyadic_size))); + } + + // The ordered range constraints are of full circuit size. + for (const auto& [ordered_range_constraint, label] : zip_view( + key->proving_key->polynomials.get_ordered_constraints(), commitment_labels.get_ordered_constraints())) { + transcript->send_to_verifier(label, key->proving_key->commitment_key->commit(ordered_range_constraint)); } } diff --git a/barretenberg/cpp/src/barretenberg/translator_vm/translator_prover.hpp b/barretenberg/cpp/src/barretenberg/translator_vm/translator_prover.hpp index 2acd99027cfd..b6a1c7009e02 100644 --- a/barretenberg/cpp/src/barretenberg/translator_vm/translator_prover.hpp +++ b/barretenberg/cpp/src/barretenberg/translator_vm/translator_prover.hpp @@ -24,7 +24,7 @@ class TranslatorProver { using PCS = typename Flavor::PCS; using Transcript = typename Flavor::Transcript; using ZKData = ZKSumcheckData; - static constexpr size_t MINIMUM_MINI_CIRCUIT_SIZE = 2048; + static constexpr size_t MINIMUM_MINI_CIRCUIT_SIZE = Flavor::MINIMUM_MINI_CIRCUIT_SIZE; size_t total_num_gates = 0; // num_gates (already include zero row offset) (used to compute dyadic size) size_t dyadic_circuit_size = 0; // final power-of-2 circuit size size_t mini_circuit_dyadic_size = 0; // The size of the small circuit that contains non-range constraint relations diff --git a/barretenberg/cpp/src/barretenberg/translator_vm/translator_proving_key.hpp b/barretenberg/cpp/src/barretenberg/translator_vm/translator_proving_key.hpp index f0ba84f368e2..31fbf94dead8 100644 --- a/barretenberg/cpp/src/barretenberg/translator_vm/translator_proving_key.hpp +++ b/barretenberg/cpp/src/barretenberg/translator_vm/translator_proving_key.hpp @@ -92,6 +92,12 @@ class TranslatorProvingKey { inline void compute_mini_circuit_dyadic_size(const Circuit& circuit) { + // Check that the Translator Circuit does not exceed the fixed upper bound, the current value 8192 corresponds + // to 10 rounds of folding (i.e. 20 circuits) + if (circuit.num_gates > Flavor::MINIMUM_MINI_CIRCUIT_SIZE) { + info("The Translator circuit size has exceeded the fixed upper bound"); + ASSERT(false); + } const size_t total_num_gates = std::max(circuit.num_gates, Flavor::MINIMUM_MINI_CIRCUIT_SIZE); // Next power of 2 mini_circuit_dyadic_size = circuit.get_circuit_subgroup_size(total_num_gates); diff --git a/barretenberg/cpp/src/barretenberg/ultra_honk/mega_honk.test.cpp b/barretenberg/cpp/src/barretenberg/ultra_honk/mega_honk.test.cpp index eaa85b26ee38..ff8f002abc32 100644 --- a/barretenberg/cpp/src/barretenberg/ultra_honk/mega_honk.test.cpp +++ b/barretenberg/cpp/src/barretenberg/ultra_honk/mega_honk.test.cpp @@ -116,6 +116,8 @@ TYPED_TEST(MegaHonkTests, BasicStructured) // In MegaZKFlavor, we mask witness polynomials by placing random values at the indices `dyadic_circuit_size`-i for // i=1,2,3. This mechanism does not work with structured polynomials yet. + // TODO(https://github.com/AztecProtocol/barretenberg/issues/1240) Structured Polynomials in + // ECCVM/Translator/MegaZK if constexpr (std::is_same_v) { GTEST_SKIP() << "Skipping 'BasicStructured' test for MegaZKFlavor."; } @@ -152,6 +154,8 @@ TYPED_TEST(MegaHonkTests, DynamicVirtualSizeIncrease) // In MegaZKFlavor, we mask witness polynomials by placing random values at the indices `dyadic_circuit_size`-i for // i=1,2,3. This mechanism does not work with structured polynomials yet. + // TODO(https://github.com/AztecProtocol/barretenberg/issues/1240) Structured Polynomials in + // ECCVM/Translator/MegaZK if constexpr (std::is_same_v) { GTEST_SKIP() << "Skipping 'DynamicVirtualSizeIncrease' test for MegaZKFlavor."; } @@ -396,6 +400,8 @@ TYPED_TEST(MegaHonkTests, PolySwap) using Flavor = TypeParam; // In MegaZKFlavor, we mask witness polynomials by placing random values at the indices `dyadic_circuit_size`-i, for // i=1,2,3. This mechanism does not work with structured polynomials yet. + // TODO(https://github.com/AztecProtocol/barretenberg/issues/1240) Structured Polynomials in + // ECCVM/Translator/MegaZK if constexpr (std::is_same_v) { GTEST_SKIP() << "Skipping 'PolySwap' test for MegaZKFlavor."; }