-
Notifications
You must be signed in to change notification settings - Fork 310
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: structured commit #9027
feat: structured commit #9027
Changes from 38 commits
a161c77
c0b4bf3
83e7fd7
e41dc02
5c9a9a7
34c716b
3e07e45
4c1cee3
74aa071
0a82bf3
a2e2246
6cc6c70
c781afd
d644404
8029501
beae61a
a985f1a
5b2023c
4f23262
2f7edea
c242d29
5854d13
d64c8d9
3e0c5ac
064058d
b150ed3
a48eac8
fedbdbb
6b7c824
7b3d0ea
c68db56
2fa5aa4
1059564
5355753
5cb568c
ec25495
551074c
77e7b5b
d6afdee
4004a67
155a6ca
109f6d3
dbc69f2
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 |
---|---|---|
|
@@ -9,7 +9,9 @@ | |
|
||
#include "barretenberg/common/debug_log.hpp" | ||
#include "barretenberg/common/op_count.hpp" | ||
#include "barretenberg/ecc/batched_affine_addition/batched_affine_addition.hpp" | ||
#include "barretenberg/ecc/scalar_multiplication/scalar_multiplication.hpp" | ||
#include "barretenberg/ecc/scalar_multiplication/sorted_msm.hpp" | ||
#include "barretenberg/numeric/bitop/get_msb.hpp" | ||
#include "barretenberg/numeric/bitop/pow.hpp" | ||
#include "barretenberg/polynomials/polynomial.hpp" | ||
|
@@ -164,7 +166,7 @@ template <class Curve> class CommitmentKey { | |
std::vector<Fr> scalars; | ||
std::vector<G1> points; | ||
scalars.reserve(num_nonzero_scalars); | ||
points.reserve(num_nonzero_scalars); | ||
points.reserve(2 * num_nonzero_scalars); // 2x accounts for endomorphism points | ||
for (size_t idx = 0; idx < num_threads; ++idx) { | ||
scalars.insert(scalars.end(), thread_scalars[idx].begin(), thread_scalars[idx].end()); | ||
points.insert(points.end(), thread_points[idx].begin(), thread_points[idx].end()); | ||
|
@@ -173,6 +175,149 @@ template <class Curve> class CommitmentKey { | |
// Call the version of pippenger which assumes all points are distinct | ||
return scalar_multiplication::pippenger_unsafe<Curve>(scalars, points, pippenger_runtime_state); | ||
} | ||
|
||
/** | ||
* @brief Efficiently commit to a polynomial whose nonzero elements are arranged in discrete blocks | ||
* @details Given a set of ranges where the polynomial takes non-zero values, copy the non-zero inputs (scalars, | ||
* points) into contiguous memory and commit to them using the normal pippenger algorithm. Defaults to the | ||
* conventional commit method if the number of non-zero entries is beyond a threshold relative to the full | ||
* polynomial size. | ||
* @note The wire polynomials have the described form when a structured execution trace is in use. | ||
* @warning Method makes a copy of all {point, scalar} pairs that comprise the reduced input. May not be efficient | ||
* in terms of memory or computation for polynomials beyond a certain sparseness threshold. | ||
* | ||
* @param polynomial | ||
* @param active_ranges | ||
* @return Commitment | ||
*/ | ||
Commitment commit_structured(PolynomialSpan<const Fr> polynomial, | ||
const std::vector<std::pair<size_t, size_t>>& active_ranges) | ||
{ | ||
BB_OP_COUNT_TIME(); | ||
ASSERT(polynomial.end_index() <= srs->get_monomial_size()); | ||
|
||
// Percentage of nonzero coefficients beyond which we resort to the conventional commit method | ||
const size_t DENSITY_THRESHOLD = 75; | ||
|
||
size_t total_num_scalars = 0; | ||
for (const auto& range : active_ranges) { | ||
total_num_scalars += range.second - range.first; | ||
} | ||
|
||
// Compute "active" percentage of polynomial; resort to standard commit if appropriate | ||
size_t usage_percentage = total_num_scalars * 100 / polynomial.size(); | ||
if (usage_percentage > DENSITY_THRESHOLD) { | ||
return commit(polynomial); | ||
} | ||
|
||
// Extract the precomputed point table (contains raw SRS points at even indices and the corresponding | ||
// endomorphism point (\beta*x, -y) at odd indices). | ||
std::span<G1> point_table = srs->get_monomial_points(); | ||
|
||
std::vector<Fr> scalars; | ||
scalars.reserve(total_num_scalars); | ||
for (const auto& range : active_ranges) { | ||
auto start = &polynomial[range.first]; | ||
auto end = &polynomial[range.second]; | ||
scalars.insert(scalars.end(), start, end); | ||
} | ||
std::vector<G1> points; | ||
points.reserve(total_num_scalars * 2); | ||
for (const auto& range : active_ranges) { | ||
auto start = &point_table[2 * range.first]; | ||
auto end = &point_table[2 * range.second]; | ||
points.insert(points.end(), start, end); | ||
} | ||
|
||
// Call pippenger | ||
return scalar_multiplication::pippenger_unsafe<Curve>(scalars, points, pippenger_runtime_state); | ||
} | ||
|
||
/** | ||
* @brief Efficiently commit to a polynomial with discrete blocks of arbitrary elements and constant elements | ||
* @details Similar to method commit_structured() except the complement blocks cantain non-zero constant values | ||
* (which are assumed to differ between blocks). This is exactly the structure of the permutation grand product | ||
* polynomial z_perm when a structured execution trace is in use. | ||
* @warning Requires a copy of all {point, scalar} pairs (including endo points) corresponding to the primary blocks | ||
* and a copy of all of the points (without endo points) corresponding to their complement. | ||
* | ||
* @param polynomial | ||
* @param active_ranges | ||
* @return Commitment | ||
*/ | ||
Commitment commit_structured_with_nonzero_complement(PolynomialSpan<const Fr> polynomial, | ||
const std::vector<std::pair<size_t, size_t>>& active_ranges) | ||
{ | ||
BB_OP_COUNT_TIME(); | ||
ASSERT(polynomial.end_index() <= srs->get_monomial_size()); | ||
|
||
using BatchedAddition = BatchedAffineAddition<Curve>; | ||
|
||
// Percentage of constant coefficients beyond which we resort to the conventional commit method | ||
const size_t DENSITY_THRESHOLD = 50; | ||
|
||
// Compute the active range complement over which the polynomial is assumed to be constant within each range | ||
std::vector<std::pair<size_t, size_t>> active_ranges_complement; | ||
for (size_t i = 0; i < active_ranges.size(); ++i) { | ||
size_t start = active_ranges[i].second; | ||
size_t end = active_ranges[i + 1].first; | ||
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. doesn't 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 does indeed, thanks. It was working correctly because the bad value gets immediately set to the correct thing on the line below but I've updated the loop to not overindex |
||
active_ranges_complement.emplace_back(start, end); | ||
} | ||
active_ranges_complement.back().second = polynomial.end_index(); // Extend final range to end of polynomial | ||
|
||
size_t total_num_complement_scalars = 0; | ||
for (const auto& range : active_ranges_complement) { | ||
total_num_complement_scalars += range.second - range.first; | ||
} | ||
|
||
// Extract the precomputed point table (contains raw SRS points at even indices and the corresponding | ||
// endomorphism point (\beta*x, -y) at odd indices). | ||
std::span<G1> point_table = srs->get_monomial_points(); | ||
|
||
// Compute complement percentage of polynomial; resort to standard commit if appropriate | ||
size_t complement_percentage = total_num_complement_scalars * 100 / polynomial.size(); | ||
if (complement_percentage < DENSITY_THRESHOLD) { | ||
return commit(polynomial); | ||
} | ||
|
||
Commitment active_region_contribution = commit_structured(polynomial, active_ranges); | ||
|
||
// Copy the raw SRS points corresponding to the constant regions into contiguous memory | ||
// TODO(https://github.com/AztecProtocol/barretenberg/issues/1131): Peak memory usage could be improved by | ||
// performing this copy and the subsequent summation as a precomputation prior to constructing the point table. | ||
std::vector<G1> points; | ||
points.reserve(2 * total_num_complement_scalars); | ||
for (const auto& range : active_ranges_complement) { | ||
size_t start = 2 * range.first; | ||
size_t end = 2 * range.second; | ||
for (size_t i = start; i < end; i += 2) { | ||
points.emplace_back(point_table[i]); | ||
} | ||
} | ||
|
||
// Populate the set of unique scalars with first coeff from each range (values assumed constant over each range) | ||
// Compute the number of points in each sequence to be summed | ||
std::vector<Fr> unique_scalars; | ||
std::vector<size_t> sequence_counts; | ||
for (const auto& range : active_ranges_complement) { | ||
if (range.second - range.first > 0) { | ||
// info("unique scalar = ", polynomial.span[range.first]); | ||
unique_scalars.emplace_back(polynomial.span[range.first]); | ||
sequence_counts.emplace_back(range.second - range.first); | ||
} | ||
} | ||
|
||
// Reduce each sequence to a single point | ||
auto reduced_points = BatchedAddition::add_in_place(points, sequence_counts); | ||
|
||
// Directly compute the full commitment given the reduced inputs | ||
Commitment result = active_region_contribution; | ||
for (auto [scalar, point] : zip_view(unique_scalars, reduced_points)) { | ||
result = result + point * scalar; | ||
} | ||
|
||
return result; | ||
} | ||
}; | ||
|
||
} // namespace bb |
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.
const here and in many other places