-
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
chore: minor Gemini refactor to prep for opening k-shifts #11393
Changes from all commits
990d978
4175a70
abf2fc1
b3ffdc2
f64b854
3cce40e
e5e468e
abc703b
9b5d4ec
b50cf3b
0cea8ce
6a46d8f
c46f49f
183fa49
a5ce95a
0433d5e
14cf0d4
07ae83e
4b9b68e
921b857
0b606d8
3fe0687
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 |
---|---|---|
|
@@ -51,11 +51,12 @@ std::vector<typename GeminiProver_<Curve>::Claim> GeminiProver_<Curve>::prove( | |
RefSpan<Polynomial> concatenated_polynomials, | ||
const std::vector<RefVector<Polynomial>>& groups_to_be_concatenated, | ||
bool has_zk) | ||
|
||
{ | ||
const size_t log_n = numeric::get_msb(static_cast<uint32_t>(circuit_size)); | ||
const size_t n = 1 << log_n; | ||
|
||
const bool has_concatenations = concatenated_polynomials.size() > 0; | ||
|
||
// Compute batched polynomials | ||
Polynomial batched_unshifted(n); | ||
Polynomial batched_to_be_shifted = Polynomial::shiftable(n); | ||
|
@@ -78,6 +79,7 @@ std::vector<typename GeminiProver_<Curve>::Claim> GeminiProver_<Curve>::prove( | |
// ρ⁰ is used to batch the hiding polynomial | ||
rho_challenge *= rho; | ||
} | ||
|
||
for (size_t i = 0; i < f_polynomials.size(); i++) { | ||
batched_unshifted.add_scaled(f_polynomials[i], rho_challenge); | ||
rho_challenge *= rho; | ||
|
@@ -90,34 +92,41 @@ std::vector<typename GeminiProver_<Curve>::Claim> GeminiProver_<Curve>::prove( | |
size_t num_groups = groups_to_be_concatenated.size(); | ||
size_t num_chunks_per_group = groups_to_be_concatenated.empty() ? 0 : groups_to_be_concatenated[0].size(); | ||
|
||
// Allocate space for the groups to be concatenated and for the concatenated polynomials | ||
Polynomial batched_concatenated(n); | ||
// If needed, allocate space for the groups to be concatenated and for the concatenated polynomials | ||
Polynomial batched_concatenated; | ||
std::vector<Polynomial> batched_group; | ||
for (size_t i = 0; i < num_chunks_per_group; ++i) { | ||
batched_group.push_back(Polynomial(n)); | ||
} | ||
if (has_concatenations) { | ||
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. maybe isolate to compute_batched_concatenated(...) method? 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. and call it below when computing A_0 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. yeah I agree the concat stuff should likely be handled there as well - I originally left it out because I know changes are coming there and I wasn't sure it would make life easier for Mara to mess with it. There is a follow on coming soon (likely today) - I'll handle it there |
||
batched_concatenated = Polynomial(n); | ||
for (size_t i = 0; i < num_chunks_per_group; ++i) { | ||
batched_group.push_back(Polynomial(n)); | ||
} | ||
|
||
for (size_t i = 0; i < num_groups; ++i) { | ||
batched_concatenated.add_scaled(concatenated_polynomials[i], rho_challenge); | ||
for (size_t j = 0; j < num_chunks_per_group; ++j) { | ||
batched_group[j].add_scaled(groups_to_be_concatenated[i][j], rho_challenge); | ||
for (size_t i = 0; i < num_groups; ++i) { | ||
batched_concatenated.add_scaled(concatenated_polynomials[i], rho_challenge); | ||
for (size_t j = 0; j < num_chunks_per_group; ++j) { | ||
batched_group[j].add_scaled(groups_to_be_concatenated[i][j], rho_challenge); | ||
} | ||
rho_challenge *= rho; | ||
} | ||
rho_challenge *= rho; | ||
} | ||
|
||
auto fold_polynomials = compute_fold_polynomials(log_n, | ||
multilinear_challenge, | ||
std::move(batched_unshifted), | ||
std::move(batched_to_be_shifted), | ||
std::move(batched_concatenated)); | ||
// Construct the batched polynomial A₀(X) = F(X) + G↺(X) = F(X) + G(X)/X | ||
Polynomial A_0 = batched_unshifted; | ||
A_0 += batched_to_be_shifted.shifted(); | ||
if (has_concatenations) { // If proving for translator, add contribution of the batched concatenation polynomials | ||
A_0 += batched_concatenated; | ||
} | ||
|
||
// Construct the d-1 Gemini foldings of A₀(X) | ||
std::vector<Polynomial> fold_polynomials = compute_fold_polynomials(log_n, multilinear_challenge, A_0); | ||
|
||
// TODO(https://github.com/AztecProtocol/barretenberg/issues/1159): Decouple constants from primitives. | ||
for (size_t l = 0; l < CONST_PROOF_SIZE_LOG_N - 1; l++) { | ||
std::string label = "Gemini:FOLD_" + std::to_string(l + 1); | ||
if (l < log_n - 1) { | ||
transcript->send_to_verifier("Gemini:FOLD_" + std::to_string(l + 1), | ||
commitment_key->commit(fold_polynomials[l + 2])); | ||
transcript->send_to_verifier(label, commitment_key->commit(fold_polynomials[l])); | ||
} else { | ||
transcript->send_to_verifier("Gemini:FOLD_" + std::to_string(l + 1), Commitment::one()); | ||
transcript->send_to_verifier(label, Commitment::one()); | ||
} | ||
} | ||
const Fr r_challenge = transcript->template get_challenge<Fr>("Gemini:r"); | ||
|
@@ -131,14 +140,20 @@ std::vector<typename GeminiProver_<Curve>::Claim> GeminiProver_<Curve>::prove( | |
throw_or_abort("Gemini evaluation challenge is in the SmallSubgroup."); | ||
} | ||
|
||
std::vector<Claim> claims = | ||
compute_fold_polynomial_evaluations(log_n, std::move(fold_polynomials), r_challenge, std::move(batched_group)); | ||
// Compute polynomials A₀₊(X) = F(X) + G(X)/r and A₀₋(X) = F(X) - G(X)/r | ||
auto [A_0_pos, A_0_neg] = compute_partially_evaluated_batch_polynomials( | ||
log_n, std::move(batched_unshifted), std::move(batched_to_be_shifted), r_challenge, batched_group); | ||
|
||
// Construct claims for the d + 1 univariate evaluations A₀₊(r), A₀₋(-r), and Foldₗ(−r^{2ˡ}), l = 1, ..., d-1 | ||
std::vector<Claim> claims = construct_univariate_opening_claims( | ||
log_n, std::move(A_0_pos), std::move(A_0_neg), std::move(fold_polynomials), r_challenge); | ||
|
||
for (size_t l = 1; l <= CONST_PROOF_SIZE_LOG_N; l++) { | ||
std::string label = "Gemini:a_" + std::to_string(l); | ||
if (l <= log_n) { | ||
transcript->send_to_verifier("Gemini:a_" + std::to_string(l), claims[l].opening_pair.evaluation); | ||
transcript->send_to_verifier(label, claims[l].opening_pair.evaluation); | ||
} else { | ||
transcript->send_to_verifier("Gemini:a_" + std::to_string(l), Fr::zero()); | ||
transcript->send_to_verifier(label, Fr::zero()); | ||
} | ||
} | ||
|
||
|
@@ -148,48 +163,24 @@ std::vector<typename GeminiProver_<Curve>::Claim> GeminiProver_<Curve>::prove( | |
/** | ||
* @brief Computes d-1 fold polynomials Fold_i, i = 1, ..., d-1 | ||
* | ||
* @param mle_opening_point multilinear opening point 'u' | ||
* @param batched_unshifted F(X) = ∑ⱼ ρʲ fⱼ(X) . | ||
* @param batched_to_be_shifted G(X) = ∑ⱼ ρᵏ⁺ʲ gⱼ(X) | ||
* @param batched_concatenated The sum of batched concatenated polynomial, | ||
* @param multilinear_challenge multilinear opening point 'u' | ||
* @param A_0 = F(X) + G↺(X) = F(X) + G(X)/X | ||
* @return std::vector<Polynomial> | ||
*/ | ||
template <typename Curve> | ||
std::vector<typename GeminiProver_<Curve>::Polynomial> GeminiProver_<Curve>::compute_fold_polynomials( | ||
const size_t num_variables, | ||
std::span<const Fr> mle_opening_point, | ||
Polynomial&& batched_unshifted, | ||
Polynomial&& batched_to_be_shifted, | ||
Polynomial&& batched_concatenated) | ||
const size_t log_n, std::span<const Fr> multilinear_challenge, const Polynomial& A_0) | ||
{ | ||
const size_t num_threads = get_num_cpus_pow2(); | ||
constexpr size_t efficient_operations_per_thread = 64; // A guess of the number of operation for which there | ||
// would be a point in sending them to a separate thread | ||
|
||
// Allocate space for m+1 Fold polynomials | ||
// | ||
// The first two are populated here with the batched unshifted and to-be-shifted polynomial respectively. | ||
// They will eventually contain the full batched polynomial A₀ partially evaluated at the challenges r,-r. | ||
// This function populates the other m-1 polynomials with the foldings of A₀. | ||
// Reserve and allocate space for m-1 Fold polynomials, the foldings of the full batched polynomial A₀ | ||
std::vector<Polynomial> fold_polynomials; | ||
fold_polynomials.reserve(num_variables + 1); | ||
|
||
// F(X) = ∑ⱼ ρʲ fⱼ(X) and G(X) = ∑ⱼ ρᵏ⁺ʲ gⱼ(X) | ||
Polynomial& batched_F = fold_polynomials.emplace_back(std::move(batched_unshifted)); | ||
Polynomial& batched_G = fold_polynomials.emplace_back(std::move(batched_to_be_shifted)); | ||
constexpr size_t offset_to_folded = 2; // Offset because of F an G | ||
// A₀(X) = F(X) + G↺(X) = F(X) + G(X)/X. | ||
Polynomial A_0 = batched_F; | ||
|
||
// If proving the opening for translator, add a non-zero contribution of the batched concatenation polynomials | ||
A_0 += batched_concatenated; | ||
|
||
A_0 += batched_G.shifted(); | ||
|
||
// Allocate everything before parallel computation | ||
for (size_t l = 0; l < num_variables - 1; ++l) { | ||
fold_polynomials.reserve(log_n - 1); | ||
for (size_t l = 0; l < log_n - 1; ++l) { | ||
// size of the previous polynomial/2 | ||
const size_t n_l = 1 << (num_variables - l - 1); | ||
const size_t n_l = 1 << (log_n - l - 1); | ||
|
||
// A_l_fold = Aₗ₊₁(X) = (1-uₗ)⋅even(Aₗ)(X) + uₗ⋅odd(Aₗ)(X) | ||
fold_polynomials.emplace_back(Polynomial(n_l)); | ||
|
@@ -199,9 +190,9 @@ std::vector<typename GeminiProver_<Curve>::Polynomial> GeminiProver_<Curve>::com | |
// in the first iteration, we take the batched polynomial | ||
// in the next iteration, it is the previously folded one | ||
auto A_l = A_0.data(); | ||
for (size_t l = 0; l < num_variables - 1; ++l) { | ||
for (size_t l = 0; l < log_n - 1; ++l) { | ||
// size of the previous polynomial/2 | ||
const size_t n_l = 1 << (num_variables - l - 1); | ||
const size_t n_l = 1 << (log_n - l - 1); | ||
|
||
// Use as many threads as it is useful so that 1 thread doesn't process 1 element, but make sure that there is | ||
// at least 1 | ||
|
@@ -210,11 +201,11 @@ std::vector<typename GeminiProver_<Curve>::Polynomial> GeminiProver_<Curve>::com | |
size_t chunk_size = n_l / num_used_threads; | ||
size_t last_chunk_size = (n_l % chunk_size) ? (n_l % num_used_threads) : chunk_size; | ||
|
||
// Openning point is the same for all | ||
const Fr u_l = mle_opening_point[l]; | ||
// Opening point is the same for all | ||
const Fr u_l = multilinear_challenge[l]; | ||
|
||
// A_l_fold = Aₗ₊₁(X) = (1-uₗ)⋅even(Aₗ)(X) + uₗ⋅odd(Aₗ)(X) | ||
auto A_l_fold = fold_polynomials[l + offset_to_folded].data(); | ||
auto A_l_fold = fold_polynomials[l].data(); | ||
|
||
parallel_for(num_used_threads, [&](size_t i) { | ||
size_t current_chunk_size = (i == (num_used_threads - 1)) ? last_chunk_size : chunk_size; | ||
|
@@ -235,51 +226,31 @@ std::vector<typename GeminiProver_<Curve>::Polynomial> GeminiProver_<Curve>::com | |
}; | ||
|
||
/** | ||
* @brief Computes/aggragates d+1 Fold polynomials and their opening pairs (challenge, evaluation) | ||
* | ||
* @details This function assumes that, upon input, last d-1 entries in fold_polynomials are Fold_i. | ||
* The first two entries are assumed to be, respectively, the batched unshifted and batched to-be-shifted | ||
* polynomials F(X) = ∑ⱼ ρʲfⱼ(X) and G(X) = ∑ⱼ ρᵏ⁺ʲ gⱼ(X). This function completes the computation | ||
* of the first two Fold polynomials as F + G/r and F - G/r. It then evaluates each of the d+1 | ||
* fold polynomials at, respectively, the points r, rₗ = r^{2ˡ} for l = 0, 1, ..., d-1. | ||
* @brief Computes partially evaluated batched polynomials A₀₊(X) = F(X) + G(X)/r and A₀₋(X) = F(X) - G(X)/r | ||
* | ||
* @param mle_opening_point u = (u₀,...,uₘ₋₁) is the MLE opening point | ||
* @param fold_polynomials vector of polynomials whose first two elements are F(X) = ∑ⱼ ρʲfⱼ(X) | ||
* and G(X) = ∑ⱼ ρᵏ⁺ʲ gⱼ(X), and the next d-1 elements are Fold_i, i = 1, ..., d-1. | ||
* @param r_challenge univariate opening challenge | ||
* @param batched_F F(X) = ∑ⱼ ρʲfⱼ(X) | ||
* @param batched_G G(X) = ∑ⱼ ρᵏ⁺ʲ gⱼ(X) | ||
* @param r_challenge | ||
* @param batched_groups_to_be_concatenated | ||
* @return {A₀₊(X), A₀₋(X)} | ||
*/ | ||
template <typename Curve> | ||
std::vector<typename GeminiProver_<Curve>::Claim> GeminiProver_<Curve>::compute_fold_polynomial_evaluations( | ||
const size_t num_variables, | ||
std::vector<Polynomial>&& fold_polynomials, | ||
const Fr& r_challenge, | ||
std::vector<Polynomial>&& batched_groups_to_be_concatenated) | ||
std::pair<typename GeminiProver_<Curve>::Polynomial, typename GeminiProver_<Curve>::Polynomial> GeminiProver_<Curve>:: | ||
compute_partially_evaluated_batch_polynomials(const size_t log_n, | ||
Polynomial&& batched_F, | ||
Polynomial&& batched_G, | ||
const Fr& r_challenge, | ||
const std::vector<Polynomial>& batched_groups_to_be_concatenated) | ||
{ | ||
|
||
Polynomial& batched_F = fold_polynomials[0]; // F(X) = ∑ⱼ ρʲ fⱼ(X) | ||
|
||
Polynomial& batched_G = fold_polynomials[1]; // G(X) = ∑ⱼ ρᵏ⁺ʲ gⱼ(X) | ||
|
||
// Compute univariate opening queries rₗ = r^{2ˡ} for l = 0, 1, ..., m-1 | ||
std::vector<Fr> r_squares = gemini::powers_of_evaluation_challenge(r_challenge, num_variables); | ||
Polynomial& A_0_pos = batched_F; // A₀₊ = F | ||
Polynomial A_0_neg = batched_F; // A₀₋ = F | ||
|
||
// Compute G/r | ||
Fr r_inv = r_challenge.invert(); | ||
batched_G *= r_inv; | ||
|
||
// Construct A₀₊ = F + G/r and A₀₋ = F - G/r in place in fold_polynomials | ||
Polynomial tmp = batched_F; | ||
Polynomial& A_0_pos = fold_polynomials[0]; | ||
|
||
// A₀₊(X) = F(X) + G(X)/r, s.t. A₀₊(r) = A₀(r) | ||
A_0_pos += batched_G; | ||
|
||
// Perform a swap so that tmp = G(X)/r and A_0_neg = F(X) | ||
std::swap(tmp, batched_G); | ||
Polynomial& A_0_neg = fold_polynomials[1]; | ||
|
||
// A₀₋(X) = F(X) - G(X)/r, s.t. A₀₋(-r) = A₀(-r) | ||
A_0_neg -= tmp; | ||
A_0_pos += batched_G; // A₀₊ = F + G/r | ||
A_0_neg -= batched_G; // A₀₋ = F - G/r | ||
|
||
// Reconstruct the batched concatenated polynomial from the batched groups, partially evaluated at r and -r and add | ||
// the result to A₀₊(X) and A₀₋(X). Explanation (for simplification assume a single concatenated polynomial): | ||
|
@@ -292,7 +263,7 @@ std::vector<typename GeminiProver_<Curve>::Claim> GeminiProver_<Curve>::compute_ | |
// P | ||
if (!batched_groups_to_be_concatenated.empty()) { | ||
// The "real" size of polynomials in concatenation groups (i.e. the number of non-zero values) | ||
const size_t mini_circuit_size = (1 << num_variables) / batched_groups_to_be_concatenated.size(); | ||
const size_t mini_circuit_size = (1 << log_n) / batched_groups_to_be_concatenated.size(); | ||
Fr current_r_shift_pos = Fr(1); | ||
Fr current_r_shift_neg = Fr(1); | ||
|
||
|
@@ -308,18 +279,57 @@ std::vector<typename GeminiProver_<Curve>::Claim> GeminiProver_<Curve>::compute_ | |
} | ||
} | ||
|
||
std::vector<Claim> opening_claims; | ||
opening_claims.reserve(num_variables + 1); | ||
return { std::move(A_0_pos), std::move(A_0_neg) }; | ||
}; | ||
|
||
// Compute first opening pair {r, A₀(r)} | ||
Fr evaluation = fold_polynomials[0].evaluate(r_challenge); | ||
opening_claims.emplace_back(Claim{ fold_polynomials[0], { r_challenge, evaluation } }); | ||
// Compute the remaining m opening pairs {−r^{2ˡ}, Aₗ(−r^{2ˡ})}, l = 0, ..., m-1. | ||
for (size_t l = 0; l < num_variables; ++l) { | ||
evaluation = fold_polynomials[l + 1].evaluate(-r_squares[l]); | ||
opening_claims.emplace_back(Claim{ fold_polynomials[l + 1], { -r_squares[l], evaluation } }); | ||
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. This line was resulting in a copy of each fold polynomial. Requires |
||
/** | ||
|
||
* | ||
* @param mle_opening_point u = (u₀,...,uₘ₋₁) is the MLE opening point | ||
* @param fold_polynomials vector of polynomials whose first two elements are F(X) = ∑ⱼ ρʲfⱼ(X) | ||
* and G(X) = ∑ⱼ ρᵏ⁺ʲ gⱼ(X), and the next d-1 elements are Fold_i, i = 1, ..., d-1. | ||
* @param r_challenge univariate opening challenge | ||
*/ | ||
|
||
/** | ||
* @brief Computes/aggragates d+1 univariate polynomial opening claims of the form {polynomial, (challenge, evaluation)} | ||
* | ||
* @details The d+1 evaluations are A₀₊(r), A₀₋(-r), and Aₗ(−r^{2ˡ}) for l = 1, ..., d-1, where the Aₗ are the fold | ||
* polynomials. | ||
* | ||
* @param A_0_pos A₀₊ | ||
* @param A_0_neg A₀₋ | ||
* @param fold_polynomials Aₗ, l = 1, ..., d-1 | ||
* @param r_challenge | ||
* @return std::vector<typename GeminiProver_<Curve>::Claim> d+1 univariate opening claims | ||
*/ | ||
template <typename Curve> | ||
std::vector<typename GeminiProver_<Curve>::Claim> GeminiProver_<Curve>::construct_univariate_opening_claims( | ||
const size_t log_n, | ||
Polynomial&& A_0_pos, | ||
Polynomial&& A_0_neg, | ||
std::vector<Polynomial>&& fold_polynomials, | ||
const Fr& r_challenge) | ||
{ | ||
std::vector<Claim> claims; | ||
|
||
// Compute evaluation of partially evaluated batch polynomial (positive) A₀₊(r) | ||
Fr a_0_pos = A_0_pos.evaluate(r_challenge); | ||
claims.emplace_back(Claim{ std::move(A_0_pos), { r_challenge, a_0_pos } }); | ||
// Compute evaluation of partially evaluated batch polynomial (negative) A₀₋(-r) | ||
Fr a_0_neg = A_0_neg.evaluate(-r_challenge); | ||
claims.emplace_back(Claim{ std::move(A_0_neg), { -r_challenge, a_0_neg } }); | ||
|
||
// Compute univariate opening queries rₗ = r^{2ˡ} for l = 0, 1, ..., m-1 | ||
std::vector<Fr> r_squares = gemini::powers_of_evaluation_challenge(r_challenge, log_n); | ||
|
||
// Compute the remaining m opening pairs {−r^{2ˡ}, Aₗ(−r^{2ˡ})}, l = 1, ..., m-1. | ||
for (size_t l = 0; l < log_n - 1; ++l) { | ||
Fr evaluation = fold_polynomials[l].evaluate(-r_squares[l + 1]); | ||
claims.emplace_back(Claim{ std::move(fold_polynomials[l]), { -r_squares[l + 1], evaluation } }); | ||
} | ||
|
||
return opening_claims; | ||
return claims; | ||
}; | ||
|
||
} // 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.
avoid unnecessary allocation of
batched_concatenated