Clearmatics Libsnark  0.1
C++ library for zkSNARK proofs
r1cs_se_ppzksnark.tcc
Go to the documentation of this file.
1 /** @file
2 *****************************************************************************
3 
4 Implementation of interfaces for a SEppzkSNARK for R1CS.
5 
6 See r1cs_se_ppzksnark.hpp .
7 
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 *****************************************************************************/
13 
14 #ifndef R1CS_SE_PPZKSNARK_TCC_
15 #define R1CS_SE_PPZKSNARK_TCC_
16 
17 #include <algorithm>
18 #include <cassert>
19 #include <functional>
20 #include <iostream>
21 #include <libff/algebra/scalar_multiplication/multiexp.hpp>
22 #include <libff/common/profiling.hpp>
23 #include <libff/common/utils.hpp>
24 #include <sstream>
25 
26 #ifdef MULTICORE
27 #include <omp.h>
28 #endif
29 
30 #include <libsnark/knowledge_commitment/kc_multiexp.hpp>
31 #include <libsnark/reductions/r1cs_to_sap/r1cs_to_sap.hpp>
32 
33 namespace libsnark
34 {
35 
36 template<typename ppT>
37 bool r1cs_se_ppzksnark_proving_key<ppT>::operator==(
38  const r1cs_se_ppzksnark_proving_key<ppT> &other) const
39 {
40  return (
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);
50 }
51 
52 template<typename ppT>
53 std::ostream &operator<<(
54  std::ostream &out, const r1cs_se_ppzksnark_proving_key<ppT> &pk)
55 {
56  out << pk.A_query;
57  out << pk.B_query;
58  out << pk.C_query_1;
59  out << pk.C_query_2;
60  out << pk.G_gamma_Z;
61  out << pk.H_gamma_Z;
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;
66 
67  return out;
68 }
69 
70 template<typename ppT>
71 std::istream &operator>>(
72  std::istream &in, r1cs_se_ppzksnark_proving_key<ppT> &pk)
73 {
74  in >> pk.A_query;
75  in >> pk.B_query;
76  in >> pk.C_query_1;
77  in >> pk.C_query_2;
78  in >> pk.G_gamma_Z;
79  in >> pk.H_gamma_Z;
80  in >> pk.G_ab_gamma_Z;
81  in >> pk.G_gamma2_Z2;
82  in >> pk.G_gamma2_Z_t;
83  in >> pk.constraint_system;
84 
85  return in;
86 }
87 
88 template<typename ppT>
89 bool r1cs_se_ppzksnark_verification_key<ppT>::operator==(
90  const r1cs_se_ppzksnark_verification_key<ppT> &other) const
91 {
92  return (
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);
96 }
97 
98 template<typename ppT>
99 std::ostream &operator<<(
100  std::ostream &out, const r1cs_se_ppzksnark_verification_key<ppT> &vk)
101 {
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;
108 
109  return out;
110 }
111 
112 template<typename ppT>
113 std::istream &operator>>(
114  std::istream &in, r1cs_se_ppzksnark_verification_key<ppT> &vk)
115 {
116  in >> vk.H;
117  libff::consume_OUTPUT_NEWLINE(in);
118  in >> vk.G_alpha;
119  libff::consume_OUTPUT_NEWLINE(in);
120  in >> vk.H_beta;
121  libff::consume_OUTPUT_NEWLINE(in);
122  in >> vk.G_gamma;
123  libff::consume_OUTPUT_NEWLINE(in);
124  in >> vk.H_gamma;
125  libff::consume_OUTPUT_NEWLINE(in);
126  in >> vk.query;
127  libff::consume_OUTPUT_NEWLINE(in);
128 
129  return in;
130 }
131 
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
135 {
136  return (
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);
142 }
143 
144 template<typename ppT>
145 std::ostream &operator<<(
146  std::ostream &out,
147  const r1cs_se_ppzksnark_processed_verification_key<ppT> &pvk)
148 {
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;
156 
157  return out;
158 }
159 
160 template<typename ppT>
161 std::istream &operator>>(
162  std::istream &in, r1cs_se_ppzksnark_processed_verification_key<ppT> &pvk)
163 {
164  in >> pvk.G_alpha;
165  libff::consume_OUTPUT_NEWLINE(in);
166  in >> pvk.H_beta;
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);
174  in >> pvk.H_pc;
175  libff::consume_OUTPUT_NEWLINE(in);
176  in >> pvk.query;
177  libff::consume_OUTPUT_NEWLINE(in);
178 
179  return in;
180 }
181 
182 template<typename ppT>
183 bool r1cs_se_ppzksnark_proof<ppT>::operator==(
184  const r1cs_se_ppzksnark_proof<ppT> &other) const
185 {
186  return (this->A == other.A && this->B == other.B && this->C == other.C);
187 }
188 
189 template<typename ppT>
190 std::ostream &operator<<(
191  std::ostream &out, const r1cs_se_ppzksnark_proof<ppT> &proof)
192 {
193  out << proof.A << OUTPUT_NEWLINE;
194  out << proof.B << OUTPUT_NEWLINE;
195  out << proof.C << OUTPUT_NEWLINE;
196 
197  return out;
198 }
199 
200 template<typename ppT>
201 std::istream &operator>>(std::istream &in, r1cs_se_ppzksnark_proof<ppT> &proof)
202 {
203  in >> proof.A;
204  libff::consume_OUTPUT_NEWLINE(in);
205  in >> proof.B;
206  libff::consume_OUTPUT_NEWLINE(in);
207  in >> proof.C;
208  libff::consume_OUTPUT_NEWLINE(in);
209 
210  return in;
211 }
212 
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)
216 {
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();
223 
224  libff::G1_vector<ppT> v;
225  for (size_t i = 0; i < input_size + 1; ++i) {
226  v.emplace_back(
227  libff::Fr<ppT>::random_element() * libff::G1<ppT>::one());
228  }
229  result.query = std::move(v);
230 
231  return result;
232 }
233 
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)
237 {
238  libff::enter_block("Call to r1cs_se_ppzksnark_generator");
239 
240  /**
241  * draw random element t at which the SAP is evaluated.
242  * it should be the case that Z(t) != 0
243  */
244  const std::shared_ptr<libfqfft::evaluation_domain<libff::Fr<ppT>>> domain =
245  r1cs_to_sap_get_domain(cs);
246  libff::Fr<ppT> t;
247  do {
248  t = libff::Fr<ppT>::random_element();
249  } while (domain->compute_vanishing_polynomial(t).is_zero());
250 
251  sap_instance_evaluation<libff::Fr<ppT>> sap_inst =
252  r1cs_to_sap_instance_map_with_evaluation(cs, t);
253 
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());
262 
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()) {
267  ++non_zero_At;
268  }
269  }
270  libff::leave_block("Compute query densities");
271 
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);
275  /**
276  * sap_inst.{A,C,H}t are now in an unspecified state,
277  * but we do not use them below
278  */
279 
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();
285 
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() +
290  1 // G_gamma2_Z_t
291  // C_query_1
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");
300 
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
304  H_gamma_window =
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");
311 
312  libff::enter_block("Generate R1CS verification key");
313  libff::G1<ppT> G_alpha = alpha * G;
314  libff::G2<ppT> H_beta = beta * H;
315 
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]);
320  }
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();
325 
326  libff::leave_block("Generate R1CS verification key");
327 
328  libff::enter_block("Generate R1CS proving key");
329 
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]);
334  }
335 
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);
342  }
343  libff::leave_block("Compute the A-query", false);
344 
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);
351  }
352  libff::leave_block("Compute the B-query", false);
353 
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;
360 
361  tmp_exponents.reserve(sap_inst.degree() + 1);
362 
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);
367  gamma2_Z_t *= t;
368  }
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);
375  }
376  libff::leave_block("Compute the G_gamma-query", false);
377 
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();
381  ++i) {
382  tmp_exponents.emplace_back(
383  gamma * (gamma * Ct[i] + (alpha + beta) * At[i]));
384  }
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);
391  }
392  libff::leave_block("Compute the C_1-query", false);
393 
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]);
400  }
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);
407  }
408  libff::leave_block("Compute the C_2-query", false);
409 
410  libff::leave_block("Generate R1CS proving key");
411 
412  libff::leave_block("Call to r1cs_se_ppzksnark_generator");
413 
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));
417 
418  r1cs_se_ppzksnark_constraint_system<ppT> cs_copy(cs);
419 
420  r1cs_se_ppzksnark_proving_key<ppT> pk = r1cs_se_ppzksnark_proving_key<ppT>(
421  std::move(A_query),
422  std::move(B_query),
423  std::move(C_query_1),
424  std::move(C_query_2),
425  G_gamma_Z,
426  H_gamma_Z,
427  G_ab_gamma_Z,
428  G_gamma2_Z2,
429  std::move(G_gamma2_Z_t),
430  std::move(cs_copy));
431 
432  pk.print_size();
433  vk.print_size();
434 
435  return r1cs_se_ppzksnark_keypair<ppT>(std::move(pk), std::move(vk));
436 }
437 
438 template<
439  typename ppT,
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)
446 {
447  libff::enter_block("Call to r1cs_se_ppzksnark_prover");
448 
449 #ifdef DEBUG
450  assert(pk.constraint_system.is_satisfied(primary_input, auxiliary_input));
451 #endif
452 
453  const libff::Fr<ppT> d1 = libff::Fr<ppT>::random_element(),
454  d2 = libff::Fr<ppT>::random_element();
455 
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");
460 
461 #ifdef DEBUG
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));
466 #endif
467 
468 #ifdef DEBUG
469  assert(pk.A_query.size() == sap_wit.num_variables() + 1);
470  assert(pk.B_query.size() == sap_wit.num_variables() + 1);
471  assert(
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);
475 #endif
476 
477 #ifdef MULTICORE
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()
481 #else
482  const size_t chunks = 1;
483 #endif
484 
485  const libff::Fr<ppT> r = libff::Fr<ppT>::random_element();
486 
487  libff::enter_block("Compute the proof");
488 
489  libff::enter_block("Compute answer to A-query", false);
490  /**
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
495  */
496  libff::G1<ppT> A =
497  r * pk.G_gamma_Z +
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,
502  pk.A_query.end(),
503  sap_wit.coefficients_for_ACs.begin(),
504  sap_wit.coefficients_for_ACs.end(),
505  chunks);
506 
507  libff::leave_block("Compute answer to A-query", false);
508 
509  libff::enter_block("Compute answer to B-query", false);
510  /**
511  * compute B exactly as A, except with H as the base
512  */
513  libff::G2<ppT> B =
514  r * pk.H_gamma_Z +
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,
519  pk.B_query.end(),
520  sap_wit.coefficients_for_ACs.begin(),
521  sap_wit.coefficients_for_ACs.end(),
522  chunks);
523  libff::leave_block("Compute answer to B-query", false);
524 
525  libff::enter_block("Compute answer to C-query", false);
526  /**
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
535  */
536  libff::G1<ppT> C =
537  libff::multi_exp<libff::G1<ppT>, libff::Fr<ppT>, Method, BaseForm>(
538  pk.C_query_1.begin(),
539  pk.C_query_1.end(),
540  sap_wit.coefficients_for_ACs.begin() + sap_wit.num_inputs(),
541  sap_wit.coefficients_for_ACs.end(),
542  chunks) +
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,
549  pk.C_query_2.end(),
550  sap_wit.coefficients_for_ACs.begin(),
551  sap_wit.coefficients_for_ACs.end(),
552  chunks) +
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(),
559  chunks);
560  libff::leave_block("Compute answer to C-query", false);
561 
562  libff::leave_block("Compute the proof");
563 
564  libff::leave_block("Call to r1cs_se_ppzksnark_prover");
565 
566  r1cs_se_ppzksnark_proof<ppT> proof =
567  r1cs_se_ppzksnark_proof<ppT>(std::move(A), std::move(B), std::move(C));
568  proof.print_size();
569 
570  return proof;
571 }
572 
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)
577 {
578  libff::enter_block("Call to r1cs_se_ppzksnark_verifier_process_vk");
579 
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);
582 
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);
590 
591  pvk.query = vk.query;
592 
593  libff::leave_block("Call to r1cs_se_ppzksnark_verifier_process_vk");
594 
595  return pvk;
596 }
597 
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)
603 {
604  libff::enter_block("Call to r1cs_se_ppzksnark_online_verifier_weak_IC");
605 
606  bool result = true;
607 
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 "
613  "curve.\n");
614  }
615  result = false;
616  }
617  libff::leave_block("Check if the proof is well-formed");
618 
619  libff::enter_block("Pairing computations");
620 
621 #ifdef MULTICORE
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()
625 #else
626  const size_t chunks = 1;
627 #endif
628 
629  libff::enter_block("Check first test");
630  /**
631  * e(A*G^{alpha}, B*H^{beta}) = e(G^{alpha}, H^{beta}) * e(G^{psi},
632  * H^{gamma})
633  * * e(C, H)
634  * where psi = \sum_{i=0}^l input_i pvk.query[i]
635  */
636  libff::G1<ppT> G_psi =
637  pvk.query[0] + libff::multi_exp<
638  libff::G1<ppT>,
639  libff::Fr<ppT>,
640  libff::multi_exp_method_bos_coster>(
641  pvk.query.begin() + 1,
642  pvk.query.end(),
643  primary_input.begin(),
644  primary_input.end(),
645  chunks);
646 
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),
653  test1_r3 =
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);
657 
658  if (test1 != libff::GT<ppT>::one()) {
659  if (!libff::inhibit_profiling_info) {
660  libff::print_indent();
661  printf("First test failed.\n");
662  }
663  result = false;
664  }
665  libff::leave_block("Check first test");
666 
667  libff::enter_block("Check second test");
668  /**
669  * e(A, H^{gamma}) = e(G^{gamma}, B)
670  */
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());
677 
678  if (test2 != libff::GT<ppT>::one()) {
679  if (!libff::inhibit_profiling_info) {
680  libff::print_indent();
681  printf("Second test failed.\n");
682  }
683  result = false;
684  }
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");
688 
689  return result;
690 }
691 
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)
697 {
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");
704  return result;
705 }
706 
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)
712 {
713  libff::enter_block("Call to r1cs_se_ppzksnark_online_verifier_strong_IC");
714  bool result = true;
715 
716  if (pvk.query.size() != primary_input.size() + 1) {
717  libff::print_indent();
718  printf(
719  "Input length differs from expected (got %zu, expected %zu).\n",
720  primary_input.size(),
721  pvk.query.size());
722  result = false;
723  } else {
724  result = r1cs_se_ppzksnark_online_verifier_weak_IC(
725  pvk, primary_input, proof);
726  }
727 
728  libff::leave_block("Call to r1cs_se_ppzksnark_online_verifier_strong_IC");
729  return result;
730 }
731 
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)
737 {
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");
744  return result;
745 }
746 
747 } // namespace libsnark
748 #endif // R1CS_SE_PPZKSNARK_TCC_