2 *****************************************************************************
4 Implementation of interfaces for pairing precomputation gadgets.
6 See weierstrass_precomputation.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 LIBSNARK_GADGETLIB1_GADGETS_PAIRING_MNT_MNT_PRECOMPUTATION_TCC_
15 #define LIBSNARK_GADGETLIB1_GADGETS_PAIRING_MNT_MNT_PRECOMPUTATION_TCC_
17 #include "libsnark/gadgetlib1/gadgets/pairing/mnt/mnt_pairing_params.hpp"
19 #include <type_traits>
24 template<typename ppT> mnt_G1_precomputation<ppT>::mnt_G1_precomputation()
26 // will be filled in precompute_G1_gadget, so do nothing here
29 template<typename ppT>
30 mnt_G1_precomputation<ppT>::mnt_G1_precomputation(
31 protoboard<FieldT> &pb,
32 const libff::G1<other_curve<ppT>> &P_val,
33 const std::string &annotation_prefix)
35 libff::G1<other_curve<ppT>> P_val_copy = P_val;
36 P_val_copy.to_affine_coordinates();
37 P.reset(new G1_variable<ppT>(pb, P_val_copy, FMT(annotation_prefix, " P")));
38 PY_twist_squared.reset(new Fqe_variable<ppT>(
40 P_val_copy.Y * libff::G2<other_curve<ppT>>::twist.squared(),
41 " PY_twist_squared"));
44 template<typename ppT>
45 void mnt_precompute_G1_gadget<ppT>::generate_r1cs_constraints()
47 /* the same for neither ppT = mnt4 nor ppT = mnt6 */
50 template<typename ppT>
51 void mnt_precompute_G1_gadget<ppT>::generate_r1cs_witness()
53 // the same for both ppT = mnt4 and ppT = mnt6
54 precomp.PY_twist_squared->evaluate();
57 template<typename ppT> mnt_G2_precomputation<ppT>::mnt_G2_precomputation() {}
59 template<typename ppT>
60 mnt_G2_precomputation<ppT>::mnt_G2_precomputation(
61 protoboard<FieldT> &pb,
62 const libff::G2<other_curve<ppT>> &Q_val,
63 const std::string &annotation_prefix)
65 Q.reset(new G2_variable<ppT>(pb, Q_val, FMT(annotation_prefix, " Q")));
66 const libff::affine_ate_G2_precomp<other_curve<ppT>> native_precomp =
67 other_curve<ppT>::affine_ate_precompute_G2(Q_val);
69 // the last precomp remains for convenient programming
70 coeffs.resize(native_precomp.coeffs.size() + 1);
71 for (size_t i = 0; i < native_precomp.coeffs.size(); ++i) {
72 coeffs[i].reset(new mnt_precompute_G2_gadget_coeffs<ppT>());
73 coeffs[i]->RX.reset(new Fqe_variable<ppT>(
75 native_precomp.coeffs[i].old_RX,
76 FMT(annotation_prefix, " RX")));
77 coeffs[i]->RY.reset(new Fqe_variable<ppT>(
79 native_precomp.coeffs[i].old_RY,
80 FMT(annotation_prefix, " RY")));
81 coeffs[i]->gamma.reset(new Fqe_variable<ppT>(
83 native_precomp.coeffs[i].gamma,
84 FMT(annotation_prefix, " gamma")));
85 coeffs[i]->gamma_X.reset(new Fqe_variable<ppT>(
87 native_precomp.coeffs[i].gamma_X,
88 FMT(annotation_prefix, " gamma_X")));
92 template<typename ppT>
93 mnt_precompute_G2_gadget_coeffs<ppT>::mnt_precompute_G2_gadget_coeffs()
95 // we will be filled in precomputed case of precompute_G2_gadget, so do
99 template<typename ppT>
100 mnt_precompute_G2_gadget_coeffs<ppT>::mnt_precompute_G2_gadget_coeffs(
101 protoboard<FieldT> &pb, const std::string &annotation_prefix)
103 RX.reset(new Fqe_variable<ppT>(pb, FMT(annotation_prefix, " RX")));
104 RY.reset(new Fqe_variable<ppT>(pb, FMT(annotation_prefix, " RY")));
105 gamma.reset(new Fqe_variable<ppT>(pb, FMT(annotation_prefix, " gamma")));
107 new Fqe_variable<ppT>(pb, FMT(annotation_prefix, " gamma_X")));
110 template<typename ppT>
111 mnt_precompute_G2_gadget_coeffs<ppT>::mnt_precompute_G2_gadget_coeffs(
112 protoboard<FieldT> &pb,
113 const G2_variable<ppT> &Q,
114 const std::string &annotation_prefix)
116 RX.reset(new Fqe_variable<ppT>(*(Q.X)));
117 RY.reset(new Fqe_variable<ppT>(*(Q.Y)));
118 gamma.reset(new Fqe_variable<ppT>(pb, FMT(annotation_prefix, " gamma")));
120 new Fqe_variable<ppT>(pb, FMT(annotation_prefix, " gamma_X")));
124 QX and QY -- X and Y coordinates of Q
130 G2_precompute_doubling_step relates coeffs[i] and coeffs[i+1] as follows
133 gamma = (3 * RX^2 + twist_coeff_a) * (2*RY).inverse()
137 RX = prev_gamma^2 - (2*prev_RX)
138 RY = prev_gamma * (prev_RX - RX) - prev_RY
141 template<typename ppT>
142 mnt_precompute_G2_gadget_doubling_step<ppT>::
143 mnt_precompute_G2_gadget_doubling_step(
144 protoboard<FieldT> &pb,
145 const mnt_precompute_G2_gadget_coeffs<ppT> &cur,
146 const mnt_precompute_G2_gadget_coeffs<ppT> &next,
147 const std::string &annotation_prefix)
148 : gadget<FieldT>(pb, annotation_prefix), cur(cur), next(next)
151 new Fqe_variable<ppT>(pb, FMT(annotation_prefix, " RXsquared")));
152 compute_RXsquared.reset(new Fqe_sqr_gadget<ppT>(
156 FMT(annotation_prefix, " compute_RXsquared")));
157 three_RXsquared_plus_a.reset(new Fqe_variable<ppT>(
158 (*RXsquared) * FieldT(3) + libff::G2<other_curve<ppT>>::coeff_a));
159 two_RY.reset(new Fqe_variable<ppT>(*(cur.RY) * FieldT(2)));
161 compute_gamma.reset(new Fqe_mul_gadget<ppT>(
165 *three_RXsquared_plus_a,
166 FMT(annotation_prefix, " compute_gamma")));
167 compute_gamma_X.reset(new Fqe_mul_gadget<ppT>(
172 FMT(annotation_prefix, " compute_gamma_X")));
174 next_RX_plus_two_RX.reset(
175 new Fqe_variable<ppT>(*(next.RX) + *(cur.RX) * FieldT(2)));
176 compute_next_RX.reset(new Fqe_sqr_gadget<ppT>(
179 *next_RX_plus_two_RX,
180 FMT(annotation_prefix, " compute_next_RX")));
182 RX_minus_next_RX.reset(
183 new Fqe_variable<ppT>(*(cur.RX) + *(next.RX) * (-FieldT::one())));
184 RY_plus_next_RY.reset(new Fqe_variable<ppT>(*(cur.RY) + *(next.RY)));
185 compute_next_RY.reset(new Fqe_mul_gadget<ppT>(
190 FMT(annotation_prefix, " compute_next_RY")));
193 template<typename ppT>
194 void mnt_precompute_G2_gadget_doubling_step<ppT>::generate_r1cs_constraints()
196 compute_RXsquared->generate_r1cs_constraints();
197 compute_gamma->generate_r1cs_constraints();
198 compute_gamma_X->generate_r1cs_constraints();
199 compute_next_RX->generate_r1cs_constraints();
200 compute_next_RY->generate_r1cs_constraints();
203 template<typename ppT>
204 void mnt_precompute_G2_gadget_doubling_step<ppT>::generate_r1cs_witness()
206 compute_RXsquared->generate_r1cs_witness();
208 three_RXsquared_plus_a->evaluate();
210 const FqeT three_RXsquared_plus_a_val =
211 three_RXsquared_plus_a->get_element();
212 const FqeT two_RY_val = two_RY->get_element();
213 const FqeT gamma_val = three_RXsquared_plus_a_val * two_RY_val.inverse();
214 cur.gamma->generate_r1cs_witness(gamma_val);
216 compute_gamma->generate_r1cs_witness();
217 compute_gamma_X->generate_r1cs_witness();
219 const FqeT RX_val = cur.RX->get_element();
220 const FqeT RY_val = cur.RY->get_element();
221 const FqeT next_RX_val = gamma_val.squared() - RX_val - RX_val;
222 const FqeT next_RY_val = gamma_val * (RX_val - next_RX_val) - RY_val;
224 next.RX->generate_r1cs_witness(next_RX_val);
225 next.RY->generate_r1cs_witness(next_RY_val);
227 RX_minus_next_RX->evaluate();
228 RY_plus_next_RY->evaluate();
230 compute_next_RX->generate_r1cs_witness();
231 compute_next_RY->generate_r1cs_witness();
235 G2_precompute_addition_step relates coeffs[i] and coeffs[i+1] as follows
238 gamma = (RY - QY) * (RX - QX).inverse()
242 RX = prev_gamma^2 - (prev_RX + QX)
243 RY = prev_gamma * (prev_RX - RX) - prev_RY
245 (where prev_ in [i+1] refer to things from [i])
247 If invert_Q is set to true: use -QY in place of QY everywhere above.
249 template<typename ppT>
250 mnt_precompute_G2_gadget_addition_step<ppT>::
251 mnt_precompute_G2_gadget_addition_step(
252 protoboard<FieldT> &pb,
254 const mnt_precompute_G2_gadget_coeffs<ppT> &cur,
255 const mnt_precompute_G2_gadget_coeffs<ppT> &next,
256 const G2_variable<ppT> &Q,
257 const std::string &annotation_prefix)
258 : gadget<FieldT>(pb, annotation_prefix)
264 RY_minus_QY.reset(new Fqe_variable<ppT>(
265 *(cur.RY) + *(Q.Y) * (!invert_Q ? -FieldT::one() : FieldT::one())));
268 new Fqe_variable<ppT>(*(cur.RX) + *(Q.X) * (-FieldT::one())));
269 compute_gamma.reset(new Fqe_mul_gadget<ppT>(
274 FMT(annotation_prefix, " compute_gamma")));
275 compute_gamma_X.reset(new Fqe_mul_gadget<ppT>(
280 FMT(annotation_prefix, " compute_gamma_X")));
282 next_RX_plus_RX_plus_QX.reset(
283 new Fqe_variable<ppT>(*(next.RX) + *(cur.RX) + *(Q.X)));
284 compute_next_RX.reset(new Fqe_sqr_gadget<ppT>(
287 *next_RX_plus_RX_plus_QX,
288 FMT(annotation_prefix, " compute_next_RX")));
290 RX_minus_next_RX.reset(
291 new Fqe_variable<ppT>(*(cur.RX) + *(next.RX) * (-FieldT::one())));
292 RY_plus_next_RY.reset(new Fqe_variable<ppT>(*(cur.RY) + *(next.RY)));
293 compute_next_RY.reset(new Fqe_mul_gadget<ppT>(
298 FMT(annotation_prefix, " compute_next_RY")));
301 template<typename ppT>
302 void mnt_precompute_G2_gadget_addition_step<ppT>::generate_r1cs_constraints()
304 compute_gamma->generate_r1cs_constraints();
305 compute_gamma_X->generate_r1cs_constraints();
306 compute_next_RX->generate_r1cs_constraints();
307 compute_next_RY->generate_r1cs_constraints();
310 template<typename ppT>
311 void mnt_precompute_G2_gadget_addition_step<ppT>::generate_r1cs_witness()
313 RY_minus_QY->evaluate();
314 RX_minus_QX->evaluate();
316 const FqeT RY_minus_QY_val = RY_minus_QY->get_element();
317 const FqeT RX_minus_QX_val = RX_minus_QX->get_element();
318 const FqeT gamma_val = RY_minus_QY_val * RX_minus_QX_val.inverse();
319 cur.gamma->generate_r1cs_witness(gamma_val);
321 compute_gamma->generate_r1cs_witness();
322 compute_gamma_X->generate_r1cs_witness();
324 const FqeT RX_val = cur.RX->get_element();
325 const FqeT RY_val = cur.RY->get_element();
326 const FqeT QX_val = Q.X->get_element();
327 const FqeT next_RX_val = gamma_val.squared() - RX_val - QX_val;
328 const FqeT next_RY_val = gamma_val * (RX_val - next_RX_val) - RY_val;
330 next.RX->generate_r1cs_witness(next_RX_val);
331 next.RY->generate_r1cs_witness(next_RY_val);
333 next_RX_plus_RX_plus_QX->evaluate();
334 RX_minus_next_RX->evaluate();
335 RY_plus_next_RY->evaluate();
337 compute_next_RX->generate_r1cs_witness();
338 compute_next_RY->generate_r1cs_witness();
341 template<typename ppT>
342 mnt_precompute_G2_gadget<ppT>::mnt_precompute_G2_gadget(
343 protoboard<FieldT> &pb,
344 const G2_variable<ppT> &Q,
345 mnt_G2_precomputation<ppT> &precomp, // will allocate this inside
346 const std::string &annotation_prefix)
347 : gadget<FieldT>(pb, annotation_prefix), precomp(precomp)
349 precomp.Q.reset(new G2_variable<ppT>(Q));
351 const auto &loop_count = mnt_pairing_params<ppT>::pairing_loop_count;
352 // the last RX/RY are unused in Miller loop, but will need to get
354 size_t coeff_count = 1;
358 bool found_nonzero = false;
359 std::vector<long> NAF = find_wnaf(1, loop_count);
360 for (long i = NAF.size() - 1; i >= 0; --i) {
361 if (!found_nonzero) {
362 // this skips the MSB itself
363 found_nonzero |= (NAF[i] != 0);
376 precomp.coeffs.resize(coeff_count);
377 addition_steps.resize(add_count);
378 doubling_steps.resize(dbl_count);
380 precomp.coeffs[0].reset(new mnt_precompute_G2_gadget_coeffs<ppT>(
381 pb, Q, FMT(annotation_prefix, " coeffs_0")));
382 for (size_t i = 1; i < coeff_count; ++i) {
383 precomp.coeffs[i].reset(new mnt_precompute_G2_gadget_coeffs<ppT>(
384 pb, FMT(annotation_prefix, " coeffs_%zu", i)));
391 found_nonzero = false;
392 for (long i = NAF.size() - 1; i >= 0; --i) {
393 if (!found_nonzero) {
394 // this skips the MSB itself
395 found_nonzero |= (NAF[i] != 0);
399 doubling_steps[dbl_id].reset(
400 new mnt_precompute_G2_gadget_doubling_step<ppT>(
402 *(precomp.coeffs[coeff_id]),
403 *(precomp.coeffs[coeff_id + 1]),
404 FMT(annotation_prefix, " doubling_steps_%zu", dbl_id)));
409 addition_steps[add_id].reset(
410 new mnt_precompute_G2_gadget_addition_step<ppT>(
413 *(precomp.coeffs[coeff_id]),
414 *(precomp.coeffs[coeff_id + 1]),
416 FMT(annotation_prefix, " addition_steps_%zu", add_id)));
423 template<typename ppT>
424 void mnt_precompute_G2_gadget<ppT>::generate_r1cs_constraints()
426 for (size_t i = 0; i < dbl_count; ++i) {
427 doubling_steps[i]->generate_r1cs_constraints();
430 for (size_t i = 0; i < add_count; ++i) {
431 addition_steps[i]->generate_r1cs_constraints();
435 template<typename ppT>
436 void mnt_precompute_G2_gadget<ppT>::generate_r1cs_witness()
438 precomp.coeffs[0]->RX->generate_r1cs_witness(precomp.Q->X->get_element());
439 precomp.coeffs[0]->RY->generate_r1cs_witness(precomp.Q->Y->get_element());
441 const auto &loop_count = mnt_pairing_params<ppT>::pairing_loop_count;
446 bool found_nonzero = false;
447 std::vector<long> NAF = find_wnaf(1, loop_count);
448 for (long i = NAF.size() - 1; i >= 0; --i) {
449 if (!found_nonzero) {
450 // this skips the MSB itself
451 found_nonzero |= (NAF[i] != 0);
455 doubling_steps[dbl_id]->generate_r1cs_witness();
459 addition_steps[add_id]->generate_r1cs_witness();
465 } // namespace libsnark
467 #endif // LIBSNARK_GADGETLIB1_GADGETS_PAIRING_MNT_MNT_PRECOMPUTATION_TCC_