Barretenberg
The ZK-SNARK library at the core of Aztec
Loading...
Searching...
No Matches
gemini.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
15
52namespace bb {
53
68namespace gemini {
77template <class Fr> inline std::vector<Fr> powers_of_rho(const Fr rho, const size_t num_powers)
78{
79 std::vector<Fr> rhos = { Fr(1), rho };
80 rhos.reserve(num_powers);
81 for (size_t j = 2; j < num_powers; j++) {
82 rhos.emplace_back(rhos[j - 1] * rho);
83 }
84 return rhos;
85};
86
94template <class Fr> inline std::vector<Fr> powers_of_evaluation_challenge(const Fr r, const size_t num_squares)
95{
96 std::vector<Fr> squares = { r };
97 squares.reserve(num_squares);
98 for (size_t j = 1; j < num_squares; j++) {
99 squares.emplace_back(squares[j - 1].sqr());
100 }
101 return squares;
102};
103} // namespace gemini
104
105template <typename Curve> class GeminiProver_ {
106 using Fr = typename Curve::ScalarField;
110
111 public:
127
128 size_t full_batched_size = 0; // size of the full batched polynomial (generally the circuit size)
129
130 Polynomial batched_unshifted; // linear combination of unshifted polynomials
131 Polynomial batched_to_be_shifted_by_one; // linear combination of to-be-shifted polynomials
132 Polynomial batched_interleaved; // linear combination of interleaved polynomials
133 // linear combination of the groups to be interleaved where polynomial i in the batched group is obtained by
134 // linearly combining the i-th polynomial in each group
136
137 public:
138 RefVector<Polynomial> unshifted; // set of unshifted polynomials
139 RefVector<Polynomial> to_be_shifted_by_one; // set of polynomials to be left shifted by 1
140 RefVector<Polynomial> interleaved; // the interleaved polynomials used in Translator
141 std::vector<RefVector<Polynomial>> groups_to_be_interleaved; // groups of polynomials to be interleaved
142
148
149 bool has_unshifted() const { return unshifted.size() > 0; }
150 bool has_to_be_shifted_by_one() const { return to_be_shifted_by_one.size() > 0; }
151 bool has_interleaved() const { return interleaved.size() > 0; }
152
153 // Set references to the polynomials to be batched
154 void set_unshifted(RefVector<Polynomial> polynomials) { unshifted = polynomials; }
156
158 {
159 // Ensure the Gemini subprotocol for interleaved polynomials operates correctly
160 if (groups[0].size() % 2 != 0) {
161 throw_or_abort("Group size must be even ");
162 }
163 interleaved = results;
165 }
166
173 Polynomial compute_batched(const Fr& challenge)
174 {
175 Fr running_scalar(1);
176 BB_BENCH_NAME("compute_batched");
177 // lambda for batching polynomials; updates the running scalar in place
178 auto batch = [&](Polynomial& batched, const RefVector<Polynomial>& polynomials_to_batch) {
179 for (auto& poly : polynomials_to_batch) {
180 batched.add_scaled(poly, running_scalar);
181 running_scalar *= challenge;
182 }
183 };
184
185 Polynomial full_batched(full_batched_size);
186
187 // compute the linear combination F of the unshifted polynomials
188 if (has_unshifted()) {
190 full_batched += batched_unshifted; // A₀ += F
191 }
192
193 // compute the linear combination G of the to-be-shifted polynomials
196 full_batched += batched_to_be_shifted_by_one.shifted(); // A₀ += G/X
197 }
198
199 // compute the linear combination of the interleaved polynomials and groups
200 if (has_interleaved()) {
202 for (size_t i = 0; i < groups_to_be_interleaved[0].size(); ++i) {
204 }
205
206 for (size_t i = 0; i < groups_to_be_interleaved.size(); ++i) {
207 batched_interleaved.add_scaled(interleaved[i], running_scalar);
208 // Use parallel chunking for the batching operations
209 parallel_for([this, running_scalar, i](const ThreadChunk& chunk) {
210 for (size_t j = 0; j < groups_to_be_interleaved[0].size(); ++j) {
211 batched_group[j].add_scaled_chunk(chunk, groups_to_be_interleaved[i][j], running_scalar);
212 }
213 });
214 running_scalar *= challenge;
215 }
216
217 full_batched += batched_interleaved;
218 }
219
220 return full_batched;
221 }
222
230 {
231 // Initialize A₀₊ and compute A₀₊ += F as necessary
232 Polynomial A_0_pos(full_batched_size); // A₀₊
233
234 if (has_unshifted()) {
235 A_0_pos += batched_unshifted; // A₀₊ += F
236 }
237
238 Polynomial A_0_neg = A_0_pos;
239
241 Fr r_inv = r_challenge.invert(); // r⁻¹
242 batched_to_be_shifted_by_one *= r_inv; // G = G/r
243
244 A_0_pos += batched_to_be_shifted_by_one; // A₀₊ += G/r
245 A_0_neg -= batched_to_be_shifted_by_one; // A₀₋ -= G/r
246 }
247
248 return { A_0_pos, A_0_neg };
249 };
262 {
263 Polynomial P_pos(batched_group[0]);
264 Polynomial P_neg(batched_group[0]);
265
266 Fr current_r_shift_pos = r_challenge;
267 Fr current_r_shift_neg = -r_challenge;
268 for (size_t i = 1; i < batched_group.size(); i++) {
269 P_pos.add_scaled(batched_group[i], current_r_shift_pos);
270 P_neg.add_scaled(batched_group[i], current_r_shift_neg);
271 current_r_shift_pos *= r_challenge;
272 current_r_shift_neg *= -r_challenge;
273 }
274
275 return { P_pos, P_neg };
276 }
277
278 size_t get_group_size() { return batched_group.size(); }
279 };
280
281 static std::vector<Polynomial> compute_fold_polynomials(const size_t log_n,
282 std::span<const Fr> multilinear_challenge,
283 const Polynomial& A_0,
284 const bool& has_zk = false);
285
287 const size_t log_n,
288 PolynomialBatcher& polynomial_batcher,
289 const Fr& r_challenge,
290 const std::vector<Polynomial>& batched_groups_to_be_concatenated = {});
291
293 Polynomial&& A_0_pos,
294 Polynomial&& A_0_neg,
295 std::vector<Polynomial>&& fold_polynomials,
296 const Fr& r_challenge);
297
298 template <typename Transcript>
299 static std::vector<Claim> prove(const Fr circuit_size,
300 PolynomialBatcher& polynomial_batcher,
301 std::span<Fr> multilinear_challenge,
302 const CommitmentKey<Curve>& commitment_key,
303 const std::shared_ptr<Transcript>& transcript,
304 bool has_zk = false);
305
306}; // namespace bb
307
311template <typename Curve> class GeminiVerifier_ {
312 using Fr = typename Curve::ScalarField;
314
315 public:
324 static std::vector<Commitment> get_fold_commitments([[maybe_unused]] const size_t virtual_log_n, auto& transcript)
325 {
326 std::vector<Commitment> fold_commitments;
327 fold_commitments.reserve(virtual_log_n - 1);
328 for (size_t i = 0; i < virtual_log_n - 1; ++i) {
329 const Commitment commitment =
330 transcript->template receive_from_prover<Commitment>("Gemini:FOLD_" + std::to_string(i + 1));
331 fold_commitments.emplace_back(commitment);
332 }
333 return fold_commitments;
334 }
335
345 static std::vector<Fr> get_gemini_evaluations(const size_t virtual_log_n, auto& transcript)
346 {
347 std::vector<Fr> gemini_evaluations;
348 gemini_evaluations.reserve(virtual_log_n);
349
350 for (size_t i = 1; i <= virtual_log_n; ++i) {
351 const Fr evaluation = transcript->template receive_from_prover<Fr>("Gemini:a_" + std::to_string(i));
352 gemini_evaluations.emplace_back(evaluation);
353 }
354 return gemini_evaluations;
355 }
356
391 static std::vector<Fr> compute_fold_pos_evaluations(std::span<const Fr> padding_indicator_array,
392 const Fr& batched_evaluation,
393 std::span<const Fr> evaluation_point, // size = virtual_log_n
394 std::span<const Fr> challenge_powers, // size = virtual_log_n
395 std::span<const Fr> fold_neg_evals, // size = virtual_log_n
396 Fr p_neg = Fr(0))
397 {
398 const size_t virtual_log_n = evaluation_point.size();
399
400 std::vector<Fr> evals(fold_neg_evals.begin(), fold_neg_evals.end());
401
402 Fr eval_pos_prev = batched_evaluation;
403
404 Fr zero{ 0 };
405 if constexpr (Curve::is_stdlib_type) {
406 zero.convert_constant_to_fixed_witness(fold_neg_evals[0].get_context());
407 }
408
409 std::vector<Fr> fold_pos_evaluations;
410 fold_pos_evaluations.reserve(virtual_log_n);
411
412 // Add the contribution of P-((-r)ˢ) to get A_0(-r), which is 0 if there are no interleaved polynomials
413 evals[0] += p_neg;
414 // Solve the sequence of linear equations
415 for (size_t l = virtual_log_n; l != 0; --l) {
416 // Get r²⁽ˡ⁻¹⁾
417 const Fr& challenge_power = challenge_powers[l - 1];
418 // Get uₗ₋₁
419 const Fr& u = evaluation_point[l - 1];
420 const Fr& eval_neg = evals[l - 1];
421 // Get A₍ₗ₋₁₎(−r²⁽ˡ⁻¹⁾)
422 // Compute the numerator
423 Fr eval_pos = ((challenge_power * eval_pos_prev * 2) - eval_neg * (challenge_power * (Fr(1) - u) - u));
424 // Divide by the denominator
425 eval_pos *= (challenge_power * (Fr(1) - u) + u).invert();
426
427 // If current index is bigger than log_n, we propagate `batched_evaluation` to the next
428 // round. Otherwise, current `eval_pos` A₍ₗ₋₁₎(−r²⁽ˡ⁻¹⁾) becomes `eval_pos_prev` in the round l-2.
429 eval_pos_prev =
430 padding_indicator_array[l - 1] * eval_pos + (Fr{ 1 } - padding_indicator_array[l - 1]) * eval_pos_prev;
431 // If current index is bigger than log_n, we emplace 0, which is later multiplied against
432 // Commitment::one().
433 fold_pos_evaluations.emplace_back(padding_indicator_array[l - 1] * eval_pos_prev);
434 }
435
436 std::reverse(fold_pos_evaluations.begin(), fold_pos_evaluations.end());
437
438 return fold_pos_evaluations;
439 }
440};
441
442} // namespace bb
#define BB_BENCH_NAME(name)
Definition bb_bench.hpp:219
CommitmentKey object over a pairing group 𝔾₁.
Class responsible for computation of the batched multilinear polynomials required by the Gemini proto...
Definition gemini.hpp:126
std::pair< Polynomial, Polynomial > compute_partially_evaluated_interleaved_polynomial(const Fr &r_challenge)
Compute the partially evaluated polynomials P₊(X, r) and P₋(X, -r)
Definition gemini.hpp:261
void set_to_be_shifted_by_one(RefVector< Polynomial > polynomials)
Definition gemini.hpp:155
void set_interleaved(RefVector< Polynomial > results, std::vector< RefVector< Polynomial > > groups)
Definition gemini.hpp:157
RefVector< Polynomial > interleaved
Definition gemini.hpp:140
std::vector< RefVector< Polynomial > > groups_to_be_interleaved
Definition gemini.hpp:141
void set_unshifted(RefVector< Polynomial > polynomials)
Definition gemini.hpp:154
std::vector< Polynomial > batched_group
Definition gemini.hpp:135
Polynomial compute_batched(const Fr &challenge)
Compute batched polynomial A₀ = F + G/X as the linear combination of all polynomials to be opened.
Definition gemini.hpp:173
RefVector< Polynomial > to_be_shifted_by_one
Definition gemini.hpp:139
std::pair< Polynomial, Polynomial > compute_partially_evaluated_batch_polynomials(const Fr &r_challenge)
Compute partially evaluated batched polynomials A₀(X, r) = A₀₊ = F + G/r, A₀(X, -r) = A₀₋ = F - G/r.
Definition gemini.hpp:229
RefVector< Polynomial > unshifted
Definition gemini.hpp:138
PolynomialBatcher(const size_t full_batched_size)
Definition gemini.hpp:143
bb::Polynomial< Fr > Polynomial
Definition gemini.hpp:108
static std::vector< Claim > construct_univariate_opening_claims(const size_t log_n, Polynomial &&A_0_pos, Polynomial &&A_0_neg, std::vector< Polynomial > &&fold_polynomials, const Fr &r_challenge)
Computes/aggragates d+1 univariate polynomial opening claims of the form {polynomial,...
typename Curve::ScalarField Fr
Definition gemini.hpp:106
static std::vector< Claim > prove(const Fr circuit_size, PolynomialBatcher &polynomial_batcher, std::span< Fr > multilinear_challenge, const CommitmentKey< Curve > &commitment_key, const std::shared_ptr< Transcript > &transcript, bool has_zk=false)
static std::pair< Polynomial, Polynomial > compute_partially_evaluated_batch_polynomials(const size_t log_n, PolynomialBatcher &polynomial_batcher, const Fr &r_challenge, const std::vector< Polynomial > &batched_groups_to_be_concatenated={})
typename Curve::AffineElement Commitment
Definition gemini.hpp:107
static std::vector< Polynomial > compute_fold_polynomials(const size_t log_n, std::span< const Fr > multilinear_challenge, const Polynomial &A_0, const bool &has_zk=false)
Computes d-1 fold polynomials Fold_i, i = 1, ..., d-1.
Gemini Verifier utility methods used by ShpleminiVerifier.
Definition gemini.hpp:311
typename Curve::ScalarField Fr
Definition gemini.hpp:312
static std::vector< Commitment > get_fold_commitments(const size_t virtual_log_n, auto &transcript)
Receive the fold commitments from the prover. This method is used by Shplemini where padding may be e...
Definition gemini.hpp:324
static std::vector< Fr > get_gemini_evaluations(const size_t virtual_log_n, auto &transcript)
Receive the fold evaluations from the prover. This method is used by Shplemini where padding may be e...
Definition gemini.hpp:345
typename Curve::AffineElement Commitment
Definition gemini.hpp:313
Structured polynomial class that represents the coefficients 'a' of a_0 + a_1 x .....
Polynomial shifted() const
Returns a Polynomial the left-shift of self.
void add_scaled(PolynomialSpan< const Fr > other, Fr scaling_factor) &
adds the polynomial q(X) 'other', multiplied by a scaling factor.
Polynomial p and an opening pair (r,v) such that p(r) = v.
Definition claim.hpp:34
A template class for a reference vector. Behaves as if std::vector<T&> was possible.
static constexpr bool is_stdlib_type
Definition grumpkin.hpp:69
typename Group::affine_element AffineElement
Definition grumpkin.hpp:63
std::vector< Fr > powers_of_evaluation_challenge(const Fr r, const size_t num_squares)
Compute squares of folding challenge r.
Definition gemini.hpp:94
std::vector< Fr > powers_of_rho(const Fr rho, const size_t num_powers)
Compute powers of challenge ρ
Definition gemini.hpp:77
Entry point for Barretenberg command-line interface.
Definition api.hpp:5
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)
Curve::ScalarField Fr
constexpr field invert() const noexcept
void throw_or_abort(std::string const &err)