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 BB_ASSERT(this->transcript != nullptr, "RoundUnivariateHandler: transcript must not be null");
39 }
40
41 void process_round_univariate(size_t round_idx,
43 {
44 transcript->send_to_verifier("Sumcheck:univariate_" + std::to_string(round_idx), round_univariate);
45 }
46
47 void finalize_last_round(size_t /*multivariate_d*/,
49 const FF& /*last_challenge*/)
50 {}
51
55};
56
60template <typename Flavor> struct RoundUnivariateHandler<Flavor, true> {
61 using FF = typename Flavor::FF;
66
67 std::shared_ptr<Transcript> transcript;
69 std::vector<FF> eval_domain;
72 std::vector<Commitment> round_commitments;
73
74 RoundUnivariateHandler(std::shared_ptr<Transcript> transcript)
75 : transcript(std::move(transcript))
77 {
78 BB_ASSERT(this->transcript != nullptr, "RoundUnivariateHandler: transcript must not be null");
79 // Compute the vector {0, 1, \ldots, BATCHED_RELATION_PARTIAL_LENGTH-1} needed to transform
80 // the round univariates from Lagrange to monomial basis
81 eval_domain.reserve(BATCHED_RELATION_PARTIAL_LENGTH);
82 for (size_t idx = 0; idx < BATCHED_RELATION_PARTIAL_LENGTH; idx++) {
83 eval_domain.push_back(FF(idx));
84 }
85 }
86
87 void process_round_univariate(size_t round_idx,
89 {
90 const std::string idx = std::to_string(round_idx);
91
92 // Transform to monomial form and commit to it
93 Polynomial<FF> round_poly_monomial(
94 eval_domain, std::span<FF>(round_univariate.evaluations), BATCHED_RELATION_PARTIAL_LENGTH);
95 auto round_commitment = ck.commit(round_poly_monomial);
96 transcript->send_to_verifier("Sumcheck:univariate_comm_" + idx, round_commitment);
97 round_commitments.push_back(round_commitment);
98
99 // Store round univariate in monomial, as it is required by Shplemini
100 round_univariates.push_back(std::move(round_poly_monomial));
101
102 // Send the evaluations of the round univariate at 0 and 1
103 transcript->send_to_verifier("Sumcheck:univariate_" + idx + "_eval_0", round_univariate.value_at(0));
104 transcript->send_to_verifier("Sumcheck:univariate_" + idx + "_eval_1", round_univariate.value_at(1));
105
106 // Store the evaluations to be used by ShpleminiProver.
107 round_evaluations.push_back({ round_univariate.value_at(0), round_univariate.value_at(1), FF(0) });
108 if (round_idx > 0) {
109 round_evaluations[round_idx - 1][2] = round_univariate.value_at(0) + round_univariate.value_at(1);
110 }
111 }
112
113 void finalize_last_round(size_t multivariate_d,
115 const FF& last_challenge)
116 {
117 round_evaluations[multivariate_d - 1][2] = round_univariate.evaluate(last_challenge);
118 }
119
120 // The members are moved out: each getter is called once at the end of `prove`, after which the handler is dead.
122 std::vector<Polynomial<FF>> get_univariates() { return std::move(round_univariates); }
123 std::vector<Commitment> get_commitments() { return std::move(round_commitments); }
124};
125
130template <typename Flavor, bool HasZK = Flavor::HasZK> struct VerifierZKCorrectionHandler {
131 using FF = typename Flavor::FF;
134
135 std::shared_ptr<Transcript> transcript;
138
139 // Construct a handler which will handle all the evaluations/
140 VerifierZKCorrectionHandler(std::shared_ptr<Transcript> transcript)
141 : transcript(std::move(transcript))
142 {}
143
145
146 void apply_zk_corrections(FF& /*full_honk_purported_value*/, const std::vector<FF>& /*multivariate_challenge*/) {}
147
149};
150
154template <typename Flavor> struct VerifierZKCorrectionHandler<Flavor, true> {
155 using FF = typename Flavor::FF;
158
159 std::shared_ptr<Transcript> transcript;
160 FF libra_total_sum = FF{ 0 };
163
164 VerifierZKCorrectionHandler(std::shared_ptr<Transcript> transcript)
165 : transcript(std::move(transcript))
166 {}
167
168 // If running zero-knowledge sumcheck the target total sum is corrected by the claimed sum of libra masking
169 // multivariate over the hypercube.
171 {
172 libra_total_sum = transcript->template receive_from_prover<FF>("Libra:Sum");
173 libra_challenge = transcript->template get_challenge<FF>("Libra:Challenge");
174 round.target_total_sum = libra_total_sum * libra_challenge;
175 }
176
177 void apply_zk_corrections(FF& full_honk_purported_value, std::vector<FF>& multivariate_challenge)
178 {
179
180 // Get the claimed evaluation of the Libra multivariate evaluated at the sumcheck challenge
181 libra_evaluation = transcript->template receive_from_prover<FF>("Libra:claimed_evaluation");
182
183 // OriginTag false positive: libra_evaluation is PCS-bound (verified by Shplemini opening).
184 // Once commitments are fixed and sumcheck challenges derived, the correct evaluation is determined.
185 if constexpr (IsRecursiveFlavor<Flavor>) {
186 const auto challenge_tag = multivariate_challenge.back().get_origin_tag();
187 libra_evaluation.set_origin_tag(challenge_tag);
188 }
189
190 full_honk_purported_value += libra_evaluation * libra_challenge;
191 }
192
194};
195
304template <typename Flavor> class SumcheckProver {
305 public:
306 using FF = typename Flavor::FF;
307 // PartiallyEvaluatedMultivariates OR ProverPolynomials
308 // both inherit from AllEntities
316
323
324 // this constant specifies the number of coefficients of libra polynomials, and evaluations of round univariate
326
328
329 // The size of the hypercube, i.e. \f$ 2^d\f$.
330 const size_t multivariate_n;
331 // The number of variables
332 const size_t multivariate_d;
333 // A reference to all prover multilinear polynomials.
335
336 std::shared_ptr<Transcript> transcript;
337 // Contains the core sumcheck methods such as `compute_univariate`.
339 // An array of size NUM_SUBRELATIONS-1 containing challenges or consecutive powers of a single challenge that
340 // separate linearly independent subrelation.
342 // pow_β(X₀, ..., X_{d−1}) = ∏ₖ₌₀^{d−1} (1 − Xₖ + Xₖ ⋅ βₖ)
343 std::vector<FF> gate_challenges;
344 // Contains various challenges, such as `beta` and `gamma` used in the Grand Product argument.
346
347 // Determines the number of rounds in the sumcheck (may include padding rounds, i.e. >= multivariate_d).
349
350 std::vector<FF> multivariate_challenge;
351
353
355
356 // SumcheckProver constructor for the Flavors that generate a single challenge `alpha` and use its powers as
357 // subrelation seperator challenges.
359 ProverPolynomials& prover_polynomials,
360 std::shared_ptr<Transcript> transcript,
361 const FF& alpha,
362 const std::vector<FF>& gate_challenges,
364 const size_t virtual_log_n)
367 , full_polynomials(prover_polynomials)
368 , transcript(std::move(transcript))
370 , alphas(initialize_relation_separator<FF, Flavor::NUM_SUBRELATIONS - 1>(alpha))
374 {
375 // multivariate_d = get_msb(multivariate_n) only gives the correct round count for a power-of-two size.
377 "SumcheckProver: multivariate_n must be a power of two");
378 if constexpr (isMultilinearBatchingFlavor) {
380 Flavor::NUM_CLAIMS,
381 "Incorrect number of computed multilinear batching challenges.");
383 0U,
384 "Sumcheck Prover: Multilinear batching flavor has only dependent relations, no gate "
385 "challenges should be provided.");
386 } else {
387 // The rounds index gate_challenges through GateSeparatorPolynomial assuming at least multivariate_d
388 // entries.
389 BB_ASSERT_GTE(gate_challenges.size(), multivariate_d, "SumcheckProver: fewer gate challenges than rounds");
390 }
391 };
399 requires(!Flavor::HasZK)
400 {
401 vinfo("starting sumcheck rounds...");
402
403 // Given gate challenges β = (β₀, ..., β_{d−1}) and d = `multivariate_d`, compute the evaluations of
404 // GateSeparator_β (X₀, ..., X_{d−1}) = ∏ₖ₌₀^{d−1} (1 − Xₖ + Xₖ · βₖ)
405 // on the boolean hypercube.
407
409 // In the first round, we compute the first univariate polynomial and populate the book-keeping table of
410 // #partially_evaluated_polynomials, which has \f$ n/2 \f$ rows and \f$ N \f$ columns.
411 PartiallyEvaluatedMultivariates partially_evaluated_polynomials = [&] {
412 BB_BENCH_NAME("sumcheck loop 0");
413 auto round_univariate =
414 round.compute_univariate(full_polynomials, relation_parameters, gate_separators, alphas);
415
416 // Place the evaluations of the round univariate into transcript.
417 transcript->send_to_verifier("Sumcheck:univariate_0", round_univariate);
418 FF round_challenge = transcript->template get_challenge<FF>("Sumcheck:u_0");
419 multivariate_challenge.emplace_back(round_challenge);
420
421 // Populate the book-keeping table
423 gate_separators.partially_evaluate(round_challenge);
424 round.advance_round();
425 return result;
426 }();
427 for (size_t round_idx = 1; round_idx < multivariate_d; round_idx++) {
428 BB_BENCH_NAME("sumcheck loop");
429
430 // Write the round univariate to the transcript
431 auto round_univariate =
432 round.compute_univariate(partially_evaluated_polynomials, relation_parameters, gate_separators, alphas);
433 // Place evaluations of Sumcheck Round Univariate in the transcript
434 transcript->send_to_verifier("Sumcheck:univariate_" + std::to_string(round_idx), round_univariate);
435 FF round_challenge = transcript->template get_challenge<FF>("Sumcheck:u_" + std::to_string(round_idx));
436 multivariate_challenge.emplace_back(round_challenge);
437 // Prepare sumcheck book-keeping table for the next round.
438 partially_evaluate_in_place(partially_evaluated_polynomials, round_challenge);
439 gate_separators.partially_evaluate(round_challenge);
440 round.advance_round();
441 }
442 vinfo("completed ", multivariate_d, " rounds of sumcheck");
443
445 // If required, extend prover's multilinear polynomials in `multivariate_d` variables by zero to get multilinear
446 // polynomials in `virtual_log_n` variables.
447 for (size_t k = multivariate_d; k < virtual_log_n; ++k) {
448 if constexpr (isMultilinearBatchingFlavor) {
449 // We need to specify the evaluation at index 1 for eq polynomials
450 Flavor::extend_eq_polynomials_for_virtual_round(
451 partially_evaluated_polynomials, multivariate_challenge, k);
452 }
453 // Compute the contribution from the extensions by zero. It is sufficient to evaluate the main constraint at
454 // `MAX_PARTIAL_RELATION_LENGTH` points.
455 const auto virtual_round_univariate = round.compute_virtual_contribution(
456 partially_evaluated_polynomials, relation_parameters, virtual_gate_separator, alphas);
457
458 transcript->send_to_verifier("Sumcheck:univariate_" + std::to_string(k), virtual_round_univariate);
459
460 const FF round_challenge = transcript->template get_challenge<FF>("Sumcheck:u_" + std::to_string(k));
461 multivariate_challenge.emplace_back(round_challenge);
462
463 // Update the book-keeping table of partial evaluations of the prover polynomials extended by zero.
464 for (auto& poly : partially_evaluated_polynomials.get_all()) {
465 // Avoid bad access if polynomials are set to be of size 0, which can happen in AVM.
466 if (poly.size() > 0) {
467 if (poly.size() == 1) {
468 poly.at(0) *= (FF(1) - round_challenge);
469 } else if (poly.size() == 2) {
470 // Here we handle the eq polynomial case
471 poly.at(0) = poly.at(0) * (FF(1) - round_challenge) + poly.at(1) * round_challenge;
472 poly.at(1) = 0;
473 } else {
474 BB_ASSERT_EQ(true, false, "Polynomial size is not 1 or 2");
475 }
476 }
477 }
478 virtual_gate_separator.partially_evaluate(round_challenge);
479 }
480
481 ClaimedEvaluations multivariate_evaluations = extract_claimed_evaluations(partially_evaluated_polynomials);
482 transcript->send_to_verifier("Sumcheck:evaluations", multivariate_evaluations.get_all());
483
484 vinfo("finished sumcheck");
486 .claimed_evaluations = multivariate_evaluations };
487 };
488
496 SumcheckOutput<Flavor> prove(ZKData& zk_sumcheck_data)
497 requires Flavor::HasZK
498 {
500 vinfo("starting sumcheck rounds...");
501 // Given gate challenges β = (β₀, ..., β_{d−1}) and d = `multivariate_d`, compute the evaluations of
502 // GateSeparator_β (X₀, ..., X_{d−1}) = ∏ₖ₌₀^{d−1} (1 − Xₖ + Xₖ · βₖ)
503 // on the boolean hypercube.
505
507 size_t round_idx = 0;
508
509 // In the first round, we compute the first univariate polynomial and populate the book-keeping table of
510 // #partially_evaluated_polynomials, which has \f$ n/2 \f$ rows and \f$ N \f$ columns.
511
512 // Compute the round univariate (excludes disabled rows; handled separately below)
513 auto round_univariate =
514 round.compute_univariate(full_polynomials, relation_parameters, gate_separators, alphas);
515
516 // Add the contribution from the Libra univariates
517 auto hiding_univariate = round.compute_libra_univariate(zk_sumcheck_data, round_idx);
518 round_univariate += hiding_univariate;
519
520 // Handle disabled rows contribution
521 if constexpr (UseRowDisablingPolynomial<Flavor>) {
522 round_univariate += round.compute_offset_area_contribution(
524 }
525
526 handler.process_round_univariate(round_idx, round_univariate);
527
528 const FF round_challenge = transcript->template get_challenge<FF>("Sumcheck:u_0");
529 multivariate_challenge.emplace_back(round_challenge);
530
531 // Populate the book-keeping table
532 PartiallyEvaluatedMultivariates partially_evaluated_polynomials =
534
535 // Prepare ZK Sumcheck data for the next round
536 zk_sumcheck_data.update_zk_sumcheck_data(round_challenge, round_idx);
537 row_disabling_polynomial.update_evaluations(round_challenge, round_idx);
538 gate_separators.partially_evaluate(round_challenge);
539 round.advance_round();
540 if constexpr (UseRowDisablingPolynomial<Flavor>) {
541 round.excluded_head_size = 2; // After round 0, disabled zone collapses to 1 edge pair
542 }
543 for (size_t round_idx = 1; round_idx < multivariate_d; round_idx++) {
544 BB_BENCH_NAME("sumcheck loop");
545
546 // Computes the round univariate in two parts: first the contribution necessary to hide the polynomial and
547 // account for having randomness at the end of the trace and then the contribution from the full
548 // relation. Note: we compute the hiding univariate first as the `compute_univariate` method prepares
549 // relevant data structures for the next round
550 round_univariate =
551 round.compute_univariate(partially_evaluated_polynomials, relation_parameters, gate_separators, alphas);
552 hiding_univariate = round.compute_libra_univariate(zk_sumcheck_data, round_idx);
553 // Add the contribution from the Libra univariates
554 round_univariate += hiding_univariate;
555 // Handle disabled rows contribution
556 if constexpr (UseRowDisablingPolynomial<Flavor>) {
557 round_univariate += round.compute_offset_area_contribution(partially_evaluated_polynomials,
559 gate_separators,
560 alphas,
562 }
563
564 handler.process_round_univariate(round_idx, round_univariate);
565
566 const FF round_challenge =
567 transcript->template get_challenge<FF>("Sumcheck:u_" + std::to_string(round_idx));
568 multivariate_challenge.emplace_back(round_challenge);
569
570 // Prepare sumcheck book-keeping table for the next round.
571 partially_evaluate_in_place(partially_evaluated_polynomials, round_challenge);
572
573 if constexpr (IsTranslatorFlavor<Flavor>) {
574 if (round_idx == Flavor::LOG_MINI_CIRCUIT_SIZE - 1) {
575 // Send mini-circuit evaluations mid-sumcheck so that they get hashed into the transcript,
576 // ensuring the remaining LOG_N - LOG_MINI_CIRCUIT_SIZE round challenges depend on them.
577 transcript->send_to_verifier("Sumcheck:minicircuit_evaluations",
578 Flavor::get_minicircuit_evaluations(partially_evaluated_polynomials));
579 }
580 }
581
582 // Prepare evaluation masking and libra structures for the next round (for ZK Flavors)
583 zk_sumcheck_data.update_zk_sumcheck_data(round_challenge, round_idx);
584 row_disabling_polynomial.update_evaluations(round_challenge, round_idx);
585
586 gate_separators.partially_evaluate(round_challenge);
587 round.advance_round();
588 }
589
590 handler.finalize_last_round(multivariate_d, round_univariate, multivariate_challenge[multivariate_d - 1]);
591
592 vinfo("completed ", multivariate_d, " rounds of sumcheck");
593
594 // Virtual rounds: unified path for ZK and non-ZK.
595 // The row-disabling polynomial 1-L is circuit-size independent,
596 // so we continue updating it through virtual rounds. The verifier evaluates
597 // 1 - ∏_{i≥2}(1-u_i) over ALL D challenges — no log_n needed.
598 // Libra univariates are generated for ALL D rounds, so compute_libra_univariate works here too.
599 GateSeparatorPolynomial<FF> virtual_gate_separator(gate_challenges, multivariate_challenge);
600 for (size_t idx = multivariate_d; idx < virtual_log_n; idx++) {
601 round_univariate = compute_virtual_round_univariate(round,
602 partially_evaluated_polynomials,
604 virtual_gate_separator,
605 alphas,
607
608 hiding_univariate = round.compute_libra_univariate(zk_sumcheck_data, idx);
609 round_univariate += hiding_univariate;
610
611 handler.process_round_univariate(idx, round_univariate);
612 const FF round_challenge = transcript->template get_challenge<FF>("Sumcheck:u_" + std::to_string(idx));
613 multivariate_challenge.emplace_back(round_challenge);
614
615 fold_for_zero_extension(partially_evaluated_polynomials, round_challenge);
616 zk_sumcheck_data.update_zk_sumcheck_data(round_challenge, idx);
617 row_disabling_polynomial.update_evaluations(round_challenge, idx);
618 virtual_gate_separator.partially_evaluate(round_challenge);
619 }
620
621 // Claimed evaluations of Prover polynomials are extracted and added to the transcript.
622 ClaimedEvaluations multivariate_evaluations = extract_claimed_evaluations(partially_evaluated_polynomials);
623
624 // For Translator: send only the full-circuit evaluations
625 if constexpr (IsTranslatorFlavor<Flavor>) {
626 transcript->send_to_verifier("Sumcheck:evaluations",
627 Flavor::get_full_circuit_evaluations(multivariate_evaluations));
628 } else {
629 transcript->send_to_verifier("Sumcheck:evaluations", multivariate_evaluations.get_all());
630 }
631
632 // Libra evaluation covers all D rounds now (real + virtual).
633 FF libra_evaluation = zk_sumcheck_data.constant_term;
634 for (const auto& libra_eval : zk_sumcheck_data.libra_evaluations) {
635 libra_evaluation += libra_eval;
636 }
637 transcript->send_to_verifier("Libra:claimed_evaluation", libra_evaluation);
638
639 // The sum of the Libra constant term and the evaluations of Libra univariates at corresponding sumcheck
640 // challenges is included in the Sumcheck Output
641 vinfo("finished sumcheck");
642 return SumcheckOutput<Flavor>{ .challenge = multivariate_challenge,
643 .claimed_evaluations = multivariate_evaluations,
644 .claimed_libra_evaluation = libra_evaluation,
645 .round_univariate_commitments = handler.get_commitments(),
646 .round_univariates = handler.get_univariates(),
647 .round_univariate_evaluations = handler.get_evaluations() };
648 };
649
660 static void partially_evaluate(auto& source_polynomials,
661 PartiallyEvaluatedMultivariates& dest_polynomials,
662 const FF& round_challenge)
663 {
664 auto source_view = source_polynomials.get_all();
665 auto dest_view = dest_polynomials.get_all();
666 parallel_for(source_view.size(), [&](size_t j) {
667 BB_BENCH_TRACY_NAME("Sumcheck::partially_evaluate");
668 const auto& poly = source_view[j];
669 auto& dest = dest_view[j];
670 const size_t limit = poly.end_index();
671 // One output per source pair (2k, 2k+1); when limit is odd the last source slot is unpaired
672 // and folds against an implicit zero, so we round up: ceil(limit / 2).
673 const size_t num_outputs = (limit / 2) + (limit % 2);
674 fold_stride2(poly, dest, /*begin=*/0, /*end=*/num_outputs, round_challenge);
675 dest.shrink_end_index(num_outputs);
676 });
677 // Halve the active-row prefix to track the folded trace; the loop above leaves the member untouched, so this
678 // reads the pre-round value even when source and dest alias (see partially_evaluate_in_place).
679 if constexpr (requires {
680 source_polynomials.row_skip_active_prefix_end;
681 dest_polynomials.row_skip_active_prefix_end;
682 }) {
683 dest_polynomials.row_skip_active_prefix_end = (source_polynomials.row_skip_active_prefix_end / 2) +
684 (source_polynomials.row_skip_active_prefix_end % 2);
685 }
686 };
687
695 const FF& round_challenge)
696 {
697 PartiallyEvaluatedMultivariates partially_evaluated_polynomials(full_polynomials, multivariate_n);
698 partially_evaluate(full_polynomials, partially_evaluated_polynomials, round_challenge);
699 return partially_evaluated_polynomials;
700 }
701
705 static void partially_evaluate_in_place(PartiallyEvaluatedMultivariates& polynomials, const FF& round_challenge)
706 {
707 partially_evaluate(polynomials, polynomials, round_challenge);
708 };
709
722 {
723 ClaimedEvaluations multivariate_evaluations;
724 for (auto [eval, poly] :
725 zip_view(multivariate_evaluations.get_all(), partially_evaluated_polynomials.get_all())) {
726 eval = poly[0];
727 };
728 return multivariate_evaluations;
729 };
730
737 template <typename PartialEvals, typename Alphas>
740 PartialEvals& partially_evaluated_polynomials,
742 GateSeparatorPolynomial<FF>& gate_separator,
743 const Alphas& alphas,
745 {
746 // Row-disabling flavors batch with per-relation L / (1 - L). Non-row-disabling flavors
747 // pass nullptr so the callee's factor defaults collapse to plain α-batching.
749 return round.compute_virtual_contribution(
750 partially_evaluated_polynomials, relation_parameters, gate_separator, alphas, rd);
751 }
752
756 static void fold_for_zero_extension(PartiallyEvaluatedMultivariates& pe, const FF& round_challenge)
757 {
758 for (auto& poly : pe.get_all()) {
759 if (poly.end_index() > 0) {
760 poly.at(0) *= (FF(1) - round_challenge);
761 }
762 }
763 }
764};
765
802template <typename Flavor> class SumcheckVerifier {
803
804 public:
806 using FF = typename Flavor::FF;
812 // For ZK Flavors: the verifier obtains a vector of evaluations of \f$ d \f$ univariate polynomials and uses them to
813 // compute full_honk_relation_purported_value
814 using ClaimedLibraEvaluations = typename std::vector<FF>;
818
820
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)
848 , alphas(initialize_relation_separator<FF, Flavor::NUM_SUBRELATIONS - 1>(alpha)) {};
860 const std::vector<FF>& gate_challenges)
861 {
862 if constexpr (isMultilinearBatchingFlavor) {
864 Flavor::NUM_CLAIMS,
865 "Incorrect number of computed multilinear batching challenges.");
866 }
867
868 bb::GateSeparatorPolynomial<FF> gate_separators(gate_challenges);
869 // Construct a ZKHandler to handle all the libra related information in the transcript
870 VerifierZKCorrectionHandler<Flavor> zk_correction_handler(transcript);
871
872 // Correct the target sum in the round in the ZK case
873 zk_correction_handler.initialize_target_sum(round);
874
875 std::vector<FF> multivariate_challenge;
876 multivariate_challenge.reserve(virtual_log_n);
877
878 // Process univariate consistancy check rounds
879 // For ECCVM we ensure the consistencies by populating an vector of claimed evaluations that will be checked in
880 // the PCS rounds
881 // For other flavors, we perform the sumcheck univariate consistency check
882
883 bool verified = true;
884 // Heap-allocate ClaimedEvaluations (AllValues) to keep the sumcheck-verify stack frame small.
885 // For recursive flavors with many columns (e.g. AVM), holding this inline on the stack can exceed the 8 MB
886 // stack limit once nested inside the inner-Mega AVM recursive verifier chain
887 auto purported_evaluations_storage = std::make_unique<ClaimedEvaluations>();
888 ClaimedEvaluations& purported_evaluations = *purported_evaluations_storage;
889 for (size_t round_idx = 0; round_idx < virtual_log_n; round_idx++) {
890 round.process_round(transcript, multivariate_challenge, gate_separators, round_idx);
891 verified = verified && !round.round_failed;
892
893 if constexpr (IsTranslatorFlavor<Flavor>) {
894 if (round_idx == Flavor::LOG_MINI_CIRCUIT_SIZE - 1) {
895 // Receive mini-circuit evaluations mid-sumcheck so that they get hashed into the transcript,
896 // ensuring the remaining LOG_N - LOG_MINI_CIRCUIT_SIZE round challenges depend on them.
897 Flavor::set_minicircuit_evaluations(
898 purported_evaluations,
900 "Sumcheck:minicircuit_evaluations"));
901 }
902 }
903 }
904
905 // Populate claimed evaluations at the challenge
906 if constexpr (IsTranslatorFlavor<Flavor>) {
907 // Translator path: receive full-circuit evaluations, set them, and complete
908 // (computable precomputed selectors + L_0 scaling of minicircuit wires already placed above)
910 transcript->template receive_from_prover<std::array<FF, Flavor::NUM_FULL_CIRCUIT_EVALUATIONS>>(
911 "Sumcheck:evaluations"));
912 Flavor::complete_full_circuit_evaluations(
913 purported_evaluations, *get_full_circuit_evaluations, std::span<const FF>(multivariate_challenge));
914 } else {
915 // Heap-allocate transcript_evaluations for the same reason as purported_evaluations above.
916 auto transcript_evaluations = std::make_unique<std::array<FF, NUM_POLYNOMIALS>>(
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 }
922
923 // OriginTag false positive: The evaluations are PCS-bound - the prover committed to the
924 // polynomials before challenges were known, and the PCS opening verifies consistency.
925 if constexpr (IsRecursiveFlavor<Flavor>) {
926 const auto challenge_tag = multivariate_challenge.back().get_origin_tag();
927 for (auto& eval : purported_evaluations.get_all()) {
928 eval.set_origin_tag(challenge_tag);
929 }
930 }
931
932 // Evaluate the Honk relation at the sumcheck challenge; row-disabling factors are applied
933 // internally for flavors that use them.
934 FF full_honk_purported_value = round.compute_full_relation_purported_value(
935 purported_evaluations, relation_parameters, gate_separators, alphas, multivariate_challenge);
936
937 // Libra correction (ZK only).
938 zk_correction_handler.apply_zk_corrections(full_honk_purported_value, multivariate_challenge);
939
941 bool final_check = round.perform_final_verification(full_honk_purported_value);
942 verified = final_check && verified;
943
944 // For ZK Flavors: the evaluations of Libra univariates are included in the Sumcheck Output
945 return SumcheckOutput<Flavor>{ .challenge = multivariate_challenge,
946 .claimed_evaluations = std::move(purported_evaluations),
947 .verified = verified,
948 .claimed_libra_evaluation = zk_correction_handler.get_libra_evaluation(),
949 .round_univariate_commitments = round.get_round_univariate_commitments(),
950 .round_univariate_evaluations = round.get_round_univariate_evaluations() };
951 };
952};
953
954template <typename FF, size_t N> std::array<FF, N> initialize_relation_separator(const FF& alpha)
955{
956 std::array<FF, N> alphas;
957 alphas[0] = alpha;
958 for (size_t i = 1; i < N; ++i) {
959 alphas[i] = alphas[i - 1] * alpha;
960 }
961 return alphas;
962}
963} // namespace bb
constexpr size_t N
#define BB_ASSERT(expression,...)
Definition assert.hpp:70
#define BB_ASSERT_GTE(left, right,...)
Definition assert.hpp:128
#define BB_ASSERT_EQ(actual, expected,...)
Definition assert.hpp:83
#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
The implementation of the sumcheck Prover for statements of the form for multilinear polynomials .
Definition sumcheck.hpp:304
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:660
static constexpr size_t BATCHED_RELATION_PARTIAL_LENGTH
Definition sumcheck.hpp:325
typename Flavor::FF FF
Definition sumcheck.hpp:306
ProverPolynomials & full_polynomials
Definition sumcheck.hpp:334
const size_t multivariate_n
Definition sumcheck.hpp:330
bb::RelationParameters< FF > relation_parameters
Definition sumcheck.hpp:345
typename Flavor::Transcript Transcript
Definition sumcheck.hpp:313
SumcheckOutput< Flavor > prove()
Non-ZK version: Compute round univariate, place it in transcript, compute challenge,...
Definition sumcheck.hpp:398
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:694
static constexpr bool isMultilinearBatchingFlavor
Definition sumcheck.hpp:317
typename Flavor::ProverPolynomials ProverPolynomials
Definition sumcheck.hpp:309
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:322
std::array< FF, Flavor::NUM_SUBRELATIONS - 1 > SubrelationSeparators
Definition sumcheck.hpp:314
const size_t multivariate_d
Definition sumcheck.hpp:332
static void partially_evaluate_in_place(PartiallyEvaluatedMultivariates &polynomials, const FF &round_challenge)
Evaluate at the round challenge in-place.
Definition sumcheck.hpp:705
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:721
typename Flavor::AllValues ClaimedEvaluations
Definition sumcheck.hpp:311
typename bb::Univariate< FF, BATCHED_RELATION_PARTIAL_LENGTH > SumcheckRoundUnivariate
Definition sumcheck.hpp:327
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:756
std::vector< FF > multivariate_challenge
Definition sumcheck.hpp:350
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:738
typename Flavor::PartiallyEvaluatedMultivariates PartiallyEvaluatedMultivariates
Definition sumcheck.hpp:310
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:358
RowDisablingPolynomial< FF > row_disabling_polynomial
Definition sumcheck.hpp:354
typename Flavor::CommitmentKey CommitmentKey
Definition sumcheck.hpp:315
std::vector< FF > gate_challenges
Definition sumcheck.hpp:343
SumcheckProverRound< Flavor > round
Definition sumcheck.hpp:338
std::shared_ptr< Transcript > transcript
Definition sumcheck.hpp:336
ZKSumcheckData< Flavor > ZKData
Definition sumcheck.hpp:312
SubrelationSeparators alphas
Definition sumcheck.hpp:341
Imlementation of the Sumcheck prover round.
Implementation of the sumcheck Verifier for statements of the form for multilinear polynomials .
Definition sumcheck.hpp:802
typename std::vector< FF > ClaimedLibraEvaluations
Definition sumcheck.hpp:814
std::array< FF, Flavor::NUM_SUBRELATIONS - 1 > SubrelationSeparators
Definition sumcheck.hpp:816
typename Flavor::FF FF
Definition sumcheck.hpp:806
typename Flavor::Commitment Commitment
Definition sumcheck.hpp:817
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
static constexpr bool isMultilinearBatchingFlavor
Definition sumcheck.hpp:819
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
static constexpr size_t NUM_POLYNOMIALS
The number of Prover Polynomials specified by the Flavor.
Definition sumcheck.hpp:829
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:811
SubrelationSeparators alphas
Definition sumcheck.hpp:839
typename Flavor::Transcript Transcript
Definition sumcheck.hpp:815
static constexpr size_t BATCHED_RELATION_PARTIAL_LENGTH
Maximum partial algebraic degree of the relation , i.e. MAX_PARTIAL_RELATION_LENGTH + 1.
Definition sumcheck.hpp:825
Implementation of the Sumcheck Verifier Round.
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:954
void parallel_for(size_t num_iterations, const std::function< void(size_t)> &func)
Definition thread.cpp:112
STL namespace.
constexpr decltype(auto) get(::tuplet::tuple< T... > &&t) noexcept
Definition tuple.hpp:13
std::string to_string(bb::avm2::ValueTag tag)
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:70
void process_round_univariate(size_t round_idx, bb::Univariate< FF, BATCHED_RELATION_PARTIAL_LENGTH > &round_univariate)
Definition sumcheck.hpp:87
typename Flavor::CommitmentKey CommitmentKey
Definition sumcheck.hpp:63
std::vector< Polynomial< FF > > round_univariates
Definition sumcheck.hpp:71
typename Flavor::Commitment Commitment
Definition sumcheck.hpp:64
std::vector< Commitment > round_commitments
Definition sumcheck.hpp:72
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:113
std::vector< Polynomial< FF > > get_univariates()
Definition sumcheck.hpp:122
std::shared_ptr< Transcript > transcript
Definition sumcheck.hpp:67
typename Flavor::Transcript Transcript
Definition sumcheck.hpp:62
std::vector< Commitment > get_commitments()
Definition sumcheck.hpp:123
std::vector< std::array< FF, 3 > > get_evaluations()
Definition sumcheck.hpp:121
RoundUnivariateHandler(std::shared_ptr< Transcript > transcript)
Definition sumcheck.hpp:74
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:47
void process_round_univariate(size_t round_idx, bb::Univariate< FF, BATCHED_RELATION_PARTIAL_LENGTH > &round_univariate)
Definition sumcheck.hpp:41
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:53
RoundUnivariateHandler(std::shared_ptr< Transcript > transcript)
Definition sumcheck.hpp:35
std::vector< typename Flavor::Commitment > get_commitments()
Definition sumcheck.hpp:54
std::vector< std::array< FF, 3 > > get_evaluations()
Definition sumcheck.hpp:52
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
void apply_zk_corrections(FF &full_honk_purported_value, std::vector< FF > &multivariate_challenge)
Definition sumcheck.hpp:177
VerifierZKCorrectionHandler(std::shared_ptr< Transcript > transcript)
Definition sumcheck.hpp:164
void initialize_target_sum(SumcheckRound &round)
Definition sumcheck.hpp:170
std::shared_ptr< Transcript > transcript
Definition sumcheck.hpp:159
Handler for ZK-related verification adjustments in sumcheck. Default implementation: no ZK adjustment...
Definition sumcheck.hpp:130
void apply_zk_corrections(FF &, const std::vector< FF > &)
Definition sumcheck.hpp:146
typename Flavor::Transcript Transcript
Definition sumcheck.hpp:132
void initialize_target_sum(SumcheckRound &)
Definition sumcheck.hpp:144
std::shared_ptr< Transcript > transcript
Definition sumcheck.hpp:135
VerifierZKCorrectionHandler(std::shared_ptr< Transcript > transcript)
Definition sumcheck.hpp:140
This structure is created to contain various polynomials and constants required by ZK Sumcheck.
VectorField result