2 *****************************************************************************
3 * @author This file is part of libsnark, developed by Clearmatics Ltd
4 * (originally developed by SCIPR Lab) and contributors
6 * @copyright MIT license (see LICENSE file)
7 *****************************************************************************/
9 #ifndef LIBSNARK_GADGETLIB1_GADGETS_FIELDS_FP12_2OVER3OVER2_GADGETS_TCC_
10 #define LIBSNARK_GADGETLIB1_GADGETS_FIELDS_FP12_2OVER3OVER2_GADGETS_TCC_
12 #include "libsnark/gadgetlib1/gadgets/fields/fp12_2over3over2_gadgets.hpp"
17 // Fp12_2over3over2_variable methods
19 template<typename Fp12T>
20 Fp12_2over3over2_variable<Fp12T>::Fp12_2over3over2_variable(
21 protoboard<FieldT> &pb, const std::string &annotation_prefix)
22 : gadget<FieldT>(pb, annotation_prefix)
23 , _c0(pb, FMT(annotation_prefix, " c0"))
24 , _c1(pb, FMT(annotation_prefix, " c1"))
28 template<typename Fp12T>
29 Fp12_2over3over2_variable<Fp12T>::Fp12_2over3over2_variable(
30 protoboard<FieldT> &pb,
32 const std::string &annotation_prefix)
33 : gadget<FieldT>(pb, annotation_prefix)
34 , _c0(pb, el.coeffs[0], FMT(annotation_prefix, " c0"))
35 , _c1(pb, el.coeffs[1], FMT(annotation_prefix, " c1"))
39 template<typename Fp12T>
40 Fp12_2over3over2_variable<Fp12T>::Fp12_2over3over2_variable(
41 protoboard<FieldT> &pb,
42 const Fp6_3over2_variable<Fp6T> &c0,
43 const Fp6_3over2_variable<Fp6T> &c1,
44 const std::string &annotation_prefix)
45 : gadget<FieldT>(pb, annotation_prefix), _c0(c0), _c1(c1)
49 template<typename Fp12T>
50 Fp12_2over3over2_variable<Fp12T> Fp12_2over3over2_variable<Fp12T>::operator*(
51 const Fp2T &fp2_const) const
53 return Fp12_2over3over2_variable(
57 FMT(this->annotation_prefix, " fp12_var*fp2_const"));
60 template<typename Fp12T>
61 Fp12_2over3over2_variable<Fp12T> Fp12_2over3over2_variable<Fp12T>::operator*(
62 const Fp12T &fp12_const) const
64 using Fp6_variable = Fp6_3over2_variable<Fp6T>;
65 const Fp6_variable a0_b0 = _c0 * fp12_const.coeffs[0];
66 const Fp6_variable a1_b1 = _c1 * fp12_const.coeffs[1];
67 const Fp6_variable a0a1_b0b1 =
68 (_c0 + _c1) * (fp12_const.coeffs[0] + fp12_const.coeffs[1]);
70 return Fp12_2over3over2_variable(
72 a0_b0 + (a1_b1 * Fp6T(Fp2T::zero(), Fp2T::one(), Fp2T::zero())),
73 a0a1_b0b1 - a0_b0 - a1_b1,
74 FMT(this->annotation_prefix, " fp12_var*fp12_const"));
77 template<typename Fp12T>
78 Fp12_2over3over2_variable<Fp12T> Fp12_2over3over2_variable<
79 Fp12T>::frobenius_map(size_t power) const
81 return Fp12_2over3over2_variable(
83 _c0.frobenius_map(power),
84 _c1.frobenius_map(power) * Fp12T::Frobenius_coeffs_c1[power % 12],
85 FMT(this->annotation_prefix, " fp12_frobenius_map"));
88 template<typename Fp12T>
89 Fp12_2over3over2_variable<Fp12T> Fp12_2over3over2_variable<
90 Fp12T>::unitary_inverse() const
92 return Fp12_2over3over2_variable(
93 this->pb, _c0, -_c1, FMT(this->annotation_prefix, " fp12_unitary_inv"));
96 template<typename Fp12T> void Fp12_2over3over2_variable<Fp12T>::evaluate() const
102 template<typename Fp12T>
103 void Fp12_2over3over2_variable<Fp12T>::generate_r1cs_witness(const Fp12T &el)
105 _c0.generate_r1cs_witness(el.coeffs[0]);
106 _c1.generate_r1cs_witness(el.coeffs[1]);
109 template<typename Fp12T>
110 Fp12T Fp12_2over3over2_variable<Fp12T>::get_element() const
112 return Fp12T(_c0.get_element(), _c1.get_element());
115 // Multiplication of Fp6 elements by Fp12::non-residue and
116 // Fp12::non-residue^{-1}.
118 template<typename Fp12T>
119 Fp6_3over2_variable<typename Fp12T::my_Fp6> fp6_mul_by_non_residue(
120 protoboard<typename Fp12T::my_Fp> &pb,
121 const Fp6_3over2_variable<typename Fp12T::my_Fp6> &c,
122 const std::string &annotation_prefix)
124 return Fp6_3over2_variable<typename Fp12T::my_Fp6>(
125 pb, c._c2 * Fp12T::non_residue, c._c0, c._c1, annotation_prefix);
128 template<typename Fp12T>
129 Fp6_3over2_variable<typename Fp12T::my_Fp6> fp6_mul_by_non_residue_inverse(
130 protoboard<typename Fp12T::my_Fp> &pb,
131 const Fp6_3over2_variable<typename Fp12T::my_Fp6> &c,
132 const std::string &annotation_prefix)
134 return Fp6_3over2_variable<typename Fp12T::my_Fp6>(
138 c._c0 * Fp12T::non_residue.inverse(),
142 // Fp12_2over3over2_square_gadget methods
144 template<typename Fp12T>
145 Fp12_2over3over2_square_gadget<Fp12T>::Fp12_2over3over2_square_gadget(
146 protoboard<FieldT> &pb,
147 const Fp12_2over3over2_variable<Fp12T> &A,
148 const Fp12_2over3over2_variable<Fp12T> &result,
149 const std::string &annotation_prefix)
150 : gadget<FieldT>(pb, annotation_prefix)
157 _result._c1 * (FieldT("2").inverse()),
158 FMT(annotation_prefix, " _compute_alpha"))
162 _A._c0 + fp6_mul_by_non_residue<Fp12T>(
163 pb, _A._c1, FMT(annotation_prefix, " a1_times_v")),
165 fp6_mul_by_non_residue<Fp12T>(
167 _compute_alpha._result,
168 FMT(annotation_prefix, " alpha_times_v")) +
169 _compute_alpha._result,
170 FMT(annotation_prefix, " _compute_beta"))
174 template<typename Fp12T>
175 const Fp12_2over3over2_variable<Fp12T>
176 &Fp12_2over3over2_square_gadget<Fp12T>::result() const
181 template<typename Fp12T>
182 void Fp12_2over3over2_square_gadget<Fp12T>::generate_r1cs_constraints()
184 _compute_alpha.generate_r1cs_constraints();
185 _compute_beta.generate_r1cs_constraints();
188 template<typename Fp12T>
189 void Fp12_2over3over2_square_gadget<Fp12T>::generate_r1cs_witness()
191 const Fp6T a0 = _A._c0.get_element();
192 const Fp6T a1 = _A._c1.get_element();
193 const Fp6T alpha = a0 * a1;
194 _result._c1.generate_r1cs_witness(alpha + alpha);
195 _compute_alpha.generate_r1cs_witness();
197 const Fp6T beta = (a0 + a1) * (a0 + Fp12T::mul_by_non_residue(a1));
198 _result._c0.generate_r1cs_witness(
199 beta - Fp12T::mul_by_non_residue(alpha) - alpha);
200 _compute_beta._A.evaluate();
201 _compute_beta._B.evaluate();
202 _compute_beta.generate_r1cs_witness();
205 // Fp12_2over3over2_mul_by_024_gadget methods
207 template<typename Fp12T>
208 Fp12_2over3over2_mul_by_024_gadget<Fp12T>::Fp12_2over3over2_mul_by_024_gadget(
209 protoboard<FieldT> &pb,
210 const Fp12_2over3over2_variable<Fp12T> &Z,
211 const Fp2_variable<Fp2T> &X_0,
212 const Fp2_variable<Fp2T> &X_2,
213 const Fp2_variable<Fp2T> &X_4,
214 const Fp12_2over3over2_variable<Fp12T> &result,
215 const std::string &annotation_prefix)
216 : gadget<FieldT>(pb, annotation_prefix)
221 // out_z0 = z0*x0 + non_residue * (z1*x2 + z4*x4)
222 // => z0 * x0 = out_z0 - non_residue * (z1*x2 + z4*x4)
227 Fp2_variable<Fp2T>(pb, FMT(annotation_prefix, " z1_x2")),
228 FMT(annotation_prefix, "_compute_z1_x2"))
233 Fp2_variable<Fp2T>(pb, FMT(annotation_prefix, " z4_x4")),
234 FMT(annotation_prefix, " _compute_z4_x4"))
239 result._c0._c0 + ((_compute_z1_x2.result + _compute_z4_x4.result) *
241 FMT(annotation_prefix, " _compute_z0_x0"))
242 // out_z1 = z1*x0 + non_residue * (z2*x2 + z5*x4)
243 // => z1 * z0 = out_z1 - non_residue * (z2*x2 + z5*x4)
248 Fp2_variable<Fp2T>(pb, FMT(annotation_prefix, " z2_x2")),
249 FMT(annotation_prefix, " _compute_z2_x2"))
254 Fp2_variable<Fp2T>(pb, FMT(annotation_prefix, " z5_x4")),
255 FMT(annotation_prefix, " _compute_z5_x4"))
260 result._c0._c1 + ((_compute_z2_x2.result + _compute_z5_x4.result) *
262 FMT(annotation_prefix, " _compute_z1_x0"))
263 // z0*x2 + z2*x0 = (z0 + z2)*(x0 + x2) - z0*x0 - z2*x2
264 // out_z2 = z0*x2 + z2*x0 + z3*x4
265 // = (z0 + z2)*(x0 + x2) - z0*x0 - z2*x2 + z3*x4
266 // => (z0 + z2)*(x0 + x2) = out_z2 + z0*x0 + z2*x2 - z3*x4
271 Fp2_variable<Fp2T>(pb, FMT(annotation_prefix, " z3_x4")),
272 FMT(annotation_prefix, " _compute_z3_x4"))
275 Z._c0._c0 + Z._c0._c2,
277 result._c0._c2 + _compute_z0_x0.result + _compute_z2_x2.result +
278 (_compute_z3_x4.result * -FieldT::one()),
279 FMT(annotation_prefix, " _compute_z02_x02"))
280 // z2*x4 + z4*x2 = (z2 + z4)*(x2 + x4) - z2*x2 - z4*x4
281 // out_z3 = z3*x0 + non_residue * (z2*x4 + z4*x2)
282 // = z3*x0 + non_residue * ((z2 + z4)*(x2 + x4) - z2*x2 - z4*x4)
283 // => (z2 + z4)*(x2 + x4) = (out_z3 - z3*x0) / non_residue + z2*x2 + z4_x4
288 Fp2_variable<Fp2T>(pb, FMT(annotation_prefix, " z3_x0")),
289 FMT(annotation_prefix, " _compute_z3_x0"))
292 Z._c0._c2 + Z._c1._c1,
294 _compute_z2_x2.result + _compute_z4_x4.result +
295 (result._c1._c0 + _compute_z3_x0.result * -FieldT::one()) *
296 Fp6T::non_residue.inverse(),
297 FMT(annotation_prefix, " _compute_z24_x24"))
298 // z0*x4 + z4*x0 = (z0 + z4)*(x0 + x4) - z0*x0 - z4*x4
299 // out_z4 = z0*x4 + z4*x0 + non_residue * z5*x2
300 // = (z0 + z4)*(x0 + x4) - z0*x0 - z4*x4 + non_residue * z5*x2
301 // => (z0 + z4)*(x0 + x4) = out_z4 + z0*x0 + z4*x4 - non_residue * z5*x2
306 Fp2_variable<Fp2T>(pb, FMT(annotation_prefix, " z5_x2")),
307 FMT(annotation_prefix, " _compute_z5_x2"))
310 Z._c0._c0 + Z._c1._c1,
312 result._c1._c1 + _compute_z0_x0.result + _compute_z4_x4.result +
313 _compute_z5_x2.result * -Fp6T::non_residue,
314 FMT(annotation_prefix, " _compute_z04_x04"))
315 // S = z1_x0 + z1_x2 + z3_x0 + z3*x4 + z5_x2 + z5*x4
316 // out_z5 = z1*x4 + z3*x2 + z5*x0
317 // = (z1 + z3 + z5)*(x0 + x2 + x4) - S
318 // => (z1 + z3 + z5)*(x0 + x2 + x4) = out_z5 + S
319 , _S(_compute_z1_x2.result + _compute_z1_x0.result + _compute_z5_x4.result +
320 _compute_z3_x4.result + _compute_z3_x0.result + _compute_z5_x2.result)
321 , _compute_out_z5_plus_S(
323 Z._c0._c1 + Z._c1._c0 + Z._c1._c2,
326 FMT(annotation_prefix, " _compute_out_z5_plus_S"))
331 template<typename Fp12T>
332 const Fp12_2over3over2_variable<Fp12T>
333 &Fp12_2over3over2_mul_by_024_gadget<Fp12T>::result() const
338 template<typename Fp12T>
339 void Fp12_2over3over2_mul_by_024_gadget<Fp12T>::generate_r1cs_constraints()
341 _compute_z1_x2.generate_r1cs_constraints();
342 _compute_z4_x4.generate_r1cs_constraints();
343 _compute_z0_x0.generate_r1cs_constraints();
344 _compute_z2_x2.generate_r1cs_constraints();
345 _compute_z5_x4.generate_r1cs_constraints();
346 _compute_z1_x0.generate_r1cs_constraints();
347 _compute_z3_x4.generate_r1cs_constraints();
348 _compute_z02_x02.generate_r1cs_constraints();
349 _compute_z3_x0.generate_r1cs_constraints();
350 _compute_z24_x24.generate_r1cs_constraints();
351 _compute_z5_x2.generate_r1cs_constraints();
352 _compute_z04_x04.generate_r1cs_constraints();
353 _compute_out_z5_plus_S.generate_r1cs_constraints();
356 template<typename Fp12T>
357 void Fp12_2over3over2_mul_by_024_gadget<Fp12T>::generate_r1cs_witness()
359 const Fp2T z0 = _Z._c0._c0.get_element();
360 const Fp2T z1 = _Z._c0._c1.get_element();
361 const Fp2T z2 = _Z._c0._c2.get_element();
362 const Fp2T z3 = _Z._c1._c0.get_element();
363 const Fp2T z4 = _Z._c1._c1.get_element();
364 const Fp2T z5 = _Z._c1._c2.get_element();
366 const Fp2T x0 = _X_0.get_element();
367 const Fp2T x2 = _X_2.get_element();
368 const Fp2T x4 = _X_4.get_element();
370 // out_z0 = z0*x0 + non_residue * (z1*x2 + z4*x4)
371 // => z0 * x0 = out_z0 - non_residue * (z1*x2 + z4*x4)
372 _compute_z1_x2.generate_r1cs_witness();
373 _compute_z4_x4.generate_r1cs_witness();
374 const Fp2T z0_x0 = z0 * x0;
375 const Fp2T z4_x4 = _compute_z4_x4.result.get_element();
376 _result._c0._c0.generate_r1cs_witness(
378 Fp6T::non_residue * (_compute_z1_x2.result.get_element() + z4_x4));
379 _compute_z0_x0.generate_r1cs_witness();
381 // out_z1 = z1*x0 + non_residue * (z2*x2 + z5*x4)
382 // => z1 * z0 = out_z1 - non_residue * (z2*x2 + z5*x4)
383 _compute_z2_x2.generate_r1cs_witness();
384 _compute_z5_x4.generate_r1cs_witness();
385 const Fp2T z2_x2 = _compute_z2_x2.result.get_element();
386 const Fp2T z1_x0 = z1 * x0;
387 _result._c0._c1.generate_r1cs_witness(
389 Fp6T::non_residue * (z2_x2 + _compute_z5_x4.result.get_element()));
390 _compute_z1_x0.generate_r1cs_witness();
392 // z0*x2 + z2*x0 = (z0 + z2)*(x0 + x2) - z0*x0 - z2*x2
393 // out_z2 = z0*x2 + z2*x0 + z3*x4
394 // = (z0 + z2)*(x0 + x2) - z0*x0 - z2*x2 + z3*x4
395 // => (z0 + z2)*(x0 + x2) = out_z2 + z0*x0 + z2*x2 - z3*x4
396 _compute_z3_x4.generate_r1cs_witness();
397 const Fp2T z3_x4 = _compute_z3_x4.result.get_element();
398 _result._c0._c2.generate_r1cs_witness(
399 (z0 + z2) * (x0 + x2) - z0_x0 - z2_x2 + z3_x4);
400 _compute_z02_x02.A.evaluate();
401 _compute_z02_x02.B.evaluate();
402 _compute_z02_x02.generate_r1cs_witness();
404 // z2*x4 + z4*x2 = (z2 + z4)*(x2 + x4) - z2*x2 - z4*x4
405 // out_z3 = z3*x0 + non_residue * (z2*x4 + z4*x2)
406 // = z3*x0 + non_residue * ((z2 + z4)*(x2 + x4) - z2*x2 - z4*x4)
407 // => (z2 + z4)*(x2 + x4) = (out_z3 - z3*x0) / non_residue + z2*x2 + z4_x4
408 _compute_z3_x0.generate_r1cs_witness();
409 const Fp2T z3_x0 = _compute_z3_x0.result.get_element();
410 _result._c1._c0.generate_r1cs_witness(
411 z3_x0 + Fp6T::non_residue * ((z2 + z4) * (x2 + x4) - z2_x2 - z4_x4));
412 _compute_z24_x24.A.evaluate();
413 _compute_z24_x24.B.evaluate();
414 _compute_z24_x24.generate_r1cs_witness();
416 // z0*x4 + z4*x0 = (z0 + z4)*(x0 + x4) - z0*x0 - z4*x4
417 // out_z4 = z0*x4 + z4*x0 + non_residue * z5*x2
418 // = (z0 + z4)*(x0 + x4) - z0*x0 - z4*x4 + non_residue * z5*x2
419 // => (z0 + z4)*(x0 + x4) = out_z4 + z0*x0 + z4*x4 - non_residue * z5*x2
420 _compute_z5_x2.generate_r1cs_witness();
421 const Fp2T z5_x2 = _compute_z5_x2.result.get_element();
422 _result._c1._c1.generate_r1cs_witness(
423 (z0 + z4) * (x0 + x4) - z0_x0 - z4_x4 + Fp6T::non_residue * z5_x2);
424 _compute_z04_x04.A.evaluate();
425 _compute_z04_x04.B.evaluate();
426 _compute_z04_x04.generate_r1cs_witness();
428 // S = z1_x0 - z1_x2 - z3_x0 - z3*x4 - z5_x2 - z5*x4
429 // out_z5 = z1*x4 + z3*x2 + z5*x0
430 // = (z1 + z3 + z5)*(x0 + x2 + x4) - S
431 // => (z1 + z3 + z5)*(x0 + x2 + x4) = out_z5 + S
433 const Fp2T S = _S.get_element();
434 _result._c1._c2.generate_r1cs_witness((z1 + z3 + z5) * (x0 + x2 + x4) - S);
435 _compute_out_z5_plus_S.A.evaluate();
436 _compute_out_z5_plus_S.B.evaluate();
437 _compute_out_z5_plus_S.generate_r1cs_witness();
440 // Fp12_2over3over2_mul_gadget methods
442 template<typename Fp12T>
443 Fp12_2over3over2_mul_gadget<Fp12T>::Fp12_2over3over2_mul_gadget(
444 protoboard<FieldT> &pb,
445 const Fp12_2over3over2_variable<Fp12T> &A,
446 const Fp12_2over3over2_variable<Fp12T> &B,
447 const Fp12_2over3over2_variable<Fp12T> &result,
448 const std::string &annotation_prefix)
449 : gadget<FieldT>(pb, annotation_prefix)
457 Fp6_3over2_variable<Fp6T>(pb, FMT(annotation_prefix, " v0")),
459 // result0 = a0*b0 + non_residue*a1*b1
460 // <=> a1*b1 = (result0 - a0*b0) * non_residue.inverse
465 fp6_mul_by_non_residue_inverse<Fp12T>(
467 _result._c0 - _compute_v0._result,
468 FMT(annotation_prefix, " v1")),
469 FMT(annotation_prefix, " _compute_v1"))
470 // result1 = a0*b1 + a1*b0 = (a0 + a1)*(b0 + b1) - a0*b0 - a1*b1
471 // <=> (a0 + a1)(b0 + b1) = result1 + a0*b0 + a1*b1
472 , _compute_a0_plus_a1_times_b0_plus_b1(
476 _result._c1 + _compute_v0._result + _compute_v1._result,
477 FMT(annotation_prefix, " _compute_a0_plus_a1_times_b0_plus_b1"))
481 template<typename Fp12T>
482 const Fp12_2over3over2_variable<Fp12T>
483 &Fp12_2over3over2_mul_gadget<Fp12T>::result() const
488 template<typename Fp12T>
489 void Fp12_2over3over2_mul_gadget<Fp12T>::generate_r1cs_constraints()
491 _compute_v0.generate_r1cs_constraints();
492 _compute_v1.generate_r1cs_constraints();
493 _compute_a0_plus_a1_times_b0_plus_b1.generate_r1cs_constraints();
496 template<typename Fp12T>
497 void Fp12_2over3over2_mul_gadget<Fp12T>::generate_r1cs_witness()
499 _compute_v0.generate_r1cs_witness();
500 const Fp6T a0 = _compute_v0._A.get_element();
501 const Fp6T a1 = _compute_v1._A.get_element();
502 const Fp6T b0 = _compute_v0._B.get_element();
503 const Fp6T b1 = _compute_v1._B.get_element();
504 const Fp6T a0b0 = _compute_v0._result.get_element();
505 const Fp6T a1b1 = a1 * b1;
507 _result._c0.generate_r1cs_witness(a0b0 + Fp12T::mul_by_non_residue(a1b1));
508 _compute_v1._result.evaluate();
509 _compute_v1.generate_r1cs_witness();
511 _result._c1.generate_r1cs_witness((a0 + a1) * (b0 + b1) - a0b0 - a1b1);
513 _compute_a0_plus_a1_times_b0_plus_b1._A.evaluate();
514 _compute_a0_plus_a1_times_b0_plus_b1._B.evaluate();
515 _compute_a0_plus_a1_times_b0_plus_b1.generate_r1cs_witness();
518 // Fp12_2over3over2_inv_gadget methods
520 template<typename Fp12T>
521 Fp12_2over3over2_inv_gadget<Fp12T>::Fp12_2over3over2_inv_gadget(
522 protoboard<FieldT> &pb,
523 const Fp12_2over3over2_variable<Fp12T> &A,
524 const Fp12_2over3over2_variable<Fp12T> &result,
525 const std::string &annotation_prefix)
526 : gadget<FieldT>(pb, annotation_prefix)
530 // <=> _result * A == Fp12::one()
531 , _compute_A_times_result(
535 Fp12_2over3over2_variable<Fp12T>(
537 Fp6_3over2_variable<Fp6T>(pb, Fp6T::one(), " (A*A.inv).c0"),
538 Fp6_3over2_variable<Fp6T>(pb, Fp6T::zero(), " (A*A.inv).c1"),
539 FMT(annotation_prefix, " A*A.mult_inv")),
540 FMT(annotation_prefix, " _compute_A_times_result"))
544 template<typename Fp12T>
545 const Fp12_2over3over2_variable<Fp12T>
546 &Fp12_2over3over2_inv_gadget<Fp12T>::result() const
551 template<typename Fp12T>
552 void Fp12_2over3over2_inv_gadget<Fp12T>::generate_r1cs_constraints()
554 _compute_A_times_result.generate_r1cs_constraints();
557 template<typename Fp12T>
558 void Fp12_2over3over2_inv_gadget<Fp12T>::generate_r1cs_witness()
560 _result.generate_r1cs_witness(_A.get_element().inverse());
561 _compute_A_times_result.generate_r1cs_witness();
564 // Fp12_2over3over2_cyclotomic_square_gadget methods
566 template<typename Fp12T>
567 Fp12_2over3over2_cyclotomic_square_gadget<Fp12T>::
568 Fp12_2over3over2_cyclotomic_square_gadget(
569 protoboard<FieldT> &pb,
570 const Fp12_2over3over2_variable<Fp12T> &A,
571 const Fp12_2over3over2_variable<Fp12T> &result,
572 const std::string &annotation_prefix)
573 : gadget<FieldT>(pb, annotation_prefix)
576 // z0z4 = 6^{-1} * (result4 - 2*z4)
581 (_result._c1._c1 - _A._c1._c1 - _A._c1._c1) * FieldT(6).inverse(),
582 FMT(annotation_prefix, " _compute_z0z4"))
583 // 3*(z0 + z4) * (z0 + non_residue * z4)
584 // = result0 + 3*(1 + non_residue)*z0z4 + 2*z0
587 (_A._c0._c0 + _A._c1._c1) * FieldT(3),
588 _A._c0._c0 + _A._c1._c1 * Fp6T::non_residue,
589 _result._c0._c0 + _A._c0._c0 + _A._c0._c0 +
590 _compute_z0z4.result * (Fp2T::one() + Fp6T::non_residue) *
592 FMT(annotation_prefix, " _check_result_0"))
593 // z3z2 = 6^{-1} * (result5 - 2*z5)
598 (_result._c1._c2 - _A._c1._c2 - _A._c1._c2) * FieldT(6).inverse(),
599 FMT(annotation_prefix, " _compute_z3z2"))
600 // 3*(z3 + z2)*(z3 + non_residue * z2)
601 // = result1 + 3*(1 + non_residue)*_z3z2 + 2*z1
604 (_A._c1._c0 + _A._c0._c2) * FieldT(3),
605 _A._c1._c0 + _A._c0._c2 * Fp6T::non_residue,
606 _result._c0._c1 + _A._c0._c1 + _A._c0._c1 +
607 _compute_z3z2.result * (Fp2T::one() + Fp6T::non_residue) *
609 FMT(annotation_prefix, " _check_result_1"))
610 // z1z5 = 6^{-1} * non_residue^{-1} * (result3 - 2*z3)
615 (_result._c1._c0 - _A._c1._c0 - _A._c1._c0) *
616 Fp6T::non_residue.inverse() * FieldT(6).inverse(),
617 FMT(annotation_prefix, " _compute_z1z5"))
618 // 3*(z1 + z5)*(z1 + non_residue * z5)
619 // = result2 + 3*(1 + non_residue)*z1z5 + 2*z2
622 (_A._c0._c1 + _A._c1._c2) * FieldT(3),
623 _A._c0._c1 + _A._c1._c2 * Fp6T::non_residue,
624 _result._c0._c2 + _A._c0._c2 + _A._c0._c2 +
625 _compute_z1z5.result * (Fp2T::one() + Fp6T::non_residue) *
627 FMT(annotation_prefix, " _check_result_2"))
631 template<typename Fp12T>
632 const Fp12_2over3over2_variable<Fp12T>
633 &Fp12_2over3over2_cyclotomic_square_gadget<Fp12T>::result() const
638 template<typename Fp12T>
639 void Fp12_2over3over2_cyclotomic_square_gadget<
640 Fp12T>::generate_r1cs_constraints()
642 _compute_z0z4.generate_r1cs_constraints();
643 _check_result_0.generate_r1cs_constraints();
644 _compute_z3z2.generate_r1cs_constraints();
645 _check_result_1.generate_r1cs_constraints();
646 _compute_z1z5.generate_r1cs_constraints();
647 _check_result_2.generate_r1cs_constraints();
650 template<typename Fp12T>
651 void Fp12_2over3over2_cyclotomic_square_gadget<Fp12T>::generate_r1cs_witness()
653 const Fp2T z0 = _A._c0._c0.get_element();
654 const Fp2T z1 = _A._c0._c1.get_element();
655 const Fp2T z2 = _A._c0._c2.get_element();
656 const Fp2T z3 = _A._c1._c0.get_element();
657 const Fp2T z4 = _A._c1._c1.get_element();
658 const Fp2T z5 = _A._c1._c2.get_element();
660 // result4 = 6 * z0z4 + 2 * z4
661 // <=> z0z4 = 6^{-1} * (result4 - 2*z4)
662 const Fp2T z0z4 = z0 * z4;
663 const Fp2T z0z4_2 = z0z4 + z0z4;
664 _result._c1._c1.generate_r1cs_witness(z0z4_2 + z0z4_2 + z0z4_2 + z4 + z4);
665 _compute_z0z4.result.evaluate();
666 _compute_z0z4.generate_r1cs_witness();
668 // result0 = 3*t0_L - 3*t0_R - 2*z0
670 // t0_L = (z0 + z4) * (z0 + non_residue * z4)
671 // t0_R = z0z4 * (my_Fp2::one() + my_Fp6::non_residue)
672 // <=> 3*(z0 + z4) * (z0 + non_residue * z4)
673 // = result0 + 3*(1 + non_residue)*z0z4 + 2*z0
674 const Fp2T t0_L = (z0 + z4) * (z0 + Fp6T::non_residue * z4);
675 const Fp2T t0_R = z0z4 * (Fp2T::one() + Fp6T::non_residue);
676 _result._c0._c0.generate_r1cs_witness(
677 t0_L + t0_L + t0_L - t0_R - t0_R - t0_R - z0 - z0);
678 _check_result_0.A.evaluate();
679 _check_result_0.B.evaluate();
680 _check_result_0.result.evaluate();
681 _check_result_0.generate_r1cs_witness();
683 // result5 = 6 * z3z2 + 2 * z5
684 // <=> z3z2 = 6^{-1} * (result5 - 2*z5)
685 const Fp2T z3z2 = z3 * z2;
686 const Fp2T z3z2_2 = z3z2 + z3z2;
687 _result._c1._c2.generate_r1cs_witness(z3z2_2 + z3z2_2 + z3z2_2 + z5 + z5);
688 _compute_z3z2.result.evaluate();
689 _compute_z3z2.generate_r1cs_witness();
691 // result1 = 3*t2_L - 3*t2_R - 2*z1
693 // t2_L = (z3 + z2) * (z3 + non_residue * z2)
694 // t2_R = z3z2 * (1 + non_residue)
695 // <=> 3*(z3 + z2)*(z3 + non_residue * z2)
696 // = result1 + 3*(1 + non_residue)*_z3z2 + 2*z1
697 const Fp2T t2_L = (z3 + z2) * (z3 + Fp6T::non_residue * z2);
698 const Fp2T t2_R = z3z2 * (Fp2T::one() + Fp6T::non_residue);
699 _result._c0._c1.generate_r1cs_witness(
700 t2_L + t2_L + t2_L - t2_R - t2_R - t2_R - z1 - z1);
701 _check_result_1.A.evaluate();
702 _check_result_1.B.evaluate();
703 _check_result_1.result.evaluate();
704 _check_result_1.generate_r1cs_witness();
706 // result3 = 6 * non_residue * z1z5 + 2*z3
707 // <=> z1z5 = 6^{-1} * non_residue^{-1} * (out3 - 2*z3)
708 const Fp2T z1z5 = z1 * z5;
709 const Fp2T z1z5_2 = z1z5 + z1z5;
710 _result._c1._c0.generate_r1cs_witness(
711 (z1z5_2 + z1z5_2 + z1z5_2) * Fp6T::non_residue + z3 + z3);
712 _compute_z1z5.result.evaluate();
713 _compute_z1z5.generate_r1cs_witness();
715 // result2 = 3*t4_L - 3*t4_R - 2*z2
717 // t4_L = (z1 + z5) * (z1 + non_residue * z5)
718 // t4_R = z1z5 * (1 + non_residue);
719 // <=> 3*(z1 + z5)*(z1 + non_residue * z5)
720 // = result2 + 3*(1 + non_residue)*z1z5 + 2*z2
721 const Fp2T t4_L = (z1 + z5) * (z1 + Fp6T::non_residue * z5);
722 const Fp2T t4_R = z1z5 * (Fp2T::one() + Fp6T::non_residue);
723 _result._c0._c2.generate_r1cs_witness(
724 t4_L + t4_L + t4_L - t4_R - t4_R - t4_R - z2 - z2);
725 _check_result_2.A.evaluate();
726 _check_result_2.B.evaluate();
727 _check_result_2.result.evaluate();
728 _check_result_2.generate_r1cs_witness();
731 } // namespace libsnark
733 #endif // LIBSNARK_GADGETLIB1_GADGETS_FIELDS_FP12_2OVER3OVER2_GADGETS_TCC_