pub fn msm_strauss_endo(
b: &CircuitBuilder,
curve: &Secp256k1,
window: usize,
scalars: &[BigUint],
points: &[Secp256k1Affine],
) -> Secp256k1AffineExpand description
Compute a multi-scalar multiplication Σ_i scalars[i] · points[i] over secp256k1 using the
fixed-window (Straus) algorithm combined with the GLV endomorphism.
n = points.len() must equal scalars.len(); both n and the window size window (in bits)
are statically known to the circuit. Each scalar is a 256-bit value (N_LIMBS limbs).
Every (scalar, point) pair is endomorphism-split into two ~128-bit signed subscalars and two
base points (P and φ(P), conditionally negated to positive subscalars), turning the
n-point 256-bit MSM into a 2n-point 128-bit one (128 doublings instead of 256). For each
base point a table of its 2^window small multiples is precomputed, and the 128-bit exponents
are consumed window bits at a time, from the top down: at each step every base point adds the
multiple selected by its current window (via multi_wire_multiplex), and the accumulator is
doubled window times between steps (skipped on the first window). The table size is
2n · 2^window — linear in n — so it scales to larger n.
The φ(P) table is not recomputed with point additions: since φ is a homomorphism,
φ(P)’s small multiples are φ applied to P’s small multiples (x · φ(P) = φ(x · P)), i.e.
one field multiplication of each entry’s x-coordinate by β rather than another
2^window-entry point-addition chain.
window = 4 (see MSM_WINDOW) is typically optimal.
§Completeness gap
Point additions use Secp256k1::add_incomplete, which asserts false when its inputs are equal
(it handles the point at infinity but not doubling). The probability of the accumulator or a
table entry hitting such a collision for independent inputs is vanishingly low.
§Panics
Panics if scalars.len() != points.len(), if n == 0, if window is not in
1..Word::BITS, or if any scalar does not have exactly N_LIMBS limbs.