From 57ebc9d7f9066cd7ce33f641764428f8b9d16290 Mon Sep 17 00:00:00 2001 From: Henry de Valence Date: Mon, 13 Mar 2017 18:08:59 -0700 Subject: [PATCH 01/37] Add an OddMultiples helper struct --- src/curve.rs | 41 +++++++++++++++++++++++++++++------------ 1 file changed, 29 insertions(+), 12 deletions(-) diff --git a/src/curve.rs b/src/curve.rs index aefecac..3d7007c 100644 --- a/src/curve.rs +++ b/src/curve.rs @@ -79,7 +79,7 @@ use core::fmt::Debug; use core::iter::Iterator; -use core::ops::{Add, Sub, Neg}; +use core::ops::{Add, Sub, Neg, Index}; use constants; use field::FieldElement; @@ -957,6 +957,30 @@ impl ExtendedPoint { } } +/// Holds odd multiples 1A, 3A, ..., 15A of a point A. +struct OddMultiples(pub [ProjectiveNielsPoint; 8]); + +impl OddMultiples { + fn create(A: &ExtendedPoint) -> OddMultiples { + let mut Ai = [ProjectiveNielsPoint::identity(); 8]; + let A2 = A.double(); + Ai[0] = A.to_projective_niels(); + for i in 0..7 { + Ai[i+1] = (&A2 + &Ai[i]).to_extended().to_projective_niels(); + } + // Now Ai = [A, 3A, 5A, 7A, 9A, 11A, 13A, 15A] + OddMultiples(Ai) + } +} + +impl Index for OddMultiples { + type Output = ProjectiveNielsPoint; + + fn index<'a>(&'a self, _index: usize) -> &'a ProjectiveNielsPoint { + &(self.0[_index]) + } +} + /// Given a point `A` and scalars `a` and `b`, compute the point /// `aA+bB`, where `B` is the Ed25519 basepoint (i.e., `B = (x,4/5)` /// with x positive). @@ -969,15 +993,6 @@ pub fn double_scalar_mult_vartime(a: &Scalar, A: &ExtendedPoint, b: &Scalar) -> let a_naf = a.non_adjacent_form(); let b_naf = b.non_adjacent_form(); - // Build a lookup table of odd multiples of A - let mut Ai = [ProjectiveNielsPoint::identity(); 8]; - let A2 = A.double(); - Ai[0] = A.to_projective_niels(); - for i in 0..7 { - Ai[i+1] = (&A2 + &Ai[i]).to_extended().to_projective_niels(); - } - // Now Ai = [A, 3A, 5A, 7A, 9A, 11A, 13A, 15A] - // Find starting index let mut i: usize = 255; for j in (0..255).rev() { @@ -987,14 +1002,16 @@ pub fn double_scalar_mult_vartime(a: &Scalar, A: &ExtendedPoint, b: &Scalar) -> } } + let odd_multiples_of_A = OddMultiples::create(A); + let mut r = ProjectivePoint::identity(); loop { let mut t = r.double(); if a_naf[i] > 0 { - t = &t.to_extended() + &Ai[( a_naf[i]/2) as usize]; + t = &t.to_extended() + &odd_multiples_of_A[( a_naf[i]/2) as usize]; } else if a_naf[i] < 0 { - t = &t.to_extended() - &Ai[(-a_naf[i]/2) as usize]; + t = &t.to_extended() - &odd_multiples_of_A[(-a_naf[i]/2) as usize]; } if b_naf[i] > 0 { From abb1b6fef9eaafeecef3fce35bcc455721abd99f Mon Sep 17 00:00:00 2001 From: Henry de Valence Date: Mon, 13 Mar 2017 20:07:38 -0700 Subject: [PATCH 02/37] Add a variable-time k-fold scalar mult function. --- src/curve.rs | 72 +++++++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 71 insertions(+), 1 deletion(-) diff --git a/src/curve.rs b/src/curve.rs index 3d7007c..3c313bd 100644 --- a/src/curve.rs +++ b/src/curve.rs @@ -958,7 +958,7 @@ impl ExtendedPoint { } /// Holds odd multiples 1A, 3A, ..., 15A of a point A. -struct OddMultiples(pub [ProjectiveNielsPoint; 8]); +struct OddMultiples([ProjectiveNielsPoint; 8]); impl OddMultiples { fn create(A: &ExtendedPoint) -> OddMultiples { @@ -981,6 +981,48 @@ impl Index for OddMultiples { } } + +/// Given a vector of public scalars and a vector of (possibly secret) +/// points, compute +/// +/// c_1 P_1 + ... + c_n P_n. +/// +/// # Warning +/// +/// This function is *not* constant time: its timing depends on the +/// input scalars. +/// +/// # Input +/// +/// A vector of `Scalar`s and a vector of `ExtendedPoints`. It is an +/// error to call this function with two vectors of different lengths. +pub fn k_fold_scalar_mult_vartime(scalars: &Vec, + points: &Vec) + -> ExtendedPoint { + assert_eq!(scalars.len(), points.len()); + + let nafs: Vec<_> = scalars.iter().map(|c| c.non_adjacent_form()).collect(); + let odd_multiples: Vec<_> = points.iter().map(|P| OddMultiples::create(&P)).collect(); + + let mut r = ProjectivePoint::identity(); + + for i in (0..255).rev() { + let mut t = r.double(); + + for (naf, odd_multiple) in nafs.iter().zip(odd_multiples.iter()) { + if naf[i] > 0 { + t = &t.to_extended() + &odd_multiple[( naf[i]/2) as usize]; + } else if naf[i] < 0 { + t = &t.to_extended() - &odd_multiple[(-naf[i]/2) as usize]; + } + } + + r = t.to_projective(); + } + + r.to_extended() +} + /// Given a point `A` and scalars `a` and `b`, compute the point /// `aA+bB`, where `B` is the Ed25519 basepoint (i.e., `B = (x,4/5)` /// with x positive). @@ -1352,6 +1394,15 @@ mod test { assert_eq!(result.compress_edwards(), DOUBLE_SCALAR_MULT_RESULT); } + #[test] + fn k_fold_scalar_mult_vartime_vs_ed25519py() { + let A = A_TIMES_BASEPOINT.decompress().unwrap(); + let points = vec![A,constants::ED25519_BASEPOINT]; + let scalars = vec![A_SCALAR, B_SCALAR]; + let result = k_fold_scalar_mult_vartime(&scalars, &points); + assert_eq!(result.compress_edwards(), DOUBLE_SCALAR_MULT_RESULT); + } + /// Test basepoint.double() versus the 2*basepoint constant. #[test] fn basepoint_double_vs_basepoint2() { @@ -1444,6 +1495,7 @@ mod test { #[cfg(all(test, feature = "bench"))] mod bench { + use rand::OsRng; use test::Bencher; use constants; use super::*; @@ -1471,6 +1523,24 @@ mod bench { b.iter(|| double_scalar_mult_vartime(&A_SCALAR, &A, &B_SCALAR)); } + #[bench] + fn ten_fold_scalar_mult_vartime(b: &mut Bencher) { + let mut csprng: OsRng = OsRng::new().unwrap(); + // Create 10 random scalars + let scalars: Vec<_> = (0..10).map(|_| Scalar::random(&mut csprng)).collect(); + // Create 10 points (by doing scalar mults) + let points: Vec<_> = scalars.iter() + .map(|s| ExtendedPoint::basepoint_mult(s)).collect(); + + // XXX Currently Rust's benchmarking implementation doesn't + // allow you to specify a sequence of random inputs, but only + // many trials of the same input. + // + // Since this is a variable-time function, this means the + // benchmark is only useful as a ballpark measurement. + b.iter(|| k_fold_scalar_mult_vartime(&scalars, &points)); + } + #[bench] fn add_extended_and_projective_niels_output_completed(b: &mut Bencher) { let p1 = constants::ED25519_BASEPOINT; From d549fdc8f9582a807274168829c711e34962813d Mon Sep 17 00:00:00 2001 From: Isis Lovecruft Date: Fri, 17 Mar 2017 21:42:40 +0000 Subject: [PATCH 03/37] Whitespace fixes. --- src/curve.rs | 4 ++-- src/field.rs | 25 +++++++++++++------------ src/scalar.rs | 28 ++++++++++++++-------------- 3 files changed, 29 insertions(+), 28 deletions(-) diff --git a/src/curve.rs b/src/curve.rs index aefecac..b5ae0c8 100644 --- a/src/curve.rs +++ b/src/curve.rs @@ -1053,14 +1053,14 @@ impl ExtendedPoint { /// Returns `Some<[u8;32]>` if `self` is in the image of the /// Elligator2 map. For a random point on the curve, this happens /// with probability 1/2. Otherwise, returns `None`. - pub fn to_uniform_representative(&self) -> Option<[u8;32]> { + pub fn to_uniform_representative(&self) -> Option<[u8; 32]> { unimplemented!(); } /// Use Elligator2 to convert a uniformly random string to a curve /// point. #[allow(unused_variables)] // REMOVE WHEN IMPLEMENTED - pub fn from_uniform_representative(bytes: &[u8;32]) -> ExtendedPoint { + pub fn from_uniform_representative(bytes: &[u8; 32]) -> ExtendedPoint { unimplemented!(); } } diff --git a/src/field.rs b/src/field.rs index 78dcc9b..dafa3bc 100644 --- a/src/field.rs +++ b/src/field.rs @@ -454,8 +454,9 @@ impl FieldElement { FieldElement(limbs) } + #[cfg(not(feature="radix_51"))] - fn reduce(input: &[i64;10]) -> FieldElement { //FeCombine + fn reduce(input: &[i64; 10]) -> FieldElement { //FeCombine let mut c = [0i64;10]; let mut h = input.clone(); @@ -533,7 +534,7 @@ impl FieldElement { /* |h[0]| <= 2^25; from now on fits into int32 unchanged */ /* |h[1]| <= 1.01*2^24 */ - let mut output = FieldElement([0i32;10]); + let mut output = FieldElement([0i32; 10]); output[0] = h[0] as i32; output[1] = h[1] as i32; output[2] = h[2] as i32; @@ -585,7 +586,7 @@ impl FieldElement { } /// Parse a `FieldElement` from 32 bytes. #[cfg(feature="radix_51")] - pub fn from_bytes(bytes: &[u8;32]) -> FieldElement { + pub fn from_bytes(bytes: &[u8; 32]) -> FieldElement { let low_51_bit_mask = (1u64 << 51) - 1; FieldElement( // load bits [ 0, 64), no shift @@ -621,7 +622,7 @@ impl FieldElement { /// assert!(data == bytes); /// ``` #[cfg(not(feature="radix_51"))] - pub fn to_bytes(&self) -> [u8;32] { //FeToBytes + pub fn to_bytes(&self) -> [u8; 32] { //FeToBytes // Comment preserved from ed25519.go (presumably originally from ref10): // // # Preconditions @@ -752,7 +753,7 @@ impl FieldElement { } /// Serialize this `FieldElement` to bytes. #[cfg(feature="radix_51")] - pub fn to_bytes(&self) -> [u8;32] { + pub fn to_bytes(&self) -> [u8; 32] { // This reduces to the range [0,2^255), but we need [0,2^255-19) let mut limbs = FieldElement::reduce(self.0).0; // Let h = limbs[0] + limbs[1]*2^51 + ... + limbs[4]*2^204. @@ -925,7 +926,7 @@ impl FieldElement { } #[cfg(not(feature="radix_51"))] - fn square_inner(&self) -> [i64;10] { + fn square_inner(&self) -> [i64; 10] { let f0 = self[0] as i64; let f1 = self[1] as i64; let f2 = self[2] as i64; @@ -964,6 +965,7 @@ impl FieldElement { h } + #[cfg(feature="radix_51")] #[inline(always)] fn square_inner(&self) -> [u64; 5] { @@ -1170,8 +1172,7 @@ impl FieldElement { /// - `(0u8, zero)` if `v` is zero; /// - `(0u8, garbage)` if `u/v` is nonsquare. /// - pub fn sqrt_ratio(u: &FieldElement, v: &FieldElement) - -> (u8, FieldElement) { + pub fn sqrt_ratio(u: &FieldElement, v: &FieldElement) -> (u8, FieldElement) { // Using the same trick as in ed25519 decoding, we merge the // inversion, the square root, and the square test as follows. // @@ -1259,28 +1260,28 @@ mod test { /// Random element a of GF(2^255-19), from Sage /// a = 1070314506888354081329385823235218444233221\ /// 2228051251926706380353716438957572 - pub static A_BYTES: [u8;32] = + pub static A_BYTES: [u8; 32] = [ 0x04, 0xfe, 0xdf, 0x98, 0xa7, 0xfa, 0x0a, 0x68, 0x84, 0x92, 0xbd, 0x59, 0x08, 0x07, 0xa7, 0x03, 0x9e, 0xd1, 0xf6, 0xf2, 0xe1, 0xd9, 0xe2, 0xa4, 0xa4, 0x51, 0x47, 0x36, 0xf3, 0xc3, 0xa9, 0x17]; /// Byte representation of a**2 - static ASQ_BYTES: [u8;32] = + static ASQ_BYTES: [u8; 32] = [ 0x75, 0x97, 0x24, 0x9e, 0xe6, 0x06, 0xfe, 0xab, 0x24, 0x04, 0x56, 0x68, 0x07, 0x91, 0x2d, 0x5d, 0x0b, 0x0f, 0x3f, 0x1c, 0xb2, 0x6e, 0xf2, 0xe2, 0x63, 0x9c, 0x12, 0xba, 0x73, 0x0b, 0xe3, 0x62]; /// Byte representation of 1/a - static AINV_BYTES: [u8;32] = + static AINV_BYTES: [u8; 32] = [0x96, 0x1b, 0xcd, 0x8d, 0x4d, 0x5e, 0xa2, 0x3a, 0xe9, 0x36, 0x37, 0x93, 0xdb, 0x7b, 0x4d, 0x70, 0xb8, 0x0d, 0xc0, 0x55, 0xd0, 0x4c, 0x1d, 0x7b, 0x90, 0x71, 0xd8, 0xe9, 0xb6, 0x18, 0xe6, 0x30]; /// Byte representation of a^((p-5)/8) - static AP58_BYTES: [u8;32] = + static AP58_BYTES: [u8; 32] = [0x6a, 0x4f, 0x24, 0x89, 0x1f, 0x57, 0x60, 0x36, 0xd0, 0xbe, 0x12, 0x3c, 0x8f, 0xf5, 0xb1, 0x59, 0xe0, 0xf0, 0xb8, 0x1b, 0x20, 0xd2, 0xb5, 0x1f, diff --git a/src/scalar.rs b/src/scalar.rs index f7808e3..5411712 100644 --- a/src/scalar.rs +++ b/src/scalar.rs @@ -190,7 +190,7 @@ impl Scalar { /// ``` /// pub fn hash_from_bytes(input: &[u8]) -> Scalar - where D: Digest + Default { + where D: Digest + Default { let mut hash = D::default(); hash.input(input); // XXX this seems clumsy @@ -200,7 +200,7 @@ impl Scalar { } /// View this `Scalar` as a sequence of bytes. - pub fn as_bytes<'a>(&'a self) -> &'a [u8;32] { + pub fn as_bytes<'a>(&'a self) -> &'a [u8; 32] { &self.0 } @@ -226,7 +226,7 @@ impl Scalar { /// Intuitively, this is like a binary expansion, except that we /// allow some coefficients to grow up to `2^(w-1)` so that the /// nonzero coefficients are as sparse as possible. - pub fn non_adjacent_form(&self) -> [i8;256] { + pub fn non_adjacent_form(&self) -> [i8; 256] { // Step 1: write out bits of the scalar let mut naf = [0i8; 256]; for i in 0..256 { @@ -270,7 +270,7 @@ impl Scalar { // Unpack a scalar into 12 21-bit limbs. fn unpack(&self) -> UnpackedScalar { let mask_21bits: i64 = (1 << 21) -1; - let mut a = UnpackedScalar([0i64;12]); + let mut a = UnpackedScalar([0i64; 12]); a[ 0] = mask_21bits & load3(&self.0[ 0..]) ; a[ 1] = mask_21bits & (load4(&self.0[ 2..]) >> 5); a[ 2] = mask_21bits & (load3(&self.0[ 5..]) >> 2); @@ -296,7 +296,7 @@ impl Scalar { /// /// Precondition: self[31] <= 127. This is the case whenever /// `self` is reduced. - pub fn to_radix_16(&self) -> [i8;64] { + pub fn to_radix_16(&self) -> [i8; 64] { debug_assert!(self[31] <= 127); let mut output = [0i8; 64]; @@ -339,8 +339,8 @@ impl Scalar { } /// Reduce a 512-bit little endian number mod l - pub fn reduce(input: &[u8;64]) -> Scalar { - let mut s = [0i64;24]; + pub fn reduce(input: &[u8; 64]) -> Scalar { + let mut s = [0i64; 24]; // XXX express this as two unpack_limbs // some issues re: masking with the top byte of the 32byte input @@ -444,7 +444,7 @@ impl UnpackedScalar { pub fn multiply_add(a: &UnpackedScalar, b: &UnpackedScalar, c: &UnpackedScalar) -> UnpackedScalar { - let mut result = [0i64;24]; + let mut result = [0i64; 24]; // Multiply a and b, and add c result[0] = c[0] + a[0]*b[0]; @@ -506,10 +506,10 @@ impl UnpackedScalar { /// limbs. Reduction mod l amounts to eliminating all of the /// high limbs while carrying as appropriate to prevent /// overflows in the lower limbs. - fn reduce_limbs(mut limbs: &mut [i64;24]) -> UnpackedScalar { + fn reduce_limbs(mut limbs: &mut [i64; 24]) -> UnpackedScalar { #[inline] #[allow(dead_code)] - fn do_reduction(limbs: &mut [i64;24], i:usize) { + fn do_reduction(limbs: &mut [i64; 24], i:usize) { limbs[i - 12] += limbs[i] * 666643; limbs[i - 11] += limbs[i] * 470296; limbs[i - 10] += limbs[i] * 654183; @@ -531,7 +531,7 @@ impl UnpackedScalar { #[allow(dead_code)] /// Carry excess from the `i`-th limb into the `(i+1)`-th limb. /// Postcondition: `-2^20 <= limbs[i] < 2^20`. - fn do_carry_centered(limbs: &mut [i64;24], i:usize) { + fn do_carry_centered(limbs: &mut [i64; 24], i:usize) { let carry: i64 = (limbs[i] + (1<<20)) >> 21; limbs[i+1] += carry; limbs[i ] -= carry << 21; @@ -585,7 +585,7 @@ impl UnpackedScalar { } // XXX better way to get [i64;12] from [i64;24] ? - UnpackedScalar(*array_ref!(limbs,0,12)) + UnpackedScalar(*array_ref!(limbs, 0, 12)) } } @@ -632,7 +632,7 @@ mod test { 0xa7, 0x58, 0xaa, 0x1b, 0x88, 0xe0, 0x40, 0xd1, 0x58, 0x9e, 0x7b, 0x7f, 0x23, 0x76, 0xef, 0x09]); - static A_NAF: [i8;256] = + static A_NAF: [i8; 256] = [0,13,0,0,0,0,0,0,0,7,0,0,0,0,0,0,-9,0,0,0,0,-11,0,0,0,0,3,0,0,0,0,1, 0,0,0,0,9,0,0,0,0,-5,0,0,0,0,0,0,3,0,0,0,0,11,0,0,0,0,11,0,0,0,0,0, -9,0,0,0,0,0,-3,0,0,0,0,9,0,0,0,0,0,1,0,0,0,0,0,0,-1,0,0,0,0,0,9,0, @@ -679,7 +679,7 @@ mod test { #[test] fn scalar_reduce() { - let mut bignum = [0u8;64]; + let mut bignum = [0u8; 64]; // set bignum = x + 2^256x for i in 0..32 { bignum[ i] = X[i]; From 5ebbd5dd86772fb0d8869d3fce22ac782edeb39c Mon Sep 17 00:00:00 2001 From: Isis Lovecruft Date: Fri, 17 Mar 2017 21:42:58 +0000 Subject: [PATCH 04/37] Remove an XXX comment about using something better than array_ref!(). It turns out array_ref!() is probably the best way, or, at least, we're already using it everywhere. --- src/scalar.rs | 1 - 1 file changed, 1 deletion(-) diff --git a/src/scalar.rs b/src/scalar.rs index 5411712..91ed65e 100644 --- a/src/scalar.rs +++ b/src/scalar.rs @@ -584,7 +584,6 @@ impl UnpackedScalar { do_carry_uncentered(&mut limbs, i); } - // XXX better way to get [i64;12] from [i64;24] ? UnpackedScalar(*array_ref!(limbs, 0, 12)) } From eca28fd3e8b6198e3d994ca258f34068e57b8434 Mon Sep 17 00:00:00 2001 From: Henry de Valence Date: Tue, 28 Feb 2017 19:08:37 -0800 Subject: [PATCH 05/37] Refactor Scalar::hash_from_bytes to allow streaming input to the hash. --- src/scalar.rs | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/src/scalar.rs b/src/scalar.rs index f7808e3..62e6183 100644 --- a/src/scalar.rs +++ b/src/scalar.rs @@ -173,6 +173,8 @@ impl Scalar { /// Takes a type parameter `D`, which is any `Digest` producing 64 /// bytes (512 bits) of output. /// + /// Convenience wrapper around `from_hash`. + /// /// # Example /// /// ``` @@ -193,6 +195,16 @@ impl Scalar { where D: Digest + Default { let mut hash = D::default(); hash.input(input); + Scalar::from_hash(hash) + } + + /// Construct a scalar from an existing `Digest` instance. + /// + /// Use this instead of `hash_from_bytes` if it is more convenient + /// to stream data into the `Digest` than to pass a single byte + /// slice. + pub fn from_hash(hash: D) -> Scalar + where D: Digest + Default { // XXX this seems clumsy let mut output = [0u8;64]; output.copy_from_slice(hash.result().as_slice()); From 73e172484c0ac982265c1d210723feaa3999eed6 Mon Sep 17 00:00:00 2001 From: Henry de Valence Date: Sun, 2 Apr 2017 23:12:18 +0200 Subject: [PATCH 06/37] Add tick marks around code items in docs --- src/constants.rs | 10 +++++----- src/curve.rs | 14 +++++++------- src/field.rs | 26 ++++++++++++++------------ 3 files changed, 26 insertions(+), 24 deletions(-) diff --git a/src/constants.rs b/src/constants.rs index 9ff4d4d..c0e6cc2 100644 --- a/src/constants.rs +++ b/src/constants.rs @@ -70,7 +70,7 @@ pub const SQRT_M1: FieldElement = FieldElement([ pub const SQRT_M1: FieldElement = FieldElement([1718705420411056, 234908883556509, 2233514472574048, 2117202627021982, 765476049583133]); /// Precomputed value of the other square root of -1 (mod p), -/// i.e., MSQRT_M1 = -SQRT_M1. +/// i.e., `MSQRT_M1 = -SQRT_M1`. #[cfg(not(feature="radix_51"))] pub const MSQRT_M1: FieldElement = FieldElement([ 32595792, 7943725, -9377950, -3500415, -12389472, @@ -92,7 +92,7 @@ pub const A: FieldElement = FieldElement([ #[cfg(feature="radix_51")] pub const A: FieldElement = FieldElement([486662, 0, 0, 0, 0]); -/// SQRT_MINUS_A is sqrt(-486662) +/// `SQRT_MINUS_A` is sqrt(-486662) // XXX I think that this was used in Adam's code for his elligator // implementation, but that should maybe be using sqrt(-486664) // instead...? - hdevalence @@ -103,7 +103,7 @@ pub const SQRT_MINUS_A: FieldElement = FieldElement([ // sqrtMinusA #[cfg(feature="radix_51")] pub const SQRT_MINUS_A: FieldElement = FieldElement([557817479725543, 1643290402203250, 16226468853936, 1304118542701054, 1985241807451647]); -/// SQRT_MINUS_APLUS2 is sqrt(-486664) +/// `SQRT_MINUS_APLUS2` is sqrt(-486664) #[cfg(not(feature="radix_51"))] pub const SQRT_MINUS_APLUS2: FieldElement = FieldElement([ -12222970, -8312128, -11511410, 9067497, -15300785, @@ -111,7 +111,7 @@ pub const SQRT_MINUS_APLUS2: FieldElement = FieldElement([ #[cfg(feature="radix_51")] pub const SQRT_MINUS_APLUS2: FieldElement = FieldElement([1693982333959686, 608509411481997, 2235573344831311, 947681270984193, 266558006233600]); -/// SQRT_MINUS_HALF is sqrt(-1/2) +/// `SQRT_MINUS_HALF` is sqrt(-1/2) #[cfg(not(feature="radix_51"))] pub const SQRT_MINUS_HALF: FieldElement = FieldElement([ // sqrtMinusHalf -17256545, 3971863, 28865457, -1750208, 27359696, @@ -119,7 +119,7 @@ pub const SQRT_MINUS_HALF: FieldElement = FieldElement([ // sqrtMinusHalf #[cfg(feature="radix_51")] pub const SQRT_MINUS_HALF: FieldElement = FieldElement([266547196637087, 2134345371906993, 1135042577398223, 67298593331632, 743161882051057]); -/// HALF_Q_MINUS_1_BYTES is (2^255-20)/2 expressed in little endian form. +/// `HALF_Q_MINUS_1_BYTES` is (2^255-20)/2 expressed in little endian form. pub const HALF_Q_MINUS_1_BYTES: [u8; 32] = [ // halfQMinus1Bytes 0xf6, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, diff --git a/src/curve.rs b/src/curve.rs index aefecac..7638da1 100644 --- a/src/curve.rs +++ b/src/curve.rs @@ -59,15 +59,15 @@ //! implementation for [Ed25519](https://ed25519.cr.yp.to/ed25519-20110926.pdf), //! we use several different models for curve points: //! -//! * CompletedPoint: points in ๐—ฃ^1 x ๐—ฃ^1; -//! * ExtendedPoint: points in ๐—ฃ^3; -//! * ProjectivePoint: points in ๐—ฃ^2. +//! * `CompletedPoint`: points in ๐—ฃ^1 x ๐—ฃ^1; +//! * `ExtendedPoint`: points in ๐—ฃ^3; +//! * `ProjectivePoint`: points in ๐—ฃ^2. //! //! Finally, to accelerate additions, we use two cached point formats, //! one for the affine model and one for the ๐—ฃ^3 model: //! -//! * AffineNielsPoint: `(y+x, y-x, 2dxy)` -//! * ProjectiveNielsPoint: `(Y+X, Y-X, Z, 2dXY)` +//! * `AffineNielsPoint`: `(y+x, y-x, 2dxy)` +//! * `ProjectiveNielsPoint`: `(Y+X, Y-X, Z, 2dXY)` //! //! [1]: https://moderncrypto.org/mail-archive/curves/2016/000807.html @@ -103,7 +103,7 @@ use std::boxed::Box; /// determined by the `y`-coordinate and the sign of `x`, marshalled /// into a 32-byte array. /// -/// The first 255 bits of a CompressedEdwardsY represent the +/// 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, Eq, PartialEq)] pub struct CompressedEdwardsY(pub [u8; 32]); @@ -303,7 +303,7 @@ pub struct ProjectivePoint { Z: FieldElement, } -/// A CompletedPoint is a point ((X:Z), (Y:T)) in ๐—ฃยน(๐”ฝโ‚š)ร—๐—ฃยน(๐”ฝโ‚š). +/// A `CompletedPoint` is a point ((X:Z), (Y:T)) in ๐—ฃยน(๐”ฝโ‚š)ร—๐—ฃยน(๐”ฝโ‚š). /// A point (x,y) in the affine model corresponds to ((x:1),(y:1)). #[derive(Copy, Clone)] pub struct CompletedPoint { diff --git a/src/field.rs b/src/field.rs index 78dcc9b..8a6373c 100644 --- a/src/field.rs +++ b/src/field.rs @@ -41,25 +41,27 @@ use constants; #[cfg(feature="radix_51")] pub type Limb = u64; -/// FieldElement represents an element of the field GF(2^255 - 19). An element -/// t, entries t[0]...t[9], represents the integer t[0]+2^26 t[1]+2^51 t[2]+2^77 -/// t[3]+2^102 t[4]+...+2^230 t[9]. Bounds on each t[i] vary depending on -/// context. +/// A `FieldElement` represents an element of the field GF(2^255 - 19). +/// +/// With the `radix_51` feature, a `FieldElement` is represented in +/// radix 2^51 as five `u64`s; the coefficients are allowed to grow up +/// to 2^54 between reductions mod `p`. #[cfg(feature="radix_51")] #[derive(Copy, Clone)] pub struct FieldElement(pub [u64; 5]); -/// 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 -/// integer. +/// Without the `radix51` feature enabled, `FieldElements` are represented +/// in radix 2^25.5 as ten `i32`s. #[cfg(not(feature="radix_51"))] pub type Limb = i32; -/// FieldElement represents an element of the field GF(2^255 - 19). An element -/// t, entries t[0]...t[9], represents the integer t[0]+2^26 t[1]+2^51 t[2]+2^77 -/// t[3]+2^102 t[4]+...+2^230 t[9]. Bounds on each t[i] vary depending on -/// context. +/// A `FieldElement` represents an element of the field GF(2^255 - 19). +/// +/// With the `radix_51` feature, a `FieldElement` is represented in +/// radix 2^25.5 as ten `i32`s, so that an element t, entries +/// t[0],...,t[9], represents the integer t[0]+2^26 t[1]+2^51 +/// t[2]+2^77 t[3]+2^102 t[4]+...+2^230 t[9]. Bounds on each t[i] +/// vary depending on context. #[cfg(not(feature="radix_51"))] #[derive(Copy, Clone)] pub struct FieldElement(pub [i32; 10]); From e74bf8e78932f7eeabfecbe7a2b7fa8c8524d9e3 Mon Sep 17 00:00:00 2001 From: Henry de Valence Date: Sun, 2 Apr 2017 23:14:19 +0200 Subject: [PATCH 07/37] Remove unnecessary if statement --- src/curve.rs | 8 +------- 1 file changed, 1 insertion(+), 7 deletions(-) diff --git a/src/curve.rs b/src/curve.rs index 7638da1..b2206d3 100644 --- a/src/curve.rs +++ b/src/curve.rs @@ -947,13 +947,7 @@ impl ExtendedPoint { /// /// 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; - } + self.mult_by_cofactor().is_identity() } } From b3041f2adcb7497ffcc38a6098ba1fa3e22a5d55 Mon Sep 17 00:00:00 2001 From: Henry de Valence Date: Sun, 2 Apr 2017 23:17:20 +0200 Subject: [PATCH 08/37] Remove unnecessary if statements --- src/curve.rs | 8 +------- src/scalar.rs | 8 +------- 2 files changed, 2 insertions(+), 14 deletions(-) diff --git a/src/curve.rs b/src/curve.rs index b2206d3..ff82477 100644 --- a/src/curve.rs +++ b/src/curve.rs @@ -470,13 +470,7 @@ pub trait IsIdentity { /// 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; - } + self.ct_eq(&T::identity()) == 1u8 } } diff --git a/src/scalar.rs b/src/scalar.rs index f7808e3..5d6a5ec 100644 --- a/src/scalar.rs +++ b/src/scalar.rs @@ -72,13 +72,7 @@ impl PartialEq for Scalar { /// /// 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; - } + arrays_equal_ct(&self.0, &other.0) == 1u8 } } From c8e7e22ddfe92d31f21ec8d2ffeb28d793f422be Mon Sep 17 00:00:00 2001 From: Henry de Valence Date: Sun, 2 Apr 2017 23:28:01 +0200 Subject: [PATCH 09/37] Remove unnecessary returns --- src/field.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/field.rs b/src/field.rs index 8a6373c..2545d02 100644 --- a/src/field.rs +++ b/src/field.rs @@ -86,7 +86,7 @@ impl PartialEq for FieldElement { for i in 0..32 { are_equal &= self_bytes[i] == other_bytes[i]; } - return are_equal; + are_equal } } @@ -923,7 +923,7 @@ impl FieldElement { for b in &bytes { x |= *b; } - return byte_is_nonzero(x); + byte_is_nonzero(x) } #[cfg(not(feature="radix_51"))] From 7f4b96150deed0be4598d3e7ec660e55bee0786f Mon Sep 17 00:00:00 2001 From: Henry de Valence Date: Sun, 2 Apr 2017 23:36:05 +0200 Subject: [PATCH 10/37] Remove explicit lifetimes --- src/curve.rs | 2 +- src/field.rs | 10 ++++------ src/scalar.rs | 22 +++++++++------------- 3 files changed, 14 insertions(+), 20 deletions(-) diff --git a/src/curve.rs b/src/curve.rs index ff82477..872d4d3 100644 --- a/src/curve.rs +++ b/src/curve.rs @@ -116,7 +116,7 @@ impl Debug for CompressedEdwardsY { impl CompressedEdwardsY { /// View this `CompressedEdwardsY` as an array of bytes. - pub fn as_bytes<'a>(&'a self) -> &'a [u8; 32] { + pub fn as_bytes(&self) -> &[u8; 32] { &self.0 } diff --git a/src/field.rs b/src/field.rs index 2545d02..1495d17 100644 --- a/src/field.rs +++ b/src/field.rs @@ -110,16 +110,14 @@ impl Debug for FieldElement { impl Index for FieldElement { type Output = Limb; - fn index<'a>(&'a self, _index: usize) -> &'a Limb { - let ret: &'a Limb = &(self.0[_index]); - ret + fn index(&self, _index: usize) -> &Limb { + &(self.0[_index]) } } impl IndexMut for FieldElement { - fn index_mut<'a>(&'a mut self, _index: usize) -> &'a mut Limb { - let ret: &'a mut Limb = &mut(self.0[_index]); - ret + fn index_mut(&mut self, _index: usize) -> &mut Limb { + &mut(self.0[_index]) } } diff --git a/src/scalar.rs b/src/scalar.rs index 5d6a5ec..8606913 100644 --- a/src/scalar.rs +++ b/src/scalar.rs @@ -90,16 +90,14 @@ impl CTEq for Scalar { impl Index for Scalar { type Output = u8; - fn index<'a>(&'a self, _index: usize) -> &'a u8 { - let ret: &'a u8 = &(self.0[_index]); - ret + fn index(&self, _index: usize) -> &u8 { + &(self.0[_index]) } } impl IndexMut for Scalar { - fn index_mut<'a>(&'a mut self, _index: usize) -> &'a mut u8 { - let ret: &'a mut u8 = &mut(self.0[_index]); - ret + fn index_mut(&mut self, _index: usize) -> &mut u8 { + &mut(self.0[_index]) } } @@ -194,7 +192,7 @@ impl Scalar { } /// View this `Scalar` as a sequence of bytes. - pub fn as_bytes<'a>(&'a self) -> &'a [u8;32] { + pub fn as_bytes(&self) -> &[u8;32] { &self.0 } @@ -381,16 +379,14 @@ pub struct UnpackedScalar(pub [i64; 12]); impl Index for UnpackedScalar { type Output = i64; - fn index<'a>(&'a self, _index: usize) -> &'a i64 { - let ret: &'a i64 = &(self.0[_index]); - ret + fn index(&self, _index: usize) -> &i64 { + &(self.0[_index]) } } impl IndexMut for UnpackedScalar { - fn index_mut<'a>(&'a mut self, _index: usize) -> &'a mut i64 { - let ret: &'a mut i64 = &mut(self.0[_index]); - ret + fn index_mut(&mut self, _index: usize) -> &mut i64 { + &mut(self.0[_index]) } } From 3705346afa90be6daa47ffee707f1480f69b0889 Mon Sep 17 00:00:00 2001 From: Henry de Valence Date: Sun, 2 Apr 2017 23:39:45 +0200 Subject: [PATCH 11/37] Remove unnecessary returns --- src/curve.rs | 3 +-- src/field.rs | 2 +- 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/src/curve.rs b/src/curve.rs index 872d4d3..0cf6890 100644 --- a/src/curve.rs +++ b/src/curve.rs @@ -927,8 +927,7 @@ impl ExtendedPoint { r = s.double(); s = r.to_projective(); } // Unroll last iteration so we can go directly to_extended() - r = s.double(); - return r.to_extended(); + s.double().to_extended() } /// Determine if this point is of small order. diff --git a/src/field.rs b/src/field.rs index 1495d17..4c2d333 100644 --- a/src/field.rs +++ b/src/field.rs @@ -907,7 +907,7 @@ impl FieldElement { /// /// If zero, return `1u8`. Otherwise, return `0u8`. pub fn is_zero(&self) -> u8 { - return 1u8 & (!self.is_nonzero()); + 1u8 & (!self.is_nonzero()) } /// Determine if this `FieldElement` is non-zero. From 162dfc83312042d09dc794292d24e38f22b7ee0b Mon Sep 17 00:00:00 2001 From: Henry de Valence Date: Sun, 2 Apr 2017 23:45:34 +0200 Subject: [PATCH 12/37] Remove clones on Copy types --- src/field.rs | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/field.rs b/src/field.rs index 4c2d333..bb0333c 100644 --- a/src/field.rs +++ b/src/field.rs @@ -132,7 +132,7 @@ impl<'b> AddAssign<&'b FieldElement> for FieldElement { impl<'a, 'b> Add<&'b FieldElement> for &'a FieldElement { type Output = FieldElement; fn add(self, _rhs: &'b FieldElement) -> FieldElement { - let mut output = self.clone(); + let mut output = *self; output += _rhs; output } @@ -158,7 +158,7 @@ impl<'a, 'b> Sub<&'b FieldElement> for &'a FieldElement { type Output = FieldElement; #[cfg(not(feature="radix_51"))] fn sub(self, _rhs: &'b FieldElement) -> FieldElement { - let mut output = self.clone(); + let mut output = *self; output -= _rhs; output } @@ -326,7 +326,7 @@ impl<'a, 'b> Mul<&'b FieldElement> for &'a FieldElement { impl<'a> Neg for &'a FieldElement { type Output = FieldElement; fn neg(self) -> FieldElement { - let mut output = self.clone(); + let mut output = *self; output.negate(); output } @@ -656,7 +656,7 @@ impl FieldElement { // so floor(2^-255 * (h + 19 * 2^-25 * h9 + 2^-1)) = q. // let mut carry = [0i32; 10]; - let mut h = self.clone(); + let mut h: [i32; 10] = self.0; let mut q:i32 = (19*h[9] + (1 << 24)) >> 25; q = (h[0] + q) >> 26; @@ -1352,7 +1352,7 @@ mod test { #[test] fn from_bytes_highbit_is_ignored() { - let mut cleared_bytes = B_BYTES.clone(); + let mut cleared_bytes = B_BYTES; cleared_bytes[31] &= 127u8; let with_highbit_set = FieldElement::from_bytes(&B_BYTES); let without_highbit_set = FieldElement::from_bytes(&cleared_bytes); From e00cd114d716e0be60dfa2c52e294e8d93456060 Mon Sep 17 00:00:00 2001 From: Henry de Valence Date: Sun, 2 Apr 2017 23:46:01 +0200 Subject: [PATCH 13/37] Have radix 25.5 reduce() consume its argument --- src/field.rs | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) diff --git a/src/field.rs b/src/field.rs index bb0333c..b4dd2d4 100644 --- a/src/field.rs +++ b/src/field.rs @@ -319,7 +319,7 @@ impl<'a, 'b> Mul<&'b FieldElement> for &'a FieldElement { let h8 = f0*g8 + f1_2*g7 + f2*g6 + f3_2*g5 + f4*g4 + f5_2*g3 + f6*g2 + f7_2*g1 + f8*g0 + f9_2*g9_19; let h9 = f0*g9 + f1*g8 + f2*g7 + f3*g6 + f4*g5 + f5*g4 + f6*g3 + f7*g2 + f8*g1 + f9*g0; - FieldElement::reduce(&[h0, h1, h2, h3, h4, h5, h6, h7, h8, h9]) + FieldElement::reduce([h0, h1, h2, h3, h4, h5, h6, h7, h8, h9]) } } @@ -455,9 +455,8 @@ impl FieldElement { FieldElement(limbs) } #[cfg(not(feature="radix_51"))] - fn reduce(input: &[i64;10]) -> FieldElement { //FeCombine + fn reduce(mut h: [i64; 10]) -> FieldElement { //FeCombine let mut c = [0i64;10]; - let mut h = input.clone(); /* |h[0]| <= (1.1*1.1*2^52*(1+19+19+19+19)+1.1*1.1*2^50*(38+38+38+38+38)) @@ -581,7 +580,7 @@ impl FieldElement { h[8] = load3(&data[26..]) << 4; h[9] = (load3(&data[29..]) & 8388607) << 2; - FieldElement::reduce(&h) + FieldElement::reduce(h) } /// Parse a `FieldElement` from 32 bytes. #[cfg(feature="radix_51")] @@ -1028,12 +1027,12 @@ impl FieldElement { /// * |h[i]| bounded by 1.1*2^25, 1.1*2^24, 1.1*2^25, 1.1*2^24, etc. #[cfg(not(feature="radix_51"))] pub fn square(&self) -> FieldElement { - FieldElement::reduce(&self.square_inner()) + FieldElement::reduce(self.square_inner()) } /// Compute `self^2`. #[cfg(feature="radix_51")] pub fn square(&self) -> FieldElement { - FieldElement::reduce( self.square_inner()) + FieldElement::reduce(self.square_inner()) } /// Square this field element and multiply the result by 2. @@ -1058,7 +1057,7 @@ impl FieldElement { for i in 0..self.0.len() { coeffs[i] += coeffs[i]; } - FieldElement::reduce(&coeffs) + FieldElement::reduce(coeffs) } /// Compute `2 * self^2`. #[cfg(feature="radix_51")] From 57c96616b9469941d9f6075c93762e9dcecf576f Mon Sep 17 00:00:00 2001 From: Henry de Valence Date: Tue, 25 Apr 2017 14:50:59 -0700 Subject: [PATCH 14/37] Remove unused import --- src/field.rs | 1 - 1 file changed, 1 deletion(-) diff --git a/src/field.rs b/src/field.rs index b4dd2d4..6b5a167 100644 --- a/src/field.rs +++ b/src/field.rs @@ -15,7 +15,6 @@ //! Based on Adam Langley's curve25519-donna and (Golang) ed25519 //! implementations. -use core::clone::Clone; use core::fmt::Debug; use core::ops::{Add, AddAssign}; use core::ops::{Sub, SubAssign}; From cb656bafa7fd0c826b556b6a350f5dd0eb1464a6 Mon Sep 17 00:00:00 2001 From: Henry de Valence Date: Tue, 25 Apr 2017 15:08:56 -0700 Subject: [PATCH 15/37] Delete bytes_equal_less_than This function is unused and untested. It's also incorrect, since the loop 32..0 iterates over an empty range. Remove it for now; if we need it later, it still lives in the history. --- src/field.rs | 26 -------------------------- 1 file changed, 26 deletions(-) diff --git a/src/field.rs b/src/field.rs index 6b5a167..7e4a99c 100644 --- a/src/field.rs +++ b/src/field.rs @@ -828,32 +828,6 @@ impl FieldElement { return s } - /// XXX clarify documentation - /// Determine if this field element, represented as a byte array, - /// is less than or equal to another field element represented as - /// a byte array. - /// - /// # Returns - /// - /// Returns `1u8` if `self.to_bytes() <= other.to_bytes()`, and `0u8` otherwise. - pub fn bytes_equal_less_than(&self, other: &[u8; 32]) -> u8 { // feBytesLess - // XXX cleanup - let mut equal_so_far: i32 = -1i32; - let mut greater: i32 = 0i32; - - let this: [u8; 32] = self.to_bytes(); - - for i in 32 .. 0 { - let x: i32 = this[i-1] as i32; - let y: i32 = other[i-1] as i32; - - greater = (!equal_so_far & greater) | (equal_so_far & ((x - y) >> 31)); - equal_so_far = equal_so_far & (((x ^ y) - 1) >> 31); - } - - (!equal_so_far & 1 & greater) as u8 - } - /// Determine if this `FieldElement` is negative, in the sense /// used in the ed25519 paper: `x` is negative if the low bit is /// set. From 60ad000609782fbfc1d65462add18e7d13c43358 Mon Sep 17 00:00:00 2001 From: Henry de Valence Date: Tue, 25 Apr 2017 15:56:36 -0700 Subject: [PATCH 16/37] Remove redundant & --- src/curve.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/curve.rs b/src/curve.rs index 0cf6890..1a1e4d8 100644 --- a/src/curve.rs +++ b/src/curve.rs @@ -232,7 +232,7 @@ impl CompressedMontgomeryU { /// Montgomery `v` corresponding to this `u`. pub fn to_montgomery_v(u: &FieldElement) -> (u8, FieldElement) { let one: FieldElement = FieldElement::one(); - let v_squared: FieldElement = u * &(&(&u.square() + &(&(&constants::A * u) + &one))); + let v_squared: FieldElement = u * &(&u.square() + &(&(&constants::A * u) + &one)); let (okay, v_inv) = v_squared.invsqrt(); let v = &v_inv * &v_squared; From 057c84abd53cb79d75a0a63fbe08d642f04ad4b8 Mon Sep 17 00:00:00 2001 From: Henry de Valence Date: Fri, 28 Apr 2017 22:51:32 -0700 Subject: [PATCH 17/37] Add a bits() function for scalars --- src/scalar.rs | 18 ++++++++++++------ 1 file changed, 12 insertions(+), 6 deletions(-) diff --git a/src/scalar.rs b/src/scalar.rs index 8606913..d97efc1 100644 --- a/src/scalar.rs +++ b/src/scalar.rs @@ -207,6 +207,17 @@ impl Scalar { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 ]) } + /// Get the bits of the scalar. + pub fn bits(&self) -> [i8;256] { + let mut bits = [0i8; 256]; + for i in 0..256 { + // As i runs from 0..256, the bottom 3 bits index the bit, + // while the upper bits index the byte. + bits[i] = ((self.0[i>>3] >> (i&7)) & 1u8) as i8; + } + bits + } + /// Compute a width-5 "Non-Adjacent Form" of this scalar. /// /// A width-`w` NAF of a positive integer `k` is an expression @@ -220,12 +231,7 @@ impl Scalar { /// nonzero coefficients are as sparse as possible. pub fn non_adjacent_form(&self) -> [i8;256] { // Step 1: write out bits of the scalar - let mut naf = [0i8; 256]; - for i in 0..256 { - // As i runs from 0..256, the bottom 3 bits index the bit, - // while the upper bits index the byte. - naf[i] = ((self.0[i>>3] >> (i&7)) & 1u8) as i8; - } + let mut naf = self.bits(); // Step 2: zero coefficients by carrying them upwards or downwards 'bits: for i in 0..256 { From b5ccb4275927386147468540794ee4b1ccff30f0 Mon Sep 17 00:00:00 2001 From: Henry de Valence Date: Fri, 28 Apr 2017 22:54:00 -0700 Subject: [PATCH 18/37] Rename lminus1 to l_minus_1 --- src/constants.rs | 11 ++++++----- src/scalar.rs | 3 ++- 2 files changed, 8 insertions(+), 6 deletions(-) diff --git a/src/constants.rs b/src/constants.rs index c0e6cc2..1821f9a 100644 --- a/src/constants.rs +++ b/src/constants.rs @@ -159,12 +159,13 @@ pub const l: Scalar = Scalar([ 0xed, 0xd3, 0xf5, 0x5c, 0x1a, 0x63, 0x12, 0x58, 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 + +/// `l_minus_1` 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 l_minus_1: 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 ]); + /// The 8-torsion subgroup ฦ[8]. /// /// In the case of Curve25519, it is cyclic; the `i`th element of the diff --git a/src/scalar.rs b/src/scalar.rs index d97efc1..c64b59b 100644 --- a/src/scalar.rs +++ b/src/scalar.rs @@ -106,7 +106,8 @@ impl Neg for Scalar { /// Negate this scalar by computing (l - 1) * self - 0 (mod l). fn neg(self) -> Scalar { - Scalar::multiply_add(&constants::lminus1, &self, &Scalar::zero()) + // XXX this could be more efficient + Scalar::multiply_add(&constants::l_minus_1, &self, &Scalar::zero()) } } From 653f134bc798ad25c4da725404c931eff10ce953 Mon Sep 17 00:00:00 2001 From: Henry de Valence Date: Fri, 28 Apr 2017 22:57:17 -0700 Subject: [PATCH 19/37] Implement Mul, MulAssign, zero(), one() for UnpackedScalar --- src/scalar.rs | 33 +++++++++++++++++++++++++++++++++ 1 file changed, 33 insertions(+) diff --git a/src/scalar.rs b/src/scalar.rs index c64b59b..6468ddd 100644 --- a/src/scalar.rs +++ b/src/scalar.rs @@ -31,6 +31,7 @@ use core::cmp::{Eq, PartialEq}; use core::ops::{Neg, Index, IndexMut}; +use core::ops::{Mul, MulAssign}; use core::fmt::Debug; #[cfg(feature = "std")] @@ -397,6 +398,20 @@ impl IndexMut for UnpackedScalar { } } +impl<'b> MulAssign<&'b UnpackedScalar> for UnpackedScalar { + fn mul_assign(&mut self, _rhs: &'b UnpackedScalar) { + let result = (self as &UnpackedScalar) * _rhs; + self.0 = result.0; + } +} + +impl<'a, 'b> Mul<&'b UnpackedScalar> for &'a UnpackedScalar { + type Output = UnpackedScalar; + fn mul(self, _rhs: &'b UnpackedScalar) -> UnpackedScalar { + UnpackedScalar::multiply_add(self,_rhs, &UnpackedScalar::zero()) + } +} + impl UnpackedScalar { /// Pack the limbs of this `UnpackedScalar` into a `Scalar`. fn pack(&self) -> Scalar { @@ -437,6 +452,16 @@ impl UnpackedScalar { s } + /// Return the zero scalar. + pub fn zero() -> UnpackedScalar { + UnpackedScalar([0,0,0,0,0,0,0,0,0,0,0,0]) + } + + /// Return the one scalar. + pub fn one() -> UnpackedScalar { + UnpackedScalar([1,0,0,0,0,0,0,0,0,0,0,0]) + } + /// Compute `ab+c (mod l)`. pub fn multiply_add(a: &UnpackedScalar, b: &UnpackedScalar, @@ -657,6 +682,14 @@ mod test { } } + #[test] + fn unpacked_mul() { + let x = X.unpack(); + let y = Y.unpack(); + let z = &x * &y; + assert_eq!(z.pack(), X_TIMES_Y); + } + #[test] fn scalar_multiply_only() { let zero = Scalar::zero(); From 6ea1d4dad2bb295513baf6f6c9c23bb9b3e5181f Mon Sep 17 00:00:00 2001 From: Henry de Valence Date: Fri, 28 Apr 2017 22:59:56 -0700 Subject: [PATCH 20/37] Add an implementation of Scalar inversion --- src/constants.rs | 7 +++++++ src/scalar.rs | 32 ++++++++++++++++++++++++++++++++ 2 files changed, 39 insertions(+) diff --git a/src/constants.rs b/src/constants.rs index 1821f9a..50879da 100644 --- a/src/constants.rs +++ b/src/constants.rs @@ -166,6 +166,13 @@ pub const l_minus_1: Scalar = Scalar([ 0xec, 0xd3, 0xf5, 0x5c, 0x1a, 0x63, 0x12, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10 ]); +/// `lminus1` is the order of base point minus two, i.e. 2^252 + +/// 27742317777372353535851937790883648493 - 2, in little-endian form +pub const l_minus_2: Scalar = Scalar([ 0xeb, 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 ]); + /// The 8-torsion subgroup ฦ[8]. /// /// In the case of Curve25519, it is cyclic; the `i`th element of the diff --git a/src/scalar.rs b/src/scalar.rs index 6468ddd..d711173 100644 --- a/src/scalar.rs +++ b/src/scalar.rs @@ -209,6 +209,11 @@ impl Scalar { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 ]) } + /// Compute the multiplicative inverse of this scalar. + pub fn invert(&self) -> Scalar { + self.unpack().invert().pack() + } + /// Get the bits of the scalar. pub fn bits(&self) -> [i8;256] { let mut bits = [0i8; 256]; @@ -462,6 +467,19 @@ impl UnpackedScalar { UnpackedScalar([1,0,0,0,0,0,0,0,0,0,0,0]) } + /// Compute the multiplicative inverse of this scalar. + pub fn invert(&self) -> UnpackedScalar { + let mut y = UnpackedScalar::one(); + // Run through bits of l-2 from highest to least + for bit in constants::l_minus_2.bits().iter().rev() { + y = &y * &y; + if *bit == 1 { + y *= self; + } + } + y + } + /// Compute `ab+c (mod l)`. pub fn multiply_add(a: &UnpackedScalar, b: &UnpackedScalar, @@ -727,6 +745,14 @@ mod test { } } + #[test] + fn invert() { + let x = UnpackedScalar([2,0,0,0,0,0,0,0,0,0,0,0]); + let x_inv = x.invert(); + let should_be_one = &x * &x_inv; + assert_eq!(should_be_one.pack(), Scalar::one()); + } + // Negating a scalar twice should result in the original scalar. #[test] fn scalar_neg() { @@ -757,6 +783,12 @@ mod bench { b.iter(|| Scalar::multiply_add(&X, &Y, &Z) ); } + #[bench] + fn invert(b: &mut Bencher) { + let x = X.unpack(); + b.iter(|| x.invert()); + } + #[bench] fn scalar_unpacked_multiply_add(b: &mut Bencher) { let x = X.unpack(); From 91e11b6318a9144b945140d63a8a00266889265a Mon Sep 17 00:00:00 2001 From: Henry de Valence Date: Tue, 2 May 2017 21:22:04 -0700 Subject: [PATCH 21/37] Change docstring to match the trait bound --- src/scalar.rs | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/src/scalar.rs b/src/scalar.rs index d711173..2ec4959 100644 --- a/src/scalar.rs +++ b/src/scalar.rs @@ -144,21 +144,19 @@ impl CTAssignable for Scalar { } impl Scalar { - /// Return a `Scalar` chosen uniformly at random using a CSPRNG. - /// Panics if the operating system's CSPRNG is unavailable. + /// Return a `Scalar` chosen uniformly at random using a user-provided RNG. /// /// # Inputs /// - /// * `cspring`: any cryptographically secure PRNG which - /// implements the `rand::Rng` interface. + /// * `rng`: any RNG which implements the `rand::Rng` interface. /// /// # Returns /// /// A random scalar within โ„ค/lโ„ค. #[cfg(feature = "std")] - pub fn random(csprng: &mut T) -> Self { + pub fn random(rng: &mut T) -> Self { let mut scalar_bytes = [0u8; 64]; - csprng.fill_bytes(&mut scalar_bytes); + rng.fill_bytes(&mut scalar_bytes); Scalar::reduce(&scalar_bytes) } From b05c8971233fb4c60622820e4b26b41a225b80a4 Mon Sep 17 00:00:00 2001 From: Henry de Valence Date: Tue, 2 May 2017 22:29:18 -0700 Subject: [PATCH 22/37] Implement operators for Scalars using multiply_add --- src/scalar.rs | 121 +++++++++++++++++++++++++++++++------------------- 1 file changed, 76 insertions(+), 45 deletions(-) diff --git a/src/scalar.rs b/src/scalar.rs index 2ec4959..03100f6 100644 --- a/src/scalar.rs +++ b/src/scalar.rs @@ -29,10 +29,13 @@ //! between two scalars, the `UnpackedScalar` struct is stored as //! limbs. -use core::cmp::{Eq, PartialEq}; -use core::ops::{Neg, Index, IndexMut}; -use core::ops::{Mul, MulAssign}; use core::fmt::Debug; +use core::ops::Neg; +use core::ops::{Add, AddAssign}; +use core::ops::{Sub, SubAssign}; +use core::ops::{Mul, MulAssign}; +use core::ops::{Index, IndexMut}; +use core::cmp::{Eq, PartialEq}; #[cfg(feature = "std")] use rand::Rng; @@ -102,16 +105,55 @@ 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 { - // XXX this could be more efficient - Scalar::multiply_add(&constants::l_minus_1, &self, &Scalar::zero()) +impl<'b> MulAssign<&'b Scalar> for Scalar { + fn mul_assign(&mut self, _rhs: &'b Scalar) { + let result = (self as &Scalar) * _rhs; + self.0 = result.0; } } +impl<'a, 'b> Mul<&'b Scalar> for &'a Scalar { + type Output = Scalar; + fn mul(self, _rhs: &'b Scalar) -> Scalar { + Scalar::multiply_add(self, _rhs, &Scalar::zero()) + } +} + +impl<'b> AddAssign<&'b Scalar> for Scalar { + fn add_assign(&mut self, _rhs: &'b Scalar) { + *self = Scalar::multiply_add(&Scalar::one(), self, _rhs); + } +} + +impl<'a, 'b> Add<&'b Scalar> for &'a Scalar { + type Output = Scalar; + fn add(self, _rhs: &'b Scalar) -> Scalar { + Scalar::multiply_add(&Scalar::one(), self, _rhs) + } +} + +impl<'b> SubAssign<&'b Scalar> for Scalar { + fn sub_assign(&mut self, _rhs: &'b Scalar) { + // (l-1)*_rhs + self = self - _rhs + *self = Scalar::multiply_add(&constants::l_minus_1, _rhs, self); + } +} + +impl<'a, 'b> Sub<&'b Scalar> for &'a Scalar { + type Output = Scalar; + fn sub(self, _rhs: &'b Scalar) -> Scalar { + // (l-1)*_rhs + self = self - _rhs + Scalar::multiply_add(&constants::l_minus_1, _rhs, self) + } +} + +impl<'a> Neg for &'a Scalar { + type Output = Scalar; + fn neg(self) -> Scalar { + self * &constants::l_minus_1 + } +} + impl CTAssignable for Scalar { /// Conditionally assign another Scalar to this one. /// @@ -401,20 +443,6 @@ impl IndexMut for UnpackedScalar { } } -impl<'b> MulAssign<&'b UnpackedScalar> for UnpackedScalar { - fn mul_assign(&mut self, _rhs: &'b UnpackedScalar) { - let result = (self as &UnpackedScalar) * _rhs; - self.0 = result.0; - } -} - -impl<'a, 'b> Mul<&'b UnpackedScalar> for &'a UnpackedScalar { - type Output = UnpackedScalar; - fn mul(self, _rhs: &'b UnpackedScalar) -> UnpackedScalar { - UnpackedScalar::multiply_add(self,_rhs, &UnpackedScalar::zero()) - } -} - impl UnpackedScalar { /// Pack the limbs of this `UnpackedScalar` into a `Scalar`. fn pack(&self) -> Scalar { @@ -470,9 +498,9 @@ impl UnpackedScalar { let mut y = UnpackedScalar::one(); // Run through bits of l-2 from highest to least for bit in constants::l_minus_2.bits().iter().rev() { - y = &y * &y; + y = UnpackedScalar::multiply_add(&y, &y, &UnpackedScalar::zero()); if *bit == 1 { - y *= self; + y = UnpackedScalar::multiply_add(&y, self, &UnpackedScalar::zero()); } } y @@ -699,20 +727,24 @@ mod test { } #[test] - fn unpacked_mul() { - let x = X.unpack(); - let y = Y.unpack(); - let z = &x * &y; - assert_eq!(z.pack(), X_TIMES_Y); + fn impl_add() { + let mut two = Scalar::zero(); two[0] = 2; + let two = two; + let one = Scalar::one(); + let should_be_two = &one + &one; + assert_eq!(should_be_two, two); } #[test] - fn scalar_multiply_only() { - let zero = Scalar::zero(); - let test_scalar = Scalar::multiply_add(&X, &Y, &zero); - for i in 0..32 { - assert!(test_scalar[i] == X_TIMES_Y[i]); - } + fn impl_sub() { + let should_be_one = &constants::l - &constants::l_minus_1; + assert_eq!(should_be_one, Scalar::one()); + } + + #[test] + fn impl_mul() { + let should_be_X_TIMES_Y = &X * &Y; + assert_eq!(should_be_X_TIMES_Y, X_TIMES_Y); } #[test] @@ -745,19 +777,18 @@ mod test { #[test] fn invert() { - let x = UnpackedScalar([2,0,0,0,0,0,0,0,0,0,0,0]); - let x_inv = x.invert(); - let should_be_one = &x * &x_inv; - assert_eq!(should_be_one.pack(), Scalar::one()); + let inv_X = X.invert(); + let should_be_one = &inv_X * &X; + assert_eq!(should_be_one, Scalar::one()); } // Negating a scalar twice should result in the original scalar. #[test] - fn scalar_neg() { - let negative_x: Scalar = -X; - let orig: Scalar = -negative_x; + fn neg_twice_is_identity() { + let negative_X = -&X; + let should_be_X = -&negative_X; - assert!(orig == X); + assert_eq!(should_be_X, X); } } From 5100ba4a07a17aeee0a9520c6a9dc17db41346de Mon Sep 17 00:00:00 2001 From: Henry de Valence Date: Wed, 3 May 2017 17:26:06 -0700 Subject: [PATCH 23/37] Move variable time code into a module --- src/curve.rs | 325 ++++++++++++++++++++++++++------------------------- 1 file changed, 168 insertions(+), 157 deletions(-) diff --git a/src/curve.rs b/src/curve.rs index 732fdf1..26a9ede 100644 --- a/src/curve.rs +++ b/src/curve.rs @@ -944,122 +944,6 @@ impl ExtendedPoint { } } -/// Holds odd multiples 1A, 3A, ..., 15A of a point A. -struct OddMultiples([ProjectiveNielsPoint; 8]); - -impl OddMultiples { - fn create(A: &ExtendedPoint) -> OddMultiples { - let mut Ai = [ProjectiveNielsPoint::identity(); 8]; - let A2 = A.double(); - Ai[0] = A.to_projective_niels(); - for i in 0..7 { - Ai[i+1] = (&A2 + &Ai[i]).to_extended().to_projective_niels(); - } - // Now Ai = [A, 3A, 5A, 7A, 9A, 11A, 13A, 15A] - OddMultiples(Ai) - } -} - -impl Index for OddMultiples { - type Output = ProjectiveNielsPoint; - - fn index<'a>(&'a self, _index: usize) -> &'a ProjectiveNielsPoint { - &(self.0[_index]) - } -} - - -/// Given a vector of public scalars and a vector of (possibly secret) -/// points, compute -/// -/// c_1 P_1 + ... + c_n P_n. -/// -/// # Warning -/// -/// This function is *not* constant time: its timing depends on the -/// input scalars. -/// -/// # Input -/// -/// A vector of `Scalar`s and a vector of `ExtendedPoints`. It is an -/// error to call this function with two vectors of different lengths. -pub fn k_fold_scalar_mult_vartime(scalars: &Vec, - points: &Vec) - -> ExtendedPoint { - assert_eq!(scalars.len(), points.len()); - - let nafs: Vec<_> = scalars.iter().map(|c| c.non_adjacent_form()).collect(); - let odd_multiples: Vec<_> = points.iter().map(|P| OddMultiples::create(&P)).collect(); - - let mut r = ProjectivePoint::identity(); - - for i in (0..255).rev() { - let mut t = r.double(); - - for (naf, odd_multiple) in nafs.iter().zip(odd_multiples.iter()) { - if naf[i] > 0 { - t = &t.to_extended() + &odd_multiple[( naf[i]/2) as usize]; - } else if naf[i] < 0 { - t = &t.to_extended() - &odd_multiple[(-naf[i]/2) as usize]; - } - } - - r = t.to_projective(); - } - - r.to_extended() -} - -/// Given a point `A` and scalars `a` and `b`, compute the point -/// `aA+bB`, where `B` is the Ed25519 basepoint (i.e., `B = (x,4/5)` -/// with x positive). -/// -/// # Warning -/// -/// This function is *not* constant time, hence its name. -// XXX should return ExtendedPoint? -pub fn double_scalar_mult_vartime(a: &Scalar, A: &ExtendedPoint, b: &Scalar) -> ProjectivePoint { - let a_naf = a.non_adjacent_form(); - let b_naf = b.non_adjacent_form(); - - // Find starting index - let mut i: usize = 255; - for j in (0..255).rev() { - i = j; - if a_naf[i] != 0 || b_naf[i] != 0 { - break; - } - } - - let odd_multiples_of_A = OddMultiples::create(A); - - let mut r = ProjectivePoint::identity(); - loop { - let mut t = r.double(); - - if a_naf[i] > 0 { - t = &t.to_extended() + &odd_multiples_of_A[( a_naf[i]/2) as usize]; - } else if a_naf[i] < 0 { - t = &t.to_extended() - &odd_multiples_of_A[(-a_naf[i]/2) as usize]; - } - - if b_naf[i] > 0 { - t = &t.to_extended() + &constants::bi[( b_naf[i]/2) as usize]; - } else if b_naf[i] < 0 { - t = &t.to_extended() - &constants::bi[(-b_naf[i]/2) as usize]; - } - - r = t.to_projective(); - - if i == 0 { - break; - } - i -= 1; - } - - r -} - /// Given precomputed points `[P, 2P, 3P, ..., 8P]`, as well as `-8 โ‰ค /// x โ‰ค 8`, compute `x * B` in constant time, i.e., without branching /// on x or using it as an array index. @@ -1150,6 +1034,122 @@ impl Debug for ProjectiveNielsPoint { } } +// ------------------------------------------------------------------------ +// Variable-time functions +// ------------------------------------------------------------------------ + +pub mod vartime { + //! Variable-time operations on curve points, useful for non-secret data. + use super::*; + + /// Holds odd multiples 1A, 3A, ..., 15A of a point A. + struct OddMultiples([ProjectiveNielsPoint; 8]); + + impl OddMultiples { + fn create(A: &ExtendedPoint) -> OddMultiples { + let mut Ai = [ProjectiveNielsPoint::identity(); 8]; + let A2 = A.double(); + Ai[0] = A.to_projective_niels(); + for i in 0..7 { + Ai[i+1] = (&A2 + &Ai[i]).to_extended().to_projective_niels(); + } + // Now Ai = [A, 3A, 5A, 7A, 9A, 11A, 13A, 15A] + OddMultiples(Ai) + } + } + + impl Index for OddMultiples { + type Output = ProjectiveNielsPoint; + + fn index<'a>(&'a self, _index: usize) -> &'a ProjectiveNielsPoint { + &(self.0[_index]) + } + } + + /// Given a vector of public scalars and a vector of (possibly secret) + /// points, compute + /// + /// c_1 P_1 + ... + c_n P_n. + /// + /// # Input + /// + /// A vector of `Scalar`s and a vector of `ExtendedPoints`. It is an + /// error to call this function with two vectors of different lengths. + pub fn k_fold_scalar_mult(scalars: &Vec, + points: &Vec) -> ExtendedPoint { + assert_eq!(scalars.len(), points.len()); + + let nafs: Vec<_> = scalars.iter().map(|c| c.non_adjacent_form()).collect(); + let odd_multiples: Vec<_> = points.iter().map(|P| OddMultiples::create(&P)).collect(); + + let mut r = ProjectivePoint::identity(); + + for i in (0..255).rev() { + let mut t = r.double(); + + for (naf, odd_multiple) in nafs.iter().zip(odd_multiples.iter()) { + if naf[i] > 0 { + t = &t.to_extended() + &odd_multiple[( naf[i]/2) as usize]; + } else if naf[i] < 0 { + t = &t.to_extended() - &odd_multiple[(-naf[i]/2) as usize]; + } + } + + r = t.to_projective(); + } + + r.to_extended() + } + + /// Given a point `A` and scalars `a` and `b`, compute the point + /// `aA+bB`, where `B` is the Ed25519 basepoint (i.e., `B = (x,4/5)` + /// with x positive). + pub fn double_scalar_mult_basepoint(a: &Scalar, + A: &ExtendedPoint, + b: &Scalar) -> ProjectivePoint { + let a_naf = a.non_adjacent_form(); + let b_naf = b.non_adjacent_form(); + + // Find starting index + let mut i: usize = 255; + for j in (0..255).rev() { + i = j; + if a_naf[i] != 0 || b_naf[i] != 0 { + break; + } + } + + let odd_multiples_of_A = OddMultiples::create(A); + + let mut r = ProjectivePoint::identity(); + loop { + let mut t = r.double(); + + if a_naf[i] > 0 { + t = &t.to_extended() + &odd_multiples_of_A[( a_naf[i]/2) as usize]; + } else if a_naf[i] < 0 { + t = &t.to_extended() - &odd_multiples_of_A[(-a_naf[i]/2) as usize]; + } + + if b_naf[i] > 0 { + t = &t.to_extended() + &constants::bi[( b_naf[i]/2) as usize]; + } else if b_naf[i] < 0 { + t = &t.to_extended() - &constants::bi[(-b_naf[i]/2) as usize]; + } + + r = t.to_projective(); + + if i == 0 { + break; + } + i -= 1; + } + + r + } + +} + // ------------------------------------------------------------------------ // Tests // ------------------------------------------------------------------------ @@ -1373,23 +1373,6 @@ mod test { assert_eq!(aB.compress_edwards(), A_TIMES_BASEPOINT); } - /// Test double_scalar_mult_vartime vs ed25519.py - #[test] - fn double_scalar_mult_vartime_vs_ed25519py() { - let A = A_TIMES_BASEPOINT.decompress().unwrap(); - let result = double_scalar_mult_vartime(&A_SCALAR, &A, &B_SCALAR); - assert_eq!(result.compress_edwards(), DOUBLE_SCALAR_MULT_RESULT); - } - - #[test] - fn k_fold_scalar_mult_vartime_vs_ed25519py() { - let A = A_TIMES_BASEPOINT.decompress().unwrap(); - let points = vec![A,constants::ED25519_BASEPOINT]; - let scalars = vec![A_SCALAR, B_SCALAR]; - let result = k_fold_scalar_mult_vartime(&scalars, &points); - assert_eq!(result.compress_edwards(), DOUBLE_SCALAR_MULT_RESULT); - } - /// Test basepoint.double() versus the 2*basepoint constant. #[test] fn basepoint_double_vs_basepoint2() { @@ -1474,6 +1457,28 @@ mod test { P = P.scalar_mult(&A_SCALAR); } } + + mod vartime { + use super::super::*; + use super::{A_SCALAR, B_SCALAR, A_TIMES_BASEPOINT, DOUBLE_SCALAR_MULT_RESULT}; + + /// Test double_scalar_mult_vartime vs ed25519.py + #[test] + fn double_scalar_mult_basepoint_vs_ed25519py() { + let A = A_TIMES_BASEPOINT.decompress().unwrap(); + let result = vartime::double_scalar_mult_basepoint(&A_SCALAR, &A, &B_SCALAR); + assert_eq!(result.compress_edwards(), DOUBLE_SCALAR_MULT_RESULT); + } + + #[test] + fn k_fold_scalar_mult_vs_ed25519py() { + let A = A_TIMES_BASEPOINT.decompress().unwrap(); + let points = vec![A,constants::ED25519_BASEPOINT]; + let scalars = vec![A_SCALAR, B_SCALAR]; + let result = vartime::k_fold_scalar_mult(&scalars, &points); + assert_eq!(result.compress_edwards(), DOUBLE_SCALAR_MULT_RESULT); + } + } } // ------------------------------------------------------------------------ @@ -1504,30 +1509,6 @@ mod bench { b.iter(|| select_precomputed_point(0, &constants::ED25519_BASEPOINT_TABLE.0[0])); } - #[bench] - fn bench_double_scalar_mult_vartime(b: &mut Bencher) { - let A = A_TIMES_BASEPOINT.decompress().unwrap(); - b.iter(|| double_scalar_mult_vartime(&A_SCALAR, &A, &B_SCALAR)); - } - - #[bench] - fn ten_fold_scalar_mult_vartime(b: &mut Bencher) { - let mut csprng: OsRng = OsRng::new().unwrap(); - // Create 10 random scalars - let scalars: Vec<_> = (0..10).map(|_| Scalar::random(&mut csprng)).collect(); - // Create 10 points (by doing scalar mults) - let points: Vec<_> = scalars.iter() - .map(|s| ExtendedPoint::basepoint_mult(s)).collect(); - - // XXX Currently Rust's benchmarking implementation doesn't - // allow you to specify a sequence of random inputs, but only - // many trials of the same input. - // - // Since this is a variable-time function, this means the - // benchmark is only useful as a ballpark measurement. - b.iter(|| k_fold_scalar_mult_vartime(&scalars, &points)); - } - #[bench] fn add_extended_and_projective_niels_output_completed(b: &mut Bencher) { let p1 = constants::ED25519_BASEPOINT; @@ -1587,4 +1568,34 @@ mod bench { let aB = ExtendedPoint::basepoint_mult(&A_SCALAR); b.iter(|| EdwardsBasepointTable::create(&aB)); } + + mod vartime { + use super::super::*; + use super::super::test::{A_SCALAR, B_SCALAR, A_TIMES_BASEPOINT}; + use super::{Bencher, OsRng}; + + #[bench] + fn bench_double_scalar_mult_basepoint(b: &mut Bencher) { + let A = A_TIMES_BASEPOINT.decompress().unwrap(); + b.iter(|| vartime::double_scalar_mult_basepoint(&A_SCALAR, &A, &B_SCALAR)); + } + + #[bench] + fn ten_fold_scalar_mult(b: &mut Bencher) { + let mut csprng: OsRng = OsRng::new().unwrap(); + // Create 10 random scalars + let scalars: Vec<_> = (0..10).map(|_| Scalar::random(&mut csprng)).collect(); + // Create 10 points (by doing scalar mults) + let points: Vec<_> = scalars.iter() + .map(|s| ExtendedPoint::basepoint_mult(s)).collect(); + + // XXX Currently Rust's benchmarking implementation doesn't + // allow you to specify a sequence of random inputs, but only + // many trials of the same input. + // + // Since this is a variable-time function, this means the + // benchmark is only useful as a ballpark measurement. + b.iter(|| vartime::k_fold_scalar_mult(&scalars, &points)); + } + } } From a479b627a83dca0a4d82e5fb0e876a3b9e8c1d5d Mon Sep 17 00:00:00 2001 From: Henry de Valence Date: Wed, 3 May 2017 17:39:06 -0700 Subject: [PATCH 24/37] Add Decaf wrapper for k-fold vartime --- src/decaf.rs | 25 +++++++++++++++++++++++++ 1 file changed, 25 insertions(+) diff --git a/src/decaf.rs b/src/decaf.rs index 19d4977..bb73132 100644 --- a/src/decaf.rs +++ b/src/decaf.rs @@ -36,6 +36,7 @@ use collections::boxed::Box; #[cfg(all(feature = "std", feature = "basepoint_table_creation"))] use std::boxed::Box; +use curve; use curve::ExtendedPoint; use curve::EdwardsBasepointTable; use curve::BasepointMult; @@ -304,6 +305,30 @@ impl Debug for DecafPoint { } } +// ------------------------------------------------------------------------ +// Variable-time functions +// ------------------------------------------------------------------------ + +pub mod vartime { + //! Variable-time operations on decaf points, useful for non-secret data. + use super::*; + + /// Given a vector of public scalars and a vector of (possibly secret) + /// points, compute + /// + /// c_1 P_1 + ... + c_n P_n. + /// + /// # Input + /// + /// A vector of `Scalar`s and a vector of `ExtendedPoints`. It is an + /// error to call this function with two vectors of different lengths. + pub fn k_fold_scalar_mult(scalars: &Vec, + points: &Vec) -> DecafPoint { + let extended_points: Vec = points.iter().map(|P| P.0).collect(); + DecafPoint(curve::vartime::k_fold_scalar_mult(scalars, &extended_points)) + } +} + // ------------------------------------------------------------------------ // Tests // ------------------------------------------------------------------------ From 59453d755d26e4051edc19671d9c368b977aea3a Mon Sep 17 00:00:00 2001 From: Henry de Valence Date: Tue, 25 Apr 2017 16:43:15 -0700 Subject: [PATCH 25/37] Implement Mul for scalar multiplication --- src/curve.rs | 24 ++++++++++++++---------- src/decaf.rs | 17 +++++++++++++---- 2 files changed, 27 insertions(+), 14 deletions(-) diff --git a/src/curve.rs b/src/curve.rs index 26a9ede..cc30d7f 100644 --- a/src/curve.rs +++ b/src/curve.rs @@ -79,7 +79,9 @@ use core::fmt::Debug; use core::iter::Iterator; -use core::ops::{Add, Sub, Neg, Index}; +use core::ops::{Add, Sub, Neg}; +use core::ops::{Mul, MulAssign}; +use core::ops::Index; use constants; use field::FieldElement; @@ -789,18 +791,20 @@ impl<'a> Neg for &'a AffineNielsPoint { // Scalar multiplication // ------------------------------------------------------------------------ -/// Trait for scalar multiplication of an arbitrary point. -pub trait ScalarMult { - /// Compute `scalar * self`. - fn scalar_mult(&self, scalar: &S) -> Self; +impl<'b> MulAssign<&'b Scalar> for ExtendedPoint { + fn mul_assign(&mut self, scalar: &'b Scalar) { + let result = (self as &ExtendedPoint) * scalar; + *self = result; + } } -impl ScalarMult for ExtendedPoint { +impl<'a, 'b> Mul<&'b Scalar> for &'a ExtendedPoint { + type Output = ExtendedPoint; /// Scalar multiplication: compute `scalar * self`. /// /// Uses a window of size 4. Note: for scalar multiplication of /// the basepoint, `basepoint_mult` is approximately 4x faster. - fn scalar_mult(&self, scalar: &Scalar) -> ExtendedPoint { + fn mul(self, scalar: &'b Scalar) -> ExtendedPoint { let A = self.to_projective_niels(); let mut As: [ProjectiveNielsPoint; 8] = [A; 8]; for i in 0..7 { @@ -1369,7 +1373,7 @@ mod test { /// Test scalar_mult versus a known scalar multiple from ed25519.py #[test] fn scalar_mult_vs_ed25519py() { - let aB = constants::ED25519_BASEPOINT.scalar_mult(&A_SCALAR); + let aB = &constants::ED25519_BASEPOINT * &A_SCALAR; assert_eq!(aB.compress_edwards(), A_TIMES_BASEPOINT); } @@ -1454,7 +1458,7 @@ mod test { // N.B. each scalar_mult does 1407 field mults, 1024 field squarings, // so this does ~ 1M of each operation. for _ in 0..1_000 { - P = P.scalar_mult(&A_SCALAR); + P *= &A_SCALAR; } } @@ -1501,7 +1505,7 @@ mod bench { #[bench] fn scalar_mult(b: &mut Bencher) { let bp = constants::ED25519_BASEPOINT; - b.iter(|| bp.scalar_mult(&A_SCALAR)); + b.iter(|| &bp * &A_SCALAR); } #[bench] diff --git a/src/decaf.rs b/src/decaf.rs index bb73132..6e4d2c6 100644 --- a/src/decaf.rs +++ b/src/decaf.rs @@ -30,6 +30,7 @@ use subtle::CTAssignable; use subtle::CTNegatable; use core::ops::{Add, Sub, Neg}; +use core::ops::{Mul, MulAssign}; #[cfg(all(not(feature = "std"), feature = "basepoint_table_creation"))] use collections::boxed::Box; @@ -40,7 +41,6 @@ use curve; use curve::ExtendedPoint; use curve::EdwardsBasepointTable; use curve::BasepointMult; -use curve::ScalarMult; use curve::Identity; use scalar::Scalar; @@ -250,9 +250,18 @@ impl<'a> Neg for &'a DecafPoint { } } -impl ScalarMult for DecafPoint { - fn scalar_mult(&self, scalar: &Scalar) -> DecafPoint { - DecafPoint(self.0.scalar_mult(scalar)) +impl<'b> MulAssign<&'b Scalar> for DecafPoint { + fn mul_assign(&mut self, scalar: &'b Scalar) { + let result = (self as &DecafPoint) * scalar; + *self = result; + } +} + +impl<'a, 'b> Mul<&'b Scalar> for &'a DecafPoint { + type Output = DecafPoint; + /// Scalar multiplication: compute `scalar * self`. + fn mul(self, scalar: &'b Scalar) -> DecafPoint { + DecafPoint(&self.0 * scalar) } } From 0678e619cc3396d8d704d5cb7ec86deb0c9ff6d5 Mon Sep 17 00:00:00 2001 From: Henry de Valence Date: Tue, 25 Apr 2017 18:52:45 -0700 Subject: [PATCH 26/37] Implement Mul for basepoint tables --- src/constants.rs | 11 ++++++ src/curve.rs | 93 +++++++++++++++++++++--------------------------- src/decaf.rs | 67 +++++++++++----------------------- 3 files changed, 72 insertions(+), 99 deletions(-) diff --git a/src/constants.rs b/src/constants.rs index 50879da..2d3c790 100644 --- a/src/constants.rs +++ b/src/constants.rs @@ -24,6 +24,8 @@ use curve::ExtendedPoint; use curve::AffineNielsPoint; use curve::CompressedEdwardsY; use curve::EdwardsBasepointTable; +#[cfg(feature = "yolocrypto")] +use decaf::{DecafPoint, DecafBasepointTable}; use scalar::Scalar; #[cfg(feature="radix_51")] @@ -136,6 +138,10 @@ pub const BASE_CMPRSSD: CompressedEdwardsY = 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66]); +/// The Ed25519 basepoint, as a `DecafPoint`. +#[cfg(feature = "yolocrypto")] +pub const DECAF_ED25519_BASEPOINT: DecafPoint = DecafPoint(ED25519_BASEPOINT); + /// Basepoint has y = 4/5. #[cfg(not(feature="radix_51"))] pub const ED25519_BASEPOINT: ExtendedPoint = ExtendedPoint{ @@ -384,6 +390,11 @@ pub const bi: [AffineNielsPoint; 8] = [ } ]; +#[cfg(feature = "yolocrypto")] +/// The Ed25519 basepoint +pub const DECAF_ED25519_BASEPOINT_TABLE: DecafBasepointTable + = DecafBasepointTable(ED25519_BASEPOINT_TABLE); + /// Table containing precomputed multiples of the basepoint `B = (x,4/5)`. /// /// The table is defined so `constants::base[i][j-1] = j*(16^2i)*B`, diff --git a/src/curve.rs b/src/curve.rs index cc30d7f..c56dd25 100644 --- a/src/curve.rs +++ b/src/curve.rs @@ -826,27 +826,8 @@ impl<'a, 'b> Mul<&'b Scalar> for &'a ExtendedPoint { #[derive(Clone)] 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? - // 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.0[i][j-1] = jP; - jP = (&P + &jP).to_extended().to_affine_niels(); - } - P = P.mult_by_pow_2(8); - } - return table - } +impl<'a, 'b> Mul<&'b Scalar> for &'a EdwardsBasepointTable { + type Output = ExtendedPoint; /// Construct an `ExtendedPoint` from a `Scalar`, `scalar`, by /// computing the multiple `aB` of the basepoint `B`. @@ -873,7 +854,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. - pub fn basepoint_mult(&self, scalar: &Scalar) -> ExtendedPoint { + fn mul(self, scalar: &'b Scalar) -> ExtendedPoint { let e = scalar.to_radix_16(); let mut h = ExtendedPoint::identity(); let mut t: CompletedPoint; @@ -894,21 +875,26 @@ impl EdwardsBasepointTable { } } -/// Trait for scalar multiplication of a distinguished basepoint. -pub trait BasepointMult { - /// Return the basepoint `B`. - fn basepoint() -> Self; - /// Compute `scalar * B`. - fn basepoint_mult(scalar: &S) -> Self; -} - -impl BasepointMult for ExtendedPoint { - fn basepoint() -> ExtendedPoint { - constants::ED25519_BASEPOINT - } - - fn basepoint_mult(scalar: &Scalar) -> ExtendedPoint { - constants::ED25519_BASEPOINT_TABLE.basepoint_mult(scalar) +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? + // 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.0[i][j-1] = jP; + jP = (&P + &jP).to_extended().to_affine_niels(); + } + P = P.mult_by_pow_2(8); + } + return table } } @@ -1286,7 +1272,7 @@ mod test { /// Test that computing 1*basepoint gives the correct basepoint. #[test] fn basepoint_mult_one_vs_basepoint() { - let bp = ExtendedPoint::basepoint_mult(&Scalar::one()); + let bp = &constants::ED25519_BASEPOINT_TABLE * &Scalar::one(); let compressed = bp.compress_edwards(); assert_eq!(compressed, constants::BASE_CMPRSSD); } @@ -1338,7 +1324,7 @@ mod test { #[test] fn to_affine_niels_clears_denominators() { // construct a point as aB so it has denominators (ie. Z != 1) - let aB = ExtendedPoint::basepoint_mult(&A_SCALAR); + let aB = &constants::ED25519_BASEPOINT_TABLE * &A_SCALAR; let aB_affine_niels = aB.to_affine_niels(); let also_aB = (&ExtendedPoint::identity() + &aB_affine_niels).to_extended(); assert_eq!( aB.compress_edwards(), @@ -1348,14 +1334,15 @@ mod test { /// Test basepoint_mult versus a known scalar multiple from ed25519.py #[test] fn basepoint_mult_vs_ed25519py() { - let aB = ExtendedPoint::basepoint_mult(&A_SCALAR); + let aB = &constants::ED25519_BASEPOINT_TABLE * &A_SCALAR; 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); + let B = &constants::ED25519_BASEPOINT_TABLE; + let should_be_id = B * &constants::l; assert!(should_be_id.is_identity()); } @@ -1364,10 +1351,9 @@ mod 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); - let aB_2 = table.basepoint_mult(&A_SCALAR); - assert_eq!(aB_1.compress_edwards(), - aB_2.compress_edwards()); + let aB_1 = &constants::ED25519_BASEPOINT_TABLE * &A_SCALAR; + let aB_2 = &(*table) * &A_SCALAR; + assert_eq!(aB_1.compress_edwards(), aB_2.compress_edwards()); } /// Test scalar_mult versus a known scalar multiple from ed25519.py @@ -1388,7 +1374,7 @@ mod test { #[test] fn basepoint_mult_two_vs_basepoint2() { let mut two_bytes = [0u8; 32]; two_bytes[0] = 2; - let bp2 = ExtendedPoint::basepoint_mult(&Scalar(two_bytes)); + let bp2 = &constants::ED25519_BASEPOINT_TABLE * &Scalar(two_bytes); assert_eq!(bp2.compress_edwards(), BASE2_CMPRSSD); } @@ -1454,7 +1440,7 @@ mod test { /// the type system and prove correctness). #[test] fn monte_carlo_overflow_underflow_debug_assert_test() { - let mut P = ExtendedPoint::basepoint(); + let mut P = constants::ED25519_BASEPOINT; // N.B. each scalar_mult does 1407 field mults, 1024 field squarings, // so this does ~ 1M of each operation. for _ in 0..1_000 { @@ -1499,13 +1485,14 @@ mod bench { #[bench] fn basepoint_mult(b: &mut Bencher) { - b.iter(|| ExtendedPoint::basepoint_mult(&A_SCALAR)); + let B = &constants::ED25519_BASEPOINT_TABLE; + b.iter(|| B * &A_SCALAR); } #[bench] fn scalar_mult(b: &mut Bencher) { - let bp = constants::ED25519_BASEPOINT; - b.iter(|| &bp * &A_SCALAR); + let B = &constants::ED25519_BASEPOINT; + b.iter(|| B * &A_SCALAR); } #[bench] @@ -1569,7 +1556,7 @@ mod bench { #[cfg(feature="basepoint_table_creation")] #[bench] fn create_basepoint_table(b: &mut Bencher) { - let aB = ExtendedPoint::basepoint_mult(&A_SCALAR); + let aB = &constants::ED25519_BASEPOINT_TABLE * &A_SCALAR; b.iter(|| EdwardsBasepointTable::create(&aB)); } @@ -1590,8 +1577,8 @@ mod bench { // Create 10 random scalars let scalars: Vec<_> = (0..10).map(|_| Scalar::random(&mut csprng)).collect(); // Create 10 points (by doing scalar mults) - let points: Vec<_> = scalars.iter() - .map(|s| ExtendedPoint::basepoint_mult(s)).collect(); + let B = &constants::ED25519_BASEPOINT_TABLE; + let points: Vec<_> = scalars.iter().map(|s| B * &s).collect(); // XXX Currently Rust's benchmarking implementation doesn't // allow you to specify a sequence of random inputs, but only diff --git a/src/decaf.rs b/src/decaf.rs index 6e4d2c6..1023b26 100644 --- a/src/decaf.rs +++ b/src/decaf.rs @@ -40,7 +40,6 @@ use std::boxed::Box; use curve; use curve::ExtendedPoint; use curve::EdwardsBasepointTable; -use curve::BasepointMult; use curve::Identity; use scalar::Scalar; @@ -265,22 +264,17 @@ impl<'a, 'b> Mul<&'b Scalar> for &'a DecafPoint { } } -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(ExtendedPoint::basepoint()) - } - - fn basepoint_mult(scalar: &Scalar) -> DecafPoint { - DecafPoint(ExtendedPoint::basepoint_mult(scalar)) - } -} - - /// Precomputation #[derive(Clone)] -pub struct DecafBasepointTable(EdwardsBasepointTable); +pub struct DecafBasepointTable(pub EdwardsBasepointTable); + +impl<'a, 'b> Mul<&'b Scalar> for &'a DecafBasepointTable { + type Output = DecafPoint; + + fn mul(self, scalar: &'b Scalar) -> DecafPoint { + DecafPoint(&self.0 * scalar) + } +} impl DecafBasepointTable { /// Create a precomputed table of multiples of the given `basepoint`. @@ -289,11 +283,6 @@ impl DecafBasepointTable { 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)) - } } // ------------------------------------------------------------------------ @@ -350,7 +339,6 @@ mod test { use constants; use curve::CompressedEdwardsY; use curve::ExtendedPoint; - use curve::BasepointMult; use curve::Identity; use super::*; @@ -376,17 +364,17 @@ mod test { #[test] fn decaf_basepoint_roundtrip() { - let bp_compressed_decaf = DecafPoint::basepoint().compress(); + let bp_compressed_decaf = constants::DECAF_ED25519_BASEPOINT.compress(); let bp_recaf = bp_compressed_decaf.decompress().unwrap().0; // 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); + let diff = &constants::ED25519_BASEPOINT - &bp_recaf; + let diff4 = diff.mult_by_pow_2(4); // XXX this is wrong assert_eq!(diff4.compress_edwards(), CompressedEdwardsY::identity()); } #[test] fn decaf_four_torsion_basepoint() { - let bp = DecafPoint::basepoint(); + let bp = constants::DECAF_ED25519_BASEPOINT; let bp_coset = bp.coset4(); for i in 0..4 { assert_eq!(bp, DecafPoint(bp_coset[i])); @@ -396,8 +384,8 @@ mod test { #[test] fn decaf_four_torsion_random() { let mut rng = OsRng::new().unwrap(); - let s = Scalar::random(&mut rng); - let P = DecafPoint::basepoint_mult(&s); + let B = &constants::DECAF_ED25519_BASEPOINT_TABLE; + let P = B * &Scalar::random(&mut rng); let P_coset = P.coset4(); for i in 0..4 { assert_eq!(P, DecafPoint(P_coset[i])); @@ -407,27 +395,14 @@ mod test { #[test] fn decaf_random_roundtrip() { let mut rng = OsRng::new().unwrap(); + let B = &constants::DECAF_ED25519_BASEPOINT_TABLE; for _ in 0..100 { - let s = Scalar::random(&mut rng); - let P = DecafPoint::basepoint_mult(&s); + let P = B * &Scalar::random(&mut rng); let compressed_P = P.compress(); let Q = compressed_P.decompress().unwrap(); assert_eq!(P, Q); } } - - /// 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(); - 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(all(test, feature = "bench"))] @@ -440,8 +415,8 @@ mod bench { #[bench] fn decompression(b: &mut Bencher) { let mut rng = OsRng::new().unwrap(); - let s = Scalar::random(&mut rng); - let P = DecafPoint::basepoint_mult(&s); + let B = &constants::DECAF_ED25519_BASEPOINT_TABLE; + let P = B * &Scalar::random(&mut rng); let P_compressed = P.compress(); b.iter(|| P_compressed.decompress().unwrap()); } @@ -449,8 +424,8 @@ mod bench { #[bench] fn compression(b: &mut Bencher) { let mut rng = OsRng::new().unwrap(); - let s = Scalar::random(&mut rng); - let P = DecafPoint::basepoint_mult(&s); + let B = &constants::DECAF_ED25519_BASEPOINT_TABLE; + let P = B * &Scalar::random(&mut rng); b.iter(|| P.compress()); } } From 127169c151f27b32ebd6e79d843307cb8cd29d05 Mon Sep 17 00:00:00 2001 From: Henry de Valence Date: Tue, 25 Apr 2017 21:55:19 -0700 Subject: [PATCH 27/37] Remove boxes --- Cargo.toml | 4 +--- src/curve.rs | 16 +++++----------- src/decaf.rs | 11 ++--------- src/lib.rs | 4 ++-- 4 files changed, 10 insertions(+), 25 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index c164472..556dd79 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -36,12 +36,10 @@ version = "^0.6" version = "0.4" [features] -nightly = ["basepoint_table_creation", "radix_51"] +nightly = ["radix_51"] default = ["std"] std = ["rand"] yolocrypto = [] -# Needs nightly for placement new -basepoint_table_creation = [] bench = [] # Radix-51 arithmetic using u128 radix_51 = [] diff --git a/src/curve.rs b/src/curve.rs index c56dd25..3a5ab52 100644 --- a/src/curve.rs +++ b/src/curve.rs @@ -92,11 +92,6 @@ use subtle::CTAssignable; use subtle::CTEq; use subtle::CTNegatable; -#[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; - // ------------------------------------------------------------------------ // Compressed points // ------------------------------------------------------------------------ @@ -877,12 +872,11 @@ impl<'a, 'b> Mul<&'b Scalar> for &'a EdwardsBasepointTable { impl EdwardsBasepointTable { /// Create a table of precomputed multiples of `basepoint`. - #[cfg(feature="basepoint_table_creation")] - pub fn create(basepoint: &ExtendedPoint) -> Box { + pub fn create(basepoint: &ExtendedPoint) -> EdwardsBasepointTable { // Create the table storage - // 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]); + // stick 30K on the stack and call it a day. + let mut table = EdwardsBasepointTable([[AffineNielsPoint::identity(); 8]; 32]); let mut P = basepoint.clone(); for i in 0..32 { // P = (16^2)^i * B @@ -894,7 +888,7 @@ impl EdwardsBasepointTable { } P = P.mult_by_pow_2(8); } - return table + table } } @@ -1352,7 +1346,7 @@ mod test { fn test_precomputed_basepoint_mult() { let table = EdwardsBasepointTable::create(&constants::ED25519_BASEPOINT); let aB_1 = &constants::ED25519_BASEPOINT_TABLE * &A_SCALAR; - let aB_2 = &(*table) * &A_SCALAR; + let aB_2 = &table * &A_SCALAR; assert_eq!(aB_1.compress_edwards(), aB_2.compress_edwards()); } diff --git a/src/decaf.rs b/src/decaf.rs index 1023b26..a0514ae 100644 --- a/src/decaf.rs +++ b/src/decaf.rs @@ -32,11 +32,6 @@ use subtle::CTNegatable; use core::ops::{Add, Sub, Neg}; use core::ops::{Mul, MulAssign}; -#[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; use curve::ExtendedPoint; use curve::EdwardsBasepointTable; @@ -278,10 +273,8 @@ impl<'a, 'b> Mul<&'b Scalar> for &'a DecafBasepointTable { 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) + pub fn create(basepoint: &DecafPoint) -> DecafBasepointTable { + DecafBasepointTable(EdwardsBasepointTable::create(&basepoint.0)) } } diff --git a/src/lib.rs b/src/lib.rs index 31e7177..40efe8b 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -11,10 +11,10 @@ #![cfg_attr(not(feature = "std"), no_std)] #![cfg_attr(not(feature = "std"), feature(collections))] -#![cfg_attr(feature = "nightly", feature(box_syntax))] #![cfg_attr(feature = "nightly", feature(i128_type))] -#![allow(unused_features)] #![cfg_attr(feature = "bench", feature(test))] + +#![allow(unused_features)] #![deny(missing_docs)] // refuse to compile if documentation is missing //! # curve25519-dalek From 0ae0d2b72a47cc17189b773fe1eeac17f68af584 Mon Sep 17 00:00:00 2001 From: Henry de Valence Date: Wed, 3 May 2017 18:18:00 -0700 Subject: [PATCH 28/37] Add function to get the basepoint from a basepoint table --- src/curve.rs | 14 ++++++++++++++ src/decaf.rs | 5 +++++ 2 files changed, 19 insertions(+) diff --git a/src/curve.rs b/src/curve.rs index 3a5ab52..ca3e4a1 100644 --- a/src/curve.rs +++ b/src/curve.rs @@ -890,6 +890,13 @@ impl EdwardsBasepointTable { } table } + + /// Get the basepoint for this table as an `ExtendedPoint`. + pub fn basepoint(&self) -> ExtendedPoint { + // self.0[0][0] has 1*(16^2)^0*B, but as an `AffineNielsPoint` + // Add identity to convert to extended. + (&ExtendedPoint::identity() + &self.0[0][0]).to_extended() + } } impl ExtendedPoint { @@ -1271,6 +1278,13 @@ mod test { assert_eq!(compressed, constants::BASE_CMPRSSD); } + /// Test that `EdwardsBasepointTable::basepoint()` gives the correct basepoint. + #[test] + fn basepoint_table_basepoint_function_correct() { + let bp = constants::ED25519_BASEPOINT_TABLE.basepoint(); + assert_eq!(bp.compress_edwards(), constants::BASE_CMPRSSD); + } + /// Test `impl Add for ExtendedPoint` /// using basepoint + basepoint versus the 2*basepoint constant. #[test] diff --git a/src/decaf.rs b/src/decaf.rs index a0514ae..9d1a830 100644 --- a/src/decaf.rs +++ b/src/decaf.rs @@ -276,6 +276,11 @@ impl DecafBasepointTable { pub fn create(basepoint: &DecafPoint) -> DecafBasepointTable { DecafBasepointTable(EdwardsBasepointTable::create(&basepoint.0)) } + + /// Get the basepoint for this table as a `DecafPoint`. + pub fn basepoint(&self) -> DecafPoint { + DecafPoint(self.0.basepoint()) + } } // ------------------------------------------------------------------------ From c6dc9d318d37629d7178615a9bb2b35f20998dcb Mon Sep 17 00:00:00 2001 From: Henry & Isis Date: Wed, 3 May 2017 19:06:41 -0700 Subject: [PATCH 29/37] Add a helper function to construct a Scalar from a u64 --- src/scalar.rs | 23 +++++++++++++++++++++++ 1 file changed, 23 insertions(+) diff --git a/src/scalar.rs b/src/scalar.rs index 067f780..73b30f1 100644 --- a/src/scalar.rs +++ b/src/scalar.rs @@ -261,6 +261,15 @@ impl Scalar { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 ]) } + /// Construct a scalar from the given `u64`. + pub fn from_u64(x: u64) -> Scalar { + let mut s = Scalar::zero(); + for i in 0..8 { + s[i] = (x >> (i*8)) as u8; + } + s + } + /// Compute the multiplicative inverse of this scalar. pub fn invert(&self) -> Scalar { self.unpack().invert().pack() @@ -728,6 +737,20 @@ mod test { } } + #[test] + fn from_unsigned() { + let val = 0xdeadbeefdeadbeef; + let s = Scalar::from_u64(val); + assert_eq!(s[7], 0xde); + assert_eq!(s[6], 0xad); + assert_eq!(s[5], 0xbe); + assert_eq!(s[4], 0xef); + assert_eq!(s[3], 0xde); + assert_eq!(s[2], 0xad); + assert_eq!(s[1], 0xbe); + assert_eq!(s[0], 0xef); + } + #[test] fn scalar_multiply_by_one() { let one = Scalar::one(); From c18627f7c2d103a5dd232cf79b8202ade5361848 Mon Sep 17 00:00:00 2001 From: Henry de Valence Date: Thu, 4 May 2017 00:02:29 -0700 Subject: [PATCH 30/37] Generalize k_fold_scalar_mult --- src/curve.rs | 20 ++++++++++++-------- src/decaf.rs | 9 +++++---- 2 files changed, 17 insertions(+), 12 deletions(-) diff --git a/src/curve.rs b/src/curve.rs index ca3e4a1..78ff254 100644 --- a/src/curve.rs +++ b/src/curve.rs @@ -1066,12 +1066,15 @@ pub mod vartime { /// /// A vector of `Scalar`s and a vector of `ExtendedPoints`. It is an /// error to call this function with two vectors of different lengths. - pub fn k_fold_scalar_mult(scalars: &Vec, - points: &Vec) -> ExtendedPoint { - assert_eq!(scalars.len(), points.len()); + pub fn k_fold_scalar_mult<'a,'b,I,J>(scalars: I, points: J) -> ExtendedPoint + where I: IntoIterator, J: IntoIterator + { + //assert_eq!(scalars.len(), points.len()); - let nafs: Vec<_> = scalars.iter().map(|c| c.non_adjacent_form()).collect(); - let odd_multiples: Vec<_> = points.iter().map(|P| OddMultiples::create(&P)).collect(); + let nafs: Vec<_> = scalars.into_iter() + .map(|c| c.non_adjacent_form()).collect(); + let odd_multiples: Vec<_> = points.into_iter() + .map(|P| OddMultiples::create(P)).collect(); let mut r = ProjectivePoint::identity(); @@ -1471,9 +1474,10 @@ mod test { #[test] fn k_fold_scalar_mult_vs_ed25519py() { let A = A_TIMES_BASEPOINT.decompress().unwrap(); - let points = vec![A,constants::ED25519_BASEPOINT]; - let scalars = vec![A_SCALAR, B_SCALAR]; - let result = vartime::k_fold_scalar_mult(&scalars, &points); + let result = vartime::k_fold_scalar_mult( + &[A_SCALAR, B_SCALAR], + &[A, constants::ED25519_BASEPOINT] + ); assert_eq!(result.compress_edwards(), DOUBLE_SCALAR_MULT_RESULT); } } diff --git a/src/decaf.rs b/src/decaf.rs index 9d1a830..4fba23f 100644 --- a/src/decaf.rs +++ b/src/decaf.rs @@ -318,10 +318,11 @@ pub mod vartime { /// /// A vector of `Scalar`s and a vector of `ExtendedPoints`. It is an /// error to call this function with two vectors of different lengths. - pub fn k_fold_scalar_mult(scalars: &Vec, - points: &Vec) -> DecafPoint { - let extended_points: Vec = points.iter().map(|P| P.0).collect(); - DecafPoint(curve::vartime::k_fold_scalar_mult(scalars, &extended_points)) + pub fn k_fold_scalar_mult<'a,'b,I,J>(scalars: I, points: J) -> DecafPoint + where I: IntoIterator, J: IntoIterator + { + let extended_points = points.into_iter().map(|P| &P.0); + DecafPoint(curve::vartime::k_fold_scalar_mult(scalars, extended_points)) } } From 4da1d795a15fed774cd18d1c33628e6bbe5d5ce2 Mon Sep 17 00:00:00 2001 From: Isis Lovecruft Date: Tue, 9 May 2017 00:01:48 +0000 Subject: [PATCH 31/37] 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 32/37] 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 33/37] 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 34/37] 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 35/37] 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 36/37] 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 { From 1b3422c37db7a3bf30af8e28c6b585f743327d36 Mon Sep 17 00:00:00 2001 From: Isis Lovecruft Date: Sun, 14 May 2017 09:39:13 +0000 Subject: [PATCH 37/37] Bump the version to 0.7.0. --- Cargo.toml | 2 +- README.md | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 556dd79..484a117 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "curve25519-dalek" -version = "0.6.0" +version = "0.7.0" authors = ["Isis Lovecruft ", "Henry de Valence "] readme = "README.md" diff --git a/README.md b/README.md index ef10f59..16bad4e 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.6" + curve25519-dalek = "^0.7" Then, in your library or executable source, add: