2 *****************************************************************************
4 Implementation of interfaces for a SEppzkSNARK for R1CS.
6 See r1cs_se_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_SE_PPZKSNARK_TCC_
15 #define R1CS_SE_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_sap/r1cs_to_sap.hpp>
36 template<typename ppT>
37 bool r1cs_se_ppzksnark_proving_key<ppT>::operator==(
38 const r1cs_se_ppzksnark_proving_key<ppT> &other) const
41 this->A_query == other.A_query && this->B_query == other.B_query &&
42 this->C_query_1 == other.C_query_1 &&
43 this->C_query_2 == other.C_query_2 &&
44 this->G_gamma_Z == other.G_gamma_Z &&
45 this->H_gamma_Z == other.H_gamma_Z &&
46 this->G_ab_gamma_Z == other.G_ab_gamma_Z &&
47 this->G_gamma2_Z2 == other.G_gamma2_Z2 &&
48 this->G_gamma2_Z_t == other.G_gamma2_Z_t &&
49 this->constraint_system == other.constraint_system);
52 template<typename ppT>
53 std::ostream &operator<<(
54 std::ostream &out, const r1cs_se_ppzksnark_proving_key<ppT> &pk)
62 out << pk.G_ab_gamma_Z;
63 out << pk.G_gamma2_Z2;
64 out << pk.G_gamma2_Z_t;
65 out << pk.constraint_system;
70 template<typename ppT>
71 std::istream &operator>>(
72 std::istream &in, r1cs_se_ppzksnark_proving_key<ppT> &pk)
80 in >> pk.G_ab_gamma_Z;
82 in >> pk.G_gamma2_Z_t;
83 in >> pk.constraint_system;
88 template<typename ppT>
89 bool r1cs_se_ppzksnark_verification_key<ppT>::operator==(
90 const r1cs_se_ppzksnark_verification_key<ppT> &other) const
93 this->H == other.H && this->G_alpha == other.G_alpha &&
94 this->H_beta == other.H_beta && this->G_gamma == other.G_gamma &&
95 this->H_gamma == other.H_gamma && this->query == other.query);
98 template<typename ppT>
99 std::ostream &operator<<(
100 std::ostream &out, const r1cs_se_ppzksnark_verification_key<ppT> &vk)
102 out << vk.H << OUTPUT_NEWLINE;
103 out << vk.G_alpha << OUTPUT_NEWLINE;
104 out << vk.H_beta << OUTPUT_NEWLINE;
105 out << vk.G_gamma << OUTPUT_NEWLINE;
106 out << vk.H_gamma << OUTPUT_NEWLINE;
107 out << vk.query << OUTPUT_NEWLINE;
112 template<typename ppT>
113 std::istream &operator>>(
114 std::istream &in, r1cs_se_ppzksnark_verification_key<ppT> &vk)
117 libff::consume_OUTPUT_NEWLINE(in);
119 libff::consume_OUTPUT_NEWLINE(in);
121 libff::consume_OUTPUT_NEWLINE(in);
123 libff::consume_OUTPUT_NEWLINE(in);
125 libff::consume_OUTPUT_NEWLINE(in);
127 libff::consume_OUTPUT_NEWLINE(in);
132 template<typename ppT>
133 bool r1cs_se_ppzksnark_processed_verification_key<ppT>::operator==(
134 const r1cs_se_ppzksnark_processed_verification_key<ppT> &other) const
137 this->G_alpha == other.G_alpha && this->H_beta == other.H_beta &&
138 this->G_alpha_H_beta_ml == other.G_alpha_H_beta_ml &&
139 this->G_gamma_pc == other.G_gamma_pc &&
140 this->H_gamma_pc == other.H_gamma_pc && this->H_pc == other.H_pc &&
141 this->query == other.query);
144 template<typename ppT>
145 std::ostream &operator<<(
147 const r1cs_se_ppzksnark_processed_verification_key<ppT> &pvk)
149 out << pvk.G_alpha << OUTPUT_NEWLINE;
150 out << pvk.H_beta << OUTPUT_NEWLINE;
151 out << pvk.G_alpha_H_beta_ml << OUTPUT_NEWLINE;
152 out << pvk.G_gamma_pc << OUTPUT_NEWLINE;
153 out << pvk.H_gamma_pc << OUTPUT_NEWLINE;
154 out << pvk.H_pc << OUTPUT_NEWLINE;
155 out << pvk.query << OUTPUT_NEWLINE;
160 template<typename ppT>
161 std::istream &operator>>(
162 std::istream &in, r1cs_se_ppzksnark_processed_verification_key<ppT> &pvk)
165 libff::consume_OUTPUT_NEWLINE(in);
167 libff::consume_OUTPUT_NEWLINE(in);
168 in >> pvk.G_alpha_H_beta_ml;
169 libff::consume_OUTPUT_NEWLINE(in);
170 in >> pvk.G_gamma_pc;
171 libff::consume_OUTPUT_NEWLINE(in);
172 in >> pvk.H_gamma_pc;
173 libff::consume_OUTPUT_NEWLINE(in);
175 libff::consume_OUTPUT_NEWLINE(in);
177 libff::consume_OUTPUT_NEWLINE(in);
182 template<typename ppT>
183 bool r1cs_se_ppzksnark_proof<ppT>::operator==(
184 const r1cs_se_ppzksnark_proof<ppT> &other) const
186 return (this->A == other.A && this->B == other.B && this->C == other.C);
189 template<typename ppT>
190 std::ostream &operator<<(
191 std::ostream &out, const r1cs_se_ppzksnark_proof<ppT> &proof)
193 out << proof.A << OUTPUT_NEWLINE;
194 out << proof.B << OUTPUT_NEWLINE;
195 out << proof.C << OUTPUT_NEWLINE;
200 template<typename ppT>
201 std::istream &operator>>(std::istream &in, r1cs_se_ppzksnark_proof<ppT> &proof)
204 libff::consume_OUTPUT_NEWLINE(in);
206 libff::consume_OUTPUT_NEWLINE(in);
208 libff::consume_OUTPUT_NEWLINE(in);
213 template<typename ppT>
214 r1cs_se_ppzksnark_verification_key<ppT> r1cs_se_ppzksnark_verification_key<
215 ppT>::dummy_verification_key(const size_t input_size)
217 r1cs_se_ppzksnark_verification_key<ppT> result;
218 result.H = libff::Fr<ppT>::random_element() * libff::G2<ppT>::one();
219 result.G_alpha = libff::Fr<ppT>::random_element() * libff::G1<ppT>::one();
220 result.H_beta = libff::Fr<ppT>::random_element() * libff::G2<ppT>::one();
221 result.G_gamma = libff::Fr<ppT>::random_element() * libff::G1<ppT>::one();
222 result.H_gamma = libff::Fr<ppT>::random_element() * libff::G2<ppT>::one();
224 libff::G1_vector<ppT> v;
225 for (size_t i = 0; i < input_size + 1; ++i) {
227 libff::Fr<ppT>::random_element() * libff::G1<ppT>::one());
229 result.query = std::move(v);
234 template<typename ppT, libff::multi_exp_base_form BaseForm>
235 r1cs_se_ppzksnark_keypair<ppT> r1cs_se_ppzksnark_generator(
236 const r1cs_se_ppzksnark_constraint_system<ppT> &cs)
238 libff::enter_block("Call to r1cs_se_ppzksnark_generator");
241 * draw random element t at which the SAP is evaluated.
242 * it should be the case that Z(t) != 0
244 const std::shared_ptr<libfqfft::evaluation_domain<libff::Fr<ppT>>> domain =
245 r1cs_to_sap_get_domain(cs);
248 t = libff::Fr<ppT>::random_element();
249 } while (domain->compute_vanishing_polynomial(t).is_zero());
251 sap_instance_evaluation<libff::Fr<ppT>> sap_inst =
252 r1cs_to_sap_instance_map_with_evaluation(cs, t);
254 libff::print_indent();
255 printf("* SAP number of variables: %zu\n", sap_inst.num_variables());
256 libff::print_indent();
257 printf("* SAP pre degree: %zu\n", cs.constraints.size());
258 libff::print_indent();
259 printf("* SAP degree: %zu\n", sap_inst.degree());
260 libff::print_indent();
261 printf("* SAP number of input variables: %zu\n", sap_inst.num_inputs());
263 libff::enter_block("Compute query densities");
264 size_t non_zero_At = 0;
265 for (size_t i = 0; i < sap_inst.num_variables() + 1; ++i) {
266 if (!sap_inst.At[i].is_zero()) {
270 libff::leave_block("Compute query densities");
272 libff::Fr_vector<ppT> At = std::move(sap_inst.At);
273 libff::Fr_vector<ppT> Ct = std::move(sap_inst.Ct);
274 libff::Fr_vector<ppT> Ht = std::move(sap_inst.Ht);
276 * sap_inst.{A,C,H}t are now in an unspecified state,
277 * but we do not use them below
280 const libff::Fr<ppT> alpha = libff::Fr<ppT>::random_element(),
281 beta = libff::Fr<ppT>::random_element(),
282 gamma = libff::Fr<ppT>::random_element();
283 const libff::G1<ppT> G = libff::G1<ppT>::random_element();
284 const libff::G2<ppT> H = libff::G2<ppT>::random_element();
286 libff::enter_block("Generating G multiexp table");
287 size_t G_exp_count = sap_inst.num_inputs() + 1 // verifier_query
288 + non_zero_At // A_query
289 + sap_inst.degree() +
292 + sap_inst.num_variables() - sap_inst.num_inputs() +
293 sap_inst.num_variables() + 1, // C_query_2
294 G_window = libff::get_exp_window_size<libff::G1<ppT>>(G_exp_count);
295 libff::print_indent();
296 printf("* G window: %zu\n", G_window);
297 libff::window_table<libff::G1<ppT>> G_table =
298 get_window_table(libff::Fr<ppT>::size_in_bits(), G_window, G);
299 libff::leave_block("Generating G multiexp table");
301 libff::enter_block("Generating H_gamma multiexp table");
302 libff::G2<ppT> H_gamma = gamma * H;
303 size_t H_gamma_exp_count = non_zero_At, // B_query
305 libff::get_exp_window_size<libff::G2<ppT>>(H_gamma_exp_count);
306 libff::print_indent();
307 printf("* H_gamma window: %zu\n", H_gamma_window);
308 libff::window_table<libff::G2<ppT>> H_gamma_table = get_window_table(
309 libff::Fr<ppT>::size_in_bits(), H_gamma_window, H_gamma);
310 libff::leave_block("Generating H_gamma multiexp table");
312 libff::enter_block("Generate R1CS verification key");
313 libff::G1<ppT> G_alpha = alpha * G;
314 libff::G2<ppT> H_beta = beta * H;
316 libff::Fr_vector<ppT> tmp_exponents;
317 tmp_exponents.reserve(sap_inst.num_inputs() + 1);
318 for (size_t i = 0; i <= sap_inst.num_inputs(); ++i) {
319 tmp_exponents.emplace_back(gamma * Ct[i] + (alpha + beta) * At[i]);
321 libff::G1_vector<ppT> verifier_query =
322 libff::batch_exp<libff::G1<ppT>, libff::Fr<ppT>>(
323 libff::Fr<ppT>::size_in_bits(), G_window, G_table, tmp_exponents);
324 tmp_exponents.clear();
326 libff::leave_block("Generate R1CS verification key");
328 libff::enter_block("Generate R1CS proving key");
330 libff::enter_block("Compute the A-query", false);
331 tmp_exponents.reserve(sap_inst.num_variables() + 1);
332 for (size_t i = 0; i < At.size(); i++) {
333 tmp_exponents.emplace_back(gamma * At[i]);
336 libff::G1_vector<ppT> A_query =
337 libff::batch_exp<libff::G1<ppT>, libff::Fr<ppT>>(
338 libff::Fr<ppT>::size_in_bits(), G_window, G_table, tmp_exponents);
339 tmp_exponents.clear();
340 if (BaseForm == libff::multi_exp_base_form_special) {
341 libff::batch_to_special<libff::G1<ppT>>(A_query);
343 libff::leave_block("Compute the A-query", false);
345 libff::enter_block("Compute the B-query", false);
346 libff::G2_vector<ppT> B_query =
347 libff::batch_exp<libff::G2<ppT>, libff::Fr<ppT>>(
348 libff::Fr<ppT>::size_in_bits(), H_gamma_window, H_gamma_table, At);
349 if (BaseForm == libff::multi_exp_base_form_special) {
350 libff::batch_to_special<libff::G2<ppT>>(B_query);
352 libff::leave_block("Compute the B-query", false);
354 libff::enter_block("Compute the G_gamma-query", false);
355 libff::G1<ppT> G_gamma = gamma * G;
356 libff::G1<ppT> G_gamma_Z = sap_inst.Zt * G_gamma;
357 libff::G2<ppT> H_gamma_Z = sap_inst.Zt * H_gamma;
358 libff::G1<ppT> G_ab_gamma_Z = (alpha + beta) * G_gamma_Z;
359 libff::G1<ppT> G_gamma2_Z2 = (sap_inst.Zt * gamma) * G_gamma_Z;
361 tmp_exponents.reserve(sap_inst.degree() + 1);
363 /* Compute the vector G_gamma2_Z_t := Z(t) * t^i * gamma^2 * G */
364 libff::Fr<ppT> gamma2_Z_t = sap_inst.Zt * gamma.squared();
365 for (size_t i = 0; i < sap_inst.degree() + 1; ++i) {
366 tmp_exponents.emplace_back(gamma2_Z_t);
369 libff::G1_vector<ppT> G_gamma2_Z_t =
370 libff::batch_exp<libff::G1<ppT>, libff::Fr<ppT>>(
371 libff::Fr<ppT>::size_in_bits(), G_window, G_table, tmp_exponents);
372 tmp_exponents.clear();
373 if (BaseForm == libff::multi_exp_base_form_special) {
374 libff::batch_to_special<libff::G1<ppT>>(G_gamma2_Z_t);
376 libff::leave_block("Compute the G_gamma-query", false);
378 libff::enter_block("Compute the C_1-query", false);
379 tmp_exponents.reserve(sap_inst.num_variables() - sap_inst.num_inputs());
380 for (size_t i = sap_inst.num_inputs() + 1; i <= sap_inst.num_variables();
382 tmp_exponents.emplace_back(
383 gamma * (gamma * Ct[i] + (alpha + beta) * At[i]));
385 libff::G1_vector<ppT> C_query_1 =
386 libff::batch_exp<libff::G1<ppT>, libff::Fr<ppT>>(
387 libff::Fr<ppT>::size_in_bits(), G_window, G_table, tmp_exponents);
388 tmp_exponents.clear();
389 if (BaseForm == libff::multi_exp_base_form_special) {
390 libff::batch_to_special<libff::G1<ppT>>(C_query_1);
392 libff::leave_block("Compute the C_1-query", false);
394 libff::enter_block("Compute the C_2-query", false);
395 tmp_exponents.reserve(sap_inst.num_variables() + 1);
396 libff::Fr<ppT> double_gamma2_Z = gamma * gamma * sap_inst.Zt;
397 double_gamma2_Z = double_gamma2_Z + double_gamma2_Z;
398 for (size_t i = 0; i <= sap_inst.num_variables(); ++i) {
399 tmp_exponents.emplace_back(double_gamma2_Z * At[i]);
401 libff::G1_vector<ppT> C_query_2 =
402 libff::batch_exp<libff::G1<ppT>, libff::Fr<ppT>>(
403 libff::Fr<ppT>::size_in_bits(), G_window, G_table, tmp_exponents);
404 tmp_exponents.clear();
405 if (BaseForm == libff::multi_exp_base_form_special) {
406 libff::batch_to_special<libff::G1<ppT>>(C_query_2);
408 libff::leave_block("Compute the C_2-query", false);
410 libff::leave_block("Generate R1CS proving key");
412 libff::leave_block("Call to r1cs_se_ppzksnark_generator");
414 r1cs_se_ppzksnark_verification_key<ppT> vk =
415 r1cs_se_ppzksnark_verification_key<ppT>(
416 H, G_alpha, H_beta, G_gamma, H_gamma, std::move(verifier_query));
418 r1cs_se_ppzksnark_constraint_system<ppT> cs_copy(cs);
420 r1cs_se_ppzksnark_proving_key<ppT> pk = r1cs_se_ppzksnark_proving_key<ppT>(
423 std::move(C_query_1),
424 std::move(C_query_2),
429 std::move(G_gamma2_Z_t),
435 return r1cs_se_ppzksnark_keypair<ppT>(std::move(pk), std::move(vk));
440 libff::multi_exp_method Method,
441 libff::multi_exp_base_form BaseForm>
442 r1cs_se_ppzksnark_proof<ppT> r1cs_se_ppzksnark_prover(
443 const r1cs_se_ppzksnark_proving_key<ppT> &pk,
444 const r1cs_se_ppzksnark_primary_input<ppT> &primary_input,
445 const r1cs_se_ppzksnark_auxiliary_input<ppT> &auxiliary_input)
447 libff::enter_block("Call to r1cs_se_ppzksnark_prover");
450 assert(pk.constraint_system.is_satisfied(primary_input, auxiliary_input));
453 const libff::Fr<ppT> d1 = libff::Fr<ppT>::random_element(),
454 d2 = libff::Fr<ppT>::random_element();
456 libff::enter_block("Compute the polynomial H");
457 const sap_witness<libff::Fr<ppT>> sap_wit = r1cs_to_sap_witness_map(
458 pk.constraint_system, primary_input, auxiliary_input, d1, d2);
459 libff::leave_block("Compute the polynomial H");
462 const libff::Fr<ppT> t = libff::Fr<ppT>::random_element();
463 sap_instance_evaluation<libff::Fr<ppT>> sap_inst =
464 r1cs_to_sap_instance_map_with_evaluation(pk.constraint_system, t);
465 assert(sap_inst.is_satisfied(sap_wit));
469 assert(pk.A_query.size() == sap_wit.num_variables() + 1);
470 assert(pk.B_query.size() == sap_wit.num_variables() + 1);
472 pk.C_query_1.size() == sap_wit.num_variables() - sap_wit.num_inputs());
473 assert(pk.C_query_2.size() == sap_wit.num_variables() + 1);
474 assert(pk.G_gamma2_Z_t.size() >= sap_wit.degree() - 1);
478 const size_t chunks =
479 omp_get_max_threads(); // to override, set OMP_NUM_THREADS env var or
480 // call omp_set_num_threads()
482 const size_t chunks = 1;
485 const libff::Fr<ppT> r = libff::Fr<ppT>::random_element();
487 libff::enter_block("Compute the proof");
489 libff::enter_block("Compute answer to A-query", false);
491 * compute A = G^{gamma * (\sum_{i=0}^m input_i * A_i(t) + r * Z(t))}
492 * = \prod_{i=0}^m (G^{gamma * A_i(t)})^{input_i)
493 * * (G^{gamma * Z(t)})^r
494 * = \prod_{i=0}^m A_query[i]^{input_i} * G_gamma_Z^r
498 pk.A_query[0] + // i = 0 is a special case because input_i = 1
499 sap_wit.d1 * pk.G_gamma_Z + // ZK-patch
500 libff::multi_exp<libff::G1<ppT>, libff::Fr<ppT>, Method, BaseForm>(
501 pk.A_query.begin() + 1,
503 sap_wit.coefficients_for_ACs.begin(),
504 sap_wit.coefficients_for_ACs.end(),
507 libff::leave_block("Compute answer to A-query", false);
509 libff::enter_block("Compute answer to B-query", false);
511 * compute B exactly as A, except with H as the base
515 pk.B_query[0] + // i = 0 is a special case because input_i = 1
516 sap_wit.d1 * pk.H_gamma_Z + // ZK-patch
517 libff::multi_exp<libff::G2<ppT>, libff::Fr<ppT>, Method, BaseForm>(
518 pk.B_query.begin() + 1,
520 sap_wit.coefficients_for_ACs.begin(),
521 sap_wit.coefficients_for_ACs.end(),
523 libff::leave_block("Compute answer to B-query", false);
525 libff::enter_block("Compute answer to C-query", false);
527 * compute C = G^{f(input) +
528 * r^2 * gamma^2 * Z(t)^2 +
529 * r * (alpha + beta) * gamma * Z(t) +
530 * 2 * r * gamma^2 * Z(t) * \sum_{i=0}^m input_i A_i(t) +
531 * gamma^2 * Z(t) * H(t)}
532 * where G^{f(input)} = \prod_{i=l+1}^m C_query_1 * input_i
533 * and G^{2 * r * gamma^2 * Z(t) * \sum_{i=0}^m input_i A_i(t)} =
534 * = \prod_{i=0}^m C_query_2 * input_i
537 libff::multi_exp<libff::G1<ppT>, libff::Fr<ppT>, Method, BaseForm>(
538 pk.C_query_1.begin(),
540 sap_wit.coefficients_for_ACs.begin() + sap_wit.num_inputs(),
541 sap_wit.coefficients_for_ACs.end(),
543 (r * r) * pk.G_gamma2_Z2 + r * pk.G_ab_gamma_Z +
544 sap_wit.d1 * pk.G_ab_gamma_Z + // ZK-patch
545 r * pk.C_query_2[0] + // i = 0 is a special case for C_query_2
546 (r + r) * sap_wit.d1 * pk.G_gamma2_Z2 + // ZK-patch for C_query_2
547 r * libff::multi_exp<libff::G1<ppT>, libff::Fr<ppT>, Method, BaseForm>(
548 pk.C_query_2.begin() + 1,
550 sap_wit.coefficients_for_ACs.begin(),
551 sap_wit.coefficients_for_ACs.end(),
553 sap_wit.d2 * pk.G_gamma2_Z_t[0] + // ZK-patch
554 libff::multi_exp<libff::G1<ppT>, libff::Fr<ppT>, Method, BaseForm>(
555 pk.G_gamma2_Z_t.begin(),
556 pk.G_gamma2_Z_t.end(),
557 sap_wit.coefficients_for_H.begin(),
558 sap_wit.coefficients_for_H.end(),
560 libff::leave_block("Compute answer to C-query", false);
562 libff::leave_block("Compute the proof");
564 libff::leave_block("Call to r1cs_se_ppzksnark_prover");
566 r1cs_se_ppzksnark_proof<ppT> proof =
567 r1cs_se_ppzksnark_proof<ppT>(std::move(A), std::move(B), std::move(C));
573 template<typename ppT>
574 r1cs_se_ppzksnark_processed_verification_key<ppT>
575 r1cs_se_ppzksnark_verifier_process_vk(
576 const r1cs_se_ppzksnark_verification_key<ppT> &vk)
578 libff::enter_block("Call to r1cs_se_ppzksnark_verifier_process_vk");
580 libff::G1_precomp<ppT> G_alpha_pc = ppT::precompute_G1(vk.G_alpha);
581 libff::G2_precomp<ppT> H_beta_pc = ppT::precompute_G2(vk.H_beta);
583 r1cs_se_ppzksnark_processed_verification_key<ppT> pvk;
584 pvk.G_alpha = vk.G_alpha;
585 pvk.H_beta = vk.H_beta;
586 pvk.G_alpha_H_beta_ml = ppT::miller_loop(G_alpha_pc, H_beta_pc);
587 pvk.G_gamma_pc = ppT::precompute_G1(vk.G_gamma);
588 pvk.H_gamma_pc = ppT::precompute_G2(vk.H_gamma);
589 pvk.H_pc = ppT::precompute_G2(vk.H);
591 pvk.query = vk.query;
593 libff::leave_block("Call to r1cs_se_ppzksnark_verifier_process_vk");
598 template<typename ppT>
599 bool r1cs_se_ppzksnark_online_verifier_weak_IC(
600 const r1cs_se_ppzksnark_processed_verification_key<ppT> &pvk,
601 const r1cs_se_ppzksnark_primary_input<ppT> &primary_input,
602 const r1cs_se_ppzksnark_proof<ppT> &proof)
604 libff::enter_block("Call to r1cs_se_ppzksnark_online_verifier_weak_IC");
608 libff::enter_block("Check if the proof is well-formed");
609 if (!proof.is_well_formed()) {
610 if (!libff::inhibit_profiling_info) {
611 libff::print_indent();
612 printf("At least one of the proof elements does not lie on the "
617 libff::leave_block("Check if the proof is well-formed");
619 libff::enter_block("Pairing computations");
622 const size_t chunks =
623 omp_get_max_threads(); // to override, set OMP_NUM_THREADS env var or
624 // call omp_set_num_threads()
626 const size_t chunks = 1;
629 libff::enter_block("Check first test");
631 * e(A*G^{alpha}, B*H^{beta}) = e(G^{alpha}, H^{beta}) * e(G^{psi},
634 * where psi = \sum_{i=0}^l input_i pvk.query[i]
636 libff::G1<ppT> G_psi =
637 pvk.query[0] + libff::multi_exp<
640 libff::multi_exp_method_bos_coster>(
641 pvk.query.begin() + 1,
643 primary_input.begin(),
647 libff::Fqk<ppT> test1_l = ppT::miller_loop(
648 ppT::precompute_G1(proof.A + pvk.G_alpha),
649 ppT::precompute_G2(proof.B + pvk.H_beta)),
650 test1_r1 = pvk.G_alpha_H_beta_ml,
651 test1_r2 = ppT::miller_loop(
652 ppT::precompute_G1(G_psi), pvk.H_gamma_pc),
654 ppT::miller_loop(ppT::precompute_G1(proof.C), pvk.H_pc);
655 libff::GT<ppT> test1 = ppT::final_exponentiation(
656 test1_l.unitary_inverse() * test1_r1 * test1_r2 * test1_r3);
658 if (test1 != libff::GT<ppT>::one()) {
659 if (!libff::inhibit_profiling_info) {
660 libff::print_indent();
661 printf("First test failed.\n");
665 libff::leave_block("Check first test");
667 libff::enter_block("Check second test");
669 * e(A, H^{gamma}) = e(G^{gamma}, B)
671 libff::Fqk<ppT> test2_l = ppT::miller_loop(
672 ppT::precompute_G1(proof.A), pvk.H_gamma_pc),
673 test2_r = ppT::miller_loop(
674 pvk.G_gamma_pc, ppT::precompute_G2(proof.B));
675 libff::GT<ppT> test2 =
676 ppT::final_exponentiation(test2_l * test2_r.unitary_inverse());
678 if (test2 != libff::GT<ppT>::one()) {
679 if (!libff::inhibit_profiling_info) {
680 libff::print_indent();
681 printf("Second test failed.\n");
685 libff::leave_block("Check second test");
686 libff::leave_block("Pairing computations");
687 libff::leave_block("Call to r1cs_se_ppzksnark_online_verifier_weak_IC");
692 template<typename ppT>
693 bool r1cs_se_ppzksnark_verifier_weak_IC(
694 const r1cs_se_ppzksnark_verification_key<ppT> &vk,
695 const r1cs_se_ppzksnark_primary_input<ppT> &primary_input,
696 const r1cs_se_ppzksnark_proof<ppT> &proof)
698 libff::enter_block("Call to r1cs_se_ppzksnark_verifier_weak_IC");
699 r1cs_se_ppzksnark_processed_verification_key<ppT> pvk =
700 r1cs_se_ppzksnark_verifier_process_vk<ppT>(vk);
701 bool result = r1cs_se_ppzksnark_online_verifier_weak_IC<ppT>(
702 pvk, primary_input, proof);
703 libff::leave_block("Call to r1cs_se_ppzksnark_verifier_weak_IC");
707 template<typename ppT>
708 bool r1cs_se_ppzksnark_online_verifier_strong_IC(
709 const r1cs_se_ppzksnark_processed_verification_key<ppT> &pvk,
710 const r1cs_se_ppzksnark_primary_input<ppT> &primary_input,
711 const r1cs_se_ppzksnark_proof<ppT> &proof)
713 libff::enter_block("Call to r1cs_se_ppzksnark_online_verifier_strong_IC");
716 if (pvk.query.size() != primary_input.size() + 1) {
717 libff::print_indent();
719 "Input length differs from expected (got %zu, expected %zu).\n",
720 primary_input.size(),
724 result = r1cs_se_ppzksnark_online_verifier_weak_IC(
725 pvk, primary_input, proof);
728 libff::leave_block("Call to r1cs_se_ppzksnark_online_verifier_strong_IC");
732 template<typename ppT>
733 bool r1cs_se_ppzksnark_verifier_strong_IC(
734 const r1cs_se_ppzksnark_verification_key<ppT> &vk,
735 const r1cs_se_ppzksnark_primary_input<ppT> &primary_input,
736 const r1cs_se_ppzksnark_proof<ppT> &proof)
738 libff::enter_block("Call to r1cs_se_ppzksnark_verifier_strong_IC");
739 r1cs_se_ppzksnark_processed_verification_key<ppT> pvk =
740 r1cs_se_ppzksnark_verifier_process_vk<ppT>(vk);
741 bool result = r1cs_se_ppzksnark_online_verifier_strong_IC<ppT>(
742 pvk, primary_input, proof);
743 libff::leave_block("Call to r1cs_se_ppzksnark_verifier_strong_IC");
747 } // namespace libsnark
748 #endif // R1CS_SE_PPZKSNARK_TCC_