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'
# 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

View file

@ -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 = []

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

View file

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

View file

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

View file

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

View file

@ -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]) {
// Montgomerys Trick and Fast Implementation of Masked AES
// Genelle, Prouff and Quisquater

View file

@ -8,10 +8,9 @@
// - Isis Agora Lovecruft <isis@patternsinthevoid.net>
// - Henry de Valence <hdevalence@hdevalence.ca>
#![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;

View file

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

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::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<CompressedRistretto>
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
// 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();

View file

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

View file

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