diff --git a/barretenberg/cpp/pil/avm/toy_avm.pil b/barretenberg/cpp/pil/avm/toy_avm.pil index ed355016195..422ff4d1a0e 100644 --- a/barretenberg/cpp/pil/avm/toy_avm.pil +++ b/barretenberg/cpp/pil/avm/toy_avm.pil @@ -13,8 +13,36 @@ namespace toy(256); q_tuple_set { set_1_column_1, set_1_column_2 } is { set_2_column_1, set_2_column_2 }; // Relation not used -> we currently require a single relation for codegen - pol commit x; - x' - x = 0; + q_tuple_set * (1 - q_tuple_set) = 0; // Also needs a fixed relation - pol fixed first = [1] + [0]*; \ No newline at end of file + pol fixed first = [1] + [0]*; + + // Lookup related stuff + + // For each xor term we need: + // - The witness wire it is over + // - The column being lookuped + // - A shift of the column being lookuped + // - An accumulator for each of the tables + + // constraint wires + pol commit xor_a; + pol commit xor_b; + pol commit xor_c; + + // Precomputed tables + pol commit table_xor_a; + pol commit table_xor_b; + pol commit table_xor_c; + + pol commit q_xor; + pol commit q_xor_table; + + q_xor * (1 - q_xor) = 0; + q_xor_table * (1 - q_xor_table) = 0; + + // Note - if no right hand side selector column is provided, then we will need to build the table ourselves + // Note - we can also take advantage of pil creating the lookup columns for us here -> I may be able to do some codegen here ! + #[lookup_xor] + q_xor { xor_a, xor_b, xor_c } in q_xor_table { table_xor_a, table_xor_b, table_xor_c }; \ No newline at end of file diff --git a/barretenberg/cpp/src/barretenberg/flavor/generated/AvmMini_flavor.hpp b/barretenberg/cpp/src/barretenberg/flavor/generated/AvmMini_flavor.hpp index 9240275729e..a7018fc8d1b 100644 --- a/barretenberg/cpp/src/barretenberg/flavor/generated/AvmMini_flavor.hpp +++ b/barretenberg/cpp/src/barretenberg/flavor/generated/AvmMini_flavor.hpp @@ -202,10 +202,10 @@ class AvmMiniFlavor { avmMini_mem_idx_b, avmMini_mem_idx_c, avmMini_last, - memTrace_m_val_shift, - memTrace_m_addr_shift, - memTrace_m_tag_shift, memTrace_m_rw_shift, + memTrace_m_tag_shift, + memTrace_m_addr_shift, + memTrace_m_val_shift, avmMini_internal_return_ptr_shift, avmMini_pc_shift) @@ -251,10 +251,10 @@ class AvmMiniFlavor { avmMini_mem_idx_b, avmMini_mem_idx_c, avmMini_last, - memTrace_m_val_shift, - memTrace_m_addr_shift, - memTrace_m_tag_shift, memTrace_m_rw_shift, + memTrace_m_tag_shift, + memTrace_m_addr_shift, + memTrace_m_val_shift, avmMini_internal_return_ptr_shift, avmMini_pc_shift }; }; @@ -303,15 +303,15 @@ class AvmMiniFlavor { }; RefVector get_to_be_shifted() { - return { memTrace_m_val, memTrace_m_addr, memTrace_m_tag, memTrace_m_rw, avmMini_internal_return_ptr, + return { memTrace_m_rw, memTrace_m_tag, memTrace_m_addr, memTrace_m_val, avmMini_internal_return_ptr, avmMini_pc }; }; RefVector get_shifted() { - return { memTrace_m_val_shift, - memTrace_m_addr_shift, + return { memTrace_m_rw_shift, memTrace_m_tag_shift, - memTrace_m_rw_shift, + memTrace_m_addr_shift, + memTrace_m_val_shift, avmMini_internal_return_ptr_shift, avmMini_pc_shift }; }; @@ -326,7 +326,7 @@ class AvmMiniFlavor { RefVector get_to_be_shifted() { - return { memTrace_m_val, memTrace_m_addr, memTrace_m_tag, memTrace_m_rw, avmMini_internal_return_ptr, + return { memTrace_m_rw, memTrace_m_tag, memTrace_m_addr, memTrace_m_val, avmMini_internal_return_ptr, avmMini_pc }; }; @@ -637,6 +637,4 @@ class AvmMiniFlavor { }; } // namespace flavor - -namespace sumcheck {} } // namespace proof_system::honk diff --git a/barretenberg/cpp/src/barretenberg/flavor/generated/Toy_flavor.hpp b/barretenberg/cpp/src/barretenberg/flavor/generated/Toy_flavor.hpp index 312dfa7cf94..7799ac60958 100644 --- a/barretenberg/cpp/src/barretenberg/flavor/generated/Toy_flavor.hpp +++ b/barretenberg/cpp/src/barretenberg/flavor/generated/Toy_flavor.hpp @@ -36,11 +36,11 @@ class ToyFlavor { using VerifierCommitmentKey = pcs::VerifierCommitmentKey; static constexpr size_t NUM_PRECOMPUTED_ENTITIES = 1; - static constexpr size_t NUM_WITNESS_ENTITIES = 7; + static constexpr size_t NUM_WITNESS_ENTITIES = 16; static constexpr size_t NUM_WIRES = NUM_WITNESS_ENTITIES + NUM_PRECOMPUTED_ENTITIES; // We have two copies of the witness entities, so we subtract the number of fixed ones (they have no shift), one for // the unshifted and one for the shifted - static constexpr size_t NUM_ALL_ENTITIES = 9; + static constexpr size_t NUM_ALL_ENTITIES = 17; using Relations = std::tuple, sumcheck::two_column_perm_relation>; @@ -81,13 +81,24 @@ class ToyFlavor { toy_set_1_column_2, toy_set_2_column_1, toy_set_2_column_2, - toy_x, - two_column_perm) + toy_xor_a, + toy_xor_b, + toy_xor_c, + toy_table_xor_a, + toy_table_xor_b, + toy_table_xor_c, + toy_q_xor, + toy_q_xor_table, + two_column_perm, + lookup_xor, + lookup_xor_counts) RefVector get_wires() { - return { toy_q_tuple_set, toy_set_1_column_1, toy_set_1_column_2, toy_set_2_column_1, toy_set_2_column_2, - toy_x, two_column_perm }; + return { toy_q_tuple_set, toy_set_1_column_1, toy_set_1_column_2, toy_set_2_column_1, + toy_set_2_column_2, toy_xor_a, toy_xor_b, toy_xor_c, + toy_table_xor_a, toy_table_xor_b, toy_table_xor_c, toy_q_xor, + toy_q_xor_table, two_column_perm, lookup_xor, lookup_xor_counts }; }; RefVector get_sorted_polynomials() { return {}; }; }; @@ -101,22 +112,34 @@ class ToyFlavor { toy_set_1_column_2, toy_set_2_column_1, toy_set_2_column_2, - toy_x, + toy_xor_a, + toy_xor_b, + toy_xor_c, + toy_table_xor_a, + toy_table_xor_b, + toy_table_xor_c, + toy_q_xor, + toy_q_xor_table, two_column_perm, - toy_x_shift) + lookup_xor, + lookup_xor_counts) RefVector get_wires() { - return { toy_first, toy_q_tuple_set, toy_set_1_column_1, toy_set_1_column_2, toy_set_2_column_1, - toy_set_2_column_2, toy_x, two_column_perm, toy_x_shift }; + return { toy_first, toy_q_tuple_set, toy_set_1_column_1, toy_set_1_column_2, toy_set_2_column_1, + toy_set_2_column_2, toy_xor_a, toy_xor_b, toy_xor_c, toy_table_xor_a, + toy_table_xor_b, toy_table_xor_c, toy_q_xor, toy_q_xor_table, two_column_perm, + lookup_xor, lookup_xor_counts }; }; RefVector get_unshifted() { - return { toy_first, toy_q_tuple_set, toy_set_1_column_1, toy_set_1_column_2, toy_set_2_column_1, - toy_set_2_column_2, toy_x, two_column_perm }; + return { toy_first, toy_q_tuple_set, toy_set_1_column_1, toy_set_1_column_2, toy_set_2_column_1, + toy_set_2_column_2, toy_xor_a, toy_xor_b, toy_xor_c, toy_table_xor_a, + toy_table_xor_b, toy_table_xor_c, toy_q_xor, toy_q_xor_table, two_column_perm, + lookup_xor, lookup_xor_counts }; }; - RefVector get_to_be_shifted() { return { toy_x }; }; - RefVector get_shifted() { return { toy_x_shift }; }; + RefVector get_to_be_shifted() { return {}; }; + RefVector get_shifted() { return {}; }; }; public: @@ -126,7 +149,7 @@ class ToyFlavor { using Base = ProvingKey_, WitnessEntities>; using Base::Base; - RefVector get_to_be_shifted() { return { toy_x }; }; + RefVector get_to_be_shifted() { return {}; }; // The plookup wires that store plookup read data. std::array get_table_column_wires() { return {}; }; @@ -169,6 +192,8 @@ class ToyFlavor { } }; + using RowPolynomials = AllEntities; + class PartiallyEvaluatedMultivariates : public AllEntities { public: PartiallyEvaluatedMultivariates() = default; @@ -206,8 +231,17 @@ class ToyFlavor { Base::toy_set_1_column_2 = "TOY_SET_1_COLUMN_2"; Base::toy_set_2_column_1 = "TOY_SET_2_COLUMN_1"; Base::toy_set_2_column_2 = "TOY_SET_2_COLUMN_2"; - Base::toy_x = "TOY_X"; + Base::toy_xor_a = "TOY_XOR_A"; + Base::toy_xor_b = "TOY_XOR_B"; + Base::toy_xor_c = "TOY_XOR_C"; + Base::toy_table_xor_a = "TOY_TABLE_XOR_A"; + Base::toy_table_xor_b = "TOY_TABLE_XOR_B"; + Base::toy_table_xor_c = "TOY_TABLE_XOR_C"; + Base::toy_q_xor = "TOY_Q_XOR"; + Base::toy_q_xor_table = "TOY_Q_XOR_TABLE"; Base::two_column_perm = "TWO_COLUMN_PERM"; + Base::lookup_xor = "LOOKUP_XOR"; + Base::lookup_xor_counts = "LOOKUP_XOR_COUNTS"; }; }; @@ -231,8 +265,17 @@ class ToyFlavor { Commitment toy_set_1_column_2; Commitment toy_set_2_column_1; Commitment toy_set_2_column_2; - Commitment toy_x; + Commitment toy_xor_a; + Commitment toy_xor_b; + Commitment toy_xor_c; + Commitment toy_table_xor_a; + Commitment toy_table_xor_b; + Commitment toy_table_xor_c; + Commitment toy_q_xor; + Commitment toy_q_xor_table; Commitment two_column_perm; + Commitment lookup_xor; + Commitment lookup_xor_counts; std::vector> sumcheck_univariates; std::array sumcheck_evaluations; @@ -257,8 +300,17 @@ class ToyFlavor { toy_set_1_column_2 = deserialize_from_buffer(Transcript::proof_data, num_bytes_read); toy_set_2_column_1 = deserialize_from_buffer(Transcript::proof_data, num_bytes_read); toy_set_2_column_2 = deserialize_from_buffer(Transcript::proof_data, num_bytes_read); - toy_x = deserialize_from_buffer(Transcript::proof_data, num_bytes_read); + toy_xor_a = deserialize_from_buffer(Transcript::proof_data, num_bytes_read); + toy_xor_b = deserialize_from_buffer(Transcript::proof_data, num_bytes_read); + toy_xor_c = deserialize_from_buffer(Transcript::proof_data, num_bytes_read); + toy_table_xor_a = deserialize_from_buffer(Transcript::proof_data, num_bytes_read); + toy_table_xor_b = deserialize_from_buffer(Transcript::proof_data, num_bytes_read); + toy_table_xor_c = deserialize_from_buffer(Transcript::proof_data, num_bytes_read); + toy_q_xor = deserialize_from_buffer(Transcript::proof_data, num_bytes_read); + toy_q_xor_table = deserialize_from_buffer(Transcript::proof_data, num_bytes_read); two_column_perm = deserialize_from_buffer(Transcript::proof_data, num_bytes_read); + lookup_xor = deserialize_from_buffer(Transcript::proof_data, num_bytes_read); + lookup_xor_counts = deserialize_from_buffer(Transcript::proof_data, num_bytes_read); for (size_t i = 0; i < log_n; ++i) { sumcheck_univariates.emplace_back( @@ -287,8 +339,17 @@ class ToyFlavor { serialize_to_buffer(toy_set_1_column_2, Transcript::proof_data); serialize_to_buffer(toy_set_2_column_1, Transcript::proof_data); serialize_to_buffer(toy_set_2_column_2, Transcript::proof_data); - serialize_to_buffer(toy_x, Transcript::proof_data); + serialize_to_buffer(toy_xor_a, Transcript::proof_data); + serialize_to_buffer(toy_xor_b, Transcript::proof_data); + serialize_to_buffer(toy_xor_c, Transcript::proof_data); + serialize_to_buffer(toy_table_xor_a, Transcript::proof_data); + serialize_to_buffer(toy_table_xor_b, Transcript::proof_data); + serialize_to_buffer(toy_table_xor_c, Transcript::proof_data); + serialize_to_buffer(toy_q_xor, Transcript::proof_data); + serialize_to_buffer(toy_q_xor_table, Transcript::proof_data); serialize_to_buffer(two_column_perm, Transcript::proof_data); + serialize_to_buffer(lookup_xor, Transcript::proof_data); + serialize_to_buffer(lookup_xor_counts, Transcript::proof_data); for (size_t i = 0; i < log_n; ++i) { serialize_to_buffer(sumcheck_univariates[i], Transcript::proof_data); @@ -307,10 +368,4 @@ class ToyFlavor { }; } // namespace flavor - -namespace sumcheck { - -DECLARE_SUMCHECK_RELATION_CLASS(two_column_perm, flavor::ToyFlavor); - -} } // namespace proof_system::honk diff --git a/barretenberg/cpp/src/barretenberg/honk/proof_system/logderivative_library.hpp b/barretenberg/cpp/src/barretenberg/honk/proof_system/logderivative_library.hpp index b4dff8157ba..f2247d3f6fe 100644 --- a/barretenberg/cpp/src/barretenberg/honk/proof_system/logderivative_library.hpp +++ b/barretenberg/cpp/src/barretenberg/honk/proof_system/logderivative_library.hpp @@ -31,6 +31,7 @@ void compute_logderivative_inverse(Polynomials& polynomials, auto& relation_para constexpr size_t WRITE_TERMS = Relation::WRITE_TERMS; auto lookup_relation = Relation(); + auto& inverse_polynomial = lookup_relation.template get_inverse_polynomial(polynomials); for (size_t i = 0; i < circuit_size; ++i) { auto row = polynomials.get_row(i); diff --git a/barretenberg/cpp/src/barretenberg/proof_system/circuit_builder/generated/AvmMini_circuit_builder.hpp b/barretenberg/cpp/src/barretenberg/proof_system/circuit_builder/generated/AvmMini_circuit_builder.hpp index bd32d969d15..bbc5836c221 100644 --- a/barretenberg/cpp/src/barretenberg/proof_system/circuit_builder/generated/AvmMini_circuit_builder.hpp +++ b/barretenberg/cpp/src/barretenberg/proof_system/circuit_builder/generated/AvmMini_circuit_builder.hpp @@ -8,6 +8,7 @@ #include "barretenberg/ecc/curves/bn254/fr.hpp" #include "barretenberg/honk/proof_system/logderivative_library.hpp" #include "barretenberg/proof_system/circuit_builder/circuit_builder_base.hpp" +#include "barretenberg/relations/generic_lookup/generic_lookup_relation.hpp" #include "barretenberg/relations/generic_permutation/generic_permutation_relation.hpp" #include "barretenberg/flavor/generated/AvmMini_flavor.hpp" @@ -59,10 +60,10 @@ template struct AvmMiniFullRow { FF avmMini_mem_idx_b{}; FF avmMini_mem_idx_c{}; FF avmMini_last{}; - FF memTrace_m_val_shift{}; - FF memTrace_m_addr_shift{}; - FF memTrace_m_tag_shift{}; FF memTrace_m_rw_shift{}; + FF memTrace_m_tag_shift{}; + FF memTrace_m_addr_shift{}; + FF memTrace_m_val_shift{}; FF avmMini_internal_return_ptr_shift{}; FF avmMini_pc_shift{}; }; @@ -136,10 +137,10 @@ class AvmMiniCircuitBuilder { polys.avmMini_last[i] = rows[i].avmMini_last; } - polys.memTrace_m_val_shift = Polynomial(polys.memTrace_m_val.shifted()); - polys.memTrace_m_addr_shift = Polynomial(polys.memTrace_m_addr.shifted()); - polys.memTrace_m_tag_shift = Polynomial(polys.memTrace_m_tag.shifted()); polys.memTrace_m_rw_shift = Polynomial(polys.memTrace_m_rw.shifted()); + polys.memTrace_m_tag_shift = Polynomial(polys.memTrace_m_tag.shifted()); + polys.memTrace_m_addr_shift = Polynomial(polys.memTrace_m_addr.shifted()); + polys.memTrace_m_val_shift = Polynomial(polys.memTrace_m_val.shifted()); polys.avmMini_internal_return_ptr_shift = Polynomial(polys.avmMini_internal_return_ptr.shifted()); polys.avmMini_pc_shift = Polynomial(polys.avmMini_pc.shifted()); diff --git a/barretenberg/cpp/src/barretenberg/proof_system/circuit_builder/generated/Toy_circuit_builder.hpp b/barretenberg/cpp/src/barretenberg/proof_system/circuit_builder/generated/Toy_circuit_builder.hpp index e8d337389a5..c43b7de5146 100644 --- a/barretenberg/cpp/src/barretenberg/proof_system/circuit_builder/generated/Toy_circuit_builder.hpp +++ b/barretenberg/cpp/src/barretenberg/proof_system/circuit_builder/generated/Toy_circuit_builder.hpp @@ -8,9 +8,11 @@ #include "barretenberg/ecc/curves/bn254/fr.hpp" #include "barretenberg/honk/proof_system/logderivative_library.hpp" #include "barretenberg/proof_system/circuit_builder/circuit_builder_base.hpp" +#include "barretenberg/relations/generic_lookup/generic_lookup_relation.hpp" #include "barretenberg/relations/generic_permutation/generic_permutation_relation.hpp" #include "barretenberg/flavor/generated/Toy_flavor.hpp" +#include "barretenberg/relations/generated/Toy/lookup_xor.hpp" #include "barretenberg/relations/generated/Toy/toy_avm.hpp" #include "barretenberg/relations/generated/Toy/two_column_perm.hpp" @@ -25,9 +27,17 @@ template struct ToyFullRow { FF toy_set_1_column_2{}; FF toy_set_2_column_1{}; FF toy_set_2_column_2{}; - FF toy_x{}; + FF toy_xor_a{}; + FF toy_xor_b{}; + FF toy_xor_c{}; + FF toy_table_xor_a{}; + FF toy_table_xor_b{}; + FF toy_table_xor_c{}; + FF toy_q_xor{}; + FF toy_q_xor_table{}; FF two_column_perm{}; - FF toy_x_shift{}; + FF lookup_xor{}; + FF lookup_xor_counts{}; }; class ToyCircuitBuilder { @@ -40,8 +50,8 @@ class ToyCircuitBuilder { using Polynomial = Flavor::Polynomial; using ProverPolynomials = Flavor::ProverPolynomials; - static constexpr size_t num_fixed_columns = 9; - static constexpr size_t num_polys = 8; + static constexpr size_t num_fixed_columns = 17; + static constexpr size_t num_polys = 17; std::vector rows; void set_trace(std::vector&& trace) { rows = std::move(trace); } @@ -63,12 +73,19 @@ class ToyCircuitBuilder { polys.toy_set_1_column_2[i] = rows[i].toy_set_1_column_2; polys.toy_set_2_column_1[i] = rows[i].toy_set_2_column_1; polys.toy_set_2_column_2[i] = rows[i].toy_set_2_column_2; - polys.toy_x[i] = rows[i].toy_x; + polys.toy_xor_a[i] = rows[i].toy_xor_a; + polys.toy_xor_b[i] = rows[i].toy_xor_b; + polys.toy_xor_c[i] = rows[i].toy_xor_c; + polys.toy_table_xor_a[i] = rows[i].toy_table_xor_a; + polys.toy_table_xor_b[i] = rows[i].toy_table_xor_b; + polys.toy_table_xor_c[i] = rows[i].toy_table_xor_c; + polys.toy_q_xor[i] = rows[i].toy_q_xor; + polys.toy_q_xor_table[i] = rows[i].toy_q_xor_table; polys.two_column_perm[i] = rows[i].two_column_perm; + polys.lookup_xor[i] = rows[i].lookup_xor; + polys.lookup_xor_counts[i] = rows[i].lookup_xor_counts; } - polys.toy_x_shift = Polynomial(polys.toy_x.shifted()); - return polys; } @@ -88,7 +105,7 @@ class ToyCircuitBuilder { .eccvm_set_permutation_delta = 0, }; - ProverPolynomials polys = compute_polynomials(); + auto polys = compute_polynomials(); const size_t num_rows = polys.get_polynomial_size(); const auto evaluate_relation = [&](const std::string& relation_name, @@ -118,22 +135,22 @@ class ToyCircuitBuilder { return true; }; - const auto evaluate_permutation = [&](const std::string& permutation_name) { - // Check the tuple permutation relation - proof_system::honk::logderivative_library::compute_logderivative_inverse( + const auto evaluate_logderivative = [&](const std::string& lookup_name) { + // Check the logderivative relation + proof_system::honk::logderivative_library::compute_logderivative_inverse( polys, params, num_rows); - typename PermutationSettings::SumcheckArrayOfValuesOverSubrelations permutation_result; + typename LogDerivativeSettings::SumcheckArrayOfValuesOverSubrelations lookup_result; - for (auto& r : permutation_result) { + for (auto& r : lookup_result) { r = 0; } for (size_t i = 0; i < num_rows; ++i) { - PermutationSettings::accumulate(permutation_result, polys.get_row(i), params, 1); + LogDerivativeSettings::accumulate(lookup_result, polys.get_row(i), params, 1); } - for (auto r : permutation_result) { + for (auto r : lookup_result) { if (r != 0) { - info("Tuple ", permutation_name, " failed."); + info("Lookup ", lookup_name, " failed."); return false; } } @@ -145,10 +162,13 @@ class ToyCircuitBuilder { return false; } - if (!evaluate_permutation.template operator()>( + if (!evaluate_logderivative.template operator()>( "two_column_perm")) { return false; } + if (!evaluate_logderivative.template operator()>("lookup_xor")) { + return false; + } return true; } diff --git a/barretenberg/cpp/src/barretenberg/proof_system/circuit_builder/toy_avm/toy_avm_circuit_builder.test.cpp b/barretenberg/cpp/src/barretenberg/proof_system/circuit_builder/toy_avm/toy_avm_circuit_builder.test.cpp index 09750e93df3..addf8df4d2f 100644 --- a/barretenberg/cpp/src/barretenberg/proof_system/circuit_builder/toy_avm/toy_avm_circuit_builder.test.cpp +++ b/barretenberg/cpp/src/barretenberg/proof_system/circuit_builder/toy_avm/toy_avm_circuit_builder.test.cpp @@ -50,8 +50,7 @@ TEST(ToyAVMCircuitBuilder, BaseCase) // Test that permutations with correct values work circuit_builder.set_trace(std::move(rows)); - bool result = circuit_builder.check_circuit(); - EXPECT_EQ(result, true); + EXPECT_EQ(circuit_builder.check_circuit(), true); // Store value temporarily FF tmp = circuit_builder.rows[5].toy_set_1_column_1; @@ -60,14 +59,63 @@ TEST(ToyAVMCircuitBuilder, BaseCase) circuit_builder.rows[5].toy_set_1_column_1 = FF::random_element(); // Check that it fails - result = circuit_builder.check_circuit(); - EXPECT_EQ(result, false); + EXPECT_EQ(circuit_builder.check_circuit(), false); // Restore value circuit_builder.rows[5].toy_set_1_column_1 = tmp; // Check circuit passes - result = circuit_builder.check_circuit(); - EXPECT_EQ(result, true); + EXPECT_EQ(circuit_builder.check_circuit(), true); + + // LOOKUPS + // Create xor lookup table, from 0 to 16; + for (size_t i = 0; i < circuit_size; i++) { + Row& row = circuit_builder.rows[i]; + size_t a = i; + size_t b = circuit_size - i; + size_t c = a ^ b; + + row.toy_q_xor_table = FF(1); + row.toy_table_xor_a = FF(a); + row.toy_table_xor_b = FF(b); + row.toy_table_xor_c = FF(c); + } + + // Perform a lookup every other row + for (size_t i = 0; i < circuit_size; i += 2) { + Row& row = circuit_builder.rows[i]; + size_t a = i; + size_t b = circuit_size - i; + size_t c = a ^ b; + + row.toy_q_xor = FF(1); + row.toy_xor_a = FF(a); + row.toy_xor_b = FF(b); + row.toy_xor_c = FF(c); + + // Add a count for this row + row.lookup_xor_counts = FF(1); + } + + // Check circuit passes + EXPECT_EQ(circuit_builder.check_circuit(), true); + + // Break lookup by changing count + tmp = circuit_builder.rows[5].lookup_xor_counts; + circuit_builder.rows[5].lookup_xor_counts = FF::random_element(); + + EXPECT_EQ(circuit_builder.check_circuit(), false); + + circuit_builder.rows[5].lookup_xor_counts = tmp; + EXPECT_EQ(circuit_builder.check_circuit(), true); + + // Break lookup by changing lookup value + tmp = circuit_builder.rows[2].toy_xor_a; + circuit_builder.rows[2].toy_xor_a = FF::random_element(); + + EXPECT_EQ(circuit_builder.check_circuit(), false); + + circuit_builder.rows[2].toy_xor_a = tmp; + EXPECT_EQ(circuit_builder.check_circuit(), true); } } // namespace toy_avm_circuit_builder_tests \ No newline at end of file diff --git a/barretenberg/cpp/src/barretenberg/relations/generated/AvmMini/avm_mini.hpp b/barretenberg/cpp/src/barretenberg/relations/generated/AvmMini/avm_mini.hpp index 7ad4452af56..9b8b57bfd89 100644 --- a/barretenberg/cpp/src/barretenberg/relations/generated/AvmMini/avm_mini.hpp +++ b/barretenberg/cpp/src/barretenberg/relations/generated/AvmMini/avm_mini.hpp @@ -7,70 +7,70 @@ namespace proof_system::AvmMini_vm { template struct Avm_miniRow { - FF avmMini_first{}; - FF avmMini_sel_jump{}; + FF avmMini_rwa{}; + FF avmMini_mem_op_a{}; + FF avmMini_sel_op_mul{}; + FF avmMini_mem_op_c{}; FF avmMini_internal_return_ptr_shift{}; - FF avmMini_pc{}; - FF avmMini_tag_err{}; + FF avmMini_sel_op_div{}; + FF avmMini_rwb{}; + FF avmMini_pc_shift{}; + FF avmMini_internal_return_ptr{}; + FF avmMini_sel_internal_call{}; + FF avmMini_ia{}; FF avmMini_mem_idx_a{}; FF avmMini_sel_op_add{}; - FF avmMini_rwb{}; - FF avmMini_rwc{}; - FF avmMini_sel_internal_return{}; - FF avmMini_rwa{}; + FF avmMini_mem_op_b{}; FF avmMini_inv{}; - FF avmMini_sel_internal_call{}; + FF avmMini_tag_err{}; FF avmMini_op_err{}; - FF avmMini_pc_shift{}; - FF avmMini_sel_op_mul{}; - FF avmMini_sel_op_div{}; - FF avmMini_sel_op_sub{}; - FF avmMini_mem_op_b{}; + FF avmMini_ib{}; + FF avmMini_pc{}; + FF avmMini_sel_internal_return{}; + FF avmMini_sel_jump{}; + FF avmMini_rwc{}; + FF avmMini_first{}; FF avmMini_sel_halt{}; - FF avmMini_ia{}; - FF avmMini_mem_op_a{}; FF avmMini_ic{}; - FF avmMini_ib{}; - FF avmMini_internal_return_ptr{}; - FF avmMini_mem_op_c{}; FF avmMini_mem_idx_b{}; + FF avmMini_sel_op_sub{}; }; inline std::string get_relation_label_avm_mini(int index) { switch (index) { - case 24: - return "SUBOP_DIVISION_ZERO_ERR2"; - - case 20: - return "SUBOP_SUBTRACTION_FF"; - - case 38: - return "PC_INCREMENT"; - - case 22: - return "SUBOP_DIVISION_FF"; - - case 23: - return "SUBOP_DIVISION_ZERO_ERR1"; + case 19: + return "SUBOP_ADDITION_FF"; case 21: return "SUBOP_MULTIPLICATION_FF"; - case 19: - return "SUBOP_ADDITION_FF"; - case 33: return "RETURN_POINTER_DECREMENT"; case 39: return "INTERNAL_RETURN_POINTER_CONSISTENCY"; + case 27: + return "RETURN_POINTER_INCREMENT"; + + case 24: + return "SUBOP_DIVISION_ZERO_ERR2"; + + case 20: + return "SUBOP_SUBTRACTION_FF"; + + case 22: + return "SUBOP_DIVISION_FF"; + case 25: return "SUBOP_ERROR_RELEVANT_OP"; - case 27: - return "RETURN_POINTER_INCREMENT"; + case 23: + return "SUBOP_DIVISION_ZERO_ERR1"; + + case 38: + return "PC_INCREMENT"; } return std::to_string(index); } diff --git a/barretenberg/cpp/src/barretenberg/relations/generated/AvmMini/declare_views.hpp b/barretenberg/cpp/src/barretenberg/relations/generated/AvmMini/declare_views.hpp index 2bd134b6298..bf4df9cb83e 100644 --- a/barretenberg/cpp/src/barretenberg/relations/generated/AvmMini/declare_views.hpp +++ b/barretenberg/cpp/src/barretenberg/relations/generated/AvmMini/declare_views.hpp @@ -42,9 +42,9 @@ [[maybe_unused]] auto avmMini_mem_idx_b = View(new_term.avmMini_mem_idx_b); \ [[maybe_unused]] auto avmMini_mem_idx_c = View(new_term.avmMini_mem_idx_c); \ [[maybe_unused]] auto avmMini_last = View(new_term.avmMini_last); \ - [[maybe_unused]] auto memTrace_m_val_shift = View(new_term.memTrace_m_val_shift); \ - [[maybe_unused]] auto memTrace_m_addr_shift = View(new_term.memTrace_m_addr_shift); \ - [[maybe_unused]] auto memTrace_m_tag_shift = View(new_term.memTrace_m_tag_shift); \ [[maybe_unused]] auto memTrace_m_rw_shift = View(new_term.memTrace_m_rw_shift); \ + [[maybe_unused]] auto memTrace_m_tag_shift = View(new_term.memTrace_m_tag_shift); \ + [[maybe_unused]] auto memTrace_m_addr_shift = View(new_term.memTrace_m_addr_shift); \ + [[maybe_unused]] auto memTrace_m_val_shift = View(new_term.memTrace_m_val_shift); \ [[maybe_unused]] auto avmMini_internal_return_ptr_shift = View(new_term.avmMini_internal_return_ptr_shift); \ [[maybe_unused]] auto avmMini_pc_shift = View(new_term.avmMini_pc_shift); diff --git a/barretenberg/cpp/src/barretenberg/relations/generated/AvmMini/mem_trace.hpp b/barretenberg/cpp/src/barretenberg/relations/generated/AvmMini/mem_trace.hpp index ef96061a9ca..4139d4b8bc3 100644 --- a/barretenberg/cpp/src/barretenberg/relations/generated/AvmMini/mem_trace.hpp +++ b/barretenberg/cpp/src/barretenberg/relations/generated/AvmMini/mem_trace.hpp @@ -7,39 +7,39 @@ namespace proof_system::AvmMini_vm { template struct Mem_traceRow { - FF memTrace_m_last{}; - FF memTrace_m_val_shift{}; - FF memTrace_m_rw{}; - FF memTrace_m_tag_err{}; - FF memTrace_m_addr_shift{}; - FF memTrace_m_lastAccess{}; - FF memTrace_m_tag_shift{}; - FF memTrace_m_tag{}; FF memTrace_m_val{}; + FF memTrace_m_lastAccess{}; + FF memTrace_m_tag_err{}; FF memTrace_m_rw_shift{}; FF memTrace_m_in_tag{}; - FF memTrace_m_addr{}; + FF memTrace_m_rw{}; + FF memTrace_m_tag_shift{}; + FF memTrace_m_last{}; + FF memTrace_m_addr_shift{}; + FF memTrace_m_tag{}; FF memTrace_m_one_min_inv{}; + FF memTrace_m_val_shift{}; + FF memTrace_m_addr{}; }; inline std::string get_relation_label_mem_trace(int index) { switch (index) { + case 8: + return "MEM_IN_TAG_CONSISTENCY_1"; + case 7: return "MEM_ZERO_INIT"; case 6: return "MEM_READ_WRITE_TAG_CONSISTENCY"; - case 8: - return "MEM_IN_TAG_CONSISTENCY_1"; + case 5: + return "MEM_READ_WRITE_VAL_CONSISTENCY"; case 4: return "MEM_LAST_ACCESS_DELIMITER"; - case 5: - return "MEM_READ_WRITE_VAL_CONSISTENCY"; - case 9: return "MEM_IN_TAG_CONSISTENCY_2"; } diff --git a/barretenberg/cpp/src/barretenberg/relations/generated/Toy/declare_views.hpp b/barretenberg/cpp/src/barretenberg/relations/generated/Toy/declare_views.hpp index 18b7ec1d45e..98e120768ea 100644 --- a/barretenberg/cpp/src/barretenberg/relations/generated/Toy/declare_views.hpp +++ b/barretenberg/cpp/src/barretenberg/relations/generated/Toy/declare_views.hpp @@ -8,6 +8,14 @@ [[maybe_unused]] auto toy_set_1_column_2 = View(new_term.toy_set_1_column_2); \ [[maybe_unused]] auto toy_set_2_column_1 = View(new_term.toy_set_2_column_1); \ [[maybe_unused]] auto toy_set_2_column_2 = View(new_term.toy_set_2_column_2); \ - [[maybe_unused]] auto toy_x = View(new_term.toy_x); \ + [[maybe_unused]] auto toy_xor_a = View(new_term.toy_xor_a); \ + [[maybe_unused]] auto toy_xor_b = View(new_term.toy_xor_b); \ + [[maybe_unused]] auto toy_xor_c = View(new_term.toy_xor_c); \ + [[maybe_unused]] auto toy_table_xor_a = View(new_term.toy_table_xor_a); \ + [[maybe_unused]] auto toy_table_xor_b = View(new_term.toy_table_xor_b); \ + [[maybe_unused]] auto toy_table_xor_c = View(new_term.toy_table_xor_c); \ + [[maybe_unused]] auto toy_q_xor = View(new_term.toy_q_xor); \ + [[maybe_unused]] auto toy_q_xor_table = View(new_term.toy_q_xor_table); \ [[maybe_unused]] auto two_column_perm = View(new_term.two_column_perm); \ - [[maybe_unused]] auto toy_x_shift = View(new_term.toy_x_shift); + [[maybe_unused]] auto lookup_xor = View(new_term.lookup_xor); \ + [[maybe_unused]] auto lookup_xor_counts = View(new_term.lookup_xor_counts); diff --git a/barretenberg/cpp/src/barretenberg/relations/generated/Toy/lookup_xor.hpp b/barretenberg/cpp/src/barretenberg/relations/generated/Toy/lookup_xor.hpp new file mode 100644 index 00000000000..6311d2a8a05 --- /dev/null +++ b/barretenberg/cpp/src/barretenberg/relations/generated/Toy/lookup_xor.hpp @@ -0,0 +1,174 @@ + + +#pragma once + +#include "barretenberg/relations/generic_lookup/generic_lookup_relation.hpp" + +#include +#include + +namespace proof_system::honk::sumcheck { + +/** + * @brief This class contains an example of how to set LookupSettings classes used by the + * GenericLookupRelationImpl class to specify a scaled lookup + * + * @details To create your own lookup: + * 1) Create a copy of this class and rename it + * 2) Update all the values with the ones needed for your lookup + * 3) Update "DECLARE_LOOKUP_IMPLEMENTATIONS_FOR_ALL_SETTINGS" and "DEFINE_LOOKUP_IMPLEMENTATIONS_FOR_ALL_SETTINGS" to + * include the new settings + * 4) Add the relation with the chosen settings to Relations in the flavor (for example,"` + * using Relations = std::tuple>;)` + * + */ +class lookup_xor_lookup_settings { + public: + /** + * @brief The number of read terms (how many lookups we perform) in each row + * + */ + static constexpr size_t READ_TERMS = 1; + /** + * @brief The number of write terms (how many additions to the lookup table we make) in each row + * + */ + static constexpr size_t WRITE_TERMS = 1; + + /** + * @brief The type of READ_TERM used for each read index (basic and scaled) + * + */ + static constexpr size_t READ_TERM_TYPES[READ_TERMS] = { 0 }; + + /** + * @brief They type of WRITE_TERM used for each write index + * + */ + static constexpr size_t WRITE_TERM_TYPES[WRITE_TERMS] = { 0 }; + + /** + * @brief How many values represent a single lookup object. This value is used by the automatic read term + * implementation in the relation in case the lookup is a basic or scaled tuple and in the write term if it's a + * basic tuple + * + */ + static constexpr size_t LOOKUP_TUPLE_SIZE = 3; + + /** + * @brief The polynomial degree of the relation telling us if the inverse polynomial value needs to be computed + * + */ + static constexpr size_t INVERSE_EXISTS_POLYNOMIAL_DEGREE = 2; + + /** + * @brief The degree of the read term if implemented arbitrarily. This value is not used by basic and scaled read + * terms, but will cause compilation error if not defined + * + */ + static constexpr size_t READ_TERM_DEGREE = 0; + + /** + * @brief The degree of the write term if implemented arbitrarily. This value is not used by the basic write + * term, but will cause compilation error if not defined + * + */ + + static constexpr size_t WRITE_TERM_DEGREE = 0; + + /** + * @brief If this method returns true on a row of values, then the inverse polynomial exists at this index. + * Otherwise the value needs to be set to zero. + * + * @details If this is true then the lookup takes place in this row + * + */ + + template static inline auto inverse_polynomial_is_computed_at_row(const AllEntities& in) + { + return (in.toy_q_xor == 1 || in.toy_q_xor_table == 1); + } + + /** + * @brief Subprocedure for computing the value deciding if the inverse polynomial value needs to be checked in this + * row + * + * @tparam Accumulator Type specified by the lookup relation + * @tparam AllEntities Values/Univariates of all entities row + * @param in Value/Univariate of all entities at row/edge + * @return Accumulator + */ + + template + static inline auto compute_inverse_exists(const AllEntities& in) + { + using View = typename Accumulator::View; + const auto is_operation = View(in.toy_q_xor); + const auto is_table_entry = View(in.toy_q_xor_table); + return (is_operation + is_table_entry - is_operation * is_table_entry); + } + + /** + * @brief Get all the entities for the lookup when need to update them + * + * @details The generic structure of this tuple is described in ./generic_lookup_relation.hpp . The following is + description for the current case: + The entities are returned as a tuple of references in the following order (this is for ): + * - The entity/polynomial used to store the product of the inverse values + * - The entity/polynomial that specifies how many times the lookup table entry at this row has been looked up + * - READ_TERMS entities/polynomials that enable individual lookup operations + * - The entity/polynomial that enables adding an entry to the lookup table in this row + * - LOOKUP_TUPLE_SIZE entities/polynomials representing the basic tuple being looked up as the first read term + * - LOOKUP_TUPLE_SIZE entities/polynomials representing the previous accumulators in the second read term + (scaled tuple) + * - LOOKUP_TUPLE_SIZE entities/polynomials representing the shifts in the second read term (scaled tuple) + * - LOOKUP_TUPLE_SIZE entities/polynomials representing the current accumulators in the second read term + (scaled tuple) + * - LOOKUP_TUPLE_SIZE entities/polynomials representing basic tuples added to the table + * + * @return All the entities needed for the lookup + */ + + template static inline auto get_const_entities(const AllEntities& in) + { + + return std::forward_as_tuple(in.lookup_xor, + in.lookup_xor_counts, + in.toy_q_xor, + in.toy_q_xor_table, + in.toy_xor_a, + in.toy_xor_b, + in.toy_xor_c, + in.toy_table_xor_a, + in.toy_table_xor_b, + in.toy_table_xor_c); + } + + /** + * @brief Get all the entities for the lookup when we only need to read them + * @details Same as in get_const_entities, but nonconst + * + * @return All the entities needed for the lookup + */ + + template static inline auto get_nonconst_entities(AllEntities& in) + { + + return std::forward_as_tuple(in.lookup_xor, + in.lookup_xor_counts, + in.toy_q_xor, + in.toy_q_xor_table, + in.toy_xor_a, + in.toy_xor_b, + in.toy_xor_c, + in.toy_table_xor_a, + in.toy_table_xor_b, + in.toy_table_xor_c); + } +}; + +template using lookup_xor_relation = GenericLookupRelation; +template using lookup_xor = GenericLookup; + +} // namespace proof_system::honk::sumcheck diff --git a/barretenberg/cpp/src/barretenberg/relations/generated/Toy/toy_avm.hpp b/barretenberg/cpp/src/barretenberg/relations/generated/Toy/toy_avm.hpp index 4364cb843ae..2c1d114413f 100644 --- a/barretenberg/cpp/src/barretenberg/relations/generated/Toy/toy_avm.hpp +++ b/barretenberg/cpp/src/barretenberg/relations/generated/Toy/toy_avm.hpp @@ -7,8 +7,9 @@ namespace proof_system::Toy_vm { template struct Toy_avmRow { - FF toy_x{}; - FF toy_x_shift{}; + FF toy_q_xor_table{}; + FF toy_q_tuple_set{}; + FF toy_q_xor{}; }; inline std::string get_relation_label_toy_avm(int index) @@ -21,8 +22,10 @@ template class toy_avmImpl { public: using FF = FF_; - static constexpr std::array SUBRELATION_PARTIAL_LENGTHS{ - 2, + static constexpr std::array SUBRELATION_PARTIAL_LENGTHS{ + 3, + 3, + 3, }; template @@ -36,10 +39,26 @@ template class toy_avmImpl { { Toy_DECLARE_VIEWS(0); - auto tmp = (toy_x_shift - toy_x); + auto tmp = (toy_q_tuple_set * (-toy_q_tuple_set + FF(1))); tmp *= scaling_factor; std::get<0>(evals) += tmp; } + // Contribution 1 + { + Toy_DECLARE_VIEWS(1); + + auto tmp = (toy_q_xor * (-toy_q_xor + FF(1))); + tmp *= scaling_factor; + std::get<1>(evals) += tmp; + } + // Contribution 2 + { + Toy_DECLARE_VIEWS(2); + + auto tmp = (toy_q_xor_table * (-toy_q_xor_table + FF(1))); + tmp *= scaling_factor; + std::get<2>(evals) += tmp; + } } }; diff --git a/barretenberg/cpp/src/barretenberg/relations/generic_lookup/generic_lookup_relation.hpp b/barretenberg/cpp/src/barretenberg/relations/generic_lookup/generic_lookup_relation.hpp new file mode 100644 index 00000000000..12f61dbb200 --- /dev/null +++ b/barretenberg/cpp/src/barretenberg/relations/generic_lookup/generic_lookup_relation.hpp @@ -0,0 +1,484 @@ +/** + * @file generic_lookup_relation.hpp + * @author Rumata888 + * @brief This file contains the template for the generic lookup that can be specialized to enforce various + * lookups (for explanation on how to define them, see "relation_definer.hpp") + * + * @details Lookup is a mechanism to ensure that a particular value or tuple of values (these can be values of + * witnesses, selectors or a function of these) is contained within a particular set. It is a relative of set + * permutation, but has a one-to-many relationship beween elements that are being looked up and the table of values they + * are being looked up from. In this relation template we use the following terminology: + * + READ - the action of looking up the value in the table + * + WRITE - the action of adding the value to the lookup table + * + * TODO(@Rumata888): Talk to Zac why "lookup_read_count" refers to the count of the looked up element in the multiset. + * (The value is applied to the write predicate, so it is confusing). + */ +#pragma once +#include +#include + +#include "barretenberg/common/constexpr_utils.hpp" +#include "barretenberg/honk/proof_system/logderivative_library.hpp" +#include "barretenberg/polynomials/polynomial.hpp" +#include "barretenberg/polynomials/univariate.hpp" +#include "barretenberg/relations/relation_types.hpp" + +namespace proof_system::honk::sumcheck { +/** + * @brief Specifies positions of elements in the tuple of entities received from methods in the Settings class + * + */ + +template class GenericLookupRelationImpl { + public: + using FF = FF_; + + // Read terms specified how many maximum lookups can be performed in 1 row + static constexpr size_t READ_TERMS = Settings::READ_TERMS; + + // Looked up entries can be a basic tuple, a scaled tuple or completely arbitrary + enum READ_TERM_TYPES { READ_BASIC_TUPLE = 0, READ_SCALED_TUPLE, READ_ARBITRARY }; + + // Write terms specifies how many insertions into the lookup table can be performed in 1 row + static constexpr size_t WRITE_TERMS = Settings::WRITE_TERMS; + + // Entries put into the table are ever defined as a tuple or constructed arbitrarily + enum WRITE_TERM_TYPES { WRITE_BASIC_TUPLE = 0, WRITE_ARBITRARY }; + + // Lookup tuple size specifies how many values are bundled together to represent a single entry in the lookup table. + // For example, it would be 1 for a range constraint lookup, or 3 for XOR lookup + static constexpr size_t LOOKUP_TUPLE_SIZE = Settings::LOOKUP_TUPLE_SIZE; + + /** + * @brief Compute the maximum degree of read terms + * + * @details We need this to evaluate the length of the subrelations correctly + * @return constexpr size_t + */ + static constexpr size_t compute_maximum_read_term_degree() + { + size_t maximum_degree = 0; + for (size_t i = 0; i < READ_TERMS; i++) { + size_t current_degree = 0; + if (Settings::READ_TERM_TYPES[i] == READ_BASIC_TUPLE) { + current_degree = 1; + } else if (Settings::READ_TERM_TYPES[i] == READ_SCALED_TUPLE) { + current_degree = 2; + } else { + current_degree = Settings::READ_TERM_DEGREE; + } + maximum_degree = std::max(current_degree, maximum_degree); + } + return maximum_degree; + } + + /** + * @brief Compute the maximum degree of write terms + * + * @details We need this to evaluate the length of the subrelations correctly + * @return constexpr size_t + */ + static constexpr size_t compute_maximum_write_term_degree() + { + size_t maximum_degree = 0; + for (size_t i = 0; i < WRITE_TERMS; i++) { + size_t current_degree = 0; + if (Settings::WRITE_TERM_TYPES[i] == WRITE_BASIC_TUPLE) { + current_degree = 1; + } else { + current_degree = Settings::WRITE_TERM_DEGREE; + } + maximum_degree = std::max(current_degree, maximum_degree); + } + return maximum_degree; + } + + /** + * @brief Compute the degree of of the product of read terms + * + * @details The degree of the inverse polynomial check subrelation is dependent on this value + * + * @return constexpr size_t + */ + static constexpr size_t compute_read_term_product_degree() + { + size_t accumulated_degree = 0; + for (size_t i = 0; i < READ_TERMS; i++) { + size_t current_degree = 0; + if (Settings::READ_TERM_TYPES[i] == READ_BASIC_TUPLE) { + current_degree = 1; + } else if (Settings::READ_TERM_TYPES[i] == READ_SCALED_TUPLE) { + current_degree = 2; + } else { + current_degree = Settings::READ_TERM_DEGREE; + } + accumulated_degree += current_degree; + } + return accumulated_degree; + } + + /** + * @brief Compute the degree of of the product of write terms + * + * @details The degree of the inverse polynomial check subrelation is dependent on this value + * + * @return constexpr size_t + */ + static constexpr size_t compute_write_term_product_degree() + { + size_t accumulated_degree = 0; + for (size_t i = 0; i < WRITE_TERMS; i++) { + size_t current_degree = 0; + if (Settings::WRITE_TERM_TYPES[i] == WRITE_BASIC_TUPLE) { + current_degree = 1; + } else { + current_degree = Settings::WRITE_TERM_DEGREE; + } + accumulated_degree += current_degree; + } + return accumulated_degree; + } + + // Read term degree is dependent on what type of read term we use + static constexpr size_t READ_TERM_DEGREE = compute_maximum_read_term_degree(); + static_assert(READ_TERM_DEGREE != 0); + + // Write term degree is dependent on what type of write term we use + static constexpr size_t WRITE_TERM_DEGREE = compute_maximum_write_term_degree(); + + static_assert(WRITE_TERM_DEGREE != 0); + + // Compute the length of the inverse polynomial correctness sub-relation MAX(product of terms * inverse, inverse + // exists polynomial) + 1; + static constexpr size_t FIRST_SUBRELATION_LENGTH = + std::max((compute_read_term_product_degree() + compute_write_term_product_degree() + 1), + Settings::INVERSE_EXISTS_POLYNOMIAL_DEGREE) + + 1; + + // Compute the length of the log-derived term subrelation MAX(read term * enable read, write term * write count * + // enable write) + static constexpr size_t SECOND_SUBRELATION_LENGTH = std::max(READ_TERM_DEGREE + 1, WRITE_TERM_DEGREE + 2); + // 1 + polynomial degree of this relation + static constexpr size_t LENGTH = std::max(FIRST_SUBRELATION_LENGTH, SECOND_SUBRELATION_LENGTH); + + // The structure of polynomial tuple returned from Settings' functions get_const_entities and get_nonconst_entities + // is the following: + // 1) 1 Polynomial used to contain the inverse product from which we reconstruct individual inverses + // used in the sum + // 2) WRITE_TERMS number of polynomials representing how much each write term has been read + // 3) READ_TERMS number of polynomials enabling the addition of a particular read term in this row (should we lookup + // or not) + // 4) WRITE_TERMS number of polynomials enabling a particular write term in this row (should we add it to + // the lookup table or not) + // 5) For each read term depending on its type (READ_BASIC_TUPLE, READ_SCALED_TUPLE or READ_ARBITRARY): + // 1. In case of basic tuple LOOKUP_TUPLE_SIZE polynomials the combination of whose values in a row is supposed to + // represent the looked up entry + // 2. In case of scaled tuple there are LOOKUP_TUPLE_SIZE previous accumulator polynomials, LOOKUP_TUPLE_SIZE + // scaling polynomials and LOOKUP_TUPLE_SIZE current accumulator polynomials. The tuple is comprised of values + // (current_accumulator-scale*previous_accumulator) + // 3. In the arbitrary case the are no additional + // polynomials, because the logic is completely decided in the settings + // 6) For each write term depending on its type (READ_BASIC_TUPLE or READ_ARBITRARY): + // 1. In case of basic tuple LOOKUP_TUPLE_SIZE polynomials the combination of whose values in a row is supposed to + // represent the entry written into the lookup table + // 2. In the arbitrary case the are no additional write term polynomials, + // because the logic is completely decided in the settings + static constexpr size_t INVERSE_POLYNOMIAL_INDEX = 0; + static constexpr size_t LOOKUP_READ_COUNT_START_POLYNOMIAL_INDEX = 1; + static constexpr size_t LOOKUP_READ_TERM_PREDICATE_START_POLYNOMIAL_INDEX = + LOOKUP_READ_COUNT_START_POLYNOMIAL_INDEX + WRITE_TERMS; + static constexpr size_t LOOKUP_WRITE_TERM_PREDICATE_START_POLYNOMIAL_INDEX = + LOOKUP_READ_TERM_PREDICATE_START_POLYNOMIAL_INDEX + READ_TERMS; + static constexpr size_t LOOKUP_READ_PREDICATE_START_POLYNOMIAL_INDEX = + LOOKUP_WRITE_TERM_PREDICATE_START_POLYNOMIAL_INDEX + WRITE_TERMS; + + static constexpr std::array SUBRELATION_PARTIAL_LENGTHS{ + LENGTH, // inverse polynomial correctness sub-relation + LENGTH // log-derived terms subrelation + }; + /** + * @brief We apply the power polynomial only to the first subrelation + * + *@details The first subrelation establishes correspondence between the inverse polynomial elements and the terms. + *The second relation computes the inverses of individual terms, which are then summed up with sumcheck + * + */ + static constexpr std::array SUBRELATION_LINEARLY_INDEPENDENT = { true, false }; + + /** + * @brief Check if we need to compute the inverse polynomial element value for this row + * @details This proxies to a method in the Settings class + * + * @param row All values at row + */ + template static bool operation_exists_at_row(const AllValues& row) + + { + return Settings::inverse_polynomial_is_computed_at_row(row); + } + + /** + * @brief Get the inverse permutation polynomial (needed to compute its value) + * + */ + template static auto& get_inverse_polynomial(AllEntities& in) + { + // WIRE containing the inverse of the product of terms at this row. Used to reconstruct individual inversed + // terms + return std::get(Settings::get_nonconst_entities(in)); + } + + /** + * @brief Get selector/wire switching on(1) or off(0) inverse computation + * + */ + template + static Accumulator compute_inverse_exists(const AllEntities& in) + { + + // A lookup could be enabled by one of several selectors or witnesses, so we want to give as much freedom as + // possible to the implementor + return Settings::template compute_inverse_exists(in); + } + + /** + * @brief Returns the number of times a particular value is written (how many times it is being looked up) + * + * @details Lookup read counts should be independent columns, so there is no need to call a separate function + * + * @tparam Accumulator + * @tparam index The index of the write predicate to which this count belongs + * @tparam AllEntities + * @param in + * @return Accumulator + */ + template + static Accumulator lookup_read_counts(const AllEntities& in) + { + + static_assert(index < WRITE_TERMS); + using View = typename Accumulator::View; + + return Accumulator( + View(std::get(Settings::get_const_entities(in)))); + } + /** + * @brief Compute if the value from the first set exists in this row + * + * @tparam read_index Kept for compatibility with lookups, behavior doesn't change + */ + template + static Accumulator compute_read_term_predicate(const AllEntities& in) + + { + static_assert(read_index < READ_TERMS); + using View = typename Accumulator::View; + + // The selector/wire value that determines that an element from the first set needs to be included. Can be + // different from the wire used in the write part. + return Accumulator(View(std::get( + Settings::get_const_entities(in)))); + } + + /** + * @brief Compute if the value from the second set exists in this row + * + * @tparam write_index Kept for compatibility with lookups, behavior doesn't change + */ + template + static Accumulator compute_write_term_predicate(const AllEntities& in) + { + + static_assert(write_index < WRITE_TERMS); + using View = typename Accumulator::View; + + // The selector/wire value that determines that an element from the first set needs to be included. Can be + // different from the wire used in the write part. + return Accumulator(View(std::get( + Settings::get_const_entities(in)))); + } + + /** + * @brief Compute where the polynomials defining a particular read term are located + * + * @details We pass polynomials involved in read an write terms from settings as a tuple of references. However, + * depending on the type of read term different number of polynomials can be used to compute it. So we need to + * compute the offset in the tuple iteratively + * + * @param read_index Index of the read term + * @return constexpr size_t + */ + static constexpr size_t compute_read_term_polynomial_offset(size_t read_index) + { + // If it's the starting index, then there is nothing to compute, just get the starting index + if (read_index == 0) { + return LOOKUP_READ_PREDICATE_START_POLYNOMIAL_INDEX; + } + + // If the previous term used basic tuple lookup, add lookup tuple size (it was using just a linear combination + // of polynomials) + if (Settings::READ_TERM_TYPES[read_index - 1] == READ_BASIC_TUPLE) { + return compute_read_term_polynomial_offset(read_index - 1) + LOOKUP_TUPLE_SIZE; + } + + // If the previous term used scaled tuple lookup, add lookup tuple size x 3 (it was using just a linear + // combination of differences (current - previousâ‹…scale)) + + if (Settings::READ_TERM_TYPES[read_index - 1] == READ_SCALED_TUPLE) { + return compute_read_term_polynomial_offset(read_index - 1) + 3 * LOOKUP_TUPLE_SIZE; + } + // In case of arbitrary read term, no polynomials from the tuple are being used + if (Settings::READ_TERM_TYPES[read_index - 1] == READ_ARBITRARY) { + return compute_read_term_polynomial_offset(read_index - 1); + } + return SIZE_MAX; + } + + /** + * @brief Compute where the polynomials defining a particular write term are located + * + * @details We pass polynomials involved in read an write terms from settings as a tuple of references. However, + * depending on the type of term different number of polynomials can be used to compute it. So we need to + * compute the offset in the tuple iteratively + * + * @param write_index Index of the write term + * @return constexpr size_t + */ + static constexpr size_t compute_write_term_polynomial_offset(size_t write_index) + { + // If it's the starting index, then we need to find out how many polynomials were taken by read terms + if (write_index == 0) { + return compute_read_term_polynomial_offset(READ_TERMS); + } + + // If the previous term used basic tuple lookup, add lookup tuple size (it was using just a linear combination + // of polynomials) + if (Settings::WRITE_TERM_TYPES[write_index - 1] == WRITE_BASIC_TUPLE) { + return compute_write_term_polynomial_offset(write_index - 1) + LOOKUP_TUPLE_SIZE; + } + + // In case of arbitrary write term, no polynomials from the tuple are being used + if (Settings::WRITE_TERM_TYPES[write_index - 1] == WRITE_ARBITRARY) { + return compute_write_term_polynomial_offset(write_index - 1); + } + return SIZE_MAX; + } + + /** + * @brief Compute the value of a single item in the set + * + * @details Computes the polynomial \gamma + \sum_{i=0}^{num_columns}(column_i*\beta^i), so the tuple of columns is + * in the first set + * + * @tparam read_index The chosen polynomial relation + * + * @param params Used for beta and gamma + */ + template + static Accumulator compute_read_term(const AllEntities& in, const Parameters& params) + { + using View = typename Accumulator::View; + + static_assert(read_index < READ_TERMS); + constexpr size_t start_polynomial_index = compute_read_term_polynomial_offset(read_index); + if constexpr (Settings::READ_TERM_TYPES[read_index] == READ_BASIC_TUPLE) { + // Retrieve all polynomials used + const auto all_polynomials = Settings::get_const_entities(in); + + auto result = Accumulator(0); + + // Iterate over tuple and sum as a polynomial over beta + barretenberg::constexpr_for( + [&]() { result = (result * params.beta) + View(std::get(all_polynomials)); }); + const auto& gamma = params.gamma; + return result + gamma; + } else if constexpr (Settings::READ_TERM_TYPES[read_index] == READ_SCALED_TUPLE) { + // Retrieve all polynomials used + const auto all_polynomials = Settings::get_const_entities(in); + + auto result = Accumulator(0); + // Iterate over tuple and sum as a polynomial over beta + barretenberg::constexpr_for( + [&]() { + result = + (result * params.beta) + View(std::get(all_polynomials)) - + View(std::get(all_polynomials)) * View(std::get(all_polynomials)); + }); + const auto& gamma = params.gamma; + return result + gamma; + } else { + + return Settings::template compute_read_term(in, params); + } + } + + /** + * @brief Compute the value of a single item in the set + * + * @details Computes the polynomial \gamma + \sum_{i=0}^{num_columns}(column_i*\beta^i), so the tuple of columns is + * in the second set + * + * @tparam write_index Kept for compatibility with lookups, behavior doesn't change + * + * @param params Used for beta and gamma + */ + template + static Accumulator compute_write_term(const AllEntities& in, const Parameters& params) + { + + static_assert(write_index < WRITE_TERMS); + + using View = typename Accumulator::View; + constexpr size_t start_polynomial_index = compute_write_term_polynomial_offset(write_index); + + if constexpr (Settings::WRITE_TERM_TYPES[write_index] == WRITE_BASIC_TUPLE) { + // Retrieve all polynomials used + const auto all_polynomials = Settings::get_const_entities(in); + + auto result = Accumulator(0); + + // Iterate over tuple and sum as a polynomial over beta + barretenberg::constexpr_for( + [&]() { result = (result * params.beta) + View(std::get(all_polynomials)); }); + const auto& gamma = params.gamma; + return result + gamma; + } else { + // Sometimes we construct lookup tables on the fly from intermediate + + return Settings::template compute_write_term(in, params); + } + } + + /** + * @brief Expression for generic log-derivative-based set permutation. + * @param accumulator transformed to `evals + C(in(X)...)*scaling_factor` + * @param in an std::array containing the fully extended Accumulator edges. + * @param relation_params contains beta, gamma, and public_input_delta, .... + * @param scaling_factor optional term to scale the evaluation before adding to evals. + */ + /** + * @brief Expression for generic log-derivative-based set permutation. + * @param accumulator transformed to `evals + C(in(X)...)*scaling_factor` + * @param in an std::array containing the fully extended Accumulator edges. + * @param relation_params contains beta, gamma, and public_input_delta, .... + * @param scaling_factor optional term to scale the evaluation before adding to evals. + */ + template + static void accumulate(ContainerOverSubrelations& accumulator, + const AllEntities& in, + const Parameters& params, + const FF& scaling_factor) + { + logderivative_library:: + accumulate_logderivative_lookup_subrelation_contributions>( + accumulator, in, params, scaling_factor); + } +}; + +template +using GenericLookupRelation = Relation>; + +template using GenericLookup = GenericLookupRelationImpl; + +} // namespace proof_system::honk::sumcheck \ No newline at end of file diff --git a/barretenberg/cpp/src/barretenberg/relations/generic_permutation/generic_permutation_relation.hpp b/barretenberg/cpp/src/barretenberg/relations/generic_permutation/generic_permutation_relation.hpp index b0b917885f4..6fd7159ba37 100644 --- a/barretenberg/cpp/src/barretenberg/relations/generic_permutation/generic_permutation_relation.hpp +++ b/barretenberg/cpp/src/barretenberg/relations/generic_permutation/generic_permutation_relation.hpp @@ -102,7 +102,7 @@ template class GenericPermutationRelationImpl static Accumulator compute_read_term_predicate(const AllEntities& in) { - static_assert(read_index < WRITE_TERMS); + static_assert(read_index < READ_TERMS); using View = typename Accumulator::View; // The selector/wire value that determines that an element from the first set needs to be included. Can be diff --git a/barretenberg/cpp/src/barretenberg/vm/generated/Toy_verifier.cpp b/barretenberg/cpp/src/barretenberg/vm/generated/Toy_verifier.cpp index e92eb206f29..02c29056ce0 100644 --- a/barretenberg/cpp/src/barretenberg/vm/generated/Toy_verifier.cpp +++ b/barretenberg/cpp/src/barretenberg/vm/generated/Toy_verifier.cpp @@ -65,9 +65,23 @@ bool ToyVerifier::verify_proof(const plonk::proof& proof) transcript->template receive_from_prover(commitment_labels.toy_set_2_column_1); commitments.toy_set_2_column_2 = transcript->template receive_from_prover(commitment_labels.toy_set_2_column_2); - commitments.toy_x = transcript->template receive_from_prover(commitment_labels.toy_x); + commitments.toy_xor_a = transcript->template receive_from_prover(commitment_labels.toy_xor_a); + commitments.toy_xor_b = transcript->template receive_from_prover(commitment_labels.toy_xor_b); + commitments.toy_xor_c = transcript->template receive_from_prover(commitment_labels.toy_xor_c); + commitments.toy_table_xor_a = + transcript->template receive_from_prover(commitment_labels.toy_table_xor_a); + commitments.toy_table_xor_b = + transcript->template receive_from_prover(commitment_labels.toy_table_xor_b); + commitments.toy_table_xor_c = + transcript->template receive_from_prover(commitment_labels.toy_table_xor_c); + commitments.toy_q_xor = transcript->template receive_from_prover(commitment_labels.toy_q_xor); + commitments.toy_q_xor_table = + transcript->template receive_from_prover(commitment_labels.toy_q_xor_table); commitments.two_column_perm = transcript->template receive_from_prover(commitment_labels.two_column_perm); + commitments.lookup_xor = transcript->template receive_from_prover(commitment_labels.lookup_xor); + commitments.lookup_xor_counts = + transcript->template receive_from_prover(commitment_labels.lookup_xor_counts); // Execute Sumcheck Verifier auto sumcheck = SumcheckVerifier(circuit_size);