-
Notifications
You must be signed in to change notification settings - Fork 188
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
refactor: more efficient verification with shplonk and gemini #8351
Changes from 15 commits
4a0f8a1
68c964a
872cb61
91b030a
ac3bc44
cf5f1a0
f722c07
4145dc0
7b352c6
70404e8
ed32536
e6bc822
3dec8eb
e1b59b9
b7a65b3
6f03c20
6e52e40
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 |
---|---|---|
|
@@ -88,7 +88,7 @@ template <class Fr> inline std::vector<Fr> powers_of_rho(const Fr rho, const siz | |
* @param num_squares The number of foldings | ||
* @return std::vector<typename Curve::ScalarField> | ||
*/ | ||
template <class Fr> inline std::vector<Fr> squares_of_r(const Fr r, const size_t num_squares) | ||
template <class Fr> inline std::vector<Fr> powers_of_evaluation_challenge(const Fr r, const size_t num_squares) | ||
{ | ||
std::vector<Fr> squares = { r }; | ||
squares.reserve(num_squares); | ||
|
@@ -132,36 +132,25 @@ template <typename Curve> class GeminiVerifier_ { | |
* (Cⱼ, Aⱼ(-r^{2ʲ}), -r^{2}), j = [1, ..., m-1] | ||
*/ | ||
static std::vector<OpeningClaim<Curve>> reduce_verification(std::span<const Fr> mle_opening_point, /* u */ | ||
const Fr batched_evaluation, /* all */ | ||
Fr& batched_evaluation, /* all */ | ||
GroupElement& batched_f, /* unshifted */ | ||
GroupElement& batched_g, /* to-be-shifted */ | ||
auto& transcript) | ||
{ | ||
const size_t num_variables = mle_opening_point.size(); | ||
|
||
// Get polynomials Fold_i, i = 1,...,m-1 from transcript | ||
std::vector<Commitment> commitments; | ||
commitments.reserve(num_variables - 1); | ||
for (size_t i = 0; i < num_variables - 1; ++i) { | ||
auto commitment = | ||
transcript->template receive_from_prover<Commitment>("Gemini:FOLD_" + std::to_string(i + 1)); | ||
commitments.emplace_back(commitment); | ||
} | ||
std::vector<Commitment> commitments = get_gemini_commitments(num_variables, transcript); | ||
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.
|
||
|
||
// compute vector of powers of random evaluation point r | ||
const Fr r = transcript->template get_challenge<Fr>("Gemini:r"); | ||
std::vector<Fr> r_squares = gemini::squares_of_r(r, num_variables); | ||
std::vector<Fr> r_squares = gemini::powers_of_evaluation_challenge(r, num_variables); | ||
|
||
// Get evaluations a_i, i = 0,...,m-1 from transcript | ||
std::vector<Fr> evaluations; | ||
evaluations.reserve(num_variables); | ||
for (size_t i = 0; i < num_variables; ++i) { | ||
auto eval = transcript->template receive_from_prover<Fr>("Gemini:a_" + std::to_string(i)); | ||
evaluations.emplace_back(eval); | ||
} | ||
|
||
std::vector<Fr> evaluations = get_gemini_evaluations(num_variables, transcript); | ||
// Compute evaluation A₀(r) | ||
auto a_0_pos = compute_eval_pos(batched_evaluation, mle_opening_point, r_squares, evaluations); | ||
auto a_0_pos = | ||
compute_gemini_batched_univariate_evaluation(batched_evaluation, mle_opening_point, r_squares, evaluations); | ||
|
||
// C₀_r_pos = ∑ⱼ ρʲ⋅[fⱼ] + r⁻¹⋅∑ⱼ ρᵏ⁺ʲ [gⱼ] | ||
// C₀_r_pos = ∑ⱼ ρʲ⋅[fⱼ] - r⁻¹⋅∑ⱼ ρᵏ⁺ʲ [gⱼ] | ||
|
@@ -183,42 +172,77 @@ template <typename Curve> class GeminiVerifier_ { | |
return fold_polynomial_opening_claims; | ||
} | ||
|
||
private: | ||
static std::vector<Commitment> get_gemini_commitments(size_t log_circuit_size, auto& transcript) | ||
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.
|
||
{ | ||
std::vector<Commitment> gemini_commitments; | ||
gemini_commitments.reserve(log_circuit_size - 1); | ||
for (size_t i = 0; i < log_circuit_size - 1; ++i) { | ||
auto commitment = | ||
transcript->template receive_from_prover<Commitment>("Gemini:FOLD_" + std::to_string(i + 1)); | ||
gemini_commitments.emplace_back(commitment); | ||
} | ||
return gemini_commitments; | ||
} | ||
static std::vector<Fr> get_gemini_evaluations(size_t log_circuit_size, auto& transcript) | ||
{ | ||
std::vector<Fr> gemini_evaluations; | ||
gemini_evaluations.reserve(log_circuit_size); | ||
for (size_t i = 0; i < log_circuit_size; ++i) { | ||
auto evaluation = transcript->template receive_from_prover<Fr>("Gemini:a_" + std::to_string(i)); | ||
gemini_evaluations.emplace_back(evaluation); | ||
} | ||
return gemini_evaluations; | ||
} | ||
|
||
/** | ||
* @brief Compute the expected evaluation of the univariate commitment to the batched polynomial. | ||
* | ||
* @param batched_mle_eval The evaluation of the folded polynomials | ||
* @param mle_vars MLE opening point u | ||
* @param r_squares squares of r, r², ..., r^{2ᵐ⁻¹} | ||
* @param fold_polynomial_evals series of Aᵢ₋₁(−r^{2ⁱ⁻¹}) | ||
* @return evaluation A₀(r) | ||
* Compute the evaluation \f$ A_0(r) = \sum \rho^i \cdot f_i + \frac{1}{r} \cdot \sum \rho^{i+k} g_i \f$, where \f$ | ||
* k \f$ is the number of "unshifted" commitments. | ||
* | ||
* @details Initialize \f$ A_{d}(r) \f$ with the batched evaluation \f$ \sum \rho^i f_i(\vec{u}) + \sum \rho^{i+k} | ||
* g_i(\vec{u}) \f$. The folding property ensures that | ||
* \f{align}{ | ||
* A_\ell\left(r^{2^\ell}\right) = (1 - u_{\ell-1}) \cdot \frac{A_{\ell-1}\left(r^{2^{\ell-1}}\right) + | ||
* A_{\ell-1}\left(-r^{2^{\ell-1}}\right)}{2} | ||
* + u_{\ell-1} \cdot \frac{A_{\ell-1}\left(r^{2^{\ell-1}}\right) - | ||
* A_{\ell-1}\left(-r^{2^{\ell-1}}\right)}{2r^{2^{\ell-1}}} | ||
* \f} | ||
* Therefore, the verifier can recover \f$ A_0(r) \f$ by solving several linear equations. | ||
* | ||
* @param batched_mle_eval The evaluation of the batched polynomial at \f$ (u_0, \ldots, u_{d-1})\f$. | ||
* @param evaluation_point Evaluation point \f$ (u_0, \ldots, u_{d-1}) \f$. | ||
* @param challenge_powers Powers of \f$ r \f$, \f$ r^2 \), ..., \( r^{2^{m-1}} \f$. | ||
* @param fold_polynomial_evals Evaluations \f$ A_{i-1}(-r^{2^{i-1}}) \f$. | ||
* @return Evaluation \f$ A_0(r) \f$. | ||
*/ | ||
static Fr compute_eval_pos(const Fr batched_mle_eval, | ||
std::span<const Fr> mle_vars, | ||
std::span<const Fr> r_squares, | ||
std::span<const Fr> fold_polynomial_evals) | ||
static Fr compute_gemini_batched_univariate_evaluation(Fr& batched_mle_eval, | ||
std::span<const Fr> evaluation_point, | ||
std::span<const Fr> challenge_powers, | ||
std::span<const Fr> fold_polynomial_evals) | ||
{ | ||
const size_t num_variables = mle_vars.size(); | ||
const size_t num_variables = evaluation_point.size(); | ||
|
||
const auto& evals = fold_polynomial_evals; | ||
|
||
// Initialize eval_pos with batched MLE eval v = ∑ⱼ ρʲ vⱼ + ∑ⱼ ρᵏ⁺ʲ v↺ⱼ | ||
Fr eval_pos = batched_mle_eval; | ||
/// Initialize the evaluation of the univariatization of the batched multilinear polynomial with | ||
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 see that all of these 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, makes sense. I rendered the latex formulas into unicode, so that they are less noisy and tried to slightly reduce the volume of comments |
||
/// the evaluation of \f$ \sum \rho^i f_i + \sum \rho^{i+k} f_{i,\text{shift}} \f$ at \f$ (u_0,\ldots, u_{d-1}) | ||
/// \f$ | ||
Fr& batched_eval = batched_mle_eval; | ||
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. Why wouldn't you just rename the input to this function? 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. done |
||
/// Solve the sequence of linear equations | ||
for (size_t l = num_variables; l != 0; --l) { | ||
const Fr r = r_squares[l - 1]; // = rₗ₋₁ = r^{2ˡ⁻¹} | ||
const Fr eval_neg = evals[l - 1]; // = Aₗ₋₁(−r^{2ˡ⁻¹}) | ||
const Fr u = mle_vars[l - 1]; // = uₗ₋₁ | ||
|
||
// The folding property ensures that | ||
// Aₗ₋₁(r^{2ˡ⁻¹}) + Aₗ₋₁(−r^{2ˡ⁻¹}) Aₗ₋₁(r^{2ˡ⁻¹}) - Aₗ₋₁(−r^{2ˡ⁻¹}) | ||
// Aₗ(r^{2ˡ}) = (1-uₗ₋₁) ----------------------------- + uₗ₋₁ ----------------------------- | ||
// 2 2r^{2ˡ⁻¹} | ||
// We solve the above equation in Aₗ₋₁(r^{2ˡ⁻¹}), using the previously computed Aₗ(r^{2ˡ}) in eval_pos | ||
// and using Aₗ₋₁(−r^{2ˡ⁻¹}) sent by the prover in the proof. | ||
eval_pos = ((r * eval_pos * 2) - eval_neg * (r * (Fr(1) - u) - u)) / (r * (Fr(1) - u) + u); | ||
/// Get \f$ r^{2^{\ell - 1}} \f$ | ||
const Fr& challenge_power = challenge_powers[l - 1]; | ||
/// Get \f$ A_{\ell-1}(−r^{2^{\ell -1 }})\f$ | ||
const Fr& eval_neg = evals[l - 1]; | ||
/// Get \f$ u_{\ell-1}\f$ | ||
const Fr& u = evaluation_point[l - 1]; | ||
/// Compute the numerator | ||
batched_eval = ((challenge_power * batched_eval * 2) - eval_neg * (challenge_power * (Fr(1) - u) - u)); | ||
/// Divide by the denominator | ||
batched_eval *= (challenge_power * (Fr(1) - u) + u).invert(); | ||
} | ||
|
||
return eval_pos; // return A₀(r) | ||
return batched_eval; | ||
} | ||
|
||
/** | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,5 +1,7 @@ | ||
#pragma once | ||
#include "barretenberg/commitment_schemes/claim.hpp" | ||
#include "barretenberg/commitment_schemes/utils/batch_mul_native.hpp" | ||
#include "barretenberg/commitment_schemes/utils/shplemini_accumulator.hpp" | ||
#include "barretenberg/commitment_schemes/verification_key.hpp" | ||
#include "barretenberg/common/assert.hpp" | ||
#include "barretenberg/common/container.hpp" | ||
|
@@ -572,6 +574,49 @@ template <typename Curve_> class IPA { | |
{ | ||
return reduce_verify_internal(vk, opening_claim, transcript); | ||
} | ||
/** | ||
* @brief A method that produces an IPA opening claim from Shplemini accumulator containing vectors of commitments | ||
* and scalars and a Shplonk evaluation challenge. | ||
* | ||
* @details Compute the commitment \f$ C \f$ that will be used to prove that Shplonk batching is performed correctly | ||
* and check the evaluation claims of the batched univariate polynomials. The check is done by verifying that the | ||
* polynomial corresponding to \f$ C \f$ evaluates to \f$ 0 \f$ at the Shplonk challenge point \f$ z \f$. | ||
* | ||
*/ | ||
static OpeningClaim<Curve> compute_opening_claim_from_shplemini_accumulators( | ||
ShpleminiAccumulator<Curve>& shplemini_accumulator) | ||
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. Looks like input should be |
||
{ | ||
using Utils = CommitmentSchemesUtils<Curve>; | ||
/// Extract batch_mul arguments from the accumulator | ||
auto& commitments = shplemini_accumulator.commitments; | ||
auto& scalars = shplemini_accumulator.scalars; | ||
Fr& shplonk_eval_challenge = shplemini_accumulator.evaluation_point; | ||
/// Compute \f$ C = \sum \text{commitments}_i \cdot \text{scalars}_i \f$ | ||
GroupElement shplonk_output_commitment; | ||
if constexpr (Curve::is_stdlib_type) { | ||
shplonk_output_commitment = | ||
GroupElement::batch_mul(commitments, scalars, /*max_num_bits=*/0, /*with_edgecases=*/true); | ||
} else { | ||
shplonk_output_commitment = Utils::batch_mul_native(commitments, scalars); | ||
} | ||
/// Output an opening claim to be verified by the IPA opening protocol | ||
return { { shplonk_eval_challenge, Fr(0) }, shplonk_output_commitment }; | ||
} | ||
/** | ||
* @brief Verify the IPA opening claim obtained from a Shplemini accumulator | ||
* | ||
* @param shplemini_accumulator | ||
* @param vk | ||
* @param transcript | ||
* @return VerifierAccumulator | ||
*/ | ||
static VerifierAccumulator reduce_verify_shplemini_accumulator(ShpleminiAccumulator<Curve>& shplemini_accumulator, | ||
const std::shared_ptr<VK>& vk, | ||
auto& transcript) | ||
{ | ||
auto opening_claim = compute_opening_claim_from_shplemini_accumulators(shplemini_accumulator); | ||
return reduce_verify_internal(vk, opening_claim, transcript); | ||
} | ||
}; | ||
|
||
} // 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.
Side note: every prover/verifier class should have
prove
/verify
methods