2 *****************************************************************************
4 Implementation of interfaces for G2 gadgets.
6 See weierstrass_g2_gadgets.hpp .
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 *****************************************************************************/
14 #ifndef WEIERSTRASS_G2_GADGET_TCC_
15 #define WEIERSTRASS_G2_GADGET_TCC_
17 #include <libff/algebra/scalar_multiplication/wnaf.hpp>
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)
27 X.reset(new Fqe_variable<ppT>(pb, FMT(annotation_prefix, " X")));
28 Y.reset(new Fqe_variable<ppT>(pb, FMT(annotation_prefix, " Y")));
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());
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)
41 libff::G2<other_curve<ppT>> Q_copy = Q;
42 Q_copy.to_affine_coordinates();
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")));
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());
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))
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());
65 template<typename ppT> G2_variable<ppT> G2_variable<ppT>::operator-() const
67 return G2_variable<ppT>(
68 this->pb, *X, -(*Y), FMT(this->annotation_prefix, " negative"));
71 template<typename ppT>
72 void G2_variable<ppT>::generate_r1cs_witness(
73 const libff::G2<other_curve<ppT>> &Q)
75 libff::G2<other_curve<ppT>> Qcopy = Q;
76 Qcopy.to_affine_coordinates();
78 X->generate_r1cs_witness(Qcopy.X);
79 Y->generate_r1cs_witness(Qcopy.Y);
82 template<typename ppT>
83 libff::G2<other_curve<ppT>> G2_variable<ppT>::get_element() const
85 using nppT = other_curve<ppT>;
86 return libff::G2<nppT>(
89 libff::G2<nppT>::twist_field::one());
92 template<typename ppT> size_t G2_variable<ppT>::size_in_bits()
94 return 2 * Fqe_variable<ppT>::size_in_bits();
97 template<typename ppT> size_t G2_variable<ppT>::num_variables()
99 return 2 * Fqe_variable<ppT>::num_variables();
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)
112 , zero_case(zero_case)
117 *one_case.X - *zero_case.X,
119 *result.X - *zero_case.X,
120 FMT(annotation_prefix, " mul_select_X"))
123 *one_case.Y - *zero_case.Y,
125 *result.Y - *zero_case.Y,
126 FMT(annotation_prefix, " mul_select_Y"))
130 template<typename ppT>
131 void G2_variable_selector_gadget<ppT>::generate_r1cs_constraints()
133 mul_select_X.generate_r1cs_constraints();
134 mul_select_Y.generate_r1cs_constraints();
137 template<typename ppT>
138 void G2_variable_selector_gadget<ppT>::generate_r1cs_witness()
140 protoboard<Field> &pb = this->pb;
141 selector.evaluate(pb);
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();
150 if (pb.lc_val(selector) == Field::one()) {
151 result.generate_r1cs_witness(one_case.get_element());
153 result.generate_r1cs_witness(zero_case.get_element());
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)
165 new Fqe_variable<ppT>(pb, FMT(annotation_prefix, " Xsquared")));
167 new Fqe_variable<ppT>(pb, FMT(annotation_prefix, " Ysquared")));
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")));
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)));
179 curve_equation.reset(new Fqe_mul_gadget<ppT>(
184 FMT(annotation_prefix, " curve_equation")));
187 template<typename ppT> void G2_checker_gadget<ppT>::generate_r1cs_constraints()
189 compute_Xsquared->generate_r1cs_constraints();
190 compute_Ysquared->generate_r1cs_constraints();
191 curve_equation->generate_r1cs_constraints();
194 template<typename ppT> void G2_checker_gadget<ppT>::generate_r1cs_witness()
196 compute_Xsquared->generate_r1cs_witness();
197 compute_Ysquared->generate_r1cs_witness();
198 Xsquared_plus_a->evaluate();
199 curve_equation->generate_r1cs_witness();
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)
213 , lambda(pb, FMT(annotation_prefix, " lambda"))
214 // lambda = (By - Ay) / (Bx - Ax)
215 // <=> lambda * (Bx - Ax) = By - Ay
221 FMT(annotation_prefix, " lambda_constraint"))
222 // Rx = lambda^2 - Ax - Bx
223 // <=> lambda^2 = Rx + Ax + Bx
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
237 FMT(annotation_prefix, " Ry_constraint"))
241 template<typename wppT> void G2_add_gadget<wppT>::generate_r1cs_constraints()
243 lambda_constraint.generate_r1cs_constraints();
244 Rx_constraint.generate_r1cs_constraints();
245 Ry_constraint.generate_r1cs_constraints();
248 template<typename wppT> void G2_add_gadget<wppT>::generate_r1cs_witness()
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();
256 // Guard against the inverse operation failing.
258 throw std::runtime_error(
259 "A.X == B.X is not supported by G2_add_gadget");
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();
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()));
276 // lambda^2 = Rx + Ax + Bx
277 Rx_constraint.result.evaluate();
278 Rx_constraint.generate_r1cs_witness();
280 // lambda * (Ax - Rx) = Ry + Ay
281 Ry_constraint.B.evaluate();
282 Ry_constraint.result.evaluate();
283 Ry_constraint.generate_r1cs_witness();
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)
295 , lambda(pb, FMT(annotation_prefix, " lambda"))
296 // Ax_squared = Ax * Ax
297 , Ax_squared_constraint(
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
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
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
327 FMT(annotation_prefix, " By_constraint"))
331 template<typename wppT> void G2_dbl_gadget<wppT>::generate_r1cs_constraints()
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();
339 template<typename wppT> void G2_dbl_gadget<wppT>::generate_r1cs_witness()
341 const libff::Fqe<nppT> Ax = A.X->get_element();
342 const libff::Fqe<nppT> Ay = A.Y->get_element();
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();
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();
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()));
367 // lambda * lambda = Bx + Ax + Ax
368 Bx_constraint.generate_r1cs_witness();
370 // lambda * (Ax - Bx) = By + Ay
371 By_constraint.B.evaluate();
372 By_constraint.generate_r1cs_witness();
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)
385 template<typename wppT>
386 void G2_equality_gadget<wppT>::generate_r1cs_constraints()
389 generate_fpe_equality_constraints(*_A.X, *_B.X);
391 generate_fpe_equality_constraints(*_A.X, *_B.X);
394 template<typename wppT> void G2_equality_gadget<wppT>::generate_r1cs_witness()
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)
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"));
412 } // namespace libsnark
414 #endif // WEIERSTRASS_G2_GADGET_TCC_