From 313607f06ac439cb1f5d277f021a6b9931921af2 Mon Sep 17 00:00:00 2001 From: Isis Lovecruft Date: Thu, 30 Nov 2017 22:04:47 +0000 Subject: [PATCH 1/7] Remove decaf fuzzer and change scalar fuzzer. * REMOVE fuzz/fuzz_targets/decaf.rs * RENAME fuzz/fuzz_targets/scalar_constructor_accepts_256bit_values.rs to fuzz/fuzz_targets/scalar_constructors_and_reduction.rs * CHANGE scalar_constructors_and_reduction fuzz target to test reduction after using the 255-bit constructor versus constructor mod order. * FIXES #91: https://github.com/isislovecruft/curve25519-dalek/issues/91 --- fuzz/Cargo.toml | 4 ---- fuzz/fuzz_targets/decaf.rs | 21 ------------------- ...s => scalar_constructors_and_reduction.rs} | 14 +++++-------- 3 files changed, 5 insertions(+), 34 deletions(-) delete mode 100644 fuzz/fuzz_targets/decaf.rs rename fuzz/fuzz_targets/{scalar_constructor_accepts_256bit_values.rs => scalar_constructors_and_reduction.rs} (63%) diff --git a/fuzz/Cargo.toml b/fuzz/Cargo.toml index ceb067b..0dccf7b 100644 --- a/fuzz/Cargo.toml +++ b/fuzz/Cargo.toml @@ -23,10 +23,6 @@ git = "https://github.com/rust-fuzz/libfuzzer-sys.git" [workspace] members = ["."] -[[bin]] -name = "decaf" -path = "fuzz_targets/decaf.rs" - [[bin]] name = "scalar_constructor_accepts_256bit_values" path = "fuzz_targets/scalar_constructor_accepts_256bit_values.rs" diff --git a/fuzz/fuzz_targets/decaf.rs b/fuzz/fuzz_targets/decaf.rs deleted file mode 100644 index 5199183..0000000 --- a/fuzz/fuzz_targets/decaf.rs +++ /dev/null @@ -1,21 +0,0 @@ -#![no_main] -#[macro_use] extern crate libfuzzer_sys; -extern crate curve25519_dalek; - -use curve25519_dalek::curve::ValidityCheck; -use curve25519_dalek::decaf::DecafPoint; -use curve25519_dalek::field::FieldElement; - -fuzz_target!(|data: &[u8]| { - if data.len() != 32 { - return; - } - let mut field_bytes = [0u8; 32]; - for (by, data) in field_bytes.iter_mut().zip(data.iter()) { - *by = *data; - } - let fe = FieldElement::from_bytes(&field_bytes); - let p = DecafPoint::elligator_decaf_flavour(&fe); - assert!(p.0.is_valid()); - p.compress(); -}); diff --git a/fuzz/fuzz_targets/scalar_constructor_accepts_256bit_values.rs b/fuzz/fuzz_targets/scalar_constructors_and_reduction.rs similarity index 63% rename from fuzz/fuzz_targets/scalar_constructor_accepts_256bit_values.rs rename to fuzz/fuzz_targets/scalar_constructors_and_reduction.rs index 38bba88..fc3eba9 100644 --- a/fuzz/fuzz_targets/scalar_constructor_accepts_256bit_values.rs +++ b/fuzz/fuzz_targets/scalar_constructors_and_reduction.rs @@ -4,10 +4,10 @@ extern crate curve25519_dalek; use curve25519_dalek::scalar::Scalar; -/// Check that the Scalar constructor accepts 256-bit input values and +/// Check that the Scalar constructor accepts 255-bit input values and /// behaves correctly on them. /// -/// Specifically, we take 256-bit values `a` and `b` from the fuzzer +/// Specifically, we take 255-bit values `a` and `b` from the fuzzer /// input data and check that `(a mod l) * (b mod l) == (a * b) mod l`. fuzz_target!(|data: &[u8]| { if data.len() != 64 { @@ -21,15 +21,11 @@ fuzz_target!(|data: &[u8]| { b_bytes.copy_from_slice(&data[32..64]); // Compute c = a*b (mod l) - let c1 = &Scalar(a_bytes) * &Scalar(b_bytes); + let c1 = (&Scalar::from_bits(a_bytes) * &Scalar::from_bits(b_bytes)).reduce(); // Compute c = (a mod l) * (b mod l) - let mut tmp = [0u8; 64]; - tmp[0..32].copy_from_slice(&a_bytes[..]); - let a_mod_l = Scalar::reduce(&tmp); - tmp[0..32].copy_from_slice(&b_bytes[..]); - let b_mod_l = Scalar::reduce(&tmp); - + let a_mod_l = Scalar::from_bytes_mod_order(a_bytes); + let b_mod_l = Scalar::from_bytes_mod_order(b_bytes); let c2 = &a_mod_l * &b_mod_l; assert_eq!(c1, c2); From 6ed4e24ddd77ce3d4201662a0f2161d250bf7422 Mon Sep 17 00:00:00 2001 From: Isis Lovecruft Date: Fri, 1 Dec 2017 01:28:33 +0000 Subject: [PATCH 2/7] Exclude all .gitignore files from all builds. --- Cargo.toml | 1 + 1 file changed, 1 insertion(+) diff --git a/Cargo.toml b/Cargo.toml index f60b8c5..c37a12e 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -12,6 +12,7 @@ categories = ["cryptography", "no-std"] keywords = ["cryptography", "curve25519", "elliptic", "curve", "ECC"] description = "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² = 1 - 121665/121666 x²y² over GF(2²⁵⁵ - 19)." exclude = [ + "**/.gitignore", ".gitignore", ".travis.yml", ] From 27ba42a6eb146e913819bf9ecf89d887e6292d88 Mon Sep 17 00:00:00 2001 From: Isis Lovecruft Date: Sat, 2 Dec 2017 03:19:19 +0000 Subject: [PATCH 3/7] Cleanup code snippets in README. --- README.md | 20 ++++++++++++++++---- 1 file changed, 16 insertions(+), 4 deletions(-) diff --git a/README.md b/README.md index 0e27d0d..7e95f11 100644 --- a/README.md +++ b/README.md @@ -44,22 +44,34 @@ 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.13" +```toml +curve25519-dalek = "^0.13" +``` Then, in your library or executable source, add: - extern crate curve25519_dalek + extern crate curve25519_dalek; + +## Features On nightly Rust, using the `nightly` feature enables a radix-51 field arithmetic implementation using `u128`s, which is approximately twice as -fast. +fast. It will also enable additional developer documentation when +compiling via `make doc-internal`. + +By default, the benchmarks are not compiled without the `bench` +feature. To run the benchmarks, do: + +```sh +cargo bench --features="bench" +``` ## TODO We intend to stabilise the following before curve25519-dalek-1.0.0: * Implement hashing to a point on the curve (Elligator). -* Finish Ristretto (Decaf for curve25519) implementation. +* Finish Ristretto documentation. ## Contributing From c71d41ddcc819a619c697ed5c667b8c42f316cff Mon Sep 17 00:00:00 2001 From: Isis Lovecruft Date: Mon, 4 Dec 2017 01:17:17 +0000 Subject: [PATCH 4/7] Whitespace fixes. --- src/backend/u32/constants.rs | 2 +- src/backend/u32/field.rs | 34 +++++++++++++++++----------------- src/backend/u32/mod.rs | 2 +- src/backend/u64/constants.rs | 2 +- src/backend/u64/field.rs | 4 ++-- src/backend/u64/mod.rs | 6 +++--- src/backend/u64/scalar.rs | 2 +- src/curve_models/mod.rs | 4 ++-- 8 files changed, 28 insertions(+), 28 deletions(-) diff --git a/src/backend/u32/constants.rs b/src/backend/u32/constants.rs index 2600c64..b717dde 100644 --- a/src/backend/u32/constants.rs +++ b/src/backend/u32/constants.rs @@ -97,7 +97,7 @@ pub const ED25519_BASEPOINT_POINT: ExtendedPoint = ExtendedPoint{ /// array is `i*P`, where `P` is a point of order 8 generating Ɛ[8]. /// /// Thus Ɛ[4] is the points indexed by 0,2,4,6 and Ɛ[2] is the points -/// indexed by 0,4. +/// indexed by 0,4. pub const EIGHT_TORSION: [ExtendedPoint; 8] = [ ExtendedPoint{ X: FieldElement32([0, 0, 0, 0, 0, 0, 0, 0, 0, 0]), diff --git a/src/backend/u32/field.rs b/src/backend/u32/field.rs index fb6b36f..a7a6419 100644 --- a/src/backend/u32/field.rs +++ b/src/backend/u32/field.rs @@ -38,11 +38,11 @@ use subtle::ConditionallyAssignable; /// to \\(2\^{25+b}\\) or \\(2\^{26+b}\\), where \\(b = 1.75\\). /// /// # Note -/// +/// /// The `curve25519_dalek::field` module provides a type alias /// `curve25519_dalek::field::FieldElement` to either `FieldElement64` /// or `FieldElement32`. -/// +/// /// The backend-specific type `FieldElement32` should not be used /// outside of the `curve25519_dalek::field` module. #[derive(Copy, Clone)] @@ -133,7 +133,7 @@ impl<'a, 'b> Mul<&'b FieldElement32> for &'a FieldElement32 { let y1_19 = 19 * y[1]; // This fits in a u32 let y2_19 = 19 * y[2]; // iff 26 + b + lg(19) < 32 let y3_19 = 19 * y[3]; // if b < 32 - 26 - 4.248 = 1.752 - let y4_19 = 19 * y[4]; + let y4_19 = 19 * y[4]; let y5_19 = 19 * y[5]; // below, b<2.5: this is a bottleneck, let y6_19 = 19 * y[6]; // could be avoided by promoting to let y7_19 = 19 * y[7]; // u64 here instead of in m() @@ -181,7 +181,7 @@ impl<'a, 'b> Mul<&'b FieldElement32> for &'a FieldElement32 { // How big is the contribution to z[i+j] from x[i], y[j]? // // Using the bounds above, we get: - // + // // i even, j even: x[i]*y[j] < 2^(26+b)*2^(26+b) = 2*2^(51+2*b) // i odd, j even: x[i]*y[j] < 2^(25+b)*2^(26+b) = 1*2^(51+2*b) // i even, j odd: x[i]*y[j] < 2^(26+b)*2^(25+b) = 1*2^(51+2*b) @@ -191,7 +191,7 @@ impl<'a, 'b> Mul<&'b FieldElement32> for &'a FieldElement32 { // (since 2^255 - 19 = 0 mod p). This adds a factor of 19, so // we get the bounds (z0 is the biggest one, but calculated for // posterity here in case finer estimation is needed later): - // + // // z0 < ( 2 + 1*19 + 2*19 + 1*19 + 2*19 + 1*19 + 2*19 + 1*19 + 2*19 + 1*19 )*2^(51 + 2b) = 249*2^(51 + 2*b) // z1 < ( 1 + 1 + 1*19 + 1*19 + 1*19 + 1*19 + 1*19 + 1*19 + 1*19 + 1*19 )*2^(51 + 2b) = 154*2^(51 + 2*b) // z2 < ( 2 + 1 + 2 + 1*19 + 2*19 + 1*19 + 2*19 + 1*19 + 2*19 + 1*19 )*2^(51 + 2b) = 195*2^(51 + 2*b) @@ -232,15 +232,15 @@ impl FieldElement32 { pub fn negate(&mut self) { // Compute -b as ((2^4 * p) - b) to avoid underflow. let neg = FieldElement32::reduce([ - ((0x3ffffed << 4) - self.0[0]) as u64, - ((0x1ffffff << 4) - self.0[1]) as u64, - ((0x3ffffff << 4) - self.0[2]) as u64, - ((0x1ffffff << 4) - self.0[3]) as u64, - ((0x3ffffff << 4) - self.0[4]) as u64, - ((0x1ffffff << 4) - self.0[5]) as u64, - ((0x3ffffff << 4) - self.0[6]) as u64, - ((0x1ffffff << 4) - self.0[7]) as u64, - ((0x3ffffff << 4) - self.0[8]) as u64, + ((0x3ffffed << 4) - self.0[0]) as u64, + ((0x1ffffff << 4) - self.0[1]) as u64, + ((0x3ffffff << 4) - self.0[2]) as u64, + ((0x1ffffff << 4) - self.0[3]) as u64, + ((0x3ffffff << 4) - self.0[4]) as u64, + ((0x1ffffff << 4) - self.0[5]) as u64, + ((0x3ffffff << 4) - self.0[6]) as u64, + ((0x1ffffff << 4) - self.0[7]) as u64, + ((0x3ffffff << 4) - self.0[8]) as u64, ((0x1ffffff << 4) - self.0[9]) as u64, ]); self.0 = neg.0; @@ -298,7 +298,7 @@ impl FieldElement32 { // Since z[3] < 2^64, c < 2^(64-25) = 2^39, // so z[4] < 2^26 + 2^39 < 2^39.0002 carry(&mut z, 4); carry(&mut z, 8); - // Now z[4] < 2^26 + // Now z[4] < 2^26 // and z[5] < 2^25 + 2^13.0002 < 2^25.0004 (good enough) // Last carry has a multiplication by 19: @@ -396,7 +396,7 @@ impl FieldElement32 { const LOW_26_BITS: u32 = (1 << 26) - 1; h[0] += 19*q; - + // Now carry the result to compute r + 19q... h[1] += h[0] >> 26; h[0] = h[0] & LOW_26_BITS; @@ -416,7 +416,7 @@ impl FieldElement32 { h[7] = h[7] & LOW_25_BITS; h[9] += h[8] >> 26; h[8] = h[8] & LOW_26_BITS; - + // ... but instead of carrying the value // (h[9] >> 25) = q*2^255 into another limb, // discard it, subtracting the value from h. diff --git a/src/backend/u32/mod.rs b/src/backend/u32/mod.rs index bd4cb75..bc1148e 100644 --- a/src/backend/u32/mod.rs +++ b/src/backend/u32/mod.rs @@ -9,7 +9,7 @@ // - Henry de Valence //! The `u32` backend uses `u32`s and a `(u32, u32) -> u64` multiplier. -//! +//! //! This code is intended to be portable, but it requires that //! multiplication of two \\(32\\)-bit values to a \\(64\\)-bit result //! is constant-time on the target platform. diff --git a/src/backend/u64/constants.rs b/src/backend/u64/constants.rs index a51ee81..53c2e1c 100644 --- a/src/backend/u64/constants.rs +++ b/src/backend/u64/constants.rs @@ -70,7 +70,7 @@ pub const ED25519_BASEPOINT_POINT: ExtendedPoint = ExtendedPoint{ /// array is `i*P`, where `P` is a point of order 8 generating Ɛ[8]. /// /// Thus Ɛ[4] is the points indexed by 0,2,4,6 and Ɛ[2] is the points -/// indexed by 0,4. +/// indexed by 0,4. pub const EIGHT_TORSION: [ExtendedPoint; 8] = [ ExtendedPoint { X: FieldElement64([0, 0, 0, 0, 0]), diff --git a/src/backend/u64/field.rs b/src/backend/u64/field.rs index e5b152e..70d7fa8 100644 --- a/src/backend/u64/field.rs +++ b/src/backend/u64/field.rs @@ -27,11 +27,11 @@ use subtle::ConditionallyAssignable; /// grow up to \\(2\^{54}\\) between reductions modulo \\(p\\). /// /// # Note -/// +/// /// The `curve25519_dalek::field` module provides a type alias /// `curve25519_dalek::field::FieldElement` to either `FieldElement64` /// or `FieldElement32`. -/// +/// /// The backend-specific type `FieldElement64` should not be used /// outside of the `curve25519_dalek::field` module. #[derive(Copy, Clone)] diff --git a/src/backend/u64/mod.rs b/src/backend/u64/mod.rs index 51980d8..a72dc0f 100644 --- a/src/backend/u64/mod.rs +++ b/src/backend/u64/mod.rs @@ -9,11 +9,11 @@ // - Henry de Valence //! The `u64` backend uses `u64`s and a `(u64, u64) -> u128` multiplier. -//! +//! //! On x86_64, the idiom `(x as u128) * (y as u128)` lowers to `MUL` //! instructions taking 64-bit inputs and producing 128-bit outputs. On -//! other platforms, this implementation is not recommended. -//! +//! other platforms, this implementation is not recommended. +//! //! On Haswell and newer, the BMI2 extension provides `MULX`, and on //! Broadwell and newer, the ADX extension provides `ADCX` and `ADOX` //! (allowing the CPU to compute two carry chains in parallel). These diff --git a/src/backend/u64/scalar.rs b/src/backend/u64/scalar.rs index 12da445..91d4acc 100644 --- a/src/backend/u64/scalar.rs +++ b/src/backend/u64/scalar.rs @@ -16,7 +16,7 @@ use core::ops::{Index, IndexMut}; use constants; -/// The `Scalar64` struct represents an element in +/// The `Scalar64` struct represents an element in /// \\(\mathbb Z / \ell \mathbb Z\\) as 5 \\(52\\)-bit limbs. #[derive(Copy,Clone)] pub struct Scalar64(pub [u64; 5]); diff --git a/src/curve_models/mod.rs b/src/curve_models/mod.rs index ad11a9b..19fc07e 100644 --- a/src/curve_models/mod.rs +++ b/src/curve_models/mod.rs @@ -10,7 +10,7 @@ //! This module contains internal curve representations which are not part //! of the public API. -//! +//! //! # Curve representations //! //! Internally, we use several different models for the curve. Here @@ -62,7 +62,7 @@ //! $$ //! \frac {W\_1} {W\_3} = \frac {XT} {ZT} = \frac X Z = x, //! $$ -//! and +//! and //! $$ //! \frac {W\_2} {W\_3} = \frac {YZ} {ZT} = \frac Y T = y, //! $$ From c4c9775cb2337ade4ff93951406044baf7208b42 Mon Sep 17 00:00:00 2001 From: Isis Lovecruft Date: Mon, 4 Dec 2017 01:19:55 +0000 Subject: [PATCH 5/7] Remove scalar_constructors_and_reduction fuzzer. It doesn't really test anything usefully discoverable since the searchspace is too large. --- .../scalar_constructors_and_reduction.rs | 32 ------------------- 1 file changed, 32 deletions(-) delete mode 100644 fuzz/fuzz_targets/scalar_constructors_and_reduction.rs diff --git a/fuzz/fuzz_targets/scalar_constructors_and_reduction.rs b/fuzz/fuzz_targets/scalar_constructors_and_reduction.rs deleted file mode 100644 index fc3eba9..0000000 --- a/fuzz/fuzz_targets/scalar_constructors_and_reduction.rs +++ /dev/null @@ -1,32 +0,0 @@ -#![no_main] -#[macro_use] extern crate libfuzzer_sys; -extern crate curve25519_dalek; - -use curve25519_dalek::scalar::Scalar; - -/// Check that the Scalar constructor accepts 255-bit input values and -/// behaves correctly on them. -/// -/// Specifically, we take 255-bit values `a` and `b` from the fuzzer -/// input data and check that `(a mod l) * (b mod l) == (a * b) mod l`. -fuzz_target!(|data: &[u8]| { - if data.len() != 64 { - return; - } - let mut a_bytes = [0u8; 32]; - let mut b_bytes = [0u8; 32]; - - // Set a, b to be random 256-bit integers - a_bytes.copy_from_slice(&data[ 0..32]); - b_bytes.copy_from_slice(&data[32..64]); - - // Compute c = a*b (mod l) - let c1 = (&Scalar::from_bits(a_bytes) * &Scalar::from_bits(b_bytes)).reduce(); - - // Compute c = (a mod l) * (b mod l) - let a_mod_l = Scalar::from_bytes_mod_order(a_bytes); - let b_mod_l = Scalar::from_bytes_mod_order(b_bytes); - let c2 = &a_mod_l * &b_mod_l; - - assert_eq!(c1, c2); -}); From d3cf2526372055cb4c384d42b2f09e44c7201292 Mon Sep 17 00:00:00 2001 From: Isis Lovecruft Date: Mon, 4 Dec 2017 01:21:46 +0000 Subject: [PATCH 6/7] Remove unused fuzz/ directory for now. --- fuzz/.gitignore | 4 ---- fuzz/Cargo.toml | 28 ---------------------------- 2 files changed, 32 deletions(-) delete mode 100644 fuzz/.gitignore delete mode 100644 fuzz/Cargo.toml diff --git a/fuzz/.gitignore b/fuzz/.gitignore deleted file mode 100644 index 572e03b..0000000 --- a/fuzz/.gitignore +++ /dev/null @@ -1,4 +0,0 @@ - -target -corpus -artifacts diff --git a/fuzz/Cargo.toml b/fuzz/Cargo.toml deleted file mode 100644 index 0dccf7b..0000000 --- a/fuzz/Cargo.toml +++ /dev/null @@ -1,28 +0,0 @@ - -[package] -name = "curve25519-dalek-fuzz" -version = "0.0.1" -authors = ["Automatically generated"] -publish = false - -[package.metadata] -cargo-fuzz = true - -[dependencies.curve25519-dalek] -path = ".." - -[features] -yolocrypto = ["curve25519-dalek/yolocrypto"] -nightly = ["curve25519-dalek/nightly"] -radix_51 = ["curve25519-dalek/radix_51"] - -[dependencies.libfuzzer-sys] -git = "https://github.com/rust-fuzz/libfuzzer-sys.git" - -# Prevent this from interfering with workspaces -[workspace] -members = ["."] - -[[bin]] -name = "scalar_constructor_accepts_256bit_values" -path = "fuzz_targets/scalar_constructor_accepts_256bit_values.rs" From 209854acc6c7618648840ef96f82276ed6b6ebb1 Mon Sep 17 00:00:00 2001 From: Isis Lovecruft Date: Mon, 4 Dec 2017 02:08:03 +0000 Subject: [PATCH 7/7] Bump curve25519-dalek version to 0.14.0. --- Cargo.toml | 2 +- README.md | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index c37a12e..470d7e5 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "curve25519-dalek" -version = "0.13.2" +version = "0.14.0" authors = ["Isis Lovecruft ", "Henry de Valence "] readme = "README.md" diff --git a/README.md b/README.md index 7e95f11..91f533b 100644 --- a/README.md +++ b/README.md @@ -45,7 +45,7 @@ To install, add the following to the dependencies section of your project's `Cargo.toml`: ```toml -curve25519-dalek = "^0.13" +curve25519-dalek = "^0.14" ``` Then, in your library or executable source, add: