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/curve.rs b/src/curve.rs index b9c3848..4f7126b 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 // ------------------------------------------------------------------------ @@ -655,6 +688,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 @@ -934,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() { @@ -1045,6 +1111,20 @@ 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); + } + + #[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)); 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 { diff --git a/src/scalar.rs b/src/scalar.rs index 17a4117..33bf764 100644 --- a/src/scalar.rs +++ b/src/scalar.rs @@ -29,14 +29,19 @@ //! between two scalars, the `UnpackedScalar` struct is stored as //! limbs. +use core::cmp::{Eq, PartialEq}; 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; +use util::CTEq; +use util::arrays_equal_ct; /// The `Scalar` struct represents an element in ℤ/lℤ, where /// @@ -46,6 +51,40 @@ use util::CTAssignable; #[derive(Copy, Clone)] pub struct Scalar(pub [u8; 32]); +impl Eq for Scalar{} +impl PartialEq for Scalar { + /// Test equality between two `Scalar`s. + /// + /// # 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 == 1u8 { + return true; + } else { + return false; + } + } +} + +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; @@ -62,6 +101,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 +675,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); + } } 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.