Barretenberg
The ZK-SNARK library at the core of Aztec
Loading...
Searching...
No Matches
sumcheck_round.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 "zk_sumcheck_data.hpp"
19
20#include <algorithm>
21
22namespace bb {
23
24// To know if a flavor is AVM, without including the flavor.
25template <typename Flavor>
26concept isAvmFlavor = std::convertible_to<decltype(Flavor::IS_AVM), bool>;
27
48template <typename Flavor> class SumcheckProverRound {
50
51 public:
52 using FF = typename Flavor::FF;
53 using Relations = typename Flavor::Relations;
54 using SumcheckTupleOfTuplesOfUnivariates = decltype(create_sumcheck_tuple_of_tuples_of_univariates<Relations>());
57 typename Flavor::template ProverUnivariates<2>,
58 typename Flavor::ExtendedEdges>;
63 size_t round_size;
64
65 // Number of rows excluded from the main sumcheck loop and handled by compute_disabled_contribution.
66 // In round 0, the RowDisablingPolynomial disables TRACE_OFFSET rows (2 edge pairs for TRACE_OFFSET=4)
67 // at the TOP of the trace. After partial evaluation in round 1+, this collapses to 2 rows (1 edge pair).
68 // Only non-zero for ZK flavors: non-ZK disabled rows are all zeros and handled by the main loop.
70
75 static constexpr size_t NUM_RELATIONS = Flavor::NUM_RELATIONS;
88 // Note: since this is not initialized with {}, the univariates contain garbage.
90
91 // The length of the polynomials used to mask the Sumcheck Round Univariates.
92 static constexpr size_t LIBRA_UNIVARIATES_LENGTH = Flavor::Curve::LIBRA_UNIVARIATES_LENGTH;
93
94 // Prover constructor
95 SumcheckProverRound(size_t initial_round_size)
96 : round_size(initial_round_size)
97 {
98 BB_BENCH_NAME("SumcheckProverRound constructor");
99
100 // Initialize univariate accumulators to 0
102 }
103
110 template <typename ProverPolynomialsOrPartiallyEvaluatedMultivariates>
111 size_t compute_effective_round_size(const ProverPolynomialsOrPartiallyEvaluatedMultivariates& multivariates) const
112 {
113 size_t max_end_index = 0;
114 if constexpr (requires { multivariates.get_witness(); }) {
115 for (auto& witness_poly : multivariates.get_witness()) {
116 max_end_index = std::max(max_end_index, witness_poly.end_index());
117 }
118 } else {
119 return round_size;
120 }
121
122 size_t effective = max_end_index + (max_end_index % 2); // round up to next even
123 if constexpr (Flavor::HasZK) {
124 if constexpr (!UseRowDisablingPolynomial<Flavor>) {
125 // ZK flavors without row disabling (e.g. Translator) must iterate over the full round_size.
126 return round_size;
127 }
128 }
129 return std::min(round_size, effective);
130 }
131
160 template <typename ProverPolynomialsOrPartiallyEvaluatedMultivariates>
161 void extend_edges(ExtendedEdges& extended_edges,
162 const ProverPolynomialsOrPartiallyEvaluatedMultivariates& multivariates,
163 const size_t edge_idx)
164 {
165 for (auto [extended_edge, multivariate] : zip_view(extended_edges.get_all(), multivariates.get_all())) {
166 if constexpr (Flavor::USE_SHORT_MONOMIALS) {
167 extended_edge = bb::Univariate<FF, 2>({ multivariate[edge_idx], multivariate[edge_idx + 1] });
168 } else {
169 if (multivariate.end_index() < edge_idx) {
170 static const auto zero_univariate = bb::Univariate<FF, MAX_PARTIAL_RELATION_LENGTH>::zero();
171 extended_edge = zero_univariate;
172 } else {
173 extended_edge = bb::Univariate<FF, 2>({ multivariate[edge_idx], multivariate[edge_idx + 1] })
174 .template extend_to<MAX_PARTIAL_RELATION_LENGTH>();
175 }
176 }
177 }
178 }
179
184 template <typename ProverPolynomialsOrPartiallyEvaluatedMultivariates>
185 SumcheckRoundUnivariate compute_univariate(ProverPolynomialsOrPartiallyEvaluatedMultivariates& polynomials,
186 const bb::RelationParameters<FF>& relation_parameters,
187 const bb::GateSeparatorPolynomial<FF>& gate_separators,
188 const SubrelationSeparators& alphas)
189 {
190 if constexpr (isAvmFlavor<Flavor>) {
191 return compute_univariate_avm(polynomials, relation_parameters, gate_separators, alphas);
192 } else {
193 return compute_univariate_with_row_skipping(polynomials, relation_parameters, gate_separators, alphas);
194 }
195 }
196
205 const size_t start_edge_idx;
206 const size_t end_edge_idx;
207 const size_t rows_per_chunk;
208 const size_t total_chunks;
209 std::atomic<size_t> next_chunk{ 0 };
210
211 ChunkStealer(size_t start, size_t end, size_t rpc)
212 : start_edge_idx(start)
213 , end_edge_idx(end)
214 , rows_per_chunk(rpc)
215 , total_chunks(((end - start) / rpc) + ((end - start) % rpc > 0 ? 1 : 0))
216 {
217 BB_ASSERT(start % 2 == 0, "start_edge_idx must be even");
218 BB_ASSERT(end % 2 == 0, "end_edge_idx must be even");
219 BB_ASSERT(rpc >= 2 && rpc % 2 == 0, "rows_per_chunk must be at least 2 and even");
220 BB_ASSERT(start <= end, "start_edge_idx must not exceed end_edge_idx");
221 }
222
223 size_t num_slots() const { return std::min(bb::get_num_cpus(), std::max<size_t>(total_chunks, 1)); }
224
226 {
227 const size_t id = next_chunk.fetch_add(1, std::memory_order_relaxed);
228 if (id >= total_chunks) {
229 return std::nullopt;
230 }
231 const size_t chunk_start = start_edge_idx + id * rows_per_chunk;
232 const size_t chunk_end = std::min(chunk_start + rows_per_chunk, end_edge_idx);
233 return std::make_pair(chunk_start, chunk_end);
234 }
235 };
236
243 template <typename ProverPolynomialsOrPartiallyEvaluatedMultivariates>
244 SumcheckRoundUnivariate compute_univariate_avm(ProverPolynomialsOrPartiallyEvaluatedMultivariates& polynomials,
245 const bb::RelationParameters<FF>& relation_parameters,
246 const bb::GateSeparatorPolynomial<FF>& gate_separators,
247 const SubrelationSeparators& alphas)
248 {
249 BB_BENCH_NAME("compute_univariate_avm");
250
251 // Compute the effective round size. If the trace is short, we don't need to iterate over the full round_size.
252 const size_t effective_round_size = compute_effective_round_size(polynomials);
253
254 // Prepare for work-stealing across chunks of edges
255 constexpr size_t rows_per_chunk = 16; // empirically chosen for good load balance in AVM
256 ChunkStealer chunks{ excluded_head_size, effective_round_size, rows_per_chunk };
257
258 // One accumulator slot per outer task; each outer task's iteration index IS its slot.
259 // No state is shared with other SumcheckProverRound invocations.
260 std::vector<SumcheckTupleOfTuplesOfUnivariates> thread_univariate_accumulators(chunks.num_slots());
261
262 // Accumulate the contribution from each sub-relation across each edge of the hyper-cube.
263 parallel_for(chunks.num_slots(), [&](size_t slot_id) {
264 ExtendedEdges lazy_extended_edges(polynomials);
265 auto& accum = thread_univariate_accumulators[slot_id];
266 while (auto range = chunks.pop()) {
267 const auto [start, end] = *range;
268 for (size_t edge_idx = start; edge_idx < end; edge_idx += 2) {
269 lazy_extended_edges.set_current_edge(edge_idx);
270 // Compute the \f$ \ell \f$-th edge's univariate contribution,
271 // scale it by the corresponding \f$ pow_{\beta} \f$ contribution and add it to the accumulators
272 // for \f$ \tilde{S}^i(X_i) \f$. If \f$ \ell \f$'s binary representation is given by \f$
273 // (\ell_{i+1},\ldots, \ell_{d-1})\f$, the \f$ pow_{\beta}\f$-contribution is
274 // \f$\beta_{i+1}^{\ell_{i+1}} \cdot \ldots \cdot \beta_{d-1}^{\ell_{d-1}}\f$.
275 accumulate_relation_univariates(
276 accum, lazy_extended_edges, relation_parameters, gate_separators[edge_idx]);
277 }
278 }
279 });
280
281 // Accumulate the per-thread univariate accumulators into a single set of accumulators
282 for (auto& accumulators : thread_univariate_accumulators) {
284 }
285
286 // Batch the univariate contributions from each sub-relation to obtain the round univariate
287 return batch_over_relations<SumcheckRoundUnivariate>(univariate_accumulators, alphas, gate_separators);
288 }
289
295 size_t size;
296 };
297
298 // True when the flavor exposes a static row-skip manifest: a contiguous prefix [head, active_prefix_end) holding
299 // every relation-active row, used directly instead of the row-by-row skip_entire_row scan below. Only sound when
300 // the prefix is tight (no inactive rows inside it); flavors whose active rows are interspersed should omit it and
301 // use the dynamic scan. See Flavor::row_skip_active_prefix_end.
302 template <typename ProverPolynomialsOrPartiallyEvaluatedMultivariates>
303 static constexpr bool HAS_STATIC_ROW_SKIP_MANIFEST =
305 requires(const ProverPolynomialsOrPartiallyEvaluatedMultivariates& polynomials) {
307 };
308
309 static size_t round_up_to_even(const size_t value) { return value + (value & 1U); }
310
311 static void append_scan_range(std::vector<BlockOfContiguousRows>& ranges, const size_t start, const size_t end)
312 {
313 if (end <= start) {
314 return;
315 }
316 if (!ranges.empty()) {
317 auto& previous = ranges.back();
318 const size_t previous_end = previous.starting_edge_idx + previous.size;
319 if (start <= previous_end) {
320 previous.size = std::max(previous_end, end) - previous.starting_edge_idx;
321 return;
322 }
323 }
324 ranges.push_back(BlockOfContiguousRows{ .starting_edge_idx = start, .size = end - start });
325 }
326
328 {
329 if (blocks.empty()) {
330 return;
331 }
332 std::sort(blocks.begin(), blocks.end(), [](const BlockOfContiguousRows& lhs, const BlockOfContiguousRows& rhs) {
333 return lhs.starting_edge_idx < rhs.starting_edge_idx;
334 });
335
336 size_t write_idx = 0;
337 for (size_t read_idx = 1; read_idx < blocks.size(); ++read_idx) {
338 auto& previous = blocks[write_idx];
339 const auto& current = blocks[read_idx];
340 const size_t previous_end = previous.starting_edge_idx + previous.size;
341 if (current.starting_edge_idx <= previous_end) {
342 previous.size =
343 std::max(previous_end, current.starting_edge_idx + current.size) - previous.starting_edge_idx;
344 } else {
345 ++write_idx;
346 blocks[write_idx] = current;
347 }
348 }
349 blocks.resize(write_idx + 1);
350 }
351
352 template <typename ProverPolynomialsOrPartiallyEvaluatedMultivariates>
354 ProverPolynomialsOrPartiallyEvaluatedMultivariates& polynomials, const size_t effective_round_size) const
355 {
356 const size_t scan_start = excluded_head_size;
358 if (effective_round_size <= scan_start) {
359 return ranges;
360 }
361
362 if constexpr (HAS_STATIC_ROW_SKIP_MANIFEST<ProverPolynomialsOrPartiallyEvaluatedMultivariates>) {
363 const size_t row_skip_active_prefix_end = Flavor::row_skip_active_prefix_end(polynomials);
364 if (row_skip_active_prefix_end == 0) {
365 append_scan_range(ranges, scan_start, effective_round_size);
366 return ranges;
367 }
368
369 const size_t active_prefix_end =
370 std::min(round_up_to_even(row_skip_active_prefix_end), effective_round_size);
371 append_scan_range(ranges, scan_start, std::max(scan_start, active_prefix_end));
372
373 // Lagrange-last lives at the end of the domain. Everything between the active prefix and this final
374 // edge-pair is known to be relation-trivial, so do not spend scan work proving it row-by-row.
375 if (effective_round_size >= scan_start + 2) {
376 append_scan_range(ranges, effective_round_size - 2, effective_round_size);
377 }
378 } else {
379 append_scan_range(ranges, scan_start, effective_round_size);
380 }
381 return ranges;
382 }
383
397 template <typename ProverPolynomialsOrPartiallyEvaluatedMultivariates>
399 ProverPolynomialsOrPartiallyEvaluatedMultivariates& polynomials)
400 {
401 // When !HasZK, compute the effective round size to avoid iterating over zero regions
402 const size_t effective_round_size = compute_effective_round_size(polynomials);
403
404 // The disabled head rows are handled by compute_disabled_contribution, so skip them here
405 const size_t start_edge_idx = excluded_head_size;
406
408 constexpr bool has_static_row_skip_manifest =
409 HAS_STATIC_ROW_SKIP_MANIFEST<ProverPolynomialsOrPartiallyEvaluatedMultivariates>;
410 constexpr bool can_skip_rows = (isRowSkippable<Flavor, decltype(polynomials), size_t>);
411
412 if constexpr (has_static_row_skip_manifest) {
413 // Static row manifests describe the relation-active edge pairs directly, avoiding the old per-row skip
414 // scan over the whole trace.
415 result = compute_row_skip_scan_ranges(polynomials, effective_round_size);
416 } else if constexpr (can_skip_rows) {
417 // Iterate over edge-pairs (stride-2) so each thread gets an even-aligned range.
418 const std::vector<BlockOfContiguousRows> scan_ranges =
419 compute_row_skip_scan_ranges(polynomials, effective_round_size);
420 // Cost per iteration: skip_entire_row reads across polynomial columns.
421 // Overestimates by using total entity count (skip_entire_row only checks a subset).
422 constexpr size_t heuristic_cost = bb::thread_heuristics::FF_COPY_COST * 2 * Flavor::NUM_ALL_ENTITIES;
424
425 for (const auto& scan_range : scan_ranges) {
426 const size_t num_edge_pairs = scan_range.size / 2;
428 num_edge_pairs,
429 [&](ThreadChunk chunk) {
430 auto range = chunk.range(num_edge_pairs);
431 if (range.empty()) {
432 return;
433 }
434 // Scan edge pairs to find contiguous runs of non-skippable rows.
435 // We track the start and size of the current run, emitting a block
436 // whenever we hit a skippable row or reach the end of the range.
437 size_t current_block_start = 0;
438 size_t current_block_size = 0;
440 for (size_t pair_idx : range) {
441 size_t edge_idx = scan_range.starting_edge_idx + pair_idx * 2;
442 if (!Flavor::skip_entire_row(polynomials, edge_idx)) {
443 // Non-skippable row: begin a new block or extend the current one
444 if (current_block_size == 0) {
445 current_block_start = edge_idx;
446 }
447 current_block_size += 2; // each pair covers 2 edges
448 } else {
449 // Skippable row: flush the current block if one is open
450 if (current_block_size > 0) {
451 thread_blocks.push_back(BlockOfContiguousRows{
452 .starting_edge_idx = current_block_start, .size = current_block_size });
453 current_block_size = 0;
454 }
455 }
456 }
457 // Flush any remaining block at the end of the range
458 if (current_block_size > 0) {
459 thread_blocks.push_back(BlockOfContiguousRows{ .starting_edge_idx = current_block_start,
460 .size = current_block_size });
461 }
462 auto& blocks = all_thread_blocks[chunk.thread_index];
463 blocks.insert(blocks.end(), thread_blocks.begin(), thread_blocks.end());
464 },
465 heuristic_cost);
466 }
467
468 for (const auto& thread_blocks : all_thread_blocks) {
469 for (const auto block : thread_blocks) {
470 result.push_back(block);
471 }
472 }
473 merge_contiguous_blocks(result);
474 } else {
475 result.push_back(BlockOfContiguousRows{ .starting_edge_idx = start_edge_idx,
476 .size = effective_round_size - start_edge_idx });
477 }
478 return result;
479 }
480
502 template <typename ProverPolynomialsOrPartiallyEvaluatedMultivariates>
504 ProverPolynomialsOrPartiallyEvaluatedMultivariates& polynomials,
505 const bb::RelationParameters<FF>& relation_parameters,
506 const bb::GateSeparatorPolynomial<FF>& gate_separators,
507 const SubrelationSeparators alphas)
508 {
509 BB_BENCH_NAME("compute_univariate_with_row_skipping");
510
511 constexpr bool has_static_row_skip_manifest =
512 HAS_STATIC_ROW_SKIP_MANIFEST<ProverPolynomialsOrPartiallyEvaluatedMultivariates>;
513 constexpr bool can_skip_rows = (isRowSkippable<Flavor, decltype(polynomials), size_t>);
514 constexpr bool uses_row_manifest = has_static_row_skip_manifest || can_skip_rows;
515
516 if constexpr (!uses_row_manifest) {
517 // Non-row-skipping flavors (UltraHonk, Mega, MultilinearBatching) use dynamic chunk
518 // dispatch to balance per-row cost variance from selector-gated relation skipping.
519 // Short traces don't need to iterate over the zero tail of the polynomial.
520 const size_t effective_round_size = compute_effective_round_size(polynomials);
521 constexpr size_t rows_per_chunk = 64; // empirically chosen for good load balance
522 ChunkStealer chunks{ excluded_head_size, effective_round_size, rows_per_chunk };
523
524 // Construct univariate accumulator containers; one per slot.
525 // Note: std::vector will trigger {}-initialization of the contents. Therefore no need to zero the
526 // univariates.
527 std::vector<SumcheckTupleOfTuplesOfUnivariates> thread_univariate_accumulators(chunks.num_slots());
528
529 parallel_for(chunks.num_slots(), [&](size_t slot_id) {
530 // Construct extended univariates container; reused across every chunk this slot claims.
531 ExtendedEdges extended_edges;
532 auto& accum = thread_univariate_accumulators[slot_id];
533 while (auto range = chunks.pop()) {
534 const auto [start, end] = *range;
535 for (size_t edge_idx = start; edge_idx < end; edge_idx += 2) {
536 extend_edges(extended_edges, polynomials, edge_idx);
537 // Compute the \f$ \ell \f$-th edge's univariate contribution,
538 // scale it by the corresponding \f$ pow_{\beta} \f$ contribution and add it to the accumulators
539 // for \f$ \tilde{S}^i(X_i) \f$. If \f$ \ell \f$'s binary representation is given by \f$
540 // (\ell_{i+1},\ldots, \ell_{d-1})\f$, the \f$ pow_{\beta}\f$-contribution is
541 // \f$\beta_{i+1}^{\ell_{i+1}} \cdot \ldots \cdot \beta_{d-1}^{\ell_{d-1}}\f$.
542 // MultilinearBatching flavors use eq polynomials and no pow_beta, so the factor is 1.
543 FF scaling_factor{ 1 };
544 if constexpr (!isMultilinearBatchingFlavor<Flavor>) {
545 scaling_factor = gate_separators[edge_idx];
546 }
547 accumulate_relation_univariates(accum, extended_edges, relation_parameters, scaling_factor);
548 }
549 }
550 });
551
552 // Accumulate the per-slot univariate accumulators into a single set of accumulators.
553 for (auto& accumulators : thread_univariate_accumulators) {
554 Utils::add_nested_tuples(univariate_accumulators, accumulators);
555 }
556 // Batch the univariate contributions from each sub-relation to obtain the round univariate;
557 // these are unmasked; we will mask in sumcheck.
558 return batch_over_relations<SumcheckRoundUnivariate>(univariate_accumulators, alphas, gate_separators);
559 }
560
561 // Row-skipping flavors (ECCVM, Translator) iterate only over contiguous blocks of non-skippable
562 // rows; work within each block is statically divided among threads via ThreadChunk ranges.
564 {
565 BB_BENCH_NAME("compute_univariate_with_row_skipping/compute_manifest");
566 round_manifest = compute_contiguous_round_size(polynomials);
567 }
568
569 // Construct univariate accumulator containers; one per thread
570 // Note: std::vector will trigger {}-initialization of the contents. Therefore no need to zero the univariates.
571 std::vector<SumcheckTupleOfTuplesOfUnivariates> thread_univariate_accumulators(get_num_cpus());
572
573 parallel_for([&](ThreadChunk chunk) {
574 BB_BENCH_NAME("compute_univariate_with_row_skipping/accumulate_blocks");
575 // Construct extended univariates containers; one per thread
576 ExtendedEdges extended_edges;
577
578 // Process each block, dividing work within each block
579 for (const BlockOfContiguousRows& block : round_manifest) {
580 size_t block_iterations = block.size / 2;
581
582 // Get the range of iterations this thread should process for this block
583 auto iteration_range = chunk.range(block_iterations);
584
585 for (size_t i : iteration_range) {
586 size_t edge_idx = block.starting_edge_idx + (i * 2);
587 extend_edges(extended_edges, polynomials, edge_idx);
588 // Compute the \f$ \ell \f$-th edge's univariate contribution,
589 // scale it by the corresponding \f$ pow_{\beta} \f$ contribution and add it to the accumulators
590 // for \f$
591 // \tilde{S}^i(X_i) \f$. If \f$ \ell \f$'s binary representation is given by \f$
592 // (\ell_{i+1},\ldots, \ell_{d-1})\f$, the \f$ pow_{\beta}\f$-contribution is
593 // \f$\beta_{i+1}^{\ell_{i+1}} \cdot \ldots
594 // \cdot
595 // \beta_{d-1}^{\ell_{d-1}}\f$.
596
597 FF scaling_factor{ 1 };
598 if constexpr (!isMultilinearBatchingFlavor<Flavor>) {
599 scaling_factor = gate_separators[edge_idx];
600 }
601 accumulate_relation_univariates(thread_univariate_accumulators[chunk.thread_index],
602 extended_edges,
603 relation_parameters,
604 scaling_factor);
605 }
606 }
607 });
608
609 // Accumulate the per-thread univariate accumulators into a single set of accumulators
610 for (auto& accumulators : thread_univariate_accumulators) {
611 Utils::add_nested_tuples(univariate_accumulators, accumulators);
612 }
613 // Batch the univariate contributions from each sub-relation to obtain the round univariate
614 // these are unmasked; we will mask in sumcheck.
615 return batch_over_relations<SumcheckRoundUnivariate>(univariate_accumulators, alphas, gate_separators);
616 };
617
627 template <typename ProverPolynomialsOrPartiallyEvaluatedMultivariates>
629 ProverPolynomialsOrPartiallyEvaluatedMultivariates& polynomials,
630 const bb::RelationParameters<FF>& relation_parameters,
631 const bb::GateSeparatorPolynomial<FF>& gate_separators,
632 const SubrelationSeparators& alphas,
633 const RowDisablingPolynomial<FF> row_disabling_polynomial)
635 {
636 SumcheckTupleOfTuplesOfUnivariates univariate_accumulator{};
637 ExtendedEdges extended_edges;
639
640 for (size_t edge_idx = 0; edge_idx < excluded_head_size; edge_idx += 2) {
641 extend_edges(extended_edges, polynomials, edge_idx);
642 accumulate_relation_univariates(
643 univariate_accumulator, extended_edges, relation_parameters, gate_separators[edge_idx]);
644 }
645
646 result = batch_over_relations<SumcheckRoundUnivariate>(univariate_accumulator, alphas, gate_separators);
647
648 // Multiply by (1-L) factor.
649 bb::Univariate<FF, 2> one_minus_L(
650 { FF::one() - row_disabling_polynomial.eval_at_0, FF::one() - row_disabling_polynomial.eval_at_1 });
651 SumcheckRoundUnivariate one_minus_L_extended =
652 one_minus_L.template extend_to<SumcheckRoundUnivariate::LENGTH>();
653 result *= one_minus_L_extended;
654
655 return result;
656 }
657
658 template <typename ProverPolynomialsOrPartiallyEvaluatedMultivariates>
660 ProverPolynomialsOrPartiallyEvaluatedMultivariates& polynomials,
661 const bb::RelationParameters<FF>& relation_parameters,
662 const GateSeparatorPolynomial<FF>& gate_separator,
663 const SubrelationSeparators& alphas)
664 {
665 // Note: {} is required to initialize the tuple contents. Otherwise the univariates contain garbage.
666 SumcheckTupleOfTuplesOfUnivariates univariate_accumulator{};
667
668 // For a given prover polynomial P_i(X_0, ..., X_{d-1}) extended by zero, i.e. multiplied by
669 // \tau(X_d, ..., X_{virtual_log_n - 1}) = \prod (1 - X_k)
670 // for k = d, ..., virtual_log_n - 1, the computation of the virtual sumcheck round univariate reduces to the
671 // edge (0, ...,0).
672 const size_t virtual_contribution_edge_idx = 0;
673
674 // Perform the usual sumcheck accumulation, but for a single edge.
675 // Note: we use a combination of `auto`, constexpr and a lambda to construct different types.
676 auto extended_edges = [&]() {
677 if constexpr (isAvmFlavor<Flavor>) {
678 auto lazy_extended_edges = ExtendedEdges(polynomials);
679 lazy_extended_edges.set_current_edge(virtual_contribution_edge_idx);
680 return lazy_extended_edges;
681 } else {
682 ExtendedEdges extended_edges;
683 extend_edges(extended_edges, polynomials, virtual_contribution_edge_idx);
684 return extended_edges;
685 }
686 }();
687
688 // The tail of G(X) = \prod_{k} (1 + X_k(\beta_k - 1) ) evaluated at the edge (0, ..., 0).
689 const FF gate_separator_tail{ 1 };
690 accumulate_relation_univariates(
691 univariate_accumulator, extended_edges, relation_parameters, gate_separator_tail);
692
693 return batch_over_relations<SumcheckRoundUnivariate>(univariate_accumulator, alphas, gate_separator);
694 };
711 template <typename ExtendedUnivariate, typename ContainerOverSubrelations>
712 static ExtendedUnivariate batch_over_relations(ContainerOverSubrelations& univariate_accumulators,
713 const SubrelationSeparators& challenge,
714 const bb::GateSeparatorPolynomial<FF>& gate_separators)
715 {
716 Utils::scale_univariates(univariate_accumulators, challenge);
717
718 auto result = ExtendedUnivariate(0);
719 extend_and_batch_univariates(univariate_accumulators, result, gate_separators);
720
721 // Reset all univariate accumulators to 0 before beginning accumulation in the next round
722 Utils::zero_univariates(univariate_accumulators);
723 return result;
724 }
725
739 template <typename ExtendedUnivariate, typename TupleOfTuplesOfUnivariates>
740 static void extend_and_batch_univariates(const TupleOfTuplesOfUnivariates& tuple,
741 ExtendedUnivariate& result,
742 const bb::GateSeparatorPolynomial<FF>& gate_separators)
743 {
744 // Pow-Factor \f$ (1-X) + X\beta_i \f$
745 auto random_polynomial = bb::Univariate<FF, 2>({ 1, gate_separators.current_element() });
746 ExtendedUnivariate extended_random_polynomial =
747 random_polynomial.template extend_to<ExtendedUnivariate::LENGTH>();
748
749 constexpr_for<0, std::tuple_size_v<TupleOfTuplesOfUnivariates>, 1>([&]<size_t relation_idx>() {
750 const auto& outer_element = std::get<relation_idx>(tuple);
751 constexpr_for<0, std::tuple_size_v<std::decay_t<decltype(outer_element)>>, 1>(
752 [&]<size_t subrelation_idx>() {
753 const auto& element = std::get<subrelation_idx>(outer_element);
754 auto extended = element.template extend_to<ExtendedUnivariate::LENGTH>();
755
757 constexpr bool is_subrelation_linearly_independent =
758 bb::subrelation_is_linearly_independent<Relation, subrelation_idx>();
759 // Except from the log derivative subrelation, each other subrelation in part is required to be 0
760 // hence we multiply by the power polynomial. As the sumcheck prover is required to send a
761 // univariate to the verifier, we additionally need a univariate contribution from the pow
762 // polynomial which is the extended_random_polynomial which is the
763 if constexpr (!is_subrelation_linearly_independent) {
764 result += extended;
765 } else {
766 // Multiply by the pow polynomial univariate contribution and the partial
767 // evaluation result c_i (i.e. \f$ pow(u_0,...,u_{l-1})) \f$ where \f$(u_0,...,u_{i-1})\f$ are
768 // the verifier challenges from previous rounds.
769 result += extended * extended_random_polynomial * gate_separators.partial_evaluation_result;
770 }
771 });
772 });
773 }
774
787 static SumcheckRoundUnivariate compute_libra_univariate(const ZKData& zk_sumcheck_data, size_t round_idx)
788 {
790 // select the i'th column of Libra book-keeping table
791 const auto& current_column = zk_sumcheck_data.libra_univariates[round_idx];
792 // the evaluation of Libra round univariate at k=0...D are equal to \f$\texttt{libra_univariates}_{i}(k)\f$
793 // corrected by the Libra running sum
794 for (size_t idx = 0; idx < LIBRA_UNIVARIATES_LENGTH; ++idx) {
795 libra_round_univariate.value_at(idx) =
796 current_column.evaluate(FF(idx)) + zk_sumcheck_data.libra_running_sum;
797 };
798 if constexpr (BATCHED_RELATION_PARTIAL_LENGTH == LIBRA_UNIVARIATES_LENGTH) {
799 return libra_round_univariate;
800 } else {
801 return libra_round_univariate.template extend_to<SumcheckRoundUnivariate::LENGTH>();
802 }
803 }
804
805 // Methods made accessible for testing
807 const auto& extended_edges,
808 const bb::RelationParameters<FF>& relation_parameters,
809 const FF& scaling_factor)
810 {
811 accumulate_relation_univariates(univariate_accumulators, extended_edges, relation_parameters, scaling_factor);
812 }
813
814 private:
843 const auto& extended_edges,
844 const bb::RelationParameters<FF>& relation_parameters,
845 const FF& scaling_factor)
846 {
847 constexpr_for<0, NUM_RELATIONS, 1>([&]<size_t relation_idx>() {
849 // Check if the relation is skippable to speed up accumulation
850 if constexpr (!isSkippable<Relation, decltype(extended_edges)>) {
851 // If not, accumulate normally
852 Relation::accumulate(std::get<relation_idx>(univariate_accumulators),
853 extended_edges,
854 relation_parameters,
855 scaling_factor);
856 } else {
857 // If so, only compute the contribution if the relation is active
858 if (!Relation::skip(extended_edges)) {
859 Relation::accumulate(std::get<relation_idx>(univariate_accumulators),
860 extended_edges,
861 relation_parameters,
862 scaling_factor);
863 }
864 }
865 });
866 }
867};
868
881template <typename Flavor, bool CommittedSumcheck = UsesCommittedSumcheck<Flavor>> class SumcheckVerifierRound {
882 using FF = typename Flavor::FF;
884 using Relations = typename Flavor::Relations;
885 using TupleOfArraysOfValues = decltype(create_tuple_of_arrays_of_values<typename Flavor::Relations>());
887
888 public:
890 using ClaimedLibraEvaluations = typename std::vector<FF>;
893
894 bool round_failed = false;
895 static constexpr size_t NUM_RELATIONS = Flavor::NUM_RELATIONS;
896 static constexpr size_t BATCHED_RELATION_PARTIAL_LENGTH = Flavor::BATCHED_RELATION_PARTIAL_LENGTH;
898
899 FF target_total_sum = 0;
901
902 explicit SumcheckVerifierRound(FF target_total_sum = 0)
903 : target_total_sum(target_total_sum)
904 {
905 Utils::zero_elements(relation_evaluations);
906 };
907
912 {
913 // OriginTag false positive: The univariate is constrained by the sumcheck relation S^i(0) + S^i(1) =
914 // S^{i-1}(u_{i-1}).
915 if constexpr (IsRecursiveFlavor<Flavor>) {
916 const auto bound_tag = target_total_sum.get_origin_tag();
917 for (auto& eval : univariate.evaluations) {
918 eval.set_origin_tag(bound_tag);
919 }
920 }
921
922 FF total_sum = univariate.value_at(0) + univariate.value_at(1);
923 bool sumcheck_round_failed(false);
924 if constexpr (IsRecursiveFlavor<Flavor>) {
925 sumcheck_round_failed = (target_total_sum.get_value() != total_sum.get_value());
926 target_total_sum.assert_equal(total_sum);
927 } else {
928 sumcheck_round_failed = (target_total_sum != total_sum);
929 }
930 round_failed = round_failed || sumcheck_round_failed;
931 };
932
937 {
938 target_total_sum = univariate.evaluate(round_challenge);
939 }
940
945 const bb::RelationParameters<FF>& relation_parameters,
946 const bb::GateSeparatorPolynomial<FF>& gate_separators,
947 const SubrelationSeparators& alphas)
948 {
949 Utils::template accumulate_relation_evaluations_without_skipping<>(purported_evaluations,
950 relation_evaluations,
951 relation_parameters,
952 gate_separators.partial_evaluation_result);
953 return Utils::scale_and_batch_elements(relation_evaluations, alphas);
954 }
955
962 void process_round(const std::shared_ptr<Transcript>& transcript,
963 std::vector<FF>& multivariate_challenge,
964 bb::GateSeparatorPolynomial<FF>& gate_separators,
965 size_t round_idx)
966 {
967 // Obtain the round univariate from the transcript
968 std::string round_univariate_label = "Sumcheck:univariate_" + std::to_string(round_idx);
969 auto round_univariate =
970 transcript->template receive_from_prover<bb::Univariate<FF, BATCHED_RELATION_PARTIAL_LENGTH>>(
971 round_univariate_label);
972 FF round_challenge = transcript->template get_challenge<FF>("Sumcheck:u_" + std::to_string(round_idx));
973 multivariate_challenge.emplace_back(round_challenge);
974 // Check that $\tilde{S}^{i-1}(u_{i-1}) == \tilde{S}^{i}(0) + \tilde{S}^{i}(1)$
975 // For i = 0, check that $\tilde{S}^0(u_0) == target_total_sum$
976 check_sum(round_univariate);
977 // Evaluate $\tilde{S}^{i}(u_i)$
978 compute_next_target_sum(round_univariate, round_challenge);
979 gate_separators.partially_evaluate(round_challenge);
980 }
981
986 bool perform_final_verification(const FF& full_honk_purported_value)
987 {
988 bool verified = false;
989 if constexpr (IsRecursiveFlavor<Flavor>) {
990 verified = (full_honk_purported_value.get_value() == target_total_sum.get_value());
991 full_honk_purported_value.assert_equal(target_total_sum);
992 } else {
993 verified = (full_honk_purported_value == target_total_sum);
994 }
995 return verified;
996 }
997
1001 std::vector<Commitment> get_round_univariate_commitments() { return {}; }
1002
1007};
1008
1013template <typename Flavor> class SumcheckVerifierRound<Flavor, true> {
1014 using FF = typename Flavor::FF;
1017 using TupleOfArraysOfValues = decltype(create_tuple_of_arrays_of_values<typename Flavor::Relations>());
1019
1020 public:
1022 using ClaimedLibraEvaluations = typename std::vector<FF>;
1025
1026 bool round_failed = false;
1027 static constexpr size_t NUM_RELATIONS = Flavor::NUM_RELATIONS;
1028 static constexpr size_t BATCHED_RELATION_PARTIAL_LENGTH = Flavor::BATCHED_RELATION_PARTIAL_LENGTH;
1030
1031 FF target_total_sum = 0;
1033
1034 // Grumpkin-specific state for Shplemini
1035 std::vector<Commitment> round_univariate_commitments;
1037
1038 explicit SumcheckVerifierRound(FF target_total_sum = 0)
1039 : target_total_sum(target_total_sum)
1040 {
1041 Utils::zero_elements(relation_evaluations);
1042 };
1043
1048 const bb::RelationParameters<FF>& relation_parameters,
1049 const bb::GateSeparatorPolynomial<FF>& gate_separators,
1050 const SubrelationSeparators& alphas)
1051 {
1052 Utils::template accumulate_relation_evaluations_without_skipping<>(purported_evaluations,
1053 relation_evaluations,
1054 relation_parameters,
1055 gate_separators.partial_evaluation_result);
1056 return Utils::scale_and_batch_elements(relation_evaluations, alphas);
1057 }
1058
1063 void process_round(const std::shared_ptr<Transcript>& transcript,
1064 std::vector<FF>& multivariate_challenge,
1065 bb::GateSeparatorPolynomial<FF>& gate_separators,
1066 size_t round_idx)
1067 {
1068 const std::string round_univariate_comm_label = "Sumcheck:univariate_comm_" + std::to_string(round_idx);
1069 const std::string univariate_eval_label_0 = "Sumcheck:univariate_" + std::to_string(round_idx) + "_eval_0";
1070 const std::string univariate_eval_label_1 = "Sumcheck:univariate_" + std::to_string(round_idx) + "_eval_1";
1071
1072 // Receive the commitment to the round univariate
1073 round_univariate_commitments.push_back(
1074 transcript->template receive_from_prover<Commitment>(round_univariate_comm_label));
1075 // Receive evals at 0 and 1
1076 round_univariate_evaluations.push_back(
1077 { transcript->template receive_from_prover<FF>(univariate_eval_label_0),
1078 transcript->template receive_from_prover<FF>(univariate_eval_label_1),
1079 FF(0) }); // Third element will be populated in perform_final_verification
1080
1081 const FF round_challenge = transcript->template get_challenge<FF>("Sumcheck:u_" + std::to_string(round_idx));
1082 multivariate_challenge.emplace_back(round_challenge);
1083
1084 gate_separators.partially_evaluate(round_challenge);
1085
1086 // For Grumpkin, we don't perform per-round verification here
1087 // It will be deferred to the final check
1088 }
1089
1094 bool perform_final_verification(const FF& full_honk_purported_value)
1095 {
1096 // Compute the sum of evaluations at 0 and 1 for the first round
1097 FF first_sumcheck_round_evaluations_sum =
1098 round_univariate_evaluations[0][0] + round_univariate_evaluations[0][1];
1099
1100 bool verified = false;
1101 if constexpr (IsRecursiveFlavor<Flavor>) {
1102 if constexpr (IsGrumpkinFlavor<Flavor>) {
1103 first_sumcheck_round_evaluations_sum.self_reduce();
1104 target_total_sum.self_reduce();
1105 full_honk_purported_value.self_reduce();
1106 }
1107 verified = (first_sumcheck_round_evaluations_sum.get_value() == target_total_sum.get_value());
1108 first_sumcheck_round_evaluations_sum.assert_equal(target_total_sum);
1109 } else {
1110 verified = (first_sumcheck_round_evaluations_sum == target_total_sum);
1111 }
1112
1113 // Populate claimed evaluations of Sumcheck Round Univariates at the round challenges.
1114 // These will be checked as a part of Shplemini.
1115 for (size_t round_idx = 1; round_idx < round_univariate_evaluations.size(); round_idx++) {
1116 round_univariate_evaluations[round_idx - 1][2] =
1117 round_univariate_evaluations[round_idx][0] + round_univariate_evaluations[round_idx][1];
1118 }
1119
1120 // Store the final evaluation for Shplemini
1121 round_univariate_evaluations[round_univariate_evaluations.size() - 1][2] = full_honk_purported_value;
1122 return verified;
1123 }
1124
1128 std::vector<Commitment> get_round_univariate_commitments() { return round_univariate_commitments; }
1129
1133 std::vector<std::array<FF, 3>> get_round_univariate_evaluations() { return round_univariate_evaluations; }
1134};
1135} // namespace bb
#define BB_ASSERT(expression,...)
Definition assert.hpp:70
bb::field< bb::Bn254FrParams > FF
Definition field.cpp:24
#define BB_BENCH_NAME(name)
Definition bb_bench.hpp:264
A base class labelling all entities (for instance, all of the polynomials used by the prover during s...
A field element for each entity of the flavor. These entities represent the prover polynomials evalua...
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
static size_t row_skip_active_prefix_end(const ProverPolynomialsOrPartiallyEvaluatedMultivariates &polynomials)
static constexpr bool USE_SHORT_MONOMIALS
static constexpr size_t BATCHED_RELATION_PARTIAL_LENGTH
static constexpr size_t NUM_RELATIONS
BaseTranscript< Codec, HashFunction > Transcript
Relations_< FF > Relations
static constexpr size_t TRACE_OFFSET
A wrapper for Relations to expose methods used by the Sumcheck prover or verifier to add the contribu...
static void zero_univariates(auto &tuple)
Set all coefficients of Univariates to zero.
Definition utils.hpp:61
static constexpr void add_nested_tuples(Tuple &tuple_1, const Tuple &tuple_2)
Componentwise addition of nested tuples (tuples of tuples)
Definition utils.hpp:118
Imlementation of the Sumcheck prover round.
decltype(create_sumcheck_tuple_of_tuples_of_univariates< Relations >()) SumcheckTupleOfTuplesOfUnivariates
static constexpr size_t LIBRA_UNIVARIATES_LENGTH
static constexpr size_t BATCHED_RELATION_PARTIAL_LENGTH
The total algebraic degree of the Sumcheck relation as a polynomial in Prover Polynomials incremen...
std::conditional_t< Flavor::USE_SHORT_MONOMIALS, typename Flavor::template ProverUnivariates< 2 >, typename Flavor::ExtendedEdges > ExtendedEdges
static constexpr size_t MAX_PARTIAL_RELATION_LENGTH
The total algebraic degree of the Sumcheck relation as a polynomial in Prover Polynomials .
static void extend_and_batch_univariates(const TupleOfTuplesOfUnivariates &tuple, ExtendedUnivariate &result, const bb::GateSeparatorPolynomial< FF > &gate_separators)
Extend Univariates then sum them multiplying by the current -contributions.
static ExtendedUnivariate batch_over_relations(ContainerOverSubrelations &univariate_accumulators, const SubrelationSeparators &challenge, const bb::GateSeparatorPolynomial< FF > &gate_separators)
Given a tuple of tuples of extended per-relation contributions, and a challenge ,...
SumcheckRoundUnivariate compute_virtual_contribution(ProverPolynomialsOrPartiallyEvaluatedMultivariates &polynomials, const bb::RelationParameters< FF > &relation_parameters, const GateSeparatorPolynomial< FF > &gate_separator, const SubrelationSeparators &alphas)
size_t compute_effective_round_size(const ProverPolynomialsOrPartiallyEvaluatedMultivariates &multivariates) const
Compute the effective round size by finding the maximum end_index() across witness polynomials.
static void append_scan_range(std::vector< BlockOfContiguousRows > &ranges, const size_t start, const size_t end)
static void merge_contiguous_blocks(std::vector< BlockOfContiguousRows > &blocks)
std::vector< BlockOfContiguousRows > compute_row_skip_scan_ranges(ProverPolynomialsOrPartiallyEvaluatedMultivariates &polynomials, const size_t effective_round_size) const
SumcheckRoundUnivariate compute_univariate_with_row_skipping(ProverPolynomialsOrPartiallyEvaluatedMultivariates &polynomials, const bb::RelationParameters< FF > &relation_parameters, const bb::GateSeparatorPolynomial< FF > &gate_separators, const SubrelationSeparators alphas)
Return the evaluations of the univariate round polynomials at . Most likely, is around ....
SumcheckProverRound(size_t initial_round_size)
SumcheckRoundUnivariate compute_univariate_avm(ProverPolynomialsOrPartiallyEvaluatedMultivariates &polynomials, const bb::RelationParameters< FF > &relation_parameters, const bb::GateSeparatorPolynomial< FF > &gate_separators, const SubrelationSeparators &alphas)
A version of compute_univariate that is better optimized for the AVM.
SumcheckTupleOfTuplesOfUnivariates univariate_accumulators
SumcheckRoundUnivariate compute_univariate(ProverPolynomialsOrPartiallyEvaluatedMultivariates &polynomials, const bb::RelationParameters< FF > &relation_parameters, const bb::GateSeparatorPolynomial< FF > &gate_separators, const SubrelationSeparators &alphas)
Return the evaluations of the univariate round polynomials. Toggles between chunked computation (desi...
void extend_edges(ExtendedEdges &extended_edges, const ProverPolynomialsOrPartiallyEvaluatedMultivariates &multivariates, const size_t edge_idx)
To compute the round univariate in Round , the prover first computes the values of Honk polynomials ...
std::array< FF, Flavor::NUM_SUBRELATIONS - 1 > SubrelationSeparators
void accumulate_relation_univariates(SumcheckTupleOfTuplesOfUnivariates &univariate_accumulators, const auto &extended_edges, const bb::RelationParameters< FF > &relation_parameters, const FF &scaling_factor)
In Round , for a given point , calculate the contribution of each sub-relation to .
static SumcheckRoundUnivariate compute_libra_univariate(const ZKData &zk_sumcheck_data, size_t round_idx)
Compute Libra round univariate expressed given by the formula.
typename Flavor::FF FF
static constexpr size_t NUM_RELATIONS
Number of batched sub-relations in specified by Flavor.
static size_t round_up_to_even(const size_t value)
SumcheckRoundUnivariate compute_disabled_contribution(ProverPolynomialsOrPartiallyEvaluatedMultivariates &polynomials, const bb::RelationParameters< FF > &relation_parameters, const bb::GateSeparatorPolynomial< FF > &gate_separators, const SubrelationSeparators &alphas, const RowDisablingPolynomial< FF > row_disabling_polynomial)
Compute the disabled rows' contribution to the round univariate.
std::vector< BlockOfContiguousRows > compute_contiguous_round_size(ProverPolynomialsOrPartiallyEvaluatedMultivariates &polynomials)
Compute the number of unskippable rows we must iterate over.
typename Flavor::Relations Relations
size_t round_size
In Round , equals .
void accumulate_relation_univariates_public(SumcheckTupleOfTuplesOfUnivariates &univariate_accumulators, const auto &extended_edges, const bb::RelationParameters< FF > &relation_parameters, const FF &scaling_factor)
std::vector< std::array< FF, 3 > > round_univariate_evaluations
typename std::vector< FF > ClaimedLibraEvaluations
std::vector< Commitment > round_univariate_commitments
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 for Grumpkin: receive commitment and evaluations, defer per-round ver...
decltype(create_tuple_of_arrays_of_values< typename Flavor::Relations >()) TupleOfArraysOfValues
bool perform_final_verification(const FF &full_honk_purported_value)
Perform final verification for Grumpkin: check first round sum, populate Shplemini data,...
std::array< FF, Flavor::NUM_SUBRELATIONS - 1 > SubrelationSeparators
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.
std::vector< std::array< FF, 3 > > get_round_univariate_evaluations()
Get round univariate evaluations for Shplemini.
std::vector< Commitment > get_round_univariate_commitments()
Get round univariate commitments for Shplemini.
typename Flavor::AllValues ClaimedEvaluations
Implementation of the Sumcheck Verifier Round.
typename Flavor::Commitment Commitment
typename Flavor::Relations Relations
typename std::vector< FF > ClaimedLibraEvaluations
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 check_sum(bb::Univariate< FF, BATCHED_RELATION_PARTIAL_LENGTH > &univariate)
Check that the round target sum is correct.
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.
decltype(create_tuple_of_arrays_of_values< typename Flavor::Relations >()) TupleOfArraysOfValues
std::array< FF, Flavor::NUM_SUBRELATIONS - 1 > SubrelationSeparators
typename Flavor::AllValues ClaimedEvaluations
TupleOfArraysOfValues relation_evaluations
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....
typename Flavor::Transcript Transcript
void compute_next_target_sum(bb::Univariate< FF, BATCHED_RELATION_PARTIAL_LENGTH > &univariate, FF &round_challenge)
Compute the next target sum.
SumcheckVerifierRound(FF target_total_sum=0)
Fr & value_at(size_t i)
static Univariate zero()
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...
Check if the flavor has a static skip method to determine if accumulation of all relations can be ski...
The templates defined herein facilitate sharing the relation arithmetic between the prover and the ve...
ECCVMFlavor Flavor
Base class templates shared across Honk flavors.
constexpr size_t FF_COPY_COST
Definition thread.hpp:144
Entry point for Barretenberg command-line interface.
Definition api.hpp:5
size_t get_num_cpus()
Definition thread.cpp:33
constexpr void constexpr_for(F &&f)
Implements a loop using a compile-time iterator. Requires c++20. Implementation (and description) fro...
void parallel_for_heuristic(size_t num_points, const std::function< void(size_t, size_t, size_t)> &func, size_t heuristic_cost)
Split a loop into several loops running in parallel based on operations in 1 iteration.
Definition thread.cpp:171
void parallel_for(size_t num_iterations, const std::function< void(size_t)> &func)
Definition thread.cpp:111
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.
FF current_element() const
Computes the component at index current_element_idx in betas.
void partially_evaluate(FF challenge)
Partially evaluate the -polynomial at the new challenge and update .
FF partial_evaluation_result
The value obtained by partially evaluating one variable in the power polynomial at each round....
Container for parameters used by the grand product (permutation, lookup) Honk relations.
Polynomial for Sumcheck with disabled Rows.
Helper struct that describes a block of non-zero unskippable rows.
Shared chunk scheduler for dynamic work-stealing in the sumcheck prover's main loop.
std::optional< std::pair< size_t, size_t > > pop()
ChunkStealer(size_t start, size_t end, size_t rpc)
size_t thread_index
Definition thread.hpp:150
auto range(size_t size, size_t offset=0) const
Definition thread.hpp:152
This structure is created to contain various polynomials and constants required by ZK Sumcheck.
std::vector< Polynomial< FF > > libra_univariates