From 59897f8e30e616bba6f97679ed2ece73fbba5fcb Mon Sep 17 00:00:00 2001 From: ledwards2225 Date: Mon, 15 May 2023 19:26:33 +0000 Subject: [PATCH 01/18] multi constraint paradigm in place for Standard --- .../composer/standard_honk_composer.test.cpp | 3 +- .../composer/ultra_honk_composer.test.cpp | 1704 +++++++++-------- .../barretenberg/honk/proof_system/prover.cpp | 10 +- .../honk/proof_system/ultra_prover.cpp | 724 +++---- .../honk/proof_system/ultra_verifier.cpp | 373 ++-- .../honk/proof_system/verifier.cpp | 11 +- .../honk/sumcheck/new_sumcheck.test.cpp | 304 +++ .../polynomials/barycentric_data.test.cpp | 172 +- .../polynomials/multivariates.test.cpp | 640 +++---- .../honk/sumcheck/polynomials/pow.test.cpp | 40 +- .../relations/arithmetic_relation.hpp | 20 +- ..._relation.hpp => permutation_relation.hpp} | 59 +- .../relations/relation_consistency.test.cpp | 208 +- .../relations/relation_correctness.test.cpp | 639 ++++--- .../relations/ultra_arithmetic_relation.hpp | 6 + .../ultra_relation_consistency.test.cpp | 1397 +++++++------- .../honk/sumcheck/sumcheck.test.cpp | 49 +- .../honk/sumcheck/sumcheck_round.hpp | 235 ++- .../honk/sumcheck/sumcheck_round.test.cpp | 655 +++---- .../honk/transcript/transcript.test.cpp | 62 +- 20 files changed, 3887 insertions(+), 3424 deletions(-) create mode 100644 cpp/src/barretenberg/honk/sumcheck/new_sumcheck.test.cpp rename cpp/src/barretenberg/honk/sumcheck/relations/{grand_product_computation_relation.hpp => permutation_relation.hpp} (75%) diff --git a/cpp/src/barretenberg/honk/composer/standard_honk_composer.test.cpp b/cpp/src/barretenberg/honk/composer/standard_honk_composer.test.cpp index 78a8c930ad..e076534f21 100644 --- a/cpp/src/barretenberg/honk/composer/standard_honk_composer.test.cpp +++ b/cpp/src/barretenberg/honk/composer/standard_honk_composer.test.cpp @@ -6,8 +6,7 @@ #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/sumcheck/relations/permutation_relation.hpp" #include "barretenberg/polynomials/polynomial.hpp" #pragma GCC diagnostic ignored "-Wunused-variable" 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 09b3373e7f..20ebd8d10c 100644 --- a/cpp/src/barretenberg/honk/composer/ultra_honk_composer.test.cpp +++ b/cpp/src/barretenberg/honk/composer/ultra_honk_composer.test.cpp @@ -1,869 +1,873 @@ -#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 -#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/grand_product_delta.hpp" -#include "barretenberg/proof_system/plookup_tables/types.hpp" - -#include -#include -#include - -using namespace proof_system::honk; - -namespace test_ultra_honk_composer { - -namespace { -auto& engine = numeric::random::get_debug_engine(); -} - -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; -} - -bool construct_and_verify_proof(auto& composer) -{ - auto prover = composer.create_prover(); - auto proof = prover.construct_proof(); - - auto verifier = composer.create_verifier(); - bool result = verifier.verify_proof(proof); - - return result; -} - -void prove_and_verify(auto& composer, bool expected_result) -{ - auto prover = composer.create_prover(); - auto verifier = composer.create_verifier(); - auto proof = prover.construct_proof(); - bool verified = verifier.verify_proof(proof); - EXPECT_EQ(verified, expected_result); -}; - -void ensure_non_zero(auto& polynomial) -{ - bool has_non_zero_coefficient = false; - for (auto& coeff : polynomial) { - has_non_zero_coefficient |= !coeff.is_zero(); - } - ASSERT_TRUE(has_non_zero_coefficient); -} - -/** - * @brief A quick test to ensure that none of our polynomials are identically zero - * - * @note This test assumes that gates have been added by default in the circuit - * constructor to achieve non-zero polynomials - * - */ -TEST(UltraHonkComposer, ANonZeroPolynomialIsAGoodPolynomial) -{ - auto composer = UltraHonkComposer(); - - composer.add_gates_to_ensure_all_polys_are_non_zero(); - - auto prover = composer.create_prover(); - auto proof = prover.construct_proof(); - - for (auto& poly : prover.key->get_selectors()) { - ensure_non_zero(poly); - } - - for (auto& poly : prover.key->get_table_polynomials()) { - ensure_non_zero(poly); - } - - for (auto& poly : prover.key->get_wires()) { - ensure_non_zero(poly); - } -} - -TEST(UltraHonkComposer, XorConstraint) -{ - auto composer = UltraHonkComposer(); - - uint32_t left_value = engine.get_random_uint32(); - uint32_t right_value = engine.get_random_uint32(); - - fr left_witness_value = fr{ left_value, 0, 0, 0 }.to_montgomery_form(); - fr right_witness_value = fr{ right_value, 0, 0, 0 }.to_montgomery_form(); - - uint32_t left_witness_index = composer.add_variable(left_witness_value); - uint32_t right_witness_index = composer.add_variable(right_witness_value); - - uint32_t xor_result_expected = left_value ^ right_value; - - const auto lookup_accumulators = plookup::get_lookup_accumulators( - plookup::MultiTableId::UINT32_XOR, left_witness_value, right_witness_value, true); - auto xor_result = lookup_accumulators[plookup::ColumnIdx::C3] - [0]; // The zeroth index in the 3rd column is the fully accumulated xor result - EXPECT_EQ(xor_result, xor_result_expected); - - composer.create_gates_from_plookup_accumulators( - plookup::MultiTableId::UINT32_XOR, lookup_accumulators, left_witness_index, right_witness_index); - - prove_and_verify(composer, /*expected_result=*/true); -} - -TEST(UltraHonkComposer, create_gates_from_plookup_accumulators) -{ - auto composer = UltraHonkComposer(); - - 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 = composer.add_variable(input_hi); - const auto input_lo_index = 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 = composer.create_gates_from_plookup_accumulators( - plookup::MultiTableId::PEDERSEN_LEFT_HI, sequence_data_hi, input_hi_index); - const auto lookup_witnesses_lo = composer.create_gates_from_plookup_accumulators( - plookup::MultiTableId::PEDERSEN_LEFT_LO, sequence_data_lo, input_lo_index); - - std::vector expected_x; - std::vector expected_y; - - const size_t num_lookups_hi = - (128 + crypto::pedersen_hash::lookup::BITS_PER_TABLE) / crypto::pedersen_hash::lookup::BITS_PER_TABLE; - const size_t num_lookups_lo = 126 / crypto::pedersen_hash::lookup::BITS_PER_TABLE; - const size_t num_lookups = num_lookups_hi + num_lookups_lo; - - EXPECT_EQ(num_lookups_hi, lookup_witnesses_hi[plookup::ColumnIdx::C1].size()); - EXPECT_EQ(num_lookups_lo, lookup_witnesses_lo[plookup::ColumnIdx::C1].size()); - - std::vector expected_scalars; - expected_x.resize(num_lookups); - expected_y.resize(num_lookups); - expected_scalars.resize(num_lookups); - - { - const size_t num_rounds = (num_lookups + 1) / 2; - uint256_t bits(input_value); - - const auto mask = crypto::pedersen_hash::lookup::PEDERSEN_TABLE_SIZE - 1; - - for (size_t i = 0; i < num_rounds; ++i) { - const auto& table = crypto::pedersen_hash::lookup::get_table(i); - const size_t index = i * 2; - - uint64_t slice_a = ((bits >> (index * 9)) & mask).data[0]; - expected_x[index] = (table[(size_t)slice_a].x); - expected_y[index] = (table[(size_t)slice_a].y); - expected_scalars[index] = slice_a; - - if (i < 14) { - uint64_t slice_b = ((bits >> ((index + 1) * 9)) & mask).data[0]; - expected_x[index + 1] = (table[(size_t)slice_b].x); - expected_y[index + 1] = (table[(size_t)slice_b].y); - expected_scalars[index + 1] = slice_b; - } - } - } - - for (size_t i = num_lookups - 2; i < num_lookups; --i) { - expected_scalars[i] += (expected_scalars[i + 1] * crypto::pedersen_hash::lookup::PEDERSEN_TABLE_SIZE); - } - - size_t hi_shift = 126; - const fr hi_cumulative = composer.get_variable(lookup_witnesses_hi[plookup::ColumnIdx::C1][0]); - for (size_t i = 0; i < num_lookups_lo; ++i) { - const fr hi_mult = fr(uint256_t(1) << hi_shift); - EXPECT_EQ(composer.get_variable(lookup_witnesses_lo[plookup::ColumnIdx::C1][i]) + (hi_cumulative * hi_mult), - expected_scalars[i]); - EXPECT_EQ(composer.get_variable(lookup_witnesses_lo[plookup::ColumnIdx::C2][i]), expected_x[i]); - EXPECT_EQ(composer.get_variable(lookup_witnesses_lo[plookup::ColumnIdx::C3][i]), expected_y[i]); - hi_shift -= crypto::pedersen_hash::lookup::BITS_PER_TABLE; - } - - for (size_t i = 0; i < num_lookups_hi; ++i) { - EXPECT_EQ(composer.get_variable(lookup_witnesses_hi[plookup::ColumnIdx::C1][i]), - expected_scalars[i + num_lookups_lo]); - EXPECT_EQ(composer.get_variable(lookup_witnesses_hi[plookup::ColumnIdx::C2][i]), - expected_x[i + num_lookups_lo]); - EXPECT_EQ(composer.get_variable(lookup_witnesses_hi[plookup::ColumnIdx::C3][i]), - expected_y[i + num_lookups_lo]); - } - - auto prover = composer.create_prover(); - auto verifier = composer.create_verifier(); - auto proof = prover.construct_proof(); - - bool result = verifier.verify_proof(proof); - - EXPECT_EQ(result, true); -} - -TEST(UltraHonkComposer, test_no_lookup_proof) -{ - auto composer = UltraHonkComposer(); - - for (size_t i = 0; i < 16; ++i) { - for (size_t j = 0; j < 16; ++j) { - uint64_t left = static_cast(j); - uint64_t right = static_cast(i); - uint32_t left_idx = composer.add_variable(fr(left)); - uint32_t right_idx = composer.add_variable(fr(right)); - uint32_t result_idx = composer.add_variable(fr(left ^ right)); - - uint32_t add_idx = composer.add_variable(fr(left) + fr(right) + composer.get_variable(result_idx)); - composer.create_big_add_gate( - { left_idx, right_idx, result_idx, add_idx, fr(1), fr(1), fr(1), fr(-1), fr(0) }); - } - } - - prove_and_verify(composer, /*expected_result=*/true); -} - -TEST(UltraHonkComposer, test_elliptic_gate) -{ - typedef grumpkin::g1::affine_element affine_element; - typedef grumpkin::g1::element element; - auto composer = UltraHonkComposer(); - - 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 = composer.add_variable(p1.x); - uint32_t y1 = composer.add_variable(p1.y); - uint32_t x2 = composer.add_variable(p2.x); - uint32_t y2 = composer.add_variable(p2.y); - uint32_t x3 = composer.add_variable(p3.x); - uint32_t y3 = composer.add_variable(p3.y); - - ecc_add_gate gate{ x1, y1, x2, y2, x3, y3, 1, 1 }; - 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 = composer.add_variable(p3.x); - y3 = composer.add_variable(p3.y); - gate = ecc_add_gate{ x1, y1, x2, y2, x3, y3, beta, 1 }; - composer.create_ecc_add_gate(gate); - - p2_endo.x *= beta; - p3 = affine_element(element(p1) - element(p2_endo)); - x3 = composer.add_variable(p3.x); - y3 = composer.add_variable(p3.y); - gate = ecc_add_gate{ x1, y1, x2, y2, x3, y3, beta.sqr(), -1 }; - composer.create_ecc_add_gate(gate); - - prove_and_verify(composer, /*expected_result=*/true); -} - -TEST(UltraHonkComposer, non_trivial_tag_permutation) -{ - auto composer = UltraHonkComposer(); - fr a = fr::random_element(); - fr b = -a; - - auto a_idx = composer.add_variable(a); - auto b_idx = composer.add_variable(b); - auto c_idx = composer.add_variable(b); - auto d_idx = composer.add_variable(a); - - composer.create_add_gate({ a_idx, b_idx, composer.get_zero_idx(), fr::one(), fr::one(), fr::zero(), fr::zero() }); - composer.create_add_gate({ c_idx, d_idx, composer.get_zero_idx(), fr::one(), fr::one(), fr::zero(), fr::zero() }); - - composer.create_tag(1, 2); - composer.create_tag(2, 1); - - composer.assign_tag(a_idx, 1); - composer.assign_tag(b_idx, 1); - composer.assign_tag(c_idx, 2); - composer.assign_tag(d_idx, 2); - - prove_and_verify(composer, /*expected_result=*/true); -} - -TEST(UltraHonkComposer, non_trivial_tag_permutation_and_cycles) -{ - auto composer = UltraHonkComposer(); - fr a = fr::random_element(); - fr c = -a; - - auto a_idx = composer.add_variable(a); - auto b_idx = composer.add_variable(a); - composer.assert_equal(a_idx, b_idx); - auto c_idx = composer.add_variable(c); - auto d_idx = composer.add_variable(c); - composer.assert_equal(c_idx, d_idx); - auto e_idx = composer.add_variable(a); - auto f_idx = composer.add_variable(a); - composer.assert_equal(e_idx, f_idx); - auto g_idx = composer.add_variable(c); - auto h_idx = composer.add_variable(c); - composer.assert_equal(g_idx, h_idx); - - composer.create_tag(1, 2); - composer.create_tag(2, 1); - - composer.assign_tag(a_idx, 1); - composer.assign_tag(c_idx, 1); - composer.assign_tag(e_idx, 2); - composer.assign_tag(g_idx, 2); - - composer.create_add_gate( - { b_idx, a_idx, composer.get_zero_idx(), fr::one(), fr::neg_one(), fr::zero(), fr::zero() }); - composer.create_add_gate({ c_idx, g_idx, composer.get_zero_idx(), fr::one(), -fr::one(), fr::zero(), fr::zero() }); - composer.create_add_gate({ e_idx, f_idx, composer.get_zero_idx(), fr::one(), -fr::one(), fr::zero(), fr::zero() }); - - prove_and_verify(composer, /*expected_result=*/true); -} - -TEST(UltraHonkComposer, bad_tag_permutation) -{ - auto composer = UltraHonkComposer(); - fr a = fr::random_element(); - fr b = -a; - - auto a_idx = composer.add_variable(a); - auto b_idx = composer.add_variable(b); - auto c_idx = composer.add_variable(b); - auto d_idx = composer.add_variable(a + 1); - - composer.create_add_gate({ a_idx, b_idx, composer.get_zero_idx(), 1, 1, 0, 0 }); - composer.create_add_gate({ c_idx, d_idx, composer.get_zero_idx(), 1, 1, 0, -1 }); - - composer.create_tag(1, 2); - composer.create_tag(2, 1); - - composer.assign_tag(a_idx, 1); - composer.assign_tag(b_idx, 1); - composer.assign_tag(c_idx, 2); - composer.assign_tag(d_idx, 2); - - prove_and_verify(composer, /*expected_result=*/false); -} - -// same as above but with turbocomposer to check reason of failue is really tag mismatch -TEST(UltraHonkComposer, bad_tag_turbo_permutation) -{ - auto composer = UltraHonkComposer(); - fr a = fr::random_element(); - fr b = -a; - - auto a_idx = composer.add_variable(a); - auto b_idx = composer.add_variable(b); - auto c_idx = composer.add_variable(b); - auto d_idx = composer.add_variable(a + 1); - - composer.create_add_gate({ a_idx, b_idx, composer.get_zero_idx(), 1, 1, 0, 0 }); - composer.create_add_gate({ c_idx, d_idx, composer.get_zero_idx(), 1, 1, 0, -1 }); - - // composer.create_add_gate({ a_idx, b_idx, composer.get_zero_idx(), fr::one(), fr::neg_one(), fr::zero(), - // fr::zero() }); composer.create_add_gate({ a_idx, b_idx, composer.get_zero_idx(), fr::one(), fr::neg_one(), - // fr::zero(), fr::zero() }); composer.create_add_gate({ a_idx, b_idx, composer.get_zero_idx(), fr::one(), - // fr::neg_one(), fr::zero(), fr::zero() }); - auto prover = composer.create_prover(); - auto verifier = composer.create_verifier(); - - prove_and_verify(composer, /*expected_result=*/true); -} - -TEST(UltraHonkComposer, sort_widget) -{ - auto composer = UltraHonkComposer(); - fr a = fr::one(); - fr b = fr(2); - fr c = fr(3); - fr d = fr(4); - - auto a_idx = composer.add_variable(a); - auto b_idx = composer.add_variable(b); - auto c_idx = composer.add_variable(c); - auto d_idx = composer.add_variable(d); - composer.create_sort_constraint({ a_idx, b_idx, c_idx, d_idx }); - - prove_and_verify(composer, /*expected_result=*/true); -} - -TEST(UltraHonkComposer, sort_with_edges_gate) -{ - - fr a = fr::one(); - fr b = fr(2); - fr c = fr(3); - fr d = fr(4); - fr e = fr(5); - fr f = fr(6); - fr g = fr(7); - fr h = fr(8); - - { - auto composer = UltraHonkComposer(); - auto a_idx = composer.add_variable(a); - auto b_idx = composer.add_variable(b); - auto c_idx = composer.add_variable(c); - auto d_idx = composer.add_variable(d); - auto e_idx = composer.add_variable(e); - auto f_idx = composer.add_variable(f); - auto g_idx = composer.add_variable(g); - auto h_idx = composer.add_variable(h); - composer.create_sort_constraint_with_edges({ a_idx, b_idx, c_idx, d_idx, e_idx, f_idx, g_idx, h_idx }, a, h); - - prove_and_verify(composer, /*expected_result=*/true); - } - - { - auto composer = UltraHonkComposer(); - auto a_idx = composer.add_variable(a); - auto b_idx = composer.add_variable(b); - auto c_idx = composer.add_variable(c); - auto d_idx = composer.add_variable(d); - auto e_idx = composer.add_variable(e); - auto f_idx = composer.add_variable(f); - auto g_idx = composer.add_variable(g); - auto h_idx = composer.add_variable(h); - composer.create_sort_constraint_with_edges({ a_idx, b_idx, c_idx, d_idx, e_idx, f_idx, g_idx, h_idx }, a, g); - - prove_and_verify(composer, /*expected_result=*/false); - } - { - auto composer = UltraHonkComposer(); - auto a_idx = composer.add_variable(a); - auto b_idx = composer.add_variable(b); - auto c_idx = composer.add_variable(c); - auto d_idx = composer.add_variable(d); - auto e_idx = composer.add_variable(e); - auto f_idx = composer.add_variable(f); - auto g_idx = composer.add_variable(g); - auto h_idx = composer.add_variable(h); - composer.create_sort_constraint_with_edges({ a_idx, b_idx, c_idx, d_idx, e_idx, f_idx, g_idx, h_idx }, b, h); - - prove_and_verify(composer, /*expected_result=*/false); - } - { - auto composer = UltraHonkComposer(); - auto a_idx = composer.add_variable(a); - auto c_idx = composer.add_variable(c); - auto d_idx = composer.add_variable(d); - auto e_idx = composer.add_variable(e); - auto f_idx = composer.add_variable(f); - auto g_idx = composer.add_variable(g); - auto h_idx = composer.add_variable(h); - auto b2_idx = composer.add_variable(fr(15)); - composer.create_sort_constraint_with_edges({ a_idx, b2_idx, c_idx, d_idx, e_idx, f_idx, g_idx, h_idx }, b, h); - - prove_and_verify(composer, /*expected_result=*/false); - } - { - auto composer = UltraHonkComposer(); - auto idx = add_variables(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 }); - composer.create_sort_constraint_with_edges(idx, 1, 45); - - prove_and_verify(composer, /*expected_result=*/true); - } - { - auto composer = UltraHonkComposer(); - auto idx = add_variables(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 }); - - composer.create_sort_constraint_with_edges(idx, 1, 29); - - prove_and_verify(composer, /*expected_result=*/false); - } -} - -TEST(UltraHonkComposer, range_constraint) -{ - { - auto composer = UltraHonkComposer(); - auto indices = add_variables(composer, { 1, 2, 3, 4, 5, 6, 7, 8 }); - for (size_t i = 0; i < indices.size(); i++) { - composer.create_new_range_constraint(indices[i], 8); - } - // auto ind = {a_idx,b_idx,c_idx,d_idx,e_idx,f_idx,g_idx,h_idx}; - composer.create_sort_constraint(indices); - - prove_and_verify(composer, /*expected_result=*/true); - } - { - auto composer = UltraHonkComposer(); - auto indices = add_variables(composer, { 3 }); - for (size_t i = 0; i < indices.size(); i++) { - composer.create_new_range_constraint(indices[i], 3); - } - // auto ind = {a_idx,b_idx,c_idx,d_idx,e_idx,f_idx,g_idx,h_idx}; - composer.create_dummy_constraints(indices); - - prove_and_verify(composer, /*expected_result=*/true); - } - { - auto composer = UltraHonkComposer(); - auto indices = add_variables(composer, { 1, 2, 3, 4, 5, 6, 8, 25 }); - for (size_t i = 0; i < indices.size(); i++) { - composer.create_new_range_constraint(indices[i], 8); - } - composer.create_sort_constraint(indices); - - prove_and_verify(composer, /*expected_result=*/false); - } - { - auto composer = UltraHonkComposer(); - auto indices = - add_variables(composer, { 1, 2, 3, 4, 5, 6, 10, 8, 15, 11, 32, 21, 42, 79, 16, 10, 3, 26, 19, 51 }); - for (size_t i = 0; i < indices.size(); i++) { - composer.create_new_range_constraint(indices[i], 128); - } - composer.create_dummy_constraints(indices); - - prove_and_verify(composer, /*expected_result=*/true); - } - { - auto composer = UltraHonkComposer(); - auto indices = - add_variables(composer, { 1, 2, 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++) { - composer.create_new_range_constraint(indices[i], 79); - } - composer.create_dummy_constraints(indices); - - prove_and_verify(composer, /*expected_result=*/false); - } - { - auto composer = UltraHonkComposer(); - auto indices = - add_variables(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++) { - composer.create_new_range_constraint(indices[i], 79); - } - composer.create_dummy_constraints(indices); - - prove_and_verify(composer, /*expected_result=*/false); - } -} - -TEST(UltraHonkComposer, range_with_gates) -{ - - auto composer = UltraHonkComposer(); - auto idx = add_variables(composer, { 1, 2, 3, 4, 5, 6, 7, 8 }); - for (size_t i = 0; i < idx.size(); i++) { - composer.create_new_range_constraint(idx[i], 8); - } - - composer.create_add_gate({ idx[0], idx[1], composer.get_zero_idx(), fr::one(), fr::one(), fr::zero(), -3 }); - composer.create_add_gate({ idx[2], idx[3], composer.get_zero_idx(), fr::one(), fr::one(), fr::zero(), -7 }); - composer.create_add_gate({ idx[4], idx[5], composer.get_zero_idx(), fr::one(), fr::one(), fr::zero(), -11 }); - composer.create_add_gate({ idx[6], idx[7], composer.get_zero_idx(), fr::one(), fr::one(), fr::zero(), -15 }); - - prove_and_verify(composer, /*expected_result=*/true); -} - -TEST(UltraHonkComposer, range_with_gates_where_range_is_not_a_power_of_two) -{ - auto composer = UltraHonkComposer(); - auto idx = add_variables(composer, { 1, 2, 3, 4, 5, 6, 7, 8 }); - for (size_t i = 0; i < idx.size(); i++) { - composer.create_new_range_constraint(idx[i], 12); - } - - composer.create_add_gate({ idx[0], idx[1], composer.get_zero_idx(), fr::one(), fr::one(), fr::zero(), -3 }); - composer.create_add_gate({ idx[2], idx[3], composer.get_zero_idx(), fr::one(), fr::one(), fr::zero(), -7 }); - composer.create_add_gate({ idx[4], idx[5], composer.get_zero_idx(), fr::one(), fr::one(), fr::zero(), -11 }); - composer.create_add_gate({ idx[6], idx[7], composer.get_zero_idx(), fr::one(), fr::one(), fr::zero(), -15 }); - - prove_and_verify(composer, /*expected_result=*/true); -} - -TEST(UltraHonkComposer, sort_widget_complex) -{ - { - - auto composer = UltraHonkComposer(); - std::vector a = { 1, 3, 4, 7, 7, 8, 11, 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(composer.add_variable(a[i])); - composer.create_sort_constraint(ind); - - prove_and_verify(composer, /*expected_result=*/true); - } - { - - auto composer = UltraHonkComposer(); - 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(composer.add_variable(a[i])); - composer.create_sort_constraint(ind); - - prove_and_verify(composer, /*expected_result=*/false); - } -} - -TEST(UltraHonkComposer, sort_widget_neg) -{ - auto composer = UltraHonkComposer(); - fr a = fr::one(); - fr b = fr(2); - fr c = fr(3); - fr d = fr(8); - - auto a_idx = composer.add_variable(a); - auto b_idx = composer.add_variable(b); - auto c_idx = composer.add_variable(c); - auto d_idx = composer.add_variable(d); - composer.create_sort_constraint({ a_idx, b_idx, c_idx, d_idx }); - - prove_and_verify(composer, /*expected_result=*/false); -} - -TEST(UltraHonkComposer, composed_range_constraint) -{ - auto composer = UltraHonkComposer(); - auto c = fr::random_element(); - auto d = uint256_t(c).slice(0, 133); - auto e = fr(d); - auto a_idx = composer.add_variable(fr(e)); - composer.create_add_gate({ a_idx, composer.get_zero_idx(), composer.get_zero_idx(), 1, 0, 0, -fr(e) }); - composer.decompose_into_default_range(a_idx, 134); - - prove_and_verify(composer, /*expected_result=*/true); -} - -TEST(UltraHonkComposer, non_native_field_multiplication) -{ - auto composer = UltraHonkComposer(); - - 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] = composer.add_variable(limbs[0]); - limb_indices[1] = composer.add_variable(limbs[1]); - limb_indices[2] = composer.add_variable(limbs[2]); - limb_indices[3] = composer.add_variable(limbs[3]); - limb_indices[4] = 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::UltraCircuitConstructor::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] = composer.evaluate_non_native_field_multiplication(inputs); - composer.range_constrain_two_limbs(lo_1_idx, hi_1_idx, 70, 70); - - prove_and_verify(composer, /*expected_result=*/true); -} - -TEST(UltraHonkComposer, rom) -{ - auto composer = UltraHonkComposer(); - - uint32_t rom_values[8]{ - composer.add_variable(fr::random_element()), composer.add_variable(fr::random_element()), - composer.add_variable(fr::random_element()), composer.add_variable(fr::random_element()), - composer.add_variable(fr::random_element()), composer.add_variable(fr::random_element()), - composer.add_variable(fr::random_element()), composer.add_variable(fr::random_element()), - }; - - size_t rom_id = composer.create_ROM_array(8); - - for (size_t i = 0; i < 8; ++i) { - composer.set_ROM_element(rom_id, i, rom_values[i]); - } - - uint32_t a_idx = composer.read_ROM_array(rom_id, composer.add_variable(5)); - EXPECT_EQ(a_idx != rom_values[5], true); - uint32_t b_idx = composer.read_ROM_array(rom_id, composer.add_variable(4)); - uint32_t c_idx = composer.read_ROM_array(rom_id, composer.add_variable(1)); - - const auto d_value = composer.get_variable(a_idx) + composer.get_variable(b_idx) + composer.get_variable(c_idx); - uint32_t d_idx = composer.add_variable(d_value); - - composer.create_big_add_gate({ - a_idx, - b_idx, - c_idx, - d_idx, - 1, - 1, - 1, - -1, - 0, - }); - - prove_and_verify(composer, /*expected_result=*/true); -} - -TEST(UltraHonkComposer, ram) -{ - auto composer = UltraHonkComposer(); - - uint32_t ram_values[8]{ - composer.add_variable(fr::random_element()), composer.add_variable(fr::random_element()), - composer.add_variable(fr::random_element()), composer.add_variable(fr::random_element()), - composer.add_variable(fr::random_element()), composer.add_variable(fr::random_element()), - composer.add_variable(fr::random_element()), composer.add_variable(fr::random_element()), - }; - - size_t ram_id = composer.create_RAM_array(8); - - for (size_t i = 0; i < 8; ++i) { - composer.init_RAM_element(ram_id, i, ram_values[i]); - } - - uint32_t a_idx = composer.read_RAM_array(ram_id, composer.add_variable(5)); - EXPECT_EQ(a_idx != ram_values[5], true); - - uint32_t b_idx = composer.read_RAM_array(ram_id, composer.add_variable(4)); - uint32_t c_idx = composer.read_RAM_array(ram_id, composer.add_variable(1)); - - composer.write_RAM_array(ram_id, composer.add_variable(4), composer.add_variable(500)); - uint32_t d_idx = composer.read_RAM_array(ram_id, composer.add_variable(4)); - - EXPECT_EQ(composer.get_variable(d_idx), 500); - - // ensure these vars get used in another arithmetic gate - const auto e_value = composer.get_variable(a_idx) + composer.get_variable(b_idx) + composer.get_variable(c_idx) + - composer.get_variable(d_idx); - uint32_t e_idx = composer.add_variable(e_value); - - composer.create_big_add_gate( - { - a_idx, - b_idx, - c_idx, - d_idx, - -1, - -1, - -1, - -1, - 0, - }, - true); - composer.create_big_add_gate( - { - composer.get_zero_idx(), - composer.get_zero_idx(), - composer.get_zero_idx(), - e_idx, - 0, - 0, - 0, - 0, - 0, - }, - false); - - prove_and_verify(composer, /*expected_result=*/true); -} - -// TODO(#378)(luke): this is a recent update from Zac and fails; do we need a corresponding bug fix in ultra circuit -// constructor? TEST(UltraHonkComposer, range_checks_on_duplicates) +// #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 +// #include +// #include "barretenberg/honk/proof_system/prover.hpp" +// #include "barretenberg/honk/sumcheck/sumcheck_round.hpp" +// #include "barretenberg/honk/sumcheck/relations/permutation_relation.hpp" +// #include "barretenberg/honk/sumcheck/relations/grand_product_initialization_relation.hpp" +// #include "barretenberg/honk/utils/grand_product_delta.hpp" +// #include "barretenberg/proof_system/plookup_tables/types.hpp" + +// #include +// #include +// #include + +// using namespace proof_system::honk; + +// namespace test_ultra_honk_composer { + +// namespace { +// auto& engine = numeric::random::get_debug_engine(); +// } + +// 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; +// } + +// bool construct_and_verify_proof(auto& composer) +// { +// auto prover = composer.create_prover(); +// auto proof = prover.construct_proof(); + +// auto verifier = composer.create_verifier(); +// bool result = verifier.verify_proof(proof); + +// return result; +// } + +// void prove_and_verify(auto& composer, bool expected_result) +// { +// auto prover = composer.create_prover(); +// auto verifier = composer.create_verifier(); +// auto proof = prover.construct_proof(); +// bool verified = verifier.verify_proof(proof); +// EXPECT_EQ(verified, expected_result); +// }; + +// void ensure_non_zero(auto& polynomial) +// { +// bool has_non_zero_coefficient = false; +// for (auto& coeff : polynomial) { +// has_non_zero_coefficient |= !coeff.is_zero(); +// } +// ASSERT_TRUE(has_non_zero_coefficient); +// } + +// /** +// * @brief A quick test to ensure that none of our polynomials are identically zero +// * +// * @note This test assumes that gates have been added by default in the circuit +// * constructor to achieve non-zero polynomials +// * +// */ +// TEST(UltraHonkComposer, ANonZeroPolynomialIsAGoodPolynomial) // { // auto composer = UltraHonkComposer(); -// uint32_t a = composer.add_variable(100); -// uint32_t b = composer.add_variable(100); -// uint32_t c = composer.add_variable(100); -// uint32_t d = composer.add_variable(100); +// composer.add_gates_to_ensure_all_polys_are_non_zero(); -// composer.assert_equal(a, b); -// composer.assert_equal(a, c); -// composer.assert_equal(a, d); +// auto prover = composer.create_prover(); +// auto proof = prover.construct_proof(); -// composer.create_new_range_constraint(a, 1000); -// composer.create_new_range_constraint(b, 1001); -// composer.create_new_range_constraint(c, 999); -// composer.create_new_range_constraint(d, 1000); +// for (auto& poly : prover.key->get_selectors()) { +// ensure_non_zero(poly); +// } -// composer.create_big_add_gate( -// { -// a, -// b, -// c, -// d, -// 0, -// 0, -// 0, -// 0, -// 0, -// }, -// false); +// for (auto& poly : prover.key->get_table_polynomials()) { +// ensure_non_zero(poly); +// } + +// for (auto& poly : prover.key->get_wires()) { +// ensure_non_zero(poly); +// } +// } + +// TEST(UltraHonkComposer, XorConstraint) +// { +// auto composer = UltraHonkComposer(); + +// uint32_t left_value = engine.get_random_uint32(); +// uint32_t right_value = engine.get_random_uint32(); + +// fr left_witness_value = fr{ left_value, 0, 0, 0 }.to_montgomery_form(); +// fr right_witness_value = fr{ right_value, 0, 0, 0 }.to_montgomery_form(); + +// uint32_t left_witness_index = composer.add_variable(left_witness_value); +// uint32_t right_witness_index = composer.add_variable(right_witness_value); + +// uint32_t xor_result_expected = left_value ^ right_value; + +// const auto lookup_accumulators = plookup::get_lookup_accumulators( +// plookup::MultiTableId::UINT32_XOR, left_witness_value, right_witness_value, true); +// auto xor_result = lookup_accumulators[plookup::ColumnIdx::C3] +// [0]; // The zeroth index in the 3rd column is the fully accumulated xor +// result +// EXPECT_EQ(xor_result, xor_result_expected); + +// composer.create_gates_from_plookup_accumulators( +// plookup::MultiTableId::UINT32_XOR, lookup_accumulators, left_witness_index, right_witness_index); // prove_and_verify(composer, /*expected_result=*/true); // } -// TODO(#378)(luke): this is a new test from Zac; ultra circuit constructor does not yet have create_range_constraint -// implemented. -// // Ensure copy constraints added on variables smaller than 2^14, which have been previously -// // range constrained, do not break the set equivalence checks because of indices mismatch. -// // 2^14 is DEFAULT_PLOOKUP_RANGE_BITNUM i.e. the maximum size before a variable gets sliced -// // before range constraints are applied to it. -// TEST(UltraHonkComposer, range_constraint_small_variable) +// TEST(UltraHonkComposer, create_gates_from_plookup_accumulators) // { // auto composer = UltraHonkComposer(); -// uint16_t mask = (1 << 8) - 1; -// int a = engine.get_random_uint16() & mask; -// uint32_t a_idx = composer.add_variable(fr(a)); -// uint32_t b_idx = composer.add_variable(fr(a)); -// ASSERT_NE(a_idx, b_idx); -// uint32_t c_idx = composer.add_variable(fr(a)); -// ASSERT_NE(c_idx, b_idx); -// composer.create_range_constraint(b_idx, 8, "bad range"); -// composer.assert_equal(a_idx, b_idx); -// composer.create_range_constraint(c_idx, 8, "bad range"); -// composer.assert_equal(a_idx, c_idx); + +// 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 = composer.add_variable(input_hi); +// const auto input_lo_index = 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 = composer.create_gates_from_plookup_accumulators( +// plookup::MultiTableId::PEDERSEN_LEFT_HI, sequence_data_hi, input_hi_index); +// const auto lookup_witnesses_lo = composer.create_gates_from_plookup_accumulators( +// plookup::MultiTableId::PEDERSEN_LEFT_LO, sequence_data_lo, input_lo_index); + +// std::vector expected_x; +// std::vector expected_y; + +// const size_t num_lookups_hi = +// (128 + crypto::pedersen_hash::lookup::BITS_PER_TABLE) / crypto::pedersen_hash::lookup::BITS_PER_TABLE; +// const size_t num_lookups_lo = 126 / crypto::pedersen_hash::lookup::BITS_PER_TABLE; +// const size_t num_lookups = num_lookups_hi + num_lookups_lo; + +// EXPECT_EQ(num_lookups_hi, lookup_witnesses_hi[plookup::ColumnIdx::C1].size()); +// EXPECT_EQ(num_lookups_lo, lookup_witnesses_lo[plookup::ColumnIdx::C1].size()); + +// std::vector expected_scalars; +// expected_x.resize(num_lookups); +// expected_y.resize(num_lookups); +// expected_scalars.resize(num_lookups); + +// { +// const size_t num_rounds = (num_lookups + 1) / 2; +// uint256_t bits(input_value); + +// const auto mask = crypto::pedersen_hash::lookup::PEDERSEN_TABLE_SIZE - 1; + +// for (size_t i = 0; i < num_rounds; ++i) { +// const auto& table = crypto::pedersen_hash::lookup::get_table(i); +// const size_t index = i * 2; + +// uint64_t slice_a = ((bits >> (index * 9)) & mask).data[0]; +// expected_x[index] = (table[(size_t)slice_a].x); +// expected_y[index] = (table[(size_t)slice_a].y); +// expected_scalars[index] = slice_a; + +// if (i < 14) { +// uint64_t slice_b = ((bits >> ((index + 1) * 9)) & mask).data[0]; +// expected_x[index + 1] = (table[(size_t)slice_b].x); +// expected_y[index + 1] = (table[(size_t)slice_b].y); +// expected_scalars[index + 1] = slice_b; +// } +// } +// } + +// for (size_t i = num_lookups - 2; i < num_lookups; --i) { +// expected_scalars[i] += (expected_scalars[i + 1] * crypto::pedersen_hash::lookup::PEDERSEN_TABLE_SIZE); +// } + +// size_t hi_shift = 126; +// const fr hi_cumulative = composer.get_variable(lookup_witnesses_hi[plookup::ColumnIdx::C1][0]); +// for (size_t i = 0; i < num_lookups_lo; ++i) { +// const fr hi_mult = fr(uint256_t(1) << hi_shift); +// EXPECT_EQ(composer.get_variable(lookup_witnesses_lo[plookup::ColumnIdx::C1][i]) + (hi_cumulative * hi_mult), +// expected_scalars[i]); +// EXPECT_EQ(composer.get_variable(lookup_witnesses_lo[plookup::ColumnIdx::C2][i]), expected_x[i]); +// EXPECT_EQ(composer.get_variable(lookup_witnesses_lo[plookup::ColumnIdx::C3][i]), expected_y[i]); +// hi_shift -= crypto::pedersen_hash::lookup::BITS_PER_TABLE; +// } + +// for (size_t i = 0; i < num_lookups_hi; ++i) { +// EXPECT_EQ(composer.get_variable(lookup_witnesses_hi[plookup::ColumnIdx::C1][i]), +// expected_scalars[i + num_lookups_lo]); +// EXPECT_EQ(composer.get_variable(lookup_witnesses_hi[plookup::ColumnIdx::C2][i]), +// expected_x[i + num_lookups_lo]); +// EXPECT_EQ(composer.get_variable(lookup_witnesses_hi[plookup::ColumnIdx::C3][i]), +// expected_y[i + num_lookups_lo]); +// } // auto prover = composer.create_prover(); -// auto proof = prover.construct_proof(); // auto verifier = composer.create_verifier(); +// auto proof = prover.construct_proof(); + // bool result = verifier.verify_proof(proof); + // EXPECT_EQ(result, true); // } -} // namespace test_ultra_honk_composer +// TEST(UltraHonkComposer, test_no_lookup_proof) +// { +// auto composer = UltraHonkComposer(); + +// for (size_t i = 0; i < 16; ++i) { +// for (size_t j = 0; j < 16; ++j) { +// uint64_t left = static_cast(j); +// uint64_t right = static_cast(i); +// uint32_t left_idx = composer.add_variable(fr(left)); +// uint32_t right_idx = composer.add_variable(fr(right)); +// uint32_t result_idx = composer.add_variable(fr(left ^ right)); + +// uint32_t add_idx = composer.add_variable(fr(left) + fr(right) + composer.get_variable(result_idx)); +// composer.create_big_add_gate( +// { left_idx, right_idx, result_idx, add_idx, fr(1), fr(1), fr(1), fr(-1), fr(0) }); +// } +// } + +// prove_and_verify(composer, /*expected_result=*/true); +// } + +// TEST(UltraHonkComposer, test_elliptic_gate) +// { +// typedef grumpkin::g1::affine_element affine_element; +// typedef grumpkin::g1::element element; +// auto composer = UltraHonkComposer(); + +// 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 = composer.add_variable(p1.x); +// uint32_t y1 = composer.add_variable(p1.y); +// uint32_t x2 = composer.add_variable(p2.x); +// uint32_t y2 = composer.add_variable(p2.y); +// uint32_t x3 = composer.add_variable(p3.x); +// uint32_t y3 = composer.add_variable(p3.y); + +// ecc_add_gate gate{ x1, y1, x2, y2, x3, y3, 1, 1 }; +// 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 = composer.add_variable(p3.x); +// y3 = composer.add_variable(p3.y); +// gate = ecc_add_gate{ x1, y1, x2, y2, x3, y3, beta, 1 }; +// composer.create_ecc_add_gate(gate); + +// p2_endo.x *= beta; +// p3 = affine_element(element(p1) - element(p2_endo)); +// x3 = composer.add_variable(p3.x); +// y3 = composer.add_variable(p3.y); +// gate = ecc_add_gate{ x1, y1, x2, y2, x3, y3, beta.sqr(), -1 }; +// composer.create_ecc_add_gate(gate); + +// prove_and_verify(composer, /*expected_result=*/true); +// } + +// TEST(UltraHonkComposer, non_trivial_tag_permutation) +// { +// auto composer = UltraHonkComposer(); +// fr a = fr::random_element(); +// fr b = -a; + +// auto a_idx = composer.add_variable(a); +// auto b_idx = composer.add_variable(b); +// auto c_idx = composer.add_variable(b); +// auto d_idx = composer.add_variable(a); + +// composer.create_add_gate({ a_idx, b_idx, composer.get_zero_idx(), fr::one(), fr::one(), fr::zero(), fr::zero() +// }); composer.create_add_gate({ c_idx, d_idx, composer.get_zero_idx(), fr::one(), fr::one(), fr::zero(), +// fr::zero() }); + +// composer.create_tag(1, 2); +// composer.create_tag(2, 1); + +// composer.assign_tag(a_idx, 1); +// composer.assign_tag(b_idx, 1); +// composer.assign_tag(c_idx, 2); +// composer.assign_tag(d_idx, 2); + +// prove_and_verify(composer, /*expected_result=*/true); +// } + +// TEST(UltraHonkComposer, non_trivial_tag_permutation_and_cycles) +// { +// auto composer = UltraHonkComposer(); +// fr a = fr::random_element(); +// fr c = -a; + +// auto a_idx = composer.add_variable(a); +// auto b_idx = composer.add_variable(a); +// composer.assert_equal(a_idx, b_idx); +// auto c_idx = composer.add_variable(c); +// auto d_idx = composer.add_variable(c); +// composer.assert_equal(c_idx, d_idx); +// auto e_idx = composer.add_variable(a); +// auto f_idx = composer.add_variable(a); +// composer.assert_equal(e_idx, f_idx); +// auto g_idx = composer.add_variable(c); +// auto h_idx = composer.add_variable(c); +// composer.assert_equal(g_idx, h_idx); + +// composer.create_tag(1, 2); +// composer.create_tag(2, 1); + +// composer.assign_tag(a_idx, 1); +// composer.assign_tag(c_idx, 1); +// composer.assign_tag(e_idx, 2); +// composer.assign_tag(g_idx, 2); + +// composer.create_add_gate( +// { b_idx, a_idx, composer.get_zero_idx(), fr::one(), fr::neg_one(), fr::zero(), fr::zero() }); +// composer.create_add_gate({ c_idx, g_idx, composer.get_zero_idx(), fr::one(), -fr::one(), fr::zero(), fr::zero() +// }); composer.create_add_gate({ e_idx, f_idx, composer.get_zero_idx(), fr::one(), -fr::one(), fr::zero(), +// fr::zero() }); + +// prove_and_verify(composer, /*expected_result=*/true); +// } + +// TEST(UltraHonkComposer, bad_tag_permutation) +// { +// auto composer = UltraHonkComposer(); +// fr a = fr::random_element(); +// fr b = -a; + +// auto a_idx = composer.add_variable(a); +// auto b_idx = composer.add_variable(b); +// auto c_idx = composer.add_variable(b); +// auto d_idx = composer.add_variable(a + 1); + +// composer.create_add_gate({ a_idx, b_idx, composer.get_zero_idx(), 1, 1, 0, 0 }); +// composer.create_add_gate({ c_idx, d_idx, composer.get_zero_idx(), 1, 1, 0, -1 }); + +// composer.create_tag(1, 2); +// composer.create_tag(2, 1); + +// composer.assign_tag(a_idx, 1); +// composer.assign_tag(b_idx, 1); +// composer.assign_tag(c_idx, 2); +// composer.assign_tag(d_idx, 2); + +// prove_and_verify(composer, /*expected_result=*/false); +// } + +// // same as above but with turbocomposer to check reason of failue is really tag mismatch +// TEST(UltraHonkComposer, bad_tag_turbo_permutation) +// { +// auto composer = UltraHonkComposer(); +// fr a = fr::random_element(); +// fr b = -a; + +// auto a_idx = composer.add_variable(a); +// auto b_idx = composer.add_variable(b); +// auto c_idx = composer.add_variable(b); +// auto d_idx = composer.add_variable(a + 1); + +// composer.create_add_gate({ a_idx, b_idx, composer.get_zero_idx(), 1, 1, 0, 0 }); +// composer.create_add_gate({ c_idx, d_idx, composer.get_zero_idx(), 1, 1, 0, -1 }); + +// // composer.create_add_gate({ a_idx, b_idx, composer.get_zero_idx(), fr::one(), fr::neg_one(), fr::zero(), +// // fr::zero() }); composer.create_add_gate({ a_idx, b_idx, composer.get_zero_idx(), fr::one(), fr::neg_one(), +// // fr::zero(), fr::zero() }); composer.create_add_gate({ a_idx, b_idx, composer.get_zero_idx(), fr::one(), +// // fr::neg_one(), fr::zero(), fr::zero() }); +// auto prover = composer.create_prover(); +// auto verifier = composer.create_verifier(); + +// prove_and_verify(composer, /*expected_result=*/true); +// } + +// TEST(UltraHonkComposer, sort_widget) +// { +// auto composer = UltraHonkComposer(); +// fr a = fr::one(); +// fr b = fr(2); +// fr c = fr(3); +// fr d = fr(4); + +// auto a_idx = composer.add_variable(a); +// auto b_idx = composer.add_variable(b); +// auto c_idx = composer.add_variable(c); +// auto d_idx = composer.add_variable(d); +// composer.create_sort_constraint({ a_idx, b_idx, c_idx, d_idx }); + +// prove_and_verify(composer, /*expected_result=*/true); +// } + +// TEST(UltraHonkComposer, sort_with_edges_gate) +// { + +// fr a = fr::one(); +// fr b = fr(2); +// fr c = fr(3); +// fr d = fr(4); +// fr e = fr(5); +// fr f = fr(6); +// fr g = fr(7); +// fr h = fr(8); + +// { +// auto composer = UltraHonkComposer(); +// auto a_idx = composer.add_variable(a); +// auto b_idx = composer.add_variable(b); +// auto c_idx = composer.add_variable(c); +// auto d_idx = composer.add_variable(d); +// auto e_idx = composer.add_variable(e); +// auto f_idx = composer.add_variable(f); +// auto g_idx = composer.add_variable(g); +// auto h_idx = composer.add_variable(h); +// composer.create_sort_constraint_with_edges({ a_idx, b_idx, c_idx, d_idx, e_idx, f_idx, g_idx, h_idx }, a, h); + +// prove_and_verify(composer, /*expected_result=*/true); +// } + +// { +// auto composer = UltraHonkComposer(); +// auto a_idx = composer.add_variable(a); +// auto b_idx = composer.add_variable(b); +// auto c_idx = composer.add_variable(c); +// auto d_idx = composer.add_variable(d); +// auto e_idx = composer.add_variable(e); +// auto f_idx = composer.add_variable(f); +// auto g_idx = composer.add_variable(g); +// auto h_idx = composer.add_variable(h); +// composer.create_sort_constraint_with_edges({ a_idx, b_idx, c_idx, d_idx, e_idx, f_idx, g_idx, h_idx }, a, g); + +// prove_and_verify(composer, /*expected_result=*/false); +// } +// { +// auto composer = UltraHonkComposer(); +// auto a_idx = composer.add_variable(a); +// auto b_idx = composer.add_variable(b); +// auto c_idx = composer.add_variable(c); +// auto d_idx = composer.add_variable(d); +// auto e_idx = composer.add_variable(e); +// auto f_idx = composer.add_variable(f); +// auto g_idx = composer.add_variable(g); +// auto h_idx = composer.add_variable(h); +// composer.create_sort_constraint_with_edges({ a_idx, b_idx, c_idx, d_idx, e_idx, f_idx, g_idx, h_idx }, b, h); + +// prove_and_verify(composer, /*expected_result=*/false); +// } +// { +// auto composer = UltraHonkComposer(); +// auto a_idx = composer.add_variable(a); +// auto c_idx = composer.add_variable(c); +// auto d_idx = composer.add_variable(d); +// auto e_idx = composer.add_variable(e); +// auto f_idx = composer.add_variable(f); +// auto g_idx = composer.add_variable(g); +// auto h_idx = composer.add_variable(h); +// auto b2_idx = composer.add_variable(fr(15)); +// composer.create_sort_constraint_with_edges({ a_idx, b2_idx, c_idx, d_idx, e_idx, f_idx, g_idx, h_idx }, b, +// h); + +// prove_and_verify(composer, /*expected_result=*/false); +// } +// { +// auto composer = UltraHonkComposer(); +// auto idx = add_variables(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 }); +// composer.create_sort_constraint_with_edges(idx, 1, 45); + +// prove_and_verify(composer, /*expected_result=*/true); +// } +// { +// auto composer = UltraHonkComposer(); +// auto idx = add_variables(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 }); + +// composer.create_sort_constraint_with_edges(idx, 1, 29); + +// prove_and_verify(composer, /*expected_result=*/false); +// } +// } + +// TEST(UltraHonkComposer, range_constraint) +// { +// { +// auto composer = UltraHonkComposer(); +// auto indices = add_variables(composer, { 1, 2, 3, 4, 5, 6, 7, 8 }); +// for (size_t i = 0; i < indices.size(); i++) { +// composer.create_new_range_constraint(indices[i], 8); +// } +// // auto ind = {a_idx,b_idx,c_idx,d_idx,e_idx,f_idx,g_idx,h_idx}; +// composer.create_sort_constraint(indices); + +// prove_and_verify(composer, /*expected_result=*/true); +// } +// { +// auto composer = UltraHonkComposer(); +// auto indices = add_variables(composer, { 3 }); +// for (size_t i = 0; i < indices.size(); i++) { +// composer.create_new_range_constraint(indices[i], 3); +// } +// // auto ind = {a_idx,b_idx,c_idx,d_idx,e_idx,f_idx,g_idx,h_idx}; +// composer.create_dummy_constraints(indices); + +// prove_and_verify(composer, /*expected_result=*/true); +// } +// { +// auto composer = UltraHonkComposer(); +// auto indices = add_variables(composer, { 1, 2, 3, 4, 5, 6, 8, 25 }); +// for (size_t i = 0; i < indices.size(); i++) { +// composer.create_new_range_constraint(indices[i], 8); +// } +// composer.create_sort_constraint(indices); + +// prove_and_verify(composer, /*expected_result=*/false); +// } +// { +// auto composer = UltraHonkComposer(); +// auto indices = +// add_variables(composer, { 1, 2, 3, 4, 5, 6, 10, 8, 15, 11, 32, 21, 42, 79, 16, 10, 3, 26, 19, 51 }); +// for (size_t i = 0; i < indices.size(); i++) { +// composer.create_new_range_constraint(indices[i], 128); +// } +// composer.create_dummy_constraints(indices); + +// prove_and_verify(composer, /*expected_result=*/true); +// } +// { +// auto composer = UltraHonkComposer(); +// auto indices = +// add_variables(composer, { 1, 2, 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++) { +// composer.create_new_range_constraint(indices[i], 79); +// } +// composer.create_dummy_constraints(indices); + +// prove_and_verify(composer, /*expected_result=*/false); +// } +// { +// auto composer = UltraHonkComposer(); +// auto indices = +// add_variables(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++) { +// composer.create_new_range_constraint(indices[i], 79); +// } +// composer.create_dummy_constraints(indices); + +// prove_and_verify(composer, /*expected_result=*/false); +// } +// } + +// TEST(UltraHonkComposer, range_with_gates) +// { + +// auto composer = UltraHonkComposer(); +// auto idx = add_variables(composer, { 1, 2, 3, 4, 5, 6, 7, 8 }); +// for (size_t i = 0; i < idx.size(); i++) { +// composer.create_new_range_constraint(idx[i], 8); +// } + +// composer.create_add_gate({ idx[0], idx[1], composer.get_zero_idx(), fr::one(), fr::one(), fr::zero(), -3 }); +// composer.create_add_gate({ idx[2], idx[3], composer.get_zero_idx(), fr::one(), fr::one(), fr::zero(), -7 }); +// composer.create_add_gate({ idx[4], idx[5], composer.get_zero_idx(), fr::one(), fr::one(), fr::zero(), -11 }); +// composer.create_add_gate({ idx[6], idx[7], composer.get_zero_idx(), fr::one(), fr::one(), fr::zero(), -15 }); + +// prove_and_verify(composer, /*expected_result=*/true); +// } + +// TEST(UltraHonkComposer, range_with_gates_where_range_is_not_a_power_of_two) +// { +// auto composer = UltraHonkComposer(); +// auto idx = add_variables(composer, { 1, 2, 3, 4, 5, 6, 7, 8 }); +// for (size_t i = 0; i < idx.size(); i++) { +// composer.create_new_range_constraint(idx[i], 12); +// } + +// composer.create_add_gate({ idx[0], idx[1], composer.get_zero_idx(), fr::one(), fr::one(), fr::zero(), -3 }); +// composer.create_add_gate({ idx[2], idx[3], composer.get_zero_idx(), fr::one(), fr::one(), fr::zero(), -7 }); +// composer.create_add_gate({ idx[4], idx[5], composer.get_zero_idx(), fr::one(), fr::one(), fr::zero(), -11 }); +// composer.create_add_gate({ idx[6], idx[7], composer.get_zero_idx(), fr::one(), fr::one(), fr::zero(), -15 }); + +// prove_and_verify(composer, /*expected_result=*/true); +// } + +// TEST(UltraHonkComposer, sort_widget_complex) +// { +// { + +// auto composer = UltraHonkComposer(); +// std::vector a = { 1, 3, 4, 7, 7, 8, 11, 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(composer.add_variable(a[i])); +// composer.create_sort_constraint(ind); + +// prove_and_verify(composer, /*expected_result=*/true); +// } +// { + +// auto composer = UltraHonkComposer(); +// 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(composer.add_variable(a[i])); +// composer.create_sort_constraint(ind); + +// prove_and_verify(composer, /*expected_result=*/false); +// } +// } + +// TEST(UltraHonkComposer, sort_widget_neg) +// { +// auto composer = UltraHonkComposer(); +// fr a = fr::one(); +// fr b = fr(2); +// fr c = fr(3); +// fr d = fr(8); + +// auto a_idx = composer.add_variable(a); +// auto b_idx = composer.add_variable(b); +// auto c_idx = composer.add_variable(c); +// auto d_idx = composer.add_variable(d); +// composer.create_sort_constraint({ a_idx, b_idx, c_idx, d_idx }); + +// prove_and_verify(composer, /*expected_result=*/false); +// } + +// TEST(UltraHonkComposer, composed_range_constraint) +// { +// auto composer = UltraHonkComposer(); +// auto c = fr::random_element(); +// auto d = uint256_t(c).slice(0, 133); +// auto e = fr(d); +// auto a_idx = composer.add_variable(fr(e)); +// composer.create_add_gate({ a_idx, composer.get_zero_idx(), composer.get_zero_idx(), 1, 0, 0, -fr(e) }); +// composer.decompose_into_default_range(a_idx, 134); + +// prove_and_verify(composer, /*expected_result=*/true); +// } + +// TEST(UltraHonkComposer, non_native_field_multiplication) +// { +// auto composer = UltraHonkComposer(); + +// 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] = composer.add_variable(limbs[0]); +// limb_indices[1] = composer.add_variable(limbs[1]); +// limb_indices[2] = composer.add_variable(limbs[2]); +// limb_indices[3] = composer.add_variable(limbs[3]); +// limb_indices[4] = 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::UltraCircuitConstructor::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] = composer.queue_non_native_field_multiplication(inputs); +// composer.range_constrain_two_limbs(lo_1_idx, hi_1_idx, 70, 70); + +// prove_and_verify(composer, /*expected_result=*/true); +// } + +// TEST(UltraHonkComposer, rom) +// { +// auto composer = UltraHonkComposer(); + +// uint32_t rom_values[8]{ +// composer.add_variable(fr::random_element()), composer.add_variable(fr::random_element()), +// composer.add_variable(fr::random_element()), composer.add_variable(fr::random_element()), +// composer.add_variable(fr::random_element()), composer.add_variable(fr::random_element()), +// composer.add_variable(fr::random_element()), composer.add_variable(fr::random_element()), +// }; + +// size_t rom_id = composer.create_ROM_array(8); + +// for (size_t i = 0; i < 8; ++i) { +// composer.set_ROM_element(rom_id, i, rom_values[i]); +// } + +// uint32_t a_idx = composer.read_ROM_array(rom_id, composer.add_variable(5)); +// EXPECT_EQ(a_idx != rom_values[5], true); +// uint32_t b_idx = composer.read_ROM_array(rom_id, composer.add_variable(4)); +// uint32_t c_idx = composer.read_ROM_array(rom_id, composer.add_variable(1)); + +// const auto d_value = composer.get_variable(a_idx) + composer.get_variable(b_idx) + composer.get_variable(c_idx); +// uint32_t d_idx = composer.add_variable(d_value); + +// composer.create_big_add_gate({ +// a_idx, +// b_idx, +// c_idx, +// d_idx, +// 1, +// 1, +// 1, +// -1, +// 0, +// }); + +// prove_and_verify(composer, /*expected_result=*/true); +// } + +// TEST(UltraHonkComposer, ram) +// { +// auto composer = UltraHonkComposer(); + +// uint32_t ram_values[8]{ +// composer.add_variable(fr::random_element()), composer.add_variable(fr::random_element()), +// composer.add_variable(fr::random_element()), composer.add_variable(fr::random_element()), +// composer.add_variable(fr::random_element()), composer.add_variable(fr::random_element()), +// composer.add_variable(fr::random_element()), composer.add_variable(fr::random_element()), +// }; + +// size_t ram_id = composer.create_RAM_array(8); + +// for (size_t i = 0; i < 8; ++i) { +// composer.init_RAM_element(ram_id, i, ram_values[i]); +// } + +// uint32_t a_idx = composer.read_RAM_array(ram_id, composer.add_variable(5)); +// EXPECT_EQ(a_idx != ram_values[5], true); + +// uint32_t b_idx = composer.read_RAM_array(ram_id, composer.add_variable(4)); +// uint32_t c_idx = composer.read_RAM_array(ram_id, composer.add_variable(1)); + +// composer.write_RAM_array(ram_id, composer.add_variable(4), composer.add_variable(500)); +// uint32_t d_idx = composer.read_RAM_array(ram_id, composer.add_variable(4)); + +// EXPECT_EQ(composer.get_variable(d_idx), 500); + +// // ensure these vars get used in another arithmetic gate +// const auto e_value = composer.get_variable(a_idx) + composer.get_variable(b_idx) + composer.get_variable(c_idx) + +// composer.get_variable(d_idx); +// uint32_t e_idx = composer.add_variable(e_value); + +// composer.create_big_add_gate( +// { +// a_idx, +// b_idx, +// c_idx, +// d_idx, +// -1, +// -1, +// -1, +// -1, +// 0, +// }, +// true); +// composer.create_big_add_gate( +// { +// composer.get_zero_idx(), +// composer.get_zero_idx(), +// composer.get_zero_idx(), +// e_idx, +// 0, +// 0, +// 0, +// 0, +// 0, +// }, +// false); + +// prove_and_verify(composer, /*expected_result=*/true); +// } + +// // TODO(#378)(luke): this is a recent update from Zac and fails; do we need a corresponding bug fix in ultra circuit +// // constructor? TEST(UltraHonkComposer, range_checks_on_duplicates) +// // { +// // auto composer = UltraHonkComposer(); + +// // uint32_t a = composer.add_variable(100); +// // uint32_t b = composer.add_variable(100); +// // uint32_t c = composer.add_variable(100); +// // uint32_t d = composer.add_variable(100); + +// // composer.assert_equal(a, b); +// // composer.assert_equal(a, c); +// // composer.assert_equal(a, d); + +// // composer.create_new_range_constraint(a, 1000); +// // composer.create_new_range_constraint(b, 1001); +// // composer.create_new_range_constraint(c, 999); +// // composer.create_new_range_constraint(d, 1000); + +// // composer.create_big_add_gate( +// // { +// // a, +// // b, +// // c, +// // d, +// // 0, +// // 0, +// // 0, +// // 0, +// // 0, +// // }, +// // false); + +// // prove_and_verify(composer, /*expected_result=*/true); +// // } + +// // TODO(#378)(luke): this is a new test from Zac; ultra circuit constructor does not yet have create_range_constraint +// // implemented. +// // // Ensure copy constraints added on variables smaller than 2^14, which have been previously +// // // range constrained, do not break the set equivalence checks because of indices mismatch. +// // // 2^14 is DEFAULT_PLOOKUP_RANGE_BITNUM i.e. the maximum size before a variable gets sliced +// // // before range constraints are applied to it. +// // TEST(UltraHonkComposer, range_constraint_small_variable) +// // { +// // auto composer = UltraHonkComposer(); +// // uint16_t mask = (1 << 8) - 1; +// // int a = engine.get_random_uint16() & mask; +// // uint32_t a_idx = composer.add_variable(fr(a)); +// // uint32_t b_idx = composer.add_variable(fr(a)); +// // ASSERT_NE(a_idx, b_idx); +// // uint32_t c_idx = composer.add_variable(fr(a)); +// // ASSERT_NE(c_idx, b_idx); +// // composer.create_range_constraint(b_idx, 8, "bad range"); +// // composer.assert_equal(a_idx, b_idx); +// // composer.create_range_constraint(c_idx, 8, "bad range"); +// // composer.assert_equal(a_idx, c_idx); + +// // auto prover = composer.create_prover(); +// // auto proof = prover.construct_proof(); +// // auto verifier = composer.create_verifier(); +// // bool result = verifier.verify_proof(proof); +// // EXPECT_EQ(result, true); +// // } + +// } // namespace test_ultra_honk_composer diff --git a/cpp/src/barretenberg/honk/proof_system/prover.cpp b/cpp/src/barretenberg/honk/proof_system/prover.cpp index ca92ca8f27..b8b50af072 100644 --- a/cpp/src/barretenberg/honk/proof_system/prover.cpp +++ b/cpp/src/barretenberg/honk/proof_system/prover.cpp @@ -4,8 +4,7 @@ #include "barretenberg/honk/transcript/transcript.hpp" #include "barretenberg/honk/utils/power_polynomial.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/honk/sumcheck/relations/permutation_relation.hpp" #include "barretenberg/honk/flavor/standard.hpp" namespace proof_system::honk { @@ -130,11 +129,8 @@ template void StandardProver_::execute_grand_pro * */ template void StandardProver_::execute_relation_check_rounds() { - using Sumcheck = sumcheck::Sumcheck, - sumcheck::ArithmeticRelation, - sumcheck::GrandProductComputationRelation, - sumcheck::GrandProductInitializationRelation>; + using Sumcheck = + sumcheck::Sumcheck, sumcheck::ArithmeticRelation, sumcheck::PermutationRelation>; auto sumcheck = Sumcheck(key->circuit_size, transcript); diff --git a/cpp/src/barretenberg/honk/proof_system/ultra_prover.cpp b/cpp/src/barretenberg/honk/proof_system/ultra_prover.cpp index ad6cb81d70..be83eff1ba 100644 --- a/cpp/src/barretenberg/honk/proof_system/ultra_prover.cpp +++ b/cpp/src/barretenberg/honk/proof_system/ultra_prover.cpp @@ -1,360 +1,364 @@ -#include "ultra_prover.hpp" -#include -#include -#include "barretenberg/honk/proof_system/prover_library.hpp" -#include "barretenberg/honk/sumcheck/relations/ultra_arithmetic_relation.hpp" -#include "barretenberg/honk/sumcheck/relations/ultra_arithmetic_relation_secondary.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/honk/sumcheck/relations/lookup_grand_product_relation.hpp" -#include "barretenberg/honk/sumcheck/relations/gen_perm_sort_relation.hpp" -#include "barretenberg/honk/sumcheck/relations/elliptic_relation.hpp" -#include "barretenberg/honk/sumcheck/relations/auxiliary_relation.hpp" -#include "barretenberg/polynomials/polynomial.hpp" -#include "barretenberg/transcript/transcript_wrappers.hpp" -#include -#include "barretenberg/honk/pcs/claim.hpp" - -namespace proof_system::honk { - -/** - * Create UltraProver_ from proving key, witness and manifest. - * - * @param input_key Proving key. - * @param input_manifest Input manifest - * - * @tparam settings Settings class. - * */ -template -UltraProver_::UltraProver_(std::shared_ptr input_key) - : key(input_key) - , queue(input_key->circuit_size, transcript) -{ - prover_polynomials.q_c = key->q_c; - prover_polynomials.q_l = key->q_l; - prover_polynomials.q_r = key->q_r; - prover_polynomials.q_o = key->q_o; - prover_polynomials.q_4 = key->q_4; - prover_polynomials.q_m = key->q_m; - prover_polynomials.q_arith = key->q_arith; - prover_polynomials.q_sort = key->q_sort; - prover_polynomials.q_elliptic = key->q_elliptic; - prover_polynomials.q_aux = key->q_aux; - prover_polynomials.q_lookup = key->q_lookup; - prover_polynomials.sigma_1 = key->sigma_1; - prover_polynomials.sigma_2 = key->sigma_2; - prover_polynomials.sigma_3 = key->sigma_3; - prover_polynomials.sigma_4 = key->sigma_4; - prover_polynomials.id_1 = key->id_1; - prover_polynomials.id_2 = key->id_2; - prover_polynomials.id_3 = key->id_3; - prover_polynomials.id_4 = key->id_4; - prover_polynomials.table_1 = key->table_1; - prover_polynomials.table_2 = key->table_2; - prover_polynomials.table_3 = key->table_3; - prover_polynomials.table_4 = key->table_4; - prover_polynomials.table_1_shift = key->table_1.shifted(); - prover_polynomials.table_2_shift = key->table_2.shifted(); - prover_polynomials.table_3_shift = key->table_3.shifted(); - prover_polynomials.table_4_shift = key->table_4.shifted(); - prover_polynomials.lagrange_first = key->lagrange_first; - prover_polynomials.lagrange_last = key->lagrange_last; - prover_polynomials.w_l = key->w_l; - prover_polynomials.w_r = key->w_r; - prover_polynomials.w_o = key->w_o; - prover_polynomials.w_l_shift = key->w_l.shifted(); - prover_polynomials.w_r_shift = key->w_r.shifted(); - prover_polynomials.w_o_shift = key->w_o.shifted(); - - // Add public inputs to transcript from the second wire polynomial - std::span public_wires_source = prover_polynomials.w_r; - - for (size_t i = 0; i < key->num_public_inputs; ++i) { - public_inputs.emplace_back(public_wires_source[i]); - } -} - -/** - * @brief Commit to the first three wires only - * - */ -template void UltraProver_::compute_wire_commitments() -{ - auto wire_polys = key->get_wires(); - auto labels = commitment_labels.get_wires(); - for (size_t idx = 0; idx < 3; ++idx) { - queue.add_commitment(wire_polys[idx], labels[idx]); - } -} - -/** - * @brief Add circuit size, public input size, and public inputs to transcript - * - */ -template void UltraProver_::execute_preamble_round() -{ - 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); - } -} - -/** - * @brief Compute commitments to the first three wires - * - */ -template void UltraProver_::execute_wire_commitments_round() -{ - auto wire_polys = key->get_wires(); - auto labels = commitment_labels.get_wires(); - for (size_t idx = 0; idx < 3; ++idx) { - queue.add_commitment(wire_polys[idx], labels[idx]); - } -} - -/** - * @brief Compute sorted witness-table accumulator - * - */ -template void UltraProver_::execute_sorted_list_accumulator_round() -{ - // Compute and add eta to relation parameters - auto eta = transcript.get_challenge("eta"); - relation_parameters.eta = eta; - - // Compute sorted witness-table accumulator and its commitment - key->sorted_accum = prover_library::compute_sorted_list_accumulator(key, eta); - queue.add_commitment(key->sorted_accum, commitment_labels.sorted_accum); - - // Finalize fourth wire polynomial by adding lookup memory records, then commit - prover_library::add_plookup_memory_records_to_wire_4(key, eta); - queue.add_commitment(key->w_4, commitment_labels.w_4); - - prover_polynomials.sorted_accum_shift = key->sorted_accum.shifted(); - prover_polynomials.sorted_accum = key->sorted_accum; - prover_polynomials.w_4 = key->w_4; - prover_polynomials.w_4_shift = key->w_4.shifted(); -} - -/** - * @brief Compute permutation and lookup grand product polynomials and commitments - * - */ -template void UltraProver_::execute_grand_product_computation_round() -{ - // 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); - auto lookup_grand_product_delta = compute_lookup_grand_product_delta(beta, gamma, key->circuit_size); - - relation_parameters.beta = beta; - relation_parameters.gamma = gamma; - relation_parameters.public_input_delta = public_input_delta; - relation_parameters.lookup_grand_product_delta = lookup_grand_product_delta; - - // Compute permutation grand product and its commitment - key->z_perm = prover_library::compute_permutation_grand_product(key, beta, gamma); - queue.add_commitment(key->z_perm, commitment_labels.z_perm); - - // Compute lookup grand product and its commitment - key->z_lookup = prover_library::compute_lookup_grand_product(key, relation_parameters.eta, beta, gamma); - queue.add_commitment(key->z_lookup, commitment_labels.z_lookup); - - prover_polynomials.z_perm = key->z_perm; - prover_polynomials.z_perm_shift = key->z_perm.shifted(); - prover_polynomials.z_lookup = key->z_lookup; - prover_polynomials.z_lookup_shift = key->z_lookup.shifted(); -} - -/** - * @brief Run Sumcheck resulting in u = (u_1,...,u_d) challenges and all evaluations at u being calculated. - * - */ -template void UltraProver_::execute_relation_check_rounds() -{ - using Sumcheck = sumcheck::Sumcheck, - sumcheck::UltraArithmeticRelation, - sumcheck::UltraArithmeticRelationSecondary, - sumcheck::UltraGrandProductComputationRelation, - sumcheck::UltraGrandProductInitializationRelation, - sumcheck::LookupGrandProductComputationRelation, - sumcheck::LookupGrandProductInitializationRelation, - sumcheck::GenPermSortRelation, - sumcheck::EllipticRelation, - sumcheck::AuxiliaryRelation>; - - 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 UltraProver_::execute_univariatization_round() -{ - const size_t NUM_POLYNOMIALS = Flavor::NUM_ALL_ENTITIES; - - // Generate batching challenge ρ and powers 1,ρ,…,ρᵐ⁻¹ - FF 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 - size_t poly_idx = 0; // TODO(#391) zip - for (auto& unshifted_poly : prover_polynomials.get_unshifted()) { - batched_poly_unshifted.add_scaled(unshifted_poly, rhos[poly_idx]); - ++poly_idx; - } - - Polynomial batched_poly_to_be_shifted(key->circuit_size); // batched to-be-shifted polynomials - for (auto& to_be_shifted_poly : prover_polynomials.get_to_be_shifted()) { - batched_poly_to_be_shifted.add_scaled(to_be_shifted_poly, rhos[poly_idx]); - ++poly_idx; - }; - - // 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) { - queue.add_commitment(fold_polynomials[l + 2], "Gemini:FOLD_" + std::to_string(l + 1)); - } -} - -/** - * - 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 UltraProver_::execute_pcs_evaluation_round() -{ - const FF 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 - * */ -template void UltraProver_::execute_shplonk_batched_quotient_round() -{ - nu_challenge = transcript.get_challenge("Shplonk:nu"); - - batched_quotient_Q = - Shplonk::compute_batched_quotient(gemini_output.opening_pairs, gemini_output.witnesses, nu_challenge); - - // commit to Q(X) and add [Q] to the transcript - queue.add_commitment(batched_quotient_Q, "Shplonk:Q"); -} - -/** - * - Do Fiat-Shamir to get "z" challenge. - * - Compute polynomial Q(X) - Q_z(X) - * */ -template void UltraProver_::execute_shplonk_partial_evaluation_round() -{ - const FF z_challenge = transcript.get_challenge("Shplonk:z"); - - shplonk_output = Shplonk::compute_partially_evaluated_batched_quotient( - gemini_output.opening_pairs, gemini_output.witnesses, std::move(batched_quotient_Q), nu_challenge, z_challenge); -} - -/** - * - Compute KZG quotient commitment [W]_1. - * - * */ -template void UltraProver_::execute_kzg_round() -{ - quotient_W = KZG::compute_opening_proof_polynomial(shplonk_output.opening_pair, shplonk_output.witness); - queue.add_commitment(quotient_W, "KZG:W"); -} - -template plonk::proof& UltraProver_::export_proof() -{ - proof.proof_data = transcript.proof_data; - return proof; -} - -template plonk::proof& UltraProver_::construct_proof() -{ - // Add circuit size public input size and public inputs to transcript. - execute_preamble_round(); - - // Compute first three wire commitments - execute_wire_commitments_round(); - queue.process_queue(); - - // Compute sorted list accumulator and commitment - execute_sorted_list_accumulator_round(); - queue.process_queue(); - - // Fiat-Shamir: beta & gamma - // Compute grand product(s) and commitments. - execute_grand_product_computation_round(); - queue.process_queue(); - - // Fiat-Shamir: alpha - // Run sumcheck subprotocol. - execute_relation_check_rounds(); - - // Fiat-Shamir: rho - // Compute Fold polynomials and their commitments. - execute_univariatization_round(); - queue.process_queue(); - - // Fiat-Shamir: r - // Compute Fold evaluations - execute_pcs_evaluation_round(); - - // Fiat-Shamir: nu - // Compute Shplonk batched quotient commitment Q - execute_shplonk_batched_quotient_round(); - queue.process_queue(); - - // Fiat-Shamir: z - // Compute partial evaluation Q_z - execute_shplonk_partial_evaluation_round(); - - // Fiat-Shamir: z - // Compute KZG quotient commitment - execute_kzg_round(); - queue.process_queue(); - - return export_proof(); -} - -template class UltraProver_; - -} // namespace proof_system::honk +// #include "ultra_prover.hpp" +// #include +// #include +// #include "barretenberg/honk/proof_system/prover_library.hpp" +// #include "barretenberg/honk/sumcheck/relations/ultra_arithmetic_relation.hpp" +// #include "barretenberg/honk/sumcheck/relations/ultra_arithmetic_relation_secondary.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/permutation_relation.hpp" +// #include "barretenberg/honk/sumcheck/relations/grand_product_initialization_relation.hpp" +// #include "barretenberg/honk/sumcheck/relations/lookup_grand_product_relation.hpp" +// #include "barretenberg/honk/sumcheck/relations/gen_perm_sort_relation.hpp" +// #include "barretenberg/honk/sumcheck/relations/elliptic_relation.hpp" +// #include "barretenberg/honk/sumcheck/relations/auxiliary_relation.hpp" +// #include "barretenberg/polynomials/polynomial.hpp" +// #include "barretenberg/transcript/transcript_wrappers.hpp" +// #include +// #include "barretenberg/honk/pcs/claim.hpp" + +// namespace proof_system::honk { + +// /** +// * Create UltraProver_ from proving key, witness and manifest. +// * +// * @param input_key Proving key. +// * @param input_manifest Input manifest +// * +// * @tparam settings Settings class. +// * */ +// template +// UltraProver_::UltraProver_(std::shared_ptr input_key) +// : key(input_key) +// , queue(input_key->circuit_size, transcript) +// { +// prover_polynomials.q_c = key->q_c; +// prover_polynomials.q_l = key->q_l; +// prover_polynomials.q_r = key->q_r; +// prover_polynomials.q_o = key->q_o; +// prover_polynomials.q_4 = key->q_4; +// prover_polynomials.q_m = key->q_m; +// prover_polynomials.q_arith = key->q_arith; +// prover_polynomials.q_sort = key->q_sort; +// prover_polynomials.q_elliptic = key->q_elliptic; +// prover_polynomials.q_aux = key->q_aux; +// prover_polynomials.q_lookup = key->q_lookup; +// prover_polynomials.sigma_1 = key->sigma_1; +// prover_polynomials.sigma_2 = key->sigma_2; +// prover_polynomials.sigma_3 = key->sigma_3; +// prover_polynomials.sigma_4 = key->sigma_4; +// prover_polynomials.id_1 = key->id_1; +// prover_polynomials.id_2 = key->id_2; +// prover_polynomials.id_3 = key->id_3; +// prover_polynomials.id_4 = key->id_4; +// prover_polynomials.table_1 = key->table_1; +// prover_polynomials.table_2 = key->table_2; +// prover_polynomials.table_3 = key->table_3; +// prover_polynomials.table_4 = key->table_4; +// prover_polynomials.table_1_shift = key->table_1.shifted(); +// prover_polynomials.table_2_shift = key->table_2.shifted(); +// prover_polynomials.table_3_shift = key->table_3.shifted(); +// prover_polynomials.table_4_shift = key->table_4.shifted(); +// prover_polynomials.lagrange_first = key->lagrange_first; +// prover_polynomials.lagrange_last = key->lagrange_last; +// prover_polynomials.w_l = key->w_l; +// prover_polynomials.w_r = key->w_r; +// prover_polynomials.w_o = key->w_o; +// prover_polynomials.w_l_shift = key->w_l.shifted(); +// prover_polynomials.w_r_shift = key->w_r.shifted(); +// prover_polynomials.w_o_shift = key->w_o.shifted(); + +// // Add public inputs to transcript from the second wire polynomial +// std::span public_wires_source = prover_polynomials.w_r; + +// for (size_t i = 0; i < key->num_public_inputs; ++i) { +// public_inputs.emplace_back(public_wires_source[i]); +// } +// } + +// /** +// * @brief Commit to the first three wires only +// * +// */ +// template void UltraProver_::compute_wire_commitments() +// { +// auto wire_polys = key->get_wires(); +// auto labels = commitment_labels.get_wires(); +// for (size_t idx = 0; idx < 3; ++idx) { +// queue.add_commitment(wire_polys[idx], labels[idx]); +// } +// } + +// /** +// * @brief Add circuit size, public input size, and public inputs to transcript +// * +// */ +// template void UltraProver_::execute_preamble_round() +// { +// 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); +// } +// } + +// /** +// * @brief Compute commitments to the first three wires +// * +// */ +// template void UltraProver_::execute_wire_commitments_round() +// { +// auto wire_polys = key->get_wires(); +// auto labels = commitment_labels.get_wires(); +// for (size_t idx = 0; idx < 3; ++idx) { +// queue.add_commitment(wire_polys[idx], labels[idx]); +// } +// } + +// /** +// * @brief Compute sorted witness-table accumulator +// * +// */ +// template void UltraProver_::execute_sorted_list_accumulator_round() +// { +// // Compute and add eta to relation parameters +// auto eta = transcript.get_challenge("eta"); +// relation_parameters.eta = eta; + +// // Compute sorted witness-table accumulator and its commitment +// key->sorted_accum = prover_library::compute_sorted_list_accumulator(key, eta); +// queue.add_commitment(key->sorted_accum, commitment_labels.sorted_accum); + +// // Finalize fourth wire polynomial by adding lookup memory records, then commit +// prover_library::add_plookup_memory_records_to_wire_4(key, eta); +// queue.add_commitment(key->w_4, commitment_labels.w_4); + +// prover_polynomials.sorted_accum_shift = key->sorted_accum.shifted(); +// prover_polynomials.sorted_accum = key->sorted_accum; +// prover_polynomials.w_4 = key->w_4; +// prover_polynomials.w_4_shift = key->w_4.shifted(); +// } + +// /** +// * @brief Compute permutation and lookup grand product polynomials and commitments +// * +// */ +// template void UltraProver_::execute_grand_product_computation_round() +// { +// // 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); +// auto lookup_grand_product_delta = compute_lookup_grand_product_delta(beta, gamma, key->circuit_size); + +// relation_parameters.beta = beta; +// relation_parameters.gamma = gamma; +// relation_parameters.public_input_delta = public_input_delta; +// relation_parameters.lookup_grand_product_delta = lookup_grand_product_delta; + +// // Compute permutation grand product and its commitment +// key->z_perm = prover_library::compute_permutation_grand_product(key, beta, gamma); +// queue.add_commitment(key->z_perm, commitment_labels.z_perm); + +// // Compute lookup grand product and its commitment +// key->z_lookup = prover_library::compute_lookup_grand_product(key, relation_parameters.eta, beta, gamma); +// queue.add_commitment(key->z_lookup, commitment_labels.z_lookup); + +// prover_polynomials.z_perm = key->z_perm; +// prover_polynomials.z_perm_shift = key->z_perm.shifted(); +// prover_polynomials.z_lookup = key->z_lookup; +// prover_polynomials.z_lookup_shift = key->z_lookup.shifted(); +// } + +// /** +// * @brief Run Sumcheck resulting in u = (u_1,...,u_d) challenges and all evaluations at u being calculated. +// * +// */ +// template void UltraProver_::execute_relation_check_rounds() +// { +// using Sumcheck = sumcheck::Sumcheck, +// sumcheck::UltraArithmeticRelation>; +// // using Sumcheck = sumcheck::Sumcheck, +// // sumcheck::UltraArithmeticRelation, +// // sumcheck::UltraArithmeticRelationSecondary, +// // sumcheck::UltraGrandProductComputationRelation, +// // sumcheck::UltraGrandProductInitializationRelation, +// // sumcheck::LookupGrandProductComputationRelation, +// // sumcheck::LookupGrandProductInitializationRelation, +// // sumcheck::GenPermSortRelation, +// // sumcheck::EllipticRelation, +// // sumcheck::AuxiliaryRelation>; + +// 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 UltraProver_::execute_univariatization_round() +// { +// const size_t NUM_POLYNOMIALS = Flavor::NUM_ALL_ENTITIES; + +// // Generate batching challenge ρ and powers 1,ρ,…,ρᵐ⁻¹ +// FF 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 +// size_t poly_idx = 0; // TODO(#391) zip +// for (auto& unshifted_poly : prover_polynomials.get_unshifted()) { +// batched_poly_unshifted.add_scaled(unshifted_poly, rhos[poly_idx]); +// ++poly_idx; +// } + +// Polynomial batched_poly_to_be_shifted(key->circuit_size); // batched to-be-shifted polynomials +// for (auto& to_be_shifted_poly : prover_polynomials.get_to_be_shifted()) { +// batched_poly_to_be_shifted.add_scaled(to_be_shifted_poly, rhos[poly_idx]); +// ++poly_idx; +// }; + +// // 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) { +// queue.add_commitment(fold_polynomials[l + 2], "Gemini:FOLD_" + std::to_string(l + 1)); +// } +// } + +// /** +// * - 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 UltraProver_::execute_pcs_evaluation_round() +// { +// const FF 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 +// * */ +// template void UltraProver_::execute_shplonk_batched_quotient_round() +// { +// nu_challenge = transcript.get_challenge("Shplonk:nu"); + +// batched_quotient_Q = +// Shplonk::compute_batched_quotient(gemini_output.opening_pairs, gemini_output.witnesses, nu_challenge); + +// // commit to Q(X) and add [Q] to the transcript +// queue.add_commitment(batched_quotient_Q, "Shplonk:Q"); +// } + +// /** +// * - Do Fiat-Shamir to get "z" challenge. +// * - Compute polynomial Q(X) - Q_z(X) +// * */ +// template void UltraProver_::execute_shplonk_partial_evaluation_round() +// { +// const FF z_challenge = transcript.get_challenge("Shplonk:z"); + +// shplonk_output = Shplonk::compute_partially_evaluated_batched_quotient( +// gemini_output.opening_pairs, gemini_output.witnesses, std::move(batched_quotient_Q), nu_challenge, +// z_challenge); +// } + +// /** +// * - Compute KZG quotient commitment [W]_1. +// * +// * */ +// template void UltraProver_::execute_kzg_round() +// { +// quotient_W = KZG::compute_opening_proof_polynomial(shplonk_output.opening_pair, shplonk_output.witness); +// queue.add_commitment(quotient_W, "KZG:W"); +// } + +// template plonk::proof& UltraProver_::export_proof() +// { +// proof.proof_data = transcript.proof_data; +// return proof; +// } + +// template plonk::proof& UltraProver_::construct_proof() +// { +// // Add circuit size public input size and public inputs to transcript. +// execute_preamble_round(); + +// // Compute first three wire commitments +// execute_wire_commitments_round(); +// queue.process_queue(); + +// // Compute sorted list accumulator and commitment +// execute_sorted_list_accumulator_round(); +// queue.process_queue(); + +// // Fiat-Shamir: beta & gamma +// // Compute grand product(s) and commitments. +// execute_grand_product_computation_round(); +// queue.process_queue(); + +// // Fiat-Shamir: alpha +// // Run sumcheck subprotocol. +// execute_relation_check_rounds(); + +// // Fiat-Shamir: rho +// // Compute Fold polynomials and their commitments. +// execute_univariatization_round(); +// queue.process_queue(); + +// // Fiat-Shamir: r +// // Compute Fold evaluations +// execute_pcs_evaluation_round(); + +// // Fiat-Shamir: nu +// // Compute Shplonk batched quotient commitment Q +// execute_shplonk_batched_quotient_round(); +// queue.process_queue(); + +// // Fiat-Shamir: z +// // Compute partial evaluation Q_z +// execute_shplonk_partial_evaluation_round(); + +// // Fiat-Shamir: z +// // Compute KZG quotient commitment +// execute_kzg_round(); +// queue.process_queue(); + +// return export_proof(); +// } + +// template class UltraProver_; + +// } // namespace proof_system::honk diff --git a/cpp/src/barretenberg/honk/proof_system/ultra_verifier.cpp b/cpp/src/barretenberg/honk/proof_system/ultra_verifier.cpp index 194d44b6e9..f23ce94a61 100644 --- a/cpp/src/barretenberg/honk/proof_system/ultra_verifier.cpp +++ b/cpp/src/barretenberg/honk/proof_system/ultra_verifier.cpp @@ -1,185 +1,188 @@ -#include "./ultra_verifier.hpp" -#include "barretenberg/honk/transcript/transcript.hpp" -#include "barretenberg/numeric/bitop/get_msb.hpp" -#include "barretenberg/honk/flavor/standard.hpp" -#include "barretenberg/ecc/curves/bn254/scalar_multiplication/scalar_multiplication.hpp" -#include "barretenberg/honk/utils/power_polynomial.hpp" -#include "barretenberg/honk/sumcheck/relations/ultra_arithmetic_relation.hpp" -#include "barretenberg/honk/sumcheck/relations/ultra_arithmetic_relation_secondary.hpp" -#include "barretenberg/honk/sumcheck/relations/grand_product_initialization_relation.hpp" -#include "barretenberg/honk/sumcheck/relations/grand_product_computation_relation.hpp" -#include "barretenberg/honk/sumcheck/relations/lookup_grand_product_relation.hpp" -#include "barretenberg/honk/sumcheck/relations/gen_perm_sort_relation.hpp" -#include "barretenberg/honk/sumcheck/relations/elliptic_relation.hpp" -#include "barretenberg/honk/sumcheck/relations/auxiliary_relation.hpp" - -#pragma GCC diagnostic ignored "-Wunused-variable" - -using namespace barretenberg; -using namespace proof_system::honk::sumcheck; - -namespace proof_system::honk { -template -UltraVerifier_::UltraVerifier_(std::shared_ptr verifier_key) - : key(verifier_key) -{} - -template -UltraVerifier_::UltraVerifier_(UltraVerifier_&& other) - : key(std::move(other.key)) - , kate_verification_key(std::move(other.kate_verification_key)) -{} - -template UltraVerifier_& UltraVerifier_::operator=(UltraVerifier_&& other) -{ - key = other.key; - kate_verification_key = (std::move(other.kate_verification_key)); - kate_g1_elements.clear(); - kate_fr_elements.clear(); - return *this; -} - -/** - * @brief This function verifies an Ultra Honk proof for given program settings. - * - */ -template bool UltraVerifier_::verify_proof(const plonk::proof& proof) -{ - using FF = typename Flavor::FF; - using GroupElement = typename Flavor::GroupElement; - using Commitment = typename Flavor::Commitment; - using Gemini = pcs::gemini::MultilinearReductionScheme; - using Shplonk = pcs::shplonk::SingleBatchOpeningScheme; - using KZG = pcs::kzg::UnivariateOpeningScheme; - using VerifierCommitments = typename Flavor::VerifierCommitments; - using CommitmentLabels = typename Flavor::CommitmentLabels; - - RelationParameters relation_parameters; - - transcript = VerifierTranscript{ proof.proof_data }; - - auto commitments = VerifierCommitments(key, transcript); - auto commitment_labels = CommitmentLabels(); - - // TODO(Adrian): Change the initialization of the transcript to take the VK hash? - const auto circuit_size = transcript.template receive_from_prover("circuit_size"); - const auto public_input_size = transcript.template receive_from_prover("public_input_size"); - - if (circuit_size != key->circuit_size) { - return false; - } - if (public_input_size != key->num_public_inputs) { - return false; - } - - std::vector public_inputs; - for (size_t i = 0; i < public_input_size; ++i) { - auto public_input_i = transcript.template receive_from_prover("public_input_" + std::to_string(i)); - public_inputs.emplace_back(public_input_i); - } - - // Get commitments to first three wires - commitments.w_l = transcript.template receive_from_prover(commitment_labels.w_l); - commitments.w_r = transcript.template receive_from_prover(commitment_labels.w_r); - commitments.w_o = transcript.template receive_from_prover(commitment_labels.w_o); - - // Get challenge for sorted list batching and wire four memory records - auto eta = transcript.get_challenge("eta"); - relation_parameters.eta = eta; - - // Get commitments to sorted list accumulator and fourth wire - commitments.sorted_accum = transcript.template receive_from_prover(commitment_labels.sorted_accum); - commitments.w_4 = transcript.template receive_from_prover(commitment_labels.w_4); - - // Get permutation challenges - auto [beta, gamma] = transcript.get_challenges("beta", "gamma"); - - const FF public_input_delta = compute_public_input_delta(public_inputs, beta, gamma, circuit_size); - const FF lookup_grand_product_delta = compute_lookup_grand_product_delta(beta, gamma, circuit_size); - - relation_parameters.beta = beta; - relation_parameters.gamma = gamma; - relation_parameters.public_input_delta = public_input_delta; - relation_parameters.lookup_grand_product_delta = lookup_grand_product_delta; - - // Get commitment to permutation and lookup grand products - commitments.z_perm = transcript.template receive_from_prover(commitment_labels.z_perm); - commitments.z_lookup = transcript.template receive_from_prover(commitment_labels.z_lookup); - - // Execute Sumcheck Verifier - auto sumcheck = Sumcheck, - honk::sumcheck::UltraArithmeticRelation, - honk::sumcheck::UltraArithmeticRelationSecondary, - honk::sumcheck::UltraGrandProductComputationRelation, - honk::sumcheck::UltraGrandProductInitializationRelation, - honk::sumcheck::LookupGrandProductComputationRelation, - honk::sumcheck::LookupGrandProductInitializationRelation, - honk::sumcheck::GenPermSortRelation, - honk::sumcheck::EllipticRelation, - honk::sumcheck::AuxiliaryRelation>(circuit_size, transcript); - - std::optional sumcheck_output = sumcheck.execute_verifier(relation_parameters); - - // If Sumcheck does not return an output, sumcheck verification has failed - if (!sumcheck_output.has_value()) { - return false; - } - - auto [multivariate_challenge, purported_evaluations] = *sumcheck_output; - - // Execute Gemini/Shplonk verification: - - // Construct inputs for Gemini verifier: - // - Multivariate opening point u = (u_0, ..., u_{d-1}) - // - batched unshifted and to-be-shifted polynomial commitments - auto batched_commitment_unshifted = GroupElement::zero(); - auto batched_commitment_to_be_shifted = GroupElement::zero(); - - // Compute powers of batching challenge rho - FF rho = transcript.get_challenge("rho"); - std::vector rhos = Gemini::powers_of_rho(rho, Flavor::NUM_ALL_ENTITIES); - - // Compute batched multivariate evaluation - FF batched_evaluation = FF::zero(); - size_t evaluation_idx = 0; - for (auto& value : purported_evaluations.get_unshifted_then_shifted()) { - batched_evaluation += value * rhos[evaluation_idx]; - ++evaluation_idx; - } - - // Construct batched commitment for NON-shifted polynomials - size_t commitment_idx = 0; - for (auto& commitment : commitments.get_unshifted()) { - batched_commitment_unshifted += commitment * rhos[commitment_idx]; - ++commitment_idx; - } - - // Construct batched commitment for to-be-shifted polynomials - for (auto& commitment : commitments.get_to_be_shifted()) { - batched_commitment_to_be_shifted += commitment * rhos[commitment_idx]; - ++commitment_idx; - } - - // Produce a Gemini claim consisting of: - // - d+1 commitments [Fold_{r}^(0)], [Fold_{-r}^(0)], and [Fold^(l)], l = 1:d-1 - // - d+1 evaluations a_0_pos, and a_l, l = 0:d-1 - auto gemini_claim = Gemini::reduce_verify(multivariate_challenge, - batched_evaluation, - batched_commitment_unshifted, - batched_commitment_to_be_shifted, - transcript); - - // Produce a Shplonk claim: commitment [Q] - [Q_z], evaluation zero (at random challenge z) - auto shplonk_claim = Shplonk::reduce_verify(gemini_claim, transcript); - - // Aggregate inputs [Q] - [Q_z] and [W] into an 'accumulator' (can perform pairing check on result) - auto kzg_claim = KZG::reduce_verify(shplonk_claim, transcript); - - // Return result of final pairing check - return kzg_claim.verify(kate_verification_key); -} - -template class UltraVerifier_; - -} // namespace proof_system::honk +// #include "./ultra_verifier.hpp" +// #include "barretenberg/honk/transcript/transcript.hpp" +// #include "barretenberg/numeric/bitop/get_msb.hpp" +// #include "barretenberg/honk/flavor/standard.hpp" +// #include "barretenberg/ecc/curves/bn254/scalar_multiplication/scalar_multiplication.hpp" +// #include "barretenberg/honk/utils/power_polynomial.hpp" +// #include "barretenberg/honk/sumcheck/relations/ultra_arithmetic_relation.hpp" +// #include "barretenberg/honk/sumcheck/relations/ultra_arithmetic_relation_secondary.hpp" +// #include "barretenberg/honk/sumcheck/relations/grand_product_initialization_relation.hpp" +// #include "barretenberg/honk/sumcheck/relations/permutation_relation.hpp" +// #include "barretenberg/honk/sumcheck/relations/lookup_grand_product_relation.hpp" +// #include "barretenberg/honk/sumcheck/relations/gen_perm_sort_relation.hpp" +// #include "barretenberg/honk/sumcheck/relations/elliptic_relation.hpp" +// #include "barretenberg/honk/sumcheck/relations/auxiliary_relation.hpp" + +// #pragma GCC diagnostic ignored "-Wunused-variable" + +// using namespace barretenberg; +// using namespace proof_system::honk::sumcheck; + +// namespace proof_system::honk { +// template +// UltraVerifier_::UltraVerifier_(std::shared_ptr verifier_key) +// : key(verifier_key) +// {} + +// template +// UltraVerifier_::UltraVerifier_(UltraVerifier_&& other) +// : key(std::move(other.key)) +// , kate_verification_key(std::move(other.kate_verification_key)) +// {} + +// template UltraVerifier_& UltraVerifier_::operator=(UltraVerifier_&& other) +// { +// key = other.key; +// kate_verification_key = (std::move(other.kate_verification_key)); +// kate_g1_elements.clear(); +// kate_fr_elements.clear(); +// return *this; +// } + +// /** +// * @brief This function verifies an Ultra Honk proof for given program settings. +// * +// */ +// template bool UltraVerifier_::verify_proof(const plonk::proof& proof) +// { +// using FF = typename Flavor::FF; +// using GroupElement = typename Flavor::GroupElement; +// using Commitment = typename Flavor::Commitment; +// using Gemini = pcs::gemini::MultilinearReductionScheme; +// using Shplonk = pcs::shplonk::SingleBatchOpeningScheme; +// using KZG = pcs::kzg::UnivariateOpeningScheme; +// using VerifierCommitments = typename Flavor::VerifierCommitments; +// using CommitmentLabels = typename Flavor::CommitmentLabels; + +// RelationParameters relation_parameters; + +// transcript = VerifierTranscript{ proof.proof_data }; + +// auto commitments = VerifierCommitments(key, transcript); +// auto commitment_labels = CommitmentLabels(); + +// // TODO(Adrian): Change the initialization of the transcript to take the VK hash? +// const auto circuit_size = transcript.template receive_from_prover("circuit_size"); +// const auto public_input_size = transcript.template receive_from_prover("public_input_size"); + +// if (circuit_size != key->circuit_size) { +// return false; +// } +// if (public_input_size != key->num_public_inputs) { +// return false; +// } + +// std::vector public_inputs; +// for (size_t i = 0; i < public_input_size; ++i) { +// auto public_input_i = transcript.template receive_from_prover("public_input_" + std::to_string(i)); +// public_inputs.emplace_back(public_input_i); +// } + +// // Get commitments to first three wires +// commitments.w_l = transcript.template receive_from_prover(commitment_labels.w_l); +// commitments.w_r = transcript.template receive_from_prover(commitment_labels.w_r); +// commitments.w_o = transcript.template receive_from_prover(commitment_labels.w_o); + +// // Get challenge for sorted list batching and wire four memory records +// auto eta = transcript.get_challenge("eta"); +// relation_parameters.eta = eta; + +// // Get commitments to sorted list accumulator and fourth wire +// commitments.sorted_accum = transcript.template receive_from_prover(commitment_labels.sorted_accum); +// commitments.w_4 = transcript.template receive_from_prover(commitment_labels.w_4); + +// // Get permutation challenges +// auto [beta, gamma] = transcript.get_challenges("beta", "gamma"); + +// const FF public_input_delta = compute_public_input_delta(public_inputs, beta, gamma, circuit_size); +// const FF lookup_grand_product_delta = compute_lookup_grand_product_delta(beta, gamma, circuit_size); + +// relation_parameters.beta = beta; +// relation_parameters.gamma = gamma; +// relation_parameters.public_input_delta = public_input_delta; +// relation_parameters.lookup_grand_product_delta = lookup_grand_product_delta; + +// // Get commitment to permutation and lookup grand products +// commitments.z_perm = transcript.template receive_from_prover(commitment_labels.z_perm); +// commitments.z_lookup = transcript.template receive_from_prover(commitment_labels.z_lookup); + +// // Execute Sumcheck Verifier +// auto sumcheck = Sumcheck, +// honk::sumcheck::UltraArithmeticRelation>(circuit_size, transcript); +// // auto sumcheck = Sumcheck, +// // honk::sumcheck::UltraArithmeticRelation, +// // honk::sumcheck::UltraArithmeticRelationSecondary, +// // honk::sumcheck::UltraGrandProductComputationRelation, +// // honk::sumcheck::UltraGrandProductInitializationRelation, +// // honk::sumcheck::LookupGrandProductComputationRelation, +// // honk::sumcheck::LookupGrandProductInitializationRelation, +// // honk::sumcheck::GenPermSortRelation, +// // honk::sumcheck::EllipticRelation, +// // honk::sumcheck::AuxiliaryRelation>(circuit_size, transcript); + +// std::optional sumcheck_output = sumcheck.execute_verifier(relation_parameters); + +// // If Sumcheck does not return an output, sumcheck verification has failed +// if (!sumcheck_output.has_value()) { +// return false; +// } + +// auto [multivariate_challenge, purported_evaluations] = *sumcheck_output; + +// // Execute Gemini/Shplonk verification: + +// // Construct inputs for Gemini verifier: +// // - Multivariate opening point u = (u_0, ..., u_{d-1}) +// // - batched unshifted and to-be-shifted polynomial commitments +// auto batched_commitment_unshifted = GroupElement::zero(); +// auto batched_commitment_to_be_shifted = GroupElement::zero(); + +// // Compute powers of batching challenge rho +// FF rho = transcript.get_challenge("rho"); +// std::vector rhos = Gemini::powers_of_rho(rho, Flavor::NUM_ALL_ENTITIES); + +// // Compute batched multivariate evaluation +// FF batched_evaluation = FF::zero(); +// size_t evaluation_idx = 0; +// for (auto& value : purported_evaluations.get_unshifted_then_shifted()) { +// batched_evaluation += value * rhos[evaluation_idx]; +// ++evaluation_idx; +// } + +// // Construct batched commitment for NON-shifted polynomials +// size_t commitment_idx = 0; +// for (auto& commitment : commitments.get_unshifted()) { +// batched_commitment_unshifted += commitment * rhos[commitment_idx]; +// ++commitment_idx; +// } + +// // Construct batched commitment for to-be-shifted polynomials +// for (auto& commitment : commitments.get_to_be_shifted()) { +// batched_commitment_to_be_shifted += commitment * rhos[commitment_idx]; +// ++commitment_idx; +// } + +// // Produce a Gemini claim consisting of: +// // - d+1 commitments [Fold_{r}^(0)], [Fold_{-r}^(0)], and [Fold^(l)], l = 1:d-1 +// // - d+1 evaluations a_0_pos, and a_l, l = 0:d-1 +// auto gemini_claim = Gemini::reduce_verify(multivariate_challenge, +// batched_evaluation, +// batched_commitment_unshifted, +// batched_commitment_to_be_shifted, +// transcript); + +// // Produce a Shplonk claim: commitment [Q] - [Q_z], evaluation zero (at random challenge z) +// auto shplonk_claim = Shplonk::reduce_verify(gemini_claim, transcript); + +// // Aggregate inputs [Q] - [Q_z] and [W] into an 'accumulator' (can perform pairing check on result) +// auto kzg_claim = KZG::reduce_verify(shplonk_claim, transcript); + +// // Return result of final pairing check +// return kzg_claim.verify(kate_verification_key); +// } + +// template class UltraVerifier_; + +// } // namespace proof_system::honk diff --git a/cpp/src/barretenberg/honk/proof_system/verifier.cpp b/cpp/src/barretenberg/honk/proof_system/verifier.cpp index 6238f6e2e1..0991b9b523 100644 --- a/cpp/src/barretenberg/honk/proof_system/verifier.cpp +++ b/cpp/src/barretenberg/honk/proof_system/verifier.cpp @@ -5,8 +5,7 @@ #include "barretenberg/ecc/curves/bn254/scalar_multiplication/scalar_multiplication.hpp" #include "barretenberg/honk/utils/power_polynomial.hpp" #include "barretenberg/honk/sumcheck/relations/arithmetic_relation.hpp" -#include "barretenberg/honk/sumcheck/relations/grand_product_initialization_relation.hpp" -#include "barretenberg/honk/sumcheck/relations/grand_product_computation_relation.hpp" +#include "barretenberg/honk/sumcheck/relations/permutation_relation.hpp" using namespace barretenberg; using namespace proof_system::honk::sumcheck; @@ -111,11 +110,9 @@ template bool StandardVerifier_::verify_proof(const pl commitments.z_perm = transcript.template receive_from_prover(commitment_labels.z_perm); // Execute Sumcheck Verifier - auto sumcheck = Sumcheck, - honk::sumcheck::ArithmeticRelation, - honk::sumcheck::GrandProductComputationRelation, - honk::sumcheck::GrandProductInitializationRelation>(circuit_size, transcript); + auto sumcheck = + Sumcheck, sumcheck::ArithmeticRelation, sumcheck::PermutationRelation>( + circuit_size, transcript); std::optional sumcheck_output = sumcheck.execute_verifier(relation_parameters); // If Sumcheck does not return an output, sumcheck verification has failed diff --git a/cpp/src/barretenberg/honk/sumcheck/new_sumcheck.test.cpp b/cpp/src/barretenberg/honk/sumcheck/new_sumcheck.test.cpp new file mode 100644 index 0000000000..f507aef42d --- /dev/null +++ b/cpp/src/barretenberg/honk/sumcheck/new_sumcheck.test.cpp @@ -0,0 +1,304 @@ +#include "sumcheck.hpp" +#include "barretenberg/honk/transcript/transcript.hpp" +#include "barretenberg/honk/flavor/standard.hpp" +#include "barretenberg/transcript/transcript_wrappers.hpp" +#include "relations/arithmetic_relation.hpp" +#include "relations/permutation_relation.hpp" +#include "barretenberg/transcript/manifest.hpp" +#include +#include +#include +#include "barretenberg/ecc/curves/bn254/fr.hpp" +#include +#include "barretenberg/numeric/random/engine.hpp" +#include "barretenberg/honk/composer/standard_honk_composer.hpp" +#include "barretenberg/honk/composer/ultra_honk_composer.hpp" + +#include +#include +#include +#include +#include +#include + +using namespace proof_system::honk; +using namespace proof_system::honk::sumcheck; +using Flavor = honk::flavor::Standard; +using FF = typename Flavor::FF; +using ProverPolynomials = typename Flavor::ProverPolynomials; + +namespace test_sumcheck_new { + +TEST(NewSumcheck, Standard) +{ + using Flavor = honk::flavor::Standard; + using FF = typename Flavor::FF; + using ProverPolynomials = typename Flavor::ProverPolynomials; + + // Create a composer and a dummy circuit with a few gates + auto composer = StandardHonkComposer(); + fr a = fr::one(); + // Using the public variable to check that public_input_delta is computed and added to the relation correctly + uint32_t a_idx = composer.add_public_variable(a); + fr b = fr::one(); + fr c = a + b; + fr d = a + c; + uint32_t b_idx = composer.add_variable(b); + uint32_t c_idx = composer.add_variable(c); + uint32_t d_idx = composer.add_variable(d); + for (size_t i = 0; i < 16; i++) { + composer.create_add_gate({ a_idx, b_idx, c_idx, fr::one(), fr::one(), fr::neg_one(), fr::zero() }); + composer.create_add_gate({ d_idx, c_idx, a_idx, fr::one(), fr::neg_one(), fr::neg_one(), fr::zero() }); + } + // Create a prover (it will compute proving key and witness) + auto prover = composer.create_prover(); + + // Generate beta and gamma + fr beta = fr::random_element(); + fr gamma = fr::random_element(); + + // Compute public input delta + const auto public_inputs = composer.circuit_constructor.get_public_inputs(); + auto public_input_delta = + honk::compute_public_input_delta(public_inputs, beta, gamma, prover.key->circuit_size); + + sumcheck::RelationParameters relation_parameters{ + .beta = beta, + .gamma = gamma, + .public_input_delta = public_input_delta, + }; + + // Compute grand product polynomial + polynomial z_permutation = prover_library::compute_permutation_grand_product(prover.key, beta, gamma); + + ProverPolynomials prover_polynomials; + + prover_polynomials.w_l = prover.key->w_l; + prover_polynomials.w_r = prover.key->w_r; + prover_polynomials.w_o = prover.key->w_o; + prover_polynomials.z_perm = z_permutation; + prover_polynomials.z_perm_shift = z_permutation.shifted(); + prover_polynomials.q_m = prover.key->q_m; + prover_polynomials.q_l = prover.key->q_l; + prover_polynomials.q_r = prover.key->q_r; + prover_polynomials.q_o = prover.key->q_o; + prover_polynomials.q_c = prover.key->q_c; + prover_polynomials.sigma_1 = prover.key->sigma_1; + prover_polynomials.sigma_2 = prover.key->sigma_2; + prover_polynomials.sigma_3 = prover.key->sigma_3; + prover_polynomials.id_1 = prover.key->id_1; + prover_polynomials.id_2 = prover.key->id_2; + prover_polynomials.id_3 = prover.key->id_3; + prover_polynomials.lagrange_first = prover.key->lagrange_first; + prover_polynomials.lagrange_last = prover.key->lagrange_last; + + auto prover_transcript = ProverTranscript::init_empty(); + + auto sumcheck_prover = Sumcheck, ArithmeticRelation, PermutationRelation>( + prover.key->circuit_size, prover_transcript); + + auto prover_output = sumcheck_prover.execute_prover(prover_polynomials, relation_parameters); + + auto verifier_transcript = VerifierTranscript::init_empty(prover_transcript); + + auto sumcheck_verifier = Sumcheck, ArithmeticRelation, PermutationRelation>( + prover.key->circuit_size, verifier_transcript); + + std::optional verifier_output = sumcheck_verifier.execute_verifier(relation_parameters); + + ASSERT_TRUE(verifier_output.has_value()); +} + +TEST(NewSumcheck, Ultra) +{ + // using Flavor = honk::flavor::Ultra; + // using FF = typename Flavor::FF; + // using ProverPolynomials = typename Flavor::ProverPolynomials; + + // // Create a composer and a dummy circuit with a few gates + // auto composer = UltraHonkComposer(); + // fr a = fr::one(); + // // Using the public variable to check that public_input_delta is computed and added to the relation correctly + // uint32_t a_idx = composer.add_variable(a); + // fr b = fr::one(); + // fr c = a + b; + // fr d = a + c; + // uint32_t b_idx = composer.add_variable(b); + // uint32_t c_idx = composer.add_variable(c); + // uint32_t d_idx = composer.add_variable(d); + // for (size_t i = 0; i < 16; i++) { + // composer.create_add_gate({ a_idx, b_idx, c_idx, fr::one(), fr::one(), fr::neg_one(), fr::zero() }); + // composer.create_add_gate({ d_idx, c_idx, a_idx, fr::one(), fr::neg_one(), fr::neg_one(), fr::zero() }); + // } + // // Create a prover (it will compute proving key and witness) + // auto prover = composer.create_prover(); + + // // Generate beta and gamma + // fr beta = fr::random_element(); + // fr gamma = fr::random_element(); + + // // Compute public input delta + // const auto public_inputs = composer.circuit_constructor.get_public_inputs(); + // auto public_input_delta = + // honk::compute_public_input_delta(public_inputs, beta, gamma, prover.key->circuit_size); + + // sumcheck::RelationParameters relation_parameters{ + // .beta = beta, + // .gamma = gamma, + // .public_input_delta = public_input_delta, + // }; + + // // Compute grand product polynomial + // polynomial z_permutation = prover_library::compute_permutation_grand_product(prover.key, beta, gamma); + + // ProverPolynomials prover_polynomials; + + // prover_polynomials.w_l = prover.key->w_l; + // prover_polynomials.w_r = prover.key->w_r; + // prover_polynomials.w_o = prover.key->w_o; + // prover_polynomials.w_4 = prover.key->w_4; + // prover_polynomials.w_l_shift = prover.key->w_l.shifted(); + // prover_polynomials.w_r_shift = prover.key->w_r.shifted(); + // prover_polynomials.w_o_shift = prover.key->w_o.shifted(); + // prover_polynomials.w_4_shift = prover.key->w_4.shifted(); + // prover_polynomials.sorted_1 = prover.key->sorted_1; + // prover_polynomials.sorted_2 = prover.key->sorted_2; + // prover_polynomials.sorted_3 = prover.key->sorted_3; + // prover_polynomials.sorted_4 = prover.key->sorted_4; + // prover_polynomials.sorted_accum = sorted_list_accumulator; + // prover_polynomials.sorted_accum_shift = sorted_list_accumulator.shifted(); + // prover_polynomials.table_1 = prover.key->table_1; + // prover_polynomials.table_2 = prover.key->table_2; + // prover_polynomials.table_3 = prover.key->table_3; + // prover_polynomials.table_4 = prover.key->table_4; + // prover_polynomials.table_1_shift = prover.key->table_1.shifted(); + // prover_polynomials.table_2_shift = prover.key->table_2.shifted(); + // prover_polynomials.table_3_shift = prover.key->table_3.shifted(); + // prover_polynomials.table_4_shift = prover.key->table_4.shifted(); + // prover_polynomials.z_perm = z_permutation; + // prover_polynomials.z_perm_shift = z_permutation.shifted(); + // prover_polynomials.z_lookup = z_lookup; + // prover_polynomials.z_lookup_shift = z_lookup.shifted(); + // prover_polynomials.q_m = prover.key->q_m; + // prover_polynomials.q_l = prover.key->q_l; + // prover_polynomials.q_r = prover.key->q_r; + // prover_polynomials.q_o = prover.key->q_o; + // prover_polynomials.q_c = prover.key->q_c; + // prover_polynomials.q_4 = prover.key->q_4; + // prover_polynomials.q_arith = prover.key->q_arith; + // prover_polynomials.q_sort = prover.key->q_sort; + // prover_polynomials.q_elliptic = prover.key->q_elliptic; + // prover_polynomials.q_aux = prover.key->q_aux; + // prover_polynomials.q_lookup = prover.key->q_lookup; + // prover_polynomials.sigma_1 = prover.key->sigma_1; + // prover_polynomials.sigma_2 = prover.key->sigma_2; + // prover_polynomials.sigma_3 = prover.key->sigma_3; + // prover_polynomials.sigma_4 = prover.key->sigma_4; + // prover_polynomials.id_1 = prover.key->id_1; + // prover_polynomials.id_2 = prover.key->id_2; + // prover_polynomials.id_3 = prover.key->id_3; + // prover_polynomials.id_4 = prover.key->id_4; + // prover_polynomials.lagrange_first = prover.key->lagrange_first; + // prover_polynomials.lagrange_last = prover.key->lagrange_last; + + // auto prover_transcript = ProverTranscript::init_empty(); + + // auto sumcheck_prover = Sumcheck, ArithmeticRelation, PermutationRelation>( + // prover.key->circuit_size, prover_transcript); + + // auto prover_output = sumcheck_prover.execute_prover(prover_polynomials, relation_parameters); + + // auto verifier_transcript = VerifierTranscript::init_empty(prover_transcript); + + // auto sumcheck_verifier = Sumcheck, ArithmeticRelation, PermutationRelation>( + // prover.key->circuit_size, verifier_transcript); + + // std::optional verifier_output = sumcheck_verifier.execute_verifier(relation_parameters); + + // ASSERT_TRUE(verifier_output.has_value()); +} + +// WORKTODO: move these utility tests to SumcheckRound tests +TEST(NewSumcheck, TupleOfTuplesOfUnivariates) +{ + using Flavor = honk::flavor::Standard; + using FF = typename Flavor::FF; + + // Define three linear univariates of different sizes + Univariate univariate_1({ 1, 2, 3 }); + Univariate univariate_2({ 2, 4 }); + Univariate univariate_3({ 3, 4, 5, 6, 7 }); + const size_t MAX_LENGTH = 5; + + // Instantiate some barycentric extension utility classes + auto barycentric_util_1 = BarycentricData(); + auto barycentric_util_2 = BarycentricData(); + auto barycentric_util_3 = BarycentricData(); + + // Construct a tuple of tuples of the form { {univariate_1}, {univariate_2, univariate_3} } + auto tuple_of_tuples = std::make_tuple(std::make_tuple(univariate_1), std::make_tuple(univariate_2, univariate_3)); + + // Use scale_univariate_accumulators to scale by challenge powers + FF challenge = 5; + FF running_challenge = 1; + SumcheckRound::scale_univariates(tuple_of_tuples, challenge, running_challenge); + + // Use extend_and_batch_univariates to extend to MAX_LENGTH then accumulate + auto result = Univariate(); + SumcheckRound::extend_and_batch_univariates(tuple_of_tuples, result); + + // Repeat the batching process manually + auto result_expected = barycentric_util_1.extend(univariate_1) * 1 + + barycentric_util_2.extend(univariate_2) * challenge + + barycentric_util_3.extend(univariate_3) * challenge * challenge; + + // Compare final batched univarites + EXPECT_EQ(result, result_expected); + + // Reinitialize univariate accumulators to zero + SumcheckRound::zero_univariates(tuple_of_tuples); + + // Check that reinitialization was successful + Univariate expected_1({ 0, 0, 0 }); + Univariate expected_2({ 0, 0 }); + Univariate expected_3({ 0, 0, 0, 0, 0 }); + EXPECT_EQ(std::get<0>(std::get<0>(tuple_of_tuples)), expected_1); + EXPECT_EQ(std::get<0>(std::get<1>(tuple_of_tuples)), expected_2); + EXPECT_EQ(std::get<1>(std::get<1>(tuple_of_tuples)), expected_3); +} + +TEST(NewSumcheck, TuplesOfEvaluationArrays) +{ + using Flavor = honk::flavor::Standard; + using FF = typename Flavor::FF; + + // Define two arrays of arbitrary elements + std::array evaluations_1 = { 4 }; + std::array evaluations_2 = { 6, 2 }; + + // Construct a tuple + auto tuple_of_arrays = std::make_tuple(evaluations_1, evaluations_2); + + // Use scale_and_batch_elements to scale by challenge powers + FF challenge = 5; + FF running_challenge = 1; + FF result = 0; + SumcheckRound::scale_and_batch_elements( + tuple_of_arrays, challenge, running_challenge, result); + + // Repeat the batching process manually + auto result_expected = + evaluations_1[0] * 1 + evaluations_2[0] * challenge + evaluations_2[1] * challenge * challenge; + + // Compare batched result + EXPECT_EQ(result, result_expected); + + // Reinitialize univariate accumulators to zero + SumcheckRound::zero_elements(tuple_of_arrays); + + EXPECT_EQ(std::get<0>(tuple_of_arrays)[0], 0); + EXPECT_EQ(std::get<1>(tuple_of_arrays)[0], 0); + EXPECT_EQ(std::get<1>(tuple_of_arrays)[1], 0); +} + +} // namespace test_sumcheck_new diff --git a/cpp/src/barretenberg/honk/sumcheck/polynomials/barycentric_data.test.cpp b/cpp/src/barretenberg/honk/sumcheck/polynomials/barycentric_data.test.cpp index ed2471d01e..12300c1bbe 100644 --- a/cpp/src/barretenberg/honk/sumcheck/polynomials/barycentric_data.test.cpp +++ b/cpp/src/barretenberg/honk/sumcheck/polynomials/barycentric_data.test.cpp @@ -1,86 +1,86 @@ -#include "barycentric_data.hpp" -#include "barretenberg/ecc/curves/bn254/fr.hpp" - -#include -#include "barretenberg/numeric/random/engine.hpp" - -using namespace proof_system::honk::sumcheck; -namespace test_sumcheck_polynomials { - -template class BarycentricDataTests : public testing::Test {}; - -using FieldTypes = testing::Types; -TYPED_TEST_SUITE(BarycentricDataTests, FieldTypes); - -#define BARYCENTIC_DATA_TESTS_TYPE_ALIASES using FF = TypeParam; - -TYPED_TEST(BarycentricDataTests, Extend) -{ - BARYCENTIC_DATA_TESTS_TYPE_ALIASES - const size_t domain_size(2); - const size_t num_evals(10); - auto f = Univariate({ 1, 2 }); - auto expected_result = Univariate({ 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 }); - BarycentricData barycentric_data; - auto result = barycentric_data.extend(f); - EXPECT_EQ(result, expected_result); -} - -TYPED_TEST(BarycentricDataTests, Evaluate) -{ - BARYCENTIC_DATA_TESTS_TYPE_ALIASES - const size_t domain_size(2); - const size_t num_evals(10); - auto f = Univariate({ 1, 2 }); - FF u = 5; - FF expected_result = 6; - BarycentricData barycentric_data; - auto result = barycentric_data.evaluate(f, u); - EXPECT_EQ(result, expected_result); -} - -TYPED_TEST(BarycentricDataTests, BarycentricData2to3) -{ - BARYCENTIC_DATA_TESTS_TYPE_ALIASES - - const size_t domain_size = 2; - const size_t num_evals = 3; - auto barycentric = BarycentricData(); - std::array expected_big_domain{ { 0, 1, 2 } }; - std::array expected_denominators{ { -1, 1 } }; - std::array expected_full_numerator_values{ { 0, 0, 2 } }; - EXPECT_EQ(barycentric.big_domain, expected_big_domain); - EXPECT_EQ(barycentric.lagrange_denominators, expected_denominators); - EXPECT_EQ(barycentric.full_numerator_values, expected_full_numerator_values); - - // e1(X) = 1*(1-X) + 2*X = 1 + X - Univariate e1{ { 1, 2 } }; - FF u = FF::random_element(); - FF calculated_val_at_u = barycentric.evaluate(e1, u); - EXPECT_EQ(u + 1, calculated_val_at_u); - - Univariate ext1 = barycentric.extend(e1); - Univariate expected{ { 1, 2, 3 } }; - EXPECT_EQ(ext1, expected); -} - -TYPED_TEST(BarycentricDataTests, BarycentricData5to6) -{ - BARYCENTIC_DATA_TESTS_TYPE_ALIASES - - const size_t domain_size = 5; - const size_t num_evals = 6; - auto barycentric = BarycentricData(); - - // Note: we are able to represent a degree 4 polynomial with 5 points thus this - // extension will succeed. It would fail for values on a polynomial of degree > 4. - Univariate e1{ { 1, 3, 25, 109, 321 } }; // X^4 + X^3 + 1 - - Univariate ext1 = barycentric.extend(e1); - - Univariate expected{ { 1, 3, 25, 109, 321, 751 } }; - - EXPECT_EQ(ext1, expected); -} - -} // namespace test_sumcheck_polynomials +// #include "barycentric_data.hpp" +// #include "barretenberg/ecc/curves/bn254/fr.hpp" + +// #include +// #include "barretenberg/numeric/random/engine.hpp" + +// using namespace proof_system::honk::sumcheck; +// namespace test_sumcheck_polynomials { + +// template class BarycentricDataTests : public testing::Test {}; + +// using FieldTypes = testing::Types; +// TYPED_TEST_SUITE(BarycentricDataTests, FieldTypes); + +// #define BARYCENTIC_DATA_TESTS_TYPE_ALIASES using FF = TypeParam; + +// TYPED_TEST(BarycentricDataTests, Extend) +// { +// BARYCENTIC_DATA_TESTS_TYPE_ALIASES +// const size_t domain_size(2); +// const size_t num_evals(10); +// auto f = Univariate({ 1, 2 }); +// auto expected_result = Univariate({ 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 }); +// BarycentricData barycentric_data; +// auto result = barycentric_data.extend(f); +// EXPECT_EQ(result, expected_result); +// } + +// TYPED_TEST(BarycentricDataTests, Evaluate) +// { +// BARYCENTIC_DATA_TESTS_TYPE_ALIASES +// const size_t domain_size(2); +// const size_t num_evals(10); +// auto f = Univariate({ 1, 2 }); +// FF u = 5; +// FF expected_result = 6; +// BarycentricData barycentric_data; +// auto result = barycentric_data.evaluate(f, u); +// EXPECT_EQ(result, expected_result); +// } + +// TYPED_TEST(BarycentricDataTests, BarycentricData2to3) +// { +// BARYCENTIC_DATA_TESTS_TYPE_ALIASES + +// const size_t domain_size = 2; +// const size_t num_evals = 3; +// auto barycentric = BarycentricData(); +// std::array expected_big_domain{ { 0, 1, 2 } }; +// std::array expected_denominators{ { -1, 1 } }; +// std::array expected_full_numerator_values{ { 0, 0, 2 } }; +// EXPECT_EQ(barycentric.big_domain, expected_big_domain); +// EXPECT_EQ(barycentric.lagrange_denominators, expected_denominators); +// EXPECT_EQ(barycentric.full_numerator_values, expected_full_numerator_values); + +// // e1(X) = 1*(1-X) + 2*X = 1 + X +// Univariate e1{ { 1, 2 } }; +// FF u = FF::random_element(); +// FF calculated_val_at_u = barycentric.evaluate(e1, u); +// EXPECT_EQ(u + 1, calculated_val_at_u); + +// Univariate ext1 = barycentric.extend(e1); +// Univariate expected{ { 1, 2, 3 } }; +// EXPECT_EQ(ext1, expected); +// } + +// TYPED_TEST(BarycentricDataTests, BarycentricData5to6) +// { +// BARYCENTIC_DATA_TESTS_TYPE_ALIASES + +// const size_t domain_size = 5; +// const size_t num_evals = 6; +// auto barycentric = BarycentricData(); + +// // Note: we are able to represent a degree 4 polynomial with 5 points thus this +// // extension will succeed. It would fail for values on a polynomial of degree > 4. +// Univariate e1{ { 1, 3, 25, 109, 321 } }; // X^4 + X^3 + 1 + +// Univariate ext1 = barycentric.extend(e1); + +// Univariate expected{ { 1, 3, 25, 109, 321, 751 } }; + +// EXPECT_EQ(ext1, expected); +// } + +// } // namespace test_sumcheck_polynomials diff --git a/cpp/src/barretenberg/honk/sumcheck/polynomials/multivariates.test.cpp b/cpp/src/barretenberg/honk/sumcheck/polynomials/multivariates.test.cpp index 3e40df0113..9917346999 100644 --- a/cpp/src/barretenberg/honk/sumcheck/polynomials/multivariates.test.cpp +++ b/cpp/src/barretenberg/honk/sumcheck/polynomials/multivariates.test.cpp @@ -1,320 +1,320 @@ -#include "barretenberg/ecc/curves/bn254/fr.hpp" -#include "barretenberg/honk/sumcheck/relations/arithmetic_relation.hpp" -#include "barretenberg/honk/sumcheck/sumcheck.hpp" - -#include -#include "barretenberg/honk/transcript/transcript.hpp" -#include "barretenberg/numeric/random/engine.hpp" -#include "barretenberg/honk/flavor/standard.hpp" - -using namespace proof_system::honk::sumcheck; -namespace test_sumcheck_polynomials { - -template class MultivariatesTests : public testing::Test {}; - -using Flavors = testing::Types; - -TYPED_TEST_SUITE(MultivariatesTests, Flavors); - -/* - * We represent a bivariate f0 as f0(X0, X1). The indexing starts from 0 to match with the round number in sumcheck. - * The idea is variable X0 (lsb) will be folded at round 2 (the first sumcheck round), - * then the variable X1 (msb) will be folded at round 1 (the last rond in this case). Pictorially we have, - * v10 ------ v11 - * | | - * X0(lsb) | | - * | X1(msb) | - * v00 ------ v01 - * f0(X0, X1) = v00 * (1-X0) * (1-X1) - * + v10 * X0 * (1-X1) - * + v01 * (1-X0) * X1 - * + v11 * X0 * X1. - * - * To effectively represent folding we write, - * f0(X0, X1) = [v00 * (1-X0) + v10 * X0] * (1-X1) - * + [v01 * (1-X0) + v11 * X0] * X1. - * - * After folding at round 0 (round challenge u0), we have, - * f0(u0,X1) = (v00 * (1-u0) + v10 * u0) * (1-X1) - * + (v01 * (1-u0) + v11 * u0) * X1. - * - * After folding at round 1 (round challenge u1), we have, - * f0(u0,u1) = (v00 * (1-u0) + v10 * u0) * (1-u1) - * + (v01 * (1-u0) + v11 * u0) * u1. - */ -TYPED_TEST(MultivariatesTests, FoldTwoRoundsSpecial) -{ - using Flavor = TypeParam; - using FF = typename Flavor::FF; - using Transcript = honk::ProverTranscript; - - // values here are chosen to check another test - const size_t multivariate_d(2); - const size_t multivariate_n(1 << multivariate_d); - - FF v00 = 0; - FF v10 = 1; - FF v01 = 0; - FF v11 = 0; - - std::array f0 = { v00, v10, v01, v11 }; - - auto full_polynomials = std::array, 1>({ f0 }); - auto transcript = Transcript::init_empty(); - auto sumcheck = Sumcheck(multivariate_n, transcript); - - FF round_challenge_0 = { 0x6c7301b49d85a46c, 0x44311531e39c64f6, 0xb13d66d8d6c1a24c, 0x04410c360230a295 }; - round_challenge_0.self_to_montgomery_form(); - FF expected_lo = v00 * (FF(1) - round_challenge_0) + v10 * round_challenge_0; - FF expected_hi = v01 * (FF(1) - round_challenge_0) + v11 * round_challenge_0; - - sumcheck.fold(full_polynomials, multivariate_n, round_challenge_0); - - EXPECT_EQ(sumcheck.folded_polynomials[0][0], round_challenge_0); - EXPECT_EQ(sumcheck.folded_polynomials[0][1], FF(0)); - - FF round_challenge_1 = 2; - FF expected_val = expected_lo * (FF(1) - round_challenge_1) + expected_hi * round_challenge_1; - - sumcheck.fold(sumcheck.folded_polynomials, multivariate_n >> 1, round_challenge_1); - EXPECT_EQ(sumcheck.folded_polynomials[0][0], expected_val); -} - -TYPED_TEST(MultivariatesTests, FoldTwoRoundsGeneric) -{ - using Flavor = TypeParam; - using FF = typename Flavor::FF; - using Transcript = honk::ProverTranscript; - - const size_t multivariate_d(2); - const size_t multivariate_n(1 << multivariate_d); - - FF v00 = FF::random_element(); - FF v10 = FF::random_element(); - FF v01 = FF::random_element(); - FF v11 = FF::random_element(); - - std::array f0 = { v00, v10, v01, v11 }; - - auto full_polynomials = std::array, 1>({ f0 }); - auto transcript = Transcript::init_empty(); - auto sumcheck = Sumcheck(multivariate_n, transcript); - - FF round_challenge_0 = FF::random_element(); - FF expected_lo = v00 * (FF(1) - round_challenge_0) + v10 * round_challenge_0; - FF expected_hi = v01 * (FF(1) - round_challenge_0) + v11 * round_challenge_0; - - sumcheck.fold(full_polynomials, multivariate_n, round_challenge_0); - - EXPECT_EQ(sumcheck.folded_polynomials[0][0], expected_lo); - EXPECT_EQ(sumcheck.folded_polynomials[0][1], expected_hi); - - FF round_challenge_1 = FF::random_element(); - FF expected_val = expected_lo * (FF(1) - round_challenge_1) + expected_hi * round_challenge_1; - sumcheck.fold(sumcheck.folded_polynomials, multivariate_n >> 1, round_challenge_1); - EXPECT_EQ(sumcheck.folded_polynomials[0][0], expected_val); -} - -/* - * Similarly for a trivariate polynomial f0(X0, X1, X2), we have - * f0(X0, X1, X2) = v000 * (1-X0) * (1-X1) * (1-X2) - * + v100 * X0 * (1-X1) * (1-X2) - * + v010 * (1-X0) * X1 * (1-X2) - * + v110 * X0 * X1 * (1-X2) - * + v001 * (1-X0) * (1-X1) * X2 - * + v101 * X0 * (1-X1) * X2 - * + v011 * (1-X0) * X1 * X2 - * + v111 * X0 * X1 * X2. - * After round 0 (round challenge u0), we have - * f0(u0, X1, X2) = [v000 * (1-u0) + v100 * u0] * (1-X1) * (1-X2) - * + [v010 * (1-u0) + v110 * u0] * X1 * (1-X2) - * + [v001 * (1-u0) + v101 * u0] * (1-X1) * X2 - * + [v011 * (1-u0) + v111 * u0] * X1 * X2. - * After round 1 (round challenge u1), we have - * f0(u0, u1, X2) = [(v000 * (1-u0) + v100 * u0) * (1-u1) + (v010 * (1-u0) + v110 * u0) * u1] * (1-X2) - * + [(v001 * (1-u0) + v101 * u0) * (1-u1) + (v011 * (1-u0) + v111 * u0) * u1] * X2. - * After round 2 (round challenge u2), we have - * f0(u0, u1, u2) = [(v000 * (1-u0) + v100 * u0) * (1-u1) + (v010 * (1-u0) + v110 * u0) * u1] * (1-u2) - * + [(v001 * (1-u0) + v101 * u0) * (1-u1) + (v011 * (1-u0) + v111 * u0) * u1] * u2. - */ -TYPED_TEST(MultivariatesTests, FoldThreeRoundsSpecial) -{ - using Flavor = TypeParam; - using FF = typename Flavor::FF; - using Transcript = honk::ProverTranscript; - - const size_t multivariate_d(3); - const size_t multivariate_n(1 << multivariate_d); - - FF v000 = 1; - FF v100 = 2; - FF v010 = 3; - FF v110 = 4; - FF v001 = 5; - FF v101 = 6; - FF v011 = 7; - FF v111 = 8; - - std::array f0 = { v000, v100, v010, v110, v001, v101, v011, v111 }; - - auto full_polynomials = std::array, 1>({ f0 }); - auto transcript = Transcript::init_empty(); - auto sumcheck = Sumcheck(multivariate_n, transcript); - - FF round_challenge_0 = 1; - FF expected_q1 = v000 * (FF(1) - round_challenge_0) + v100 * round_challenge_0; // 2 - FF expected_q2 = v010 * (FF(1) - round_challenge_0) + v110 * round_challenge_0; // 4 - FF expected_q3 = v001 * (FF(1) - round_challenge_0) + v101 * round_challenge_0; // 6 - FF expected_q4 = v011 * (FF(1) - round_challenge_0) + v111 * round_challenge_0; // 8 - - sumcheck.fold(full_polynomials, multivariate_n, round_challenge_0); - - EXPECT_EQ(sumcheck.folded_polynomials[0][0], expected_q1); - EXPECT_EQ(sumcheck.folded_polynomials[0][1], expected_q2); - EXPECT_EQ(sumcheck.folded_polynomials[0][2], expected_q3); - EXPECT_EQ(sumcheck.folded_polynomials[0][3], expected_q4); - - FF round_challenge_1 = 2; - FF expected_lo = expected_q1 * (FF(1) - round_challenge_1) + expected_q2 * round_challenge_1; // 6 - FF expected_hi = expected_q3 * (FF(1) - round_challenge_1) + expected_q4 * round_challenge_1; // 10 - - sumcheck.fold(sumcheck.folded_polynomials, multivariate_n >> 1, round_challenge_1); - EXPECT_EQ(sumcheck.folded_polynomials[0][0], expected_lo); - EXPECT_EQ(sumcheck.folded_polynomials[0][1], expected_hi); - - FF round_challenge_2 = 3; - FF expected_val = expected_lo * (FF(1) - round_challenge_2) + expected_hi * round_challenge_2; // 18 - sumcheck.fold(sumcheck.folded_polynomials, multivariate_n >> 2, round_challenge_2); - EXPECT_EQ(sumcheck.folded_polynomials[0][0], expected_val); -} - -TYPED_TEST(MultivariatesTests, FoldThreeRoundsGeneric) -{ - using Flavor = TypeParam; - using FF = typename Flavor::FF; - using Transcript = honk::ProverTranscript; - - const size_t multivariate_d(3); - const size_t multivariate_n(1 << multivariate_d); - - FF v000 = FF::random_element(); - FF v100 = FF::random_element(); - FF v010 = FF::random_element(); - FF v110 = FF::random_element(); - FF v001 = FF::random_element(); - FF v101 = FF::random_element(); - FF v011 = FF::random_element(); - FF v111 = FF::random_element(); - - std::array f0 = { v000, v100, v010, v110, v001, v101, v011, v111 }; - - auto full_polynomials = std::array, 1>({ f0 }); - auto transcript = Transcript::init_empty(); - auto sumcheck = Sumcheck(multivariate_n, transcript); - - FF round_challenge_0 = FF::random_element(); - FF expected_q1 = v000 * (FF(1) - round_challenge_0) + v100 * round_challenge_0; - FF expected_q2 = v010 * (FF(1) - round_challenge_0) + v110 * round_challenge_0; - FF expected_q3 = v001 * (FF(1) - round_challenge_0) + v101 * round_challenge_0; - FF expected_q4 = v011 * (FF(1) - round_challenge_0) + v111 * round_challenge_0; - - sumcheck.fold(full_polynomials, multivariate_n, round_challenge_0); - - EXPECT_EQ(sumcheck.folded_polynomials[0][0], expected_q1); - EXPECT_EQ(sumcheck.folded_polynomials[0][1], expected_q2); - EXPECT_EQ(sumcheck.folded_polynomials[0][2], expected_q3); - EXPECT_EQ(sumcheck.folded_polynomials[0][3], expected_q4); - - FF round_challenge_1 = FF::random_element(); - FF expected_lo = expected_q1 * (FF(1) - round_challenge_1) + expected_q2 * round_challenge_1; - FF expected_hi = expected_q3 * (FF(1) - round_challenge_1) + expected_q4 * round_challenge_1; - - sumcheck.fold(sumcheck.folded_polynomials, multivariate_n >> 1, round_challenge_1); - EXPECT_EQ(sumcheck.folded_polynomials[0][0], expected_lo); - EXPECT_EQ(sumcheck.folded_polynomials[0][1], expected_hi); - - FF round_challenge_2 = FF::random_element(); - FF expected_val = expected_lo * (FF(1) - round_challenge_2) + expected_hi * round_challenge_2; - sumcheck.fold(sumcheck.folded_polynomials, multivariate_n >> 2, round_challenge_2); - EXPECT_EQ(sumcheck.folded_polynomials[0][0], expected_val); -} - -TYPED_TEST(MultivariatesTests, FoldThreeRoundsGenericMultiplePolys) -{ - using Flavor = TypeParam; - using FF = typename Flavor::FF; - using Transcript = honk::ProverTranscript; - - const size_t multivariate_d(3); - const size_t multivariate_n(1 << multivariate_d); - std::array v000; - std::array v100; - std::array v010; - std::array v110; - std::array v001; - std::array v101; - std::array v011; - std::array v111; - - for (size_t i = 0; i < 3; i++) { - v000[i] = FF::random_element(); - v100[i] = FF::random_element(); - v010[i] = FF::random_element(); - v110[i] = FF::random_element(); - v001[i] = FF::random_element(); - v101[i] = FF::random_element(); - v011[i] = FF::random_element(); - v111[i] = FF::random_element(); - } - std::array f0 = { v000[0], v100[0], v010[0], v110[0], v001[0], v101[0], v011[0], v111[0] }; - std::array f1 = { v000[1], v100[1], v010[1], v110[1], v001[1], v101[1], v011[1], v111[1] }; - std::array f2 = { v000[2], v100[2], v010[2], v110[2], v001[2], v101[2], v011[2], v111[2] }; - - auto full_polynomials = std::array, 3>{ f0, f1, f2 }; - auto transcript = Transcript::init_empty(); - auto sumcheck = Sumcheck(multivariate_n, transcript); - - std::array expected_q1; - std::array expected_q2; - std::array expected_q3; - std::array expected_q4; - FF round_challenge_0 = FF::random_element(); - for (size_t i = 0; i < 3; i++) { - expected_q1[i] = v000[i] * (FF(1) - round_challenge_0) + v100[i] * round_challenge_0; - expected_q2[i] = v010[i] * (FF(1) - round_challenge_0) + v110[i] * round_challenge_0; - expected_q3[i] = v001[i] * (FF(1) - round_challenge_0) + v101[i] * round_challenge_0; - expected_q4[i] = v011[i] * (FF(1) - round_challenge_0) + v111[i] * round_challenge_0; - } - - sumcheck.fold(full_polynomials, multivariate_n, round_challenge_0); - for (size_t i = 0; i < 3; i++) { - EXPECT_EQ(sumcheck.folded_polynomials[i][0], expected_q1[i]); - EXPECT_EQ(sumcheck.folded_polynomials[i][1], expected_q2[i]); - EXPECT_EQ(sumcheck.folded_polynomials[i][2], expected_q3[i]); - EXPECT_EQ(sumcheck.folded_polynomials[i][3], expected_q4[i]); - } - - FF round_challenge_1 = FF::random_element(); - std::array expected_lo; - std::array expected_hi; - for (size_t i = 0; i < 3; i++) { - expected_lo[i] = expected_q1[i] * (FF(1) - round_challenge_1) + expected_q2[i] * round_challenge_1; - expected_hi[i] = expected_q3[i] * (FF(1) - round_challenge_1) + expected_q4[i] * round_challenge_1; - } - sumcheck.fold(sumcheck.folded_polynomials, multivariate_n >> 1, round_challenge_1); - for (size_t i = 0; i < 3; i++) { - EXPECT_EQ(sumcheck.folded_polynomials[i][0], expected_lo[i]); - EXPECT_EQ(sumcheck.folded_polynomials[i][1], expected_hi[i]); - } - FF round_challenge_2 = FF::random_element(); - std::array expected_val; - for (size_t i = 0; i < 3; i++) { - expected_val[i] = expected_lo[i] * (FF(1) - round_challenge_2) + expected_hi[i] * round_challenge_2; - } - sumcheck.fold(sumcheck.folded_polynomials, multivariate_n >> 2, round_challenge_2); - for (size_t i = 0; i < 3; i++) { - EXPECT_EQ(sumcheck.folded_polynomials[i][0], expected_val[i]); - } -} - -} // namespace test_sumcheck_polynomials +// #include "barretenberg/ecc/curves/bn254/fr.hpp" +// #include "barretenberg/honk/sumcheck/relations/arithmetic_relation.hpp" +// #include "barretenberg/honk/sumcheck/sumcheck.hpp" + +// #include +// #include "barretenberg/honk/transcript/transcript.hpp" +// #include "barretenberg/numeric/random/engine.hpp" +// #include "barretenberg/honk/flavor/standard.hpp" + +// using namespace proof_system::honk::sumcheck; +// namespace test_sumcheck_polynomials { + +// template class MultivariatesTests : public testing::Test {}; + +// using Flavors = testing::Types; + +// TYPED_TEST_SUITE(MultivariatesTests, Flavors); + +// /* +// * We represent a bivariate f0 as f0(X0, X1). The indexing starts from 0 to match with the round number in sumcheck. +// * The idea is variable X0 (lsb) will be folded at round 2 (the first sumcheck round), +// * then the variable X1 (msb) will be folded at round 1 (the last rond in this case). Pictorially we have, +// * v10 ------ v11 +// * | | +// * X0(lsb) | | +// * | X1(msb) | +// * v00 ------ v01 +// * f0(X0, X1) = v00 * (1-X0) * (1-X1) +// * + v10 * X0 * (1-X1) +// * + v01 * (1-X0) * X1 +// * + v11 * X0 * X1. +// * +// * To effectively represent folding we write, +// * f0(X0, X1) = [v00 * (1-X0) + v10 * X0] * (1-X1) +// * + [v01 * (1-X0) + v11 * X0] * X1. +// * +// * After folding at round 0 (round challenge u0), we have, +// * f0(u0,X1) = (v00 * (1-u0) + v10 * u0) * (1-X1) +// * + (v01 * (1-u0) + v11 * u0) * X1. +// * +// * After folding at round 1 (round challenge u1), we have, +// * f0(u0,u1) = (v00 * (1-u0) + v10 * u0) * (1-u1) +// * + (v01 * (1-u0) + v11 * u0) * u1. +// */ +// TYPED_TEST(MultivariatesTests, FoldTwoRoundsSpecial) +// { +// using Flavor = TypeParam; +// using FF = typename Flavor::FF; +// using Transcript = honk::ProverTranscript; + +// // values here are chosen to check another test +// const size_t multivariate_d(2); +// const size_t multivariate_n(1 << multivariate_d); + +// FF v00 = 0; +// FF v10 = 1; +// FF v01 = 0; +// FF v11 = 0; + +// std::array f0 = { v00, v10, v01, v11 }; + +// auto full_polynomials = std::array, 1>({ f0 }); +// auto transcript = Transcript::init_empty(); +// auto sumcheck = Sumcheck(multivariate_n, transcript); + +// FF round_challenge_0 = { 0x6c7301b49d85a46c, 0x44311531e39c64f6, 0xb13d66d8d6c1a24c, 0x04410c360230a295 }; +// round_challenge_0.self_to_montgomery_form(); +// FF expected_lo = v00 * (FF(1) - round_challenge_0) + v10 * round_challenge_0; +// FF expected_hi = v01 * (FF(1) - round_challenge_0) + v11 * round_challenge_0; + +// sumcheck.fold(full_polynomials, multivariate_n, round_challenge_0); + +// EXPECT_EQ(sumcheck.folded_polynomials[0][0], round_challenge_0); +// EXPECT_EQ(sumcheck.folded_polynomials[0][1], FF(0)); + +// FF round_challenge_1 = 2; +// FF expected_val = expected_lo * (FF(1) - round_challenge_1) + expected_hi * round_challenge_1; + +// sumcheck.fold(sumcheck.folded_polynomials, multivariate_n >> 1, round_challenge_1); +// EXPECT_EQ(sumcheck.folded_polynomials[0][0], expected_val); +// } + +// TYPED_TEST(MultivariatesTests, FoldTwoRoundsGeneric) +// { +// using Flavor = TypeParam; +// using FF = typename Flavor::FF; +// using Transcript = honk::ProverTranscript; + +// const size_t multivariate_d(2); +// const size_t multivariate_n(1 << multivariate_d); + +// FF v00 = FF::random_element(); +// FF v10 = FF::random_element(); +// FF v01 = FF::random_element(); +// FF v11 = FF::random_element(); + +// std::array f0 = { v00, v10, v01, v11 }; + +// auto full_polynomials = std::array, 1>({ f0 }); +// auto transcript = Transcript::init_empty(); +// auto sumcheck = Sumcheck(multivariate_n, transcript); + +// FF round_challenge_0 = FF::random_element(); +// FF expected_lo = v00 * (FF(1) - round_challenge_0) + v10 * round_challenge_0; +// FF expected_hi = v01 * (FF(1) - round_challenge_0) + v11 * round_challenge_0; + +// sumcheck.fold(full_polynomials, multivariate_n, round_challenge_0); + +// EXPECT_EQ(sumcheck.folded_polynomials[0][0], expected_lo); +// EXPECT_EQ(sumcheck.folded_polynomials[0][1], expected_hi); + +// FF round_challenge_1 = FF::random_element(); +// FF expected_val = expected_lo * (FF(1) - round_challenge_1) + expected_hi * round_challenge_1; +// sumcheck.fold(sumcheck.folded_polynomials, multivariate_n >> 1, round_challenge_1); +// EXPECT_EQ(sumcheck.folded_polynomials[0][0], expected_val); +// } + +// /* +// * Similarly for a trivariate polynomial f0(X0, X1, X2), we have +// * f0(X0, X1, X2) = v000 * (1-X0) * (1-X1) * (1-X2) +// * + v100 * X0 * (1-X1) * (1-X2) +// * + v010 * (1-X0) * X1 * (1-X2) +// * + v110 * X0 * X1 * (1-X2) +// * + v001 * (1-X0) * (1-X1) * X2 +// * + v101 * X0 * (1-X1) * X2 +// * + v011 * (1-X0) * X1 * X2 +// * + v111 * X0 * X1 * X2. +// * After round 0 (round challenge u0), we have +// * f0(u0, X1, X2) = [v000 * (1-u0) + v100 * u0] * (1-X1) * (1-X2) +// * + [v010 * (1-u0) + v110 * u0] * X1 * (1-X2) +// * + [v001 * (1-u0) + v101 * u0] * (1-X1) * X2 +// * + [v011 * (1-u0) + v111 * u0] * X1 * X2. +// * After round 1 (round challenge u1), we have +// * f0(u0, u1, X2) = [(v000 * (1-u0) + v100 * u0) * (1-u1) + (v010 * (1-u0) + v110 * u0) * u1] * (1-X2) +// * + [(v001 * (1-u0) + v101 * u0) * (1-u1) + (v011 * (1-u0) + v111 * u0) * u1] * X2. +// * After round 2 (round challenge u2), we have +// * f0(u0, u1, u2) = [(v000 * (1-u0) + v100 * u0) * (1-u1) + (v010 * (1-u0) + v110 * u0) * u1] * (1-u2) +// * + [(v001 * (1-u0) + v101 * u0) * (1-u1) + (v011 * (1-u0) + v111 * u0) * u1] * u2. +// */ +// TYPED_TEST(MultivariatesTests, FoldThreeRoundsSpecial) +// { +// using Flavor = TypeParam; +// using FF = typename Flavor::FF; +// using Transcript = honk::ProverTranscript; + +// const size_t multivariate_d(3); +// const size_t multivariate_n(1 << multivariate_d); + +// FF v000 = 1; +// FF v100 = 2; +// FF v010 = 3; +// FF v110 = 4; +// FF v001 = 5; +// FF v101 = 6; +// FF v011 = 7; +// FF v111 = 8; + +// std::array f0 = { v000, v100, v010, v110, v001, v101, v011, v111 }; + +// auto full_polynomials = std::array, 1>({ f0 }); +// auto transcript = Transcript::init_empty(); +// auto sumcheck = Sumcheck(multivariate_n, transcript); + +// FF round_challenge_0 = 1; +// FF expected_q1 = v000 * (FF(1) - round_challenge_0) + v100 * round_challenge_0; // 2 +// FF expected_q2 = v010 * (FF(1) - round_challenge_0) + v110 * round_challenge_0; // 4 +// FF expected_q3 = v001 * (FF(1) - round_challenge_0) + v101 * round_challenge_0; // 6 +// FF expected_q4 = v011 * (FF(1) - round_challenge_0) + v111 * round_challenge_0; // 8 + +// sumcheck.fold(full_polynomials, multivariate_n, round_challenge_0); + +// EXPECT_EQ(sumcheck.folded_polynomials[0][0], expected_q1); +// EXPECT_EQ(sumcheck.folded_polynomials[0][1], expected_q2); +// EXPECT_EQ(sumcheck.folded_polynomials[0][2], expected_q3); +// EXPECT_EQ(sumcheck.folded_polynomials[0][3], expected_q4); + +// FF round_challenge_1 = 2; +// FF expected_lo = expected_q1 * (FF(1) - round_challenge_1) + expected_q2 * round_challenge_1; // 6 +// FF expected_hi = expected_q3 * (FF(1) - round_challenge_1) + expected_q4 * round_challenge_1; // 10 + +// sumcheck.fold(sumcheck.folded_polynomials, multivariate_n >> 1, round_challenge_1); +// EXPECT_EQ(sumcheck.folded_polynomials[0][0], expected_lo); +// EXPECT_EQ(sumcheck.folded_polynomials[0][1], expected_hi); + +// FF round_challenge_2 = 3; +// FF expected_val = expected_lo * (FF(1) - round_challenge_2) + expected_hi * round_challenge_2; // 18 +// sumcheck.fold(sumcheck.folded_polynomials, multivariate_n >> 2, round_challenge_2); +// EXPECT_EQ(sumcheck.folded_polynomials[0][0], expected_val); +// } + +// TYPED_TEST(MultivariatesTests, FoldThreeRoundsGeneric) +// { +// using Flavor = TypeParam; +// using FF = typename Flavor::FF; +// using Transcript = honk::ProverTranscript; + +// const size_t multivariate_d(3); +// const size_t multivariate_n(1 << multivariate_d); + +// FF v000 = FF::random_element(); +// FF v100 = FF::random_element(); +// FF v010 = FF::random_element(); +// FF v110 = FF::random_element(); +// FF v001 = FF::random_element(); +// FF v101 = FF::random_element(); +// FF v011 = FF::random_element(); +// FF v111 = FF::random_element(); + +// std::array f0 = { v000, v100, v010, v110, v001, v101, v011, v111 }; + +// auto full_polynomials = std::array, 1>({ f0 }); +// auto transcript = Transcript::init_empty(); +// auto sumcheck = Sumcheck(multivariate_n, transcript); + +// FF round_challenge_0 = FF::random_element(); +// FF expected_q1 = v000 * (FF(1) - round_challenge_0) + v100 * round_challenge_0; +// FF expected_q2 = v010 * (FF(1) - round_challenge_0) + v110 * round_challenge_0; +// FF expected_q3 = v001 * (FF(1) - round_challenge_0) + v101 * round_challenge_0; +// FF expected_q4 = v011 * (FF(1) - round_challenge_0) + v111 * round_challenge_0; + +// sumcheck.fold(full_polynomials, multivariate_n, round_challenge_0); + +// EXPECT_EQ(sumcheck.folded_polynomials[0][0], expected_q1); +// EXPECT_EQ(sumcheck.folded_polynomials[0][1], expected_q2); +// EXPECT_EQ(sumcheck.folded_polynomials[0][2], expected_q3); +// EXPECT_EQ(sumcheck.folded_polynomials[0][3], expected_q4); + +// FF round_challenge_1 = FF::random_element(); +// FF expected_lo = expected_q1 * (FF(1) - round_challenge_1) + expected_q2 * round_challenge_1; +// FF expected_hi = expected_q3 * (FF(1) - round_challenge_1) + expected_q4 * round_challenge_1; + +// sumcheck.fold(sumcheck.folded_polynomials, multivariate_n >> 1, round_challenge_1); +// EXPECT_EQ(sumcheck.folded_polynomials[0][0], expected_lo); +// EXPECT_EQ(sumcheck.folded_polynomials[0][1], expected_hi); + +// FF round_challenge_2 = FF::random_element(); +// FF expected_val = expected_lo * (FF(1) - round_challenge_2) + expected_hi * round_challenge_2; +// sumcheck.fold(sumcheck.folded_polynomials, multivariate_n >> 2, round_challenge_2); +// EXPECT_EQ(sumcheck.folded_polynomials[0][0], expected_val); +// } + +// TYPED_TEST(MultivariatesTests, FoldThreeRoundsGenericMultiplePolys) +// { +// using Flavor = TypeParam; +// using FF = typename Flavor::FF; +// using Transcript = honk::ProverTranscript; + +// const size_t multivariate_d(3); +// const size_t multivariate_n(1 << multivariate_d); +// std::array v000; +// std::array v100; +// std::array v010; +// std::array v110; +// std::array v001; +// std::array v101; +// std::array v011; +// std::array v111; + +// for (size_t i = 0; i < 3; i++) { +// v000[i] = FF::random_element(); +// v100[i] = FF::random_element(); +// v010[i] = FF::random_element(); +// v110[i] = FF::random_element(); +// v001[i] = FF::random_element(); +// v101[i] = FF::random_element(); +// v011[i] = FF::random_element(); +// v111[i] = FF::random_element(); +// } +// std::array f0 = { v000[0], v100[0], v010[0], v110[0], v001[0], v101[0], v011[0], v111[0] }; +// std::array f1 = { v000[1], v100[1], v010[1], v110[1], v001[1], v101[1], v011[1], v111[1] }; +// std::array f2 = { v000[2], v100[2], v010[2], v110[2], v001[2], v101[2], v011[2], v111[2] }; + +// auto full_polynomials = std::array, 3>{ f0, f1, f2 }; +// auto transcript = Transcript::init_empty(); +// auto sumcheck = Sumcheck(multivariate_n, transcript); + +// std::array expected_q1; +// std::array expected_q2; +// std::array expected_q3; +// std::array expected_q4; +// FF round_challenge_0 = FF::random_element(); +// for (size_t i = 0; i < 3; i++) { +// expected_q1[i] = v000[i] * (FF(1) - round_challenge_0) + v100[i] * round_challenge_0; +// expected_q2[i] = v010[i] * (FF(1) - round_challenge_0) + v110[i] * round_challenge_0; +// expected_q3[i] = v001[i] * (FF(1) - round_challenge_0) + v101[i] * round_challenge_0; +// expected_q4[i] = v011[i] * (FF(1) - round_challenge_0) + v111[i] * round_challenge_0; +// } + +// sumcheck.fold(full_polynomials, multivariate_n, round_challenge_0); +// for (size_t i = 0; i < 3; i++) { +// EXPECT_EQ(sumcheck.folded_polynomials[i][0], expected_q1[i]); +// EXPECT_EQ(sumcheck.folded_polynomials[i][1], expected_q2[i]); +// EXPECT_EQ(sumcheck.folded_polynomials[i][2], expected_q3[i]); +// EXPECT_EQ(sumcheck.folded_polynomials[i][3], expected_q4[i]); +// } + +// FF round_challenge_1 = FF::random_element(); +// std::array expected_lo; +// std::array expected_hi; +// for (size_t i = 0; i < 3; i++) { +// expected_lo[i] = expected_q1[i] * (FF(1) - round_challenge_1) + expected_q2[i] * round_challenge_1; +// expected_hi[i] = expected_q3[i] * (FF(1) - round_challenge_1) + expected_q4[i] * round_challenge_1; +// } +// sumcheck.fold(sumcheck.folded_polynomials, multivariate_n >> 1, round_challenge_1); +// for (size_t i = 0; i < 3; i++) { +// EXPECT_EQ(sumcheck.folded_polynomials[i][0], expected_lo[i]); +// EXPECT_EQ(sumcheck.folded_polynomials[i][1], expected_hi[i]); +// } +// FF round_challenge_2 = FF::random_element(); +// std::array expected_val; +// for (size_t i = 0; i < 3; i++) { +// expected_val[i] = expected_lo[i] * (FF(1) - round_challenge_2) + expected_hi[i] * round_challenge_2; +// } +// sumcheck.fold(sumcheck.folded_polynomials, multivariate_n >> 2, round_challenge_2); +// for (size_t i = 0; i < 3; i++) { +// EXPECT_EQ(sumcheck.folded_polynomials[i][0], expected_val[i]); +// } +// } + +// } // namespace test_sumcheck_polynomials diff --git a/cpp/src/barretenberg/honk/sumcheck/polynomials/pow.test.cpp b/cpp/src/barretenberg/honk/sumcheck/polynomials/pow.test.cpp index a8dd2f5ef3..2e2fe4a120 100644 --- a/cpp/src/barretenberg/honk/sumcheck/polynomials/pow.test.cpp +++ b/cpp/src/barretenberg/honk/sumcheck/polynomials/pow.test.cpp @@ -1,26 +1,26 @@ -#include "pow.hpp" -#include "barretenberg/honk/utils/power_polynomial.hpp" -#include "barretenberg/ecc/curves/bn254/fr.hpp" -#include +// #include "pow.hpp" +// #include "barretenberg/honk/utils/power_polynomial.hpp" +// #include "barretenberg/ecc/curves/bn254/fr.hpp" +// #include -namespace proof_system::honk::sumcheck::pow_test { +// namespace proof_system::honk::sumcheck::pow_test { -using FF = barretenberg::fr; +// using FF = barretenberg::fr; -TEST(SumcheckPow, FullPowConsistency) -{ - constexpr size_t d = 5; +// TEST(SumcheckPow, FullPowConsistency) +// { +// constexpr size_t d = 5; - FF zeta = FF::random_element(); - PowUnivariate pow_univariate(zeta); +// FF zeta = FF::random_element(); +// PowUnivariate pow_univariate(zeta); - std::array variables{}; - for (auto& u_i : variables) { - u_i = FF::random_element(); - pow_univariate.partially_evaluate(u_i); - } +// std::array variables{}; +// for (auto& u_i : variables) { +// u_i = FF::random_element(); +// pow_univariate.partially_evaluate(u_i); +// } - FF expected_eval = proof_system::honk::power_polynomial::evaluate(zeta, variables); - EXPECT_EQ(pow_univariate.partial_evaluation_constant, expected_eval); -} -} // namespace proof_system::honk::sumcheck::pow_test +// FF expected_eval = proof_system::honk::power_polynomial::evaluate(zeta, variables); +// EXPECT_EQ(pow_univariate.partial_evaluation_constant, expected_eval); +// } +// } // namespace proof_system::honk::sumcheck::pow_test diff --git a/cpp/src/barretenberg/honk/sumcheck/relations/arithmetic_relation.hpp b/cpp/src/barretenberg/honk/sumcheck/relations/arithmetic_relation.hpp index e7d095119c..74a0b733cc 100644 --- a/cpp/src/barretenberg/honk/sumcheck/relations/arithmetic_relation.hpp +++ b/cpp/src/barretenberg/honk/sumcheck/relations/arithmetic_relation.hpp @@ -12,6 +12,12 @@ template class ArithmeticRelation { // 1 + polynomial degree of this relation static constexpr size_t RELATION_LENGTH = 4; + static constexpr size_t NUM_CONSTRAINTS = 1; + static constexpr std::array CONSTRAINT_LENGTH = { 4 }; + + using RelationUnivariates = std::tuple>; + using RelationValues = std::array; + /** * @brief Expression for the StandardArithmetic gate. * @details The relation is defined as C(extended_edges(X)...) = @@ -22,7 +28,7 @@ template class ArithmeticRelation { * @param parameters contains beta, gamma, and public_input_delta, .... * @param scaling_factor optional term to scale the evaluation before adding to evals. */ - void add_edge_contribution(Univariate& evals, + void add_edge_contribution(RelationUnivariates& evals, const auto& extended_edges, const RelationParameters&, const FF& scaling_factor) const @@ -44,10 +50,10 @@ template class ArithmeticRelation { tmp += q_o * w_o; tmp += q_c; tmp *= scaling_factor; - evals += tmp; + std::get<0>(evals) += tmp; }; - void add_full_relation_value_contribution(FF& full_honk_relation_value, + void add_full_relation_value_contribution(RelationValues& full_honk_relation_value, const auto& purported_evaluations, const RelationParameters&) const { @@ -60,10 +66,10 @@ template class ArithmeticRelation { auto q_o = purported_evaluations.q_o; auto q_c = purported_evaluations.q_c; - full_honk_relation_value += w_l * (q_m * w_r + q_l); - full_honk_relation_value += q_r * w_r; - full_honk_relation_value += q_o * w_o; - full_honk_relation_value += q_c; + std::get<0>(full_honk_relation_value) += w_l * (q_m * w_r + q_l); + std::get<0>(full_honk_relation_value) += q_r * w_r; + std::get<0>(full_honk_relation_value) += q_o * w_o; + std::get<0>(full_honk_relation_value) += q_c; }; }; } // namespace proof_system::honk::sumcheck diff --git a/cpp/src/barretenberg/honk/sumcheck/relations/grand_product_computation_relation.hpp b/cpp/src/barretenberg/honk/sumcheck/relations/permutation_relation.hpp similarity index 75% rename from cpp/src/barretenberg/honk/sumcheck/relations/grand_product_computation_relation.hpp rename to cpp/src/barretenberg/honk/sumcheck/relations/permutation_relation.hpp index ff2bc0ea8f..3cbaa8c280 100644 --- a/cpp/src/barretenberg/honk/sumcheck/relations/grand_product_computation_relation.hpp +++ b/cpp/src/barretenberg/honk/sumcheck/relations/permutation_relation.hpp @@ -5,11 +5,18 @@ namespace proof_system::honk::sumcheck { -template class GrandProductComputationRelation { +template class PermutationRelation { public: // 1 + polynomial degree of this relation + // WORKTODO: change this in all relations to be MAX_CONSTRAINT_LENGTH or something? static constexpr size_t RELATION_LENGTH = 5; + static constexpr size_t NUM_CONSTRAINTS = 2; + static constexpr std::array CONSTRAINT_LENGTH = { 5, 3 }; + + using RelationUnivariates = std::tuple, Univariate>; + using RelationValues = std::array; + /** * @brief Compute contribution of the permutation relation for a given edge (internal function) * @@ -28,7 +35,7 @@ template class GrandProductComputationRelation { * @param parameters contains beta, gamma, and public_input_delta, .... * @param scaling_factor optional term to scale the evaluation before adding to evals. */ - inline void add_edge_contribution(Univariate& evals, + inline void add_edge_contribution(RelationUnivariates& evals, const auto& extended_edges, const RelationParameters& relation_parameters, const FF& scaling_factor) const @@ -37,29 +44,35 @@ template class GrandProductComputationRelation { const auto& gamma = relation_parameters.gamma; const auto& public_input_delta = relation_parameters.public_input_delta; - auto w_1 = UnivariateView(extended_edges.w_l); - auto w_2 = UnivariateView(extended_edges.w_r); - auto w_3 = UnivariateView(extended_edges.w_o); - auto sigma_1 = UnivariateView(extended_edges.sigma_1); - auto sigma_2 = UnivariateView(extended_edges.sigma_2); - auto sigma_3 = UnivariateView(extended_edges.sigma_3); - auto id_1 = UnivariateView(extended_edges.id_1); - auto id_2 = UnivariateView(extended_edges.id_2); - auto id_3 = UnivariateView(extended_edges.id_3); - auto z_perm = UnivariateView(extended_edges.z_perm); - auto z_perm_shift = UnivariateView(extended_edges.z_perm_shift); - auto lagrange_first = UnivariateView(extended_edges.lagrange_first); - auto lagrange_last = UnivariateView(extended_edges.lagrange_last); + auto w_1 = UnivariateView(extended_edges.w_l); + auto w_2 = UnivariateView(extended_edges.w_r); + auto w_3 = UnivariateView(extended_edges.w_o); + auto sigma_1 = UnivariateView(extended_edges.sigma_1); + auto sigma_2 = UnivariateView(extended_edges.sigma_2); + auto sigma_3 = UnivariateView(extended_edges.sigma_3); + auto id_1 = UnivariateView(extended_edges.id_1); + auto id_2 = UnivariateView(extended_edges.id_2); + auto id_3 = UnivariateView(extended_edges.id_3); + auto z_perm = UnivariateView(extended_edges.z_perm); + auto z_perm_shift = UnivariateView(extended_edges.z_perm_shift); + auto lagrange_first = UnivariateView(extended_edges.lagrange_first); + auto lagrange_last = UnivariateView(extended_edges.lagrange_last); // Contribution (1) - evals += (((z_perm + lagrange_first) * (w_1 + id_1 * beta + gamma) * (w_2 + id_2 * beta + gamma) * - (w_3 + id_3 * beta + gamma)) - - ((z_perm_shift + lagrange_last * public_input_delta) * (w_1 + sigma_1 * beta + gamma) * - (w_2 + sigma_2 * beta + gamma) * (w_3 + sigma_3 * beta + gamma))) * - scaling_factor; + std::get<0>(evals) += (((z_perm + lagrange_first) * (w_1 + id_1 * beta + gamma) * (w_2 + id_2 * beta + gamma) * + (w_3 + id_3 * beta + gamma)) - + ((z_perm_shift + lagrange_last * public_input_delta) * (w_1 + sigma_1 * beta + gamma) * + (w_2 + sigma_2 * beta + gamma) * (w_3 + sigma_3 * beta + gamma))) * + scaling_factor; + + auto z_perm_shift_ = UnivariateView(extended_edges.z_perm_shift); + auto lagrange_last_ = UnivariateView(extended_edges.lagrange_last); + + // Contribution (2) + std::get<1>(evals) += (lagrange_last_ * z_perm_shift_) * scaling_factor; }; - void add_full_relation_value_contribution(FF& full_honk_relation_value, + void add_full_relation_value_contribution(RelationValues& full_honk_relation_value, auto& purported_evaluations, const RelationParameters& relation_parameters) const { @@ -82,11 +95,13 @@ template class GrandProductComputationRelation { auto lagrange_last = purported_evaluations.lagrange_last; // Contribution (1) - full_honk_relation_value += + std::get<0>(full_honk_relation_value) += ((z_perm + lagrange_first) * (w_1 + beta * id_1 + gamma) * (w_2 + beta * id_2 + gamma) * (w_3 + beta * id_3 + gamma) - (z_perm_shift + lagrange_last * public_input_delta) * (w_1 + beta * sigma_1 + gamma) * (w_2 + beta * sigma_2 + gamma) * (w_3 + beta * sigma_3 + gamma)); + + std::get<1>(full_honk_relation_value) += lagrange_last * z_perm_shift; }; }; diff --git a/cpp/src/barretenberg/honk/sumcheck/relations/relation_consistency.test.cpp b/cpp/src/barretenberg/honk/sumcheck/relations/relation_consistency.test.cpp index be3cce9708..49192d87bd 100644 --- a/cpp/src/barretenberg/honk/sumcheck/relations/relation_consistency.test.cpp +++ b/cpp/src/barretenberg/honk/sumcheck/relations/relation_consistency.test.cpp @@ -4,8 +4,7 @@ #include "barretenberg/honk/flavor/standard.hpp" #include "relation.hpp" #include "arithmetic_relation.hpp" -#include "grand_product_initialization_relation.hpp" -#include "grand_product_computation_relation.hpp" +#include "permutation_relation.hpp" #include "../polynomials/univariate.hpp" #include "../polynomials/barycentric_data.hpp" @@ -16,8 +15,8 @@ #include using namespace proof_system::honk::sumcheck; /** - * We want to test if all three relations (namely, ArithmeticRelation, GrandProductComputationRelation, - * GrandProductInitializationRelation) provide correct contributions by manually computing their + * We want to test if all three relations (namely, ArithmeticRelation, PermutationRelation) + * provide correct contributions by manually computing their * contributions with deterministic and random inputs. The relations are supposed to work with * univariates (edges) of degree one (length 2) and spit out polynomials of corresponding degrees. We have * MAX_RELATION_LENGTH = 5, meaning the output of a relation can atmost be a degree 5 polynomial. Hence, @@ -38,9 +37,9 @@ class StandardRelationConsistency : public testing::Test { template using ExtendedEdges = typename Flavor::template ExtendedEdges; - // TODO(#225)(Adrian): Accept FULL_RELATION_LENGTH as a template parameter for this function only, so that the test - // can decide to which degree the polynomials must be extended. Possible accept an existing list of "edges" and - // extend them to the degree. + // TODO(#225)(Adrian): Accept FULL_RELATION_LENGTH as a template parameter for this function only, so that the + // test can decide to which degree the polynomials must be extended. Possible accept an existing list of + // "edges" and extend them to the degree. template static void compute_mock_extended_edges( ExtendedEdges& extended_edges, @@ -97,7 +96,8 @@ class StandardRelationConsistency : public testing::Test { /** * @brief Compute the evaluation of a `relation` in different ways, comparing it to the provided `expected_evals` * - * @details Check both `add_full_relation_value_contribution` and `add_edge_contribution` by comparing the result to + * @details Check both `add_full_relation_value_contribution` and `add_edge_contribution` by comparing the result + to * the `expected_evals` computed by the caller. * Ensures that the relations compute the same result as the expression given in the tests. * @@ -107,34 +107,74 @@ class StandardRelationConsistency : public testing::Test { * @param relation_parameters */ template - static void validate_evaluations(const Univariate& expected_evals, + static void validate_evaluations(const auto& expected_full_length_univariates, /* array of Univariates*/ const auto relation, const ExtendedEdges& extended_edges, const RelationParameters& relation_parameters) { + // First check that the verifier's computation on individual evaluations is correct. + // Note: it is sufficient to check at only the first index of the input edges. - // Compute the expression index-by-index - Univariate expected_evals_index{ 0 }; - for (size_t i = 0; i < FULL_RELATION_LENGTH; ++i) { - // Get an array of the same size as `extended_edges` with only the i-th element of each extended edge. - PurportedEvaluations evals_i = transposed_univariate_array_at(extended_edges, i); - // Evaluate the relation - relation.add_full_relation_value_contribution( - expected_evals_index.value_at(i), evals_i, relation_parameters); + // Extract the RelationValues type for the given relation + using RelationValues = typename decltype(relation)::RelationValues; + RelationValues relation_evals; + RelationValues expected_relation_evals; + + ASSERT_EQ(expected_relation_evals.size(), expected_full_length_univariates.size()); + // Initialize expected_evals to 0th coefficient of expected full length univariates + for (size_t idx = 0; idx < relation_evals.size(); ++idx) { + relation_evals[idx] = FF(0); // initialize to 0 + expected_relation_evals[idx] = expected_full_length_univariates[idx].value_at(0); } - EXPECT_EQ(expected_evals, expected_evals_index); - // Compute the expression using the class, that converts the extended edges to UnivariateView - auto expected_evals_view = Univariate(0); - // The scaling factor is essentially 1 since we are working with degree 1 univariates - relation.add_edge_contribution(expected_evals_view, extended_edges, relation_parameters, 1); + // Extract 0th evaluation from extended edges + PurportedEvaluations edge_evaluations = transposed_univariate_array_at(extended_edges, 0); - // Tiny hack to reduce `expected_evals` to be of size `relation.RELATION_LENGTH` - Univariate expected_evals_restricted{ - UnivariateView(expected_evals) - }; - EXPECT_EQ(expected_evals_restricted, expected_evals_view); + // Evaluate the relation using the verifier functionality + relation.add_full_relation_value_contribution(relation_evals, edge_evaluations, relation_parameters); + + EXPECT_EQ(relation_evals, expected_relation_evals); + + // Next, check that the prover's computation on Univariates is correct + + using RelationUnivariates = typename decltype(relation)::RelationUnivariates; + RelationUnivariates relation_univariates; + zero_univariates<>(relation_univariates); + + constexpr std::size_t num_univariates = std::tuple_size::value; + + // Compute the relatiion univariates via the sumcheck prover functionality, then extend + // them to full length for easy comparison with the expected result. + relation.add_edge_contribution(relation_univariates, extended_edges, relation_parameters, 1); + + auto full_length_univariates = std::array, num_univariates>(); + extend_tuple_of_arrays(relation_univariates, full_length_univariates); + + EXPECT_EQ(full_length_univariates, expected_full_length_univariates); }; + + template static void zero_univariates(std::tuple& tuple) + { + auto& element = std::get(tuple); + std::fill(element.evaluations.begin(), element.evaluations.end(), FF(0)); + + if constexpr (idx + 1 < sizeof...(Ts)) { + zero_univariates(tuple); + } + } + + template + static void extend_tuple_of_arrays(std::tuple& tuple, auto& result_univariates) + { + auto& element = std::get(tuple); + using Element = std::remove_reference_t; + BarycentricData barycentric_utils; + result_univariates[idx] = barycentric_utils.extend(element); + + if constexpr (idx + 1 < sizeof...(Ts)) { + extend_tuple_of_arrays(tuple, result_univariates); + } + } }; TEST_F(StandardRelationConsistency, ArithmeticRelation) @@ -174,17 +214,18 @@ TEST_F(StandardRelationConsistency, ArithmeticRelation) const auto& q_o = extended_edges.q_o; const auto& q_c = extended_edges.q_c; - // We first compute the evaluations using UnivariateViews, with the provided hard-coded formula. - // Ensure that expression changes are detected. - // expected_evals, length 4, extends to { { 5, 22, 57, 116, 205} } for input polynomial {1, 2} - auto expected_evals = (q_m * w_r * w_l) + (q_r * w_r) + (q_l * w_l) + (q_o * w_o) + (q_c); - validate_evaluations(expected_evals, relation, extended_edges, relation_parameters); + // Compute expected full length Univariates using straight forward expressions. + // Note: expect { { 5, 22, 57, 116, 205} } for input polynomial {1, 2} + constexpr std::size_t NUM_CONSTRAINTS = decltype(relation)::NUM_CONSTRAINTS; + auto expected_full_length_univariates = std::array, NUM_CONSTRAINTS>(); + expected_full_length_univariates[0] = (q_m * w_r * w_l) + (q_r * w_r) + (q_l * w_l) + (q_o * w_o) + (q_c); + validate_evaluations(expected_full_length_univariates, relation, extended_edges, relation_parameters); }; run_test(/* is_random_input=*/true); run_test(/* is_random_input=*/false); }; -TEST_F(StandardRelationConsistency, GrandProductComputationRelation) +TEST_F(StandardRelationConsistency, PermutationRelation) { using Flavor = honk::flavor::Standard; using FF = typename Flavor::FF; @@ -210,16 +251,11 @@ TEST_F(StandardRelationConsistency, GrandProductComputationRelation) } compute_mock_extended_edges(extended_edges, input_polynomials); }; - auto relation = GrandProductComputationRelation(); + auto relation = PermutationRelation(); const auto& beta = relation_parameters.beta; const auto& gamma = relation_parameters.gamma; const auto& public_input_delta = relation_parameters.public_input_delta; - // TODO(#225)(luke): Write a test that illustrates the following? - // Note: the below z_perm_shift = X^2 will fail because it results in a relation of degree 2*1*1*1 = 5 which - // cannot be represented by 5 points. Therefore when we do the calculation then barycentrically extend, we are - // effectively exprapolating a 4th degree polynomial instead of the correct 5th degree poly - // auto z_perm_shift = Univariate({ 1, 4, 9, 16, 25 }); // X^2 // Manually compute the expected edge contribution const auto& w_1 = extended_edges.w_l; @@ -236,58 +272,62 @@ TEST_F(StandardRelationConsistency, GrandProductComputationRelation) const auto& lagrange_first = extended_edges.lagrange_first; const auto& lagrange_last = extended_edges.lagrange_last; - // We first compute the evaluations using UnivariateViews, with the provided hard-coded formula. - // Ensure that expression changes are detected. - // expected_evals in the below step { { 27, 250, 1029, 2916, 6655 } } - { { 27, 125, 343, 729, 1331 } } - auto expected_evals = (z_perm + lagrange_first) * (w_1 + id_1 * beta + gamma) * (w_2 + id_2 * beta + gamma) * - (w_3 + id_3 * beta + gamma) - - (z_perm_shift + lagrange_last * public_input_delta) * (w_1 + sigma_1 * beta + gamma) * - (w_2 + sigma_2 * beta + gamma) * (w_3 + sigma_3 * beta + gamma); + // Compute expected full length Univariates using straight forward expressions + constexpr std::size_t NUM_CONSTRAINTS = decltype(relation)::NUM_CONSTRAINTS; + auto expected_full_length_univariates = std::array, NUM_CONSTRAINTS>(); + + expected_full_length_univariates[0] = (z_perm + lagrange_first) * (w_1 + id_1 * beta + gamma) * + (w_2 + id_2 * beta + gamma) * (w_3 + id_3 * beta + gamma) - + (z_perm_shift + lagrange_last * public_input_delta) * + (w_1 + sigma_1 * beta + gamma) * (w_2 + sigma_2 * beta + gamma) * + (w_3 + sigma_3 * beta + gamma); - validate_evaluations(expected_evals, relation, extended_edges, relation_parameters); + expected_full_length_univariates[1] = z_perm_shift * lagrange_last; + + validate_evaluations(expected_full_length_univariates, relation, extended_edges, relation_parameters); }; run_test(/* is_random_input=*/true); run_test(/* is_random_input=*/false); }; -TEST_F(StandardRelationConsistency, GrandProductInitializationRelation) -{ - using Flavor = honk::flavor::Standard; - using FF = typename Flavor::FF; - static constexpr size_t FULL_RELATION_LENGTH = 5; - using ExtendedEdges = typename Flavor::template ExtendedEdges; - static const size_t NUM_POLYNOMIALS = Flavor::NUM_ALL_ENTITIES; +// TEST_F(StandardRelationConsistency, GrandProductInitializationRelation) +// { +// using Flavor = honk::flavor::Standard; +// using FF = typename Flavor::FF; +// static constexpr size_t FULL_RELATION_LENGTH = 5; +// using ExtendedEdges = typename Flavor::template ExtendedEdges; +// static const size_t NUM_POLYNOMIALS = Flavor::NUM_ALL_ENTITIES; - const auto relation_parameters = compute_mock_relation_parameters(); - auto run_test = [&relation_parameters](bool is_random_input) { - ExtendedEdges extended_edges; - std::array, NUM_POLYNOMIALS> input_polynomials; - if (!is_random_input) { - // evaluation form, i.e. input_univariate(0) = 1, input_univariate(1) = 2,.. The polynomial is x+1. - for (size_t i = 0; i < NUM_POLYNOMIALS; ++i) { - input_polynomials[i] = Univariate({ 1, 2 }); - } - compute_mock_extended_edges(extended_edges, input_polynomials); - } else { - // input_univariates are random polynomials of degree one - for (size_t i = 0; i < NUM_POLYNOMIALS; ++i) { - input_polynomials[i] = - Univariate({ FF::random_element(), FF::random_element() }); - } - compute_mock_extended_edges(extended_edges, input_polynomials); - }; - auto relation = GrandProductInitializationRelation(); - const auto& z_perm_shift = extended_edges.z_perm_shift; - const auto& lagrange_last = extended_edges.lagrange_last; - // We first compute the evaluations using UnivariateViews, with the provided hard-coded formula. - // Ensure that expression changes are detected. - // expected_evals, lenght 3 (coeff form = x^2 + x), extends to { { 0, 2, 6, 12, 20 } } - auto expected_evals = z_perm_shift * lagrange_last; +// const auto relation_parameters = compute_mock_relation_parameters(); +// auto run_test = [&relation_parameters](bool is_random_input) { +// ExtendedEdges extended_edges; +// std::array, NUM_POLYNOMIALS> input_polynomials; +// if (!is_random_input) { +// // evaluation form, i.e. input_univariate(0) = 1, input_univariate(1) = 2,.. The polynomial is x+1. +// for (size_t i = 0; i < NUM_POLYNOMIALS; ++i) { +// input_polynomials[i] = Univariate({ 1, 2 }); +// } +// compute_mock_extended_edges(extended_edges, input_polynomials); +// } else { +// // input_univariates are random polynomials of degree one +// for (size_t i = 0; i < NUM_POLYNOMIALS; ++i) { +// input_polynomials[i] = +// Univariate({ FF::random_element(), FF::random_element() }); +// } +// compute_mock_extended_edges(extended_edges, input_polynomials); +// }; +// auto relation = GrandProductInitializationRelation(); +// const auto& z_perm_shift = extended_edges.z_perm_shift; +// const auto& lagrange_last = extended_edges.lagrange_last; +// // We first compute the evaluations using UnivariateViews, with the provided hard-coded formula. +// // Ensure that expression changes are detected. +// // expected_evals, lenght 3 (coeff form = x^2 + x), extends to { { 0, 2, 6, 12, 20 } } +// auto expected_evals = z_perm_shift * lagrange_last; - validate_evaluations(expected_evals, relation, extended_edges, relation_parameters); - }; - run_test(/* is_random_input=*/true); - run_test(/* is_random_input=*/false); -}; +// validate_evaluations(expected_evals, relation, extended_edges, relation_parameters); +// }; +// run_test(/* is_random_input=*/true); +// run_test(/* is_random_input=*/false); +// }; } // namespace proof_system::honk_relation_tests diff --git a/cpp/src/barretenberg/honk/sumcheck/relations/relation_correctness.test.cpp b/cpp/src/barretenberg/honk/sumcheck/relations/relation_correctness.test.cpp index d9b1bc3a3e..b424ff172f 100644 --- a/cpp/src/barretenberg/honk/sumcheck/relations/relation_correctness.test.cpp +++ b/cpp/src/barretenberg/honk/sumcheck/relations/relation_correctness.test.cpp @@ -5,8 +5,7 @@ #include "barretenberg/honk/proof_system/prover_library.hpp" #include "barretenberg/honk/sumcheck/relations/relation.hpp" #include "barretenberg/honk/sumcheck/relations/arithmetic_relation.hpp" -#include "barretenberg/honk/sumcheck/relations/grand_product_initialization_relation.hpp" -#include "barretenberg/honk/sumcheck/relations/grand_product_computation_relation.hpp" +#include "barretenberg/honk/sumcheck/relations/permutation_relation.hpp" #include "barretenberg/honk/sumcheck/relations/ultra_arithmetic_relation.hpp" #include "barretenberg/honk/sumcheck/relations/ultra_arithmetic_relation_secondary.hpp" #include "barretenberg/honk/sumcheck/relations/lookup_grand_product_relation.hpp" @@ -28,146 +27,63 @@ void ensure_non_zero(auto& polynomial) } /** - * @brief Test the correctness of the Standard Honk relations - * - * @details Check that the constraints encoded by the relations are satisfied by the polynomials produced by the - * Standard Honk Composer for a real circuit. - * - * TODO(Kesha): We'll have to update this function once we add zk, since the relation will be incorrect for he first few - * indices + * @brief Check that a given relation is satified for a set of polynomials * + * @tparam relation_idx Index into a tuple of provided relations + * @tparam Flavor */ -TEST(RelationCorrectness, StandardRelationCorrectness) +// WORKTODO: pass single relation instead of all of them? +template +void check_relation(auto relations, auto circuit_size, auto polynomials, auto params) { - using Flavor = honk::flavor::Standard; - using FF = typename Flavor::FF; - using ProverPolynomials = typename Flavor::ProverPolynomials; using PurportedEvaluations = typename Flavor::PurportedEvaluations; + for (size_t i = 0; i < circuit_size; i++) { - // Create a composer and a dummy circuit with a few gates - auto composer = StandardHonkComposer(); - fr a = fr::one(); - // Using the public variable to check that public_input_delta is computed and added to the relation correctly - uint32_t a_idx = composer.add_public_variable(a); - fr b = fr::one(); - fr c = a + b; - fr d = a + c; - uint32_t b_idx = composer.add_variable(b); - uint32_t c_idx = composer.add_variable(c); - uint32_t d_idx = composer.add_variable(d); - for (size_t i = 0; i < 16; i++) { - composer.create_add_gate({ a_idx, b_idx, c_idx, fr::one(), fr::one(), fr::neg_one(), fr::zero() }); - composer.create_add_gate({ d_idx, c_idx, a_idx, fr::one(), fr::neg_one(), fr::neg_one(), fr::zero() }); - } - // Create a prover (it will compute proving key and witness) - auto prover = composer.create_prover(); - - // Generate beta and gamma - fr beta = fr::random_element(); - fr gamma = fr::random_element(); - - // Compute public input delta - const auto public_inputs = composer.circuit_constructor.get_public_inputs(); - auto public_input_delta = - honk::compute_public_input_delta(public_inputs, beta, gamma, prover.key->circuit_size); - - sumcheck::RelationParameters params{ - .beta = beta, - .gamma = gamma, - .public_input_delta = public_input_delta, - }; - - // Compute grand product polynomial - polynomial z_permutation = - prover_library::compute_permutation_grand_product(prover.key, beta, gamma); - - // Create an array of spans to the underlying polynomials to more easily - // get the transposition. - // Ex: polynomial_spans[3][i] returns the i-th coefficient of the third polynomial - // in the list below - ProverPolynomials prover_polynomials; - - prover_polynomials.w_l = prover.key->w_l; - prover_polynomials.w_r = prover.key->w_r; - prover_polynomials.w_o = prover.key->w_o; - prover_polynomials.z_perm = z_permutation; - prover_polynomials.z_perm_shift = z_permutation.shifted(); - prover_polynomials.q_m = prover.key->q_m; - prover_polynomials.q_l = prover.key->q_l; - prover_polynomials.q_r = prover.key->q_r; - prover_polynomials.q_o = prover.key->q_o; - prover_polynomials.q_c = prover.key->q_c; - prover_polynomials.sigma_1 = prover.key->sigma_1; - prover_polynomials.sigma_2 = prover.key->sigma_2; - prover_polynomials.sigma_3 = prover.key->sigma_3; - prover_polynomials.id_1 = prover.key->id_1; - prover_polynomials.id_2 = prover.key->id_2; - prover_polynomials.id_3 = prover.key->id_3; - prover_polynomials.lagrange_first = prover.key->lagrange_first; - prover_polynomials.lagrange_last = prover.key->lagrange_last; - - // Construct the round for applying sumcheck relations and results for storing computed results - auto relations = std::tuple(honk::sumcheck::ArithmeticRelation(), - honk::sumcheck::GrandProductComputationRelation(), - honk::sumcheck::GrandProductInitializationRelation()); - - fr result = 0; - for (size_t i = 0; i < prover.key->circuit_size; i++) { - // Compute an array containing all the evaluations at a given row i - + // Extract an array containing all the polynomial evaluations at a given row i PurportedEvaluations evaluations_at_index_i; size_t poly_idx = 0; - for (auto& polynomial : prover_polynomials) { - evaluations_at_index_i[poly_idx] = polynomial[i]; + for (auto& poly : polynomials) { + evaluations_at_index_i[poly_idx] = poly[i]; ++poly_idx; } - // For each relation, call the `accumulate_relation_evaluation` over all witness/selector values at the - // i-th row/vertex of the hypercube. - // We use ASSERT_EQ instead of EXPECT_EQ so that the tests stops at the first index at which the result is not - // 0, since result = 0 + C(transposed), which we expect will equal 0. - std::get<0>(relations).add_full_relation_value_contribution(result, evaluations_at_index_i, params); - ASSERT_EQ(result, 0); - - std::get<1>(relations).add_full_relation_value_contribution(result, evaluations_at_index_i, params); - ASSERT_EQ(result, 0); + // Define the appropriate RelationValues type for this relation and initialize to zero + using RelationValues = typename std::tuple_element::type::RelationValues; + RelationValues result; + for (auto& element : result) { + element = 0; + } - std::get<2>(relations).add_full_relation_value_contribution(result, evaluations_at_index_i, params); - ASSERT_EQ(result, 0); + // Evaluate each constraint in the relation and check that each is satisfied + std::get(relations).add_full_relation_value_contribution(result, evaluations_at_index_i, params); + for (auto& element : result) { + ASSERT_EQ(element, 0); + } } } /** - * @brief Test the correctness of the Ultra Honk relations + * @brief Test the correctness of the Standard Honk relations * * @details Check that the constraints encoded by the relations are satisfied by the polynomials produced by the - * Ultra Honk Composer for a real circuit. + * Standard Honk Composer for a real circuit. * - * TODO(Kesha): We'll have to update this function once we add zk, since the relation will be incorrect for he first few + * TODO(Kesha): We'll have to update this function once we add zk, since the relation will be incorrect for he first + few * indices * */ -// TODO(luke): possibly make circuit construction one or many functions to clarify the individual components -// TODO(luke): Add a gate that sets q_arith = 3 to check secondary arithmetic relation -TEST(RelationCorrectness, UltraRelationCorrectness) +TEST(RelationCorrectness, StandardRelationCorrectness) { - using Flavor = honk::flavor::Ultra; + using Flavor = honk::flavor::Standard; using FF = typename Flavor::FF; using ProverPolynomials = typename Flavor::ProverPolynomials; - using PurportedEvaluations = typename Flavor::PurportedEvaluations; - // Create a composer and then add an assortment of gates designed to ensure that the constraint(s) represented - // by each relation are non-trivially exercised. - auto composer = UltraHonkComposer(); - - barretenberg::fr pedersen_input_value = fr::random_element(); + // Create a composer and a dummy circuit with a few gates + auto composer = StandardHonkComposer(); fr a = fr::one(); // Using the public variable to check that public_input_delta is computed and added to the relation correctly - // TODO(luke): add method "add_public_variable" to UH composer - // uint32_t a_idx = composer.add_public_variable(a); - - // Add some basic add gates - uint32_t a_idx = composer.add_variable(a); + uint32_t a_idx = composer.add_public_variable(a); fr b = fr::one(); fr c = a + b; fr d = a + c; @@ -175,109 +91,14 @@ TEST(RelationCorrectness, UltraRelationCorrectness) uint32_t c_idx = composer.add_variable(c); uint32_t d_idx = composer.add_variable(d); for (size_t i = 0; i < 16; i++) { - composer.create_add_gate({ a_idx, b_idx, c_idx, 1, 1, -1, 0 }); - composer.create_add_gate({ d_idx, c_idx, a_idx, 1, -1, -1, 0 }); - } - - // Add a big add gate with use of next row to test q_arith = 2 - fr e = a + b + c + d; - uint32_t e_idx = composer.add_variable(e); - - uint32_t zero_idx = composer.get_zero_idx(); - composer.create_big_add_gate({ a_idx, b_idx, c_idx, d_idx, -1, -1, -1, -1, 0 }, true); // use next row - composer.create_big_add_gate({ zero_idx, zero_idx, zero_idx, e_idx, 0, 0, 0, 0, 0 }, false); - - // Add some lookup gates (related to pedersen hashing) - const fr input_hi = uint256_t(pedersen_input_value).slice(126, 256); - const fr input_lo = uint256_t(pedersen_input_value).slice(0, 126); - const auto input_hi_index = composer.add_variable(input_hi); - const auto input_lo_index = 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); - - composer.create_gates_from_plookup_accumulators( - plookup::MultiTableId::PEDERSEN_LEFT_HI, sequence_data_hi, input_hi_index); - composer.create_gates_from_plookup_accumulators( - plookup::MultiTableId::PEDERSEN_LEFT_LO, sequence_data_lo, input_lo_index); - - // Add a sort gate (simply checks that consecutive inputs have a difference of < 4) - a_idx = composer.add_variable(FF(0)); - b_idx = composer.add_variable(FF(1)); - c_idx = composer.add_variable(FF(2)); - d_idx = composer.add_variable(FF(3)); - composer.create_sort_constraint({ a_idx, b_idx, c_idx, d_idx }); - - // Add an elliptic curve addition gate - grumpkin::g1::affine_element p1 = crypto::generators::get_generator_data({ 0, 0 }).generator; - grumpkin::g1::affine_element p2 = crypto::generators::get_generator_data({ 0, 1 }).generator; - - grumpkin::fq beta_scalar = grumpkin::fq::cube_root_of_unity(); - grumpkin::g1::affine_element p2_endo = p2; - p2_endo.x *= beta_scalar; - - grumpkin::g1::affine_element p3(grumpkin::g1::element(p1) - grumpkin::g1::element(p2_endo)); - - uint32_t x1 = composer.add_variable(p1.x); - uint32_t y1 = composer.add_variable(p1.y); - uint32_t x2 = composer.add_variable(p2.x); - uint32_t y2 = composer.add_variable(p2.y); - uint32_t x3 = composer.add_variable(p3.x); - uint32_t y3 = composer.add_variable(p3.y); - - ecc_add_gate gate{ x1, y1, x2, y2, x3, y3, beta_scalar, -1 }; - composer.create_ecc_add_gate(gate); - - // Add some RAM gates - uint32_t ram_values[8]{ - composer.add_variable(fr::random_element()), composer.add_variable(fr::random_element()), - composer.add_variable(fr::random_element()), composer.add_variable(fr::random_element()), - composer.add_variable(fr::random_element()), composer.add_variable(fr::random_element()), - composer.add_variable(fr::random_element()), composer.add_variable(fr::random_element()), - }; - - size_t ram_id = composer.create_RAM_array(8); - - for (size_t i = 0; i < 8; ++i) { - composer.init_RAM_element(ram_id, i, ram_values[i]); + composer.create_add_gate({ a_idx, b_idx, c_idx, fr::one(), fr::one(), fr::neg_one(), fr::zero() }); + composer.create_add_gate({ d_idx, c_idx, a_idx, fr::one(), fr::neg_one(), fr::neg_one(), fr::zero() }); } - - a_idx = composer.read_RAM_array(ram_id, composer.add_variable(5)); - EXPECT_EQ(a_idx != ram_values[5], true); - - b_idx = composer.read_RAM_array(ram_id, composer.add_variable(4)); - c_idx = composer.read_RAM_array(ram_id, composer.add_variable(1)); - - composer.write_RAM_array(ram_id, composer.add_variable(4), composer.add_variable(500)); - d_idx = composer.read_RAM_array(ram_id, composer.add_variable(4)); - - EXPECT_EQ(composer.get_variable(d_idx), 500); - - // ensure these vars get used in another arithmetic gate - const auto e_value = composer.get_variable(a_idx) + composer.get_variable(b_idx) + composer.get_variable(c_idx) + - composer.get_variable(d_idx); - e_idx = composer.add_variable(e_value); - - composer.create_big_add_gate({ a_idx, b_idx, c_idx, d_idx, -1, -1, -1, -1, 0 }, true); - composer.create_big_add_gate( - { - composer.get_zero_idx(), - composer.get_zero_idx(), - composer.get_zero_idx(), - e_idx, - 0, - 0, - 0, - 0, - 0, - }, - false); - // Create a prover (it will compute proving key and witness) auto prover = composer.create_prover(); + auto circuit_size = prover.key->circuit_size; - // Generate eta, beta and gamma - fr eta = fr::random_element(); + // Generate beta and gamma fr beta = fr::random_element(); fr gamma = fr::random_element(); @@ -285,28 +106,16 @@ TEST(RelationCorrectness, UltraRelationCorrectness) const auto public_inputs = composer.circuit_constructor.get_public_inputs(); auto public_input_delta = honk::compute_public_input_delta(public_inputs, beta, gamma, prover.key->circuit_size); - auto lookup_grand_product_delta = - honk::compute_lookup_grand_product_delta(beta, gamma, prover.key->circuit_size); sumcheck::RelationParameters params{ - .eta = eta, .beta = beta, .gamma = gamma, .public_input_delta = public_input_delta, - .lookup_grand_product_delta = lookup_grand_product_delta, }; - // Compute sorted witness-table accumulator - prover.key->sorted_accum = prover_library::compute_sorted_list_accumulator(prover.key, eta); - - // Add RAM/ROM memory records to wire four - prover_library::add_plookup_memory_records_to_wire_4(prover.key, eta); - // Compute grand product polynomial - prover.key->z_perm = prover_library::compute_permutation_grand_product(prover.key, beta, gamma); - - // Compute lookup grand product polynomial - prover.key->z_lookup = prover_library::compute_lookup_grand_product(prover.key, eta, beta, gamma); + polynomial z_permutation = + prover_library::compute_permutation_grand_product(prover.key, beta, gamma); // Create an array of spans to the underlying polynomials to more easily // get the transposition. @@ -317,106 +126,312 @@ TEST(RelationCorrectness, UltraRelationCorrectness) prover_polynomials.w_l = prover.key->w_l; prover_polynomials.w_r = prover.key->w_r; prover_polynomials.w_o = prover.key->w_o; - prover_polynomials.w_4 = prover.key->w_4; - prover_polynomials.w_l_shift = prover.key->w_l.shifted(); - prover_polynomials.w_r_shift = prover.key->w_r.shifted(); - prover_polynomials.w_o_shift = prover.key->w_o.shifted(); - prover_polynomials.w_4_shift = prover.key->w_4.shifted(); - prover_polynomials.sorted_accum = prover.key->sorted_accum; - prover_polynomials.sorted_accum_shift = prover.key->sorted_accum.shifted(); - prover_polynomials.table_1 = prover.key->table_1; - prover_polynomials.table_2 = prover.key->table_2; - prover_polynomials.table_3 = prover.key->table_3; - prover_polynomials.table_4 = prover.key->table_4; - prover_polynomials.table_1_shift = prover.key->table_1.shifted(); - prover_polynomials.table_2_shift = prover.key->table_2.shifted(); - prover_polynomials.table_3_shift = prover.key->table_3.shifted(); - prover_polynomials.table_4_shift = prover.key->table_4.shifted(); - prover_polynomials.z_perm = prover.key->z_perm; - prover_polynomials.z_perm_shift = prover.key->z_perm.shifted(); - prover_polynomials.z_lookup = prover.key->z_lookup; - prover_polynomials.z_lookup_shift = prover.key->z_lookup.shifted(); + prover_polynomials.z_perm = z_permutation; + prover_polynomials.z_perm_shift = z_permutation.shifted(); prover_polynomials.q_m = prover.key->q_m; prover_polynomials.q_l = prover.key->q_l; prover_polynomials.q_r = prover.key->q_r; prover_polynomials.q_o = prover.key->q_o; prover_polynomials.q_c = prover.key->q_c; - prover_polynomials.q_4 = prover.key->q_4; - prover_polynomials.q_arith = prover.key->q_arith; - prover_polynomials.q_sort = prover.key->q_sort; - prover_polynomials.q_elliptic = prover.key->q_elliptic; - prover_polynomials.q_aux = prover.key->q_aux; - prover_polynomials.q_lookup = prover.key->q_lookup; prover_polynomials.sigma_1 = prover.key->sigma_1; prover_polynomials.sigma_2 = prover.key->sigma_2; prover_polynomials.sigma_3 = prover.key->sigma_3; - prover_polynomials.sigma_4 = prover.key->sigma_4; prover_polynomials.id_1 = prover.key->id_1; prover_polynomials.id_2 = prover.key->id_2; prover_polynomials.id_3 = prover.key->id_3; - prover_polynomials.id_4 = prover.key->id_4; prover_polynomials.lagrange_first = prover.key->lagrange_first; prover_polynomials.lagrange_last = prover.key->lagrange_last; - // Check that selectors are nonzero to ensure corresponding relation has nontrivial contribution - ensure_non_zero(prover.key->q_arith); - ensure_non_zero(prover.key->q_sort); - ensure_non_zero(prover.key->q_lookup); - ensure_non_zero(prover.key->q_elliptic); - ensure_non_zero(prover.key->q_aux); - // Construct the round for applying sumcheck relations and results for storing computed results - auto relations = std::tuple(honk::sumcheck::UltraArithmeticRelation(), - honk::sumcheck::UltraArithmeticRelationSecondary(), - honk::sumcheck::UltraGrandProductInitializationRelation(), - honk::sumcheck::UltraGrandProductComputationRelation(), - honk::sumcheck::LookupGrandProductComputationRelation(), - honk::sumcheck::LookupGrandProductInitializationRelation(), - honk::sumcheck::GenPermSortRelation(), - honk::sumcheck::EllipticRelation(), - honk::sumcheck::AuxiliaryRelation()); - - fr result = 0; - for (size_t i = 0; i < prover.key->circuit_size; i++) { - // Compute an array containing all the evaluations at a given row i - PurportedEvaluations evaluations_at_index_i; - size_t poly_idx = 0; - for (auto& polynomial : prover_polynomials) { - evaluations_at_index_i[poly_idx] = polynomial[i]; - ++poly_idx; - } - - // For each relation, call the `accumulate_relation_evaluation` over all witness/selector values at the - // i-th row/vertex of the hypercube. We use ASSERT_EQ instead of EXPECT_EQ so that the tests stops at - // the first index at which the result is not 0, since result = 0 + C(transposed), which we expect will - // equal 0. - std::get<0>(relations).add_full_relation_value_contribution(result, evaluations_at_index_i, params); - ASSERT_EQ(result, 0); - - std::get<1>(relations).add_full_relation_value_contribution(result, evaluations_at_index_i, params); - ASSERT_EQ(result, 0); - - std::get<2>(relations).add_full_relation_value_contribution(result, evaluations_at_index_i, params); - ASSERT_EQ(result, 0); + auto relations = std::tuple(honk::sumcheck::ArithmeticRelation(), honk::sumcheck::PermutationRelation()); - std::get<3>(relations).add_full_relation_value_contribution(result, evaluations_at_index_i, params); - ASSERT_EQ(result, 0); - - std::get<4>(relations).add_full_relation_value_contribution(result, evaluations_at_index_i, params); - ASSERT_EQ(result, 0); - - std::get<5>(relations).add_full_relation_value_contribution(result, evaluations_at_index_i, params); - ASSERT_EQ(result, 0); - - std::get<6>(relations).add_full_relation_value_contribution(result, evaluations_at_index_i, params); - ASSERT_EQ(result, 0); - - std::get<7>(relations).add_full_relation_value_contribution(result, evaluations_at_index_i, params); - ASSERT_EQ(result, 0); - - std::get<8>(relations).add_full_relation_value_contribution(result, evaluations_at_index_i, params); - ASSERT_EQ(result, 0); - } + // Check that each relation is satisfied across each row of the prover polynomials + check_relation<0, Flavor>(relations, circuit_size, prover_polynomials, params); + check_relation<1, Flavor>(relations, circuit_size, prover_polynomials, params); } +// /** +// * @brief Test the correctness of the Ultra Honk relations +// * +// * @details Check that the constraints encoded by the relations are satisfied by the polynomials produced by the +// * Ultra Honk Composer for a real circuit. +// * +// * TODO(Kesha): We'll have to update this function once we add zk, since the relation will be incorrect for he first +// few +// * indices +// * +// */ +// // TODO(luke): possibly make circuit construction one or many functions to clarify the individual components +// // TODO(luke): Add a gate that sets q_arith = 3 to check secondary arithmetic relation +// TEST(RelationCorrectness, UltraRelationCorrectness) +// { +// using Flavor = honk::flavor::Ultra; +// using FF = typename Flavor::FF; +// using ProverPolynomials = typename Flavor::ProverPolynomials; +// using PurportedEvaluations = typename Flavor::PurportedEvaluations; + +// // Create a composer and then add an assortment of gates designed to ensure that the constraint(s) represented +// // by each relation are non-trivially exercised. +// auto composer = UltraHonkComposer(); + +// barretenberg::fr pedersen_input_value = fr::random_element(); +// fr a = fr::one(); +// // Using the public variable to check that public_input_delta is computed and added to the relation correctly +// // TODO(luke): add method "add_public_variable" to UH composer +// // uint32_t a_idx = composer.add_public_variable(a); + +// // Add some basic add gates +// uint32_t a_idx = composer.add_variable(a); +// fr b = fr::one(); +// fr c = a + b; +// fr d = a + c; +// uint32_t b_idx = composer.add_variable(b); +// uint32_t c_idx = composer.add_variable(c); +// uint32_t d_idx = composer.add_variable(d); +// for (size_t i = 0; i < 16; i++) { +// composer.create_add_gate({ a_idx, b_idx, c_idx, 1, 1, -1, 0 }); +// composer.create_add_gate({ d_idx, c_idx, a_idx, 1, -1, -1, 0 }); +// } + +// // // Add a big add gate with use of next row to test q_arith = 2 +// // fr e = a + b + c + d; +// // uint32_t e_idx = composer.add_variable(e); + +// // uint32_t zero_idx = composer.get_zero_idx(); +// // composer.create_big_add_gate({ a_idx, b_idx, c_idx, d_idx, -1, -1, -1, -1, 0 }, true); // use next row +// // composer.create_big_add_gate({ zero_idx, zero_idx, zero_idx, e_idx, 0, 0, 0, 0, 0 }, false); + +// // // Add some lookup gates (related to pedersen hashing) +// // const fr input_hi = uint256_t(pedersen_input_value).slice(126, 256); +// // const fr input_lo = uint256_t(pedersen_input_value).slice(0, 126); +// // const auto input_hi_index = composer.add_variable(input_hi); +// // const auto input_lo_index = 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); + +// // composer.create_gates_from_plookup_accumulators( +// // plookup::MultiTableId::PEDERSEN_LEFT_HI, sequence_data_hi, input_hi_index); +// // composer.create_gates_from_plookup_accumulators( +// // plookup::MultiTableId::PEDERSEN_LEFT_LO, sequence_data_lo, input_lo_index); + +// // Add a sort gate (simply checks that consecutive inputs have a difference of < 4) +// a_idx = composer.add_variable(FF(0)); +// b_idx = composer.add_variable(FF(1)); +// c_idx = composer.add_variable(FF(2)); +// d_idx = composer.add_variable(FF(3)); +// composer.create_sort_constraint({ a_idx, b_idx, c_idx, d_idx }); + +// // Add an elliptic curve addition gate +// grumpkin::g1::affine_element p1 = crypto::generators::get_generator_data({ 0, 0 }).generator; +// grumpkin::g1::affine_element p2 = crypto::generators::get_generator_data({ 0, 1 }).generator; + +// grumpkin::fq beta_scalar = grumpkin::fq::cube_root_of_unity(); +// grumpkin::g1::affine_element p2_endo = p2; +// p2_endo.x *= beta_scalar; + +// grumpkin::g1::affine_element p3(grumpkin::g1::element(p1) - grumpkin::g1::element(p2_endo)); + +// uint32_t x1 = composer.add_variable(p1.x); +// uint32_t y1 = composer.add_variable(p1.y); +// uint32_t x2 = composer.add_variable(p2.x); +// uint32_t y2 = composer.add_variable(p2.y); +// uint32_t x3 = composer.add_variable(p3.x); +// uint32_t y3 = composer.add_variable(p3.y); + +// ecc_add_gate gate{ x1, y1, x2, y2, x3, y3, beta_scalar, -1 }; +// composer.create_ecc_add_gate(gate); + +// // Add some RAM gates +// uint32_t ram_values[8]{ +// composer.add_variable(fr::random_element()), composer.add_variable(fr::random_element()), +// composer.add_variable(fr::random_element()), composer.add_variable(fr::random_element()), +// composer.add_variable(fr::random_element()), composer.add_variable(fr::random_element()), +// composer.add_variable(fr::random_element()), composer.add_variable(fr::random_element()), +// }; + +// size_t ram_id = composer.create_RAM_array(8); + +// for (size_t i = 0; i < 8; ++i) { +// composer.init_RAM_element(ram_id, i, ram_values[i]); +// } + +// a_idx = composer.read_RAM_array(ram_id, composer.add_variable(5)); +// EXPECT_EQ(a_idx != ram_values[5], true); + +// b_idx = composer.read_RAM_array(ram_id, composer.add_variable(4)); +// c_idx = composer.read_RAM_array(ram_id, composer.add_variable(1)); + +// composer.write_RAM_array(ram_id, composer.add_variable(4), composer.add_variable(500)); +// d_idx = composer.read_RAM_array(ram_id, composer.add_variable(4)); + +// EXPECT_EQ(composer.get_variable(d_idx), 500); + +// // ensure these vars get used in another arithmetic gate +// const auto e_value = composer.get_variable(a_idx) + composer.get_variable(b_idx) + composer.get_variable(c_idx) + +// composer.get_variable(d_idx); +// e_idx = composer.add_variable(e_value); + +// composer.create_big_add_gate({ a_idx, b_idx, c_idx, d_idx, -1, -1, -1, -1, 0 }, true); +// composer.create_big_add_gate( +// { +// composer.get_zero_idx(), +// composer.get_zero_idx(), +// composer.get_zero_idx(), +// e_idx, +// 0, +// 0, +// 0, +// 0, +// 0, +// }, +// false); + +// // Create a prover (it will compute proving key and witness) +// auto prover = composer.create_prover(); + +// // // Generate eta, beta and gamma +// // fr eta = fr::random_element(); +// // fr beta = fr::random_element(); +// // fr gamma = fr::random_element(); + +// // // Compute public input delta +// // const auto public_inputs = composer.circuit_constructor.get_public_inputs(); +// // auto public_input_delta = +// // honk::compute_public_input_delta(public_inputs, beta, gamma, prover.key->circuit_size); +// // auto lookup_grand_product_delta = +// // honk::compute_lookup_grand_product_delta(beta, gamma, prover.key->circuit_size); + +// sumcheck::RelationParameters params{ +// .eta = eta, +// .beta = beta, +// .gamma = gamma, +// .public_input_delta = public_input_delta, +// .lookup_grand_product_delta = lookup_grand_product_delta, +// }; + +// // Compute sorted witness-table accumulator +// prover.key->sorted_accum = prover_library::compute_sorted_list_accumulator(prover.key, eta); + +// // Add RAM/ROM memory records to wire four +// prover_library::add_plookup_memory_records_to_wire_4(prover.key, eta); + +// // Compute grand product polynomial +// prover.key->z_perm = prover_library::compute_permutation_grand_product(prover.key, beta, gamma); + +// // Compute lookup grand product polynomial +// prover.key->z_lookup = prover_library::compute_lookup_grand_product(prover.key, eta, beta, gamma); + +// // // Create an array of spans to the underlying polynomials to more easily +// // // get the transposition. +// // // Ex: polynomial_spans[3][i] returns the i-th coefficient of the third polynomial +// // // in the list below +// // ProverPolynomials prover_polynomials; + +// prover_polynomials.w_l = prover.key->w_l; +// prover_polynomials.w_r = prover.key->w_r; +// prover_polynomials.w_o = prover.key->w_o; +// prover_polynomials.w_4 = prover.key->w_4; +// prover_polynomials.w_l_shift = prover.key->w_l.shifted(); +// prover_polynomials.w_r_shift = prover.key->w_r.shifted(); +// prover_polynomials.w_o_shift = prover.key->w_o.shifted(); +// prover_polynomials.w_4_shift = prover.key->w_4.shifted(); +// prover_polynomials.sorted_accum = prover.key->sorted_accum; +// prover_polynomials.sorted_accum_shift = prover.key->sorted_accum.shifted(); +// prover_polynomials.table_1 = prover.key->table_1; +// prover_polynomials.table_2 = prover.key->table_2; +// prover_polynomials.table_3 = prover.key->table_3; +// prover_polynomials.table_4 = prover.key->table_4; +// prover_polynomials.table_1_shift = prover.key->table_1.shifted(); +// prover_polynomials.table_2_shift = prover.key->table_2.shifted(); +// prover_polynomials.table_3_shift = prover.key->table_3.shifted(); +// prover_polynomials.table_4_shift = prover.key->table_4.shifted(); +// prover_polynomials.z_perm = prover.key->z_perm; +// prover_polynomials.z_perm_shift = prover.key->z_perm.shifted(); +// prover_polynomials.z_lookup = prover.key->z_lookup; +// prover_polynomials.z_lookup_shift = prover.key->z_lookup.shifted(); +// prover_polynomials.q_m = prover.key->q_m; +// prover_polynomials.q_l = prover.key->q_l; +// prover_polynomials.q_r = prover.key->q_r; +// prover_polynomials.q_o = prover.key->q_o; +// prover_polynomials.q_c = prover.key->q_c; +// prover_polynomials.q_4 = prover.key->q_4; +// prover_polynomials.q_arith = prover.key->q_arith; +// prover_polynomials.q_sort = prover.key->q_sort; +// prover_polynomials.q_elliptic = prover.key->q_elliptic; +// prover_polynomials.q_aux = prover.key->q_aux; +// prover_polynomials.q_lookup = prover.key->q_lookup; +// prover_polynomials.sigma_1 = prover.key->sigma_1; +// prover_polynomials.sigma_2 = prover.key->sigma_2; +// prover_polynomials.sigma_3 = prover.key->sigma_3; +// prover_polynomials.sigma_4 = prover.key->sigma_4; +// prover_polynomials.id_1 = prover.key->id_1; +// prover_polynomials.id_2 = prover.key->id_2; +// prover_polynomials.id_3 = prover.key->id_3; +// prover_polynomials.id_4 = prover.key->id_4; +// prover_polynomials.lagrange_first = prover.key->lagrange_first; +// prover_polynomials.lagrange_last = prover.key->lagrange_last; + +// // Check that selectors are nonzero to ensure corresponding relation has nontrivial contribution +// ensure_non_zero(prover.key->q_arith); +// ensure_non_zero(prover.key->q_sort); +// ensure_non_zero(prover.key->q_lookup); +// ensure_non_zero(prover.key->q_elliptic); +// ensure_non_zero(prover.key->q_aux); + +// // Construct the round for applying sumcheck relations and results for storing computed results +// auto relations = std::tuple(honk::sumcheck::UltraArithmeticRelation(), +// honk::sumcheck::UltraArithmeticRelationSecondary(), +// honk::sumcheck::UltraGrandProductInitializationRelation(), +// honk::sumcheck::UltraGrandProductComputationRelation(), +// honk::sumcheck::LookupGrandProductComputationRelation(), +// honk::sumcheck::LookupGrandProductInitializationRelation(), +// honk::sumcheck::GenPermSortRelation(), +// honk::sumcheck::EllipticRelation(), +// honk::sumcheck::AuxiliaryRelation()); + +// // fr result = 0; +// // for (size_t i = 0; i < prover.key->circuit_size; i++) { +// // // Compute an array containing all the evaluations at a given row i +// // PurportedEvaluations evaluations_at_index_i; +// // size_t poly_idx = 0; +// // for (auto& polynomial : prover_polynomials) { +// // evaluations_at_index_i[poly_idx] = polynomial[i]; +// // ++poly_idx; +// // } + +// // // For each relation, call the `accumulate_relation_evaluation` over all witness/selector values at the +// // // i-th row/vertex of the hypercube. We use ASSERT_EQ instead of EXPECT_EQ so that the tests stops at +// // // the first index at which the result is not 0, since result = 0 + C(transposed), which we expect will +// // // equal 0. +// // std::get<0>(relations).add_full_relation_value_contribution(result, evaluations_at_index_i, params); +// // ASSERT_EQ(result, 0); + +// // std::get<1>(relations).add_full_relation_value_contribution(result, evaluations_at_index_i, params); +// // ASSERT_EQ(result, 0); + +// // std::get<2>(relations).add_full_relation_value_contribution(result, evaluations_at_index_i, params); +// // ASSERT_EQ(result, 0); + +// // std::get<3>(relations).add_full_relation_value_contribution(result, evaluations_at_index_i, params); +// // ASSERT_EQ(result, 0); + +// // std::get<4>(relations).add_full_relation_value_contribution(result, evaluations_at_index_i, params); +// // ASSERT_EQ(result, 0); + +// std::get<5>(relations).add_full_relation_value_contribution(result, evaluations_at_index_i, params); +// ASSERT_EQ(result, 0); + +// std::get<6>(relations).add_full_relation_value_contribution(result, evaluations_at_index_i, params); +// ASSERT_EQ(result, 0); + +// std::get<7>(relations).add_full_relation_value_contribution(result, evaluations_at_index_i, params); +// ASSERT_EQ(result, 0); + +// std::get<8>(relations).add_full_relation_value_contribution(result, evaluations_at_index_i, params); +// ASSERT_EQ(result, 0); +// } +// } + } // namespace test_honk_relations diff --git a/cpp/src/barretenberg/honk/sumcheck/relations/ultra_arithmetic_relation.hpp b/cpp/src/barretenberg/honk/sumcheck/relations/ultra_arithmetic_relation.hpp index dd5aa02b85..ad07aed617 100644 --- a/cpp/src/barretenberg/honk/sumcheck/relations/ultra_arithmetic_relation.hpp +++ b/cpp/src/barretenberg/honk/sumcheck/relations/ultra_arithmetic_relation.hpp @@ -12,6 +12,12 @@ template class UltraArithmeticRelation { // 1 + polynomial degree of this relation static constexpr size_t RELATION_LENGTH = 6; // degree(q_arith^2 * q_m * w_r * w_l) = 5 + static constexpr size_t NUM_CONSTRAINTS = 1; + static constexpr std::array CONSTRAINT_LENGTH = { 6 }; + + using RelationUnivariates = std::tuple>; + using RelationValues = std::array; + /** * @brief Expression for the Ultra Arithmetic gate. * @details The relation is defined as C(extended_edges(X)...) = diff --git a/cpp/src/barretenberg/honk/sumcheck/relations/ultra_relation_consistency.test.cpp b/cpp/src/barretenberg/honk/sumcheck/relations/ultra_relation_consistency.test.cpp index e363dd8725..6696a7bbf1 100644 --- a/cpp/src/barretenberg/honk/sumcheck/relations/ultra_relation_consistency.test.cpp +++ b/cpp/src/barretenberg/honk/sumcheck/relations/ultra_relation_consistency.test.cpp @@ -1,692 +1,705 @@ -#include "barretenberg/honk/sumcheck/relations/ultra_arithmetic_relation.hpp" -#include "barretenberg/honk/sumcheck/relations/ultra_arithmetic_relation_secondary.hpp" -#include "barretenberg/honk/sumcheck/relations/lookup_grand_product_relation.hpp" -#include "barretenberg/honk/sumcheck/relations/gen_perm_sort_relation.hpp" -#include "barretenberg/honk/sumcheck/relations/elliptic_relation.hpp" -#include "barretenberg/honk/sumcheck/relations/auxiliary_relation.hpp" -#include "barretenberg/honk/flavor/ultra.hpp" -#include "relation.hpp" -#include "arithmetic_relation.hpp" -#include "grand_product_initialization_relation.hpp" -#include "grand_product_computation_relation.hpp" -#include "../polynomials/univariate.hpp" -#include "../polynomials/barycentric_data.hpp" - -#include "barretenberg/ecc/curves/bn254/fr.hpp" -#include "barretenberg/numeric/random/engine.hpp" - -#include -#include -using namespace proof_system::honk::sumcheck; -/** - * We want to test if all three relations (namely, ArithmeticRelation, GrandProductComputationRelation, - * GrandProductInitializationRelation) provide correct contributions by manually computing their - * contributions with deterministic and random inputs. The relations are supposed to work with - * univariates (edges) of degree one (length 2) and spit out polynomials of corresponding degrees. We have - * MAX_RELATION_LENGTH = 5, meaning the output of a relation can atmost be a degree 5 polynomial. Hence, - * we use a method compute_mock_extended_edges() which starts with degree one input polynomial (two evaluation - points), - * extends them (using barycentric formula) to six evaluation points, and stores them to an array of polynomials. - */ -static const size_t INPUT_UNIVARIATE_LENGTH = 2; - -namespace proof_system::honk_relation_tests { - -class UltraRelationConsistency : public testing::Test { - public: - using Flavor = honk::flavor::Ultra; - using FF = typename Flavor::FF; - using PurportedEvaluations = typename Flavor::PurportedEvaluations; - - // TODO(#390): Move MAX_RELATION_LENGTH into Flavor and simplify this. - template using ExtendedEdges = typename Flavor::template ExtendedEdges; - - // TODO(#225)(Adrian): Accept FULL_RELATION_LENGTH as a template parameter for this function only, so that the test - // can decide to which degree the polynomials must be extended. Possible accept an existing list of "edges" and - // extend them to the degree. - template - static void compute_mock_extended_edges( - ExtendedEdges& extended_edges, - std::array, NUM_POLYNOMIALS>& input_edges) - { - BarycentricData barycentric_2_to_max = - BarycentricData(); - for (size_t i = 0; i < NUM_POLYNOMIALS; ++i) { - extended_edges[i] = barycentric_2_to_max.extend(input_edges[i]); - } - } - - /** - * @brief Returns randomly sampled parameters to feed to the relations. - * - * @return RelationParameters - */ - RelationParameters compute_mock_relation_parameters() - { - return { .beta = FF::random_element(), - .gamma = FF::random_element(), - .public_input_delta = FF::random_element() }; - } - - /** - * @brief Given an array of Univariates, create a new array containing only the i-th evaluations - * of all the univariates. - * - * @note Not really optimized, mainly used for testing that the relations evaluate to the same value when - * evaluated as Univariates, Expressions, or index-by-index - * @todo(Adrian) Maybe this is more helpful as part of a `check_logic` function. - * - * @tparam NUM_UNIVARIATES number of univariates in the input array (deduced from `univariates`) - * @tparam univariate_length number of evaluations (deduced from `univariates`) - * @param univariates array of Univariates - * @param i index of the evaluations we want to take from each univariate - * @return std::array such that result[j] = univariates[j].value_at(i) - */ - template - static PurportedEvaluations transposed_univariate_array_at(ExtendedEdges univariates, size_t i) - { - ASSERT(i < univariate_length); - std::array result; - size_t result_idx = 0; // TODO(#391) zip - for (auto& univariate : univariates) { - result[result_idx] = univariate.value_at(i); - ++result_idx; - } - return result; - }; - - /** - * @brief Compute the evaluation of a `relation` in different ways, comparing it to the provided `expected_evals` - * - * @details Check both `add_full_relation_value_contribution` and `add_edge_contribution` by comparing the result to - * the `expected_evals` computed by the caller. - * Ensures that the relations compute the same result as the expression given in the tests. - * - * @param expected_evals Relation evaluation computed by the caller. - * @param relation being tested - * @param extended_edges - * @param relation_parameters - */ - template - static void validate_evaluations(const Univariate& expected_evals, - const auto relation, - const ExtendedEdges& extended_edges, - const RelationParameters& relation_parameters) - { - - // Compute the expression index-by-index - Univariate expected_evals_index{ 0 }; - for (size_t i = 0; i < FULL_RELATION_LENGTH; ++i) { - // Get an array of the same size as `extended_edges` with only the i-th element of each extended edge. - PurportedEvaluations evals_i = transposed_univariate_array_at(extended_edges, i); - // Evaluate the relation - relation.add_full_relation_value_contribution( - expected_evals_index.value_at(i), evals_i, relation_parameters); - } - EXPECT_EQ(expected_evals, expected_evals_index); - - // Compute the expression using the class, that converts the extended edges to UnivariateView - auto expected_evals_view = Univariate(0); - // The scaling factor is essentially 1 since we are working with degree 1 univariates - relation.add_edge_contribution(expected_evals_view, extended_edges, relation_parameters, 1); - - // Tiny hack to reduce `expected_evals` to be of size `relation.RELATION_LENGTH` - Univariate expected_evals_restricted{ - UnivariateView(expected_evals) - }; - EXPECT_EQ(expected_evals_restricted, expected_evals_view); - }; -}; - -TEST_F(UltraRelationConsistency, UltraArithmeticRelation) -{ - using Flavor = honk::flavor::Ultra; - using FF = typename Flavor::FF; - static constexpr size_t FULL_RELATION_LENGTH = 6; - using ExtendedEdges = typename Flavor::template ExtendedEdges; - static const size_t NUM_POLYNOMIALS = Flavor::NUM_ALL_ENTITIES; - - const auto relation_parameters = compute_mock_relation_parameters(); - ExtendedEdges extended_edges; - std::array, NUM_POLYNOMIALS> input_polynomials; - - // input_univariates are random polynomials of degree one - for (size_t i = 0; i < NUM_POLYNOMIALS; ++i) { - input_polynomials[i] = Univariate({ FF::random_element(), FF::random_element() }); - } - compute_mock_extended_edges(extended_edges, input_polynomials); - - auto relation = UltraArithmeticRelation(); - - // Extract the extended edges for manual computation of relation contribution - const auto& w_1 = extended_edges.w_l; - const auto& w_2 = extended_edges.w_r; - const auto& w_3 = extended_edges.w_o; - const auto& w_4 = extended_edges.w_4; - const auto& w_4_shift = extended_edges.w_4_shift; - const auto& q_m = extended_edges.q_m; - const auto& q_l = extended_edges.q_l; - const auto& q_r = extended_edges.q_r; - const auto& q_o = extended_edges.q_o; - const auto& q_4 = extended_edges.q_4; - const auto& q_c = extended_edges.q_c; - const auto& q_arith = extended_edges.q_arith; - - static const FF neg_half = FF(-2).invert(); - - auto expected_evals = (q_arith - 3) * (q_m * w_2 * w_1) * neg_half; - expected_evals += (q_l * w_1) + (q_r * w_2) + (q_o * w_3) + (q_4 * w_4) + q_c; - expected_evals += (q_arith - 1) * w_4_shift; - expected_evals *= q_arith; - - validate_evaluations(expected_evals, relation, extended_edges, relation_parameters); -}; - -TEST_F(UltraRelationConsistency, UltraArithmeticRelationSecondary) -{ - using Flavor = honk::flavor::Ultra; - using FF = typename Flavor::FF; - static constexpr size_t FULL_RELATION_LENGTH = 6; - using ExtendedEdges = typename Flavor::template ExtendedEdges; - static const size_t NUM_POLYNOMIALS = Flavor::NUM_ALL_ENTITIES; - - const auto relation_parameters = compute_mock_relation_parameters(); - ExtendedEdges extended_edges; - std::array, NUM_POLYNOMIALS> input_polynomials; - - // input_univariates are random polynomials of degree one - for (size_t i = 0; i < NUM_POLYNOMIALS; ++i) { - input_polynomials[i] = Univariate({ FF::random_element(), FF::random_element() }); - } - compute_mock_extended_edges(extended_edges, input_polynomials); - - auto relation = UltraArithmeticRelationSecondary(); - - // Extract the extended edges for manual computation of relation contribution - const auto& w_1 = extended_edges.w_l; - const auto& w_4 = extended_edges.w_4; - const auto& w_l_shift = extended_edges.w_l_shift; - const auto& q_m = extended_edges.q_m; - const auto& q_arith = extended_edges.q_arith; - - auto expected_evals = (w_1 + w_4 - w_l_shift + q_m); - expected_evals *= (q_arith - 2) * (q_arith - 1) * q_arith; - - validate_evaluations(expected_evals, relation, extended_edges, relation_parameters); -}; - -TEST_F(UltraRelationConsistency, UltraGrandProductInitializationRelation) -{ - using Flavor = honk::flavor::Ultra; - using FF = typename Flavor::FF; - using Flavor = honk::flavor::Ultra; - static constexpr size_t FULL_RELATION_LENGTH = 6; - using ExtendedEdges = typename Flavor::ExtendedEdges; - static const size_t NUM_POLYNOMIALS = Flavor::NUM_ALL_ENTITIES; - auto relation_parameters = compute_mock_relation_parameters(); - ExtendedEdges extended_edges; - std::array, NUM_POLYNOMIALS> input_polynomials; - - // input_univariates are random polynomials of degree one - for (size_t i = 0; i < NUM_POLYNOMIALS; ++i) { - input_polynomials[i] = Univariate({ FF::random_element(), FF::random_element() }); - } - compute_mock_extended_edges(extended_edges, input_polynomials); - - auto relation = UltraGrandProductInitializationRelation(); - - // Extract the extended edges for manual computation of relation contribution - const auto& z_perm_shift = extended_edges.z_perm_shift; - const auto& lagrange_last = extended_edges.lagrange_last; - - // Compute the expected result using a simple to read version of the relation expression - auto expected_evals = z_perm_shift * lagrange_last; - - validate_evaluations(expected_evals, relation, extended_edges, relation_parameters); -}; - -TEST_F(UltraRelationConsistency, UltraGrandProductComputationRelation) -{ - using Flavor = honk::flavor::Ultra; - using FF = typename Flavor::FF; - using Flavor = honk::flavor::Ultra; - static constexpr size_t FULL_RELATION_LENGTH = 6; - using ExtendedEdges = typename Flavor::template ExtendedEdges; - static const size_t NUM_POLYNOMIALS = Flavor::NUM_ALL_ENTITIES; - auto relation_parameters = compute_mock_relation_parameters(); - ExtendedEdges extended_edges; - std::array, NUM_POLYNOMIALS> input_polynomials; - - // input_univariates are random polynomials of degree one - for (size_t i = 0; i < NUM_POLYNOMIALS; ++i) { - input_polynomials[i] = Univariate({ FF::random_element(), FF::random_element() }); - } - compute_mock_extended_edges(extended_edges, input_polynomials); - - auto relation = UltraGrandProductComputationRelation(); - - const auto& beta = relation_parameters.beta; - const auto& gamma = relation_parameters.gamma; - const auto& public_input_delta = relation_parameters.public_input_delta; - - // Extract the extended edges for manual computation of relation contribution - const auto& w_1 = extended_edges.w_l; - const auto& w_2 = extended_edges.w_r; - const auto& w_3 = extended_edges.w_o; - const auto& w_4 = extended_edges.w_4; - const auto& sigma_1 = extended_edges.sigma_1; - const auto& sigma_2 = extended_edges.sigma_2; - const auto& sigma_3 = extended_edges.sigma_3; - const auto& sigma_4 = extended_edges.sigma_4; - const auto& id_1 = extended_edges.id_1; - const auto& id_2 = extended_edges.id_2; - const auto& id_3 = extended_edges.id_3; - const auto& id_4 = extended_edges.id_4; - const auto& z_perm = extended_edges.z_perm; - const auto& z_perm_shift = extended_edges.z_perm_shift; - const auto& lagrange_first = extended_edges.lagrange_first; - const auto& lagrange_last = extended_edges.lagrange_last; - - // Compute the expected result using a simple to read version of the relation expression - auto expected_evals = (z_perm + lagrange_first) * (w_1 + id_1 * beta + gamma) * (w_2 + id_2 * beta + gamma) * - (w_3 + id_3 * beta + gamma) * (w_4 + id_4 * beta + gamma) - - (z_perm_shift + lagrange_last * public_input_delta) * (w_1 + sigma_1 * beta + gamma) * - (w_2 + sigma_2 * beta + gamma) * (w_3 + sigma_3 * beta + gamma) * - (w_4 + sigma_4 * beta + gamma); - - validate_evaluations(expected_evals, relation, extended_edges, relation_parameters); -}; - -TEST_F(UltraRelationConsistency, LookupGrandProductComputationRelation) -{ - using Flavor = honk::flavor::Ultra; - using FF = typename Flavor::FF; - using Flavor = honk::flavor::Ultra; - static constexpr size_t FULL_RELATION_LENGTH = 6; - using ExtendedEdges = typename Flavor::ExtendedEdges; - static const size_t NUM_POLYNOMIALS = Flavor::NUM_ALL_ENTITIES; - auto relation_parameters = compute_mock_relation_parameters(); - ExtendedEdges extended_edges; - std::array, NUM_POLYNOMIALS> input_polynomials; - - // input_univariates are random polynomials of degree one - for (size_t i = 0; i < NUM_POLYNOMIALS; ++i) { - input_polynomials[i] = Univariate({ FF::random_element(), FF::random_element() }); - } - compute_mock_extended_edges(extended_edges, input_polynomials); - - auto relation = LookupGrandProductComputationRelation(); - - const auto eta = relation_parameters.eta; - const auto beta = relation_parameters.beta; - const auto gamma = relation_parameters.gamma; - auto grand_product_delta = relation_parameters.lookup_grand_product_delta; - - // Extract the extended edges for manual computation of relation contribution - auto one_plus_beta = FF::one() + beta; - auto gamma_by_one_plus_beta = gamma * one_plus_beta; - auto eta_sqr = eta * eta; - auto eta_cube = eta_sqr * eta; - - const auto& w_1 = extended_edges.w_l; - const auto& w_2 = extended_edges.w_r; - const auto& w_3 = extended_edges.w_o; - - const auto& w_1_shift = extended_edges.w_l_shift; - const auto& w_2_shift = extended_edges.w_r_shift; - const auto& w_3_shift = extended_edges.w_o_shift; - - const auto& table_1 = extended_edges.table_1; - const auto& table_2 = extended_edges.table_2; - const auto& table_3 = extended_edges.table_3; - const auto& table_4 = extended_edges.table_4; - - const auto& table_1_shift = extended_edges.table_1_shift; - const auto& table_2_shift = extended_edges.table_2_shift; - const auto& table_3_shift = extended_edges.table_3_shift; - const auto& table_4_shift = extended_edges.table_4_shift; - - const auto& s_accum = extended_edges.sorted_accum; - const auto& s_accum_shift = extended_edges.sorted_accum_shift; - const auto& z_lookup = extended_edges.z_lookup; - const auto& z_lookup_shift = extended_edges.z_lookup_shift; - - const auto& table_index = extended_edges.q_o; - const auto& column_1_step_size = extended_edges.q_r; - const auto& column_2_step_size = extended_edges.q_m; - const auto& column_3_step_size = extended_edges.q_c; - const auto& q_lookup = extended_edges.q_lookup; - - const auto& lagrange_first = extended_edges.lagrange_first; - const auto& lagrange_last = extended_edges.lagrange_last; - - auto wire_accum = (w_1 + column_1_step_size * w_1_shift) + (w_2 + column_2_step_size * w_2_shift) * eta + - (w_3 + column_3_step_size * w_3_shift) * eta_sqr + table_index * eta_cube; - - auto table_accum = table_1 + table_2 * eta + table_3 * eta_sqr + table_4 * eta_cube; - auto table_accum_shift = table_1_shift + table_2_shift * eta + table_3_shift * eta_sqr + table_4_shift * eta_cube; - - // Compute the expected result using a simple to read version of the relation expression - auto expected_evals = (z_lookup + lagrange_first) * (q_lookup * wire_accum + gamma) * - (table_accum + table_accum_shift * beta + gamma_by_one_plus_beta) * one_plus_beta; - expected_evals -= (z_lookup_shift + lagrange_last * grand_product_delta) * - (s_accum + s_accum_shift * beta + gamma_by_one_plus_beta); - - validate_evaluations(expected_evals, relation, extended_edges, relation_parameters); -}; - -TEST_F(UltraRelationConsistency, LookupGrandProductInitializationRelation) -{ - using Flavor = honk::flavor::Ultra; - using FF = typename Flavor::FF; - using Flavor = honk::flavor::Ultra; - static constexpr size_t FULL_RELATION_LENGTH = 6; - using ExtendedEdges = typename Flavor::ExtendedEdges; - static const size_t NUM_POLYNOMIALS = Flavor::NUM_ALL_ENTITIES; - auto relation_parameters = compute_mock_relation_parameters(); - ExtendedEdges extended_edges; - std::array, NUM_POLYNOMIALS> input_polynomials; - - // input_univariates are random polynomials of degree one - for (size_t i = 0; i < NUM_POLYNOMIALS; ++i) { - input_polynomials[i] = Univariate({ FF::random_element(), FF::random_element() }); - } - compute_mock_extended_edges(extended_edges, input_polynomials); - - auto relation = LookupGrandProductInitializationRelation(); - - // Extract the extended edges for manual computation of relation contribution - const auto& z_lookup_shift = extended_edges.z_lookup_shift; - const auto& lagrange_last = extended_edges.lagrange_last; - - // Compute the expected result using a simple to read version of the relation expression - auto expected_evals = z_lookup_shift * lagrange_last; - - validate_evaluations(expected_evals, relation, extended_edges, relation_parameters); -}; - -TEST_F(UltraRelationConsistency, GenPermSortRelation) -{ - using Flavor = honk::flavor::Ultra; - using FF = typename Flavor::FF; - using Flavor = honk::flavor::Ultra; - static constexpr size_t FULL_RELATION_LENGTH = 6; - using ExtendedEdges = typename Flavor::ExtendedEdges; - static const size_t NUM_POLYNOMIALS = Flavor::NUM_ALL_ENTITIES; - auto relation_parameters = compute_mock_relation_parameters(); - ExtendedEdges extended_edges; - std::array, NUM_POLYNOMIALS> input_polynomials; - - // input_univariates are random polynomials of degree one - for (size_t i = 0; i < NUM_POLYNOMIALS; ++i) { - input_polynomials[i] = Univariate({ FF::random_element(), FF::random_element() }); - } - compute_mock_extended_edges(extended_edges, input_polynomials); - - auto relation = GenPermSortRelation(); - - // Extract the extended edges for manual computation of relation contribution - const auto& z_lookup_shift = extended_edges.z_lookup_shift; - const auto& lagrange_last = extended_edges.lagrange_last; - - const auto& w_1 = extended_edges.w_l; - const auto& w_2 = extended_edges.w_r; - const auto& w_3 = extended_edges.w_o; - const auto& w_4 = extended_edges.w_4; - const auto& w_1_shift = extended_edges.w_l_shift; - const auto& q_sort = extended_edges.q_sort; - - static const FF fake_alpha_1 = FF(1); - static const FF fake_alpha_2 = fake_alpha_1 * fake_alpha_1; - static const FF fake_alpha_3 = fake_alpha_2 * fake_alpha_1; - static const FF fake_alpha_4 = fake_alpha_3 * fake_alpha_1; - - // Compute wire differences - auto delta_1 = w_2 - w_1; - auto delta_2 = w_3 - w_2; - auto delta_3 = w_4 - w_3; - auto delta_4 = w_1_shift - w_4; - - // Compute the expected result using a simple to read version of the relation expression - auto expected_evals = delta_1 * (delta_1 - 1) * (delta_1 - 2) * (delta_1 - 3) * fake_alpha_1; - expected_evals += delta_2 * (delta_2 - 1) * (delta_2 - 2) * (delta_2 - 3) * fake_alpha_2; - expected_evals += delta_3 * (delta_3 - 1) * (delta_3 - 2) * (delta_3 - 3) * fake_alpha_3; - expected_evals += delta_4 * (delta_4 - 1) * (delta_4 - 2) * (delta_4 - 3) * fake_alpha_4; - expected_evals *= q_sort; - - validate_evaluations(expected_evals, relation, extended_edges, relation_parameters); -}; - -TEST_F(UltraRelationConsistency, EllipticRelation) -{ - using Flavor = honk::flavor::Ultra; - using FF = typename Flavor::FF; - using Flavor = honk::flavor::Ultra; - static constexpr size_t FULL_RELATION_LENGTH = 6; - using ExtendedEdges = typename Flavor::ExtendedEdges; - static const size_t NUM_POLYNOMIALS = Flavor::NUM_ALL_ENTITIES; - auto relation_parameters = compute_mock_relation_parameters(); - ExtendedEdges extended_edges; - std::array, NUM_POLYNOMIALS> input_polynomials; - - // input_univariates are random polynomials of degree one - for (size_t i = 0; i < NUM_POLYNOMIALS; ++i) { - input_polynomials[i] = Univariate({ FF::random_element(), FF::random_element() }); - } - compute_mock_extended_edges(extended_edges, input_polynomials); - - auto relation = EllipticRelation(); - - // Extract the extended edges for manual computation of relation contribution - const auto& x_1 = extended_edges.w_r; - const auto& y_1 = extended_edges.w_o; - - const auto& x_2 = extended_edges.w_l_shift; - const auto& y_2 = extended_edges.w_4_shift; - const auto& x_3 = extended_edges.w_r_shift; - const auto& y_3 = extended_edges.w_o_shift; - - const auto& q_sign = extended_edges.q_l; - const auto& q_beta = extended_edges.q_o; - const auto& q_beta_sqr = extended_edges.q_4; - const auto& q_elliptic = extended_edges.q_elliptic; - - static const FF fake_alpha_1 = FF(1); - static const FF fake_alpha_2 = fake_alpha_1 * fake_alpha_1; - - // Compute x/y coordinate identities - auto x_identity = q_sign * (y_1 * y_2 * 2); - x_identity += q_beta * (x_1 * x_2 * x_3 * 2 + x_1 * x_1 * x_2) * FF(-1); - x_identity += q_beta_sqr * (x_2 * x_2 * x_3 - x_1 * x_2 * x_2); - x_identity += (x_1 * x_1 * x_3 - y_2 * y_2 - y_1 * y_1 + x_2 * x_2 * x_2 + x_1 * x_1 * x_1); - - auto y_identity = q_sign * (y_2 * x_3 - y_2 * x_1); - y_identity += q_beta * (x_2 * y_3 + y_1 * x_2); - y_identity += (x_1 * y_1 - x_1 * y_3 - y_1 * x_3 - x_1 * y_1); - - auto expected_evals = x_identity * fake_alpha_1 + y_identity * fake_alpha_2; - expected_evals *= q_elliptic; - - validate_evaluations(expected_evals, relation, extended_edges, relation_parameters); -}; - -TEST_F(UltraRelationConsistency, AuxiliaryRelation) -{ - using Flavor = honk::flavor::Ultra; - using FF = typename Flavor::FF; - using Flavor = honk::flavor::Ultra; - static constexpr size_t FULL_RELATION_LENGTH = 6; - using ExtendedEdges = typename Flavor::ExtendedEdges; - static const size_t NUM_POLYNOMIALS = Flavor::NUM_ALL_ENTITIES; - auto relation_parameters = compute_mock_relation_parameters(); - ExtendedEdges extended_edges; - std::array, NUM_POLYNOMIALS> input_polynomials; - - // input_univariates are random polynomials of degree one - for (size_t i = 0; i < NUM_POLYNOMIALS; ++i) { - input_polynomials[i] = Univariate({ FF::random_element(), FF::random_element() }); - } - compute_mock_extended_edges(extended_edges, input_polynomials); - - auto relation = AuxiliaryRelation(); - - const auto& eta = relation_parameters.eta; - const auto fake_alpha = FF(1); - - // Extract the extended edges for manual computation of relation contribution - const auto& w_1 = extended_edges.w_l; - const auto& w_2 = extended_edges.w_r; - const auto& w_3 = extended_edges.w_o; - const auto& w_4 = extended_edges.w_4; - const auto& w_1_shift = extended_edges.w_l_shift; - const auto& w_2_shift = extended_edges.w_r_shift; - const auto& w_3_shift = extended_edges.w_o_shift; - const auto& w_4_shift = extended_edges.w_4_shift; - - const auto& q_1 = extended_edges.q_l; - const auto& q_2 = extended_edges.q_r; - const auto& q_3 = extended_edges.q_o; - const auto& q_4 = extended_edges.q_4; - const auto& q_m = extended_edges.q_m; - const auto& q_c = extended_edges.q_c; - const auto& q_arith = extended_edges.q_arith; - const auto& q_aux = extended_edges.q_aux; - - constexpr FF LIMB_SIZE(uint256_t(1) << 68); - constexpr FF SUBLIMB_SHIFT(uint256_t(1) << 14); - constexpr FF SUBLIMB_SHIFT_2(SUBLIMB_SHIFT * SUBLIMB_SHIFT); - constexpr FF SUBLIMB_SHIFT_3(SUBLIMB_SHIFT_2 * SUBLIMB_SHIFT); - constexpr FF SUBLIMB_SHIFT_4(SUBLIMB_SHIFT_3 * SUBLIMB_SHIFT); - - /** - * Non native field arithmetic gate 2 - * - * _ _ - * / _ _ _ 14 \ - * q_2 . q_4 | (w_1 . w_2) + (w_1 . w_2) + (w_1 . w_4 + w_2 . w_3 - w_3) . 2 - w_3 - w_4 | - * \_ _/ - * - **/ - auto limb_subproduct = w_1 * w_2_shift + w_1_shift * w_2; - auto non_native_field_gate_2 = (w_1 * w_4 + w_2 * w_3 - w_3_shift); - non_native_field_gate_2 *= LIMB_SIZE; - non_native_field_gate_2 -= w_4_shift; - non_native_field_gate_2 += limb_subproduct; - non_native_field_gate_2 *= q_4; - - limb_subproduct *= LIMB_SIZE; - limb_subproduct += (w_1_shift * w_2_shift); - auto non_native_field_gate_1 = limb_subproduct; - non_native_field_gate_1 -= (w_3 + w_4); - non_native_field_gate_1 *= q_3; - - auto non_native_field_gate_3 = limb_subproduct; - non_native_field_gate_3 += w_4; - non_native_field_gate_3 -= (w_3_shift + w_4_shift); - non_native_field_gate_3 *= q_m; - - auto non_native_field_identity = non_native_field_gate_1 + non_native_field_gate_2 + non_native_field_gate_3; - non_native_field_identity *= q_2; - - auto limb_accumulator_1 = w_1 + w_2 * SUBLIMB_SHIFT + w_3 * SUBLIMB_SHIFT_2 + w_1_shift * SUBLIMB_SHIFT_3 + - w_2_shift * SUBLIMB_SHIFT_4 - w_4; - limb_accumulator_1 *= q_4; - - auto limb_accumulator_2 = w_3 + w_4 * SUBLIMB_SHIFT + w_1_shift * SUBLIMB_SHIFT_2 + w_2_shift * SUBLIMB_SHIFT_3 + - w_3_shift * SUBLIMB_SHIFT_4 - w_4_shift; - limb_accumulator_2 *= q_m; - - auto limb_accumulator_identity = limb_accumulator_1 + limb_accumulator_2; - limb_accumulator_identity *= q_3; - - /** - * MEMORY - **/ - - /** - * Memory Record Check - */ - auto memory_record_check = w_3; - memory_record_check *= eta; - memory_record_check += w_2; - memory_record_check *= eta; - memory_record_check += w_1; - memory_record_check *= eta; - memory_record_check += q_c; - auto partial_record_check = memory_record_check; // used in RAM consistency check - memory_record_check = memory_record_check - w_4; - - /** - * ROM Consistency Check - */ - auto index_delta = w_1_shift - w_1; - auto record_delta = w_4_shift - w_4; - - auto index_is_monotonically_increasing = index_delta * index_delta - index_delta; - - // auto adjacent_values_match_if_adjacent_indices_match = (FF(1) - index_delta) * record_delta; - auto adjacent_values_match_if_adjacent_indices_match = (index_delta * FF(-1) + FF(1)) * record_delta; - - auto ROM_consistency_check_identity = adjacent_values_match_if_adjacent_indices_match; - ROM_consistency_check_identity *= fake_alpha; - ROM_consistency_check_identity += index_is_monotonically_increasing; - ROM_consistency_check_identity *= fake_alpha; - ROM_consistency_check_identity += memory_record_check; - - /** - * RAM Consistency Check - */ - auto access_type = (w_4 - partial_record_check); // will be 0 or 1 for honest Prover - auto access_check = access_type * access_type - access_type; // check value is 0 or 1 - - auto next_gate_access_type = w_3_shift; - next_gate_access_type *= eta; - next_gate_access_type += w_2_shift; - next_gate_access_type *= eta; - next_gate_access_type += w_1_shift; - next_gate_access_type *= eta; - next_gate_access_type = w_4_shift - next_gate_access_type; - - auto value_delta = w_3_shift - w_3; - auto adjacent_values_match_if_adjacent_indices_match_and_next_access_is_a_read_operation = - (index_delta * FF(-1) + FF(1)) * value_delta * (next_gate_access_type * FF(-1) + FF(1)); - - // We can't apply the RAM consistency check identity on the final entry in the sorted list (the wires in the - // next gate would make the identity fail). - // We need to validate that its 'access type' bool is correct. Can't do - // with an arithmetic gate because of the `eta` factors. We need to check that the *next* gate's access type is - // correct, to cover this edge case - auto next_gate_access_type_is_boolean = next_gate_access_type * next_gate_access_type - next_gate_access_type; - - // Putting it all together... - auto RAM_consistency_check_identity = - adjacent_values_match_if_adjacent_indices_match_and_next_access_is_a_read_operation; - RAM_consistency_check_identity *= fake_alpha; - RAM_consistency_check_identity += index_is_monotonically_increasing; - RAM_consistency_check_identity *= fake_alpha; - RAM_consistency_check_identity += next_gate_access_type_is_boolean; - RAM_consistency_check_identity *= fake_alpha; - RAM_consistency_check_identity += access_check; - - /** - * RAM Timestamp Consistency Check - */ - auto timestamp_delta = w_2_shift - w_2; - auto RAM_timestamp_check_identity = (index_delta * FF(-1) + FF(1)) * timestamp_delta - w_3; - - /** - * The complete RAM/ROM memory identity - */ - auto memory_identity = ROM_consistency_check_identity * q_2; - memory_identity += RAM_timestamp_check_identity * q_4; - memory_identity += memory_record_check * q_m; - memory_identity *= q_1; - memory_identity += (RAM_consistency_check_identity * q_arith); - - auto expected_evals = memory_identity + non_native_field_identity + limb_accumulator_identity; - expected_evals *= q_aux; - - validate_evaluations(expected_evals, relation, extended_edges, relation_parameters); -}; - -} // namespace proof_system::honk_relation_tests +// #include "barretenberg/honk/sumcheck/relations/ultra_arithmetic_relation.hpp" +// #include "barretenberg/honk/sumcheck/relations/ultra_arithmetic_relation_secondary.hpp" +// #include "barretenberg/honk/sumcheck/relations/lookup_grand_product_relation.hpp" +// #include "barretenberg/honk/sumcheck/relations/gen_perm_sort_relation.hpp" +// #include "barretenberg/honk/sumcheck/relations/elliptic_relation.hpp" +// #include "barretenberg/honk/sumcheck/relations/auxiliary_relation.hpp" +// #include "barretenberg/honk/flavor/ultra.hpp" +// #include "relation.hpp" +// #include "arithmetic_relation.hpp" +// #include "grand_product_initialization_relation.hpp" +// #include "permutation_relation.hpp" +// #include "../polynomials/univariate.hpp" +// #include "../polynomials/barycentric_data.hpp" + +// #include "barretenberg/ecc/curves/bn254/fr.hpp" +// #include "barretenberg/numeric/random/engine.hpp" + +// #include +// #include +// using namespace proof_system::honk::sumcheck; +// /** +// * We want to test if all three relations (namely, ArithmeticRelation, GrandProductComputationRelation, +// * GrandProductInitializationRelation) provide correct contributions by manually computing their +// * contributions with deterministic and random inputs. The relations are supposed to work with +// * univariates (edges) of degree one (length 2) and spit out polynomials of corresponding degrees. We have +// * MAX_RELATION_LENGTH = 5, meaning the output of a relation can atmost be a degree 5 polynomial. Hence, +// * we use a method compute_mock_extended_edges() which starts with degree one input polynomial (two evaluation +// points), +// * extends them (using barycentric formula) to six evaluation points, and stores them to an array of polynomials. +// */ +// static const size_t INPUT_UNIVARIATE_LENGTH = 2; + +// namespace proof_system::honk_relation_tests { + +// class UltraRelationConsistency : public testing::Test { +// public: +// using Flavor = honk::flavor::Ultra; +// using FF = typename Flavor::FF; +// using PurportedEvaluations = typename Flavor::PurportedEvaluations; + +// // TODO(#390): Move MAX_RELATION_LENGTH into Flavor and simplify this. +// template using ExtendedEdges = typename Flavor::template ExtendedEdges; + +// // TODO(#225)(Adrian): Accept FULL_RELATION_LENGTH as a template parameter for this function only, so that the +// test +// // can decide to which degree the polynomials must be extended. Possible accept an existing list of "edges" and +// // extend them to the degree. +// template +// static void compute_mock_extended_edges( +// ExtendedEdges& extended_edges, +// std::array, NUM_POLYNOMIALS>& input_edges) +// { +// BarycentricData barycentric_2_to_max = +// BarycentricData(); +// for (size_t i = 0; i < NUM_POLYNOMIALS; ++i) { +// extended_edges[i] = barycentric_2_to_max.extend(input_edges[i]); +// } +// } + +// /** +// * @brief Returns randomly sampled parameters to feed to the relations. +// * +// * @return RelationParameters +// */ +// RelationParameters compute_mock_relation_parameters() +// { +// return { .beta = FF::random_element(), +// .gamma = FF::random_element(), +// .public_input_delta = FF::random_element() }; +// } + +// /** +// * @brief Given an array of Univariates, create a new array containing only the i-th evaluations +// * of all the univariates. +// * +// * @note Not really optimized, mainly used for testing that the relations evaluate to the same value when +// * evaluated as Univariates, Expressions, or index-by-index +// * @todo(Adrian) Maybe this is more helpful as part of a `check_logic` function. +// * +// * @tparam NUM_UNIVARIATES number of univariates in the input array (deduced from `univariates`) +// * @tparam univariate_length number of evaluations (deduced from `univariates`) +// * @param univariates array of Univariates +// * @param i index of the evaluations we want to take from each univariate +// * @return std::array such that result[j] = univariates[j].value_at(i) +// */ +// template +// static PurportedEvaluations transposed_univariate_array_at(ExtendedEdges univariates, size_t +// i) +// { +// ASSERT(i < univariate_length); +// std::array result; +// size_t result_idx = 0; // TODO(#391) zip +// for (auto& univariate : univariates) { +// result[result_idx] = univariate.value_at(i); +// ++result_idx; +// } +// return result; +// }; + +// /** +// * @brief Compute the evaluation of a `relation` in different ways, comparing it to the provided `expected_evals` +// * +// * @details Check both `add_full_relation_value_contribution` and `add_edge_contribution` by comparing the result +// to +// * the `expected_evals` computed by the caller. +// * Ensures that the relations compute the same result as the expression given in the tests. +// * +// * @param expected_evals Relation evaluation computed by the caller. +// * @param relation being tested +// * @param extended_edges +// * @param relation_parameters +// */ +// template +// static void validate_evaluations(const Univariate& expected_evals, +// const auto relation, +// const ExtendedEdges& extended_edges, +// const RelationParameters& relation_parameters) +// { + +// // Compute the expression index-by-index +// Univariate expected_evals_index{ 0 }; +// for (size_t i = 0; i < FULL_RELATION_LENGTH; ++i) { +// // Get an array of the same size as `extended_edges` with only the i-th element of each extended edge. +// PurportedEvaluations evals_i = transposed_univariate_array_at(extended_edges, i); +// // Evaluate the relation +// relation.add_full_relation_value_contribution( +// expected_evals_index.value_at(i), evals_i, relation_parameters); +// } +// EXPECT_EQ(expected_evals, expected_evals_index); + +// // Compute the expression using the class, that converts the extended edges to UnivariateView +// auto expected_evals_view = Univariate(0); +// // The scaling factor is essentially 1 since we are working with degree 1 univariates +// relation.add_edge_contribution(expected_evals_view, extended_edges, relation_parameters, 1); + +// // Tiny hack to reduce `expected_evals` to be of size `relation.RELATION_LENGTH` +// Univariate expected_evals_restricted{ +// UnivariateView(expected_evals) +// }; +// EXPECT_EQ(expected_evals_restricted, expected_evals_view); +// }; +// }; + +// TEST_F(UltraRelationConsistency, UltraArithmeticRelation) +// { +// using Flavor = honk::flavor::Ultra; +// using FF = typename Flavor::FF; +// static constexpr size_t FULL_RELATION_LENGTH = 6; +// using ExtendedEdges = typename Flavor::template ExtendedEdges; +// static const size_t NUM_POLYNOMIALS = Flavor::NUM_ALL_ENTITIES; + +// const auto relation_parameters = compute_mock_relation_parameters(); +// ExtendedEdges extended_edges; +// std::array, NUM_POLYNOMIALS> input_polynomials; + +// // input_univariates are random polynomials of degree one +// for (size_t i = 0; i < NUM_POLYNOMIALS; ++i) { +// input_polynomials[i] = Univariate({ FF::random_element(), FF::random_element() +// }); +// } +// compute_mock_extended_edges(extended_edges, input_polynomials); + +// auto relation = UltraArithmeticRelation(); + +// // Extract the extended edges for manual computation of relation contribution +// const auto& w_1 = extended_edges.w_l; +// const auto& w_2 = extended_edges.w_r; +// const auto& w_3 = extended_edges.w_o; +// const auto& w_4 = extended_edges.w_4; +// const auto& w_4_shift = extended_edges.w_4_shift; +// const auto& q_m = extended_edges.q_m; +// const auto& q_l = extended_edges.q_l; +// const auto& q_r = extended_edges.q_r; +// const auto& q_o = extended_edges.q_o; +// const auto& q_4 = extended_edges.q_4; +// const auto& q_c = extended_edges.q_c; +// const auto& q_arith = extended_edges.q_arith; + +// static const FF neg_half = FF(-2).invert(); + +// auto expected_evals = (q_arith - 3) * (q_m * w_2 * w_1) * neg_half; +// expected_evals += (q_l * w_1) + (q_r * w_2) + (q_o * w_3) + (q_4 * w_4) + q_c; +// expected_evals += (q_arith - 1) * w_4_shift; +// expected_evals *= q_arith; + +// validate_evaluations(expected_evals, relation, extended_edges, relation_parameters); +// }; + +// TEST_F(UltraRelationConsistency, UltraArithmeticRelationSecondary) +// { +// using Flavor = honk::flavor::Ultra; +// using FF = typename Flavor::FF; +// static constexpr size_t FULL_RELATION_LENGTH = 6; +// using ExtendedEdges = typename Flavor::template ExtendedEdges; +// static const size_t NUM_POLYNOMIALS = Flavor::NUM_ALL_ENTITIES; + +// const auto relation_parameters = compute_mock_relation_parameters(); +// ExtendedEdges extended_edges; +// std::array, NUM_POLYNOMIALS> input_polynomials; + +// // input_univariates are random polynomials of degree one +// for (size_t i = 0; i < NUM_POLYNOMIALS; ++i) { +// input_polynomials[i] = Univariate({ FF::random_element(), FF::random_element() +// }); +// } +// compute_mock_extended_edges(extended_edges, input_polynomials); + +// auto relation = UltraArithmeticRelationSecondary(); + +// // Extract the extended edges for manual computation of relation contribution +// const auto& w_1 = extended_edges.w_l; +// const auto& w_4 = extended_edges.w_4; +// const auto& w_l_shift = extended_edges.w_l_shift; +// const auto& q_m = extended_edges.q_m; +// const auto& q_arith = extended_edges.q_arith; + +// auto expected_evals = (w_1 + w_4 - w_l_shift + q_m); +// expected_evals *= (q_arith - 2) * (q_arith - 1) * q_arith; + +// validate_evaluations(expected_evals, relation, extended_edges, relation_parameters); +// }; + +// TEST_F(UltraRelationConsistency, UltraGrandProductInitializationRelation) +// { +// using Flavor = honk::flavor::Ultra; +// using FF = typename Flavor::FF; +// using Flavor = honk::flavor::Ultra; +// static constexpr size_t FULL_RELATION_LENGTH = 6; +// using ExtendedEdges = typename Flavor::ExtendedEdges; +// static const size_t NUM_POLYNOMIALS = Flavor::NUM_ALL_ENTITIES; +// auto relation_parameters = compute_mock_relation_parameters(); +// ExtendedEdges extended_edges; +// std::array, NUM_POLYNOMIALS> input_polynomials; + +// // input_univariates are random polynomials of degree one +// for (size_t i = 0; i < NUM_POLYNOMIALS; ++i) { +// input_polynomials[i] = Univariate({ FF::random_element(), FF::random_element() +// }); +// } +// compute_mock_extended_edges(extended_edges, input_polynomials); + +// auto relation = UltraGrandProductInitializationRelation(); + +// // Extract the extended edges for manual computation of relation contribution +// const auto& z_perm_shift = extended_edges.z_perm_shift; +// const auto& lagrange_last = extended_edges.lagrange_last; + +// // Compute the expected result using a simple to read version of the relation expression +// auto expected_evals = z_perm_shift * lagrange_last; + +// validate_evaluations(expected_evals, relation, extended_edges, relation_parameters); +// }; + +// TEST_F(UltraRelationConsistency, UltraGrandProductComputationRelation) +// { +// using Flavor = honk::flavor::Ultra; +// using FF = typename Flavor::FF; +// using Flavor = honk::flavor::Ultra; +// static constexpr size_t FULL_RELATION_LENGTH = 6; +// using ExtendedEdges = typename Flavor::template ExtendedEdges; +// static const size_t NUM_POLYNOMIALS = Flavor::NUM_ALL_ENTITIES; +// auto relation_parameters = compute_mock_relation_parameters(); +// ExtendedEdges extended_edges; +// std::array, NUM_POLYNOMIALS> input_polynomials; + +// // input_univariates are random polynomials of degree one +// for (size_t i = 0; i < NUM_POLYNOMIALS; ++i) { +// input_polynomials[i] = Univariate({ FF::random_element(), FF::random_element() +// }); +// } +// compute_mock_extended_edges(extended_edges, input_polynomials); + +// auto relation = UltraGrandProductComputationRelation(); + +// const auto& beta = relation_parameters.beta; +// const auto& gamma = relation_parameters.gamma; +// const auto& public_input_delta = relation_parameters.public_input_delta; + +// // Extract the extended edges for manual computation of relation contribution +// const auto& w_1 = extended_edges.w_l; +// const auto& w_2 = extended_edges.w_r; +// const auto& w_3 = extended_edges.w_o; +// const auto& w_4 = extended_edges.w_4; +// const auto& sigma_1 = extended_edges.sigma_1; +// const auto& sigma_2 = extended_edges.sigma_2; +// const auto& sigma_3 = extended_edges.sigma_3; +// const auto& sigma_4 = extended_edges.sigma_4; +// const auto& id_1 = extended_edges.id_1; +// const auto& id_2 = extended_edges.id_2; +// const auto& id_3 = extended_edges.id_3; +// const auto& id_4 = extended_edges.id_4; +// const auto& z_perm = extended_edges.z_perm; +// const auto& z_perm_shift = extended_edges.z_perm_shift; +// const auto& lagrange_first = extended_edges.lagrange_first; +// const auto& lagrange_last = extended_edges.lagrange_last; + +// // Compute the expected result using a simple to read version of the relation expression +// auto expected_evals = (z_perm + lagrange_first) * (w_1 + id_1 * beta + gamma) * (w_2 + id_2 * beta + gamma) * +// (w_3 + id_3 * beta + gamma) * (w_4 + id_4 * beta + gamma) - +// (z_perm_shift + lagrange_last * public_input_delta) * (w_1 + sigma_1 * beta + gamma) * +// (w_2 + sigma_2 * beta + gamma) * (w_3 + sigma_3 * beta + gamma) * +// (w_4 + sigma_4 * beta + gamma); + +// validate_evaluations(expected_evals, relation, extended_edges, relation_parameters); +// }; + +// TEST_F(UltraRelationConsistency, LookupGrandProductComputationRelation) +// { +// using Flavor = honk::flavor::Ultra; +// using FF = typename Flavor::FF; +// using Flavor = honk::flavor::Ultra; +// static constexpr size_t FULL_RELATION_LENGTH = 6; +// using ExtendedEdges = typename Flavor::ExtendedEdges; +// static const size_t NUM_POLYNOMIALS = Flavor::NUM_ALL_ENTITIES; +// auto relation_parameters = compute_mock_relation_parameters(); +// ExtendedEdges extended_edges; +// std::array, NUM_POLYNOMIALS> input_polynomials; + +// // input_univariates are random polynomials of degree one +// for (size_t i = 0; i < NUM_POLYNOMIALS; ++i) { +// input_polynomials[i] = Univariate({ FF::random_element(), FF::random_element() +// }); +// } +// compute_mock_extended_edges(extended_edges, input_polynomials); + +// auto relation = LookupGrandProductComputationRelation(); + +// const auto eta = relation_parameters.eta; +// const auto beta = relation_parameters.beta; +// const auto gamma = relation_parameters.gamma; +// auto grand_product_delta = relation_parameters.lookup_grand_product_delta; + +// // Extract the extended edges for manual computation of relation contribution +// auto one_plus_beta = FF::one() + beta; +// auto gamma_by_one_plus_beta = gamma * one_plus_beta; +// auto eta_sqr = eta * eta; +// auto eta_cube = eta_sqr * eta; + +// const auto& w_1 = extended_edges.w_l; +// const auto& w_2 = extended_edges.w_r; +// const auto& w_3 = extended_edges.w_o; + +// const auto& w_1_shift = extended_edges.w_l_shift; +// const auto& w_2_shift = extended_edges.w_r_shift; +// const auto& w_3_shift = extended_edges.w_o_shift; + +// const auto& table_1 = extended_edges.table_1; +// const auto& table_2 = extended_edges.table_2; +// const auto& table_3 = extended_edges.table_3; +// const auto& table_4 = extended_edges.table_4; + +// const auto& table_1_shift = extended_edges.table_1_shift; +// const auto& table_2_shift = extended_edges.table_2_shift; +// const auto& table_3_shift = extended_edges.table_3_shift; +// const auto& table_4_shift = extended_edges.table_4_shift; + +// const auto& s_accum = extended_edges.sorted_accum; +// const auto& s_accum_shift = extended_edges.sorted_accum_shift; +// const auto& z_lookup = extended_edges.z_lookup; +// const auto& z_lookup_shift = extended_edges.z_lookup_shift; + +// const auto& table_index = extended_edges.q_o; +// const auto& column_1_step_size = extended_edges.q_r; +// const auto& column_2_step_size = extended_edges.q_m; +// const auto& column_3_step_size = extended_edges.q_c; +// const auto& q_lookup = extended_edges.q_lookup; + +// const auto& lagrange_first = extended_edges.lagrange_first; +// const auto& lagrange_last = extended_edges.lagrange_last; + +// auto wire_accum = (w_1 + column_1_step_size * w_1_shift) + (w_2 + column_2_step_size * w_2_shift) * eta + +// (w_3 + column_3_step_size * w_3_shift) * eta_sqr + table_index * eta_cube; + +// auto table_accum = table_1 + table_2 * eta + table_3 * eta_sqr + table_4 * eta_cube; +// auto table_accum_shift = table_1_shift + table_2_shift * eta + table_3_shift * eta_sqr + table_4_shift * +// eta_cube; + +// // Compute the expected result using a simple to read version of the relation expression +// auto expected_evals = (z_lookup + lagrange_first) * (q_lookup * wire_accum + gamma) * +// (table_accum + table_accum_shift * beta + gamma_by_one_plus_beta) * one_plus_beta; +// expected_evals -= (z_lookup_shift + lagrange_last * grand_product_delta) * +// (s_accum + s_accum_shift * beta + gamma_by_one_plus_beta); + +// validate_evaluations(expected_evals, relation, extended_edges, relation_parameters); +// }; + +// TEST_F(UltraRelationConsistency, LookupGrandProductInitializationRelation) +// { +// using Flavor = honk::flavor::Ultra; +// using FF = typename Flavor::FF; +// using Flavor = honk::flavor::Ultra; +// static constexpr size_t FULL_RELATION_LENGTH = 6; +// using ExtendedEdges = typename Flavor::ExtendedEdges; +// static const size_t NUM_POLYNOMIALS = Flavor::NUM_ALL_ENTITIES; +// auto relation_parameters = compute_mock_relation_parameters(); +// ExtendedEdges extended_edges; +// std::array, NUM_POLYNOMIALS> input_polynomials; + +// // input_univariates are random polynomials of degree one +// for (size_t i = 0; i < NUM_POLYNOMIALS; ++i) { +// input_polynomials[i] = Univariate({ FF::random_element(), FF::random_element() +// }); +// } +// compute_mock_extended_edges(extended_edges, input_polynomials); + +// auto relation = LookupGrandProductInitializationRelation(); + +// // Extract the extended edges for manual computation of relation contribution +// const auto& z_lookup_shift = extended_edges.z_lookup_shift; +// const auto& lagrange_last = extended_edges.lagrange_last; + +// // Compute the expected result using a simple to read version of the relation expression +// auto expected_evals = z_lookup_shift * lagrange_last; + +// validate_evaluations(expected_evals, relation, extended_edges, relation_parameters); +// }; + +// TEST_F(UltraRelationConsistency, GenPermSortRelation) +// { +// using Flavor = honk::flavor::Ultra; +// using FF = typename Flavor::FF; +// using Flavor = honk::flavor::Ultra; +// static constexpr size_t FULL_RELATION_LENGTH = 6; +// using ExtendedEdges = typename Flavor::ExtendedEdges; +// static const size_t NUM_POLYNOMIALS = Flavor::NUM_ALL_ENTITIES; +// auto relation_parameters = compute_mock_relation_parameters(); +// ExtendedEdges extended_edges; +// std::array, NUM_POLYNOMIALS> input_polynomials; + +// // input_univariates are random polynomials of degree one +// for (size_t i = 0; i < NUM_POLYNOMIALS; ++i) { +// input_polynomials[i] = Univariate({ FF::random_element(), FF::random_element() +// }); +// } +// compute_mock_extended_edges(extended_edges, input_polynomials); + +// auto relation = GenPermSortRelation(); + +// // Extract the extended edges for manual computation of relation contribution +// const auto& z_lookup_shift = extended_edges.z_lookup_shift; +// const auto& lagrange_last = extended_edges.lagrange_last; + +// const auto& w_1 = extended_edges.w_l; +// const auto& w_2 = extended_edges.w_r; +// const auto& w_3 = extended_edges.w_o; +// const auto& w_4 = extended_edges.w_4; +// const auto& w_1_shift = extended_edges.w_l_shift; +// const auto& q_sort = extended_edges.q_sort; + +// static const FF fake_alpha_1 = FF(1); +// static const FF fake_alpha_2 = fake_alpha_1 * fake_alpha_1; +// static const FF fake_alpha_3 = fake_alpha_2 * fake_alpha_1; +// static const FF fake_alpha_4 = fake_alpha_3 * fake_alpha_1; + +// // Compute wire differences +// auto delta_1 = w_2 - w_1; +// auto delta_2 = w_3 - w_2; +// auto delta_3 = w_4 - w_3; +// auto delta_4 = w_1_shift - w_4; + +// // Compute the expected result using a simple to read version of the relation expression +// auto expected_evals = delta_1 * (delta_1 - 1) * (delta_1 - 2) * (delta_1 - 3) * fake_alpha_1; +// expected_evals += delta_2 * (delta_2 - 1) * (delta_2 - 2) * (delta_2 - 3) * fake_alpha_2; +// expected_evals += delta_3 * (delta_3 - 1) * (delta_3 - 2) * (delta_3 - 3) * fake_alpha_3; +// expected_evals += delta_4 * (delta_4 - 1) * (delta_4 - 2) * (delta_4 - 3) * fake_alpha_4; +// expected_evals *= q_sort; + +// validate_evaluations(expected_evals, relation, extended_edges, relation_parameters); +// }; + +// TEST_F(UltraRelationConsistency, EllipticRelation) +// { +// using Flavor = honk::flavor::Ultra; +// using FF = typename Flavor::FF; +// using Flavor = honk::flavor::Ultra; +// static constexpr size_t FULL_RELATION_LENGTH = 6; +// using ExtendedEdges = typename Flavor::ExtendedEdges; +// static const size_t NUM_POLYNOMIALS = Flavor::NUM_ALL_ENTITIES; +// auto relation_parameters = compute_mock_relation_parameters(); +// ExtendedEdges extended_edges; +// std::array, NUM_POLYNOMIALS> input_polynomials; + +// // input_univariates are random polynomials of degree one +// for (size_t i = 0; i < NUM_POLYNOMIALS; ++i) { +// input_polynomials[i] = Univariate({ FF::random_element(), FF::random_element() +// }); +// } +// compute_mock_extended_edges(extended_edges, input_polynomials); + +// auto relation = EllipticRelation(); + +// // Extract the extended edges for manual computation of relation contribution +// const auto& x_1 = extended_edges.w_r; +// const auto& y_1 = extended_edges.w_o; + +// const auto& x_2 = extended_edges.w_l_shift; +// const auto& y_2 = extended_edges.w_4_shift; +// const auto& x_3 = extended_edges.w_r_shift; +// const auto& y_3 = extended_edges.w_o_shift; + +// const auto& q_sign = extended_edges.q_l; +// const auto& q_beta = extended_edges.q_o; +// const auto& q_beta_sqr = extended_edges.q_4; +// const auto& q_elliptic = extended_edges.q_elliptic; + +// static const FF fake_alpha_1 = FF(1); +// static const FF fake_alpha_2 = fake_alpha_1 * fake_alpha_1; + +// // Compute x/y coordinate identities +// auto x_identity = q_sign * (y_1 * y_2 * 2); +// x_identity += q_beta * (x_1 * x_2 * x_3 * 2 + x_1 * x_1 * x_2) * FF(-1); +// x_identity += q_beta_sqr * (x_2 * x_2 * x_3 - x_1 * x_2 * x_2); +// x_identity += (x_1 * x_1 * x_3 - y_2 * y_2 - y_1 * y_1 + x_2 * x_2 * x_2 + x_1 * x_1 * x_1); + +// auto y_identity = q_sign * (y_2 * x_3 - y_2 * x_1); +// y_identity += q_beta * (x_2 * y_3 + y_1 * x_2); +// y_identity += (x_1 * y_1 - x_1 * y_3 - y_1 * x_3 - x_1 * y_1); + +// auto expected_evals = x_identity * fake_alpha_1 + y_identity * fake_alpha_2; +// expected_evals *= q_elliptic; + +// validate_evaluations(expected_evals, relation, extended_edges, relation_parameters); +// }; + +// TEST_F(UltraRelationConsistency, AuxiliaryRelation) +// { +// using Flavor = honk::flavor::Ultra; +// using FF = typename Flavor::FF; +// using Flavor = honk::flavor::Ultra; +// static constexpr size_t FULL_RELATION_LENGTH = 6; +// using ExtendedEdges = typename Flavor::ExtendedEdges; +// static const size_t NUM_POLYNOMIALS = Flavor::NUM_ALL_ENTITIES; +// auto relation_parameters = compute_mock_relation_parameters(); +// ExtendedEdges extended_edges; +// std::array, NUM_POLYNOMIALS> input_polynomials; + +// // input_univariates are random polynomials of degree one +// for (size_t i = 0; i < NUM_POLYNOMIALS; ++i) { +// input_polynomials[i] = Univariate({ FF::random_element(), FF::random_element() +// }); +// } +// compute_mock_extended_edges(extended_edges, input_polynomials); + +// auto relation = AuxiliaryRelation(); + +// const auto& eta = relation_parameters.eta; +// const auto fake_alpha = FF(1); + +// // Extract the extended edges for manual computation of relation contribution +// const auto& w_1 = extended_edges.w_l; +// const auto& w_2 = extended_edges.w_r; +// const auto& w_3 = extended_edges.w_o; +// const auto& w_4 = extended_edges.w_4; +// const auto& w_1_shift = extended_edges.w_l_shift; +// const auto& w_2_shift = extended_edges.w_r_shift; +// const auto& w_3_shift = extended_edges.w_o_shift; +// const auto& w_4_shift = extended_edges.w_4_shift; + +// const auto& q_1 = extended_edges.q_l; +// const auto& q_2 = extended_edges.q_r; +// const auto& q_3 = extended_edges.q_o; +// const auto& q_4 = extended_edges.q_4; +// const auto& q_m = extended_edges.q_m; +// const auto& q_c = extended_edges.q_c; +// const auto& q_arith = extended_edges.q_arith; +// const auto& q_aux = extended_edges.q_aux; + +// constexpr FF LIMB_SIZE(uint256_t(1) << 68); +// constexpr FF SUBLIMB_SHIFT(uint256_t(1) << 14); +// constexpr FF SUBLIMB_SHIFT_2(SUBLIMB_SHIFT * SUBLIMB_SHIFT); +// constexpr FF SUBLIMB_SHIFT_3(SUBLIMB_SHIFT_2 * SUBLIMB_SHIFT); +// constexpr FF SUBLIMB_SHIFT_4(SUBLIMB_SHIFT_3 * SUBLIMB_SHIFT); + +// /** +// * Non native field arithmetic gate 2 +// * +// * _ _ +// * / _ _ _ 14 \ +// * q_2 . q_4 | (w_1 . w_2) + (w_1 . w_2) + (w_1 . w_4 + w_2 . w_3 - w_3) . 2 - w_3 - w_4 | +// * \_ _/ +// * +// **/ +// auto limb_subproduct = w_1 * w_2_shift + w_1_shift * w_2; +// auto non_native_field_gate_2 = (w_1 * w_4 + w_2 * w_3 - w_3_shift); +// non_native_field_gate_2 *= LIMB_SIZE; +// non_native_field_gate_2 -= w_4_shift; +// non_native_field_gate_2 += limb_subproduct; +// non_native_field_gate_2 *= q_4; + +// limb_subproduct *= LIMB_SIZE; +// limb_subproduct += (w_1_shift * w_2_shift); +// auto non_native_field_gate_1 = limb_subproduct; +// non_native_field_gate_1 -= (w_3 + w_4); +// non_native_field_gate_1 *= q_3; + +// auto non_native_field_gate_3 = limb_subproduct; +// non_native_field_gate_3 += w_4; +// non_native_field_gate_3 -= (w_3_shift + w_4_shift); +// non_native_field_gate_3 *= q_m; + +// auto non_native_field_identity = non_native_field_gate_1 + non_native_field_gate_2 + non_native_field_gate_3; +// non_native_field_identity *= q_2; + +// auto limb_accumulator_1 = w_1 + w_2 * SUBLIMB_SHIFT + w_3 * SUBLIMB_SHIFT_2 + w_1_shift * SUBLIMB_SHIFT_3 + +// w_2_shift * SUBLIMB_SHIFT_4 - w_4; +// limb_accumulator_1 *= q_4; + +// auto limb_accumulator_2 = w_3 + w_4 * SUBLIMB_SHIFT + w_1_shift * SUBLIMB_SHIFT_2 + w_2_shift * SUBLIMB_SHIFT_3 + +// w_3_shift * SUBLIMB_SHIFT_4 - w_4_shift; +// limb_accumulator_2 *= q_m; + +// auto limb_accumulator_identity = limb_accumulator_1 + limb_accumulator_2; +// limb_accumulator_identity *= q_3; + +// /** +// * MEMORY +// **/ + +// /** +// * Memory Record Check +// */ +// auto memory_record_check = w_3; +// memory_record_check *= eta; +// memory_record_check += w_2; +// memory_record_check *= eta; +// memory_record_check += w_1; +// memory_record_check *= eta; +// memory_record_check += q_c; +// auto partial_record_check = memory_record_check; // used in RAM consistency check +// memory_record_check = memory_record_check - w_4; + +// /** +// * ROM Consistency Check +// */ +// auto index_delta = w_1_shift - w_1; +// auto record_delta = w_4_shift - w_4; + +// auto index_is_monotonically_increasing = index_delta * index_delta - index_delta; + +// // auto adjacent_values_match_if_adjacent_indices_match = (FF(1) - index_delta) * record_delta; +// auto adjacent_values_match_if_adjacent_indices_match = (index_delta * FF(-1) + FF(1)) * record_delta; + +// auto ROM_consistency_check_identity = adjacent_values_match_if_adjacent_indices_match; +// ROM_consistency_check_identity *= fake_alpha; +// ROM_consistency_check_identity += index_is_monotonically_increasing; +// ROM_consistency_check_identity *= fake_alpha; +// ROM_consistency_check_identity += memory_record_check; + +// /** +// * RAM Consistency Check +// */ +// auto access_type = (w_4 - partial_record_check); // will be 0 or 1 for honest Prover +// auto access_check = access_type * access_type - access_type; // check value is 0 or 1 + +// auto next_gate_access_type = w_3_shift; +// next_gate_access_type *= eta; +// next_gate_access_type += w_2_shift; +// next_gate_access_type *= eta; +// next_gate_access_type += w_1_shift; +// next_gate_access_type *= eta; +// next_gate_access_type = w_4_shift - next_gate_access_type; + +// auto value_delta = w_3_shift - w_3; +// auto adjacent_values_match_if_adjacent_indices_match_and_next_access_is_a_read_operation = +// (index_delta * FF(-1) + FF(1)) * value_delta * (next_gate_access_type * FF(-1) + FF(1)); + +// // We can't apply the RAM consistency check identity on the final entry in the sorted list (the wires in the +// // next gate would make the identity fail). +// // We need to validate that its 'access type' bool is correct. Can't do +// // with an arithmetic gate because of the `eta` factors. We need to check that the *next* gate's access type is +// // correct, to cover this edge case +// auto next_gate_access_type_is_boolean = next_gate_access_type * next_gate_access_type - next_gate_access_type; + +// // Putting it all together... +// auto RAM_consistency_check_identity = +// adjacent_values_match_if_adjacent_indices_match_and_next_access_is_a_read_operation; +// RAM_consistency_check_identity *= fake_alpha; +// RAM_consistency_check_identity += index_is_monotonically_increasing; +// RAM_consistency_check_identity *= fake_alpha; +// RAM_consistency_check_identity += next_gate_access_type_is_boolean; +// RAM_consistency_check_identity *= fake_alpha; +// RAM_consistency_check_identity += access_check; + +// /** +// * RAM Timestamp Consistency Check +// */ +// auto timestamp_delta = w_2_shift - w_2; +// auto RAM_timestamp_check_identity = (index_delta * FF(-1) + FF(1)) * timestamp_delta - w_3; + +// /** +// * The complete RAM/ROM memory identity +// */ +// auto memory_identity = ROM_consistency_check_identity * q_2; +// memory_identity += RAM_timestamp_check_identity * q_4; +// memory_identity += memory_record_check * q_m; +// memory_identity *= q_1; +// memory_identity += (RAM_consistency_check_identity * q_arith); + +// auto expected_evals = memory_identity + non_native_field_identity + limb_accumulator_identity; +// expected_evals *= q_aux; + +// validate_evaluations(expected_evals, relation, extended_edges, relation_parameters); +// }; + +// } // namespace proof_system::honk_relation_tests diff --git a/cpp/src/barretenberg/honk/sumcheck/sumcheck.test.cpp b/cpp/src/barretenberg/honk/sumcheck/sumcheck.test.cpp index 356ad662b9..6f21137279 100644 --- a/cpp/src/barretenberg/honk/sumcheck/sumcheck.test.cpp +++ b/cpp/src/barretenberg/honk/sumcheck/sumcheck.test.cpp @@ -3,8 +3,7 @@ #include "barretenberg/honk/flavor/standard.hpp" #include "barretenberg/transcript/transcript_wrappers.hpp" #include "relations/arithmetic_relation.hpp" -#include "relations/grand_product_computation_relation.hpp" -#include "relations/grand_product_initialization_relation.hpp" +#include "relations/permutation_relation.hpp" #include "barretenberg/transcript/manifest.hpp" #include #include @@ -138,11 +137,8 @@ TEST(Sumcheck, PolynomialNormalization) auto transcript = ProverTranscript::init_empty(); - auto sumcheck = Sumcheck, - ArithmeticRelation, - GrandProductComputationRelation, - GrandProductInitializationRelation>(multivariate_n, transcript); + auto sumcheck = + Sumcheck, ArithmeticRelation, PermutationRelation>(multivariate_n, transcript); auto [multivariate_challenge, evaluations] = sumcheck.execute_prover(full_polynomials, {}); @@ -154,8 +150,8 @@ TEST(Sumcheck, PolynomialNormalization) * sumcheck.multivariates.folded_polynoimals[i][0] is the evaluatioin of the i'th multivariate at the vector of challenges u_i. What does this mean? - Here we show that if the multivariate is F(X0, X1, X2) defined as above, then what we get is F(u0, u1, u2) and not, - say F(u2, u1, u0). This is in accordance with Adrian's thesis (cf page 9). + Here we show that if the multivariate is F(X0, X1, X2) defined as above, then what we get is F(u0, u1, u2) and + not, say F(u2, u1, u0). This is in accordance with Adrian's thesis (cf page 9). */ // Get the values of the Lagrange basis polys L_i defined @@ -238,11 +234,8 @@ TEST(Sumcheck, Prover) auto transcript = ProverTranscript::init_empty(); - auto sumcheck = Sumcheck, - ArithmeticRelation, - GrandProductComputationRelation, - GrandProductInitializationRelation>(multivariate_n, transcript); + auto sumcheck = + Sumcheck, ArithmeticRelation, PermutationRelation>(multivariate_n, transcript); auto [multivariate_challenge, evaluations] = sumcheck.execute_prover(full_polynomials, {}); FF u_0 = multivariate_challenge[0]; @@ -319,21 +312,15 @@ TEST(Sumcheck, ProverAndVerifier) auto prover_transcript = ProverTranscript::init_empty(); - auto sumcheck_prover = Sumcheck, - ArithmeticRelation, - GrandProductComputationRelation, - GrandProductInitializationRelation>(multivariate_n, prover_transcript); + auto sumcheck_prover = Sumcheck, ArithmeticRelation, PermutationRelation>( + multivariate_n, prover_transcript); auto prover_output = sumcheck_prover.execute_prover(full_polynomials, relation_parameters); auto verifier_transcript = VerifierTranscript::init_empty(prover_transcript); - auto sumcheck_verifier = Sumcheck, - ArithmeticRelation, - GrandProductComputationRelation, - GrandProductInitializationRelation>(multivariate_n, verifier_transcript); + auto sumcheck_verifier = Sumcheck, ArithmeticRelation, PermutationRelation>( + multivariate_n, verifier_transcript); std::optional verifier_output = sumcheck_verifier.execute_verifier(relation_parameters); @@ -401,21 +388,15 @@ TEST(Sumcheck, ProverAndVerifierLonger) auto prover_transcript = ProverTranscript::init_empty(); - auto sumcheck_prover = Sumcheck, - ArithmeticRelation, - GrandProductComputationRelation, - GrandProductInitializationRelation>(multivariate_n, prover_transcript); + auto sumcheck_prover = Sumcheck, ArithmeticRelation, PermutationRelation>( + multivariate_n, prover_transcript); auto prover_output = sumcheck_prover.execute_prover(full_polynomials, relation_parameters); auto verifier_transcript = VerifierTranscript::init_empty(prover_transcript); - auto sumcheck_verifier = Sumcheck, - ArithmeticRelation, - GrandProductComputationRelation, - GrandProductInitializationRelation>(multivariate_n, verifier_transcript); + auto sumcheck_verifier = Sumcheck, ArithmeticRelation, PermutationRelation>( + multivariate_n, verifier_transcript); std::optional verifier_output = sumcheck_verifier.execute_verifier(relation_parameters); diff --git a/cpp/src/barretenberg/honk/sumcheck/sumcheck_round.hpp b/cpp/src/barretenberg/honk/sumcheck/sumcheck_round.hpp index 0aea53047f..1df35bf24e 100644 --- a/cpp/src/barretenberg/honk/sumcheck/sumcheck_round.hpp +++ b/cpp/src/barretenberg/honk/sumcheck/sumcheck_round.hpp @@ -61,6 +61,9 @@ template class... Relations> class SumcheckRo using ExtendedEdges = typename Flavor::template ExtendedEdges; using PurportedEvaluations = typename Flavor::PurportedEvaluations; + using RelationUnivariates = std::tuple::RelationUnivariates...>; + using RelationEvaluations = std::tuple::RelationValues...>; + bool round_failed = false; size_t round_size; // a power of 2 @@ -70,12 +73,9 @@ template class... Relations> class SumcheckRo FF target_total_sum = 0; - // TODO(#224)(Cody): this barycentric stuff should be more built-in? - std::tuple::RELATION_LENGTH, MAX_RELATION_LENGTH>...> barycentric_utils; - std::tuple::RELATION_LENGTH>...> univariate_accumulators; - std::array relation_evaluations; + RelationUnivariates univariate_accumulators; + RelationEvaluations relation_evaluations; ExtendedEdges extended_edges; - std::array, NUM_RELATIONS> extended_univariates; // TODO(#224)(Cody): this should go away and we should use constexpr method to extend BarycentricData barycentric_2_to_max = BarycentricData(); @@ -84,69 +84,37 @@ template class... Relations> class SumcheckRo SumcheckRound(size_t initial_round_size, auto&& relations) : round_size(initial_round_size) , relations(relations) - , barycentric_utils(BarycentricData::RELATION_LENGTH, MAX_RELATION_LENGTH>()...) - , univariate_accumulators(Univariate::RELATION_LENGTH>()...) - {} + { + zero_univariates(univariate_accumulators); + } // Verifier constructor explicit SumcheckRound(auto relations) : relations(relations) { - // FF's default constructor may not initialize to zero (e.g., barretenberg::fr), hence we can't rely on - // aggregate initialization of the evaluations array. - std::fill(relation_evaluations.begin(), relation_evaluations.end(), FF(0)); - }; - - /** - * @brief After computing the round univariate, it is necessary to zero-out the accumulators used to compute it. - */ - template void reset_accumulators() - { - auto& univariate = std::get(univariate_accumulators); - std::fill(univariate.evaluations.begin(), univariate.evaluations.end(), FF(0)); - - if constexpr (idx + 1 < NUM_RELATIONS) { - reset_accumulators(); - } - }; - // IMPROVEMENT(Cody): This is kind of ugly. There should be a one-liner with folding - // or std::apply or something. - - /** - * @brief Given a tuple t = (t_0, t_1, ..., t_{NUM_RELATIONS-1}) and a challenge α, - * modify the tuple in place to (t_0, αt_1, ..., α^{NUM_RELATIONS-1}t_{NUM_RELATIONS-1}). - */ - template void scale_tuple(auto& tuple, FF challenge, FF running_challenge) - { - std::get(tuple) *= running_challenge; - running_challenge *= challenge; - if constexpr (idx + 1 < NUM_RELATIONS) { - scale_tuple(tuple, challenge, running_challenge); - } + zero_elements(relation_evaluations); }; /** * @brief Given a tuple t = (t_0, t_1, ..., t_{NUM_RELATIONS-1}) and a challenge α, * return t_0 + αt_1 + ... + α^{NUM_RELATIONS-1}t_{NUM_RELATIONS-1}). * - * @tparam T : In practice, this is an FF or a Univariate. + * @tparam T : In practice, this is a Univariate. */ - template T batch_over_relations(FF challenge) + Univariate batch_over_relations(FF challenge) { FF running_challenge = 1; - scale_tuple<>(univariate_accumulators, challenge, running_challenge); - extend_univariate_accumulators<>(); - auto result = T(); - for (size_t i = 0; i < NUM_RELATIONS; ++i) { - result += extended_univariates[i]; - } + scale_univariates(univariate_accumulators, challenge, running_challenge); + + auto result = Univariate(); + extend_and_batch_univariates(univariate_accumulators, result); + + zero_univariates(univariate_accumulators); return result; } /** - * @brief Evaluate some relations by evaluating each edge in the edge group at - * Univariate::length-many values. Store each value separately in the corresponding - * entry of relation_evals. + * @brief Extend each edge in the edge group at to max-relation-length-many values. * * @details Should only be called externally with relation_idx equal to 0. * In practice, multivariates is one of ProverPolynomials or FoldedPolynomials. @@ -162,23 +130,6 @@ template class... Relations> class SumcheckRo } } - /** - * @brief After executing each widget on each edge, producing a tuple of univariates of differing lenghths, - * extend all univariates to the max of the lenghths required by the largest relation. - * - * @tparam relation_idx - */ - template void extend_univariate_accumulators() - { - extended_univariates[relation_idx] = - std::get(barycentric_utils).extend(std::get(univariate_accumulators)); - - // Repeat for the next relation. - if constexpr (relation_idx + 1 < NUM_RELATIONS) { - extend_univariate_accumulators(); - } - } - /** * @brief Return the evaluations of the univariate restriction (S_l(X_l) in the thesis) at num_multivariates-many * values. Most likely this will end up being S_l(0), ... , S_l(t-1) where t is around 12. At the end, reset all @@ -203,11 +154,7 @@ template class... Relations> class SumcheckRo pow_challenge *= pow_univariate.zeta_pow_sqr; } - auto result = batch_over_relations>(alpha); - - reset_accumulators<>(); - - return result; + return batch_over_relations(alpha); } /** @@ -225,13 +172,10 @@ template class... Relations> class SumcheckRo { accumulate_relation_evaluations<>(purported_evaluations, relation_parameters); - // IMPROVEMENT(Cody): Reuse functions from univariate_accumulators batching? - FF running_challenge = 1; - FF output = 0; - for (auto& evals : relation_evaluations) { - output += evals * running_challenge; - running_challenge *= alpha; - } + auto running_challenge = FF(1); + auto output = FF(0); + scale_and_batch_elements(relation_evaluations, alpha, running_challenge, output); + output *= pow_univariate.partial_evaluation_constant; return output; @@ -320,12 +264,143 @@ template class... Relations> class SumcheckRo const RelationParameters& relation_parameters) { std::get(relations).add_full_relation_value_contribution( - relation_evaluations[relation_idx], purported_evaluations, relation_parameters); + std::get(relation_evaluations), purported_evaluations, relation_parameters); // Repeat for the next relation. if constexpr (relation_idx + 1 < NUM_RELATIONS) { accumulate_relation_evaluations(purported_evaluations, relation_parameters); } } + + // WORKTODO: make these private (need to make test suite a friend?) + public: + /** + * Utility methods for tuple of tuples of Univariates + */ + + /** + * @brief Extend Univariates to specified size then sum them + * + * @tparam extended_size Size after extension + * @param tuple A tuple of tuples of Univariates + * @param result A Univariate of length extended_size + */ + template + static void extend_and_batch_univariates(auto& tuple, Univariate& result) + { + auto extend_and_sum = [&](auto& element) { + using Element = std::remove_reference_t; + // TODO(#224)(Cody): this barycentric stuff should be more built-in? + BarycentricData barycentric_utils; + result += barycentric_utils.extend(element); + }; + apply_to_tuple_of_tuples(tuple, extend_and_sum); + } + + /** + * @brief Set all coefficients of Univariates to zero + * + * @details After computing the round univariate, it is necessary to zero-out the accumulators used to compute it. + */ + static void zero_univariates(auto& tuple) + { + auto set_to_zero = [](auto& element) { + std::fill(element.evaluations.begin(), element.evaluations.end(), FF(0)); + }; + apply_to_tuple_of_tuples(tuple, set_to_zero); + } + + /** + * @brief Scale Univaraites by consecutive powers of the provided challenge + * + * @param tuple Tuple of tuples of Univariates + * @param challenge + * @param current_scalar power of the challenge + */ + static void scale_univariates(auto& tuple, const FF& challenge, FF current_scalar) + { + auto scale_by_consecutive_powers_of_challenge = [&](auto& element) { + element *= current_scalar; + current_scalar *= challenge; + }; + apply_to_tuple_of_tuples(tuple, scale_by_consecutive_powers_of_challenge); + } + + /** + * @brief General purpose method for applying an operation to a tuple of tuples of Univariates + * + * @tparam Operation Any operation valid on Univariates + * @tparam outer_idx Index into the outer tuple + * @tparam inner_idx Index into the inner tuple + * @param tuple A Tuple of tuples of Univariates + * @param operation Operation to apply to Univariates + */ + template + static void apply_to_tuple_of_tuples(auto& tuple, Operation&& operation) + { + auto& inner_tuple = std::get(tuple); + auto& univariate = std::get(inner_tuple); + + // Apply the specified operation to each Univariate + std::invoke(std::forward(operation), univariate); + + const size_t inner_size = std::tuple_size_v(tuple))>>; + const size_t outer_size = std::tuple_size_v>; + + // Recurse over inner and outer tuples + if constexpr (inner_idx + 1 < inner_size) { + apply_to_tuple_of_tuples(tuple, std::forward(operation)); + } else if constexpr (outer_idx + 1 < outer_size) { + apply_to_tuple_of_tuples(tuple, std::forward(operation)); + } + } + + /** + * Utility methods for tuple of arrays + */ + + /** + * @brief Set each element in a tuple of arrays to zero. + * @details FF's default constructor may not initialize to zero (e.g., barretenberg::fr), hence we can't rely on + * aggregate initialization of the evaluations array. + */ + template static void zero_elements(auto& tuple) + { + auto set_to_zero = [](auto& element) { std::fill(element.begin(), element.end(), FF(0)); }; + apply_to_tuple_of_arrays(set_to_zero, tuple); + }; + + /** + * @brief Scale elements by consecutive powers of the challenge then sum + * @param result Batched result + */ + static void scale_and_batch_elements(auto& tuple, const FF& challenge, FF current_scalar, FF& result) + { + auto scale_by_challenge_and_accumulate = [&](auto& element) { + for (auto& entry : element) { + result += entry * current_scalar; + current_scalar *= challenge; + } + }; + apply_to_tuple_of_arrays(scale_by_challenge_and_accumulate, tuple); + } + + /** + * @brief General purpose method for applying a tuple of arrays (of FFs) + * + * @tparam Operation Any operation valid on elements of the inner arrays (FFs) + * @param tuple Tuple of arrays (of FFs) + */ + template + static void apply_to_tuple_of_arrays(Operation&& operation, std::tuple& tuple) + { + auto& element = std::get(tuple); + + std::invoke(std::forward(operation), element); + + if constexpr (idx + 1 < sizeof...(Ts)) { + apply_to_tuple_of_arrays(operation, tuple); + } + } }; } // namespace proof_system::honk::sumcheck diff --git a/cpp/src/barretenberg/honk/sumcheck/sumcheck_round.test.cpp b/cpp/src/barretenberg/honk/sumcheck/sumcheck_round.test.cpp index 97fefa6a48..d5afe3ee67 100644 --- a/cpp/src/barretenberg/honk/sumcheck/sumcheck_round.test.cpp +++ b/cpp/src/barretenberg/honk/sumcheck/sumcheck_round.test.cpp @@ -1,343 +1,348 @@ -#include "sumcheck_round.hpp" -#include "relations/arithmetic_relation.hpp" -#include "relations/grand_product_computation_relation.hpp" -#include "relations/grand_product_initialization_relation.hpp" -#include "polynomials/univariate.hpp" -#include "barretenberg/ecc/curves/bn254/fr.hpp" -#include "barretenberg/numeric/random/engine.hpp" -#include "barretenberg/honk/flavor/standard.hpp" +// #include "sumcheck_round.hpp" +// #include "relations/arithmetic_relation.hpp" +// #include "relations/permutation_relation.hpp" +// #include "polynomials/univariate.hpp" +// #include "barretenberg/ecc/curves/bn254/fr.hpp" +// #include "barretenberg/numeric/random/engine.hpp" +// #include "barretenberg/honk/flavor/standard.hpp" -#include +// #include -#include "barretenberg/common/mem.hpp" -#include -/** - * We want to test if the univariate (S_l in the thesis) computed by the prover in a particular round is correct. We - * also want to verify given the purported evaluations of all the relevant polynomials, the verifer can correctly verify - * the purported evaluation of S_l. For the prover, we use a couple of methods to compute the univariate by the sumcheck - * method `compute_univariate` and by step by step manual computation respectively. For the verifier, we follow a - * similar approach. - */ +// #include "barretenberg/common/mem.hpp" +// #include +// /** +// * We want to test if the univariate (S_l in the thesis) computed by the prover in a particular round is correct. We +// * also want to verify given the purported evaluations of all the relevant polynomials, the verifer can correctly +// verify +// * the purported evaluation of S_l. For the prover, we use a couple of methods to compute the univariate by the +// sumcheck +// * method `compute_univariate` and by step by step manual computation respectively. For the verifier, we follow a +// * similar approach. +// */ -using namespace proof_system::honk; -using namespace proof_system::honk::sumcheck; +// using namespace proof_system::honk; +// using namespace proof_system::honk::sumcheck; -using Flavor = flavor::Standard; -using FF = typename Flavor::FF; -using ProverPolynomials = typename Flavor::ProverPolynomials; -using PurportedEvaluations = typename Flavor::PurportedEvaluations; +// using Flavor = flavor::Standard; +// using FF = typename Flavor::FF; +// using ProverPolynomials = typename Flavor::ProverPolynomials; +// using PurportedEvaluations = typename Flavor::PurportedEvaluations; -const size_t NUM_POLYNOMIALS = Flavor::NUM_ALL_ENTITIES; -const size_t max_relation_length = 5; -const size_t input_polynomial_length = 2; +// const size_t NUM_POLYNOMIALS = Flavor::NUM_ALL_ENTITIES; +// const size_t max_relation_length = 5; +// const size_t input_polynomial_length = 2; -namespace test_sumcheck_round { -template -void construct_full_polynomials(ProverPolynomials& full_polynomials, - std::array& w_l, - std::array& w_r, - std::array& w_o, - std::array& z_perm, - std::array& z_perm_shift, - std::array& q_m, - std::array& q_l, - std::array& q_r, - std::array& q_o, - std::array& q_c, - std::array& sigma_1, - std::array& sigma_2, - std::array& sigma_3, - std::array& id_1, - std::array& id_2, - std::array& id_3, - std::array& lagrange_first, - std::array& lagrange_last) -{ - full_polynomials.w_l = w_l; - full_polynomials.w_r = w_r; - full_polynomials.w_o = w_o; - full_polynomials.z_perm = z_perm; - full_polynomials.z_perm_shift = z_perm_shift; - full_polynomials.q_m = q_m; - full_polynomials.q_l = q_l; - full_polynomials.q_r = q_r; - full_polynomials.q_o = q_o; - full_polynomials.q_c = q_c; - full_polynomials.sigma_1 = sigma_1; - full_polynomials.sigma_2 = sigma_2; - full_polynomials.sigma_3 = sigma_3; - full_polynomials.id_1 = id_1; - full_polynomials.id_2 = id_2; - full_polynomials.id_3 = id_3; - full_polynomials.lagrange_first = lagrange_first; - full_polynomials.lagrange_last = lagrange_last; -} +// namespace test_sumcheck_round { +// template +// void construct_full_polynomials(ProverPolynomials& full_polynomials, +// std::array& w_l, +// std::array& w_r, +// std::array& w_o, +// std::array& z_perm, +// std::array& z_perm_shift, +// std::array& q_m, +// std::array& q_l, +// std::array& q_r, +// std::array& q_o, +// std::array& q_c, +// std::array& sigma_1, +// std::array& sigma_2, +// std::array& sigma_3, +// std::array& id_1, +// std::array& id_2, +// std::array& id_3, +// std::array& lagrange_first, +// std::array& lagrange_last) +// { +// full_polynomials.w_l = w_l; +// full_polynomials.w_r = w_r; +// full_polynomials.w_o = w_o; +// full_polynomials.z_perm = z_perm; +// full_polynomials.z_perm_shift = z_perm_shift; +// full_polynomials.q_m = q_m; +// full_polynomials.q_l = q_l; +// full_polynomials.q_r = q_r; +// full_polynomials.q_o = q_o; +// full_polynomials.q_c = q_c; +// full_polynomials.sigma_1 = sigma_1; +// full_polynomials.sigma_2 = sigma_2; +// full_polynomials.sigma_3 = sigma_3; +// full_polynomials.id_1 = id_1; +// full_polynomials.id_2 = id_2; +// full_polynomials.id_3 = id_3; +// full_polynomials.lagrange_first = lagrange_first; +// full_polynomials.lagrange_last = lagrange_last; +// } -// The below two methods are used in the test ComputeUnivariateProver -static Univariate compute_round_univariate( - std::array, NUM_POLYNOMIALS>& input_polynomials, - const RelationParameters& relation_parameters, - const FF alpha) -{ - size_t round_size = 1; - auto relations = std::tuple( - ArithmeticRelation(), GrandProductComputationRelation(), GrandProductInitializationRelation()); - // Improvement(Cody): This is ugly? Maye supply some/all of this data through "flavor" class? - auto round = - SumcheckRound( - round_size, relations); - auto w_l = input_polynomials[0]; - auto w_r = input_polynomials[1]; - auto w_o = input_polynomials[2]; - auto z_perm = input_polynomials[3]; - auto z_perm_shift = input_polynomials[4]; - auto q_m = input_polynomials[5]; - auto q_l = input_polynomials[6]; - auto q_r = input_polynomials[7]; - auto q_o = input_polynomials[8]; - auto q_c = input_polynomials[9]; - auto sigma_1 = input_polynomials[10]; - auto sigma_2 = input_polynomials[11]; - auto sigma_3 = input_polynomials[12]; - auto id_1 = input_polynomials[13]; - auto id_2 = input_polynomials[14]; - auto id_3 = input_polynomials[15]; - auto lagrange_first = input_polynomials[16]; - auto lagrange_last = input_polynomials[17]; +// // The below two methods are used in the test ComputeUnivariateProver +// static Univariate compute_round_univariate( +// std::array, NUM_POLYNOMIALS>& input_polynomials, +// const RelationParameters& relation_parameters, +// const FF alpha) +// { +// size_t round_size = 1; +// auto relations = std::tuple( +// ArithmeticRelation(), PermutationRelation(), GrandProductInitializationRelation()); +// // Improvement(Cody): This is ugly? Maye supply some/all of this data through "flavor" class? +// auto round = +// SumcheckRound( +// round_size, relations); +// auto w_l = input_polynomials[0]; +// auto w_r = input_polynomials[1]; +// auto w_o = input_polynomials[2]; +// auto z_perm = input_polynomials[3]; +// auto z_perm_shift = input_polynomials[4]; +// auto q_m = input_polynomials[5]; +// auto q_l = input_polynomials[6]; +// auto q_r = input_polynomials[7]; +// auto q_o = input_polynomials[8]; +// auto q_c = input_polynomials[9]; +// auto sigma_1 = input_polynomials[10]; +// auto sigma_2 = input_polynomials[11]; +// auto sigma_3 = input_polynomials[12]; +// auto id_1 = input_polynomials[13]; +// auto id_2 = input_polynomials[14]; +// auto id_3 = input_polynomials[15]; +// auto lagrange_first = input_polynomials[16]; +// auto lagrange_last = input_polynomials[17]; - ProverPolynomials full_polynomials; - construct_full_polynomials(full_polynomials, - w_l, - w_r, - w_o, - z_perm, - z_perm_shift, - q_m, - q_l, - q_r, - q_o, - q_c, - sigma_1, - sigma_2, - sigma_3, - id_1, - id_2, - id_3, - lagrange_first, - lagrange_last); - PowUnivariate pow_zeta(1); - Univariate round_univariate = - round.compute_univariate(full_polynomials, relation_parameters, pow_zeta, alpha); - return round_univariate; -} +// ProverPolynomials full_polynomials; +// construct_full_polynomials(full_polynomials, +// w_l, +// w_r, +// w_o, +// z_perm, +// z_perm_shift, +// q_m, +// q_l, +// q_r, +// q_o, +// q_c, +// sigma_1, +// sigma_2, +// sigma_3, +// id_1, +// id_2, +// id_3, +// lagrange_first, +// lagrange_last); +// PowUnivariate pow_zeta(1); +// Univariate round_univariate = +// round.compute_univariate(full_polynomials, relation_parameters, pow_zeta, alpha); +// return round_univariate; +// } -static Univariate compute_expected_round_univariate( - std::array, NUM_POLYNOMIALS>& input_univariates, - const RelationParameters& relation_parameters, - const FF alpha) -{ - BarycentricData barycentric_2_to_max = - BarycentricData(); - std::array, NUM_POLYNOMIALS> extended_univariates; - for (size_t i = 0; i < NUM_POLYNOMIALS; ++i) { - extended_univariates[i] = barycentric_2_to_max.extend(input_univariates[i]); - } - auto w_l_univariate = Univariate(extended_univariates[0]); - auto w_r_univariate = Univariate(extended_univariates[1]); - auto w_o_univariate = Univariate(extended_univariates[2]); - auto z_perm_univariate = Univariate(extended_univariates[3]); - auto z_perm_shift_univariate = - Univariate(extended_univariates[4]); // this is not real shifted data - auto q_m_univariate = Univariate(extended_univariates[5]); - auto q_l_univariate = Univariate(extended_univariates[6]); - auto q_r_univariate = Univariate(extended_univariates[7]); - auto q_o_univariate = Univariate(extended_univariates[8]); - auto q_c_univariate = Univariate(extended_univariates[9]); - auto sigma_1_univariate = Univariate(extended_univariates[10]); - auto sigma_2_univariate = Univariate(extended_univariates[11]); - auto sigma_3_univariate = Univariate(extended_univariates[12]); - auto id_1_univariate = Univariate(extended_univariates[13]); - auto id_2_univariate = Univariate(extended_univariates[14]); - auto id_3_univariate = Univariate(extended_univariates[15]); - auto lagrange_first_univariate = Univariate(extended_univariates[16]); - auto lagrange_last_univariate = Univariate(extended_univariates[17]); +// static Univariate compute_expected_round_univariate( +// std::array, NUM_POLYNOMIALS>& input_univariates, +// const RelationParameters& relation_parameters, +// const FF alpha) +// { +// BarycentricData barycentric_2_to_max = +// BarycentricData(); +// std::array, NUM_POLYNOMIALS> extended_univariates; +// for (size_t i = 0; i < NUM_POLYNOMIALS; ++i) { +// extended_univariates[i] = barycentric_2_to_max.extend(input_univariates[i]); +// } +// auto w_l_univariate = Univariate(extended_univariates[0]); +// auto w_r_univariate = Univariate(extended_univariates[1]); +// auto w_o_univariate = Univariate(extended_univariates[2]); +// auto z_perm_univariate = Univariate(extended_univariates[3]); +// auto z_perm_shift_univariate = +// Univariate(extended_univariates[4]); // this is not real shifted data +// auto q_m_univariate = Univariate(extended_univariates[5]); +// auto q_l_univariate = Univariate(extended_univariates[6]); +// auto q_r_univariate = Univariate(extended_univariates[7]); +// auto q_o_univariate = Univariate(extended_univariates[8]); +// auto q_c_univariate = Univariate(extended_univariates[9]); +// auto sigma_1_univariate = Univariate(extended_univariates[10]); +// auto sigma_2_univariate = Univariate(extended_univariates[11]); +// auto sigma_3_univariate = Univariate(extended_univariates[12]); +// auto id_1_univariate = Univariate(extended_univariates[13]); +// auto id_2_univariate = Univariate(extended_univariates[14]); +// auto id_3_univariate = Univariate(extended_univariates[15]); +// auto lagrange_first_univariate = Univariate(extended_univariates[16]); +// auto lagrange_last_univariate = Univariate(extended_univariates[17]); - auto expected_arithmetic_relation = - ((q_m_univariate * w_r_univariate * w_l_univariate) + (q_r_univariate * w_r_univariate) + - (q_l_univariate * w_l_univariate) + (q_o_univariate * w_o_univariate) + (q_c_univariate)); - auto expected_grand_product_computation_relation = - ((z_perm_univariate + lagrange_first_univariate) * - (w_l_univariate + id_1_univariate * relation_parameters.beta + relation_parameters.gamma) * - (w_r_univariate + id_2_univariate * relation_parameters.beta + relation_parameters.gamma) * - (w_o_univariate + id_3_univariate * relation_parameters.beta + relation_parameters.gamma)); - expected_grand_product_computation_relation -= - ((z_perm_shift_univariate + lagrange_last_univariate * relation_parameters.public_input_delta) * - (w_l_univariate + sigma_1_univariate * relation_parameters.beta + relation_parameters.gamma) * - (w_r_univariate + sigma_2_univariate * relation_parameters.beta + relation_parameters.gamma) * - (w_o_univariate + sigma_3_univariate * relation_parameters.beta + relation_parameters.gamma)); - auto expected_grand_product_initialization_relation = (z_perm_shift_univariate * lagrange_last_univariate); - Univariate expected_round_univariate = - expected_arithmetic_relation + expected_grand_product_computation_relation * alpha + - expected_grand_product_initialization_relation * alpha.sqr(); - return expected_round_univariate; -} +// auto expected_arithmetic_relation = +// ((q_m_univariate * w_r_univariate * w_l_univariate) + (q_r_univariate * w_r_univariate) + +// (q_l_univariate * w_l_univariate) + (q_o_univariate * w_o_univariate) + (q_c_univariate)); +// auto expected_grand_product_computation_relation = +// ((z_perm_univariate + lagrange_first_univariate) * +// (w_l_univariate + id_1_univariate * relation_parameters.beta + relation_parameters.gamma) * +// (w_r_univariate + id_2_univariate * relation_parameters.beta + relation_parameters.gamma) * +// (w_o_univariate + id_3_univariate * relation_parameters.beta + relation_parameters.gamma)); +// expected_grand_product_computation_relation -= +// ((z_perm_shift_univariate + lagrange_last_univariate * relation_parameters.public_input_delta) * +// (w_l_univariate + sigma_1_univariate * relation_parameters.beta + relation_parameters.gamma) * +// (w_r_univariate + sigma_2_univariate * relation_parameters.beta + relation_parameters.gamma) * +// (w_o_univariate + sigma_3_univariate * relation_parameters.beta + relation_parameters.gamma)); +// auto expected_grand_product_initialization_relation = (z_perm_shift_univariate * lagrange_last_univariate); +// Univariate expected_round_univariate = +// expected_arithmetic_relation + expected_grand_product_computation_relation * alpha + +// expected_grand_product_initialization_relation * alpha.sqr(); +// return expected_round_univariate; +// } -// The below two methods are used in the test ComputeUnivariateVerifier -static FF compute_full_purported_value(std::array& input_values, - const RelationParameters& relation_parameters, - const FF alpha) -{ - PurportedEvaluations purported_evaluations; - purported_evaluations.w_l = input_values[0]; - purported_evaluations.w_r = input_values[1]; - purported_evaluations.w_o = input_values[2]; - purported_evaluations.z_perm = input_values[3]; - purported_evaluations.z_perm_shift = input_values[4]; - purported_evaluations.q_m = input_values[5]; - purported_evaluations.q_l = input_values[6]; - purported_evaluations.q_r = input_values[7]; - purported_evaluations.q_o = input_values[8]; - purported_evaluations.q_c = input_values[9]; - purported_evaluations.sigma_1 = input_values[10]; - purported_evaluations.sigma_2 = input_values[11]; - purported_evaluations.sigma_3 = input_values[12]; - purported_evaluations.id_1 = input_values[13]; - purported_evaluations.id_2 = input_values[14]; - purported_evaluations.id_3 = input_values[15]; - purported_evaluations.lagrange_first = input_values[16]; - purported_evaluations.lagrange_last = input_values[17]; - auto relations = std::tuple( - ArithmeticRelation(), GrandProductComputationRelation(), GrandProductInitializationRelation()); - auto round = - SumcheckRound( - relations); - PowUnivariate pow_univariate(1); - FF full_purported_value = round.compute_full_honk_relation_purported_value( - purported_evaluations, relation_parameters, pow_univariate, alpha); - return full_purported_value; -} +// // The below two methods are used in the test ComputeUnivariateVerifier +// static FF compute_full_purported_value(std::array& input_values, +// const RelationParameters& relation_parameters, +// const FF alpha) +// { +// PurportedEvaluations purported_evaluations; +// purported_evaluations.w_l = input_values[0]; +// purported_evaluations.w_r = input_values[1]; +// purported_evaluations.w_o = input_values[2]; +// purported_evaluations.z_perm = input_values[3]; +// purported_evaluations.z_perm_shift = input_values[4]; +// purported_evaluations.q_m = input_values[5]; +// purported_evaluations.q_l = input_values[6]; +// purported_evaluations.q_r = input_values[7]; +// purported_evaluations.q_o = input_values[8]; +// purported_evaluations.q_c = input_values[9]; +// purported_evaluations.sigma_1 = input_values[10]; +// purported_evaluations.sigma_2 = input_values[11]; +// purported_evaluations.sigma_3 = input_values[12]; +// purported_evaluations.id_1 = input_values[13]; +// purported_evaluations.id_2 = input_values[14]; +// purported_evaluations.id_3 = input_values[15]; +// purported_evaluations.lagrange_first = input_values[16]; +// purported_evaluations.lagrange_last = input_values[17]; +// auto relations = std::tuple( +// ArithmeticRelation(), PermutationRelation(), GrandProductInitializationRelation()); +// auto round = +// SumcheckRound( +// relations); +// PowUnivariate pow_univariate(1); +// FF full_purported_value = round.compute_full_honk_relation_purported_value( +// purported_evaluations, relation_parameters, pow_univariate, alpha); +// return full_purported_value; +// } -static FF compute_full_purported_value_expected(std::array& input_values, - const RelationParameters& relation_parameters, - const FF alpha) -{ - FF w_l = input_values[0]; - FF w_r = input_values[1]; - FF w_o = input_values[2]; - FF z_perm = input_values[3]; - FF z_perm_shift = input_values[4]; - FF q_m = input_values[5]; - FF q_l = input_values[6]; - FF q_r = input_values[7]; - FF q_o = input_values[8]; - FF q_c = input_values[9]; - FF sigma_1 = input_values[10]; - FF sigma_2 = input_values[11]; - FF sigma_3 = input_values[12]; - FF id_1 = input_values[13]; - FF id_2 = input_values[14]; - FF id_3 = input_values[15]; - FF lagrange_first = input_values[16]; - FF lagrange_last = input_values[17]; - auto expected_arithmetic_relation = (q_m * w_r * w_l) + (q_r * w_r) + (q_l * w_l) + (q_o * w_o) + q_c; - auto expected_grand_product_computation_relation = - (z_perm + lagrange_first) * (w_l + id_1 * relation_parameters.beta + relation_parameters.gamma) * - (w_r + id_2 * relation_parameters.beta + relation_parameters.gamma) * - (w_o + id_3 * relation_parameters.beta + relation_parameters.gamma); - expected_grand_product_computation_relation -= - (z_perm_shift + lagrange_last * relation_parameters.public_input_delta) * - (w_l + sigma_1 * relation_parameters.beta + relation_parameters.gamma) * - (w_r + sigma_2 * relation_parameters.beta + relation_parameters.gamma) * - (w_o + sigma_3 * relation_parameters.beta + relation_parameters.gamma); - auto expected_grand_product_initialization_relation = z_perm_shift * lagrange_last; - auto expected_full_purported_value = expected_arithmetic_relation + - expected_grand_product_computation_relation * alpha + - expected_grand_product_initialization_relation * alpha.sqr(); - return expected_full_purported_value; -} +// static FF compute_full_purported_value_expected(std::array& input_values, +// const RelationParameters& relation_parameters, +// const FF alpha) +// { +// FF w_l = input_values[0]; +// FF w_r = input_values[1]; +// FF w_o = input_values[2]; +// FF z_perm = input_values[3]; +// FF z_perm_shift = input_values[4]; +// FF q_m = input_values[5]; +// FF q_l = input_values[6]; +// FF q_r = input_values[7]; +// FF q_o = input_values[8]; +// FF q_c = input_values[9]; +// FF sigma_1 = input_values[10]; +// FF sigma_2 = input_values[11]; +// FF sigma_3 = input_values[12]; +// FF id_1 = input_values[13]; +// FF id_2 = input_values[14]; +// FF id_3 = input_values[15]; +// FF lagrange_first = input_values[16]; +// FF lagrange_last = input_values[17]; +// auto expected_arithmetic_relation = (q_m * w_r * w_l) + (q_r * w_r) + (q_l * w_l) + (q_o * w_o) + q_c; +// auto expected_grand_product_computation_relation = +// (z_perm + lagrange_first) * (w_l + id_1 * relation_parameters.beta + relation_parameters.gamma) * +// (w_r + id_2 * relation_parameters.beta + relation_parameters.gamma) * +// (w_o + id_3 * relation_parameters.beta + relation_parameters.gamma); +// expected_grand_product_computation_relation -= +// (z_perm_shift + lagrange_last * relation_parameters.public_input_delta) * +// (w_l + sigma_1 * relation_parameters.beta + relation_parameters.gamma) * +// (w_r + sigma_2 * relation_parameters.beta + relation_parameters.gamma) * +// (w_o + sigma_3 * relation_parameters.beta + relation_parameters.gamma); +// auto expected_grand_product_initialization_relation = z_perm_shift * lagrange_last; +// auto expected_full_purported_value = expected_arithmetic_relation + +// expected_grand_product_computation_relation * alpha + +// expected_grand_product_initialization_relation * alpha.sqr(); +// return expected_full_purported_value; +// } -TEST(SumcheckRound, ComputeUnivariateProver) -{ - auto run_test = [](bool is_random_input) { - if (is_random_input) { - std::array, NUM_POLYNOMIALS> input_polynomials; - for (size_t i = 0; i < NUM_POLYNOMIALS; ++i) { - input_polynomials[i] = { FF::random_element(), FF::random_element() }; - } +// TEST(SumcheckRound, ComputeUnivariateProver) +// { +// auto run_test = [](bool is_random_input) { +// if (is_random_input) { +// std::array, NUM_POLYNOMIALS> input_polynomials; +// for (size_t i = 0; i < NUM_POLYNOMIALS; ++i) { +// input_polynomials[i] = { FF::random_element(), FF::random_element() }; +// } - const FF alpha = FF::random_element(); - const RelationParameters relation_parameters = RelationParameters{ - .beta = FF::random_element(), .gamma = FF::random_element(), .public_input_delta = FF::random_element() - }; +// const FF alpha = FF::random_element(); +// const RelationParameters relation_parameters = RelationParameters{ +// .beta = FF::random_element(), .gamma = FF::random_element(), .public_input_delta = +// FF::random_element() +// }; - auto round_univariate = compute_round_univariate(input_polynomials, relation_parameters, alpha); +// auto round_univariate = compute_round_univariate(input_polynomials, relation_parameters, alpha); - // Compute round_univariate manually - std::array, NUM_POLYNOMIALS> input_univariates; - for (size_t i = 0; i < NUM_POLYNOMIALS; ++i) { - input_univariates[i] = Univariate(input_polynomials[i]); - } - auto expected_round_univariate = - compute_expected_round_univariate(input_univariates, relation_parameters, alpha); - EXPECT_EQ(round_univariate, expected_round_univariate); - } else { - std::array, NUM_POLYNOMIALS> input_polynomials; - for (size_t i = 0; i < NUM_POLYNOMIALS; ++i) { - input_polynomials[i] = { 1, 2 }; - } - const FF alpha = 1; - const RelationParameters relation_parameters = - RelationParameters{ .beta = 1, .gamma = 1, .public_input_delta = 1 }; - auto round_univariate = compute_round_univariate(input_polynomials, relation_parameters, alpha); - // Compute round_univariate manually - std::array, NUM_POLYNOMIALS> input_univariates; - for (size_t i = 0; i < NUM_POLYNOMIALS; ++i) { - input_univariates[i] = Univariate(input_polynomials[i]); - } - // expected_round_univariate = { 6, 26, 66, 132, 230, 366 } - auto expected_round_univariate = - compute_expected_round_univariate(input_univariates, relation_parameters, alpha); - EXPECT_EQ(round_univariate, expected_round_univariate); - }; - }; - run_test(/* is_random_input=*/false); - run_test(/* is_random_input=*/true); -} +// // Compute round_univariate manually +// std::array, NUM_POLYNOMIALS> input_univariates; +// for (size_t i = 0; i < NUM_POLYNOMIALS; ++i) { +// input_univariates[i] = Univariate(input_polynomials[i]); +// } +// auto expected_round_univariate = +// compute_expected_round_univariate(input_univariates, relation_parameters, alpha); +// EXPECT_EQ(round_univariate, expected_round_univariate); +// } else { +// std::array, NUM_POLYNOMIALS> input_polynomials; +// for (size_t i = 0; i < NUM_POLYNOMIALS; ++i) { +// input_polynomials[i] = { 1, 2 }; +// } +// const FF alpha = 1; +// const RelationParameters relation_parameters = +// RelationParameters{ .beta = 1, .gamma = 1, .public_input_delta = 1 }; +// auto round_univariate = compute_round_univariate(input_polynomials, relation_parameters, alpha); +// // Compute round_univariate manually +// std::array, NUM_POLYNOMIALS> input_univariates; +// for (size_t i = 0; i < NUM_POLYNOMIALS; ++i) { +// input_univariates[i] = Univariate(input_polynomials[i]); +// } +// // expected_round_univariate = { 6, 26, 66, 132, 230, 366 } +// auto expected_round_univariate = +// compute_expected_round_univariate(input_univariates, relation_parameters, alpha); +// EXPECT_EQ(round_univariate, expected_round_univariate); +// }; +// }; +// run_test(/* is_random_input=*/false); +// run_test(/* is_random_input=*/true); +// } -TEST(SumcheckRound, ComputeUnivariateVerifier) -{ - auto run_test = [](bool is_random_input) { - if (is_random_input) { - std::array input_values; - for (size_t i = 0; i < NUM_POLYNOMIALS; ++i) { - input_values[i] = FF::random_element(); - } - const FF alpha = FF::random_element(); - const RelationParameters relation_parameters = RelationParameters{ - .beta = FF::random_element(), .gamma = FF::random_element(), .public_input_delta = FF::random_element() - }; - auto full_purported_value = compute_full_purported_value(input_values, relation_parameters, alpha); - // Compute round_univariate manually - auto expected_full_purported_value = - compute_full_purported_value_expected(input_values, relation_parameters, alpha); - EXPECT_EQ(full_purported_value, expected_full_purported_value); - } else { - std::array input_values; - for (size_t i = 0; i < NUM_POLYNOMIALS; ++i) { - input_values[i] = FF(2); - } - const FF alpha = 1; - const RelationParameters relation_parameters = - RelationParameters{ .beta = 1, .gamma = 1, .public_input_delta = 1 }; - auto full_purported_value = compute_full_purported_value(input_values, relation_parameters, alpha); - // Compute round_univariate manually - auto expected_full_purported_value = - compute_full_purported_value_expected(input_values, relation_parameters, alpha); - EXPECT_EQ(full_purported_value, expected_full_purported_value); - }; - }; - run_test(/* is_random_input=*/false); - run_test(/* is_random_input=*/true); -} +// TEST(SumcheckRound, ComputeUnivariateVerifier) +// { +// auto run_test = [](bool is_random_input) { +// if (is_random_input) { +// std::array input_values; +// for (size_t i = 0; i < NUM_POLYNOMIALS; ++i) { +// input_values[i] = FF::random_element(); +// } +// const FF alpha = FF::random_element(); +// const RelationParameters relation_parameters = RelationParameters{ +// .beta = FF::random_element(), .gamma = FF::random_element(), .public_input_delta = +// FF::random_element() +// }; +// auto full_purported_value = compute_full_purported_value(input_values, relation_parameters, alpha); +// // Compute round_univariate manually +// auto expected_full_purported_value = +// compute_full_purported_value_expected(input_values, relation_parameters, alpha); +// EXPECT_EQ(full_purported_value, expected_full_purported_value); +// } else { +// std::array input_values; +// for (size_t i = 0; i < NUM_POLYNOMIALS; ++i) { +// input_values[i] = FF(2); +// } +// const FF alpha = 1; +// const RelationParameters relation_parameters = +// RelationParameters{ .beta = 1, .gamma = 1, .public_input_delta = 1 }; +// auto full_purported_value = compute_full_purported_value(input_values, relation_parameters, alpha); +// // Compute round_univariate manually +// auto expected_full_purported_value = +// compute_full_purported_value_expected(input_values, relation_parameters, alpha); +// EXPECT_EQ(full_purported_value, expected_full_purported_value); +// }; +// }; +// run_test(/* is_random_input=*/false); +// run_test(/* is_random_input=*/true); +// } -} // namespace test_sumcheck_round +// } // namespace test_sumcheck_round diff --git a/cpp/src/barretenberg/honk/transcript/transcript.test.cpp b/cpp/src/barretenberg/honk/transcript/transcript.test.cpp index 6f82adc460..1842989a4f 100644 --- a/cpp/src/barretenberg/honk/transcript/transcript.test.cpp +++ b/cpp/src/barretenberg/honk/transcript/transcript.test.cpp @@ -255,34 +255,34 @@ TYPED_TEST(TranscriptTest, VerifierMistake) * construction and the one generated by the verifier over the course of proof verification. * */ -TYPED_TEST(TranscriptTest, UltraVerifierManifestConsistency) -{ - // Construct a simple circuit of size n = 8 (i.e. the minimum circuit size) - auto composer = UltraHonkComposer(); - // fr a = 2; - // composer.circuit_constructor.add_variable(a); - // composer.circuit_constructor.add_public_variable(a); - - composer.add_gates_to_ensure_all_polys_are_non_zero(); - - // Automatically generate a transcript manifest in the prover by constructing a proof - auto prover = composer.create_prover(); - plonk::proof proof = prover.construct_proof(); - - // Automatically generate a transcript manifest in the verifier by verifying a proof - auto verifier = composer.create_verifier(); - verifier.verify_proof(proof); - - prover.transcript.print(); - verifier.transcript.print(); - - // Check consistency between the manifests generated by the prover and verifier - auto prover_manifest = prover.transcript.get_manifest(); - auto verifier_manifest = verifier.transcript.get_manifest(); - - // Note: a manifest can be printed using manifest.print() - for (size_t round = 0; round < prover_manifest.size(); ++round) { - ASSERT_EQ(prover_manifest[round], verifier_manifest[round]) - << "Prover/Verifier manifest discrepency in round " << round; - } -} +// TYPED_TEST(TranscriptTest, UltraVerifierManifestConsistency) +// { +// // Construct a simple circuit of size n = 8 (i.e. the minimum circuit size) +// auto composer = UltraHonkComposer(); +// // fr a = 2; +// // composer.circuit_constructor.add_variable(a); +// // composer.circuit_constructor.add_public_variable(a); + +// composer.add_gates_to_ensure_all_polys_are_non_zero(); + +// // Automatically generate a transcript manifest in the prover by constructing a proof +// auto prover = composer.create_prover(); +// plonk::proof proof = prover.construct_proof(); + +// // Automatically generate a transcript manifest in the verifier by verifying a proof +// auto verifier = composer.create_verifier(); +// verifier.verify_proof(proof); + +// prover.transcript.print(); +// verifier.transcript.print(); + +// // Check consistency between the manifests generated by the prover and verifier +// auto prover_manifest = prover.transcript.get_manifest(); +// auto verifier_manifest = verifier.transcript.get_manifest(); + +// // Note: a manifest can be printed using manifest.print() +// for (size_t round = 0; round < prover_manifest.size(); ++round) { +// ASSERT_EQ(prover_manifest[round], verifier_manifest[round]) +// << "Prover/Verifier manifest discrepency in round " << round; +// } +// } From bd6ae5ecebaa49a3f945748f3ccb422b59bc4ee7 Mon Sep 17 00:00:00 2001 From: ledwards2225 Date: Mon, 15 May 2023 22:57:43 +0000 Subject: [PATCH 02/18] multi contraint arith and perm for ultra --- .../composer/ultra_honk_composer.test.cpp | 1 - .../honk/proof_system/ultra_prover.cpp | 724 +++++++++--------- .../honk/proof_system/ultra_verifier.cpp | 374 +++++---- .../honk/sumcheck/new_sumcheck.test.cpp | 232 +++--- .../grand_product_initialization_relation.hpp | 89 --- .../relations/permutation_relation.hpp | 132 ++-- .../relations/relation_correctness.test.cpp | 2 +- .../relations/ultra_arithmetic_relation.hpp | 90 ++- .../ultra_relation_consistency.test.cpp | 5 +- 9 files changed, 816 insertions(+), 833 deletions(-) delete mode 100644 cpp/src/barretenberg/honk/sumcheck/relations/grand_product_initialization_relation.hpp 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 20ebd8d10c..41f35402a1 100644 --- a/cpp/src/barretenberg/honk/composer/ultra_honk_composer.test.cpp +++ b/cpp/src/barretenberg/honk/composer/ultra_honk_composer.test.cpp @@ -8,7 +8,6 @@ // #include "barretenberg/honk/proof_system/prover.hpp" // #include "barretenberg/honk/sumcheck/sumcheck_round.hpp" // #include "barretenberg/honk/sumcheck/relations/permutation_relation.hpp" -// #include "barretenberg/honk/sumcheck/relations/grand_product_initialization_relation.hpp" // #include "barretenberg/honk/utils/grand_product_delta.hpp" // #include "barretenberg/proof_system/plookup_tables/types.hpp" diff --git a/cpp/src/barretenberg/honk/proof_system/ultra_prover.cpp b/cpp/src/barretenberg/honk/proof_system/ultra_prover.cpp index be83eff1ba..e271b8040a 100644 --- a/cpp/src/barretenberg/honk/proof_system/ultra_prover.cpp +++ b/cpp/src/barretenberg/honk/proof_system/ultra_prover.cpp @@ -1,364 +1,360 @@ -// #include "ultra_prover.hpp" -// #include -// #include -// #include "barretenberg/honk/proof_system/prover_library.hpp" -// #include "barretenberg/honk/sumcheck/relations/ultra_arithmetic_relation.hpp" -// #include "barretenberg/honk/sumcheck/relations/ultra_arithmetic_relation_secondary.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/permutation_relation.hpp" -// #include "barretenberg/honk/sumcheck/relations/grand_product_initialization_relation.hpp" -// #include "barretenberg/honk/sumcheck/relations/lookup_grand_product_relation.hpp" -// #include "barretenberg/honk/sumcheck/relations/gen_perm_sort_relation.hpp" -// #include "barretenberg/honk/sumcheck/relations/elliptic_relation.hpp" -// #include "barretenberg/honk/sumcheck/relations/auxiliary_relation.hpp" -// #include "barretenberg/polynomials/polynomial.hpp" -// #include "barretenberg/transcript/transcript_wrappers.hpp" -// #include -// #include "barretenberg/honk/pcs/claim.hpp" - -// namespace proof_system::honk { - -// /** -// * Create UltraProver_ from proving key, witness and manifest. -// * -// * @param input_key Proving key. -// * @param input_manifest Input manifest -// * -// * @tparam settings Settings class. -// * */ -// template -// UltraProver_::UltraProver_(std::shared_ptr input_key) -// : key(input_key) -// , queue(input_key->circuit_size, transcript) -// { -// prover_polynomials.q_c = key->q_c; -// prover_polynomials.q_l = key->q_l; -// prover_polynomials.q_r = key->q_r; -// prover_polynomials.q_o = key->q_o; -// prover_polynomials.q_4 = key->q_4; -// prover_polynomials.q_m = key->q_m; -// prover_polynomials.q_arith = key->q_arith; -// prover_polynomials.q_sort = key->q_sort; -// prover_polynomials.q_elliptic = key->q_elliptic; -// prover_polynomials.q_aux = key->q_aux; -// prover_polynomials.q_lookup = key->q_lookup; -// prover_polynomials.sigma_1 = key->sigma_1; -// prover_polynomials.sigma_2 = key->sigma_2; -// prover_polynomials.sigma_3 = key->sigma_3; -// prover_polynomials.sigma_4 = key->sigma_4; -// prover_polynomials.id_1 = key->id_1; -// prover_polynomials.id_2 = key->id_2; -// prover_polynomials.id_3 = key->id_3; -// prover_polynomials.id_4 = key->id_4; -// prover_polynomials.table_1 = key->table_1; -// prover_polynomials.table_2 = key->table_2; -// prover_polynomials.table_3 = key->table_3; -// prover_polynomials.table_4 = key->table_4; -// prover_polynomials.table_1_shift = key->table_1.shifted(); -// prover_polynomials.table_2_shift = key->table_2.shifted(); -// prover_polynomials.table_3_shift = key->table_3.shifted(); -// prover_polynomials.table_4_shift = key->table_4.shifted(); -// prover_polynomials.lagrange_first = key->lagrange_first; -// prover_polynomials.lagrange_last = key->lagrange_last; -// prover_polynomials.w_l = key->w_l; -// prover_polynomials.w_r = key->w_r; -// prover_polynomials.w_o = key->w_o; -// prover_polynomials.w_l_shift = key->w_l.shifted(); -// prover_polynomials.w_r_shift = key->w_r.shifted(); -// prover_polynomials.w_o_shift = key->w_o.shifted(); - -// // Add public inputs to transcript from the second wire polynomial -// std::span public_wires_source = prover_polynomials.w_r; - -// for (size_t i = 0; i < key->num_public_inputs; ++i) { -// public_inputs.emplace_back(public_wires_source[i]); -// } -// } - -// /** -// * @brief Commit to the first three wires only -// * -// */ -// template void UltraProver_::compute_wire_commitments() -// { -// auto wire_polys = key->get_wires(); -// auto labels = commitment_labels.get_wires(); -// for (size_t idx = 0; idx < 3; ++idx) { -// queue.add_commitment(wire_polys[idx], labels[idx]); -// } -// } - -// /** -// * @brief Add circuit size, public input size, and public inputs to transcript -// * -// */ -// template void UltraProver_::execute_preamble_round() -// { -// 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); -// } -// } - -// /** -// * @brief Compute commitments to the first three wires -// * -// */ -// template void UltraProver_::execute_wire_commitments_round() -// { -// auto wire_polys = key->get_wires(); -// auto labels = commitment_labels.get_wires(); -// for (size_t idx = 0; idx < 3; ++idx) { -// queue.add_commitment(wire_polys[idx], labels[idx]); -// } -// } - -// /** -// * @brief Compute sorted witness-table accumulator -// * -// */ -// template void UltraProver_::execute_sorted_list_accumulator_round() -// { -// // Compute and add eta to relation parameters -// auto eta = transcript.get_challenge("eta"); -// relation_parameters.eta = eta; - -// // Compute sorted witness-table accumulator and its commitment -// key->sorted_accum = prover_library::compute_sorted_list_accumulator(key, eta); -// queue.add_commitment(key->sorted_accum, commitment_labels.sorted_accum); - -// // Finalize fourth wire polynomial by adding lookup memory records, then commit -// prover_library::add_plookup_memory_records_to_wire_4(key, eta); -// queue.add_commitment(key->w_4, commitment_labels.w_4); - -// prover_polynomials.sorted_accum_shift = key->sorted_accum.shifted(); -// prover_polynomials.sorted_accum = key->sorted_accum; -// prover_polynomials.w_4 = key->w_4; -// prover_polynomials.w_4_shift = key->w_4.shifted(); -// } - -// /** -// * @brief Compute permutation and lookup grand product polynomials and commitments -// * -// */ -// template void UltraProver_::execute_grand_product_computation_round() -// { -// // 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); -// auto lookup_grand_product_delta = compute_lookup_grand_product_delta(beta, gamma, key->circuit_size); - -// relation_parameters.beta = beta; -// relation_parameters.gamma = gamma; -// relation_parameters.public_input_delta = public_input_delta; -// relation_parameters.lookup_grand_product_delta = lookup_grand_product_delta; - -// // Compute permutation grand product and its commitment -// key->z_perm = prover_library::compute_permutation_grand_product(key, beta, gamma); -// queue.add_commitment(key->z_perm, commitment_labels.z_perm); - -// // Compute lookup grand product and its commitment -// key->z_lookup = prover_library::compute_lookup_grand_product(key, relation_parameters.eta, beta, gamma); -// queue.add_commitment(key->z_lookup, commitment_labels.z_lookup); - -// prover_polynomials.z_perm = key->z_perm; -// prover_polynomials.z_perm_shift = key->z_perm.shifted(); -// prover_polynomials.z_lookup = key->z_lookup; -// prover_polynomials.z_lookup_shift = key->z_lookup.shifted(); -// } - -// /** -// * @brief Run Sumcheck resulting in u = (u_1,...,u_d) challenges and all evaluations at u being calculated. -// * -// */ -// template void UltraProver_::execute_relation_check_rounds() -// { -// using Sumcheck = sumcheck::Sumcheck, -// sumcheck::UltraArithmeticRelation>; -// // using Sumcheck = sumcheck::Sumcheck, -// // sumcheck::UltraArithmeticRelation, -// // sumcheck::UltraArithmeticRelationSecondary, -// // sumcheck::UltraGrandProductComputationRelation, -// // sumcheck::UltraGrandProductInitializationRelation, -// // sumcheck::LookupGrandProductComputationRelation, -// // sumcheck::LookupGrandProductInitializationRelation, -// // sumcheck::GenPermSortRelation, -// // sumcheck::EllipticRelation, -// // sumcheck::AuxiliaryRelation>; - -// 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 UltraProver_::execute_univariatization_round() -// { -// const size_t NUM_POLYNOMIALS = Flavor::NUM_ALL_ENTITIES; - -// // Generate batching challenge ρ and powers 1,ρ,…,ρᵐ⁻¹ -// FF 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 -// size_t poly_idx = 0; // TODO(#391) zip -// for (auto& unshifted_poly : prover_polynomials.get_unshifted()) { -// batched_poly_unshifted.add_scaled(unshifted_poly, rhos[poly_idx]); -// ++poly_idx; -// } - -// Polynomial batched_poly_to_be_shifted(key->circuit_size); // batched to-be-shifted polynomials -// for (auto& to_be_shifted_poly : prover_polynomials.get_to_be_shifted()) { -// batched_poly_to_be_shifted.add_scaled(to_be_shifted_poly, rhos[poly_idx]); -// ++poly_idx; -// }; - -// // 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) { -// queue.add_commitment(fold_polynomials[l + 2], "Gemini:FOLD_" + std::to_string(l + 1)); -// } -// } - -// /** -// * - 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 UltraProver_::execute_pcs_evaluation_round() -// { -// const FF 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 -// * */ -// template void UltraProver_::execute_shplonk_batched_quotient_round() -// { -// nu_challenge = transcript.get_challenge("Shplonk:nu"); - -// batched_quotient_Q = -// Shplonk::compute_batched_quotient(gemini_output.opening_pairs, gemini_output.witnesses, nu_challenge); - -// // commit to Q(X) and add [Q] to the transcript -// queue.add_commitment(batched_quotient_Q, "Shplonk:Q"); -// } - -// /** -// * - Do Fiat-Shamir to get "z" challenge. -// * - Compute polynomial Q(X) - Q_z(X) -// * */ -// template void UltraProver_::execute_shplonk_partial_evaluation_round() -// { -// const FF z_challenge = transcript.get_challenge("Shplonk:z"); - -// shplonk_output = Shplonk::compute_partially_evaluated_batched_quotient( -// gemini_output.opening_pairs, gemini_output.witnesses, std::move(batched_quotient_Q), nu_challenge, -// z_challenge); -// } - -// /** -// * - Compute KZG quotient commitment [W]_1. -// * -// * */ -// template void UltraProver_::execute_kzg_round() -// { -// quotient_W = KZG::compute_opening_proof_polynomial(shplonk_output.opening_pair, shplonk_output.witness); -// queue.add_commitment(quotient_W, "KZG:W"); -// } - -// template plonk::proof& UltraProver_::export_proof() -// { -// proof.proof_data = transcript.proof_data; -// return proof; -// } - -// template plonk::proof& UltraProver_::construct_proof() -// { -// // Add circuit size public input size and public inputs to transcript. -// execute_preamble_round(); - -// // Compute first three wire commitments -// execute_wire_commitments_round(); -// queue.process_queue(); - -// // Compute sorted list accumulator and commitment -// execute_sorted_list_accumulator_round(); -// queue.process_queue(); - -// // Fiat-Shamir: beta & gamma -// // Compute grand product(s) and commitments. -// execute_grand_product_computation_round(); -// queue.process_queue(); - -// // Fiat-Shamir: alpha -// // Run sumcheck subprotocol. -// execute_relation_check_rounds(); - -// // Fiat-Shamir: rho -// // Compute Fold polynomials and their commitments. -// execute_univariatization_round(); -// queue.process_queue(); - -// // Fiat-Shamir: r -// // Compute Fold evaluations -// execute_pcs_evaluation_round(); - -// // Fiat-Shamir: nu -// // Compute Shplonk batched quotient commitment Q -// execute_shplonk_batched_quotient_round(); -// queue.process_queue(); - -// // Fiat-Shamir: z -// // Compute partial evaluation Q_z -// execute_shplonk_partial_evaluation_round(); - -// // Fiat-Shamir: z -// // Compute KZG quotient commitment -// execute_kzg_round(); -// queue.process_queue(); - -// return export_proof(); -// } - -// template class UltraProver_; - -// } // namespace proof_system::honk +#include "ultra_prover.hpp" +#include +#include +#include "barretenberg/honk/proof_system/prover_library.hpp" +#include "barretenberg/honk/sumcheck/relations/ultra_arithmetic_relation.hpp" +#include "barretenberg/honk/sumcheck/relations/ultra_arithmetic_relation_secondary.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/permutation_relation.hpp" +#include "barretenberg/honk/sumcheck/relations/lookup_grand_product_relation.hpp" +#include "barretenberg/honk/sumcheck/relations/gen_perm_sort_relation.hpp" +#include "barretenberg/honk/sumcheck/relations/elliptic_relation.hpp" +#include "barretenberg/honk/sumcheck/relations/auxiliary_relation.hpp" +#include "barretenberg/polynomials/polynomial.hpp" +#include "barretenberg/transcript/transcript_wrappers.hpp" +#include +#include "barretenberg/honk/pcs/claim.hpp" + +namespace proof_system::honk { + +/** + * Create UltraProver_ from proving key, witness and manifest. + * + * @param input_key Proving key. + * @param input_manifest Input manifest + * + * @tparam settings Settings class. + * */ +template +UltraProver_::UltraProver_(std::shared_ptr input_key) + : key(input_key) + , queue(input_key->circuit_size, transcript) +{ + prover_polynomials.q_c = key->q_c; + prover_polynomials.q_l = key->q_l; + prover_polynomials.q_r = key->q_r; + prover_polynomials.q_o = key->q_o; + prover_polynomials.q_4 = key->q_4; + prover_polynomials.q_m = key->q_m; + prover_polynomials.q_arith = key->q_arith; + prover_polynomials.q_sort = key->q_sort; + prover_polynomials.q_elliptic = key->q_elliptic; + prover_polynomials.q_aux = key->q_aux; + prover_polynomials.q_lookup = key->q_lookup; + prover_polynomials.sigma_1 = key->sigma_1; + prover_polynomials.sigma_2 = key->sigma_2; + prover_polynomials.sigma_3 = key->sigma_3; + prover_polynomials.sigma_4 = key->sigma_4; + prover_polynomials.id_1 = key->id_1; + prover_polynomials.id_2 = key->id_2; + prover_polynomials.id_3 = key->id_3; + prover_polynomials.id_4 = key->id_4; + prover_polynomials.table_1 = key->table_1; + prover_polynomials.table_2 = key->table_2; + prover_polynomials.table_3 = key->table_3; + prover_polynomials.table_4 = key->table_4; + prover_polynomials.table_1_shift = key->table_1.shifted(); + prover_polynomials.table_2_shift = key->table_2.shifted(); + prover_polynomials.table_3_shift = key->table_3.shifted(); + prover_polynomials.table_4_shift = key->table_4.shifted(); + prover_polynomials.lagrange_first = key->lagrange_first; + prover_polynomials.lagrange_last = key->lagrange_last; + prover_polynomials.w_l = key->w_l; + prover_polynomials.w_r = key->w_r; + prover_polynomials.w_o = key->w_o; + prover_polynomials.w_l_shift = key->w_l.shifted(); + prover_polynomials.w_r_shift = key->w_r.shifted(); + prover_polynomials.w_o_shift = key->w_o.shifted(); + + // Add public inputs to transcript from the second wire polynomial + std::span public_wires_source = prover_polynomials.w_r; + + for (size_t i = 0; i < key->num_public_inputs; ++i) { + public_inputs.emplace_back(public_wires_source[i]); + } +} + +/** + * @brief Commit to the first three wires only + * + */ +template void UltraProver_::compute_wire_commitments() +{ + auto wire_polys = key->get_wires(); + auto labels = commitment_labels.get_wires(); + for (size_t idx = 0; idx < 3; ++idx) { + queue.add_commitment(wire_polys[idx], labels[idx]); + } +} + +/** + * @brief Add circuit size, public input size, and public inputs to transcript + * + */ +template void UltraProver_::execute_preamble_round() +{ + 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); + } +} + +/** + * @brief Compute commitments to the first three wires + * + */ +template void UltraProver_::execute_wire_commitments_round() +{ + auto wire_polys = key->get_wires(); + auto labels = commitment_labels.get_wires(); + for (size_t idx = 0; idx < 3; ++idx) { + queue.add_commitment(wire_polys[idx], labels[idx]); + } +} + +/** + * @brief Compute sorted witness-table accumulator + * + */ +template void UltraProver_::execute_sorted_list_accumulator_round() +{ + // Compute and add eta to relation parameters + auto eta = transcript.get_challenge("eta"); + relation_parameters.eta = eta; + + // Compute sorted witness-table accumulator and its commitment + key->sorted_accum = prover_library::compute_sorted_list_accumulator(key, eta); + queue.add_commitment(key->sorted_accum, commitment_labels.sorted_accum); + + // Finalize fourth wire polynomial by adding lookup memory records, then commit + prover_library::add_plookup_memory_records_to_wire_4(key, eta); + queue.add_commitment(key->w_4, commitment_labels.w_4); + + prover_polynomials.sorted_accum_shift = key->sorted_accum.shifted(); + prover_polynomials.sorted_accum = key->sorted_accum; + prover_polynomials.w_4 = key->w_4; + prover_polynomials.w_4_shift = key->w_4.shifted(); +} + +/** + * @brief Compute permutation and lookup grand product polynomials and commitments + * + */ +template void UltraProver_::execute_grand_product_computation_round() +{ + // 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); + auto lookup_grand_product_delta = compute_lookup_grand_product_delta(beta, gamma, key->circuit_size); + + relation_parameters.beta = beta; + relation_parameters.gamma = gamma; + relation_parameters.public_input_delta = public_input_delta; + relation_parameters.lookup_grand_product_delta = lookup_grand_product_delta; + + // Compute permutation grand product and its commitment + key->z_perm = prover_library::compute_permutation_grand_product(key, beta, gamma); + queue.add_commitment(key->z_perm, commitment_labels.z_perm); + + // Compute lookup grand product and its commitment + key->z_lookup = prover_library::compute_lookup_grand_product(key, relation_parameters.eta, beta, gamma); + queue.add_commitment(key->z_lookup, commitment_labels.z_lookup); + + prover_polynomials.z_perm = key->z_perm; + prover_polynomials.z_perm_shift = key->z_perm.shifted(); + prover_polynomials.z_lookup = key->z_lookup; + prover_polynomials.z_lookup_shift = key->z_lookup.shifted(); +} + +/** + * @brief Run Sumcheck resulting in u = (u_1,...,u_d) challenges and all evaluations at u being calculated. + * + */ +template void UltraProver_::execute_relation_check_rounds() +{ + using Sumcheck = sumcheck::Sumcheck, sumcheck::UltraArithmeticRelation>; + // using Sumcheck = sumcheck::Sumcheck, + // sumcheck::UltraArithmeticRelation, + // sumcheck::UltraArithmeticRelationSecondary, + // sumcheck::UltraPermutationRelation, + // sumcheck::UltraGrandProductInitializationRelation, + // sumcheck::LookupGrandProductComputationRelation, + // sumcheck::LookupGrandProductInitializationRelation, + // sumcheck::GenPermSortRelation, + // sumcheck::EllipticRelation, + // sumcheck::AuxiliaryRelation>; + + 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 UltraProver_::execute_univariatization_round() +{ + const size_t NUM_POLYNOMIALS = Flavor::NUM_ALL_ENTITIES; + + // Generate batching challenge ρ and powers 1,ρ,…,ρᵐ⁻¹ + FF 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 + size_t poly_idx = 0; // TODO(#391) zip + for (auto& unshifted_poly : prover_polynomials.get_unshifted()) { + batched_poly_unshifted.add_scaled(unshifted_poly, rhos[poly_idx]); + ++poly_idx; + } + + Polynomial batched_poly_to_be_shifted(key->circuit_size); // batched to-be-shifted polynomials + for (auto& to_be_shifted_poly : prover_polynomials.get_to_be_shifted()) { + batched_poly_to_be_shifted.add_scaled(to_be_shifted_poly, rhos[poly_idx]); + ++poly_idx; + }; + + // 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) { + queue.add_commitment(fold_polynomials[l + 2], "Gemini:FOLD_" + std::to_string(l + 1)); + } +} + +/** + * - 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 UltraProver_::execute_pcs_evaluation_round() +{ + const FF 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 + * */ +template void UltraProver_::execute_shplonk_batched_quotient_round() +{ + nu_challenge = transcript.get_challenge("Shplonk:nu"); + + batched_quotient_Q = + Shplonk::compute_batched_quotient(gemini_output.opening_pairs, gemini_output.witnesses, nu_challenge); + + // commit to Q(X) and add [Q] to the transcript + queue.add_commitment(batched_quotient_Q, "Shplonk:Q"); +} + +/** + * - Do Fiat-Shamir to get "z" challenge. + * - Compute polynomial Q(X) - Q_z(X) + * */ +template void UltraProver_::execute_shplonk_partial_evaluation_round() +{ + const FF z_challenge = transcript.get_challenge("Shplonk:z"); + + shplonk_output = Shplonk::compute_partially_evaluated_batched_quotient( + gemini_output.opening_pairs, gemini_output.witnesses, std::move(batched_quotient_Q), nu_challenge, z_challenge); +} + +/** + * - Compute KZG quotient commitment [W]_1. + * + * */ +template void UltraProver_::execute_kzg_round() +{ + quotient_W = KZG::compute_opening_proof_polynomial(shplonk_output.opening_pair, shplonk_output.witness); + queue.add_commitment(quotient_W, "KZG:W"); +} + +template plonk::proof& UltraProver_::export_proof() +{ + proof.proof_data = transcript.proof_data; + return proof; +} + +template plonk::proof& UltraProver_::construct_proof() +{ + // Add circuit size public input size and public inputs to transcript. + execute_preamble_round(); + + // Compute first three wire commitments + execute_wire_commitments_round(); + queue.process_queue(); + + // Compute sorted list accumulator and commitment + execute_sorted_list_accumulator_round(); + queue.process_queue(); + + // Fiat-Shamir: beta & gamma + // Compute grand product(s) and commitments. + execute_grand_product_computation_round(); + queue.process_queue(); + + // Fiat-Shamir: alpha + // Run sumcheck subprotocol. + execute_relation_check_rounds(); + + // Fiat-Shamir: rho + // Compute Fold polynomials and their commitments. + execute_univariatization_round(); + queue.process_queue(); + + // Fiat-Shamir: r + // Compute Fold evaluations + execute_pcs_evaluation_round(); + + // Fiat-Shamir: nu + // Compute Shplonk batched quotient commitment Q + execute_shplonk_batched_quotient_round(); + queue.process_queue(); + + // Fiat-Shamir: z + // Compute partial evaluation Q_z + execute_shplonk_partial_evaluation_round(); + + // Fiat-Shamir: z + // Compute KZG quotient commitment + execute_kzg_round(); + queue.process_queue(); + + return export_proof(); +} + +template class UltraProver_; + +} // namespace proof_system::honk diff --git a/cpp/src/barretenberg/honk/proof_system/ultra_verifier.cpp b/cpp/src/barretenberg/honk/proof_system/ultra_verifier.cpp index f23ce94a61..2a8a5817d9 100644 --- a/cpp/src/barretenberg/honk/proof_system/ultra_verifier.cpp +++ b/cpp/src/barretenberg/honk/proof_system/ultra_verifier.cpp @@ -1,188 +1,186 @@ -// #include "./ultra_verifier.hpp" -// #include "barretenberg/honk/transcript/transcript.hpp" -// #include "barretenberg/numeric/bitop/get_msb.hpp" -// #include "barretenberg/honk/flavor/standard.hpp" -// #include "barretenberg/ecc/curves/bn254/scalar_multiplication/scalar_multiplication.hpp" -// #include "barretenberg/honk/utils/power_polynomial.hpp" -// #include "barretenberg/honk/sumcheck/relations/ultra_arithmetic_relation.hpp" -// #include "barretenberg/honk/sumcheck/relations/ultra_arithmetic_relation_secondary.hpp" -// #include "barretenberg/honk/sumcheck/relations/grand_product_initialization_relation.hpp" -// #include "barretenberg/honk/sumcheck/relations/permutation_relation.hpp" -// #include "barretenberg/honk/sumcheck/relations/lookup_grand_product_relation.hpp" -// #include "barretenberg/honk/sumcheck/relations/gen_perm_sort_relation.hpp" -// #include "barretenberg/honk/sumcheck/relations/elliptic_relation.hpp" -// #include "barretenberg/honk/sumcheck/relations/auxiliary_relation.hpp" - -// #pragma GCC diagnostic ignored "-Wunused-variable" - -// using namespace barretenberg; -// using namespace proof_system::honk::sumcheck; - -// namespace proof_system::honk { -// template -// UltraVerifier_::UltraVerifier_(std::shared_ptr verifier_key) -// : key(verifier_key) -// {} - -// template -// UltraVerifier_::UltraVerifier_(UltraVerifier_&& other) -// : key(std::move(other.key)) -// , kate_verification_key(std::move(other.kate_verification_key)) -// {} - -// template UltraVerifier_& UltraVerifier_::operator=(UltraVerifier_&& other) -// { -// key = other.key; -// kate_verification_key = (std::move(other.kate_verification_key)); -// kate_g1_elements.clear(); -// kate_fr_elements.clear(); -// return *this; -// } - -// /** -// * @brief This function verifies an Ultra Honk proof for given program settings. -// * -// */ -// template bool UltraVerifier_::verify_proof(const plonk::proof& proof) -// { -// using FF = typename Flavor::FF; -// using GroupElement = typename Flavor::GroupElement; -// using Commitment = typename Flavor::Commitment; -// using Gemini = pcs::gemini::MultilinearReductionScheme; -// using Shplonk = pcs::shplonk::SingleBatchOpeningScheme; -// using KZG = pcs::kzg::UnivariateOpeningScheme; -// using VerifierCommitments = typename Flavor::VerifierCommitments; -// using CommitmentLabels = typename Flavor::CommitmentLabels; - -// RelationParameters relation_parameters; - -// transcript = VerifierTranscript{ proof.proof_data }; - -// auto commitments = VerifierCommitments(key, transcript); -// auto commitment_labels = CommitmentLabels(); - -// // TODO(Adrian): Change the initialization of the transcript to take the VK hash? -// const auto circuit_size = transcript.template receive_from_prover("circuit_size"); -// const auto public_input_size = transcript.template receive_from_prover("public_input_size"); - -// if (circuit_size != key->circuit_size) { -// return false; -// } -// if (public_input_size != key->num_public_inputs) { -// return false; -// } - -// std::vector public_inputs; -// for (size_t i = 0; i < public_input_size; ++i) { -// auto public_input_i = transcript.template receive_from_prover("public_input_" + std::to_string(i)); -// public_inputs.emplace_back(public_input_i); -// } - -// // Get commitments to first three wires -// commitments.w_l = transcript.template receive_from_prover(commitment_labels.w_l); -// commitments.w_r = transcript.template receive_from_prover(commitment_labels.w_r); -// commitments.w_o = transcript.template receive_from_prover(commitment_labels.w_o); - -// // Get challenge for sorted list batching and wire four memory records -// auto eta = transcript.get_challenge("eta"); -// relation_parameters.eta = eta; - -// // Get commitments to sorted list accumulator and fourth wire -// commitments.sorted_accum = transcript.template receive_from_prover(commitment_labels.sorted_accum); -// commitments.w_4 = transcript.template receive_from_prover(commitment_labels.w_4); - -// // Get permutation challenges -// auto [beta, gamma] = transcript.get_challenges("beta", "gamma"); - -// const FF public_input_delta = compute_public_input_delta(public_inputs, beta, gamma, circuit_size); -// const FF lookup_grand_product_delta = compute_lookup_grand_product_delta(beta, gamma, circuit_size); - -// relation_parameters.beta = beta; -// relation_parameters.gamma = gamma; -// relation_parameters.public_input_delta = public_input_delta; -// relation_parameters.lookup_grand_product_delta = lookup_grand_product_delta; - -// // Get commitment to permutation and lookup grand products -// commitments.z_perm = transcript.template receive_from_prover(commitment_labels.z_perm); -// commitments.z_lookup = transcript.template receive_from_prover(commitment_labels.z_lookup); - -// // Execute Sumcheck Verifier -// auto sumcheck = Sumcheck, -// honk::sumcheck::UltraArithmeticRelation>(circuit_size, transcript); -// // auto sumcheck = Sumcheck, -// // honk::sumcheck::UltraArithmeticRelation, -// // honk::sumcheck::UltraArithmeticRelationSecondary, -// // honk::sumcheck::UltraGrandProductComputationRelation, -// // honk::sumcheck::UltraGrandProductInitializationRelation, -// // honk::sumcheck::LookupGrandProductComputationRelation, -// // honk::sumcheck::LookupGrandProductInitializationRelation, -// // honk::sumcheck::GenPermSortRelation, -// // honk::sumcheck::EllipticRelation, -// // honk::sumcheck::AuxiliaryRelation>(circuit_size, transcript); - -// std::optional sumcheck_output = sumcheck.execute_verifier(relation_parameters); - -// // If Sumcheck does not return an output, sumcheck verification has failed -// if (!sumcheck_output.has_value()) { -// return false; -// } - -// auto [multivariate_challenge, purported_evaluations] = *sumcheck_output; - -// // Execute Gemini/Shplonk verification: - -// // Construct inputs for Gemini verifier: -// // - Multivariate opening point u = (u_0, ..., u_{d-1}) -// // - batched unshifted and to-be-shifted polynomial commitments -// auto batched_commitment_unshifted = GroupElement::zero(); -// auto batched_commitment_to_be_shifted = GroupElement::zero(); - -// // Compute powers of batching challenge rho -// FF rho = transcript.get_challenge("rho"); -// std::vector rhos = Gemini::powers_of_rho(rho, Flavor::NUM_ALL_ENTITIES); - -// // Compute batched multivariate evaluation -// FF batched_evaluation = FF::zero(); -// size_t evaluation_idx = 0; -// for (auto& value : purported_evaluations.get_unshifted_then_shifted()) { -// batched_evaluation += value * rhos[evaluation_idx]; -// ++evaluation_idx; -// } - -// // Construct batched commitment for NON-shifted polynomials -// size_t commitment_idx = 0; -// for (auto& commitment : commitments.get_unshifted()) { -// batched_commitment_unshifted += commitment * rhos[commitment_idx]; -// ++commitment_idx; -// } - -// // Construct batched commitment for to-be-shifted polynomials -// for (auto& commitment : commitments.get_to_be_shifted()) { -// batched_commitment_to_be_shifted += commitment * rhos[commitment_idx]; -// ++commitment_idx; -// } - -// // Produce a Gemini claim consisting of: -// // - d+1 commitments [Fold_{r}^(0)], [Fold_{-r}^(0)], and [Fold^(l)], l = 1:d-1 -// // - d+1 evaluations a_0_pos, and a_l, l = 0:d-1 -// auto gemini_claim = Gemini::reduce_verify(multivariate_challenge, -// batched_evaluation, -// batched_commitment_unshifted, -// batched_commitment_to_be_shifted, -// transcript); - -// // Produce a Shplonk claim: commitment [Q] - [Q_z], evaluation zero (at random challenge z) -// auto shplonk_claim = Shplonk::reduce_verify(gemini_claim, transcript); - -// // Aggregate inputs [Q] - [Q_z] and [W] into an 'accumulator' (can perform pairing check on result) -// auto kzg_claim = KZG::reduce_verify(shplonk_claim, transcript); - -// // Return result of final pairing check -// return kzg_claim.verify(kate_verification_key); -// } - -// template class UltraVerifier_; - -// } // namespace proof_system::honk +#include "./ultra_verifier.hpp" +#include "barretenberg/honk/transcript/transcript.hpp" +#include "barretenberg/numeric/bitop/get_msb.hpp" +#include "barretenberg/honk/flavor/standard.hpp" +#include "barretenberg/ecc/curves/bn254/scalar_multiplication/scalar_multiplication.hpp" +#include "barretenberg/honk/utils/power_polynomial.hpp" +#include "barretenberg/honk/sumcheck/relations/ultra_arithmetic_relation.hpp" +#include "barretenberg/honk/sumcheck/relations/ultra_arithmetic_relation_secondary.hpp" +#include "barretenberg/honk/sumcheck/relations/permutation_relation.hpp" +#include "barretenberg/honk/sumcheck/relations/lookup_grand_product_relation.hpp" +#include "barretenberg/honk/sumcheck/relations/gen_perm_sort_relation.hpp" +#include "barretenberg/honk/sumcheck/relations/elliptic_relation.hpp" +#include "barretenberg/honk/sumcheck/relations/auxiliary_relation.hpp" + +#pragma GCC diagnostic ignored "-Wunused-variable" + +using namespace barretenberg; +using namespace proof_system::honk::sumcheck; + +namespace proof_system::honk { +template +UltraVerifier_::UltraVerifier_(std::shared_ptr verifier_key) + : key(verifier_key) +{} + +template +UltraVerifier_::UltraVerifier_(UltraVerifier_&& other) + : key(std::move(other.key)) + , kate_verification_key(std::move(other.kate_verification_key)) +{} + +template UltraVerifier_& UltraVerifier_::operator=(UltraVerifier_&& other) +{ + key = other.key; + kate_verification_key = (std::move(other.kate_verification_key)); + kate_g1_elements.clear(); + kate_fr_elements.clear(); + return *this; +} + +/** + * @brief This function verifies an Ultra Honk proof for given program settings. + * + */ +template bool UltraVerifier_::verify_proof(const plonk::proof& proof) +{ + using FF = typename Flavor::FF; + using GroupElement = typename Flavor::GroupElement; + using Commitment = typename Flavor::Commitment; + using Gemini = pcs::gemini::MultilinearReductionScheme; + using Shplonk = pcs::shplonk::SingleBatchOpeningScheme; + using KZG = pcs::kzg::UnivariateOpeningScheme; + using VerifierCommitments = typename Flavor::VerifierCommitments; + using CommitmentLabels = typename Flavor::CommitmentLabels; + + RelationParameters relation_parameters; + + transcript = VerifierTranscript{ proof.proof_data }; + + auto commitments = VerifierCommitments(key, transcript); + auto commitment_labels = CommitmentLabels(); + + // TODO(Adrian): Change the initialization of the transcript to take the VK hash? + const auto circuit_size = transcript.template receive_from_prover("circuit_size"); + const auto public_input_size = transcript.template receive_from_prover("public_input_size"); + + if (circuit_size != key->circuit_size) { + return false; + } + if (public_input_size != key->num_public_inputs) { + return false; + } + + std::vector public_inputs; + for (size_t i = 0; i < public_input_size; ++i) { + auto public_input_i = transcript.template receive_from_prover("public_input_" + std::to_string(i)); + public_inputs.emplace_back(public_input_i); + } + + // Get commitments to first three wires + commitments.w_l = transcript.template receive_from_prover(commitment_labels.w_l); + commitments.w_r = transcript.template receive_from_prover(commitment_labels.w_r); + commitments.w_o = transcript.template receive_from_prover(commitment_labels.w_o); + + // Get challenge for sorted list batching and wire four memory records + auto eta = transcript.get_challenge("eta"); + relation_parameters.eta = eta; + + // Get commitments to sorted list accumulator and fourth wire + commitments.sorted_accum = transcript.template receive_from_prover(commitment_labels.sorted_accum); + commitments.w_4 = transcript.template receive_from_prover(commitment_labels.w_4); + + // Get permutation challenges + auto [beta, gamma] = transcript.get_challenges("beta", "gamma"); + + const FF public_input_delta = compute_public_input_delta(public_inputs, beta, gamma, circuit_size); + const FF lookup_grand_product_delta = compute_lookup_grand_product_delta(beta, gamma, circuit_size); + + relation_parameters.beta = beta; + relation_parameters.gamma = gamma; + relation_parameters.public_input_delta = public_input_delta; + relation_parameters.lookup_grand_product_delta = lookup_grand_product_delta; + + // Get commitment to permutation and lookup grand products + commitments.z_perm = transcript.template receive_from_prover(commitment_labels.z_perm); + commitments.z_lookup = transcript.template receive_from_prover(commitment_labels.z_lookup); + + // Execute Sumcheck Verifier + auto sumcheck = + Sumcheck, honk::sumcheck::UltraArithmeticRelation>(circuit_size, transcript); + // auto sumcheck = Sumcheck, + // honk::sumcheck::UltraArithmeticRelation, + // honk::sumcheck::UltraArithmeticRelationSecondary, + // honk::sumcheck::UltraPermutationRelation, + // honk::sumcheck::UltraGrandProductInitializationRelation, + // honk::sumcheck::LookupGrandProductComputationRelation, + // honk::sumcheck::LookupGrandProductInitializationRelation, + // honk::sumcheck::GenPermSortRelation, + // honk::sumcheck::EllipticRelation, + // honk::sumcheck::AuxiliaryRelation>(circuit_size, transcript); + + std::optional sumcheck_output = sumcheck.execute_verifier(relation_parameters); + + // If Sumcheck does not return an output, sumcheck verification has failed + if (!sumcheck_output.has_value()) { + return false; + } + + auto [multivariate_challenge, purported_evaluations] = *sumcheck_output; + + // Execute Gemini/Shplonk verification: + + // Construct inputs for Gemini verifier: + // - Multivariate opening point u = (u_0, ..., u_{d-1}) + // - batched unshifted and to-be-shifted polynomial commitments + auto batched_commitment_unshifted = GroupElement::zero(); + auto batched_commitment_to_be_shifted = GroupElement::zero(); + + // Compute powers of batching challenge rho + FF rho = transcript.get_challenge("rho"); + std::vector rhos = Gemini::powers_of_rho(rho, Flavor::NUM_ALL_ENTITIES); + + // Compute batched multivariate evaluation + FF batched_evaluation = FF::zero(); + size_t evaluation_idx = 0; + for (auto& value : purported_evaluations.get_unshifted_then_shifted()) { + batched_evaluation += value * rhos[evaluation_idx]; + ++evaluation_idx; + } + + // Construct batched commitment for NON-shifted polynomials + size_t commitment_idx = 0; + for (auto& commitment : commitments.get_unshifted()) { + batched_commitment_unshifted += commitment * rhos[commitment_idx]; + ++commitment_idx; + } + + // Construct batched commitment for to-be-shifted polynomials + for (auto& commitment : commitments.get_to_be_shifted()) { + batched_commitment_to_be_shifted += commitment * rhos[commitment_idx]; + ++commitment_idx; + } + + // Produce a Gemini claim consisting of: + // - d+1 commitments [Fold_{r}^(0)], [Fold_{-r}^(0)], and [Fold^(l)], l = 1:d-1 + // - d+1 evaluations a_0_pos, and a_l, l = 0:d-1 + auto gemini_claim = Gemini::reduce_verify(multivariate_challenge, + batched_evaluation, + batched_commitment_unshifted, + batched_commitment_to_be_shifted, + transcript); + + // Produce a Shplonk claim: commitment [Q] - [Q_z], evaluation zero (at random challenge z) + auto shplonk_claim = Shplonk::reduce_verify(gemini_claim, transcript); + + // Aggregate inputs [Q] - [Q_z] and [W] into an 'accumulator' (can perform pairing check on result) + auto kzg_claim = KZG::reduce_verify(shplonk_claim, transcript); + + // Return result of final pairing check + return kzg_claim.verify(kate_verification_key); +} + +template class UltraVerifier_; + +} // namespace proof_system::honk diff --git a/cpp/src/barretenberg/honk/sumcheck/new_sumcheck.test.cpp b/cpp/src/barretenberg/honk/sumcheck/new_sumcheck.test.cpp index f507aef42d..15687269b6 100644 --- a/cpp/src/barretenberg/honk/sumcheck/new_sumcheck.test.cpp +++ b/cpp/src/barretenberg/honk/sumcheck/new_sumcheck.test.cpp @@ -4,6 +4,7 @@ #include "barretenberg/transcript/transcript_wrappers.hpp" #include "relations/arithmetic_relation.hpp" #include "relations/permutation_relation.hpp" +#include "relations/ultra_arithmetic_relation.hpp" #include "barretenberg/transcript/manifest.hpp" #include #include @@ -111,111 +112,132 @@ TEST(NewSumcheck, Standard) TEST(NewSumcheck, Ultra) { - // using Flavor = honk::flavor::Ultra; - // using FF = typename Flavor::FF; - // using ProverPolynomials = typename Flavor::ProverPolynomials; - - // // Create a composer and a dummy circuit with a few gates - // auto composer = UltraHonkComposer(); - // fr a = fr::one(); - // // Using the public variable to check that public_input_delta is computed and added to the relation correctly - // uint32_t a_idx = composer.add_variable(a); - // fr b = fr::one(); - // fr c = a + b; - // fr d = a + c; - // uint32_t b_idx = composer.add_variable(b); - // uint32_t c_idx = composer.add_variable(c); - // uint32_t d_idx = composer.add_variable(d); - // for (size_t i = 0; i < 16; i++) { - // composer.create_add_gate({ a_idx, b_idx, c_idx, fr::one(), fr::one(), fr::neg_one(), fr::zero() }); - // composer.create_add_gate({ d_idx, c_idx, a_idx, fr::one(), fr::neg_one(), fr::neg_one(), fr::zero() }); - // } - // // Create a prover (it will compute proving key and witness) - // auto prover = composer.create_prover(); - - // // Generate beta and gamma - // fr beta = fr::random_element(); - // fr gamma = fr::random_element(); - - // // Compute public input delta - // const auto public_inputs = composer.circuit_constructor.get_public_inputs(); - // auto public_input_delta = - // honk::compute_public_input_delta(public_inputs, beta, gamma, prover.key->circuit_size); - - // sumcheck::RelationParameters relation_parameters{ - // .beta = beta, - // .gamma = gamma, - // .public_input_delta = public_input_delta, - // }; - - // // Compute grand product polynomial - // polynomial z_permutation = prover_library::compute_permutation_grand_product(prover.key, beta, gamma); - - // ProverPolynomials prover_polynomials; - - // prover_polynomials.w_l = prover.key->w_l; - // prover_polynomials.w_r = prover.key->w_r; - // prover_polynomials.w_o = prover.key->w_o; - // prover_polynomials.w_4 = prover.key->w_4; - // prover_polynomials.w_l_shift = prover.key->w_l.shifted(); - // prover_polynomials.w_r_shift = prover.key->w_r.shifted(); - // prover_polynomials.w_o_shift = prover.key->w_o.shifted(); - // prover_polynomials.w_4_shift = prover.key->w_4.shifted(); - // prover_polynomials.sorted_1 = prover.key->sorted_1; - // prover_polynomials.sorted_2 = prover.key->sorted_2; - // prover_polynomials.sorted_3 = prover.key->sorted_3; - // prover_polynomials.sorted_4 = prover.key->sorted_4; - // prover_polynomials.sorted_accum = sorted_list_accumulator; - // prover_polynomials.sorted_accum_shift = sorted_list_accumulator.shifted(); - // prover_polynomials.table_1 = prover.key->table_1; - // prover_polynomials.table_2 = prover.key->table_2; - // prover_polynomials.table_3 = prover.key->table_3; - // prover_polynomials.table_4 = prover.key->table_4; - // prover_polynomials.table_1_shift = prover.key->table_1.shifted(); - // prover_polynomials.table_2_shift = prover.key->table_2.shifted(); - // prover_polynomials.table_3_shift = prover.key->table_3.shifted(); - // prover_polynomials.table_4_shift = prover.key->table_4.shifted(); - // prover_polynomials.z_perm = z_permutation; - // prover_polynomials.z_perm_shift = z_permutation.shifted(); - // prover_polynomials.z_lookup = z_lookup; - // prover_polynomials.z_lookup_shift = z_lookup.shifted(); - // prover_polynomials.q_m = prover.key->q_m; - // prover_polynomials.q_l = prover.key->q_l; - // prover_polynomials.q_r = prover.key->q_r; - // prover_polynomials.q_o = prover.key->q_o; - // prover_polynomials.q_c = prover.key->q_c; - // prover_polynomials.q_4 = prover.key->q_4; - // prover_polynomials.q_arith = prover.key->q_arith; - // prover_polynomials.q_sort = prover.key->q_sort; - // prover_polynomials.q_elliptic = prover.key->q_elliptic; - // prover_polynomials.q_aux = prover.key->q_aux; - // prover_polynomials.q_lookup = prover.key->q_lookup; - // prover_polynomials.sigma_1 = prover.key->sigma_1; - // prover_polynomials.sigma_2 = prover.key->sigma_2; - // prover_polynomials.sigma_3 = prover.key->sigma_3; - // prover_polynomials.sigma_4 = prover.key->sigma_4; - // prover_polynomials.id_1 = prover.key->id_1; - // prover_polynomials.id_2 = prover.key->id_2; - // prover_polynomials.id_3 = prover.key->id_3; - // prover_polynomials.id_4 = prover.key->id_4; - // prover_polynomials.lagrange_first = prover.key->lagrange_first; - // prover_polynomials.lagrange_last = prover.key->lagrange_last; - - // auto prover_transcript = ProverTranscript::init_empty(); - - // auto sumcheck_prover = Sumcheck, ArithmeticRelation, PermutationRelation>( - // prover.key->circuit_size, prover_transcript); - - // auto prover_output = sumcheck_prover.execute_prover(prover_polynomials, relation_parameters); - - // auto verifier_transcript = VerifierTranscript::init_empty(prover_transcript); - - // auto sumcheck_verifier = Sumcheck, ArithmeticRelation, PermutationRelation>( - // prover.key->circuit_size, verifier_transcript); - - // std::optional verifier_output = sumcheck_verifier.execute_verifier(relation_parameters); - - // ASSERT_TRUE(verifier_output.has_value()); + using Flavor = honk::flavor::Ultra; + using FF = typename Flavor::FF; + using ProverPolynomials = typename Flavor::ProverPolynomials; + + // Create a composer and a dummy circuit with a few gates + auto composer = UltraHonkComposer(); + fr a = fr::one(); + + // Add some basic add gates + uint32_t a_idx = composer.add_variable(a); + fr b = fr::one(); + fr c = a + b; + fr d = a + c; + uint32_t b_idx = composer.add_variable(b); + uint32_t c_idx = composer.add_variable(c); + uint32_t d_idx = composer.add_variable(d); + for (size_t i = 0; i < 16; i++) { + composer.create_add_gate({ a_idx, b_idx, c_idx, 1, 1, -1, 0 }); + composer.create_add_gate({ d_idx, c_idx, a_idx, 1, -1, -1, 0 }); + } + + // Add a big add gate with use of next row to test q_arith = 2 + fr e = a + b + c + d; + uint32_t e_idx = composer.add_variable(e); + + uint32_t zero_idx = composer.get_zero_idx(); + composer.create_big_add_gate({ a_idx, b_idx, c_idx, d_idx, -1, -1, -1, -1, 0 }, true); // use next row + composer.create_big_add_gate({ zero_idx, zero_idx, zero_idx, e_idx, 0, 0, 0, 0, 0 }, false); + + // Create a prover (it will compute proving key and witness) + auto prover = composer.create_prover(); + + // Generate eta, beta and gamma + fr eta = fr::random_element(); + fr beta = fr::random_element(); + fr gamma = fr::random_element(); + + // Compute public input delta + const auto public_inputs = composer.circuit_constructor.get_public_inputs(); + auto public_input_delta = + honk::compute_public_input_delta(public_inputs, beta, gamma, prover.key->circuit_size); + auto lookup_grand_product_delta = + honk::compute_lookup_grand_product_delta(beta, gamma, prover.key->circuit_size); + + sumcheck::RelationParameters relation_parameters{ + .eta = eta, + .beta = beta, + .gamma = gamma, + .public_input_delta = public_input_delta, + .lookup_grand_product_delta = lookup_grand_product_delta, + }; + + // Compute sorted witness-table accumulator + prover.key->sorted_accum = prover_library::compute_sorted_list_accumulator(prover.key, eta); + + // Add RAM/ROM memory records to wire four + prover_library::add_plookup_memory_records_to_wire_4(prover.key, eta); + + // Compute grand product polynomial + prover.key->z_perm = prover_library::compute_permutation_grand_product(prover.key, beta, gamma); + + // Compute lookup grand product polynomial + prover.key->z_lookup = prover_library::compute_lookup_grand_product(prover.key, eta, beta, gamma); + + ProverPolynomials prover_polynomials; + + prover_polynomials.w_l = prover.key->w_l; + prover_polynomials.w_r = prover.key->w_r; + prover_polynomials.w_o = prover.key->w_o; + prover_polynomials.w_4 = prover.key->w_4; + prover_polynomials.w_l_shift = prover.key->w_l.shifted(); + prover_polynomials.w_r_shift = prover.key->w_r.shifted(); + prover_polynomials.w_o_shift = prover.key->w_o.shifted(); + prover_polynomials.w_4_shift = prover.key->w_4.shifted(); + prover_polynomials.sorted_accum = prover.key->sorted_accum; + prover_polynomials.sorted_accum_shift = prover.key->sorted_accum.shifted(); + prover_polynomials.table_1 = prover.key->table_1; + prover_polynomials.table_2 = prover.key->table_2; + prover_polynomials.table_3 = prover.key->table_3; + prover_polynomials.table_4 = prover.key->table_4; + prover_polynomials.table_1_shift = prover.key->table_1.shifted(); + prover_polynomials.table_2_shift = prover.key->table_2.shifted(); + prover_polynomials.table_3_shift = prover.key->table_3.shifted(); + prover_polynomials.table_4_shift = prover.key->table_4.shifted(); + prover_polynomials.z_perm = prover.key->z_perm; + prover_polynomials.z_perm_shift = prover.key->z_perm.shifted(); + prover_polynomials.z_lookup = prover.key->z_lookup; + prover_polynomials.z_lookup_shift = prover.key->z_lookup.shifted(); + prover_polynomials.q_m = prover.key->q_m; + prover_polynomials.q_l = prover.key->q_l; + prover_polynomials.q_r = prover.key->q_r; + prover_polynomials.q_o = prover.key->q_o; + prover_polynomials.q_c = prover.key->q_c; + prover_polynomials.q_4 = prover.key->q_4; + prover_polynomials.q_arith = prover.key->q_arith; + prover_polynomials.q_sort = prover.key->q_sort; + prover_polynomials.q_elliptic = prover.key->q_elliptic; + prover_polynomials.q_aux = prover.key->q_aux; + prover_polynomials.q_lookup = prover.key->q_lookup; + prover_polynomials.sigma_1 = prover.key->sigma_1; + prover_polynomials.sigma_2 = prover.key->sigma_2; + prover_polynomials.sigma_3 = prover.key->sigma_3; + prover_polynomials.sigma_4 = prover.key->sigma_4; + prover_polynomials.id_1 = prover.key->id_1; + prover_polynomials.id_2 = prover.key->id_2; + prover_polynomials.id_3 = prover.key->id_3; + prover_polynomials.id_4 = prover.key->id_4; + prover_polynomials.lagrange_first = prover.key->lagrange_first; + prover_polynomials.lagrange_last = prover.key->lagrange_last; + + auto prover_transcript = ProverTranscript::init_empty(); + + auto sumcheck_prover = Sumcheck, UltraArithmeticRelation, UltraPermutationRelation>( + prover.key->circuit_size, prover_transcript); + + auto prover_output = sumcheck_prover.execute_prover(prover_polynomials, relation_parameters); + + auto verifier_transcript = VerifierTranscript::init_empty(prover_transcript); + + auto sumcheck_verifier = + Sumcheck, UltraArithmeticRelation, UltraPermutationRelation>( + prover.key->circuit_size, verifier_transcript); + + std::optional verifier_output = sumcheck_verifier.execute_verifier(relation_parameters); + + ASSERT_TRUE(verifier_output.has_value()); } // WORKTODO: move these utility tests to SumcheckRound tests diff --git a/cpp/src/barretenberg/honk/sumcheck/relations/grand_product_initialization_relation.hpp b/cpp/src/barretenberg/honk/sumcheck/relations/grand_product_initialization_relation.hpp deleted file mode 100644 index 0fd8fbd606..0000000000 --- a/cpp/src/barretenberg/honk/sumcheck/relations/grand_product_initialization_relation.hpp +++ /dev/null @@ -1,89 +0,0 @@ -#pragma once -#include "relation.hpp" -#include "../polynomials/univariate.hpp" - -namespace proof_system::honk::sumcheck { - -template class GrandProductInitializationRelation { - public: - // 1 + polynomial degree of this relation - static constexpr size_t RELATION_LENGTH = 3; - - /** - * @brief Add contribution of the permutation relation for a given edge - * - * @details There are 2 relations associated with enforcing the wire copy relations - * This file handles the relation Z_perm_shift(n_last) = 0 via the relation: - * - * C(X) = L_LAST(X) * Z_perm_shift(X) - * - * @param evals transformed to `evals + C(extended_edges(X)...)*scaling_factor` - * @param extended_edges an std::array containing the fully extended Univariate edges. - * @param parameters contains beta, gamma, and public_input_delta, .... - * @param scaling_factor optional term to scale the evaluation before adding to evals. - */ - void add_edge_contribution(Univariate& evals, - const auto& extended_edges, - const RelationParameters&, - const FF& scaling_factor) const - { - auto z_perm_shift = UnivariateView(extended_edges.z_perm_shift); - auto lagrange_last = UnivariateView(extended_edges.lagrange_last); - - evals += (lagrange_last * z_perm_shift) * scaling_factor; - }; - - void add_full_relation_value_contribution(FF& full_honk_relation_value, - auto& purported_evaluations, - const RelationParameters&) const - { - auto z_perm_shift = purported_evaluations.z_perm_shift; - auto lagrange_last = purported_evaluations.lagrange_last; - - full_honk_relation_value += lagrange_last * z_perm_shift; - }; -}; - -// TODO(luke): The only difference between the Ultra relation and the Standard version is the enum -// used to refer into the edge polynomials. Seems desireable to not duplicate the code here but -// leaving this as is until Codys Flavor work is settled. -template class UltraGrandProductInitializationRelation { - public: - // 1 + polynomial degree of this relation - static constexpr size_t RELATION_LENGTH = 3; - - /** - * @brief Add contribution of the permutation relation for a given edge - * - * @details There are 2 relations associated with enforcing the wire copy relations - * This file handles the relation Z_perm_shift(n_last) = 0 via the relation: - * - * C(X) = L_LAST(X) * Z_perm_shift(X) - * - * @param evals transformed to `evals + C(extended_edges(X)...)*scaling_factor` - * @param extended_edges an std::array containing the fully extended Univariate edges. - * @param parameters contains beta, gamma, and public_input_delta, .... - * @param scaling_factor optional term to scale the evaluation before adding to evals. - */ - void add_edge_contribution(Univariate& evals, - const auto& extended_edges, - const RelationParameters&, - const FF& scaling_factor) const - { - auto z_perm_shift = UnivariateView(extended_edges.z_perm_shift); - auto lagrange_last = UnivariateView(extended_edges.lagrange_last); - - evals += (lagrange_last * z_perm_shift) * scaling_factor; - }; - - void add_full_relation_value_contribution(FF& full_honk_relation_value, - auto& purported_evaluations, - const RelationParameters&) const - { - auto z_perm_shift = purported_evaluations.z_perm_shift; - auto lagrange_last = purported_evaluations.lagrange_last; - - full_honk_relation_value += lagrange_last * z_perm_shift; - }; -}; -} // namespace proof_system::honk::sumcheck diff --git a/cpp/src/barretenberg/honk/sumcheck/relations/permutation_relation.hpp b/cpp/src/barretenberg/honk/sumcheck/relations/permutation_relation.hpp index 3cbaa8c280..9a415de4d9 100644 --- a/cpp/src/barretenberg/honk/sumcheck/relations/permutation_relation.hpp +++ b/cpp/src/barretenberg/honk/sumcheck/relations/permutation_relation.hpp @@ -44,32 +44,38 @@ template class PermutationRelation { const auto& gamma = relation_parameters.gamma; const auto& public_input_delta = relation_parameters.public_input_delta; - auto w_1 = UnivariateView(extended_edges.w_l); - auto w_2 = UnivariateView(extended_edges.w_r); - auto w_3 = UnivariateView(extended_edges.w_o); - auto sigma_1 = UnivariateView(extended_edges.sigma_1); - auto sigma_2 = UnivariateView(extended_edges.sigma_2); - auto sigma_3 = UnivariateView(extended_edges.sigma_3); - auto id_1 = UnivariateView(extended_edges.id_1); - auto id_2 = UnivariateView(extended_edges.id_2); - auto id_3 = UnivariateView(extended_edges.id_3); - auto z_perm = UnivariateView(extended_edges.z_perm); - auto z_perm_shift = UnivariateView(extended_edges.z_perm_shift); - auto lagrange_first = UnivariateView(extended_edges.lagrange_first); - auto lagrange_last = UnivariateView(extended_edges.lagrange_last); - - // Contribution (1) - std::get<0>(evals) += (((z_perm + lagrange_first) * (w_1 + id_1 * beta + gamma) * (w_2 + id_2 * beta + gamma) * - (w_3 + id_3 * beta + gamma)) - - ((z_perm_shift + lagrange_last * public_input_delta) * (w_1 + sigma_1 * beta + gamma) * - (w_2 + sigma_2 * beta + gamma) * (w_3 + sigma_3 * beta + gamma))) * - scaling_factor; - - auto z_perm_shift_ = UnivariateView(extended_edges.z_perm_shift); - auto lagrange_last_ = UnivariateView(extended_edges.lagrange_last); - - // Contribution (2) - std::get<1>(evals) += (lagrange_last_ * z_perm_shift_) * scaling_factor; + { + static constexpr size_t LENGTH = CONSTRAINT_LENGTH[0]; + auto w_1 = UnivariateView(extended_edges.w_l); + auto w_2 = UnivariateView(extended_edges.w_r); + auto w_3 = UnivariateView(extended_edges.w_o); + auto sigma_1 = UnivariateView(extended_edges.sigma_1); + auto sigma_2 = UnivariateView(extended_edges.sigma_2); + auto sigma_3 = UnivariateView(extended_edges.sigma_3); + auto id_1 = UnivariateView(extended_edges.id_1); + auto id_2 = UnivariateView(extended_edges.id_2); + auto id_3 = UnivariateView(extended_edges.id_3); + auto z_perm = UnivariateView(extended_edges.z_perm); + auto z_perm_shift = UnivariateView(extended_edges.z_perm_shift); + auto lagrange_first = UnivariateView(extended_edges.lagrange_first); + auto lagrange_last = UnivariateView(extended_edges.lagrange_last); + + // Contribution (1) + std::get<0>(evals) += + (((z_perm + lagrange_first) * (w_1 + id_1 * beta + gamma) * (w_2 + id_2 * beta + gamma) * + (w_3 + id_3 * beta + gamma)) - + ((z_perm_shift + lagrange_last * public_input_delta) * (w_1 + sigma_1 * beta + gamma) * + (w_2 + sigma_2 * beta + gamma) * (w_3 + sigma_3 * beta + gamma))) * + scaling_factor; + } + { + static constexpr size_t LENGTH = CONSTRAINT_LENGTH[1]; + auto z_perm_shift = UnivariateView(extended_edges.z_perm_shift); + auto lagrange_last = UnivariateView(extended_edges.lagrange_last); + + // Contribution (2) + std::get<1>(evals) += (lagrange_last * z_perm_shift) * scaling_factor; + } }; void add_full_relation_value_contribution(RelationValues& full_honk_relation_value, @@ -101,17 +107,24 @@ template class PermutationRelation { (z_perm_shift + lagrange_last * public_input_delta) * (w_1 + beta * sigma_1 + gamma) * (w_2 + beta * sigma_2 + gamma) * (w_3 + beta * sigma_3 + gamma)); + // Contribution (2) std::get<1>(full_honk_relation_value) += lagrange_last * z_perm_shift; }; }; // TODO(luke): With Cody's Flavor work it should be easier to create a simple templated relation // for handling arbitrary width. For now I'm duplicating the width 3 logic for width 4. -template class UltraGrandProductComputationRelation { +template class UltraPermutationRelation { public: // 1 + polynomial degree of this relation static constexpr size_t RELATION_LENGTH = 6; + static constexpr size_t NUM_CONSTRAINTS = 2; + static constexpr std::array CONSTRAINT_LENGTH = { 6, 3 }; + + using RelationUnivariates = std::tuple, Univariate>; + using RelationValues = std::array; + /** * @brief Compute contribution of the permutation relation for a given edge (internal function) * @@ -123,7 +136,7 @@ template class UltraGrandProductComputationRelation { * @param parameters contains beta, gamma, and public_input_delta, .... * @param scaling_factor optional term to scale the evaluation before adding to evals. */ - inline void add_edge_contribution(Univariate& evals, + inline void add_edge_contribution(RelationUnivariates& evals, const auto& extended_edges, const RelationParameters& relation_parameters, const FF& scaling_factor) const @@ -132,32 +145,44 @@ template class UltraGrandProductComputationRelation { const auto& gamma = relation_parameters.gamma; const auto& public_input_delta = relation_parameters.public_input_delta; - auto w_1 = UnivariateView(extended_edges.w_l); - auto w_2 = UnivariateView(extended_edges.w_r); - auto w_3 = UnivariateView(extended_edges.w_o); - auto w_4 = UnivariateView(extended_edges.w_4); - auto sigma_1 = UnivariateView(extended_edges.sigma_1); - auto sigma_2 = UnivariateView(extended_edges.sigma_2); - auto sigma_3 = UnivariateView(extended_edges.sigma_3); - auto sigma_4 = UnivariateView(extended_edges.sigma_4); - auto id_1 = UnivariateView(extended_edges.id_1); - auto id_2 = UnivariateView(extended_edges.id_2); - auto id_3 = UnivariateView(extended_edges.id_3); - auto id_4 = UnivariateView(extended_edges.id_4); - auto z_perm = UnivariateView(extended_edges.z_perm); - auto z_perm_shift = UnivariateView(extended_edges.z_perm_shift); - auto lagrange_first = UnivariateView(extended_edges.lagrange_first); - auto lagrange_last = UnivariateView(extended_edges.lagrange_last); - // Contribution (1) - evals += (((z_perm + lagrange_first) * (w_1 + id_1 * beta + gamma) * (w_2 + id_2 * beta + gamma) * - (w_3 + id_3 * beta + gamma) * (w_4 + id_4 * beta + gamma)) - - ((z_perm_shift + lagrange_last * public_input_delta) * (w_1 + sigma_1 * beta + gamma) * - (w_2 + sigma_2 * beta + gamma) * (w_3 + sigma_3 * beta + gamma) * (w_4 + sigma_4 * beta + gamma))) * - scaling_factor; + { + static constexpr size_t LENGTH = CONSTRAINT_LENGTH[0]; + auto w_1 = UnivariateView(extended_edges.w_l); + auto w_2 = UnivariateView(extended_edges.w_r); + auto w_3 = UnivariateView(extended_edges.w_o); + auto w_4 = UnivariateView(extended_edges.w_4); + auto sigma_1 = UnivariateView(extended_edges.sigma_1); + auto sigma_2 = UnivariateView(extended_edges.sigma_2); + auto sigma_3 = UnivariateView(extended_edges.sigma_3); + auto sigma_4 = UnivariateView(extended_edges.sigma_4); + auto id_1 = UnivariateView(extended_edges.id_1); + auto id_2 = UnivariateView(extended_edges.id_2); + auto id_3 = UnivariateView(extended_edges.id_3); + auto id_4 = UnivariateView(extended_edges.id_4); + auto z_perm = UnivariateView(extended_edges.z_perm); + auto z_perm_shift = UnivariateView(extended_edges.z_perm_shift); + auto lagrange_first = UnivariateView(extended_edges.lagrange_first); + auto lagrange_last = UnivariateView(extended_edges.lagrange_last); + + std::get<0>(evals) += + (((z_perm + lagrange_first) * (w_1 + id_1 * beta + gamma) * (w_2 + id_2 * beta + gamma) * + (w_3 + id_3 * beta + gamma) * (w_4 + id_4 * beta + gamma)) - + ((z_perm_shift + lagrange_last * public_input_delta) * (w_1 + sigma_1 * beta + gamma) * + (w_2 + sigma_2 * beta + gamma) * (w_3 + sigma_3 * beta + gamma) * (w_4 + sigma_4 * beta + gamma))) * + scaling_factor; + } + // Contribution (2) + { + static constexpr size_t LENGTH = CONSTRAINT_LENGTH[1]; + auto z_perm_shift_ = UnivariateView(extended_edges.z_perm_shift); + auto lagrange_last_ = UnivariateView(extended_edges.lagrange_last); + + std::get<1>(evals) += (lagrange_last_ * z_perm_shift_) * scaling_factor; + } }; - void add_full_relation_value_contribution(FF& full_honk_relation_value, + void add_full_relation_value_contribution(RelationValues& full_honk_relation_value, auto& purported_evaluations, const RelationParameters& relation_parameters) const { @@ -183,11 +208,14 @@ template class UltraGrandProductComputationRelation { auto lagrange_last = purported_evaluations.lagrange_last; // Contribution (1) - full_honk_relation_value += + std::get<0>(full_honk_relation_value) += ((z_perm + lagrange_first) * (w_1 + beta * id_1 + gamma) * (w_2 + beta * id_2 + gamma) * (w_3 + beta * id_3 + gamma) * (w_4 + beta * id_4 + gamma) - (z_perm_shift + lagrange_last * public_input_delta) * (w_1 + beta * sigma_1 + gamma) * (w_2 + beta * sigma_2 + gamma) * (w_3 + beta * sigma_3 + gamma) * (w_4 + beta * sigma_4 + gamma)); + + // Contribution (2) + std::get<1>(full_honk_relation_value) += lagrange_last * z_perm_shift; }; }; } // namespace proof_system::honk::sumcheck diff --git a/cpp/src/barretenberg/honk/sumcheck/relations/relation_correctness.test.cpp b/cpp/src/barretenberg/honk/sumcheck/relations/relation_correctness.test.cpp index b424ff172f..8d86e13995 100644 --- a/cpp/src/barretenberg/honk/sumcheck/relations/relation_correctness.test.cpp +++ b/cpp/src/barretenberg/honk/sumcheck/relations/relation_correctness.test.cpp @@ -384,7 +384,7 @@ TEST(RelationCorrectness, StandardRelationCorrectness) // auto relations = std::tuple(honk::sumcheck::UltraArithmeticRelation(), // honk::sumcheck::UltraArithmeticRelationSecondary(), // honk::sumcheck::UltraGrandProductInitializationRelation(), -// honk::sumcheck::UltraGrandProductComputationRelation(), +// honk::sumcheck::UltraPermutationRelation(), // honk::sumcheck::LookupGrandProductComputationRelation(), // honk::sumcheck::LookupGrandProductInitializationRelation(), // honk::sumcheck::GenPermSortRelation(), diff --git a/cpp/src/barretenberg/honk/sumcheck/relations/ultra_arithmetic_relation.hpp b/cpp/src/barretenberg/honk/sumcheck/relations/ultra_arithmetic_relation.hpp index ad07aed617..4bbd28b94a 100644 --- a/cpp/src/barretenberg/honk/sumcheck/relations/ultra_arithmetic_relation.hpp +++ b/cpp/src/barretenberg/honk/sumcheck/relations/ultra_arithmetic_relation.hpp @@ -7,15 +7,16 @@ namespace proof_system::honk::sumcheck { +// WORKTODO: fix formatting around scopes in this file template class UltraArithmeticRelation { public: // 1 + polynomial degree of this relation static constexpr size_t RELATION_LENGTH = 6; // degree(q_arith^2 * q_m * w_r * w_l) = 5 - static constexpr size_t NUM_CONSTRAINTS = 1; - static constexpr std::array CONSTRAINT_LENGTH = { 6 }; + static constexpr size_t NUM_CONSTRAINTS = 2; + static constexpr std::array CONSTRAINT_LENGTH = { 6, 5 }; - using RelationUnivariates = std::tuple>; + using RelationUnivariates = std::tuple, Univariate>; using RelationValues = std::array; /** @@ -31,42 +32,62 @@ template class UltraArithmeticRelation { * @param parameters contains beta, gamma, and public_input_delta, .... * @param scaling_factor optional term to scale the evaluation before adding to evals. */ - void add_edge_contribution(Univariate& evals, + void add_edge_contribution(RelationUnivariates& evals, const auto& extended_edges, const RelationParameters&, - const FF& scaling_factor) const - { + const FF& scaling_factor) const { // OPTIMIZATION?: Karatsuba in general, at least for some degrees? // See https://hackmd.io/xGLuj6biSsCjzQnYN-pEiA?both + // clang-format off + // Contribution 1 + { + static constexpr size_t LENGTH = CONSTRAINT_LENGTH[0]; + auto w_l = UnivariateView(extended_edges.w_l); + auto w_r = UnivariateView(extended_edges.w_r); + auto w_o = UnivariateView(extended_edges.w_o); + auto w_4 = UnivariateView(extended_edges.w_4); + auto w_4_shift = UnivariateView(extended_edges.w_4_shift); + auto q_m = UnivariateView(extended_edges.q_m); + auto q_l = UnivariateView(extended_edges.q_l); + auto q_r = UnivariateView(extended_edges.q_r); + auto q_o = UnivariateView(extended_edges.q_o); + auto q_4 = UnivariateView(extended_edges.q_4); + auto q_c = UnivariateView(extended_edges.q_c); + auto q_arith = UnivariateView(extended_edges.q_arith); - auto w_l = UnivariateView(extended_edges.w_l); - auto w_r = UnivariateView(extended_edges.w_r); - auto w_o = UnivariateView(extended_edges.w_o); - auto w_4 = UnivariateView(extended_edges.w_4); - auto w_4_shift = UnivariateView(extended_edges.w_4_shift); - auto q_m = UnivariateView(extended_edges.q_m); - auto q_l = UnivariateView(extended_edges.q_l); - auto q_r = UnivariateView(extended_edges.q_r); - auto q_o = UnivariateView(extended_edges.q_o); - auto q_4 = UnivariateView(extended_edges.q_4); - auto q_c = UnivariateView(extended_edges.q_c); - auto q_arith = UnivariateView(extended_edges.q_arith); + static const FF neg_half = FF(-2).invert(); - static const FF neg_half = FF(-2).invert(); + auto tmp = (q_arith - 3) * (q_m * w_r * w_l) * neg_half; + tmp += (q_l * w_l) + (q_r * w_r) + (q_o * w_o) + (q_4 * w_4) + q_c; + tmp += (q_arith - 1) * w_4_shift; + tmp *= q_arith; + tmp *= scaling_factor; + std::get<0>(evals) += tmp; + } + // Contribution 2 + { + static constexpr size_t LENGTH = CONSTRAINT_LENGTH[1]; + auto w_l = UnivariateView(extended_edges.w_l); + auto w_4 = UnivariateView(extended_edges.w_4); + auto w_l_shift = UnivariateView(extended_edges.w_l_shift); + auto q_m = UnivariateView(extended_edges.q_m); + auto q_arith = UnivariateView(extended_edges.q_arith); - auto tmp = (q_arith - 3) * (q_m * w_r * w_l) * neg_half; - tmp += (q_l * w_l) + (q_r * w_r) + (q_o * w_o) + (q_4 * w_4) + q_c; - tmp += (q_arith - 1) * w_4_shift; - tmp *= q_arith; - tmp *= scaling_factor; - evals += tmp; - }; + auto tmp = w_l + w_4 - w_l_shift + q_m; + tmp *= (q_arith - 2); + tmp *= (q_arith - 1); + tmp *= q_arith; + tmp *= scaling_factor; + std::get<1>(evals) += tmp; + } + }; // namespace proof_system::honk::sumcheck - void add_full_relation_value_contribution(FF& full_honk_relation_value, - const auto& purported_evaluations, - const RelationParameters&) const + void add_full_relation_value_contribution(RelationValues& full_honk_relation_value, + const auto& purported_evaluations, + const RelationParameters&) const { auto w_l = purported_evaluations.w_l; + auto w_l_shift = purported_evaluations.w_l_shift; auto w_r = purported_evaluations.w_r; auto w_o = purported_evaluations.w_o; auto w_4 = purported_evaluations.w_4; @@ -81,11 +102,20 @@ template class UltraArithmeticRelation { static const FF neg_half = FF(-2).invert(); + // Contribution 1 auto tmp = (q_arith - 3) * (q_m * w_r * w_l) * neg_half; tmp += (q_l * w_l) + (q_r * w_r) + (q_o * w_o) + (q_4 * w_4) + q_c; tmp += (q_arith - 1) * w_4_shift; tmp *= q_arith; - full_honk_relation_value += tmp; + std::get<0>(full_honk_relation_value) += tmp; + + // Contribution 2 + tmp = w_l + w_4 - w_l_shift + q_m; + tmp *= (q_arith - 2); + tmp *= (q_arith - 1); + tmp *= q_arith; + std::get<1>(full_honk_relation_value) += tmp; }; }; +// clang-format on } // namespace proof_system::honk::sumcheck diff --git a/cpp/src/barretenberg/honk/sumcheck/relations/ultra_relation_consistency.test.cpp b/cpp/src/barretenberg/honk/sumcheck/relations/ultra_relation_consistency.test.cpp index 6696a7bbf1..fe874ad11a 100644 --- a/cpp/src/barretenberg/honk/sumcheck/relations/ultra_relation_consistency.test.cpp +++ b/cpp/src/barretenberg/honk/sumcheck/relations/ultra_relation_consistency.test.cpp @@ -7,7 +7,6 @@ // #include "barretenberg/honk/flavor/ultra.hpp" // #include "relation.hpp" // #include "arithmetic_relation.hpp" -// #include "grand_product_initialization_relation.hpp" // #include "permutation_relation.hpp" // #include "../polynomials/univariate.hpp" // #include "../polynomials/barycentric_data.hpp" @@ -251,7 +250,7 @@ // validate_evaluations(expected_evals, relation, extended_edges, relation_parameters); // }; -// TEST_F(UltraRelationConsistency, UltraGrandProductComputationRelation) +// TEST_F(UltraRelationConsistency, UltraPermutationRelation) // { // using Flavor = honk::flavor::Ultra; // using FF = typename Flavor::FF; @@ -270,7 +269,7 @@ // } // compute_mock_extended_edges(extended_edges, input_polynomials); -// auto relation = UltraGrandProductComputationRelation(); +// auto relation = UltraPermutationRelation(); // const auto& beta = relation_parameters.beta; // const auto& gamma = relation_parameters.gamma; From 2a7a923bf1cdd363946d4ed231c5999fe8eef378 Mon Sep 17 00:00:00 2001 From: ledwards2225 Date: Mon, 15 May 2023 23:21:59 +0000 Subject: [PATCH 03/18] try to fix build errorfor invoke --- cpp/src/barretenberg/honk/sumcheck/sumcheck_round.hpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/cpp/src/barretenberg/honk/sumcheck/sumcheck_round.hpp b/cpp/src/barretenberg/honk/sumcheck/sumcheck_round.hpp index 1df35bf24e..c84557b8b8 100644 --- a/cpp/src/barretenberg/honk/sumcheck/sumcheck_round.hpp +++ b/cpp/src/barretenberg/honk/sumcheck/sumcheck_round.hpp @@ -7,7 +7,8 @@ #include "polynomials/univariate.hpp" #include "polynomials/pow.hpp" #include "relations/relation.hpp" -#include "barretenberg/honk/flavor/ultra.hpp" // WORKTOO +#include "barretenberg/honk/flavor/ultra.hpp" +#include namespace proof_system::honk::sumcheck { From 4c89695b361c319a8283835509c5bdf2cf35daf0 Mon Sep 17 00:00:00 2001 From: ledwards2225 Date: Mon, 15 May 2023 23:47:41 +0000 Subject: [PATCH 04/18] add lookup relation --- .../honk/proof_system/ultra_prover.cpp | 4 +- .../honk/proof_system/ultra_verifier.cpp | 4 +- .../honk/sumcheck/new_sumcheck.test.cpp | 23 +++- ...oduct_relation.hpp => lookup_relation.hpp} | 128 ++++++++++-------- .../relations/permutation_relation.hpp | 6 +- .../relations/relation_consistency.test.cpp | 2 +- .../relations/relation_correctness.test.cpp | 4 +- .../ultra_relation_consistency.test.cpp | 6 +- 8 files changed, 107 insertions(+), 70 deletions(-) rename cpp/src/barretenberg/honk/sumcheck/relations/{lookup_grand_product_relation.hpp => lookup_relation.hpp} (62%) diff --git a/cpp/src/barretenberg/honk/proof_system/ultra_prover.cpp b/cpp/src/barretenberg/honk/proof_system/ultra_prover.cpp index e271b8040a..752fc94054 100644 --- a/cpp/src/barretenberg/honk/proof_system/ultra_prover.cpp +++ b/cpp/src/barretenberg/honk/proof_system/ultra_prover.cpp @@ -17,7 +17,7 @@ #include "barretenberg/ecc/curves/bn254/g1.hpp" #include "barretenberg/honk/sumcheck/relations/arithmetic_relation.hpp" #include "barretenberg/honk/sumcheck/relations/permutation_relation.hpp" -#include "barretenberg/honk/sumcheck/relations/lookup_grand_product_relation.hpp" +#include "barretenberg/honk/sumcheck/relations/lookup_relation.hpp" #include "barretenberg/honk/sumcheck/relations/gen_perm_sort_relation.hpp" #include "barretenberg/honk/sumcheck/relations/elliptic_relation.hpp" #include "barretenberg/honk/sumcheck/relations/auxiliary_relation.hpp" @@ -197,7 +197,7 @@ template void UltraProver_::execute_relation_check_ // sumcheck::UltraArithmeticRelationSecondary, // sumcheck::UltraPermutationRelation, // sumcheck::UltraGrandProductInitializationRelation, - // sumcheck::LookupGrandProductComputationRelation, + // sumcheck::LookupRelation, // sumcheck::LookupGrandProductInitializationRelation, // sumcheck::GenPermSortRelation, // sumcheck::EllipticRelation, diff --git a/cpp/src/barretenberg/honk/proof_system/ultra_verifier.cpp b/cpp/src/barretenberg/honk/proof_system/ultra_verifier.cpp index 2a8a5817d9..7652cf5f2a 100644 --- a/cpp/src/barretenberg/honk/proof_system/ultra_verifier.cpp +++ b/cpp/src/barretenberg/honk/proof_system/ultra_verifier.cpp @@ -7,7 +7,7 @@ #include "barretenberg/honk/sumcheck/relations/ultra_arithmetic_relation.hpp" #include "barretenberg/honk/sumcheck/relations/ultra_arithmetic_relation_secondary.hpp" #include "barretenberg/honk/sumcheck/relations/permutation_relation.hpp" -#include "barretenberg/honk/sumcheck/relations/lookup_grand_product_relation.hpp" +#include "barretenberg/honk/sumcheck/relations/lookup_relation.hpp" #include "barretenberg/honk/sumcheck/relations/gen_perm_sort_relation.hpp" #include "barretenberg/honk/sumcheck/relations/elliptic_relation.hpp" #include "barretenberg/honk/sumcheck/relations/auxiliary_relation.hpp" @@ -114,7 +114,7 @@ template bool UltraVerifier_::verify_proof(const plonk // honk::sumcheck::UltraArithmeticRelationSecondary, // honk::sumcheck::UltraPermutationRelation, // honk::sumcheck::UltraGrandProductInitializationRelation, - // honk::sumcheck::LookupGrandProductComputationRelation, + // honk::sumcheck::LookupRelation, // honk::sumcheck::LookupGrandProductInitializationRelation, // honk::sumcheck::GenPermSortRelation, // honk::sumcheck::EllipticRelation, diff --git a/cpp/src/barretenberg/honk/sumcheck/new_sumcheck.test.cpp b/cpp/src/barretenberg/honk/sumcheck/new_sumcheck.test.cpp index 15687269b6..1b0f68d149 100644 --- a/cpp/src/barretenberg/honk/sumcheck/new_sumcheck.test.cpp +++ b/cpp/src/barretenberg/honk/sumcheck/new_sumcheck.test.cpp @@ -4,6 +4,7 @@ #include "barretenberg/transcript/transcript_wrappers.hpp" #include "relations/arithmetic_relation.hpp" #include "relations/permutation_relation.hpp" +#include "relations/lookup_relation.hpp" #include "relations/ultra_arithmetic_relation.hpp" #include "barretenberg/transcript/manifest.hpp" #include @@ -141,6 +142,21 @@ TEST(NewSumcheck, Ultra) composer.create_big_add_gate({ a_idx, b_idx, c_idx, d_idx, -1, -1, -1, -1, 0 }, true); // use next row composer.create_big_add_gate({ zero_idx, zero_idx, zero_idx, e_idx, 0, 0, 0, 0, 0 }, false); + // Add some lookup gates (related to pedersen hashing) + barretenberg::fr pedersen_input_value = fr::random_element(); + const fr input_hi = uint256_t(pedersen_input_value).slice(126, 256); + const fr input_lo = uint256_t(pedersen_input_value).slice(0, 126); + const auto input_hi_index = composer.add_variable(input_hi); + const auto input_lo_index = 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); + + composer.create_gates_from_plookup_accumulators( + plookup::MultiTableId::PEDERSEN_LEFT_HI, sequence_data_hi, input_hi_index); + composer.create_gates_from_plookup_accumulators( + plookup::MultiTableId::PEDERSEN_LEFT_LO, sequence_data_lo, input_lo_index); + // Create a prover (it will compute proving key and witness) auto prover = composer.create_prover(); @@ -224,15 +240,16 @@ TEST(NewSumcheck, Ultra) auto prover_transcript = ProverTranscript::init_empty(); - auto sumcheck_prover = Sumcheck, UltraArithmeticRelation, UltraPermutationRelation>( - prover.key->circuit_size, prover_transcript); + auto sumcheck_prover = + Sumcheck, UltraArithmeticRelation, UltraPermutationRelation, LookupRelation>( + prover.key->circuit_size, prover_transcript); auto prover_output = sumcheck_prover.execute_prover(prover_polynomials, relation_parameters); auto verifier_transcript = VerifierTranscript::init_empty(prover_transcript); auto sumcheck_verifier = - Sumcheck, UltraArithmeticRelation, UltraPermutationRelation>( + Sumcheck, UltraArithmeticRelation, UltraPermutationRelation, LookupRelation>( prover.key->circuit_size, verifier_transcript); std::optional verifier_output = sumcheck_verifier.execute_verifier(relation_parameters); diff --git a/cpp/src/barretenberg/honk/sumcheck/relations/lookup_grand_product_relation.hpp b/cpp/src/barretenberg/honk/sumcheck/relations/lookup_relation.hpp similarity index 62% rename from cpp/src/barretenberg/honk/sumcheck/relations/lookup_grand_product_relation.hpp rename to cpp/src/barretenberg/honk/sumcheck/relations/lookup_relation.hpp index 32830a8dc3..f966caf86a 100644 --- a/cpp/src/barretenberg/honk/sumcheck/relations/lookup_grand_product_relation.hpp +++ b/cpp/src/barretenberg/honk/sumcheck/relations/lookup_relation.hpp @@ -7,11 +7,17 @@ namespace proof_system::honk::sumcheck { -template class LookupGrandProductComputationRelation { +template class LookupRelation { public: // 1 + polynomial degree of this relation static constexpr size_t RELATION_LENGTH = 6; // deg(z_lookup * column_selector * wire * q_lookup * table) = 5 + static constexpr size_t NUM_CONSTRAINTS = 2; + static constexpr std::array CONSTRAINT_LENGTH = { 6, 3 }; + + using RelationUnivariates = std::tuple, Univariate>; + using RelationValues = std::array; + /** * @brief Compute contribution of the lookup grand prod relation for a given edge (internal function) * @@ -30,7 +36,7 @@ template class LookupGrandProductComputationRelation { * @param parameters contains beta, gamma, and public_input_delta, .... * @param scaling_factor optional term to scale the evaluation before adding to evals. */ - inline void add_edge_contribution(Univariate& evals, + inline void add_edge_contribution(RelationUnivariates& evals, const auto& extended_edges, const RelationParameters& relation_parameters, const FF& scaling_factor) const @@ -45,60 +51,71 @@ template class LookupGrandProductComputationRelation { const auto eta_sqr = eta * eta; const auto eta_cube = eta_sqr * eta; - auto w_1 = UnivariateView(extended_edges.w_l); - auto w_2 = UnivariateView(extended_edges.w_r); - auto w_3 = UnivariateView(extended_edges.w_o); - - auto w_1_shift = UnivariateView(extended_edges.w_l_shift); - auto w_2_shift = UnivariateView(extended_edges.w_r_shift); - auto w_3_shift = UnivariateView(extended_edges.w_o_shift); - - auto table_1 = UnivariateView(extended_edges.table_1); - auto table_2 = UnivariateView(extended_edges.table_2); - auto table_3 = UnivariateView(extended_edges.table_3); - auto table_4 = UnivariateView(extended_edges.table_4); - - auto table_1_shift = UnivariateView(extended_edges.table_1_shift); - auto table_2_shift = UnivariateView(extended_edges.table_2_shift); - auto table_3_shift = UnivariateView(extended_edges.table_3_shift); - auto table_4_shift = UnivariateView(extended_edges.table_4_shift); - - auto s_accum = UnivariateView(extended_edges.sorted_accum); - auto s_accum_shift = UnivariateView(extended_edges.sorted_accum_shift); - - auto z_lookup = UnivariateView(extended_edges.z_lookup); - auto z_lookup_shift = UnivariateView(extended_edges.z_lookup_shift); - - auto table_index = UnivariateView(extended_edges.q_o); - auto column_1_step_size = UnivariateView(extended_edges.q_r); - auto column_2_step_size = UnivariateView(extended_edges.q_m); - auto column_3_step_size = UnivariateView(extended_edges.q_c); - auto q_lookup = UnivariateView(extended_edges.q_lookup); - - auto lagrange_first = UnivariateView(extended_edges.lagrange_first); - auto lagrange_last = UnivariateView(extended_edges.lagrange_last); - - // (w_1 + q_2*w_1_shift) + η(w_2 + q_m*w_2_shift) + η²(w_3 + q_c*w_3_shift) + η³q_index. - auto wire_accum = (w_1 + column_1_step_size * w_1_shift) + (w_2 + column_2_step_size * w_2_shift) * eta + - (w_3 + column_3_step_size * w_3_shift) * eta_sqr + table_index * eta_cube; - - // t_1 + ηt_2 + η²t_3 + η³t_4 - auto table_accum = table_1 + table_2 * eta + table_3 * eta_sqr + table_4 * eta_cube; - // t_1_shift + ηt_2_shift + η²t_3_shift + η³t_4_shift - auto table_accum_shift = - table_1_shift + table_2_shift * eta + table_3_shift * eta_sqr + table_4_shift * eta_cube; - // Contribution (1) - auto tmp = (q_lookup * wire_accum + gamma); - tmp *= (table_accum + table_accum_shift * beta + gamma_by_one_plus_beta); - tmp *= one_plus_beta; - tmp *= (z_lookup + lagrange_first); - tmp -= (z_lookup_shift + lagrange_last * grand_product_delta) * - (s_accum + s_accum_shift * beta + gamma_by_one_plus_beta); - evals += tmp * scaling_factor; + { + static constexpr size_t LENGTH = CONSTRAINT_LENGTH[0]; + auto w_1 = UnivariateView(extended_edges.w_l); + auto w_2 = UnivariateView(extended_edges.w_r); + auto w_3 = UnivariateView(extended_edges.w_o); + + auto w_1_shift = UnivariateView(extended_edges.w_l_shift); + auto w_2_shift = UnivariateView(extended_edges.w_r_shift); + auto w_3_shift = UnivariateView(extended_edges.w_o_shift); + + auto table_1 = UnivariateView(extended_edges.table_1); + auto table_2 = UnivariateView(extended_edges.table_2); + auto table_3 = UnivariateView(extended_edges.table_3); + auto table_4 = UnivariateView(extended_edges.table_4); + + auto table_1_shift = UnivariateView(extended_edges.table_1_shift); + auto table_2_shift = UnivariateView(extended_edges.table_2_shift); + auto table_3_shift = UnivariateView(extended_edges.table_3_shift); + auto table_4_shift = UnivariateView(extended_edges.table_4_shift); + + auto s_accum = UnivariateView(extended_edges.sorted_accum); + auto s_accum_shift = UnivariateView(extended_edges.sorted_accum_shift); + + auto z_lookup = UnivariateView(extended_edges.z_lookup); + auto z_lookup_shift = UnivariateView(extended_edges.z_lookup_shift); + + auto table_index = UnivariateView(extended_edges.q_o); + auto column_1_step_size = UnivariateView(extended_edges.q_r); + auto column_2_step_size = UnivariateView(extended_edges.q_m); + auto column_3_step_size = UnivariateView(extended_edges.q_c); + auto q_lookup = UnivariateView(extended_edges.q_lookup); + + auto lagrange_first = UnivariateView(extended_edges.lagrange_first); + auto lagrange_last = UnivariateView(extended_edges.lagrange_last); + + // (w_1 + q_2*w_1_shift) + η(w_2 + q_m*w_2_shift) + η²(w_3 + q_c*w_3_shift) + η³q_index. + auto wire_accum = (w_1 + column_1_step_size * w_1_shift) + (w_2 + column_2_step_size * w_2_shift) * eta + + (w_3 + column_3_step_size * w_3_shift) * eta_sqr + table_index * eta_cube; + + // t_1 + ηt_2 + η²t_3 + η³t_4 + auto table_accum = table_1 + table_2 * eta + table_3 * eta_sqr + table_4 * eta_cube; + // t_1_shift + ηt_2_shift + η²t_3_shift + η³t_4_shift + auto table_accum_shift = + table_1_shift + table_2_shift * eta + table_3_shift * eta_sqr + table_4_shift * eta_cube; + + auto tmp = (q_lookup * wire_accum + gamma); + tmp *= (table_accum + table_accum_shift * beta + gamma_by_one_plus_beta); + tmp *= one_plus_beta; + tmp *= (z_lookup + lagrange_first); + tmp -= (z_lookup_shift + lagrange_last * grand_product_delta) * + (s_accum + s_accum_shift * beta + gamma_by_one_plus_beta); + std::get<0>(evals) += tmp * scaling_factor; + } + { + static constexpr size_t LENGTH = CONSTRAINT_LENGTH[1]; + auto z_lookup_shift = UnivariateView(extended_edges.z_lookup_shift); + auto lagrange_last = UnivariateView(extended_edges.lagrange_last); + + // Contribution (2) + std::get<1>(evals) += (lagrange_last * z_lookup_shift) * scaling_factor; + } }; - void add_full_relation_value_contribution(FF& full_honk_relation_value, + void add_full_relation_value_contribution(RelationValues& full_honk_relation_value, auto& purported_evaluations, const RelationParameters& relation_parameters) const { @@ -162,7 +179,10 @@ template class LookupGrandProductComputationRelation { tmp *= (z_lookup + lagrange_first); tmp -= (z_lookup_shift + lagrange_last * grand_product_delta) * (s_accum + beta * s_accum_shift + gamma_by_one_plus_beta); - full_honk_relation_value += tmp; + std::get<0>(full_honk_relation_value) += tmp; + + // Contribution (2) + std::get<1>(full_honk_relation_value) += lagrange_last * z_lookup_shift; }; }; diff --git a/cpp/src/barretenberg/honk/sumcheck/relations/permutation_relation.hpp b/cpp/src/barretenberg/honk/sumcheck/relations/permutation_relation.hpp index 9a415de4d9..829d73f08e 100644 --- a/cpp/src/barretenberg/honk/sumcheck/relations/permutation_relation.hpp +++ b/cpp/src/barretenberg/honk/sumcheck/relations/permutation_relation.hpp @@ -175,10 +175,10 @@ template class UltraPermutationRelation { // Contribution (2) { static constexpr size_t LENGTH = CONSTRAINT_LENGTH[1]; - auto z_perm_shift_ = UnivariateView(extended_edges.z_perm_shift); - auto lagrange_last_ = UnivariateView(extended_edges.lagrange_last); + auto z_perm_shift = UnivariateView(extended_edges.z_perm_shift); + auto lagrange_last = UnivariateView(extended_edges.lagrange_last); - std::get<1>(evals) += (lagrange_last_ * z_perm_shift_) * scaling_factor; + std::get<1>(evals) += (lagrange_last * z_perm_shift) * scaling_factor; } }; diff --git a/cpp/src/barretenberg/honk/sumcheck/relations/relation_consistency.test.cpp b/cpp/src/barretenberg/honk/sumcheck/relations/relation_consistency.test.cpp index 49192d87bd..51425e5c03 100644 --- a/cpp/src/barretenberg/honk/sumcheck/relations/relation_consistency.test.cpp +++ b/cpp/src/barretenberg/honk/sumcheck/relations/relation_consistency.test.cpp @@ -1,4 +1,4 @@ -#include "barretenberg/honk/sumcheck/relations/lookup_grand_product_relation.hpp" +#include "barretenberg/honk/sumcheck/relations/lookup_relation.hpp" #include "barretenberg/honk/sumcheck/relations/ultra_arithmetic_relation.hpp" #include "barretenberg/honk/sumcheck/relations/ultra_arithmetic_relation_secondary.hpp" #include "barretenberg/honk/flavor/standard.hpp" diff --git a/cpp/src/barretenberg/honk/sumcheck/relations/relation_correctness.test.cpp b/cpp/src/barretenberg/honk/sumcheck/relations/relation_correctness.test.cpp index 8d86e13995..492b3818be 100644 --- a/cpp/src/barretenberg/honk/sumcheck/relations/relation_correctness.test.cpp +++ b/cpp/src/barretenberg/honk/sumcheck/relations/relation_correctness.test.cpp @@ -8,7 +8,7 @@ #include "barretenberg/honk/sumcheck/relations/permutation_relation.hpp" #include "barretenberg/honk/sumcheck/relations/ultra_arithmetic_relation.hpp" #include "barretenberg/honk/sumcheck/relations/ultra_arithmetic_relation_secondary.hpp" -#include "barretenberg/honk/sumcheck/relations/lookup_grand_product_relation.hpp" +#include "barretenberg/honk/sumcheck/relations/lookup_relation.hpp" #include "barretenberg/honk/sumcheck/relations/gen_perm_sort_relation.hpp" #include "barretenberg/honk/sumcheck/relations/elliptic_relation.hpp" #include "barretenberg/honk/sumcheck/relations/auxiliary_relation.hpp" @@ -385,7 +385,7 @@ TEST(RelationCorrectness, StandardRelationCorrectness) // honk::sumcheck::UltraArithmeticRelationSecondary(), // honk::sumcheck::UltraGrandProductInitializationRelation(), // honk::sumcheck::UltraPermutationRelation(), -// honk::sumcheck::LookupGrandProductComputationRelation(), +// honk::sumcheck::LookupRelation(), // honk::sumcheck::LookupGrandProductInitializationRelation(), // honk::sumcheck::GenPermSortRelation(), // honk::sumcheck::EllipticRelation(), diff --git a/cpp/src/barretenberg/honk/sumcheck/relations/ultra_relation_consistency.test.cpp b/cpp/src/barretenberg/honk/sumcheck/relations/ultra_relation_consistency.test.cpp index fe874ad11a..331950ea89 100644 --- a/cpp/src/barretenberg/honk/sumcheck/relations/ultra_relation_consistency.test.cpp +++ b/cpp/src/barretenberg/honk/sumcheck/relations/ultra_relation_consistency.test.cpp @@ -1,6 +1,6 @@ // #include "barretenberg/honk/sumcheck/relations/ultra_arithmetic_relation.hpp" // #include "barretenberg/honk/sumcheck/relations/ultra_arithmetic_relation_secondary.hpp" -// #include "barretenberg/honk/sumcheck/relations/lookup_grand_product_relation.hpp" +// #include "barretenberg/honk/sumcheck/relations/lookup_relation.hpp" // #include "barretenberg/honk/sumcheck/relations/gen_perm_sort_relation.hpp" // #include "barretenberg/honk/sumcheck/relations/elliptic_relation.hpp" // #include "barretenberg/honk/sumcheck/relations/auxiliary_relation.hpp" @@ -303,7 +303,7 @@ // validate_evaluations(expected_evals, relation, extended_edges, relation_parameters); // }; -// TEST_F(UltraRelationConsistency, LookupGrandProductComputationRelation) +// TEST_F(UltraRelationConsistency, LookupRelation) // { // using Flavor = honk::flavor::Ultra; // using FF = typename Flavor::FF; @@ -322,7 +322,7 @@ // } // compute_mock_extended_edges(extended_edges, input_polynomials); -// auto relation = LookupGrandProductComputationRelation(); +// auto relation = LookupRelation(); // const auto eta = relation_parameters.eta; // const auto beta = relation_parameters.beta; From 616c03141c5f16714da31b565d6809ce9fcc404f Mon Sep 17 00:00:00 2001 From: ledwards2225 Date: Tue, 16 May 2023 18:54:59 +0000 Subject: [PATCH 05/18] update gen perm sort relation --- .../honk/sumcheck/new_sumcheck.test.cpp | 26 +++++-- .../relations/gen_perm_sort_relation.hpp | 74 +++++++++---------- 2 files changed, 55 insertions(+), 45 deletions(-) diff --git a/cpp/src/barretenberg/honk/sumcheck/new_sumcheck.test.cpp b/cpp/src/barretenberg/honk/sumcheck/new_sumcheck.test.cpp index 1b0f68d149..1d343e59d7 100644 --- a/cpp/src/barretenberg/honk/sumcheck/new_sumcheck.test.cpp +++ b/cpp/src/barretenberg/honk/sumcheck/new_sumcheck.test.cpp @@ -6,6 +6,7 @@ #include "relations/permutation_relation.hpp" #include "relations/lookup_relation.hpp" #include "relations/ultra_arithmetic_relation.hpp" +#include "relations/gen_perm_sort_relation.hpp" #include "barretenberg/transcript/manifest.hpp" #include #include @@ -157,6 +158,13 @@ TEST(NewSumcheck, Ultra) composer.create_gates_from_plookup_accumulators( plookup::MultiTableId::PEDERSEN_LEFT_LO, sequence_data_lo, input_lo_index); + // Add a sort gate (simply checks that consecutive inputs have a difference of < 4) + a_idx = composer.add_variable(FF(0)); + b_idx = composer.add_variable(FF(1)); + c_idx = composer.add_variable(FF(2)); + d_idx = composer.add_variable(FF(3)); + composer.create_sort_constraint({ a_idx, b_idx, c_idx, d_idx }); + // Create a prover (it will compute proving key and witness) auto prover = composer.create_prover(); @@ -240,17 +248,23 @@ TEST(NewSumcheck, Ultra) auto prover_transcript = ProverTranscript::init_empty(); - auto sumcheck_prover = - Sumcheck, UltraArithmeticRelation, UltraPermutationRelation, LookupRelation>( - prover.key->circuit_size, prover_transcript); + auto sumcheck_prover = Sumcheck, + UltraArithmeticRelation, + UltraPermutationRelation, + LookupRelation, + GenPermSortRelation>(prover.key->circuit_size, prover_transcript); auto prover_output = sumcheck_prover.execute_prover(prover_polynomials, relation_parameters); auto verifier_transcript = VerifierTranscript::init_empty(prover_transcript); - auto sumcheck_verifier = - Sumcheck, UltraArithmeticRelation, UltraPermutationRelation, LookupRelation>( - prover.key->circuit_size, verifier_transcript); + auto sumcheck_verifier = Sumcheck, + UltraArithmeticRelation, + UltraPermutationRelation, + LookupRelation, + GenPermSortRelation>(prover.key->circuit_size, verifier_transcript); std::optional verifier_output = sumcheck_verifier.execute_verifier(relation_parameters); diff --git a/cpp/src/barretenberg/honk/sumcheck/relations/gen_perm_sort_relation.hpp b/cpp/src/barretenberg/honk/sumcheck/relations/gen_perm_sort_relation.hpp index 1eb10c0670..e1cd70f10c 100644 --- a/cpp/src/barretenberg/honk/sumcheck/relations/gen_perm_sort_relation.hpp +++ b/cpp/src/barretenberg/honk/sumcheck/relations/gen_perm_sort_relation.hpp @@ -12,6 +12,15 @@ template class GenPermSortRelation { // 1 + polynomial degree of this relation static constexpr size_t RELATION_LENGTH = 6; // degree(q_sort * D(D - 1)(D - 2)(D - 3)) = 5 + static constexpr size_t NUM_CONSTRAINTS = 4; + static constexpr std::array CONSTRAINT_LENGTH = { 6, 6, 6, 6 }; + + using RelationUnivariates = std::tuple, + Univariate, + Univariate, + Univariate>; + using RelationValues = std::array; + /** * @brief Expression for the generalized permutation sort gate. * @details The relation is defined as C(extended_edges(X)...) = @@ -27,7 +36,7 @@ template class GenPermSortRelation { * @param parameters contains beta, gamma, and public_input_delta, .... * @param scaling_factor optional term to scale the evaluation before adding to evals. */ - void add_edge_contribution(Univariate& evals, + void add_edge_contribution(RelationUnivariates& evals, const auto& extended_edges, const RelationParameters&, const FF& scaling_factor) const @@ -46,53 +55,50 @@ template class GenPermSortRelation { static const FF minus_two = FF(-2); static const FF minus_three = FF(-3); - // TODO(#427): Eventually this would be based on real alpha but this is not a full solution - // since utilizing powers of alpha internal to a relation results in incorrect powers - // being used in the ultimate univariate batching. i.e we'd wind up reusing the same power - // of alpha in multiple relations. - static const FF fake_alpha_1 = FF(1); - static const FF fake_alpha_2 = fake_alpha_1 * fake_alpha_1; - static const FF fake_alpha_3 = fake_alpha_2 * fake_alpha_1; - static const FF fake_alpha_4 = fake_alpha_3 * fake_alpha_1; - // Compute wire differences auto delta_1 = w_2 - w_1; auto delta_2 = w_3 - w_2; auto delta_3 = w_4 - w_3; auto delta_4 = w_1_shift - w_4; + // Contribution (1) auto tmp_1 = delta_1; tmp_1 *= (delta_1 + minus_one); tmp_1 *= (delta_1 + minus_two); tmp_1 *= (delta_1 + minus_three); - tmp_1 *= fake_alpha_1; // 1 + tmp_1 *= q_sort; + tmp_1 *= scaling_factor; + std::get<0>(evals) += tmp_1; + // Contribution (2) auto tmp_2 = delta_2; tmp_2 *= (delta_2 + minus_one); tmp_2 *= (delta_2 + minus_two); tmp_2 *= (delta_2 + minus_three); - tmp_2 *= fake_alpha_2; // alpha + tmp_2 *= q_sort; + tmp_2 *= scaling_factor; + std::get<1>(evals) += tmp_2; + // Contribution (3) auto tmp_3 = delta_3; tmp_3 *= (delta_3 + minus_one); tmp_3 *= (delta_3 + minus_two); tmp_3 *= (delta_3 + minus_three); - tmp_3 *= fake_alpha_3; // alpha^2 + tmp_3 *= q_sort; + tmp_3 *= scaling_factor; + std::get<2>(evals) += tmp_3; + // Contribution (4) auto tmp_4 = delta_4; tmp_4 *= (delta_4 + minus_one); tmp_4 *= (delta_4 + minus_two); tmp_4 *= (delta_4 + minus_three); - tmp_4 *= fake_alpha_4; // alpha^3 - - auto tmp = tmp_1 + tmp_2 + tmp_3 + tmp_4; - tmp *= q_sort; - tmp *= scaling_factor; - - evals += tmp; + tmp_4 *= q_sort; + tmp_4 *= scaling_factor; + std::get<3>(evals) += tmp_4; }; - void add_full_relation_value_contribution(FF& full_honk_relation_value, + void add_full_relation_value_contribution(RelationValues& full_honk_relation_value, const auto& purported_evaluations, const RelationParameters&) const { @@ -107,15 +113,6 @@ template class GenPermSortRelation { static const FF minus_two = FF(-2); static const FF minus_three = FF(-3); - // TODO(#427): Eventually this would be based on real alpha but this is not a full solution - // since utilizing powers of alpha internal to a relation results in incorrect powers - // being used in the ultimate univariate batching. i.e we'd wind up reusing the same power - // of alpha in multiple relations. - static const FF fake_alpha_1 = FF(1); - static const FF fake_alpha_2 = fake_alpha_1 * fake_alpha_1; - static const FF fake_alpha_3 = fake_alpha_2 * fake_alpha_1; - static const FF fake_alpha_4 = fake_alpha_3 * fake_alpha_1; - // Compute wire differences auto delta_1 = w_2 - w_1; auto delta_2 = w_3 - w_2; @@ -126,30 +123,29 @@ template class GenPermSortRelation { tmp_1 *= (delta_1 + minus_one); tmp_1 *= (delta_1 + minus_two); tmp_1 *= (delta_1 + minus_three); - tmp_1 *= fake_alpha_1; // 1 + tmp_1 *= q_sort; + std::get<0>(full_honk_relation_value) += tmp_1; auto tmp_2 = delta_2; tmp_2 *= (delta_2 + minus_one); tmp_2 *= (delta_2 + minus_two); tmp_2 *= (delta_2 + minus_three); - tmp_2 *= fake_alpha_2; // alpha + tmp_2 *= q_sort; + std::get<1>(full_honk_relation_value) += tmp_2; auto tmp_3 = delta_3; tmp_3 *= (delta_3 + minus_one); tmp_3 *= (delta_3 + minus_two); tmp_3 *= (delta_3 + minus_three); - tmp_3 *= fake_alpha_3; // alpha^2 + tmp_3 *= q_sort; + std::get<2>(full_honk_relation_value) += tmp_3; auto tmp_4 = delta_4; tmp_4 *= (delta_4 + minus_one); tmp_4 *= (delta_4 + minus_two); tmp_4 *= (delta_4 + minus_three); - tmp_4 *= fake_alpha_4; // alpha^3 - - auto tmp = tmp_1 + tmp_2 + tmp_3 + tmp_4; - tmp *= q_sort; - - full_honk_relation_value += tmp; + tmp_4 *= q_sort; + std::get<3>(full_honk_relation_value) += tmp_4; }; }; } // namespace proof_system::honk::sumcheck From 24c945bf56c60cf227a394755bc023344155d88d Mon Sep 17 00:00:00 2001 From: ledwards2225 Date: Tue, 16 May 2023 19:34:35 +0000 Subject: [PATCH 06/18] update elliptic relation --- .../honk/sumcheck/new_sumcheck.test.cpp | 27 +++- .../sumcheck/relations/elliptic_relation.hpp | 141 ++++++++++-------- 2 files changed, 103 insertions(+), 65 deletions(-) diff --git a/cpp/src/barretenberg/honk/sumcheck/new_sumcheck.test.cpp b/cpp/src/barretenberg/honk/sumcheck/new_sumcheck.test.cpp index 1d343e59d7..fb4e66845b 100644 --- a/cpp/src/barretenberg/honk/sumcheck/new_sumcheck.test.cpp +++ b/cpp/src/barretenberg/honk/sumcheck/new_sumcheck.test.cpp @@ -7,6 +7,7 @@ #include "relations/lookup_relation.hpp" #include "relations/ultra_arithmetic_relation.hpp" #include "relations/gen_perm_sort_relation.hpp" +#include "relations/elliptic_relation.hpp" #include "barretenberg/transcript/manifest.hpp" #include #include @@ -165,6 +166,26 @@ TEST(NewSumcheck, Ultra) d_idx = composer.add_variable(FF(3)); composer.create_sort_constraint({ a_idx, b_idx, c_idx, d_idx }); + // Add an elliptic curve addition gate + grumpkin::g1::affine_element p1 = crypto::generators::get_generator_data({ 0, 0 }).generator; + grumpkin::g1::affine_element p2 = crypto::generators::get_generator_data({ 0, 1 }).generator; + + grumpkin::fq beta_scalar = grumpkin::fq::cube_root_of_unity(); + grumpkin::g1::affine_element p2_endo = p2; + p2_endo.x *= beta_scalar; + + grumpkin::g1::affine_element p3(grumpkin::g1::element(p1) - grumpkin::g1::element(p2_endo)); + + uint32_t x1 = composer.add_variable(p1.x); + uint32_t y1 = composer.add_variable(p1.y); + uint32_t x2 = composer.add_variable(p2.x); + uint32_t y2 = composer.add_variable(p2.y); + uint32_t x3 = composer.add_variable(p3.x); + uint32_t y3 = composer.add_variable(p3.y); + + ecc_add_gate gate{ x1, y1, x2, y2, x3, y3, beta_scalar, -1 }; + composer.create_ecc_add_gate(gate); + // Create a prover (it will compute proving key and witness) auto prover = composer.create_prover(); @@ -253,7 +274,8 @@ TEST(NewSumcheck, Ultra) UltraArithmeticRelation, UltraPermutationRelation, LookupRelation, - GenPermSortRelation>(prover.key->circuit_size, prover_transcript); + GenPermSortRelation, + EllipticRelation>(prover.key->circuit_size, prover_transcript); auto prover_output = sumcheck_prover.execute_prover(prover_polynomials, relation_parameters); @@ -264,7 +286,8 @@ TEST(NewSumcheck, Ultra) UltraArithmeticRelation, UltraPermutationRelation, LookupRelation, - GenPermSortRelation>(prover.key->circuit_size, verifier_transcript); + GenPermSortRelation, + EllipticRelation>(prover.key->circuit_size, verifier_transcript); std::optional verifier_output = sumcheck_verifier.execute_verifier(relation_parameters); diff --git a/cpp/src/barretenberg/honk/sumcheck/relations/elliptic_relation.hpp b/cpp/src/barretenberg/honk/sumcheck/relations/elliptic_relation.hpp index 9063a43297..16b1237fd7 100644 --- a/cpp/src/barretenberg/honk/sumcheck/relations/elliptic_relation.hpp +++ b/cpp/src/barretenberg/honk/sumcheck/relations/elliptic_relation.hpp @@ -10,7 +10,13 @@ namespace proof_system::honk::sumcheck { template class EllipticRelation { public: // 1 + polynomial degree of this relation - static constexpr size_t RELATION_LENGTH = 6; // degree(q_arith^2 * q_m * w_r * w_l) = 5 + static constexpr size_t RELATION_LENGTH = 5; // degree(q_elliptic * q_beta * x^3) = 5 + + static constexpr size_t NUM_CONSTRAINTS = 2; + static constexpr std::array CONSTRAINT_LENGTH = { 6, 5 }; + + using RelationUnivariates = std::tuple, Univariate>; + using RelationValues = std::array; /** * @brief Expression for the Ultra Arithmetic gate. @@ -22,64 +28,76 @@ template class EllipticRelation { * @param parameters contains beta, gamma, and public_input_delta, .... * @param scaling_factor optional term to scale the evaluation before adding to evals. */ - void add_edge_contribution(Univariate& evals, + void add_edge_contribution(RelationUnivariates& evals, const auto& extended_edges, const RelationParameters&, - const FF& scaling_factor) const - { + const FF& scaling_factor) const { // OPTIMIZATION?: Karatsuba in general, at least for some degrees? // See https://hackmd.io/xGLuj6biSsCjzQnYN-pEiA?both - - auto x_1 = UnivariateView(extended_edges.w_r); - auto y_1 = UnivariateView(extended_edges.w_o); - - auto x_2 = UnivariateView(extended_edges.w_l_shift); - auto y_2 = UnivariateView(extended_edges.w_4_shift); - auto x_3 = UnivariateView(extended_edges.w_r_shift); - auto y_3 = UnivariateView(extended_edges.w_o_shift); - - auto q_sign = UnivariateView(extended_edges.q_l); - auto q_beta = UnivariateView(extended_edges.q_o); - auto q_beta_sqr = UnivariateView(extended_edges.q_4); - auto q_elliptic = UnivariateView(extended_edges.q_elliptic); - - static const FF fake_alpha_1 = FF(1); - static const FF fake_alpha_2 = fake_alpha_1 * fake_alpha_1; - - auto beta_term = x_2 * x_1 * (x_3 + x_3 + x_1) * FF(-1); // -x_1 * x_2 * (2 * x_3 + x_1) - auto beta_sqr_term = x_2 * x_2; // x_2^2 - auto leftovers = beta_sqr_term; // x_2^2 - beta_sqr_term *= (x_3 - x_1); // x_2^2 * (x_3 - x_1) - auto sign_term = y_2 * y_1; // y_1 * y_2 - sign_term += sign_term; // 2 * y_1 * y_2 - beta_term *= q_beta; // -β * x_1 * x_2 * (2 * x_3 + x_1) - beta_sqr_term *= q_beta_sqr; // β^2 * x_2^2 * (x_3 - x_1) - sign_term *= q_sign; // 2 * y_1 * y_2 * sign - leftovers *= x_2; // x_2^3 - leftovers += x_1 * x_1 * (x_3 + x_1); // x_2^3 + x_1 * (x_3 + x_1) - leftovers -= (y_2 * y_2 + y_1 * y_1); // x_2^3 + x_1 * (x_3 + x_1) - y_2^2 - y_1^2 - - // Can be found in class description - auto x_identity = beta_term + beta_sqr_term + sign_term + leftovers; - x_identity *= fake_alpha_1; - - beta_term = x_2 * (y_3 + y_1) * q_beta; // β * x_2 * (y_3 + y_1) - sign_term = y_2 * (x_1 - x_3) * q_sign * FF(-1); // - signt * y_2 * (x_1 - x_3) - // TODO: remove extra additions if we decide to stay with this implementation - leftovers = x_1 * (y_3 + y_1) * FF(-1) + y_1 * (x_1 - x_3); // -x_1 * y_3 - x_1 * y_1 + y_1 * x_1 - y_1 * x_3 - - auto y_identity = beta_term + sign_term + leftovers; - y_identity *= fake_alpha_2; - - auto tmp = x_identity + y_identity; - tmp *= q_elliptic; - - tmp *= scaling_factor; - - evals += tmp; + // clang-format off + // Contribution (1) + { + static constexpr size_t LENGTH = CONSTRAINT_LENGTH[0]; + auto x_1 = UnivariateView(extended_edges.w_r); + auto y_1 = UnivariateView(extended_edges.w_o); + + auto x_2 = UnivariateView(extended_edges.w_l_shift); + auto y_2 = UnivariateView(extended_edges.w_4_shift); + auto x_3 = UnivariateView(extended_edges.w_r_shift); + auto y_3 = UnivariateView(extended_edges.w_o_shift); + + auto q_sign = UnivariateView(extended_edges.q_l); + auto q_beta = UnivariateView(extended_edges.q_o); + auto q_beta_sqr = UnivariateView(extended_edges.q_4); + auto q_elliptic = UnivariateView(extended_edges.q_elliptic); + + auto beta_term = x_2 * x_1 * (x_3 + x_3 + x_1) * FF(-1); // -x_1 * x_2 * (2 * x_3 + x_1) + auto beta_sqr_term = x_2 * x_2; // x_2^2 + auto leftovers = beta_sqr_term; // x_2^2 + beta_sqr_term *= (x_3 - x_1); // x_2^2 * (x_3 - x_1) + auto sign_term = y_2 * y_1; // y_1 * y_2 + sign_term += sign_term; // 2 * y_1 * y_2 + beta_term *= q_beta; // -β * x_1 * x_2 * (2 * x_3 + x_1) + beta_sqr_term *= q_beta_sqr; // β^2 * x_2^2 * (x_3 - x_1) + sign_term *= q_sign; // 2 * y_1 * y_2 * sign + leftovers *= x_2; // x_2^3 + leftovers += x_1 * x_1 * (x_3 + x_1); // x_2^3 + x_1 * (x_3 + x_1) + leftovers -= (y_2 * y_2 + y_1 * y_1); // x_2^3 + x_1 * (x_3 + x_1) - y_2^2 - y_1^2 + + // Can be found in class description + auto x_identity = beta_term + beta_sqr_term + sign_term + leftovers; + x_identity *= q_elliptic; + x_identity *= scaling_factor; + std::get<0>(evals) += x_identity; + } + // Contribution (2) + { + static constexpr size_t LENGTH = CONSTRAINT_LENGTH[1]; + auto x_1 = UnivariateView(extended_edges.w_r); + auto y_1 = UnivariateView(extended_edges.w_o); + + auto x_2 = UnivariateView(extended_edges.w_l_shift); + auto y_2 = UnivariateView(extended_edges.w_4_shift); + auto x_3 = UnivariateView(extended_edges.w_r_shift); + auto y_3 = UnivariateView(extended_edges.w_o_shift); + + auto q_sign = UnivariateView(extended_edges.q_l); + auto q_beta = UnivariateView(extended_edges.q_o); + auto q_elliptic = UnivariateView(extended_edges.q_elliptic); + + auto beta_term = x_2 * (y_3 + y_1) * q_beta; // β * x_2 * (y_3 + y_1) + auto sign_term = y_2 * (x_1 - x_3) * q_sign * FF(-1); // - signt * y_2 * (x_1 - x_3) + // TODO: remove extra additions if we decide to stay with this implementation + auto leftovers = x_1 * (y_3 + y_1) * FF(-1) + y_1 * (x_1 - x_3); // -x_1 * y_3 - x_1 * y_1 + y_1 * x_1 - y_1 * x_3 + + auto y_identity = beta_term + sign_term + leftovers; + y_identity *= q_elliptic; + y_identity *= scaling_factor; + std::get<1>(evals) += y_identity; + } }; - void add_full_relation_value_contribution(FF& full_honk_relation_value, + void add_full_relation_value_contribution(RelationValues& full_honk_relation_value, const auto& purported_evaluations, const RelationParameters&) const { @@ -96,9 +114,7 @@ template class EllipticRelation { auto q_beta_sqr = purported_evaluations.q_4; auto q_elliptic = purported_evaluations.q_elliptic; - static const FF fake_alpha_1 = FF(1); - static const FF fake_alpha_2 = fake_alpha_1 * fake_alpha_1; - + // Contribution (1) auto beta_term = x_2 * x_1 * (x_3 + x_3 + x_1) * FF(-1); // -x_1 * x_2 * (2 * x_3 + x_1) auto beta_sqr_term = x_2 * x_2; // x_2^2 auto leftovers = beta_sqr_term; // x_2^2 @@ -114,20 +130,19 @@ template class EllipticRelation { // Can be found in class description auto x_identity = beta_term + beta_sqr_term + sign_term + leftovers; - x_identity *= fake_alpha_1; + x_identity *= q_elliptic; + std::get<0>(full_honk_relation_value) += x_identity; + // Contribution (2) beta_term = x_2 * (y_3 + y_1) * q_beta; // β * x_2 * (y_3 + y_1) sign_term = y_2 * (x_1 - x_3) * q_sign * FF(-1); // - signt * y_2 * (x_1 - x_3) // TODO: remove extra additions if we decide to stay with this implementation leftovers = x_1 * (y_3 + y_1) * FF(-1) + y_1 * (x_1 - x_3); // -x_1 * y_3 - x_1 * y_1 + y_1 * x_1 - y_1 * x_3 auto y_identity = beta_term + sign_term + leftovers; - y_identity *= fake_alpha_2; - - auto tmp = x_identity + y_identity; - tmp *= q_elliptic; - - full_honk_relation_value += tmp; + y_identity *= q_elliptic; + std::get<1>(full_honk_relation_value) += y_identity; }; }; +// clang-format on } // namespace proof_system::honk::sumcheck From 83b333064a7772b09b9a8e1f7cf54b9e5e904a2e Mon Sep 17 00:00:00 2001 From: ledwards2225 Date: Tue, 16 May 2023 20:33:02 +0000 Subject: [PATCH 07/18] update relation correctness for ultra --- .../sumcheck/relations/elliptic_relation.hpp | 1 + .../relations/relation_correctness.test.cpp | 523 ++++++++---------- 2 files changed, 241 insertions(+), 283 deletions(-) diff --git a/cpp/src/barretenberg/honk/sumcheck/relations/elliptic_relation.hpp b/cpp/src/barretenberg/honk/sumcheck/relations/elliptic_relation.hpp index 16b1237fd7..bea8fd40b9 100644 --- a/cpp/src/barretenberg/honk/sumcheck/relations/elliptic_relation.hpp +++ b/cpp/src/barretenberg/honk/sumcheck/relations/elliptic_relation.hpp @@ -34,6 +34,7 @@ template class EllipticRelation { const FF& scaling_factor) const { // OPTIMIZATION?: Karatsuba in general, at least for some degrees? // See https://hackmd.io/xGLuj6biSsCjzQnYN-pEiA?both + // TODO(luke): Formatter doesnt properly handle explicit scoping below so turning off. Whats up? // clang-format off // Contribution (1) { diff --git a/cpp/src/barretenberg/honk/sumcheck/relations/relation_correctness.test.cpp b/cpp/src/barretenberg/honk/sumcheck/relations/relation_correctness.test.cpp index 492b3818be..da473eafec 100644 --- a/cpp/src/barretenberg/honk/sumcheck/relations/relation_correctness.test.cpp +++ b/cpp/src/barretenberg/honk/sumcheck/relations/relation_correctness.test.cpp @@ -150,288 +150,245 @@ TEST(RelationCorrectness, StandardRelationCorrectness) check_relation<1, Flavor>(relations, circuit_size, prover_polynomials, params); } -// /** -// * @brief Test the correctness of the Ultra Honk relations -// * -// * @details Check that the constraints encoded by the relations are satisfied by the polynomials produced by the -// * Ultra Honk Composer for a real circuit. -// * -// * TODO(Kesha): We'll have to update this function once we add zk, since the relation will be incorrect for he first -// few -// * indices -// * -// */ -// // TODO(luke): possibly make circuit construction one or many functions to clarify the individual components -// // TODO(luke): Add a gate that sets q_arith = 3 to check secondary arithmetic relation -// TEST(RelationCorrectness, UltraRelationCorrectness) -// { -// using Flavor = honk::flavor::Ultra; -// using FF = typename Flavor::FF; -// using ProverPolynomials = typename Flavor::ProverPolynomials; -// using PurportedEvaluations = typename Flavor::PurportedEvaluations; - -// // Create a composer and then add an assortment of gates designed to ensure that the constraint(s) represented -// // by each relation are non-trivially exercised. -// auto composer = UltraHonkComposer(); - -// barretenberg::fr pedersen_input_value = fr::random_element(); -// fr a = fr::one(); -// // Using the public variable to check that public_input_delta is computed and added to the relation correctly -// // TODO(luke): add method "add_public_variable" to UH composer -// // uint32_t a_idx = composer.add_public_variable(a); - -// // Add some basic add gates -// uint32_t a_idx = composer.add_variable(a); -// fr b = fr::one(); -// fr c = a + b; -// fr d = a + c; -// uint32_t b_idx = composer.add_variable(b); -// uint32_t c_idx = composer.add_variable(c); -// uint32_t d_idx = composer.add_variable(d); -// for (size_t i = 0; i < 16; i++) { -// composer.create_add_gate({ a_idx, b_idx, c_idx, 1, 1, -1, 0 }); -// composer.create_add_gate({ d_idx, c_idx, a_idx, 1, -1, -1, 0 }); -// } - -// // // Add a big add gate with use of next row to test q_arith = 2 -// // fr e = a + b + c + d; -// // uint32_t e_idx = composer.add_variable(e); - -// // uint32_t zero_idx = composer.get_zero_idx(); -// // composer.create_big_add_gate({ a_idx, b_idx, c_idx, d_idx, -1, -1, -1, -1, 0 }, true); // use next row -// // composer.create_big_add_gate({ zero_idx, zero_idx, zero_idx, e_idx, 0, 0, 0, 0, 0 }, false); - -// // // Add some lookup gates (related to pedersen hashing) -// // const fr input_hi = uint256_t(pedersen_input_value).slice(126, 256); -// // const fr input_lo = uint256_t(pedersen_input_value).slice(0, 126); -// // const auto input_hi_index = composer.add_variable(input_hi); -// // const auto input_lo_index = 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); - -// // composer.create_gates_from_plookup_accumulators( -// // plookup::MultiTableId::PEDERSEN_LEFT_HI, sequence_data_hi, input_hi_index); -// // composer.create_gates_from_plookup_accumulators( -// // plookup::MultiTableId::PEDERSEN_LEFT_LO, sequence_data_lo, input_lo_index); - -// // Add a sort gate (simply checks that consecutive inputs have a difference of < 4) -// a_idx = composer.add_variable(FF(0)); -// b_idx = composer.add_variable(FF(1)); -// c_idx = composer.add_variable(FF(2)); -// d_idx = composer.add_variable(FF(3)); -// composer.create_sort_constraint({ a_idx, b_idx, c_idx, d_idx }); - -// // Add an elliptic curve addition gate -// grumpkin::g1::affine_element p1 = crypto::generators::get_generator_data({ 0, 0 }).generator; -// grumpkin::g1::affine_element p2 = crypto::generators::get_generator_data({ 0, 1 }).generator; - -// grumpkin::fq beta_scalar = grumpkin::fq::cube_root_of_unity(); -// grumpkin::g1::affine_element p2_endo = p2; -// p2_endo.x *= beta_scalar; - -// grumpkin::g1::affine_element p3(grumpkin::g1::element(p1) - grumpkin::g1::element(p2_endo)); - -// uint32_t x1 = composer.add_variable(p1.x); -// uint32_t y1 = composer.add_variable(p1.y); -// uint32_t x2 = composer.add_variable(p2.x); -// uint32_t y2 = composer.add_variable(p2.y); -// uint32_t x3 = composer.add_variable(p3.x); -// uint32_t y3 = composer.add_variable(p3.y); - -// ecc_add_gate gate{ x1, y1, x2, y2, x3, y3, beta_scalar, -1 }; -// composer.create_ecc_add_gate(gate); - -// // Add some RAM gates -// uint32_t ram_values[8]{ -// composer.add_variable(fr::random_element()), composer.add_variable(fr::random_element()), -// composer.add_variable(fr::random_element()), composer.add_variable(fr::random_element()), -// composer.add_variable(fr::random_element()), composer.add_variable(fr::random_element()), -// composer.add_variable(fr::random_element()), composer.add_variable(fr::random_element()), -// }; - -// size_t ram_id = composer.create_RAM_array(8); - -// for (size_t i = 0; i < 8; ++i) { -// composer.init_RAM_element(ram_id, i, ram_values[i]); -// } - -// a_idx = composer.read_RAM_array(ram_id, composer.add_variable(5)); -// EXPECT_EQ(a_idx != ram_values[5], true); - -// b_idx = composer.read_RAM_array(ram_id, composer.add_variable(4)); -// c_idx = composer.read_RAM_array(ram_id, composer.add_variable(1)); - -// composer.write_RAM_array(ram_id, composer.add_variable(4), composer.add_variable(500)); -// d_idx = composer.read_RAM_array(ram_id, composer.add_variable(4)); - -// EXPECT_EQ(composer.get_variable(d_idx), 500); - -// // ensure these vars get used in another arithmetic gate -// const auto e_value = composer.get_variable(a_idx) + composer.get_variable(b_idx) + composer.get_variable(c_idx) + -// composer.get_variable(d_idx); -// e_idx = composer.add_variable(e_value); - -// composer.create_big_add_gate({ a_idx, b_idx, c_idx, d_idx, -1, -1, -1, -1, 0 }, true); -// composer.create_big_add_gate( -// { -// composer.get_zero_idx(), -// composer.get_zero_idx(), -// composer.get_zero_idx(), -// e_idx, -// 0, -// 0, -// 0, -// 0, -// 0, -// }, -// false); - -// // Create a prover (it will compute proving key and witness) -// auto prover = composer.create_prover(); - -// // // Generate eta, beta and gamma -// // fr eta = fr::random_element(); -// // fr beta = fr::random_element(); -// // fr gamma = fr::random_element(); - -// // // Compute public input delta -// // const auto public_inputs = composer.circuit_constructor.get_public_inputs(); -// // auto public_input_delta = -// // honk::compute_public_input_delta(public_inputs, beta, gamma, prover.key->circuit_size); -// // auto lookup_grand_product_delta = -// // honk::compute_lookup_grand_product_delta(beta, gamma, prover.key->circuit_size); - -// sumcheck::RelationParameters params{ -// .eta = eta, -// .beta = beta, -// .gamma = gamma, -// .public_input_delta = public_input_delta, -// .lookup_grand_product_delta = lookup_grand_product_delta, -// }; - -// // Compute sorted witness-table accumulator -// prover.key->sorted_accum = prover_library::compute_sorted_list_accumulator(prover.key, eta); - -// // Add RAM/ROM memory records to wire four -// prover_library::add_plookup_memory_records_to_wire_4(prover.key, eta); - -// // Compute grand product polynomial -// prover.key->z_perm = prover_library::compute_permutation_grand_product(prover.key, beta, gamma); - -// // Compute lookup grand product polynomial -// prover.key->z_lookup = prover_library::compute_lookup_grand_product(prover.key, eta, beta, gamma); - -// // // Create an array of spans to the underlying polynomials to more easily -// // // get the transposition. -// // // Ex: polynomial_spans[3][i] returns the i-th coefficient of the third polynomial -// // // in the list below -// // ProverPolynomials prover_polynomials; - -// prover_polynomials.w_l = prover.key->w_l; -// prover_polynomials.w_r = prover.key->w_r; -// prover_polynomials.w_o = prover.key->w_o; -// prover_polynomials.w_4 = prover.key->w_4; -// prover_polynomials.w_l_shift = prover.key->w_l.shifted(); -// prover_polynomials.w_r_shift = prover.key->w_r.shifted(); -// prover_polynomials.w_o_shift = prover.key->w_o.shifted(); -// prover_polynomials.w_4_shift = prover.key->w_4.shifted(); -// prover_polynomials.sorted_accum = prover.key->sorted_accum; -// prover_polynomials.sorted_accum_shift = prover.key->sorted_accum.shifted(); -// prover_polynomials.table_1 = prover.key->table_1; -// prover_polynomials.table_2 = prover.key->table_2; -// prover_polynomials.table_3 = prover.key->table_3; -// prover_polynomials.table_4 = prover.key->table_4; -// prover_polynomials.table_1_shift = prover.key->table_1.shifted(); -// prover_polynomials.table_2_shift = prover.key->table_2.shifted(); -// prover_polynomials.table_3_shift = prover.key->table_3.shifted(); -// prover_polynomials.table_4_shift = prover.key->table_4.shifted(); -// prover_polynomials.z_perm = prover.key->z_perm; -// prover_polynomials.z_perm_shift = prover.key->z_perm.shifted(); -// prover_polynomials.z_lookup = prover.key->z_lookup; -// prover_polynomials.z_lookup_shift = prover.key->z_lookup.shifted(); -// prover_polynomials.q_m = prover.key->q_m; -// prover_polynomials.q_l = prover.key->q_l; -// prover_polynomials.q_r = prover.key->q_r; -// prover_polynomials.q_o = prover.key->q_o; -// prover_polynomials.q_c = prover.key->q_c; -// prover_polynomials.q_4 = prover.key->q_4; -// prover_polynomials.q_arith = prover.key->q_arith; -// prover_polynomials.q_sort = prover.key->q_sort; -// prover_polynomials.q_elliptic = prover.key->q_elliptic; -// prover_polynomials.q_aux = prover.key->q_aux; -// prover_polynomials.q_lookup = prover.key->q_lookup; -// prover_polynomials.sigma_1 = prover.key->sigma_1; -// prover_polynomials.sigma_2 = prover.key->sigma_2; -// prover_polynomials.sigma_3 = prover.key->sigma_3; -// prover_polynomials.sigma_4 = prover.key->sigma_4; -// prover_polynomials.id_1 = prover.key->id_1; -// prover_polynomials.id_2 = prover.key->id_2; -// prover_polynomials.id_3 = prover.key->id_3; -// prover_polynomials.id_4 = prover.key->id_4; -// prover_polynomials.lagrange_first = prover.key->lagrange_first; -// prover_polynomials.lagrange_last = prover.key->lagrange_last; - -// // Check that selectors are nonzero to ensure corresponding relation has nontrivial contribution -// ensure_non_zero(prover.key->q_arith); -// ensure_non_zero(prover.key->q_sort); -// ensure_non_zero(prover.key->q_lookup); -// ensure_non_zero(prover.key->q_elliptic); -// ensure_non_zero(prover.key->q_aux); - -// // Construct the round for applying sumcheck relations and results for storing computed results -// auto relations = std::tuple(honk::sumcheck::UltraArithmeticRelation(), -// honk::sumcheck::UltraArithmeticRelationSecondary(), -// honk::sumcheck::UltraGrandProductInitializationRelation(), -// honk::sumcheck::UltraPermutationRelation(), -// honk::sumcheck::LookupRelation(), -// honk::sumcheck::LookupGrandProductInitializationRelation(), -// honk::sumcheck::GenPermSortRelation(), -// honk::sumcheck::EllipticRelation(), -// honk::sumcheck::AuxiliaryRelation()); - -// // fr result = 0; -// // for (size_t i = 0; i < prover.key->circuit_size; i++) { -// // // Compute an array containing all the evaluations at a given row i -// // PurportedEvaluations evaluations_at_index_i; -// // size_t poly_idx = 0; -// // for (auto& polynomial : prover_polynomials) { -// // evaluations_at_index_i[poly_idx] = polynomial[i]; -// // ++poly_idx; -// // } - -// // // For each relation, call the `accumulate_relation_evaluation` over all witness/selector values at the -// // // i-th row/vertex of the hypercube. We use ASSERT_EQ instead of EXPECT_EQ so that the tests stops at -// // // the first index at which the result is not 0, since result = 0 + C(transposed), which we expect will -// // // equal 0. -// // std::get<0>(relations).add_full_relation_value_contribution(result, evaluations_at_index_i, params); -// // ASSERT_EQ(result, 0); - -// // std::get<1>(relations).add_full_relation_value_contribution(result, evaluations_at_index_i, params); -// // ASSERT_EQ(result, 0); - -// // std::get<2>(relations).add_full_relation_value_contribution(result, evaluations_at_index_i, params); -// // ASSERT_EQ(result, 0); - -// // std::get<3>(relations).add_full_relation_value_contribution(result, evaluations_at_index_i, params); -// // ASSERT_EQ(result, 0); - -// // std::get<4>(relations).add_full_relation_value_contribution(result, evaluations_at_index_i, params); -// // ASSERT_EQ(result, 0); - -// std::get<5>(relations).add_full_relation_value_contribution(result, evaluations_at_index_i, params); -// ASSERT_EQ(result, 0); - -// std::get<6>(relations).add_full_relation_value_contribution(result, evaluations_at_index_i, params); -// ASSERT_EQ(result, 0); - -// std::get<7>(relations).add_full_relation_value_contribution(result, evaluations_at_index_i, params); -// ASSERT_EQ(result, 0); - -// std::get<8>(relations).add_full_relation_value_contribution(result, evaluations_at_index_i, params); -// ASSERT_EQ(result, 0); -// } -// } +/** + * @brief Test the correctness of the Ultra Honk relations + * + * @details Check that the constraints encoded by the relations are satisfied by the polynomials produced by the + * Ultra Honk Composer for a real circuit. + * + * TODO(Kesha): We'll have to update this function once we add zk, since the relation will be incorrect for he first + few + * indices + * + */ +// TODO(luke): possibly make circuit construction one or many functions to clarify the individual components +// TODO(luke): Add a gate that sets q_arith = 3 to check secondary arithmetic relation +TEST(RelationCorrectness, UltraRelationCorrectness) +{ + using Flavor = honk::flavor::Ultra; + using FF = typename Flavor::FF; + using ProverPolynomials = typename Flavor::ProverPolynomials; + + // Create a composer and then add an assortment of gates designed to ensure that the constraint(s) represented + // by each relation are non-trivially exercised. + auto composer = UltraHonkComposer(); + + barretenberg::fr pedersen_input_value = fr::random_element(); + fr a = fr::one(); + // Using the public variable to check that public_input_delta is computed and added to the relation correctly + // TODO(luke): add method "add_public_variable" to UH composer + // uint32_t a_idx = composer.add_public_variable(a); + + // Add some basic add gates + uint32_t a_idx = composer.add_variable(a); + fr b = fr::one(); + fr c = a + b; + fr d = a + c; + uint32_t b_idx = composer.add_variable(b); + uint32_t c_idx = composer.add_variable(c); + uint32_t d_idx = composer.add_variable(d); + for (size_t i = 0; i < 16; i++) { + composer.create_add_gate({ a_idx, b_idx, c_idx, 1, 1, -1, 0 }); + composer.create_add_gate({ d_idx, c_idx, a_idx, 1, -1, -1, 0 }); + } + + // Add a big add gate with use of next row to test q_arith = 2 + fr e = a + b + c + d; + uint32_t e_idx = composer.add_variable(e); + + uint32_t zero_idx = composer.get_zero_idx(); + composer.create_big_add_gate({ a_idx, b_idx, c_idx, d_idx, -1, -1, -1, -1, 0 }, true); // use next row + composer.create_big_add_gate({ zero_idx, zero_idx, zero_idx, e_idx, 0, 0, 0, 0, 0 }, false); + + // Add some lookup gates (related to pedersen hashing) + const fr input_hi = uint256_t(pedersen_input_value).slice(126, 256); + const fr input_lo = uint256_t(pedersen_input_value).slice(0, 126); + const auto input_hi_index = composer.add_variable(input_hi); + const auto input_lo_index = 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); + + composer.create_gates_from_plookup_accumulators( + plookup::MultiTableId::PEDERSEN_LEFT_HI, sequence_data_hi, input_hi_index); + composer.create_gates_from_plookup_accumulators( + plookup::MultiTableId::PEDERSEN_LEFT_LO, sequence_data_lo, input_lo_index); + + // Add a sort gate (simply checks that consecutive inputs have a difference of < 4) + a_idx = composer.add_variable(FF(0)); + b_idx = composer.add_variable(FF(1)); + c_idx = composer.add_variable(FF(2)); + d_idx = composer.add_variable(FF(3)); + composer.create_sort_constraint({ a_idx, b_idx, c_idx, d_idx }); + + // Add an elliptic curve addition gate + grumpkin::g1::affine_element p1 = crypto::generators::get_generator_data({ 0, 0 }).generator; + grumpkin::g1::affine_element p2 = crypto::generators::get_generator_data({ 0, 1 }).generator; + + grumpkin::fq beta_scalar = grumpkin::fq::cube_root_of_unity(); + grumpkin::g1::affine_element p2_endo = p2; + p2_endo.x *= beta_scalar; + + grumpkin::g1::affine_element p3(grumpkin::g1::element(p1) - grumpkin::g1::element(p2_endo)); + + uint32_t x1 = composer.add_variable(p1.x); + uint32_t y1 = composer.add_variable(p1.y); + uint32_t x2 = composer.add_variable(p2.x); + uint32_t y2 = composer.add_variable(p2.y); + uint32_t x3 = composer.add_variable(p3.x); + uint32_t y3 = composer.add_variable(p3.y); + + ecc_add_gate gate{ x1, y1, x2, y2, x3, y3, beta_scalar, -1 }; + composer.create_ecc_add_gate(gate); + + // Add some RAM gates + uint32_t ram_values[8]{ + composer.add_variable(fr::random_element()), composer.add_variable(fr::random_element()), + composer.add_variable(fr::random_element()), composer.add_variable(fr::random_element()), + composer.add_variable(fr::random_element()), composer.add_variable(fr::random_element()), + composer.add_variable(fr::random_element()), composer.add_variable(fr::random_element()), + }; + + size_t ram_id = composer.create_RAM_array(8); + + for (size_t i = 0; i < 8; ++i) { + composer.init_RAM_element(ram_id, i, ram_values[i]); + } + + a_idx = composer.read_RAM_array(ram_id, composer.add_variable(5)); + EXPECT_EQ(a_idx != ram_values[5], true); + + b_idx = composer.read_RAM_array(ram_id, composer.add_variable(4)); + c_idx = composer.read_RAM_array(ram_id, composer.add_variable(1)); + + composer.write_RAM_array(ram_id, composer.add_variable(4), composer.add_variable(500)); + d_idx = composer.read_RAM_array(ram_id, composer.add_variable(4)); + + EXPECT_EQ(composer.get_variable(d_idx), 500); + + // ensure these vars get used in another arithmetic gate + const auto e_value = composer.get_variable(a_idx) + composer.get_variable(b_idx) + composer.get_variable(c_idx) + + composer.get_variable(d_idx); + e_idx = composer.add_variable(e_value); + + composer.create_big_add_gate({ a_idx, b_idx, c_idx, d_idx, -1, -1, -1, -1, 0 }, true); + composer.create_big_add_gate( + { + composer.get_zero_idx(), + composer.get_zero_idx(), + composer.get_zero_idx(), + e_idx, + 0, + 0, + 0, + 0, + 0, + }, + false); + + // Create a prover (it will compute proving key and witness) + auto prover = composer.create_prover(); + auto circuit_size = prover.key->circuit_size; + + // Generate eta, beta and gamma + fr eta = fr::random_element(); + fr beta = fr::random_element(); + fr gamma = fr::random_element(); + + // Compute public input delta + const auto public_inputs = composer.circuit_constructor.get_public_inputs(); + auto public_input_delta = + honk::compute_public_input_delta(public_inputs, beta, gamma, prover.key->circuit_size); + auto lookup_grand_product_delta = + honk::compute_lookup_grand_product_delta(beta, gamma, prover.key->circuit_size); + + sumcheck::RelationParameters params{ + .eta = eta, + .beta = beta, + .gamma = gamma, + .public_input_delta = public_input_delta, + .lookup_grand_product_delta = lookup_grand_product_delta, + }; + + // Compute sorted witness-table accumulator + prover.key->sorted_accum = prover_library::compute_sorted_list_accumulator(prover.key, eta); + + // Add RAM/ROM memory records to wire four + prover_library::add_plookup_memory_records_to_wire_4(prover.key, eta); + + // Compute grand product polynomial + prover.key->z_perm = prover_library::compute_permutation_grand_product(prover.key, beta, gamma); + + // Compute lookup grand product polynomial + prover.key->z_lookup = prover_library::compute_lookup_grand_product(prover.key, eta, beta, gamma); + + ProverPolynomials prover_polynomials; + + prover_polynomials.w_l = prover.key->w_l; + prover_polynomials.w_r = prover.key->w_r; + prover_polynomials.w_o = prover.key->w_o; + prover_polynomials.w_4 = prover.key->w_4; + prover_polynomials.w_l_shift = prover.key->w_l.shifted(); + prover_polynomials.w_r_shift = prover.key->w_r.shifted(); + prover_polynomials.w_o_shift = prover.key->w_o.shifted(); + prover_polynomials.w_4_shift = prover.key->w_4.shifted(); + prover_polynomials.sorted_accum = prover.key->sorted_accum; + prover_polynomials.sorted_accum_shift = prover.key->sorted_accum.shifted(); + prover_polynomials.table_1 = prover.key->table_1; + prover_polynomials.table_2 = prover.key->table_2; + prover_polynomials.table_3 = prover.key->table_3; + prover_polynomials.table_4 = prover.key->table_4; + prover_polynomials.table_1_shift = prover.key->table_1.shifted(); + prover_polynomials.table_2_shift = prover.key->table_2.shifted(); + prover_polynomials.table_3_shift = prover.key->table_3.shifted(); + prover_polynomials.table_4_shift = prover.key->table_4.shifted(); + prover_polynomials.z_perm = prover.key->z_perm; + prover_polynomials.z_perm_shift = prover.key->z_perm.shifted(); + prover_polynomials.z_lookup = prover.key->z_lookup; + prover_polynomials.z_lookup_shift = prover.key->z_lookup.shifted(); + prover_polynomials.q_m = prover.key->q_m; + prover_polynomials.q_l = prover.key->q_l; + prover_polynomials.q_r = prover.key->q_r; + prover_polynomials.q_o = prover.key->q_o; + prover_polynomials.q_c = prover.key->q_c; + prover_polynomials.q_4 = prover.key->q_4; + prover_polynomials.q_arith = prover.key->q_arith; + prover_polynomials.q_sort = prover.key->q_sort; + prover_polynomials.q_elliptic = prover.key->q_elliptic; + prover_polynomials.q_aux = prover.key->q_aux; + prover_polynomials.q_lookup = prover.key->q_lookup; + prover_polynomials.sigma_1 = prover.key->sigma_1; + prover_polynomials.sigma_2 = prover.key->sigma_2; + prover_polynomials.sigma_3 = prover.key->sigma_3; + prover_polynomials.sigma_4 = prover.key->sigma_4; + prover_polynomials.id_1 = prover.key->id_1; + prover_polynomials.id_2 = prover.key->id_2; + prover_polynomials.id_3 = prover.key->id_3; + prover_polynomials.id_4 = prover.key->id_4; + prover_polynomials.lagrange_first = prover.key->lagrange_first; + prover_polynomials.lagrange_last = prover.key->lagrange_last; + + // Check that selectors are nonzero to ensure corresponding relation has nontrivial contribution + ensure_non_zero(prover.key->q_arith); + ensure_non_zero(prover.key->q_sort); + ensure_non_zero(prover.key->q_lookup); + ensure_non_zero(prover.key->q_elliptic); + ensure_non_zero(prover.key->q_aux); + + // Construct the round for applying sumcheck relations and results for storing computed results + auto relations = std::tuple(honk::sumcheck::UltraArithmeticRelation(), + honk::sumcheck::UltraPermutationRelation(), + honk::sumcheck::LookupRelation(), + honk::sumcheck::GenPermSortRelation(), + honk::sumcheck::EllipticRelation()); + // honk::sumcheck::AuxiliaryRelation()); + + // Check that each relation is satisfied across each row of the prover polynomials + check_relation<0, Flavor>(relations, circuit_size, prover_polynomials, params); + check_relation<1, Flavor>(relations, circuit_size, prover_polynomials, params); + check_relation<2, Flavor>(relations, circuit_size, prover_polynomials, params); + check_relation<3, Flavor>(relations, circuit_size, prover_polynomials, params); + check_relation<4, Flavor>(relations, circuit_size, prover_polynomials, params); +} } // namespace test_honk_relations From 1f82ef1d140a241ee29993ed23acf349d66cdcd4 Mon Sep 17 00:00:00 2001 From: ledwards2225 Date: Tue, 16 May 2023 21:10:23 +0000 Subject: [PATCH 08/18] update consistency tests for ultra --- .../relations/relation_consistency.test.cpp | 1 + .../ultra_relation_consistency.test.cpp | 1063 +++++++++-------- 2 files changed, 541 insertions(+), 523 deletions(-) diff --git a/cpp/src/barretenberg/honk/sumcheck/relations/relation_consistency.test.cpp b/cpp/src/barretenberg/honk/sumcheck/relations/relation_consistency.test.cpp index 51425e5c03..4add53f864 100644 --- a/cpp/src/barretenberg/honk/sumcheck/relations/relation_consistency.test.cpp +++ b/cpp/src/barretenberg/honk/sumcheck/relations/relation_consistency.test.cpp @@ -218,6 +218,7 @@ TEST_F(StandardRelationConsistency, ArithmeticRelation) // Note: expect { { 5, 22, 57, 116, 205} } for input polynomial {1, 2} constexpr std::size_t NUM_CONSTRAINTS = decltype(relation)::NUM_CONSTRAINTS; auto expected_full_length_univariates = std::array, NUM_CONSTRAINTS>(); + expected_full_length_univariates[0] = (q_m * w_r * w_l) + (q_r * w_r) + (q_l * w_l) + (q_o * w_o) + (q_c); validate_evaluations(expected_full_length_univariates, relation, extended_edges, relation_parameters); }; diff --git a/cpp/src/barretenberg/honk/sumcheck/relations/ultra_relation_consistency.test.cpp b/cpp/src/barretenberg/honk/sumcheck/relations/ultra_relation_consistency.test.cpp index 331950ea89..1bdac16ad1 100644 --- a/cpp/src/barretenberg/honk/sumcheck/relations/ultra_relation_consistency.test.cpp +++ b/cpp/src/barretenberg/honk/sumcheck/relations/ultra_relation_consistency.test.cpp @@ -1,525 +1,542 @@ -// #include "barretenberg/honk/sumcheck/relations/ultra_arithmetic_relation.hpp" -// #include "barretenberg/honk/sumcheck/relations/ultra_arithmetic_relation_secondary.hpp" -// #include "barretenberg/honk/sumcheck/relations/lookup_relation.hpp" -// #include "barretenberg/honk/sumcheck/relations/gen_perm_sort_relation.hpp" -// #include "barretenberg/honk/sumcheck/relations/elliptic_relation.hpp" -// #include "barretenberg/honk/sumcheck/relations/auxiliary_relation.hpp" -// #include "barretenberg/honk/flavor/ultra.hpp" -// #include "relation.hpp" -// #include "arithmetic_relation.hpp" -// #include "permutation_relation.hpp" -// #include "../polynomials/univariate.hpp" -// #include "../polynomials/barycentric_data.hpp" - -// #include "barretenberg/ecc/curves/bn254/fr.hpp" -// #include "barretenberg/numeric/random/engine.hpp" - -// #include -// #include -// using namespace proof_system::honk::sumcheck; -// /** -// * We want to test if all three relations (namely, ArithmeticRelation, GrandProductComputationRelation, -// * GrandProductInitializationRelation) provide correct contributions by manually computing their -// * contributions with deterministic and random inputs. The relations are supposed to work with -// * univariates (edges) of degree one (length 2) and spit out polynomials of corresponding degrees. We have -// * MAX_RELATION_LENGTH = 5, meaning the output of a relation can atmost be a degree 5 polynomial. Hence, -// * we use a method compute_mock_extended_edges() which starts with degree one input polynomial (two evaluation -// points), -// * extends them (using barycentric formula) to six evaluation points, and stores them to an array of polynomials. -// */ -// static const size_t INPUT_UNIVARIATE_LENGTH = 2; - -// namespace proof_system::honk_relation_tests { - -// class UltraRelationConsistency : public testing::Test { -// public: -// using Flavor = honk::flavor::Ultra; -// using FF = typename Flavor::FF; -// using PurportedEvaluations = typename Flavor::PurportedEvaluations; - -// // TODO(#390): Move MAX_RELATION_LENGTH into Flavor and simplify this. -// template using ExtendedEdges = typename Flavor::template ExtendedEdges; - -// // TODO(#225)(Adrian): Accept FULL_RELATION_LENGTH as a template parameter for this function only, so that the -// test -// // can decide to which degree the polynomials must be extended. Possible accept an existing list of "edges" and -// // extend them to the degree. -// template -// static void compute_mock_extended_edges( -// ExtendedEdges& extended_edges, -// std::array, NUM_POLYNOMIALS>& input_edges) -// { -// BarycentricData barycentric_2_to_max = -// BarycentricData(); -// for (size_t i = 0; i < NUM_POLYNOMIALS; ++i) { -// extended_edges[i] = barycentric_2_to_max.extend(input_edges[i]); -// } -// } - -// /** -// * @brief Returns randomly sampled parameters to feed to the relations. -// * -// * @return RelationParameters -// */ -// RelationParameters compute_mock_relation_parameters() -// { -// return { .beta = FF::random_element(), -// .gamma = FF::random_element(), -// .public_input_delta = FF::random_element() }; -// } - -// /** -// * @brief Given an array of Univariates, create a new array containing only the i-th evaluations -// * of all the univariates. -// * -// * @note Not really optimized, mainly used for testing that the relations evaluate to the same value when -// * evaluated as Univariates, Expressions, or index-by-index -// * @todo(Adrian) Maybe this is more helpful as part of a `check_logic` function. -// * -// * @tparam NUM_UNIVARIATES number of univariates in the input array (deduced from `univariates`) -// * @tparam univariate_length number of evaluations (deduced from `univariates`) -// * @param univariates array of Univariates -// * @param i index of the evaluations we want to take from each univariate -// * @return std::array such that result[j] = univariates[j].value_at(i) -// */ -// template -// static PurportedEvaluations transposed_univariate_array_at(ExtendedEdges univariates, size_t -// i) -// { -// ASSERT(i < univariate_length); -// std::array result; -// size_t result_idx = 0; // TODO(#391) zip -// for (auto& univariate : univariates) { -// result[result_idx] = univariate.value_at(i); -// ++result_idx; -// } -// return result; -// }; - -// /** -// * @brief Compute the evaluation of a `relation` in different ways, comparing it to the provided `expected_evals` -// * -// * @details Check both `add_full_relation_value_contribution` and `add_edge_contribution` by comparing the result -// to -// * the `expected_evals` computed by the caller. -// * Ensures that the relations compute the same result as the expression given in the tests. -// * -// * @param expected_evals Relation evaluation computed by the caller. -// * @param relation being tested -// * @param extended_edges -// * @param relation_parameters -// */ -// template -// static void validate_evaluations(const Univariate& expected_evals, -// const auto relation, -// const ExtendedEdges& extended_edges, -// const RelationParameters& relation_parameters) -// { - -// // Compute the expression index-by-index -// Univariate expected_evals_index{ 0 }; -// for (size_t i = 0; i < FULL_RELATION_LENGTH; ++i) { -// // Get an array of the same size as `extended_edges` with only the i-th element of each extended edge. -// PurportedEvaluations evals_i = transposed_univariate_array_at(extended_edges, i); -// // Evaluate the relation -// relation.add_full_relation_value_contribution( -// expected_evals_index.value_at(i), evals_i, relation_parameters); -// } -// EXPECT_EQ(expected_evals, expected_evals_index); - -// // Compute the expression using the class, that converts the extended edges to UnivariateView -// auto expected_evals_view = Univariate(0); -// // The scaling factor is essentially 1 since we are working with degree 1 univariates -// relation.add_edge_contribution(expected_evals_view, extended_edges, relation_parameters, 1); - -// // Tiny hack to reduce `expected_evals` to be of size `relation.RELATION_LENGTH` -// Univariate expected_evals_restricted{ -// UnivariateView(expected_evals) -// }; -// EXPECT_EQ(expected_evals_restricted, expected_evals_view); -// }; -// }; - -// TEST_F(UltraRelationConsistency, UltraArithmeticRelation) -// { -// using Flavor = honk::flavor::Ultra; -// using FF = typename Flavor::FF; -// static constexpr size_t FULL_RELATION_LENGTH = 6; -// using ExtendedEdges = typename Flavor::template ExtendedEdges; -// static const size_t NUM_POLYNOMIALS = Flavor::NUM_ALL_ENTITIES; - -// const auto relation_parameters = compute_mock_relation_parameters(); -// ExtendedEdges extended_edges; -// std::array, NUM_POLYNOMIALS> input_polynomials; - -// // input_univariates are random polynomials of degree one -// for (size_t i = 0; i < NUM_POLYNOMIALS; ++i) { -// input_polynomials[i] = Univariate({ FF::random_element(), FF::random_element() -// }); -// } -// compute_mock_extended_edges(extended_edges, input_polynomials); - -// auto relation = UltraArithmeticRelation(); - -// // Extract the extended edges for manual computation of relation contribution -// const auto& w_1 = extended_edges.w_l; -// const auto& w_2 = extended_edges.w_r; -// const auto& w_3 = extended_edges.w_o; -// const auto& w_4 = extended_edges.w_4; -// const auto& w_4_shift = extended_edges.w_4_shift; -// const auto& q_m = extended_edges.q_m; -// const auto& q_l = extended_edges.q_l; -// const auto& q_r = extended_edges.q_r; -// const auto& q_o = extended_edges.q_o; -// const auto& q_4 = extended_edges.q_4; -// const auto& q_c = extended_edges.q_c; -// const auto& q_arith = extended_edges.q_arith; - -// static const FF neg_half = FF(-2).invert(); - -// auto expected_evals = (q_arith - 3) * (q_m * w_2 * w_1) * neg_half; -// expected_evals += (q_l * w_1) + (q_r * w_2) + (q_o * w_3) + (q_4 * w_4) + q_c; -// expected_evals += (q_arith - 1) * w_4_shift; -// expected_evals *= q_arith; - -// validate_evaluations(expected_evals, relation, extended_edges, relation_parameters); -// }; - -// TEST_F(UltraRelationConsistency, UltraArithmeticRelationSecondary) -// { -// using Flavor = honk::flavor::Ultra; -// using FF = typename Flavor::FF; -// static constexpr size_t FULL_RELATION_LENGTH = 6; -// using ExtendedEdges = typename Flavor::template ExtendedEdges; -// static const size_t NUM_POLYNOMIALS = Flavor::NUM_ALL_ENTITIES; - -// const auto relation_parameters = compute_mock_relation_parameters(); -// ExtendedEdges extended_edges; -// std::array, NUM_POLYNOMIALS> input_polynomials; - -// // input_univariates are random polynomials of degree one -// for (size_t i = 0; i < NUM_POLYNOMIALS; ++i) { -// input_polynomials[i] = Univariate({ FF::random_element(), FF::random_element() -// }); -// } -// compute_mock_extended_edges(extended_edges, input_polynomials); - -// auto relation = UltraArithmeticRelationSecondary(); - -// // Extract the extended edges for manual computation of relation contribution -// const auto& w_1 = extended_edges.w_l; -// const auto& w_4 = extended_edges.w_4; -// const auto& w_l_shift = extended_edges.w_l_shift; -// const auto& q_m = extended_edges.q_m; -// const auto& q_arith = extended_edges.q_arith; - -// auto expected_evals = (w_1 + w_4 - w_l_shift + q_m); -// expected_evals *= (q_arith - 2) * (q_arith - 1) * q_arith; - -// validate_evaluations(expected_evals, relation, extended_edges, relation_parameters); -// }; - -// TEST_F(UltraRelationConsistency, UltraGrandProductInitializationRelation) -// { -// using Flavor = honk::flavor::Ultra; -// using FF = typename Flavor::FF; -// using Flavor = honk::flavor::Ultra; -// static constexpr size_t FULL_RELATION_LENGTH = 6; -// using ExtendedEdges = typename Flavor::ExtendedEdges; -// static const size_t NUM_POLYNOMIALS = Flavor::NUM_ALL_ENTITIES; -// auto relation_parameters = compute_mock_relation_parameters(); -// ExtendedEdges extended_edges; -// std::array, NUM_POLYNOMIALS> input_polynomials; - -// // input_univariates are random polynomials of degree one -// for (size_t i = 0; i < NUM_POLYNOMIALS; ++i) { -// input_polynomials[i] = Univariate({ FF::random_element(), FF::random_element() -// }); -// } -// compute_mock_extended_edges(extended_edges, input_polynomials); - -// auto relation = UltraGrandProductInitializationRelation(); - -// // Extract the extended edges for manual computation of relation contribution -// const auto& z_perm_shift = extended_edges.z_perm_shift; -// const auto& lagrange_last = extended_edges.lagrange_last; - -// // Compute the expected result using a simple to read version of the relation expression -// auto expected_evals = z_perm_shift * lagrange_last; - -// validate_evaluations(expected_evals, relation, extended_edges, relation_parameters); -// }; - -// TEST_F(UltraRelationConsistency, UltraPermutationRelation) -// { -// using Flavor = honk::flavor::Ultra; -// using FF = typename Flavor::FF; -// using Flavor = honk::flavor::Ultra; -// static constexpr size_t FULL_RELATION_LENGTH = 6; -// using ExtendedEdges = typename Flavor::template ExtendedEdges; -// static const size_t NUM_POLYNOMIALS = Flavor::NUM_ALL_ENTITIES; -// auto relation_parameters = compute_mock_relation_parameters(); -// ExtendedEdges extended_edges; -// std::array, NUM_POLYNOMIALS> input_polynomials; - -// // input_univariates are random polynomials of degree one -// for (size_t i = 0; i < NUM_POLYNOMIALS; ++i) { -// input_polynomials[i] = Univariate({ FF::random_element(), FF::random_element() -// }); -// } -// compute_mock_extended_edges(extended_edges, input_polynomials); - -// auto relation = UltraPermutationRelation(); - -// const auto& beta = relation_parameters.beta; -// const auto& gamma = relation_parameters.gamma; -// const auto& public_input_delta = relation_parameters.public_input_delta; - -// // Extract the extended edges for manual computation of relation contribution -// const auto& w_1 = extended_edges.w_l; -// const auto& w_2 = extended_edges.w_r; -// const auto& w_3 = extended_edges.w_o; -// const auto& w_4 = extended_edges.w_4; -// const auto& sigma_1 = extended_edges.sigma_1; -// const auto& sigma_2 = extended_edges.sigma_2; -// const auto& sigma_3 = extended_edges.sigma_3; -// const auto& sigma_4 = extended_edges.sigma_4; -// const auto& id_1 = extended_edges.id_1; -// const auto& id_2 = extended_edges.id_2; -// const auto& id_3 = extended_edges.id_3; -// const auto& id_4 = extended_edges.id_4; -// const auto& z_perm = extended_edges.z_perm; -// const auto& z_perm_shift = extended_edges.z_perm_shift; -// const auto& lagrange_first = extended_edges.lagrange_first; -// const auto& lagrange_last = extended_edges.lagrange_last; - -// // Compute the expected result using a simple to read version of the relation expression -// auto expected_evals = (z_perm + lagrange_first) * (w_1 + id_1 * beta + gamma) * (w_2 + id_2 * beta + gamma) * -// (w_3 + id_3 * beta + gamma) * (w_4 + id_4 * beta + gamma) - -// (z_perm_shift + lagrange_last * public_input_delta) * (w_1 + sigma_1 * beta + gamma) * -// (w_2 + sigma_2 * beta + gamma) * (w_3 + sigma_3 * beta + gamma) * -// (w_4 + sigma_4 * beta + gamma); - -// validate_evaluations(expected_evals, relation, extended_edges, relation_parameters); -// }; - -// TEST_F(UltraRelationConsistency, LookupRelation) -// { -// using Flavor = honk::flavor::Ultra; -// using FF = typename Flavor::FF; -// using Flavor = honk::flavor::Ultra; -// static constexpr size_t FULL_RELATION_LENGTH = 6; -// using ExtendedEdges = typename Flavor::ExtendedEdges; -// static const size_t NUM_POLYNOMIALS = Flavor::NUM_ALL_ENTITIES; -// auto relation_parameters = compute_mock_relation_parameters(); -// ExtendedEdges extended_edges; -// std::array, NUM_POLYNOMIALS> input_polynomials; - -// // input_univariates are random polynomials of degree one -// for (size_t i = 0; i < NUM_POLYNOMIALS; ++i) { -// input_polynomials[i] = Univariate({ FF::random_element(), FF::random_element() -// }); -// } -// compute_mock_extended_edges(extended_edges, input_polynomials); - -// auto relation = LookupRelation(); - -// const auto eta = relation_parameters.eta; -// const auto beta = relation_parameters.beta; -// const auto gamma = relation_parameters.gamma; -// auto grand_product_delta = relation_parameters.lookup_grand_product_delta; - -// // Extract the extended edges for manual computation of relation contribution -// auto one_plus_beta = FF::one() + beta; -// auto gamma_by_one_plus_beta = gamma * one_plus_beta; -// auto eta_sqr = eta * eta; -// auto eta_cube = eta_sqr * eta; - -// const auto& w_1 = extended_edges.w_l; -// const auto& w_2 = extended_edges.w_r; -// const auto& w_3 = extended_edges.w_o; - -// const auto& w_1_shift = extended_edges.w_l_shift; -// const auto& w_2_shift = extended_edges.w_r_shift; -// const auto& w_3_shift = extended_edges.w_o_shift; - -// const auto& table_1 = extended_edges.table_1; -// const auto& table_2 = extended_edges.table_2; -// const auto& table_3 = extended_edges.table_3; -// const auto& table_4 = extended_edges.table_4; - -// const auto& table_1_shift = extended_edges.table_1_shift; -// const auto& table_2_shift = extended_edges.table_2_shift; -// const auto& table_3_shift = extended_edges.table_3_shift; -// const auto& table_4_shift = extended_edges.table_4_shift; - -// const auto& s_accum = extended_edges.sorted_accum; -// const auto& s_accum_shift = extended_edges.sorted_accum_shift; -// const auto& z_lookup = extended_edges.z_lookup; -// const auto& z_lookup_shift = extended_edges.z_lookup_shift; - -// const auto& table_index = extended_edges.q_o; -// const auto& column_1_step_size = extended_edges.q_r; -// const auto& column_2_step_size = extended_edges.q_m; -// const auto& column_3_step_size = extended_edges.q_c; -// const auto& q_lookup = extended_edges.q_lookup; - -// const auto& lagrange_first = extended_edges.lagrange_first; -// const auto& lagrange_last = extended_edges.lagrange_last; - -// auto wire_accum = (w_1 + column_1_step_size * w_1_shift) + (w_2 + column_2_step_size * w_2_shift) * eta + -// (w_3 + column_3_step_size * w_3_shift) * eta_sqr + table_index * eta_cube; - -// auto table_accum = table_1 + table_2 * eta + table_3 * eta_sqr + table_4 * eta_cube; -// auto table_accum_shift = table_1_shift + table_2_shift * eta + table_3_shift * eta_sqr + table_4_shift * -// eta_cube; - -// // Compute the expected result using a simple to read version of the relation expression -// auto expected_evals = (z_lookup + lagrange_first) * (q_lookup * wire_accum + gamma) * -// (table_accum + table_accum_shift * beta + gamma_by_one_plus_beta) * one_plus_beta; -// expected_evals -= (z_lookup_shift + lagrange_last * grand_product_delta) * -// (s_accum + s_accum_shift * beta + gamma_by_one_plus_beta); - -// validate_evaluations(expected_evals, relation, extended_edges, relation_parameters); -// }; - -// TEST_F(UltraRelationConsistency, LookupGrandProductInitializationRelation) -// { -// using Flavor = honk::flavor::Ultra; -// using FF = typename Flavor::FF; -// using Flavor = honk::flavor::Ultra; -// static constexpr size_t FULL_RELATION_LENGTH = 6; -// using ExtendedEdges = typename Flavor::ExtendedEdges; -// static const size_t NUM_POLYNOMIALS = Flavor::NUM_ALL_ENTITIES; -// auto relation_parameters = compute_mock_relation_parameters(); -// ExtendedEdges extended_edges; -// std::array, NUM_POLYNOMIALS> input_polynomials; - -// // input_univariates are random polynomials of degree one -// for (size_t i = 0; i < NUM_POLYNOMIALS; ++i) { -// input_polynomials[i] = Univariate({ FF::random_element(), FF::random_element() -// }); -// } -// compute_mock_extended_edges(extended_edges, input_polynomials); - -// auto relation = LookupGrandProductInitializationRelation(); - -// // Extract the extended edges for manual computation of relation contribution -// const auto& z_lookup_shift = extended_edges.z_lookup_shift; -// const auto& lagrange_last = extended_edges.lagrange_last; - -// // Compute the expected result using a simple to read version of the relation expression -// auto expected_evals = z_lookup_shift * lagrange_last; - -// validate_evaluations(expected_evals, relation, extended_edges, relation_parameters); -// }; - -// TEST_F(UltraRelationConsistency, GenPermSortRelation) -// { -// using Flavor = honk::flavor::Ultra; -// using FF = typename Flavor::FF; -// using Flavor = honk::flavor::Ultra; -// static constexpr size_t FULL_RELATION_LENGTH = 6; -// using ExtendedEdges = typename Flavor::ExtendedEdges; -// static const size_t NUM_POLYNOMIALS = Flavor::NUM_ALL_ENTITIES; -// auto relation_parameters = compute_mock_relation_parameters(); -// ExtendedEdges extended_edges; -// std::array, NUM_POLYNOMIALS> input_polynomials; - -// // input_univariates are random polynomials of degree one -// for (size_t i = 0; i < NUM_POLYNOMIALS; ++i) { -// input_polynomials[i] = Univariate({ FF::random_element(), FF::random_element() -// }); -// } -// compute_mock_extended_edges(extended_edges, input_polynomials); - -// auto relation = GenPermSortRelation(); - -// // Extract the extended edges for manual computation of relation contribution -// const auto& z_lookup_shift = extended_edges.z_lookup_shift; -// const auto& lagrange_last = extended_edges.lagrange_last; - -// const auto& w_1 = extended_edges.w_l; -// const auto& w_2 = extended_edges.w_r; -// const auto& w_3 = extended_edges.w_o; -// const auto& w_4 = extended_edges.w_4; -// const auto& w_1_shift = extended_edges.w_l_shift; -// const auto& q_sort = extended_edges.q_sort; - -// static const FF fake_alpha_1 = FF(1); -// static const FF fake_alpha_2 = fake_alpha_1 * fake_alpha_1; -// static const FF fake_alpha_3 = fake_alpha_2 * fake_alpha_1; -// static const FF fake_alpha_4 = fake_alpha_3 * fake_alpha_1; - -// // Compute wire differences -// auto delta_1 = w_2 - w_1; -// auto delta_2 = w_3 - w_2; -// auto delta_3 = w_4 - w_3; -// auto delta_4 = w_1_shift - w_4; - -// // Compute the expected result using a simple to read version of the relation expression -// auto expected_evals = delta_1 * (delta_1 - 1) * (delta_1 - 2) * (delta_1 - 3) * fake_alpha_1; -// expected_evals += delta_2 * (delta_2 - 1) * (delta_2 - 2) * (delta_2 - 3) * fake_alpha_2; -// expected_evals += delta_3 * (delta_3 - 1) * (delta_3 - 2) * (delta_3 - 3) * fake_alpha_3; -// expected_evals += delta_4 * (delta_4 - 1) * (delta_4 - 2) * (delta_4 - 3) * fake_alpha_4; -// expected_evals *= q_sort; - -// validate_evaluations(expected_evals, relation, extended_edges, relation_parameters); -// }; - -// TEST_F(UltraRelationConsistency, EllipticRelation) -// { -// using Flavor = honk::flavor::Ultra; -// using FF = typename Flavor::FF; -// using Flavor = honk::flavor::Ultra; -// static constexpr size_t FULL_RELATION_LENGTH = 6; -// using ExtendedEdges = typename Flavor::ExtendedEdges; -// static const size_t NUM_POLYNOMIALS = Flavor::NUM_ALL_ENTITIES; -// auto relation_parameters = compute_mock_relation_parameters(); -// ExtendedEdges extended_edges; -// std::array, NUM_POLYNOMIALS> input_polynomials; - -// // input_univariates are random polynomials of degree one -// for (size_t i = 0; i < NUM_POLYNOMIALS; ++i) { -// input_polynomials[i] = Univariate({ FF::random_element(), FF::random_element() -// }); -// } -// compute_mock_extended_edges(extended_edges, input_polynomials); - -// auto relation = EllipticRelation(); - -// // Extract the extended edges for manual computation of relation contribution -// const auto& x_1 = extended_edges.w_r; -// const auto& y_1 = extended_edges.w_o; - -// const auto& x_2 = extended_edges.w_l_shift; -// const auto& y_2 = extended_edges.w_4_shift; -// const auto& x_3 = extended_edges.w_r_shift; -// const auto& y_3 = extended_edges.w_o_shift; - -// const auto& q_sign = extended_edges.q_l; -// const auto& q_beta = extended_edges.q_o; -// const auto& q_beta_sqr = extended_edges.q_4; -// const auto& q_elliptic = extended_edges.q_elliptic; - -// static const FF fake_alpha_1 = FF(1); -// static const FF fake_alpha_2 = fake_alpha_1 * fake_alpha_1; - -// // Compute x/y coordinate identities -// auto x_identity = q_sign * (y_1 * y_2 * 2); -// x_identity += q_beta * (x_1 * x_2 * x_3 * 2 + x_1 * x_1 * x_2) * FF(-1); -// x_identity += q_beta_sqr * (x_2 * x_2 * x_3 - x_1 * x_2 * x_2); -// x_identity += (x_1 * x_1 * x_3 - y_2 * y_2 - y_1 * y_1 + x_2 * x_2 * x_2 + x_1 * x_1 * x_1); - -// auto y_identity = q_sign * (y_2 * x_3 - y_2 * x_1); -// y_identity += q_beta * (x_2 * y_3 + y_1 * x_2); -// y_identity += (x_1 * y_1 - x_1 * y_3 - y_1 * x_3 - x_1 * y_1); - -// auto expected_evals = x_identity * fake_alpha_1 + y_identity * fake_alpha_2; -// expected_evals *= q_elliptic; - -// validate_evaluations(expected_evals, relation, extended_edges, relation_parameters); -// }; +#include "barretenberg/honk/sumcheck/relations/ultra_arithmetic_relation.hpp" +#include "barretenberg/honk/sumcheck/relations/ultra_arithmetic_relation_secondary.hpp" +#include "barretenberg/honk/sumcheck/relations/lookup_relation.hpp" +#include "barretenberg/honk/sumcheck/relations/gen_perm_sort_relation.hpp" +#include "barretenberg/honk/sumcheck/relations/elliptic_relation.hpp" +#include "barretenberg/honk/sumcheck/relations/auxiliary_relation.hpp" +#include "barretenberg/honk/flavor/ultra.hpp" +#include "relation.hpp" +#include "arithmetic_relation.hpp" +#include "permutation_relation.hpp" +#include "../polynomials/univariate.hpp" +#include "../polynomials/barycentric_data.hpp" + +#include "barretenberg/ecc/curves/bn254/fr.hpp" +#include "barretenberg/numeric/random/engine.hpp" + +#include +#include +using namespace proof_system::honk::sumcheck; +/** + * We want to test if all three relations (namely, ArithmeticRelation, GrandProductComputationRelation, + * GrandProductInitializationRelation) provide correct contributions by manually computing their + * contributions with deterministic and random inputs. The relations are supposed to work with + * univariates (edges) of degree one (length 2) and spit out polynomials of corresponding degrees. We have + * MAX_RELATION_LENGTH = 5, meaning the output of a relation can atmost be a degree 5 polynomial. Hence, + * we use a method compute_mock_extended_edges() which starts with degree one input polynomial (two evaluation + points), + * extends them (using barycentric formula) to six evaluation points, and stores them to an array of polynomials. + */ +static const size_t INPUT_UNIVARIATE_LENGTH = 2; + +namespace proof_system::honk_relation_tests { + +class UltraRelationConsistency : public testing::Test { + public: + using Flavor = honk::flavor::Ultra; + using FF = typename Flavor::FF; + using PurportedEvaluations = typename Flavor::PurportedEvaluations; + + // TODO(#390): Move MAX_RELATION_LENGTH into Flavor and simplify this. + template using ExtendedEdges = typename Flavor::template ExtendedEdges; + + // TODO(#225)(Adrian): Accept FULL_RELATION_LENGTH as a template parameter for this function only, so that the test + // can decide to which degree the polynomials must be extended. Possible accept an existing list of "edges" and + // extend them to the degree. + template + static void compute_mock_extended_edges( + ExtendedEdges& extended_edges, + std::array, NUM_POLYNOMIALS>& input_edges) + { + BarycentricData barycentric_2_to_max = + BarycentricData(); + for (size_t i = 0; i < NUM_POLYNOMIALS; ++i) { + extended_edges[i] = barycentric_2_to_max.extend(input_edges[i]); + } + } + + /** + * @brief Returns randomly sampled parameters to feed to the relations. + * + * @return RelationParameters + */ + RelationParameters compute_mock_relation_parameters() + { + return { .eta = FF::random_element(), + .beta = FF::random_element(), + .gamma = FF::random_element(), + .public_input_delta = FF::random_element(), + .lookup_grand_product_delta = FF::random_element() }; + } + + /** + * @brief Given an array of Univariates, create a new array containing only the i-th evaluations + * of all the univariates. + * + * @note Not really optimized, mainly used for testing that the relations evaluate to the same value when + * evaluated as Univariates, Expressions, or index-by-index + * @todo(Adrian) Maybe this is more helpful as part of a `check_logic` function. + * + * @tparam NUM_UNIVARIATES number of univariates in the input array (deduced from `univariates`) + * @tparam univariate_length number of evaluations (deduced from `univariates`) + * @param univariates array of Univariates + * @param i index of the evaluations we want to take from each univariate + * @return std::array such that result[j] = univariates[j].value_at(i) + */ + template + static PurportedEvaluations transposed_univariate_array_at(ExtendedEdges univariates, size_t i) + { + ASSERT(i < univariate_length); + std::array result; + size_t result_idx = 0; // TODO(#391) zip + for (auto& univariate : univariates) { + result[result_idx] = univariate.value_at(i); + ++result_idx; + } + return result; + }; + + /** + * @brief Compute the evaluation of a `relation` in different ways, comparing it to the provided `expected_evals` + * + * @details Check both `add_full_relation_value_contribution` and `add_edge_contribution` by comparing the result + to + * the `expected_evals` computed by the caller. + * Ensures that the relations compute the same result as the expression given in the tests. + * + * @param expected_evals Relation evaluation computed by the caller. + * @param relation being tested + * @param extended_edges + * @param relation_parameters + */ + template + static void validate_evaluations(const auto& expected_full_length_univariates, /* array of Univariates*/ + const auto relation, + const ExtendedEdges& extended_edges, + const RelationParameters& relation_parameters) + { + // First check that the verifier's computation on individual evaluations is correct. + // Note: it is sufficient to check at only the first index of the input edges. + + // Extract the RelationValues type for the given relation + using RelationValues = typename decltype(relation)::RelationValues; + RelationValues relation_evals; + RelationValues expected_relation_evals; + + ASSERT_EQ(expected_relation_evals.size(), expected_full_length_univariates.size()); + // Initialize expected_evals to 0th coefficient of expected full length univariates + for (size_t idx = 0; idx < relation_evals.size(); ++idx) { + relation_evals[idx] = FF(0); // initialize to 0 + expected_relation_evals[idx] = expected_full_length_univariates[idx].value_at(0); + } + + // Extract 0th evaluation from extended edges + PurportedEvaluations edge_evaluations = transposed_univariate_array_at(extended_edges, 0); + + // Evaluate the relation using the verifier functionality + relation.add_full_relation_value_contribution(relation_evals, edge_evaluations, relation_parameters); + + EXPECT_EQ(relation_evals, expected_relation_evals); + + // Next, check that the prover's computation on Univariates is correct + + using RelationUnivariates = typename decltype(relation)::RelationUnivariates; + RelationUnivariates relation_univariates; + zero_univariates<>(relation_univariates); + + constexpr std::size_t num_univariates = std::tuple_size::value; + + // Compute the relatiion univariates via the sumcheck prover functionality, then extend + // them to full length for easy comparison with the expected result. + relation.add_edge_contribution(relation_univariates, extended_edges, relation_parameters, 1); + + auto full_length_univariates = std::array, num_univariates>(); + extend_tuple_of_arrays(relation_univariates, full_length_univariates); + + EXPECT_EQ(full_length_univariates, expected_full_length_univariates); + }; + + template static void zero_univariates(std::tuple& tuple) + { + auto& element = std::get(tuple); + std::fill(element.evaluations.begin(), element.evaluations.end(), FF(0)); + + if constexpr (idx + 1 < sizeof...(Ts)) { + zero_univariates(tuple); + } + } + + template + static void extend_tuple_of_arrays(std::tuple& tuple, auto& result_univariates) + { + auto& element = std::get(tuple); + using Element = std::remove_reference_t; + BarycentricData barycentric_utils; + result_univariates[idx] = barycentric_utils.extend(element); + + if constexpr (idx + 1 < sizeof...(Ts)) { + extend_tuple_of_arrays(tuple, result_univariates); + } + } + + // /** + // * @brief Compute the evaluation of a `relation` in different ways, comparing it to the provided `expected_evals` + // * + // * @details Check both `add_full_relation_value_contribution` and `add_edge_contribution` by comparing the result + // to + // * the `expected_evals` computed by the caller. + // * Ensures that the relations compute the same result as the expression given in the tests. + // * + // * @param expected_evals Relation evaluation computed by the caller. + // * @param relation being tested + // * @param extended_edges + // * @param relation_parameters + // */ + // template + // static void validate_evaluations(const Univariate& expected_evals, + // const auto relation, + // const ExtendedEdges& extended_edges, + // const RelationParameters& relation_parameters) + // { + + // // Compute the expression index-by-index + // Univariate expected_evals_index{ 0 }; + // for (size_t i = 0; i < FULL_RELATION_LENGTH; ++i) { + // // Get an array of the same size as `extended_edges` with only the i-th element of each extended edge. + // PurportedEvaluations evals_i = transposed_univariate_array_at(extended_edges, i); + // // Evaluate the relation + // relation.add_full_relation_value_contribution( + // expected_evals_index.value_at(i), evals_i, relation_parameters); + // } + // EXPECT_EQ(expected_evals, expected_evals_index); + + // // Compute the expression using the class, that converts the extended edges to UnivariateView + // auto expected_evals_view = Univariate(0); + // // The scaling factor is essentially 1 since we are working with degree 1 univariates + // relation.add_edge_contribution(expected_evals_view, extended_edges, relation_parameters, 1); + + // // Tiny hack to reduce `expected_evals` to be of size `relation.RELATION_LENGTH` + // Univariate expected_evals_restricted{ + // UnivariateView(expected_evals) + // }; + // EXPECT_EQ(expected_evals_restricted, expected_evals_view); + // }; +}; + +TEST_F(UltraRelationConsistency, UltraArithmeticRelation) +{ + using Flavor = honk::flavor::Ultra; + using FF = typename Flavor::FF; + static constexpr size_t FULL_RELATION_LENGTH = 6; + using ExtendedEdges = typename Flavor::template ExtendedEdges; + static const size_t NUM_POLYNOMIALS = Flavor::NUM_ALL_ENTITIES; + + const auto relation_parameters = compute_mock_relation_parameters(); + ExtendedEdges extended_edges; + std::array, NUM_POLYNOMIALS> input_polynomials; + + // input_univariates are random polynomials of degree one + for (size_t i = 0; i < NUM_POLYNOMIALS; ++i) { + input_polynomials[i] = Univariate({ FF::random_element(), FF::random_element() }); + } + compute_mock_extended_edges(extended_edges, input_polynomials); + + auto relation = UltraArithmeticRelation(); + + // Extract the extended edges for manual computation of relation contribution + const auto& w_1 = extended_edges.w_l; + const auto& w_1_shift = extended_edges.w_l_shift; + const auto& w_2 = extended_edges.w_r; + const auto& w_3 = extended_edges.w_o; + const auto& w_4 = extended_edges.w_4; + const auto& w_4_shift = extended_edges.w_4_shift; + const auto& q_m = extended_edges.q_m; + const auto& q_l = extended_edges.q_l; + const auto& q_r = extended_edges.q_r; + const auto& q_o = extended_edges.q_o; + const auto& q_4 = extended_edges.q_4; + const auto& q_c = extended_edges.q_c; + const auto& q_arith = extended_edges.q_arith; + + static const FF neg_half = FF(-2).invert(); + + constexpr std::size_t NUM_CONSTRAINTS = decltype(relation)::NUM_CONSTRAINTS; + auto expected_full_length_univariates = std::array, NUM_CONSTRAINTS>(); + + // Contribution 1 + auto contribution_1 = (q_arith - 3) * (q_m * w_2 * w_1) * neg_half; + contribution_1 += (q_l * w_1) + (q_r * w_2) + (q_o * w_3) + (q_4 * w_4) + q_c; + contribution_1 += (q_arith - 1) * w_4_shift; + contribution_1 *= q_arith; + expected_full_length_univariates[0] = contribution_1; + + // Contribution 2 + auto contribution_2 = (w_1 + w_4 - w_1_shift + q_m); + contribution_2 *= (q_arith - 2) * (q_arith - 1) * q_arith; + expected_full_length_univariates[1] = contribution_2; + + validate_evaluations(expected_full_length_univariates, relation, extended_edges, relation_parameters); +}; + +TEST_F(UltraRelationConsistency, UltraPermutationRelation) +{ + using Flavor = honk::flavor::Ultra; + using FF = typename Flavor::FF; + using Flavor = honk::flavor::Ultra; + static constexpr size_t FULL_RELATION_LENGTH = 6; + using ExtendedEdges = typename Flavor::template ExtendedEdges; + static const size_t NUM_POLYNOMIALS = Flavor::NUM_ALL_ENTITIES; + auto relation_parameters = compute_mock_relation_parameters(); + ExtendedEdges extended_edges; + std::array, NUM_POLYNOMIALS> input_polynomials; + + // input_univariates are random polynomials of degree one + for (size_t i = 0; i < NUM_POLYNOMIALS; ++i) { + input_polynomials[i] = Univariate({ FF::random_element(), FF::random_element() }); + } + compute_mock_extended_edges(extended_edges, input_polynomials); + + auto relation = UltraPermutationRelation(); + + const auto& beta = relation_parameters.beta; + const auto& gamma = relation_parameters.gamma; + const auto& public_input_delta = relation_parameters.public_input_delta; + + // Extract the extended edges for manual computation of relation contribution + const auto& w_1 = extended_edges.w_l; + const auto& w_2 = extended_edges.w_r; + const auto& w_3 = extended_edges.w_o; + const auto& w_4 = extended_edges.w_4; + const auto& sigma_1 = extended_edges.sigma_1; + const auto& sigma_2 = extended_edges.sigma_2; + const auto& sigma_3 = extended_edges.sigma_3; + const auto& sigma_4 = extended_edges.sigma_4; + const auto& id_1 = extended_edges.id_1; + const auto& id_2 = extended_edges.id_2; + const auto& id_3 = extended_edges.id_3; + const auto& id_4 = extended_edges.id_4; + const auto& z_perm = extended_edges.z_perm; + const auto& z_perm_shift = extended_edges.z_perm_shift; + const auto& lagrange_first = extended_edges.lagrange_first; + const auto& lagrange_last = extended_edges.lagrange_last; + + constexpr std::size_t NUM_CONSTRAINTS = decltype(relation)::NUM_CONSTRAINTS; + auto expected_full_length_univariates = std::array, NUM_CONSTRAINTS>(); + + // Compute the expected result using a simple to read version of the relation expression + + // Contribution 1 + auto contribution_1 = (z_perm + lagrange_first) * (w_1 + id_1 * beta + gamma) * (w_2 + id_2 * beta + gamma) * + (w_3 + id_3 * beta + gamma) * (w_4 + id_4 * beta + gamma) - + (z_perm_shift + lagrange_last * public_input_delta) * (w_1 + sigma_1 * beta + gamma) * + (w_2 + sigma_2 * beta + gamma) * (w_3 + sigma_3 * beta + gamma) * + (w_4 + sigma_4 * beta + gamma); + expected_full_length_univariates[0] = contribution_1; + + // Contribution 2 + auto contribution_2 = z_perm_shift * lagrange_last; + expected_full_length_univariates[1] = contribution_2; + + validate_evaluations(expected_full_length_univariates, relation, extended_edges, relation_parameters); +}; + +TEST_F(UltraRelationConsistency, LookupRelation) +{ + using Flavor = honk::flavor::Ultra; + using FF = typename Flavor::FF; + using Flavor = honk::flavor::Ultra; + static constexpr size_t FULL_RELATION_LENGTH = 6; + using ExtendedEdges = typename Flavor::ExtendedEdges; + static const size_t NUM_POLYNOMIALS = Flavor::NUM_ALL_ENTITIES; + auto relation_parameters = compute_mock_relation_parameters(); + ExtendedEdges extended_edges; + std::array, NUM_POLYNOMIALS> input_polynomials; + + // input_univariates are random polynomials of degree one + for (size_t i = 0; i < NUM_POLYNOMIALS; ++i) { + input_polynomials[i] = Univariate({ FF::random_element(), FF::random_element() }); + } + compute_mock_extended_edges(extended_edges, input_polynomials); + + auto relation = LookupRelation(); + + const auto eta = relation_parameters.eta; + const auto beta = relation_parameters.beta; + const auto gamma = relation_parameters.gamma; + auto grand_product_delta = relation_parameters.lookup_grand_product_delta; + + // Extract the extended edges for manual computation of relation contribution + auto one_plus_beta = FF::one() + beta; + auto gamma_by_one_plus_beta = gamma * one_plus_beta; + auto eta_sqr = eta * eta; + auto eta_cube = eta_sqr * eta; + + const auto& w_1 = extended_edges.w_l; + const auto& w_2 = extended_edges.w_r; + const auto& w_3 = extended_edges.w_o; + + const auto& w_1_shift = extended_edges.w_l_shift; + const auto& w_2_shift = extended_edges.w_r_shift; + const auto& w_3_shift = extended_edges.w_o_shift; + + const auto& table_1 = extended_edges.table_1; + const auto& table_2 = extended_edges.table_2; + const auto& table_3 = extended_edges.table_3; + const auto& table_4 = extended_edges.table_4; + + const auto& table_1_shift = extended_edges.table_1_shift; + const auto& table_2_shift = extended_edges.table_2_shift; + const auto& table_3_shift = extended_edges.table_3_shift; + const auto& table_4_shift = extended_edges.table_4_shift; + + const auto& s_accum = extended_edges.sorted_accum; + const auto& s_accum_shift = extended_edges.sorted_accum_shift; + const auto& z_lookup = extended_edges.z_lookup; + const auto& z_lookup_shift = extended_edges.z_lookup_shift; + + const auto& table_index = extended_edges.q_o; + const auto& column_1_step_size = extended_edges.q_r; + const auto& column_2_step_size = extended_edges.q_m; + const auto& column_3_step_size = extended_edges.q_c; + const auto& q_lookup = extended_edges.q_lookup; + + const auto& lagrange_first = extended_edges.lagrange_first; + const auto& lagrange_last = extended_edges.lagrange_last; + + auto wire_accum = (w_1 + column_1_step_size * w_1_shift) + (w_2 + column_2_step_size * w_2_shift) * eta + + (w_3 + column_3_step_size * w_3_shift) * eta_sqr + table_index * eta_cube; + + auto table_accum = table_1 + table_2 * eta + table_3 * eta_sqr + table_4 * eta_cube; + auto table_accum_shift = table_1_shift + table_2_shift * eta + table_3_shift * eta_sqr + table_4_shift * eta_cube; + + constexpr std::size_t NUM_CONSTRAINTS = decltype(relation)::NUM_CONSTRAINTS; + auto expected_full_length_univariates = std::array, NUM_CONSTRAINTS>(); + + // Compute the expected result using a simple to read version of the relation expression + + // Contribution 1 + auto contribution_1 = (z_lookup + lagrange_first) * (q_lookup * wire_accum + gamma) * + (table_accum + table_accum_shift * beta + gamma_by_one_plus_beta) * one_plus_beta; + contribution_1 -= (z_lookup_shift + lagrange_last * grand_product_delta) * + (s_accum + s_accum_shift * beta + gamma_by_one_plus_beta); + expected_full_length_univariates[0] = contribution_1; + + // Contribution 2 + auto contribution_2 = z_lookup_shift * lagrange_last; + expected_full_length_univariates[1] = contribution_2; + + validate_evaluations(expected_full_length_univariates, relation, extended_edges, relation_parameters); +}; + +TEST_F(UltraRelationConsistency, GenPermSortRelation) +{ + using Flavor = honk::flavor::Ultra; + using FF = typename Flavor::FF; + using Flavor = honk::flavor::Ultra; + static constexpr size_t FULL_RELATION_LENGTH = 6; + using ExtendedEdges = typename Flavor::ExtendedEdges; + static const size_t NUM_POLYNOMIALS = Flavor::NUM_ALL_ENTITIES; + auto relation_parameters = compute_mock_relation_parameters(); + ExtendedEdges extended_edges; + std::array, NUM_POLYNOMIALS> input_polynomials; + + // input_univariates are random polynomials of degree one + for (size_t i = 0; i < NUM_POLYNOMIALS; ++i) { + input_polynomials[i] = Univariate({ FF::random_element(), FF::random_element() }); + } + compute_mock_extended_edges(extended_edges, input_polynomials); + + auto relation = GenPermSortRelation(); + + // Extract the extended edges for manual computation of relation contribution + const auto& z_lookup_shift = extended_edges.z_lookup_shift; + const auto& lagrange_last = extended_edges.lagrange_last; + + const auto& w_1 = extended_edges.w_l; + const auto& w_2 = extended_edges.w_r; + const auto& w_3 = extended_edges.w_o; + const auto& w_4 = extended_edges.w_4; + const auto& w_1_shift = extended_edges.w_l_shift; + const auto& q_sort = extended_edges.q_sort; + + // Compute wire differences + auto delta_1 = w_2 - w_1; + auto delta_2 = w_3 - w_2; + auto delta_3 = w_4 - w_3; + auto delta_4 = w_1_shift - w_4; + + constexpr std::size_t NUM_CONSTRAINTS = decltype(relation)::NUM_CONSTRAINTS; + auto expected_full_length_univariates = std::array, NUM_CONSTRAINTS>(); + + // Compute the expected result using a simple to read version of the relation expression + auto contribution_1 = delta_1 * (delta_1 - 1) * (delta_1 - 2) * (delta_1 - 3); + auto contribution_2 = delta_2 * (delta_2 - 1) * (delta_2 - 2) * (delta_2 - 3); + auto contribution_3 = delta_3 * (delta_3 - 1) * (delta_3 - 2) * (delta_3 - 3); + auto contribution_4 = delta_4 * (delta_4 - 1) * (delta_4 - 2) * (delta_4 - 3); + + expected_full_length_univariates[0] = contribution_1 * q_sort; + expected_full_length_univariates[1] = contribution_2 * q_sort; + expected_full_length_univariates[2] = contribution_3 * q_sort; + expected_full_length_univariates[3] = contribution_4 * q_sort; + + validate_evaluations(expected_full_length_univariates, relation, extended_edges, relation_parameters); +}; + +TEST_F(UltraRelationConsistency, EllipticRelation) +{ + using Flavor = honk::flavor::Ultra; + using FF = typename Flavor::FF; + using Flavor = honk::flavor::Ultra; + static constexpr size_t FULL_RELATION_LENGTH = 6; + using ExtendedEdges = typename Flavor::ExtendedEdges; + static const size_t NUM_POLYNOMIALS = Flavor::NUM_ALL_ENTITIES; + auto relation_parameters = compute_mock_relation_parameters(); + ExtendedEdges extended_edges; + std::array, NUM_POLYNOMIALS> input_polynomials; + + // input_univariates are random polynomials of degree one + for (size_t i = 0; i < NUM_POLYNOMIALS; ++i) { + input_polynomials[i] = Univariate({ FF::random_element(), FF::random_element() }); + } + compute_mock_extended_edges(extended_edges, input_polynomials); + + auto relation = EllipticRelation(); + + // Extract the extended edges for manual computation of relation contribution + const auto& x_1 = extended_edges.w_r; + const auto& y_1 = extended_edges.w_o; + + const auto& x_2 = extended_edges.w_l_shift; + const auto& y_2 = extended_edges.w_4_shift; + const auto& x_3 = extended_edges.w_r_shift; + const auto& y_3 = extended_edges.w_o_shift; + + const auto& q_sign = extended_edges.q_l; + const auto& q_beta = extended_edges.q_o; + const auto& q_beta_sqr = extended_edges.q_4; + const auto& q_elliptic = extended_edges.q_elliptic; + + constexpr std::size_t NUM_CONSTRAINTS = decltype(relation)::NUM_CONSTRAINTS; + auto expected_full_length_univariates = std::array, NUM_CONSTRAINTS>(); + + // Compute x/y coordinate identities + + // Contribution 1 + auto x_identity = q_sign * (y_1 * y_2 * 2); + x_identity += q_beta * (x_1 * x_2 * x_3 * 2 + x_1 * x_1 * x_2) * FF(-1); + x_identity += q_beta_sqr * (x_2 * x_2 * x_3 - x_1 * x_2 * x_2); + x_identity += (x_1 * x_1 * x_3 - y_2 * y_2 - y_1 * y_1 + x_2 * x_2 * x_2 + x_1 * x_1 * x_1); + + // Contribution 2 + auto y_identity = q_sign * (y_2 * x_3 - y_2 * x_1); + y_identity += q_beta * (x_2 * y_3 + y_1 * x_2); + y_identity += (x_1 * y_1 - x_1 * y_3 - y_1 * x_3 - x_1 * y_1); + + expected_full_length_univariates[0] = x_identity * q_elliptic; + expected_full_length_univariates[1] = y_identity * q_elliptic; + + validate_evaluations(expected_full_length_univariates, relation, extended_edges, relation_parameters); +}; // TEST_F(UltraRelationConsistency, AuxiliaryRelation) // { @@ -701,4 +718,4 @@ // validate_evaluations(expected_evals, relation, extended_edges, relation_parameters); // }; -// } // namespace proof_system::honk_relation_tests +} // namespace proof_system::honk_relation_tests From 4c00b5d347265fa1834c274e1345d3ab7f20f4fd Mon Sep 17 00:00:00 2001 From: ledwards2225 Date: Tue, 16 May 2023 21:30:29 +0000 Subject: [PATCH 09/18] delete unused relations and rename relations hpp --- .../composer/standard_honk_composer.test.cpp | 2 +- .../composer/ultra_honk_composer.test.cpp | 2 +- .../honk/proof_system/ultra_prover.cpp | 4 -- .../honk/proof_system/ultra_prover.hpp | 2 +- .../honk/proof_system/ultra_verifier.cpp | 4 -- .../relations/arithmetic_relation.hpp | 2 +- .../sumcheck/relations/auxiliary_relation.hpp | 2 +- .../sumcheck/relations/elliptic_relation.hpp | 2 +- .../relations/gen_perm_sort_relation.hpp | 2 +- .../sumcheck/relations/lookup_relation.hpp | 40 +---------- .../relations/permutation_relation.hpp | 2 +- .../relations/relation_consistency.test.cpp | 3 +- .../relations/relation_correctness.test.cpp | 3 +- .../{relation.hpp => relation_parameters.hpp} | 0 .../relations/ultra_arithmetic_relation.hpp | 5 +- .../ultra_arithmetic_relation_secondary.hpp | 66 ------------------- .../ultra_relation_consistency.test.cpp | 47 +------------ .../barretenberg/honk/sumcheck/sumcheck.hpp | 2 +- .../honk/sumcheck/sumcheck_round.hpp | 2 +- 19 files changed, 19 insertions(+), 173 deletions(-) rename cpp/src/barretenberg/honk/sumcheck/relations/{relation.hpp => relation_parameters.hpp} (100%) delete mode 100644 cpp/src/barretenberg/honk/sumcheck/relations/ultra_arithmetic_relation_secondary.hpp diff --git a/cpp/src/barretenberg/honk/composer/standard_honk_composer.test.cpp b/cpp/src/barretenberg/honk/composer/standard_honk_composer.test.cpp index e076534f21..a13e0df167 100644 --- a/cpp/src/barretenberg/honk/composer/standard_honk_composer.test.cpp +++ b/cpp/src/barretenberg/honk/composer/standard_honk_composer.test.cpp @@ -1,5 +1,5 @@ #include "standard_honk_composer.hpp" -#include "barretenberg/honk/sumcheck/relations/relation.hpp" +#include "barretenberg/honk/sumcheck/relations/relation_parameters.hpp" #include "barretenberg/numeric/uint256/uint256.hpp" #include #include 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 41f35402a1..5ae7e2b338 100644 --- a/cpp/src/barretenberg/honk/composer/ultra_honk_composer.test.cpp +++ b/cpp/src/barretenberg/honk/composer/ultra_honk_composer.test.cpp @@ -1,7 +1,7 @@ // #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/honk/sumcheck/relations/relation_parameters.hpp" // #include "barretenberg/numeric/uint256/uint256.hpp" // #include // #include diff --git a/cpp/src/barretenberg/honk/proof_system/ultra_prover.cpp b/cpp/src/barretenberg/honk/proof_system/ultra_prover.cpp index 752fc94054..1d6d6cacd3 100644 --- a/cpp/src/barretenberg/honk/proof_system/ultra_prover.cpp +++ b/cpp/src/barretenberg/honk/proof_system/ultra_prover.cpp @@ -3,7 +3,6 @@ #include #include "barretenberg/honk/proof_system/prover_library.hpp" #include "barretenberg/honk/sumcheck/relations/ultra_arithmetic_relation.hpp" -#include "barretenberg/honk/sumcheck/relations/ultra_arithmetic_relation_secondary.hpp" #include "barretenberg/honk/sumcheck/sumcheck.hpp" #include #include "barretenberg/honk/sumcheck/polynomials/univariate.hpp" // will go away @@ -194,11 +193,8 @@ template void UltraProver_::execute_relation_check_ // using Sumcheck = sumcheck::Sumcheck, // sumcheck::UltraArithmeticRelation, - // sumcheck::UltraArithmeticRelationSecondary, // sumcheck::UltraPermutationRelation, - // sumcheck::UltraGrandProductInitializationRelation, // sumcheck::LookupRelation, - // sumcheck::LookupGrandProductInitializationRelation, // sumcheck::GenPermSortRelation, // sumcheck::EllipticRelation, // sumcheck::AuxiliaryRelation>; diff --git a/cpp/src/barretenberg/honk/proof_system/ultra_prover.hpp b/cpp/src/barretenberg/honk/proof_system/ultra_prover.hpp index 9bbe7314f2..34060f878c 100644 --- a/cpp/src/barretenberg/honk/proof_system/ultra_prover.hpp +++ b/cpp/src/barretenberg/honk/proof_system/ultra_prover.hpp @@ -6,7 +6,7 @@ #include "barretenberg/honk/pcs/kzg/kzg.hpp" #include "barretenberg/honk/transcript/transcript.hpp" #include "barretenberg/honk/flavor/ultra.hpp" -#include "barretenberg/honk/sumcheck/relations/relation.hpp" +#include "barretenberg/honk/sumcheck/relations/relation_parameters.hpp" #include "barretenberg/honk/sumcheck/sumcheck_output.hpp" namespace proof_system::honk { diff --git a/cpp/src/barretenberg/honk/proof_system/ultra_verifier.cpp b/cpp/src/barretenberg/honk/proof_system/ultra_verifier.cpp index 7652cf5f2a..48dd02f5db 100644 --- a/cpp/src/barretenberg/honk/proof_system/ultra_verifier.cpp +++ b/cpp/src/barretenberg/honk/proof_system/ultra_verifier.cpp @@ -5,7 +5,6 @@ #include "barretenberg/ecc/curves/bn254/scalar_multiplication/scalar_multiplication.hpp" #include "barretenberg/honk/utils/power_polynomial.hpp" #include "barretenberg/honk/sumcheck/relations/ultra_arithmetic_relation.hpp" -#include "barretenberg/honk/sumcheck/relations/ultra_arithmetic_relation_secondary.hpp" #include "barretenberg/honk/sumcheck/relations/permutation_relation.hpp" #include "barretenberg/honk/sumcheck/relations/lookup_relation.hpp" #include "barretenberg/honk/sumcheck/relations/gen_perm_sort_relation.hpp" @@ -111,11 +110,8 @@ template bool UltraVerifier_::verify_proof(const plonk // auto sumcheck = Sumcheck, // honk::sumcheck::UltraArithmeticRelation, - // honk::sumcheck::UltraArithmeticRelationSecondary, // honk::sumcheck::UltraPermutationRelation, - // honk::sumcheck::UltraGrandProductInitializationRelation, // honk::sumcheck::LookupRelation, - // honk::sumcheck::LookupGrandProductInitializationRelation, // honk::sumcheck::GenPermSortRelation, // honk::sumcheck::EllipticRelation, // honk::sumcheck::AuxiliaryRelation>(circuit_size, transcript); diff --git a/cpp/src/barretenberg/honk/sumcheck/relations/arithmetic_relation.hpp b/cpp/src/barretenberg/honk/sumcheck/relations/arithmetic_relation.hpp index 74a0b733cc..be7a9ee261 100644 --- a/cpp/src/barretenberg/honk/sumcheck/relations/arithmetic_relation.hpp +++ b/cpp/src/barretenberg/honk/sumcheck/relations/arithmetic_relation.hpp @@ -3,7 +3,7 @@ #include #include "../polynomials/univariate.hpp" -#include "relation.hpp" +#include "relation_parameters.hpp" namespace proof_system::honk::sumcheck { diff --git a/cpp/src/barretenberg/honk/sumcheck/relations/auxiliary_relation.hpp b/cpp/src/barretenberg/honk/sumcheck/relations/auxiliary_relation.hpp index c8b7f288a2..76410b663a 100644 --- a/cpp/src/barretenberg/honk/sumcheck/relations/auxiliary_relation.hpp +++ b/cpp/src/barretenberg/honk/sumcheck/relations/auxiliary_relation.hpp @@ -4,7 +4,7 @@ #include "../polynomials/univariate.hpp" #include "barretenberg/numeric/uint256/uint256.hpp" -#include "relation.hpp" +#include "relation_parameters.hpp" namespace proof_system::honk::sumcheck { diff --git a/cpp/src/barretenberg/honk/sumcheck/relations/elliptic_relation.hpp b/cpp/src/barretenberg/honk/sumcheck/relations/elliptic_relation.hpp index bea8fd40b9..a30fc07f02 100644 --- a/cpp/src/barretenberg/honk/sumcheck/relations/elliptic_relation.hpp +++ b/cpp/src/barretenberg/honk/sumcheck/relations/elliptic_relation.hpp @@ -3,7 +3,7 @@ #include #include "../polynomials/univariate.hpp" -#include "relation.hpp" +#include "relation_parameters.hpp" namespace proof_system::honk::sumcheck { diff --git a/cpp/src/barretenberg/honk/sumcheck/relations/gen_perm_sort_relation.hpp b/cpp/src/barretenberg/honk/sumcheck/relations/gen_perm_sort_relation.hpp index e1cd70f10c..39ff5595b7 100644 --- a/cpp/src/barretenberg/honk/sumcheck/relations/gen_perm_sort_relation.hpp +++ b/cpp/src/barretenberg/honk/sumcheck/relations/gen_perm_sort_relation.hpp @@ -3,7 +3,7 @@ #include #include "../polynomials/univariate.hpp" -#include "relation.hpp" +#include "relation_parameters.hpp" namespace proof_system::honk::sumcheck { diff --git a/cpp/src/barretenberg/honk/sumcheck/relations/lookup_relation.hpp b/cpp/src/barretenberg/honk/sumcheck/relations/lookup_relation.hpp index f966caf86a..1ae3794306 100644 --- a/cpp/src/barretenberg/honk/sumcheck/relations/lookup_relation.hpp +++ b/cpp/src/barretenberg/honk/sumcheck/relations/lookup_relation.hpp @@ -1,5 +1,5 @@ #pragma once -#include "relation.hpp" +#include "relation_parameters.hpp" #include "../polynomials/univariate.hpp" #pragma GCC diagnostic ignored "-Wunused-variable" @@ -185,42 +185,4 @@ template class LookupRelation { std::get<1>(full_honk_relation_value) += lagrange_last * z_lookup_shift; }; }; - -template class LookupGrandProductInitializationRelation { - public: - // 1 + polynomial degree of this relation - static constexpr size_t RELATION_LENGTH = 3; // deg(lagrange_last * z_lookup_shift) = 2 - - /** - * @brief Compute contribution of the lookup grand prod relation for a given edge (internal function) - * - * @details This the relation confirms correct initialization of the lookup grand - * product polynomial Z_lookup with Z_lookup[circuit_size] = 0. - * - * @param evals transformed to `evals + C(extended_edges(X)...)*scaling_factor` - * @param extended_edges an std::array containing the fully extended Univariate edges. - * @param parameters contains beta, gamma, and public_input_delta, .... - * @param scaling_factor optional term to scale the evaluation before adding to evals. - */ - inline void add_edge_contribution(Univariate& evals, - const auto& extended_edges, - const RelationParameters& /*unused*/, - const FF& scaling_factor) const - { - auto z_lookup_shift = UnivariateView(extended_edges.z_lookup_shift); - auto lagrange_last = UnivariateView(extended_edges.lagrange_last); - - evals += (lagrange_last * z_lookup_shift) * scaling_factor; - }; - - void add_full_relation_value_contribution(FF& full_honk_relation_value, - auto& purported_evaluations, - const RelationParameters& /*unused*/) const - { - auto z_lookup_shift = purported_evaluations.z_lookup_shift; - auto lagrange_last = purported_evaluations.lagrange_last; - - full_honk_relation_value += lagrange_last * z_lookup_shift; - }; -}; } // namespace proof_system::honk::sumcheck \ No newline at end of file diff --git a/cpp/src/barretenberg/honk/sumcheck/relations/permutation_relation.hpp b/cpp/src/barretenberg/honk/sumcheck/relations/permutation_relation.hpp index 829d73f08e..27100d865e 100644 --- a/cpp/src/barretenberg/honk/sumcheck/relations/permutation_relation.hpp +++ b/cpp/src/barretenberg/honk/sumcheck/relations/permutation_relation.hpp @@ -1,5 +1,5 @@ #pragma once -#include "relation.hpp" +#include "relation_parameters.hpp" #include "../polynomials/univariate.hpp" // TODO(luke): change name of this file to permutation_grand_product_relation(s).hpp and move 'init' relation into it. diff --git a/cpp/src/barretenberg/honk/sumcheck/relations/relation_consistency.test.cpp b/cpp/src/barretenberg/honk/sumcheck/relations/relation_consistency.test.cpp index 4add53f864..4473add902 100644 --- a/cpp/src/barretenberg/honk/sumcheck/relations/relation_consistency.test.cpp +++ b/cpp/src/barretenberg/honk/sumcheck/relations/relation_consistency.test.cpp @@ -1,8 +1,7 @@ #include "barretenberg/honk/sumcheck/relations/lookup_relation.hpp" #include "barretenberg/honk/sumcheck/relations/ultra_arithmetic_relation.hpp" -#include "barretenberg/honk/sumcheck/relations/ultra_arithmetic_relation_secondary.hpp" #include "barretenberg/honk/flavor/standard.hpp" -#include "relation.hpp" +#include "relation_parameters.hpp" #include "arithmetic_relation.hpp" #include "permutation_relation.hpp" #include "../polynomials/univariate.hpp" diff --git a/cpp/src/barretenberg/honk/sumcheck/relations/relation_correctness.test.cpp b/cpp/src/barretenberg/honk/sumcheck/relations/relation_correctness.test.cpp index da473eafec..4a5628150f 100644 --- a/cpp/src/barretenberg/honk/sumcheck/relations/relation_correctness.test.cpp +++ b/cpp/src/barretenberg/honk/sumcheck/relations/relation_correctness.test.cpp @@ -3,11 +3,10 @@ #include "barretenberg/honk/composer/ultra_honk_composer.hpp" #include "barretenberg/honk/composer/standard_honk_composer.hpp" #include "barretenberg/honk/proof_system/prover_library.hpp" -#include "barretenberg/honk/sumcheck/relations/relation.hpp" +#include "barretenberg/honk/sumcheck/relations/relation_parameters.hpp" #include "barretenberg/honk/sumcheck/relations/arithmetic_relation.hpp" #include "barretenberg/honk/sumcheck/relations/permutation_relation.hpp" #include "barretenberg/honk/sumcheck/relations/ultra_arithmetic_relation.hpp" -#include "barretenberg/honk/sumcheck/relations/ultra_arithmetic_relation_secondary.hpp" #include "barretenberg/honk/sumcheck/relations/lookup_relation.hpp" #include "barretenberg/honk/sumcheck/relations/gen_perm_sort_relation.hpp" #include "barretenberg/honk/sumcheck/relations/elliptic_relation.hpp" diff --git a/cpp/src/barretenberg/honk/sumcheck/relations/relation.hpp b/cpp/src/barretenberg/honk/sumcheck/relations/relation_parameters.hpp similarity index 100% rename from cpp/src/barretenberg/honk/sumcheck/relations/relation.hpp rename to cpp/src/barretenberg/honk/sumcheck/relations/relation_parameters.hpp diff --git a/cpp/src/barretenberg/honk/sumcheck/relations/ultra_arithmetic_relation.hpp b/cpp/src/barretenberg/honk/sumcheck/relations/ultra_arithmetic_relation.hpp index 4bbd28b94a..a62046a8e9 100644 --- a/cpp/src/barretenberg/honk/sumcheck/relations/ultra_arithmetic_relation.hpp +++ b/cpp/src/barretenberg/honk/sumcheck/relations/ultra_arithmetic_relation.hpp @@ -3,7 +3,7 @@ #include #include "../polynomials/univariate.hpp" -#include "relation.hpp" +#include "relation_parameters.hpp" namespace proof_system::honk::sumcheck { @@ -27,6 +27,9 @@ template class UltraArithmeticRelation { * (q_l * w_l) + (q_r * w_r) + (q_o * w_o) + (q_4 * w_4) + q_c + * (q_arith - 1)w_4_shift ] * + * q_arith * + * (q_arith - 2) * (q_arith - 1) * (w_l + w_4 - w_l_shift + q_m) + * * @param evals transformed to `evals + C(extended_edges(X)...)*scaling_factor` * @param extended_edges an std::array containing the fully extended Univariate edges. * @param parameters contains beta, gamma, and public_input_delta, .... diff --git a/cpp/src/barretenberg/honk/sumcheck/relations/ultra_arithmetic_relation_secondary.hpp b/cpp/src/barretenberg/honk/sumcheck/relations/ultra_arithmetic_relation_secondary.hpp deleted file mode 100644 index 84bb0ce60c..0000000000 --- a/cpp/src/barretenberg/honk/sumcheck/relations/ultra_arithmetic_relation_secondary.hpp +++ /dev/null @@ -1,66 +0,0 @@ -#pragma once -#include -#include - -#include "../polynomials/univariate.hpp" -#include "relation.hpp" - -// TODO(luke): Move this into ultra_arithmetic_relation.hpp. -namespace proof_system::honk::sumcheck { - -template class UltraArithmeticRelationSecondary { - public: - // 1 + polynomial degree of this relation - static constexpr size_t RELATION_LENGTH = 5; // degree(q_arith^3 * w_l) = 4 - - /** - * @brief Expression for the Ultra Arithmetic gate. - * @details The relation is defined as C(extended_edges(X)...) = - * q_arith * - * (q_arith - 2) * (q_arith - 1) * (w_l + w_4 - w_l_shift + q_m) - * - * @param evals transformed to `evals + C(extended_edges(X)...)*scaling_factor` - * @param extended_edges an std::array containing the fully extended Univariate edges. - * @param parameters contains beta, gamma, and public_input_delta, .... - * @param scaling_factor optional term to scale the evaluation before adding to evals. - */ - void add_edge_contribution(Univariate& evals, - const auto& extended_edges, - const RelationParameters&, - const FF& scaling_factor) const - { - // OPTIMIZATION?: Karatsuba in general, at least for some degrees? - // See https://hackmd.io/xGLuj6biSsCjzQnYN-pEiA?both - - auto w_l = UnivariateView(extended_edges.w_l); - auto w_4 = UnivariateView(extended_edges.w_4); - auto w_l_shift = UnivariateView(extended_edges.w_l_shift); - auto q_m = UnivariateView(extended_edges.q_m); - auto q_arith = UnivariateView(extended_edges.q_arith); - - auto tmp = w_l + w_4 - w_l_shift + q_m; - tmp *= (q_arith - 2); - tmp *= (q_arith - 1); - tmp *= q_arith; - tmp *= scaling_factor; - evals += tmp; - }; - - void add_full_relation_value_contribution(FF& full_honk_relation_value, - const auto& purported_evaluations, - const RelationParameters&) const - { - auto w_l = purported_evaluations.w_l; - auto w_4 = purported_evaluations.w_4; - auto w_l_shift = purported_evaluations.w_l_shift; - auto q_m = purported_evaluations.q_m; - auto q_arith = purported_evaluations.q_arith; - - auto tmp = w_l + w_4 - w_l_shift + q_m; - tmp *= (q_arith - 2); - tmp *= (q_arith - 1); - tmp *= q_arith; - full_honk_relation_value += tmp; - }; -}; -} // namespace proof_system::honk::sumcheck diff --git a/cpp/src/barretenberg/honk/sumcheck/relations/ultra_relation_consistency.test.cpp b/cpp/src/barretenberg/honk/sumcheck/relations/ultra_relation_consistency.test.cpp index 1bdac16ad1..be50fe06e5 100644 --- a/cpp/src/barretenberg/honk/sumcheck/relations/ultra_relation_consistency.test.cpp +++ b/cpp/src/barretenberg/honk/sumcheck/relations/ultra_relation_consistency.test.cpp @@ -1,11 +1,11 @@ #include "barretenberg/honk/sumcheck/relations/ultra_arithmetic_relation.hpp" -#include "barretenberg/honk/sumcheck/relations/ultra_arithmetic_relation_secondary.hpp" +#include "barretenberg/honk/sumcheck/relations/permutation_relation.hpp" #include "barretenberg/honk/sumcheck/relations/lookup_relation.hpp" #include "barretenberg/honk/sumcheck/relations/gen_perm_sort_relation.hpp" #include "barretenberg/honk/sumcheck/relations/elliptic_relation.hpp" #include "barretenberg/honk/sumcheck/relations/auxiliary_relation.hpp" #include "barretenberg/honk/flavor/ultra.hpp" -#include "relation.hpp" +#include "relation_parameters.hpp" #include "arithmetic_relation.hpp" #include "permutation_relation.hpp" #include "../polynomials/univariate.hpp" @@ -178,49 +178,6 @@ class UltraRelationConsistency : public testing::Test { extend_tuple_of_arrays(tuple, result_univariates); } } - - // /** - // * @brief Compute the evaluation of a `relation` in different ways, comparing it to the provided `expected_evals` - // * - // * @details Check both `add_full_relation_value_contribution` and `add_edge_contribution` by comparing the result - // to - // * the `expected_evals` computed by the caller. - // * Ensures that the relations compute the same result as the expression given in the tests. - // * - // * @param expected_evals Relation evaluation computed by the caller. - // * @param relation being tested - // * @param extended_edges - // * @param relation_parameters - // */ - // template - // static void validate_evaluations(const Univariate& expected_evals, - // const auto relation, - // const ExtendedEdges& extended_edges, - // const RelationParameters& relation_parameters) - // { - - // // Compute the expression index-by-index - // Univariate expected_evals_index{ 0 }; - // for (size_t i = 0; i < FULL_RELATION_LENGTH; ++i) { - // // Get an array of the same size as `extended_edges` with only the i-th element of each extended edge. - // PurportedEvaluations evals_i = transposed_univariate_array_at(extended_edges, i); - // // Evaluate the relation - // relation.add_full_relation_value_contribution( - // expected_evals_index.value_at(i), evals_i, relation_parameters); - // } - // EXPECT_EQ(expected_evals, expected_evals_index); - - // // Compute the expression using the class, that converts the extended edges to UnivariateView - // auto expected_evals_view = Univariate(0); - // // The scaling factor is essentially 1 since we are working with degree 1 univariates - // relation.add_edge_contribution(expected_evals_view, extended_edges, relation_parameters, 1); - - // // Tiny hack to reduce `expected_evals` to be of size `relation.RELATION_LENGTH` - // Univariate expected_evals_restricted{ - // UnivariateView(expected_evals) - // }; - // EXPECT_EQ(expected_evals_restricted, expected_evals_view); - // }; }; TEST_F(UltraRelationConsistency, UltraArithmeticRelation) diff --git a/cpp/src/barretenberg/honk/sumcheck/sumcheck.hpp b/cpp/src/barretenberg/honk/sumcheck/sumcheck.hpp index 8968ee1260..2ab25cefc7 100644 --- a/cpp/src/barretenberg/honk/sumcheck/sumcheck.hpp +++ b/cpp/src/barretenberg/honk/sumcheck/sumcheck.hpp @@ -1,7 +1,7 @@ #pragma once #include "barretenberg/common/serialize.hpp" #include -#include "barretenberg/honk/sumcheck/relations/relation.hpp" +#include "barretenberg/honk/sumcheck/relations/relation_parameters.hpp" #include "barretenberg/honk/transcript/transcript.hpp" #include "barretenberg/honk/utils/grand_product_delta.hpp" #include "barretenberg/common/throw_or_abort.hpp" diff --git a/cpp/src/barretenberg/honk/sumcheck/sumcheck_round.hpp b/cpp/src/barretenberg/honk/sumcheck/sumcheck_round.hpp index c84557b8b8..f548f1b561 100644 --- a/cpp/src/barretenberg/honk/sumcheck/sumcheck_round.hpp +++ b/cpp/src/barretenberg/honk/sumcheck/sumcheck_round.hpp @@ -6,7 +6,7 @@ #include "polynomials/barycentric_data.hpp" #include "polynomials/univariate.hpp" #include "polynomials/pow.hpp" -#include "relations/relation.hpp" +#include "relations/relation_parameters.hpp" #include "barretenberg/honk/flavor/ultra.hpp" #include From eafe1ada322ecbc73f975170578b74787913e3ed Mon Sep 17 00:00:00 2001 From: ledwards2225 Date: Tue, 16 May 2023 22:12:06 +0000 Subject: [PATCH 10/18] reinstate ultra honk composer tests with all but aux relation --- .../composer/ultra_honk_composer.test.cpp | 1701 ++++++++--------- .../honk/proof_system/ultra_prover.cpp | 17 +- .../honk/proof_system/ultra_verifier.cpp | 19 +- .../ultra_relation_consistency.test.cpp | 54 +- 4 files changed, 892 insertions(+), 899 deletions(-) diff --git a/cpp/src/barretenberg/honk/composer/ultra_honk_composer.test.cpp b/cpp/src/barretenberg/honk/composer/ultra_honk_composer.test.cpp index 5ae7e2b338..fd096a74c1 100644 --- a/cpp/src/barretenberg/honk/composer/ultra_honk_composer.test.cpp +++ b/cpp/src/barretenberg/honk/composer/ultra_honk_composer.test.cpp @@ -1,799 +1,830 @@ -// #include "ultra_honk_composer.hpp" -// #include "barretenberg/common/log.hpp" -// #include "barretenberg/honk/proof_system/ultra_prover.hpp" -// #include "barretenberg/honk/sumcheck/relations/relation_parameters.hpp" -// #include "barretenberg/numeric/uint256/uint256.hpp" -// #include -// #include -// #include "barretenberg/honk/proof_system/prover.hpp" -// #include "barretenberg/honk/sumcheck/sumcheck_round.hpp" -// #include "barretenberg/honk/sumcheck/relations/permutation_relation.hpp" -// #include "barretenberg/honk/utils/grand_product_delta.hpp" -// #include "barretenberg/proof_system/plookup_tables/types.hpp" - -// #include -// #include -// #include - -// using namespace proof_system::honk; - -// namespace test_ultra_honk_composer { - -// namespace { -// auto& engine = numeric::random::get_debug_engine(); -// } - -// 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; -// } - -// bool construct_and_verify_proof(auto& composer) -// { -// auto prover = composer.create_prover(); -// auto proof = prover.construct_proof(); - -// auto verifier = composer.create_verifier(); -// bool result = verifier.verify_proof(proof); - -// return result; -// } - -// void prove_and_verify(auto& composer, bool expected_result) -// { -// auto prover = composer.create_prover(); -// auto verifier = composer.create_verifier(); -// auto proof = prover.construct_proof(); -// bool verified = verifier.verify_proof(proof); -// EXPECT_EQ(verified, expected_result); -// }; - -// void ensure_non_zero(auto& polynomial) -// { -// bool has_non_zero_coefficient = false; -// for (auto& coeff : polynomial) { -// has_non_zero_coefficient |= !coeff.is_zero(); -// } -// ASSERT_TRUE(has_non_zero_coefficient); -// } - -// /** -// * @brief A quick test to ensure that none of our polynomials are identically zero -// * -// * @note This test assumes that gates have been added by default in the circuit -// * constructor to achieve non-zero polynomials -// * -// */ -// TEST(UltraHonkComposer, ANonZeroPolynomialIsAGoodPolynomial) -// { -// auto composer = UltraHonkComposer(); - -// composer.add_gates_to_ensure_all_polys_are_non_zero(); - -// auto prover = composer.create_prover(); -// auto proof = prover.construct_proof(); - -// for (auto& poly : prover.key->get_selectors()) { -// ensure_non_zero(poly); -// } - -// for (auto& poly : prover.key->get_table_polynomials()) { -// ensure_non_zero(poly); -// } - -// for (auto& poly : prover.key->get_wires()) { -// ensure_non_zero(poly); -// } -// } - -// TEST(UltraHonkComposer, XorConstraint) -// { -// auto composer = UltraHonkComposer(); - -// uint32_t left_value = engine.get_random_uint32(); -// uint32_t right_value = engine.get_random_uint32(); - -// fr left_witness_value = fr{ left_value, 0, 0, 0 }.to_montgomery_form(); -// fr right_witness_value = fr{ right_value, 0, 0, 0 }.to_montgomery_form(); - -// uint32_t left_witness_index = composer.add_variable(left_witness_value); -// uint32_t right_witness_index = composer.add_variable(right_witness_value); - -// uint32_t xor_result_expected = left_value ^ right_value; - -// const auto lookup_accumulators = plookup::get_lookup_accumulators( -// plookup::MultiTableId::UINT32_XOR, left_witness_value, right_witness_value, true); -// auto xor_result = lookup_accumulators[plookup::ColumnIdx::C3] -// [0]; // The zeroth index in the 3rd column is the fully accumulated xor -// result -// EXPECT_EQ(xor_result, xor_result_expected); - -// composer.create_gates_from_plookup_accumulators( -// plookup::MultiTableId::UINT32_XOR, lookup_accumulators, left_witness_index, right_witness_index); - -// prove_and_verify(composer, /*expected_result=*/true); -// } - -// TEST(UltraHonkComposer, create_gates_from_plookup_accumulators) -// { -// auto composer = UltraHonkComposer(); - -// 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 = composer.add_variable(input_hi); -// const auto input_lo_index = 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 = composer.create_gates_from_plookup_accumulators( -// plookup::MultiTableId::PEDERSEN_LEFT_HI, sequence_data_hi, input_hi_index); -// const auto lookup_witnesses_lo = composer.create_gates_from_plookup_accumulators( -// plookup::MultiTableId::PEDERSEN_LEFT_LO, sequence_data_lo, input_lo_index); - -// std::vector expected_x; -// std::vector expected_y; - -// const size_t num_lookups_hi = -// (128 + crypto::pedersen_hash::lookup::BITS_PER_TABLE) / crypto::pedersen_hash::lookup::BITS_PER_TABLE; -// const size_t num_lookups_lo = 126 / crypto::pedersen_hash::lookup::BITS_PER_TABLE; -// const size_t num_lookups = num_lookups_hi + num_lookups_lo; - -// EXPECT_EQ(num_lookups_hi, lookup_witnesses_hi[plookup::ColumnIdx::C1].size()); -// EXPECT_EQ(num_lookups_lo, lookup_witnesses_lo[plookup::ColumnIdx::C1].size()); - -// std::vector expected_scalars; -// expected_x.resize(num_lookups); -// expected_y.resize(num_lookups); -// expected_scalars.resize(num_lookups); - -// { -// const size_t num_rounds = (num_lookups + 1) / 2; -// uint256_t bits(input_value); - -// const auto mask = crypto::pedersen_hash::lookup::PEDERSEN_TABLE_SIZE - 1; - -// for (size_t i = 0; i < num_rounds; ++i) { -// const auto& table = crypto::pedersen_hash::lookup::get_table(i); -// const size_t index = i * 2; - -// uint64_t slice_a = ((bits >> (index * 9)) & mask).data[0]; -// expected_x[index] = (table[(size_t)slice_a].x); -// expected_y[index] = (table[(size_t)slice_a].y); -// expected_scalars[index] = slice_a; - -// if (i < 14) { -// uint64_t slice_b = ((bits >> ((index + 1) * 9)) & mask).data[0]; -// expected_x[index + 1] = (table[(size_t)slice_b].x); -// expected_y[index + 1] = (table[(size_t)slice_b].y); -// expected_scalars[index + 1] = slice_b; -// } -// } -// } - -// for (size_t i = num_lookups - 2; i < num_lookups; --i) { -// expected_scalars[i] += (expected_scalars[i + 1] * crypto::pedersen_hash::lookup::PEDERSEN_TABLE_SIZE); -// } - -// size_t hi_shift = 126; -// const fr hi_cumulative = composer.get_variable(lookup_witnesses_hi[plookup::ColumnIdx::C1][0]); -// for (size_t i = 0; i < num_lookups_lo; ++i) { -// const fr hi_mult = fr(uint256_t(1) << hi_shift); -// EXPECT_EQ(composer.get_variable(lookup_witnesses_lo[plookup::ColumnIdx::C1][i]) + (hi_cumulative * hi_mult), -// expected_scalars[i]); -// EXPECT_EQ(composer.get_variable(lookup_witnesses_lo[plookup::ColumnIdx::C2][i]), expected_x[i]); -// EXPECT_EQ(composer.get_variable(lookup_witnesses_lo[plookup::ColumnIdx::C3][i]), expected_y[i]); -// hi_shift -= crypto::pedersen_hash::lookup::BITS_PER_TABLE; -// } - -// for (size_t i = 0; i < num_lookups_hi; ++i) { -// EXPECT_EQ(composer.get_variable(lookup_witnesses_hi[plookup::ColumnIdx::C1][i]), -// expected_scalars[i + num_lookups_lo]); -// EXPECT_EQ(composer.get_variable(lookup_witnesses_hi[plookup::ColumnIdx::C2][i]), -// expected_x[i + num_lookups_lo]); -// EXPECT_EQ(composer.get_variable(lookup_witnesses_hi[plookup::ColumnIdx::C3][i]), -// expected_y[i + num_lookups_lo]); -// } - -// auto prover = composer.create_prover(); -// auto verifier = composer.create_verifier(); -// auto proof = prover.construct_proof(); - -// bool result = verifier.verify_proof(proof); - -// EXPECT_EQ(result, true); -// } - -// TEST(UltraHonkComposer, test_no_lookup_proof) -// { -// auto composer = UltraHonkComposer(); - -// for (size_t i = 0; i < 16; ++i) { -// for (size_t j = 0; j < 16; ++j) { -// uint64_t left = static_cast(j); -// uint64_t right = static_cast(i); -// uint32_t left_idx = composer.add_variable(fr(left)); -// uint32_t right_idx = composer.add_variable(fr(right)); -// uint32_t result_idx = composer.add_variable(fr(left ^ right)); - -// uint32_t add_idx = composer.add_variable(fr(left) + fr(right) + composer.get_variable(result_idx)); -// composer.create_big_add_gate( -// { left_idx, right_idx, result_idx, add_idx, fr(1), fr(1), fr(1), fr(-1), fr(0) }); -// } -// } - -// prove_and_verify(composer, /*expected_result=*/true); -// } - -// TEST(UltraHonkComposer, test_elliptic_gate) +#include "ultra_honk_composer.hpp" +#include "barretenberg/common/log.hpp" +#include "barretenberg/honk/proof_system/ultra_prover.hpp" +#include "barretenberg/honk/sumcheck/relations/relation_parameters.hpp" +#include "barretenberg/numeric/uint256/uint256.hpp" +#include +#include +#include "barretenberg/honk/proof_system/prover.hpp" +#include "barretenberg/honk/sumcheck/sumcheck_round.hpp" +#include "barretenberg/honk/sumcheck/relations/permutation_relation.hpp" +#include "barretenberg/honk/utils/grand_product_delta.hpp" +#include "barretenberg/proof_system/plookup_tables/types.hpp" + +#include +#include +#include + +using namespace proof_system::honk; + +namespace test_ultra_honk_composer { + +namespace { +auto& engine = numeric::random::get_debug_engine(); +} + +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; +} + +bool construct_and_verify_proof(auto& composer) +{ + auto prover = composer.create_prover(); + auto proof = prover.construct_proof(); + + auto verifier = composer.create_verifier(); + bool result = verifier.verify_proof(proof); + + return result; +} + +void prove_and_verify(auto& composer, bool expected_result) +{ + auto prover = composer.create_prover(); + auto verifier = composer.create_verifier(); + auto proof = prover.construct_proof(); + bool verified = verifier.verify_proof(proof); + EXPECT_EQ(verified, expected_result); +}; + +void ensure_non_zero(auto& polynomial) +{ + bool has_non_zero_coefficient = false; + for (auto& coeff : polynomial) { + has_non_zero_coefficient |= !coeff.is_zero(); + } + ASSERT_TRUE(has_non_zero_coefficient); +} + +/** + * @brief A quick test to ensure that none of our polynomials are identically zero + * + * @note This test assumes that gates have been added by default in the circuit + * constructor to achieve non-zero polynomials + * + */ +TEST(UltraHonkComposer, ANonZeroPolynomialIsAGoodPolynomial) +{ + auto composer = UltraHonkComposer(); + + composer.add_gates_to_ensure_all_polys_are_non_zero(); + + auto prover = composer.create_prover(); + auto proof = prover.construct_proof(); + + for (auto& poly : prover.key->get_selectors()) { + ensure_non_zero(poly); + } + + for (auto& poly : prover.key->get_table_polynomials()) { + ensure_non_zero(poly); + } + + for (auto& poly : prover.key->get_wires()) { + ensure_non_zero(poly); + } +} + +TEST(UltraHonkComposer, XorConstraint) +{ + auto composer = UltraHonkComposer(); + + uint32_t left_value = engine.get_random_uint32(); + uint32_t right_value = engine.get_random_uint32(); + + fr left_witness_value = fr{ left_value, 0, 0, 0 }.to_montgomery_form(); + fr right_witness_value = fr{ right_value, 0, 0, 0 }.to_montgomery_form(); + + uint32_t left_witness_index = composer.add_variable(left_witness_value); + uint32_t right_witness_index = composer.add_variable(right_witness_value); + + uint32_t xor_result_expected = left_value ^ right_value; + + const auto lookup_accumulators = plookup::get_lookup_accumulators( + plookup::MultiTableId::UINT32_XOR, left_witness_value, right_witness_value, true); + auto xor_result = lookup_accumulators[plookup::ColumnIdx::C3] + [0]; // The zeroth index in the 3rd column is the fully accumulated xor result + EXPECT_EQ(xor_result, xor_result_expected); + + composer.create_gates_from_plookup_accumulators( + plookup::MultiTableId::UINT32_XOR, lookup_accumulators, left_witness_index, right_witness_index); + + prove_and_verify(composer, /*expected_result=*/true); +} + +TEST(UltraHonkComposer, create_gates_from_plookup_accumulators) +{ + auto composer = UltraHonkComposer(); + + 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 = composer.add_variable(input_hi); + const auto input_lo_index = 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 = composer.create_gates_from_plookup_accumulators( + plookup::MultiTableId::PEDERSEN_LEFT_HI, sequence_data_hi, input_hi_index); + const auto lookup_witnesses_lo = composer.create_gates_from_plookup_accumulators( + plookup::MultiTableId::PEDERSEN_LEFT_LO, sequence_data_lo, input_lo_index); + + std::vector expected_x; + std::vector expected_y; + + const size_t num_lookups_hi = + (128 + crypto::pedersen_hash::lookup::BITS_PER_TABLE) / crypto::pedersen_hash::lookup::BITS_PER_TABLE; + const size_t num_lookups_lo = 126 / crypto::pedersen_hash::lookup::BITS_PER_TABLE; + const size_t num_lookups = num_lookups_hi + num_lookups_lo; + + EXPECT_EQ(num_lookups_hi, lookup_witnesses_hi[plookup::ColumnIdx::C1].size()); + EXPECT_EQ(num_lookups_lo, lookup_witnesses_lo[plookup::ColumnIdx::C1].size()); + + std::vector expected_scalars; + expected_x.resize(num_lookups); + expected_y.resize(num_lookups); + expected_scalars.resize(num_lookups); + + { + const size_t num_rounds = (num_lookups + 1) / 2; + uint256_t bits(input_value); + + const auto mask = crypto::pedersen_hash::lookup::PEDERSEN_TABLE_SIZE - 1; + + for (size_t i = 0; i < num_rounds; ++i) { + const auto& table = crypto::pedersen_hash::lookup::get_table(i); + const size_t index = i * 2; + + uint64_t slice_a = ((bits >> (index * 9)) & mask).data[0]; + expected_x[index] = (table[(size_t)slice_a].x); + expected_y[index] = (table[(size_t)slice_a].y); + expected_scalars[index] = slice_a; + + if (i < 14) { + uint64_t slice_b = ((bits >> ((index + 1) * 9)) & mask).data[0]; + expected_x[index + 1] = (table[(size_t)slice_b].x); + expected_y[index + 1] = (table[(size_t)slice_b].y); + expected_scalars[index + 1] = slice_b; + } + } + } + + for (size_t i = num_lookups - 2; i < num_lookups; --i) { + expected_scalars[i] += (expected_scalars[i + 1] * crypto::pedersen_hash::lookup::PEDERSEN_TABLE_SIZE); + } + + size_t hi_shift = 126; + const fr hi_cumulative = composer.get_variable(lookup_witnesses_hi[plookup::ColumnIdx::C1][0]); + for (size_t i = 0; i < num_lookups_lo; ++i) { + const fr hi_mult = fr(uint256_t(1) << hi_shift); + EXPECT_EQ(composer.get_variable(lookup_witnesses_lo[plookup::ColumnIdx::C1][i]) + (hi_cumulative * hi_mult), + expected_scalars[i]); + EXPECT_EQ(composer.get_variable(lookup_witnesses_lo[plookup::ColumnIdx::C2][i]), expected_x[i]); + EXPECT_EQ(composer.get_variable(lookup_witnesses_lo[plookup::ColumnIdx::C3][i]), expected_y[i]); + hi_shift -= crypto::pedersen_hash::lookup::BITS_PER_TABLE; + } + + for (size_t i = 0; i < num_lookups_hi; ++i) { + EXPECT_EQ(composer.get_variable(lookup_witnesses_hi[plookup::ColumnIdx::C1][i]), + expected_scalars[i + num_lookups_lo]); + EXPECT_EQ(composer.get_variable(lookup_witnesses_hi[plookup::ColumnIdx::C2][i]), + expected_x[i + num_lookups_lo]); + EXPECT_EQ(composer.get_variable(lookup_witnesses_hi[plookup::ColumnIdx::C3][i]), + expected_y[i + num_lookups_lo]); + } + + auto prover = composer.create_prover(); + auto verifier = composer.create_verifier(); + auto proof = prover.construct_proof(); + + bool result = verifier.verify_proof(proof); + + EXPECT_EQ(result, true); +} + +TEST(UltraHonkComposer, test_no_lookup_proof) +{ + auto composer = UltraHonkComposer(); + + for (size_t i = 0; i < 16; ++i) { + for (size_t j = 0; j < 16; ++j) { + uint64_t left = static_cast(j); + uint64_t right = static_cast(i); + uint32_t left_idx = composer.add_variable(fr(left)); + uint32_t right_idx = composer.add_variable(fr(right)); + uint32_t result_idx = composer.add_variable(fr(left ^ right)); + + uint32_t add_idx = composer.add_variable(fr(left) + fr(right) + composer.get_variable(result_idx)); + composer.create_big_add_gate( + { left_idx, right_idx, result_idx, add_idx, fr(1), fr(1), fr(1), fr(-1), fr(0) }); + } + } + + prove_and_verify(composer, /*expected_result=*/true); +} + +TEST(UltraHonkComposer, test_elliptic_gate) +{ + typedef grumpkin::g1::affine_element affine_element; + typedef grumpkin::g1::element element; + auto composer = UltraHonkComposer(); + + 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 = composer.add_variable(p1.x); + uint32_t y1 = composer.add_variable(p1.y); + uint32_t x2 = composer.add_variable(p2.x); + uint32_t y2 = composer.add_variable(p2.y); + uint32_t x3 = composer.add_variable(p3.x); + uint32_t y3 = composer.add_variable(p3.y); + + ecc_add_gate gate{ x1, y1, x2, y2, x3, y3, 1, 1 }; + 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 = composer.add_variable(p3.x); + y3 = composer.add_variable(p3.y); + gate = ecc_add_gate{ x1, y1, x2, y2, x3, y3, beta, 1 }; + composer.create_ecc_add_gate(gate); + + p2_endo.x *= beta; + p3 = affine_element(element(p1) - element(p2_endo)); + x3 = composer.add_variable(p3.x); + y3 = composer.add_variable(p3.y); + gate = ecc_add_gate{ x1, y1, x2, y2, x3, y3, beta.sqr(), -1 }; + composer.create_ecc_add_gate(gate); + + prove_and_verify(composer, /*expected_result=*/true); +} + +TEST(UltraHonkComposer, non_trivial_tag_permutation) +{ + auto composer = UltraHonkComposer(); + fr a = fr::random_element(); + fr b = -a; + + auto a_idx = composer.add_variable(a); + auto b_idx = composer.add_variable(b); + auto c_idx = composer.add_variable(b); + auto d_idx = composer.add_variable(a); + + composer.create_add_gate({ a_idx, b_idx, composer.get_zero_idx(), fr::one(), fr::one(), fr::zero(), fr::zero() }); + composer.create_add_gate({ c_idx, d_idx, composer.get_zero_idx(), fr::one(), fr::one(), fr::zero(), fr::zero() }); + + composer.create_tag(1, 2); + composer.create_tag(2, 1); + + composer.assign_tag(a_idx, 1); + composer.assign_tag(b_idx, 1); + composer.assign_tag(c_idx, 2); + composer.assign_tag(d_idx, 2); + + prove_and_verify(composer, /*expected_result=*/true); +} + +TEST(UltraHonkComposer, non_trivial_tag_permutation_and_cycles) +{ + auto composer = UltraHonkComposer(); + fr a = fr::random_element(); + fr c = -a; + + auto a_idx = composer.add_variable(a); + auto b_idx = composer.add_variable(a); + composer.assert_equal(a_idx, b_idx); + auto c_idx = composer.add_variable(c); + auto d_idx = composer.add_variable(c); + composer.assert_equal(c_idx, d_idx); + auto e_idx = composer.add_variable(a); + auto f_idx = composer.add_variable(a); + composer.assert_equal(e_idx, f_idx); + auto g_idx = composer.add_variable(c); + auto h_idx = composer.add_variable(c); + composer.assert_equal(g_idx, h_idx); + + composer.create_tag(1, 2); + composer.create_tag(2, 1); + + composer.assign_tag(a_idx, 1); + composer.assign_tag(c_idx, 1); + composer.assign_tag(e_idx, 2); + composer.assign_tag(g_idx, 2); + + composer.create_add_gate( + { b_idx, a_idx, composer.get_zero_idx(), fr::one(), fr::neg_one(), fr::zero(), fr::zero() }); + composer.create_add_gate({ c_idx, g_idx, composer.get_zero_idx(), fr::one(), -fr::one(), fr::zero(), fr::zero() }); + composer.create_add_gate({ e_idx, f_idx, composer.get_zero_idx(), fr::one(), -fr::one(), fr::zero(), fr::zero() }); + + prove_and_verify(composer, /*expected_result=*/true); +} + +TEST(UltraHonkComposer, bad_tag_permutation) +{ + auto composer = UltraHonkComposer(); + fr a = fr::random_element(); + fr b = -a; + + auto a_idx = composer.add_variable(a); + auto b_idx = composer.add_variable(b); + auto c_idx = composer.add_variable(b); + auto d_idx = composer.add_variable(a + 1); + + composer.create_add_gate({ a_idx, b_idx, composer.get_zero_idx(), 1, 1, 0, 0 }); + composer.create_add_gate({ c_idx, d_idx, composer.get_zero_idx(), 1, 1, 0, -1 }); + + composer.create_tag(1, 2); + composer.create_tag(2, 1); + + composer.assign_tag(a_idx, 1); + composer.assign_tag(b_idx, 1); + composer.assign_tag(c_idx, 2); + composer.assign_tag(d_idx, 2); + + prove_and_verify(composer, /*expected_result=*/false); +} + +// same as above but with turbocomposer to check reason of failue is really tag mismatch +TEST(UltraHonkComposer, bad_tag_turbo_permutation) +{ + auto composer = UltraHonkComposer(); + fr a = fr::random_element(); + fr b = -a; + + auto a_idx = composer.add_variable(a); + auto b_idx = composer.add_variable(b); + auto c_idx = composer.add_variable(b); + auto d_idx = composer.add_variable(a + 1); + + composer.create_add_gate({ a_idx, b_idx, composer.get_zero_idx(), 1, 1, 0, 0 }); + composer.create_add_gate({ c_idx, d_idx, composer.get_zero_idx(), 1, 1, 0, -1 }); + + // composer.create_add_gate({ a_idx, b_idx, composer.get_zero_idx(), fr::one(), fr::neg_one(), fr::zero(), + // fr::zero() }); composer.create_add_gate({ a_idx, b_idx, composer.get_zero_idx(), fr::one(), fr::neg_one(), + // fr::zero(), fr::zero() }); composer.create_add_gate({ a_idx, b_idx, composer.get_zero_idx(), fr::one(), + // fr::neg_one(), fr::zero(), fr::zero() }); + auto prover = composer.create_prover(); + auto verifier = composer.create_verifier(); + + prove_and_verify(composer, /*expected_result=*/true); +} + +TEST(UltraHonkComposer, sort_widget) +{ + auto composer = UltraHonkComposer(); + fr a = fr::one(); + fr b = fr(2); + fr c = fr(3); + fr d = fr(4); + + auto a_idx = composer.add_variable(a); + auto b_idx = composer.add_variable(b); + auto c_idx = composer.add_variable(c); + auto d_idx = composer.add_variable(d); + composer.create_sort_constraint({ a_idx, b_idx, c_idx, d_idx }); + + prove_and_verify(composer, /*expected_result=*/true); +} + +TEST(UltraHonkComposer, sort_with_edges_gate) +{ + + fr a = fr::one(); + fr b = fr(2); + fr c = fr(3); + fr d = fr(4); + fr e = fr(5); + fr f = fr(6); + fr g = fr(7); + fr h = fr(8); + + { + auto composer = UltraHonkComposer(); + auto a_idx = composer.add_variable(a); + auto b_idx = composer.add_variable(b); + auto c_idx = composer.add_variable(c); + auto d_idx = composer.add_variable(d); + auto e_idx = composer.add_variable(e); + auto f_idx = composer.add_variable(f); + auto g_idx = composer.add_variable(g); + auto h_idx = composer.add_variable(h); + composer.create_sort_constraint_with_edges({ a_idx, b_idx, c_idx, d_idx, e_idx, f_idx, g_idx, h_idx }, a, h); + + prove_and_verify(composer, /*expected_result=*/true); + } + + { + auto composer = UltraHonkComposer(); + auto a_idx = composer.add_variable(a); + auto b_idx = composer.add_variable(b); + auto c_idx = composer.add_variable(c); + auto d_idx = composer.add_variable(d); + auto e_idx = composer.add_variable(e); + auto f_idx = composer.add_variable(f); + auto g_idx = composer.add_variable(g); + auto h_idx = composer.add_variable(h); + composer.create_sort_constraint_with_edges({ a_idx, b_idx, c_idx, d_idx, e_idx, f_idx, g_idx, h_idx }, a, g); + + prove_and_verify(composer, /*expected_result=*/false); + } + { + auto composer = UltraHonkComposer(); + auto a_idx = composer.add_variable(a); + auto b_idx = composer.add_variable(b); + auto c_idx = composer.add_variable(c); + auto d_idx = composer.add_variable(d); + auto e_idx = composer.add_variable(e); + auto f_idx = composer.add_variable(f); + auto g_idx = composer.add_variable(g); + auto h_idx = composer.add_variable(h); + composer.create_sort_constraint_with_edges({ a_idx, b_idx, c_idx, d_idx, e_idx, f_idx, g_idx, h_idx }, b, h); + + prove_and_verify(composer, /*expected_result=*/false); + } + { + auto composer = UltraHonkComposer(); + auto a_idx = composer.add_variable(a); + auto c_idx = composer.add_variable(c); + auto d_idx = composer.add_variable(d); + auto e_idx = composer.add_variable(e); + auto f_idx = composer.add_variable(f); + auto g_idx = composer.add_variable(g); + auto h_idx = composer.add_variable(h); + auto b2_idx = composer.add_variable(fr(15)); + composer.create_sort_constraint_with_edges({ a_idx, b2_idx, c_idx, d_idx, e_idx, f_idx, g_idx, h_idx }, b, h); + + prove_and_verify(composer, /*expected_result=*/false); + } + { + auto composer = UltraHonkComposer(); + auto idx = add_variables(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 }); + composer.create_sort_constraint_with_edges(idx, 1, 45); + + prove_and_verify(composer, /*expected_result=*/true); + } + { + auto composer = UltraHonkComposer(); + auto idx = add_variables(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 }); + + composer.create_sort_constraint_with_edges(idx, 1, 29); + + prove_and_verify(composer, /*expected_result=*/false); + } +} + +TEST(UltraHonkComposer, range_constraint) +{ + { + auto composer = UltraHonkComposer(); + auto indices = add_variables(composer, { 1, 2, 3, 4, 5, 6, 7, 8 }); + for (size_t i = 0; i < indices.size(); i++) { + composer.create_new_range_constraint(indices[i], 8); + } + // auto ind = {a_idx,b_idx,c_idx,d_idx,e_idx,f_idx,g_idx,h_idx}; + composer.create_sort_constraint(indices); + + prove_and_verify(composer, /*expected_result=*/true); + } + { + auto composer = UltraHonkComposer(); + auto indices = add_variables(composer, { 3 }); + for (size_t i = 0; i < indices.size(); i++) { + composer.create_new_range_constraint(indices[i], 3); + } + // auto ind = {a_idx,b_idx,c_idx,d_idx,e_idx,f_idx,g_idx,h_idx}; + composer.create_dummy_constraints(indices); + + prove_and_verify(composer, /*expected_result=*/true); + } + { + auto composer = UltraHonkComposer(); + auto indices = add_variables(composer, { 1, 2, 3, 4, 5, 6, 8, 25 }); + for (size_t i = 0; i < indices.size(); i++) { + composer.create_new_range_constraint(indices[i], 8); + } + composer.create_sort_constraint(indices); + + prove_and_verify(composer, /*expected_result=*/false); + } + { + auto composer = UltraHonkComposer(); + auto indices = + add_variables(composer, { 1, 2, 3, 4, 5, 6, 10, 8, 15, 11, 32, 21, 42, 79, 16, 10, 3, 26, 19, 51 }); + for (size_t i = 0; i < indices.size(); i++) { + composer.create_new_range_constraint(indices[i], 128); + } + composer.create_dummy_constraints(indices); + + prove_and_verify(composer, /*expected_result=*/true); + } + { + auto composer = UltraHonkComposer(); + auto indices = + add_variables(composer, { 1, 2, 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++) { + composer.create_new_range_constraint(indices[i], 79); + } + composer.create_dummy_constraints(indices); + + prove_and_verify(composer, /*expected_result=*/false); + } + { + auto composer = UltraHonkComposer(); + auto indices = + add_variables(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++) { + composer.create_new_range_constraint(indices[i], 79); + } + composer.create_dummy_constraints(indices); + + prove_and_verify(composer, /*expected_result=*/false); + } +} + +TEST(UltraHonkComposer, range_with_gates) +{ + + auto composer = UltraHonkComposer(); + auto idx = add_variables(composer, { 1, 2, 3, 4, 5, 6, 7, 8 }); + for (size_t i = 0; i < idx.size(); i++) { + composer.create_new_range_constraint(idx[i], 8); + } + + composer.create_add_gate({ idx[0], idx[1], composer.get_zero_idx(), fr::one(), fr::one(), fr::zero(), -3 }); + composer.create_add_gate({ idx[2], idx[3], composer.get_zero_idx(), fr::one(), fr::one(), fr::zero(), -7 }); + composer.create_add_gate({ idx[4], idx[5], composer.get_zero_idx(), fr::one(), fr::one(), fr::zero(), -11 }); + composer.create_add_gate({ idx[6], idx[7], composer.get_zero_idx(), fr::one(), fr::one(), fr::zero(), -15 }); + + prove_and_verify(composer, /*expected_result=*/true); +} + +TEST(UltraHonkComposer, range_with_gates_where_range_is_not_a_power_of_two) +{ + auto composer = UltraHonkComposer(); + auto idx = add_variables(composer, { 1, 2, 3, 4, 5, 6, 7, 8 }); + for (size_t i = 0; i < idx.size(); i++) { + composer.create_new_range_constraint(idx[i], 12); + } + + composer.create_add_gate({ idx[0], idx[1], composer.get_zero_idx(), fr::one(), fr::one(), fr::zero(), -3 }); + composer.create_add_gate({ idx[2], idx[3], composer.get_zero_idx(), fr::one(), fr::one(), fr::zero(), -7 }); + composer.create_add_gate({ idx[4], idx[5], composer.get_zero_idx(), fr::one(), fr::one(), fr::zero(), -11 }); + composer.create_add_gate({ idx[6], idx[7], composer.get_zero_idx(), fr::one(), fr::one(), fr::zero(), -15 }); + + prove_and_verify(composer, /*expected_result=*/true); +} + +TEST(UltraHonkComposer, sort_widget_complex) +{ + { + + auto composer = UltraHonkComposer(); + std::vector a = { 1, 3, 4, 7, 7, 8, 11, 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(composer.add_variable(a[i])); + composer.create_sort_constraint(ind); + + prove_and_verify(composer, /*expected_result=*/true); + } + { + + auto composer = UltraHonkComposer(); + 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(composer.add_variable(a[i])); + composer.create_sort_constraint(ind); + + prove_and_verify(composer, /*expected_result=*/false); + } +} + +TEST(UltraHonkComposer, sort_widget_neg) +{ + auto composer = UltraHonkComposer(); + fr a = fr::one(); + fr b = fr(2); + fr c = fr(3); + fr d = fr(8); + + auto a_idx = composer.add_variable(a); + auto b_idx = composer.add_variable(b); + auto c_idx = composer.add_variable(c); + auto d_idx = composer.add_variable(d); + composer.create_sort_constraint({ a_idx, b_idx, c_idx, d_idx }); + + prove_and_verify(composer, /*expected_result=*/false); +} + +TEST(UltraHonkComposer, composed_range_constraint) +{ + auto composer = UltraHonkComposer(); + auto c = fr::random_element(); + auto d = uint256_t(c).slice(0, 133); + auto e = fr(d); + auto a_idx = composer.add_variable(fr(e)); + composer.create_add_gate({ a_idx, composer.get_zero_idx(), composer.get_zero_idx(), 1, 0, 0, -fr(e) }); + composer.decompose_into_default_range(a_idx, 134); + + prove_and_verify(composer, /*expected_result=*/true); +} + +TEST(UltraHonkComposer, non_native_field_multiplication) +{ + auto composer = UltraHonkComposer(); + + 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] = composer.add_variable(limbs[0]); + limb_indices[1] = composer.add_variable(limbs[1]); + limb_indices[2] = composer.add_variable(limbs[2]); + limb_indices[3] = composer.add_variable(limbs[3]); + limb_indices[4] = 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::UltraCircuitConstructor::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] = composer.queue_non_native_field_multiplication(inputs); + composer.range_constrain_two_limbs(lo_1_idx, hi_1_idx, 70, 70); + + prove_and_verify(composer, /*expected_result=*/true); +} + +TEST(UltraHonkComposer, rom) +{ + auto composer = UltraHonkComposer(); + + uint32_t rom_values[8]{ + composer.add_variable(fr::random_element()), composer.add_variable(fr::random_element()), + composer.add_variable(fr::random_element()), composer.add_variable(fr::random_element()), + composer.add_variable(fr::random_element()), composer.add_variable(fr::random_element()), + composer.add_variable(fr::random_element()), composer.add_variable(fr::random_element()), + }; + + size_t rom_id = composer.create_ROM_array(8); + + for (size_t i = 0; i < 8; ++i) { + composer.set_ROM_element(rom_id, i, rom_values[i]); + } + + uint32_t a_idx = composer.read_ROM_array(rom_id, composer.add_variable(5)); + EXPECT_EQ(a_idx != rom_values[5], true); + uint32_t b_idx = composer.read_ROM_array(rom_id, composer.add_variable(4)); + uint32_t c_idx = composer.read_ROM_array(rom_id, composer.add_variable(1)); + + const auto d_value = composer.get_variable(a_idx) + composer.get_variable(b_idx) + composer.get_variable(c_idx); + uint32_t d_idx = composer.add_variable(d_value); + + composer.create_big_add_gate({ + a_idx, + b_idx, + c_idx, + d_idx, + 1, + 1, + 1, + -1, + 0, + }); + + prove_and_verify(composer, /*expected_result=*/true); +} + +TEST(UltraHonkComposer, ram) +{ + auto composer = UltraHonkComposer(); + + uint32_t ram_values[8]{ + composer.add_variable(fr::random_element()), composer.add_variable(fr::random_element()), + composer.add_variable(fr::random_element()), composer.add_variable(fr::random_element()), + composer.add_variable(fr::random_element()), composer.add_variable(fr::random_element()), + composer.add_variable(fr::random_element()), composer.add_variable(fr::random_element()), + }; + + size_t ram_id = composer.create_RAM_array(8); + + for (size_t i = 0; i < 8; ++i) { + composer.init_RAM_element(ram_id, i, ram_values[i]); + } + + uint32_t a_idx = composer.read_RAM_array(ram_id, composer.add_variable(5)); + EXPECT_EQ(a_idx != ram_values[5], true); + + uint32_t b_idx = composer.read_RAM_array(ram_id, composer.add_variable(4)); + uint32_t c_idx = composer.read_RAM_array(ram_id, composer.add_variable(1)); + + composer.write_RAM_array(ram_id, composer.add_variable(4), composer.add_variable(500)); + uint32_t d_idx = composer.read_RAM_array(ram_id, composer.add_variable(4)); + + EXPECT_EQ(composer.get_variable(d_idx), 500); + + // ensure these vars get used in another arithmetic gate + const auto e_value = composer.get_variable(a_idx) + composer.get_variable(b_idx) + composer.get_variable(c_idx) + + composer.get_variable(d_idx); + uint32_t e_idx = composer.add_variable(e_value); + + composer.create_big_add_gate( + { + a_idx, + b_idx, + c_idx, + d_idx, + -1, + -1, + -1, + -1, + 0, + }, + true); + composer.create_big_add_gate( + { + composer.get_zero_idx(), + composer.get_zero_idx(), + composer.get_zero_idx(), + e_idx, + 0, + 0, + 0, + 0, + 0, + }, + false); + + prove_and_verify(composer, /*expected_result=*/true); +} + +// TODO(#378)(luke): this is a recent update from Zac and fails; do we need a corresponding bug fix in ultra circuit +// constructor? TEST(UltraHonkComposer, range_checks_on_duplicates) // { -// typedef grumpkin::g1::affine_element affine_element; -// typedef grumpkin::g1::element element; // auto composer = UltraHonkComposer(); -// 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 = composer.add_variable(p1.x); -// uint32_t y1 = composer.add_variable(p1.y); -// uint32_t x2 = composer.add_variable(p2.x); -// uint32_t y2 = composer.add_variable(p2.y); -// uint32_t x3 = composer.add_variable(p3.x); -// uint32_t y3 = composer.add_variable(p3.y); - -// ecc_add_gate gate{ x1, y1, x2, y2, x3, y3, 1, 1 }; -// 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 = composer.add_variable(p3.x); -// y3 = composer.add_variable(p3.y); -// gate = ecc_add_gate{ x1, y1, x2, y2, x3, y3, beta, 1 }; -// composer.create_ecc_add_gate(gate); - -// p2_endo.x *= beta; -// p3 = affine_element(element(p1) - element(p2_endo)); -// x3 = composer.add_variable(p3.x); -// y3 = composer.add_variable(p3.y); -// gate = ecc_add_gate{ x1, y1, x2, y2, x3, y3, beta.sqr(), -1 }; -// composer.create_ecc_add_gate(gate); - -// prove_and_verify(composer, /*expected_result=*/true); -// } +// uint32_t a = composer.add_variable(100); +// uint32_t b = composer.add_variable(100); +// uint32_t c = composer.add_variable(100); +// uint32_t d = composer.add_variable(100); -// TEST(UltraHonkComposer, non_trivial_tag_permutation) -// { -// auto composer = UltraHonkComposer(); -// fr a = fr::random_element(); -// fr b = -a; +// composer.assert_equal(a, b); +// composer.assert_equal(a, c); +// composer.assert_equal(a, d); -// auto a_idx = composer.add_variable(a); -// auto b_idx = composer.add_variable(b); -// auto c_idx = composer.add_variable(b); -// auto d_idx = composer.add_variable(a); - -// composer.create_add_gate({ a_idx, b_idx, composer.get_zero_idx(), fr::one(), fr::one(), fr::zero(), fr::zero() -// }); composer.create_add_gate({ c_idx, d_idx, composer.get_zero_idx(), fr::one(), fr::one(), fr::zero(), -// fr::zero() }); - -// composer.create_tag(1, 2); -// composer.create_tag(2, 1); - -// composer.assign_tag(a_idx, 1); -// composer.assign_tag(b_idx, 1); -// composer.assign_tag(c_idx, 2); -// composer.assign_tag(d_idx, 2); - -// prove_and_verify(composer, /*expected_result=*/true); -// } - -// TEST(UltraHonkComposer, non_trivial_tag_permutation_and_cycles) -// { -// auto composer = UltraHonkComposer(); -// fr a = fr::random_element(); -// fr c = -a; - -// auto a_idx = composer.add_variable(a); -// auto b_idx = composer.add_variable(a); -// composer.assert_equal(a_idx, b_idx); -// auto c_idx = composer.add_variable(c); -// auto d_idx = composer.add_variable(c); -// composer.assert_equal(c_idx, d_idx); -// auto e_idx = composer.add_variable(a); -// auto f_idx = composer.add_variable(a); -// composer.assert_equal(e_idx, f_idx); -// auto g_idx = composer.add_variable(c); -// auto h_idx = composer.add_variable(c); -// composer.assert_equal(g_idx, h_idx); - -// composer.create_tag(1, 2); -// composer.create_tag(2, 1); - -// composer.assign_tag(a_idx, 1); -// composer.assign_tag(c_idx, 1); -// composer.assign_tag(e_idx, 2); -// composer.assign_tag(g_idx, 2); - -// composer.create_add_gate( -// { b_idx, a_idx, composer.get_zero_idx(), fr::one(), fr::neg_one(), fr::zero(), fr::zero() }); -// composer.create_add_gate({ c_idx, g_idx, composer.get_zero_idx(), fr::one(), -fr::one(), fr::zero(), fr::zero() -// }); composer.create_add_gate({ e_idx, f_idx, composer.get_zero_idx(), fr::one(), -fr::one(), fr::zero(), -// fr::zero() }); - -// prove_and_verify(composer, /*expected_result=*/true); -// } - -// TEST(UltraHonkComposer, bad_tag_permutation) -// { -// auto composer = UltraHonkComposer(); -// fr a = fr::random_element(); -// fr b = -a; - -// auto a_idx = composer.add_variable(a); -// auto b_idx = composer.add_variable(b); -// auto c_idx = composer.add_variable(b); -// auto d_idx = composer.add_variable(a + 1); - -// composer.create_add_gate({ a_idx, b_idx, composer.get_zero_idx(), 1, 1, 0, 0 }); -// composer.create_add_gate({ c_idx, d_idx, composer.get_zero_idx(), 1, 1, 0, -1 }); - -// composer.create_tag(1, 2); -// composer.create_tag(2, 1); - -// composer.assign_tag(a_idx, 1); -// composer.assign_tag(b_idx, 1); -// composer.assign_tag(c_idx, 2); -// composer.assign_tag(d_idx, 2); - -// prove_and_verify(composer, /*expected_result=*/false); -// } +// composer.create_new_range_constraint(a, 1000); +// composer.create_new_range_constraint(b, 1001); +// composer.create_new_range_constraint(c, 999); +// composer.create_new_range_constraint(d, 1000); -// // same as above but with turbocomposer to check reason of failue is really tag mismatch -// TEST(UltraHonkComposer, bad_tag_turbo_permutation) -// { -// auto composer = UltraHonkComposer(); -// fr a = fr::random_element(); -// fr b = -a; - -// auto a_idx = composer.add_variable(a); -// auto b_idx = composer.add_variable(b); -// auto c_idx = composer.add_variable(b); -// auto d_idx = composer.add_variable(a + 1); - -// composer.create_add_gate({ a_idx, b_idx, composer.get_zero_idx(), 1, 1, 0, 0 }); -// composer.create_add_gate({ c_idx, d_idx, composer.get_zero_idx(), 1, 1, 0, -1 }); - -// // composer.create_add_gate({ a_idx, b_idx, composer.get_zero_idx(), fr::one(), fr::neg_one(), fr::zero(), -// // fr::zero() }); composer.create_add_gate({ a_idx, b_idx, composer.get_zero_idx(), fr::one(), fr::neg_one(), -// // fr::zero(), fr::zero() }); composer.create_add_gate({ a_idx, b_idx, composer.get_zero_idx(), fr::one(), -// // fr::neg_one(), fr::zero(), fr::zero() }); -// auto prover = composer.create_prover(); -// auto verifier = composer.create_verifier(); - -// prove_and_verify(composer, /*expected_result=*/true); -// } - -// TEST(UltraHonkComposer, sort_widget) -// { -// auto composer = UltraHonkComposer(); -// fr a = fr::one(); -// fr b = fr(2); -// fr c = fr(3); -// fr d = fr(4); - -// auto a_idx = composer.add_variable(a); -// auto b_idx = composer.add_variable(b); -// auto c_idx = composer.add_variable(c); -// auto d_idx = composer.add_variable(d); -// composer.create_sort_constraint({ a_idx, b_idx, c_idx, d_idx }); - -// prove_and_verify(composer, /*expected_result=*/true); -// } - -// TEST(UltraHonkComposer, sort_with_edges_gate) -// { - -// fr a = fr::one(); -// fr b = fr(2); -// fr c = fr(3); -// fr d = fr(4); -// fr e = fr(5); -// fr f = fr(6); -// fr g = fr(7); -// fr h = fr(8); - -// { -// auto composer = UltraHonkComposer(); -// auto a_idx = composer.add_variable(a); -// auto b_idx = composer.add_variable(b); -// auto c_idx = composer.add_variable(c); -// auto d_idx = composer.add_variable(d); -// auto e_idx = composer.add_variable(e); -// auto f_idx = composer.add_variable(f); -// auto g_idx = composer.add_variable(g); -// auto h_idx = composer.add_variable(h); -// composer.create_sort_constraint_with_edges({ a_idx, b_idx, c_idx, d_idx, e_idx, f_idx, g_idx, h_idx }, a, h); - -// prove_and_verify(composer, /*expected_result=*/true); -// } - -// { -// auto composer = UltraHonkComposer(); -// auto a_idx = composer.add_variable(a); -// auto b_idx = composer.add_variable(b); -// auto c_idx = composer.add_variable(c); -// auto d_idx = composer.add_variable(d); -// auto e_idx = composer.add_variable(e); -// auto f_idx = composer.add_variable(f); -// auto g_idx = composer.add_variable(g); -// auto h_idx = composer.add_variable(h); -// composer.create_sort_constraint_with_edges({ a_idx, b_idx, c_idx, d_idx, e_idx, f_idx, g_idx, h_idx }, a, g); - -// prove_and_verify(composer, /*expected_result=*/false); -// } -// { -// auto composer = UltraHonkComposer(); -// auto a_idx = composer.add_variable(a); -// auto b_idx = composer.add_variable(b); -// auto c_idx = composer.add_variable(c); -// auto d_idx = composer.add_variable(d); -// auto e_idx = composer.add_variable(e); -// auto f_idx = composer.add_variable(f); -// auto g_idx = composer.add_variable(g); -// auto h_idx = composer.add_variable(h); -// composer.create_sort_constraint_with_edges({ a_idx, b_idx, c_idx, d_idx, e_idx, f_idx, g_idx, h_idx }, b, h); - -// prove_and_verify(composer, /*expected_result=*/false); -// } -// { -// auto composer = UltraHonkComposer(); -// auto a_idx = composer.add_variable(a); -// auto c_idx = composer.add_variable(c); -// auto d_idx = composer.add_variable(d); -// auto e_idx = composer.add_variable(e); -// auto f_idx = composer.add_variable(f); -// auto g_idx = composer.add_variable(g); -// auto h_idx = composer.add_variable(h); -// auto b2_idx = composer.add_variable(fr(15)); -// composer.create_sort_constraint_with_edges({ a_idx, b2_idx, c_idx, d_idx, e_idx, f_idx, g_idx, h_idx }, b, -// h); - -// prove_and_verify(composer, /*expected_result=*/false); -// } -// { -// auto composer = UltraHonkComposer(); -// auto idx = add_variables(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 }); -// composer.create_sort_constraint_with_edges(idx, 1, 45); - -// prove_and_verify(composer, /*expected_result=*/true); -// } -// { -// auto composer = UltraHonkComposer(); -// auto idx = add_variables(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 }); - -// composer.create_sort_constraint_with_edges(idx, 1, 29); - -// prove_and_verify(composer, /*expected_result=*/false); -// } -// } - -// TEST(UltraHonkComposer, range_constraint) -// { -// { -// auto composer = UltraHonkComposer(); -// auto indices = add_variables(composer, { 1, 2, 3, 4, 5, 6, 7, 8 }); -// for (size_t i = 0; i < indices.size(); i++) { -// composer.create_new_range_constraint(indices[i], 8); -// } -// // auto ind = {a_idx,b_idx,c_idx,d_idx,e_idx,f_idx,g_idx,h_idx}; -// composer.create_sort_constraint(indices); - -// prove_and_verify(composer, /*expected_result=*/true); -// } -// { -// auto composer = UltraHonkComposer(); -// auto indices = add_variables(composer, { 3 }); -// for (size_t i = 0; i < indices.size(); i++) { -// composer.create_new_range_constraint(indices[i], 3); -// } -// // auto ind = {a_idx,b_idx,c_idx,d_idx,e_idx,f_idx,g_idx,h_idx}; -// composer.create_dummy_constraints(indices); - -// prove_and_verify(composer, /*expected_result=*/true); -// } -// { -// auto composer = UltraHonkComposer(); -// auto indices = add_variables(composer, { 1, 2, 3, 4, 5, 6, 8, 25 }); -// for (size_t i = 0; i < indices.size(); i++) { -// composer.create_new_range_constraint(indices[i], 8); -// } -// composer.create_sort_constraint(indices); - -// prove_and_verify(composer, /*expected_result=*/false); -// } -// { -// auto composer = UltraHonkComposer(); -// auto indices = -// add_variables(composer, { 1, 2, 3, 4, 5, 6, 10, 8, 15, 11, 32, 21, 42, 79, 16, 10, 3, 26, 19, 51 }); -// for (size_t i = 0; i < indices.size(); i++) { -// composer.create_new_range_constraint(indices[i], 128); -// } -// composer.create_dummy_constraints(indices); - -// prove_and_verify(composer, /*expected_result=*/true); -// } -// { -// auto composer = UltraHonkComposer(); -// auto indices = -// add_variables(composer, { 1, 2, 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++) { -// composer.create_new_range_constraint(indices[i], 79); -// } -// composer.create_dummy_constraints(indices); - -// prove_and_verify(composer, /*expected_result=*/false); -// } -// { -// auto composer = UltraHonkComposer(); -// auto indices = -// add_variables(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++) { -// composer.create_new_range_constraint(indices[i], 79); -// } -// composer.create_dummy_constraints(indices); - -// prove_and_verify(composer, /*expected_result=*/false); -// } -// } - -// TEST(UltraHonkComposer, range_with_gates) -// { - -// auto composer = UltraHonkComposer(); -// auto idx = add_variables(composer, { 1, 2, 3, 4, 5, 6, 7, 8 }); -// for (size_t i = 0; i < idx.size(); i++) { -// composer.create_new_range_constraint(idx[i], 8); -// } - -// composer.create_add_gate({ idx[0], idx[1], composer.get_zero_idx(), fr::one(), fr::one(), fr::zero(), -3 }); -// composer.create_add_gate({ idx[2], idx[3], composer.get_zero_idx(), fr::one(), fr::one(), fr::zero(), -7 }); -// composer.create_add_gate({ idx[4], idx[5], composer.get_zero_idx(), fr::one(), fr::one(), fr::zero(), -11 }); -// composer.create_add_gate({ idx[6], idx[7], composer.get_zero_idx(), fr::one(), fr::one(), fr::zero(), -15 }); - -// prove_and_verify(composer, /*expected_result=*/true); -// } - -// TEST(UltraHonkComposer, range_with_gates_where_range_is_not_a_power_of_two) -// { -// auto composer = UltraHonkComposer(); -// auto idx = add_variables(composer, { 1, 2, 3, 4, 5, 6, 7, 8 }); -// for (size_t i = 0; i < idx.size(); i++) { -// composer.create_new_range_constraint(idx[i], 12); -// } - -// composer.create_add_gate({ idx[0], idx[1], composer.get_zero_idx(), fr::one(), fr::one(), fr::zero(), -3 }); -// composer.create_add_gate({ idx[2], idx[3], composer.get_zero_idx(), fr::one(), fr::one(), fr::zero(), -7 }); -// composer.create_add_gate({ idx[4], idx[5], composer.get_zero_idx(), fr::one(), fr::one(), fr::zero(), -11 }); -// composer.create_add_gate({ idx[6], idx[7], composer.get_zero_idx(), fr::one(), fr::one(), fr::zero(), -15 }); - -// prove_and_verify(composer, /*expected_result=*/true); -// } - -// TEST(UltraHonkComposer, sort_widget_complex) -// { -// { - -// auto composer = UltraHonkComposer(); -// std::vector a = { 1, 3, 4, 7, 7, 8, 11, 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(composer.add_variable(a[i])); -// composer.create_sort_constraint(ind); - -// prove_and_verify(composer, /*expected_result=*/true); -// } -// { - -// auto composer = UltraHonkComposer(); -// 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(composer.add_variable(a[i])); -// composer.create_sort_constraint(ind); - -// prove_and_verify(composer, /*expected_result=*/false); -// } -// } - -// TEST(UltraHonkComposer, sort_widget_neg) -// { -// auto composer = UltraHonkComposer(); -// fr a = fr::one(); -// fr b = fr(2); -// fr c = fr(3); -// fr d = fr(8); - -// auto a_idx = composer.add_variable(a); -// auto b_idx = composer.add_variable(b); -// auto c_idx = composer.add_variable(c); -// auto d_idx = composer.add_variable(d); -// composer.create_sort_constraint({ a_idx, b_idx, c_idx, d_idx }); - -// prove_and_verify(composer, /*expected_result=*/false); -// } - -// TEST(UltraHonkComposer, composed_range_constraint) -// { -// auto composer = UltraHonkComposer(); -// auto c = fr::random_element(); -// auto d = uint256_t(c).slice(0, 133); -// auto e = fr(d); -// auto a_idx = composer.add_variable(fr(e)); -// composer.create_add_gate({ a_idx, composer.get_zero_idx(), composer.get_zero_idx(), 1, 0, 0, -fr(e) }); -// composer.decompose_into_default_range(a_idx, 134); - -// prove_and_verify(composer, /*expected_result=*/true); -// } - -// TEST(UltraHonkComposer, non_native_field_multiplication) -// { -// auto composer = UltraHonkComposer(); - -// 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] = composer.add_variable(limbs[0]); -// limb_indices[1] = composer.add_variable(limbs[1]); -// limb_indices[2] = composer.add_variable(limbs[2]); -// limb_indices[3] = composer.add_variable(limbs[3]); -// limb_indices[4] = 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::UltraCircuitConstructor::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] = composer.queue_non_native_field_multiplication(inputs); -// composer.range_constrain_two_limbs(lo_1_idx, hi_1_idx, 70, 70); - -// prove_and_verify(composer, /*expected_result=*/true); -// } - -// TEST(UltraHonkComposer, rom) -// { -// auto composer = UltraHonkComposer(); - -// uint32_t rom_values[8]{ -// composer.add_variable(fr::random_element()), composer.add_variable(fr::random_element()), -// composer.add_variable(fr::random_element()), composer.add_variable(fr::random_element()), -// composer.add_variable(fr::random_element()), composer.add_variable(fr::random_element()), -// composer.add_variable(fr::random_element()), composer.add_variable(fr::random_element()), -// }; - -// size_t rom_id = composer.create_ROM_array(8); - -// for (size_t i = 0; i < 8; ++i) { -// composer.set_ROM_element(rom_id, i, rom_values[i]); -// } - -// uint32_t a_idx = composer.read_ROM_array(rom_id, composer.add_variable(5)); -// EXPECT_EQ(a_idx != rom_values[5], true); -// uint32_t b_idx = composer.read_ROM_array(rom_id, composer.add_variable(4)); -// uint32_t c_idx = composer.read_ROM_array(rom_id, composer.add_variable(1)); - -// const auto d_value = composer.get_variable(a_idx) + composer.get_variable(b_idx) + composer.get_variable(c_idx); -// uint32_t d_idx = composer.add_variable(d_value); - -// composer.create_big_add_gate({ -// a_idx, -// b_idx, -// c_idx, -// d_idx, -// 1, -// 1, -// 1, -// -1, -// 0, -// }); - -// prove_and_verify(composer, /*expected_result=*/true); -// } - -// TEST(UltraHonkComposer, ram) -// { -// auto composer = UltraHonkComposer(); - -// uint32_t ram_values[8]{ -// composer.add_variable(fr::random_element()), composer.add_variable(fr::random_element()), -// composer.add_variable(fr::random_element()), composer.add_variable(fr::random_element()), -// composer.add_variable(fr::random_element()), composer.add_variable(fr::random_element()), -// composer.add_variable(fr::random_element()), composer.add_variable(fr::random_element()), -// }; - -// size_t ram_id = composer.create_RAM_array(8); - -// for (size_t i = 0; i < 8; ++i) { -// composer.init_RAM_element(ram_id, i, ram_values[i]); -// } - -// uint32_t a_idx = composer.read_RAM_array(ram_id, composer.add_variable(5)); -// EXPECT_EQ(a_idx != ram_values[5], true); - -// uint32_t b_idx = composer.read_RAM_array(ram_id, composer.add_variable(4)); -// uint32_t c_idx = composer.read_RAM_array(ram_id, composer.add_variable(1)); - -// composer.write_RAM_array(ram_id, composer.add_variable(4), composer.add_variable(500)); -// uint32_t d_idx = composer.read_RAM_array(ram_id, composer.add_variable(4)); - -// EXPECT_EQ(composer.get_variable(d_idx), 500); - -// // ensure these vars get used in another arithmetic gate -// const auto e_value = composer.get_variable(a_idx) + composer.get_variable(b_idx) + composer.get_variable(c_idx) + -// composer.get_variable(d_idx); -// uint32_t e_idx = composer.add_variable(e_value); - -// composer.create_big_add_gate( -// { -// a_idx, -// b_idx, -// c_idx, -// d_idx, -// -1, -// -1, -// -1, -// -1, -// 0, -// }, -// true); // composer.create_big_add_gate( // { -// composer.get_zero_idx(), -// composer.get_zero_idx(), -// composer.get_zero_idx(), -// e_idx, +// a, +// b, +// c, +// d, // 0, // 0, // 0, @@ -805,68 +836,32 @@ // prove_and_verify(composer, /*expected_result=*/true); // } -// // TODO(#378)(luke): this is a recent update from Zac and fails; do we need a corresponding bug fix in ultra circuit -// // constructor? TEST(UltraHonkComposer, range_checks_on_duplicates) -// // { -// // auto composer = UltraHonkComposer(); - -// // uint32_t a = composer.add_variable(100); -// // uint32_t b = composer.add_variable(100); -// // uint32_t c = composer.add_variable(100); -// // uint32_t d = composer.add_variable(100); - -// // composer.assert_equal(a, b); -// // composer.assert_equal(a, c); -// // composer.assert_equal(a, d); - -// // composer.create_new_range_constraint(a, 1000); -// // composer.create_new_range_constraint(b, 1001); -// // composer.create_new_range_constraint(c, 999); -// // composer.create_new_range_constraint(d, 1000); - -// // composer.create_big_add_gate( -// // { -// // a, -// // b, -// // c, -// // d, -// // 0, -// // 0, -// // 0, -// // 0, -// // 0, -// // }, -// // false); - -// // prove_and_verify(composer, /*expected_result=*/true); -// // } - -// // TODO(#378)(luke): this is a new test from Zac; ultra circuit constructor does not yet have create_range_constraint -// // implemented. -// // // Ensure copy constraints added on variables smaller than 2^14, which have been previously -// // // range constrained, do not break the set equivalence checks because of indices mismatch. -// // // 2^14 is DEFAULT_PLOOKUP_RANGE_BITNUM i.e. the maximum size before a variable gets sliced -// // // before range constraints are applied to it. -// // TEST(UltraHonkComposer, range_constraint_small_variable) -// // { -// // auto composer = UltraHonkComposer(); -// // uint16_t mask = (1 << 8) - 1; -// // int a = engine.get_random_uint16() & mask; -// // uint32_t a_idx = composer.add_variable(fr(a)); -// // uint32_t b_idx = composer.add_variable(fr(a)); -// // ASSERT_NE(a_idx, b_idx); -// // uint32_t c_idx = composer.add_variable(fr(a)); -// // ASSERT_NE(c_idx, b_idx); -// // composer.create_range_constraint(b_idx, 8, "bad range"); -// // composer.assert_equal(a_idx, b_idx); -// // composer.create_range_constraint(c_idx, 8, "bad range"); -// // composer.assert_equal(a_idx, c_idx); - -// // auto prover = composer.create_prover(); -// // auto proof = prover.construct_proof(); -// // auto verifier = composer.create_verifier(); -// // bool result = verifier.verify_proof(proof); -// // EXPECT_EQ(result, true); -// // } - -// } // namespace test_ultra_honk_composer +// TODO(#378)(luke): this is a new test from Zac; ultra circuit constructor does not yet have create_range_constraint +// implemented. +// // Ensure copy constraints added on variables smaller than 2^14, which have been previously +// // range constrained, do not break the set equivalence checks because of indices mismatch. +// // 2^14 is DEFAULT_PLOOKUP_RANGE_BITNUM i.e. the maximum size before a variable gets sliced +// // before range constraints are applied to it. +// TEST(UltraHonkComposer, range_constraint_small_variable) +// { +// auto composer = UltraHonkComposer(); +// uint16_t mask = (1 << 8) - 1; +// int a = engine.get_random_uint16() & mask; +// uint32_t a_idx = composer.add_variable(fr(a)); +// uint32_t b_idx = composer.add_variable(fr(a)); +// ASSERT_NE(a_idx, b_idx); +// uint32_t c_idx = composer.add_variable(fr(a)); +// ASSERT_NE(c_idx, b_idx); +// composer.create_range_constraint(b_idx, 8, "bad range"); +// composer.assert_equal(a_idx, b_idx); +// composer.create_range_constraint(c_idx, 8, "bad range"); +// composer.assert_equal(a_idx, c_idx); + +// auto prover = composer.create_prover(); +// auto proof = prover.construct_proof(); +// auto verifier = composer.create_verifier(); +// bool result = verifier.verify_proof(proof); +// EXPECT_EQ(result, true); +// } + +} // namespace test_ultra_honk_composer diff --git a/cpp/src/barretenberg/honk/proof_system/ultra_prover.cpp b/cpp/src/barretenberg/honk/proof_system/ultra_prover.cpp index 1d6d6cacd3..2c48221fb6 100644 --- a/cpp/src/barretenberg/honk/proof_system/ultra_prover.cpp +++ b/cpp/src/barretenberg/honk/proof_system/ultra_prover.cpp @@ -189,15 +189,14 @@ template void UltraProver_::execute_grand_product_c */ template void UltraProver_::execute_relation_check_rounds() { - using Sumcheck = sumcheck::Sumcheck, sumcheck::UltraArithmeticRelation>; - // using Sumcheck = sumcheck::Sumcheck, - // sumcheck::UltraArithmeticRelation, - // sumcheck::UltraPermutationRelation, - // sumcheck::LookupRelation, - // sumcheck::GenPermSortRelation, - // sumcheck::EllipticRelation, - // sumcheck::AuxiliaryRelation>; + // using Sumcheck = sumcheck::Sumcheck, sumcheck::UltraArithmeticRelation>; + using Sumcheck = sumcheck::Sumcheck, + sumcheck::UltraArithmeticRelation, + sumcheck::UltraPermutationRelation, + sumcheck::LookupRelation, + sumcheck::GenPermSortRelation, + sumcheck::EllipticRelation>; auto sumcheck = Sumcheck(key->circuit_size, transcript); diff --git a/cpp/src/barretenberg/honk/proof_system/ultra_verifier.cpp b/cpp/src/barretenberg/honk/proof_system/ultra_verifier.cpp index 48dd02f5db..410438beeb 100644 --- a/cpp/src/barretenberg/honk/proof_system/ultra_verifier.cpp +++ b/cpp/src/barretenberg/honk/proof_system/ultra_verifier.cpp @@ -105,16 +105,15 @@ template bool UltraVerifier_::verify_proof(const plonk commitments.z_lookup = transcript.template receive_from_prover(commitment_labels.z_lookup); // Execute Sumcheck Verifier - auto sumcheck = - Sumcheck, honk::sumcheck::UltraArithmeticRelation>(circuit_size, transcript); - // auto sumcheck = Sumcheck, - // honk::sumcheck::UltraArithmeticRelation, - // honk::sumcheck::UltraPermutationRelation, - // honk::sumcheck::LookupRelation, - // honk::sumcheck::GenPermSortRelation, - // honk::sumcheck::EllipticRelation, - // honk::sumcheck::AuxiliaryRelation>(circuit_size, transcript); + // auto sumcheck = + // Sumcheck, honk::sumcheck::UltraArithmeticRelation>(circuit_size, transcript); + auto sumcheck = Sumcheck, + honk::sumcheck::UltraArithmeticRelation, + honk::sumcheck::UltraPermutationRelation, + honk::sumcheck::LookupRelation, + honk::sumcheck::GenPermSortRelation, + honk::sumcheck::EllipticRelation>(circuit_size, transcript); std::optional sumcheck_output = sumcheck.execute_verifier(relation_parameters); diff --git a/cpp/src/barretenberg/honk/sumcheck/relations/ultra_relation_consistency.test.cpp b/cpp/src/barretenberg/honk/sumcheck/relations/ultra_relation_consistency.test.cpp index be50fe06e5..0ebe5c63d2 100644 --- a/cpp/src/barretenberg/honk/sumcheck/relations/ultra_relation_consistency.test.cpp +++ b/cpp/src/barretenberg/honk/sumcheck/relations/ultra_relation_consistency.test.cpp @@ -544,15 +544,15 @@ TEST_F(UltraRelationConsistency, EllipticRelation) // constexpr FF SUBLIMB_SHIFT_3(SUBLIMB_SHIFT_2 * SUBLIMB_SHIFT); // constexpr FF SUBLIMB_SHIFT_4(SUBLIMB_SHIFT_3 * SUBLIMB_SHIFT); -// /** -// * Non native field arithmetic gate 2 -// * -// * _ _ -// * / _ _ _ 14 \ -// * q_2 . q_4 | (w_1 . w_2) + (w_1 . w_2) + (w_1 . w_4 + w_2 . w_3 - w_3) . 2 - w_3 - w_4 | -// * \_ _/ -// * -// **/ +/** + * Non native field arithmetic gate 2 + * + * _ _ + * / _ _ _ 14 \ + * q_2 . q_4 | (w_1 . w_2) + (w_1 . w_2) + (w_1 . w_4 + w_2 . w_3 - w_3) . 2 - w_3 - w_4 | + * \_ _/ + * + **/ // auto limb_subproduct = w_1 * w_2_shift + w_1_shift * w_2; // auto non_native_field_gate_2 = (w_1 * w_4 + w_2 * w_3 - w_3_shift); // non_native_field_gate_2 *= LIMB_SIZE; @@ -585,13 +585,13 @@ TEST_F(UltraRelationConsistency, EllipticRelation) // auto limb_accumulator_identity = limb_accumulator_1 + limb_accumulator_2; // limb_accumulator_identity *= q_3; -// /** -// * MEMORY -// **/ +/** + * MEMORY + **/ -// /** -// * Memory Record Check -// */ +/** + * Memory Record Check + */ // auto memory_record_check = w_3; // memory_record_check *= eta; // memory_record_check += w_2; @@ -602,9 +602,9 @@ TEST_F(UltraRelationConsistency, EllipticRelation) // auto partial_record_check = memory_record_check; // used in RAM consistency check // memory_record_check = memory_record_check - w_4; -// /** -// * ROM Consistency Check -// */ +/** + * ROM Consistency Check + */ // auto index_delta = w_1_shift - w_1; // auto record_delta = w_4_shift - w_4; @@ -619,9 +619,9 @@ TEST_F(UltraRelationConsistency, EllipticRelation) // ROM_consistency_check_identity *= fake_alpha; // ROM_consistency_check_identity += memory_record_check; -// /** -// * RAM Consistency Check -// */ +/** + * RAM Consistency Check + */ // auto access_type = (w_4 - partial_record_check); // will be 0 or 1 for honest Prover // auto access_check = access_type * access_type - access_type; // check value is 0 or 1 @@ -654,15 +654,15 @@ TEST_F(UltraRelationConsistency, EllipticRelation) // RAM_consistency_check_identity *= fake_alpha; // RAM_consistency_check_identity += access_check; -// /** -// * RAM Timestamp Consistency Check -// */ +/** + * RAM Timestamp Consistency Check + */ // auto timestamp_delta = w_2_shift - w_2; // auto RAM_timestamp_check_identity = (index_delta * FF(-1) + FF(1)) * timestamp_delta - w_3; -// /** -// * The complete RAM/ROM memory identity -// */ +/** + * The complete RAM/ROM memory identity + */ // auto memory_identity = ROM_consistency_check_identity * q_2; // memory_identity += RAM_timestamp_check_identity * q_4; // memory_identity += memory_record_check * q_m; From d77aac465b16b7e7bb3c1e28acdac1d44761e672 Mon Sep 17 00:00:00 2001 From: ledwards2225 Date: Tue, 16 May 2023 22:26:27 +0000 Subject: [PATCH 11/18] delete unused param to fix gcc build --- .../barretenberg/honk/sumcheck/relations/elliptic_relation.hpp | 1 - 1 file changed, 1 deletion(-) diff --git a/cpp/src/barretenberg/honk/sumcheck/relations/elliptic_relation.hpp b/cpp/src/barretenberg/honk/sumcheck/relations/elliptic_relation.hpp index a30fc07f02..3265dec03c 100644 --- a/cpp/src/barretenberg/honk/sumcheck/relations/elliptic_relation.hpp +++ b/cpp/src/barretenberg/honk/sumcheck/relations/elliptic_relation.hpp @@ -45,7 +45,6 @@ template class EllipticRelation { auto x_2 = UnivariateView(extended_edges.w_l_shift); auto y_2 = UnivariateView(extended_edges.w_4_shift); auto x_3 = UnivariateView(extended_edges.w_r_shift); - auto y_3 = UnivariateView(extended_edges.w_o_shift); auto q_sign = UnivariateView(extended_edges.q_l); auto q_beta = UnivariateView(extended_edges.q_o); From dbcaafd15eb0c905a99391b8d8d1d572d262a1ac Mon Sep 17 00:00:00 2001 From: ledwards2225 Date: Wed, 17 May 2023 00:35:56 +0000 Subject: [PATCH 12/18] uncomment some tests --- .../polynomials/barycentric_data.test.cpp | 172 ++--- .../polynomials/multivariates.test.cpp | 640 +++++++++--------- .../honk/sumcheck/polynomials/pow.test.cpp | 40 +- .../relations/relation_consistency.test.cpp | 40 -- .../relations/relation_correctness.test.cpp | 6 +- .../honk/transcript/transcript.test.cpp | 62 +- 6 files changed, 459 insertions(+), 501 deletions(-) diff --git a/cpp/src/barretenberg/honk/sumcheck/polynomials/barycentric_data.test.cpp b/cpp/src/barretenberg/honk/sumcheck/polynomials/barycentric_data.test.cpp index 12300c1bbe..ed2471d01e 100644 --- a/cpp/src/barretenberg/honk/sumcheck/polynomials/barycentric_data.test.cpp +++ b/cpp/src/barretenberg/honk/sumcheck/polynomials/barycentric_data.test.cpp @@ -1,86 +1,86 @@ -// #include "barycentric_data.hpp" -// #include "barretenberg/ecc/curves/bn254/fr.hpp" - -// #include -// #include "barretenberg/numeric/random/engine.hpp" - -// using namespace proof_system::honk::sumcheck; -// namespace test_sumcheck_polynomials { - -// template class BarycentricDataTests : public testing::Test {}; - -// using FieldTypes = testing::Types; -// TYPED_TEST_SUITE(BarycentricDataTests, FieldTypes); - -// #define BARYCENTIC_DATA_TESTS_TYPE_ALIASES using FF = TypeParam; - -// TYPED_TEST(BarycentricDataTests, Extend) -// { -// BARYCENTIC_DATA_TESTS_TYPE_ALIASES -// const size_t domain_size(2); -// const size_t num_evals(10); -// auto f = Univariate({ 1, 2 }); -// auto expected_result = Univariate({ 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 }); -// BarycentricData barycentric_data; -// auto result = barycentric_data.extend(f); -// EXPECT_EQ(result, expected_result); -// } - -// TYPED_TEST(BarycentricDataTests, Evaluate) -// { -// BARYCENTIC_DATA_TESTS_TYPE_ALIASES -// const size_t domain_size(2); -// const size_t num_evals(10); -// auto f = Univariate({ 1, 2 }); -// FF u = 5; -// FF expected_result = 6; -// BarycentricData barycentric_data; -// auto result = barycentric_data.evaluate(f, u); -// EXPECT_EQ(result, expected_result); -// } - -// TYPED_TEST(BarycentricDataTests, BarycentricData2to3) -// { -// BARYCENTIC_DATA_TESTS_TYPE_ALIASES - -// const size_t domain_size = 2; -// const size_t num_evals = 3; -// auto barycentric = BarycentricData(); -// std::array expected_big_domain{ { 0, 1, 2 } }; -// std::array expected_denominators{ { -1, 1 } }; -// std::array expected_full_numerator_values{ { 0, 0, 2 } }; -// EXPECT_EQ(barycentric.big_domain, expected_big_domain); -// EXPECT_EQ(barycentric.lagrange_denominators, expected_denominators); -// EXPECT_EQ(barycentric.full_numerator_values, expected_full_numerator_values); - -// // e1(X) = 1*(1-X) + 2*X = 1 + X -// Univariate e1{ { 1, 2 } }; -// FF u = FF::random_element(); -// FF calculated_val_at_u = barycentric.evaluate(e1, u); -// EXPECT_EQ(u + 1, calculated_val_at_u); - -// Univariate ext1 = barycentric.extend(e1); -// Univariate expected{ { 1, 2, 3 } }; -// EXPECT_EQ(ext1, expected); -// } - -// TYPED_TEST(BarycentricDataTests, BarycentricData5to6) -// { -// BARYCENTIC_DATA_TESTS_TYPE_ALIASES - -// const size_t domain_size = 5; -// const size_t num_evals = 6; -// auto barycentric = BarycentricData(); - -// // Note: we are able to represent a degree 4 polynomial with 5 points thus this -// // extension will succeed. It would fail for values on a polynomial of degree > 4. -// Univariate e1{ { 1, 3, 25, 109, 321 } }; // X^4 + X^3 + 1 - -// Univariate ext1 = barycentric.extend(e1); - -// Univariate expected{ { 1, 3, 25, 109, 321, 751 } }; - -// EXPECT_EQ(ext1, expected); -// } - -// } // namespace test_sumcheck_polynomials +#include "barycentric_data.hpp" +#include "barretenberg/ecc/curves/bn254/fr.hpp" + +#include +#include "barretenberg/numeric/random/engine.hpp" + +using namespace proof_system::honk::sumcheck; +namespace test_sumcheck_polynomials { + +template class BarycentricDataTests : public testing::Test {}; + +using FieldTypes = testing::Types; +TYPED_TEST_SUITE(BarycentricDataTests, FieldTypes); + +#define BARYCENTIC_DATA_TESTS_TYPE_ALIASES using FF = TypeParam; + +TYPED_TEST(BarycentricDataTests, Extend) +{ + BARYCENTIC_DATA_TESTS_TYPE_ALIASES + const size_t domain_size(2); + const size_t num_evals(10); + auto f = Univariate({ 1, 2 }); + auto expected_result = Univariate({ 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 }); + BarycentricData barycentric_data; + auto result = barycentric_data.extend(f); + EXPECT_EQ(result, expected_result); +} + +TYPED_TEST(BarycentricDataTests, Evaluate) +{ + BARYCENTIC_DATA_TESTS_TYPE_ALIASES + const size_t domain_size(2); + const size_t num_evals(10); + auto f = Univariate({ 1, 2 }); + FF u = 5; + FF expected_result = 6; + BarycentricData barycentric_data; + auto result = barycentric_data.evaluate(f, u); + EXPECT_EQ(result, expected_result); +} + +TYPED_TEST(BarycentricDataTests, BarycentricData2to3) +{ + BARYCENTIC_DATA_TESTS_TYPE_ALIASES + + const size_t domain_size = 2; + const size_t num_evals = 3; + auto barycentric = BarycentricData(); + std::array expected_big_domain{ { 0, 1, 2 } }; + std::array expected_denominators{ { -1, 1 } }; + std::array expected_full_numerator_values{ { 0, 0, 2 } }; + EXPECT_EQ(barycentric.big_domain, expected_big_domain); + EXPECT_EQ(barycentric.lagrange_denominators, expected_denominators); + EXPECT_EQ(barycentric.full_numerator_values, expected_full_numerator_values); + + // e1(X) = 1*(1-X) + 2*X = 1 + X + Univariate e1{ { 1, 2 } }; + FF u = FF::random_element(); + FF calculated_val_at_u = barycentric.evaluate(e1, u); + EXPECT_EQ(u + 1, calculated_val_at_u); + + Univariate ext1 = barycentric.extend(e1); + Univariate expected{ { 1, 2, 3 } }; + EXPECT_EQ(ext1, expected); +} + +TYPED_TEST(BarycentricDataTests, BarycentricData5to6) +{ + BARYCENTIC_DATA_TESTS_TYPE_ALIASES + + const size_t domain_size = 5; + const size_t num_evals = 6; + auto barycentric = BarycentricData(); + + // Note: we are able to represent a degree 4 polynomial with 5 points thus this + // extension will succeed. It would fail for values on a polynomial of degree > 4. + Univariate e1{ { 1, 3, 25, 109, 321 } }; // X^4 + X^3 + 1 + + Univariate ext1 = barycentric.extend(e1); + + Univariate expected{ { 1, 3, 25, 109, 321, 751 } }; + + EXPECT_EQ(ext1, expected); +} + +} // namespace test_sumcheck_polynomials diff --git a/cpp/src/barretenberg/honk/sumcheck/polynomials/multivariates.test.cpp b/cpp/src/barretenberg/honk/sumcheck/polynomials/multivariates.test.cpp index 9917346999..3e40df0113 100644 --- a/cpp/src/barretenberg/honk/sumcheck/polynomials/multivariates.test.cpp +++ b/cpp/src/barretenberg/honk/sumcheck/polynomials/multivariates.test.cpp @@ -1,320 +1,320 @@ -// #include "barretenberg/ecc/curves/bn254/fr.hpp" -// #include "barretenberg/honk/sumcheck/relations/arithmetic_relation.hpp" -// #include "barretenberg/honk/sumcheck/sumcheck.hpp" - -// #include -// #include "barretenberg/honk/transcript/transcript.hpp" -// #include "barretenberg/numeric/random/engine.hpp" -// #include "barretenberg/honk/flavor/standard.hpp" - -// using namespace proof_system::honk::sumcheck; -// namespace test_sumcheck_polynomials { - -// template class MultivariatesTests : public testing::Test {}; - -// using Flavors = testing::Types; - -// TYPED_TEST_SUITE(MultivariatesTests, Flavors); - -// /* -// * We represent a bivariate f0 as f0(X0, X1). The indexing starts from 0 to match with the round number in sumcheck. -// * The idea is variable X0 (lsb) will be folded at round 2 (the first sumcheck round), -// * then the variable X1 (msb) will be folded at round 1 (the last rond in this case). Pictorially we have, -// * v10 ------ v11 -// * | | -// * X0(lsb) | | -// * | X1(msb) | -// * v00 ------ v01 -// * f0(X0, X1) = v00 * (1-X0) * (1-X1) -// * + v10 * X0 * (1-X1) -// * + v01 * (1-X0) * X1 -// * + v11 * X0 * X1. -// * -// * To effectively represent folding we write, -// * f0(X0, X1) = [v00 * (1-X0) + v10 * X0] * (1-X1) -// * + [v01 * (1-X0) + v11 * X0] * X1. -// * -// * After folding at round 0 (round challenge u0), we have, -// * f0(u0,X1) = (v00 * (1-u0) + v10 * u0) * (1-X1) -// * + (v01 * (1-u0) + v11 * u0) * X1. -// * -// * After folding at round 1 (round challenge u1), we have, -// * f0(u0,u1) = (v00 * (1-u0) + v10 * u0) * (1-u1) -// * + (v01 * (1-u0) + v11 * u0) * u1. -// */ -// TYPED_TEST(MultivariatesTests, FoldTwoRoundsSpecial) -// { -// using Flavor = TypeParam; -// using FF = typename Flavor::FF; -// using Transcript = honk::ProverTranscript; - -// // values here are chosen to check another test -// const size_t multivariate_d(2); -// const size_t multivariate_n(1 << multivariate_d); - -// FF v00 = 0; -// FF v10 = 1; -// FF v01 = 0; -// FF v11 = 0; - -// std::array f0 = { v00, v10, v01, v11 }; - -// auto full_polynomials = std::array, 1>({ f0 }); -// auto transcript = Transcript::init_empty(); -// auto sumcheck = Sumcheck(multivariate_n, transcript); - -// FF round_challenge_0 = { 0x6c7301b49d85a46c, 0x44311531e39c64f6, 0xb13d66d8d6c1a24c, 0x04410c360230a295 }; -// round_challenge_0.self_to_montgomery_form(); -// FF expected_lo = v00 * (FF(1) - round_challenge_0) + v10 * round_challenge_0; -// FF expected_hi = v01 * (FF(1) - round_challenge_0) + v11 * round_challenge_0; - -// sumcheck.fold(full_polynomials, multivariate_n, round_challenge_0); - -// EXPECT_EQ(sumcheck.folded_polynomials[0][0], round_challenge_0); -// EXPECT_EQ(sumcheck.folded_polynomials[0][1], FF(0)); - -// FF round_challenge_1 = 2; -// FF expected_val = expected_lo * (FF(1) - round_challenge_1) + expected_hi * round_challenge_1; - -// sumcheck.fold(sumcheck.folded_polynomials, multivariate_n >> 1, round_challenge_1); -// EXPECT_EQ(sumcheck.folded_polynomials[0][0], expected_val); -// } - -// TYPED_TEST(MultivariatesTests, FoldTwoRoundsGeneric) -// { -// using Flavor = TypeParam; -// using FF = typename Flavor::FF; -// using Transcript = honk::ProverTranscript; - -// const size_t multivariate_d(2); -// const size_t multivariate_n(1 << multivariate_d); - -// FF v00 = FF::random_element(); -// FF v10 = FF::random_element(); -// FF v01 = FF::random_element(); -// FF v11 = FF::random_element(); - -// std::array f0 = { v00, v10, v01, v11 }; - -// auto full_polynomials = std::array, 1>({ f0 }); -// auto transcript = Transcript::init_empty(); -// auto sumcheck = Sumcheck(multivariate_n, transcript); - -// FF round_challenge_0 = FF::random_element(); -// FF expected_lo = v00 * (FF(1) - round_challenge_0) + v10 * round_challenge_0; -// FF expected_hi = v01 * (FF(1) - round_challenge_0) + v11 * round_challenge_0; - -// sumcheck.fold(full_polynomials, multivariate_n, round_challenge_0); - -// EXPECT_EQ(sumcheck.folded_polynomials[0][0], expected_lo); -// EXPECT_EQ(sumcheck.folded_polynomials[0][1], expected_hi); - -// FF round_challenge_1 = FF::random_element(); -// FF expected_val = expected_lo * (FF(1) - round_challenge_1) + expected_hi * round_challenge_1; -// sumcheck.fold(sumcheck.folded_polynomials, multivariate_n >> 1, round_challenge_1); -// EXPECT_EQ(sumcheck.folded_polynomials[0][0], expected_val); -// } - -// /* -// * Similarly for a trivariate polynomial f0(X0, X1, X2), we have -// * f0(X0, X1, X2) = v000 * (1-X0) * (1-X1) * (1-X2) -// * + v100 * X0 * (1-X1) * (1-X2) -// * + v010 * (1-X0) * X1 * (1-X2) -// * + v110 * X0 * X1 * (1-X2) -// * + v001 * (1-X0) * (1-X1) * X2 -// * + v101 * X0 * (1-X1) * X2 -// * + v011 * (1-X0) * X1 * X2 -// * + v111 * X0 * X1 * X2. -// * After round 0 (round challenge u0), we have -// * f0(u0, X1, X2) = [v000 * (1-u0) + v100 * u0] * (1-X1) * (1-X2) -// * + [v010 * (1-u0) + v110 * u0] * X1 * (1-X2) -// * + [v001 * (1-u0) + v101 * u0] * (1-X1) * X2 -// * + [v011 * (1-u0) + v111 * u0] * X1 * X2. -// * After round 1 (round challenge u1), we have -// * f0(u0, u1, X2) = [(v000 * (1-u0) + v100 * u0) * (1-u1) + (v010 * (1-u0) + v110 * u0) * u1] * (1-X2) -// * + [(v001 * (1-u0) + v101 * u0) * (1-u1) + (v011 * (1-u0) + v111 * u0) * u1] * X2. -// * After round 2 (round challenge u2), we have -// * f0(u0, u1, u2) = [(v000 * (1-u0) + v100 * u0) * (1-u1) + (v010 * (1-u0) + v110 * u0) * u1] * (1-u2) -// * + [(v001 * (1-u0) + v101 * u0) * (1-u1) + (v011 * (1-u0) + v111 * u0) * u1] * u2. -// */ -// TYPED_TEST(MultivariatesTests, FoldThreeRoundsSpecial) -// { -// using Flavor = TypeParam; -// using FF = typename Flavor::FF; -// using Transcript = honk::ProverTranscript; - -// const size_t multivariate_d(3); -// const size_t multivariate_n(1 << multivariate_d); - -// FF v000 = 1; -// FF v100 = 2; -// FF v010 = 3; -// FF v110 = 4; -// FF v001 = 5; -// FF v101 = 6; -// FF v011 = 7; -// FF v111 = 8; - -// std::array f0 = { v000, v100, v010, v110, v001, v101, v011, v111 }; - -// auto full_polynomials = std::array, 1>({ f0 }); -// auto transcript = Transcript::init_empty(); -// auto sumcheck = Sumcheck(multivariate_n, transcript); - -// FF round_challenge_0 = 1; -// FF expected_q1 = v000 * (FF(1) - round_challenge_0) + v100 * round_challenge_0; // 2 -// FF expected_q2 = v010 * (FF(1) - round_challenge_0) + v110 * round_challenge_0; // 4 -// FF expected_q3 = v001 * (FF(1) - round_challenge_0) + v101 * round_challenge_0; // 6 -// FF expected_q4 = v011 * (FF(1) - round_challenge_0) + v111 * round_challenge_0; // 8 - -// sumcheck.fold(full_polynomials, multivariate_n, round_challenge_0); - -// EXPECT_EQ(sumcheck.folded_polynomials[0][0], expected_q1); -// EXPECT_EQ(sumcheck.folded_polynomials[0][1], expected_q2); -// EXPECT_EQ(sumcheck.folded_polynomials[0][2], expected_q3); -// EXPECT_EQ(sumcheck.folded_polynomials[0][3], expected_q4); - -// FF round_challenge_1 = 2; -// FF expected_lo = expected_q1 * (FF(1) - round_challenge_1) + expected_q2 * round_challenge_1; // 6 -// FF expected_hi = expected_q3 * (FF(1) - round_challenge_1) + expected_q4 * round_challenge_1; // 10 - -// sumcheck.fold(sumcheck.folded_polynomials, multivariate_n >> 1, round_challenge_1); -// EXPECT_EQ(sumcheck.folded_polynomials[0][0], expected_lo); -// EXPECT_EQ(sumcheck.folded_polynomials[0][1], expected_hi); - -// FF round_challenge_2 = 3; -// FF expected_val = expected_lo * (FF(1) - round_challenge_2) + expected_hi * round_challenge_2; // 18 -// sumcheck.fold(sumcheck.folded_polynomials, multivariate_n >> 2, round_challenge_2); -// EXPECT_EQ(sumcheck.folded_polynomials[0][0], expected_val); -// } - -// TYPED_TEST(MultivariatesTests, FoldThreeRoundsGeneric) -// { -// using Flavor = TypeParam; -// using FF = typename Flavor::FF; -// using Transcript = honk::ProverTranscript; - -// const size_t multivariate_d(3); -// const size_t multivariate_n(1 << multivariate_d); - -// FF v000 = FF::random_element(); -// FF v100 = FF::random_element(); -// FF v010 = FF::random_element(); -// FF v110 = FF::random_element(); -// FF v001 = FF::random_element(); -// FF v101 = FF::random_element(); -// FF v011 = FF::random_element(); -// FF v111 = FF::random_element(); - -// std::array f0 = { v000, v100, v010, v110, v001, v101, v011, v111 }; - -// auto full_polynomials = std::array, 1>({ f0 }); -// auto transcript = Transcript::init_empty(); -// auto sumcheck = Sumcheck(multivariate_n, transcript); - -// FF round_challenge_0 = FF::random_element(); -// FF expected_q1 = v000 * (FF(1) - round_challenge_0) + v100 * round_challenge_0; -// FF expected_q2 = v010 * (FF(1) - round_challenge_0) + v110 * round_challenge_0; -// FF expected_q3 = v001 * (FF(1) - round_challenge_0) + v101 * round_challenge_0; -// FF expected_q4 = v011 * (FF(1) - round_challenge_0) + v111 * round_challenge_0; - -// sumcheck.fold(full_polynomials, multivariate_n, round_challenge_0); - -// EXPECT_EQ(sumcheck.folded_polynomials[0][0], expected_q1); -// EXPECT_EQ(sumcheck.folded_polynomials[0][1], expected_q2); -// EXPECT_EQ(sumcheck.folded_polynomials[0][2], expected_q3); -// EXPECT_EQ(sumcheck.folded_polynomials[0][3], expected_q4); - -// FF round_challenge_1 = FF::random_element(); -// FF expected_lo = expected_q1 * (FF(1) - round_challenge_1) + expected_q2 * round_challenge_1; -// FF expected_hi = expected_q3 * (FF(1) - round_challenge_1) + expected_q4 * round_challenge_1; - -// sumcheck.fold(sumcheck.folded_polynomials, multivariate_n >> 1, round_challenge_1); -// EXPECT_EQ(sumcheck.folded_polynomials[0][0], expected_lo); -// EXPECT_EQ(sumcheck.folded_polynomials[0][1], expected_hi); - -// FF round_challenge_2 = FF::random_element(); -// FF expected_val = expected_lo * (FF(1) - round_challenge_2) + expected_hi * round_challenge_2; -// sumcheck.fold(sumcheck.folded_polynomials, multivariate_n >> 2, round_challenge_2); -// EXPECT_EQ(sumcheck.folded_polynomials[0][0], expected_val); -// } - -// TYPED_TEST(MultivariatesTests, FoldThreeRoundsGenericMultiplePolys) -// { -// using Flavor = TypeParam; -// using FF = typename Flavor::FF; -// using Transcript = honk::ProverTranscript; - -// const size_t multivariate_d(3); -// const size_t multivariate_n(1 << multivariate_d); -// std::array v000; -// std::array v100; -// std::array v010; -// std::array v110; -// std::array v001; -// std::array v101; -// std::array v011; -// std::array v111; - -// for (size_t i = 0; i < 3; i++) { -// v000[i] = FF::random_element(); -// v100[i] = FF::random_element(); -// v010[i] = FF::random_element(); -// v110[i] = FF::random_element(); -// v001[i] = FF::random_element(); -// v101[i] = FF::random_element(); -// v011[i] = FF::random_element(); -// v111[i] = FF::random_element(); -// } -// std::array f0 = { v000[0], v100[0], v010[0], v110[0], v001[0], v101[0], v011[0], v111[0] }; -// std::array f1 = { v000[1], v100[1], v010[1], v110[1], v001[1], v101[1], v011[1], v111[1] }; -// std::array f2 = { v000[2], v100[2], v010[2], v110[2], v001[2], v101[2], v011[2], v111[2] }; - -// auto full_polynomials = std::array, 3>{ f0, f1, f2 }; -// auto transcript = Transcript::init_empty(); -// auto sumcheck = Sumcheck(multivariate_n, transcript); - -// std::array expected_q1; -// std::array expected_q2; -// std::array expected_q3; -// std::array expected_q4; -// FF round_challenge_0 = FF::random_element(); -// for (size_t i = 0; i < 3; i++) { -// expected_q1[i] = v000[i] * (FF(1) - round_challenge_0) + v100[i] * round_challenge_0; -// expected_q2[i] = v010[i] * (FF(1) - round_challenge_0) + v110[i] * round_challenge_0; -// expected_q3[i] = v001[i] * (FF(1) - round_challenge_0) + v101[i] * round_challenge_0; -// expected_q4[i] = v011[i] * (FF(1) - round_challenge_0) + v111[i] * round_challenge_0; -// } - -// sumcheck.fold(full_polynomials, multivariate_n, round_challenge_0); -// for (size_t i = 0; i < 3; i++) { -// EXPECT_EQ(sumcheck.folded_polynomials[i][0], expected_q1[i]); -// EXPECT_EQ(sumcheck.folded_polynomials[i][1], expected_q2[i]); -// EXPECT_EQ(sumcheck.folded_polynomials[i][2], expected_q3[i]); -// EXPECT_EQ(sumcheck.folded_polynomials[i][3], expected_q4[i]); -// } - -// FF round_challenge_1 = FF::random_element(); -// std::array expected_lo; -// std::array expected_hi; -// for (size_t i = 0; i < 3; i++) { -// expected_lo[i] = expected_q1[i] * (FF(1) - round_challenge_1) + expected_q2[i] * round_challenge_1; -// expected_hi[i] = expected_q3[i] * (FF(1) - round_challenge_1) + expected_q4[i] * round_challenge_1; -// } -// sumcheck.fold(sumcheck.folded_polynomials, multivariate_n >> 1, round_challenge_1); -// for (size_t i = 0; i < 3; i++) { -// EXPECT_EQ(sumcheck.folded_polynomials[i][0], expected_lo[i]); -// EXPECT_EQ(sumcheck.folded_polynomials[i][1], expected_hi[i]); -// } -// FF round_challenge_2 = FF::random_element(); -// std::array expected_val; -// for (size_t i = 0; i < 3; i++) { -// expected_val[i] = expected_lo[i] * (FF(1) - round_challenge_2) + expected_hi[i] * round_challenge_2; -// } -// sumcheck.fold(sumcheck.folded_polynomials, multivariate_n >> 2, round_challenge_2); -// for (size_t i = 0; i < 3; i++) { -// EXPECT_EQ(sumcheck.folded_polynomials[i][0], expected_val[i]); -// } -// } - -// } // namespace test_sumcheck_polynomials +#include "barretenberg/ecc/curves/bn254/fr.hpp" +#include "barretenberg/honk/sumcheck/relations/arithmetic_relation.hpp" +#include "barretenberg/honk/sumcheck/sumcheck.hpp" + +#include +#include "barretenberg/honk/transcript/transcript.hpp" +#include "barretenberg/numeric/random/engine.hpp" +#include "barretenberg/honk/flavor/standard.hpp" + +using namespace proof_system::honk::sumcheck; +namespace test_sumcheck_polynomials { + +template class MultivariatesTests : public testing::Test {}; + +using Flavors = testing::Types; + +TYPED_TEST_SUITE(MultivariatesTests, Flavors); + +/* + * We represent a bivariate f0 as f0(X0, X1). The indexing starts from 0 to match with the round number in sumcheck. + * The idea is variable X0 (lsb) will be folded at round 2 (the first sumcheck round), + * then the variable X1 (msb) will be folded at round 1 (the last rond in this case). Pictorially we have, + * v10 ------ v11 + * | | + * X0(lsb) | | + * | X1(msb) | + * v00 ------ v01 + * f0(X0, X1) = v00 * (1-X0) * (1-X1) + * + v10 * X0 * (1-X1) + * + v01 * (1-X0) * X1 + * + v11 * X0 * X1. + * + * To effectively represent folding we write, + * f0(X0, X1) = [v00 * (1-X0) + v10 * X0] * (1-X1) + * + [v01 * (1-X0) + v11 * X0] * X1. + * + * After folding at round 0 (round challenge u0), we have, + * f0(u0,X1) = (v00 * (1-u0) + v10 * u0) * (1-X1) + * + (v01 * (1-u0) + v11 * u0) * X1. + * + * After folding at round 1 (round challenge u1), we have, + * f0(u0,u1) = (v00 * (1-u0) + v10 * u0) * (1-u1) + * + (v01 * (1-u0) + v11 * u0) * u1. + */ +TYPED_TEST(MultivariatesTests, FoldTwoRoundsSpecial) +{ + using Flavor = TypeParam; + using FF = typename Flavor::FF; + using Transcript = honk::ProverTranscript; + + // values here are chosen to check another test + const size_t multivariate_d(2); + const size_t multivariate_n(1 << multivariate_d); + + FF v00 = 0; + FF v10 = 1; + FF v01 = 0; + FF v11 = 0; + + std::array f0 = { v00, v10, v01, v11 }; + + auto full_polynomials = std::array, 1>({ f0 }); + auto transcript = Transcript::init_empty(); + auto sumcheck = Sumcheck(multivariate_n, transcript); + + FF round_challenge_0 = { 0x6c7301b49d85a46c, 0x44311531e39c64f6, 0xb13d66d8d6c1a24c, 0x04410c360230a295 }; + round_challenge_0.self_to_montgomery_form(); + FF expected_lo = v00 * (FF(1) - round_challenge_0) + v10 * round_challenge_0; + FF expected_hi = v01 * (FF(1) - round_challenge_0) + v11 * round_challenge_0; + + sumcheck.fold(full_polynomials, multivariate_n, round_challenge_0); + + EXPECT_EQ(sumcheck.folded_polynomials[0][0], round_challenge_0); + EXPECT_EQ(sumcheck.folded_polynomials[0][1], FF(0)); + + FF round_challenge_1 = 2; + FF expected_val = expected_lo * (FF(1) - round_challenge_1) + expected_hi * round_challenge_1; + + sumcheck.fold(sumcheck.folded_polynomials, multivariate_n >> 1, round_challenge_1); + EXPECT_EQ(sumcheck.folded_polynomials[0][0], expected_val); +} + +TYPED_TEST(MultivariatesTests, FoldTwoRoundsGeneric) +{ + using Flavor = TypeParam; + using FF = typename Flavor::FF; + using Transcript = honk::ProverTranscript; + + const size_t multivariate_d(2); + const size_t multivariate_n(1 << multivariate_d); + + FF v00 = FF::random_element(); + FF v10 = FF::random_element(); + FF v01 = FF::random_element(); + FF v11 = FF::random_element(); + + std::array f0 = { v00, v10, v01, v11 }; + + auto full_polynomials = std::array, 1>({ f0 }); + auto transcript = Transcript::init_empty(); + auto sumcheck = Sumcheck(multivariate_n, transcript); + + FF round_challenge_0 = FF::random_element(); + FF expected_lo = v00 * (FF(1) - round_challenge_0) + v10 * round_challenge_0; + FF expected_hi = v01 * (FF(1) - round_challenge_0) + v11 * round_challenge_0; + + sumcheck.fold(full_polynomials, multivariate_n, round_challenge_0); + + EXPECT_EQ(sumcheck.folded_polynomials[0][0], expected_lo); + EXPECT_EQ(sumcheck.folded_polynomials[0][1], expected_hi); + + FF round_challenge_1 = FF::random_element(); + FF expected_val = expected_lo * (FF(1) - round_challenge_1) + expected_hi * round_challenge_1; + sumcheck.fold(sumcheck.folded_polynomials, multivariate_n >> 1, round_challenge_1); + EXPECT_EQ(sumcheck.folded_polynomials[0][0], expected_val); +} + +/* + * Similarly for a trivariate polynomial f0(X0, X1, X2), we have + * f0(X0, X1, X2) = v000 * (1-X0) * (1-X1) * (1-X2) + * + v100 * X0 * (1-X1) * (1-X2) + * + v010 * (1-X0) * X1 * (1-X2) + * + v110 * X0 * X1 * (1-X2) + * + v001 * (1-X0) * (1-X1) * X2 + * + v101 * X0 * (1-X1) * X2 + * + v011 * (1-X0) * X1 * X2 + * + v111 * X0 * X1 * X2. + * After round 0 (round challenge u0), we have + * f0(u0, X1, X2) = [v000 * (1-u0) + v100 * u0] * (1-X1) * (1-X2) + * + [v010 * (1-u0) + v110 * u0] * X1 * (1-X2) + * + [v001 * (1-u0) + v101 * u0] * (1-X1) * X2 + * + [v011 * (1-u0) + v111 * u0] * X1 * X2. + * After round 1 (round challenge u1), we have + * f0(u0, u1, X2) = [(v000 * (1-u0) + v100 * u0) * (1-u1) + (v010 * (1-u0) + v110 * u0) * u1] * (1-X2) + * + [(v001 * (1-u0) + v101 * u0) * (1-u1) + (v011 * (1-u0) + v111 * u0) * u1] * X2. + * After round 2 (round challenge u2), we have + * f0(u0, u1, u2) = [(v000 * (1-u0) + v100 * u0) * (1-u1) + (v010 * (1-u0) + v110 * u0) * u1] * (1-u2) + * + [(v001 * (1-u0) + v101 * u0) * (1-u1) + (v011 * (1-u0) + v111 * u0) * u1] * u2. + */ +TYPED_TEST(MultivariatesTests, FoldThreeRoundsSpecial) +{ + using Flavor = TypeParam; + using FF = typename Flavor::FF; + using Transcript = honk::ProverTranscript; + + const size_t multivariate_d(3); + const size_t multivariate_n(1 << multivariate_d); + + FF v000 = 1; + FF v100 = 2; + FF v010 = 3; + FF v110 = 4; + FF v001 = 5; + FF v101 = 6; + FF v011 = 7; + FF v111 = 8; + + std::array f0 = { v000, v100, v010, v110, v001, v101, v011, v111 }; + + auto full_polynomials = std::array, 1>({ f0 }); + auto transcript = Transcript::init_empty(); + auto sumcheck = Sumcheck(multivariate_n, transcript); + + FF round_challenge_0 = 1; + FF expected_q1 = v000 * (FF(1) - round_challenge_0) + v100 * round_challenge_0; // 2 + FF expected_q2 = v010 * (FF(1) - round_challenge_0) + v110 * round_challenge_0; // 4 + FF expected_q3 = v001 * (FF(1) - round_challenge_0) + v101 * round_challenge_0; // 6 + FF expected_q4 = v011 * (FF(1) - round_challenge_0) + v111 * round_challenge_0; // 8 + + sumcheck.fold(full_polynomials, multivariate_n, round_challenge_0); + + EXPECT_EQ(sumcheck.folded_polynomials[0][0], expected_q1); + EXPECT_EQ(sumcheck.folded_polynomials[0][1], expected_q2); + EXPECT_EQ(sumcheck.folded_polynomials[0][2], expected_q3); + EXPECT_EQ(sumcheck.folded_polynomials[0][3], expected_q4); + + FF round_challenge_1 = 2; + FF expected_lo = expected_q1 * (FF(1) - round_challenge_1) + expected_q2 * round_challenge_1; // 6 + FF expected_hi = expected_q3 * (FF(1) - round_challenge_1) + expected_q4 * round_challenge_1; // 10 + + sumcheck.fold(sumcheck.folded_polynomials, multivariate_n >> 1, round_challenge_1); + EXPECT_EQ(sumcheck.folded_polynomials[0][0], expected_lo); + EXPECT_EQ(sumcheck.folded_polynomials[0][1], expected_hi); + + FF round_challenge_2 = 3; + FF expected_val = expected_lo * (FF(1) - round_challenge_2) + expected_hi * round_challenge_2; // 18 + sumcheck.fold(sumcheck.folded_polynomials, multivariate_n >> 2, round_challenge_2); + EXPECT_EQ(sumcheck.folded_polynomials[0][0], expected_val); +} + +TYPED_TEST(MultivariatesTests, FoldThreeRoundsGeneric) +{ + using Flavor = TypeParam; + using FF = typename Flavor::FF; + using Transcript = honk::ProverTranscript; + + const size_t multivariate_d(3); + const size_t multivariate_n(1 << multivariate_d); + + FF v000 = FF::random_element(); + FF v100 = FF::random_element(); + FF v010 = FF::random_element(); + FF v110 = FF::random_element(); + FF v001 = FF::random_element(); + FF v101 = FF::random_element(); + FF v011 = FF::random_element(); + FF v111 = FF::random_element(); + + std::array f0 = { v000, v100, v010, v110, v001, v101, v011, v111 }; + + auto full_polynomials = std::array, 1>({ f0 }); + auto transcript = Transcript::init_empty(); + auto sumcheck = Sumcheck(multivariate_n, transcript); + + FF round_challenge_0 = FF::random_element(); + FF expected_q1 = v000 * (FF(1) - round_challenge_0) + v100 * round_challenge_0; + FF expected_q2 = v010 * (FF(1) - round_challenge_0) + v110 * round_challenge_0; + FF expected_q3 = v001 * (FF(1) - round_challenge_0) + v101 * round_challenge_0; + FF expected_q4 = v011 * (FF(1) - round_challenge_0) + v111 * round_challenge_0; + + sumcheck.fold(full_polynomials, multivariate_n, round_challenge_0); + + EXPECT_EQ(sumcheck.folded_polynomials[0][0], expected_q1); + EXPECT_EQ(sumcheck.folded_polynomials[0][1], expected_q2); + EXPECT_EQ(sumcheck.folded_polynomials[0][2], expected_q3); + EXPECT_EQ(sumcheck.folded_polynomials[0][3], expected_q4); + + FF round_challenge_1 = FF::random_element(); + FF expected_lo = expected_q1 * (FF(1) - round_challenge_1) + expected_q2 * round_challenge_1; + FF expected_hi = expected_q3 * (FF(1) - round_challenge_1) + expected_q4 * round_challenge_1; + + sumcheck.fold(sumcheck.folded_polynomials, multivariate_n >> 1, round_challenge_1); + EXPECT_EQ(sumcheck.folded_polynomials[0][0], expected_lo); + EXPECT_EQ(sumcheck.folded_polynomials[0][1], expected_hi); + + FF round_challenge_2 = FF::random_element(); + FF expected_val = expected_lo * (FF(1) - round_challenge_2) + expected_hi * round_challenge_2; + sumcheck.fold(sumcheck.folded_polynomials, multivariate_n >> 2, round_challenge_2); + EXPECT_EQ(sumcheck.folded_polynomials[0][0], expected_val); +} + +TYPED_TEST(MultivariatesTests, FoldThreeRoundsGenericMultiplePolys) +{ + using Flavor = TypeParam; + using FF = typename Flavor::FF; + using Transcript = honk::ProverTranscript; + + const size_t multivariate_d(3); + const size_t multivariate_n(1 << multivariate_d); + std::array v000; + std::array v100; + std::array v010; + std::array v110; + std::array v001; + std::array v101; + std::array v011; + std::array v111; + + for (size_t i = 0; i < 3; i++) { + v000[i] = FF::random_element(); + v100[i] = FF::random_element(); + v010[i] = FF::random_element(); + v110[i] = FF::random_element(); + v001[i] = FF::random_element(); + v101[i] = FF::random_element(); + v011[i] = FF::random_element(); + v111[i] = FF::random_element(); + } + std::array f0 = { v000[0], v100[0], v010[0], v110[0], v001[0], v101[0], v011[0], v111[0] }; + std::array f1 = { v000[1], v100[1], v010[1], v110[1], v001[1], v101[1], v011[1], v111[1] }; + std::array f2 = { v000[2], v100[2], v010[2], v110[2], v001[2], v101[2], v011[2], v111[2] }; + + auto full_polynomials = std::array, 3>{ f0, f1, f2 }; + auto transcript = Transcript::init_empty(); + auto sumcheck = Sumcheck(multivariate_n, transcript); + + std::array expected_q1; + std::array expected_q2; + std::array expected_q3; + std::array expected_q4; + FF round_challenge_0 = FF::random_element(); + for (size_t i = 0; i < 3; i++) { + expected_q1[i] = v000[i] * (FF(1) - round_challenge_0) + v100[i] * round_challenge_0; + expected_q2[i] = v010[i] * (FF(1) - round_challenge_0) + v110[i] * round_challenge_0; + expected_q3[i] = v001[i] * (FF(1) - round_challenge_0) + v101[i] * round_challenge_0; + expected_q4[i] = v011[i] * (FF(1) - round_challenge_0) + v111[i] * round_challenge_0; + } + + sumcheck.fold(full_polynomials, multivariate_n, round_challenge_0); + for (size_t i = 0; i < 3; i++) { + EXPECT_EQ(sumcheck.folded_polynomials[i][0], expected_q1[i]); + EXPECT_EQ(sumcheck.folded_polynomials[i][1], expected_q2[i]); + EXPECT_EQ(sumcheck.folded_polynomials[i][2], expected_q3[i]); + EXPECT_EQ(sumcheck.folded_polynomials[i][3], expected_q4[i]); + } + + FF round_challenge_1 = FF::random_element(); + std::array expected_lo; + std::array expected_hi; + for (size_t i = 0; i < 3; i++) { + expected_lo[i] = expected_q1[i] * (FF(1) - round_challenge_1) + expected_q2[i] * round_challenge_1; + expected_hi[i] = expected_q3[i] * (FF(1) - round_challenge_1) + expected_q4[i] * round_challenge_1; + } + sumcheck.fold(sumcheck.folded_polynomials, multivariate_n >> 1, round_challenge_1); + for (size_t i = 0; i < 3; i++) { + EXPECT_EQ(sumcheck.folded_polynomials[i][0], expected_lo[i]); + EXPECT_EQ(sumcheck.folded_polynomials[i][1], expected_hi[i]); + } + FF round_challenge_2 = FF::random_element(); + std::array expected_val; + for (size_t i = 0; i < 3; i++) { + expected_val[i] = expected_lo[i] * (FF(1) - round_challenge_2) + expected_hi[i] * round_challenge_2; + } + sumcheck.fold(sumcheck.folded_polynomials, multivariate_n >> 2, round_challenge_2); + for (size_t i = 0; i < 3; i++) { + EXPECT_EQ(sumcheck.folded_polynomials[i][0], expected_val[i]); + } +} + +} // namespace test_sumcheck_polynomials diff --git a/cpp/src/barretenberg/honk/sumcheck/polynomials/pow.test.cpp b/cpp/src/barretenberg/honk/sumcheck/polynomials/pow.test.cpp index 2e2fe4a120..a8dd2f5ef3 100644 --- a/cpp/src/barretenberg/honk/sumcheck/polynomials/pow.test.cpp +++ b/cpp/src/barretenberg/honk/sumcheck/polynomials/pow.test.cpp @@ -1,26 +1,26 @@ -// #include "pow.hpp" -// #include "barretenberg/honk/utils/power_polynomial.hpp" -// #include "barretenberg/ecc/curves/bn254/fr.hpp" -// #include +#include "pow.hpp" +#include "barretenberg/honk/utils/power_polynomial.hpp" +#include "barretenberg/ecc/curves/bn254/fr.hpp" +#include -// namespace proof_system::honk::sumcheck::pow_test { +namespace proof_system::honk::sumcheck::pow_test { -// using FF = barretenberg::fr; +using FF = barretenberg::fr; -// TEST(SumcheckPow, FullPowConsistency) -// { -// constexpr size_t d = 5; +TEST(SumcheckPow, FullPowConsistency) +{ + constexpr size_t d = 5; -// FF zeta = FF::random_element(); -// PowUnivariate pow_univariate(zeta); + FF zeta = FF::random_element(); + PowUnivariate pow_univariate(zeta); -// std::array variables{}; -// for (auto& u_i : variables) { -// u_i = FF::random_element(); -// pow_univariate.partially_evaluate(u_i); -// } + std::array variables{}; + for (auto& u_i : variables) { + u_i = FF::random_element(); + pow_univariate.partially_evaluate(u_i); + } -// FF expected_eval = proof_system::honk::power_polynomial::evaluate(zeta, variables); -// EXPECT_EQ(pow_univariate.partial_evaluation_constant, expected_eval); -// } -// } // namespace proof_system::honk::sumcheck::pow_test + FF expected_eval = proof_system::honk::power_polynomial::evaluate(zeta, variables); + EXPECT_EQ(pow_univariate.partial_evaluation_constant, expected_eval); +} +} // namespace proof_system::honk::sumcheck::pow_test diff --git a/cpp/src/barretenberg/honk/sumcheck/relations/relation_consistency.test.cpp b/cpp/src/barretenberg/honk/sumcheck/relations/relation_consistency.test.cpp index 4473add902..5d7d12ed62 100644 --- a/cpp/src/barretenberg/honk/sumcheck/relations/relation_consistency.test.cpp +++ b/cpp/src/barretenberg/honk/sumcheck/relations/relation_consistency.test.cpp @@ -290,44 +290,4 @@ TEST_F(StandardRelationConsistency, PermutationRelation) run_test(/* is_random_input=*/false); }; -// TEST_F(StandardRelationConsistency, GrandProductInitializationRelation) -// { -// using Flavor = honk::flavor::Standard; -// using FF = typename Flavor::FF; -// static constexpr size_t FULL_RELATION_LENGTH = 5; -// using ExtendedEdges = typename Flavor::template ExtendedEdges; -// static const size_t NUM_POLYNOMIALS = Flavor::NUM_ALL_ENTITIES; - -// const auto relation_parameters = compute_mock_relation_parameters(); -// auto run_test = [&relation_parameters](bool is_random_input) { -// ExtendedEdges extended_edges; -// std::array, NUM_POLYNOMIALS> input_polynomials; -// if (!is_random_input) { -// // evaluation form, i.e. input_univariate(0) = 1, input_univariate(1) = 2,.. The polynomial is x+1. -// for (size_t i = 0; i < NUM_POLYNOMIALS; ++i) { -// input_polynomials[i] = Univariate({ 1, 2 }); -// } -// compute_mock_extended_edges(extended_edges, input_polynomials); -// } else { -// // input_univariates are random polynomials of degree one -// for (size_t i = 0; i < NUM_POLYNOMIALS; ++i) { -// input_polynomials[i] = -// Univariate({ FF::random_element(), FF::random_element() }); -// } -// compute_mock_extended_edges(extended_edges, input_polynomials); -// }; -// auto relation = GrandProductInitializationRelation(); -// const auto& z_perm_shift = extended_edges.z_perm_shift; -// const auto& lagrange_last = extended_edges.lagrange_last; -// // We first compute the evaluations using UnivariateViews, with the provided hard-coded formula. -// // Ensure that expression changes are detected. -// // expected_evals, lenght 3 (coeff form = x^2 + x), extends to { { 0, 2, 6, 12, 20 } } -// auto expected_evals = z_perm_shift * lagrange_last; - -// validate_evaluations(expected_evals, relation, extended_edges, relation_parameters); -// }; -// run_test(/* is_random_input=*/true); -// run_test(/* is_random_input=*/false); -// }; - } // namespace proof_system::honk_relation_tests diff --git a/cpp/src/barretenberg/honk/sumcheck/relations/relation_correctness.test.cpp b/cpp/src/barretenberg/honk/sumcheck/relations/relation_correctness.test.cpp index 4a5628150f..2f11f9a3a4 100644 --- a/cpp/src/barretenberg/honk/sumcheck/relations/relation_correctness.test.cpp +++ b/cpp/src/barretenberg/honk/sumcheck/relations/relation_correctness.test.cpp @@ -67,8 +67,7 @@ void check_relation(auto relations, auto circuit_size, auto polynomials, auto pa * @details Check that the constraints encoded by the relations are satisfied by the polynomials produced by the * Standard Honk Composer for a real circuit. * - * TODO(Kesha): We'll have to update this function once we add zk, since the relation will be incorrect for he first - few + * TODO(Kesha): We'll have to update this function once we add zk, since the relation will be incorrect for he first few * indices * */ @@ -155,8 +154,7 @@ TEST(RelationCorrectness, StandardRelationCorrectness) * @details Check that the constraints encoded by the relations are satisfied by the polynomials produced by the * Ultra Honk Composer for a real circuit. * - * TODO(Kesha): We'll have to update this function once we add zk, since the relation will be incorrect for he first - few + * TODO(Kesha): We'll have to update this function once we add zk, since the relation will be incorrect for he first few * indices * */ diff --git a/cpp/src/barretenberg/honk/transcript/transcript.test.cpp b/cpp/src/barretenberg/honk/transcript/transcript.test.cpp index 1842989a4f..6f82adc460 100644 --- a/cpp/src/barretenberg/honk/transcript/transcript.test.cpp +++ b/cpp/src/barretenberg/honk/transcript/transcript.test.cpp @@ -255,34 +255,34 @@ TYPED_TEST(TranscriptTest, VerifierMistake) * construction and the one generated by the verifier over the course of proof verification. * */ -// TYPED_TEST(TranscriptTest, UltraVerifierManifestConsistency) -// { -// // Construct a simple circuit of size n = 8 (i.e. the minimum circuit size) -// auto composer = UltraHonkComposer(); -// // fr a = 2; -// // composer.circuit_constructor.add_variable(a); -// // composer.circuit_constructor.add_public_variable(a); - -// composer.add_gates_to_ensure_all_polys_are_non_zero(); - -// // Automatically generate a transcript manifest in the prover by constructing a proof -// auto prover = composer.create_prover(); -// plonk::proof proof = prover.construct_proof(); - -// // Automatically generate a transcript manifest in the verifier by verifying a proof -// auto verifier = composer.create_verifier(); -// verifier.verify_proof(proof); - -// prover.transcript.print(); -// verifier.transcript.print(); - -// // Check consistency between the manifests generated by the prover and verifier -// auto prover_manifest = prover.transcript.get_manifest(); -// auto verifier_manifest = verifier.transcript.get_manifest(); - -// // Note: a manifest can be printed using manifest.print() -// for (size_t round = 0; round < prover_manifest.size(); ++round) { -// ASSERT_EQ(prover_manifest[round], verifier_manifest[round]) -// << "Prover/Verifier manifest discrepency in round " << round; -// } -// } +TYPED_TEST(TranscriptTest, UltraVerifierManifestConsistency) +{ + // Construct a simple circuit of size n = 8 (i.e. the minimum circuit size) + auto composer = UltraHonkComposer(); + // fr a = 2; + // composer.circuit_constructor.add_variable(a); + // composer.circuit_constructor.add_public_variable(a); + + composer.add_gates_to_ensure_all_polys_are_non_zero(); + + // Automatically generate a transcript manifest in the prover by constructing a proof + auto prover = composer.create_prover(); + plonk::proof proof = prover.construct_proof(); + + // Automatically generate a transcript manifest in the verifier by verifying a proof + auto verifier = composer.create_verifier(); + verifier.verify_proof(proof); + + prover.transcript.print(); + verifier.transcript.print(); + + // Check consistency between the manifests generated by the prover and verifier + auto prover_manifest = prover.transcript.get_manifest(); + auto verifier_manifest = verifier.transcript.get_manifest(); + + // Note: a manifest can be printed using manifest.print() + for (size_t round = 0; round < prover_manifest.size(); ++round) { + ASSERT_EQ(prover_manifest[round], verifier_manifest[round]) + << "Prover/Verifier manifest discrepency in round " << round; + } +} From 03b1718bc3d5f78c97d9a45cdc27ede4e348d404 Mon Sep 17 00:00:00 2001 From: ledwards2225 Date: Wed, 17 May 2023 21:26:09 +0000 Subject: [PATCH 13/18] aux relation fully integrated --- .../honk/proof_system/ultra_prover.cpp | 3 +- .../honk/proof_system/ultra_verifier.cpp | 3 +- .../honk/sumcheck/new_sumcheck.test.cpp | 52 ++- .../sumcheck/relations/auxiliary_relation.hpp | 90 +++-- .../relations/relation_correctness.test.cpp | 5 +- .../ultra_relation_consistency.test.cpp | 338 +++++++++--------- 6 files changed, 270 insertions(+), 221 deletions(-) diff --git a/cpp/src/barretenberg/honk/proof_system/ultra_prover.cpp b/cpp/src/barretenberg/honk/proof_system/ultra_prover.cpp index 2c48221fb6..09e265609a 100644 --- a/cpp/src/barretenberg/honk/proof_system/ultra_prover.cpp +++ b/cpp/src/barretenberg/honk/proof_system/ultra_prover.cpp @@ -196,7 +196,8 @@ template void UltraProver_::execute_relation_check_ sumcheck::UltraPermutationRelation, sumcheck::LookupRelation, sumcheck::GenPermSortRelation, - sumcheck::EllipticRelation>; + sumcheck::EllipticRelation, + sumcheck::AuxiliaryRelation>; auto sumcheck = Sumcheck(key->circuit_size, transcript); diff --git a/cpp/src/barretenberg/honk/proof_system/ultra_verifier.cpp b/cpp/src/barretenberg/honk/proof_system/ultra_verifier.cpp index 410438beeb..a321e2777b 100644 --- a/cpp/src/barretenberg/honk/proof_system/ultra_verifier.cpp +++ b/cpp/src/barretenberg/honk/proof_system/ultra_verifier.cpp @@ -113,7 +113,8 @@ template bool UltraVerifier_::verify_proof(const plonk honk::sumcheck::UltraPermutationRelation, honk::sumcheck::LookupRelation, honk::sumcheck::GenPermSortRelation, - honk::sumcheck::EllipticRelation>(circuit_size, transcript); + honk::sumcheck::EllipticRelation, + honk::sumcheck::AuxiliaryRelation>(circuit_size, transcript); std::optional sumcheck_output = sumcheck.execute_verifier(relation_parameters); diff --git a/cpp/src/barretenberg/honk/sumcheck/new_sumcheck.test.cpp b/cpp/src/barretenberg/honk/sumcheck/new_sumcheck.test.cpp index fb4e66845b..c040776be0 100644 --- a/cpp/src/barretenberg/honk/sumcheck/new_sumcheck.test.cpp +++ b/cpp/src/barretenberg/honk/sumcheck/new_sumcheck.test.cpp @@ -8,6 +8,7 @@ #include "relations/ultra_arithmetic_relation.hpp" #include "relations/gen_perm_sort_relation.hpp" #include "relations/elliptic_relation.hpp" +#include "relations/auxiliary_relation.hpp" #include "barretenberg/transcript/manifest.hpp" #include #include @@ -186,6 +187,51 @@ TEST(NewSumcheck, Ultra) ecc_add_gate gate{ x1, y1, x2, y2, x3, y3, beta_scalar, -1 }; composer.create_ecc_add_gate(gate); + // Add some RAM gates + uint32_t ram_values[8]{ + composer.add_variable(fr::random_element()), composer.add_variable(fr::random_element()), + composer.add_variable(fr::random_element()), composer.add_variable(fr::random_element()), + composer.add_variable(fr::random_element()), composer.add_variable(fr::random_element()), + composer.add_variable(fr::random_element()), composer.add_variable(fr::random_element()), + }; + + size_t ram_id = composer.create_RAM_array(8); + + for (size_t i = 0; i < 8; ++i) { + composer.init_RAM_element(ram_id, i, ram_values[i]); + } + + a_idx = composer.read_RAM_array(ram_id, composer.add_variable(5)); + EXPECT_EQ(a_idx != ram_values[5], true); + + b_idx = composer.read_RAM_array(ram_id, composer.add_variable(4)); + c_idx = composer.read_RAM_array(ram_id, composer.add_variable(1)); + + composer.write_RAM_array(ram_id, composer.add_variable(4), composer.add_variable(500)); + d_idx = composer.read_RAM_array(ram_id, composer.add_variable(4)); + + EXPECT_EQ(composer.get_variable(d_idx), 500); + + // ensure these vars get used in another arithmetic gate + const auto e_value = composer.get_variable(a_idx) + composer.get_variable(b_idx) + composer.get_variable(c_idx) + + composer.get_variable(d_idx); + e_idx = composer.add_variable(e_value); + + composer.create_big_add_gate({ a_idx, b_idx, c_idx, d_idx, -1, -1, -1, -1, 0 }, true); + composer.create_big_add_gate( + { + composer.get_zero_idx(), + composer.get_zero_idx(), + composer.get_zero_idx(), + e_idx, + 0, + 0, + 0, + 0, + 0, + }, + false); + // Create a prover (it will compute proving key and witness) auto prover = composer.create_prover(); @@ -275,7 +321,8 @@ TEST(NewSumcheck, Ultra) UltraPermutationRelation, LookupRelation, GenPermSortRelation, - EllipticRelation>(prover.key->circuit_size, prover_transcript); + EllipticRelation, + AuxiliaryRelation>(prover.key->circuit_size, prover_transcript); auto prover_output = sumcheck_prover.execute_prover(prover_polynomials, relation_parameters); @@ -287,7 +334,8 @@ TEST(NewSumcheck, Ultra) UltraPermutationRelation, LookupRelation, GenPermSortRelation, - EllipticRelation>(prover.key->circuit_size, verifier_transcript); + EllipticRelation, + AuxiliaryRelation>(prover.key->circuit_size, verifier_transcript); std::optional verifier_output = sumcheck_verifier.execute_verifier(relation_parameters); diff --git a/cpp/src/barretenberg/honk/sumcheck/relations/auxiliary_relation.hpp b/cpp/src/barretenberg/honk/sumcheck/relations/auxiliary_relation.hpp index 76410b663a..d4d12ae37e 100644 --- a/cpp/src/barretenberg/honk/sumcheck/relations/auxiliary_relation.hpp +++ b/cpp/src/barretenberg/honk/sumcheck/relations/auxiliary_relation.hpp @@ -11,19 +11,30 @@ namespace proof_system::honk::sumcheck { template class AuxiliaryRelation { public: // 1 + polynomial degree of this relation - static constexpr size_t RELATION_LENGTH = 6; // degree() = WORKTODO + static constexpr size_t RELATION_LENGTH = 6; + + static constexpr size_t NUM_CONSTRAINTS = 6; + static constexpr std::array CONSTRAINT_LENGTH = { 6, 6, 6, 6, 6, 6 }; // Each has degree 5 + + using RelationUnivariates = std::tuple, + Univariate, + Univariate, + Univariate, + Univariate, + Univariate>; + using RelationValues = std::array; /** * @brief Expression for the generalized permutation sort gate. * @details The relation is defined as C(extended_edges(X)...) = - * //WORKTODO + * // WORKTODO * * @param evals transformed to `evals + C(extended_edges(X)...)*scaling_factor` * @param extended_edges an std::array containing the fully extended Univariate edges. * @param parameters contains beta, gamma, and public_input_delta, .... * @param scaling_factor optional term to scale the evaluation before adding to evals. */ - void add_edge_contribution(Univariate& evals, + void add_edge_contribution(RelationUnivariates& evals, const auto& extended_edges, const RelationParameters& relation_parameters, const FF& scaling_factor) const @@ -32,7 +43,6 @@ template class AuxiliaryRelation { // See https://hackmd.io/xGLuj6biSsCjzQnYN-pEiA?both const auto& eta = relation_parameters.eta; - const auto fake_alpha = FF(1); auto w_1 = UnivariateView(extended_edges.w_l); auto w_2 = UnivariateView(extended_edges.w_r); @@ -177,11 +187,9 @@ template class AuxiliaryRelation { auto adjacent_values_match_if_adjacent_indices_match = (index_delta * FF(-1) + FF(1)) * record_delta; - auto ROM_consistency_check_identity = adjacent_values_match_if_adjacent_indices_match; - ROM_consistency_check_identity *= fake_alpha; - ROM_consistency_check_identity += index_is_monotonically_increasing; - ROM_consistency_check_identity *= fake_alpha; - ROM_consistency_check_identity += memory_record_check; + std::get<1>(evals) += adjacent_values_match_if_adjacent_indices_match * (q_1 * q_2) * (q_aux * scaling_factor); + std::get<2>(evals) += index_is_monotonically_increasing * (q_1 * q_2) * (q_aux * scaling_factor); + auto ROM_consistency_check_identity = memory_record_check * (q_1 * q_2); /** * RAM Consistency Check @@ -224,14 +232,11 @@ template class AuxiliaryRelation { auto next_gate_access_type_is_boolean = next_gate_access_type * next_gate_access_type - next_gate_access_type; // Putting it all together... - auto RAM_consistency_check_identity = - adjacent_values_match_if_adjacent_indices_match_and_next_access_is_a_read_operation; - RAM_consistency_check_identity *= fake_alpha; - RAM_consistency_check_identity += index_is_monotonically_increasing; - RAM_consistency_check_identity *= fake_alpha; - RAM_consistency_check_identity += next_gate_access_type_is_boolean; - RAM_consistency_check_identity *= fake_alpha; - RAM_consistency_check_identity += access_check; + std::get<3>(evals) += adjacent_values_match_if_adjacent_indices_match_and_next_access_is_a_read_operation * + (q_arith) * (q_aux * scaling_factor); + std::get<4>(evals) += index_is_monotonically_increasing * (q_arith) * (q_aux * scaling_factor); + std::get<5>(evals) += next_gate_access_type_is_boolean * (q_arith) * (q_aux * scaling_factor); + auto RAM_consistency_check_identity = access_check * (q_arith); /** * RAM Timestamp Consistency Check @@ -251,25 +256,21 @@ template class AuxiliaryRelation { * The complete RAM/ROM memory identity * */ - auto memory_identity = ROM_consistency_check_identity * q_2; - memory_identity += RAM_timestamp_check_identity * q_4; - memory_identity += memory_record_check * q_m; - memory_identity *= q_1; - memory_identity += (RAM_consistency_check_identity * q_arith); + auto memory_identity = ROM_consistency_check_identity; + memory_identity += RAM_timestamp_check_identity * (q_4 * q_1); + memory_identity += memory_record_check * (q_m * q_1); + memory_identity += RAM_consistency_check_identity; auto auxiliary_identity = memory_identity + non_native_field_identity + limb_accumulator_identity; - auxiliary_identity *= q_aux; - auxiliary_identity *= scaling_factor; - - evals += auxiliary_identity; + auxiliary_identity *= (q_aux * scaling_factor); + std::get<0>(evals) += auxiliary_identity; }; - void add_full_relation_value_contribution(FF& full_honk_relation_value, + void add_full_relation_value_contribution(RelationValues& full_honk_relation_value, const auto& purported_evaluations, const RelationParameters& relation_parameters) const { const auto& eta = relation_parameters.eta; - const auto fake_alpha = FF(1); auto w_1 = purported_evaluations.w_l; auto w_2 = purported_evaluations.w_r; @@ -417,11 +418,9 @@ template class AuxiliaryRelation { auto adjacent_values_match_if_adjacent_indices_match = (FF(1) - index_delta) * record_delta; - auto ROM_consistency_check_identity = adjacent_values_match_if_adjacent_indices_match; - ROM_consistency_check_identity *= fake_alpha; - ROM_consistency_check_identity += index_is_monotonically_increasing; - ROM_consistency_check_identity *= fake_alpha; - ROM_consistency_check_identity += memory_record_check; + std::get<1>(full_honk_relation_value) += adjacent_values_match_if_adjacent_indices_match * (q_1 * q_2) * q_aux; + std::get<2>(full_honk_relation_value) += index_is_monotonically_increasing * (q_1 * q_2) * q_aux; + auto ROM_consistency_check_identity = memory_record_check * (q_1 * q_2); /** * RAM Consistency Check @@ -465,14 +464,11 @@ template class AuxiliaryRelation { auto next_gate_access_type_is_boolean = next_gate_access_type.sqr() - next_gate_access_type; // Putting it all together... - auto RAM_consistency_check_identity = - adjacent_values_match_if_adjacent_indices_match_and_next_access_is_a_read_operation; - RAM_consistency_check_identity *= fake_alpha; - RAM_consistency_check_identity += index_is_monotonically_increasing; - RAM_consistency_check_identity *= fake_alpha; - RAM_consistency_check_identity += next_gate_access_type_is_boolean; - RAM_consistency_check_identity *= fake_alpha; - RAM_consistency_check_identity += access_check; + std::get<3>(full_honk_relation_value) += + adjacent_values_match_if_adjacent_indices_match_and_next_access_is_a_read_operation * (q_arith)*q_aux; + std::get<4>(full_honk_relation_value) += index_is_monotonically_increasing * (q_arith)*q_aux; + std::get<5>(full_honk_relation_value) += next_gate_access_type_is_boolean * (q_arith)*q_aux; + auto RAM_consistency_check_identity = access_check * (q_arith); /** * RAM Timestamp Consistency Check @@ -492,17 +488,15 @@ template class AuxiliaryRelation { * The complete RAM/ROM memory identity * */ - auto memory_identity = ROM_consistency_check_identity * q_2; - memory_identity += RAM_timestamp_check_identity * q_4; - memory_identity += memory_record_check * q_m; - memory_identity *= q_1; - memory_identity += (RAM_consistency_check_identity * q_arith); + auto memory_identity = ROM_consistency_check_identity; + memory_identity += RAM_timestamp_check_identity * q_1 * q_4; + memory_identity += memory_record_check * q_1 * q_m; + memory_identity += RAM_consistency_check_identity; // auto auxiliary_identity = limb_accumulator_identity; auto auxiliary_identity = memory_identity + non_native_field_identity + limb_accumulator_identity; auxiliary_identity *= q_aux; - - full_honk_relation_value += auxiliary_identity; + std::get<0>(full_honk_relation_value) += auxiliary_identity; }; }; } // namespace proof_system::honk::sumcheck diff --git a/cpp/src/barretenberg/honk/sumcheck/relations/relation_correctness.test.cpp b/cpp/src/barretenberg/honk/sumcheck/relations/relation_correctness.test.cpp index 2f11f9a3a4..0bed484c6d 100644 --- a/cpp/src/barretenberg/honk/sumcheck/relations/relation_correctness.test.cpp +++ b/cpp/src/barretenberg/honk/sumcheck/relations/relation_correctness.test.cpp @@ -377,8 +377,8 @@ TEST(RelationCorrectness, UltraRelationCorrectness) honk::sumcheck::UltraPermutationRelation(), honk::sumcheck::LookupRelation(), honk::sumcheck::GenPermSortRelation(), - honk::sumcheck::EllipticRelation()); - // honk::sumcheck::AuxiliaryRelation()); + honk::sumcheck::EllipticRelation(), + honk::sumcheck::AuxiliaryRelation()); // Check that each relation is satisfied across each row of the prover polynomials check_relation<0, Flavor>(relations, circuit_size, prover_polynomials, params); @@ -386,6 +386,7 @@ TEST(RelationCorrectness, UltraRelationCorrectness) check_relation<2, Flavor>(relations, circuit_size, prover_polynomials, params); check_relation<3, Flavor>(relations, circuit_size, prover_polynomials, params); check_relation<4, Flavor>(relations, circuit_size, prover_polynomials, params); + check_relation<5, Flavor>(relations, circuit_size, prover_polynomials, params); } } // namespace test_honk_relations diff --git a/cpp/src/barretenberg/honk/sumcheck/relations/ultra_relation_consistency.test.cpp b/cpp/src/barretenberg/honk/sumcheck/relations/ultra_relation_consistency.test.cpp index 0ebe5c63d2..5920aadb17 100644 --- a/cpp/src/barretenberg/honk/sumcheck/relations/ultra_relation_consistency.test.cpp +++ b/cpp/src/barretenberg/honk/sumcheck/relations/ultra_relation_consistency.test.cpp @@ -495,184 +495,188 @@ TEST_F(UltraRelationConsistency, EllipticRelation) validate_evaluations(expected_full_length_univariates, relation, extended_edges, relation_parameters); }; -// TEST_F(UltraRelationConsistency, AuxiliaryRelation) -// { -// using Flavor = honk::flavor::Ultra; -// using FF = typename Flavor::FF; -// using Flavor = honk::flavor::Ultra; -// static constexpr size_t FULL_RELATION_LENGTH = 6; -// using ExtendedEdges = typename Flavor::ExtendedEdges; -// static const size_t NUM_POLYNOMIALS = Flavor::NUM_ALL_ENTITIES; -// auto relation_parameters = compute_mock_relation_parameters(); -// ExtendedEdges extended_edges; -// std::array, NUM_POLYNOMIALS> input_polynomials; - -// // input_univariates are random polynomials of degree one -// for (size_t i = 0; i < NUM_POLYNOMIALS; ++i) { -// input_polynomials[i] = Univariate({ FF::random_element(), FF::random_element() -// }); -// } -// compute_mock_extended_edges(extended_edges, input_polynomials); - -// auto relation = AuxiliaryRelation(); - -// const auto& eta = relation_parameters.eta; -// const auto fake_alpha = FF(1); - -// // Extract the extended edges for manual computation of relation contribution -// const auto& w_1 = extended_edges.w_l; -// const auto& w_2 = extended_edges.w_r; -// const auto& w_3 = extended_edges.w_o; -// const auto& w_4 = extended_edges.w_4; -// const auto& w_1_shift = extended_edges.w_l_shift; -// const auto& w_2_shift = extended_edges.w_r_shift; -// const auto& w_3_shift = extended_edges.w_o_shift; -// const auto& w_4_shift = extended_edges.w_4_shift; - -// const auto& q_1 = extended_edges.q_l; -// const auto& q_2 = extended_edges.q_r; -// const auto& q_3 = extended_edges.q_o; -// const auto& q_4 = extended_edges.q_4; -// const auto& q_m = extended_edges.q_m; -// const auto& q_c = extended_edges.q_c; -// const auto& q_arith = extended_edges.q_arith; -// const auto& q_aux = extended_edges.q_aux; - -// constexpr FF LIMB_SIZE(uint256_t(1) << 68); -// constexpr FF SUBLIMB_SHIFT(uint256_t(1) << 14); -// constexpr FF SUBLIMB_SHIFT_2(SUBLIMB_SHIFT * SUBLIMB_SHIFT); -// constexpr FF SUBLIMB_SHIFT_3(SUBLIMB_SHIFT_2 * SUBLIMB_SHIFT); -// constexpr FF SUBLIMB_SHIFT_4(SUBLIMB_SHIFT_3 * SUBLIMB_SHIFT); +TEST_F(UltraRelationConsistency, AuxiliaryRelation) +{ + using Flavor = honk::flavor::Ultra; + using FF = typename Flavor::FF; + using Flavor = honk::flavor::Ultra; + static constexpr size_t FULL_RELATION_LENGTH = 6; + using ExtendedEdges = typename Flavor::ExtendedEdges; + static const size_t NUM_POLYNOMIALS = Flavor::NUM_ALL_ENTITIES; + auto relation_parameters = compute_mock_relation_parameters(); + ExtendedEdges extended_edges; + std::array, NUM_POLYNOMIALS> input_polynomials; -/** - * Non native field arithmetic gate 2 - * - * _ _ - * / _ _ _ 14 \ - * q_2 . q_4 | (w_1 . w_2) + (w_1 . w_2) + (w_1 . w_4 + w_2 . w_3 - w_3) . 2 - w_3 - w_4 | - * \_ _/ - * - **/ -// auto limb_subproduct = w_1 * w_2_shift + w_1_shift * w_2; -// auto non_native_field_gate_2 = (w_1 * w_4 + w_2 * w_3 - w_3_shift); -// non_native_field_gate_2 *= LIMB_SIZE; -// non_native_field_gate_2 -= w_4_shift; -// non_native_field_gate_2 += limb_subproduct; -// non_native_field_gate_2 *= q_4; - -// limb_subproduct *= LIMB_SIZE; -// limb_subproduct += (w_1_shift * w_2_shift); -// auto non_native_field_gate_1 = limb_subproduct; -// non_native_field_gate_1 -= (w_3 + w_4); -// non_native_field_gate_1 *= q_3; - -// auto non_native_field_gate_3 = limb_subproduct; -// non_native_field_gate_3 += w_4; -// non_native_field_gate_3 -= (w_3_shift + w_4_shift); -// non_native_field_gate_3 *= q_m; - -// auto non_native_field_identity = non_native_field_gate_1 + non_native_field_gate_2 + non_native_field_gate_3; -// non_native_field_identity *= q_2; - -// auto limb_accumulator_1 = w_1 + w_2 * SUBLIMB_SHIFT + w_3 * SUBLIMB_SHIFT_2 + w_1_shift * SUBLIMB_SHIFT_3 + -// w_2_shift * SUBLIMB_SHIFT_4 - w_4; -// limb_accumulator_1 *= q_4; - -// auto limb_accumulator_2 = w_3 + w_4 * SUBLIMB_SHIFT + w_1_shift * SUBLIMB_SHIFT_2 + w_2_shift * SUBLIMB_SHIFT_3 + -// w_3_shift * SUBLIMB_SHIFT_4 - w_4_shift; -// limb_accumulator_2 *= q_m; - -// auto limb_accumulator_identity = limb_accumulator_1 + limb_accumulator_2; -// limb_accumulator_identity *= q_3; + // input_univariates are random polynomials of degree one + for (size_t i = 0; i < NUM_POLYNOMIALS; ++i) { + input_polynomials[i] = Univariate({ FF::random_element(), FF::random_element() }); + } + compute_mock_extended_edges(extended_edges, input_polynomials); -/** - * MEMORY - **/ + auto relation = AuxiliaryRelation(); -/** - * Memory Record Check - */ -// auto memory_record_check = w_3; -// memory_record_check *= eta; -// memory_record_check += w_2; -// memory_record_check *= eta; -// memory_record_check += w_1; -// memory_record_check *= eta; -// memory_record_check += q_c; -// auto partial_record_check = memory_record_check; // used in RAM consistency check -// memory_record_check = memory_record_check - w_4; + const auto& eta = relation_parameters.eta; + const auto fake_alpha = FF(1); -/** - * ROM Consistency Check - */ -// auto index_delta = w_1_shift - w_1; -// auto record_delta = w_4_shift - w_4; + // Extract the extended edges for manual computation of relation contribution + const auto& w_1 = extended_edges.w_l; + const auto& w_2 = extended_edges.w_r; + const auto& w_3 = extended_edges.w_o; + const auto& w_4 = extended_edges.w_4; + const auto& w_1_shift = extended_edges.w_l_shift; + const auto& w_2_shift = extended_edges.w_r_shift; + const auto& w_3_shift = extended_edges.w_o_shift; + const auto& w_4_shift = extended_edges.w_4_shift; -// auto index_is_monotonically_increasing = index_delta * index_delta - index_delta; + const auto& q_1 = extended_edges.q_l; + const auto& q_2 = extended_edges.q_r; + const auto& q_3 = extended_edges.q_o; + const auto& q_4 = extended_edges.q_4; + const auto& q_m = extended_edges.q_m; + const auto& q_c = extended_edges.q_c; + const auto& q_arith = extended_edges.q_arith; + const auto& q_aux = extended_edges.q_aux; -// // auto adjacent_values_match_if_adjacent_indices_match = (FF(1) - index_delta) * record_delta; -// auto adjacent_values_match_if_adjacent_indices_match = (index_delta * FF(-1) + FF(1)) * record_delta; + constexpr std::size_t NUM_CONSTRAINTS = decltype(relation)::NUM_CONSTRAINTS; + auto expected_full_length_univariates = std::array, NUM_CONSTRAINTS>(); -// auto ROM_consistency_check_identity = adjacent_values_match_if_adjacent_indices_match; -// ROM_consistency_check_identity *= fake_alpha; -// ROM_consistency_check_identity += index_is_monotonically_increasing; -// ROM_consistency_check_identity *= fake_alpha; -// ROM_consistency_check_identity += memory_record_check; + constexpr FF LIMB_SIZE(uint256_t(1) << 68); + constexpr FF SUBLIMB_SHIFT(uint256_t(1) << 14); + constexpr FF SUBLIMB_SHIFT_2(SUBLIMB_SHIFT * SUBLIMB_SHIFT); + constexpr FF SUBLIMB_SHIFT_3(SUBLIMB_SHIFT_2 * SUBLIMB_SHIFT); + constexpr FF SUBLIMB_SHIFT_4(SUBLIMB_SHIFT_3 * SUBLIMB_SHIFT); -/** - * RAM Consistency Check - */ -// auto access_type = (w_4 - partial_record_check); // will be 0 or 1 for honest Prover -// auto access_check = access_type * access_type - access_type; // check value is 0 or 1 - -// auto next_gate_access_type = w_3_shift; -// next_gate_access_type *= eta; -// next_gate_access_type += w_2_shift; -// next_gate_access_type *= eta; -// next_gate_access_type += w_1_shift; -// next_gate_access_type *= eta; -// next_gate_access_type = w_4_shift - next_gate_access_type; - -// auto value_delta = w_3_shift - w_3; -// auto adjacent_values_match_if_adjacent_indices_match_and_next_access_is_a_read_operation = -// (index_delta * FF(-1) + FF(1)) * value_delta * (next_gate_access_type * FF(-1) + FF(1)); - -// // We can't apply the RAM consistency check identity on the final entry in the sorted list (the wires in the -// // next gate would make the identity fail). -// // We need to validate that its 'access type' bool is correct. Can't do -// // with an arithmetic gate because of the `eta` factors. We need to check that the *next* gate's access type is -// // correct, to cover this edge case -// auto next_gate_access_type_is_boolean = next_gate_access_type * next_gate_access_type - next_gate_access_type; - -// // Putting it all together... -// auto RAM_consistency_check_identity = -// adjacent_values_match_if_adjacent_indices_match_and_next_access_is_a_read_operation; -// RAM_consistency_check_identity *= fake_alpha; -// RAM_consistency_check_identity += index_is_monotonically_increasing; -// RAM_consistency_check_identity *= fake_alpha; -// RAM_consistency_check_identity += next_gate_access_type_is_boolean; -// RAM_consistency_check_identity *= fake_alpha; -// RAM_consistency_check_identity += access_check; + /** + * Non native field arithmetic gate 2 + * + * _ _ + * / _ _ _ 14 \ + * q_2 . q_4 | (w_1 . w_2) + (w_1 . w_2) + (w_1 . w_4 + w_2 . w_3 - w_3) . 2 - w_3 - w_4 | + * \_ _/ + * + **/ + auto limb_subproduct = w_1 * w_2_shift + w_1_shift * w_2; + auto non_native_field_gate_2 = (w_1 * w_4 + w_2 * w_3 - w_3_shift); + non_native_field_gate_2 *= LIMB_SIZE; + non_native_field_gate_2 -= w_4_shift; + non_native_field_gate_2 += limb_subproduct; -/** - * RAM Timestamp Consistency Check - */ -// auto timestamp_delta = w_2_shift - w_2; -// auto RAM_timestamp_check_identity = (index_delta * FF(-1) + FF(1)) * timestamp_delta - w_3; + limb_subproduct *= LIMB_SIZE; + limb_subproduct += (w_1_shift * w_2_shift); + auto non_native_field_gate_1 = limb_subproduct; + non_native_field_gate_1 -= (w_3 + w_4); -/** - * The complete RAM/ROM memory identity - */ -// auto memory_identity = ROM_consistency_check_identity * q_2; -// memory_identity += RAM_timestamp_check_identity * q_4; -// memory_identity += memory_record_check * q_m; -// memory_identity *= q_1; -// memory_identity += (RAM_consistency_check_identity * q_arith); + auto non_native_field_gate_3 = limb_subproduct; + non_native_field_gate_3 += w_4; + non_native_field_gate_3 -= (w_3_shift + w_4_shift); + + auto non_native_field_identity = q_2 * q_3 * non_native_field_gate_1; + non_native_field_identity += q_2 * q_4 * non_native_field_gate_2; + non_native_field_identity += q_2 * q_m * non_native_field_gate_3; + + auto limb_accumulator_1 = w_1 + w_2 * SUBLIMB_SHIFT + w_3 * SUBLIMB_SHIFT_2 + w_1_shift * SUBLIMB_SHIFT_3 + + w_2_shift * SUBLIMB_SHIFT_4 - w_4; + + auto limb_accumulator_2 = w_3 + w_4 * SUBLIMB_SHIFT + w_1_shift * SUBLIMB_SHIFT_2 + w_2_shift * SUBLIMB_SHIFT_3 + + w_3_shift * SUBLIMB_SHIFT_4 - w_4_shift; + + auto limb_accumulator_identity = q_3 * q_4 * limb_accumulator_1; + limb_accumulator_identity += q_3 * q_m * limb_accumulator_2; + + /** + * MEMORY + **/ + + /** + * Memory Record Check + */ + auto memory_record_check = w_3; + memory_record_check *= eta; + memory_record_check += w_2; + memory_record_check *= eta; + memory_record_check += w_1; + memory_record_check *= eta; + memory_record_check += q_c; + auto partial_record_check = memory_record_check; // used in RAM consistency check + memory_record_check = memory_record_check - w_4; + + /** + * ROM Consistency Check + */ + auto index_delta = w_1_shift - w_1; + auto record_delta = w_4_shift - w_4; -// auto expected_evals = memory_identity + non_native_field_identity + limb_accumulator_identity; -// expected_evals *= q_aux; + auto index_is_monotonically_increasing = index_delta * index_delta - index_delta; -// validate_evaluations(expected_evals, relation, extended_edges, relation_parameters); -// }; + // auto adjacent_values_match_if_adjacent_indices_match = (FF(1) - index_delta) * record_delta; + auto adjacent_values_match_if_adjacent_indices_match = (index_delta * FF(-1) + FF(1)) * record_delta; + + expected_full_length_univariates[1] = adjacent_values_match_if_adjacent_indices_match * (q_1 * q_2); + expected_full_length_univariates[2] = index_is_monotonically_increasing * (q_1 * q_2); + auto ROM_consistency_check_identity = memory_record_check * (q_1 * q_2); + + /** + * RAM Consistency Check + */ + auto access_type = (w_4 - partial_record_check); // will be 0 or 1 for honest Prover + auto access_check = access_type * access_type - access_type; // check value is 0 or 1 + + auto next_gate_access_type = w_3_shift; + next_gate_access_type *= eta; + next_gate_access_type += w_2_shift; + next_gate_access_type *= eta; + next_gate_access_type += w_1_shift; + next_gate_access_type *= eta; + next_gate_access_type = w_4_shift - next_gate_access_type; + + auto value_delta = w_3_shift - w_3; + auto adjacent_values_match_if_adjacent_indices_match_and_next_access_is_a_read_operation = + (index_delta * FF(-1) + FF(1)) * value_delta * (next_gate_access_type * FF(-1) + FF(1)); + + // We can't apply the RAM consistency check identity on the final entry in the sorted list (the wires in the + // next gate would make the identity fail). + // We need to validate that its 'access type' bool is correct. Can't do + // with an arithmetic gate because of the `eta` factors. We need to check that the *next* gate's access type is + // correct, to cover this edge case + auto next_gate_access_type_is_boolean = next_gate_access_type * next_gate_access_type - next_gate_access_type; + + // Putting it all together... + expected_full_length_univariates[3] = + adjacent_values_match_if_adjacent_indices_match_and_next_access_is_a_read_operation * (q_arith); + expected_full_length_univariates[4] = index_is_monotonically_increasing * (q_arith); + expected_full_length_univariates[5] = next_gate_access_type_is_boolean * (q_arith); + auto RAM_consistency_check_identity = access_check * (q_arith); + + /** + * RAM/ROM access check gate + */ + memory_record_check *= (q_1 * q_m); + + /** + * RAM Timestamp Consistency Check + */ + auto timestamp_delta = w_2_shift - w_2; + auto RAM_timestamp_check_identity = (index_delta * FF(-1) + FF(1)) * timestamp_delta - w_3; + RAM_timestamp_check_identity *= (q_1 * q_4); + + /** + * The complete RAM/ROM memory identity + */ + auto memory_identity = ROM_consistency_check_identity; + memory_identity += RAM_timestamp_check_identity; + memory_identity += memory_record_check; + memory_identity += RAM_consistency_check_identity; + + expected_full_length_univariates[0] = memory_identity + non_native_field_identity + limb_accumulator_identity; + + expected_full_length_univariates[0] *= q_aux; + expected_full_length_univariates[1] *= q_aux; + expected_full_length_univariates[2] *= q_aux; + expected_full_length_univariates[3] *= q_aux; + expected_full_length_univariates[4] *= q_aux; + expected_full_length_univariates[5] *= q_aux; + + validate_evaluations(expected_full_length_univariates, relation, extended_edges, relation_parameters); +}; } // namespace proof_system::honk_relation_tests From a72c80d353f0781b80dac58edbce474e6549f1e3 Mon Sep 17 00:00:00 2001 From: ledwards2225 Date: Wed, 17 May 2023 22:01:17 +0000 Subject: [PATCH 14/18] cleanup and address some WORKTODOs --- .../honk/sumcheck/new_sumcheck.test.cpp | 84 -- .../relations/permutation_relation.hpp | 1 - .../relations/relation_correctness.test.cpp | 24 +- .../relations/ultra_arithmetic_relation.hpp | 1 - .../honk/sumcheck/sumcheck_round.hpp | 1 - .../honk/sumcheck/sumcheck_round.test.cpp | 718 +++++++++--------- 6 files changed, 381 insertions(+), 448 deletions(-) diff --git a/cpp/src/barretenberg/honk/sumcheck/new_sumcheck.test.cpp b/cpp/src/barretenberg/honk/sumcheck/new_sumcheck.test.cpp index c040776be0..a3f7cfaa59 100644 --- a/cpp/src/barretenberg/honk/sumcheck/new_sumcheck.test.cpp +++ b/cpp/src/barretenberg/honk/sumcheck/new_sumcheck.test.cpp @@ -341,88 +341,4 @@ TEST(NewSumcheck, Ultra) ASSERT_TRUE(verifier_output.has_value()); } - -// WORKTODO: move these utility tests to SumcheckRound tests -TEST(NewSumcheck, TupleOfTuplesOfUnivariates) -{ - using Flavor = honk::flavor::Standard; - using FF = typename Flavor::FF; - - // Define three linear univariates of different sizes - Univariate univariate_1({ 1, 2, 3 }); - Univariate univariate_2({ 2, 4 }); - Univariate univariate_3({ 3, 4, 5, 6, 7 }); - const size_t MAX_LENGTH = 5; - - // Instantiate some barycentric extension utility classes - auto barycentric_util_1 = BarycentricData(); - auto barycentric_util_2 = BarycentricData(); - auto barycentric_util_3 = BarycentricData(); - - // Construct a tuple of tuples of the form { {univariate_1}, {univariate_2, univariate_3} } - auto tuple_of_tuples = std::make_tuple(std::make_tuple(univariate_1), std::make_tuple(univariate_2, univariate_3)); - - // Use scale_univariate_accumulators to scale by challenge powers - FF challenge = 5; - FF running_challenge = 1; - SumcheckRound::scale_univariates(tuple_of_tuples, challenge, running_challenge); - - // Use extend_and_batch_univariates to extend to MAX_LENGTH then accumulate - auto result = Univariate(); - SumcheckRound::extend_and_batch_univariates(tuple_of_tuples, result); - - // Repeat the batching process manually - auto result_expected = barycentric_util_1.extend(univariate_1) * 1 + - barycentric_util_2.extend(univariate_2) * challenge + - barycentric_util_3.extend(univariate_3) * challenge * challenge; - - // Compare final batched univarites - EXPECT_EQ(result, result_expected); - - // Reinitialize univariate accumulators to zero - SumcheckRound::zero_univariates(tuple_of_tuples); - - // Check that reinitialization was successful - Univariate expected_1({ 0, 0, 0 }); - Univariate expected_2({ 0, 0 }); - Univariate expected_3({ 0, 0, 0, 0, 0 }); - EXPECT_EQ(std::get<0>(std::get<0>(tuple_of_tuples)), expected_1); - EXPECT_EQ(std::get<0>(std::get<1>(tuple_of_tuples)), expected_2); - EXPECT_EQ(std::get<1>(std::get<1>(tuple_of_tuples)), expected_3); -} - -TEST(NewSumcheck, TuplesOfEvaluationArrays) -{ - using Flavor = honk::flavor::Standard; - using FF = typename Flavor::FF; - - // Define two arrays of arbitrary elements - std::array evaluations_1 = { 4 }; - std::array evaluations_2 = { 6, 2 }; - - // Construct a tuple - auto tuple_of_arrays = std::make_tuple(evaluations_1, evaluations_2); - - // Use scale_and_batch_elements to scale by challenge powers - FF challenge = 5; - FF running_challenge = 1; - FF result = 0; - SumcheckRound::scale_and_batch_elements( - tuple_of_arrays, challenge, running_challenge, result); - - // Repeat the batching process manually - auto result_expected = - evaluations_1[0] * 1 + evaluations_2[0] * challenge + evaluations_2[1] * challenge * challenge; - - // Compare batched result - EXPECT_EQ(result, result_expected); - - // Reinitialize univariate accumulators to zero - SumcheckRound::zero_elements(tuple_of_arrays); - - EXPECT_EQ(std::get<0>(tuple_of_arrays)[0], 0); - EXPECT_EQ(std::get<1>(tuple_of_arrays)[0], 0); - EXPECT_EQ(std::get<1>(tuple_of_arrays)[1], 0); -} - } // namespace test_sumcheck_new diff --git a/cpp/src/barretenberg/honk/sumcheck/relations/permutation_relation.hpp b/cpp/src/barretenberg/honk/sumcheck/relations/permutation_relation.hpp index 27100d865e..4a993a9639 100644 --- a/cpp/src/barretenberg/honk/sumcheck/relations/permutation_relation.hpp +++ b/cpp/src/barretenberg/honk/sumcheck/relations/permutation_relation.hpp @@ -8,7 +8,6 @@ namespace proof_system::honk::sumcheck { template class PermutationRelation { public: // 1 + polynomial degree of this relation - // WORKTODO: change this in all relations to be MAX_CONSTRAINT_LENGTH or something? static constexpr size_t RELATION_LENGTH = 5; static constexpr size_t NUM_CONSTRAINTS = 2; diff --git a/cpp/src/barretenberg/honk/sumcheck/relations/relation_correctness.test.cpp b/cpp/src/barretenberg/honk/sumcheck/relations/relation_correctness.test.cpp index 0bed484c6d..c76fc548a9 100644 --- a/cpp/src/barretenberg/honk/sumcheck/relations/relation_correctness.test.cpp +++ b/cpp/src/barretenberg/honk/sumcheck/relations/relation_correctness.test.cpp @@ -31,9 +31,7 @@ void ensure_non_zero(auto& polynomial) * @tparam relation_idx Index into a tuple of provided relations * @tparam Flavor */ -// WORKTODO: pass single relation instead of all of them? -template -void check_relation(auto relations, auto circuit_size, auto polynomials, auto params) +template void check_relation(auto relation, auto circuit_size, auto polynomials, auto params) { using PurportedEvaluations = typename Flavor::PurportedEvaluations; for (size_t i = 0; i < circuit_size; i++) { @@ -47,14 +45,14 @@ void check_relation(auto relations, auto circuit_size, auto polynomials, auto pa } // Define the appropriate RelationValues type for this relation and initialize to zero - using RelationValues = typename std::tuple_element::type::RelationValues; + using RelationValues = typename decltype(relation)::RelationValues; RelationValues result; for (auto& element : result) { element = 0; } // Evaluate each constraint in the relation and check that each is satisfied - std::get(relations).add_full_relation_value_contribution(result, evaluations_at_index_i, params); + relation.add_full_relation_value_contribution(result, evaluations_at_index_i, params); for (auto& element : result) { ASSERT_EQ(element, 0); } @@ -144,8 +142,8 @@ TEST(RelationCorrectness, StandardRelationCorrectness) auto relations = std::tuple(honk::sumcheck::ArithmeticRelation(), honk::sumcheck::PermutationRelation()); // Check that each relation is satisfied across each row of the prover polynomials - check_relation<0, Flavor>(relations, circuit_size, prover_polynomials, params); - check_relation<1, Flavor>(relations, circuit_size, prover_polynomials, params); + check_relation(std::get<0>(relations), circuit_size, prover_polynomials, params); + check_relation(std::get<1>(relations), circuit_size, prover_polynomials, params); } /** @@ -381,12 +379,12 @@ TEST(RelationCorrectness, UltraRelationCorrectness) honk::sumcheck::AuxiliaryRelation()); // Check that each relation is satisfied across each row of the prover polynomials - check_relation<0, Flavor>(relations, circuit_size, prover_polynomials, params); - check_relation<1, Flavor>(relations, circuit_size, prover_polynomials, params); - check_relation<2, Flavor>(relations, circuit_size, prover_polynomials, params); - check_relation<3, Flavor>(relations, circuit_size, prover_polynomials, params); - check_relation<4, Flavor>(relations, circuit_size, prover_polynomials, params); - check_relation<5, Flavor>(relations, circuit_size, prover_polynomials, params); + check_relation(std::get<0>(relations), circuit_size, prover_polynomials, params); + check_relation(std::get<1>(relations), circuit_size, prover_polynomials, params); + check_relation(std::get<2>(relations), circuit_size, prover_polynomials, params); + check_relation(std::get<3>(relations), circuit_size, prover_polynomials, params); + check_relation(std::get<4>(relations), circuit_size, prover_polynomials, params); + check_relation(std::get<5>(relations), circuit_size, prover_polynomials, params); } } // namespace test_honk_relations diff --git a/cpp/src/barretenberg/honk/sumcheck/relations/ultra_arithmetic_relation.hpp b/cpp/src/barretenberg/honk/sumcheck/relations/ultra_arithmetic_relation.hpp index a62046a8e9..83e0e9dc3f 100644 --- a/cpp/src/barretenberg/honk/sumcheck/relations/ultra_arithmetic_relation.hpp +++ b/cpp/src/barretenberg/honk/sumcheck/relations/ultra_arithmetic_relation.hpp @@ -7,7 +7,6 @@ namespace proof_system::honk::sumcheck { -// WORKTODO: fix formatting around scopes in this file template class UltraArithmeticRelation { public: // 1 + polynomial degree of this relation diff --git a/cpp/src/barretenberg/honk/sumcheck/sumcheck_round.hpp b/cpp/src/barretenberg/honk/sumcheck/sumcheck_round.hpp index f548f1b561..934bd1d75d 100644 --- a/cpp/src/barretenberg/honk/sumcheck/sumcheck_round.hpp +++ b/cpp/src/barretenberg/honk/sumcheck/sumcheck_round.hpp @@ -273,7 +273,6 @@ template class... Relations> class SumcheckRo } } - // WORKTODO: make these private (need to make test suite a friend?) public: /** * Utility methods for tuple of tuples of Univariates diff --git a/cpp/src/barretenberg/honk/sumcheck/sumcheck_round.test.cpp b/cpp/src/barretenberg/honk/sumcheck/sumcheck_round.test.cpp index d5afe3ee67..85c9312d06 100644 --- a/cpp/src/barretenberg/honk/sumcheck/sumcheck_round.test.cpp +++ b/cpp/src/barretenberg/honk/sumcheck/sumcheck_round.test.cpp @@ -1,348 +1,370 @@ -// #include "sumcheck_round.hpp" -// #include "relations/arithmetic_relation.hpp" -// #include "relations/permutation_relation.hpp" -// #include "polynomials/univariate.hpp" -// #include "barretenberg/ecc/curves/bn254/fr.hpp" -// #include "barretenberg/numeric/random/engine.hpp" -// #include "barretenberg/honk/flavor/standard.hpp" - -// #include - -// #include "barretenberg/common/mem.hpp" -// #include -// /** -// * We want to test if the univariate (S_l in the thesis) computed by the prover in a particular round is correct. We -// * also want to verify given the purported evaluations of all the relevant polynomials, the verifer can correctly -// verify -// * the purported evaluation of S_l. For the prover, we use a couple of methods to compute the univariate by the -// sumcheck -// * method `compute_univariate` and by step by step manual computation respectively. For the verifier, we follow a -// * similar approach. -// */ - -// using namespace proof_system::honk; -// using namespace proof_system::honk::sumcheck; - -// using Flavor = flavor::Standard; -// using FF = typename Flavor::FF; -// using ProverPolynomials = typename Flavor::ProverPolynomials; -// using PurportedEvaluations = typename Flavor::PurportedEvaluations; - -// const size_t NUM_POLYNOMIALS = Flavor::NUM_ALL_ENTITIES; -// const size_t max_relation_length = 5; -// const size_t input_polynomial_length = 2; - -// namespace test_sumcheck_round { -// template -// void construct_full_polynomials(ProverPolynomials& full_polynomials, -// std::array& w_l, -// std::array& w_r, -// std::array& w_o, -// std::array& z_perm, -// std::array& z_perm_shift, -// std::array& q_m, -// std::array& q_l, -// std::array& q_r, -// std::array& q_o, -// std::array& q_c, -// std::array& sigma_1, -// std::array& sigma_2, -// std::array& sigma_3, -// std::array& id_1, -// std::array& id_2, -// std::array& id_3, -// std::array& lagrange_first, -// std::array& lagrange_last) -// { -// full_polynomials.w_l = w_l; -// full_polynomials.w_r = w_r; -// full_polynomials.w_o = w_o; -// full_polynomials.z_perm = z_perm; -// full_polynomials.z_perm_shift = z_perm_shift; -// full_polynomials.q_m = q_m; -// full_polynomials.q_l = q_l; -// full_polynomials.q_r = q_r; -// full_polynomials.q_o = q_o; -// full_polynomials.q_c = q_c; -// full_polynomials.sigma_1 = sigma_1; -// full_polynomials.sigma_2 = sigma_2; -// full_polynomials.sigma_3 = sigma_3; -// full_polynomials.id_1 = id_1; -// full_polynomials.id_2 = id_2; -// full_polynomials.id_3 = id_3; -// full_polynomials.lagrange_first = lagrange_first; -// full_polynomials.lagrange_last = lagrange_last; -// } - -// // The below two methods are used in the test ComputeUnivariateProver -// static Univariate compute_round_univariate( -// std::array, NUM_POLYNOMIALS>& input_polynomials, -// const RelationParameters& relation_parameters, -// const FF alpha) -// { -// size_t round_size = 1; -// auto relations = std::tuple( -// ArithmeticRelation(), PermutationRelation(), GrandProductInitializationRelation()); -// // Improvement(Cody): This is ugly? Maye supply some/all of this data through "flavor" class? -// auto round = -// SumcheckRound( -// round_size, relations); -// auto w_l = input_polynomials[0]; -// auto w_r = input_polynomials[1]; -// auto w_o = input_polynomials[2]; -// auto z_perm = input_polynomials[3]; -// auto z_perm_shift = input_polynomials[4]; -// auto q_m = input_polynomials[5]; -// auto q_l = input_polynomials[6]; -// auto q_r = input_polynomials[7]; -// auto q_o = input_polynomials[8]; -// auto q_c = input_polynomials[9]; -// auto sigma_1 = input_polynomials[10]; -// auto sigma_2 = input_polynomials[11]; -// auto sigma_3 = input_polynomials[12]; -// auto id_1 = input_polynomials[13]; -// auto id_2 = input_polynomials[14]; -// auto id_3 = input_polynomials[15]; -// auto lagrange_first = input_polynomials[16]; -// auto lagrange_last = input_polynomials[17]; - -// ProverPolynomials full_polynomials; -// construct_full_polynomials(full_polynomials, -// w_l, -// w_r, -// w_o, -// z_perm, -// z_perm_shift, -// q_m, -// q_l, -// q_r, -// q_o, -// q_c, -// sigma_1, -// sigma_2, -// sigma_3, -// id_1, -// id_2, -// id_3, -// lagrange_first, -// lagrange_last); -// PowUnivariate pow_zeta(1); -// Univariate round_univariate = -// round.compute_univariate(full_polynomials, relation_parameters, pow_zeta, alpha); -// return round_univariate; -// } - -// static Univariate compute_expected_round_univariate( -// std::array, NUM_POLYNOMIALS>& input_univariates, -// const RelationParameters& relation_parameters, -// const FF alpha) -// { -// BarycentricData barycentric_2_to_max = -// BarycentricData(); -// std::array, NUM_POLYNOMIALS> extended_univariates; -// for (size_t i = 0; i < NUM_POLYNOMIALS; ++i) { -// extended_univariates[i] = barycentric_2_to_max.extend(input_univariates[i]); -// } -// auto w_l_univariate = Univariate(extended_univariates[0]); -// auto w_r_univariate = Univariate(extended_univariates[1]); -// auto w_o_univariate = Univariate(extended_univariates[2]); -// auto z_perm_univariate = Univariate(extended_univariates[3]); -// auto z_perm_shift_univariate = -// Univariate(extended_univariates[4]); // this is not real shifted data -// auto q_m_univariate = Univariate(extended_univariates[5]); -// auto q_l_univariate = Univariate(extended_univariates[6]); -// auto q_r_univariate = Univariate(extended_univariates[7]); -// auto q_o_univariate = Univariate(extended_univariates[8]); -// auto q_c_univariate = Univariate(extended_univariates[9]); -// auto sigma_1_univariate = Univariate(extended_univariates[10]); -// auto sigma_2_univariate = Univariate(extended_univariates[11]); -// auto sigma_3_univariate = Univariate(extended_univariates[12]); -// auto id_1_univariate = Univariate(extended_univariates[13]); -// auto id_2_univariate = Univariate(extended_univariates[14]); -// auto id_3_univariate = Univariate(extended_univariates[15]); -// auto lagrange_first_univariate = Univariate(extended_univariates[16]); -// auto lagrange_last_univariate = Univariate(extended_univariates[17]); - -// auto expected_arithmetic_relation = -// ((q_m_univariate * w_r_univariate * w_l_univariate) + (q_r_univariate * w_r_univariate) + -// (q_l_univariate * w_l_univariate) + (q_o_univariate * w_o_univariate) + (q_c_univariate)); -// auto expected_grand_product_computation_relation = -// ((z_perm_univariate + lagrange_first_univariate) * -// (w_l_univariate + id_1_univariate * relation_parameters.beta + relation_parameters.gamma) * -// (w_r_univariate + id_2_univariate * relation_parameters.beta + relation_parameters.gamma) * -// (w_o_univariate + id_3_univariate * relation_parameters.beta + relation_parameters.gamma)); -// expected_grand_product_computation_relation -= -// ((z_perm_shift_univariate + lagrange_last_univariate * relation_parameters.public_input_delta) * -// (w_l_univariate + sigma_1_univariate * relation_parameters.beta + relation_parameters.gamma) * -// (w_r_univariate + sigma_2_univariate * relation_parameters.beta + relation_parameters.gamma) * -// (w_o_univariate + sigma_3_univariate * relation_parameters.beta + relation_parameters.gamma)); -// auto expected_grand_product_initialization_relation = (z_perm_shift_univariate * lagrange_last_univariate); -// Univariate expected_round_univariate = -// expected_arithmetic_relation + expected_grand_product_computation_relation * alpha + -// expected_grand_product_initialization_relation * alpha.sqr(); -// return expected_round_univariate; -// } - -// // The below two methods are used in the test ComputeUnivariateVerifier -// static FF compute_full_purported_value(std::array& input_values, -// const RelationParameters& relation_parameters, -// const FF alpha) -// { -// PurportedEvaluations purported_evaluations; -// purported_evaluations.w_l = input_values[0]; -// purported_evaluations.w_r = input_values[1]; -// purported_evaluations.w_o = input_values[2]; -// purported_evaluations.z_perm = input_values[3]; -// purported_evaluations.z_perm_shift = input_values[4]; -// purported_evaluations.q_m = input_values[5]; -// purported_evaluations.q_l = input_values[6]; -// purported_evaluations.q_r = input_values[7]; -// purported_evaluations.q_o = input_values[8]; -// purported_evaluations.q_c = input_values[9]; -// purported_evaluations.sigma_1 = input_values[10]; -// purported_evaluations.sigma_2 = input_values[11]; -// purported_evaluations.sigma_3 = input_values[12]; -// purported_evaluations.id_1 = input_values[13]; -// purported_evaluations.id_2 = input_values[14]; -// purported_evaluations.id_3 = input_values[15]; -// purported_evaluations.lagrange_first = input_values[16]; -// purported_evaluations.lagrange_last = input_values[17]; -// auto relations = std::tuple( -// ArithmeticRelation(), PermutationRelation(), GrandProductInitializationRelation()); -// auto round = -// SumcheckRound( -// relations); -// PowUnivariate pow_univariate(1); -// FF full_purported_value = round.compute_full_honk_relation_purported_value( -// purported_evaluations, relation_parameters, pow_univariate, alpha); -// return full_purported_value; -// } - -// static FF compute_full_purported_value_expected(std::array& input_values, -// const RelationParameters& relation_parameters, -// const FF alpha) -// { -// FF w_l = input_values[0]; -// FF w_r = input_values[1]; -// FF w_o = input_values[2]; -// FF z_perm = input_values[3]; -// FF z_perm_shift = input_values[4]; -// FF q_m = input_values[5]; -// FF q_l = input_values[6]; -// FF q_r = input_values[7]; -// FF q_o = input_values[8]; -// FF q_c = input_values[9]; -// FF sigma_1 = input_values[10]; -// FF sigma_2 = input_values[11]; -// FF sigma_3 = input_values[12]; -// FF id_1 = input_values[13]; -// FF id_2 = input_values[14]; -// FF id_3 = input_values[15]; -// FF lagrange_first = input_values[16]; -// FF lagrange_last = input_values[17]; -// auto expected_arithmetic_relation = (q_m * w_r * w_l) + (q_r * w_r) + (q_l * w_l) + (q_o * w_o) + q_c; -// auto expected_grand_product_computation_relation = -// (z_perm + lagrange_first) * (w_l + id_1 * relation_parameters.beta + relation_parameters.gamma) * -// (w_r + id_2 * relation_parameters.beta + relation_parameters.gamma) * -// (w_o + id_3 * relation_parameters.beta + relation_parameters.gamma); -// expected_grand_product_computation_relation -= -// (z_perm_shift + lagrange_last * relation_parameters.public_input_delta) * -// (w_l + sigma_1 * relation_parameters.beta + relation_parameters.gamma) * -// (w_r + sigma_2 * relation_parameters.beta + relation_parameters.gamma) * -// (w_o + sigma_3 * relation_parameters.beta + relation_parameters.gamma); -// auto expected_grand_product_initialization_relation = z_perm_shift * lagrange_last; -// auto expected_full_purported_value = expected_arithmetic_relation + -// expected_grand_product_computation_relation * alpha + -// expected_grand_product_initialization_relation * alpha.sqr(); -// return expected_full_purported_value; -// } - -// TEST(SumcheckRound, ComputeUnivariateProver) -// { -// auto run_test = [](bool is_random_input) { -// if (is_random_input) { -// std::array, NUM_POLYNOMIALS> input_polynomials; -// for (size_t i = 0; i < NUM_POLYNOMIALS; ++i) { -// input_polynomials[i] = { FF::random_element(), FF::random_element() }; -// } - -// const FF alpha = FF::random_element(); -// const RelationParameters relation_parameters = RelationParameters{ -// .beta = FF::random_element(), .gamma = FF::random_element(), .public_input_delta = -// FF::random_element() -// }; - -// auto round_univariate = compute_round_univariate(input_polynomials, relation_parameters, alpha); - -// // Compute round_univariate manually -// std::array, NUM_POLYNOMIALS> input_univariates; -// for (size_t i = 0; i < NUM_POLYNOMIALS; ++i) { -// input_univariates[i] = Univariate(input_polynomials[i]); -// } -// auto expected_round_univariate = -// compute_expected_round_univariate(input_univariates, relation_parameters, alpha); -// EXPECT_EQ(round_univariate, expected_round_univariate); -// } else { -// std::array, NUM_POLYNOMIALS> input_polynomials; -// for (size_t i = 0; i < NUM_POLYNOMIALS; ++i) { -// input_polynomials[i] = { 1, 2 }; -// } -// const FF alpha = 1; -// const RelationParameters relation_parameters = -// RelationParameters{ .beta = 1, .gamma = 1, .public_input_delta = 1 }; -// auto round_univariate = compute_round_univariate(input_polynomials, relation_parameters, alpha); -// // Compute round_univariate manually -// std::array, NUM_POLYNOMIALS> input_univariates; -// for (size_t i = 0; i < NUM_POLYNOMIALS; ++i) { -// input_univariates[i] = Univariate(input_polynomials[i]); -// } -// // expected_round_univariate = { 6, 26, 66, 132, 230, 366 } -// auto expected_round_univariate = -// compute_expected_round_univariate(input_univariates, relation_parameters, alpha); -// EXPECT_EQ(round_univariate, expected_round_univariate); -// }; -// }; -// run_test(/* is_random_input=*/false); -// run_test(/* is_random_input=*/true); -// } - -// TEST(SumcheckRound, ComputeUnivariateVerifier) -// { -// auto run_test = [](bool is_random_input) { -// if (is_random_input) { -// std::array input_values; -// for (size_t i = 0; i < NUM_POLYNOMIALS; ++i) { -// input_values[i] = FF::random_element(); -// } -// const FF alpha = FF::random_element(); -// const RelationParameters relation_parameters = RelationParameters{ -// .beta = FF::random_element(), .gamma = FF::random_element(), .public_input_delta = -// FF::random_element() -// }; -// auto full_purported_value = compute_full_purported_value(input_values, relation_parameters, alpha); -// // Compute round_univariate manually -// auto expected_full_purported_value = -// compute_full_purported_value_expected(input_values, relation_parameters, alpha); -// EXPECT_EQ(full_purported_value, expected_full_purported_value); -// } else { -// std::array input_values; -// for (size_t i = 0; i < NUM_POLYNOMIALS; ++i) { -// input_values[i] = FF(2); -// } -// const FF alpha = 1; -// const RelationParameters relation_parameters = -// RelationParameters{ .beta = 1, .gamma = 1, .public_input_delta = 1 }; -// auto full_purported_value = compute_full_purported_value(input_values, relation_parameters, alpha); -// // Compute round_univariate manually -// auto expected_full_purported_value = -// compute_full_purported_value_expected(input_values, relation_parameters, alpha); -// EXPECT_EQ(full_purported_value, expected_full_purported_value); -// }; -// }; -// run_test(/* is_random_input=*/false); -// run_test(/* is_random_input=*/true); -// } - -// } // namespace test_sumcheck_round +#include "sumcheck_round.hpp" +#include "relations/arithmetic_relation.hpp" +#include "relations/permutation_relation.hpp" +#include "polynomials/univariate.hpp" +#include "barretenberg/ecc/curves/bn254/fr.hpp" +#include "barretenberg/numeric/random/engine.hpp" +#include "barretenberg/honk/flavor/standard.hpp" + +#include + +#include "barretenberg/common/mem.hpp" +#include +/** + * We want to test if the univariate (S_l in the thesis) computed by the prover in a particular round is correct. We + * also want to verify given the purported evaluations of all the relevant polynomials, the verifer can correctly + verify + * the purported evaluation of S_l. For the prover, we use a couple of methods to compute the univariate by the + sumcheck + * method `compute_univariate` and by step by step manual computation respectively. For the verifier, we follow a + * similar approach. + */ + +using namespace proof_system::honk; +using namespace proof_system::honk::sumcheck; + +using Flavor = flavor::Standard; +using FF = typename Flavor::FF; +using ProverPolynomials = typename Flavor::ProverPolynomials; +using PurportedEvaluations = typename Flavor::PurportedEvaluations; + +const size_t NUM_POLYNOMIALS = Flavor::NUM_ALL_ENTITIES; +const size_t max_relation_length = 5; +const size_t input_polynomial_length = 2; + +namespace test_sumcheck_round { + +// The below two methods are used in the test ComputeUnivariateProver +static Univariate compute_round_univariate( + std::array, NUM_POLYNOMIALS>& input_polynomials, + const RelationParameters& relation_parameters, + const FF alpha) +{ + size_t round_size = 1; + auto relations = std::tuple(ArithmeticRelation(), PermutationRelation()); + // Improvement(Cody): This is ugly? Maye supply some/all of this data through "flavor" class? + auto round = SumcheckRound(round_size, relations); + + ProverPolynomials full_polynomials; + full_polynomials.w_l = input_polynomials[0]; + full_polynomials.w_r = input_polynomials[1]; + full_polynomials.w_o = input_polynomials[2]; + full_polynomials.z_perm = input_polynomials[3]; + full_polynomials.z_perm_shift = input_polynomials[4]; + full_polynomials.q_m = input_polynomials[5]; + full_polynomials.q_l = input_polynomials[6]; + full_polynomials.q_r = input_polynomials[7]; + full_polynomials.q_o = input_polynomials[8]; + full_polynomials.q_c = input_polynomials[9]; + full_polynomials.sigma_1 = input_polynomials[10]; + full_polynomials.sigma_2 = input_polynomials[11]; + full_polynomials.sigma_3 = input_polynomials[12]; + full_polynomials.id_1 = input_polynomials[13]; + full_polynomials.id_2 = input_polynomials[14]; + full_polynomials.id_3 = input_polynomials[15]; + full_polynomials.lagrange_first = input_polynomials[16]; + full_polynomials.lagrange_last = input_polynomials[17]; + + PowUnivariate pow_zeta(1); + Univariate round_univariate = + round.compute_univariate(full_polynomials, relation_parameters, pow_zeta, alpha); + return round_univariate; +} + +static Univariate compute_expected_round_univariate( + std::array, NUM_POLYNOMIALS>& input_univariates, + const RelationParameters& relation_parameters, + const FF alpha) +{ + BarycentricData barycentric_2_to_max = + BarycentricData(); + std::array, NUM_POLYNOMIALS> extended_univariates; + for (size_t i = 0; i < NUM_POLYNOMIALS; ++i) { + extended_univariates[i] = barycentric_2_to_max.extend(input_univariates[i]); + } + auto w_l_univariate = Univariate(extended_univariates[0]); + auto w_r_univariate = Univariate(extended_univariates[1]); + auto w_o_univariate = Univariate(extended_univariates[2]); + auto z_perm_univariate = Univariate(extended_univariates[3]); + auto z_perm_shift_univariate = + Univariate(extended_univariates[4]); // this is not real shifted data + auto q_m_univariate = Univariate(extended_univariates[5]); + auto q_l_univariate = Univariate(extended_univariates[6]); + auto q_r_univariate = Univariate(extended_univariates[7]); + auto q_o_univariate = Univariate(extended_univariates[8]); + auto q_c_univariate = Univariate(extended_univariates[9]); + auto sigma_1_univariate = Univariate(extended_univariates[10]); + auto sigma_2_univariate = Univariate(extended_univariates[11]); + auto sigma_3_univariate = Univariate(extended_univariates[12]); + auto id_1_univariate = Univariate(extended_univariates[13]); + auto id_2_univariate = Univariate(extended_univariates[14]); + auto id_3_univariate = Univariate(extended_univariates[15]); + auto lagrange_first_univariate = Univariate(extended_univariates[16]); + auto lagrange_last_univariate = Univariate(extended_univariates[17]); + + auto expected_arithmetic_relation = + ((q_m_univariate * w_r_univariate * w_l_univariate) + (q_r_univariate * w_r_univariate) + + (q_l_univariate * w_l_univariate) + (q_o_univariate * w_o_univariate) + (q_c_univariate)); + auto expected_grand_product_computation_relation = + ((z_perm_univariate + lagrange_first_univariate) * + (w_l_univariate + id_1_univariate * relation_parameters.beta + relation_parameters.gamma) * + (w_r_univariate + id_2_univariate * relation_parameters.beta + relation_parameters.gamma) * + (w_o_univariate + id_3_univariate * relation_parameters.beta + relation_parameters.gamma)); + expected_grand_product_computation_relation -= + ((z_perm_shift_univariate + lagrange_last_univariate * relation_parameters.public_input_delta) * + (w_l_univariate + sigma_1_univariate * relation_parameters.beta + relation_parameters.gamma) * + (w_r_univariate + sigma_2_univariate * relation_parameters.beta + relation_parameters.gamma) * + (w_o_univariate + sigma_3_univariate * relation_parameters.beta + relation_parameters.gamma)); + auto expected_grand_product_initialization_relation = (z_perm_shift_univariate * lagrange_last_univariate); + Univariate expected_round_univariate = + expected_arithmetic_relation + expected_grand_product_computation_relation * alpha + + expected_grand_product_initialization_relation * alpha.sqr(); + return expected_round_univariate; +} + +// The below two methods are used in the test ComputeUnivariateVerifier +static FF compute_full_purported_value(std::array& input_values, + const RelationParameters& relation_parameters, + const FF alpha) +{ + PurportedEvaluations purported_evaluations; + purported_evaluations.w_l = input_values[0]; + purported_evaluations.w_r = input_values[1]; + purported_evaluations.w_o = input_values[2]; + purported_evaluations.z_perm = input_values[3]; + purported_evaluations.z_perm_shift = input_values[4]; + purported_evaluations.q_m = input_values[5]; + purported_evaluations.q_l = input_values[6]; + purported_evaluations.q_r = input_values[7]; + purported_evaluations.q_o = input_values[8]; + purported_evaluations.q_c = input_values[9]; + purported_evaluations.sigma_1 = input_values[10]; + purported_evaluations.sigma_2 = input_values[11]; + purported_evaluations.sigma_3 = input_values[12]; + purported_evaluations.id_1 = input_values[13]; + purported_evaluations.id_2 = input_values[14]; + purported_evaluations.id_3 = input_values[15]; + purported_evaluations.lagrange_first = input_values[16]; + purported_evaluations.lagrange_last = input_values[17]; + auto relations = std::tuple(ArithmeticRelation(), PermutationRelation()); + auto round = SumcheckRound(relations); + PowUnivariate pow_univariate(1); + FF full_purported_value = round.compute_full_honk_relation_purported_value( + purported_evaluations, relation_parameters, pow_univariate, alpha); + return full_purported_value; +} + +static FF compute_full_purported_value_expected(std::array& input_values, + const RelationParameters& relation_parameters, + const FF alpha) +{ + FF w_l = input_values[0]; + FF w_r = input_values[1]; + FF w_o = input_values[2]; + FF z_perm = input_values[3]; + FF z_perm_shift = input_values[4]; + FF q_m = input_values[5]; + FF q_l = input_values[6]; + FF q_r = input_values[7]; + FF q_o = input_values[8]; + FF q_c = input_values[9]; + FF sigma_1 = input_values[10]; + FF sigma_2 = input_values[11]; + FF sigma_3 = input_values[12]; + FF id_1 = input_values[13]; + FF id_2 = input_values[14]; + FF id_3 = input_values[15]; + FF lagrange_first = input_values[16]; + FF lagrange_last = input_values[17]; + auto expected_arithmetic_relation = (q_m * w_r * w_l) + (q_r * w_r) + (q_l * w_l) + (q_o * w_o) + q_c; + auto expected_grand_product_computation_relation = + (z_perm + lagrange_first) * (w_l + id_1 * relation_parameters.beta + relation_parameters.gamma) * + (w_r + id_2 * relation_parameters.beta + relation_parameters.gamma) * + (w_o + id_3 * relation_parameters.beta + relation_parameters.gamma); + expected_grand_product_computation_relation -= + (z_perm_shift + lagrange_last * relation_parameters.public_input_delta) * + (w_l + sigma_1 * relation_parameters.beta + relation_parameters.gamma) * + (w_r + sigma_2 * relation_parameters.beta + relation_parameters.gamma) * + (w_o + sigma_3 * relation_parameters.beta + relation_parameters.gamma); + auto expected_grand_product_initialization_relation = z_perm_shift * lagrange_last; + auto expected_full_purported_value = expected_arithmetic_relation + + expected_grand_product_computation_relation * alpha + + expected_grand_product_initialization_relation * alpha.sqr(); + return expected_full_purported_value; +} + +TEST(SumcheckRound, ComputeUnivariateProver) +{ + auto run_test = [](bool is_random_input) { + if (is_random_input) { + std::array, NUM_POLYNOMIALS> input_polynomials; + for (size_t i = 0; i < NUM_POLYNOMIALS; ++i) { + input_polynomials[i] = { FF::random_element(), FF::random_element() }; + } + + const FF alpha = FF::random_element(); + const RelationParameters relation_parameters = RelationParameters{ + .beta = FF::random_element(), .gamma = FF::random_element(), .public_input_delta = FF::random_element() + }; + + auto round_univariate = compute_round_univariate(input_polynomials, relation_parameters, alpha); + + // Compute round_univariate manually + std::array, NUM_POLYNOMIALS> input_univariates; + for (size_t i = 0; i < NUM_POLYNOMIALS; ++i) { + input_univariates[i] = Univariate(input_polynomials[i]); + } + auto expected_round_univariate = + compute_expected_round_univariate(input_univariates, relation_parameters, alpha); + EXPECT_EQ(round_univariate, expected_round_univariate); + } else { + std::array, NUM_POLYNOMIALS> input_polynomials; + for (size_t i = 0; i < NUM_POLYNOMIALS; ++i) { + input_polynomials[i] = { 1, 2 }; + } + const FF alpha = 1; + const RelationParameters relation_parameters = + RelationParameters{ .beta = 1, .gamma = 1, .public_input_delta = 1 }; + auto round_univariate = compute_round_univariate(input_polynomials, relation_parameters, alpha); + // Compute round_univariate manually + std::array, NUM_POLYNOMIALS> input_univariates; + for (size_t i = 0; i < NUM_POLYNOMIALS; ++i) { + input_univariates[i] = Univariate(input_polynomials[i]); + } + // expected_round_univariate = { 6, 26, 66, 132, 230, 366 } + auto expected_round_univariate = + compute_expected_round_univariate(input_univariates, relation_parameters, alpha); + EXPECT_EQ(round_univariate, expected_round_univariate); + }; + }; + run_test(/* is_random_input=*/false); + run_test(/* is_random_input=*/true); +} + +TEST(SumcheckRound, ComputeUnivariateVerifier) +{ + auto run_test = [](bool is_random_input) { + if (is_random_input) { + std::array input_values; + for (size_t i = 0; i < NUM_POLYNOMIALS; ++i) { + input_values[i] = FF::random_element(); + } + const FF alpha = FF::random_element(); + const RelationParameters relation_parameters = RelationParameters{ + .beta = FF::random_element(), .gamma = FF::random_element(), .public_input_delta = FF::random_element() + }; + auto full_purported_value = compute_full_purported_value(input_values, relation_parameters, alpha); + // Compute round_univariate manually + auto expected_full_purported_value = + compute_full_purported_value_expected(input_values, relation_parameters, alpha); + EXPECT_EQ(full_purported_value, expected_full_purported_value); + } else { + std::array input_values; + for (size_t i = 0; i < NUM_POLYNOMIALS; ++i) { + input_values[i] = FF(2); + } + const FF alpha = 1; + const RelationParameters relation_parameters = + RelationParameters{ .beta = 1, .gamma = 1, .public_input_delta = 1 }; + auto full_purported_value = compute_full_purported_value(input_values, relation_parameters, alpha); + // Compute round_univariate manually + auto expected_full_purported_value = + compute_full_purported_value_expected(input_values, relation_parameters, alpha); + EXPECT_EQ(full_purported_value, expected_full_purported_value); + }; + }; + run_test(/* is_random_input=*/false); + run_test(/* is_random_input=*/true); +} + +/** + * @brief Test utility functions for applying operations to tuple of tuple of Univariates + * + */ +TEST(SumcheckRound, TupleOfTuplesOfUnivariates) +{ + using Flavor = proof_system::honk::flavor::Standard; + using FF = typename Flavor::FF; + + // Define three linear univariates of different sizes + Univariate univariate_1({ 1, 2, 3 }); + Univariate univariate_2({ 2, 4 }); + Univariate univariate_3({ 3, 4, 5, 6, 7 }); + const size_t MAX_LENGTH = 5; + + // Instantiate some barycentric extension utility classes + auto barycentric_util_1 = BarycentricData(); + auto barycentric_util_2 = BarycentricData(); + auto barycentric_util_3 = BarycentricData(); + + // Construct a tuple of tuples of the form { {univariate_1}, {univariate_2, univariate_3} } + auto tuple_of_tuples = std::make_tuple(std::make_tuple(univariate_1), std::make_tuple(univariate_2, univariate_3)); + + // Use scale_univariate_accumulators to scale by challenge powers + FF challenge = 5; + FF running_challenge = 1; + SumcheckRound::scale_univariates(tuple_of_tuples, challenge, running_challenge); + + // Use extend_and_batch_univariates to extend to MAX_LENGTH then accumulate + auto result = Univariate(); + SumcheckRound::extend_and_batch_univariates(tuple_of_tuples, result); + + // Repeat the batching process manually + auto result_expected = barycentric_util_1.extend(univariate_1) * 1 + + barycentric_util_2.extend(univariate_2) * challenge + + barycentric_util_3.extend(univariate_3) * challenge * challenge; + + // Compare final batched univarites + EXPECT_EQ(result, result_expected); + + // Reinitialize univariate accumulators to zero + SumcheckRound::zero_univariates(tuple_of_tuples); + + // Check that reinitialization was successful + Univariate expected_1({ 0, 0, 0 }); + Univariate expected_2({ 0, 0 }); + Univariate expected_3({ 0, 0, 0, 0, 0 }); + EXPECT_EQ(std::get<0>(std::get<0>(tuple_of_tuples)), expected_1); + EXPECT_EQ(std::get<0>(std::get<1>(tuple_of_tuples)), expected_2); + EXPECT_EQ(std::get<1>(std::get<1>(tuple_of_tuples)), expected_3); +} + +/** + * @brief Test utility functions for applying operations to tuple of std::arrays of field elements + * + */ +TEST(SumcheckRound, TuplesOfEvaluationArrays) +{ + using Flavor = proof_system::honk::flavor::Standard; + using FF = typename Flavor::FF; + + // Define two arrays of arbitrary elements + std::array evaluations_1 = { 4 }; + std::array evaluations_2 = { 6, 2 }; + + // Construct a tuple + auto tuple_of_arrays = std::make_tuple(evaluations_1, evaluations_2); + + // Use scale_and_batch_elements to scale by challenge powers + FF challenge = 5; + FF running_challenge = 1; + FF result = 0; + SumcheckRound::scale_and_batch_elements( + tuple_of_arrays, challenge, running_challenge, result); + + // Repeat the batching process manually + auto result_expected = + evaluations_1[0] * 1 + evaluations_2[0] * challenge + evaluations_2[1] * challenge * challenge; + + // Compare batched result + EXPECT_EQ(result, result_expected); + + // Reinitialize univariate accumulators to zero + SumcheckRound::zero_elements(tuple_of_arrays); + + EXPECT_EQ(std::get<0>(tuple_of_arrays)[0], 0); + EXPECT_EQ(std::get<1>(tuple_of_arrays)[0], 0); + EXPECT_EQ(std::get<1>(tuple_of_arrays)[1], 0); +} + +} // namespace test_sumcheck_round From 05ced6118262dacb07d907b27a714c7bd1f86d73 Mon Sep 17 00:00:00 2001 From: ledwards2225 Date: Wed, 17 May 2023 22:08:40 +0000 Subject: [PATCH 15/18] update function name after rebase --- cpp/src/barretenberg/honk/composer/ultra_honk_composer.test.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) 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 fd096a74c1..2eb23f820a 100644 --- a/cpp/src/barretenberg/honk/composer/ultra_honk_composer.test.cpp +++ b/cpp/src/barretenberg/honk/composer/ultra_honk_composer.test.cpp @@ -691,7 +691,7 @@ TEST(UltraHonkComposer, non_native_field_multiplication) proof_system::UltraCircuitConstructor::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] = composer.queue_non_native_field_multiplication(inputs); + const auto [lo_1_idx, hi_1_idx] = composer.evaluate_non_native_field_multiplication(inputs); composer.range_constrain_two_limbs(lo_1_idx, hi_1_idx, 70, 70); prove_and_verify(composer, /*expected_result=*/true); From ef20c44450e4a11dce49c457ec31253840d974a4 Mon Sep 17 00:00:00 2001 From: ledwards2225 Date: Wed, 17 May 2023 22:09:57 +0000 Subject: [PATCH 16/18] remove unused variable for gcc --- .../honk/sumcheck/relations/ultra_relation_consistency.test.cpp | 1 - 1 file changed, 1 deletion(-) diff --git a/cpp/src/barretenberg/honk/sumcheck/relations/ultra_relation_consistency.test.cpp b/cpp/src/barretenberg/honk/sumcheck/relations/ultra_relation_consistency.test.cpp index 5920aadb17..50aadef569 100644 --- a/cpp/src/barretenberg/honk/sumcheck/relations/ultra_relation_consistency.test.cpp +++ b/cpp/src/barretenberg/honk/sumcheck/relations/ultra_relation_consistency.test.cpp @@ -516,7 +516,6 @@ TEST_F(UltraRelationConsistency, AuxiliaryRelation) auto relation = AuxiliaryRelation(); const auto& eta = relation_parameters.eta; - const auto fake_alpha = FF(1); // Extract the extended edges for manual computation of relation contribution const auto& w_1 = extended_edges.w_l; From 94d29a5a6f94413396e6e42a5516685bbd597faa Mon Sep 17 00:00:00 2001 From: ledwards2225 Date: Thu, 18 May 2023 01:33:31 +0000 Subject: [PATCH 17/18] cleanup --- .../honk/proof_system/ultra_prover.cpp | 1 - .../honk/proof_system/ultra_verifier.cpp | 2 - .../honk/sumcheck/new_sumcheck.test.cpp | 344 ------------------ .../sumcheck/relations/auxiliary_relation.hpp | 2 +- .../relations/relation_consistency.test.cpp | 3 +- .../ultra_relation_consistency.test.cpp | 3 +- .../honk/sumcheck/sumcheck.test.cpp | 327 ++++++++++++++++- .../honk/sumcheck/sumcheck_round.test.cpp | 6 +- 8 files changed, 330 insertions(+), 358 deletions(-) delete mode 100644 cpp/src/barretenberg/honk/sumcheck/new_sumcheck.test.cpp diff --git a/cpp/src/barretenberg/honk/proof_system/ultra_prover.cpp b/cpp/src/barretenberg/honk/proof_system/ultra_prover.cpp index 09e265609a..1c56e552d9 100644 --- a/cpp/src/barretenberg/honk/proof_system/ultra_prover.cpp +++ b/cpp/src/barretenberg/honk/proof_system/ultra_prover.cpp @@ -189,7 +189,6 @@ template void UltraProver_::execute_grand_product_c */ template void UltraProver_::execute_relation_check_rounds() { - // using Sumcheck = sumcheck::Sumcheck, sumcheck::UltraArithmeticRelation>; using Sumcheck = sumcheck::Sumcheck, sumcheck::UltraArithmeticRelation, diff --git a/cpp/src/barretenberg/honk/proof_system/ultra_verifier.cpp b/cpp/src/barretenberg/honk/proof_system/ultra_verifier.cpp index a321e2777b..31f04550be 100644 --- a/cpp/src/barretenberg/honk/proof_system/ultra_verifier.cpp +++ b/cpp/src/barretenberg/honk/proof_system/ultra_verifier.cpp @@ -105,8 +105,6 @@ template bool UltraVerifier_::verify_proof(const plonk commitments.z_lookup = transcript.template receive_from_prover(commitment_labels.z_lookup); // Execute Sumcheck Verifier - // auto sumcheck = - // Sumcheck, honk::sumcheck::UltraArithmeticRelation>(circuit_size, transcript); auto sumcheck = Sumcheck, honk::sumcheck::UltraArithmeticRelation, diff --git a/cpp/src/barretenberg/honk/sumcheck/new_sumcheck.test.cpp b/cpp/src/barretenberg/honk/sumcheck/new_sumcheck.test.cpp deleted file mode 100644 index a3f7cfaa59..0000000000 --- a/cpp/src/barretenberg/honk/sumcheck/new_sumcheck.test.cpp +++ /dev/null @@ -1,344 +0,0 @@ -#include "sumcheck.hpp" -#include "barretenberg/honk/transcript/transcript.hpp" -#include "barretenberg/honk/flavor/standard.hpp" -#include "barretenberg/transcript/transcript_wrappers.hpp" -#include "relations/arithmetic_relation.hpp" -#include "relations/permutation_relation.hpp" -#include "relations/lookup_relation.hpp" -#include "relations/ultra_arithmetic_relation.hpp" -#include "relations/gen_perm_sort_relation.hpp" -#include "relations/elliptic_relation.hpp" -#include "relations/auxiliary_relation.hpp" -#include "barretenberg/transcript/manifest.hpp" -#include -#include -#include -#include "barretenberg/ecc/curves/bn254/fr.hpp" -#include -#include "barretenberg/numeric/random/engine.hpp" -#include "barretenberg/honk/composer/standard_honk_composer.hpp" -#include "barretenberg/honk/composer/ultra_honk_composer.hpp" - -#include -#include -#include -#include -#include -#include - -using namespace proof_system::honk; -using namespace proof_system::honk::sumcheck; -using Flavor = honk::flavor::Standard; -using FF = typename Flavor::FF; -using ProverPolynomials = typename Flavor::ProverPolynomials; - -namespace test_sumcheck_new { - -TEST(NewSumcheck, Standard) -{ - using Flavor = honk::flavor::Standard; - using FF = typename Flavor::FF; - using ProverPolynomials = typename Flavor::ProverPolynomials; - - // Create a composer and a dummy circuit with a few gates - auto composer = StandardHonkComposer(); - fr a = fr::one(); - // Using the public variable to check that public_input_delta is computed and added to the relation correctly - uint32_t a_idx = composer.add_public_variable(a); - fr b = fr::one(); - fr c = a + b; - fr d = a + c; - uint32_t b_idx = composer.add_variable(b); - uint32_t c_idx = composer.add_variable(c); - uint32_t d_idx = composer.add_variable(d); - for (size_t i = 0; i < 16; i++) { - composer.create_add_gate({ a_idx, b_idx, c_idx, fr::one(), fr::one(), fr::neg_one(), fr::zero() }); - composer.create_add_gate({ d_idx, c_idx, a_idx, fr::one(), fr::neg_one(), fr::neg_one(), fr::zero() }); - } - // Create a prover (it will compute proving key and witness) - auto prover = composer.create_prover(); - - // Generate beta and gamma - fr beta = fr::random_element(); - fr gamma = fr::random_element(); - - // Compute public input delta - const auto public_inputs = composer.circuit_constructor.get_public_inputs(); - auto public_input_delta = - honk::compute_public_input_delta(public_inputs, beta, gamma, prover.key->circuit_size); - - sumcheck::RelationParameters relation_parameters{ - .beta = beta, - .gamma = gamma, - .public_input_delta = public_input_delta, - }; - - // Compute grand product polynomial - polynomial z_permutation = prover_library::compute_permutation_grand_product(prover.key, beta, gamma); - - ProverPolynomials prover_polynomials; - - prover_polynomials.w_l = prover.key->w_l; - prover_polynomials.w_r = prover.key->w_r; - prover_polynomials.w_o = prover.key->w_o; - prover_polynomials.z_perm = z_permutation; - prover_polynomials.z_perm_shift = z_permutation.shifted(); - prover_polynomials.q_m = prover.key->q_m; - prover_polynomials.q_l = prover.key->q_l; - prover_polynomials.q_r = prover.key->q_r; - prover_polynomials.q_o = prover.key->q_o; - prover_polynomials.q_c = prover.key->q_c; - prover_polynomials.sigma_1 = prover.key->sigma_1; - prover_polynomials.sigma_2 = prover.key->sigma_2; - prover_polynomials.sigma_3 = prover.key->sigma_3; - prover_polynomials.id_1 = prover.key->id_1; - prover_polynomials.id_2 = prover.key->id_2; - prover_polynomials.id_3 = prover.key->id_3; - prover_polynomials.lagrange_first = prover.key->lagrange_first; - prover_polynomials.lagrange_last = prover.key->lagrange_last; - - auto prover_transcript = ProverTranscript::init_empty(); - - auto sumcheck_prover = Sumcheck, ArithmeticRelation, PermutationRelation>( - prover.key->circuit_size, prover_transcript); - - auto prover_output = sumcheck_prover.execute_prover(prover_polynomials, relation_parameters); - - auto verifier_transcript = VerifierTranscript::init_empty(prover_transcript); - - auto sumcheck_verifier = Sumcheck, ArithmeticRelation, PermutationRelation>( - prover.key->circuit_size, verifier_transcript); - - std::optional verifier_output = sumcheck_verifier.execute_verifier(relation_parameters); - - ASSERT_TRUE(verifier_output.has_value()); -} - -TEST(NewSumcheck, Ultra) -{ - using Flavor = honk::flavor::Ultra; - using FF = typename Flavor::FF; - using ProverPolynomials = typename Flavor::ProverPolynomials; - - // Create a composer and a dummy circuit with a few gates - auto composer = UltraHonkComposer(); - fr a = fr::one(); - - // Add some basic add gates - uint32_t a_idx = composer.add_variable(a); - fr b = fr::one(); - fr c = a + b; - fr d = a + c; - uint32_t b_idx = composer.add_variable(b); - uint32_t c_idx = composer.add_variable(c); - uint32_t d_idx = composer.add_variable(d); - for (size_t i = 0; i < 16; i++) { - composer.create_add_gate({ a_idx, b_idx, c_idx, 1, 1, -1, 0 }); - composer.create_add_gate({ d_idx, c_idx, a_idx, 1, -1, -1, 0 }); - } - - // Add a big add gate with use of next row to test q_arith = 2 - fr e = a + b + c + d; - uint32_t e_idx = composer.add_variable(e); - - uint32_t zero_idx = composer.get_zero_idx(); - composer.create_big_add_gate({ a_idx, b_idx, c_idx, d_idx, -1, -1, -1, -1, 0 }, true); // use next row - composer.create_big_add_gate({ zero_idx, zero_idx, zero_idx, e_idx, 0, 0, 0, 0, 0 }, false); - - // Add some lookup gates (related to pedersen hashing) - barretenberg::fr pedersen_input_value = fr::random_element(); - const fr input_hi = uint256_t(pedersen_input_value).slice(126, 256); - const fr input_lo = uint256_t(pedersen_input_value).slice(0, 126); - const auto input_hi_index = composer.add_variable(input_hi); - const auto input_lo_index = 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); - - composer.create_gates_from_plookup_accumulators( - plookup::MultiTableId::PEDERSEN_LEFT_HI, sequence_data_hi, input_hi_index); - composer.create_gates_from_plookup_accumulators( - plookup::MultiTableId::PEDERSEN_LEFT_LO, sequence_data_lo, input_lo_index); - - // Add a sort gate (simply checks that consecutive inputs have a difference of < 4) - a_idx = composer.add_variable(FF(0)); - b_idx = composer.add_variable(FF(1)); - c_idx = composer.add_variable(FF(2)); - d_idx = composer.add_variable(FF(3)); - composer.create_sort_constraint({ a_idx, b_idx, c_idx, d_idx }); - - // Add an elliptic curve addition gate - grumpkin::g1::affine_element p1 = crypto::generators::get_generator_data({ 0, 0 }).generator; - grumpkin::g1::affine_element p2 = crypto::generators::get_generator_data({ 0, 1 }).generator; - - grumpkin::fq beta_scalar = grumpkin::fq::cube_root_of_unity(); - grumpkin::g1::affine_element p2_endo = p2; - p2_endo.x *= beta_scalar; - - grumpkin::g1::affine_element p3(grumpkin::g1::element(p1) - grumpkin::g1::element(p2_endo)); - - uint32_t x1 = composer.add_variable(p1.x); - uint32_t y1 = composer.add_variable(p1.y); - uint32_t x2 = composer.add_variable(p2.x); - uint32_t y2 = composer.add_variable(p2.y); - uint32_t x3 = composer.add_variable(p3.x); - uint32_t y3 = composer.add_variable(p3.y); - - ecc_add_gate gate{ x1, y1, x2, y2, x3, y3, beta_scalar, -1 }; - composer.create_ecc_add_gate(gate); - - // Add some RAM gates - uint32_t ram_values[8]{ - composer.add_variable(fr::random_element()), composer.add_variable(fr::random_element()), - composer.add_variable(fr::random_element()), composer.add_variable(fr::random_element()), - composer.add_variable(fr::random_element()), composer.add_variable(fr::random_element()), - composer.add_variable(fr::random_element()), composer.add_variable(fr::random_element()), - }; - - size_t ram_id = composer.create_RAM_array(8); - - for (size_t i = 0; i < 8; ++i) { - composer.init_RAM_element(ram_id, i, ram_values[i]); - } - - a_idx = composer.read_RAM_array(ram_id, composer.add_variable(5)); - EXPECT_EQ(a_idx != ram_values[5], true); - - b_idx = composer.read_RAM_array(ram_id, composer.add_variable(4)); - c_idx = composer.read_RAM_array(ram_id, composer.add_variable(1)); - - composer.write_RAM_array(ram_id, composer.add_variable(4), composer.add_variable(500)); - d_idx = composer.read_RAM_array(ram_id, composer.add_variable(4)); - - EXPECT_EQ(composer.get_variable(d_idx), 500); - - // ensure these vars get used in another arithmetic gate - const auto e_value = composer.get_variable(a_idx) + composer.get_variable(b_idx) + composer.get_variable(c_idx) + - composer.get_variable(d_idx); - e_idx = composer.add_variable(e_value); - - composer.create_big_add_gate({ a_idx, b_idx, c_idx, d_idx, -1, -1, -1, -1, 0 }, true); - composer.create_big_add_gate( - { - composer.get_zero_idx(), - composer.get_zero_idx(), - composer.get_zero_idx(), - e_idx, - 0, - 0, - 0, - 0, - 0, - }, - false); - - // Create a prover (it will compute proving key and witness) - auto prover = composer.create_prover(); - - // Generate eta, beta and gamma - fr eta = fr::random_element(); - fr beta = fr::random_element(); - fr gamma = fr::random_element(); - - // Compute public input delta - const auto public_inputs = composer.circuit_constructor.get_public_inputs(); - auto public_input_delta = - honk::compute_public_input_delta(public_inputs, beta, gamma, prover.key->circuit_size); - auto lookup_grand_product_delta = - honk::compute_lookup_grand_product_delta(beta, gamma, prover.key->circuit_size); - - sumcheck::RelationParameters relation_parameters{ - .eta = eta, - .beta = beta, - .gamma = gamma, - .public_input_delta = public_input_delta, - .lookup_grand_product_delta = lookup_grand_product_delta, - }; - - // Compute sorted witness-table accumulator - prover.key->sorted_accum = prover_library::compute_sorted_list_accumulator(prover.key, eta); - - // Add RAM/ROM memory records to wire four - prover_library::add_plookup_memory_records_to_wire_4(prover.key, eta); - - // Compute grand product polynomial - prover.key->z_perm = prover_library::compute_permutation_grand_product(prover.key, beta, gamma); - - // Compute lookup grand product polynomial - prover.key->z_lookup = prover_library::compute_lookup_grand_product(prover.key, eta, beta, gamma); - - ProverPolynomials prover_polynomials; - - prover_polynomials.w_l = prover.key->w_l; - prover_polynomials.w_r = prover.key->w_r; - prover_polynomials.w_o = prover.key->w_o; - prover_polynomials.w_4 = prover.key->w_4; - prover_polynomials.w_l_shift = prover.key->w_l.shifted(); - prover_polynomials.w_r_shift = prover.key->w_r.shifted(); - prover_polynomials.w_o_shift = prover.key->w_o.shifted(); - prover_polynomials.w_4_shift = prover.key->w_4.shifted(); - prover_polynomials.sorted_accum = prover.key->sorted_accum; - prover_polynomials.sorted_accum_shift = prover.key->sorted_accum.shifted(); - prover_polynomials.table_1 = prover.key->table_1; - prover_polynomials.table_2 = prover.key->table_2; - prover_polynomials.table_3 = prover.key->table_3; - prover_polynomials.table_4 = prover.key->table_4; - prover_polynomials.table_1_shift = prover.key->table_1.shifted(); - prover_polynomials.table_2_shift = prover.key->table_2.shifted(); - prover_polynomials.table_3_shift = prover.key->table_3.shifted(); - prover_polynomials.table_4_shift = prover.key->table_4.shifted(); - prover_polynomials.z_perm = prover.key->z_perm; - prover_polynomials.z_perm_shift = prover.key->z_perm.shifted(); - prover_polynomials.z_lookup = prover.key->z_lookup; - prover_polynomials.z_lookup_shift = prover.key->z_lookup.shifted(); - prover_polynomials.q_m = prover.key->q_m; - prover_polynomials.q_l = prover.key->q_l; - prover_polynomials.q_r = prover.key->q_r; - prover_polynomials.q_o = prover.key->q_o; - prover_polynomials.q_c = prover.key->q_c; - prover_polynomials.q_4 = prover.key->q_4; - prover_polynomials.q_arith = prover.key->q_arith; - prover_polynomials.q_sort = prover.key->q_sort; - prover_polynomials.q_elliptic = prover.key->q_elliptic; - prover_polynomials.q_aux = prover.key->q_aux; - prover_polynomials.q_lookup = prover.key->q_lookup; - prover_polynomials.sigma_1 = prover.key->sigma_1; - prover_polynomials.sigma_2 = prover.key->sigma_2; - prover_polynomials.sigma_3 = prover.key->sigma_3; - prover_polynomials.sigma_4 = prover.key->sigma_4; - prover_polynomials.id_1 = prover.key->id_1; - prover_polynomials.id_2 = prover.key->id_2; - prover_polynomials.id_3 = prover.key->id_3; - prover_polynomials.id_4 = prover.key->id_4; - prover_polynomials.lagrange_first = prover.key->lagrange_first; - prover_polynomials.lagrange_last = prover.key->lagrange_last; - - auto prover_transcript = ProverTranscript::init_empty(); - - auto sumcheck_prover = Sumcheck, - UltraArithmeticRelation, - UltraPermutationRelation, - LookupRelation, - GenPermSortRelation, - EllipticRelation, - AuxiliaryRelation>(prover.key->circuit_size, prover_transcript); - - auto prover_output = sumcheck_prover.execute_prover(prover_polynomials, relation_parameters); - - auto verifier_transcript = VerifierTranscript::init_empty(prover_transcript); - - auto sumcheck_verifier = Sumcheck, - UltraArithmeticRelation, - UltraPermutationRelation, - LookupRelation, - GenPermSortRelation, - EllipticRelation, - AuxiliaryRelation>(prover.key->circuit_size, verifier_transcript); - - std::optional verifier_output = sumcheck_verifier.execute_verifier(relation_parameters); - - ASSERT_TRUE(verifier_output.has_value()); -} -} // namespace test_sumcheck_new diff --git a/cpp/src/barretenberg/honk/sumcheck/relations/auxiliary_relation.hpp b/cpp/src/barretenberg/honk/sumcheck/relations/auxiliary_relation.hpp index d4d12ae37e..4a89ac5934 100644 --- a/cpp/src/barretenberg/honk/sumcheck/relations/auxiliary_relation.hpp +++ b/cpp/src/barretenberg/honk/sumcheck/relations/auxiliary_relation.hpp @@ -27,7 +27,7 @@ template class AuxiliaryRelation { /** * @brief Expression for the generalized permutation sort gate. * @details The relation is defined as C(extended_edges(X)...) = - * // WORKTODO + * TODO(#452)(luke): Fully document all constraints handled by this relation. * * @param evals transformed to `evals + C(extended_edges(X)...)*scaling_factor` * @param extended_edges an std::array containing the fully extended Univariate edges. diff --git a/cpp/src/barretenberg/honk/sumcheck/relations/relation_consistency.test.cpp b/cpp/src/barretenberg/honk/sumcheck/relations/relation_consistency.test.cpp index 5d7d12ed62..fffcba6452 100644 --- a/cpp/src/barretenberg/honk/sumcheck/relations/relation_consistency.test.cpp +++ b/cpp/src/barretenberg/honk/sumcheck/relations/relation_consistency.test.cpp @@ -95,8 +95,7 @@ class StandardRelationConsistency : public testing::Test { /** * @brief Compute the evaluation of a `relation` in different ways, comparing it to the provided `expected_evals` * - * @details Check both `add_full_relation_value_contribution` and `add_edge_contribution` by comparing the result - to + * @details Check both `add_full_relation_value_contribution` and `add_edge_contribution` by comparing the result to * the `expected_evals` computed by the caller. * Ensures that the relations compute the same result as the expression given in the tests. * diff --git a/cpp/src/barretenberg/honk/sumcheck/relations/ultra_relation_consistency.test.cpp b/cpp/src/barretenberg/honk/sumcheck/relations/ultra_relation_consistency.test.cpp index 50aadef569..b3dce447cc 100644 --- a/cpp/src/barretenberg/honk/sumcheck/relations/ultra_relation_consistency.test.cpp +++ b/cpp/src/barretenberg/honk/sumcheck/relations/ultra_relation_consistency.test.cpp @@ -99,8 +99,7 @@ class UltraRelationConsistency : public testing::Test { /** * @brief Compute the evaluation of a `relation` in different ways, comparing it to the provided `expected_evals` * - * @details Check both `add_full_relation_value_contribution` and `add_edge_contribution` by comparing the result - to + * @details Check both `add_full_relation_value_contribution` and `add_edge_contribution` by comparing the result to * the `expected_evals` computed by the caller. * Ensures that the relations compute the same result as the expression given in the tests. * diff --git a/cpp/src/barretenberg/honk/sumcheck/sumcheck.test.cpp b/cpp/src/barretenberg/honk/sumcheck/sumcheck.test.cpp index 6f21137279..8841365375 100644 --- a/cpp/src/barretenberg/honk/sumcheck/sumcheck.test.cpp +++ b/cpp/src/barretenberg/honk/sumcheck/sumcheck.test.cpp @@ -11,6 +11,13 @@ #include "barretenberg/ecc/curves/bn254/fr.hpp" #include #include "barretenberg/numeric/random/engine.hpp" +#include "barretenberg/honk/composer/standard_honk_composer.hpp" +#include "barretenberg/honk/composer/ultra_honk_composer.hpp" +#include "barretenberg/honk/sumcheck/relations/ultra_arithmetic_relation.hpp" +#include "barretenberg/honk/sumcheck/relations/lookup_relation.hpp" +#include "barretenberg/honk/sumcheck/relations/gen_perm_sort_relation.hpp" +#include "barretenberg/honk/sumcheck/relations/elliptic_relation.hpp" +#include "barretenberg/honk/sumcheck/relations/auxiliary_relation.hpp" #include #include @@ -150,8 +157,8 @@ TEST(Sumcheck, PolynomialNormalization) * sumcheck.multivariates.folded_polynoimals[i][0] is the evaluatioin of the i'th multivariate at the vector of challenges u_i. What does this mean? - Here we show that if the multivariate is F(X0, X1, X2) defined as above, then what we get is F(u0, u1, u2) and - not, say F(u2, u1, u0). This is in accordance with Adrian's thesis (cf page 9). + Here we show that if the multivariate is F(X0, X1, X2) defined as above, then what we get is F(u0, u1, u2) and not, + say F(u2, u1, u0). This is in accordance with Adrian's thesis (cf page 9). */ // Get the values of the Lagrange basis polys L_i defined @@ -407,4 +414,320 @@ TEST(Sumcheck, ProverAndVerifierLonger) run_test(/* expect_verified=*/false); } +/** + * @brief Test the Standard Sumcheck Prover and Verifier for a real circuit + * + */ +TEST(Sumcheck, RealCircuitStandard) +{ + using Flavor = honk::flavor::Standard; + using FF = typename Flavor::FF; + using ProverPolynomials = typename Flavor::ProverPolynomials; + + // Create a composer and a dummy circuit with a few gates + auto composer = StandardHonkComposer(); + fr a = fr::one(); + // Using the public variable to check that public_input_delta is computed and added to the relation correctly + uint32_t a_idx = composer.add_public_variable(a); + fr b = fr::one(); + fr c = a + b; + fr d = a + c; + uint32_t b_idx = composer.add_variable(b); + uint32_t c_idx = composer.add_variable(c); + uint32_t d_idx = composer.add_variable(d); + for (size_t i = 0; i < 16; i++) { + composer.create_add_gate({ a_idx, b_idx, c_idx, fr::one(), fr::one(), fr::neg_one(), fr::zero() }); + composer.create_add_gate({ d_idx, c_idx, a_idx, fr::one(), fr::neg_one(), fr::neg_one(), fr::zero() }); + } + // Create a prover (it will compute proving key and witness) + auto prover = composer.create_prover(); + + // Generate beta and gamma + fr beta = fr::random_element(); + fr gamma = fr::random_element(); + + // Compute public input delta + const auto public_inputs = composer.circuit_constructor.get_public_inputs(); + auto public_input_delta = + honk::compute_public_input_delta(public_inputs, beta, gamma, prover.key->circuit_size); + + sumcheck::RelationParameters relation_parameters{ + .beta = beta, + .gamma = gamma, + .public_input_delta = public_input_delta, + }; + + // Compute grand product polynomial + polynomial z_permutation = prover_library::compute_permutation_grand_product(prover.key, beta, gamma); + + ProverPolynomials prover_polynomials; + + prover_polynomials.w_l = prover.key->w_l; + prover_polynomials.w_r = prover.key->w_r; + prover_polynomials.w_o = prover.key->w_o; + prover_polynomials.z_perm = z_permutation; + prover_polynomials.z_perm_shift = z_permutation.shifted(); + prover_polynomials.q_m = prover.key->q_m; + prover_polynomials.q_l = prover.key->q_l; + prover_polynomials.q_r = prover.key->q_r; + prover_polynomials.q_o = prover.key->q_o; + prover_polynomials.q_c = prover.key->q_c; + prover_polynomials.sigma_1 = prover.key->sigma_1; + prover_polynomials.sigma_2 = prover.key->sigma_2; + prover_polynomials.sigma_3 = prover.key->sigma_3; + prover_polynomials.id_1 = prover.key->id_1; + prover_polynomials.id_2 = prover.key->id_2; + prover_polynomials.id_3 = prover.key->id_3; + prover_polynomials.lagrange_first = prover.key->lagrange_first; + prover_polynomials.lagrange_last = prover.key->lagrange_last; + + auto prover_transcript = ProverTranscript::init_empty(); + + auto sumcheck_prover = Sumcheck, ArithmeticRelation, PermutationRelation>( + prover.key->circuit_size, prover_transcript); + + auto prover_output = sumcheck_prover.execute_prover(prover_polynomials, relation_parameters); + + auto verifier_transcript = VerifierTranscript::init_empty(prover_transcript); + + auto sumcheck_verifier = Sumcheck, ArithmeticRelation, PermutationRelation>( + prover.key->circuit_size, verifier_transcript); + + std::optional verifier_output = sumcheck_verifier.execute_verifier(relation_parameters); + + ASSERT_TRUE(verifier_output.has_value()); +} + +/** + * @brief Test the Ultra Sumcheck Prover and Verifier for a real circuit + * + */ +TEST(Sumcheck, RealCircuitUltra) +{ + using Flavor = honk::flavor::Ultra; + using FF = typename Flavor::FF; + using ProverPolynomials = typename Flavor::ProverPolynomials; + + // Create a composer and a dummy circuit with a few gates + auto composer = UltraHonkComposer(); + fr a = fr::one(); + + // Add some basic add gates + uint32_t a_idx = composer.add_variable(a); + fr b = fr::one(); + fr c = a + b; + fr d = a + c; + uint32_t b_idx = composer.add_variable(b); + uint32_t c_idx = composer.add_variable(c); + uint32_t d_idx = composer.add_variable(d); + for (size_t i = 0; i < 16; i++) { + composer.create_add_gate({ a_idx, b_idx, c_idx, 1, 1, -1, 0 }); + composer.create_add_gate({ d_idx, c_idx, a_idx, 1, -1, -1, 0 }); + } + + // Add a big add gate with use of next row to test q_arith = 2 + fr e = a + b + c + d; + uint32_t e_idx = composer.add_variable(e); + + uint32_t zero_idx = composer.get_zero_idx(); + composer.create_big_add_gate({ a_idx, b_idx, c_idx, d_idx, -1, -1, -1, -1, 0 }, true); // use next row + composer.create_big_add_gate({ zero_idx, zero_idx, zero_idx, e_idx, 0, 0, 0, 0, 0 }, false); + + // Add some lookup gates (related to pedersen hashing) + barretenberg::fr pedersen_input_value = fr::random_element(); + const fr input_hi = uint256_t(pedersen_input_value).slice(126, 256); + const fr input_lo = uint256_t(pedersen_input_value).slice(0, 126); + const auto input_hi_index = composer.add_variable(input_hi); + const auto input_lo_index = 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); + + composer.create_gates_from_plookup_accumulators( + plookup::MultiTableId::PEDERSEN_LEFT_HI, sequence_data_hi, input_hi_index); + composer.create_gates_from_plookup_accumulators( + plookup::MultiTableId::PEDERSEN_LEFT_LO, sequence_data_lo, input_lo_index); + + // Add a sort gate (simply checks that consecutive inputs have a difference of < 4) + a_idx = composer.add_variable(FF(0)); + b_idx = composer.add_variable(FF(1)); + c_idx = composer.add_variable(FF(2)); + d_idx = composer.add_variable(FF(3)); + composer.create_sort_constraint({ a_idx, b_idx, c_idx, d_idx }); + + // Add an elliptic curve addition gate + grumpkin::g1::affine_element p1 = crypto::generators::get_generator_data({ 0, 0 }).generator; + grumpkin::g1::affine_element p2 = crypto::generators::get_generator_data({ 0, 1 }).generator; + + grumpkin::fq beta_scalar = grumpkin::fq::cube_root_of_unity(); + grumpkin::g1::affine_element p2_endo = p2; + p2_endo.x *= beta_scalar; + + grumpkin::g1::affine_element p3(grumpkin::g1::element(p1) - grumpkin::g1::element(p2_endo)); + + uint32_t x1 = composer.add_variable(p1.x); + uint32_t y1 = composer.add_variable(p1.y); + uint32_t x2 = composer.add_variable(p2.x); + uint32_t y2 = composer.add_variable(p2.y); + uint32_t x3 = composer.add_variable(p3.x); + uint32_t y3 = composer.add_variable(p3.y); + + ecc_add_gate gate{ x1, y1, x2, y2, x3, y3, beta_scalar, -1 }; + composer.create_ecc_add_gate(gate); + + // Add some RAM gates + uint32_t ram_values[8]{ + composer.add_variable(fr::random_element()), composer.add_variable(fr::random_element()), + composer.add_variable(fr::random_element()), composer.add_variable(fr::random_element()), + composer.add_variable(fr::random_element()), composer.add_variable(fr::random_element()), + composer.add_variable(fr::random_element()), composer.add_variable(fr::random_element()), + }; + + size_t ram_id = composer.create_RAM_array(8); + + for (size_t i = 0; i < 8; ++i) { + composer.init_RAM_element(ram_id, i, ram_values[i]); + } + + a_idx = composer.read_RAM_array(ram_id, composer.add_variable(5)); + EXPECT_EQ(a_idx != ram_values[5], true); + + b_idx = composer.read_RAM_array(ram_id, composer.add_variable(4)); + c_idx = composer.read_RAM_array(ram_id, composer.add_variable(1)); + + composer.write_RAM_array(ram_id, composer.add_variable(4), composer.add_variable(500)); + d_idx = composer.read_RAM_array(ram_id, composer.add_variable(4)); + + EXPECT_EQ(composer.get_variable(d_idx), 500); + + // ensure these vars get used in another arithmetic gate + const auto e_value = composer.get_variable(a_idx) + composer.get_variable(b_idx) + composer.get_variable(c_idx) + + composer.get_variable(d_idx); + e_idx = composer.add_variable(e_value); + + composer.create_big_add_gate({ a_idx, b_idx, c_idx, d_idx, -1, -1, -1, -1, 0 }, true); + composer.create_big_add_gate( + { + composer.get_zero_idx(), + composer.get_zero_idx(), + composer.get_zero_idx(), + e_idx, + 0, + 0, + 0, + 0, + 0, + }, + false); + + // Create a prover (it will compute proving key and witness) + auto prover = composer.create_prover(); + + // Generate eta, beta and gamma + fr eta = fr::random_element(); + fr beta = fr::random_element(); + fr gamma = fr::random_element(); + + // Compute public input delta + const auto public_inputs = composer.circuit_constructor.get_public_inputs(); + auto public_input_delta = + honk::compute_public_input_delta(public_inputs, beta, gamma, prover.key->circuit_size); + auto lookup_grand_product_delta = + honk::compute_lookup_grand_product_delta(beta, gamma, prover.key->circuit_size); + + sumcheck::RelationParameters relation_parameters{ + .eta = eta, + .beta = beta, + .gamma = gamma, + .public_input_delta = public_input_delta, + .lookup_grand_product_delta = lookup_grand_product_delta, + }; + + // Compute sorted witness-table accumulator + prover.key->sorted_accum = prover_library::compute_sorted_list_accumulator(prover.key, eta); + + // Add RAM/ROM memory records to wire four + prover_library::add_plookup_memory_records_to_wire_4(prover.key, eta); + + // Compute grand product polynomial + prover.key->z_perm = prover_library::compute_permutation_grand_product(prover.key, beta, gamma); + + // Compute lookup grand product polynomial + prover.key->z_lookup = prover_library::compute_lookup_grand_product(prover.key, eta, beta, gamma); + + ProverPolynomials prover_polynomials; + + prover_polynomials.w_l = prover.key->w_l; + prover_polynomials.w_r = prover.key->w_r; + prover_polynomials.w_o = prover.key->w_o; + prover_polynomials.w_4 = prover.key->w_4; + prover_polynomials.w_l_shift = prover.key->w_l.shifted(); + prover_polynomials.w_r_shift = prover.key->w_r.shifted(); + prover_polynomials.w_o_shift = prover.key->w_o.shifted(); + prover_polynomials.w_4_shift = prover.key->w_4.shifted(); + prover_polynomials.sorted_accum = prover.key->sorted_accum; + prover_polynomials.sorted_accum_shift = prover.key->sorted_accum.shifted(); + prover_polynomials.table_1 = prover.key->table_1; + prover_polynomials.table_2 = prover.key->table_2; + prover_polynomials.table_3 = prover.key->table_3; + prover_polynomials.table_4 = prover.key->table_4; + prover_polynomials.table_1_shift = prover.key->table_1.shifted(); + prover_polynomials.table_2_shift = prover.key->table_2.shifted(); + prover_polynomials.table_3_shift = prover.key->table_3.shifted(); + prover_polynomials.table_4_shift = prover.key->table_4.shifted(); + prover_polynomials.z_perm = prover.key->z_perm; + prover_polynomials.z_perm_shift = prover.key->z_perm.shifted(); + prover_polynomials.z_lookup = prover.key->z_lookup; + prover_polynomials.z_lookup_shift = prover.key->z_lookup.shifted(); + prover_polynomials.q_m = prover.key->q_m; + prover_polynomials.q_l = prover.key->q_l; + prover_polynomials.q_r = prover.key->q_r; + prover_polynomials.q_o = prover.key->q_o; + prover_polynomials.q_c = prover.key->q_c; + prover_polynomials.q_4 = prover.key->q_4; + prover_polynomials.q_arith = prover.key->q_arith; + prover_polynomials.q_sort = prover.key->q_sort; + prover_polynomials.q_elliptic = prover.key->q_elliptic; + prover_polynomials.q_aux = prover.key->q_aux; + prover_polynomials.q_lookup = prover.key->q_lookup; + prover_polynomials.sigma_1 = prover.key->sigma_1; + prover_polynomials.sigma_2 = prover.key->sigma_2; + prover_polynomials.sigma_3 = prover.key->sigma_3; + prover_polynomials.sigma_4 = prover.key->sigma_4; + prover_polynomials.id_1 = prover.key->id_1; + prover_polynomials.id_2 = prover.key->id_2; + prover_polynomials.id_3 = prover.key->id_3; + prover_polynomials.id_4 = prover.key->id_4; + prover_polynomials.lagrange_first = prover.key->lagrange_first; + prover_polynomials.lagrange_last = prover.key->lagrange_last; + + auto prover_transcript = ProverTranscript::init_empty(); + + auto sumcheck_prover = Sumcheck, + UltraArithmeticRelation, + UltraPermutationRelation, + LookupRelation, + GenPermSortRelation, + EllipticRelation, + AuxiliaryRelation>(prover.key->circuit_size, prover_transcript); + + auto prover_output = sumcheck_prover.execute_prover(prover_polynomials, relation_parameters); + + auto verifier_transcript = VerifierTranscript::init_empty(prover_transcript); + + auto sumcheck_verifier = Sumcheck, + UltraArithmeticRelation, + UltraPermutationRelation, + LookupRelation, + GenPermSortRelation, + EllipticRelation, + AuxiliaryRelation>(prover.key->circuit_size, verifier_transcript); + + std::optional verifier_output = sumcheck_verifier.execute_verifier(relation_parameters); + + ASSERT_TRUE(verifier_output.has_value()); +} + } // namespace test_sumcheck_round diff --git a/cpp/src/barretenberg/honk/sumcheck/sumcheck_round.test.cpp b/cpp/src/barretenberg/honk/sumcheck/sumcheck_round.test.cpp index 85c9312d06..88b511191b 100644 --- a/cpp/src/barretenberg/honk/sumcheck/sumcheck_round.test.cpp +++ b/cpp/src/barretenberg/honk/sumcheck/sumcheck_round.test.cpp @@ -12,10 +12,8 @@ #include /** * We want to test if the univariate (S_l in the thesis) computed by the prover in a particular round is correct. We - * also want to verify given the purported evaluations of all the relevant polynomials, the verifer can correctly - verify - * the purported evaluation of S_l. For the prover, we use a couple of methods to compute the univariate by the - sumcheck + * also want to verify given the purported evaluations of all the relevant polynomials, the verifer can correctly verify + * the purported evaluation of S_l. For the prover, we use a couple of methods to compute the univariate by the sumcheck * method `compute_univariate` and by step by step manual computation respectively. For the verifier, we follow a * similar approach. */ From 9bc506db81b807441d1e3bab8cbaee284748668d Mon Sep 17 00:00:00 2001 From: ledwards2225 Date: Thu, 25 May 2023 19:24:50 +0000 Subject: [PATCH 18/18] adressing Maras review comments mostly through updated docs --- cpp/src/barretenberg/honk/flavor/standard.hpp | 2 +- .../relations/arithmetic_relation.hpp | 7 +++ .../sumcheck/relations/auxiliary_relation.hpp | 35 +++++++++++- .../sumcheck/relations/elliptic_relation.hpp | 7 +++ .../relations/gen_perm_sort_relation.hpp | 7 +++ .../sumcheck/relations/lookup_relation.hpp | 7 +++ .../relations/permutation_relation.hpp | 14 +++++ .../relations/relation_consistency.test.cpp | 21 ++++---- .../relations/ultra_arithmetic_relation.hpp | 53 +++++++++++++++++-- .../ultra_relation_consistency.test.cpp | 22 ++++---- .../honk/sumcheck/sumcheck_round.hpp | 2 + .../honk/sumcheck/sumcheck_round.test.cpp | 19 ------- 12 files changed, 150 insertions(+), 46 deletions(-) diff --git a/cpp/src/barretenberg/honk/flavor/standard.hpp b/cpp/src/barretenberg/honk/flavor/standard.hpp index b14c581e21..29fed767c0 100644 --- a/cpp/src/barretenberg/honk/flavor/standard.hpp +++ b/cpp/src/barretenberg/honk/flavor/standard.hpp @@ -41,7 +41,7 @@ class Standard { using CommitmentHandle = G1::affine_element; using PCSParams = pcs::kzg::Params; - static constexpr size_t NUM_WIRES = CircuitConstructor::NUM_WIRES; // MERGETODO + static constexpr size_t NUM_WIRES = CircuitConstructor::NUM_WIRES; // The number of multivariate polynomials on which a sumcheck prover sumcheck operates (including shifts). We often // need containers of this size to hold related data, so we choose a name more agnostic than `NUM_POLYNOMIALS` static constexpr size_t NUM_ALL_ENTITIES = 18; diff --git a/cpp/src/barretenberg/honk/sumcheck/relations/arithmetic_relation.hpp b/cpp/src/barretenberg/honk/sumcheck/relations/arithmetic_relation.hpp index be7a9ee261..1f0349fae5 100644 --- a/cpp/src/barretenberg/honk/sumcheck/relations/arithmetic_relation.hpp +++ b/cpp/src/barretenberg/honk/sumcheck/relations/arithmetic_relation.hpp @@ -53,6 +53,13 @@ template class ArithmeticRelation { std::get<0>(evals) += tmp; }; + /** + * @brief Add the result of each identity in this relation evaluated at the multivariate evaluations produced by the + * Sumcheck Prover. + * + * @param full_honk_relation_value + * @param purported_evaluations + */ void add_full_relation_value_contribution(RelationValues& full_honk_relation_value, const auto& purported_evaluations, const RelationParameters&) const diff --git a/cpp/src/barretenberg/honk/sumcheck/relations/auxiliary_relation.hpp b/cpp/src/barretenberg/honk/sumcheck/relations/auxiliary_relation.hpp index 4a89ac5934..890e16326b 100644 --- a/cpp/src/barretenberg/honk/sumcheck/relations/auxiliary_relation.hpp +++ b/cpp/src/barretenberg/honk/sumcheck/relations/auxiliary_relation.hpp @@ -26,8 +26,32 @@ template class AuxiliaryRelation { /** * @brief Expression for the generalized permutation sort gate. - * @details The relation is defined as C(extended_edges(X)...) = - * TODO(#452)(luke): Fully document all constraints handled by this relation. + * @details The following explanation is reproduced from the Plonk analog 'plookup_auxiliary_widget': + * Adds contributions for identities associated with several custom gates: + * * RAM/ROM read-write consistency check + * * RAM timestamp difference consistency check + * * RAM/ROM index difference consistency check + * * Bigfield product evaluation (3 in total) + * * Bigfield limb accumulation (2 in total) + * + * Multiple selectors are used to 'switch' aux gates on/off according to the following pattern: + * + * | gate type | q_aux | q_1 | q_2 | q_3 | q_4 | q_m | q_c | q_arith | + * | ---------------------------- | ----- | --- | --- | --- | --- | --- | --- | ------ | + * | Bigfield Limb Accumulation 1 | 1 | 0 | 0 | 1 | 1 | 0 | --- | 0 | + * | Bigfield Limb Accumulation 2 | 1 | 0 | 0 | 1 | 0 | 1 | --- | 0 | + * | Bigfield Product 1 | 1 | 0 | 1 | 1 | 0 | 0 | --- | 0 | + * | Bigfield Product 2 | 1 | 0 | 1 | 0 | 1 | 0 | --- | 0 | + * | Bigfield Product 3 | 1 | 0 | 1 | 0 | 0 | 1 | --- | 0 | + * | RAM/ROM access gate | 1 | 1 | 0 | 0 | 0 | 1 | --- | 0 | + * | RAM timestamp check | 1 | 1 | 0 | 0 | 1 | 0 | --- | 0 | + * | ROM consistency check | 1 | 1 | 1 | 0 | 0 | 0 | --- | 0 | + * | RAM consistency check | 1 | 0 | 0 | 0 | 0 | 0 | 0 | 1 | + * + * N.B. The RAM consistency check identity is degree 3. To keep the overall quotient degree at <=5, only 2 selectors + * can be used to select it. + * + * N.B.2 The q_c selector is used to store circuit-specific values in the RAM/ROM access gate * * @param evals transformed to `evals + C(extended_edges(X)...)*scaling_factor` * @param extended_edges an std::array containing the fully extended Univariate edges. @@ -266,6 +290,13 @@ template class AuxiliaryRelation { std::get<0>(evals) += auxiliary_identity; }; + /** + * @brief Add the result of each identity in this relation evaluated at the multivariate evaluations produced by the + * Sumcheck Prover. + * + * @param full_honk_relation_value + * @param purported_evaluations + */ void add_full_relation_value_contribution(RelationValues& full_honk_relation_value, const auto& purported_evaluations, const RelationParameters& relation_parameters) const diff --git a/cpp/src/barretenberg/honk/sumcheck/relations/elliptic_relation.hpp b/cpp/src/barretenberg/honk/sumcheck/relations/elliptic_relation.hpp index 3265dec03c..f05cacbf5b 100644 --- a/cpp/src/barretenberg/honk/sumcheck/relations/elliptic_relation.hpp +++ b/cpp/src/barretenberg/honk/sumcheck/relations/elliptic_relation.hpp @@ -97,6 +97,13 @@ template class EllipticRelation { } }; + /** + * @brief Add the result of each identity in this relation evaluated at the multivariate evaluations produced by the + * Sumcheck Prover. + * + * @param full_honk_relation_value + * @param purported_evaluations + */ void add_full_relation_value_contribution(RelationValues& full_honk_relation_value, const auto& purported_evaluations, const RelationParameters&) const diff --git a/cpp/src/barretenberg/honk/sumcheck/relations/gen_perm_sort_relation.hpp b/cpp/src/barretenberg/honk/sumcheck/relations/gen_perm_sort_relation.hpp index 39ff5595b7..d4649acafa 100644 --- a/cpp/src/barretenberg/honk/sumcheck/relations/gen_perm_sort_relation.hpp +++ b/cpp/src/barretenberg/honk/sumcheck/relations/gen_perm_sort_relation.hpp @@ -98,6 +98,13 @@ template class GenPermSortRelation { std::get<3>(evals) += tmp_4; }; + /** + * @brief Add the result of each identity in this relation evaluated at the multivariate evaluations produced by the + * Sumcheck Prover. + * + * @param full_honk_relation_value + * @param purported_evaluations + */ void add_full_relation_value_contribution(RelationValues& full_honk_relation_value, const auto& purported_evaluations, const RelationParameters&) const diff --git a/cpp/src/barretenberg/honk/sumcheck/relations/lookup_relation.hpp b/cpp/src/barretenberg/honk/sumcheck/relations/lookup_relation.hpp index 1ae3794306..b08a2bdedd 100644 --- a/cpp/src/barretenberg/honk/sumcheck/relations/lookup_relation.hpp +++ b/cpp/src/barretenberg/honk/sumcheck/relations/lookup_relation.hpp @@ -115,6 +115,13 @@ template class LookupRelation { } }; + /** + * @brief Add the result of each identity in this relation evaluated at the multivariate evaluations produced by the + * Sumcheck Prover. + * + * @param full_honk_relation_value + * @param purported_evaluations + */ void add_full_relation_value_contribution(RelationValues& full_honk_relation_value, auto& purported_evaluations, const RelationParameters& relation_parameters) const diff --git a/cpp/src/barretenberg/honk/sumcheck/relations/permutation_relation.hpp b/cpp/src/barretenberg/honk/sumcheck/relations/permutation_relation.hpp index 4a993a9639..f613f0c3b6 100644 --- a/cpp/src/barretenberg/honk/sumcheck/relations/permutation_relation.hpp +++ b/cpp/src/barretenberg/honk/sumcheck/relations/permutation_relation.hpp @@ -77,6 +77,13 @@ template class PermutationRelation { } }; + /** + * @brief Add the result of each identity in this relation evaluated at the multivariate evaluations produced by the + * Sumcheck Prover. + * + * @param full_honk_relation_value + * @param purported_evaluations + */ void add_full_relation_value_contribution(RelationValues& full_honk_relation_value, auto& purported_evaluations, const RelationParameters& relation_parameters) const @@ -181,6 +188,13 @@ template class UltraPermutationRelation { } }; + /** + * @brief Add the result of each identity in this relation evaluated at the multivariate evaluations produced by the + * Sumcheck Prover. + * + * @param full_honk_relation_value + * @param purported_evaluations + */ void add_full_relation_value_contribution(RelationValues& full_honk_relation_value, auto& purported_evaluations, const RelationParameters& relation_parameters) const diff --git a/cpp/src/barretenberg/honk/sumcheck/relations/relation_consistency.test.cpp b/cpp/src/barretenberg/honk/sumcheck/relations/relation_consistency.test.cpp index 567846c756..f794b16603 100644 --- a/cpp/src/barretenberg/honk/sumcheck/relations/relation_consistency.test.cpp +++ b/cpp/src/barretenberg/honk/sumcheck/relations/relation_consistency.test.cpp @@ -14,14 +14,14 @@ #include using namespace proof_system::honk::sumcheck; /** - * We want to test if all three relations (namely, ArithmeticRelation, PermutationRelation) - * provide correct contributions by manually computing their - * contributions with deterministic and random inputs. The relations are supposed to work with - * univariates (edges) of degree one (length 2) and spit out polynomials of corresponding degrees. We have - * MAX_RELATION_LENGTH = 5, meaning the output of a relation can atmost be a degree 5 polynomial. Hence, - * we use a method compute_mock_extended_edges() which starts with degree one input polynomial (two evaluation - points), - * extends them (using barycentric formula) to six evaluation points, and stores them to an array of polynomials. + * The purpose of this test suite is to show that the identity arithmetic implemented in the Relations is equivalent to + * a simpler unoptimized version implemented in the tests themselves. This is useful 1) as documentation since the + * simple implementations here should make the underlying arithmetic easier to see, and 2) as a check that optimizations + * introduced into the Relations have not changed the result. + * + * For this purpose, we simply feed (the same) random inputs into each of the two implementations and confirm that + * the outputs match. This does not confirm the correctness of the identity arithmetic (the identities will not be + * satisfied in general by random inputs) only that the two implementations are equivalent. */ static const size_t INPUT_UNIVARIATE_LENGTH = 2; @@ -111,7 +111,9 @@ class StandardRelationConsistency : public testing::Test { const RelationParameters& relation_parameters) { // First check that the verifier's computation on individual evaluations is correct. - // Note: it is sufficient to check at only the first index of the input edges. + // Note: since add_full_relation_value_contribution computes the identities at a single evaluation of the + // multivariates, we need only pass in one evaluation point from the extended edges. Which one we choose is + // arbitrary so we choose the 0th. // Extract the RelationValues type for the given relation using RelationValues = typename decltype(relation)::RelationValues; @@ -125,7 +127,6 @@ class StandardRelationConsistency : public testing::Test { expected_relation_evals[idx] = expected_full_length_univariates[idx].value_at(0); } - // MERGETODO? // Extract 0th evaluation from extended edges ClaimedEvaluations edge_evaluations = transposed_univariate_array_at(extended_edges, 0); diff --git a/cpp/src/barretenberg/honk/sumcheck/relations/ultra_arithmetic_relation.hpp b/cpp/src/barretenberg/honk/sumcheck/relations/ultra_arithmetic_relation.hpp index 83e0e9dc3f..1ea1de263e 100644 --- a/cpp/src/barretenberg/honk/sumcheck/relations/ultra_arithmetic_relation.hpp +++ b/cpp/src/barretenberg/honk/sumcheck/relations/ultra_arithmetic_relation.hpp @@ -13,6 +13,7 @@ template class UltraArithmeticRelation { static constexpr size_t RELATION_LENGTH = 6; // degree(q_arith^2 * q_m * w_r * w_l) = 5 static constexpr size_t NUM_CONSTRAINTS = 2; + // TODO(luke): The degree of the identities varies based on q_arith. Can we do something to improve efficiency here? static constexpr std::array CONSTRAINT_LENGTH = { 6, 5 }; using RelationUnivariates = std::tuple, Univariate>; @@ -20,11 +21,46 @@ template class UltraArithmeticRelation { /** * @brief Expression for the Ultra Arithmetic gate. - * @details The relation is defined as C(extended_edges(X)...) = - * q_arith * - * [ -1/2(q_arith - 3)(q_m * w_r * w_l) + - * (q_l * w_l) + (q_r * w_r) + (q_o * w_o) + (q_4 * w_4) + q_c + - * (q_arith - 1)w_4_shift ] + * @details This relation encapsulates several idenitities, toggled by the value of q_arith in [0, 1, 2, 3, ...]. + * The following description is reproduced from the Plonk analog 'plookup_arithmetic_widget': + * The whole formula is: + * + * q_arith * ( ( (-1/2) * (q_arith - 3) * q_m * w_1 * w_2 + q_1 * w_1 + q_2 * w_2 + q_3 * w_3 + q_4 * w_4 + q_c ) + + * (q_arith - 1)*( α * (q_arith - 2) * (w_1 + w_4 - w_1_omega + q_m) + w_4_omega) ) = 0 + * + * This formula results in several cases depending on q_arith: + * 1. q_arith == 0: Arithmetic gate is completely disabled + * + * 2. q_arith == 1: Everything in the minigate on the right is disabled. The equation is just a standard plonk + * equation with extra wires: q_m * w_1 * w_2 + q_1 * w_1 + q_2 * w_2 + q_3 * w_3 + q_4 * w_4 + q_c = 0 + * + * 3. q_arith == 2: The (w_1 + w_4 - ...) term is disabled. THe equation is: + * (1/2) * q_m * w_1 * w_2 + q_1 * w_1 + q_2 * w_2 + q_3 * w_3 + q_4 * w_4 + q_c + w_4_omega = 0 + * It allows defining w_4 at next index (w_4_omega) in terms of current wire values + * + * 4. q_arith == 3: The product of w_1 and w_2 is disabled, but a mini addition gate is enabled. α² allows us to + * split the equation into two: + * + * q_1 * w_1 + q_2 * w_2 + q_3 * w_3 + q_4 * w_4 + q_c + 2 * w_4_omega = 0 + * + * w_1 + w_4 - w_1_omega + q_m = 0 (we are reusing q_m here) + * + * 5. q_arith > 3: The product of w_1 and w_2 is scaled by (q_arith - 3), while the w_4_omega term is scaled by + * (q_arith + * - 1). The equation can be split into two: + * + * (q_arith - 3)* q_m * w_1 * w_ 2 + q_1 * w_1 + q_2 * w_2 + q_3 * w_3 + q_4 * w_4 + q_c + (q_arith - 1) * w_4_omega + * = 0 + * + * w_1 + w_4 - w_1_omega + q_m = 0 + * + * The problem that q_m is used both in both equations can be dealt with by appropriately changing selector values + * at the next gate. Then we can treat (q_arith - 1) as a simulated q_6 selector and scale q_m to handle (q_arith - + * 3) at product. + * + * The The relation is + * defined as C(extended_edges(X)...) = q_arith * [ -1/2(q_arith - 3)(q_m * w_r * w_l) + (q_l * w_l) + (q_r * w_r) + + * (q_o * w_o) + (q_4 * w_4) + q_c + (q_arith - 1)w_4_shift ] * * q_arith * * (q_arith - 2) * (q_arith - 1) * (w_l + w_4 - w_l_shift + q_m) @@ -84,6 +120,13 @@ template class UltraArithmeticRelation { } }; // namespace proof_system::honk::sumcheck + /** + * @brief Add the result of each identity in this relation evaluated at the multivariate evaluations produced by the + * Sumcheck Prover. + * + * @param full_honk_relation_value + * @param purported_evaluations + */ void add_full_relation_value_contribution(RelationValues& full_honk_relation_value, const auto& purported_evaluations, const RelationParameters&) const diff --git a/cpp/src/barretenberg/honk/sumcheck/relations/ultra_relation_consistency.test.cpp b/cpp/src/barretenberg/honk/sumcheck/relations/ultra_relation_consistency.test.cpp index 8fdc4cf3be..1be27d4bda 100644 --- a/cpp/src/barretenberg/honk/sumcheck/relations/ultra_relation_consistency.test.cpp +++ b/cpp/src/barretenberg/honk/sumcheck/relations/ultra_relation_consistency.test.cpp @@ -16,16 +16,18 @@ #include #include +// TODO(luke): This testing infrastructure was duplicated between here and relation_consistency.test.cpp with the +// orignal Flavor PR. Find a way to recombine these test suites or at least share this functionality. using namespace proof_system::honk::sumcheck; /** - * We want to test if all three relations (namely, ArithmeticRelation, GrandProductComputationRelation, - * GrandProductInitializationRelation) provide correct contributions by manually computing their - * contributions with deterministic and random inputs. The relations are supposed to work with - * univariates (edges) of degree one (length 2) and spit out polynomials of corresponding degrees. We have - * MAX_RELATION_LENGTH = 5, meaning the output of a relation can atmost be a degree 5 polynomial. Hence, - * we use a method compute_mock_extended_edges() which starts with degree one input polynomial (two evaluation - points), - * extends them (using barycentric formula) to six evaluation points, and stores them to an array of polynomials. + * The purpose of this test suite is to show that the identity arithmetic implemented in the Relations is equivalent to + * a simpler unoptimized version implemented in the tests themselves. This is useful 1) as documentation since the + * simple implementations here should make the underlying arithmetic easier to see, and 2) as a check that optimizations + * introduced into the Relations have not changed the result. + * + * For this purpose, we simply feed (the same) random inputs into each of the two implementations and confirm that + * the outputs match. This does not confirm the correctness of the identity arithmetic (the identities will not be + * satisfied in general by random inputs) only that the two implementations are equivalent. */ static const size_t INPUT_UNIVARIATE_LENGTH = 2; @@ -115,7 +117,9 @@ class UltraRelationConsistency : public testing::Test { const RelationParameters& relation_parameters) { // First check that the verifier's computation on individual evaluations is correct. - // Note: it is sufficient to check at only the first index of the input edges. + // Note: since add_full_relation_value_contribution computes the identities at a single evaluation of the + // multivariates, we need only pass in one evaluation point from the extended edges. Which one we choose is + // arbitrary so we choose the 0th. // Extract the RelationValues type for the given relation using RelationValues = typename decltype(relation)::RelationValues; diff --git a/cpp/src/barretenberg/honk/sumcheck/sumcheck_round.hpp b/cpp/src/barretenberg/honk/sumcheck/sumcheck_round.hpp index a6ead723a3..a90d422e51 100644 --- a/cpp/src/barretenberg/honk/sumcheck/sumcheck_round.hpp +++ b/cpp/src/barretenberg/honk/sumcheck/sumcheck_round.hpp @@ -87,6 +87,7 @@ template class SumcheckRound { SumcheckRound(size_t initial_round_size) : round_size(initial_round_size) { + // Initialize univariate accumulators to 0 zero_univariates(univariate_accumulators); } @@ -107,6 +108,7 @@ template class SumcheckRound { auto result = Univariate(); extend_and_batch_univariates(univariate_accumulators, result); + // Reset all univariate accumulators to 0 before beginning accumulation in the next round zero_univariates(univariate_accumulators); return result; } diff --git a/cpp/src/barretenberg/honk/sumcheck/sumcheck_round.test.cpp b/cpp/src/barretenberg/honk/sumcheck/sumcheck_round.test.cpp index 3dffe00a6c..c5e7260be4 100644 --- a/cpp/src/barretenberg/honk/sumcheck/sumcheck_round.test.cpp +++ b/cpp/src/barretenberg/honk/sumcheck/sumcheck_round.test.cpp @@ -39,25 +39,6 @@ static Univariate compute_round_univariate( size_t round_size = 1; // Improvement(Cody): This is ugly? Maye supply some/all of this data through "flavor" class? auto round = SumcheckRound(round_size); - // MERGETODO - // auto w_l = input_polynomials[0]; - // auto w_r = input_polynomials[1]; - // auto w_o = input_polynomials[2]; - // auto z_perm = input_polynomials[3]; - // auto z_perm_shift = input_polynomials[4]; - // auto q_m = input_polynomials[5]; - // auto q_l = input_polynomials[6]; - // auto q_r = input_polynomials[7]; - // auto q_o = input_polynomials[8]; - // auto q_c = input_polynomials[9]; - // auto sigma_1 = input_polynomials[10]; - // auto sigma_2 = input_polynomials[11]; - // auto sigma_3 = input_polynomials[12]; - // auto id_1 = input_polynomials[13]; - // auto id_2 = input_polynomials[14]; - // auto id_3 = input_polynomials[15]; - // auto lagrange_first = input_polynomials[16]; - // auto lagrange_last = input_polynomials[17]; ProverPolynomials full_polynomials; full_polynomials.w_l = input_polynomials[0];