From 3a664a054aab763b55146c8c9585bd5f67ba0bc8 Mon Sep 17 00:00:00 2001 From: Isis Lovecruft Date: Sat, 27 May 2017 01:20:14 +0000 Subject: [PATCH 01/17] Whitespace fix in decaf module. --- src/decaf.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/decaf.rs b/src/decaf.rs index 6e41868..ecaa616 100644 --- a/src/decaf.rs +++ b/src/decaf.rs @@ -209,7 +209,7 @@ impl DecafPoint { // Its inverse is x -> -ix. // let untwisted_X = &self.X * &constants::MSQRT_M1; // etc. - + // // Step 0: pre-rotation, needed for Decaf with E[8] = Z/8. // // We want to select a point (x,y) in the coset P + E[4] with From 044128dc586a4dc5e4532bff81507ed9e8fdc433 Mon Sep 17 00:00:00 2001 From: Isis Lovecruft Date: Sat, 27 May 2017 18:21:37 +0000 Subject: [PATCH 02/17] Remove excessive clone() on Copy, caught by clippy. --- src/curve.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/curve.rs b/src/curve.rs index cc1cfc8..045da8c 100644 --- a/src/curve.rs +++ b/src/curve.rs @@ -1006,7 +1006,7 @@ impl EdwardsBasepointTable { // XXX can we skip the initialization without too much unsafety? // stick 30K on the stack and call it a day. let mut table = EdwardsBasepointTable([[AffineNielsPoint::identity(); 8]; 32]); - let mut P = basepoint.clone(); + let mut P = *basepoint; for i in 0..32 { // P = (16^2)^i * B let mut jP = P.to_affine_niels(); From 2485472023a101ea3329bc4a50a798ebedb07b95 Mon Sep 17 00:00:00 2001 From: Isis Lovecruft Date: Sat, 27 May 2017 18:23:31 +0000 Subject: [PATCH 03/17] Remove explicit lifetime, caught by clippy. --- src/curve.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/curve.rs b/src/curve.rs index 045da8c..2d91d38 100644 --- a/src/curve.rs +++ b/src/curve.rs @@ -1181,7 +1181,7 @@ pub mod vartime { impl Index for OddMultiples { type Output = ProjectiveNielsPoint; - fn index<'a>(&'a self, _index: usize) -> &'a ProjectiveNielsPoint { + fn index(&self, _index: usize) -> &ProjectiveNielsPoint { &(self.0[_index]) } } From 60692ce891a1542526f85f4ac8ef43de7960e7cf Mon Sep 17 00:00:00 2001 From: Isis Lovecruft Date: Sat, 27 May 2017 18:24:02 +0000 Subject: [PATCH 04/17] Put math/code in a docstring in ticks. --- src/curve.rs | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/src/curve.rs b/src/curve.rs index 2d91d38..9052b1f 100644 --- a/src/curve.rs +++ b/src/curve.rs @@ -1187,9 +1187,7 @@ pub mod vartime { } /// Given a vector of public scalars and a vector of (possibly secret) - /// points, compute - /// - /// c_1 P_1 + ... + c_n P_n. + /// points, compute `c_1 P_1 + ... + c_n P_n`. /// /// # Input /// From 1c4f283be4d4d37bced6a8da7119cf4ab8bf0762 Mon Sep 17 00:00:00 2001 From: Isis Lovecruft Date: Sat, 27 May 2017 18:28:37 +0000 Subject: [PATCH 05/17] Change debug_assert to assert in arrays_equal(). --- src/subtle.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/subtle.rs b/src/subtle.rs index 1dd6ba4..93a6e52 100644 --- a/src/subtle.rs +++ b/src/subtle.rs @@ -96,7 +96,7 @@ pub fn byte_is_nonzero(b: u8) -> u8 { /// Check equality of two arrays, `a` and `b`, in constant time. /// -/// There is a `debug_assert!` that the two arrays are of equal length. For +/// There is an `assert!` that the two arrays are of equal length. For /// example, the following code will panic: /// /// ```rust,ignore @@ -142,7 +142,7 @@ pub fn byte_is_nonzero(b: u8) -> u8 { /// Returns `1u8` if `a == b` and `0u8` otherwise. #[inline(always)] pub fn arrays_equal(a: &[u8], b: &[u8]) -> u8 { - debug_assert!(a.len() == b.len()); + assert_eq!(a.len(), b.len()); let mut x: u8 = 0; From 648f95887a36bdcbbac655af34e9eb931b4409f4 Mon Sep 17 00:00:00 2001 From: Isis Lovecruft Date: Sat, 27 May 2017 18:35:34 +0000 Subject: [PATCH 06/17] Rename subtle::bytes_equal_ct() to bytes_equal(). --- src/curve.rs | 4 ++-- src/subtle.rs | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/curve.rs b/src/curve.rs index 9052b1f..5909cba 100644 --- a/src/curve.rs +++ b/src/curve.rs @@ -91,7 +91,7 @@ use constants; use field::FieldElement; use scalar::Scalar; use subtle::arrays_equal; -use subtle::bytes_equal_ct; +use subtle::bytes_equal; use subtle::CTAssignable; use subtle::CTEq; use subtle::CTNegatable; @@ -1081,7 +1081,7 @@ fn select_precomputed_point(x: i8, points: &[T; 8]) -> T for j in 1..9 { // Copy `points[j-1] == j*P` onto `t` in constant time if `|x| == j`. t.conditional_assign(&points[j-1], - bytes_equal_ct(xabs as u8, j as u8)); + bytes_equal(xabs as u8, j as u8)); } // Now t == |x| * P. diff --git a/src/subtle.rs b/src/subtle.rs index 93a6e52..9770951 100644 --- a/src/subtle.rs +++ b/src/subtle.rs @@ -57,7 +57,7 @@ impl CTNegatable for T /// /// Returns `1u8` if `a == b` and `0u8` otherwise. #[inline(always)] -pub fn bytes_equal_ct(a: u8, b: u8) -> u8 { +pub fn bytes_equal(a: u8, b: u8) -> u8 { let mut x: u8; x = !(a ^ b); @@ -149,7 +149,7 @@ pub fn arrays_equal(a: &[u8], b: &[u8]) -> u8 { for i in 0 .. a.len() { x |= a[i] ^ b[i]; } - bytes_equal_ct(x, 0) + bytes_equal(x, 0) } #[cfg(test)] From 674a00df5b86e0701cb0bcad8c4234585fc32864 Mon Sep 17 00:00:00 2001 From: Isis Lovecruft Date: Sun, 28 May 2017 22:42:09 +0000 Subject: [PATCH 07/17] Some rustfmt fixes. I disagreed with all the other ones. --- src/curve.rs | 40 +++++++++++++++++++++------------------- src/decaf.rs | 35 +++++++++++++++++++---------------- src/field.rs | 12 ++++++------ src/scalar.rs | 33 +++++++++++++++++---------------- src/subtle.rs | 3 +-- 5 files changed, 64 insertions(+), 59 deletions(-) diff --git a/src/curve.rs b/src/curve.rs index 5909cba..3fbea08 100644 --- a/src/curve.rs +++ b/src/curve.rs @@ -193,7 +193,7 @@ impl CompressedMontgomeryU { // // XXX any other exceptional points for the birational map? pub fn decompress(&self) -> Option { - let u: FieldElement = FieldElement::from_bytes(&self.0); + let u: FieldElement = FieldElement::from_bytes(&self.0); // If u = -1, then v^2 = u*(u^2+486662*u+1) = 486660. // But 486660 is nonsquare mod p, so this is not a curve point. @@ -317,8 +317,9 @@ impl<'de> Deserialize<'de> for ExtendedPoint { where E: serde::de::Error { if v.len() == 32 { - let arr32 = array_ref!(v,0,32); // &[u8;32] from &[u8] - CompressedEdwardsY(*arr32).decompress() + let arr32 = array_ref!(v, 0, 32); // &[u8;32] from &[u8] + CompressedEdwardsY(*arr32) + .decompress() .ok_or(serde::de::Error::custom("decompression failed")) } else { Err(serde::de::Error::invalid_length(v.len(), &self)) @@ -518,8 +519,8 @@ impl CTAssignable for ExtendedPoint { impl CTEq for ExtendedPoint { fn ct_eq(&self, other: &ExtendedPoint) -> u8 { - arrays_equal( self.compress_edwards().as_bytes(), - other.compress_edwards().as_bytes()) + arrays_equal(self.compress_edwards().as_bytes(), + other.compress_edwards().as_bytes()) } } @@ -551,7 +552,7 @@ impl ProjectivePoint { /// Given (X:Y:Z) in Ɛ, passing to Ɛₑ can be performed in 3M+1S by /// computing (XZ,YZ,XY,Z²). (Note that in that paper, points are /// (X:Y:T:Z) so this really does match the code below). - #[allow(dead_code)] // rustc complains this is unused even when it's used + #[allow(dead_code)] // rustc complains this is unused even when it's used fn to_extended(&self) -> ExtendedPoint { ExtendedPoint{ X: &self.X * &self.Z, @@ -714,7 +715,7 @@ impl ExtendedPoint { // Addition and Subtraction // ------------------------------------------------------------------------ -impl<'a,'b> Add<&'b ProjectiveNielsPoint> for &'a ExtendedPoint { +impl<'a, 'b> Add<&'b ProjectiveNielsPoint> for &'a ExtendedPoint { type Output = CompletedPoint; fn add(self, other: &'b ProjectiveNielsPoint) -> CompletedPoint { @@ -735,7 +736,7 @@ impl<'a,'b> Add<&'b ProjectiveNielsPoint> for &'a ExtendedPoint { } } -impl<'a,'b> Sub<&'b ProjectiveNielsPoint> for &'a ExtendedPoint { +impl<'a, 'b> Sub<&'b ProjectiveNielsPoint> for &'a ExtendedPoint { type Output = CompletedPoint; fn sub(self, other: &'b ProjectiveNielsPoint) -> CompletedPoint { @@ -756,7 +757,7 @@ impl<'a,'b> Sub<&'b ProjectiveNielsPoint> for &'a ExtendedPoint { } } -impl<'a,'b> Add<&'b AffineNielsPoint> for &'a ExtendedPoint { +impl<'a, 'b> Add<&'b AffineNielsPoint> for &'a ExtendedPoint { type Output = CompletedPoint; fn add(self, other: &'b AffineNielsPoint) -> CompletedPoint { @@ -776,7 +777,7 @@ impl<'a,'b> Add<&'b AffineNielsPoint> for &'a ExtendedPoint { } } -impl<'a,'b> Sub<&'b AffineNielsPoint> for &'a ExtendedPoint { +impl<'a, 'b> Sub<&'b AffineNielsPoint> for &'a ExtendedPoint { type Output = CompletedPoint; fn sub(self, other: &'b AffineNielsPoint) -> CompletedPoint { @@ -796,7 +797,7 @@ impl<'a,'b> Sub<&'b AffineNielsPoint> for &'a ExtendedPoint { } } -impl<'a,'b> Add<&'b ExtendedPoint> for &'a ExtendedPoint { +impl<'a, 'b> Add<&'b ExtendedPoint> for &'a ExtendedPoint { type Output = ExtendedPoint; fn add(self, other: &'b ExtendedPoint) -> ExtendedPoint { (self + &other.to_projective_niels()).to_extended() @@ -809,7 +810,7 @@ impl<'b> AddAssign<&'b ExtendedPoint> for ExtendedPoint { } } -impl<'a,'b> Sub<&'b ExtendedPoint> for &'a ExtendedPoint { +impl<'a, 'b> Sub<&'b ExtendedPoint> for &'a ExtendedPoint { type Output = ExtendedPoint; fn sub(self, other: &'b ExtendedPoint) -> ExtendedPoint { (self - &other.to_projective_niels()).to_extended() @@ -1193,8 +1194,9 @@ 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<'a,'b,I,J>(scalars: I, points: J) -> ExtendedPoint - where I: IntoIterator, J: IntoIterator + 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()); @@ -1652,7 +1654,7 @@ mod test { // CBOR apparently has two bytes of overhead for a 32-byte string. // Set the low byte of the compressed point to 1 to make it invalid. output[2] = 1; - let parsed: Result = serde_cbor::from_slice(&output); + let parsed: Result = serde_cbor::from_slice(&output); assert!(parsed.is_err()); } } @@ -1667,7 +1669,7 @@ mod bench { use test::Bencher; use constants; use super::*; - use super::test::{A_SCALAR}; + use super::test::A_SCALAR; #[bench] fn edwards_decompress(b: &mut Bencher) { @@ -1734,21 +1736,21 @@ mod bench { fn projective_double_output_completed(b: &mut Bencher) { let p1 = constants::ED25519_BASEPOINT.to_projective(); - b.iter(|| p1.double() ); + b.iter(|| p1.double()); } #[bench] fn extended_double_output_extended(b: &mut Bencher) { let p1 = constants::ED25519_BASEPOINT; - b.iter(|| p1.double() ); + b.iter(|| p1.double()); } #[bench] fn mult_by_cofactor(b: &mut Bencher) { let p1 = constants::ED25519_BASEPOINT; - b.iter(|| p1.mult_by_cofactor() ); + b.iter(|| p1.mult_by_cofactor()); } #[cfg(feature="basepoint_table_creation")] diff --git a/src/decaf.rs b/src/decaf.rs index ecaa616..08abe89 100644 --- a/src/decaf.rs +++ b/src/decaf.rs @@ -60,7 +60,7 @@ pub struct CompressedDecaf(pub [u8; 32]); /// The result of compressing a `DecafPoint`. impl CompressedDecaf { /// View this `CompressedDecaf` as an array of bytes. - pub fn as_bytes<'a>(&'a self) -> &'a [u8;32] { + pub fn as_bytes<'a>(&'a self) -> &'a [u8; 32] { &self.0 } @@ -121,7 +121,7 @@ impl CompressedDecaf { impl Identity for CompressedDecaf { fn identity() -> CompressedDecaf { - CompressedDecaf([0u8;32]) + CompressedDecaf([0u8; 32]) } } @@ -165,8 +165,9 @@ impl<'de> Deserialize<'de> for DecafPoint { where E: serde::de::Error { if v.len() == 32 { - let arr32 = array_ref!(v,0,32); // &[u8;32] from &[u8] - CompressedDecaf(*arr32).decompress() + let arr32 = array_ref!(v, 0, 32); // &[u8;32] from &[u8] + CompressedDecaf(*arr32) + .decompress() .ok_or(serde::de::Error::custom("decompression failed")) } else { Err(serde::de::Error::invalid_length(v.len(), &self)) @@ -193,10 +194,10 @@ impl DecafPoint { pub fn compress(&self) -> CompressedDecaf { // Q: Do we want to encode twisted or untwisted? // - // Notes: + // Notes: // Recall that the twisted Edwards curve E_{a,d} is of the form // - // ax^2 + y^2 = 1 + dx^2y^2. + // ax^2 + y^2 = 1 + dx^2y^2. // // Internally, we operate on the curve with a = -1, d = // -121665/121666, a.k.a., the twist. But maybe we would like @@ -205,7 +206,7 @@ impl DecafPoint { // // Fix i, a square root of -1 (mod p). // - // The map x -> ix is an isomorphism from E_{a,d} to E_{-a,-d}. + // The map x -> ix is an isomorphism from E_{a,d} to E_{-a,-d}. // Its inverse is x -> -ix. // let untwisted_X = &self.X * &constants::MSQRT_M1; // etc. @@ -247,7 +248,7 @@ impl DecafPoint { // // 0 = (-X^2 + Y^2)*Z^2 - Z^4 - d*X^2*Y^2, // - // so + // so // 0 = (-X^2 + Y^2)*Z^2 - Z^4 - d*T^2*Z^2 since XY=TZ // = (-X^2 + Y^2 - Z^2 - d*T^2)*Z^2 // = ( X^2 - Y^2 + Z^2 + d*T^2)*Z^2 mult by -1 @@ -304,7 +305,7 @@ impl DecafPoint { let (tmp_is_nonzero_square, W) = tmp.invsqrt(); // tmp should always be a square (why? related to being in the // image of the isogeny?) - debug_assert_eq!( tmp_is_nonzero_square | tmp.is_zero(), 1u8 ); + debug_assert_eq!(tmp_is_nonzero_square | tmp.is_zero(), 1u8); let xy = &T.square() * &(&W.square() * &(&TZ * &ZZ_plus_XX)); let rotate = 1u8 & !(Y.is_nonzero() & xy.is_nonnegative_decaf()); @@ -363,7 +364,7 @@ impl DecafPoint { let r_0_squared = r_0.square(); let r = &r_0_squared + &r_0_squared; - // 2. Compute D <--- (dr + (a-d)) * (dr - (d + ar)) + // 2. Compute D <--- (dr + (a-d)) * (dr - (d + ar)) let dr = &constants::d * &r; // D = (dr + (a-d)) * (dr - (d + ar)) // = (dr + (a-d)) * (dr - (d-r)) since a=-1 @@ -398,7 +399,7 @@ impl DecafPoint { s *= &c; // 6. Compute t <--- -c*N*(r-1)* ((a-2d)*e)^2 -1 - let a_minus_2d_e_sq = (&(&minus_one-&constants::d2)*&e).square(); + let a_minus_2d_e_sq = (&(&minus_one - &constants::d2) * &e).square(); let c_N_r_minus_1 = &c * &(&N * &(&r + &minus_one)); let t = &minus_one - &(&c_N_r_minus_1 * &a_minus_2d_e_sq); @@ -467,7 +468,8 @@ impl DecafPoint { /// ``` /// pub fn hash_from_bytes(input: &[u8]) -> DecafPoint - where D: Digest + Default { + where D: Digest + Default + { let mut hash = D::default(); hash.input(input); DecafPoint::from_hash(hash) @@ -479,7 +481,8 @@ impl DecafPoint { /// to stream data into the `Digest` than to pass a single byte /// slice. pub fn from_hash(hash: D) -> DecafPoint - where D: Digest + Default { + where D: Digest + Default + { // XXX this seems clumsy let mut output = [0u8; 32]; output.copy_from_slice(hash.result().as_slice()); @@ -674,8 +677,9 @@ 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<'a,'b,I,J>(scalars: I, points: J) -> DecafPoint - where I: IntoIterator, J: IntoIterator + 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)) @@ -836,4 +840,3 @@ mod bench { b.iter(|| P.compress()); } } - diff --git a/src/field.rs b/src/field.rs index ef36f28..57aae65 100644 --- a/src/field.rs +++ b/src/field.rs @@ -116,7 +116,7 @@ impl Index for FieldElement { impl IndexMut for FieldElement { fn index_mut(&mut self, _index: usize) -> &mut Limb { - &mut(self.0[_index]) + &mut (self.0[_index]) } } @@ -456,7 +456,7 @@ impl FieldElement { #[cfg(not(feature="radix_51"))] fn reduce(mut h: [i64; 10]) -> FieldElement { //FeCombine - let mut c = [0i64;10]; + let mut c = [0i64; 10]; /* |h[0]| <= (1.1*1.1*2^52*(1+19+19+19+19)+1.1*1.1*2^50*(38+38+38+38+38)) @@ -709,7 +709,7 @@ impl FieldElement { // evidently 2^255 h10-2^255 q = 0. // Goal: Output h[0]+...+2^230 h[9]. - let mut s = [0u8;32]; + let mut s = [0u8; 32]; s[0] = (h[0] >> 0) as u8; s[1] = (h[0] >> 8) as u8; s[2] = (h[0] >> 16) as u8; @@ -1179,7 +1179,7 @@ impl FieldElement { let r_prime = &constants::SQRT_M1 * &r; r.conditional_assign(&r_prime, flipped_sign_sqrt); - + let was_nonzero_square = correct_sign_sqrt | flipped_sign_sqrt; (was_nonzero_square, r) @@ -1263,7 +1263,7 @@ mod test { fn a_mul_a_vs_a_squared_constant() { let a = FieldElement::from_bytes(&A_BYTES); let asq = FieldElement::from_bytes(&ASQ_BYTES); - assert_eq!(asq, &a*&a); + assert_eq!(asq, &a * &a); } #[test] @@ -1381,7 +1381,7 @@ mod bench { #[bench] fn fieldelement_a_mul_a(b: &mut Bencher) { let a = FieldElement::from_bytes(&A_BYTES); - b.iter(|| &a*&a); + b.iter(|| &a * &a); } #[bench] diff --git a/src/scalar.rs b/src/scalar.rs index 3f4a6cc..ed38c0d 100644 --- a/src/scalar.rs +++ b/src/scalar.rs @@ -63,7 +63,7 @@ impl Debug for Scalar { } } -impl Eq for Scalar{} +impl Eq for Scalar {} impl PartialEq for Scalar { /// Test equality between two `Scalar`s. /// @@ -101,7 +101,7 @@ impl Index for Scalar { impl IndexMut for Scalar { fn index_mut(&mut self, _index: usize) -> &mut u8 { - &mut(self.0[_index]) + &mut (self.0[_index]) } } @@ -151,7 +151,7 @@ impl<'a> Neg for &'a Scalar { type Output = Scalar; fn neg(self) -> Scalar { self * &constants::l_minus_1 - } + } } impl CTAssignable for Scalar { @@ -218,7 +218,7 @@ impl<'de> Deserialize<'de> for Scalar { { if v.len() == 32 { // array_ref turns &[u8] into &[u8;32] - Ok(Scalar(*array_ref!(v,0,32))) + Ok(Scalar(*array_ref!(v, 0, 32))) } else { Err(serde::de::Error::invalid_length(v.len(), &self)) } @@ -270,7 +270,8 @@ 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); Scalar::from_hash(hash) @@ -282,9 +283,10 @@ impl Scalar { /// to stream data into the `Digest` than to pass a single byte /// slice. pub fn from_hash(hash: D) -> Scalar - where D: Digest + Default { + where D: Digest + Default + { // XXX this seems clumsy - let mut output = [0u8;64]; + let mut output = [0u8; 64]; output.copy_from_slice(hash.result().as_slice()); Scalar::reduce(&output) } @@ -320,7 +322,7 @@ impl Scalar { } /// Get the bits of the scalar. - pub fn bits(&self) -> [i8;256] { + 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, @@ -379,7 +381,7 @@ impl Scalar { // Unpack a scalar into 12 21-bit limbs. fn unpack(&self) -> UnpackedScalar { - let mask_21bits: i64 = (1 << 21) -1; + let mask_21bits: i64 = (1 << 21) - 1; let mut a = UnpackedScalar([0i64; 12]); a[ 0] = mask_21bits & load3(&self.0[ 0..]) ; a[ 1] = mask_21bits & (load4(&self.0[ 2..]) >> 5); @@ -504,7 +506,7 @@ impl Index for UnpackedScalar { impl IndexMut for UnpackedScalar { fn index_mut(&mut self, _index: usize) -> &mut i64 { - &mut(self.0[_index]) + &mut (self.0[_index]) } } @@ -616,7 +618,7 @@ impl UnpackedScalar { /// 2^252 = -27742317777372353535851937790883648493 (mod l). /// /// We can write the right-hand side in 21-bit limbs as - /// + /// /// rhs = 666643 * 2^0 /// + 470296 * 2^21 /// + 654183 * 2^42 @@ -640,7 +642,7 @@ impl 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; @@ -662,7 +664,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; @@ -717,7 +719,6 @@ impl UnpackedScalar { UnpackedScalar(*array_ref!(limbs, 0, 12)) } - } #[cfg(test)] @@ -901,7 +902,7 @@ mod bench { #[bench] fn scalar_multiply_add(b: &mut Bencher) { - b.iter(|| Scalar::multiply_add(&X, &Y, &Z) ); + b.iter(|| Scalar::multiply_add(&X, &Y, &Z)); } #[bench] @@ -915,6 +916,6 @@ mod bench { let x = X.unpack(); let y = Y.unpack(); let z = Z.unpack(); - b.iter(|| UnpackedScalar::multiply_add(&x, &y, &z) ); + b.iter(|| UnpackedScalar::multiply_add(&x, &y, &z)); } } diff --git a/src/subtle.rs b/src/subtle.rs index 9770951..5d024bc 100644 --- a/src/subtle.rs +++ b/src/subtle.rs @@ -35,8 +35,7 @@ pub trait CTEq { /// /// Note: it is not necessary to implement this trait, as a generic /// implementation is provided. -pub trait CTNegatable -{ +pub trait CTNegatable { /// Conditionally negate an element if `choice == 1u8`. fn conditional_negate(&mut self, choice: u8); } From 16904432bee939d18542520e33f864231fcc45ce Mon Sep 17 00:00:00 2001 From: Isis Lovecruft Date: Sun, 28 May 2017 22:45:13 +0000 Subject: [PATCH 08/17] Remove an unnecessary explicit return in FieldElement.to_bytes(). --- src/field.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/field.rs b/src/field.rs index 57aae65..e1dda92 100644 --- a/src/field.rs +++ b/src/field.rs @@ -826,7 +826,7 @@ impl FieldElement { debug_assert!((s[31] & 0b1000_0000u8) == 0u8); s[31] &= 127u8; - return s + s } /// Determine if this `FieldElement` is negative, in the sense From c0d3cfc3b76cbba259971e8d5ed5f96dfa06333a Mon Sep 17 00:00:00 2001 From: Isis Lovecruft Date: Fri, 26 May 2017 21:56:11 +0000 Subject: [PATCH 09/17] Whitespace fix in subtle module. From 4ecf6ab326700569bff39be12a01e02b11ab8646 Mon Sep 17 00:00:00 2001 From: Isis Lovecruft Date: Fri, 26 May 2017 22:37:36 +0000 Subject: [PATCH 10/17] Implement constant-time selection between two things. --- Cargo.toml | 6 ++- src/lib.rs | 4 ++ src/subtle.rs | 101 ++++++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 110 insertions(+), 1 deletion(-) diff --git a/Cargo.toml b/Cargo.toml index 500dffb..3ca54f9 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -36,6 +36,10 @@ version = "0.4" # same version that digest depends on version = "^0.6" +[dependencies.num-traits] +optional = true +version = "^0.1" + [dev-dependencies.sha2] version = "0.4" @@ -45,7 +49,7 @@ version = "0.6" [features] nightly = ["radix_51"] default = ["std"] -std = ["rand"] +std = ["rand", "num-traits"] yolocrypto = [] bench = [] # Radix-51 arithmetic using u128 diff --git a/src/lib.rs b/src/lib.rs index 408d7ff..ac8522e 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -13,6 +13,7 @@ #![cfg_attr(not(feature = "std"), feature(collections))] #![cfg_attr(feature = "nightly", feature(i128_type))] #![cfg_attr(feature = "bench", feature(test))] +#![cfg_attr(all(feature = "nightly", feature = "std"), feature(zero_one))] #![allow(unused_features)] #![deny(missing_docs)] // refuse to compile if documentation is missing @@ -58,6 +59,9 @@ extern crate core; #[cfg(feature = "std")] extern crate rand; +#[cfg(feature = "std")] +extern crate num_traits; + #[cfg(not(feature = "std"))] extern crate collections; diff --git a/src/subtle.rs b/src/subtle.rs index 5d024bc..7c98510 100644 --- a/src/subtle.rs +++ b/src/subtle.rs @@ -11,8 +11,23 @@ //! Constant-time traits and utility functions. +#[cfg(feature = "std")] +use core::ops::BitAnd; +#[cfg(feature = "std")] +use core::ops::BitOr; +#[cfg(feature = "std")] +use core::ops::Not; +#[cfg(feature = "std")] +use core::ops::Sub; + use core::ops::Neg; +#[cfg(feature = "std")] +use num_traits::One; +#[cfg(feature = "std")] +use num_traits::Signed; + + /// Trait for items which can be conditionally assigned in constant time. pub trait CTAssignable { /// If `choice == 1u8`, assign `other` to `self`. @@ -50,6 +65,72 @@ impl CTNegatable for T } } +/// Select `a` if `choice == 1` or select `b` if `choice == 0`, in constant time. +/// +/// # Inputs +/// +/// * `a`, `b`, and `choice` must be types for which bitwise-AND, and +/// bitwise-OR, bitwise-complement, subtraction, multiplicative identity, +/// copying, partial equality, and partial order comparison are defined. +/// * `choice`: If `choice` is equal to the multiplicative identity of the type +/// (i.e. `1u8` for `u8`, etc.), then `a` is returned. If `choice` is equal +/// to the additive identity (i.e. `0u8` for `u8`, etc.) then `b` is returned. +/// +/// # Warning +/// +/// The behaviour of this function is undefined if `choice` is something other +/// than a multiplicative identity or additive identity (i.e. `1u8` or `0u8`). +/// +/// If you somehow manage to design a type which is not a signed integer, and +/// yet implements all the requisite trait bounds for this generic, it's your +/// problem if something breaks. +/// +/// # Examples +/// +/// This function should work for signed integer types: +/// +/// ``` +/// # extern crate curve25519_dalek; +/// # use curve25519_dalek::subtle::conditional_select; +/// # fn main() { +/// let a: i32 = 5; +/// let b: i32 = 13; +/// +/// assert!(conditional_select(a, b, 0) == 13); +/// assert!(conditional_select(a, b, 1) == 5); +/// +/// let c: i64 = 2343249123; +/// let d: i64 = 8723884895; +/// +/// assert!(conditional_select(c, d, 0) == d); +/// assert!(conditional_select(c, d, 1) == c); +/// # } +/// ``` +/// +/// It does not work with `i128`s, however, because the `num` crate doesn't +/// implement `num::traits::Signed` for `i128`. +/// +/// # TODO +/// +/// Once `#[feature(specialization)]` is finished, we should rewrite this. Or +/// find some other way to only implement it for types which we know work +/// correctly. +#[inline(always)] +#[cfg(feature = "std")] +pub fn conditional_select(a: T, b: T, choice: T) -> T + where T: PartialEq + + PartialOrd + + One + + Copy + + Signed + + Sub + + BitAnd + + BitOr + + Not +{ + (!(choice - T::one()) & a) | ((choice - T::one()) & b) +} + /// Check equality of two bytes in constant time. /// /// # Return @@ -163,4 +244,24 @@ mod test { assert!(arrays_equal(&a, &b) == 1); } + + #[test] + #[cfg(feature = "std")] + fn conditional_select_i32() { + let a: i32 = 5; + let b: i32 = 13; + + assert_eq!(conditional_select(a, b, 0), 13); + assert_eq!(conditional_select(a, b, 1), 5); + } + + #[test] + #[cfg(feature = "std")] + fn conditional_select_i64() { + let c: i64 = 2343249123; + let d: i64 = 8723884895; + + assert_eq!(conditional_select(c, d, 0), d); + assert_eq!(conditional_select(c, d, 1), c); + } } From 43481a9ff65135736ced32cb7cac4e8c5891b008 Mon Sep 17 00:00:00 2001 From: Isis Lovecruft Date: Sun, 28 May 2017 02:35:48 +0000 Subject: [PATCH 11/17] Change the whitespace because Boats made fun of it on twitter. --- src/subtle.rs | 13 +++---------- 1 file changed, 3 insertions(+), 10 deletions(-) diff --git a/src/subtle.rs b/src/subtle.rs index 7c98510..a81b3e2 100644 --- a/src/subtle.rs +++ b/src/subtle.rs @@ -118,16 +118,9 @@ impl CTNegatable for T #[inline(always)] #[cfg(feature = "std")] pub fn conditional_select(a: T, b: T, choice: T) -> T - where T: PartialEq + - PartialOrd + - One + - Copy + - Signed + - Sub + - BitAnd + - BitOr + - Not -{ + where T: PartialEq + PartialOrd + Copy + + One + Signed + Sub + Not + + BitAnd + BitOr { (!(choice - T::one()) & a) | ((choice - T::one()) & b) } From 161c0cd96dc9ca65c7643063aedac3c256d53f36 Mon Sep 17 00:00:00 2001 From: Isis Lovecruft Date: Mon, 29 May 2017 00:56:57 +0000 Subject: [PATCH 12/17] Add a doctest for subtle::bytes_equal(). --- src/subtle.rs | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/src/subtle.rs b/src/subtle.rs index a81b3e2..b29b635 100644 --- a/src/subtle.rs +++ b/src/subtle.rs @@ -129,6 +129,20 @@ pub fn conditional_select(a: T, b: T, choice: T) -> T /// # Return /// /// Returns `1u8` if `a == b` and `0u8` otherwise. +/// +/// # Examples +/// +/// ``` +/// # extern crate curve25519_dalek; +/// # use curve25519_dalek::subtle::bytes_equal; +/// # fn main() { +/// let a: u8 = 0xDE; +/// let b: u8 = 0xAD; +/// +/// assert_eq!(bytes_equal(a, b), 0); +/// assert_eq!(bytes_equal(a, a), 1); +/// # } +/// ``` #[inline(always)] pub fn bytes_equal(a: u8, b: u8) -> u8 { let mut x: u8; From 4bcf8bed9d48d35f52a10d4623e410a56fbe83ef Mon Sep 17 00:00:00 2001 From: Isis Lovecruft Date: Wed, 31 May 2017 04:37:16 +0000 Subject: [PATCH 13/17] Move subtle to its own crate. --- Cargo.toml | 9 +- src/decaf.rs | 8 +- src/field.rs | 12 ++- src/lib.rs | 7 +- src/scalar.rs | 6 +- src/subtle.rs | 274 -------------------------------------------------- 6 files changed, 28 insertions(+), 288 deletions(-) delete mode 100644 src/subtle.rs diff --git a/Cargo.toml b/Cargo.toml index 3ca54f9..4d195cb 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -32,14 +32,13 @@ version = "0.3" [dependencies.digest] version = "0.4" +[dependencies.subtle] +version = "^0.1" + [dependencies.generic-array] # same version that digest depends on version = "^0.6" -[dependencies.num-traits] -optional = true -version = "^0.1" - [dev-dependencies.sha2] version = "0.4" @@ -49,7 +48,7 @@ version = "0.6" [features] nightly = ["radix_51"] default = ["std"] -std = ["rand", "num-traits"] +std = ["rand"] yolocrypto = [] bench = [] # Radix-51 arithmetic using u128 diff --git a/src/decaf.rs b/src/decaf.rs index 08abe89..2b489b0 100644 --- a/src/decaf.rs +++ b/src/decaf.rs @@ -620,10 +620,15 @@ impl CTAssignable for DecafPoint { /// # Example /// /// ``` + /// # extern crate subtle; + /// # extern crate curve25519_dalek; + /// # + /// # use subtle::CTAssignable; + /// # /// # use curve25519_dalek::curve::Identity; /// # use curve25519_dalek::decaf::DecafPoint; - /// # use curve25519_dalek::subtle::CTAssignable; /// # use curve25519_dalek::constants; + /// # fn main() { /// let A = DecafPoint::identity(); /// let B = constants::DECAF_ED25519_BASEPOINT; /// @@ -633,6 +638,7 @@ impl CTAssignable for DecafPoint { /// 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); diff --git a/src/field.rs b/src/field.rs index e1dda92..bcf8d17 100644 --- a/src/field.rs +++ b/src/field.rs @@ -340,25 +340,33 @@ impl CTAssignable for FieldElement { /// If `choice == 0`, replace `self` with `self`: /// /// ``` + /// # extern crate subtle; + /// # extern crate curve25519_dalek; /// # use curve25519_dalek::field::FieldElement; - /// # use curve25519_dalek::subtle::CTAssignable; + /// # use subtle::CTAssignable; + /// # fn main() { /// let f = FieldElement([1,1,1,1,1,1,1,1,1,1]); /// let g = FieldElement([2,2,2,2,2,2,2,2,2,2]); /// let mut h = FieldElement([1,1,1,1,1,1,1,1,1,1]); /// h.conditional_assign(&g, 0); /// assert!(h == f); + /// # } /// ``` /// /// If `choice == 1`, replace `self` with `f`: /// /// ``` + /// # extern crate subtle; + /// # extern crate curve25519_dalek; /// # use curve25519_dalek::field::FieldElement; - /// # use curve25519_dalek::subtle::CTAssignable; + /// # use subtle::CTAssignable; + /// # fn main() { /// # let f = FieldElement([1,1,1,1,1,1,1,1,1,1]); /// # let g = FieldElement([2,2,2,2,2,2,2,2,2,2]); /// # let mut h = FieldElement([1,1,1,1,1,1,1,1,1,1]); /// h.conditional_assign(&g, 1); /// assert!(h == g); + /// # } /// ``` /// /// # Preconditions diff --git a/src/lib.rs b/src/lib.rs index ac8522e..2a15780 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -47,6 +47,7 @@ extern crate arrayref; extern crate generic_array; extern crate digest; +extern crate subtle; #[cfg(feature = "serde")] extern crate serde; @@ -59,9 +60,6 @@ extern crate core; #[cfg(feature = "std")] extern crate rand; -#[cfg(feature = "std")] -extern crate num_traits; - #[cfg(not(feature = "std"))] extern crate collections; @@ -75,9 +73,8 @@ pub mod curve; #[cfg(feature = "yolocrypto")] pub mod decaf; -// Constant-time functions and other miscelaneous utilities. +// Other miscelaneous utilities. -pub mod subtle; pub mod utils; // Low-level curve and point constants, as well as pre-computed curve group elements. diff --git a/src/scalar.rs b/src/scalar.rs index ed38c0d..e8beab7 100644 --- a/src/scalar.rs +++ b/src/scalar.rs @@ -158,8 +158,11 @@ impl CTAssignable for Scalar { /// Conditionally assign another Scalar to this one. /// /// ``` + /// # extern crate curve25519_dalek; + /// # extern crate subtle; /// # use curve25519_dalek::scalar::Scalar; - /// # use curve25519_dalek::subtle::CTAssignable; + /// # use subtle::CTAssignable; + /// # fn main() { /// let a = Scalar([0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /// 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0]); /// let b = Scalar([1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, @@ -169,6 +172,7 @@ impl CTAssignable for Scalar { /// assert!(t[0] == a[0]); /// t.conditional_assign(&b, 1u8); /// assert!(t[0] == b[0]); + /// # } /// ``` /// /// # Preconditions diff --git a/src/subtle.rs b/src/subtle.rs deleted file mode 100644 index b29b635..0000000 --- a/src/subtle.rs +++ /dev/null @@ -1,274 +0,0 @@ -// -*- mode: rust; -*- -// -// To the extent possible under law, the authors have waived all copyright and -// related or neighboring rights to curve25519-dalek, using the Creative -// Commons "CC0" public domain dedication. See -// for full details. -// -// Authors: -// - Isis Agora Lovecruft -// - Henry de Valence - -//! Constant-time traits and utility functions. - -#[cfg(feature = "std")] -use core::ops::BitAnd; -#[cfg(feature = "std")] -use core::ops::BitOr; -#[cfg(feature = "std")] -use core::ops::Not; -#[cfg(feature = "std")] -use core::ops::Sub; - -use core::ops::Neg; - -#[cfg(feature = "std")] -use num_traits::One; -#[cfg(feature = "std")] -use num_traits::Signed; - - -/// Trait for items which can be conditionally assigned in constant time. -pub trait CTAssignable { - /// If `choice == 1u8`, assign `other` to `self`. - /// Otherwise, leave `self` unchanged. - /// Executes in constant time. - fn conditional_assign(&mut self, other: &Self, choice: u8); -} - -/// Trait for items whose equality to another item may be tested in constant time. -pub trait CTEq { - /// Determine if two items are equal in constant time. - /// - /// # Returns - /// - /// `1u8` if the two items are equal, and `0u8` otherwise. - fn ct_eq(&self, other: &Self) -> u8; -} - -/// Trait for items which can be conditionally negated in constant time. -/// -/// Note: it is not necessary to implement this trait, as a generic -/// implementation is provided. -pub trait CTNegatable { - /// Conditionally negate an element if `choice == 1u8`. - fn conditional_negate(&mut self, choice: u8); -} - -impl CTNegatable for T - where T: CTAssignable, for<'a> &'a T: Neg -{ - fn conditional_negate(&mut self, choice: u8) { - // Need to cast to eliminate mutability - let self_neg: T = -(self as &T); - self.conditional_assign(&self_neg, choice); - } -} - -/// Select `a` if `choice == 1` or select `b` if `choice == 0`, in constant time. -/// -/// # Inputs -/// -/// * `a`, `b`, and `choice` must be types for which bitwise-AND, and -/// bitwise-OR, bitwise-complement, subtraction, multiplicative identity, -/// copying, partial equality, and partial order comparison are defined. -/// * `choice`: If `choice` is equal to the multiplicative identity of the type -/// (i.e. `1u8` for `u8`, etc.), then `a` is returned. If `choice` is equal -/// to the additive identity (i.e. `0u8` for `u8`, etc.) then `b` is returned. -/// -/// # Warning -/// -/// The behaviour of this function is undefined if `choice` is something other -/// than a multiplicative identity or additive identity (i.e. `1u8` or `0u8`). -/// -/// If you somehow manage to design a type which is not a signed integer, and -/// yet implements all the requisite trait bounds for this generic, it's your -/// problem if something breaks. -/// -/// # Examples -/// -/// This function should work for signed integer types: -/// -/// ``` -/// # extern crate curve25519_dalek; -/// # use curve25519_dalek::subtle::conditional_select; -/// # fn main() { -/// let a: i32 = 5; -/// let b: i32 = 13; -/// -/// assert!(conditional_select(a, b, 0) == 13); -/// assert!(conditional_select(a, b, 1) == 5); -/// -/// let c: i64 = 2343249123; -/// let d: i64 = 8723884895; -/// -/// assert!(conditional_select(c, d, 0) == d); -/// assert!(conditional_select(c, d, 1) == c); -/// # } -/// ``` -/// -/// It does not work with `i128`s, however, because the `num` crate doesn't -/// implement `num::traits::Signed` for `i128`. -/// -/// # TODO -/// -/// Once `#[feature(specialization)]` is finished, we should rewrite this. Or -/// find some other way to only implement it for types which we know work -/// correctly. -#[inline(always)] -#[cfg(feature = "std")] -pub fn conditional_select(a: T, b: T, choice: T) -> T - where T: PartialEq + PartialOrd + Copy + - One + Signed + Sub + Not + - BitAnd + BitOr { - (!(choice - T::one()) & a) | ((choice - T::one()) & b) -} - -/// Check equality of two bytes in constant time. -/// -/// # Return -/// -/// Returns `1u8` if `a == b` and `0u8` otherwise. -/// -/// # Examples -/// -/// ``` -/// # extern crate curve25519_dalek; -/// # use curve25519_dalek::subtle::bytes_equal; -/// # fn main() { -/// let a: u8 = 0xDE; -/// let b: u8 = 0xAD; -/// -/// assert_eq!(bytes_equal(a, b), 0); -/// assert_eq!(bytes_equal(a, a), 1); -/// # } -/// ``` -#[inline(always)] -pub fn bytes_equal(a: u8, b: u8) -> u8 { - let mut x: u8; - - x = !(a ^ b); - x &= x >> 4; - x &= x >> 2; - x &= x >> 1; - x -} - -/// Test if a byte is non-zero in constant time. -/// -/// ``` -/// # extern crate curve25519_dalek; -/// # use curve25519_dalek::subtle::byte_is_nonzero; -/// # fn main() { -/// let mut x: u8; -/// x = 0; -/// assert!(byte_is_nonzero(x) == 0); -/// x = 3; -/// assert!(byte_is_nonzero(x) == 1); -/// # } -/// ``` -/// -/// # Return -/// -/// * If b != 0, returns 1u8. -/// * If b == 0, returns 0u8. -#[inline(always)] -pub fn byte_is_nonzero(b: u8) -> u8 { - let mut x = b; - x |= x >> 4; - x |= x >> 2; - x |= x >> 1; - (x & 1) -} - -/// Check equality of two arrays, `a` and `b`, in constant time. -/// -/// There is an `assert!` that the two arrays are of equal length. For -/// example, the following code will panic: -/// -/// ```rust,ignore -/// let a: [u8; 3] = [0, 0, 0]; -/// let b: [u8; 4] = [0, 0, 0, 0]; -/// -/// assert!(arrays_equal(&a, &b) == 1); -/// ``` -/// -/// However, if the arrays are equal length, but their contents do *not* match, -/// `0u8` will be returned: -/// -/// ``` -/// # extern crate curve25519_dalek; -/// # use curve25519_dalek::subtle::arrays_equal; -/// # fn main() { -/// let a: [u8; 3] = [0, 1, 2]; -/// let b: [u8; 3] = [1, 2, 3]; -/// -/// assert!(arrays_equal(&a, &b) == 0); -/// # } -/// ``` -/// -/// And finally, if the contents *do* match, `1u8` is returned: -/// -/// ``` -/// # extern crate curve25519_dalek; -/// # use curve25519_dalek::subtle::arrays_equal; -/// # fn main() { -/// let a: [u8; 3] = [0, 1, 2]; -/// let b: [u8; 3] = [0, 1, 2]; -/// -/// assert!(arrays_equal(&a, &b) == 1); -/// # } -/// ``` -/// -/// This function is commonly used in various cryptographic applications, such -/// as [signature verification](https://github.com/isislovecruft/ed25519-dalek/blob/0.3.2/src/ed25519.rs#L280), -/// among many other applications. -/// -/// # Return -/// -/// Returns `1u8` if `a == b` and `0u8` otherwise. -#[inline(always)] -pub fn arrays_equal(a: &[u8], b: &[u8]) -> u8 { - assert_eq!(a.len(), b.len()); - - let mut x: u8 = 0; - - for i in 0 .. a.len() { - x |= a[i] ^ b[i]; - } - bytes_equal(x, 0) -} - -#[cfg(test)] -mod test { - use super::*; - - #[test] - #[should_panic] - fn arrays_equal_different_lengths() { - let a: [u8; 3] = [0, 0, 0]; - let b: [u8; 4] = [0, 0, 0, 0]; - - assert!(arrays_equal(&a, &b) == 1); - } - - #[test] - #[cfg(feature = "std")] - fn conditional_select_i32() { - let a: i32 = 5; - let b: i32 = 13; - - assert_eq!(conditional_select(a, b, 0), 13); - assert_eq!(conditional_select(a, b, 1), 5); - } - - #[test] - #[cfg(feature = "std")] - fn conditional_select_i64() { - let c: i64 = 2343249123; - let d: i64 = 8723884895; - - assert_eq!(conditional_select(c, d, 0), d); - assert_eq!(conditional_select(c, d, 1), c); - } -} From d9742c2367d0a576960a800a563b27498abeff6b Mon Sep 17 00:00:00 2001 From: Tony Arcieri Date: Mon, 19 Jun 2017 16:59:45 -0700 Subject: [PATCH 14/17] Switch from libcollections to liballoc (gated on an "alloc" feature) libcollections was recently merged into liballoc: https://github.com/rust-lang/rust/pull/42648 I went ahead and also added an "alloc" feature which no_std users can use to opt into liballoc features (i.e. any code using Vec). This should have no effect on anything but no_std usage. It does make it possible for people without allocators to use curve25519-dalek if they want though. Might be nice for "bare metal" development. All that said, from what I can gather liballoc, while not "stable", should likely stick around for the forseeable future. Some backstory on the liballoc/libcollections merge here: https://github.com/rust-lang/rust/pull/42565 --- .travis.yml | 2 ++ Cargo.toml | 1 + src/curve.rs | 5 +++-- src/lib.rs | 6 +++--- 4 files changed, 9 insertions(+), 5 deletions(-) diff --git a/.travis.yml b/.travis.yml index af16309..6a3e92b 100644 --- a/.travis.yml +++ b/.travis.yml @@ -37,6 +37,8 @@ matrix: env: TEST_COMMAND=build EXTRA_FLAGS=--no-default-features FEATURES='' - rust: beta env: TEST_COMMAND=build EXTRA_FLAGS=--no-default-features FEATURES='' + - rust: nightly + env: TEST_COMMAND=build EXTRA_FLAGS=--no-default-features FEATURES='alloc' script: - cargo $TEST_COMMAND --features="$FEATURES" $EXTRA_FLAGS diff --git a/Cargo.toml b/Cargo.toml index 500dffb..772eab3 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -46,6 +46,7 @@ version = "0.6" nightly = ["radix_51"] default = ["std"] std = ["rand"] +alloc = [] yolocrypto = [] bench = [] # Radix-51 arithmetic using u128 diff --git a/src/curve.rs b/src/curve.rs index cc1cfc8..59cb0f3 100644 --- a/src/curve.rs +++ b/src/curve.rs @@ -77,8 +77,8 @@ // affine and projective cakes and eat both of them too. #![allow(non_snake_case)] -#[cfg(not(feature = "std"))] -use collections::Vec; +#[cfg(feature = "alloc")] +use alloc::Vec; use core::fmt::Debug; use core::iter::Iterator; @@ -1195,6 +1195,7 @@ 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. + #[cfg(any(feature = "alloc", feature = "std"))] pub fn k_fold_scalar_mult<'a,'b,I,J>(scalars: I, points: J) -> ExtendedPoint where I: IntoIterator, J: IntoIterator { diff --git a/src/lib.rs b/src/lib.rs index 408d7ff..e96b115 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -10,7 +10,7 @@ // - Henry de Valence #![cfg_attr(not(feature = "std"), no_std)] -#![cfg_attr(not(feature = "std"), feature(collections))] +#![cfg_attr(feature = "alloc", feature(alloc))] #![cfg_attr(feature = "nightly", feature(i128_type))] #![cfg_attr(feature = "bench", feature(test))] @@ -58,8 +58,8 @@ extern crate core; #[cfg(feature = "std")] extern crate rand; -#[cfg(not(feature = "std"))] -extern crate collections; +#[cfg(feature = "alloc")] +extern crate alloc; // Modules for low-level operations directly on field elements and curve points. From 74b80b227ee261a2588694cbfb296bf5018a320d Mon Sep 17 00:00:00 2001 From: Michael Rosenberg Date: Mon, 26 Jun 2017 10:20:07 -0400 Subject: [PATCH 15/17] Update sha2 and digest deps --- Cargo.toml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 500dffb..01bf2b3 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -30,14 +30,14 @@ optional = true version = "0.3" [dependencies.digest] -version = "0.4" +version = "0.6" [dependencies.generic-array] # same version that digest depends on version = "^0.6" [dev-dependencies.sha2] -version = "0.4" +version = "0.6" [dev-dependencies.serde_cbor] version = "0.6" From d7b33297804d5510af9d940b901a0bb9ebd1a6b3 Mon Sep 17 00:00:00 2001 From: Isis Lovecruft Date: Mon, 26 Jun 2017 20:27:22 +0000 Subject: [PATCH 16/17] Bump curve25519-dalek version to 0.9.1. --- Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Cargo.toml b/Cargo.toml index 6f18bb5..07dd5d9 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "curve25519-dalek" -version = "0.9.0" +version = "0.9.1" authors = ["Isis Lovecruft ", "Henry de Valence "] readme = "README.md" From 8374fa300027d0d9c766e024c6aee59a4db05b25 Mon Sep 17 00:00:00 2001 From: Isis Lovecruft Date: Mon, 26 Jun 2017 20:31:37 +0000 Subject: [PATCH 17/17] Bump generic-array version to ^0.8. --- Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Cargo.toml b/Cargo.toml index 07dd5d9..7a25c98 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -37,7 +37,7 @@ version = "^0.1" [dependencies.generic-array] # same version that digest depends on -version = "^0.6" +version = "^0.8" [dev-dependencies.sha2] version = "0.6"