Pippenger Algorithm
Pipenger Algorithm or Bucket Method is an algorithm to compute MSM efficiently.
The multi-scalar multiplication (MSM) problem is: Given elliptic curve points and scalars , compute:
where denotes scalar multiplication.
Description
Let’s first partition each scalar into windows each has bits, then:
You can think of each scalar as a big number so this is just a representation of it as a multi-precision integer with a limb size equal to .
Then we have:
By reordering the sums and denoting , we get:
It means we can calculate the MSM for each window first, and then aggregate the results.
Because each window has bits, has a value in range . Therefore, we can put points into buckets according to the value of . Using this fact we can compute in the following way:
for each bucket : calculate the sum of points in this bucket to get
for each compute :
For example, if and , then we have 15 points and 8 buckets, such that:
Algorithm
Here:
- number of terms
- size of window in bits
- number of windows
Init windows , with additive identities
For each in :
Init buckets , with additive identities
For each in :
Compute :
Shift right on bits
Compute remainder modulo
Add to a bucket
Compute partial sum:
Compute final sum:
Sage example:
# BN254
Fq = GF("21888242871839275222246405745257275088696311157297823662689037894645226208583")
E = EllipticCurve(Fq,[0,3])
def pippenger(s, G, c):
m = (256 // c) + 1
n = len(s)
zero = E(0)
W = [zero for k in range(0, m)]
for j in range(0, m):
B = [zero for k in range(0, 2**c)]
for i in range(0, n):
s_i_j = s[i] >> c * j
s_i_j = Integer(s_i_j) % (2**c)
B[s_i_j] += G[i]
# the code below is the more optimal way to compute
# for t in range(0, 2**c):
# W[j] += t * B[t]
running_sum = E(0)
for t in range(2**c - 1, 0, -1):
running_sum += B[t]
W[j] += running_sum
# the code below is the same as
# S = zero
# p = 1
# for j in range(0, m):
# S += p * W[j]
# p *= 2**c
S = zero
for j in range(m-1, -1, -1):
for k in range(0, c):
S = S + S
S += W[j]
return S
n = 2**9
c = 13
s = [Fq.random_element() for i in range(0, n)]
G = [E.random_element() for i in range(0, n)]
%time pippenger(s, G, c)
Last updated