From e57778a5a81fb06787b2406dffd197107d4d47c8 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 | 10 +++++----- src/field.rs | 2 +- src/lib.rs | 17 +++++++++++------ src/montgomery.rs | 2 ++ src/prelude.rs | 8 ++++++++ src/ristretto.rs | 14 +++++++++++--- src/scalar.rs | 3 +-- src/scalar_mul/straus.rs | 7 +++++-- 13 files changed, 66 insertions(+), 25 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 3978ee5..fb71021 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 053713f..2550839 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 aa44d52..b271205 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 5f03929..74a7bb0 100644 --- a/src/edwards.rs +++ b/src/edwards.rs @@ -90,9 +90,6 @@ // affine and projective cakes and eat both of them too. #![allow(non_snake_case)] -#[cfg(feature = "alloc")] -use alloc::Vec; - use core::fmt::Debug; use core::iter::Iterator; use core::ops::{Add, Sub, Neg}; @@ -118,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}; @@ -526,7 +526,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; @@ -555,7 +555,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 938fa03..ae92d72 100644 --- a/src/field.rs +++ b/src/field.rs @@ -145,7 +145,7 @@ impl FieldElement { /// /// This function is most efficient when the batch size (slice /// length) is a power of 2. - #[cfg(any(feature = "alloc", feature = "std"))] + #[cfg(feature = "alloc")] pub fn batch_invert(inputs: &mut [FieldElement]) { // First, compute the product of all inputs using a product // tree: diff --git a/src/lib.rs b/src/lib.rs index 70f80f5..6b629c0 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 0b8450d..e8c2a11 100644 --- a/src/montgomery.rs +++ b/src/montgomery.rs @@ -284,6 +284,7 @@ mod test { use constants; use super::*; + #[cfg(feature = "rand")] use rand::rngs::OsRng; /// Test Montgomery -> Edwards on the X/Ed25519 basepoint @@ -337,6 +338,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 78cd178..8584291 100644 --- a/src/ristretto.rs +++ b/src/ristretto.rs @@ -188,6 +188,9 @@ use subtle::Choice; use edwards::EdwardsPoint; use edwards::EdwardsBasepointTable; +#[allow(unused_imports)] +use prelude::*; + use scalar::Scalar; use curve_models::CompletedPoint; @@ -420,7 +423,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 { @@ -794,7 +797,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; @@ -812,7 +815,7 @@ impl MultiscalarMul for RistrettoPoint { } } -#[cfg(any(feature = "alloc", feature = "std"))] +#[cfg(feature = "alloc")] impl VartimeMultiscalarMul for RistrettoPoint { type Point = RistrettoPoint; @@ -937,6 +940,7 @@ impl Debug for RistrettoPoint { #[cfg(all(test, feature = "stage2_build"))] mod test { + #[cfg(feature = "rand")] use rand::rngs::OsRng; use scalar::Scalar; @@ -1072,6 +1076,7 @@ mod test { } } + #[cfg(feature = "rand")] #[test] fn four_torsion_random() { let mut rng = OsRng::new().unwrap(); @@ -1134,6 +1139,7 @@ mod test { } } + #[cfg(feature = "rand")] #[test] fn random_roundtrip() { let mut rng = OsRng::new().unwrap(); @@ -1146,6 +1152,7 @@ mod test { } } + #[cfg(feature = "rand")] #[test] fn double_and_compress_1024_random_points() { let mut rng = OsRng::new().unwrap(); @@ -1160,6 +1167,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 5b67732..a97939c 100644 --- a/src/scalar.rs +++ b/src/scalar.rs @@ -328,7 +328,6 @@ impl Scalar { /// # Returns /// /// A random scalar within ℤ/lℤ. - #[cfg(feature = "std")] pub fn random(rng: &mut T) -> Self { let mut scalar_bytes = [0u8; 64]; rng.fill(&mut scalar_bytes); @@ -460,7 +459,7 @@ impl Scalar { /// assert_eq!(scalars[3], Scalar::from_u64(11).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 21bf29e..f25ba55 100644 --- a/src/scalar_mul/straus.rs +++ b/src/scalar_mul/straus.rs @@ -19,6 +19,9 @@ use scalar::Scalar; use traits::MultiscalarMul; 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 @@ -42,7 +45,7 @@ use traits::VartimeMultiscalarMul; /// [problem]: https://www.jstor.org/stable/2312273 pub struct Straus {} -#[cfg(any(feature = "alloc", feature = "std"))] +#[cfg(feature = "alloc")] impl MultiscalarMul for Straus { type Point = EdwardsPoint; @@ -139,7 +142,7 @@ impl MultiscalarMul for Straus { } } -#[cfg(any(feature = "alloc", feature = "std"))] +#[cfg(feature = "alloc")] impl VartimeMultiscalarMul for Straus { type Point = EdwardsPoint;