Clearmatics Libsnark  0.1
C++ library for zkSNARK proofs
r1cs_gg_ppzksnark.tcc
Go to the documentation of this file.
1 /** @file
2 *****************************************************************************
3 
4 Implementation of interfaces for a ppzkSNARK for R1CS.
5 
6 See r1cs_gg_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_GG_PPZKSNARK_TCC_
15 #define R1CS_GG_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_qap/r1cs_to_qap.hpp>
32 
33 namespace libsnark
34 {
35 
36 template<typename ppT>
37 bool r1cs_gg_ppzksnark_proving_key<ppT>::operator==(
38  const r1cs_gg_ppzksnark_proving_key<ppT> &other) const
39 {
40  return (
41  this->alpha_g1 == other.alpha_g1 && this->beta_g1 == other.beta_g1 &&
42  this->beta_g2 == other.beta_g2 && this->delta_g1 == other.delta_g1 &&
43  this->delta_g2 == other.delta_g2 && this->A_query == other.A_query &&
44  this->B_query == other.B_query && this->H_query == other.H_query &&
45  this->L_query == other.L_query &&
46  this->constraint_system == other.constraint_system);
47 }
48 
49 template<typename ppT>
50 std::ostream &operator<<(
51  std::ostream &out, const r1cs_gg_ppzksnark_proving_key<ppT> &pk)
52 {
53  out << pk.alpha_g1 << OUTPUT_NEWLINE;
54  out << pk.beta_g1 << OUTPUT_NEWLINE;
55  out << pk.beta_g2 << OUTPUT_NEWLINE;
56  out << pk.delta_g1 << OUTPUT_NEWLINE;
57  out << pk.delta_g2 << OUTPUT_NEWLINE;
58  out << pk.A_query;
59  out << pk.B_query;
60  out << pk.H_query;
61  out << pk.L_query;
62  out << pk.constraint_system;
63 
64  return out;
65 }
66 
67 template<typename ppT>
68 std::istream &operator>>(
69  std::istream &in, r1cs_gg_ppzksnark_proving_key<ppT> &pk)
70 {
71  in >> pk.alpha_g1;
72  libff::consume_OUTPUT_NEWLINE(in);
73  in >> pk.beta_g1;
74  libff::consume_OUTPUT_NEWLINE(in);
75  in >> pk.beta_g2;
76  libff::consume_OUTPUT_NEWLINE(in);
77  in >> pk.delta_g1;
78  libff::consume_OUTPUT_NEWLINE(in);
79  in >> pk.delta_g2;
80  libff::consume_OUTPUT_NEWLINE(in);
81  in >> pk.A_query;
82  in >> pk.B_query;
83  in >> pk.H_query;
84  in >> pk.L_query;
85  in >> pk.constraint_system;
86 
87  return in;
88 }
89 
90 template<typename ppT>
91 bool r1cs_gg_ppzksnark_verification_key<ppT>::operator==(
92  const r1cs_gg_ppzksnark_verification_key<ppT> &other) const
93 {
94  return (
95  this->alpha_g1 == other.alpha_g1 && this->beta_g2 == other.beta_g2 &&
96  this->delta_g2 == other.delta_g2 && this->ABC_g1 == other.ABC_g1);
97 }
98 
99 template<typename ppT>
100 std::ostream &operator<<(
101  std::ostream &out, const r1cs_gg_ppzksnark_verification_key<ppT> &vk)
102 {
103  out << vk.alpha_g1 << OUTPUT_NEWLINE;
104  out << vk.beta_g2 << OUTPUT_NEWLINE;
105  out << vk.delta_g2 << OUTPUT_NEWLINE;
106  out << vk.ABC_g1 << OUTPUT_NEWLINE;
107 
108  return out;
109 }
110 
111 template<typename ppT>
112 std::istream &operator>>(
113  std::istream &in, r1cs_gg_ppzksnark_verification_key<ppT> &vk)
114 {
115  in >> vk.alpha_g1;
116  libff::consume_OUTPUT_NEWLINE(in);
117  in >> vk.beta_g2;
118  libff::consume_OUTPUT_NEWLINE(in);
119  in >> vk.delta_g2;
120  libff::consume_OUTPUT_NEWLINE(in);
121  in >> vk.ABC_g1;
122  libff::consume_OUTPUT_NEWLINE(in);
123 
124  return in;
125 }
126 
127 template<typename ppT>
128 bool r1cs_gg_ppzksnark_processed_verification_key<ppT>::operator==(
129  const r1cs_gg_ppzksnark_processed_verification_key<ppT> &other) const
130 {
131  return (
132  this->vk_alpha_g1_precomp == other.vk_alpha_g1_precomp &&
133  this->vk_beta_g2_precomp == other.vk_beta_g2_precomp &&
134  this->vk_generator_g2_precomp == other.vk_generator_g2_precomp &&
135  this->vk_delta_g2_precomp == other.vk_delta_g2_precomp &&
136  this->ABC_g1 == other.ABC_g1);
137 }
138 
139 template<typename ppT>
140 std::ostream &operator<<(
141  std::ostream &out,
142  const r1cs_gg_ppzksnark_processed_verification_key<ppT> &pvk)
143 {
144  out << pvk.vk_alpha_g1_precomp << OUTPUT_NEWLINE;
145  out << pvk.vk_beta_g2_precomp << OUTPUT_NEWLINE;
146  out << pvk.vk_generator_g2_precomp << OUTPUT_NEWLINE;
147  out << pvk.vk_delta_g2_precomp << OUTPUT_NEWLINE;
148  out << pvk.ABC_g1 << OUTPUT_NEWLINE;
149 
150  return out;
151 }
152 
153 template<typename ppT>
154 std::istream &operator>>(
155  std::istream &in, r1cs_gg_ppzksnark_processed_verification_key<ppT> &pvk)
156 {
157  in >> pvk.vk_alpha_g1_precomp;
158  libff::consume_OUTPUT_NEWLINE(in);
159  in >> pvk.vk_beta_g2_precomp;
160  libff::consume_OUTPUT_NEWLINE(in);
161  in >> pvk.vk_generator_g2_precomp;
162  libff::consume_OUTPUT_NEWLINE(in);
163  in >> pvk.vk_delta_g2_precomp;
164  libff::consume_OUTPUT_NEWLINE(in);
165  in >> pvk.ABC_g1;
166  libff::consume_OUTPUT_NEWLINE(in);
167 
168  return in;
169 }
170 
171 template<typename ppT>
172 bool r1cs_gg_ppzksnark_proof<ppT>::operator==(
173  const r1cs_gg_ppzksnark_proof<ppT> &other) const
174 {
175  return (
176  this->g_A == other.g_A && this->g_B == other.g_B &&
177  this->g_C == other.g_C);
178 }
179 
180 template<typename ppT>
181 std::ostream &operator<<(
182  std::ostream &out, const r1cs_gg_ppzksnark_proof<ppT> &proof)
183 {
184  out << proof.g_A << OUTPUT_NEWLINE;
185  out << proof.g_B << OUTPUT_NEWLINE;
186  out << proof.g_C << OUTPUT_NEWLINE;
187 
188  return out;
189 }
190 
191 template<typename ppT>
192 std::istream &operator>>(std::istream &in, r1cs_gg_ppzksnark_proof<ppT> &proof)
193 {
194  in >> proof.g_A;
195  libff::consume_OUTPUT_NEWLINE(in);
196  in >> proof.g_B;
197  libff::consume_OUTPUT_NEWLINE(in);
198  in >> proof.g_C;
199  libff::consume_OUTPUT_NEWLINE(in);
200 
201  return in;
202 }
203 
204 template<typename ppT>
205 r1cs_gg_ppzksnark_verification_key<ppT> r1cs_gg_ppzksnark_verification_key<
206  ppT>::dummy_verification_key(const size_t input_size)
207 {
208  r1cs_gg_ppzksnark_verification_key<ppT> result;
209  result.alpha_g1 = libff::G1<ppT>::random_element();
210  result.beta_g2 = libff::G2<ppT>::random_element();
211  result.delta_g2 = libff::G2<ppT>::random_element();
212 
213  libff::G1<ppT> base = libff::G1<ppT>::random_element();
214  libff::G1_vector<ppT> v;
215  for (size_t i = 0; i < input_size; ++i) {
216  v.emplace_back(libff::G1<ppT>::random_element());
217  }
218 
219  result.ABC_g1 =
220  accumulation_vector<libff::G1<ppT>>(std::move(base), std::move(v));
221 
222  return result;
223 }
224 
225 template<typename ppT, libff::multi_exp_base_form BaseForm>
226 r1cs_gg_ppzksnark_keypair<ppT> r1cs_gg_ppzksnark_generator_from_secrets(
227  const r1cs_gg_ppzksnark_constraint_system<ppT> &r1cs,
228  const libff::Fr<ppT> &t,
229  const libff::Fr<ppT> &alpha,
230  const libff::Fr<ppT> &beta,
231  const libff::Fr<ppT> &delta,
232  const libff::G1<ppT> &g1_generator,
233  const libff::G2<ppT> &g2_generator,
234  bool force_pow_2_domain)
235 {
236  libff::enter_block("Call to r1cs_gg_ppzksnark_generator_from_secrets");
237 
238  /* Make the B_query "lighter" if possible */
239  r1cs_gg_ppzksnark_constraint_system<ppT> r1cs_copy(r1cs);
240  r1cs_copy.swap_AB_if_beneficial();
241 
242  const libff::Fr<ppT> delta_inverse = delta.inverse();
243 
244  /* A quadratic arithmetic program evaluated at t. */
245  qap_instance_evaluation<libff::Fr<ppT>> qap =
246  r1cs_to_qap_instance_map_with_evaluation(
247  r1cs_copy, t, force_pow_2_domain);
248 
249  libff::print_indent();
250  printf("* QAP number of variables: %zu\n", qap.num_variables());
251  libff::print_indent();
252  printf("* QAP pre degree: %zu\n", r1cs_copy.constraints.size());
253  libff::print_indent();
254  printf("* QAP degree: %zu\n", qap.degree());
255  libff::print_indent();
256  printf("* QAP number of input variables: %zu\n", qap.num_inputs());
257 
258  libff::enter_block("Compute query densities");
259  size_t non_zero_At = 0;
260  size_t non_zero_Bt = 0;
261  for (size_t i = 0; i < qap.num_variables() + 1; ++i) {
262  if (!qap.At[i].is_zero()) {
263  ++non_zero_At;
264  }
265  if (!qap.Bt[i].is_zero()) {
266  ++non_zero_Bt;
267  }
268  }
269  libff::leave_block("Compute query densities");
270 
271  /* qap.{At,Bt,Ct,Ht} are now in unspecified state, but we do not use them
272  * later */
273  libff::Fr_vector<ppT> At = std::move(qap.At);
274  libff::Fr_vector<ppT> Bt = std::move(qap.Bt);
275  libff::Fr_vector<ppT> Ct = std::move(qap.Ct);
276  libff::Fr_vector<ppT> Ht = std::move(qap.Ht);
277 
278  /* The product component: (beta*A_i(t) + alpha*B_i(t) + C_i(t)). */
279  libff::enter_block("Compute ABC for R1CS verification key");
280  libff::Fr_vector<ppT> ABC;
281  ABC.reserve(qap.num_inputs());
282 
283  const libff::Fr<ppT> ABC_0 = beta * At[0] + alpha * Bt[0] + Ct[0];
284  for (size_t i = 1; i < qap.num_inputs() + 1; ++i) {
285  ABC.emplace_back(beta * At[i] + alpha * Bt[i] + Ct[i]);
286  }
287  libff::leave_block("Compute ABC for R1CS verification key");
288 
289  /* The delta inverse product component: (beta*A_i(t) + alpha*B_i(t) +
290  * C_i(t)) * delta^{-1}. */
291  libff::enter_block("Compute L query for R1CS proving key");
292  libff::Fr_vector<ppT> Lt;
293  Lt.reserve(qap.num_variables() - qap.num_inputs());
294 
295  const size_t Lt_offset = qap.num_inputs() + 1;
296  for (size_t i = Lt_offset; i < qap.num_variables() + 1; ++i) {
297  Lt.emplace_back((beta * At[i] + alpha * Bt[i] + Ct[i]) * delta_inverse);
298  }
299  libff::leave_block("Compute L query for R1CS proving key");
300 
301  /**
302  * Note that H for Groth's proof system is degree d-2, but the QAP
303  * reduction returns coefficients for degree d polynomial H (in
304  * style of PGHR-type proof systems)
305  */
306  Ht.resize(Ht.size() - 2);
307 
308 #ifdef MULTICORE
309  const size_t chunks =
310  omp_get_max_threads(); // to override, set OMP_NUM_THREADS env var or
311  // call omp_set_num_threads()
312 #else
313  const size_t chunks = 1;
314 #endif
315 
316  libff::enter_block("Generating G1 MSM window table");
317  const size_t g1_scalar_count =
318  non_zero_At + non_zero_Bt + qap.num_variables();
319  const size_t g1_scalar_size = libff::Fr<ppT>::size_in_bits();
320  const size_t g1_window_size =
321  libff::get_exp_window_size<libff::G1<ppT>>(g1_scalar_count);
322 
323  libff::print_indent();
324  printf("* G1 window: %zu\n", g1_window_size);
325  libff::window_table<libff::G1<ppT>> g1_table =
326  libff::get_window_table(g1_scalar_size, g1_window_size, g1_generator);
327  libff::leave_block("Generating G1 MSM window table");
328 
329  libff::enter_block("Generating G2 MSM window table");
330  const size_t g2_scalar_count = non_zero_Bt;
331  const size_t g2_scalar_size = libff::Fr<ppT>::size_in_bits();
332  size_t g2_window_size =
333  libff::get_exp_window_size<libff::G2<ppT>>(g2_scalar_count);
334 
335  libff::print_indent();
336  printf("* G2 window: %zu\n", g2_window_size);
337  libff::window_table<libff::G2<ppT>> g2_table =
338  libff::get_window_table(g2_scalar_size, g2_window_size, g2_generator);
339  libff::leave_block("Generating G2 MSM window table");
340 
341  libff::enter_block("Generate R1CS proving key");
342  libff::G1<ppT> alpha_g1 = alpha * g1_generator;
343  libff::G1<ppT> beta_g1 = beta * g1_generator;
344  libff::G2<ppT> beta_g2 = beta * g2_generator;
345  libff::G1<ppT> delta_g1 = delta * g1_generator;
346  libff::G2<ppT> delta_g2 = delta * g2_generator;
347 
348  libff::enter_block("Generate queries");
349  libff::enter_block("Compute the A-query", false);
350  libff::G1_vector<ppT> A_query =
351  batch_exp(g1_scalar_size, g1_window_size, g1_table, At);
352  if (BaseForm == libff::multi_exp_base_form_special) {
353  libff::batch_to_special<libff::G1<ppT>>(A_query);
354  }
355  libff::leave_block("Compute the A-query", false);
356 
357  libff::enter_block("Compute the B-query", false);
358  // Force kc_batch_exp to convert to special form, if BaseForm ==
359  // libff::multi_exp_base_form_special.
360  knowledge_commitment_vector<libff::G2<ppT>, libff::G1<ppT>> B_query =
361  kc_batch_exp(
362  libff::Fr<ppT>::size_in_bits(),
363  g2_window_size,
364  g1_window_size,
365  g2_table,
366  g1_table,
367  libff::Fr<ppT>::one(),
368  libff::Fr<ppT>::one(),
369  Bt,
370  chunks,
371  BaseForm == libff::multi_exp_base_form_special);
372  libff::leave_block("Compute the B-query", false);
373 
374  libff::enter_block("Compute the H-query", false);
375  libff::G1_vector<ppT> H_query = batch_exp_with_coeff(
376  g1_scalar_size, g1_window_size, g1_table, qap.Zt * delta_inverse, Ht);
377  if (BaseForm == libff::multi_exp_base_form_special) {
378  libff::batch_to_special<libff::G1<ppT>>(H_query);
379  }
380  libff::leave_block("Compute the H-query", false);
381 
382  libff::enter_block("Compute the L-query", false);
383  libff::G1_vector<ppT> L_query =
384  batch_exp(g1_scalar_size, g1_window_size, g1_table, Lt);
385  if (BaseForm == libff::multi_exp_base_form_special) {
386  libff::batch_to_special<libff::G1<ppT>>(L_query);
387  }
388  libff::leave_block("Compute the L-query", false);
389  libff::leave_block("Generate queries");
390 
391  libff::leave_block("Generate R1CS proving key");
392 
393  libff::enter_block("Generate R1CS verification key");
394 
395  libff::enter_block("Encode ABC for R1CS verification key");
396  libff::G1<ppT> ABC_g1_0 = ABC_0 * g1_generator;
397  libff::G1_vector<ppT> ABC_g1_values =
398  batch_exp(g1_scalar_size, g1_window_size, g1_table, ABC);
399  libff::leave_block("Encode ABC for R1CS verification key");
400  libff::leave_block("Generate R1CS verification key");
401 
402  libff::leave_block("Call to r1cs_gg_ppzksnark_generator_from_secrets");
403 
404  accumulation_vector<libff::G1<ppT>> ABC_g1(
405  std::move(ABC_g1_0), std::move(ABC_g1_values));
406 
407  r1cs_gg_ppzksnark_verification_key<ppT> vk =
408  r1cs_gg_ppzksnark_verification_key<ppT>(
409  alpha_g1, beta_g2, delta_g2, ABC_g1);
410 
411  r1cs_gg_ppzksnark_proving_key<ppT> pk = r1cs_gg_ppzksnark_proving_key<ppT>(
412  std::move(alpha_g1),
413  std::move(beta_g1),
414  std::move(beta_g2),
415  std::move(delta_g1),
416  std::move(delta_g2),
417  std::move(A_query),
418  std::move(B_query),
419  std::move(H_query),
420  std::move(L_query),
421  std::move(r1cs_copy));
422 
423  pk.print_size();
424  vk.print_size();
425 
426  return r1cs_gg_ppzksnark_keypair<ppT>(std::move(pk), std::move(vk));
427 }
428 
429 template<typename ppT, libff::multi_exp_base_form BaseForm>
430 r1cs_gg_ppzksnark_keypair<ppT> r1cs_gg_ppzksnark_generator(
431  const r1cs_gg_ppzksnark_constraint_system<ppT> &r1cs,
432  bool force_pow_2_domain)
433 {
434  libff::enter_block("Call to r1cs_gg_ppzksnark_generator");
435 
436  /* Generate secret randomness */
437  const libff::Fr<ppT> t = libff::Fr<ppT>::random_element();
438  const libff::Fr<ppT> alpha = libff::Fr<ppT>::random_element();
439  const libff::Fr<ppT> beta = libff::Fr<ppT>::random_element();
440  const libff::Fr<ppT> delta = libff::Fr<ppT>::random_element();
441  const libff::G1<ppT> g1_generator = libff::G1<ppT>::one();
442  const libff::G2<ppT> g2_generator = libff::G2<ppT>::one();
443 
444  r1cs_gg_ppzksnark_keypair<ppT> key_pair =
445  r1cs_gg_ppzksnark_generator_from_secrets<ppT, BaseForm>(
446  r1cs,
447  t,
448  alpha,
449  beta,
450  delta,
451  g1_generator,
452  g2_generator,
453  force_pow_2_domain);
454 
455  libff::leave_block("Call to r1cs_gg_ppzksnark_generator");
456 
457  return key_pair;
458 }
459 
460 template<
461  typename ppT,
462  libff::multi_exp_method Method,
463  libff::multi_exp_base_form BaseForm>
464 r1cs_gg_ppzksnark_proof<ppT> r1cs_gg_ppzksnark_prover(
465  const r1cs_gg_ppzksnark_proving_key<ppT> &pk,
466  const r1cs_gg_ppzksnark_primary_input<ppT> &primary_input,
467  const r1cs_gg_ppzksnark_auxiliary_input<ppT> &auxiliary_input,
468  bool force_pow_2_domain)
469 {
470  libff::enter_block("Call to r1cs_gg_ppzksnark_prover");
471 
472 #ifdef DEBUG
473  assert(pk.constraint_system.is_satisfied(primary_input, auxiliary_input));
474 #endif
475 
476  libff::enter_block("Compute the polynomial H");
477  const qap_witness<libff::Fr<ppT>> qap_wit = r1cs_to_qap_witness_map(
478  pk.constraint_system,
479  primary_input,
480  auxiliary_input,
481  libff::Fr<ppT>::zero(),
482  libff::Fr<ppT>::zero(),
483  libff::Fr<ppT>::zero(),
484  force_pow_2_domain);
485 
486  /* We are dividing degree 2(d-1) polynomial by degree d polynomial
487  and not adding a PGHR-style ZK-patch, so our H is degree d-2 */
488  assert(!qap_wit.coefficients_for_H[qap_wit.degree() - 2].is_zero());
489  assert(qap_wit.coefficients_for_H[qap_wit.degree() - 1].is_zero());
490  assert(qap_wit.coefficients_for_H[qap_wit.degree()].is_zero());
491  libff::leave_block("Compute the polynomial H");
492 
493 #ifdef DEBUG
494  const libff::Fr<ppT> t = libff::Fr<ppT>::random_element();
495  qap_instance_evaluation<libff::Fr<ppT>> qap_inst =
496  r1cs_to_qap_instance_map_with_evaluation(
497  pk.constraint_system, t, force_pow_2_domain);
498  assert(qap_inst.is_satisfied(qap_wit));
499 #endif
500 
501  /* Choose two random field elements for prover zero-knowledge. */
502  const libff::Fr<ppT> r = libff::Fr<ppT>::random_element();
503  const libff::Fr<ppT> s = libff::Fr<ppT>::random_element();
504 
505 #ifdef DEBUG
506  assert(qap_wit.coefficients_for_ABCs.size() == qap_wit.num_variables());
507  assert(pk.A_query.size() == qap_wit.num_variables() + 1);
508  assert(pk.B_query.domain_size() == qap_wit.num_variables() + 1);
509  assert(pk.H_query.size() == qap_wit.degree() - 1);
510  assert(pk.L_query.size() == qap_wit.num_variables() - qap_wit.num_inputs());
511 #endif
512 
513 #ifdef MULTICORE
514  const size_t chunks =
515  omp_get_max_threads(); // to override, set OMP_NUM_THREADS env var or
516  // call omp_set_num_threads()
517 #else
518  const size_t chunks = 1;
519 #endif
520 
521  libff::enter_block("Compute the proof");
522 
523  libff::enter_block("Compute evaluation to A-query", false);
524  // TODO: sort out indexing
525  libff::Fr_vector<ppT> const_padded_assignment(1, libff::Fr<ppT>::one());
526  const_padded_assignment.insert(
527  const_padded_assignment.end(),
528  qap_wit.coefficients_for_ABCs.begin(),
529  qap_wit.coefficients_for_ABCs.end());
530 
531  libff::G1<ppT> evaluation_At = libff::multi_exp_filter_one_zero<
532  libff::G1<ppT>,
533  libff::Fr<ppT>,
534  Method,
535  BaseForm>(
536  pk.A_query.begin(),
537  pk.A_query.begin() + qap_wit.num_variables() + 1,
538  const_padded_assignment.begin(),
539  const_padded_assignment.begin() + qap_wit.num_variables() + 1,
540  chunks);
541  libff::leave_block("Compute evaluation to A-query", false);
542 
543  libff::enter_block("Compute evaluation to B-query", false);
544  knowledge_commitment<libff::G2<ppT>, libff::G1<ppT>> evaluation_Bt =
545  kc_multi_exp_with_mixed_addition<
546  libff::G2<ppT>,
547  libff::G1<ppT>,
548  libff::Fr<ppT>,
549  Method,
550  BaseForm>(
551  pk.B_query,
552  0,
553  qap_wit.num_variables() + 1,
554  const_padded_assignment.begin(),
555  const_padded_assignment.begin() + qap_wit.num_variables() + 1,
556  chunks);
557  libff::leave_block("Compute evaluation to B-query", false);
558 
559  libff::enter_block("Compute evaluation to H-query", false);
560  libff::G1<ppT> evaluation_Ht =
561  libff::multi_exp<libff::G1<ppT>, libff::Fr<ppT>, Method, BaseForm>(
562  pk.H_query.begin(),
563  pk.H_query.begin() + (qap_wit.degree() - 1),
564  qap_wit.coefficients_for_H.begin(),
565  qap_wit.coefficients_for_H.begin() + (qap_wit.degree() - 1),
566  chunks);
567  libff::leave_block("Compute evaluation to H-query", false);
568 
569  libff::enter_block("Compute evaluation to L-query", false);
570  libff::G1<ppT> evaluation_Lt = libff::multi_exp_filter_one_zero<
571  libff::G1<ppT>,
572  libff::Fr<ppT>,
573  Method,
574  BaseForm>(
575  pk.L_query.begin(),
576  pk.L_query.end(),
577  const_padded_assignment.begin() + qap_wit.num_inputs() + 1,
578  const_padded_assignment.begin() + qap_wit.num_variables() + 1,
579  chunks);
580  libff::leave_block("Compute evaluation to L-query", false);
581 
582  /* A = alpha + sum_i(a_i*A_i(t)) + r*delta */
583  libff::G1<ppT> g1_A = pk.alpha_g1 + evaluation_At + r * pk.delta_g1;
584 
585  /* B = beta + sum_i(a_i*B_i(t)) + s*delta */
586  libff::G1<ppT> g1_B = pk.beta_g1 + evaluation_Bt.h + s * pk.delta_g1;
587  libff::G2<ppT> g2_B = pk.beta_g2 + evaluation_Bt.g + s * pk.delta_g2;
588 
589  /* C = sum_i(a_i*((beta*A_i(t) + alpha*B_i(t) + C_i(t)) + H(t)*Z(t))/delta)
590  * + A*s + r*b - r*s*delta */
591  libff::G1<ppT> g1_C = evaluation_Ht + evaluation_Lt + s * g1_A + r * g1_B -
592  (r * s) * pk.delta_g1;
593 
594  libff::leave_block("Compute the proof");
595 
596  libff::leave_block("Call to r1cs_gg_ppzksnark_prover");
597 
598  r1cs_gg_ppzksnark_proof<ppT> proof = r1cs_gg_ppzksnark_proof<ppT>(
599  std::move(g1_A), std::move(g2_B), std::move(g1_C));
600  proof.print_size();
601 
602  return proof;
603 }
604 
605 template<typename ppT>
606 r1cs_gg_ppzksnark_processed_verification_key<ppT>
607 r1cs_gg_ppzksnark_verifier_process_vk(
608  const r1cs_gg_ppzksnark_verification_key<ppT> &vk)
609 {
610  libff::enter_block("Call to r1cs_gg_ppzksnark_verifier_process_vk");
611 
612  r1cs_gg_ppzksnark_processed_verification_key<ppT> pvk;
613  pvk.vk_alpha_g1_precomp = ppT::precompute_G1(vk.alpha_g1);
614  pvk.vk_beta_g2_precomp = ppT::precompute_G2(vk.beta_g2);
615  pvk.vk_generator_g2_precomp = ppT::precompute_G2(libff::G2<ppT>::one());
616  pvk.vk_delta_g2_precomp = ppT::precompute_G2(vk.delta_g2);
617  pvk.ABC_g1 = vk.ABC_g1;
618 
619  libff::leave_block("Call to r1cs_gg_ppzksnark_verifier_process_vk");
620 
621  return pvk;
622 }
623 
624 template<typename ppT>
625 bool r1cs_gg_ppzksnark_online_verifier_weak_IC(
626  const r1cs_gg_ppzksnark_processed_verification_key<ppT> &pvk,
627  const r1cs_gg_ppzksnark_primary_input<ppT> &primary_input,
628  const r1cs_gg_ppzksnark_proof<ppT> &proof)
629 {
630  libff::enter_block("Call to r1cs_gg_ppzksnark_online_verifier_weak_IC");
631  assert(pvk.ABC_g1.domain_size() >= primary_input.size());
632 
633  libff::enter_block("Accumulate input");
634  const accumulation_vector<libff::G1<ppT>> accumulated_IC =
635  pvk.ABC_g1.template accumulate_chunk<libff::Fr<ppT>>(
636  primary_input.begin(), primary_input.end(), 0);
637  const libff::G1<ppT> &acc = accumulated_IC.first;
638  libff::leave_block("Accumulate input");
639 
640  bool result = true;
641 
642  libff::enter_block("Check if the proof is well-formed");
643  if (!proof.is_well_formed()) {
644  if (!libff::inhibit_profiling_info) {
645  libff::print_indent();
646  printf("At least one of the proof elements does not lie on the "
647  "curve.\n");
648  }
649  result = false;
650  }
651  libff::leave_block("Check if the proof is well-formed");
652 
653  libff::enter_block("Online pairing computations");
654  libff::enter_block("Check QAP divisibility");
655  const libff::G1_precomp<ppT> proof_g_A_precomp =
656  ppT::precompute_G1(proof.g_A);
657  const libff::G2_precomp<ppT> proof_g_B_precomp =
658  ppT::precompute_G2(proof.g_B);
659  const libff::G1_precomp<ppT> proof_g_C_precomp =
660  ppT::precompute_G1(proof.g_C);
661  const libff::G1_precomp<ppT> acc_precomp = ppT::precompute_G1(acc);
662 
663  const libff::Fqk<ppT> f =
664  ppT::miller_loop(pvk.vk_alpha_g1_precomp, pvk.vk_beta_g2_precomp);
665  const libff::GT<ppT> vk_alpha_g1_beta_g2 = ppT::final_exponentiation(f);
666 
667  const libff::Fqk<ppT> QAP1 =
668  ppT::miller_loop(proof_g_A_precomp, proof_g_B_precomp);
669  const libff::Fqk<ppT> QAP2 = ppT::double_miller_loop(
670  acc_precomp,
671  pvk.vk_generator_g2_precomp,
672  proof_g_C_precomp,
673  pvk.vk_delta_g2_precomp);
674  const libff::GT<ppT> QAP =
675  ppT::final_exponentiation(QAP1 * QAP2.unitary_inverse());
676 
677  if (QAP != vk_alpha_g1_beta_g2) {
678  if (!libff::inhibit_profiling_info) {
679  libff::print_indent();
680  printf("QAP divisibility check failed.\n");
681  }
682  result = false;
683  }
684  libff::leave_block("Check QAP divisibility");
685  libff::leave_block("Online pairing computations");
686 
687  libff::leave_block("Call to r1cs_gg_ppzksnark_online_verifier_weak_IC");
688 
689  return result;
690 }
691 
692 template<typename ppT>
693 bool r1cs_gg_ppzksnark_verifier_weak_IC(
694  const r1cs_gg_ppzksnark_verification_key<ppT> &vk,
695  const r1cs_gg_ppzksnark_primary_input<ppT> &primary_input,
696  const r1cs_gg_ppzksnark_proof<ppT> &proof)
697 {
698  libff::enter_block("Call to r1cs_gg_ppzksnark_verifier_weak_IC");
699  r1cs_gg_ppzksnark_processed_verification_key<ppT> pvk =
700  r1cs_gg_ppzksnark_verifier_process_vk<ppT>(vk);
701  bool result = r1cs_gg_ppzksnark_online_verifier_weak_IC<ppT>(
702  pvk, primary_input, proof);
703  libff::leave_block("Call to r1cs_gg_ppzksnark_verifier_weak_IC");
704  return result;
705 }
706 
707 template<typename ppT>
708 bool r1cs_gg_ppzksnark_online_verifier_strong_IC(
709  const r1cs_gg_ppzksnark_processed_verification_key<ppT> &pvk,
710  const r1cs_gg_ppzksnark_primary_input<ppT> &primary_input,
711  const r1cs_gg_ppzksnark_proof<ppT> &proof)
712 {
713  bool result = true;
714  libff::enter_block("Call to r1cs_gg_ppzksnark_online_verifier_strong_IC");
715 
716  if (pvk.ABC_g1.domain_size() != primary_input.size()) {
717  libff::print_indent();
718  printf(
719  "Input length differs from expected (got %zu, expected %zu).\n",
720  primary_input.size(),
721  pvk.ABC_g1.domain_size());
722  result = false;
723  } else {
724  result = r1cs_gg_ppzksnark_online_verifier_weak_IC(
725  pvk, primary_input, proof);
726  }
727 
728  libff::leave_block("Call to r1cs_gg_ppzksnark_online_verifier_strong_IC");
729  return result;
730 }
731 
732 template<typename ppT>
733 bool r1cs_gg_ppzksnark_verifier_strong_IC(
734  const r1cs_gg_ppzksnark_verification_key<ppT> &vk,
735  const r1cs_gg_ppzksnark_primary_input<ppT> &primary_input,
736  const r1cs_gg_ppzksnark_proof<ppT> &proof)
737 {
738  libff::enter_block("Call to r1cs_gg_ppzksnark_verifier_strong_IC");
739  r1cs_gg_ppzksnark_processed_verification_key<ppT> pvk =
740  r1cs_gg_ppzksnark_verifier_process_vk<ppT>(vk);
741  bool result = r1cs_gg_ppzksnark_online_verifier_strong_IC<ppT>(
742  pvk, primary_input, proof);
743  libff::leave_block("Call to r1cs_gg_ppzksnark_verifier_strong_IC");
744  return result;
745 }
746 
747 template<typename ppT>
748 bool r1cs_gg_ppzksnark_affine_verifier_weak_IC(
749  const r1cs_gg_ppzksnark_verification_key<ppT> &vk,
750  const r1cs_gg_ppzksnark_primary_input<ppT> &primary_input,
751  const r1cs_gg_ppzksnark_proof<ppT> &proof)
752 {
753  libff::enter_block("Call to r1cs_gg_ppzksnark_affine_verifier_weak_IC");
754  assert(vk.ABC_g1.domain_size() >= primary_input.size());
755 
756  libff::affine_ate_G2_precomp<ppT> pvk_vk_generator_g2_precomp =
757  ppT::affine_ate_precompute_G2(libff::G2<ppT>::one());
758  libff::affine_ate_G2_precomp<ppT> pvk_vk_delta_g2_precomp =
759  ppT::affine_ate_precompute_G2(vk.delta_g2);
760 
761  libff::enter_block("Accumulate input");
762  const accumulation_vector<libff::G1<ppT>> accumulated_IC =
763  vk.ABC_g1.template accumulate_chunk<libff::Fr<ppT>>(
764  primary_input.begin(), primary_input.end(), 0);
765  const libff::G1<ppT> &acc = accumulated_IC.first;
766  libff::leave_block("Accumulate input");
767 
768  bool result = true;
769 
770  libff::enter_block("Check if the proof is well-formed");
771  if (!proof.is_well_formed()) {
772  if (!libff::inhibit_profiling_info) {
773  libff::print_indent();
774  printf("At least one of the proof elements does not lie on the "
775  "curve.\n");
776  }
777  result = false;
778  }
779  libff::leave_block("Check if the proof is well-formed");
780 
781  libff::enter_block("Check QAP divisibility");
782  const libff::affine_ate_G1_precomp<ppT> proof_g_A_precomp =
783  ppT::affine_ate_precompute_G1(proof.g_A);
784  const libff::affine_ate_G2_precomp<ppT> proof_g_B_precomp =
785  ppT::affine_ate_precompute_G2(proof.g_B);
786  const libff::affine_ate_G1_precomp<ppT> proof_g_C_precomp =
787  ppT::affine_ate_precompute_G1(proof.g_C);
788  const libff::affine_ate_G1_precomp<ppT> acc_precomp =
789  ppT::affine_ate_precompute_G1(acc);
790 
791  const libff::Fqk<ppT> QAP_miller =
792  ppT::affine_ate_e_times_e_over_e_miller_loop(
793  acc_precomp,
794  pvk_vk_generator_g2_precomp,
795  proof_g_C_precomp,
796  pvk_vk_delta_g2_precomp,
797  proof_g_A_precomp,
798  proof_g_B_precomp);
799  const libff::GT<ppT> QAP =
800  ppT::final_exponentiation(QAP_miller.unitary_inverse());
801  const libff::GT<ppT> vk_alpha_g1_beta_g2 =
802  ppT::reduced_pairing(vk.alpha_g1, vk.beta_g2);
803 
804  if (QAP != vk_alpha_g1_beta_g2) {
805  if (!libff::inhibit_profiling_info) {
806  libff::print_indent();
807  printf("QAP divisibility check failed.\n");
808  }
809  result = false;
810  }
811  libff::leave_block("Check QAP divisibility");
812 
813  libff::leave_block("Call to r1cs_gg_ppzksnark_affine_verifier_weak_IC");
814 
815  return result;
816 }
817 
818 } // namespace libsnark
819 #endif // R1CS_GG_PPZKSNARK_TCC_