Move subtle to its own crate.

This commit is contained in:
Isis Lovecruft 2017-05-31 04:37:16 +00:00
parent b2470cb7b9
commit 4bcf8bed9d
Failed to extract signature
6 changed files with 28 additions and 288 deletions

View file

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

View file

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

View file

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

View file

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

View file

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

View file

@ -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
// <http://creativecommons.org/publicdomain/zero/.0/> for full details.
//
// Authors:
// - Isis Agora Lovecruft <isis@patternsinthevoid.net>
// - Henry de Valence <hdevalence@hdevalence.ca>
//! 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<T> CTNegatable for T
where T: CTAssignable, for<'a> &'a T: Neg<Output=T>
{
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<T>(a: T, b: T, choice: T) -> T
where T: PartialEq + PartialOrd + Copy +
One + Signed + Sub<T, Output = T> + Not<Output = T> +
BitAnd<T, Output = T> + BitOr<T, Output = T> {
(!(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);
}
}