From 170111e9182ce93f3317040339e701477243fdd7 Mon Sep 17 00:00:00 2001 From: ledwards2225 Date: Mon, 10 Apr 2023 18:33:37 +0000 Subject: [PATCH 01/11] add split UltraHonk composer and checks for consistency with UltraPlonk --- .../ultra_honk_composer_helper.cpp | 36 ++- .../ultra_honk_composer_helper.hpp | 4 +- .../composer/ultra_honk_composer.test.cpp | 5 +- .../barretenberg/honk/proof_system/prover.hpp | 7 +- .../honk/proof_system/ultra_prover.cpp | 269 +++++++++++++++++- .../honk/proof_system/ultra_prover.hpp | 49 +++- .../honk/proof_system/verifier.hpp | 3 + .../plonk/composer/composer_base.cpp | 7 + .../plonk/composer/ultra_composer.cpp | 11 + .../composer/composer_helper_lib.hpp | 20 ++ .../composer/permutation_helper.hpp | 4 +- 11 files changed, 386 insertions(+), 29 deletions(-) diff --git a/cpp/src/barretenberg/honk/composer/composer_helper/ultra_honk_composer_helper.cpp b/cpp/src/barretenberg/honk/composer/composer_helper/ultra_honk_composer_helper.cpp index 26b7781bc4..6adafef13f 100644 --- a/cpp/src/barretenberg/honk/composer/composer_helper/ultra_honk_composer_helper.cpp +++ b/cpp/src/barretenberg/honk/composer/composer_helper/ultra_honk_composer_helper.cpp @@ -15,10 +15,12 @@ namespace proof_system::honk { /** - * @brief Compute witness polynomials + * @brief Computes `this.witness`, which is basiclly a set of polynomials mapped-to by strings. * - * TODO(luke): The wire polynomials are returned directly whereas the sorted list polys are added to the proving - * key. This should be made consistent once Cody's Flavor work is settled. + * Note: this doesn't actually compute the _entire_ witness. Things missing: randomness for blinding both the wires + and + * sorted `s` poly, lookup rows of the wire witnesses, the values of `z_lookup`, `z`. These are all calculated + * elsewhere. */ template void UltraHonkComposerHelper::compute_witness(CircuitConstructor& circuit_constructor) @@ -49,22 +51,33 @@ void UltraHonkComposerHelper::compute_witness(CircuitConstru circuit_constructor.w_4.emplace_back(circuit_constructor.zero_idx); } - // TODO(#340)(luke): within compute_witness_base, the 3rd argument is used in the calculation of the dyadic circuit - // size (subgroup_size). Here (and in other split composers) we're passing in NUM_RANDOMIZED_GATES, but elsewhere, - // e.g. directly above, we use NUM_RESERVED_GATES in a similar role. Therefore, these two constants must be equal - // for everything to be consistent. What we should do is compute the dyadic circuit size once and for all then pass - // that around rather than computing in multiple places. + info("circuit_constructor.w_l.size() = ", circuit_constructor.w_l.size()); + info("filled_gates = ", filled_gates); + info("total_num_gates = ", total_num_gates); + info("subgroup_size = ", subgroup_size); + info("circuit_constructor.w_l[2786] = ", circuit_constructor.w_l[2786]); + // info("circuit_constructor.w_l.end() = ", circuit_constructor.w_l.end()); + + // TODO(luke): subgroup size was already computed above but compute_witness_base computes it again. If we pass in + // NUM_RANDOMIZED_GATES (as in the other split composers) the resulting sizes can differ. Reconcile this. wire_polynomials = compute_witness_base(circuit_constructor, total_num_gates, NUM_RANDOMIZED_GATES); + info("circuit_constructor.w_l.size() = ", circuit_constructor.w_l.size()); + info("circuit_constructor.w_l[2786] = ", circuit_constructor.w_l[2786]); + info("circuit_constructor.w_l[4095] = ", circuit_constructor.w_l[4095]); + // info("circuit_constructor.w_l.end() = ", circuit_constructor.w_l.end()); + polynomial s_1(subgroup_size); polynomial s_2(subgroup_size); polynomial s_3(subgroup_size); polynomial s_4(subgroup_size); polynomial z_lookup(subgroup_size + 1); // Only instantiated in this function; nothing assigned. - // Save space for adding random scalars in the s polynomial later. The subtracted 1 allows us to insert a `1` at the - // end, to ensure the evaluations (and hence coefficients) aren't all 0. See ComposerBase::compute_proving_key_base - // for further explanation, as a similar trick is done there. + // Save space for adding random scalars in the s polynomial later. + // The subtracted 1 allows us to insert a `1` at the end, to ensure the evaluations (and hence coefficients) + // aren't + // all 0. + // See ComposerBase::compute_proving_key_base for further explanation, as a similar trick is done there. size_t count = subgroup_size - tables_size - lookups_size - s_randomness - 1; for (size_t i = 0; i < count; ++i) { s_1[i] = 0; @@ -201,6 +214,7 @@ std::shared_ptr UltraHonkComposerHelper: construct_lagrange_selector_forms(circuit_constructor, circuit_proving_key.get()); + // TODO(luke): was there some question as to whether we would take this same strategy for Honk? enforce_nonzero_polynomial_selectors(circuit_constructor, circuit_proving_key.get()); compute_honk_generalized_sigma_permutations(circuit_constructor, diff --git a/cpp/src/barretenberg/honk/composer/composer_helper/ultra_honk_composer_helper.hpp b/cpp/src/barretenberg/honk/composer/composer_helper/ultra_honk_composer_helper.hpp index de309735e6..b019190e6d 100644 --- a/cpp/src/barretenberg/honk/composer/composer_helper/ultra_honk_composer_helper.hpp +++ b/cpp/src/barretenberg/honk/composer/composer_helper/ultra_honk_composer_helper.hpp @@ -17,8 +17,8 @@ namespace proof_system::honk { // Cody: What does this mean? template class UltraHonkComposerHelper { public: - // TODO(#340)(luke): In the split composers, NUM_RANDOMIZED_GATES has replaced NUM_RESERVED_GATES (in some places) - // to determine the next-power-of-2 circuit size. (There are some places in this composer that still use + // TODO(luke): In the split composers, NUM_RANDOMIZED_GATES has replaced NUM_RESERVED_GATES (in some places) to + // determine the next-power-of-2 circuit size. (There are some places in this composer that still use // NUM_RESERVED_GATES). Therefore for consistency within this composer itself, and consistency with the original // Ultra Composer, this value must match that of NUM_RESERVED_GATES. This issue needs to be reconciled // simultaneously here and in the other split composers. diff --git a/cpp/src/barretenberg/honk/composer/ultra_honk_composer.test.cpp b/cpp/src/barretenberg/honk/composer/ultra_honk_composer.test.cpp index 29f7b26c55..142562ac98 100644 --- a/cpp/src/barretenberg/honk/composer/ultra_honk_composer.test.cpp +++ b/cpp/src/barretenberg/honk/composer/ultra_honk_composer.test.cpp @@ -71,6 +71,7 @@ void check_consistency(honk::UltraProver& honk_prover, plonk::UltraProver& plonk for (auto& entry : honk_store) { std::string key = entry.first; if (plonk_store.contains(key)) { + // info(key); bool polys_equal = (honk_store.get(key) == plonk_store.get(key)); if (polys_equal) { @@ -79,6 +80,9 @@ void check_consistency(honk::UltraProver& honk_prover, plonk::UltraProver& plonk if (!polys_equal) { info("UNEQUAL: ", key); } + // bool size_equal = (honk_store.get(key).size() == plonk_store.get(key).size()); + // if(size_equal) { info("Size Equal: ", key); } + // if(!size_equal) { info("Size UNEQUAL: ", key); } } } @@ -876,7 +880,6 @@ TEST(UltraHonkComposer, rom) auto honk_prover = honk_composer.create_prover(); auto plonk_prover = plonk_composer.create_prover(); - check_consistency(honk_prover, plonk_prover); verify_consistency(honk_prover, plonk_prover); } diff --git a/cpp/src/barretenberg/honk/proof_system/prover.hpp b/cpp/src/barretenberg/honk/proof_system/prover.hpp index 2a0e4de314..9d47244ce6 100644 --- a/cpp/src/barretenberg/honk/proof_system/prover.hpp +++ b/cpp/src/barretenberg/honk/proof_system/prover.hpp @@ -27,12 +27,11 @@ #include "barretenberg/honk/proof_system/work_queue.hpp" namespace proof_system::honk { - -using Fr = barretenberg::fr; -using Polynomial = Polynomial; - template class Prover { + using Fr = barretenberg::fr; + using Polynomial = Polynomial; + public: Prover(std::vector&& wire_polys, std::shared_ptr input_key = nullptr); diff --git a/cpp/src/barretenberg/honk/proof_system/ultra_prover.cpp b/cpp/src/barretenberg/honk/proof_system/ultra_prover.cpp index 769e744a6d..2070829c40 100644 --- a/cpp/src/barretenberg/honk/proof_system/ultra_prover.cpp +++ b/cpp/src/barretenberg/honk/proof_system/ultra_prover.cpp @@ -24,6 +24,11 @@ namespace proof_system::honk { +using Fr = barretenberg::fr; +using Commitment = barretenberg::g1::affine_element; +using Polynomial = barretenberg::Polynomial; +using POLYNOMIAL = proof_system::honk::StandardArithmetization::POLYNOMIAL; + /** * Create UltraHonkProver from proving key, witness and manifest. * @@ -37,8 +42,221 @@ UltraHonkProver::UltraHonkProver(std::vector std::shared_ptr input_key) : wire_polynomials(wire_polys) , key(input_key) - , queue(key, transcript) -{} + , commitment_key(std::make_unique( + input_key->circuit_size, + "../srs_db/ignition")) // TODO(Cody): Need better constructors for prover. +// , queue(proving_key.get(), &transcript) +{ + // // 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_store.get("q_c_lagrange"); + // prover_polynomials[POLYNOMIAL::Q_L] = key->polynomial_store.get("q_1_lagrange"); + // prover_polynomials[POLYNOMIAL::Q_R] = key->polynomial_store.get("q_2_lagrange"); + // prover_polynomials[POLYNOMIAL::Q_O] = key->polynomial_store.get("q_3_lagrange"); + // prover_polynomials[POLYNOMIAL::Q_M] = key->polynomial_store.get("q_m_lagrange"); + // prover_polynomials[POLYNOMIAL::SIGMA_1] = key->polynomial_store.get("sigma_1_lagrange"); + // prover_polynomials[POLYNOMIAL::SIGMA_2] = key->polynomial_store.get("sigma_2_lagrange"); + // prover_polynomials[POLYNOMIAL::SIGMA_3] = key->polynomial_store.get("sigma_3_lagrange"); + // prover_polynomials[POLYNOMIAL::ID_1] = key->polynomial_store.get("id_1_lagrange"); + // prover_polynomials[POLYNOMIAL::ID_2] = key->polynomial_store.get("id_2_lagrange"); + // prover_polynomials[POLYNOMIAL::ID_3] = key->polynomial_store.get("id_3_lagrange"); + // prover_polynomials[POLYNOMIAL::LAGRANGE_FIRST] = key->polynomial_store.get("L_first_lagrange"); + // prover_polynomials[POLYNOMIAL::LAGRANGE_LAST] = key->polynomial_store.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]; + + // // Add public inputs to transcript from the second wire polynomial + // std::span public_wires_source = prover_polynomials[POLYNOMIAL::W_R]; + + // for (size_t i = 0; i < key->num_public_inputs; ++i) { + // public_inputs.emplace_back(public_wires_source[i]); + // } +} + +// /** +// * - Commit to wires 1,2,3 +// * - Add PI to transcript (I guess PI will stay in w_2 for now?) +// * +// * */ +// template void UltraHonkProver::compute_wire_commitments() +// { +// for (size_t i = 0; i < settings::Arithmetization::num_wires; ++i) { +// auto commitment = commitment_key->commit(wire_polynomials[i]); + +// transcript.send_to_verifier("W_" + std::to_string(i + 1), commitment); +// } +// } + +// /** +// * - Add circuit size, public input size, and public inputs to transcript +// * +// * */ +// template void UltraHonkProver::execute_preamble_round() +// { +// // queue.flush_queue(); // NOTE: Don't remove; we may reinstate the queue + +// const auto circuit_size = static_cast(key->circuit_size); +// const auto num_public_inputs = static_cast(key->num_public_inputs); + +// transcript.send_to_verifier("circuit_size", circuit_size); +// transcript.send_to_verifier("public_input_size", num_public_inputs); + +// for (size_t i = 0; i < key->num_public_inputs; ++i) { +// auto public_input_i = public_inputs[i]; +// transcript.send_to_verifier("public_input_" + std::to_string(i), public_input_i); +// } +// } + +// /** +// * - compute wire commitments +// * */ +// template void UltraHonkProver::execute_wire_commitments_round() +// { +// // queue.flush_queue(); // NOTE: Don't remove; we may reinstate the queue +// compute_wire_commitments(); +// } + +// /** +// * For Standard Honk, this is a non-op (just like for Standard/Turbo Plonk). +// * */ +// template void UltraHonkProver::execute_tables_round() +// { +// // No operations are needed here for Standard Honk +// } + +// /** +// * - Do Fiat-Shamir to get "beta" challenge (Note: gamma = beta^2) +// * - Compute grand product polynomial (permutation only) and commitment +// * */ +// template void UltraHonkProver::execute_grand_product_computation_round() +// { +// // queue.flush_queue(); // NOTE: Don't remove; we may reinstate the queue + +// // Compute and store parameters required by relations in Sumcheck +// auto [beta, gamma] = transcript.get_challenges("beta", "gamma"); + +// auto public_input_delta = compute_public_input_delta(public_inputs, beta, gamma, key->circuit_size); + +// relation_parameters = sumcheck::RelationParameters{ +// .beta = beta, +// .gamma = gamma, +// .public_input_delta = public_input_delta, +// }; + +// z_permutation = +// prover_library::compute_permutation_grand_product(key, wire_polynomials, beta, +// gamma); + +// auto commitment = commitment_key->commit(z_permutation); + +// transcript.send_to_verifier("Z_PERM", commitment); + +// prover_polynomials[POLYNOMIAL::Z_PERM] = z_permutation; +// prover_polynomials[POLYNOMIAL::Z_PERM_SHIFT] = z_permutation.shifted(); +// } + +// /** +// * - Do Fiat-Shamir to get "alpha" challenge +// * - Run Sumcheck resulting in u = (u_1,...,u_d) challenges and all +// * evaluations at u being calculated. +// * */ +// template void UltraHonkProver::execute_relation_check_rounds() +// { +// // queue.flush_queue(); // NOTE: Don't remove; we may reinstate the queue + +// using Sumcheck = sumcheck::Sumcheck, +// sumcheck::ArithmeticRelation, +// sumcheck::GrandProductComputationRelation, +// sumcheck::GrandProductInitializationRelation>; + +// auto sumcheck = Sumcheck(key->circuit_size, transcript); + +// sumcheck_output = sumcheck.execute_prover(prover_polynomials, relation_parameters); +// } + +// /** +// * - Get rho challenge +// * - Compute d+1 Fold polynomials and their evaluations. +// * +// * */ +// template void UltraHonkProver::execute_univariatization_round() +// { +// const size_t NUM_POLYNOMIALS = proof_system::honk::StandardArithmetization::NUM_POLYNOMIALS; +// const size_t NUM_UNSHIFTED_POLYS = proof_system::honk::StandardArithmetization::NUM_UNSHIFTED_POLYNOMIALS; + +// // Generate batching challenge ρ and powers 1,ρ,…,ρᵐ⁻¹ +// Fr rho = transcript.get_challenge("rho"); +// std::vector rhos = Gemini::powers_of_rho(rho, NUM_POLYNOMIALS); + +// // Batch the unshifted polynomials and the to-be-shifted polynomials using ρ +// Polynomial batched_poly_unshifted(key->circuit_size); // batched unshifted polynomials +// for (size_t i = 0; i < NUM_UNSHIFTED_POLYS; ++i) { +// batched_poly_unshifted.add_scaled(prover_polynomials[i], rhos[i]); +// } +// Polynomial batched_poly_to_be_shifted(key->circuit_size); // batched to-be-shifted polynomials +// batched_poly_to_be_shifted.add_scaled(prover_polynomials[POLYNOMIAL::Z_PERM], rhos[NUM_UNSHIFTED_POLYS]); + +// // // Reserve space for d+1 Fold polynomials. At the end of this round, the last d-1 polynomials will +// // // correspond to Fold^(i). At the end of the full Gemini prover protocol, the first two will +// // // be the partially evaluated Fold polynomials Fold_{r}^(0) and Fold_{-r}^(0). +// // fold_polynomials.reserve(key->log_circuit_size + 1); +// // fold_polynomials.emplace_back(batched_poly_unshifted); +// // fold_polynomials.emplace_back(batched_poly_to_be_shifted); + +// // Compute d-1 polynomials Fold^(i), i = 1, ..., d-1. +// fold_polynomials = Gemini::compute_fold_polynomials( +// sumcheck_output.challenge_point, std::move(batched_poly_unshifted), std::move(batched_poly_to_be_shifted)); + +// // Compute and add to trasnscript the commitments [Fold^(i)], i = 1, ..., d-1 +// for (size_t l = 0; l < key->log_circuit_size - 1; ++l) { +// std::string label = "Gemini:FOLD_" + std::to_string(l + 1); +// auto commitment = commitment_key->commit(fold_polynomials[l + 2]); +// transcript.send_to_verifier(label, commitment); +// } +// } + +// /** +// * - Do Fiat-Shamir to get "r" challenge +// * - Compute remaining two partially evaluated Fold polynomials Fold_{r}^(0) and Fold_{-r}^(0). +// * - Compute and aggregate opening pairs (challenge, evaluation) for each of d Fold polynomials. +// * - Add d-many Fold evaluations a_i, i = 0, ..., d-1 to the transcript, excluding eval of Fold_{r}^(0) +// * */ +// template void UltraHonkProver::execute_pcs_evaluation_round() +// { +// const Fr r_challenge = transcript.get_challenge("Gemini:r"); + +// gemini_output = Gemini::compute_fold_polynomial_evaluations( +// sumcheck_output.challenge_point, std::move(fold_polynomials), r_challenge); + +// for (size_t l = 0; l < key->log_circuit_size; ++l) { +// std::string label = "Gemini:a_" + std::to_string(l); +// const auto& evaluation = gemini_output.opening_pairs[l + 1].evaluation; +// transcript.send_to_verifier(label, evaluation); +// } +// } + +// /** +// * - Do Fiat-Shamir to get "nu" challenge. +// * - Compute commitment [Q]_1 +// * - Do Fiat-Shamir to get "z" challenge. +// * - Compute polynomial Q(X) - Q_z(X) +// * */ +// template void UltraHonkProver::execute_shplonk_round() +// { +// shplonk_output = +// Shplonk::reduce_prove(commitment_key, gemini_output.opening_pairs, gemini_output.witnesses, transcript); +// } + +// /** +// * - Compute KZG quotient commitment [W]_1. +// * +// * */ +// template void UltraHonkProver::execute_kzg_round() +// { +// KZG::reduce_prove(commitment_key, shplonk_output.opening_pair, shplonk_output.witness, transcript); +// } template plonk::proof& UltraHonkProver::export_proof() { @@ -48,6 +266,53 @@ template plonk::proof& UltraHonkProver::export_pro template plonk::proof& UltraHonkProver::construct_proof() { + // // Add circuit size and public input size to transcript. + // execute_preamble_round(); + // // queue.process_queue(); // NOTE: Don't remove; we may reinstate the queue + + // // Compute wire commitments; Add PI to transcript + // execute_wire_commitments_round(); + // // queue.process_queue(); // NOTE: Don't remove; we may reinstate the queue + + // // Currently a no-op; may execute some "random widgets", commit to W_4, do RAM/ROM stuff + // // if this prover structure is kept when we bring tables to Honk. + // // Suggestion: Maybe we shouldn't mix and match proof creation for different systems and + // // instead instatiate construct_proof differently for each? + // execute_tables_round(); + // // queue.process_queue(); // NOTE: Don't remove; we may reinstate the queue + + // // Fiat-Shamir: beta & gamma + // // Compute grand product(s) and commitments. + // execute_grand_product_computation_round(); + // // queue.process_queue(); // NOTE: Don't remove; we may reinstate the queue + + // // Fiat-Shamir: alpha + // // Run sumcheck subprotocol. + // execute_relation_check_rounds(); + // // // queue currently only handles commitments, not partial multivariate evaluations. + // // queue.process_queue(); // NOTE: Don't remove; we may reinstate the queue + + // // Fiat-Shamir: rho + // // Compute Fold polynomials and their commitments. + // execute_univariatization_round(); + // // queue.process_queue(); // NOTE: Don't remove; we may reinstate the queue + + // // Fiat-Shamir: r + // // Compute Fold evaluations + // execute_pcs_evaluation_round(); + + // // Fiat-Shamir: nu + // // Compute Shplonk batched quotient commitment + // execute_shplonk_round(); + // // queue.process_queue(); // NOTE: Don't remove; we may reinstate the queue + + // // Fiat-Shamir: z + // // Compute KZG quotient commitment + // execute_kzg_round(); + // // queue.process_queue(); // NOTE: Don't remove; we may reinstate the queue + + // // queue.flush_queue(); // NOTE: Don't remove; we may reinstate the queue + return export_proof(); } diff --git a/cpp/src/barretenberg/honk/proof_system/ultra_prover.hpp b/cpp/src/barretenberg/honk/proof_system/ultra_prover.hpp index b645e5863f..df80838f64 100644 --- a/cpp/src/barretenberg/honk/proof_system/ultra_prover.hpp +++ b/cpp/src/barretenberg/honk/proof_system/ultra_prover.hpp @@ -27,30 +27,65 @@ namespace proof_system::honk { -// TODO(luke): The naming here is awkward. The Standard Honk prover is called "Prover" and aliased as StandardProver. To -// be consistent with that convention outside of the prover class itself, I've called this class UltraHonkProver and use -// the alias UltraProver externally. Resolve. +// using Fr = barretenberg::fr; +// using Polynomial = Polynomial; + +// TODO(luke): UltraHonkProver is probably bad name but this allows use of UltraProver elsewhere. Resolve. template class UltraHonkProver { using Fr = barretenberg::fr; - using Polynomial = barretenberg::Polynomial; - using Commitment = barretenberg::g1::affine_element; - using POLYNOMIAL = proof_system::honk::StandardArithmetization::POLYNOMIAL; + using Polynomial = Polynomial; public: UltraHonkProver(std::vector&& wire_polys, std::shared_ptr input_key = nullptr); + void execute_preamble_round(); + void execute_wire_commitments_round(); + void execute_tables_round(); + void execute_grand_product_computation_round(); + void execute_relation_check_rounds(); + void execute_univariatization_round(); + void execute_pcs_evaluation_round(); + void execute_shplonk_round(); + void execute_kzg_round(); + + void compute_wire_commitments(); + + void construct_prover_polynomials(); + plonk::proof& export_proof(); plonk::proof& construct_proof(); ProverTranscript transcript; + std::vector public_inputs; + + sumcheck::RelationParameters relation_parameters; + std::vector wire_polynomials; + barretenberg::polynomial z_permutation; std::shared_ptr key; - work_queue queue; + std::shared_ptr commitment_key; + + // Container for spans of all polynomials required by the prover (i.e. all multivariates evaluated by Sumcheck). + std::array, honk::StandardArithmetization::POLYNOMIAL::COUNT> prover_polynomials; + + // Container for d + 1 Fold polynomials produced by Gemini + std::vector fold_polynomials; + + // This makes 'settings' accesible from UltraHonkProver + using settings_ = settings; + + sumcheck::SumcheckOutput sumcheck_output; + pcs::gemini::ProverOutput gemini_output; + pcs::shplonk::ProverOutput shplonk_output; + + using Gemini = pcs::gemini::MultilinearReductionScheme; + using Shplonk = pcs::shplonk::SingleBatchOpeningScheme; + using KZG = pcs::kzg::UnivariateOpeningScheme; private: plonk::proof proof; diff --git a/cpp/src/barretenberg/honk/proof_system/verifier.hpp b/cpp/src/barretenberg/honk/proof_system/verifier.hpp index ed4fe608a1..d26f85819e 100644 --- a/cpp/src/barretenberg/honk/proof_system/verifier.hpp +++ b/cpp/src/barretenberg/honk/proof_system/verifier.hpp @@ -15,6 +15,9 @@ namespace proof_system::honk { template class Verifier { + using Fr = barretenberg::fr; + using Polynomial = Polynomial; + public: Verifier(std::shared_ptr verifier_key = nullptr); Verifier(Verifier&& other); diff --git a/cpp/src/barretenberg/plonk/composer/composer_base.cpp b/cpp/src/barretenberg/plonk/composer/composer_base.cpp index 46e404a57e..6b70ce47dc 100644 --- a/cpp/src/barretenberg/plonk/composer/composer_base.cpp +++ b/cpp/src/barretenberg/plonk/composer/composer_base.cpp @@ -404,6 +404,10 @@ template void ComposerBase::compute_witness_base(const si fr::__copy(get_variable(w_4[i - public_inputs.size()]), w_4_lagrange.at(i)); } + info("Normal: public_inputs.size() = ", public_inputs.size()); + info("Normal: w_l[1] = ", w_l[1]); + info("Normal: w_1_lagrange[1] = ", w_1_lagrange[1]); + circuit_proving_key->polynomial_store.put("w_1_lagrange", std::move(w_1_lagrange)); circuit_proving_key->polynomial_store.put("w_2_lagrange", std::move(w_2_lagrange)); circuit_proving_key->polynomial_store.put("w_3_lagrange", std::move(w_3_lagrange)); @@ -411,6 +415,9 @@ template void ComposerBase::compute_witness_base(const si circuit_proving_key->polynomial_store.put("w_4_lagrange", std::move(w_4_lagrange)); } + info("Normal: polynomial_store.get(w_1_lagrange)[1] = ", + circuit_proving_key->polynomial_store.get("w_1_lagrange")[1]); + computed_witness = true; } diff --git a/cpp/src/barretenberg/plonk/composer/ultra_composer.cpp b/cpp/src/barretenberg/plonk/composer/ultra_composer.cpp index 8782f6ab61..5c9b9b0154 100644 --- a/cpp/src/barretenberg/plonk/composer/ultra_composer.cpp +++ b/cpp/src/barretenberg/plonk/composer/ultra_composer.cpp @@ -719,9 +719,20 @@ void UltraComposer::compute_witness() w_4.emplace_back(zero_idx); } + // info("w_l.size() = ", w_l.size()); + // info("filled_gates = ", filled_gates); + // info("total_num_gates = ", total_num_gates); + // info("subgroup_size = ", subgroup_size); + // info("w_l[2786] = ", w_l[2786]); + // info("w_l[4095] = ", w_l[4095]); + // Create and store polynomials which interpolate the wire values (variable values pointed-to by the `w_`s). ComposerBase::compute_witness_base(total_num_gates); + // info("w_l.size() = ", w_l.size()); + // info("w_l[2786] = ", w_l[2786]); + // info("w_l[4095] = ", w_l[4095]); + polynomial s_1(subgroup_size); polynomial s_2(subgroup_size); polynomial s_3(subgroup_size); diff --git a/cpp/src/barretenberg/proof_system/composer/composer_helper_lib.hpp b/cpp/src/barretenberg/proof_system/composer/composer_helper_lib.hpp index c31dfe13b9..df7f731406 100644 --- a/cpp/src/barretenberg/proof_system/composer/composer_helper_lib.hpp +++ b/cpp/src/barretenberg/proof_system/composer/composer_helper_lib.hpp @@ -114,6 +114,18 @@ std::vector compute_witness_base(const CircuitConstruc const size_t subgroup_size = circuit_constructor.get_circuit_subgroup_size(num_constraints + number_of_randomized_gates); + // // TODO(luke): + // for (size_t i = num_gates; i < subgroup_size; ++i) { + // circuit_constructor.w_l.emplace_back(circuit_constructor.zero_idx); + // circuit_constructor.w_r.emplace_back(circuit_constructor.zero_idx); + // circuit_constructor.w_o.emplace_back(circuit_constructor.zero_idx); + // } + // if (program_width > 3) { + // for (size_t i = num_gates; i < subgroup_size; ++i) { + // circuit_constructor.w_4.emplace_back(circuit_constructor.zero_idx); + // } + // } + // construct a view over all the wire's variable indices // w[j][i] is the index of the variable in the j-th wire, at gate i // Each array should be of size `num_gates` @@ -124,6 +136,10 @@ std::vector compute_witness_base(const CircuitConstruc if constexpr (program_width > 3) { w[3] = circuit_constructor.w_4; } + + info("New: num_public_inputs = ", num_public_inputs); + info("New: w_l[1] = ", circuit_constructor.w_l[1]); + std::vector wires; // Note: randomness is added to 3 of the last 4 positions in plonk/proof_system/prover/prover.cpp // StandardProverBase::execute_preamble_round(). @@ -145,8 +161,12 @@ std::vector compute_witness_base(const CircuitConstruc for (size_t i = 0; i < num_gates; ++i) { w_lagrange[num_public_inputs + i] = circuit_constructor.get_variable(w[j][i]); } + if (j == 0) { + info("New: w_lagrange[1] = ", w_lagrange[1]); + } wires.push_back(std::move(w_lagrange)); } + info("New: wires[0][1] = ", wires[0][1]); return wires; } } // namespace proof_system diff --git a/cpp/src/barretenberg/proof_system/composer/permutation_helper.hpp b/cpp/src/barretenberg/proof_system/composer/permutation_helper.hpp index 9685a3eb29..957f496f2e 100644 --- a/cpp/src/barretenberg/proof_system/composer/permutation_helper.hpp +++ b/cpp/src/barretenberg/proof_system/composer/permutation_helper.hpp @@ -517,14 +517,14 @@ void compute_plonk_generalized_sigma_permutations(const CircuitConstructor& circ * @param key * @return std::array, program_width> */ -// TODO(luke): Consider consolidation of the various "compute sigma permutations" methods which overlap considerably +// TODO(luke): plenty of code duplication involved in this and related methods. Consolidate. template void compute_honk_generalized_sigma_permutations(const CircuitConstructor& circuit_constructor, plonk::proving_key* key) { auto mapping = compute_permutation_mapping(circuit_constructor, key); // Compute Plonk-style sigma and ID polynomials from the corresponding mappings - // TODO(luke): Change these to Honk style! (The only difference is we don't need any fancy coset logic). + // TODO(luke): Change these to Honk style! compute_plonk_permutation_lagrange_polynomials_from_mapping("sigma", mapping.sigmas, key); compute_plonk_permutation_lagrange_polynomials_from_mapping("id", mapping.ids, key); } From bb935341422ae481c58dbe7ee9db23f6b034d909 Mon Sep 17 00:00:00 2001 From: ledwards2225 Date: Mon, 10 Apr 2023 19:28:50 +0000 Subject: [PATCH 02/11] fix gcc build --- .../ultra_honk_composer_helper.cpp | 12 ----------- .../composer/ultra_honk_composer.test.cpp | 5 +---- .../barretenberg/honk/proof_system/prover.hpp | 7 ++++--- .../honk/proof_system/ultra_prover.cpp | 5 ----- .../honk/proof_system/ultra_prover.hpp | 10 +++++----- .../honk/proof_system/verifier.hpp | 3 --- .../plonk/composer/composer_base.cpp | 7 ------- .../plonk/composer/ultra_composer.cpp | 11 ---------- .../composer/composer_helper_lib.hpp | 20 ------------------- .../composer/permutation_helper.hpp | 2 +- 10 files changed, 11 insertions(+), 71 deletions(-) diff --git a/cpp/src/barretenberg/honk/composer/composer_helper/ultra_honk_composer_helper.cpp b/cpp/src/barretenberg/honk/composer/composer_helper/ultra_honk_composer_helper.cpp index 6adafef13f..87916d9d4c 100644 --- a/cpp/src/barretenberg/honk/composer/composer_helper/ultra_honk_composer_helper.cpp +++ b/cpp/src/barretenberg/honk/composer/composer_helper/ultra_honk_composer_helper.cpp @@ -51,22 +51,10 @@ void UltraHonkComposerHelper::compute_witness(CircuitConstru circuit_constructor.w_4.emplace_back(circuit_constructor.zero_idx); } - info("circuit_constructor.w_l.size() = ", circuit_constructor.w_l.size()); - info("filled_gates = ", filled_gates); - info("total_num_gates = ", total_num_gates); - info("subgroup_size = ", subgroup_size); - info("circuit_constructor.w_l[2786] = ", circuit_constructor.w_l[2786]); - // info("circuit_constructor.w_l.end() = ", circuit_constructor.w_l.end()); - // TODO(luke): subgroup size was already computed above but compute_witness_base computes it again. If we pass in // NUM_RANDOMIZED_GATES (as in the other split composers) the resulting sizes can differ. Reconcile this. wire_polynomials = compute_witness_base(circuit_constructor, total_num_gates, NUM_RANDOMIZED_GATES); - info("circuit_constructor.w_l.size() = ", circuit_constructor.w_l.size()); - info("circuit_constructor.w_l[2786] = ", circuit_constructor.w_l[2786]); - info("circuit_constructor.w_l[4095] = ", circuit_constructor.w_l[4095]); - // info("circuit_constructor.w_l.end() = ", circuit_constructor.w_l.end()); - polynomial s_1(subgroup_size); polynomial s_2(subgroup_size); polynomial s_3(subgroup_size); diff --git a/cpp/src/barretenberg/honk/composer/ultra_honk_composer.test.cpp b/cpp/src/barretenberg/honk/composer/ultra_honk_composer.test.cpp index 142562ac98..29f7b26c55 100644 --- a/cpp/src/barretenberg/honk/composer/ultra_honk_composer.test.cpp +++ b/cpp/src/barretenberg/honk/composer/ultra_honk_composer.test.cpp @@ -71,7 +71,6 @@ void check_consistency(honk::UltraProver& honk_prover, plonk::UltraProver& plonk for (auto& entry : honk_store) { std::string key = entry.first; if (plonk_store.contains(key)) { - // info(key); bool polys_equal = (honk_store.get(key) == plonk_store.get(key)); if (polys_equal) { @@ -80,9 +79,6 @@ void check_consistency(honk::UltraProver& honk_prover, plonk::UltraProver& plonk if (!polys_equal) { info("UNEQUAL: ", key); } - // bool size_equal = (honk_store.get(key).size() == plonk_store.get(key).size()); - // if(size_equal) { info("Size Equal: ", key); } - // if(!size_equal) { info("Size UNEQUAL: ", key); } } } @@ -880,6 +876,7 @@ TEST(UltraHonkComposer, rom) auto honk_prover = honk_composer.create_prover(); auto plonk_prover = plonk_composer.create_prover(); + check_consistency(honk_prover, plonk_prover); verify_consistency(honk_prover, plonk_prover); } diff --git a/cpp/src/barretenberg/honk/proof_system/prover.hpp b/cpp/src/barretenberg/honk/proof_system/prover.hpp index 9d47244ce6..2a0e4de314 100644 --- a/cpp/src/barretenberg/honk/proof_system/prover.hpp +++ b/cpp/src/barretenberg/honk/proof_system/prover.hpp @@ -27,10 +27,11 @@ #include "barretenberg/honk/proof_system/work_queue.hpp" namespace proof_system::honk { -template class Prover { - using Fr = barretenberg::fr; - using Polynomial = Polynomial; +using Fr = barretenberg::fr; +using Polynomial = Polynomial; + +template class Prover { public: Prover(std::vector&& wire_polys, std::shared_ptr input_key = nullptr); diff --git a/cpp/src/barretenberg/honk/proof_system/ultra_prover.cpp b/cpp/src/barretenberg/honk/proof_system/ultra_prover.cpp index 2070829c40..1c3f2f6923 100644 --- a/cpp/src/barretenberg/honk/proof_system/ultra_prover.cpp +++ b/cpp/src/barretenberg/honk/proof_system/ultra_prover.cpp @@ -24,11 +24,6 @@ namespace proof_system::honk { -using Fr = barretenberg::fr; -using Commitment = barretenberg::g1::affine_element; -using Polynomial = barretenberg::Polynomial; -using POLYNOMIAL = proof_system::honk::StandardArithmetization::POLYNOMIAL; - /** * Create UltraHonkProver from proving key, witness and manifest. * diff --git a/cpp/src/barretenberg/honk/proof_system/ultra_prover.hpp b/cpp/src/barretenberg/honk/proof_system/ultra_prover.hpp index df80838f64..1372ae6f34 100644 --- a/cpp/src/barretenberg/honk/proof_system/ultra_prover.hpp +++ b/cpp/src/barretenberg/honk/proof_system/ultra_prover.hpp @@ -27,14 +27,14 @@ namespace proof_system::honk { -// using Fr = barretenberg::fr; -// using Polynomial = Polynomial; - -// TODO(luke): UltraHonkProver is probably bad name but this allows use of UltraProver elsewhere. Resolve. +// TODO(luke): UltraHonkProver is bad name but this allows use of UltraProver elsewhere (consistent with +// StandardProver). Resolve. template class UltraHonkProver { using Fr = barretenberg::fr; - using Polynomial = Polynomial; + using Polynomial = barretenberg::Polynomial; + using Commitment = barretenberg::g1::affine_element; + using POLYNOMIAL = proof_system::honk::StandardArithmetization::POLYNOMIAL; public: UltraHonkProver(std::vector&& wire_polys, diff --git a/cpp/src/barretenberg/honk/proof_system/verifier.hpp b/cpp/src/barretenberg/honk/proof_system/verifier.hpp index d26f85819e..ed4fe608a1 100644 --- a/cpp/src/barretenberg/honk/proof_system/verifier.hpp +++ b/cpp/src/barretenberg/honk/proof_system/verifier.hpp @@ -15,9 +15,6 @@ namespace proof_system::honk { template class Verifier { - using Fr = barretenberg::fr; - using Polynomial = Polynomial; - public: Verifier(std::shared_ptr verifier_key = nullptr); Verifier(Verifier&& other); diff --git a/cpp/src/barretenberg/plonk/composer/composer_base.cpp b/cpp/src/barretenberg/plonk/composer/composer_base.cpp index 6b70ce47dc..46e404a57e 100644 --- a/cpp/src/barretenberg/plonk/composer/composer_base.cpp +++ b/cpp/src/barretenberg/plonk/composer/composer_base.cpp @@ -404,10 +404,6 @@ template void ComposerBase::compute_witness_base(const si fr::__copy(get_variable(w_4[i - public_inputs.size()]), w_4_lagrange.at(i)); } - info("Normal: public_inputs.size() = ", public_inputs.size()); - info("Normal: w_l[1] = ", w_l[1]); - info("Normal: w_1_lagrange[1] = ", w_1_lagrange[1]); - circuit_proving_key->polynomial_store.put("w_1_lagrange", std::move(w_1_lagrange)); circuit_proving_key->polynomial_store.put("w_2_lagrange", std::move(w_2_lagrange)); circuit_proving_key->polynomial_store.put("w_3_lagrange", std::move(w_3_lagrange)); @@ -415,9 +411,6 @@ template void ComposerBase::compute_witness_base(const si circuit_proving_key->polynomial_store.put("w_4_lagrange", std::move(w_4_lagrange)); } - info("Normal: polynomial_store.get(w_1_lagrange)[1] = ", - circuit_proving_key->polynomial_store.get("w_1_lagrange")[1]); - computed_witness = true; } diff --git a/cpp/src/barretenberg/plonk/composer/ultra_composer.cpp b/cpp/src/barretenberg/plonk/composer/ultra_composer.cpp index 5c9b9b0154..8782f6ab61 100644 --- a/cpp/src/barretenberg/plonk/composer/ultra_composer.cpp +++ b/cpp/src/barretenberg/plonk/composer/ultra_composer.cpp @@ -719,20 +719,9 @@ void UltraComposer::compute_witness() w_4.emplace_back(zero_idx); } - // info("w_l.size() = ", w_l.size()); - // info("filled_gates = ", filled_gates); - // info("total_num_gates = ", total_num_gates); - // info("subgroup_size = ", subgroup_size); - // info("w_l[2786] = ", w_l[2786]); - // info("w_l[4095] = ", w_l[4095]); - // Create and store polynomials which interpolate the wire values (variable values pointed-to by the `w_`s). ComposerBase::compute_witness_base(total_num_gates); - // info("w_l.size() = ", w_l.size()); - // info("w_l[2786] = ", w_l[2786]); - // info("w_l[4095] = ", w_l[4095]); - polynomial s_1(subgroup_size); polynomial s_2(subgroup_size); polynomial s_3(subgroup_size); diff --git a/cpp/src/barretenberg/proof_system/composer/composer_helper_lib.hpp b/cpp/src/barretenberg/proof_system/composer/composer_helper_lib.hpp index df7f731406..c31dfe13b9 100644 --- a/cpp/src/barretenberg/proof_system/composer/composer_helper_lib.hpp +++ b/cpp/src/barretenberg/proof_system/composer/composer_helper_lib.hpp @@ -114,18 +114,6 @@ std::vector compute_witness_base(const CircuitConstruc const size_t subgroup_size = circuit_constructor.get_circuit_subgroup_size(num_constraints + number_of_randomized_gates); - // // TODO(luke): - // for (size_t i = num_gates; i < subgroup_size; ++i) { - // circuit_constructor.w_l.emplace_back(circuit_constructor.zero_idx); - // circuit_constructor.w_r.emplace_back(circuit_constructor.zero_idx); - // circuit_constructor.w_o.emplace_back(circuit_constructor.zero_idx); - // } - // if (program_width > 3) { - // for (size_t i = num_gates; i < subgroup_size; ++i) { - // circuit_constructor.w_4.emplace_back(circuit_constructor.zero_idx); - // } - // } - // construct a view over all the wire's variable indices // w[j][i] is the index of the variable in the j-th wire, at gate i // Each array should be of size `num_gates` @@ -136,10 +124,6 @@ std::vector compute_witness_base(const CircuitConstruc if constexpr (program_width > 3) { w[3] = circuit_constructor.w_4; } - - info("New: num_public_inputs = ", num_public_inputs); - info("New: w_l[1] = ", circuit_constructor.w_l[1]); - std::vector wires; // Note: randomness is added to 3 of the last 4 positions in plonk/proof_system/prover/prover.cpp // StandardProverBase::execute_preamble_round(). @@ -161,12 +145,8 @@ std::vector compute_witness_base(const CircuitConstruc for (size_t i = 0; i < num_gates; ++i) { w_lagrange[num_public_inputs + i] = circuit_constructor.get_variable(w[j][i]); } - if (j == 0) { - info("New: w_lagrange[1] = ", w_lagrange[1]); - } wires.push_back(std::move(w_lagrange)); } - info("New: wires[0][1] = ", wires[0][1]); return wires; } } // namespace proof_system diff --git a/cpp/src/barretenberg/proof_system/composer/permutation_helper.hpp b/cpp/src/barretenberg/proof_system/composer/permutation_helper.hpp index 957f496f2e..c84f6e0edc 100644 --- a/cpp/src/barretenberg/proof_system/composer/permutation_helper.hpp +++ b/cpp/src/barretenberg/proof_system/composer/permutation_helper.hpp @@ -524,7 +524,7 @@ void compute_honk_generalized_sigma_permutations(const CircuitConstructor& circu auto mapping = compute_permutation_mapping(circuit_constructor, key); // Compute Plonk-style sigma and ID polynomials from the corresponding mappings - // TODO(luke): Change these to Honk style! + // TODO(luke): Change these to Honk style! (The only difference is we don't need any fancy coset logic) compute_plonk_permutation_lagrange_polynomials_from_mapping("sigma", mapping.sigmas, key); compute_plonk_permutation_lagrange_polynomials_from_mapping("id", mapping.ids, key); } From 736636d422da75a404e2d578b3ddaba9a31ca817 Mon Sep 17 00:00:00 2001 From: ledwards2225 Date: Mon, 10 Apr 2023 20:28:49 +0000 Subject: [PATCH 03/11] simplification and comment cleanup --- .../ultra_honk_composer_helper.cpp | 24 +- .../honk/proof_system/ultra_prover.cpp | 264 +----------------- .../honk/proof_system/ultra_prover.hpp | 43 +-- .../composer/permutation_helper.hpp | 4 +- 4 files changed, 19 insertions(+), 316 deletions(-) diff --git a/cpp/src/barretenberg/honk/composer/composer_helper/ultra_honk_composer_helper.cpp b/cpp/src/barretenberg/honk/composer/composer_helper/ultra_honk_composer_helper.cpp index 87916d9d4c..80a0b128ce 100644 --- a/cpp/src/barretenberg/honk/composer/composer_helper/ultra_honk_composer_helper.cpp +++ b/cpp/src/barretenberg/honk/composer/composer_helper/ultra_honk_composer_helper.cpp @@ -15,12 +15,10 @@ namespace proof_system::honk { /** - * @brief Computes `this.witness`, which is basiclly a set of polynomials mapped-to by strings. + * @brief Compute witness polynomials * - * Note: this doesn't actually compute the _entire_ witness. Things missing: randomness for blinding both the wires - and - * sorted `s` poly, lookup rows of the wire witnesses, the values of `z_lookup`, `z`. These are all calculated - * elsewhere. + * TODO(luke): The wire polynomials are returned directly whereas the sorted list polys are added to the proving + * key. This should be made consistent once Cody's Flavor work is settled. */ template void UltraHonkComposerHelper::compute_witness(CircuitConstructor& circuit_constructor) @@ -51,8 +49,11 @@ void UltraHonkComposerHelper::compute_witness(CircuitConstru circuit_constructor.w_4.emplace_back(circuit_constructor.zero_idx); } - // TODO(luke): subgroup size was already computed above but compute_witness_base computes it again. If we pass in - // NUM_RANDOMIZED_GATES (as in the other split composers) the resulting sizes can differ. Reconcile this. + // TODO(luke): within compute_witness_base, the 3rd argument is used in the calculation of the dyadic circuit size + // (subgroup_size). Here (and in other split composers) we're passing in NUM_RANDOMIZED_GATES, but elsewhere, e.g. + // directly above, we use NUM_RESERVED_GATES in a similar role. Therefore, these two constants must be equal for + // everything to be consistent. What we should do is compute the dyadic circuit size once and for all then pass that + // around rather than computing in multiple places. wire_polynomials = compute_witness_base(circuit_constructor, total_num_gates, NUM_RANDOMIZED_GATES); polynomial s_1(subgroup_size); @@ -61,11 +62,9 @@ void UltraHonkComposerHelper::compute_witness(CircuitConstru polynomial s_4(subgroup_size); polynomial z_lookup(subgroup_size + 1); // Only instantiated in this function; nothing assigned. - // Save space for adding random scalars in the s polynomial later. - // The subtracted 1 allows us to insert a `1` at the end, to ensure the evaluations (and hence coefficients) - // aren't - // all 0. - // See ComposerBase::compute_proving_key_base for further explanation, as a similar trick is done there. + // Save space for adding random scalars in the s polynomial later. The subtracted 1 allows us to insert a `1` at the + // end, to ensure the evaluations (and hence coefficients) aren't all 0. See ComposerBase::compute_proving_key_base + // for further explanation, as a similar trick is done there. size_t count = subgroup_size - tables_size - lookups_size - s_randomness - 1; for (size_t i = 0; i < count; ++i) { s_1[i] = 0; @@ -202,7 +201,6 @@ std::shared_ptr UltraHonkComposerHelper: construct_lagrange_selector_forms(circuit_constructor, circuit_proving_key.get()); - // TODO(luke): was there some question as to whether we would take this same strategy for Honk? enforce_nonzero_polynomial_selectors(circuit_constructor, circuit_proving_key.get()); compute_honk_generalized_sigma_permutations(circuit_constructor, diff --git a/cpp/src/barretenberg/honk/proof_system/ultra_prover.cpp b/cpp/src/barretenberg/honk/proof_system/ultra_prover.cpp index 1c3f2f6923..769e744a6d 100644 --- a/cpp/src/barretenberg/honk/proof_system/ultra_prover.cpp +++ b/cpp/src/barretenberg/honk/proof_system/ultra_prover.cpp @@ -37,221 +37,8 @@ UltraHonkProver::UltraHonkProver(std::vector std::shared_ptr input_key) : wire_polynomials(wire_polys) , 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) -{ - // // 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_store.get("q_c_lagrange"); - // prover_polynomials[POLYNOMIAL::Q_L] = key->polynomial_store.get("q_1_lagrange"); - // prover_polynomials[POLYNOMIAL::Q_R] = key->polynomial_store.get("q_2_lagrange"); - // prover_polynomials[POLYNOMIAL::Q_O] = key->polynomial_store.get("q_3_lagrange"); - // prover_polynomials[POLYNOMIAL::Q_M] = key->polynomial_store.get("q_m_lagrange"); - // prover_polynomials[POLYNOMIAL::SIGMA_1] = key->polynomial_store.get("sigma_1_lagrange"); - // prover_polynomials[POLYNOMIAL::SIGMA_2] = key->polynomial_store.get("sigma_2_lagrange"); - // prover_polynomials[POLYNOMIAL::SIGMA_3] = key->polynomial_store.get("sigma_3_lagrange"); - // prover_polynomials[POLYNOMIAL::ID_1] = key->polynomial_store.get("id_1_lagrange"); - // prover_polynomials[POLYNOMIAL::ID_2] = key->polynomial_store.get("id_2_lagrange"); - // prover_polynomials[POLYNOMIAL::ID_3] = key->polynomial_store.get("id_3_lagrange"); - // prover_polynomials[POLYNOMIAL::LAGRANGE_FIRST] = key->polynomial_store.get("L_first_lagrange"); - // prover_polynomials[POLYNOMIAL::LAGRANGE_LAST] = key->polynomial_store.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]; - - // // Add public inputs to transcript from the second wire polynomial - // std::span public_wires_source = prover_polynomials[POLYNOMIAL::W_R]; - - // for (size_t i = 0; i < key->num_public_inputs; ++i) { - // public_inputs.emplace_back(public_wires_source[i]); - // } -} - -// /** -// * - Commit to wires 1,2,3 -// * - Add PI to transcript (I guess PI will stay in w_2 for now?) -// * -// * */ -// template void UltraHonkProver::compute_wire_commitments() -// { -// for (size_t i = 0; i < settings::Arithmetization::num_wires; ++i) { -// auto commitment = commitment_key->commit(wire_polynomials[i]); - -// transcript.send_to_verifier("W_" + std::to_string(i + 1), commitment); -// } -// } - -// /** -// * - Add circuit size, public input size, and public inputs to transcript -// * -// * */ -// template void UltraHonkProver::execute_preamble_round() -// { -// // queue.flush_queue(); // NOTE: Don't remove; we may reinstate the queue - -// const auto circuit_size = static_cast(key->circuit_size); -// const auto num_public_inputs = static_cast(key->num_public_inputs); - -// transcript.send_to_verifier("circuit_size", circuit_size); -// transcript.send_to_verifier("public_input_size", num_public_inputs); - -// for (size_t i = 0; i < key->num_public_inputs; ++i) { -// auto public_input_i = public_inputs[i]; -// transcript.send_to_verifier("public_input_" + std::to_string(i), public_input_i); -// } -// } - -// /** -// * - compute wire commitments -// * */ -// template void UltraHonkProver::execute_wire_commitments_round() -// { -// // queue.flush_queue(); // NOTE: Don't remove; we may reinstate the queue -// compute_wire_commitments(); -// } - -// /** -// * For Standard Honk, this is a non-op (just like for Standard/Turbo Plonk). -// * */ -// template void UltraHonkProver::execute_tables_round() -// { -// // No operations are needed here for Standard Honk -// } - -// /** -// * - Do Fiat-Shamir to get "beta" challenge (Note: gamma = beta^2) -// * - Compute grand product polynomial (permutation only) and commitment -// * */ -// template void UltraHonkProver::execute_grand_product_computation_round() -// { -// // queue.flush_queue(); // NOTE: Don't remove; we may reinstate the queue - -// // Compute and store parameters required by relations in Sumcheck -// auto [beta, gamma] = transcript.get_challenges("beta", "gamma"); - -// auto public_input_delta = compute_public_input_delta(public_inputs, beta, gamma, key->circuit_size); - -// relation_parameters = sumcheck::RelationParameters{ -// .beta = beta, -// .gamma = gamma, -// .public_input_delta = public_input_delta, -// }; - -// z_permutation = -// prover_library::compute_permutation_grand_product(key, wire_polynomials, beta, -// gamma); - -// auto commitment = commitment_key->commit(z_permutation); - -// transcript.send_to_verifier("Z_PERM", commitment); - -// prover_polynomials[POLYNOMIAL::Z_PERM] = z_permutation; -// prover_polynomials[POLYNOMIAL::Z_PERM_SHIFT] = z_permutation.shifted(); -// } - -// /** -// * - Do Fiat-Shamir to get "alpha" challenge -// * - Run Sumcheck resulting in u = (u_1,...,u_d) challenges and all -// * evaluations at u being calculated. -// * */ -// template void UltraHonkProver::execute_relation_check_rounds() -// { -// // queue.flush_queue(); // NOTE: Don't remove; we may reinstate the queue - -// using Sumcheck = sumcheck::Sumcheck, -// sumcheck::ArithmeticRelation, -// sumcheck::GrandProductComputationRelation, -// sumcheck::GrandProductInitializationRelation>; - -// auto sumcheck = Sumcheck(key->circuit_size, transcript); - -// sumcheck_output = sumcheck.execute_prover(prover_polynomials, relation_parameters); -// } - -// /** -// * - Get rho challenge -// * - Compute d+1 Fold polynomials and their evaluations. -// * -// * */ -// template void UltraHonkProver::execute_univariatization_round() -// { -// const size_t NUM_POLYNOMIALS = proof_system::honk::StandardArithmetization::NUM_POLYNOMIALS; -// const size_t NUM_UNSHIFTED_POLYS = proof_system::honk::StandardArithmetization::NUM_UNSHIFTED_POLYNOMIALS; - -// // Generate batching challenge ρ and powers 1,ρ,…,ρᵐ⁻¹ -// Fr rho = transcript.get_challenge("rho"); -// std::vector rhos = Gemini::powers_of_rho(rho, NUM_POLYNOMIALS); - -// // Batch the unshifted polynomials and the to-be-shifted polynomials using ρ -// Polynomial batched_poly_unshifted(key->circuit_size); // batched unshifted polynomials -// for (size_t i = 0; i < NUM_UNSHIFTED_POLYS; ++i) { -// batched_poly_unshifted.add_scaled(prover_polynomials[i], rhos[i]); -// } -// Polynomial batched_poly_to_be_shifted(key->circuit_size); // batched to-be-shifted polynomials -// batched_poly_to_be_shifted.add_scaled(prover_polynomials[POLYNOMIAL::Z_PERM], rhos[NUM_UNSHIFTED_POLYS]); - -// // // Reserve space for d+1 Fold polynomials. At the end of this round, the last d-1 polynomials will -// // // correspond to Fold^(i). At the end of the full Gemini prover protocol, the first two will -// // // be the partially evaluated Fold polynomials Fold_{r}^(0) and Fold_{-r}^(0). -// // fold_polynomials.reserve(key->log_circuit_size + 1); -// // fold_polynomials.emplace_back(batched_poly_unshifted); -// // fold_polynomials.emplace_back(batched_poly_to_be_shifted); - -// // Compute d-1 polynomials Fold^(i), i = 1, ..., d-1. -// fold_polynomials = Gemini::compute_fold_polynomials( -// sumcheck_output.challenge_point, std::move(batched_poly_unshifted), std::move(batched_poly_to_be_shifted)); - -// // Compute and add to trasnscript the commitments [Fold^(i)], i = 1, ..., d-1 -// for (size_t l = 0; l < key->log_circuit_size - 1; ++l) { -// std::string label = "Gemini:FOLD_" + std::to_string(l + 1); -// auto commitment = commitment_key->commit(fold_polynomials[l + 2]); -// transcript.send_to_verifier(label, commitment); -// } -// } - -// /** -// * - Do Fiat-Shamir to get "r" challenge -// * - Compute remaining two partially evaluated Fold polynomials Fold_{r}^(0) and Fold_{-r}^(0). -// * - Compute and aggregate opening pairs (challenge, evaluation) for each of d Fold polynomials. -// * - Add d-many Fold evaluations a_i, i = 0, ..., d-1 to the transcript, excluding eval of Fold_{r}^(0) -// * */ -// template void UltraHonkProver::execute_pcs_evaluation_round() -// { -// const Fr r_challenge = transcript.get_challenge("Gemini:r"); - -// gemini_output = Gemini::compute_fold_polynomial_evaluations( -// sumcheck_output.challenge_point, std::move(fold_polynomials), r_challenge); - -// for (size_t l = 0; l < key->log_circuit_size; ++l) { -// std::string label = "Gemini:a_" + std::to_string(l); -// const auto& evaluation = gemini_output.opening_pairs[l + 1].evaluation; -// transcript.send_to_verifier(label, evaluation); -// } -// } - -// /** -// * - Do Fiat-Shamir to get "nu" challenge. -// * - Compute commitment [Q]_1 -// * - Do Fiat-Shamir to get "z" challenge. -// * - Compute polynomial Q(X) - Q_z(X) -// * */ -// template void UltraHonkProver::execute_shplonk_round() -// { -// shplonk_output = -// Shplonk::reduce_prove(commitment_key, gemini_output.opening_pairs, gemini_output.witnesses, transcript); -// } - -// /** -// * - Compute KZG quotient commitment [W]_1. -// * -// * */ -// template void UltraHonkProver::execute_kzg_round() -// { -// KZG::reduce_prove(commitment_key, shplonk_output.opening_pair, shplonk_output.witness, transcript); -// } + , queue(key, transcript) +{} template plonk::proof& UltraHonkProver::export_proof() { @@ -261,53 +48,6 @@ template plonk::proof& UltraHonkProver::export_pro template plonk::proof& UltraHonkProver::construct_proof() { - // // Add circuit size and public input size to transcript. - // execute_preamble_round(); - // // queue.process_queue(); // NOTE: Don't remove; we may reinstate the queue - - // // Compute wire commitments; Add PI to transcript - // execute_wire_commitments_round(); - // // queue.process_queue(); // NOTE: Don't remove; we may reinstate the queue - - // // Currently a no-op; may execute some "random widgets", commit to W_4, do RAM/ROM stuff - // // if this prover structure is kept when we bring tables to Honk. - // // Suggestion: Maybe we shouldn't mix and match proof creation for different systems and - // // instead instatiate construct_proof differently for each? - // execute_tables_round(); - // // queue.process_queue(); // NOTE: Don't remove; we may reinstate the queue - - // // Fiat-Shamir: beta & gamma - // // Compute grand product(s) and commitments. - // execute_grand_product_computation_round(); - // // queue.process_queue(); // NOTE: Don't remove; we may reinstate the queue - - // // Fiat-Shamir: alpha - // // Run sumcheck subprotocol. - // execute_relation_check_rounds(); - // // // queue currently only handles commitments, not partial multivariate evaluations. - // // queue.process_queue(); // NOTE: Don't remove; we may reinstate the queue - - // // Fiat-Shamir: rho - // // Compute Fold polynomials and their commitments. - // execute_univariatization_round(); - // // queue.process_queue(); // NOTE: Don't remove; we may reinstate the queue - - // // Fiat-Shamir: r - // // Compute Fold evaluations - // execute_pcs_evaluation_round(); - - // // Fiat-Shamir: nu - // // Compute Shplonk batched quotient commitment - // execute_shplonk_round(); - // // queue.process_queue(); // NOTE: Don't remove; we may reinstate the queue - - // // Fiat-Shamir: z - // // Compute KZG quotient commitment - // execute_kzg_round(); - // // queue.process_queue(); // NOTE: Don't remove; we may reinstate the queue - - // // queue.flush_queue(); // NOTE: Don't remove; we may reinstate the queue - return export_proof(); } diff --git a/cpp/src/barretenberg/honk/proof_system/ultra_prover.hpp b/cpp/src/barretenberg/honk/proof_system/ultra_prover.hpp index 1372ae6f34..b645e5863f 100644 --- a/cpp/src/barretenberg/honk/proof_system/ultra_prover.hpp +++ b/cpp/src/barretenberg/honk/proof_system/ultra_prover.hpp @@ -27,8 +27,9 @@ namespace proof_system::honk { -// TODO(luke): UltraHonkProver is bad name but this allows use of UltraProver elsewhere (consistent with -// StandardProver). Resolve. +// TODO(luke): The naming here is awkward. The Standard Honk prover is called "Prover" and aliased as StandardProver. To +// be consistent with that convention outside of the prover class itself, I've called this class UltraHonkProver and use +// the alias UltraProver externally. Resolve. template class UltraHonkProver { using Fr = barretenberg::fr; @@ -40,52 +41,16 @@ template class UltraHonkProver { UltraHonkProver(std::vector&& wire_polys, std::shared_ptr input_key = nullptr); - void execute_preamble_round(); - void execute_wire_commitments_round(); - void execute_tables_round(); - void execute_grand_product_computation_round(); - void execute_relation_check_rounds(); - void execute_univariatization_round(); - void execute_pcs_evaluation_round(); - void execute_shplonk_round(); - void execute_kzg_round(); - - void compute_wire_commitments(); - - void construct_prover_polynomials(); - plonk::proof& export_proof(); plonk::proof& construct_proof(); ProverTranscript transcript; - std::vector public_inputs; - - sumcheck::RelationParameters relation_parameters; - 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, honk::StandardArithmetization::POLYNOMIAL::COUNT> prover_polynomials; - - // Container for d + 1 Fold polynomials produced by Gemini - std::vector fold_polynomials; - - // This makes 'settings' accesible from UltraHonkProver - using settings_ = settings; - - sumcheck::SumcheckOutput sumcheck_output; - pcs::gemini::ProverOutput gemini_output; - pcs::shplonk::ProverOutput shplonk_output; - - using Gemini = pcs::gemini::MultilinearReductionScheme; - using Shplonk = pcs::shplonk::SingleBatchOpeningScheme; - using KZG = pcs::kzg::UnivariateOpeningScheme; + work_queue queue; private: plonk::proof proof; diff --git a/cpp/src/barretenberg/proof_system/composer/permutation_helper.hpp b/cpp/src/barretenberg/proof_system/composer/permutation_helper.hpp index c84f6e0edc..9685a3eb29 100644 --- a/cpp/src/barretenberg/proof_system/composer/permutation_helper.hpp +++ b/cpp/src/barretenberg/proof_system/composer/permutation_helper.hpp @@ -517,14 +517,14 @@ void compute_plonk_generalized_sigma_permutations(const CircuitConstructor& circ * @param key * @return std::array, program_width> */ -// TODO(luke): plenty of code duplication involved in this and related methods. Consolidate. +// TODO(luke): Consider consolidation of the various "compute sigma permutations" methods which overlap considerably template void compute_honk_generalized_sigma_permutations(const CircuitConstructor& circuit_constructor, plonk::proving_key* key) { auto mapping = compute_permutation_mapping(circuit_constructor, key); // Compute Plonk-style sigma and ID polynomials from the corresponding mappings - // TODO(luke): Change these to Honk style! (The only difference is we don't need any fancy coset logic) + // TODO(luke): Change these to Honk style! (The only difference is we don't need any fancy coset logic). compute_plonk_permutation_lagrange_polynomials_from_mapping("sigma", mapping.sigmas, key); compute_plonk_permutation_lagrange_polynomials_from_mapping("id", mapping.ids, key); } From 26c621f5add290883e62caa1ebe3c7e75de3ec8f Mon Sep 17 00:00:00 2001 From: ledwards2225 Date: Mon, 10 Apr 2023 20:39:55 +0000 Subject: [PATCH 04/11] adding issue number to some TODOs --- .../composer_helper/ultra_honk_composer_helper.cpp | 10 +++++----- .../composer_helper/ultra_honk_composer_helper.hpp | 4 ++-- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/cpp/src/barretenberg/honk/composer/composer_helper/ultra_honk_composer_helper.cpp b/cpp/src/barretenberg/honk/composer/composer_helper/ultra_honk_composer_helper.cpp index 80a0b128ce..26b7781bc4 100644 --- a/cpp/src/barretenberg/honk/composer/composer_helper/ultra_honk_composer_helper.cpp +++ b/cpp/src/barretenberg/honk/composer/composer_helper/ultra_honk_composer_helper.cpp @@ -49,11 +49,11 @@ void UltraHonkComposerHelper::compute_witness(CircuitConstru circuit_constructor.w_4.emplace_back(circuit_constructor.zero_idx); } - // TODO(luke): within compute_witness_base, the 3rd argument is used in the calculation of the dyadic circuit size - // (subgroup_size). Here (and in other split composers) we're passing in NUM_RANDOMIZED_GATES, but elsewhere, e.g. - // directly above, we use NUM_RESERVED_GATES in a similar role. Therefore, these two constants must be equal for - // everything to be consistent. What we should do is compute the dyadic circuit size once and for all then pass that - // around rather than computing in multiple places. + // TODO(#340)(luke): within compute_witness_base, the 3rd argument is used in the calculation of the dyadic circuit + // size (subgroup_size). Here (and in other split composers) we're passing in NUM_RANDOMIZED_GATES, but elsewhere, + // e.g. directly above, we use NUM_RESERVED_GATES in a similar role. Therefore, these two constants must be equal + // for everything to be consistent. What we should do is compute the dyadic circuit size once and for all then pass + // that around rather than computing in multiple places. wire_polynomials = compute_witness_base(circuit_constructor, total_num_gates, NUM_RANDOMIZED_GATES); polynomial s_1(subgroup_size); diff --git a/cpp/src/barretenberg/honk/composer/composer_helper/ultra_honk_composer_helper.hpp b/cpp/src/barretenberg/honk/composer/composer_helper/ultra_honk_composer_helper.hpp index b019190e6d..de309735e6 100644 --- a/cpp/src/barretenberg/honk/composer/composer_helper/ultra_honk_composer_helper.hpp +++ b/cpp/src/barretenberg/honk/composer/composer_helper/ultra_honk_composer_helper.hpp @@ -17,8 +17,8 @@ namespace proof_system::honk { // Cody: What does this mean? template class UltraHonkComposerHelper { public: - // TODO(luke): In the split composers, NUM_RANDOMIZED_GATES has replaced NUM_RESERVED_GATES (in some places) to - // determine the next-power-of-2 circuit size. (There are some places in this composer that still use + // TODO(#340)(luke): In the split composers, NUM_RANDOMIZED_GATES has replaced NUM_RESERVED_GATES (in some places) + // to determine the next-power-of-2 circuit size. (There are some places in this composer that still use // NUM_RESERVED_GATES). Therefore for consistency within this composer itself, and consistency with the original // Ultra Composer, this value must match that of NUM_RESERVED_GATES. This issue needs to be reconciled // simultaneously here and in the other split composers. From 8e343cf22f92cffee6909ea9379c8b89ccd0b8cc Mon Sep 17 00:00:00 2001 From: ledwards2225 Date: Tue, 11 Apr 2023 17:51:29 +0000 Subject: [PATCH 05/11] add width 4 perm grand prod construction relation --- cpp/src/barretenberg/honk/flavor/flavor.hpp | 52 ++++++++ .../grand_product_computation_relation.hpp | 87 +++++++++++++ .../honk/sumcheck/relations/relation.hpp | 1 - .../honk/sumcheck/relations/relation.test.cpp | 115 ++++++++++++++---- 4 files changed, 230 insertions(+), 25 deletions(-) diff --git a/cpp/src/barretenberg/honk/flavor/flavor.hpp b/cpp/src/barretenberg/honk/flavor/flavor.hpp index ad47783e1d..fa76fc2f79 100644 --- a/cpp/src/barretenberg/honk/flavor/flavor.hpp +++ b/cpp/src/barretenberg/honk/flavor/flavor.hpp @@ -187,4 +187,56 @@ struct StandardHonk { return output; } }; + +struct UltraArithmetization { + /** + * @brief All of the multivariate polynomials used by the Ultra 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 { + /* --- PRECOMPUTED POLYNOMIALS --- */ + Q_C, + Q_L, + Q_R, + Q_O, + Q_4, + Q_M, + QARITH, + QSORT, + QELLIPTIC, + QAUX, + QLOOKUPTYPE, + SIGMA_1, + SIGMA_2, + SIGMA_3, + SIGMA_4, + ID_1, + ID_2, + ID_3, + ID_4, + LAGRANGE_FIRST, + LAGRANGE_LAST, // = LAGRANGE_N-1 whithout ZK, but can be less + /* --- WITNESS POLYNOMIALS --- */ + W_L, + W_R, + W_O, + W_4, + S_1, + S_2, + S_3, + S_4, + Z_PERM, + Z_LOOKUP, + /* --- SHIFTED POLYNOMIALS --- */ + Z_PERM_SHIFT, + Z_LOOKUP_SHIFT, + /* --- --- */ + COUNT // for programmatic determination of NUM_POLYNOMIALS + }; +}; } // namespace proof_system::honk diff --git a/cpp/src/barretenberg/honk/sumcheck/relations/grand_product_computation_relation.hpp b/cpp/src/barretenberg/honk/sumcheck/relations/grand_product_computation_relation.hpp index 5ecdedf61d..802dd70cd1 100644 --- a/cpp/src/barretenberg/honk/sumcheck/relations/grand_product_computation_relation.hpp +++ b/cpp/src/barretenberg/honk/sumcheck/relations/grand_product_computation_relation.hpp @@ -90,4 +90,91 @@ template class GrandProductComputationRelation { (w_2 + beta * sigma_2 + gamma) * (w_3 + beta * sigma_3 + gamma)); }; }; + +// TODO(luke): With Cody's Flavor work it should be easier to create a simple templated relation +// for handling arbitrary width. For now I'm duplicating the width 3 logic for width 4. +template class GrandProductComputationRelationUltra { + public: + // 1 + polynomial degree of this relation + static constexpr size_t RELATION_LENGTH = 6; + using MULTIVARIATE = proof_system::honk::UltraArithmetization::POLYNOMIAL; + + /** + * @brief Compute contribution of the permutation relation for a given edge (internal function) + * + * @details This the relation confirms faithful calculation of the grand + * product polynomial Z_perm. + * + * @param evals transformed to `evals + C(extended_edges(X)...)*scaling_factor` + * @param extended_edges an std::array containing the fully extended Univariate edges. + * @param parameters contains beta, gamma, and public_input_delta, .... + * @param scaling_factor optional term to scale the evaluation before adding to evals. + */ + inline void add_edge_contribution(Univariate& evals, + const auto& extended_edges, + const RelationParameters& relation_parameters, + const FF& scaling_factor) const + { + const auto& beta = relation_parameters.beta; + const auto& gamma = relation_parameters.gamma; + const auto& public_input_delta = relation_parameters.public_input_delta; + + auto w_1 = UnivariateView(extended_edges[MULTIVARIATE::W_L]); + auto w_2 = UnivariateView(extended_edges[MULTIVARIATE::W_R]); + auto w_3 = UnivariateView(extended_edges[MULTIVARIATE::W_O]); + auto w_4 = UnivariateView(extended_edges[MULTIVARIATE::W_4]); + auto sigma_1 = UnivariateView(extended_edges[MULTIVARIATE::SIGMA_1]); + auto sigma_2 = UnivariateView(extended_edges[MULTIVARIATE::SIGMA_2]); + auto sigma_3 = UnivariateView(extended_edges[MULTIVARIATE::SIGMA_3]); + auto sigma_4 = UnivariateView(extended_edges[MULTIVARIATE::SIGMA_4]); + auto id_1 = UnivariateView(extended_edges[MULTIVARIATE::ID_1]); + auto id_2 = UnivariateView(extended_edges[MULTIVARIATE::ID_2]); + auto id_3 = UnivariateView(extended_edges[MULTIVARIATE::ID_3]); + auto id_4 = UnivariateView(extended_edges[MULTIVARIATE::ID_4]); + auto z_perm = UnivariateView(extended_edges[MULTIVARIATE::Z_PERM]); + auto z_perm_shift = UnivariateView(extended_edges[MULTIVARIATE::Z_PERM_SHIFT]); + auto lagrange_first = UnivariateView(extended_edges[MULTIVARIATE::LAGRANGE_FIRST]); + auto lagrange_last = UnivariateView(extended_edges[MULTIVARIATE::LAGRANGE_LAST]); + + // Contribution (1) + evals += (((z_perm + lagrange_first) * (w_1 + id_1 * beta + gamma) * (w_2 + id_2 * beta + gamma) * + (w_3 + id_3 * beta + gamma) * (w_4 + id_4 * beta + gamma)) - + ((z_perm_shift + lagrange_last * public_input_delta) * (w_1 + sigma_1 * beta + gamma) * + (w_2 + sigma_2 * beta + gamma) * (w_3 + sigma_3 * beta + gamma) * (w_4 + sigma_4 * beta + gamma))) * + scaling_factor; + }; + + void add_full_relation_value_contribution(FF& full_honk_relation_value, + auto& purported_evaluations, + const RelationParameters& relation_parameters) const + { + const auto& beta = relation_parameters.beta; + const auto& gamma = relation_parameters.gamma; + const auto& public_input_delta = relation_parameters.public_input_delta; + + auto w_1 = purported_evaluations[MULTIVARIATE::W_L]; + auto w_2 = purported_evaluations[MULTIVARIATE::W_R]; + auto w_3 = purported_evaluations[MULTIVARIATE::W_O]; + auto w_4 = purported_evaluations[MULTIVARIATE::W_4]; + auto sigma_1 = purported_evaluations[MULTIVARIATE::SIGMA_1]; + auto sigma_2 = purported_evaluations[MULTIVARIATE::SIGMA_2]; + auto sigma_3 = purported_evaluations[MULTIVARIATE::SIGMA_3]; + auto sigma_4 = purported_evaluations[MULTIVARIATE::SIGMA_4]; + auto id_1 = purported_evaluations[MULTIVARIATE::ID_1]; + auto id_2 = purported_evaluations[MULTIVARIATE::ID_2]; + auto id_3 = purported_evaluations[MULTIVARIATE::ID_3]; + auto id_4 = purported_evaluations[MULTIVARIATE::ID_4]; + auto z_perm = purported_evaluations[MULTIVARIATE::Z_PERM]; + auto z_perm_shift = purported_evaluations[MULTIVARIATE::Z_PERM_SHIFT]; + auto lagrange_first = purported_evaluations[MULTIVARIATE::LAGRANGE_FIRST]; + auto lagrange_last = purported_evaluations[MULTIVARIATE::LAGRANGE_LAST]; + + // Contribution (1) + full_honk_relation_value += + ((z_perm + lagrange_first) * (w_1 + beta * id_1 + gamma) * (w_2 + beta * id_2 + gamma) * + (w_3 + beta * id_3 + gamma) * (w_4 + beta * id_4 + gamma) - + (z_perm_shift + lagrange_last * public_input_delta) * (w_1 + beta * sigma_1 + gamma) * + (w_2 + beta * sigma_2 + gamma) * (w_3 + beta * sigma_3 + gamma) * (w_4 + beta * sigma_4 + gamma)); + }; +}; } // namespace proof_system::honk::sumcheck diff --git a/cpp/src/barretenberg/honk/sumcheck/relations/relation.hpp b/cpp/src/barretenberg/honk/sumcheck/relations/relation.hpp index a7860faeeb..e03f09f990 100644 --- a/cpp/src/barretenberg/honk/sumcheck/relations/relation.hpp +++ b/cpp/src/barretenberg/honk/sumcheck/relations/relation.hpp @@ -2,7 +2,6 @@ namespace proof_system::honk::sumcheck { -// TODO(#226)(Adrian): Remove zeta, alpha as they are not used by the relations. template struct RelationParameters { FF beta; FF gamma; diff --git a/cpp/src/barretenberg/honk/sumcheck/relations/relation.test.cpp b/cpp/src/barretenberg/honk/sumcheck/relations/relation.test.cpp index 6b7e1ac521..ca2a7d078e 100644 --- a/cpp/src/barretenberg/honk/sumcheck/relations/relation.test.cpp +++ b/cpp/src/barretenberg/honk/sumcheck/relations/relation.test.cpp @@ -9,6 +9,7 @@ #include "barretenberg/ecc/curves/bn254/fr.hpp" #include "barretenberg/numeric/random/engine.hpp" +#include #include using namespace proof_system::honk::sumcheck; /** @@ -21,9 +22,9 @@ using namespace proof_system::honk::sumcheck; points), * extends them (using barycentric formula) to six evaluation points, and stores them to an array of polynomials. */ -static const size_t input_univariate_length = 2; -static constexpr size_t FULL_RELATION_LENGTH = 5; -static const size_t NUM_POLYNOMIALS = proof_system::honk::StandardArithmetization::NUM_POLYNOMIALS; +static const size_t INPUT_UNIVARIATE_LENGTH = 2; +// static constexpr size_t FULL_RELATION_LENGTH = 5; +// static const size_t NUM_POLYNOMIALS = proof_system::honk::StandardArithmetization::NUM_POLYNOMIALS; namespace proof_system::honk_relation_tests { @@ -35,11 +36,12 @@ template class SumcheckRelation : public testing::Test { // TODO(#225)(Adrian): Accept FULL_RELATION_LENGTH as a template parameter for this function only, so that the test // can decide to which degree the polynomials must be extended. Possible accept an existing list of "edges" and // extend them to the degree. + template static std::array, NUM_POLYNOMIALS> compute_mock_extended_edges( - std::array, NUM_POLYNOMIALS>& input_univariates) + std::array, NUM_POLYNOMIALS>& input_univariates) { - BarycentricData barycentric_2_to_max = - BarycentricData(); + BarycentricData barycentric_2_to_max = + BarycentricData(); std::array, NUM_POLYNOMIALS> extended_univariates; for (size_t i = 0; i < NUM_POLYNOMIALS; ++i) { extended_univariates[i] = barycentric_2_to_max.extend(input_univariates[i]); @@ -136,6 +138,7 @@ template class SumcheckRelation : public testing::Test { * @param extended_edges * @param relation_parameters */ + template static void validate_evaluations( const Univariate& expected_evals, const auto relation, @@ -174,23 +177,27 @@ TYPED_TEST(SumcheckRelation, ArithmeticRelation) { SUMCHECK_RELATION_TYPE_ALIASES using MULTIVARIATE = honk::StandardArithmetization::POLYNOMIAL; + + static constexpr size_t FULL_RELATION_LENGTH = 5; + static const size_t NUM_POLYNOMIALS = proof_system::honk::StandardArithmetization::NUM_POLYNOMIALS; + const auto relation_parameters = TestFixture::compute_mock_relation_parameters(); auto run_test = [&relation_parameters](bool is_random_input) { std::array, NUM_POLYNOMIALS> extended_edges; - std::array, NUM_POLYNOMIALS> input_polynomials; + std::array, NUM_POLYNOMIALS> input_polynomials; if (!is_random_input) { // evaluation form, i.e. input_univariate(0) = 1, input_univariate(1) = 2,.. The polynomial is x+1. for (size_t i = 0; i < NUM_POLYNOMIALS; ++i) { - input_polynomials[i] = Univariate({ 1, 2 }); + input_polynomials[i] = Univariate({ 1, 2 }); } - extended_edges = TestFixture::compute_mock_extended_edges(input_polynomials); + extended_edges = TestFixture::template compute_mock_extended_edges(input_polynomials); } else { // input_univariates are random polynomials of degree one for (size_t i = 0; i < NUM_POLYNOMIALS; ++i) { input_polynomials[i] = - Univariate({ FF::random_element(), FF::random_element() }); + Univariate({ FF::random_element(), FF::random_element() }); } - extended_edges = TestFixture::compute_mock_extended_edges(input_polynomials); + extended_edges = TestFixture::template compute_mock_extended_edges(input_polynomials); }; auto relation = ArithmeticRelation(); // Manually compute the expected edge contribution @@ -207,7 +214,7 @@ TYPED_TEST(SumcheckRelation, ArithmeticRelation) // Ensure that expression changes are detected. // expected_evals, length 4, extends to { { 5, 22, 57, 116, 205} } for input polynomial {1, 2} auto expected_evals = (q_m * w_r * w_l) + (q_r * w_r) + (q_l * w_l) + (q_o * w_o) + (q_c); - TestFixture::validate_evaluations(expected_evals, relation, extended_edges, relation_parameters); + TestFixture::template validate_evaluations(expected_evals, relation, extended_edges, relation_parameters); }; run_test(/* is_random_input=*/true); run_test(/* is_random_input=*/false); @@ -217,23 +224,27 @@ TYPED_TEST(SumcheckRelation, GrandProductComputationRelation) { SUMCHECK_RELATION_TYPE_ALIASES using MULTIVARIATE = honk::StandardArithmetization::POLYNOMIAL; + + static constexpr size_t FULL_RELATION_LENGTH = 5; + static const size_t NUM_POLYNOMIALS = proof_system::honk::StandardArithmetization::NUM_POLYNOMIALS; + const auto relation_parameters = TestFixture::compute_mock_relation_parameters(); auto run_test = [&relation_parameters](bool is_random_input) { std::array, NUM_POLYNOMIALS> extended_edges; - std::array, NUM_POLYNOMIALS> input_polynomials; + std::array, NUM_POLYNOMIALS> input_polynomials; if (!is_random_input) { // evaluation form, i.e. input_univariate(0) = 1, input_univariate(1) = 2,.. The polynomial is x+1. for (size_t i = 0; i < NUM_POLYNOMIALS; ++i) { - input_polynomials[i] = Univariate({ 1, 2 }); + input_polynomials[i] = Univariate({ 1, 2 }); } - extended_edges = TestFixture::compute_mock_extended_edges(input_polynomials); + extended_edges = TestFixture::template compute_mock_extended_edges(input_polynomials); } else { // input_univariates are random polynomials of degree one for (size_t i = 0; i < NUM_POLYNOMIALS; ++i) { input_polynomials[i] = - Univariate({ FF::random_element(), FF::random_element() }); + Univariate({ FF::random_element(), FF::random_element() }); } - extended_edges = TestFixture::compute_mock_extended_edges(input_polynomials); + extended_edges = TestFixture::template compute_mock_extended_edges(input_polynomials); }; auto relation = GrandProductComputationRelation(); @@ -269,7 +280,7 @@ TYPED_TEST(SumcheckRelation, GrandProductComputationRelation) (z_perm_shift + lagrange_last * public_input_delta) * (w_1 + sigma_1 * beta + gamma) * (w_2 + sigma_2 * beta + gamma) * (w_3 + sigma_3 * beta + gamma); - TestFixture::validate_evaluations(expected_evals, relation, extended_edges, relation_parameters); + TestFixture::template validate_evaluations(expected_evals, relation, extended_edges, relation_parameters); }; run_test(/* is_random_input=*/true); run_test(/* is_random_input=*/false); @@ -279,23 +290,27 @@ TYPED_TEST(SumcheckRelation, GrandProductInitializationRelation) { SUMCHECK_RELATION_TYPE_ALIASES using MULTIVARIATE = honk::StandardArithmetization::POLYNOMIAL; + + static constexpr size_t FULL_RELATION_LENGTH = 5; + static const size_t NUM_POLYNOMIALS = proof_system::honk::StandardArithmetization::NUM_POLYNOMIALS; + const auto relation_parameters = TestFixture::compute_mock_relation_parameters(); auto run_test = [&relation_parameters](bool is_random_input) { std::array, NUM_POLYNOMIALS> extended_edges; - std::array, NUM_POLYNOMIALS> input_polynomials; + std::array, NUM_POLYNOMIALS> input_polynomials; if (!is_random_input) { // evaluation form, i.e. input_univariate(0) = 1, input_univariate(1) = 2,.. The polynomial is x+1. for (size_t i = 0; i < NUM_POLYNOMIALS; ++i) { - input_polynomials[i] = Univariate({ 1, 2 }); + input_polynomials[i] = Univariate({ 1, 2 }); } - extended_edges = TestFixture::compute_mock_extended_edges(input_polynomials); + extended_edges = TestFixture::template compute_mock_extended_edges(input_polynomials); } else { // input_univariates are random polynomials of degree one for (size_t i = 0; i < NUM_POLYNOMIALS; ++i) { input_polynomials[i] = - Univariate({ FF::random_element(), FF::random_element() }); + Univariate({ FF::random_element(), FF::random_element() }); } - extended_edges = TestFixture::compute_mock_extended_edges(input_polynomials); + extended_edges = TestFixture::template compute_mock_extended_edges(input_polynomials); }; auto relation = GrandProductInitializationRelation(); const auto& z_perm_shift = extended_edges[MULTIVARIATE::Z_PERM_SHIFT]; @@ -305,10 +320,62 @@ TYPED_TEST(SumcheckRelation, GrandProductInitializationRelation) // expected_evals, lenght 3 (coeff form = x^2 + x), extends to { { 0, 2, 6, 12, 20 } } auto expected_evals = z_perm_shift * lagrange_last; - TestFixture::validate_evaluations(expected_evals, relation, extended_edges, relation_parameters); + TestFixture::template validate_evaluations(expected_evals, relation, extended_edges, relation_parameters); }; run_test(/* is_random_input=*/true); run_test(/* is_random_input=*/false); }; +TYPED_TEST(SumcheckRelation, GrandProductComputationRelationUltra) +{ + SUMCHECK_RELATION_TYPE_ALIASES + using MULTIVARIATE = honk::UltraArithmetization::POLYNOMIAL; + + static constexpr size_t FULL_RELATION_LENGTH = 6; + static const size_t NUM_POLYNOMIALS = proof_system::honk::UltraArithmetization::COUNT; + + const auto relation_parameters = TestFixture::compute_mock_relation_parameters(); + std::array, NUM_POLYNOMIALS> extended_edges; + std::array, NUM_POLYNOMIALS> input_polynomials; + + // input_univariates are random polynomials of degree one + for (size_t i = 0; i < NUM_POLYNOMIALS; ++i) { + input_polynomials[i] = Univariate({ FF::random_element(), FF::random_element() }); + } + extended_edges = TestFixture::template compute_mock_extended_edges(input_polynomials); + + auto relation = GrandProductComputationRelationUltra(); + + const auto& beta = relation_parameters.beta; + const auto& gamma = relation_parameters.gamma; + const auto& public_input_delta = relation_parameters.public_input_delta; + + // Extract the extended edges for manual computation of relation contribution + const auto& w_1 = extended_edges[MULTIVARIATE::W_L]; + const auto& w_2 = extended_edges[MULTIVARIATE::W_R]; + const auto& w_3 = extended_edges[MULTIVARIATE::W_O]; + const auto& w_4 = extended_edges[MULTIVARIATE::W_4]; + const auto& sigma_1 = extended_edges[MULTIVARIATE::SIGMA_1]; + const auto& sigma_2 = extended_edges[MULTIVARIATE::SIGMA_2]; + const auto& sigma_3 = extended_edges[MULTIVARIATE::SIGMA_3]; + const auto& sigma_4 = extended_edges[MULTIVARIATE::SIGMA_4]; + const auto& id_1 = extended_edges[MULTIVARIATE::ID_1]; + const auto& id_2 = extended_edges[MULTIVARIATE::ID_2]; + const auto& id_3 = extended_edges[MULTIVARIATE::ID_3]; + const auto& id_4 = extended_edges[MULTIVARIATE::ID_4]; + const auto& z_perm = extended_edges[MULTIVARIATE::Z_PERM]; + const auto& z_perm_shift = extended_edges[MULTIVARIATE::Z_PERM_SHIFT]; + const auto& lagrange_first = extended_edges[MULTIVARIATE::LAGRANGE_FIRST]; + const auto& lagrange_last = extended_edges[MULTIVARIATE::LAGRANGE_LAST]; + + // Compute the expected result using a simple to read version of the relation expression + auto expected_evals = (z_perm + lagrange_first) * (w_1 + id_1 * beta + gamma) * (w_2 + id_2 * beta + gamma) * + (w_3 + id_3 * beta + gamma) * (w_4 + id_4 * beta + gamma) - + (z_perm_shift + lagrange_last * public_input_delta) * (w_1 + sigma_1 * beta + gamma) * + (w_2 + sigma_2 * beta + gamma) * (w_3 + sigma_3 * beta + gamma) * + (w_4 + sigma_4 * beta + gamma); + + TestFixture::template validate_evaluations(expected_evals, relation, extended_edges, relation_parameters); +}; + } // namespace proof_system::honk_relation_tests From e5ba41063e897e116d1c42daf97853187eaa85c2 Mon Sep 17 00:00:00 2001 From: ledwards2225 Date: Wed, 12 Apr 2023 15:23:34 +0000 Subject: [PATCH 06/11] make grand prod constrution use id polys, relation correctness passing --- .../ultra_honk_composer_helper.cpp | 2 + .../composer/ultra_honk_relations.test.cpp | 235 ++++++++++++++++++ .../honk/proof_system/prover_library.cpp | 10 +- .../honk/proof_system/prover_library.test.cpp | 13 +- .../grand_product_computation_relation.hpp | 49 +++- .../composer/permutation_helper.hpp | 22 +- 6 files changed, 309 insertions(+), 22 deletions(-) create mode 100644 cpp/src/barretenberg/honk/composer/ultra_honk_relations.test.cpp diff --git a/cpp/src/barretenberg/honk/composer/composer_helper/ultra_honk_composer_helper.cpp b/cpp/src/barretenberg/honk/composer/composer_helper/ultra_honk_composer_helper.cpp index 26b7781bc4..47e3393172 100644 --- a/cpp/src/barretenberg/honk/composer/composer_helper/ultra_honk_composer_helper.cpp +++ b/cpp/src/barretenberg/honk/composer/composer_helper/ultra_honk_composer_helper.cpp @@ -206,6 +206,8 @@ std::shared_ptr UltraHonkComposerHelper: compute_honk_generalized_sigma_permutations(circuit_constructor, circuit_proving_key.get()); + compute_first_and_last_lagrange_polynomials(circuit_proving_key.get()); + const size_t subgroup_size = circuit_proving_key->circuit_size; polynomial poly_q_table_column_1(subgroup_size); diff --git a/cpp/src/barretenberg/honk/composer/ultra_honk_relations.test.cpp b/cpp/src/barretenberg/honk/composer/ultra_honk_relations.test.cpp new file mode 100644 index 0000000000..28305ffd0a --- /dev/null +++ b/cpp/src/barretenberg/honk/composer/ultra_honk_relations.test.cpp @@ -0,0 +1,235 @@ +#include "ultra_honk_composer.hpp" +#include "barretenberg/honk/sumcheck/relations/relation.hpp" +#include "barretenberg/numeric/uint256/uint256.hpp" +#include "barretenberg/honk/flavor/flavor.hpp" +#include +#include "barretenberg/honk/proof_system/prover.hpp" +#include "barretenberg/honk/sumcheck/sumcheck_round.hpp" +#include "barretenberg/honk/sumcheck/relations/grand_product_computation_relation.hpp" +#include "barretenberg/honk/sumcheck/relations/grand_product_initialization_relation.hpp" +#include "barretenberg/honk/utils/public_inputs.hpp" + +#include + +using namespace proof_system::honk; + +namespace test_ultra_honk_relations { + +/** + * @brief Check correctness of Ultra Honk relations on a real circuit + * + */ +TEST(UltraHonkRelations, SumcheckRelationCorrectness) +{ + // Create a composer and a dummy circuit with a few gates + auto composer = UltraHonkComposer(); + static const size_t num_wires = 4; + fr a = fr::one(); + // Using the public variable to check that public_input_delta is computed and added to the relation correctly + // TODO(luke): add method "add_public_variable" to UH composer + // uint32_t a_idx = composer.add_public_variable(a); + uint32_t a_idx = composer.add_variable(a); + fr b = fr::one(); + fr c = a + b; + uint32_t b_idx = composer.add_variable(b); + uint32_t c_idx = composer.add_variable(c); + composer.create_add_gate({ a_idx, b_idx, c_idx, fr::one(), fr::one(), fr::neg_one(), fr::zero() }); + + // Create a prover (it will compute proving key and witness) + auto prover = composer.create_prover(); + + // Generate beta and gamma + fr beta = fr::random_element(); + fr gamma = fr::random_element(); + + // Compute public input delta + const auto public_inputs = composer.circuit_constructor.get_public_inputs(); + auto public_input_delta = + honk::compute_public_input_delta(public_inputs, beta, gamma, prover.key->circuit_size); + + sumcheck::RelationParameters params{ + .beta = beta, + .gamma = gamma, + .public_input_delta = public_input_delta, + }; + + constexpr size_t num_polynomials = proof_system::honk::UltraArithmetization::COUNT; + // Compute grand product polynomial + auto z_perm_poly = + prover_library::compute_permutation_grand_product(prover.key, prover.wire_polynomials, beta, gamma); + + // Create an array of spans to the underlying polynomials to more easily + // get the transposition. + // Ex: polynomial_spans[3][i] returns the i-th coefficient of the third polynomial + // in the list below + std::array, num_polynomials> evaluations_array; + + using POLYNOMIAL = proof_system::honk::UltraArithmetization::POLYNOMIAL; + evaluations_array[POLYNOMIAL::W_L] = prover.wire_polynomials[0]; + evaluations_array[POLYNOMIAL::W_R] = prover.wire_polynomials[1]; + evaluations_array[POLYNOMIAL::W_O] = prover.wire_polynomials[2]; + evaluations_array[POLYNOMIAL::W_4] = prover.wire_polynomials[3]; + evaluations_array[POLYNOMIAL::S_1] = prover.key->polynomial_store.get("s_1_lagrange"); + evaluations_array[POLYNOMIAL::S_2] = prover.key->polynomial_store.get("s_2_lagrange"); + evaluations_array[POLYNOMIAL::S_3] = prover.key->polynomial_store.get("s_3_lagrange"); + evaluations_array[POLYNOMIAL::S_4] = prover.key->polynomial_store.get("s_4_lagrange"); + evaluations_array[POLYNOMIAL::Z_PERM] = z_perm_poly; + evaluations_array[POLYNOMIAL::Z_PERM_SHIFT] = z_perm_poly.shifted(); + evaluations_array[POLYNOMIAL::Z_LOOKUP] = z_perm_poly; + evaluations_array[POLYNOMIAL::Z_LOOKUP_SHIFT] = z_perm_poly.shifted(); + evaluations_array[POLYNOMIAL::Q_M] = prover.key->polynomial_store.get("q_m_lagrange"); + evaluations_array[POLYNOMIAL::Q_L] = prover.key->polynomial_store.get("q_1_lagrange"); + evaluations_array[POLYNOMIAL::Q_R] = prover.key->polynomial_store.get("q_2_lagrange"); + evaluations_array[POLYNOMIAL::Q_O] = prover.key->polynomial_store.get("q_3_lagrange"); + evaluations_array[POLYNOMIAL::Q_C] = prover.key->polynomial_store.get("q_c_lagrange"); + evaluations_array[POLYNOMIAL::Q_4] = prover.key->polynomial_store.get("q_4_lagrange"); + evaluations_array[POLYNOMIAL::QARITH] = prover.key->polynomial_store.get("q_arith_lagrange"); + evaluations_array[POLYNOMIAL::QSORT] = prover.key->polynomial_store.get("q_sort_lagrange"); + evaluations_array[POLYNOMIAL::QELLIPTIC] = prover.key->polynomial_store.get("q_elliptic_lagrange"); + evaluations_array[POLYNOMIAL::QAUX] = prover.key->polynomial_store.get("q_aux_lagrange"); + evaluations_array[POLYNOMIAL::QLOOKUPTYPE] = prover.key->polynomial_store.get("table_type_lagrange"); + evaluations_array[POLYNOMIAL::SIGMA_1] = prover.key->polynomial_store.get("sigma_1_lagrange"); + evaluations_array[POLYNOMIAL::SIGMA_2] = prover.key->polynomial_store.get("sigma_2_lagrange"); + evaluations_array[POLYNOMIAL::SIGMA_3] = prover.key->polynomial_store.get("sigma_3_lagrange"); + evaluations_array[POLYNOMIAL::SIGMA_4] = prover.key->polynomial_store.get("sigma_4_lagrange"); + evaluations_array[POLYNOMIAL::ID_1] = prover.key->polynomial_store.get("id_1_lagrange"); + evaluations_array[POLYNOMIAL::ID_2] = prover.key->polynomial_store.get("id_2_lagrange"); + evaluations_array[POLYNOMIAL::ID_3] = prover.key->polynomial_store.get("id_3_lagrange"); + evaluations_array[POLYNOMIAL::ID_4] = prover.key->polynomial_store.get("id_4_lagrange"); + evaluations_array[POLYNOMIAL::LAGRANGE_FIRST] = prover.key->polynomial_store.get("L_first_lagrange"); + evaluations_array[POLYNOMIAL::LAGRANGE_LAST] = prover.key->polynomial_store.get("L_last_lagrange"); + + // Construct the round for applying sumcheck relations and results for storing computed results + auto relations = std::tuple(honk::sumcheck::GrandProductComputationRelationUltra()); + + fr result = 0; + for (size_t i = 0; i < prover.key->circuit_size; i++) { + // Compute an array containing all the evaluations at a given row i + std::array evaluations_at_index_i; + for (size_t j = 0; j < num_polynomials; ++j) { + evaluations_at_index_i[j] = evaluations_array[j][i]; + } + + // For each relation, call the `accumulate_relation_evaluation` over all witness/selector values at the + // i-th row/vertex of the hypercube. + // We use ASSERT_EQ instead of EXPECT_EQ so that the tests stops at the first index at which the result is not + // 0, since result = 0 + C(transposed), which we expect will equal 0. + std::get<0>(relations).add_full_relation_value_contribution(result, evaluations_at_index_i, params); + ASSERT_EQ(result, 0); + } +} + +// /** +// * @brief Check correctness of Ultra Honk relations on a real circuit +// * +// */ +// TEST(UltraHonkRelations, SumcheckRelationCorrectness) +// { +// // Create a composer and a dummy circuit with a few gates +// auto composer = UltraHonkComposer(); +// static const size_t num_wires = 4; +// fr a = fr::one(); +// // Using the public variable to check that public_input_delta is computed and added to the relation correctly +// // TODO(luke): add method "add_public_variable" to UH composer +// // uint32_t a_idx = composer.add_public_variable(a); +// uint32_t a_idx = composer.add_variable(a); +// fr b = fr::one(); +// fr c = a + b; +// fr d = a + c; +// uint32_t b_idx = composer.add_variable(b); +// uint32_t c_idx = composer.add_variable(c); +// uint32_t d_idx = composer.add_variable(d); +// for (size_t i = 0; i < 16; i++) { +// composer.create_add_gate({ a_idx, b_idx, c_idx, fr::one(), fr::one(), fr::neg_one(), fr::zero() }); +// composer.create_add_gate({ d_idx, c_idx, a_idx, fr::one(), fr::neg_one(), fr::neg_one(), fr::zero() }); +// } +// // Create a prover (it will compute proving key and witness) +// auto prover = composer.create_prover(); + +// // Generate beta and gamma +// fr beta = fr::random_element(); +// fr gamma = fr::random_element(); + +// // Compute public input delta +// const auto public_inputs = composer.circuit_constructor.get_public_inputs(); +// auto public_input_delta = +// honk::compute_public_input_delta(public_inputs, beta, gamma, prover.key->circuit_size); + +// info("public_input_delta = ", public_input_delta); + +// sumcheck::RelationParameters params{ +// .beta = beta, +// .gamma = gamma, +// .public_input_delta = public_input_delta, +// }; + +// constexpr size_t num_polynomials = proof_system::honk::UltraArithmetization::COUNT; +// // Compute grand product polynomial +// auto z_perm_poly = +// prover_library::compute_permutation_grand_product(prover.key, prover.wire_polynomials, beta, +// gamma); + +// // Create an array of spans to the underlying polynomials to more easily +// // get the transposition. +// // Ex: polynomial_spans[3][i] returns the i-th coefficient of the third polynomial +// // in the list below +// std::array, num_polynomials> evaluations_array; + +// using POLYNOMIAL = proof_system::honk::UltraArithmetization::POLYNOMIAL; +// evaluations_array[POLYNOMIAL::W_L] = prover.wire_polynomials[0]; +// evaluations_array[POLYNOMIAL::W_R] = prover.wire_polynomials[1]; +// evaluations_array[POLYNOMIAL::W_O] = prover.wire_polynomials[2]; +// evaluations_array[POLYNOMIAL::W_4] = prover.wire_polynomials[3]; +// evaluations_array[POLYNOMIAL::S_1] = prover.key->polynomial_store.get("s_1_lagrange"); +// evaluations_array[POLYNOMIAL::S_2] = prover.key->polynomial_store.get("s_2_lagrange"); +// evaluations_array[POLYNOMIAL::S_3] = prover.key->polynomial_store.get("s_3_lagrange"); +// evaluations_array[POLYNOMIAL::S_4] = prover.key->polynomial_store.get("s_4_lagrange"); +// evaluations_array[POLYNOMIAL::Z_PERM] = z_perm_poly; +// evaluations_array[POLYNOMIAL::Z_PERM_SHIFT] = z_perm_poly.shifted(); +// evaluations_array[POLYNOMIAL::Z_LOOKUP] = z_perm_poly; +// evaluations_array[POLYNOMIAL::Z_LOOKUP_SHIFT] = z_perm_poly.shifted(); +// evaluations_array[POLYNOMIAL::Q_M] = prover.key->polynomial_store.get("q_m_lagrange"); +// evaluations_array[POLYNOMIAL::Q_L] = prover.key->polynomial_store.get("q_1_lagrange"); +// evaluations_array[POLYNOMIAL::Q_R] = prover.key->polynomial_store.get("q_2_lagrange"); +// evaluations_array[POLYNOMIAL::Q_O] = prover.key->polynomial_store.get("q_3_lagrange"); +// evaluations_array[POLYNOMIAL::Q_C] = prover.key->polynomial_store.get("q_c_lagrange"); +// evaluations_array[POLYNOMIAL::Q_4] = prover.key->polynomial_store.get("q_4_lagrange"); +// evaluations_array[POLYNOMIAL::QARITH] = prover.key->polynomial_store.get("q_arith_lagrange"); +// evaluations_array[POLYNOMIAL::QSORT] = prover.key->polynomial_store.get("q_sort_lagrange"); +// evaluations_array[POLYNOMIAL::QELLIPTIC] = prover.key->polynomial_store.get("q_elliptic_lagrange"); +// evaluations_array[POLYNOMIAL::QAUX] = prover.key->polynomial_store.get("q_aux_lagrange"); +// evaluations_array[POLYNOMIAL::QLOOKUPTYPE] = prover.key->polynomial_store.get("table_type_lagrange"); +// evaluations_array[POLYNOMIAL::SIGMA_1] = prover.key->polynomial_store.get("sigma_1_lagrange"); +// evaluations_array[POLYNOMIAL::SIGMA_2] = prover.key->polynomial_store.get("sigma_2_lagrange"); +// evaluations_array[POLYNOMIAL::SIGMA_3] = prover.key->polynomial_store.get("sigma_3_lagrange"); +// evaluations_array[POLYNOMIAL::SIGMA_4] = prover.key->polynomial_store.get("sigma_4_lagrange"); +// evaluations_array[POLYNOMIAL::ID_1] = prover.key->polynomial_store.get("id_1_lagrange"); +// evaluations_array[POLYNOMIAL::ID_2] = prover.key->polynomial_store.get("id_2_lagrange"); +// evaluations_array[POLYNOMIAL::ID_3] = prover.key->polynomial_store.get("id_3_lagrange"); +// evaluations_array[POLYNOMIAL::ID_4] = prover.key->polynomial_store.get("id_4_lagrange"); +// evaluations_array[POLYNOMIAL::LAGRANGE_FIRST] = prover.key->polynomial_store.get("L_first_lagrange"); +// evaluations_array[POLYNOMIAL::LAGRANGE_LAST] = prover.key->polynomial_store.get("L_last_lagrange"); + +// // Construct the round for applying sumcheck relations and results for storing computed results +// auto relations = std::tuple(honk::sumcheck::GrandProductComputationRelationUltra()); + +// fr result = 0; +// for (size_t i = 0; i < prover.key->circuit_size; i++) { +// // Compute an array containing all the evaluations at a given row i +// std::array evaluations_at_index_i; +// for (size_t j = 0; j < num_polynomials; ++j) { +// evaluations_at_index_i[j] = evaluations_array[j][i]; +// } +// info("INDEX = ", i); + +// // For each relation, call the `accumulate_relation_evaluation` over all witness/selector values at the +// // i-th row/vertex of the hypercube. +// // We use ASSERT_EQ instead of EXPECT_EQ so that the tests stops at the first index at which the result is +// not +// // 0, since result = 0 + C(transposed), which we expect will equal 0. +// std::get<0>(relations).add_full_relation_value_contribution(result, evaluations_at_index_i, params); +// ASSERT_EQ(result, 0); +// } +// } + +} // namespace test_ultra_honk_relations diff --git a/cpp/src/barretenberg/honk/proof_system/prover_library.cpp b/cpp/src/barretenberg/honk/proof_system/prover_library.cpp index d99a2947a4..753bee2b92 100644 --- a/cpp/src/barretenberg/honk/proof_system/prover_library.cpp +++ b/cpp/src/barretenberg/honk/proof_system/prover_library.cpp @@ -1,6 +1,7 @@ #include "prover_library.hpp" #include "barretenberg/plonk/proof_system/types/prover_settings.hpp" #include +#include namespace proof_system::honk::prover_library { @@ -55,19 +56,18 @@ Polynomial compute_permutation_grand_product(std::shared_ptr // Populate wire and permutation polynomials std::array, program_width> wires; std::array, program_width> sigmas; + std::array, program_width> ids; for (size_t i = 0; i < program_width; ++i) { - std::string sigma_id = "sigma_" + std::to_string(i + 1) + "_lagrange"; wires[i] = wire_polynomials[i]; - sigmas[i] = key->polynomial_store.get(sigma_id); + sigmas[i] = key->polynomial_store.get("sigma_" + std::to_string(i + 1) + "_lagrange"); + ids[i] = key->polynomial_store.get("id_" + std::to_string(i + 1) + "_lagrange"); } // Step (1) // TODO(#222)(kesha): Change the order to engage automatic prefetching and get rid of redundant computation for (size_t i = 0; i < key->circuit_size; ++i) { for (size_t k = 0; k < program_width; ++k) { - // Note(luke): this idx could be replaced by proper ID polys if desired - Fr idx = k * key->circuit_size + i; - numerator_accumulator[k][i] = wires[k][i] + (idx * beta) + gamma; // w_k(i) + β.(k*n+i) + γ + numerator_accumulator[k][i] = wires[k][i] + (ids[k][i] * beta) + gamma; // w_k(i) + β.id_k(i) + γ denominator_accumulator[k][i] = wires[k][i] + (sigmas[k][i] * beta) + gamma; // w_k(i) + β.σ_k(i) + γ } } diff --git a/cpp/src/barretenberg/honk/proof_system/prover_library.test.cpp b/cpp/src/barretenberg/honk/proof_system/prover_library.test.cpp index 2dd4b77830..f62380ebc9 100644 --- a/cpp/src/barretenberg/honk/proof_system/prover_library.test.cpp +++ b/cpp/src/barretenberg/honk/proof_system/prover_library.test.cpp @@ -59,13 +59,17 @@ template class ProverLibraryTests : public testing::Test { // can simply be random. We're not interested in the particular properties of the result. std::vector wires; std::vector sigmas; + std::vector ids; for (size_t i = 0; i < program_width; ++i) { wires.emplace_back(get_random_polynomial(num_gates)); sigmas.emplace_back(get_random_polynomial(num_gates)); + ids.emplace_back(get_random_polynomial(num_gates)); - // Add sigma polys to proving_key; to be used by the prover in constructing it's own z_perm - std::string sigma_id = "sigma_" + std::to_string(i + 1) + "_lagrange"; - proving_key->polynomial_store.put(sigma_id, Polynomial{ sigmas[i] }); + // Add sigma/ID polys to proving_key; to be used by the prover in constructing it's own z_perm + std::string sigma_label = "sigma_" + std::to_string(i + 1) + "_lagrange"; + proving_key->polynomial_store.put(sigma_label, Polynomial{ sigmas[i] }); + std::string id_label = "id_" + std::to_string(i + 1) + "_lagrange"; + proving_key->polynomial_store.put(id_label, Polynomial{ ids[i] }); } // Get random challenges @@ -108,8 +112,7 @@ template class ProverLibraryTests : public testing::Test { // Step (1) for (size_t i = 0; i < proving_key->circuit_size; ++i) { for (size_t k = 0; k < program_width; ++k) { - FF idx = k * proving_key->circuit_size + i; // id_k[i] - numererator_accum[k][i] = wires[k][i] + (idx * beta) + gamma; // w_k(i) + β.(k*n+i) + γ + numererator_accum[k][i] = wires[k][i] + (ids[k][i] * beta) + gamma; // w_k(i) + β.id_k(i) + γ denominator_accum[k][i] = wires[k][i] + (sigmas[k][i] * beta) + gamma; // w_k(i) + β.σ_k(i) + γ } } diff --git a/cpp/src/barretenberg/honk/sumcheck/relations/grand_product_computation_relation.hpp b/cpp/src/barretenberg/honk/sumcheck/relations/grand_product_computation_relation.hpp index 802dd70cd1..8891d2174a 100644 --- a/cpp/src/barretenberg/honk/sumcheck/relations/grand_product_computation_relation.hpp +++ b/cpp/src/barretenberg/honk/sumcheck/relations/grand_product_computation_relation.hpp @@ -82,6 +82,21 @@ template class GrandProductComputationRelation { auto lagrange_first = purported_evaluations[MULTIVARIATE::LAGRANGE_FIRST]; auto lagrange_last = purported_evaluations[MULTIVARIATE::LAGRANGE_LAST]; + info("public_input_delta = ", public_input_delta); + info("w_1 = ", w_1); + info("w_2 = ", w_2); + info("w_3 = ", w_3); + info("sigma_1 = ", sigma_1); + info("sigma_2 = ", sigma_2); + info("sigma_3 = ", sigma_3); + info("id_1 = ", id_1); + info("id_2 = ", id_2); + info("id_3 = ", id_3); + info("z_perm = ", z_perm); + info("z_perm_shift = ", z_perm_shift); + info("lagrange_first = ", lagrange_first); + info("lagrange_last = ", lagrange_last); + // Contribution (1) full_honk_relation_value += ((z_perm + lagrange_first) * (w_1 + beta * id_1 + gamma) * (w_2 + beta * id_2 + gamma) * @@ -169,12 +184,36 @@ template class GrandProductComputationRelationUltra { auto lagrange_first = purported_evaluations[MULTIVARIATE::LAGRANGE_FIRST]; auto lagrange_last = purported_evaluations[MULTIVARIATE::LAGRANGE_LAST]; + info("w_1 = ", w_1); + info("w_2 = ", w_2); + info("w_3 = ", w_3); + info("w_4 = ", w_4); + info("sigma_1 = ", sigma_1); + info("sigma_2 = ", sigma_2); + info("sigma_3 = ", sigma_3); + info("sigma_4 = ", sigma_4); + info("id_1 = ", id_1); + info("id_2 = ", id_2); + info("id_3 = ", id_3); + info("id_4 = ", id_4); + info("z_perm = ", z_perm); + info("z_perm_shift = ", z_perm_shift); + info("lagrange_first = ", lagrange_first); + info("lagrange_last = ", lagrange_last); + // Contribution (1) - full_honk_relation_value += - ((z_perm + lagrange_first) * (w_1 + beta * id_1 + gamma) * (w_2 + beta * id_2 + gamma) * - (w_3 + beta * id_3 + gamma) * (w_4 + beta * id_4 + gamma) - - (z_perm_shift + lagrange_last * public_input_delta) * (w_1 + beta * sigma_1 + gamma) * - (w_2 + beta * sigma_2 + gamma) * (w_3 + beta * sigma_3 + gamma) * (w_4 + beta * sigma_4 + gamma)); + auto lhs = (z_perm + lagrange_first) * (w_1 + beta * id_1 + gamma) * (w_2 + beta * id_2 + gamma) * + (w_3 + beta * id_3 + gamma) * (w_4 + beta * id_4 + gamma); + auto rhs = (z_perm_shift + lagrange_last * public_input_delta) * (w_1 + beta * sigma_1 + gamma) * + (w_2 + beta * sigma_2 + gamma) * (w_3 + beta * sigma_3 + gamma) * (w_4 + beta * sigma_4 + gamma); + info("lhs = ", lhs); + info("rhs = ", rhs); + full_honk_relation_value += lhs - rhs; + // full_honk_relation_value += + // ((z_perm + lagrange_first) * (w_1 + beta * id_1 + gamma) * (w_2 + beta * id_2 + gamma) * + // (w_3 + beta * id_3 + gamma) * (w_4 + beta * id_4 + gamma) - + // (z_perm_shift + lagrange_last * public_input_delta) * (w_1 + beta * sigma_1 + gamma) * + // (w_2 + beta * sigma_2 + gamma) * (w_3 + beta * sigma_3 + gamma) * (w_4 + beta * sigma_4 + gamma)); }; }; } // namespace proof_system::honk::sumcheck diff --git a/cpp/src/barretenberg/proof_system/composer/permutation_helper.hpp b/cpp/src/barretenberg/proof_system/composer/permutation_helper.hpp index 9685a3eb29..fc6c33f954 100644 --- a/cpp/src/barretenberg/proof_system/composer/permutation_helper.hpp +++ b/cpp/src/barretenberg/proof_system/composer/permutation_helper.hpp @@ -9,6 +9,8 @@ #pragma once #include "barretenberg/ecc/curves/bn254/fr.hpp" +// #include "barretenberg/polynomials/iterate_over_domain.hpp" +#include "barretenberg/polynomials/iterate_over_domain.hpp" #include "barretenberg/polynomials/polynomial.hpp" #include "barretenberg/plonk/proof_system/proving_key/proving_key.hpp" @@ -233,8 +235,10 @@ PermutationMapping compute_permutation_mapping(const CircuitConst * @param key Pointer to the proving key */ template -void compute_honk_style_sigma_lagrange_polynomials_from_mapping( - std::array, program_width>& sigma_mappings, plonk::proving_key* key) +void compute_honk_style_permutation_lagrange_polynomials_from_mapping( + std::string label, + std::array, program_width>& sigma_mappings, + plonk::proving_key* key) { const size_t num_gates = key->circuit_size; @@ -256,8 +260,10 @@ void compute_honk_style_sigma_lagrange_polynomials_from_mapping( // product to be equal to the "public input delta" that is computed in current_sigma_polynomial[i] = -barretenberg::fr(current_mapping.row_index + 1 + num_gates * current_mapping.column_index); + } else if (current_mapping.is_tag) { + // TODO(luke): enough to make these unique values? + current_sigma_polynomial[i] = barretenberg::fr::zero(); } else { - ASSERT(!current_mapping.is_tag); // For the regular permutation we simply point to the next location by setting the evaluation to its // index current_sigma_polynomial[i] = @@ -268,7 +274,7 @@ void compute_honk_style_sigma_lagrange_polynomials_from_mapping( // Save to polynomial cache for (size_t j = 0; j < program_width; j++) { std::string index = std::to_string(j + 1); - key->polynomial_store.put("sigma_" + index + "_lagrange", std::move(sigma[j])); + key->polynomial_store.put(label + "_" + index + "_lagrange", std::move(sigma[j])); } } @@ -447,7 +453,7 @@ void compute_standard_honk_sigma_permutations(CircuitConstructor& circuit_constr // Compute the permutation table specifying which element becomes which auto mapping = compute_permutation_mapping(circuit_constructor, key); // Compute Honk-style sigma polynomial fromt the permutation table - compute_honk_style_sigma_lagrange_polynomials_from_mapping(mapping.sigmas, key); + compute_honk_style_permutation_lagrange_polynomials_from_mapping("sigma", mapping.sigmas, key); } /** @@ -525,8 +531,10 @@ void compute_honk_generalized_sigma_permutations(const CircuitConstructor& circu // Compute Plonk-style sigma and ID polynomials from the corresponding mappings // TODO(luke): Change these to Honk style! (The only difference is we don't need any fancy coset logic). - compute_plonk_permutation_lagrange_polynomials_from_mapping("sigma", mapping.sigmas, key); - compute_plonk_permutation_lagrange_polynomials_from_mapping("id", mapping.ids, key); + compute_honk_style_permutation_lagrange_polynomials_from_mapping("sigma", mapping.sigmas, key); + compute_honk_style_permutation_lagrange_polynomials_from_mapping("id", mapping.ids, key); + // compute_plonk_permutation_lagrange_polynomials_from_mapping("sigma", mapping.sigmas, key); + // compute_plonk_permutation_lagrange_polynomials_from_mapping("id", mapping.ids, key); } } // namespace proof_system From 265e79f8d3a92cb8584125ecbe40483f3a29009a Mon Sep 17 00:00:00 2001 From: ledwards2225 Date: Wed, 12 Apr 2023 16:17:18 +0000 Subject: [PATCH 07/11] reorganize relation testing suites and general cleanup --- .../composer/standard_honk_composer.test.cpp | 103 -------- .../composer/ultra_honk_composer.test.cpp | 5 +- .../composer/ultra_honk_relations.test.cpp | 235 ----------------- .../grand_product_computation_relation.hpp | 49 +--- ...test.cpp => relation_consistency.test.cpp} | 14 +- .../relations/relation_correctness.test.cpp | 241 ++++++++++++++++++ .../composer/permutation_helper.hpp | 37 ++- 7 files changed, 270 insertions(+), 414 deletions(-) delete mode 100644 cpp/src/barretenberg/honk/composer/ultra_honk_relations.test.cpp rename cpp/src/barretenberg/honk/sumcheck/relations/{relation.test.cpp => relation_consistency.test.cpp} (97%) create mode 100644 cpp/src/barretenberg/honk/sumcheck/relations/relation_correctness.test.cpp diff --git a/cpp/src/barretenberg/honk/composer/standard_honk_composer.test.cpp b/cpp/src/barretenberg/honk/composer/standard_honk_composer.test.cpp index 84717e21a4..8ab126ba01 100644 --- a/cpp/src/barretenberg/honk/composer/standard_honk_composer.test.cpp +++ b/cpp/src/barretenberg/honk/composer/standard_honk_composer.test.cpp @@ -304,109 +304,6 @@ TEST(StandardHonkComposer, VerificationKeyCreation) composer.circuit_constructor.selectors.size() + composer.num_wires * 2 + 2); } -/** - * @brief A test taking sumcheck relations and applying them to the witness and selector polynomials to ensure that the - * realtions are correct. - * - * TODO(Kesha): We'll have to update this function once we add zk, since the relation will be incorrect for he first few - * indices - * - */ -TEST(StandardHonkComposer, SumcheckRelationCorrectness) -{ - // Create a composer and a dummy circuit with a few gates - StandardHonkComposer composer = StandardHonkComposer(); - static const size_t num_wires = StandardHonkComposer::num_wires; - fr a = fr::one(); - // Using the public variable to check that public_input_delta is computed and added to the relation correctly - uint32_t a_idx = composer.add_public_variable(a); - fr b = fr::one(); - fr c = a + b; - fr d = a + c; - uint32_t b_idx = composer.add_variable(b); - uint32_t c_idx = composer.add_variable(c); - uint32_t d_idx = composer.add_variable(d); - for (size_t i = 0; i < 16; i++) { - composer.create_add_gate({ a_idx, b_idx, c_idx, fr::one(), fr::one(), fr::neg_one(), fr::zero() }); - composer.create_add_gate({ d_idx, c_idx, a_idx, fr::one(), fr::neg_one(), fr::neg_one(), fr::zero() }); - } - // Create a prover (it will compute proving key and witness) - auto prover = composer.create_prover(); - - // Generate beta and gamma - fr beta = fr::random_element(); - fr gamma = fr::random_element(); - - // Compute public input delta - const auto public_inputs = composer.circuit_constructor.get_public_inputs(); - auto public_input_delta = - honk::compute_public_input_delta(public_inputs, beta, gamma, prover.key->circuit_size); - - sumcheck::RelationParameters params{ - .beta = beta, - .gamma = gamma, - .public_input_delta = public_input_delta, - }; - - constexpr size_t num_polynomials = proof_system::honk::StandardArithmetization::NUM_POLYNOMIALS; - // Compute grand product polynomial - polynomial z_perm_poly = - prover_library::compute_permutation_grand_product(prover.key, prover.wire_polynomials, beta, gamma); - - // Create an array of spans to the underlying polynomials to more easily - // get the transposition. - // Ex: polynomial_spans[3][i] returns the i-th coefficient of the third polynomial - // in the list below - std::array, num_polynomials> evaluations_array; - - using POLYNOMIAL = proof_system::honk::StandardArithmetization::POLYNOMIAL; - evaluations_array[POLYNOMIAL::W_L] = prover.wire_polynomials[0]; - evaluations_array[POLYNOMIAL::W_R] = prover.wire_polynomials[1]; - evaluations_array[POLYNOMIAL::W_O] = prover.wire_polynomials[2]; - evaluations_array[POLYNOMIAL::Z_PERM] = z_perm_poly; - evaluations_array[POLYNOMIAL::Z_PERM_SHIFT] = z_perm_poly.shifted(); - evaluations_array[POLYNOMIAL::Q_M] = prover.key->polynomial_store.get("q_m_lagrange"); - evaluations_array[POLYNOMIAL::Q_L] = prover.key->polynomial_store.get("q_1_lagrange"); - evaluations_array[POLYNOMIAL::Q_R] = prover.key->polynomial_store.get("q_2_lagrange"); - evaluations_array[POLYNOMIAL::Q_O] = prover.key->polynomial_store.get("q_3_lagrange"); - evaluations_array[POLYNOMIAL::Q_C] = prover.key->polynomial_store.get("q_c_lagrange"); - evaluations_array[POLYNOMIAL::SIGMA_1] = prover.key->polynomial_store.get("sigma_1_lagrange"); - evaluations_array[POLYNOMIAL::SIGMA_2] = prover.key->polynomial_store.get("sigma_2_lagrange"); - evaluations_array[POLYNOMIAL::SIGMA_3] = prover.key->polynomial_store.get("sigma_3_lagrange"); - evaluations_array[POLYNOMIAL::ID_1] = prover.key->polynomial_store.get("id_1_lagrange"); - evaluations_array[POLYNOMIAL::ID_2] = prover.key->polynomial_store.get("id_2_lagrange"); - evaluations_array[POLYNOMIAL::ID_3] = prover.key->polynomial_store.get("id_3_lagrange"); - evaluations_array[POLYNOMIAL::LAGRANGE_FIRST] = prover.key->polynomial_store.get("L_first_lagrange"); - evaluations_array[POLYNOMIAL::LAGRANGE_LAST] = prover.key->polynomial_store.get("L_last_lagrange"); - - // Construct the round for applying sumcheck relations and results for storing computed results - auto relations = std::tuple(honk::sumcheck::ArithmeticRelation(), - honk::sumcheck::GrandProductComputationRelation(), - honk::sumcheck::GrandProductInitializationRelation()); - - fr result = 0; - for (size_t i = 0; i < prover.key->circuit_size; i++) { - // Compute an array containing all the evaluations at a given row i - std::array evaluations_at_index_i; - for (size_t j = 0; j < num_polynomials; ++j) { - evaluations_at_index_i[j] = evaluations_array[j][i]; - } - - // For each relation, call the `accumulate_relation_evaluation` over all witness/selector values at the - // i-th row/vertex of the hypercube. - // We use ASSERT_EQ instead of EXPECT_EQ so that the tests stops at the first index at which the result is not - // 0, since result = 0 + C(transposed), which we expect will equal 0. - std::get<0>(relations).add_full_relation_value_contribution(result, evaluations_at_index_i, params); - ASSERT_EQ(result, 0); - - std::get<1>(relations).add_full_relation_value_contribution(result, evaluations_at_index_i, params); - ASSERT_EQ(result, 0); - - std::get<2>(relations).add_full_relation_value_contribution(result, evaluations_at_index_i, params); - ASSERT_EQ(result, 0); - } -} - TEST(StandardHonkComposer, BaseCase) { auto composer = StandardHonkComposer(); diff --git a/cpp/src/barretenberg/honk/composer/ultra_honk_composer.test.cpp b/cpp/src/barretenberg/honk/composer/ultra_honk_composer.test.cpp index 29f7b26c55..708d414ebb 100644 --- a/cpp/src/barretenberg/honk/composer/ultra_honk_composer.test.cpp +++ b/cpp/src/barretenberg/honk/composer/ultra_honk_composer.test.cpp @@ -41,12 +41,13 @@ std::vector add_variables(auto& composer, std::vector variables) */ void verify_consistency(honk::UltraProver& honk_prover, plonk::UltraProver& plonk_prover) { - // Check that all lagrange polys agree + // Check that all lagrange polys agree (except for sigmas/ids which are constructed differently for Honk) auto& honk_store = honk_prover.key->polynomial_store; auto& plonk_store = plonk_prover.key->polynomial_store; for (auto& entry : honk_store) { std::string key = entry.first; - if (plonk_store.contains(key)) { + bool is_not_sigma_or_id = !(key.find("sigma") || key.find("id")); + if (plonk_store.contains(key) && is_not_sigma_or_id) { ASSERT_EQ(honk_store.get(key), plonk_store.get(key)); } } diff --git a/cpp/src/barretenberg/honk/composer/ultra_honk_relations.test.cpp b/cpp/src/barretenberg/honk/composer/ultra_honk_relations.test.cpp deleted file mode 100644 index 28305ffd0a..0000000000 --- a/cpp/src/barretenberg/honk/composer/ultra_honk_relations.test.cpp +++ /dev/null @@ -1,235 +0,0 @@ -#include "ultra_honk_composer.hpp" -#include "barretenberg/honk/sumcheck/relations/relation.hpp" -#include "barretenberg/numeric/uint256/uint256.hpp" -#include "barretenberg/honk/flavor/flavor.hpp" -#include -#include "barretenberg/honk/proof_system/prover.hpp" -#include "barretenberg/honk/sumcheck/sumcheck_round.hpp" -#include "barretenberg/honk/sumcheck/relations/grand_product_computation_relation.hpp" -#include "barretenberg/honk/sumcheck/relations/grand_product_initialization_relation.hpp" -#include "barretenberg/honk/utils/public_inputs.hpp" - -#include - -using namespace proof_system::honk; - -namespace test_ultra_honk_relations { - -/** - * @brief Check correctness of Ultra Honk relations on a real circuit - * - */ -TEST(UltraHonkRelations, SumcheckRelationCorrectness) -{ - // Create a composer and a dummy circuit with a few gates - auto composer = UltraHonkComposer(); - static const size_t num_wires = 4; - fr a = fr::one(); - // Using the public variable to check that public_input_delta is computed and added to the relation correctly - // TODO(luke): add method "add_public_variable" to UH composer - // uint32_t a_idx = composer.add_public_variable(a); - uint32_t a_idx = composer.add_variable(a); - fr b = fr::one(); - fr c = a + b; - uint32_t b_idx = composer.add_variable(b); - uint32_t c_idx = composer.add_variable(c); - composer.create_add_gate({ a_idx, b_idx, c_idx, fr::one(), fr::one(), fr::neg_one(), fr::zero() }); - - // Create a prover (it will compute proving key and witness) - auto prover = composer.create_prover(); - - // Generate beta and gamma - fr beta = fr::random_element(); - fr gamma = fr::random_element(); - - // Compute public input delta - const auto public_inputs = composer.circuit_constructor.get_public_inputs(); - auto public_input_delta = - honk::compute_public_input_delta(public_inputs, beta, gamma, prover.key->circuit_size); - - sumcheck::RelationParameters params{ - .beta = beta, - .gamma = gamma, - .public_input_delta = public_input_delta, - }; - - constexpr size_t num_polynomials = proof_system::honk::UltraArithmetization::COUNT; - // Compute grand product polynomial - auto z_perm_poly = - prover_library::compute_permutation_grand_product(prover.key, prover.wire_polynomials, beta, gamma); - - // Create an array of spans to the underlying polynomials to more easily - // get the transposition. - // Ex: polynomial_spans[3][i] returns the i-th coefficient of the third polynomial - // in the list below - std::array, num_polynomials> evaluations_array; - - using POLYNOMIAL = proof_system::honk::UltraArithmetization::POLYNOMIAL; - evaluations_array[POLYNOMIAL::W_L] = prover.wire_polynomials[0]; - evaluations_array[POLYNOMIAL::W_R] = prover.wire_polynomials[1]; - evaluations_array[POLYNOMIAL::W_O] = prover.wire_polynomials[2]; - evaluations_array[POLYNOMIAL::W_4] = prover.wire_polynomials[3]; - evaluations_array[POLYNOMIAL::S_1] = prover.key->polynomial_store.get("s_1_lagrange"); - evaluations_array[POLYNOMIAL::S_2] = prover.key->polynomial_store.get("s_2_lagrange"); - evaluations_array[POLYNOMIAL::S_3] = prover.key->polynomial_store.get("s_3_lagrange"); - evaluations_array[POLYNOMIAL::S_4] = prover.key->polynomial_store.get("s_4_lagrange"); - evaluations_array[POLYNOMIAL::Z_PERM] = z_perm_poly; - evaluations_array[POLYNOMIAL::Z_PERM_SHIFT] = z_perm_poly.shifted(); - evaluations_array[POLYNOMIAL::Z_LOOKUP] = z_perm_poly; - evaluations_array[POLYNOMIAL::Z_LOOKUP_SHIFT] = z_perm_poly.shifted(); - evaluations_array[POLYNOMIAL::Q_M] = prover.key->polynomial_store.get("q_m_lagrange"); - evaluations_array[POLYNOMIAL::Q_L] = prover.key->polynomial_store.get("q_1_lagrange"); - evaluations_array[POLYNOMIAL::Q_R] = prover.key->polynomial_store.get("q_2_lagrange"); - evaluations_array[POLYNOMIAL::Q_O] = prover.key->polynomial_store.get("q_3_lagrange"); - evaluations_array[POLYNOMIAL::Q_C] = prover.key->polynomial_store.get("q_c_lagrange"); - evaluations_array[POLYNOMIAL::Q_4] = prover.key->polynomial_store.get("q_4_lagrange"); - evaluations_array[POLYNOMIAL::QARITH] = prover.key->polynomial_store.get("q_arith_lagrange"); - evaluations_array[POLYNOMIAL::QSORT] = prover.key->polynomial_store.get("q_sort_lagrange"); - evaluations_array[POLYNOMIAL::QELLIPTIC] = prover.key->polynomial_store.get("q_elliptic_lagrange"); - evaluations_array[POLYNOMIAL::QAUX] = prover.key->polynomial_store.get("q_aux_lagrange"); - evaluations_array[POLYNOMIAL::QLOOKUPTYPE] = prover.key->polynomial_store.get("table_type_lagrange"); - evaluations_array[POLYNOMIAL::SIGMA_1] = prover.key->polynomial_store.get("sigma_1_lagrange"); - evaluations_array[POLYNOMIAL::SIGMA_2] = prover.key->polynomial_store.get("sigma_2_lagrange"); - evaluations_array[POLYNOMIAL::SIGMA_3] = prover.key->polynomial_store.get("sigma_3_lagrange"); - evaluations_array[POLYNOMIAL::SIGMA_4] = prover.key->polynomial_store.get("sigma_4_lagrange"); - evaluations_array[POLYNOMIAL::ID_1] = prover.key->polynomial_store.get("id_1_lagrange"); - evaluations_array[POLYNOMIAL::ID_2] = prover.key->polynomial_store.get("id_2_lagrange"); - evaluations_array[POLYNOMIAL::ID_3] = prover.key->polynomial_store.get("id_3_lagrange"); - evaluations_array[POLYNOMIAL::ID_4] = prover.key->polynomial_store.get("id_4_lagrange"); - evaluations_array[POLYNOMIAL::LAGRANGE_FIRST] = prover.key->polynomial_store.get("L_first_lagrange"); - evaluations_array[POLYNOMIAL::LAGRANGE_LAST] = prover.key->polynomial_store.get("L_last_lagrange"); - - // Construct the round for applying sumcheck relations and results for storing computed results - auto relations = std::tuple(honk::sumcheck::GrandProductComputationRelationUltra()); - - fr result = 0; - for (size_t i = 0; i < prover.key->circuit_size; i++) { - // Compute an array containing all the evaluations at a given row i - std::array evaluations_at_index_i; - for (size_t j = 0; j < num_polynomials; ++j) { - evaluations_at_index_i[j] = evaluations_array[j][i]; - } - - // For each relation, call the `accumulate_relation_evaluation` over all witness/selector values at the - // i-th row/vertex of the hypercube. - // We use ASSERT_EQ instead of EXPECT_EQ so that the tests stops at the first index at which the result is not - // 0, since result = 0 + C(transposed), which we expect will equal 0. - std::get<0>(relations).add_full_relation_value_contribution(result, evaluations_at_index_i, params); - ASSERT_EQ(result, 0); - } -} - -// /** -// * @brief Check correctness of Ultra Honk relations on a real circuit -// * -// */ -// TEST(UltraHonkRelations, SumcheckRelationCorrectness) -// { -// // Create a composer and a dummy circuit with a few gates -// auto composer = UltraHonkComposer(); -// static const size_t num_wires = 4; -// fr a = fr::one(); -// // Using the public variable to check that public_input_delta is computed and added to the relation correctly -// // TODO(luke): add method "add_public_variable" to UH composer -// // uint32_t a_idx = composer.add_public_variable(a); -// uint32_t a_idx = composer.add_variable(a); -// fr b = fr::one(); -// fr c = a + b; -// fr d = a + c; -// uint32_t b_idx = composer.add_variable(b); -// uint32_t c_idx = composer.add_variable(c); -// uint32_t d_idx = composer.add_variable(d); -// for (size_t i = 0; i < 16; i++) { -// composer.create_add_gate({ a_idx, b_idx, c_idx, fr::one(), fr::one(), fr::neg_one(), fr::zero() }); -// composer.create_add_gate({ d_idx, c_idx, a_idx, fr::one(), fr::neg_one(), fr::neg_one(), fr::zero() }); -// } -// // Create a prover (it will compute proving key and witness) -// auto prover = composer.create_prover(); - -// // Generate beta and gamma -// fr beta = fr::random_element(); -// fr gamma = fr::random_element(); - -// // Compute public input delta -// const auto public_inputs = composer.circuit_constructor.get_public_inputs(); -// auto public_input_delta = -// honk::compute_public_input_delta(public_inputs, beta, gamma, prover.key->circuit_size); - -// info("public_input_delta = ", public_input_delta); - -// sumcheck::RelationParameters params{ -// .beta = beta, -// .gamma = gamma, -// .public_input_delta = public_input_delta, -// }; - -// constexpr size_t num_polynomials = proof_system::honk::UltraArithmetization::COUNT; -// // Compute grand product polynomial -// auto z_perm_poly = -// prover_library::compute_permutation_grand_product(prover.key, prover.wire_polynomials, beta, -// gamma); - -// // Create an array of spans to the underlying polynomials to more easily -// // get the transposition. -// // Ex: polynomial_spans[3][i] returns the i-th coefficient of the third polynomial -// // in the list below -// std::array, num_polynomials> evaluations_array; - -// using POLYNOMIAL = proof_system::honk::UltraArithmetization::POLYNOMIAL; -// evaluations_array[POLYNOMIAL::W_L] = prover.wire_polynomials[0]; -// evaluations_array[POLYNOMIAL::W_R] = prover.wire_polynomials[1]; -// evaluations_array[POLYNOMIAL::W_O] = prover.wire_polynomials[2]; -// evaluations_array[POLYNOMIAL::W_4] = prover.wire_polynomials[3]; -// evaluations_array[POLYNOMIAL::S_1] = prover.key->polynomial_store.get("s_1_lagrange"); -// evaluations_array[POLYNOMIAL::S_2] = prover.key->polynomial_store.get("s_2_lagrange"); -// evaluations_array[POLYNOMIAL::S_3] = prover.key->polynomial_store.get("s_3_lagrange"); -// evaluations_array[POLYNOMIAL::S_4] = prover.key->polynomial_store.get("s_4_lagrange"); -// evaluations_array[POLYNOMIAL::Z_PERM] = z_perm_poly; -// evaluations_array[POLYNOMIAL::Z_PERM_SHIFT] = z_perm_poly.shifted(); -// evaluations_array[POLYNOMIAL::Z_LOOKUP] = z_perm_poly; -// evaluations_array[POLYNOMIAL::Z_LOOKUP_SHIFT] = z_perm_poly.shifted(); -// evaluations_array[POLYNOMIAL::Q_M] = prover.key->polynomial_store.get("q_m_lagrange"); -// evaluations_array[POLYNOMIAL::Q_L] = prover.key->polynomial_store.get("q_1_lagrange"); -// evaluations_array[POLYNOMIAL::Q_R] = prover.key->polynomial_store.get("q_2_lagrange"); -// evaluations_array[POLYNOMIAL::Q_O] = prover.key->polynomial_store.get("q_3_lagrange"); -// evaluations_array[POLYNOMIAL::Q_C] = prover.key->polynomial_store.get("q_c_lagrange"); -// evaluations_array[POLYNOMIAL::Q_4] = prover.key->polynomial_store.get("q_4_lagrange"); -// evaluations_array[POLYNOMIAL::QARITH] = prover.key->polynomial_store.get("q_arith_lagrange"); -// evaluations_array[POLYNOMIAL::QSORT] = prover.key->polynomial_store.get("q_sort_lagrange"); -// evaluations_array[POLYNOMIAL::QELLIPTIC] = prover.key->polynomial_store.get("q_elliptic_lagrange"); -// evaluations_array[POLYNOMIAL::QAUX] = prover.key->polynomial_store.get("q_aux_lagrange"); -// evaluations_array[POLYNOMIAL::QLOOKUPTYPE] = prover.key->polynomial_store.get("table_type_lagrange"); -// evaluations_array[POLYNOMIAL::SIGMA_1] = prover.key->polynomial_store.get("sigma_1_lagrange"); -// evaluations_array[POLYNOMIAL::SIGMA_2] = prover.key->polynomial_store.get("sigma_2_lagrange"); -// evaluations_array[POLYNOMIAL::SIGMA_3] = prover.key->polynomial_store.get("sigma_3_lagrange"); -// evaluations_array[POLYNOMIAL::SIGMA_4] = prover.key->polynomial_store.get("sigma_4_lagrange"); -// evaluations_array[POLYNOMIAL::ID_1] = prover.key->polynomial_store.get("id_1_lagrange"); -// evaluations_array[POLYNOMIAL::ID_2] = prover.key->polynomial_store.get("id_2_lagrange"); -// evaluations_array[POLYNOMIAL::ID_3] = prover.key->polynomial_store.get("id_3_lagrange"); -// evaluations_array[POLYNOMIAL::ID_4] = prover.key->polynomial_store.get("id_4_lagrange"); -// evaluations_array[POLYNOMIAL::LAGRANGE_FIRST] = prover.key->polynomial_store.get("L_first_lagrange"); -// evaluations_array[POLYNOMIAL::LAGRANGE_LAST] = prover.key->polynomial_store.get("L_last_lagrange"); - -// // Construct the round for applying sumcheck relations and results for storing computed results -// auto relations = std::tuple(honk::sumcheck::GrandProductComputationRelationUltra()); - -// fr result = 0; -// for (size_t i = 0; i < prover.key->circuit_size; i++) { -// // Compute an array containing all the evaluations at a given row i -// std::array evaluations_at_index_i; -// for (size_t j = 0; j < num_polynomials; ++j) { -// evaluations_at_index_i[j] = evaluations_array[j][i]; -// } -// info("INDEX = ", i); - -// // For each relation, call the `accumulate_relation_evaluation` over all witness/selector values at the -// // i-th row/vertex of the hypercube. -// // We use ASSERT_EQ instead of EXPECT_EQ so that the tests stops at the first index at which the result is -// not -// // 0, since result = 0 + C(transposed), which we expect will equal 0. -// std::get<0>(relations).add_full_relation_value_contribution(result, evaluations_at_index_i, params); -// ASSERT_EQ(result, 0); -// } -// } - -} // namespace test_ultra_honk_relations diff --git a/cpp/src/barretenberg/honk/sumcheck/relations/grand_product_computation_relation.hpp b/cpp/src/barretenberg/honk/sumcheck/relations/grand_product_computation_relation.hpp index 8891d2174a..802dd70cd1 100644 --- a/cpp/src/barretenberg/honk/sumcheck/relations/grand_product_computation_relation.hpp +++ b/cpp/src/barretenberg/honk/sumcheck/relations/grand_product_computation_relation.hpp @@ -82,21 +82,6 @@ template class GrandProductComputationRelation { auto lagrange_first = purported_evaluations[MULTIVARIATE::LAGRANGE_FIRST]; auto lagrange_last = purported_evaluations[MULTIVARIATE::LAGRANGE_LAST]; - info("public_input_delta = ", public_input_delta); - info("w_1 = ", w_1); - info("w_2 = ", w_2); - info("w_3 = ", w_3); - info("sigma_1 = ", sigma_1); - info("sigma_2 = ", sigma_2); - info("sigma_3 = ", sigma_3); - info("id_1 = ", id_1); - info("id_2 = ", id_2); - info("id_3 = ", id_3); - info("z_perm = ", z_perm); - info("z_perm_shift = ", z_perm_shift); - info("lagrange_first = ", lagrange_first); - info("lagrange_last = ", lagrange_last); - // Contribution (1) full_honk_relation_value += ((z_perm + lagrange_first) * (w_1 + beta * id_1 + gamma) * (w_2 + beta * id_2 + gamma) * @@ -184,36 +169,12 @@ template class GrandProductComputationRelationUltra { auto lagrange_first = purported_evaluations[MULTIVARIATE::LAGRANGE_FIRST]; auto lagrange_last = purported_evaluations[MULTIVARIATE::LAGRANGE_LAST]; - info("w_1 = ", w_1); - info("w_2 = ", w_2); - info("w_3 = ", w_3); - info("w_4 = ", w_4); - info("sigma_1 = ", sigma_1); - info("sigma_2 = ", sigma_2); - info("sigma_3 = ", sigma_3); - info("sigma_4 = ", sigma_4); - info("id_1 = ", id_1); - info("id_2 = ", id_2); - info("id_3 = ", id_3); - info("id_4 = ", id_4); - info("z_perm = ", z_perm); - info("z_perm_shift = ", z_perm_shift); - info("lagrange_first = ", lagrange_first); - info("lagrange_last = ", lagrange_last); - // Contribution (1) - auto lhs = (z_perm + lagrange_first) * (w_1 + beta * id_1 + gamma) * (w_2 + beta * id_2 + gamma) * - (w_3 + beta * id_3 + gamma) * (w_4 + beta * id_4 + gamma); - auto rhs = (z_perm_shift + lagrange_last * public_input_delta) * (w_1 + beta * sigma_1 + gamma) * - (w_2 + beta * sigma_2 + gamma) * (w_3 + beta * sigma_3 + gamma) * (w_4 + beta * sigma_4 + gamma); - info("lhs = ", lhs); - info("rhs = ", rhs); - full_honk_relation_value += lhs - rhs; - // full_honk_relation_value += - // ((z_perm + lagrange_first) * (w_1 + beta * id_1 + gamma) * (w_2 + beta * id_2 + gamma) * - // (w_3 + beta * id_3 + gamma) * (w_4 + beta * id_4 + gamma) - - // (z_perm_shift + lagrange_last * public_input_delta) * (w_1 + beta * sigma_1 + gamma) * - // (w_2 + beta * sigma_2 + gamma) * (w_3 + beta * sigma_3 + gamma) * (w_4 + beta * sigma_4 + gamma)); + full_honk_relation_value += + ((z_perm + lagrange_first) * (w_1 + beta * id_1 + gamma) * (w_2 + beta * id_2 + gamma) * + (w_3 + beta * id_3 + gamma) * (w_4 + beta * id_4 + gamma) - + (z_perm_shift + lagrange_last * public_input_delta) * (w_1 + beta * sigma_1 + gamma) * + (w_2 + beta * sigma_2 + gamma) * (w_3 + beta * sigma_3 + gamma) * (w_4 + beta * sigma_4 + gamma)); }; }; } // namespace proof_system::honk::sumcheck diff --git a/cpp/src/barretenberg/honk/sumcheck/relations/relation.test.cpp b/cpp/src/barretenberg/honk/sumcheck/relations/relation_consistency.test.cpp similarity index 97% rename from cpp/src/barretenberg/honk/sumcheck/relations/relation.test.cpp rename to cpp/src/barretenberg/honk/sumcheck/relations/relation_consistency.test.cpp index ca2a7d078e..dd2567d486 100644 --- a/cpp/src/barretenberg/honk/sumcheck/relations/relation.test.cpp +++ b/cpp/src/barretenberg/honk/sumcheck/relations/relation_consistency.test.cpp @@ -23,12 +23,10 @@ using namespace proof_system::honk::sumcheck; * extends them (using barycentric formula) to six evaluation points, and stores them to an array of polynomials. */ static const size_t INPUT_UNIVARIATE_LENGTH = 2; -// static constexpr size_t FULL_RELATION_LENGTH = 5; -// static const size_t NUM_POLYNOMIALS = proof_system::honk::StandardArithmetization::NUM_POLYNOMIALS; namespace proof_system::honk_relation_tests { -template class SumcheckRelation : public testing::Test { +template class RelationConsistency : public testing::Test { public: template using Univariate = Univariate; template using UnivariateView = UnivariateView; @@ -169,11 +167,11 @@ template class SumcheckRelation : public testing::Test { }; }; using FieldTypes = testing::Types; -TYPED_TEST_SUITE(SumcheckRelation, FieldTypes); +TYPED_TEST_SUITE(RelationConsistency, FieldTypes); #define SUMCHECK_RELATION_TYPE_ALIASES using FF = TypeParam; -TYPED_TEST(SumcheckRelation, ArithmeticRelation) +TYPED_TEST(RelationConsistency, ArithmeticRelation) { SUMCHECK_RELATION_TYPE_ALIASES using MULTIVARIATE = honk::StandardArithmetization::POLYNOMIAL; @@ -220,7 +218,7 @@ TYPED_TEST(SumcheckRelation, ArithmeticRelation) run_test(/* is_random_input=*/false); }; -TYPED_TEST(SumcheckRelation, GrandProductComputationRelation) +TYPED_TEST(RelationConsistency, GrandProductComputationRelation) { SUMCHECK_RELATION_TYPE_ALIASES using MULTIVARIATE = honk::StandardArithmetization::POLYNOMIAL; @@ -286,7 +284,7 @@ TYPED_TEST(SumcheckRelation, GrandProductComputationRelation) run_test(/* is_random_input=*/false); }; -TYPED_TEST(SumcheckRelation, GrandProductInitializationRelation) +TYPED_TEST(RelationConsistency, GrandProductInitializationRelation) { SUMCHECK_RELATION_TYPE_ALIASES using MULTIVARIATE = honk::StandardArithmetization::POLYNOMIAL; @@ -326,7 +324,7 @@ TYPED_TEST(SumcheckRelation, GrandProductInitializationRelation) run_test(/* is_random_input=*/false); }; -TYPED_TEST(SumcheckRelation, GrandProductComputationRelationUltra) +TYPED_TEST(RelationConsistency, GrandProductComputationRelationUltra) { SUMCHECK_RELATION_TYPE_ALIASES using MULTIVARIATE = honk::UltraArithmetization::POLYNOMIAL; diff --git a/cpp/src/barretenberg/honk/sumcheck/relations/relation_correctness.test.cpp b/cpp/src/barretenberg/honk/sumcheck/relations/relation_correctness.test.cpp new file mode 100644 index 0000000000..0ec91422a9 --- /dev/null +++ b/cpp/src/barretenberg/honk/sumcheck/relations/relation_correctness.test.cpp @@ -0,0 +1,241 @@ +#include "barretenberg/honk/composer/ultra_honk_composer.hpp" +#include "barretenberg/honk/composer/standard_honk_composer.hpp" +#include "barretenberg/honk/sumcheck/relations/relation.hpp" +#include "barretenberg/numeric/uint256/uint256.hpp" +#include "barretenberg/honk/flavor/flavor.hpp" +#include +#include "barretenberg/honk/proof_system/prover.hpp" +#include "barretenberg/honk/sumcheck/sumcheck_round.hpp" +#include "barretenberg/honk/sumcheck/relations/grand_product_computation_relation.hpp" +#include "barretenberg/honk/sumcheck/relations/grand_product_initialization_relation.hpp" +#include "barretenberg/honk/utils/public_inputs.hpp" + +#include + +using namespace proof_system::honk; + +namespace test_honk_relations { + +/** + * @brief Test the correctness of the Standard Honk rleations + * + * @details Check that the constraints encoded by the relations are satisfied by the polynomials produced by the + * Standard Honk Composer for a real circuit. + * + * TODO(Kesha): We'll have to update this function once we add zk, since the relation will be incorrect for he first few + * indices + * + */ +TEST(RelationCorrectness, StandardRelationCorrectness) +{ + // Create a composer and a dummy circuit with a few gates + auto composer = StandardHonkComposer(); + static const size_t num_wires = StandardHonkComposer::num_wires; + fr a = fr::one(); + // Using the public variable to check that public_input_delta is computed and added to the relation correctly + uint32_t a_idx = composer.add_public_variable(a); + fr b = fr::one(); + fr c = a + b; + fr d = a + c; + uint32_t b_idx = composer.add_variable(b); + uint32_t c_idx = composer.add_variable(c); + uint32_t d_idx = composer.add_variable(d); + for (size_t i = 0; i < 16; i++) { + composer.create_add_gate({ a_idx, b_idx, c_idx, fr::one(), fr::one(), fr::neg_one(), fr::zero() }); + composer.create_add_gate({ d_idx, c_idx, a_idx, fr::one(), fr::neg_one(), fr::neg_one(), fr::zero() }); + } + // Create a prover (it will compute proving key and witness) + auto prover = composer.create_prover(); + + // Generate beta and gamma + fr beta = fr::random_element(); + fr gamma = fr::random_element(); + + // Compute public input delta + const auto public_inputs = composer.circuit_constructor.get_public_inputs(); + auto public_input_delta = + honk::compute_public_input_delta(public_inputs, beta, gamma, prover.key->circuit_size); + + sumcheck::RelationParameters params{ + .beta = beta, + .gamma = gamma, + .public_input_delta = public_input_delta, + }; + + constexpr size_t num_polynomials = proof_system::honk::StandardArithmetization::NUM_POLYNOMIALS; + // Compute grand product polynomial + polynomial z_perm_poly = + prover_library::compute_permutation_grand_product(prover.key, prover.wire_polynomials, beta, gamma); + + // Create an array of spans to the underlying polynomials to more easily + // get the transposition. + // Ex: polynomial_spans[3][i] returns the i-th coefficient of the third polynomial + // in the list below + std::array, num_polynomials> evaluations_array; + + using POLYNOMIAL = proof_system::honk::StandardArithmetization::POLYNOMIAL; + evaluations_array[POLYNOMIAL::W_L] = prover.wire_polynomials[0]; + evaluations_array[POLYNOMIAL::W_R] = prover.wire_polynomials[1]; + evaluations_array[POLYNOMIAL::W_O] = prover.wire_polynomials[2]; + evaluations_array[POLYNOMIAL::Z_PERM] = z_perm_poly; + evaluations_array[POLYNOMIAL::Z_PERM_SHIFT] = z_perm_poly.shifted(); + evaluations_array[POLYNOMIAL::Q_M] = prover.key->polynomial_store.get("q_m_lagrange"); + evaluations_array[POLYNOMIAL::Q_L] = prover.key->polynomial_store.get("q_1_lagrange"); + evaluations_array[POLYNOMIAL::Q_R] = prover.key->polynomial_store.get("q_2_lagrange"); + evaluations_array[POLYNOMIAL::Q_O] = prover.key->polynomial_store.get("q_3_lagrange"); + evaluations_array[POLYNOMIAL::Q_C] = prover.key->polynomial_store.get("q_c_lagrange"); + evaluations_array[POLYNOMIAL::SIGMA_1] = prover.key->polynomial_store.get("sigma_1_lagrange"); + evaluations_array[POLYNOMIAL::SIGMA_2] = prover.key->polynomial_store.get("sigma_2_lagrange"); + evaluations_array[POLYNOMIAL::SIGMA_3] = prover.key->polynomial_store.get("sigma_3_lagrange"); + evaluations_array[POLYNOMIAL::ID_1] = prover.key->polynomial_store.get("id_1_lagrange"); + evaluations_array[POLYNOMIAL::ID_2] = prover.key->polynomial_store.get("id_2_lagrange"); + evaluations_array[POLYNOMIAL::ID_3] = prover.key->polynomial_store.get("id_3_lagrange"); + evaluations_array[POLYNOMIAL::LAGRANGE_FIRST] = prover.key->polynomial_store.get("L_first_lagrange"); + evaluations_array[POLYNOMIAL::LAGRANGE_LAST] = prover.key->polynomial_store.get("L_last_lagrange"); + + // Construct the round for applying sumcheck relations and results for storing computed results + auto relations = std::tuple(honk::sumcheck::ArithmeticRelation(), + honk::sumcheck::GrandProductComputationRelation(), + honk::sumcheck::GrandProductInitializationRelation()); + + fr result = 0; + for (size_t i = 0; i < prover.key->circuit_size; i++) { + // Compute an array containing all the evaluations at a given row i + std::array evaluations_at_index_i; + for (size_t j = 0; j < num_polynomials; ++j) { + evaluations_at_index_i[j] = evaluations_array[j][i]; + } + + // For each relation, call the `accumulate_relation_evaluation` over all witness/selector values at the + // i-th row/vertex of the hypercube. + // We use ASSERT_EQ instead of EXPECT_EQ so that the tests stops at the first index at which the result is not + // 0, since result = 0 + C(transposed), which we expect will equal 0. + std::get<0>(relations).add_full_relation_value_contribution(result, evaluations_at_index_i, params); + ASSERT_EQ(result, 0); + + std::get<1>(relations).add_full_relation_value_contribution(result, evaluations_at_index_i, params); + ASSERT_EQ(result, 0); + + std::get<2>(relations).add_full_relation_value_contribution(result, evaluations_at_index_i, params); + ASSERT_EQ(result, 0); + } +} + +/** + * @brief Test the correctness of the Ultra Honk rleations + * + * @details Check that the constraints encoded by the relations are satisfied by the polynomials produced by the + * Ultra Honk Composer for a real circuit. + * + * TODO(Kesha): We'll have to update this function once we add zk, since the relation will be incorrect for he first few + * indices + * + */ +// NOTE(luke): More relations will be added as they are implemented for Ultra Honk +TEST(RelationCorrectness, UltraRelationCorrectness) +{ + // Create a composer and a dummy circuit with a few gates + auto composer = UltraHonkComposer(); + static const size_t num_wires = 4; + fr a = fr::one(); + // Using the public variable to check that public_input_delta is computed and added to the relation correctly + // TODO(luke): add method "add_public_variable" to UH composer + // uint32_t a_idx = composer.add_public_variable(a); + uint32_t a_idx = composer.add_variable(a); + fr b = fr::one(); + fr c = a + b; + fr d = a + c; + uint32_t b_idx = composer.add_variable(b); + uint32_t c_idx = composer.add_variable(c); + uint32_t d_idx = composer.add_variable(d); + for (size_t i = 0; i < 16; i++) { + composer.create_add_gate({ a_idx, b_idx, c_idx, fr::one(), fr::one(), fr::neg_one(), fr::zero() }); + composer.create_add_gate({ d_idx, c_idx, a_idx, fr::one(), fr::neg_one(), fr::neg_one(), fr::zero() }); + } + // Create a prover (it will compute proving key and witness) + auto prover = composer.create_prover(); + + // Generate beta and gamma + fr beta = fr::random_element(); + fr gamma = fr::random_element(); + + // Compute public input delta + const auto public_inputs = composer.circuit_constructor.get_public_inputs(); + auto public_input_delta = + honk::compute_public_input_delta(public_inputs, beta, gamma, prover.key->circuit_size); + + info("public_input_delta = ", public_input_delta); + + sumcheck::RelationParameters params{ + .beta = beta, + .gamma = gamma, + .public_input_delta = public_input_delta, + }; + + constexpr size_t num_polynomials = proof_system::honk::UltraArithmetization::COUNT; + // Compute grand product polynomial + auto z_perm_poly = + prover_library::compute_permutation_grand_product(prover.key, prover.wire_polynomials, beta, gamma); + + // Create an array of spans to the underlying polynomials to more easily + // get the transposition. + // Ex: polynomial_spans[3][i] returns the i-th coefficient of the third polynomial + // in the list below + std::array, num_polynomials> evaluations_array; + + using POLYNOMIAL = proof_system::honk::UltraArithmetization::POLYNOMIAL; + evaluations_array[POLYNOMIAL::W_L] = prover.wire_polynomials[0]; + evaluations_array[POLYNOMIAL::W_R] = prover.wire_polynomials[1]; + evaluations_array[POLYNOMIAL::W_O] = prover.wire_polynomials[2]; + evaluations_array[POLYNOMIAL::W_4] = prover.wire_polynomials[3]; + evaluations_array[POLYNOMIAL::S_1] = prover.key->polynomial_store.get("s_1_lagrange"); + evaluations_array[POLYNOMIAL::S_2] = prover.key->polynomial_store.get("s_2_lagrange"); + evaluations_array[POLYNOMIAL::S_3] = prover.key->polynomial_store.get("s_3_lagrange"); + evaluations_array[POLYNOMIAL::S_4] = prover.key->polynomial_store.get("s_4_lagrange"); + evaluations_array[POLYNOMIAL::Z_PERM] = z_perm_poly; + evaluations_array[POLYNOMIAL::Z_PERM_SHIFT] = z_perm_poly.shifted(); + evaluations_array[POLYNOMIAL::Z_LOOKUP] = z_perm_poly; + evaluations_array[POLYNOMIAL::Z_LOOKUP_SHIFT] = z_perm_poly.shifted(); + evaluations_array[POLYNOMIAL::Q_M] = prover.key->polynomial_store.get("q_m_lagrange"); + evaluations_array[POLYNOMIAL::Q_L] = prover.key->polynomial_store.get("q_1_lagrange"); + evaluations_array[POLYNOMIAL::Q_R] = prover.key->polynomial_store.get("q_2_lagrange"); + evaluations_array[POLYNOMIAL::Q_O] = prover.key->polynomial_store.get("q_3_lagrange"); + evaluations_array[POLYNOMIAL::Q_C] = prover.key->polynomial_store.get("q_c_lagrange"); + evaluations_array[POLYNOMIAL::Q_4] = prover.key->polynomial_store.get("q_4_lagrange"); + evaluations_array[POLYNOMIAL::QARITH] = prover.key->polynomial_store.get("q_arith_lagrange"); + evaluations_array[POLYNOMIAL::QSORT] = prover.key->polynomial_store.get("q_sort_lagrange"); + evaluations_array[POLYNOMIAL::QELLIPTIC] = prover.key->polynomial_store.get("q_elliptic_lagrange"); + evaluations_array[POLYNOMIAL::QAUX] = prover.key->polynomial_store.get("q_aux_lagrange"); + evaluations_array[POLYNOMIAL::QLOOKUPTYPE] = prover.key->polynomial_store.get("table_type_lagrange"); + evaluations_array[POLYNOMIAL::SIGMA_1] = prover.key->polynomial_store.get("sigma_1_lagrange"); + evaluations_array[POLYNOMIAL::SIGMA_2] = prover.key->polynomial_store.get("sigma_2_lagrange"); + evaluations_array[POLYNOMIAL::SIGMA_3] = prover.key->polynomial_store.get("sigma_3_lagrange"); + evaluations_array[POLYNOMIAL::SIGMA_4] = prover.key->polynomial_store.get("sigma_4_lagrange"); + evaluations_array[POLYNOMIAL::ID_1] = prover.key->polynomial_store.get("id_1_lagrange"); + evaluations_array[POLYNOMIAL::ID_2] = prover.key->polynomial_store.get("id_2_lagrange"); + evaluations_array[POLYNOMIAL::ID_3] = prover.key->polynomial_store.get("id_3_lagrange"); + evaluations_array[POLYNOMIAL::ID_4] = prover.key->polynomial_store.get("id_4_lagrange"); + evaluations_array[POLYNOMIAL::LAGRANGE_FIRST] = prover.key->polynomial_store.get("L_first_lagrange"); + evaluations_array[POLYNOMIAL::LAGRANGE_LAST] = prover.key->polynomial_store.get("L_last_lagrange"); + + // Construct the round for applying sumcheck relations and results for storing computed results + auto relations = std::tuple(honk::sumcheck::GrandProductComputationRelationUltra()); + + fr result = 0; + for (size_t i = 0; i < prover.key->circuit_size; i++) { + // Compute an array containing all the evaluations at a given row i + std::array evaluations_at_index_i; + for (size_t j = 0; j < num_polynomials; ++j) { + evaluations_at_index_i[j] = evaluations_array[j][i]; + } + + // For each relation, call the `accumulate_relation_evaluation` over all witness/selector values at the + // i-th row/vertex of the hypercube. We use ASSERT_EQ instead of EXPECT_EQ so that the tests stops at + // the first index at which the result is not 0, since result = 0 + C(transposed), which we expect will + // equal 0. + std::get<0>(relations).add_full_relation_value_contribution(result, evaluations_at_index_i, params); + ASSERT_EQ(result, 0); + } +} + +} // namespace test_honk_relations diff --git a/cpp/src/barretenberg/proof_system/composer/permutation_helper.hpp b/cpp/src/barretenberg/proof_system/composer/permutation_helper.hpp index fc6c33f954..b5f74894cd 100644 --- a/cpp/src/barretenberg/proof_system/composer/permutation_helper.hpp +++ b/cpp/src/barretenberg/proof_system/composer/permutation_helper.hpp @@ -9,8 +9,6 @@ #pragma once #include "barretenberg/ecc/curves/bn254/fr.hpp" -// #include "barretenberg/polynomials/iterate_over_domain.hpp" -#include "barretenberg/polynomials/iterate_over_domain.hpp" #include "barretenberg/polynomials/polynomial.hpp" #include "barretenberg/plonk/proof_system/proving_key/proving_key.hpp" @@ -224,31 +222,30 @@ PermutationMapping compute_permutation_mapping(const CircuitConst } /** - * @brief Compute Sigma polynomials for Honk from a mapping and put into polynomial cache + * @brief Compute Sigma/ID polynomials for Honk from a mapping and put into polynomial cache * - * @details Given a mapping (effectively at table pointing witnesses to other witnesses) compute Sigma polynomials in - * lagrange form and put them into the cache. This version distinguishes betweenr regular elements and public inputs, - * but ignores tags + * @details Given a mapping (effectively at table pointing witnesses to other witnesses) compute Sigma/ID polynomials in + * lagrange form and put them into the cache. This version is suitable for traditional and generalized permutations. * * @tparam program_width The number of wires - * @param sigma_mappings A table with information about permuting each element + * @param permutation_mappings A table with information about permuting each element * @param key Pointer to the proving key */ template void compute_honk_style_permutation_lagrange_polynomials_from_mapping( std::string label, - std::array, program_width>& sigma_mappings, + std::array, program_width>& permutation_mappings, plonk::proving_key* key) { const size_t num_gates = key->circuit_size; - std::array sigma; + std::array permutation_poly; // sigma or ID poly for (size_t wire_index = 0; wire_index < program_width; wire_index++) { - sigma[wire_index] = barretenberg::polynomial(num_gates); - auto& current_sigma_polynomial = sigma[wire_index]; + permutation_poly[wire_index] = barretenberg::polynomial(num_gates); + auto& current_permutation_poly = permutation_poly[wire_index]; ITERATE_OVER_DOMAIN_START(key->small_domain) - const auto& current_mapping = sigma_mappings[wire_index][i]; + const auto& current_mapping = permutation_mappings[wire_index][i]; if (current_mapping.is_public_input) { // We intentionally want to break the cycles of the public input variables. // During the witness generation, the left and right wire polynomials at index i contain the i-th public @@ -258,15 +255,15 @@ void compute_honk_style_permutation_lagrange_polynomials_from_mapping( // -(i+1) -> (n+i) // These indices are chosen so they can easily be computed by the verifier. They can expect the running // product to be equal to the "public input delta" that is computed in - current_sigma_polynomial[i] = + current_permutation_poly[i] = -barretenberg::fr(current_mapping.row_index + 1 + num_gates * current_mapping.column_index); } else if (current_mapping.is_tag) { - // TODO(luke): enough to make these unique values? - current_sigma_polynomial[i] = barretenberg::fr::zero(); + // TODO(luke): enough to simply make these disjoint from non-tag values? + current_permutation_poly[i] = barretenberg::fr::zero(); } else { // For the regular permutation we simply point to the next location by setting the evaluation to its // index - current_sigma_polynomial[i] = + current_permutation_poly[i] = barretenberg::fr(current_mapping.row_index + num_gates * current_mapping.column_index); } ITERATE_OVER_DOMAIN_END; @@ -274,7 +271,7 @@ void compute_honk_style_permutation_lagrange_polynomials_from_mapping( // Save to polynomial cache for (size_t j = 0; j < program_width; j++) { std::string index = std::to_string(j + 1); - key->polynomial_store.put(label + "_" + index + "_lagrange", std::move(sigma[j])); + key->polynomial_store.put(label + "_" + index + "_lagrange", std::move(permutation_poly[j])); } } @@ -523,18 +520,14 @@ void compute_plonk_generalized_sigma_permutations(const CircuitConstructor& circ * @param key * @return std::array, program_width> */ -// TODO(luke): Consider consolidation of the various "compute sigma permutations" methods which overlap considerably template void compute_honk_generalized_sigma_permutations(const CircuitConstructor& circuit_constructor, plonk::proving_key* key) { auto mapping = compute_permutation_mapping(circuit_constructor, key); - // Compute Plonk-style sigma and ID polynomials from the corresponding mappings - // TODO(luke): Change these to Honk style! (The only difference is we don't need any fancy coset logic). + // Compute Honk-style sigma and ID polynomials from the corresponding mappings compute_honk_style_permutation_lagrange_polynomials_from_mapping("sigma", mapping.sigmas, key); compute_honk_style_permutation_lagrange_polynomials_from_mapping("id", mapping.ids, key); - // compute_plonk_permutation_lagrange_polynomials_from_mapping("sigma", mapping.sigmas, key); - // compute_plonk_permutation_lagrange_polynomials_from_mapping("id", mapping.ids, key); } } // namespace proof_system From bd1005e841bab45f5e53efa479505b58542ec075 Mon Sep 17 00:00:00 2001 From: ledwards2225 Date: Wed, 12 Apr 2023 20:38:10 +0000 Subject: [PATCH 08/11] primary ultra arithmetic relation with passing tests --- .../ultra_honk_composer_helper.cpp | 4 +- .../composer/ultra_honk_composer.test.cpp | 10 ++- cpp/src/barretenberg/honk/flavor/flavor.hpp | 1 + .../relations/relation_consistency.test.cpp | 45 ++++++++++ .../relations/relation_correctness.test.cpp | 11 ++- .../relations/ultra_arithmetic_relation.hpp | 87 +++++++++++++++++++ 6 files changed, 153 insertions(+), 5 deletions(-) create mode 100644 cpp/src/barretenberg/honk/sumcheck/relations/ultra_arithmetic_relation.hpp diff --git a/cpp/src/barretenberg/honk/composer/composer_helper/ultra_honk_composer_helper.cpp b/cpp/src/barretenberg/honk/composer/composer_helper/ultra_honk_composer_helper.cpp index 47e3393172..1ef6fdcba0 100644 --- a/cpp/src/barretenberg/honk/composer/composer_helper/ultra_honk_composer_helper.cpp +++ b/cpp/src/barretenberg/honk/composer/composer_helper/ultra_honk_composer_helper.cpp @@ -201,7 +201,9 @@ std::shared_ptr UltraHonkComposerHelper: construct_lagrange_selector_forms(circuit_constructor, circuit_proving_key.get()); - enforce_nonzero_polynomial_selectors(circuit_constructor, circuit_proving_key.get()); + // TODO(#217)(luke): Naively enforcing non-zero selectors for Honk will result in some relations not being + // satisfied. + // enforce_nonzero_polynomial_selectors(circuit_constructor, circuit_proving_key.get()); compute_honk_generalized_sigma_permutations(circuit_constructor, circuit_proving_key.get()); diff --git a/cpp/src/barretenberg/honk/composer/ultra_honk_composer.test.cpp b/cpp/src/barretenberg/honk/composer/ultra_honk_composer.test.cpp index 708d414ebb..1664ec5520 100644 --- a/cpp/src/barretenberg/honk/composer/ultra_honk_composer.test.cpp +++ b/cpp/src/barretenberg/honk/composer/ultra_honk_composer.test.cpp @@ -39,6 +39,9 @@ std::vector add_variables(auto& composer, std::vector variables) * @param honk_prover * @param plonk_prover */ +// NOTE: Currently only checking witness polynomials (wires, sorted lists) and table polys. The permutation polys +// are computed differently between plonk and honk and we do not enforce non-zero selectors in Honk so the final +// element will disagree. void verify_consistency(honk::UltraProver& honk_prover, plonk::UltraProver& plonk_prover) { // Check that all lagrange polys agree (except for sigmas/ids which are constructed differently for Honk) @@ -46,8 +49,10 @@ void verify_consistency(honk::UltraProver& honk_prover, plonk::UltraProver& plon auto& plonk_store = plonk_prover.key->polynomial_store; for (auto& entry : honk_store) { std::string key = entry.first; - bool is_not_sigma_or_id = !(key.find("sigma") || key.find("id")); - if (plonk_store.contains(key) && is_not_sigma_or_id) { + bool is_sorted_table = (key.find("s_") != std::string::npos); + bool is_table = (key.find("table_value_") != std::string::npos); + // bool is_not_selector = (key.find("sigma") == std::string::npos) && (key.find("id") == std::string::npos); + if (plonk_store.contains(key) && (is_sorted_table || is_table)) { ASSERT_EQ(honk_store.get(key), plonk_store.get(key)); } } @@ -150,6 +155,7 @@ TEST(UltraHonkComposer, create_gates_from_plookup_accumulators) auto honk_prover = honk_composer.create_prover(); auto plonk_prover = plonk_composer.create_prover(); + check_consistency(honk_prover, plonk_prover); verify_consistency(honk_prover, plonk_prover); } diff --git a/cpp/src/barretenberg/honk/flavor/flavor.hpp b/cpp/src/barretenberg/honk/flavor/flavor.hpp index fa76fc2f79..55fb59869a 100644 --- a/cpp/src/barretenberg/honk/flavor/flavor.hpp +++ b/cpp/src/barretenberg/honk/flavor/flavor.hpp @@ -233,6 +233,7 @@ struct UltraArithmetization { Z_PERM, Z_LOOKUP, /* --- SHIFTED POLYNOMIALS --- */ + W_4_SHIFT, Z_PERM_SHIFT, Z_LOOKUP_SHIFT, /* --- --- */ diff --git a/cpp/src/barretenberg/honk/sumcheck/relations/relation_consistency.test.cpp b/cpp/src/barretenberg/honk/sumcheck/relations/relation_consistency.test.cpp index dd2567d486..c36557189c 100644 --- a/cpp/src/barretenberg/honk/sumcheck/relations/relation_consistency.test.cpp +++ b/cpp/src/barretenberg/honk/sumcheck/relations/relation_consistency.test.cpp @@ -1,3 +1,4 @@ +#include "barretenberg/honk/sumcheck/relations/ultra_arithmetic_relation.hpp" #include "relation.hpp" #include "barretenberg/honk/flavor/flavor.hpp" #include "arithmetic_relation.hpp" @@ -376,4 +377,48 @@ TYPED_TEST(RelationConsistency, GrandProductComputationRelationUltra) TestFixture::template validate_evaluations(expected_evals, relation, extended_edges, relation_parameters); }; +TYPED_TEST(RelationConsistency, UltraArithmeticRelation) +{ + SUMCHECK_RELATION_TYPE_ALIASES + using MULTIVARIATE = honk::UltraArithmetization::POLYNOMIAL; + + static constexpr size_t FULL_RELATION_LENGTH = 6; + static const size_t NUM_POLYNOMIALS = proof_system::honk::UltraArithmetization::COUNT; + + const auto relation_parameters = TestFixture::compute_mock_relation_parameters(); + std::array, NUM_POLYNOMIALS> extended_edges; + std::array, NUM_POLYNOMIALS> input_polynomials; + + // input_univariates are random polynomials of degree one + for (size_t i = 0; i < NUM_POLYNOMIALS; ++i) { + input_polynomials[i] = Univariate({ FF::random_element(), FF::random_element() }); + } + extended_edges = TestFixture::template compute_mock_extended_edges(input_polynomials); + + auto relation = UltraArithmeticRelation(); + + // Extract the extended edges for manual computation of relation contribution + const auto& w_1 = extended_edges[MULTIVARIATE::W_L]; + const auto& w_2 = extended_edges[MULTIVARIATE::W_R]; + const auto& w_3 = extended_edges[MULTIVARIATE::W_O]; + const auto& w_4 = extended_edges[MULTIVARIATE::W_4]; + const auto& w_4_shift = extended_edges[MULTIVARIATE::W_4_SHIFT]; + const auto& q_m = extended_edges[MULTIVARIATE::Q_M]; + const auto& q_l = extended_edges[MULTIVARIATE::Q_L]; + const auto& q_r = extended_edges[MULTIVARIATE::Q_R]; + const auto& q_o = extended_edges[MULTIVARIATE::Q_O]; + const auto& q_4 = extended_edges[MULTIVARIATE::Q_4]; + const auto& q_c = extended_edges[MULTIVARIATE::Q_C]; + const auto& q_arith = extended_edges[MULTIVARIATE::QARITH]; + + static const FF neg_half = FF(-2).invert(); + + auto expected_evals = (q_arith - 3) * (q_m * w_2 * w_1) * neg_half; + expected_evals += (q_l * w_1) + (q_r * w_2) + (q_o * w_3) + (q_4 * w_4) + q_c; + expected_evals += (q_arith - 1) * w_4_shift; + expected_evals *= q_arith; + + TestFixture::template validate_evaluations(expected_evals, relation, extended_edges, relation_parameters); +}; + } // namespace proof_system::honk_relation_tests diff --git a/cpp/src/barretenberg/honk/sumcheck/relations/relation_correctness.test.cpp b/cpp/src/barretenberg/honk/sumcheck/relations/relation_correctness.test.cpp index 0ec91422a9..b58b79642f 100644 --- a/cpp/src/barretenberg/honk/sumcheck/relations/relation_correctness.test.cpp +++ b/cpp/src/barretenberg/honk/sumcheck/relations/relation_correctness.test.cpp @@ -1,6 +1,7 @@ #include "barretenberg/honk/composer/ultra_honk_composer.hpp" #include "barretenberg/honk/composer/standard_honk_composer.hpp" #include "barretenberg/honk/sumcheck/relations/relation.hpp" +#include "barretenberg/honk/sumcheck/relations/ultra_arithmetic_relation.hpp" #include "barretenberg/numeric/uint256/uint256.hpp" #include "barretenberg/honk/flavor/flavor.hpp" #include @@ -131,6 +132,7 @@ TEST(RelationCorrectness, StandardRelationCorrectness) * indices * */ +// TODO(luke): Increase variety of gates in the test circuit to fully stress the relations, e.g. create_big_add_gate. // NOTE(luke): More relations will be added as they are implemented for Ultra Honk TEST(RelationCorrectness, UltraRelationCorrectness) { @@ -148,7 +150,7 @@ TEST(RelationCorrectness, UltraRelationCorrectness) uint32_t b_idx = composer.add_variable(b); uint32_t c_idx = composer.add_variable(c); uint32_t d_idx = composer.add_variable(d); - for (size_t i = 0; i < 16; i++) { + for (size_t i = 0; i < 1; i++) { composer.create_add_gate({ a_idx, b_idx, c_idx, fr::one(), fr::one(), fr::neg_one(), fr::zero() }); composer.create_add_gate({ d_idx, c_idx, a_idx, fr::one(), fr::neg_one(), fr::neg_one(), fr::zero() }); } @@ -188,6 +190,7 @@ TEST(RelationCorrectness, UltraRelationCorrectness) evaluations_array[POLYNOMIAL::W_R] = prover.wire_polynomials[1]; evaluations_array[POLYNOMIAL::W_O] = prover.wire_polynomials[2]; evaluations_array[POLYNOMIAL::W_4] = prover.wire_polynomials[3]; + evaluations_array[POLYNOMIAL::W_4_SHIFT] = prover.wire_polynomials[3].shifted(); evaluations_array[POLYNOMIAL::S_1] = prover.key->polynomial_store.get("s_1_lagrange"); evaluations_array[POLYNOMIAL::S_2] = prover.key->polynomial_store.get("s_2_lagrange"); evaluations_array[POLYNOMIAL::S_3] = prover.key->polynomial_store.get("s_3_lagrange"); @@ -219,7 +222,8 @@ TEST(RelationCorrectness, UltraRelationCorrectness) evaluations_array[POLYNOMIAL::LAGRANGE_LAST] = prover.key->polynomial_store.get("L_last_lagrange"); // Construct the round for applying sumcheck relations and results for storing computed results - auto relations = std::tuple(honk::sumcheck::GrandProductComputationRelationUltra()); + auto relations = std::tuple(honk::sumcheck::UltraArithmeticRelation(), + honk::sumcheck::GrandProductComputationRelationUltra()); fr result = 0; for (size_t i = 0; i < prover.key->circuit_size; i++) { @@ -235,6 +239,9 @@ TEST(RelationCorrectness, UltraRelationCorrectness) // equal 0. std::get<0>(relations).add_full_relation_value_contribution(result, evaluations_at_index_i, params); ASSERT_EQ(result, 0); + + std::get<1>(relations).add_full_relation_value_contribution(result, evaluations_at_index_i, params); + ASSERT_EQ(result, 0); } } diff --git a/cpp/src/barretenberg/honk/sumcheck/relations/ultra_arithmetic_relation.hpp b/cpp/src/barretenberg/honk/sumcheck/relations/ultra_arithmetic_relation.hpp new file mode 100644 index 0000000000..2df6efc2c7 --- /dev/null +++ b/cpp/src/barretenberg/honk/sumcheck/relations/ultra_arithmetic_relation.hpp @@ -0,0 +1,87 @@ +#pragma once +#include +#include + +#include "barretenberg/honk/flavor/flavor.hpp" +#include "../polynomials/univariate.hpp" +#include "relation.hpp" + +namespace proof_system::honk::sumcheck { + +template class UltraArithmeticRelation { + public: + // 1 + polynomial degree of this relation + static constexpr size_t RELATION_LENGTH = 6; // degree(q_arith^2 * q_m * w_r * w_l) = 5 + using MULTIVARIATE = UltraArithmetization::POLYNOMIAL; + + /** + * @brief Expression for the Ultra Arithmetic gate. + * @details The relation is defined as C(extended_edges(X)...) = + * q_arith * + * [ -1/2(q_arith - 3)(q_m * w_r * w_l) + + * (q_l * w_l) + (q_r * w_r) + (q_o * w_o) + (q_4 * w_4) + q_c + + * (q_arith - 1)w_4_shift ] + * + * @param evals transformed to `evals + C(extended_edges(X)...)*scaling_factor` + * @param extended_edges an std::array containing the fully extended Univariate edges. + * @param parameters contains beta, gamma, and public_input_delta, .... + * @param scaling_factor optional term to scale the evaluation before adding to evals. + */ + void add_edge_contribution(Univariate& evals, + const auto& extended_edges, + const RelationParameters&, + const FF& scaling_factor) const + { + // OPTIMIZATION?: Karatsuba in general, at least for some degrees? + // See https://hackmd.io/xGLuj6biSsCjzQnYN-pEiA?both + + auto w_l = UnivariateView(extended_edges[MULTIVARIATE::W_L]); + auto w_r = UnivariateView(extended_edges[MULTIVARIATE::W_R]); + auto w_o = UnivariateView(extended_edges[MULTIVARIATE::W_O]); + auto w_4 = UnivariateView(extended_edges[MULTIVARIATE::W_4]); + auto w_4_shift = UnivariateView(extended_edges[MULTIVARIATE::W_4_SHIFT]); + auto q_m = UnivariateView(extended_edges[MULTIVARIATE::Q_M]); + auto q_l = UnivariateView(extended_edges[MULTIVARIATE::Q_L]); + auto q_r = UnivariateView(extended_edges[MULTIVARIATE::Q_R]); + auto q_o = UnivariateView(extended_edges[MULTIVARIATE::Q_O]); + auto q_4 = UnivariateView(extended_edges[MULTIVARIATE::Q_4]); + auto q_c = UnivariateView(extended_edges[MULTIVARIATE::Q_C]); + auto q_arith = UnivariateView(extended_edges[MULTIVARIATE::QARITH]); + + static const FF neg_half = FF(-2).invert(); + + auto tmp = (q_arith - 3) * (q_m * w_r * w_l) * neg_half; + tmp += (q_l * w_l) + (q_r * w_r) + (q_o * w_o) + (q_4 * w_4) + q_c; + tmp += (q_arith - 1) * w_4_shift; + tmp *= q_arith; + tmp *= scaling_factor; + evals += tmp; + }; + + void add_full_relation_value_contribution(FF& full_honk_relation_value, + const auto& purported_evaluations, + const RelationParameters&) const + { + auto w_l = purported_evaluations[MULTIVARIATE::W_L]; + auto w_r = purported_evaluations[MULTIVARIATE::W_R]; + auto w_o = purported_evaluations[MULTIVARIATE::W_O]; + auto w_4 = purported_evaluations[MULTIVARIATE::W_4]; + auto w_4_shift = purported_evaluations[MULTIVARIATE::W_4_SHIFT]; + auto q_m = purported_evaluations[MULTIVARIATE::Q_M]; + auto q_l = purported_evaluations[MULTIVARIATE::Q_L]; + auto q_r = purported_evaluations[MULTIVARIATE::Q_R]; + auto q_o = purported_evaluations[MULTIVARIATE::Q_O]; + auto q_4 = purported_evaluations[MULTIVARIATE::Q_4]; + auto q_c = purported_evaluations[MULTIVARIATE::Q_C]; + auto q_arith = purported_evaluations[MULTIVARIATE::QARITH]; + + static const FF neg_half = FF(-2).invert(); + + auto tmp = (q_arith - 3) * (q_m * w_r * w_l) * neg_half; + tmp += (q_l * w_l) + (q_r * w_r) + (q_o * w_o) + (q_4 * w_4) + q_c; + tmp += (q_arith - 1) * w_4_shift; + tmp *= q_arith; + full_honk_relation_value += tmp; + }; +}; +} // namespace proof_system::honk::sumcheck From eb7c95a774428ae27e04cd05903c863a7d242eb5 Mon Sep 17 00:00:00 2001 From: ledwards2225 Date: Wed, 12 Apr 2023 21:05:17 +0000 Subject: [PATCH 09/11] secondary arith relation and grand prod init relation plus tests --- cpp/src/barretenberg/honk/flavor/flavor.hpp | 1 + .../grand_product_computation_relation.hpp | 2 +- .../grand_product_initialization_relation.hpp | 44 ++++++ .../relations/relation_consistency.test.cpp | 138 +++++++++++++----- .../relations/relation_correctness.test.cpp | 12 +- .../ultra_arithmetic_relation_secondary.hpp | 67 +++++++++ 6 files changed, 225 insertions(+), 39 deletions(-) create mode 100644 cpp/src/barretenberg/honk/sumcheck/relations/ultra_arithmetic_relation_secondary.hpp diff --git a/cpp/src/barretenberg/honk/flavor/flavor.hpp b/cpp/src/barretenberg/honk/flavor/flavor.hpp index 55fb59869a..be21fd4e18 100644 --- a/cpp/src/barretenberg/honk/flavor/flavor.hpp +++ b/cpp/src/barretenberg/honk/flavor/flavor.hpp @@ -233,6 +233,7 @@ struct UltraArithmetization { Z_PERM, Z_LOOKUP, /* --- SHIFTED POLYNOMIALS --- */ + W_1_SHIFT, W_4_SHIFT, Z_PERM_SHIFT, Z_LOOKUP_SHIFT, diff --git a/cpp/src/barretenberg/honk/sumcheck/relations/grand_product_computation_relation.hpp b/cpp/src/barretenberg/honk/sumcheck/relations/grand_product_computation_relation.hpp index 802dd70cd1..61f799e030 100644 --- a/cpp/src/barretenberg/honk/sumcheck/relations/grand_product_computation_relation.hpp +++ b/cpp/src/barretenberg/honk/sumcheck/relations/grand_product_computation_relation.hpp @@ -93,7 +93,7 @@ template class GrandProductComputationRelation { // TODO(luke): With Cody's Flavor work it should be easier to create a simple templated relation // for handling arbitrary width. For now I'm duplicating the width 3 logic for width 4. -template class GrandProductComputationRelationUltra { +template class UltraGrandProductComputationRelation { public: // 1 + polynomial degree of this relation static constexpr size_t RELATION_LENGTH = 6; diff --git a/cpp/src/barretenberg/honk/sumcheck/relations/grand_product_initialization_relation.hpp b/cpp/src/barretenberg/honk/sumcheck/relations/grand_product_initialization_relation.hpp index 788cec7f52..6aa7d9f3b2 100644 --- a/cpp/src/barretenberg/honk/sumcheck/relations/grand_product_initialization_relation.hpp +++ b/cpp/src/barretenberg/honk/sumcheck/relations/grand_product_initialization_relation.hpp @@ -45,4 +45,48 @@ template class GrandProductInitializationRelation { full_honk_relation_value += lagrange_last * z_perm_shift; }; }; + +// TODO(luke): The only difference between the Ultra relation and the Standard version is the enum +// used to refer into the edge polynomials. Seems desireable to not duplicate the code here but +// leaving this as is until Codys Flavor work is settled. +template class UltraGrandProductInitializationRelation { + public: + // 1 + polynomial degree of this relation + static constexpr size_t RELATION_LENGTH = 3; + using MULTIVARIATE = UltraArithmetization::POLYNOMIAL; // could just get from StandardArithmetization + + /** + * @brief Add contribution of the permutation relation for a given edge + * + * @details There are 2 relations associated with enforcing the wire copy relations + * This file handles the relation Z_perm_shift(n_last) = 0 via the relation: + * + * C(X) = L_LAST(X) * Z_perm_shift(X) + * + * @param evals transformed to `evals + C(extended_edges(X)...)*scaling_factor` + * @param extended_edges an std::array containing the fully extended Univariate edges. + * @param parameters contains beta, gamma, and public_input_delta, .... + * @param scaling_factor optional term to scale the evaluation before adding to evals. + */ + void add_edge_contribution(Univariate& evals, + const auto& extended_edges, + const RelationParameters&, + const FF& scaling_factor) const + { + auto z_perm_shift = UnivariateView(extended_edges[MULTIVARIATE::Z_PERM_SHIFT]); + auto lagrange_last = UnivariateView(extended_edges[MULTIVARIATE::LAGRANGE_LAST]); + + evals += (lagrange_last * z_perm_shift) * scaling_factor; + }; + + void add_full_relation_value_contribution(FF& full_honk_relation_value, + auto& purported_evaluations, + const RelationParameters&) const + { + auto z_perm_shift = purported_evaluations[MULTIVARIATE::Z_PERM_SHIFT]; + auto lagrange_last = purported_evaluations[MULTIVARIATE::LAGRANGE_LAST]; + + full_honk_relation_value += lagrange_last * z_perm_shift; + }; +}; } // namespace proof_system::honk::sumcheck diff --git a/cpp/src/barretenberg/honk/sumcheck/relations/relation_consistency.test.cpp b/cpp/src/barretenberg/honk/sumcheck/relations/relation_consistency.test.cpp index c36557189c..5557d7d47c 100644 --- a/cpp/src/barretenberg/honk/sumcheck/relations/relation_consistency.test.cpp +++ b/cpp/src/barretenberg/honk/sumcheck/relations/relation_consistency.test.cpp @@ -1,4 +1,5 @@ #include "barretenberg/honk/sumcheck/relations/ultra_arithmetic_relation.hpp" +#include "barretenberg/honk/sumcheck/relations/ultra_arithmetic_relation_secondary.hpp" #include "relation.hpp" #include "barretenberg/honk/flavor/flavor.hpp" #include "arithmetic_relation.hpp" @@ -325,7 +326,7 @@ TYPED_TEST(RelationConsistency, GrandProductInitializationRelation) run_test(/* is_random_input=*/false); }; -TYPED_TEST(RelationConsistency, GrandProductComputationRelationUltra) +TYPED_TEST(RelationConsistency, UltraArithmeticRelation) { SUMCHECK_RELATION_TYPE_ALIASES using MULTIVARIATE = honk::UltraArithmetization::POLYNOMIAL; @@ -343,41 +344,96 @@ TYPED_TEST(RelationConsistency, GrandProductComputationRelationUltra) } extended_edges = TestFixture::template compute_mock_extended_edges(input_polynomials); - auto relation = GrandProductComputationRelationUltra(); - - const auto& beta = relation_parameters.beta; - const auto& gamma = relation_parameters.gamma; - const auto& public_input_delta = relation_parameters.public_input_delta; + auto relation = UltraArithmeticRelation(); // Extract the extended edges for manual computation of relation contribution const auto& w_1 = extended_edges[MULTIVARIATE::W_L]; const auto& w_2 = extended_edges[MULTIVARIATE::W_R]; const auto& w_3 = extended_edges[MULTIVARIATE::W_O]; const auto& w_4 = extended_edges[MULTIVARIATE::W_4]; - const auto& sigma_1 = extended_edges[MULTIVARIATE::SIGMA_1]; - const auto& sigma_2 = extended_edges[MULTIVARIATE::SIGMA_2]; - const auto& sigma_3 = extended_edges[MULTIVARIATE::SIGMA_3]; - const auto& sigma_4 = extended_edges[MULTIVARIATE::SIGMA_4]; - const auto& id_1 = extended_edges[MULTIVARIATE::ID_1]; - const auto& id_2 = extended_edges[MULTIVARIATE::ID_2]; - const auto& id_3 = extended_edges[MULTIVARIATE::ID_3]; - const auto& id_4 = extended_edges[MULTIVARIATE::ID_4]; - const auto& z_perm = extended_edges[MULTIVARIATE::Z_PERM]; + const auto& w_4_shift = extended_edges[MULTIVARIATE::W_4_SHIFT]; + const auto& q_m = extended_edges[MULTIVARIATE::Q_M]; + const auto& q_l = extended_edges[MULTIVARIATE::Q_L]; + const auto& q_r = extended_edges[MULTIVARIATE::Q_R]; + const auto& q_o = extended_edges[MULTIVARIATE::Q_O]; + const auto& q_4 = extended_edges[MULTIVARIATE::Q_4]; + const auto& q_c = extended_edges[MULTIVARIATE::Q_C]; + const auto& q_arith = extended_edges[MULTIVARIATE::QARITH]; + + static const FF neg_half = FF(-2).invert(); + + auto expected_evals = (q_arith - 3) * (q_m * w_2 * w_1) * neg_half; + expected_evals += (q_l * w_1) + (q_r * w_2) + (q_o * w_3) + (q_4 * w_4) + q_c; + expected_evals += (q_arith - 1) * w_4_shift; + expected_evals *= q_arith; + + TestFixture::template validate_evaluations(expected_evals, relation, extended_edges, relation_parameters); +}; + +TYPED_TEST(RelationConsistency, UltraArithmeticRelationSecondary) +{ + SUMCHECK_RELATION_TYPE_ALIASES + using MULTIVARIATE = honk::UltraArithmetization::POLYNOMIAL; + + static constexpr size_t FULL_RELATION_LENGTH = 6; + static const size_t NUM_POLYNOMIALS = proof_system::honk::UltraArithmetization::COUNT; + + const auto relation_parameters = TestFixture::compute_mock_relation_parameters(); + std::array, NUM_POLYNOMIALS> extended_edges; + std::array, NUM_POLYNOMIALS> input_polynomials; + + // input_univariates are random polynomials of degree one + for (size_t i = 0; i < NUM_POLYNOMIALS; ++i) { + input_polynomials[i] = Univariate({ FF::random_element(), FF::random_element() }); + } + extended_edges = TestFixture::template compute_mock_extended_edges(input_polynomials); + + auto relation = UltraArithmeticRelationSecondary(); + + // Extract the extended edges for manual computation of relation contribution + const auto& w_1 = extended_edges[MULTIVARIATE::W_L]; + const auto& w_4 = extended_edges[MULTIVARIATE::W_4]; + const auto& w_1_shift = extended_edges[MULTIVARIATE::W_1_SHIFT]; + const auto& q_m = extended_edges[MULTIVARIATE::Q_M]; + const auto& q_arith = extended_edges[MULTIVARIATE::QARITH]; + + auto expected_evals = (w_1 + w_4 - w_1_shift + q_m); + expected_evals *= (q_arith - 2) * (q_arith - 1) * q_arith; + + TestFixture::template validate_evaluations(expected_evals, relation, extended_edges, relation_parameters); +}; + +TYPED_TEST(RelationConsistency, UltraGrandProductInitializationRelation) +{ + SUMCHECK_RELATION_TYPE_ALIASES + using MULTIVARIATE = honk::UltraArithmetization::POLYNOMIAL; + + static constexpr size_t FULL_RELATION_LENGTH = 6; + static const size_t NUM_POLYNOMIALS = proof_system::honk::UltraArithmetization::COUNT; + + const auto relation_parameters = TestFixture::compute_mock_relation_parameters(); + std::array, NUM_POLYNOMIALS> extended_edges; + std::array, NUM_POLYNOMIALS> input_polynomials; + + // input_univariates are random polynomials of degree one + for (size_t i = 0; i < NUM_POLYNOMIALS; ++i) { + input_polynomials[i] = Univariate({ FF::random_element(), FF::random_element() }); + } + extended_edges = TestFixture::template compute_mock_extended_edges(input_polynomials); + + auto relation = UltraGrandProductInitializationRelation(); + + // Extract the extended edges for manual computation of relation contribution const auto& z_perm_shift = extended_edges[MULTIVARIATE::Z_PERM_SHIFT]; - const auto& lagrange_first = extended_edges[MULTIVARIATE::LAGRANGE_FIRST]; const auto& lagrange_last = extended_edges[MULTIVARIATE::LAGRANGE_LAST]; // Compute the expected result using a simple to read version of the relation expression - auto expected_evals = (z_perm + lagrange_first) * (w_1 + id_1 * beta + gamma) * (w_2 + id_2 * beta + gamma) * - (w_3 + id_3 * beta + gamma) * (w_4 + id_4 * beta + gamma) - - (z_perm_shift + lagrange_last * public_input_delta) * (w_1 + sigma_1 * beta + gamma) * - (w_2 + sigma_2 * beta + gamma) * (w_3 + sigma_3 * beta + gamma) * - (w_4 + sigma_4 * beta + gamma); + auto expected_evals = z_perm_shift * lagrange_last; TestFixture::template validate_evaluations(expected_evals, relation, extended_edges, relation_parameters); }; -TYPED_TEST(RelationConsistency, UltraArithmeticRelation) +TYPED_TEST(RelationConsistency, UltraGrandProductComputationRelation) { SUMCHECK_RELATION_TYPE_ALIASES using MULTIVARIATE = honk::UltraArithmetization::POLYNOMIAL; @@ -395,28 +451,36 @@ TYPED_TEST(RelationConsistency, UltraArithmeticRelation) } extended_edges = TestFixture::template compute_mock_extended_edges(input_polynomials); - auto relation = UltraArithmeticRelation(); + auto relation = UltraGrandProductComputationRelation(); + + const auto& beta = relation_parameters.beta; + const auto& gamma = relation_parameters.gamma; + const auto& public_input_delta = relation_parameters.public_input_delta; // Extract the extended edges for manual computation of relation contribution const auto& w_1 = extended_edges[MULTIVARIATE::W_L]; const auto& w_2 = extended_edges[MULTIVARIATE::W_R]; const auto& w_3 = extended_edges[MULTIVARIATE::W_O]; const auto& w_4 = extended_edges[MULTIVARIATE::W_4]; - const auto& w_4_shift = extended_edges[MULTIVARIATE::W_4_SHIFT]; - const auto& q_m = extended_edges[MULTIVARIATE::Q_M]; - const auto& q_l = extended_edges[MULTIVARIATE::Q_L]; - const auto& q_r = extended_edges[MULTIVARIATE::Q_R]; - const auto& q_o = extended_edges[MULTIVARIATE::Q_O]; - const auto& q_4 = extended_edges[MULTIVARIATE::Q_4]; - const auto& q_c = extended_edges[MULTIVARIATE::Q_C]; - const auto& q_arith = extended_edges[MULTIVARIATE::QARITH]; - - static const FF neg_half = FF(-2).invert(); + const auto& sigma_1 = extended_edges[MULTIVARIATE::SIGMA_1]; + const auto& sigma_2 = extended_edges[MULTIVARIATE::SIGMA_2]; + const auto& sigma_3 = extended_edges[MULTIVARIATE::SIGMA_3]; + const auto& sigma_4 = extended_edges[MULTIVARIATE::SIGMA_4]; + const auto& id_1 = extended_edges[MULTIVARIATE::ID_1]; + const auto& id_2 = extended_edges[MULTIVARIATE::ID_2]; + const auto& id_3 = extended_edges[MULTIVARIATE::ID_3]; + const auto& id_4 = extended_edges[MULTIVARIATE::ID_4]; + const auto& z_perm = extended_edges[MULTIVARIATE::Z_PERM]; + const auto& z_perm_shift = extended_edges[MULTIVARIATE::Z_PERM_SHIFT]; + const auto& lagrange_first = extended_edges[MULTIVARIATE::LAGRANGE_FIRST]; + const auto& lagrange_last = extended_edges[MULTIVARIATE::LAGRANGE_LAST]; - auto expected_evals = (q_arith - 3) * (q_m * w_2 * w_1) * neg_half; - expected_evals += (q_l * w_1) + (q_r * w_2) + (q_o * w_3) + (q_4 * w_4) + q_c; - expected_evals += (q_arith - 1) * w_4_shift; - expected_evals *= q_arith; + // Compute the expected result using a simple to read version of the relation expression + auto expected_evals = (z_perm + lagrange_first) * (w_1 + id_1 * beta + gamma) * (w_2 + id_2 * beta + gamma) * + (w_3 + id_3 * beta + gamma) * (w_4 + id_4 * beta + gamma) - + (z_perm_shift + lagrange_last * public_input_delta) * (w_1 + sigma_1 * beta + gamma) * + (w_2 + sigma_2 * beta + gamma) * (w_3 + sigma_3 * beta + gamma) * + (w_4 + sigma_4 * beta + gamma); TestFixture::template validate_evaluations(expected_evals, relation, extended_edges, relation_parameters); }; diff --git a/cpp/src/barretenberg/honk/sumcheck/relations/relation_correctness.test.cpp b/cpp/src/barretenberg/honk/sumcheck/relations/relation_correctness.test.cpp index b58b79642f..f73df218fb 100644 --- a/cpp/src/barretenberg/honk/sumcheck/relations/relation_correctness.test.cpp +++ b/cpp/src/barretenberg/honk/sumcheck/relations/relation_correctness.test.cpp @@ -2,6 +2,7 @@ #include "barretenberg/honk/composer/standard_honk_composer.hpp" #include "barretenberg/honk/sumcheck/relations/relation.hpp" #include "barretenberg/honk/sumcheck/relations/ultra_arithmetic_relation.hpp" +#include "barretenberg/honk/sumcheck/relations/ultra_arithmetic_relation_secondary.hpp" #include "barretenberg/numeric/uint256/uint256.hpp" #include "barretenberg/honk/flavor/flavor.hpp" #include @@ -190,6 +191,7 @@ TEST(RelationCorrectness, UltraRelationCorrectness) evaluations_array[POLYNOMIAL::W_R] = prover.wire_polynomials[1]; evaluations_array[POLYNOMIAL::W_O] = prover.wire_polynomials[2]; evaluations_array[POLYNOMIAL::W_4] = prover.wire_polynomials[3]; + evaluations_array[POLYNOMIAL::W_1_SHIFT] = prover.wire_polynomials[0].shifted(); evaluations_array[POLYNOMIAL::W_4_SHIFT] = prover.wire_polynomials[3].shifted(); evaluations_array[POLYNOMIAL::S_1] = prover.key->polynomial_store.get("s_1_lagrange"); evaluations_array[POLYNOMIAL::S_2] = prover.key->polynomial_store.get("s_2_lagrange"); @@ -223,7 +225,9 @@ TEST(RelationCorrectness, UltraRelationCorrectness) // Construct the round for applying sumcheck relations and results for storing computed results auto relations = std::tuple(honk::sumcheck::UltraArithmeticRelation(), - honk::sumcheck::GrandProductComputationRelationUltra()); + honk::sumcheck::UltraArithmeticRelationSecondary(), + honk::sumcheck::UltraGrandProductInitializationRelation(), + honk::sumcheck::UltraGrandProductComputationRelation()); fr result = 0; for (size_t i = 0; i < prover.key->circuit_size; i++) { @@ -242,6 +246,12 @@ TEST(RelationCorrectness, UltraRelationCorrectness) std::get<1>(relations).add_full_relation_value_contribution(result, evaluations_at_index_i, params); ASSERT_EQ(result, 0); + + std::get<2>(relations).add_full_relation_value_contribution(result, evaluations_at_index_i, params); + ASSERT_EQ(result, 0); + + std::get<3>(relations).add_full_relation_value_contribution(result, evaluations_at_index_i, params); + ASSERT_EQ(result, 0); } } diff --git a/cpp/src/barretenberg/honk/sumcheck/relations/ultra_arithmetic_relation_secondary.hpp b/cpp/src/barretenberg/honk/sumcheck/relations/ultra_arithmetic_relation_secondary.hpp new file mode 100644 index 0000000000..78c01db356 --- /dev/null +++ b/cpp/src/barretenberg/honk/sumcheck/relations/ultra_arithmetic_relation_secondary.hpp @@ -0,0 +1,67 @@ +#pragma once +#include +#include + +#include "barretenberg/honk/flavor/flavor.hpp" +#include "../polynomials/univariate.hpp" +#include "relation.hpp" + +namespace proof_system::honk::sumcheck { + +template class UltraArithmeticRelationSecondary { + public: + // 1 + polynomial degree of this relation + static constexpr size_t RELATION_LENGTH = 5; // degree(q_arith^3 * w_l) = 4 + using MULTIVARIATE = UltraArithmetization::POLYNOMIAL; + + /** + * @brief Expression for the Ultra Arithmetic gate. + * @details The relation is defined as C(extended_edges(X)...) = + * q_arith * + * (q_arith - 2) * (q_arith - 1) * (w_l + w_4 - w_l_shift + q_m) + * + * @param evals transformed to `evals + C(extended_edges(X)...)*scaling_factor` + * @param extended_edges an std::array containing the fully extended Univariate edges. + * @param parameters contains beta, gamma, and public_input_delta, .... + * @param scaling_factor optional term to scale the evaluation before adding to evals. + */ + void add_edge_contribution(Univariate& evals, + const auto& extended_edges, + const RelationParameters&, + const FF& scaling_factor) const + { + // OPTIMIZATION?: Karatsuba in general, at least for some degrees? + // See https://hackmd.io/xGLuj6biSsCjzQnYN-pEiA?both + + auto w_l = UnivariateView(extended_edges[MULTIVARIATE::W_L]); + auto w_4 = UnivariateView(extended_edges[MULTIVARIATE::W_4]); + auto w_l_shift = UnivariateView(extended_edges[MULTIVARIATE::W_1_SHIFT]); + auto q_m = UnivariateView(extended_edges[MULTIVARIATE::Q_M]); + auto q_arith = UnivariateView(extended_edges[MULTIVARIATE::QARITH]); + + auto tmp = w_l + w_4 - w_l_shift + q_m; + tmp *= (q_arith - 2); + tmp *= (q_arith - 1); + tmp *= q_arith; + tmp *= scaling_factor; + evals += tmp; + }; + + void add_full_relation_value_contribution(FF& full_honk_relation_value, + const auto& purported_evaluations, + const RelationParameters&) const + { + auto w_l = purported_evaluations[MULTIVARIATE::W_L]; + auto w_4 = purported_evaluations[MULTIVARIATE::W_4]; + auto w_l_shift = purported_evaluations[MULTIVARIATE::W_1_SHIFT]; + auto q_m = purported_evaluations[MULTIVARIATE::Q_M]; + auto q_arith = purported_evaluations[MULTIVARIATE::QARITH]; + + auto tmp = w_l + w_4 - w_l_shift + q_m; + tmp *= (q_arith - 2); + tmp *= (q_arith - 1); + tmp *= q_arith; + full_honk_relation_value += tmp; + }; +}; +} // namespace proof_system::honk::sumcheck From dff21ab503b86728c1ef40f94ac55dad96ca5257 Mon Sep 17 00:00:00 2001 From: ledwards2225 Date: Wed, 12 Apr 2023 21:22:18 +0000 Subject: [PATCH 10/11] cleanup --- .../barretenberg/honk/composer/ultra_honk_composer.test.cpp | 6 ++---- .../honk/sumcheck/relations/relation_correctness.test.cpp | 4 ++-- .../proof_system/composer/permutation_helper.hpp | 4 ++-- 3 files changed, 6 insertions(+), 8 deletions(-) diff --git a/cpp/src/barretenberg/honk/composer/ultra_honk_composer.test.cpp b/cpp/src/barretenberg/honk/composer/ultra_honk_composer.test.cpp index 1664ec5520..6d8f1a26ef 100644 --- a/cpp/src/barretenberg/honk/composer/ultra_honk_composer.test.cpp +++ b/cpp/src/barretenberg/honk/composer/ultra_honk_composer.test.cpp @@ -41,17 +41,16 @@ std::vector add_variables(auto& composer, std::vector variables) */ // NOTE: Currently only checking witness polynomials (wires, sorted lists) and table polys. The permutation polys // are computed differently between plonk and honk and we do not enforce non-zero selectors in Honk so the final -// element will disagree. +// element in the selectors will disagree. void verify_consistency(honk::UltraProver& honk_prover, plonk::UltraProver& plonk_prover) { - // Check that all lagrange polys agree (except for sigmas/ids which are constructed differently for Honk) + // Check that all lagrange polys agree auto& honk_store = honk_prover.key->polynomial_store; auto& plonk_store = plonk_prover.key->polynomial_store; for (auto& entry : honk_store) { std::string key = entry.first; bool is_sorted_table = (key.find("s_") != std::string::npos); bool is_table = (key.find("table_value_") != std::string::npos); - // bool is_not_selector = (key.find("sigma") == std::string::npos) && (key.find("id") == std::string::npos); if (plonk_store.contains(key) && (is_sorted_table || is_table)) { ASSERT_EQ(honk_store.get(key), plonk_store.get(key)); } @@ -155,7 +154,6 @@ TEST(UltraHonkComposer, create_gates_from_plookup_accumulators) auto honk_prover = honk_composer.create_prover(); auto plonk_prover = plonk_composer.create_prover(); - check_consistency(honk_prover, plonk_prover); verify_consistency(honk_prover, plonk_prover); } diff --git a/cpp/src/barretenberg/honk/sumcheck/relations/relation_correctness.test.cpp b/cpp/src/barretenberg/honk/sumcheck/relations/relation_correctness.test.cpp index f73df218fb..f5556a31da 100644 --- a/cpp/src/barretenberg/honk/sumcheck/relations/relation_correctness.test.cpp +++ b/cpp/src/barretenberg/honk/sumcheck/relations/relation_correctness.test.cpp @@ -19,7 +19,7 @@ using namespace proof_system::honk; namespace test_honk_relations { /** - * @brief Test the correctness of the Standard Honk rleations + * @brief Test the correctness of the Standard Honk relations * * @details Check that the constraints encoded by the relations are satisfied by the polynomials produced by the * Standard Honk Composer for a real circuit. @@ -124,7 +124,7 @@ TEST(RelationCorrectness, StandardRelationCorrectness) } /** - * @brief Test the correctness of the Ultra Honk rleations + * @brief Test the correctness of the Ultra Honk relations * * @details Check that the constraints encoded by the relations are satisfied by the polynomials produced by the * Ultra Honk Composer for a real circuit. diff --git a/cpp/src/barretenberg/proof_system/composer/permutation_helper.hpp b/cpp/src/barretenberg/proof_system/composer/permutation_helper.hpp index b5f74894cd..ef70eb9a18 100644 --- a/cpp/src/barretenberg/proof_system/composer/permutation_helper.hpp +++ b/cpp/src/barretenberg/proof_system/composer/permutation_helper.hpp @@ -258,8 +258,8 @@ void compute_honk_style_permutation_lagrange_polynomials_from_mapping( current_permutation_poly[i] = -barretenberg::fr(current_mapping.row_index + 1 + num_gates * current_mapping.column_index); } else if (current_mapping.is_tag) { - // TODO(luke): enough to simply make these disjoint from non-tag values? - current_permutation_poly[i] = barretenberg::fr::zero(); + // Set evaluations to (arbitrary) values disjoint from non-tag values + current_permutation_poly[i] = num_gates * program_width + current_mapping.row_index; } else { // For the regular permutation we simply point to the next location by setting the evaluation to its // index From 4c9f2b1651920570d016cc0fad5fe4531edfb276 Mon Sep 17 00:00:00 2001 From: ledwards2225 Date: Thu, 13 Apr 2023 19:02:35 +0000 Subject: [PATCH 11/11] adjust some comments per PR feedback --- .../barretenberg/honk/composer/ultra_honk_composer.test.cpp | 1 + cpp/src/barretenberg/honk/flavor/flavor.hpp | 4 ++-- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/cpp/src/barretenberg/honk/composer/ultra_honk_composer.test.cpp b/cpp/src/barretenberg/honk/composer/ultra_honk_composer.test.cpp index 6d8f1a26ef..97f21b0ec0 100644 --- a/cpp/src/barretenberg/honk/composer/ultra_honk_composer.test.cpp +++ b/cpp/src/barretenberg/honk/composer/ultra_honk_composer.test.cpp @@ -57,6 +57,7 @@ void verify_consistency(honk::UltraProver& honk_prover, plonk::UltraProver& plon } // Check that all wires agree + // Note: for Honk, wires are owned directly by the prover. For Plonk they are stored in the key. for (size_t i = 0; i < 4; ++i) { std::string label = "w_" + std::to_string(i + 1) + "_lagrange"; ASSERT_EQ(honk_prover.wire_polynomials[i], plonk_prover.key->polynomial_store.get(label)); diff --git a/cpp/src/barretenberg/honk/flavor/flavor.hpp b/cpp/src/barretenberg/honk/flavor/flavor.hpp index be21fd4e18..c420ed64aa 100644 --- a/cpp/src/barretenberg/honk/flavor/flavor.hpp +++ b/cpp/src/barretenberg/honk/flavor/flavor.hpp @@ -14,7 +14,7 @@ struct StandardArithmetization { * 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. + * number of polynomials in each category must be manually updated. * */ enum POLYNOMIAL { @@ -195,7 +195,7 @@ struct UltraArithmetization { * 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. + * number of polynomials in each category must be manually updated. * */ enum POLYNOMIAL {