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: 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
18#include "sumcheck_round.hpp"
19#include <memory>
20
21namespace bb {
22
27template <typename Flavor, bool CommittedSumcheck = UsesCommittedSumcheck<Flavor>> struct RoundUnivariateHandler {
28 using FF = typename Flavor::FF;
32
33 std::shared_ptr<Transcript> transcript;
34
35 RoundUnivariateHandler(std::shared_ptr<Transcript> transcript)
36 : transcript(std::move(transcript))
37 {}
38
39 void process_round_univariate(size_t round_idx,
41 {
42 transcript->send_to_verifier("Sumcheck:univariate_" + std::to_string(round_idx), round_univariate);
43 }
44
45 void finalize_last_round(size_t /*multivariate_d*/,
47 const FF& /*last_challenge*/)
48 {}
49
52};
53
57template <typename Flavor> struct RoundUnivariateHandler<Flavor, true> {
58 using FF = typename Flavor::FF;
62
63 std::shared_ptr<Transcript> transcript;
65 std::vector<FF> eval_domain;
68
69 RoundUnivariateHandler(std::shared_ptr<Transcript> transcript)
70 : transcript(std::move(transcript))
72 {
73 // Compute the vector {0, 1, \ldots, BATCHED_RELATION_PARTIAL_LENGTH-1} needed to transform
74 // the round univariates from Lagrange to monomial basis
75 for (size_t idx = 0; idx < BATCHED_RELATION_PARTIAL_LENGTH; idx++) {
76 eval_domain.push_back(FF(idx));
77 }
78 }
79
80 void process_round_univariate(size_t round_idx,
82 {
83 const std::string idx = std::to_string(round_idx);
84
85 // Transform to monomial form and commit to it
86 Polynomial<FF> round_poly_monomial(
87 eval_domain, std::span<FF>(round_univariate.evaluations), BATCHED_RELATION_PARTIAL_LENGTH);
88 transcript->send_to_verifier("Sumcheck:univariate_comm_" + idx, ck.commit(round_poly_monomial));
89
90 // Store round univariate in monomial, as it is required by Shplemini
91 round_univariates.push_back(std::move(round_poly_monomial));
92
93 // Send the evaluations of the round univariate at 0 and 1
94 transcript->send_to_verifier("Sumcheck:univariate_" + idx + "_eval_0", round_univariate.value_at(0));
95 transcript->send_to_verifier("Sumcheck:univariate_" + idx + "_eval_1", round_univariate.value_at(1));
96
97 // Store the evaluations to be used by ShpleminiProver.
98 round_evaluations.push_back({ round_univariate.value_at(0), round_univariate.value_at(1), FF(0) });
99 if (round_idx > 0) {
100 round_evaluations[round_idx - 1][2] = round_univariate.value_at(0) + round_univariate.value_at(1);
101 }
102 }
103
104 void finalize_last_round(size_t multivariate_d,
106 const FF& last_challenge)
107 {
108 round_evaluations[multivariate_d - 1][2] = round_univariate.evaluate(last_challenge);
109 }
110
111 std::vector<std::array<FF, 3>> get_evaluations() { return round_evaluations; }
112 std::vector<Polynomial<FF>> get_univariates() { return round_univariates; }
113};
114
119template <typename Flavor, bool HasZK = Flavor::HasZK> struct VerifierZKCorrectionHandler {
120 using FF = typename Flavor::FF;
123
124 std::shared_ptr<Transcript> transcript;
127
128 // Construct a handler which will handle all the evaluations/
129 VerifierZKCorrectionHandler(std::shared_ptr<Transcript> transcript)
130 : transcript(std::move(transcript))
131 {}
132
134
135 void apply_zk_corrections(FF& /*full_honk_purported_value*/, const std::vector<FF>& /*multivariate_challenge*/) {}
136
138};
139
143template <typename Flavor> struct VerifierZKCorrectionHandler<Flavor, true> {
144 using FF = typename Flavor::FF;
147
148 std::shared_ptr<Transcript> transcript;
149 FF libra_total_sum = FF{ 0 };
152
153 // If running zero-knowledge sumcheck the target total sum is corrected by the claimed sum of libra masking
154 // multivariate over the hypercube
155 VerifierZKCorrectionHandler(std::shared_ptr<Transcript> transcript)
156 : transcript(std::move(transcript))
157 , libra_total_sum(this->transcript->template receive_from_prover<FF>("Libra:Sum"))
158 , libra_challenge(this->transcript->template get_challenge<FF>("Libra:Challenge"))
159 {}
160
161 void initialize_target_sum(SumcheckRound& round) { round.target_total_sum = libra_total_sum * libra_challenge; }
162
163 void apply_zk_corrections(FF& full_honk_purported_value, std::vector<FF>& multivariate_challenge)
164 {
165 if constexpr (UseRowDisablingPolynomial<Flavor>) {
166 // The row-disabling polynomial 1 - ∏_{i≥2}(1-u_i) is circuit-size
167 // independent. The verifier evaluates it over ALL challenges.
168 full_honk_purported_value *= RowDisablingPolynomial<FF>::evaluate_at_challenge(
169 multivariate_challenge, multivariate_challenge.size());
170 }
171
172 // Get the claimed evaluation of the Libra multivariate evaluated at the sumcheck challenge
173 libra_evaluation = transcript->template receive_from_prover<FF>("Libra:claimed_evaluation");
174
175 // OriginTag false positive: libra_evaluation is PCS-bound (verified by Shplemini opening).
176 // Once commitments are fixed and sumcheck challenges derived, the correct evaluation is determined.
177 if constexpr (IsRecursiveFlavor<Flavor>) {
178 const auto challenge_tag = multivariate_challenge.back().get_origin_tag();
179 libra_evaluation.set_origin_tag(challenge_tag);
180 }
181
182 full_honk_purported_value += libra_evaluation * libra_challenge;
183 }
184
186};
187
294template <typename Flavor> class SumcheckProver {
295 public:
296 using FF = typename Flavor::FF;
297 // PartiallyEvaluatedMultivariates OR ProverPolynomials
298 // both inherit from AllEntities
306
313
314 // this constant specifies the number of coefficients of libra polynomials, and evaluations of round univariate
316
318
319 // The size of the hypercube, i.e. \f$ 2^d\f$.
320 const size_t multivariate_n;
321 // The number of variables
322 const size_t multivariate_d;
323 // A reference to all prover multilinear polynomials.
325
326 std::shared_ptr<Transcript> transcript;
327 // Contains the core sumcheck methods such as `compute_univariate`.
329 // An array of size NUM_SUBRELATIONS-1 containing challenges or consecutive powers of a single challenge that
330 // separate linearly independent subrelation.
332 // pow_β(X₀, ..., X_{d−1}) = ∏ₖ₌₀^{d−1} (1 − Xₖ + Xₖ ⋅ βₖ)
333 std::vector<FF> gate_challenges;
334 // Contains various challenges, such as `beta` and `gamma` used in the Grand Product argument.
336
337 // Determines the number of rounds in the sumcheck (may include padding rounds, i.e. >= multivariate_d).
339
340 std::vector<FF> multivariate_challenge;
341
342 // For computing eq polymomials in Multilinear Batching Flavor
343 std::vector<FF> accumulator_challenge = {};
344 std::vector<FF> instance_challenge = {};
346
348
349 // SumcheckProver constructor for MultilinearBatchingFlavor.
351 ProverPolynomials& prover_polynomials,
352 std::shared_ptr<Transcript> transcript,
353 const FF& relation_separator,
354 const size_t virtual_log_n,
355 const std::vector<FF>& accumulator_challenge,
356 const std::vector<FF>& instance_challenge)
359 , full_polynomials(prover_polynomials)
360 , transcript(std::move(transcript))
362 , alphas(initialize_relation_separator<FF, Flavor::NUM_SUBRELATIONS - 1>(relation_separator))
363 , gate_challenges({})
367
368 // SumcheckProver constructor for the Flavors that generate a single challenge `alpha` and use its powers as
369 // subrelation seperator challenges.
371 ProverPolynomials& prover_polynomials,
372 std::shared_ptr<Transcript> transcript,
373 const FF& alpha,
374 const std::vector<FF>& gate_challenges,
376 const size_t virtual_log_n)
379 , full_polynomials(prover_polynomials)
380 , transcript(std::move(transcript))
382 , alphas(initialize_relation_separator<FF, Flavor::NUM_SUBRELATIONS - 1>(alpha))
393 {
394 vinfo("starting sumcheck rounds...");
395
396 // Given gate challenges β = (β₀, ..., β_{d−1}) and d = `multivariate_d`, compute the evaluations of
397 // GateSeparator_β (X₀, ..., X_{d−1}) = ∏ₖ₌₀^{d−1} (1 − Xₖ + Xₖ · βₖ)
398 // on the boolean hypercube.
400
402 // In the first round, we compute the first univariate polynomial and populate the book-keeping table of
403 // #partially_evaluated_polynomials, which has \f$ n/2 \f$ rows and \f$ N \f$ columns.
404 PartiallyEvaluatedMultivariates partially_evaluated_polynomials = [&] {
405 BB_BENCH_NAME("sumcheck loop 0");
406 auto round_univariate =
407 round.compute_univariate(full_polynomials, relation_parameters, gate_separators, alphas);
408
409 // Place the evaluations of the round univariate into transcript.
410 transcript->send_to_verifier("Sumcheck:univariate_0", round_univariate);
411 FF round_challenge = transcript->template get_challenge<FF>("Sumcheck:u_0");
412 multivariate_challenge.emplace_back(round_challenge);
413
414 // Populate the book-keeping table
415 auto result = partially_evaluate_first_round(full_polynomials, round_challenge);
416 gate_separators.partially_evaluate(round_challenge);
417 round.round_size = round.round_size >> 1;
418 return result;
419 }();
420 for (size_t round_idx = 1; round_idx < multivariate_d; round_idx++) {
421 BB_BENCH_NAME("sumcheck loop");
422
423 // Write the round univariate to the transcript
424 auto round_univariate =
425 round.compute_univariate(partially_evaluated_polynomials, relation_parameters, gate_separators, alphas);
426 // Place evaluations of Sumcheck Round Univariate in the transcript
427 transcript->send_to_verifier("Sumcheck:univariate_" + std::to_string(round_idx), round_univariate);
428 FF round_challenge = transcript->template get_challenge<FF>("Sumcheck:u_" + std::to_string(round_idx));
429 multivariate_challenge.emplace_back(round_challenge);
430 // Prepare sumcheck book-keeping table for the next round.
431 partially_evaluate_in_place(partially_evaluated_polynomials, round_challenge);
432 gate_separators.partially_evaluate(round_challenge);
433 round.round_size = round.round_size >> 1;
434 }
435 vinfo("completed ", multivariate_d, " rounds of sumcheck");
436
438 // If required, extend prover's multilinear polynomials in `multivariate_d` variables by zero to get multilinear
439 // polynomials in `virtual_log_n` variables.
440 for (size_t k = multivariate_d; k < virtual_log_n; ++k) {
441 if constexpr (isMultilinearBatchingFlavor) {
442 // We need to specify the evaluation at index 1 for eq polynomials
443 std::vector<FF> index_1_challenge(virtual_log_n);
444 for (size_t i = 0; i < k; i++) {
445 index_1_challenge[i] = multivariate_challenge[i];
446 }
447 index_1_challenge[k] = FF(1);
448 if (partially_evaluated_polynomials.eq_accumulator.size() == 1) {
449
450 // We need to reallocate the polynomials
451 auto new_polynomial =
452 Polynomial<FF>(2, partially_evaluated_polynomials.eq_accumulator.virtual_size());
453 new_polynomial.at(0) = partially_evaluated_polynomials.eq_accumulator.at(0);
454 partially_evaluated_polynomials.eq_accumulator = new_polynomial;
455 }
456 if (partially_evaluated_polynomials.eq_instance.size() == 1) {
457 // We need to reallocate the polynomials
458 auto new_polynomial = Polynomial<FF>(2, partially_evaluated_polynomials.eq_instance.virtual_size());
459 new_polynomial.at(0) = partially_evaluated_polynomials.eq_instance.at(0);
460 partially_evaluated_polynomials.eq_instance = new_polynomial;
461 }
462 partially_evaluated_polynomials.eq_accumulator.at(1) =
464 partially_evaluated_polynomials.eq_instance.at(1) =
466 index_1_challenge[k] = FF(0);
467 }
468 // Compute the contribution from the extensions by zero. It is sufficient to evaluate the main constraint at
469 // `MAX_PARTIAL_RELATION_LENGTH` points.
470 const auto virtual_round_univariate = round.compute_virtual_contribution(
471 partially_evaluated_polynomials, relation_parameters, virtual_gate_separator, alphas);
472
473 transcript->send_to_verifier("Sumcheck:univariate_" + std::to_string(k), virtual_round_univariate);
474
475 const FF round_challenge = transcript->template get_challenge<FF>("Sumcheck:u_" + std::to_string(k));
476 multivariate_challenge.emplace_back(round_challenge);
477
478 // Update the book-keeping table of partial evaluations of the prover polynomials extended by zero.
479 for (auto& poly : partially_evaluated_polynomials.get_all()) {
480 // Avoid bad access if polynomials are set to be of size 0, which can happen in AVM.
481 if (poly.size() > 0) {
482 if (poly.size() == 1) {
483 poly.at(0) *= (FF(1) - round_challenge);
484 } else if (poly.size() == 2) {
485 // Here we handle the eq polynomial case
486 poly.at(0) = poly.at(0) * (FF(1) - round_challenge) + poly.at(1) * round_challenge;
487 poly.at(1) = 0;
488 } else {
489 BB_ASSERT_EQ(true, false, "Polynomial size is not 1 or 2");
490 }
491 }
492 }
493 virtual_gate_separator.partially_evaluate(round_challenge);
494 }
495
496 ClaimedEvaluations multivariate_evaluations = extract_claimed_evaluations(partially_evaluated_polynomials);
497 transcript->send_to_verifier("Sumcheck:evaluations", multivariate_evaluations.get_all());
498 // For ZK Flavors: the evaluations of Libra univariates are included in the Sumcheck Output
499
500 vinfo("finished sumcheck");
502 .claimed_evaluations = multivariate_evaluations };
503 };
504
512 SumcheckOutput<Flavor> prove(ZKData& zk_sumcheck_data)
513 requires Flavor::HasZK
514 {
516 vinfo("starting sumcheck rounds...");
517 // Given gate challenges β = (β₀, ..., β_{d−1}) and d = `multivariate_d`, compute the evaluations of
518 // GateSeparator_β (X₀, ..., X_{d−1}) = ∏ₖ₌₀^{d−1} (1 − Xₖ + Xₖ · βₖ)
519 // on the boolean hypercube.
521
523 size_t round_idx = 0;
524
525 // In the first round, we compute the first univariate polynomial and populate the book-keeping table of
526 // #partially_evaluated_polynomials, which has \f$ n/2 \f$ rows and \f$ N \f$ columns.
527
528 // Compute the round univariate (excludes disabled rows; handled separately below)
529 auto round_univariate =
530 round.compute_univariate(full_polynomials, relation_parameters, gate_separators, alphas);
531
532 // Add the contribution from the Libra univariates
533 auto hiding_univariate = round.compute_libra_univariate(zk_sumcheck_data, round_idx);
534 round_univariate += hiding_univariate;
535
536 // Handle disabled rows contribution
537 if constexpr (UseRowDisablingPolynomial<Flavor>) {
538 round_univariate += round.compute_disabled_contribution(
540 }
541
542 handler.process_round_univariate(round_idx, round_univariate);
543
544 const FF round_challenge = transcript->template get_challenge<FF>("Sumcheck:u_0");
545 multivariate_challenge.emplace_back(round_challenge);
546
547 // Populate the book-keeping table
548 PartiallyEvaluatedMultivariates partially_evaluated_polynomials =
550
551 // Prepare ZK Sumcheck data for the next round
552 zk_sumcheck_data.update_zk_sumcheck_data(round_challenge, round_idx);
553 row_disabling_polynomial.update_evaluations(round_challenge, round_idx);
554 gate_separators.partially_evaluate(round_challenge);
555 round.round_size = round.round_size >> 1;
556 if constexpr (UseRowDisablingPolynomial<Flavor>) {
557 round.excluded_head_size = 2; // After round 0, disabled zone collapses to 1 edge pair
558 }
559 for (size_t round_idx = 1; round_idx < multivariate_d; round_idx++) {
560 BB_BENCH_NAME("sumcheck loop");
561
562 // Computes the round univariate in two parts: first the contribution necessary to hide the polynomial and
563 // account for having randomness at the end of the trace and then the contribution from the full
564 // relation. Note: we compute the hiding univariate first as the `compute_univariate` method prepares
565 // relevant data structures for the next round
566 round_univariate =
567 round.compute_univariate(partially_evaluated_polynomials, relation_parameters, gate_separators, alphas);
568 hiding_univariate = round.compute_libra_univariate(zk_sumcheck_data, round_idx);
569 // Add the contribution from the Libra univariates
570 round_univariate += hiding_univariate;
571 // Handle disabled rows contribution
572 if constexpr (UseRowDisablingPolynomial<Flavor>) {
573 round_univariate += round.compute_disabled_contribution(partially_evaluated_polynomials,
575 gate_separators,
576 alphas,
578 }
579
580 handler.process_round_univariate(round_idx, round_univariate);
581
582 const FF round_challenge =
583 transcript->template get_challenge<FF>("Sumcheck:u_" + std::to_string(round_idx));
584 multivariate_challenge.emplace_back(round_challenge);
585
586 // Prepare sumcheck book-keeping table for the next round.
587 partially_evaluate_in_place(partially_evaluated_polynomials, round_challenge);
588
589 if constexpr (IsTranslatorFlavor<Flavor>) {
590 if (round_idx == Flavor::LOG_MINI_CIRCUIT_SIZE - 1) {
591 // Send mini-circuit evaluations mid-sumcheck so that they get hashed into the transcript,
592 // ensuring the remaining LOG_N - LOG_MINI_CIRCUIT_SIZE round challenges depend on them.
593 transcript->send_to_verifier("Sumcheck:minicircuit_evaluations",
594 Flavor::get_minicircuit_evaluations(partially_evaluated_polynomials));
595 }
596 }
597
598 // Prepare evaluation masking and libra structures for the next round (for ZK Flavors)
599 zk_sumcheck_data.update_zk_sumcheck_data(round_challenge, round_idx);
600 row_disabling_polynomial.update_evaluations(round_challenge, round_idx);
601
602 gate_separators.partially_evaluate(round_challenge);
603 round.round_size = round.round_size >> 1;
604 }
605
606 handler.finalize_last_round(multivariate_d, round_univariate, multivariate_challenge[multivariate_d - 1]);
607
608 vinfo("completed ", multivariate_d, " rounds of sumcheck");
609
610 // Virtual rounds: unified path for ZK and non-ZK.
611 // The row-disabling polynomial 1-L is circuit-size independent,
612 // so we continue updating it through virtual rounds. The verifier evaluates
613 // 1 - ∏_{i≥2}(1-u_i) over ALL D challenges — no log_n needed.
614 // Libra univariates are generated for ALL D rounds, so compute_libra_univariate works here too.
615 GateSeparatorPolynomial<FF> virtual_gate_separator(gate_challenges, multivariate_challenge);
616 for (size_t idx = multivariate_d; idx < virtual_log_n; idx++) {
617 round_univariate = compute_virtual_round_univariate(round,
618 partially_evaluated_polynomials,
620 virtual_gate_separator,
621 alphas,
623
624 hiding_univariate = round.compute_libra_univariate(zk_sumcheck_data, idx);
625 round_univariate += hiding_univariate;
626
627 handler.process_round_univariate(idx, round_univariate);
628 const FF round_challenge = transcript->template get_challenge<FF>("Sumcheck:u_" + std::to_string(idx));
629 multivariate_challenge.emplace_back(round_challenge);
630
631 fold_for_zero_extension(partially_evaluated_polynomials, round_challenge);
632 zk_sumcheck_data.update_zk_sumcheck_data(round_challenge, idx);
633 row_disabling_polynomial.update_evaluations(round_challenge, idx);
634 virtual_gate_separator.partially_evaluate(round_challenge);
635 }
636
637 // Claimed evaluations of Prover polynomials are extracted and added to the transcript.
638 ClaimedEvaluations multivariate_evaluations = extract_claimed_evaluations(partially_evaluated_polynomials);
639
640 // For Translator: send only the full-circuit evaluations
641 if constexpr (IsTranslatorFlavor<Flavor>) {
642 transcript->send_to_verifier("Sumcheck:evaluations",
643 Flavor::get_full_circuit_evaluations(multivariate_evaluations));
644 } else {
645 transcript->send_to_verifier("Sumcheck:evaluations", multivariate_evaluations.get_all());
646 }
647
648 // Libra evaluation covers all D rounds now (real + virtual).
649 FF libra_evaluation = zk_sumcheck_data.constant_term;
650 for (const auto& libra_eval : zk_sumcheck_data.libra_evaluations) {
651 libra_evaluation += libra_eval;
652 }
653 transcript->send_to_verifier("Libra:claimed_evaluation", libra_evaluation);
654
655 // The sum of the Libra constant term and the evaluations of Libra univariates at corresponding sumcheck
656 // challenges is included in the Sumcheck Output
657 vinfo("finished sumcheck");
658 return SumcheckOutput<Flavor>{ .challenge = multivariate_challenge,
659 .claimed_evaluations = multivariate_evaluations,
660 .claimed_libra_evaluation = libra_evaluation,
661 .round_univariates = handler.get_univariates(),
662 .round_univariate_evaluations = handler.get_evaluations() };
663 };
664
670 static void partially_evaluate(auto& source_polynomials,
671 PartiallyEvaluatedMultivariates& dest_polynomials,
672 const FF& round_challenge)
673 {
674 auto source_view = source_polynomials.get_all();
675 auto dest_view = dest_polynomials.get_all();
676 parallel_for(source_view.size(), [&](size_t j) {
677 BB_BENCH_TRACY_NAME("Sumcheck::partially_evaluate");
678 const auto& poly = source_view[j];
679 size_t limit = poly.end_index();
680 for (size_t i = 0; i < limit; i += 2) {
681 dest_view[j].at(i >> 1) = poly[i] + round_challenge * (poly[i + 1] - poly[i]);
682 }
683 dest_view[j].shrink_end_index((limit / 2) + (limit % 2));
684 });
685 };
686
694 const FF& round_challenge)
695 {
696 PartiallyEvaluatedMultivariates partially_evaluated_polynomials(full_polynomials, multivariate_n);
697 partially_evaluate(full_polynomials, partially_evaluated_polynomials, round_challenge);
698 return partially_evaluated_polynomials;
699 }
700
704 static void partially_evaluate_in_place(PartiallyEvaluatedMultivariates& polynomials, const FF& round_challenge)
705 {
706 partially_evaluate(polynomials, polynomials, round_challenge);
707 };
708
721 {
722 ClaimedEvaluations multivariate_evaluations;
723 for (auto [eval, poly] :
724 zip_view(multivariate_evaluations.get_all(), partially_evaluated_polynomials.get_all())) {
725 eval = poly[0];
726 };
727 return multivariate_evaluations;
728 };
729
736 template <typename PartialEvals, typename Alphas>
739 PartialEvals& partially_evaluated_polynomials,
740 const RelationParameters<FF>& relation_parameters,
741 GateSeparatorPolynomial<FF>& gate_separator,
742 const Alphas& alphas,
743 RowDisablingPolynomial<FF>& row_disabling_polynomial)
744 {
745 auto univariate = round.compute_virtual_contribution(
746 partially_evaluated_polynomials, relation_parameters, gate_separator, alphas);
747 if constexpr (UseRowDisablingPolynomial<Flavor>) {
748 bb::Univariate<FF, 2> one_minus_L(
749 { FF::one() - row_disabling_polynomial.eval_at_0, FF::one() - row_disabling_polynomial.eval_at_1 });
750 univariate *= one_minus_L.template extend_to<Flavor::BATCHED_RELATION_PARTIAL_LENGTH>();
751 }
752 return univariate;
753 }
754
758 static void fold_for_zero_extension(PartiallyEvaluatedMultivariates& pe, const FF& round_challenge)
759 {
760 for (auto& poly : pe.get_all()) {
761 if (poly.end_index() > 0) {
762 poly.at(0) *= (FF(1) - round_challenge);
763 }
764 }
765 }
766};
767
804template <typename Flavor> class SumcheckVerifier {
805
806 public:
808 using FF = typename Flavor::FF;
814 // For ZK Flavors: the verifier obtains a vector of evaluations of \f$ d \f$ univariate polynomials and uses them to
815 // compute full_honk_relation_purported_value
816 using ClaimedLibraEvaluations = typename std::vector<FF>;
820
825 static constexpr size_t BATCHED_RELATION_PARTIAL_LENGTH = Flavor::BATCHED_RELATION_PARTIAL_LENGTH;
829 static constexpr size_t NUM_POLYNOMIALS = Flavor::NUM_ALL_ENTITIES;
830
831 std::shared_ptr<Transcript> transcript;
833
834 // Determines number of rounds in the sumcheck (may include padding rounds)
836
837 // An array of size NUM_SUBRELATIONS-1 containing challenges or consecutive powers of a single challenge that
838 // separate linearly independent subrelation.
840
841 explicit SumcheckVerifier(std::shared_ptr<Transcript> transcript,
842 const FF& alpha,
843 size_t virtual_log_n,
844 FF target_sum = 0)
845 : transcript(std::move(transcript))
846 , round(target_sum)
847 , virtual_log_n(virtual_log_n)
848 , alphas(initialize_relation_separator<FF, Flavor::NUM_SUBRELATIONS - 1>(alpha)) {};
860 const std::vector<FF>& gate_challenges)
861 {
862 bb::GateSeparatorPolynomial<FF> gate_separators(gate_challenges);
863 // Construct a ZKHandler to handle all the libra related information in the transcript
864 VerifierZKCorrectionHandler<Flavor> zk_correction_handler(transcript);
865
866 // Correct the target sum in the round in the ZK case
867 zk_correction_handler.initialize_target_sum(round);
868
869 std::vector<FF> multivariate_challenge;
870 multivariate_challenge.reserve(virtual_log_n);
871
872 // Process univariate consistancy check rounds
873 // For ECCVM we ensure the consistencies by populating an vector of claimed evaluations that will be checked in
874 // the PCS rounds
875 // For other flavors, we perform the sumcheck univariate consistency check
876
877 bool verified = true;
878 // Heap-allocate ClaimedEvaluations (AllValues) to keep the sumcheck-verify stack frame small.
879 // For recursive flavors with many columns (e.g. AVM), holding this inline on the stack can exceed the 8 MB
880 // stack limit once nested inside the inner-Mega AVM recursive verifier chain
881 auto purported_evaluations_storage = std::make_unique<ClaimedEvaluations>();
882 ClaimedEvaluations& purported_evaluations = *purported_evaluations_storage;
883 for (size_t round_idx = 0; round_idx < virtual_log_n; round_idx++) {
884 round.process_round(transcript, multivariate_challenge, gate_separators, round_idx);
885 verified = verified && !round.round_failed;
886
887 if constexpr (IsTranslatorFlavor<Flavor>) {
888 if (round_idx == Flavor::LOG_MINI_CIRCUIT_SIZE - 1) {
889 // Receive mini-circuit evaluations mid-sumcheck so that they get hashed into the transcript,
890 // ensuring the remaining LOG_N - LOG_MINI_CIRCUIT_SIZE round challenges depend on them.
891 Flavor::set_minicircuit_evaluations(
892 purported_evaluations,
893 transcript->template receive_from_prover<std::array<FF, Flavor::NUM_MINICIRCUIT_EVALUATIONS>>(
894 "Sumcheck:minicircuit_evaluations"));
895 }
896 }
897 }
898
899 // Populate claimed evaluations at the challenge
900 if constexpr (IsTranslatorFlavor<Flavor>) {
901 // Translator path: receive full-circuit evaluations, set them, and complete
902 // (computable precomputed selectors + L_0 scaling of minicircuit wires already placed above)
904 transcript->template receive_from_prover<std::array<FF, Flavor::NUM_FULL_CIRCUIT_EVALUATIONS>>(
905 "Sumcheck:evaluations"));
906 Flavor::complete_full_circuit_evaluations(
907 purported_evaluations, *get_full_circuit_evaluations, std::span<const FF>(multivariate_challenge));
908 } else {
909 // Heap-allocate transcript_evaluations for the same reason as purported_evaluations above.
910 auto transcript_evaluations = std::make_unique<std::array<FF, NUM_POLYNOMIALS>>(
911 transcript->template receive_from_prover<std::array<FF, NUM_POLYNOMIALS>>("Sumcheck:evaluations"));
912 for (auto [eval, transcript_eval] : zip_view(purported_evaluations.get_all(), *transcript_evaluations)) {
913 eval = transcript_eval;
914 }
915 }
916
917 // OriginTag false positive: The evaluations are PCS-bound - the prover committed to the
918 // polynomials before challenges were known, and the PCS opening verifies consistency.
919 if constexpr (IsRecursiveFlavor<Flavor>) {
920 const auto challenge_tag = multivariate_challenge.back().get_origin_tag();
921 for (auto& eval : purported_evaluations.get_all()) {
922 eval.set_origin_tag(challenge_tag);
923 }
924 }
925
926 // Evaluate the Honk relation at the point (u_0, ..., u_{d-1}) using claimed evaluations of prover polynomials.
927 // In ZK Flavors, the evaluation is corrected by full_libra_purported_value
928 FF full_honk_purported_value = round.compute_full_relation_purported_value(
929 purported_evaluations, relation_parameters, gate_separators, alphas);
930
931 // For ZK Flavors: compute the evaluation of the Row Disabling Polynomial at the sumcheck challenge and of the
932 // libra univariate used to hide the contribution from the actual Honk relation
933 zk_correction_handler.apply_zk_corrections(full_honk_purported_value, multivariate_challenge);
934
936 bool final_check = round.perform_final_verification(full_honk_purported_value);
937 verified = final_check && verified;
938
939 // For ZK Flavors: the evaluations of Libra univariates are included in the Sumcheck Output
940 return SumcheckOutput<Flavor>{ .challenge = multivariate_challenge,
941 .claimed_evaluations = std::move(purported_evaluations),
942 .verified = verified,
943 .claimed_libra_evaluation = zk_correction_handler.get_libra_evaluation(),
944 .round_univariate_commitments = round.get_round_univariate_commitments(),
945 .round_univariate_evaluations = round.get_round_univariate_evaluations() };
946 };
947};
948
949template <typename FF, size_t N> std::array<FF, N> initialize_relation_separator(const FF& alpha)
950{
951 std::array<FF, N> alphas;
952 alphas[0] = alpha;
953 for (size_t i = 1; i < N; ++i) {
954 alphas[i] = alphas[i - 1] * alpha;
955 }
956 return alphas;
957}
958} // namespace bb
#define BB_ASSERT_EQ(actual, expected,...)
Definition assert.hpp:83
bb::field< bb::Bn254FrParams > FF
Definition field.cpp:24
#define BB_BENCH_NAME(name)
Definition bb_bench.hpp:264
A field element for each entity of the flavor. These entities represent the prover polynomials evalua...
A container for the prover polynomials.
static constexpr bool HasZK
typename Curve::ScalarField FF
static constexpr size_t NUM_SUBRELATIONS
static constexpr size_t NUM_ALL_ENTITIES
static constexpr size_t MAX_PARTIAL_RELATION_LENGTH
typename G1::affine_element Commitment
PartiallyEvaluatedMultivariatesBase< AllEntities< Polynomial >, ProverPolynomials, Polynomial > PartiallyEvaluatedMultivariates
A container for storing the partially evaluated multivariates produced by sumcheck.
bb::CommitmentKey< Curve > CommitmentKey
static constexpr size_t BATCHED_RELATION_PARTIAL_LENGTH
BaseTranscript< Codec, HashFunction > Transcript
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:294
SumcheckOutput< Flavor > static prove(ZKData &zk_sumcheck_data) void partially_evaluate(auto &source_polynomials, PartiallyEvaluatedMultivariates &dest_polynomials, const FF &round_challenge)
ZK-version of prove that runs Sumcheck with disabled rows and masking of Round Univariates....
Definition sumcheck.hpp:670
static constexpr size_t BATCHED_RELATION_PARTIAL_LENGTH
Definition sumcheck.hpp:315
typename Flavor::FF FF
Definition sumcheck.hpp:296
ProverPolynomials & full_polynomials
Definition sumcheck.hpp:324
const size_t multivariate_n
Definition sumcheck.hpp:320
bb::RelationParameters< FF > relation_parameters
Definition sumcheck.hpp:335
typename Flavor::Transcript Transcript
Definition sumcheck.hpp:303
std::vector< FF > accumulator_challenge
Definition sumcheck.hpp:343
std::vector< FF > instance_challenge
Definition sumcheck.hpp:344
PartiallyEvaluatedMultivariates partially_evaluate_first_round(ProverPolynomials &full_polynomials, const FF &round_challenge)
Initialize partially evaluated polynomials and perform first round of partial evaluation.
Definition sumcheck.hpp:693
static constexpr bool isMultilinearBatchingFlavor
Definition sumcheck.hpp:307
typename Flavor::ProverPolynomials ProverPolynomials
Definition sumcheck.hpp:299
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:312
std::array< FF, Flavor::NUM_SUBRELATIONS - 1 > SubrelationSeparators
Definition sumcheck.hpp:304
const size_t multivariate_d
Definition sumcheck.hpp:322
static void partially_evaluate_in_place(PartiallyEvaluatedMultivariates &polynomials, const FF &round_challenge)
Evaluate at the round challenge in-place.
Definition sumcheck.hpp:704
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:720
typename Flavor::AllValues ClaimedEvaluations
Definition sumcheck.hpp:301
typename bb::Univariate< FF, BATCHED_RELATION_PARTIAL_LENGTH > SumcheckRoundUnivariate
Definition sumcheck.hpp:317
static void fold_for_zero_extension(PartiallyEvaluatedMultivariates &pe, const FF &round_challenge)
Fold partially-evaluated polynomials for zero-extension: PE[0] *= (1 - u_k).
Definition sumcheck.hpp:758
std::vector< FF > multivariate_challenge
Definition sumcheck.hpp:340
static bb::Univariate< FF, Flavor::BATCHED_RELATION_PARTIAL_LENGTH > compute_virtual_round_univariate(SumcheckProverRound< Flavor > &round, PartialEvals &partially_evaluated_polynomials, const RelationParameters< FF > &relation_parameters, GateSeparatorPolynomial< FF > &gate_separator, const Alphas &alphas, RowDisablingPolynomial< FF > &row_disabling_polynomial)
Compute the virtual round univariate with the row-disabling polynomial factor applied.
Definition sumcheck.hpp:737
typename Flavor::PartiallyEvaluatedMultivariates PartiallyEvaluatedMultivariates
Definition sumcheck.hpp:300
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)
Definition sumcheck.hpp:370
RowDisablingPolynomial< FF > row_disabling_polynomial
Definition sumcheck.hpp:347
typename Flavor::CommitmentKey CommitmentKey
Definition sumcheck.hpp:305
SumcheckProver(size_t multivariate_n, ProverPolynomials &prover_polynomials, std::shared_ptr< Transcript > transcript, const FF &relation_separator, const size_t virtual_log_n, const std::vector< FF > &accumulator_challenge, const std::vector< FF > &instance_challenge)
Definition sumcheck.hpp:350
std::vector< FF > gate_challenges
Definition sumcheck.hpp:333
SumcheckProverRound< Flavor > round
Definition sumcheck.hpp:328
std::shared_ptr< Transcript > transcript
Definition sumcheck.hpp:326
SumcheckOutput< Flavor > prove()
Non-ZK version: Compute round univariate, place it in transcript, compute challenge,...
Definition sumcheck.hpp:392
ZKSumcheckData< Flavor > ZKData
Definition sumcheck.hpp:302
SubrelationSeparators alphas
Definition sumcheck.hpp:331
Imlementation of the Sumcheck prover round.
SumcheckRoundUnivariate compute_virtual_contribution(ProverPolynomialsOrPartiallyEvaluatedMultivariates &polynomials, const bb::RelationParameters< FF > &relation_parameters, const GateSeparatorPolynomial< FF > &gate_separator, const SubrelationSeparators &alphas)
Implementation of the sumcheck Verifier for statements of the form for multilinear polynomials .
Definition sumcheck.hpp:804
typename std::vector< FF > ClaimedLibraEvaluations
Definition sumcheck.hpp:816
std::array< FF, Flavor::NUM_SUBRELATIONS - 1 > SubrelationSeparators
Definition sumcheck.hpp:818
typename Flavor::FF FF
Definition sumcheck.hpp:808
typename Flavor::Commitment Commitment
Definition sumcheck.hpp:819
SumcheckOutput< Flavor > verify(const bb::RelationParameters< FF > &relation_parameters, const std::vector< FF > &gate_challenges)
The Sumcheck verification method. First it extracts round univariate, checks sum (the sumcheck univar...
Definition sumcheck.hpp:859
SumcheckVerifierRound< Flavor > round
Definition sumcheck.hpp:832
SumcheckVerifier(std::shared_ptr< Transcript > transcript, const FF &alpha, size_t virtual_log_n, FF target_sum=0)
Definition sumcheck.hpp:841
std::shared_ptr< Transcript > transcript
Definition sumcheck.hpp:831
typename Flavor::AllValues ClaimedEvaluations
Container type for the evaluations of Prover Polynomials at the challenge point .
Definition sumcheck.hpp:813
SubrelationSeparators alphas
Definition sumcheck.hpp:839
typename Flavor::Transcript Transcript
Definition sumcheck.hpp:817
Implementation of the Sumcheck Verifier Round.
std::vector< std::array< FF, 3 > > get_round_univariate_evaluations()
Get round univariate evaluations (only used for Grumpkin flavors).
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)
Compute the full relation purported value.
void process_round(const std::shared_ptr< Transcript > &transcript, std::vector< FF > &multivariate_challenge, bb::GateSeparatorPolynomial< FF > &gate_separators, size_t round_idx)
Process a single sumcheck round: receive univariate from transcript, verify sum, generate challenge.
std::vector< Commitment > get_round_univariate_commitments()
Get round univariate commitments (only used for Grumpkin flavors).
bool perform_final_verification(const FF &full_honk_purported_value)
Perform final verification: check that the computed target sum matches the full relation evaluation....
A univariate polynomial represented by its values on {0, 1,..., domain_end - 1}.
Fr & value_at(size_t i)
std::array< Fr, LENGTH > evaluations
Fr evaluate(const Fr &u) const
Evaluate a univariate at a point u not known at compile time and assumed not to be in the domain (els...
#define vinfo(...)
Definition log.hpp:94
constexpr T get_msb(const T in)
Definition get_msb.hpp:50
Entry point for Barretenberg command-line interface.
Definition api.hpp:5
CommitmentKey< Curve > ck
std::array< FF, N > initialize_relation_separator(const FF &alpha)
Definition sumcheck.hpp:949
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.
std::vector< std::array< FF, 3 > > round_evaluations
Definition sumcheck.hpp:66
void process_round_univariate(size_t round_idx, bb::Univariate< FF, BATCHED_RELATION_PARTIAL_LENGTH > &round_univariate)
Definition sumcheck.hpp:80
typename Flavor::CommitmentKey CommitmentKey
Definition sumcheck.hpp:60
std::vector< Polynomial< FF > > round_univariates
Definition sumcheck.hpp:67
void finalize_last_round(size_t multivariate_d, const bb::Univariate< FF, BATCHED_RELATION_PARTIAL_LENGTH > &round_univariate, const FF &last_challenge)
Definition sumcheck.hpp:104
std::vector< Polynomial< FF > > get_univariates()
Definition sumcheck.hpp:112
std::shared_ptr< Transcript > transcript
Definition sumcheck.hpp:63
typename Flavor::Transcript Transcript
Definition sumcheck.hpp:59
std::vector< std::array< FF, 3 > > get_evaluations()
Definition sumcheck.hpp:111
RoundUnivariateHandler(std::shared_ptr< Transcript > transcript)
Definition sumcheck.hpp:69
Handler for processing round univariates in sumcheck. Default implementation: send evaluations direct...
Definition sumcheck.hpp:27
static constexpr size_t BATCHED_RELATION_PARTIAL_LENGTH
Definition sumcheck.hpp:31
typename Flavor::Transcript Transcript
Definition sumcheck.hpp:29
void finalize_last_round(size_t, const bb::Univariate< FF, BATCHED_RELATION_PARTIAL_LENGTH > &, const FF &)
Definition sumcheck.hpp:45
void process_round_univariate(size_t round_idx, bb::Univariate< FF, BATCHED_RELATION_PARTIAL_LENGTH > &round_univariate)
Definition sumcheck.hpp:39
std::shared_ptr< Transcript > transcript
Definition sumcheck.hpp:33
typename Flavor::CommitmentKey CommitmentKey
Definition sumcheck.hpp:30
typename Flavor::FF FF
Definition sumcheck.hpp:28
std::vector< Polynomial< FF > > get_univariates()
Definition sumcheck.hpp:51
RoundUnivariateHandler(std::shared_ptr< Transcript > transcript)
Definition sumcheck.hpp:35
std::vector< std::array< FF, 3 > > get_evaluations()
Definition sumcheck.hpp:50
Polynomial for Sumcheck with disabled Rows.
static FF evaluate_at_challenge(std::span< const FF > multivariate_challenge, const size_t log_circuit_size)
Compute the evaluation of at the sumcheck challenge.
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)
void apply_zk_corrections(FF &full_honk_purported_value, std::vector< FF > &multivariate_challenge)
Definition sumcheck.hpp:163
VerifierZKCorrectionHandler(std::shared_ptr< Transcript > transcript)
Definition sumcheck.hpp:155
void initialize_target_sum(SumcheckRound &round)
Definition sumcheck.hpp:161
std::shared_ptr< Transcript > transcript
Definition sumcheck.hpp:148
Handler for ZK-related verification adjustments in sumcheck. Default implementation: no ZK adjustment...
Definition sumcheck.hpp:119
void apply_zk_corrections(FF &, const std::vector< FF > &)
Definition sumcheck.hpp:135
typename Flavor::Transcript Transcript
Definition sumcheck.hpp:121
void initialize_target_sum(SumcheckRound &)
Definition sumcheck.hpp:133
std::shared_ptr< Transcript > transcript
Definition sumcheck.hpp:124
VerifierZKCorrectionHandler(std::shared_ptr< Transcript > transcript)
Definition sumcheck.hpp:129
This structure is created to contain various polynomials and constants required by ZK Sumcheck.