2 *****************************************************************************
4 Implementation of interfaces for a ppzkSNARK for R1CS.
6 See r1cs_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_PPZKSNARK_TCC_
15 #define R1CS_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_ppzksnark_proving_key<ppT>::operator==(
38 const r1cs_ppzksnark_proving_key<ppT> &other) const
41 this->A_query == other.A_query && this->B_query == other.B_query &&
42 this->C_query == other.C_query && this->H_query == other.H_query &&
43 this->K_query == other.K_query &&
44 this->constraint_system == other.constraint_system);
47 template<typename ppT>
48 std::ostream &operator<<(
49 std::ostream &out, const r1cs_ppzksnark_proving_key<ppT> &pk)
56 out << pk.constraint_system;
61 template<typename ppT>
62 std::istream &operator>>(std::istream &in, r1cs_ppzksnark_proving_key<ppT> &pk)
69 in >> pk.constraint_system;
74 template<typename ppT>
75 bool r1cs_ppzksnark_verification_key<ppT>::operator==(
76 const r1cs_ppzksnark_verification_key<ppT> &other) const
79 this->alphaA_g2 == other.alphaA_g2 &&
80 this->alphaB_g1 == other.alphaB_g1 &&
81 this->alphaC_g2 == other.alphaC_g2 &&
82 this->gamma_g2 == other.gamma_g2 &&
83 this->gamma_beta_g1 == other.gamma_beta_g1 &&
84 this->gamma_beta_g2 == other.gamma_beta_g2 &&
85 this->rC_Z_g2 == other.rC_Z_g2 &&
86 this->encoded_IC_query == other.encoded_IC_query);
89 template<typename ppT>
90 std::ostream &operator<<(
91 std::ostream &out, const r1cs_ppzksnark_verification_key<ppT> &vk)
93 out << vk.alphaA_g2 << OUTPUT_NEWLINE;
94 out << vk.alphaB_g1 << OUTPUT_NEWLINE;
95 out << vk.alphaC_g2 << OUTPUT_NEWLINE;
96 out << vk.gamma_g2 << OUTPUT_NEWLINE;
97 out << vk.gamma_beta_g1 << OUTPUT_NEWLINE;
98 out << vk.gamma_beta_g2 << OUTPUT_NEWLINE;
99 out << vk.rC_Z_g2 << OUTPUT_NEWLINE;
100 out << vk.encoded_IC_query << OUTPUT_NEWLINE;
105 template<typename ppT>
106 std::istream &operator>>(
107 std::istream &in, r1cs_ppzksnark_verification_key<ppT> &vk)
110 libff::consume_OUTPUT_NEWLINE(in);
112 libff::consume_OUTPUT_NEWLINE(in);
114 libff::consume_OUTPUT_NEWLINE(in);
116 libff::consume_OUTPUT_NEWLINE(in);
117 in >> vk.gamma_beta_g1;
118 libff::consume_OUTPUT_NEWLINE(in);
119 in >> vk.gamma_beta_g2;
120 libff::consume_OUTPUT_NEWLINE(in);
122 libff::consume_OUTPUT_NEWLINE(in);
123 in >> vk.encoded_IC_query;
124 libff::consume_OUTPUT_NEWLINE(in);
129 template<typename ppT>
130 bool r1cs_ppzksnark_processed_verification_key<ppT>::operator==(
131 const r1cs_ppzksnark_processed_verification_key<ppT> &other) const
134 this->pp_G2_one_precomp == other.pp_G2_one_precomp &&
135 this->vk_alphaA_g2_precomp == other.vk_alphaA_g2_precomp &&
136 this->vk_alphaB_g1_precomp == other.vk_alphaB_g1_precomp &&
137 this->vk_alphaC_g2_precomp == other.vk_alphaC_g2_precomp &&
138 this->vk_rC_Z_g2_precomp == other.vk_rC_Z_g2_precomp &&
139 this->vk_gamma_g2_precomp == other.vk_gamma_g2_precomp &&
140 this->vk_gamma_beta_g1_precomp == other.vk_gamma_beta_g1_precomp &&
141 this->vk_gamma_beta_g2_precomp == other.vk_gamma_beta_g2_precomp &&
142 this->encoded_IC_query == other.encoded_IC_query);
145 template<typename ppT>
146 std::ostream &operator<<(
148 const r1cs_ppzksnark_processed_verification_key<ppT> &pvk)
150 out << pvk.pp_G2_one_precomp << OUTPUT_NEWLINE;
151 out << pvk.vk_alphaA_g2_precomp << OUTPUT_NEWLINE;
152 out << pvk.vk_alphaB_g1_precomp << OUTPUT_NEWLINE;
153 out << pvk.vk_alphaC_g2_precomp << OUTPUT_NEWLINE;
154 out << pvk.vk_rC_Z_g2_precomp << OUTPUT_NEWLINE;
155 out << pvk.vk_gamma_g2_precomp << OUTPUT_NEWLINE;
156 out << pvk.vk_gamma_beta_g1_precomp << OUTPUT_NEWLINE;
157 out << pvk.vk_gamma_beta_g2_precomp << OUTPUT_NEWLINE;
158 out << pvk.encoded_IC_query << OUTPUT_NEWLINE;
163 template<typename ppT>
164 std::istream &operator>>(
165 std::istream &in, r1cs_ppzksnark_processed_verification_key<ppT> &pvk)
167 in >> pvk.pp_G2_one_precomp;
168 libff::consume_OUTPUT_NEWLINE(in);
169 in >> pvk.vk_alphaA_g2_precomp;
170 libff::consume_OUTPUT_NEWLINE(in);
171 in >> pvk.vk_alphaB_g1_precomp;
172 libff::consume_OUTPUT_NEWLINE(in);
173 in >> pvk.vk_alphaC_g2_precomp;
174 libff::consume_OUTPUT_NEWLINE(in);
175 in >> pvk.vk_rC_Z_g2_precomp;
176 libff::consume_OUTPUT_NEWLINE(in);
177 in >> pvk.vk_gamma_g2_precomp;
178 libff::consume_OUTPUT_NEWLINE(in);
179 in >> pvk.vk_gamma_beta_g1_precomp;
180 libff::consume_OUTPUT_NEWLINE(in);
181 in >> pvk.vk_gamma_beta_g2_precomp;
182 libff::consume_OUTPUT_NEWLINE(in);
183 in >> pvk.encoded_IC_query;
184 libff::consume_OUTPUT_NEWLINE(in);
189 template<typename ppT>
190 bool r1cs_ppzksnark_proof<ppT>::operator==(
191 const r1cs_ppzksnark_proof<ppT> &other) const
194 this->g_A == other.g_A && this->g_B == other.g_B &&
195 this->g_C == other.g_C && this->g_H == other.g_H &&
196 this->g_K == other.g_K);
199 template<typename ppT>
200 std::ostream &operator<<(
201 std::ostream &out, const r1cs_ppzksnark_proof<ppT> &proof)
203 out << proof.g_A << OUTPUT_NEWLINE;
204 out << proof.g_B << OUTPUT_NEWLINE;
205 out << proof.g_C << OUTPUT_NEWLINE;
206 out << proof.g_H << OUTPUT_NEWLINE;
207 out << proof.g_K << OUTPUT_NEWLINE;
212 template<typename ppT>
213 std::istream &operator>>(std::istream &in, r1cs_ppzksnark_proof<ppT> &proof)
216 libff::consume_OUTPUT_NEWLINE(in);
218 libff::consume_OUTPUT_NEWLINE(in);
220 libff::consume_OUTPUT_NEWLINE(in);
222 libff::consume_OUTPUT_NEWLINE(in);
224 libff::consume_OUTPUT_NEWLINE(in);
229 template<typename ppT>
230 r1cs_ppzksnark_verification_key<ppT> r1cs_ppzksnark_verification_key<
231 ppT>::dummy_verification_key(const size_t input_size)
233 r1cs_ppzksnark_verification_key<ppT> result;
234 result.alphaA_g2 = libff::Fr<ppT>::random_element() * libff::G2<ppT>::one();
235 result.alphaB_g1 = libff::Fr<ppT>::random_element() * libff::G1<ppT>::one();
236 result.alphaC_g2 = libff::Fr<ppT>::random_element() * libff::G2<ppT>::one();
237 result.gamma_g2 = libff::Fr<ppT>::random_element() * libff::G2<ppT>::one();
238 result.gamma_beta_g1 =
239 libff::Fr<ppT>::random_element() * libff::G1<ppT>::one();
240 result.gamma_beta_g2 =
241 libff::Fr<ppT>::random_element() * libff::G2<ppT>::one();
242 result.rC_Z_g2 = libff::Fr<ppT>::random_element() * libff::G2<ppT>::one();
244 libff::G1<ppT> base =
245 libff::Fr<ppT>::random_element() * libff::G1<ppT>::one();
246 libff::G1_vector<ppT> v;
247 for (size_t i = 0; i < input_size; ++i) {
249 libff::Fr<ppT>::random_element() * libff::G1<ppT>::one());
252 result.encoded_IC_query =
253 accumulation_vector<libff::G1<ppT>>(std::move(base), std::move(v));
258 template<typename ppT, libff::multi_exp_base_form BaseForm>
259 r1cs_ppzksnark_keypair<ppT> r1cs_ppzksnark_generator(
260 const r1cs_ppzksnark_constraint_system<ppT> &cs)
262 libff::enter_block("Call to r1cs_ppzksnark_generator");
264 /* make the B_query "lighter" if possible */
265 r1cs_ppzksnark_constraint_system<ppT> cs_copy(cs);
266 cs_copy.swap_AB_if_beneficial();
268 /* draw random element at which the QAP is evaluated */
269 const libff::Fr<ppT> t = libff::Fr<ppT>::random_element();
271 qap_instance_evaluation<libff::Fr<ppT>> qap_inst =
272 r1cs_to_qap_instance_map_with_evaluation(cs_copy, t);
274 libff::print_indent();
275 printf("* QAP number of variables: %zu\n", qap_inst.num_variables());
276 libff::print_indent();
277 printf("* QAP pre degree: %zu\n", cs_copy.constraints.size());
278 libff::print_indent();
279 printf("* QAP degree: %zu\n", qap_inst.degree());
280 libff::print_indent();
281 printf("* QAP number of input variables: %zu\n", qap_inst.num_inputs());
283 libff::enter_block("Compute query densities");
284 size_t non_zero_At = 0, non_zero_Bt = 0, non_zero_Ct = 0, non_zero_Ht = 0;
285 for (size_t i = 0; i < qap_inst.num_variables() + 1; ++i) {
286 if (!qap_inst.At[i].is_zero()) {
289 if (!qap_inst.Bt[i].is_zero()) {
292 if (!qap_inst.Ct[i].is_zero()) {
296 for (size_t i = 0; i < qap_inst.degree() + 1; ++i) {
297 if (!qap_inst.Ht[i].is_zero()) {
301 libff::leave_block("Compute query densities");
303 libff::Fr_vector<ppT> At =
304 std::move(qap_inst.At); // qap_inst.At is now in unspecified state, but
305 // we do not use it later
306 libff::Fr_vector<ppT> Bt =
307 std::move(qap_inst.Bt); // qap_inst.Bt is now in unspecified state, but
308 // we do not use it later
309 libff::Fr_vector<ppT> Ct =
310 std::move(qap_inst.Ct); // qap_inst.Ct is now in unspecified state, but
311 // we do not use it later
312 libff::Fr_vector<ppT> Ht =
313 std::move(qap_inst.Ht); // qap_inst.Ht is now in unspecified state, but
314 // we do not use it later
316 /* append Zt to At,Bt,Ct with */
317 At.emplace_back(qap_inst.Zt);
318 Bt.emplace_back(qap_inst.Zt);
319 Ct.emplace_back(qap_inst.Zt);
321 const libff::Fr<ppT> alphaA = libff::Fr<ppT>::random_element(),
322 alphaB = libff::Fr<ppT>::random_element(),
323 alphaC = libff::Fr<ppT>::random_element(),
324 rA = libff::Fr<ppT>::random_element(),
325 rB = libff::Fr<ppT>::random_element(),
326 beta = libff::Fr<ppT>::random_element(),
327 gamma = libff::Fr<ppT>::random_element();
328 const libff::Fr<ppT> rC = rA * rB;
330 // consrtuct the same-coefficient-check query (must happen before zeroing
331 // out the prefix of At)
332 libff::Fr_vector<ppT> Kt;
333 Kt.reserve(qap_inst.num_variables() + 4);
334 for (size_t i = 0; i < qap_inst.num_variables() + 1; ++i) {
335 Kt.emplace_back(beta * (rA * At[i] + rB * Bt[i] + rC * Ct[i]));
337 Kt.emplace_back(beta * rA * qap_inst.Zt);
338 Kt.emplace_back(beta * rB * qap_inst.Zt);
339 Kt.emplace_back(beta * rC * qap_inst.Zt);
341 /* zero out prefix of At and stick it into IC coefficients */
342 libff::Fr_vector<ppT> IC_coefficients;
343 IC_coefficients.reserve(qap_inst.num_inputs() + 1);
344 for (size_t i = 0; i < qap_inst.num_inputs() + 1; ++i) {
345 IC_coefficients.emplace_back(At[i]);
346 assert(!IC_coefficients[i].is_zero());
347 At[i] = libff::Fr<ppT>::zero();
350 const size_t g1_exp_count =
351 2 * (non_zero_At - qap_inst.num_inputs() + non_zero_Ct) + non_zero_Bt +
352 non_zero_Ht + Kt.size();
353 const size_t g2_exp_count = non_zero_Bt;
355 size_t g1_window = libff::get_exp_window_size<libff::G1<ppT>>(g1_exp_count);
356 size_t g2_window = libff::get_exp_window_size<libff::G2<ppT>>(g2_exp_count);
357 libff::print_indent();
358 printf("* G1 window: %zu\n", g1_window);
359 libff::print_indent();
360 printf("* G2 window: %zu\n", g2_window);
363 const size_t chunks =
364 omp_get_max_threads(); // to override, set OMP_NUM_THREADS env var or
365 // call omp_set_num_threads()
367 const size_t chunks = 1;
370 libff::enter_block("Generating G1 multiexp table");
371 libff::window_table<libff::G1<ppT>> g1_table = get_window_table(
372 libff::Fr<ppT>::size_in_bits(), g1_window, libff::G1<ppT>::one());
373 libff::leave_block("Generating G1 multiexp table");
375 libff::enter_block("Generating G2 multiexp table");
376 libff::window_table<libff::G2<ppT>> g2_table = get_window_table(
377 libff::Fr<ppT>::size_in_bits(), g2_window, libff::G2<ppT>::one());
378 libff::leave_block("Generating G2 multiexp table");
380 libff::enter_block("Generate R1CS proving key");
382 libff::enter_block("Generate knowledge commitments");
383 libff::enter_block("Compute the A-query", false);
384 knowledge_commitment_vector<libff::G1<ppT>, libff::G1<ppT>> A_query =
386 libff::Fr<ppT>::size_in_bits(),
395 BaseForm == libff::multi_exp_base_form_special);
396 libff::leave_block("Compute the A-query", false);
398 libff::enter_block("Compute the B-query", false);
399 knowledge_commitment_vector<libff::G2<ppT>, libff::G1<ppT>> B_query =
401 libff::Fr<ppT>::size_in_bits(),
410 BaseForm == libff::multi_exp_base_form_special);
411 libff::leave_block("Compute the B-query", false);
413 libff::enter_block("Compute the C-query", false);
414 knowledge_commitment_vector<libff::G1<ppT>, libff::G1<ppT>> C_query =
416 libff::Fr<ppT>::size_in_bits(),
425 BaseForm == libff::multi_exp_base_form_special);
426 libff::leave_block("Compute the C-query", false);
428 libff::enter_block("Compute the H-query", false);
429 libff::G1_vector<ppT> H_query =
430 batch_exp(libff::Fr<ppT>::size_in_bits(), g1_window, g1_table, Ht);
431 if (BaseForm == libff::multi_exp_base_form_special) {
432 libff::batch_to_special<libff::G1<ppT>>(H_query);
434 libff::leave_block("Compute the H-query", false);
436 libff::enter_block("Compute the K-query", false);
437 libff::G1_vector<ppT> K_query =
438 batch_exp(libff::Fr<ppT>::size_in_bits(), g1_window, g1_table, Kt);
439 if (BaseForm == libff::multi_exp_base_form_special) {
440 libff::batch_to_special<libff::G1<ppT>>(K_query);
442 libff::leave_block("Compute the K-query", false);
444 libff::leave_block("Generate knowledge commitments");
446 libff::leave_block("Generate R1CS proving key");
448 libff::enter_block("Generate R1CS verification key");
449 libff::G2<ppT> alphaA_g2 = alphaA * libff::G2<ppT>::one();
450 libff::G1<ppT> alphaB_g1 = alphaB * libff::G1<ppT>::one();
451 libff::G2<ppT> alphaC_g2 = alphaC * libff::G2<ppT>::one();
452 libff::G2<ppT> gamma_g2 = gamma * libff::G2<ppT>::one();
453 libff::G1<ppT> gamma_beta_g1 = (gamma * beta) * libff::G1<ppT>::one();
454 libff::G2<ppT> gamma_beta_g2 = (gamma * beta) * libff::G2<ppT>::one();
455 libff::G2<ppT> rC_Z_g2 = (rC * qap_inst.Zt) * libff::G2<ppT>::one();
457 libff::enter_block("Encode IC query for R1CS verification key");
458 libff::G1<ppT> encoded_IC_base =
459 (rA * IC_coefficients[0]) * libff::G1<ppT>::one();
460 libff::Fr_vector<ppT> multiplied_IC_coefficients;
461 multiplied_IC_coefficients.reserve(qap_inst.num_inputs());
462 for (size_t i = 1; i < qap_inst.num_inputs() + 1; ++i) {
463 multiplied_IC_coefficients.emplace_back(rA * IC_coefficients[i]);
465 libff::G1_vector<ppT> encoded_IC_values = batch_exp(
466 libff::Fr<ppT>::size_in_bits(),
469 multiplied_IC_coefficients);
471 libff::leave_block("Encode IC query for R1CS verification key");
472 libff::leave_block("Generate R1CS verification key");
474 libff::leave_block("Call to r1cs_ppzksnark_generator");
476 accumulation_vector<libff::G1<ppT>> encoded_IC_query(
477 std::move(encoded_IC_base), std::move(encoded_IC_values));
479 r1cs_ppzksnark_verification_key<ppT> vk =
480 r1cs_ppzksnark_verification_key<ppT>(
489 r1cs_ppzksnark_proving_key<ppT> pk = r1cs_ppzksnark_proving_key<ppT>(
500 return r1cs_ppzksnark_keypair<ppT>(std::move(pk), std::move(vk));
505 libff::multi_exp_method Method,
506 libff::multi_exp_base_form BaseForm>
507 r1cs_ppzksnark_proof<ppT> r1cs_ppzksnark_prover(
508 const r1cs_ppzksnark_proving_key<ppT> &pk,
509 const r1cs_ppzksnark_primary_input<ppT> &primary_input,
510 const r1cs_ppzksnark_auxiliary_input<ppT> &auxiliary_input)
512 libff::enter_block("Call to r1cs_ppzksnark_prover");
515 assert(pk.constraint_system.is_satisfied(primary_input, auxiliary_input));
518 const libff::Fr<ppT> d1 = libff::Fr<ppT>::random_element(),
519 d2 = libff::Fr<ppT>::random_element(),
520 d3 = libff::Fr<ppT>::random_element();
522 libff::enter_block("Compute the polynomial H");
523 const qap_witness<libff::Fr<ppT>> qap_wit = r1cs_to_qap_witness_map(
524 pk.constraint_system, primary_input, auxiliary_input, d1, d2, d3);
525 libff::leave_block("Compute the polynomial H");
528 const libff::Fr<ppT> t = libff::Fr<ppT>::random_element();
529 qap_instance_evaluation<libff::Fr<ppT>> qap_inst =
530 r1cs_to_qap_instance_map_with_evaluation(pk.constraint_system, t);
531 assert(qap_inst.is_satisfied(qap_wit));
534 knowledge_commitment<libff::G1<ppT>, libff::G1<ppT>> g_A =
535 pk.A_query[0] + qap_wit.d1 * pk.A_query[qap_wit.num_variables() + 1];
536 knowledge_commitment<libff::G2<ppT>, libff::G1<ppT>> g_B =
537 pk.B_query[0] + qap_wit.d2 * pk.B_query[qap_wit.num_variables() + 1];
538 knowledge_commitment<libff::G1<ppT>, libff::G1<ppT>> g_C =
539 pk.C_query[0] + qap_wit.d3 * pk.C_query[qap_wit.num_variables() + 1];
541 libff::G1<ppT> g_H = libff::G1<ppT>::zero();
543 (pk.K_query[0] + qap_wit.d1 * pk.K_query[qap_wit.num_variables() + 1] +
544 qap_wit.d2 * pk.K_query[qap_wit.num_variables() + 2] +
545 qap_wit.d3 * pk.K_query[qap_wit.num_variables() + 3]);
548 for (size_t i = 0; i < qap_wit.num_inputs() + 1; ++i) {
549 assert(pk.A_query[i].g == libff::G1<ppT>::zero());
551 assert(pk.A_query.domain_size() == qap_wit.num_variables() + 2);
552 assert(pk.B_query.domain_size() == qap_wit.num_variables() + 2);
553 assert(pk.C_query.domain_size() == qap_wit.num_variables() + 2);
554 assert(pk.H_query.size() == qap_wit.degree() + 1);
555 assert(pk.K_query.size() == qap_wit.num_variables() + 4);
559 const size_t chunks =
560 omp_get_max_threads(); // to override, set OMP_NUM_THREADS env var or
561 // call omp_set_num_threads()
563 const size_t chunks = 1;
566 libff::enter_block("Compute the proof");
568 libff::enter_block("Compute answer to A-query", false);
570 kc_multi_exp_with_mixed_addition<
578 1 + qap_wit.num_variables(),
579 qap_wit.coefficients_for_ABCs.begin(),
580 qap_wit.coefficients_for_ABCs.begin() + qap_wit.num_variables(),
582 libff::leave_block("Compute answer to A-query", false);
584 libff::enter_block("Compute answer to B-query", false);
586 kc_multi_exp_with_mixed_addition<
594 1 + qap_wit.num_variables(),
595 qap_wit.coefficients_for_ABCs.begin(),
596 qap_wit.coefficients_for_ABCs.begin() + qap_wit.num_variables(),
598 libff::leave_block("Compute answer to B-query", false);
600 libff::enter_block("Compute answer to C-query", false);
602 kc_multi_exp_with_mixed_addition<
610 1 + qap_wit.num_variables(),
611 qap_wit.coefficients_for_ABCs.begin(),
612 qap_wit.coefficients_for_ABCs.begin() + qap_wit.num_variables(),
614 libff::leave_block("Compute answer to C-query", false);
616 libff::enter_block("Compute answer to H-query", false);
618 libff::multi_exp<libff::G1<ppT>, libff::Fr<ppT>, Method, BaseForm>(
620 pk.H_query.begin() + qap_wit.degree() + 1,
621 qap_wit.coefficients_for_H.begin(),
622 qap_wit.coefficients_for_H.begin() + qap_wit.degree() + 1,
624 libff::leave_block("Compute answer to H-query", false);
626 libff::enter_block("Compute answer to K-query", false);
628 libff::multi_exp_filter_one_zero<
633 pk.K_query.begin() + 1,
634 pk.K_query.begin() + 1 + qap_wit.num_variables(),
635 qap_wit.coefficients_for_ABCs.begin(),
636 qap_wit.coefficients_for_ABCs.begin() + qap_wit.num_variables(),
638 libff::leave_block("Compute answer to K-query", false);
640 libff::leave_block("Compute the proof");
642 libff::leave_block("Call to r1cs_ppzksnark_prover");
644 r1cs_ppzksnark_proof<ppT> proof = r1cs_ppzksnark_proof<ppT>(
655 template<typename ppT>
656 r1cs_ppzksnark_processed_verification_key<ppT> r1cs_ppzksnark_verifier_process_vk(
657 const r1cs_ppzksnark_verification_key<ppT> &vk)
659 libff::enter_block("Call to r1cs_ppzksnark_verifier_process_vk");
661 r1cs_ppzksnark_processed_verification_key<ppT> pvk;
662 pvk.pp_G2_one_precomp = ppT::precompute_G2(libff::G2<ppT>::one());
663 pvk.vk_alphaA_g2_precomp = ppT::precompute_G2(vk.alphaA_g2);
664 pvk.vk_alphaB_g1_precomp = ppT::precompute_G1(vk.alphaB_g1);
665 pvk.vk_alphaC_g2_precomp = ppT::precompute_G2(vk.alphaC_g2);
666 pvk.vk_rC_Z_g2_precomp = ppT::precompute_G2(vk.rC_Z_g2);
667 pvk.vk_gamma_g2_precomp = ppT::precompute_G2(vk.gamma_g2);
668 pvk.vk_gamma_beta_g1_precomp = ppT::precompute_G1(vk.gamma_beta_g1);
669 pvk.vk_gamma_beta_g2_precomp = ppT::precompute_G2(vk.gamma_beta_g2);
671 pvk.encoded_IC_query = vk.encoded_IC_query;
673 libff::leave_block("Call to r1cs_ppzksnark_verifier_process_vk");
678 template<typename ppT>
679 bool r1cs_ppzksnark_online_verifier_weak_IC(
680 const r1cs_ppzksnark_processed_verification_key<ppT> &pvk,
681 const r1cs_ppzksnark_primary_input<ppT> &primary_input,
682 const r1cs_ppzksnark_proof<ppT> &proof)
684 libff::enter_block("Call to r1cs_ppzksnark_online_verifier_weak_IC");
685 assert(pvk.encoded_IC_query.domain_size() >= primary_input.size());
687 libff::enter_block("Compute input-dependent part of A");
688 const accumulation_vector<libff::G1<ppT>> accumulated_IC =
689 pvk.encoded_IC_query.template accumulate_chunk<libff::Fr<ppT>>(
690 primary_input.begin(), primary_input.end(), 0);
691 const libff::G1<ppT> &acc = accumulated_IC.first;
692 libff::leave_block("Compute input-dependent part of A");
696 libff::enter_block("Check if the proof is well-formed");
697 if (!proof.is_well_formed()) {
698 if (!libff::inhibit_profiling_info) {
699 libff::print_indent();
700 printf("At least one of the proof elements does not lie on the "
705 libff::leave_block("Check if the proof is well-formed");
707 libff::enter_block("Online pairing computations");
708 libff::enter_block("Check knowledge commitment for A is valid");
709 libff::G1_precomp<ppT> proof_g_A_g_precomp =
710 ppT::precompute_G1(proof.g_A.g);
711 libff::G1_precomp<ppT> proof_g_A_h_precomp =
712 ppT::precompute_G1(proof.g_A.h);
713 libff::Fqk<ppT> kc_A_1 =
714 ppT::miller_loop(proof_g_A_g_precomp, pvk.vk_alphaA_g2_precomp);
715 libff::Fqk<ppT> kc_A_2 =
716 ppT::miller_loop(proof_g_A_h_precomp, pvk.pp_G2_one_precomp);
717 libff::GT<ppT> kc_A =
718 ppT::final_exponentiation(kc_A_1 * kc_A_2.unitary_inverse());
719 if (kc_A != libff::GT<ppT>::one()) {
720 if (!libff::inhibit_profiling_info) {
721 libff::print_indent();
722 printf("Knowledge commitment for A query incorrect.\n");
726 libff::leave_block("Check knowledge commitment for A is valid");
728 libff::enter_block("Check knowledge commitment for B is valid");
729 libff::G2_precomp<ppT> proof_g_B_g_precomp =
730 ppT::precompute_G2(proof.g_B.g);
731 libff::G1_precomp<ppT> proof_g_B_h_precomp =
732 ppT::precompute_G1(proof.g_B.h);
733 libff::Fqk<ppT> kc_B_1 =
734 ppT::miller_loop(pvk.vk_alphaB_g1_precomp, proof_g_B_g_precomp);
735 libff::Fqk<ppT> kc_B_2 =
736 ppT::miller_loop(proof_g_B_h_precomp, pvk.pp_G2_one_precomp);
737 libff::GT<ppT> kc_B =
738 ppT::final_exponentiation(kc_B_1 * kc_B_2.unitary_inverse());
739 if (kc_B != libff::GT<ppT>::one()) {
740 if (!libff::inhibit_profiling_info) {
741 libff::print_indent();
742 printf("Knowledge commitment for B query incorrect.\n");
746 libff::leave_block("Check knowledge commitment for B is valid");
748 libff::enter_block("Check knowledge commitment for C is valid");
749 libff::G1_precomp<ppT> proof_g_C_g_precomp =
750 ppT::precompute_G1(proof.g_C.g);
751 libff::G1_precomp<ppT> proof_g_C_h_precomp =
752 ppT::precompute_G1(proof.g_C.h);
753 libff::Fqk<ppT> kc_C_1 =
754 ppT::miller_loop(proof_g_C_g_precomp, pvk.vk_alphaC_g2_precomp);
755 libff::Fqk<ppT> kc_C_2 =
756 ppT::miller_loop(proof_g_C_h_precomp, pvk.pp_G2_one_precomp);
757 libff::GT<ppT> kc_C =
758 ppT::final_exponentiation(kc_C_1 * kc_C_2.unitary_inverse());
759 if (kc_C != libff::GT<ppT>::one()) {
760 if (!libff::inhibit_profiling_info) {
761 libff::print_indent();
762 printf("Knowledge commitment for C query incorrect.\n");
766 libff::leave_block("Check knowledge commitment for C is valid");
768 libff::enter_block("Check QAP divisibility");
769 // check that g^((A+acc)*B)=g^(H*\Prod(t-\sigma)+C)
770 // equivalently, via pairings, that e(g^(A+acc), g^B) = e(g^H, g^Z) + e(g^C,
772 libff::G1_precomp<ppT> proof_g_A_g_acc_precomp =
773 ppT::precompute_G1(proof.g_A.g + acc);
774 libff::G1_precomp<ppT> proof_g_H_precomp = ppT::precompute_G1(proof.g_H);
775 libff::Fqk<ppT> QAP_1 =
776 ppT::miller_loop(proof_g_A_g_acc_precomp, proof_g_B_g_precomp);
777 libff::Fqk<ppT> QAP_23 = ppT::double_miller_loop(
779 pvk.vk_rC_Z_g2_precomp,
781 pvk.pp_G2_one_precomp);
783 ppT::final_exponentiation(QAP_1 * QAP_23.unitary_inverse());
784 if (QAP != libff::GT<ppT>::one()) {
785 if (!libff::inhibit_profiling_info) {
786 libff::print_indent();
787 printf("QAP divisibility check failed.\n");
791 libff::leave_block("Check QAP divisibility");
793 libff::enter_block("Check same coefficients were used");
794 libff::G1_precomp<ppT> proof_g_K_precomp = ppT::precompute_G1(proof.g_K);
795 libff::G1_precomp<ppT> proof_g_A_g_acc_C_precomp =
796 ppT::precompute_G1((proof.g_A.g + acc) + proof.g_C.g);
797 libff::Fqk<ppT> K_1 =
798 ppT::miller_loop(proof_g_K_precomp, pvk.vk_gamma_g2_precomp);
799 libff::Fqk<ppT> K_23 = ppT::double_miller_loop(
800 proof_g_A_g_acc_C_precomp,
801 pvk.vk_gamma_beta_g2_precomp,
802 pvk.vk_gamma_beta_g1_precomp,
803 proof_g_B_g_precomp);
804 libff::GT<ppT> K = ppT::final_exponentiation(K_1 * K_23.unitary_inverse());
805 if (K != libff::GT<ppT>::one()) {
806 if (!libff::inhibit_profiling_info) {
807 libff::print_indent();
808 printf("Same-coefficient check failed.\n");
812 libff::leave_block("Check same coefficients were used");
813 libff::leave_block("Online pairing computations");
814 libff::leave_block("Call to r1cs_ppzksnark_online_verifier_weak_IC");
819 template<typename ppT>
820 bool r1cs_ppzksnark_verifier_weak_IC(
821 const r1cs_ppzksnark_verification_key<ppT> &vk,
822 const r1cs_ppzksnark_primary_input<ppT> &primary_input,
823 const r1cs_ppzksnark_proof<ppT> &proof)
825 libff::enter_block("Call to r1cs_ppzksnark_verifier_weak_IC");
826 r1cs_ppzksnark_processed_verification_key<ppT> pvk =
827 r1cs_ppzksnark_verifier_process_vk<ppT>(vk);
829 r1cs_ppzksnark_online_verifier_weak_IC<ppT>(pvk, primary_input, proof);
830 libff::leave_block("Call to r1cs_ppzksnark_verifier_weak_IC");
834 template<typename ppT>
835 bool r1cs_ppzksnark_online_verifier_strong_IC(
836 const r1cs_ppzksnark_processed_verification_key<ppT> &pvk,
837 const r1cs_ppzksnark_primary_input<ppT> &primary_input,
838 const r1cs_ppzksnark_proof<ppT> &proof)
841 libff::enter_block("Call to r1cs_ppzksnark_online_verifier_strong_IC");
843 if (pvk.encoded_IC_query.domain_size() != primary_input.size()) {
844 libff::print_indent();
846 "Input length differs from expected (got %zu, expected %zu).\n",
847 primary_input.size(),
848 pvk.encoded_IC_query.domain_size());
852 r1cs_ppzksnark_online_verifier_weak_IC(pvk, primary_input, proof);
855 libff::leave_block("Call to r1cs_ppzksnark_online_verifier_strong_IC");
859 template<typename ppT>
860 bool r1cs_ppzksnark_verifier_strong_IC(
861 const r1cs_ppzksnark_verification_key<ppT> &vk,
862 const r1cs_ppzksnark_primary_input<ppT> &primary_input,
863 const r1cs_ppzksnark_proof<ppT> &proof)
865 libff::enter_block("Call to r1cs_ppzksnark_verifier_strong_IC");
866 r1cs_ppzksnark_processed_verification_key<ppT> pvk =
867 r1cs_ppzksnark_verifier_process_vk<ppT>(vk);
868 bool result = r1cs_ppzksnark_online_verifier_strong_IC<ppT>(
869 pvk, primary_input, proof);
870 libff::leave_block("Call to r1cs_ppzksnark_verifier_strong_IC");
874 template<typename ppT>
875 bool r1cs_ppzksnark_affine_verifier_weak_IC(
876 const r1cs_ppzksnark_verification_key<ppT> &vk,
877 const r1cs_ppzksnark_primary_input<ppT> &primary_input,
878 const r1cs_ppzksnark_proof<ppT> &proof)
880 libff::enter_block("Call to r1cs_ppzksnark_affine_verifier_weak_IC");
881 assert(vk.encoded_IC_query.domain_size() >= primary_input.size());
883 libff::affine_ate_G2_precomp<ppT> pvk_pp_G2_one_precomp =
884 ppT::affine_ate_precompute_G2(libff::G2<ppT>::one());
885 libff::affine_ate_G2_precomp<ppT> pvk_vk_alphaA_g2_precomp =
886 ppT::affine_ate_precompute_G2(vk.alphaA_g2);
887 libff::affine_ate_G1_precomp<ppT> pvk_vk_alphaB_g1_precomp =
888 ppT::affine_ate_precompute_G1(vk.alphaB_g1);
889 libff::affine_ate_G2_precomp<ppT> pvk_vk_alphaC_g2_precomp =
890 ppT::affine_ate_precompute_G2(vk.alphaC_g2);
891 libff::affine_ate_G2_precomp<ppT> pvk_vk_rC_Z_g2_precomp =
892 ppT::affine_ate_precompute_G2(vk.rC_Z_g2);
893 libff::affine_ate_G2_precomp<ppT> pvk_vk_gamma_g2_precomp =
894 ppT::affine_ate_precompute_G2(vk.gamma_g2);
895 libff::affine_ate_G1_precomp<ppT> pvk_vk_gamma_beta_g1_precomp =
896 ppT::affine_ate_precompute_G1(vk.gamma_beta_g1);
897 libff::affine_ate_G2_precomp<ppT> pvk_vk_gamma_beta_g2_precomp =
898 ppT::affine_ate_precompute_G2(vk.gamma_beta_g2);
900 libff::enter_block("Compute input-dependent part of A");
901 const accumulation_vector<libff::G1<ppT>> accumulated_IC =
902 vk.encoded_IC_query.template accumulate_chunk<libff::Fr<ppT>>(
903 primary_input.begin(), primary_input.end(), 0);
904 assert(accumulated_IC.is_fully_accumulated());
905 const libff::G1<ppT> &acc = accumulated_IC.first;
906 libff::leave_block("Compute input-dependent part of A");
909 libff::enter_block("Check knowledge commitment for A is valid");
910 libff::affine_ate_G1_precomp<ppT> proof_g_A_g_precomp =
911 ppT::affine_ate_precompute_G1(proof.g_A.g);
912 libff::affine_ate_G1_precomp<ppT> proof_g_A_h_precomp =
913 ppT::affine_ate_precompute_G1(proof.g_A.h);
914 libff::Fqk<ppT> kc_A_miller = ppT::affine_ate_e_over_e_miller_loop(
916 pvk_vk_alphaA_g2_precomp,
918 pvk_pp_G2_one_precomp);
919 libff::GT<ppT> kc_A = ppT::final_exponentiation(kc_A_miller);
921 if (kc_A != libff::GT<ppT>::one()) {
922 libff::print_indent();
923 printf("Knowledge commitment for A query incorrect.\n");
926 libff::leave_block("Check knowledge commitment for A is valid");
928 libff::enter_block("Check knowledge commitment for B is valid");
929 libff::affine_ate_G2_precomp<ppT> proof_g_B_g_precomp =
930 ppT::affine_ate_precompute_G2(proof.g_B.g);
931 libff::affine_ate_G1_precomp<ppT> proof_g_B_h_precomp =
932 ppT::affine_ate_precompute_G1(proof.g_B.h);
933 libff::Fqk<ppT> kc_B_miller = ppT::affine_ate_e_over_e_miller_loop(
934 pvk_vk_alphaB_g1_precomp,
937 pvk_pp_G2_one_precomp);
938 libff::GT<ppT> kc_B = ppT::final_exponentiation(kc_B_miller);
939 if (kc_B != libff::GT<ppT>::one()) {
940 libff::print_indent();
941 printf("Knowledge commitment for B query incorrect.\n");
944 libff::leave_block("Check knowledge commitment for B is valid");
946 libff::enter_block("Check knowledge commitment for C is valid");
947 libff::affine_ate_G1_precomp<ppT> proof_g_C_g_precomp =
948 ppT::affine_ate_precompute_G1(proof.g_C.g);
949 libff::affine_ate_G1_precomp<ppT> proof_g_C_h_precomp =
950 ppT::affine_ate_precompute_G1(proof.g_C.h);
951 libff::Fqk<ppT> kc_C_miller = ppT::affine_ate_e_over_e_miller_loop(
953 pvk_vk_alphaC_g2_precomp,
955 pvk_pp_G2_one_precomp);
956 libff::GT<ppT> kc_C = ppT::final_exponentiation(kc_C_miller);
957 if (kc_C != libff::GT<ppT>::one()) {
958 libff::print_indent();
959 printf("Knowledge commitment for C query incorrect.\n");
962 libff::leave_block("Check knowledge commitment for C is valid");
964 libff::enter_block("Check QAP divisibility");
965 libff::affine_ate_G1_precomp<ppT> proof_g_A_g_acc_precomp =
966 ppT::affine_ate_precompute_G1(proof.g_A.g + acc);
967 libff::affine_ate_G1_precomp<ppT> proof_g_H_precomp =
968 ppT::affine_ate_precompute_G1(proof.g_H);
969 libff::Fqk<ppT> QAP_miller = ppT::affine_ate_e_times_e_over_e_miller_loop(
971 pvk_vk_rC_Z_g2_precomp,
973 pvk_pp_G2_one_precomp,
974 proof_g_A_g_acc_precomp,
975 proof_g_B_g_precomp);
976 libff::GT<ppT> QAP = ppT::final_exponentiation(QAP_miller);
977 if (QAP != libff::GT<ppT>::one()) {
978 libff::print_indent();
979 printf("QAP divisibility check failed.\n");
982 libff::leave_block("Check QAP divisibility");
984 libff::enter_block("Check same coefficients were used");
985 libff::affine_ate_G1_precomp<ppT> proof_g_K_precomp =
986 ppT::affine_ate_precompute_G1(proof.g_K);
987 libff::affine_ate_G1_precomp<ppT> proof_g_A_g_acc_C_precomp =
988 ppT::affine_ate_precompute_G1((proof.g_A.g + acc) + proof.g_C.g);
989 libff::Fqk<ppT> K_miller = ppT::affine_ate_e_times_e_over_e_miller_loop(
990 proof_g_A_g_acc_C_precomp,
991 pvk_vk_gamma_beta_g2_precomp,
992 pvk_vk_gamma_beta_g1_precomp,
995 pvk_vk_gamma_g2_precomp);
996 libff::GT<ppT> K = ppT::final_exponentiation(K_miller);
997 if (K != libff::GT<ppT>::one()) {
998 libff::print_indent();
999 printf("Same-coefficient check failed.\n");
1002 libff::leave_block("Check same coefficients were used");
1004 libff::leave_block("Call to r1cs_ppzksnark_affine_verifier_weak_IC");
1009 } // namespace libsnark
1010 #endif // R1CS_PPZKSNARK_TCC_