Barretenberg
The ZK-SNARK library at the core of Aztec
Loading...
Searching...
No Matches
sumcheck.hpp
Go to the documentation of this file.
1// === AUDIT STATUS ===
2// internal: { status: not started, auditors: [], date: YYYY-MM-DD }
3// external_1: { status: not started, auditors: [], date: YYYY-MM-DD }
4// external_2: { status: not started, auditors: [], date: YYYY-MM-DD }
5// =====================
6
7#pragma once
16#include "sumcheck_round.hpp"
17
18namespace bb {
19
126template <typename Flavor> class SumcheckProver {
127 public:
128 using FF = typename Flavor::FF;
129 // PartiallyEvaluatedMultivariates OR ProverPolynomials
130 // both inherit from AllEntities
138
145
146 // this constant specifies the number of coefficients of libra polynomials, and evaluations of round univariate
148
150
151 // The size of the hypercube, i.e. \f$ 2^d\f$.
152 const size_t multivariate_n;
153 // The number of variables
154 const size_t multivariate_d;
155 // A reference to all prover multilinear polynomials.
157
158 std::shared_ptr<Transcript> transcript;
159 // Contains the core sumcheck methods such as `compute_univariate`.
161 // An array of size NUM_SUBRELATIONS-1 containing challenges or consecutive powers of a single challenge that
162 // separate linearly independent subrelation.
164 // pow_β(X₀, ..., X_{d−1}) = ∏ₖ₌₀^{d−1} (1 − Xₖ + Xₖ ⋅ βₖ)
165 std::vector<FF> gate_challenges;
166 // Contains various challenges, such as `beta` and `gamma` used in the Grand Product argument.
168
169 // Determines the number of rounds in the sumcheck (may include padding rounds, i.e. >= multivariate_d).
171
172 std::vector<FF> multivariate_challenge;
173
174 std::vector<typename Flavor::Commitment> round_univariate_commitments = {};
177 std::vector<FF> eval_domain = {};
178 // For computing eq polymomials in Multilinear Batching Flavor
179 std::vector<FF> accumulator_challenge = {};
180 std::vector<FF> instance_challenge = {};
182
184
195
196 // SumcheckProver constructor for the Flavors that generate NUM_SUBRELATIONS - 1 subrelation separator challenges.
198 ProverPolynomials& prover_polynomials,
199 std::shared_ptr<Transcript> transcript,
200 const SubrelationSeparators& relation_separator,
201 const std::vector<FF>& gate_challenges,
203 const size_t virtual_log_n,
204 const std::vector<FF>& accumulator_challenge = {},
205 const std::vector<FF>& instance_challenge = {})
208 , full_polynomials(prover_polynomials)
209 , transcript(std::move(transcript))
211 , alphas(relation_separator)
217
218 // SumcheckProver constructor for the Flavors that generate a single challenge `alpha` and use its powers as
219 // subrelation seperator challenges.
221 ProverPolynomials& prover_polynomials,
222 std::shared_ptr<Transcript> transcript,
223 const FF& alpha,
224 const std::vector<FF>& gate_challenges,
226 const size_t virtual_log_n,
227 const std::vector<FF>& accumulator_challenge = {},
228 const std::vector<FF>& instance_challenge = {})
231 , full_polynomials(prover_polynomials)
232 , transcript(std::move(transcript))
234 , alphas(initialize_relation_separator<FF, Flavor::NUM_SUBRELATIONS - 1>(alpha))
247 {
248 vinfo("starting sumcheck rounds...");
249
250 // Given gate challenges β = (β₀, ..., β_{d−1}) and d = `multivariate_d`, compute the evaluations of
251 // GateSeparator_β (X₀, ..., X_{d−1}) = ∏ₖ₌₀^{d−1} (1 − Xₖ + Xₖ · βₖ)
252 // on the boolean hypercube.
254
256 // In the first round, we compute the first univariate polynomial and populate the book-keeping table of
257 // #partially_evaluated_polynomials, which has \f$ n/2 \f$ rows and \f$ N \f$ columns.
258 auto round_univariate =
259 round.compute_univariate(full_polynomials, relation_parameters, gate_separators, alphas);
260 // Initialize the partially evaluated polynomials which will be used in the following rounds.
261 // This will use the information in the structured full polynomials to save memory if possible.
263
264 {
265 BB_BENCH_NAME("rest of sumcheck round 1");
266
267 // Place the evaluations of the round univariate into transcript.
268 transcript->send_to_verifier("Sumcheck:univariate_0", round_univariate);
269 FF round_challenge = transcript->template get_challenge<FF>("Sumcheck:u_0");
270 multivariate_challenge.emplace_back(round_challenge);
271 // Prepare sumcheck book-keeping table for the next round
272 partially_evaluate(full_polynomials, round_challenge);
273
274 gate_separators.partially_evaluate(round_challenge);
275 round.round_size = round.round_size >> 1; // TODO(#224)(Cody): Maybe partially_evaluate should do this and
276 // release memory? // All but final round
277 // We operate on partially_evaluated_polynomials in place.
278 }
279 for (size_t round_idx = 1; round_idx < multivariate_d; round_idx++) {
280 BB_BENCH_NAME("sumcheck loop");
281
282 // Write the round univariate to the transcript
283 round_univariate =
284 round.compute_univariate(partially_evaluated_polynomials, relation_parameters, gate_separators, alphas);
285 // Place evaluations of Sumcheck Round Univariate in the transcript
286 transcript->send_to_verifier("Sumcheck:univariate_" + std::to_string(round_idx), round_univariate);
287 FF round_challenge = transcript->template get_challenge<FF>("Sumcheck:u_" + std::to_string(round_idx));
288 multivariate_challenge.emplace_back(round_challenge);
289 // Prepare sumcheck book-keeping table for the next round.
291 gate_separators.partially_evaluate(round_challenge);
292 round.round_size = round.round_size >> 1;
293 }
294 vinfo("completed ", multivariate_d, " rounds of sumcheck");
295
297 // If required, extend prover's multilinear polynomials in `multivariate_d` variables by zero to get multilinear
298 // polynomials in `virtual_log_n` variables.
299 for (size_t k = multivariate_d; k < virtual_log_n; ++k) {
300 if constexpr (isMultilinearBatchingFlavor) {
301 // We need to specify the evaluation at index 1 for eq polynomials
302 std::vector<FF> index_1_challenge(virtual_log_n);
303 for (size_t i = 0; i < k; i++) {
304 index_1_challenge[i] = multivariate_challenge[i];
305 }
306 index_1_challenge[k] = FF(1);
307 if (partially_evaluated_polynomials.w_evaluations_accumulator.size() == 1) {
308
309 // We need to reallocate the polynomials
310 auto new_polynomial =
311 Polynomial<FF>(2, partially_evaluated_polynomials.w_evaluations_accumulator.virtual_size());
312 new_polynomial.at(0) = partially_evaluated_polynomials.w_evaluations_accumulator.at(0);
313 partially_evaluated_polynomials.w_evaluations_accumulator = new_polynomial;
314 }
315 if (partially_evaluated_polynomials.w_evaluations_instance.size() == 1) {
316 // We need to reallocate the polynomials
317 auto new_polynomial =
318 Polynomial<FF>(2, partially_evaluated_polynomials.w_evaluations_instance.virtual_size());
319 new_polynomial.at(0) = partially_evaluated_polynomials.w_evaluations_instance.at(0);
320 partially_evaluated_polynomials.w_evaluations_instance = new_polynomial;
321 }
322 partially_evaluated_polynomials.w_evaluations_accumulator.at(1) =
324 partially_evaluated_polynomials.w_evaluations_instance.at(1) =
326 index_1_challenge[k] = FF(0);
327 }
328 // Compute the contribution from the extensions by zero. It is sufficient to evaluate the main constraint at
329 // `MAX_PARTIAL_RELATION_LENGTH` points.
330 const auto virtual_round_univariate = round.compute_virtual_contribution(
332
333 transcript->send_to_verifier("Sumcheck:univariate_" + std::to_string(k), virtual_round_univariate);
334
335 const FF round_challenge = transcript->template get_challenge<FF>("Sumcheck:u_" + std::to_string(k));
336 multivariate_challenge.emplace_back(round_challenge);
337
338 // Update the book-keeping table of partial evaluations of the prover polynomials extended by zero.
339 for (auto& poly : partially_evaluated_polynomials.get_all()) {
340 // Avoid bad access if polynomials are set to be of size 0, which can happen in AVM.
341 if (poly.size() > 0) {
342 if (poly.size() == 1) {
343 poly.at(0) *= (FF(1) - round_challenge);
344 } else if (poly.size() == 2) {
345 // Here we handle the eq polynomial case
346 poly.at(0) = poly.at(0) * (FF(1) - round_challenge) + poly.at(1) * round_challenge;
347 poly.at(1) = 0;
348 } else {
349 BB_ASSERT_EQ(true, false, "Polynomial size is not 1 or 2");
350 }
351 }
352 }
353 virtual_gate_separator.partially_evaluate(round_challenge);
354 }
355
357 transcript->send_to_verifier("Sumcheck:evaluations", multivariate_evaluations.get_all());
358 // For ZK Flavors: the evaluations of Libra univariates are included in the Sumcheck Output
359
361 .claimed_evaluations = multivariate_evaluations };
362 vinfo("finished sumcheck");
363 };
364
372 SumcheckOutput<Flavor> prove(ZKData& zk_sumcheck_data)
373 requires Flavor::HasZK
374 {
376
377 if constexpr (IsGrumpkinFlavor<Flavor>) {
379 // Compute the vector {0, 1, \ldots, BATCHED_RELATION_PARTIAL_LENGTH-1} needed to transform the round
380 // univariates from Lagrange to monomial basis
381 for (size_t idx = 0; idx < BATCHED_RELATION_PARTIAL_LENGTH; idx++) {
382 eval_domain.push_back(FF(idx));
383 }
384 }
385
386 vinfo("starting sumcheck rounds...");
387 // Given gate challenges β = (β₀, ..., β_{d−1}) and d = `multivariate_d`, compute the evaluations of
388 // GateSeparator_β (X₀, ..., X_{d−1}) = ∏ₖ₌₀^{d−1} (1 − Xₖ + Xₖ · βₖ)
389 // on the boolean hypercube.
390 GateSeparatorPolynomial<FF> gate_separators(gate_challenges, multivariate_d);
391
393 size_t round_idx = 0;
394 // In the first round, we compute the first univariate polynomial and populate the book-keeping table of
395 // #partially_evaluated_polynomials, which has \f$ n/2 \f$ rows and \f$ N \f$ columns.
396 auto hiding_univariate = round.compute_hiding_univariate(round_idx,
399 gate_separators,
400 alphas,
401 zk_sumcheck_data,
403 auto round_univariate =
404 round.compute_univariate(full_polynomials, relation_parameters, gate_separators, alphas);
405 round_univariate += hiding_univariate;
406
407 // Initialize the partially evaluated polynomials which will be used in the following rounds.
408 // This will use the information in the structured full polynomials to save memory if possible.
410
411 {
412 BB_BENCH_NAME("rest of sumcheck round 1");
413
414 if constexpr (!IsGrumpkinFlavor<Flavor>) {
415 // Place the evaluations of the round univariate into transcript.
416 transcript->send_to_verifier("Sumcheck:univariate_0", round_univariate);
417 } else {
418
419 // Compute monomial coefficients of the round univariate, commit to it, populate an auxiliary structure
420 // needed in the PCS round
421 commit_to_round_univariate(round_idx, round_univariate, ck);
422 }
423
424 const FF round_challenge = transcript->template get_challenge<FF>("Sumcheck:u_0");
425
426 multivariate_challenge.emplace_back(round_challenge);
427 // Prepare sumcheck book-keeping table for the next round
428 partially_evaluate(full_polynomials, round_challenge);
429 // Prepare ZK Sumcheck data for the next round
430 zk_sumcheck_data.update_zk_sumcheck_data(round_challenge, round_idx);
431 row_disabling_polynomial.update_evaluations(round_challenge, round_idx);
432 gate_separators.partially_evaluate(round_challenge);
433 round.round_size = round.round_size >> 1; // TODO(#224)(Cody): Maybe partially_evaluate should do this and
434 // release memory? // All but final round
435 // We operate on partially_evaluated_polynomials in place.
436 }
437 for (size_t round_idx = 1; round_idx < multivariate_d; round_idx++) {
438 BB_BENCH_NAME("sumcheck loop");
439
440 // Computes the round univariate in two parts: first the contribution necessary to hide the polynomial and
441 // account for having randomness at the end of the trace and then the contribution from the full
442 // relation. Note: we compute the hiding univariate first as the `compute_univariate` method prepares
443 // relevant data structures for the next round
444 hiding_univariate = round.compute_hiding_univariate(round_idx,
447 gate_separators,
448 alphas,
449 zk_sumcheck_data,
451 round_univariate =
452 round.compute_univariate(partially_evaluated_polynomials, relation_parameters, gate_separators, alphas);
453 round_univariate += hiding_univariate;
454
455 if constexpr (!IsGrumpkinFlavor<Flavor>) {
456 // Place evaluations of Sumcheck Round Univariate in the transcript
457 transcript->send_to_verifier("Sumcheck:univariate_" + std::to_string(round_idx), round_univariate);
458 } else {
459
460 // Compute monomial coefficients of the round univariate, commit to it, populate an auxiliary structure
461 // needed in the PCS round
462 commit_to_round_univariate(round_idx, round_univariate, ck);
463 }
464 const FF round_challenge =
465 transcript->template get_challenge<FF>("Sumcheck:u_" + std::to_string(round_idx));
466 multivariate_challenge.emplace_back(round_challenge);
467 // Prepare sumcheck book-keeping table for the next round.
469 // Prepare evaluation masking and libra structures for the next round (for ZK Flavors)
470 zk_sumcheck_data.update_zk_sumcheck_data(round_challenge, round_idx);
471 row_disabling_polynomial.update_evaluations(round_challenge, round_idx);
472
473 gate_separators.partially_evaluate(round_challenge);
474 round.round_size = round.round_size >> 1;
475 }
476
477 if constexpr (IsGrumpkinFlavor<Flavor>) {
479 round_univariate.evaluate(multivariate_challenge[multivariate_d - 1]);
480 }
481 vinfo("completed ", multivariate_d, " rounds of sumcheck");
482
483 // Zero univariates are used to pad the proof to the fixed size virtual_log_n.
485 for (size_t idx = multivariate_d; idx < virtual_log_n; idx++) {
486 transcript->send_to_verifier("Sumcheck:univariate_" + std::to_string(idx), zero_univariate);
487
488 FF round_challenge = transcript->template get_challenge<FF>("Sumcheck:u_" + std::to_string(idx));
489 multivariate_challenge.emplace_back(round_challenge);
490 }
491
492 // Claimed evaluations of Prover polynomials are extracted and added to the transcript. When Flavor has ZK, the
493 // evaluations of all witnesses are masked.
495 transcript->send_to_verifier("Sumcheck:evaluations", multivariate_evaluations.get_all());
496
497 // The evaluations of Libra uninvariates at \f$ g_0(u_0), \ldots, g_{d-1} (u_{d-1}) \f$ are added to the
498 // transcript.
499 FF libra_evaluation = zk_sumcheck_data.constant_term;
500 for (const auto& libra_eval : zk_sumcheck_data.libra_evaluations) {
501 libra_evaluation += libra_eval;
502 }
503 transcript->send_to_verifier("Libra:claimed_evaluation", libra_evaluation);
504
505 // The sum of the Libra constant term and the evaluations of Libra univariates at corresponding sumcheck
506 // challenges is included in the Sumcheck Output
507 if constexpr (!IsGrumpkinFlavor<Flavor>) {
508 return SumcheckOutput<Flavor>{ .challenge = multivariate_challenge,
509 .claimed_evaluations = multivariate_evaluations,
510 .claimed_libra_evaluation = libra_evaluation };
511 } else {
512 return SumcheckOutput<Flavor>{ .challenge = multivariate_challenge,
513 .claimed_evaluations = multivariate_evaluations,
514 .claimed_libra_evaluation = libra_evaluation,
515 .round_univariates = round_univariates,
516 .round_univariate_evaluations = round_evaluations };
517 }
518 vinfo("finished sumcheck");
519 };
520
556 void partially_evaluate(auto& polynomials, const FF& round_challenge)
557 {
558 auto pep_view = partially_evaluated_polynomials.get_all();
559 auto poly_view = polynomials.get_all();
560 // after the first round, operate in place on partially_evaluated_polynomials
561 parallel_for(poly_view.size(), [&](size_t j) {
562 const auto& poly = poly_view[j];
563 // The polynomial is shorter than the round size.
564 size_t limit = poly.end_index();
565 for (size_t i = 0; i < limit; i += 2) {
566 pep_view[j].at(i >> 1) = poly[i] + round_challenge * (poly[i + 1] - poly[i]);
567 }
568
569 // We resize pep_view[j] to have the exact size required for the next round which is
570 // CEIL(limit/2). This has the effect to reduce the limit in next round and also to
571 // virtually zeroize any leftover values beyond the limit (in-place computation).
572 // This is important to zeroize leftover values to not mess up with compute_univariate().
573 // Note that the virtual size of pep_view[j] remains unchanged.
574 pep_view[j].shrink_end_index((limit / 2) + (limit % 2));
575 });
576 };
581 template <typename PolynomialT, std::size_t N>
582 void partially_evaluate(std::array<PolynomialT, N>& polynomials, const FF& round_challenge)
583 {
584 auto pep_view = partially_evaluated_polynomials.get_all();
585 // after the first round, operate in place on partially_evaluated_polynomials
586 parallel_for(polynomials.size(), [&](size_t j) {
587 const auto& poly = polynomials[j];
588 // The polynomial is shorter than the round size.
589 size_t limit = poly.end_index();
590 for (size_t i = 0; i < limit; i += 2) {
591 pep_view[j].at(i >> 1) = poly[i] + round_challenge * (poly[i + 1] - poly[i]);
592 }
593
594 // We resize pep_view[j] to have the exact size required for the next round which is
595 // CEIL(limit/2). This has the effect to reduce the limit in next round and also to
596 // virtually zeroize any leftover values beyond the limit (in-place computation).
597 // This is important to zeroize leftover values to not mess up with compute_univariate().
598 // Note that the virtual size of pep_view[j] remains unchanged.
599 pep_view[j].shrink_end_index((limit / 2) + (limit % 2));
600 });
601 };
602
615 {
616 ClaimedEvaluations multivariate_evaluations;
617 for (auto [eval, poly] :
618 zip_view(multivariate_evaluations.get_all(), partially_evaluated_polynomials.get_all())) {
619 eval = poly[0];
620 };
621 return multivariate_evaluations;
622 };
623
636 void commit_to_round_univariate(const size_t round_idx,
638 const CommitmentKey& ck)
639
640 {
641 const std::string idx = std::to_string(round_idx);
642
643 // Transform to monomial form and commit to it
644 Polynomial<FF> round_poly_monomial(
645 eval_domain, std::span<FF>(round_univariate.evaluations), BATCHED_RELATION_PARTIAL_LENGTH);
646 transcript->send_to_verifier("Sumcheck:univariate_comm_" + idx, ck.commit(round_poly_monomial));
647
648 // Store round univariate in monomial, as it is required by Shplemini
649 round_univariates.push_back(std::move(round_poly_monomial));
650
651 // Send the evaluations of the round univariate at 0 and 1
652 transcript->send_to_verifier("Sumcheck:univariate_" + idx + "_eval_0", round_univariate.value_at(0));
653 transcript->send_to_verifier("Sumcheck:univariate_" + idx + "_eval_1", round_univariate.value_at(1));
654
655 // Store the evaluations to be used by ShpleminiProver.
656 round_evaluations.push_back({ round_univariate.value_at(0), round_univariate.value_at(1), FF(0) });
657 if (round_idx > 0) {
658 round_evaluations[round_idx - 1][2] = round_univariate.value_at(0) + round_univariate.value_at(1);
659 };
660 }
661};
698template <typename Flavor> class SumcheckVerifier {
699
700 public:
702 using FF = typename Flavor::FF;
709 // For ZK Flavors: the verifier obtains a vector of evaluations of \f$ d \f$ univariate polynomials and uses them to
710 // compute full_honk_relation_purported_value
711 using ClaimedLibraEvaluations = typename std::vector<FF>;
715
720 static constexpr size_t BATCHED_RELATION_PARTIAL_LENGTH = Flavor::BATCHED_RELATION_PARTIAL_LENGTH;
725 static constexpr size_t NUM_POLYNOMIALS = Flavor::NUM_ALL_ENTITIES;
726
727 std::shared_ptr<Transcript> transcript;
729
730 // Determines number of rounds in the sumcheck (may include padding rounds)
732
733 // An array of size NUM_SUBRELATIONS-1 containing challenges or consecutive powers of a single challenge that
734 // separate linearly independent subrelation.
736 FF libra_evaluation{ 0 };
739
741
742 std::vector<Commitment> round_univariate_commitments = {};
743 std::vector<std::array<FF, 3>> round_univariate_evaluations = {};
744
745 explicit SumcheckVerifier(std::shared_ptr<Transcript> transcript,
746 SubrelationSeparators& relation_separator,
747 size_t virtual_log_n,
748 FF target_sum = 0)
749 : transcript(std::move(transcript))
750 , round(target_sum)
751 , virtual_log_n(virtual_log_n)
752 , alphas(relation_separator) {};
753
754 explicit SumcheckVerifier(std::shared_ptr<Transcript> transcript,
755 const FF& alpha,
756 size_t virtual_log_n,
757 FF target_sum = 0)
758 : transcript(std::move(transcript))
759 , round(target_sum)
760 , virtual_log_n(virtual_log_n)
761 , alphas(initialize_relation_separator<FF, Flavor::NUM_SUBRELATIONS - 1>(alpha)) {};
772 std::vector<FF>& gate_challenges,
773 const std::vector<FF>& padding_indicator_array)
774 requires(!IsGrumpkinFlavor<Flavor>)
775 {
776 bool verified(true);
777
778 bb::GateSeparatorPolynomial<FF> gate_separators(gate_challenges);
779 // All but final round.
780 // target_total_sum is initialized to zero then mutated in place.
781
783
784 if constexpr (Flavor::HasZK) {
785 // If running zero-knowledge sumcheck the target total sum is corrected by the claimed sum of libra masking
786 // multivariate over the hypercube
787 libra_total_sum = transcript->template receive_from_prover<FF>("Libra:Sum");
788 libra_challenge = transcript->template get_challenge<FF>("Libra:Challenge");
789 round.target_total_sum = libra_total_sum * libra_challenge;
790 }
791
792 std::vector<FF> multivariate_challenge;
793 multivariate_challenge.reserve(virtual_log_n);
794 for (size_t round_idx = 0; round_idx < virtual_log_n; round_idx++) {
795 // Obtain the round univariate from the transcript
796 std::string round_univariate_label = "Sumcheck:univariate_" + std::to_string(round_idx);
797 round_univariate =
798 transcript->template receive_from_prover<bb::Univariate<FF, BATCHED_RELATION_PARTIAL_LENGTH>>(
799 round_univariate_label);
800 FF round_challenge = transcript->template get_challenge<FF>("Sumcheck:u_" + std::to_string(round_idx));
801 multivariate_challenge.emplace_back(round_challenge);
802
803 const bool checked = round.check_sum(round_univariate, padding_indicator_array[round_idx]);
804 round.compute_next_target_sum(round_univariate, round_challenge, padding_indicator_array[round_idx]);
805 gate_separators.partially_evaluate(round_challenge, padding_indicator_array[round_idx]);
806
807 verified = verified && checked;
808 }
809 // Extract claimed evaluations of Libra univariates and compute their sum multiplied by the Libra challenge
810 // Final round
811 ClaimedEvaluations purported_evaluations;
812 auto transcript_evaluations =
813 transcript->template receive_from_prover<std::array<FF, NUM_POLYNOMIALS>>("Sumcheck:evaluations");
814 for (auto [eval, transcript_eval] : zip_view(purported_evaluations.get_all(), transcript_evaluations)) {
815 eval = transcript_eval;
816 }
817
818 // Evaluate the Honk relation at the point (u_0, ..., u_{d-1}) using claimed evaluations of prover polynomials.
819 // In ZK Flavors, the evaluation is corrected by full_libra_purported_value
820 FF full_honk_purported_value = round.compute_full_relation_purported_value(
821 purported_evaluations, relation_parameters, gate_separators, alphas);
822
823 // For ZK Flavors: compute the evaluation of the Row Disabling Polynomial at the sumcheck challenge and of the
824 // libra univariate used to hide the contribution from the actual Honk relation
825 if constexpr (Flavor::HasZK) {
826 if constexpr (UseRowDisablingPolynomial<Flavor>) {
827 // Compute the evaluations of the polynomial (1 - \sum L_i) where the sum is for i corresponding to the
828 // rows where all sumcheck relations are disabled
829 full_honk_purported_value *=
830 RowDisablingPolynomial<FF>::evaluate_at_challenge(multivariate_challenge, padding_indicator_array);
831 }
832
833 libra_evaluation = transcript->template receive_from_prover<FF>("Libra:claimed_evaluation");
834 full_honk_purported_value += libra_evaluation * libra_challenge;
835 }
836
838 bool final_check(false);
839 if constexpr (IsRecursiveFlavor<Flavor>) {
840 // These booleans are only needed for debugging
841 final_check = (full_honk_purported_value.get_value() == round.target_total_sum.get_value());
842 verified = verified && final_check;
843
844 full_honk_purported_value.assert_equal(round.target_total_sum);
845 } else {
846 final_check = (full_honk_purported_value == round.target_total_sum);
847 verified = verified && final_check;
848 }
849
850 return SumcheckOutput<Flavor>{ .challenge = multivariate_challenge,
851 .claimed_evaluations = purported_evaluations,
852 .verified = verified,
853 .claimed_libra_evaluation = libra_evaluation };
854 };
855
872 const std::vector<FF>& gate_challenges)
874 {
875 bool verified(false);
876
877 bb::GateSeparatorPolynomial<FF> gate_separators(gate_challenges);
878
879 // get the claimed sum of libra masking multivariate over the hypercube
880 libra_total_sum = transcript->template receive_from_prover<FF>("Libra:Sum");
881 // get the challenge for the ZK Sumcheck claim
882 const FF libra_challenge = transcript->template get_challenge<FF>("Libra:Challenge");
883
884 std::vector<FF> multivariate_challenge;
885 multivariate_challenge.reserve(virtual_log_n);
886 // if Flavor has ZK, the target total sum is corrected by Libra total sum multiplied by the Libra
887 // challenge
888 round.target_total_sum = libra_total_sum * libra_challenge;
889
890 for (size_t round_idx = 0; round_idx < virtual_log_n; round_idx++) {
891 // Obtain the round univariate from the transcript
892 const std::string round_univariate_comm_label = "Sumcheck:univariate_comm_" + std::to_string(round_idx);
893 const std::string univariate_eval_label_0 = "Sumcheck:univariate_" + std::to_string(round_idx) + "_eval_0";
894 const std::string univariate_eval_label_1 = "Sumcheck:univariate_" + std::to_string(round_idx) + "_eval_1";
895
896 // Receive the commitment to the round univariate
897 round_univariate_commitments.push_back(
898 transcript->template receive_from_prover<Commitment>(round_univariate_comm_label));
899 // Receive evals at 0 and 1
900 round_univariate_evaluations.push_back(
901 { transcript->template receive_from_prover<FF>(univariate_eval_label_0),
902 transcript->template receive_from_prover<FF>(univariate_eval_label_1) });
903
904 const FF round_challenge =
905 transcript->template get_challenge<FF>("Sumcheck:u_" + std::to_string(round_idx));
906 multivariate_challenge.emplace_back(round_challenge);
907
908 gate_separators.partially_evaluate(round_challenge);
909 }
910
911 FF first_sumcheck_round_evaluations_sum =
912 round_univariate_evaluations[0][0] + round_univariate_evaluations[0][1];
913
914 // Populate claimed evaluations at the challenge
915 ClaimedEvaluations purported_evaluations;
916 auto transcript_evaluations =
917 transcript->template receive_from_prover<std::array<FF, NUM_POLYNOMIALS>>("Sumcheck:evaluations");
918 for (auto [eval, transcript_eval] : zip_view(purported_evaluations.get_all(), transcript_evaluations)) {
919 eval = transcript_eval;
920 }
921 // For ZK Flavors: the evaluation of the Row Disabling Polynomial at the sumcheck challenge
922 // Evaluate the Honk relation at the point (u_0, ..., u_{d-1}) using claimed evaluations of prover polynomials.
923 // In ZK Flavors, the evaluation is corrected by full_libra_purported_value
924 FF full_honk_purported_value = round.compute_full_relation_purported_value(
925 purported_evaluations, relation_parameters, gate_separators, alphas);
926
927 // Compute the evaluations of the polynomial (1 - \sum L_i) where the sum is for i corresponding to the rows
928 // where all sumcheck relations are disabled
929 full_honk_purported_value *=
930 RowDisablingPolynomial<FF>::evaluate_at_challenge(multivariate_challenge, virtual_log_n);
931
932 // Extract claimed evaluations of Libra univariates and compute their sum multiplied by the Libra challenge
933 const FF libra_evaluation = transcript->template receive_from_prover<FF>("Libra:claimed_evaluation");
934 // Verifier computes full ZK Honk value, taking into account the contribution from the disabled row and the
935 // Libra polynomials
936 full_honk_purported_value += libra_evaluation * libra_challenge;
937
938 // Populate claimed evaluations of Sumcheck Round Unviariates at the round challenges. These will be checked as
939 // a part of Shplemini.
940 for (size_t round_idx = 1; round_idx < virtual_log_n; round_idx++) {
941 round_univariate_evaluations[round_idx - 1][2] =
942 round_univariate_evaluations[round_idx][0] + round_univariate_evaluations[round_idx][1];
943 };
944
945 if constexpr (IsRecursiveFlavor<Flavor>) {
946
947 first_sumcheck_round_evaluations_sum.self_reduce();
948 round.target_total_sum.self_reduce();
949
950 // This bool is only needed for debugging
951 verified = (first_sumcheck_round_evaluations_sum.get_value() == round.target_total_sum.get_value());
952 // Ensure that the sum of the evaluations of the first Sumcheck Round Univariate is equal to the claimed
953 // target total sum
954 first_sumcheck_round_evaluations_sum.assert_equal(round.target_total_sum);
955
956 // TODO(https://github.com/AztecProtocol/barretenberg/issues/1197)
957 full_honk_purported_value.self_reduce();
958
959 } else {
960 // Ensure that the sum of the evaluations of the first Sumcheck Round Univariate is equal to the claimed
961 // target total sum
962 verified = (first_sumcheck_round_evaluations_sum == round.target_total_sum);
963 }
964
965 round_univariate_evaluations[virtual_log_n - 1][2] = full_honk_purported_value;
966
968 // For ZK Flavors: the evaluations of Libra univariates are included in the Sumcheck Output
969 return SumcheckOutput<Flavor>{ .challenge = multivariate_challenge,
970 .claimed_evaluations = purported_evaluations,
971 .verified = verified,
972 .claimed_libra_evaluation = libra_evaluation,
973 .round_univariate_commitments = round_univariate_commitments,
974 .round_univariate_evaluations = round_univariate_evaluations };
975 };
976};
977
978template <typename FF, size_t N> std::array<FF, N> initialize_relation_separator(const FF& alpha)
979{
980 std::array<FF, N> alphas;
981 alphas[0] = alpha;
982 for (size_t i = 1; i < N; ++i) {
983 alphas[i] = alphas[i - 1] * alpha;
984 }
985 return alphas;
986}
987} // namespace bb
#define BB_ASSERT_EQ(actual, expected,...)
Definition assert.hpp:88
#define BB_BENCH_NAME(name)
Definition bb_bench.hpp:218
CommitmentKey object over a pairing group 𝔾₁.
static constexpr bool HasZK
typename Curve::ScalarField FF
static constexpr size_t NUM_ALL_ENTITIES
typename G1::affine_element Commitment
NativeTranscript Transcript
static constexpr size_t BATCHED_RELATION_PARTIAL_LENGTH
std::array< FF, NUM_SUBRELATIONS - 1 > SubrelationSeparators
A field element for each entity of the flavor. These entities represent the prover polynomials evalua...
A container for storing the partially evaluated multivariates produced by sumcheck.
A container for the prover polynomials handles.
Curve::ScalarField FF
bb::CommitmentKey< Curve > CommitmentKey
std::array< FF, NUM_SUBRELATIONS - 1 > SubrelationSeparators
NativeTranscript Transcript
static constexpr bool HasZK
static constexpr size_t MAX_PARTIAL_RELATION_LENGTH
static constexpr size_t BATCHED_RELATION_PARTIAL_LENGTH
Structured polynomial class that represents the coefficients 'a' of a_0 + a_1 x .....
The implementation of the sumcheck Prover for statements of the form for multilinear polynomials .
Definition sumcheck.hpp:126
static constexpr size_t BATCHED_RELATION_PARTIAL_LENGTH
Definition sumcheck.hpp:147
std::vector< Polynomial< FF > > round_univariates
Definition sumcheck.hpp:176
typename Flavor::FF FF
Definition sumcheck.hpp:128
ProverPolynomials & full_polynomials
Definition sumcheck.hpp:156
const size_t multivariate_n
Definition sumcheck.hpp:152
bb::RelationParameters< FF > relation_parameters
Definition sumcheck.hpp:167
typename Flavor::Transcript Transcript
Definition sumcheck.hpp:135
std::vector< FF > accumulator_challenge
Definition sumcheck.hpp:179
std::vector< FF > instance_challenge
Definition sumcheck.hpp:180
std::vector< std::array< FF, 3 > > round_evaluations
Definition sumcheck.hpp:175
std::vector< typename Flavor::Commitment > round_univariate_commitments
Definition sumcheck.hpp:174
void partially_evaluate(std::array< PolynomialT, N > &polynomials, const FF &round_challenge)
Evaluate at the round challenge and prepare class for next round. Specialization for array,...
Definition sumcheck.hpp:582
static constexpr bool isMultilinearBatchingFlavor
Definition sumcheck.hpp:139
typename Flavor::ProverPolynomials ProverPolynomials
Definition sumcheck.hpp:131
static constexpr size_t MAX_PARTIAL_RELATION_LENGTH
The total algebraic degree of the Sumcheck relation as a polynomial in Prover Polynomials .
Definition sumcheck.hpp:144
void commit_to_round_univariate(const size_t round_idx, bb::Univariate< FF, BATCHED_RELATION_PARTIAL_LENGTH > &round_univariate, const CommitmentKey &ck)
Compute monomial coefficients of the round univariate, commit to it, populate an auxiliary structure ...
Definition sumcheck.hpp:636
const size_t multivariate_d
Definition sumcheck.hpp:154
ClaimedEvaluations extract_claimed_evaluations(PartiallyEvaluatedMultivariates &partially_evaluated_polynomials)
This method takes the book-keeping table containing partially evaluated prover polynomials and create...
Definition sumcheck.hpp:614
typename Flavor::AllValues ClaimedEvaluations
Definition sumcheck.hpp:133
typename bb::Univariate< FF, BATCHED_RELATION_PARTIAL_LENGTH > SumcheckRoundUnivariate
Definition sumcheck.hpp:149
std::vector< FF > eval_domain
Definition sumcheck.hpp:177
SumcheckProver(size_t multivariate_n, ProverPolynomials &prover_polynomials, std::shared_ptr< Transcript > transcript, const SubrelationSeparators &relation_separator, const std::vector< FF > &gate_challenges, const RelationParameters< FF > &relation_parameters, const size_t virtual_log_n, const std::vector< FF > &accumulator_challenge={}, const std::vector< FF > &instance_challenge={})
Definition sumcheck.hpp:197
SumcheckProver(size_t multivariate_n, ProverPolynomials &prover_polynomials, std::shared_ptr< Transcript > transcript, const FF &alpha, const std::vector< FF > &gate_challenges, const RelationParameters< FF > &relation_parameters, const size_t virtual_log_n, const std::vector< FF > &accumulator_challenge={}, const std::vector< FF > &instance_challenge={})
Definition sumcheck.hpp:220
std::vector< FF > multivariate_challenge
Definition sumcheck.hpp:172
SumcheckOutput< Flavor > prove(ZKData &zk_sumcheck_data) void partially_evaluate(auto &polynomials, const FF &round_challenge)
ZK-version of prove that runs Sumcheck with disabled rows and masking of Round Univariates....
Definition sumcheck.hpp:556
typename Flavor::PartiallyEvaluatedMultivariates PartiallyEvaluatedMultivariates
Definition sumcheck.hpp:132
RowDisablingPolynomial< FF > row_disabling_polynomial
Definition sumcheck.hpp:183
typename Flavor::CommitmentKey CommitmentKey
Definition sumcheck.hpp:137
std::vector< FF > gate_challenges
Definition sumcheck.hpp:165
SumcheckProverRound< Flavor > round
Definition sumcheck.hpp:160
typename Flavor::SubrelationSeparators SubrelationSeparators
Definition sumcheck.hpp:136
PartiallyEvaluatedMultivariates partially_evaluated_polynomials
Container for partially evaluated Prover Polynomials at a current challenge. Upon computing challenge...
Definition sumcheck.hpp:194
std::shared_ptr< Transcript > transcript
Definition sumcheck.hpp:158
SumcheckOutput< Flavor > prove()
Non-ZK version: Compute round univariate, place it in transcript, compute challenge,...
Definition sumcheck.hpp:246
ZKSumcheckData< Flavor > ZKData
Definition sumcheck.hpp:134
SubrelationSeparators alphas
Definition sumcheck.hpp:163
Imlementation of the Sumcheck prover round.
Implementation of the sumcheck Verifier for statements of the form for multilinear polynomials .
Definition sumcheck.hpp:698
SumcheckOutput< Flavor > verify(const bb::RelationParameters< FF > &relation_parameters, std::vector< FF > &gate_challenges, const std::vector< FF > &padding_indicator_array)
Extract round univariate, check sum, generate challenge, compute next target sum.....
Definition sumcheck.hpp:771
typename std::vector< FF > ClaimedLibraEvaluations
Definition sumcheck.hpp:711
SumcheckVerifier(std::shared_ptr< Transcript > transcript, SubrelationSeparators &relation_separator, size_t virtual_log_n, FF target_sum=0)
Definition sumcheck.hpp:745
typename Flavor::FF FF
Definition sumcheck.hpp:702
SumcheckOutput< Flavor > verify(const bb::RelationParameters< FF > &relation_parameters, const std::vector< FF > &gate_challenges)
Sumcheck Verifier for ECCVM and ECCVMRecursive.
Definition sumcheck.hpp:871
typename Flavor::Commitment Commitment
Definition sumcheck.hpp:714
SumcheckVerifierRound< Flavor > round
Definition sumcheck.hpp:728
typename Flavor::SubrelationSeparators SubrelationSeparators
Definition sumcheck.hpp:713
SumcheckVerifier(std::shared_ptr< Transcript > transcript, const FF &alpha, size_t virtual_log_n, FF target_sum=0)
Definition sumcheck.hpp:754
std::shared_ptr< Transcript > transcript
Definition sumcheck.hpp:727
typename Flavor::AllValues ClaimedEvaluations
Container type for the evaluations of Prover Polynomials at the challenge point .
Definition sumcheck.hpp:708
SubrelationSeparators alphas
Definition sumcheck.hpp:735
typename Flavor::Transcript Transcript
Definition sumcheck.hpp:712
Implementation of the Sumcheck Verifier Round.
FF compute_full_relation_purported_value(const ClaimedEvaluations &purported_evaluations, const bb::RelationParameters< FF > &relation_parameters, const bb::GateSeparatorPolynomial< FF > &gate_separators, const SubrelationSeparators &alphas)
Given the evaluations of the ProverPolynomials at the challenge point stored in purported_evaluatio...
void compute_next_target_sum(bb::Univariate< FF, BATCHED_RELATION_PARTIAL_LENGTH > &univariate, FF &round_challenge, const FF &indicator)
After checking that the univariate is good for this round, compute the next target sum given by the e...
bool check_sum(bb::Univariate< FF, BATCHED_RELATION_PARTIAL_LENGTH > &univariate, const FF &indicator)
Check that the round target sum is correct.
A univariate polynomial represented by its values on {domain_start, domain_start + 1,...
Fr & value_at(size_t i)
static Univariate zero()
std::array< Fr, LENGTH > evaluations
#define vinfo(...)
Definition log.hpp:79
constexpr T get_msb(const T in)
Definition get_msb.hpp:47
Entry point for Barretenberg command-line interface.
typename Flavor::FF FF
CommitmentKey< Curve > ck
std::array< FF, N > initialize_relation_separator(const FF &alpha)
Definition sumcheck.hpp:978
void parallel_for(size_t num_iterations, const std::function< void(size_t)> &func)
Definition thread.cpp:111
STL namespace.
constexpr decltype(auto) get(::tuplet::tuple< T... > &&t) noexcept
Definition tuple.hpp:13
std::string to_string(bb::avm2::ValueTag tag)
Implementation of the methods for the -polynomials used in in Sumcheck.
void partially_evaluate(FF challenge)
Partially evaluate the -polynomial at the new challenge and update .
Container for parameters used by the grand product (permutation, lookup) Honk relations.
Polynomial for Sumcheck with disabled Rows.
Contains the evaluations of multilinear polynomials at the challenge point . These are computed by S...
std::vector< FF > challenge
static FF eval(std::span< const FF > r_in, std::span< const FF > u)
This structure is created to contain various polynomials and constants required by ZK Sumcheck.