diff --git a/barretenberg/cpp/src/barretenberg/flavor/flavor.hpp b/barretenberg/cpp/src/barretenberg/flavor/flavor.hpp index 7a37e57d6c16..7f044f495e07 100644 --- a/barretenberg/cpp/src/barretenberg/flavor/flavor.hpp +++ b/barretenberg/cpp/src/barretenberg/flavor/flavor.hpp @@ -15,7 +15,7 @@ * relationships between these. We aim for a more uniform treatment, to enfore identical and informative naming, and to * prevent the developer having to think very much about the ordering of protocol entities in disparate places. * - * Another motivation is iterate on the polynomial manifest of plonk, which is nice in its compatness, but which feels + * Another motivation is iterate on the polynomial manifest of plonk, which is nice in its compactness, but which feels * needlessly manual and low-level. In the past, this contained even more boolean parameters, making it quite hard to * parse. A typical construction is to loop over the polynomial manifest by extracting a globally-defined * "FOO_MANIFEST_SIZE" (the use of "manifest" here is distinct from the manifests in the transcript) to loop diff --git a/barretenberg/cpp/src/barretenberg/honk/proof_system/barycentric.py b/barretenberg/cpp/src/barretenberg/honk/proof_system/barycentric.py new file mode 100644 index 000000000000..b4f7d3e6c5b8 --- /dev/null +++ b/barretenberg/cpp/src/barretenberg/honk/proof_system/barycentric.py @@ -0,0 +1,44 @@ +import numpy as np + + +def get_A_at_z(z, xs): + result = 1 + for x in xs: + result *= (z - x) + return result + +def get_A_deriv(i, xs): + result = 1 + xi = xs[i] + for j in range(len(xs)): + if j != i: + result *= (xi - xs[j]) + return result + + + +points = [2,3] +evals = [2, 3] + +z = 5 + +result = get_A_at_z(z, points) +s = 0 +for i in range(len(evals)): + s += evals[i] / ((z - points[i])* get_A_deriv(i, points)) +result *= s +print(result) + +points = [32, 33, 34, 35, 36] +evals = [1,11,111,1111,11111] + +z = 2 + +result = get_A_at_z(z, points) +s = 0 +for i in range(len(evals)): + s += evals[i] / ((z - points[i])* get_A_deriv(i, points)) +result *= s +print(result) + + diff --git a/barretenberg/cpp/src/barretenberg/polynomials/barycentric.hpp b/barretenberg/cpp/src/barretenberg/polynomials/barycentric.hpp index a8ddb6d30d34..27cd1c8631ba 100644 --- a/barretenberg/cpp/src/barretenberg/polynomials/barycentric.hpp +++ b/barretenberg/cpp/src/barretenberg/polynomials/barycentric.hpp @@ -20,22 +20,25 @@ namespace barretenberg { /** * @todo: TODO(https://github.com/AztecProtocol/barretenberg/issues/713) Optimize with lookup tables? + * @tparam domain_end, domain_start specify the given evaluation domain {domain_start,..., domain_end - 1} + * @tparam num_evals the number of evaluations that are computable with specific barycentric extension formula */ -template class BarycentricDataCompileTime { +template class BarycentricDataCompileTime { public: + static constexpr size_t domain_size = domain_end - domain_start; static constexpr size_t big_domain_size = std::max(domain_size, num_evals); /** * Static constexpr methods for computing arrays of precomputable data used for barycentric extension and evaluation */ - // build big_domain, currently the set of x_i in {0, 1, ..., t-1} + // build big_domain, currently the set of x_i in {domain_start, ..., big_domain_end - 1 } static constexpr std::array construct_big_domain() { std::array result; for (size_t i = 0; i < big_domain_size; ++i) { - result[i] = static_cast(i); + result[i] = static_cast(i + domain_start); } return result; } @@ -109,7 +112,7 @@ template class BarycentricDataC std::array result; for (size_t i = 0; i != num_evals; ++i) { result[i] = 1; - Fr v_i = i; + Fr v_i = i + domain_start; for (size_t j = 0; j != domain_size; ++j) { result[i] *= v_i - big_domain[j]; } @@ -124,20 +127,21 @@ template class BarycentricDataC static constexpr auto full_numerator_values = construct_full_numerator_values(big_domain); }; -template class BarycentricDataRunTime { +template class BarycentricDataRunTime { public: + static constexpr size_t domain_size = domain_end - domain_start; static constexpr size_t big_domain_size = std::max(domain_size, num_evals); /** * Static constexpr methods for computing arrays of precomputable data used for barycentric extension and evaluation */ - // build big_domain, currently the set of x_i in {0, 1, ..., t-1} + // build big_domain, currently the set of x_i in {domain_start, ..., big_domain_end - 1 } static std::array construct_big_domain() { std::array result; for (size_t i = 0; i < big_domain_size; ++i) { - result[i] = static_cast(i); + result[i] = static_cast(i + domain_start); } return result; } @@ -210,7 +214,7 @@ template class BarycentricDataR std::array result; for (size_t i = 0; i != num_evals; ++i) { result[i] = 1; - Fr v_i = i; + Fr v_i = i + domain_start; for (size_t j = 0; j != domain_size; ++j) { result[i] *= v_i - big_domain[j]; } @@ -247,9 +251,9 @@ template inline constexpr bool is_field_type_v = is_field_type:: * @tparam domain_size * @tparam num_evals */ -template +template using BarycentricData = std::conditional_t, - BarycentricDataCompileTime, - BarycentricDataRunTime>; + BarycentricDataCompileTime, + BarycentricDataRunTime>; } // namespace barretenberg diff --git a/barretenberg/cpp/src/barretenberg/polynomials/univariate.hpp b/barretenberg/cpp/src/barretenberg/polynomials/univariate.hpp index 6cd154ba0ed7..138917654bc7 100644 --- a/barretenberg/cpp/src/barretenberg/polynomials/univariate.hpp +++ b/barretenberg/cpp/src/barretenberg/polynomials/univariate.hpp @@ -13,22 +13,24 @@ namespace barretenberg { * of the data in those univariates. We do that by taking a view of those elements and then, as needed, using this to * populate new containers. */ -template class UnivariateView; +template class UnivariateView; /** - * @brief A univariate polynomial represented by its values on {0,1,..., _length-1} + * @brief A univariate polynomial represented by its values on {domain_start, domain_start + 1,..., domain_end - 1}. For + * memory efficiency purposes, we store the evaluations in an array starting from 0 and make the mapping to the right + * domain under the hood. */ -template class Univariate { +template class Univariate { public: - static constexpr size_t LENGTH = _length; - using View = UnivariateView; + static constexpr size_t LENGTH = domain_end - domain_start; + using View = UnivariateView; // TODO(https://github.com/AztecProtocol/barretenberg/issues/714) Try out std::valarray? - std::array evaluations; + std::array evaluations; Univariate() = default; - explicit Univariate(std::array evaluations) + explicit Univariate(std::array evaluations) : evaluations(evaluations) {} ~Univariate() = default; @@ -40,12 +42,12 @@ template class Univariate { explicit Univariate(Fr value) : evaluations{} { - for (size_t i = 0; i < _length; ++i) { + for (size_t i = 0; i < LENGTH; ++i) { evaluations[i] = value; } } // Construct Univariate from UnivariateView - explicit Univariate(UnivariateView in) + explicit Univariate(UnivariateView in) : evaluations{} { for (size_t i = 0; i < in.evaluations.size(); ++i) { @@ -53,8 +55,9 @@ template class Univariate { } } - Fr& value_at(size_t i) { return evaluations[i]; }; - const Fr& value_at(size_t i) const { return evaluations[i]; }; + Fr& value_at(size_t i) { return evaluations[i - domain_start]; }; + const Fr& value_at(size_t i) const { return evaluations[i - domain_start]; }; + size_t size() { return evaluations.size(); }; // Write the Univariate evaluations to a buffer std::vector to_buffer() const { return ::to_buffer(evaluations); } @@ -71,8 +74,8 @@ template class Univariate { static Univariate get_random() { - auto output = Univariate(); - for (size_t i = 0; i != _length; ++i) { + auto output = Univariate(); + for (size_t i = 0; i != LENGTH; ++i) { output.value_at(i) = Fr::random_element(); } return output; @@ -85,21 +88,21 @@ template class Univariate { Univariate& operator+=(const Univariate& other) { - for (size_t i = 0; i < _length; ++i) { + for (size_t i = 0; i < LENGTH; ++i) { evaluations[i] += other.evaluations[i]; } return *this; } Univariate& operator-=(const Univariate& other) { - for (size_t i = 0; i < _length; ++i) { + for (size_t i = 0; i < LENGTH; ++i) { evaluations[i] -= other.evaluations[i]; } return *this; } Univariate& operator*=(const Univariate& other) { - for (size_t i = 0; i < _length; ++i) { + for (size_t i = 0; i < LENGTH; ++i) { evaluations[i] *= other.evaluations[i]; } return *this; @@ -179,45 +182,45 @@ template class Univariate { } // Operations between Univariate and UnivariateView - Univariate& operator+=(const UnivariateView& view) + Univariate& operator+=(const UnivariateView& view) { - for (size_t i = 0; i < _length; ++i) { + for (size_t i = 0; i < LENGTH; ++i) { evaluations[i] += view.evaluations[i]; } return *this; } - Univariate& operator-=(const UnivariateView& view) + Univariate& operator-=(const UnivariateView& view) { - for (size_t i = 0; i < _length; ++i) { + for (size_t i = 0; i < LENGTH; ++i) { evaluations[i] -= view.evaluations[i]; } return *this; } - Univariate& operator*=(const UnivariateView& view) + Univariate& operator*=(const UnivariateView& view) { - for (size_t i = 0; i < _length; ++i) { + for (size_t i = 0; i < LENGTH; ++i) { evaluations[i] *= view.evaluations[i]; } return *this; } - Univariate operator+(const UnivariateView& view) const + Univariate operator+(const UnivariateView& view) const { Univariate res(*this); res += view; return res; } - Univariate operator-(const UnivariateView& view) const + Univariate operator-(const UnivariateView& view) const { Univariate res(*this); res -= view; return res; } - Univariate operator*(const UnivariateView& view) const + Univariate operator*(const UnivariateView& view) const { Univariate res(*this); res *= view; @@ -241,22 +244,24 @@ template class Univariate { } /** - * @brief Given a univariate f represented by {f(0), ..., f(t-1)}, compute {f(t), ..., f(u-1)} - * and return the Univariate represented by {f(0), ..., f(u-1)}. + * @brief Given a univariate f represented by {f(domain_start), ..., f(domain_end - 1)}, compute the evaluations + * {f(domain_end),..., f(extended_domain_end -1)} and return the Univariate represented by {f(domain_start),..., + * f(extended_domain_end -1)} * - * @details Write v_i = f(x_i) on a the domain {x_0, ..., x_{t-1}}. To efficiently compute the needed values of f, - * we use the barycentric formula - * - f(x) = B(x) Σ_{i=0}^{t-1} v_i / (d_i*(x-x_i)) + * @details Write v_i = f(x_i) on a the domain {x_{domain_start}, ..., x_{domain_end-1}}. To efficiently compute the + * needed values of f, we use the barycentric formula + * - f(x) = B(x) Σ_{i=domain_start}^{domain_end-1} v_i / (d_i*(x-x_i)) * where - * - B(x) = Π_{i=0}^{t-1} (x-x_i) - * - d_i = Π_{j ∈ {0, ..., t-1}, j≠i} (x_i-x_j) for i ∈ {0, ..., t-1} + * - B(x) = Π_{i=domain_start}^{domain_end-1} (x-x_i) + * - d_i = Π_{j ∈ {domain_start, ..., domain_end-1}, j≠i} (x_i-x_j) for i ∈ {domain_start, ..., domain_end-1} * * When the domain size is two, extending f = v0(1-X) + v1X to a new value involves just one addition and a * subtraction: setting Δ = v1-v0, the values of f(X) are f(0)=v0, f(1)= v0 + Δ, v2 = f(1) + Δ, v3 = f(2) + Δ... * */ - template Univariate extend_to() const + template Univariate extend_to() const { + const size_t EXTENDED_LENGTH = EXTENDED_DOMAIN_END - domain_start; using Data = BarycentricData; static_assert(EXTENDED_LENGTH >= LENGTH); @@ -267,15 +272,15 @@ template class Univariate { if constexpr (LENGTH == 2) { Fr delta = value_at(1) - value_at(0); static_assert(EXTENDED_LENGTH != 0); - for (size_t idx = 1; idx < EXTENDED_LENGTH - 1; idx++) { + for (size_t idx = domain_start; idx < EXTENDED_DOMAIN_END - 1; idx++) { result.value_at(idx + 1) = result.value_at(idx) + delta; } return result; } else { - for (size_t k = LENGTH; k != EXTENDED_LENGTH; ++k) { + for (size_t k = domain_end; k != EXTENDED_DOMAIN_END; ++k) { result.value_at(k) = 0; // compute each term v_j / (d_j*(x-x_j)) of the sum - for (size_t j = 0; j != LENGTH; ++j) { + for (size_t j = domain_start; j != domain_end; ++j) { Fr term = value_at(j); term *= Data::precomputed_denominator_inverses[LENGTH * k + j]; result.value_at(k) += term; @@ -295,9 +300,9 @@ template class Univariate { */ Fr evaluate(const Fr& u) { - using Data = BarycentricData; + using Data = BarycentricData; Fr full_numerator_value = 1; - for (size_t i = 0; i != LENGTH; ++i) { + for (size_t i = domain_start; i != domain_end; ++i) { full_numerator_value *= u - i; } @@ -313,9 +318,9 @@ template class Univariate { Fr result = 0; // compute each term v_j / (d_j*(x-x_j)) of the sum - for (size_t i = 0; i != LENGTH; ++i) { + for (size_t i = domain_start; i != domain_end; ++i) { Fr term = value_at(i); - term *= denominator_inverses[i]; + term *= denominator_inverses[i - domain_start]; result += term; } // scale the sum by the the value of of B(x) @@ -324,98 +329,101 @@ template class Univariate { }; }; -template inline void read(B& it, Univariate& univariate) +template +inline void read(B& it, Univariate& univariate) { using serialize::read; read(it, univariate.evaluations); } -template inline void write(B& it, Univariate const& univariate) +template +inline void write(B& it, Univariate const& univariate) { using serialize::write; write(it, univariate.evaluations); } -template class UnivariateView { +template class UnivariateView { public: - std::span evaluations; + static constexpr size_t LENGTH = domain_end - domain_start; + std::span evaluations; UnivariateView() = default; const Fr& value_at(size_t i) const { return evaluations[i]; }; - template - explicit UnivariateView(const Univariate& univariate_in) - : evaluations(std::span(univariate_in.evaluations.data(), view_length)){}; + template + explicit UnivariateView(const Univariate& univariate_in) + : evaluations(std::span(univariate_in.evaluations.data(), LENGTH)){}; - Univariate operator+(const UnivariateView& other) const + Univariate operator+(const UnivariateView& other) const { - Univariate res(*this); + Univariate res(*this); res += other; return res; } - Univariate operator-(const UnivariateView& other) const + Univariate operator-(const UnivariateView& other) const { - Univariate res(*this); + Univariate res(*this); res -= other; return res; } - Univariate operator-() const + Univariate operator-() const { - Univariate res(*this); + Univariate res(*this); for (auto& eval : res.evaluations) { eval = -eval; } return res; } - Univariate operator*(const UnivariateView& other) const + Univariate operator*(const UnivariateView& other) const { - Univariate res(*this); + Univariate res(*this); res *= other; return res; } - Univariate operator*(const Univariate& other) const + Univariate operator*(const Univariate& other) const { - Univariate res(*this); + Univariate res(*this); res *= other; return res; } - Univariate operator+(const Univariate& other) const + Univariate operator+(const Univariate& other) const { - Univariate res(*this); + Univariate res(*this); res += other; return res; } - Univariate operator+(const Fr& other) const + Univariate operator+(const Fr& other) const { - Univariate res(*this); + Univariate res(*this); res += other; return res; } - Univariate operator-(const Fr& other) const + Univariate operator-(const Fr& other) const { - Univariate res(*this); + Univariate res(*this); res -= other; return res; } - Univariate operator*(const Fr& other) const + Univariate operator*(const Fr& other) const { - Univariate res(*this); + Univariate res(*this); res *= other; return res; } - Univariate operator-(const Univariate& other) const + Univariate operator-(const Univariate& other) const { - Univariate res(*this); + Univariate res(*this); res -= other; return res; } diff --git a/barretenberg/cpp/src/barretenberg/polynomials/univariate.test.cpp b/barretenberg/cpp/src/barretenberg/polynomials/univariate.test.cpp index 5138a51167ad..238470370a39 100644 --- a/barretenberg/cpp/src/barretenberg/polynomials/univariate.test.cpp +++ b/barretenberg/cpp/src/barretenberg/polynomials/univariate.test.cpp @@ -158,4 +158,19 @@ TYPED_TEST(UnivariateTest, Serialization) } } +TYPED_TEST(UnivariateTest, EvaluationCustomDomain) +{ + UNIVARIATE_TESTS_ALIASES + + []() { + auto poly = Univariate(std::array{ 1, 2 }); + EXPECT_EQ(poly.evaluate(FF(5)), FF(5)); + }(); + + []() { + auto poly = Univariate(std::array{ 1, 11, 111, 1111, 11111 }); + EXPECT_EQ(poly.evaluate(FF(2)), FF(294330751)); + }(); +} + } // namespace barretenberg::test_univariate diff --git a/barretenberg/cpp/src/barretenberg/protogalaxy/combiner.test.cpp b/barretenberg/cpp/src/barretenberg/protogalaxy/combiner.test.cpp index 3cdc96707d1b..162e6cba68bf 100644 --- a/barretenberg/cpp/src/barretenberg/protogalaxy/combiner.test.cpp +++ b/barretenberg/cpp/src/barretenberg/protogalaxy/combiner.test.cpp @@ -35,7 +35,7 @@ TEST(Protogalaxy, CombinerOn2Instances) std::vector> instance_data(NUM_INSTANCES); std::array, NUM_INSTANCES> storage_arrays; ProtoGalaxyProver prover; - auto pow_univariate = PowUnivariate(/*zeta_pow=*/2); + std::vector pow_betas = { FF(1), FF(2) }; auto alpha = FF(0); // focus on the arithmetic relation only for (size_t idx = 0; idx < NUM_INSTANCES; idx++) { @@ -50,27 +50,27 @@ TEST(Protogalaxy, CombinerOn2Instances) ProverInstances instances{ instance_data }; - auto result = prover.compute_combiner(instances, pow_univariate, alpha); + auto result = prover.compute_combiner(instances, pow_betas, alpha); auto expected_result = barretenberg::Univariate(std::array{ 87706, - 27289140, - 229355214, - 905031784, - static_cast(2504059650), - static_cast(5627174556), - static_cast(11026107190), - static_cast(19603583184), - static_cast(32413323114), - static_cast(50660042500), - static_cast(75699451806), - static_cast(109038256440), - static_cast(152334156754) }); + 13644570, + 76451738, + 226257946, + static_cast(500811930), + static_cast(937862426), + static_cast(1575158170), + static_cast(2450447898), + static_cast(3601480346), + static_cast(5066004250), + static_cast(6881768346), + static_cast(9086521370), + static_cast(11718012058) }); EXPECT_EQ(result, expected_result); } else { std::vector> instance_data(NUM_INSTANCES); std::array, NUM_INSTANCES> storage_arrays; ProtoGalaxyProver prover; - auto pow_univariate = PowUnivariate(/*zeta_pow=*/2); + std::vector pow_betas = { FF(1), FF(2) }; auto alpha = FF(0); // focus on the arithmetic relation only for (size_t idx = 0; idx < NUM_INSTANCES; idx++) { @@ -129,9 +129,10 @@ TEST(Protogalaxy, CombinerOn2Instances) relation value: 0 0 0 0 0 0 0 0 0 6 18 36 60 90 */ - auto result = prover.compute_combiner(instances, pow_univariate, alpha); + auto result = prover.compute_combiner(instances, pow_betas, alpha); auto expected_result = barretenberg::Univariate( - std::array{ 0, 0, 36, 144, 360, 720, 1260, 2016, 3024, 4320, 5940, 7920, 10296 }); + std::array{ 0, 0, 12, 36, 72, 120, 180, 252, 336, 432, 540, 660, 792 }); + EXPECT_EQ(result, expected_result); } }; @@ -161,8 +162,8 @@ TEST(Protogalaxy, CombinerOn4Instances) std::vector> instance_data(NUM_INSTANCES); std::array, NUM_INSTANCES> storage_arrays; ProtoGalaxyProver prover; - auto pow_univariate = PowUnivariate(/*zeta_pow=*/2); auto alpha = FF(0); // focus on the arithmetic relation only + std::vector pow_betas = { FF(1), FF(2) }; for (size_t idx = 0; idx < NUM_INSTANCES; idx++) { auto instance = std::make_shared(); @@ -180,7 +181,7 @@ TEST(Protogalaxy, CombinerOn4Instances) zero_all_selectors(instances[2]->prover_polynomials); zero_all_selectors(instances[3]->prover_polynomials); - auto result = prover.compute_combiner(instances, pow_univariate, alpha); + auto result = prover.compute_combiner(instances, pow_betas, alpha); std::array zeroes; std::fill(zeroes.begin(), zeroes.end(), 0); auto expected_result = barretenberg::Univariate(zeroes); diff --git a/barretenberg/cpp/src/barretenberg/protogalaxy/combiner_example_gen.py b/barretenberg/cpp/src/barretenberg/protogalaxy/combiner_example_gen.py index e222d8e9033c..906d1948847b 100644 --- a/barretenberg/cpp/src/barretenberg/protogalaxy/combiner_example_gen.py +++ b/barretenberg/cpp/src/barretenberg/protogalaxy/combiner_example_gen.py @@ -86,7 +86,7 @@ def get_extended_univariates(instances, row_idx): result = [row.entities[entity_idx] for row in rows] result = np.array(extend_one_entity(result)) return result - + def compute_first_example(): i0 = Instance([Row(0), Row(1)]) i1 = Instance([Row(128), Row(129)]) @@ -104,7 +104,6 @@ def compute_first_example(): accumulator += zeta_pow * relation_value zeta_pow *= zeta - accumulator *= extend_one_entity([1, 2]) return accumulator @@ -134,7 +133,6 @@ def compute_second_example(): result += rel(w_l, w_r, w_o, q_m, q_l, q_r, q_o, q_c) result *= 2 - result *= extend_one_entity([1, 2]) return result if __name__ == "__main__": diff --git a/barretenberg/cpp/src/barretenberg/protogalaxy/folding_result.hpp b/barretenberg/cpp/src/barretenberg/protogalaxy/folding_result.hpp index 1d177e252aa3..61118b8b6e14 100644 --- a/barretenberg/cpp/src/barretenberg/protogalaxy/folding_result.hpp +++ b/barretenberg/cpp/src/barretenberg/protogalaxy/folding_result.hpp @@ -17,7 +17,7 @@ template struct VerifierFoldingResult { using VerificationKey = typename Flavor::VerificationKey; using FoldingParameters = typename Flavor::FoldingParameters; std::vector folded_public_inputs; - VerificationKey folded_verification_key; + std::shared_ptr folded_verification_key; FoldingParameters parameters; }; diff --git a/barretenberg/cpp/src/barretenberg/protogalaxy/protogalaxy_prover.cpp b/barretenberg/cpp/src/barretenberg/protogalaxy/protogalaxy_prover.cpp index f9c3f8398672..74b7ae2245b9 100644 --- a/barretenberg/cpp/src/barretenberg/protogalaxy/protogalaxy_prover.cpp +++ b/barretenberg/cpp/src/barretenberg/protogalaxy/protogalaxy_prover.cpp @@ -4,7 +4,6 @@ namespace proof_system::honk { template void ProtoGalaxyProver_::prepare_for_folding() { - // this doesnt work in the current format auto idx = 0; for (auto it = instances.begin(); it != instances.end(); it++, idx++) { auto instance = *it; @@ -24,8 +23,6 @@ template void ProtoGalaxyProver_::prepa transcript.send_to_verifier(domain_separator + "_public_input_" + std::to_string(i), public_input_i); } - // TODO(https://github.com/AztecProtocol/barretenberg/issues/752): establish whether we can use the same grand - // product parameters for all instances securely auto [eta, beta, gamma] = transcript.get_challenges( domain_separator + "_eta", domain_separator + "_beta", domain_separator + "_gamma"); instance->compute_sorted_accumulator_polynomials(eta); @@ -42,18 +39,47 @@ ProverFoldingResult ProtoGalaxyProver_prover_polynomials.get_polynomial_size(); - auto log_instance_size = static_cast(numeric::get_msb(instance_size)); + const auto log_instance_size = static_cast(numeric::get_msb(instance_size)); auto deltas = compute_round_challenge_pows(log_instance_size, delta); - auto perturbator = compute_perturbator(accumulator, deltas, alpha); + auto perturbator = compute_perturbator(accumulator, deltas, alpha); for (size_t idx = 0; idx <= log_instance_size; idx++) { transcript.send_to_verifier("perturbator_" + std::to_string(idx), perturbator[idx]); } + auto perturbator_challenge = transcript.get_challenge("perturbator_challenge"); + auto compressed_perturbator = perturbator.evaluate(perturbator_challenge); + std::vector betas_star(log_instance_size); + betas_star[0] = 1; + auto betas = accumulator->folding_parameters.gate_separation_challenges; + for (size_t idx = 1; idx < log_instance_size; idx++) { + betas_star[idx] = betas[idx] + perturbator_challenge * deltas[idx - 1]; + } + + auto pow_betas_star = compute_pow_polynomial_at_values(betas_star, instance_size); + + auto combiner = compute_combiner(instances, pow_betas_star, alpha); + auto combiner_quotient = compute_combiner_quotient(compressed_perturbator, combiner); + for (size_t idx = ProverInstances::NUM; idx < combiner.size(); idx++) { + transcript.send_to_verifier("combiner_quotient_" + std::to_string(idx), combiner_quotient.value_at(idx)); + } + auto combiner_challenge = transcript.get_challenge("combiner_quotient_challenge"); + auto combiner_quotient_at_challenge = combiner_quotient.evaluate(combiner_challenge); + + // TODO(https://github.com/AztecProtocol/barretenberg/issues/764): Generalise these formulas as well as computation + // of Lagrange basis + auto vanishing_polynomial_at_challenge = combiner_challenge * (combiner_challenge - FF(1)); + auto lagrange_0_at_challenge = FF(1) - combiner_challenge; + + auto new_target_sum = compressed_perturbator * lagrange_0_at_challenge + + vanishing_polynomial_at_challenge * combiner_quotient_at_challenge; + ProverFoldingResult res; + res.params.target_sum = new_target_sum; res.folding_data = transcript.proof_data; return res; } diff --git a/barretenberg/cpp/src/barretenberg/protogalaxy/protogalaxy_prover.hpp b/barretenberg/cpp/src/barretenberg/protogalaxy/protogalaxy_prover.hpp index 69329e6b82bd..304b031e8b30 100644 --- a/barretenberg/cpp/src/barretenberg/protogalaxy/protogalaxy_prover.hpp +++ b/barretenberg/cpp/src/barretenberg/protogalaxy/protogalaxy_prover.hpp @@ -51,6 +51,24 @@ template class ProtoGalaxyProver_ { */ void prepare_for_folding(); + /** + * @brief Given a vector \vec{\beta} of values, compute the pow polynomial on these values as defined in the paper. + */ + static std::vector compute_pow_polynomial_at_values(const std::vector& betas, const size_t instance_size) + { + std::vector pow_betas(instance_size); + for (size_t i = 0; i < instance_size; i++) { + auto res = FF(1); + for (size_t j = i, beta_idx = 0; j > 0; j >>= 1, beta_idx++) { + if ((j & 1) == 1) { + res *= betas[beta_idx]; + } + } + pow_betas[i] = res; + } + return pow_betas; + } + /** * @brief For a new round challenge δ at each iteration of the ProtoGalaxy protocol, compute the vector * [δ, δ^2,..., δ^t] where t = logn and n is the size of the instance. @@ -218,21 +236,12 @@ template class ProtoGalaxyProver_ { /** * @brief Compute the combiner polynomial $G$ in the Protogalaxy paper. * - * @todo TODO(https://github.com/AztecProtocol/barretenberg/issues/754) Provide the right challenge to here */ ExtendedUnivariateWithRandomization compute_combiner(const ProverInstances& instances, - const PowUnivariate& pow_univariate, - const typename Flavor::FF alpha) + const std::vector& pow_betas_star, + const FF& alpha) { size_t common_circuit_size = instances[0]->prover_polynomials._data[0].size(); - // Precompute the vector of required powers of zeta - // TODO(https://github.com/AztecProtocol/barretenberg/issues/751): Parallelize this. - // NB: there is a similar TODO in the sumcheck function `compute_univariate`. - std::vector pow_challenges(common_circuit_size); - pow_challenges[0] = pow_univariate.partial_evaluation_constant; - for (size_t i = 1; i < common_circuit_size; ++i) { - pow_challenges[i] = pow_challenges[i - 1] * pow_univariate.zeta_pow; - } // Determine number of threads for multithreading. // Note: Multithreading is "on" for every round but we reduce the number of threads from the max available based @@ -263,7 +272,7 @@ template class ProtoGalaxyProver_ { for (size_t idx = start; idx < end; idx++) { extend_univariates(extended_univariates[thread_idx], instances, idx); - FF pow_challenge = pow_challenges[idx]; + FF pow_challenge = pow_betas_star[idx]; // Accumulate the i-th row's univariate contribution. Note that the relation parameters passed to this // function have already been folded @@ -280,8 +289,41 @@ template class ProtoGalaxyProver_ { Utils::add_nested_tuples(univariate_accumulators, accumulators); } // Batch the univariate contributions from each sub-relation to obtain the round univariate - return Utils::template batch_over_relations( - univariate_accumulators, alpha, pow_univariate); + return Utils::template batch_over_relations(univariate_accumulators, + alpha); + } + + /** + * @brief Compute the combiner quotient defined as $K$ polynomial in the paper. + * + * TODO(https://github.com/AztecProtocol/barretenberg/issues/764): generalise the computation of vanishing + * polynomials and Lagrange basis and use batch_invert. + * + */ + static Univariate + compute_combiner_quotient(FF compressed_perturbator, ExtendedUnivariateWithRandomization combiner) + { + std::array + combiner_quotient_evals = {}; + + // Compute the combiner quotient polynomial as evaluations on points that are not in the vanishing set. + // + for (size_t point = ProverInstances::NUM; point < combiner.size(); point++) { + auto idx = point - ProverInstances::NUM; + auto lagrange_0 = FF(1) - FF(point); + auto vanishing_polynomial = FF(point) * (FF(point) - 1); + + combiner_quotient_evals[idx] = + (combiner.value_at(point) - compressed_perturbator * lagrange_0) * vanishing_polynomial.invert(); + } + + Univariate + combiner_quotient(combiner_quotient_evals); + return combiner_quotient; } /** diff --git a/barretenberg/cpp/src/barretenberg/protogalaxy/protogalaxy_verifier.cpp b/barretenberg/cpp/src/barretenberg/protogalaxy/protogalaxy_verifier.cpp index 8bbc6a6ded94..321c50a1ed6d 100644 --- a/barretenberg/cpp/src/barretenberg/protogalaxy/protogalaxy_verifier.cpp +++ b/barretenberg/cpp/src/barretenberg/protogalaxy/protogalaxy_verifier.cpp @@ -1,9 +1,9 @@ #include "protogalaxy_verifier.hpp" #include "barretenberg/proof_system/library/grand_product_delta.hpp" namespace proof_system::honk { + template -VerifierFoldingResult ProtoGalaxyVerifier_< - VerifierInstances>::fold_public_parameters(std::vector fold_data) +void ProtoGalaxyVerifier_::prepare_for_folding(std::vector fold_data) { transcript = BaseTranscript{ fold_data }; auto index = 0; @@ -29,19 +29,49 @@ VerifierFoldingResult ProtoGalaxyVerifier_< inst->relation_parameters = RelationParameters{ eta, beta, gamma, public_input_delta, lookup_grand_product_delta }; } +} - auto [alpha, delta] = - transcript.get_challenges("alpha", "delta"); // what does verifier do with this alpha which is from plonk paper? +template +VerifierFoldingResult ProtoGalaxyVerifier_< + VerifierInstances>::fold_public_parameters(std::vector fold_data) +{ + using Flavor = typename VerifierInstances::Flavor; + + prepare_for_folding(fold_data); + auto [alpha, delta] = transcript.get_challenges("alpha", "delta"); auto accumulator = get_accumulator(); auto log_instance_size = static_cast(numeric::get_msb(accumulator->instance_size)); auto deltas = compute_round_challenge_pows(log_instance_size, delta); - std::vector perturbator(log_instance_size + 1); + std::vector perturbator_coeffs(log_instance_size + 1); for (size_t idx = 0; idx <= log_instance_size; idx++) { - perturbator[idx] = transcript.template receive_from_prover("perturbator_" + std::to_string(idx)); + perturbator_coeffs[idx] = transcript.template receive_from_prover("perturbator_" + std::to_string(idx)); + } + auto perturbator = Polynomial(perturbator_coeffs); + auto perturbator_challenge = transcript.get_challenge("perturbator_challenge"); + auto perturbator_at_challenge = perturbator.evaluate(perturbator_challenge); + + // Thed degree of K(X) is dk - k - 1 = k(d - 1) - 1. Hence we need k(d - 1) evaluations to represent it. + std::array + combiner_quotient_evals = {}; + for (size_t idx = 0; idx < (Flavor::BATCHED_RELATION_TOTAL_LENGTH - 2) * (VerifierInstances::NUM - 1); idx++) { + combiner_quotient_evals[idx] = transcript.template receive_from_prover( + "combiner_quotient_" + std::to_string(idx + VerifierInstances::NUM)); } + Univariate + combiner_quotient(combiner_quotient_evals); + auto combiner_challenge = transcript.get_challenge("combiner_quotient_challenge"); + auto combiner_quotient_at_challenge = combiner_quotient.evaluate(combiner_challenge); + + auto vanishing_polynomial_at_challenge = combiner_challenge * (combiner_challenge - FF(1)); + auto lagrange_0_at_challenge = FF(1) - combiner_challenge; + + auto new_target_sum = perturbator_at_challenge * lagrange_0_at_challenge + + vanishing_polynomial_at_challenge * combiner_quotient_at_challenge; - // TODO(https://github.com/AztecProtocol/barretenberg/issues/690): finalise the Protogalaxy verifier logic VerifierFoldingResult res; + res.parameters.target_sum = new_target_sum; return res; } diff --git a/barretenberg/cpp/src/barretenberg/protogalaxy/protogalaxy_verifier.hpp b/barretenberg/cpp/src/barretenberg/protogalaxy/protogalaxy_verifier.hpp index 524c50a2f1a8..e8f7032cb306 100644 --- a/barretenberg/cpp/src/barretenberg/protogalaxy/protogalaxy_verifier.hpp +++ b/barretenberg/cpp/src/barretenberg/protogalaxy/protogalaxy_verifier.hpp @@ -16,7 +16,6 @@ template class ProtoGalaxyVerifier_ { VerifierInstances verifier_instances; BaseTranscript transcript; - // should the PG verifier be given the VerifierInstances, nah this makes sense yo me ProtoGalaxyVerifier_(VerifierInstances insts) : verifier_instances(insts){}; ~ProtoGalaxyVerifier_() = default; @@ -33,8 +32,21 @@ template class ProtoGalaxyVerifier_ { } return pows; } + std::shared_ptr get_accumulator() { return verifier_instances[0]; } + /** + * @brief Instatiate the VerifierInstances and the VerifierTranscript. + * + * @param fold_data The data transmitted via the transcript by the prover. + */ + void prepare_for_folding(std::vector fold_data); + + /** + * @brief Run the folding protocol on the verifier side. + * + * TODO(https://github.com/AztecProtocol/barretenberg/issues/690): finalise the implementation of this function + */ VerifierFoldingResult fold_public_parameters(std::vector fold_data); }; diff --git a/barretenberg/cpp/src/barretenberg/relations/nested_containers.hpp b/barretenberg/cpp/src/barretenberg/relations/nested_containers.hpp index 601d4f35a839..90ca8238ce1d 100644 --- a/barretenberg/cpp/src/barretenberg/relations/nested_containers.hpp +++ b/barretenberg/cpp/src/barretenberg/relations/nested_containers.hpp @@ -10,25 +10,30 @@ namespace proof_system { * * @details Credit: https://stackoverflow.com/a/60440611 */ -template