mirror of
https://github.com/saymrwulf/curve25519-dalek-source.git
synced 2026-09-04 20:24:10 +00:00
Merge branch 'feature/subtle' into develop
This commit is contained in:
commit
b2470cb7b9
3 changed files with 117 additions and 1 deletions
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
||||
|
|
|
|||
108
src/subtle.rs
108
src/subtle.rs
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in a new issue