Clearmatics Libsnark  0.1
C++ library for zkSNARK proofs
scalar_multiplication.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_CURVE_SCALAR_MULTIPLICATION_TCC_
10 #define LIBSNARK_GADGETLIB1_GADGETS_CURVE_SCALAR_MULTIPLICATION_TCC_
11 
12 namespace libsnark
13 {
14 
15 template<typename ppT, typename groupT, typename groupVariableT>
16 variable_or_identity<ppT, groupT, groupVariableT>::variable_or_identity(
17  protoboard<FieldT> &pb, const std::string &annotation_prefix)
18  : gadget<FieldT>(pb, annotation_prefix), value(pb, annotation_prefix)
19 {
20  is_identity_var.allocate(pb, " is_identity");
21  is_identity = pb_linear_combination<FieldT>(is_identity_var);
22  generate_boolean_r1cs_constraint(
23  pb, is_identity, FMT(annotation_prefix, " is_identity_is_bool"));
24 }
25 
26 template<typename ppT, typename groupT, typename groupVariableT>
27 variable_or_identity<ppT, groupT, groupVariableT>::variable_or_identity(
28  protoboard<FieldT> &pb,
29  const groupT &P,
30  const std::string &annotation_prefix)
31  : gadget<FieldT>(pb, annotation_prefix), value(pb, P, annotation_prefix)
32 {
33  is_identity.assign(pb, P.is_zero() ? FieldT::one() : FieldT::zero());
34  is_identity.evaluate(pb);
35 }
36 
37 template<typename ppT, typename groupT, typename groupVariableT>
38 void variable_or_identity<ppT, groupT, groupVariableT>::generate_r1cs_witness(
39  const groupT &elt)
40 {
41  const bool is_zero = elt.is_zero();
42  value.generate_r1cs_witness(is_zero ? groupT::one() : elt);
43  generate_r1cs_witness(is_zero);
44 }
45 
46 template<typename ppT, typename groupT, typename groupVariableT>
47 void variable_or_identity<ppT, groupT, groupVariableT>::generate_r1cs_witness(
48  bool is_zero)
49 {
50  this->pb.val(is_identity_var) = is_zero ? FieldT::one() : FieldT::zero();
51 }
52 
53 template<typename ppT, typename groupT, typename groupVariableT>
54 groupT variable_or_identity<ppT, groupT, groupVariableT>::get_element() const
55 {
56  if (this->pb.lc_val(is_identity) == FieldT::one()) {
57  return groupT::zero();
58  }
59 
60  return value.get_element();
61 }
62 
63 template<
64  typename ppT,
65  typename groupT,
66  typename variableT,
67  typename variableSelectorT>
68 variable_or_identity_selector<ppT, groupT, variableT, variableSelectorT>::
69  variable_or_identity_selector(
70  protoboard<FieldT> &pb,
71  const pb_linear_combination<FieldT> &selector,
72  const variableOrIdentity &zero_case,
73  const variableOrIdentity &one_case,
74  const variableOrIdentity &result,
75  const std::string &annotation_prefix)
76  : gadget<libff::Fr<ppT>>(pb, annotation_prefix)
77  , value_selector(
78  pb,
79  selector,
80  zero_case.value,
81  one_case.value,
82  result.value,
83  FMT(annotation_prefix, " value_selector"))
84  , zero_case_is_identity(zero_case.is_identity)
85  , one_case_is_identity(one_case.is_identity)
86  , result_is_identity(result.is_identity)
87 {
88 }
89 
90 template<
91  typename ppT,
92  typename groupT,
93  typename variableT,
94  typename variableSelectorT>
95 void variable_or_identity_selector<ppT, groupT, variableT, variableSelectorT>::
96  generate_r1cs_constraints()
97 {
98  value_selector.generate_r1cs_constraints();
99  // result.is_identity - zero_case = selector * (one_case - zero_case)
100  this->pb.add_r1cs_constraint(
101  r1cs_constraint<FieldT>(
102  value_selector.selector,
103  one_case_is_identity - zero_case_is_identity,
104  result_is_identity - zero_case_is_identity),
105  FMT(this->annotation_prefix, " result_is_identity_constraint"));
106 }
107 
108 template<
109  typename ppT,
110  typename groupT,
111  typename variableT,
112  typename variableSelectorT>
113 void variable_or_identity_selector<ppT, groupT, variableT, variableSelectorT>::
114  generate_r1cs_witness()
115 {
116  value_selector.generate_r1cs_witness();
117  if (this->pb.lc_val(value_selector.selector) == FieldT::one()) {
118  this->pb.lc_val(result_is_identity) =
119  this->pb.lc_val(one_case_is_identity);
120  } else {
121  this->pb.lc_val(result_is_identity) =
122  this->pb.lc_val(zero_case_is_identity);
123  }
124 }
125 
126 template<
127  typename ppT,
128  typename groupT,
129  typename variableT,
130  typename variableSelectorT>
131 variable_and_variable_or_identity_selector<
132  ppT,
133  groupT,
134  variableT,
135  variableSelectorT>::
136  variable_and_variable_or_identity_selector(
137  protoboard<FieldT> &pb,
138  const pb_linear_combination<FieldT> &selector,
139  const variableOrIdentity &zero_case,
140  const variableT &one_case,
141  const variableOrIdentity &result,
142  const std::string &annotation_prefix)
143  : gadget<libff::Fr<ppT>>(pb, annotation_prefix)
144  , value_selector(
145  pb,
146  selector,
147  zero_case.value,
148  one_case,
149  result.value,
150  FMT(annotation_prefix, " value_selector"))
151  , zero_case_is_identity(zero_case.is_identity)
152  , result(result)
153 {
154 }
155 
156 template<
157  typename ppT,
158  typename groupT,
159  typename variableT,
160  typename variableSelectorT>
161 void variable_and_variable_or_identity_selector<
162  ppT,
163  groupT,
164  variableT,
165  variableSelectorT>::generate_r1cs_constraints()
166 {
167  value_selector.generate_r1cs_constraints();
168  // result.is_identity = (1 - selector) * zero_case.is_identity
169  this->pb.add_r1cs_constraint(
170  r1cs_constraint<FieldT>(
171  FieldT::one() - value_selector.selector,
172  zero_case_is_identity,
173  result.is_identity),
174  FMT(this->annotation_prefix, " result_is_identity_constraint"));
175 }
176 
177 template<
178  typename ppT,
179  typename groupT,
180  typename variableT,
181  typename variableSelectorT>
182 void variable_and_variable_or_identity_selector<
183  ppT,
184  groupT,
185  variableT,
186  variableSelectorT>::generate_r1cs_witness()
187 {
188  value_selector.generate_r1cs_witness();
189  const bool selector_value =
190  this->pb.lc_val(value_selector.selector) == FieldT::one();
191  if (selector_value) {
192  result.generate_r1cs_witness(false);
193  } else {
194  const bool zero_case_is_identity_value =
195  this->pb.lc_val(zero_case_is_identity) == FieldT::one();
196  result.generate_r1cs_witness(zero_case_is_identity_value);
197  }
198 }
199 
200 template<
201  typename ppT,
202  typename groupT,
203  typename groupVariableT,
204  typename variableSelectorT,
205  typename addGadgetT>
206 add_variable_or_identity<
207  ppT,
208  groupT,
209  groupVariableT,
210  variableSelectorT,
211  addGadgetT>::
212  add_variable_or_identity(
213  protoboard<FieldT> &pb,
214  const variableOrIdentity &A,
215  const variableOrIdentity &B,
216  const variableOrIdentity &result,
217  const std::string &annotation_prefix)
218  : gadget<FieldT>(pb, annotation_prefix)
219  , add_result(pb, FMT(annotation_prefix, " add_result"))
220  , add(pb, A.value, B.value, add_result, FMT(annotation_prefix, " add"))
221  , A_not_identity_result(
222  pb, FMT(annotation_prefix, " A_not_identity_result"))
223  , selector_A_not_identity(
224  pb,
225  B.is_identity,
226  add_result,
227  A.value,
228  A_not_identity_result,
229  FMT(annotation_prefix, " selector_A_not_identity"))
230  , selector_A(
231  pb,
232  A.is_identity,
233  A_not_identity_result,
234  B.value,
235  result.value,
236  FMT(annotation_prefix, " selector_A"))
237  , result(result)
238 {
239 }
240 
241 template<
242  typename ppT,
243  typename groupT,
244  typename groupVariableT,
245  typename variableSelectorT,
246  typename addGadgetT>
247 void add_variable_or_identity<
248  ppT,
249  groupT,
250  groupVariableT,
251  variableSelectorT,
252  addGadgetT>::generate_r1cs_constraints()
253 {
254  add.generate_r1cs_constraints();
255  selector_A_not_identity.generate_r1cs_constraints();
256  selector_A.generate_r1cs_constraints();
257 
258  // result.is_identity = A.is_identity * B.is_identity
259  // (no need to call generate_r1cs_constraints() on result itself)
260  this->pb.add_r1cs_constraint(
261  r1cs_constraint<libff::Fr<ppT>>(
262  selector_A.selector, // A.is_identity
263  selector_A_not_identity.selector, // B.is_identity
264  result.is_identity),
265  FMT(this->annotation_prefix, " result.is_identity"));
266 }
267 
268 template<
269  typename ppT,
270  typename groupT,
271  typename groupVariableT,
272  typename variableSelectorT,
273  typename addGadgetT>
274 void add_variable_or_identity<
275  ppT,
276  groupT,
277  groupVariableT,
278  variableSelectorT,
279  addGadgetT>::generate_r1cs_witness()
280 {
281  add.generate_r1cs_witness();
282  selector_A_not_identity.generate_r1cs_witness();
283 
284  // Generate result.value via the result of selector_A, and set
285  // result.is_identity manually via result.generate_r1cs_witness().
286  selector_A.generate_r1cs_witness();
287 
288  const libff::Fr<ppT> result_is_identity =
289  this->pb.lc_val(selector_A.selector) *
290  this->pb.lc_val(selector_A_not_identity.selector);
291  result.generate_r1cs_witness(result_is_identity == libff::Fr<ppT>::one());
292 }
293 
294 template<
295  typename ppT,
296  typename groupT,
297  typename groupVariableT,
298  typename variableSelectorT,
299  typename addGadgetT>
300 add_variable_and_variable_or_identity<
301  ppT,
302  groupT,
303  groupVariableT,
304  variableSelectorT,
305  addGadgetT>::
306  add_variable_and_variable_or_identity(
307  protoboard<FieldT> &pb,
308  const variableOrIdentity &A,
309  const groupVariableT &B,
310  const groupVariableT &result,
311  const std::string &annotation_prefix)
312  : gadget<FieldT>(pb, annotation_prefix)
313  , result(result)
314  , add_result(pb, FMT(annotation_prefix, " add_result"))
315  , add(pb, A.value, B, add_result, FMT(annotation_prefix, " add"))
316  , selector_A(
317  pb,
318  A.is_identity,
319  add_result,
320  B,
321  result,
322  FMT(annotation_prefix, " selector_A"))
323 {
324 }
325 
326 template<
327  typename ppT,
328  typename groupT,
329  typename groupVariableT,
330  typename variableSelectorT,
331  typename addGadgetT>
332 void add_variable_and_variable_or_identity<
333  ppT,
334  groupT,
335  groupVariableT,
336  variableSelectorT,
337  addGadgetT>::generate_r1cs_constraints()
338 {
339  add.generate_r1cs_constraints();
340  selector_A.generate_r1cs_constraints();
341 }
342 
343 template<
344  typename ppT,
345  typename groupT,
346  typename groupVariableT,
347  typename variableSelectorT,
348  typename addGadgetT>
349 void add_variable_and_variable_or_identity<
350  ppT,
351  groupT,
352  groupVariableT,
353  variableSelectorT,
354  addGadgetT>::generate_r1cs_witness()
355 {
356  add.generate_r1cs_witness();
357  selector_A.generate_r1cs_witness();
358 }
359 
360 template<
361  typename ppT,
362  typename groupT,
363  typename groupVariableT,
364  typename dblGadgetT>
365 dbl_variable_or_identity<ppT, groupT, groupVariableT, dblGadgetT>::
366  dbl_variable_or_identity(
367  protoboard<FieldT> &pb,
368  const variableOrIdentity &A,
369  const variableOrIdentity &result,
370  const std::string &annotation_prefix)
371  : gadget<libff::Fr<ppT>>(pb, annotation_prefix)
372  , A_is_identity(A.is_identity)
373  , result(result)
374  , double_gadget(
375  pb, A.value, result.value, FMT(annotation_prefix, " double_gadget"))
376 {
377 }
378 
379 template<
380  typename ppT,
381  typename groupT,
382  typename groupVariableT,
383  typename dblGadgetT>
384 void dbl_variable_or_identity<ppT, groupT, groupVariableT, dblGadgetT>::
385  generate_r1cs_constraints()
386 {
387  // It should be possible to do this by simply assigning A.is_identity to
388  // result.is_identity, but result.is_identity has already been allocated at
389  // this stage.
390 
391  this->pb.add_r1cs_constraint(
392  r1cs_constraint<FieldT>(
393  A_is_identity, libff::Fr<ppT>::one(), result.is_identity),
394  FMT(this->annotation_prefix, " result_is_identity_constraint"));
395  double_gadget.generate_r1cs_constraints();
396 }
397 
398 template<
399  typename ppT,
400  typename groupT,
401  typename groupVariableT,
402  typename dblGadgetT>
403 void dbl_variable_or_identity<ppT, groupT, groupVariableT, dblGadgetT>::
404  generate_r1cs_witness()
405 {
406  A_is_identity.evaluate(this->pb);
407  this->pb.lc_val(result.is_identity) = this->pb.lc_val(A_is_identity);
408  double_gadget.generate_r1cs_witness();
409 }
410 
411 template<
412  typename groupT,
413  typename groupVariableT,
414  typename add_gadget,
415  typename dbl_gadget,
416  typename scalarT>
417 point_mul_by_const_scalar_gadget<
418  groupT,
419  groupVariableT,
420  add_gadget,
421  dbl_gadget,
422  scalarT>::
423  point_mul_by_const_scalar_gadget(
424  protoboard<FieldT> &pb,
425  const scalarT &scalar,
426  const groupVariableT &P,
427  const groupVariableT &result,
428  const std::string &annotation_prefix)
429  : gadget<FieldT>(pb, annotation_prefix), _scalar(scalar), _result(result)
430 {
431  const size_t last_bit = _scalar.num_bits() - 1;
432  const groupVariableT *last_value = &P;
433 
434  // Temporary vector of intermediate variables. Reserve the maximum number
435  // of possible entries to ensure no reallocation (i.e. last_value is always
436  // valid).
437  std::vector<groupVariableT> values;
438  values.reserve(2 * last_bit);
439 
440  for (size_t i = last_bit - 1; i > 0; --i) {
441  // Double
442  values.emplace_back(pb, FMT(annotation_prefix, " value[%zu]", i));
443  _dbl_gadgets.emplace_back(new dbl_gadget(
444  pb,
445  *last_value,
446  values.back(),
447  FMT(annotation_prefix, " double[%zu]", i)));
448  last_value = &values.back();
449 
450  // Add
451  if (_scalar.test_bit(i)) {
452  values.emplace_back(pb, FMT(annotation_prefix, " value[%zu]", i));
453  _add_gadgets.emplace_back(new add_gadget(
454  pb,
455  *last_value,
456  P,
457  values.back(),
458  FMT(annotation_prefix, " add[%zu]", i)));
459  last_value = &values.back();
460  }
461  }
462 
463  // Depending on the value of the final (lowest-order) bit, perform final
464  // double or double-and-add into result.
465 
466  if (_scalar.test_bit(0)) {
467  // Double
468  values.emplace_back(pb, FMT(annotation_prefix, " value[0]"));
469  _dbl_gadgets.emplace_back(new dbl_gadget(
470  pb,
471  *last_value,
472  values.back(),
473  FMT(annotation_prefix, " double[0]")));
474  last_value = &values.back();
475 
476  // Add into result
477  _add_gadgets.emplace_back(new add_gadget(
478  pb, *last_value, P, result, FMT(annotation_prefix, " add[0]")));
479  } else {
480  // Double
481  _dbl_gadgets.emplace_back(new dbl_gadget(
482  pb, *last_value, result, FMT(annotation_prefix, " double[0]")));
483  }
484 }
485 
486 template<
487  typename groupT,
488  typename groupVariableT,
489  typename add_gadget,
490  typename dbl_gadget,
491  typename scalarT>
492 void point_mul_by_const_scalar_gadget<
493  groupT,
494  groupVariableT,
495  add_gadget,
496  dbl_gadget,
497  scalarT>::generate_r1cs_constraints()
498 {
499  const size_t last_bit = _scalar.num_bits() - 1;
500  size_t dbl_idx = 0;
501  size_t add_idx = 0;
502  for (ssize_t i = last_bit - 1; i >= 0; --i) {
503  // Double gadget constraints
504  _dbl_gadgets[dbl_idx++]->generate_r1cs_constraints();
505 
506  // Add gadget constraints
507  if (_scalar.test_bit(i)) {
508  _add_gadgets[add_idx++]->generate_r1cs_constraints();
509  }
510  }
511 }
512 
513 template<
514  typename groupT,
515  typename groupVariableT,
516  typename add_gadget,
517  typename dbl_gadget,
518  typename scalarT>
519 void point_mul_by_const_scalar_gadget<
520  groupT,
521  groupVariableT,
522  add_gadget,
523  dbl_gadget,
524  scalarT>::generate_r1cs_witness()
525 {
526  const size_t last_bit = _scalar.num_bits() - 1;
527  size_t dbl_idx = 0;
528  size_t add_idx = 0;
529  for (ssize_t i = last_bit - 1; i >= 0; --i) {
530  // Double gadget constraints
531  _dbl_gadgets[dbl_idx++]->generate_r1cs_witness();
532 
533  // Add gadget constraints
534  if (_scalar.test_bit(i)) {
535  _add_gadgets[add_idx++]->generate_r1cs_witness();
536  }
537  }
538 }
539 
540 template<
541  typename groupT,
542  typename groupVariableT,
543  typename add_gadget,
544  typename dbl_gadget,
545  typename scalarT>
546 const groupVariableT &point_mul_by_const_scalar_gadget<
547  groupT,
548  groupVariableT,
549  add_gadget,
550  dbl_gadget,
551  scalarT>::result() const
552 {
553  return _result;
554 }
555 
556 template<
557  typename ppT,
558  typename groupT,
559  typename groupVarT,
560  typename selectorGadgetT,
561  typename addGadgetT,
562  typename dblGadgetT>
563 point_mul_by_scalar_gadget<
564  ppT,
565  groupT,
566  groupVarT,
567  selectorGadgetT,
568  addGadgetT,
569  dblGadgetT>::
570  point_mul_by_scalar_gadget(
571  protoboard<Field> &pb,
572  const pb_linear_combination<Field> &scalar,
573  const groupVarT &P,
574  const groupVarOrIdentity &result,
575  const std::string &annotation_prefix)
576  : gadget<Field>(pb, annotation_prefix)
577  , scalar_unpacked(
578  pb,
579  create_variable_array_for_bits(pb, annotation_prefix),
580  scalar,
581  FMT(annotation_prefix, " scalar_as_bits"))
582 {
583  add_gadgets.reserve(nFr::num_bits - 1);
584  dbl_gadgets.reserve(nFr::num_bits - 1);
585  selector_gadgets.reserve(nFr::num_bits);
586 
587  // Given n bits:
588  // res = select(scalar_as_bits[n-1], P, one)
589  // for i = n-2 ... 0:
590  // res = dbl(res)
591  // res = select(scalar_as_bits[i], add(res, P), res)
592 
593  // Lowest order bit has smallest index in scalar_unpacked.bits
594 
595  // First selector must choose (bit[num_bits - 1] ? P : zero)
596 
597  selector_gadgets.emplace_back(
598  pb,
599  scalar_unpacked.bits[nFr::num_bits - 1],
600  groupVarOrIdentity(pb, groupT::zero(), FMT(annotation_prefix, " zero")),
601  P,
602  groupVarOrIdentity(
603  pb,
604  FMT(annotation_prefix, " select_result[%zu]", nFr::num_bits - 1)),
605  FMT(annotation_prefix, " selector_gadgets[%zu]", nFr::num_bits - 1));
606 
607  for (size_t i = nFr::num_bits - 2; i > 0; --i) {
608  // Double
609  dbl_gadgets.emplace_back(
610  pb,
611  selector_gadgets.back().result,
612  groupVarOrIdentity(
613  pb, FMT(annotation_prefix, " dbl_result[%zu]", i)),
614  FMT(annotation_prefix, " dbl_gadgets[%zu]", i));
615 
616  // Add
617  add_gadgets.emplace_back(
618  pb,
619  dbl_gadgets.back().result,
620  P,
621  groupVarT(pb, FMT(annotation_prefix, " add_result[%zu]", i)),
622  FMT(annotation_prefix, " add_gadgets[%zu]", i));
623 
624  // Select the doubled or double-and-added output value, based on the
625  // currenet bit of scalar_unpacked.
626  //
627  // If bit == 0, the selector should output result of the dbl (*last).
628  // For bit == 1, it should output the result of the add.
629 
630  selector_gadgets.emplace_back(
631  pb,
632  scalar_unpacked.bits[i],
633  dbl_gadgets.back().result,
634  add_gadgets.back().result,
635  groupVarOrIdentity(
636  pb, FMT(annotation_prefix, " select_result[%zu]", i)),
637  FMT(annotation_prefix, " selector_gadgets[%zu]", i));
638  }
639 
640  // Handle the 0-th bit. Perform the double as usual, but adjust the inputs
641  // to the final add based on the 0-th bit (namely, if the 0-th bit is 0, we
642  // use a dummy addition to avoid division by 0 - see comment in
643  // scalar_multiplication.hpp).
644 
645  dbl_gadgets.emplace_back(
646  pb,
647  selector_gadgets.back().result,
648  groupVarOrIdentity(pb, FMT(annotation_prefix, " dbl_result[0]")),
649  FMT(annotation_prefix, " dbl_gadgets[0]"));
650 
651  // In pseudo-code:
652  //
653  // if bits[0]:
654  // left_input = dbl_gadgets.back().result
655  // right_input = P
656  // else:
657  // left_input = GroupT::one()
658  // right_input = GroupT::one() + GroupT::one()
659  //
660  // final_add = addVarAndVarOrIdentityGadget(left_input, right_input)
661 
662  pb_linear_combination<Field> final_add_input_select;
663  final_add_input_select.assign(
664  pb, pb_variable<Field>(0) - scalar_unpacked.bits[0]);
665 
666  final_add_input_left.reset(new selectVarOrVarIdentityGadget(
667  pb,
668  final_add_input_select,
669  dbl_gadgets.back().result,
670  groupVarT(
671  pb,
672  groupT::one(),
673  FMT(annotation_prefix, " final_add_input_left_dummy")),
674  groupVarOrIdentity(
675  pb, FMT(annotation_prefix, " final_add_input_left_result")),
676  FMT(annotation_prefix, " final_add_input_left")));
677 
678  final_add_input_right.reset(new selectorGadgetT(
679  pb,
680  final_add_input_select,
681  P,
682  groupVarT(
683  pb,
684  groupT::one() + groupT::one(),
685  FMT(annotation_prefix, " final_add_input_right_dummy")),
686  groupVarT(pb, FMT(annotation_prefix, " final_add_input_left_result")),
687  FMT(annotation_prefix, " final_add_input_right")));
688 
689  add_gadgets.emplace_back(
690  pb,
691  final_add_input_left->result,
692  final_add_input_right->result,
693  groupVarT(pb, FMT(annotation_prefix, " add_result[0]")),
694  FMT(annotation_prefix, " add_gadgets[0]"));
695 
696  // Final selector outputs to the result:
697  //
698  // if bit[0]:
699  // result = final_add
700  // else:
701  // result = dbl_gadgets.back().result
702 
703  selector_gadgets.emplace_back(
704  pb,
705  scalar_unpacked.bits[0],
706  dbl_gadgets.back().result,
707  add_gadgets.back().result,
708  result,
709  FMT(annotation_prefix, " selector_gadgets[0]"));
710 
711  assert(selector_gadgets.size() == nFr::num_bits);
712  assert(dbl_gadgets.size() == nFr::num_bits - 1);
713  assert(add_gadgets.size() == nFr::num_bits - 1);
714 }
715 
716 template<
717  typename ppT,
718  typename groupT,
719  typename groupVarT,
720  typename selectorGadgetT,
721  typename addGadgetT,
722  typename dblGadgetT>
723 void point_mul_by_scalar_gadget<
724  ppT,
725  groupT,
726  groupVarT,
727  selectorGadgetT,
728  addGadgetT,
729  dblGadgetT>::generate_r1cs_constraints()
730 {
731  scalar_unpacked.generate_r1cs_constraints(true);
732  selector_gadgets[0].generate_r1cs_constraints();
733  for (size_t i = 0; i < nFr::num_bits - 2; ++i) {
734  dbl_gadgets[i].generate_r1cs_constraints();
735  add_gadgets[i].generate_r1cs_constraints();
736  selector_gadgets[i + 1].generate_r1cs_constraints();
737  }
738 
739  dbl_gadgets.back().generate_r1cs_constraints();
740  final_add_input_left->generate_r1cs_constraints();
741  final_add_input_right->generate_r1cs_constraints();
742  add_gadgets.back().generate_r1cs_constraints();
743  selector_gadgets.back().generate_r1cs_constraints();
744 }
745 
746 template<
747  typename ppT,
748  typename groupT,
749  typename groupVarT,
750  typename selectorGadgetT,
751  typename addGadgetT,
752  typename dblGadgetT>
753 void point_mul_by_scalar_gadget<
754  ppT,
755  groupT,
756  groupVarT,
757  selectorGadgetT,
758  addGadgetT,
759  dblGadgetT>::generate_r1cs_witness()
760 {
761  // Assign and evaluate in the same order as in the constructor /
762  // generate_r1cs_constraints - first selector_gadget is used first,
763  // followed by repeated double-add-select.
764 
765  scalar_unpacked.generate_r1cs_witness_from_packed();
766  selector_gadgets[0].generate_r1cs_witness();
767 
768  for (size_t i = 0; i < nFr::num_bits - 2; ++i) {
769  dbl_gadgets[i].generate_r1cs_witness();
770  add_gadgets[i].generate_r1cs_witness();
771 
772  selector_gadgets[i + 1].generate_r1cs_witness();
773  }
774 
775  dbl_gadgets.back().generate_r1cs_witness();
776  final_add_input_right->selector.evaluate(this->pb);
777 
778  final_add_input_left->generate_r1cs_witness();
779  final_add_input_right->generate_r1cs_witness();
780  add_gadgets.back().generate_r1cs_witness();
781  selector_gadgets.back().generate_r1cs_witness();
782 }
783 
784 template<
785  typename ppT,
786  typename groupT,
787  typename groupVarT,
788  typename selectorGadgetT,
789  typename addGadgetT,
790  typename dblGadgetT>
791 const variable_or_identity<ppT, groupT, groupVarT> &point_mul_by_scalar_gadget<
792  ppT,
793  groupT,
794  groupVarT,
795  selectorGadgetT,
796  addGadgetT,
797  dblGadgetT>::result() const
798 {
799  return selector_gadgets.back().result;
800 }
801 
802 template<
803  typename ppT,
804  typename groupT,
805  typename groupVarT,
806  typename selectorGadgetT,
807  typename addGadgetT,
808  typename dblGadgetT>
809 pb_variable_array<libff::Fr<ppT>> point_mul_by_scalar_gadget<
810  ppT,
811  groupT,
812  groupVarT,
813  selectorGadgetT,
814  addGadgetT,
815  dblGadgetT>::
816  create_variable_array_for_bits(
817  protoboard<Field> &pb, const std::string &annotation_prefix)
818 {
819  pb_variable_array<Field> bits;
820  bits.allocate(pb, nFr::num_bits, FMT(annotation_prefix, " unpacked_bits"));
821  return bits;
822 }
823 
824 } // namespace libsnark
825 
826 #endif // LIBSNARK_GADGETLIB1_GADGETS_CURVE_SCALAR_MULTIPLICATION_TCC_