@@ -46,6 +46,7 @@ namespace nil {
46
46
namespace commitments {
47
47
48
48
// Placeholder-friendly class.
49
+ // LPCScheme is usually 'batched_list_polynomial_commitment<...>'.
49
50
template <typename LPCScheme, typename PolynomialType = typename math::polynomial_dfs<
50
51
typename LPCScheme::params_type::field_type::value_type>>
51
52
class lpc_commitment_scheme : public polys_evaluator <typename LPCScheme::params_type,
@@ -61,6 +62,9 @@ namespace nil {
61
62
using fri_type = typename LPCScheme::fri_type;
62
63
using basic_fri = typename LPCScheme::fri_type;
63
64
using proof_type = typename LPCScheme::proof_type;
65
+ using aggregated_proof_type = typename LPCScheme::aggregated_proof_type;
66
+ using lpc_proof_type = typename LPCScheme::lpc_proof_type;
67
+ using fri_proof_type = typename LPCScheme::fri_proof_type;
64
68
using transcript_type = typename LPCScheme::transcript_type;
65
69
using transcript_hash_type = typename LPCScheme::transcript_hash_type;
66
70
using polynomial_type = PolynomialType;
@@ -110,7 +114,7 @@ namespace nil {
110
114
: _fri_params(fri_params), _etha(0u ) {
111
115
}
112
116
113
- preprocessed_data_type preprocess (transcript_type& transcript) const {
117
+ preprocessed_data_type preprocess (transcript_type& transcript) const {
114
118
auto etha = transcript.template challenge <field_type>();
115
119
116
120
preprocessed_data_type result;
@@ -132,6 +136,7 @@ namespace nil {
132
136
133
137
commitment_type commit (std::size_t index) {
134
138
this ->state_commited (index);
139
+
135
140
_trees[index] = nil::crypto3::zk::algorithms::precommit<fri_type>(
136
141
this ->_polys [index], _fri_params.D [0 ], _fri_params.step_list .front ());
137
142
return _trees[index].root ();
@@ -149,24 +154,142 @@ namespace nil {
149
154
BOOST_ASSERT (this ->_points .size () == this ->_polys .size ());
150
155
BOOST_ASSERT (this ->_points .size () == this ->_z .get_batches_num ());
151
156
152
- for (auto const & it: this ->_trees ) {
157
+ // For each batch we have a merkle tree.
158
+ for (auto const & it: this ->_trees ) {
153
159
transcript (it.second .root ());
154
160
}
155
161
156
162
// Prepare z-s and combined_Q;
157
163
auto theta = transcript.template challenge <field_type>();
158
- typename field_type::value_type theta_acc = field_type::value_type::one ();
164
+ polynomial_type combined_Q = prepare_combined_Q (theta);
165
+
166
+ auto fri_proof = commit_and_fri_proof (combined_Q, transcript);
167
+ return proof_type ({this ->_z , fri_proof});
168
+ }
169
+
170
+ /* * This function must be called for the cases where we want to skip the
171
+ * round proof for FRI. Must be called once per instance of prover for the aggregated FRI.
172
+ * \param[in] combined_Q - Polynomial combined_Q was already computed by the current
173
+ prover in the previous step of the aggregated FRI protocol.
174
+ * \param[in] transcript - This transcript is initialized from a challenge sent from the "Main" prover,
175
+ on which the round proof was created for the polynomial F(x) = Sum(combined_Q).
176
+ */
177
+ lpc_proof_type proof_eval_lpc_proof (
178
+ const polynomial_type& combined_Q, transcript_type &transcript) {
179
+
180
+ this ->eval_polys ();
181
+
182
+ BOOST_ASSERT (this ->_points .size () == this ->_polys .size ());
183
+ BOOST_ASSERT (this ->_points .size () == this ->_z .get_batches_num ());
184
+
185
+ // For each batch we have a merkle tree.
186
+ for (auto const & it: this ->_trees ) {
187
+ transcript (it.second .root ());
188
+ }
189
+
190
+ std::vector<typename fri_type::field_type::value_type> challenges =
191
+ transcript.template challenges <typename fri_type::field_type>(this ->_fri_params .lambda );
192
+
193
+ typename fri_type::initial_proofs_batch_type initial_proofs =
194
+ nil::crypto3::zk::algorithms::query_phase_initial_proofs<fri_type, polynomial_type>(
195
+ this ->_trees , this ->_fri_params , this ->_polys , challenges);
196
+ return {this ->_z , initial_proofs};
197
+ }
198
+
199
+ /* * This function must be called once for the aggregated FRI, to proof that polynomial
200
+ 'sum_poly' has low degree.
201
+ * \param[in] sum_poly - polynomial F(x) = Sum(combined_Q).
202
+ * \param[in] transcript - This transcript is initialized on the main prover, which has digested
203
+ challenges from all the other provers.
204
+ */
205
+ fri_proof_type proof_eval_FRI_proof (const polynomial_type& sum_poly, transcript_type &transcript) {
206
+ // TODO(martun): this function belongs to FRI, not here, will move later.
207
+ // Precommit to sum_poly.
208
+ if (sum_poly.size () != _fri_params.D [0 ]->size ()) {
209
+ sum_poly.resize (_fri_params.D [0 ]->size (), nullptr , _fri_params.D [0 ]);
210
+ }
211
+ precommitment_type sum_poly_precommitment = nil::crypto3::zk::algorithms::precommit<fri_type>(
212
+ sum_poly,
213
+ _fri_params.D [0 ],
214
+ _fri_params.step_list .front ()
215
+ );
216
+
217
+ std::vector<typename fri_type::precommitment_type> fri_trees;
218
+ std::vector<polynomial_type> fs;
219
+ math::polynomial<typename fri_type::field_type::value_type> final_polynomial;
220
+
221
+ // Contains fri_roots and final_polynomial.
222
+ typename fri_type::commitments_part_of_proof commitments_proof;
223
+
224
+ // Commit to sum_poly.
225
+ std::tie (fs, fri_trees, commitments_proof) =
226
+ nil::crypto3::zk::algorithms::commit_phase<fri_type, polynomial_type>(
227
+ sum_poly,
228
+ sum_poly_precommitment,
229
+ _fri_params, transcript);
230
+
231
+ std::vector<typename fri_type::field_type::value_type> challenges =
232
+ transcript.template challenges <typename fri_type::field_type>(this ->_fri_params .lambda );
233
+
234
+ fri_proof_type result;
235
+
236
+ result.fri_round_proof = nil::crypto3::zk::algorithms::query_phase_round_proofs<
237
+ fri_type, polynomial_type>(
238
+ _fri_params,
239
+ fri_trees,
240
+ fs,
241
+ sum_poly,
242
+ challenges);
243
+
244
+ result.fri_commitments_proof_part .fri_roots = std::move (commitments_proof.fri_roots );
245
+ result.fri_commitments_proof_part .final_polynomial = std::move (final_polynomial);
246
+
247
+ return result;
248
+ }
249
+
250
+ typename fri_type::proof_type commit_and_fri_proof (
251
+ const polynomial_type& combined_Q, transcript_type &transcript) {
252
+
253
+
254
+ precommitment_type combined_Q_precommitment = nil::crypto3::zk::algorithms::precommit<fri_type>(
255
+ combined_Q,
256
+ _fri_params.D [0 ],
257
+ _fri_params.step_list .front ()
258
+ );
259
+
260
+ typename fri_type::proof_type fri_proof = nil::crypto3::zk::algorithms::proof_eval<
261
+ fri_type, polynomial_type>(
262
+ this ->_polys ,
263
+ combined_Q,
264
+ this ->_trees ,
265
+ combined_Q_precommitment,
266
+ this ->_fri_params ,
267
+ transcript
268
+ );
269
+ return fri_proof;
270
+ }
271
+
272
+ /* * \brief
273
+ * \param theta The value of challenge. When called from aggregated FRI, this values is sent from
274
+ the "main prover" machine.
275
+ * \param starting_power When aggregated FRI is used, the value is not zero, it's the total degree of all
276
+ the polynomials in all the provers with indices lower than the current one.
277
+ */
278
+ polynomial_type prepare_combined_Q (
279
+ const typename field_type::value_type& theta,
280
+ std::size_t starting_power = 0 ) {
281
+ typename field_type::value_type theta_acc = theta.pow (starting_power);
159
282
polynomial_type combined_Q;
160
283
math::polynomial<value_type> V;
161
284
162
285
auto points = this ->get_unique_points ();
163
286
math::polynomial<value_type> combined_Q_normal;
164
287
165
- for (auto const &point: points){
288
+ for (auto const &point: points) {
166
289
V = {-point, 1u };
167
290
math::polynomial<value_type> Q_normal;
168
- for (std::size_t i: this ->_z .get_batches ()){
169
- for (std::size_t j = 0 ; j < this ->_z .get_batch_size (i); j++){
291
+ for (std::size_t i: this ->_z .get_batches ()) {
292
+ for (std::size_t j = 0 ; j < this ->_z .get_batch_size (i); j++) {
170
293
auto it = std::find (this ->_points [i][j].begin (), this ->_points [i][j].end (), point);
171
294
if ( it == this ->_points [i][j].end ()) continue ;
172
295
math::polynomial<value_type> g_normal;
@@ -185,6 +308,7 @@ namespace nil {
185
308
combined_Q_normal += Q_normal;
186
309
}
187
310
311
+ // TODO(martun): the following code is the same as above with point = _etha, de-duplicate it.
188
312
for (std::size_t i: this ->_z .get_batches ()) {
189
313
if (!_batch_fixed[i])
190
314
continue ;
@@ -212,27 +336,14 @@ namespace nil {
212
336
213
337
if constexpr (std::is_same<math::polynomial_dfs<value_type>, PolynomialType>::value) {
214
338
combined_Q.from_coefficients (combined_Q_normal);
339
+ if (combined_Q.size () != _fri_params.D [0 ]->size ()) {
340
+ combined_Q.resize (_fri_params.D [0 ]->size (), nullptr , _fri_params.D [0 ]);
341
+ }
215
342
} else {
216
343
combined_Q = std::move (combined_Q_normal);
217
344
}
218
345
219
- precommitment_type combined_Q_precommitment = nil::crypto3::zk::algorithms::precommit<fri_type>(
220
- combined_Q,
221
- _fri_params.D [0 ],
222
- _fri_params.step_list .front ()
223
- );
224
-
225
- typename fri_type::proof_type fri_proof = nil::crypto3::zk::algorithms::proof_eval<
226
- fri_type, polynomial_type
227
- >(
228
- this ->_polys ,
229
- combined_Q,
230
- this ->_trees ,
231
- combined_Q_precommitment,
232
- this ->_fri_params ,
233
- transcript
234
- );
235
- return proof_type ({this ->_z , fri_proof});
346
+ return combined_Q;
236
347
}
237
348
238
349
bool verify_eval (
@@ -421,6 +532,60 @@ namespace nil {
421
532
eval_storage_type z;
422
533
typename basic_fri::proof_type fri_proof;
423
534
};
535
+
536
+ // Represents an initial proof, which must be created for each of the N provers.
537
+ struct lpc_proof_type {
538
+ bool operator ==(const lpc_proof_type &rhs) const {
539
+ return initial_fri_proofs == rhs.initial_fri_proofs && z == rhs.z ;
540
+ }
541
+
542
+ bool operator !=(const lpc_proof_type &rhs) const {
543
+ return !(rhs == *this );
544
+ }
545
+
546
+ eval_storage_type z;
547
+ typename basic_fri::initial_proofs_batch_type initial_fri_proofs;
548
+ };
549
+
550
+ // Represents a round proof, which must be created just once on the main prover.
551
+ struct fri_proof_type {
552
+ bool operator ==(const fri_proof_type &rhs) const {
553
+ return fri_round_proof == rhs.fri_round_proof &&
554
+ fri_commitments_proof_part == rhs.fri_commitments_proof_part ;
555
+ }
556
+
557
+ bool operator !=(const fri_proof_type &rhs) const {
558
+ return !(rhs == *this );
559
+ }
560
+
561
+ // We have a single round proof for checking that F(X) is a low degree polynomial.
562
+ typename basic_fri::round_proofs_batch_type fri_round_proof;
563
+
564
+ // Contains fri_roots and final_polynomial that correspond to the polynomial F(x).
565
+ typename basic_fri::commitments_part_of_proof fri_commitments_proof_part;
566
+ };
567
+
568
+ // A single instance of this class will store all the LPC proofs for a group of provers
569
+ // when aggregated FRI is used.
570
+ struct aggregated_proof_type {
571
+ bool operator ==(const aggregated_proof_type &rhs) const {
572
+ return fri_proof == rhs.fri_proof &&
573
+ intial_proofs_per_prover == rhs.intial_proofs_per_prover &&
574
+ proof_of_work == rhs.proof_of_work ;
575
+ }
576
+
577
+ bool operator !=(const proof_type &rhs) const {
578
+ return !(rhs == *this );
579
+ }
580
+
581
+ // We have a single round proof for checking that F(X) is a low degree polynomial.
582
+ fri_proof_type fri_proof;
583
+
584
+ // For each prover we have an initial proof.
585
+ std::vector<lpc_proof_type> intial_proofs_per_prover;
586
+
587
+ typename LPCParams::grinding_type::output_type proof_of_work;
588
+ };
424
589
};
425
590
426
591
template <typename FieldType, typename LPCParams>
0 commit comments