diff --git a/algebra-core/src/group/mod.rs b/algebra-core/src/group/mod.rs index 9e7c799a7..03222a812 100644 --- a/algebra-core/src/group/mod.rs +++ b/algebra-core/src/group/mod.rs @@ -139,9 +139,10 @@ pub trait MultiplicativeGroup: invert_and_mul_batch(v, &Self::one()); } - fn invert_batch(v: &[Self]) { + fn invert_batch(v: &[Self]) -> Vec { let mut v = v.to_vec(); - Self::invert_batch(&mut v); + Self::invert_batch_in_place(&mut v); + v } } diff --git a/algebra-core/src/module/mod.rs b/algebra-core/src/module/mod.rs index c377a2035..8c80ea7c0 100644 --- a/algebra-core/src/module/mod.rs +++ b/algebra-core/src/module/mod.rs @@ -102,7 +102,7 @@ pub trait ScalarExp: fn pow_exp_base(base: &Self::ExpBase, exp: Exponent) -> Self { let mut res = Self::one(); let (sign, exp) = exp.as_u64s(); - for (i, bit) in crate::bits::BitIteratorBE::without_leading_zeros(exp).enumerate() { + for bit in crate::bits::BitIteratorBE::without_leading_zeros(exp) { res.square_in_place(); if bit { res *= base; diff --git a/algebra-core/src/module/scalar.rs b/algebra-core/src/module/scalar.rs index 4077a4481..235b1f4c3 100644 --- a/algebra-core/src/module/scalar.rs +++ b/algebra-core/src/module/scalar.rs @@ -1,5 +1,7 @@ use ark_std::fmt::Debug; +use crate::biginteger::{signed_mod_reduction, arithmetic::{sbb_for_sub_with_borrow, adc_for_add_with_carry}}; + #[derive(Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Hash, Debug, Default)] pub enum Sign { Negative = -1, @@ -25,6 +27,68 @@ pub trait Scalar: Send + Sync + Copy + Debug { fn as_bytes(&self) -> (Sign, Self::U8Ref); fn as_u64s(&self) -> (Sign, Self::U64Ref); + + /// Returns the windowed non-adjacent form of `self`, for a window of size `w`. + fn find_wnaf(&self, w: usize) -> Option> { + // w > 2 due to definition of wNAF, and w < 64 to make sure that `i64` + // can fit each signed digit + if (2..64).contains(&w) { + let mut res = vec![]; + let mut e = self.as_u64s().1.as_ref().to_vec(); + + while !is_zero(&e) { + let z: i64; + if is_odd(&e) { + z = signed_mod_reduction(e[0], 1 << w); + if z >= 0 { + sub_with_borrow(&mut e, z as u64); + } else { + add_with_carry(&mut e, (-z) as u64); + } + } else { + z = 0; + } + res.push(z); + div2(&mut e); + } + + Some(res) + } else { + None + } + } +} + +fn is_zero(a: &[u64]) -> bool { + a.iter().all(|x| *x == 0) +} + +fn is_odd(a: &[u64]) -> bool { + a[0] % 2 == 1 +} + +fn sub_with_borrow(a: &mut [u64], b: u64) { + let mut borrow = sbb_for_sub_with_borrow(&mut a[0], b, 0); + for a in &mut a[1..] { + borrow = sbb_for_sub_with_borrow(a, 0, borrow); + } +} + +fn add_with_carry(a: &mut [u64], b: u64) { + let mut carry = adc_for_add_with_carry(&mut a[0], b, 0); + for a in &mut a[1..] { + carry = adc_for_add_with_carry(a, 0, carry); + } +} + +fn div2(a: &mut [u64]) { + let mut t = 0; + for a in a.iter_mut().rev() { + let t2 = *a << 63; + *a >>= 1; + *a |= t; + t = t2; + } } macro_rules! impl_scalar_unsigned { diff --git a/algebra-core/src/scalar_mul/wnaf.rs b/algebra-core/src/scalar_mul/wnaf.rs index b35cf5c89..d238f3fcb 100644 --- a/algebra-core/src/scalar_mul/wnaf.rs +++ b/algebra-core/src/scalar_mul/wnaf.rs @@ -1,6 +1,6 @@ use crate::{ - module::{Scalar, ScalarMul}, - AdditiveGroup, + module::{Scalar, ScalarMul, ScalarExp}, + AdditiveGroup, MultiplicativeGroup, }; use ark_std::vec::Vec; @@ -60,7 +60,7 @@ impl WnafContext { if 1 << (self.window_size - 1) > base_table.len() { return None; } - let scalar_wnaf = scalar.into_bigint().find_wnaf(self.window_size).unwrap(); + let scalar_wnaf = scalar.find_wnaf(self.window_size).unwrap(); let mut result = G::zero(); @@ -85,3 +85,72 @@ impl WnafContext { Some(result) } } + + +impl WnafContext { + pub fn multiplicative_table(&self, mut base: G) -> Vec { + let mut table = Vec::with_capacity(1 << (self.window_size - 1)); + let sqr = base.square(); + + for _ in 0..(1 << (self.window_size - 1)) { + table.push(base); + base *= &sqr; + } + table + } + + /// Computes scalar multiplication of a group element `g` by `scalar`. + /// + /// This method uses the wNAF algorithm to perform the scalar + /// multiplication; first, it uses `Self::table` to calculate an + /// appropriate table of multiples of `g`, and then uses the wNAF + /// algorithm to compute the scalar multiple. + pub fn exp, S: Scalar>(&self, g: G, scalar: &S) -> G { + let table = self.multiplicative_table(g); + self.exp_with_table(&table, scalar).unwrap() + } + + /// Computes scalar multiplication of a group element by `scalar`. + /// `base_table` holds precomputed multiples of the group element; it can be + /// generated using `Self::table`. `scalar` is an element of + /// `G::ScalarField`. + /// + /// Returns `None` if the table is too small. + pub fn exp_with_table, S: Scalar>( + &self, + base_table: &[G], + scalar: &S, + ) -> Option { + if 1 << (self.window_size - 1) > base_table.len() { + return None; + } + let scalar_wnaf = scalar.find_wnaf(self.window_size).unwrap(); + let inv_table = if G::INVERSION_IS_FAST { + vec![] + } else { + G::invert_batch(base_table) + }; + + let mut result = G::one(); + + let mut found_non_zero = false; + + for n in scalar_wnaf.iter().rev() { + if found_non_zero { + result.square_in_place(); + } + + if *n != 0 { + found_non_zero = true; + + if *n > 0 { + result *= &base_table[(n / 2) as usize]; + } else { + result *= &inv_table[(n / 2) as usize]; + } + } + } + + Some(result) + } +} \ No newline at end of file diff --git a/ff/src/fields/utils.rs b/ff/src/fields/utils.rs index e670317b3..e69de29bb 100644 --- a/ff/src/fields/utils.rs +++ b/ff/src/fields/utils.rs @@ -1,14 +0,0 @@ -/// Calculates the k-adicity of n, i.e., the number of trailing 0s in a base-k -/// representation. -pub fn k_adicity(k: u64, mut n: u64) -> u32 { - let mut r = 0; - while n > 1 { - if n % k == 0 { - r += 1; - n /= k; - } else { - return r; - } - } - r -}