Barretenberg
The ZK-SNARK library at the core of Aztec
Loading...
Searching...
No Matches
scalar_multiplication_fast.hpp
Go to the documentation of this file.
1#pragma once
2
7#include <string>
8
9#include <atomic>
10#include <cstddef>
11#include <cstdint>
12#include <span>
13#include <vector>
14
16
21size_t window_bits_tuning_oversub_factor(size_t n_input);
22
54// `external_glv_doubled`: optional caller-supplied [P, φP, ...] interleaved buffer
55// (length 2*n). When non-empty, every n_input is treated as GLV-eligible and the
56// doubled points are aliased instead of recomputed — the batched driver uses this
57// to share the doubled SRS prefix across MSMs in a batch.
58// `external_arena`: optional caller-supplied scratch buffer ≥ this MSM_fast's required
59// bytes. When empty, allocated per-MSM_fast and freed at return. The batched driver
60// supplies a single arena sized to the largest member.
61// `dedup_info`: MSM dedup pre-pass hint — 0 = off, 1 = hinted (no estimate), >=2 = a caller-measured
62// duplicate count used to discount the window-selection point count.
63template <typename Curve>
65 PolynomialSpan<const typename Curve::ScalarField> scalars,
67 size_t dedup_info = 0,
68 std::span<const typename Curve::AffineElement> external_glv_doubled = {},
69 std::span<std::byte> external_arena = {},
70 size_t max_threads = 0) noexcept;
71
73 PolynomialSpan<const curve::BN254::ScalarField> scalars,
75 size_t dedup_info,
77 std::span<std::byte> external_arena,
78 size_t max_threads) noexcept;
79
81 PolynomialSpan<const curve::Grumpkin::ScalarField> scalars,
83 size_t dedup_info,
85 std::span<std::byte> external_arena,
86 size_t max_threads) noexcept;
87
88// ===================================================================================
89// Public API (interface-compatible with the legacy `scalar_multiplication::MSM_fast` class).
90// ===================================================================================
91//
92// `pippenger_fast` — handle_edge_cases routed: false → fast affine round-parallel,
93// true → Jacobian fast path (handles point-at-infinity / equal-x
94// bucket collisions).
95// `pippenger_unsafe_fast` — always the fast path; caller asserts linear-independence of points.
96// `MSM_fast<Curve>::msm` — single-MSM_fast convenience wrapper (returns AffineElement).
97// `MSM_fast<Curve>::batch_multi_scalar_mul` — multi-MSM_fast driver: runs each MSM_fast via `pippenger_fast`
98// and returns a vector of AffineElement results.
99
100template <typename Curve>
101typename Curve::Element pippenger_fast(PolynomialSpan<const typename Curve::ScalarField> scalars,
103 bool handle_edge_cases = true,
104 size_t dedup_info = 0) noexcept;
105
106template <typename Curve>
107typename Curve::Element pippenger_unsafe_fast(PolynomialSpan<const typename Curve::ScalarField> scalars,
108 std::span<const typename Curve::AffineElement> points,
109 size_t dedup_info = 0) noexcept;
110
111extern template curve::BN254::Element pippenger_fast<curve::BN254>(
112 PolynomialSpan<const curve::BN254::ScalarField> scalars,
113 std::span<const curve::BN254::AffineElement> points,
114 bool handle_edge_cases,
115 size_t dedup_info) noexcept;
116
117extern template curve::Grumpkin::Element pippenger_fast<curve::Grumpkin>(
118 PolynomialSpan<const curve::Grumpkin::ScalarField> scalars,
119 std::span<const curve::Grumpkin::AffineElement> points,
120 bool handle_edge_cases,
121 size_t dedup_info) noexcept;
122
123extern template curve::BN254::Element pippenger_unsafe_fast<curve::BN254>(
124 PolynomialSpan<const curve::BN254::ScalarField> scalars,
125 std::span<const curve::BN254::AffineElement> points,
126 size_t dedup_info) noexcept;
127
128extern template curve::Grumpkin::Element pippenger_unsafe_fast<curve::Grumpkin>(
129 PolynomialSpan<const curve::Grumpkin::ScalarField> scalars,
130 std::span<const curve::Grumpkin::AffineElement> points,
131 size_t dedup_info) noexcept;
132
133template <typename Curve> class MSM_fast {
134 public:
135 using Element = typename Curve::Element;
138
145 static AffineElement msm(std::span<const AffineElement> points,
147 bool handle_edge_cases = false,
148 size_t dedup_info = 0) noexcept;
149
170 static std::vector<AffineElement> batch_multi_scalar_mul(std::span<const AffineElement> points,
171 std::span<PolynomialSpan<ScalarField>> scalars,
172 bool handle_edge_cases = true,
173 std::span<const uint32_t> dedup_infos = {}) noexcept;
174};
175
176extern template class MSM_fast<curve::Grumpkin>;
177extern template class MSM_fast<curve::BN254>;
178
179// `pippenger_round_parallel` falls back to `trivial_msm_threaded` when each worker
180// would receive fewer than this many points (after the n_active filter). Exposed so tests
181// and bench targets can pin behaviour at the boundary.
182inline constexpr size_t MIN_PTS_PER_THREAD_FOR_PIPPENGER = 24;
183
184// Points-per-worker floor below which intra-MSM multithreading loses to its parallel_for barrier
185// overhead. Drives both the worker-count pick in pippenger_round_parallel and the batch driver's
186// concurrent/sequential split. SIZE_MAX forces single-threaded on wasm.
187#ifdef __wasm__
188inline constexpr size_t MSM_MIN_PTS_PER_THREAD = SIZE_MAX;
189#else
190inline constexpr size_t MSM_MIN_PTS_PER_THREAD = 256;
191#endif
192
193// Point-count bound for the batch driver's concurrent/sequential split on wasm. Intra-MSM work is
194// always single-threaded on wasm (MSM_MIN_PTS_PER_THREAD == SIZE_MAX), so the native split rule
195// `n < MSM_MIN_PTS_PER_THREAD * pool_width` would classify every member as small and route them all
196// through the concurrent pool, whose per-worker arena is sized to the largest member and caps the
197// worker count by memory budget. This finite bound keeps large members on the sequential shared-arena
198// path so the concurrent pool retains full worker width. Members at or below it dispatch one-per-worker.
199inline constexpr size_t SMALL_MSM_BATCH_THRESHOLD = size_t{ 1 } << 13;
200
201// Per-MSM_fast arena sizer. Returns 0 for shapes that fall back to the Jacobian-fast path
202// (no affine arena). Mirrors the inline budget calc inside `pippenger_round_parallel`;
203// declared here so the test suite can exercise the same sizer.
204template <typename Curve>
205size_t compute_arena_bytes_for_msm(size_t n_input,
206 bool external_glv_provided,
207 bool dedup_active = false,
208 size_t max_threads = 0) noexcept;
209
210namespace round_parallel_detail {
211
212// Above this N, GLV's 2x point-count cost outweighs the windows-halved benefit.
213#ifdef __wasm__
214inline constexpr size_t GLV_SMALL_N_THRESHOLD = size_t{ 1 } << 16;
215#else
216inline constexpr size_t GLV_SMALL_N_THRESHOLD = size_t{ 1 } << 13;
217#endif
218
227template <typename Curve>
228typename Curve::Element pippenger_round_parallel_jacobian_fast(std::span<const typename Curve::ScalarField> scalars,
230 size_t min_pts_per_thread_override = 0,
231 size_t max_threads = 0) noexcept;
232
233extern template curve::BN254::Element pippenger_round_parallel_jacobian_fast<curve::BN254>(
234 std::span<const curve::BN254::ScalarField> scalars,
235 std::span<const curve::BN254::AffineElement> points,
236 size_t min_pts_per_thread_override,
237 size_t max_threads) noexcept;
238
239extern template curve::Grumpkin::Element pippenger_round_parallel_jacobian_fast<curve::Grumpkin>(
240 std::span<const curve::Grumpkin::ScalarField> scalars,
241 std::span<const curve::Grumpkin::AffineElement> points,
242 size_t min_pts_per_thread_override,
243 size_t max_threads) noexcept;
244
245} // namespace round_parallel_detail
246
250template <typename Curve>
251typename Curve::Element trivial_msm(PolynomialSpan<const typename Curve::ScalarField> scalars_span,
252 std::span<const typename Curve::AffineElement> all_points) noexcept;
253
254extern template curve::BN254::Element trivial_msm<curve::BN254>(
255 PolynomialSpan<const curve::BN254::ScalarField> scalars_span,
256 std::span<const curve::BN254::AffineElement> all_points) noexcept;
257
258extern template curve::Grumpkin::Element trivial_msm<curve::Grumpkin>(
259 PolynomialSpan<const curve::Grumpkin::ScalarField> scalars_span,
260 std::span<const curve::Grumpkin::AffineElement> all_points) noexcept;
261
266template <typename Curve>
267typename Curve::Element trivial_msm_threaded(PolynomialSpan<const typename Curve::ScalarField> scalars_span,
268 std::span<const typename Curve::AffineElement> all_points,
269 size_t max_threads = 0) noexcept;
270
271extern template curve::BN254::Element trivial_msm_threaded<curve::BN254>(
272 PolynomialSpan<const curve::BN254::ScalarField> scalars_span,
273 std::span<const curve::BN254::AffineElement> all_points,
274 size_t max_threads) noexcept;
275
276extern template curve::Grumpkin::Element trivial_msm_threaded<curve::Grumpkin>(
277 PolynomialSpan<const curve::Grumpkin::ScalarField> scalars_span,
278 std::span<const curve::Grumpkin::AffineElement> all_points,
279 size_t max_threads) noexcept;
280
281} // namespace bb::scalar_multiplication
typename Group::element Element
Definition bn254.hpp:21
typename Group::element Element
Definition grumpkin.hpp:63
typename Group::affine_element AffineElement
Definition grumpkin.hpp:64
Curve::Element trivial_msm(PolynomialSpan< const typename Curve::ScalarField > scalars_span, std::span< const typename Curve::AffineElement > all_points) noexcept
Single-threaded small-MSM_fast driver: Element::straus_msm over the input slice.
Curve::Element pippenger_unsafe_fast(PolynomialSpan< const typename Curve::ScalarField > scalars, std::span< const typename Curve::AffineElement > points, size_t dedup_info) noexcept
Curve::Element trivial_msm_threaded(PolynomialSpan< const typename Curve::ScalarField > scalars_span, std::span< const typename Curve::AffineElement > all_points, size_t max_threads=0) noexcept
Multi-threaded small-MSM_fast driver: parallel Element::straus_msm over zero-skipped input slices.
template curve::BN254::Element pippenger_round_parallel< curve::BN254 >(PolynomialSpan< const curve::BN254::ScalarField > scalars, std::span< const curve::BN254::AffineElement > points, size_t dedup_info, std::span< const curve::BN254::AffineElement > external_glv_doubled, std::span< std::byte > external_arena, size_t max_threads) noexcept
size_t compute_arena_bytes_for_msm(size_t n_input, bool external_glv_provided, bool dedup_active, size_t max_threads) noexcept
Round-parallel Pippenger MSM_fast. Windows process sequentially (high-to-low) but each window is full...
template curve::Grumpkin::Element pippenger_round_parallel< curve::Grumpkin >(PolynomialSpan< const curve::Grumpkin::ScalarField > scalars, std::span< const curve::Grumpkin::AffineElement > points, size_t dedup_info, std::span< const curve::Grumpkin::AffineElement > external_glv_doubled, std::span< std::byte > external_arena, size_t max_threads) noexcept
size_t window_bits_tuning_oversub_factor(size_t n_input)
N-dependent oversubscription factor used ONLY for choose_window_bits' target_load formula (not for ac...
Curve::Element pippenger_fast(PolynomialSpan< const typename Curve::ScalarField > scalars, std::span< const typename Curve::AffineElement > points, bool handle_edge_cases, size_t dedup_info) noexcept
Curve::Element pippenger_round_parallel(PolynomialSpan< const typename Curve::ScalarField > scalars_span, std::span< const typename Curve::AffineElement > all_points, size_t dedup_info, std::span< const typename Curve::AffineElement > external_glv_doubled, std::span< std::byte > external_arena, size_t max_threads) noexcept
State of the art pippenger_fast multiscalar multiplication algorithm.
@ BN254
Definition types.hpp:10
STL namespace.
constexpr decltype(auto) get(::tuplet::tuple< T... > &&t) noexcept
Definition tuple.hpp:13
Curve::Element Element