3#include "../bit_array/bit_array.hpp"
4#include "../circuit_builders/circuit_builders.hpp"
8namespace proof_system::plonk::stdlib {
10template <
typename C,
class Fq,
class Fr,
class G>
11element<C, Fq, Fr, G>::element()
16template <
typename C,
class Fq,
class Fr,
class G>
17element<C, Fq, Fr, G>::element(
const typename G::affine_element& input)
22template <
typename C,
class Fq,
class Fr,
class G>
23element<C, Fq, Fr, G>::element(
const Fq& x_in,
const Fq& y_in)
28template <
typename C,
class Fq,
class Fr,
class G>
29element<C, Fq, Fr, G>::element(
const element& other)
34template <
typename C,
class Fq,
class Fr,
class G>
35element<C, Fq, Fr, G>::element(element&& other)
40template <
typename C,
class Fq,
class Fr,
class G>
41element<C, Fq, Fr, G>& element<C, Fq, Fr, G>::operator=(
const element& other)
48template <
typename C,
class Fq,
class Fr,
class G>
49element<C, Fq, Fr, G>& element<C, Fq, Fr, G>::operator=(element&& other)
56template <
typename C,
class Fq,
class Fr,
class G>
57element<C, Fq, Fr, G> element<C, Fq, Fr, G>::operator+(
const element& other)
const
62 std::vector<element> points{ *
this, other };
63 std::vector<Fr> scalars{ 1, 1 };
64 return goblin_batch_mul(points, scalars);
67 other.x.assert_is_not_equal(x);
68 const Fq lambda = Fq::div_without_denominator_check({ other.y, -y }, (other.x - x));
69 const Fq x3 = lambda.sqradd({ -other.x, -x });
70 const Fq y3 = lambda.madd(x - x3, { -y });
71 return element(x3, y3);
74template <
typename C,
class Fq,
class Fr,
class G>
75element<C, Fq, Fr, G> element<C, Fq, Fr, G>::operator-(
const element& other)
const
79 std::vector<element> points{ *
this, other };
80 std::vector<Fr> scalars{ 1, -
Fr(1) };
81 return goblin_batch_mul(points, scalars);
84 other.x.assert_is_not_equal(x);
85 const Fq lambda = Fq::div_without_denominator_check({ other.y, y }, (other.x - x));
86 const Fq x_3 = lambda.sqradd({ -other.x, -x });
87 const Fq y_3 = lambda.madd(x_3 - x, { -y });
89 return element(x_3, y_3);
107template <
typename C,
class Fq,
class Fr,
class G>
111 return { *
this + other, *
this - other };
114 other.x.assert_is_not_equal(x);
116 const Fq denominator = other.x - x;
117 const Fq x2x1 = -(other.x + x);
119 const Fq lambda1 = Fq::div_without_denominator_check({ other.y, -y }, denominator);
120 const Fq x_3 = lambda1.sqradd({ x2x1 });
121 const Fq y_3 = lambda1.madd(x - x_3, { -y });
122 const Fq lambda2 = Fq::div_without_denominator_check({ -other.y, -y }, denominator);
123 const Fq x_4 = lambda2.sqradd({ x2x1 });
124 const Fq y_4 = lambda2.madd(x - x_4, { -y });
133 if constexpr (G::has_a) {
135 Fq neg_lambda = Fq::msub_div({ x }, { (two_x + x) }, (y + y), { a });
136 Fq x_3 = neg_lambda.sqradd({ -(two_x) });
137 Fq y_3 = neg_lambda.madd(x_3 - x, { -y });
138 return element(x_3, y_3);
140 Fq neg_lambda = Fq::msub_div({ x }, { (two_x + x) }, (y + y), {});
141 Fq x_3 = neg_lambda.sqradd({ -(two_x) });
142 Fq y_3 = neg_lambda.madd(x_3 - x, { -y });
143 return element(x_3, y_3);
164template <
typename C,
class Fq,
class Fr,
class G>
170 output.x1_prev = p1.x;
171 output.y1_prev = p1.y;
173 p1.x.assert_is_not_equal(p2.x);
174 const Fq lambda = Fq::div_without_denominator_check({ p2.y, -p1.y }, (p2.x - p1.x));
176 const Fq x3 = lambda.sqradd({ -p2.x, -p1.x });
178 output.lambda_prev = lambda;
182template <
typename C,
class Fq,
class Fr,
class G>
188 if (acc.is_element) {
189 return chain_add_start(p1,
element(acc.x3_prev, acc.y3_prev));
192 p1.x.assert_is_not_equal(acc.x3_prev);
211 auto& x2 = acc.x3_prev;
212 const auto lambda = Fq::msub_div({ acc.lambda_prev }, { (x2 - acc.x1_prev) }, (x2 - p1.x), { acc.y1_prev, p1.y });
213 const auto x3 = lambda.sqradd({ -x2, -p1.x });
217 output.x1_prev = p1.x;
218 output.y1_prev = p1.y;
219 output.lambda_prev = lambda;
227template <
typename C,
class Fq,
class Fr,
class G>
231 if (acc.is_element) {
232 return element(acc.x3_prev, acc.y3_prev);
234 auto& x3 = acc.x3_prev;
235 auto& lambda = acc.lambda_prev;
237 Fq y3 = lambda.madd((acc.x1_prev - x3), { -acc.y1_prev });
281template <
typename C,
class Fq,
class Fr,
class G>
285 other.x.assert_is_not_equal(x);
286 const Fq lambda_1 = Fq::div_without_denominator_check({ other.y - y }, (other.x - x));
288 const Fq x_3 = lambda_1.sqradd({ -other.x, -x });
290 const Fq minus_lambda_2 = lambda_1 + Fq::div_without_denominator_check({ y + y }, (x_3 - x));
292 const Fq x_4 = minus_lambda_2.sqradd({ -x, -x_3 });
294 const Fq y_4 = minus_lambda_2.madd(x_4 - x, { -y });
318template <
typename C,
class Fq,
class Fr,
class G>
322 if (to_add.is_element) {
323 throw_or_abort(
"An accumulator expected");
325 x.assert_is_not_equal(to_add.x3_prev);
335 auto& x2 = to_add.x3_prev;
337 Fq::msub_div({ to_add.lambda_prev }, { (x2 - to_add.x1_prev) }, (x2 - x), { to_add.y1_prev, y });
338 const auto x3 = lambda.sqradd({ -x2, -x });
340 const Fq minus_lambda_2 = lambda + Fq::div_without_denominator_check({ y + y }, (x3 - x));
342 const Fq x4 = minus_lambda_2.sqradd({ -x, -x3 });
344 const Fq y4 = minus_lambda_2.madd(x4 - x, { -y });
362template <
typename C,
class Fq,
class Fr,
class G>
366 const Fq two_x = x + x;
369 if constexpr (G::has_a) {
371 minus_lambda_dbl = Fq::msub_div({ x }, { (two_x + x) }, (y + y), { a });
372 x_1 = minus_lambda_dbl.sqradd({ -(two_x) });
374 minus_lambda_dbl = Fq::msub_div({ x }, { (two_x + x) }, (y + y), {});
375 x_1 = minus_lambda_dbl.sqradd({ -(two_x) });
378 ASSERT(to_add.size() > 0);
379 to_add[0].x.assert_is_not_equal(x_1);
381 const Fq x_minus_x_1 = x - x_1;
383 const Fq lambda_1 = Fq::msub_div({ minus_lambda_dbl }, { x_minus_x_1 }, (x_1 - to_add[0].x), { to_add[0].y, y });
385 const Fq x_3 = lambda_1.sqradd({ -to_add[0].x, -x_1 });
387 const Fq half_minus_lambda_2_minus_lambda_1 =
388 Fq::msub_div({ minus_lambda_dbl }, { x_minus_x_1 }, (x_3 - x_1), { y });
390 const Fq minus_lambda_2_minus_lambda_1 = half_minus_lambda_2_minus_lambda_1 + half_minus_lambda_2_minus_lambda_1;
391 const Fq minus_lambda_2 = minus_lambda_2_minus_lambda_1 + lambda_1;
393 const Fq x_4 = minus_lambda_2.sqradd({ -x_1, -x_3 });
395 const Fq x_4_sub_x_1 = x_4 - x_1;
397 if (to_add.size() == 1) {
398 const Fq y_4 = Fq::dual_madd(minus_lambda_2, x_4_sub_x_1, minus_lambda_dbl, x_minus_x_1, { y });
401 to_add[1].x.assert_is_not_equal(to_add[0].x);
403 Fq minus_lambda_3 = Fq::msub_div(
404 { minus_lambda_dbl, minus_lambda_2 }, { x_minus_x_1, x_4_sub_x_1 }, (x_4 - to_add[1].x), { y, -(to_add[1].y) });
407 const Fq x_5 = minus_lambda_3.sqradd({ -x_4, -to_add[1].x });
409 if (to_add.size() == 2) {
411 const Fq y_5 = minus_lambda_3.madd(x_5 - to_add[1].x, { -to_add[1].y });
416 Fq minus_lambda_prev = minus_lambda_3;
418 for (
size_t i = 2; i < to_add.size(); ++i) {
420 to_add[i].x.assert_is_not_equal(to_add[i - 1].x);
423 const Fq minus_lambda = Fq::msub_div({ minus_lambda_prev },
424 { to_add[i - 1].x - x_prev },
425 (to_add[i].x - x_prev),
426 { to_add[i - 1].y, to_add[i].y });
428 const Fq x_out = minus_lambda.sqradd({ -x_prev, -to_add[i].x });
431 minus_lambda_prev = minus_lambda;
433 const Fq y_out = minus_lambda_prev.madd(x_prev - to_add[to_add.size() - 1].x, { -to_add[to_add.size() - 1].y });
457template <
typename C,
class Fq,
class Fr,
class G>
459 const std::vector<chain_add_accumulator>& add)
const
463 std::vector<Fq> mul_left;
464 std::vector<Fq> mul_right;
466 bool is_negative =
false;
470 composite_y previous_y{ std::vector<Fq>(), std::vector<Fq>(), std::vector<Fq>(),
false };
471 for (
size_t i = 0; i < add.size(); ++i) {
472 previous_x.assert_is_not_equal(add[i].x3_prev);
475 bool negate_add_y = (i > 0) && !previous_y.is_negative;
476 std::vector<Fq> lambda1_left;
477 std::vector<Fq> lambda1_right;
478 std::vector<Fq> lambda1_add;
481 lambda1_add.emplace_back(-y);
483 lambda1_left = previous_y.mul_left;
484 lambda1_right = previous_y.mul_right;
485 lambda1_add = previous_y.add;
488 if (!add[i].is_element) {
489 lambda1_left.emplace_back(add[i].lambda_prev);
490 lambda1_right.emplace_back(negate_add_y ? add[i].x3_prev - add[i].x1_prev
491 : add[i].x1_prev - add[i].x3_prev);
492 lambda1_add.emplace_back(negate_add_y ? add[i].y1_prev : -add[i].y1_prev);
494 lambda1_add.emplace_back(negate_add_y ? -add[i].y3_prev : add[i].y3_prev);
504 if (!add[i].is_element || i > 0) {
505 bool flip_lambda1_denominator = !negate_add_y;
506 Fq denominator = flip_lambda1_denominator ? previous_x - add[i].x3_prev : add[i].x3_prev - previous_x;
507 lambda1 = Fq::msub_div(lambda1_left, lambda1_right, denominator, lambda1_add);
509 lambda1 = Fq::div_without_denominator_check({ add[i].y3_prev - y }, (add[i].x3_prev - x));
512 Fq x_3 = lambda1.madd(lambda1, { -add[i].x3_prev, -previous_x });
520 lambda2 = Fq::div_without_denominator_check({ y + y }, (previous_x - x_3)) - lambda1;
522 Fq l2_denominator = previous_y.is_negative ? previous_x - x_3 : x_3 - previous_x;
524 Fq::msub_div(previous_y.mul_left, previous_y.mul_right, l2_denominator, previous_y.add);
525 partial_lambda2 = partial_lambda2 + partial_lambda2;
526 lambda2 = partial_lambda2 - lambda1;
529 Fq x_4 = lambda2.sqradd({ -x_3, -previous_x });
535 bool num_points_even = ((add.size() & 0x01UL) == 0);
536 y_4.add.emplace_back(num_points_even ? y : -y);
537 y_4.mul_left.emplace_back(lambda2);
538 y_4.mul_right.emplace_back(num_points_even ? x_4 - previous_x : previous_x - x_4);
539 y_4.is_negative = num_points_even;
541 y_4.is_negative = !previous_y.is_negative;
542 y_4.mul_left.emplace_back(lambda2);
543 y_4.mul_right.emplace_back(previous_y.is_negative ? previous_x - x_4 : x_4 - previous_x);
549 std::copy(previous_y.mul_left.begin(), previous_y.mul_left.end(), std::back_inserter(y_4.mul_left));
550 std::copy(previous_y.mul_right.begin(), previous_y.mul_right.end(), std::back_inserter(y_4.mul_right));
551 std::copy(previous_y.add.begin(), previous_y.add.end(), std::back_inserter(y_4.add));
556 Fq x_out = previous_x;
558 ASSERT(!previous_y.is_negative);
560 Fq y_out = Fq::mult_madd(previous_y.mul_left, previous_y.mul_right, previous_y.add);
601template <
typename C,
class Fq,
class Fr,
class G>
602std::pair<element<C, Fq, Fr, G>,
element<C, Fq, Fr, G>>
element<C, Fq, Fr, G>::compute_offset_generators(
603 const size_t num_rounds)
605 constexpr typename G::affine_element offset_generator = G::derive_generators(
"biggroup offset generator", 1)[0];
609 const typename G::affine_element offset_generator_end =
typename G::element(offset_generator) * offset_multiplier;
610 return std::make_pair<element, element>(offset_generator, offset_generator_end);
619template <
typename C,
class Fq,
class Fr,
class G>
621 const std::vector<Fr>& scalars,
622 const size_t max_num_bits)
626 return goblin_batch_mul(points, scalars);
629 const size_t num_points = points.size();
630 ASSERT(scalars.size() == num_points);
631 batch_lookup_table point_table(points);
632 const size_t num_rounds = (max_num_bits == 0) ? Fr::modulus.get_msb() + 1 : max_num_bits;
634 std::vector<std::vector<bool_t<C>>> naf_entries;
635 for (
size_t i = 0; i < num_points; ++i) {
636 naf_entries.emplace_back(compute_naf(scalars[i], max_num_bits));
638 const auto offset_generators = compute_offset_generators(num_rounds);
640 element::chain_add_end(element::chain_add(offset_generators.first, point_table.get_chain_initial_entry()));
642 constexpr size_t num_rounds_per_iteration = 4;
643 size_t num_iterations = num_rounds / num_rounds_per_iteration;
644 num_iterations += ((num_iterations * num_rounds_per_iteration) == num_rounds) ? 0 : 1;
645 const size_t num_rounds_per_final_iteration =
646 (num_rounds - 1) - ((num_iterations - 1) * num_rounds_per_iteration);
647 for (
size_t i = 0; i < num_iterations; ++i) {
649 std::vector<bool_t<C>> nafs(num_points);
650 std::vector<element::chain_add_accumulator> to_add;
651 const size_t inner_num_rounds =
652 (i != num_iterations - 1) ? num_rounds_per_iteration : num_rounds_per_final_iteration;
653 for (
size_t j = 0; j < inner_num_rounds; ++j) {
654 for (
size_t k = 0; k < num_points; ++k) {
655 nafs[k] = (naf_entries[k][i * num_rounds_per_iteration + j + 1]);
657 to_add.emplace_back(point_table.get_chain_add_accumulator(nafs));
661 for (
size_t i = 0; i < num_points; ++i) {
662 element skew = accumulator - points[i];
663 Fq out_x = accumulator.x.conditional_select(skew.x, naf_entries[i][num_rounds]);
664 Fq out_y = accumulator.y.conditional_select(skew.y, naf_entries[i][num_rounds]);
665 accumulator =
element(out_x, out_y);
667 accumulator = accumulator - offset_generators.second;
678template <
typename C,
class Fq,
class Fr,
class G>
706 std::vector<element> points{ *
this };
707 std::vector<Fr> scalars{ scalar };
708 return goblin_batch_mul(points, scalars);
710 constexpr uint64_t num_rounds = Fr::modulus.get_msb() + 1;
712 std::vector<bool_t<C>> naf_entries = compute_naf(scalar);
714 const auto offset_generators = compute_offset_generators(num_rounds);
716 element accumulator = *
this + offset_generators.first;
718 for (
size_t i = 1; i < num_rounds; ++i) {
720 bigfield y_test = y.conditional_negate(predicate);
725 element skew_output = accumulator - (*this);
727 Fq out_x = accumulator.x.conditional_select(skew_output.x, naf_entries[num_rounds]);
728 Fq out_y = accumulator.y.conditional_select(skew_output.y, naf_entries[num_rounds]);
Definition: uint256.hpp:25
Definition: bigfield.hpp:17
Definition: biggroup.hpp:22
element multiple_montgomery_ladder(const std::vector< chain_add_accumulator > &to_add) const
Perform repeated iterations of the montgomery ladder algorithm.
Definition: biggroup_impl.hpp:458
element montgomery_ladder(const element &other) const
Definition: biggroup_impl.hpp:282
Definition: circuit_builders.hpp:15
Definition: biggroup.hpp:17
constexpr_utils defines some helper methods that perform some stl-equivalent operations but in a cons...
Definition: constexpr_utils.hpp:16
Definition: biggroup.hpp:135