diff --git a/barretenberg/cpp/src/barretenberg/client_ivc/client_ivc.cpp b/barretenberg/cpp/src/barretenberg/client_ivc/client_ivc.cpp index 691d48616080..d66406d6bd08 100644 --- a/barretenberg/cpp/src/barretenberg/client_ivc/client_ivc.cpp +++ b/barretenberg/cpp/src/barretenberg/client_ivc/client_ivc.cpp @@ -156,9 +156,9 @@ void ClientIVC::accumulate(ClientCircuit& circuit, // Construct the proving key for circuit std::shared_ptr proving_key = std::make_shared(circuit, trace_settings); - // The commitment key is initialised with the number of points determined by the trace_settings' dyadic size. If a - // circuit overflows past the dyadic size the commitment key will not have enough points so we need to increase it - if (proving_key->proving_key.circuit_size > trace_settings.dyadic_size()) { + // If the current circuit overflows past the current size of the commitment key, reinitialize accordingly. + // TODO(https://github.com/AztecProtocol/barretenberg/issues/1319) + if (proving_key->proving_key.circuit_size > bn254_commitment_key->dyadic_size) { bn254_commitment_key = std::make_shared>(proving_key->proving_key.circuit_size); goblin.commitment_key = bn254_commitment_key; } diff --git a/barretenberg/cpp/src/barretenberg/client_ivc/client_ivc.hpp b/barretenberg/cpp/src/barretenberg/client_ivc/client_ivc.hpp index f6ef4ce0f320..bbc8e41a210b 100644 --- a/barretenberg/cpp/src/barretenberg/client_ivc/client_ivc.hpp +++ b/barretenberg/cpp/src/barretenberg/client_ivc/client_ivc.hpp @@ -191,11 +191,16 @@ class ClientIVC { ClientIVC(TraceSettings trace_settings = {}) : trace_usage_tracker(trace_settings) , trace_settings(trace_settings) - , bn254_commitment_key(trace_settings.structure.has_value() - ? std::make_shared>(trace_settings.dyadic_size()) - : nullptr) , goblin(bn254_commitment_key) - {} + { + // Allocate BN254 commitment key based on the max dyadic Mega structured trace size and translator circuit size. + // https://github.com/AztecProtocol/barretenberg/issues/1319): Account for Translator only when it's necessary + size_t commitment_key_size = + std::max(trace_settings.dyadic_size(), + TranslatorFlavor::TRANSLATOR_VM_FIXED_SIZE * TranslatorFlavor::INTERLEAVING_GROUP_SIZE); + info("BN254 commitment key size: ", commitment_key_size); + bn254_commitment_key = std::make_shared>(commitment_key_size); + } void instantiate_stdlib_verification_queue( ClientCircuit& circuit, const std::vector>& input_keys = {}); 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 e60f986dd769..f3c94e8fea4f 100644 --- a/barretenberg/cpp/src/barretenberg/client_ivc/client_ivc.test.cpp +++ b/barretenberg/cpp/src/barretenberg/client_ivc/client_ivc.test.cpp @@ -10,6 +10,8 @@ using namespace bb; +static constexpr size_t MAX_NUM_KERNELS = 17; + class ClientIVCTests : public ::testing::Test { protected: static void SetUpTestSuite() @@ -438,6 +440,34 @@ TEST(ClientIVCBenchValidation, Full6MockedVKs) ASSERT_NO_FATAL_FAILURE(run_test()); } +TEST(ClientIVCKernelCapacity, MaxCapacityPassing) +{ + bb::srs::init_crs_factory(bb::srs::get_ignition_crs_path()); + bb::srs::init_grumpkin_crs_factory(bb::srs::get_grumpkin_crs_path()); + + ClientIVC ivc{ { CLIENT_IVC_BENCH_STRUCTURE } }; + const size_t total_num_circuits{ 2 * MAX_NUM_KERNELS }; + PrivateFunctionExecutionMockCircuitProducer circuit_producer; + auto precomputed_vkeys = circuit_producer.precompute_verification_keys(total_num_circuits, ivc.trace_settings); + perform_ivc_accumulation_rounds(total_num_circuits, ivc, precomputed_vkeys); + auto proof = ivc.prove(); + bool verified = verify_ivc(proof, ivc); + EXPECT_TRUE(verified); +} + +TEST(ClientIVCKernelCapacity, MaxCapacityFailing) +{ + bb::srs::init_crs_factory(bb::srs::get_ignition_crs_path()); + bb::srs::init_grumpkin_crs_factory(bb::srs::get_grumpkin_crs_path()); + + ClientIVC ivc{ { CLIENT_IVC_BENCH_STRUCTURE } }; + const size_t total_num_circuits{ 2 * (MAX_NUM_KERNELS + 1) }; + PrivateFunctionExecutionMockCircuitProducer circuit_producer; + auto precomputed_vkeys = circuit_producer.precompute_verification_keys(total_num_circuits, ivc.trace_settings); + perform_ivc_accumulation_rounds(total_num_circuits, ivc, precomputed_vkeys); + EXPECT_ANY_THROW(ivc.prove()); +} + /** * @brief Test use of structured trace overflow block mechanism * @details Accumulate 4 circuits which have progressively more arithmetic gates. The final two overflow the prescribed diff --git a/barretenberg/cpp/src/barretenberg/eccvm/eccvm_flavor.hpp b/barretenberg/cpp/src/barretenberg/eccvm/eccvm_flavor.hpp index bb702b6675a4..d910ce18e8bc 100644 --- a/barretenberg/cpp/src/barretenberg/eccvm/eccvm_flavor.hpp +++ b/barretenberg/cpp/src/barretenberg/eccvm/eccvm_flavor.hpp @@ -46,6 +46,8 @@ class ECCVMFlavor { // Indicates that this flavor runs with ZK Sumcheck. static constexpr bool HasZK = true; // Fixed size of the ECCVM circuits used in ClientIVC + // Important: these constants cannot be arbitrarily changes - please consult with a member of the Crypto team if + // they become too small. static constexpr size_t ECCVM_FIXED_SIZE = 1UL << CONST_ECCVM_LOG_N; static constexpr size_t NUM_WIRES = 85; @@ -527,8 +529,7 @@ class ECCVMFlavor { 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); + throw_or_abort("The ECCVM circuit size has exceeded the fixed upper bound"); } dyadic_num_rows = fixed_size ? ECCVM_FIXED_SIZE : dyadic_num_rows; diff --git a/barretenberg/cpp/src/barretenberg/goblin/goblin.hpp b/barretenberg/cpp/src/barretenberg/goblin/goblin.hpp index 582d64e1e301..323e09d99b79 100644 --- a/barretenberg/cpp/src/barretenberg/goblin/goblin.hpp +++ b/barretenberg/cpp/src/barretenberg/goblin/goblin.hpp @@ -149,6 +149,8 @@ class GoblinProver { PROFILE_THIS_NAME("Goblin::prove"); + info("Constructing a Goblin proof with num ultra ops = ", op_queue->get_ultra_ops_table_num_rows()); + goblin_proof.merge_proof = merge_proof_in.empty() ? std::move(merge_proof) : std::move(merge_proof_in); { PROFILE_THIS_NAME("prove_eccvm"); diff --git a/barretenberg/cpp/src/barretenberg/relations/translator_vm/translator_permutation_relation.hpp b/barretenberg/cpp/src/barretenberg/relations/translator_vm/translator_permutation_relation.hpp index 6bb732644ad2..578e2ab86b80 100644 --- a/barretenberg/cpp/src/barretenberg/relations/translator_vm/translator_permutation_relation.hpp +++ b/barretenberg/cpp/src/barretenberg/relations/translator_vm/translator_permutation_relation.hpp @@ -14,6 +14,17 @@ template class TranslatorPermutationRelationImpl { 3 // left-shiftable polynomial sub-relation }; + /** + * @brief Returns true if the contribution from all subrelations for the provided inputs is identically zero + * + */ + 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(); + } + inline static auto& get_grand_product_polynomial(auto& in) { return in.z_perm; } inline static auto& get_shifted_grand_product_polynomial(auto& in) { return in.z_perm_shift; } diff --git a/barretenberg/cpp/src/barretenberg/translator_vm/relation_correctness.test.cpp b/barretenberg/cpp/src/barretenberg/translator_vm/relation_correctness.test.cpp index cd81284dba21..53815e3b2a78 100644 --- a/barretenberg/cpp/src/barretenberg/translator_vm/relation_correctness.test.cpp +++ b/barretenberg/cpp/src/barretenberg/translator_vm/relation_correctness.test.cpp @@ -24,7 +24,6 @@ TEST_F(TranslatorRelationCorrectnessTests, Permutation) using ProverPolynomials = typename Flavor::ProverPolynomials; auto& engine = numeric::get_debug_randomness(); const size_t mini_circuit_size = 2048; - const size_t full_circuit_size = mini_circuit_size * Flavor::INTERLEAVING_GROUP_SIZE; // Fill needed relation parameters RelationParameters params{ .beta = FF::random_element(), .gamma = FF::random_element() }; @@ -35,7 +34,7 @@ TEST_F(TranslatorRelationCorrectnessTests, Permutation) // Fill in lagrange polynomials used in the permutation relation prover_polynomials.lagrange_first.at(0) = 1; - prover_polynomials.lagrange_last.at(full_circuit_size - 1) = 1; + prover_polynomials.lagrange_last.at(key.dyadic_circuit_size - 1) = 1; // Put random values in all the non-interleaved constraint polynomials used to range constrain the values auto fill_polynomial_with_random_14_bit_values = [&](auto& polynomial) { @@ -60,7 +59,6 @@ TEST_F(TranslatorRelationCorrectnessTests, Permutation) // Compute the grand product polynomial compute_grand_product>(prover_polynomials, params); - prover_polynomials.z_perm_shift = prover_polynomials.z_perm.shifted(); // Check that permutation relation is satisfied across each row of the prover polynomials RelationChecker::check>( @@ -74,15 +72,15 @@ TEST_F(TranslatorRelationCorrectnessTests, DeltaRangeConstraint) using ProverPolynomials = typename Flavor::ProverPolynomials; auto& engine = numeric::get_debug_randomness(); const size_t mini_circuit_size = 2048; - const size_t full_circuit_size = Flavor::INTERLEAVING_GROUP_SIZE * mini_circuit_size; const auto sort_step = Flavor::SORT_STEP; const auto max_value = (1 << Flavor::MICRO_LIMB_BITS) - 1; - ProverPolynomials prover_polynomials(mini_circuit_size); + TranslatorProvingKey key{ mini_circuit_size }; + ProverPolynomials& prover_polynomials = key.proving_key->polynomials; // Construct lagrange polynomials that are needed for Translator's DeltaRangeConstraint Relation prover_polynomials.lagrange_first.at(0) = 0; - prover_polynomials.lagrange_real_last.at(full_circuit_size - 1) = 1; + prover_polynomials.lagrange_real_last.at(key.dyadic_circuit_size - 1) = 1; // Create a vector and fill with necessary steps for the DeltaRangeConstraint relation auto sorted_elements_count = (max_value / sort_step) + 1; @@ -645,147 +643,147 @@ TEST_F(TranslatorRelationCorrectnessTests, NonNative) prover_polynomials, params, "TranslatorNonNativeFieldRelation"); } -TEST_F(TranslatorRelationCorrectnessTests, ZeroKnowledgePermutation) -{ - using Flavor = TranslatorFlavor; - using FF = typename Flavor::FF; - using ProverPolynomials = typename Flavor::ProverPolynomials; - - const size_t mini_circuit_size = 2048; - auto& engine = numeric::get_debug_randomness(); - const size_t full_circuit_size = mini_circuit_size * Flavor::INTERLEAVING_GROUP_SIZE; - const size_t full_masking_offset = MASKING_OFFSET * Flavor::INTERLEAVING_GROUP_SIZE; - const size_t real_circuit_size = full_circuit_size - full_masking_offset; - - TranslatorProvingKey key{ mini_circuit_size }; - ProverPolynomials& prover_polynomials = key.proving_key->polynomials; - - // Fill required relation parameters - RelationParameters params{ .beta = FF::random_element(), .gamma = FF::random_element() }; - - // Populate the group polynomials with appropriate values and also enough random values to mask their commitment and - // evaluation - auto fill_polynomial_with_random_14_bit_values = [&](auto& polynomial) { - for (size_t i = polynomial.start_index(); i < polynomial.end_index() - MASKING_OFFSET; i++) { - polynomial.at(i) = engine.get_random_uint16() & ((1 << Flavor::MICRO_LIMB_BITS) - 1); - } - for (size_t i = polynomial.end_index() - MASKING_OFFSET; i < polynomial.end_index(); i++) { - polynomial.at(i) = FF::random_element(); - } - }; - - for (const auto& group : prover_polynomials.get_groups_to_be_interleaved()) { - for (auto& poly : group) { - fill_polynomial_with_random_14_bit_values(poly); - } - } - - // Fill in lagrange polynomials used in the permutation relation - prover_polynomials.lagrange_first.at(0) = 1; - prover_polynomials.lagrange_real_last.at(real_circuit_size - 1) = 1; - prover_polynomials.lagrange_last.at(full_circuit_size - 1) = 1; - for (size_t i = real_circuit_size; i < full_circuit_size; i++) { - prover_polynomials.lagrange_masking.at(i) = 1; - } - - key.compute_interleaved_polynomials(); - key.compute_extra_range_constraint_numerator(); - key.compute_translator_range_constraint_ordered_polynomials(true); - - // Populate the first 4 ordered polynomials with the random values from the interleaved polynomials - for (size_t i = 0; i < 4; i++) { - auto& ordered = prover_polynomials.get_ordered_range_constraints()[i]; - auto& interleaved = prover_polynomials.get_interleaved()[i]; - for (size_t j = real_circuit_size; j < full_circuit_size; j++) { - ordered.at(j) = interleaved.at(j); - } - } - - // Populate the last ordered range constraint and the extra polynomial in the numerator with random values - for (size_t i = real_circuit_size; i < full_circuit_size; i++) { - FF random_value = FF::random_element(); - prover_polynomials.ordered_extra_range_constraints_numerator.at(i) = random_value; - prover_polynomials.ordered_range_constraints_4.at(i) = random_value; - } - - // Compute the grand product polynomial - compute_grand_product>(prover_polynomials, params); - - // Check that permutation relation is satisfied across each row of the prover polynomials - RelationChecker::check>( - prover_polynomials, params, "TranslatorPermutationRelation"); - RelationChecker::check>( - prover_polynomials, params, "TranslatorPermutationRelation"); -} - -TEST_F(TranslatorRelationCorrectnessTests, ZeroKnowledgeDeltaRange) -{ - using Flavor = TranslatorFlavor; - using FF = typename Flavor::FF; - using ProverPolynomials = typename Flavor::ProverPolynomials; - auto& engine = numeric::get_debug_randomness(); - const size_t mini_circuit_size = 2048; - const size_t full_circuit_size = Flavor::INTERLEAVING_GROUP_SIZE * mini_circuit_size; - const auto sort_step = Flavor::SORT_STEP; - const auto max_value = (1 << Flavor::MICRO_LIMB_BITS) - 1; - - ProverPolynomials prover_polynomials(mini_circuit_size); - - const size_t full_masking_offset = MASKING_OFFSET * Flavor::INTERLEAVING_GROUP_SIZE; - const size_t real_circuit_size = full_circuit_size - full_masking_offset; - - // Construct lagrange polynomials that are needed for Translator's DeltaRangeConstraint Relation - prover_polynomials.lagrange_first.at(0) = 0; - prover_polynomials.lagrange_real_last.at(real_circuit_size - 1) = 1; - - for (size_t i = real_circuit_size; i < full_circuit_size; i++) { - prover_polynomials.lagrange_masking.at(i) = 1; - } - - // Create a vector and fill with necessary steps for the DeltaRangeConstraint relation - auto sorted_elements_count = (max_value / sort_step) + 1; - std::vector vector_for_sorting; - vector_for_sorting.reserve(prover_polynomials.ordered_range_constraints_0.size()); - for (size_t i = 0; i < sorted_elements_count - 1; i++) { - vector_for_sorting.emplace_back(i * sort_step); - } - vector_for_sorting[sorted_elements_count - 1] = max_value; - - // Add random values in the appropriate range to fill the leftover space - for (size_t i = sorted_elements_count; i < real_circuit_size; i++) { - vector_for_sorting.emplace_back(engine.get_random_uint16() & ((1 << Flavor::MICRO_LIMB_BITS) - 1)); - } - - // Get ordered polynomials - auto polynomial_pointers = std::vector{ &prover_polynomials.ordered_range_constraints_0, - &prover_polynomials.ordered_range_constraints_1, - &prover_polynomials.ordered_range_constraints_2, - &prover_polynomials.ordered_range_constraints_3, - &prover_polynomials.ordered_range_constraints_4 }; - - // Sort the vector - std::sort(vector_for_sorting.begin(), vector_for_sorting.end()); - - // Add masking values - for (size_t i = real_circuit_size; i < full_circuit_size; i++) { - vector_for_sorting.emplace_back(FF::random_element()); - } - - // Copy values, transforming them into Finite Field elements - std::transform(vector_for_sorting.cbegin(), - vector_for_sorting.cend(), - prover_polynomials.ordered_range_constraints_0.coeffs().begin(), - [](uint64_t in) { return FF(in); }); - - // Copy the same polynomial into the 4 other ordered polynomials (they are not the same in an actual proof, but - // we only need to check the correctness of the relation and it acts independently on each polynomial) - for (size_t i = 0; i < 4; ++i) { - std::copy(prover_polynomials.ordered_range_constraints_0.coeffs().begin(), - prover_polynomials.ordered_range_constraints_0.coeffs().end(), - polynomial_pointers[i + 1]->coeffs().begin()); - } - - // Check that DeltaRangeConstraint relation is satisfied across each row of the prover polynomials - RelationChecker::check>( - prover_polynomials, RelationParameters(), "TranslatorDeltaRangeConstraintRelation"); -} +// TEST_F(TranslatorRelationCorrectnessTests, ZeroKnowledgePermutation) +// { +// using Flavor = TranslatorFlavor; +// using FF = typename Flavor::FF; +// using ProverPolynomials = typename Flavor::ProverPolynomials; + +// const size_t mini_circuit_size = 2048; +// auto& engine = numeric::get_debug_randomness(); +// const size_t full_masking_offset = MASKING_OFFSET * Flavor::INTERLEAVING_GROUP_SIZE; + +// TranslatorProvingKey key{ mini_circuit_size }; +// ProverPolynomials& prover_polynomials = key.proving_key->polynomials; +// const size_t real_circuit_size = full_circuit_size - full_masking_offset; + +// // Fill required relation parameters +// RelationParameters params{ .beta = FF::random_element(), .gamma = FF::random_element() }; + +// // Populate the group polynomials with appropriate values and also enough random values to mask their commitment +// and +// // evaluation +// auto fill_polynomial_with_random_14_bit_values = [&](auto& polynomial) { +// for (size_t i = polynomial.start_index(); i < polynomial.end_index() - MASKING_OFFSET; i++) { +// polynomial.at(i) = engine.get_random_uint16() & ((1 << Flavor::MICRO_LIMB_BITS) - 1); +// } +// for (size_t i = polynomial.end_index() - MASKING_OFFSET; i < polynomial.end_index(); i++) { +// polynomial.at(i) = FF::random_element(); +// } +// }; + +// for (const auto& group : prover_polynomials.get_groups_to_be_interleaved()) { +// for (auto& poly : group) { +// fill_polynomial_with_random_14_bit_values(poly); +// } +// } + +// // Fill in lagrange polynomials used in the permutation relation +// prover_polynomials.lagrange_first.at(0) = 1; +// prover_polynomials.lagrange_real_last.at(real_circuit_size - 1) = 1; +// prover_polynomials.lagrange_last.at(full_circuit_size - 1) = 1; +// for (size_t i = real_circuit_size; i < full_circuit_size; i++) { +// prover_polynomials.lagrange_masking.at(i) = 1; +// } + +// key.compute_interleaved_polynomials(); +// key.compute_extra_range_constraint_numerator(); +// key.compute_translator_range_constraint_ordered_polynomials(true); + +// // Populate the first 4 ordered polynomials with the random values from the interleaved polynomials +// for (size_t i = 0; i < 4; i++) { +// auto& ordered = prover_polynomials.get_ordered_range_constraints()[i]; +// auto& interleaved = prover_polynomials.get_interleaved()[i]; +// for (size_t j = real_circuit_size; j < full_circuit_size; j++) { +// ordered.at(j) = interleaved.at(j); +// } +// } + +// // Populate the last ordered range constraint and the extra polynomial in the numerator with random values +// for (size_t i = real_circuit_size; i < full_circuit_size; i++) { +// FF random_value = FF::random_element(); +// prover_polynomials.ordered_extra_range_constraints_numerator.at(i) = random_value; +// prover_polynomials.ordered_range_constraints_4.at(i) = random_value; +// } + +// // Compute the grand product polynomial +// compute_grand_product>(prover_polynomials, params); + +// // Check that permutation relation is satisfied across each row of the prover polynomials +// RelationChecker::check>( +// prover_polynomials, params, "TranslatorPermutationRelation"); +// RelationChecker::check>( +// prover_polynomials, params, "TranslatorPermutationRelation"); +// } + +// TEST_F(TranslatorRelationCorrectnessTests, ZeroKnowledgeDeltaRange) +// { +// using Flavor = TranslatorFlavor; +// using FF = typename Flavor::FF; +// using ProverPolynomials = typename Flavor::ProverPolynomials; +// auto& engine = numeric::get_debug_randomness(); +// const size_t mini_circuit_size = 2048; +// const auto sort_step = Flavor::SORT_STEP; +// const auto max_value = (1 << Flavor::MICRO_LIMB_BITS) - 1; + +// TranslatorProvingKey key{ mini_circuit_size }; +// ProverPolynomials& prover_polynomials = key.proving_key->polynomials; + +// const size_t full_masking_offset = MASKING_OFFSET * Flavor::INTERLEAVING_GROUP_SIZE; +// const size_t real_circuit_size = key.dyadic_circuit_size - full_masking_offset; + +// // Construct lagrange polynomials that are needed for Translator's DeltaRangeConstraint Relation +// prover_polynomials.lagrange_first.at(0) = 0; +// prover_polynomials.lagrange_real_last.at(real_circuit_size - 1) = 1; + +// for (size_t i = real_circuit_size; i < key.dyadic_circuit_size; i++) { +// prover_polynomials.lagrange_masking.at(i) = 1; +// } + +// // Create a vector and fill with necessary steps for the DeltaRangeConstraint relation +// auto sorted_elements_count = (max_value / sort_step) + 1; +// std::vector vector_for_sorting; +// vector_for_sorting.reserve(prover_polynomials.ordered_range_constraints_0.size()); +// for (size_t i = 0; i < sorted_elements_count - 1; i++) { +// vector_for_sorting.emplace_back(i * sort_step); +// } +// vector_for_sorting[sorted_elements_count - 1] = max_value; + +// // Add random values in the appropriate range to fill the leftover space +// for (size_t i = sorted_elements_count; i < real_circuit_size; i++) { +// vector_for_sorting.emplace_back(engine.get_random_uint16() & ((1 << Flavor::MICRO_LIMB_BITS) - 1)); +// } + +// // Get ordered polynomials +// auto polynomial_pointers = std::vector{ &prover_polynomials.ordered_range_constraints_0, +// &prover_polynomials.ordered_range_constraints_1, +// &prover_polynomials.ordered_range_constraints_2, +// &prover_polynomials.ordered_range_constraints_3, +// &prover_polynomials.ordered_range_constraints_4 }; + +// // Sort the vector +// std::sort(vector_for_sorting.begin(), vector_for_sorting.end()); + +// // Add masking values +// for (size_t i = real_circuit_size; i < key.dyadic_circuit_size; i++) { +// vector_for_sorting.emplace_back(FF::random_element()); +// } + +// // Copy values, transforming them into Finite Field elements +// std::transform(vector_for_sorting.cbegin(), +// vector_for_sorting.cend(), +// prover_polynomials.ordered_range_constraints_0.coeffs().begin(), +// [](uint64_t in) { return FF(in); }); + +// // Copy the same polynomial into the 4 other ordered polynomials (they are not the same in an actual proof, but +// // we only need to check the correctness of the relation and it acts independently on each polynomial) +// for (size_t i = 0; i < 4; ++i) { +// std::copy(prover_polynomials.ordered_range_constraints_0.coeffs().begin(), +// prover_polynomials.ordered_range_constraints_0.coeffs().end(), +// polynomial_pointers[i + 1]->coeffs().begin()); +// } + +// // Check that DeltaRangeConstraint relation is satisfied across each row of the prover polynomials +// RelationChecker::check>( +// prover_polynomials, RelationParameters(), "TranslatorDeltaRangeConstraintRelation"); +// } diff --git a/barretenberg/cpp/src/barretenberg/translator_vm/translator_flavor.hpp b/barretenberg/cpp/src/barretenberg/translator_vm/translator_flavor.hpp index 0cf41a07c186..ec40bdbffd3c 100644 --- a/barretenberg/cpp/src/barretenberg/translator_vm/translator_flavor.hpp +++ b/barretenberg/cpp/src/barretenberg/translator_vm/translator_flavor.hpp @@ -43,8 +43,10 @@ class TranslatorFlavor { // A minicircuit of such size allows for 10 rounds of folding (i.e. 20 circuits). // Lowest possible size for the translator circuit (this sets the mini_circuit_size) + // Important: these constants cannot be arbitrarily changes - please consult with a member of the Crypto team if + // they become too small. static constexpr size_t MINIMUM_MINI_CIRCUIT_SIZE = 2048; - static constexpr size_t TRANSLATOR_VM_FIXED_SIZE = 8192; + static constexpr size_t TRANSLATOR_VM_FIXED_SIZE = 16384; static_assert(TRANSLATOR_VM_FIXED_SIZE >= MINIMUM_MINI_CIRCUIT_SIZE); // The size of the circuit which is filled with non-zero values for most polynomials. Most relations (everything @@ -302,6 +304,8 @@ class TranslatorFlavor { WireToBeShiftedEntities::get_all()); }; + auto get_wires_to_be_shifted() { return WireToBeShiftedEntities::get_all(); }; + /** * @brief Witness Entities to which the prover commits and do not require challenges (i.e. not derived). */ @@ -593,39 +597,60 @@ class TranslatorFlavor { public: // Define all operations as default, except copy construction/assignment ProverPolynomials() = default; - // Constructor to init all unshifted polys to the zero polynomial and set the shifted poly data - ProverPolynomials(size_t mini_circuit_size) + + /** + * @brief ProverPolynomials constructor + * @details Attempts to initialize polynomials efficiently by using the actual size of the mini circuit rather + * than the fixed dydaic size. + * + * @param actual_mini_circuit_size Actual number of rows in the Translator circuit. + */ + // TODO(https://github.com/AztecProtocol/barretenberg/issues/1318) + ProverPolynomials(size_t actual_mini_circuit_size) { - size_t circuit_size = mini_circuit_size * INTERLEAVING_GROUP_SIZE; + const size_t mini_circuit_size = TRANSLATOR_VM_FIXED_SIZE; + const size_t circuit_size = TRANSLATOR_VM_FIXED_SIZE * INTERLEAVING_GROUP_SIZE; + for (auto& ordered_range_constraint : get_ordered_range_constraints()) { ordered_range_constraint = Polynomial{ /*size*/ circuit_size - 1, - /*largest possible index*/ circuit_size, + /*virtual_size*/ circuit_size, 1 }; } - for (auto& interleaved : get_interleaved()) { - interleaved = Polynomial{ /*size*/ circuit_size, circuit_size }; - } z_perm = Polynomial{ /*size*/ circuit_size - 1, /*virtual_size*/ circuit_size, /*start_index*/ 1 }; - // All to_be_shifted witnesses except the ordered range constraints and z_perm are only non-zero in the mini - // circuit - for (auto& poly : get_to_be_shifted()) { - if (poly.is_empty()) { - poly = Polynomial{ /*size*/ mini_circuit_size - 1, - /*virtual_size*/ circuit_size, - /*start_index*/ 1 }; - } + // Initialize to be shifted wires based on actual size of the mini circuit + for (auto& poly : get_wires_to_be_shifted()) { + poly = Polynomial{ /*size*/ actual_mini_circuit_size - 1, + /*virtual_size*/ circuit_size, + /*start_index*/ 1 }; + } + + // Initialize interleaved polys based on actual mini circuit size times number of polys to be interleaved + const size_t actual_circuit_size = actual_mini_circuit_size * INTERLEAVING_GROUP_SIZE; + for (auto& poly : get_interleaved()) { + poly = Polynomial{ actual_circuit_size, circuit_size }; } + // Initialize some one-off polys with special structure + lagrange_first = Polynomial{ /*size*/ 1, /*virtual_size*/ circuit_size }; + lagrange_second = Polynomial{ /*size*/ 2, /*virtual_size*/ circuit_size }; + lagrange_even_in_minicircuit = Polynomial{ /*size*/ mini_circuit_size, /*virtual_size*/ circuit_size }; + lagrange_odd_in_minicircuit = Polynomial{ /*size*/ mini_circuit_size, /*virtual_size*/ circuit_size }; + + // WORKTODO: why does limiting this to actual_mini_circuit_size not work? + op = Polynomial{ circuit_size }; // Polynomial{ actual_mini_circuit_size, circuit_size }; + + // Catch-all for the rest of the polynomials + // WORKTODO: determine what exactly falls in here and be more specific (just the remaining precomputed?) for (auto& poly : get_unshifted()) { - if (poly.is_empty()) { - // Not set above + if (poly.is_empty()) { // Only set those polys which were not already set above poly = Polynomial{ circuit_size }; } } + // Set all shifted polynomials based on their unshifted counterpart set_shifted(); } ProverPolynomials& operator=(const ProverPolynomials&) = delete; @@ -669,9 +694,17 @@ class TranslatorFlavor { using Base::Base; ProvingKey() = default; - ProvingKey(const size_t dyadic_circuit_size, std::shared_ptr commitment_key = nullptr) + // WORKTODO: this is a constructor used only in tests. We should get rid of it or make it a test-only method. + ProvingKey(const size_t dyadic_circuit_size, const size_t actual_mini_circuit_size) + : Base(dyadic_circuit_size, 0) + , polynomials(actual_mini_circuit_size) + {} + + ProvingKey(const size_t dyadic_circuit_size, + std::shared_ptr commitment_key, + const size_t actual_mini_circuit_size) : Base(dyadic_circuit_size, 0, std::move(commitment_key)) - , polynomials(this->circuit_size) + , polynomials(actual_mini_circuit_size) {} }; diff --git a/barretenberg/cpp/src/barretenberg/translator_vm/translator_prover.cpp b/barretenberg/cpp/src/barretenberg/translator_vm/translator_prover.cpp index bf80cd46b943..a22ef722b801 100644 --- a/barretenberg/cpp/src/barretenberg/translator_vm/translator_prover.cpp +++ b/barretenberg/cpp/src/barretenberg/translator_vm/translator_prover.cpp @@ -134,8 +134,13 @@ void TranslatorProver::execute_relation_check_rounds() gate_challenges[idx] = transcript->template get_challenge("Sumcheck:gate_challenge_" + std::to_string(idx)); } - // // create masking polynomials for sumcheck round univariates and auxiliary data - zk_sumcheck_data = ZKData(key->proving_key->log_circuit_size, transcript, key->proving_key->commitment_key); + const size_t log_subgroup_size = static_cast(numeric::get_msb(Flavor::Curve::SUBGROUP_SIZE)); + // // Create a temporary commitment key that is only used to initialise the ZKSumcheckData + // // If proving in WASM, the commitment key that is part of the Translator proving key remains deallocated + // // until we enter the PCS round + auto ck = std::make_shared(1 << (log_subgroup_size + 1)); + + zk_sumcheck_data = ZKData(key->proving_key->log_circuit_size, transcript, ck); sumcheck_output = sumcheck.prove(key->proving_key->polynomials, relation_parameters, alpha, gate_challenges, zk_sumcheck_data); @@ -154,11 +159,12 @@ void TranslatorProver::execute_pcs_rounds() using SmallSubgroupIPA = SmallSubgroupIPAProver; using PolynomialBatcher = GeminiProver_::PolynomialBatcher; - SmallSubgroupIPA small_subgroup_ipa_prover(zk_sumcheck_data, - sumcheck_output.challenge, - sumcheck_output.claimed_libra_evaluation, - transcript, - key->proving_key->commitment_key); + // Check whether the commitment key has been deallocated and reinitialise it if necessary + auto& ck = key->proving_key->commitment_key; + ck = ck ? ck : std::make_shared(key->proving_key->circuit_size); + + SmallSubgroupIPA small_subgroup_ipa_prover( + zk_sumcheck_data, sumcheck_output.challenge, sumcheck_output.claimed_libra_evaluation, transcript, ck); small_subgroup_ipa_prover.prove(); PolynomialBatcher polynomial_batcher(key->proving_key->circuit_size); @@ -171,11 +177,11 @@ void TranslatorProver::execute_pcs_rounds() ShpleminiProver_::prove(key->proving_key->circuit_size, polynomial_batcher, sumcheck_output.challenge, - key->proving_key->commitment_key, + ck, transcript, small_subgroup_ipa_prover.get_witness_polynomials()); - PCS::compute_opening_proof(key->proving_key->commitment_key, prover_opening_claim, transcript); + PCS::compute_opening_proof(ck, prover_opening_claim, transcript); } HonkProof TranslatorProver::export_proof() @@ -198,6 +204,11 @@ HonkProof TranslatorProver::construct_proof() // Compute grand product(s) and commitments. execute_grand_product_computation_round(); + // #ifndef __wasm__ + // Free the commitment key + key->proving_key->commitment_key = nullptr; + // #endif + // Fiat-Shamir: alpha // Run sumcheck subprotocol. execute_relation_check_rounds(); @@ -206,7 +217,6 @@ HonkProof TranslatorProver::construct_proof() // Execute Shplemini PCS execute_pcs_rounds(); vinfo("computed opening proof"); - return export_proof(); } 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 2ec1c1382abb..82c7dee50084 100644 --- a/barretenberg/cpp/src/barretenberg/translator_vm/translator_proving_key.hpp +++ b/barretenberg/cpp/src/barretenberg/translator_vm/translator_proving_key.hpp @@ -3,6 +3,7 @@ #include "barretenberg/translator_vm/translator_flavor.hpp" namespace bb { +// TODO(https://github.com/AztecProtocol/barretenberg/issues/1317) class TranslatorProvingKey { public: using Flavor = TranslatorFlavor; @@ -23,13 +24,11 @@ class TranslatorProvingKey { TranslatorProvingKey() = default; - TranslatorProvingKey(size_t mini_circuit_dyadic_size) - : mini_circuit_dyadic_size(mini_circuit_dyadic_size) - , dyadic_circuit_size(mini_circuit_dyadic_size * Flavor::INTERLEAVING_GROUP_SIZE) - , proving_key(std::make_shared(dyadic_circuit_size)) - + TranslatorProvingKey(size_t actual_mini_circuit_size) { - proving_key->polynomials = Flavor::ProverPolynomials(mini_circuit_dyadic_size); + compute_mini_circuit_dyadic_size(actual_mini_circuit_size); + compute_dyadic_circuit_size(); + proving_key = std::make_shared(dyadic_circuit_size, actual_mini_circuit_size); } TranslatorProvingKey(const Circuit& circuit, std::shared_ptr commitment_key = nullptr) @@ -38,15 +37,19 @@ class TranslatorProvingKey { { PROFILE_THIS_NAME("TranslatorProvingKey(TranslatorCircuit&)"); - compute_mini_circuit_dyadic_size(circuit); + // WORKTODO: the methods below just set the constant values TRANSLATOR_VM_FIXED_SIZE and + // TRANSLATOR_VM_FIXED_SIZE * INTERLEAVING_GROUP_SIZE + compute_mini_circuit_dyadic_size(circuit.num_gates); compute_dyadic_circuit_size(); - proving_key = std::make_shared(dyadic_circuit_size, std::move(commitment_key)); - proving_key->polynomials = Flavor::ProverPolynomials(mini_circuit_dyadic_size); + + proving_key = std::make_shared( + dyadic_circuit_size, std::move(commitment_key), /*actual_mini_ circuit_size=*/circuit.num_gates); // Populate the wire polynomials from the wire vectors in the circuit for (auto [wire_poly_, wire_] : zip_view(proving_key->polynomials.get_wires(), circuit.wires)) { auto& wire_poly = wire_poly_; const auto& wire = wire_; + // WORKTODO: I think we should share memory here in the same way we do in the `DeciderProvingKey` class. parallel_for_range(circuit.num_gates, [&](size_t start, size_t end) { for (size_t i = start; i < end; i++) { if (i >= wire_poly.start_index() && i < wire_poly.end_index()) { @@ -88,11 +91,11 @@ class TranslatorProvingKey { dyadic_circuit_size = mini_circuit_dyadic_size * Flavor::INTERLEAVING_GROUP_SIZE; } - inline void compute_mini_circuit_dyadic_size(const Circuit& circuit) + inline void compute_mini_circuit_dyadic_size(size_t num_gates) { // 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::TRANSLATOR_VM_FIXED_SIZE) { + if (num_gates > Flavor::TRANSLATOR_VM_FIXED_SIZE) { throw_or_abort("The Translator circuit size has exceeded the fixed upper bound"); } mini_circuit_dyadic_size = Flavor::TRANSLATOR_VM_FIXED_SIZE;