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: 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
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 diff.self_reduce();
271 }
272 bool out = (diff.get_value() == FF(0).get_value());
273 diff.assert_equal(FF(0));
274 return out;
275 } else {
276 return (diff == FF(0));
277 };
278 };
279
293 const FF& gemini_evaluation_challenge,
294 const std::vector<FF>& multilinear_challenge,
295 const FF& inner_product_eval_claim)
296 {
297
298 // Compute the evaluation of the vanishing polynomia Z_H(X) at X =
299 // gemini_evaluation_challenge
300 const FF vanishing_poly_eval = gemini_evaluation_challenge.pow(SUBGROUP_SIZE) - FF(1);
301
302 return check_consistency(libra_evaluations,
303 gemini_evaluation_challenge,
304 compute_challenge_polynomial_coeffs<Curve>(multilinear_challenge),
305 inner_product_eval_claim,
306 vanishing_poly_eval);
307 }
320 const std::array<FF, NUM_SMALL_IPA_EVALUATIONS>& small_ipa_evaluations,
321 const FF& evaluation_challenge,
322 const FF& evaluation_challenge_x,
323 const FF& batching_challenge_v,
324 const FF& inner_product_eval_claim)
325 {
326
327 // Compute the evaluation of the vanishing polynomia Z_H(X) at `evaluation_challenge`
328 const FF vanishing_poly_eval = evaluation_challenge.pow(SUBGROUP_SIZE) - FF(1);
329
330 return check_consistency(small_ipa_evaluations,
331 evaluation_challenge,
332 compute_eccvm_challenge_coeffs<Curve>(evaluation_challenge_x, batching_challenge_v),
333 inner_product_eval_claim,
334 vanishing_poly_eval);
335 }
336
342 static void handle_edge_cases(const FF& vanishing_poly_eval)
343 {
344 bool evaluation_challenge_in_small_subgroup = false;
345 if constexpr (Curve::is_stdlib_type) {
346 evaluation_challenge_in_small_subgroup = (vanishing_poly_eval.get_value() == FF(0).get_value());
347 } else {
348 evaluation_challenge_in_small_subgroup = (vanishing_poly_eval == FF(0));
349 }
350 // The probability of this event is negligible but it has to be processed correctly
351 if (evaluation_challenge_in_small_subgroup) {
352 throw_or_abort("SmallSubgroupIPA: Evaluation challenge is in the SmallSubgroup. This would cancel out the "
353 "hiding property of the commitment.");
354 }
355 }
368 const std::vector<FF>& coeffs, const FF& r, const FF& vanishing_poly_eval)
369 {
370 FF one{ 1 };
371 FF zero{ 0 };
372 if constexpr (Curve::is_stdlib_type) {
373 auto builder = r.get_context();
374 one.convert_constant_to_fixed_witness(builder);
375 zero.convert_constant_to_fixed_witness(builder);
376 }
377
378 // Construct the denominators of the Lagrange polynomials evaluated
379 // at r
380 std::array<FF, SUBGROUP_SIZE> denominators;
381 FF running_power = one;
382 for (size_t i = 0; i < SUBGROUP_SIZE; ++i) {
383 denominators[i] = running_power * r - one; // r * g^{-i} - 1
384 running_power *= Curve::subgroup_generator_inverse;
385 }
386
387 // Invert/Batch invert denominators
388 if constexpr (Curve::is_stdlib_type) {
389 std::transform(
390 denominators.begin(), denominators.end(), denominators.begin(), [](FF& d) { return d.invert(); });
391 } else {
392 FF::batch_invert(&denominators[0], SUBGROUP_SIZE);
393 }
394
395 // Construct the evaluation of the polynomial using its evaluations over H, Lagrange first evaluated at r,
396 // Lagrange last evaluated at r
397 FF numerator = vanishing_poly_eval * FF(SUBGROUP_SIZE).invert(); // (r^n - 1) / n
399 std::inner_product(coeffs.begin(), coeffs.end(), denominators.begin(), zero),
400 denominators[0],
401 denominators[SUBGROUP_SIZE - 1]
402 };
403 std::transform(
404 result.begin(), result.end(), result.begin(), [&](FF& denominator) { return denominator * numerator; });
405 return result;
406 }
407 static std::array<FF, NUM_SMALL_IPA_EVALUATIONS> evaluation_points(const FF& small_ipa_evaluation_challenge)
408 {
409 return compute_evaluation_points<FF>(small_ipa_evaluation_challenge, Curve::subgroup_generator);
410 }
412 {
413 return get_evaluation_labels(label_prefix);
414 };
415};
416
426template <typename Curve>
427static std::vector<typename Curve::ScalarField> compute_challenge_polynomial_coeffs(
428 const std::vector<typename Curve::ScalarField>& multivariate_challenge)
429{
430
431 using FF = typename Curve::ScalarField;
432 std::vector<FF> challenge_polynomial_lagrange(Curve::SUBGROUP_SIZE);
433 static constexpr size_t libra_univariates_length = Curve::LIBRA_UNIVARIATES_LENGTH;
434
435 const size_t challenge_poly_length = libra_univariates_length * multivariate_challenge.size() + 1;
436
437 FF one{ 1 };
438 FF zero{ 0 };
439 if constexpr (Curve::is_stdlib_type) {
440 auto builder = multivariate_challenge[0].get_context();
441 one.convert_constant_to_fixed_witness(builder);
442 zero.convert_constant_to_fixed_witness(builder);
443 }
444
445 challenge_polynomial_lagrange[0] = one;
446
447 // Populate the vector with the powers of the challenges
448 size_t round_idx = 0;
449 for (auto challenge : multivariate_challenge) {
450 size_t current_idx = 1 + libra_univariates_length * round_idx;
451 challenge_polynomial_lagrange[current_idx] = one;
452 for (size_t idx = current_idx + 1; idx < current_idx + libra_univariates_length; idx++) {
453 // Recursively compute the powers of the challenge up to the length of libra univariates
454 challenge_polynomial_lagrange[idx] = challenge_polynomial_lagrange[idx - 1] * challenge;
455 }
456 round_idx++;
457 }
458
459 // Ensure that the coefficients are padded with fixed witnesses obtained from 0
460 for (size_t idx = challenge_poly_length; idx < Curve::SUBGROUP_SIZE; idx++) {
461 challenge_polynomial_lagrange[idx] = zero;
462 }
463
464 return challenge_polynomial_lagrange;
465}
466
479template <typename Curve>
481 const typename Curve::ScalarField& evaluation_challenge_x, const typename Curve::ScalarField& batching_challenge_v)
482{
483 using FF = typename Curve::ScalarField;
484 std::vector<FF> coeffs_lagrange_basis(Curve::SUBGROUP_SIZE);
485 FF one{ 1 };
486 FF zero{ 0 };
487 if constexpr (Curve::is_stdlib_type) {
488 auto builder = evaluation_challenge_x.get_context();
489 one.convert_constant_to_fixed_witness(builder);
490 zero.convert_constant_to_fixed_witness(builder);
491 }
492 FF v_power = one;
493 for (size_t poly_idx = 0; poly_idx < NUM_TRANSLATION_EVALUATIONS; poly_idx++) {
494 const size_t start = NUM_DISABLED_ROWS_IN_SUMCHECK * poly_idx;
495 coeffs_lagrange_basis[start] = v_power;
496
497 for (size_t idx = start + 1; idx < start + NUM_DISABLED_ROWS_IN_SUMCHECK; idx++) {
498 coeffs_lagrange_basis[idx] = coeffs_lagrange_basis[idx - 1] * evaluation_challenge_x;
499 }
500
501 v_power *= batching_challenge_v;
502 }
503
504 static constexpr size_t challenge_poly_length = NUM_TRANSLATION_EVALUATIONS * NUM_DISABLED_ROWS_IN_SUMCHECK;
505
506 // Ensure that the coefficients are padded with fixed witnesses obtained from 0
507 for (size_t idx = challenge_poly_length; idx < Curve::SUBGROUP_SIZE; idx++) {
508 coeffs_lagrange_basis[idx] = zero;
509 }
510
511 return coeffs_lagrange_basis;
512}
513} // namespace bb
CommitmentKey object over a pairing group 𝔾₁.
curve::Grumpkin 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:73
static constexpr uint32_t LIBRA_UNIVARIATES_LENGTH
Definition grumpkin.hpp:85
static constexpr bool is_stdlib_type
Definition grumpkin.hpp:68
static constexpr ScalarField subgroup_generator_inverse
Definition grumpkin.hpp:80
static constexpr ScalarField subgroup_generator
Definition grumpkin.hpp:78
AluTraceBuilder builder
Definition alu.test.cpp:124
Entry point for Barretenberg command-line interface.
Definition api.hpp:5
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(C &coeffs) noexcept
Batch invert a collection of field elements using Montgomery's trick.
void throw_or_abort(std::string const &err)