From 7a2ea44ce647342539bbedca5639bae5de15de83 Mon Sep 17 00:00:00 2001 From: Henry & Isis Date: Sat, 11 Mar 2017 12:01:29 -0800 Subject: [PATCH 01/10] Test multiplication by basepoint order --- src/curve.rs | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/src/curve.rs b/src/curve.rs index beb92a3..903375a 100644 --- a/src/curve.rs +++ b/src/curve.rs @@ -1270,6 +1270,13 @@ mod test { assert_eq!(aB.compress_edwards(), A_TIMES_BASEPOINT); } + /// Test that multiplication by the basepoint order kills the basepoint + #[test] + fn basepoint_mult_by_basepoint_order() { + let should_be_id = ExtendedPoint::basepoint_mult(&constants::l); + assert!(should_be_id.is_identity()); + } + /// Test scalar_mult versus a known scalar multiple from ed25519.py #[test] fn scalar_mult_vs_ed25519py() { From 05fa1318b900b67e5833653d9022cbcced24b64f Mon Sep 17 00:00:00 2001 From: Henry de Valence Date: Mon, 6 Mar 2017 21:11:01 -0800 Subject: [PATCH 02/10] First work on dynamic basepoint table generation --- src/curve.rs | 89 ++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 89 insertions(+) diff --git a/src/curve.rs b/src/curve.rs index 903375a..11a37a8 100644 --- a/src/curve.rs +++ b/src/curve.rs @@ -81,6 +81,9 @@ use core::fmt::Debug; use core::iter::Iterator; use core::ops::{Add, Sub, Neg}; +#[cfg(feature = "std")] +use std::boxed::Box; + use constants; use field::FieldElement; use scalar::Scalar; @@ -822,6 +825,83 @@ impl ScalarMult for ExtendedPoint { } } +/// Precomputation +#[derive(Clone)] +pub struct BasepointTable(pub [[AffineNielsPoint; 8]; 32]); + +impl BasepointTable { + /// Create a table of precomputed multiples of `basepoint`. + pub fn create(basepoint: &ExtendedPoint) -> Box { + // Create the table storage + // XXX this is a dirty hack, does placement new work here? + let mut table: Box<[[AffineNielsPoint; 8]; 32]> = unsafe { + Box::from_raw( + Box::into_raw( // 8 * 32 = 256 + vec![AffineNielsPoint::identity(); 256].into_boxed_slice() + ) as *mut [[AffineNielsPoint; 8]; 32] + ) + }; + let mut P = basepoint.clone(); + for i in 0..32 { + // P = (16^2)^i * B + let mut jP = P.to_affine_niels(); + for j in 1..9 { + // table[i][j-1] is supposed to be j*(16^2)^i*B + table[i][j-1] = jP; + jP = (&P + &jP).to_extended().to_affine_niels(); + } + P = P.mult_by_pow_2(8); + } + // XXX can we do just 1 alloc instead of 2? + return Box::new(BasepointTable(*table)); + } + + /// Construct an `ExtendedPoint` from a `Scalar`, `scalar`, by + /// computing the multiple `aB` of the basepoint `B`. + /// + /// Precondition: the scalar must be reduced. + /// + /// The computation proceeds as follows, as described on page 13 + /// of the Ed25519 paper. Write the 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 basepoint_mult(&self, scalar: &Scalar) -> ExtendedPoint { //GeScalarMultBase + let e = scalar.to_radix_16(); + let mut h = ExtendedPoint::identity(); + let mut t: CompletedPoint; + + for i in (0..64).filter(|x| x % 2 == 1) { + t = &h + &select_precomputed_point(e[i], &self.0[i/2]); + h = t.to_extended(); + } + + h = h.mult_by_pow_2(4); + + for i in (0..64).filter(|x| x % 2 == 0) { + t = &h + &select_precomputed_point(e[i], &self.0[i/2]); + h = t.to_extended(); + } + + h + } +} + /// Trait for scalar multiplication of a distinguished basepoint. pub trait BasepointMult { /// Return the basepoint `B`. @@ -1277,6 +1357,15 @@ mod test { assert!(should_be_id.is_identity()); } + /// Test precomputed basepoint mult + #[test] + fn test_precomputed_basepoint_mult() { + let table = BasepointTable::create(&constants::BASEPOINT); + let aB_1 = ExtendedPoint::basepoint_mult(&A_SCALAR); + let aB_2 = table.basepoint_mult(&A_SCALAR); + assert_eq!(aB_1.compress(), aB_2.compress()); + } + /// Test scalar_mult versus a known scalar multiple from ed25519.py #[test] fn scalar_mult_vs_ed25519py() { From 640f40287fe94a2d000537d93479796d7b8a3ece Mon Sep 17 00:00:00 2001 From: Henry de Valence Date: Mon, 6 Mar 2017 21:48:31 -0800 Subject: [PATCH 03/10] Wrap the existing basepoint table as a BasepointTable --- src/constants.rs | 26 ++--------- src/curve.rs | 111 +++++++++++++++-------------------------------- 2 files changed, 40 insertions(+), 97 deletions(-) diff --git a/src/constants.rs b/src/constants.rs index 112d060..6072293 100644 --- a/src/constants.rs +++ b/src/constants.rs @@ -23,6 +23,7 @@ use field::FieldElement; use curve::ExtendedPoint; use curve::AffineNielsPoint; use curve::CompressedEdwardsY; +use curve::BasepointTable; use scalar::Scalar; pub const d: FieldElement = FieldElement([ @@ -100,7 +101,7 @@ pub const BASE_CMPRSSD: CompressedEdwardsY = 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66]); /// Basepoint has y = 4/5. -pub const BASEPOINT: ExtendedPoint = ExtendedPoint{ +pub const ED25519_BASEPOINT: ExtendedPoint = ExtendedPoint{ X: FieldElement([-14297830, -7645148, 16144683, -16471763, 27570974, -2696100, -26142465, 8378389, 20764389, 8758491]), Y: FieldElement([-26843541, -6710886, 13421773, -13421773, 26843546, 6710886, -13421773, 13421773, -26843546, -6710886]), Z: FieldElement([1, 0, 0, 0, 0, 0, 0, 0, 0, 0]), @@ -225,7 +226,7 @@ pub const bi: [AffineNielsPoint; 8] = [ /// /// The table is defined so `constants::base[i][j-1] = j*(16^2i)*B`, /// for `0 ≤ i < 32`, `1 ≤ j < 9`. -pub const base: [[AffineNielsPoint; 8]; 32] = [ +pub const ED25519_BASEPOINT_TABLE: BasepointTable = BasepointTable([ [ AffineNielsPoint{ y_plus_x: FieldElement([25967493, -14356035, 29566456, 3660896, -12694345, 4014787, 27544626, -11754271, -6079156, 2047605]), @@ -1569,7 +1570,7 @@ pub const base: [[AffineNielsPoint; 8]; 32] = [ y_minus_x: FieldElement([29701166, -14373934, -10878120, 9279288, -17568, 13127210, 21382910, 11042292, 25838796, 4642684]), xy2d: FieldElement([-20430234, 14955537, -24126347, 8124619, -5369288, -5990470, 30468147, -13900640, 18423289, 4177476]), }, -]]; +]]); #[cfg(test)] mod test { @@ -1670,23 +1671,4 @@ mod test { let a_minus_d = &a - &constants::d; assert_eq!(a_minus_d, constants::a_minus_d); } - - /// Test the values in the lookup table of precomputed multiples - /// of the basepoint. - #[test] - fn test_precomputed_basepoint_multiples() { - let bp = constants::BASE_CMPRSSD.decompress().unwrap(); - let mut P = bp; - for i in 0..32 { - // P = (16^2)^i * B - let mut jP = P.to_affine_niels(); - for j in 1..9 { - // constants::base[i][j-1] is supposed to be - // j * (16^2)^i * B - assert_eq!(constants::base[i][j-1], jP); - jP = (&P + &jP).to_extended().to_affine_niels(); - } - P = P.mult_by_pow_2(8); - } - } } diff --git a/src/curve.rs b/src/curve.rs index 11a37a8..804d180 100644 --- a/src/curve.rs +++ b/src/curve.rs @@ -912,52 +912,11 @@ pub trait BasepointMult { impl BasepointMult for ExtendedPoint { fn basepoint() -> ExtendedPoint { - constants::BASEPOINT + constants::ED25519_BASEPOINT } - /// Construct an `ExtendedPoint` from a `Scalar`, `scalar`, by - /// computing the multiple `aB` of the basepoint `B`. - /// - /// Precondition: the scalar must be reduced. - /// - /// The computation proceeds as follows, as described on page 13 - /// of the Ed25519 paper. Write the 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 basepoint_mult(scalar: &Scalar) -> ExtendedPoint { //GeScalarMultBase - let e = scalar.to_radix_16(); - let mut h = ExtendedPoint::identity(); - let mut t: CompletedPoint; - - for i in (0..64).filter(|x| x % 2 == 1) { - t = &h + &select_precomputed_point(e[i], &constants::base[i/2]); - h = t.to_extended(); - } - - h = h.mult_by_pow_2(4); - - for i in (0..64).filter(|x| x % 2 == 0) { - t = &h + &select_precomputed_point(e[i], &constants::base[i/2]); - h = t.to_extended(); - } - - h + fn basepoint_mult(scalar: &Scalar) -> ExtendedPoint { + constants::ED25519_BASEPOINT_TABLE.basepoint_mult(scalar) } } @@ -1222,7 +1181,7 @@ mod test { /// Test Montgomery conversion against the X25519 basepoint. #[test] fn basepoint_to_montgomery() { - assert_eq!(constants::BASEPOINT.compress_montgomery().unwrap(), + assert_eq!(constants::ED25519_BASEPOINT.compress_montgomery().unwrap(), BASE_CMPRSSD_MONTY); } @@ -1275,10 +1234,10 @@ mod test { .decompress().unwrap(); // Test projective coordinates exactly since we know they should // only differ by a flipped sign. - assert_eq!(minus_basepoint.X, -(&constants::BASEPOINT.X)); - assert_eq!(minus_basepoint.Y, constants::BASEPOINT.Y); - assert_eq!(minus_basepoint.Z, constants::BASEPOINT.Z); - assert_eq!(minus_basepoint.T, -(&constants::BASEPOINT.T)); + assert_eq!(minus_basepoint.X, -(&constants::ED25519_BASEPOINT.X)); + assert_eq!(minus_basepoint.Y, constants::ED25519_BASEPOINT.Y); + assert_eq!(minus_basepoint.Z, constants::ED25519_BASEPOINT.Z); + assert_eq!(minus_basepoint.T, -(&constants::ED25519_BASEPOINT.T)); } /// Test that computing 1*basepoint gives the correct basepoint. @@ -1293,7 +1252,7 @@ mod test { /// using basepoint + basepoint versus the 2*basepoint constant. #[test] fn basepoint_plus_basepoint_vs_basepoint2() { - let bp = constants::BASEPOINT; + let bp = constants::ED25519_BASEPOINT; let bp_added = &bp + &bp; assert_eq!(bp_added.compress_edwards(), BASE2_CMPRSSD); } @@ -1302,7 +1261,7 @@ mod test { /// using the basepoint, basepoint2 constants #[test] fn basepoint_plus_basepoint_projective_niels_vs_basepoint2() { - let bp = constants::BASEPOINT; + let bp = constants::ED25519_BASEPOINT; let bp_added = (&bp + &bp.to_projective_niels()).to_extended(); assert_eq!(bp_added.compress_edwards(), BASE2_CMPRSSD); } @@ -1311,7 +1270,7 @@ mod test { /// using the basepoint, basepoint2 constants #[test] fn basepoint_plus_basepoint_affine_niels_vs_basepoint2() { - let bp = constants::BASEPOINT; + let bp = constants::ED25519_BASEPOINT; let bp_affine_niels = bp.to_affine_niels(); let bp_added = (&bp + &bp_affine_niels).to_extended(); assert_eq!(bp_added.compress_edwards(), BASE2_CMPRSSD); @@ -1360,16 +1319,17 @@ mod test { /// Test precomputed basepoint mult #[test] fn test_precomputed_basepoint_mult() { - let table = BasepointTable::create(&constants::BASEPOINT); + let table = BasepointTable::create(&constants::ED25519_BASEPOINT); let aB_1 = ExtendedPoint::basepoint_mult(&A_SCALAR); let aB_2 = table.basepoint_mult(&A_SCALAR); - assert_eq!(aB_1.compress(), aB_2.compress()); + assert_eq!(aB_1.compress_edwards(), + aB_2.compress_edwards()); } /// Test scalar_mult versus a known scalar multiple from ed25519.py #[test] fn scalar_mult_vs_ed25519py() { - let aB = constants::BASEPOINT.scalar_mult(&A_SCALAR); + let aB = constants::ED25519_BASEPOINT.scalar_mult(&A_SCALAR); assert_eq!(aB.compress_edwards(), A_TIMES_BASEPOINT); } @@ -1384,7 +1344,7 @@ mod test { /// Test basepoint.double() versus the 2*basepoint constant. #[test] fn basepoint_double_vs_basepoint2() { - assert_eq!(constants::BASEPOINT.double().compress_edwards(), + assert_eq!(constants::ED25519_BASEPOINT.double().compress_edwards(), BASE2_CMPRSSD); } @@ -1399,14 +1359,15 @@ mod test { /// Check that converting to projective and then back to extended round-trips. #[test] fn basepoint_projective_extended_round_trip() { - assert_eq!(constants::BASEPOINT.to_projective().to_extended().compress_edwards(), + assert_eq!(constants::ED25519_BASEPOINT + .to_projective().to_extended().compress_edwards(), constants::BASE_CMPRSSD); } /// Test computing 16*basepoint vs mult_by_pow_2(4) #[test] fn basepoint16_vs_mult_by_pow_2_4() { - let bp16 = constants::BASEPOINT.mult_by_pow_2(4); + let bp16 = constants::ED25519_BASEPOINT.mult_by_pow_2(4); assert_eq!(bp16.compress_edwards(), BASE16_CMPRSSD); } @@ -1415,7 +1376,7 @@ mod test { fn conditional_assign_for_affine_niels_point() { let id = AffineNielsPoint::identity(); let mut p1 = AffineNielsPoint::identity(); - let bp = constants::BASEPOINT.to_affine_niels(); + let bp = constants::ED25519_BASEPOINT.to_affine_niels(); p1.conditional_assign(&bp, 0); assert_eq!(p1, id); @@ -1426,7 +1387,7 @@ mod test { #[test] fn is_small_order() { // The basepoint has large prime order - assert!(constants::BASEPOINT.is_small_order() == false); + assert!(constants::ED25519_BASEPOINT.is_small_order() == false); // constants::EIGHT_TORSION has all points of small order. for torsion_point in &constants::EIGHT_TORSION { assert!(torsion_point.is_small_order() == true); @@ -1441,8 +1402,8 @@ mod test { #[test] fn is_identity() { - assert!(ExtendedPoint::identity().is_identity() == true); - assert!( constants::BASEPOINT.is_identity() == false); + assert!( ExtendedPoint::identity().is_identity() == true); + assert!(constants::ED25519_BASEPOINT.is_identity() == false); } } @@ -1464,13 +1425,13 @@ mod bench { #[bench] fn scalar_mult(b: &mut Bencher) { - let bp = constants::BASEPOINT; + let bp = constants::ED25519_BASEPOINT; b.iter(|| bp.scalar_mult(&A_SCALAR)); } #[bench] fn bench_select_precomputed_point(b: &mut Bencher) { - b.iter(|| select_precomputed_point(0, &constants::base[12])); + b.iter(|| select_precomputed_point(0, &constants::ED25519_BASEPOINT_TABLE.0[0])); } #[bench] @@ -1481,53 +1442,53 @@ mod bench { #[bench] fn add_extended_and_cached_output_completed(b: &mut Bencher) { - let p1 = constants::BASEPOINT; - let p2 = constants::BASEPOINT.to_projective_niels(); + let p1 = constants::ED25519_BASEPOINT; + let p2 = constants::ED25519_BASEPOINT.to_projective_niels(); b.iter(|| &p1 + &p2); } #[bench] fn add_extended_and_cached_output_extended(b: &mut Bencher) { - let p1 = constants::BASEPOINT; - let p2 = constants::BASEPOINT.to_projective_niels(); + let p1 = constants::ED25519_BASEPOINT; + let p2 = constants::ED25519_BASEPOINT.to_projective_niels(); b.iter(|| (&p1 + &p2).to_extended()); } #[bench] fn add_extended_and_precomputed_output_completed(b: &mut Bencher) { - let p1 = constants::BASEPOINT; - let p2 = select_precomputed_point(6, &constants::base[27]); + let p1 = constants::ED25519_BASEPOINT; + let p2 = constants::ED25519_BASEPOINT.to_affine_niels(); b.iter(|| &p1 + &p2); } #[bench] fn add_extended_and_precomputed_output_extended(b: &mut Bencher) { - let p1 = constants::BASEPOINT; - let p2 = select_precomputed_point(6, &constants::base[27]); + let p1 = constants::ED25519_BASEPOINT; + let p2 = constants::ED25519_BASEPOINT.to_affine_niels(); b.iter(|| (&p1 + &p2).to_extended()); } #[bench] fn projective_double_output_completed(b: &mut Bencher) { - let p1 = constants::BASEPOINT.to_projective(); + let p1 = constants::ED25519_BASEPOINT.to_projective(); b.iter(|| p1.double() ); } #[bench] fn extended_double_output_extended(b: &mut Bencher) { - let p1 = constants::BASEPOINT; + let p1 = constants::ED25519_BASEPOINT; b.iter(|| p1.double() ); } #[bench] fn mult_by_cofactor(b: &mut Bencher) { - let p1 = constants::BASEPOINT; + let p1 = constants::ED25519_BASEPOINT; b.iter(|| p1.mult_by_cofactor() ); } From a4ed8e2b81aabe7954aa76ed4217fa75f102945a Mon Sep 17 00:00:00 2001 From: Henry de Valence Date: Mon, 6 Mar 2017 22:08:32 -0800 Subject: [PATCH 04/10] Use box syntax instead of an unsafe block --- src/curve.rs | 8 +------- src/lib.rs | 1 + 2 files changed, 2 insertions(+), 7 deletions(-) diff --git a/src/curve.rs b/src/curve.rs index 804d180..96e0b16 100644 --- a/src/curve.rs +++ b/src/curve.rs @@ -834,13 +834,7 @@ impl BasepointTable { pub fn create(basepoint: &ExtendedPoint) -> Box { // Create the table storage // XXX this is a dirty hack, does placement new work here? - let mut table: Box<[[AffineNielsPoint; 8]; 32]> = unsafe { - Box::from_raw( - Box::into_raw( // 8 * 32 = 256 - vec![AffineNielsPoint::identity(); 256].into_boxed_slice() - ) as *mut [[AffineNielsPoint; 8]; 32] - ) - }; + let mut table = box [[AffineNielsPoint::identity(); 8]; 32]; let mut P = basepoint.clone(); for i in 0..32 { // P = (16^2)^i * B diff --git a/src/lib.rs b/src/lib.rs index 947a531..bcacba1 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -13,6 +13,7 @@ #![cfg_attr(not(feature = "std"), feature(collections))] #![allow(unused_features)] #![feature(test)] +#![feature(box_syntax)] #![deny(missing_docs)] // refuse to compile if documentation is missing //! # curve25519-dalek From e757959bb89501b17ca656a3657068b4844fad15 Mon Sep 17 00:00:00 2001 From: Henry de Valence Date: Mon, 6 Mar 2017 22:22:11 -0800 Subject: [PATCH 05/10] Add benchmark for basepoint table creation --- src/curve.rs | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/curve.rs b/src/curve.rs index 96e0b16..817a43e 100644 --- a/src/curve.rs +++ b/src/curve.rs @@ -1486,4 +1486,10 @@ mod bench { b.iter(|| p1.mult_by_cofactor() ); } + + #[bench] + fn create_basepoint_table(b: &mut Bencher) { + let aB = ExtendedPoint::basepoint_mult(&A_SCALAR); + b.iter(|| BasepointTable::create(&aB)); + } } From f312160d2cf81acbfff89e69445e399a26df7970 Mon Sep 17 00:00:00 2001 From: Henry & Isis Date: Fri, 10 Mar 2017 22:16:11 -0800 Subject: [PATCH 06/10] Fixup errors introduced from not running yolocrypto tests by default --- src/decaf.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/decaf.rs b/src/decaf.rs index db12cde..99fe115 100644 --- a/src/decaf.rs +++ b/src/decaf.rs @@ -253,7 +253,7 @@ impl BasepointMult for DecafPoint { // XXX is this actually in the image of the isogeny, // or do we need a different basepoint? fn basepoint() -> DecafPoint { - DecafPoint(constants::BASEPOINT) + DecafPoint(ExtendedPoint::basepoint()) } fn basepoint_mult(scalar: &Scalar) -> DecafPoint { @@ -322,7 +322,7 @@ mod test { // Check that bp_recaf differs from bp by a point of order 4 let diff = &ExtendedPoint::basepoint() - &bp_recaf; let diff4 = diff.mult_by_pow_2(4); - assert_eq!(diff4.compress_edwards(), ExtendedPoint::identity().compress_edwards()); + assert_eq!(diff4.compress_edwards(), CompressedEdwardsY::identity()); } #[test] From c873f725a5601e425042d9c6ddd2f9a42caae965 Mon Sep 17 00:00:00 2001 From: Henry & Isis Date: Fri, 10 Mar 2017 22:21:17 -0800 Subject: [PATCH 07/10] Rename `BasepointTable` as `EdwardsBasepointTable`. --- src/constants.rs | 4 ++-- src/curve.rs | 20 ++++++++++---------- 2 files changed, 12 insertions(+), 12 deletions(-) diff --git a/src/constants.rs b/src/constants.rs index 6072293..bfc103d 100644 --- a/src/constants.rs +++ b/src/constants.rs @@ -23,7 +23,7 @@ use field::FieldElement; use curve::ExtendedPoint; use curve::AffineNielsPoint; use curve::CompressedEdwardsY; -use curve::BasepointTable; +use curve::EdwardsBasepointTable; use scalar::Scalar; pub const d: FieldElement = FieldElement([ @@ -226,7 +226,7 @@ pub const bi: [AffineNielsPoint; 8] = [ /// /// The table is defined so `constants::base[i][j-1] = j*(16^2i)*B`, /// for `0 ≤ i < 32`, `1 ≤ j < 9`. -pub const ED25519_BASEPOINT_TABLE: BasepointTable = BasepointTable([ +pub const ED25519_BASEPOINT_TABLE: EdwardsBasepointTable = EdwardsBasepointTable([ [ AffineNielsPoint{ 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 817a43e..b736f65 100644 --- a/src/curve.rs +++ b/src/curve.rs @@ -827,27 +827,27 @@ impl ScalarMult for ExtendedPoint { /// Precomputation #[derive(Clone)] -pub struct BasepointTable(pub [[AffineNielsPoint; 8]; 32]); +pub struct EdwardsBasepointTable(pub [[AffineNielsPoint; 8]; 32]); -impl BasepointTable { +impl EdwardsBasepointTable { /// Create a table of precomputed multiples of `basepoint`. - pub fn create(basepoint: &ExtendedPoint) -> Box { + pub fn create(basepoint: &ExtendedPoint) -> Box { // Create the table storage - // XXX this is a dirty hack, does placement new work here? - let mut table = box [[AffineNielsPoint::identity(); 8]; 32]; + // XXX can we be assured that this is not allocated on the stack? + // XXX can we skip the initialization without too much unsafety? + let mut table = box EdwardsBasepointTable([[AffineNielsPoint::identity(); 8]; 32]); let mut P = basepoint.clone(); for i in 0..32 { // P = (16^2)^i * B let mut jP = P.to_affine_niels(); for j in 1..9 { // table[i][j-1] is supposed to be j*(16^2)^i*B - table[i][j-1] = jP; + table.0[i][j-1] = jP; jP = (&P + &jP).to_extended().to_affine_niels(); } P = P.mult_by_pow_2(8); } - // XXX can we do just 1 alloc instead of 2? - return Box::new(BasepointTable(*table)); + return table } /// Construct an `ExtendedPoint` from a `Scalar`, `scalar`, by @@ -1313,7 +1313,7 @@ mod test { /// Test precomputed basepoint mult #[test] fn test_precomputed_basepoint_mult() { - let table = BasepointTable::create(&constants::ED25519_BASEPOINT); + let table = EdwardsBasepointTable::create(&constants::ED25519_BASEPOINT); let aB_1 = ExtendedPoint::basepoint_mult(&A_SCALAR); let aB_2 = table.basepoint_mult(&A_SCALAR); assert_eq!(aB_1.compress_edwards(), @@ -1490,6 +1490,6 @@ mod bench { #[bench] fn create_basepoint_table(b: &mut Bencher) { let aB = ExtendedPoint::basepoint_mult(&A_SCALAR); - b.iter(|| BasepointTable::create(&aB)); + b.iter(|| EdwardsBasepointTable::create(&aB)); } } From 049556147fcc83de20ed0a071d9f90022dc7246c Mon Sep 17 00:00:00 2001 From: Henry & Isis Date: Fri, 10 Mar 2017 22:43:07 -0800 Subject: [PATCH 08/10] Add wrapper for basepoint precomputations for decaf --- src/curve.rs | 2 +- src/decaf.rs | 34 ++++++++++++++++++++++++++++++++++ 2 files changed, 35 insertions(+), 1 deletion(-) diff --git a/src/curve.rs b/src/curve.rs index b736f65..f90e69b 100644 --- a/src/curve.rs +++ b/src/curve.rs @@ -875,7 +875,7 @@ impl EdwardsBasepointTable { /// 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 basepoint_mult(&self, scalar: &Scalar) -> ExtendedPoint { //GeScalarMultBase + pub fn basepoint_mult(&self, scalar: &Scalar) -> ExtendedPoint { let e = scalar.to_radix_16(); let mut h = ExtendedPoint::identity(); let mut t: CompletedPoint; diff --git a/src/decaf.rs b/src/decaf.rs index 99fe115..71a8d1c 100644 --- a/src/decaf.rs +++ b/src/decaf.rs @@ -31,7 +31,11 @@ use subtle::CTNegatable; use core::ops::{Add, Sub, Neg}; +#[cfg(feature = "std")] +use std::boxed::Box; + use curve::ExtendedPoint; +use curve::EdwardsBasepointTable; use curve::BasepointMult; use curve::ScalarMult; use curve::Identity; @@ -261,6 +265,24 @@ impl BasepointMult for DecafPoint { } } + +/// Precomputation +#[derive(Clone)] +pub struct DecafBasepointTable(EdwardsBasepointTable); + +impl DecafBasepointTable { + /// Create a precomputed table of multiples of the given `basepoint`. + pub fn create(basepoint: &DecafPoint) -> Box { + let edwards_table = EdwardsBasepointTable::create(&basepoint.0); + box DecafBasepointTable(*edwards_table) + } + + /// Use the precomputed table to quickly compute `scalar * basepoint` + pub fn basepoint_mult(&self, scalar: &Scalar) -> DecafPoint { + DecafPoint(self.0.basepoint_mult(scalar)) + } +} + // ------------------------------------------------------------------------ // Debug traits // ------------------------------------------------------------------------ @@ -356,6 +378,18 @@ mod test { assert_eq!(P, Q); } } + + /// Test basepoint_mult versus a newly-generated DecafBasepointTable + #[test] + fn basepoint_mult_vs_decafbasepointtable() { + let table = DecafBasepointTable::create(&DecafPoint::basepoint()); + let mut rng = OsRng::new().unwrap(); + let s = Scalar::random(&mut rng); + let basepoint_mult_s = DecafPoint::basepoint_mult(&s); + let table_basepoint_mult_s = table.basepoint_mult(&s); + + assert_eq!(basepoint_mult_s, table_basepoint_mult_s); + } } #[cfg(test)] From 2610ab872a6a0b4174455b52de461655df59e5fe Mon Sep 17 00:00:00 2001 From: Henry de Valence Date: Mon, 13 Mar 2017 16:28:43 -0700 Subject: [PATCH 09/10] Feature-gate basepoint table creation on a `nightly` feature --- Cargo.toml | 3 +++ src/curve.rs | 8 +++++--- src/lib.rs | 2 +- 3 files changed, 9 insertions(+), 4 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 691f464..f0189e5 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -33,9 +33,12 @@ version = "^0.6" version = "0.4" [features] +nightly = ["basepoint_table_creation"] default = ["std"] std = ["rand"] yolocrypto = [] +# Needs nightly for placement new +basepoint_table_creation = [] # The development profile, used for `cargo build`. [profile.dev] diff --git a/src/curve.rs b/src/curve.rs index f90e69b..054b164 100644 --- a/src/curve.rs +++ b/src/curve.rs @@ -81,9 +81,6 @@ use core::fmt::Debug; use core::iter::Iterator; use core::ops::{Add, Sub, Neg}; -#[cfg(feature = "std")] -use std::boxed::Box; - use constants; use field::FieldElement; use scalar::Scalar; @@ -95,6 +92,8 @@ use subtle::CTNegatable; #[cfg(not(feature = "std"))] use collections::boxed::Box; +#[cfg(feature = "std")] +use std::boxed::Box; // ------------------------------------------------------------------------ // Compressed points @@ -831,6 +830,7 @@ pub struct EdwardsBasepointTable(pub [[AffineNielsPoint; 8]; 32]); impl EdwardsBasepointTable { /// Create a table of precomputed multiples of `basepoint`. + #[cfg(feature="basepoint_table_creation")] pub fn create(basepoint: &ExtendedPoint) -> Box { // Create the table storage // XXX can we be assured that this is not allocated on the stack? @@ -1312,6 +1312,7 @@ mod test { /// Test precomputed basepoint mult #[test] + #[cfg(feature="basepoint_table_creation")] fn test_precomputed_basepoint_mult() { let table = EdwardsBasepointTable::create(&constants::ED25519_BASEPOINT); let aB_1 = ExtendedPoint::basepoint_mult(&A_SCALAR); @@ -1487,6 +1488,7 @@ mod bench { b.iter(|| p1.mult_by_cofactor() ); } + #[cfg(feature="basepoint_table_creation")] #[bench] fn create_basepoint_table(b: &mut Bencher) { let aB = ExtendedPoint::basepoint_mult(&A_SCALAR); diff --git a/src/lib.rs b/src/lib.rs index bcacba1..b268354 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -11,9 +11,9 @@ #![cfg_attr(not(feature = "std"), no_std)] #![cfg_attr(not(feature = "std"), feature(collections))] +#![cfg_attr(feature = "nightly", feature(box_syntax))] #![allow(unused_features)] #![feature(test)] -#![feature(box_syntax)] #![deny(missing_docs)] // refuse to compile if documentation is missing //! # curve25519-dalek From 26a77cd7f3a6dc325b2ddb77261f85f45a9968d4 Mon Sep 17 00:00:00 2001 From: Isis Lovecruft Date: Tue, 14 Mar 2017 03:21:32 +0000 Subject: [PATCH 10/10] Feature-gate box syntax on both std and basepoint_table_creation. --- src/curve.rs | 4 ++-- src/decaf.rs | 6 +++++- 2 files changed, 7 insertions(+), 3 deletions(-) diff --git a/src/curve.rs b/src/curve.rs index 054b164..4fad323 100644 --- a/src/curve.rs +++ b/src/curve.rs @@ -90,9 +90,9 @@ use subtle::CTAssignable; use subtle::CTEq; use subtle::CTNegatable; -#[cfg(not(feature = "std"))] +#[cfg(all(not(feature = "std"), feature = "basepoint_table_creation"))] use collections::boxed::Box; -#[cfg(feature = "std")] +#[cfg(all(feature = "std", feature = "basepoint_table_creation"))] use std::boxed::Box; // ------------------------------------------------------------------------ diff --git a/src/decaf.rs b/src/decaf.rs index 71a8d1c..0bee7de 100644 --- a/src/decaf.rs +++ b/src/decaf.rs @@ -31,7 +31,9 @@ use subtle::CTNegatable; use core::ops::{Add, Sub, Neg}; -#[cfg(feature = "std")] +#[cfg(all(not(feature = "std"), feature = "basepoint_table_creation"))] +use collections::boxed::Box; +#[cfg(all(feature = "std", feature = "basepoint_table_creation"))] use std::boxed::Box; use curve::ExtendedPoint; @@ -272,6 +274,7 @@ pub struct DecafBasepointTable(EdwardsBasepointTable); impl DecafBasepointTable { /// Create a precomputed table of multiples of the given `basepoint`. + #[cfg(feature = "basepoint_table_creation")] pub fn create(basepoint: &DecafPoint) -> Box { let edwards_table = EdwardsBasepointTable::create(&basepoint.0); box DecafBasepointTable(*edwards_table) @@ -381,6 +384,7 @@ mod test { /// Test basepoint_mult versus a newly-generated DecafBasepointTable #[test] + #[cfg(feature = "basepoint_table_creation")] fn basepoint_mult_vs_decafbasepointtable() { let table = DecafBasepointTable::create(&DecafPoint::basepoint()); let mut rng = OsRng::new().unwrap();