From 10e8abf926bc83375c1efebecce723e35df7dbfd Mon Sep 17 00:00:00 2001 From: Tony Arcieri Date: Fri, 20 Jul 2018 14:43:31 -0700 Subject: [PATCH] Unify `alloc` and `std` cargo features This change provides a common convention for using allocator-dependent features with: #![cfg(feature = "alloc")] When available, `Vec` is imported consistently as `prelude::Vec`, which means modules that need access to `Vec` can simply do: use prelude::*; and if an allocator is available, `Vec` will be in the crate prelude. This allows all `alloc` vs `std` gating to be handled in `lib.rs`, `build.rs`, and `prelude.rs` so the rest of the codebase doesn't have to do any gating whatsoever. --- .travis.yml | 8 +++++--- Cargo.toml | 2 +- build.rs | 5 +++++ src/backend/avx2/scalar_mul/straus.rs | 7 +++++-- src/backend/mod.rs | 6 ++++++ src/edwards.rs | 7 +++++-- src/field.rs | 2 +- src/lib.rs | 17 +++++++++++------ src/montgomery.rs | 2 ++ src/prelude.rs | 8 ++++++++ src/ristretto.rs | 14 +++++++++++--- src/scalar.rs | 2 +- src/scalar_mul/straus.rs | 7 +++++-- 13 files changed, 66 insertions(+), 21 deletions(-) create mode 100644 src/prelude.rs diff --git a/.travis.yml b/.travis.yml index 50e9a3c..fc5f2dc 100644 --- a/.travis.yml +++ b/.travis.yml @@ -15,16 +15,18 @@ env: - TEST_COMMAND=test EXTRA_FLAGS='' FEATURES='serde' # Tests building without std. We have to select a backend, so we select the one # most likely to be useful in an embedded environment. - - TEST_COMMAND=build EXTRA_FLAGS=--no-default-features FEATURES='u32_backend' + - TEST_COMMAND=build EXTRA_FLAGS='--no-default-features' FEATURES='u32_backend' + # Tests no_std+alloc usage using the most embedded-friendly backend + - TEST_COMMAND=test EXTRA_FLAGS='--lib --no-default-features' FEATURES='alloc u32_backend' matrix: exclude: # Test the avx2 backend only on nightly - rust: stable env: TEST_COMMAND=test EXTRA_FLAGS='--no-default-features' FEATURES='std avx2_backend' - # Test no_std only on nightly. + # Test no_std+alloc only on nightly - rust: stable - env: TEST_COMMAND=build EXTRA_FLAGS=--no-default-features FEATURES='u32_backend' + env: TEST_COMMAND=test EXTRA_FLAGS='--lib --no-default-features' FEATURES='alloc u32_backend' script: - cargo $TEST_COMMAND --features="$FEATURES" $EXTRA_FLAGS diff --git a/Cargo.toml b/Cargo.toml index 32d5783..f8b1503 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -61,7 +61,7 @@ serde = { version = "1.0", optional = true } [features] nightly = ["subtle/nightly", "clear_on_drop/nightly"] default = ["std", "u64_backend"] -std = ["subtle/std", "rand/std"] +std = ["alloc", "subtle/std", "rand/std"] alloc = [] yolocrypto = [] diff --git a/build.rs b/build.rs index e0a2da7..6295fdd 100644 --- a/build.rs +++ b/build.rs @@ -1,9 +1,12 @@ +#![cfg_attr(all(feature = "alloc", not(feature = "std")), feature(alloc))] #![cfg_attr(feature = "nightly", feature(cfg_target_feature))] #![cfg_attr(all(feature = "nightly", feature = "avx2_backend"), feature(stdsimd))] #![allow(unused_variables)] #![allow(non_snake_case)] #![allow(dead_code)] +#[cfg(all(feature = "alloc", not(feature = "std")))] +extern crate alloc; extern crate byteorder; extern crate clear_on_drop; extern crate core; @@ -53,6 +56,8 @@ mod field; mod curve_models; #[path = "src/backend/mod.rs"] mod backend; +#[path = "src/prelude.rs"] +mod prelude; #[path = "src/scalar_mul/mod.rs"] mod scalar_mul; diff --git a/src/backend/avx2/scalar_mul/straus.rs b/src/backend/avx2/scalar_mul/straus.rs index 1e40b7c..eed9084 100644 --- a/src/backend/avx2/scalar_mul/straus.rs +++ b/src/backend/avx2/scalar_mul/straus.rs @@ -20,6 +20,9 @@ use scalar::Scalar; use scalar_mul::window::{LookupTable, NafLookupTable5}; use traits::{Identity, MultiscalarMul, VartimeMultiscalarMul}; +#[allow(unused_imports)] +use prelude::*; + /// Multiscalar multiplication using interleaved window / Straus' /// method. See the `Straus` struct in the serial backend for more /// details. @@ -30,7 +33,7 @@ use traits::{Identity, MultiscalarMul, VartimeMultiscalarMul}; /// point representation on the fly. pub struct Straus {} -#[cfg(any(feature = "alloc", feature = "std"))] +#[cfg(feature = "alloc")] impl MultiscalarMul for Straus { type Point = EdwardsPoint; @@ -68,7 +71,7 @@ impl MultiscalarMul for Straus { } } -#[cfg(any(feature = "alloc", feature = "std"))] +#[cfg(feature = "alloc")] impl VartimeMultiscalarMul for Straus { type Point = EdwardsPoint; diff --git a/src/backend/mod.rs b/src/backend/mod.rs index d325715..75fa6c0 100644 --- a/src/backend/mod.rs +++ b/src/backend/mod.rs @@ -21,6 +21,12 @@ //! `32bit` since identifiers can't start with letters, and the backends //! do use `u32`/`u64`, so this seems like a least-bad option. +#[cfg(not(any(feature = "u32_backend", feature = "u64_backend", feature = "avx2_backend")))] +compile_error!( + "no curve25519-dalek backend cargo feature enabled! \ + please enable one of: u32_backend, u64_backend, avx2_backend" +); + #[cfg(feature = "u32_backend")] pub mod u32; diff --git a/src/edwards.rs b/src/edwards.rs index 97e97c9..f58b182 100644 --- a/src/edwards.rs +++ b/src/edwards.rs @@ -115,6 +115,9 @@ use curve_models::CompletedPoint; use curve_models::AffineNielsPoint; use curve_models::ProjectiveNielsPoint; +#[allow(unused_imports)] +use prelude::*; + use scalar_mul::window::LookupTable; use traits::{Identity, IsIdentity}; @@ -540,7 +543,7 @@ impl<'a, 'b> Mul<&'b EdwardsPoint> for &'a Scalar { // These use the iterator's size hint and the target settings to // forward to a specific backend implementation. -#[cfg(any(feature = "alloc", feature = "std"))] +#[cfg(feature = "alloc")] impl MultiscalarMul for EdwardsPoint { type Point = EdwardsPoint; @@ -569,7 +572,7 @@ impl MultiscalarMul for EdwardsPoint { } } -#[cfg(any(feature = "alloc", feature = "std"))] +#[cfg(feature = "alloc")] impl VartimeMultiscalarMul for EdwardsPoint { type Point = EdwardsPoint; diff --git a/src/field.rs b/src/field.rs index 9d8d041..e523df9 100644 --- a/src/field.rs +++ b/src/field.rs @@ -135,7 +135,7 @@ impl FieldElement { /// Given a slice of public `FieldElements`, replace each with its inverse. /// /// All input `FieldElements` **MUST** be nonzero. - #[cfg(any(feature = "alloc", feature = "std"))] + #[cfg(feature = "alloc")] pub fn batch_invert(inputs: &mut [FieldElement]) { // Montgomery’s Trick and Fast Implementation of Masked AES // Genelle, Prouff and Quisquater diff --git a/src/lib.rs b/src/lib.rs index c28ff31..aaf8ace 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -8,10 +8,9 @@ // - Isis Agora Lovecruft // - Henry de Valence -#![cfg_attr(not(feature = "std"), no_std)] - -#![cfg_attr(feature = "alloc", feature(alloc))] +#![no_std] +#![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))] #![cfg_attr(all(feature = "nightly", feature = "avx2_backend"), feature(stdsimd))] @@ -32,11 +31,14 @@ // External dependencies: //------------------------------------------------------------------------ -#[cfg(feature = "std")] -extern crate core; -#[cfg(feature = "alloc")] +#[cfg(all(feature = "alloc", not(feature = "std")))] +#[macro_use] extern crate alloc; +#[cfg(feature = "std")] +#[macro_use] +extern crate std; + extern crate rand; extern crate clear_on_drop; extern crate byteorder; @@ -94,5 +96,8 @@ pub(crate) mod backend; // Internal curve models which are not part of the public API. pub(crate) mod curve_models; +// Crate-local prelude (for alloc-dependent features like `Vec`) +pub(crate) mod prelude; + // Implementations of scalar mul algorithms live here pub(crate) mod scalar_mul; diff --git a/src/montgomery.rs b/src/montgomery.rs index 68b871a..fe7423b 100644 --- a/src/montgomery.rs +++ b/src/montgomery.rs @@ -290,6 +290,7 @@ mod test { use constants; use super::*; + #[cfg(feature = "rand")] use rand::rngs::OsRng; /// Test Montgomery -> Edwards on the X/Ed25519 basepoint @@ -343,6 +344,7 @@ mod test { assert_eq!(u18, u18_unred); } + #[cfg(feature = "rand")] #[test] fn montgomery_ladder_matches_edwards_scalarmult() { let mut csprng: OsRng = OsRng::new().unwrap(); diff --git a/src/prelude.rs b/src/prelude.rs new file mode 100644 index 0000000..be2f600 --- /dev/null +++ b/src/prelude.rs @@ -0,0 +1,8 @@ +//! Crate-local prelude (for alloc-dependent features like `Vec`) + +// TODO: switch to alloc::prelude +#[cfg(all(feature = "alloc", not(feature = "std")))] +pub use alloc::vec::Vec; + +#[cfg(feature = "std")] +pub use std::vec::Vec; diff --git a/src/ristretto.rs b/src/ristretto.rs index 6be5310..c0041f5 100644 --- a/src/ristretto.rs +++ b/src/ristretto.rs @@ -178,6 +178,9 @@ use subtle::Choice; use edwards::EdwardsPoint; use edwards::EdwardsBasepointTable; +#[allow(unused_imports)] +use prelude::*; + use scalar::Scalar; use curve_models::CompletedPoint; @@ -418,7 +421,7 @@ impl RistrettoPoint { /// } /// # } /// ``` - #[cfg(any(feature = "alloc", feature = "std"))] + #[cfg(feature = "alloc")] pub fn double_and_compress_batch<'a, I>(points: I) -> Vec where I: IntoIterator { @@ -798,7 +801,7 @@ define_mul_variants!(LHS = Scalar, RHS = RistrettoPoint, Output = RistrettoPoint // These use iterator combinators to unwrap the underlying points and // forward to the EdwardsPoint implementations. -#[cfg(any(feature = "alloc", feature = "std"))] +#[cfg(feature = "alloc")] impl MultiscalarMul for RistrettoPoint { type Point = RistrettoPoint; @@ -816,7 +819,7 @@ impl MultiscalarMul for RistrettoPoint { } } -#[cfg(any(feature = "alloc", feature = "std"))] +#[cfg(feature = "alloc")] impl VartimeMultiscalarMul for RistrettoPoint { type Point = RistrettoPoint; @@ -955,6 +958,7 @@ impl Debug for RistrettoPoint { #[cfg(all(test, feature = "stage2_build"))] mod test { + #[cfg(feature = "rand")] use rand::rngs::OsRng; use scalar::Scalar; @@ -1090,6 +1094,7 @@ mod test { } } + #[cfg(feature = "rand")] #[test] fn four_torsion_random() { let mut rng = OsRng::new().unwrap(); @@ -1152,6 +1157,7 @@ mod test { } } + #[cfg(feature = "rand")] #[test] fn random_roundtrip() { let mut rng = OsRng::new().unwrap(); @@ -1164,6 +1170,7 @@ mod test { } } + #[cfg(feature = "rand")] #[test] fn double_and_compress_1024_random_points() { let mut rng = OsRng::new().unwrap(); @@ -1178,6 +1185,7 @@ mod test { } } + #[cfg(feature = "rand")] #[test] fn random_is_valid() { let mut rng = OsRng::new().unwrap(); diff --git a/src/scalar.rs b/src/scalar.rs index beaaec0..7bf330d 100644 --- a/src/scalar.rs +++ b/src/scalar.rs @@ -725,7 +725,7 @@ impl Scalar { /// assert_eq!(scalars[3], Scalar::from(11u64).invert()); /// # } /// ``` - #[cfg(any(feature = "alloc", feature = "std"))] + #[cfg(feature = "alloc")] pub fn batch_invert(inputs: &mut [Scalar]) -> Scalar { // This code is essentially identical to the FieldElement // implementation, and is documented there. Unfortunately, diff --git a/src/scalar_mul/straus.rs b/src/scalar_mul/straus.rs index 8d6c109..0053570 100644 --- a/src/scalar_mul/straus.rs +++ b/src/scalar_mul/straus.rs @@ -24,6 +24,9 @@ use traits::MultiscalarMul; #[cfg(any(feature = "alloc", feature = "std"))] use traits::VartimeMultiscalarMul; +#[allow(unused_imports)] +use prelude::*; + /// Perform multiscalar multiplication by the interleaved window /// method, also known as Straus' method (since it was apparently /// [first published][solution] by Straus in 1964, as a solution to [a @@ -48,7 +51,7 @@ use traits::VartimeMultiscalarMul; #[cfg(any(feature = "alloc", feature = "std"))] pub struct Straus {} -#[cfg(any(feature = "alloc", feature = "std"))] +#[cfg(feature = "alloc")] impl MultiscalarMul for Straus { type Point = EdwardsPoint; @@ -145,7 +148,7 @@ impl MultiscalarMul for Straus { } } -#[cfg(any(feature = "alloc", feature = "std"))] +#[cfg(feature = "alloc")] impl VartimeMultiscalarMul for Straus { type Point = EdwardsPoint;