36 template <
typename Transcript>
41 const std::shared_ptr<Transcript>& transcript,
50 const bool has_zk = (libra_polynomials[0].size() > 0);
51 for (
const auto& libra_poly : libra_polynomials) {
52 BB_ASSERT((libra_poly.size() > 0) == has_zk,
53 "ShpleminiProver: libra_polynomials must be either all populated (ZK) or all empty (non-ZK)");
57 const size_t virtual_log_n = multilinear_challenge.size();
60 circuit_size, polynomial_batcher, multilinear_challenge, commitment_key, transcript, has_zk);
65 const auto gemini_r = opening_claims[0].opening_pair.challenge;
72 if (!sumcheck_round_univariates.empty()) {
74 circuit_size, multilinear_challenge, sumcheck_round_univariates, sumcheck_round_evaluations);
78 commitment_key, opening_claims, transcript, libra_opening_claims, sumcheck_round_claims, virtual_log_n);
86 template <
typename Transcript>
90 const std::shared_ptr<Transcript>& transcript)
93 make_small_ipa_prover_opening_claims<Curve>(libra_polynomials, gemini_r,
"Libra:", transcript);
106 const std::vector<std::array<FF, 3>>& sumcheck_round_evaluations)
111 for (
size_t idx = 0; idx < log_n; idx++) {
112 const std::vector<FF> evaluation_points = {
FF(0),
FF(1), multilinear_challenge[idx] };
115 new_claim.
polynomial = sumcheck_round_univariates[idx];
117 for (
auto& eval_point : evaluation_points) {
119 new_claim.
opening_pair.evaluation = sumcheck_round_evaluations[idx][eval_idx];
120 sumcheck_round_claims.push_back(new_claim);
125 return sumcheck_round_claims;
170template <
typename Curve,
bool HasZK = false,
bool HasGeminiMasking = HasZK>
class ShpleminiVerifier_ {
205 template <
typename Transcript>
208 const std::vector<Fr>& multivariate_challenge,
210 const std::shared_ptr<Transcript>& transcript,
212 const std::array<Commitment, NUM_SMALL_IPA_COMMITMENTS>& libra_commitments = {},
213 const Fr& libra_univariate_evaluation =
Fr{ 0 },
214 const std::vector<Commitment>& sumcheck_round_commitments = {},
218 const size_t virtual_log_n = multivariate_challenge.size();
222 if (virtual_log_n == 0) {
223 throw_or_abort(
"Shplemini: multivariate_challenge must be non-empty");
226 BB_ASSERT(sumcheck_round_commitments.empty() == sumcheck_round_evaluations.empty(),
227 "Shplemini: sumcheck_round_commitments and sumcheck_round_evaluations must be consistently empty");
228 const bool committed_sumcheck = !sumcheck_round_evaluations.empty();
230 Fr batched_evaluation =
Fr{ 0 };
233 const Fr gemini_batching_challenge = transcript->template get_challenge<Fr>(
"rho");
237 const std::vector<Commitment> fold_commitments =
241 const Fr gemini_evaluation_challenge = transcript->template get_challenge<Fr>(
"Gemini:r");
247 const std::vector<Fr> gemini_eval_challenge_powers =
252 if constexpr (HasZK) {
253 libra_evaluations = receive_small_ipa_evaluations<Curve>(
"Libra:", transcript);
258 const Fr shplonk_batching_challenge = transcript->template get_challenge<Fr>(
"Shplonk:nu");
262 const std::vector<Fr> shplonk_batching_challenge_powers = compute_shplonk_batching_challenge_powers(
263 shplonk_batching_challenge, virtual_log_n, HasZK, committed_sumcheck);
265 const auto Q_commitment = transcript->template receive_from_prover<Commitment>(
"Shplonk:Q");
269 std::vector<Commitment> commitments{ Q_commitment };
272 const Fr shplonk_evaluation_challenge = transcript->template get_challenge<Fr>(
"Shplonk:z");
278 const auto challenge_tag = shplonk_evaluation_challenge.get_origin_tag();
280 for (
auto& eval : gemini_fold_neg_evaluations) {
281 eval.set_origin_tag(challenge_tag);
286 Fr constant_term_accumulator =
Fr(0);
289 std::vector<Fr> scalars;
291 scalars.emplace_back(
Fr(1));
296 shplonk_evaluation_challenge, gemini_eval_challenge_powers);
303 inverse_vanishing_evals, shplonk_batching_challenge, gemini_evaluation_challenge);
308 commitments, scalars, batched_evaluation, gemini_batching_challenge);
313 batched_evaluation, multivariate_challenge, gemini_eval_challenge_powers, gemini_fold_neg_evaluations);
319 gemini_fold_neg_evaluations,
320 gemini_fold_pos_evaluations,
321 inverse_vanishing_evals,
322 shplonk_batching_challenge_powers,
325 constant_term_accumulator);
326 const Fr a_0_pos = gemini_fold_pos_evaluations[0];
329 constant_term_accumulator += a_0_pos * inverse_vanishing_evals[0];
331 constant_term_accumulator +=
332 gemini_fold_neg_evaluations[0] * shplonk_batching_challenge * inverse_vanishing_evals[1];
336 bool consistency_checked =
true;
339 if constexpr (HasZK) {
343 constant_term_accumulator,
346 gemini_evaluation_challenge,
347 shplonk_batching_challenge_powers,
348 shplonk_evaluation_challenge);
351 libra_evaluations, gemini_evaluation_challenge, multivariate_challenge, libra_univariate_evaluation);
356 if (committed_sumcheck) {
357 if constexpr (!HasZK) {
358 throw_or_abort(
"Shplemini: committed sumcheck requires ZK for correct nu power indexing");
362 constant_term_accumulator,
363 multivariate_challenge,
364 shplonk_batching_challenge_powers,
365 shplonk_evaluation_challenge,
366 sumcheck_round_commitments,
367 sumcheck_round_evaluations);
371 commitments.emplace_back(g1_identity);
372 scalars.emplace_back(constant_term_accumulator);
374 BatchOpeningClaim<Curve> batch_opening_claim{
std::move(commitments),
376 shplonk_evaluation_challenge };
378 if constexpr (HasZK) {
433 std::vector<Commitment>& commitments,
434 std::vector<Fr>& scalars,
435 Fr& constant_term_accumulator)
437 const size_t virtual_log_n = gemini_neg_evaluations.size();
440 for (
size_t j = 1; j < virtual_log_n; ++j) {
442 const size_t pos_index = 2 * j;
444 const size_t neg_index = (2 * j) + 1;
447 Fr scaling_factor_pos = shplonk_batching_challenge_powers[pos_index] * inverse_vanishing_evals[pos_index];
449 Fr scaling_factor_neg = shplonk_batching_challenge_powers[neg_index] * inverse_vanishing_evals[neg_index];
453 constant_term_accumulator +=
454 scaling_factor_neg * gemini_neg_evaluations[j] + scaling_factor_pos * gemini_pos_evaluations[j];
457 scalars.emplace_back(-(scaling_factor_neg + scaling_factor_pos));
459 commitments.emplace_back(
std::move(fold_commitments[j - 1]));
474 std::vector<Fr>& scalars,
476 bool has_gemini_masking_commitment)
481 const size_t offset = has_gemini_masking_commitment ? 2 : 1;
483 const auto& r1 = repeated_commitments.
first;
484 const auto& r2 = repeated_commitments.
second;
486 const size_t first_duplicate_start = r1.duplicate_start +
offset;
487 const size_t second_original_start = r2.original_start +
offset;
488 const size_t second_duplicate_start = r2.duplicate_start +
offset;
491 for (
size_t i = 0; i < r1.count; i++) {
492 scalars[i + first_original_start] = scalars[i + first_original_start] + scalars[i + first_duplicate_start];
494 for (
size_t i = 0; i < r2.count; i++) {
495 scalars[i + second_original_start] =
496 scalars[i + second_original_start] + scalars[i + second_duplicate_start];
504 auto erase_range = [&](
size_t duplicate_start, [[maybe_unused]]
size_t original_start,
size_t count) {
505 for (
size_t i = 0; i < count; ++i) {
506 scalars.erase(scalars.begin() +
static_cast<std::ptrdiff_t>(duplicate_start));
507 commitments.erase(commitments.begin() +
static_cast<std::ptrdiff_t>(duplicate_start));
510 if (second_duplicate_start > first_duplicate_start) {
511 erase_range(second_duplicate_start, second_original_start, r2.count);
512 erase_range(first_duplicate_start, first_original_start, r1.count);
514 erase_range(first_duplicate_start, first_original_start, r1.count);
515 erase_range(second_duplicate_start, second_original_start, r2.count);
537 const size_t virtual_log_n,
538 std::vector<Commitment>& commitments,
539 std::vector<Fr>& scalars,
540 Fr& constant_term_accumulator,
541 const std::array<Commitment, NUM_SMALL_IPA_COMMITMENTS>& libra_commitments,
543 const Fr& gemini_evaluation_challenge,
544 const std::vector<Fr>& shplonk_batching_challenge_powers,
545 const Fr& shplonk_evaluation_challenge)
549 for (
size_t idx = 0; idx < libra_commitments.size(); idx++) {
550 commitments.push_back(libra_commitments[idx]);
553 const auto denominators = compute_shplonk_denominators_for_small_ipa<Curve>(shplonk_evaluation_challenge,
554 gemini_evaluation_challenge);
560 const Fr scaling_factor = denominators[idx] * shplonk_batching_challenge_powers[2 * virtual_log_n + idx];
562 constant_term_accumulator += scaling_factor * libra_evaluations[idx];
564 for (
const Fr& s : grouped_scalars) {
565 scalars.push_back(s);
613 std::vector<Fr>& scalars,
614 Fr& constant_term_accumulator,
615 const std::vector<Fr>& multilinear_challenge,
616 const std::vector<Fr>& shplonk_batching_challenge_powers,
617 const Fr& shplonk_evaluation_challenge,
618 const std::vector<Commitment>& sumcheck_round_commitments,
619 const std::vector<std::array<Fr, 3>>& sumcheck_round_evaluations)
622 std::vector<Fr> denominators;
623 denominators.reserve(multilinear_challenge.size());
627 const size_t num_gemini_claims = 2 * multilinear_challenge.size();
632 const_denominators[0] =
Fr(1) / (shplonk_evaluation_challenge);
633 const_denominators[1] =
Fr(1) / (shplonk_evaluation_challenge -
Fr{ 1 });
637 for (
const auto& [challenge, comm] :
zip_view(multilinear_challenge, sumcheck_round_commitments)) {
638 denominators.push_back(shplonk_evaluation_challenge - challenge);
639 commitments.push_back(comm);
646 for (
auto& denominator : denominators) {
647 denominator =
Fr{ 1 } / denominator;
656 for (
const auto& [eval_array, denominator] :
zip_view(sumcheck_round_evaluations, denominators)) {
658 Fr batched_scalar =
Fr(0);
659 Fr const_term_contribution =
Fr(0);
661 for (
size_t idx = 0; idx < 2; idx++) {
662 Fr current_scaling_factor = const_denominators[idx] * shplonk_batching_challenge_powers[power++];
663 batched_scalar -= current_scaling_factor;
664 const_term_contribution += current_scaling_factor * eval_array[idx];
668 Fr current_scaling_factor = denominator * shplonk_batching_challenge_powers[power++];
669 batched_scalar -= current_scaling_factor;
670 const_term_contribution += current_scaling_factor * eval_array[2];
673 constant_term_accumulator += const_term_contribution;
674 scalars.push_back(batched_scalar);
#define BB_ASSERT(expression,...)
#define BB_BENCH_NAME(name)
CommitmentKey object over a pairing group 𝔾₁.
Class responsible for computation of the batched multilinear polynomials required by the Gemini proto...
static std::vector< Claim > prove(size_t circuit_size, PolynomialBatcher &polynomial_batcher, std::span< Fr > multilinear_challenge, const CommitmentKey< Curve > &commitment_key, const std::shared_ptr< Transcript > &transcript, bool has_zk=false)
Gemini Verifier utility methods used by ShpleminiVerifier.
static std::vector< Fr > compute_fold_pos_evaluations(const Fr &batched_evaluation, std::span< const Fr > evaluation_point, std::span< const Fr > challenge_powers, std::span< const Fr > fold_neg_evals)
Compute .
static std::vector< Commitment > get_fold_commitments(const size_t virtual_log_n, auto &transcript)
Receive the fold commitments from the prover. This method is used by Shplemini where padding may be e...
static std::vector< Fr > get_gemini_evaluations(const size_t virtual_log_n, auto &transcript)
Receive the fold evaluations from the prover. This method is used by Shplemini where padding may be e...
Polynomial p and an opening pair (r,v) such that p(r) = v.
OpeningPair< Curve > opening_pair
typename Curve::Element GroupElement
static std::vector< OpeningClaim > compute_libra_opening_claims(const FF gemini_r, const std::array< Polynomial, NUM_SMALL_IPA_COMMITMENTS > &libra_polynomials, const std::shared_ptr< Transcript > &transcript)
For ZK Flavors: Evaluate the polynomials used in SmallSubgroupIPA argument, send the evaluations to t...
typename Curve::AffineElement Commitment
typename Curve::ScalarField FF
static std::vector< OpeningClaim > compute_sumcheck_round_claims(size_t circuit_size, std::span< FF > multilinear_challenge, const std::vector< Polynomial > &sumcheck_round_univariates, const std::vector< std::array< FF, 3 > > &sumcheck_round_evaluations)
Create a vector of 3*log_n opening claims for the evaluations of Sumcheck Round Univariates at 0,...
static OpeningClaim prove(size_t circuit_size, PolynomialBatcher &polynomial_batcher, std::span< FF > multilinear_challenge, const CommitmentKey< Curve > &commitment_key, const std::shared_ptr< Transcript > &transcript, const std::array< Polynomial, NUM_SMALL_IPA_COMMITMENTS > &libra_polynomials={}, const std::vector< Polynomial > &sumcheck_round_univariates={}, const std::vector< std::array< FF, 3 > > &sumcheck_round_evaluations={})
typename Curve::Element GroupElement
typename Curve::AffineElement Commitment
static void remove_repeated_commitments(std::vector< Commitment > &commitments, std::vector< Fr > &scalars, const RepeatedCommitmentsData &repeated_commitments, bool has_gemini_masking_commitment)
Combines scalars of repeating commitments to reduce the number of scalar multiplications performed by...
static void batch_sumcheck_round_claims(std::vector< Commitment > &commitments, std::vector< Fr > &scalars, Fr &constant_term_accumulator, const std::vector< Fr > &multilinear_challenge, const std::vector< Fr > &shplonk_batching_challenge_powers, const Fr &shplonk_evaluation_challenge, const std::vector< Commitment > &sumcheck_round_commitments, const std::vector< std::array< Fr, 3 > > &sumcheck_round_evaluations)
Adds the Sumcheck data into the Shplemini BatchOpeningClaim.
typename Curve::ScalarField Fr
static ShpleminiVerifierOutput compute_batch_opening_claim(ClaimBatcher &claim_batcher, const std::vector< Fr > &multivariate_challenge, const Commitment &g1_identity, const std::shared_ptr< Transcript > &transcript, const RepeatedCommitmentsData &repeated_commitments={}, const std::array< Commitment, NUM_SMALL_IPA_COMMITMENTS > &libra_commitments={}, const Fr &libra_univariate_evaluation=Fr{ 0 }, const std::vector< Commitment > &sumcheck_round_commitments={}, const std::vector< std::array< Fr, 3 > > &sumcheck_round_evaluations={})
This method receives commitments to all prover polynomials, their claimed evaluations,...
ShpleminiVerifierOutput_< Curve, HasZK > ShpleminiVerifierOutput
static void batch_small_ipa_opening_claims(const size_t virtual_log_n, std::vector< Commitment > &commitments, std::vector< Fr > &scalars, Fr &constant_term_accumulator, const std::array< Commitment, NUM_SMALL_IPA_COMMITMENTS > &libra_commitments, const std::array< Fr, NUM_SMALL_IPA_OPENING_CLAIMS > &libra_evaluations, const Fr &gemini_evaluation_challenge, const std::vector< Fr > &shplonk_batching_challenge_powers, const Fr &shplonk_evaluation_challenge)
Add the opening data corresponding to Libra masking univariates to the batched opening claim.
static void batch_gemini_claims_received_from_prover(const std::vector< Commitment > &fold_commitments, std::span< const Fr > gemini_neg_evaluations, std::span< const Fr > gemini_pos_evaluations, std::span< const Fr > inverse_vanishing_evals, std::span< const Fr > shplonk_batching_challenge_powers, std::vector< Commitment > &commitments, std::vector< Fr > &scalars, Fr &constant_term_accumulator)
Place fold polynomial commitments to commitments and compute the corresponding scalar multipliers.
static ProverOpeningClaim< Curve > prove(const CommitmentKey< Curve > &commitment_key, std::span< ProverOpeningClaim< Curve > > opening_claims, const std::shared_ptr< Transcript > &transcript, std::span< ProverOpeningClaim< Curve > > libra_opening_claims={}, std::span< ProverOpeningClaim< Curve > > sumcheck_round_claims={}, const size_t virtual_log_n=0)
static std::vector< Fr > compute_inverted_gemini_denominators(const Fr &shplonk_eval_challenge, const std::vector< Fr > &gemini_eval_challenge_powers)
Computes .
static bool check_libra_evaluations_consistency(const std::array< FF, NUM_SMALL_IPA_OPENING_CLAIMS > &libra_evaluations, const FF &gemini_evaluation_challenge, const std::vector< FF > &multilinear_challenge, const FF &inner_product_eval_claim)
A method required by ZKSumcheck. The challenge polynomial is concatenated from the powers of the sumc...
Representation of the Grumpkin Verifier Commitment Key inside a bn254 circuit.
typename Group::element Element
static constexpr bool is_stdlib_type
typename Group::affine_element AffineElement
std::vector< Fr > powers_of_evaluation_challenge(const Fr &r, const size_t num_squares)
Compute squares of folding challenge r.
constexpr T get_msb(const T in)
Entry point for Barretenberg command-line interface.
constexpr auto SMALL_IPA_CLAIMS
The five SmallSubgroupIPA opening claims, in transcript order.
constexpr size_t NUM_SMALL_IPA_OPENING_CLAIMS
constexpr decltype(auto) get(::tuplet::tuple< T... > &&t) noexcept
This file contains part of the logic for the Origin Tag mechanism that tracks the use of in-circuit p...
An accumulator consisting of the Shplonk evaluation challenge and vectors of commitments and scalars.
Logic to support batching opening claims for unshifted and shifted polynomials in Shplemini.
void update_batch_mul_inputs_and_batched_evaluation(std::vector< Commitment > &commitments, std::vector< Fr > &scalars, Fr &batched_evaluation, const Fr &rho)
Append the commitments and scalars from each batch of claims to the Shplemini vectors which subsequen...
void compute_scalars_for_each_batch(std::span< const Fr > inverted_vanishing_evals, const Fr &nu_challenge, const Fr &r_challenge)
Compute scalars used to batch each set of claims, excluding contribution from batching challenge \rho...
BatchOpeningClaim< Curve > batch_opening_claim
An efficient verifier for the evaluation proofs of multilinear polynomials and their shifts.
BatchOpeningClaim< Curve > batch_opening_claim
static void batch_invert(C &coeffs) noexcept
Batch invert a collection of field elements using Montgomery's trick.
void throw_or_abort(std::string const &err)