15template <
typename Curve>
class MSM {
41 std::span<const AffineElement>
points;
88 const size_t num_rounds = (
NUM_BITS_IN_FIELD + (bits_per_slice - 1)) / bits_per_slice;
92 const size_t num_points,
95 std::vector<uint32_t>& consolidated_indices)
noexcept;
98 std::vector<std::vector<uint32_t>>& msm_scalar_indices)
noexcept;
101 static bool use_affine_trick(
const size_t num_points,
const size_t num_buckets)
noexcept;
106 const size_t round_index,
107 JacobianBucketAccumulators& bucket_data,
109 const size_t bits_per_slice)
noexcept;
112 const size_t round_index,
113 AffineAdditionData& affine_data,
114 BucketAccumulators& bucket_data,
116 const size_t bits_per_slice)
noexcept;
119 std::span<const AffineElement> points,
120 AffineAdditionData& affine_data,
121 BucketAccumulators& bucket_data,
122 size_t num_input_points_processed,
123 size_t num_queued_affine_points)
noexcept;
125 static std::vector<AffineElement>
batch_multi_scalar_mul(std::vector<std::span<const AffineElement>>& points,
127 bool handle_edge_cases =
true) noexcept;
130 bool handle_edge_cases = false) noexcept;
134 auto& buckets = bucket_accumulators.buckets;
136 int starting_index =
static_cast<int>(buckets.size() - 1);
138 bool found_start =
false;
139 while (!found_start && starting_index > 0) {
140 const size_t idx =
static_cast<size_t>(starting_index);
141 if (bucket_accumulators.bucket_exists.get(idx)) {
143 prefix_sum = buckets[idx];
150 return Curve::Group::point_at_infinity;
153 AffineElement offset_generator = Curve::Group::affine_point_at_infinity;
156 offset_generator = gen;
159 offset_generator = gen;
162 for (
int i =
static_cast<int>(starting_index - 1); i > 0; --i) {
163 size_t idx =
static_cast<size_t>(i);
164 BB_ASSERT_LT(idx, bucket_accumulators.bucket_exists.size());
165 if (bucket_accumulators.bucket_exists.get(idx)) {
167 prefix_sum += buckets[idx];
171 return sum - offset_generator;
175template <
typename Curve>
178 bool handle_edge_cases =
true) noexcept;
179template <typename
Curve>
181 std::span<const typename
Curve::AffineElement> points) noexcept;
183extern template class MSM<curve::Grumpkin>;
184extern template class MSM<curve::
BN254>;
#define BB_ASSERT_GT(left, right,...)
#define BB_ASSERT_LT(left, right,...)
Custom class to handle packed vectors of bits.
typename Group::element Element
typename grumpkin::g1 Group
typename Group::affine_element AffineElement
typename Curve::BaseField BaseField
static Element evaluate_small_pippenger_round(MSMData &msm_data, const size_t round_index, JacobianBucketAccumulators &bucket_data, Element previous_round_output, const size_t bits_per_slice) noexcept
Evaluate a single Pippenger round when we do not use the Affine trick.
static Element small_pippenger_low_memory_with_transformed_scalars(MSMData &msm_data) noexcept
Top-level Pippenger algorithm where number of points is small and we are not using the Affine trick.
static Element pippenger_low_memory_with_transformed_scalars(MSMData &msm_data) noexcept
Top-level Pippenger algorithm.
static Element accumulate_buckets(BucketType &bucket_accumulators) noexcept
static size_t get_num_rounds(size_t num_points) noexcept
static uint32_t get_scalar_slice(const ScalarField &scalar, size_t round, size_t normal_slice_size) noexcept
Given a scalar that is NOT in Montgomery form, extract a slice_size-bit chunk.
static bool use_affine_trick(const size_t num_points, const size_t num_buckets) noexcept
Given a number of points and an optimal bucket size, should we use the affine trick?
static void add_affine_points(AffineElement *points, const size_t num_points, typename Curve::BaseField *scratch_space) noexcept
static size_t get_optimal_log_num_buckets(const size_t num_points) noexcept
For a given number of points, compute the optimal Pippenger bucket size.
std::vector< MSMWorkUnit > ThreadWorkUnits
static std::vector< AffineElement > batch_multi_scalar_mul(std::vector< std::span< const AffineElement > > &points, std::vector< std::span< ScalarField > > &scalars, bool handle_edge_cases=true) noexcept
Compute multiple multi-scalar multiplications.
typename Curve::Element Element
static constexpr size_t NUM_BITS_IN_FIELD
static void consume_point_schedule(std::span< const uint64_t > point_schedule, std::span< const AffineElement > points, AffineAdditionData &affine_data, BucketAccumulators &bucket_data, size_t num_input_points_processed, size_t num_queued_affine_points) noexcept
Given a list of points and target buckets to add into, perform required group operations.
static std::vector< ThreadWorkUnits > get_work_units(std::vector< std::span< ScalarField > > &scalars, std::vector< std::vector< uint32_t > > &msm_scalar_indices) noexcept
Split a multiple multi-scalar-multiplication into equal units of work that can be processed by thread...
static Element evaluate_pippenger_round(MSMData &msm_data, const size_t round_index, AffineAdditionData &affine_data, BucketAccumulators &bucket_data, Element previous_round_output, const size_t bits_per_slice) noexcept
Evaluate a single Pippenger round where we use the affine trick.
static void transform_scalar_and_get_nonzero_scalar_indices(std::span< typename Curve::ScalarField > scalars, std::vector< uint32_t > &consolidated_indices) noexcept
Convert scalar out of Montgomery form. Populate consolidated_indices with nonzero scalar indices.
typename Curve::ScalarField ScalarField
static AffineElement msm(std::span< const AffineElement > points, PolynomialSpan< const ScalarField > _scalars, bool handle_edge_cases=false) noexcept
Helper method to evaluate a single MSM. Internally calls batch_multi_scalar_mul
typename Curve::AffineElement AffineElement
Curve::Element pippenger(PolynomialSpan< const typename Curve::ScalarField > scalars, std::span< const typename Curve::AffineElement > points, bool handle_edge_cases) noexcept
Curve::Element pippenger_unsafe(PolynomialSpan< const typename Curve::ScalarField > scalars, std::span< const typename Curve::AffineElement > points) noexcept
Inner sum(Cont< Inner, Args... > const &in)
constexpr std::span< const typename Group::affine_element > get_precomputed_generators()
constexpr decltype(auto) get(::tuplet::tuple< T... > &&t) noexcept
Temp data structure, one created per thread!
std::vector< uint64_t > addition_result_bucket_destinations
std::vector< AffineElement > points_to_add
std::vector< BaseField > scalar_scratch_space
AffineAdditionData() noexcept
static constexpr size_t BATCH_OVERFLOW_SIZE
static constexpr size_t BATCH_SIZE
Temp data structure, one created per thread!
BucketAccumulators(size_t num_buckets) noexcept
std::vector< AffineElement > buckets
std::vector< Element > buckets
JacobianBucketAccumulators(size_t num_buckets) noexcept
std::span< uint64_t > point_schedule
std::span< const ScalarField > scalars
std::span< const AffineElement > points
std::span< const uint32_t > scalar_indices
MSMWorkUnit describes an MSM that may be part of a larger MSM.