Barretenberg
The ZK-SNARK library at the core of Aztec
Loading...
Searching...
No Matches
small_subgroup_ipa.cpp
Go to the documentation of this file.
1// === AUDIT STATUS ===
2// internal: { status: Planned, auditors: [Khashayar], commit: }
3// external_1: { status: not started, auditors: [], commit: }
4// external_2: { status: not started, auditors: [], commit: }
5// =====================
6
23
24#include <array>
25#include <type_traits>
26#include <vector>
27
28namespace bb {
29
30// Default constructor to initialize all common members.
31template <typename Flavor>
33 typename Flavor::CommitmentKey commitment_key)
34 : interpolation_domain{}
35 , concatenated_polynomial(MASKED_CONCATENATED_WITNESS_LENGTH)
36 , concatenated_lagrange_form(SUBGROUP_SIZE)
37 , challenge_polynomial(SUBGROUP_SIZE)
38 , challenge_polynomial_lagrange(SUBGROUP_SIZE)
39 , grand_sum_polynomial_unmasked(SUBGROUP_SIZE)
40 , grand_sum_polynomial(MASKED_GRAND_SUM_LENGTH)
41 , grand_sum_identity_polynomial(GRAND_SUM_IDENTITY_LENGTH)
42 , grand_sum_identity_quotient(QUOTIENT_LENGTH)
43 , transcript(transcript)
44{
45 // Reallocate the commitment key if necessary. This is an edge case with SmallSubgroupIPA since it has
46 // polynomials that may exceed the circuit size.
49 };
50 this->commitment_key = commitment_key;
51};
52
60template <typename Flavor>
62 const std::vector<FF>& multivariate_challenge,
63 const FF claimed_inner_product,
65 const typename Flavor::CommitmentKey& commitment_key)
66 : SmallSubgroupIPAProver(transcript, commitment_key)
67{
68 this->claimed_inner_product = claimed_inner_product;
73
74 label_prefix = "Libra:";
75 // Extract the evaluation domain computed by ZKSumcheckData
78 }
79
80 // Construct the challenge polynomial in Lagrange basis, compute its monomial coefficients
81 compute_challenge_polynomial(multivariate_challenge);
82}
83
95template <typename Flavor>
97 const FF evaluation_challenge_x,
98 const FF batching_challenge_v,
100 const typename Flavor::CommitmentKey& commitment_key)
101 : SmallSubgroupIPAProver(transcript, commitment_key)
102
103{
104 // TranslationData is Grumpkin-specific
106 label_prefix = "Translation:";
111
112 // Construct the challenge polynomial in Lagrange basis, compute its monomial coefficients
113 compute_eccvm_challenge_polynomial(evaluation_challenge_x, batching_challenge_v);
114
115 // The prover computes the inner product of the challenge polynomial and the concatenation of
116 // the masking terms. This value is used to "denoise" the masked batched evaluation of
117 // `translation_polynomials` contained in `translation_data`.
119 transcript->send_to_verifier(label_prefix + "masking_term_eval", claimed_inner_product);
120 }
121}
122
155template <typename Flavor> void SmallSubgroupIPAProver<Flavor>::prove()
156{
157
158 // Construct unmasked grand sum polynomial in Lagrange basis, compute its monomial coefficients and mask it
159 compute_grand_sum_polynomial();
160
161 // Send masked commitment [A + Z_H * R] to the verifier, where R is of degree 2
162 witness_commitments[1] = commitment_key.commit(grand_sum_polynomial);
163 transcript->send_to_verifier(label_prefix + "grand_sum_commitment", witness_commitments[1]);
164
165 // Compute C(X)
166 compute_grand_sum_identity_polynomial();
167
168 // Compute Q(X)
169 compute_grand_sum_identity_quotient();
170
171 // Send commitment [Q] to the verifier
172 witness_commitments[2] = commitment_key.commit(grand_sum_identity_quotient);
173 transcript->send_to_verifier(label_prefix + "quotient_commitment", witness_commitments[2]);
174}
175
200template <typename Flavor>
201void SmallSubgroupIPAProver<Flavor>::compute_challenge_polynomial(const std::vector<FF>& multivariate_challenge)
202{
203 std::vector<FF> coeffs_lagrange_basis =
204 compute_challenge_polynomial_coeffs<typename Flavor::Curve>(multivariate_challenge);
205
206 challenge_polynomial_lagrange = Polynomial<FF>(coeffs_lagrange_basis);
207
208 // Compute monomial coefficients
209 challenge_polynomial =
210 compute_monomial_coefficients(coeffs_lagrange_basis, interpolation_domain, bn_evaluation_domain);
211}
221template <typename Flavor>
223 const FF batching_challenge_v)
224{
225
226 std::vector<FF> coeffs_lagrange_basis = compute_eccvm_challenge_coeffs<typename Flavor::Curve>(
227 evaluation_challenge_x, batching_challenge_v, NUM_TRANSLATION_EVALUATIONS, NUM_DISABLED_ROWS_IN_SUMCHECK);
228
229 challenge_polynomial_lagrange = Polynomial<FF>(coeffs_lagrange_basis);
230
231 // Compute monomial coefficients
232 challenge_polynomial = Polynomial<FF>(interpolation_domain, coeffs_lagrange_basis, SUBGROUP_SIZE);
233}
252{
253 // The masking accumulation below (`+=`) relies on the constructor's zero-initialization of
254 // grand_sum_polynomial, so this must run exactly once per instance.
255 grand_sum_lagrange_coeffs[0] = 0;
256
257 // Compute the grand sum coefficients recursively
258 for (size_t idx = 1; idx < SUBGROUP_SIZE; idx++) {
259 size_t prev_idx = idx - 1;
260 grand_sum_lagrange_coeffs[idx] =
261 grand_sum_lagrange_coeffs[prev_idx] +
262 challenge_polynomial_lagrange.at(prev_idx) * concatenated_lagrange_form.at(prev_idx);
263 };
264
265 // Get the coefficients in the monomial basis
266 grand_sum_polynomial_unmasked =
267 compute_monomial_coefficients(grand_sum_lagrange_coeffs, interpolation_domain, bn_evaluation_domain);
268
269 // Generate random masking_term of degree 2
271
272 grand_sum_polynomial += grand_sum_polynomial_unmasked;
273 // Since Z_H(X) = X^|H| - 1, its product with the masking term R(X) is given by X^{H}*R(X) - R(X). Therefore
274 // to mask A, we subtract the coefficients of R from the first GRAND_SUM_MASKING_TERM_LENGTH coefficients
275 // of A and by set the coefficients A_{i+SUBGROUP_SIZE} to be equal to R_i
276 for (size_t idx = 0; idx < GRAND_SUM_MASKING_TERM_LENGTH; idx++) {
277 grand_sum_polynomial.at(idx) -= masking_term.value_at(idx);
278 grand_sum_polynomial.at(idx + SUBGROUP_SIZE) += masking_term.value_at(idx);
279 }
280};
281
288{
289 // The accumulations below (`+=` / `-=`) rely on the constructor's zero-initialization of
290 // grand_sum_identity_polynomial, so this must run exactly once per instance.
291 // Compute shifted grand sum polynomial A(gX)
292 Polynomial<FF> shifted_grand_sum(MASKED_GRAND_SUM_LENGTH);
293
294 for (size_t idx = 0; idx < MASKED_GRAND_SUM_LENGTH; idx++) {
295 shifted_grand_sum.at(idx) = grand_sum_polynomial.at(idx) * interpolation_domain[idx % SUBGROUP_SIZE];
296 }
297
298 const auto& [lagrange_first, lagrange_last] =
299 compute_lagrange_first_and_last(interpolation_domain, bn_evaluation_domain);
300
301 // Compute -F(X)*G(X), the negated product of challenge_polynomial and concatenated_polynomial
302 for (size_t i = 0; i < MASKED_CONCATENATED_WITNESS_LENGTH; ++i) {
303 for (size_t j = 0; j < SUBGROUP_SIZE; ++j) {
304 grand_sum_identity_polynomial.at(i + j) -= concatenated_polynomial.at(i) * challenge_polynomial.at(j);
305 }
306 }
307
308 // Compute - F(X) * G(X) + A(gX) - A(X)
309 for (size_t idx = 0; idx < MASKED_GRAND_SUM_LENGTH; idx++) {
310 grand_sum_identity_polynomial.at(idx) += shifted_grand_sum.at(idx) - grand_sum_polynomial.at(idx);
311 }
312
313 // Multiply -F(X) * G(X) + A(gX) - A(X) by X - g^{-1}:
314 // 1. Multiply by X
315 for (size_t idx = GRAND_SUM_IDENTITY_LENGTH - 1; idx > 0; idx--) {
316 grand_sum_identity_polynomial.at(idx) = grand_sum_identity_polynomial.at(idx - 1);
317 }
318 grand_sum_identity_polynomial.at(0) = FF(0);
319 // 2. Subtract g^{-1}(A(gX) - A(X) - F(X) * G(X)).
320 for (size_t idx = 0; idx < GRAND_SUM_IDENTITY_LENGTH - 1; idx++) {
321 grand_sum_identity_polynomial.at(idx) -=
322 grand_sum_identity_polynomial.at(idx + 1) * interpolation_domain[SUBGROUP_SIZE - 1];
323 }
324
325 // Add (L_1 + L_{|H|}) * A(X) to the result
326 for (size_t i = 0; i < MASKED_GRAND_SUM_LENGTH; ++i) {
327 for (size_t j = 0; j < SUBGROUP_SIZE; ++j) {
328 grand_sum_identity_polynomial.at(i + j) +=
329 grand_sum_polynomial.at(i) * (lagrange_first.at(j) + lagrange_last.at(j));
330 }
331 }
332 // Subtract L_{|H|} * s
333 for (size_t idx = 0; idx < SUBGROUP_SIZE; idx++) {
334 grand_sum_identity_polynomial.at(idx) -= lagrange_last.at(idx) * claimed_inner_product;
335 }
336}
351template <typename Flavor>
353 Flavor>::compute_lagrange_first_and_last(const std::array<FF, SUBGROUP_SIZE>& interpolation_domain,
354 const EvaluationDomain<FF>& bn_evaluation_domain)
355{
356 // Compute the monomial coefficients of L_1
357 std::array<FF, SUBGROUP_SIZE> lagrange_coeffs;
358 lagrange_coeffs[0] = FF(1);
359 for (size_t idx = 1; idx < SUBGROUP_SIZE; idx++) {
360 lagrange_coeffs[idx] = FF(0);
361 }
362
363 Polynomial<FF> lagrange_first_monomial =
364 compute_monomial_coefficients(lagrange_coeffs, interpolation_domain, bn_evaluation_domain);
365
366 // Compute the monomial coefficients of L_{|H|}, the last Lagrange polynomial
367 lagrange_coeffs[0] = FF(0);
368 lagrange_coeffs[SUBGROUP_SIZE - 1] = FF(1);
369
370 Polynomial<FF> lagrange_last_monomial =
371 compute_monomial_coefficients(lagrange_coeffs, interpolation_domain, bn_evaluation_domain);
372
373 return { lagrange_first_monomial, lagrange_last_monomial };
374}
375
380{
381
382 auto remainder = grand_sum_identity_polynomial;
383 for (size_t idx = GRAND_SUM_IDENTITY_LENGTH - 1; idx >= SUBGROUP_SIZE; idx--) {
384 grand_sum_identity_quotient.at(idx - SUBGROUP_SIZE) = remainder.at(idx);
385 remainder.at(idx - SUBGROUP_SIZE) += remainder.at(idx);
386 }
387}
388
397template <typename Flavor>
399 ZKSumcheckData<Flavor>& zk_sumcheck_data,
400 const std::vector<FF>& multivariate_challenge,
401 const size_t& log_circuit_size)
402{
403 const FF libra_challenge_inv = zk_sumcheck_data.libra_challenge.invert();
404 // Compute claimed inner product similarly to the SumcheckProver
405 FF claimed_inner_product = FF{ 0 };
406 size_t idx = 0;
407 for (const auto& univariate : zk_sumcheck_data.libra_univariates) {
408 claimed_inner_product += univariate.evaluate(multivariate_challenge[idx]);
409 idx++;
410 }
411 // Libra univariates are multiplied by the Libra challenge in setup_auxiliary_data(), which needs to be undone.
412 claimed_inner_product *= libra_challenge_inv / FF(1 << (log_circuit_size - 1));
413 claimed_inner_product += zk_sumcheck_data.constant_term;
414 return claimed_inner_product;
415}
416
425template <typename Flavor>
428{
429 FF claimed_inner_product{ 0 };
431 for (size_t idx = 0; idx < SUBGROUP_SIZE; idx++) {
432 claimed_inner_product +=
433 translation_data.concatenated_polynomial_lagrange.at(idx) * challenge_polynomial_lagrange.at(idx);
434 }
435 }
436 return claimed_inner_product;
437}
438
445template <typename Flavor>
447 std::span<FF> lagrange_coeffs,
448 const std::array<FF, SUBGROUP_SIZE>& interpolation_domain,
449 const EvaluationDomain<FF>& bn_evaluation_domain)
450{
451 using FF = typename Flavor::Curve::ScalarField;
453 return Polynomial<FF>(interpolation_domain, lagrange_coeffs, SUBGROUP_SIZE);
454 } else {
455 std::vector<FF> lagrange_last_ifft(SUBGROUP_SIZE);
456 polynomial_arithmetic::ifft<FF>(lagrange_coeffs.data(), lagrange_last_ifft.data(), bn_evaluation_domain);
457 return Polynomial<FF>(lagrange_last_ifft);
458 }
459}
460
461// Instantiate with ZK Flavors
469#ifdef STARKNET_GARAGA_FLAVORS
471#endif
472
473// Instantiations used in tests
476
477} // namespace bb
bb::field< bb::Bn254FrParams > FF
Definition field.cpp:24
CommitmentKey object over a pairing group 𝔾₁.
bb::CommitmentKey< Curve > CommitmentKey
Fr & at(size_t index)
Our mutable accessor, unlike operator[]. We abuse precedent a bit to differentiate at() and operator[...
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.
typename Curve::ScalarField FF
void compute_challenge_polynomial(const std::vector< FF > &multivariate_challenge)
Computes the challenge polynomial F(X) based on the provided multivariate challenges.
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 ...
std::array< FF, SUBGROUP_SIZE > interpolation_domain
void compute_grand_sum_polynomial()
Computes the grand sum polynomial .
static constexpr size_t MASKED_GRAND_SUM_LENGTH
void compute_grand_sum_identity_quotient()
Efficiently compute the quotient of the grand sum identity polynomial by .
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...
void compute_grand_sum_identity_polynomial()
Compute , where is the fixed generator of .
std::array< Commitment, NUM_SMALL_IPA_COMMITMENTS > witness_commitments
Polynomial< FF > concatenated_lagrange_form
SmallSubgroupIPAProver(const std::shared_ptr< typename Flavor::Transcript > &transcript, typename Flavor::CommitmentKey commitment_key)
Flavor::CommitmentKey commitment_key
EvaluationDomain< FF > bn_evaluation_domain
void prove()
Compute the derived witnesses and and commit to them.
FF compute_claimed_translation_inner_product(TranslationData< typename Flavor::Transcript > &translation_data)
Compute the batched evaluation of the last NUM_DISABLED_ROWS_IN_SUMCHECK rows of the ECCVM transcript...
A class designed to accept the ECCVM Transcript Polynomials, concatenate their masking terms in Lagra...
std::array< FF, SUBGROUP_SIZE > interpolation_domain
static Univariate get_random()
Entry point for Barretenberg command-line interface.
Definition api.hpp:5
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.
Polynomial< FF > libra_concatenated_monomial_form
std::vector< Polynomial< FF > > libra_univariates
Commitment libra_concatenation_commitment
Polynomial< FF > libra_concatenated_lagrange_form
EvaluationDomain< FF > bn_evaluation_domain
std::array< FF, SUBGROUP_SIZE > interpolation_domain