mirror of
https://github.com/saymrwulf/curve25519-dalek-source.git
synced 2026-09-04 20:24:10 +00:00
Move subtle to its own crate.
This commit is contained in:
parent
b2470cb7b9
commit
4bcf8bed9d
6 changed files with 28 additions and 288 deletions
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
12
src/field.rs
12
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
|
||||
|
|
|
|||
|
|
@ -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.
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
274
src/subtle.rs
274
src/subtle.rs
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
Loading…
Reference in a new issue