From 4d6e5e304cf84b81f0e666b089d817be48f0557a Mon Sep 17 00:00:00 2001 From: Isis Lovecruft Date: Fri, 26 May 2017 20:09:58 +0000 Subject: [PATCH 1/7] Bump curve25519-dalek version to 0.9.0. --- Cargo.toml | 2 +- README.md | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 3c10672..500dffb 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "curve25519-dalek" -version = "0.8.1" +version = "0.9.0" authors = ["Isis Lovecruft ", "Henry de Valence "] readme = "README.md" diff --git a/README.md b/README.md index 7258558..7954ab1 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.8" + curve25519-dalek = "^0.9" Then, in your library or executable source, add: From 1d189562862b6214ed4dcba4edf88237c7f78703 Mon Sep 17 00:00:00 2001 From: Isis Lovecruft Date: Fri, 26 May 2017 20:14:55 +0000 Subject: [PATCH 2/7] Make badges in README be links. --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 7954ab1..c1b783c 100644 --- a/README.md +++ b/README.md @@ -1,5 +1,5 @@ -# curve25519-dalek ![](https://img.shields.io/crates/v/curve25519-dalek.svg) ![](https://docs.rs/curve25519-dalek/badge.svg) ![](https://travis-ci.org/isislovecruft/curve25519-dalek.svg?branch=master) +# curve25519-dalek [![](https://img.shields.io/crates/v/curve25519-dalek.svg)](https://crates.io/curve25519-dalek) [![](https://docs.rs/curve25519-dalek/badge.svg)](https://docs.rs/curve25519-dalek) [![](https://travis-ci.org/isislovecruft/curve25519-dalek.svg?branch=master)](https://travis-ci.org/isislovecruft/curve25519-dalek) **A low-level cryptographic library for point, group, field, and scalar operations on a curve isomorphic to the twisted Edwards curve defined by -x²+y² From 994a70b071ef88181b7bff448509f797ff39f196 Mon Sep 17 00:00:00 2001 From: Isis Lovecruft Date: Fri, 26 May 2017 20:16:30 +0000 Subject: [PATCH 3/7] Remove the TODO for serde. --- README.md | 1 - 1 file changed, 1 deletion(-) diff --git a/README.md b/README.md index c1b783c..c66e519 100644 --- a/README.md +++ b/README.md @@ -57,7 +57,6 @@ fast. ## TODO * Implement hashing to a point on the curve (Elligator). -* Maybe use serde for serialization. * Make a new `mask` type in `subtle.rs` and return that instead of `u8`s. * Implement all utilities in Golang's `crypto/subtle` package, and move the module to its own crate. From a12c2979fb5f14fe07189cc5a476f65061797d46 Mon Sep 17 00:00:00 2001 From: Isis Lovecruft Date: Fri, 26 May 2017 20:53:18 +0000 Subject: [PATCH 4/7] Fix the doctest for byte_is_nonzero. --- src/subtle.rs | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/src/subtle.rs b/src/subtle.rs index 098733f..d1f3241 100644 --- a/src/subtle.rs +++ b/src/subtle.rs @@ -69,12 +69,16 @@ pub fn bytes_equal_ct(a: u8, b: u8) -> u8 { /// Test if a byte is non-zero in constant time. /// -/// ```rust,ignore +/// ``` +/// # extern crate curve25519_dalek; +/// # use curve25519_dalek::subtle::byte_is_nonzero; +/// # fn main() { /// let mut x: u8; /// x = 0; -/// assert!(byte_is_nonzero(x)); +/// assert!(byte_is_nonzero(x) == 0); /// x = 3; /// assert!(byte_is_nonzero(x) == 1); +/// # } /// ``` /// /// # Return From e74be0024d6b173639811df76d66454d1d074863 Mon Sep 17 00:00:00 2001 From: Isis Lovecruft Date: Fri, 26 May 2017 21:22:31 +0000 Subject: [PATCH 5/7] Better documentation for arrays_equal_ct. --- src/subtle.rs | 31 +++++++++++++++++++++++++++++++ 1 file changed, 31 insertions(+) diff --git a/src/subtle.rs b/src/subtle.rs index d1f3241..203c1c5 100644 --- a/src/subtle.rs +++ b/src/subtle.rs @@ -96,6 +96,37 @@ pub fn byte_is_nonzero(b: u8) -> u8 { /// Check equality of two 32-byte arrays in constant time. /// +/// If the contents of the arrays do *not* match, +/// `0u8` will be returned: +/// +/// ``` +/// # extern crate curve25519_dalek; +/// # use curve25519_dalek::subtle::arrays_equal_ct; +/// # fn main() { +/// let a: [u8; 3] = [0, 1, 2]; +/// let b: [u8; 3] = [1, 2, 3]; +/// +/// assert!(arrays_equal_ct(&a, &b) == 0); +/// # } +/// ``` +/// +/// If the contents *do* match, `1u8` is returned: +/// +/// ``` +/// # extern crate curve25519_dalek; +/// # use curve25519_dalek::subtle::arrays_equal_ct; +/// # fn main() { +/// let a: [u8; 3] = [0, 1, 2]; +/// let b: [u8; 3] = [0, 1, 2]; +/// +/// assert!(arrays_equal_ct(&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. From 0c3871834671d23b986367500b88578225a205aa Mon Sep 17 00:00:00 2001 From: Isis Lovecruft Date: Fri, 26 May 2017 21:25:31 +0000 Subject: [PATCH 6/7] Rename subtle::arrays_equal_ct() to subtle::arrays_equal(). It's already obvious that it's constant-time because it's in the subtle module. --- src/curve.rs | 6 +++--- src/field.rs | 4 ++-- src/scalar.rs | 6 +++--- src/subtle.rs | 10 +++++----- 4 files changed, 13 insertions(+), 13 deletions(-) diff --git a/src/curve.rs b/src/curve.rs index 9987f73..cc1cfc8 100644 --- a/src/curve.rs +++ b/src/curve.rs @@ -90,7 +90,7 @@ use core::ops::Index; use constants; use field::FieldElement; use scalar::Scalar; -use subtle::arrays_equal_ct; +use subtle::arrays_equal; use subtle::bytes_equal_ct; use subtle::CTAssignable; use subtle::CTEq; @@ -518,8 +518,8 @@ impl CTAssignable for ExtendedPoint { impl CTEq for ExtendedPoint { fn ct_eq(&self, other: &ExtendedPoint) -> u8 { - arrays_equal_ct( self.compress_edwards().as_bytes(), - other.compress_edwards().as_bytes()) + arrays_equal( self.compress_edwards().as_bytes(), + other.compress_edwards().as_bytes()) } } diff --git a/src/field.rs b/src/field.rs index 2d43545..ef36f28 100644 --- a/src/field.rs +++ b/src/field.rs @@ -23,7 +23,7 @@ use core::ops::{Index, IndexMut}; use core::cmp::{Eq, PartialEq}; use core::ops::Neg; -use subtle::arrays_equal_ct; +use subtle::arrays_equal; use subtle::byte_is_nonzero; use subtle::CTAssignable; use subtle::CTEq; @@ -96,7 +96,7 @@ impl CTEq for FieldElement { /// /// `1u8` if the two `FieldElement`s are equal, and `0u8` otherwise. fn ct_eq(&self, other: &FieldElement) -> u8 { - arrays_equal_ct(&self.to_bytes(), &other.to_bytes()) + arrays_equal(&self.to_bytes(), &other.to_bytes()) } } diff --git a/src/scalar.rs b/src/scalar.rs index 7f90624..3f4a6cc 100644 --- a/src/scalar.rs +++ b/src/scalar.rs @@ -47,7 +47,7 @@ use constants; use utils::{load3, load4}; use subtle::CTAssignable; use subtle::CTEq; -use subtle::arrays_equal_ct; +use subtle::arrays_equal; /// The `Scalar` struct represents an element in ℤ/lℤ, where /// @@ -76,7 +76,7 @@ impl PartialEq for Scalar { /// /// True if they are equal, and false otherwise. fn eq(&self, other: &Self) -> bool { - arrays_equal_ct(&self.0, &other.0) == 1u8 + arrays_equal(&self.0, &other.0) == 1u8 } } @@ -87,7 +87,7 @@ impl CTEq for Scalar { /// /// `1u8` if they are equal, and `0u8` otherwise. fn ct_eq(&self, other: &Self) -> u8 { - arrays_equal_ct(&self.0, &other.0) + arrays_equal(&self.0, &other.0) } } diff --git a/src/subtle.rs b/src/subtle.rs index 203c1c5..19eebb3 100644 --- a/src/subtle.rs +++ b/src/subtle.rs @@ -101,12 +101,12 @@ pub fn byte_is_nonzero(b: u8) -> u8 { /// /// ``` /// # extern crate curve25519_dalek; -/// # use curve25519_dalek::subtle::arrays_equal_ct; +/// # 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_ct(&a, &b) == 0); +/// assert!(arrays_equal(&a, &b) == 0); /// # } /// ``` /// @@ -114,12 +114,12 @@ pub fn byte_is_nonzero(b: u8) -> u8 { /// /// ``` /// # extern crate curve25519_dalek; -/// # use curve25519_dalek::subtle::arrays_equal_ct; +/// # 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_ct(&a, &b) == 1); +/// assert!(arrays_equal(&a, &b) == 1); /// # } /// ``` /// @@ -131,7 +131,7 @@ pub fn byte_is_nonzero(b: u8) -> u8 { /// /// Returns `1u8` if `a == b` and `0u8` otherwise. #[inline(always)] -pub fn arrays_equal_ct(a: &[u8; 32], b: &[u8; 32]) -> u8 { +pub fn arrays_equal(a: &[u8; 32], b: &[u8; 32]) -> u8 { let mut x: u8 = 0; for i in 0..32 { From 3decdbed0ddf4d8e0f299670a1e3a977bd1a5e72 Mon Sep 17 00:00:00 2001 From: Isis Lovecruft Date: Fri, 26 May 2017 21:28:53 +0000 Subject: [PATCH 7/7] Make arrays_equal() work for any size &[u8], as long as sizes are equal. --- src/subtle.rs | 36 +++++++++++++++++++++++++++++++----- 1 file changed, 31 insertions(+), 5 deletions(-) diff --git a/src/subtle.rs b/src/subtle.rs index 19eebb3..1dd6ba4 100644 --- a/src/subtle.rs +++ b/src/subtle.rs @@ -94,9 +94,19 @@ pub fn byte_is_nonzero(b: u8) -> u8 { (x & 1) } -/// Check equality of two 32-byte arrays in constant time. +/// Check equality of two arrays, `a` and `b`, in constant time. /// -/// If the contents of the arrays do *not* match, +/// There is a `debug_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: /// /// ``` @@ -110,7 +120,7 @@ pub fn byte_is_nonzero(b: u8) -> u8 { /// # } /// ``` /// -/// If the contents *do* match, `1u8` is returned: +/// And finally, if the contents *do* match, `1u8` is returned: /// /// ``` /// # extern crate curve25519_dalek; @@ -131,11 +141,27 @@ pub fn byte_is_nonzero(b: u8) -> u8 { /// /// Returns `1u8` if `a == b` and `0u8` otherwise. #[inline(always)] -pub fn arrays_equal(a: &[u8; 32], b: &[u8; 32]) -> u8 { +pub fn arrays_equal(a: &[u8], b: &[u8]) -> u8 { + debug_assert!(a.len() == b.len()); + let mut x: u8 = 0; - for i in 0..32 { + for i in 0 .. a.len() { x |= a[i] ^ b[i]; } bytes_equal_ct(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); + } +}