93 const bool_ct x_coordinates_match = other.
x == x;
94 const bool_ct y_coordinates_match = (y == other.
y);
95 const bool_ct infinity_predicate = (x_coordinates_match && !y_coordinates_match);
96 const bool_ct double_predicate = (x_coordinates_match && y_coordinates_match);
97 const bool_ct lhs_infinity = is_point_at_infinity();
99 const bool_ct has_infinity_input = lhs_infinity || rhs_infinity;
102 const Fq add_lambda_numerator = other.
y - y;
104 const Fq dbl_lambda_numerator = xx + xx + xx;
105 const Fq lambda_numerator = Fq::conditional_assign(double_predicate, dbl_lambda_numerator, add_lambda_numerator);
107 const Fq add_lambda_denominator = other.
x - x;
108 const Fq dbl_lambda_denominator = y + y;
109 Fq lambda_denominator = Fq::conditional_assign(double_predicate, dbl_lambda_denominator, add_lambda_denominator);
113 Fq safe_edgecase_denominator =
Fq(1);
115 Fq::conditional_assign(has_infinity_input || infinity_predicate, safe_edgecase_denominator, lambda_denominator);
116 const Fq lambda = Fq::div_without_denominator_check({ lambda_numerator }, lambda_denominator);
118 const Fq x3 = lambda.sqradd({ -other.
x, -x });
119 const Fq y3 = lambda.madd(x - x3, { -y });
123 result.
x = Fq::conditional_assign(lhs_infinity, other.
x, result.
x);
124 result.
y = Fq::conditional_assign(lhs_infinity, other.
y, result.
y);
126 result.
x = Fq::conditional_assign(rhs_infinity, x, result.
x);
127 result.
y = Fq::conditional_assign(rhs_infinity, y, result.
y);
133 bool_ct result_is_infinity = (infinity_predicate && !has_infinity_input) || (lhs_infinity && rhs_infinity);
165 const bool_ct x_coordinates_match = other.
x == x;
166 const bool_ct y_coordinates_match = (y == other.
y);
167 const bool_ct infinity_predicate = (x_coordinates_match && y_coordinates_match);
168 const bool_ct double_predicate = (x_coordinates_match && !y_coordinates_match);
169 const bool_ct lhs_infinity = is_point_at_infinity();
171 const bool_ct has_infinity_input = lhs_infinity || rhs_infinity;
174 const Fq add_lambda_numerator = -other.
y - y;
176 const Fq dbl_lambda_numerator = xx + xx + xx;
177 const Fq lambda_numerator = Fq::conditional_assign(double_predicate, dbl_lambda_numerator, add_lambda_numerator);
179 const Fq add_lambda_denominator = other.
x - x;
180 const Fq dbl_lambda_denominator = y + y;
181 Fq lambda_denominator = Fq::conditional_assign(double_predicate, dbl_lambda_denominator, add_lambda_denominator);
185 Fq safe_edgecase_denominator =
Fq(1);
187 Fq::conditional_assign(has_infinity_input || infinity_predicate, safe_edgecase_denominator, lambda_denominator);
188 const Fq lambda = Fq::div_without_denominator_check({ lambda_numerator }, lambda_denominator);
190 const Fq x3 = lambda.sqradd({ -other.
x, -x });
191 const Fq y3 = lambda.madd(x - x3, { -y });
195 result.
x = Fq::conditional_assign(lhs_infinity, other.
x, result.
x);
196 result.
y = Fq::conditional_assign(lhs_infinity, -other.
y, result.
y);
198 result.
x = Fq::conditional_assign(rhs_infinity, x, result.
x);
199 result.
y = Fq::conditional_assign(rhs_infinity, y, result.
y);
205 bool_ct result_is_infinity = (infinity_predicate && !has_infinity_input) || (lhs_infinity && rhs_infinity);
255 other.
x.assert_is_not_equal(x);
257 const Fq denominator = other.
x - x;
258 const Fq x2x1 = -(other.
x + x);
260 const Fq lambda1 = Fq::div_without_denominator_check({ other.
y, -y }, denominator);
261 const Fq x_3 = lambda1.sqradd({ x2x1 });
262 const Fq y_3 = lambda1.madd(x - x_3, { -y });
263 const Fq lambda2 = Fq::div_without_denominator_check({ -other.
y, -y }, denominator);
264 const Fq x_4 = lambda2.sqradd({ x2x1 });
265 const Fq y_4 = lambda2.madd(x - x_4, { -y });
274 if constexpr (G::has_a) {
276 Fq neg_lambda = Fq::msub_div({ x }, { (two_x + x) }, (y + y), {
a },
false);
277 Fq x_3 = neg_lambda.sqradd({ -(two_x) });
278 Fq y_3 = neg_lambda.madd(x_3 - x, { -y });
283 Fq neg_lambda = Fq::msub_div({ x }, { (two_x + x) }, (y + y), {},
false);
284 Fq x_3 = neg_lambda.sqradd({ -(two_x) });
285 Fq y_3 = neg_lambda.madd(x_3 - x, { -y });
431 other.
x.assert_is_not_equal(x);
432 const Fq lambda_1 = Fq::div_without_denominator_check({ other.
y - y }, (other.
x - x));
434 const Fq x_3 = lambda_1.sqradd({ -other.
x, -x });
436 const Fq minus_lambda_2 = lambda_1 + Fq::div_without_denominator_check({ y + y }, (x_3 - x));
438 const Fq x_4 = minus_lambda_2.sqradd({ -x, -x_3 });
440 const Fq y_4 = minus_lambda_2.madd(x_4 - x, { -y });
470 x.assert_is_not_equal(to_add.
x3_prev);
481 const auto lambda = Fq::msub_div({ to_add.
lambda_prev },
486 const auto x3 = lambda.sqradd({ -x2, -x });
488 const Fq minus_lambda_2 = lambda + Fq::div_without_denominator_check({ y + y }, (x3 - x));
490 const Fq x4 = minus_lambda_2.sqradd({ -x, -x3 });
492 const Fq y4 = minus_lambda_2.madd(x4 - x, { -y });
513 const Fq two_x = x + x;
516 if constexpr (G::has_a) {
518 minus_lambda_dbl = Fq::msub_div({ x }, { (two_x + x) }, (y + y), {
a },
false);
519 x_1 = minus_lambda_dbl.sqradd({ -(two_x) });
522 minus_lambda_dbl = Fq::msub_div({ x }, { (two_x + x) }, (y + y), {},
false);
523 x_1 = minus_lambda_dbl.sqradd({ -(two_x) });
527 to_add[0].x.assert_is_not_equal(x_1);
529 const Fq x_minus_x_1 = x - x_1;
532 Fq::msub_div({ minus_lambda_dbl },
538 const Fq x_3 = lambda_1.sqradd({ -to_add[0].x, -x_1 });
541 const Fq half_minus_lambda_2_minus_lambda_1 =
542 Fq::msub_div({ minus_lambda_dbl },
548 const Fq minus_lambda_2_minus_lambda_1 = half_minus_lambda_2_minus_lambda_1 + half_minus_lambda_2_minus_lambda_1;
549 const Fq minus_lambda_2 = minus_lambda_2_minus_lambda_1 + lambda_1;
551 const Fq x_4 = minus_lambda_2.sqradd({ -x_1, -x_3 });
553 const Fq x_4_sub_x_1 = x_4 - x_1;
555 if (to_add.size() == 1) {
556 const Fq y_4 = Fq::dual_madd(minus_lambda_2, x_4_sub_x_1, minus_lambda_dbl, x_minus_x_1, { y });
559 to_add[1].x.assert_is_not_equal(to_add[0].x);
562 Fq minus_lambda_3 = Fq::msub_div({ minus_lambda_dbl, minus_lambda_2 },
563 { x_minus_x_1, x_4_sub_x_1 },
565 { y, -(to_add[1].y) },
569 const Fq x_5 = minus_lambda_3.sqradd({ -x_4, -to_add[1].x });
571 if (to_add.size() == 2) {
573 const Fq y_5 = minus_lambda_3.madd(x_5 - to_add[1].x, { -to_add[1].y });
578 Fq minus_lambda_prev = minus_lambda_3;
580 for (
size_t i = 2; i < to_add.size(); ++i) {
582 to_add[i].x.assert_is_not_equal(to_add[i - 1].x);
585 const Fq minus_lambda =
586 Fq::msub_div({ minus_lambda_prev },
587 { to_add[i - 1].x - x_prev },
588 (to_add[i].x - x_prev),
589 { to_add[i - 1].y, to_add[i].y },
593 const Fq x_out = minus_lambda.sqradd({ -x_prev, -to_add[i].x });
596 minus_lambda_prev = minus_lambda;
598 const Fq y_out = minus_lambda_prev.madd(x_prev - to_add[to_add.size() - 1].x, { -to_add[to_add.size() - 1].y });
630 bool is_negative =
false;
635 for (
size_t i = 0; i < add.size(); ++i) {
636 previous_x.assert_is_not_equal(add[i].x3_prev);
639 bool negate_add_y = (i > 0) && !previous_y.is_negative;
645 lambda1_add.emplace_back(-y);
647 lambda1_left = previous_y.mul_left;
648 lambda1_right = previous_y.mul_right;
649 lambda1_add = previous_y.add;
652 if (!add[i].is_element) {
653 lambda1_left.emplace_back(add[i].lambda_prev);
654 lambda1_right.emplace_back(negate_add_y ? add[i].x3_prev - add[i].x1_prev
655 : add[i].x1_prev - add[i].x3_prev);
656 lambda1_add.emplace_back(negate_add_y ? add[i].y1_prev : -add[i].y1_prev);
658 lambda1_add.emplace_back(negate_add_y ? -add[i].y3_prev : add[i].y3_prev);
668 if (!add[i].is_element || i > 0) {
669 bool flip_lambda1_denominator = !negate_add_y;
670 Fq denominator = flip_lambda1_denominator ? previous_x - add[i].x3_prev : add[i].x3_prev - previous_x;
671 lambda1 = Fq::msub_div(
678 lambda1 = Fq::div_without_denominator_check({ add[i].y3_prev - y }, (add[i].x3_prev - x));
681 Fq x_3 = lambda1.madd(lambda1, { -add[i].x3_prev, -previous_x });
690 lambda2 = Fq::div_without_denominator_check({ y + y }, (previous_x - x_3)) - lambda1;
692 Fq l2_denominator = previous_y.is_negative ? previous_x - x_3 : x_3 - previous_x;
694 Fq partial_lambda2 = Fq::msub_div(previous_y.mul_left,
695 previous_y.mul_right,
699 partial_lambda2 = partial_lambda2 + partial_lambda2;
700 lambda2 = partial_lambda2 - lambda1;
703 Fq x_4 = lambda2.sqradd({ -x_3, -previous_x });
709 bool num_points_even = ((add.size() & 0x01UL) == 0);
710 y_4.add.emplace_back(num_points_even ? y : -y);
711 y_4.mul_left.emplace_back(lambda2);
712 y_4.mul_right.emplace_back(num_points_even ? x_4 - previous_x : previous_x - x_4);
713 y_4.is_negative = num_points_even;
715 y_4.is_negative = !previous_y.is_negative;
716 y_4.mul_left.emplace_back(lambda2);
717 y_4.mul_right.emplace_back(previous_y.is_negative ? previous_x - x_4 : x_4 - previous_x);
731 Fq x_out = previous_x;
733 ASSERT(!previous_y.is_negative);
735 Fq y_out = Fq::mult_madd(previous_y.mul_left, previous_y.mul_right, previous_y.add);
807 const std::vector<Fr>& _scalars,
808 const size_t max_num_bits,
809 const bool with_edgecases)
811 auto [points, scalars] = handle_points_at_infinity(_points, _scalars);
815 for (
size_t i = 0; i < _points.size(); i++) {
816 tag =
OriginTag(tag,
OriginTag(_points[i].get_origin_tag(), _scalars[i].get_origin_tag()));
818 for (
size_t i = 0; i < scalars.size(); i++) {
825 points[i].set_origin_tag(empty_tag);
826 scalars[i].set_origin_tag(empty_tag);
830 if (with_edgecases) {
831 std::tie(points, scalars) = mask_points(points, scalars);
833 const size_t num_points = points.size();
837 const size_t num_rounds = (max_num_bits == 0) ?
Fr::modulus.
get_msb() + 1 : max_num_bits;
840 for (
size_t i = 0; i < num_points; ++i) {
841 naf_entries.emplace_back(compute_naf(scalars[i], max_num_bits));
843 const auto offset_generators = compute_offset_generators(num_rounds);
847 constexpr size_t num_rounds_per_iteration = 4;
848 size_t num_iterations = num_rounds / num_rounds_per_iteration;
849 num_iterations += ((num_iterations * num_rounds_per_iteration) == num_rounds) ? 0 : 1;
850 const size_t num_rounds_per_final_iteration = (num_rounds - 1) - ((num_iterations - 1) * num_rounds_per_iteration);
851 for (
size_t i = 0; i < num_iterations; ++i) {
855 const size_t inner_num_rounds =
856 (i != num_iterations - 1) ? num_rounds_per_iteration : num_rounds_per_final_iteration;
857 for (
size_t j = 0; j < inner_num_rounds; ++j) {
858 for (
size_t k = 0; k < num_points; ++k) {
859 nafs[k] = (naf_entries[k][i * num_rounds_per_iteration + j + 1]);
865 for (
size_t i = 0; i < num_points; ++i) {
866 element skew = accumulator - points[i];
867 Fq out_x = accumulator.
x.conditional_select(skew.
x, naf_entries[i][num_rounds]);
868 Fq out_y = accumulator.
y.conditional_select(skew.
y, naf_entries[i][num_rounds]);
869 accumulator =
element(out_x, out_y);
871 accumulator = accumulator - offset_generators.second;
924 bool_ct is_point_at_infinity = this->is_point_at_infinity();
926 const size_t num_rounds = (max_num_bits == 0) ?
Fr::modulus.
get_msb() + 1 : max_num_bits;
929 if (max_num_bits != 0) {
931 result = element::bn254_endo_batch_mul({}, {}, { *
this }, { scalar }, num_rounds);
934 result = element::bn254_endo_batch_mul({ *
this }, { scalar }, {}, {}, num_rounds);
938 result.
x = Fq::conditional_assign(is_point_at_infinity, x, result.
x);
939 result.
y = Fq::conditional_assign(is_point_at_infinity, y, result.
y);