Barretenberg
The ZK-SNARK library at the core of Aztec
Loading...
Searching...
No Matches
shplemini.hpp
Go to the documentation of this file.
1// === AUDIT STATUS ===
2// internal: { status: Complete, auditors: [Khashayar], commit: }
3// external_1: { status: not started, auditors: [], commit: }
4// external_2: { status: not started, auditors: [], commit: }
5// =====================
6
7#pragma once
19
20namespace bb {
21
22template <typename Curve> class ShpleminiProver_ {
23 public:
24 using FF = typename Curve::ScalarField;
25 using GroupElement = typename Curve::Element;
29
34
35 template <typename Transcript>
36 static OpeningClaim prove(size_t circuit_size,
37 PolynomialBatcher& polynomial_batcher,
38 std::span<FF> multilinear_challenge,
39 const CommitmentKey<Curve>& commitment_key,
40 const std::shared_ptr<Transcript>& transcript,
41 const std::array<Polynomial, NUM_SMALL_IPA_EVALUATIONS>& libra_polynomials = {},
42 const std::vector<Polynomial>& sumcheck_round_univariates = {},
43 const std::vector<std::array<FF, 3>>& sumcheck_round_evaluations = {})
44 {
45 // While Shplemini is not templated on Flavor, we derive ZK flag this way
46 const bool has_zk = (libra_polynomials[0].size() > 0);
47
48 // When padding is enabled, the size of the multilinear challenge may be bigger than the log of `circuit_size`.
49 const size_t virtual_log_n = multilinear_challenge.size();
50
52 circuit_size, polynomial_batcher, multilinear_challenge, commitment_key, transcript, has_zk);
53 // Create opening claims for Libra masking univariates and Sumcheck Round Univariates
54 std::vector<OpeningClaim> libra_opening_claims;
55
56 if (has_zk) {
57 const auto gemini_r = opening_claims[0].opening_pair.challenge;
58 libra_opening_claims = compute_libra_opening_claims(gemini_r, libra_polynomials, transcript);
59 }
60
61 // Currently, only used in ECCVM.
62 std::vector<OpeningClaim> sumcheck_round_claims;
63
64 if (!sumcheck_round_univariates.empty()) {
65 sumcheck_round_claims = compute_sumcheck_round_claims(
66 circuit_size, multilinear_challenge, sumcheck_round_univariates, sumcheck_round_evaluations);
67 }
68
70 commitment_key, opening_claims, transcript, libra_opening_claims, sumcheck_round_claims, virtual_log_n);
71 };
72
78 template <typename Transcript>
80 const FF gemini_r,
82 const std::shared_ptr<Transcript>& transcript)
83 {
84 OpeningClaim new_claim;
85
86 std::vector<OpeningClaim> libra_opening_claims = {};
87
88 static constexpr FF subgroup_generator = Curve::subgroup_generator;
89
91 "Libra:concatenation_eval", "Libra:shifted_grand_sum_eval", "Libra:grand_sum_eval", "Libra:quotient_eval"
92 };
93 const std::array<FF, NUM_SMALL_IPA_EVALUATIONS> evaluation_points = {
94 gemini_r, gemini_r * subgroup_generator, gemini_r, gemini_r
95 };
96 for (size_t idx = 0; idx < NUM_SMALL_IPA_EVALUATIONS; idx++) {
97 new_claim.polynomial = std::move(libra_polynomials[idx]);
98 new_claim.opening_pair.challenge = evaluation_points[idx];
99 new_claim.opening_pair.evaluation = new_claim.polynomial.evaluate(evaluation_points[idx]);
100 transcript->send_to_verifier(libra_eval_labels[idx], new_claim.opening_pair.evaluation);
101 libra_opening_claims.push_back(new_claim);
102 }
103
104 return libra_opening_claims;
105 }
106
113 size_t circuit_size,
114 std::span<FF> multilinear_challenge,
115 const std::vector<Polynomial>& sumcheck_round_univariates,
116 const std::vector<std::array<FF, 3>>& sumcheck_round_evaluations)
117 {
118 OpeningClaim new_claim;
119 std::vector<OpeningClaim> sumcheck_round_claims = {};
120
121 const size_t log_n = numeric::get_msb(circuit_size);
122 for (size_t idx = 0; idx < log_n; idx++) {
123 const std::vector<FF> evaluation_points = { FF(0), FF(1), multilinear_challenge[idx] };
124 size_t eval_idx = 0;
125 new_claim.polynomial = std::move(sumcheck_round_univariates[idx]);
126
127 for (auto& eval_point : evaluation_points) {
128 new_claim.opening_pair.challenge = eval_point;
129 new_claim.opening_pair.evaluation = sumcheck_round_evaluations[idx][eval_idx];
130 sumcheck_round_claims.push_back(new_claim);
131 eval_idx++;
132 }
133 }
134
135 return sumcheck_round_claims;
136 }
137};
138
167template <typename Curve, bool HasZK> struct ShpleminiVerifierOutput_ {
169};
174
175template <typename Curve, bool HasZK = false> class ShpleminiVerifier_ {
176 using Fr = typename Curve::ScalarField;
177 using GroupElement = typename Curve::Element;
184
185 public:
213 template <typename Transcript>
215 std::span<const Fr> padding_indicator_array,
216 ClaimBatcher& claim_batcher,
217 const std::vector<Fr>& multivariate_challenge,
218 const Commitment& g1_identity,
219 const std::shared_ptr<Transcript>& transcript,
220 const RepeatedCommitmentsData& repeated_commitments = {},
221 const std::array<Commitment, NUM_LIBRA_COMMITMENTS>& libra_commitments = {},
222 const Fr& libra_univariate_evaluation = Fr{ 0 },
223 const std::vector<Commitment>& sumcheck_round_commitments = {},
224 const std::vector<std::array<Fr, 3>>& sumcheck_round_evaluations = {})
225
226 {
227 const size_t virtual_log_n = multivariate_challenge.size();
228
229 const bool committed_sumcheck = !sumcheck_round_evaluations.empty();
230
231 Fr batched_evaluation = Fr{ 0 };
232
233 // Get the challenge ρ to batch commitments to multilinear polynomials and their shifts
234 const Fr gemini_batching_challenge = transcript->template get_challenge<Fr>("rho");
235
236 // Process Gemini transcript data:
237 // - Get Gemini commitments (com(A₁), com(A₂), … , com(Aₙ₋₁))
238 const std::vector<Commitment> fold_commitments =
239 GeminiVerifier::get_fold_commitments(virtual_log_n, transcript);
240 // - Get Gemini evaluation challenge r, that is used to open the Gemini fold polynomials Aᵢ, i = 0, … , d−1 on
241 // r^{2^i}
242 const Fr gemini_evaluation_challenge = transcript->template get_challenge<Fr>("Gemini:r");
243
244 // - Get negative fold evaluations (A₀(−r), A₁(−r²), ... , Aₙ₋₁(−r²⁽ⁿ⁻¹⁾))
245 const std::vector<Fr> gemini_fold_neg_evaluations =
246 GeminiVerifier::get_gemini_evaluations(virtual_log_n, transcript);
247
248 // Get evaluations of partially evaluated batched interleaved polynomials P₊(rˢ) and P₋((-r)ˢ)
249 Fr p_pos = Fr(0);
250 Fr p_neg = Fr(0);
251 if (claim_batcher.interleaved) {
252 p_pos = transcript->template receive_from_prover<Fr>("Gemini:P_pos");
253 p_neg = transcript->template receive_from_prover<Fr>("Gemini:P_neg");
254 }
255
256 // - Compute vector (r, r², ... , r^{2^{d-1}}), where d = log_n
257 const std::vector<Fr> gemini_eval_challenge_powers =
258 gemini::powers_of_evaluation_challenge(gemini_evaluation_challenge, virtual_log_n);
259
261 // In case of ZK, get the evaluations of Libra univariates from the transcript
262 if constexpr (HasZK) {
263 libra_evaluations[0] = transcript->template receive_from_prover<Fr>("Libra:concatenation_eval");
264 libra_evaluations[1] = transcript->template receive_from_prover<Fr>("Libra:shifted_grand_sum_eval");
265 libra_evaluations[2] = transcript->template receive_from_prover<Fr>("Libra:grand_sum_eval");
266 libra_evaluations[3] = transcript->template receive_from_prover<Fr>("Libra:quotient_eval");
267
268 // OriginTag false positive: Libra evaluations need to satisfy an identity where they
269 // are mixing without challenge, it is safe because these evaluations are opened in Shplonk.
270 if constexpr (Curve::is_stdlib_type) {
271 for (auto& eval : libra_evaluations) {
272 eval.clear_round_provenance();
273 }
274 }
275 }
276
277 // Process Shplonk transcript data:
278 // - Get Shplonk batching challenge
279 const Fr shplonk_batching_challenge = transcript->template get_challenge<Fr>("Shplonk:nu");
280
281 // Compute the powers of ν that are required for batching Gemini, SmallSubgroupIPA, and committed sumcheck
282 // univariate opening claims.
283 const std::vector<Fr> shplonk_batching_challenge_powers = compute_shplonk_batching_challenge_powers(
284 shplonk_batching_challenge, virtual_log_n, HasZK, committed_sumcheck);
285 // - Get the quotient commitment for the Shplonk batching of Gemini opening claims
286 const auto Q_commitment = transcript->template receive_from_prover<Commitment>("Shplonk:Q");
287
288 // Start populating the vector (Q, f₀, ... , fₖ₋₁, g₀, ... , gₘ₋₁, com(A₁), ... , com(A_{d-1}), [1]₁) where fᵢ
289 // are the k commitments to unshifted polynomials and gⱼ are the m commitments to shifted polynomials
290 std::vector<Commitment> commitments{ Q_commitment };
291
292 // Get Shplonk opening point z
293 const Fr shplonk_evaluation_challenge = transcript->template get_challenge<Fr>("Shplonk:z");
294
295 // Start computing the scalar to be multiplied by [1]₁
296 Fr constant_term_accumulator = Fr(0);
297
298 // Initialize the vector of scalars placing the scalar 1 corresponding to Q_commitment
299 std::vector<Fr> scalars;
300
301 scalars.emplace_back(Fr(1));
302
303 // Compute 1/(z − r), 1/(z + r), 1/(z - r²), 1/(z + r²), … , 1/(z - r^{2^{d-1}}), 1/(z + r^{2^{d-1}})
304 // These represent the denominators of the summand terms in Shplonk partially evaluated polynomial Q_z
305 const std::vector<Fr> inverse_vanishing_evals = ShplonkVerifier::compute_inverted_gemini_denominators(
306 shplonk_evaluation_challenge, gemini_eval_challenge_powers);
307
308 // Compute the additional factors to be multiplied with unshifted and shifted commitments when lazily
309 // reconstructing the commitment of Q_z
310 // For unshifted values, the scalar is computed as (1/(z−r) + ν/(z+r))
311 // For shifted values, the scalar is computed as r⁻¹ ⋅ (1/(z−r) − ν/(z+r))
312 claim_batcher.compute_scalars_for_each_batch(
313 inverse_vanishing_evals, shplonk_batching_challenge, gemini_evaluation_challenge);
314
315 // Place the commitments to prover polynomials in the commitments vector. Compute the evaluation of the
316 // batched multilinear polynomial. Populate the vector of scalars for the final batch mul
317
318 // Compute the Shplonk batching power for the interleaved claims. This is \nu^{d+1} where d = log_n as the
319 // interleaved claims are sent after the rest of Gemini fold claims. Add the evaluations of (P₊(rˢ) ⋅ ν^{d+1}) /
320 // (z − r^s) and (P₋(rˢ) ⋅ ν^{d+2})/(z − r^s) to the constant term accumulator
321 Fr shplonk_interleaving_batching_pos = Fr{ 0 };
322 Fr shplonk_interleaving_batching_neg = Fr{ 0 };
323 if (claim_batcher.interleaved) {
324 // The prover places the Interleaving claims (P₊, P₋) after all Gemini fold claims.
325 // Their batching powers are ν^{2·virtual_log_n} and ν^{2·virtual_log_n+1}.
326 // TODO(https://github.com/AztecProtocol/barretenberg/issues/1293): Decouple Gemini from Interleaving.
327 const size_t interleaved_pos_index = 2 * virtual_log_n;
328 const size_t interleaved_neg_index = interleaved_pos_index + 1;
329 shplonk_interleaving_batching_pos = shplonk_batching_challenge_powers[interleaved_pos_index];
330 shplonk_interleaving_batching_neg = shplonk_batching_challenge_powers[interleaved_neg_index];
331 constant_term_accumulator +=
332 claim_batcher.interleaved->shplonk_denominator *
333 (p_pos * shplonk_interleaving_batching_pos + p_neg * shplonk_interleaving_batching_neg);
334 }
335 // Update the commitments and scalars vectors as well as the batched evaluation given the present batches
336 claim_batcher.update_batch_mul_inputs_and_batched_evaluation(commitments,
337 scalars,
338 batched_evaluation,
339 gemini_batching_challenge,
340 shplonk_interleaving_batching_pos,
341 shplonk_interleaving_batching_neg);
342
343 // Reconstruct Aᵢ(r²ⁱ) for i=0, ..., d - 1 from the batched evaluation of the multilinear polynomials and
344 // Aᵢ(−r²ⁱ) for i = 0, ..., d - 1. In the case of interleaving, we compute A₀(r) as A₀₊(r) + P₊(r^s).
345 const std::vector<Fr> gemini_fold_pos_evaluations =
347 batched_evaluation,
348 multivariate_challenge,
349 gemini_eval_challenge_powers,
350 gemini_fold_neg_evaluations,
351 p_neg);
352
353 // Place the commitments to Gemini fold polynomials Aᵢ in the vector of batch_mul commitments, compute the
354 // contributions from Aᵢ(−r²ⁱ) for i=1, … , d − 1 to the constant term accumulator, add corresponding scalars
355 // for the batch mul
356 batch_gemini_claims_received_from_prover(padding_indicator_array,
357 fold_commitments,
358 gemini_fold_neg_evaluations,
359 gemini_fold_pos_evaluations,
360 inverse_vanishing_evals,
361 shplonk_batching_challenge_powers,
362 commitments,
363 scalars,
364 constant_term_accumulator);
365 const Fr full_a_0_pos = gemini_fold_pos_evaluations[0];
366 // Retrieve the contribution without P₊(r^s)
367 Fr a_0_pos = full_a_0_pos - p_pos;
368 // Add contributions from A₀₊(r) and A₀₋(-r) to constant_term_accumulator:
369 // Add A₀₊(r)/(z−r) to the constant term accumulator
370 constant_term_accumulator += a_0_pos * inverse_vanishing_evals[0];
371 // Add A₀₋(-r)/(z+r) to the constant term accumulator
372 constant_term_accumulator +=
373 gemini_fold_neg_evaluations[0] * shplonk_batching_challenge * inverse_vanishing_evals[1];
374
375 remove_repeated_commitments(commitments, scalars, repeated_commitments, HasZK);
376 // An optional boolean flag for SmallSubgroupIPAVerifier to check the consistency of the Libra evaluations
377 bool consistency_checked = true;
378 // For ZK flavors, the sumcheck output contains the evaluations of Libra univariates that submitted to the
379 // ShpleminiVerifier, otherwise this argument is set to be empty
380 if constexpr (HasZK) {
381 add_zk_data(virtual_log_n,
382 commitments,
383 scalars,
384 constant_term_accumulator,
385 libra_commitments,
386 libra_evaluations,
387 gemini_evaluation_challenge,
388 shplonk_batching_challenge_powers,
389 shplonk_evaluation_challenge);
390
392 libra_evaluations, gemini_evaluation_challenge, multivariate_challenge, libra_univariate_evaluation);
393 }
394
395 // Currently, only used in ECCVM
396 if (committed_sumcheck) {
397 batch_sumcheck_round_claims(commitments,
398 scalars,
399 constant_term_accumulator,
400 multivariate_challenge,
401 shplonk_batching_challenge_powers,
402 shplonk_evaluation_challenge,
403 sumcheck_round_commitments,
404 sumcheck_round_evaluations);
405 }
406
407 // Finalize the batch opening claim
408 commitments.emplace_back(g1_identity);
409 scalars.emplace_back(constant_term_accumulator);
410
411 BatchOpeningClaim<Curve> batch_opening_claim{ commitments, scalars, shplonk_evaluation_challenge };
412 ShpleminiVerifierOutput output{ batch_opening_claim };
413 if constexpr (HasZK) {
414 output.consistency_checked = consistency_checked;
415 }
416 return output;
417 };
418
464 const std::vector<Commitment>& fold_commitments,
465 std::span<const Fr> gemini_neg_evaluations,
466 std::span<const Fr> gemini_pos_evaluations,
467 std::span<const Fr> inverse_vanishing_evals,
468 std::span<const Fr> shplonk_batching_challenge_powers,
469 std::vector<Commitment>& commitments,
470 std::vector<Fr>& scalars,
471 Fr& constant_term_accumulator)
472 {
473 const size_t virtual_log_n = gemini_neg_evaluations.size();
474 // Start from 1, because the commitment to A_0 is reconstructed from the commitments to the multilinear
475 // polynomials. The corresponding evaluations are also handled separately.
476 for (size_t j = 1; j < virtual_log_n; ++j) {
477 // The index of 1/ (z - r^{2^{j}}) in the vector of inverted Gemini denominators
478 const size_t pos_index = 2 * j;
479 // The index of 1/ (z + r^{2^{j}}) in the vector of inverted Gemini denominators
480 const size_t neg_index = (2 * j) + 1;
481
482 // Compute the "positive" scaling factor (ν^{2j}) / (z - r^{2^{j}})
483 Fr scaling_factor_pos = shplonk_batching_challenge_powers[pos_index] * inverse_vanishing_evals[pos_index];
484 // Compute the "negative" scaling factor (ν^{2j+1}) / (z + r^{2^{j}})
485 Fr scaling_factor_neg = shplonk_batching_challenge_powers[neg_index] * inverse_vanishing_evals[neg_index];
486
487 // Accumulate the const term contribution given by
488 // v^{2j} * A_j(r^{2^j}) /(z - r^{2^j}) + v^{2j+1} * A_j(-r^{2^j}) /(z+ r^{2^j})
489 constant_term_accumulator +=
490 scaling_factor_neg * gemini_neg_evaluations[j] + scaling_factor_pos * gemini_pos_evaluations[j];
491
492 // Place the scaling factor to the 'scalars' vector
493 scalars.emplace_back(-padding_indicator_array[j] * (scaling_factor_neg + scaling_factor_pos));
494 // Move com(Aᵢ) to the 'commitments' vector
495 commitments.emplace_back(std::move(fold_commitments[j - 1]));
496 }
497 }
498
517 // TODO(https://github.com/AztecProtocol/barretenberg/issues/1151) Avoid erasing vector elements.
518 static void remove_repeated_commitments(std::vector<Commitment>& commitments,
519 std::vector<Fr>& scalars,
520 const RepeatedCommitmentsData& repeated_commitments,
521 bool has_zk)
522 {
523 // We started populating commitments and scalars by adding Shplonk:Q commitmment and the corresponding scalar
524 // factor 1. In the case of ZK, we also added Gemini:masking_poly_comm before populating the vector with
525 // commitments to prover polynomials
526 const size_t offset = has_zk ? 2 : 1;
527
528 // Extract the indices from the container, which is normally created in a given Flavor
529 const size_t& first_range_to_be_shifted_start = repeated_commitments.first_range_to_be_shifted_start + offset;
530 const size_t& first_range_shifted_start = repeated_commitments.first_range_shifted_start + offset;
531 const size_t& first_range_size = repeated_commitments.first_range_size;
532
533 const size_t& second_range_to_be_shifted_start = repeated_commitments.second_range_to_be_shifted_start + offset;
534 const size_t& second_range_shifted_start = repeated_commitments.second_range_shifted_start + offset;
535 const size_t& second_range_size = repeated_commitments.second_range_size;
536
537 // Iterate over the first range of to-be-shifted scalars and their shifted counterparts
538 for (size_t i = 0; i < first_range_size; i++) {
539 size_t idx_to_be_shifted = i + first_range_to_be_shifted_start;
540 size_t idx_shifted = i + first_range_shifted_start;
541 scalars[idx_to_be_shifted] = scalars[idx_to_be_shifted] + scalars[idx_shifted];
542 }
543
544 // Iterate over the second range of to-be-shifted precomputed scalars and their shifted counterparts (if
545 // provided)
546 for (size_t i = 0; i < second_range_size; i++) {
547 size_t idx_to_be_shifted = i + second_range_to_be_shifted_start;
548 size_t idx_shifted = i + second_range_shifted_start;
549 scalars[idx_to_be_shifted] = scalars[idx_to_be_shifted] + scalars[idx_shifted];
550 }
551
552 if (second_range_shifted_start > first_range_shifted_start) {
553 // Erase the shifted scalars and commitments from the second range (if provided)
554 for (size_t i = 0; i < second_range_size; ++i) {
555 scalars.erase(scalars.begin() + static_cast<std::ptrdiff_t>(second_range_shifted_start));
556 commitments.erase(commitments.begin() + static_cast<std::ptrdiff_t>(second_range_shifted_start));
557 }
558
559 // Erase the shifted scalars and commitments from the first range
560 for (size_t i = 0; i < first_range_size; ++i) {
561 scalars.erase(scalars.begin() + static_cast<std::ptrdiff_t>(first_range_shifted_start));
562 commitments.erase(commitments.begin() + static_cast<std::ptrdiff_t>(first_range_shifted_start));
563 }
564 } else {
565 // Erase the shifted scalars and commitments from the first range
566 for (size_t i = 0; i < first_range_size; ++i) {
567 scalars.erase(scalars.begin() + static_cast<std::ptrdiff_t>(first_range_shifted_start));
568 commitments.erase(commitments.begin() + static_cast<std::ptrdiff_t>(first_range_shifted_start));
569 }
570 // Erase the shifted scalars and commitments from the second range (if provided)
571 for (size_t i = 0; i < second_range_size; ++i) {
572 scalars.erase(scalars.begin() + static_cast<std::ptrdiff_t>(second_range_shifted_start));
573 commitments.erase(commitments.begin() + static_cast<std::ptrdiff_t>(second_range_shifted_start));
574 }
575 }
576 }
577
595 static void add_zk_data(const size_t virtual_log_n,
596 std::vector<Commitment>& commitments,
597 std::vector<Fr>& scalars,
598 Fr& constant_term_accumulator,
599 const std::array<Commitment, NUM_LIBRA_COMMITMENTS>& libra_commitments,
600 const std::array<Fr, NUM_SMALL_IPA_EVALUATIONS>& libra_evaluations,
601 const Fr& gemini_evaluation_challenge,
602 const std::vector<Fr>& shplonk_batching_challenge_powers,
603 const Fr& shplonk_evaluation_challenge)
604
605 {
606 // add Libra commitments to the vector of commitments
607 for (size_t idx = 0; idx < libra_commitments.size(); idx++) {
608 commitments.push_back(libra_commitments[idx]);
609 }
610
611 // compute corresponding scalars and the correction to the constant term
614 // compute Shplonk denominators and invert them
615 denominators[0] = Fr(1) / (shplonk_evaluation_challenge - gemini_evaluation_challenge);
616 denominators[1] =
617 Fr(1) / (shplonk_evaluation_challenge - Fr(Curve::subgroup_generator) * gemini_evaluation_challenge);
618 denominators[2] = denominators[0];
619 denominators[3] = denominators[0];
620
621 // compute the scalars to be multiplied against the commitments [libra_concatenated], [grand_sum], [grand_sum],
622 // and [libra_quotient]
623 for (size_t idx = 0; idx < NUM_SMALL_IPA_EVALUATIONS; idx++) {
624 Fr scaling_factor = denominators[idx] *
625 shplonk_batching_challenge_powers[2 * virtual_log_n + NUM_INTERLEAVING_CLAIMS + idx];
626 batching_scalars[idx] = -scaling_factor;
627 constant_term_accumulator += scaling_factor * libra_evaluations[idx];
628 }
629
630 // to save a scalar mul, add the sum of the batching scalars corresponding to the big sum evaluations
631 scalars.push_back(batching_scalars[0]);
632 scalars.push_back(batching_scalars[1] + batching_scalars[2]);
633 scalars.push_back(batching_scalars[3]);
634 }
635
679 static void batch_sumcheck_round_claims(std::vector<Commitment>& commitments,
680 std::vector<Fr>& scalars,
681 Fr& constant_term_accumulator,
682 const std::vector<Fr>& multilinear_challenge,
683 const std::vector<Fr>& shplonk_batching_challenge_powers,
684 const Fr& shplonk_evaluation_challenge,
685 const std::vector<Commitment>& sumcheck_round_commitments,
686 const std::vector<std::array<Fr, 3>>& sumcheck_round_evaluations)
687 {
688
689 std::vector<Fr> denominators = {};
690
691 // The number of Gemini claims is equal to `2 * log_n` and `log_n` is equal to the size of
692 // `multilinear_challenge`, as this method is never used with padding.
693 const size_t num_gemini_claims = 2 * multilinear_challenge.size();
694 // Denominators for the opening claims at 0 and 1. Need to be computed only once as opposed to the claims at the
695 // sumcheck round challenges.
696 std::array<Fr, 2> const_denominators;
697
698 const_denominators[0] = Fr(1) / (shplonk_evaluation_challenge);
699 const_denominators[1] = Fr(1) / (shplonk_evaluation_challenge - Fr{ 1 });
700
701 // Compute the denominators corresponding to the evaluation claims at the round challenges and add the
702 // commitments to the sumcheck round univariates to the vector of commitments
703 for (const auto& [challenge, comm] : zip_view(multilinear_challenge, sumcheck_round_commitments)) {
704 denominators.push_back(shplonk_evaluation_challenge - challenge);
705 commitments.push_back(comm);
706 }
707
708 // Invert denominators
709 if constexpr (!Curve::is_stdlib_type) {
710 Fr::batch_invert(denominators);
711 } else {
712 for (auto& denominator : denominators) {
713 denominator = Fr{ 1 } / denominator;
714 }
715 }
716
717 // Each commitment to a sumcheck round univariate [S_i] is multiplied by the sum of three scalars corresponding
718 // to the evaluations at 0, 1, and the round challenge u_i.
719 // Compute the power of `shplonk_batching_challenge` to add sumcheck univariate commitments and evaluations to
720 // the batch.
721 size_t power = num_gemini_claims + NUM_INTERLEAVING_CLAIMS + NUM_SMALL_IPA_EVALUATIONS;
722 for (const auto& [eval_array, denominator] : zip_view(sumcheck_round_evaluations, denominators)) {
723 // Initialize batched_scalar corresponding to 3 evaluations claims
724 Fr batched_scalar = Fr(0);
725 Fr const_term_contribution = Fr(0);
726 // Compute the contribution from the evaluations at 0 and 1
727 for (size_t idx = 0; idx < 2; idx++) {
728 Fr current_scaling_factor = const_denominators[idx] * shplonk_batching_challenge_powers[power++];
729 batched_scalar -= current_scaling_factor;
730 const_term_contribution += current_scaling_factor * eval_array[idx];
731 }
732
733 // Compute the contribution from the evaluation at the challenge u_i
734 Fr current_scaling_factor = denominator * shplonk_batching_challenge_powers[power++];
735 batched_scalar -= current_scaling_factor;
736 const_term_contribution += current_scaling_factor * eval_array[2];
737
738 // Update Shplonk constant term accumulator
739 constant_term_accumulator += const_term_contribution;
740 scalars.push_back(batched_scalar);
741 }
742 };
743};
744} // namespace bb
CommitmentKey object over a pairing group 𝔾₁.
Class responsible for computation of the batched multilinear polynomials required by the Gemini proto...
Definition gemini.hpp:126
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.
Definition gemini.hpp:316
static std::vector< Fr > compute_fold_pos_evaluations(std::span< const Fr > padding_indicator_array, const Fr &batched_evaluation, std::span< const Fr > evaluation_point, std::span< const Fr > challenge_powers, std::span< const Fr > fold_neg_evals, Fr p_neg=Fr(0))
Compute .
Definition gemini.hpp:397
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...
Definition gemini.hpp:329
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...
Definition gemini.hpp:350
Fr evaluate(const Fr &z, size_t target_size) const
Polynomial p and an opening pair (r,v) such that p(r) = v.
Definition claim.hpp:34
Polynomial polynomial
Definition claim.hpp:39
OpeningPair< Curve > opening_pair
Definition claim.hpp:40
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_EVALUATIONS > &libra_polynomials={}, const std::vector< Polynomial > &sumcheck_round_univariates={}, const std::vector< std::array< FF, 3 > > &sumcheck_round_evaluations={})
Definition shplemini.hpp:36
typename Curve::Element GroupElement
Definition shplemini.hpp:25
typename Curve::AffineElement Commitment
Definition shplemini.hpp:26
static std::vector< OpeningClaim > compute_libra_opening_claims(const FF gemini_r, const std::array< Polynomial, NUM_SMALL_IPA_EVALUATIONS > &libra_polynomials, const std::shared_ptr< Transcript > &transcript)
For ZK Flavors: Evaluate the polynomials used in SmallSubgroupIPA argument, send the evaluations to t...
Definition shplemini.hpp:79
typename Curve::ScalarField FF
Definition shplemini.hpp:24
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 void batch_gemini_claims_received_from_prover(std::span< const Fr > padding_indicator_array, 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 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::AffineElement Commitment
typename Curve::ScalarField Fr
static ShpleminiVerifierOutput compute_batch_opening_claim(std::span< const Fr > padding_indicator_array, 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_LIBRA_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,...
typename Curve::Element GroupElement
static void remove_repeated_commitments(std::vector< Commitment > &commitments, std::vector< Fr > &scalars, const RepeatedCommitmentsData &repeated_commitments, bool has_zk)
Combines scalars of repeating commitments to reduce the number of scalar multiplications performed by...
ShpleminiVerifierOutput_< Curve, HasZK > ShpleminiVerifierOutput
static void add_zk_data(const size_t virtual_log_n, std::vector< Commitment > &commitments, std::vector< Fr > &scalars, Fr &constant_term_accumulator, const std::array< Commitment, NUM_LIBRA_COMMITMENTS > &libra_commitments, const std::array< Fr, NUM_SMALL_IPA_EVALUATIONS > &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.
Shplonk Prover.
Definition shplonk.hpp:36
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)
Returns a batched opening claim equivalent to a set of opening claims consisting of polynomials,...
Definition shplonk.hpp:267
Shplonk Verifier.
Definition shplonk.hpp:343
static std::vector< Fr > compute_inverted_gemini_denominators(const Fr &shplonk_eval_challenge, const std::vector< Fr > &gemini_eval_challenge_powers)
Computes .
Definition shplonk.hpp:516
static bool check_libra_evaluations_consistency(const std::array< FF, NUM_SMALL_IPA_EVALUATIONS > &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
Definition grumpkin.hpp:62
static constexpr bool is_stdlib_type
Definition grumpkin.hpp:69
typename Group::affine_element AffineElement
Definition grumpkin.hpp:63
static constexpr ScalarField subgroup_generator
Definition grumpkin.hpp:79
ssize_t offset
Definition engine.cpp:36
std::vector< Fr > powers_of_evaluation_challenge(const Fr &r, const size_t num_squares)
Compute squares of folding challenge r.
Definition gemini.hpp:94
constexpr T get_msb(const T in)
Definition get_msb.hpp:47
Entry point for Barretenberg command-line interface.
Definition api.hpp:5
constexpr decltype(auto) get(::tuplet::tuple< T... > &&t) noexcept
Definition tuple.hpp:13
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.
Definition claim.hpp:151
Logic to support batching opening claims for unshifted, shifted and interleaved polynomials in Shplem...
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...
void update_batch_mul_inputs_and_batched_evaluation(std::vector< Commitment > &commitments, std::vector< Fr > &scalars, Fr &batched_evaluation, const Fr &rho, Fr shplonk_batching_pos={ 0 }, Fr shplonk_batching_neg={ 0 })
Append the commitments and scalars from each batch of claims to the Shplemini, vectors which subseque...
std::optional< InterleavedBatch > interleaved
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