Clearmatics Libsnark  0.1
C++ library for zkSNARK proofs
r1cs_gg_ppzksnark_verifier_gadget.tcc
Go to the documentation of this file.
1 /** @file
2  *****************************************************************************
3  * @author This file is part of libsnark, developed by Clearmatics Ltd
4  * (originally developed by SCIPR Lab) and contributors
5  * (see AUTHORS).
6  * @copyright MIT license (see LICENSE file)
7  *****************************************************************************/
8 
9 #ifndef LIBSNARK_GADGETLIB1_GADGETS_VERFIERS_R1CS_GG_PPZKSNARK_VERIFIER_GADGET_TCC_
10 #define LIBSNARK_GADGETLIB1_GADGETS_VERFIERS_R1CS_GG_PPZKSNARK_VERIFIER_GADGET_TCC_
11 
12 #include "libsnark/gadgetlib1/constraint_profiling.hpp"
13 #include "libsnark/gadgetlib1/gadgets/verifiers/r1cs_gg_ppzksnark_verifier_gadget.hpp"
14 
15 namespace libsnark
16 {
17 
18 template<typename ppT>
19 r1cs_gg_ppzksnark_proof_variable<ppT>::r1cs_gg_ppzksnark_proof_variable(
20  protoboard<FieldT> &pb, const std::string &annotation_prefix)
21  : gadget<FieldT>(pb, annotation_prefix)
22 {
23 #ifndef NDEBUG
24  // g_A, g_C
25  const size_t num_G1 = 2;
26  // g_B
27  const size_t num_G2 = 1;
28 #endif
29 
30  _g_A.reset(new G1_variable<ppT>(pb, FMT(annotation_prefix, " g_A")));
31  _g_B.reset(new G2_variable<ppT>(pb, FMT(annotation_prefix, " g_B")));
32  _g_C.reset(new G1_variable<ppT>(pb, FMT(annotation_prefix, " g_C")));
33 
34  _all_G1_vars = {_g_A, _g_C};
35  _all_G2_vars = {_g_B};
36 
37  _all_G1_checkers.resize(_all_G1_vars.size());
38 
39  for (size_t i = 0; i < _all_G1_vars.size(); ++i) {
40  _all_G1_checkers[i].reset(new G1_checker<ppT>(
41  pb,
42  *_all_G1_vars[i],
43  FMT(annotation_prefix, " all_G1_checkers_%zu", i)));
44  }
45 
46  _G2_checker.reset(
47  new G2_checker<ppT>(pb, *_g_B, FMT(annotation_prefix, " G2_checker")));
48 
49  assert(_all_G1_vars.size() == num_G1);
50  assert(_all_G2_vars.size() == num_G2);
51 }
52 
53 template<typename ppT>
54 void r1cs_gg_ppzksnark_proof_variable<ppT>::generate_r1cs_constraints()
55 {
56  for (auto &G1_checker : _all_G1_checkers) {
57  G1_checker->generate_r1cs_constraints();
58  }
59 
60  _G2_checker->generate_r1cs_constraints();
61 }
62 
63 template<typename ppT>
64 void r1cs_gg_ppzksnark_proof_variable<ppT>::generate_r1cs_witness(
65  const r1cs_gg_ppzksnark_proof<other_curve<ppT>> &proof)
66 {
67  std::vector<libff::G1<other_curve<ppT>>> G1_elems;
68  std::vector<libff::G2<other_curve<ppT>>> G2_elems;
69 
70  G1_elems = {proof.g_A, proof.g_C};
71  G2_elems = {proof.g_B};
72 
73  assert(G1_elems.size() == _all_G1_vars.size());
74  assert(G2_elems.size() == _all_G2_vars.size());
75 
76  for (size_t i = 0; i < G1_elems.size(); ++i) {
77  _all_G1_vars[i]->generate_r1cs_witness(G1_elems[i]);
78  }
79 
80  for (size_t i = 0; i < G2_elems.size(); ++i) {
81  _all_G2_vars[i]->generate_r1cs_witness(G2_elems[i]);
82  }
83 
84  for (auto &G1_checker : _all_G1_checkers) {
85  G1_checker->generate_r1cs_witness();
86  }
87 
88  _G2_checker->generate_r1cs_witness();
89 }
90 
91 template<typename ppT> size_t r1cs_gg_ppzksnark_proof_variable<ppT>::size()
92 {
93  const size_t num_G1 = 2;
94  const size_t num_G2 = 1;
95  return (
96  num_G1 * G1_variable<ppT>::num_field_elems +
97  num_G2 * G2_variable<ppT>::num_field_elems);
98 }
99 
100 template<typename ppT>
101 r1cs_gg_ppzksnark_verification_key_variable<ppT>::
102  r1cs_gg_ppzksnark_verification_key_variable(
103  protoboard<libff::Fr<ppT>> &pb,
104  const size_t num_primary_inputs,
105  const std::string &annotation_prefix)
106  : gadget<FieldT>(pb, annotation_prefix)
107  , _alpha_g1(pb, FMT(annotation_prefix, " alpha_g1"))
108  , _beta_g2(pb, FMT(annotation_prefix, " beta_g2"))
109  , _delta_g2(pb, FMT(annotation_prefix, " delta_g2"))
110  , _encoded_ABC_base(
111  new G1_variable<ppT>(pb, FMT(annotation_prefix, " encoded_ABC_base")))
112  , _num_primary_inputs(num_primary_inputs)
113 {
114  // Populate _all_vars with alpha, beta, gamma and ABC_base variables.
115  _all_vars.insert(
116  _all_vars.end(), _alpha_g1.all_vars.begin(), _alpha_g1.all_vars.end());
117  _all_vars.insert(
118  _all_vars.end(), _beta_g2.all_vars.begin(), _beta_g2.all_vars.end());
119  _all_vars.insert(
120  _all_vars.end(), _delta_g2.all_vars.begin(), _delta_g2.all_vars.end());
121  _all_vars.insert(
122  _all_vars.end(),
123  _encoded_ABC_base->all_vars.begin(),
124  _encoded_ABC_base->all_vars.end());
125 
126  // Allocate variables for ABC_g1 elements, and populate _all_vars with each
127  // variable.
128  _ABC_g1.reserve(_num_primary_inputs);
129  for (size_t i = 0; i < _num_primary_inputs; ++i) {
130  _ABC_g1.emplace_back(new G1_variable<ppT>(
131  pb, FMT(annotation_prefix, " ABC_g1[%zu]", i)));
132  const G1_variable<ppT> &ivar = *(_ABC_g1.back());
133  _all_vars.insert(
134  _all_vars.end(), ivar.all_vars.begin(), ivar.all_vars.end());
135  }
136 }
137 
138 template<typename ppT>
139 void r1cs_gg_ppzksnark_verification_key_variable<
140  ppT>::generate_r1cs_constraints()
141 {
142 }
143 
144 template<typename ppT>
145 void r1cs_gg_ppzksnark_verification_key_variable<ppT>::generate_r1cs_witness(
146  const r1cs_gg_ppzksnark_verification_key<other_curve<ppT>> &vk)
147 {
148  assert(vk.ABC_g1.rest.size() == _num_primary_inputs);
149  _alpha_g1.generate_r1cs_witness(vk.alpha_g1);
150  _beta_g2.generate_r1cs_witness(vk.beta_g2);
151  _delta_g2.generate_r1cs_witness(vk.delta_g2);
152  _encoded_ABC_base->generate_r1cs_witness(vk.ABC_g1.first);
153  for (size_t i = 0; i < _num_primary_inputs; ++i) {
154  assert(vk.ABC_g1.rest.indices[i] == i);
155  _ABC_g1[i]->generate_r1cs_witness(vk.ABC_g1.rest.values[i]);
156  }
157 }
158 
159 template<typename ppT>
160 size_t r1cs_gg_ppzksnark_verification_key_variable<ppT>::num_primary_inputs()
161  const
162 {
163  return _num_primary_inputs;
164 }
165 
166 template<typename ppT>
167 const pb_linear_combination_array<libff::Fr<ppT>>
168  &r1cs_gg_ppzksnark_verification_key_variable<ppT>::get_all_vars() const
169 {
170  return _all_vars;
171 }
172 
173 template<typename ppT>
174 std::vector<libff::Fr<ppT>> r1cs_gg_ppzksnark_verification_key_variable<ppT>::
175  get_verification_key_scalars(
176  const r1cs_gg_ppzksnark_verification_key<other_curve<ppT>> &r1cs_vk)
177 {
178  // TODO: It would be much more efficient to simply iterate through the
179  // field elements of r1cs_vk, replicating the order in the constructor. For
180  // now, to avoid replicating that order (which also depends on the G1 and
181  // G2 variable gadgets), we instantiate this gadget and extract the values
182  // of _all_vars.
183 
184  const size_t num_primary_inputs = r1cs_vk.ABC_g1.rest.indices.size();
185 
186  protoboard<FieldT> pb;
187  r1cs_gg_ppzksnark_verification_key_variable<ppT> vk(
188  pb, num_primary_inputs, "vk");
189  vk.generate_r1cs_witness(r1cs_vk);
190  const pb_linear_combination_array<FieldT> &vk_vars = vk.get_all_vars();
191 
192  std::vector<FieldT> scalar_values;
193  scalar_values.reserve(vk_vars.size());
194  for (const pb_linear_combination<FieldT> &lc : vk_vars) {
195  scalar_values.push_back(pb.lc_val(lc));
196  }
197 
198  return scalar_values;
199 }
200 
201 template<typename ppT>
202 r1cs_gg_ppzksnark_preprocessed_verification_key_variable<
203  ppT>::r1cs_gg_ppzksnark_preprocessed_verification_key_variable()
204 {
205  // will be allocated outside
206 }
207 
208 template<typename ppT>
209 r1cs_gg_ppzksnark_preprocessed_verification_key_variable<ppT>::
210  r1cs_gg_ppzksnark_preprocessed_verification_key_variable(
211  protoboard<FieldT> &pb,
212  const r1cs_gg_ppzksnark_verification_key<other_curve<ppT>> &r1cs_vk,
213  const std::string &annotation_prefix)
214 {
215  _encoded_ABC_base.reset(new G1_variable<ppT>(
216  pb, r1cs_vk.ABC_g1.first, FMT(annotation_prefix, " encoded_ABC_base")));
217  _ABC_g1.resize(r1cs_vk.ABC_g1.rest.indices.size());
218  for (size_t i = 0; i < r1cs_vk.ABC_g1.rest.indices.size(); ++i) {
219  assert(r1cs_vk.ABC_g1.rest.indices[i] == i);
220  _ABC_g1[i].reset(new G1_variable<ppT>(
221  pb,
222  r1cs_vk.ABC_g1.rest.values[i],
223  FMT(annotation_prefix, " ABC_g1[%zu]", i)));
224  }
225 
226  _vk_alpha_g1_precomp.reset(new G1_precomputation<ppT>(
227  pb, r1cs_vk.alpha_g1, FMT(annotation_prefix, " vk_alpha_g1_precomp")));
228 
229  _vk_generator_g2_precomp.reset(new G2_precomputation<ppT>(
230  pb,
231  libff::G2<other_curve<ppT>>::one(),
232  FMT(annotation_prefix, " vk_generator_g2_precomp")));
233  _vk_beta_g2_precomp.reset(new G2_precomputation<ppT>(
234  pb, r1cs_vk.beta_g2, FMT(annotation_prefix, " vk_beta_g2_precomp")));
235  _vk_delta_g2_precomp.reset(new G2_precomputation<ppT>(
236  pb, r1cs_vk.delta_g2, FMT(annotation_prefix, " vk_delta_g2_precomp")));
237 }
238 
239 template<typename ppT>
240 r1cs_gg_ppzksnark_verifier_process_vk_gadget<ppT>::
241  r1cs_gg_ppzksnark_verifier_process_vk_gadget(
242  protoboard<FieldT> &pb,
243  const r1cs_gg_ppzksnark_verification_key_variable<ppT> &vk,
244  r1cs_gg_ppzksnark_preprocessed_verification_key_variable<ppT> &pvk,
245  const std::string &annotation_prefix)
246  : gadget<FieldT>(pb, annotation_prefix), _vk(vk), _pvk(pvk)
247 {
248  _pvk._encoded_ABC_base = vk._encoded_ABC_base;
249  _pvk._ABC_g1 = vk._ABC_g1;
250 
251  _pvk._vk_alpha_g1_precomp.reset(new G1_precomputation<ppT>());
252 
253  _pvk._vk_generator_g2_precomp.reset(new G2_precomputation<ppT>());
254  _pvk._vk_beta_g2_precomp.reset(new G2_precomputation<ppT>());
255  _pvk._vk_delta_g2_precomp.reset(new G2_precomputation<ppT>());
256 
257  _compute_vk_alpha_g1_precomp.reset(new precompute_G1_gadget<ppT>(
258  pb,
259  vk._alpha_g1,
260  *pvk._vk_alpha_g1_precomp,
261  FMT(annotation_prefix, " compute_vk_alpha_g1_precomp")));
262 
263  _pvk._vk_generator_g2_precomp.reset(new G2_precomputation<ppT>(
264  pb,
265  libff::G2<other_curve<ppT>>::one(),
266  FMT(annotation_prefix, " vk_generator_g2_precomp")));
267  _compute_vk_beta_g2_precomp.reset(new precompute_G2_gadget<ppT>(
268  pb,
269  vk._beta_g2,
270  *pvk._vk_beta_g2_precomp,
271  FMT(annotation_prefix, " compute_vk_beta_g2_precomp")));
272  _compute_vk_delta_g2_precomp.reset(new precompute_G2_gadget<ppT>(
273  pb,
274  vk._delta_g2,
275  *pvk._vk_delta_g2_precomp,
276  FMT(annotation_prefix, " compute_vk_delta_g2_precomp")));
277 }
278 
279 template<typename ppT>
280 void r1cs_gg_ppzksnark_verifier_process_vk_gadget<
281  ppT>::generate_r1cs_constraints()
282 {
283  _compute_vk_alpha_g1_precomp->generate_r1cs_constraints();
284 
285  _compute_vk_beta_g2_precomp->generate_r1cs_constraints();
286  _compute_vk_delta_g2_precomp->generate_r1cs_constraints();
287 }
288 
289 template<typename ppT>
290 void r1cs_gg_ppzksnark_verifier_process_vk_gadget<ppT>::generate_r1cs_witness()
291 {
292  _compute_vk_alpha_g1_precomp->generate_r1cs_witness();
293 
294  _compute_vk_beta_g2_precomp->generate_r1cs_witness();
295  _compute_vk_delta_g2_precomp->generate_r1cs_witness();
296 }
297 
298 template<typename ppT>
299 r1cs_gg_ppzksnark_online_verifier_gadget<ppT>::
300  r1cs_gg_ppzksnark_online_verifier_gadget(
301  protoboard<FieldT> &pb,
302  const r1cs_gg_ppzksnark_preprocessed_verification_key_variable<ppT>
303  &pvk,
304  const pb_variable_array<FieldT> &input,
305  const size_t elt_size,
306  const r1cs_gg_ppzksnark_proof_variable<ppT> &proof,
307  const pb_variable<FieldT> &result_QAP_valid,
308  const std::string &annotation_prefix)
309  : gadget<FieldT>(pb, annotation_prefix)
310  , _pvk(pvk)
311  , _input(input)
312  , _elt_size(elt_size)
313  , _proof(proof)
314  , _result(result_QAP_valid)
315  , _input_len(input.size())
316 {
317  // 1. Accumulate input and store base in acc
318  // See:
319  // https://github.com/clearmatics/libsnark/blob/master/libsnark/zk_proof_systems/ppzksnark/r1cs_gg_ppzksnark/r1cs_gg_ppzksnark.tcc#L568-L571
320  _acc.reset(new G1_variable<ppT>(pb, FMT(annotation_prefix, " acc")));
321  std::vector<G1_variable<ppT>> IC_terms;
322  for (size_t i = 0; i < _pvk._ABC_g1.size(); ++i) {
323  IC_terms.emplace_back(*(_pvk._ABC_g1[i]));
324  }
325  _accumulate_input.reset(new G1_multiscalar_mul_gadget<ppT>(
326  pb,
327  *(_pvk._encoded_ABC_base),
328  _input,
329  _elt_size,
330  IC_terms,
331  *_acc,
332  FMT(annotation_prefix, " accumulate_input")));
333 
334  // 2. Do the precomputations on the inputs of the pairings
335  // See:
336  // https://github.com/clearmatics/libsnark/blob/master/libsnark/zk_proof_systems/ppzksnark/r1cs_gg_ppzksnark/r1cs_gg_ppzksnark.tcc#L588-L591
337  //
338  // 2.1 Allocate the results of the precomputations
339  _proof_g_A_precomp.reset(new G1_precomputation<ppT>());
340  _proof_g_B_precomp.reset(new G2_precomputation<ppT>());
341  _proof_g_C_precomp.reset(new G1_precomputation<ppT>());
342  _acc_precomp.reset(new G1_precomputation<ppT>());
343  // 2.2 Do the precomputations
344  _compute_proof_g_A_precomp.reset(new precompute_G1_gadget<ppT>(
345  pb,
346  *(proof._g_A),
347  *_proof_g_A_precomp,
348  FMT(annotation_prefix, " compute_proof_g_A_precomp")));
349  _compute_proof_g_B_precomp.reset(new precompute_G2_gadget<ppT>(
350  pb,
351  *(proof._g_B),
352  *_proof_g_B_precomp,
353  FMT(annotation_prefix, " compute_proof_g_B_precomp")));
354  _compute_proof_g_C_precomp.reset(new precompute_G1_gadget<ppT>(
355  pb,
356  *(proof._g_C),
357  *_proof_g_C_precomp,
358  FMT(annotation_prefix, " compute_proof_g_C_precomp")));
359  _compute_acc_precomp.reset(new precompute_G1_gadget<ppT>(
360  pb,
361  *_acc,
362  *_acc_precomp,
363  FMT(annotation_prefix, " compute_acc_precomp")));
364 
365  // 3. Carry out the pairing checks to check QAP equation
366  _check_QAP_valid.reset(new check_e_equals_eee_gadget<ppT>(
367  pb,
368  // LHS
369  *_proof_g_A_precomp,
370  *_proof_g_B_precomp,
371  // RHS
372  *(pvk._vk_alpha_g1_precomp),
373  *(pvk._vk_beta_g2_precomp),
374  *(_acc_precomp),
375  *(pvk._vk_generator_g2_precomp),
376  *(_proof_g_C_precomp),
377  *(pvk._vk_delta_g2_precomp),
378  // Result of pairing check (allocated outside of this circuit)
379  _result,
380  FMT(annotation_prefix, " check_QAP_valid")));
381 }
382 
383 template<typename ppT>
384 void r1cs_gg_ppzksnark_online_verifier_gadget<ppT>::generate_r1cs_constraints()
385 {
386  // For the macros below
387  using namespace libsnark;
388 
389  PROFILE_CONSTRAINTS(this->pb, "accumulate verifier input")
390  {
391  libff::print_indent();
392  printf(
393  "* Number of bits as an input to verifier gadget: %zu\n",
394  _input.size());
395  _accumulate_input->generate_r1cs_constraints();
396  }
397 
398  PROFILE_CONSTRAINTS(this->pb, "rest of the verifier")
399  {
400  _compute_proof_g_A_precomp->generate_r1cs_constraints();
401  _compute_proof_g_B_precomp->generate_r1cs_constraints();
402  _compute_proof_g_C_precomp->generate_r1cs_constraints();
403  _compute_acc_precomp->generate_r1cs_constraints();
404 
405  _check_QAP_valid->generate_r1cs_constraints();
406  }
407 }
408 
409 template<typename ppT>
410 void r1cs_gg_ppzksnark_online_verifier_gadget<ppT>::generate_r1cs_witness()
411 {
412  _accumulate_input->generate_r1cs_witness();
413 
414  _compute_proof_g_A_precomp->generate_r1cs_witness();
415  _compute_proof_g_B_precomp->generate_r1cs_witness();
416  _compute_proof_g_C_precomp->generate_r1cs_witness();
417  _compute_acc_precomp->generate_r1cs_witness();
418 
419  _check_QAP_valid->generate_r1cs_witness();
420 }
421 
422 template<typename ppT>
423 r1cs_gg_ppzksnark_verifier_gadget<ppT>::r1cs_gg_ppzksnark_verifier_gadget(
424  protoboard<FieldT> &pb,
425  const r1cs_gg_ppzksnark_verification_key_variable<ppT> &vk,
426  const pb_variable_array<FieldT> &input,
427  const size_t elt_size,
428  const r1cs_gg_ppzksnark_proof_variable<ppT> &proof,
429  const pb_variable<FieldT> &result,
430  const std::string &annotation_prefix)
431  : gadget<FieldT>(pb, annotation_prefix)
432 {
433  _pvk.reset(
434  new r1cs_gg_ppzksnark_preprocessed_verification_key_variable<ppT>());
435  _compute_pvk.reset(new r1cs_gg_ppzksnark_verifier_process_vk_gadget<ppT>(
436  pb, vk, *_pvk, FMT(annotation_prefix, " compute_pvk")));
437  _online_verifier.reset(new r1cs_gg_ppzksnark_online_verifier_gadget<ppT>(
438  pb,
439  *_pvk,
440  input,
441  elt_size,
442  proof,
443  result,
444  FMT(annotation_prefix, " online_verifier")));
445 }
446 
447 template<typename ppT>
448 void r1cs_gg_ppzksnark_verifier_gadget<ppT>::generate_r1cs_constraints()
449 {
450  // For the macros below
451  using namespace libsnark;
452 
453  PROFILE_CONSTRAINTS(this->pb, "precompute pvk")
454  {
455  _compute_pvk->generate_r1cs_constraints();
456  }
457 
458  PROFILE_CONSTRAINTS(this->pb, "online verifier")
459  {
460  _online_verifier->generate_r1cs_constraints();
461  }
462 }
463 
464 template<typename ppT>
465 void r1cs_gg_ppzksnark_verifier_gadget<ppT>::generate_r1cs_witness()
466 {
467  _compute_pvk->generate_r1cs_witness();
468  _online_verifier->generate_r1cs_witness();
469 }
470 
471 } // namespace libsnark
472 
473 #endif // LIBSNARK_GADGETLIB1_GADGETS_VERFIERS_R1CS_GG_PPZKSNARK_VERIFIER_GADGET_TCC_