diff --git a/circuits/cpp/barretenberg/cpp/src/barretenberg/plonk/proof_system/verifier/verifier.test.cpp b/circuits/cpp/barretenberg/cpp/src/barretenberg/plonk/proof_system/verifier/verifier.test.cpp index dd923130f83..f76f3ea49fe 100644 --- a/circuits/cpp/barretenberg/cpp/src/barretenberg/plonk/proof_system/verifier/verifier.test.cpp +++ b/circuits/cpp/barretenberg/cpp/src/barretenberg/plonk/proof_system/verifier/verifier.test.cpp @@ -1,3 +1,4 @@ +#include "verifier.hpp" #include "../../../transcript/transcript.hpp" #include "../prover/prover.hpp" #include "../utils/permutation.hpp" @@ -9,7 +10,6 @@ #include "barretenberg/plonk/proof_system/proving_key/proving_key.hpp" #include "barretenberg/polynomials/polynomial_arithmetic.hpp" #include "barretenberg/srs/factories/file_crs_factory.hpp" -#include "verifier.hpp" #include namespace verifier_helpers { diff --git a/circuits/cpp/barretenberg/cpp/src/barretenberg/polynomials/polynomial.cpp b/circuits/cpp/barretenberg/cpp/src/barretenberg/polynomials/polynomial.cpp index 1fe1e128be5..47d57d8b986 100644 --- a/circuits/cpp/barretenberg/cpp/src/barretenberg/polynomials/polynomial.cpp +++ b/circuits/cpp/barretenberg/cpp/src/barretenberg/polynomials/polynomial.cpp @@ -12,7 +12,6 @@ #include namespace barretenberg { - /** * Constructors / Destructors **/ @@ -150,7 +149,9 @@ template void Polynomial::zero_memory_beyond(const size_t star * FFTs **/ -template void Polynomial::fft(const EvaluationDomain& domain) +template +void Polynomial::fft(const EvaluationDomain& domain) + requires polynomial_arithmetic::SupportsFFT { ASSERT(in_place_operation_viable(domain.size)); zero_memory_beyond(domain.size); @@ -158,7 +159,9 @@ template void Polynomial::fft(const EvaluationDomain& doma polynomial_arithmetic::fft(coefficients_.get(), domain); } -template void Polynomial::partial_fft(const EvaluationDomain& domain, Fr constant, bool is_coset) +template +void Polynomial::partial_fft(const EvaluationDomain& domain, Fr constant, bool is_coset) + requires polynomial_arithmetic::SupportsFFT { ASSERT(in_place_operation_viable(domain.size)); zero_memory_beyond(domain.size); @@ -166,7 +169,9 @@ template void Polynomial::partial_fft(const EvaluationDomain void Polynomial::coset_fft(const EvaluationDomain& domain) +template +void Polynomial::coset_fft(const EvaluationDomain& domain) + requires polynomial_arithmetic::SupportsFFT { ASSERT(in_place_operation_viable(domain.size)); zero_memory_beyond(domain.size); @@ -178,6 +183,7 @@ template void Polynomial::coset_fft(const EvaluationDomain& domain, const EvaluationDomain& large_domain, const size_t domain_extension) + requires polynomial_arithmetic::SupportsFFT { size_t extended_size = domain.size * domain_extension; @@ -189,6 +195,7 @@ void Polynomial::coset_fft(const EvaluationDomain& domain, template void Polynomial::coset_fft_with_constant(const EvaluationDomain& domain, const Fr& constant) + requires polynomial_arithmetic::SupportsFFT { ASSERT(in_place_operation_viable(domain.size)); zero_memory_beyond(domain.size); @@ -198,6 +205,7 @@ void Polynomial::coset_fft_with_constant(const EvaluationDomain& domain, template void Polynomial::coset_fft_with_generator_shift(const EvaluationDomain& domain, const Fr& constant) + requires polynomial_arithmetic::SupportsFFT { ASSERT(in_place_operation_viable(domain.size)); zero_memory_beyond(domain.size); @@ -205,7 +213,9 @@ void Polynomial::coset_fft_with_generator_shift(const EvaluationDomain& polynomial_arithmetic::coset_fft_with_generator_shift(coefficients_.get(), domain, constant); } -template void Polynomial::ifft(const EvaluationDomain& domain) +template +void Polynomial::ifft(const EvaluationDomain& domain) + requires polynomial_arithmetic::SupportsFFT { ASSERT(in_place_operation_viable(domain.size)); zero_memory_beyond(domain.size); @@ -213,7 +223,9 @@ template void Polynomial::ifft(const EvaluationDomain& dom polynomial_arithmetic::ifft(coefficients_.get(), domain); } -template void Polynomial::ifft_with_constant(const EvaluationDomain& domain, const Fr& constant) +template +void Polynomial::ifft_with_constant(const EvaluationDomain& domain, const Fr& constant) + requires polynomial_arithmetic::SupportsFFT { ASSERT(in_place_operation_viable(domain.size)); zero_memory_beyond(domain.size); @@ -221,7 +233,9 @@ template void Polynomial::ifft_with_constant(const EvaluationD polynomial_arithmetic::ifft_with_constant(coefficients_.get(), domain, constant); } -template void Polynomial::coset_ifft(const EvaluationDomain& domain) +template +void Polynomial::coset_ifft(const EvaluationDomain& domain) + requires polynomial_arithmetic::SupportsFFT { ASSERT(in_place_operation_viable(domain.size)); zero_memory_beyond(domain.size); @@ -229,13 +243,16 @@ template void Polynomial::coset_ifft(const EvaluationDomain Fr Polynomial::compute_kate_opening_coefficients(const Fr& z) +template +Fr Polynomial::compute_kate_opening_coefficients(const Fr& z) + requires polynomial_arithmetic::SupportsFFT { return polynomial_arithmetic::compute_kate_opening_coefficients(coefficients_.get(), coefficients_.get(), z, size_); } template Fr Polynomial::compute_barycentric_evaluation(const Fr& z, const EvaluationDomain& domain) + requires polynomial_arithmetic::SupportsFFT { return polynomial_arithmetic::compute_barycentric_evaluation(coefficients_.get(), domain.size, z, domain); } @@ -244,6 +261,8 @@ template Fr Polynomial::evaluate_from_fft(const EvaluationDomain& large_domain, const Fr& z, const EvaluationDomain& small_domain) + requires polynomial_arithmetic::SupportsFFT + { return polynomial_arithmetic::evaluate_from_fft(coefficients_.get(), large_domain, z, small_domain); } diff --git a/circuits/cpp/barretenberg/cpp/src/barretenberg/polynomials/polynomial.hpp b/circuits/cpp/barretenberg/cpp/src/barretenberg/polynomials/polynomial.hpp index 9196e5cd6eb..f3863555943 100644 --- a/circuits/cpp/barretenberg/cpp/src/barretenberg/polynomials/polynomial.hpp +++ b/circuits/cpp/barretenberg/cpp/src/barretenberg/polynomials/polynomial.hpp @@ -8,10 +8,9 @@ #include #include #include - namespace barretenberg { - template class Polynomial { + public: /** * Implements requirements of `std::ranges::contiguous_range` and `std::ranges::sized_range` @@ -107,27 +106,35 @@ template class Polynomial { Fr evaluate(const Fr& z, const size_t target_size) const; Fr evaluate(const Fr& z) const; - Fr compute_barycentric_evaluation(const Fr& z, const EvaluationDomain& domain); + Fr compute_barycentric_evaluation(const Fr& z, const EvaluationDomain& domain) + requires polynomial_arithmetic::SupportsFFT; Fr evaluate_from_fft(const EvaluationDomain& large_domain, const Fr& z, - const EvaluationDomain& small_domain); - - void fft(const EvaluationDomain& domain); - void partial_fft(const EvaluationDomain& domain, Fr constant = 1, bool is_coset = false); - void coset_fft(const EvaluationDomain& domain); + const EvaluationDomain& small_domain) + requires polynomial_arithmetic::SupportsFFT; + void fft(const EvaluationDomain& domain) + requires polynomial_arithmetic::SupportsFFT; + void partial_fft(const EvaluationDomain& domain, Fr constant = 1, bool is_coset = false) + requires polynomial_arithmetic::SupportsFFT; + void coset_fft(const EvaluationDomain& domain) + requires polynomial_arithmetic::SupportsFFT; void coset_fft(const EvaluationDomain& domain, const EvaluationDomain& large_domain, - const size_t domain_extension); - - void coset_fft_with_constant(const EvaluationDomain& domain, const Fr& costant); - void coset_fft_with_generator_shift(const EvaluationDomain& domain, const Fr& constant); - - void ifft(const EvaluationDomain& domain); - void ifft_with_constant(const EvaluationDomain& domain, const Fr& constant); - void coset_ifft(const EvaluationDomain& domain); - - Fr compute_kate_opening_coefficients(const Fr& z); + const size_t domain_extension) + requires polynomial_arithmetic::SupportsFFT; + void coset_fft_with_constant(const EvaluationDomain& domain, const Fr& costant) + requires polynomial_arithmetic::SupportsFFT; + void coset_fft_with_generator_shift(const EvaluationDomain& domain, const Fr& constant) + requires polynomial_arithmetic::SupportsFFT; + void ifft(const EvaluationDomain& domain) + requires polynomial_arithmetic::SupportsFFT; + void ifft_with_constant(const EvaluationDomain& domain, const Fr& constant) + requires polynomial_arithmetic::SupportsFFT; + void coset_ifft(const EvaluationDomain& domain) + requires polynomial_arithmetic::SupportsFFT; + Fr compute_kate_opening_coefficients(const Fr& z) + requires polynomial_arithmetic::SupportsFFT; bool is_empty() const { return (coefficients_ == nullptr) || (size_ == 0); } @@ -252,6 +259,7 @@ template inline std::ostream& operator<<(std::ostream& os, Polynom << "]"; } +// Done // N.B. grumpkin polynomials don't support fast fourier transforms using roots of unity! // TODO: use template junk to disable fft methods if Fr::SUPPORTS_FFTS == false // extern template class Polynomial; diff --git a/circuits/cpp/barretenberg/cpp/src/barretenberg/polynomials/polynomial_arithmetic.cpp b/circuits/cpp/barretenberg/cpp/src/barretenberg/polynomials/polynomial_arithmetic.cpp index 8dfb0e40d05..0fa9083bd90 100644 --- a/circuits/cpp/barretenberg/cpp/src/barretenberg/polynomials/polynomial_arithmetic.cpp +++ b/circuits/cpp/barretenberg/cpp/src/barretenberg/polynomials/polynomial_arithmetic.cpp @@ -59,6 +59,7 @@ void copy_polynomial(const Fr* src, Fr* dest, size_t num_src_coefficients, size_ } template + requires SupportsFFT void fft_inner_serial(std::vector coeffs, const size_t domain_size, const std::vector& root_table) { // Assert that the number of polynomials is a power of two. @@ -145,6 +146,7 @@ void scale_by_generator(Fr* coeffs, * @param subgroup_roots Pointer to the array for saving subgroup members. * */ template + requires SupportsFFT void compute_multiplicative_subgroup(const size_t log2_subgroup_size, const EvaluationDomain& src_domain, Fr* subgroup_roots) @@ -167,6 +169,7 @@ void compute_multiplicative_subgroup(const size_t log2_subgroup_size, } template + requires SupportsFFT void fft_inner_parallel(std::vector coeffs, const EvaluationDomain& domain, const Fr&, @@ -294,6 +297,7 @@ void fft_inner_parallel(std::vector coeffs, } template + requires SupportsFFT void fft_inner_parallel( Fr* coeffs, Fr* target, const EvaluationDomain& domain, const Fr&, const std::vector& root_table) { @@ -388,6 +392,7 @@ void fft_inner_parallel( } template + requires SupportsFFT void partial_fft_serial_inner(Fr* coeffs, Fr* target, const EvaluationDomain& domain, @@ -430,6 +435,7 @@ void partial_fft_serial_inner(Fr* coeffs, } template + requires SupportsFFT void partial_fft_parellel_inner( Fr* coeffs, const EvaluationDomain& domain, const std::vector& root_table, Fr constant, bool is_coset) { @@ -500,32 +506,44 @@ void partial_fft_parellel_inner( ITERATE_OVER_DOMAIN_END; } -template void partial_fft_serial(Fr* coeffs, Fr* target, const EvaluationDomain& domain) +template + requires SupportsFFT +void partial_fft_serial(Fr* coeffs, Fr* target, const EvaluationDomain& domain) { partial_fft_serial_inner(coeffs, target, domain, domain.get_round_roots()); } -template void partial_fft(Fr* coeffs, const EvaluationDomain& domain, Fr constant, bool is_coset) +template + requires SupportsFFT +void partial_fft(Fr* coeffs, const EvaluationDomain& domain, Fr constant, bool is_coset) { partial_fft_parellel_inner(coeffs, domain, domain.get_round_roots(), constant, is_coset); } -template void fft(Fr* coeffs, const EvaluationDomain& domain) +template + requires SupportsFFT +void fft(Fr* coeffs, const EvaluationDomain& domain) { fft_inner_parallel({ coeffs }, domain, domain.root, domain.get_round_roots()); } -template void fft(Fr* coeffs, Fr* target, const EvaluationDomain& domain) +template + requires SupportsFFT +void fft(Fr* coeffs, Fr* target, const EvaluationDomain& domain) { fft_inner_parallel(coeffs, target, domain, domain.root, domain.get_round_roots()); } -template void fft(std::vector coeffs, const EvaluationDomain& domain) +template + requires SupportsFFT +void fft(std::vector coeffs, const EvaluationDomain& domain) { fft_inner_parallel(coeffs, domain.size, domain.root, domain.get_round_roots()); } -template void ifft(Fr* coeffs, const EvaluationDomain& domain) +template + requires SupportsFFT +void ifft(Fr* coeffs, const EvaluationDomain& domain) { fft_inner_parallel({ coeffs }, domain, domain.root_inverse, domain.get_inverse_round_roots()); ITERATE_OVER_DOMAIN_START(domain); @@ -533,7 +551,9 @@ template void ifft(Fr* coeffs, const EvaluationDomain& domain) ITERATE_OVER_DOMAIN_END; } -template void ifft(Fr* coeffs, Fr* target, const EvaluationDomain& domain) +template + requires SupportsFFT +void ifft(Fr* coeffs, Fr* target, const EvaluationDomain& domain) { fft_inner_parallel(coeffs, target, domain, domain.root_inverse, domain.get_inverse_round_roots()); ITERATE_OVER_DOMAIN_START(domain); @@ -541,7 +561,9 @@ template void ifft(Fr* coeffs, Fr* target, const EvaluationDomain< ITERATE_OVER_DOMAIN_END; } -template void ifft(std::vector coeffs, const EvaluationDomain& domain) +template + requires SupportsFFT +void ifft(std::vector coeffs, const EvaluationDomain& domain) { fft_inner_parallel(coeffs, domain, domain.root_inverse, domain.get_inverse_round_roots()); @@ -557,7 +579,9 @@ template void ifft(std::vector coeffs, const EvaluationDomain ITERATE_OVER_DOMAIN_END; } -template void fft_with_constant(Fr* coeffs, const EvaluationDomain& domain, const Fr& value) +template + requires SupportsFFT +void fft_with_constant(Fr* coeffs, const EvaluationDomain& domain, const Fr& value) { fft_inner_parallel({ coeffs }, domain, domain.root, domain.get_round_roots()); ITERATE_OVER_DOMAIN_START(domain); @@ -565,19 +589,25 @@ template void fft_with_constant(Fr* coeffs, const EvaluationDomain ITERATE_OVER_DOMAIN_END; } -template void coset_fft(Fr* coeffs, const EvaluationDomain& domain) +template + requires SupportsFFT +void coset_fft(Fr* coeffs, const EvaluationDomain& domain) { scale_by_generator(coeffs, coeffs, domain, Fr::one(), domain.generator, domain.generator_size); fft(coeffs, domain); } -template void coset_fft(Fr* coeffs, Fr* target, const EvaluationDomain& domain) +template + requires SupportsFFT +void coset_fft(Fr* coeffs, Fr* target, const EvaluationDomain& domain) { scale_by_generator(coeffs, target, domain, Fr::one(), domain.generator, domain.generator_size); fft(coeffs, target, domain); } -template void coset_fft(std::vector coeffs, const EvaluationDomain& domain) +template + requires SupportsFFT +void coset_fft(std::vector coeffs, const EvaluationDomain& domain) { const size_t num_polys = coeffs.size(); ASSERT(is_power_of_two(num_polys)); @@ -593,6 +623,7 @@ template void coset_fft(std::vector coeffs, const EvaluationD } template + requires SupportsFFT void coset_fft(Fr* coeffs, const EvaluationDomain& domain, const EvaluationDomain&, @@ -652,7 +683,9 @@ void coset_fft(Fr* coeffs, } } -template void coset_fft_with_constant(Fr* coeffs, const EvaluationDomain& domain, const Fr& constant) +template + requires SupportsFFT +void coset_fft_with_constant(Fr* coeffs, const EvaluationDomain& domain, const Fr& constant) { Fr start = constant; scale_by_generator(coeffs, coeffs, domain, start, domain.generator, domain.generator_size); @@ -660,13 +693,16 @@ template void coset_fft_with_constant(Fr* coeffs, const Evaluation } template + requires SupportsFFT void coset_fft_with_generator_shift(Fr* coeffs, const EvaluationDomain& domain, const Fr& constant) { scale_by_generator(coeffs, coeffs, domain, Fr::one(), domain.generator * constant, domain.generator_size); fft(coeffs, domain); } -template void ifft_with_constant(Fr* coeffs, const EvaluationDomain& domain, const Fr& value) +template + requires SupportsFFT +void ifft_with_constant(Fr* coeffs, const EvaluationDomain& domain, const Fr& value) { fft_inner_parallel({ coeffs }, domain, domain.root_inverse, domain.get_inverse_round_roots()); Fr T0 = domain.domain_inverse * value; @@ -675,13 +711,17 @@ template void ifft_with_constant(Fr* coeffs, const EvaluationDomai ITERATE_OVER_DOMAIN_END; } -template void coset_ifft(Fr* coeffs, const EvaluationDomain& domain) +template + requires SupportsFFT +void coset_ifft(Fr* coeffs, const EvaluationDomain& domain) { ifft(coeffs, domain); scale_by_generator(coeffs, coeffs, domain, Fr::one(), domain.generator_inverse, domain.size); } -template void coset_ifft(std::vector coeffs, const EvaluationDomain& domain) +template + requires SupportsFFT +void coset_ifft(std::vector coeffs, const EvaluationDomain& domain) { ifft(coeffs, domain); @@ -812,6 +852,7 @@ template Fr evaluate(const std::vector coeffs, const Fr& z, c * L_i(X), we perform a (k*i)-left-shift of this vector. */ template + requires SupportsFFT void compute_lagrange_polynomial_fft(Fr* l_1_coefficients, const EvaluationDomain& src_domain, const EvaluationDomain& target_domain) @@ -858,6 +899,7 @@ void compute_lagrange_polynomial_fft(Fr* l_1_coefficients, } template + requires SupportsFFT void divide_by_pseudo_vanishing_polynomial(std::vector coeffs, const EvaluationDomain& src_domain, const EvaluationDomain& target_domain, @@ -966,7 +1008,9 @@ void divide_by_pseudo_vanishing_polynomial(std::vector coeffs, delete[] subgroup_roots; } -template Fr compute_kate_opening_coefficients(const Fr* src, Fr* dest, const Fr& z, const size_t n) +template + requires SupportsFFT +Fr compute_kate_opening_coefficients(const Fr* src, Fr* dest, const Fr& z, const size_t n) { // if `coeffs` represents F(X), we want to compute W(X) // where W(X) = F(X) - F(z) / (X - z) @@ -995,6 +1039,7 @@ template Fr compute_kate_opening_coefficients(const Fr* src, Fr* d * @param zeta - the name given (in our code) to the evaluation challenge ʓ from the Plonk paper. */ template + requires SupportsFFT barretenberg::polynomial_arithmetic::LagrangeEvaluations get_lagrange_evaluations( const Fr& zeta, const EvaluationDomain& domain, const size_t num_roots_cut_out_of_vanishing_polynomial) { @@ -1076,6 +1121,7 @@ barretenberg::polynomial_arithmetic::LagrangeEvaluations get_lagrange_evalua // n.(ʓ.ω^{1-i)} - 1) // template + requires SupportsFFT Fr compute_barycentric_evaluation(const Fr* coeffs, const size_t num_coeffs, const Fr& z, @@ -1120,7 +1166,9 @@ Fr compute_barycentric_evaluation(const Fr* coeffs, } // Convert an fft with `current_size` point evaluations, to one with `current_size >> compress_factor` point evaluations -template void compress_fft(const Fr* src, Fr* dest, const size_t cur_size, const size_t compress_factor) +template + requires SupportsFFT +void compress_fft(const Fr* src, Fr* dest, const size_t cur_size, const size_t compress_factor) { // iterate from top to bottom, allows `dest` to overlap with `src` size_t log2_compress_factor = (size_t)numeric::get_msb(compress_factor); @@ -1132,6 +1180,7 @@ template void compress_fft(const Fr* src, Fr* dest, const size_t c } template + requires SupportsFFT Fr evaluate_from_fft(const Fr* poly_coset_fft, const EvaluationDomain& large_domain, const Fr& z, @@ -1193,6 +1242,7 @@ template Fr compute_linear_polynomial_product_evaluation(const Fr* } template + requires SupportsFFT void fft_linear_polynomial_product( const Fr* roots, Fr* dest, const size_t n, const EvaluationDomain& domain, const bool is_coset) { @@ -1365,48 +1415,6 @@ template void compute_efficient_interpolation(const fr*, fr*, const fr*, con template grumpkin::fr evaluate(const grumpkin::fr*, const grumpkin::fr&, const size_t); template grumpkin::fr evaluate(const std::vector, const grumpkin::fr&, const size_t); template void copy_polynomial(const grumpkin::fr*, grumpkin::fr*, size_t, size_t); -template void fft_inner_serial(std::vector, - const size_t, - const std::vector&); -template void fft_inner_parallel(std::vector, - const EvaluationDomain&, - const grumpkin::fr&, - const std::vector&); -template void fft(grumpkin::fr*, const EvaluationDomain&); -template void fft(grumpkin::fr*, grumpkin::fr*, const EvaluationDomain&); -template void fft(std::vector, const EvaluationDomain&); -template void fft_with_constant(grumpkin::fr*, - const EvaluationDomain&, - const grumpkin::fr&); -template void coset_fft(grumpkin::fr*, const EvaluationDomain&); -template void coset_fft(grumpkin::fr*, grumpkin::fr*, const EvaluationDomain&); -template void coset_fft(std::vector, const EvaluationDomain&); -template void coset_fft(grumpkin::fr*, - const EvaluationDomain&, - const EvaluationDomain&, - const size_t); -template void coset_fft_with_constant(grumpkin::fr*, - const EvaluationDomain&, - const grumpkin::fr&); -template void coset_fft_with_generator_shift(grumpkin::fr*, - const EvaluationDomain&, - const grumpkin::fr&); -template void ifft(grumpkin::fr*, const EvaluationDomain&); -template void ifft(grumpkin::fr*, grumpkin::fr*, const EvaluationDomain&); -template void ifft(std::vector, const EvaluationDomain&); -template void ifft_with_constant(grumpkin::fr*, - const EvaluationDomain&, - const grumpkin::fr&); -template void coset_ifft(grumpkin::fr*, const EvaluationDomain&); -template void coset_ifft(std::vector, const EvaluationDomain&); -template void partial_fft_serial_inner(grumpkin::fr*, - grumpkin::fr*, - const EvaluationDomain&, - const std::vector&); -template void partial_fft_parellel_inner( - grumpkin::fr*, const EvaluationDomain&, const std::vector&, grumpkin::fr, bool); -template void partial_fft_serial(grumpkin::fr*, grumpkin::fr*, const EvaluationDomain&); -template void partial_fft(grumpkin::fr*, const EvaluationDomain&, grumpkin::fr, bool); template void add(const grumpkin::fr*, const grumpkin::fr*, grumpkin::fr*, @@ -1419,36 +1427,11 @@ template void mul(const grumpkin::fr*, const grumpkin::fr*, grumpkin::fr*, const EvaluationDomain&); -template void compute_lagrange_polynomial_fft(grumpkin::fr*, - const EvaluationDomain&, - const EvaluationDomain&); -template void divide_by_pseudo_vanishing_polynomial(std::vector, - const EvaluationDomain&, - const EvaluationDomain&, - const size_t); -template grumpkin::fr compute_kate_opening_coefficients(const grumpkin::fr*, - grumpkin::fr*, - const grumpkin::fr&, - const size_t); -template LagrangeEvaluations get_lagrange_evaluations(const grumpkin::fr&, - const EvaluationDomain&, - const size_t); -template grumpkin::fr compute_barycentric_evaluation(const grumpkin::fr*, - const size_t, - const grumpkin::fr&, - const EvaluationDomain&); -template void compress_fft(const grumpkin::fr*, grumpkin::fr*, const size_t, const size_t); -template grumpkin::fr evaluate_from_fft(const grumpkin::fr*, - const EvaluationDomain&, - const grumpkin::fr&, - const EvaluationDomain&); template grumpkin::fr compute_sum(const grumpkin::fr*, const size_t); template void compute_linear_polynomial_product(const grumpkin::fr*, grumpkin::fr*, const size_t); template grumpkin::fr compute_linear_polynomial_product_evaluation(const grumpkin::fr*, const grumpkin::fr, const size_t); -template void fft_linear_polynomial_product( - const grumpkin::fr* roots, grumpkin::fr*, const size_t n, const EvaluationDomain&, const bool); template void compute_interpolation(const grumpkin::fr*, grumpkin::fr*, const grumpkin::fr*, diff --git a/circuits/cpp/barretenberg/cpp/src/barretenberg/polynomials/polynomial_arithmetic.hpp b/circuits/cpp/barretenberg/cpp/src/barretenberg/polynomials/polynomial_arithmetic.hpp index 441d52c8342..56ce9ec1a39 100644 --- a/circuits/cpp/barretenberg/cpp/src/barretenberg/polynomials/polynomial_arithmetic.hpp +++ b/circuits/cpp/barretenberg/cpp/src/barretenberg/polynomials/polynomial_arithmetic.hpp @@ -3,6 +3,9 @@ namespace barretenberg { namespace polynomial_arithmetic { + +template +concept SupportsFFT = std::same_as; template struct LagrangeEvaluations { Fr vanishing_poly; Fr l_start; @@ -26,54 +29,91 @@ void copy_polynomial(const Fr* src, Fr* dest, size_t num_src_coefficients, size_ // 2. Compute a lookup table of the roots of unity, and suffer through cache misses from nonlinear access patterns template + requires SupportsFFT void fft_inner_serial(std::vector coeffs, const size_t domain_size, const std::vector& root_table); template + requires SupportsFFT void fft_inner_parallel(std::vector coeffs, const EvaluationDomain& domain, const Fr&, const std::vector& root_table); -template void fft(Fr* coeffs, const EvaluationDomain& domain); -template void fft(Fr* coeffs, Fr* target, const EvaluationDomain& domain); -template void fft(std::vector coeffs, const EvaluationDomain& domain); -template void fft_with_constant(Fr* coeffs, const EvaluationDomain& domain, const Fr& value); +template + requires SupportsFFT +void fft(Fr* coeffs, const EvaluationDomain& domain); +template + requires SupportsFFT +void fft(Fr* coeffs, Fr* target, const EvaluationDomain& domain); +template + requires SupportsFFT +void fft(std::vector coeffs, const EvaluationDomain& domain); +template + requires SupportsFFT +void fft_with_constant(Fr* coeffs, const EvaluationDomain& domain, const Fr& value); -template void coset_fft(Fr* coeffs, const EvaluationDomain& domain); -template void coset_fft(Fr* coeffs, Fr* target, const EvaluationDomain& domain); -template void coset_fft(std::vector coeffs, const EvaluationDomain& domain); template + requires SupportsFFT +void coset_fft(Fr* coeffs, const EvaluationDomain& domain); +template + requires SupportsFFT +void coset_fft(Fr* coeffs, Fr* target, const EvaluationDomain& domain); +template + requires SupportsFFT +void coset_fft(std::vector coeffs, const EvaluationDomain& domain); +template + requires SupportsFFT void coset_fft(Fr* coeffs, const EvaluationDomain& small_domain, const EvaluationDomain& large_domain, const size_t domain_extension); -template void coset_fft_with_constant(Fr* coeffs, const EvaluationDomain& domain, const Fr& constant); template + requires SupportsFFT +void coset_fft_with_constant(Fr* coeffs, const EvaluationDomain& domain, const Fr& constant); +template + requires SupportsFFT void coset_fft_with_generator_shift(Fr* coeffs, const EvaluationDomain& domain, const Fr& constant); -template void ifft(Fr* coeffs, const EvaluationDomain& domain); -template void ifft(Fr* coeffs, Fr* target, const EvaluationDomain& domain); -template void ifft(std::vector coeffs, const EvaluationDomain& domain); +template + requires SupportsFFT +void ifft(Fr* coeffs, const EvaluationDomain& domain); +template + requires SupportsFFT +void ifft(Fr* coeffs, Fr* target, const EvaluationDomain& domain); +template + requires SupportsFFT +void ifft(std::vector coeffs, const EvaluationDomain& domain); -template void ifft_with_constant(Fr* coeffs, const EvaluationDomain& domain, const Fr& value); +template + requires SupportsFFT +void ifft_with_constant(Fr* coeffs, const EvaluationDomain& domain, const Fr& value); -template void coset_ifft(Fr* coeffs, const EvaluationDomain& domain); -template void coset_ifft(std::vector coeffs, const EvaluationDomain& domain); +template + requires SupportsFFT +void coset_ifft(Fr* coeffs, const EvaluationDomain& domain); +template + requires SupportsFFT +void coset_ifft(std::vector coeffs, const EvaluationDomain& domain); template + requires SupportsFFT void partial_fft_serial_inner(Fr* coeffs, Fr* target, const EvaluationDomain& domain, const std::vector& root_table); template + requires SupportsFFT void partial_fft_parellel_inner(Fr* coeffs, const EvaluationDomain& domain, const std::vector& root_table, Fr constant = 1, bool is_coset = false); -template void partial_fft_serial(Fr* coeffs, Fr* target, const EvaluationDomain& domain); template + requires SupportsFFT +void partial_fft_serial(Fr* coeffs, Fr* target, const EvaluationDomain& domain); +template + requires SupportsFFT void partial_fft(Fr* coeffs, const EvaluationDomain& domain, Fr constant = 1, bool is_coset = false); template @@ -91,11 +131,13 @@ void mul(const Fr* a_coeffs, const Fr* b_coeffs, Fr* r_coeffs, const EvaluationD // for all X = k*n'th roots of unity. // To compute the vector for the k*n-fft transform of L_i(X), we perform a (k*i)-left-shift of this vector template + requires SupportsFFT void compute_lagrange_polynomial_fft(Fr* l_1_coefficients, const EvaluationDomain& src_domain, const EvaluationDomain& target_domain); template + requires SupportsFFT void divide_by_pseudo_vanishing_polynomial(std::vector coeffs, const EvaluationDomain& src_domain, const EvaluationDomain& target_domain, @@ -104,10 +146,13 @@ void divide_by_pseudo_vanishing_polynomial(std::vector coeffs, // void populate_with_vanishing_polynomial(Fr* coeffs, const size_t num_non_zero_entries, const EvaluationDomain& // src_domain, const EvaluationDomain& target_domain); -template Fr compute_kate_opening_coefficients(const Fr* src, Fr* dest, const Fr& z, const size_t n); +template + requires SupportsFFT +Fr compute_kate_opening_coefficients(const Fr* src, Fr* dest, const Fr& z, const size_t n); // compute Z_H*(z), l_start(z), l_{end}(z) (= l_{n-4}(z)) template + requires SupportsFFT LagrangeEvaluations get_lagrange_evaluations(const Fr& z, const EvaluationDomain& domain, const size_t num_roots_cut_out_of_vanishing_polynomial = 4); @@ -118,9 +163,11 @@ Fr compute_barycentric_evaluation(const Fr* coeffs, const EvaluationDomain& domain); // Convert an fft with `current_size` point evaluations, to one with `current_size >> compress_factor` point evaluations template + requires SupportsFFT void compress_fft(const Fr* src, Fr* dest, const size_t current_size, const size_t compress_factor); template + requires SupportsFFT Fr evaluate_from_fft(const Fr* poly_coset_fft, const EvaluationDomain& large_domain, const Fr& z, @@ -139,6 +186,7 @@ template Fr compute_linear_polynomial_product_evaluation(const Fr* // This function computes the lagrange (or coset-lagrange) form of the polynomial (x - a)(x - b)(x - c)... // given n distinct roots (a, b, c, ...). template + requires SupportsFFT void fft_linear_polynomial_product( const Fr* roots, Fr* dest, const size_t n, const EvaluationDomain& domain, const bool is_coset = false); @@ -387,53 +435,6 @@ extern template grumpkin::fr evaluate(const std::vector(const grumpkin::fr*, grumpkin::fr*, size_t, size_t); -extern template void fft_inner_serial(std::vector, - const size_t, - const std::vector&); -extern template void fft_inner_parallel(std::vector, - const EvaluationDomain&, - const grumpkin::fr&, - const std::vector&); -extern template void fft(grumpkin::fr*, const EvaluationDomain&); -extern template void fft(grumpkin::fr*, grumpkin::fr*, const EvaluationDomain&); -extern template void fft(std::vector, const EvaluationDomain&); -extern template void fft_with_constant(grumpkin::fr*, - const EvaluationDomain&, - const grumpkin::fr&); -extern template void coset_fft(grumpkin::fr*, const EvaluationDomain&); -extern template void coset_fft(grumpkin::fr*, grumpkin::fr*, const EvaluationDomain&); -extern template void coset_fft(std::vector, const EvaluationDomain&); -extern template void coset_fft(grumpkin::fr*, - const EvaluationDomain&, - const EvaluationDomain&, - const size_t); -extern template void coset_fft_with_constant(grumpkin::fr*, - const EvaluationDomain&, - const grumpkin::fr&); -extern template void coset_fft_with_generator_shift(grumpkin::fr*, - const EvaluationDomain&, - const grumpkin::fr&); -extern template void ifft(grumpkin::fr*, const EvaluationDomain&); -extern template void ifft(grumpkin::fr*, grumpkin::fr*, const EvaluationDomain&); -extern template void ifft(std::vector, const EvaluationDomain&); -extern template void ifft_with_constant(grumpkin::fr*, - const EvaluationDomain&, - const grumpkin::fr&); -extern template void coset_ifft(grumpkin::fr*, const EvaluationDomain&); -extern template void coset_ifft(std::vector, const EvaluationDomain&); -extern template void partial_fft_serial_inner(grumpkin::fr*, - grumpkin::fr*, - const EvaluationDomain&, - const std::vector&); -extern template void partial_fft_parellel_inner( - grumpkin::fr*, const EvaluationDomain&, const std::vector&, grumpkin::fr, bool); -extern template void partial_fft_serial(grumpkin::fr*, - grumpkin::fr*, - const EvaluationDomain&); -extern template void partial_fft(grumpkin::fr*, - const EvaluationDomain&, - grumpkin::fr, - bool); extern template void add(const grumpkin::fr*, const grumpkin::fr*, grumpkin::fr*, @@ -446,35 +447,11 @@ extern template void mul(const grumpkin::fr*, const grumpkin::fr*, grumpkin::fr*, const EvaluationDomain&); -extern template void compute_lagrange_polynomial_fft(grumpkin::fr*, - const EvaluationDomain&, - const EvaluationDomain&); -extern template void divide_by_pseudo_vanishing_polynomial(std::vector, - const EvaluationDomain&, - const EvaluationDomain&, - const size_t); -extern template grumpkin::fr compute_kate_opening_coefficients(const grumpkin::fr*, - grumpkin::fr*, - const grumpkin::fr&, - const size_t); -extern template LagrangeEvaluations get_lagrange_evaluations( - const grumpkin::fr&, const EvaluationDomain&, const size_t); -extern template grumpkin::fr compute_barycentric_evaluation(const grumpkin::fr*, - const size_t, - const grumpkin::fr&, - const EvaluationDomain&); -extern template void compress_fft(const grumpkin::fr*, grumpkin::fr*, const size_t, const size_t); -extern template grumpkin::fr evaluate_from_fft(const grumpkin::fr*, - const EvaluationDomain&, - const grumpkin::fr&, - const EvaluationDomain&); extern template grumpkin::fr compute_sum(const grumpkin::fr*, const size_t); extern template void compute_linear_polynomial_product(const grumpkin::fr*, grumpkin::fr*, const size_t); extern template grumpkin::fr compute_linear_polynomial_product_evaluation(const grumpkin::fr*, const grumpkin::fr, const size_t); -extern template void fft_linear_polynomial_product( - const grumpkin::fr* roots, grumpkin::fr*, const size_t n, const EvaluationDomain&, const bool); extern template void compute_interpolation(const grumpkin::fr*, grumpkin::fr*, const grumpkin::fr*, diff --git a/circuits/cpp/barretenberg/cpp/src/barretenberg/polynomials/polynomial_arithmetic.test.cpp b/circuits/cpp/barretenberg/cpp/src/barretenberg/polynomials/polynomial_arithmetic.test.cpp index 644144fc9f7..5bb675a2064 100644 --- a/circuits/cpp/barretenberg/cpp/src/barretenberg/polynomials/polynomial_arithmetic.test.cpp +++ b/circuits/cpp/barretenberg/cpp/src/barretenberg/polynomials/polynomial_arithmetic.test.cpp @@ -1,53 +1,16 @@ +#include "polynomial_arithmetic.hpp" #include "barretenberg/common/mem.hpp" #include "barretenberg/numeric/bitop/get_msb.hpp" #include "barretenberg/numeric/random/engine.hpp" +#include "barretenberg/polynomials/evaluation_domain.hpp" #include "polynomial.hpp" -#include "polynomial_arithmetic.hpp" #include #include #include #include using namespace barretenberg; -// TODO(#635): This tests should be typed to run on both barretenberg::fr and grumpkin::fr. - -TEST(polynomials, evaluation_domain) -{ - constexpr size_t n = 256; - evaluation_domain domain = evaluation_domain(n); - - EXPECT_EQ(domain.size, 256UL); - EXPECT_EQ(domain.log2_size, 8UL); -} -TEST(polynomials, domain_roots) -{ - constexpr size_t n = 256; - evaluation_domain domain = evaluation_domain(n); - - fr result; - fr expected; - expected = fr::one(); - result = domain.root.pow(static_cast(n)); - - EXPECT_EQ((result == expected), true); -} - -TEST(polynomials, evaluation_domain_roots) -{ - constexpr size_t n = 16; - evaluation_domain domain(n); - domain.compute_lookup_table(); - std::vector root_table = domain.get_round_roots(); - std::vector inverse_root_table = domain.get_inverse_round_roots(); - fr* roots = root_table[root_table.size() - 1]; - fr* inverse_roots = inverse_root_table[inverse_root_table.size() - 1]; - for (size_t i = 0; i < (n - 1) / 2; ++i) { - EXPECT_EQ(roots[i] * domain.root, roots[i + 1]); - EXPECT_EQ(inverse_roots[i] * domain.root_inverse, inverse_roots[i + 1]); - EXPECT_EQ(roots[i] * inverse_roots[i], fr::one()); - } -} TEST(polynomials, fft_with_small_degree) { constexpr size_t n = 16; @@ -59,7 +22,7 @@ TEST(polynomials, fft_with_small_degree) fr::__copy(poly[i], fft_transform[i]); } - evaluation_domain domain = evaluation_domain(n); + auto domain = evaluation_domain(n); domain.compute_lookup_table(); polynomial_arithmetic::fft(fft_transform, domain); @@ -91,7 +54,7 @@ TEST(polynomials, split_polynomial_fft) fft_transform_[i / n_poly][i % n_poly] = poly[i]; } - evaluation_domain domain = evaluation_domain(n); + auto domain = evaluation_domain(n); domain.compute_lookup_table(); polynomial_arithmetic::fft(fft_transform, domain); polynomial_arithmetic::fft({ fft_transform_[0], fft_transform_[1], fft_transform_[2], fft_transform_[3] }, domain); @@ -143,7 +106,7 @@ TEST(polynomials, basic_fft) fr::__copy(result[i], expected[i]); } - evaluation_domain domain = evaluation_domain(n); + auto domain = evaluation_domain(n); domain.compute_lookup_table(); polynomial_arithmetic::fft(result, domain); polynomial_arithmetic::ifft(result, domain); @@ -164,7 +127,7 @@ TEST(polynomials, fft_ifft_consistency) fr::__copy(result[i], expected[i]); } - evaluation_domain domain = evaluation_domain(n); + auto domain = evaluation_domain(n); domain.compute_lookup_table(); polynomial_arithmetic::fft(result, domain); polynomial_arithmetic::ifft(result, domain); @@ -187,7 +150,7 @@ TEST(polynomials, split_polynomial_fft_ifft_consistency) } } - evaluation_domain domain = evaluation_domain(num_poly * n); + auto domain = evaluation_domain(num_poly * n); domain.compute_lookup_table(); std::vector coeffs_vec; @@ -214,7 +177,7 @@ TEST(polynomials, fft_coset_ifft_consistency) fr::__copy(result[i], expected[i]); } - evaluation_domain domain = evaluation_domain(n); + auto domain = evaluation_domain(n); domain.compute_lookup_table(); fr T0; T0 = domain.generator * domain.generator_inverse; @@ -241,7 +204,7 @@ TEST(polynomials, split_polynomial_fft_coset_ifft_consistency) } } - evaluation_domain domain = evaluation_domain(num_poly * n); + auto domain = evaluation_domain(num_poly * n); domain.compute_lookup_table(); std::vector coeffs_vec; @@ -279,9 +242,9 @@ TEST(polynomials, fft_coset_ifft_cross_consistency) poly_b[i] = fr::zero(); poly_c[i] = fr::zero(); } - evaluation_domain small_domain = evaluation_domain(n); - evaluation_domain mid_domain = evaluation_domain(2 * n); - evaluation_domain large_domain = evaluation_domain(4 * n); + auto small_domain = evaluation_domain(n); + auto mid_domain = evaluation_domain(2 * n); + auto large_domain = evaluation_domain(4 * n); small_domain.compute_lookup_table(); mid_domain.compute_lookup_table(); large_domain.compute_lookup_table(); @@ -307,8 +270,8 @@ TEST(polynomials, fft_coset_ifft_cross_consistency) TEST(polynomials, compute_lagrange_polynomial_fft) { constexpr size_t n = 256; - evaluation_domain small_domain = evaluation_domain(n); - evaluation_domain mid_domain = evaluation_domain(2 * n); + auto small_domain = evaluation_domain(n); + auto mid_domain = evaluation_domain(2 * n); small_domain.compute_lookup_table(); mid_domain.compute_lookup_table(); fr l_1_coefficients[2 * n]; @@ -375,8 +338,8 @@ TEST(polynomials, compute_lagrange_polynomial_fft_large_domain) { constexpr size_t n = 256; // size of small_domain constexpr size_t M = 4; // size of large_domain == M * n - evaluation_domain small_domain = evaluation_domain(n); - evaluation_domain large_domain = evaluation_domain(M * n); + auto small_domain = evaluation_domain(n); + auto large_domain = evaluation_domain(M * n); small_domain.compute_lookup_table(); large_domain.compute_lookup_table(); @@ -461,8 +424,8 @@ TEST(polynomials, divide_by_pseudo_vanishing_polynomial) // make the final evaluation not vanish // c[n-1].one(); - evaluation_domain small_domain = evaluation_domain(n); - evaluation_domain large_domain = evaluation_domain(n_large); + auto small_domain = evaluation_domain(n); + auto large_domain = evaluation_domain(n_large); small_domain.compute_lookup_table(); large_domain.compute_lookup_table(); @@ -521,7 +484,7 @@ TEST(polynomials, compute_kate_opening_coefficients) coeffs[0] -= f; // compute fft of polynomials - evaluation_domain domain = evaluation_domain(2 * n); + auto domain = evaluation_domain(2 * n); domain.compute_lookup_table(); polynomial_arithmetic::coset_fft(coeffs, domain); polynomial_arithmetic::coset_fft(W, domain); @@ -543,7 +506,7 @@ TEST(polynomials, get_lagrange_evaluations) { constexpr size_t n = 16; - evaluation_domain domain = evaluation_domain(n); + auto domain = evaluation_domain(n); domain.compute_lookup_table(); fr z = fr::random_element(); @@ -908,7 +871,7 @@ TEST(polynomials, fft_linear_poly_product) constexpr size_t log2_n = static_cast(numeric::get_msb(n)); constexpr size_t N = static_cast(1 << (log2_n + 1)); - evaluation_domain domain = evaluation_domain(N); + auto domain = evaluation_domain(N); domain.compute_lookup_table(); fr dest[N]; @@ -929,17 +892,65 @@ TEST(polynomials, fft_linear_poly_product) EXPECT_EQ(result2, expected); } -TEST(polynomials, compute_interpolation) +template class PolynomialTests : public ::testing::Test {}; + +using FieldTypes = ::testing::Types; + +TYPED_TEST_SUITE(PolynomialTests, FieldTypes); + +TYPED_TEST(PolynomialTests, evaluation_domain) +{ + using FF = TypeParam; + constexpr size_t n = 256; + auto domain = EvaluationDomain(n); + + EXPECT_EQ(domain.size, 256UL); + EXPECT_EQ(domain.log2_size, 8UL); +} + +TYPED_TEST(PolynomialTests, domain_roots) +{ + using FF = TypeParam; + constexpr size_t n = 256; + auto domain = EvaluationDomain(n); + + FF result; + FF expected; + expected = FF::one(); + result = domain.root.pow(static_cast(n)); + + EXPECT_EQ((result == expected), true); +} + +TYPED_TEST(PolynomialTests, evaluation_domain_roots) +{ + using FF = TypeParam; + constexpr size_t n = 16; + EvaluationDomain domain(n); + domain.compute_lookup_table(); + std::vector root_table = domain.get_round_roots(); + std::vector inverse_root_table = domain.get_inverse_round_roots(); + FF* roots = root_table[root_table.size() - 1]; + FF* inverse_roots = inverse_root_table[inverse_root_table.size() - 1]; + for (size_t i = 0; i < (n - 1) / 2; ++i) { + EXPECT_EQ(roots[i] * domain.root, roots[i + 1]); + EXPECT_EQ(inverse_roots[i] * domain.root_inverse, inverse_roots[i + 1]); + EXPECT_EQ(roots[i] * inverse_roots[i], FF::one()); + } +} + +TYPED_TEST(PolynomialTests, compute_interpolation) { + using FF = TypeParam; constexpr size_t n = 100; - fr src[n], poly[n], x[n]; + FF src[n], poly[n], x[n]; for (size_t i = 0; i < n; ++i) { - poly[i] = fr::random_element(); + poly[i] = FF::random_element(); } for (size_t i = 0; i < n; ++i) { - x[i] = fr::random_element(); + x[i] = FF::random_element(); src[i] = polynomial_arithmetic::evaluate(poly, x[i], n); } polynomial_arithmetic::compute_interpolation(src, src, x, n); @@ -949,17 +960,18 @@ TEST(polynomials, compute_interpolation) } } -TEST(polynomials, compute_efficient_interpolation) +TYPED_TEST(PolynomialTests, compute_efficient_interpolation) { + using FF = TypeParam; constexpr size_t n = 250; - fr src[n], poly[n], x[n]; + FF src[n], poly[n], x[n]; for (size_t i = 0; i < n; ++i) { - poly[i] = fr::random_element(); + poly[i] = FF::random_element(); } for (size_t i = 0; i < n; ++i) { - x[i] = fr::random_element(); + x[i] = FF::random_element(); src[i] = polynomial_arithmetic::evaluate(poly, x[i], n); } polynomial_arithmetic::compute_efficient_interpolation(src, src, x, n); @@ -969,67 +981,73 @@ TEST(polynomials, compute_efficient_interpolation) } } -TEST(polynomials, interpolation_constructor_single) +TYPED_TEST(PolynomialTests, interpolation_constructor_single) { - auto root = std::array{ fr(3) }; - auto eval = std::array{ fr(4) }; - polynomial t(root, eval); + using FF = TypeParam; + + auto root = std::array{ FF(3) }; + auto eval = std::array{ FF(4) }; + Polynomial t(root, eval); ASSERT_EQ(t.size(), 1); ASSERT_EQ(t[0], eval[0]); } -TEST(polynomials, interpolation_constructor) +TYPED_TEST(PolynomialTests, interpolation_constructor) { + using FF = TypeParam; + constexpr size_t N = 32; - std::array roots; - std::array evaluations; + std::array roots; + std::array evaluations; for (size_t i = 0; i < N; ++i) { - roots[i] = fr::random_element(); - evaluations[i] = fr::random_element(); + roots[i] = FF::random_element(); + evaluations[i] = FF::random_element(); } auto roots_copy(roots); auto evaluations_copy(evaluations); - polynomial interpolated(roots, evaluations); + Polynomial interpolated(roots, evaluations); ASSERT_EQ(interpolated.size(), N); ASSERT_EQ(roots, roots_copy); ASSERT_EQ(evaluations, evaluations_copy); for (size_t i = 0; i < N; ++i) { - fr eval = interpolated.evaluate(roots[i]); + FF eval = interpolated.evaluate(roots[i]); ASSERT_EQ(eval, evaluations[i]); } } -TEST(polynomials, evaluate_mle) +TYPED_TEST(PolynomialTests, evaluate_mle) { + using FF = TypeParam; + auto test_case = [](size_t N) { auto& engine = numeric::random::get_debug_engine(); const size_t m = numeric::get_msb(N); EXPECT_EQ(N, 1 << m); - polynomial poly(N); + Polynomial poly(N); for (size_t i = 1; i < N - 1; ++i) { - poly[i] = fr::random_element(&engine); + poly[i] = FF::random_element(&engine); } - poly[N - 1] = fr::zero(); + poly[N - 1] = FF::zero(); EXPECT_TRUE(poly[0].is_zero()); // sample u = (u₀,…,uₘ₋₁) - std::vector u(m); + std::vector u(m); for (size_t l = 0; l < m; ++l) { - u[l] = fr::random_element(&engine); + u[l] = FF::random_element(&engine); } - std::vector lagrange_evals(N, fr(1)); + std::vector lagrange_evals(N, FF(1)); for (size_t i = 0; i < N; ++i) { auto& coef = lagrange_evals[i]; for (size_t l = 0; l < m; ++l) { size_t mask = (1 << l); if ((i & mask) == 0) { - coef *= (fr(1) - u[l]); + coef *= (FF(1) - u[l]); } else { coef *= u[l]; } @@ -1038,19 +1056,19 @@ TEST(polynomials, evaluate_mle) // check eval by computing scalar product between // lagrange evaluations and coefficients - fr real_eval(0); + FF real_eval(0); for (size_t i = 0; i < N; ++i) { real_eval += poly[i] * lagrange_evals[i]; } - fr computed_eval = poly.evaluate_mle(u); + FF computed_eval = poly.evaluate_mle(u); EXPECT_EQ(real_eval, computed_eval); // also check shifted eval - fr real_eval_shift(0); + FF real_eval_shift(0); for (size_t i = 1; i < N; ++i) { real_eval_shift += poly[i] * lagrange_evals[i - 1]; } - fr computed_eval_shift = poly.evaluate_mle(u, true); + FF computed_eval_shift = poly.evaluate_mle(u, true); EXPECT_EQ(real_eval_shift, computed_eval_shift); }; test_case(32); @@ -1058,38 +1076,40 @@ TEST(polynomials, evaluate_mle) test_case(2); } -TEST(polynomials, factor_roots) +TYPED_TEST(PolynomialTests, factor_roots) { + using FF = TypeParam; + constexpr size_t N = 32; - auto test_case = [](size_t NUM_ZERO_ROOTS, size_t NUM_NON_ZERO_ROOTS) { + auto test_case = [&](size_t NUM_ZERO_ROOTS, size_t NUM_NON_ZERO_ROOTS) { const size_t NUM_ROOTS = NUM_NON_ZERO_ROOTS + NUM_ZERO_ROOTS; - polynomial poly(N); + Polynomial poly(N); for (size_t i = NUM_ZERO_ROOTS; i < N; ++i) { - poly[i] = fr::random_element(); + poly[i] = FF::random_element(); } // sample a root r, and compute p(r)/r^N for each non-zero root r - std::vector non_zero_roots(NUM_NON_ZERO_ROOTS); - std::vector non_zero_evaluations(NUM_NON_ZERO_ROOTS); + std::vector non_zero_roots(NUM_NON_ZERO_ROOTS); + std::vector non_zero_evaluations(NUM_NON_ZERO_ROOTS); for (size_t i = 0; i < NUM_NON_ZERO_ROOTS; ++i) { - const auto root = fr::random_element(); + const auto root = FF::random_element(); non_zero_roots[i] = root; const auto root_pow = root.pow(NUM_ZERO_ROOTS); non_zero_evaluations[i] = poly.evaluate(root) / root_pow; } - std::vector roots(NUM_ROOTS); + std::vector roots(NUM_ROOTS); for (size_t i = 0; i < NUM_ZERO_ROOTS; ++i) { - roots[i] = fr::zero(); + roots[i] = FF::zero(); } for (size_t i = 0; i < NUM_NON_ZERO_ROOTS; ++i) { roots[NUM_ZERO_ROOTS + i] = non_zero_roots[i]; } if (NUM_NON_ZERO_ROOTS > 0) { - polynomial interpolated(non_zero_roots, non_zero_evaluations); + Polynomial interpolated(non_zero_roots, non_zero_evaluations); EXPECT_EQ(interpolated.size(), NUM_NON_ZERO_ROOTS); for (size_t i = 0; i < NUM_NON_ZERO_ROOTS; ++i) { poly[NUM_ZERO_ROOTS + i] -= interpolated[i]; @@ -1098,27 +1118,27 @@ TEST(polynomials, factor_roots) // Sanity check that all roots are actually roots for (size_t i = 0; i < NUM_ROOTS; ++i) { - EXPECT_EQ(poly.evaluate(roots[i]), fr::zero()) << i; + EXPECT_EQ(poly.evaluate(roots[i]), FF::zero()) << i; } - polynomial quotient(poly); + Polynomial quotient(poly); quotient.factor_roots(roots); // check that (t-r)q(t) == p(t) - fr t = fr::random_element(); - fr roots_eval = polynomial_arithmetic::compute_linear_polynomial_product_evaluation(roots.data(), t, NUM_ROOTS); - fr q_t = quotient.evaluate(t, N - NUM_ROOTS); - fr p_t = poly.evaluate(t, N); + FF t = FF::random_element(); + FF roots_eval = polynomial_arithmetic::compute_linear_polynomial_product_evaluation(roots.data(), t, NUM_ROOTS); + FF q_t = quotient.evaluate(t, N - NUM_ROOTS); + FF p_t = poly.evaluate(t, N); EXPECT_EQ(roots_eval * q_t, p_t); for (size_t i = N - NUM_ROOTS; i < N; ++i) { - EXPECT_EQ(quotient[i], fr::zero()); + EXPECT_EQ(quotient[i], FF::zero()); } if (NUM_ROOTS == 0) { EXPECT_EQ(poly, quotient); } if (NUM_ROOTS == 1) { - polynomial quotient_single(poly); + Polynomial quotient_single(poly); quotient_single.factor_roots(roots[0]); EXPECT_EQ(quotient_single, quotient); } @@ -1132,17 +1152,19 @@ TEST(polynomials, factor_roots) test_case(3, 6); } -TEST(polynomials, move_construct_and_assign) +TYPED_TEST(PolynomialTests, move_construct_and_assign) { + using FF = TypeParam; + // construct a poly with some arbitrary data size_t num_coeffs = 64; - polynomial polynomial_a(num_coeffs); + Polynomial polynomial_a(num_coeffs); for (auto& coeff : polynomial_a) { - coeff = fr::random_element(); + coeff = FF::random_element(); } - // construct a new poly from the original via the move constructor - polynomial polynomial_b(std::move(polynomial_a)); + // construct a new poly FFom the original via the move constructor + Polynomial polynomial_b(std::move(polynomial_a)); // verifiy that source poly is appropriately destroyed EXPECT_EQ(polynomial_a.begin(), nullptr); @@ -1156,9 +1178,9 @@ TEST(polynomials, move_construct_and_assign) EXPECT_EQ(polynomial_b.size(), 0); // define a poly with some arbitrary coefficients - polynomial polynomial_d(num_coeffs); + Polynomial polynomial_d(num_coeffs); for (auto& coeff : polynomial_d) { - coeff = fr::random_element(); + coeff = FF::random_element(); } // reset its data using move assignment @@ -1169,17 +1191,19 @@ TEST(polynomials, move_construct_and_assign) EXPECT_EQ(polynomial_c.size(), 0); } -TEST(polynomials, default_construct_then_assign) +TYPED_TEST(PolynomialTests, default_construct_then_assign) { + using FF = TypeParam; + // construct an arbitrary but non-empty polynomial size_t num_coeffs = 64; - polynomial interesting_poly(num_coeffs); + Polynomial interesting_poly(num_coeffs); for (auto& coeff : interesting_poly) { - coeff = fr::random_element(); + coeff = FF::random_element(); } // construct an empty poly via the default constructor - polynomial poly; + Polynomial poly; EXPECT_EQ(poly.is_empty(), true);