Merge branch 'feature/subtle' into develop

This commit is contained in:
Isis Lovecruft 2017-05-31 02:05:00 +00:00
commit b2470cb7b9
Failed to extract signature
3 changed files with 117 additions and 1 deletions

View file

@ -36,6 +36,10 @@ version = "0.4"
# same version that digest depends on
version = "^0.6"
[dependencies.num-traits]
optional = true
version = "^0.1"
[dev-dependencies.sha2]
version = "0.4"
@ -45,7 +49,7 @@ version = "0.6"
[features]
nightly = ["radix_51"]
default = ["std"]
std = ["rand"]
std = ["rand", "num-traits"]
yolocrypto = []
bench = []
# Radix-51 arithmetic using u128

View file

@ -13,6 +13,7 @@
#![cfg_attr(not(feature = "std"), feature(collections))]
#![cfg_attr(feature = "nightly", feature(i128_type))]
#![cfg_attr(feature = "bench", feature(test))]
#![cfg_attr(all(feature = "nightly", feature = "std"), feature(zero_one))]
#![allow(unused_features)]
#![deny(missing_docs)] // refuse to compile if documentation is missing
@ -58,6 +59,9 @@ extern crate core;
#[cfg(feature = "std")]
extern crate rand;
#[cfg(feature = "std")]
extern crate num_traits;
#[cfg(not(feature = "std"))]
extern crate collections;

View file

@ -11,8 +11,23 @@
//! 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`.
@ -50,11 +65,84 @@ impl<T> CTNegatable for T
}
}
/// 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;
@ -163,4 +251,24 @@ mod test {
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);
}
}