Clearmatics Libsnark  0.1
C++ library for zkSNARK proofs
fp12_2over3over2_gadgets.tcc
Go to the documentation of this file.
1 /** @file
2  *****************************************************************************
3  * @author This file is part of libsnark, developed by Clearmatics Ltd
4  * (originally developed by SCIPR Lab) and contributors
5  * (see AUTHORS).
6  * @copyright MIT license (see LICENSE file)
7  *****************************************************************************/
8 
9 #ifndef LIBSNARK_GADGETLIB1_GADGETS_FIELDS_FP12_2OVER3OVER2_GADGETS_TCC_
10 #define LIBSNARK_GADGETLIB1_GADGETS_FIELDS_FP12_2OVER3OVER2_GADGETS_TCC_
11 
12 #include "libsnark/gadgetlib1/gadgets/fields/fp12_2over3over2_gadgets.hpp"
13 
14 namespace libsnark
15 {
16 
17 // Fp12_2over3over2_variable methods
18 
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"))
25 {
26 }
27 
28 template<typename Fp12T>
29 Fp12_2over3over2_variable<Fp12T>::Fp12_2over3over2_variable(
30  protoboard<FieldT> &pb,
31  const Fp12T &el,
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"))
36 {
37 }
38 
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)
46 {
47 }
48 
49 template<typename Fp12T>
50 Fp12_2over3over2_variable<Fp12T> Fp12_2over3over2_variable<Fp12T>::operator*(
51  const Fp2T &fp2_const) const
52 {
53  return Fp12_2over3over2_variable(
54  this->pb,
55  _c0 * fp2_const,
56  _c1 * fp2_const,
57  FMT(this->annotation_prefix, " fp12_var*fp2_const"));
58 }
59 
60 template<typename Fp12T>
61 Fp12_2over3over2_variable<Fp12T> Fp12_2over3over2_variable<Fp12T>::operator*(
62  const Fp12T &fp12_const) const
63 {
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]);
69 
70  return Fp12_2over3over2_variable(
71  this->pb,
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"));
75 }
76 
77 template<typename Fp12T>
78 Fp12_2over3over2_variable<Fp12T> Fp12_2over3over2_variable<
79  Fp12T>::frobenius_map(size_t power) const
80 {
81  return Fp12_2over3over2_variable(
82  this->pb,
83  _c0.frobenius_map(power),
84  _c1.frobenius_map(power) * Fp12T::Frobenius_coeffs_c1[power % 12],
85  FMT(this->annotation_prefix, " fp12_frobenius_map"));
86 }
87 
88 template<typename Fp12T>
89 Fp12_2over3over2_variable<Fp12T> Fp12_2over3over2_variable<
90  Fp12T>::unitary_inverse() const
91 {
92  return Fp12_2over3over2_variable(
93  this->pb, _c0, -_c1, FMT(this->annotation_prefix, " fp12_unitary_inv"));
94 }
95 
96 template<typename Fp12T> void Fp12_2over3over2_variable<Fp12T>::evaluate() const
97 {
98  _c0.evaluate();
99  _c1.evaluate();
100 }
101 
102 template<typename Fp12T>
103 void Fp12_2over3over2_variable<Fp12T>::generate_r1cs_witness(const Fp12T &el)
104 {
105  _c0.generate_r1cs_witness(el.coeffs[0]);
106  _c1.generate_r1cs_witness(el.coeffs[1]);
107 }
108 
109 template<typename Fp12T>
110 Fp12T Fp12_2over3over2_variable<Fp12T>::get_element() const
111 {
112  return Fp12T(_c0.get_element(), _c1.get_element());
113 }
114 
115 // Multiplication of Fp6 elements by Fp12::non-residue and
116 // Fp12::non-residue^{-1}.
117 
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)
123 {
124  return Fp6_3over2_variable<typename Fp12T::my_Fp6>(
125  pb, c._c2 * Fp12T::non_residue, c._c0, c._c1, annotation_prefix);
126 }
127 
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)
133 {
134  return Fp6_3over2_variable<typename Fp12T::my_Fp6>(
135  pb,
136  c._c1,
137  c._c2,
138  c._c0 * Fp12T::non_residue.inverse(),
139  annotation_prefix);
140 }
141 
142 // Fp12_2over3over2_square_gadget methods
143 
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)
151  , _A(A)
152  , _result(result)
153  , _compute_alpha(
154  pb,
155  _A._c0,
156  _A._c1,
157  _result._c1 * (FieldT("2").inverse()),
158  FMT(annotation_prefix, " _compute_alpha"))
159  , _compute_beta(
160  pb,
161  _A._c0 + _A._c1,
162  _A._c0 + fp6_mul_by_non_residue<Fp12T>(
163  pb, _A._c1, FMT(annotation_prefix, " a1_times_v")),
164  _result._c0 +
165  fp6_mul_by_non_residue<Fp12T>(
166  pb,
167  _compute_alpha._result,
168  FMT(annotation_prefix, " alpha_times_v")) +
169  _compute_alpha._result,
170  FMT(annotation_prefix, " _compute_beta"))
171 {
172 }
173 
174 template<typename Fp12T>
175 const Fp12_2over3over2_variable<Fp12T>
176  &Fp12_2over3over2_square_gadget<Fp12T>::result() const
177 {
178  return _result;
179 }
180 
181 template<typename Fp12T>
182 void Fp12_2over3over2_square_gadget<Fp12T>::generate_r1cs_constraints()
183 {
184  _compute_alpha.generate_r1cs_constraints();
185  _compute_beta.generate_r1cs_constraints();
186 }
187 
188 template<typename Fp12T>
189 void Fp12_2over3over2_square_gadget<Fp12T>::generate_r1cs_witness()
190 {
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();
196 
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();
203 }
204 
205 // Fp12_2over3over2_mul_by_024_gadget methods
206 
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)
217  , _Z(Z)
218  , _X_0(X_0)
219  , _X_2(X_2)
220  , _X_4(X_4)
221  // out_z0 = z0*x0 + non_residue * (z1*x2 + z4*x4)
222  // => z0 * x0 = out_z0 - non_residue * (z1*x2 + z4*x4)
223  , _compute_z1_x2(
224  pb,
225  Z._c0._c1,
226  X_2,
227  Fp2_variable<Fp2T>(pb, FMT(annotation_prefix, " z1_x2")),
228  FMT(annotation_prefix, "_compute_z1_x2"))
229  , _compute_z4_x4(
230  pb,
231  Z._c1._c1,
232  X_4,
233  Fp2_variable<Fp2T>(pb, FMT(annotation_prefix, " z4_x4")),
234  FMT(annotation_prefix, " _compute_z4_x4"))
235  , _compute_z0_x0(
236  pb,
237  Z._c0._c0,
238  X_0,
239  result._c0._c0 + ((_compute_z1_x2.result + _compute_z4_x4.result) *
240  -Fp6T::non_residue),
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)
244  , _compute_z2_x2(
245  pb,
246  Z._c0._c2,
247  X_2,
248  Fp2_variable<Fp2T>(pb, FMT(annotation_prefix, " z2_x2")),
249  FMT(annotation_prefix, " _compute_z2_x2"))
250  , _compute_z5_x4(
251  pb,
252  Z._c1._c2,
253  X_4,
254  Fp2_variable<Fp2T>(pb, FMT(annotation_prefix, " z5_x4")),
255  FMT(annotation_prefix, " _compute_z5_x4"))
256  , _compute_z1_x0(
257  pb,
258  Z._c0._c1,
259  X_0,
260  result._c0._c1 + ((_compute_z2_x2.result + _compute_z5_x4.result) *
261  -Fp6T::non_residue),
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
267  , _compute_z3_x4(
268  pb,
269  Z._c1._c0,
270  X_4,
271  Fp2_variable<Fp2T>(pb, FMT(annotation_prefix, " z3_x4")),
272  FMT(annotation_prefix, " _compute_z3_x4"))
273  , _compute_z02_x02(
274  pb,
275  Z._c0._c0 + Z._c0._c2,
276  X_0 + X_2,
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
284  , _compute_z3_x0(
285  pb,
286  Z._c1._c0,
287  X_0,
288  Fp2_variable<Fp2T>(pb, FMT(annotation_prefix, " z3_x0")),
289  FMT(annotation_prefix, " _compute_z3_x0"))
290  , _compute_z24_x24(
291  pb,
292  Z._c0._c2 + Z._c1._c1,
293  X_2 + X_4,
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
302  , _compute_z5_x2(
303  pb,
304  Z._c1._c2,
305  X_2,
306  Fp2_variable<Fp2T>(pb, FMT(annotation_prefix, " z5_x2")),
307  FMT(annotation_prefix, " _compute_z5_x2"))
308  , _compute_z04_x04(
309  pb,
310  Z._c0._c0 + Z._c1._c1,
311  X_0 + X_4,
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(
322  pb,
323  Z._c0._c1 + Z._c1._c0 + Z._c1._c2,
324  X_0 + X_2 + X_4,
325  result._c1._c2 + _S,
326  FMT(annotation_prefix, " _compute_out_z5_plus_S"))
327  , _result(result)
328 {
329 }
330 
331 template<typename Fp12T>
332 const Fp12_2over3over2_variable<Fp12T>
333  &Fp12_2over3over2_mul_by_024_gadget<Fp12T>::result() const
334 {
335  return _result;
336 }
337 
338 template<typename Fp12T>
339 void Fp12_2over3over2_mul_by_024_gadget<Fp12T>::generate_r1cs_constraints()
340 {
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();
354 }
355 
356 template<typename Fp12T>
357 void Fp12_2over3over2_mul_by_024_gadget<Fp12T>::generate_r1cs_witness()
358 {
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();
365 
366  const Fp2T x0 = _X_0.get_element();
367  const Fp2T x2 = _X_2.get_element();
368  const Fp2T x4 = _X_4.get_element();
369 
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(
377  z0_x0 +
378  Fp6T::non_residue * (_compute_z1_x2.result.get_element() + z4_x4));
379  _compute_z0_x0.generate_r1cs_witness();
380 
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(
388  z1_x0 +
389  Fp6T::non_residue * (z2_x2 + _compute_z5_x4.result.get_element()));
390  _compute_z1_x0.generate_r1cs_witness();
391 
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();
403 
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();
415 
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();
427 
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
432  _S.evaluate();
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();
438 }
439 
440 // Fp12_2over3over2_mul_gadget methods
441 
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)
450  , _A(A)
451  , _B(B)
452  , _result(result)
453  , _compute_v0(
454  pb,
455  A._c0,
456  B._c0,
457  Fp6_3over2_variable<Fp6T>(pb, FMT(annotation_prefix, " v0")),
458  " _compute_v0")
459  // result0 = a0*b0 + non_residue*a1*b1
460  // <=> a1*b1 = (result0 - a0*b0) * non_residue.inverse
461  , _compute_v1(
462  pb,
463  A._c1,
464  B._c1,
465  fp6_mul_by_non_residue_inverse<Fp12T>(
466  pb,
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(
473  pb,
474  A._c0 + A._c1,
475  B._c0 + B._c1,
476  _result._c1 + _compute_v0._result + _compute_v1._result,
477  FMT(annotation_prefix, " _compute_a0_plus_a1_times_b0_plus_b1"))
478 {
479 }
480 
481 template<typename Fp12T>
482 const Fp12_2over3over2_variable<Fp12T>
483  &Fp12_2over3over2_mul_gadget<Fp12T>::result() const
484 {
485  return _result;
486 }
487 
488 template<typename Fp12T>
489 void Fp12_2over3over2_mul_gadget<Fp12T>::generate_r1cs_constraints()
490 {
491  _compute_v0.generate_r1cs_constraints();
492  _compute_v1.generate_r1cs_constraints();
493  _compute_a0_plus_a1_times_b0_plus_b1.generate_r1cs_constraints();
494 }
495 
496 template<typename Fp12T>
497 void Fp12_2over3over2_mul_gadget<Fp12T>::generate_r1cs_witness()
498 {
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;
506 
507  _result._c0.generate_r1cs_witness(a0b0 + Fp12T::mul_by_non_residue(a1b1));
508  _compute_v1._result.evaluate();
509  _compute_v1.generate_r1cs_witness();
510 
511  _result._c1.generate_r1cs_witness((a0 + a1) * (b0 + b1) - a0b0 - a1b1);
512 
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();
516 }
517 
518 // Fp12_2over3over2_inv_gadget methods
519 
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)
527  , _A(A)
528  , _result(result)
529  // _result == A^{-1}
530  // <=> _result * A == Fp12::one()
531  , _compute_A_times_result(
532  pb,
533  _A,
534  _result,
535  Fp12_2over3over2_variable<Fp12T>(
536  pb,
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"))
541 {
542 }
543 
544 template<typename Fp12T>
545 const Fp12_2over3over2_variable<Fp12T>
546  &Fp12_2over3over2_inv_gadget<Fp12T>::result() const
547 {
548  return _result;
549 }
550 
551 template<typename Fp12T>
552 void Fp12_2over3over2_inv_gadget<Fp12T>::generate_r1cs_constraints()
553 {
554  _compute_A_times_result.generate_r1cs_constraints();
555 }
556 
557 template<typename Fp12T>
558 void Fp12_2over3over2_inv_gadget<Fp12T>::generate_r1cs_witness()
559 {
560  _result.generate_r1cs_witness(_A.get_element().inverse());
561  _compute_A_times_result.generate_r1cs_witness();
562 }
563 
564 // Fp12_2over3over2_cyclotomic_square_gadget methods
565 
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)
574  , _A(A)
575  , _result(result)
576  // z0z4 = 6^{-1} * (result4 - 2*z4)
577  , _compute_z0z4(
578  pb,
579  _A._c0._c0,
580  _A._c1._c1,
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
585  , _check_result_0(
586  pb,
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) *
591  FieldT(3),
592  FMT(annotation_prefix, " _check_result_0"))
593  // z3z2 = 6^{-1} * (result5 - 2*z5)
594  , _compute_z3z2(
595  pb,
596  _A._c1._c0,
597  _A._c0._c2,
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
602  , _check_result_1(
603  pb,
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) *
608  FieldT(3),
609  FMT(annotation_prefix, " _check_result_1"))
610  // z1z5 = 6^{-1} * non_residue^{-1} * (result3 - 2*z3)
611  , _compute_z1z5(
612  pb,
613  _A._c0._c1,
614  _A._c1._c2,
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
620  , _check_result_2(
621  pb,
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) *
626  FieldT(3),
627  FMT(annotation_prefix, " _check_result_2"))
628 {
629 }
630 
631 template<typename Fp12T>
632 const Fp12_2over3over2_variable<Fp12T>
633  &Fp12_2over3over2_cyclotomic_square_gadget<Fp12T>::result() const
634 {
635  return _result;
636 }
637 
638 template<typename Fp12T>
639 void Fp12_2over3over2_cyclotomic_square_gadget<
640  Fp12T>::generate_r1cs_constraints()
641 {
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();
648 }
649 
650 template<typename Fp12T>
651 void Fp12_2over3over2_cyclotomic_square_gadget<Fp12T>::generate_r1cs_witness()
652 {
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();
659 
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();
667 
668  // result0 = 3*t0_L - 3*t0_R - 2*z0
669  // where
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();
682 
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();
690 
691  // result1 = 3*t2_L - 3*t2_R - 2*z1
692  // where
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();
705 
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();
714 
715  // result2 = 3*t4_L - 3*t4_R - 2*z2
716  // where
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();
729 }
730 
731 } // namespace libsnark
732 
733 #endif // LIBSNARK_GADGETLIB1_GADGETS_FIELDS_FP12_2OVER3OVER2_GADGETS_TCC_