pub fn msm<C, T>(cs: &[C], points: &[T]) -> Result<T, MSMError>
where
    C: IsUnsignedInteger,
    T: IsGroup,
{
    if cs.len() != points.len() {
        return Err(MSMError::LengthMismatch(cs.len(), points.len()));
    }
    let res = cs
        .iter()
        .zip(points.iter())
        .map(|(&c, h)| h.operate_with_self(c))
        .reduce(|acc, x| acc.operate_with(&x))
        .unwrap_or_else(T::neutral_element);

    Ok(res)
}
This function computes the multiscalar multiplication (MSM).

Assume a group G of order r is given.
Let `points = [g_1, ..., g_n]` be a tuple of group points in G and
let `cs = [k_1, ..., k_n]` be a tuple of scalars in the Galois field GF(r).

Then, with additive notation, `msm(cs, points)` computes k_1 * g_1 + .... + k_n * g_n.

If `points` and `cs` are empty, then `msm` returns the zero element of the group.

Panics if `cs` and `points` have different lengths.
crates/math/src/msm/naive.rs