Barretenberg
The ZK-SNARK library at the core of Aztec
Loading...
Searching...
No Matches
scalar_multiplication.test.cpp
Go to the documentation of this file.
10#include <filesystem>
11#include <gtest/gtest.h>
12
13using namespace bb;
14
15namespace {
17} // namespace
18
19template <class Curve> class ScalarMultiplicationTest : public ::testing::Test {
20 public:
21 using Group = typename Curve::Group;
22 using Element = typename Curve::Element;
25
26 static constexpr size_t num_points = 201123;
27 static inline std::vector<AffineElement> generators{};
28 static inline std::vector<ScalarField> scalars{};
29
30 static AffineElement naive_msm(std::span<ScalarField> input_scalars, std::span<const AffineElement> input_points)
31 {
32 size_t total_points = input_scalars.size();
33 size_t num_threads = get_num_cpus();
34 std::vector<Element> expected_accs(num_threads);
35 size_t range_per_thread = (total_points + num_threads - 1) / num_threads;
36 parallel_for(num_threads, [&](size_t thread_idx) {
37 Element expected_thread_acc;
38 expected_thread_acc.self_set_infinity();
39 size_t start = thread_idx * range_per_thread;
40 size_t end = ((thread_idx + 1) * range_per_thread > total_points) ? total_points
41 : (thread_idx + 1) * range_per_thread;
42 bool skip = start >= total_points;
43 if (!skip) {
44 for (size_t i = start; i < end; ++i) {
45 expected_thread_acc += input_points[i] * input_scalars[i];
46 }
47 }
48 expected_accs[thread_idx] = expected_thread_acc;
49 });
50
51 Element expected_acc = Element();
52 expected_acc.self_set_infinity();
53 for (auto& acc : expected_accs) {
54 expected_acc += acc;
55 }
56 return AffineElement(expected_acc);
57 }
58
59 static void SetUpTestSuite()
60 {
61 generators.resize(num_points);
62 scalars.resize(num_points);
63 parallel_for_range(num_points, [&](size_t start, size_t end) {
64 for (size_t i = start; i < end; ++i) {
65 generators[i] = Group::one * Curve::ScalarField::random_element(&engine);
66 scalars[i] = Curve::ScalarField::random_element(&engine);
67 }
68 });
69 for (size_t i = 0; i < num_points - 1; ++i) {
70 ASSERT_EQ(generators[i].x == generators[i + 1].x, false);
71 }
72 };
73
74 // ======================= Test Methods =======================
75
77 {
78 constexpr uint32_t fr_size = 254;
79 constexpr uint32_t slice_bits = 7;
80 constexpr uint32_t num_slices = (fr_size + 6) / 7;
81 constexpr uint32_t last_slice_bits = fr_size - ((num_slices - 1) * slice_bits);
82
83 for (size_t x = 0; x < 100; ++x) {
84 uint256_t input_u256 = engine.get_random_uint256();
85 input_u256.data[3] = input_u256.data[3] & 0x3FFFFFFFFFFFFFFF; // 254 bits
86 while (input_u256 > ScalarField::modulus) {
87 input_u256 -= ScalarField::modulus;
88 }
89 std::vector<uint32_t> slices(num_slices);
90
91 uint256_t acc = input_u256;
92 for (uint32_t i = 0; i < num_slices; ++i) {
93 uint32_t mask = ((1U << slice_bits) - 1U);
94 uint32_t shift = slice_bits;
95 if (i == 0) {
96 mask = ((1U << last_slice_bits) - 1U);
97 shift = last_slice_bits;
98 }
99 slices[num_slices - 1 - i] = static_cast<uint32_t>((acc & mask).data[0]);
100 acc = acc >> shift;
101 }
102
103 ScalarField input(input_u256);
104 input.self_from_montgomery_form_reduced();
105
106 ASSERT_EQ(input.data[0], input_u256.data[0]);
107 ASSERT_EQ(input.data[1], input_u256.data[1]);
108 ASSERT_EQ(input.data[2], input_u256.data[2]);
109 ASSERT_EQ(input.data[3], input_u256.data[3]);
110
111 for (uint32_t i = 0; i < num_slices; ++i) {
112 uint32_t result = scalar_multiplication::MSM<Curve>::get_scalar_slice(input, i, slice_bits);
113 EXPECT_EQ(result, slices[i]);
114 }
115 }
116 }
117
119 {
120 const size_t total_points = 30071;
121 const size_t num_buckets = 128;
122
123 std::vector<uint64_t> input_point_schedule;
124 for (size_t i = 0; i < total_points; ++i) {
125 uint64_t bucket = static_cast<uint64_t>(engine.get_random_uint8()) & 0x7f;
126 uint64_t schedule = static_cast<uint64_t>(bucket) + (static_cast<uint64_t>(i) << 32);
127 input_point_schedule.push_back(schedule);
128 }
130 typename scalar_multiplication::MSM<Curve>::BucketAccumulators bucket_data(num_buckets);
132 input_point_schedule, generators, affine_data, bucket_data);
133
134 std::vector<Element> expected_buckets(num_buckets);
135 for (auto& e : expected_buckets) {
136 e.self_set_infinity();
137 }
138 for (size_t i = 0; i < total_points; ++i) {
139 uint64_t bucket = input_point_schedule[i] & 0xFFFFFFFF;
140 EXPECT_LT(static_cast<size_t>(bucket), num_buckets);
141 expected_buckets[static_cast<size_t>(bucket)] += generators[i];
142 }
143 for (size_t i = 0; i < num_buckets; ++i) {
144 if (!expected_buckets[i].is_point_at_infinity()) {
145 AffineElement expected(expected_buckets[i]);
146 EXPECT_EQ(expected, bucket_data.buckets[i]);
147 } else {
148 EXPECT_FALSE(bucket_data.bucket_exists.get(i));
149 }
150 }
151 }
152
154 {
155 const size_t total_points = 30071;
156 const size_t num_buckets = 128;
157
158 std::vector<uint64_t> input_point_schedule;
159 for (size_t i = 0; i < total_points; ++i) {
160 uint64_t bucket = static_cast<uint64_t>(engine.get_random_uint8()) & 0x7f;
161 uint64_t schedule = static_cast<uint64_t>(bucket) + (static_cast<uint64_t>(i) << 32);
162 input_point_schedule.push_back(schedule);
163 }
165 typename scalar_multiplication::MSM<Curve>::BucketAccumulators bucket_data(num_buckets);
167 input_point_schedule, generators, affine_data, bucket_data);
168
170
171 Element expected_acc;
172 expected_acc.self_set_infinity();
173 size_t num_threads = get_num_cpus();
174 std::vector<Element> expected_accs(num_threads);
175 size_t range_per_thread = (total_points + num_threads - 1) / num_threads;
176 parallel_for(num_threads, [&](size_t thread_idx) {
177 Element expected_thread_acc;
178 expected_thread_acc.self_set_infinity();
179 size_t start = thread_idx * range_per_thread;
180 size_t end = (thread_idx == num_threads - 1) ? total_points : (thread_idx + 1) * range_per_thread;
181 bool skip = start >= total_points;
182 if (!skip) {
183 for (size_t i = start; i < end; ++i) {
184 ScalarField scalar = input_point_schedule[i] & 0xFFFFFFFF;
185 expected_thread_acc += generators[i] * scalar;
186 }
187 }
188 expected_accs[thread_idx] = expected_thread_acc;
189 });
190
191 for (size_t i = 0; i < num_threads; ++i) {
192 expected_acc += expected_accs[i];
193 }
194 AffineElement expected(expected_acc);
195 EXPECT_EQ(AffineElement(result), expected);
196 }
197
199 {
200 const size_t total_points = 30071;
201
202 std::vector<uint64_t> input_point_schedule;
203 for (size_t i = 0; i < total_points; ++i) {
204 uint64_t bucket = static_cast<uint64_t>(engine.get_random_uint8()) & 0x7f;
205 uint64_t schedule = static_cast<uint64_t>(bucket) + (static_cast<uint64_t>(i) << 32);
206 input_point_schedule.push_back(schedule);
207 }
208
210 &input_point_schedule[0], input_point_schedule.size(), 7);
211
212 // Verify zero entry count is correct
213 size_t expected = 0;
214 for (size_t i = 0; i < total_points; ++i) {
215 expected += static_cast<size_t>((input_point_schedule[i] & 0xFFFFFFFF) == 0);
216 }
217 EXPECT_EQ(result, expected);
218
219 // Verify the array is sorted by bucket index (lower 32 bits)
220 for (size_t i = 1; i < total_points; ++i) {
221 uint32_t prev_bucket = static_cast<uint32_t>(input_point_schedule[i - 1]);
222 uint32_t curr_bucket = static_cast<uint32_t>(input_point_schedule[i]);
223 EXPECT_LE(prev_bucket, curr_bucket) << "Array not sorted at index " << i;
224 }
225 }
226
228 {
229 std::span<ScalarField> test_scalars(&scalars[0], num_points);
230 AffineElement result =
232 AffineElement expected = naive_msm(test_scalars, generators);
233 EXPECT_EQ(result, expected);
234 }
235
237 {
238 BB_BENCH_NAME("BatchMultiScalarMul");
239
240 const size_t num_msms = static_cast<size_t>(engine.get_random_uint8());
241 std::vector<AffineElement> expected(num_msms);
242
243 std::vector<std::vector<ScalarField>> batch_scalars_copies(num_msms);
245 std::vector<std::span<ScalarField>> batch_scalars_spans;
246
247 size_t vector_offset = 0;
248 for (size_t k = 0; k < num_msms; ++k) {
249 const size_t num_pts = static_cast<size_t>(engine.get_random_uint16()) % 400;
250
251 ASSERT_LT(vector_offset + num_pts, num_points);
252 std::span<const AffineElement> batch_points(&generators[vector_offset], num_pts);
253
254 batch_scalars_copies[k].resize(num_pts);
255 for (size_t i = 0; i < num_pts; ++i) {
256 batch_scalars_copies[k][i] = scalars[vector_offset + i];
257 }
258
259 vector_offset += num_pts;
260 batch_points_span.push_back(batch_points);
261 batch_scalars_spans.push_back(batch_scalars_copies[k]);
262
263 expected[k] = naive_msm(batch_scalars_spans[k], batch_points_span[k]);
264 }
265
266 std::vector<AffineElement> result =
267 scalar_multiplication::MSM<Curve>::batch_multi_scalar_mul(batch_points_span, batch_scalars_spans);
268
269 EXPECT_EQ(result, expected);
270 }
271
273 {
274 const size_t num_msms = 10;
275 std::vector<AffineElement> expected(num_msms);
276
277 std::vector<std::vector<ScalarField>> batch_scalars(num_msms);
279 std::vector<std::span<ScalarField>> batch_scalars_spans;
280
281 for (size_t k = 0; k < num_msms; ++k) {
282 const size_t num_pts = 33;
283 auto& test_scalars = batch_scalars[k];
284
285 test_scalars.resize(num_pts);
286
287 size_t fixture_offset = k * num_pts;
288
289 std::span<AffineElement> batch_points(&generators[fixture_offset], num_pts);
290 for (size_t i = 0; i < 13; ++i) {
291 test_scalars[i] = 0;
292 }
293 for (size_t i = 13; i < 23; ++i) {
294 test_scalars[i] = scalars[fixture_offset + i + 13];
295 }
296 for (size_t i = 23; i < num_pts; ++i) {
297 test_scalars[i] = 0;
298 }
299 batch_points_span.push_back(batch_points);
300 batch_scalars_spans.push_back(batch_scalars[k]);
301
302 expected[k] = naive_msm(batch_scalars[k], batch_points);
303 }
304
305 std::vector<AffineElement> result =
306 scalar_multiplication::MSM<Curve>::batch_multi_scalar_mul(batch_points_span, batch_scalars_spans);
307
308 EXPECT_EQ(result, expected);
309 }
310
311 void test_msm()
312 {
313 const size_t start_index = 1234;
314 const size_t num_pts = num_points - start_index;
315
316 PolynomialSpan<ScalarField> scalar_span =
319
320 std::span<AffineElement> points(&generators[start_index], num_pts);
321 AffineElement expected = naive_msm(scalar_span.span, points);
322 EXPECT_EQ(result, expected);
323 }
324
326 {
327 const size_t start_index = 1234;
328 const size_t num_pts = num_points - start_index;
329 std::vector<ScalarField> test_scalars(num_pts, ScalarField::zero());
330
331 PolynomialSpan<ScalarField> scalar_span = PolynomialSpan<ScalarField>(start_index, test_scalars);
333
334 EXPECT_EQ(result, Group::affine_point_at_infinity);
335 }
336
338 {
339 std::vector<ScalarField> test_scalars;
340 std::vector<AffineElement> input_points;
341 PolynomialSpan<ScalarField> scalar_span = PolynomialSpan<ScalarField>(0, test_scalars);
342 AffineElement result = scalar_multiplication::MSM<Curve>::msm(input_points, scalar_span);
343
344 EXPECT_EQ(result, Group::affine_point_at_infinity);
345 }
346
348 {
349 const size_t num_pts = 100;
350 std::vector<ScalarField> test_scalars(num_pts);
351 std::vector<ScalarField> scalars_copy(num_pts);
352
353 for (size_t i = 0; i < num_pts; ++i) {
354 test_scalars[i] = scalars[i];
355 scalars_copy[i] = test_scalars[i];
356 }
357
358 std::span<const AffineElement> points(&generators[0], num_pts);
359 PolynomialSpan<ScalarField> scalar_span(0, test_scalars);
360
361 scalar_multiplication::MSM<Curve>::msm(points, scalar_span);
362
363 for (size_t i = 0; i < num_pts; ++i) {
364 EXPECT_EQ(test_scalars[i], scalars_copy[i]) << "Scalar at index " << i << " was modified";
365 }
366 }
367
369 {
370 const size_t num_msms = 3;
371 const size_t num_pts = 100;
372
373 std::vector<std::vector<ScalarField>> batch_scalars(num_msms);
374 std::vector<std::vector<ScalarField>> scalars_copies(num_msms);
376 std::vector<std::span<ScalarField>> batch_scalar_spans;
377
378 for (size_t k = 0; k < num_msms; ++k) {
379 batch_scalars[k].resize(num_pts);
380 scalars_copies[k].resize(num_pts);
381
382 for (size_t i = 0; i < num_pts; ++i) {
383 batch_scalars[k][i] = scalars[k * num_pts + i];
384 scalars_copies[k][i] = batch_scalars[k][i];
385 }
386
387 batch_points.push_back(std::span<const AffineElement>(&generators[k * num_pts], num_pts));
388 batch_scalar_spans.push_back(batch_scalars[k]);
389 }
390
391 scalar_multiplication::MSM<Curve>::batch_multi_scalar_mul(batch_points, batch_scalar_spans);
392
393 for (size_t k = 0; k < num_msms; ++k) {
394 for (size_t i = 0; i < num_pts; ++i) {
395 EXPECT_EQ(batch_scalars[k][i], scalars_copies[k][i])
396 << "Scalar at MSM " << k << ", index " << i << " was modified";
397 }
398 }
399 }
400
402 {
403 const size_t num_pts = 5;
404 std::vector<ScalarField> test_scalars(num_pts, ScalarField::one());
405 std::span<const AffineElement> points(&generators[0], num_pts);
406
407 PolynomialSpan<ScalarField> scalar_span(0, test_scalars);
408 AffineElement result = scalar_multiplication::MSM<Curve>::msm(points, scalar_span);
409
410 Element expected;
411 expected.self_set_infinity();
412 for (size_t i = 0; i < num_pts; ++i) {
413 expected += points[i];
414 }
415
416 EXPECT_EQ(result, AffineElement(expected));
417 }
418
420 {
421 const size_t num_pts = 5;
422 std::vector<ScalarField> test_scalars(num_pts, -ScalarField::one());
423 std::span<const AffineElement> points(&generators[0], num_pts);
424
425 PolynomialSpan<ScalarField> scalar_span(0, test_scalars);
426 AffineElement result = scalar_multiplication::MSM<Curve>::msm(points, scalar_span);
427
428 Element expected;
429 expected.self_set_infinity();
430 for (size_t i = 0; i < num_pts; ++i) {
431 expected -= points[i];
432 }
433
434 EXPECT_EQ(result, AffineElement(expected));
435 }
436
438 {
439 std::vector<ScalarField> test_scalars = { scalars[0] };
440 std::span<const AffineElement> points(&generators[0], 1);
441
442 PolynomialSpan<ScalarField> scalar_span(0, test_scalars);
443 AffineElement result = scalar_multiplication::MSM<Curve>::msm(points, scalar_span);
444
445 AffineElement expected(points[0] * test_scalars[0]);
446 EXPECT_EQ(result, expected);
447 }
448
450 {
451 std::vector<size_t> test_sizes = { 1, 2, 15, 16, 17, 50, 127, 128, 129, 256, 512 };
452
453 for (size_t num_pts : test_sizes) {
454 ASSERT_LE(num_pts, num_points);
455
456 std::vector<ScalarField> test_scalars(num_pts);
457 for (size_t i = 0; i < num_pts; ++i) {
458 test_scalars[i] = scalars[i];
459 }
460
461 std::span<const AffineElement> points(&generators[0], num_pts);
462 PolynomialSpan<ScalarField> scalar_span(0, test_scalars);
463
464 AffineElement result = scalar_multiplication::MSM<Curve>::msm(points, scalar_span);
465 AffineElement expected = naive_msm(test_scalars, points);
466
467 EXPECT_EQ(result, expected) << "Failed for size " << num_pts;
468 }
469 }
470
472 {
473 // Use enough points to trigger Pippenger (> PIPPENGER_THRESHOLD = 16)
474 const size_t num_pts = 32;
475 AffineElement base_point = generators[0];
476
477 std::vector<AffineElement> points(num_pts, base_point);
478 std::vector<ScalarField> test_scalars(num_pts);
479 ScalarField scalar_sum = ScalarField::zero();
480
481 for (size_t i = 0; i < num_pts; ++i) {
482 test_scalars[i] = scalars[i];
483 scalar_sum += test_scalars[i];
484 }
485
486 PolynomialSpan<ScalarField> scalar_span(0, test_scalars);
487 // Duplicate points are an edge case (P + P requires doubling, not addition).
488 // Must use handle_edge_cases=true for correctness with Pippenger.
489 AffineElement result = scalar_multiplication::MSM<Curve>::msm(points, scalar_span, /*handle_edge_cases=*/true);
490
491 AffineElement expected(base_point * scalar_sum);
492 EXPECT_EQ(result, expected);
493 }
494
496 {
497 const size_t num_pts = 100;
498 std::vector<ScalarField> test_scalars(num_pts);
499 Element expected;
500 expected.self_set_infinity();
501
502 for (size_t i = 0; i < num_pts; ++i) {
503 if (i % 2 == 0) {
504 test_scalars[i] = ScalarField::zero();
505 } else {
506 test_scalars[i] = scalars[i];
507 expected += generators[i] * test_scalars[i];
508 }
509 }
510
511 std::span<const AffineElement> points(&generators[0], num_pts);
512 PolynomialSpan<ScalarField> scalar_span(0, test_scalars);
513
514 AffineElement result = scalar_multiplication::MSM<Curve>::msm(points, scalar_span);
515 EXPECT_EQ(result, AffineElement(expected));
516 }
517
519 {
520 const size_t num_pts = 200;
521 std::vector<ScalarField> test_scalars(num_pts);
522 for (size_t i = 0; i < num_pts; ++i) {
523 test_scalars[i] = scalars[i];
524 }
525
526 std::span<const AffineElement> points(&generators[0], num_pts);
527 PolynomialSpan<ScalarField> scalar_span(0, test_scalars);
528
529 auto result = scalar_multiplication::pippenger<Curve>(scalar_span, points);
530
531 AffineElement expected = naive_msm(test_scalars, points);
532 EXPECT_EQ(AffineElement(result), expected);
533 }
534
536 {
537 const size_t num_pts = 200;
538 std::vector<ScalarField> test_scalars(num_pts);
539 for (size_t i = 0; i < num_pts; ++i) {
540 test_scalars[i] = scalars[i];
541 }
542
543 std::span<const AffineElement> points(&generators[0], num_pts);
544 PolynomialSpan<ScalarField> scalar_span(0, test_scalars);
545
546 auto result = scalar_multiplication::pippenger_unsafe<Curve>(scalar_span, points);
547
548 AffineElement expected = naive_msm(test_scalars, points);
549 EXPECT_EQ(AffineElement(result), expected);
550 }
551};
552
553using CurveTypes = ::testing::Types<bb::curve::BN254, bb::curve::Grumpkin>;
555
556// ======================= Test Wrappers =======================
557
559{
560 this->test_get_scalar_slice();
561}
563{
564 this->test_consume_point_batch();
565}
566TYPED_TEST(ScalarMultiplicationTest, ConsumePointBatchAndAccumulate)
567{
568 this->test_consume_point_batch_and_accumulate();
569}
570TYPED_TEST(ScalarMultiplicationTest, RadixSortCountZeroEntries)
571{
572 this->test_radix_sort_count_zero_entries();
573}
575{
576 this->test_pippenger_low_memory();
577}
579{
580 this->test_batch_multi_scalar_mul();
581}
582TYPED_TEST(ScalarMultiplicationTest, BatchMultiScalarMulSparse)
583{
584 this->test_batch_multi_scalar_mul_sparse();
585}
587{
588 this->test_msm();
589}
591{
592 this->test_msm_all_zeroes();
593}
595{
596 this->test_msm_empty_polynomial();
597}
598TYPED_TEST(ScalarMultiplicationTest, ScalarsUnchangedAfterMSM)
599{
600 this->test_scalars_unchanged_after_msm();
601}
602TYPED_TEST(ScalarMultiplicationTest, ScalarsUnchangedAfterBatchMultiScalarMul)
603{
604 this->test_scalars_unchanged_after_batch_multi_scalar_mul();
605}
607{
608 this->test_scalar_one();
609}
611{
612 this->test_scalar_minus_one();
613}
615{
616 this->test_single_point();
617}
619{
620 this->test_size_thresholds();
621}
623{
624 this->test_duplicate_points();
625}
627{
628 this->test_mixed_zero_scalars();
629}
631{
632 this->test_pippenger_free_function();
633}
634TYPED_TEST(ScalarMultiplicationTest, PippengerUnsafeFreeFunction)
635{
636 this->test_pippenger_unsafe_free_function();
637}
638
639// Non-templated test for explicit small inputs
640TEST(ScalarMultiplication, SmallInputsExplicit)
641{
642 uint256_t x0(0x68df84429941826a, 0xeb08934ed806781c, 0xc14b6a2e4f796a73, 0x08dc1a9a11a3c8db);
643 uint256_t y0(0x8ae5c31aa997f141, 0xe85f20c504f2c11b, 0x81a94193f3b1ce2b, 0x26f2c37372adb5b7);
644 uint256_t x1(0x80f5a592d919d32f, 0x1362652b984e51ca, 0xa0b26666f770c2a1, 0x142c6e1964e5c3c5);
645 uint256_t y1(0xb6c322ebb5ae4bc5, 0xf9fef6c7909c00f8, 0xb37ca1cc9af3b421, 0x1e331c7fa73d6a59);
646 uint256_t s0(0xe48bf12a24272e08, 0xf8dd0182577f3567, 0xec8fd222b8a6becb, 0x102d76b945612c9b);
647 uint256_t s1(0x098ae8d69f1e4e9e, 0xb5c8313c0f6040ed, 0xf78041e30cc46c44, 0x1d1e6e0c21892e13);
648
649 std::vector<grumpkin::fr> scalars{ s0, s1 };
650
653
655
656 auto result = scalar_multiplication::MSM<curve::Grumpkin>::msm(points, scalar_span);
657
658 grumpkin::g1::element expected = (points[0] * scalars[0]) + (points[1] * scalars[1]);
659
660 EXPECT_EQ(result, grumpkin::g1::affine_element(expected));
661}
#define BB_BENCH_NAME(name)
Definition bb_bench.hpp:225
BB_INLINE bool get(size_t index) const noexcept
Definition bitvector.hpp:42
typename Curve::ScalarField ScalarField
static std::vector< AffineElement > generators
static std::vector< ScalarField > scalars
typename Curve::AffineElement AffineElement
static AffineElement naive_msm(std::span< ScalarField > input_scalars, std::span< const AffineElement > input_points)
typename Group::element Element
Definition grumpkin.hpp:64
typename grumpkin::g1 Group
Definition grumpkin.hpp:63
typename Group::affine_element AffineElement
Definition grumpkin.hpp:65
element class. Implements ecc group arithmetic using Jacobian coordinates See https://hyperelliptic....
Definition element.hpp:33
group_elements::affine_element< Fq, Fr, Params > affine_element
Definition group.hpp:42
virtual uint8_t get_random_uint8()=0
virtual uint16_t get_random_uint16()=0
virtual uint256_t get_random_uint256()=0
static Element accumulate_buckets(BucketType &bucket_accumulators) noexcept
Reduce buckets to single point using running (suffix) sum from high to low: R = sum(k * B_k)
static uint32_t get_scalar_slice(const ScalarField &scalar, size_t round, size_t slice_size) noexcept
Extract c-bit slice from scalar for bucket index computation.
static AffineElement msm(std::span< const AffineElement > points, PolynomialSpan< const ScalarField > scalars, bool handle_edge_cases=false) noexcept
Main entry point for single MSM computation.
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 MSMs in parallel with work balancing.
static void batch_accumulate_points_into_buckets(std::span< const uint64_t > point_schedule, std::span< const AffineElement > points, AffineAdditionData &affine_data, BucketAccumulators &bucket_data) noexcept
Process sorted point schedule into bucket accumulators using batched affine additions.
const std::vector< MemoryValue > data
numeric::RNG & engine
RNG & get_randomness()
Definition engine.cpp:230
size_t sort_point_schedule_and_count_zero_buckets(uint64_t *point_schedule, const size_t num_entries, const uint32_t bucket_index_bits) noexcept
Sort point schedule by bucket index and count zero-bucket entries.
Entry point for Barretenberg command-line interface.
Definition api.hpp:5
TYPED_TEST_SUITE(CommitmentKeyTest, Curves)
size_t get_num_cpus()
Definition thread.cpp:33
::testing::Types< curve::BN254, curve::Grumpkin > CurveTypes
TYPED_TEST(CommitmentKeyTest, CommitToZeroPoly)
TEST(BoomerangMegaCircuitBuilder, BasicCircuit)
void parallel_for(size_t num_iterations, const std::function< void(size_t)> &func)
Definition thread.cpp:111
void parallel_for_range(size_t num_points, const std::function< void(size_t, size_t)> &func, size_t no_multhreading_if_less_or_equal)
Split a loop into several loops running in parallel.
Definition thread.cpp:141
constexpr decltype(auto) get(::tuplet::tuple< T... > &&t) noexcept
Definition tuple.hpp:13
std::span< Fr > span
Scratch space for batched affine point additions (one per thread)
Affine bucket accumulators for the fast affine-trick Pippenger variant.