From 4da1d795a15fed774cd18d1c33628e6bbe5d5ce2 Mon Sep 17 00:00:00 2001 From: Isis Lovecruft Date: Tue, 9 May 2017 00:01:48 +0000 Subject: [PATCH 1/6] Make scalar multiplication go both ways. Being able to do `P * s`, but not `s * P`, is slightly annoying, particularly with longer equations when it is desired to be able to glance at the maths and see that the code is the same. Now either syntax is allowed. --- src/curve.rs | 23 +++++++++++++++++++++++ 1 file changed, 23 insertions(+) diff --git a/src/curve.rs b/src/curve.rs index 78ff254..4ad938c 100644 --- a/src/curve.rs +++ b/src/curve.rs @@ -817,6 +817,18 @@ 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 + } +} + /// Precomputation #[derive(Clone)] pub struct EdwardsBasepointTable(pub [[AffineNielsPoint; 8]; 32]); @@ -1459,6 +1471,17 @@ mod test { } } + #[test] + fn scalarmult_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()); + } + mod vartime { use super::super::*; use super::{A_SCALAR, B_SCALAR, A_TIMES_BASEPOINT, DOUBLE_SCALAR_MULT_RESULT}; From 944e8e164962fbc5869936d9037c18bb6b2f60da Mon Sep 17 00:00:00 2001 From: Isis Lovecruft Date: Tue, 9 May 2017 00:05:11 +0000 Subject: [PATCH 2/6] Fix and allow some non-snakecased variables in scalar tests. --- src/scalar.rs | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/src/scalar.rs b/src/scalar.rs index 73b30f1..75fa0c9 100644 --- a/src/scalar.rs +++ b/src/scalar.rs @@ -776,10 +776,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] @@ -810,6 +811,7 @@ mod test { } } + #[allow(non_snake_case)] #[test] fn invert() { let inv_X = X.invert(); @@ -818,6 +820,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; From 738049619bbdc68044fd1b5529cf175f9c7a8fc3 Mon Sep 17 00:00:00 2001 From: Isis Lovecruft Date: Tue, 9 May 2017 00:17:42 +0000 Subject: [PATCH 3/6] Also make scalar multiplication with DecafPoints go both ways. --- src/curve.rs | 29 ++++++++++++++++++++++++++++- 1 file changed, 28 insertions(+), 1 deletion(-) diff --git a/src/curve.rs b/src/curve.rs index 4ad938c..7dd0c14 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; @@ -829,6 +831,17 @@ impl<'a, 'b> Mul<&'b ExtendedPoint> for &'a Scalar { } } +#[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]); @@ -1162,6 +1175,8 @@ pub mod vartime { #[cfg(test)] mod test { + #[cfg(feature = "yolocrypto")] + use decaf::DecafPoint; use field::FieldElement; use scalar::Scalar; use subtle::CTAssignable; @@ -1472,7 +1487,7 @@ mod test { } #[test] - fn scalarmult_works_both_ways() { + fn scalarmult_extended_point_works_both_ways() { let G: ExtendedPoint = constants::ED25519_BASEPOINT; let s: Scalar = A_SCALAR; @@ -1482,6 +1497,18 @@ mod test { 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}; From b6faf7c05e7e9e4cf973ffa3522a40272f91fd96 Mon Sep 17 00:00:00 2001 From: Isis Lovecruft Date: Sun, 14 May 2017 02:31:36 +0000 Subject: [PATCH 4/6] Implement CTAssignable for ExtendedPoint. --- src/curve.rs | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/src/curve.rs b/src/curve.rs index 7dd0c14..811d4b6 100644 --- a/src/curve.rs +++ b/src/curve.rs @@ -447,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 // ------------------------------------------------------------------------ From 7478814dfc4134805c75997a63ba04a7c24e983a Mon Sep 17 00:00:00 2001 From: Isis Lovecruft Date: Sun, 14 May 2017 02:59:54 +0000 Subject: [PATCH 5/6] Implement CTAssignable for DecafPoint. --- src/decaf.rs | 32 ++++++++++++++++++++++++++++++++ 1 file changed, 32 insertions(+) diff --git a/src/decaf.rs b/src/decaf.rs index 4fba23f..426cea7 100644 --- a/src/decaf.rs +++ b/src/decaf.rs @@ -283,6 +283,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 // ------------------------------------------------------------------------ From 1b7b57c351f530cc85fe9799815ab9a2a85c9fff Mon Sep 17 00:00:00 2001 From: Isis Lovecruft Date: Sun, 14 May 2017 03:10:26 +0000 Subject: [PATCH 6/6] Make basepoint multiplication for precomputed tables go both ways. --- src/curve.rs | 33 +++++++++++++++++++++++++++++++++ src/decaf.rs | 8 ++++++++ 2 files changed, 41 insertions(+) diff --git a/src/curve.rs b/src/curve.rs index 811d4b6..fde57e8 100644 --- a/src/curve.rs +++ b/src/curve.rs @@ -904,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 { diff --git a/src/decaf.rs b/src/decaf.rs index 426cea7..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 {