2 *****************************************************************************
4 Implementation of interfaces for a ppzkSNARK for R1CS.
6 See r1cs_gg_ppzksnark.hpp .
8 *****************************************************************************
9 * @author This file is part of libsnark, developed by SCIPR Lab
10 * and contributors (see AUTHORS).
11 * @copyright MIT license (see LICENSE file)
12 *****************************************************************************/
14 #ifndef R1CS_GG_PPZKSNARK_TCC_
15 #define R1CS_GG_PPZKSNARK_TCC_
21 #include <libff/algebra/scalar_multiplication/multiexp.hpp>
22 #include <libff/common/profiling.hpp>
23 #include <libff/common/utils.hpp>
30 #include <libsnark/knowledge_commitment/kc_multiexp.hpp>
31 #include <libsnark/reductions/r1cs_to_qap/r1cs_to_qap.hpp>
36 template<typename ppT>
37 bool r1cs_gg_ppzksnark_proving_key<ppT>::operator==(
38 const r1cs_gg_ppzksnark_proving_key<ppT> &other) const
41 this->alpha_g1 == other.alpha_g1 && this->beta_g1 == other.beta_g1 &&
42 this->beta_g2 == other.beta_g2 && this->delta_g1 == other.delta_g1 &&
43 this->delta_g2 == other.delta_g2 && this->A_query == other.A_query &&
44 this->B_query == other.B_query && this->H_query == other.H_query &&
45 this->L_query == other.L_query &&
46 this->constraint_system == other.constraint_system);
49 template<typename ppT>
50 std::ostream &operator<<(
51 std::ostream &out, const r1cs_gg_ppzksnark_proving_key<ppT> &pk)
53 out << pk.alpha_g1 << OUTPUT_NEWLINE;
54 out << pk.beta_g1 << OUTPUT_NEWLINE;
55 out << pk.beta_g2 << OUTPUT_NEWLINE;
56 out << pk.delta_g1 << OUTPUT_NEWLINE;
57 out << pk.delta_g2 << OUTPUT_NEWLINE;
62 out << pk.constraint_system;
67 template<typename ppT>
68 std::istream &operator>>(
69 std::istream &in, r1cs_gg_ppzksnark_proving_key<ppT> &pk)
72 libff::consume_OUTPUT_NEWLINE(in);
74 libff::consume_OUTPUT_NEWLINE(in);
76 libff::consume_OUTPUT_NEWLINE(in);
78 libff::consume_OUTPUT_NEWLINE(in);
80 libff::consume_OUTPUT_NEWLINE(in);
85 in >> pk.constraint_system;
90 template<typename ppT>
91 bool r1cs_gg_ppzksnark_verification_key<ppT>::operator==(
92 const r1cs_gg_ppzksnark_verification_key<ppT> &other) const
95 this->alpha_g1 == other.alpha_g1 && this->beta_g2 == other.beta_g2 &&
96 this->delta_g2 == other.delta_g2 && this->ABC_g1 == other.ABC_g1);
99 template<typename ppT>
100 std::ostream &operator<<(
101 std::ostream &out, const r1cs_gg_ppzksnark_verification_key<ppT> &vk)
103 out << vk.alpha_g1 << OUTPUT_NEWLINE;
104 out << vk.beta_g2 << OUTPUT_NEWLINE;
105 out << vk.delta_g2 << OUTPUT_NEWLINE;
106 out << vk.ABC_g1 << OUTPUT_NEWLINE;
111 template<typename ppT>
112 std::istream &operator>>(
113 std::istream &in, r1cs_gg_ppzksnark_verification_key<ppT> &vk)
116 libff::consume_OUTPUT_NEWLINE(in);
118 libff::consume_OUTPUT_NEWLINE(in);
120 libff::consume_OUTPUT_NEWLINE(in);
122 libff::consume_OUTPUT_NEWLINE(in);
127 template<typename ppT>
128 bool r1cs_gg_ppzksnark_processed_verification_key<ppT>::operator==(
129 const r1cs_gg_ppzksnark_processed_verification_key<ppT> &other) const
132 this->vk_alpha_g1_precomp == other.vk_alpha_g1_precomp &&
133 this->vk_beta_g2_precomp == other.vk_beta_g2_precomp &&
134 this->vk_generator_g2_precomp == other.vk_generator_g2_precomp &&
135 this->vk_delta_g2_precomp == other.vk_delta_g2_precomp &&
136 this->ABC_g1 == other.ABC_g1);
139 template<typename ppT>
140 std::ostream &operator<<(
142 const r1cs_gg_ppzksnark_processed_verification_key<ppT> &pvk)
144 out << pvk.vk_alpha_g1_precomp << OUTPUT_NEWLINE;
145 out << pvk.vk_beta_g2_precomp << OUTPUT_NEWLINE;
146 out << pvk.vk_generator_g2_precomp << OUTPUT_NEWLINE;
147 out << pvk.vk_delta_g2_precomp << OUTPUT_NEWLINE;
148 out << pvk.ABC_g1 << OUTPUT_NEWLINE;
153 template<typename ppT>
154 std::istream &operator>>(
155 std::istream &in, r1cs_gg_ppzksnark_processed_verification_key<ppT> &pvk)
157 in >> pvk.vk_alpha_g1_precomp;
158 libff::consume_OUTPUT_NEWLINE(in);
159 in >> pvk.vk_beta_g2_precomp;
160 libff::consume_OUTPUT_NEWLINE(in);
161 in >> pvk.vk_generator_g2_precomp;
162 libff::consume_OUTPUT_NEWLINE(in);
163 in >> pvk.vk_delta_g2_precomp;
164 libff::consume_OUTPUT_NEWLINE(in);
166 libff::consume_OUTPUT_NEWLINE(in);
171 template<typename ppT>
172 bool r1cs_gg_ppzksnark_proof<ppT>::operator==(
173 const r1cs_gg_ppzksnark_proof<ppT> &other) const
176 this->g_A == other.g_A && this->g_B == other.g_B &&
177 this->g_C == other.g_C);
180 template<typename ppT>
181 std::ostream &operator<<(
182 std::ostream &out, const r1cs_gg_ppzksnark_proof<ppT> &proof)
184 out << proof.g_A << OUTPUT_NEWLINE;
185 out << proof.g_B << OUTPUT_NEWLINE;
186 out << proof.g_C << OUTPUT_NEWLINE;
191 template<typename ppT>
192 std::istream &operator>>(std::istream &in, r1cs_gg_ppzksnark_proof<ppT> &proof)
195 libff::consume_OUTPUT_NEWLINE(in);
197 libff::consume_OUTPUT_NEWLINE(in);
199 libff::consume_OUTPUT_NEWLINE(in);
204 template<typename ppT>
205 r1cs_gg_ppzksnark_verification_key<ppT> r1cs_gg_ppzksnark_verification_key<
206 ppT>::dummy_verification_key(const size_t input_size)
208 r1cs_gg_ppzksnark_verification_key<ppT> result;
209 result.alpha_g1 = libff::G1<ppT>::random_element();
210 result.beta_g2 = libff::G2<ppT>::random_element();
211 result.delta_g2 = libff::G2<ppT>::random_element();
213 libff::G1<ppT> base = libff::G1<ppT>::random_element();
214 libff::G1_vector<ppT> v;
215 for (size_t i = 0; i < input_size; ++i) {
216 v.emplace_back(libff::G1<ppT>::random_element());
220 accumulation_vector<libff::G1<ppT>>(std::move(base), std::move(v));
225 template<typename ppT, libff::multi_exp_base_form BaseForm>
226 r1cs_gg_ppzksnark_keypair<ppT> r1cs_gg_ppzksnark_generator_from_secrets(
227 const r1cs_gg_ppzksnark_constraint_system<ppT> &r1cs,
228 const libff::Fr<ppT> &t,
229 const libff::Fr<ppT> &alpha,
230 const libff::Fr<ppT> &beta,
231 const libff::Fr<ppT> &delta,
232 const libff::G1<ppT> &g1_generator,
233 const libff::G2<ppT> &g2_generator,
234 bool force_pow_2_domain)
236 libff::enter_block("Call to r1cs_gg_ppzksnark_generator_from_secrets");
238 /* Make the B_query "lighter" if possible */
239 r1cs_gg_ppzksnark_constraint_system<ppT> r1cs_copy(r1cs);
240 r1cs_copy.swap_AB_if_beneficial();
242 const libff::Fr<ppT> delta_inverse = delta.inverse();
244 /* A quadratic arithmetic program evaluated at t. */
245 qap_instance_evaluation<libff::Fr<ppT>> qap =
246 r1cs_to_qap_instance_map_with_evaluation(
247 r1cs_copy, t, force_pow_2_domain);
249 libff::print_indent();
250 printf("* QAP number of variables: %zu\n", qap.num_variables());
251 libff::print_indent();
252 printf("* QAP pre degree: %zu\n", r1cs_copy.constraints.size());
253 libff::print_indent();
254 printf("* QAP degree: %zu\n", qap.degree());
255 libff::print_indent();
256 printf("* QAP number of input variables: %zu\n", qap.num_inputs());
258 libff::enter_block("Compute query densities");
259 size_t non_zero_At = 0;
260 size_t non_zero_Bt = 0;
261 for (size_t i = 0; i < qap.num_variables() + 1; ++i) {
262 if (!qap.At[i].is_zero()) {
265 if (!qap.Bt[i].is_zero()) {
269 libff::leave_block("Compute query densities");
271 /* qap.{At,Bt,Ct,Ht} are now in unspecified state, but we do not use them
273 libff::Fr_vector<ppT> At = std::move(qap.At);
274 libff::Fr_vector<ppT> Bt = std::move(qap.Bt);
275 libff::Fr_vector<ppT> Ct = std::move(qap.Ct);
276 libff::Fr_vector<ppT> Ht = std::move(qap.Ht);
278 /* The product component: (beta*A_i(t) + alpha*B_i(t) + C_i(t)). */
279 libff::enter_block("Compute ABC for R1CS verification key");
280 libff::Fr_vector<ppT> ABC;
281 ABC.reserve(qap.num_inputs());
283 const libff::Fr<ppT> ABC_0 = beta * At[0] + alpha * Bt[0] + Ct[0];
284 for (size_t i = 1; i < qap.num_inputs() + 1; ++i) {
285 ABC.emplace_back(beta * At[i] + alpha * Bt[i] + Ct[i]);
287 libff::leave_block("Compute ABC for R1CS verification key");
289 /* The delta inverse product component: (beta*A_i(t) + alpha*B_i(t) +
290 * C_i(t)) * delta^{-1}. */
291 libff::enter_block("Compute L query for R1CS proving key");
292 libff::Fr_vector<ppT> Lt;
293 Lt.reserve(qap.num_variables() - qap.num_inputs());
295 const size_t Lt_offset = qap.num_inputs() + 1;
296 for (size_t i = Lt_offset; i < qap.num_variables() + 1; ++i) {
297 Lt.emplace_back((beta * At[i] + alpha * Bt[i] + Ct[i]) * delta_inverse);
299 libff::leave_block("Compute L query for R1CS proving key");
302 * Note that H for Groth's proof system is degree d-2, but the QAP
303 * reduction returns coefficients for degree d polynomial H (in
304 * style of PGHR-type proof systems)
306 Ht.resize(Ht.size() - 2);
309 const size_t chunks =
310 omp_get_max_threads(); // to override, set OMP_NUM_THREADS env var or
311 // call omp_set_num_threads()
313 const size_t chunks = 1;
316 libff::enter_block("Generating G1 MSM window table");
317 const size_t g1_scalar_count =
318 non_zero_At + non_zero_Bt + qap.num_variables();
319 const size_t g1_scalar_size = libff::Fr<ppT>::size_in_bits();
320 const size_t g1_window_size =
321 libff::get_exp_window_size<libff::G1<ppT>>(g1_scalar_count);
323 libff::print_indent();
324 printf("* G1 window: %zu\n", g1_window_size);
325 libff::window_table<libff::G1<ppT>> g1_table =
326 libff::get_window_table(g1_scalar_size, g1_window_size, g1_generator);
327 libff::leave_block("Generating G1 MSM window table");
329 libff::enter_block("Generating G2 MSM window table");
330 const size_t g2_scalar_count = non_zero_Bt;
331 const size_t g2_scalar_size = libff::Fr<ppT>::size_in_bits();
332 size_t g2_window_size =
333 libff::get_exp_window_size<libff::G2<ppT>>(g2_scalar_count);
335 libff::print_indent();
336 printf("* G2 window: %zu\n", g2_window_size);
337 libff::window_table<libff::G2<ppT>> g2_table =
338 libff::get_window_table(g2_scalar_size, g2_window_size, g2_generator);
339 libff::leave_block("Generating G2 MSM window table");
341 libff::enter_block("Generate R1CS proving key");
342 libff::G1<ppT> alpha_g1 = alpha * g1_generator;
343 libff::G1<ppT> beta_g1 = beta * g1_generator;
344 libff::G2<ppT> beta_g2 = beta * g2_generator;
345 libff::G1<ppT> delta_g1 = delta * g1_generator;
346 libff::G2<ppT> delta_g2 = delta * g2_generator;
348 libff::enter_block("Generate queries");
349 libff::enter_block("Compute the A-query", false);
350 libff::G1_vector<ppT> A_query =
351 batch_exp(g1_scalar_size, g1_window_size, g1_table, At);
352 if (BaseForm == libff::multi_exp_base_form_special) {
353 libff::batch_to_special<libff::G1<ppT>>(A_query);
355 libff::leave_block("Compute the A-query", false);
357 libff::enter_block("Compute the B-query", false);
358 // Force kc_batch_exp to convert to special form, if BaseForm ==
359 // libff::multi_exp_base_form_special.
360 knowledge_commitment_vector<libff::G2<ppT>, libff::G1<ppT>> B_query =
362 libff::Fr<ppT>::size_in_bits(),
367 libff::Fr<ppT>::one(),
368 libff::Fr<ppT>::one(),
371 BaseForm == libff::multi_exp_base_form_special);
372 libff::leave_block("Compute the B-query", false);
374 libff::enter_block("Compute the H-query", false);
375 libff::G1_vector<ppT> H_query = batch_exp_with_coeff(
376 g1_scalar_size, g1_window_size, g1_table, qap.Zt * delta_inverse, Ht);
377 if (BaseForm == libff::multi_exp_base_form_special) {
378 libff::batch_to_special<libff::G1<ppT>>(H_query);
380 libff::leave_block("Compute the H-query", false);
382 libff::enter_block("Compute the L-query", false);
383 libff::G1_vector<ppT> L_query =
384 batch_exp(g1_scalar_size, g1_window_size, g1_table, Lt);
385 if (BaseForm == libff::multi_exp_base_form_special) {
386 libff::batch_to_special<libff::G1<ppT>>(L_query);
388 libff::leave_block("Compute the L-query", false);
389 libff::leave_block("Generate queries");
391 libff::leave_block("Generate R1CS proving key");
393 libff::enter_block("Generate R1CS verification key");
395 libff::enter_block("Encode ABC for R1CS verification key");
396 libff::G1<ppT> ABC_g1_0 = ABC_0 * g1_generator;
397 libff::G1_vector<ppT> ABC_g1_values =
398 batch_exp(g1_scalar_size, g1_window_size, g1_table, ABC);
399 libff::leave_block("Encode ABC for R1CS verification key");
400 libff::leave_block("Generate R1CS verification key");
402 libff::leave_block("Call to r1cs_gg_ppzksnark_generator_from_secrets");
404 accumulation_vector<libff::G1<ppT>> ABC_g1(
405 std::move(ABC_g1_0), std::move(ABC_g1_values));
407 r1cs_gg_ppzksnark_verification_key<ppT> vk =
408 r1cs_gg_ppzksnark_verification_key<ppT>(
409 alpha_g1, beta_g2, delta_g2, ABC_g1);
411 r1cs_gg_ppzksnark_proving_key<ppT> pk = r1cs_gg_ppzksnark_proving_key<ppT>(
421 std::move(r1cs_copy));
426 return r1cs_gg_ppzksnark_keypair<ppT>(std::move(pk), std::move(vk));
429 template<typename ppT, libff::multi_exp_base_form BaseForm>
430 r1cs_gg_ppzksnark_keypair<ppT> r1cs_gg_ppzksnark_generator(
431 const r1cs_gg_ppzksnark_constraint_system<ppT> &r1cs,
432 bool force_pow_2_domain)
434 libff::enter_block("Call to r1cs_gg_ppzksnark_generator");
436 /* Generate secret randomness */
437 const libff::Fr<ppT> t = libff::Fr<ppT>::random_element();
438 const libff::Fr<ppT> alpha = libff::Fr<ppT>::random_element();
439 const libff::Fr<ppT> beta = libff::Fr<ppT>::random_element();
440 const libff::Fr<ppT> delta = libff::Fr<ppT>::random_element();
441 const libff::G1<ppT> g1_generator = libff::G1<ppT>::one();
442 const libff::G2<ppT> g2_generator = libff::G2<ppT>::one();
444 r1cs_gg_ppzksnark_keypair<ppT> key_pair =
445 r1cs_gg_ppzksnark_generator_from_secrets<ppT, BaseForm>(
455 libff::leave_block("Call to r1cs_gg_ppzksnark_generator");
462 libff::multi_exp_method Method,
463 libff::multi_exp_base_form BaseForm>
464 r1cs_gg_ppzksnark_proof<ppT> r1cs_gg_ppzksnark_prover(
465 const r1cs_gg_ppzksnark_proving_key<ppT> &pk,
466 const r1cs_gg_ppzksnark_primary_input<ppT> &primary_input,
467 const r1cs_gg_ppzksnark_auxiliary_input<ppT> &auxiliary_input,
468 bool force_pow_2_domain)
470 libff::enter_block("Call to r1cs_gg_ppzksnark_prover");
473 assert(pk.constraint_system.is_satisfied(primary_input, auxiliary_input));
476 libff::enter_block("Compute the polynomial H");
477 const qap_witness<libff::Fr<ppT>> qap_wit = r1cs_to_qap_witness_map(
478 pk.constraint_system,
481 libff::Fr<ppT>::zero(),
482 libff::Fr<ppT>::zero(),
483 libff::Fr<ppT>::zero(),
486 /* We are dividing degree 2(d-1) polynomial by degree d polynomial
487 and not adding a PGHR-style ZK-patch, so our H is degree d-2 */
488 assert(!qap_wit.coefficients_for_H[qap_wit.degree() - 2].is_zero());
489 assert(qap_wit.coefficients_for_H[qap_wit.degree() - 1].is_zero());
490 assert(qap_wit.coefficients_for_H[qap_wit.degree()].is_zero());
491 libff::leave_block("Compute the polynomial H");
494 const libff::Fr<ppT> t = libff::Fr<ppT>::random_element();
495 qap_instance_evaluation<libff::Fr<ppT>> qap_inst =
496 r1cs_to_qap_instance_map_with_evaluation(
497 pk.constraint_system, t, force_pow_2_domain);
498 assert(qap_inst.is_satisfied(qap_wit));
501 /* Choose two random field elements for prover zero-knowledge. */
502 const libff::Fr<ppT> r = libff::Fr<ppT>::random_element();
503 const libff::Fr<ppT> s = libff::Fr<ppT>::random_element();
506 assert(qap_wit.coefficients_for_ABCs.size() == qap_wit.num_variables());
507 assert(pk.A_query.size() == qap_wit.num_variables() + 1);
508 assert(pk.B_query.domain_size() == qap_wit.num_variables() + 1);
509 assert(pk.H_query.size() == qap_wit.degree() - 1);
510 assert(pk.L_query.size() == qap_wit.num_variables() - qap_wit.num_inputs());
514 const size_t chunks =
515 omp_get_max_threads(); // to override, set OMP_NUM_THREADS env var or
516 // call omp_set_num_threads()
518 const size_t chunks = 1;
521 libff::enter_block("Compute the proof");
523 libff::enter_block("Compute evaluation to A-query", false);
524 // TODO: sort out indexing
525 libff::Fr_vector<ppT> const_padded_assignment(1, libff::Fr<ppT>::one());
526 const_padded_assignment.insert(
527 const_padded_assignment.end(),
528 qap_wit.coefficients_for_ABCs.begin(),
529 qap_wit.coefficients_for_ABCs.end());
531 libff::G1<ppT> evaluation_At = libff::multi_exp_filter_one_zero<
537 pk.A_query.begin() + qap_wit.num_variables() + 1,
538 const_padded_assignment.begin(),
539 const_padded_assignment.begin() + qap_wit.num_variables() + 1,
541 libff::leave_block("Compute evaluation to A-query", false);
543 libff::enter_block("Compute evaluation to B-query", false);
544 knowledge_commitment<libff::G2<ppT>, libff::G1<ppT>> evaluation_Bt =
545 kc_multi_exp_with_mixed_addition<
553 qap_wit.num_variables() + 1,
554 const_padded_assignment.begin(),
555 const_padded_assignment.begin() + qap_wit.num_variables() + 1,
557 libff::leave_block("Compute evaluation to B-query", false);
559 libff::enter_block("Compute evaluation to H-query", false);
560 libff::G1<ppT> evaluation_Ht =
561 libff::multi_exp<libff::G1<ppT>, libff::Fr<ppT>, Method, BaseForm>(
563 pk.H_query.begin() + (qap_wit.degree() - 1),
564 qap_wit.coefficients_for_H.begin(),
565 qap_wit.coefficients_for_H.begin() + (qap_wit.degree() - 1),
567 libff::leave_block("Compute evaluation to H-query", false);
569 libff::enter_block("Compute evaluation to L-query", false);
570 libff::G1<ppT> evaluation_Lt = libff::multi_exp_filter_one_zero<
577 const_padded_assignment.begin() + qap_wit.num_inputs() + 1,
578 const_padded_assignment.begin() + qap_wit.num_variables() + 1,
580 libff::leave_block("Compute evaluation to L-query", false);
582 /* A = alpha + sum_i(a_i*A_i(t)) + r*delta */
583 libff::G1<ppT> g1_A = pk.alpha_g1 + evaluation_At + r * pk.delta_g1;
585 /* B = beta + sum_i(a_i*B_i(t)) + s*delta */
586 libff::G1<ppT> g1_B = pk.beta_g1 + evaluation_Bt.h + s * pk.delta_g1;
587 libff::G2<ppT> g2_B = pk.beta_g2 + evaluation_Bt.g + s * pk.delta_g2;
589 /* C = sum_i(a_i*((beta*A_i(t) + alpha*B_i(t) + C_i(t)) + H(t)*Z(t))/delta)
590 * + A*s + r*b - r*s*delta */
591 libff::G1<ppT> g1_C = evaluation_Ht + evaluation_Lt + s * g1_A + r * g1_B -
592 (r * s) * pk.delta_g1;
594 libff::leave_block("Compute the proof");
596 libff::leave_block("Call to r1cs_gg_ppzksnark_prover");
598 r1cs_gg_ppzksnark_proof<ppT> proof = r1cs_gg_ppzksnark_proof<ppT>(
599 std::move(g1_A), std::move(g2_B), std::move(g1_C));
605 template<typename ppT>
606 r1cs_gg_ppzksnark_processed_verification_key<ppT>
607 r1cs_gg_ppzksnark_verifier_process_vk(
608 const r1cs_gg_ppzksnark_verification_key<ppT> &vk)
610 libff::enter_block("Call to r1cs_gg_ppzksnark_verifier_process_vk");
612 r1cs_gg_ppzksnark_processed_verification_key<ppT> pvk;
613 pvk.vk_alpha_g1_precomp = ppT::precompute_G1(vk.alpha_g1);
614 pvk.vk_beta_g2_precomp = ppT::precompute_G2(vk.beta_g2);
615 pvk.vk_generator_g2_precomp = ppT::precompute_G2(libff::G2<ppT>::one());
616 pvk.vk_delta_g2_precomp = ppT::precompute_G2(vk.delta_g2);
617 pvk.ABC_g1 = vk.ABC_g1;
619 libff::leave_block("Call to r1cs_gg_ppzksnark_verifier_process_vk");
624 template<typename ppT>
625 bool r1cs_gg_ppzksnark_online_verifier_weak_IC(
626 const r1cs_gg_ppzksnark_processed_verification_key<ppT> &pvk,
627 const r1cs_gg_ppzksnark_primary_input<ppT> &primary_input,
628 const r1cs_gg_ppzksnark_proof<ppT> &proof)
630 libff::enter_block("Call to r1cs_gg_ppzksnark_online_verifier_weak_IC");
631 assert(pvk.ABC_g1.domain_size() >= primary_input.size());
633 libff::enter_block("Accumulate input");
634 const accumulation_vector<libff::G1<ppT>> accumulated_IC =
635 pvk.ABC_g1.template accumulate_chunk<libff::Fr<ppT>>(
636 primary_input.begin(), primary_input.end(), 0);
637 const libff::G1<ppT> &acc = accumulated_IC.first;
638 libff::leave_block("Accumulate input");
642 libff::enter_block("Check if the proof is well-formed");
643 if (!proof.is_well_formed()) {
644 if (!libff::inhibit_profiling_info) {
645 libff::print_indent();
646 printf("At least one of the proof elements does not lie on the "
651 libff::leave_block("Check if the proof is well-formed");
653 libff::enter_block("Online pairing computations");
654 libff::enter_block("Check QAP divisibility");
655 const libff::G1_precomp<ppT> proof_g_A_precomp =
656 ppT::precompute_G1(proof.g_A);
657 const libff::G2_precomp<ppT> proof_g_B_precomp =
658 ppT::precompute_G2(proof.g_B);
659 const libff::G1_precomp<ppT> proof_g_C_precomp =
660 ppT::precompute_G1(proof.g_C);
661 const libff::G1_precomp<ppT> acc_precomp = ppT::precompute_G1(acc);
663 const libff::Fqk<ppT> f =
664 ppT::miller_loop(pvk.vk_alpha_g1_precomp, pvk.vk_beta_g2_precomp);
665 const libff::GT<ppT> vk_alpha_g1_beta_g2 = ppT::final_exponentiation(f);
667 const libff::Fqk<ppT> QAP1 =
668 ppT::miller_loop(proof_g_A_precomp, proof_g_B_precomp);
669 const libff::Fqk<ppT> QAP2 = ppT::double_miller_loop(
671 pvk.vk_generator_g2_precomp,
673 pvk.vk_delta_g2_precomp);
674 const libff::GT<ppT> QAP =
675 ppT::final_exponentiation(QAP1 * QAP2.unitary_inverse());
677 if (QAP != vk_alpha_g1_beta_g2) {
678 if (!libff::inhibit_profiling_info) {
679 libff::print_indent();
680 printf("QAP divisibility check failed.\n");
684 libff::leave_block("Check QAP divisibility");
685 libff::leave_block("Online pairing computations");
687 libff::leave_block("Call to r1cs_gg_ppzksnark_online_verifier_weak_IC");
692 template<typename ppT>
693 bool r1cs_gg_ppzksnark_verifier_weak_IC(
694 const r1cs_gg_ppzksnark_verification_key<ppT> &vk,
695 const r1cs_gg_ppzksnark_primary_input<ppT> &primary_input,
696 const r1cs_gg_ppzksnark_proof<ppT> &proof)
698 libff::enter_block("Call to r1cs_gg_ppzksnark_verifier_weak_IC");
699 r1cs_gg_ppzksnark_processed_verification_key<ppT> pvk =
700 r1cs_gg_ppzksnark_verifier_process_vk<ppT>(vk);
701 bool result = r1cs_gg_ppzksnark_online_verifier_weak_IC<ppT>(
702 pvk, primary_input, proof);
703 libff::leave_block("Call to r1cs_gg_ppzksnark_verifier_weak_IC");
707 template<typename ppT>
708 bool r1cs_gg_ppzksnark_online_verifier_strong_IC(
709 const r1cs_gg_ppzksnark_processed_verification_key<ppT> &pvk,
710 const r1cs_gg_ppzksnark_primary_input<ppT> &primary_input,
711 const r1cs_gg_ppzksnark_proof<ppT> &proof)
714 libff::enter_block("Call to r1cs_gg_ppzksnark_online_verifier_strong_IC");
716 if (pvk.ABC_g1.domain_size() != primary_input.size()) {
717 libff::print_indent();
719 "Input length differs from expected (got %zu, expected %zu).\n",
720 primary_input.size(),
721 pvk.ABC_g1.domain_size());
724 result = r1cs_gg_ppzksnark_online_verifier_weak_IC(
725 pvk, primary_input, proof);
728 libff::leave_block("Call to r1cs_gg_ppzksnark_online_verifier_strong_IC");
732 template<typename ppT>
733 bool r1cs_gg_ppzksnark_verifier_strong_IC(
734 const r1cs_gg_ppzksnark_verification_key<ppT> &vk,
735 const r1cs_gg_ppzksnark_primary_input<ppT> &primary_input,
736 const r1cs_gg_ppzksnark_proof<ppT> &proof)
738 libff::enter_block("Call to r1cs_gg_ppzksnark_verifier_strong_IC");
739 r1cs_gg_ppzksnark_processed_verification_key<ppT> pvk =
740 r1cs_gg_ppzksnark_verifier_process_vk<ppT>(vk);
741 bool result = r1cs_gg_ppzksnark_online_verifier_strong_IC<ppT>(
742 pvk, primary_input, proof);
743 libff::leave_block("Call to r1cs_gg_ppzksnark_verifier_strong_IC");
747 template<typename ppT>
748 bool r1cs_gg_ppzksnark_affine_verifier_weak_IC(
749 const r1cs_gg_ppzksnark_verification_key<ppT> &vk,
750 const r1cs_gg_ppzksnark_primary_input<ppT> &primary_input,
751 const r1cs_gg_ppzksnark_proof<ppT> &proof)
753 libff::enter_block("Call to r1cs_gg_ppzksnark_affine_verifier_weak_IC");
754 assert(vk.ABC_g1.domain_size() >= primary_input.size());
756 libff::affine_ate_G2_precomp<ppT> pvk_vk_generator_g2_precomp =
757 ppT::affine_ate_precompute_G2(libff::G2<ppT>::one());
758 libff::affine_ate_G2_precomp<ppT> pvk_vk_delta_g2_precomp =
759 ppT::affine_ate_precompute_G2(vk.delta_g2);
761 libff::enter_block("Accumulate input");
762 const accumulation_vector<libff::G1<ppT>> accumulated_IC =
763 vk.ABC_g1.template accumulate_chunk<libff::Fr<ppT>>(
764 primary_input.begin(), primary_input.end(), 0);
765 const libff::G1<ppT> &acc = accumulated_IC.first;
766 libff::leave_block("Accumulate input");
770 libff::enter_block("Check if the proof is well-formed");
771 if (!proof.is_well_formed()) {
772 if (!libff::inhibit_profiling_info) {
773 libff::print_indent();
774 printf("At least one of the proof elements does not lie on the "
779 libff::leave_block("Check if the proof is well-formed");
781 libff::enter_block("Check QAP divisibility");
782 const libff::affine_ate_G1_precomp<ppT> proof_g_A_precomp =
783 ppT::affine_ate_precompute_G1(proof.g_A);
784 const libff::affine_ate_G2_precomp<ppT> proof_g_B_precomp =
785 ppT::affine_ate_precompute_G2(proof.g_B);
786 const libff::affine_ate_G1_precomp<ppT> proof_g_C_precomp =
787 ppT::affine_ate_precompute_G1(proof.g_C);
788 const libff::affine_ate_G1_precomp<ppT> acc_precomp =
789 ppT::affine_ate_precompute_G1(acc);
791 const libff::Fqk<ppT> QAP_miller =
792 ppT::affine_ate_e_times_e_over_e_miller_loop(
794 pvk_vk_generator_g2_precomp,
796 pvk_vk_delta_g2_precomp,
799 const libff::GT<ppT> QAP =
800 ppT::final_exponentiation(QAP_miller.unitary_inverse());
801 const libff::GT<ppT> vk_alpha_g1_beta_g2 =
802 ppT::reduced_pairing(vk.alpha_g1, vk.beta_g2);
804 if (QAP != vk_alpha_g1_beta_g2) {
805 if (!libff::inhibit_profiling_info) {
806 libff::print_indent();
807 printf("QAP divisibility check failed.\n");
811 libff::leave_block("Check QAP divisibility");
813 libff::leave_block("Call to r1cs_gg_ppzksnark_affine_verifier_weak_IC");
818 } // namespace libsnark
819 #endif // R1CS_GG_PPZKSNARK_TCC_