Skip to content

Commit 8aeddd2

Browse files
authored
Merge 6ed50ea into 7a2870f
2 parents 7a2870f + 6ed50ea commit 8aeddd2

25 files changed

+524
-390
lines changed

barretenberg/cpp/src/CMakeLists.txt

+2
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,8 @@ if(CMAKE_CXX_COMPILER_ID MATCHES "Clang")
2626
if(CMAKE_CXX_COMPILER_VERSION VERSION_GREATER_EQUAL 18)
2727
# We target clang18 and need this, eventually warning should be fixed or this will be unconditional.
2828
add_compile_options(-Wno-vla-cxx-extension)
29+
# This gets in the way of a valid designated initializer pattern (i.e. MyClass my_class{ .my_member = init_value })
30+
add_compile_options(-Wno-missing-field-initializers)
2931
endif()
3032
endif()
3133

Original file line numberDiff line numberDiff line change
@@ -0,0 +1,128 @@
1+
#pragma once
2+
#include "barretenberg/common/ref_vector.hpp"
3+
#include <optional>
4+
5+
namespace bb {
6+
7+
/**
8+
* @brief Logic to support batching opening claims for unshifted and shifted polynomials in Shplemini
9+
* @details Stores references to the commitments/evaluations of unshifted and shifted polynomials to be batched
10+
* opened via Shplemini. Aggregates the commitments and batching scalars for each batch into the corresponding
11+
* containers for Shplemini. Computes the batched evaluation. Contains logic for computing the per-batch scalars
12+
* used to batch each set of claims (see details below).
13+
* @note This class performs the actual batching of the evaluations but not of the commitments. The latter are
14+
* simply appended to a larger container, along with the scalars used to batch them. This is because Shplemini
15+
* is optimized to perform a single batch mul that includes all commitments from each stage of the PCS. See
16+
* description of ShpleminiVerifier for more details.
17+
*
18+
*/
19+
template <typename Curve> struct ClaimBatcher_ {
20+
using Fr = typename Curve::ScalarField;
21+
using Commitment = typename Curve::AffineElement;
22+
23+
struct Batch {
24+
RefVector<Commitment> commitments;
25+
RefVector<Fr> evaluations;
26+
// scalar used for batching the claims, excluding the power of batching challenge \rho
27+
Fr scalar = 0;
28+
};
29+
30+
std::optional<Batch> unshifted; // commitments and evaluations of unshifted polynomials
31+
std::optional<Batch> shifted; // commitments of to-be-shifted-by-1 polys, evals of their shifts
32+
std::optional<Batch> right_shifted_by_k; // commitments of to-be-right-shifted-by-k polys, evals of their shifts
33+
34+
Batch get_unshifted() { return (unshifted) ? *unshifted : Batch{}; }
35+
Batch get_shifted() { return (shifted) ? *shifted : Batch{}; }
36+
Batch get_right_shifted_by_k() { return (right_shifted_by_k) ? *right_shifted_by_k : Batch{}; }
37+
38+
size_t k_shift_magnitude = 0; // magnitude of right-shift-by-k (assumed even)
39+
40+
Fr get_unshifted_batch_scalar() const { return unshifted ? unshifted->scalar : Fr{ 0 }; }
41+
42+
/**
43+
* @brief Compute scalars used to batch each set of claims, excluding contribution from batching challenge \rho
44+
* @details Computes scalars s_0, s_1, s_2 given by
45+
* \f[
46+
* - s_0 = \left(\frac{1}{z-r} + \nu \times \frac{1}{z+r}\right) \f],
47+
* - s_1 = \frac{1}{r} \times \left(\frac{1}{z-r} - \nu \times \frac{1}{z+r}\right)
48+
* - s_2 = r^{k} \times \left(\frac{1}{z-r} + \nu \times \frac{1}{z+r}\right)
49+
* \f]
50+
* where the scalars used to batch the claims are given by
51+
* \f[
52+
* \left(
53+
* - s_0,
54+
* \ldots,
55+
* - \rho^{i+k-1} \times s_0,
56+
* - \rho^{i+k} \times s_1,
57+
* \ldots,
58+
* - \rho^{k+m-1} \times s_1
59+
* \right)
60+
* \f]
61+
*
62+
* @param inverse_vanishing_eval_pos 1/(z-r)
63+
* @param inverse_vanishing_eval_neg 1/(z+r)
64+
* @param nu_challenge ν (shplonk batching challenge)
65+
* @param r_challenge r (gemini evaluation challenge)
66+
*/
67+
void compute_scalars_for_each_batch(const Fr& inverse_vanishing_eval_pos,
68+
const Fr& inverse_vanishing_eval_neg,
69+
const Fr& nu_challenge,
70+
const Fr& r_challenge)
71+
{
72+
if (unshifted) {
73+
// (1/(z−r) + ν/(z+r))
74+
unshifted->scalar = inverse_vanishing_eval_pos + nu_challenge * inverse_vanishing_eval_neg;
75+
}
76+
if (shifted) {
77+
// r⁻¹ ⋅ (1/(z−r) − ν/(z+r))
78+
shifted->scalar =
79+
r_challenge.invert() * (inverse_vanishing_eval_pos - nu_challenge * inverse_vanishing_eval_neg);
80+
}
81+
if (right_shifted_by_k) {
82+
// r^k ⋅ (1/(z−r) + ν/(z+r))
83+
right_shifted_by_k->scalar = r_challenge.pow(k_shift_magnitude) *
84+
(inverse_vanishing_eval_pos + nu_challenge * inverse_vanishing_eval_neg);
85+
}
86+
}
87+
88+
/**
89+
* @brief Append the commitments and scalars from each batch of claims to the Shplemini batch mul input vectors;
90+
* update the batched evaluation and the running batching challenge (power of rho) in place.
91+
*
92+
* @param commitments commitment inputs to the single Shplemini batch mul
93+
* @param scalars scalar inputs to the single Shplemini batch mul
94+
* @param batched_evaluation running batched evaluation of the committed multilinear polynomials
95+
* @param rho multivariate batching challenge \rho
96+
* @param rho_power current power of \rho used in the batching scalar
97+
*/
98+
void update_batch_mul_inputs_and_batched_evaluation(std::vector<Commitment>& commitments,
99+
std::vector<Fr>& scalars,
100+
Fr& batched_evaluation,
101+
const Fr& rho,
102+
Fr& rho_power)
103+
{
104+
// Append the commitments/scalars from a given batch to the corresponding containers; update the batched
105+
// evaluation and the running batching challenge in place
106+
auto aggregate_claim_data_and_update_batched_evaluation = [&](const Batch& batch, Fr& rho_power) {
107+
for (auto [commitment, evaluation] : zip_view(batch.commitments, batch.evaluations)) {
108+
commitments.emplace_back(std::move(commitment));
109+
scalars.emplace_back(-batch.scalar * rho_power);
110+
batched_evaluation += evaluation * rho_power;
111+
rho_power *= rho;
112+
}
113+
};
114+
115+
// Incorporate the claim data from each batch of claims that is present
116+
if (unshifted) {
117+
aggregate_claim_data_and_update_batched_evaluation(*unshifted, rho_power);
118+
}
119+
if (shifted) {
120+
aggregate_claim_data_and_update_batched_evaluation(*shifted, rho_power);
121+
}
122+
if (right_shifted_by_k) {
123+
aggregate_claim_data_and_update_batched_evaluation(*right_shifted_by_k, rho_power);
124+
}
125+
}
126+
};
127+
128+
} // namespace bb

barretenberg/cpp/src/barretenberg/commitment_schemes/gemini/gemini.hpp

+42-16
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
#pragma once
22

33
#include "barretenberg/commitment_schemes/claim.hpp"
4+
#include "barretenberg/commitment_schemes/claim_batcher.hpp"
45
#include "barretenberg/polynomials/polynomial.hpp"
56
#include "barretenberg/transcript/transcript.hpp"
67

@@ -104,11 +105,12 @@ template <typename Curve> class GeminiProver_ {
104105
* @brief Class responsible for computation of the batched multilinear polynomials required by the Gemini protocol
105106
* @details Opening multivariate polynomials using Gemini requires the computation of three batched polynomials. The
106107
* first, here denoted A₀, is a linear combination of all polynomials to be opened. If we denote the linear
107-
* combinations (based on challenge rho) of the unshifted and the to-be-shited-by-1 polynomials by F and G,
108-
* respectively, then A₀ = F + G/X. This polynomial is "folded" in Gemini to produce d-1 univariate polynomials
109-
* Fold_i, i = 1, ..., d-1. The second and third are the partially evaluated batched polynomials A₀₊ = F + G/r, and
110-
* A₀₋ = F - G/r. These are required in order to prove the opening of shifted polynomials G_i/X from the commitments
111-
* to their unshifted counterparts G_i.
108+
* combinations (based on challenge rho) of the unshifted, to-be-shifted-by-1, and to-be-right-shifted-by-k
109+
* polynomials by F, G, and H respectively, then A₀ = F + G/X + X^k*H. (Note: 'k' is assumed even and thus a factor
110+
* (-1)^k in not needed for the evaluation at -r). This polynomial is "folded" in Gemini to produce d-1 univariate
111+
* polynomials Fold_i, i = 1, ..., d-1. The second and third are the partially evaluated batched polynomials A₀₊ = F
112+
* + G/r + r^K*H, and A₀₋ = F - G/r + r^K*H. These are required in order to prove the opening of shifted polynomials
113+
* G_i/X, X^k*H_i and from the commitments to their unshifted counterparts G_i and H_i.
112114
* @note TODO(https://github.com/AztecProtocol/barretenberg/issues/1223): There are certain operations herein that
113115
* could be made more efficient by e.g. reusing already initialized polynomials, possibly at the expense of clarity.
114116
*/
@@ -122,9 +124,13 @@ template <typename Curve> class GeminiProver_ {
122124

123125
RefVector<Polynomial> unshifted; // set of unshifted polynomials
124126
RefVector<Polynomial> to_be_shifted_by_one; // set of polynomials to be left shifted by 1
127+
RefVector<Polynomial> to_be_shifted_by_k; // set of polynomials to be right shifted by k
128+
129+
size_t k_shift_magnitude = 0; // magnitude of right-shift-by-k (assumed even)
125130

126131
Polynomial batched_unshifted; // linear combination of unshifted polynomials
127132
Polynomial batched_to_be_shifted_by_one; // linear combination of to-be-shifted polynomials
133+
Polynomial batched_to_be_shifted_by_k; // linear combination of to-be-shifted-by-k polynomials
128134

129135
public:
130136
PolynomialBatcher(const size_t full_batched_size)
@@ -135,10 +141,17 @@ template <typename Curve> class GeminiProver_ {
135141

136142
bool has_unshifted() const { return unshifted.size() > 0; }
137143
bool has_to_be_shifted_by_one() const { return to_be_shifted_by_one.size() > 0; }
144+
bool has_to_be_shifted_by_k() const { return to_be_shifted_by_k.size() > 0; }
138145

139146
// Set references to the polynomials to be batched
140147
void set_unshifted(RefVector<Polynomial> polynomials) { unshifted = polynomials; }
141148
void set_to_be_shifted_by_one(RefVector<Polynomial> polynomials) { to_be_shifted_by_one = polynomials; }
149+
void set_to_be_shifted_by_k(RefVector<Polynomial> polynomials, const size_t shift_magnitude)
150+
{
151+
ASSERT(k_shift_magnitude % 2 == 0); // k must be even for the formulas herein to be valid
152+
to_be_shifted_by_k = polynomials;
153+
k_shift_magnitude = shift_magnitude;
154+
}
142155

143156
// Initialize the random polynomial used to add randomness to the batched polynomials for ZK
144157
void set_random_polynomial(Polynomial&& random)
@@ -169,19 +182,26 @@ template <typename Curve> class GeminiProver_ {
169182

170183
// if necessary, add randomness to the full batched polynomial for ZK
171184
if (has_random_polynomial) {
172-
full_batched += random_polynomial;
185+
full_batched += random_polynomial; // A₀ += rand
173186
}
174187

175188
// compute the linear combination F of the unshifted polynomials
176189
if (has_unshifted()) {
177190
batch(batched_unshifted, unshifted);
178-
full_batched += batched_unshifted; // A₀ = F
191+
full_batched += batched_unshifted; // A₀ += F
179192
}
180193

181194
// compute the linear combination G of the to-be-shifted polynomials
182195
if (has_to_be_shifted_by_one()) {
183196
batch(batched_to_be_shifted_by_one, to_be_shifted_by_one);
184-
full_batched += batched_to_be_shifted_by_one.shifted(); // A₀ = F + G/X
197+
full_batched += batched_to_be_shifted_by_one.shifted(); // A₀ += G/X
198+
}
199+
200+
// compute the linear combination H of the to-be-shifted-by-k polynomials
201+
if (has_to_be_shifted_by_k()) {
202+
batched_to_be_shifted_by_k = Polynomial(full_batched_size - k_shift_magnitude, full_batched_size, 0);
203+
batch(batched_to_be_shifted_by_k, to_be_shifted_by_k);
204+
full_batched += batched_to_be_shifted_by_k.right_shifted(k_shift_magnitude); // A₀ += X^k * H
185205
}
186206

187207
return full_batched;
@@ -206,14 +226,20 @@ template <typename Curve> class GeminiProver_ {
206226
A_0_pos += batched_unshifted; // A₀₊ += F
207227
}
208228

229+
if (has_to_be_shifted_by_k()) {
230+
Fr r_pow_k = r_challenge.pow(k_shift_magnitude); // r^k
231+
batched_to_be_shifted_by_k *= r_pow_k;
232+
A_0_pos += batched_to_be_shifted_by_k; // A₀₊ += r^k * H
233+
}
234+
209235
Polynomial A_0_neg = A_0_pos;
210236

211237
if (has_to_be_shifted_by_one()) {
212238
Fr r_inv = r_challenge.invert(); // r⁻¹
213239
batched_to_be_shifted_by_one *= r_inv; // G = G/r
214240

215-
A_0_pos += batched_to_be_shifted_by_one; // A₀₊ = F + G/r
216-
A_0_neg -= batched_to_be_shifted_by_one; // A₀₋ = F - G/r
241+
A_0_pos += batched_to_be_shifted_by_one; // A₀₊ += G/r
242+
A_0_neg -= batched_to_be_shifted_by_one; // A₀₋ -= G/r
217243
}
218244

219245
return { A_0_pos, A_0_neg };
@@ -252,6 +278,7 @@ template <typename Curve> class GeminiVerifier_ {
252278
using Fr = typename Curve::ScalarField;
253279
using GroupElement = typename Curve::Element;
254280
using Commitment = typename Curve::AffineElement;
281+
using ClaimBatcher = ClaimBatcher_<Curve>;
255282

256283
public:
257284
/**
@@ -268,10 +295,7 @@ template <typename Curve> class GeminiVerifier_ {
268295
*/
269296
static std::vector<OpeningClaim<Curve>> reduce_verification(
270297
std::span<Fr> multilinear_challenge,
271-
RefSpan<Fr> unshifted_evaluations,
272-
RefSpan<Fr> shifted_evaluations,
273-
RefSpan<Commitment> unshifted_commitments,
274-
RefSpan<Commitment> to_be_shifted_commitments,
298+
ClaimBatcher& claim_batcher,
275299
auto& transcript,
276300
const std::vector<RefVector<Commitment>>& concatenation_group_commitments = {},
277301
RefSpan<Fr> concatenated_evaluations = {})
@@ -288,13 +312,15 @@ template <typename Curve> class GeminiVerifier_ {
288312

289313
Fr batched_evaluation = Fr(0);
290314
Fr batching_scalar = Fr(1);
291-
for (auto [eval, comm] : zip_view(unshifted_evaluations, unshifted_commitments)) {
315+
for (auto [eval, comm] :
316+
zip_view(claim_batcher.get_unshifted().evaluations, claim_batcher.get_unshifted().commitments)) {
292317
batched_evaluation += eval * batching_scalar;
293318
batched_commitment_unshifted += comm * batching_scalar;
294319
batching_scalar *= rho;
295320
}
296321

297-
for (auto [eval, comm] : zip_view(shifted_evaluations, to_be_shifted_commitments)) {
322+
for (auto [eval, comm] :
323+
zip_view(claim_batcher.get_shifted().evaluations, claim_batcher.get_shifted().commitments)) {
298324
batched_evaluation += eval * batching_scalar;
299325
batched_commitment_to_be_shifted += comm * batching_scalar;
300326
batching_scalar *= rho;

0 commit comments

Comments
 (0)