diff --git a/barretenberg/cpp/cmake/toolchains/x86_64-linux-gcc.cmake b/barretenberg/cpp/cmake/toolchains/x86_64-linux-gcc.cmake index bf0027451c7e..9cd8af83f785 100644 --- a/barretenberg/cpp/cmake/toolchains/x86_64-linux-gcc.cmake +++ b/barretenberg/cpp/cmake/toolchains/x86_64-linux-gcc.cmake @@ -1,4 +1,5 @@ set(CMAKE_C_COMPILER "gcc") set(CMAKE_CXX_COMPILER "g++") # TODO(Cody): git rid of this when Adrian's work goes in -add_compile_options(-Wno-uninitialized) \ No newline at end of file +add_compile_options(-Wno-uninitialized) +add_compile_options(-Wno-maybe-uninitialized) \ No newline at end of file diff --git a/barretenberg/cpp/cmake/toolchains/x86_64-linux-gcc10.cmake b/barretenberg/cpp/cmake/toolchains/x86_64-linux-gcc10.cmake index f7095a1ff79d..36fdcfacc85f 100644 --- a/barretenberg/cpp/cmake/toolchains/x86_64-linux-gcc10.cmake +++ b/barretenberg/cpp/cmake/toolchains/x86_64-linux-gcc10.cmake @@ -1,4 +1,5 @@ set(CMAKE_C_COMPILER "gcc-10") set(CMAKE_CXX_COMPILER "g++-10") # TODO(Cody): git rid of this when Adrian's work goes in -add_compile_options(-Wno-uninitialized) \ No newline at end of file +add_compile_options(-Wno-uninitialized) +add_compile_options(-Wno-maybe-uninitialized) \ No newline at end of file diff --git a/barretenberg/cpp/src/aztec/honk/flavor/flavor.hpp b/barretenberg/cpp/src/aztec/honk/flavor/flavor.hpp new file mode 100644 index 000000000000..e39485183e47 --- /dev/null +++ b/barretenberg/cpp/src/aztec/honk/flavor/flavor.hpp @@ -0,0 +1,40 @@ +#pragma once +#include + +class StandardArithmetization { + public: + enum POLYNOMIAL { + 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_1, + COUNT + }; + + static constexpr size_t NUM_POLYNOMIALS = POLYNOMIAL::COUNT; +}; + +namespace honk::sumcheck { // TODO(Cody): get namespaces right here +class StandardHonk { + public: + using Arithmetization = StandardArithmetization; + using MULTIVARIATE = Arithmetization::POLYNOMIAL; + static constexpr size_t MAX_RELATION_LENGTH = 5; // TODO(Cody): increment after fixing add_edge_contribution; kill + // after moving barycentric class out of relations + + // TODO(Cody): should extract this from the parameter pack. Maybe that should be done here? +}; +} // namespace honk::sumcheck \ No newline at end of file diff --git a/barretenberg/cpp/src/aztec/honk/flavor/flavor.test.cpp b/barretenberg/cpp/src/aztec/honk/flavor/flavor.test.cpp new file mode 100644 index 000000000000..55072e64f552 --- /dev/null +++ b/barretenberg/cpp/src/aztec/honk/flavor/flavor.test.cpp @@ -0,0 +1,31 @@ +#include "flavor.hpp" + +#include + +using namespace honk::sumcheck; +namespace test_flavor { + +// // TODO(Cody) This seems like a good idea, but I'm not sure why. +// TEST(Flavor, StandardArithmetization){ +// EXPECT_EQ(StandardArithmetization::MULTIVARIATE::W_L, 0); +// EXPECT_EQ(StandardArithmetization::MULTIVARIATE::W_R, 1); +// EXPECT_EQ(StandardArithmetization::MULTIVARIATE::W_O, 2); +// EXPECT_EQ(StandardArithmetization::MULTIVARIATE::Z_PERM, 3); +// EXPECT_EQ(StandardArithmetization::MULTIVARIATE::Z_PERM_SHIFT, 4); +// EXPECT_EQ(StandardArithmetization::MULTIVARIATE::Q_M, 5); +// EXPECT_EQ(StandardArithmetization::MULTIVARIATE::Q_L, 6); +// EXPECT_EQ(StandardArithmetization::MULTIVARIATE::Q_R, 7); +// EXPECT_EQ(StandardArithmetization::MULTIVARIATE::Q_O, 8); +// EXPECT_EQ(StandardArithmetization::MULTIVARIATE::Q_C, 9); +// EXPECT_EQ(StandardArithmetization::MULTIVARIATE::SIGMA_1, 10); +// EXPECT_EQ(StandardArithmetization::MULTIVARIATE::SIGMA_2, 11); +// EXPECT_EQ(StandardArithmetization::MULTIVARIATE::SIGMA_3, 12); +// EXPECT_EQ(StandardArithmetization::MULTIVARIATE::ID_1, 13); +// EXPECT_EQ(StandardArithmetization::MULTIVARIATE::ID_2, 14); +// EXPECT_EQ(StandardArithmetization::MULTIVARIATE::ID_3, 15); +// EXPECT_EQ(StandardArithmetization::MULTIVARIATE::LAGRANGE_1, 16); +// EXPECT_EQ(StandardArithmetization::MULTIVARIATE::COUNT, 17); + +// } + +} // namespace test_flavor diff --git a/barretenberg/cpp/src/aztec/honk/sumcheck/challenge_container.hpp b/barretenberg/cpp/src/aztec/honk/sumcheck/challenge_container.hpp new file mode 100644 index 000000000000..fedb521efc65 --- /dev/null +++ b/barretenberg/cpp/src/aztec/honk/sumcheck/challenge_container.hpp @@ -0,0 +1,47 @@ +#pragma once +#include // for size_t, for now +#include +#include "transcript.hpp" +#include "../flavor/flavor.hpp" + +namespace honk::sumcheck { +// TODO(Cody): This is just for present purposes. I think this kind of structure is nice, but for the purpose of getting +// the PoC working we should link this/replace with existing transcript, then refactor later. +// +// TODO(Cody): needs to know number of rounds? +// TODO(Cody): Univariate class should not be provided as a template parameter? +template class ChallengeContainer { + public: + Transcript transcript; // TODO(Cody):really a pointer to such a thing? + explicit ChallengeContainer(Transcript transcript) + : transcript(transcript){}; + + FF get_relation_separator_challenge() { return transcript.get_challenge(); }; // these are powers of a challenge + + // FF get_relation_bliding_base(){return transcript.get_challenge(1);} // will get element zeta as well + + FF get_challenge_equals_one() { return transcript.get_challenge_equals_one(); }; + + FF get_grand_product_beta_challenge() { return transcript.get_challenge_equals_one(); }; + + FF get_grand_product_gamma_challenge() { return transcript.get_challenge_equals_one(); }; + + FF get_sumcheck_round_challenge(size_t) // NOLINT(readability-named-parameter) + { + return transcript.get_challenge(); + }; + + Univariate get_sumcheck_round_univariate(size_t) // NOLINT(readability-named-parameter) + { + Univariate result; + return result; + }; + + std::vector get_sumcheck_purported_evaluations() + { + std::vector result{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }; + return result; + }; + // TODO(Cody): Leaving how things are added to the transcript as a black box for now. +}; +} // namespace honk::sumcheck diff --git a/barretenberg/cpp/src/aztec/honk/sumcheck/sumcheck_types/barycentric_data.hpp b/barretenberg/cpp/src/aztec/honk/sumcheck/polynomials/barycentric_data.hpp similarity index 88% rename from barretenberg/cpp/src/aztec/honk/sumcheck/sumcheck_types/barycentric_data.hpp rename to barretenberg/cpp/src/aztec/honk/sumcheck/polynomials/barycentric_data.hpp index 1dad6b20a82f..6575ee516328 100644 --- a/barretenberg/cpp/src/aztec/honk/sumcheck/sumcheck_types/barycentric_data.hpp +++ b/barretenberg/cpp/src/aztec/honk/sumcheck/polynomials/barycentric_data.hpp @@ -1,23 +1,32 @@ #pragma once #include #include -#include #include "univariate.hpp" #pragma GCC diagnostic ignored "-Wunused-variable" #pragma GCC diagnostic ignored "-Wunused-parameter" -namespace honk { -namespace sumcheck { +/* IMPROVEMENT(Cody): This could or should be improved in various ways. In no particular order: + 1) Edge cases are not considered. One non-use case situation (I forget which) leads to a segfault. + + 2) This could all be constexpr. + + 3) Precomputing for all possible size pairs is probably feasible and might be a better solution than instantiating + many instances separately. Then perhaps we could infer input type to `extend`. + + 4) There should be more thorough testing of this class in isolation. + */ +namespace honk::sumcheck { /** * NOTE: We should definitely consider question of optimal choice of domain, but if decide on {0,1,...,t-1} then we can * simplify the implementation a bit. + * NOTE: if we use this approach in the recursive setting, will use Plookup? */ template class BarycentricData { public: static constexpr size_t big_domain_size = std::max(domain_size, num_evals); - // TODO: these should be static, also constexpr, but arrays are not constexpr + // TODO(Cody): these should be static, also constexpr, but arrays are not constexpr std::array big_domain; std::array lagrange_denominators; std::array precomputed_denominator_inverses; @@ -141,5 +150,4 @@ template class BarycentricData return result; }; }; -} // namespace sumcheck -} // namespace honk +} // namespace honk::sumcheck diff --git a/barretenberg/cpp/src/aztec/honk/sumcheck/polynomials/multivariates.hpp b/barretenberg/cpp/src/aztec/honk/sumcheck/polynomials/multivariates.hpp new file mode 100644 index 000000000000..2eabad2ce629 --- /dev/null +++ b/barretenberg/cpp/src/aztec/honk/sumcheck/polynomials/multivariates.hpp @@ -0,0 +1,113 @@ +#pragma once // just adding these willy-nilly +#include +#include +#include +#include + +namespace honk { +namespace sumcheck { + +// std::span has no comparison operator, so this is a quick-and-dirty workaround for testing +// IMPROVEMENT(Cody): Move and/or implement as == in some class +bool span_arrays_equal(auto& lhs, auto& rhs) +{ + bool result(true); + result = lhs.size() == rhs.size(); + if (result) { + for (size_t i = 0; i < lhs.size(); i++) { + result &= std::equal(lhs[i].begin(), lhs[i].end(), rhs[i].begin(), rhs[i].end()); + }; + } + return result; +} + +/** + * + * @brief A container for all of the Honk polynomials (wire and selector polynomials, grand product, and much more). + * These polynomials all low-degree extensions over H^d with H = {0, 1} (where d = ceil(log(number of gates))), hence + * they are multilinear polynomials in d variables. As such, it is efficient to store these polynomials in terms of + * univariate degree-1 polynomials. + + * Suppose now the Honk polynomials (multilinear in d variables) are called P_1, ..., P_N. At initialization, + * we think of these as lying in a two-dimensional array, where each column records the value of one P_i on H^d. After + * the first round, the array will be updated ('folded'), so that the first n/2 rows will represent the evaluations + * P_i(X1, ..., X_{d-1}, u_d) as a low-degree extension on H^{d-1}. In reality, we elide copying all of the polynomial- + * defining data by only populating folded_multivariates after the first round. I.e.: + + We imagine all of the defining polynomial data in a matrix like this: + | P_1 | P_2 | P_3 | P_4 | ... | P_N | N = number of multivariatesk + |-----------------------------------| + group 0 --| * | * | * | * | ... | * | vertex 0 + \-| * | * | * | * | ... | * | vertex 1 + group 1 --| * | * | * | * | ... | * | vertex 2 + \-| * | * | * | * | ... | * | vertex 3 + | * | * | * | * | ... | * | + group m-1 --| * | * | * | * | ... | * | vertex n-2 + \-| * | * | * | * | ... | * | vertex n-1 + m = n/2 + * + Each group consists of N edges |, and our construction of univariates and folding + * + operations naturally operate on these groups of edges + + * + * NOTE: With ~40 columns, prob only want to allocate 256 EdgeGroup's at once to keep stack under 1MB? + * TODO(Cody): might want to just do C-style multidimensional array? for guaranteed adjacency? + */ +template class Multivariates { + public: + using FF = FF_; + const static size_t multivariate_d = num_vars; + const static size_t multivariate_n = 1 << num_vars; + static constexpr size_t num = num_polys; + + std::array, num_polys> full_polynomials; + // TODO(Cody): adjacency issues with std::array of std::arrays? + // IMPROVEMENT(Cody): for each round after the first, we could release half of the memory reserved by + // folded_polynomials. + std::array> 1)>, num_polys> folded_polynomials; + + Multivariates() = default; + + // TODO(Cody): static span extent below more efficient + explicit Multivariates(std::array, num_polys> full_polynomials) + : full_polynomials(full_polynomials){}; + + /** + * @brief Evaluate at the round challenge and prepare class for next round. + * Illustration of layout in example of first round when d==3 (showing just one Honk polynomial, + * i.e., what happens in just one column of our two-dimensional array): + * + * groups vertex terms collected vertex terms groups after folding + * g0 -- v0 (1-X1)(1-X2)(1-X3) --- (v0(1-X3) + v1 X3) (1-X1)(1-X2) ---- (v0(1-u3) + v1 u3) (1-X1)(1-X2) + * \- v1 (1-X1)(1-X2) X3 --/ --- (v2(1-u3) + v3 u3) (1-X1) X2 + * g1 -- v2 (1-X1) X2 (1-X3) --- (v1(1-X3) + v2 X3) (1-X1) X2 -/ -- (v4(1-u3) + v5 u3) X1 (1-X2) + * \- v3 (1-X1) X2 X3 --/ / - (v6(1-u3) + v7 u3) X1 X2 + * g2 -- v4 X1 (1-X2)(1-X3) --- (v3(1-X3) + v4 X3) X1 (1-X2)-/ / + * \- v5 X1 (1-X2) X3 --/ / + * g3 -- v6 X1 X2 (1-X3) --- (v5(1-X3) + v6 X3) X1 X2 -/ + * \- v7 X1 X2 X3 --/ + * + * @param challenge + */ + + void fold(auto& polynomials, size_t round_size, const FF& round_challenge) + { + // after the first round, operate in place on folded_polynomials + for (size_t j = 0; j < num_polys; ++j) { + for (size_t i = 0; i < round_size; i += 2) { + folded_polynomials[j][i >> 1] = + polynomials[j][i] + round_challenge * (polynomials[j][i + 1] - polynomials[j][i]); + } + } + }; + + std::array batch_evaluate(std::array input) + { + // TODO(Cody): IOU implementation. + static_cast(input); + return { { 1 } }; + }; +}; +} // namespace sumcheck +} // namespace honk \ No newline at end of file diff --git a/barretenberg/cpp/src/aztec/honk/sumcheck/polynomials/multivariates.test.cpp b/barretenberg/cpp/src/aztec/honk/sumcheck/polynomials/multivariates.test.cpp new file mode 100644 index 000000000000..915dc729d0f7 --- /dev/null +++ b/barretenberg/cpp/src/aztec/honk/sumcheck/polynomials/multivariates.test.cpp @@ -0,0 +1,125 @@ +#include "multivariates.hpp" +#include + +#include +#include + +#pragma GCC diagnostic ignored "-Wunused-variable" +#pragma GCC diagnostic ignored "-Wunused-parameter" + +using namespace honk::sumcheck; +namespace test_sumcheck_polynomials { + +template class MultivariatesTests : public testing::Test { + public: + // template + // using Multivariates = Multivariates; + // TODO(Cody): reinstate this + // /* + // u2 = 1 + // 3 -------- 7 4 -------- 8 ~~> + // | | | | ~~> + // | Y1 | | Y2 | ~~> + // | | | | ~~> + // 1 -------- 5 2 -------- 6 ~~> 3 -------- 7 4 -------- 8 + // (3(1-X1)+7X1) X2 (4(1-X1)+8X1) X2 3(1-X1)+7X1 4(1-X1)+8X1 + // +(1(1-X1)+5X1)(1-X2) +(2(1-X1)+6X1)(1-X2) + // */ + // static void test_fold_2() + // { + // const size_t num_polys(2); + // const size_t multivariate_d(2); + // const size_t multivariate_n(1 << multivariate_d); + + // Edge Y11 = Edge({ 1, 3 }); + // Edge Y12 = Edge({ 5, 7 }); + // Edge Y21 = Edge({ 2, 4 }); + // Edge Y22 = Edge({ 6, 8 }); + + // auto group_1 = EdgeGroup({ Y11, Y21 }); + // auto group_2 = EdgeGroup({ Y12, Y22 }); + + // std::array, multivariate_d> groups{ group_1, group_2 }; + // auto polys = Multivariates(groups); + + // FF u2 = 1; + // polys.fold(n, u2); + + // EXPECT_EQ(polys.groups[0][0].at(0), 3); + // EXPECT_EQ(polys.groups[0][0].at(1), 7); + + // EXPECT_EQ(polys.groups[0][1].at(0), 4); + // EXPECT_EQ(polys.groups[0][1].at(1), 8); + // } +}; + +using FieldTypes = testing::Types; +TYPED_TEST_SUITE(MultivariatesTests, FieldTypes); + +#define MULTIVARIATES_TESTS_TYPE_ALIASES using FF = TypeParam; + +TYPED_TEST(MultivariatesTests, Constructor) +{ + MULTIVARIATES_TESTS_TYPE_ALIASES + + const size_t num_polys(4); + const size_t multivariate_d(2); + // const size_t multivariate_n(1 << multivariate_d); + + std::array f0 = { 0, 0, 1 }; + std::array f1 = { 1, 1, 1 }; + std::array f2 = { 3, 4, 1 }; + std::array f3 = { -1, -1, 1 }; + + auto full_polynomials = std::array, num_polys>({ f0, f1, f2, f3 }); + auto multivariates = Multivariates(full_polynomials); + + ASSERT_TRUE(span_arrays_equal(full_polynomials, multivariates.full_polynomials)); +} + +// IMPROVEMENT(Cody): rewrite or clarify this comment? +/* + u2 = 1 ~~> + v01 ------ v11 ~~> + | | ~~> + | Y | ~~> + | | ~~> + v00 ------ v10 ~~> v00 * (1-u2) + v01 * u2 -------- (v11 * u2 + v10 * (1-u2)) + (v01 * (1-X1) + v11 * X1) * X2 ~~> (v00 * (1-u2) + v01 * u2) * (1-X1) + + (v00 * (1-X1) + v10 * X1) * (1-X2) ~~> + (v11 * u2 + v10 * (1-u2)) * X1 + */ +TYPED_TEST(MultivariatesTests, FoldTwo) +{ + MULTIVARIATES_TESTS_TYPE_ALIASES + + const size_t num_polys(2); + const size_t multivariate_d(1); + const size_t multivariate_n(1 << multivariate_d); + + FF v00 = FF::random_element(); + FF v01 = FF::random_element(); + FF v10 = FF::random_element(); + FF v11 = FF::random_element(); + + std::array f0 = { v00, v10 }; + std::array f1 = { v01, v11 }; + + auto full_polynomials = std::array, 2>({ f0, f1 }); + auto multivariates = Multivariates(full_polynomials); + + FF round_challenge_2 = FF::random_element(); + FF expected_lo = v00 * (FF(1) - round_challenge_2) + v10 * round_challenge_2; + FF expected_hi = v11 * round_challenge_2 + v01 * (FF(1) - round_challenge_2); + + multivariates.fold(multivariates.full_polynomials, multivariate_n, round_challenge_2); + + EXPECT_EQ(multivariates.folded_polynomials[0][0], expected_lo); + EXPECT_EQ(multivariates.folded_polynomials[1][0], expected_hi); + + FF round_challenge_1 = FF::random_element(); + FF expected_val = expected_lo * (FF(1) - round_challenge_1) + expected_hi * round_challenge_1; + + multivariates.fold(multivariates.folded_polynomials, multivariate_n >> 1, round_challenge_1); + EXPECT_EQ(multivariates.folded_polynomials[0][0], expected_val); +} +} // namespace test_sumcheck_polynomials \ No newline at end of file diff --git a/barretenberg/cpp/src/aztec/honk/sumcheck/sumcheck_types/univariate.hpp b/barretenberg/cpp/src/aztec/honk/sumcheck/polynomials/univariate.hpp similarity index 90% rename from barretenberg/cpp/src/aztec/honk/sumcheck/sumcheck_types/univariate.hpp rename to barretenberg/cpp/src/aztec/honk/sumcheck/polynomials/univariate.hpp index 9843b92960cb..722639047cb6 100644 --- a/barretenberg/cpp/src/aztec/honk/sumcheck/sumcheck_types/univariate.hpp +++ b/barretenberg/cpp/src/aztec/honk/sumcheck/polynomials/univariate.hpp @@ -1,17 +1,16 @@ #pragma once #include #include -#include -#include +#include #pragma GCC diagnostic ignored "-Wunused-variable" #pragma GCC diagnostic ignored "-Wunused-parameter" -namespace honk { -namespace sumcheck { +namespace honk::sumcheck { template class UnivariateView; +// TODO(Cody): This violates Rule of Five template class Univariate { public: static constexpr size_t LENGTH = _length; @@ -187,6 +186,22 @@ template class Univariate { res *= view; return res; } + + // Output is immediately parsable as a list of integers by Python. + friend std::ostream& operator<<(std::ostream& os, const Univariate& u) + { + os << "["; + os << u.evaluations[0] << "," << std::endl; + for (size_t i = 1; i < u.evaluations.size(); i++) { + os << " " << u.evaluations[i]; + if (i + 1 < u.evaluations.size()) { + os << "," << std::endl; + } else { + os << "]"; + }; + } + return os; + } }; template class UnivariateView { @@ -257,5 +272,4 @@ template class UnivariateView { return res; } }; -} // namespace sumcheck -} // namespace honk +} // namespace honk::sumcheck diff --git a/barretenberg/cpp/src/aztec/honk/sumcheck/polynomials/univariate.test.cpp b/barretenberg/cpp/src/aztec/honk/sumcheck/polynomials/univariate.test.cpp new file mode 100644 index 000000000000..75545c7263c9 --- /dev/null +++ b/barretenberg/cpp/src/aztec/honk/sumcheck/polynomials/univariate.test.cpp @@ -0,0 +1,197 @@ +#include "univariate.hpp" +#include "barycentric_data.hpp" +#include + +#include +#include + +#pragma GCC diagnostic ignored "-Wunused-variable" +#pragma GCC diagnostic ignored "-Wunused-parameter" + +using namespace honk::sumcheck; +namespace test_univariate { + +template class UnivariateTest : public testing::Test { + public: + template using UnivariateView = UnivariateView; + + // IMPROVEMENT(Cody) this is not used anywhere? Move to memeber function of U/snivariate? + template Univariate random_univariate() + { + auto output = Univariate(); + for (size_t i = 0; i != length; ++i) { + output.value_at(i) = FF::random_element(); + } + return output; + }; +}; + +using FieldTypes = testing::Types; +TYPED_TEST_SUITE(UnivariateTest, FieldTypes); + +#define UNIVARIATE_TESTS_ALIASES using FF = TypeParam; +// IMPROVEMENT: Can't make alias for Univariate for some reason. +// Might be convenient to solve boilerplate or repeated type aliasing +// using this or some other means. + +TYPED_TEST(UnivariateTest, Constructors) +{ + UNIVARIATE_TESTS_ALIASES + + FF a0 = FF::random_element(); + FF a1 = FF::random_element(); + FF a2 = FF::random_element(); + + Univariate uni({ a0, a1, a2 }); + + EXPECT_EQ(uni.value_at(0), a0); + EXPECT_EQ(uni.value_at(1), a1); + EXPECT_EQ(uni.value_at(2), a2); +} + +TYPED_TEST(UnivariateTest, Addition) +{ + UNIVARIATE_TESTS_ALIASES + + Univariate f1{ { 1, 2 } }; + Univariate f2{ { 3, 4 } }; + // output should be {4, 6} + Univariate expected_result{ { 4, 6 } }; + auto f1f2 = f1 + f2; + EXPECT_EQ(f1f2, expected_result); +} + +TYPED_TEST(UnivariateTest, BarycentricData2to3) +{ + UNIVARIATE_TESTS_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(UnivariateTest, BarycentricData5to6) +{ + UNIVARIATE_TESTS_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); +} + +TYPED_TEST(UnivariateTest, Multiplication) +{ + UNIVARIATE_TESTS_ALIASES + + auto barycentric = BarycentricData(); + Univariate f1 = barycentric.extend(Univariate{ { 1, 2 } }); + Univariate f2 = barycentric.extend(Univariate{ { 3, 4 } }); + // output should be {3, 8, 15} + Univariate expected_result{ { 3, 8, 15 } }; + Univariate f1f2 = f1 * f2; + EXPECT_EQ(f1f2, expected_result); +} + +TYPED_TEST(UnivariateTest, ConstructUnivariateViewFromUnivariate) +{ + UNIVARIATE_TESTS_ALIASES + + Univariate f{ { 1, 2, 3 } }; + UnivariateView g(f); + EXPECT_EQ(g.value_at(0), f.value_at(0)); + EXPECT_EQ(g.value_at(1), f.value_at(1)); +} + +TYPED_TEST(UnivariateTest, ConstructUnivariateFromUnivariateView) +{ + UNIVARIATE_TESTS_ALIASES + + Univariate f{ { 1, 2, 3 } }; + UnivariateView g(f); + Univariate h(g); + EXPECT_EQ(h.value_at(0), g.value_at(0)); + EXPECT_EQ(h.value_at(1), g.value_at(1)); +} + +TYPED_TEST(UnivariateTest, UnivariateViewAddition) +{ + UNIVARIATE_TESTS_ALIASES + + Univariate f1{ { 1, 2, 3 } }; + Univariate f2{ { 3, 4, 3 } }; + + UnivariateView g1(f1); + UnivariateView g2(f2); + + Univariate expected_result{ { 4, 6 } }; + Univariate result = g1 + g2; + EXPECT_EQ(result, expected_result); + + Univariate result2 = result + g1; + Univariate expected_result2{ { 5, 8 } }; + EXPECT_EQ(result2, expected_result2); +} +TYPED_TEST(UnivariateTest, UnivariateViewSubtraction) +{ + UNIVARIATE_TESTS_ALIASES + + Univariate f1{ { 1, 2, 3 } }; + Univariate f2{ { 3, 4, 3 } }; + + UnivariateView g1(f1); + UnivariateView g2(f2); + + Univariate expected_result{ { -2, -2 } }; + Univariate result = g1 - g2; + EXPECT_EQ(result, expected_result); + + Univariate result2 = result - g1; + Univariate expected_result2{ { -3, -4 } }; + EXPECT_EQ(result2, expected_result2); +} + +TYPED_TEST(UnivariateTest, UnivariateViewMultiplication) +{ + UNIVARIATE_TESTS_ALIASES + + Univariate f1{ { 1, 2, 3 } }; + Univariate f2{ { 3, 4, 3 } }; + + UnivariateView g1(f1); + UnivariateView g2(f2); + + Univariate expected_result{ { 3, 8 } }; + Univariate result = g1 * g2; + EXPECT_EQ(result, expected_result); + + Univariate result2 = result * g1; + Univariate expected_result2{ { 3, 16 } }; + EXPECT_EQ(result2, expected_result2); +} +} // namespace test_univariate diff --git a/barretenberg/cpp/src/aztec/honk/sumcheck/relations/arithmetic_relation.hpp b/barretenberg/cpp/src/aztec/honk/sumcheck/relations/arithmetic_relation.hpp new file mode 100644 index 000000000000..d2e14ef13579 --- /dev/null +++ b/barretenberg/cpp/src/aztec/honk/sumcheck/relations/arithmetic_relation.hpp @@ -0,0 +1,65 @@ +#include +#include + +#include "../../flavor/flavor.hpp" +#include "relation.hpp" +#include "../transcript.hpp" +#include "../polynomials/multivariates.hpp" +#include "../polynomials/barycentric_data.hpp" +#include "../polynomials/univariate.hpp" + +#pragma GCC diagnostic ignored "-Wunused-variable" +#pragma GCC diagnostic ignored "-Wunused-parameter" + +namespace honk::sumcheck { + +template class ArithmeticRelation : public Relation { + public: + // 1 + polynomial degree of this relation + static constexpr size_t RELATION_LENGTH = 4; + using MULTIVARIATE = StandardHonk::MULTIVARIATE; // could just get from StandardArithmetization + + // FUTURE OPTIMIZATION: successively extend as needed? + + // This relation takes no randomness, so it will not receive a ChallengeContainer. + ArithmeticRelation() = default; + explicit ArithmeticRelation(auto){}; // NOLINT(readability-named-parameter) + + // OPTIMIZATION?: Karatsuba in general, at least for some degrees? + // See https://hackmd.io/xGLuj6biSsCjzQnYN-pEiA?both + void add_edge_contribution(auto extended_edges, Univariate& evals) + { + auto w_l = UnivariateView(extended_edges[MULTIVARIATE::W_L]); + auto w_r = UnivariateView(extended_edges[MULTIVARIATE::W_R]); + auto w_o = UnivariateView(extended_edges[MULTIVARIATE::W_O]); + auto q_m = UnivariateView(extended_edges[MULTIVARIATE::Q_M]); + auto q_l = UnivariateView(extended_edges[MULTIVARIATE::Q_L]); + auto q_r = UnivariateView(extended_edges[MULTIVARIATE::Q_R]); + auto q_o = UnivariateView(extended_edges[MULTIVARIATE::Q_O]); + auto q_c = UnivariateView(extended_edges[MULTIVARIATE::Q_C]); + + evals += w_l * (q_m * w_r + q_l); + evals += q_r * w_r; + evals += q_o * w_o; + evals += q_c; + }; + + void add_full_relation_value_contribution(auto& purported_evaluations, FF& full_honk_relation_value) + { + + auto w_l = purported_evaluations[MULTIVARIATE::W_L]; + auto w_r = purported_evaluations[MULTIVARIATE::W_R]; + auto w_o = purported_evaluations[MULTIVARIATE::W_O]; + auto q_m = purported_evaluations[MULTIVARIATE::Q_M]; + auto q_l = purported_evaluations[MULTIVARIATE::Q_L]; + auto q_r = purported_evaluations[MULTIVARIATE::Q_R]; + auto q_o = purported_evaluations[MULTIVARIATE::Q_O]; + auto q_c = purported_evaluations[MULTIVARIATE::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; + }; +}; +} // namespace honk::sumcheck diff --git a/barretenberg/cpp/src/aztec/honk/sumcheck/sumcheck_types/grand_product_computation_constraint.hpp b/barretenberg/cpp/src/aztec/honk/sumcheck/relations/grand_product_computation_relation.hpp similarity index 61% rename from barretenberg/cpp/src/aztec/honk/sumcheck/sumcheck_types/grand_product_computation_constraint.hpp rename to barretenberg/cpp/src/aztec/honk/sumcheck/relations/grand_product_computation_relation.hpp index 8e1baa68984a..f570fa1deb86 100644 --- a/barretenberg/cpp/src/aztec/honk/sumcheck/sumcheck_types/grand_product_computation_constraint.hpp +++ b/barretenberg/cpp/src/aztec/honk/sumcheck/relations/grand_product_computation_relation.hpp @@ -1,60 +1,55 @@ -#include "./constraint.hpp" -#include "./multivariates.hpp" -#include "./univariate.hpp" -#include "./barycentric_data.hpp" -#include "./challenge_container.hpp" +#include "relation.hpp" +#include "../../flavor/flavor.hpp" +#include "../polynomials/multivariates.hpp" // TODO(Cody): don't need? +#include "../polynomials/univariate.hpp" +#include "../polynomials/barycentric_data.hpp" +#include "../challenge_container.hpp" #pragma GCC diagnostic ignored "-Wunused-variable" #pragma GCC diagnostic ignored "-Wunused-parameter" namespace honk::sumcheck { -template class GrandProductComputationConstraint : public Constraint { +template class GrandProductComputationRelation : public Relation { public: - static constexpr size_t CONSTRAINT_LENGTH = 5; // degree of this constraint + 1 - using Constraint::HONK_CONSTRAINT_LENGTH; - using Constraint::NUM_HONK_MULTIVARIATES; - BarycentricData barycentric = - BarycentricData(); - using UnivariateClass = Univariate; // TODO(cody): ugly name temporary for gcc - // using UnivariateView = UnivariateView; - - // using ChallengeContainer = ChallengeContainer, UnivariateClass>; + // 1 + polynomial degree of this relation + static constexpr size_t RELATION_LENGTH = 5; + using MULTIVARIATE = StandardHonk::MULTIVARIATE; public: - GrandProductComputationConstraint() = default; + const FF beta; + const FF gamma; + + explicit GrandProductComputationRelation(auto& challenge_container) + : beta(challenge_container.get_grand_product_beta_challenge()) + , gamma(challenge_container.get_grand_product_gamma_challenge()){}; /** - * @brief Add contribution of the permutation constraint for a given edge + * @brief Add contribution of the permutation relation for a given edge * - * @detail There are 2 constraints associated with enforcing the wire copy constraints - * This file handles the constraint that confirms faithful calculation of the grand - * product polynomial Z_perm. (Initialization constraint Z_perm(0) = 1 is handled elsewhere). + * @detail There are 2 relations associated with enforcing the wire copy relations + * This file handles the relation that confirms faithful calculation of the grand + * product polynomial Z_perm. (Initialization relation Z_perm(0) = 1 is handled elsewhere). * * z_perm(X)*P(X) - z_perm_shift(X)*Q(X), where * P(X) = Prod_{i=1:3} w_i(X) + β*(n*(i-1) + idx(X)) + γ * Q(X) = Prod_{i=1:3} w_i(X) + β*σ_i(X) + γ * */ - void add_edge_contribution(auto& edge_extensions, - UnivariateClass& evals, - ChallengeContainer, UnivariateClass> challenge_container) + void add_edge_contribution(auto& extended_edges, Univariate& evals) { - Fr beta = challenge_container.get_challenge_equals_one(); // Fr(1) - Fr gamma = challenge_container.get_challenge_equals_one(); // Fr(1) - - auto w_1 = UnivariateView(edge_extensions[MULTIVARIATE::W_L]); - auto w_2 = UnivariateView(edge_extensions[MULTIVARIATE::W_R]); - auto w_3 = UnivariateView(edge_extensions[MULTIVARIATE::W_O]); - auto sigma_1 = UnivariateView(edge_extensions[MULTIVARIATE::SIGMA_1]); - auto sigma_2 = UnivariateView(edge_extensions[MULTIVARIATE::SIGMA_2]); - auto sigma_3 = UnivariateView(edge_extensions[MULTIVARIATE::SIGMA_3]); - auto id_1 = UnivariateView(edge_extensions[MULTIVARIATE::ID_1]); - auto id_2 = UnivariateView(edge_extensions[MULTIVARIATE::ID_1]); - auto id_3 = UnivariateView(edge_extensions[MULTIVARIATE::ID_1]); - auto z_perm = UnivariateView(edge_extensions[MULTIVARIATE::Z_PERM]); - auto z_perm_shift = UnivariateView(edge_extensions[MULTIVARIATE::Z_PERM_SHIFT]); - // auto lagrange_1 = UnivariateView(edge_extensions[MULTIVARIATE::LAGRANGE_1]); + auto w_1 = UnivariateView(extended_edges[MULTIVARIATE::W_L]); + auto w_2 = UnivariateView(extended_edges[MULTIVARIATE::W_R]); + auto w_3 = UnivariateView(extended_edges[MULTIVARIATE::W_O]); + auto sigma_1 = UnivariateView(extended_edges[MULTIVARIATE::SIGMA_1]); + auto sigma_2 = UnivariateView(extended_edges[MULTIVARIATE::SIGMA_2]); + auto sigma_3 = UnivariateView(extended_edges[MULTIVARIATE::SIGMA_3]); + auto id_1 = UnivariateView(extended_edges[MULTIVARIATE::ID_1]); + auto id_2 = UnivariateView(extended_edges[MULTIVARIATE::ID_1]); + auto id_3 = UnivariateView(extended_edges[MULTIVARIATE::ID_1]); + auto z_perm = UnivariateView(extended_edges[MULTIVARIATE::Z_PERM]); + auto z_perm_shift = UnivariateView(extended_edges[MULTIVARIATE::Z_PERM_SHIFT]); + // auto lagrange_1 = UnivariateView(extended_edges[MULTIVARIATE::LAGRANGE_1]); // Contribution (1) evals += z_perm; @@ -65,11 +60,10 @@ template class GrandProductComputationConstraint : public Constrai (w_3 + sigma_3 * beta + gamma); }; - void add_full_constraint_value_contribution(std::array purported_evaluations, - Fr& full_honk_constraint_value) + void add_full_relation_value_contribution(auto& purported_evaluations, FF& full_honk_relation_value) { - Fr beta = 1; // to be obtained from transcript - Fr gamma = 1; + FF beta = 1; // to be obtained from transcript + FF gamma = 1; auto w_1 = purported_evaluations[MULTIVARIATE::W_L]; auto w_2 = purported_evaluations[MULTIVARIATE::W_R]; @@ -82,15 +76,15 @@ template class GrandProductComputationConstraint : public Constrai auto id_3 = purported_evaluations[MULTIVARIATE::ID_1]; auto z_perm = purported_evaluations[MULTIVARIATE::Z_PERM]; auto z_perm_shift = purported_evaluations[MULTIVARIATE::Z_PERM_SHIFT]; - auto lagrange_1 = purported_evaluations[MULTIVARIATE::LAGRANGE_1]; + // auto lagrange_1 = purported_evaluations[MULTIVARIATE::LAGRANGE_1]; // Contribution (1) - full_honk_constraint_value += z_perm; - full_honk_constraint_value *= w_1 + beta * id_1 + gamma; - full_honk_constraint_value *= w_2 + beta * id_2 + gamma; - full_honk_constraint_value *= w_3 + beta * id_3 + gamma; - full_honk_constraint_value -= z_perm_shift * (w_1 + beta * sigma_1 + gamma) * (w_2 + beta * sigma_2 + gamma) * - (w_3 + beta * sigma_3 + gamma); + full_honk_relation_value += z_perm; + full_honk_relation_value *= w_1 + beta * id_1 + gamma; + full_honk_relation_value *= w_2 + beta * id_2 + gamma; + full_honk_relation_value *= w_3 + beta * id_3 + gamma; + full_honk_relation_value -= z_perm_shift * (w_1 + beta * sigma_1 + gamma) * (w_2 + beta * sigma_2 + gamma) * + (w_3 + beta * sigma_3 + gamma); }; /* ********* ********* ********* ********* ********* ********* ********* ********* ********* ********* */ @@ -129,16 +123,17 @@ template class GrandProductComputationConstraint : public Constrai size_t key_n = 100; // temp placeholder to get things building // Allocate scratch space for accumulators - Fr* numererator_accum[program_width]; - Fr* denominator_accum[program_width]; + FF* numererator_accum[program_width]; + FF* denominator_accum[program_width]; for (size_t i = 0; i < program_width; ++i) { - numererator_accum[i] = static_cast(aligned_alloc(64, sizeof(Fr) * key_n)); - denominator_accum[i] = static_cast(aligned_alloc(64, sizeof(Fr) * key_n)); + // TODO(Cody): clang-tidy is not happy with these lines. + numererator_accum[i] = static_cast(aligned_alloc(64, sizeof(FF) * key_n)); + denominator_accum[i] = static_cast(aligned_alloc(64, sizeof(FF) * key_n)); } // Popoulate wire and permutation polynomials - std::array wires; - std::array sigmas; + std::array wires; + std::array sigmas; for (size_t i = 0; i < program_width; ++i) { std::string wire_id = "w_" + std::to_string(i + 1) + "_lagrange"; std::string sigma_id = "sigma_" + std::to_string(i + 1) + "_lagrange"; @@ -147,14 +142,14 @@ template class GrandProductComputationConstraint : public Constrai } // Get random challenges (to be obtained from transcript) - Fr beta = Fr::random_element(); - Fr gamma = Fr::random_element(); + FF beta = FF::random_element(); + FF gamma = FF::random_element(); // Step (1) for (size_t i = 0; i < key_n; ++i) { for (size_t k = 0; k < program_width; ++k) { // TODO(luke): maybe this idx is replaced by proper ID polys in the future - Fr idx = k * key_n + i; + FF idx = k * key_n + i; numererator_accum[k][i] = wires[k][i] + (idx * beta) + gamma; // w_k(i) + β.(k*n+i) + γ denominator_accum[k][i] = wires[k][i] + (sigmas[k][i] * beta) + gamma; // w_k(i) + β.σ_k(i) + γ } @@ -178,8 +173,8 @@ template class GrandProductComputationConstraint : public Constrai // Step (4) // Use Montgomery batch inversion to compute z_perm[i+1] = numererator_accum[0][i] / denominator_accum[0][i] - Fr* inversion_coefficients = &denominator_accum[1][0]; // arbitrary scratch space - Fr inversion_accumulator = Fr::one(); + FF* inversion_coefficients = &denominator_accum[1][0]; // arbitrary scratch space + FF inversion_accumulator = FF::one(); for (size_t i = 0; i < key_n; ++i) { inversion_coefficients[i] = numererator_accum[0][i] * inversion_accumulator; inversion_accumulator *= denominator_accum[0][i]; @@ -196,7 +191,7 @@ template class GrandProductComputationConstraint : public Constrai // Construct permutation polynomial 'z_perm' in lagrange form as: // z_perm = [1 numererator_accum[0][0] numererator_accum[0][1] ... numererator_accum[0][n-2]] // polynomial z_perm(key_n, key_n); - // z_perm[0] = Fr::one(); + // z_perm[0] = FF::one(); // barretenberg::polynomial_arithmetic::copy_polynomial(numererator_accum[0], &z_perm[1], key_n - 1, key_n - // 1); diff --git a/barretenberg/cpp/src/aztec/honk/sumcheck/relations/grand_product_initialization_relation.hpp b/barretenberg/cpp/src/aztec/honk/sumcheck/relations/grand_product_initialization_relation.hpp new file mode 100644 index 000000000000..96481b9ee0e0 --- /dev/null +++ b/barretenberg/cpp/src/aztec/honk/sumcheck/relations/grand_product_initialization_relation.hpp @@ -0,0 +1,47 @@ +#include "relation.hpp" +#include "../../flavor/flavor.hpp" +#include "../polynomials/multivariates.hpp" +#include "../polynomials/univariate.hpp" +#include "../polynomials/barycentric_data.hpp" + +#pragma GCC diagnostic ignored "-Wunused-variable" +#pragma GCC diagnostic ignored "-Wunused-parameter" + +namespace honk::sumcheck { + +template class GrandProductInitializationRelation : public Relation { + public: + // 1 + polynomial degree of this relation + static constexpr size_t RELATION_LENGTH = 3; + using MULTIVARIATE = StandardHonk::MULTIVARIATE; // could just get from StandardArithmetization + + GrandProductInitializationRelation() = default; + explicit GrandProductInitializationRelation(auto){}; // NOLINT(readability-named-parameter) + + /** + * @brief Add contribution of the permutation relation for a given edge + * + * @detail There are 2 relations associated with enforcing the wire copy relations + * This file handles the relation Z_perm(0) = 1 via the relation: + * + * C(X) = L_1(X)(z_perm(X) - 1) + */ + void add_edge_contribution(auto& extended_edges, Univariate& evals) + { + auto z_perm = UnivariateView(extended_edges[MULTIVARIATE::Z_PERM]); + auto lagrange_1 = UnivariateView(extended_edges[MULTIVARIATE::LAGRANGE_1]); + auto one = FF(1); + + evals += lagrange_1 * (z_perm - one); + }; + + void add_full_relation_value_contribution(auto& purported_evaluations, FF& full_honk_relation_value) + { + auto z_perm = purported_evaluations[MULTIVARIATE::Z_PERM]; + auto lagrange_1 = purported_evaluations[MULTIVARIATE::LAGRANGE_1]; + auto one = FF(1); + + full_honk_relation_value += lagrange_1 * (z_perm - one); + }; +}; +} // namespace honk::sumcheck diff --git a/barretenberg/cpp/src/aztec/honk/sumcheck/relations/relation.hpp b/barretenberg/cpp/src/aztec/honk/sumcheck/relations/relation.hpp new file mode 100644 index 000000000000..9b6ca9df2de6 --- /dev/null +++ b/barretenberg/cpp/src/aztec/honk/sumcheck/relations/relation.hpp @@ -0,0 +1,9 @@ +#pragma once +// #include "../../flavor/flavor.hpp" +// #include "../polynomials/multivariates.hpp" + +namespace honk::sumcheck { + +template class Relation {}; // TODO(Cody): Use or eventually remove. + +} // namespace honk::sumcheck diff --git a/barretenberg/cpp/src/aztec/honk/sumcheck/relations/relation.test.cpp b/barretenberg/cpp/src/aztec/honk/sumcheck/relations/relation.test.cpp new file mode 100644 index 000000000000..d8003cc9fa3c --- /dev/null +++ b/barretenberg/cpp/src/aztec/honk/sumcheck/relations/relation.test.cpp @@ -0,0 +1,174 @@ +#include "relation.hpp" +#include "../../flavor/flavor.hpp" +#include "arithmetic_relation.hpp" +#include "grand_product_initialization_relation.hpp" +#include "grand_product_computation_relation.hpp" +#include "../polynomials/multivariates.hpp" +#include "../polynomials/univariate.hpp" +#include "../challenge_container.hpp" +#include "../transcript.hpp" +#include "../polynomials/barycentric_data.hpp" + +#include +#include + +#include + +#pragma GCC diagnostic ignored "-Wunused-variable" +#pragma GCC diagnostic ignored "-Wunused-parameter" + +using namespace honk::sumcheck; + +namespace honk_relation_tests { + +template class MockTranscript : public honk::Transcript { + public: + Fr get_challenge() { return mock_challenge; }; + Fr mock_challenge = -1; +}; + +template class SumcheckRelation : public testing::Test { + public: + template using Univariate = Univariate; + template using UnivariateView = UnivariateView; + + // TODO(luke): may want to make this more flexible/genericzs + static std::array, StandardArithmetization::NUM_POLYNOMIALS> compute_mock_extended_edges() + { + // TODO(Cody): build from Univariate<2>'s? + auto w_l = Univariate<5>({ 1, 2, 3, 4, 5 }); + auto w_r = Univariate<5>({ 1, 2, 3, 4, 5 }); + auto w_o = Univariate<5>({ 1, 2, 3, 4, 5 }); + auto z_perm = Univariate<5>({ 1, 2, 3, 4, 5 }); + // Note: z_perm and z_perm_shift can be any linear poly for the sake of the tests but should not be be equal to + // each other In order to avoid a trivial computation in the case of the grand_product_computation_relation. + // Values here were chosen so that output univariates in tests are small positive numbers. + auto z_perm_shift = Univariate<5>({ 0, 1, 2, 3, 4 }); // this is not real shifted data + auto q_m = Univariate<5>({ 1, 2, 3, 4, 5 }); + auto q_l = Univariate<5>({ 1, 2, 3, 4, 5 }); + auto q_r = Univariate<5>({ 1, 2, 3, 4, 5 }); + auto q_o = Univariate<5>({ 1, 2, 3, 4, 5 }); + auto q_c = Univariate<5>({ 1, 2, 3, 4, 5 }); + auto sigma_1 = Univariate<5>({ 1, 2, 3, 4, 5 }); + auto sigma_2 = Univariate<5>({ 1, 2, 3, 4, 5 }); + auto sigma_3 = Univariate<5>({ 1, 2, 3, 4, 5 }); + auto id_1 = Univariate<5>({ 1, 2, 3, 4, 5 }); + auto id_2 = Univariate<5>({ 1, 2, 3, 4, 5 }); + auto id_3 = Univariate<5>({ 1, 2, 3, 4, 5 }); + auto lagrange_1 = Univariate<5>({ 1, 2, 3, 4, 5 }); + + std::array, StandardArithmetization::NUM_POLYNOMIALS> extended_edges = { + w_l, w_r, w_o, z_perm, z_perm_shift, q_m, q_l, q_r, q_o, + q_c, sigma_1, sigma_2, sigma_3, id_1, id_2, id_3, lagrange_1 + }; + return extended_edges; + } +}; + +using FieldTypes = testing::Types; +TYPED_TEST_SUITE(SumcheckRelation, FieldTypes); + +#define SUMCHECK_RELATION_TYPE_ALIASES using FF = TypeParam; + +TYPED_TEST(SumcheckRelation, ArithmeticRelation) +{ + SUMCHECK_RELATION_TYPE_ALIASES + + auto extended_edges = TestFixture::compute_mock_extended_edges(); + + auto relation = ArithmeticRelation(); + using MULTIVARIATE = StandardArithmetization::POLYNOMIAL; + + // Manually compute the expected edge contribution + auto w_l = UnivariateView(extended_edges[MULTIVARIATE::W_L]); + auto w_r = UnivariateView(extended_edges[MULTIVARIATE::W_R]); + auto w_o = UnivariateView(extended_edges[MULTIVARIATE::W_O]); + auto q_m = UnivariateView(extended_edges[MULTIVARIATE::Q_M]); + auto q_l = UnivariateView(extended_edges[MULTIVARIATE::Q_L]); + auto q_r = UnivariateView(extended_edges[MULTIVARIATE::Q_R]); + auto q_o = UnivariateView(extended_edges[MULTIVARIATE::Q_O]); + auto q_c = UnivariateView(extended_edges[MULTIVARIATE::Q_C]); + // expected_evals, length 4, extends to { { 5, 22, 57, 116, 205} }; + Univariate expected_evals = (q_m * w_r * w_l) + (q_r * w_r) + (q_l * w_l) + (q_o * w_o) + (q_c); + + auto evals = Univariate(); + relation.add_edge_contribution(extended_edges, evals); + + EXPECT_EQ(evals, expected_evals); +}; + +TYPED_TEST(SumcheckRelation, GrandProductComputationRelation) +{ + SUMCHECK_RELATION_TYPE_ALIASES + + using ChallengeContainer = ChallengeContainer, Univariate>; + + // TODO(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 + + auto extended_edges = TestFixture::compute_mock_extended_edges(); + auto transcript = honk::Transcript(); + auto challenges = ChallengeContainer(transcript); + auto relation = GrandProductComputationRelation(challenges); + using UnivariateView = UnivariateView; + using Univariate = Univariate; + + // Manually compute the expected edge contribution + using MULTIVARIATE = StandardArithmetization::POLYNOMIAL; + + auto w_1 = UnivariateView(extended_edges[MULTIVARIATE::W_L]); + auto w_2 = UnivariateView(extended_edges[MULTIVARIATE::W_R]); + auto w_3 = UnivariateView(extended_edges[MULTIVARIATE::W_O]); + auto sigma_1 = UnivariateView(extended_edges[MULTIVARIATE::SIGMA_1]); + auto sigma_2 = UnivariateView(extended_edges[MULTIVARIATE::SIGMA_2]); + auto sigma_3 = UnivariateView(extended_edges[MULTIVARIATE::SIGMA_3]); + auto id_1 = UnivariateView(extended_edges[MULTIVARIATE::ID_1]); + auto id_2 = UnivariateView(extended_edges[MULTIVARIATE::ID_1]); + auto id_3 = UnivariateView(extended_edges[MULTIVARIATE::ID_1]); + auto z_perm = UnivariateView(extended_edges[MULTIVARIATE::Z_PERM]); + auto z_perm_shift = UnivariateView(extended_edges[MULTIVARIATE::Z_PERM_SHIFT]); + // auto lagrange_1 = UnivariateView(extended_edges[MULTIVARIATE::LAGRANGE_1]); + // TODO(luke): use real transcript/challenges + FF beta = challenges.get_challenge_equals_one(); + FF gamma = challenges.get_challenge_equals_one(); + + auto expected_evals = Univariate(); + // expected_evals is { { 27, 125, 343, 729, 1331 } } + expected_evals += z_perm * (w_1 + id_1 * beta + gamma) * (w_2 + id_2 * beta + gamma) * (w_3 + id_3 * beta + gamma); + expected_evals -= + z_perm_shift * (w_1 + sigma_1 * beta + gamma) * (w_2 + sigma_2 * beta + gamma) * (w_3 + sigma_3 * beta + gamma); + + auto evals = Univariate(); + relation.add_edge_contribution(extended_edges, evals); + + EXPECT_EQ(evals, expected_evals); +}; + +TYPED_TEST(SumcheckRelation, GrandProductInitializationRelation) +{ + SUMCHECK_RELATION_TYPE_ALIASES + + auto extended_edges = TestFixture::compute_mock_extended_edges(); + auto relation = GrandProductInitializationRelation(); + using UnivariateView = UnivariateView; + using Univariate = Univariate; + + // Manually compute the expected edge contribution + using MULTIVARIATE = StandardArithmetization::POLYNOMIAL; + + auto z_perm = UnivariateView(extended_edges[MULTIVARIATE::Z_PERM]); + auto lagrange_1 = UnivariateView(extended_edges[MULTIVARIATE::LAGRANGE_1]); + // expectede_evals, lenght 3, extends to { { 0, 2, 6, 12, 20 } } + auto expected_evals = lagrange_1 * (z_perm - FF(1)); + + // Compute the edge contribution using add_edge_contribution + auto evals = Univariate(); + relation.add_edge_contribution(extended_edges, evals); + + EXPECT_EQ(evals, expected_evals); +}; + +} // namespace honk_relation_tests diff --git a/barretenberg/cpp/src/aztec/honk/sumcheck/sumcheck.hpp b/barretenberg/cpp/src/aztec/honk/sumcheck/sumcheck.hpp index 74040b326e87..01261d4aec06 100644 --- a/barretenberg/cpp/src/aztec/honk/sumcheck/sumcheck.hpp +++ b/barretenberg/cpp/src/aztec/honk/sumcheck/sumcheck.hpp @@ -1,35 +1,89 @@ -#include "./sumcheck_round.hpp" -#include -#include -#include - -namespace honk { -namespace sumcheck { -template class... ConstraintPack> class Sumcheck { - using Fr = typename SumcheckTypes::Fr; - using Univariate = typename SumcheckTypes::Univariate; - using EdgeGroup = typename SumcheckTypes::EdgeGroup; - using HonkPolys = typename SumcheckTypes::HonkPolys; - using ChallengeContainer = typename SumcheckTypes::ChallengeContainer; - using Transcript = Transcript; +#include "sumcheck_round.hpp" +#include "polynomials/univariate.hpp" +#include "../flavor/flavor.hpp" +#include +namespace honk::sumcheck { +template class... Relations> class Sumcheck { + using FF = typename Multivariates::FF; public: - static constexpr size_t NUM_CONSTRAINTS = sizeof...(ConstraintPack); + Multivariates multivariates; + static constexpr size_t multivariate_d = Multivariates::multivariate_d; // number of variables + static constexpr size_t multivariate_n = Multivariates::multivariate_n; // 2^d - HonkPolys polynomials; - SumcheckRound round; - size_t multivariate_d; // aka num_vars - size_t multivariate_n; - Transcript transcript; - ChallengeContainer challenges; // construct with round size, claimed sum + std::array purported_evaluations; + ChallengeContainer challenges; + SumcheckRound round; - Sumcheck(HonkPolys polynomials) - : polynomials(polynomials) + // prover instantiates sumcheck with multivariates + Sumcheck(Multivariates multivariates, ChallengeContainer challenges) + : multivariates(multivariates) + , challenges(challenges) + , round(Multivariates::num, std::tuple(Relations(challenges)...)){}; + + // verifier instantiates with challenges alone + explicit Sumcheck(ChallengeContainer challenges) + : challenges(challenges) + , round(Multivariates::num, std::tuple(Relations(challenges)...)){}; + + /** + * @brief Compute univariate restriction place in transcript, generate challenge, fold,... repeat until final round, + * then compute multivariate evaluations and place in transcript. + * + * @details + */ + void execute_prover() + { + std::array round_challenges; + std::fill(round_challenges.begin(), round_challenges.end(), 0); + + // First round + // This populates multivariates.folded_polynomials. + FF relation_separator_challenge = challenges.get_relation_separator_challenge(); + challenges.transcript.add( + round.compute_univariate(multivariates.full_polynomials, relation_separator_challenge)); + // IMPROVEMENT(Cody): Could move building of this list into challenge container? + round_challenges[0] = challenges.get_sumcheck_round_challenge(0); + multivariates.fold(multivariates.full_polynomials, multivariate_n, round_challenges[0]); + + // All but final round + // We operate on multivariates.full_polynomials in place. + for (size_t round_idx = 1; round_idx < multivariate_d; round_idx++) { + challenges.transcript.add( + round.compute_univariate(multivariates.folded_polynomials, relation_separator_challenge)); + round_challenges[round_idx] = challenges.get_sumcheck_round_challenge(round_idx); + multivariates.fold(multivariates.folded_polynomials, multivariate_n, round_challenges[round_idx]); + } + + // Final round + challenges.transcript.add(multivariates.batch_evaluate(round_challenges)); + }; + + /** + * @brief Extract round univariate, check sum, generate challenge, compute next target sum..., repeat until final + * round, then use purported evaluations to generate purported full Honk relation value and check against final + * target sum. + */ + bool execute_verifier() { - multivariate_d = polynomials.multivariate_d; - multivariate_n = 1 << multivariate_d; - // TODO: construct round, etc. + bool verified(true); + + // All but final round. + // target_total_sum is initialized to zero then mutated in place. + for (size_t round_idx = 0; round_idx < multivariate_d; round_idx++) { + auto round_univariate = challenges.get_sumcheck_round_univariate(round_idx); + verified = verified && round.check_sum(round_univariate); + FF round_challenge = challenges.get_sumcheck_round_challenge(round_idx); + round.compute_next_target_sum(round_univariate, round_challenge); + } + + // Final round + std::vector purported_evaluations = challenges.get_sumcheck_purported_evaluations(); + FF relation_separator_challenge = challenges.get_relation_separator_challenge(); + FF full_honk_relation_purported_value = + round.compute_full_honk_relation_purported_value(purported_evaluations, relation_separator_challenge); + verified = verified && (full_honk_relation_purported_value == round.target_total_sum); + return verified; }; }; -} // namespace sumcheck -} // namespace honk +} // namespace honk::sumcheck diff --git a/barretenberg/cpp/src/aztec/honk/sumcheck/sumcheck.test.cpp b/barretenberg/cpp/src/aztec/honk/sumcheck/sumcheck.test.cpp new file mode 100644 index 000000000000..78cbcc84d1fa --- /dev/null +++ b/barretenberg/cpp/src/aztec/honk/sumcheck/sumcheck.test.cpp @@ -0,0 +1,101 @@ +#include "sumcheck.hpp" +#include "transcript.hpp" +#include "polynomials/multivariates.hpp" +#include "relations/arithmetic_relation.hpp" +#include "relations/grand_product_computation_relation.hpp" +#include "relations/grand_product_initialization_relation.hpp" +#include "challenge_container.hpp" +#include +#include + +#include +#include + +#pragma GCC diagnostic ignored "-Wunused-variable" +#pragma GCC diagnostic ignored "-Wunused-parameter" + +using namespace honk; +using namespace honk::sumcheck; + +template class MockTranscript : public Transcript { + public: + FF get_challenge() { return mock_challenge; }; + FF mock_challenge = -1; +}; + +namespace test_sumcheck_round { + +TEST(Sumcheck, Prover) +{ + const size_t num_polys(StandardArithmetization::NUM_POLYNOMIALS); + const size_t multivariate_d(1); + const size_t multivariate_n(1 << multivariate_d); + const size_t max_relation_length = 4; + + using FF = barretenberg::fr; + using Multivariates = ::Multivariates; + using ChallengeContainer = ::ChallengeContainer, Univariate>; + + std::array w_l = { 1, 2 }; + std::array w_r = { 1, 2 }; + std::array w_o = { 1, 2 }; + std::array z_perm = { 1, 2 }; + std::array z_perm_shift = { 0, 1 }; + std::array q_m = { 1, 2 }; + std::array q_l = { 1, 2 }; + std::array q_r = { 1, 2 }; + std::array q_o = { 1, 2 }; + std::array q_c = { 1, 2 }; + std::array sigma_1 = { 1, 2 }; + std::array sigma_2 = { 1, 2 }; + std::array sigma_3 = { 1, 2 }; + std::array id_1 = { 1, 2 }; + std::array id_2 = { 1, 2 }; + std::array id_3 = { 1, 2 }; + std::array lagrange_1 = { 1, 2 }; + + // These will be owned outside the class, probably by the composer. + std::array, Multivariates::num> full_polynomials = { + w_l, w_r, w_o, z_perm, z_perm_shift, q_m, q_l, q_r, q_o, + q_c, sigma_1, sigma_2, sigma_3, id_1, id_2, id_3, lagrange_1 + }; + auto transcript = MockTranscript(); + auto challenges = ChallengeContainer(transcript); + + auto multivariates = Multivariates(full_polynomials); + + auto sumcheck = Sumcheck(multivariates, challenges); + + sumcheck.execute_prover(); + // TODO(Cody) This does not constitute a test. +} + +TEST(Sumcheck, Verifier) +{ + const size_t num_polys(StandardArithmetization::NUM_POLYNOMIALS); + const size_t multivariate_d(1); + const size_t multivariate_n(1 << multivariate_d); + const size_t max_relation_length = 5; + + using FF = barretenberg::fr; + using Multivariates = ::Multivariates; + using ChallengeContainer = ::ChallengeContainer, Univariate>; + + auto transcript = MockTranscript(); + auto challenges = ChallengeContainer(transcript); + + auto sumcheck = Sumcheck(challenges); + + sumcheck.execute_verifier(); + // TODO(Cody) This does not constitute a test. +} + +} // namespace test_sumcheck_round diff --git a/barretenberg/cpp/src/aztec/honk/sumcheck/sumcheck_round.hpp b/barretenberg/cpp/src/aztec/honk/sumcheck/sumcheck_round.hpp index 157b040ce81f..1e938b57ab90 100644 --- a/barretenberg/cpp/src/aztec/honk/sumcheck/sumcheck_round.hpp +++ b/barretenberg/cpp/src/aztec/honk/sumcheck/sumcheck_round.hpp @@ -1,13 +1,10 @@ #include -#include #include -#include +#include #include -#include "./sumcheck_types/univariate.hpp" -#include "./sumcheck_types/constraint_manager.hpp" -#include "./sumcheck_types/barycentric_data.hpp" -namespace honk { -namespace sumcheck { +#include "polynomials/barycentric_data.hpp" +#include "polynomials/univariate.hpp" +namespace honk::sumcheck { /* Notation: The polynomial P(X1, X2) that is the low-degree extension of its values vij = P(i,j) @@ -25,293 +22,230 @@ namespace sumcheck { 3 -------- 7 4 -------- 8 | | | | Let F(X1, X2) = G(Y1, Y2) = G0(Y1(X1, X2) + Y2(X1, X2)) | Y1 | | Y2 | + α G1(Y1(X1, X2) + Y2(X1, X2)), - | | | | where the constraints are G0(Y1, Y2) = Y1 * Y2 - 1 -------- 5 2 -------- 6 and G1(Y1, Y2) = Y1 + Y2. - - G itself is represented by a SumcheckRound class. - G1, G2 together comprise the ConstraintPack. - The polynomials Y1, Y2 are stored as two edge groups: - 3 4 7 8 -one containing | and | and another containing | and | . - 1 2 5 6 -The rationale here is that both folding and evaluation will proceed one edge group at a time. + | | | | where the relations are G0(Y1, Y2) = Y1 * Y2 + 1 -------- 5 2 -------- 6 and G1(Y1, Y2) = Y1 + Y2. + + G1, G2 together comprise the Relations. + + In the first round, the computations will relate elements along veritcal lines. As a mnemonic, we + use the term "edge" for the linear, univariate polynomials corresponding to the four lines + 3 4 7 8 + | , | , | , | . + 1 2 5 6 + + The polynomials Y1, Y2 are stored in an array in Multivariates. In the first round, these are arrays + of spans living outside of the Multivariates object, and in sebsequent rounts these are arrays of field + elements that are stored in the Multivariates. The rationale for adopting this model is to + avoid copying the full-length polynomials; this way, the largest polynomial array stores in a + Multivariates class is multivariates_n/2. */ -template class... ConstraintPack> class SumcheckRound { - using Fr = typename SumcheckTypes::Fr; - using Multivariates = typename SumcheckTypes::Multivariates; - using ChallengeContainer = typename SumcheckTypes::ChallengeContainer; +template class... Relations> class SumcheckRound { public: - size_t round_size; - bool failed = false; - Fr target_total_sum; - Multivariates multivariates; - std::array purported_evaluations; - ConstraintManager...> constraint_manager; // TODO(cody); move more evals, maybe more, into here - ChallengeContainer challenges; - static constexpr size_t SUMCHECK_CONSTRAINT_DEGREE_PLUS_ONE = - 5; // TODO(luke): This value is independently defined in multiple locations - BarycentricData barycentric = - BarycentricData(); - std::array, Multivariates::num> edge_extensions; - std::array, Multivariates::num> extended_univariates; - static constexpr size_t NUM_CONSTRAINTS = sizeof...(ConstraintPack); + bool round_failed = false; + size_t round_size; // a power of 2 + + std::tuple...> relations; + static constexpr size_t NUM_RELATIONS = sizeof...(Relations); + static constexpr size_t MAX_RELATION_LENGTH = std::max({ Relations::RELATION_LENGTH... }); + + FF target_total_sum = 0; + + // TODO(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 evaluations; + std::array, num_multivariates> extended_edges; + std::array, num_multivariates> extended_univariates; + + // TODO(Cody): this should go away and we should use constexpr method to extend + BarycentricData barycentric_2_to_max = BarycentricData(); + + // Prover constructor + SumcheckRound(size_t initial_round_size, auto relations) // TOPO: want auto&& relations + : round_size(initial_round_size) + , relations(relations) + , barycentric_utils(BarycentricData::RELATION_LENGTH, MAX_RELATION_LENGTH>()...) + , univariate_accumulators(Univariate::RELATION_LENGTH>()...) + {} - SumcheckRound(Multivariates multivariates, ChallengeContainer challenges) - : multivariates(multivariates) - , challenges(challenges) + // Verifier constructor + explicit SumcheckRound(auto relations) + : relations(relations) + // TODO(Cody): this is a hack; accumulators not needed by verifier + , univariate_accumulators(Univariate::RELATION_LENGTH>()...) { - // TODO: test edge case - // Here (and everywhere?) multivariate_n is assumed to be a power of 2 - // will be halved after each round - round_size = multivariates.multivariate_n; - } + // 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(evaluations.begin(), evaluations.end(), 0); + }; - SumcheckRound(std::array purported_evaluations, ChallengeContainer challenges) - : purported_evaluations(purported_evaluations) - , challenges(challenges) - {} + // 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_CONSTRAINTS-1}) and a challenge α, - * modify the tuple in place to (t_0, αt_1, ..., α^{NUM_CONSTRAINTS-1}t_{NUM_CONSTRAINTS-1}). + * @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, Fr challenge, Fr running_challenge) + template void scale_tuple(auto& tuple, FF challenge, FF running_challenge) { std::get(tuple) *= running_challenge; running_challenge *= challenge; - if constexpr (idx + 1 < NUM_CONSTRAINTS) { + if constexpr (idx + 1 < NUM_RELATIONS) { scale_tuple(tuple, challenge, running_challenge); } }; /** - * @brief Given a tuple t = (t_0, t_1, ..., t_{NUM_CONSTRAINTS-1}) and a challenge α, - * return t_0 + αt_1 + ... + α^{NUM_CONSTRAINTS-1}t_{NUM_CONSTRAINTS-1}). + * @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. */ - template T batch_over_constraints(auto& tuple, Fr challenge) + template T batch_over_relations(auto& tuple, FF challenge) { - Fr running_challenge = 1; + FF running_challenge = 1; scale_tuple<>(tuple, challenge, running_challenge); extend_univariate_accumulators<>(); auto result = T(); - // T result = std::apply([&](auto... v) { return (v + ...); }, tuple); - for (size_t i = 0; i < NUM_CONSTRAINTS; ++i) { + for (size_t i = 0; i < NUM_RELATIONS; ++i) { result += extended_univariates[i]; } return result; } /** - * @brief Evaluate some constraints by evaluating each edge in the edge group at + * @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 constraint_evals. + * entry of relation_evals. * - * @details Should only be called externally with constraint_idx equal to 0. + * @details Should only be called externally with relation_idx equal to 0. * */ - void extend_edges(std::array polynomial, size_t edge_idx) - { - for (size_t idx = 0; idx < Multivariates::num; idx++) { - auto edge = Univariate({ polynomial[idx][edge_idx], polynomial[idx][edge_idx + 1] }); - edge_extensions[idx] = barycentric.extend(edge); - } - } - - // TODO(cody): make private - template void accumulate_constraint_univariates() + template void extend_edges(T multivariate, size_t edge_idx) { - std::get(constraint_manager.constraints) - .add_edge_contribution(edge_extensions, - std::get(constraint_manager.univariate_accumulators)); - - // Repeat for the next constraint. - if constexpr (constraint_idx + 1 < NUM_CONSTRAINTS) { - accumulate_constraint_univariates(); + for (size_t idx = 0; idx < num_multivariates; idx++) { + auto edge = Univariate({ multivariate[idx][edge_idx], multivariate[idx][edge_idx + 1] }); + extended_edges[idx] = barycentric_2_to_max.extend(edge); } } - // TODO(cody): make private - // TODO(cody): make uniform with univariates - template - void accumulate_constraint_evaluations(std::array& constraint_evaluations) + // TODO(Cody): make private + /** + * @brief For a given edge, calculate the contribution of each relation to the prover round univariate (S_l in the + * thesis). + * + * @details In Round l, the univariate S_l computed by the prover is computed as follows: + * - Outer loop: iterate through the points on the boolean hypercube of dimension = log(round_size), skipping + * every other point. On each iteration, create a Univariate (an 'edge') for each + * multivariate. + * - Inner loop: iterate throught the relations, feeding each relation the present collection of edges. Each + * relation adds a contribution + * + * Result: for each relation, a univariate of some degree is computed by accumulating the contributions of each + * group of edges. These are stored in `univariate_accumulators`. Adding these univariates together, with + * appropriate scaling factors, produces S_l. + */ + template void accumulate_relation_univariates() { - std::get(constraint_manager.constraints) - .add_full_constraint_value_contribution(purported_evaluations, constraint_evaluations[constraint_idx]); + std::get(relations).add_edge_contribution(extended_edges, + std::get(univariate_accumulators)); - // Repeat for the next constraint. - if constexpr (constraint_idx + 1 < NUM_CONSTRAINTS) { - accumulate_constraint_evaluations(constraint_evaluations); + // Repeat for the next relation. + if constexpr (relation_idx + 1 < NUM_RELATIONS) { + accumulate_relation_univariates(); } } + // TODO(Cody): make private + // TODO(Cody): make uniform with accumulate_relation_univariates /** - * @brief After executing each widget on each edge, producing a tuple of univariates of differing lenghts, - * extend all univariates to the max of the lenghts required by the largest constraint. + * @brief Calculate the contribution of each relation to the expected value of the full Honk relation. * - * @tparam constraint_idx + * @details For each relation, use the purported values (supplied by the prover) of the multivariates to calculate + * a contribution to the purported value of the full Honk relation. These are stored in `evaluations`. Adding these + * together, with appropriate scaling factors, produces the expected value of the full Honk relation. This value is + * checked against the final value of the target total sum (called sigma_0 in the thesis). */ - template void extend_univariate_accumulators() + template + // TODO(Cody): Input should be an array? Then challenge container has to know array length. + void accumulate_relation_evaluations(std::vector& purported_evaluations) { - extended_univariates[constraint_idx] = - std::get(constraint_manager.constraints) - .barycentric.extend(std::get(constraint_manager.univariate_accumulators)); + std::get(relations).add_full_relation_value_contribution(purported_evaluations, + evaluations[relation_idx]); - // Repeat for the next constraint. - if constexpr (constraint_idx + 1 < NUM_CONSTRAINTS) { - extend_univariate_accumulators(); + // Repeat for the next relation. + if constexpr (relation_idx + 1 < NUM_RELATIONS) { + accumulate_relation_evaluations(purported_evaluations); } } /** - * @brief In the first round, return the evaluations of the univariate restriction S(X_l) at EdgeGroup::length-many - * values. Most likely this will end up being S(0), ... , S(t-1) where t is around 12. - * - * @details We have a separate function for the first round so we can halve the memory - * usage of the sumcheck round by only copy the results after folding. - * - * @param edges - * @param challenges - * @return Univariate + * @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 */ - Univariate compute_initial_univariate_restriction( - Multivariates& multivariates, ChallengeContainer& challenges) + template void extend_univariate_accumulators() { - for (size_t edge_idx = 0; edge_idx < round_size; edge_idx += 2) { - extend_edges(multivariates.full_polynomials, edge_idx); - accumulate_constraint_univariates<>(); - } - - Fr running_challenge(1); - Fr challenge = challenges.get_constraint_separator_challenge(); - auto result = batch_over_constraints>( - constraint_manager.univariate_accumulators, challenge); + extended_univariates[relation_idx] = + std::get(barycentric_utils).extend(std::get(univariate_accumulators)); - // at this point, we are able to - // - add these coefficients to the transcript and extract u_l - // - partially evaluate all multivariates in u_l - return result; + // 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) at EdgeGroup::length-many values. - * Most likely this will end up being S_l(0), ... , S_l(t-1) where t is around 12. - * - * @param edges - * @param challenges - * @return Univariate - * + * @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. */ - Univariate compute_univariate_restriction(Multivariates& multivariates, - ChallengeContainer& challenges) + Univariate compute_univariate(auto& polynomials, FF& relation_separator_challenge) { - // For each edge index, iterate over all constraints, accumulating for each constraint the contribution - // to each of desired evaluations of S_l. - std::tuple::CONSTRAINT_LENGTH>...> constraint_univariates = - std::tuple(ConstraintPack::CONSTRAINT_LENGTH...); - for (size_t edge_idx = 0; edge_idx < round_size; edge_idx += 2) { - extend_edges(multivariates.folded_multivariates, edge_idx); - accumulate_constraint_univariates<>(constraint_univariates); + extend_edges(polynomials, edge_idx); + accumulate_relation_univariates<>(); } - // Construct the univariate restriction - Fr running_challenge(1); - Fr challenge = challenges.get_constraint_separator_challenge(); - Univariate result({ 0 }); // need to initialize to 0 - for (auto& univariate : constraint_univariates) { - result += univariate * running_challenge; - running_challenge *= challenge; - } + FF running_challenge(1); + auto result = batch_over_relations>(univariate_accumulators, + relation_separator_challenge); - // - add these coefficients to the transcript and extract u_l - // - partially evaluate all multivariates in u_l return result; } - Fr compute_full_honk_constraint_purported_value(ChallengeContainer& challenges) + FF compute_full_honk_relation_purported_value(std::vector purported_evaluations, + FF& relation_separator_challenge) { - // TODO(cody): Reuse functions from univariate_accumulators batching? - std::array constraint_evaluations{ { 0 } }; - accumulate_constraint_evaluations<>(constraint_evaluations); + accumulate_relation_evaluations<>(purported_evaluations); - Fr running_challenge(1); - Fr challenge = challenges.get_constraint_separator_challenge(); - Fr output(0); - for (auto& evals : constraint_evaluations) { + // IMPROVEMENT(Cody): Reuse functions from univariate_accumulators batching? + FF running_challenge(1); + FF output(0); + for (auto& evals : evaluations) { output += evals * running_challenge; - running_challenge *= challenge; + running_challenge *= relation_separator_challenge; } return output; } - bool check_sum(Univariate& univariate_restriction) + bool check_sum(Univariate& univariate) { - // S_l(0) + S_l(1) - Fr total_sum = univariate_restriction.at(0) + univariate_restriction.at(1); - bool sumcheck_round_passes = (target_total_sum == total_sum); // an assert_equal - return sumcheck_round_passes; + FF total_sum = univariate.value_at(0) + univariate.value_at(1); + bool sumcheck_round_failed = (target_total_sum != total_sum); + round_failed = round_failed || sumcheck_round_failed; + return sumcheck_round_failed; }; - /** - * @brief Have ChallengeContainer sample the next univariate evalution challenge u_l and the resulting univariate - * value sigma_l of the function S_l. - * @param evals - * @param challenges - */ - Fr compute_challenge_and_evaluation(Univariate& univariate_restriction, - ChallengeContainer& challenges) + FF compute_next_target_sum(Univariate& univariate, FF& round_challenge) { - // add challenges to transcript and run Fiat-Shamir - Fr challenge = challenges.get_sumcheck_round_challenge(univariate_restriction); - auto barycentric = BarycentricData::num_evals, - Univariate::num_evals>(); - target_total_sum = barycentric.evaluate(univariate_restriction, challenge); - return challenge; + // IMPROVEMENT(Cody): Use barycentric static method, maybe implement evaluation as member + // function on Univariate. + auto barycentric = BarycentricData(); + target_total_sum = barycentric.evaluate(univariate, round_challenge); + return target_total_sum; } - - bool execute_first_round() - { - Univariate univariate_restriction = - compute_initial_univariate_restriction(multivariates, challenges); - // evaluate univariate restriction and challenge and check for equality with target value - failed = !check_sum(univariate_restriction); - - if (failed) { - // TODO: use to set composer.failed? - return false; - } - // compute univariate evaluation challenge and update the target value - // for the next call to check_sum - Fr round_challenge = compute_challenge_and_evaluation(univariate_restriction, challenges); - multivariates.fold(round_size, round_challenge); - round_size /= 2; - - return true; - }; - - bool execute() - { - Univariate univariate_restriction = - compute_univariate_restriction(multivariates, challenges); - // evaluate univariate restriction and challenge and check for equality with target value - failed = !check_sum(univariate_restriction); - - if (failed) { - // TODO: use to set composer.failed? - return false; - } - // compute univariate evaluation challenge and update the target value - // for the next call to check_sum - Fr round_challenge = compute_challenge_and_evaluation(univariate_restriction, challenges); - multivariates.fold(round_size, round_challenge); - round_size /= 2; - - return true; - }; }; -} // namespace sumcheck -} // namespace honk +} // namespace honk::sumcheck diff --git a/barretenberg/cpp/src/aztec/honk/sumcheck/sumcheck_round.test.cpp b/barretenberg/cpp/src/aztec/honk/sumcheck/sumcheck_round.test.cpp index 43573ac5d86a..36a22fbf138c 100644 --- a/barretenberg/cpp/src/aztec/honk/sumcheck/sumcheck_round.test.cpp +++ b/barretenberg/cpp/src/aztec/honk/sumcheck/sumcheck_round.test.cpp @@ -1,10 +1,13 @@ -#include "./transcript.hpp" -#include "./sumcheck_round.hpp" -#include "./sumcheck_types/constraint.hpp" -#include "./sumcheck_types/arithmetic_constraint.hpp" -#include "./sumcheck_types/multivariates.hpp" -#include "./sumcheck_types/univariate.hpp" -#include "./sumcheck_types/challenge_container.hpp" +#include "../flavor/flavor.hpp" +#include "transcript.hpp" +#include "sumcheck_round.hpp" +#include "relations/relation.hpp" +#include "relations/arithmetic_relation.hpp" +#include "relations/grand_product_computation_relation.hpp" +#include "relations/grand_product_initialization_relation.hpp" +#include "polynomials/multivariates.hpp" +#include "polynomials/univariate.hpp" +#include "challenge_container.hpp" #include #include @@ -13,9 +16,6 @@ #include #include -#pragma GCC diagnostic ignored "-Wunused-variable" -#pragma GCC diagnostic ignored "-Wunused-parameter" - using namespace honk; using namespace honk::sumcheck; @@ -27,166 +27,131 @@ template class MockTranscript : public Transcript { namespace test_sumcheck_round { -TEST(Sumcheck, ComputeUnivariateProverMock) +TEST(SumcheckRound, ComputeUnivariateProver) { - // arithmetic constraint G is deegree 3 in 8 variables - // G(Y1, ..., Y8) = Y4Y1Y2 + Y5Y1 + Y6Y2 + Y7Y3 + Y8 - const size_t num_polys(MULTIVARIATE::COUNT); + const size_t num_polys(StandardArithmetization::NUM_POLYNOMIALS); const size_t multivariate_d(1); - const size_t multivariate_n(1 << multivariate_d); - const size_t constraint_degree_plus_one = 5; // TODO(cody) extract from widget - - class SumcheckTypes { - public: - using Fr = barretenberg::fr; - // using Univariate = Univariate; - using Multivariates = ::Multivariates; - using ChallengeContainer = - ::ChallengeContainer, Univariate>; + const size_t max_relation_length = 5; + + using FF = barretenberg::fr; + using Multivariates = ::Multivariates; + using ChallengeContainer = ::ChallengeContainer, Univariate>; + + std::array w_l = { 1, 2 }; + std::array w_r = { 1, 2 }; + std::array w_o = { 1, 2 }; + std::array z_perm = { 1, 2 }; + std::array z_perm_shift = { 0, 1 }; // chosen to reuse value computed in tests of grand product relations + std::array q_m = { 1, 2 }; + std::array q_l = { 1, 2 }; + std::array q_r = { 1, 2 }; + std::array q_o = { 1, 2 }; + std::array q_c = { 1, 2 }; + std::array sigma_1 = { 1, 2 }; + std::array sigma_2 = { 1, 2 }; + std::array sigma_3 = { 1, 2 }; + std::array id_1 = { 1, 2 }; + std::array id_2 = { 1, 2 }; + std::array id_3 = { 1, 2 }; + std::array lagrange_1 = { 1, 2 }; + + std::array, StandardArithmetization::NUM_POLYNOMIALS> full_polynomials = { + w_l, w_r, w_o, z_perm, z_perm_shift, q_m, q_l, q_r, q_o, + q_c, sigma_1, sigma_2, sigma_3, id_1, id_2, id_3, lagrange_1 }; - SumcheckTypes::Fr w_l[2] = { 1, 2 }; - SumcheckTypes::Fr w_r[2] = { 1, 2 }; - SumcheckTypes::Fr w_o[2] = { 1, 2 }; - SumcheckTypes::Fr z_perm[2] = { 1, 2 }; - SumcheckTypes::Fr z_perm_shift[2] = { 1, 2 }; - SumcheckTypes::Fr q_m[2] = { 1, 2 }; - SumcheckTypes::Fr q_l[2] = { 1, 2 }; - SumcheckTypes::Fr q_r[2] = { 1, 2 }; - SumcheckTypes::Fr q_o[2] = { 1, 2 }; - SumcheckTypes::Fr q_c[2] = { 1, 2 }; - SumcheckTypes::Fr sigma_1[2] = { 1, 2 }; - SumcheckTypes::Fr sigma_2[2] = { 1, 2 }; - SumcheckTypes::Fr sigma_3[2] = { 1, 2 }; - SumcheckTypes::Fr id_1[2] = { 1, 2 }; - SumcheckTypes::Fr id_2[2] = { 1, 2 }; - SumcheckTypes::Fr id_3[2] = { 1, 2 }; - SumcheckTypes::Fr lagrange_1[2] = { 1, 2 }; - - std::array 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_1 }); - - auto multivariates = SumcheckTypes::Multivariates(full_polynomials); - - auto transcript = MockTranscript(); // actually a shared pointer to a transcript? - auto challenges = SumcheckTypes::ChallengeContainer(transcript); - + auto transcript = MockTranscript(); + auto challenges = ChallengeContainer(transcript); size_t round_size = 1; - // call SumcheckRound with one constraint - auto round = SumcheckRound(multivariates, challenges); - Univariate restriction = - round.compute_initial_univariate_restriction(multivariates, challenges); - Univariate expected_restriction{ { 5, 22, 57, 116, 205 } }; - EXPECT_EQ(restriction, expected_restriction); + + auto relations = std::tuple(ArithmeticRelation(challenges), + GrandProductComputationRelation(challenges), + GrandProductInitializationRelation(challenges)); + + // Improvement(Cody): This is ugly? Maye supply some/all of this data through "flavor" class? + auto round = SumcheckRound(round_size, relations); + FF relation_separator_challenge = 1; + Univariate round_univariate = + round.compute_univariate(full_polynomials, relation_separator_challenge); + Univariate expected_round_univariate{ { 32, 149, 406, 857, 1556 } }; + + EXPECT_EQ(round_univariate, expected_round_univariate); } -TEST(Sumcheck, ComputeUnivariateVerifierMock) +TEST(SumcheckRound, ComputeUnivariateVerifier) { - // arithmetic constraint G is deegree 3 in 8 variables - // G(Y1, ..., Y8) = Y4Y1Y2 + Y5Y1 + Y6Y2 + Y7Y3 + Y8 - const size_t num_polys(MULTIVARIATE::COUNT); + const size_t num_polys(StandardArithmetization::NUM_POLYNOMIALS); const size_t multivariate_d(1); const size_t multivariate_n(1 << multivariate_d); - const size_t constraint_degree_plus_one = 5; // TODO(cody) extract from widget - - class SumcheckTypes { - public: - using Fr = barretenberg::fr; - // using Univariate = Univariate; - using Multivariates = ::Multivariates; - using ChallengeContainer = - ::ChallengeContainer, Univariate>; - }; - - SumcheckTypes::Fr w_l = { 1 }; - SumcheckTypes::Fr w_r = { 2 }; - SumcheckTypes::Fr w_o = { 3 }; - SumcheckTypes::Fr z_perm = { 0 }; - SumcheckTypes::Fr z_perm_shift = { 0 }; - SumcheckTypes::Fr q_m = { 4 }; - SumcheckTypes::Fr q_l = { 5 }; - SumcheckTypes::Fr q_r = { 6 }; - SumcheckTypes::Fr q_o = { 7 }; - SumcheckTypes::Fr q_c = { 8 }; - SumcheckTypes::Fr sigma_1 = { 0 }; - SumcheckTypes::Fr sigma_2 = { 0 }; - SumcheckTypes::Fr sigma_3 = { 0 }; - SumcheckTypes::Fr id_1 = { 0 }; - SumcheckTypes::Fr id_2 = { 0 }; - SumcheckTypes::Fr id_3 = { 0 }; - SumcheckTypes::Fr lagrange_1 = { 0 }; + const size_t max_relation_length = 5; + + using FF = barretenberg::fr; + using Multivariates = ::Multivariates; + using ChallengeContainer = ::ChallengeContainer, Univariate>; + + FF w_l = { 1 }; + FF w_r = { 2 }; + FF w_o = { 3 }; + // TODO(Cody): compute permutation value? + FF z_perm = { 0 }; + FF z_perm_shift = { 0 }; + FF q_m = { 4 }; + FF q_l = { 5 }; + FF q_r = { 6 }; + FF q_o = { 7 }; + FF q_c = { 8 }; + FF sigma_1 = { 0 }; + FF sigma_2 = { 0 }; + FF sigma_3 = { 0 }; + FF id_1 = { 0 }; + FF id_2 = { 0 }; + FF id_3 = { 0 }; + FF lagrange_1 = { 0 }; // 4 * 1 * 2 + 5 * 1 + 6 * 2 + 7 * 3 + 8 = 54 - SumcheckTypes::Fr expected_full_purported_value = 54; - std::array purported_evaluations({ w_l, - w_r, - w_o, - z_perm, - z_perm_shift, - q_m, - q_l, - q_r, - q_o, - q_c, - sigma_1, - sigma_2, - sigma_3, - id_1, - id_2, - id_3, - lagrange_1 }); + FF expected_full_purported_value = 54; + std::vector purported_evaluations = { w_l, w_r, w_o, z_perm, z_perm_shift, q_m, q_l, q_r, q_o, + q_c, sigma_1, sigma_2, sigma_3, id_1, id_2, id_3, lagrange_1 }; - auto transcript = MockTranscript(); // actually a shared pointer to a transcript? - auto challenges = SumcheckTypes::ChallengeContainer(transcript); + auto transcript = MockTranscript(); + auto challenges = ChallengeContainer(transcript); size_t round_size = 1; - // call SumcheckRound with one constraint - auto round = SumcheckRound(purported_evaluations, challenges); - SumcheckTypes::Fr full_purported_value = round.compute_full_honk_constraint_purported_value(challenges); + auto relations = std::tuple(ArithmeticRelation(challenges), + GrandProductComputationRelation(challenges), + GrandProductInitializationRelation(challenges)); + auto round = SumcheckRound(relations); + FF relation_separator_challenge = -1; + FF full_purported_value = + round.compute_full_honk_relation_purported_value(purported_evaluations, relation_separator_challenge); EXPECT_EQ(full_purported_value, expected_full_purported_value); } +// TODO(Cody): Implement this and better tests. // TEST(sumcheck, round) // { -// // arithmetic constraint G is deegree 3 in 8 variables +// // arithmetic relation G is deegree 3 in 8 variables // // G(Y1, ..., Y8) = Y4Y1Y2 + Y5Y1 + Y6Y2 + Y7Y3 + Y8 -// const size_t num_polys(MULTIVARIATE::COUNT); +// const size_t num_polys(StandardArithmetization::NUM_POLYNOMIALS); // const size_t multivariate_d(2); // const size_t multivariate_n(1 << multivariate_d); -// const size_t constraint_degree_plus_one = 5; +// const size_t max_relation_length = 5; // using Fr = barretenberg::fr; // using Edge = Edge; // using EdgeGroup = EdgeGroup; // using Multivariates = Multivariates; -// using Univariate = Univariate; +// using Univariate = Univariate; // using ChallengeContainer = ChallengeContainer, Univariate>; - -// class SumcheckTypes { -// public: -// using Fr = Fr; -// using EdgeGroup = EdgeGroup; -// using Multivariates = Multivariates; -// using ChallengeContainer = ChallengeContainer; -// using Univariate = Univariate; -// }; - -// // TODO(cody): move this out of round. +// // TODO(Cody): move this out of round. // EdgeGroup group0({ Edge({ 1, 2 }), // Edge({ 1, 2 }), // Edge({ 1, 2 }), @@ -206,11 +171,11 @@ TEST(Sumcheck, ComputeUnivariateVerifierMock) // Edge({ 7, 8 }) }); // auto polynomials = Multivariates({ group0, group1 }); -// auto constraints = std::make_tuple(ArithmeticConstraint()); +// auto relations = std::make_tuple(ArithmeticRelation()); // auto transcript = MockTranscript(); // actually a shared pointer to a transcript? // auto challenges = ChallengeContainer(transcript); -// auto round = SumcheckRound(polynomials, constraints, challenges); +// auto round = SumcheckRound<..., ArithmeticRelation>(polynomials, relations, challenges); // // The values of the univariate restriction S2 created in the first round // // are the sum of a contribution form group0 and a contribution from group1. // // Using Sage; @@ -244,78 +209,4 @@ TEST(Sumcheck, ComputeUnivariateVerifierMock) // EXPECT_EQ(round.round_size, 1); // } -// TEST(sumcheck, round_from_pointers) -// { -// // arithmetic constraint G is deegree 3 in 8 variables -// // G(Y1, ..., Y8) = Y4Y1Y2 + Y5Y1 + Y6Y2 + Y7Y3 + Y8 -// const size_t num_polys(MULTIVARIATE::COUNT); -// const size_t multivariate_d(2); -// const size_t multivariate_n(1 << multivariate_d); -// const size_t constraint_degree_plus_one = 5; - -// using Fr = barretenberg::fr; -// using Edge = Edge; -// using EdgeGroup = EdgeGroup; -// using Multivariates = Multivariates; -// using ChallengeContainer = ChallengeContainer, Univariate>; - -// class SumcheckTypes { -// public: -// using Fr = Fr; -// using EdgeGroup = EdgeGroup; -// using Multivariates = Multivariates; -// using ChallengeContainer = ChallengeContainer; -// using Univariate = Univariate; -// }; - -// Fr w_l[4] = { 1, 2, 7, 8 }; -// Fr w_r[4] = { 1, 2, 7, 8 }; -// Fr w_o[4] = { 1, 2, 7, 8 }; -// Fr q_l[4] = { 1, 2, 7, 8 }; -// Fr q_m[4] = { 1, 2, 7, 8 }; -// Fr q_r[4] = { 1, 2, 7, 8 }; -// Fr q_o[4] = { 1, 2, 7, 8 }; -// Fr q_c[4] = { 1, 2, 7, 8 }; - -// std::array input_polys = { w_l, w_r, w_o, q_l, q_m, q_r, q_o, q_c }; - -// auto polynomials = Multivariates(input_polys); -// auto constraints = std::make_tuple(ArithmeticConstraint()); -// auto transcript = MockTranscript(); // actually a shared pointer to a transcript? -// auto challenges = ChallengeContainer(transcript); - -// auto round = SumcheckRound(polynomials, constraints, challenges); -// // The values of the univariate restriction S2 created in the first round -// // are the sum of a contribution form group0 and a contribution from group1. -// // Using Sage; -// // group0 contributes: [5, 22, 57, 116] -// // group1 contributes: [497, 712, 981, 1310] -// // Therefore the values of S2 on {0, 1, 2, 3} are: [502, 734, 1038, 1426] -// // and S2(0) + S2(1) = 502 + 734 = 1236 -// round.target_total_sum = 1236; -// EXPECT_EQ(round.round_size, 2); -// /* -// Folding with u2 = -1 -// 2 -------- 8 -// | | -// | Yi | -// | i=1...8 | -// 1 -------- 7 ~~> 0 -------- 6 -// (2(1-X1)+8X1) X2 0(1-X1)+6X1 -// +(1(1-X1)+7X1)(1-X2) -// */ -// round.execute(); -// // EdgeGroup expected_group0({ Edge({ 0, 6 }), -// // Edge({ 0, 6 }), -// // Edge({ 0, 6 }), -// // Edge({ 0, 6 }), -// // Edge({ 0, 6 }), -// // Edge({ 0, 6 }), -// // Edge({ 0, 6 }), -// // Edge({ 0, 6 }) }); -// // EXPECT_EQ(expected_group0, round.polynomials.groups[0]); -// // ASSERT_FALSE(round.failed); -// // EXPECT_EQ(round.round_size, 1); -// } } // namespace test_sumcheck_round diff --git a/barretenberg/cpp/src/aztec/honk/sumcheck/sumcheck_types/arithmetic_constraint.hpp b/barretenberg/cpp/src/aztec/honk/sumcheck/sumcheck_types/arithmetic_constraint.hpp deleted file mode 100644 index 002160b03d30..000000000000 --- a/barretenberg/cpp/src/aztec/honk/sumcheck/sumcheck_types/arithmetic_constraint.hpp +++ /dev/null @@ -1,71 +0,0 @@ -#include -#include -#include -#include "./constraint.hpp" -#include "./multivariates.hpp" -#include "./barycentric_data.hpp" -#include "./univariate.hpp" -#include "./challenge_container.hpp" -#include "../transcript.hpp" -#include -#pragma GCC diagnostic ignored "-Wunused-variable" -#pragma GCC diagnostic ignored "-Wunused-parameter" - -namespace honk { -namespace sumcheck { - -template class ArithmeticConstraint : public Constraint { - public: - static constexpr size_t CONSTRAINT_LENGTH = 4; // degree of this constraint + 1 - using Constraint::HONK_CONSTRAINT_LENGTH; - using Constraint::NUM_HONK_MULTIVARIATES; - // Will be used after adding all edge contributions to extend - // FUTURE OPTIMIZATION: successively extend as needed? - BarycentricData barycentric = - BarycentricData(); - - using UnivariateClass = Univariate; - - // using UnivariateView = UnivariateView; - - ArithmeticConstraint() = default; - - // TODO: optimize! Karatsuba in general, at least for some degrees? - // See https://hackmd.io/xGLuj6biSsCjzQnYN-pEiA?both - void add_edge_contribution(auto edge_extensions, Univariate& evals) - { - auto w_l = UnivariateView(edge_extensions[MULTIVARIATE::W_L]); - auto w_r = UnivariateView(edge_extensions[MULTIVARIATE::W_R]); - auto w_o = UnivariateView(edge_extensions[MULTIVARIATE::W_O]); - auto q_m = UnivariateView(edge_extensions[MULTIVARIATE::Q_M]); - auto q_l = UnivariateView(edge_extensions[MULTIVARIATE::Q_L]); - auto q_r = UnivariateView(edge_extensions[MULTIVARIATE::Q_R]); - auto q_o = UnivariateView(edge_extensions[MULTIVARIATE::Q_O]); - auto q_c = UnivariateView(edge_extensions[MULTIVARIATE::Q_C]); - - evals += w_l * (q_m * w_r + q_l); - evals += q_r * w_r; - evals += q_o * w_o; - evals += q_c; - }; - - void add_full_constraint_value_contribution(std::array purported_evaluations, - Fr& full_honk_constraint_value) - { - - auto w_l = purported_evaluations[MULTIVARIATE::W_L]; - auto w_r = purported_evaluations[MULTIVARIATE::W_R]; - auto w_o = purported_evaluations[MULTIVARIATE::W_O]; - auto q_m = purported_evaluations[MULTIVARIATE::Q_M]; - auto q_l = purported_evaluations[MULTIVARIATE::Q_L]; - auto q_r = purported_evaluations[MULTIVARIATE::Q_R]; - auto q_o = purported_evaluations[MULTIVARIATE::Q_O]; - auto q_c = purported_evaluations[MULTIVARIATE::Q_C]; - full_honk_constraint_value += w_l * (q_m * w_r + q_l); - full_honk_constraint_value += q_r * w_r; - full_honk_constraint_value += q_o * w_o; - full_honk_constraint_value += q_c; - }; -}; -} // namespace sumcheck -} // namespace honk diff --git a/barretenberg/cpp/src/aztec/honk/sumcheck/sumcheck_types/challenge_container.hpp b/barretenberg/cpp/src/aztec/honk/sumcheck/sumcheck_types/challenge_container.hpp deleted file mode 100644 index f0d6d86e5697..000000000000 --- a/barretenberg/cpp/src/aztec/honk/sumcheck/sumcheck_types/challenge_container.hpp +++ /dev/null @@ -1,24 +0,0 @@ -#pragma once -#include -#include -#include "../transcript.hpp" - -namespace honk { -namespace sumcheck { -template class ChallengeContainer { - public: - Fr get_constraint_separator_challenge() { return transcript.get_challenge(); }; // these are powers of a challenge - // Fr get_constraint_bliding_base(){return transcript.get_challenge(1);} // will get element zeta as well - - Transcript transcript; // TODO(cody):really a pointer to such a thing? - ChallengeContainer(Transcript transcript) - : transcript(transcript){}; - Fr get_sumcheck_round_challenge(Univariate univariate_restriction) - { - return transcript.get_challenge(); - }; // this is u_l - - Fr get_challenge_equals_one() { return transcript.get_challenge_equals_one(); }; -}; -} // namespace sumcheck -} // namespace honk diff --git a/barretenberg/cpp/src/aztec/honk/sumcheck/sumcheck_types/constraint.hpp b/barretenberg/cpp/src/aztec/honk/sumcheck/sumcheck_types/constraint.hpp deleted file mode 100644 index 042df2b0a791..000000000000 --- a/barretenberg/cpp/src/aztec/honk/sumcheck/sumcheck_types/constraint.hpp +++ /dev/null @@ -1,16 +0,0 @@ -#pragma once -#include -#include -#include -#include "./multivariates.hpp" -// #include "honk/sumcheck/sumcheck_types/univariate.hpp" - -namespace honk::sumcheck { - -template class Constraint { - public: - static const size_t HONK_CONSTRAINT_LENGTH = 5; // TODO(luke): move to something more global - static constexpr size_t NUM_HONK_MULTIVARIATES = MULTIVARIATE::COUNT; -}; - -} // namespace honk::sumcheck diff --git a/barretenberg/cpp/src/aztec/honk/sumcheck/sumcheck_types/constraint.test.cpp b/barretenberg/cpp/src/aztec/honk/sumcheck/sumcheck_types/constraint.test.cpp deleted file mode 100644 index c992d01232a6..000000000000 --- a/barretenberg/cpp/src/aztec/honk/sumcheck/sumcheck_types/constraint.test.cpp +++ /dev/null @@ -1,198 +0,0 @@ -#include "./constraint.hpp" -#include "./arithmetic_constraint.hpp" -#include "./grand_product_initialization_constraint.hpp" -#include "./grand_product_computation_constraint.hpp" -#include "./multivariates.hpp" -#include "./univariate.hpp" -#include "./challenge_container.hpp" -#include -#include -#include "../transcript.hpp" - -#include -#include - -#pragma GCC diagnostic ignored "-Wunused-variable" -#pragma GCC diagnostic ignored "-Wunused-parameter" - -using namespace honk::sumcheck; - -namespace honk { -namespace sumcheck { - -// template class MockTranscript : public Transcript { -// public: -// Fr get_challenge() { return mock_challenge; }; -// Fr mock_challenge = -1; -// }; - -// field is named Fscalar here because of clash with the Fr expected to be -// part of ConstraintTypes. Got impatient; should find better way -template class sumcheck_constraint : public testing::Test { - template using Univariate = Univariate; - template using UnivariateView = UnivariateView; - // template using ChallengeContainer = ChallengeContainer, Univariate>; - - template class ExampleConstraintTypes { - public: - using Fr = Fscalar; - // using Univariate = Univariate; - // using ChallengeContainer = ChallengeContainer; - }; - - // TODO(luke): may want to make this more flexible/generic - static std::array, MULTIVARIATE::COUNT> compute_mock_edge_extensions() - { - // TODO(cody): build from Univariate<2>'s? - auto w_l = Univariate<5>({ 1, 2, 3, 4, 5 }); - auto w_r = Univariate<5>({ 1, 2, 3, 4, 5 }); - auto w_o = Univariate<5>({ 1, 2, 3, 4, 5 }); - auto z_perm = Univariate<5>({ 1, 2, 3, 4, 5 }); - // Note: z_perm_shift can be any linear poly for the sake of the tests but should not be equal to z_perm to - // avoid a trivial computation in the case of the grand_product_computation_constraint - auto z_perm_shift = Univariate<5>({ 2, 1, 0, -1, -2 }); - auto q_m = Univariate<5>({ 1, 2, 3, 4, 5 }); - auto q_l = Univariate<5>({ 1, 2, 3, 4, 5 }); - auto q_r = Univariate<5>({ 1, 2, 3, 4, 5 }); - auto q_o = Univariate<5>({ 1, 2, 3, 4, 5 }); - auto q_c = Univariate<5>({ 1, 2, 3, 4, 5 }); - auto sigma_1 = Univariate<5>({ 1, 2, 3, 4, 5 }); - auto sigma_2 = Univariate<5>({ 1, 2, 3, 4, 5 }); - auto sigma_3 = Univariate<5>({ 1, 2, 3, 4, 5 }); - auto id_1 = Univariate<5>({ 1, 2, 3, 4, 5 }); - auto id_2 = Univariate<5>({ 1, 2, 3, 4, 5 }); - auto id_3 = Univariate<5>({ 1, 2, 3, 4, 5 }); - auto lagrange_1 = Univariate<5>({ 1, 2, 3, 4, 5 }); - - std::array, MULTIVARIATE::COUNT> edge_extensions({ 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_1 }); - return edge_extensions; - } - - public: - static void test_arithmetic_constraint() - { - auto edge_extensions = compute_mock_edge_extensions(); - - auto constraint = ArithmeticConstraint(); - using UnivariateView = UnivariateView; - using Univariate = Univariate; - - // Manually compute the expected edge contribution - auto w_l = UnivariateView(edge_extensions[MULTIVARIATE::W_L]); - auto w_r = UnivariateView(edge_extensions[MULTIVARIATE::W_R]); - auto w_o = UnivariateView(edge_extensions[MULTIVARIATE::W_O]); - auto q_m = UnivariateView(edge_extensions[MULTIVARIATE::Q_M]); - auto q_l = UnivariateView(edge_extensions[MULTIVARIATE::Q_L]); - auto q_r = UnivariateView(edge_extensions[MULTIVARIATE::Q_R]); - auto q_o = UnivariateView(edge_extensions[MULTIVARIATE::Q_O]); - auto q_c = UnivariateView(edge_extensions[MULTIVARIATE::Q_C]); - Univariate expected_evals = (q_m * w_r * w_l) + (q_r * w_r) + (q_l * w_l) + (q_o * w_o) + (q_c); - // Univariate expected_evals{ { 5, 22, 57, 116 } }; - - auto evals = Univariate(); - constraint.add_edge_contribution(edge_extensions, evals); - - EXPECT_EQ(evals, expected_evals); - }; - - static void test_grand_product_computation_constraint() - { - using ChallengeContainer = ChallengeContainer, Univariate<5>>; - - // TODO(luke): Write a test that illustrates the following? - // Note: the below z_perm_shift = X^2 will fail because it results in a constraint 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<5>({ 1, 4, 9, 16, 25 }); // X^2 - - auto edge_extensions = compute_mock_edge_extensions(); - auto constraint = GrandProductComputationConstraint(); - auto transcript = Transcript(); - auto challenges = ChallengeContainer(transcript); - using UnivariateView = UnivariateView; - using Univariate = Univariate; - - // Manually compute the expected edge contribution - auto w_1 = UnivariateView(edge_extensions[MULTIVARIATE::W_L]); - auto w_2 = UnivariateView(edge_extensions[MULTIVARIATE::W_R]); - auto w_3 = UnivariateView(edge_extensions[MULTIVARIATE::W_O]); - auto sigma_1 = UnivariateView(edge_extensions[MULTIVARIATE::SIGMA_1]); - auto sigma_2 = UnivariateView(edge_extensions[MULTIVARIATE::SIGMA_2]); - auto sigma_3 = UnivariateView(edge_extensions[MULTIVARIATE::SIGMA_3]); - auto id_1 = UnivariateView(edge_extensions[MULTIVARIATE::ID_1]); - auto id_2 = UnivariateView(edge_extensions[MULTIVARIATE::ID_1]); - auto id_3 = UnivariateView(edge_extensions[MULTIVARIATE::ID_1]); - auto z_perm = UnivariateView(edge_extensions[MULTIVARIATE::Z_PERM]); - auto z_perm_shift = UnivariateView(edge_extensions[MULTIVARIATE::Z_PERM_SHIFT]); - // auto lagrange_1 = UnivariateView(edge_extensions[MULTIVARIATE::LAGRANGE_1]); - // TODO(luke): use real transcript/challenges - Fscalar beta = challenges.get_challenge_equals_one(); - Fscalar gamma = challenges.get_challenge_equals_one(); - - auto expected_evals = Univariate(); - expected_evals += - z_perm * (w_1 + id_1 * beta + gamma) * (w_2 + id_2 * beta + gamma) * (w_3 + id_3 * beta + gamma); - expected_evals -= z_perm_shift * (w_1 + sigma_1 * beta + gamma) * (w_2 + sigma_2 * beta + gamma) * - (w_3 + sigma_3 * beta + gamma); - - auto evals = Univariate(); - constraint.add_edge_contribution(edge_extensions, evals, challenges); - - EXPECT_EQ(evals, expected_evals); - }; - - static void test_grand_product_initialization_constraint() - { - auto edge_extensions = compute_mock_edge_extensions(); - auto constraint = GrandProductInitializationConstraint(); - using UnivariateView = UnivariateView; - using Univariate = Univariate; - - // Manually compute the expected edge contribution - auto z_perm = UnivariateView(edge_extensions[MULTIVARIATE::Z_PERM]); - auto lagrange_1 = UnivariateView(edge_extensions[MULTIVARIATE::LAGRANGE_1]); - auto expected_evals = lagrange_1 * (z_perm - Fscalar(1)); - - // Compute the edge contribution using add_edge_contribution - auto evals = Univariate(); - constraint.add_edge_contribution(edge_extensions, evals); - - EXPECT_EQ(evals, expected_evals); - }; -}; - -typedef testing::Types FieldTypes; -TYPED_TEST_SUITE(sumcheck_constraint, FieldTypes); - -TYPED_TEST(sumcheck_constraint, arithmetic_constraint) -{ - TestFixture::test_arithmetic_constraint(); -} - -TYPED_TEST(sumcheck_constraint, grand_product_computation_constraint) -{ - TestFixture::test_grand_product_computation_constraint(); -} - -TYPED_TEST(sumcheck_constraint, grand_product_initialization_constraint) -{ - TestFixture::test_grand_product_initialization_constraint(); -} -} // namespace sumcheck -} // namespace honk diff --git a/barretenberg/cpp/src/aztec/honk/sumcheck/sumcheck_types/constraint_manager.hpp b/barretenberg/cpp/src/aztec/honk/sumcheck/sumcheck_types/constraint_manager.hpp deleted file mode 100644 index a6029a159d9a..000000000000 --- a/barretenberg/cpp/src/aztec/honk/sumcheck/sumcheck_types/constraint_manager.hpp +++ /dev/null @@ -1,25 +0,0 @@ -#pragma once -#include -#include -#include -#include "barycentric_data.hpp" -#include "univariate.hpp" - -namespace honk::sumcheck { - -template class ConstraintManager { - // template class ConstraintManager { - public: - static constexpr size_t NUM_CONSTRAINTS = sizeof...(Constraints); - // TODO(cody): const correctness - std::tuple constraints; - std::tuple univariate_accumulators; - // TODO(cody): make barycentric stuff static and put in here, rather than constraints? - // First need to figure out how max length (determined by flavour) is supplied. - // static constexpr auto barycentric_data = - // std::tuple(BarycentricData()...) - ConstraintManager() - : constraints(Constraints()...) - , univariate_accumulators(typename Constraints::UnivariateClass()...){}; -}; -} // namespace honk::sumcheck \ No newline at end of file diff --git a/barretenberg/cpp/src/aztec/honk/sumcheck/sumcheck_types/constraint_manager.test.cpp b/barretenberg/cpp/src/aztec/honk/sumcheck/sumcheck_types/constraint_manager.test.cpp deleted file mode 100644 index f91d343a2b73..000000000000 --- a/barretenberg/cpp/src/aztec/honk/sumcheck/sumcheck_types/constraint_manager.test.cpp +++ /dev/null @@ -1,43 +0,0 @@ -#include "./constraint_manager.hpp" -#include "./arithmetic_constraint.hpp" -#include "./grand_product_computation_constraint.hpp" -#include "./grand_product_initialization_constraint.hpp" -#include "./multivariates.hpp" -#include "./univariate.hpp" -#include "./challenge_container.hpp" -#include -#include -#include "../transcript.hpp" - -#include -#include - -#pragma GCC diagnostic ignored "-Wunused-variable" -#pragma GCC diagnostic ignored "-Wunused-parameter" - -using namespace honk::sumcheck; - -namespace honk { -namespace sumcheck { - -template class ConstraintManagerTests : public testing::Test {}; - -typedef testing::Types FieldTypes; -TYPED_TEST_SUITE(ConstraintManagerTests, FieldTypes); - -TYPED_TEST(ConstraintManagerTests, Constructor) -{ - using Field = TypeParam; - using ArithmeticConstraint = ArithmeticConstraint; - using GrandProductComputationConstraint = GrandProductComputationConstraint; - using GrandProductInitializationConstraint = GrandProductInitializationConstraint; - using ConstraintManager = ConstraintManager; - auto constraint_manager = ConstraintManager(); - EXPECT_EQ(std::get<0>(constraint_manager.constraints).CONSTRAINT_LENGTH, 4); - EXPECT_EQ(std::get<1>(constraint_manager.constraints).CONSTRAINT_LENGTH, 5); - EXPECT_EQ(std::get<2>(constraint_manager.constraints).CONSTRAINT_LENGTH, 3); -} -} // namespace sumcheck -} // namespace honk \ No newline at end of file diff --git a/barretenberg/cpp/src/aztec/honk/sumcheck/sumcheck_types/grand_product_initialization_constraint.hpp b/barretenberg/cpp/src/aztec/honk/sumcheck/sumcheck_types/grand_product_initialization_constraint.hpp deleted file mode 100644 index 45d79e8ed73d..000000000000 --- a/barretenberg/cpp/src/aztec/honk/sumcheck/sumcheck_types/grand_product_initialization_constraint.hpp +++ /dev/null @@ -1,51 +0,0 @@ -#include "./constraint.hpp" -#include "./multivariates.hpp" -#include "./univariate.hpp" -#include "./barycentric_data.hpp" - -#pragma GCC diagnostic ignored "-Wunused-variable" -#pragma GCC diagnostic ignored "-Wunused-parameter" - -namespace honk::sumcheck { - -template class GrandProductInitializationConstraint : public Constraint { - public: - static constexpr size_t CONSTRAINT_LENGTH = 3; // degree of this constraint + 1 - using Constraint::HONK_CONSTRAINT_LENGTH; - using Constraint::NUM_HONK_MULTIVARIATES; - BarycentricData barycentric = - BarycentricData(); - using UnivariateClass = Univariate; - // using UnivariateView = UnivariateView; - - public: - GrandProductInitializationConstraint() = default; - - /** - * @brief Add contribution of the permutation constraint for a given edge - * - * @detail There are 2 constraints associated with enforcing the wire copy constraints - * This file handles the constraint Z_perm(0) = 1 via the constraint: - * - * C(X) = L_1(X)(z_perm(X) - 1) - */ - void add_edge_contribution(auto& edge_extensions, UnivariateClass& evals) - { - auto z_perm = UnivariateView(edge_extensions[MULTIVARIATE::Z_PERM]); - auto lagrange_1 = UnivariateView(edge_extensions[MULTIVARIATE::LAGRANGE_1]); - auto one = Fr(1); - - evals += lagrange_1 * (z_perm - one); - }; - - void add_full_constraint_value_contribution(std::array purported_evaluations, - Fr& full_honk_constraint_value) - { - auto z_perm = purported_evaluations[MULTIVARIATE::Z_PERM]; - auto lagrange_1 = purported_evaluations[MULTIVARIATE::LAGRANGE_1]; - auto one = Fr(1); - - full_honk_constraint_value += lagrange_1 * (z_perm - one); - }; -}; -} // namespace honk::sumcheck diff --git a/barretenberg/cpp/src/aztec/honk/sumcheck/sumcheck_types/multivariates.hpp b/barretenberg/cpp/src/aztec/honk/sumcheck/sumcheck_types/multivariates.hpp deleted file mode 100644 index cc5153caf635..000000000000 --- a/barretenberg/cpp/src/aztec/honk/sumcheck/sumcheck_types/multivariates.hpp +++ /dev/null @@ -1,134 +0,0 @@ -#pragma once // just adding these willy-nilly -#include // just added to get info() - -namespace honk { -// starting with arithmetic and permutation constraints -// Note: including Z_PERM_SHIFT here is probably not the right thing long term but -// doing it for now for convenience -enum MULTIVARIATE { - 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_1, - COUNT -}; -static constexpr size_t NUM_MULTIVARIATES = MULTIVARIATE::COUNT; - -namespace sumcheck { -/** - * - * @brief A container for all of the Honk! polynomials (e.g., wire and selector polynomials). - * These polynomials all low-degree extensions over H^d with H = {0, 1} (where d = - * ceil(log(number of gates))), hence they are multilinear polynomials in d variables. As such, it is efficient to store - * these polynomials in terms of univariate degree-1 polynomials. We call such a polynomial an Edge, short for - - ... TODO(cody)rewrite! - - * Suppose now the Honk polynomials (multilinear in d variables) are called P_1, ..., P_N. At initialization, - * we think of these as lying in a two-dimensional array, where each column records the value of one P_i on H^d. In this - * array, each row contains N edge polynomials (an EdgeGroup). Hence the array has shape (n/2, N). After the first - * round, the array will be updated ('folded'), so that the first n/4 rows will represent the evaluations P_i(X1, ..., - * X_{d-1}, u_d) as a low-degree extension on H^{d-1}. - * - * @tparam Fr - * - * NOTE: With ~40 columns, prob only want to allocate 256 EdgeGroup's at once to keep stack under 1MB? - * TODO: might want to just do C-style multidimensional array? for guaranteed adjacency? - * NOTE: got rid of `populate` method--just assuming the EdgeGroup's are constructed at the time that the - * Multivariatess instance is constructed - */ -template class Multivariates { - public: - const static size_t multivariate_d = num_vars; - const static size_t multivariate_n = 1 << num_vars; - static constexpr size_t num = num_polys; - - std::array> 1)>, num_polys> folded_polynomials; - std::array full_polynomials; - - /* For groups, we imagine all of the defining polynomial data in - a matrix like this: - | P_1 | P_2 | P_3 | P_4 | ... | P_N | N = NUM_HONK_POLYS - |-----------------------------------| - group 0 --| * | * | * | * | ... | * | vertex 0 - \-| * | * | * | * | ... | * | vertex 1 - group 1 --| * | * | * | * | ... | * | vertex 2 - \-| * | * | * | * | ... | * | vertex 3 - | * | * | * | * | ... | * | - group m-1 --| * | * | * | * | ... | * | vertex n-2 - \-| * | * | * | * | ... | * | vertex n-1 - m = n/2 - - In practice, we record this value in an n/2 x N matrix groups - where each row is though of as a group of edge polynomials. - - */ - Multivariates() = default; - - Multivariates(std::array full_polynomials) - : full_polynomials(full_polynomials){}; - - /** - * @brief Evaluate at the round challenge and prepare class for next round. - * Illustration of layout in example of first round when d==3 (showing just one Honk polynomial, - * i.e., what happens in just one column of our two-dimensional array): - * - * groups vertex terms collected vertex terms groups after folding - * g0 -- v0 (1-X1)(1-X2)(1-X3) --- (v0(1-X3) + v1 X3) (1-X1)(1-X2) ---- (v0(1-u3) + v1 u3) (1-X1)(1-X2) - * \- v1 (1-X1)(1-X2) X3 --/ --- (v2(1-u3) + v3 u3) (1-X1) X2 - * g1 -- v2 (1-X1) X2 (1-X3) --- (v1(1-X3) + v2 X3) (1-X1) X2 -/ -- (v4(1-u3) + v5 u3) X1 (1-X2) - * \- v3 (1-X1) X2 X3 --/ / - (v6(1-u3) + v7 u3) X1 X2 - * g2 -- v4 X1 (1-X2)(1-X3) --- (v3(1-X3) + v4 X3) X1 (1-X2)-/ / - * \- v5 X1 (1-X2) X3 --/ / - * g3 -- v6 X1 X2 (1-X3) --- (v5(1-X3) + v6 X3) X1 X2 -/ - * \- v7 X1 X2 X3 --/ - * - * TODO: Is it better to avoid copying in the to get the third column? could maybe do by - * just tracking a gap parameter in the for loop, e.g. EDGE_GAP = (1 << i). - * @param challenge - */ - - void fold(size_t round_size, const Fr& challenge) - { - for (size_t j = 0; j < num_polys; ++j) { - for (size_t i = 0; i < round_size; i += 2) { - // old: a0, a1 - // new: (1 - r).a0 + r.a1 - // => r.(a1 - a0) + a0 - folded_polynomials[j][i >> 1] = - folded_polynomials[j][i] + challenge * (folded_polynomials[j][i + 1] - folded_polynomials[j][i]); - } - } - } - - void fold_first_round(size_t round_size, const Fr& challenge) - { - for (size_t j = 0; j < num_polys; ++j) { - for (size_t i = 0; i < round_size; i += 2) { - // old: a0, a1 - // new: (1 - r).a0 + r.a1 - // => r.(a1 - a0) + a0 - folded_polynomials[j][i >> 1] = - full_polynomials[j][i] + challenge * (full_polynomials[j][i + 1] - full_polynomials[j][i]); - } - } - } - - // TODO(cody): Double check edge case here and above. For now, test_fold_1 - // seems to show that the round_size==2 case is handled correctly -}; -} // namespace sumcheck -} // namespace honk diff --git a/barretenberg/cpp/src/aztec/honk/sumcheck/sumcheck_types/multivariates.test.cpp b/barretenberg/cpp/src/aztec/honk/sumcheck/sumcheck_types/multivariates.test.cpp deleted file mode 100644 index e262b15da570..000000000000 --- a/barretenberg/cpp/src/aztec/honk/sumcheck/sumcheck_types/multivariates.test.cpp +++ /dev/null @@ -1,134 +0,0 @@ -#include "./multivariates.hpp" -#include -#include -#include -#include - -#pragma GCC diagnostic ignored "-Wunused-variable" -#pragma GCC diagnostic ignored "-Wunused-parameter" - -using namespace honk::sumcheck; -namespace test_sumcheck_polynomials { - -template class sumcheck_polynomials : public testing::Test { - template - using Multivariates = Multivariates; - - public: - static void test_honk_polys_constructors() - { - const size_t num_polys(4); - const size_t multivariate_d(2); - // const size_t multivariate_n(1 << multivariate_d); - - Fr f0[3] = { 0, 0, 1 }; - Fr f1[3] = { 1, 1, 1 }; - Fr f2[3] = { 3, 4, 1 }; - Fr f3[3] = { -1, -1, 1 }; - - auto full_polynomials = std::array({ f0, f1, f2, f3 }); - auto multivariates = Multivariates(full_polynomials); - - EXPECT_EQ(multivariates.full_polynomials, full_polynomials); - } - - // TODO(cody): rewrite this comment - /* - u2 = 1 ~~> - v01 ------ v11 ~~> - | | ~~> - | Y | ~~> - | | ~~> - v00 ------ v10 ~~> v00 * (1-u2) + v01 * u2 -------- (v11 * u2 + v10 * (1-u2)) - (v01 * (1-X1) + v11 * X1) * X2 ~~> (v00 * (1-u2) + v01 * u2) * (1-X1) - + (v00 * (1-X1) + v10 * X1) * (1-X2) ~~> + (v11 * u2 + v10 * (1-u2)) * X1 - */ - static void test_fold_two() - { - const size_t num_polys(2); - const size_t multivariate_d(1); - const size_t multivariate_n(1 << multivariate_d); - - Fr v00 = Fr::random_element(); - Fr v01 = Fr::random_element(); - Fr v10 = Fr::random_element(); - Fr v11 = Fr::random_element(); - - Fr f0[2] = { v00, v10 }; - Fr f1[2] = { v01, v11 }; - - auto full_polynomials = std::array({ f0, f1 }); - auto multivariates = Multivariates(full_polynomials); - - Fr u2 = Fr::random_element(); - Fr expected_lo = v00 * (Fr(1) - u2) + v10 * u2; - Fr expected_hi = v11 * u2 + v01 * (Fr(1) - u2); - - multivariates.fold_first_round(2, u2); - - EXPECT_EQ(multivariates.folded_polynomials[0][0], expected_lo); - EXPECT_EQ(multivariates.folded_polynomials[1][0], expected_hi); - - Fr u1 = Fr::random_element(); - Fr expected_val = expected_lo * (Fr(1) - u1) + expected_hi * u1; - - multivariates.fold(multivariate_n >> 1, u1); - // Seems the edge case is handled correctly? - EXPECT_EQ(multivariates.folded_polynomials[0][0], expected_val); - } - - // TODO(cody): reinstate this - // /* - // u2 = 1 - // 3 -------- 7 4 -------- 8 ~~> - // | | | | ~~> - // | Y1 | | Y2 | ~~> - // | | | | ~~> - // 1 -------- 5 2 -------- 6 ~~> 3 -------- 7 4 -------- 8 - // (3(1-X1)+7X1) X2 (4(1-X1)+8X1) X2 3(1-X1)+7X1 4(1-X1)+8X1 - // +(1(1-X1)+5X1)(1-X2) +(2(1-X1)+6X1)(1-X2) - // */ - // static void test_fold_2() - // { - // const size_t num_polys(2); - // const size_t multivariate_d(2); - // const size_t multivariate_n(1 << multivariate_d); - - // Edge Y11 = Edge({ 1, 3 }); - // Edge Y12 = Edge({ 5, 7 }); - // Edge Y21 = Edge({ 2, 4 }); - // Edge Y22 = Edge({ 6, 8 }); - - // auto group_1 = EdgeGroup({ Y11, Y21 }); - // auto group_2 = EdgeGroup({ Y12, Y22 }); - - // std::array, multivariate_d> groups{ group_1, group_2 }; - // auto polys = Multivariates(groups); - - // Fr u2 = 1; - // polys.fold(n, u2); - - // EXPECT_EQ(polys.groups[0][0].at(0), 3); - // EXPECT_EQ(polys.groups[0][0].at(1), 7); - - // EXPECT_EQ(polys.groups[0][1].at(0), 4); - // EXPECT_EQ(polys.groups[0][1].at(1), 8); - // } -}; - -typedef testing::Types FieldTypes; -TYPED_TEST_SUITE(sumcheck_polynomials, FieldTypes); - -TYPED_TEST(sumcheck_polynomials, honk_polys_constructor) -{ - TestFixture::test_honk_polys_constructors(); -} -TYPED_TEST(sumcheck_polynomials, fold_2) -{ - TestFixture::test_fold_two(); -} -// TYPED_TEST(sumcheck_polynomials, fold_2) -// { -// TestFixture::test_fold_2(); -// } -} // namespace test_sumcheck_polynomials \ No newline at end of file diff --git a/barretenberg/cpp/src/aztec/honk/sumcheck/sumcheck_types/univariate.test.cpp b/barretenberg/cpp/src/aztec/honk/sumcheck/sumcheck_types/univariate.test.cpp deleted file mode 100644 index ccb2b5c9d655..000000000000 --- a/barretenberg/cpp/src/aztec/honk/sumcheck/sumcheck_types/univariate.test.cpp +++ /dev/null @@ -1,213 +0,0 @@ -#include "./barycentric_data.hpp" -#include "./univariate.hpp" -#include -#include -#include -#include -#include - -#pragma GCC diagnostic ignored "-Wunused-variable" -#pragma GCC diagnostic ignored "-Wunused-parameter" - -using namespace honk::sumcheck; -namespace test_univariate { - -template class UnivariateTests : public testing::Test { - template using UnivariateView = UnivariateView; - - template Univariate random_univariate() - { - auto output = Univariate(); - for (size_t i = 0; i != length; ++i) { - output.value_at(i) = Fr::random_element(); - } - return output; - }; - - public: - static void test_constructors() - { - Fr a0 = Fr::random_element(); - Fr a1 = Fr::random_element(); - Fr a2 = Fr::random_element(); - - Univariate uni({ a0, a1, a2 }); - - EXPECT_EQ(uni.value_at(0), a0); - EXPECT_EQ(uni.value_at(1), a1); - EXPECT_EQ(uni.value_at(2), a2); - } - - static void test_addition() - { - Univariate f1{ { 1, 2 } }; - Univariate f2{ { 3, 4 } }; - // output should be {4, 6} - Univariate expected_result{ { 4, 6 } }; - auto f1f2 = f1 + f2; - EXPECT_EQ(f1f2, expected_result); - } - - static void test_barycentric_data() - { - 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 } }; - Fr u = Fr::random_element(); - Fr 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); - } - - static void test_barycentric_data_extend() - { - 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); - } - - static void test_multiplication() - { - auto barycentric = BarycentricData(); - Univariate f1 = barycentric.extend(Univariate{ { 1, 2 } }); - Univariate f2 = barycentric.extend(Univariate{ { 3, 4 } }); - // output should be {3, 8, 15} - Univariate expected_result{ { 3, 8, 15 } }; - Univariate f1f2 = f1 * f2; - EXPECT_EQ(f1f2, expected_result); - } - - static void test_construct_univariate_view_from_univariate() - { - Univariate f{ { 1, 2, 3 } }; - UnivariateView<2> g(f); - EXPECT_EQ(g.value_at(0), f.value_at(0)); - EXPECT_EQ(g.value_at(1), f.value_at(1)); - } - - static void test_construct_univariate_from_univariate_view() - { - Univariate f{ { 1, 2, 3 } }; - UnivariateView<2> g(f); - Univariate h(g); - EXPECT_EQ(h.value_at(0), g.value_at(0)); - EXPECT_EQ(h.value_at(1), g.value_at(1)); - } - - static void test_univariate_view_addition() - { - Univariate f1{ { 1, 2, 3 } }; - Univariate f2{ { 3, 4, 3 } }; - - UnivariateView<2> g1(f1); - UnivariateView<2> g2(f2); - - Univariate expected_result{ { 4, 6 } }; - Univariate result = g1 + g2; - EXPECT_EQ(result, expected_result); - - Univariate result2 = result + g1; - Univariate expected_result2{ { 5, 8 } }; - EXPECT_EQ(result2, expected_result2); - } - static void test_univariate_view_subtraction() - { - Univariate f1{ { 1, 2, 3 } }; - Univariate f2{ { 3, 4, 3 } }; - - UnivariateView<2> g1(f1); - UnivariateView<2> g2(f2); - - Univariate expected_result{ { -2, -2 } }; - Univariate result = g1 - g2; - EXPECT_EQ(result, expected_result); - - Univariate result2 = result - g1; - Univariate expected_result2{ { -3, -4 } }; - EXPECT_EQ(result2, expected_result2); - } - - static void test_univariate_view_multiplication() - { - Univariate f1{ { 1, 2, 3 } }; - Univariate f2{ { 3, 4, 3 } }; - - UnivariateView<2> g1(f1); - UnivariateView<2> g2(f2); - - Univariate expected_result{ { 3, 8 } }; - Univariate result = g1 * g2; - EXPECT_EQ(result, expected_result); - - Univariate result2 = result * g1; - Univariate expected_result2{ { 3, 16 } }; - EXPECT_EQ(result2, expected_result2); - } -}; - -using FieldTypes = testing::Types; -TYPED_TEST_SUITE(UnivariateTests, FieldTypes); - -TYPED_TEST(UnivariateTests, Constructors) -{ - TestFixture::test_constructors(); -} -TYPED_TEST(UnivariateTests, Addition) -{ - TestFixture::test_addition(); -} -TYPED_TEST(UnivariateTests, UnivariateToView) -{ - TestFixture::test_construct_univariate_from_univariate_view(); -} -TYPED_TEST(UnivariateTests, ViewToUnivariate) -{ - TestFixture::test_construct_univariate_view_from_univariate(); -} -TYPED_TEST(UnivariateTests, ViewAddition) -{ - TestFixture::test_univariate_view_addition(); -} -TYPED_TEST(UnivariateTests, ViewMultiplication) -{ - TestFixture::test_univariate_view_subtraction(); -} -TYPED_TEST(UnivariateTests, ViewSubtraction) -{ - TestFixture::test_univariate_view_multiplication(); -} -TYPED_TEST(UnivariateTests, BarycentricData) -{ - TestFixture::test_barycentric_data(); -} -TYPED_TEST(UnivariateTests, BarycentricDataExtend) -{ - TestFixture::test_barycentric_data_extend(); -} -TYPED_TEST(UnivariateTests, Multiplication) -{ - TestFixture::test_multiplication(); -} -} // namespace test_univariate diff --git a/barretenberg/cpp/src/aztec/honk/sumcheck/transcript.hpp b/barretenberg/cpp/src/aztec/honk/sumcheck/transcript.hpp index b1158172c3c0..f1d107127578 100644 --- a/barretenberg/cpp/src/aztec/honk/sumcheck/transcript.hpp +++ b/barretenberg/cpp/src/aztec/honk/sumcheck/transcript.hpp @@ -1,10 +1,13 @@ #pragma once + +#pragma GCC diagnostic ignored "-Wunused-variable" +#pragma GCC diagnostic ignored "-Wunused-parameter" + namespace honk { template class Transcript { public: - // Fr add() // data to the transcript + template void add(Frs... field_elements){}; // TODO(Cody): implementation Fr get_challenge() { return Fr::random_element(); }; Fr get_challenge_equals_one() { return Fr::one(); }; - // std::array<...> data }; }; // namespace honk