diff --git a/src/curve.rs b/src/curve.rs index daab17d..46358ad 100644 --- a/src/curve.rs +++ b/src/curve.rs @@ -84,6 +84,8 @@ use core::ops::{Mul, MulAssign}; use core::ops::Index; use constants; +#[cfg(feature = "yolocrypto")] +use decaf::DecafPoint; use field::FieldElement; use scalar::Scalar; use subtle::arrays_equal_ct; @@ -445,6 +447,15 @@ impl CTAssignable for AffineNielsPoint { } } +impl CTAssignable for ExtendedPoint { + fn conditional_assign(&mut self, other: &ExtendedPoint, choice: u8) { + self.X.conditional_assign(&other.X, choice); + self.Y.conditional_assign(&other.Y, choice); + self.Z.conditional_assign(&other.Z, choice); + self.T.conditional_assign(&other.T, choice); + } +} + // ------------------------------------------------------------------------ // Constant-time Equality // ------------------------------------------------------------------------ @@ -817,6 +828,29 @@ impl<'a, 'b> Mul<&'b Scalar> for &'a ExtendedPoint { } } +impl<'a, 'b> Mul<&'b ExtendedPoint> for &'a Scalar { + type Output = ExtendedPoint; + + /// Scalar multiplication: compute `self * point`. + /// + /// Uses a window of size 4. Note: for scalar multiplication of + /// the basepoint, `basepoint_mult` is approximately 4x faster. + fn mul(self, point: &'b ExtendedPoint) -> ExtendedPoint { + point * &self + } +} + +#[cfg(feature = "yolocrypto")] +impl<'a, 'b> Mul<&'b DecafPoint> for &'a Scalar { + type Output = DecafPoint; + + /// Scalar multiplication: compute `self * scalar`. + fn mul(self, point: &'b DecafPoint) -> DecafPoint { + DecafPoint(self * &point.0) + } +} + + /// Precomputation #[derive(Clone)] pub struct EdwardsBasepointTable(pub [[AffineNielsPoint; 8]; 32]); @@ -870,6 +904,39 @@ impl<'a, 'b> Mul<&'b Scalar> for &'a EdwardsBasepointTable { } } +impl<'a, 'b> Mul<&'a EdwardsBasepointTable> for &'b Scalar { + type Output = ExtendedPoint; + + /// Construct an `ExtendedPoint` by via this `Scalar` times + /// a the basepoint, `B` included in a precomputed `basepoint_table`. + /// + /// Precondition: this scalar must be reduced. + /// + /// The computation proceeds as follows, as described on page 13 + /// of the Ed25519 paper. Write this scalar `a` in radix 16 with + /// coefficients in [-8,8), i.e., + /// + /// a = a_0 + a_1*16^1 + ... + a_63*16^63, + /// + /// with -8 ≤ a_i < 8. Then + /// + /// a*B = a_0*B + a_1*16^1*B + ... + a_63*16^63*B. + /// + /// Grouping even and odd coefficients gives + /// + /// a*B = a_0*16^0*B + a_2*16^2*B + ... + a_62*16^62*B + /// + a_1*16^1*B + a_3*16^3*B + ... + a_63*16^63*B + /// = (a_0*16^0*B + a_2*16^2*B + ... + a_62*16^62*B) + /// + 16*(a_1*16^0*B + a_3*16^2*B + ... + a_63*16^62*B). + /// + /// We then use the `select_precomputed_point` function, which + /// takes `-8 ≤ x < 8` and `[16^2i * B, ..., 8 * 16^2i * B]`, + /// and returns `x * 16^2i * B` in constant time. + fn mul(self, basepoint_table: &'a EdwardsBasepointTable) -> ExtendedPoint { + basepoint_table * &self + } +} + impl EdwardsBasepointTable { /// Create a table of precomputed multiples of `basepoint`. pub fn create(basepoint: &ExtendedPoint) -> EdwardsBasepointTable { @@ -1150,6 +1217,8 @@ pub mod vartime { #[cfg(test)] mod test { + #[cfg(feature = "yolocrypto")] + use decaf::DecafPoint; use field::FieldElement; use scalar::Scalar; use subtle::CTAssignable; @@ -1459,6 +1528,29 @@ mod test { } } + #[test] + fn scalarmult_extended_point_works_both_ways() { + let G: ExtendedPoint = constants::ED25519_BASEPOINT; + let s: Scalar = A_SCALAR; + + let P1 = &G * &s; + let P2 = &s * &G; + + assert!(P1.compress_edwards().to_bytes() == P2.compress_edwards().to_bytes()); + } + + #[test] + #[cfg(feature = "yolocrypto")] + fn scalarmult_decafpoint_works_both_ways() { + let P: DecafPoint = DecafPoint(constants::ED25519_BASEPOINT); + let s: Scalar = A_SCALAR; + + let P1 = &P * &s; + let P2 = &s * &P; + + assert!(P1.compress().as_bytes() == P2.compress().as_bytes()); + } + mod vartime { use super::super::*; use super::{A_SCALAR, B_SCALAR, A_TIMES_BASEPOINT, DOUBLE_SCALAR_MULT_RESULT}; diff --git a/src/decaf.rs b/src/decaf.rs index 4fba23f..9d36c10 100644 --- a/src/decaf.rs +++ b/src/decaf.rs @@ -271,6 +271,14 @@ impl<'a, 'b> Mul<&'b Scalar> for &'a DecafBasepointTable { } } +impl<'a, 'b> Mul<&'a DecafBasepointTable> for &'b Scalar { + type Output = DecafPoint; + + fn mul(self, basepoint_table: &'a DecafBasepointTable) -> DecafPoint { + DecafPoint(self * &basepoint_table.0) + } +} + impl DecafBasepointTable { /// Create a precomputed table of multiples of the given `basepoint`. pub fn create(basepoint: &DecafPoint) -> DecafBasepointTable { @@ -283,6 +291,38 @@ impl DecafBasepointTable { } } +// ------------------------------------------------------------------------ +// Constant-time conditional assignment +// ------------------------------------------------------------------------ + +impl CTAssignable for DecafPoint { + /// Conditionally assign `other` to `self`, if `choice == 1u8`. + /// + /// # Example + /// + /// ``` + /// # use curve25519_dalek::curve::Identity; + /// # use curve25519_dalek::decaf::DecafPoint; + /// # use curve25519_dalek::subtle::CTAssignable; + /// # use curve25519_dalek::constants; + /// let A = DecafPoint::identity(); + /// let B = constants::DECAF_ED25519_BASEPOINT; + /// + /// let mut P = A; + /// + /// P.conditional_assign(&B, 0u8); + /// 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); + self.0.Y.conditional_assign(&other.0.Y, choice); + self.0.Z.conditional_assign(&other.0.Z, choice); + self.0.T.conditional_assign(&other.0.T, choice); + } +} + // ------------------------------------------------------------------------ // Debug traits // ------------------------------------------------------------------------ diff --git a/src/scalar.rs b/src/scalar.rs index 90f3931..34a45ba 100644 --- a/src/scalar.rs +++ b/src/scalar.rs @@ -775,10 +775,11 @@ mod test { assert_eq!(should_be_one, Scalar::one()); } + #[allow(non_snake_case)] #[test] fn impl_mul() { - let should_be_X_TIMES_Y = &X * &Y; - assert_eq!(should_be_X_TIMES_Y, X_TIMES_Y); + let should_be_X_times_Y = &X * &Y; + assert_eq!(should_be_X_times_Y, X_TIMES_Y); } #[test] @@ -809,6 +810,7 @@ mod test { } } + #[allow(non_snake_case)] #[test] fn invert() { let inv_X = X.invert(); @@ -817,6 +819,7 @@ mod test { } // Negating a scalar twice should result in the original scalar. + #[allow(non_snake_case)] #[test] fn neg_twice_is_identity() { let negative_X = -&X;