pub fn multi_scalar_mul<G: AffineCurve>(
        bases: &[G],
        scalars: &[<G::ScalarField as PrimeField>::BigInt],
    ) -> G::Projective {
        let size = scalars.len();

        let c = if size < 32 {
            3
        } else {
            ln_without_floats(size) + 2
        };

        let num_bits = <G::ScalarField as PrimeField>::MODULUS_BIT_SIZE as usize;
        let digits_count = (num_bits + c - 1) / c;

        let scalar_digits = scalars
            .iter()
            .map(|s| digits(s, c, num_bits))
            .collect::<Vec<_>>();

        let zero = G::Projective::zero();

        // Each window is of size `c`.
        // We divide up the bits 0..num_bits into windows of size `c`, and
        // in parallel process each such window.

        let mut window_sums = (0..digits_count)
            .map(|i| {
                // We only have 2 ^ (c-1) buckets.
                let mut buckets = vec![zero; 1 << c];
                // This clone is cheap, because the iterator contains just a
                // pointer and an index into the original vectors.
                for (digits, base) in scalar_digits.iter().zip(bases) {
                    let scalar = digits[i];
                    match scalar.cmp(&0) {
                        Ordering::Greater => buckets[(scalar - 1) as usize].add_assign_mixed(base),
                        Ordering::Less => {
                            let basem = -*base;
                            buckets[(-scalar - 1) as usize].add_assign_mixed(&basem);
                        }
                        Ordering::Equal => (),
                    }
                }
                // Compute sum_{i in 0..num_buckets} (sum_{j in i..num_buckets} bucket[j])
                // This is computed below for b buckets, using 2b curve additions.
                //
                // We could first normalize `buckets` and then use mixed-addition
                // here, but that's slower for the kinds of groups we care about
                // (Short Weierstrass curves and Twisted Edwards curves).
                // In the case of Short Weierstrass curves,
                // mixed addition saves ~4 field multiplications per addition.
                // However normalization (with the inversion batched) takes ~6
                // field multiplications per element,
                // hence batch normalization is a slowdown.

                // `running_sum` = sum_{j in i..num_buckets} bucket[j],
                // where we iterate backward from i = num_buckets to 0.
                let buckets = buckets.into_iter();
                let mut running_sum = G::Projective::zero();

                let mut res = zero;
                buckets.into_iter().rev().for_each(|b| {
                    running_sum += &b;
                    res += &running_sum;
                });
                res
            })
            .rev();

        // We're traversing windows from high to low.
        let first = window_sums.next().unwrap();
        window_sums.fold(first, |mut total, sum_i| {
            for _ in 0..c {
                total.double_in_place();
            }
            total + sum_i
        })
    }
/// Multi-scalar multiplciaiton of bases and scalars.
Multi-scalar multiplciaiton of bases and scalars.
Multi - scalar multiplciaiton of bases and scalars .
pub fn multi_scalar_mul<G: AffineCurve>(
        bases: &[G],
        scalars: &[<G::ScalarField as PrimeField>::BigInt],
    ) -> G::Projective {
        let size = scalars.len();
        let c = if size < 32 {
            3
        } else {
            ln_without_floats(size) + 2
        };
        let num_bits = <G::ScalarField as PrimeField>::MODULUS_BIT_SIZE as usize;
        let digits_count = (num_bits + c - 1) / c;
        let scalar_digits = scalars
            .iter()
            .map(|s| digits(s, c, num_bits))
            .collect::<Vec<_>>();
        let zero = G::Projective::zero();
        // Each window is of size `c`.
        // We divide up the bits 0..num_bits into windows of size `c`, and
        // in parallel process each such window.
        let mut window_sums = (0..digits_count)
            .map(|i| {
                // We only have 2 ^ (c-1) buckets.
                let mut buckets = vec![zero; 1 << c];
                // This clone is cheap, because the iterator contains just a
                // pointer and an index into the original vectors.
                for (digits, base) in scalar_digits.iter().zip(bases) {
                    let scalar = digits[i];
                    match scalar.cmp(&0) {
                        Ordering::Greater => buckets[(scalar - 1) as usize].add_assign_mixed(base),
                        Ordering::Less => {
                            let basem = -*base;
                            buckets[(-scalar - 1) as usize].add_assign_mixed(&basem);
                        }
                        Ordering::Equal => (),
                    }
                }
                // Compute sum_{i in 0..num_buckets} (sum_{j in i..num_buckets} bucket[j])
                // This is computed below for b buckets, using 2b curve additions.
                //
                // We could first normalize `buckets` and then use mixed-addition
                // here, but that's slower for the kinds of groups we care about
                // (Short Weierstrass curves and Twisted Edwards curves).
                // In the case of Short Weierstrass curves,
                // mixed addition saves ~4 field multiplications per addition.
                // However normalization (with the inversion batched) takes ~6
                // field multiplications per element,
                // hence batch normalization is a slowdown.
                // `running_sum` = sum_{j in i..num_buckets} bucket[j],
                // where we iterate backward from i = num_buckets to 0.
                let buckets = buckets.into_iter();
                let mut running_sum = G::Projective::zero();
                let mut res = zero;
                buckets.into_iter().rev().for_each(|b| {
                    running_sum += &b;
                    res += &running_sum;
                });
                res
            })
            .rev();
        // We're traversing windows from high to low.
        let first = window_sums.next().unwrap();
        window_sums.fold(first, |mut total, sum_i| {
            for _ in 0..c {
                total.double_in_place();
            }
            total + sum_i
        })
    }
pub fn multi_scalar_mul < G : AffineCurve > ( bases : & [ G ] , scalars : & [ < G :: ScalarField as PrimeField > :: BigInt ] , ) -> G :: Projective { let size = scalars . len ( ) ; let c = if size < 32 { 3 } else { ln_without_floats ( size ) + 2 } ; let num_bits = < G :: ScalarField as PrimeField > :: MODULUS_BIT_SIZE as usize ; let digits_count = ( num_bits + c - 1 ) / c ; let scalar_digits = scalars . iter ( ) . map ( | s | digits ( s , c , num_bits ) ) . collect :: < Vec < _ > > ( ) ; let zero = G :: Projective :: zero ( ) ; // Each window is of size `c`. // We divide up the bits 0..num_bits into windows of size `c`, and // in parallel process each such window. let mut window_sums = ( 0 .. digits_count ) . map ( | i | { // We only have 2 ^ (c-1) buckets. let mut buckets = vec ! [ zero 1 c ] ; // This clone is cheap, because the iterator contains just a // pointer and an index into the original vectors. for ( digits , base ) in scalar_digits . iter ( ) . zip ( bases ) { let scalar = digits [ i ] ; match scalar . cmp ( & 0 ) { Ordering :: Greater => buckets [ ( scalar - 1 ) as usize ] . add_assign_mixed ( base ) , Ordering :: Less => { let basem = - * base ; buckets [ ( - scalar - 1 ) as usize ] . add_assign_mixed ( & basem ) ; } Ordering :: Equal => ( ) , } } // Compute sum_{i in 0..num_buckets} (sum_{j in i..num_buckets} bucket[j]) // This is computed below for b buckets, using 2b curve additions. // // We could first normalize `buckets` and then use mixed-addition // here, but that's slower for the kinds of groups we care about // (Short Weierstrass curves and Twisted Edwards curves). // In the case of Short Weierstrass curves, // mixed addition saves ~4 field multiplications per addition. // However normalization (with the inversion batched) takes ~6 // field multiplications per element, // hence batch normalization is a slowdown. // `running_sum` = sum_{j in i..num_buckets} bucket[j], // where we iterate backward from i = num_buckets to 0. let buckets = buckets . into_iter ( ) ; let mut running_sum = G :: Projective :: zero ( ) ; let mut res = zero ; buckets . into_iter ( ) . rev ( ) . for_each ( | b | { running_sum += & b ; res += & running_sum ; } ) ; res } ) . rev ( ) ; // We're traversing windows from high to low. let first = window_sums . next ( ) . unwrap ( ) ; window_sums . fold ( first , | mut total , sum_i | { for _ in 0 .. c { total . double_in_place ( ) ; } total + sum_i } ) }
Multi-scalar multiplciaiton of bases and scalars.
Multi - scalar multiplciaiton of bases and scalars .
bases
&[G]
scalars
&[<G::ScalarField as PrimeField>::BigInt]