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.
This commit is contained in:
Tony Arcieri 2018-07-20 14:43:31 -07:00 committed by Henry de Valence
parent f675f4cd2b
commit 10e8abf926
13 changed files with 66 additions and 21 deletions

View file

@ -15,16 +15,18 @@ env:
- TEST_COMMAND=test EXTRA_FLAGS='' FEATURES='serde' - TEST_COMMAND=test EXTRA_FLAGS='' FEATURES='serde'
# Tests building without std. We have to select a backend, so we select the one # Tests building without std. We have to select a backend, so we select the one
# most likely to be useful in an embedded environment. # 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: matrix:
exclude: exclude:
# Test the avx2 backend only on nightly # Test the avx2 backend only on nightly
- rust: stable - rust: stable
env: TEST_COMMAND=test EXTRA_FLAGS='--no-default-features' FEATURES='std avx2_backend' 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 - 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: script:
- cargo $TEST_COMMAND --features="$FEATURES" $EXTRA_FLAGS - cargo $TEST_COMMAND --features="$FEATURES" $EXTRA_FLAGS

View file

@ -61,7 +61,7 @@ serde = { version = "1.0", optional = true }
[features] [features]
nightly = ["subtle/nightly", "clear_on_drop/nightly"] nightly = ["subtle/nightly", "clear_on_drop/nightly"]
default = ["std", "u64_backend"] default = ["std", "u64_backend"]
std = ["subtle/std", "rand/std"] std = ["alloc", "subtle/std", "rand/std"]
alloc = [] alloc = []
yolocrypto = [] yolocrypto = []

View file

@ -1,9 +1,12 @@
#![cfg_attr(all(feature = "alloc", not(feature = "std")), feature(alloc))]
#![cfg_attr(feature = "nightly", feature(cfg_target_feature))] #![cfg_attr(feature = "nightly", feature(cfg_target_feature))]
#![cfg_attr(all(feature = "nightly", feature = "avx2_backend"), feature(stdsimd))] #![cfg_attr(all(feature = "nightly", feature = "avx2_backend"), feature(stdsimd))]
#![allow(unused_variables)] #![allow(unused_variables)]
#![allow(non_snake_case)] #![allow(non_snake_case)]
#![allow(dead_code)] #![allow(dead_code)]
#[cfg(all(feature = "alloc", not(feature = "std")))]
extern crate alloc;
extern crate byteorder; extern crate byteorder;
extern crate clear_on_drop; extern crate clear_on_drop;
extern crate core; extern crate core;
@ -53,6 +56,8 @@ mod field;
mod curve_models; mod curve_models;
#[path = "src/backend/mod.rs"] #[path = "src/backend/mod.rs"]
mod backend; mod backend;
#[path = "src/prelude.rs"]
mod prelude;
#[path = "src/scalar_mul/mod.rs"] #[path = "src/scalar_mul/mod.rs"]
mod scalar_mul; mod scalar_mul;

View file

@ -20,6 +20,9 @@ use scalar::Scalar;
use scalar_mul::window::{LookupTable, NafLookupTable5}; use scalar_mul::window::{LookupTable, NafLookupTable5};
use traits::{Identity, MultiscalarMul, VartimeMultiscalarMul}; use traits::{Identity, MultiscalarMul, VartimeMultiscalarMul};
#[allow(unused_imports)]
use prelude::*;
/// Multiscalar multiplication using interleaved window / Straus' /// Multiscalar multiplication using interleaved window / Straus'
/// method. See the `Straus` struct in the serial backend for more /// method. See the `Straus` struct in the serial backend for more
/// details. /// details.
@ -30,7 +33,7 @@ use traits::{Identity, MultiscalarMul, VartimeMultiscalarMul};
/// point representation on the fly. /// point representation on the fly.
pub struct Straus {} pub struct Straus {}
#[cfg(any(feature = "alloc", feature = "std"))] #[cfg(feature = "alloc")]
impl MultiscalarMul for Straus { impl MultiscalarMul for Straus {
type Point = EdwardsPoint; type Point = EdwardsPoint;
@ -68,7 +71,7 @@ impl MultiscalarMul for Straus {
} }
} }
#[cfg(any(feature = "alloc", feature = "std"))] #[cfg(feature = "alloc")]
impl VartimeMultiscalarMul for Straus { impl VartimeMultiscalarMul for Straus {
type Point = EdwardsPoint; type Point = EdwardsPoint;

View file

@ -21,6 +21,12 @@
//! `32bit` since identifiers can't start with letters, and the backends //! `32bit` since identifiers can't start with letters, and the backends
//! do use `u32`/`u64`, so this seems like a least-bad option. //! 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")] #[cfg(feature = "u32_backend")]
pub mod u32; pub mod u32;

View file

@ -115,6 +115,9 @@ use curve_models::CompletedPoint;
use curve_models::AffineNielsPoint; use curve_models::AffineNielsPoint;
use curve_models::ProjectiveNielsPoint; use curve_models::ProjectiveNielsPoint;
#[allow(unused_imports)]
use prelude::*;
use scalar_mul::window::LookupTable; use scalar_mul::window::LookupTable;
use traits::{Identity, IsIdentity}; 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 // These use the iterator's size hint and the target settings to
// forward to a specific backend implementation. // forward to a specific backend implementation.
#[cfg(any(feature = "alloc", feature = "std"))] #[cfg(feature = "alloc")]
impl MultiscalarMul for EdwardsPoint { impl MultiscalarMul for EdwardsPoint {
type Point = 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 { impl VartimeMultiscalarMul for EdwardsPoint {
type Point = EdwardsPoint; type Point = EdwardsPoint;

View file

@ -135,7 +135,7 @@ impl FieldElement {
/// Given a slice of public `FieldElements`, replace each with its inverse. /// Given a slice of public `FieldElements`, replace each with its inverse.
/// ///
/// All input `FieldElements` **MUST** be nonzero. /// All input `FieldElements` **MUST** be nonzero.
#[cfg(any(feature = "alloc", feature = "std"))] #[cfg(feature = "alloc")]
pub fn batch_invert(inputs: &mut [FieldElement]) { pub fn batch_invert(inputs: &mut [FieldElement]) {
// Montgomerys Trick and Fast Implementation of Masked AES // Montgomerys Trick and Fast Implementation of Masked AES
// Genelle, Prouff and Quisquater // Genelle, Prouff and Quisquater

View file

@ -8,10 +8,9 @@
// - Isis Agora Lovecruft <isis@patternsinthevoid.net> // - Isis Agora Lovecruft <isis@patternsinthevoid.net>
// - Henry de Valence <hdevalence@hdevalence.ca> // - Henry de Valence <hdevalence@hdevalence.ca>
#![cfg_attr(not(feature = "std"), no_std)] #![no_std]
#![cfg_attr(feature = "alloc", feature(alloc))]
#![cfg_attr(all(feature = "alloc", not(feature = "std")), feature(alloc))]
#![cfg_attr(feature = "nightly", feature(cfg_target_feature))] #![cfg_attr(feature = "nightly", feature(cfg_target_feature))]
#![cfg_attr(feature = "nightly", feature(external_doc))] #![cfg_attr(feature = "nightly", feature(external_doc))]
#![cfg_attr(all(feature = "nightly", feature = "avx2_backend"), feature(stdsimd))] #![cfg_attr(all(feature = "nightly", feature = "avx2_backend"), feature(stdsimd))]
@ -32,11 +31,14 @@
// External dependencies: // External dependencies:
//------------------------------------------------------------------------ //------------------------------------------------------------------------
#[cfg(feature = "std")] #[cfg(all(feature = "alloc", not(feature = "std")))]
extern crate core; #[macro_use]
#[cfg(feature = "alloc")]
extern crate alloc; extern crate alloc;
#[cfg(feature = "std")]
#[macro_use]
extern crate std;
extern crate rand; extern crate rand;
extern crate clear_on_drop; extern crate clear_on_drop;
extern crate byteorder; extern crate byteorder;
@ -94,5 +96,8 @@ pub(crate) mod backend;
// Internal curve models which are not part of the public API. // Internal curve models which are not part of the public API.
pub(crate) mod curve_models; 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 // Implementations of scalar mul algorithms live here
pub(crate) mod scalar_mul; pub(crate) mod scalar_mul;

View file

@ -290,6 +290,7 @@ mod test {
use constants; use constants;
use super::*; use super::*;
#[cfg(feature = "rand")]
use rand::rngs::OsRng; use rand::rngs::OsRng;
/// Test Montgomery -> Edwards on the X/Ed25519 basepoint /// Test Montgomery -> Edwards on the X/Ed25519 basepoint
@ -343,6 +344,7 @@ mod test {
assert_eq!(u18, u18_unred); assert_eq!(u18, u18_unred);
} }
#[cfg(feature = "rand")]
#[test] #[test]
fn montgomery_ladder_matches_edwards_scalarmult() { fn montgomery_ladder_matches_edwards_scalarmult() {
let mut csprng: OsRng = OsRng::new().unwrap(); let mut csprng: OsRng = OsRng::new().unwrap();

8
src/prelude.rs Normal file
View file

@ -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;

View file

@ -178,6 +178,9 @@ use subtle::Choice;
use edwards::EdwardsPoint; use edwards::EdwardsPoint;
use edwards::EdwardsBasepointTable; use edwards::EdwardsBasepointTable;
#[allow(unused_imports)]
use prelude::*;
use scalar::Scalar; use scalar::Scalar;
use curve_models::CompletedPoint; 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<CompressedRistretto> pub fn double_and_compress_batch<'a, I>(points: I) -> Vec<CompressedRistretto>
where I: IntoIterator<Item = &'a RistrettoPoint> where I: IntoIterator<Item = &'a RistrettoPoint>
{ {
@ -798,7 +801,7 @@ define_mul_variants!(LHS = Scalar, RHS = RistrettoPoint, Output = RistrettoPoint
// These use iterator combinators to unwrap the underlying points and // These use iterator combinators to unwrap the underlying points and
// forward to the EdwardsPoint implementations. // forward to the EdwardsPoint implementations.
#[cfg(any(feature = "alloc", feature = "std"))] #[cfg(feature = "alloc")]
impl MultiscalarMul for RistrettoPoint { impl MultiscalarMul for RistrettoPoint {
type Point = 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 { impl VartimeMultiscalarMul for RistrettoPoint {
type Point = RistrettoPoint; type Point = RistrettoPoint;
@ -955,6 +958,7 @@ impl Debug for RistrettoPoint {
#[cfg(all(test, feature = "stage2_build"))] #[cfg(all(test, feature = "stage2_build"))]
mod test { mod test {
#[cfg(feature = "rand")]
use rand::rngs::OsRng; use rand::rngs::OsRng;
use scalar::Scalar; use scalar::Scalar;
@ -1090,6 +1094,7 @@ mod test {
} }
} }
#[cfg(feature = "rand")]
#[test] #[test]
fn four_torsion_random() { fn four_torsion_random() {
let mut rng = OsRng::new().unwrap(); let mut rng = OsRng::new().unwrap();
@ -1152,6 +1157,7 @@ mod test {
} }
} }
#[cfg(feature = "rand")]
#[test] #[test]
fn random_roundtrip() { fn random_roundtrip() {
let mut rng = OsRng::new().unwrap(); let mut rng = OsRng::new().unwrap();
@ -1164,6 +1170,7 @@ mod test {
} }
} }
#[cfg(feature = "rand")]
#[test] #[test]
fn double_and_compress_1024_random_points() { fn double_and_compress_1024_random_points() {
let mut rng = OsRng::new().unwrap(); let mut rng = OsRng::new().unwrap();
@ -1178,6 +1185,7 @@ mod test {
} }
} }
#[cfg(feature = "rand")]
#[test] #[test]
fn random_is_valid() { fn random_is_valid() {
let mut rng = OsRng::new().unwrap(); let mut rng = OsRng::new().unwrap();

View file

@ -725,7 +725,7 @@ impl Scalar {
/// assert_eq!(scalars[3], Scalar::from(11u64).invert()); /// 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 { pub fn batch_invert(inputs: &mut [Scalar]) -> Scalar {
// This code is essentially identical to the FieldElement // This code is essentially identical to the FieldElement
// implementation, and is documented there. Unfortunately, // implementation, and is documented there. Unfortunately,

View file

@ -24,6 +24,9 @@ use traits::MultiscalarMul;
#[cfg(any(feature = "alloc", feature = "std"))] #[cfg(any(feature = "alloc", feature = "std"))]
use traits::VartimeMultiscalarMul; use traits::VartimeMultiscalarMul;
#[allow(unused_imports)]
use prelude::*;
/// Perform multiscalar multiplication by the interleaved window /// Perform multiscalar multiplication by the interleaved window
/// method, also known as Straus' method (since it was apparently /// method, also known as Straus' method (since it was apparently
/// [first published][solution] by Straus in 1964, as a solution to [a /// [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"))] #[cfg(any(feature = "alloc", feature = "std"))]
pub struct Straus {} pub struct Straus {}
#[cfg(any(feature = "alloc", feature = "std"))] #[cfg(feature = "alloc")]
impl MultiscalarMul for Straus { impl MultiscalarMul for Straus {
type Point = EdwardsPoint; type Point = EdwardsPoint;
@ -145,7 +148,7 @@ impl MultiscalarMul for Straus {
} }
} }
#[cfg(any(feature = "alloc", feature = "std"))] #[cfg(feature = "alloc")]
impl VartimeMultiscalarMul for Straus { impl VartimeMultiscalarMul for Straus {
type Point = EdwardsPoint; type Point = EdwardsPoint;