Clearmatics Libsnark  0.1
C++ library for zkSNARK proofs
weierstrass_g2_gadget.tcc
Go to the documentation of this file.
1 /** @file
2  *****************************************************************************
3 
4  Implementation of interfaces for G2 gadgets.
5 
6  See weierstrass_g2_gadgets.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 WEIERSTRASS_G2_GADGET_TCC_
15 #define WEIERSTRASS_G2_GADGET_TCC_
16 
17 #include <libff/algebra/scalar_multiplication/wnaf.hpp>
18 
19 namespace libsnark
20 {
21 
22 template<typename ppT>
23 G2_variable<ppT>::G2_variable(
24  protoboard<FieldT> &pb, const std::string &annotation_prefix)
25  : gadget<FieldT>(pb, annotation_prefix)
26 {
27  X.reset(new Fqe_variable<ppT>(pb, FMT(annotation_prefix, " X")));
28  Y.reset(new Fqe_variable<ppT>(pb, FMT(annotation_prefix, " Y")));
29 
30  all_vars.insert(all_vars.end(), X->all_vars.begin(), X->all_vars.end());
31  all_vars.insert(all_vars.end(), Y->all_vars.begin(), Y->all_vars.end());
32 }
33 
34 template<typename ppT>
35 G2_variable<ppT>::G2_variable(
36  protoboard<FieldT> &pb,
37  const libff::G2<other_curve<ppT>> &Q,
38  const std::string &annotation_prefix)
39  : gadget<FieldT>(pb, annotation_prefix)
40 {
41  libff::G2<other_curve<ppT>> Q_copy = Q;
42  Q_copy.to_affine_coordinates();
43 
44  X.reset(new Fqe_variable<ppT>(pb, Q_copy.X, FMT(annotation_prefix, " X")));
45  Y.reset(new Fqe_variable<ppT>(pb, Q_copy.Y, FMT(annotation_prefix, " Y")));
46 
47  all_vars.insert(all_vars.end(), X->all_vars.begin(), X->all_vars.end());
48  all_vars.insert(all_vars.end(), Y->all_vars.begin(), Y->all_vars.end());
49 }
50 
51 template<typename ppT>
52 G2_variable<ppT>::G2_variable(
53  protoboard<FieldT> &pb,
54  const Fqe_variable<ppT> &X_coord,
55  const Fqe_variable<ppT> &Y_coord,
56  const std::string &annotation_prefix)
57  : gadget<FieldT>(pb, annotation_prefix)
58  , X(new Fqe_variable<ppT>(X_coord))
59  , Y(new Fqe_variable<ppT>(Y_coord))
60 {
61  all_vars.insert(all_vars.end(), X->all_vars.begin(), X->all_vars.end());
62  all_vars.insert(all_vars.end(), Y->all_vars.begin(), Y->all_vars.end());
63 }
64 
65 template<typename ppT> G2_variable<ppT> G2_variable<ppT>::operator-() const
66 {
67  return G2_variable<ppT>(
68  this->pb, *X, -(*Y), FMT(this->annotation_prefix, " negative"));
69 }
70 
71 template<typename ppT>
72 void G2_variable<ppT>::generate_r1cs_witness(
73  const libff::G2<other_curve<ppT>> &Q)
74 {
75  libff::G2<other_curve<ppT>> Qcopy = Q;
76  Qcopy.to_affine_coordinates();
77 
78  X->generate_r1cs_witness(Qcopy.X);
79  Y->generate_r1cs_witness(Qcopy.Y);
80 }
81 
82 template<typename ppT>
83 libff::G2<other_curve<ppT>> G2_variable<ppT>::get_element() const
84 {
85  using nppT = other_curve<ppT>;
86  return libff::G2<nppT>(
87  X->get_element(),
88  Y->get_element(),
89  libff::G2<nppT>::twist_field::one());
90 }
91 
92 template<typename ppT> size_t G2_variable<ppT>::size_in_bits()
93 {
94  return 2 * Fqe_variable<ppT>::size_in_bits();
95 }
96 
97 template<typename ppT> size_t G2_variable<ppT>::num_variables()
98 {
99  return 2 * Fqe_variable<ppT>::num_variables();
100 }
101 
102 template<typename ppT>
103 G2_variable_selector_gadget<ppT>::G2_variable_selector_gadget(
104  protoboard<Field> &pb,
105  const pb_linear_combination<Field> &selector,
106  const G2_variable<ppT> &zero_case,
107  const G2_variable<ppT> &one_case,
108  const G2_variable<ppT> &result,
109  const std::string &annotation_prefix)
110  : gadget<Field>(pb, annotation_prefix)
111  , selector(selector)
112  , zero_case(zero_case)
113  , one_case(one_case)
114  , result(result)
115  , mul_select_X(
116  pb,
117  *one_case.X - *zero_case.X,
118  selector,
119  *result.X - *zero_case.X,
120  FMT(annotation_prefix, " mul_select_X"))
121  , mul_select_Y(
122  pb,
123  *one_case.Y - *zero_case.Y,
124  selector,
125  *result.Y - *zero_case.Y,
126  FMT(annotation_prefix, " mul_select_Y"))
127 {
128 }
129 
130 template<typename ppT>
131 void G2_variable_selector_gadget<ppT>::generate_r1cs_constraints()
132 {
133  mul_select_X.generate_r1cs_constraints();
134  mul_select_Y.generate_r1cs_constraints();
135 }
136 
137 template<typename ppT>
138 void G2_variable_selector_gadget<ppT>::generate_r1cs_witness()
139 {
140  protoboard<Field> &pb = this->pb;
141  selector.evaluate(pb);
142 
143  zero_case.X->evaluate();
144  zero_case.Y->evaluate();
145  one_case.X->evaluate();
146  one_case.Y->evaluate();
147  mul_select_X.generate_r1cs_witness();
148  mul_select_Y.generate_r1cs_witness();
149 
150  if (pb.lc_val(selector) == Field::one()) {
151  result.generate_r1cs_witness(one_case.get_element());
152  } else {
153  result.generate_r1cs_witness(zero_case.get_element());
154  }
155 }
156 
157 template<typename ppT>
158 G2_checker_gadget<ppT>::G2_checker_gadget(
159  protoboard<FieldT> &pb,
160  const G2_variable<ppT> &Q,
161  const std::string &annotation_prefix)
162  : gadget<FieldT>(pb, annotation_prefix), Q(Q)
163 {
164  Xsquared.reset(
165  new Fqe_variable<ppT>(pb, FMT(annotation_prefix, " Xsquared")));
166  Ysquared.reset(
167  new Fqe_variable<ppT>(pb, FMT(annotation_prefix, " Ysquared")));
168 
169  compute_Xsquared.reset(new Fqe_sqr_gadget<ppT>(
170  pb, *(Q.X), *Xsquared, FMT(annotation_prefix, " compute_Xsquared")));
171  compute_Ysquared.reset(new Fqe_sqr_gadget<ppT>(
172  pb, *(Q.Y), *Ysquared, FMT(annotation_prefix, " compute_Ysquared")));
173 
174  Xsquared_plus_a.reset(new Fqe_variable<ppT>(
175  (*Xsquared) + libff::G2<other_curve<ppT>>::coeff_a));
176  Ysquared_minus_b.reset(new Fqe_variable<ppT>(
177  (*Ysquared) + (-libff::G2<other_curve<ppT>>::coeff_b)));
178 
179  curve_equation.reset(new Fqe_mul_gadget<ppT>(
180  pb,
181  *(Q.X),
182  *Xsquared_plus_a,
183  *Ysquared_minus_b,
184  FMT(annotation_prefix, " curve_equation")));
185 }
186 
187 template<typename ppT> void G2_checker_gadget<ppT>::generate_r1cs_constraints()
188 {
189  compute_Xsquared->generate_r1cs_constraints();
190  compute_Ysquared->generate_r1cs_constraints();
191  curve_equation->generate_r1cs_constraints();
192 }
193 
194 template<typename ppT> void G2_checker_gadget<ppT>::generate_r1cs_witness()
195 {
196  compute_Xsquared->generate_r1cs_witness();
197  compute_Ysquared->generate_r1cs_witness();
198  Xsquared_plus_a->evaluate();
199  curve_equation->generate_r1cs_witness();
200 }
201 
202 template<typename wppT>
203 G2_add_gadget<wppT>::G2_add_gadget(
204  protoboard<libff::Fr<wppT>> &pb,
205  const G2_variable<wppT> &A,
206  const G2_variable<wppT> &B,
207  const G2_variable<wppT> &result,
208  const std::string &annotation_prefix)
209  : gadget<libff::Fr<wppT>>(pb, annotation_prefix)
210  , A(A)
211  , B(B)
212  , result(result)
213  , lambda(pb, FMT(annotation_prefix, " lambda"))
214  // lambda = (By - Ay) / (Bx - Ax)
215  // <=> lambda * (Bx - Ax) = By - Ay
216  , lambda_constraint(
217  pb,
218  lambda,
219  *B.X - *A.X,
220  *B.Y - *A.Y,
221  FMT(annotation_prefix, " lambda_constraint"))
222  // Rx = lambda^2 - Ax - Bx
223  // <=> lambda^2 = Rx + Ax + Bx
224  , Rx_constraint(
225  pb,
226  lambda,
227  lambda,
228  *result.X + *A.X + *B.X,
229  FMT(annotation_prefix, " Rx_constraint"))
230  // Ry = lambda * (Ax - Rx) - Ay
231  // <=> lambda * (Ax - Rx) = Ry + Ay
232  , Ry_constraint(
233  pb,
234  lambda,
235  (*A.X - *result.X),
236  *result.Y + *A.Y,
237  FMT(annotation_prefix, " Ry_constraint"))
238 {
239 }
240 
241 template<typename wppT> void G2_add_gadget<wppT>::generate_r1cs_constraints()
242 {
243  lambda_constraint.generate_r1cs_constraints();
244  Rx_constraint.generate_r1cs_constraints();
245  Ry_constraint.generate_r1cs_constraints();
246 }
247 
248 template<typename wppT> void G2_add_gadget<wppT>::generate_r1cs_witness()
249 {
250  using nppT = other_curve<wppT>;
251  const libff::Fqe<nppT> Ax = A.X->get_element();
252  const libff::Fqe<nppT> Ay = A.Y->get_element();
253  const libff::Fqe<nppT> Bx = B.X->get_element();
254  const libff::Fqe<nppT> By = B.Y->get_element();
255 
256  // Guard against the inverse operation failing.
257  if (Ax == Bx) {
258  throw std::runtime_error(
259  "A.X == B.X is not supported by G2_add_gadget");
260  }
261 
262  // lambda = (By - Ay) / (Bx - Ax)
263  const libff::Fqe<nppT> lambda_value = (By - Ay) * (Bx - Ax).inverse();
264  lambda.generate_r1cs_witness(lambda_value);
265  lambda_constraint.B.evaluate();
266  lambda_constraint.result.evaluate();
267  lambda_constraint.generate_r1cs_witness();
268 
269  // Rx = lambda^2 - Ax - Bx
270  // Ry = lambda * (Ax - Rx) - Ay
271  const libff::Fqe<nppT> Rx = lambda_value.squared() - Ax - Bx;
272  const libff::Fqe<nppT> Ry = lambda_value * (Ax - Rx) - Ay;
273  result.generate_r1cs_witness(
274  libff::G2<nppT>(Rx, Ry, libff::Fqe<nppT>::one()));
275 
276  // lambda^2 = Rx + Ax + Bx
277  Rx_constraint.result.evaluate();
278  Rx_constraint.generate_r1cs_witness();
279 
280  // lambda * (Ax - Rx) = Ry + Ay
281  Ry_constraint.B.evaluate();
282  Ry_constraint.result.evaluate();
283  Ry_constraint.generate_r1cs_witness();
284 }
285 
286 template<typename wppT>
287 G2_dbl_gadget<wppT>::G2_dbl_gadget(
288  protoboard<libff::Fr<wppT>> &pb,
289  const G2_variable<wppT> &A,
290  const G2_variable<wppT> &result,
291  const std::string &annotation_prefix)
292  : gadget<libff::Fr<wppT>>(pb, annotation_prefix)
293  , A(A)
294  , result(result)
295  , lambda(pb, FMT(annotation_prefix, " lambda"))
296  // Ax_squared = Ax * Ax
297  , Ax_squared_constraint(
298  pb,
299  *A.X,
300  *A.X,
301  Fqe_variable<wppT>(pb, FMT(annotation_prefix, " Ax^2")),
302  FMT(annotation_prefix, " _Ax_squared_constraint"))
303  // lambda = (3 * Ax^2 + a) / 2 * Ay
304  // <=> lambda * (Ay + Ay) = 3 * Ax_squared + a
305  , lambda_constraint(
306  pb,
307  lambda,
308  *A.Y + *A.Y,
309  Ax_squared_constraint.result * libff::Fr<wppT>(3) +
310  libff::G2<nppT>::coeff_a,
311  FMT(annotation_prefix, " lambda_constraint"))
312  // Bx = lambda^2 - 2 * Ax
313  // <=> lambda * lambda = Bx + Ax + Ax
314  , Bx_constraint(
315  pb,
316  lambda,
317  lambda,
318  *result.X + *A.X + *A.X,
319  FMT(annotation_prefix, " Bx_constraint"))
320  // By = lambda * (Ax - Bx) - Ay
321  // <=> lambda * (Ax - Bx) = By + Ay
322  , By_constraint(
323  pb,
324  lambda,
325  (*A.X - *result.X),
326  *result.Y + *A.Y,
327  FMT(annotation_prefix, " By_constraint"))
328 {
329 }
330 
331 template<typename wppT> void G2_dbl_gadget<wppT>::generate_r1cs_constraints()
332 {
333  Ax_squared_constraint.generate_r1cs_constraints();
334  lambda_constraint.generate_r1cs_constraints();
335  Bx_constraint.generate_r1cs_constraints();
336  By_constraint.generate_r1cs_constraints();
337 }
338 
339 template<typename wppT> void G2_dbl_gadget<wppT>::generate_r1cs_witness()
340 {
341  const libff::Fqe<nppT> Ax = A.X->get_element();
342  const libff::Fqe<nppT> Ay = A.Y->get_element();
343 
344  // Ax_squared = Ax * Ax
345  Ax_squared_constraint.generate_r1cs_witness();
346  Ax_squared_constraint.result.evaluate();
347  const libff::Fqe<nppT> Ax_squared =
348  Ax_squared_constraint.result.get_element();
349 
350  // lambda = (3 * Ax^2 + a) / 2 * Ay
351  // <=> lambda * (Ay + Ay) = 3 * Ax_squared + a
352  const libff::Fqe<nppT> Ax_squared_plus_a =
353  Ax_squared + Ax_squared + Ax_squared + libff::G2<nppT>::coeff_a;
354  const libff::Fqe<nppT> lambda_value =
355  Ax_squared_plus_a * (Ay + Ay).inverse();
356  lambda.generate_r1cs_witness(lambda_value);
357  lambda_constraint.B.evaluate();
358  lambda_constraint.generate_r1cs_witness();
359 
360  // Bx = lambda^2 - 2 * Ax
361  // By = lambda * (Ax - Bx) - Ay
362  const libff::Fqe<nppT> Bx = lambda_value.squared() - Ax - Ax;
363  const libff::Fqe<nppT> By = lambda_value * (Ax - Bx) - Ay;
364  result.generate_r1cs_witness(
365  libff::G2<nppT>(Bx, By, libff::Fqe<nppT>::one()));
366 
367  // lambda * lambda = Bx + Ax + Ax
368  Bx_constraint.generate_r1cs_witness();
369 
370  // lambda * (Ax - Bx) = By + Ay
371  By_constraint.B.evaluate();
372  By_constraint.generate_r1cs_witness();
373 }
374 
375 template<typename wppT>
376 G2_equality_gadget<wppT>::G2_equality_gadget(
377  protoboard<libff::Fr<wppT>> &pb,
378  const G2_variable<wppT> &A,
379  const G2_variable<wppT> &B,
380  const std::string &annotation_prefix)
381  : gadget<libff::Fr<wppT>>(pb, annotation_prefix), _A(A), _B(B)
382 {
383 }
384 
385 template<typename wppT>
386 void G2_equality_gadget<wppT>::generate_r1cs_constraints()
387 {
388  // A.X == B.X
389  generate_fpe_equality_constraints(*_A.X, *_B.X);
390  // A.Y == B.Y
391  generate_fpe_equality_constraints(*_A.X, *_B.X);
392 }
393 
394 template<typename wppT> void G2_equality_gadget<wppT>::generate_r1cs_witness()
395 {
396  // Nothing to do
397 }
398 
399 template<typename wppT>
400 void G2_equality_gadget<wppT>::generate_fpe_equality_constraints(
401  const Fp2_variable<libff::Fqe<other_curve<wppT>>> &a,
402  const Fp2_variable<libff::Fqe<other_curve<wppT>>> &b)
403 {
404  this->pb.add_r1cs_constraint(
405  r1cs_constraint<libff::Fr<wppT>>(a.c0, 1, b.c0),
406  FMT(this->annotation_prefix, " c0"));
407  this->pb.add_r1cs_constraint(
408  r1cs_constraint<libff::Fr<wppT>>(a.c1, 1, b.c1),
409  FMT(this->annotation_prefix, " c1"));
410 }
411 
412 } // namespace libsnark
413 
414 #endif // WEIERSTRASS_G2_GADGET_TCC_