diff --git a/src/curve.rs b/src/curve.rs index 8720601..bd5a342 100644 --- a/src/curve.rs +++ b/src/curve.rs @@ -86,6 +86,7 @@ use constants; use field::FieldElement; use scalar::Scalar; use util::bytes_equal_ct; +use util::CTAssignable; // ------------------------------------------------------------------------ // Compressed points @@ -283,15 +284,6 @@ impl Identity for PreComputedPoint { // Constant-time assignment // ------------------------------------------------------------------------ -/// 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. - // XXX this trait should be extracted? - fn conditional_assign(&mut self, other: &Self, choice: u8); -} - impl CTAssignable for CachedPoint { fn conditional_assign(&mut self, other: &CachedPoint, choice: u8) { self.Y_plus_X.conditional_assign(&other.Y_plus_X, choice); @@ -815,6 +807,7 @@ mod test { use test::Bencher; use field::FieldElement; use scalar::Scalar; + use util::CTAssignable; use constants; use super::*; use super::select_precomputed_point; diff --git a/src/field.rs b/src/field.rs index 2f1301f..4b9758c 100644 --- a/src/field.rs +++ b/src/field.rs @@ -25,6 +25,7 @@ use std::cmp::{Eq, PartialEq}; use std::ops::Neg; use util::byte_is_nonzero; +use util::CTAssignable; /// FieldElements are represented as an array of ten "Limbs", which are radix /// 25.5, that is, each Limb of a FieldElement alternates between being @@ -142,6 +143,44 @@ impl<'a> Neg for &'a FieldElement { } } +impl CTAssignable for FieldElement { + /// Conditionally assign another FieldElement to this one. + /// + /// If `choice == 0`, replace `self` with `self`: + /// + /// ``` + /// # use curve25519_dalek::field::FieldElement; + /// # use curve25519_dalek::util::CTAssignable; + /// 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`: + /// + /// ``` + /// # use curve25519_dalek::field::FieldElement; + /// # use curve25519_dalek::util::CTAssignable; + /// # 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 + /// + /// * `choice` in {0,1} + fn conditional_assign(&mut self, f: &FieldElement, choice: u8) { + let mask = -(choice as Limb); + for i in 0..10 { + self[i] ^= mask & (self[i] ^ f[i]); + } + } +} + /// Convert an array of (at least) three bytes into an i64. #[inline] #[allow(dead_code)] @@ -179,82 +218,6 @@ impl FieldElement { FieldElement([ 1, 0, 0, 0, 0, 0, 0, 0, 0, 0 ]) } - /// Overwrite this FieldElement with one of the inputs without branching. - /// Like `conditional_assign`, but chooses between two inputs instead of - /// one input and the original value. - /// - /// If `choice == 0`, replace `self` with `f`: - /// - /// ``` - /// # use curve25519_dalek::field::FieldElement; - /// 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([0,0,0,0,0,0,0,0,0,0]); - /// h.conditional_choose(&f, &g, 0); - /// assert!(h == f); - /// ``` - /// - /// If `choice == 1`, replace `self` with `g`: - /// - /// ``` - /// # use curve25519_dalek::field::FieldElement; - /// # 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([0,0,0,0,0,0,0,0,0,0]); - /// h.conditional_choose(&f, &g, 1); - /// assert!(h == g); - /// ``` - /// - /// # Preconditions - /// - /// * `b` in {0,1} - pub fn conditional_choose(&mut self, - f: &FieldElement, - g: &FieldElement, - choice: u8) - { - let mask = -(choice as Limb); - for i in 0..10 { - self[i] = f[i] ^ (mask & (f[i] ^ g[i])); - } - } - - /// Conditionally assign the Limbs of another FieldElement to this - /// one. Like `conditional_choose`, but choosing between one - /// input and the original value. - /// - /// If `choice == 0`, replace `self` with `self`: - /// - /// ``` - /// # use curve25519_dalek::field::FieldElement; - /// 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`: - /// - /// ``` - /// # use curve25519_dalek::field::FieldElement; - /// # 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 - /// - /// * `choice` in {0,1} - pub fn conditional_assign(&mut self, f: &FieldElement, choice: u8) { - let mask = -(choice as Limb); - for i in 0..10 { - self[i] ^= mask & (self[i] ^ f[i]); - } - } - fn combine_coeffs(input: &[i64;10]) -> FieldElement { //FeCombine let mut c = [0i64;10]; let mut h = input.clone(); diff --git a/src/scalar.rs b/src/scalar.rs index 6c3497b..e070d4b 100644 --- a/src/scalar.rs +++ b/src/scalar.rs @@ -35,6 +35,7 @@ use rand::Rng; // XXX should these be in a utility module ? use field::{load3, load4}; +use util::CTAssignable; /// The `Scalar` struct represents an element in ℤ/lℤ, where /// @@ -60,6 +61,37 @@ impl IndexMut for Scalar { } } +impl CTAssignable for Scalar { + /// Conditionally assign another Scalar to this one. + /// + /// ``` + /// # use curve25519_dalek::scalar::Scalar; + /// # use curve25519_dalek::util::CTAssignable; + /// 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, + /// 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1]); + /// let mut t = a; + /// t.conditional_assign(&b, 0u8); + /// assert!(t[0] == a[0]); + /// t.conditional_assign(&b, 1u8); + /// assert!(t[0] == b[0]); + /// ``` + /// + /// # Preconditions + /// + /// * `choice` in {0,1} + // XXX above test checks first byte because Scalar does not impl Eq + fn conditional_assign(&mut self, other: &Scalar, choice: u8) { + // if choice = 0u8, mask = (-0i8) as u8 = 00000000 + // if choice = 1u8, mask = (-1i8) as u8 = 11111111 + let mask = -(choice as i8) as u8; + for i in 0..32 { + self[i] ^= mask & (self[i] ^ other[i]); + } + } +} + impl Scalar { /// Return a `Scalar` chosen uniformly at random using a CSPRNG. /// Panics if the operating system's CSPRNG is unavailable. diff --git a/src/util.rs b/src/util.rs index d94a853..1391ef8 100644 --- a/src/util.rs +++ b/src/util.rs @@ -11,6 +11,14 @@ //! Utility functions and tools for constant-time comparisons. +/// 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); +} + /// Check equality of two bytes in constant time. /// /// # Return