Skip to content
This repository was archived by the owner on Feb 17, 2025. It is now read-only.

Commit f8bca3a

Browse files
committed
Dividing LPC and FRI into stages and creating structures for aggregated FRI.
1 parent 246955a commit f8bca3a

File tree

6 files changed

+467
-97
lines changed

6 files changed

+467
-97
lines changed

libs/zk/include/nil/crypto3/zk/commitments/detail/polynomial/basic_fri.hpp

Lines changed: 179 additions & 53 deletions
Large diffs are not rendered by default.

libs/zk/include/nil/crypto3/zk/commitments/polynomial/lpc.hpp

Lines changed: 188 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,7 @@ namespace nil {
4646
namespace commitments {
4747

4848
// Placeholder-friendly class.
49+
// LPCScheme is usually 'batched_list_polynomial_commitment<...>'.
4950
template<typename LPCScheme, typename PolynomialType = typename math::polynomial_dfs<
5051
typename LPCScheme::params_type::field_type::value_type>>
5152
class lpc_commitment_scheme : public polys_evaluator<typename LPCScheme::params_type,
@@ -61,6 +62,9 @@ namespace nil {
6162
using fri_type = typename LPCScheme::fri_type;
6263
using basic_fri = typename LPCScheme::fri_type;
6364
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;
6468
using transcript_type = typename LPCScheme::transcript_type;
6569
using transcript_hash_type = typename LPCScheme::transcript_hash_type;
6670
using polynomial_type = PolynomialType;
@@ -110,7 +114,7 @@ namespace nil {
110114
: _fri_params(fri_params), _etha(0u) {
111115
}
112116

113-
preprocessed_data_type preprocess(transcript_type& transcript) const{
117+
preprocessed_data_type preprocess(transcript_type& transcript) const {
114118
auto etha = transcript.template challenge<field_type>();
115119

116120
preprocessed_data_type result;
@@ -132,6 +136,7 @@ namespace nil {
132136

133137
commitment_type commit(std::size_t index) {
134138
this->state_commited(index);
139+
135140
_trees[index] = nil::crypto3::zk::algorithms::precommit<fri_type>(
136141
this->_polys[index], _fri_params.D[0], _fri_params.step_list.front());
137142
return _trees[index].root();
@@ -149,24 +154,142 @@ namespace nil {
149154
BOOST_ASSERT(this->_points.size() == this->_polys.size());
150155
BOOST_ASSERT(this->_points.size() == this->_z.get_batches_num());
151156

152-
for(auto const& it: this->_trees) {
157+
// For each batch we have a merkle tree.
158+
for (auto const& it: this->_trees) {
153159
transcript(it.second.root());
154160
}
155161

156162
// Prepare z-s and combined_Q;
157163
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);
159282
polynomial_type combined_Q;
160283
math::polynomial<value_type> V;
161284

162285
auto points = this->get_unique_points();
163286
math::polynomial<value_type> combined_Q_normal;
164287

165-
for (auto const &point: points){
288+
for (auto const &point: points) {
166289
V = {-point, 1u};
167290
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++) {
170293
auto it = std::find(this->_points[i][j].begin(), this->_points[i][j].end(), point);
171294
if( it == this->_points[i][j].end()) continue;
172295
math::polynomial<value_type> g_normal;
@@ -185,6 +308,7 @@ namespace nil {
185308
combined_Q_normal += Q_normal;
186309
}
187310

311+
// TODO(martun): the following code is the same as above with point = _etha, de-duplicate it.
188312
for (std::size_t i: this->_z.get_batches()) {
189313
if (!_batch_fixed[i])
190314
continue;
@@ -212,27 +336,14 @@ namespace nil {
212336

213337
if constexpr (std::is_same<math::polynomial_dfs<value_type>, PolynomialType>::value) {
214338
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+
}
215342
} else {
216343
combined_Q = std::move(combined_Q_normal);
217344
}
218345

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;
236347
}
237348

238349
bool verify_eval(
@@ -421,6 +532,60 @@ namespace nil {
421532
eval_storage_type z;
422533
typename basic_fri::proof_type fri_proof;
423534
};
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+
};
424589
};
425590

426591
template<typename FieldType, typename LPCParams>

0 commit comments

Comments
 (0)