From 90baaba5916b9862b25a7c7300809f23ab0b1f27 Mon Sep 17 00:00:00 2001 From: Tony Arcieri Date: Tue, 14 Feb 2017 08:34:24 -0800 Subject: [PATCH 01/22] Add "cryptography" and "no-std" categories --- Cargo.toml | 1 + 1 file changed, 1 insertion(+) diff --git a/Cargo.toml b/Cargo.toml index 014cce1..cbc5a5e 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -8,6 +8,7 @@ license = "CC0-1.0" repository = "https://code.ciph.re/isis/curve25519-dalek" homepage = "https://code.ciph.re/isis/curve25519-dalek" documentation = "https://docs.rs/curve25519-dalek" +categories = ["cryptography", "no-std"] keywords = ["cryptography", "curve25519", "elliptic", "curve", "ECC"] description = "A low-level cryptographic library for point, group, field, and scalar operations on a curve isomorphic to the twisted Edwards curve defined by -x²+y² = 1 - 121665/121666 x²y² over GF(2²⁵⁵ - 19)." exclude = [ From eaa5d3e59515a932b073b45f5385cbdee731fdb0 Mon Sep 17 00:00:00 2001 From: Henry de Valence Date: Tue, 31 Jan 2017 01:13:07 -0500 Subject: [PATCH 02/22] Derive Eq, PartialEq for CompressedEdwardsY --- src/curve.rs | 14 +------------- 1 file changed, 1 insertion(+), 13 deletions(-) diff --git a/src/curve.rs b/src/curve.rs index b0732ae..b36cc0b 100644 --- a/src/curve.rs +++ b/src/curve.rs @@ -98,7 +98,7 @@ use util::CTAssignable; /// /// The first 255 bits of a CompressedEdwardsY represent the /// y-coordinate. The high bit of the 32nd byte gives the sign of `x`. -#[derive(Copy, Clone)] +#[derive(Copy, Clone, Eq, PartialEq)] pub struct CompressedEdwardsY(pub [u8; 32]); impl Debug for CompressedEdwardsY { @@ -107,18 +107,6 @@ impl Debug for CompressedEdwardsY { } } -impl Eq for CompressedEdwardsY {} -impl PartialEq for CompressedEdwardsY { - /// Determine if this `CompressedEdwardsY` is equal to another. - /// - /// # Warning - /// - /// This function is NOT constant time. - fn eq(&self, other: &CompressedEdwardsY) -> bool { - return self.0 == other.0; - } -} - impl Index for CompressedEdwardsY { type Output = u8; From 5f70ab55f82fe79eab95b6c5b5e8f920ef242816 Mon Sep 17 00:00:00 2001 From: Isis Lovecruft Date: Mon, 20 Feb 2017 01:58:56 +0000 Subject: [PATCH 03/22] Obsessive compulsive whitespace fix. --- src/field.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/field.rs b/src/field.rs index 0ef58c2..dc21ea3 100644 --- a/src/field.rs +++ b/src/field.rs @@ -711,7 +711,7 @@ impl FieldElement { /// XXX This returns an extra intermediate to save computation in /// finding inverses, at the cost of an extra copy when it's not /// used (e.g., when raising to (p-1)/2 or (p-5)/8). Good idea? - fn pow22501(&self) -> (FieldElement,FieldElement) { + fn pow22501(&self) -> (FieldElement, FieldElement) { // Instead of managing which temporary variables are used // for what, we define as many as we need and trust the // compiler to reuse stack space as appropriate. From 5f4de0074d6c34f01659a3d652df581c870a011e Mon Sep 17 00:00:00 2001 From: Henry de Valence Date: Mon, 20 Feb 2017 14:20:43 -0800 Subject: [PATCH 04/22] Add a conditional negation function. --- src/field.rs | 14 ++++++++++++++ src/util.rs | 11 +++++++++++ 2 files changed, 25 insertions(+) diff --git a/src/field.rs b/src/field.rs index dc21ea3..865d633 100644 --- a/src/field.rs +++ b/src/field.rs @@ -803,6 +803,7 @@ impl FieldElement { mod test { use field::*; use test::Bencher; + use util::conditional_negate; #[bench] fn bench_fieldelement_a_mul_a(b: &mut Bencher) { @@ -932,4 +933,17 @@ mod test { // high bit is set to zero in to_bytes assert!(test_bytes[31] == (B_BYTES[31] & 127u8)); } + + #[test] + fn test_conditional_negate() { + let one = FieldElement([ 1,0,0,0,0,0,0,0,0,0]); + let minus_one = FieldElement([-1,0,0,0,0,0,0,0,0,0]); + let mut x = one; + conditional_negate(&mut x,1u8); + assert_eq!(x, minus_one); + conditional_negate(&mut x,0u8); + assert_eq!(x, minus_one); + conditional_negate(&mut x,1u8); + assert_eq!(x, one); + } } diff --git a/src/util.rs b/src/util.rs index 1391ef8..86d91aa 100644 --- a/src/util.rs +++ b/src/util.rs @@ -11,6 +11,8 @@ //! Utility functions and tools for constant-time comparisons. +use core::ops::Neg; + /// Trait for items which can be conditionally assigned in constant time. pub trait CTAssignable { /// If `choice == 1u8`, assign `other` to `self`. @@ -19,6 +21,15 @@ pub trait CTAssignable { fn conditional_assign(&mut self, other: &Self, choice: u8); } +/// Conditionally negate an element if `choice == 1u8`. +pub fn conditional_negate(x: &mut T, choice: u8) + where T: CTAssignable, for<'a> &'a T: Neg +{ + // Need to cast to discard mutability + let x_neg = -(x as &T); + x.conditional_assign(&x_neg, choice); +} + /// Check equality of two bytes in constant time. /// /// # Return From 8a1c13ef49a38d997521c16166f93aae5da2fba2 Mon Sep 17 00:00:00 2001 From: Henry de Valence Date: Mon, 20 Feb 2017 14:39:55 -0800 Subject: [PATCH 05/22] Make a CTNegateable trait with a generic impl for better ergonomics --- src/field.rs | 8 ++++---- src/util.rs | 21 ++++++++++++++++----- 2 files changed, 20 insertions(+), 9 deletions(-) diff --git a/src/field.rs b/src/field.rs index 865d633..e0e4767 100644 --- a/src/field.rs +++ b/src/field.rs @@ -803,7 +803,7 @@ impl FieldElement { mod test { use field::*; use test::Bencher; - use util::conditional_negate; + use util::CTNegateable; #[bench] fn bench_fieldelement_a_mul_a(b: &mut Bencher) { @@ -939,11 +939,11 @@ mod test { let one = FieldElement([ 1,0,0,0,0,0,0,0,0,0]); let minus_one = FieldElement([-1,0,0,0,0,0,0,0,0,0]); let mut x = one; - conditional_negate(&mut x,1u8); + x.conditional_negate(1u8); assert_eq!(x, minus_one); - conditional_negate(&mut x,0u8); + x.conditional_negate(0u8); assert_eq!(x, minus_one); - conditional_negate(&mut x,1u8); + x.conditional_negate(1u8); assert_eq!(x, one); } } diff --git a/src/util.rs b/src/util.rs index 86d91aa..2d08f79 100644 --- a/src/util.rs +++ b/src/util.rs @@ -21,13 +21,24 @@ pub trait CTAssignable { fn conditional_assign(&mut self, other: &Self, choice: u8); } -/// Conditionally negate an element if `choice == 1u8`. -pub fn conditional_negate(x: &mut T, choice: 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 CTNegateable +{ + /// Conditionally negate an element if `choice == 1u8`. + fn conditional_negate(&mut self, choice: u8); +} + +impl CTNegateable for T where T: CTAssignable, for<'a> &'a T: Neg { - // Need to cast to discard mutability - let x_neg = -(x as &T); - x.conditional_assign(&x_neg, choice); + 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); + } } /// Check equality of two bytes in constant time. From dc5621f5272553e0e64893f22bb25c358ca5b841 Mon Sep 17 00:00:00 2001 From: Henry de Valence Date: Mon, 20 Feb 2017 15:22:28 -0800 Subject: [PATCH 06/22] Use conditional_negate in select_precomputed_point --- src/curve.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/curve.rs b/src/curve.rs index b36cc0b..b659980 100644 --- a/src/curve.rs +++ b/src/curve.rs @@ -87,6 +87,7 @@ use field::FieldElement; use scalar::Scalar; use util::bytes_equal_ct; use util::CTAssignable; +use util::CTNegateable; // ------------------------------------------------------------------------ // Compressed points @@ -734,9 +735,8 @@ fn select_precomputed_point(x: i8, points: &[T; 8]) -> T } // Now t == |x| * P. - let minus_t = -(&t); let neg_mask = (xmask & 1) as u8; - t.conditional_assign(&minus_t, neg_mask); + t.conditional_negate(neg_mask); // Now t == x * P. t From 8c432ef78a8bad248dda2fa5f312503809e19fd6 Mon Sep 17 00:00:00 2001 From: Isis Lovecruft Date: Tue, 21 Feb 2017 01:46:01 +0000 Subject: [PATCH 07/22] Another obsessive compulsive whitespace fix. --- src/scalar.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/scalar.rs b/src/scalar.rs index f98881b..17a4117 100644 --- a/src/scalar.rs +++ b/src/scalar.rs @@ -43,7 +43,7 @@ use util::CTAssignable; /// l = 2^252 + 27742317777372353535851937790883648493 /// /// is the order of the basepoint. The `Scalar` is stored as bytes. -#[derive(Copy,Clone)] +#[derive(Copy, Clone)] pub struct Scalar(pub [u8; 32]); impl Index for Scalar { From 51f59565f5ff60297df0c169ff38f99eb27dd912 Mon Sep 17 00:00:00 2001 From: Isis Lovecruft Date: Tue, 21 Feb 2017 04:15:09 +0000 Subject: [PATCH 08/22] =?UTF-8?q?Typo=20fix;=20Negateable=20=E2=86=92=20Ne?= =?UTF-8?q?gatable.?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Fixup on #22. --- src/curve.rs | 2 +- src/field.rs | 2 +- src/util.rs | 4 ++-- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/curve.rs b/src/curve.rs index b659980..b9c3848 100644 --- a/src/curve.rs +++ b/src/curve.rs @@ -87,7 +87,7 @@ use field::FieldElement; use scalar::Scalar; use util::bytes_equal_ct; use util::CTAssignable; -use util::CTNegateable; +use util::CTNegatable; // ------------------------------------------------------------------------ // Compressed points diff --git a/src/field.rs b/src/field.rs index e0e4767..aa632b1 100644 --- a/src/field.rs +++ b/src/field.rs @@ -803,7 +803,7 @@ impl FieldElement { mod test { use field::*; use test::Bencher; - use util::CTNegateable; + use util::CTNegatable; #[bench] fn bench_fieldelement_a_mul_a(b: &mut Bencher) { diff --git a/src/util.rs b/src/util.rs index 2d08f79..b0ab17d 100644 --- a/src/util.rs +++ b/src/util.rs @@ -25,13 +25,13 @@ pub trait CTAssignable { /// /// Note: it is not necessary to implement this trait, as a generic /// implementation is provided. -pub trait CTNegateable +pub trait CTNegatable { /// Conditionally negate an element if `choice == 1u8`. fn conditional_negate(&mut self, choice: u8); } -impl CTNegateable for T +impl CTNegatable for T where T: CTAssignable, for<'a> &'a T: Neg { fn conditional_negate(&mut self, choice: u8) { From 32da4c7d5044381dd468dcd2c40a6c7ebd4232c6 Mon Sep 17 00:00:00 2001 From: Isis Lovecruft Date: Fri, 6 Jan 2017 17:08:37 +0000 Subject: [PATCH 09/22] Implement Neg for Scalar. --- src/constants.rs | 15 +++++++++++++++ src/scalar.rs | 20 ++++++++++++++++++++ 2 files changed, 35 insertions(+) diff --git a/src/constants.rs b/src/constants.rs index 0b927d3..71417d8 100644 --- a/src/constants.rs +++ b/src/constants.rs @@ -21,6 +21,7 @@ use field::FieldElement; use curve::PreComputedPoint; use curve::CompressedEdwardsY; +use scalar::Scalar; pub const d: FieldElement = FieldElement([ -10913610, 13857413, -15372611, 6949391, 114729, @@ -66,6 +67,20 @@ pub const BASE_CMPRSSD: CompressedEdwardsY = 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66]); +/// `l` is the order of base point, i.e. 2^252 + +/// 27742317777372353535851937790883648493, in little-endian form +pub const l: Scalar = Scalar([ 0xed, 0xd3, 0xf5, 0x5c, 0x1a, 0x63, 0x12, 0x58, + 0xd6, 0x9c, 0xf7, 0xa2, 0xde, 0xf9, 0xde, 0x14, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10 ]); + +/// `lminus1` is the order of base point minus one, i.e. 2^252 + +/// 27742317777372353535851937790883648493 - 1, in little-endian form +pub const lminus1: Scalar = Scalar([ 0xec, 0xd3, 0xf5, 0x5c, 0x1a, 0x63, 0x12, 0x58, + 0xd6, 0x9c, 0xf7, 0xa2, 0xde, 0xf9, 0xde, 0x14, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10 ]); + pub const bi: [PreComputedPoint; 8] = [ PreComputedPoint{ y_plus_x: FieldElement([25967493, -14356035, 29566456, 3660896, -12694345, 4014787, 27544626, -11754271, -6079156, 2047605]), diff --git a/src/scalar.rs b/src/scalar.rs index 17a4117..565d740 100644 --- a/src/scalar.rs +++ b/src/scalar.rs @@ -30,11 +30,13 @@ //! limbs. use core::ops::{Index, IndexMut}; +use core::ops::{Neg}; #[cfg(feature = "std")] use rand::Rng; // XXX should these be in a utility module ? +use constants; use field::{load3, load4}; use util::CTAssignable; @@ -62,6 +64,15 @@ impl IndexMut for Scalar { } } +impl Neg for Scalar { + type Output = Scalar; + + /// Negate this scalar by computing (l - 1) * self - 0 (mod l). + fn neg(self) -> Scalar { + Scalar::multiply_add(&constants::lminus1, &self, &Scalar::zero()) + } +} + impl CTAssignable for Scalar { /// Conditionally assign another Scalar to this one. /// @@ -627,4 +638,13 @@ mod test { assert!(test_red[i] == reduced[i]); } } + + // Negating a scalar twice should result in the original scalar. + #[test] + fn test_scalar_neg() { + let negative_x: Scalar = -X; + let orig: Scalar = -negative_x; + + assert!(orig == X); + } } From 7b57be69fd9ae937ee8a27460a03c520017e5d0e Mon Sep 17 00:00:00 2001 From: Isis Lovecruft Date: Fri, 6 Jan 2017 19:39:55 +0000 Subject: [PATCH 10/22] Implement constant time equality check for scalars. --- src/scalar.rs | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) diff --git a/src/scalar.rs b/src/scalar.rs index 565d740..c5f3734 100644 --- a/src/scalar.rs +++ b/src/scalar.rs @@ -29,6 +29,7 @@ //! between two scalars, the `UnpackedScalar` struct is stored as //! limbs. +use core::cmp::{Eq, PartialEq}; use core::ops::{Index, IndexMut}; use core::ops::{Neg}; @@ -39,6 +40,7 @@ use rand::Rng; use constants; use field::{load3, load4}; use util::CTAssignable; +use util::arrays_equal_ct; /// The `Scalar` struct represents an element in ℤ/lℤ, where /// @@ -48,6 +50,25 @@ use util::CTAssignable; #[derive(Copy, Clone)] pub struct Scalar(pub [u8; 32]); +// XXX make CTEq traits +impl Eq for Scalar{} +impl PartialEq for Scalar { + /// Test equality between two `Scalar`s in constant time. + /// + /// Returns + /// + /// True if they are equal, and false otherwise. + fn eq(&self, other: &Self) -> bool { + let equal: u8 = arrays_equal_ct(&self.0, &other.0); + + if equal == 1 { + return true; + } else { + return false; + } + } +} + impl Index for Scalar { type Output = u8; From 03589dff43b654c967fe0c9b212e08f2bd9e8b43 Mon Sep 17 00:00:00 2001 From: Isis Lovecruft Date: Fri, 6 Jan 2017 21:29:27 +0000 Subject: [PATCH 11/22] Add method for determining if an ExtendedPoint is of small order. --- src/curve.rs | 28 ++++++++++++++++++++++++++++ 1 file changed, 28 insertions(+) diff --git a/src/curve.rs b/src/curve.rs index b9c3848..1d60559 100644 --- a/src/curve.rs +++ b/src/curve.rs @@ -655,6 +655,25 @@ impl ExtendedPoint { r = s.double(); return r.to_extended(); } + + /// Determine if this point is of small order. + /// + /// The order of the group of points on the curve Ɛ is |Ɛ| = 8q. Thus, to + /// check if a point P is of small order, we multiply by 8 and then test + /// if the result is equal to the identity. + /// + /// # Return + /// + /// True if it is of small order; false otherwise. + pub fn is_small_order(&self) -> bool { + let p8: ExtendedPoint = self.mult_by_pow_2(3); + + if p8.is_identity() { + return true; + } else { + return false; + } + } } /// Given a point `A` and scalars `a` and `b`, compute the point @@ -1045,6 +1064,15 @@ mod test { assert_eq!(p1.xy2d, p2.xy2d); } + #[test] + fn test_is_small_order() { + let p1: ExtendedPoint = ExtendedPoint::identity(); + let p2: ExtendedPoint = BASE_CMPRSSD.decompress().unwrap(); + + assert!(p1.is_small_order() == true); + assert!(p2.is_small_order() == false); + } + #[bench] fn bench_basepoint_mult(b: &mut Bencher) { b.iter(|| ExtendedPoint::basepoint_mult(&A_SCALAR)); From 1381e07ffb655653bd6e66c5550e41537f1f8497 Mon Sep 17 00:00:00 2001 From: Isis Lovecruft Date: Thu, 12 Jan 2017 22:27:48 +0000 Subject: [PATCH 12/22] Implement a method for determining if an element is the identity. This corresponds to ge_isneutral() in Open Whispersystems' ed25519 library. --- src/curve.rs | 40 +++++++++++++++++++++++++++++++++++++++- 1 file changed, 39 insertions(+), 1 deletion(-) diff --git a/src/curve.rs b/src/curve.rs index 1d60559..fef11b7 100644 --- a/src/curve.rs +++ b/src/curve.rs @@ -85,8 +85,10 @@ use core::cmp::{PartialEq, Eq}; use constants; use field::FieldElement; use scalar::Scalar; +use util::arrays_equal_ct; use util::bytes_equal_ct; use util::CTAssignable; +use util::CTEq; use util::CTNegatable; // ------------------------------------------------------------------------ @@ -227,7 +229,7 @@ pub struct CachedPoint { // Constructors // ------------------------------------------------------------------------ -/// Trait for curve point types that have an identity constructor. +/// Trait for curve point types which have an identity constructor. pub trait Identity { /// Returns the identity element of the curve. /// Can be used as a constructor. @@ -292,6 +294,37 @@ impl CTAssignable for PreComputedPoint { } } +// ------------------------------------------------------------------------ +// Constant-time Equality +// ------------------------------------------------------------------------ + +impl CTEq for ExtendedPoint { + fn ct_eq(&self, other: &ExtendedPoint) -> u8 { + arrays_equal_ct(&self.compress().0, &other.compress().0) + } +} + +/// Trait for testing if a curve point is equivalent to the identity point. +pub trait IsIdentity { + /// Return true if this element is the identity element of the curve. + fn is_identity(&self) -> bool; +} + +/// Implement generic identity equality testing for a point representations +/// which have constant-time equality testing and a defined identity +/// constructor. +impl IsIdentity for T where T: CTEq + Identity { + fn is_identity(&self) -> bool { + let identity: T = T::identity(); + + if self.ct_eq(&identity) == 1u8 { + return true; + } else { + return false; + } + } +} + // ------------------------------------------------------------------------ // Point conversions // ------------------------------------------------------------------------ @@ -1073,6 +1106,11 @@ mod test { assert!(p2.is_small_order() == false); } + #[test] + fn test_is_identity() { + assert!(ExtendedPoint::identity().is_identity()); + } + #[bench] fn bench_basepoint_mult(b: &mut Bencher) { b.iter(|| ExtendedPoint::basepoint_mult(&A_SCALAR)); From 5308fef21022e7b00e65da7743140e1ca9b9725c Mon Sep 17 00:00:00 2001 From: Isis Lovecruft Date: Tue, 21 Feb 2017 02:14:31 +0000 Subject: [PATCH 13/22] Add CTEq trait and implement it for Scalar. --- src/scalar.rs | 24 ++++++++++++++++++++---- src/util.rs | 12 +++++++++++- 2 files changed, 31 insertions(+), 5 deletions(-) diff --git a/src/scalar.rs b/src/scalar.rs index c5f3734..33bf764 100644 --- a/src/scalar.rs +++ b/src/scalar.rs @@ -40,6 +40,7 @@ use rand::Rng; use constants; use field::{load3, load4}; use util::CTAssignable; +use util::CTEq; use util::arrays_equal_ct; /// The `Scalar` struct represents an element in ℤ/lℤ, where @@ -50,18 +51,22 @@ use util::arrays_equal_ct; #[derive(Copy, Clone)] pub struct Scalar(pub [u8; 32]); -// XXX make CTEq traits impl Eq for Scalar{} impl PartialEq for Scalar { - /// Test equality between two `Scalar`s in constant time. + /// Test equality between two `Scalar`s. /// - /// Returns + /// # Warning + /// + /// This function is *not* guaranteed to be constant time and should only be + /// used for debugging purposes. + /// + /// # Returns /// /// True if they are equal, and false otherwise. fn eq(&self, other: &Self) -> bool { let equal: u8 = arrays_equal_ct(&self.0, &other.0); - if equal == 1 { + if equal == 1u8 { return true; } else { return false; @@ -69,6 +74,17 @@ impl PartialEq for Scalar { } } +impl CTEq for Scalar { + /// Test equality between two `Scalar`s in constant time. + /// + /// # Returns + /// + /// `1u8` if they are equal, and `0u8` otherwise. + fn ct_eq(&self, other: &Self) -> u8 { + arrays_equal_ct(&self.0, &other.0) + } +} + impl Index for Scalar { type Output = u8; diff --git a/src/util.rs b/src/util.rs index b0ab17d..a3db551 100644 --- a/src/util.rs +++ b/src/util.rs @@ -21,7 +21,17 @@ pub trait CTAssignable { fn conditional_assign(&mut self, other: &Self, choice: u8); } -/// Trait for items which can be conditionally negated in constant time. +/// 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. From b1afdf520458837386f1c607cd5aca6b29b448d5 Mon Sep 17 00:00:00 2001 From: Isis Lovecruft Date: Tue, 21 Feb 2017 02:36:50 +0000 Subject: [PATCH 14/22] Implement CTEq for FieldElement. --- src/field.rs | 22 +++++++++++++++++----- 1 file changed, 17 insertions(+), 5 deletions(-) diff --git a/src/field.rs b/src/field.rs index aa632b1..448c1ac 100644 --- a/src/field.rs +++ b/src/field.rs @@ -24,8 +24,10 @@ use core::ops::{Index, IndexMut}; use core::cmp::{Eq, PartialEq}; use core::ops::Neg; +use util::arrays_equal_ct; use util::byte_is_nonzero; use util::CTAssignable; +use util::CTEq; /// FieldElements are represented as an array of ten "Limbs", which are radix /// 25.5, that is, each Limb of a FieldElement alternates between being @@ -40,6 +42,7 @@ pub type Limb = i32; #[derive(Copy, Clone)] pub struct FieldElement(pub [Limb; 10]); +impl Eq for FieldElement {} impl PartialEq for FieldElement { /// Test equality between two FieldElements by converting them to bytes. /// @@ -48,10 +51,10 @@ impl PartialEq for FieldElement { /// This comparison is *not* constant time. It could easily be /// made to be, but the main use of an `Eq` implementation is for /// branching, so it seems pointless. - /// - /// XXX it would be good to encode constant-time considerations - /// (no data flow from secret information) into Rust's type - /// system. + // + // XXX it would be good to encode constant-time considerations + // (no data flow from secret information) into Rust's type + // system. fn eq(&self, other: &FieldElement) -> bool { let self_bytes = self.to_bytes(); let other_bytes = other.to_bytes(); @@ -63,7 +66,16 @@ impl PartialEq for FieldElement { } } -impl Eq for FieldElement {} +impl CTEq for FieldElement { + /// Test equality between two `FieldElement`s by converting them to bytes. + /// + /// # Returns + /// + /// `1u8` if the two `FieldElement`s are equal, and `0u8` otherwise. + fn ct_eq(&self, other: &FieldElement) -> u8 { + arrays_equal_ct(&self.to_bytes(), &other.to_bytes()) + } +} impl Debug for FieldElement { fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result { From 3eb5dcaae743257d8c0c547fecc840eb1cf40737 Mon Sep 17 00:00:00 2001 From: Isis Lovecruft Date: Tue, 21 Feb 2017 03:13:30 +0000 Subject: [PATCH 15/22] Implement CTEq for ExtendedPoint. --- src/curve.rs | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/src/curve.rs b/src/curve.rs index fef11b7..4f7126b 100644 --- a/src/curve.rs +++ b/src/curve.rs @@ -986,6 +986,20 @@ mod test { assert_eq!( bp_added.compress(), BASE2_CMPRSSD); } + #[test] + fn test_extended_point_equality() { + let two = [2, 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 id1 = ExtendedPoint::identity(); + let id2 = ExtendedPoint{ + X: FieldElement::zero(), + Y: FieldElement::from_bytes(&two), + Z: FieldElement::from_bytes(&two), + T: FieldElement::zero()}; + + assert!(id1.ct_eq(&id2) == 1u8); + } + /// Sanity check for conversion to precomputed points #[test] fn test_convert_to_precomputed() { From 6f67a7d71618792d04d906496344ba92000155cb Mon Sep 17 00:00:00 2001 From: Isis Lovecruft Date: Tue, 21 Feb 2017 06:01:17 +0000 Subject: [PATCH 16/22] Rename util module to subtle. * CHANGE subtle module documentation slightly to clarify the module's purpose. * FIXES issue #25. --- src/curve.rs | 12 ++++++------ src/field.rs | 14 +++++++------- src/lib.rs | 4 ++-- src/scalar.rs | 8 ++++---- src/{util.rs => subtle.rs} | 8 ++++---- 5 files changed, 23 insertions(+), 23 deletions(-) rename src/{util.rs => subtle.rs} (92%) diff --git a/src/curve.rs b/src/curve.rs index 4f7126b..da10163 100644 --- a/src/curve.rs +++ b/src/curve.rs @@ -85,11 +85,11 @@ use core::cmp::{PartialEq, Eq}; use constants; use field::FieldElement; use scalar::Scalar; -use util::arrays_equal_ct; -use util::bytes_equal_ct; -use util::CTAssignable; -use util::CTEq; -use util::CTNegatable; +use subtle::arrays_equal_ct; +use subtle::bytes_equal_ct; +use subtle::CTAssignable; +use subtle::CTEq; +use subtle::CTNegatable; // ------------------------------------------------------------------------ // Compressed points @@ -865,7 +865,7 @@ mod test { use test::Bencher; use field::FieldElement; use scalar::Scalar; - use util::CTAssignable; + use subtle::CTAssignable; use constants; use constants::BASE_CMPRSSD; use super::*; diff --git a/src/field.rs b/src/field.rs index 448c1ac..9ed0aea 100644 --- a/src/field.rs +++ b/src/field.rs @@ -24,10 +24,10 @@ use core::ops::{Index, IndexMut}; use core::cmp::{Eq, PartialEq}; use core::ops::Neg; -use util::arrays_equal_ct; -use util::byte_is_nonzero; -use util::CTAssignable; -use util::CTEq; +use subtle::arrays_equal_ct; +use subtle::byte_is_nonzero; +use subtle::CTAssignable; +use subtle::CTEq; /// FieldElements are represented as an array of ten "Limbs", which are radix /// 25.5, that is, each Limb of a FieldElement alternates between being @@ -162,7 +162,7 @@ impl CTAssignable for FieldElement { /// /// ``` /// # use curve25519_dalek::field::FieldElement; - /// # use curve25519_dalek::util::CTAssignable; + /// # use curve25519_dalek::subtle::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]); @@ -174,7 +174,7 @@ impl CTAssignable for FieldElement { /// /// ``` /// # use curve25519_dalek::field::FieldElement; - /// # use curve25519_dalek::util::CTAssignable; + /// # use curve25519_dalek::subtle::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]); @@ -815,7 +815,7 @@ impl FieldElement { mod test { use field::*; use test::Bencher; - use util::CTNegatable; + use subtle::CTNegatable; #[bench] fn bench_fieldelement_a_mul_a(b: &mut Bencher) { diff --git a/src/lib.rs b/src/lib.rs index 36e3a05..2007ada 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -47,9 +47,9 @@ pub mod field; pub mod curve; pub mod scalar; -// Utilities module. +// Constant-time functions and other miscelaneous utilities. -pub mod util; +pub mod subtle; // Low-level curve and point constants, as well as pre-computed curve group elements. diff --git a/src/scalar.rs b/src/scalar.rs index 33bf764..a1ec8d0 100644 --- a/src/scalar.rs +++ b/src/scalar.rs @@ -39,9 +39,9 @@ use rand::Rng; // XXX should these be in a utility module ? use constants; use field::{load3, load4}; -use util::CTAssignable; -use util::CTEq; -use util::arrays_equal_ct; +use subtle::CTAssignable; +use subtle::CTEq; +use subtle::arrays_equal_ct; /// The `Scalar` struct represents an element in ℤ/lℤ, where /// @@ -115,7 +115,7 @@ impl CTAssignable for Scalar { /// /// ``` /// # use curve25519_dalek::scalar::Scalar; - /// # use curve25519_dalek::util::CTAssignable; + /// # use curve25519_dalek::subtle::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, diff --git a/src/util.rs b/src/subtle.rs similarity index 92% rename from src/util.rs rename to src/subtle.rs index a3db551..c46393a 100644 --- a/src/util.rs +++ b/src/subtle.rs @@ -9,7 +9,7 @@ // - Isis Agora Lovecruft // - Henry de Valence -//! Utility functions and tools for constant-time comparisons. +//! Constant-time traits and utility functions. use core::ops::Neg; @@ -31,7 +31,7 @@ pub trait CTEq { fn ct_eq(&self, other: &Self) -> u8; } -// Trait for items which can be conditionally negated in constant time. +/// 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. @@ -55,7 +55,7 @@ impl CTNegatable for T /// /// # Return /// -/// Returns 1 if `a == b` and 0 otherwise. +/// Returns `1u8` if `a == b` and `0u8` otherwise. #[inline(always)] pub fn bytes_equal_ct(a: u8, b: u8) -> u8 { let mut x: u8; @@ -94,7 +94,7 @@ pub fn byte_is_nonzero(b: u8) -> u8 { /// /// # Return /// -/// Returns 1 if `a == b` and 0 otherwise. +/// Returns `1u8` if `a == b` and `0u8` otherwise. #[inline(always)] // We don't use this in curve25519-dalek, but it's useful for e.g. an ed25519 implementation. #[allow(dead_code)] From 4b738c7e19a5a546d98d2098cd06067ee1d93a01 Mon Sep 17 00:00:00 2001 From: Isis Lovecruft Date: Tue, 21 Feb 2017 06:06:07 +0000 Subject: [PATCH 17/22] Remove #[allow(dead_code)] from arrays_equal_ct(). --- src/subtle.rs | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/subtle.rs b/src/subtle.rs index c46393a..098733f 100644 --- a/src/subtle.rs +++ b/src/subtle.rs @@ -96,8 +96,6 @@ pub fn byte_is_nonzero(b: u8) -> u8 { /// /// Returns `1u8` if `a == b` and `0u8` otherwise. #[inline(always)] -// We don't use this in curve25519-dalek, but it's useful for e.g. an ed25519 implementation. -#[allow(dead_code)] pub fn arrays_equal_ct(a: &[u8; 32], b: &[u8; 32]) -> u8 { let mut x: u8 = 0; From e4d041836e2311f114806bff5a09ef12981b2d1d Mon Sep 17 00:00:00 2001 From: Isis Lovecruft Date: Tue, 21 Feb 2017 06:06:46 +0000 Subject: [PATCH 18/22] Move load3 and load4 to new utils module and remove #[allow(dead_code)]. --- src/field.rs | 21 ++------------------- src/lib.rs | 1 + src/scalar.rs | 3 +-- src/utils.rs | 31 +++++++++++++++++++++++++++++++ 4 files changed, 35 insertions(+), 21 deletions(-) create mode 100644 src/utils.rs diff --git a/src/field.rs b/src/field.rs index 9ed0aea..7d5bc44 100644 --- a/src/field.rs +++ b/src/field.rs @@ -29,6 +29,8 @@ use subtle::byte_is_nonzero; use subtle::CTAssignable; use subtle::CTEq; +use utils::{load3, load4}; + /// FieldElements are represented as an array of ten "Limbs", which are radix /// 25.5, that is, each Limb of a FieldElement alternates between being /// represented as a factor of 2^25 or 2^26 more than the last corresponding @@ -193,25 +195,6 @@ impl CTAssignable for FieldElement { } } -/// Convert an array of (at least) three bytes into an i64. -#[inline] -#[allow(dead_code)] -pub fn load3(input: &[u8]) -> i64 { - (input[0] as i64) - | ((input[1] as i64) << 8) - | ((input[2] as i64) << 16) -} - -/// Convert an array of (at least) four bytes into an i64. -#[inline] -#[allow(dead_code)] -pub fn load4(input: &[u8]) -> i64 { - (input[0] as i64) - | ((input[1] as i64) << 8) - | ((input[2] as i64) << 16) - | ((input[3] as i64) << 24) -} - impl FieldElement { /// Invert the sign of this field element pub fn negate(&mut self) { diff --git a/src/lib.rs b/src/lib.rs index 2007ada..7855923 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -50,6 +50,7 @@ pub mod scalar; // Constant-time functions and other miscelaneous utilities. pub mod subtle; +pub mod utils; // Low-level curve and point constants, as well as pre-computed curve group elements. diff --git a/src/scalar.rs b/src/scalar.rs index a1ec8d0..85c77be 100644 --- a/src/scalar.rs +++ b/src/scalar.rs @@ -36,9 +36,8 @@ use core::ops::{Neg}; #[cfg(feature = "std")] use rand::Rng; -// XXX should these be in a utility module ? use constants; -use field::{load3, load4}; +use utils::{load3, load4}; use subtle::CTAssignable; use subtle::CTEq; use subtle::arrays_equal_ct; diff --git a/src/utils.rs b/src/utils.rs new file mode 100644 index 0000000..ad53166 --- /dev/null +++ b/src/utils.rs @@ -0,0 +1,31 @@ +// -*- 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 +// for full details. +// +// Authors: +// - Isis Agora Lovecruft +// - Henry de Valence + +//! Miscellaneous common utility function. + +/// Convert an array of (at least) three bytes into an i64. +#[inline] +//#[allow(dead_code)] +pub fn load3(input: &[u8]) -> i64 { + (input[0] as i64) + | ((input[1] as i64) << 8) + | ((input[2] as i64) << 16) +} + +/// Convert an array of (at least) four bytes into an i64. +#[inline] +//#[allow(dead_code)] +pub fn load4(input: &[u8]) -> i64 { + (input[0] as i64) + | ((input[1] as i64) << 8) + | ((input[2] as i64) << 16) + | ((input[3] as i64) << 24) +} From a6850f8e82694aea0a8e03484d26dbe39018738b Mon Sep 17 00:00:00 2001 From: Isis Lovecruft Date: Tue, 21 Feb 2017 06:15:48 +0000 Subject: [PATCH 19/22] Fix version number in install instructions in README. --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 2c0b3ef..074dc28 100644 --- a/README.md +++ b/README.md @@ -44,7 +44,7 @@ Extensive documentation is available [here](https://docs.rs/curve25519-dalek). To install, add the following to the dependencies section of your project's `Cargo.toml`: - curve25519-dalek = "^0.2" + curve25519-dalek = "^0.3" Then, in your library or executable source, add: From 1dac334b8422c7f0d862d65148d3a9e144ca9fa8 Mon Sep 17 00:00:00 2001 From: Isis Lovecruft Date: Tue, 21 Feb 2017 20:59:04 +0000 Subject: [PATCH 20/22] Whitespace fix. --- Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Cargo.toml b/Cargo.toml index 3746cbb..d6a9cb0 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -35,7 +35,7 @@ lto = false # controls `-C lto` for binaries and staticlibs debug-assertions = true # controls whether debug assertions are enabled codegen-units = 1 # controls whether the compiler passes `-C codegen-units` # `codegen-units` is ignored when `lto = true` - panic = 'unwind' # panic strategy (`-C panic=...`), can also be 'abort' +panic = 'unwind' # panic strategy (`-C panic=...`), can also be 'abort' # The release profile, used for `cargo build --release`. [profile.release] From 78701d5441fe2ae6d6414b478683b9f5cf61c2df Mon Sep 17 00:00:00 2001 From: Isis Lovecruft Date: Tue, 21 Feb 2017 20:59:17 +0000 Subject: [PATCH 21/22] Bump version to 0.4.0. --- Cargo.toml | 2 +- README.md | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index d6a9cb0..2733c45 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "curve25519-dalek" -version = "0.3.0" +version = "0.4.0" authors = ["Isis Lovecruft ", "Henry de Valence "] readme = "README.md" diff --git a/README.md b/README.md index 074dc28..d6dd6e2 100644 --- a/README.md +++ b/README.md @@ -44,7 +44,7 @@ Extensive documentation is available [here](https://docs.rs/curve25519-dalek). To install, add the following to the dependencies section of your project's `Cargo.toml`: - curve25519-dalek = "^0.3" + curve25519-dalek = "^0.4" Then, in your library or executable source, add: From 44e7d500db2f4aea377760e78d92ba4fed090773 Mon Sep 17 00:00:00 2001 From: Isis Lovecruft Date: Tue, 21 Feb 2017 21:01:58 +0000 Subject: [PATCH 22/22] Remove unused import of PartialEq and Eq in curve module. --- src/curve.rs | 1 - 1 file changed, 1 deletion(-) diff --git a/src/curve.rs b/src/curve.rs index da10163..9dc6f22 100644 --- a/src/curve.rs +++ b/src/curve.rs @@ -80,7 +80,6 @@ use core::fmt::Debug; use core::iter::Iterator; use core::ops::{Add, Sub, Neg, Index}; -use core::cmp::{PartialEq, Eq}; use constants; use field::FieldElement;