Barretenberg
The ZK-SNARK library at the core of Aztec
Loading...
Searching...
No Matches
small_subgroup_ipa.hpp
Go to the documentation of this file.
1// === AUDIT STATUS ===
2// internal: { status: not started, auditors: [], date: YYYY-MM-DD }
3// external_1: { status: not started, auditors: [], date: YYYY-MM-DD }
4// external_2: { status: not started, auditors: [], date: YYYY-MM-DD }
5// =====================
6
7#pragma once
8
18
19#include <array>
20#include <vector>
21
22namespace bb {
69template <typename Flavor> class SmallSubgroupIPAProver {
70 using Curve = typename Flavor::Curve;
71 using FF = typename Curve::ScalarField;
72 // The size of a multiplicative subgroup in the ScalarField of a curve
73 static constexpr size_t SUBGROUP_SIZE = Curve::SUBGROUP_SIZE;
74
75 // A masking term of length 2 (degree 1) is required to mask [G] and G(r).
76 static constexpr size_t WITNESS_MASKING_TERM_LENGTH = 2;
78
79 // A masking term of length 3 (degree 2) is required to mask [A], A(r), and A(g*r)
80 static constexpr size_t GRAND_SUM_MASKING_TERM_LENGTH = 3;
82
83 // Length of the big sum identity polynomial C. It is equal to the length of the highest degree term X * F(X) * G(X)
85
86 // Length of the big sum identity quotient Q(X) = length(C) - length(Z_H) + 1
88
89 // The length of a random polynomial masking Prover's Sumcheck Univariates. In the case of BN254-based Flavors, we
90 // send the coefficients of the univariates, hence we choose these value to be the max sumcheck univariate length
91 // over Translator, Ultra, and Mega. In ECCVM, the Sumcheck prover will commit to its univariates, which reduces the
92 // required length from 23 to 3.
94 // Fixed generator of H
96
97 // Interpolation domain {1, g, \ldots, g^{SUBGROUP_SIZE - 1}} used by ECCVM
98 std::array<FF, SUBGROUP_SIZE> interpolation_domain;
99 // We use IFFT over BN254 scalar field
101
102 // Monomial coefficients of the concatenated polynomial extracted from ZKSumcheckData or TranslationData
104 // Lagrange coefficeints of the concatenated polynomial
106
107 // The polynomial obtained by concatenated powers of sumcheck challenges or the productcs of
108 // `evaluation_challenge_x` and `batching_challenge_v`
111
112 // Grand sum polynomial A(X)
115 std::array<FF, SUBGROUP_SIZE> grand_sum_lagrange_coeffs;
116
117 // The RHS of the key identity, denoted C(X) in the HackMD
119
120 // Quotient of the grand sum identity polynomial C(X) by the vanishing polynomial Z_H = X^{|H|} - 1
122
123 // Either "Translation:" or "Libra:".
124 std::string label_prefix;
125
128
129 public:
130 // The SmallSubgroupIPA claim
132
133 // Default constructor to initialize all polynomials, transcript, and commitment key.
136
137 // Construct prover from ZKSumcheckData. Used by all ZK Provers.
139 const std::vector<FF>& multivariate_challenge,
142 const typename Flavor::CommitmentKey& commitment_key);
143
144 // Construct prover from TranslationData. Used by ECCVMProver.
146 const FF evaluation_challenge_x,
147 const FF batching_challenge_v,
149 const typename Flavor::CommitmentKey& commitment_key);
150
151 void prove();
152
153 void compute_challenge_polynomial(const std::vector<FF>& multivariate_challenge);
154
155 void compute_eccvm_challenge_polynomial(const FF evaluation_challenge_x, const FF batching_challenge_v);
156
158
160
162 const std::array<FF, SUBGROUP_SIZE>& interpolation_domain, const EvaluationDomain<FF>& bn_evaluation_domain);
163
165
167 const std::vector<FF>& multivariate_challenge,
168 const size_t& log_circuit_size);
169
171
173 const std::array<FF, SUBGROUP_SIZE>& interpolation_domain,
175
176 // Getter to pass the witnesses to ShpleminiProver. Grand sum polynomial appears twice, because it is evaluated at 2
177 // points (and is small).
182 // Getters for test purposes
185
187 {
188 return compute_evaluation_points(small_ipa_evaluation_challenge, Curve::subgroup_generator);
189 }
190
195};
196
216template <typename Curve> class SmallSubgroupIPAVerifier {
217 using FF = typename Curve::ScalarField;
218
219 static constexpr size_t SUBGROUP_SIZE = Curve::SUBGROUP_SIZE;
220
221 // The verifier has to evaluate 3 polynomials on its own, namely, the challenge polynomial F, Lagrange first
222 // L_1, and Lagrange last L_{H}.
223 static constexpr size_t NUM_BARYCENTRIC_EVALUATIONS = 3;
224
225 // The length of a random polynomial masking Prover's Sumcheck Univariates. In the case of BN254-based Flavors, we
226 // send the coefficients of the univariates, hence we choose these value to be the max sumcheck univariate length
227 // over Translator, UltraZK, and MegaZK. In ECCVM, the Sumcheck prover will commit to its univariates, which reduces
228 // the required length from 23 to 3.
230
231 public:
244 static bool check_consistency(const std::array<FF, NUM_SMALL_IPA_EVALUATIONS>& small_ipa_evaluations,
245 const FF& small_ipa_eval_challenge,
246 const std::vector<FF>& challenge_polynomial,
247 const FF& inner_product_eval_claim,
248 const FF& vanishing_poly_eval)
249 {
250 // Check if Z_H(r) = 0.
251 handle_edge_cases(vanishing_poly_eval);
252 // Compute evaluations at r of F, Lagrange first, and Lagrange last for the fixed small subgroup
253 auto [challenge_poly, lagrange_first, lagrange_last] = compute_batched_barycentric_evaluations(
254 challenge_polynomial, small_ipa_eval_challenge, vanishing_poly_eval);
255
256 const FF& concatenated_at_r = small_ipa_evaluations[0];
257 const FF& grand_sum_shifted_eval = small_ipa_evaluations[1];
258 const FF& grand_sum_eval = small_ipa_evaluations[2];
259 const FF& quotient_eval = small_ipa_evaluations[3];
260
261 // Compute the evaluation of L_1(X) * A(X) + (X - 1/g) (A(gX) - A(X) - F(X) G(X)) + L_{|H|}(X)(A(X) - s) -
262 // Z_H(X) * Q(X)
263 FF diff = lagrange_first * grand_sum_eval;
264 diff += (small_ipa_eval_challenge - Curve::subgroup_generator_inverse) *
265 (grand_sum_shifted_eval - grand_sum_eval - concatenated_at_r * challenge_poly);
266 diff += lagrange_last * (grand_sum_eval - inner_product_eval_claim) - vanishing_poly_eval * quotient_eval;
267
268 if constexpr (Curve::is_stdlib_type) {
270 // TODO(https://github.com/AztecProtocol/barretenberg/issues/1197)
271 diff.self_reduce();
272 }
273 diff.assert_equal(FF(0));
274 // TODO(https://github.com/AztecProtocol/barretenberg/issues/1186).
275 // Insecure pattern.
276 return (diff.get_value() == FF(0).get_value());
277 } else {
278 return (diff == FF(0));
279 };
280 };
281
295 const FF& gemini_evaluation_challenge,
296 const std::vector<FF>& multilinear_challenge,
297 const FF& inner_product_eval_claim)
298 {
299
300 // Compute the evaluation of the vanishing polynomia Z_H(X) at X =
301 // gemini_evaluation_challenge
302 const FF vanishing_poly_eval = gemini_evaluation_challenge.pow(SUBGROUP_SIZE) - FF(1);
303
304 return check_consistency(libra_evaluations,
305 gemini_evaluation_challenge,
306 compute_challenge_polynomial_coeffs<Curve>(multilinear_challenge),
307 inner_product_eval_claim,
308 vanishing_poly_eval);
309 }
322 const std::array<FF, NUM_SMALL_IPA_EVALUATIONS>& small_ipa_evaluations,
323 const FF& evaluation_challenge,
324 const FF& evaluation_challenge_x,
325 const FF& batching_challenge_v,
326 const FF& inner_product_eval_claim)
327 {
328
329 // Compute the evaluation of the vanishing polynomia Z_H(X) at `evaluation_challenge`
330 const FF vanishing_poly_eval = evaluation_challenge.pow(SUBGROUP_SIZE) - FF(1);
331
332 return check_consistency(small_ipa_evaluations,
333 evaluation_challenge,
334 compute_eccvm_challenge_coeffs<Curve>(evaluation_challenge_x, batching_challenge_v),
335 inner_product_eval_claim,
336 vanishing_poly_eval);
337 }
338
344 static void handle_edge_cases(const FF& vanishing_poly_eval)
345 {
346
347 // TODO(https://github.com/AztecProtocol/barretenberg/issues/1194). Handle edge cases in PCS
348 // TODO(https://github.com/AztecProtocol/barretenberg/issues/1186). Insecure pattern.
349 bool evaluation_challenge_in_small_subgroup = false;
350 if constexpr (Curve::is_stdlib_type) {
351 evaluation_challenge_in_small_subgroup = (vanishing_poly_eval.get_value() == FF(0).get_value());
352 } else {
353 evaluation_challenge_in_small_subgroup = (vanishing_poly_eval == FF(0));
354 }
355 // The probability of this event is negligible but it has to be processed correctly
356 if (evaluation_challenge_in_small_subgroup) {
357 throw_or_abort("Evaluation challenge is in the SmallSubgroup.");
358 }
359 }
374 const std::vector<FF>& coeffs, const FF& r, const FF& vanishing_poly_eval)
375 {
376 FF one{ 1 };
377 FF zero{ 0 };
378 if constexpr (Curve::is_stdlib_type) {
379 auto builder = r.get_context();
380 one.convert_constant_to_fixed_witness(builder);
381 zero.convert_constant_to_fixed_witness(builder);
382 }
383
384 // Construct the denominators of the Lagrange polynomials evaluated
385 // at r
386 std::array<FF, SUBGROUP_SIZE> denominators;
387 FF running_power = one;
388 for (size_t i = 0; i < SUBGROUP_SIZE; ++i) {
389 denominators[i] = running_power * r - one; // r * g^{-i} - 1
390 running_power *= Curve::subgroup_generator_inverse;
391 }
392
393 // Invert/Batch invert denominators
394 if constexpr (Curve::is_stdlib_type) {
395 std::transform(
396 denominators.begin(), denominators.end(), denominators.begin(), [](FF& d) { return d.invert(); });
397 } else {
398 FF::batch_invert(&denominators[0], SUBGROUP_SIZE);
399 }
400
401 // Construct the evaluation of the polynomial using its evaluations over H, Lagrange first evaluated at r,
402 // Lagrange last evaluated at r
403 FF numerator = vanishing_poly_eval * FF(SUBGROUP_SIZE).invert(); // (r^n - 1) / n
405 std::inner_product(coeffs.begin(), coeffs.end(), denominators.begin(), zero),
406 denominators[0],
407 denominators[SUBGROUP_SIZE - 1]
408 };
409 std::transform(
410 result.begin(), result.end(), result.begin(), [&](FF& denominator) { return denominator * numerator; });
411 return result;
412 }
413 static std::array<FF, NUM_SMALL_IPA_EVALUATIONS> evaluation_points(const FF& small_ipa_evaluation_challenge)
414 {
415 return compute_evaluation_points<FF>(small_ipa_evaluation_challenge, Curve::subgroup_generator);
416 }
418 {
419 return get_evaluation_labels(label_prefix);
420 };
421};
422
432template <typename Curve>
433static std::vector<typename Curve::ScalarField> compute_challenge_polynomial_coeffs(
434 const std::vector<typename Curve::ScalarField>& multivariate_challenge)
435{
436
437 using FF = typename Curve::ScalarField;
438 std::vector<FF> challenge_polynomial_lagrange(Curve::SUBGROUP_SIZE);
439 static constexpr size_t libra_univariates_length = Curve::LIBRA_UNIVARIATES_LENGTH;
440
441 const size_t challenge_poly_length = libra_univariates_length * multivariate_challenge.size() + 1;
442
443 FF one{ 1 };
444 FF zero{ 0 };
445 if constexpr (Curve::is_stdlib_type) {
446 auto builder = multivariate_challenge[0].get_context();
447 one.convert_constant_to_fixed_witness(builder);
448 zero.convert_constant_to_fixed_witness(builder);
449 }
450
451 challenge_polynomial_lagrange[0] = one;
452
453 // Populate the vector with the powers of the challenges
454 size_t round_idx = 0;
455 for (auto challenge : multivariate_challenge) {
456 size_t current_idx = 1 + libra_univariates_length * round_idx;
457 challenge_polynomial_lagrange[current_idx] = one;
458 for (size_t idx = current_idx + 1; idx < current_idx + libra_univariates_length; idx++) {
459 // Recursively compute the powers of the challenge up to the length of libra univariates
460 challenge_polynomial_lagrange[idx] = challenge_polynomial_lagrange[idx - 1] * challenge;
461 }
462 round_idx++;
463 }
464
465 // Ensure that the coefficients are padded with fixed witnesses obtained from 0
466 for (size_t idx = challenge_poly_length; idx < Curve::SUBGROUP_SIZE; idx++) {
467 challenge_polynomial_lagrange[idx] = zero;
468 }
469
470 return challenge_polynomial_lagrange;
471}
472
485template <typename Curve>
487 const typename Curve::ScalarField& evaluation_challenge_x, const typename Curve::ScalarField& batching_challenge_v)
488{
489 using FF = typename Curve::ScalarField;
490 std::vector<FF> coeffs_lagrange_basis(Curve::SUBGROUP_SIZE);
491 FF one{ 1 };
492 FF zero{ 0 };
493 if constexpr (Curve::is_stdlib_type) {
494 auto builder = evaluation_challenge_x.get_context();
495 one.convert_constant_to_fixed_witness(builder);
496 zero.convert_constant_to_fixed_witness(builder);
497 }
498 FF v_power = one;
499 for (size_t poly_idx = 0; poly_idx < NUM_TRANSLATION_EVALUATIONS; poly_idx++) {
500 const size_t start = NUM_DISABLED_ROWS_IN_SUMCHECK * poly_idx;
501 coeffs_lagrange_basis[start] = v_power;
502
503 for (size_t idx = start + 1; idx < start + NUM_DISABLED_ROWS_IN_SUMCHECK; idx++) {
504 coeffs_lagrange_basis[idx] = coeffs_lagrange_basis[idx - 1] * evaluation_challenge_x;
505 }
506
507 v_power *= batching_challenge_v;
508 }
509
510 static constexpr size_t challenge_poly_length = NUM_TRANSLATION_EVALUATIONS * NUM_DISABLED_ROWS_IN_SUMCHECK;
511
512 // Ensure that the coefficients are padded with fixed witnesses obtained from 0
513 for (size_t idx = challenge_poly_length; idx < Curve::SUBGROUP_SIZE; idx++) {
514 coeffs_lagrange_basis[idx] = zero;
515 }
516
517 return coeffs_lagrange_basis;
518}
519} // namespace bb
CommitmentKey object over a pairing group 𝔾₁.
curve::BN254 Curve
Structured polynomial class that represents the coefficients 'a' of a_0 + a_1 x .....
A Curve-agnostic ZK protocol to prove inner products of small vectors.
std::shared_ptr< typename Flavor::Transcript > transcript
void compute_eccvm_challenge_polynomial(const FF evaluation_challenge_x, const FF batching_challenge_v)
Compute a (public) challenge polynomial from the evaluation and batching challenges.
const Polynomial< FF > & get_batched_polynomial() const
static constexpr size_t WITNESS_MASKING_TERM_LENGTH
typename Curve::ScalarField FF
std::array< bb::Polynomial< FF >, NUM_SMALL_IPA_EVALUATIONS > get_witness_polynomials() const
void compute_challenge_polynomial(const std::vector< FF > &multivariate_challenge)
Computes the challenge polynomial F(X) based on the provided multivariate challenges.
static constexpr size_t MASKED_CONCATENATED_WITNESS_LENGTH
static constexpr size_t QUOTIENT_LENGTH
static Polynomial< FF > compute_monomial_coefficients(std::span< FF > lagrange_coeffs, const std::array< FF, SUBGROUP_SIZE > &interpolation_domain, const EvaluationDomain< FF > &bn_evaluation_domain)
Given a vector of coefficients of a polynomial in the Lagrange basis over , compute its coefficients ...
static constexpr FF subgroup_generator
std::array< std::string, NUM_SMALL_IPA_EVALUATIONS > evaluation_labels()
std::array< FF, SUBGROUP_SIZE > interpolation_domain
std::array< FF, NUM_SMALL_IPA_EVALUATIONS > evaluation_points(const FF &small_ipa_evaluation_challenge)
void compute_grand_sum_polynomial()
Computes the grand sum polynomial .
static constexpr size_t MASKED_GRAND_SUM_LENGTH
static std::array< Polynomial< FF >, 2 > compute_lagrange_first_and_last(const std::array< FF, SUBGROUP_SIZE > &interpolation_domain, const EvaluationDomain< FF > &bn_evaluation_domain)
Compute monomial coefficients of the first and last Lagrange polynomials.
typename Flavor::Curve Curve
void compute_grand_sum_identity_quotient()
Efficiently compute the quotient of the grand sum identity polynomial by .
Polynomial< FF > grand_sum_polynomial_unmasked
static FF compute_claimed_inner_product(ZKSumcheckData< Flavor > &zk_sumcheck_data, const std::vector< FF > &multivariate_challenge, const size_t &log_circuit_size)
For test purposes: Compute the sum of the Libra constant term and Libra univariates evaluated at Sumc...
const Polynomial< FF > & get_challenge_polynomial() const
static constexpr size_t GRAND_SUM_MASKING_TERM_LENGTH
static constexpr size_t LIBRA_UNIVARIATES_LENGTH
void compute_grand_sum_identity_polynomial()
Compute , where is the fixed generator of .
Polynomial< FF > concatenated_lagrange_form
Polynomial< FF > grand_sum_identity_polynomial
Flavor::CommitmentKey commitment_key
Polynomial< FF > challenge_polynomial_lagrange
EvaluationDomain< FF > bn_evaluation_domain
void prove()
Compute the derived witnesses and and commit to them.
static constexpr size_t GRAND_SUM_IDENTITY_LENGTH
Polynomial< FF > grand_sum_identity_quotient
static constexpr size_t SUBGROUP_SIZE
FF compute_claimed_translation_inner_product(TranslationData< typename Flavor::Transcript > &translation_data)
For test purposes: compute the batched evaluation of the last NUM_DISABLED_ROWS_IN_SUMCHECK rows of t...
std::array< FF, SUBGROUP_SIZE > grand_sum_lagrange_coeffs
Verifies the consistency of polynomial evaluations provided by the the prover.
static std::array< FF, NUM_BARYCENTRIC_EVALUATIONS > compute_batched_barycentric_evaluations(const std::vector< FF > &coeffs, const FF &r, const FF &vanishing_poly_eval)
Efficient batch evaluation of the challenge polynomial, Lagrange first, and Lagrange last.
typename Curve::ScalarField FF
static constexpr size_t NUM_BARYCENTRIC_EVALUATIONS
static bool check_libra_evaluations_consistency(const std::array< FF, NUM_SMALL_IPA_EVALUATIONS > &libra_evaluations, const FF &gemini_evaluation_challenge, const std::vector< FF > &multilinear_challenge, const FF &inner_product_eval_claim)
A method required by ZKSumcheck. The challenge polynomial is concatenated from the powers of the sumc...
static void handle_edge_cases(const FF &vanishing_poly_eval)
Check if the random evaluation challenge is in the SmallSubgroup.
static constexpr size_t LIBRA_UNIVARIATES_LENGTH
static std::array< std::string, NUM_SMALL_IPA_EVALUATIONS > evaluation_labels(const std::string &label_prefix)
static bool check_consistency(const std::array< FF, NUM_SMALL_IPA_EVALUATIONS > &small_ipa_evaluations, const FF &small_ipa_eval_challenge, const std::vector< FF > &challenge_polynomial, const FF &inner_product_eval_claim, const FF &vanishing_poly_eval)
Generic consistency check agnostic to challenge polynomial .
static constexpr size_t SUBGROUP_SIZE
static bool check_eccvm_evaluations_consistency(const std::array< FF, NUM_SMALL_IPA_EVALUATIONS > &small_ipa_evaluations, const FF &evaluation_challenge, const FF &evaluation_challenge_x, const FF &batching_challenge_v, const FF &inner_product_eval_claim)
A method required for the verification Translation Evaluations in the ECCVMVerifier....
static std::array< FF, NUM_SMALL_IPA_EVALUATIONS > evaluation_points(const FF &small_ipa_evaluation_challenge)
A class designed to accept the ECCVM Transcript Polynomials, concatenate their masking terms in Lagra...
static constexpr size_t SUBGROUP_SIZE
Definition grumpkin.hpp:67
static constexpr uint32_t LIBRA_UNIVARIATES_LENGTH
Definition grumpkin.hpp:79
static constexpr bool is_stdlib_type
Definition grumpkin.hpp:62
static constexpr ScalarField subgroup_generator_inverse
Definition grumpkin.hpp:74
static constexpr ScalarField subgroup_generator
Definition grumpkin.hpp:72
AluTraceBuilder builder
Definition alu.test.cpp:123
Entry point for Barretenberg command-line interface.
typename Flavor::FF FF
std::array< std::string, NUM_SMALL_IPA_EVALUATIONS > get_evaluation_labels(const std::string &label_prefix)
Shared by Prover and Verifier. label_prefix is either Libra: or Translation:.
std::array< FF, NUM_SMALL_IPA_EVALUATIONS > compute_evaluation_points(const FF &small_ipa_evaluation_challenge, const FF &subgroup_generator)
The verification of Grand Sum Identity requires the evaluations G(r), A(g * r), A(r),...
std::vector< typename Curve::ScalarField > compute_eccvm_challenge_coeffs(const typename Curve::ScalarField &evaluation_challenge_x, const typename Curve::ScalarField &batching_challenge_v)
Denote and . Given an evaluation challenge and a batching challenge , compute the polynomial whose ...
constexpr decltype(auto) get(::tuplet::tuple< T... > &&t) noexcept
Definition tuple.hpp:13
This structure is created to contain various polynomials and constants required by ZK Sumcheck.
constexpr field invert() const noexcept
static void batch_invert(std::span< field > coeffs) noexcept
void throw_or_abort(std::string const &err)