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_PAIRING_BW6_761_BLS12_377_BLS12_377_PRECOMPUTATION_TCC_
10 #define LIBSNARK_GADGETLIB1_GADGETS_PAIRING_BW6_761_BLS12_377_BLS12_377_PRECOMPUTATION_TCC_
15 // Iterate through bits of loop_count, skipping the highest order bit.
17 class bls12_377_miller_loop_bits
20 inline bls12_377_miller_loop_bits()
22 // TODO: should not need to do this dynamically
23 ssize_t start_i = libff::bls12_377_ate_loop_count.max_bits();
24 while (!libff::bls12_377_ate_loop_count.test_bit(start_i--)) {
39 inline bool current() const
41 return libff::bls12_377_ate_loop_count.test_bit(_i);
44 inline size_t index() const { return (size_t)_i; }
46 inline bool last() const { return 0 == index(); }
52 // bls12_377_G1_precomputation methods
54 template<typename ppT>
55 bls12_377_G1_precomputation<ppT>::bls12_377_G1_precomputation() : _Px(), _Py()
59 template<typename ppT>
60 bls12_377_G1_precomputation<ppT>::bls12_377_G1_precomputation(
61 protoboard<FieldT> &pb,
62 const libff::G1<other_curve<ppT>> &P_val,
63 const std::string & /* annotation_prefix */)
64 : _Px(new pb_linear_combination<FieldT>())
65 , _Py(new pb_linear_combination<FieldT>())
67 libff::G1<other_curve<ppT>> P_affine = P_val;
68 P_affine.to_affine_coordinates();
69 _Px->assign(pb, P_affine.X);
70 _Py->assign(pb, P_affine.Y);
75 // bls12_377_G2_proj methods
77 template<typename ppT>
78 bls12_377_G2_proj<ppT>::bls12_377_G2_proj(
79 protoboard<libff::Fr<ppT>> &pb, const std::string &annotation_prefix)
80 : X(pb, FMT(annotation_prefix, " X"))
81 , Y(pb, FMT(annotation_prefix, " Y"))
82 , Z(pb, FMT(annotation_prefix, " Z"))
86 template<typename ppT>
87 bls12_377_G2_proj<ppT>::bls12_377_G2_proj(
88 const Fqe_variable<ppT> &X_var,
89 const Fqe_variable<ppT> &Y_var,
90 const Fqe_variable<ppT> &Z_var)
91 : X(X_var), Y(Y_var), Z(Z_var)
95 template<typename ppT>
96 void bls12_377_G2_proj<ppT>::generate_r1cs_witness(
97 const libff::bls12_377_G2 &element)
99 X.generate_r1cs_witness(element.X);
100 Y.generate_r1cs_witness(element.Y);
101 Z.generate_r1cs_witness(element.Z);
104 // bls12_377_ate_ell_coeffs methods
106 template<typename ppT>
107 bls12_377_ate_ell_coeffs<ppT>::bls12_377_ate_ell_coeffs(
108 protoboard<FqT> &pb, const std::string &annotation_prefix)
109 : ell_0(pb, FMT(annotation_prefix, " ell_0"))
110 , ell_vw(pb, FMT(annotation_prefix, " ell_vw"))
111 , ell_vv(pb, FMT(annotation_prefix, " ell_vv"))
115 template<typename ppT>
116 bls12_377_ate_ell_coeffs<ppT>::bls12_377_ate_ell_coeffs(
118 const libff::Fqe<other_curve<ppT>> ell_0_val,
119 const libff::Fqe<other_curve<ppT>> ell_vw_val,
120 const libff::Fqe<other_curve<ppT>> ell_vv_val,
121 const std::string &annotation_prefix)
122 : ell_0(pb, ell_0_val, FMT(annotation_prefix, " ell_0"))
123 , ell_vw(pb, ell_vw_val, FMT(annotation_prefix, " ell_vw"))
124 , ell_vv(pb, ell_vv_val, FMT(annotation_prefix, " ell_vv"))
128 // bls12_377_G2_precomputation methods
130 template<typename ppT>
131 bls12_377_G2_precomputation<ppT>::bls12_377_G2_precomputation()
135 template<typename ppT>
136 bls12_377_G2_precomputation<ppT>::bls12_377_G2_precomputation(
137 protoboard<FieldT> &pb,
138 const libff::G2<other_curve<ppT>> &Q_val,
139 const std::string &annotation_prefix)
141 const libff::G2_precomp<other_curve<ppT>> Q_prec =
142 other_curve<ppT>::precompute_G2(Q_val);
143 const size_t num_coeffs = Q_prec.coeffs.size();
144 _coeffs.reserve(num_coeffs);
145 for (size_t i = 0; i < num_coeffs; ++i) {
146 const libff::bls12_377_ate_ell_coeffs &c = Q_prec.coeffs[i];
147 _coeffs.emplace_back(new bls12_377_ate_ell_coeffs<ppT>(
152 FMT(annotation_prefix, " coeffs[%zu]", i)));
155 assert(num_coeffs == _coeffs.size());
158 // bls12_377_G1_precompute_gadget methods
160 template<typename ppT>
161 bls12_377_G1_precompute_gadget<ppT>::bls12_377_G1_precompute_gadget(
162 protoboard<libff::Fr<ppT>> &pb,
163 const G1_variable<ppT> &P,
164 bls12_377_G1_precomputation<ppT> &P_prec,
165 const std::string &annotation_prefix)
166 : gadget<libff::Fr<ppT>>(pb, annotation_prefix)
167 , _Px(new pb_linear_combination<libff::Fr<ppT>>())
168 , _Py(new pb_linear_combination<libff::Fr<ppT>>())
170 // Ensure that we don't overwrite an existing precomputation.
173 _Px->assign(pb, P.X);
174 _Py->assign(pb, P.Y);
179 template<typename ppT>
180 void bls12_377_G1_precompute_gadget<ppT>::generate_r1cs_constraints()
184 template<typename ppT>
185 void bls12_377_G1_precompute_gadget<ppT>::generate_r1cs_witness()
187 _Px->evaluate(this->pb);
188 _Py->evaluate(this->pb);
191 // bls12_377_ate_dbl_gadget methods
193 template<typename ppT>
194 bls12_377_ate_dbl_gadget<ppT>::bls12_377_ate_dbl_gadget(
196 const bls12_377_G2_proj<ppT> &R,
197 const bls12_377_G2_proj<ppT> &out_R,
198 const bls12_377_ate_ell_coeffs<ppT> &coeffs,
199 const std::string &annotation_prefix)
200 : gadget<libff::Fr<ppT>>(pb, annotation_prefix)
203 , _out_coeffs(coeffs)
209 _in_R.Y * FqT(2).inverse(),
210 Fqe_variable<ppT>(pb, FMT(annotation_prefix, " A")),
211 FMT(annotation_prefix, " _compute_A"))
217 Fqe_variable<ppT>(pb, FMT(annotation_prefix, " B")),
218 FMT(annotation_prefix, " _compute_B"))
228 // = xi * (3*b'*C - B)
229 // = xi * (3*b'*Rz^2 - Ry^2)
230 // <=> Rz^2 [C] = (ell_0 + xi.Ry^2) / 3*b'*xi
231 // = (3*b')^{-1}(ell_0*xi^{-1} + B)
235 (_out_coeffs.ell_0 * libff::bls12_377_twist.inverse() +
237 (FqT(3) * libff::bls12_377_twist_coeff_b).inverse(),
238 FMT(annotation_prefix, " _compute_C"))
244 // H = (Y + Z) ^ 2 - (B + C)
247 // <=> (Y+2)^2 [H] = B + C - ell_vw
248 , _compute_Y_plus_Z_squared(
251 _compute_B.result + _compute_C.result - _out_coeffs.ell_vw,
252 FMT(annotation_prefix, " _compute_Y_plus_Z_squared"))
258 // <=> Rx^2 [J] = ell_vv * 3^{-1}
262 _out_coeffs.ell_vv * FqT(3).inverse(),
263 FMT(annotation_prefix, " _compute_J"))
269 _compute_B.result - _compute_C.result *
270 libff::bls12_377_twist_coeff_b *
273 FMT(annotation_prefix, " _check_out_Rx"))
275 // outRy = G^2 - 3E^2
276 // where G = (B + F) / 2
277 // <=> G^2 = outRy + 3 * E^2
278 , _compute_E_squared(
280 _compute_C.result * libff::bls12_377_twist_coeff_b * FqT(3), // E
281 Fqe_variable<ppT>(pb, FMT(annotation_prefix, "E_squared")),
282 FMT(annotation_prefix, " _compute_E_squared"))
283 , _compute_G_squared(
286 _compute_C.result * libff::bls12_377_twist_coeff_b * FqT(9)) *
287 FqT(2).inverse(), // G = (B+F)/2
288 _out_R.Y + _compute_E_squared.result + _compute_E_squared.result +
289 _compute_E_squared.result,
290 FMT(annotation_prefix, " _compute_G_squared"))
294 // H = (Y + Z)^2 - (B + C)
298 _compute_Y_plus_Z_squared.result - _compute_B.result -
301 FMT(annotation_prefix, " _check_out_Rz"))
305 template<typename ppT>
306 void bls12_377_ate_dbl_gadget<ppT>::generate_r1cs_constraints()
308 _compute_A.generate_r1cs_constraints();
309 _compute_B.generate_r1cs_constraints();
310 _compute_C.generate_r1cs_constraints();
311 _compute_Y_plus_Z_squared.generate_r1cs_constraints();
312 _compute_J.generate_r1cs_constraints();
313 _check_out_Rx.generate_r1cs_constraints();
314 _compute_E_squared.generate_r1cs_constraints();
315 _compute_G_squared.generate_r1cs_constraints();
316 _check_out_Rz.generate_r1cs_constraints();
319 template<typename ppT>
320 void bls12_377_ate_dbl_gadget<ppT>::generate_r1cs_witness()
322 const FqeT Rx = _in_R.X.get_element();
323 const FqeT Ry = _in_R.Y.get_element();
324 const FqeT Rz = _in_R.Z.get_element();
327 _compute_A.B.evaluate();
328 _compute_A.generate_r1cs_witness();
331 _compute_B.generate_r1cs_witness();
339 // <=> Rz^2 [C] = (ell_0.xi^{-1} + Ry^2) * (3*b')^{-1}
340 const FqeT B = _compute_B.result.get_element();
341 const FqeT C = Rz * Rz;
342 const FqeT D = FqT(3) * C;
343 const FqeT E = libff::bls12_377_twist_coeff_b * D;
344 const FqeT I = E - B;
345 _out_coeffs.ell_0.generate_r1cs_witness(libff::bls12_377_twist * I);
346 _compute_C.result.evaluate();
347 _compute_C.generate_r1cs_witness();
348 assert(C == _compute_C.result.get_element());
350 (_out_coeffs.ell_0.get_element() * libff::bls12_377_twist.inverse() +
352 (FqT(3) * libff::bls12_377_twist_coeff_b).inverse() ==
353 _compute_C.result.get_element());
358 // H = (Y + 2) ^ 2 - (B + C)
359 // ell_vw = (B+C) - (Y+2)^2
360 // <=> (Y+2)^2 [H] = ell_vw - B - C
361 const FqeT Ry_plus_Rz_squared = (Ry + Rz) * (Ry + Rz);
362 _out_coeffs.ell_vw.generate_r1cs_witness(B + C - Ry_plus_Rz_squared);
363 _compute_Y_plus_Z_squared.A.evaluate();
364 _compute_Y_plus_Z_squared.result.evaluate();
365 _compute_Y_plus_Z_squared.generate_r1cs_witness();
367 _compute_Y_plus_Z_squared.result.get_element() == Ry_plus_Rz_squared);
373 const FqeT J = Rx * Rx;
374 _out_coeffs.ell_vv.generate_r1cs_witness(FqT(3) * J);
375 _compute_J.result.evaluate();
376 _compute_J.generate_r1cs_witness();
378 // outRx = A * (B - F)
379 _check_out_Rx.B.evaluate();
380 _check_out_Rx.result.evaluate();
381 _check_out_Rx.generate_r1cs_witness();
383 // outRy = G^2 - 3E^2
384 // where G = (B + F) / 2
385 // <=> G^2 = outRy + 3 * E^2
386 _compute_E_squared.A.evaluate();
387 _compute_E_squared.generate_r1cs_witness();
388 const FqeT E_squared = _compute_E_squared.result.get_element();
389 const FqeT F = FqT(3) * E;
390 const FqeT G = FqT(2).inverse() * (B + F);
391 const FqeT G_squared = G * G;
392 _out_R.Y.generate_r1cs_witness(G_squared - FqT(3) * E_squared);
393 _compute_G_squared.A.evaluate();
394 _compute_G_squared.result.evaluate();
395 _compute_G_squared.generate_r1cs_witness();
397 // out_Rz = B * H (assigned by check_outRz)
398 _check_out_Rz.B.evaluate();
399 assert(B == _check_out_Rz.A.get_element());
400 assert(Ry_plus_Rz_squared - B - C == _check_out_Rz.B.get_element());
401 _check_out_Rz.generate_r1cs_witness();
403 B * (Ry_plus_Rz_squared - B - C) == _check_out_Rz.result.get_element());
406 // bls12_377_ate_add_gadget methods
408 template<typename ppT>
409 bls12_377_ate_add_gadget<ppT>::bls12_377_ate_add_gadget(
410 protoboard<libff::Fr<ppT>> &pb,
411 const Fqe_variable<ppT> &Q_X,
412 const Fqe_variable<ppT> &Q_Y,
413 const bls12_377_G2_proj<ppT> &in_R,
414 const bls12_377_G2_proj<ppT> &out_R,
415 const bls12_377_ate_ell_coeffs<ppT> &out_coeffs,
416 const std::string &annotation_prefix)
417 : gadget<libff::Fr<ppT>>(pb, annotation_prefix)
422 , _out_coeffs(out_coeffs)
427 // <=> A = Qy * Rz = ell_vv + Ry
432 _out_coeffs.ell_vv + _in_R.Y,
433 FMT(annotation_prefix, " _compute_A"))
438 // <=> B = Qx * Rz = Rx - ell_vw
443 _in_R.X - _out_coeffs.ell_vw,
444 FMT(annotation_prefix, " _compute_B"))
446 // , theta(in_R.Y + (A * -libff::Fr<ppT>::one()))
448 // , lambda(in_R.X + (B * -libff::Fr<ppT>::one()))
449 // C = theta.squared() = ell_vv^2
453 Fqe_variable<ppT>(pb, FMT(annotation_prefix, " C")),
454 FMT(annotation_prefix, " _compute_C"))
455 // D = lambda.squared() = ell_vw^2
459 Fqe_variable<ppT>(pb, FMT(annotation_prefix, " D")),
460 FMT(annotation_prefix, " _compute_D"))
461 // E = lambda * D = D * ell_vw;
466 Fqe_variable<ppT>(pb, FMT(annotation_prefix, " E")),
467 FMT(annotation_prefix, " _compute_E"))
473 Fqe_variable<ppT>(pb, FMT(annotation_prefix, " F")),
474 FMT(annotation_prefix, " _compute_F"))
480 Fqe_variable<ppT>(pb, FMT(annotation_prefix, " G")),
481 FMT(annotation_prefix, " _compute_G"))
482 // H = E + F - (G + G);
483 , _H(_compute_E.result + _compute_F.result - _compute_G.result -
490 Fqe_variable<ppT>(pb, FMT(annotation_prefix, " I")),
491 FMT(annotation_prefix, " _compute_I"))
492 // out_coeffs.ell_0 = xi * J
493 // where J = theta * Qx - lambda * Qy
494 // <=> lambda * Qy = theta * Qx - ell_0 * xi^{-1}
495 , _compute_theta_times_Qx(
499 Fqe_variable<ppT>(pb, FMT(annotation_prefix, " theta_times_Qx")),
500 FMT(annotation_prefix, " _compute_theta_times_Qx"))
501 , _compute_lambda_times_Qy(
505 _compute_theta_times_Qx.result -
506 (_out_coeffs.ell_0 * libff::bls12_377_twist.inverse()),
507 FMT(annotation_prefix, " _compute_lambda_times_Qy"))
508 // out_Rx = lambda * H = ell_vw * H
514 FMT(annotation_prefix, " _check_out_Rx"))
515 // out_Ry = theta * (G - H) - I = -ell_vv * (G-H) - I
516 // <=> ell_vv * (H-G) = out_Ry + I
520 _H - _compute_G.result,
521 _out_R.Y + _compute_I.result,
522 FMT(annotation_prefix, " _check_out_Ry"))
529 FMT(annotation_prefix, " _check_out_Rz"))
533 template<typename ppT>
534 void bls12_377_ate_add_gadget<ppT>::generate_r1cs_constraints()
536 _compute_A.generate_r1cs_constraints();
537 _compute_B.generate_r1cs_constraints();
538 _compute_C.generate_r1cs_constraints();
539 _compute_D.generate_r1cs_constraints();
540 _compute_E.generate_r1cs_constraints();
541 _compute_F.generate_r1cs_constraints();
542 _compute_G.generate_r1cs_constraints();
543 _compute_theta_times_Qx.generate_r1cs_constraints();
544 _compute_lambda_times_Qy.generate_r1cs_constraints();
545 _check_out_Rx.generate_r1cs_constraints();
546 _check_out_Ry.generate_r1cs_constraints();
547 _check_out_Rz.generate_r1cs_constraints();
550 template<typename ppT>
551 void bls12_377_ate_add_gadget<ppT>::generate_r1cs_witness()
553 const FqeT Qx = _Q_X.get_element();
554 const FqeT Qy = _Q_Y.get_element();
555 const FqeT Rx = _in_R.X.get_element();
556 const FqeT Ry = _in_R.Y.get_element();
557 const FqeT Rz = _in_R.Z.get_element();
563 // <=> A = Qy * Rz = ell_vv + Ry
564 const FqeT A = Qy * Rz;
565 const FqeT theta = Ry - A;
566 _out_coeffs.ell_vv.generate_r1cs_witness(-theta);
567 _compute_A.result.evaluate();
568 _compute_A.generate_r1cs_witness();
574 // <=> B = Qx * Rz = Rx - ell_vw
575 const FqeT B = Qx * Rz;
576 const FqeT lambda = Rx - B;
577 _out_coeffs.ell_vw.generate_r1cs_witness(lambda);
578 _compute_B.result.evaluate();
579 _compute_B.generate_r1cs_witness();
580 // C = theta.squared() = ell_vv^2
581 _compute_C.generate_r1cs_witness();
582 // D = lambda.squared() = ell_vw^2
583 _compute_D.generate_r1cs_witness();
584 // E = lambda * D = D * ell_vw;
585 _compute_E.generate_r1cs_witness();
587 _compute_F.generate_r1cs_witness();
589 _compute_G.generate_r1cs_witness();
590 // H = E + F - (G + G);
593 _compute_I.generate_r1cs_witness();
594 // out_coeffs.ell_0 = xi * J
595 // where J = theta * Qx - lambda * Qy
596 // <=> lambda * Qy = theta * Qx - ell_0 * xi^{-1}
597 _compute_theta_times_Qx.A.evaluate();
598 _compute_theta_times_Qx.generate_r1cs_witness();
599 const FqeT theta_times_Qx = _compute_theta_times_Qx.result.get_element();
600 const FqeT lambda_times_Qy = lambda * Qy;
601 _out_coeffs.ell_0.generate_r1cs_witness(
602 libff::bls12_377_twist * (theta_times_Qx - lambda_times_Qy));
603 _compute_lambda_times_Qy.result.evaluate();
604 _compute_lambda_times_Qy.generate_r1cs_witness();
605 // out_Rx = lambda * H = ell_vw * H
606 _check_out_Rx.generate_r1cs_witness();
607 // out_Ry = theta * (G - H) - I = -ell_vv * (G-H) - I
608 // <=> ell_vv * (H-G) = out_Ry + I
609 const FqeT G = _compute_G.result.get_element();
610 const FqeT H = _H.get_element();
611 const FqeT I = _compute_I.result.get_element();
612 _out_R.Y.generate_r1cs_witness(theta * (G - H) - I);
613 _check_out_Ry.B.evaluate();
614 _check_out_Ry.result.evaluate();
615 _check_out_Ry.generate_r1cs_witness();
617 _check_out_Rz.generate_r1cs_witness();
620 // bls12_377_G2_precompute methods
622 template<typename ppT>
623 bls12_377_G2_precompute_gadget<ppT>::bls12_377_G2_precompute_gadget(
624 protoboard<libff::Fr<ppT>> &pb,
625 const G2_variable<ppT> &Q,
626 bls12_377_G2_precomputation<ppT> &Q_prec,
627 const std::string &annotation_prefix)
628 : gadget<libff::Fr<ppT>>(pb, annotation_prefix)
629 , _R0(*Q.X, *Q.Y, Fqe_variable<ppT>(pb, FqeT::one(), "Fqe(1)"))
631 // Track the R variable at each step. Initially it is _R0;
632 const bls12_377_G2_proj<ppT> *currentR = &_R0;
636 std::vector<std::shared_ptr<bls12_377_G2_proj<ppT>>> R;
638 // Iterate through bits of loop_count
639 bls12_377_miller_loop_bits bits;
640 while (bits.next()) {
642 std::shared_ptr<bls12_377_G2_proj<ppT>>(new bls12_377_G2_proj<ppT>(
643 pb, FMT(annotation_prefix, " R%zu", num_Rs++))));
644 Q_prec._coeffs.push_back(std::shared_ptr<bls12_377_ate_ell_coeffs<ppT>>(
645 new bls12_377_ate_ell_coeffs<ppT>(
646 pb, FMT(annotation_prefix, " Q_prec_dbl_%zu", num_dbl++))));
647 _ate_dbls.push_back(std::shared_ptr<bls12_377_ate_dbl_gadget<ppT>>(
648 new bls12_377_ate_dbl_gadget<ppT>(
652 *Q_prec._coeffs.back(),
653 FMT(annotation_prefix, " dbls[%zu]", bits.index()))));
654 currentR = &(*R.back());
656 if (bits.current()) {
657 R.push_back(std::shared_ptr<bls12_377_G2_proj<ppT>>(
658 new bls12_377_G2_proj<ppT>(
659 pb, FMT(annotation_prefix, " R%zu", num_Rs++))));
660 Q_prec._coeffs.push_back(
661 std::shared_ptr<bls12_377_ate_ell_coeffs<ppT>>(
662 new bls12_377_ate_ell_coeffs<ppT>(
664 FMT(annotation_prefix, " Q_prec_add_%zu", num_add++))));
665 _ate_adds.push_back(std::shared_ptr<bls12_377_ate_add_gadget<ppT>>(
666 new bls12_377_ate_add_gadget<ppT>(
672 *Q_prec._coeffs.back(),
673 FMT(annotation_prefix, " adds[%zu]", bits.index()))));
674 currentR = &(*R.back());
679 template<typename ppT>
680 void bls12_377_G2_precompute_gadget<ppT>::generate_r1cs_constraints()
685 // TODO: There should be no need to loop through the bits of loop_count
686 // when generating the constraints (all variables have been allocated, so
687 // the order of generation is not important). For now we do
689 // consistent loop in all methods.
691 bls12_377_miller_loop_bits bits;
692 while (bits.next()) {
693 _ate_dbls[dbl_idx++]->generate_r1cs_constraints();
694 if (bits.current()) {
695 _ate_adds[add_idx++]->generate_r1cs_constraints();
700 template<typename ppT>
701 void bls12_377_G2_precompute_gadget<ppT>::generate_r1cs_witness()
705 bls12_377_miller_loop_bits bits;
706 while (bits.next()) {
707 _ate_dbls[dbl_idx++]->generate_r1cs_witness();
708 if (bits.current()) {
709 _ate_adds[add_idx++]->generate_r1cs_witness();
714 } // namespace libsnark
716 #endif // LIBSNARK_GADGETLIB1_GADGETS_PAIRING_BW6_761_BLS12_377_BLS12_377_PRECOMPUTATION_TCC_