39 const std::vector<Fr>& scalars,
40 [[maybe_unused]]
const size_t max_num_bits,
41 [[maybe_unused]]
const bool handle_edge_cases)
46 ASSERT(
builder->op_queue->get_accumulator().is_point_at_infinity());
49 size_t num_points = points.size();
52 for (
size_t i = 0; i < num_points; ++i) {
53 auto& point = points[i];
54 auto& scalar = scalars[i];
58 tag_union =
OriginTag(tag_union,
OriginTag(point.get_origin_tag(), scalar.get_origin_tag()));
61 bool scalar_is_constant_equal_one = scalar.get_witness_index() == IS_CONSTANT && scalar.get_value() == 1;
62 if (scalar_is_constant_equal_one) {
63 op_tuple =
builder->queue_ecc_add_accum(point.get_value());
65 op_tuple =
builder->queue_ecc_mul_accum(point.get_value(), scalar.get_value());
71 auto x_lo = Fr::from_witness_index(
builder, op_tuple.
x_lo);
72 auto x_hi = Fr::from_witness_index(
builder, op_tuple.
x_hi);
73 auto y_lo = Fr::from_witness_index(
builder, op_tuple.
y_lo);
74 auto y_hi = Fr::from_witness_index(
builder, op_tuple.
y_hi);
80 x_lo.assert_equal(point.x.limbs[0]);
81 x_hi.assert_equal(point.x.limbs[1]);
82 y_lo.assert_equal(point.y.limbs[0]);
83 y_hi.assert_equal(point.y.limbs[1]);
86 if (!scalar_is_constant_equal_one) {
87 auto z_1 = Fr::from_witness_index(
builder, op_tuple.
z_1);
88 auto z_2 = Fr::from_witness_index(
builder, op_tuple.
z_2);
90 scalar.assert_equal(z_1 - z_2 * beta);
95 auto op_tuple =
builder->queue_ecc_eq();
98 auto x_lo = Fr::from_witness_index(
builder, op_tuple.x_lo);
99 auto x_hi = Fr::from_witness_index(
builder, op_tuple.x_hi);
100 auto y_lo = Fr::from_witness_index(
builder, op_tuple.y_lo);
101 auto y_hi = Fr::from_witness_index(
builder, op_tuple.y_hi);
102 Fq point_x(x_lo, x_hi);
103 Fq point_y(y_lo, y_hi);
110 auto op2_is_infinity = (x_lo.add_two(x_hi, y_lo) + y_hi).is_zero();
static goblin_element batch_mul(const std::vector< goblin_element > &points, const std::vector< Fr > &scalars, const size_t max_num_bits=0, const bool handle_edge_cases=false)
Goblin style batch multiplication.