From 7fba2a1bccc7674794eb832720d6c9e568039192 Mon Sep 17 00:00:00 2001 From: Oleg Andreev Date: Wed, 22 May 2019 11:14:26 -0700 Subject: [PATCH] avoid unnecessary allocation --- src/backend/serial/scalar_mul/pippenger.rs | 23 ++++++++++----------- src/backend/vector/scalar_mul/pippenger.rs | 24 ++++++++-------------- 2 files changed, 20 insertions(+), 27 deletions(-) diff --git a/src/backend/serial/scalar_mul/pippenger.rs b/src/backend/serial/scalar_mul/pippenger.rs index 82cf1bd..2425ee1 100644 --- a/src/backend/serial/scalar_mul/pippenger.rs +++ b/src/backend/serial/scalar_mul/pippenger.rs @@ -112,7 +112,7 @@ impl VartimeMultiscalarMul for Pippenger { .map(|_| EdwardsPoint::identity()) .collect(); - let columns: Vec<_> = (0..digits_count).map(|digit_index| { + let mut columns = (0..digits_count).rev().map(|digit_index| { // Clear the buckets when processing another digit. for i in 0..buckets_count { @@ -150,18 +150,17 @@ impl VartimeMultiscalarMul for Pippenger { } buckets_sum - }) - .collect(); - // ^ Note: we collect points because if we chain .rev().fold() - // then the .map() will run in reversed order, producing incorrect digit values - // (they can only be produced in lo->hi order). + }); - // Add the intermediate per-digit results in hi->lo order - // so that we can minimize doublings. - Some(columns[0..(digits_count - 1)].iter().rev().fold( - columns[digits_count - 1], - |total, &p| total.mul_by_pow_2(w as u32) + p, - )) + // Take the high column as an initial value to avoid wasting time doubling the identity element in `fold()`. + // `unwrap()` always succeeds because we know we have more than zero digits. + let hi_column = columns.next().unwrap(); + + Some( + columns.fold(hi_column, |total, p| { + total.mul_by_pow_2(w as u32) + p + }).into() + ) } } diff --git a/src/backend/vector/scalar_mul/pippenger.rs b/src/backend/vector/scalar_mul/pippenger.rs index 070273b..039ea56 100644 --- a/src/backend/vector/scalar_mul/pippenger.rs +++ b/src/backend/vector/scalar_mul/pippenger.rs @@ -69,7 +69,7 @@ impl VartimeMultiscalarMul for Pippenger { .map(|_| ExtendedPoint::identity()) .collect(); - let columns: Vec = (0..digits_count).map(|digit_index| { + let mut columns = (0..digits_count).rev().map(|digit_index| { // Clear the buckets when processing another digit. for i in 0..buckets_count { @@ -107,22 +107,16 @@ impl VartimeMultiscalarMul for Pippenger { } buckets_sum - }) - .collect(); - // ^ Note: we collect points because if we chain .rev().fold() - // then the .map() will run in reversed order, producing incorrect digit values - // (they can only be produced in lo->hi order). + }); + + // Take the high column as an initial value to avoid wasting time doubling the identity element in `fold()`. + // `unwrap()` always succeeds because we know we have more than zero digits. + let hi_column = columns.next().unwrap(); - // Add the intermediate per-digit results in hi->lo order - // so that we can minimize doublings. Some( - columns[0..(digits_count - 1)] - .iter() - .rev() - .fold(columns[digits_count - 1], |total, &p| { - &total.mul_by_pow_2(w as u32) + &CachedPoint::from(p) - }) - .into(), + columns.fold(hi_column, |total, p| { + &total.mul_by_pow_2(w as u32) + &CachedPoint::from(p) + }).into() ) } }