Barretenberg
The ZK-SNARK library at the core of Aztec
Loading...
Searching...
No Matches
scalar_multiplication.hpp
Go to the documentation of this file.
1// === AUDIT STATUS ===
2// internal: { status: Planned, auditors: [Sergei], commit: }
3// external_1: { status: not started, auditors: [], commit: }
4// external_2: { status: not started, auditors: [], commit: }
5// =====================
6
7#pragma once
10
14
15#include "./process_buckets.hpp"
17
18#include "./bitvector.hpp"
20
21template <typename Curve> class MSM {
22 public:
23 using Element = typename Curve::Element;
25 using BaseField = typename Curve::BaseField;
27
29 static constexpr size_t NUM_BITS_IN_FIELD = ScalarField::modulus.get_msb() + 1;
30
38 struct MSMWorkUnit {
39 size_t batch_msm_index = 0;
40 size_t start_index = 0;
41 size_t size = 0;
42 };
44
45 struct MSMData {
46 std::span<const ScalarField> scalars;
47 std::span<const AffineElement> points;
48 std::span<const uint32_t> scalar_indices;
49 std::span<uint64_t> point_schedule;
50 };
51
56 std::vector<AffineElement> buckets;
58
59 BucketAccumulators(size_t num_buckets) noexcept
60 : buckets(num_buckets)
61 , bucket_exists(num_buckets)
62 {}
63 };
64
66 std::vector<Element> buckets;
68
69 JacobianBucketAccumulators(size_t num_buckets) noexcept
70 : buckets(num_buckets)
71 , bucket_exists(num_buckets)
72 {}
73 };
78 static constexpr size_t BATCH_SIZE = 2048;
79 // when adding affine points, we have an edge case where the number of points in the batch can overflow by 2
80 static constexpr size_t BATCH_OVERFLOW_SIZE = 2;
81 std::vector<AffineElement> points_to_add;
82 std::vector<BaseField> scalar_scratch_space;
84
90 };
91 static size_t get_num_rounds(size_t num_points) noexcept
92 {
93 const size_t bits_per_slice = get_optimal_log_num_buckets(num_points);
94 const size_t num_rounds = (NUM_BITS_IN_FIELD + (bits_per_slice - 1)) / bits_per_slice;
95 return num_rounds;
96 }
97 static void add_affine_points(AffineElement* points,
98 const size_t num_points,
99 typename Curve::BaseField* scratch_space) noexcept;
101 std::vector<uint32_t>& consolidated_indices) noexcept;
102
104 std::vector<std::vector<uint32_t>>& msm_scalar_indices) noexcept;
105 static uint32_t get_scalar_slice(const ScalarField& scalar, size_t round, size_t normal_slice_size) noexcept;
106 static size_t get_optimal_log_num_buckets(const size_t num_points) noexcept;
107 static bool use_affine_trick(const size_t num_points, const size_t num_buckets) noexcept;
108
109 static Element small_pippenger_low_memory_with_transformed_scalars(MSMData& msm_data) noexcept;
110 static Element pippenger_low_memory_with_transformed_scalars(MSMData& msm_data) noexcept;
111 static Element evaluate_small_pippenger_round(MSMData& msm_data,
112 const size_t round_index,
113 JacobianBucketAccumulators& bucket_data,
114 Element previous_round_output,
115 const size_t bits_per_slice) noexcept;
116
117 static Element evaluate_pippenger_round(MSMData& msm_data,
118 const size_t round_index,
119 AffineAdditionData& affine_data,
120 BucketAccumulators& bucket_data,
121 Element previous_round_output,
122 const size_t bits_per_slice) noexcept;
123
124 static void consume_point_schedule(std::span<const uint64_t> point_schedule,
125 std::span<const AffineElement> points,
126 AffineAdditionData& affine_data,
127 BucketAccumulators& bucket_data,
128 size_t num_input_points_processed,
129 size_t num_queued_affine_points) noexcept;
130
131 static std::vector<AffineElement> batch_multi_scalar_mul(std::span<std::span<const AffineElement>> points,
132 std::span<std::span<ScalarField>> scalars,
133 bool handle_edge_cases = true) noexcept;
134 static AffineElement msm(std::span<const AffineElement> points,
135 PolynomialSpan<const ScalarField> _scalars,
136 bool handle_edge_cases = false) noexcept;
137
138 template <typename BucketType> static Element accumulate_buckets(BucketType& bucket_accumulators) noexcept
139 {
140 auto& buckets = bucket_accumulators.buckets;
141 BB_ASSERT_DEBUG(buckets.size() > static_cast<size_t>(0));
142 int starting_index = static_cast<int>(buckets.size() - 1);
143 Element prefix_sum;
144 bool found_start = false;
145 while (!found_start && starting_index > 0) {
146 const size_t idx = static_cast<size_t>(starting_index);
147 if (bucket_accumulators.bucket_exists.get(idx)) {
148
149 prefix_sum = buckets[idx];
150 found_start = true;
151 } else {
152 starting_index -= 1;
153 }
154 }
155 if (!found_start) {
156 return Curve::Group::point_at_infinity;
157 }
158 BB_ASSERT_DEBUG(starting_index > 0);
159 AffineElement offset_generator = Curve::Group::affine_point_at_infinity;
161 constexpr auto gen = get_precomputed_generators<typename Curve::Group, "ECCVM_OFFSET_GENERATOR", 1>()[0];
162 offset_generator = gen;
163 } else {
164 constexpr auto gen = get_precomputed_generators<typename Curve::Group, "DEFAULT_DOMAIN_SEPARATOR", 8>()[0];
165 offset_generator = gen;
166 }
167 Element sum = prefix_sum + offset_generator;
168 for (int i = static_cast<int>(starting_index - 1); i > 0; --i) {
169 size_t idx = static_cast<size_t>(i);
170 BB_ASSERT_DEBUG(idx < bucket_accumulators.bucket_exists.size());
171 if (bucket_accumulators.bucket_exists.get(idx)) {
172
173 prefix_sum += buckets[idx];
174 }
175 sum += prefix_sum;
176 }
177 return sum - offset_generator;
178 }
179};
180
181template <typename Curve>
184 bool handle_edge_cases = true) noexcept;
185template <typename Curve>
186typename Curve::Element pippenger_unsafe(PolynomialSpan<const typename Curve::ScalarField> scalars,
187 std::span<const typename Curve::AffineElement> points) noexcept;
188
189extern template class MSM<curve::Grumpkin>;
190extern template class MSM<curve::BN254>;
191
192// NEXT STEP ACCUMULATE BUVKETS
193} // namespace bb::scalar_multiplication
#define BB_ASSERT_DEBUG(expression,...)
Definition assert.hpp:55
Custom class to handle packed vectors of bits.
Definition bitvector.hpp:21
typename Group::element Element
Definition grumpkin.hpp:62
typename grumpkin::g1 Group
Definition grumpkin.hpp:61
typename Group::affine_element AffineElement
Definition grumpkin.hpp:63
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< ThreadWorkUnits > get_work_units(std::span< 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 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< AffineElement > batch_multi_scalar_mul(std::span< std::span< const AffineElement > > points, std::span< std::span< ScalarField > > scalars, bool handle_edge_cases=true) noexcept
Compute multiple multi-scalar multiplications.
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)
Definition container.hpp:70
constexpr std::span< const typename Group::affine_element > get_precomputed_generators()
@ BN254
Definition types.hpp:10
STL namespace.
constexpr decltype(auto) get(::tuplet::tuple< T... > &&t) noexcept
Definition tuple.hpp:13
Curve::Element Element
Temp data structure, one created per thread!
Temp data structure, one created per thread!
std::span< const AffineElement > points
MSMWorkUnit describes an MSM that may be part of a larger MSM.