-
Notifications
You must be signed in to change notification settings - Fork 272
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
feat(bb): towards reduced polynomial memory usage #7990
Changes from 66 commits
88cb0b4
3714e2e
3ddc166
67de114
9421093
b2cb0d8
ac72179
e3b8713
f9ce86b
d528cc0
428f0de
30c8e5c
496fdae
f9c7931
1552197
4f1e519
eaa6a34
50f59fe
d79914e
d83219e
cdeedc6
24b35f3
a3d18fb
23ff433
45ee50d
b3868e2
b6f6968
f3a7f60
8e4ece7
35fa784
5f347ca
da1baa9
d0b3918
99d672a
ebf2a90
6a6795e
5561f67
109146b
bbc3b84
55ded5b
549edb2
98bc35c
abff423
7fba8bd
a8023b0
0869084
70d194e
6932aac
195d845
8698df4
15d9184
44bd924
e682488
88c0c28
ede7f41
44c7f78
fdd2b29
e0e0153
95022c2
81503b3
9623ecf
5e99416
2770bcc
65f76b0
6ce46c4
d3a4498
d63fea1
73fa590
5616be3
bce13aa
57d4d81
956a794
cac72b1
bb6b7cc
d6d08d0
4a871b2
cf62795
01efa1f
5c8418a
cb8f5e6
536ebbe
528142a
c371e37
069c007
b1d4b79
84d7b74
94e6df3
7dc942b
25f64be
bf21caf
1b16007
55758d0
485d627
39a9525
47c7736
84cb602
00981cb
686c4a5
c3e37c5
ac15f5b
7dae750
a9c2617
49fa0ad
e791c97
2be10cd
6386e95
34425ea
70f03c5
7e518f8
80d568b
06c61cd
dd7e461
d720c55
e55bb85
1d306e8
52027b3
782f472
971a388
7dbd1d9
f5514c3
41c01c6
7f4ea77
e5bcec1
d1c7702
1457a3c
e307d13
5bbff94
c70ef6f
0f0b86f
c81ec3b
4192629
0e6c1b6
200a243
9573c93
2c6a6c6
4a2e3a8
f5b430e
27f1d36
2646dbc
f51042a
44dd297
e72cdbd
95e1c5e
60d111d
8bb094d
4e9e400
6047855
e16f609
7befd6d
f0e9ecd
964384c
b2a5423
bd0b6dc
a4f34cb
e1d8f4d
8f5af24
0b69ca6
5efcd7e
be4a79e
8adb0b6
213cc28
a45ab52
72d286c
92926cf
0ffcee2
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -7,9 +7,11 @@ | |
* simplify the codebase. | ||
*/ | ||
|
||
#include "barretenberg/common/debug_log.hpp" | ||
#include "barretenberg/common/op_count.hpp" | ||
#include "barretenberg/ecc/scalar_multiplication/scalar_multiplication.hpp" | ||
#include "barretenberg/numeric/bitop/pow.hpp" | ||
#include "barretenberg/polynomials/polynomial.hpp" | ||
#include "barretenberg/polynomials/polynomial_arithmetic.hpp" | ||
#include "barretenberg/srs/factories/crs_factory.hpp" | ||
#include "barretenberg/srs/factories/file_crs_factory.hpp" | ||
|
@@ -67,7 +69,7 @@ template <class Curve> class CommitmentKey { | |
* @param polynomial a univariate polynomial p(X) = ∑ᵢ aᵢ⋅Xⁱ | ||
* @return Commitment computed as C = [p(x)] = ∑ᵢ aᵢ⋅Gᵢ | ||
*/ | ||
Commitment commit(std::span<const Fr> polynomial) | ||
Commitment commit(PolynomialSpan<const Fr> polynomial) | ||
{ | ||
BB_OP_COUNT_TIME(); | ||
const size_t degree = polynomial.size(); | ||
|
@@ -78,8 +80,16 @@ template <class Curve> class CommitmentKey { | |
srs->get_monomial_size()); | ||
ASSERT(false); | ||
} | ||
return scalar_multiplication::pippenger_unsafe<Curve>( | ||
const_cast<Fr*>(polynomial.data()), srs->get_monomial_points(), degree, pippenger_runtime_state); | ||
|
||
// Extract the precomputed point table (contains raw SRS points at even indices and the corresponding | ||
// endomorphism point (\beta*x, -y) at odd indices). We offset by polynomial.start_index * 2 to align | ||
// with our polynomial span. | ||
G1* point_table = srs->get_monomial_points() + polynomial.start_index * 2; | ||
ludamad marked this conversation as resolved.
Show resolved
Hide resolved
|
||
DEBUG_LOG_ALL(polynomial.span); | ||
Commitment point = scalar_multiplication::pippenger_unsafe<Curve>( | ||
polynomial.data(), point_table, degree, pippenger_runtime_state); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Should actually update the name of the variable |
||
DEBUG_LOG(point); | ||
return point; | ||
}; | ||
|
||
/** | ||
|
@@ -92,19 +102,20 @@ template <class Curve> class CommitmentKey { | |
* @param polynomial | ||
* @return Commitment | ||
*/ | ||
Commitment commit_sparse(std::span<const Fr> polynomial) | ||
Commitment commit_sparse(PolynomialSpan<const Fr> polynomial) | ||
{ | ||
BB_OP_COUNT_TIME(); | ||
const size_t degree = polynomial.size(); | ||
ASSERT(degree <= srs->get_monomial_size()); | ||
const size_t poly_size = polynomial.size(); | ||
ASSERT(poly_size + polynomial.start_index * 2 <= srs->get_monomial_size()); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Not related to this PR but there really should be an srs->size() that returns the size you'd expect There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. at least now you can do srs->get_monomial_points.size() |
||
|
||
// Extract the precomputed point table (contains raw SRS points at even indices and the corresponding | ||
// endomorphism point (\beta*x, -y) at odd indices). | ||
G1* point_table = srs->get_monomial_points(); | ||
// endomorphism point (\beta*x, -y) at odd indices). We offset by polynomial.start_index * 2 to align | ||
// with our polynomial spann. | ||
G1* point_table = srs->get_monomial_points() + polynomial.start_index * 2; | ||
|
||
// Define structures needed to multithread the extraction of non-zero inputs | ||
const size_t num_threads = degree >= get_num_cpus_pow2() ? get_num_cpus_pow2() : 1; | ||
const size_t block_size = degree / num_threads; | ||
const size_t num_threads = poly_size >= get_num_cpus_pow2() ? get_num_cpus_pow2() : 1; | ||
const size_t block_size = poly_size / num_threads; | ||
std::vector<std::vector<Fr>> thread_scalars(num_threads); | ||
std::vector<std::vector<G1>> thread_points(num_threads); | ||
|
||
|
@@ -115,7 +126,7 @@ template <class Curve> class CommitmentKey { | |
|
||
for (size_t idx = start; idx < end; ++idx) { | ||
|
||
const Fr& scalar = polynomial[idx]; | ||
const Fr& scalar = polynomial.span[idx]; | ||
|
||
if (!scalar.is_zero()) { | ||
thread_scalars[thread_idx].emplace_back(scalar); | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -44,12 +44,13 @@ template <class Curve> class GeminiTest : public CommitmentTest<Curve> { | |
const size_t num_unshifted = multilinear_polynomials.size(); | ||
const size_t num_shifted = multilinear_polynomials_to_be_shifted.size(); | ||
for (size_t i = 0; i < num_unshifted; ++i) { | ||
batched_unshifted.add_scaled(multilinear_polynomials[i], rhos[i]); | ||
batched_unshifted.add_scaled({ /*start index*/ 0, multilinear_polynomials[i] }, rhos[i]); | ||
batched_commitment_unshifted += multilinear_commitments[i] * rhos[i]; | ||
} | ||
for (size_t i = 0; i < num_shifted; ++i) { | ||
size_t rho_idx = num_unshifted + i; | ||
batched_to_be_shifted.add_scaled(multilinear_polynomials_to_be_shifted[i], rhos[rho_idx]); | ||
batched_to_be_shifted.add_scaled({ /*start index*/ 0, multilinear_polynomials_to_be_shifted[i] }, | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I'm hopeful that we can in general make tradeoffs on methods like There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Not sure I understand here, there is that check, but everything has start indices now whereas 0 was implicit before so I passed it There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Ah I get it. Will experiment There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I have made it more strict as discussed |
||
rhos[rho_idx]); | ||
batched_commitment_to_be_shifted += multilinear_commitments_to_be_shifted[i] * rhos[rho_idx]; | ||
} | ||
|
||
|
@@ -119,7 +120,7 @@ TYPED_TEST(GeminiTest, Single) | |
|
||
// Collect multilinear polynomials evaluations, and commitments for input to prover/verifier | ||
std::vector<Fr> multilinear_evaluations = { eval }; | ||
std::vector<std::span<Fr>> multilinear_polynomials = { poly }; | ||
std::vector<std::span<Fr>> multilinear_polynomials = { poly.coeffs() }; | ||
std::vector<std::span<Fr>> multilinear_polynomials_to_be_shifted = {}; | ||
std::vector<GroupElement> multilinear_commitments = { commitment }; | ||
std::vector<GroupElement> multilinear_commitments_to_be_shifted = {}; | ||
|
@@ -145,15 +146,15 @@ TYPED_TEST(GeminiTest, SingleShift) | |
|
||
// shiftable polynomial must have 0 as last coefficient | ||
auto poly = this->random_polynomial(n); | ||
poly[0] = Fr::zero(); | ||
poly.at(0) = Fr::zero(); | ||
|
||
auto commitment = this->commit(poly); | ||
auto eval_shift = poly.evaluate_mle(u, true); | ||
|
||
// Collect multilinear polynomials evaluations, and commitments for input to prover/verifier | ||
std::vector<Fr> multilinear_evaluations = { eval_shift }; | ||
std::vector<std::span<Fr>> multilinear_polynomials = {}; | ||
std::vector<std::span<Fr>> multilinear_polynomials_to_be_shifted = { poly }; | ||
std::vector<std::span<Fr>> multilinear_polynomials_to_be_shifted = { poly.coeffs() }; | ||
std::vector<GroupElement> multilinear_commitments = {}; | ||
std::vector<GroupElement> multilinear_commitments_to_be_shifted = { commitment }; | ||
|
||
|
@@ -187,7 +188,7 @@ TYPED_TEST(GeminiTest, Double) | |
|
||
// Collect multilinear polynomials evaluations, and commitments for input to prover/verifier | ||
std::vector<Fr> multilinear_evaluations = { eval1, eval2 }; | ||
std::vector<std::span<Fr>> multilinear_polynomials = { poly1, poly2 }; | ||
std::vector<std::span<Fr>> multilinear_polynomials = { poly1.coeffs(), poly2.coeffs() }; | ||
std::vector<std::span<Fr>> multilinear_polynomials_to_be_shifted = {}; | ||
std::vector<GroupElement> multilinear_commitments = { commitment1, commitment2 }; | ||
std::vector<GroupElement> multilinear_commitments_to_be_shifted = {}; | ||
|
@@ -212,8 +213,7 @@ TYPED_TEST(GeminiTest, DoubleWithShift) | |
auto u = this->random_evaluation_point(log_n); | ||
|
||
auto poly1 = this->random_polynomial(n); | ||
auto poly2 = this->random_polynomial(n); | ||
poly2[0] = Fr::zero(); // necessary for polynomial to be 'shiftable' | ||
auto poly2 = this->random_polynomial(n).unshifted(); // make 'shiftable' | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Not sure how I feel about this unshifted() method. Seems only to be used in tests at the moment. I see you have a WORKTODO in it so maybe its going to go away? My concern is that it's either 'throwing away' the last coefficient or resulting a poly that has degree +1 the 'nominal' size of other polynomials. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. It's a test-only method - I can make sure it has the right size There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Moving this functionality to random |
||
|
||
auto commitment1 = this->commit(poly1); | ||
auto commitment2 = this->commit(poly2); | ||
|
@@ -224,8 +224,8 @@ TYPED_TEST(GeminiTest, DoubleWithShift) | |
|
||
// Collect multilinear polynomials evaluations, and commitments for input to prover/verifier | ||
std::vector<Fr> multilinear_evaluations = { eval1, eval2, eval2_shift }; | ||
std::vector<std::span<Fr>> multilinear_polynomials = { poly1, poly2 }; | ||
std::vector<std::span<Fr>> multilinear_polynomials_to_be_shifted = { poly2 }; | ||
std::vector<std::span<Fr>> multilinear_polynomials = { poly1.coeffs(), poly2.coeffs() }; | ||
std::vector<std::span<Fr>> multilinear_polynomials_to_be_shifted = { poly2.coeffs() }; | ||
std::vector<GroupElement> multilinear_commitments = { commitment1, commitment2 }; | ||
std::vector<GroupElement> multilinear_commitments_to_be_shifted = { commitment2 }; | ||
|
||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -161,7 +161,8 @@ template <typename Curve_> class IPA { | |
|
||
// Step 4. | ||
// Set initial vector a to the polynomial monomial coefficients and load vector G | ||
auto a_vec = polynomial; | ||
// Ensure the polynomial copy is fully-formed | ||
auto a_vec = polynomial.expand(polynomial.start_index()); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. It took me a couple of minutes to understand what this was doing. I'm still not totally sure I understand. Seems like it will make a copy of the poly but ensure that the mem block extends all the way to zero. What about the end of the poly? Do we not need to do the same there? I wonder if in some of these situations we can just do something a bit dumber but easier to follow like There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. .full() is a good shout - but I took up the conversation on slack if this shiftable model is even worth it. It sounded conceptually nice to have shiftable polys just have start_index = 1, but not so much in practice |
||
auto* srs_elements = ck->srs->get_monomial_points(); | ||
std::vector<Commitment> G_vec_local(poly_length); | ||
|
||
|
@@ -212,16 +213,16 @@ template <typename Curve_> class IPA { | |
}, thread_heuristics::FF_ADDITION_COST * 2 + thread_heuristics::FF_MULTIPLICATION_COST * 2); | ||
// Sum inner product contributions computed in parallel and unpack the std::pair | ||
auto [inner_prod_L, inner_prod_R] = sum_pairs(inner_prods); | ||
// Step 6.a (using letters, because doxygen automaticall converts the sublist counters to letters :( ) | ||
// Step 6.a (using letters, because doxygen automatically converts the sublist counters to letters :( ) | ||
// L_i = < a_vec_lo, G_vec_hi > + inner_prod_L * aux_generator | ||
L_i = bb::scalar_multiplication::pippenger_without_endomorphism_basis_points<Curve>( | ||
&a_vec[0], &G_vec_local[round_size], round_size, ck->pippenger_runtime_state); | ||
a_vec.data(), &G_vec_local[round_size], round_size, ck->pippenger_runtime_state); | ||
L_i += aux_generator * inner_prod_L; | ||
|
||
// Step 6.b | ||
// R_i = < a_vec_hi, G_vec_lo > + inner_prod_R * aux_generator | ||
R_i = bb::scalar_multiplication::pippenger_without_endomorphism_basis_points<Curve>( | ||
&a_vec[round_size], &G_vec_local[0], round_size, ck->pippenger_runtime_state); | ||
&a_vec.data()[round_size], &G_vec_local[0], round_size, ck->pippenger_runtime_state); | ||
R_i += aux_generator * inner_prod_R; | ||
|
||
// Step 6.c | ||
|
@@ -257,7 +258,7 @@ template <typename Curve_> class IPA { | |
parallel_for_heuristic( | ||
round_size, | ||
[&](size_t j) { | ||
a_vec[j] += round_challenge * a_vec[round_size + j]; | ||
a_vec.at(j) += round_challenge * a_vec[round_size + j]; | ||
b_vec[j] += round_challenge_inv * b_vec[round_size + j]; | ||
}, thread_heuristics::FF_ADDITION_COST * 2 + thread_heuristics::FF_MULTIPLICATION_COST * 2); | ||
} | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -33,9 +33,9 @@ TEST_F(IPATest, CommitOnManyZeroCoeffPolyWorks) | |
constexpr size_t n = 4; | ||
Polynomial p(n); | ||
for (size_t i = 0; i < n - 1; i++) { | ||
p[i] = Fr::zero(); | ||
p.at(i) = Fr::zero(); | ||
} | ||
p[3] = Fr::one(); | ||
p.at(3) = Fr::one(); | ||
GroupElement commitment = this->commit(p); | ||
auto* srs_elements = this->ck()->srs->get_monomial_points(); | ||
GroupElement expected = srs_elements[0] * p[0]; | ||
|
@@ -156,8 +156,8 @@ TEST_F(IPATest, AIsZeroAfterOneRound) | |
size_t n = 4; | ||
auto poly = Polynomial(n); | ||
for (size_t i = 0; i < n / 2; i++) { | ||
poly[i] = Fr::random_element(); | ||
poly[i + (n / 2)] = poly[i]; | ||
poly.at(i) = Fr::random_element(); | ||
poly.at(i + (n / 2)) = poly[i]; | ||
} | ||
auto [x, eval] = this->random_eval(poly); | ||
auto commitment = this->commit(poly); | ||
|
@@ -249,7 +249,7 @@ TEST_F(IPATest, GeminiShplonkIPAWithShift) | |
const auto mle_opening_point = this->random_evaluation_point(log_n); // sometimes denoted 'u' | ||
auto poly1 = this->random_polynomial(n); | ||
auto poly2 = this->random_polynomial(n); | ||
poly2[0] = Fr::zero(); // this property is required of polynomials whose shift is used | ||
poly2.at(0) = Fr::zero(); // this property is required of polynomials whose shift is used | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. So I guess if I tried to write There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. yes |
||
|
||
GroupElement commitment1 = this->commit(poly1); | ||
GroupElement commitment2 = this->commit(poly2); | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
IIUC size() just returns the size of the memory block so the check below needs to be updated accordingly right?