From 4e25f4d8e6b20280ffc0d2f1a73c2527d2861ec5 Mon Sep 17 00:00:00 2001 From: ledwards2225 Date: Mon, 10 Apr 2023 18:33:37 +0000 Subject: [PATCH 1/4] add split UltraHonk composer and checks for consistency with UltraPlonk --- .../standard_honk_composer_helper.cpp | 1 + .../ultra_honk_composer_helper.cpp | 366 ++++++ .../ultra_honk_composer_helper.hpp | 72 ++ .../honk/composer/ultra_honk_composer.hpp | 470 ++++++++ .../composer/ultra_honk_composer.test.cpp | 1018 +++++++++++++++++ .../barretenberg/honk/proof_system/prover.hpp | 7 +- .../honk/proof_system/prover_library.test.cpp | 21 +- .../honk/proof_system/ultra_prover.cpp | 321 ++++++ .../honk/proof_system/ultra_prover.hpp | 98 ++ .../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 | 21 + 14 files changed, 2421 insertions(+), 15 deletions(-) create mode 100644 cpp/src/barretenberg/honk/composer/composer_helper/ultra_honk_composer_helper.cpp create mode 100644 cpp/src/barretenberg/honk/composer/composer_helper/ultra_honk_composer_helper.hpp create mode 100644 cpp/src/barretenberg/honk/composer/ultra_honk_composer.hpp create mode 100644 cpp/src/barretenberg/honk/composer/ultra_honk_composer.test.cpp create mode 100644 cpp/src/barretenberg/honk/proof_system/ultra_prover.cpp create mode 100644 cpp/src/barretenberg/honk/proof_system/ultra_prover.hpp diff --git a/cpp/src/barretenberg/honk/composer/composer_helper/standard_honk_composer_helper.cpp b/cpp/src/barretenberg/honk/composer/composer_helper/standard_honk_composer_helper.cpp index 8c61e02a5d..6867d9af37 100644 --- a/cpp/src/barretenberg/honk/composer/composer_helper/standard_honk_composer_helper.cpp +++ b/cpp/src/barretenberg/honk/composer/composer_helper/standard_honk_composer_helper.cpp @@ -165,6 +165,7 @@ StandardProver StandardHonkComposerHelper::create_prover( compute_witness(circuit_constructor); size_t num_sumcheck_rounds(circuit_proving_key->log_circuit_size); + // TODO(luke): what is this manifest? Remove? auto manifest = Flavor::create_manifest(circuit_constructor.public_inputs.size(), num_sumcheck_rounds); StandardProver output_state(std::move(wire_polynomials), circuit_proving_key); 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 new file mode 100644 index 0000000000..6adafef13f --- /dev/null +++ b/cpp/src/barretenberg/honk/composer/composer_helper/ultra_honk_composer_helper.cpp @@ -0,0 +1,366 @@ +#include "ultra_honk_composer_helper.hpp" +#include "barretenberg/honk/proof_system/ultra_prover.hpp" +#include "barretenberg/plonk/proof_system/types/program_settings.hpp" +#include "barretenberg/plonk/proof_system/types/prover_settings.hpp" +// #include "barretenberg/plonk/proof_system/verifier/verifier.hpp" +#include "barretenberg/proof_system/circuit_constructors/ultra_circuit_constructor.hpp" +#include "barretenberg/proof_system/composer/permutation_helper.hpp" +#include "barretenberg/plonk/proof_system/commitment_scheme/kate_commitment_scheme.hpp" + +#include +#include +#include +#include + +namespace proof_system::honk { + +/** + * @brief Computes `this.witness`, which is basiclly a set of polynomials mapped-to by strings. + * + * 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) +{ + if (computed_witness) { + return; + } + + size_t tables_size = 0; + size_t lookups_size = 0; + for (const auto& table : circuit_constructor.lookup_tables) { + tables_size += table.size; + lookups_size += table.lookup_gates.size(); + } + + const size_t filled_gates = circuit_constructor.num_gates + circuit_constructor.public_inputs.size(); + const size_t total_num_gates = std::max(filled_gates, tables_size + lookups_size); + + const size_t subgroup_size = circuit_constructor.get_circuit_subgroup_size(total_num_gates + NUM_RESERVED_GATES); + + // Pad the wires (pointers to `witness_indices` of the `variables` vector). + // Note: the remaining NUM_RESERVED_GATES indices are padded with zeros within `compute_witness_base` (called + // next). + for (size_t i = filled_gates; i < total_num_gates; ++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); + 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); + 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. + size_t count = subgroup_size - tables_size - lookups_size - s_randomness - 1; + for (size_t i = 0; i < count; ++i) { + s_1[i] = 0; + s_2[i] = 0; + s_3[i] = 0; + s_4[i] = 0; + } + + for (auto& table : circuit_constructor.lookup_tables) { + const fr table_index(table.table_index); + auto& lookup_gates = table.lookup_gates; + for (size_t i = 0; i < table.size; ++i) { + if (table.use_twin_keys) { + lookup_gates.push_back({ + { + table.column_1[i].from_montgomery_form().data[0], + table.column_2[i].from_montgomery_form().data[0], + }, + { + table.column_3[i], + 0, + }, + }); + } else { + lookup_gates.push_back({ + { + table.column_1[i].from_montgomery_form().data[0], + 0, + }, + { + table.column_2[i], + table.column_3[i], + }, + }); + } + } + +#ifdef NO_TBB + std::sort(lookup_gates.begin(), lookup_gates.end()); +#else + std::sort(std::execution::par_unseq, lookup_gates.begin(), lookup_gates.end()); +#endif + + for (const auto& entry : lookup_gates) { + const auto components = entry.to_sorted_list_components(table.use_twin_keys); + s_1[count] = components[0]; + s_2[count] = components[1]; + s_3[count] = components[2]; + s_4[count] = table_index; + ++count; + } + } + + // Initialise the `s_randomness` positions in the s polynomials with 0. + // These will be the positions where we will be adding random scalars to add zero knowledge + // to plookup (search for `Blinding` in plonk/proof_system/widgets/random_widgets/plookup_widget_impl.hpp + // ProverPlookupWidget::compute_sorted_list_polynomial()) + for (size_t i = 0; i < s_randomness; ++i) { + s_1[count] = 0; + s_2[count] = 0; + s_3[count] = 0; + s_4[count] = 0; + ++count; + } + + // TODO(luke): Adding these to the key for now but this is inconsistent since these are 'witness' polys. Need + // to see what becomes of the proving key before making a decision here. + circuit_proving_key->polynomial_store.put("s_1_lagrange", std::move(s_1)); + circuit_proving_key->polynomial_store.put("s_2_lagrange", std::move(s_2)); + circuit_proving_key->polynomial_store.put("s_3_lagrange", std::move(s_3)); + circuit_proving_key->polynomial_store.put("s_4_lagrange", std::move(s_4)); + + computed_witness = true; +} + +template +UltraProver UltraHonkComposerHelper::create_prover(CircuitConstructor& circuit_constructor) +{ + finalize_circuit(circuit_constructor); + + compute_proving_key(circuit_constructor); + compute_witness(circuit_constructor); + + UltraProver output_state(std::move(wire_polynomials), circuit_proving_key); + + return output_state; +} + +// /** +// * Create verifier: compute verification key, +// * initialize verifier with it and an initial manifest and initialize commitment_scheme. +// * +// * @return The verifier. +// * */ +// // TODO(Cody): This should go away altogether. +// template +// plonk::UltraVerifier UltraHonkComposerHelper::create_verifier( +// const CircuitConstructor& circuit_constructor) +// { +// auto verification_key = compute_verification_key(circuit_constructor); + +// plonk::UltraVerifier output_state(circuit_verification_key, +// create_manifest(circuit_constructor.public_inputs.size())); + +// std::unique_ptr> kate_commitment_scheme = +// std::make_unique>(); + +// output_state.commitment_scheme = std::move(kate_commitment_scheme); + +// return output_state; +// } + +template +std::shared_ptr UltraHonkComposerHelper::compute_proving_key( + const CircuitConstructor& circuit_constructor) +{ + if (circuit_proving_key) { + return circuit_proving_key; + } + + size_t tables_size = 0; + size_t lookups_size = 0; + for (const auto& table : circuit_constructor.lookup_tables) { + tables_size += table.size; + lookups_size += table.lookup_gates.size(); + } + + const size_t minimum_circuit_size = tables_size + lookups_size; + const size_t num_randomized_gates = NUM_RANDOMIZED_GATES; + // Initialize circuit_proving_key + // TODO(#229)(Kesha): replace composer types. + circuit_proving_key = initialize_proving_key( + circuit_constructor, crs_factory_.get(), minimum_circuit_size, num_randomized_gates, ComposerType::PLOOKUP); + + 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, + circuit_proving_key.get()); + + const size_t subgroup_size = circuit_proving_key->circuit_size; + + polynomial poly_q_table_column_1(subgroup_size); + polynomial poly_q_table_column_2(subgroup_size); + polynomial poly_q_table_column_3(subgroup_size); + polynomial poly_q_table_column_4(subgroup_size); + + size_t offset = subgroup_size - tables_size - s_randomness - 1; + + // Create lookup selector polynomials which interpolate each table column. + // Our selector polys always need to interpolate the full subgroup size, so here we offset so as to + // put the table column's values at the end. (The first gates are for non-lookup constraints). + // [0, ..., 0, ...table, 0, 0, 0, x] + // ^^^^^^^^^ ^^^^^^^^ ^^^^^^^ ^nonzero to ensure uniqueness and to avoid infinity commitments + // | table randomness + // ignored, as used for regular constraints and padding to the next power of 2. + + for (size_t i = 0; i < offset; ++i) { + poly_q_table_column_1[i] = 0; + poly_q_table_column_2[i] = 0; + poly_q_table_column_3[i] = 0; + poly_q_table_column_4[i] = 0; + } + + for (const auto& table : circuit_constructor.lookup_tables) { + const fr table_index(table.table_index); + + for (size_t i = 0; i < table.size; ++i) { + poly_q_table_column_1[offset] = table.column_1[i]; + poly_q_table_column_2[offset] = table.column_2[i]; + poly_q_table_column_3[offset] = table.column_3[i]; + poly_q_table_column_4[offset] = table_index; + ++offset; + } + } + + // Initialise the last `s_randomness` positions in table polynomials with 0. We don't need to actually randomise + // the table polynomials. + for (size_t i = 0; i < s_randomness; ++i) { + poly_q_table_column_1[offset] = 0; + poly_q_table_column_2[offset] = 0; + poly_q_table_column_3[offset] = 0; + poly_q_table_column_4[offset] = 0; + ++offset; + } + + // // In the case of using UltraPlonkComposer for a circuit which does _not_ make use of any lookup tables, all + // four + // // table columns would be all zeros. This would result in these polys' commitments all being the point at + // infinity + // // (which is bad because our point arithmetic assumes we'll never operate on the point at infinity). To avoid + // this, + // // we set the last evaluation of each poly to be nonzero. The last `num_roots_cut_out_of_vanishing_poly = 4` + // // evaluations are ignored by constraint checks; we arbitrarily choose the very-last evaluation to be nonzero. + // See + // // ComposerBase::compute_proving_key_base for further explanation, as a similar trick is done there. We could + // // have chosen `1` for each such evaluation here, but that would have resulted in identical commitments for + // // all four columns. We don't want to have equal commitments, because biggroup operations assume no points are + // // equal, so if we tried to verify an ultra proof in a circuit, the biggroup operations would fail. To combat + // // this, we just choose distinct values: + size_t num_selectors = circuit_constructor.num_selectors; + ASSERT(offset == subgroup_size - 1); + auto unique_last_value = num_selectors + 1; // Note: in compute_proving_key_base, moments earlier, each selector + // vector was given a unique last value from 1..num_selectors. So we + // avoid those values and continue the count, to ensure uniqueness. + poly_q_table_column_1[subgroup_size - 1] = unique_last_value; + poly_q_table_column_2[subgroup_size - 1] = ++unique_last_value; + poly_q_table_column_3[subgroup_size - 1] = ++unique_last_value; + poly_q_table_column_4[subgroup_size - 1] = ++unique_last_value; + + circuit_proving_key->polynomial_store.put("table_value_1_lagrange", std::move(poly_q_table_column_1)); + circuit_proving_key->polynomial_store.put("table_value_2_lagrange", std::move(poly_q_table_column_2)); + circuit_proving_key->polynomial_store.put("table_value_3_lagrange", std::move(poly_q_table_column_3)); + circuit_proving_key->polynomial_store.put("table_value_4_lagrange", std::move(poly_q_table_column_4)); + + // Copy memory read/write record data into proving key. Prover needs to know which gates contain a read/write + // 'record' witness on the 4th wire. This wire value can only be fully computed once the first 3 wire polynomials + // have been committed to. The 4th wire on these gates will be a random linear combination of the first 3 wires, + // using the plookup challenge `eta` + std::copy(circuit_constructor.memory_read_records.begin(), + circuit_constructor.memory_read_records.end(), + std::back_inserter(circuit_proving_key->memory_read_records)); + std::copy(circuit_constructor.memory_write_records.begin(), + circuit_constructor.memory_write_records.end(), + std::back_inserter(circuit_proving_key->memory_write_records)); + + circuit_proving_key->recursive_proof_public_input_indices = + std::vector(recursive_proof_public_input_indices.begin(), recursive_proof_public_input_indices.end()); + + circuit_proving_key->contains_recursive_proof = contains_recursive_proof; + + return circuit_proving_key; +} + +// /** +// * Compute verification key consisting of selector precommitments. +// * +// * @return Pointer to created circuit verification key. +// * */ +// template +// std::shared_ptr UltraHonkComposerHelper::compute_verification_key( +// const CircuitConstructor& circuit_constructor) +// { +// if (circuit_verification_key) { +// return circuit_verification_key; +// } + +// if (!circuit_proving_key) { +// compute_proving_key(circuit_constructor); +// } +// circuit_verification_key = compute_verification_key_common(circuit_proving_key, +// crs_factory_->get_verifier_crs()); + +// circuit_verification_key->composer_type = type; // Invariably plookup for this class. + +// // See `add_recusrive_proof()` for how this recursive data is assigned. +// circuit_verification_key->recursive_proof_public_input_indices = +// std::vector(recursive_proof_public_input_indices.begin(), +// recursive_proof_public_input_indices.end()); + +// circuit_verification_key->contains_recursive_proof = contains_recursive_proof; + +// return circuit_verification_key; +// } + +// template +// void UltraHonkComposerHelper::add_table_column_selector_poly_to_proving_key( +// polynomial& selector_poly_lagrange_form, const std::string& tag) +// { +// polynomial selector_poly_lagrange_form_copy(selector_poly_lagrange_form, circuit_proving_key->small_domain.size); + +// selector_poly_lagrange_form.ifft(circuit_proving_key->small_domain); +// auto& selector_poly_coeff_form = selector_poly_lagrange_form; + +// polynomial selector_poly_coset_form(selector_poly_coeff_form, circuit_proving_key->circuit_size * 4); +// selector_poly_coset_form.coset_fft(circuit_proving_key->large_domain); + +// circuit_proving_key->polynomial_store.put(tag, std::move(selector_poly_coeff_form)); +// circuit_proving_key->polynomial_store.put(tag + "_lagrange", std::move(selector_poly_lagrange_form_copy)); +// circuit_proving_key->polynomial_store.put(tag + "_fft", std::move(selector_poly_coset_form)); +// } + +template class UltraHonkComposerHelper; +} // namespace proof_system::honk 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 new file mode 100644 index 0000000000..b019190e6d --- /dev/null +++ b/cpp/src/barretenberg/honk/composer/composer_helper/ultra_honk_composer_helper.hpp @@ -0,0 +1,72 @@ +#pragma once + +#include "barretenberg/proof_system/composer/composer_helper_lib.hpp" +#include "barretenberg/plonk/composer/splitting_tmp/composer_helper/composer_helper_lib.hpp" +#include "barretenberg/srs/reference_string/file_reference_string.hpp" +#include "barretenberg/plonk/proof_system/proving_key/proving_key.hpp" +#include "barretenberg/honk/proof_system/ultra_prover.hpp" +// #include "barretenberg/plonk/proof_system/verifier/verifier.hpp" + +#include +#include +#include +#include + +namespace proof_system::honk { +// TODO(Kesha): change initializations to specify this parameter +// 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 + // 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. + static constexpr size_t NUM_RANDOMIZED_GATES = 4; // equal to the number of multilinear evaluations leaked + static constexpr size_t program_width = CircuitConstructor::program_width; + std::vector wire_polynomials; + std::shared_ptr circuit_proving_key; + std::shared_ptr circuit_verification_key; + // TODO(#218)(kesha): we need to put this into the commitment key, so that the composer doesn't have to handle srs + // at all + std::shared_ptr crs_factory_; + + std::vector recursive_proof_public_input_indices; + bool contains_recursive_proof = false; + bool computed_witness = false; + + // This variable controls the amount with which the lookup table and witness values need to be shifted + // above to make room for adding randomness into the permutation and witness polynomials in the plookup widget. + // This must be (num_roots_cut_out_of_the_vanishing_polynomial - 1), since the variable num_roots_cut_out_of_ + // vanishing_polynomial cannot be trivially fetched here, I am directly setting this to 4 - 1 = 3. + static constexpr size_t s_randomness = 3; + + explicit UltraHonkComposerHelper(std::shared_ptr crs_factory) + : crs_factory_(std::move(crs_factory)) + {} + + UltraHonkComposerHelper(std::shared_ptr p_key, std::shared_ptr v_key) + : circuit_proving_key(std::move(p_key)) + , circuit_verification_key(std::move(v_key)) + {} + + UltraHonkComposerHelper(UltraHonkComposerHelper&& other) noexcept = default; + UltraHonkComposerHelper(UltraHonkComposerHelper const& other) noexcept = default; + UltraHonkComposerHelper& operator=(UltraHonkComposerHelper&& other) noexcept = default; + UltraHonkComposerHelper& operator=(UltraHonkComposerHelper const& other) noexcept = default; + ~UltraHonkComposerHelper() = default; + + void finalize_circuit(CircuitConstructor& circuit_constructor) { circuit_constructor.finalize_circuit(); }; + + std::shared_ptr compute_proving_key(const CircuitConstructor& circuit_constructor); + // std::shared_ptr compute_verification_key(const CircuitConstructor& circuit_constructor); + + void compute_witness(CircuitConstructor& circuit_constructor); + + UltraProver create_prover(CircuitConstructor& circuit_constructor); + // UltraVerifier create_verifier(const CircuitConstructor& circuit_constructor); + + void add_table_column_selector_poly_to_proving_key(polynomial& small, const std::string& tag); +}; + +} // namespace proof_system::honk diff --git a/cpp/src/barretenberg/honk/composer/ultra_honk_composer.hpp b/cpp/src/barretenberg/honk/composer/ultra_honk_composer.hpp new file mode 100644 index 0000000000..5fa40b4626 --- /dev/null +++ b/cpp/src/barretenberg/honk/composer/ultra_honk_composer.hpp @@ -0,0 +1,470 @@ +#pragma once +#include "barretenberg/plonk/composer/plookup_tables/plookup_tables.hpp" +#include "barretenberg/honk/proof_system/ultra_prover.hpp" +#include "barretenberg/proof_system/circuit_constructors/ultra_circuit_constructor.hpp" +#include "barretenberg/honk/composer/composer_helper/ultra_honk_composer_helper.hpp" +#include + +namespace proof_system::honk { + +class UltraHonkComposer { + + public: + // An instantiation of the circuit constructor that only depends on arithmetization, not on the proof system + UltraCircuitConstructor circuit_constructor; + // Composer helper contains all proof-related material that is separate from circuit creation such as: + // 1) Proving and verification keys + // 2) CRS + // 3) Converting variables to witness vectors/polynomials + UltraHonkComposerHelper composer_helper; + size_t& num_gates; + + UltraHonkComposer() + : UltraHonkComposer("../srs_db/ignition", 0){}; + + UltraHonkComposer(std::string const& crs_path, const size_t size_hint) + : UltraHonkComposer(std::unique_ptr(new FileReferenceStringFactory(crs_path)), + size_hint){}; + + UltraHonkComposer(std::shared_ptr const& crs_factory, const size_t size_hint) + : circuit_constructor(size_hint) + , composer_helper(crs_factory) + , num_gates(circuit_constructor.num_gates){}; + + UltraHonkComposer(std::shared_ptr const& p_key, + std::shared_ptr const& v_key, + size_t size_hint = 0); + UltraHonkComposer(UltraHonkComposer&& other) = default; + UltraHonkComposer& operator=(UltraHonkComposer&& other) = delete; + ~UltraHonkComposer() = default; + + uint32_t get_zero_idx() { return circuit_constructor.zero_idx; } + + uint32_t add_variable(const barretenberg::fr& in) { return circuit_constructor.add_variable(in); } + + barretenberg::fr get_variable(const uint32_t index) const { return circuit_constructor.get_variable(index); } + + void finalize_circuit() { circuit_constructor.finalize_circuit(); }; + + UltraProver create_prover() { return composer_helper.create_prover(circuit_constructor); }; + // UltraVerifier create_verifier() { return composer_helper.create_verifier(circuit_constructor); }; + + void create_add_gate(const add_triple& in) { circuit_constructor.create_add_gate(in); } + + void create_big_add_gate(const add_quad& in, const bool use_next_gate_w_4 = false) + { + circuit_constructor.create_big_add_gate(in, use_next_gate_w_4); + }; + + // void create_big_add_gate_with_bit_extraction(const add_quad& in); + // void create_big_mul_gate(const mul_quad& in); + // void create_balanced_add_gate(const add_quad& in); + + // void create_mul_gate(const mul_triple& in) override; + // void create_bool_gate(const uint32_t a) override; + // void create_poly_gate(const poly_triple& in) override; + void create_ecc_add_gate(const ecc_add_gate& in) { circuit_constructor.create_ecc_add_gate(in); }; + + // void fix_witness(const uint32_t witness_index, const barretenberg::fr& witness_value); + + // void add_recursive_proof(const std::vector& proof_output_witness_indices) + // { + // if (contains_recursive_proof) { + // failure("added recursive proof when one already exists"); + // } + // contains_recursive_proof = true; + + // for (const auto& idx : proof_output_witness_indices) { + // set_public_input(idx); + // recursive_proof_public_input_indices.push_back((uint32_t)(public_inputs.size() - 1)); + // } + // } + + void create_new_range_constraint(const uint32_t variable_index, + const uint64_t target_range, + std::string const msg = "create_new_range_constraint") + { + circuit_constructor.create_new_range_constraint(variable_index, target_range, msg); + }; + // void create_range_constraint(const uint32_t variable_index, const size_t num_bits, std::string const& msg) + // { + // if (num_bits <= DEFAULT_PLOOKUP_RANGE_BITNUM) { + // /** + // * N.B. if `variable_index` is not used in any arithmetic constraints, this will create an unsatisfiable + // * circuit! + // * this range constraint will increase the size of the 'sorted set' of range-constrained integers + // by 1. + // * The 'non-sorted set' of range-constrained integers is a subset of the wire indices of all + // arithmetic + // * gates. No arithemtic gate => size imbalance between sorted and non-sorted sets. Checking for this + // * and throwing an error would require a refactor of the Composer to catelog all 'orphan' variables + // not + // * assigned to gates. + // **/ + // create_new_range_constraint(variable_index, 1ULL << num_bits, msg); + // } else { + // decompose_into_default_range(variable_index, num_bits, DEFAULT_PLOOKUP_RANGE_BITNUM, msg); + // } + // } + + // accumulator_triple create_logic_constraint(const uint32_t a, + // const uint32_t b, + // const size_t num_bits, + // bool is_xor_gate); + // accumulator_triple create_and_constraint(const uint32_t a, const uint32_t b, const size_t num_bits); + // accumulator_triple create_xor_constraint(const uint32_t a, const uint32_t b, const size_t num_bits); + + // uint32_t put_constant_variable(const barretenberg::fr& variable); + + // size_t get_num_constant_gates() const override { return 0; } + + // /** + // * @brief Get the final number of gates in a circuit, which consists of the sum of: + // * 1) Current number number of actual gates + // * 2) Number of public inputs, as we'll need to add a gate for each of them + // * 3) Number of Rom array-associated gates + // * 4) NUmber of range-list associated gates + // * + // * + // * @param count return arument, number of existing gates + // * @param rangecount return argument, extra gates due to range checks + // * @param romcount return argument, extra gates due to rom reads + // * @param ramcount return argument, extra gates due to ram read/writes + // */ + // void get_num_gates_split_into_components(size_t& count, + // size_t& rangecount, + // size_t& romcount, + // size_t& ramcount) const + // { + // count = num_gates; + // // each ROM gate adds +1 extra gate due to the rom reads being copied to a sorted list set + // for (size_t i = 0; i < rom_arrays.size(); ++i) { + // for (size_t j = 0; j < rom_arrays[i].state.size(); ++j) { + // if (rom_arrays[i].state[j][0] == UNINITIALIZED_MEMORY_RECORD) { + // romcount += 2; + // } + // } + // romcount += (rom_arrays[i].records.size()); + // romcount += 1; // we add an addition gate after procesing a rom array + // } + + // constexpr size_t gate_width = ultra_settings::program_width; + // // each RAM gate adds +2 extra gates due to the ram reads being copied to a sorted list set, + // // as well as an extra gate to validate timestamps + // std::vector ram_timestamps; + // std::vector ram_range_sizes; + // std::vector ram_range_exists; + // for (size_t i = 0; i < ram_arrays.size(); ++i) { + // for (size_t j = 0; j < ram_arrays[i].state.size(); ++j) { + // if (ram_arrays[i].state[j] == UNINITIALIZED_MEMORY_RECORD) { + // ramcount += NUMBER_OF_GATES_PER_RAM_ACCESS; + // } + // } + // ramcount += (ram_arrays[i].records.size() * NUMBER_OF_GATES_PER_RAM_ACCESS); + // ramcount += NUMBER_OF_ARITHMETIC_GATES_PER_RAM_ARRAY; // we add an addition gate after procesing a ram + // array + + // // there will be 'max_timestamp' number of range checks, need to calculate. + // const auto max_timestamp = ram_arrays[i].access_count - 1; + + // // if a range check of length `max_timestamp` already exists, we are double counting. + // // We record `ram_timestamps` to detect and correct for this error when we process range lists. + // ram_timestamps.push_back(max_timestamp); + // size_t padding = (gate_width - (max_timestamp % gate_width)) % gate_width; + // if (max_timestamp == gate_width) + // padding += gate_width; + // const size_t ram_range_check_list_size = max_timestamp + padding; + + // size_t ram_range_check_gate_count = (ram_range_check_list_size / gate_width); + // ram_range_check_gate_count += 1; // we need to add 1 extra addition gates for every distinct range list + + // ram_range_sizes.push_back(ram_range_check_gate_count); + // ram_range_exists.push_back(false); + // // rangecount += ram_range_check_gate_count; + // } + // for (const auto& list : range_lists) { + // auto list_size = list.second.variable_indices.size(); + // size_t padding = (gate_width - (list.second.variable_indices.size() % gate_width)) % gate_width; + // if (list.second.variable_indices.size() == gate_width) + // padding += gate_width; + // list_size += padding; + + // for (size_t i = 0; i < ram_timestamps.size(); ++i) { + // if (list.second.target_range == ram_timestamps[i]) { + // ram_range_exists[i] = true; + // } + // } + // rangecount += (list_size / gate_width); + // rangecount += 1; // we need to add 1 extra addition gates for every distinct range list + // } + // // update rangecount to include the ram range checks the composer will eventually be creating + // for (size_t i = 0; i < ram_range_sizes.size(); ++i) { + // if (!ram_range_exists[i]) { + // rangecount += ram_range_sizes[i]; + // } + // } + // } + + // /** + // * @brief Get the final number of gates in a circuit, which consists of the sum of: + // * 1) Current number number of actual gates + // * 2) Number of public inputs, as we'll need to add a gate for each of them + // * 3) Number of Rom array-associated gates + // * 4) NUmber of range-list associated gates + // * + // * @return size_t + // */ + // virtual size_t get_num_gates() const override + // { + // // if circuit finalised already added extra gates + // if (circuit_finalised) { + // return num_gates; + // } + // size_t count = 0; + // size_t rangecount = 0; + // size_t romcount = 0; + // size_t ramcount = 0; + // get_num_gates_split_into_components(count, rangecount, romcount, ramcount); + // return count + romcount + ramcount + rangecount; + // } + + // virtual void print_num_gates() const override + // { + // size_t count = 0; + // size_t rangecount = 0; + // size_t romcount = 0; + // size_t ramcount = 0; + + // get_num_gates_split_into_components(count, rangecount, romcount, ramcount); + + // size_t total = count + romcount + ramcount + rangecount; + // std::cout << "gates = " << total << " (arith " << count << ", rom " << romcount << ", ram " << ramcount + // << ", range " << rangecount << "), pubinp = " << public_inputs.size() << std::endl; + // } + + void assert_equal(const uint32_t a_variable_idx, + const uint32_t b_variable_idx, + std::string const& msg = "assert_equal") + { + circuit_constructor.assert_equal(a_variable_idx, b_variable_idx, msg); + } + + // void assert_equal_constant(const uint32_t a_idx, + // const barretenberg::fr& b, + // std::string const& msg = "assert equal constant") + // { + // if (variables[a_idx] != b && !failed()) { + // failure(msg); + // } + // auto b_idx = put_constant_variable(b); + // assert_equal(a_idx, b_idx, msg); + // } + + // /** + // * Plookup Methods + // **/ + // void add_table_column_selector_poly_to_proving_key(polynomial& small, const std::string& tag); + // void initialize_precomputed_table( + // const plookup::BasicTableId id, + // bool (*generator)(std::vector&, + // std::vector&, + // std::vector&), + // std::array (*get_values_from_key)(const std::array)); + + // plookup::BasicTable& get_table(const plookup::BasicTableId id); + // plookup::MultiTable& create_table(const plookup::MultiTableId id); + + plookup::ReadData create_gates_from_plookup_accumulators( + const plookup::MultiTableId& id, + const plookup::ReadData& read_values, + const uint32_t key_a_index, + std::optional key_b_index = std::nullopt) + { + return circuit_constructor.create_gates_from_plookup_accumulators(id, read_values, key_a_index, key_b_index); + }; + + // /** + // * Generalized Permutation Methods + // **/ + std::vector decompose_into_default_range( + const uint32_t variable_index, + const uint64_t num_bits, + const uint64_t target_range_bitnum = DEFAULT_PLOOKUP_RANGE_BITNUM, + std::string const& msg = "decompose_into_default_range") + { + return circuit_constructor.decompose_into_default_range(variable_index, num_bits, target_range_bitnum, msg); + }; + // std::vector decompose_into_default_range_better_for_oddlimbnum( + // const uint32_t variable_index, + // const size_t num_bits, + // std::string const& msg = "decompose_into_default_range_better_for_oddlimbnum"); + void create_dummy_constraints(const std::vector& variable_index) + { + circuit_constructor.create_dummy_constraints(variable_index); + }; + void create_sort_constraint(const std::vector& variable_index) + { + circuit_constructor.create_sort_constraint(variable_index); + }; + void create_sort_constraint_with_edges(const std::vector& variable_index, + const barretenberg::fr& start, + const barretenberg::fr& end) + { + circuit_constructor.create_sort_constraint_with_edges(variable_index, start, end); + }; + + void assign_tag(const uint32_t variable_index, const uint32_t tag) + { + circuit_constructor.assign_tag(variable_index, tag); + } + + // void assign_tag(const uint32_t variable_index, const uint32_t tag) + // { + // ASSERT(tag <= current_tag); + // ASSERT(real_variable_tags[real_variable_index[variable_index]] == DUMMY_TAG); + // real_variable_tags[real_variable_index[variable_index]] = tag; + // } + + uint32_t create_tag(const uint32_t tag_index, const uint32_t tau_index) + { + return circuit_constructor.create_tag(tag_index, tau_index); + } + + // uint32_t get_new_tag() + // { + // current_tag++; + // return current_tag; + // } + + // RangeList create_range_list(const uint64_t target_range); + // void process_range_list(const RangeList& list); + // void process_range_lists(); + + // /** + // * Custom Gate Selectors + // **/ + // void apply_aux_selectors(const AUX_SELECTORS type); + + // /** + // * Non Native Field Arithmetic + // **/ + void range_constrain_two_limbs(const uint32_t lo_idx, + const uint32_t hi_idx, + const size_t lo_limb_bits = DEFAULT_NON_NATIVE_FIELD_LIMB_BITS, + const size_t hi_limb_bits = DEFAULT_NON_NATIVE_FIELD_LIMB_BITS) + { + circuit_constructor.range_constrain_two_limbs(lo_idx, hi_idx, lo_limb_bits, hi_limb_bits); + }; + // std::array decompose_non_native_field_double_width_limb( + // const uint32_t limb_idx, const size_t num_limb_bits = (2 * DEFAULT_NON_NATIVE_FIELD_LIMB_BITS)); + std::array evaluate_non_native_field_multiplication( + const non_native_field_witnesses& input, const bool range_constrain_quotient_and_remainder = true) + { + return circuit_constructor.evaluate_non_native_field_multiplication(input, + range_constrain_quotient_and_remainder); + }; + // std::array evaluate_partial_non_native_field_multiplication(const non_native_field_witnesses& + // input); typedef std::pair scaled_witness; typedef std::tuple add_simple; std::array evaluate_non_native_field_subtraction( + // add_simple limb0, + // add_simple limb1, + // add_simple limb2, + // add_simple limb3, + // std::tuple limbp); + // std::array evaluate_non_native_field_addition(add_simple limb0, + // add_simple limb1, + // add_simple limb2, + // add_simple limb3, + // std::tuple + // limbp); + + // /** + // * Memory + // **/ + + size_t create_RAM_array(const size_t array_size) { return circuit_constructor.create_RAM_array(array_size); }; + size_t create_ROM_array(const size_t array_size) { return circuit_constructor.create_ROM_array(array_size); }; + + void set_ROM_element(const size_t rom_id, const size_t index_value, const uint32_t value_witness) + { + circuit_constructor.set_ROM_element(rom_id, index_value, value_witness); + }; + // void set_ROM_element_pair(const size_t rom_id, + // const size_t index_value, + // const std::array& value_witnesses); + uint32_t read_ROM_array(const size_t rom_id, const uint32_t index_witness) + { + return circuit_constructor.read_ROM_array(rom_id, index_witness); + }; + // std::array read_ROM_array_pair(const size_t rom_id, const uint32_t index_witness); + // void create_ROM_gate(RomRecord& record); + // void create_sorted_ROM_gate(RomRecord& record); + // void process_ROM_array(const size_t rom_id, const size_t gate_offset_from_public_inputs); + // void process_ROM_arrays(const size_t gate_offset_from_public_inputs); + + // void create_RAM_gate(RamRecord& record); + // void create_sorted_RAM_gate(RamRecord& record); + // void create_final_sorted_RAM_gate(RamRecord& record, const size_t ram_array_size); + + // size_t create_RAM_array(const size_t array_size); + void init_RAM_element(const size_t ram_id, const size_t index_value, const uint32_t value_witness) + { + circuit_constructor.init_RAM_element(ram_id, index_value, value_witness); + }; + uint32_t read_RAM_array(const size_t ram_id, const uint32_t index_witness) + { + return circuit_constructor.read_RAM_array(ram_id, index_witness); + }; + void write_RAM_array(const size_t ram_id, const uint32_t index_witness, const uint32_t value_witness) + { + circuit_constructor.write_RAM_array(ram_id, index_witness, value_witness); + }; + // void process_RAM_array(const size_t ram_id, const size_t gate_offset_from_public_inputs); + // void process_RAM_arrays(const size_t gate_offset_from_public_inputs); + + // /** + // * Member Variables + // **/ + + // uint32_t zero_idx = 0; + bool circuit_finalised = false; + + // // This variable controls the amount with which the lookup table and witness values need to be shifted + // // above to make room for adding randomness into the permutation and witness polynomials in the plookup widget. + // // This must be (num_roots_cut_out_of_the_vanishing_polynomial - 1), since the variable num_roots_cut_out_of_ + // // vanishing_polynomial cannot be trivially fetched here, I am directly setting this to 4 - 1 = 3. + // static constexpr size_t s_randomness = 3; + + // // these are variables that we have used a gate on, to enforce that they are equal to a defined value + // std::map constant_variable_indices; + + // std::vector lookup_tables; + // std::vector lookup_multi_tables; + // std::map range_lists; // DOCTODO: explain this. + + // /** + // * @brief Each entry in ram_arrays represents an independent RAM table. + // * RamTranscript tracks the current table state, + // * as well as the 'records' produced by each read and write operation. + // * Used in `compute_proving_key` to generate consistency check gates required to validate the RAM read/write + // history + // */ + // std::vector ram_arrays; + + // /** + // * @brief Each entry in ram_arrays represents an independent ROM table. + // * RomTranscript tracks the current table state, + // * as well as the 'records' produced by each read operation. + // * Used in `compute_proving_key` to generate consistency check gates required to validate the ROM read history + // */ + // std::vector rom_arrays; + + // // Stores gate index of ROM and RAM reads (required by proving key) + // std::vector memory_read_records; + // // Stores gate index of RAM writes (required by proving key) + // std::vector memory_write_records; + + // std::vector recursive_proof_public_input_indices; + // bool contains_recursive_proof = false; +}; +} // namespace proof_system::honk diff --git a/cpp/src/barretenberg/honk/composer/ultra_honk_composer.test.cpp b/cpp/src/barretenberg/honk/composer/ultra_honk_composer.test.cpp new file mode 100644 index 0000000000..142562ac98 --- /dev/null +++ b/cpp/src/barretenberg/honk/composer/ultra_honk_composer.test.cpp @@ -0,0 +1,1018 @@ +#include "ultra_honk_composer.hpp" +#include "barretenberg/common/log.hpp" +#include "barretenberg/honk/proof_system/ultra_prover.hpp" +#include "barretenberg/honk/sumcheck/relations/relation.hpp" +#include "barretenberg/numeric/uint256/uint256.hpp" +#include "barretenberg/honk/flavor/flavor.hpp" +#include +#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" + +// TODO(luke): TEMPORARY; for testing only (comparison with Ultra Plonk composers) +#include "barretenberg/plonk/composer/ultra_composer.hpp" +#include "barretenberg/plonk/composer/splitting_tmp/ultra_plonk_composer.hpp" +#include "barretenberg/plonk/proof_system/prover/prover.hpp" + +#include +#include + +using namespace proof_system::honk; + +namespace test_ultra_honk_composer { + +std::vector add_variables(auto& composer, std::vector variables) +{ + std::vector res; + for (size_t i = 0; i < variables.size(); i++) { + res.emplace_back(composer.add_variable(variables[i])); + } + return res; +} + +/** + * @brief TEMPORARY method for checking consistency of polynomials computed by Ultra Plonk/Honk composers + * + * @param honk_prover + * @param plonk_prover + */ +void verify_consistency(honk::UltraProver& honk_prover, plonk::UltraProver& plonk_prover) +{ + // 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; + if (plonk_store.contains(key)) { + ASSERT_EQ(honk_store.get(key), plonk_store.get(key)); + } + } + + // Check that all wires agree + 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)); + } +} + +/** + * @brief TEMPORARY (verbose) method for checking consistency of polynomials computed by Ultra Plonk/Honk composers + * + * @param honk_prover + * @param plonk_prover + */ +void check_consistency(honk::UltraProver& honk_prover, plonk::UltraProver& plonk_prover) +{ + 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)) { + // info(key); + + bool polys_equal = (honk_store.get(key) == plonk_store.get(key)); + if (polys_equal) { + info("Equal: ", key); + } + 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); } + } + } + + for (size_t i = 0; i < 4; ++i) { + std::string label = "w_" + std::to_string(i + 1) + "_lagrange"; + bool wire_equal = (honk_prover.wire_polynomials[i] == plonk_prover.key->polynomial_store.get(label)); + if (wire_equal) { + info("Wire Equal: ", i); + } + if (!wire_equal) { + info("Wire UNEQUAL: ", i); + } + } + + // std::string label = "w_1_lagrange"; + // for (size_t i = 0; i < plonk_store.get(label).size(); ++i) { + // auto val_honk = honk_prover.wire_polynomials[0][i]; + // // auto val_honk = honk_store.get(label)[i]; + // auto val_plonk = plonk_store.get(label)[i]; + // if (val_honk != val_plonk) { + // info("UNEQUAL index = ", i); + // info("honk: ",val_honk); + // info("plonk: ", val_plonk); + // } + // } +} + +TEST(UltraHonkComposer, create_gates_from_plookup_accumulators) +{ + auto honk_composer = UltraHonkComposer(); + auto plonk_composer = proof_system::plonk::UltraComposer(); + + barretenberg::fr input_value = fr::random_element(); + { + + const fr input_hi = uint256_t(input_value).slice(126, 256); + const fr input_lo = uint256_t(input_value).slice(0, 126); + const auto input_hi_index = honk_composer.add_variable(input_hi); + const auto input_lo_index = honk_composer.add_variable(input_lo); + + const auto sequence_data_hi = + plookup::get_lookup_accumulators(plookup::MultiTableId::PEDERSEN_LEFT_HI, input_hi); + const auto sequence_data_lo = + plookup::get_lookup_accumulators(plookup::MultiTableId::PEDERSEN_LEFT_LO, input_lo); + + const auto lookup_witnesses_hi = honk_composer.create_gates_from_plookup_accumulators( + plookup::MultiTableId::PEDERSEN_LEFT_HI, sequence_data_hi, input_hi_index); + const auto lookup_witnesses_lo = honk_composer.create_gates_from_plookup_accumulators( + plookup::MultiTableId::PEDERSEN_LEFT_LO, sequence_data_lo, input_lo_index); + } + { + const fr input_hi = uint256_t(input_value).slice(126, 256); + const fr input_lo = uint256_t(input_value).slice(0, 126); + const auto input_hi_index = plonk_composer.add_variable(input_hi); + const auto input_lo_index = plonk_composer.add_variable(input_lo); + + const auto sequence_data_hi = + plookup::get_lookup_accumulators(plookup::MultiTableId::PEDERSEN_LEFT_HI, input_hi); + const auto sequence_data_lo = + plookup::get_lookup_accumulators(plookup::MultiTableId::PEDERSEN_LEFT_LO, input_lo); + + const auto lookup_witnesses_hi = plonk_composer.create_gates_from_plookup_accumulators( + plookup::MultiTableId::PEDERSEN_LEFT_HI, sequence_data_hi, input_hi_index); + const auto lookup_witnesses_lo = plonk_composer.create_gates_from_plookup_accumulators( + plookup::MultiTableId::PEDERSEN_LEFT_LO, sequence_data_lo, input_lo_index); + } + + auto honk_prover = honk_composer.create_prover(); + auto plonk_prover = plonk_composer.create_prover(); + + verify_consistency(honk_prover, plonk_prover); +} + +/** + * @brief Build UltraHonkComposer + * + */ +TEST(UltraHonkComposer, test_no_lookup_proof) +{ + auto honk_composer = UltraHonkComposer(); + auto plonk_composer = proof_system::plonk::UltraComposer(); + + size_t MM = 4; + for (size_t i = 0; i < MM; ++i) { + for (size_t j = 0; j < MM; ++j) { + uint64_t left = static_cast(j); + uint64_t right = static_cast(i); + uint32_t left_idx = honk_composer.add_variable(fr(left)); + uint32_t right_idx = honk_composer.add_variable(fr(right)); + uint32_t result_idx = honk_composer.add_variable(fr(left ^ right)); + + uint32_t add_idx = + honk_composer.add_variable(fr(left) + fr(right) + honk_composer.get_variable(result_idx)); + honk_composer.create_big_add_gate( + { left_idx, right_idx, result_idx, add_idx, fr(1), fr(1), fr(1), fr(-1), fr(0) }); + } + } + + for (size_t i = 0; i < MM; ++i) { + for (size_t j = 0; j < MM; ++j) { + uint64_t left = static_cast(j); + uint64_t right = static_cast(i); + uint32_t left_idx = plonk_composer.add_variable(fr(left)); + uint32_t right_idx = plonk_composer.add_variable(fr(right)); + uint32_t result_idx = plonk_composer.add_variable(fr(left ^ right)); + + uint32_t add_idx = + plonk_composer.add_variable(fr(left) + fr(right) + plonk_composer.get_variable(result_idx)); + plonk_composer.create_big_add_gate( + { left_idx, right_idx, result_idx, add_idx, fr(1), fr(1), fr(1), fr(-1), fr(0) }); + } + } + + auto honk_prover = honk_composer.create_prover(); + auto plonk_prover = plonk_composer.create_prover(); + + verify_consistency(honk_prover, plonk_prover); +} + +TEST(UltraHonkComposer, test_elliptic_gate) +{ + typedef grumpkin::g1::affine_element affine_element; + typedef grumpkin::g1::element element; + + auto honk_composer = UltraHonkComposer(); + auto plonk_composer = proof_system::plonk::UltraComposer(); + + { + affine_element p1 = crypto::generators::get_generator_data({ 0, 0 }).generator; + affine_element p2 = crypto::generators::get_generator_data({ 0, 1 }).generator; + affine_element p3(element(p1) + element(p2)); + + uint32_t x1 = honk_composer.add_variable(p1.x); + uint32_t y1 = honk_composer.add_variable(p1.y); + uint32_t x2 = honk_composer.add_variable(p2.x); + uint32_t y2 = honk_composer.add_variable(p2.y); + uint32_t x3 = honk_composer.add_variable(p3.x); + uint32_t y3 = honk_composer.add_variable(p3.y); + + ecc_add_gate gate{ x1, y1, x2, y2, x3, y3, 1, 1 }; + honk_composer.create_ecc_add_gate(gate); + + grumpkin::fq beta = grumpkin::fq::cube_root_of_unity(); + affine_element p2_endo = p2; + p2_endo.x *= beta; + p3 = affine_element(element(p1) + element(p2_endo)); + x3 = honk_composer.add_variable(p3.x); + y3 = honk_composer.add_variable(p3.y); + gate = ecc_add_gate{ x1, y1, x2, y2, x3, y3, beta, 1 }; + honk_composer.create_ecc_add_gate(gate); + + p2_endo.x *= beta; + p3 = affine_element(element(p1) - element(p2_endo)); + x3 = honk_composer.add_variable(p3.x); + y3 = honk_composer.add_variable(p3.y); + gate = ecc_add_gate{ x1, y1, x2, y2, x3, y3, beta.sqr(), -1 }; + honk_composer.create_ecc_add_gate(gate); + } + { + affine_element p1 = crypto::generators::get_generator_data({ 0, 0 }).generator; + affine_element p2 = crypto::generators::get_generator_data({ 0, 1 }).generator; + affine_element p3(element(p1) + element(p2)); + + uint32_t x1 = plonk_composer.add_variable(p1.x); + uint32_t y1 = plonk_composer.add_variable(p1.y); + uint32_t x2 = plonk_composer.add_variable(p2.x); + uint32_t y2 = plonk_composer.add_variable(p2.y); + uint32_t x3 = plonk_composer.add_variable(p3.x); + uint32_t y3 = plonk_composer.add_variable(p3.y); + + ecc_add_gate gate{ x1, y1, x2, y2, x3, y3, 1, 1 }; + plonk_composer.create_ecc_add_gate(gate); + + grumpkin::fq beta = grumpkin::fq::cube_root_of_unity(); + affine_element p2_endo = p2; + p2_endo.x *= beta; + p3 = affine_element(element(p1) + element(p2_endo)); + x3 = plonk_composer.add_variable(p3.x); + y3 = plonk_composer.add_variable(p3.y); + gate = ecc_add_gate{ x1, y1, x2, y2, x3, y3, beta, 1 }; + plonk_composer.create_ecc_add_gate(gate); + + p2_endo.x *= beta; + p3 = affine_element(element(p1) - element(p2_endo)); + x3 = plonk_composer.add_variable(p3.x); + y3 = plonk_composer.add_variable(p3.y); + gate = ecc_add_gate{ x1, y1, x2, y2, x3, y3, beta.sqr(), -1 }; + plonk_composer.create_ecc_add_gate(gate); + } + + auto honk_prover = honk_composer.create_prover(); + auto plonk_prover = plonk_composer.create_prover(); + + verify_consistency(honk_prover, plonk_prover); +} + +TEST(UltraHonkComposer, non_trivial_tag_permutation) +{ + auto honk_composer = UltraHonkComposer(); + auto plonk_composer = proof_system::plonk::UltraComposer(); + + fr a = fr::random_element(); + { + fr b = -a; + + auto a_idx = honk_composer.add_variable(a); + auto b_idx = honk_composer.add_variable(b); + auto c_idx = honk_composer.add_variable(b); + auto d_idx = honk_composer.add_variable(a); + + honk_composer.create_add_gate( + { a_idx, b_idx, honk_composer.get_zero_idx(), fr::one(), fr::one(), fr::zero(), fr::zero() }); + honk_composer.create_add_gate( + { c_idx, d_idx, honk_composer.get_zero_idx(), fr::one(), fr::one(), fr::zero(), fr::zero() }); + + honk_composer.create_tag(1, 2); + honk_composer.create_tag(2, 1); + + honk_composer.assign_tag(a_idx, 1); + honk_composer.assign_tag(b_idx, 1); + honk_composer.assign_tag(c_idx, 2); + honk_composer.assign_tag(d_idx, 2); + } + { + fr b = -a; + + auto a_idx = plonk_composer.add_variable(a); + auto b_idx = plonk_composer.add_variable(b); + auto c_idx = plonk_composer.add_variable(b); + auto d_idx = plonk_composer.add_variable(a); + + plonk_composer.create_add_gate( + { a_idx, b_idx, plonk_composer.zero_idx, fr::one(), fr::one(), fr::zero(), fr::zero() }); + plonk_composer.create_add_gate( + { c_idx, d_idx, plonk_composer.zero_idx, fr::one(), fr::one(), fr::zero(), fr::zero() }); + + plonk_composer.create_tag(1, 2); + plonk_composer.create_tag(2, 1); + + plonk_composer.assign_tag(a_idx, 1); + plonk_composer.assign_tag(b_idx, 1); + plonk_composer.assign_tag(c_idx, 2); + plonk_composer.assign_tag(d_idx, 2); + } + + auto honk_prover = honk_composer.create_prover(); + auto plonk_prover = plonk_composer.create_prover(); + + verify_consistency(honk_prover, plonk_prover); +} + +TEST(UltraHonkComposer, non_trivial_tag_permutation_and_cycles) +{ + auto honk_composer = UltraHonkComposer(); + auto plonk_composer = proof_system::plonk::UltraComposer(); + + fr a = fr::random_element(); + { + fr c = -a; + + auto a_idx = honk_composer.add_variable(a); + auto b_idx = honk_composer.add_variable(a); + honk_composer.assert_equal(a_idx, b_idx); + auto c_idx = honk_composer.add_variable(c); + auto d_idx = honk_composer.add_variable(c); + honk_composer.assert_equal(c_idx, d_idx); + auto e_idx = honk_composer.add_variable(a); + auto f_idx = honk_composer.add_variable(a); + honk_composer.assert_equal(e_idx, f_idx); + auto g_idx = honk_composer.add_variable(c); + auto h_idx = honk_composer.add_variable(c); + honk_composer.assert_equal(g_idx, h_idx); + + honk_composer.create_tag(1, 2); + honk_composer.create_tag(2, 1); + + honk_composer.assign_tag(a_idx, 1); + honk_composer.assign_tag(c_idx, 1); + honk_composer.assign_tag(e_idx, 2); + honk_composer.assign_tag(g_idx, 2); + + honk_composer.create_add_gate( + { b_idx, a_idx, honk_composer.get_zero_idx(), fr::one(), fr::neg_one(), fr::zero(), fr::zero() }); + honk_composer.create_add_gate( + { c_idx, g_idx, honk_composer.get_zero_idx(), fr::one(), -fr::one(), fr::zero(), fr::zero() }); + honk_composer.create_add_gate( + { e_idx, f_idx, honk_composer.get_zero_idx(), fr::one(), -fr::one(), fr::zero(), fr::zero() }); + } + { + fr c = -a; + + auto a_idx = plonk_composer.add_variable(a); + auto b_idx = plonk_composer.add_variable(a); + plonk_composer.assert_equal(a_idx, b_idx); + auto c_idx = plonk_composer.add_variable(c); + auto d_idx = plonk_composer.add_variable(c); + plonk_composer.assert_equal(c_idx, d_idx); + auto e_idx = plonk_composer.add_variable(a); + auto f_idx = plonk_composer.add_variable(a); + plonk_composer.assert_equal(e_idx, f_idx); + auto g_idx = plonk_composer.add_variable(c); + auto h_idx = plonk_composer.add_variable(c); + plonk_composer.assert_equal(g_idx, h_idx); + + plonk_composer.create_tag(1, 2); + plonk_composer.create_tag(2, 1); + + plonk_composer.assign_tag(a_idx, 1); + plonk_composer.assign_tag(c_idx, 1); + plonk_composer.assign_tag(e_idx, 2); + plonk_composer.assign_tag(g_idx, 2); + + plonk_composer.create_add_gate( + { b_idx, a_idx, plonk_composer.zero_idx, fr::one(), fr::neg_one(), fr::zero(), fr::zero() }); + plonk_composer.create_add_gate( + { c_idx, g_idx, plonk_composer.zero_idx, fr::one(), -fr::one(), fr::zero(), fr::zero() }); + plonk_composer.create_add_gate( + { e_idx, f_idx, plonk_composer.zero_idx, fr::one(), -fr::one(), fr::zero(), fr::zero() }); + } + + auto honk_prover = honk_composer.create_prover(); + auto plonk_prover = plonk_composer.create_prover(); + + verify_consistency(honk_prover, plonk_prover); +} + +TEST(UltraHonkComposer, bad_tag_permutation) +{ + auto honk_composer = UltraHonkComposer(); + auto plonk_composer = proof_system::plonk::UltraComposer(); + + fr a = fr::random_element(); + { + fr b = -a; + + auto a_idx = honk_composer.add_variable(a); + auto b_idx = honk_composer.add_variable(b); + auto c_idx = honk_composer.add_variable(b); + auto d_idx = honk_composer.add_variable(a + 1); + + honk_composer.create_add_gate({ a_idx, b_idx, honk_composer.get_zero_idx(), 1, 1, 0, 0 }); + honk_composer.create_add_gate({ c_idx, d_idx, honk_composer.get_zero_idx(), 1, 1, 0, -1 }); + + honk_composer.create_tag(1, 2); + honk_composer.create_tag(2, 1); + + honk_composer.assign_tag(a_idx, 1); + honk_composer.assign_tag(b_idx, 1); + honk_composer.assign_tag(c_idx, 2); + honk_composer.assign_tag(d_idx, 2); + } + { + fr b = -a; + + auto a_idx = plonk_composer.add_variable(a); + auto b_idx = plonk_composer.add_variable(b); + auto c_idx = plonk_composer.add_variable(b); + auto d_idx = plonk_composer.add_variable(a + 1); + + plonk_composer.create_add_gate({ a_idx, b_idx, plonk_composer.zero_idx, 1, 1, 0, 0 }); + plonk_composer.create_add_gate({ c_idx, d_idx, plonk_composer.zero_idx, 1, 1, 0, -1 }); + + plonk_composer.create_tag(1, 2); + plonk_composer.create_tag(2, 1); + + plonk_composer.assign_tag(a_idx, 1); + plonk_composer.assign_tag(b_idx, 1); + plonk_composer.assign_tag(c_idx, 2); + plonk_composer.assign_tag(d_idx, 2); + } + + auto honk_prover = honk_composer.create_prover(); + auto plonk_prover = plonk_composer.create_prover(); + + verify_consistency(honk_prover, plonk_prover); +} + +TEST(UltraHonkComposer, sort_widget) +{ + auto honk_composer = UltraHonkComposer(); + auto plonk_composer = proof_system::plonk::UltraComposer(); + + { + fr a = fr::one(); + fr b = fr(2); + fr c = fr(3); + fr d = fr(4); + + auto a_idx = honk_composer.add_variable(a); + auto b_idx = honk_composer.add_variable(b); + auto c_idx = honk_composer.add_variable(c); + auto d_idx = honk_composer.add_variable(d); + honk_composer.create_sort_constraint({ a_idx, b_idx, c_idx, d_idx }); + } + { + fr a = fr::one(); + fr b = fr(2); + fr c = fr(3); + fr d = fr(4); + + auto a_idx = plonk_composer.add_variable(a); + auto b_idx = plonk_composer.add_variable(b); + auto c_idx = plonk_composer.add_variable(c); + auto d_idx = plonk_composer.add_variable(d); + plonk_composer.create_sort_constraint({ a_idx, b_idx, c_idx, d_idx }); + } + + auto honk_prover = honk_composer.create_prover(); + auto plonk_prover = plonk_composer.create_prover(); + + verify_consistency(honk_prover, plonk_prover); +} + +TEST(UltraHonkComposer, sort_with_edges_gate) +{ + auto honk_composer = UltraHonkComposer(); + auto plonk_composer = proof_system::plonk::UltraComposer(); + + { + auto idx = add_variables(honk_composer, { 1, 2, 5, 6, 7, 10, 11, 13, 16, 17, 20, 22, 22, 25, + 26, 29, 29, 32, 32, 33, 35, 38, 39, 39, 42, 42, 43, 45 }); + + honk_composer.create_sort_constraint_with_edges(idx, 1, 29); + } + { + auto idx = add_variables(plonk_composer, { 1, 2, 5, 6, 7, 10, 11, 13, 16, 17, 20, 22, 22, 25, + 26, 29, 29, 32, 32, 33, 35, 38, 39, 39, 42, 42, 43, 45 }); + + plonk_composer.create_sort_constraint_with_edges(idx, 1, 29); + } + + auto honk_prover = honk_composer.create_prover(); + auto plonk_prover = plonk_composer.create_prover(); + + verify_consistency(honk_prover, plonk_prover); +} + +TEST(UltraHonkComposer, range_constraint) +{ + auto honk_composer = UltraHonkComposer(); + auto plonk_composer = proof_system::plonk::UltraComposer(); + + { + auto indices = + add_variables(honk_composer, { 1, 0, 3, 80, 5, 6, 29, 8, 15, 11, 32, 21, 42, 79, 16, 10, 3, 26, 13, 14 }); + for (size_t i = 0; i < indices.size(); i++) { + honk_composer.create_new_range_constraint(indices[i], 79); + } + honk_composer.create_dummy_constraints(indices); + } + { + auto indices = + add_variables(plonk_composer, { 1, 0, 3, 80, 5, 6, 29, 8, 15, 11, 32, 21, 42, 79, 16, 10, 3, 26, 13, 14 }); + for (size_t i = 0; i < indices.size(); i++) { + plonk_composer.create_new_range_constraint(indices[i], 79); + } + plonk_composer.create_dummy_constraints(indices); + } + + auto honk_prover = honk_composer.create_prover(); + auto plonk_prover = plonk_composer.create_prover(); + + verify_consistency(honk_prover, plonk_prover); +} + +TEST(UltraHonkComposer, range_with_gates) +{ + + auto honk_composer = UltraHonkComposer(); + auto plonk_composer = proof_system::plonk::UltraComposer(); + + { + auto idx = add_variables(honk_composer, { 1, 2, 3, 4, 5, 6, 7, 8 }); + for (size_t i = 0; i < idx.size(); i++) { + honk_composer.create_new_range_constraint(idx[i], 8); + } + + honk_composer.create_add_gate( + { idx[0], idx[1], honk_composer.get_zero_idx(), fr::one(), fr::one(), fr::zero(), -3 }); + honk_composer.create_add_gate( + { idx[2], idx[3], honk_composer.get_zero_idx(), fr::one(), fr::one(), fr::zero(), -7 }); + honk_composer.create_add_gate( + { idx[4], idx[5], honk_composer.get_zero_idx(), fr::one(), fr::one(), fr::zero(), -11 }); + honk_composer.create_add_gate( + { idx[6], idx[7], honk_composer.get_zero_idx(), fr::one(), fr::one(), fr::zero(), -15 }); + } + { + auto idx = add_variables(plonk_composer, { 1, 2, 3, 4, 5, 6, 7, 8 }); + for (size_t i = 0; i < idx.size(); i++) { + plonk_composer.create_new_range_constraint(idx[i], 8); + } + + plonk_composer.create_add_gate( + { idx[0], idx[1], plonk_composer.zero_idx, fr::one(), fr::one(), fr::zero(), -3 }); + plonk_composer.create_add_gate( + { idx[2], idx[3], plonk_composer.zero_idx, fr::one(), fr::one(), fr::zero(), -7 }); + plonk_composer.create_add_gate( + { idx[4], idx[5], plonk_composer.zero_idx, fr::one(), fr::one(), fr::zero(), -11 }); + plonk_composer.create_add_gate( + { idx[6], idx[7], plonk_composer.zero_idx, fr::one(), fr::one(), fr::zero(), -15 }); + } + + auto honk_prover = honk_composer.create_prover(); + auto plonk_prover = plonk_composer.create_prover(); + + verify_consistency(honk_prover, plonk_prover); +} + +TEST(UltraHonkComposer, range_with_gates_where_range_is_not_a_power_of_two) +{ + auto honk_composer = UltraHonkComposer(); + auto plonk_composer = proof_system::plonk::UltraComposer(); + + { + auto idx = add_variables(honk_composer, { 1, 2, 3, 4, 5, 6, 7, 8 }); + for (size_t i = 0; i < idx.size(); i++) { + honk_composer.create_new_range_constraint(idx[i], 12); + } + + honk_composer.create_add_gate( + { idx[0], idx[1], honk_composer.get_zero_idx(), fr::one(), fr::one(), fr::zero(), -3 }); + honk_composer.create_add_gate( + { idx[2], idx[3], honk_composer.get_zero_idx(), fr::one(), fr::one(), fr::zero(), -7 }); + honk_composer.create_add_gate( + { idx[4], idx[5], honk_composer.get_zero_idx(), fr::one(), fr::one(), fr::zero(), -11 }); + honk_composer.create_add_gate( + { idx[6], idx[7], honk_composer.get_zero_idx(), fr::one(), fr::one(), fr::zero(), -15 }); + } + { + auto idx = add_variables(plonk_composer, { 1, 2, 3, 4, 5, 6, 7, 8 }); + for (size_t i = 0; i < idx.size(); i++) { + plonk_composer.create_new_range_constraint(idx[i], 12); + } + + plonk_composer.create_add_gate( + { idx[0], idx[1], plonk_composer.zero_idx, fr::one(), fr::one(), fr::zero(), -3 }); + plonk_composer.create_add_gate( + { idx[2], idx[3], plonk_composer.zero_idx, fr::one(), fr::one(), fr::zero(), -7 }); + plonk_composer.create_add_gate( + { idx[4], idx[5], plonk_composer.zero_idx, fr::one(), fr::one(), fr::zero(), -11 }); + plonk_composer.create_add_gate( + { idx[6], idx[7], plonk_composer.zero_idx, fr::one(), fr::one(), fr::zero(), -15 }); + } + + auto honk_prover = honk_composer.create_prover(); + auto plonk_prover = plonk_composer.create_prover(); + + verify_consistency(honk_prover, plonk_prover); +} + +TEST(UltraHonkComposer, sort_widget_complex) +{ + auto honk_composer = UltraHonkComposer(); + auto plonk_composer = proof_system::plonk::UltraComposer(); + + { + std::vector a = { 1, 3, 4, 7, 7, 8, 16, 14, 15, 15, 18, 19, 21, 21, 24, 25, 26, 27, 30, 32 }; + std::vector ind; + for (size_t i = 0; i < a.size(); i++) + ind.emplace_back(honk_composer.add_variable(a[i])); + honk_composer.create_sort_constraint(ind); + } + { + std::vector a = { 1, 3, 4, 7, 7, 8, 16, 14, 15, 15, 18, 19, 21, 21, 24, 25, 26, 27, 30, 32 }; + std::vector ind; + for (size_t i = 0; i < a.size(); i++) + ind.emplace_back(plonk_composer.add_variable(a[i])); + plonk_composer.create_sort_constraint(ind); + } + + auto honk_prover = honk_composer.create_prover(); + auto plonk_prover = plonk_composer.create_prover(); + + verify_consistency(honk_prover, plonk_prover); +} + +TEST(UltraHonkComposer, composed_range_constraint) +{ + auto honk_composer = UltraHonkComposer(); + auto plonk_composer = proof_system::plonk::UltraComposer(); + + auto c = fr::random_element(); + { + auto d = uint256_t(c).slice(0, 133); + auto e = fr(d); + auto a_idx = honk_composer.add_variable(fr(e)); + honk_composer.create_add_gate( + { a_idx, honk_composer.get_zero_idx(), honk_composer.get_zero_idx(), 1, 0, 0, -fr(e) }); + honk_composer.decompose_into_default_range(a_idx, 134); + } + { + auto d = uint256_t(c).slice(0, 133); + auto e = fr(d); + auto a_idx = plonk_composer.add_variable(fr(e)); + plonk_composer.create_add_gate({ a_idx, plonk_composer.zero_idx, plonk_composer.zero_idx, 1, 0, 0, -fr(e) }); + plonk_composer.decompose_into_default_range(a_idx, 134); + } + + auto honk_prover = honk_composer.create_prover(); + auto plonk_prover = plonk_composer.create_prover(); + + verify_consistency(honk_prover, plonk_prover); +} + +TEST(UltraHonkComposer, non_native_field_multiplication) +{ + auto honk_composer = UltraHonkComposer(); + auto plonk_composer = proof_system::plonk::UltraComposer(); + + fq a = fq::random_element(); + fq b = fq::random_element(); + { + uint256_t modulus = fq::modulus; + + uint1024_t a_big = uint512_t(uint256_t(a)); + uint1024_t b_big = uint512_t(uint256_t(b)); + uint1024_t p_big = uint512_t(uint256_t(modulus)); + + uint1024_t q_big = (a_big * b_big) / p_big; + uint1024_t r_big = (a_big * b_big) % p_big; + + uint256_t q(q_big.lo.lo); + uint256_t r(r_big.lo.lo); + + const auto split_into_limbs = [&](const uint512_t& input) { + constexpr size_t NUM_BITS = 68; + std::array limbs; + limbs[0] = input.slice(0, NUM_BITS).lo; + limbs[1] = input.slice(NUM_BITS * 1, NUM_BITS * 2).lo; + limbs[2] = input.slice(NUM_BITS * 2, NUM_BITS * 3).lo; + limbs[3] = input.slice(NUM_BITS * 3, NUM_BITS * 4).lo; + limbs[4] = fr(input.lo); + return limbs; + }; + + const auto get_limb_witness_indices = [&](const std::array& limbs) { + std::array limb_indices; + limb_indices[0] = honk_composer.add_variable(limbs[0]); + limb_indices[1] = honk_composer.add_variable(limbs[1]); + limb_indices[2] = honk_composer.add_variable(limbs[2]); + limb_indices[3] = honk_composer.add_variable(limbs[3]); + limb_indices[4] = honk_composer.add_variable(limbs[4]); + return limb_indices; + }; + const uint512_t BINARY_BASIS_MODULUS = uint512_t(1) << (68 * 4); + auto modulus_limbs = split_into_limbs(BINARY_BASIS_MODULUS - uint512_t(modulus)); + + const auto a_indices = get_limb_witness_indices(split_into_limbs(uint256_t(a))); + const auto b_indices = get_limb_witness_indices(split_into_limbs(uint256_t(b))); + const auto q_indices = get_limb_witness_indices(split_into_limbs(uint256_t(q))); + const auto r_indices = get_limb_witness_indices(split_into_limbs(uint256_t(r))); + + proof_system::non_native_field_witnesses inputs{ + a_indices, b_indices, q_indices, r_indices, modulus_limbs, fr(uint256_t(modulus)), + }; + const auto [lo_1_idx, hi_1_idx] = honk_composer.evaluate_non_native_field_multiplication(inputs); + honk_composer.range_constrain_two_limbs(lo_1_idx, hi_1_idx, 70, 70); + } + { + uint256_t modulus = fq::modulus; + + uint1024_t a_big = uint512_t(uint256_t(a)); + uint1024_t b_big = uint512_t(uint256_t(b)); + uint1024_t p_big = uint512_t(uint256_t(modulus)); + + uint1024_t q_big = (a_big * b_big) / p_big; + uint1024_t r_big = (a_big * b_big) % p_big; + + uint256_t q(q_big.lo.lo); + uint256_t r(r_big.lo.lo); + + const auto split_into_limbs = [&](const uint512_t& input) { + constexpr size_t NUM_BITS = 68; + std::array limbs; + limbs[0] = input.slice(0, NUM_BITS).lo; + limbs[1] = input.slice(NUM_BITS * 1, NUM_BITS * 2).lo; + limbs[2] = input.slice(NUM_BITS * 2, NUM_BITS * 3).lo; + limbs[3] = input.slice(NUM_BITS * 3, NUM_BITS * 4).lo; + limbs[4] = fr(input.lo); + return limbs; + }; + + const auto get_limb_witness_indices = [&](const std::array& limbs) { + std::array limb_indices; + limb_indices[0] = plonk_composer.add_variable(limbs[0]); + limb_indices[1] = plonk_composer.add_variable(limbs[1]); + limb_indices[2] = plonk_composer.add_variable(limbs[2]); + limb_indices[3] = plonk_composer.add_variable(limbs[3]); + limb_indices[4] = plonk_composer.add_variable(limbs[4]); + return limb_indices; + }; + const uint512_t BINARY_BASIS_MODULUS = uint512_t(1) << (68 * 4); + auto modulus_limbs = split_into_limbs(BINARY_BASIS_MODULUS - uint512_t(modulus)); + + const auto a_indices = get_limb_witness_indices(split_into_limbs(uint256_t(a))); + const auto b_indices = get_limb_witness_indices(split_into_limbs(uint256_t(b))); + const auto q_indices = get_limb_witness_indices(split_into_limbs(uint256_t(q))); + const auto r_indices = get_limb_witness_indices(split_into_limbs(uint256_t(r))); + + proof_system::plonk::UltraComposer::non_native_field_witnesses inputs{ + a_indices, b_indices, q_indices, r_indices, modulus_limbs, fr(uint256_t(modulus)), + }; + const auto [lo_1_idx, hi_1_idx] = plonk_composer.evaluate_non_native_field_multiplication(inputs); + plonk_composer.range_constrain_two_limbs(lo_1_idx, hi_1_idx, 70, 70); + } + + auto honk_prover = honk_composer.create_prover(); + auto plonk_prover = plonk_composer.create_prover(); + + verify_consistency(honk_prover, plonk_prover); +} + +TEST(UltraHonkComposer, rom) +{ + auto honk_composer = UltraHonkComposer(); + auto plonk_composer = proof_system::plonk::UltraComposer(); + + auto a = fr::random_element(); + auto b = fr::random_element(); + auto c = fr::random_element(); + auto d = fr::random_element(); + auto e = fr::random_element(); + auto f = fr::random_element(); + auto g = fr::random_element(); + auto h = fr::random_element(); + { + uint32_t rom_values[8]{ + honk_composer.add_variable(a), honk_composer.add_variable(b), honk_composer.add_variable(c), + honk_composer.add_variable(d), honk_composer.add_variable(e), honk_composer.add_variable(f), + honk_composer.add_variable(g), honk_composer.add_variable(h), + }; + + size_t rom_id = honk_composer.create_ROM_array(8); + + for (size_t i = 0; i < 8; ++i) { + honk_composer.set_ROM_element(rom_id, i, rom_values[i]); + } + + uint32_t a_idx = honk_composer.read_ROM_array(rom_id, honk_composer.add_variable(5)); + EXPECT_EQ(a_idx != rom_values[5], true); + uint32_t b_idx = honk_composer.read_ROM_array(rom_id, honk_composer.add_variable(4)); + uint32_t c_idx = honk_composer.read_ROM_array(rom_id, honk_composer.add_variable(1)); + + const auto d_value = + honk_composer.get_variable(a_idx) + honk_composer.get_variable(b_idx) + honk_composer.get_variable(c_idx); + uint32_t d_idx = honk_composer.add_variable(d_value); + + honk_composer.create_big_add_gate({ + a_idx, + b_idx, + c_idx, + d_idx, + 1, + 1, + 1, + -1, + 0, + }); + } + { + uint32_t rom_values[8]{ + plonk_composer.add_variable(a), plonk_composer.add_variable(b), plonk_composer.add_variable(c), + plonk_composer.add_variable(d), plonk_composer.add_variable(e), plonk_composer.add_variable(f), + plonk_composer.add_variable(g), plonk_composer.add_variable(h), + }; + + size_t rom_id = plonk_composer.create_ROM_array(8); + + for (size_t i = 0; i < 8; ++i) { + plonk_composer.set_ROM_element(rom_id, i, rom_values[i]); + } + + uint32_t a_idx = plonk_composer.read_ROM_array(rom_id, plonk_composer.add_variable(5)); + EXPECT_EQ(a_idx != rom_values[5], true); + uint32_t b_idx = plonk_composer.read_ROM_array(rom_id, plonk_composer.add_variable(4)); + uint32_t c_idx = plonk_composer.read_ROM_array(rom_id, plonk_composer.add_variable(1)); + + const auto d_value = plonk_composer.get_variable(a_idx) + plonk_composer.get_variable(b_idx) + + plonk_composer.get_variable(c_idx); + uint32_t d_idx = plonk_composer.add_variable(d_value); + + plonk_composer.create_big_add_gate({ + a_idx, + b_idx, + c_idx, + d_idx, + 1, + 1, + 1, + -1, + 0, + }); + } + + auto honk_prover = honk_composer.create_prover(); + auto plonk_prover = plonk_composer.create_prover(); + + verify_consistency(honk_prover, plonk_prover); +} + +TEST(UltraHonkComposer, ram) +{ + auto honk_composer = UltraHonkComposer(); + auto plonk_composer = proof_system::plonk::UltraComposer(); + + auto a = fr::random_element(); + auto b = fr::random_element(); + auto c = fr::random_element(); + auto d = fr::random_element(); + auto e = fr::random_element(); + auto f = fr::random_element(); + auto g = fr::random_element(); + auto h = fr::random_element(); + { + uint32_t ram_values[8]{ + honk_composer.add_variable(a), honk_composer.add_variable(b), honk_composer.add_variable(c), + honk_composer.add_variable(d), honk_composer.add_variable(e), honk_composer.add_variable(f), + honk_composer.add_variable(g), honk_composer.add_variable(h), + }; + + size_t ram_id = honk_composer.create_RAM_array(8); + + for (size_t i = 0; i < 8; ++i) { + honk_composer.init_RAM_element(ram_id, i, ram_values[i]); + } + + uint32_t a_idx = honk_composer.read_RAM_array(ram_id, honk_composer.add_variable(5)); + EXPECT_EQ(a_idx != ram_values[5], true); + + uint32_t b_idx = honk_composer.read_RAM_array(ram_id, honk_composer.add_variable(4)); + uint32_t c_idx = honk_composer.read_RAM_array(ram_id, honk_composer.add_variable(1)); + + honk_composer.write_RAM_array(ram_id, honk_composer.add_variable(4), honk_composer.add_variable(500)); + uint32_t d_idx = honk_composer.read_RAM_array(ram_id, honk_composer.add_variable(4)); + + EXPECT_EQ(honk_composer.get_variable(d_idx), 500); + + // ensure these vars get used in another arithmetic gate + const auto e_value = honk_composer.get_variable(a_idx) + honk_composer.get_variable(b_idx) + + honk_composer.get_variable(c_idx) + honk_composer.get_variable(d_idx); + uint32_t e_idx = honk_composer.add_variable(e_value); + + honk_composer.create_big_add_gate( + { + a_idx, + b_idx, + c_idx, + d_idx, + -1, + -1, + -1, + -1, + 0, + }, + true); + honk_composer.create_big_add_gate( + { + honk_composer.get_zero_idx(), + honk_composer.get_zero_idx(), + honk_composer.get_zero_idx(), + e_idx, + 0, + 0, + 0, + 0, + 0, + }, + false); + } + { + uint32_t ram_values[8]{ + plonk_composer.add_variable(a), plonk_composer.add_variable(b), plonk_composer.add_variable(c), + plonk_composer.add_variable(d), plonk_composer.add_variable(e), plonk_composer.add_variable(f), + plonk_composer.add_variable(g), plonk_composer.add_variable(h), + }; + + size_t ram_id = plonk_composer.create_RAM_array(8); + + for (size_t i = 0; i < 8; ++i) { + plonk_composer.init_RAM_element(ram_id, i, ram_values[i]); + } + + uint32_t a_idx = plonk_composer.read_RAM_array(ram_id, plonk_composer.add_variable(5)); + EXPECT_EQ(a_idx != ram_values[5], true); + + uint32_t b_idx = plonk_composer.read_RAM_array(ram_id, plonk_composer.add_variable(4)); + uint32_t c_idx = plonk_composer.read_RAM_array(ram_id, plonk_composer.add_variable(1)); + + plonk_composer.write_RAM_array(ram_id, plonk_composer.add_variable(4), plonk_composer.add_variable(500)); + uint32_t d_idx = plonk_composer.read_RAM_array(ram_id, plonk_composer.add_variable(4)); + + EXPECT_EQ(plonk_composer.get_variable(d_idx), 500); + + // ensure these vars get used in another arithmetic gate + const auto e_value = plonk_composer.get_variable(a_idx) + plonk_composer.get_variable(b_idx) + + plonk_composer.get_variable(c_idx) + plonk_composer.get_variable(d_idx); + uint32_t e_idx = plonk_composer.add_variable(e_value); + + plonk_composer.create_big_add_gate( + { + a_idx, + b_idx, + c_idx, + d_idx, + -1, + -1, + -1, + -1, + 0, + }, + true); + plonk_composer.create_big_add_gate( + { + plonk_composer.zero_idx, + plonk_composer.zero_idx, + plonk_composer.zero_idx, + e_idx, + 0, + 0, + 0, + 0, + 0, + }, + false); + } + + auto honk_prover = honk_composer.create_prover(); + auto plonk_prover = plonk_composer.create_prover(); + + verify_consistency(honk_prover, plonk_prover); +} + +} // namespace test_ultra_honk_composer 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/prover_library.test.cpp b/cpp/src/barretenberg/honk/proof_system/prover_library.test.cpp index 0902129370..2dd4b77830 100644 --- a/cpp/src/barretenberg/honk/proof_system/prover_library.test.cpp +++ b/cpp/src/barretenberg/honk/proof_system/prover_library.test.cpp @@ -13,7 +13,6 @@ using namespace proof_system::honk; namespace prover_library_tests { -// field is named Fscalar here because of clash with the Fr template class ProverLibraryTests : public testing::Test { using Polynomial = barretenberg::Polynomial; @@ -206,8 +205,8 @@ template class ProverLibraryTests : public testing::Test { // ∏(s_k + βs_{k+1} + γ(1 + β)) // // in a way that is simple to read (but inefficient). See prover library method for more details. - const Fr eta_sqr = eta.sqr(); - const Fr eta_cube = eta_sqr * eta; + const FF eta_sqr = eta.sqr(); + const FF eta_cube = eta_sqr * eta; std::array accumulators; for (size_t i = 0; i < 4; ++i) { @@ -219,12 +218,12 @@ template class ProverLibraryTests : public testing::Test { // Note: block_mask is used for efficient modulus, i.e. i % N := i & (N-1), for N = 2^k const size_t block_mask = circuit_size - 1; // Initialize 't(X)' to be used in an expression of the form t(X) + β*t(Xω) - Fr table_i = tables[0][0] + tables[1][0] * eta + tables[2][0] * eta_sqr + tables[3][0] * eta_cube; + FF table_i = tables[0][0] + tables[1][0] * eta + tables[2][0] * eta_sqr + tables[3][0] * eta_cube; for (size_t i = 0; i < circuit_size; ++i) { size_t shift_idx = (i + 1) & block_mask; // f = (w_1 + q_2*w_1(Xω)) + η(w_2 + q_m*w_2(Xω)) + η²(w_3 + q_c*w_3(Xω)) + η³q_index. - Fr f_i = (wires[0][i] + wires[0][shift_idx] * column_1_step_size[i]) + + FF f_i = (wires[0][i] + wires[0][shift_idx] * column_1_step_size[i]) + (wires[1][i] + wires[1][shift_idx] * column_2_step_size[i]) * eta + (wires[2][i] + wires[2][shift_idx] * column_3_step_size[i]) * eta_sqr + eta_cube * lookup_index_selector[i]; @@ -233,17 +232,17 @@ template class ProverLibraryTests : public testing::Test { accumulators[0][i] = lookup_selector[i] * f_i + gamma; // t = t_1 + ηt_2 + η²t_3 + η³t_4 - Fr table_i_plus_1 = tables[0][shift_idx] + eta * tables[1][shift_idx] + eta_sqr * tables[2][shift_idx] + + FF table_i_plus_1 = tables[0][shift_idx] + eta * tables[1][shift_idx] + eta_sqr * tables[2][shift_idx] + eta_cube * tables[3][shift_idx]; // t + βt(Xω) + γ(1 + β) - accumulators[1][i] = table_i + table_i_plus_1 * beta + gamma * (Fr::one() + beta); + accumulators[1][i] = table_i + table_i_plus_1 * beta + gamma * (FF::one() + beta); // (1 + β) - accumulators[2][i] = Fr::one() + beta; + accumulators[2][i] = FF::one() + beta; // s + βs(Xω) + γ(1 + β) - accumulators[3][i] = s_lagrange[i] + beta * s_lagrange[shift_idx] + gamma * (Fr::one() + beta); + accumulators[3][i] = s_lagrange[i] + beta * s_lagrange[shift_idx] + gamma * (FF::one() + beta); // Set t(X_i) for next iteration table_i = table_i_plus_1; @@ -303,8 +302,8 @@ template class ProverLibraryTests : public testing::Test { prover_library::compute_sorted_list_accumulator(proving_key, sorted_list_polynomials, eta); // Method 2: Compute local sorted list accumulator simply and inefficiently - const Fr eta_sqr = eta.sqr(); - const Fr eta_cube = eta_sqr * eta; + const FF eta_sqr = eta.sqr(); + const FF eta_cube = eta_sqr * eta; // Compute s = s_1 + η*s_2 + η²*s_3 + η³*s_4 Polynomial sorted_list_accumulator_expected{ sorted_list_polynomials[0] }; diff --git a/cpp/src/barretenberg/honk/proof_system/ultra_prover.cpp b/cpp/src/barretenberg/honk/proof_system/ultra_prover.cpp new file mode 100644 index 0000000000..2070829c40 --- /dev/null +++ b/cpp/src/barretenberg/honk/proof_system/ultra_prover.cpp @@ -0,0 +1,321 @@ +#include "ultra_prover.hpp" +#include +#include +#include "barretenberg/honk/proof_system/prover_library.hpp" +#include "barretenberg/honk/sumcheck/sumcheck.hpp" +#include +#include "barretenberg/honk/sumcheck/polynomials/univariate.hpp" // will go away +#include "barretenberg/honk/utils/power_polynomial.hpp" +#include "barretenberg/honk/pcs/commitment_key.hpp" +#include +#include +#include +#include +#include "barretenberg/ecc/curves/bn254/fr.hpp" +#include "barretenberg/ecc/curves/bn254/g1.hpp" +#include "barretenberg/honk/sumcheck/relations/arithmetic_relation.hpp" +#include "barretenberg/honk/sumcheck/relations/grand_product_computation_relation.hpp" +#include "barretenberg/honk/sumcheck/relations/grand_product_initialization_relation.hpp" +#include "barretenberg/polynomials/polynomial.hpp" +#include "barretenberg/honk/flavor/flavor.hpp" +#include "barretenberg/transcript/transcript_wrappers.hpp" +#include +#include "barretenberg/honk/pcs/claim.hpp" + +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. + * + * @param input_key Proving key. + * @param input_manifest Input manifest + * + * @tparam settings Settings class. + * */ +template +UltraHonkProver::UltraHonkProver(std::vector&& wire_polys, + 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); +// } + +template plonk::proof& UltraHonkProver::export_proof() +{ + proof.proof_data = transcript.proof_data; + return proof; +} + +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(); +} + +template class UltraHonkProver; + +} // namespace proof_system::honk diff --git a/cpp/src/barretenberg/honk/proof_system/ultra_prover.hpp b/cpp/src/barretenberg/honk/proof_system/ultra_prover.hpp new file mode 100644 index 0000000000..df80838f64 --- /dev/null +++ b/cpp/src/barretenberg/honk/proof_system/ultra_prover.hpp @@ -0,0 +1,98 @@ +#pragma once +#include "barretenberg/ecc/curves/bn254/fr.hpp" +#include "barretenberg/honk/pcs/shplonk/shplonk.hpp" +#include "barretenberg/polynomials/polynomial.hpp" +#include "barretenberg/honk/flavor/flavor.hpp" +#include +#include "barretenberg/plonk/proof_system/proving_key/proving_key.hpp" +#include "barretenberg/honk/pcs/commitment_key.hpp" +#include "barretenberg/plonk/proof_system/types/proof.hpp" +#include "barretenberg/plonk/proof_system/types/program_settings.hpp" +#include "barretenberg/honk/pcs/gemini/gemini.hpp" +#include "barretenberg/honk/pcs/shplonk/shplonk_single.hpp" +#include "barretenberg/honk/pcs/kzg/kzg.hpp" +#include "barretenberg/honk/transcript/transcript.hpp" +#include "barretenberg/honk/sumcheck/sumcheck.hpp" +#include "barretenberg/honk/sumcheck/sumcheck_output.hpp" +#include +#include +#include +#include +#include +#include +#include +#include +#include "barretenberg/honk/pcs/claim.hpp" +#include "barretenberg/honk/proof_system/prover_library.hpp" + +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. +template class UltraHonkProver { + + using Fr = barretenberg::fr; + 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; + + 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; +}; + +extern template class UltraHonkProver; + +using UltraProver = UltraHonkProver; + +} // namespace proof_system::honk 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 597b2ddea0..179a80eb8f 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 73039533fc..957f496f2e 100644 --- a/cpp/src/barretenberg/proof_system/composer/permutation_helper.hpp +++ b/cpp/src/barretenberg/proof_system/composer/permutation_helper.hpp @@ -508,4 +508,25 @@ void compute_plonk_generalized_sigma_permutations(const CircuitConstructor& circ compute_monomial_and_coset_fft_polynomials_from_lagrange("id", key); } +/** + * @brief Compute generalized permutation sigmas and ids for ultra plonk + * + * @tparam program_width + * @tparam CircuitConstructor + * @param circuit_constructor + * @param key + * @return std::array, program_width> + */ +// 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! + 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 1c4edac75cc22da9e3a7ed300cfedd4ee135ba83 Mon Sep 17 00:00:00 2001 From: ledwards2225 Date: Mon, 10 Apr 2023 19:28:50 +0000 Subject: [PATCH 2/4] 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 179a80eb8f..597b2ddea0 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 6f727e4f951f2d177feacb1673cb117644e0900d Mon Sep 17 00:00:00 2001 From: ledwards2225 Date: Mon, 10 Apr 2023 20:28:49 +0000 Subject: [PATCH 3/4] 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 6183a3bfe838a3eb11611e875d400c2b331ffffc Mon Sep 17 00:00:00 2001 From: ledwards2225 Date: Mon, 10 Apr 2023 20:39:55 +0000 Subject: [PATCH 4/4] 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.