From 76a8d43a04b0ed0b523d3c3b94fae9cd9432acc4 Mon Sep 17 00:00:00 2001 From: Henry de Valence Date: Tue, 20 Mar 2018 12:10:39 -0700 Subject: [PATCH 1/9] Create a new `scalar_mul` module hierarchy. This should contain generic implementations of scalar multiplication algorithms that can be used with multiple backends. The goal is to move the existing scalar multiplication code into this submodule, then call it from the user-facing API. This can also contain code for things we can't do now, like multiscalar multiplication with precomputation. --- build.rs | 4 +++- src/backend/avx2/edwards.rs | 2 +- src/curve_models/mod.rs | 2 -- src/edwards.rs | 2 +- src/lib.rs | 8 ++++++++ src/scalar_mul/mod.rs | 11 +++++++++++ src/{curve_models => scalar_mul}/window.rs | 0 7 files changed, 24 insertions(+), 5 deletions(-) create mode 100644 src/scalar_mul/mod.rs rename src/{curve_models => scalar_mul}/window.rs (100%) diff --git a/build.rs b/build.rs index 1c8be62..5eb523b 100644 --- a/build.rs +++ b/build.rs @@ -54,6 +54,8 @@ mod field; mod curve_models; #[path="src/backend/mod.rs"] mod backend; +#[path="src/scalar_mul/mod.rs"] +mod scalar_mul; use edwards::EdwardsBasepointTable; @@ -77,9 +79,9 @@ use backend::u32::field::FieldElement32; use edwards::EdwardsBasepointTable; -use curve_models::window::LookupTable; use curve_models::AffineNielsPoint; +use scalar_mul::window::LookupTable; /// Table containing precomputed multiples of the Ed25519 basepoint \\\\(B = (x, 4/5)\\\\). pub const ED25519_BASEPOINT_TABLE: EdwardsBasepointTable = ED25519_BASEPOINT_TABLE_INNER_DOC_HIDDEN; diff --git a/src/backend/avx2/edwards.rs b/src/backend/avx2/edwards.rs index 7f564d7..74b0797 100644 --- a/src/backend/avx2/edwards.rs +++ b/src/backend/avx2/edwards.rs @@ -24,7 +24,7 @@ use subtle::Choice; use edwards; use scalar::Scalar; -use curve_models::window::LookupTable; +use scalar_mul::window::LookupTable; use traits::Identity; diff --git a/src/curve_models/mod.rs b/src/curve_models/mod.rs index 59426fa..a88c37d 100644 --- a/src/curve_models/mod.rs +++ b/src/curve_models/mod.rs @@ -135,8 +135,6 @@ use field::FieldElement; use edwards::EdwardsPoint; use traits::ValidityCheck; -pub mod window; - // ------------------------------------------------------------------------ // Internal point representations // ------------------------------------------------------------------------ diff --git a/src/edwards.rs b/src/edwards.rs index bcc4db6..439d6e6 100644 --- a/src/edwards.rs +++ b/src/edwards.rs @@ -117,7 +117,7 @@ use curve_models::CompletedPoint; use curve_models::AffineNielsPoint; use curve_models::ProjectiveNielsPoint; -use curve_models::window::LookupTable; +use scalar_mul::window::LookupTable; use traits::{Identity, IsIdentity}; use traits::ValidityCheck; diff --git a/src/lib.rs b/src/lib.rs index bb788c4..ffe0009 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -67,14 +67,19 @@ pub(crate) mod macros; // Scalar arithmetic mod l = 2^252 + ..., the order of the Ristretto group pub mod scalar; + // Point operations on the Montgomery form of Curve25519 pub mod montgomery; + // Point operations on the Edwards form of Curve25519 pub mod edwards; + // Group operations on the Ristretto group pub mod ristretto; + // Useful constants, like the Ed25519 basepoint pub mod constants; + // External (and internal) traits. pub mod traits; @@ -90,3 +95,6 @@ pub(crate) mod backend; // Internal curve models which are not part of the public API. pub(crate) mod curve_models; + +// Implementations of scalar mul algorithms live here +pub(crate) mod scalar_mul; diff --git a/src/scalar_mul/mod.rs b/src/scalar_mul/mod.rs new file mode 100644 index 0000000..bc3ef90 --- /dev/null +++ b/src/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 window; diff --git a/src/curve_models/window.rs b/src/scalar_mul/window.rs similarity index 100% rename from src/curve_models/window.rs rename to src/scalar_mul/window.rs From ac739a3edddb60d8c6fc2e71cbafdf7cdb011092 Mon Sep 17 00:00:00 2001 From: Henry de Valence Date: Mon, 26 Mar 2018 15:01:48 -0700 Subject: [PATCH 2/9] Split out constant-time variable-base scalar mul. The serial (`u32`/`u64`) implementations use a multiple curve models, passing between extended and projective coordinates when performing addition and doubling (respectively). But the AVX2 backend doesn't, so in order to write a single scalar mult implementation, we have to either abstract over the curve models or have two implementations. A generic solution is possible but extremely unreadable: the scalar mul implementation would be parameterized over the point types used by the serial implementations, with many where clauses describing how the types relate. The AVX2 types could then be substituted in the appropriate places. Instead we just duplicate the code into the `avx2` backend. --- src/backend/avx2/edwards.rs | 114 ------------------- src/backend/avx2/mod.rs | 2 + src/backend/avx2/scalar_mul/mod.rs | 11 ++ src/backend/avx2/scalar_mul/variable_base.rs | 34 ++++++ src/edwards.rs | 41 ++----- src/scalar_mul/mod.rs | 2 + src/scalar_mul/variable_base.rs | 32 ++++++ 7 files changed, 90 insertions(+), 146 deletions(-) create mode 100644 src/backend/avx2/scalar_mul/mod.rs create mode 100644 src/backend/avx2/scalar_mul/variable_base.rs create mode 100644 src/scalar_mul/variable_base.rs 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 +} From 2864a422bc2025be78413404a707d19cd66839d1 Mon Sep 17 00:00:00 2001 From: Henry de Valence Date: Mon, 26 Mar 2018 15:32:20 -0700 Subject: [PATCH 3/9] Pull out constant-time straus implementation --- src/backend/avx2/scalar_mul/mod.rs | 2 + src/backend/avx2/scalar_mul/straus.rs | 57 ++++++++++++++++++ src/edwards.rs | 74 ++++-------------------- src/scalar_mul/mod.rs | 2 + src/scalar_mul/straus.rs | 83 +++++++++++++++++++++++++++ src/scalar_mul/vartime_straus.rs | 64 +++++++++++++++++++++ 6 files changed, 219 insertions(+), 63 deletions(-) create mode 100644 src/backend/avx2/scalar_mul/straus.rs create mode 100644 src/scalar_mul/straus.rs create mode 100644 src/scalar_mul/vartime_straus.rs diff --git a/src/backend/avx2/scalar_mul/mod.rs b/src/backend/avx2/scalar_mul/mod.rs index 54f5214..f529730 100644 --- a/src/backend/avx2/scalar_mul/mod.rs +++ b/src/backend/avx2/scalar_mul/mod.rs @@ -9,3 +9,5 @@ // - Henry de Valence pub mod variable_base; + +pub mod straus; diff --git a/src/backend/avx2/scalar_mul/straus.rs b/src/backend/avx2/scalar_mul/straus.rs new file mode 100644 index 0000000..5f76abe --- /dev/null +++ b/src/backend/avx2/scalar_mul/straus.rs @@ -0,0 +1,57 @@ +// -*- 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 +#![allow(non_snake_case)] + +use core::borrow::Borrow; + +use clear_on_drop::ClearOnDrop; + +use traits::Identity; +use scalar::Scalar; +use edwards::EdwardsPoint; +use scalar_mul::window::LookupTable; +use backend::avx2::edwards::{CachedPoint, ExtendedPoint}; + +/// Perform constant-time, variable-base scalar multiplication. +pub(crate) fn multiscalar_mul(scalars: I, points: J) -> EdwardsPoint +where + I: IntoIterator, + I::Item: Borrow, + J: IntoIterator, + J::Item: Borrow, +{ + // Construct a lookup table of [P,2P,3P,4P,5P,6P,7P,8P] + // for each input point P + let lookup_tables: Vec<_> = points + .into_iter() + .map(|point| { + let avx2_point = ExtendedPoint::from(*point.borrow()); + LookupTable::::from(avx2_point) + }) + .collect(); + + let scalar_digits_vec: Vec<_> = scalars + .into_iter() + .map(|s| s.borrow().to_radix_16()) + .collect(); + // Pass ownership to a ClearOnDrop wrapper + let scalar_digits = ClearOnDrop::new(scalar_digits_vec); + + let mut Q = ExtendedPoint::identity(); + for j in (0..64).rev() { + Q = Q.mul_by_pow_2(4); + let it = scalar_digits.iter().zip(lookup_tables.iter()); + for (s_i, lookup_table_i) in it { + // Q = Q + s_{i,j} * P_i + Q = &Q + &lookup_table_i.select(s_i[j]); + } + } + Q.into() +} diff --git a/src/edwards.rs b/src/edwards.rs index 1e2f31d..42802cb 100644 --- a/src/edwards.rs +++ b/src/edwards.rs @@ -547,8 +547,6 @@ impl<'a, 'b> Mul<&'b EdwardsPoint> for &'a Scalar { /// /// assert_eq!(A1.compress(), (-A2).compress()); /// ``` -// XXX later when we do more fancy multiscalar mults, we can delegate -// based on the iter's size hint -- hdevalence #[cfg(any(feature = "alloc", feature = "std"))] pub fn multiscalar_mul(scalars: I, points: J) -> EdwardsPoint where I: IntoIterator, @@ -556,70 +554,20 @@ pub fn multiscalar_mul(scalars: I, points: J) -> EdwardsPoint J: IntoIterator, J::Item: Borrow, { - // If we built with AVX2, use the AVX2 backend. - #[cfg(all(feature="nightly", all(feature="avx2_backend", target_feature="avx2")))] { - use backend::avx2::edwards as edwards_avx2; + // XXX later when we do more fancy multiscalar mults, we can + // delegate based on the iter's size hint -- hdevalence - edwards_avx2::multiscalar_mul(scalars, points) + // If we built with AVX2, use the AVX2 backend. + #[cfg(all(feature="nightly", all(feature="avx2_backend", target_feature="avx2")))] + { + use backend::avx2::scalar_mul::straus::multiscalar_mul; + multiscalar_mul(scalars, points) } // Otherwise, proceed as normal: - #[cfg(not(all(feature="nightly", all(feature="avx2_backend", target_feature="avx2"))))] { - //assert_eq!(scalars.len(), points.len()); - - use clear_on_drop::ClearOnDrop; - - let lookup_tables_vec: Vec<_> = points.into_iter() - .map(|P| LookupTable::::from(P.borrow()) ) - .collect(); - - let lookup_tables = ClearOnDrop::new(lookup_tables_vec); - - // Setting s_i = i-th scalar, compute - // - // s_i = s_{i,0} + s_{i,1}*16^1 + ... + s_{i,63}*16^63, - // - // with `-8 ≤ s_{i,j} < 8` for `0 ≤ j < 63` and `-8 ≤ s_{i,63} ≤ 8`. - let scalar_digits_vec: Vec<_> = scalars.into_iter() - .map(|c| c.borrow().to_radix_16()) - .collect(); - - // This above puts the scalar digits into a heap-allocated Vec. - // To ensure that these are erased, pass ownership of the Vec into a - // ClearOnDrop wrapper. - let scalar_digits = ClearOnDrop::new(scalar_digits_vec); - - // Compute s_1*P_1 + ... + s_n*P_n: since - // - // s_i*P_i = P_i*(s_{i,0} + s_{i,1}*16^1 + ... + s_{i,63}*16^63) - // s_i*P_i = P_i*s_{i,0} + P_i*s_{i,1}*16^1 + ... + P_i*s_{i,63}*16^63 - // s_i*P_i = P_i*s_{i,0} + 16*(P_i*s_{i,1} + 16*( ... + 16*P_i*s_{i,63})...) - // - // we have the two-dimensional sum - // - // s_1*P_1 = P_1*s_{1,0} + 16*(P_1*s_{1,1} + 16*( ... + 16*P_1*s_{1,63})...) - // + s_2*P_2 = + P_2*s_{2,0} + 16*(P_2*s_{2,1} + 16*( ... + 16*P_2*s_{2,63})...) - // ... - // + s_n*P_n = + P_n*s_{n,0} + 16*(P_n*s_{n,1} + 16*( ... + 16*P_n*s_{n,63})...) - // - // We sum column-wise top-to-bottom, then right-to-left, - // multiplying by 16 only once per column. - // - // This provides the speedup over doing n independent scalar - // mults: we perform 63 multiplications by 16 instead of 63*n - // multiplications, saving 252*(n-1) doublings. - let mut Q = EdwardsPoint::identity(); - // XXX this impl makes no effort to be cache-aware; maybe it could be improved? - for j in (0..64).rev() { - Q = Q.mul_by_pow_2(4); - let it = scalar_digits.iter().zip(lookup_tables.iter()); - for (s_i, lookup_table_i) in it { - // R_i = s_{i,j} * P_i - let R_i = lookup_table_i.select(s_i[j]); - // Q = Q + R_i - Q = (&Q + &R_i).to_extended(); - } - } - Q + #[cfg(not(all(feature="nightly", all(feature="avx2_backend", target_feature="avx2"))))] + { + use scalar_mul::straus::multiscalar_mul; + multiscalar_mul(scalars, points) } } diff --git a/src/scalar_mul/mod.rs b/src/scalar_mul/mod.rs index acb5020..b69535d 100644 --- a/src/scalar_mul/mod.rs +++ b/src/scalar_mul/mod.rs @@ -11,3 +11,5 @@ pub mod window; pub mod variable_base; + +pub mod straus; diff --git a/src/scalar_mul/straus.rs b/src/scalar_mul/straus.rs new file mode 100644 index 0000000..e448ee9 --- /dev/null +++ b/src/scalar_mul/straus.rs @@ -0,0 +1,83 @@ +// -*- 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 +#![allow(non_snake_case)] + +use core::borrow::Borrow; + +use clear_on_drop::ClearOnDrop; + +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 multiscalar_mul(scalars: I, points: J) -> EdwardsPoint +where + I: IntoIterator, + I::Item: Borrow, + J: IntoIterator, + J::Item: Borrow, +{ + // Construct a lookup table of [P,2P,3P,4P,5P,6P,7P,8P] + // for each input point P + let lookup_tables: Vec<_> = points + .into_iter() + .map(|point| LookupTable::::from(point.borrow())) + .collect(); + + // Setting s_i = i-th scalar, compute + // + // s_i = s_{i,0} + s_{i,1}*16^1 + ... + s_{i,63}*16^63, + // + // with `-8 ≤ s_{i,j} < 8` for `0 ≤ j < 63` and `-8 ≤ s_{i,63} ≤ 8`. + // + // This puts the scalar digits into a heap-allocated Vec. + // To ensure that these are erased, pass ownership of the Vec into a + // ClearOnDrop wrapper. + let scalar_digits_vec: Vec<_> = scalars + .into_iter() + .map(|s| s.borrow().to_radix_16()) + .collect(); + let scalar_digits = ClearOnDrop::new(scalar_digits_vec); + + // Compute s_1*P_1 + ... + s_n*P_n: since + // + // s_i*P_i = P_i*(s_{i,0} + s_{i,1}*16^1 + ... + s_{i,63}*16^63) + // s_i*P_i = P_i*s_{i,0} + P_i*s_{i,1}*16^1 + ... + P_i*s_{i,63}*16^63 + // s_i*P_i = P_i*s_{i,0} + 16*(P_i*s_{i,1} + 16*( ... + 16*P_i*s_{i,63})...) + // + // we have the two-dimensional sum + // + // s_1*P_1 = P_1*s_{1,0} + 16*(P_1*s_{1,1} + 16*( ... + 16*P_1*s_{1,63})...) + // + s_2*P_2 = + P_2*s_{2,0} + 16*(P_2*s_{2,1} + 16*( ... + 16*P_2*s_{2,63})...) + // ... + // + s_n*P_n = + P_n*s_{n,0} + 16*(P_n*s_{n,1} + 16*( ... + 16*P_n*s_{n,63})...) + // + // We sum column-wise top-to-bottom, then right-to-left, + // multiplying by 16 only once per column. + // + // This provides the speedup over doing n independent scalar + // mults: we perform 63 multiplications by 16 instead of 63*n + // multiplications, saving 252*(n-1) doublings. + let mut Q = EdwardsPoint::identity(); + for j in (0..64).rev() { + Q = Q.mul_by_pow_2(4); + let it = scalar_digits.iter().zip(lookup_tables.iter()); + for (s_i, lookup_table_i) in it { + // R_i = s_{i,j} * P_i + let R_i = lookup_table_i.select(s_i[j]); + // Q = Q + R_i + Q = (&Q + &R_i).to_extended(); + } + } + Q +} diff --git a/src/scalar_mul/vartime_straus.rs b/src/scalar_mul/vartime_straus.rs new file mode 100644 index 0000000..890677b --- /dev/null +++ b/src/scalar_mul/vartime_straus.rs @@ -0,0 +1,64 @@ +// -*- 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 +#![allow(non_snake_case)] + +use core::ops::{Add, Sub}; +use core::borrow::Borrow; + +use scalar::Scalar; + +//use super::window::OddLookupTable; +use scalar_mul::window::OddLookupTable; +use traits::{Doubleable, Identity}; + +/// Perform variable-time, variable-base scalar multiplication. +pub(crate) fn multiscalar_mul( + scalars: I, + points: J, +) -> ExtendedPoint +where + I: IntoIterator, + I::Item: Borrow, + J: IntoIterator, + J::Item: Borrow, + for<'a> OddLookupTable: From<&'a ExtendedPoint>, + for<'a, 'b> &'a ExtendedPoint: Add<&'b CachedPoint, Output = CompletedPoint>, + for<'a, 'b> &'a ExtendedPoint: Sub<&'b CachedPoint, Output = CompletedPoint>, + ExtendedPoint: Identity + From + From, + ProjectivePoint: Identity + Doubleable + From, + CachedPoint: Copy, +{ + let nafs: Vec<_> = scalars + .into_iter() + .map(|c| c.borrow().non_adjacent_form()) + .collect(); + let lookup_tables: Vec<_> = points + .into_iter() + .map(|P| OddLookupTable::from(P.borrow())) + .collect(); + + let mut r = ProjectivePoint::identity(); + + for i in (0..255).rev() { + let mut t: CompletedPoint = r.double(); + + for (naf, lookup_table) in nafs.iter().zip(lookup_tables.iter()) { + if naf[i] > 0 { + t = &ExtendedPoint::from(t) + &lookup_table.select(naf[i] as usize); + } else if naf[i] < 0 { + t = &ExtendedPoint::from(t) - &lookup_table.select(-naf[i] as usize); + } + } + + r = ProjectivePoint::from(t); + } + + ExtendedPoint::from(r) +} From 2d99892eabcae205ee88cada2187ac5b5d6a0305 Mon Sep 17 00:00:00 2001 From: Henry de Valence Date: Mon, 26 Mar 2018 15:54:13 -0700 Subject: [PATCH 4/9] Pull out variable-time straus implementation --- src/backend/avx2/edwards.rs | 113 ++++-------------- src/backend/avx2/scalar_mul/mod.rs | 2 + src/backend/avx2/scalar_mul/vartime_straus.rs | 54 +++++++++ src/edwards.rs | 41 ++----- src/scalar_mul/mod.rs | 2 + src/scalar_mul/vartime_straus.rs | 30 ++--- src/scalar_mul/window.rs | 70 ++++++++--- 7 files changed, 156 insertions(+), 156 deletions(-) create mode 100644 src/backend/avx2/scalar_mul/vartime_straus.rs diff --git a/src/backend/avx2/edwards.rs b/src/backend/avx2/edwards.rs index 5aad787..0741652 100644 --- a/src/backend/avx2/edwards.rs +++ b/src/backend/avx2/edwards.rs @@ -144,7 +144,7 @@ impl<'a> Neg for &'a ExtendedPoint { } impl ExtendedPoint { - fn double(&self) -> ExtendedPoint { + pub fn double(&self) -> ExtendedPoint { unsafe { use stdsimd::vendor::_mm256_permute2x128_si256; use stdsimd::vendor::_mm256_permutevar8x32_epi32; @@ -361,6 +361,18 @@ impl<'a, 'b> Sub<&'b ExtendedPoint> for &'a ExtendedPoint { } } +impl<'a, 'b> Sub<&'b CachedPoint> for &'a ExtendedPoint { + type Output = ExtendedPoint; + + /// Implement subtraction by negating the point and adding. + /// + /// Empirically, this seems about the same cost as a custom subtraction impl (maybe because the + /// benefit is cancelled by increased code size?) + fn sub(self, other: &'b CachedPoint) -> ExtendedPoint { + self + &(-other) + } +} + impl From for LookupTable { fn from(P: ExtendedPoint) -> Self { let mut points = [CachedPoint::from(P); 8]; @@ -421,67 +433,18 @@ impl EdwardsBasepointTable { } } -/// Internal multiscalar code. -#[cfg(any(feature = "alloc", feature = "std"))] -pub fn multiscalar_mul(scalars: I, points: J) -> edwards::EdwardsPoint - where I: IntoIterator, - I::Item: Borrow, - J: IntoIterator, - J::Item: Borrow, -{ - //assert_eq!(scalars.len(), points.len()); +use scalar_mul::window::OddLookupTable; - use clear_on_drop::ClearOnDrop; - let lookup_tables_vec: Vec<_> = points.into_iter() - .map(|P| LookupTable::from(ExtendedPoint::from(*P.borrow())) ) - .collect(); - - let lookup_tables = ClearOnDrop::new(lookup_tables_vec); - - // Setting s_i = i-th scalar, compute - // - // s_i = s_{i,0} + s_{i,1}*16^1 + ... + s_{i,63}*16^63, - // - // with `-8 ≤ s_{i,j} < 8` for `0 ≤ j < 63` and `-8 ≤ s_{i,63} ≤ 8`. - let scalar_digits_vec: Vec<_> = scalars.into_iter() - .map(|c| c.borrow().to_radix_16()) - .collect(); - - // The above puts the scalar digits into a heap-allocated Vec. - // To ensure that these are erased, pass ownership of the Vec into a - // ClearOnDrop wrapper. - let scalar_digits = ClearOnDrop::new(scalar_digits_vec); - - // Compute s_1*P_1 + ... + s_n*P_n: since - // - // s_i*P_i = P_i*(s_{i,0} + s_{i,1}*16^1 + ... + s_{i,63}*16^63) - // s_i*P_i = P_i*s_{i,0} + P_i*s_{i,1}*16^1 + ... + P_i*s_{i,63}*16^63 - // s_i*P_i = P_i*s_{i,0} + 16*(P_i*s_{i,1} + 16*( ... + 16*P_i*s_{i,63})...) - // - // we have the two-dimensional sum - // - // s_1*P_1 = P_1*s_{1,0} + 16*(P_1*s_{1,1} + 16*( ... + 16*P_1*s_{1,63})...) - // + s_2*P_2 = + P_2*s_{2,0} + 16*(P_2*s_{2,1} + 16*( ... + 16*P_2*s_{2,63})...) - // ... - // + s_n*P_n = + P_n*s_{n,0} + 16*(P_n*s_{n,1} + 16*( ... + 16*P_n*s_{n,63})...) - // - // We sum column-wise top-to-bottom, then right-to-left, - // multiplying by 16 only once per column. - // - // This provides the speedup over doing n independent scalar - // mults: we perform 63 multiplications by 16 instead of 63*n - // multiplications, saving 252*(n-1) doublings. - let mut Q = ExtendedPoint::identity(); - // XXX this algorithm makes no effort to be cache-aware; maybe it could be improved? - for j in (0..64).rev() { - Q = Q.mul_by_pow_2(4); - let it = scalar_digits.iter().zip(lookup_tables.iter()); - for (s_i, lookup_table_i) in it { - // Q = Q + s_{i,j} * P_i - Q = &Q + &lookup_table_i.select(s_i[j]); +impl<'a> From<&'a ExtendedPoint> for OddLookupTable { + fn from(A: &'a ExtendedPoint) -> Self { + let mut Ai = [CachedPoint::from(*A); 8]; + let A2 = A.double(); + for i in 0..7 { + Ai[i + 1] = (&A2 + &Ai[i]).into(); } + // Now Ai = [A, 3A, 5A, 7A, 9A, 11A, 13A, 15A] + OddLookupTable(Ai) } - Q.into() } pub mod vartime { @@ -560,38 +523,6 @@ pub mod vartime { Q.into() } - - /// Internal multiscalar function - #[cfg(any(feature = "alloc", feature = "std"))] - pub fn multiscalar_mul(scalars: I, points: J) -> edwards::EdwardsPoint - where I: IntoIterator, - I::Item: Borrow, - J: IntoIterator, - J::Item: Borrow, - { - //assert_eq!(scalars.len(), points.len()); - - let nafs: Vec<_> = scalars.into_iter() - .map(|c| c.borrow().non_adjacent_form()).collect(); - - let odd_multiples: Vec<_> = points.into_iter() - .map(|P| OddMultiples::create((*P.borrow()).into()) ).collect(); - - let mut Q = ExtendedPoint::identity(); - - for i in (0..255).rev() { - Q = Q.double(); - - for (naf, odd_multiple) in nafs.iter().zip(odd_multiples.iter()) { - if naf[i] > 0 { - Q = &Q + &odd_multiple[( naf[i]/2) as usize]; - } else if naf[i] < 0 { - Q = &Q - &odd_multiple[(-naf[i]/2) as usize]; - } - } - } - Q.into() - } } #[cfg(test)] diff --git a/src/backend/avx2/scalar_mul/mod.rs b/src/backend/avx2/scalar_mul/mod.rs index f529730..3c62538 100644 --- a/src/backend/avx2/scalar_mul/mod.rs +++ b/src/backend/avx2/scalar_mul/mod.rs @@ -11,3 +11,5 @@ pub mod variable_base; pub mod straus; + +pub mod vartime_straus; diff --git a/src/backend/avx2/scalar_mul/vartime_straus.rs b/src/backend/avx2/scalar_mul/vartime_straus.rs new file mode 100644 index 0000000..c53e7d4 --- /dev/null +++ b/src/backend/avx2/scalar_mul/vartime_straus.rs @@ -0,0 +1,54 @@ +// -*- 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 +#![allow(non_snake_case)] + +use core::borrow::Borrow; + +use traits::Identity; +use scalar::Scalar; +use edwards::EdwardsPoint; +use scalar_mul::window::OddLookupTable; +use backend::avx2::edwards::{CachedPoint, ExtendedPoint}; + +/// Perform variable-time, variable-base scalar multiplication. +pub(crate) fn multiscalar_mul(scalars: I, points: J) -> EdwardsPoint +where + I: IntoIterator, + I::Item: Borrow, + J: IntoIterator, + J::Item: Borrow, +{ + let nafs: Vec<_> = scalars + .into_iter() + .map(|c| c.borrow().non_adjacent_form()) + .collect(); + let lookup_tables: Vec<_> = points + .into_iter() + .map(|point| { + let avx2_point = ExtendedPoint::from(*point.borrow()); + OddLookupTable::::from(&avx2_point) + }) + .collect(); + + let mut Q = ExtendedPoint::identity(); + + for i in (0..255).rev() { + Q = Q.double(); + + for (naf, lookup_table) in nafs.iter().zip(lookup_tables.iter()) { + if naf[i] > 0 { + Q = &Q + &lookup_table.select(naf[i] as usize); + } else if naf[i] < 0 { + Q = &Q - &lookup_table.select(-naf[i] as usize); + } + } + } + Q.into() +} diff --git a/src/edwards.rs b/src/edwards.rs index 42802cb..0fc0855 100644 --- a/src/edwards.rs +++ b/src/edwards.rs @@ -845,8 +845,6 @@ pub mod vartime { /// /// assert_eq!(A1.compress(), (-A2).compress()); /// ``` - // XXX later when we do more fancy multiscalar mults, we can delegate - // based on the iter's size hint -- hdevalence #[cfg(any(feature = "alloc", feature = "std"))] pub fn multiscalar_mul(scalars: I, points: J) -> EdwardsPoint where I: IntoIterator, @@ -854,38 +852,19 @@ pub mod vartime { J: IntoIterator, J::Item: Borrow, { + // XXX later when we do more fancy multiscalar mults, we can delegate + // based on the iter's size hint -- hdevalence // If we built with AVX2, use the AVX2 backend. - #[cfg(all(feature="nightly", all(feature="avx2_backend", target_feature="avx2")))] { - use backend::avx2::edwards as edwards_avx2; - - edwards_avx2::vartime::multiscalar_mul(scalars, points) + #[cfg(all(feature="nightly", all(feature="avx2_backend", target_feature="avx2")))] + { + use backend::avx2::scalar_mul::vartime_straus::multiscalar_mul; + multiscalar_mul(scalars, points) } // Otherwise, proceed as normal: - #[cfg(not(all(feature="nightly", all(feature="avx2_backend", target_feature="avx2"))))] { - //assert_eq!(scalars.len(), points.len()); - - let nafs: Vec<_> = scalars.into_iter() - .map(|c| c.borrow().non_adjacent_form()).collect(); - let odd_multiples: Vec<_> = points.into_iter() - .map(|P| OddMultiples::create(P.borrow())).collect(); - - let mut r = ProjectivePoint::identity(); - - for i in (0..255).rev() { - let mut t = r.double(); - - for (naf, odd_multiple) in nafs.iter().zip(odd_multiples.iter()) { - if naf[i] > 0 { - t = &t.to_extended() + &odd_multiple[( naf[i]/2) as usize]; - } else if naf[i] < 0 { - t = &t.to_extended() - &odd_multiple[(-naf[i]/2) as usize]; - } - } - - r = t.to_projective(); - } - - r.to_extended() + #[cfg(not(all(feature="nightly", all(feature="avx2_backend", target_feature="avx2"))))] + { + use scalar_mul::vartime_straus::multiscalar_mul; + multiscalar_mul(scalars, points) } } diff --git a/src/scalar_mul/mod.rs b/src/scalar_mul/mod.rs index b69535d..2f295d7 100644 --- a/src/scalar_mul/mod.rs +++ b/src/scalar_mul/mod.rs @@ -13,3 +13,5 @@ pub mod window; pub mod variable_base; pub mod straus; + +pub mod vartime_straus; diff --git a/src/scalar_mul/vartime_straus.rs b/src/scalar_mul/vartime_straus.rs index 890677b..c55ce21 100644 --- a/src/scalar_mul/vartime_straus.rs +++ b/src/scalar_mul/vartime_straus.rs @@ -9,31 +9,21 @@ // - Henry de Valence #![allow(non_snake_case)] -use core::ops::{Add, Sub}; use core::borrow::Borrow; +use traits::Identity; use scalar::Scalar; - -//use super::window::OddLookupTable; +use edwards::EdwardsPoint; +use curve_models::{CompletedPoint, ProjectivePoint, ProjectiveNielsPoint}; use scalar_mul::window::OddLookupTable; -use traits::{Doubleable, Identity}; /// Perform variable-time, variable-base scalar multiplication. -pub(crate) fn multiscalar_mul( - scalars: I, - points: J, -) -> ExtendedPoint +pub(crate) fn multiscalar_mul(scalars: I, points: J) -> EdwardsPoint where I: IntoIterator, I::Item: Borrow, J: IntoIterator, - J::Item: Borrow, - for<'a> OddLookupTable: From<&'a ExtendedPoint>, - for<'a, 'b> &'a ExtendedPoint: Add<&'b CachedPoint, Output = CompletedPoint>, - for<'a, 'b> &'a ExtendedPoint: Sub<&'b CachedPoint, Output = CompletedPoint>, - ExtendedPoint: Identity + From + From, - ProjectivePoint: Identity + Doubleable + From, - CachedPoint: Copy, + J::Item: Borrow, { let nafs: Vec<_> = scalars .into_iter() @@ -41,7 +31,7 @@ where .collect(); let lookup_tables: Vec<_> = points .into_iter() - .map(|P| OddLookupTable::from(P.borrow())) + .map(|P| OddLookupTable::::from(P.borrow())) .collect(); let mut r = ProjectivePoint::identity(); @@ -51,14 +41,14 @@ where for (naf, lookup_table) in nafs.iter().zip(lookup_tables.iter()) { if naf[i] > 0 { - t = &ExtendedPoint::from(t) + &lookup_table.select(naf[i] as usize); + t = &t.to_extended() + &lookup_table.select(naf[i] as usize); } else if naf[i] < 0 { - t = &ExtendedPoint::from(t) - &lookup_table.select(-naf[i] as usize); + t = &t.to_extended() - &lookup_table.select(-naf[i] as usize); } } - r = ProjectivePoint::from(t); + r = t.to_projective(); } - ExtendedPoint::from(r) + r.to_extended() } diff --git a/src/scalar_mul/window.rs b/src/scalar_mul/window.rs index ada3706..9b25917 100644 --- a/src/scalar_mul/window.rs +++ b/src/scalar_mul/window.rs @@ -21,6 +21,10 @@ use subtle::Choice; use traits::Identity; +use edwards::EdwardsPoint; +use curve_models::ProjectiveNielsPoint; +use curve_models::AffineNielsPoint; + /// A lookup table of precomputed multiples of a point \\(P\\), used to /// compute \\( xP \\) for \\( -8 \leq x \leq 8 \\). /// @@ -54,22 +58,24 @@ use clear_on_drop::clear::ZeroSafe; unsafe impl ZeroSafe for LookupTable {} impl LookupTable -where T: Identity + ConditionallyAssignable + ConditionallyNegatable +where + T: Identity + ConditionallyAssignable + ConditionallyNegatable, { /// Given \\(-8 \leq x \leq 8\\), return \\(xP\\) in constant time. pub fn select(&self, x: i8) -> T { - debug_assert!(x >= -8); debug_assert!(x <= 8); + debug_assert!(x >= -8); + debug_assert!(x <= 8); // Compute xabs = |x| let xmask = x >> 7; - let xabs = (x + xmask) ^ xmask; + let xabs = (x + xmask) ^ xmask; // Set t = 0 * P = identity let mut t = T::identity(); for j in 1..9 { // Copy `points[j-1] == j*P` onto `t` in constant time if `|x| == j`. let c = (xabs as u8).ct_eq(&(j as u8)); - t.conditional_assign(&self.0[j-1], c); + t.conditional_assign(&self.0[j - 1], c); } // Now t == |x| * P. @@ -93,17 +99,11 @@ impl Debug for LookupTable { } } -use edwards::EdwardsPoint; -use curve_models::ProjectiveNielsPoint; -use curve_models::AffineNielsPoint; - impl<'a> From<&'a EdwardsPoint> for LookupTable { fn from(P: &'a EdwardsPoint) -> Self { let mut points = [P.to_projective_niels(); 8]; for j in 0..7 { - points[j+1] = (P + &points[j]) - .to_extended() - .to_projective_niels(); + points[j + 1] = (P + &points[j]).to_extended().to_projective_niels(); } LookupTable(points) } @@ -114,10 +114,52 @@ impl<'a> From<&'a EdwardsPoint> for LookupTable { let mut points = [P.to_affine_niels(); 8]; // XXX batch inversion would be good if perf mattered here for j in 0..7 { - points[j+1] = (P + &points[j]) - .to_extended() - .to_affine_niels() + points[j + 1] = (P + &points[j]).to_extended().to_affine_niels() } LookupTable(points) } } + +/// Holds odd multiples 1A, 3A, ..., 15A of a point A. +#[derive(Copy, Clone)] +pub(crate) struct OddLookupTable(pub(crate) [T; 8]); + +impl OddLookupTable { + /// Given public, odd \\( x \\) with \\( 0 < x < 2^4 \\), return \\(xA\\). + pub fn select(&self, x: usize) -> T { + debug_assert_eq!(x & 1, 1); + debug_assert!(x < 16); + + self.0[x / 2] + } +} + +impl Debug for OddLookupTable { + fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result { + write!(f, "OddLookupTable({:?})", self.0) + } +} + +impl<'a> From<&'a EdwardsPoint> for OddLookupTable { + fn from(A: &'a EdwardsPoint) -> Self { + let mut Ai = [A.to_projective_niels(); 8]; + let A2 = A.double(); + for i in 0..7 { + Ai[i + 1] = (&A2 + &Ai[i]).to_extended().to_projective_niels(); + } + // Now Ai = [A, 3A, 5A, 7A, 9A, 11A, 13A, 15A] + OddLookupTable(Ai) + } +} + +impl<'a> From<&'a EdwardsPoint> for OddLookupTable { + fn from(A: &'a EdwardsPoint) -> Self { + let mut Ai = [A.to_affine_niels(); 8]; + let A2 = A.double(); + for i in 0..7 { + Ai[i + 1] = (&A2 + &Ai[i]).to_extended().to_affine_niels(); + } + // Now Ai = [A, 3A, 5A, 7A, 9A, 11A, 13A, 15A] + OddLookupTable(Ai) + } +} From 0c4e7188a07775a436ef18d859a0c685c8a7a5a0 Mon Sep 17 00:00:00 2001 From: Henry de Valence Date: Mon, 26 Mar 2018 17:02:59 -0700 Subject: [PATCH 5/9] Pull out vartime double-base scalar mul code --- build.rs | 57 +++++---- src/backend/avx2/constants.rs | 119 +++++++++--------- src/backend/avx2/edwards.rs | 78 ------------ src/backend/avx2/scalar_mul/mod.rs | 3 + .../avx2/scalar_mul/vartime_double_base.rs | 61 +++++++++ src/edwards.rs | 89 ++----------- src/scalar_mul/mod.rs | 3 + src/scalar_mul/vartime_double_base.rs | 61 +++++++++ 8 files changed, 231 insertions(+), 240 deletions(-) create mode 100644 src/backend/avx2/scalar_mul/vartime_double_base.rs create mode 100644 src/scalar_mul/vartime_double_base.rs diff --git a/build.rs b/build.rs index 5eb523b..60a9f7a 100644 --- a/build.rs +++ b/build.rs @@ -4,12 +4,12 @@ #![allow(non_snake_case)] #![allow(dead_code)] +extern crate clear_on_drop; extern crate core; -extern crate subtle; -extern crate rand; extern crate digest; extern crate generic_array; -extern crate clear_on_drop; +extern crate rand; +extern crate subtle; use std::env; use std::fs::File; @@ -27,37 +27,39 @@ extern crate serde; extern crate stdsimd; // Macros come first! -#[path="src/macros.rs"] +#[path = "src/macros.rs"] #[macro_use] mod macros; // Public modules -#[path="src/scalar.rs"] +#[path = "src/scalar.rs"] mod scalar; -#[path="src/montgomery.rs"] +#[path = "src/montgomery.rs"] mod montgomery; -#[path="src/edwards.rs"] +#[path = "src/edwards.rs"] mod edwards; -#[path="src/ristretto.rs"] +#[path = "src/ristretto.rs"] mod ristretto; -#[path="src/constants.rs"] +#[path = "src/constants.rs"] mod constants; -#[path="src/traits.rs"] +#[path = "src/traits.rs"] mod traits; // Internal modules -#[path="src/field.rs"] +#[path = "src/field.rs"] mod field; -#[path="src/curve_models/mod.rs"] +#[path = "src/curve_models/mod.rs"] mod curve_models; -#[path="src/backend/mod.rs"] +#[path = "src/backend/mod.rs"] mod backend; -#[path="src/scalar_mul/mod.rs"] +#[path = "src/scalar_mul/mod.rs"] mod scalar_mul; use edwards::EdwardsBasepointTable; +use curve_models::AffineNielsPoint; +use scalar_mul::window::OddLookupTable; fn main() { // Enable the "precomputed_tables" feature in the main build stage @@ -70,7 +72,9 @@ fn main() { // Generate a table of precomputed multiples of the basepoint let table = EdwardsBasepointTable::create(&constants::ED25519_BASEPOINT_POINT); - f.write_all(format!("\n + f.write_all( + format!( + "\n #[cfg(feature=\"radix_51\")] use backend::u64::field::FieldElement64; @@ -82,6 +86,7 @@ use edwards::EdwardsBasepointTable; use curve_models::AffineNielsPoint; use scalar_mul::window::LookupTable; +use scalar_mul::window::OddLookupTable; /// Table containing precomputed multiples of the Ed25519 basepoint \\\\(B = (x, 4/5)\\\\). pub const ED25519_BASEPOINT_TABLE: EdwardsBasepointTable = ED25519_BASEPOINT_TABLE_INNER_DOC_HIDDEN; @@ -89,18 +94,22 @@ pub const ED25519_BASEPOINT_TABLE: EdwardsBasepointTable = ED25519_BASEPOINT_TAB /// Inner constant, used to avoid filling the docs with precomputed points. #[doc(hidden)] pub const ED25519_BASEPOINT_TABLE_INNER_DOC_HIDDEN: EdwardsBasepointTable = {:?}; - \n\n", &table).as_bytes()).unwrap(); +\n\n", + &table + ).as_bytes(), + ).unwrap(); // Now generate AFFINE_ODD_MULTIPLES_OF_BASEPOINT let B = &constants::ED25519_BASEPOINT_POINT; - let B2 = B.double(); - let mut odd_multiples = [B.to_affine_niels(); 8]; - for i in 0..7 { - odd_multiples[i+1] = (&B2 + &odd_multiples[i]).to_extended().to_affine_niels(); - } + let odd_multiples = OddLookupTable::::from(B); - f.write_all(format!("\n + f.write_all( + format!( + "\n /// Odd multiples of the basepoint `[B, 3B, 5B, 7B, 9B, 11B, 13B, 15B]`. -pub(crate) const AFFINE_ODD_MULTIPLES_OF_BASEPOINT: [AffineNielsPoint; 8] = {:?}; - \n\n", &odd_multiples).as_bytes()).unwrap(); +pub(crate) const AFFINE_ODD_MULTIPLES_OF_BASEPOINT: OddLookupTable = {:?}; +\n\n", + &odd_multiples + ).as_bytes(), + ).unwrap(); } diff --git a/src/backend/avx2/constants.rs b/src/backend/avx2/constants.rs index 362b518..3fb77d8 100644 --- a/src/backend/avx2/constants.rs +++ b/src/backend/avx2/constants.rs @@ -12,8 +12,9 @@ use stdsimd::simd::u32x8; +use scalar_mul::window::OddLookupTable; use backend::avx2::field::FieldElement32x4; -use backend::avx2::edwards::ExtendedPoint; +use backend::avx2::edwards::{ExtendedPoint, CachedPoint}; /// The low limbs of (2p, 2p, 2p, 2p), so that /// ```no_run @@ -52,61 +53,61 @@ pub(crate) static P_TIMES_2_MASKED: FieldElement32x4 = FieldElement32x4([ ]); /// Odd multiples of the Ed25519 basepoint: -pub static ODD_MULTIPLES_OF_BASEPOINT: [ExtendedPoint; 8] = [ - ExtendedPoint(FieldElement32x4([ - u32x8::new(52811034, 40265304, 25909283, 26843545, 1, 28827043, 0, 27438313), - u32x8::new(16144682, 13421772, 17082669, 20132659, 0, 39759291, 0, 244362), - u32x8::new(27570973, 26843545, 30858332, 6710886, 0, 8635006, 0, 11264893), - u32x8::new(40966398, 53687091, 8378388, 13421772, 0, 19351346, 0, 13413597), - u32x8::new(20764389, 40265318, 8758491, 26843545, 0, 16611511, 0, 27139452), - ])), - ExtendedPoint(FieldElement32x4([ - u32x8::new(63703867, 19156774, 608100, 2486757, 12685460, 3173753, 21649412, 16313381), - u32x8::new(52397038, 65858675, 26775664, 16661035, 14269998, 9080558, 1059463, 28938752), - u32x8::new( 5461635, 28034025, 23358301, 1245198, 1367765, 20288887, 31111942, 18395221), - u32x8::new( 1886934, 32436996, 681756, 18977693, 8129860, 40112764, 25764567, 11876840), - u32x8::new(63042604, 52399761, 22087481, 29829870, 8565820, 33723612, 28645162, 8502864), - ])), - ExtendedPoint(FieldElement32x4([ - u32x8::new(14879397, 3951036, 9454671, 16606238, 23529732, 44147004, 11890541, 17067526), - u32x8::new(58509479, 57216664, 9671992, 32001147, 60966207, 11801823, 10808378, 15115613), - u32x8::new(54854992, 39210911, 8112050, 1353604, 1337416, 35520540, 32967851, 17786030), - u32x8::new(59007462, 40864509, 26240923, 30403852, 28456403, 21546582, 32732450, 21005910), - u32x8::new(40711675, 22446613, 9664668, 12483629, 26142305, 56254715, 15439904, 214849), - ])), - ExtendedPoint(FieldElement32x4([ - u32x8::new(52231579, 51632644, 173613, 7677257, 26374424, 45994428, 5303371, 1425942), - u32x8::new(38126791, 48854506, 23252518, 30611978, 49977504, 66706952, 1076178, 27100873), - u32x8::new(26349427, 63077566, 20258199, 3884787, 33226507, 2371423, 5787271, 18628170), - u32x8::new(15005754, 22729577, 4978944, 2522289, 1404784, 56367795, 22517039, 29271243), - u32x8::new(22748934, 35977548, 25561257, 31734126, 22775284, 32000077, 927866, 2278697), - ])), - ExtendedPoint(FieldElement32x4([ - u32x8::new(66090281, 61980626, 23780289, 6519561, 62542590, 47174086, 28818882, 15661068), - u32x8::new(17433715, 12931425, 12232056, 7885877, 44179512, 35590146, 32787344, 22631048), - u32x8::new(43729883, 6870635, 15782399, 11810556, 2652935, 31800505, 23683367, 13638649), - u32x8::new(64007953, 40242373, 32810277, 20180235, 20399465, 48133835, 32913956, 19094667), - u32x8::new(56562708, 40269142, 18953105, 9027935, 35700921, 12896915, 14757156, 22773619), - ])), - ExtendedPoint(FieldElement32x4([ - u32x8::new(65129016, 34709402, 25132940, 13788431, 3661652, 16914498, 27409409, 18941039), - u32x8::new(42488074, 49427602, 6177212, 20812339, 41644653, 2977316, 12162542, 5293661), - u32x8::new( 7981168, 12223605, 6239200, 20403609, 20710415, 4828170, 11627702, 4431044), - u32x8::new(65817142, 96824, 25021652, 16364722, 50410869, 24651857, 6979034, 33176209), - u32x8::new(33008344, 8687253, 27859668, 28796356, 30192014, 11975680, 11991047, 27710707), - ])), - ExtendedPoint(FieldElement32x4([ - u32x8::new(14676653, 50945941, 13489249, 31456262, 47726639, 21761847, 3324839, 7843947), - u32x8::new(53352326, 8688989, 12944061, 12994004, 50113821, 37990636, 1537898, 20483689), - u32x8::new(46786852, 15572264, 24004728, 7566233, 32596174, 34437796, 23201722, 3431551), - u32x8::new(49025674, 52497128, 13273618, 10266201, 66795206, 2887684, 30966565, 33449990), - u32x8::new(53210238, 65839385, 15458877, 18409918, 24777464, 25586795, 15335748, 12323382), - ])), - ExtendedPoint(FieldElement32x4([ - u32x8::new(57816016, 23106045, 24948505, 27413507, 32551424, 26145165, 22632568, 27527446), - u32x8::new(53022711, 40974949, 14110533, 30646997, 51399118, 53289754, 32528560, 15822835), - u32x8::new(23810949, 51779690, 17532625, 21326637, 60314333, 43761996, 4852905, 3474945), - u32x8::new(13323962, 10752742, 16431634, 26425049, 24258356, 53260846, 19756601, 19546842), - u32x8::new(17403634, 52199608, 32323720, 5313255, 48522162, 33376516, 31903659, 15291466), - ])), -]; +pub(crate) static BASEPOINT_ODD_LOOKUP_TABLE: OddLookupTable = + OddLookupTable([ + CachedPoint(FieldElement32x4([ + u32x8::new(3571425, 10045002, 19036563, 1096096, 243332, 65897020, 0, 28963681), + u32x8::new(30896895, 63055514, 1614915, 5095970, 0, 53791688, 0, 31258312), + u32x8::new(13347627, 40339464, 2236269, 11185503, 0, 22520087, 0, 8659512), + u32x8::new(11125413, 29139905, 32037254, 28360723, 0, 64556417, 0, 9635759), + u32x8::new(33268144, 47262491, 4336918, 15795740, 0, 22027545, 0, 4846528), + ])), + CachedPoint(FieldElement32x4([ + u32x8::new(47099681, 31447946, 29365447, 24740513, 42991046, 18317844, 16051644, 21404226), + u32x8::new(31708133, 28909527, 2366091, 13703791, 469246, 54159622, 2601402, 32988002), + u32x8::new(63432457, 30251794, 15163516, 18491340, 28144087, 35605455, 13682295, 18474872), + u32x8::new(12221607, 4967598, 26061980, 26008006, 20226147, 9726961, 17410, 18051083), + u32x8::new(60569645, 62487085, 11911242, 21920922, 4092105, 38186967, 22431483, 31366585), + ])), + CachedPoint(FieldElement32x4([ + u32x8::new(18147205, 62587998, 2554617, 536692, 11924528, 26674131, 17645433, 24341419), + u32x8::new(11573357, 27579485, 31491870, 29000885, 10800976, 51902791, 28076395, 20464029), + u32x8::new(56031649, 10856669, 11791193, 26769430, 25306956, 5922200, 6630685, 9385098), + u32x8::new(31319348, 23906711, 16290213, 32142166, 61106354, 17181823, 3548308, 12022566), + u32x8::new(5904298, 50218605, 11826440, 5492249, 10379071, 3472255, 172742, 31948344), + ])), + CachedPoint(FieldElement32x4([ + u32x8::new(10625852, 15193821, 22918394, 23676410, 53695416, 54987793, 10067515, 11747680), + u32x8::new(65013325, 1309652, 29616320, 28922974, 60360891, 19621771, 9938982, 30406429), + u32x8::new(54967954, 65931918, 5595602, 25719523, 64909864, 30566415, 15945272, 8495317), + u32x8::new(1167157, 55265018, 11507029, 31641054, 43497904, 2367338, 12937761, 27517066), + u32x8::new(656704, 2544994, 13006713, 480979, 38471594, 62541240, 25353597, 11531760), + ])), + CachedPoint(FieldElement32x4([ + u32x8::new(22176662, 3984313, 27495285, 4110608, 2909584, 30594106, 15677919, 2549183), + u32x8::new(33979105, 62269905, 2071511, 6894756, 53189950, 47232857, 6408191, 6123225), + u32x8::new(32553873, 63948030, 12612401, 3633166, 24054373, 37626618, 14481327, 8520484), + u32x8::new(56552486, 10749438, 12034813, 28811946, 1445640, 36755601, 12104575, 10257833), + u32x8::new(22795808, 48761311, 1136056, 9380768, 1411523, 5341811, 27318329, 9686767)])), + CachedPoint(FieldElement32x4([ + u32x8::new(21157200, 39156966, 20473176, 4934657, 61478183, 45121537, 5429856, 13035023), + u32x8::new(7954529, 58789246, 31440083, 7054221, 38438565, 36856107, 1364112, 14548122), + u32x8::new(26120083, 36321360, 4919997, 31687496, 33757765, 36237559, 15243054, 32163861), + u32x8::new(25878307, 46544824, 19455951, 2414935, 16844726, 56521560, 32680554, 26660660), + u32x8::new(48360220, 43407178, 12187042, 24925816, 7423722, 25746484, 12814654, 17395963), + ])), + CachedPoint(FieldElement32x4([ + u32x8::new(63153652, 32195955, 4087908, 8431689, 30392384, 47203165, 8986649, 9053039), + u32x8::new(63659241, 47988767, 2931872, 19953600, 11747107, 51610101, 20952181, 13364887), + u32x8::new(3659197, 58790649, 5930099, 2605312, 28477896, 580728, 20579735, 2610622), + u32x8::new(41781607, 17161358, 10690531, 24368015, 47027031, 36742339, 5414694, 13156365), + u32x8::new(13237853, 51182423, 8954802, 29006542, 22643989, 56896541, 22830593, 10289708), + ])), + CachedPoint(FieldElement32x4([ + u32x8::new(1401265, 58846825, 30911620, 32239180, 15391552, 15200821, 6339309, 16403588), + u32x8::new(55913797, 29541724, 1664461, 21709410, 38470488, 47097092, 17674945, 32666066), + u32x8::new(22844482, 10797709, 27548106, 31638735, 34500968, 26611503, 19727211, 13160873), + u32x8::new(31485204, 14496164, 13981208, 10276888, 5748808, 35024436, 2740987, 7479021), + u32x8::new(58541207, 14866135, 32344041, 545930, 62661488, 6941250, 27940205, 11976112), + ])), + ]); diff --git a/src/backend/avx2/edwards.rs b/src/backend/avx2/edwards.rs index 0741652..caa8322 100644 --- a/src/backend/avx2/edwards.rs +++ b/src/backend/avx2/edwards.rs @@ -447,84 +447,6 @@ impl<'a> From<&'a ExtendedPoint> for OddLookupTable { } } -pub mod vartime { - //! Variable-time operations on curve points, useful for non-secret data. - use super::*; - - /// Holds odd multiples 1A, 3A, ..., 15A of a point A. - struct OddMultiples([ExtendedPoint; 8]); - - impl OddMultiples { - fn create(A: ExtendedPoint) -> OddMultiples { - // XXX would be great to skip this initialization - let mut Ai = [A; 8]; - let A2 = A.double(); - for i in 0..7 { - Ai[i+1] = &A2 + &Ai[i]; - } - // Now Ai = [A, 3A, 5A, 7A, 9A, 11A, 13A, 15A] - OddMultiples(Ai) - } - } - - impl Index for OddMultiples { - type Output = ExtendedPoint; - - fn index(&self, _index: usize) -> &ExtendedPoint { - &(self.0[_index]) - } - } - - /// Given a point `A` and scalars `a` and `b`, compute the point - /// `aA+bB`, where `B` is the Ed25519 basepoint (i.e., `B = (x,4/5)` - /// with x positive). - /// - /// This is the same as calling the iterator-based function, but slightly faster. - pub fn double_scalar_mul_basepoint(a: &Scalar, - A: &edwards::EdwardsPoint, - b: &Scalar) -> edwards::EdwardsPoint { - let a_naf = a.non_adjacent_form(); - let b_naf = b.non_adjacent_form(); - - // Find starting index - let mut i: usize = 255; - for j in (0..255).rev() { - i = j; - if a_naf[i] != 0 || b_naf[i] != 0 { - break; - } - } - - let odd_multiples_of_A = OddMultiples::create((*A).into()); - let odd_multiples_of_B = &avx2::constants::ODD_MULTIPLES_OF_BASEPOINT; - - let mut Q = ExtendedPoint::identity(); - - loop { - Q = Q.double(); - - if a_naf[i] > 0 { - Q = &Q + &odd_multiples_of_A[( a_naf[i]/2) as usize]; - } else if a_naf[i] < 0 { - Q = &Q - &odd_multiples_of_A[(-a_naf[i]/2) as usize]; - } - - if b_naf[i] > 0 { - Q = &Q + &odd_multiples_of_B[( b_naf[i]/2) as usize]; - } else if b_naf[i] < 0 { - Q = &Q - &odd_multiples_of_B[(-b_naf[i]/2) as usize]; - } - - if i == 0 { - break; - } - i -= 1; - } - - Q.into() - } -} - #[cfg(test)] mod test { use super::*; diff --git a/src/backend/avx2/scalar_mul/mod.rs b/src/backend/avx2/scalar_mul/mod.rs index 3c62538..8b1e84e 100644 --- a/src/backend/avx2/scalar_mul/mod.rs +++ b/src/backend/avx2/scalar_mul/mod.rs @@ -10,6 +10,9 @@ pub mod variable_base; +#[cfg(feature="precomputed_tables")] +pub mod vartime_double_base; + pub mod straus; pub mod vartime_straus; diff --git a/src/backend/avx2/scalar_mul/vartime_double_base.rs b/src/backend/avx2/scalar_mul/vartime_double_base.rs new file mode 100644 index 0000000..f7703bb --- /dev/null +++ b/src/backend/avx2/scalar_mul/vartime_double_base.rs @@ -0,0 +1,61 @@ +// -*- 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 +#![allow(non_snake_case)] + +use traits::Identity; +use scalar::Scalar; +use edwards::EdwardsPoint; +use scalar_mul::window::OddLookupTable; +use backend::avx2::edwards::{CachedPoint, ExtendedPoint}; +use backend::avx2::constants::BASEPOINT_ODD_LOOKUP_TABLE; + +/// Compute \\(aA + bB\\) in variable time, where \\(B\\) is the Ed25519 basepoint. +pub fn mul(a: &Scalar, A: &EdwardsPoint, b: &Scalar) -> EdwardsPoint { + let a_naf = a.non_adjacent_form(); + let b_naf = b.non_adjacent_form(); + + // Find starting index + let mut i: usize = 255; + for j in (0..255).rev() { + i = j; + if a_naf[i] != 0 || b_naf[i] != 0 { + break; + } + } + + let avx2_A = ExtendedPoint::from(*A); + let table_A = OddLookupTable::::from(&avx2_A); + let table_B = &BASEPOINT_ODD_LOOKUP_TABLE; + + let mut Q = ExtendedPoint::identity(); + + loop { + Q = Q.double(); + + if a_naf[i] > 0 { + Q = &Q + &table_A.select(a_naf[i] as usize); + } else if a_naf[i] < 0 { + Q = &Q - &table_A.select(-a_naf[i] as usize); + } + + if b_naf[i] > 0 { + Q = &Q + &table_B.select(b_naf[i] as usize); + } else if b_naf[i] < 0 { + Q = &Q - &table_B.select(-b_naf[i] as usize); + } + + if i == 0 { + break; + } + i -= 1; + } + + Q.into() +} diff --git a/src/edwards.rs b/src/edwards.rs index 0fc0855..8487073 100644 --- a/src/edwards.rs +++ b/src/edwards.rs @@ -98,7 +98,6 @@ use core::iter::Iterator; use core::ops::{Add, Sub, Neg}; use core::ops::{AddAssign, SubAssign}; use core::ops::{Mul, MulAssign}; -use core::ops::Index; use core::borrow::Borrow; use subtle::ConditionallyAssignable; @@ -778,30 +777,6 @@ pub mod vartime { //! Variable-time operations on curve points, useful for non-secret data. use super::*; - /// Holds odd multiples 1A, 3A, ..., 15A of a point A. - struct OddMultiples([ProjectiveNielsPoint; 8]); - - impl OddMultiples { - fn create(A: &EdwardsPoint) -> OddMultiples { - let mut Ai = [ProjectiveNielsPoint::identity(); 8]; - let A2 = A.double(); - Ai[0] = A.to_projective_niels(); - for i in 0..7 { - Ai[i+1] = (&A2 + &Ai[i]).to_extended().to_projective_niels(); - } - // Now Ai = [A, 3A, 5A, 7A, 9A, 11A, 13A, 15A] - OddMultiples(Ai) - } - } - - impl Index for OddMultiples { - type Output = ProjectiveNielsPoint; - - fn index(&self, _index: usize) -> &ProjectiveNielsPoint { - &(self.0[_index]) - } - } - /// Given an iterator of public scalars and an iterator of public points, compute /// $$ /// Q = c\_1 P\_1 + \cdots + c\_n P\_n. @@ -868,66 +843,22 @@ pub mod vartime { } } - /// Given a point \\(A\\) and scalars \\(a\\) and \\(b\\), compute the point - /// \\(aA+bB\\), where \\(B\\) is the Ed25519 basepoint (i.e., \\(B = (x,4/5)\\) - /// with x positive). + /// Compute \\(aA + bB\\) in variable time, where \\(B\\) is the Ed25519 basepoint. #[cfg(feature="precomputed_tables")] - pub fn double_scalar_mul_basepoint( - a: &Scalar, - A: &EdwardsPoint, - b: &Scalar, - ) -> EdwardsPoint { + pub fn double_scalar_mul_basepoint(a: &Scalar, A: &EdwardsPoint, 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 as edwards_avx2; - - edwards_avx2::vartime::double_scalar_mul_basepoint(a, A, b) + #[cfg(all(feature="nightly", all(feature="avx2_backend", target_feature="avx2")))] + { + use backend::avx2::scalar_mul::vartime_double_base::mul; + mul(a, A, b) } // Otherwise, proceed as normal: - #[cfg(not(all(feature="nightly", all(feature="avx2_backend", target_feature="avx2"))))] { - let a_naf = a.non_adjacent_form(); - let b_naf = b.non_adjacent_form(); - - // Find starting index - let mut i: usize = 255; - for j in (0..255).rev() { - i = j; - if a_naf[i] != 0 || b_naf[i] != 0 { - break; - } - } - - let odd_multiples_of_A = OddMultiples::create(A); - let odd_multiples_of_B = &constants::AFFINE_ODD_MULTIPLES_OF_BASEPOINT; - - let mut r = ProjectivePoint::identity(); - loop { - let mut t = r.double(); - - if a_naf[i] > 0 { - t = &t.to_extended() + &odd_multiples_of_A[( a_naf[i]/2) as usize]; - } else if a_naf[i] < 0 { - t = &t.to_extended() - &odd_multiples_of_A[(-a_naf[i]/2) as usize]; - } - - if b_naf[i] > 0 { - t = &t.to_extended() + &odd_multiples_of_B[( b_naf[i]/2) as usize]; - } else if b_naf[i] < 0 { - t = &t.to_extended() - &odd_multiples_of_B[(-b_naf[i]/2) as usize]; - } - - r = t.to_projective(); - - if i == 0 { - break; - } - i -= 1; - } - - r.to_extended() + #[cfg(not(all(feature="nightly", all(feature="avx2_backend", target_feature="avx2"))))] + { + use scalar_mul::vartime_double_base::mul; + mul(a, A, b) } } - } // ------------------------------------------------------------------------ diff --git a/src/scalar_mul/mod.rs b/src/scalar_mul/mod.rs index 2f295d7..7b3cdff 100644 --- a/src/scalar_mul/mod.rs +++ b/src/scalar_mul/mod.rs @@ -12,6 +12,9 @@ pub mod window; pub mod variable_base; +#[cfg(feature="precomputed_tables")] +pub mod vartime_double_base; + pub mod straus; pub mod vartime_straus; diff --git a/src/scalar_mul/vartime_double_base.rs b/src/scalar_mul/vartime_double_base.rs new file mode 100644 index 0000000..60c51e6 --- /dev/null +++ b/src/scalar_mul/vartime_double_base.rs @@ -0,0 +1,61 @@ +// -*- 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 +#![allow(non_snake_case)] + +use constants; +use traits::Identity; +use scalar::Scalar; +use edwards::EdwardsPoint; +use curve_models::{ProjectiveNielsPoint, ProjectivePoint}; +use scalar_mul::window::OddLookupTable; + +/// Compute \\(aA + bB\\) in variable time, where \\(B\\) is the Ed25519 basepoint. +pub fn mul(a: &Scalar, A: &EdwardsPoint, b: &Scalar) -> EdwardsPoint { + let a_naf = a.non_adjacent_form(); + let b_naf = b.non_adjacent_form(); + + // Find starting index + let mut i: usize = 255; + for j in (0..255).rev() { + i = j; + if a_naf[i] != 0 || b_naf[i] != 0 { + break; + } + } + + let table_A = OddLookupTable::::from(A); + let table_B = &constants::AFFINE_ODD_MULTIPLES_OF_BASEPOINT; + + let mut r = ProjectivePoint::identity(); + loop { + let mut t = r.double(); + + if a_naf[i] > 0 { + t = &t.to_extended() + &table_A.select(a_naf[i] as usize); + } else if a_naf[i] < 0 { + t = &t.to_extended() - &table_A.select(-a_naf[i] as usize); + } + + if b_naf[i] > 0 { + t = &t.to_extended() + &table_B.select(b_naf[i] as usize); + } else if b_naf[i] < 0 { + t = &t.to_extended() - &table_B.select(-b_naf[i] as usize); + } + + r = t.to_projective(); + + if i == 0 { + break; + } + i -= 1; + } + + r.to_extended() +} From c73a0fd0d6d0177334d4c37caa51cfdc29ce0d58 Mon Sep 17 00:00:00 2001 From: Henry de Valence Date: Mon, 26 Mar 2018 17:05:54 -0700 Subject: [PATCH 6/9] Remove AVX2 fixed-base code. This was faster than the non-AVX2 code, but the serial code is already so fast that there's no reason not to use it. --- src/backend/avx2/edwards.rs | 50 ------------------------------------- 1 file changed, 50 deletions(-) diff --git a/src/backend/avx2/edwards.rs b/src/backend/avx2/edwards.rs index caa8322..9099148 100644 --- a/src/backend/avx2/edwards.rs +++ b/src/backend/avx2/edwards.rs @@ -383,56 +383,6 @@ impl From for LookupTable { } } -#[derive(Clone)] -pub struct EdwardsBasepointTable(pub [LookupTable; 32]); - -impl<'a, 'b> Mul<&'b Scalar> for &'a EdwardsBasepointTable { - type Output = ExtendedPoint; - - fn mul(self, scalar: &'b Scalar) -> ExtendedPoint { - let a = scalar.to_radix_16(); - - let tables = &self.0; - let mut P = ExtendedPoint::identity(); - - for i in (0..64).filter(|x| x % 2 == 1) { - P = &P + &tables[i/2].select(a[i]); - } - - P = P.mul_by_pow_2(4); - - for i in (0..64).filter(|x| x % 2 == 0) { - P = &P + &tables[i/2].select(a[i]); - } - - P - } -} - -impl<'a, 'b> Mul<&'a EdwardsBasepointTable> for &'b Scalar { - type Output = ExtendedPoint; - - /// Given `self` a table of precomputed multiples of the point `B`, compute `B * s`. - fn mul(self, basepoint_table: &'a EdwardsBasepointTable) -> ExtendedPoint { - basepoint_table * &self - } -} - -impl EdwardsBasepointTable { - /// Create a table of precomputed multiples of `basepoint`. - pub fn create(basepoint: &ExtendedPoint) -> EdwardsBasepointTable { - // XXX use init_with - let mut table = EdwardsBasepointTable([LookupTable::default(); 32]); - let mut P = *basepoint; - for i in 0..32 { - // P = (16^2)^i * B - table.0[i] = LookupTable::from(P); - P = P.mul_by_pow_2(8); - } - table - } -} - use scalar_mul::window::OddLookupTable; impl<'a> From<&'a ExtendedPoint> for OddLookupTable { From e8b053b28145bcca6f78d415d11a3215b10cab97 Mon Sep 17 00:00:00 2001 From: Henry de Valence Date: Mon, 26 Mar 2018 17:12:32 -0700 Subject: [PATCH 7/9] Remove AVX2 addition formulas Only the readdition formulas are actually used by scalar multiplication, so there's no reason to implement vectorized addition. --- src/backend/avx2/edwards.rs | 110 +----------------------------------- 1 file changed, 2 insertions(+), 108 deletions(-) diff --git a/src/backend/avx2/edwards.rs b/src/backend/avx2/edwards.rs index 9099148..6fa72bb 100644 --- a/src/backend/avx2/edwards.rs +++ b/src/backend/avx2/edwards.rs @@ -132,17 +132,6 @@ impl<'a> Neg for &'a CachedPoint { } } -impl<'a> Neg for &'a ExtendedPoint { - type Output = ExtendedPoint; - - fn neg(self) -> ExtendedPoint { - let mut neg = *self; - // (X Y Z T) -> (-X Y Z -T) - neg.0.negate(A_LANES | D_LANES); - neg - } -} - impl ExtendedPoint { pub fn double(&self) -> ExtendedPoint { unsafe { @@ -287,80 +276,6 @@ impl<'a, 'b> Add<&'b CachedPoint> for &'a ExtendedPoint { } } -impl<'a, 'b> Add<&'b ExtendedPoint> for &'a ExtendedPoint { - type Output = ExtendedPoint; - - /// Uses a slight tweak of the parallel unified formulas of HWCD'08 - fn add(self, other: &'b ExtendedPoint) -> ExtendedPoint { - unsafe { - use stdsimd::vendor::_mm256_permute2x128_si256; - use stdsimd::vendor::_mm256_permutevar8x32_epi32; - use stdsimd::vendor::_mm256_blend_epi32; - - let P: &FieldElement32x4 = &self.0; - let Q: &FieldElement32x4 = &other.0; - - let mut t0 = FieldElement32x4::zero(); - let mut t1 = FieldElement32x4::zero(); - - // set t0 = (X1 Y1 X2 Y2) - for i in 0..5 { - t0.0[i] = _mm256_permute2x128_si256(P.0[i].into(), Q.0[i].into(), 32).into(); - } - - // set t0 = (Y1-X1 Y1+X1 Y2-X2 Y2+X2) = (S0 S1 S2 S3) - t0.diff_sum(0xff); - - // set t1 = (S0 S1 Z1 T1) - // set t0 = (S2 S3 Z2 T2) - for i in 0..5 { - // why does this intrinsic take an i32 for the imm8 ??? - t1.0[i] = _mm256_blend_epi32(t0.0[i].into(), P.0[i].into(), (C_LANES | D_LANES) as i32).into(); - t0.0[i] = _mm256_permute2x128_si256(t0.0[i].into(), Q.0[i].into(), 49).into(); - } - - // set t2 = (S0*S2 S1*S3 Z1*Z2 T1*T2) = (S4 S5 S6 S7) - let mut t2 = &t0 * &t1; - - //// set t2 = (S8 S9 S10 S11) - // set t2 = (121666*S4 121666*S5 2*121666*S6 2*121665*S7) - // = ( S8 S9 S10 -S11) - t2.scale_by_curve_constants(); - - // set t2 = (S8 S9 -S11 S10) - t2.swap_CD(); - - // set t2 = (S9-S8 S9+S8 S10+S11 S10-S11) = (S12 S13 S15 S14) - t2.diff_sum(0xff); - - let c0 = u32x8::new(0,4,2,6,4,0,6,2); // (ABCD) -> (ACCA) - let c1 = u32x8::new(5,1,7,3,5,1,7,3); // (ABCD) -> (DBDB) - - // set t0 = (S12 S15 S15 S12) - // set t1 = (S14 S13 S14 S13) - for i in 0..5 { - t0.0[i] = _mm256_permutevar8x32_epi32(t2.0[i], c0); - t1.0[i] = _mm256_permutevar8x32_epi32(t2.0[i], c1); - } - - // return (S12*S14 S15*S13 S15*S14 S12*S13) = (X3 Y3 Z3 T3) - ExtendedPoint(&t0 * &t1) - } - } -} - -impl<'a, 'b> Sub<&'b ExtendedPoint> for &'a ExtendedPoint { - type Output = ExtendedPoint; - - /// Implement subtraction by negating the point and adding. - /// - /// Empirically, this seems about the same cost as a custom subtraction impl (maybe because the - /// benefit is cancelled by increased code size?) - fn sub(self, other: &'b ExtendedPoint) -> ExtendedPoint { - self + &(-other) - } -} - impl<'a, 'b> Sub<&'b CachedPoint> for &'a ExtendedPoint { type Output = ExtendedPoint; @@ -466,14 +381,11 @@ mod test { fn addition_test_helper(P: edwards::EdwardsPoint, Q: edwards::EdwardsPoint) { // Test the serial implementation of the parallel addition formulas let R_serial: edwards::EdwardsPoint = serial_add(P.into(), Q.into()).into(); - // Test the vector implementation of the parallel addition formulas - let R_vector: edwards::EdwardsPoint = (&ExtendedPoint::from(P) + &ExtendedPoint::from(Q)).into(); - // Test the vector implementation of the parallel subtraction formulas - let S_vector: edwards::EdwardsPoint = (&ExtendedPoint::from(P) - &ExtendedPoint::from(Q)).into(); // Test the vector implementation of the parallel readdition formulas let cached_Q = CachedPoint::from(ExtendedPoint::from(Q)); - let T_vector: edwards::EdwardsPoint = (&ExtendedPoint::from(P) + &cached_Q).into(); + let R_vector: edwards::EdwardsPoint = (&ExtendedPoint::from(P) + &cached_Q).into(); + let S_vector: edwards::EdwardsPoint = (&ExtendedPoint::from(P) - &cached_Q).into(); println!("Testing point addition:"); println!("P = {:?}", P); @@ -482,32 +394,14 @@ mod test { println!("R = P + Q = {:?}", &P + &Q); println!("R_serial = {:?}", R_serial); println!("R_vector = {:?}", R_vector); - println!("T_vector = {:?}", T_vector); println!("S = P - Q = {:?}", &P - &Q); println!("S_vector = {:?}", S_vector); assert_eq!(R_serial.compress(), (&P + &Q).compress()); assert_eq!(R_vector.compress(), (&P + &Q).compress()); - assert_eq!(T_vector.compress(), (&P + &Q).compress()); assert_eq!(S_vector.compress(), (&P - &Q).compress()); println!("OK!\n"); } - #[test] - fn sub_vs_add_minus() { - let P: ExtendedPoint = edwards::EdwardsPoint::identity().into(); - let Q: ExtendedPoint = edwards::EdwardsPoint::identity().into(); - - let mQ = -&Q; - - println!("sub"); - let R1: edwards::EdwardsPoint = (&P - &Q).into(); - println!("add neg"); - let R2: edwards::EdwardsPoint = (&P + &mQ).into(); - - assert_eq!(R2.compress(), edwards::EdwardsPoint::identity().compress()); - assert_eq!(R1.compress(), edwards::EdwardsPoint::identity().compress()); - } - #[test] fn vector_addition_vs_serial_addition_vs_edwards_extendedpoint() { use constants; From 7ef6a1e6fa0a3a94685c3c216454cb09cd093999 Mon Sep 17 00:00:00 2001 From: Henry de Valence Date: Mon, 26 Mar 2018 17:35:08 -0700 Subject: [PATCH 8/9] Reorganize AVX2 point code --- src/backend/avx2/edwards.rs | 128 +++++++++--------- src/backend/avx2/scalar_mul/straus.rs | 5 +- src/backend/avx2/scalar_mul/variable_base.rs | 4 +- .../avx2/scalar_mul/vartime_double_base.rs | 3 +- src/backend/avx2/scalar_mul/vartime_straus.rs | 5 +- 5 files changed, 68 insertions(+), 77 deletions(-) diff --git a/src/backend/avx2/edwards.rs b/src/backend/avx2/edwards.rs index 6fa72bb..c9da1ea 100644 --- a/src/backend/avx2/edwards.rs +++ b/src/backend/avx2/edwards.rs @@ -24,7 +24,7 @@ use subtle::Choice; use edwards; use scalar::Scalar; -use scalar_mul::window::LookupTable; +use scalar_mul::window::{LookupTable, OddLookupTable}; use traits::Identity; @@ -76,62 +76,6 @@ impl Identity for ExtendedPoint { } } -/// A cached point with some precomputed variables used for readdition. -#[derive(Copy, Clone, Debug)] -pub struct CachedPoint(pub(super) FieldElement32x4); - -impl From for CachedPoint { - fn from(P: ExtendedPoint) -> CachedPoint { - let mut x = P.0; - - // x = (S2 S3 Z2 T2) - x.diff_sum(0b00001111); - - // x = (121666*S2 121666*S3 2*121666*Z2 2*121665*T2) - x.scale_by_curve_constants(); - - // x = (121666*S2 121666*S3 2*121666*Z2 -2*121665*T2) - x.negate(D_LANES); - - CachedPoint(x) - } -} - -impl Default for CachedPoint { - fn default() -> CachedPoint { - CachedPoint::identity() - } -} - -impl Identity for CachedPoint { - fn identity() -> CachedPoint { - CachedPoint(FieldElement32x4([ - u32x8::new(121647, 121666, 0, 0, 243332, 67108845, 0, 33554431), - u32x8::new(67108864, 0, 33554431, 0, 0, 67108863, 0, 33554431), - u32x8::new(67108863, 0, 33554431, 0, 0, 67108863, 0, 33554431), - u32x8::new(67108863, 0, 33554431, 0, 0, 67108863, 0, 33554431), - u32x8::new(67108863, 0, 33554431, 0, 0, 67108863, 0, 33554431), - ])) - } -} - -impl ConditionallyAssignable for CachedPoint { - fn conditional_assign(&mut self, other: &CachedPoint, choice: Choice) { - self.0.conditional_assign(&other.0, choice); - } -} - -impl<'a> Neg for &'a CachedPoint { - type Output = CachedPoint; - - fn neg(self) -> CachedPoint { - let mut neg = *self; - neg.0.swap_AB(); - neg.0.negate_lazy(D_LANES); - neg - } -} - impl ExtendedPoint { pub fn double(&self) -> ExtendedPoint { unsafe { @@ -236,6 +180,62 @@ impl ExtendedPoint { } } +/// A cached point with some precomputed variables used for readdition. +#[derive(Copy, Clone, Debug)] +pub struct CachedPoint(pub(super) FieldElement32x4); + +impl From for CachedPoint { + fn from(P: ExtendedPoint) -> CachedPoint { + let mut x = P.0; + + // x = (S2 S3 Z2 T2) + x.diff_sum(0b00001111); + + // x = (121666*S2 121666*S3 2*121666*Z2 2*121665*T2) + x.scale_by_curve_constants(); + + // x = (121666*S2 121666*S3 2*121666*Z2 -2*121665*T2) + x.negate(D_LANES); + + CachedPoint(x) + } +} + +impl Default for CachedPoint { + fn default() -> CachedPoint { + CachedPoint::identity() + } +} + +impl Identity for CachedPoint { + fn identity() -> CachedPoint { + CachedPoint(FieldElement32x4([ + u32x8::new(121647, 121666, 0, 0, 243332, 67108845, 0, 33554431), + u32x8::new(67108864, 0, 33554431, 0, 0, 67108863, 0, 33554431), + u32x8::new(67108863, 0, 33554431, 0, 0, 67108863, 0, 33554431), + u32x8::new(67108863, 0, 33554431, 0, 0, 67108863, 0, 33554431), + u32x8::new(67108863, 0, 33554431, 0, 0, 67108863, 0, 33554431), + ])) + } +} + +impl ConditionallyAssignable for CachedPoint { + fn conditional_assign(&mut self, other: &CachedPoint, choice: Choice) { + self.0.conditional_assign(&other.0, choice); + } +} + +impl<'a> Neg for &'a CachedPoint { + type Output = CachedPoint; + + fn neg(self) -> CachedPoint { + let mut neg = *self; + neg.0.swap_AB(); + neg.0.negate_lazy(D_LANES); + neg + } +} + impl<'a, 'b> Add<&'b CachedPoint> for &'a ExtendedPoint { type Output = ExtendedPoint; @@ -288,8 +288,9 @@ impl<'a, 'b> Sub<&'b CachedPoint> for &'a ExtendedPoint { } } -impl From for LookupTable { - fn from(P: ExtendedPoint) -> Self { +impl<'a> From<&'a edwards::EdwardsPoint> for LookupTable { + fn from(point: &'a edwards::EdwardsPoint) -> Self { + let P = ExtendedPoint::from(*point); let mut points = [CachedPoint::from(P); 8]; for i in 0..7 { points[i+1] = (&P + &points[i]).into(); @@ -298,11 +299,10 @@ impl From for LookupTable { } } -use scalar_mul::window::OddLookupTable; - -impl<'a> From<&'a ExtendedPoint> for OddLookupTable { - fn from(A: &'a ExtendedPoint) -> Self { - let mut Ai = [CachedPoint::from(*A); 8]; +impl<'a> From<&'a edwards::EdwardsPoint> for OddLookupTable { + fn from(point: &'a edwards::EdwardsPoint) -> Self { + let A = ExtendedPoint::from(*point); + let mut Ai = [CachedPoint::from(A); 8]; let A2 = A.double(); for i in 0..7 { Ai[i + 1] = (&A2 + &Ai[i]).into(); diff --git a/src/backend/avx2/scalar_mul/straus.rs b/src/backend/avx2/scalar_mul/straus.rs index 5f76abe..59e123e 100644 --- a/src/backend/avx2/scalar_mul/straus.rs +++ b/src/backend/avx2/scalar_mul/straus.rs @@ -31,10 +31,7 @@ where // for each input point P let lookup_tables: Vec<_> = points .into_iter() - .map(|point| { - let avx2_point = ExtendedPoint::from(*point.borrow()); - LookupTable::::from(avx2_point) - }) + .map(|point| LookupTable::::from(point.borrow())) .collect(); let scalar_digits_vec: Vec<_> = scalars diff --git a/src/backend/avx2/scalar_mul/variable_base.rs b/src/backend/avx2/scalar_mul/variable_base.rs index e5261fb..6f36bc7 100644 --- a/src/backend/avx2/scalar_mul/variable_base.rs +++ b/src/backend/avx2/scalar_mul/variable_base.rs @@ -8,10 +8,8 @@ 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); + let lookup_table = LookupTable::::from(point); // Setting s = scalar, compute // // s = s_0 + s_1*16^1 + ... + s_63*16^63, diff --git a/src/backend/avx2/scalar_mul/vartime_double_base.rs b/src/backend/avx2/scalar_mul/vartime_double_base.rs index f7703bb..1ba09f1 100644 --- a/src/backend/avx2/scalar_mul/vartime_double_base.rs +++ b/src/backend/avx2/scalar_mul/vartime_double_base.rs @@ -30,8 +30,7 @@ pub fn mul(a: &Scalar, A: &EdwardsPoint, b: &Scalar) -> EdwardsPoint { } } - let avx2_A = ExtendedPoint::from(*A); - let table_A = OddLookupTable::::from(&avx2_A); + let table_A = OddLookupTable::::from(A); let table_B = &BASEPOINT_ODD_LOOKUP_TABLE; let mut Q = ExtendedPoint::identity(); diff --git a/src/backend/avx2/scalar_mul/vartime_straus.rs b/src/backend/avx2/scalar_mul/vartime_straus.rs index c53e7d4..224713d 100644 --- a/src/backend/avx2/scalar_mul/vartime_straus.rs +++ b/src/backend/avx2/scalar_mul/vartime_straus.rs @@ -31,10 +31,7 @@ where .collect(); let lookup_tables: Vec<_> = points .into_iter() - .map(|point| { - let avx2_point = ExtendedPoint::from(*point.borrow()); - OddLookupTable::::from(&avx2_point) - }) + .map(|point| OddLookupTable::::from(point.borrow())) .collect(); let mut Q = ExtendedPoint::identity(); From 4a648df7130ec16e62ca77bd4183694a9cd00fc4 Mon Sep 17 00:00:00 2001 From: Henry de Valence Date: Mon, 26 Mar 2018 17:58:31 -0700 Subject: [PATCH 9/9] Feature-gate multiscalar impls on alloc --- src/backend/avx2/scalar_mul/mod.rs | 2 ++ src/scalar_mul/mod.rs | 2 ++ 2 files changed, 4 insertions(+) diff --git a/src/backend/avx2/scalar_mul/mod.rs b/src/backend/avx2/scalar_mul/mod.rs index 8b1e84e..c4c944b 100644 --- a/src/backend/avx2/scalar_mul/mod.rs +++ b/src/backend/avx2/scalar_mul/mod.rs @@ -13,6 +13,8 @@ pub mod variable_base; #[cfg(feature="precomputed_tables")] pub mod vartime_double_base; +#[cfg(any(feature = "alloc", feature = "std"))] pub mod straus; +#[cfg(any(feature = "alloc", feature = "std"))] pub mod vartime_straus; diff --git a/src/scalar_mul/mod.rs b/src/scalar_mul/mod.rs index 7b3cdff..f172788 100644 --- a/src/scalar_mul/mod.rs +++ b/src/scalar_mul/mod.rs @@ -15,6 +15,8 @@ pub mod variable_base; #[cfg(feature="precomputed_tables")] pub mod vartime_double_base; +#[cfg(any(feature = "alloc", feature = "std"))] pub mod straus; +#[cfg(any(feature = "alloc", feature = "std"))] pub mod vartime_straus;