2 *****************************************************************************
4 Implementation of interfaces for final exponentiation gadgets.
6 See weierstrass_final_exponentiation.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_FINAL_EXPONENTIATION_TCC_
15 #define LIBSNARK_GADGETLIB1_GADGETS_PAIRING_MNT_MNT_FINAL_EXPONENTIATION_TCC_
17 #include "libsnark/gadgetlib1/gadgets/basic_gadgets.hpp"
18 #include "libsnark/gadgetlib1/gadgets/pairing/mnt/mnt_pairing_params.hpp"
23 template<typename ppT>
24 mnt4_final_exp_gadget<ppT>::mnt4_final_exp_gadget(
25 protoboard<FieldT> &pb,
26 const Fqk_variable<ppT> &el,
27 const pb_variable<FieldT> &result_is_one,
28 const std::string &annotation_prefix)
29 : gadget<FieldT>(pb, annotation_prefix)
31 , result_is_one(result_is_one)
33 one.reset(new Fqk_variable<ppT>(pb, FMT(annotation_prefix, " one")));
34 el_inv.reset(new Fqk_variable<ppT>(pb, FMT(annotation_prefix, " el_inv")));
35 el_q_3.reset(new Fqk_variable<ppT>(el.Frobenius_map(3)));
37 new Fqk_variable<ppT>(pb, FMT(annotation_prefix, " el_q_3_minus_1")));
38 alpha.reset(new Fqk_variable<ppT>(el_q_3_minus_1->Frobenius_map(1)));
39 beta.reset(new Fqk_variable<ppT>(pb, FMT(annotation_prefix, " beta")));
40 beta_q.reset(new Fqk_variable<ppT>(beta->Frobenius_map(1)));
42 el_inv_q_3.reset(new Fqk_variable<ppT>(el_inv->Frobenius_map(3)));
43 el_inv_q_3_minus_1.reset(new Fqk_variable<ppT>(
44 pb, FMT(annotation_prefix, " el_inv_q_3_minus_1")));
46 new Fqk_variable<ppT>(el_inv_q_3_minus_1->Frobenius_map(1)));
48 new Fqk_variable<ppT>(pb, FMT(annotation_prefix, " inv_beta")));
49 w1.reset(new Fqk_variable<ppT>(pb, FMT(annotation_prefix, " w1")));
50 w0.reset(new Fqk_variable<ppT>(pb, FMT(annotation_prefix, " w0")));
51 result.reset(new Fqk_variable<ppT>(pb, FMT(annotation_prefix, " result")));
53 compute_el_inv.reset(new Fqk_mul_gadget<ppT>(
54 pb, el, *el_inv, *one, FMT(annotation_prefix, " compute_el_inv")));
55 compute_el_q_3_minus_1.reset(new Fqk_mul_gadget<ppT>(
60 FMT(annotation_prefix, " compute_el_q_3_minus_1")));
61 compute_beta.reset(new Fqk_mul_gadget<ppT>(
66 FMT(annotation_prefix, " compute_beta")));
68 compute_el_inv_q_3_minus_1.reset(new Fqk_mul_gadget<ppT>(
73 FMT(annotation_prefix, " compute_el_inv__q_3_minus_1")));
74 compute_inv_beta.reset(new Fqk_mul_gadget<ppT>(
79 FMT(annotation_prefix, " compute_inv_beta")));
81 compute_w1.reset(new exponentiation_gadget<
84 Fp6_2over3_mul_gadget,
85 Fp6_2over3_cyclotomic_sqr_gadget,
89 libff::mnt6_final_exponent_last_chunk_w1,
91 FMT(annotation_prefix, " compute_w1")));
93 compute_w0.reset(new exponentiation_gadget<
96 Fp6_2over3_mul_gadget,
97 Fp6_2over3_cyclotomic_sqr_gadget,
100 (libff::mnt6_final_exponent_last_chunk_is_w0_neg ? *inv_beta : *beta),
101 libff::mnt6_final_exponent_last_chunk_abs_of_w0,
103 FMT(annotation_prefix, " compute_w0")));
105 compute_result.reset(new Fqk_mul_gadget<ppT>(
106 pb, *w1, *w0, *result, FMT(annotation_prefix, " compute_result")));
109 template<typename ppT>
110 void mnt4_final_exp_gadget<ppT>::generate_r1cs_constraints()
112 one->generate_r1cs_equals_const_constraints(
113 libff::Fqk<other_curve<ppT>>::one());
115 compute_el_inv->generate_r1cs_constraints();
116 compute_el_q_3_minus_1->generate_r1cs_constraints();
117 compute_beta->generate_r1cs_constraints();
119 compute_el_inv_q_3_minus_1->generate_r1cs_constraints();
120 compute_inv_beta->generate_r1cs_constraints();
122 compute_w0->generate_r1cs_constraints();
123 compute_w1->generate_r1cs_constraints();
124 compute_result->generate_r1cs_constraints();
126 generate_boolean_r1cs_constraint<FieldT>(
129 FMT(this->annotation_prefix, " result_is_one"));
130 this->pb.add_r1cs_constraint(
131 r1cs_constraint<FieldT>(result_is_one, 1 - result->c0.c0, 0),
133 this->pb.add_r1cs_constraint(
134 r1cs_constraint<FieldT>(result_is_one, result->c0.c1, 0),
136 this->pb.add_r1cs_constraint(
137 r1cs_constraint<FieldT>(result_is_one, result->c0.c2, 0),
139 this->pb.add_r1cs_constraint(
140 r1cs_constraint<FieldT>(result_is_one, result->c1.c0, 0),
142 this->pb.add_r1cs_constraint(
143 r1cs_constraint<FieldT>(result_is_one, result->c1.c1, 0),
145 this->pb.add_r1cs_constraint(
146 r1cs_constraint<FieldT>(result_is_one, result->c1.c2, 0),
150 template<typename ppT> void mnt4_final_exp_gadget<ppT>::generate_r1cs_witness()
152 one->generate_r1cs_witness(libff::Fqk<other_curve<ppT>>::one());
153 el_inv->generate_r1cs_witness(el.get_element().inverse());
155 compute_el_inv->generate_r1cs_witness();
157 compute_el_q_3_minus_1->generate_r1cs_witness();
159 compute_beta->generate_r1cs_witness();
162 el_inv_q_3->evaluate();
163 compute_el_inv_q_3_minus_1->generate_r1cs_witness();
164 inv_alpha->evaluate();
165 compute_inv_beta->generate_r1cs_witness();
167 compute_w0->generate_r1cs_witness();
168 compute_w1->generate_r1cs_witness();
169 compute_result->generate_r1cs_witness();
171 this->pb.val(result_is_one) =
172 (result->get_element() == one->get_element() ? FieldT::one()
176 template<typename ppT>
177 mnt6_final_exp_gadget<ppT>::mnt6_final_exp_gadget(
178 protoboard<FieldT> &pb,
179 const Fqk_variable<ppT> &el,
180 const pb_variable<FieldT> &result_is_one,
181 const std::string &annotation_prefix)
182 : gadget<FieldT>(pb, annotation_prefix)
184 , result_is_one(result_is_one)
186 one.reset(new Fqk_variable<ppT>(pb, FMT(annotation_prefix, " one")));
187 el_inv.reset(new Fqk_variable<ppT>(pb, FMT(annotation_prefix, " el_inv")));
188 el_q_2.reset(new Fqk_variable<ppT>(el.Frobenius_map(2)));
189 el_q_2_minus_1.reset(
190 new Fqk_variable<ppT>(pb, FMT(annotation_prefix, " el_q_2_minus_1")));
191 el_q_3_minus_q.reset(
192 new Fqk_variable<ppT>(el_q_2_minus_1->Frobenius_map(1)));
193 el_inv_q_2.reset(new Fqk_variable<ppT>(el_inv->Frobenius_map(2)));
194 el_inv_q_2_minus_1.reset(new Fqk_variable<ppT>(
195 pb, FMT(annotation_prefix, " el_inv_q_2_minus_1")));
196 w1.reset(new Fqk_variable<ppT>(pb, FMT(annotation_prefix, " w1")));
197 w0.reset(new Fqk_variable<ppT>(pb, FMT(annotation_prefix, " w0")));
198 result.reset(new Fqk_variable<ppT>(pb, FMT(annotation_prefix, " result")));
200 compute_el_inv.reset(new Fqk_mul_gadget<ppT>(
201 pb, el, *el_inv, *one, FMT(annotation_prefix, " compute_el_inv")));
202 compute_el_q_2_minus_1.reset(new Fqk_mul_gadget<ppT>(
207 FMT(annotation_prefix, " compute_el_q_2_minus_1")));
208 compute_el_inv_q_2_minus_1.reset(new Fqk_mul_gadget<ppT>(
213 FMT(annotation_prefix, " compute_el_inv_q_2_minus_1")));
215 compute_w1.reset(new exponentiation_gadget<
219 Fp4_cyclotomic_sqr_gadget,
220 libff::mnt4_q_limbs>(
223 libff::mnt4_final_exponent_last_chunk_w1,
225 FMT(annotation_prefix, " compute_w1")));
226 compute_w0.reset(new exponentiation_gadget<
230 Fp4_cyclotomic_sqr_gadget,
231 libff::mnt4_q_limbs>(
233 (libff::mnt4_final_exponent_last_chunk_is_w0_neg ? *el_inv_q_2_minus_1
235 libff::mnt4_final_exponent_last_chunk_abs_of_w0,
237 FMT(annotation_prefix, " compute_w0")));
238 compute_result.reset(new Fqk_mul_gadget<ppT>(
239 pb, *w1, *w0, *result, FMT(annotation_prefix, " compute_result")));
242 template<typename ppT>
243 void mnt6_final_exp_gadget<ppT>::generate_r1cs_constraints()
245 one->generate_r1cs_equals_const_constraints(
246 libff::Fqk<other_curve<ppT>>::one());
248 compute_el_inv->generate_r1cs_constraints();
249 compute_el_q_2_minus_1->generate_r1cs_constraints();
250 compute_el_inv_q_2_minus_1->generate_r1cs_constraints();
251 compute_w1->generate_r1cs_constraints();
252 compute_w0->generate_r1cs_constraints();
253 compute_result->generate_r1cs_constraints();
255 generate_boolean_r1cs_constraint<FieldT>(
258 FMT(this->annotation_prefix, " result_is_one"));
259 this->pb.add_r1cs_constraint(
260 r1cs_constraint<FieldT>(result_is_one, 1 - result->c0.c0, 0),
262 this->pb.add_r1cs_constraint(
263 r1cs_constraint<FieldT>(result_is_one, result->c0.c1, 0),
265 this->pb.add_r1cs_constraint(
266 r1cs_constraint<FieldT>(result_is_one, result->c1.c0, 0),
268 this->pb.add_r1cs_constraint(
269 r1cs_constraint<FieldT>(result_is_one, result->c1.c1, 0),
273 template<typename ppT> void mnt6_final_exp_gadget<ppT>::generate_r1cs_witness()
275 one->generate_r1cs_witness(libff::Fqk<other_curve<ppT>>::one());
276 el_inv->generate_r1cs_witness(el.get_element().inverse());
278 compute_el_inv->generate_r1cs_witness();
280 compute_el_q_2_minus_1->generate_r1cs_witness();
281 el_q_3_minus_q->evaluate();
282 el_inv_q_2->evaluate();
283 compute_el_inv_q_2_minus_1->generate_r1cs_witness();
284 compute_w1->generate_r1cs_witness();
285 compute_w0->generate_r1cs_witness();
286 compute_result->generate_r1cs_witness();
288 this->pb.val(result_is_one) =
289 (result->get_element() == one->get_element() ? FieldT::one()
293 } // namespace libsnark
295 #endif // LIBSNARK_GADGETLIB1_GADGETS_PAIRING_MNT_MNT_FINAL_EXPONENTIATION_TCC_