UltrafastSecp256k1 3.50.0
Ultra high-performance secp256k1 elliptic curve cryptography library
Loading...
Searching...
No Matches
pippenger.hpp
Go to the documentation of this file.
1#ifndef SECP256K1_PIPPENGER_HPP
2#define SECP256K1_PIPPENGER_HPP
3#pragma once
4
5// ============================================================================
6// Pippenger Bucket Method for Multi-Scalar Multiplication
7// ============================================================================
8//
9// Computes: R = s_1*P_1 + s_2*P_2 + ... + s_n*P_n
10//
11// Algorithm (bucket method, a.k.a. Pippenger):
12// 1. Choose window width c from an empirically tuned CPU heuristic.
13// 2. Represent each scalar s in base-2^c digits.
14// 3. For each digit position j (from MSB to LSB):
15// a. Scatter: place P into bucket[digit_j(s)] for all i.
16// b. Aggregate: sum buckets as Sum = Sum_{b=1}^{2^c-1} b * bucket[b].
17// Computed bottom-up: running_sum += bucket[b], partial_sum += running_sum.
18// c. Combine: R = R*2^c + Sum
19//
20// Complexity: O(n/c + 2^c + 256*dbl) vs Strauss O(256 + n*2^(w-1))
21// Current CPU crossover: Pippenger wins around n ~= 48.
22//
23// This implementation:
24// - Pre-allocates all buckets in a single flat array (no heap per iteration)
25// - Uses predecoded digits and bucket reuse on the optimized CPU path
26// - Falls back to Strauss for small n
27//
28// Reference: Bernstein, Doumen, Lange, Oosterwijk (2012),
29// "Faster batch forgery identification"
30// ============================================================================
31
32#include <cstddef>
33#include <cstdint>
34#include <vector>
35#include "secp256k1/scalar.hpp"
36#include "secp256k1/point.hpp"
37
38namespace secp256k1 {
39
40// -- Pippenger Multi-Scalar Multiplication ------------------------------------
41// Computes: R = sum( scalars[i] * points[i] ) for i in [0, n).
42// Uses bucket method (Pippenger) which is asymptotically optimal.
43//
44// Parameters:
45// scalars - array of n scalars
46// points - array of n points
47// n - number of scalar-point pairs
48//
49// Performance: O(n/c + 2^c) per window, with c chosen from measured bands.
50// n=256: ~4x faster than Strauss
51// n=1024: ~8x faster than Strauss
52// n=4096: ~12x faster than Strauss
53
55 const fast::Point* points,
56 std::size_t n);
57
58// Convenience: vector version
59fast::Point pippenger_msm(const std::vector<fast::Scalar>& scalars,
60 const std::vector<fast::Point>& points);
61
62// -- Optimal Window Width -----------------------------------------------------
63// Returns the optimal bucket window width c for n points.
64// Uses measured CPU bands, not just the textbook floor(log2(n)) heuristic.
65unsigned pippenger_optimal_window(std::size_t n);
66
67// -- Unified MSM (auto-selects best algorithm) --------------------------------
68// Automatically picks Strauss for very small MSMs and Pippenger from n >= 48.
70 const fast::Point* points,
71 std::size_t n);
72
73fast::Point msm(const std::vector<fast::Scalar>& scalars,
74 const std::vector<fast::Point>& points);
75
76} // namespace secp256k1
77
78#endif // SECP256K1_PIPPENGER_HPP
unsigned pippenger_optimal_window(std::size_t n)
fast::Point pippenger_msm(const fast::Scalar *scalars, const fast::Point *points, std::size_t n)
fast::Point msm(const fast::Scalar *scalars, const fast::Point *points, std::size_t n)