2 *****************************************************************************
4 Implementation of interfaces for a ppzkADSNARK for R1CS.
6 See r1cs_ppzkadsnark.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_PPZKADSNARK_TCC_
15 #define R1CS_PPZKADSNARK_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_ppzkadsnark_pub_auth_prms<ppT>::operator==(
38 const r1cs_ppzkadsnark_pub_auth_prms<ppT> &other) const
40 return (this->I1 == other.I1);
43 template<typename ppT>
44 std::ostream &operator<<(
45 std::ostream &out, const r1cs_ppzkadsnark_pub_auth_prms<ppT> &pap)
52 template<typename ppT>
53 std::istream &operator>>(
54 std::istream &in, r1cs_ppzkadsnark_pub_auth_prms<ppT> &pap)
61 template<typename ppT>
62 bool r1cs_ppzkadsnark_sec_auth_key<ppT>::operator==(
63 const r1cs_ppzkadsnark_sec_auth_key<ppT> &other) const
65 return (this->i == other.i) && (this->skp == other.skp) &&
69 template<typename ppT>
70 std::ostream &operator<<(
71 std::ostream &out, const r1cs_ppzkadsnark_sec_auth_key<ppT> &key)
80 template<typename ppT>
81 std::istream &operator>>(
82 std::istream &in, r1cs_ppzkadsnark_sec_auth_key<ppT> &key)
91 template<typename ppT>
92 bool r1cs_ppzkadsnark_pub_auth_key<ppT>::operator==(
93 const r1cs_ppzkadsnark_pub_auth_key<ppT> &other) const
95 return (this->minusI2 == other.minusI2) && (this->vkp == other.vkp);
98 template<typename ppT>
99 std::ostream &operator<<(
100 std::ostream &out, const r1cs_ppzkadsnark_pub_auth_key<ppT> &key)
108 template<typename ppT>
109 std::istream &operator>>(
110 std::istream &in, r1cs_ppzkadsnark_pub_auth_key<ppT> &key)
118 template<typename ppT>
119 bool r1cs_ppzkadsnark_auth_data<ppT>::operator==(
120 const r1cs_ppzkadsnark_auth_data<ppT> &other) const
122 return (this->mu == other.mu) && (this->Lambda == other.Lambda) &&
123 (this->sigma == other.sigma);
126 template<typename ppT>
127 std::ostream &operator<<(
128 std::ostream &out, const r1cs_ppzkadsnark_auth_data<ppT> &data)
137 template<typename ppT>
138 std::istream &operator>>(
139 std::istream &in, r1cs_ppzkadsnark_auth_data<ppT> &data)
148 template<typename ppT>
149 bool r1cs_ppzkadsnark_proving_key<ppT>::operator==(
150 const r1cs_ppzkadsnark_proving_key<ppT> &other) const
153 this->A_query == other.A_query && this->B_query == other.B_query &&
154 this->C_query == other.C_query && this->H_query == other.H_query &&
155 this->K_query == other.K_query && this->rA_i_Z_g1 == other.rA_i_Z_g1 &&
156 this->constraint_system == other.constraint_system);
159 template<typename ppT>
160 std::ostream &operator<<(
161 std::ostream &out, const r1cs_ppzkadsnark_proving_key<ppT> &pk)
169 out << pk.constraint_system;
174 template<typename ppT>
175 std::istream &operator>>(
176 std::istream &in, r1cs_ppzkadsnark_proving_key<ppT> &pk)
184 in >> pk.constraint_system;
189 template<typename ppT>
190 bool r1cs_ppzkadsnark_verification_key<ppT>::operator==(
191 const r1cs_ppzkadsnark_verification_key<ppT> &other) const
194 this->alphaA_g2 == other.alphaA_g2 &&
195 this->alphaB_g1 == other.alphaB_g1 &&
196 this->alphaC_g2 == other.alphaC_g2 &&
197 this->gamma_g2 == other.gamma_g2 &&
198 this->gamma_beta_g1 == other.gamma_beta_g1 &&
199 this->gamma_beta_g2 == other.gamma_beta_g2 &&
200 this->rC_Z_g2 == other.rC_Z_g2 && this->A0 == other.A0 &&
201 this->Ain == other.Ain);
204 template<typename ppT>
205 std::ostream &operator<<(
206 std::ostream &out, const r1cs_ppzkadsnark_verification_key<ppT> &vk)
208 out << vk.alphaA_g2 << OUTPUT_NEWLINE;
209 out << vk.alphaB_g1 << OUTPUT_NEWLINE;
210 out << vk.alphaC_g2 << OUTPUT_NEWLINE;
211 out << vk.gamma_g2 << OUTPUT_NEWLINE;
212 out << vk.gamma_beta_g1 << OUTPUT_NEWLINE;
213 out << vk.gamma_beta_g2 << OUTPUT_NEWLINE;
214 out << vk.rC_Z_g2 << OUTPUT_NEWLINE;
215 out << vk.A0 << OUTPUT_NEWLINE;
216 out << vk.Ain << OUTPUT_NEWLINE;
221 template<typename ppT>
222 std::istream &operator>>(
223 std::istream &in, r1cs_ppzkadsnark_verification_key<ppT> &vk)
226 libff::consume_OUTPUT_NEWLINE(in);
228 libff::consume_OUTPUT_NEWLINE(in);
230 libff::consume_OUTPUT_NEWLINE(in);
232 libff::consume_OUTPUT_NEWLINE(in);
233 in >> vk.gamma_beta_g1;
234 libff::consume_OUTPUT_NEWLINE(in);
235 in >> vk.gamma_beta_g2;
236 libff::consume_OUTPUT_NEWLINE(in);
238 libff::consume_OUTPUT_NEWLINE(in);
240 libff::consume_OUTPUT_NEWLINE(in);
242 libff::consume_OUTPUT_NEWLINE(in);
247 template<typename ppT>
248 bool r1cs_ppzkadsnark_processed_verification_key<ppT>::operator==(
249 const r1cs_ppzkadsnark_processed_verification_key<ppT> &other) const
252 (this->pp_G2_one_precomp == other.pp_G2_one_precomp &&
253 this->vk_alphaA_g2_precomp == other.vk_alphaA_g2_precomp &&
254 this->vk_alphaB_g1_precomp == other.vk_alphaB_g1_precomp &&
255 this->vk_alphaC_g2_precomp == other.vk_alphaC_g2_precomp &&
256 this->vk_rC_Z_g2_precomp == other.vk_rC_Z_g2_precomp &&
257 this->vk_gamma_g2_precomp == other.vk_gamma_g2_precomp &&
258 this->vk_gamma_beta_g1_precomp == other.vk_gamma_beta_g1_precomp &&
259 this->vk_gamma_beta_g2_precomp == other.vk_gamma_beta_g2_precomp &&
260 this->vk_rC_i_g2_precomp == other.vk_rC_i_g2_precomp &&
261 this->A0 == other.A0 && this->Ain == other.Ain &&
262 this->proof_g_vki_precomp.size() == other.proof_g_vki_precomp.size());
264 for (size_t i = 0; i < this->proof_g_vki_precomp.size(); i++)
266 this->proof_g_vki_precomp[i] == other.proof_g_vki_precomp[i];
271 template<typename ppT>
272 std::ostream &operator<<(
274 const r1cs_ppzkadsnark_processed_verification_key<ppT> &pvk)
276 out << pvk.pp_G2_one_precomp << OUTPUT_NEWLINE;
277 out << pvk.vk_alphaA_g2_precomp << OUTPUT_NEWLINE;
278 out << pvk.vk_alphaB_g1_precomp << OUTPUT_NEWLINE;
279 out << pvk.vk_alphaC_g2_precomp << OUTPUT_NEWLINE;
280 out << pvk.vk_rC_Z_g2_precomp << OUTPUT_NEWLINE;
281 out << pvk.vk_gamma_g2_precomp << OUTPUT_NEWLINE;
282 out << pvk.vk_gamma_beta_g1_precomp << OUTPUT_NEWLINE;
283 out << pvk.vk_gamma_beta_g2_precomp << OUTPUT_NEWLINE;
284 out << pvk.vk_rC_i_g2_precomp << OUTPUT_NEWLINE;
285 out << pvk.A0 << OUTPUT_NEWLINE;
286 out << pvk.Ain << OUTPUT_NEWLINE;
287 out << pvk.proof_g_vki_precomp << OUTPUT_NEWLINE;
292 template<typename ppT>
293 std::istream &operator>>(
294 std::istream &in, r1cs_ppzkadsnark_processed_verification_key<ppT> &pvk)
296 in >> pvk.pp_G2_one_precomp;
297 libff::consume_OUTPUT_NEWLINE(in);
298 in >> pvk.vk_alphaA_g2_precomp;
299 libff::consume_OUTPUT_NEWLINE(in);
300 in >> pvk.vk_alphaB_g1_precomp;
301 libff::consume_OUTPUT_NEWLINE(in);
302 in >> pvk.vk_alphaC_g2_precomp;
303 libff::consume_OUTPUT_NEWLINE(in);
304 in >> pvk.vk_rC_Z_g2_precomp;
305 libff::consume_OUTPUT_NEWLINE(in);
306 in >> pvk.vk_gamma_g2_precomp;
307 libff::consume_OUTPUT_NEWLINE(in);
308 in >> pvk.vk_gamma_beta_g1_precomp;
309 libff::consume_OUTPUT_NEWLINE(in);
310 in >> pvk.vk_gamma_beta_g2_precomp;
311 libff::consume_OUTPUT_NEWLINE(in);
312 in >> pvk.vk_rC_i_g2_precomp;
313 libff::consume_OUTPUT_NEWLINE(in);
315 libff::consume_OUTPUT_NEWLINE(in);
317 libff::consume_OUTPUT_NEWLINE(in);
318 in >> pvk.proof_g_vki_precomp;
319 libff::consume_OUTPUT_NEWLINE(in);
324 template<typename ppT>
325 bool r1cs_ppzkadsnark_proof<ppT>::operator==(
326 const r1cs_ppzkadsnark_proof<ppT> &other) const
329 this->g_A == other.g_A && this->g_B == other.g_B &&
330 this->g_C == other.g_C && this->g_H == other.g_H &&
331 this->g_K == other.g_K && this->g_Aau == other.g_Aau &&
332 this->muA == other.muA);
335 template<typename ppT>
336 std::ostream &operator<<(
337 std::ostream &out, const r1cs_ppzkadsnark_proof<ppT> &proof)
339 out << proof.g_A << OUTPUT_NEWLINE;
340 out << proof.g_B << OUTPUT_NEWLINE;
341 out << proof.g_C << OUTPUT_NEWLINE;
342 out << proof.g_H << OUTPUT_NEWLINE;
343 out << proof.g_K << OUTPUT_NEWLINE;
344 out << proof.g_Aau << OUTPUT_NEWLINE;
345 out << proof.muA << OUTPUT_NEWLINE;
350 template<typename ppT>
351 std::istream &operator>>(std::istream &in, r1cs_ppzkadsnark_proof<ppT> &proof)
354 libff::consume_OUTPUT_NEWLINE(in);
356 libff::consume_OUTPUT_NEWLINE(in);
358 libff::consume_OUTPUT_NEWLINE(in);
360 libff::consume_OUTPUT_NEWLINE(in);
362 libff::consume_OUTPUT_NEWLINE(in);
364 libff::consume_OUTPUT_NEWLINE(in);
366 libff::consume_OUTPUT_NEWLINE(in);
371 template<typename ppT>
372 r1cs_ppzkadsnark_verification_key<ppT> r1cs_ppzkadsnark_verification_key<
373 ppT>::dummy_verification_key(const size_t input_size)
375 r1cs_ppzkadsnark_verification_key<ppT> result;
376 result.alphaA_g2 = libff::Fr<snark_pp<ppT>>::random_element() *
377 libff::G2<snark_pp<ppT>>::one();
378 result.alphaB_g1 = libff::Fr<snark_pp<ppT>>::random_element() *
379 libff::G1<snark_pp<ppT>>::one();
380 result.alphaC_g2 = libff::Fr<snark_pp<ppT>>::random_element() *
381 libff::G2<snark_pp<ppT>>::one();
382 result.gamma_g2 = libff::Fr<snark_pp<ppT>>::random_element() *
383 libff::G2<snark_pp<ppT>>::one();
384 result.gamma_beta_g1 = libff::Fr<snark_pp<ppT>>::random_element() *
385 libff::G1<snark_pp<ppT>>::one();
386 result.gamma_beta_g2 = libff::Fr<snark_pp<ppT>>::random_element() *
387 libff::G2<snark_pp<ppT>>::one();
388 result.rC_Z_g2 = libff::Fr<snark_pp<ppT>>::random_element() *
389 libff::G2<snark_pp<ppT>>::one();
391 result.A0 = libff::Fr<snark_pp<ppT>>::random_element() *
392 libff::G1<snark_pp<ppT>>::one();
393 for (size_t i = 0; i < input_size; ++i) {
394 result.Ain.emplace_back(
395 libff::Fr<snark_pp<ppT>>::random_element() *
396 libff::G1<snark_pp<ppT>>::one());
402 template<typename ppT>
403 r1cs_ppzkadsnark_auth_keys<ppT> r1cs_ppzkadsnark_auth_generator(void)
405 kpT<ppT> sigkp = sigGen<ppT>();
406 r1cs_ppzkadsnark_prfKeyT<ppT> prfseed = prfGen<ppT>();
407 libff::Fr<snark_pp<ppT>> i = libff::Fr<snark_pp<ppT>>::random_element();
408 libff::G1<snark_pp<ppT>> I1 = i * libff::G1<snark_pp<ppT>>::one();
409 libff::G2<snark_pp<ppT>> minusI2 =
410 libff::G2<snark_pp<ppT>>::zero() - i * libff::G2<snark_pp<ppT>>::one();
411 return r1cs_ppzkadsnark_auth_keys<ppT>(
412 r1cs_ppzkadsnark_pub_auth_prms<ppT>(std::move(I1)),
413 r1cs_ppzkadsnark_pub_auth_key<ppT>(
414 std::move(minusI2), std::move(sigkp.vk)),
415 r1cs_ppzkadsnark_sec_auth_key<ppT>(
416 std::move(i), std::move(sigkp.sk), std::move(prfseed)));
419 template<typename ppT>
420 std::vector<r1cs_ppzkadsnark_auth_data<ppT>> r1cs_ppzkadsnark_auth_sign(
421 const std::vector<libff::Fr<snark_pp<ppT>>> &ins,
422 const r1cs_ppzkadsnark_sec_auth_key<ppT> &sk,
423 const std::vector<labelT> labels)
425 libff::enter_block("Call to r1cs_ppzkadsnark_auth_sign");
426 assert(labels.size() == ins.size());
427 std::vector<r1cs_ppzkadsnark_auth_data<ppT>> res;
428 res.reserve(ins.size());
429 for (size_t i = 0; i < ins.size(); i++) {
430 libff::Fr<snark_pp<ppT>> lambda = prfCompute<ppT>(sk.S, labels[i]);
431 libff::G2<snark_pp<ppT>> Lambda =
432 lambda * libff::G2<snark_pp<ppT>>::one();
433 r1cs_ppzkadsnark_sigT<ppT> sig =
434 sigSign<ppT>(sk.skp, labels[i], Lambda);
435 r1cs_ppzkadsnark_auth_data<ppT> val(
436 std::move(lambda + sk.i * ins[i]),
439 res.emplace_back(val);
441 libff::leave_block("Call to r1cs_ppzkadsnark_auth_sign");
442 return std::move(res);
446 template<typename ppT>
447 bool r1cs_ppzkadsnark_auth_verify(
448 const std::vector<libff::Fr<snark_pp<ppT>>> &data,
449 const std::vector<r1cs_ppzkadsnark_auth_data<ppT>> &auth_data,
450 const r1cs_ppzkadsnark_sec_auth_key<ppT> &sak,
451 const std::vector<labelT> &labels)
453 libff::enter_block("Call to r1cs_ppzkadsnark_auth_verify");
455 (data.size() == labels.size()) && (auth_data.size() == labels.size()));
457 for (size_t i = 0; i < data.size(); i++) {
458 libff::Fr<snark_pp<ppT>> lambda = prfCompute<ppT>(sak.S, labels[i]);
459 libff::Fr<snark_pp<ppT>> mup = lambda + sak.i * data[i];
460 res = res && (auth_data[i].mu == mup);
462 libff::leave_block("Call to r1cs_ppzkadsnark_auth_verify");
467 template<typename ppT>
468 bool r1cs_ppzkadsnark_auth_verify(
469 const std::vector<libff::Fr<snark_pp<ppT>>> &data,
470 const std::vector<r1cs_ppzkadsnark_auth_data<ppT>> &auth_data,
471 const r1cs_ppzkadsnark_pub_auth_key<ppT> &pak,
472 const std::vector<labelT> &labels)
474 libff::enter_block("Call to r1cs_ppzkadsnark_auth_verify");
475 assert((data.size() == labels.size()) && (data.size() == auth_data.size()));
477 for (size_t i = 0; i < auth_data.size(); i++) {
478 libff::G2<snark_pp<ppT>> Mup =
479 auth_data[i].Lambda - data[i] * pak.minusI2;
480 res = res && (auth_data[i].mu * libff::G2<snark_pp<ppT>>::one() == Mup);
483 pak.vkp, labels[i], auth_data[i].Lambda, auth_data[i].sigma);
485 libff::leave_block("Call to r1cs_ppzkadsnark_auth_verify");
489 template<typename ppT, libff::multi_exp_base_form BaseForm>
490 r1cs_ppzkadsnark_keypair<ppT> r1cs_ppzkadsnark_generator(
491 const r1cs_ppzkadsnark_constraint_system<ppT> &cs,
492 const r1cs_ppzkadsnark_pub_auth_prms<ppT> &prms)
494 libff::enter_block("Call to r1cs_ppzkadsnark_generator");
496 /* make the B_query "lighter" if possible */
497 r1cs_ppzkadsnark_constraint_system<ppT> cs_copy(cs);
498 cs_copy.swap_AB_if_beneficial();
500 /* draw random element at which the QAP is evaluated */
501 const libff::Fr<snark_pp<ppT>> t =
502 libff::Fr<snark_pp<ppT>>::random_element();
504 qap_instance_evaluation<libff::Fr<snark_pp<ppT>>> qap_inst =
505 r1cs_to_qap_instance_map_with_evaluation(cs_copy, t);
507 libff::print_indent();
508 printf("* QAP number of variables: %zu\n", qap_inst.num_variables());
509 libff::print_indent();
510 printf("* QAP pre degree: %zu\n", cs_copy.constraints.size());
511 libff::print_indent();
512 printf("* QAP degree: %zu\n", qap_inst.degree());
513 libff::print_indent();
514 printf("* QAP number of input variables: %zu\n", qap_inst.num_inputs());
516 libff::enter_block("Compute query densities");
517 size_t non_zero_At = 0, non_zero_Bt = 0, non_zero_Ct = 0, non_zero_Ht = 0;
518 for (size_t i = 0; i < qap_inst.num_variables() + 1; ++i) {
519 if (!qap_inst.At[i].is_zero()) {
522 if (!qap_inst.Bt[i].is_zero()) {
525 if (!qap_inst.Ct[i].is_zero()) {
529 for (size_t i = 0; i < qap_inst.degree() + 1; ++i) {
530 if (!qap_inst.Ht[i].is_zero()) {
534 libff::leave_block("Compute query densities");
536 libff::Fr_vector<snark_pp<ppT>> At =
537 std::move(qap_inst.At); // qap_inst.At is now in unspecified state, but
538 // we do not use it later
539 libff::Fr_vector<snark_pp<ppT>> Bt =
540 std::move(qap_inst.Bt); // qap_inst.Bt is now in unspecified state, but
541 // we do not use it later
542 libff::Fr_vector<snark_pp<ppT>> Ct =
543 std::move(qap_inst.Ct); // qap_inst.Ct is now in unspecified state, but
544 // we do not use it later
545 libff::Fr_vector<snark_pp<ppT>> Ht =
546 std::move(qap_inst.Ht); // qap_inst.Ht is now in unspecified state, but
547 // we do not use it later
549 /* append Zt to At,Bt,Ct with */
550 At.emplace_back(qap_inst.Zt);
551 Bt.emplace_back(qap_inst.Zt);
552 Ct.emplace_back(qap_inst.Zt);
554 const libff::Fr<snark_pp<ppT>>
555 alphaA = libff::Fr<snark_pp<ppT>>::random_element(),
556 alphaB = libff::Fr<snark_pp<ppT>>::random_element(),
557 alphaC = libff::Fr<snark_pp<ppT>>::random_element(),
558 rA = libff::Fr<snark_pp<ppT>>::random_element(),
559 rB = libff::Fr<snark_pp<ppT>>::random_element(),
560 beta = libff::Fr<snark_pp<ppT>>::random_element(),
561 gamma = libff::Fr<snark_pp<ppT>>::random_element();
562 const libff::Fr<snark_pp<ppT>> rC = rA * rB;
564 // construct the same-coefficient-check query (must happen before zeroing
565 // out the prefix of At)
566 libff::Fr_vector<snark_pp<ppT>> Kt;
567 Kt.reserve(qap_inst.num_variables() + 4);
568 for (size_t i = 0; i < qap_inst.num_variables() + 1; ++i) {
569 Kt.emplace_back(beta * (rA * At[i] + rB * Bt[i] + rC * Ct[i]));
571 Kt.emplace_back(beta * rA * qap_inst.Zt);
572 Kt.emplace_back(beta * rB * qap_inst.Zt);
573 Kt.emplace_back(beta * rC * qap_inst.Zt);
575 const size_t g1_exp_count =
576 2 * (non_zero_At - qap_inst.num_inputs() + non_zero_Ct) + non_zero_Bt +
577 non_zero_Ht + Kt.size();
578 const size_t g2_exp_count = non_zero_Bt;
581 libff::get_exp_window_size<libff::G1<snark_pp<ppT>>>(g1_exp_count);
583 libff::get_exp_window_size<libff::G2<snark_pp<ppT>>>(g2_exp_count);
584 libff::print_indent();
585 printf("* G1 window: %zu\n", g1_window);
586 libff::print_indent();
587 printf("* G2 window: %zu\n", g2_window);
590 const size_t chunks =
591 omp_get_max_threads(); // to override, set OMP_NUM_THREADS env var or
592 // call omp_set_num_threads()
594 const size_t chunks = 1;
597 libff::enter_block("Generating G1 multiexp table");
598 libff::window_table<libff::G1<snark_pp<ppT>>> g1_table = get_window_table(
599 libff::Fr<snark_pp<ppT>>::size_in_bits(),
601 libff::G1<snark_pp<ppT>>::one());
602 libff::leave_block("Generating G1 multiexp table");
604 libff::enter_block("Generating G2 multiexp table");
605 libff::window_table<libff::G2<snark_pp<ppT>>> g2_table = get_window_table(
606 libff::Fr<snark_pp<ppT>>::size_in_bits(),
608 libff::G2<snark_pp<ppT>>::one());
609 libff::leave_block("Generating G2 multiexp table");
611 libff::enter_block("Generate R1CS proving key");
613 libff::enter_block("Generate knowledge commitments");
614 libff::enter_block("Compute the A-query", false);
615 knowledge_commitment_vector<
616 libff::G1<snark_pp<ppT>>,
617 libff::G1<snark_pp<ppT>>>
618 A_query = kc_batch_exp(
619 libff::Fr<snark_pp<ppT>>::size_in_bits(),
628 BaseForm == libff::multi_exp_base_form_special);
629 libff::leave_block("Compute the A-query", false);
631 libff::enter_block("Compute the B-query", false);
632 knowledge_commitment_vector<
633 libff::G2<snark_pp<ppT>>,
634 libff::G1<snark_pp<ppT>>>
635 B_query = kc_batch_exp(
636 libff::Fr<snark_pp<ppT>>::size_in_bits(),
645 BaseForm == libff::multi_exp_base_form_special);
646 libff::leave_block("Compute the B-query", false);
648 libff::enter_block("Compute the C-query", false);
649 knowledge_commitment_vector<
650 libff::G1<snark_pp<ppT>>,
651 libff::G1<snark_pp<ppT>>>
652 C_query = kc_batch_exp(
653 libff::Fr<snark_pp<ppT>>::size_in_bits(),
662 BaseForm == libff::multi_exp_base_form_special);
663 libff::leave_block("Compute the C-query", false);
665 libff::enter_block("Compute the H-query", false);
666 libff::G1_vector<snark_pp<ppT>> H_query = batch_exp(
667 libff::Fr<snark_pp<ppT>>::size_in_bits(), g1_window, g1_table, Ht);
668 if (BaseForm == libff::multi_exp_base_form_special) {
669 libff::batch_to_special<libff::G1<snark_pp<ppT>>>(H_query);
671 libff::leave_block("Compute the H-query", false);
673 libff::enter_block("Compute the K-query", false);
674 libff::G1_vector<snark_pp<ppT>> K_query = batch_exp(
675 libff::Fr<snark_pp<ppT>>::size_in_bits(), g1_window, g1_table, Kt);
676 if (BaseForm == libff::multi_exp_base_form_special) {
677 libff::batch_to_special<libff::G1<snark_pp<ppT>>>(K_query);
679 libff::leave_block("Compute the K-query", false);
681 libff::leave_block("Generate knowledge commitments");
683 libff::leave_block("Generate R1CS proving key");
685 libff::enter_block("Generate R1CS verification key");
686 libff::G2<snark_pp<ppT>> alphaA_g2 =
687 alphaA * libff::G2<snark_pp<ppT>>::one();
688 libff::G1<snark_pp<ppT>> alphaB_g1 =
689 alphaB * libff::G1<snark_pp<ppT>>::one();
690 libff::G2<snark_pp<ppT>> alphaC_g2 =
691 alphaC * libff::G2<snark_pp<ppT>>::one();
692 libff::G2<snark_pp<ppT>> gamma_g2 = gamma * libff::G2<snark_pp<ppT>>::one();
693 libff::G1<snark_pp<ppT>> gamma_beta_g1 =
694 (gamma * beta) * libff::G1<snark_pp<ppT>>::one();
695 libff::G2<snark_pp<ppT>> gamma_beta_g2 =
696 (gamma * beta) * libff::G2<snark_pp<ppT>>::one();
697 libff::G2<snark_pp<ppT>> rC_Z_g2 =
698 (rC * qap_inst.Zt) * libff::G2<snark_pp<ppT>>::one();
700 libff::enter_block("Generate extra authentication elements");
701 libff::G1<snark_pp<ppT>> rA_i_Z_g1 = (rA * qap_inst.Zt) * prms.I1;
702 libff::leave_block("Generate extra authentication elements");
705 "Copy encoded input coefficients for R1CS verification key");
706 libff::G1<snark_pp<ppT>> A0 = A_query[0].g;
707 libff::G1_vector<snark_pp<ppT>> Ain;
708 Ain.reserve(qap_inst.num_inputs());
709 for (size_t i = 0; i < qap_inst.num_inputs(); ++i) {
710 Ain.emplace_back(A_query[1 + i].g);
714 "Copy encoded input coefficients for R1CS verification key");
716 libff::leave_block("Generate R1CS verification key");
718 libff::leave_block("Call to r1cs_ppzkadsnark_generator");
720 r1cs_ppzkadsnark_verification_key<ppT> vk =
721 r1cs_ppzkadsnark_verification_key<ppT>(
731 r1cs_ppzkadsnark_proving_key<ppT> pk = r1cs_ppzkadsnark_proving_key<ppT>(
737 std::move(rA_i_Z_g1),
743 return r1cs_ppzkadsnark_keypair<ppT>(std::move(pk), std::move(vk));
746 template<typename ppT>
747 r1cs_ppzkadsnark_proof<ppT> r1cs_ppzkadsnark_prover(
748 const r1cs_ppzkadsnark_proving_key<ppT> &pk,
749 const r1cs_ppzkadsnark_primary_input<ppT> &primary_input,
750 const r1cs_ppzkadsnark_auxiliary_input<ppT> &auxiliary_input,
751 const std::vector<r1cs_ppzkadsnark_auth_data<ppT>> &auth_data)
753 libff::enter_block("Call to r1cs_ppzkadsnark_prover");
756 assert(pk.constraint_system.is_satisfied(primary_input, auxiliary_input));
759 const libff::Fr<snark_pp<ppT>>
760 d1 = libff::Fr<snark_pp<ppT>>::random_element(),
761 d2 = libff::Fr<snark_pp<ppT>>::random_element(),
762 d3 = libff::Fr<snark_pp<ppT>>::random_element(),
763 dauth = libff::Fr<snark_pp<ppT>>::random_element();
765 libff::enter_block("Compute the polynomial H");
766 const qap_witness<libff::Fr<snark_pp<ppT>>> qap_wit =
767 r1cs_to_qap_witness_map(
768 pk.constraint_system,
774 libff::leave_block("Compute the polynomial H");
777 const libff::Fr<snark_pp<ppT>> t =
778 libff::Fr<snark_pp<ppT>>::random_element();
779 qap_instance_evaluation<libff::Fr<snark_pp<ppT>>> qap_inst =
780 r1cs_to_qap_instance_map_with_evaluation(pk.constraint_system, t);
781 assert(qap_inst.is_satisfied(qap_wit));
784 knowledge_commitment<libff::G1<snark_pp<ppT>>, libff::G1<snark_pp<ppT>>>
786 /* pk.A_query[0] + */ d1 * pk.A_query[qap_wit.num_variables() + 1];
787 knowledge_commitment<libff::G2<snark_pp<ppT>>, libff::G1<snark_pp<ppT>>>
788 g_B = pk.B_query[0] +
789 qap_wit.d2 * pk.B_query[qap_wit.num_variables() + 1];
790 knowledge_commitment<libff::G1<snark_pp<ppT>>, libff::G1<snark_pp<ppT>>>
791 g_C = pk.C_query[0] +
792 qap_wit.d3 * pk.C_query[qap_wit.num_variables() + 1];
794 knowledge_commitment<libff::G1<snark_pp<ppT>>, libff::G1<snark_pp<ppT>>>
795 g_Ain = dauth * pk.A_query[qap_wit.num_variables() + 1];
797 libff::G1<snark_pp<ppT>> g_H = libff::G1<snark_pp<ppT>>::zero();
798 libff::G1<snark_pp<ppT>> g_K =
799 (pk.K_query[0] + qap_wit.d1 * pk.K_query[qap_wit.num_variables() + 1] +
800 qap_wit.d2 * pk.K_query[qap_wit.num_variables() + 2] +
801 qap_wit.d3 * pk.K_query[qap_wit.num_variables() + 3]);
804 for (size_t i = 0; i < qap_wit.num_inputs() + 1; ++i) {
805 assert(pk.A_query[i].g == libff::G1<snark_pp<ppT>>::zero());
807 assert(pk.A_query.domain_size() == qap_wit.num_variables() + 2);
808 assert(pk.B_query.domain_size() == qap_wit.num_variables() + 2);
809 assert(pk.C_query.domain_size() == qap_wit.num_variables() + 2);
810 assert(pk.H_query.size() == qap_wit.degree() + 1);
811 assert(pk.K_query.size() == qap_wit.num_variables() + 4);
815 const size_t chunks =
816 omp_get_max_threads(); // to override, set OMP_NUM_THREADS env var or
817 // call omp_set_num_threads()
819 const size_t chunks = 1;
822 libff::enter_block("Compute the proof");
824 libff::enter_block("Compute answer to A-query", false);
826 kc_multi_exp_with_mixed_addition<
827 libff::G1<snark_pp<ppT>>,
828 libff::G1<snark_pp<ppT>>,
829 libff::Fr<snark_pp<ppT>>,
830 libff::multi_exp_method_bos_coster>(
832 1 + qap_wit.num_inputs(),
833 1 + qap_wit.num_variables(),
834 qap_wit.coefficients_for_ABCs.begin() + qap_wit.num_inputs(),
835 qap_wit.coefficients_for_ABCs.begin() + qap_wit.num_variables(),
837 libff::leave_block("Compute answer to A-query", false);
839 libff::enter_block("Compute answer to Ain-query", false);
841 kc_multi_exp_with_mixed_addition<
842 libff::G1<snark_pp<ppT>>,
843 libff::G1<snark_pp<ppT>>,
844 libff::Fr<snark_pp<ppT>>,
845 libff::multi_exp_method_bos_coster>(
848 1 + qap_wit.num_inputs(),
849 qap_wit.coefficients_for_ABCs.begin(),
850 qap_wit.coefficients_for_ABCs.begin() + qap_wit.num_inputs(),
852 // std :: cout << "The input proof term: " << g_Ain << "\n";
853 libff::leave_block("Compute answer to Ain-query", false);
855 libff::enter_block("Compute answer to B-query", false);
857 kc_multi_exp_with_mixed_addition<
858 libff::G2<snark_pp<ppT>>,
859 libff::G1<snark_pp<ppT>>,
860 libff::Fr<snark_pp<ppT>>,
861 libff::multi_exp_method_bos_coster>(
864 1 + qap_wit.num_variables(),
865 qap_wit.coefficients_for_ABCs.begin(),
866 qap_wit.coefficients_for_ABCs.begin() + qap_wit.num_variables(),
868 libff::leave_block("Compute answer to B-query", false);
870 libff::enter_block("Compute answer to C-query", false);
872 kc_multi_exp_with_mixed_addition<
873 libff::G1<snark_pp<ppT>>,
874 libff::G1<snark_pp<ppT>>,
875 libff::Fr<snark_pp<ppT>>,
876 libff::multi_exp_method_bos_coster>(
879 1 + qap_wit.num_variables(),
880 qap_wit.coefficients_for_ABCs.begin(),
881 qap_wit.coefficients_for_ABCs.begin() + qap_wit.num_variables(),
883 libff::leave_block("Compute answer to C-query", false);
885 libff::enter_block("Compute answer to H-query", false);
886 g_H = g_H + libff::multi_exp<
887 libff::G1<snark_pp<ppT>>,
888 libff::Fr<snark_pp<ppT>>,
889 libff::multi_exp_method_BDLO12>(
891 pk.H_query.begin() + qap_wit.degree() + 1,
892 qap_wit.coefficients_for_H.begin(),
893 qap_wit.coefficients_for_H.begin() + qap_wit.degree() + 1,
895 libff::leave_block("Compute answer to H-query", false);
897 libff::enter_block("Compute answer to K-query", false);
899 libff::multi_exp_with_mixed_addition<
900 libff::G1<snark_pp<ppT>>,
901 libff::Fr<snark_pp<ppT>>,
902 libff::multi_exp_method_bos_coster>(
903 pk.K_query.begin() + 1,
904 pk.K_query.begin() + 1 + qap_wit.num_variables(),
905 qap_wit.coefficients_for_ABCs.begin(),
906 qap_wit.coefficients_for_ABCs.begin() + qap_wit.num_variables(),
908 libff::leave_block("Compute answer to K-query", false);
910 libff::enter_block("Compute extra auth terms", false);
911 std::vector<libff::Fr<snark_pp<ppT>>> mus;
912 std::vector<libff::G1<snark_pp<ppT>>> Ains;
913 mus.reserve(qap_wit.num_inputs());
914 Ains.reserve(qap_wit.num_inputs());
915 for (size_t i = 0; i < qap_wit.num_inputs(); i++) {
916 mus.emplace_back(auth_data[i].mu);
917 Ains.emplace_back(pk.A_query[i + 1].g);
919 libff::G1<snark_pp<ppT>> muA = dauth * pk.rA_i_Z_g1;
920 muA = muA + libff::multi_exp<
921 libff::G1<snark_pp<ppT>>,
922 libff::Fr<snark_pp<ppT>>,
923 libff::multi_exp_method_bos_coster>(
925 Ains.begin() + qap_wit.num_inputs(),
927 mus.begin() + qap_wit.num_inputs(),
930 // To Do: Decide whether to include relevant parts of auth_data in proof
931 libff::leave_block("Compute extra auth terms", false);
933 libff::leave_block("Compute the proof");
935 libff::leave_block("Call to r1cs_ppzkadsnark_prover");
937 r1cs_ppzkadsnark_proof<ppT> proof = r1cs_ppzkadsnark_proof<ppT>(
950 template<typename ppT>
951 r1cs_ppzkadsnark_processed_verification_key<ppT>
952 r1cs_ppzkadsnark_verifier_process_vk(
953 const r1cs_ppzkadsnark_verification_key<ppT> &vk)
955 libff::enter_block("Call to r1cs_ppzkadsnark_verifier_process_vk");
957 r1cs_ppzkadsnark_processed_verification_key<ppT> pvk;
958 pvk.pp_G2_one_precomp =
959 snark_pp<ppT>::precompute_G2(libff::G2<snark_pp<ppT>>::one());
960 pvk.vk_alphaA_g2_precomp = snark_pp<ppT>::precompute_G2(vk.alphaA_g2);
961 pvk.vk_alphaB_g1_precomp = snark_pp<ppT>::precompute_G1(vk.alphaB_g1);
962 pvk.vk_alphaC_g2_precomp = snark_pp<ppT>::precompute_G2(vk.alphaC_g2);
963 pvk.vk_rC_Z_g2_precomp = snark_pp<ppT>::precompute_G2(vk.rC_Z_g2);
964 pvk.vk_gamma_g2_precomp = snark_pp<ppT>::precompute_G2(vk.gamma_g2);
965 pvk.vk_gamma_beta_g1_precomp =
966 snark_pp<ppT>::precompute_G1(vk.gamma_beta_g1);
967 pvk.vk_gamma_beta_g2_precomp =
968 snark_pp<ppT>::precompute_G2(vk.gamma_beta_g2);
970 libff::enter_block("Pre-processing for additional auth elements");
971 libff::G2_precomp<snark_pp<ppT>> vk_rC_z_g2_precomp =
972 snark_pp<ppT>::precompute_G2(vk.rC_Z_g2);
974 pvk.A0 = libff::G1<snark_pp<ppT>>(vk.A0);
975 pvk.Ain = libff::G1_vector<snark_pp<ppT>>(vk.Ain);
977 pvk.proof_g_vki_precomp.reserve(pvk.Ain.size());
978 for (size_t i = 0; i < pvk.Ain.size(); i++) {
979 pvk.proof_g_vki_precomp.emplace_back(
980 snark_pp<ppT>::precompute_G1(pvk.Ain[i]));
983 libff::leave_block("Pre-processing for additional auth elements");
985 libff::leave_block("Call to r1cs_ppzkadsnark_verifier_process_vk");
991 template<typename ppT>
992 bool r1cs_ppzkadsnark_online_verifier(
993 const r1cs_ppzkadsnark_processed_verification_key<ppT> &pvk,
994 const r1cs_ppzkadsnark_proof<ppT> &proof,
995 const r1cs_ppzkadsnark_sec_auth_key<ppT> &sak,
996 const std::vector<labelT> &labels)
999 libff::enter_block("Call to r1cs_ppzkadsnark_online_verifier");
1001 libff::enter_block("Check if the proof is well-formed");
1002 if (!proof.is_well_formed()) {
1003 if (!libff::inhibit_profiling_info) {
1004 libff::print_indent();
1005 printf("At least one of the proof elements does not lie on the "
1010 libff::leave_block("Check if the proof is well-formed");
1012 libff::enter_block("Checking auth-specific elements");
1014 libff::enter_block("Checking A1");
1016 libff::enter_block("Compute PRFs");
1017 std::vector<libff::Fr<snark_pp<ppT>>> lambdas;
1018 lambdas.reserve(labels.size());
1019 for (size_t i = 0; i < labels.size(); i++) {
1020 lambdas.emplace_back(prfCompute<ppT>(sak.S, labels[i]));
1022 libff::leave_block("Compute PRFs");
1023 libff::G1<snark_pp<ppT>> prodA = sak.i * proof.g_Aau.g;
1024 prodA = prodA + libff::multi_exp<
1025 libff::G1<snark_pp<ppT>>,
1026 libff::Fr<snark_pp<ppT>>,
1027 libff::multi_exp_method_bos_coster>(
1029 pvk.Ain.begin() + labels.size(),
1031 lambdas.begin() + labels.size(),
1034 bool result_auth = true;
1036 if (!(prodA == proof.muA)) {
1037 if (!libff::inhibit_profiling_info) {
1038 libff::print_indent();
1039 printf("Authentication check failed.\n");
1041 result_auth = false;
1044 libff::leave_block("Checking A1");
1046 libff::enter_block("Checking A2");
1047 libff::G1_precomp<snark_pp<ppT>> proof_g_Aau_g_precomp =
1048 snark_pp<ppT>::precompute_G1(proof.g_Aau.g);
1049 libff::G1_precomp<snark_pp<ppT>> proof_g_Aau_h_precomp =
1050 snark_pp<ppT>::precompute_G1(proof.g_Aau.h);
1051 libff::Fqk<snark_pp<ppT>> kc_Aau_1 = snark_pp<ppT>::miller_loop(
1052 proof_g_Aau_g_precomp, pvk.vk_alphaA_g2_precomp);
1053 libff::Fqk<snark_pp<ppT>> kc_Aau_2 = snark_pp<ppT>::miller_loop(
1054 proof_g_Aau_h_precomp, pvk.pp_G2_one_precomp);
1055 libff::GT<snark_pp<ppT>> kc_Aau = snark_pp<ppT>::final_exponentiation(
1056 kc_Aau_1 * kc_Aau_2.unitary_inverse());
1057 if (kc_Aau != libff::GT<snark_pp<ppT>>::one()) {
1058 if (!libff::inhibit_profiling_info) {
1059 libff::print_indent();
1060 printf("Knowledge commitment for Aau query incorrect.\n");
1062 result_auth = false;
1064 libff::leave_block("Checking A2");
1066 libff::leave_block("Checking auth-specific elements");
1068 result &= result_auth;
1070 libff::enter_block("Online pairing computations");
1071 libff::enter_block("Check knowledge commitment for A is valid");
1072 libff::G1_precomp<snark_pp<ppT>> proof_g_A_g_precomp =
1073 snark_pp<ppT>::precompute_G1(proof.g_A.g);
1074 libff::G1_precomp<snark_pp<ppT>> proof_g_A_h_precomp =
1075 snark_pp<ppT>::precompute_G1(proof.g_A.h);
1076 libff::Fqk<snark_pp<ppT>> kc_A_1 = snark_pp<ppT>::miller_loop(
1077 proof_g_A_g_precomp, pvk.vk_alphaA_g2_precomp);
1078 libff::Fqk<snark_pp<ppT>> kc_A_2 =
1079 snark_pp<ppT>::miller_loop(proof_g_A_h_precomp, pvk.pp_G2_one_precomp);
1080 libff::GT<snark_pp<ppT>> kc_A =
1081 snark_pp<ppT>::final_exponentiation(kc_A_1 * kc_A_2.unitary_inverse());
1082 if (kc_A != libff::GT<snark_pp<ppT>>::one()) {
1083 if (!libff::inhibit_profiling_info) {
1084 libff::print_indent();
1085 printf("Knowledge commitment for A query incorrect.\n");
1089 libff::leave_block("Check knowledge commitment for A is valid");
1091 libff::enter_block("Check knowledge commitment for B is valid");
1092 libff::G2_precomp<snark_pp<ppT>> proof_g_B_g_precomp =
1093 snark_pp<ppT>::precompute_G2(proof.g_B.g);
1094 libff::G1_precomp<snark_pp<ppT>> proof_g_B_h_precomp =
1095 snark_pp<ppT>::precompute_G1(proof.g_B.h);
1096 libff::Fqk<snark_pp<ppT>> kc_B_1 = snark_pp<ppT>::miller_loop(
1097 pvk.vk_alphaB_g1_precomp, proof_g_B_g_precomp);
1098 libff::Fqk<snark_pp<ppT>> kc_B_2 =
1099 snark_pp<ppT>::miller_loop(proof_g_B_h_precomp, pvk.pp_G2_one_precomp);
1100 libff::GT<snark_pp<ppT>> kc_B =
1101 snark_pp<ppT>::final_exponentiation(kc_B_1 * kc_B_2.unitary_inverse());
1102 if (kc_B != libff::GT<snark_pp<ppT>>::one()) {
1103 if (!libff::inhibit_profiling_info) {
1104 libff::print_indent();
1105 printf("Knowledge commitment for B query incorrect.\n");
1109 libff::leave_block("Check knowledge commitment for B is valid");
1111 libff::enter_block("Check knowledge commitment for C is valid");
1112 libff::G1_precomp<snark_pp<ppT>> proof_g_C_g_precomp =
1113 snark_pp<ppT>::precompute_G1(proof.g_C.g);
1114 libff::G1_precomp<snark_pp<ppT>> proof_g_C_h_precomp =
1115 snark_pp<ppT>::precompute_G1(proof.g_C.h);
1116 libff::Fqk<snark_pp<ppT>> kc_C_1 = snark_pp<ppT>::miller_loop(
1117 proof_g_C_g_precomp, pvk.vk_alphaC_g2_precomp);
1118 libff::Fqk<snark_pp<ppT>> kc_C_2 =
1119 snark_pp<ppT>::miller_loop(proof_g_C_h_precomp, pvk.pp_G2_one_precomp);
1120 libff::GT<snark_pp<ppT>> kc_C =
1121 snark_pp<ppT>::final_exponentiation(kc_C_1 * kc_C_2.unitary_inverse());
1122 if (kc_C != libff::GT<snark_pp<ppT>>::one()) {
1123 if (!libff::inhibit_profiling_info) {
1124 libff::print_indent();
1125 printf("Knowledge commitment for C query incorrect.\n");
1129 libff::leave_block("Check knowledge commitment for C is valid");
1131 libff::G1<snark_pp<ppT>> Aacc = pvk.A0 + proof.g_Aau.g + proof.g_A.g;
1133 libff::enter_block("Check QAP divisibility");
1134 libff::G1_precomp<snark_pp<ppT>> proof_g_Aacc_precomp =
1135 snark_pp<ppT>::precompute_G1(Aacc);
1136 libff::G1_precomp<snark_pp<ppT>> proof_g_H_precomp =
1137 snark_pp<ppT>::precompute_G1(proof.g_H);
1138 libff::Fqk<snark_pp<ppT>> QAP_1 =
1139 snark_pp<ppT>::miller_loop(proof_g_Aacc_precomp, proof_g_B_g_precomp);
1140 libff::Fqk<snark_pp<ppT>> QAP_23 = snark_pp<ppT>::double_miller_loop(
1142 pvk.vk_rC_Z_g2_precomp,
1143 proof_g_C_g_precomp,
1144 pvk.pp_G2_one_precomp);
1145 libff::GT<snark_pp<ppT>> QAP =
1146 snark_pp<ppT>::final_exponentiation(QAP_1 * QAP_23.unitary_inverse());
1147 if (QAP != libff::GT<snark_pp<ppT>>::one()) {
1148 if (!libff::inhibit_profiling_info) {
1149 libff::print_indent();
1150 printf("QAP divisibility check failed.\n");
1154 libff::leave_block("Check QAP divisibility");
1156 libff::enter_block("Check same coefficients were used");
1157 libff::G1_precomp<snark_pp<ppT>> proof_g_K_precomp =
1158 snark_pp<ppT>::precompute_G1(proof.g_K);
1159 libff::G1_precomp<snark_pp<ppT>> proof_g_Aacc_C_precomp =
1160 snark_pp<ppT>::precompute_G1(Aacc + proof.g_C.g);
1161 libff::Fqk<snark_pp<ppT>> K_1 =
1162 snark_pp<ppT>::miller_loop(proof_g_K_precomp, pvk.vk_gamma_g2_precomp);
1163 libff::Fqk<snark_pp<ppT>> K_23 = snark_pp<ppT>::double_miller_loop(
1164 proof_g_Aacc_C_precomp,
1165 pvk.vk_gamma_beta_g2_precomp,
1166 pvk.vk_gamma_beta_g1_precomp,
1167 proof_g_B_g_precomp);
1168 libff::GT<snark_pp<ppT>> K =
1169 snark_pp<ppT>::final_exponentiation(K_1 * K_23.unitary_inverse());
1170 if (K != libff::GT<snark_pp<ppT>>::one()) {
1171 if (!libff::inhibit_profiling_info) {
1172 libff::print_indent();
1173 printf("Same-coefficient check failed.\n");
1177 libff::leave_block("Check same coefficients were used");
1178 libff::leave_block("Online pairing computations");
1179 libff::leave_block("Call to r1cs_ppzkadsnark_online_verifier");
1184 template<typename ppT>
1185 bool r1cs_ppzkadsnark_verifier(
1186 const r1cs_ppzkadsnark_verification_key<ppT> &vk,
1187 const r1cs_ppzkadsnark_proof<ppT> &proof,
1188 const r1cs_ppzkadsnark_sec_auth_key<ppT> &sak,
1189 const std::vector<labelT> &labels)
1191 libff::enter_block("Call to r1cs_ppzkadsnark_verifier");
1192 r1cs_ppzkadsnark_processed_verification_key<ppT> pvk =
1193 r1cs_ppzkadsnark_verifier_process_vk<ppT>(vk);
1195 r1cs_ppzkadsnark_online_verifier<ppT>(pvk, proof, sak, labels);
1196 libff::leave_block("Call to r1cs_ppzkadsnark_verifier");
1201 template<typename ppT>
1202 bool r1cs_ppzkadsnark_online_verifier(
1203 const r1cs_ppzkadsnark_processed_verification_key<ppT> &pvk,
1204 const std::vector<r1cs_ppzkadsnark_auth_data<ppT>> &auth_data,
1205 const r1cs_ppzkadsnark_proof<ppT> &proof,
1206 const r1cs_ppzkadsnark_pub_auth_key<ppT> &pak,
1207 const std::vector<labelT> &labels)
1210 libff::enter_block("Call to r1cs_ppzkadsnark_online_verifier");
1212 libff::enter_block("Check if the proof is well-formed");
1213 if (!proof.is_well_formed()) {
1214 if (!libff::inhibit_profiling_info) {
1215 libff::print_indent();
1216 printf("At least one of the proof elements does not lie on the "
1221 libff::leave_block("Check if the proof is well-formed");
1223 libff::enter_block("Checking auth-specific elements");
1224 assert(labels.size() == auth_data.size());
1226 libff::enter_block("Checking A1");
1228 libff::enter_block("Checking signatures");
1229 std::vector<libff::G2<snark_pp<ppT>>> Lambdas;
1230 std::vector<r1cs_ppzkadsnark_sigT<ppT>> sigs;
1231 Lambdas.reserve(labels.size());
1232 sigs.reserve(labels.size());
1233 for (size_t i = 0; i < labels.size(); i++) {
1234 Lambdas.emplace_back(auth_data[i].Lambda);
1235 sigs.emplace_back(auth_data[i].sigma);
1237 bool result_auth = sigBatchVerif<ppT>(pak.vkp, labels, Lambdas, sigs);
1239 if (!libff::inhibit_profiling_info) {
1240 libff::print_indent();
1241 printf("Auth sig check failed.\n");
1245 libff::leave_block("Checking signatures");
1247 libff::enter_block("Checking pairings");
1248 // To Do: Decide whether to move pak and lambda preprocessing to offline
1249 std::vector<libff::G2_precomp<snark_pp<ppT>>> g_Lambdas_precomp;
1250 g_Lambdas_precomp.reserve(auth_data.size());
1251 for (size_t i = 0; i < auth_data.size(); i++)
1252 g_Lambdas_precomp.emplace_back(
1253 snark_pp<ppT>::precompute_G2(auth_data[i].Lambda));
1254 libff::G2_precomp<snark_pp<ppT>> g_minusi_precomp =
1255 snark_pp<ppT>::precompute_G2(pak.minusI2);
1257 libff::enter_block("Computation");
1258 libff::Fqk<snark_pp<ppT>> accum;
1259 if (auth_data.size() % 2 == 1) {
1260 accum = snark_pp<ppT>::miller_loop(
1261 pvk.proof_g_vki_precomp[0], g_Lambdas_precomp[0]);
1263 accum = libff::Fqk<snark_pp<ppT>>::one();
1265 for (size_t i = auth_data.size() % 2; i < labels.size(); i = i + 2) {
1266 accum = accum * snark_pp<ppT>::double_miller_loop(
1267 pvk.proof_g_vki_precomp[i],
1268 g_Lambdas_precomp[i],
1269 pvk.proof_g_vki_precomp[i + 1],
1270 g_Lambdas_precomp[i + 1]);
1272 libff::G1_precomp<snark_pp<ppT>> proof_g_muA_precomp =
1273 snark_pp<ppT>::precompute_G1(proof.muA);
1274 libff::G1_precomp<snark_pp<ppT>> proof_g_Aau_precomp =
1275 snark_pp<ppT>::precompute_G1(proof.g_Aau.g);
1276 libff::Fqk<snark_pp<ppT>> accum2 = snark_pp<ppT>::double_miller_loop(
1277 proof_g_muA_precomp,
1278 pvk.pp_G2_one_precomp,
1279 proof_g_Aau_precomp,
1281 libff::GT<snark_pp<ppT>> authPair =
1282 snark_pp<ppT>::final_exponentiation(accum * accum2.unitary_inverse());
1283 if (authPair != libff::GT<snark_pp<ppT>>::one()) {
1284 if (!libff::inhibit_profiling_info) {
1285 libff::print_indent();
1286 printf("Auth pairing check failed.\n");
1288 result_auth = false;
1290 libff::leave_block("Computation");
1291 libff::leave_block("Checking pairings");
1293 if (!(result_auth)) {
1294 if (!libff::inhibit_profiling_info) {
1295 libff::print_indent();
1296 printf("Authentication check failed.\n");
1300 libff::leave_block("Checking A1");
1302 libff::enter_block("Checking A2");
1303 libff::G1_precomp<snark_pp<ppT>> proof_g_Aau_g_precomp =
1304 snark_pp<ppT>::precompute_G1(proof.g_Aau.g);
1305 libff::G1_precomp<snark_pp<ppT>> proof_g_Aau_h_precomp =
1306 snark_pp<ppT>::precompute_G1(proof.g_Aau.h);
1307 libff::Fqk<snark_pp<ppT>> kc_Aau_1 = snark_pp<ppT>::miller_loop(
1308 proof_g_Aau_g_precomp, pvk.vk_alphaA_g2_precomp);
1309 libff::Fqk<snark_pp<ppT>> kc_Aau_2 = snark_pp<ppT>::miller_loop(
1310 proof_g_Aau_h_precomp, pvk.pp_G2_one_precomp);
1311 libff::GT<snark_pp<ppT>> kc_Aau = snark_pp<ppT>::final_exponentiation(
1312 kc_Aau_1 * kc_Aau_2.unitary_inverse());
1313 if (kc_Aau != libff::GT<snark_pp<ppT>>::one()) {
1314 if (!libff::inhibit_profiling_info) {
1315 libff::print_indent();
1316 printf("Knowledge commitment for Aau query incorrect.\n");
1318 result_auth = false;
1320 libff::leave_block("Checking A2");
1322 libff::leave_block("Checking auth-specific elements");
1324 result &= result_auth;
1326 libff::enter_block("Online pairing computations");
1327 libff::enter_block("Check knowledge commitment for A is valid");
1328 libff::G1_precomp<snark_pp<ppT>> proof_g_A_g_precomp =
1329 snark_pp<ppT>::precompute_G1(proof.g_A.g);
1330 libff::G1_precomp<snark_pp<ppT>> proof_g_A_h_precomp =
1331 snark_pp<ppT>::precompute_G1(proof.g_A.h);
1332 libff::Fqk<snark_pp<ppT>> kc_A_1 = snark_pp<ppT>::miller_loop(
1333 proof_g_A_g_precomp, pvk.vk_alphaA_g2_precomp);
1334 libff::Fqk<snark_pp<ppT>> kc_A_2 =
1335 snark_pp<ppT>::miller_loop(proof_g_A_h_precomp, pvk.pp_G2_one_precomp);
1336 libff::GT<snark_pp<ppT>> kc_A =
1337 snark_pp<ppT>::final_exponentiation(kc_A_1 * kc_A_2.unitary_inverse());
1338 if (kc_A != libff::GT<snark_pp<ppT>>::one()) {
1339 if (!libff::inhibit_profiling_info) {
1340 libff::print_indent();
1341 printf("Knowledge commitment for A query incorrect.\n");
1345 libff::leave_block("Check knowledge commitment for A is valid");
1347 libff::enter_block("Check knowledge commitment for B is valid");
1348 libff::G2_precomp<snark_pp<ppT>> proof_g_B_g_precomp =
1349 snark_pp<ppT>::precompute_G2(proof.g_B.g);
1350 libff::G1_precomp<snark_pp<ppT>> proof_g_B_h_precomp =
1351 snark_pp<ppT>::precompute_G1(proof.g_B.h);
1352 libff::Fqk<snark_pp<ppT>> kc_B_1 = snark_pp<ppT>::miller_loop(
1353 pvk.vk_alphaB_g1_precomp, proof_g_B_g_precomp);
1354 libff::Fqk<snark_pp<ppT>> kc_B_2 =
1355 snark_pp<ppT>::miller_loop(proof_g_B_h_precomp, pvk.pp_G2_one_precomp);
1356 libff::GT<snark_pp<ppT>> kc_B =
1357 snark_pp<ppT>::final_exponentiation(kc_B_1 * kc_B_2.unitary_inverse());
1358 if (kc_B != libff::GT<snark_pp<ppT>>::one()) {
1359 if (!libff::inhibit_profiling_info) {
1360 libff::print_indent();
1361 printf("Knowledge commitment for B query incorrect.\n");
1365 libff::leave_block("Check knowledge commitment for B is valid");
1367 libff::enter_block("Check knowledge commitment for C is valid");
1368 libff::G1_precomp<snark_pp<ppT>> proof_g_C_g_precomp =
1369 snark_pp<ppT>::precompute_G1(proof.g_C.g);
1370 libff::G1_precomp<snark_pp<ppT>> proof_g_C_h_precomp =
1371 snark_pp<ppT>::precompute_G1(proof.g_C.h);
1372 libff::Fqk<snark_pp<ppT>> kc_C_1 = snark_pp<ppT>::miller_loop(
1373 proof_g_C_g_precomp, pvk.vk_alphaC_g2_precomp);
1374 libff::Fqk<snark_pp<ppT>> kc_C_2 =
1375 snark_pp<ppT>::miller_loop(proof_g_C_h_precomp, pvk.pp_G2_one_precomp);
1376 libff::GT<snark_pp<ppT>> kc_C =
1377 snark_pp<ppT>::final_exponentiation(kc_C_1 * kc_C_2.unitary_inverse());
1378 if (kc_C != libff::GT<snark_pp<ppT>>::one()) {
1379 if (!libff::inhibit_profiling_info) {
1380 libff::print_indent();
1381 printf("Knowledge commitment for C query incorrect.\n");
1385 libff::leave_block("Check knowledge commitment for C is valid");
1387 libff::G1<snark_pp<ppT>> Aacc = pvk.A0 + proof.g_Aau.g + proof.g_A.g;
1389 libff::enter_block("Check QAP divisibility");
1390 libff::G1_precomp<snark_pp<ppT>> proof_g_Aacc_precomp =
1391 snark_pp<ppT>::precompute_G1(Aacc);
1392 libff::G1_precomp<snark_pp<ppT>> proof_g_H_precomp =
1393 snark_pp<ppT>::precompute_G1(proof.g_H);
1394 libff::Fqk<snark_pp<ppT>> QAP_1 =
1395 snark_pp<ppT>::miller_loop(proof_g_Aacc_precomp, proof_g_B_g_precomp);
1396 libff::Fqk<snark_pp<ppT>> QAP_23 = snark_pp<ppT>::double_miller_loop(
1398 pvk.vk_rC_Z_g2_precomp,
1399 proof_g_C_g_precomp,
1400 pvk.pp_G2_one_precomp);
1401 libff::GT<snark_pp<ppT>> QAP =
1402 snark_pp<ppT>::final_exponentiation(QAP_1 * QAP_23.unitary_inverse());
1403 if (QAP != libff::GT<snark_pp<ppT>>::one()) {
1404 if (!libff::inhibit_profiling_info) {
1405 libff::print_indent();
1406 printf("QAP divisibility check failed.\n");
1410 libff::leave_block("Check QAP divisibility");
1412 libff::enter_block("Check same coefficients were used");
1413 libff::G1_precomp<snark_pp<ppT>> proof_g_K_precomp =
1414 snark_pp<ppT>::precompute_G1(proof.g_K);
1415 libff::G1_precomp<snark_pp<ppT>> proof_g_Aacc_C_precomp =
1416 snark_pp<ppT>::precompute_G1(Aacc + proof.g_C.g);
1417 libff::Fqk<snark_pp<ppT>> K_1 =
1418 snark_pp<ppT>::miller_loop(proof_g_K_precomp, pvk.vk_gamma_g2_precomp);
1419 libff::Fqk<snark_pp<ppT>> K_23 = snark_pp<ppT>::double_miller_loop(
1420 proof_g_Aacc_C_precomp,
1421 pvk.vk_gamma_beta_g2_precomp,
1422 pvk.vk_gamma_beta_g1_precomp,
1423 proof_g_B_g_precomp);
1424 libff::GT<snark_pp<ppT>> K =
1425 snark_pp<ppT>::final_exponentiation(K_1 * K_23.unitary_inverse());
1426 if (K != libff::GT<snark_pp<ppT>>::one()) {
1427 if (!libff::inhibit_profiling_info) {
1428 libff::print_indent();
1429 printf("Same-coefficient check failed.\n");
1433 libff::leave_block("Check same coefficients were used");
1434 libff::leave_block("Online pairing computations");
1435 libff::leave_block("Call to r1cs_ppzkadsnark_online_verifier");
1441 template<typename ppT>
1442 bool r1cs_ppzkadsnark_verifier(
1443 const r1cs_ppzkadsnark_verification_key<ppT> &vk,
1444 const std::vector<r1cs_ppzkadsnark_auth_data<ppT>> &auth_data,
1445 const r1cs_ppzkadsnark_proof<ppT> &proof,
1446 const r1cs_ppzkadsnark_pub_auth_key<ppT> &pak,
1447 const std::vector<labelT> &labels)
1449 assert(labels.size() == auth_data.size());
1450 libff::enter_block("Call to r1cs_ppzkadsnark_verifier");
1451 r1cs_ppzkadsnark_processed_verification_key<ppT> pvk =
1452 r1cs_ppzkadsnark_verifier_process_vk<ppT>(vk);
1453 bool result = r1cs_ppzkadsnark_online_verifier<ppT>(
1454 pvk, auth_data, proof, pak, labels);
1455 libff::leave_block("Call to r1cs_ppzkadsnark_verifier");
1459 } // namespace libsnark
1460 #endif // R1CS_PPZKADSNARK_TCC_