@@ -100,14 +100,133 @@ template <typename Curve> class GeminiProver_ {
100
100
using Claim = ProverOpeningClaim<Curve>;
101
101
102
102
public:
103
+ /* *
104
+ * @brief Class responsible for computation of the batched multilinear polynomials required by the Gemini protocol
105
+ * @details Opening multivariate polynomials using Gemini requires the computation of three batched polynomials. The
106
+ * 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.
112
+ * @note TODO(https://github.com/AztecProtocol/barretenberg/issues/1223): There are certain operations herein that
113
+ * could be made more efficient by e.g. reusing already initialized polynomials, possibly at the expense of clarity.
114
+ */
115
+ class PolynomialBatcher {
116
+
117
+ size_t full_batched_size = 0 ; // size of the full batched polynomial (generally the circuit size)
118
+ bool batched_unshifted_initialized = false ;
119
+
120
+ Polynomial random_polynomial; // random polynomial used for ZK
121
+ bool has_random_polynomial = false ;
122
+
123
+ RefVector<Polynomial> unshifted; // set of unshifted polynomials
124
+ RefVector<Polynomial> to_be_shifted_by_one; // set of polynomials to be left shifted by 1
125
+
126
+ Polynomial batched_unshifted; // linear combination of unshifted polynomials
127
+ Polynomial batched_to_be_shifted_by_one; // linear combination of to-be-shifted polynomials
128
+
129
+ public:
130
+ PolynomialBatcher (const size_t full_batched_size)
131
+ : full_batched_size(full_batched_size)
132
+ , batched_unshifted(full_batched_size)
133
+ , batched_to_be_shifted_by_one(Polynomial::shiftable(full_batched_size))
134
+ {}
135
+
136
+ bool has_unshifted () const { return unshifted.size () > 0 ; }
137
+ bool has_to_be_shifted_by_one () const { return to_be_shifted_by_one.size () > 0 ; }
138
+
139
+ // Set references to the polynomials to be batched
140
+ void set_unshifted (RefVector<Polynomial> polynomials) { unshifted = polynomials; }
141
+ void set_to_be_shifted_by_one (RefVector<Polynomial> polynomials) { to_be_shifted_by_one = polynomials; }
142
+
143
+ // Initialize the random polynomial used to add randomness to the batched polynomials for ZK
144
+ void set_random_polynomial (Polynomial&& random)
145
+ {
146
+ has_random_polynomial = true ;
147
+ random_polynomial = random ;
148
+ }
149
+
150
+ /* *
151
+ * @brief Compute batched polynomial A₀ = F + G/X as the linear combination of all polynomials to be opened
152
+ * @details If the random polynomial is set, it is added to the batched polynomial for ZK
153
+ *
154
+ * @param challenge batching challenge
155
+ * @param running_scalar power of the batching challenge
156
+ * @return Polynomial A₀
157
+ */
158
+ Polynomial compute_batched (const Fr& challenge, Fr& running_scalar)
159
+ {
160
+ // lambda for batching polynomials; updates the running scalar in place
161
+ auto batch = [&](Polynomial& batched, const RefVector<Polynomial>& polynomials_to_batch) {
162
+ for (auto & poly : polynomials_to_batch) {
163
+ batched.add_scaled (poly, running_scalar);
164
+ running_scalar *= challenge;
165
+ }
166
+ };
167
+
168
+ Polynomial full_batched (full_batched_size);
169
+
170
+ // if necessary, add randomness to the full batched polynomial for ZK
171
+ if (has_random_polynomial) {
172
+ full_batched += random_polynomial;
173
+ }
174
+
175
+ // compute the linear combination F of the unshifted polynomials
176
+ if (has_unshifted ()) {
177
+ batch (batched_unshifted, unshifted);
178
+ full_batched += batched_unshifted; // A₀ = F
179
+ }
180
+
181
+ // compute the linear combination G of the to-be-shifted polynomials
182
+ if (has_to_be_shifted_by_one ()) {
183
+ 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
185
+ }
186
+
187
+ return full_batched;
188
+ }
189
+
190
+ /* *
191
+ * @brief Compute partially evaluated batched polynomials A₀(X, r) = A₀₊ = F + G/r, A₀(X, -r) = A₀₋ = F - G/r
192
+ * @details If the random polynomial is set, it is added to each batched polynomial for ZK
193
+ *
194
+ * @param r_challenge partial evaluation challenge
195
+ * @return std::pair<Polynomial, Polynomial> {A₀₊, A₀₋}
196
+ */
197
+ std::pair<Polynomial, Polynomial> compute_partially_evaluated_batch_polynomials (const Fr& r_challenge)
198
+ {
199
+ // Initialize A₀₊ and compute A₀₊ += Random and A₀₊ += F as necessary
200
+ Polynomial A_0_pos (full_batched_size); // A₀₊
201
+
202
+ if (has_random_polynomial) {
203
+ A_0_pos += random_polynomial; // A₀₊ += random
204
+ }
205
+ if (has_unshifted ()) {
206
+ A_0_pos += batched_unshifted; // A₀₊ += F
207
+ }
208
+
209
+ Polynomial A_0_neg = A_0_pos;
210
+
211
+ if (has_to_be_shifted_by_one ()) {
212
+ Fr r_inv = r_challenge.invert (); // r⁻¹
213
+ batched_to_be_shifted_by_one *= r_inv; // G = G/r
214
+
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
217
+ }
218
+
219
+ return { A_0_pos, A_0_neg };
220
+ };
221
+ };
222
+
103
223
static std::vector<Polynomial> compute_fold_polynomials (const size_t log_n,
104
224
std::span<const Fr> multilinear_challenge,
105
225
const Polynomial& A_0);
106
226
107
227
static std::pair<Polynomial, Polynomial> compute_partially_evaluated_batch_polynomials (
108
228
const size_t log_n,
109
- Polynomial&& batched_F,
110
- Polynomial&& batched_G,
229
+ PolynomialBatcher& polynomial_batcher,
111
230
const Fr& r_challenge,
112
231
const std::vector<Polynomial>& batched_groups_to_be_concatenated = {});
113
232
@@ -119,8 +238,7 @@ template <typename Curve> class GeminiProver_ {
119
238
120
239
template <typename Transcript>
121
240
static std::vector<Claim> prove (const Fr circuit_size,
122
- RefSpan<Polynomial> f_polynomials,
123
- RefSpan<Polynomial> g_polynomials,
241
+ PolynomialBatcher& polynomial_batcher,
124
242
std::span<Fr> multilinear_challenge,
125
243
const std::shared_ptr<CommitmentKey<Curve>>& commitment_key,
126
244
const std::shared_ptr<Transcript>& transcript,
0 commit comments