diff --git a/src/backend/avx2/edwards.rs b/src/backend/avx2/edwards.rs index 74b0797..5aad787 100644 --- a/src/backend/avx2/edwards.rs +++ b/src/backend/avx2/edwards.rs @@ -371,40 +371,6 @@ impl From for LookupTable { } } -impl<'a, 'b> Mul<&'b Scalar> for &'a ExtendedPoint { - type Output = ExtendedPoint; - /// Scalar multiplication: compute `scalar * self`. - /// - /// Uses a window of size 4. - fn mul(self, scalar: &'b Scalar) -> ExtendedPoint { - // Construct a lookup table of [P,2P,3P,4P,5P,6P,7P,8P] - let lookup_table = LookupTable::::from(*self); - - // Setting s = scalar, compute - // - // s = s_0 + s_1*16^1 + ... + s_63*16^63, - // - // with `-8 ≤ s_i < 8` for `0 ≤ i < 63` and `-8 ≤ s_63 ≤ 8`. - let scalar_digits = scalar.to_radix_16(); - - // Compute s*P as - // - // s*P = P*(s_0 + s_1*16^1 + s_2*16^2 + ... + s_63*16^63) - // s*P = P*s_0 + P*s_1*16^1 + P*s_2*16^2 + ... + P*s_63*16^63 - // s*P = P*s_0 + 16*(P*s_1 + 16*(P*s_2 + 16*( ... + P*s_63)...)) - // - // We sum right-to-left. - let mut Q = ExtendedPoint::identity(); - for i in (0..64).rev() { - // Q = 16*Q - Q = Q.mul_by_pow_2(4); - // Q += P*s_i - Q = &Q + &lookup_table.select(scalar_digits[i]); - } - Q - } -} - #[derive(Clone)] pub struct EdwardsBasepointTable(pub [LookupTable; 32]); @@ -739,7 +705,6 @@ mod test { assert_eq!(R1.compress(), edwards::EdwardsPoint::identity().compress()); } - #[test] fn vector_addition_vs_serial_addition_vs_edwards_extendedpoint() { use constants; @@ -839,83 +804,4 @@ mod test { let P = &constants::ED25519_BASEPOINT_TABLE * &Scalar::from_u64(8475983829); doubling_test_helper(P); } - - #[test] - fn identity_trait_vs_edwards_identity() { - let id1: edwards::EdwardsPoint = ExtendedPoint::identity().into(); - let id2: edwards::EdwardsPoint = edwards::EdwardsPoint::identity(); - assert_eq!(id1.compress(), id2.compress()); - } - - #[test] - fn neg_vs_edwards_neg() { - let B: ExtendedPoint = constants::ED25519_BASEPOINT_POINT.into(); - let Bneg = -&B; - assert_eq!(edwards::EdwardsPoint::from(Bneg).compress(), - (-&constants::ED25519_BASEPOINT_POINT).compress()); - } - - #[test] - fn scalar_mul_vs_edwards_scalar_mul() { - let B: ExtendedPoint = constants::ED25519_BASEPOINT_POINT.into(); - // some random bytes - let s = Scalar::from_bits([233, 1, 233, 147, 113, 78, 244, 120, 40, 45, 103, 51, 224, 199, 189, 218, 96, 140, 211, 112, 39, 194, 73, 216, 173, 33, 102, 93, 76, 200, 84, 12]); - - let R1 = edwards::EdwardsPoint::from(&B * &s); - let R2 = &constants::ED25519_BASEPOINT_TABLE * &s; - - assert_eq!(R1.compress(), R2.compress()); - } - - #[test] - fn scalar_mul_vs_basepoint_table_scalar_mul() { - let B: ExtendedPoint = constants::ED25519_BASEPOINT_POINT.into(); - let B_table = EdwardsBasepointTable::create(&B); - // some random bytes - let s = Scalar::from_bits([233, 1, 233, 147, 113, 78, 244, 120, 40, 45, 103, 51, 224, 199, 189, 218, 96, 140, 211, 112, 39, 194, 73, 216, 173, 33, 102, 93, 76, 200, 84, 12]); - - let P1 = &B * &s; - let P2 = &B_table * &s; - - assert_eq!(edwards::EdwardsPoint::from(P1).compress(), - edwards::EdwardsPoint::from(P2).compress()); - } - - #[test] - fn multiscalar_mul_vs_adding_scalar_muls() { - let B: ExtendedPoint = constants::ED25519_BASEPOINT_POINT.into(); - let s1 = Scalar::from_bits([233, 1, 233, 147, 113, 78, 244, 120, 40, 45, 103, 51, 224, 199, 189, 218, 96, 140, 211, 112, 39, 194, 73, 216, 173, 33, 102, 93, 76, 200, 84, 12]); - let s2 = Scalar::from_bits([165, 30, 79, 89, 58, 24, 195, 245, 248, 146, 203, 236, 119, 43, 64, 119, 196, 111, 188, 251, 248, 53, 234, 59, 215, 28, 218, 13, 59, 120, 14, 4]); - - let P1 = &B * &s2; - let P2 = &B * &s1; - - let R = &(&P1 * &s1) + &(&P2 * &s2); - - let R_multiscalar = multiscalar_mul(&[s1, s2], &[P1.into(), P2.into()]); - - assert_eq!(edwards::EdwardsPoint::from(R).compress(), - R_multiscalar.compress()); - } - - mod vartime { - use super::*; - - #[test] - fn multiscalar_mul_vs_adding_scalar_muls() { - let B: ExtendedPoint = constants::ED25519_BASEPOINT_POINT.into(); - let s1 = Scalar::from_bits([233, 1, 233, 147, 113, 78, 244, 120, 40, 45, 103, 51, 224, 199, 189, 218, 96, 140, 211, 112, 39, 194, 73, 216, 173, 33, 102, 93, 76, 200, 84, 12]); - let s2 = Scalar::from_bits([165, 30, 79, 89, 58, 24, 195, 245, 248, 146, 203, 236, 119, 43, 64, 119, 196, 111, 188, 251, 248, 53, 234, 59, 215, 28, 218, 13, 59, 120, 14, 4]); - - let P1 = &B * &s2; - let P2 = &B * &s1; - - let R = &(&P1 * &s1) + &(&P2 * &s2); - - let R_multiscalar = vartime::multiscalar_mul(&[s1, s2], &[P1.into(), P2.into()]); - - assert_eq!(edwards::EdwardsPoint::from(R).compress(), - R_multiscalar.compress()); - } - } } diff --git a/src/backend/avx2/mod.rs b/src/backend/avx2/mod.rs index ebae72f..bd3e860 100644 --- a/src/backend/avx2/mod.rs +++ b/src/backend/avx2/mod.rs @@ -479,3 +479,5 @@ pub(crate) mod field; pub(crate) mod edwards; pub(crate) mod constants; + +pub(crate) mod scalar_mul; diff --git a/src/backend/avx2/scalar_mul/mod.rs b/src/backend/avx2/scalar_mul/mod.rs new file mode 100644 index 0000000..54f5214 --- /dev/null +++ b/src/backend/avx2/scalar_mul/mod.rs @@ -0,0 +1,11 @@ +// -*- mode: rust; -*- +// +// This file is part of curve25519-dalek. +// Copyright (c) 2016-2018 Isis Lovecruft, Henry de Valence +// See LICENSE for licensing information. +// +// Authors: +// - Isis Agora Lovecruft +// - Henry de Valence + +pub mod variable_base; diff --git a/src/backend/avx2/scalar_mul/variable_base.rs b/src/backend/avx2/scalar_mul/variable_base.rs new file mode 100644 index 0000000..e5261fb --- /dev/null +++ b/src/backend/avx2/scalar_mul/variable_base.rs @@ -0,0 +1,34 @@ +#![allow(non_snake_case)] + +use traits::Identity; +use scalar::Scalar; +use edwards::EdwardsPoint; +use backend::avx2::edwards::{ExtendedPoint, CachedPoint}; +use scalar_mul::window::LookupTable; + +/// Perform constant-time, variable-base scalar multiplication. +pub fn mul(point: &EdwardsPoint, scalar: &Scalar) -> EdwardsPoint { + // XXX combine these conversions + let avx2_point = ExtendedPoint::from(*point); + // Construct a lookup table of [P,2P,3P,4P,5P,6P,7P,8P] + let lookup_table = LookupTable::::from(avx2_point); + // Setting s = scalar, compute + // + // s = s_0 + s_1*16^1 + ... + s_63*16^63, + // + // with `-8 ≤ s_i < 8` for `0 ≤ i < 63` and `-8 ≤ s_63 ≤ 8`. + let scalar_digits = scalar.to_radix_16(); + // Compute s*P as + // + // s*P = P*(s_0 + s_1*16^1 + s_2*16^2 + ... + s_63*16^63) + // s*P = P*s_0 + P*s_1*16^1 + P*s_2*16^2 + ... + P*s_63*16^63 + // s*P = P*s_0 + 16*(P*s_1 + 16*(P*s_2 + 16*( ... + P*s_63)...)) + // + // We sum right-to-left. + let mut Q = ExtendedPoint::identity(); + for i in (0..64).rev() { + Q = Q.mul_by_pow_2(4); + Q = &Q + &lookup_table.select(scalar_digits[i]); + } + Q.into() +} diff --git a/src/edwards.rs b/src/edwards.rs index 439d6e6..1e2f31d 100644 --- a/src/edwards.rs +++ b/src/edwards.rs @@ -477,39 +477,16 @@ impl<'a, 'b> Mul<&'b Scalar> for &'a EdwardsPoint { /// `EdwardsBasepointTable` is approximately 4x faster. fn mul(self, scalar: &'b Scalar) -> EdwardsPoint { // If we built with AVX2, use the AVX2 backend. - #[cfg(all(feature="nightly", all(feature="avx2_backend", target_feature="avx2")))] { - use backend::avx2::edwards::ExtendedPoint; - let P_avx2 = ExtendedPoint::from(*self); - return EdwardsPoint::from(&P_avx2 * scalar); + #[cfg(all(feature="nightly", all(feature="avx2_backend", target_feature="avx2")))] + { + use backend::avx2::scalar_mul::variable_base::mul; + mul(self, scalar) } - // Otherwise, proceed as normal: - #[cfg(not(all(feature="nightly", all(feature="avx2_backend", target_feature="avx2"))))] { - // Construct a lookup table of [P,2P,3P,4P,5P,6P,7P,8P] - let lookup_table = LookupTable::::from(self); - - // Setting s = scalar, compute - // - // s = s_0 + s_1*16^1 + ... + s_63*16^63, - // - // with `-8 ≤ s_i < 8` for `0 ≤ i < 63` and `-8 ≤ s_63 ≤ 8`. - let scalar_digits = scalar.to_radix_16(); - - // Compute s*P as - // - // s*P = P*(s_0 + s_1*16^1 + s_2*16^2 + ... + s_63*16^63) - // s*P = P*s_0 + P*s_1*16^1 + P*s_2*16^2 + ... + P*s_63*16^63 - // s*P = P*s_0 + 16*(P*s_1 + 16*(P*s_2 + 16*( ... + P*s_63)...)) - // - // We sum right-to-left. - let mut Q = EdwardsPoint::identity(); - for i in (0..64).rev() { - // Q <-- 16*Q - Q = Q.mul_by_pow_2(4); - // Q <-- Q + P * s_i - Q = (&Q + &lookup_table.select(scalar_digits[i])).to_extended() - } - - Q + // Otherwise, use the serial backend: + #[cfg(not(all(feature="nightly", all(feature="avx2_backend", target_feature="avx2"))))] + { + use scalar_mul::variable_base::mul; + mul(self, scalar) } } } diff --git a/src/scalar_mul/mod.rs b/src/scalar_mul/mod.rs index bc3ef90..acb5020 100644 --- a/src/scalar_mul/mod.rs +++ b/src/scalar_mul/mod.rs @@ -9,3 +9,5 @@ // - Henry de Valence pub mod window; + +pub mod variable_base; diff --git a/src/scalar_mul/variable_base.rs b/src/scalar_mul/variable_base.rs new file mode 100644 index 0000000..9569bd5 --- /dev/null +++ b/src/scalar_mul/variable_base.rs @@ -0,0 +1,32 @@ +#![allow(non_snake_case)] + +use traits::Identity; +use scalar::Scalar; +use edwards::EdwardsPoint; +use curve_models::ProjectiveNielsPoint; +use scalar_mul::window::LookupTable; + +/// Perform constant-time, variable-base scalar multiplication. +pub(crate) fn mul(point: &EdwardsPoint, scalar: &Scalar) -> EdwardsPoint { + // Construct a lookup table of [P,2P,3P,4P,5P,6P,7P,8P] + let lookup_table = LookupTable::::from(point); + // Setting s = scalar, compute + // + // s = s_0 + s_1*16^1 + ... + s_63*16^63, + // + // with `-8 ≤ s_i < 8` for `0 ≤ i < 63` and `-8 ≤ s_63 ≤ 8`. + let scalar_digits = scalar.to_radix_16(); + // Compute s*P as + // + // s*P = P*(s_0 + s_1*16^1 + s_2*16^2 + ... + s_63*16^63) + // s*P = P*s_0 + P*s_1*16^1 + P*s_2*16^2 + ... + P*s_63*16^63 + // s*P = P*s_0 + 16*(P*s_1 + 16*(P*s_2 + 16*( ... + P*s_63)...)) + // + // We sum right-to-left. + let mut Q = EdwardsPoint::identity(); + for i in (0..64).rev() { + Q = Q.mul_by_pow_2(4); + Q = (&Q + &lookup_table.select(scalar_digits[i])).to_extended(); + } + Q +}