From 47a164da4dfe732ef23ec9a0f06c8300e9284c3f Mon Sep 17 00:00:00 2001 From: Henry de Valence Date: Sat, 24 Nov 2018 13:12:20 -0800 Subject: [PATCH] Replace `avx2_backend` with `simd_backend` (autoselects AVX2/IFMA) --- Cargo.toml | 8 ++--- build.rs | 12 ++++++-- src/backend/mod.rs | 10 +++---- src/backend/vector/mod.rs | 10 ++++--- src/edwards.rs | 61 ++++++++++++++------------------------- src/lib.rs | 24 ++++++++------- 6 files changed, 60 insertions(+), 65 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 6c7ea30..fea904c 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -69,10 +69,10 @@ yolocrypto = [] u32_backend = [] # The u64 backend uses u64s with u128 products. u64_backend = [] -# The AVX2 backend uses u32x8s with u64x4 products. -# It uses the u64 code for serial operations. -avx2_backend = ["nightly", "u64_backend", "packed_simd"] -ifma_backend = ["nightly", "u64_backend", "packed_simd", "yolocrypto"] +# The SIMD backend uses parallel formulas, using either AVX2 or AVX512-IFMA. +simd_backend = ["nightly", "u64_backend", "packed_simd"] +# Old name for the SIMD backend, preserved for compatibility +avx2_backend = ["simd_backend"] # Signals that we're in the main build stage. This is off by default, # to signal stage 1 of the build, where build.rs loads the library diff --git a/build.rs b/build.rs index e684b37..f24e47b 100644 --- a/build.rs +++ b/build.rs @@ -1,5 +1,11 @@ -#![cfg_attr(feature = "ifma_backend", feature(simd_ffi))] -#![cfg_attr(feature = "ifma_backend", feature(link_llvm_intrinsics))] +#![cfg_attr( + all(feature = "simd_backend", target_feature = "avx512ifma"), + feature(simd_ffi) +)] +#![cfg_attr( + all(feature = "simd_backend", target_feature = "avx512ifma"), + feature(link_llvm_intrinsics) +)] #![cfg_attr(all(feature = "alloc", not(feature = "std")), feature(alloc))] #![cfg_attr(feature = "nightly", feature(cfg_target_feature))] #![allow(unused_variables)] @@ -15,7 +21,7 @@ extern crate digest; extern crate rand; extern crate subtle; -#[cfg(all(feature = "nightly", any(feature = "avx2_backend", feature = "ifma_backend")))] +#[cfg(all(feature = "nightly", feature = "packed_simd"))] extern crate packed_simd; use std::env; diff --git a/src/backend/mod.rs b/src/backend/mod.rs index 82eeb5b..c088c23 100644 --- a/src/backend/mod.rs +++ b/src/backend/mod.rs @@ -24,17 +24,17 @@ #[cfg(not(any( feature = "u32_backend", feature = "u64_backend", - feature = "avx2_backend" + feature = "simd_backend", )))] compile_error!( "no curve25519-dalek backend cargo feature enabled! \ - please enable one of: u32_backend, u64_backend, avx2_backend" + please enable one of: u32_backend, u64_backend, simd_backend" ); pub mod serial; -#[cfg(any( - all(feature = "ifma_backend", target_feature = "avx512ifma"), - all(feature = "avx2_backend", target_feature = "avx2"), +#[cfg(all( + feature = "simd_backend", + any(target_feature = "avx2", target_feature = "avx512ifma") ))] pub mod vector; diff --git a/src/backend/vector/mod.rs b/src/backend/vector/mod.rs index e7749f2..5975301 100644 --- a/src/backend/vector/mod.rs +++ b/src/backend/vector/mod.rs @@ -21,15 +21,17 @@ //! `32bit` since identifiers can't start with letters, and the backends //! do use `u32`/`u64`, so this seems like a least-bad option. -#[cfg(all(feature = "avx2_backend", target_feature = "avx2"))] +#[cfg(not(any(target_feature = "avx2", target_feature = "avx512ifma",)))] +compile_error!("simd_backend selected without target_feature=+avx2 or +avx512ifma"); + +#[cfg(all(target_feature = "avx2", not(target_feature = "avx512ifma")))] pub mod avx2; -#[cfg(all(feature = "avx2_backend", target_feature = "avx2"))] +#[cfg(all(target_feature = "avx2", not(target_feature = "avx512ifma")))] pub(crate) use self::avx2::{ constants::BASEPOINT_ODD_LOOKUP_TABLE, edwards::CachedPoint, edwards::ExtendedPoint, }; -#[cfg(all(feature = "ifma_backend", target_feature = "avx512ifma"))] +#[cfg(all(target_feature = "avx512ifma"))] pub mod ifma; pub mod scalar_mul; - diff --git a/src/edwards.rs b/src/edwards.rs index dbaa1c3..a56822f 100644 --- a/src/edwards.rs +++ b/src/edwards.rs @@ -130,6 +130,17 @@ use traits::MultiscalarMul; #[cfg(any(feature = "alloc", feature = "std"))] use traits::VartimeMultiscalarMul; +#[cfg(not(all( + feature = "simd_backend", + any(target_feature = "avx2", target_feature = "avx512ifma") +)))] +use backend::serial::scalar_mul; +#[cfg(all( + feature = "simd_backend", + any(target_feature = "avx2", target_feature = "avx512ifma") +))] +use backend::vector::scalar_mul; + // ------------------------------------------------------------------------ // Compressed points // ------------------------------------------------------------------------ @@ -572,18 +583,7 @@ impl<'a, 'b> Mul<&'b Scalar> for &'a EdwardsPoint { /// For scalar multiplication of a basepoint, /// `EdwardsBasepointTable` is approximately 4x faster. fn mul(self, scalar: &'b Scalar) -> EdwardsPoint { - // If we built with AVX2, use the AVX2 backend. - #[cfg(all(feature="avx2_backend", target_feature="avx2"))] - { - use backend::vector::scalar_mul::variable_base::mul; - mul(self, scalar) - } - // Otherwise, use the serial backend: - #[cfg(not(all(feature="avx2_backend", target_feature="avx2")))] - { - use backend::serial::scalar_mul::variable_base::mul; - mul(self, scalar) - } + scalar_mul::variable_base::mul(self, scalar) } } @@ -609,7 +609,7 @@ impl<'a, 'b> Mul<&'b EdwardsPoint> for &'a Scalar { #[cfg(feature = "alloc")] impl MultiscalarMul for EdwardsPoint { type Point = EdwardsPoint; - + fn multiscalar_mul(scalars: I, points: J) -> EdwardsPoint where I: IntoIterator, @@ -634,21 +634,14 @@ impl MultiscalarMul for EdwardsPoint { // size-dependent algorithm dispatch, use this as the hint. let _size = s_lo; - // If we built with AVX2, use the AVX2 backend. - #[cfg(all(feature="avx2_backend", target_feature="avx2"))] - use backend::vector::scalar_mul::straus::Straus; - // Otherwise, proceed as normal: - #[cfg(not(all(feature="avx2_backend", target_feature="avx2")))] - use backend::serial::scalar_mul::straus::Straus; - - Straus::multiscalar_mul(scalars, points) + scalar_mul::straus::Straus::multiscalar_mul(scalars, points) } } #[cfg(feature = "alloc")] impl VartimeMultiscalarMul for EdwardsPoint { type Point = EdwardsPoint; - + fn optional_multiscalar_mul(scalars: I, points: J) -> Option where I: IntoIterator, @@ -672,29 +665,19 @@ impl VartimeMultiscalarMul for EdwardsPoint { // size-dependent algorithm dispatch, use this as the hint. let _size = s_lo; - // If we built with AVX2, use the AVX2 backend. - #[cfg(all(feature="avx2_backend", target_feature="avx2"))] - use backend::vector::scalar_mul::straus::Straus; - // Otherwise, proceed as normal: - #[cfg(not(all(feature="avx2_backend", target_feature="avx2")))] - use backend::serial::scalar_mul::straus::Straus; - - Straus::optional_multiscalar_mul(scalars, points) + scalar_mul::straus::Straus::optional_multiscalar_mul(scalars, points) } } impl EdwardsPoint { /// Compute \\(aA + bB\\) in variable time, where \\(B\\) is the Ed25519 basepoint. #[cfg(feature = "stage2_build")] - pub fn vartime_double_scalar_mul_basepoint(a: &Scalar, A: &EdwardsPoint, b: &Scalar) -> EdwardsPoint { - // If we built with AVX2, use the AVX2 backend. - #[cfg(all(feature="avx2_backend", target_feature="avx2"))] - use backend::vector::scalar_mul::vartime_double_base; - // Otherwise, use the serial backend: - #[cfg(not(all(feature="avx2_backend", target_feature="avx2")))] - use backend::serial::scalar_mul::vartime_double_base; - - vartime_double_base::mul(a, A, b) + pub fn vartime_double_scalar_mul_basepoint( + a: &Scalar, + A: &EdwardsPoint, + b: &Scalar, + ) -> EdwardsPoint { + scalar_mul::vartime_double_base::mul(a, A, b) } } diff --git a/src/lib.rs b/src/lib.rs index 07a91be..cd3b583 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -9,14 +9,18 @@ // - Henry de Valence #![no_std] - -#![cfg_attr(feature = "ifma_backend", feature(simd_ffi))] -#![cfg_attr(feature = "ifma_backend", feature(link_llvm_intrinsics))] - +#![cfg_attr( + all(feature = "simd_backend", target_feature = "avx512ifma"), + feature(simd_ffi) +)] +#![cfg_attr( + all(feature = "simd_backend", target_feature = "avx512ifma"), + feature(link_llvm_intrinsics) +)] +#![cfg_attr(feature = "nightly", feature(test))] #![cfg_attr(all(feature = "alloc", not(feature = "std")), feature(alloc))] #![cfg_attr(feature = "nightly", feature(cfg_target_feature))] #![cfg_attr(feature = "nightly", feature(external_doc))] - // Refuse to compile if documentation is missing, but only on nightly. // // This means that missing docs will still fail CI, but means we can use @@ -41,21 +45,21 @@ extern crate alloc; #[macro_use] extern crate std; -#[cfg(all(feature = "nightly", any(feature = "avx2_backend", feature = "ifma_backend")))] +#[cfg(all(feature = "nightly", feature = "packed_simd"))] extern crate packed_simd; -extern crate rand; -extern crate clear_on_drop; extern crate byteorder; +extern crate clear_on_drop; pub extern crate digest; +extern crate rand; // Used for traits related to constant-time code. extern crate subtle; -#[cfg(feature = "serde")] -extern crate serde; #[cfg(all(test, feature = "serde"))] extern crate bincode; +#[cfg(feature = "serde")] +extern crate serde; // Internal macros. Must come first! #[macro_use]