diff --git a/Cargo.toml b/Cargo.toml index 3ca54f9..4d195cb 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -32,14 +32,13 @@ version = "0.3" [dependencies.digest] version = "0.4" +[dependencies.subtle] +version = "^0.1" + [dependencies.generic-array] # same version that digest depends on version = "^0.6" -[dependencies.num-traits] -optional = true -version = "^0.1" - [dev-dependencies.sha2] version = "0.4" @@ -49,7 +48,7 @@ version = "0.6" [features] nightly = ["radix_51"] default = ["std"] -std = ["rand", "num-traits"] +std = ["rand"] yolocrypto = [] bench = [] # Radix-51 arithmetic using u128 diff --git a/src/decaf.rs b/src/decaf.rs index 08abe89..2b489b0 100644 --- a/src/decaf.rs +++ b/src/decaf.rs @@ -620,10 +620,15 @@ impl CTAssignable for DecafPoint { /// # Example /// /// ``` + /// # extern crate subtle; + /// # extern crate curve25519_dalek; + /// # + /// # use subtle::CTAssignable; + /// # /// # use curve25519_dalek::curve::Identity; /// # use curve25519_dalek::decaf::DecafPoint; - /// # use curve25519_dalek::subtle::CTAssignable; /// # use curve25519_dalek::constants; + /// # fn main() { /// let A = DecafPoint::identity(); /// let B = constants::DECAF_ED25519_BASEPOINT; /// @@ -633,6 +638,7 @@ impl CTAssignable for DecafPoint { /// assert!(P == A); /// P.conditional_assign(&B, 1u8); /// assert!(P == B); + /// # } /// ``` fn conditional_assign(&mut self, other: &DecafPoint, choice: u8) { self.0.X.conditional_assign(&other.0.X, choice); diff --git a/src/field.rs b/src/field.rs index e1dda92..bcf8d17 100644 --- a/src/field.rs +++ b/src/field.rs @@ -340,25 +340,33 @@ impl CTAssignable for FieldElement { /// If `choice == 0`, replace `self` with `self`: /// /// ``` + /// # extern crate subtle; + /// # extern crate curve25519_dalek; /// # use curve25519_dalek::field::FieldElement; - /// # use curve25519_dalek::subtle::CTAssignable; + /// # use subtle::CTAssignable; + /// # fn main() { /// let f = FieldElement([1,1,1,1,1,1,1,1,1,1]); /// let g = FieldElement([2,2,2,2,2,2,2,2,2,2]); /// let mut h = FieldElement([1,1,1,1,1,1,1,1,1,1]); /// h.conditional_assign(&g, 0); /// assert!(h == f); + /// # } /// ``` /// /// If `choice == 1`, replace `self` with `f`: /// /// ``` + /// # extern crate subtle; + /// # extern crate curve25519_dalek; /// # use curve25519_dalek::field::FieldElement; - /// # use curve25519_dalek::subtle::CTAssignable; + /// # use subtle::CTAssignable; + /// # fn main() { /// # let f = FieldElement([1,1,1,1,1,1,1,1,1,1]); /// # let g = FieldElement([2,2,2,2,2,2,2,2,2,2]); /// # let mut h = FieldElement([1,1,1,1,1,1,1,1,1,1]); /// h.conditional_assign(&g, 1); /// assert!(h == g); + /// # } /// ``` /// /// # Preconditions diff --git a/src/lib.rs b/src/lib.rs index ac8522e..2a15780 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -47,6 +47,7 @@ extern crate arrayref; extern crate generic_array; extern crate digest; +extern crate subtle; #[cfg(feature = "serde")] extern crate serde; @@ -59,9 +60,6 @@ extern crate core; #[cfg(feature = "std")] extern crate rand; -#[cfg(feature = "std")] -extern crate num_traits; - #[cfg(not(feature = "std"))] extern crate collections; @@ -75,9 +73,8 @@ pub mod curve; #[cfg(feature = "yolocrypto")] pub mod decaf; -// Constant-time functions and other miscelaneous utilities. +// Other miscelaneous utilities. -pub mod subtle; pub mod utils; // Low-level curve and point constants, as well as pre-computed curve group elements. diff --git a/src/scalar.rs b/src/scalar.rs index ed38c0d..e8beab7 100644 --- a/src/scalar.rs +++ b/src/scalar.rs @@ -158,8 +158,11 @@ impl CTAssignable for Scalar { /// Conditionally assign another Scalar to this one. /// /// ``` + /// # extern crate curve25519_dalek; + /// # extern crate subtle; /// # use curve25519_dalek::scalar::Scalar; - /// # use curve25519_dalek::subtle::CTAssignable; + /// # use subtle::CTAssignable; + /// # fn main() { /// let a = Scalar([0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /// 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0]); /// let b = Scalar([1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, @@ -169,6 +172,7 @@ impl CTAssignable for Scalar { /// assert!(t[0] == a[0]); /// t.conditional_assign(&b, 1u8); /// assert!(t[0] == b[0]); + /// # } /// ``` /// /// # Preconditions diff --git a/src/subtle.rs b/src/subtle.rs deleted file mode 100644 index b29b635..0000000 --- a/src/subtle.rs +++ /dev/null @@ -1,274 +0,0 @@ -// -*- mode: rust; -*- -// -// To the extent possible under law, the authors have waived all copyright and -// related or neighboring rights to curve25519-dalek, using the Creative -// Commons "CC0" public domain dedication. See -// for full details. -// -// Authors: -// - Isis Agora Lovecruft -// - Henry de Valence - -//! Constant-time traits and utility functions. - -#[cfg(feature = "std")] -use core::ops::BitAnd; -#[cfg(feature = "std")] -use core::ops::BitOr; -#[cfg(feature = "std")] -use core::ops::Not; -#[cfg(feature = "std")] -use core::ops::Sub; - -use core::ops::Neg; - -#[cfg(feature = "std")] -use num_traits::One; -#[cfg(feature = "std")] -use num_traits::Signed; - - -/// Trait for items which can be conditionally assigned in constant time. -pub trait CTAssignable { - /// If `choice == 1u8`, assign `other` to `self`. - /// Otherwise, leave `self` unchanged. - /// Executes in constant time. - fn conditional_assign(&mut self, other: &Self, choice: u8); -} - -/// Trait for items whose equality to another item may be tested in constant time. -pub trait CTEq { - /// Determine if two items are equal in constant time. - /// - /// # Returns - /// - /// `1u8` if the two items are equal, and `0u8` otherwise. - fn ct_eq(&self, other: &Self) -> u8; -} - -/// Trait for items which can be conditionally negated in constant time. -/// -/// Note: it is not necessary to implement this trait, as a generic -/// implementation is provided. -pub trait CTNegatable { - /// Conditionally negate an element if `choice == 1u8`. - fn conditional_negate(&mut self, choice: u8); -} - -impl CTNegatable for T - where T: CTAssignable, for<'a> &'a T: Neg -{ - fn conditional_negate(&mut self, choice: u8) { - // Need to cast to eliminate mutability - let self_neg: T = -(self as &T); - self.conditional_assign(&self_neg, choice); - } -} - -/// Select `a` if `choice == 1` or select `b` if `choice == 0`, in constant time. -/// -/// # Inputs -/// -/// * `a`, `b`, and `choice` must be types for which bitwise-AND, and -/// bitwise-OR, bitwise-complement, subtraction, multiplicative identity, -/// copying, partial equality, and partial order comparison are defined. -/// * `choice`: If `choice` is equal to the multiplicative identity of the type -/// (i.e. `1u8` for `u8`, etc.), then `a` is returned. If `choice` is equal -/// to the additive identity (i.e. `0u8` for `u8`, etc.) then `b` is returned. -/// -/// # Warning -/// -/// The behaviour of this function is undefined if `choice` is something other -/// than a multiplicative identity or additive identity (i.e. `1u8` or `0u8`). -/// -/// If you somehow manage to design a type which is not a signed integer, and -/// yet implements all the requisite trait bounds for this generic, it's your -/// problem if something breaks. -/// -/// # Examples -/// -/// This function should work for signed integer types: -/// -/// ``` -/// # extern crate curve25519_dalek; -/// # use curve25519_dalek::subtle::conditional_select; -/// # fn main() { -/// let a: i32 = 5; -/// let b: i32 = 13; -/// -/// assert!(conditional_select(a, b, 0) == 13); -/// assert!(conditional_select(a, b, 1) == 5); -/// -/// let c: i64 = 2343249123; -/// let d: i64 = 8723884895; -/// -/// assert!(conditional_select(c, d, 0) == d); -/// assert!(conditional_select(c, d, 1) == c); -/// # } -/// ``` -/// -/// It does not work with `i128`s, however, because the `num` crate doesn't -/// implement `num::traits::Signed` for `i128`. -/// -/// # TODO -/// -/// Once `#[feature(specialization)]` is finished, we should rewrite this. Or -/// find some other way to only implement it for types which we know work -/// correctly. -#[inline(always)] -#[cfg(feature = "std")] -pub fn conditional_select(a: T, b: T, choice: T) -> T - where T: PartialEq + PartialOrd + Copy + - One + Signed + Sub + Not + - BitAnd + BitOr { - (!(choice - T::one()) & a) | ((choice - T::one()) & b) -} - -/// Check equality of two bytes in constant time. -/// -/// # Return -/// -/// Returns `1u8` if `a == b` and `0u8` otherwise. -/// -/// # Examples -/// -/// ``` -/// # extern crate curve25519_dalek; -/// # use curve25519_dalek::subtle::bytes_equal; -/// # fn main() { -/// let a: u8 = 0xDE; -/// let b: u8 = 0xAD; -/// -/// assert_eq!(bytes_equal(a, b), 0); -/// assert_eq!(bytes_equal(a, a), 1); -/// # } -/// ``` -#[inline(always)] -pub fn bytes_equal(a: u8, b: u8) -> u8 { - let mut x: u8; - - x = !(a ^ b); - x &= x >> 4; - x &= x >> 2; - x &= x >> 1; - x -} - -/// Test if a byte is non-zero in constant time. -/// -/// ``` -/// # extern crate curve25519_dalek; -/// # use curve25519_dalek::subtle::byte_is_nonzero; -/// # fn main() { -/// let mut x: u8; -/// x = 0; -/// assert!(byte_is_nonzero(x) == 0); -/// x = 3; -/// assert!(byte_is_nonzero(x) == 1); -/// # } -/// ``` -/// -/// # Return -/// -/// * If b != 0, returns 1u8. -/// * If b == 0, returns 0u8. -#[inline(always)] -pub fn byte_is_nonzero(b: u8) -> u8 { - let mut x = b; - x |= x >> 4; - x |= x >> 2; - x |= x >> 1; - (x & 1) -} - -/// Check equality of two arrays, `a` and `b`, in constant time. -/// -/// There is an `assert!` that the two arrays are of equal length. For -/// example, the following code will panic: -/// -/// ```rust,ignore -/// let a: [u8; 3] = [0, 0, 0]; -/// let b: [u8; 4] = [0, 0, 0, 0]; -/// -/// assert!(arrays_equal(&a, &b) == 1); -/// ``` -/// -/// However, if the arrays are equal length, but their contents do *not* match, -/// `0u8` will be returned: -/// -/// ``` -/// # extern crate curve25519_dalek; -/// # use curve25519_dalek::subtle::arrays_equal; -/// # fn main() { -/// let a: [u8; 3] = [0, 1, 2]; -/// let b: [u8; 3] = [1, 2, 3]; -/// -/// assert!(arrays_equal(&a, &b) == 0); -/// # } -/// ``` -/// -/// And finally, if the contents *do* match, `1u8` is returned: -/// -/// ``` -/// # extern crate curve25519_dalek; -/// # use curve25519_dalek::subtle::arrays_equal; -/// # fn main() { -/// let a: [u8; 3] = [0, 1, 2]; -/// let b: [u8; 3] = [0, 1, 2]; -/// -/// assert!(arrays_equal(&a, &b) == 1); -/// # } -/// ``` -/// -/// This function is commonly used in various cryptographic applications, such -/// as [signature verification](https://github.com/isislovecruft/ed25519-dalek/blob/0.3.2/src/ed25519.rs#L280), -/// among many other applications. -/// -/// # Return -/// -/// Returns `1u8` if `a == b` and `0u8` otherwise. -#[inline(always)] -pub fn arrays_equal(a: &[u8], b: &[u8]) -> u8 { - assert_eq!(a.len(), b.len()); - - let mut x: u8 = 0; - - for i in 0 .. a.len() { - x |= a[i] ^ b[i]; - } - bytes_equal(x, 0) -} - -#[cfg(test)] -mod test { - use super::*; - - #[test] - #[should_panic] - fn arrays_equal_different_lengths() { - let a: [u8; 3] = [0, 0, 0]; - let b: [u8; 4] = [0, 0, 0, 0]; - - assert!(arrays_equal(&a, &b) == 1); - } - - #[test] - #[cfg(feature = "std")] - fn conditional_select_i32() { - let a: i32 = 5; - let b: i32 = 13; - - assert_eq!(conditional_select(a, b, 0), 13); - assert_eq!(conditional_select(a, b, 1), 5); - } - - #[test] - #[cfg(feature = "std")] - fn conditional_select_i64() { - let c: i64 = 2343249123; - let d: i64 = 8723884895; - - assert_eq!(conditional_select(c, d, 0), d); - assert_eq!(conditional_select(c, d, 1), c); - } -}