From 954a37ae2b0603b1e8dec9fd869cc8ca10a8b9ab Mon Sep 17 00:00:00 2001 From: ledwards2225 <98505400+ledwards2225@users.noreply.github.com> Date: Wed, 22 Feb 2023 13:46:51 -0700 Subject: [PATCH] =?UTF-8?q?split=20witness=20out,=20deprecate=20poly=20man?= =?UTF-8?q?ifest,=20unify=20sumcheck=20pcs=20inputs=E2=80=A6=20(#159)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * split witness out, deprecate poly manifest, unify sumcheck pcs inputs, WiP but all tests passing * minor updates * cleanup and rebase fixes * split up wires and z perm in prover * making sumcheck related tests use enum for poly ordering * remove poly manifest from prover tests * make two more test suites rely on enum for poly ordering * making verifier properly depend on enum * fixed one more test, enum can now be permuted arbitrarily up to category * automating claim construction in verifier * completely removing Multivariates * attempt to fix build error in CCI * remove honk poly manifest altogether * witness properly moved from composer helper to prover * fix bad access of wires in pkey in some tests * adding comments and doing some general cleanup --- .../composer_helper/composer_helper.cpp | 115 ++--------- .../composer_helper/composer_helper.hpp | 14 +- .../composer/standard_honk_composer.test.cpp | 64 +++--- cpp/src/aztec/honk/proof_system/prover.cpp | 120 +++++------ cpp/src/aztec/honk/proof_system/prover.hpp | 33 +-- .../aztec/honk/proof_system/prover.test.cpp | 52 ++--- cpp/src/aztec/honk/proof_system/verifier.cpp | 56 ++---- cpp/src/aztec/honk/proof_system/verifier.hpp | 1 - .../aztec/honk/proof_system/verifier.test.cpp | 7 +- .../sumcheck/polynomials/multivariates.hpp | 145 -------------- .../polynomials/multivariates.test.cpp | 116 +++++------ .../honk/sumcheck/relations/relation.test.cpp | 30 ++- cpp/src/aztec/honk/sumcheck/sumcheck.hpp | 174 ++++++++++------ cpp/src/aztec/honk/sumcheck/sumcheck.test.cpp | 188 +++++++++++++----- .../honk/sumcheck/sumcheck_round.test.cpp | 61 ++++-- cpp/src/aztec/proof_system/flavor/flavor.hpp | 48 ++++- .../types/polynomial_manifest.hpp | 31 --- .../stdlib/primitives/bool/bool.test.cpp | 38 ++-- .../stdlib/primitives/field/field.test.cpp | 14 +- 19 files changed, 626 insertions(+), 681 deletions(-) delete mode 100644 cpp/src/aztec/honk/sumcheck/polynomials/multivariates.hpp diff --git a/cpp/src/aztec/honk/composer/composer_helper/composer_helper.cpp b/cpp/src/aztec/honk/composer/composer_helper/composer_helper.cpp index 0914c2948b..8eaccc43ac 100644 --- a/cpp/src/aztec/honk/composer/composer_helper/composer_helper.cpp +++ b/cpp/src/aztec/honk/composer/composer_helper/composer_helper.cpp @@ -80,32 +80,27 @@ template std::shared_ptr ComposerHelper::compute_verification_key_base( std::shared_ptr const& proving_key, std::shared_ptr const& vrs) { - auto circuit_verification_key = std::make_shared( + auto key = std::make_shared( proving_key->circuit_size, proving_key->num_public_inputs, vrs, proving_key->composer_type); // TODO(kesha): Dirty hack for now. Need to actually make commitment-agnositc auto commitment_key = pcs::kzg::CommitmentKey(proving_key->circuit_size, "../srs_db/ignition"); - for (size_t i = 0; i < proving_key->polynomial_manifest.size(); ++i) { - const auto& poly_info = proving_key->polynomial_manifest[i]; - - const std::string poly_label(poly_info.polynomial_label); - const std::string selector_commitment_label(poly_info.commitment_label); - - if (poly_info.source == bonk::PolynomialSource::SELECTOR || - poly_info.source == bonk::PolynomialSource::PERMUTATION || - poly_info.source == bonk::PolynomialSource::OTHER) { - - // Commit to the constraint selector polynomial and insert the commitment in the verification key. - - auto poly_commitment = commitment_key.commit(proving_key->polynomial_cache.get(poly_label)); - circuit_verification_key->commitments.insert({ selector_commitment_label, poly_commitment }); - } - } - - // Set the polynomial manifest in verification key. - circuit_verification_key->polynomial_manifest = bonk::PolynomialManifest(proving_key->composer_type); - - return circuit_verification_key; + // Compute and store commitments to all precomputed polynomials + key->commitments["Q_M"] = commitment_key.commit(proving_key->polynomial_cache.get("q_m_lagrange")); + key->commitments["Q_1"] = commitment_key.commit(proving_key->polynomial_cache.get("q_1_lagrange")); + key->commitments["Q_2"] = commitment_key.commit(proving_key->polynomial_cache.get("q_2_lagrange")); + key->commitments["Q_3"] = commitment_key.commit(proving_key->polynomial_cache.get("q_3_lagrange")); + key->commitments["Q_C"] = commitment_key.commit(proving_key->polynomial_cache.get("q_c_lagrange")); + key->commitments["SIGMA_1"] = commitment_key.commit(proving_key->polynomial_cache.get("sigma_1_lagrange")); + key->commitments["SIGMA_2"] = commitment_key.commit(proving_key->polynomial_cache.get("sigma_2_lagrange")); + key->commitments["SIGMA_3"] = commitment_key.commit(proving_key->polynomial_cache.get("sigma_3_lagrange")); + key->commitments["ID_1"] = commitment_key.commit(proving_key->polynomial_cache.get("id_1_lagrange")); + key->commitments["ID_2"] = commitment_key.commit(proving_key->polynomial_cache.get("id_2_lagrange")); + key->commitments["ID_3"] = commitment_key.commit(proving_key->polynomial_cache.get("id_3_lagrange")); + key->commitments["LAGRANGE_FIRST"] = commitment_key.commit(proving_key->polynomial_cache.get("L_first_lagrange")); + key->commitments["LAGRANGE_LAST"] = commitment_key.commit(proving_key->polynomial_cache.get("L_last_lagrange")); + + return key; } /** @@ -151,23 +146,22 @@ void ComposerHelper::compute_witness_base(const CircuitConst for (size_t j = 0; j < program_width; ++j) { // Initialize the polynomial with all the actual copies variable values // Expect all values to be set to 0 initially - polynomial w_lagrange(subgroup_size); + // Construct wire polynomials in place + auto& wire_lagrange = wire_polynomials.emplace_back(polynomial(subgroup_size)); // Place all public inputs at the start of w_l and w_r. // All selectors at these indices are set to 0 so these values are not constrained at all. if ((j == 0) || (j == 1)) { for (size_t i = 0; i < num_public_inputs; ++i) { - w_lagrange[i] = circuit_constructor.get_variable(public_inputs[i]); + wire_lagrange[i] = circuit_constructor.get_variable(public_inputs[i]); } } // Assign the variable values (which are pointed-to by the `w_` wires) to the wire witness polynomials // `poly_w_`, shifted to make room for the public inputs at the beginning. for (size_t i = 0; i < num_gates; ++i) { - w_lagrange[num_public_inputs + i] = circuit_constructor.get_variable(w[j][i]); + wire_lagrange[num_public_inputs + i] = circuit_constructor.get_variable(w[j][i]); } - std::string index = std::to_string(j + 1); - circuit_proving_key->polynomial_cache.put("w_" + index + "_lagrange", std::move(w_lagrange)); } computed_witness = true; @@ -223,32 +217,6 @@ std::shared_ptr ComposerHelper::comp return circuit_verification_key; } -/** - * Create verifier: compute verification key, - * initialize verifier with it and an initial manifest and initialize commitment_scheme. - * - * @return The verifier. - * */ -// TODO(Cody): This should go away altogether. -template -StandardVerifier ComposerHelper::create_verifier(const CircuitConstructor& circuit_constructor) -{ - auto verification_key = compute_verification_key(circuit_constructor); - // TODO figure out types, actually - // circuit_verification_key->composer_type = type; - - // TODO: initialize verifier according to manifest and key - // Verifier output_state(circuit_verification_key, create_manifest(public_inputs.size())); - StandardVerifier output_state; - // TODO: Do we need a commitment scheme defined here? - // std::unique_ptr> kate_commitment_scheme = - // std::make_unique>(); - - // output_state.commitment_scheme = std::move(kate_commitment_scheme); - - return output_state; -} - template StandardUnrolledVerifier ComposerHelper::create_unrolled_verifier( const CircuitConstructor& circuit_constructor) @@ -278,7 +246,7 @@ StandardUnrolledProver ComposerHelper::create_unrolled_prove size_t num_sumcheck_rounds(circuit_proving_key->log_circuit_size); auto manifest = Flavor::create_unrolled_manifest(circuit_constructor.public_inputs.size(), num_sumcheck_rounds); - StandardUnrolledProver output_state(circuit_proving_key, manifest); + StandardUnrolledProver output_state(std::move(wire_polynomials), circuit_proving_key, manifest); // TODO(Cody): This should be more generic std::unique_ptr kate_commitment_key = @@ -288,45 +256,6 @@ StandardUnrolledProver ComposerHelper::create_unrolled_prove return output_state; } -/** - * Create prover. - * 1. Compute the starting polynomials (q_l, etc, sigma, witness polynomials). - * 2. Initialize StandardProver with them. - * 3. Add Permutation and arithmetic widgets to the prover. - * 4. Add KateCommitmentScheme to the prover. - * - * @return Initialized prover. - * */ -template -StandardProver ComposerHelper::create_prover(const CircuitConstructor& circuit_constructor) -{ - // Compute q_l, etc. and sigma polynomials. - compute_proving_key(circuit_constructor); - - // Compute witness polynomials. - compute_witness(circuit_constructor); - // TODO: Initialize prover properly - // Prover output_state(circuit_proving_key, create_manifest(public_inputs.size())); - StandardProver output_state(circuit_proving_key); - // Initialize constraints - - // std::unique_ptr> permutation_widget = - // std::make_unique>(circuit_proving_key.get()); - - // std::unique_ptr> arithmetic_widget = - // std::make_unique>(circuit_proving_key.get()); - - // output_state.random_widgets.emplace_back(std::move(permutation_widget)); - // output_state.transition_widgets.emplace_back(std::move(arithmetic_widget)); - - // Is commitment scheme going to stay a part of the prover? Why is it here? - // std::unique_ptr> kate_commitment_scheme = - // std::make_unique>(); - - // output_state.commitment_scheme = std::move(kate_commitment_scheme); - - return output_state; -} template class ComposerHelper; template StandardUnrolledProver ComposerHelper::create_unrolled_prover( diff --git a/cpp/src/aztec/honk/composer/composer_helper/composer_helper.hpp b/cpp/src/aztec/honk/composer/composer_helper/composer_helper.hpp index 9c11fabb1e..97c3ff00b2 100644 --- a/cpp/src/aztec/honk/composer/composer_helper/composer_helper.hpp +++ b/cpp/src/aztec/honk/composer/composer_helper/composer_helper.hpp @@ -1,5 +1,6 @@ #pragma once +#include "polynomials/polynomial.hpp" #include #include #include @@ -20,6 +21,7 @@ template class ComposerHelper { static constexpr size_t NUM_RANDOMIZED_GATES = 2; // equal to the number of multilinear evaluations leaked static constexpr size_t program_width = CircuitConstructor::program_width; std::shared_ptr circuit_proving_key; + std::vector wire_polynomials; std::shared_ptr circuit_verification_key; // TODO(kesha): we need to put this into the commitment key, so that the composer doesn't have to handle srs at all std::shared_ptr crs_factory_; @@ -53,18 +55,6 @@ template class ComposerHelper { compute_witness_base(circuit_constructor); } - StandardVerifier create_verifier(const CircuitConstructor& circuit_constructor); - /** - * Preprocess the circuit. Delegates to create_prover. - * - * @return A new initialized prover. - */ - StandardProver preprocess(const CircuitConstructor& circuit_constructor) - { - return create_prover(circuit_constructor); - }; - StandardProver create_prover(const CircuitConstructor& circuit_constructor); - StandardUnrolledVerifier create_unrolled_verifier(const CircuitConstructor& circuit_constructor); template diff --git a/cpp/src/aztec/honk/composer/standard_honk_composer.test.cpp b/cpp/src/aztec/honk/composer/standard_honk_composer.test.cpp index 50d3b70e95..897cf0fb00 100644 --- a/cpp/src/aztec/honk/composer/standard_honk_composer.test.cpp +++ b/cpp/src/aztec/honk/composer/standard_honk_composer.test.cpp @@ -1,9 +1,9 @@ #include "standard_honk_composer.hpp" #include "common/assert.hpp" #include "numeric/uint256/uint256.hpp" +#include "proof_system/flavor/flavor.hpp" #include #include -#include #include #include #include @@ -70,7 +70,7 @@ TEST(standard_honk_composer, test_sigma_and_id_correctness) for (size_t j = 0; j < composer.program_width; ++j) { std::string index = std::to_string(j + 1); const auto& permutation_polynomial = proving_key->polynomial_cache.get("sigma_" + index + "_lagrange"); - const auto& witness_polynomial = proving_key->polynomial_cache.get("w_" + index + "_lagrange"); + const auto& witness_polynomial = composer.composer_helper.wire_polynomials[j]; const auto& id_polynomial = proving_key->polynomial_cache.get("id_" + index + "_lagrange"); // left = ∏ᵢ,ⱼ(ωᵢ,ⱼ + β⋅ind(i,j) + γ) // right = ∏ᵢ,ⱼ(ωᵢ,ⱼ + β⋅σ(i,j) + γ) @@ -338,7 +338,7 @@ TEST(standard_honk_composer, test_check_sumcheck_relations_correctness) fr gamma = fr::random_element(); // Compute grand product polynomial (now all the necessary polynomials are inside the proving key) - prover.compute_grand_product_polynomial(beta, gamma); + auto z_permutation = prover.compute_grand_product_polynomial(beta, gamma); // Compute public input delta const auto public_inputs = composer.circuit_constructor.get_public_inputs(); @@ -346,10 +346,9 @@ TEST(standard_honk_composer, test_check_sumcheck_relations_correctness) honk::compute_public_input_delta(public_inputs, beta, gamma, prover.key->circuit_size); // Retrieve polynomials from proving key - polynomial z_perm = prover.key->polynomial_cache.get("z_perm_lagrange"); - polynomial w_1 = prover.key->polynomial_cache.get("w_1_lagrange"); - polynomial w_2 = prover.key->polynomial_cache.get("w_2_lagrange"); - polynomial w_3 = prover.key->polynomial_cache.get("w_3_lagrange"); + polynomial w_1 = prover.wire_polynomials[0]; + polynomial w_2 = prover.wire_polynomials[1]; + polynomial w_3 = prover.wire_polynomials[2]; polynomial q_m = prover.key->polynomial_cache.get("q_m_lagrange"); polynomial q_1 = prover.key->polynomial_cache.get("q_1_lagrange"); polynomial q_2 = prover.key->polynomial_cache.get("q_2_lagrange"); @@ -367,9 +366,8 @@ TEST(standard_honk_composer, test_check_sumcheck_relations_correctness) // Specify sumcheck configuration using honk::sumcheck::Univariate; using honk::sumcheck::UnivariateView; - using Multivariates = honk::sumcheck::Multivariates; using SumCheckRound = honk::sumcheck::SumcheckRound; @@ -394,6 +392,8 @@ TEST(standard_honk_composer, test_check_sumcheck_relations_correctness) // Transpose the polynomials so that each entry of the vector contains an array of polynomial entries at that // index + std::array, bonk::StandardArithmetization::NUM_POLYNOMIALS> + univariate_array; for (size_t i = 0; i < prover.key->circuit_size; i++) { // We only fill in the first element of each univariate with the value of an entry from the original poynomial StandardUnivariate w_1_univariate(0); @@ -403,9 +403,9 @@ TEST(standard_honk_composer, test_check_sumcheck_relations_correctness) StandardUnivariate w_3_univariate(0); w_3_univariate.value_at(0) = w_3[i]; StandardUnivariate z_perm_univariate(0); - z_perm_univariate.value_at(0) = z_perm[i]; + z_perm_univariate.value_at(0) = z_permutation[i]; StandardUnivariate z_perm_shift_univariate(0); - z_perm_shift_univariate.value_at(0) = (i < (prover.key->circuit_size - 1)) ? z_perm[i + 1] : 0; + z_perm_shift_univariate.value_at(0) = (i < (prover.key->circuit_size - 1)) ? z_permutation[i + 1] : 0; StandardUnivariate q_m_univariate(0); q_m_univariate.value_at(0) = q_m[i]; StandardUnivariate q_1_univariate(0); @@ -432,26 +432,28 @@ TEST(standard_honk_composer, test_check_sumcheck_relations_correctness) L_first_univariate.value_at(0) = L_first[i]; StandardUnivariate L_last_univariate(0); L_last_univariate.value_at(0) = L_last[i]; - sumcheck_typed_polynomial_vector.push_back({ - w_1_univariate, - w_2_univariate, - w_3_univariate, - z_perm_univariate, - z_perm_shift_univariate, - q_m_univariate, - q_1_univariate, - q_2_univariate, - q_3_univariate, - q_c_univariate, - sigma_1_univariate, - sigma_2_univariate, - sigma_3_univariate, - id_1_univariate, - id_2_univariate, - id_3_univariate, - L_first_univariate, - L_last_univariate, - }); + + using POLYNOMIAL = bonk::StandardArithmetization::POLYNOMIAL; + univariate_array[POLYNOMIAL::W_L] = w_1_univariate; + univariate_array[POLYNOMIAL::W_R] = w_2_univariate; + univariate_array[POLYNOMIAL::W_O] = w_3_univariate; + univariate_array[POLYNOMIAL::Z_PERM] = z_perm_univariate; + univariate_array[POLYNOMIAL::Z_PERM_SHIFT] = z_perm_shift_univariate; + univariate_array[POLYNOMIAL::Q_M] = q_m_univariate; + univariate_array[POLYNOMIAL::Q_L] = q_1_univariate; + univariate_array[POLYNOMIAL::Q_R] = q_2_univariate; + univariate_array[POLYNOMIAL::Q_O] = q_3_univariate; + univariate_array[POLYNOMIAL::Q_C] = q_c_univariate; + univariate_array[POLYNOMIAL::SIGMA_1] = sigma_1_univariate; + univariate_array[POLYNOMIAL::SIGMA_2] = sigma_2_univariate; + univariate_array[POLYNOMIAL::SIGMA_3] = sigma_3_univariate; + univariate_array[POLYNOMIAL::ID_1] = id_1_univariate; + univariate_array[POLYNOMIAL::ID_2] = id_2_univariate; + univariate_array[POLYNOMIAL::ID_3] = id_3_univariate; + univariate_array[POLYNOMIAL::LAGRANGE_FIRST] = L_first_univariate; + univariate_array[POLYNOMIAL::LAGRANGE_LAST] = L_last_univariate; + + sumcheck_typed_polynomial_vector.push_back(univariate_array); } // Check all relations at all indices for (size_t i = 0; i < prover.key->circuit_size; i++) { diff --git a/cpp/src/aztec/honk/proof_system/prover.cpp b/cpp/src/aztec/honk/proof_system/prover.cpp index 9bc9253311..8489d6133d 100644 --- a/cpp/src/aztec/honk/proof_system/prover.cpp +++ b/cpp/src/aztec/honk/proof_system/prover.cpp @@ -1,4 +1,5 @@ #include "prover.hpp" +#include #include #include // will need #include @@ -6,10 +7,12 @@ #include #include #include +#include +#include #include +#include "common/assert.hpp" #include "ecc/curves/bn254/fr.hpp" #include "ecc/curves/bn254/g1.hpp" -#include #include #include #include @@ -25,6 +28,7 @@ namespace honk { using Fr = barretenberg::fr; using Commitment = barretenberg::g1::affine_element; using Polynomial = barretenberg::Polynomial; +using POLYNOMIAL = bonk::StandardArithmetization::POLYNOMIAL; /** * Create Prover from proving key, witness and manifest. @@ -35,15 +39,36 @@ using Polynomial = barretenberg::Polynomial; * @tparam settings Settings class. * */ template -Prover::Prover(std::shared_ptr input_key, const transcript::Manifest& input_manifest) - : circuit_size(input_key == nullptr ? 0 : input_key->circuit_size) - , transcript(input_manifest, settings::hash_type, settings::num_challenge_bytes) +Prover::Prover(std::vector&& wire_polys, + std::shared_ptr input_key, + const transcript::Manifest& input_manifest) + : transcript(input_manifest, settings::hash_type, settings::num_challenge_bytes) + , wire_polynomials(wire_polys) // TODO(luke): move these properly , key(input_key) , commitment_key(std::make_unique( input_key->circuit_size, "../srs_db/ignition")) // TODO(Cody): Need better constructors for prover. // , queue(proving_key.get(), &transcript) // TODO(Adrian): explore whether it's needed -{} +{ + // Note(luke): This could be done programmatically with some hacks but this isnt too bad and its nice to see the + // polys laid out explicitly. + prover_polynomials[POLYNOMIAL::Q_C] = key->polynomial_cache.get("q_c_lagrange"); + prover_polynomials[POLYNOMIAL::Q_L] = key->polynomial_cache.get("q_1_lagrange"); + prover_polynomials[POLYNOMIAL::Q_R] = key->polynomial_cache.get("q_2_lagrange"); + prover_polynomials[POLYNOMIAL::Q_O] = key->polynomial_cache.get("q_3_lagrange"); + prover_polynomials[POLYNOMIAL::Q_M] = key->polynomial_cache.get("q_m_lagrange"); + prover_polynomials[POLYNOMIAL::SIGMA_1] = key->polynomial_cache.get("sigma_1_lagrange"); + prover_polynomials[POLYNOMIAL::SIGMA_2] = key->polynomial_cache.get("sigma_2_lagrange"); + prover_polynomials[POLYNOMIAL::SIGMA_3] = key->polynomial_cache.get("sigma_3_lagrange"); + prover_polynomials[POLYNOMIAL::ID_1] = key->polynomial_cache.get("id_1_lagrange"); + prover_polynomials[POLYNOMIAL::ID_2] = key->polynomial_cache.get("id_2_lagrange"); + prover_polynomials[POLYNOMIAL::ID_3] = key->polynomial_cache.get("id_3_lagrange"); + prover_polynomials[POLYNOMIAL::LAGRANGE_FIRST] = key->polynomial_cache.get("L_first_lagrange"); + prover_polynomials[POLYNOMIAL::LAGRANGE_LAST] = key->polynomial_cache.get("L_last_lagrange"); + prover_polynomials[POLYNOMIAL::W_L] = wire_polynomials[0]; + prover_polynomials[POLYNOMIAL::W_R] = wire_polynomials[1]; + prover_polynomials[POLYNOMIAL::W_O] = wire_polynomials[2]; +} /** * For Plonk systems: @@ -58,12 +83,9 @@ Prover::Prover(std::shared_ptr input_key, const tra template void Prover::compute_wire_commitments() { for (size_t i = 0; i < settings::program_width; ++i) { - std::string wire_tag = "w_" + std::to_string(i + 1) + "_lagrange"; - std::string commit_tag = "W_" + std::to_string(i + 1); - - auto commitment = commitment_key->commit(key->polynomial_cache.get(wire_tag)); + auto commitment = commitment_key->commit(wire_polynomials[i]); - transcript.add_element(commit_tag, commitment.to_buffer()); + transcript.add_element("W_" + std::to_string(i + 1), commitment.to_buffer()); } } @@ -93,8 +115,7 @@ template void Prover::compute_wire_commitments() * Note: Step (4) utilizes Montgomery batch inversion to replace n-many inversions with * one batch inversion (at the expense of more multiplications) */ -template -void Prover::compute_grand_product_polynomial(barretenberg::fr beta, barretenberg::fr gamma) +template Polynomial Prover::compute_grand_product_polynomial(Fr beta, Fr gamma) { using barretenberg::polynomial_arithmetic::copy_polynomial; static const size_t program_width = settings::program_width; @@ -111,9 +132,8 @@ void Prover::compute_grand_product_polynomial(barretenberg::fr beta, b std::array, program_width> wires; std::array, program_width> sigmas; for (size_t i = 0; i < program_width; ++i) { - std::string wire_id = "w_" + std::to_string(i + 1) + "_lagrange"; std::string sigma_id = "sigma_" + std::to_string(i + 1) + "_lagrange"; - wires[i] = key->polynomial_cache.get(wire_id); + wires[i] = wire_polynomials[i]; sigmas[i] = key->polynomial_cache.get(sigma_id); } @@ -175,9 +195,7 @@ void Prover::compute_grand_product_polynomial(barretenberg::fr beta, b aligned_free(denominator_accumulator[k]); } - // Commit to z_perm here? This would match Plonk but maybe best to do separately? - - key->polynomial_cache.put("z_perm_lagrange", std::move(z_perm)); + return z_perm; } /** @@ -197,10 +215,10 @@ template void Prover::execute_preamble_round() // queue.flush_queue(); // NOTE: Don't remove; we may reinstate the queue transcript.add_element("circuit_size", - { static_cast(circuit_size >> 24), - static_cast(circuit_size >> 16), - static_cast(circuit_size >> 8), - static_cast(circuit_size) }); + { static_cast(key->circuit_size >> 24), + static_cast(key->circuit_size >> 16), + static_cast(key->circuit_size >> 8), + static_cast(key->circuit_size) }); transcript.add_element("public_input_size", { static_cast(key->num_public_inputs >> 24), @@ -225,8 +243,9 @@ template void Prover::execute_wire_commitments_rou // queue.flush_queue(); // NOTE: Don't remove; we may reinstate the queue compute_wire_commitments(); - // Add public inputs to transcript - const Polynomial& public_wires_source = key->polynomial_cache.get("w_2_lagrange"); + // Add public inputs to transcript from the second wire polynomial + const Polynomial& public_wires_source = wire_polynomials[1]; + std::vector public_wires; for (size_t i = 0; i < key->num_public_inputs; ++i) { public_wires.push_back(public_wires_source[i]); @@ -267,10 +286,13 @@ template void Prover::execute_grand_product_comput auto beta = transcript.get_challenge_field_element("beta", 0); auto gamma = transcript.get_challenge_field_element("beta", 1); - compute_grand_product_polynomial(beta, gamma); + z_permutation = compute_grand_product_polynomial(beta, gamma); // The actual polynomial is of length n+1, but commitment key is just n, so we need to limit it - auto commitment = commitment_key->commit(key->polynomial_cache.get("z_perm_lagrange")); + auto commitment = commitment_key->commit(z_permutation); transcript.add_element("Z_PERM", commitment.to_buffer()); + + prover_polynomials[POLYNOMIAL::Z_PERM] = z_permutation; + prover_polynomials[POLYNOMIAL::Z_PERM_SHIFT] = z_permutation.shifted(); } /** @@ -289,21 +311,18 @@ template void Prover::execute_relation_check_round { // queue.flush_queue(); // NOTE: Don't remove; we may reinstate the queue - using Multivariates = sumcheck::Multivariates; using Transcript = transcript::StandardTranscript; - using Sumcheck = sumcheck::Sumcheck; - // Compute alpha challenge transcript.apply_fiat_shamir("alpha"); - auto multivariates = Multivariates(key); - auto sumcheck = Sumcheck(multivariates, transcript); + auto sumcheck = Sumcheck(key->circuit_size, transcript); - sumcheck.execute_prover(); + sumcheck.execute_prover(prover_polynomials); } /** @@ -327,9 +346,6 @@ template void Prover::execute_univariatization_rou std::vector opening_claims_shifted; std::vector> multivariate_polynomials; std::vector> multivariate_polynomials_shifted; - // TODO(luke): Currently feeding in mock commitments for non-WITNESS polynomials. This may be sufficient for simple - // proof verification since the other commitments are only needed to produce 'claims' in gemini.reduce_prove, they - // are not needed in the proof itself. // Construct MLE opening point // Note: for consistency the evaluation point must be constructed as u = (u_d,...,u_1) @@ -340,31 +356,19 @@ template void Prover::execute_univariatization_rou // Get vector of multivariate evaluations produced by Sumcheck auto multivariate_evaluations = transcript.get_field_element_vector("multivariate_evaluations"); - std::unordered_map evals_map; - size_t eval_idx = 0; - for (auto& entry : key->polynomial_manifest.get()) { - std::string label(entry.polynomial_label); - evals_map[label] = multivariate_evaluations[eval_idx++]; - if (entry.requires_shifted_evaluation) { - evals_map[label + "_shift"] = multivariate_evaluations[eval_idx++]; - } - } - // Construct opening claims and polynomials - // Note: the prover does not require genuine commitments to produce genuine proofs so we mock them. - for (auto& entry : key->polynomial_manifest.get()) { - std::string label(entry.polynomial_label); - - auto evaluation = evals_map[label]; - auto commitment = Commitment::one(); - opening_claims.emplace_back(commitment, evaluation); - multivariate_polynomials.emplace_back(key->polynomial_cache.get(label)); - if (entry.requires_shifted_evaluation) { - // Note: For a polynomial p for which we need the shift p_shift, we provide Gemini with the SHIFTED - // evaluation p_shift(u), but the UNSHIFTED polynomial p and its UNSHIFTED commitment [p]. - auto shifted_evaluation = evals_map[label + "_shift"]; - opening_claims_shifted.emplace_back(commitment, shifted_evaluation); - multivariate_polynomials_shifted.emplace_back(key->polynomial_cache.get(label)); + // Collect NON-shifted and shifted polynomials and opening claims based on enum. + auto mock_commitment = Commitment::one(); // prover does not require genuine commitments + for (size_t i = 0; i < bonk::StandardArithmetization::NUM_POLYNOMIALS; ++i) { + if (i < bonk::StandardArithmetization::NUM_UNSHIFTED_POLYNOMIALS) { + multivariate_polynomials.push_back(prover_polynomials[i]); + opening_claims.emplace_back(mock_commitment, multivariate_evaluations[i]); + } else { // shifted polynomials/claims + // Note: we must provide the NON-shifted polynomial but the shifted evaluation. + // TODO(luke): This is a bit hard-coded for standard Honk right now. Can do away with this after changing + // Gemini interface to accept shifted polynomials. + multivariate_polynomials_shifted.push_back(prover_polynomials[POLYNOMIAL::Z_PERM]); + opening_claims_shifted.emplace_back(mock_commitment, multivariate_evaluations[i]); } } diff --git a/cpp/src/aztec/honk/proof_system/prover.hpp b/cpp/src/aztec/honk/proof_system/prover.hpp index 4311321190..660f643c62 100644 --- a/cpp/src/aztec/honk/proof_system/prover.hpp +++ b/cpp/src/aztec/honk/proof_system/prover.hpp @@ -1,4 +1,9 @@ #pragma once +#include "ecc/curves/bn254/fr.hpp" +#include "polynomials/polynomial.hpp" +#include "proof_system/flavor/flavor.hpp" +#include "proof_system/polynomial_cache/polynomial_cache.hpp" +#include #include #include #include @@ -6,14 +11,20 @@ #include #include #include +#include +#include +#include namespace honk { +using Fr = barretenberg::fr; + template class Prover { public: // TODO(luke): update this appropriately to work with Honk Manifest - Prover(std::shared_ptr input_key = nullptr, + Prover(std::vector&& wire_polys, + std::shared_ptr input_key = nullptr, const transcript::Manifest& manifest = transcript::Manifest()); void execute_preamble_round(); @@ -28,27 +39,25 @@ template class Prover { void compute_wire_commitments(); - void compute_grand_product_polynomial(barretenberg::fr beta, barretenberg::fr gamma); + barretenberg::polynomial compute_grand_product_polynomial(Fr beta, Fr gamma); + + void construct_prover_polynomials(); plonk::proof& export_proof(); plonk::proof& construct_proof(); - size_t get_circuit_size() const { return circuit_size; } - - // TODO(luke): Eventually get rid of this but leave it for convenience for now - const size_t circuit_size; - - // No more widgets. The new 'relations' may be owned by Sumcheck rather than Prover... - // std::vector> random_widgets; - // std::vector>> transition_widgets; - - // TODO(luke): maybe pointer instead? transcript::StandardTranscript transcript; + std::vector wire_polynomials; + barretenberg::polynomial z_permutation; + std::shared_ptr key; std::shared_ptr commitment_key; + // Container for spans of all polynomials required by the prover (i.e. all multivariates evaluated by Sumcheck). + std::array, bonk::StandardArithmetization::POLYNOMIAL::COUNT> prover_polynomials; + // Honk only needs a small portion of the functionality but may be fine to use existing work_queue // NOTE: this is not currently in use, but it may well be used in the future. // TODO(Adrian): Uncomment when we need this again. diff --git a/cpp/src/aztec/honk/proof_system/prover.test.cpp b/cpp/src/aztec/honk/proof_system/prover.test.cpp index 3abe84b8e7..5ebaa91ce7 100644 --- a/cpp/src/aztec/honk/proof_system/prover.test.cpp +++ b/cpp/src/aztec/honk/proof_system/prover.test.cpp @@ -1,4 +1,6 @@ #include "prover.hpp" +#include "honk/composer/standard_honk_composer.hpp" +#include "polynomials/polynomial.hpp" #include #include @@ -13,26 +15,6 @@ namespace honk_prover_tests { template class ProverTests : public testing::Test { public: - /** - * @brief Simple test of Prover instantiation. This is handy while were in the Honk PoC building phase but may - * eventually be unnecessary. - * - */ - static void test_prover_instantiation() - { - // Define some mock inputs for ProvingKey constructor - size_t num_gates = 8; - size_t num_public_inputs = 0; - auto reference_string = std::make_shared(num_gates + 1, "../srs_db/ignition"); - - // Instatiate a proving_key and make a pointer to it - auto proving_key = - std::make_shared(num_gates, num_public_inputs, reference_string, plonk::STANDARD); - - // Instantiate a Prover with the proving_key pointer - auto honk_prover = StandardProver(proving_key); - }; - /** * @brief Test the correctness of the computation of the permutation grand product polynomial z_permutation * @details This test compares a simple, unoptimized, easily readable calculation of the grand product z_permutation @@ -49,8 +31,8 @@ template class ProverTests : public testing::Test { auto reference_string = std::make_shared(num_gates + 1, "../srs_db/ignition"); // Instatiate a proving_key and make a pointer to it. This will be used to instantiate a Prover. - auto proving_key = - std::make_shared(num_gates, num_public_inputs, reference_string, plonk::STANDARD); + auto proving_key = std::make_shared( + num_gates, num_public_inputs, reference_string, plonk::ComposerType::STANDARD_HONK); static const size_t program_width = StandardProver::settings_::program_width; @@ -77,8 +59,21 @@ template class ProverTests : public testing::Test { proving_key->polynomial_cache.put(sigma_id, std::move(sigma_poly)); } - // Instantiate a Prover with pointer to the proving_key just constructed - auto honk_prover = StandardProver(proving_key); + // Add some empty polynomials to make Prover constructor happy; not used in the z_perm calculation + proving_key->polynomial_cache.put("id_1_lagrange", polynomial(proving_key->circuit_size)); + proving_key->polynomial_cache.put("id_2_lagrange", polynomial(proving_key->circuit_size)); + proving_key->polynomial_cache.put("id_3_lagrange", polynomial(proving_key->circuit_size)); + proving_key->polynomial_cache.put("q_1_lagrange", polynomial(proving_key->circuit_size)); + proving_key->polynomial_cache.put("q_2_lagrange", polynomial(proving_key->circuit_size)); + proving_key->polynomial_cache.put("q_3_lagrange", polynomial(proving_key->circuit_size)); + proving_key->polynomial_cache.put("q_m_lagrange", polynomial(proving_key->circuit_size)); + proving_key->polynomial_cache.put("q_c_lagrange", polynomial(proving_key->circuit_size)); + proving_key->polynomial_cache.put("L_first_lagrange", polynomial(proving_key->circuit_size)); + proving_key->polynomial_cache.put("L_last_lagrange", polynomial(proving_key->circuit_size)); + + // Instantiate a Prover with wire polynomials and pointer to the proving_key just constructed + auto wires_copy = wires; + auto honk_prover = StandardProver(std::move(wires_copy), proving_key); // Get random challenges // (TODO(luke): set these up to come from a transcript. Must match actual implementation @@ -86,7 +81,7 @@ template class ProverTests : public testing::Test { Fscalar gamma = Fscalar::one(); // Method 1: Compute z_perm using 'compute_grand_product_polynomial' as the prover would in practice - honk_prover.compute_grand_product_polynomial(beta, gamma); + polynomial prover_z_perm = honk_prover.compute_grand_product_polynomial(beta, gamma); // Method 2: Compute z_perm locally using the simplest non-optimized syntax possible. The comment below, // which describes the computation in 4 steps, is adapted from a similar comment in @@ -151,18 +146,13 @@ template class ProverTests : public testing::Test { } // Check consistency between locally computed z_perm and the one computed by the prover - EXPECT_EQ(z_perm, honk_prover.key->polynomial_cache.get("z_perm_lagrange")); + EXPECT_EQ(z_perm, prover_z_perm); }; }; typedef testing::Types FieldTypes; TYPED_TEST_SUITE(ProverTests, FieldTypes); -TYPED_TEST(ProverTests, prover_instantiation) -{ - TestFixture::test_prover_instantiation(); -} - TYPED_TEST(ProverTests, grand_product_construction) { TestFixture::test_grand_product_construction(); diff --git a/cpp/src/aztec/honk/proof_system/verifier.cpp b/cpp/src/aztec/honk/proof_system/verifier.cpp index 677fd8f3ce..a0c0e7e031 100644 --- a/cpp/src/aztec/honk/proof_system/verifier.cpp +++ b/cpp/src/aztec/honk/proof_system/verifier.cpp @@ -10,6 +10,7 @@ #include "honk/pcs/gemini/gemini.hpp" #include "honk/pcs/kzg/kzg.hpp" #include "numeric/bitop/get_msb.hpp" +#include "proof_system/flavor/flavor.hpp" #include "proof_system/polynomial_cache/polynomial_cache.hpp" #include #include @@ -86,12 +87,15 @@ template bool Verifier::verify_pro using FF = typename program_settings::fr; using Commitment = barretenberg::g1::affine_element; using Transcript = typename program_settings::Transcript; - using Multivariates = Multivariates; using Gemini = pcs::gemini::MultilinearReductionScheme; using Shplonk = pcs::shplonk::SingleBatchOpeningScheme; using KZG = pcs::kzg::UnivariateOpeningScheme; using MLEOpeningClaim = pcs::MLEOpeningClaim; using GeminiProof = pcs::gemini::Proof; + using POLYNOMIAL = bonk::StandardArithmetization::POLYNOMIAL; + const size_t NUM_UNSHIFTED = bonk::StandardArithmetization::NUM_UNSHIFTED_POLYNOMIALS; + const size_t NUM_SHIFTED = bonk::StandardArithmetization::NUM_SHIFTED_POLYNOMIALS; + const size_t NUM_PRECOMPUTED = bonk::StandardArithmetization::NUM_PRECOMPUTED_POLYNOMIALS; key->program_width = program_settings::program_width; @@ -132,7 +136,7 @@ template bool Verifier::verify_pro // // TODO(Cody): Compute some basic public polys like id(X), pow(X), and any required Lagrange polys // Execute Sumcheck Verifier - auto sumcheck = Sumcheck bool Verifier::verify_pro // Get vector of multivariate evaluations produced by Sumcheck auto multivariate_evaluations = transcript.get_field_element_vector("multivariate_evaluations"); - std::unordered_map evals_map; - size_t eval_idx = 0; - for (auto& entry : key->polynomial_manifest.get()) { - std::string label(entry.polynomial_label); - evals_map[label] = multivariate_evaluations[eval_idx++]; - if (entry.requires_shifted_evaluation) { - evals_map[label + "_shift"] = multivariate_evaluations[eval_idx++]; - } - } - // Reconstruct Gemini opening claims and polynomials from the transcript/verification_key - for (auto& entry : key->polynomial_manifest.get()) { - std::string label(entry.polynomial_label); - std::string commitment_label(entry.commitment_label); - auto evaluation = evals_map[label]; - Commitment commitment = Commitment::one(); // initialize to make gcc happy - - switch (entry.source) { - case bonk::WITNESS: { - commitment = transcript.get_group_element(commitment_label); - break; - } - case bonk::SELECTOR: - case bonk::PERMUTATION: - case bonk::OTHER: { - commitment = key->commitments[commitment_label]; - break; - } - } - - opening_claims.emplace_back(commitment, evaluation); - if (entry.requires_shifted_evaluation) { - // Note: For a polynomial p for which we need the shift p_shift, we provide Gemini with the SHIFTED - // evaluation p_shift(u), but the UNSHIFTED commitment [p]. - auto shifted_evaluation = evals_map[label + "_shift"]; - opening_claims_shifted.emplace_back(commitment, shifted_evaluation); + // Construct NON-shifted opening claims + for (size_t i = 0; i < NUM_UNSHIFTED; ++i) { + if (i < NUM_PRECOMPUTED) { // if precomputed, commitment comes from verification key + Commitment commitment = key->commitments[bonk::StandardArithmetization::ENUM_TO_COMM[i]]; + opening_claims.emplace_back(commitment, multivariate_evaluations[i]); + } else { // if witness, commitment comes from prover (via transcript) + Commitment commitment = transcript.get_group_element(bonk::StandardArithmetization::ENUM_TO_COMM[i]); + opening_claims.emplace_back(commitment, multivariate_evaluations[i]); } } + // Constructed shifted opening claims + Commitment commitment = transcript.get_group_element("Z_PERM"); + Fr evaluation = multivariate_evaluations[POLYNOMIAL::Z_PERM_SHIFT]; + opening_claims_shifted.emplace_back(commitment, evaluation); + // Reconstruct the Gemini Proof from the transcript GeminiProof gemini_proof; diff --git a/cpp/src/aztec/honk/proof_system/verifier.hpp b/cpp/src/aztec/honk/proof_system/verifier.hpp index 89ce6fbccb..095a42c074 100644 --- a/cpp/src/aztec/honk/proof_system/verifier.hpp +++ b/cpp/src/aztec/honk/proof_system/verifier.hpp @@ -4,7 +4,6 @@ #include "../../proof_system/verification_key/verification_key.hpp" #include #include -#include "../sumcheck/polynomials/multivariates.hpp" #include "../sumcheck/sumcheck.hpp" #include "../sumcheck/relations/arithmetic_relation.hpp" #include "honk/pcs/commitment_key.hpp" diff --git a/cpp/src/aztec/honk/proof_system/verifier.test.cpp b/cpp/src/aztec/honk/proof_system/verifier.test.cpp index 9caffa5fad..0472e87cb7 100644 --- a/cpp/src/aztec/honk/proof_system/verifier.test.cpp +++ b/cpp/src/aztec/honk/proof_system/verifier.test.cpp @@ -1,5 +1,6 @@ #include "numeric/bitop/get_msb.hpp" #include "plonk/proof_system/constants.hpp" +#include "polynomials/polynomial.hpp" #include "proof_system/flavor/flavor.hpp" #include "prover.hpp" #include "proof_system/proving_key/proving_key.hpp" @@ -11,6 +12,7 @@ #include #include #include +#include using namespace barretenberg; using namespace honk; @@ -193,8 +195,9 @@ template class VerifierTests : public testing::Test { proving_key->polynomial_cache.put("q_c_lagrange", std::move(q_c)); // TODO(Cody): This should be more generic - StandardUnrolledProver prover = - StandardUnrolledProver(proving_key, create_manifest(0, proving_key->log_circuit_size)); + std::vector witness_polynomials; + StandardUnrolledProver prover = StandardUnrolledProver( + std::move(witness_polynomials), proving_key, create_manifest(0, proving_key->log_circuit_size)); std::unique_ptr kate_commitment_key = std::make_unique(proving_key->circuit_size, "../srs_db/ignition"); diff --git a/cpp/src/aztec/honk/sumcheck/polynomials/multivariates.hpp b/cpp/src/aztec/honk/sumcheck/polynomials/multivariates.hpp deleted file mode 100644 index 68d710c7c3..0000000000 --- a/cpp/src/aztec/honk/sumcheck/polynomials/multivariates.hpp +++ /dev/null @@ -1,145 +0,0 @@ -#pragma once // just adding these willy-nilly -#include "numeric/bitop/get_msb.hpp" -#include "polynomials/polynomial.hpp" -#include "proof_system/proving_key/proving_key.hpp" -#include "transcript/transcript_wrappers.hpp" -#include -#include -#include -#include -#include -#include - -namespace honk::sumcheck { - -// std::span has no comparison operator, so this is a quick-and-dirty workaround for testing -// IMPROVEMENT(Cody): Move and/or implement as == in some class -bool span_arrays_equal(auto& lhs, auto& rhs) -{ - bool result(true); - result = lhs.size() == rhs.size(); - if (result) { - for (size_t i = 0; i < lhs.size(); i++) { - result &= std::equal(lhs[i].begin(), lhs[i].end(), rhs[i].begin(), rhs[i].end()); - }; - } - return result; -} - -/** - * - * @brief A container for all of the Honk polynomials (wire and selector polynomials, grand product, and much more). - * These polynomials all low-degree extensions over H^d with H = {0, 1} (where d = ceil(log(number of gates))), hence - * they are multilinear polynomials in d variables. As such, it is efficient to store these polynomials in terms of - * univariate degree-1 polynomials. - - * Suppose now the Honk polynomials (multilinear in d variables) are called P_1, ..., P_N. At initialization, - * we think of these as lying in a two-dimensional array, where each column records the value of one P_i on H^d. After - * the first round, the array will be updated ('folded'), so that the first n/2 rows will represent the evaluations - * P_i(X1, ..., X_{d-1}, u_d) as a low-degree extension on H^{d-1}. In reality, we elude copying all of the polynomial- - * defining data by only populating folded_multivariates after the first round. I.e.: - - We imagine all of the defining polynomial data in a matrix like this: - | P_1 | P_2 | P_3 | P_4 | ... | P_N | N = number of multivariatesk - |-----------------------------------| - group 0 --| * | * | * | * | ... | * | vertex 0 - \-| * | * | * | * | ... | * | vertex 1 - group 1 --| * | * | * | * | ... | * | vertex 2 - \-| * | * | * | * | ... | * | vertex 3 - | * | * | * | * | ... | * | - group m-1 --| * | * | * | * | ... | * | vertex n-2 - \-| * | * | * | * | ... | * | vertex n-1 - m = n/2 - * - Each group consists of N edges |, and our construction of univariates and folding - * - operations naturally operate on these groups of edges - - * - * NOTE: With ~40 columns, prob only want to allocate 256 EdgeGroup's at once to keep stack under 1MB? - * TODO(Cody): might want to just do C-style multidimensional array? for guaranteed adjacency? - */ -template class Multivariates { - public: - using FF = FF_; - const size_t multivariate_n; - const size_t multivariate_d; - static constexpr size_t num = num_polys; - - std::array, num_polys> full_polynomials; - // TODO(Cody): adjacency issues with std::array of std::vectors? - // IMPROVEMENT(Cody): for each round after the first, we could release half of the memory reserved by - // folded_polynomials. - std::array, num_polys> folded_polynomials; - - Multivariates() = default; - - explicit Multivariates(std::array, num_polys> full_polynomials) - : multivariate_n(full_polynomials[0].size()) - , multivariate_d(numeric::get_msb(multivariate_n)) - , full_polynomials(full_polynomials) - { - for (auto& polynomial : folded_polynomials) { - polynomial.resize(multivariate_n >> 1); - } - }; - - explicit Multivariates(const std::shared_ptr& proving_key) - : multivariate_n(proving_key->circuit_size) - , multivariate_d(proving_key->log_circuit_size) - { - // Iterate through polynomial manifest to populate full_polynomials from polynomial cache - size_t poly_idx = 0; - for (auto& entry : proving_key->polynomial_manifest.get()) { - std::string label(entry.polynomial_label); - full_polynomials[poly_idx++] = proving_key->polynomial_cache.get(label); - if (entry.requires_shifted_evaluation) { - full_polynomials[poly_idx++] = proving_key->polynomial_cache.get(label).shifted(); - } - } - - for (auto& polynomial : folded_polynomials) { - polynomial.reserve(multivariate_n >> 1); - polynomial.resize(multivariate_n >> 1); - } - } - - explicit Multivariates(transcript::StandardTranscript transcript) - : multivariate_n([](std::vector buffer) { - return static_cast(buffer[3]) + (static_cast(buffer[2]) << 8) + - (static_cast(buffer[1]) << 16) + (static_cast(buffer[0]) << 24); - }(transcript.get_element("circuit_size"))) - , multivariate_d(numeric::get_msb(multivariate_n)) - {} - - // TODO(Cody): Rename. fold is not descriptive, and it's already in use in the Gemini context. - // Probably just call it partial_evaluation? - /** - * @brief Evaluate at the round challenge and prepare class for next round. - * Illustration of layout in example of first round when d==3 (showing just one Honk polynomial, - * i.e., what happens in just one column of our two-dimensional array): - * - * groups vertex terms collected vertex terms groups after folding - * g0 -- v0 (1-X1)(1-X2)(1-X3) --- (v0(1-X3) + v1 X3) (1-X1)(1-X2) ---- (v0(1-u3) + v1 u3) (1-X1)(1-X2) - * \- v1 (1-X1)(1-X2) X3 --/ --- (v2(1-u3) + v3 u3) (1-X1) X2 - * g1 -- v2 (1-X1) X2 (1-X3) --- (v2(1-X3) + v3 X3) (1-X1) X2 -/ -- (v4(1-u3) + v5 u3) X1 (1-X2) - * \- v3 (1-X1) X2 X3 --/ / - (v6(1-u3) + v7 u3) X1 X2 - * g2 -- v4 X1 (1-X2)(1-X3) --- (v4(1-X3) + v5 X3) X1 (1-X2)-/ / - * \- v5 X1 (1-X2) X3 --/ / - * g3 -- v6 X1 X2 (1-X3) --- (v6(1-X3) + v7 X3) X1 X2 -/ - * \- v7 X1 X2 X3 --/ - * - * @param challenge - */ - void fold(auto& polynomials, size_t round_size, FF round_challenge) - { - // after the first round, operate in place on folded_polynomials - for (size_t j = 0; j < num_polys; ++j) { - for (size_t i = 0; i < round_size; i += 2) { - folded_polynomials[j][i >> 1] = - polynomials[j][i] + round_challenge * (polynomials[j][i + 1] - polynomials[j][i]); - } - } - }; -}; -} // namespace honk::sumcheck \ No newline at end of file diff --git a/cpp/src/aztec/honk/sumcheck/polynomials/multivariates.test.cpp b/cpp/src/aztec/honk/sumcheck/polynomials/multivariates.test.cpp index 00e4f2cf62..6b6a12330d 100644 --- a/cpp/src/aztec/honk/sumcheck/polynomials/multivariates.test.cpp +++ b/cpp/src/aztec/honk/sumcheck/polynomials/multivariates.test.cpp @@ -1,5 +1,6 @@ -#include "multivariates.hpp" #include +#include "honk/sumcheck/relations/arithmetic_relation.hpp" +#include "honk/sumcheck/sumcheck.hpp" #include #include @@ -12,27 +13,11 @@ namespace test_sumcheck_polynomials { template class MultivariatesTests : public testing::Test {}; using FieldTypes = testing::Types; +using Transcript = transcript::StandardTranscript; TYPED_TEST_SUITE(MultivariatesTests, FieldTypes); #define MULTIVARIATES_TESTS_TYPE_ALIASES using FF = TypeParam; -TYPED_TEST(MultivariatesTests, Constructor) -{ - MULTIVARIATES_TESTS_TYPE_ALIASES - - const size_t num_polys(4); - - std::array f0 = { 0, 0, 1 }; - std::array f1 = { 1, 1, 1 }; - std::array f2 = { 3, 4, 1 }; - std::array f3 = { -1, -1, 1 }; - - auto full_polynomials = std::array, num_polys>({ f0, f1, f2, f3 }); - auto multivariates = Multivariates(full_polynomials); - - ASSERT_TRUE(span_arrays_equal(full_polynomials, multivariates.full_polynomials)); -} - /* * We represent a bivariate f0 as f0(X1, X2). The indexing starts from 1 to match with the round number in sumcheck. * The idea is variable X2 (lsb) will be folded at round 2 (the first sumcheck round), @@ -70,23 +55,24 @@ TYPED_TEST(MultivariatesTests, FoldTwoRoundsSpecial) std::array f0 = { v00, v01, v10, v11 }; auto full_polynomials = std::array, 1>({ f0 }); - auto multivariates = Multivariates(full_polynomials); + auto transcript = Transcript(transcript::Manifest()); + auto sumcheck = Sumcheck(multivariate_n, transcript); FF round_challenge_2 = { 0x6c7301b49d85a46c, 0x44311531e39c64f6, 0xb13d66d8d6c1a24c, 0x04410c360230a295 }; round_challenge_2.self_to_montgomery_form(); FF expected_lo = v00 * (FF(1) - round_challenge_2) + v01 * round_challenge_2; FF expected_hi = v11 * round_challenge_2 + v10 * (FF(1) - round_challenge_2); - multivariates.fold(multivariates.full_polynomials, multivariate_n, round_challenge_2); + sumcheck.fold(full_polynomials, multivariate_n, round_challenge_2); - EXPECT_EQ(multivariates.folded_polynomials[0][0], round_challenge_2); - EXPECT_EQ(multivariates.folded_polynomials[0][1], FF(0)); + EXPECT_EQ(sumcheck.folded_polynomials[0][0], round_challenge_2); + EXPECT_EQ(sumcheck.folded_polynomials[0][1], FF(0)); FF round_challenge_1 = 2; FF expected_val = expected_lo * (FF(1) - round_challenge_1) + expected_hi * round_challenge_1; - multivariates.fold(multivariates.folded_polynomials, multivariate_n >> 1, round_challenge_1); - EXPECT_EQ(multivariates.folded_polynomials[0][0], expected_val); + sumcheck.fold(sumcheck.folded_polynomials, multivariate_n >> 1, round_challenge_1); + EXPECT_EQ(sumcheck.folded_polynomials[0][0], expected_val); } TYPED_TEST(MultivariatesTests, FoldTwoRoundsGeneric) @@ -105,21 +91,22 @@ TYPED_TEST(MultivariatesTests, FoldTwoRoundsGeneric) std::array f0 = { v00, v01, v10, v11 }; auto full_polynomials = std::array, 1>({ f0 }); - auto multivariates = Multivariates(full_polynomials); + auto transcript = Transcript(transcript::Manifest()); + auto sumcheck = Sumcheck(multivariate_n, transcript); FF round_challenge_2 = FF::random_element(); FF expected_lo = v00 * (FF(1) - round_challenge_2) + v01 * round_challenge_2; FF expected_hi = v11 * round_challenge_2 + v10 * (FF(1) - round_challenge_2); - multivariates.fold(multivariates.full_polynomials, multivariate_n, round_challenge_2); + sumcheck.fold(full_polynomials, multivariate_n, round_challenge_2); - EXPECT_EQ(multivariates.folded_polynomials[0][0], expected_lo); - EXPECT_EQ(multivariates.folded_polynomials[0][1], expected_hi); + EXPECT_EQ(sumcheck.folded_polynomials[0][0], expected_lo); + EXPECT_EQ(sumcheck.folded_polynomials[0][1], expected_hi); FF round_challenge_1 = FF::random_element(); FF expected_val = expected_lo * (FF(1) - round_challenge_1) + expected_hi * round_challenge_1; - multivariates.fold(multivariates.folded_polynomials, multivariate_n >> 1, round_challenge_1); - EXPECT_EQ(multivariates.folded_polynomials[0][0], expected_val); + sumcheck.fold(sumcheck.folded_polynomials, multivariate_n >> 1, round_challenge_1); + EXPECT_EQ(sumcheck.folded_polynomials[0][0], expected_val); } /* @@ -157,7 +144,8 @@ TYPED_TEST(MultivariatesTests, FoldThreeRoundsSpecial) std::array f0 = { v000, v001, v010, v011, v100, v101, v110, v111 }; auto full_polynomials = std::array, 1>({ f0 }); - auto multivariates = Multivariates(full_polynomials); + auto transcript = Transcript(transcript::Manifest()); + auto sumcheck = Sumcheck(multivariate_n, transcript); FF round_challenge_3 = 1; FF expected_q1 = v000 * (FF(1) - round_challenge_3) + v001 * round_challenge_3; // 2 @@ -165,25 +153,25 @@ TYPED_TEST(MultivariatesTests, FoldThreeRoundsSpecial) FF expected_q3 = v100 * (FF(1) - round_challenge_3) + v101 * round_challenge_3; // 6 FF expected_q4 = v110 * (FF(1) - round_challenge_3) + v111 * round_challenge_3; // 8 - multivariates.fold(multivariates.full_polynomials, multivariate_n, round_challenge_3); + sumcheck.fold(full_polynomials, multivariate_n, round_challenge_3); - EXPECT_EQ(multivariates.folded_polynomials[0][0], expected_q1); - EXPECT_EQ(multivariates.folded_polynomials[0][1], expected_q2); - EXPECT_EQ(multivariates.folded_polynomials[0][2], expected_q3); - EXPECT_EQ(multivariates.folded_polynomials[0][3], expected_q4); + EXPECT_EQ(sumcheck.folded_polynomials[0][0], expected_q1); + EXPECT_EQ(sumcheck.folded_polynomials[0][1], expected_q2); + EXPECT_EQ(sumcheck.folded_polynomials[0][2], expected_q3); + EXPECT_EQ(sumcheck.folded_polynomials[0][3], expected_q4); FF round_challenge_2 = 2; FF expected_lo = expected_q1 * (FF(1) - round_challenge_2) + expected_q2 * round_challenge_2; // 6 FF expected_hi = expected_q3 * (FF(1) - round_challenge_2) + expected_q4 * round_challenge_2; // 10 - multivariates.fold(multivariates.folded_polynomials, multivariate_n >> 1, round_challenge_2); - EXPECT_EQ(multivariates.folded_polynomials[0][0], expected_lo); - EXPECT_EQ(multivariates.folded_polynomials[0][1], expected_hi); + sumcheck.fold(sumcheck.folded_polynomials, multivariate_n >> 1, round_challenge_2); + EXPECT_EQ(sumcheck.folded_polynomials[0][0], expected_lo); + EXPECT_EQ(sumcheck.folded_polynomials[0][1], expected_hi); FF round_challenge_1 = 3; FF expected_val = expected_lo * (FF(1) - round_challenge_1) + expected_hi * round_challenge_1; // 18 - multivariates.fold(multivariates.folded_polynomials, multivariate_n >> 2, round_challenge_1); - EXPECT_EQ(multivariates.folded_polynomials[0][0], expected_val); + sumcheck.fold(sumcheck.folded_polynomials, multivariate_n >> 2, round_challenge_1); + EXPECT_EQ(sumcheck.folded_polynomials[0][0], expected_val); } TYPED_TEST(MultivariatesTests, FoldThreeRoundsGeneric) @@ -206,7 +194,8 @@ TYPED_TEST(MultivariatesTests, FoldThreeRoundsGeneric) std::array f0 = { v000, v001, v010, v011, v100, v101, v110, v111 }; auto full_polynomials = std::array, 1>({ f0 }); - auto multivariates = Multivariates(full_polynomials); + auto transcript = Transcript(transcript::Manifest()); + auto sumcheck = Sumcheck(multivariate_n, transcript); FF round_challenge_3 = FF::random_element(); FF expected_q1 = v000 * (FF(1) - round_challenge_3) + v001 * round_challenge_3; @@ -214,25 +203,25 @@ TYPED_TEST(MultivariatesTests, FoldThreeRoundsGeneric) FF expected_q3 = v100 * (FF(1) - round_challenge_3) + v101 * round_challenge_3; FF expected_q4 = v110 * (FF(1) - round_challenge_3) + v111 * round_challenge_3; - multivariates.fold(multivariates.full_polynomials, multivariate_n, round_challenge_3); + sumcheck.fold(full_polynomials, multivariate_n, round_challenge_3); - EXPECT_EQ(multivariates.folded_polynomials[0][0], expected_q1); - EXPECT_EQ(multivariates.folded_polynomials[0][1], expected_q2); - EXPECT_EQ(multivariates.folded_polynomials[0][2], expected_q3); - EXPECT_EQ(multivariates.folded_polynomials[0][3], expected_q4); + EXPECT_EQ(sumcheck.folded_polynomials[0][0], expected_q1); + EXPECT_EQ(sumcheck.folded_polynomials[0][1], expected_q2); + EXPECT_EQ(sumcheck.folded_polynomials[0][2], expected_q3); + EXPECT_EQ(sumcheck.folded_polynomials[0][3], expected_q4); FF round_challenge_2 = FF::random_element(); FF expected_lo = expected_q1 * (FF(1) - round_challenge_2) + expected_q2 * round_challenge_2; FF expected_hi = expected_q3 * (FF(1) - round_challenge_2) + expected_q4 * round_challenge_2; - multivariates.fold(multivariates.folded_polynomials, multivariate_n >> 1, round_challenge_2); - EXPECT_EQ(multivariates.folded_polynomials[0][0], expected_lo); - EXPECT_EQ(multivariates.folded_polynomials[0][1], expected_hi); + sumcheck.fold(sumcheck.folded_polynomials, multivariate_n >> 1, round_challenge_2); + EXPECT_EQ(sumcheck.folded_polynomials[0][0], expected_lo); + EXPECT_EQ(sumcheck.folded_polynomials[0][1], expected_hi); FF round_challenge_1 = FF::random_element(); FF expected_val = expected_lo * (FF(1) - round_challenge_1) + expected_hi * round_challenge_1; - multivariates.fold(multivariates.folded_polynomials, multivariate_n >> 2, round_challenge_1); - EXPECT_EQ(multivariates.folded_polynomials[0][0], expected_val); + sumcheck.fold(sumcheck.folded_polynomials, multivariate_n >> 2, round_challenge_1); + EXPECT_EQ(sumcheck.folded_polynomials[0][0], expected_val); } TYPED_TEST(MultivariatesTests, FoldThreeRoundsGenericMultiplePolys) @@ -265,7 +254,8 @@ TYPED_TEST(MultivariatesTests, FoldThreeRoundsGenericMultiplePolys) std::array f2 = { v000[2], v001[2], v010[2], v011[2], v100[2], v101[2], v110[2], v111[2] }; auto full_polynomials = std::array, 3>{ f0, f1, f2 }; - auto multivariates = Multivariates(full_polynomials); + auto transcript = Transcript(transcript::Manifest()); + auto sumcheck = Sumcheck(multivariate_n, transcript); std::array expected_q1; std::array expected_q2; @@ -279,12 +269,12 @@ TYPED_TEST(MultivariatesTests, FoldThreeRoundsGenericMultiplePolys) expected_q4[i] = v110[i] * (FF(1) - round_challenge_3) + v111[i] * round_challenge_3; } - multivariates.fold(multivariates.full_polynomials, multivariate_n, round_challenge_3); + sumcheck.fold(full_polynomials, multivariate_n, round_challenge_3); for (size_t i = 0; i < 3; i++) { - EXPECT_EQ(multivariates.folded_polynomials[i][0], expected_q1[i]); - EXPECT_EQ(multivariates.folded_polynomials[i][1], expected_q2[i]); - EXPECT_EQ(multivariates.folded_polynomials[i][2], expected_q3[i]); - EXPECT_EQ(multivariates.folded_polynomials[i][3], expected_q4[i]); + EXPECT_EQ(sumcheck.folded_polynomials[i][0], expected_q1[i]); + EXPECT_EQ(sumcheck.folded_polynomials[i][1], expected_q2[i]); + EXPECT_EQ(sumcheck.folded_polynomials[i][2], expected_q3[i]); + EXPECT_EQ(sumcheck.folded_polynomials[i][3], expected_q4[i]); } FF round_challenge_2 = FF::random_element(); @@ -294,19 +284,19 @@ TYPED_TEST(MultivariatesTests, FoldThreeRoundsGenericMultiplePolys) expected_lo[i] = expected_q1[i] * (FF(1) - round_challenge_2) + expected_q2[i] * round_challenge_2; expected_hi[i] = expected_q3[i] * (FF(1) - round_challenge_2) + expected_q4[i] * round_challenge_2; } - multivariates.fold(multivariates.folded_polynomials, multivariate_n >> 1, round_challenge_2); + sumcheck.fold(sumcheck.folded_polynomials, multivariate_n >> 1, round_challenge_2); for (size_t i = 0; i < 3; i++) { - EXPECT_EQ(multivariates.folded_polynomials[i][0], expected_lo[i]); - EXPECT_EQ(multivariates.folded_polynomials[i][1], expected_hi[i]); + EXPECT_EQ(sumcheck.folded_polynomials[i][0], expected_lo[i]); + EXPECT_EQ(sumcheck.folded_polynomials[i][1], expected_hi[i]); } FF round_challenge_1 = FF::random_element(); std::array expected_val; for (size_t i = 0; i < 3; i++) { expected_val[i] = expected_lo[i] * (FF(1) - round_challenge_1) + expected_hi[i] * round_challenge_1; } - multivariates.fold(multivariates.folded_polynomials, multivariate_n >> 2, round_challenge_1); + sumcheck.fold(sumcheck.folded_polynomials, multivariate_n >> 2, round_challenge_1); for (size_t i = 0; i < 3; i++) { - EXPECT_EQ(multivariates.folded_polynomials[i][0], expected_val[i]); + EXPECT_EQ(sumcheck.folded_polynomials[i][0], expected_val[i]); } } diff --git a/cpp/src/aztec/honk/sumcheck/relations/relation.test.cpp b/cpp/src/aztec/honk/sumcheck/relations/relation.test.cpp index 1166118aac..cb7035fb44 100644 --- a/cpp/src/aztec/honk/sumcheck/relations/relation.test.cpp +++ b/cpp/src/aztec/honk/sumcheck/relations/relation.test.cpp @@ -3,7 +3,6 @@ #include "arithmetic_relation.hpp" #include "grand_product_initialization_relation.hpp" #include "grand_product_computation_relation.hpp" -#include "../polynomials/multivariates.hpp" #include "../polynomials/univariate.hpp" #include "../polynomials/barycentric_data.hpp" @@ -20,9 +19,11 @@ template class SumcheckRelation : public testing::Test { public: template using Univariate = Univariate; template using UnivariateView = UnivariateView; + static const size_t NUM_POLYNOMIALS = bonk::StandardArithmetization::NUM_POLYNOMIALS; + using POLYNOMIAL = bonk::StandardArithmetization::POLYNOMIAL; // TODO(luke): may want to make this more flexible/genericzs - static std::array, bonk::StandardArithmetization::NUM_POLYNOMIALS> compute_mock_extended_edges() + static std::array, NUM_POLYNOMIALS> compute_mock_extended_edges() { // TODO(Cody): build from Univariate<2>'s? // evaluation form, i.e. w_l(0) = 1, w_l(1) = 2,.. The poly is x+1. @@ -48,10 +49,27 @@ template class SumcheckRelation : public testing::Test { auto lagrange_first = Univariate<5>({ 1, 2, 3, 4, 5 }); auto lagrange_last = Univariate<5>({ 1, 2, 3, 4, 5 }); - std::array, bonk::StandardArithmetization::NUM_POLYNOMIALS> extended_edges = { - w_l, w_r, w_o, z_perm, z_perm_shift, q_m, q_l, q_r, q_o, q_c, sigma_1, sigma_2, - sigma_3, id_1, id_2, id_3, lagrange_first, lagrange_last - }; + // Construct extended edges array in order determined by enum + std::array, bonk::StandardArithmetization::NUM_POLYNOMIALS> extended_edges; + extended_edges[POLYNOMIAL::W_L] = w_l; + extended_edges[POLYNOMIAL::W_R] = w_r; + extended_edges[POLYNOMIAL::W_O] = w_o; + extended_edges[POLYNOMIAL::Z_PERM] = z_perm; + extended_edges[POLYNOMIAL::Z_PERM_SHIFT] = z_perm_shift; + extended_edges[POLYNOMIAL::Q_M] = q_m; + extended_edges[POLYNOMIAL::Q_L] = q_l; + extended_edges[POLYNOMIAL::Q_R] = q_r; + extended_edges[POLYNOMIAL::Q_O] = q_o; + extended_edges[POLYNOMIAL::Q_C] = q_c; + extended_edges[POLYNOMIAL::SIGMA_1] = sigma_1; + extended_edges[POLYNOMIAL::SIGMA_2] = sigma_2; + extended_edges[POLYNOMIAL::SIGMA_3] = sigma_3; + extended_edges[POLYNOMIAL::ID_1] = id_1; + extended_edges[POLYNOMIAL::ID_2] = id_2; + extended_edges[POLYNOMIAL::ID_3] = id_3; + extended_edges[POLYNOMIAL::LAGRANGE_FIRST] = lagrange_first; + extended_edges[POLYNOMIAL::LAGRANGE_LAST] = lagrange_last; + return extended_edges; } }; diff --git a/cpp/src/aztec/honk/sumcheck/sumcheck.hpp b/cpp/src/aztec/honk/sumcheck/sumcheck.hpp index a8f1034b04..4db3bbf8d0 100644 --- a/cpp/src/aztec/honk/sumcheck/sumcheck.hpp +++ b/cpp/src/aztec/honk/sumcheck/sumcheck.hpp @@ -1,6 +1,6 @@ #pragma once #include "common/serialize.hpp" -#include "proof_system/types/polynomial_manifest.hpp" +#include #include #include "common/throw_or_abort.hpp" #include "sumcheck_round.hpp" @@ -8,33 +8,80 @@ #include #include #include +#include #include #include - +#include namespace honk::sumcheck { -template class... Relations> class Sumcheck { - using FF = typename Multivariates::FF; +template class... Relations> class Sumcheck { public: - Multivariates multivariates; // TODO(luke): this value is needed here but also lives in sumcheck_round static constexpr size_t MAX_RELATION_LENGTH = std::max({ Relations::RELATION_LENGTH... }); - std::array purported_evaluations; + std::array purported_evaluations; Transcript& transcript; - SumcheckRound round; + const size_t multivariate_n; + const size_t multivariate_d; + SumcheckRound round; - // prover instantiates sumcheck with multivariates - Sumcheck(Multivariates& multivariates, Transcript& transcript) - : multivariates(multivariates) - , transcript(transcript) - , round(multivariates.multivariate_n, std::tuple(Relations()...)){}; + /** + * + * @brief (folded_polynomials) Suppose the Honk polynomials (multilinear in d variables) are called P_1, ..., P_N. + * At initialization, + * we think of these as lying in a two-dimensional array, where each column records the value of one P_i on H^d. + * After the first round, the array will be updated ('folded'), so that the first n/2 rows will represent the + * evaluations P_i(X1, ..., X_{d-1}, u_d) as a low-degree extension on H^{d-1}. In reality, we elude copying all + * of the polynomial-defining data by only populating folded_multivariates after the first round. I.e.: + + We imagine all of the defining polynomial data in a matrix like this: + | P_1 | P_2 | P_3 | P_4 | ... | P_N | N = number of multivariatesk + |-----------------------------------| + group 0 --| * | * | * | * | ... | * | vertex 0 + \-| * | * | * | * | ... | * | vertex 1 + group 1 --| * | * | * | * | ... | * | vertex 2 + \-| * | * | * | * | ... | * | vertex 3 + | * | * | * | * | ... | * | + group m-1 --| * | * | * | * | ... | * | vertex n-2 + \-| * | * | * | * | ... | * | vertex n-1 + m = n/2 + * + Each group consists of N edges |, and our construction of univariates and folding + * + operations naturally operate on these groups of edges + + * + * NOTE: With ~40 columns, prob only want to allocate 256 EdgeGroup's at once to keep stack under 1MB? + * TODO(Cody): might want to just do C-style multidimensional array? for guaranteed adjacency? + */ + std::array, bonk::StandardArithmetization::NUM_POLYNOMIALS> folded_polynomials; + + // prover instantiates sumcheck with circuit size and transcript + Sumcheck(size_t multivariate_n, Transcript& transcript) + : transcript(transcript) + , multivariate_n(multivariate_n) + , multivariate_d(numeric::get_msb(multivariate_n)) + , round(multivariate_n, std::tuple(Relations()...)) + { + for (auto& polynomial : folded_polynomials) { + polynomial.resize(multivariate_n >> 1); + } + }; - // verifier instantiates with challenges alone + // verifier instantiates with transcript alone explicit Sumcheck(Transcript& transcript) - : multivariates(transcript) - , transcript(transcript) - , round(std::tuple(Relations()...)){}; + : transcript(transcript) + , multivariate_n([](std::vector buffer) { + return static_cast(buffer[3]) + (static_cast(buffer[2]) << 8) + + (static_cast(buffer[1]) << 16) + (static_cast(buffer[0]) << 24); + }(transcript.get_element("circuit_size"))) + , multivariate_d(numeric::get_msb(multivariate_n)) + , round(std::tuple(Relations()...)) + { + for (auto& polynomial : folded_polynomials) { + polynomial.resize(multivariate_n >> 1); + } + }; /** * @brief Get all the challenges and computed parameters used in sumcheck in a convenient format @@ -65,70 +112,52 @@ template class... Relat }; return relation_parameters; } + /** * @brief Compute univariate restriction place in transcript, generate challenge, fold,... repeat until final round, * then compute multivariate evaluations and place in transcript. * * @details */ - void execute_prover() + void execute_prover(auto full_polynomials) // pass by value, not by reference { // First round - // This populates multivariates.folded_polynomials. + // This populates folded_polynomials. const auto relation_parameters = retrieve_proof_parameters(); PowUnivariate pow_univariate(relation_parameters.zeta); // round.pow_univariate = PowUnivariate(relation_parameters.zeta); - auto round_univariate = - round.compute_univariate(multivariates.full_polynomials, relation_parameters, pow_univariate); - transcript.add_element("univariate_" + std::to_string(multivariates.multivariate_d), - round_univariate.to_buffer()); - std::string challenge_label = "u_" + std::to_string(multivariates.multivariate_d); + auto round_univariate = round.compute_univariate(full_polynomials, relation_parameters, pow_univariate); + transcript.add_element("univariate_" + std::to_string(multivariate_d), round_univariate.to_buffer()); + std::string challenge_label = "u_" + std::to_string(multivariate_d); transcript.apply_fiat_shamir(challenge_label); FF round_challenge = FF::serialize_from_buffer(transcript.get_challenge(challenge_label).begin()); - multivariates.fold(multivariates.full_polynomials, multivariates.multivariate_n, round_challenge); + fold(full_polynomials, multivariate_n, round_challenge); pow_univariate.partially_evaluate(round_challenge); round.round_size = round.round_size >> 1; // TODO(Cody): Maybe fold should do this and release memory? // All but final round - // We operate on multivariates.folded_polynomials in place. - for (size_t round_idx = 1; round_idx < multivariates.multivariate_d; round_idx++) { + // We operate on folded_polynomials in place. + for (size_t round_idx = 1; round_idx < multivariate_d; round_idx++) { // Write the round univariate to the transcript - round_univariate = - round.compute_univariate(multivariates.folded_polynomials, relation_parameters, pow_univariate); - transcript.add_element("univariate_" + std::to_string(multivariates.multivariate_d - round_idx), + round_univariate = round.compute_univariate(folded_polynomials, relation_parameters, pow_univariate); + transcript.add_element("univariate_" + std::to_string(multivariate_d - round_idx), round_univariate.to_buffer()); - challenge_label = "u_" + std::to_string(multivariates.multivariate_d - round_idx); + challenge_label = "u_" + std::to_string(multivariate_d - round_idx); transcript.apply_fiat_shamir(challenge_label); FF round_challenge = FF::serialize_from_buffer(transcript.get_challenge(challenge_label).begin()); - multivariates.fold(multivariates.folded_polynomials, round.round_size, round_challenge); + fold(folded_polynomials, round.round_size, round_challenge); pow_univariate.partially_evaluate(round_challenge); round.round_size = round.round_size >> 1; } - // Final round - transcript.add_element("multivariate_evaluations", - // TODO(Cody): will need to do this programatically. - to_buffer(std::array( - { multivariates.folded_polynomials[0][0], - multivariates.folded_polynomials[1][0], - multivariates.folded_polynomials[2][0], - multivariates.folded_polynomials[3][0], - multivariates.folded_polynomials[4][0], - multivariates.folded_polynomials[5][0], - multivariates.folded_polynomials[6][0], - multivariates.folded_polynomials[7][0], - multivariates.folded_polynomials[8][0], - multivariates.folded_polynomials[9][0], - multivariates.folded_polynomials[10][0], - multivariates.folded_polynomials[11][0], - multivariates.folded_polynomials[12][0], - multivariates.folded_polynomials[13][0], - multivariates.folded_polynomials[14][0], - multivariates.folded_polynomials[15][0], - multivariates.folded_polynomials[16][0], - multivariates.folded_polynomials[17][0] }))); + // Final round: Extract multivariate evaluations from folded_polynomials and add to transcript + std::array multivariate_evaluations; + for (size_t i = 0; i < bonk::StandardArithmetization::NUM_POLYNOMIALS; ++i) { + multivariate_evaluations[i] = folded_polynomials[i][0]; + } + transcript.add_element("multivariate_evaluations", to_buffer(multivariate_evaluations)); }; /** @@ -145,18 +174,18 @@ template class... Relat // All but final round. // target_total_sum is initialized to zero then mutated in place. - if (multivariates.multivariate_d == 0) { + if (multivariate_d == 0) { throw_or_abort("Number of variables in multivariate is 0."); } - for (size_t round_idx = 0; round_idx < multivariates.multivariate_d; round_idx++) { + for (size_t round_idx = 0; round_idx < multivariate_d; round_idx++) { // Obtain the round univariate from the transcript auto round_univariate = Univariate::serialize_from_buffer( - &transcript.get_element("univariate_" + std::to_string(multivariates.multivariate_d - round_idx))[0]); + &transcript.get_element("univariate_" + std::to_string(multivariate_d - round_idx))[0]); bool checked = round.check_sum(round_univariate, pow_univariate); verified = verified && checked; FF round_challenge = FF::serialize_from_buffer( - transcript.get_challenge("u_" + std::to_string(multivariates.multivariate_d - round_idx)).begin()); + transcript.get_challenge("u_" + std::to_string(multivariate_d - round_idx)).begin()); round.compute_next_target_sum(round_univariate, round_challenge, pow_univariate); pow_univariate.partially_evaluate(round_challenge); @@ -173,5 +202,36 @@ template class... Relat verified = verified && (full_honk_relation_purported_value == round.target_total_sum); return verified; }; + + // TODO(Cody): Rename. fold is not descriptive, and it's already in use in the Gemini context. + // Probably just call it partial_evaluation? + /** + * @brief Evaluate at the round challenge and prepare class for next round. + * Illustration of layout in example of first round when d==3 (showing just one Honk polynomial, + * i.e., what happens in just one column of our two-dimensional array): + * + * groups vertex terms collected vertex terms groups after folding + * g0 -- v0 (1-X1)(1-X2)(1-X3) --- (v0(1-X3) + v1 X3) (1-X1)(1-X2) ---- (v0(1-u3) + v1 u3) (1-X1)(1-X2) + * \- v1 (1-X1)(1-X2) X3 --/ --- (v2(1-u3) + v3 u3) (1-X1) X2 + * g1 -- v2 (1-X1) X2 (1-X3) --- (v2(1-X3) + v3 X3) (1-X1) X2 -/ -- (v4(1-u3) + v5 u3) X1 (1-X2) + * \- v3 (1-X1) X2 X3 --/ / - (v6(1-u3) + v7 u3) X1 X2 + * g2 -- v4 X1 (1-X2)(1-X3) --- (v4(1-X3) + v5 X3) X1 (1-X2)-/ / + * \- v5 X1 (1-X2) X3 --/ / + * g3 -- v6 X1 X2 (1-X3) --- (v6(1-X3) + v7 X3) X1 X2 -/ + * \- v7 X1 X2 X3 --/ + * + * @param challenge + */ + void fold(auto& polynomials, size_t round_size, FF round_challenge) + { + // after the first round, operate in place on folded_polynomials + for (size_t j = 0; j < polynomials.size(); ++j) { + // for (size_t j = 0; j < bonk::StandardArithmetization::NUM_POLYNOMIALS; ++j) { + for (size_t i = 0; i < round_size; i += 2) { + folded_polynomials[j][i >> 1] = + polynomials[j][i] + round_challenge * (polynomials[j][i + 1] - polynomials[j][i]); + } + } + }; }; } // namespace honk::sumcheck diff --git a/cpp/src/aztec/honk/sumcheck/sumcheck.test.cpp b/cpp/src/aztec/honk/sumcheck/sumcheck.test.cpp index b2955623d4..665d80a130 100644 --- a/cpp/src/aztec/honk/sumcheck/sumcheck.test.cpp +++ b/cpp/src/aztec/honk/sumcheck/sumcheck.test.cpp @@ -1,7 +1,6 @@ #include "sumcheck.hpp" #include "proof_system/flavor/flavor.hpp" #include "transcript/transcript_wrappers.hpp" -#include "polynomials/multivariates.hpp" #include "relations/arithmetic_relation.hpp" #include "relations/grand_product_computation_relation.hpp" #include "relations/grand_product_initialization_relation.hpp" @@ -28,6 +27,55 @@ namespace test_sumcheck_round { using Transcript = transcript::StandardTranscript; using FF = barretenberg::fr; +const size_t NUM_POLYNOMIALS = bonk::StandardArithmetization::NUM_POLYNOMIALS; +using POLYNOMIAL = bonk::StandardArithmetization::POLYNOMIAL; + +/** + * @brief Place polynomials into full_polynomials in the order determined by the StandardArithmetization enum. + * + */ +template +std::array, NUM_POLYNOMIALS> construct_full_polynomials(std::array& w_l, + std::array& w_r, + std::array& w_o, + std::array& z_perm, + std::array& z_perm_shift, + std::array& q_m, + std::array& q_l, + std::array& q_r, + std::array& q_o, + std::array& q_c, + std::array& sigma_1, + std::array& sigma_2, + std::array& sigma_3, + std::array& id_1, + std::array& id_2, + std::array& id_3, + std::array& lagrange_first, + std::array& lagrange_last) +{ + std::array, NUM_POLYNOMIALS> full_polynomials; + full_polynomials[POLYNOMIAL::W_L] = w_l; + full_polynomials[POLYNOMIAL::W_R] = w_r; + full_polynomials[POLYNOMIAL::W_O] = w_o; + full_polynomials[POLYNOMIAL::Z_PERM] = z_perm; + full_polynomials[POLYNOMIAL::Z_PERM_SHIFT] = z_perm_shift; + full_polynomials[POLYNOMIAL::Q_M] = q_m; + full_polynomials[POLYNOMIAL::Q_L] = q_l; + full_polynomials[POLYNOMIAL::Q_R] = q_r; + full_polynomials[POLYNOMIAL::Q_O] = q_o; + full_polynomials[POLYNOMIAL::Q_C] = q_c; + full_polynomials[POLYNOMIAL::SIGMA_1] = sigma_1; + full_polynomials[POLYNOMIAL::SIGMA_2] = sigma_2; + full_polynomials[POLYNOMIAL::SIGMA_3] = sigma_3; + full_polynomials[POLYNOMIAL::ID_1] = id_1; + full_polynomials[POLYNOMIAL::ID_2] = id_2; + full_polynomials[POLYNOMIAL::ID_3] = id_3; + full_polynomials[POLYNOMIAL::LAGRANGE_FIRST] = lagrange_first; + full_polynomials[POLYNOMIAL::LAGRANGE_LAST] = lagrange_last; + + return full_polynomials; +} Transcript produce_mocked_transcript(size_t multivariate_d, size_t num_public_inputs) { @@ -96,8 +144,6 @@ TEST(Sumcheck, PolynomialNormalization) constexpr size_t fr_size = 32; - using Multivariates = ::Multivariates; - // clang-format off std::array w_l = { 0, 1, 2, 3, 4, 5, 6, 7 }; std::array w_r = { 0, 0, 0, 0, 0, 0, 0, 0 }; @@ -119,23 +165,34 @@ TEST(Sumcheck, PolynomialNormalization) std::array lagrange_last = { 0, 0, 0, 0, 0, 0, 0, 0 }; // clang-format on - // These will be owned outside the class, probably by the composer. - std::array, Multivariates::num> full_polynomials = { - w_l, w_r, w_o, z_perm, z_perm_shift, q_m, q_l, q_r, q_o, q_c, sigma_1, sigma_2, - sigma_3, id_1, id_2, id_3, lagrange_first, lagrange_last - }; + auto full_polynomials = construct_full_polynomials(w_l, + w_r, + w_o, + z_perm, + z_perm_shift, + q_m, + q_l, + q_r, + q_o, + q_c, + sigma_1, + sigma_2, + sigma_3, + id_1, + id_2, + id_3, + lagrange_first, + lagrange_last); auto transcript = produce_mocked_transcript(multivariate_d, num_public_inputs); - auto multivariates = Multivariates(full_polynomials); - - auto sumcheck = Sumcheck(multivariates, transcript); + GrandProductInitializationRelation>(multivariate_n, transcript); - sumcheck.execute_prover(); + sumcheck.execute_prover(full_polynomials); FF u_1 = transcript.get_challenge_field_element("u_1"); FF u_2 = transcript.get_challenge_field_element("u_2"); @@ -165,7 +222,7 @@ TEST(Sumcheck, PolynomialNormalization) FF hand_computed_value = l_0 * w_l[0] + l_1 * w_l[1] + l_2 * w_l[2] + l_3 * w_l[3] + l_4 * w_l[4] + l_5 * w_l[5] + l_6 * w_l[6] + l_7 * w_l[7]; - EXPECT_EQ(hand_computed_value, sumcheck.multivariates.folded_polynomials[0][0]); + EXPECT_EQ(hand_computed_value, sumcheck.folded_polynomials[POLYNOMIAL::W_L][0]); } TEST(Sumcheck, Prover) @@ -178,8 +235,6 @@ TEST(Sumcheck, Prover) // const size_t max_relation_length = 4; constexpr size_t fr_size = 32; - using Multivariates = ::Multivariates; - // clang-format off std::array w_l = { 1, 2, 0, 0}; std::array w_r = { 1, 2, 0, 0}; @@ -201,23 +256,34 @@ TEST(Sumcheck, Prover) std::array lagrange_last = { 1, 2, 0, 0}; // clang-format on - // These will be owned outside the class, probably by the composer. - std::array, Multivariates::num> full_polynomials = { - w_l, w_r, w_o, z_perm, z_perm_shift, q_m, q_l, q_r, q_o, q_c, sigma_1, sigma_2, - sigma_3, id_1, id_2, id_3, lagrange_first, lagrange_last - }; + auto full_polynomials = construct_full_polynomials(w_l, + w_r, + w_o, + z_perm, + z_perm_shift, + q_m, + q_l, + q_r, + q_o, + q_c, + sigma_1, + sigma_2, + sigma_3, + id_1, + id_2, + id_3, + lagrange_first, + lagrange_last); auto transcript = produce_mocked_transcript(multivariate_d, num_public_inputs); - auto multivariates = Multivariates(full_polynomials); - - auto sumcheck = Sumcheck(multivariates, transcript); + GrandProductInitializationRelation>(multivariate_n, transcript); - sumcheck.execute_prover(); + sumcheck.execute_prover(full_polynomials); FF u_1 = transcript.get_challenge_field_element("u_1"); FF u_2 = transcript.get_challenge_field_element("u_2"); @@ -247,8 +313,6 @@ TEST(Sumcheck, ProverAndVerifier) constexpr size_t fr_size = 32; const size_t num_public_inputs(1); - using Multivariates = ::Multivariates; - std::array w_l = { 0, 1 }; std::array w_r = { 0, 1 }; std::array w_o = { 0, 2 }; @@ -268,25 +332,36 @@ TEST(Sumcheck, ProverAndVerifier) std::array lagrange_first = { 0, 0 }; std::array lagrange_last = { 0, 0 }; // NOTE: Not set up to be valid. - // These will be owned outside the class, probably by the composer. - std::array, Multivariates::num> full_polynomials = { - w_l, w_r, w_o, z_perm, z_perm_shift, q_m, q_l, q_r, q_o, q_c, sigma_1, sigma_2, - sigma_3, id_1, id_2, id_3, lagrange_first, lagrange_last - }; + auto full_polynomials = construct_full_polynomials(w_l, + w_r, + w_o, + z_perm, + z_perm_shift, + q_m, + q_l, + q_r, + q_o, + q_c, + sigma_1, + sigma_2, + sigma_3, + id_1, + id_2, + id_3, + lagrange_first, + lagrange_last); auto transcript = produce_mocked_transcript(multivariate_d, num_public_inputs); - auto multivariates = Multivariates(full_polynomials); - - auto sumcheck_prover = Sumcheck(multivariates, transcript); + GrandProductInitializationRelation>(multivariate_n, transcript); - sumcheck_prover.execute_prover(); + sumcheck_prover.execute_prover(full_polynomials); - auto sumcheck_verifier = Sumcheck; - // clang-format off std::array w_l; if (expect_verified) { w_l = { 0, 1, 2, 0 }; @@ -335,25 +408,36 @@ TEST(Sumcheck, ProverAndVerifierLonger) std::array lagrange_last = { 0, 0, 0, 0 }; // clang-format on - // These will be owned outside the class, probably by the composer. - std::array, Multivariates::num> full_polynomials = { - w_l, w_r, w_o, z_perm, z_perm_shift, q_m, q_l, q_r, q_o, q_c, sigma_1, sigma_2, - sigma_3, id_1, id_2, id_3, lagrange_first, lagrange_last - }; + auto full_polynomials = construct_full_polynomials(w_l, + w_r, + w_o, + z_perm, + z_perm_shift, + q_m, + q_l, + q_r, + q_o, + q_c, + sigma_1, + sigma_2, + sigma_3, + id_1, + id_2, + id_3, + lagrange_first, + lagrange_last); auto transcript = produce_mocked_transcript(multivariate_d, num_public_inputs); - auto multivariates = Multivariates(full_polynomials); - - auto sumcheck_prover = Sumcheck(multivariates, transcript); + GrandProductInitializationRelation>(multivariate_n, transcript); - sumcheck_prover.execute_prover(); + sumcheck_prover.execute_prover(full_polynomials); - auto sumcheck_verifier = Sumcheck #include @@ -20,12 +19,11 @@ namespace test_sumcheck_round { TEST(SumcheckRound, ComputeUnivariateProver) { - const size_t num_polys(bonk::StandardArithmetization::NUM_POLYNOMIALS); + const size_t NUM_POLYNOMIALS(bonk::StandardArithmetization::NUM_POLYNOMIALS); // const size_t multivariate_d(1); const size_t max_relation_length = 5; using FF = barretenberg::fr; - using Multivariates = ::Multivariates; std::array w_l = { 1, 2 }; std::array w_r = { 1, 2 }; @@ -46,10 +44,26 @@ TEST(SumcheckRound, ComputeUnivariateProver) std::array lagrange_first = { 1, 2 }; std::array lagrange_last = { 1, 2 }; - std::array, bonk::StandardArithmetization::NUM_POLYNOMIALS> full_polynomials = { - w_l, w_r, w_o, z_perm, z_perm_shift, q_m, q_l, q_r, q_o, q_c, sigma_1, sigma_2, - sigma_3, id_1, id_2, id_3, lagrange_first, lagrange_last - }; + std::array, NUM_POLYNOMIALS> full_polynomials; + using POLYNOMIAL = bonk::StandardArithmetization::POLYNOMIAL; + full_polynomials[POLYNOMIAL::W_L] = w_l; + full_polynomials[POLYNOMIAL::W_R] = w_r; + full_polynomials[POLYNOMIAL::W_O] = w_o; + full_polynomials[POLYNOMIAL::Z_PERM] = z_perm; + full_polynomials[POLYNOMIAL::Z_PERM_SHIFT] = z_perm_shift; + full_polynomials[POLYNOMIAL::Q_M] = q_m; + full_polynomials[POLYNOMIAL::Q_L] = q_l; + full_polynomials[POLYNOMIAL::Q_R] = q_r; + full_polynomials[POLYNOMIAL::Q_O] = q_o; + full_polynomials[POLYNOMIAL::Q_C] = q_c; + full_polynomials[POLYNOMIAL::SIGMA_1] = sigma_1; + full_polynomials[POLYNOMIAL::SIGMA_2] = sigma_2; + full_polynomials[POLYNOMIAL::SIGMA_3] = sigma_3; + full_polynomials[POLYNOMIAL::ID_1] = id_1; + full_polynomials[POLYNOMIAL::ID_2] = id_2; + full_polynomials[POLYNOMIAL::ID_3] = id_3; + full_polynomials[POLYNOMIAL::LAGRANGE_FIRST] = lagrange_first; + full_polynomials[POLYNOMIAL::LAGRANGE_LAST] = lagrange_last; size_t round_size = 1; @@ -58,7 +72,7 @@ TEST(SumcheckRound, ComputeUnivariateProver) // Improvement(Cody): This is ugly? Maye supply some/all of this data through "flavor" class? auto round = SumcheckRound(round_size, relations); @@ -74,13 +88,12 @@ TEST(SumcheckRound, ComputeUnivariateProver) TEST(SumcheckRound, ComputeUnivariateVerifier) { - const size_t num_polys(bonk::StandardArithmetization::NUM_POLYNOMIALS); + const size_t NUM_POLYNOMIALS(bonk::StandardArithmetization::NUM_POLYNOMIALS); // const size_t multivariate_d(1); // const size_t multivariate_n(1 << multivariate_d); // const size_t max_rezlation_length = 5; using FF = barretenberg::fr; - using Multivariates = ::Multivariates; FF w_l = { 1 }; FF w_r = { 2 }; @@ -105,15 +118,35 @@ TEST(SumcheckRound, ComputeUnivariateVerifier) // q_m * w_l * w_r + q_l * w_l + q_r * w_r + q_o * w_o + q_c // = 1 * (4 * 1 * 2 + 5 * 1 + 6 * 2 + 7 * 3 + 8) = 54 FF expected_full_purported_value = 54; - std::vector purported_evaluations = { w_l, w_r, w_o, z_perm, z_perm_shift, q_m, - q_l, q_r, q_o, q_c, sigma_1, sigma_2, - sigma_3, id_1, id_2, id_3, lagrange_first, lagrange_last }; + + std::vector purported_evaluations; + purported_evaluations.resize(NUM_POLYNOMIALS); + + using POLYNOMIAL = bonk::StandardArithmetization::POLYNOMIAL; + purported_evaluations[POLYNOMIAL::W_L] = w_l; + purported_evaluations[POLYNOMIAL::W_R] = w_r; + purported_evaluations[POLYNOMIAL::W_O] = w_o; + purported_evaluations[POLYNOMIAL::Z_PERM] = z_perm; + purported_evaluations[POLYNOMIAL::Z_PERM_SHIFT] = z_perm_shift; + purported_evaluations[POLYNOMIAL::Q_M] = q_m; + purported_evaluations[POLYNOMIAL::Q_L] = q_l; + purported_evaluations[POLYNOMIAL::Q_R] = q_r; + purported_evaluations[POLYNOMIAL::Q_O] = q_o; + purported_evaluations[POLYNOMIAL::Q_C] = q_c; + purported_evaluations[POLYNOMIAL::SIGMA_1] = sigma_1; + purported_evaluations[POLYNOMIAL::SIGMA_2] = sigma_2; + purported_evaluations[POLYNOMIAL::SIGMA_3] = sigma_3; + purported_evaluations[POLYNOMIAL::ID_1] = id_1; + purported_evaluations[POLYNOMIAL::ID_2] = id_2; + purported_evaluations[POLYNOMIAL::ID_3] = id_3; + purported_evaluations[POLYNOMIAL::LAGRANGE_FIRST] = lagrange_first; + purported_evaluations[POLYNOMIAL::LAGRANGE_LAST] = lagrange_last; // size_t round_size = 1; auto relations = std::tuple( ArithmeticRelation(), GrandProductComputationRelation(), GrandProductInitializationRelation()); auto round = SumcheckRound(relations); diff --git a/cpp/src/aztec/proof_system/flavor/flavor.hpp b/cpp/src/aztec/proof_system/flavor/flavor.hpp index 0f8d1a2ea7..ff3be32386 100644 --- a/cpp/src/aztec/proof_system/flavor/flavor.hpp +++ b/cpp/src/aztec/proof_system/flavor/flavor.hpp @@ -1,5 +1,6 @@ #pragma once -#include "proof_system/types/polynomial_manifest.hpp" +#include +#include #include #include @@ -7,17 +8,22 @@ // TODO(Cody): "bonk" is short for "both plonk and honk". Just need a short and non-vague temporary name. namespace bonk { struct StandardArithmetization { + /** + * @brief All of the multivariate polynomials used by the Standard Honk Prover. + * @details The polynomials are broken into three categories: precomputed, witness, and shifted. + * This separation must be maintained to allow for programmatic access, but the ordering of the + * polynomials can be permuted within each category if necessary. Polynomials can also be added + * or removed (assuming consistency with the prover algorithm) but the constants describing the + * number of poynomials in each category must be manually updated. + * + */ enum POLYNOMIAL { - W_L, - W_R, - W_O, - Z_PERM, - Z_PERM_SHIFT, - Q_M, + /* --- PRECOMPUTED POLYNOMIALS --- */ + Q_C, Q_L, Q_R, Q_O, - Q_C, + Q_M, SIGMA_1, SIGMA_2, SIGMA_3, @@ -26,10 +32,32 @@ struct StandardArithmetization { ID_3, LAGRANGE_FIRST, LAGRANGE_LAST, // = LAGRANGE_N-1 whithout ZK, but can be less - COUNT + /* --- WITNESS POLYNOMIALS --- */ + W_L, + W_R, + W_O, + Z_PERM, + /* --- SHIFTED POLYNOMIALS --- */ + Z_PERM_SHIFT, + /* --- --- */ + COUNT // for programmatic determination of NUM_POLYNOMIALS }; static constexpr size_t NUM_POLYNOMIALS = POLYNOMIAL::COUNT; + static constexpr size_t NUM_SHIFTED_POLYNOMIALS = 1; + static constexpr size_t NUM_PRECOMPUTED_POLYNOMIALS = 13; + static constexpr size_t NUM_UNSHIFTED_POLYNOMIALS = NUM_POLYNOMIALS - NUM_SHIFTED_POLYNOMIALS; + + // *** WARNING: The order of this array must be manually updated to match POLYNOMIAL enum *** + // TODO(luke): This is a temporary measure to associate the above enum with sting tags. Its only needed because + // the + // polynomials/commitments in the prover/verifier are stored in maps. This storage could be converted to simple + // arrays at which point these string tags can be removed. + inline static const std::array ENUM_TO_COMM = { + "Q_C", "Q_1", "Q_2", "Q_3", "Q_M", "SIGMA_1", + "SIGMA_2", "SIGMA_3", "ID_1", "ID_2", "ID_3", "LAGRANGE_FIRST", + "LAGRANGE_LAST", "W_1", "W_2", "W_3", "Z_PERM", "Z_PERM_SHIFT" + }; }; } // namespace bonk @@ -108,7 +136,7 @@ struct StandardHonk { // Round 5 + num_sumcheck_rounds manifest_rounds.emplace_back(transcript::Manifest::RoundManifest( { - { .name = "multivariate_evaluations", .num_bytes = fr_size * bonk::STANDARD_HONK_TOTAL_NUM_POLYS, .derived_by_verifier = false, .challenge_map_index = 0 }, + { .name = "multivariate_evaluations", .num_bytes = fr_size * bonk::StandardArithmetization::NUM_POLYNOMIALS, .derived_by_verifier = false, .challenge_map_index = 0 }, }, /* challenge_name = */ "rho", /* num_challenges_in = */ 1)); /* TODO(Cody): magic number! Where should this be specified? */ diff --git a/cpp/src/aztec/proof_system/types/polynomial_manifest.hpp b/cpp/src/aztec/proof_system/types/polynomial_manifest.hpp index a3f488f5f0..5362913f64 100644 --- a/cpp/src/aztec/proof_system/types/polynomial_manifest.hpp +++ b/cpp/src/aztec/proof_system/types/polynomial_manifest.hpp @@ -171,31 +171,6 @@ static constexpr PolynomialDescriptor ultra_polynomial_manifest[ULTRA_UNROLLED_M PolynomialDescriptor("ID_4", "id_4", false, false, PERMUTATION, ID_4), // }; -// TODO(Cody): Get this right; just using for now to extract names. -static constexpr size_t STANDARD_HONK_MANIFEST_SIZE = 17; // equivalent to num unshifted polynomials -static constexpr size_t NUM_SHIFTED_POLYNOMIALS = 1; -static constexpr size_t STANDARD_HONK_TOTAL_NUM_POLYS = STANDARD_HONK_MANIFEST_SIZE + NUM_SHIFTED_POLYNOMIALS; -static constexpr PolynomialDescriptor standard_honk_polynomial_manifest[STANDARD_HONK_MANIFEST_SIZE]{ - PolynomialDescriptor("W_1", "w_1_lagrange", false, false, WITNESS, W_1), // - PolynomialDescriptor("W_2", "w_2_lagrange", false, false, WITNESS, W_2), // - PolynomialDescriptor("W_3", "w_3_lagrange", false, false, WITNESS, W_3), // - PolynomialDescriptor("Z_PERM", "z_perm_lagrange", true, true, WITNESS, Z), // - // PolynomialDescriptor("Z_PERM_SHIFT", "z_perm_shift_lagrange", true, true, WITNESS, Z_LOOKUP), // - PolynomialDescriptor("Q_M", "q_m_lagrange", true, false, SELECTOR, Q_M), // - PolynomialDescriptor("Q_1", "q_1_lagrange", true, false, SELECTOR, Q_1), // - PolynomialDescriptor("Q_2", "q_2_lagrange", true, false, SELECTOR, Q_2), // - PolynomialDescriptor("Q_3", "q_3_lagrange", true, false, SELECTOR, Q_3), // - PolynomialDescriptor("Q_C", "q_c_lagrange", true, false, SELECTOR, Q_C), // - PolynomialDescriptor("SIGMA_1", "sigma_1_lagrange", false, false, PERMUTATION, SIGMA_1), // - PolynomialDescriptor("SIGMA_2", "sigma_2_lagrange", false, false, PERMUTATION, SIGMA_2), // - PolynomialDescriptor("SIGMA_3", "sigma_3_lagrange", true, false, PERMUTATION, SIGMA_3), // - PolynomialDescriptor("ID_1", "id_1_lagrange", false, false, PERMUTATION, ID_1), // - PolynomialDescriptor("ID_2", "id_2_lagrange", false, false, PERMUTATION, ID_2), // - PolynomialDescriptor("ID_3", "id_3_lagrange", true, false, PERMUTATION, ID_3), // - PolynomialDescriptor("LAGRANGE_FIRST", "L_first_lagrange", false, false, OTHER, LAGRANGE_FIRST), // - PolynomialDescriptor("LAGRANGE_LAST", "L_last_lagrange", false, false, OTHER, LAGRANGE_LAST), // -}; - // Simple class allowing for access to a polynomial manifest based on composer type class PolynomialManifest { // TODO(luke): make this object iterable, i.e. compatible with range-based for loop @@ -226,12 +201,6 @@ class PolynomialManifest { std::back_inserter(manifest)); break; }; - case plonk::ComposerType::STANDARD_HONK: { - std::copy(standard_honk_polynomial_manifest, - standard_honk_polynomial_manifest + STANDARD_HONK_MANIFEST_SIZE, - std::back_inserter(manifest)); - break; - }; default: { // TODO(luke): reinstate this. Was getting "use of undeclared identifier" error for 'throw_or_abort'. // throw_or_abort("Received invalid composer type"); diff --git a/cpp/src/aztec/stdlib/primitives/bool/bool.test.cpp b/cpp/src/aztec/stdlib/primitives/bool/bool.test.cpp index b9fd08836d..c882dabafb 100644 --- a/cpp/src/aztec/stdlib/primitives/bool/bool.test.cpp +++ b/cpp/src/aztec/stdlib/primitives/bool/bool.test.cpp @@ -27,24 +27,24 @@ TEST(stdlib_bool, test_basic_operations) d = (!f) & a; // d = 1 auto prover = composer.preprocess(); // if constexpr (Composer::type == plonk::ComposerType::STANDARD_HONK) { - EXPECT_EQ(prover.key->polynomial_cache.get("w_1_lagrange")[3], fr(1)); - EXPECT_EQ(prover.key->polynomial_cache.get("w_2_lagrange")[3], fr(1)); - EXPECT_EQ(prover.key->polynomial_cache.get("w_3_lagrange")[3], fr(1)); - EXPECT_EQ(prover.key->polynomial_cache.get("w_1_lagrange")[4], fr(0)); - EXPECT_EQ(prover.key->polynomial_cache.get("w_2_lagrange")[4], fr(0)); - EXPECT_EQ(prover.key->polynomial_cache.get("w_3_lagrange")[4], fr(0)); - EXPECT_EQ(prover.key->polynomial_cache.get("w_1_lagrange")[5], fr(1)); - EXPECT_EQ(prover.key->polynomial_cache.get("w_2_lagrange")[5], fr(0)); - EXPECT_EQ(prover.key->polynomial_cache.get("w_3_lagrange")[5], fr(1)); - EXPECT_EQ(prover.key->polynomial_cache.get("w_1_lagrange")[6], fr(1)); - EXPECT_EQ(prover.key->polynomial_cache.get("w_2_lagrange")[6], fr(0)); - EXPECT_EQ(prover.key->polynomial_cache.get("w_3_lagrange")[6], fr(1)); - EXPECT_EQ(prover.key->polynomial_cache.get("w_1_lagrange")[7], fr(1)); - EXPECT_EQ(prover.key->polynomial_cache.get("w_2_lagrange")[7], fr(0)); - EXPECT_EQ(prover.key->polynomial_cache.get("w_3_lagrange")[7], fr(0)); - EXPECT_EQ(prover.key->polynomial_cache.get("w_1_lagrange")[8], fr(0)); - EXPECT_EQ(prover.key->polynomial_cache.get("w_2_lagrange")[8], fr(1)); - EXPECT_EQ(prover.key->polynomial_cache.get("w_3_lagrange")[8], fr(1)); + EXPECT_EQ(prover.wire_polynomials[0][3], fr(1)); + EXPECT_EQ(prover.wire_polynomials[1][3], fr(1)); + EXPECT_EQ(prover.wire_polynomials[2][3], fr(1)); + EXPECT_EQ(prover.wire_polynomials[0][4], fr(0)); + EXPECT_EQ(prover.wire_polynomials[1][4], fr(0)); + EXPECT_EQ(prover.wire_polynomials[2][4], fr(0)); + EXPECT_EQ(prover.wire_polynomials[0][5], fr(1)); + EXPECT_EQ(prover.wire_polynomials[1][5], fr(0)); + EXPECT_EQ(prover.wire_polynomials[2][5], fr(1)); + EXPECT_EQ(prover.wire_polynomials[0][6], fr(1)); + EXPECT_EQ(prover.wire_polynomials[1][6], fr(0)); + EXPECT_EQ(prover.wire_polynomials[2][6], fr(1)); + EXPECT_EQ(prover.wire_polynomials[0][7], fr(1)); + EXPECT_EQ(prover.wire_polynomials[1][7], fr(0)); + EXPECT_EQ(prover.wire_polynomials[2][7], fr(0)); + EXPECT_EQ(prover.wire_polynomials[0][8], fr(0)); + EXPECT_EQ(prover.wire_polynomials[1][8], fr(1)); + EXPECT_EQ(prover.wire_polynomials[2][8], fr(1)); // } else { // EXPECT_EQ(prover.key->polynomial_cache.get("w_1_lagrange")[1], fr(1)); // EXPECT_EQ(prover.key->polynomial_cache.get("w_2_lagrange")[1], fr(1)); @@ -65,7 +65,7 @@ TEST(stdlib_bool, test_basic_operations) // EXPECT_EQ(prover.key->polynomial_cache.get("w_2_lagrange")[6], fr(1)); // EXPECT_EQ(prover.key->polynomial_cache.get("w_3_lagrange")[6], fr(1)); // } - EXPECT_EQ(prover.circuit_size, 16UL); + EXPECT_EQ(prover.key->circuit_size, 16UL); } TEST(stdlib_bool, xor) diff --git a/cpp/src/aztec/stdlib/primitives/field/field.test.cpp b/cpp/src/aztec/stdlib/primitives/field/field.test.cpp index eb9e7d1ab3..5c0ba6fc06 100644 --- a/cpp/src/aztec/stdlib/primitives/field/field.test.cpp +++ b/cpp/src/aztec/stdlib/primitives/field/field.test.cpp @@ -193,12 +193,12 @@ template class stdlib_field : public testing::Test { auto prover = composer.create_prover(); if constexpr (Composer::type == plonk::ComposerType::STANDARD_HONK) { - EXPECT_EQ(prover.key->polynomial_cache.get("w_3_lagrange")[20], fr(expected)); + EXPECT_EQ(prover.wire_polynomials[2][20], fr(expected)); } else { EXPECT_EQ(prover.key->polynomial_cache.get("w_3_lagrange")[18], fr(expected)); } - EXPECT_EQ(prover.circuit_size, 32UL); + EXPECT_EQ(prover.key->circuit_size, 32UL); auto verifier = composer.create_verifier(); plonk::proof proof = prover.construct_proof(); bool result = verifier.verify_proof(proof); @@ -250,12 +250,12 @@ template class stdlib_field : public testing::Test { auto prover = composer.create_prover(); if constexpr (Composer::type == plonk::ComposerType::STANDARD_HONK) { - EXPECT_EQ(prover.key->polynomial_cache.get("w_3_lagrange")[19], fr(4181)); + EXPECT_EQ(prover.wire_polynomials[2][19], fr(4181)); } else { EXPECT_EQ(prover.key->polynomial_cache.get("w_3_lagrange")[17], fr(4181)); } - EXPECT_EQ(prover.circuit_size, 32UL); + EXPECT_EQ(prover.key->circuit_size, 32UL); auto verifier = composer.create_verifier(); plonk::proof proof = prover.construct_proof(); @@ -306,7 +306,7 @@ template class stdlib_field : public testing::Test { fr x = composer.get_variable(r.witness_index); EXPECT_EQ(x, fr(1)); - EXPECT_EQ(prover.circuit_size, 16UL); + EXPECT_EQ(prover.key->circuit_size, 16UL); auto verifier = composer.create_verifier(); plonk::proof proof = prover.construct_proof(); @@ -330,7 +330,7 @@ template class stdlib_field : public testing::Test { fr x = composer.get_variable(r.witness_index); EXPECT_EQ(x, fr(0)); - EXPECT_EQ(prover.circuit_size, 16UL); + EXPECT_EQ(prover.key->circuit_size, 16UL); auto verifier = composer.create_verifier(); plonk::proof proof = prover.construct_proof(); @@ -355,7 +355,7 @@ template class stdlib_field : public testing::Test { fr x = composer.get_variable(r.witness_index); EXPECT_EQ(x, fr(1)); - EXPECT_EQ(prover.circuit_size, 16UL); + EXPECT_EQ(prover.key->circuit_size, 16UL); auto verifier = composer.create_verifier(); plonk::proof proof = prover.construct_proof();