From 617f3186e2c3f95a16e02e80834aab11fafacb42 Mon Sep 17 00:00:00 2001 From: Greg Fitzgerald Date: Wed, 24 Oct 2018 00:00:37 -0600 Subject: [PATCH 01/43] Expose CI failures --- .travis.yml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/.travis.yml b/.travis.yml index 4c8d19e..732228a 100644 --- a/.travis.yml +++ b/.travis.yml @@ -7,14 +7,14 @@ rust: env: - TEST_COMMAND=test FEATURES='' - - TEST_COMMAND=test FEATURES=--features="serde" + - TEST_COMMAND=test FEATURES='--features=serde' matrix: include: - rust: nightly - env: TEST_COMMAND=build FEATURES="--no-default-features --features=u32_backend" + env: TEST_COMMAND=build FEATURES='--no-default-features --features=u32_backend' - rust: nightly - env: TEST_COMMAND=test FEATURES=--features="nightly" + env: TEST_COMMAND=test FEATURES='--features=nightly' script: - cargo $TEST_COMMAND $FEATURES From 82948f0dd6fb966249f1035200b4acf863251cf1 Mon Sep 17 00:00:00 2001 From: Greg Fitzgerald Date: Tue, 23 Oct 2018 22:57:25 -0600 Subject: [PATCH 02/43] Fix serde doc tests And let latest rustfmt reorder imports. --- src/lib.rs | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/lib.rs b/src/lib.rs index 488ea5c..e01e2fd 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -198,11 +198,11 @@ //! # use ed25519_dalek::{Keypair, Signature, PublicKey}; //! use bincode::{serialize, Infinite}; //! # let mut csprng: ChaChaRng = ChaChaRng::from_seed([0u8; 32]); -//! # let keypair: Keypair = Keypair::generate::(&mut csprng); +//! # let keypair: Keypair = Keypair::generate::(&mut csprng); //! # let message: &[u8] = "This is a test of the tsunami alert system.".as_bytes(); //! # let signature: Signature = keypair.sign::(message); //! # let public_key: PublicKey = keypair.public; -//! # let verified: bool = public_key.verify::(message, &signature); +//! # let verified: bool = public_key.verify::(message, &signature).is_ok(); //! //! let encoded_public_key: Vec = serialize(&public_key, Infinite).unwrap(); //! let encoded_signature: Vec = serialize(&signature, Infinite).unwrap(); @@ -232,11 +232,11 @@ //! use bincode::{deserialize}; //! //! # let mut csprng: ChaChaRng = ChaChaRng::from_seed([0u8; 32]); -//! # let keypair: Keypair = Keypair::generate::(&mut csprng); +//! # let keypair: Keypair = Keypair::generate::(&mut csprng); //! let message: &[u8] = "This is a test of the tsunami alert system.".as_bytes(); //! # let signature: Signature = keypair.sign::(message); //! # let public_key: PublicKey = keypair.public; -//! # let verified: bool = public_key.verify::(message, &signature); +//! # let verified: bool = public_key.verify::(message, &signature).is_ok(); //! # let encoded_public_key: Vec = serialize(&public_key, Infinite).unwrap(); //! # let encoded_signature: Vec = serialize(&signature, Infinite).unwrap(); //! let decoded_public_key: PublicKey = deserialize(&encoded_public_key).unwrap(); @@ -245,7 +245,7 @@ //! # assert_eq!(public_key, decoded_public_key); //! # assert_eq!(signature, decoded_signature); //! # -//! let verified: bool = decoded_public_key.verify::(&message, &decoded_signature); +//! let verified: bool = decoded_public_key.verify::(&message, &decoded_signature).is_ok(); //! //! assert!(verified); //! # } @@ -257,10 +257,10 @@ #![allow(unused_features)] #![deny(missing_docs)] // refuse to compile if documentation is missing +extern crate clear_on_drop; extern crate curve25519_dalek; extern crate failure; extern crate rand; -extern crate clear_on_drop; #[cfg(any(feature = "std", test))] #[macro_use] From 680f68be3137ed24d268a73b2978cf97fd734df5 Mon Sep 17 00:00:00 2001 From: Greg Fitzgerald Date: Tue, 23 Oct 2018 23:14:29 -0600 Subject: [PATCH 03/43] Add tests for generic_array serialized size generic_array v0.12 no longer serializes GenericArray as a Vec, which reduces the serialized size of PublicKey, Signature, and SecretKey by 8 bytes. Now that generic_array has been upgraded, these tests simply ensure the serialization size doesn't change in the future. --- src/ed25519.rs | 30 +++++++++++++++++++++++++++++- 1 file changed, 29 insertions(+), 1 deletion(-) diff --git a/src/ed25519.rs b/src/ed25519.rs index 0654eb1..a3b7454 100644 --- a/src/ed25519.rs +++ b/src/ed25519.rs @@ -1629,7 +1629,10 @@ mod test { } #[cfg(all(test, feature = "serde"))] - use bincode::{serialize, deserialize, Infinite}; + use bincode::{serialize, serialized_size, deserialize, Infinite}; + + #[cfg(all(test, feature = "serde"))] + use std::mem::size_of; #[cfg(all(test, feature = "serde"))] #[test] @@ -1660,4 +1663,29 @@ mod test { assert_eq!(SECRET_KEY.0[i], decoded_secret_key.0[i]); } } + + #[cfg(all(test, feature = "serde"))] + #[test] + fn serialize_public_key_size() { + assert_eq!( + serialized_size(&PUBLIC_KEY) as usize, + size_of::() + ); + } + + #[cfg(all(test, feature = "serde"))] + #[test] + fn serialize_signature_size() { + let signature: Signature = Signature::from_bytes(&SIGNATURE_BYTES).unwrap(); + assert_eq!(serialized_size(&signature) as usize, size_of::()); + } + + #[cfg(all(test, feature = "serde"))] + #[test] + fn serialize_secret_key_size() { + assert_eq!( + serialized_size(&SECRET_KEY) as usize, + size_of::() + ); + } } From 42b5d6ada905d949e66d93985fcdd2a2800e3887 Mon Sep 17 00:00:00 2001 From: Colt Frederickson Date: Wed, 17 Oct 2018 10:26:44 -0600 Subject: [PATCH 04/43] Rand 0.6 version bump --- Cargo.toml | 6 ++++-- src/ed25519.rs | 13 +++++++------ src/lib.rs | 28 +++++++++++++++++++++------- 3 files changed, 32 insertions(+), 15 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 9e3e300..09748c0 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -16,11 +16,12 @@ exclude = [ ".gitignore", "TESTVECTORS", "res/*" ] travis-ci = { repository = "dalek-cryptography/ed25519-dalek", branch = "master"} [dependencies.curve25519-dalek] -version = "1.0.0-pre.0" +git = "https://github.com/IronCoreLabs/curve25519-dalek.git" +branch = "rand-0.6" default-features = false [dependencies.rand] -version = "0.5" +version = "0.6.0" default-features = false features = ["i128_support"] @@ -44,6 +45,7 @@ hex = "^0.3" sha2 = "^0.8" bincode = "^0.9" criterion = "0.2" +rand_chacha = "0.1.0" [[bench]] name = "ed25519_benchmarks" diff --git a/src/ed25519.rs b/src/ed25519.rs index 0654eb1..6c119a7 100644 --- a/src/ed25519.rs +++ b/src/ed25519.rs @@ -281,13 +281,14 @@ impl SecretKey { /// /// ``` /// # extern crate rand; + /// # extern crate rand_chacha; /// # extern crate sha2; /// # extern crate ed25519_dalek; /// # /// # fn main() { /// # /// # use rand::Rng; - /// # use rand::ChaChaRng; + /// # use rand_chacha::ChaChaRng; /// # use rand::SeedableRng; /// # use sha2::Sha512; /// # use ed25519_dalek::PublicKey; @@ -307,7 +308,7 @@ impl SecretKey { /// /// # Input /// - /// A CSPRNG with a `fill_bytes()` method, e.g. `rand::ChaChaRng` + /// A CSPRNG with a `fill_bytes()` method, e.g. `rand_chacha::ChaChaRng` pub fn generate(csprng: &mut T) -> SecretKey where T: CryptoRng + Rng, { @@ -939,7 +940,7 @@ impl From for PublicKey { /// use ed25519_dalek::PublicKey; /// use ed25519_dalek::Signature; /// use rand::thread_rng; -/// use rand::ThreadRng; +/// use rand::rngs::ThreadRng; /// use sha2::Sha512; /// /// # fn main() { @@ -1135,7 +1136,7 @@ impl Keypair { /// /// # Input /// - /// A CSPRNG with a `fill_bytes()` method, e.g. `rand::ChaChaRng`. + /// A CSPRNG with a `fill_bytes()` method, e.g. `rand_chacha::ChaChaRng`. /// /// The caller must also supply a hash function which implements the /// `Digest` and `Default` traits, and which returns 512 bits of output. @@ -1380,9 +1381,9 @@ mod test { use std::string::String; use std::vec::Vec; use rand::thread_rng; - use rand::ChaChaRng; + use rand_chacha::ChaChaRng; use rand::SeedableRng; - use rand::ThreadRng; + use rand::rngs::ThreadRng; use hex::FromHex; use sha2::Sha512; use super::*; diff --git a/src/lib.rs b/src/lib.rs index 488ea5c..a37b964 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -44,11 +44,12 @@ //! //! ``` //! # extern crate rand; +//! # extern crate rand_chacha; //! # extern crate sha2; //! # extern crate ed25519_dalek; //! # fn main() { //! # use rand::Rng; -//! # use rand::ChaChaRng; +//! # use rand_chacha::ChaChaRng; //! # use rand::SeedableRng; //! # use sha2::Sha512; //! # use ed25519_dalek::Keypair; @@ -67,9 +68,10 @@ //! # extern crate rand; //! # extern crate sha2; //! # extern crate ed25519_dalek; +//! # extern crate rand_chacha; //! # fn main() { //! # use rand::Rng; -//! # use rand::ChaChaRng; +//! # use rand_chacha::ChaChaRng; //! # use rand::SeedableRng; //! # use sha2::Sha512; //! # use ed25519_dalek::Keypair; @@ -89,9 +91,10 @@ //! # extern crate rand; //! # extern crate sha2; //! # extern crate ed25519_dalek; +//! # extern crate rand_chacha; //! # fn main() { //! # use rand::Rng; -//! # use rand::ChaChaRng; +//! # use rand_chacha::ChaChaRng; //! # use rand::SeedableRng; //! # use sha2::Sha512; //! # use ed25519_dalek::Keypair; @@ -119,8 +122,10 @@ //! # extern crate rand; //! # extern crate sha2; //! # extern crate ed25519_dalek; +//! # extern crate rand_chacha; //! # fn main() { -//! # use rand::{Rng, ChaChaRng, SeedableRng}; +//! # use rand::{Rng, SeedableRng}; +//! # use rand_chacha::ChaChaRng; //! # use sha2::Sha512; //! # use ed25519_dalek::{Keypair, Signature, PublicKey}; //! use ed25519_dalek::{PUBLIC_KEY_LENGTH, SECRET_KEY_LENGTH, KEYPAIR_LENGTH, SIGNATURE_LENGTH}; @@ -142,8 +147,10 @@ //! ``` //! # extern crate rand; //! # extern crate sha2; +//! # extern crate rand_chacha; //! # extern crate ed25519_dalek; -//! # use rand::{Rng, ChaChaRng, SeedableRng}; +//! # use rand::{Rng, SeedableRng}; +//! # use rand_chacha::ChaChaRng; //! # use sha2::Sha512; //! # use ed25519_dalek::{Keypair, Signature, PublicKey, SecretKey, SignatureError}; //! # use ed25519_dalek::{PUBLIC_KEY_LENGTH, SECRET_KEY_LENGTH, KEYPAIR_LENGTH, SIGNATURE_LENGTH}; @@ -186,6 +193,7 @@ //! # extern crate rand; //! # extern crate sha2; //! # extern crate ed25519_dalek; +//! # extern crate rand_chacha; //! # #[cfg(feature = "serde")] //! extern crate serde; //! # #[cfg(feature = "serde")] @@ -193,7 +201,8 @@ //! //! # #[cfg(feature = "serde")] //! # fn main() { -//! # use rand::{Rng, ChaChaRng, SeedableRng}; +//! # use rand::{Rng, SeedableRng}; +//! # use rand_chacha::ChaChaRng; //! # use sha2::Sha512; //! # use ed25519_dalek::{Keypair, Signature, PublicKey}; //! use bincode::{serialize, Infinite}; @@ -218,6 +227,7 @@ //! # extern crate rand; //! # extern crate sha2; //! # extern crate ed25519_dalek; +//! # extern crate rand_chacha; //! # #[cfg(feature = "serde")] //! # extern crate serde; //! # #[cfg(feature = "serde")] @@ -225,7 +235,8 @@ //! # //! # #[cfg(feature = "serde")] //! # fn main() { -//! # use rand::{Rng, ChaChaRng, SeedableRng}; +//! # use rand::{Rng, SeedableRng}; +//! # use rand_chacha::ChaChaRng; //! # use sha2::Sha512; //! # use ed25519_dalek::{Keypair, Signature, PublicKey}; //! # use bincode::{serialize, Infinite}; @@ -272,6 +283,9 @@ extern crate sha2; #[cfg(test)] extern crate hex; +#[cfg(test)] +extern crate rand_chacha; + #[cfg(feature = "serde")] extern crate serde; From 1132665ac2e2fa8bcb9ee9e47d4cb131d979ec8f Mon Sep 17 00:00:00 2001 From: Colt Frederickson Date: Mon, 19 Nov 2018 10:13:15 -0700 Subject: [PATCH 05/43] Update to 1.0.0-pre1 curve25519 --- Cargo.toml | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 09748c0..98ae864 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -16,8 +16,7 @@ exclude = [ ".gitignore", "TESTVECTORS", "res/*" ] travis-ci = { repository = "dalek-cryptography/ed25519-dalek", branch = "master"} [dependencies.curve25519-dalek] -git = "https://github.com/IronCoreLabs/curve25519-dalek.git" -branch = "rand-0.6" +version = "1.0.0-pre.1" default-features = false [dependencies.rand] From 0708974aaaf480d3ffbcc3a7445bea872bbbe75c Mon Sep 17 00:00:00 2001 From: Isis Lovecruft Date: Sat, 22 Dec 2018 12:10:03 +0000 Subject: [PATCH 06/43] =?UTF-8?q?Bump=20curve25519-dalek=20dependency=20to?= =?UTF-8?q?=20version=201.0.=20=F0=9F=8E=89?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Cargo.toml b/Cargo.toml index 98ae864..b5158ba 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -16,7 +16,7 @@ exclude = [ ".gitignore", "TESTVECTORS", "res/*" ] travis-ci = { repository = "dalek-cryptography/ed25519-dalek", branch = "master"} [dependencies.curve25519-dalek] -version = "1.0.0-pre.1" +version = "1" default-features = false [dependencies.rand] From b9f078af16e9216cbf3bcc7de216000b88335e55 Mon Sep 17 00:00:00 2001 From: Isis Lovecruft Date: Sat, 22 Dec 2018 12:14:45 +0000 Subject: [PATCH 07/43] Remove default-features=false from rand dependency. cf. https://github.com/rust-random/rand/issues/645 --- Cargo.toml | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index b5158ba..572cad4 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -20,8 +20,7 @@ version = "1" default-features = false [dependencies.rand] -version = "0.6.0" -default-features = false +version = "0.6" features = ["i128_support"] [dependencies.serde] From 80ae5d06832aee8a25f1842e0571256bc094e8b8 Mon Sep 17 00:00:00 2001 From: Isis Lovecruft Date: Sat, 22 Dec 2018 12:20:59 +0000 Subject: [PATCH 08/43] Cleanup RNG usage after merging #57. --- Cargo.toml | 1 - benches/ed25519_benchmarks.rs | 2 +- src/ed25519.rs | 33 ++++++++++++----------- src/lib.rs | 51 +++++++++++++---------------------- 4 files changed, 37 insertions(+), 50 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 572cad4..776b7ed 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -43,7 +43,6 @@ hex = "^0.3" sha2 = "^0.8" bincode = "^0.9" criterion = "0.2" -rand_chacha = "0.1.0" [[bench]] name = "ed25519_benchmarks" diff --git a/benches/ed25519_benchmarks.rs b/benches/ed25519_benchmarks.rs index 5db1361..79575c9 100644 --- a/benches/ed25519_benchmarks.rs +++ b/benches/ed25519_benchmarks.rs @@ -23,7 +23,7 @@ mod ed25519_benches { use ed25519_dalek::Signature; use ed25519_dalek::verify_batch; use rand::thread_rng; - use rand::ThreadRng; + use rand::rngs::ThreadRng; use sha2::Sha512; fn sign(c: &mut Criterion) { diff --git a/src/ed25519.rs b/src/ed25519.rs index 41acac6..1803e47 100644 --- a/src/ed25519.rs +++ b/src/ed25519.rs @@ -267,7 +267,7 @@ impl SecretKey { /// # fn main() { /// # /// use rand::Rng; - /// use rand::OsRng; + /// use rand::rngs::OsRng; /// use sha2::Sha512; /// use ed25519_dalek::PublicKey; /// use ed25519_dalek::SecretKey; @@ -287,21 +287,19 @@ impl SecretKey { /// /// ``` /// # extern crate rand; - /// # extern crate rand_chacha; /// # extern crate sha2; /// # extern crate ed25519_dalek; /// # /// # fn main() { /// # /// # use rand::Rng; - /// # use rand_chacha::ChaChaRng; - /// # use rand::SeedableRng; + /// # use rand::thread_rng; /// # use sha2::Sha512; /// # use ed25519_dalek::PublicKey; /// # use ed25519_dalek::SecretKey; /// # use ed25519_dalek::Signature; /// # - /// # let mut csprng: ChaChaRng = ChaChaRng::from_seed([0u8; 32]); + /// # let mut csprng = thread_rng(); /// # let secret_key: SecretKey = SecretKey::generate(&mut csprng); /// /// let public_key: PublicKey = PublicKey::from_secret::(&secret_key); @@ -417,7 +415,8 @@ impl<'a> From<&'a SecretKey> for ExpandedSecretKey { /// # #[cfg(all(feature = "std", feature = "sha2"))] /// # fn main() { /// # - /// use rand::{Rng, OsRng}; + /// use rand::Rng; + /// use rand::rngs::OsRng; /// use sha2::Sha512; /// use ed25519_dalek::{SecretKey, ExpandedSecretKey}; /// @@ -453,7 +452,8 @@ impl ExpandedSecretKey { /// # #[cfg(all(feature = "sha2", feature = "std"))] /// # fn main() { /// # - /// use rand::{Rng, OsRng}; + /// use rand::Rng; + /// use rand::rngs::OsRng; /// use sha2::Sha512; /// use ed25519_dalek::{SecretKey, ExpandedSecretKey}; /// @@ -494,7 +494,8 @@ impl ExpandedSecretKey { /// # #[cfg(all(feature = "sha2", feature = "std"))] /// # fn do_test() -> Result { /// # - /// use rand::{Rng, OsRng}; + /// use rand::Rng; + /// use rand::rngs::OsRng; /// use ed25519_dalek::{SecretKey, ExpandedSecretKey}; /// use ed25519_dalek::SignatureError; /// @@ -544,7 +545,8 @@ impl ExpandedSecretKey { /// # #[cfg(all(feature = "std", feature = "sha2"))] /// # fn main() { /// # - /// use rand::{Rng, OsRng}; + /// use rand::Rng; + /// use rand::rngs::OsRng; /// use sha2::Sha512; /// use ed25519_dalek::{SecretKey, ExpandedSecretKey}; /// @@ -927,7 +929,8 @@ impl From for PublicKey { /// * `messages` is a slice of byte slices, one per signed message. /// * `signatures` is a slice of `Signature`s. /// * `public_keys` is a slice of `PublicKey`s. -/// * `csprng` is an implementation of `Rng + CryptoRng`, such as `rand::ThreadRng`. +/// * `csprng` is an implementation of `Rng + CryptoRng`, such as +/// `rand::rngs::ThreadRng`. /// /// # Panics /// @@ -1393,8 +1396,6 @@ mod test { use std::string::String; use std::vec::Vec; use rand::thread_rng; - use rand_chacha::ChaChaRng; - use rand::SeedableRng; use rand::rngs::ThreadRng; use hex::FromHex; use sha2::Sha512; @@ -1428,7 +1429,7 @@ mod test { #[test] fn sign_verify() { // TestSignVerify - let mut csprng: ChaChaRng; + let mut csprng: ThreadRng; let keypair: Keypair; let good_sig: Signature; let bad_sig: Signature; @@ -1436,7 +1437,7 @@ mod test { let good: &[u8] = "test message".as_bytes(); let bad: &[u8] = "wrong message".as_bytes(); - csprng = ChaChaRng::from_seed([0u8; 32]); + csprng = thread_rng(); keypair = Keypair::generate::(&mut csprng); good_sig = keypair.sign::(&good); bad_sig = keypair.sign::(&bad); @@ -1530,7 +1531,7 @@ mod test { #[test] fn ed25519ph_sign_verify() { - let mut csprng: ChaChaRng; + let mut csprng: ThreadRng; let keypair: Keypair; let good_sig: Signature; let bad_sig: Signature; @@ -1553,7 +1554,7 @@ mod test { let context: &[u8] = b"testing testing 1 2 3"; - csprng = ChaChaRng::from_seed([0u8; 32]); + csprng = thread_rng(); keypair = Keypair::generate::(&mut csprng); good_sig = keypair.sign_prehashed::(prehashed_good1, Some(context)); bad_sig = keypair.sign_prehashed::(prehashed_bad1, Some(context)); diff --git a/src/lib.rs b/src/lib.rs index d6a023b..ff8ed03 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -33,7 +33,7 @@ //! use ed25519_dalek::Signature; //! //! let mut csprng: OsRng = OsRng::new().unwrap(); -//! let keypair: Keypair = Keypair::generate::(&mut csprng); +//! let keypair: Keypair = Keypair::generate::(&mut csprng); // The `_` can be the type of `csprng` //! # } //! # //! # #[cfg(any(not(feature = "std"), not(feature = "sha2")))] @@ -44,17 +44,15 @@ //! //! ``` //! # extern crate rand; -//! # extern crate rand_chacha; //! # extern crate sha2; //! # extern crate ed25519_dalek; //! # fn main() { //! # use rand::Rng; -//! # use rand_chacha::ChaChaRng; -//! # use rand::SeedableRng; +//! # use rand::thread_rng; //! # use sha2::Sha512; //! # use ed25519_dalek::Keypair; //! # use ed25519_dalek::Signature; -//! # let mut csprng: ChaChaRng = ChaChaRng::from_seed([0u8; 32]); +//! # let mut csprng = thread_rng(); //! # let keypair: Keypair = Keypair::generate::(&mut csprng); //! let message: &[u8] = "This is a test of the tsunami alert system.".as_bytes(); //! let signature: Signature = keypair.sign::(message); @@ -68,15 +66,13 @@ //! # extern crate rand; //! # extern crate sha2; //! # extern crate ed25519_dalek; -//! # extern crate rand_chacha; //! # fn main() { //! # use rand::Rng; -//! # use rand_chacha::ChaChaRng; -//! # use rand::SeedableRng; +//! # use rand::thread_rng; //! # use sha2::Sha512; //! # use ed25519_dalek::Keypair; //! # use ed25519_dalek::Signature; -//! # let mut csprng: ChaChaRng = ChaChaRng::from_seed([0u8; 32]); +//! # let mut csprng = thread_rng(); //! # let keypair: Keypair = Keypair::generate::(&mut csprng); //! # let message: &[u8] = "This is a test of the tsunami alert system.".as_bytes(); //! # let signature: Signature = keypair.sign::(message); @@ -91,16 +87,14 @@ //! # extern crate rand; //! # extern crate sha2; //! # extern crate ed25519_dalek; -//! # extern crate rand_chacha; //! # fn main() { //! # use rand::Rng; -//! # use rand_chacha::ChaChaRng; -//! # use rand::SeedableRng; +//! # use rand::thread_rng; //! # use sha2::Sha512; //! # use ed25519_dalek::Keypair; //! # use ed25519_dalek::Signature; //! use ed25519_dalek::PublicKey; -//! # let mut csprng: ChaChaRng = ChaChaRng::from_seed([0u8; 32]); +//! # let mut csprng = thread_rng(); //! # let keypair: Keypair = Keypair::generate::(&mut csprng); //! # let message: &[u8] = "This is a test of the tsunami alert system.".as_bytes(); //! # let signature: Signature = keypair.sign::(message); @@ -122,14 +116,13 @@ //! # extern crate rand; //! # extern crate sha2; //! # extern crate ed25519_dalek; -//! # extern crate rand_chacha; //! # fn main() { -//! # use rand::{Rng, SeedableRng}; -//! # use rand_chacha::ChaChaRng; +//! # use rand::Rng; +//! # use rand::thread_rng; //! # use sha2::Sha512; //! # use ed25519_dalek::{Keypair, Signature, PublicKey}; //! use ed25519_dalek::{PUBLIC_KEY_LENGTH, SECRET_KEY_LENGTH, KEYPAIR_LENGTH, SIGNATURE_LENGTH}; -//! # let mut csprng: ChaChaRng = ChaChaRng::from_seed([0u8; 32]); +//! # let mut csprng = thread_rng(); //! # let keypair: Keypair = Keypair::generate::(&mut csprng); //! # let message: &[u8] = "This is a test of the tsunami alert system.".as_bytes(); //! # let signature: Signature = keypair.sign::(message); @@ -147,15 +140,14 @@ //! ``` //! # extern crate rand; //! # extern crate sha2; -//! # extern crate rand_chacha; //! # extern crate ed25519_dalek; -//! # use rand::{Rng, SeedableRng}; -//! # use rand_chacha::ChaChaRng; +//! # use rand::Rng; +//! # use rand::thread_rng; //! # use sha2::Sha512; //! # use ed25519_dalek::{Keypair, Signature, PublicKey, SecretKey, SignatureError}; //! # use ed25519_dalek::{PUBLIC_KEY_LENGTH, SECRET_KEY_LENGTH, KEYPAIR_LENGTH, SIGNATURE_LENGTH}; //! # fn do_test() -> Result<(SecretKey, PublicKey, Keypair, Signature), SignatureError> { -//! # let mut csprng: ChaChaRng = ChaChaRng::from_seed([0u8; 32]); +//! # let mut csprng = thread_rng(); //! # let keypair_orig: Keypair = Keypair::generate::(&mut csprng); //! # let message: &[u8] = "This is a test of the tsunami alert system.".as_bytes(); //! # let signature_orig: Signature = keypair_orig.sign::(message); @@ -193,7 +185,6 @@ //! # extern crate rand; //! # extern crate sha2; //! # extern crate ed25519_dalek; -//! # extern crate rand_chacha; //! # #[cfg(feature = "serde")] //! extern crate serde; //! # #[cfg(feature = "serde")] @@ -201,12 +192,12 @@ //! //! # #[cfg(feature = "serde")] //! # fn main() { -//! # use rand::{Rng, SeedableRng}; -//! # use rand_chacha::ChaChaRng; +//! # use rand::Rng; +//! # use rand::thread_rng; //! # use sha2::Sha512; //! # use ed25519_dalek::{Keypair, Signature, PublicKey}; //! use bincode::{serialize, Infinite}; -//! # let mut csprng: ChaChaRng = ChaChaRng::from_seed([0u8; 32]); +//! # let mut csprng = thread_rng(); //! # let keypair: Keypair = Keypair::generate::(&mut csprng); //! # let message: &[u8] = "This is a test of the tsunami alert system.".as_bytes(); //! # let signature: Signature = keypair.sign::(message); @@ -227,7 +218,6 @@ //! # extern crate rand; //! # extern crate sha2; //! # extern crate ed25519_dalek; -//! # extern crate rand_chacha; //! # #[cfg(feature = "serde")] //! # extern crate serde; //! # #[cfg(feature = "serde")] @@ -235,14 +225,14 @@ //! # //! # #[cfg(feature = "serde")] //! # fn main() { -//! # use rand::{Rng, SeedableRng}; -//! # use rand_chacha::ChaChaRng; +//! # use rand::Rng; +//! # use rand::thread_rng; //! # use sha2::Sha512; //! # use ed25519_dalek::{Keypair, Signature, PublicKey}; //! # use bincode::{serialize, Infinite}; //! use bincode::{deserialize}; //! -//! # let mut csprng: ChaChaRng = ChaChaRng::from_seed([0u8; 32]); +//! # let mut csprng = thread_rng(); //! # let keypair: Keypair = Keypair::generate::(&mut csprng); //! let message: &[u8] = "This is a test of the tsunami alert system.".as_bytes(); //! # let signature: Signature = keypair.sign::(message); @@ -283,9 +273,6 @@ extern crate sha2; #[cfg(test)] extern crate hex; -#[cfg(test)] -extern crate rand_chacha; - #[cfg(feature = "serde")] extern crate serde; From d052e63da86156f955f4d9d900ae85c43726c3a4 Mon Sep 17 00:00:00 2001 From: Isis Lovecruft Date: Sat, 22 Dec 2018 12:21:59 +0000 Subject: [PATCH 09/43] Enabling std feature can now enable rand/std. Previously it pulled in a bunch of fuschia dependencies regardless of target system. --- Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Cargo.toml b/Cargo.toml index 776b7ed..5b04835 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -51,7 +51,7 @@ harness = false [features] default = ["std", "u64_backend"] # We don't add "rand/std" here because it would enable a bunch of Fuchsia dependencies. -std = ["curve25519-dalek/std"] +std = ["curve25519-dalek/std", "rand/std"] alloc = ["curve25519-dalek/alloc"] nightly = ["curve25519-dalek/nightly", "rand/nightly", "clear_on_drop/nightly"] asm = ["sha2/asm"] From a9e5410f695b1b3da9a2e86b9312d2d07920af16 Mon Sep 17 00:00:00 2001 From: Isis Lovecruft Date: Sat, 22 Dec 2018 12:57:04 +0000 Subject: [PATCH 10/43] Fix serialised size assumptions from #48. Unfortunately the serialised size is likely never going to be the same as the type's size in memory, as most serialisation formats define additional headers for parsing safety reasons, such as buffer lengths and type information. --- src/ed25519.rs | 15 +++------------ 1 file changed, 3 insertions(+), 12 deletions(-) diff --git a/src/ed25519.rs b/src/ed25519.rs index 1803e47..8343f39 100644 --- a/src/ed25519.rs +++ b/src/ed25519.rs @@ -1645,9 +1645,6 @@ mod test { #[cfg(all(test, feature = "serde"))] use bincode::{serialize, serialized_size, deserialize, Infinite}; - #[cfg(all(test, feature = "serde"))] - use std::mem::size_of; - #[cfg(all(test, feature = "serde"))] #[test] fn serialize_deserialize_signature() { @@ -1681,25 +1678,19 @@ mod test { #[cfg(all(test, feature = "serde"))] #[test] fn serialize_public_key_size() { - assert_eq!( - serialized_size(&PUBLIC_KEY) as usize, - size_of::() - ); + assert_eq!(serialized_size(&PUBLIC_KEY) as usize, 40); // These sizes are specific to bincode==1.0.1 } #[cfg(all(test, feature = "serde"))] #[test] fn serialize_signature_size() { let signature: Signature = Signature::from_bytes(&SIGNATURE_BYTES).unwrap(); - assert_eq!(serialized_size(&signature) as usize, size_of::()); + assert_eq!(serialized_size(&signature) as usize, 72); // These sizes are specific to bincode==1.0.1 } #[cfg(all(test, feature = "serde"))] #[test] fn serialize_secret_key_size() { - assert_eq!( - serialized_size(&SECRET_KEY) as usize, - size_of::() - ); + assert_eq!(serialized_size(&SECRET_KEY) as usize, 40); // These sizes are specific to bincode==1.0.1 } } From 3d697bf27af293464e6e32028631d1e8937ad40d Mon Sep 17 00:00:00 2001 From: Isis Lovecruft Date: Sat, 22 Dec 2018 13:11:56 +0000 Subject: [PATCH 11/43] Fix doctests which relied on the sha2 feature being enabled. --- src/ed25519.rs | 26 ++++++++++++++------------ 1 file changed, 14 insertions(+), 12 deletions(-) diff --git a/src/ed25519.rs b/src/ed25519.rs index 8343f39..8367022 100644 --- a/src/ed25519.rs +++ b/src/ed25519.rs @@ -491,6 +491,8 @@ impl ExpandedSecretKey { /// # extern crate sha2; /// # extern crate ed25519_dalek; /// # + /// # use ed25519_dalek::{ExpandedSecretKey, SignatureError}; + /// # /// # #[cfg(all(feature = "sha2", feature = "std"))] /// # fn do_test() -> Result { /// # @@ -1200,17 +1202,17 @@ impl Keypair { /// use ed25519_dalek::Keypair; /// use ed25519_dalek::Signature; /// use rand::thread_rng; - /// use rand::ThreadRng; + /// use sha2::Digest; /// use sha2::Sha512; /// /// # #[cfg(all(feature = "std", feature = "sha2"))] /// # fn main() { - /// let mut csprng: ThreadRng = thread_rng(); + /// let mut csprng = thread_rng(); /// let keypair: Keypair = Keypair::generate::(&mut csprng); /// let message: &[u8] = b"All I want is to pet all of the dogs."; /// /// // Create a hash digest object which we'll feed the message into: - /// let prehashed: Sha512 = Sha512::default(); + /// let mut prehashed: Sha512 = Sha512::default(); /// /// prehashed.input(message); /// # } @@ -1248,15 +1250,15 @@ impl Keypair { /// # use ed25519_dalek::Keypair; /// # use ed25519_dalek::Signature; /// # use rand::thread_rng; - /// # use rand::ThreadRng; + /// # use sha2::Digest; /// # use sha2::Sha512; /// # /// # #[cfg(all(feature = "std", feature = "sha2"))] /// # fn main() { - /// # let mut csprng: ThreadRng = thread_rng(); + /// # let mut csprng = thread_rng(); /// # let keypair: Keypair = Keypair::generate::(&mut csprng); /// # let message: &[u8] = b"All I want is to pet all of the dogs."; - /// # let prehashed: Sha512 = Sha512::default(); + /// # let mut prehashed: Sha512 = Sha512::default(); /// # prehashed.input(message); /// # /// let context: &[u8] = b"Ed25519DalekSignPrehashedDoctest"; @@ -1311,16 +1313,16 @@ impl Keypair { /// use ed25519_dalek::Keypair; /// use ed25519_dalek::Signature; /// use rand::thread_rng; - /// use rand::ThreadRng; + /// use sha2::Digest; /// use sha2::Sha512; /// /// # #[cfg(all(feature = "std", feature = "sha2"))] /// # fn main() { - /// let mut csprng: ThreadRng = thread_rng(); + /// let mut csprng = thread_rng(); /// let keypair: Keypair = Keypair::generate::(&mut csprng); /// let message: &[u8] = b"All I want is to pet all of the dogs."; /// - /// let prehashed: Sha512 = Sha512::default(); + /// let mut prehashed: Sha512 = Sha512::default(); /// prehashed.input(message); /// /// let context: &[u8] = b"Ed25519DalekSignPrehashedDoctest"; @@ -1328,12 +1330,12 @@ impl Keypair { /// let sig: Signature = keypair.sign_prehashed(prehashed, Some(context)); /// /// // The sha2::Sha512 struct doesn't implement Copy, so we'll have to create a new one: - /// let prehashed_again: Sha512 = Sha512::default(); + /// let mut prehashed_again: Sha512 = Sha512::default(); /// prehashed_again.input(message); /// - /// let valid: bool = keypair.public.verify_prehashed(prehashed_again, context, sig); + /// let verified = keypair.public.verify_prehashed(prehashed_again, Some(context), &sig); /// - /// assert!(valid); + /// assert!(verified.is_ok()); /// # } /// # /// # #[cfg(any(not(feature = "sha2"), not(feature = "std")))] From 1459e726887b220379eea36f6437261c4c1f8fc0 Mon Sep 17 00:00:00 2001 From: Isis Lovecruft Date: Sat, 22 Dec 2018 13:20:44 +0000 Subject: [PATCH 12/43] Only test serde feature on stable to save CI resources. --- .travis.yml | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index 732228a..fa73140 100644 --- a/.travis.yml +++ b/.travis.yml @@ -7,14 +7,18 @@ rust: env: - TEST_COMMAND=test FEATURES='' - - TEST_COMMAND=test FEATURES='--features=serde' matrix: include: + # We use the 64-bit optimised curve backend by default, so also test with the 32-bit backend: - rust: nightly env: TEST_COMMAND=build FEATURES='--no-default-features --features=u32_backend' + # Test any nightly gated features on nightly: - rust: nightly env: TEST_COMMAND=test FEATURES='--features=nightly' + # Test serde support on stable, assuming that if it works there it'll work everywhere: + - rust: stable + env: TEST_COMMAND=test FEATURE='--features=serde' script: - cargo $TEST_COMMAND $FEATURES From aee0043a927c96f2f5d529dc5cebf8f1c0ab98fc Mon Sep 17 00:00:00 2001 From: Isis Lovecruft Date: Sat, 22 Dec 2018 13:23:41 +0000 Subject: [PATCH 13/43] Also exercise the test suite with the sha2 feature enabled in CI. --- .travis.yml | 3 +++ 1 file changed, 3 insertions(+) diff --git a/.travis.yml b/.travis.yml index fa73140..7a43c0d 100644 --- a/.travis.yml +++ b/.travis.yml @@ -19,6 +19,9 @@ matrix: # Test serde support on stable, assuming that if it works there it'll work everywhere: - rust: stable env: TEST_COMMAND=test FEATURE='--features=serde' + # Test with the optional sha2 feature enabled: + - rust: stable + env: TEST_COMMAND=test FEATURE='--features=sha2' script: - cargo $TEST_COMMAND $FEATURES From 4f53a4826d01d2c54a68f09becd8301ae148e188 Mon Sep 17 00:00:00 2001 From: Isis Lovecruft Date: Sat, 22 Dec 2018 13:27:44 +0000 Subject: [PATCH 14/43] Add comment in .travis.yml about testing no_std. --- .travis.yml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index 7a43c0d..82c3918 100644 --- a/.travis.yml +++ b/.travis.yml @@ -10,7 +10,8 @@ env: matrix: include: - # We use the 64-bit optimised curve backend by default, so also test with the 32-bit backend: + # We use the 64-bit optimised curve backend by default, so also test with + # the 32-bit backend (this also exercises testing with `no_std`): - rust: nightly env: TEST_COMMAND=build FEATURES='--no-default-features --features=u32_backend' # Test any nightly gated features on nightly: From 8dbaf9a8d249a24a5225a1247195d4135669f608 Mon Sep 17 00:00:00 2001 From: Isis Lovecruft Date: Thu, 20 Dec 2018 15:21:20 +0000 Subject: [PATCH 15/43] Move PublicKey point decompression into initialisation. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This caches the public key internally so that we effectively get a free speedup on key reuse in regular signature verification, similar to that in batch verification. (However, this also "speeds up"¹ batch verifications.) ¹ Less of a speed up than moving the computation elsewhere, but the speed up on reuse still also applies to key reuse for batch verification. --- src/ed25519.rs | 56 ++++++++++++++++++++++++++++---------------------- 1 file changed, 32 insertions(+), 24 deletions(-) diff --git a/src/ed25519.rs b/src/ed25519.rs index 8367022..d8e7766 100644 --- a/src/ed25519.rs +++ b/src/ed25519.rs @@ -718,11 +718,14 @@ impl<'d> Deserialize<'d> for ExpandedSecretKey { /// An ed25519 public key. #[derive(Copy, Clone, Default, Eq, PartialEq)] #[repr(C)] -pub struct PublicKey(pub (crate) CompressedEdwardsY); +pub struct PublicKey( + pub (crate) CompressedEdwardsY, + pub (crate) EdwardsPoint, +); impl Debug for PublicKey { fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result { - write!(f, "PublicKey( CompressedEdwardsY( {:?} ))", self.0) + write!(f, "PublicKey({:?}), {:?})", self.0, self.1) } } @@ -790,7 +793,10 @@ impl PublicKey { let mut bits: [u8; 32] = [0u8; 32]; bits.copy_from_slice(&bytes[..32]); - Ok(PublicKey(CompressedEdwardsY(bits))) + let compressed = CompressedEdwardsY(bits); + let point = compressed.decompress().ok_or(SignatureError(InternalError::PointDecompressionError))?; + + Ok(PublicKey(compressed, point)) } /// Derive this public key from its corresponding `SecretKey`. @@ -825,9 +831,10 @@ impl PublicKey { bits[31] &= 127; bits[31] |= 64; - let pk = (&Scalar::from_bits(*bits) * &constants::ED25519_BASEPOINT_TABLE).compress().to_bytes(); + let point = &Scalar::from_bits(*bits) * &constants::ED25519_BASEPOINT_TABLE; + let compressed = point.compress(); - PublicKey(CompressedEdwardsY(pk)) + PublicKey(compressed, point) } /// Verify a signature on a message with this keypair's public key. @@ -842,18 +849,14 @@ impl PublicKey { let mut h: D = D::default(); let R: EdwardsPoint; let k: Scalar; - - let A: EdwardsPoint = match self.0.decompress() { - Some(x) => x, - None => return Err(SignatureError(InternalError::PointDecompressionError)), - }; + let minus_A: EdwardsPoint = -self.1; h.input(signature.R.as_bytes()); h.input(self.as_bytes()); h.input(&message); k = Scalar::from_hash(h); - R = EdwardsPoint::vartime_double_scalar_mul_basepoint(&k, &(-A), &signature.s); + R = EdwardsPoint::vartime_double_scalar_mul_basepoint(&k, &(minus_A), &signature.s); if R.compress() == signature.R { Ok(()) @@ -894,10 +897,7 @@ impl PublicKey { let ctx: &[u8] = context.unwrap_or(b""); debug_assert!(ctx.len() <= 255, "The context must not be longer than 255 octets."); - let A: EdwardsPoint = match self.0.decompress() { - Some(x) => x, - None => return Err(SignatureError(InternalError::PointDecompressionError)), - }; + let minus_A: EdwardsPoint = -self.1; h.input(b"SigEd25519 no Ed25519 collisions"); h.input(&[1]); // Ed25519ph @@ -908,7 +908,7 @@ impl PublicKey { h.input(prehashed_message.result().as_slice()); k = Scalar::from_hash(h); - R = EdwardsPoint::vartime_double_scalar_mul_basepoint(&k, &(-A), &signature.s); + R = EdwardsPoint::vartime_double_scalar_mul_basepoint(&k, &(minus_A), &signature.s); if R.compress() == signature.R { Ok(()) @@ -1022,7 +1022,7 @@ pub fn verify_batch(messages: &[&[u8]], let zhrams = hrams.zip(zs.iter()).map(|(hram, z)| hram * z); let Rs = signatures.iter().map(|sig| sig.R.decompress()); - let As = public_keys.iter().map(|pk| pk.0.decompress()); + let As = public_keys.iter().map(|pk| Some(pk.1)); let B = once(Some(constants::ED25519_BASEPOINT_POINT)); // Compute (-∑ z[i]s[i] (mod l)) B + ∑ z[i]R[i] + ∑ (z[i]H(R||A||M)[i] (mod l)) A[i] = 0 @@ -1404,11 +1404,11 @@ mod test { use super::*; #[cfg(all(test, feature = "serde"))] - static PUBLIC_KEY: PublicKey = PublicKey(CompressedEdwardsY([ + static PUBLIC_KEY_BYTES: [u8; PUBLIC_KEY_LENGTH] = [ 130, 039, 155, 015, 062, 076, 188, 063, 124, 122, 026, 251, 233, 253, 225, 220, 014, 041, 166, 120, 108, 035, 254, 077, - 160, 083, 172, 058, 219, 042, 086, 120, ])); + 160, 083, 172, 058, 219, 042, 086, 120, ]; #[cfg(all(test, feature = "serde"))] static SECRET_KEY: SecretKey = SecretKey([ @@ -1612,12 +1612,17 @@ mod test { 215, 090, 152, 001, 130, 177, 010, 183, 213, 075, 254, 211, 201, 100, 007, 058, 014, 225, 114, 243, 218, 166, 035, 037, - 175, 002, 026, 104, 247, 007, 081, 026, ])))) + 175, 002, 026, 104, 247, 007, 081, 026, ]), + CompressedEdwardsY([ + 215, 090, 152, 001, 130, 177, 010, 183, + 213, 075, 254, 211, 201, 100, 007, 058, + 014, 225, 114, 243, 218, 166, 035, 037, + 175, 002, 026, 104, 247, 007, 081, 026, ]).decompress().unwrap()))) } #[test] fn keypair_clear_on_drop() { - let mut keypair: Keypair = Keypair::from_bytes(&[15u8; KEYPAIR_LENGTH][..]).unwrap(); + let mut keypair: Keypair = Keypair::from_bytes(&[1u8; KEYPAIR_LENGTH][..]).unwrap(); keypair.clear(); @@ -1660,10 +1665,12 @@ mod test { #[cfg(all(test, feature = "serde"))] #[test] fn serialize_deserialize_public_key() { - let encoded_public_key: Vec = serialize(&PUBLIC_KEY, Infinite).unwrap(); + let public_key: PublicKey = PublicKey::from_bytes(&PUBLIC_KEY_BYTES).unwrap(); + let encoded_public_key: Vec = serialize(&public_key, Infinite).unwrap(); let decoded_public_key: PublicKey = deserialize(&encoded_public_key).unwrap(); - assert_eq!(PUBLIC_KEY, decoded_public_key); + assert_eq!(&PUBLIC_KEY_BYTES[..], &encoded_public_key[encoded_public_key.len() - 32..]); + assert_eq!(public_key, decoded_public_key); } #[cfg(all(test, feature = "serde"))] @@ -1680,7 +1687,8 @@ mod test { #[cfg(all(test, feature = "serde"))] #[test] fn serialize_public_key_size() { - assert_eq!(serialized_size(&PUBLIC_KEY) as usize, 40); // These sizes are specific to bincode==1.0.1 + let public_key: PublicKey = PublicKey::from_bytes(&PUBLIC_KEY_BYTES).unwrap(); + assert_eq!(serialized_size(&public_key) as usize, 40); // These sizes are specific to bincode==1.0.1 } #[cfg(all(test, feature = "serde"))] From 7877a7fa00c526d6a42b984c769ffc7263a1ee83 Mon Sep 17 00:00:00 2001 From: Isis Lovecruft Date: Sat, 22 Dec 2018 14:40:42 +0000 Subject: [PATCH 16/43] WARNING: Remove #[repr(C)] from all types. --- src/ed25519.rs | 5 ----- 1 file changed, 5 deletions(-) diff --git a/src/ed25519.rs b/src/ed25519.rs index d8e7766..4d2fabd 100644 --- a/src/ed25519.rs +++ b/src/ed25519.rs @@ -71,7 +71,6 @@ pub const EXPANDED_SECRET_KEY_LENGTH: usize = EXPANDED_SECRET_KEY_KEY_LENGTH + E /// been signed. #[allow(non_snake_case)] #[derive(Copy, Eq, PartialEq)] -#[repr(C)] pub struct Signature { /// `R` is an `EdwardsPoint`, formed by using an hash function with /// 512-bits output to produce the digest of: @@ -166,7 +165,6 @@ impl<'d> Deserialize<'d> for Signature { } /// An EdDSA secret key. -#[repr(C)] #[derive(Default)] // we derive Default in order to use the clear() method in Drop pub struct SecretKey(pub (crate) [u8; SECRET_KEY_LENGTH]); @@ -386,7 +384,6 @@ impl<'d> Deserialize<'d> for SecretKey { // same signature scheme, and which both fail in exactly the same way. For a // better-designed, Schnorr-based signature scheme, see Trevor Perrin's work on // "generalised EdDSA" and "VXEdDSA". -#[repr(C)] #[derive(Default)] // we derive Default in order to use the clear() method in Drop pub struct ExpandedSecretKey { pub (crate) key: Scalar, @@ -717,7 +714,6 @@ impl<'d> Deserialize<'d> for ExpandedSecretKey { /// An ed25519 public key. #[derive(Copy, Clone, Default, Eq, PartialEq)] -#[repr(C)] pub struct PublicKey( pub (crate) CompressedEdwardsY, pub (crate) EdwardsPoint, @@ -1068,7 +1064,6 @@ impl<'d> Deserialize<'d> for PublicKey { /// An ed25519 keypair. #[derive(Debug, Default)] // we derive Default in order to use the clear() method in Drop -#[repr(C)] pub struct Keypair { /// The secret half of this keypair. pub secret: SecretKey, From d81d43e3ae957e4c707560d7aaf9f7326a96eaaa Mon Sep 17 00:00:00 2001 From: Isis Lovecruft Date: Sat, 29 Dec 2018 22:56:16 +0000 Subject: [PATCH 17/43] Hardcode use of sha2::Sha512 in most cases. This implements https://github.com/dalek-cryptography/ed25519-dalek/issues/64 You can still choose the "prehash" algorithm, as long as it has 64 bytes of output. Otherwise, everything is hardcoded to use sha2::Sha512. To use a different implementation you'll need a [patch.crates-io] section in cargo config. --- Cargo.toml | 5 +- src/ed25519.rs | 332 ++++++++++++++++++++++--------------------------- src/lib.rs | 80 +++++------- 3 files changed, 179 insertions(+), 238 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 5b04835..5d5cc94 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -29,7 +29,7 @@ optional = true [dependencies.sha2] version = "^0.8" -optional = true +default-features = false [dependencies.failure] version = "^0.1.1" @@ -40,7 +40,6 @@ version = "0.2" [dev-dependencies] hex = "^0.3" -sha2 = "^0.8" bincode = "^0.9" criterion = "0.2" @@ -51,7 +50,7 @@ harness = false [features] default = ["std", "u64_backend"] # We don't add "rand/std" here because it would enable a bunch of Fuchsia dependencies. -std = ["curve25519-dalek/std", "rand/std"] +std = ["curve25519-dalek/std", "rand/std", "sha2/std"] alloc = ["curve25519-dalek/alloc"] nightly = ["curve25519-dalek/nightly", "rand/nightly", "clear_on_drop/nightly"] asm = ["sha2/asm"] diff --git a/src/ed25519.rs b/src/ed25519.rs index 4d2fabd..fe207df 100644 --- a/src/ed25519.rs +++ b/src/ed25519.rs @@ -7,8 +7,7 @@ // Authors: // - Isis Agora Lovecruft -//! A Rust implementation of ed25519 EdDSA key generation, signing, and -//! verification. +//! A Rust implementation of ed25519 key generation, signing, and verification. use core::default::Default; use core::fmt::{Debug}; @@ -25,12 +24,11 @@ use serde::de::Error as SerdeError; #[cfg(feature = "serde")] use serde::de::Visitor; -#[cfg(feature = "sha2")] -use sha2::Sha512; +pub use sha2::Sha512; use clear_on_drop::clear::Clear; -use curve25519_dalek::digest::Digest; +pub use curve25519_dalek::digest::Digest; use curve25519_dalek::digest::generic_array::typenum::U64; use curve25519_dalek::constants; @@ -188,13 +186,6 @@ impl AsRef<[u8]> for SecretKey { } impl SecretKey { - /// Expand this `SecretKey` into an `ExpandedSecretKey`. - pub fn expand(&self) -> ExpandedSecretKey - where D: Digest + Default - { - ExpandedSecretKey::from_secret_key::(&self) - } - /// Convert this secret key to a byte array. #[inline] pub fn to_bytes(&self) -> [u8; SECRET_KEY_LENGTH] { @@ -279,20 +270,16 @@ impl SecretKey { /// # fn main() { } /// ``` /// - /// Afterwards, you can generate the corresponding public—provided you also - /// supply a hash function which implements the `Digest` and `Default` - /// traits, and which returns 512 bits of output—via: + /// Afterwards, you can generate the corresponding public: /// /// ``` /// # extern crate rand; - /// # extern crate sha2; /// # extern crate ed25519_dalek; /// # /// # fn main() { /// # /// # use rand::Rng; /// # use rand::thread_rng; - /// # use sha2::Sha512; /// # use ed25519_dalek::PublicKey; /// # use ed25519_dalek::SecretKey; /// # use ed25519_dalek::Signature; @@ -300,17 +287,13 @@ impl SecretKey { /// # let mut csprng = thread_rng(); /// # let secret_key: SecretKey = SecretKey::generate(&mut csprng); /// - /// let public_key: PublicKey = PublicKey::from_secret::(&secret_key); + /// let public_key: PublicKey = (&secret_key).into(); /// # } /// ``` /// - /// The standard hash function used for most ed25519 libraries is SHA-512, - /// which is available with `use sha2::Sha512` as in the example above. - /// Other suitable hash functions include Keccak-512 and Blake2b-512. - /// /// # Input /// - /// A CSPRNG with a `fill_bytes()` method, e.g. `rand_chacha::ChaChaRng` + /// A CSPRNG with a `fill_bytes()` method, e.g. `rand::OsRng` pub fn generate(csprng: &mut T) -> SecretKey where T: CryptoRng + Rng, { @@ -398,7 +381,6 @@ impl Drop for ExpandedSecretKey { } } -#[cfg(feature = "sha2")] impl<'a> From<&'a SecretKey> for ExpandedSecretKey { /// Construct an `ExpandedSecretKey` from a `SecretKey`. /// @@ -409,24 +391,35 @@ impl<'a> From<&'a SecretKey> for ExpandedSecretKey { /// # extern crate sha2; /// # extern crate ed25519_dalek; /// # - /// # #[cfg(all(feature = "std", feature = "sha2"))] /// # fn main() { /// # /// use rand::Rng; - /// use rand::rngs::OsRng; + /// use rand::thread_rng; /// use sha2::Sha512; /// use ed25519_dalek::{SecretKey, ExpandedSecretKey}; /// - /// let mut csprng: OsRng = OsRng::new().unwrap(); + /// let mut csprng = thread_rng(); /// let secret_key: SecretKey = SecretKey::generate(&mut csprng); /// let expanded_secret_key: ExpandedSecretKey = ExpandedSecretKey::from(&secret_key); /// # } - /// # - /// # #[cfg(any(not(feature = "std"), not(feature = "sha2")))] - /// # fn main() {} /// ``` fn from(secret_key: &'a SecretKey) -> ExpandedSecretKey { - ExpandedSecretKey::from_secret_key::(&secret_key) + let mut h: Sha512 = Sha512::default(); + let mut hash: [u8; 64] = [0u8; 64]; + let mut lower: [u8; 32] = [0u8; 32]; + let mut upper: [u8; 32] = [0u8; 32]; + + h.input(secret_key.as_bytes()); + hash.copy_from_slice(h.result().as_slice()); + + lower.copy_from_slice(&hash[00..32]); + upper.copy_from_slice(&hash[32..64]); + + lower[0] &= 248; + lower[31] &= 63; + lower[31] |= 64; + + ExpandedSecretKey{ key: Scalar::from_bits(lower), nonce: upper, } } } @@ -532,56 +525,10 @@ impl ExpandedSecretKey { nonce: upper }) } - /// Construct an `ExpandedSecretKey` from a `SecretKey`, using hash function `D`. - /// - /// # Examples - /// - /// ``` - /// # extern crate rand; - /// # extern crate sha2; - /// # extern crate ed25519_dalek; - /// # - /// # #[cfg(all(feature = "std", feature = "sha2"))] - /// # fn main() { - /// # - /// use rand::Rng; - /// use rand::rngs::OsRng; - /// use sha2::Sha512; - /// use ed25519_dalek::{SecretKey, ExpandedSecretKey}; - /// - /// let mut csprng: OsRng = OsRng::new().unwrap(); - /// let secret_key: SecretKey = SecretKey::generate(&mut csprng); - /// let expanded_secret_key: ExpandedSecretKey = ExpandedSecretKey::from_secret_key::(&secret_key); - /// # } - /// # - /// # #[cfg(any(not(feature = "sha2"), not(feature = "std")))] - /// # fn main() { } - /// ``` - pub fn from_secret_key(secret_key: &SecretKey) -> ExpandedSecretKey - where D: Digest + Default { - let mut h: D = D::default(); - let mut hash: [u8; 64] = [0u8; 64]; - let mut lower: [u8; 32] = [0u8; 32]; - let mut upper: [u8; 32] = [0u8; 32]; - - h.input(secret_key.as_bytes()); - hash.copy_from_slice(h.result().as_slice()); - - lower.copy_from_slice(&hash[00..32]); - upper.copy_from_slice(&hash[32..64]); - - lower[0] &= 248; - lower[31] &= 63; - lower[31] |= 64; - - ExpandedSecretKey{ key: Scalar::from_bits(lower), nonce: upper, } - } - /// Sign a message with this `ExpandedSecretKey`. #[allow(non_snake_case)] - pub fn sign(&self, message: &[u8], public_key: &PublicKey) -> Signature - where D: Digest + Default { - let mut h: D = D::default(); + pub fn sign(&self, message: &[u8], public_key: &PublicKey) -> Signature { + let mut h: Sha512 = Sha512::new(); let R: CompressedEdwardsY; let r: Scalar; let s: Scalar; @@ -593,7 +540,7 @@ impl ExpandedSecretKey { r = Scalar::from_hash(h); R = (&r * &constants::ED25519_BASEPOINT_TABLE).compress(); - h = D::default(); + h = Sha512::new(); h.input(R.as_bytes()); h.input(public_key.as_bytes()); h.input(&message); @@ -623,13 +570,16 @@ impl ExpandedSecretKey { /// /// [rfc8032]: https://tools.ietf.org/html/rfc8032#section-5.1 #[allow(non_snake_case)] - pub fn sign_prehashed(&self, - prehashed_message: D, - public_key: &PublicKey, - context: Option<&'static [u8]>) -> Signature - where D: Digest + Default + pub fn sign_prehashed( + &self, + prehashed_message: D, + public_key: &PublicKey, + context: Option<&'static [u8]>, + ) -> Signature + where + D: Digest, { - let mut h: D; + let mut h: Sha512; let mut prehash: [u8; 64] = [0u8; 64]; let R: CompressedEdwardsY; let r: Scalar; @@ -657,7 +607,7 @@ impl ExpandedSecretKey { // // This is a really fucking stupid bandaid, and the damned scheme is // still bleeding from malleability, for fuck's sake. - h = D::default() + h = Sha512::new() .chain(b"SigEd25519 no Ed25519 collisions") .chain(&[1]) // Ed25519ph .chain(&[ctx_len]) @@ -668,7 +618,7 @@ impl ExpandedSecretKey { r = Scalar::from_hash(h); R = (&r * &constants::ED25519_BASEPOINT_TABLE).compress(); - h = D::default() + h = Sha512::new() .chain(b"SigEd25519 no Ed25519 collisions") .chain(&[1]) // Ed25519ph .chain(&[ctx_len]) @@ -794,13 +744,12 @@ impl PublicKey { Ok(PublicKey(compressed, point)) } +} +impl<'a> From<&'a SecretKey> for PublicKey { /// Derive this public key from its corresponding `SecretKey`. - #[allow(unused_assignments)] - pub fn from_secret(secret_key: &SecretKey) -> PublicKey - where D: Digest + Default - { - let mut h: D = D::default(); + fn from(secret_key: &SecretKey) -> PublicKey { + let mut h: Sha512 = Sha512::new(); let mut hash: [u8; 64] = [0u8; 64]; let mut digest: [u8; 32] = [0u8; 32]; @@ -811,14 +760,18 @@ impl PublicKey { PublicKey::mangle_scalar_bits_and_multiply_by_basepoint_to_produce_public_key(&mut digest) } +} +impl<'a> From<&'a ExpandedSecretKey> for PublicKey { /// Derive this public key from its corresponding `ExpandedSecretKey`. - pub fn from_expanded_secret(expanded_secret_key: &ExpandedSecretKey) -> PublicKey { + fn from(expanded_secret_key: &ExpandedSecretKey) -> PublicKey { let mut bits: [u8; 32] = expanded_secret_key.key.to_bytes(); PublicKey::mangle_scalar_bits_and_multiply_by_basepoint_to_produce_public_key(&mut bits) } +} +impl PublicKey { /// Internal utility function for mangling the bits of a (formerly /// mathematically well-defined) "scalar" and multiplying it to produce a /// public key. @@ -839,10 +792,13 @@ impl PublicKey { /// /// Returns `Ok(())` if the signature is valid, and `Err` otherwise. #[allow(non_snake_case)] - pub fn verify(&self, message: &[u8], signature: &Signature) -> Result<(), SignatureError> - where D: Digest + Default + pub fn verify( + &self, + message: &[u8], + signature: &Signature + ) -> Result<(), SignatureError> { - let mut h: D = D::default(); + let mut h: Sha512 = Sha512::new(); let R: EdwardsPoint; let k: Scalar; let minus_A: EdwardsPoint = -self.1; @@ -880,13 +836,16 @@ impl PublicKey { /// /// [rfc8032]: https://tools.ietf.org/html/rfc8032#section-5.1 #[allow(non_snake_case)] - pub fn verify_prehashed(&self, - prehashed_message: D, - context: Option<&[u8]>, - signature: &Signature) -> Result<(), SignatureError> - where D: Digest + Default + pub fn verify_prehashed( + &self, + prehashed_message: D, + context: Option<&[u8]>, + signature: &Signature, + ) -> Result<(), SignatureError> + where + D: Digest, { - let mut h: D = D::default(); + let mut h: Sha512 = Sha512::default(); let R: EdwardsPoint; let k: Scalar; @@ -914,12 +873,6 @@ impl PublicKey { } } -impl From for PublicKey { - fn from(source: ExpandedSecretKey) -> PublicKey { - PublicKey::from_expanded_secret(&source) - } -} - /// Verify a batch of `signatures` on `messages` with their respective `public_keys`. /// /// # Inputs @@ -946,7 +899,6 @@ impl From for PublicKey { /// ``` /// extern crate ed25519_dalek; /// extern crate rand; -/// extern crate sha2; /// /// use ed25519_dalek::verify_batch; /// use ed25519_dalek::Keypair; @@ -954,26 +906,26 @@ impl From for PublicKey { /// use ed25519_dalek::Signature; /// use rand::thread_rng; /// use rand::rngs::ThreadRng; -/// use sha2::Sha512; /// /// # fn main() { /// let mut csprng: ThreadRng = thread_rng(); -/// let keypairs: Vec = (0..64).map(|_| Keypair::generate::(&mut csprng)).collect(); +/// let keypairs: Vec = (0..64).map(|_| Keypair::generate(&mut csprng)).collect(); /// let msg: &[u8] = b"They're good dogs Brant"; /// let messages: Vec<&[u8]> = (0..64).map(|_| msg).collect(); -/// let signatures: Vec = keypairs.iter().map(|key| key.sign::(&msg)).collect(); +/// let signatures: Vec = keypairs.iter().map(|key| key.sign(&msg)).collect(); /// let public_keys: Vec = keypairs.iter().map(|key| key.public).collect(); /// -/// let result = verify_batch::(&messages[..], &signatures[..], &public_keys[..]); +/// let result = verify_batch(&messages[..], &signatures[..], &public_keys[..]); /// assert!(result.is_ok()); /// # } /// ``` #[cfg(any(feature = "alloc", feature = "std"))] #[allow(non_snake_case)] -pub fn verify_batch(messages: &[&[u8]], - signatures: &[Signature], - public_keys: &[PublicKey]) -> Result<(), SignatureError> - where D: Digest + Default +pub fn verify_batch( + messages: &[&[u8]], + signatures: &[Signature], + public_keys: &[PublicKey], +) -> Result<(), SignatureError> { const ASSERT_MESSAGE: &'static [u8] = b"The number of messages, signatures, and public keys must be equal."; assert!(signatures.len() == messages.len(), ASSERT_MESSAGE); @@ -1007,7 +959,7 @@ pub fn verify_batch(messages: &[&[u8]], // Compute H(R || A || M) for each (signature, public_key, message) triplet let hrams = (0..signatures.len()).map(|i| { - let mut h: D = D::default(); + let mut h: Sha512 = Sha512::default(); h.input(signatures[i].R.as_bytes()); h.input(public_keys[i].as_bytes()); h.input(&messages[i]); @@ -1125,24 +1077,22 @@ impl Keypair { /// /// ``` /// extern crate rand; - /// extern crate sha2; /// extern crate ed25519_dalek; /// - /// # #[cfg(all(feature = "std", feature = "sha2"))] + /// # #[cfg(feature = "std")] /// # fn main() { /// /// use rand::Rng; /// use rand::OsRng; - /// use sha2::Sha512; /// use ed25519_dalek::Keypair; /// use ed25519_dalek::Signature; /// /// let mut csprng: OsRng = OsRng::new().unwrap(); - /// let keypair: Keypair = Keypair::generate::(&mut csprng); + /// let keypair: Keypair = Keypair::generate(&mut csprng); /// /// # } /// # - /// # #[cfg(any(not(feature = "sha2"), not(feature = "std")))] + /// # #[cfg(not(feature = "std"))] /// # fn main() { } /// ``` /// @@ -1155,20 +1105,21 @@ impl Keypair { /// The standard hash function used for most ed25519 libraries is SHA-512, /// which is available with `use sha2::Sha512` as in the example above. /// Other suitable hash functions include Keccak-512 and Blake2b-512. - pub fn generate(csprng: &mut R) -> Keypair - where D: Digest + Default, - R: CryptoRng + Rng, + pub fn generate(csprng: &mut R) -> Keypair + where R: CryptoRng + Rng, { let sk: SecretKey = SecretKey::generate(csprng); - let pk: PublicKey = PublicKey::from_secret::(&sk); + let pk: PublicKey = (&sk).into(); Keypair{ public: pk, secret: sk } } /// Sign a message with this keypair's secret key. - pub fn sign(&self, message: &[u8]) -> Signature - where D: Digest + Default { - self.secret.expand::().sign::(&message, &self.public) + pub fn sign(&self, message: &[u8]) -> Signature + { + let expanded: ExpandedSecretKey = (&self.secret).into(); + + expanded.sign(&message, &self.public) } /// Sign a `prehashed_message` with this `Keypair` using the @@ -1192,27 +1143,26 @@ impl Keypair { /// ``` /// extern crate ed25519_dalek; /// extern crate rand; - /// extern crate sha2; /// + /// use ed25519_dalek::Digest; /// use ed25519_dalek::Keypair; + /// use ed25519_dalek::Sha512; /// use ed25519_dalek::Signature; /// use rand::thread_rng; - /// use sha2::Digest; - /// use sha2::Sha512; /// - /// # #[cfg(all(feature = "std", feature = "sha2"))] + /// # #[cfg(feature = "std")] /// # fn main() { /// let mut csprng = thread_rng(); - /// let keypair: Keypair = Keypair::generate::(&mut csprng); + /// let keypair: Keypair = Keypair::generate(&mut csprng); /// let message: &[u8] = b"All I want is to pet all of the dogs."; /// /// // Create a hash digest object which we'll feed the message into: - /// let mut prehashed: Sha512 = Sha512::default(); + /// let mut prehashed: Sha512 = Sha512::new(); /// /// prehashed.input(message); /// # } /// # - /// # #[cfg(any(not(feature = "sha2"), not(feature = "std")))] + /// # #[cfg(not(feature = "std"))] /// # fn main() { } /// ``` /// @@ -1240,20 +1190,19 @@ impl Keypair { /// ``` /// # extern crate ed25519_dalek; /// # extern crate rand; - /// # extern crate sha2; /// # + /// # use ed25519_dalek::Digest; /// # use ed25519_dalek::Keypair; /// # use ed25519_dalek::Signature; + /// # use ed25519_dalek::Sha512; /// # use rand::thread_rng; - /// # use sha2::Digest; - /// # use sha2::Sha512; /// # - /// # #[cfg(all(feature = "std", feature = "sha2"))] + /// # #[cfg(feature = "std")] /// # fn main() { /// # let mut csprng = thread_rng(); - /// # let keypair: Keypair = Keypair::generate::(&mut csprng); + /// # let keypair: Keypair = Keypair::generate(&mut csprng); /// # let message: &[u8] = b"All I want is to pet all of the dogs."; - /// # let mut prehashed: Sha512 = Sha512::default(); + /// # let mut prehashed: Sha512 = Sha512::new(); /// # prehashed.input(message); /// # /// let context: &[u8] = b"Ed25519DalekSignPrehashedDoctest"; @@ -1261,24 +1210,33 @@ impl Keypair { /// let sig: Signature = keypair.sign_prehashed(prehashed, Some(context)); /// # } /// # - /// # #[cfg(any(not(feature = "sha2"), not(feature = "std")))] + /// # #[cfg(not(feature = "std"))] /// # fn main() { } /// ``` /// /// [rfc8032]: https://tools.ietf.org/html/rfc8032#section-5.1 /// [terrible_idea]: https://github.com/isislovecruft/scripts/blob/master/gpgkey2bc.py - pub fn sign_prehashed(&self, - prehashed_message: D, - context: Option<&'static [u8]>) -> Signature - where D: Digest + Default + pub fn sign_prehashed( + &self, + prehashed_message: D, + context: Option<&'static [u8]> + ) -> Signature + where + D: Digest, { - self.secret.expand::().sign_prehashed::(prehashed_message, &self.public, context) + let expanded: ExpandedSecretKey = (&self.secret).into(); // xxx thanks i hate this + + expanded.sign_prehashed(prehashed_message, &self.public, context) } /// Verify a signature on a message with this keypair's public key. - pub fn verify(&self, message: &[u8], signature: &Signature) -> Result<(), SignatureError> - where D: Digest + Default { - self.public.verify::(message, signature) + pub fn verify( + &self, + message: &[u8], + signature: &Signature + ) -> Result<(), SignatureError> + { + self.public.verify(message, signature) } /// Verify a `signature` on a `prehashed_message` using the Ed25519ph algorithm. @@ -1303,18 +1261,17 @@ impl Keypair { /// ``` /// extern crate ed25519_dalek; /// extern crate rand; - /// extern crate sha2; /// + /// use ed25519_dalek::Digest; /// use ed25519_dalek::Keypair; /// use ed25519_dalek::Signature; + /// use ed25519_dalek::Sha512; /// use rand::thread_rng; - /// use sha2::Digest; - /// use sha2::Sha512; /// - /// # #[cfg(all(feature = "std", feature = "sha2"))] + /// # #[cfg(feature = "std")] /// # fn main() { /// let mut csprng = thread_rng(); - /// let keypair: Keypair = Keypair::generate::(&mut csprng); + /// let keypair: Keypair = Keypair::generate(&mut csprng); /// let message: &[u8] = b"All I want is to pet all of the dogs."; /// /// let mut prehashed: Sha512 = Sha512::default(); @@ -1333,18 +1290,21 @@ impl Keypair { /// assert!(verified.is_ok()); /// # } /// # - /// # #[cfg(any(not(feature = "sha2"), not(feature = "std")))] + /// # #[cfg(not(feature = "std"))] /// # fn main() { } /// ``` /// /// [rfc8032]: https://tools.ietf.org/html/rfc8032#section-5.1 - pub fn verify_prehashed(&self, - prehashed_message: D, - context: Option<&[u8]>, - signature: &Signature) -> Result<(), SignatureError> - where D: Digest + Default + pub fn verify_prehashed( + &self, + prehashed_message: D, + context: Option<&[u8]>, + signature: &Signature + ) -> Result<(), SignatureError> + where + D: Digest, { - self.public.verify_prehashed::(prehashed_message, context, signature) + self.public.verify_prehashed(prehashed_message, context, signature) } } @@ -1435,15 +1395,15 @@ mod test { let bad: &[u8] = "wrong message".as_bytes(); csprng = thread_rng(); - keypair = Keypair::generate::(&mut csprng); - good_sig = keypair.sign::(&good); - bad_sig = keypair.sign::(&bad); + keypair = Keypair::generate(&mut csprng); + good_sig = keypair.sign(&good); + bad_sig = keypair.sign(&bad); - assert!(keypair.verify::(&good, &good_sig).is_ok(), + assert!(keypair.verify(&good, &good_sig).is_ok(), "Verification of a valid signature failed!"); - assert!(keypair.verify::(&good, &bad_sig).is_err(), + assert!(keypair.verify(&good, &bad_sig).is_err(), "Verification of a signature on a different message passed!"); - assert!(keypair.verify::(&bad, &good_sig).is_err(), + assert!(keypair.verify(&bad, &good_sig).is_err(), "Verification of a signature on a different message passed!"); } @@ -1485,10 +1445,10 @@ mod test { // The signatures in the test vectors also include the message // at the end, but we just want R and S. let sig1: Signature = Signature::from_bytes(&sig_bytes[..64]).unwrap(); - let sig2: Signature = keypair.sign::(&msg_bytes); + let sig2: Signature = keypair.sign(&msg_bytes); assert!(sig1 == sig2, "Signature bytes not equal on line {}", lineno); - assert!(keypair.verify::(&msg_bytes, &sig2).is_ok(), + assert!(keypair.verify(&msg_bytes, &sig2).is_ok(), "Signature verification failed on line {}", lineno); } } @@ -1552,15 +1512,15 @@ mod test { let context: &[u8] = b"testing testing 1 2 3"; csprng = thread_rng(); - keypair = Keypair::generate::(&mut csprng); - good_sig = keypair.sign_prehashed::(prehashed_good1, Some(context)); - bad_sig = keypair.sign_prehashed::(prehashed_bad1, Some(context)); + keypair = Keypair::generate(&mut csprng); + good_sig = keypair.sign_prehashed(prehashed_good1, Some(context)); + bad_sig = keypair.sign_prehashed(prehashed_bad1, Some(context)); - assert!(keypair.verify_prehashed::(prehashed_good2, Some(context), &good_sig).is_ok(), + assert!(keypair.verify_prehashed(prehashed_good2, Some(context), &good_sig).is_ok(), "Verification of a valid signature failed!"); - assert!(keypair.verify_prehashed::(prehashed_good3, Some(context), &bad_sig).is_err(), + assert!(keypair.verify_prehashed(prehashed_good3, Some(context), &bad_sig).is_err(), "Verification of a signature on a different message passed!"); - assert!(keypair.verify_prehashed::(prehashed_bad2, Some(context), &good_sig).is_err(), + assert!(keypair.verify_prehashed(prehashed_bad2, Some(context), &good_sig).is_err(), "Verification of a signature on a different message passed!"); } @@ -1579,13 +1539,13 @@ mod test { let mut signatures: Vec = Vec::new(); for i in 0..messages.len() { - let keypair: Keypair = Keypair::generate::(&mut csprng); - signatures.push(keypair.sign::(&messages[i])); + let keypair: Keypair = Keypair::generate(&mut csprng); + signatures.push(keypair.sign(&messages[i])); keypairs.push(keypair); } let public_keys: Vec = keypairs.iter().map(|key| key.public).collect(); - let result = verify_batch::(&messages, &signatures[..], &public_keys[..]); + let result = verify_batch(&messages, &signatures[..], &public_keys[..]); assert!(result.is_ok()); } @@ -1636,10 +1596,10 @@ mod test { #[test] fn pubkey_from_secret_and_expanded_secret() { let mut csprng = thread_rng(); - let secret: SecretKey = SecretKey::generate::<_>(&mut csprng); - let expanded_secret: ExpandedSecretKey = ExpandedSecretKey::from_secret_key::(&secret); - let public_from_secret: PublicKey = PublicKey::from_secret::(&secret); - let public_from_expanded_secret: PublicKey = PublicKey::from_expanded_secret(&expanded_secret); + let secret: SecretKey = SecretKey::generate(&mut csprng); + let expanded_secret: ExpandedSecretKey = (&secret).into(); + let public_from_secret: PublicKey = (&secret).into(); // XXX eww + let public_from_expanded_secret: PublicKey = (&expanded_secret).into(); // XXX eww assert!(public_from_secret == public_from_expanded_secret); } diff --git a/src/lib.rs b/src/lib.rs index ff8ed03..6c92afb 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -15,28 +15,25 @@ //! //! First, we need to generate a `Keypair`, which includes both public and //! secret halves of an asymmetric key. To do so, we need a cryptographically -//! secure pseudorandom number generator (CSPRNG), and a hash function which -//! has 512 bits of output. For this example, we'll use the operating -//! system's builtin PRNG and SHA-512 to generate a keypair: +//! secure pseudorandom number generator (CSPRNG). For this example, we'll use +//! the operating system's builtin PRNG: //! //! ``` //! extern crate rand; -//! extern crate sha2; //! extern crate ed25519_dalek; //! -//! # #[cfg(all(feature = "std", feature = "sha2"))] +//! # #[cfg(feature = "std")] //! # fn main() { //! use rand::Rng; //! use rand::OsRng; -//! use sha2::Sha512; //! use ed25519_dalek::Keypair; //! use ed25519_dalek::Signature; //! //! let mut csprng: OsRng = OsRng::new().unwrap(); -//! let keypair: Keypair = Keypair::generate::(&mut csprng); // The `_` can be the type of `csprng` +//! let keypair: Keypair = Keypair::generate(&mut csprng); //! # } //! # -//! # #[cfg(any(not(feature = "std"), not(feature = "sha2")))] +//! # #[cfg(not(feature = "std"))] //! # fn main() { } //! ``` //! @@ -44,18 +41,16 @@ //! //! ``` //! # extern crate rand; -//! # extern crate sha2; //! # extern crate ed25519_dalek; //! # fn main() { //! # use rand::Rng; //! # use rand::thread_rng; -//! # use sha2::Sha512; //! # use ed25519_dalek::Keypair; //! # use ed25519_dalek::Signature; //! # let mut csprng = thread_rng(); -//! # let keypair: Keypair = Keypair::generate::(&mut csprng); -//! let message: &[u8] = "This is a test of the tsunami alert system.".as_bytes(); -//! let signature: Signature = keypair.sign::(message); +//! # let keypair: Keypair = Keypair::generate(&mut csprng); +//! let message: &[u8] = b"This is a test of the tsunami alert system."; +//! let signature: Signature = keypair.sign(message); //! # } //! ``` //! @@ -64,19 +59,17 @@ //! //! ``` //! # extern crate rand; -//! # extern crate sha2; //! # extern crate ed25519_dalek; //! # fn main() { //! # use rand::Rng; //! # use rand::thread_rng; -//! # use sha2::Sha512; //! # use ed25519_dalek::Keypair; //! # use ed25519_dalek::Signature; //! # let mut csprng = thread_rng(); -//! # let keypair: Keypair = Keypair::generate::(&mut csprng); -//! # let message: &[u8] = "This is a test of the tsunami alert system.".as_bytes(); -//! # let signature: Signature = keypair.sign::(message); -//! assert!(keypair.verify::(message, &signature).is_ok()); +//! # let keypair: Keypair = Keypair::generate(&mut csprng); +//! # let message: &[u8] = b"This is a test of the tsunami alert system."; +//! # let signature: Signature = keypair.sign(message); +//! assert!(keypair.verify(message, &signature).is_ok()); //! # } //! ``` //! @@ -85,22 +78,20 @@ //! //! ``` //! # extern crate rand; -//! # extern crate sha2; //! # extern crate ed25519_dalek; //! # fn main() { //! # use rand::Rng; //! # use rand::thread_rng; -//! # use sha2::Sha512; //! # use ed25519_dalek::Keypair; //! # use ed25519_dalek::Signature; //! use ed25519_dalek::PublicKey; //! # let mut csprng = thread_rng(); -//! # let keypair: Keypair = Keypair::generate::(&mut csprng); -//! # let message: &[u8] = "This is a test of the tsunami alert system.".as_bytes(); -//! # let signature: Signature = keypair.sign::(message); +//! # let keypair: Keypair = Keypair::generate(&mut csprng); +//! # let message: &[u8] = b"This is a test of the tsunami alert system."; +//! # let signature: Signature = keypair.sign(message); //! //! let public_key: PublicKey = keypair.public; -//! assert!(public_key.verify::(message, &signature).is_ok()); +//! assert!(public_key.verify(message, &signature).is_ok()); //! # } //! ``` //! @@ -114,18 +105,16 @@ //! //! ``` //! # extern crate rand; -//! # extern crate sha2; //! # extern crate ed25519_dalek; //! # fn main() { //! # use rand::Rng; //! # use rand::thread_rng; -//! # use sha2::Sha512; //! # use ed25519_dalek::{Keypair, Signature, PublicKey}; //! use ed25519_dalek::{PUBLIC_KEY_LENGTH, SECRET_KEY_LENGTH, KEYPAIR_LENGTH, SIGNATURE_LENGTH}; //! # let mut csprng = thread_rng(); -//! # let keypair: Keypair = Keypair::generate::(&mut csprng); -//! # let message: &[u8] = "This is a test of the tsunami alert system.".as_bytes(); -//! # let signature: Signature = keypair.sign::(message); +//! # let keypair: Keypair = Keypair::generate(&mut csprng); +//! # let message: &[u8] = b"This is a test of the tsunami alert system."; +//! # let signature: Signature = keypair.sign(message); //! # let public_key: PublicKey = keypair.public; //! //! let public_key_bytes: [u8; PUBLIC_KEY_LENGTH] = public_key.to_bytes(); @@ -139,18 +128,16 @@ //! //! ``` //! # extern crate rand; -//! # extern crate sha2; //! # extern crate ed25519_dalek; //! # use rand::Rng; //! # use rand::thread_rng; -//! # use sha2::Sha512; //! # use ed25519_dalek::{Keypair, Signature, PublicKey, SecretKey, SignatureError}; //! # use ed25519_dalek::{PUBLIC_KEY_LENGTH, SECRET_KEY_LENGTH, KEYPAIR_LENGTH, SIGNATURE_LENGTH}; //! # fn do_test() -> Result<(SecretKey, PublicKey, Keypair, Signature), SignatureError> { //! # let mut csprng = thread_rng(); -//! # let keypair_orig: Keypair = Keypair::generate::(&mut csprng); -//! # let message: &[u8] = "This is a test of the tsunami alert system.".as_bytes(); -//! # let signature_orig: Signature = keypair_orig.sign::(message); +//! # let keypair_orig: Keypair = Keypair::generate(&mut csprng); +//! # let message: &[u8] = b"This is a test of the tsunami alert system."; +//! # let signature_orig: Signature = keypair_orig.sign(message); //! # let public_key_bytes: [u8; PUBLIC_KEY_LENGTH] = keypair_orig.public.to_bytes(); //! # let secret_key_bytes: [u8; SECRET_KEY_LENGTH] = keypair_orig.secret.to_bytes(); //! # let keypair_bytes: [u8; KEYPAIR_LENGTH] = keypair_orig.to_bytes(); @@ -183,7 +170,6 @@ //! //! ``` //! # extern crate rand; -//! # extern crate sha2; //! # extern crate ed25519_dalek; //! # #[cfg(feature = "serde")] //! extern crate serde; @@ -194,15 +180,14 @@ //! # fn main() { //! # use rand::Rng; //! # use rand::thread_rng; -//! # use sha2::Sha512; //! # use ed25519_dalek::{Keypair, Signature, PublicKey}; //! use bincode::{serialize, Infinite}; //! # let mut csprng = thread_rng(); -//! # let keypair: Keypair = Keypair::generate::(&mut csprng); -//! # let message: &[u8] = "This is a test of the tsunami alert system.".as_bytes(); -//! # let signature: Signature = keypair.sign::(message); +//! # let keypair: Keypair = Keypair::generate(&mut csprng); +//! # let message: &[u8] = b"This is a test of the tsunami alert system."; +//! # let signature: Signature = keypair.sign(message); //! # let public_key: PublicKey = keypair.public; -//! # let verified: bool = public_key.verify::(message, &signature).is_ok(); +//! # let verified: bool = public_key.verify(message, &signature).is_ok(); //! //! let encoded_public_key: Vec = serialize(&public_key, Infinite).unwrap(); //! let encoded_signature: Vec = serialize(&signature, Infinite).unwrap(); @@ -216,7 +201,6 @@ //! //! ``` //! # extern crate rand; -//! # extern crate sha2; //! # extern crate ed25519_dalek; //! # #[cfg(feature = "serde")] //! # extern crate serde; @@ -227,17 +211,16 @@ //! # fn main() { //! # use rand::Rng; //! # use rand::thread_rng; -//! # use sha2::Sha512; //! # use ed25519_dalek::{Keypair, Signature, PublicKey}; //! # use bincode::{serialize, Infinite}; //! use bincode::{deserialize}; //! //! # let mut csprng = thread_rng(); -//! # let keypair: Keypair = Keypair::generate::(&mut csprng); -//! let message: &[u8] = "This is a test of the tsunami alert system.".as_bytes(); -//! # let signature: Signature = keypair.sign::(message); +//! # let keypair: Keypair = Keypair::generate(&mut csprng); +//! let message: &[u8] = b"This is a test of the tsunami alert system."; +//! # let signature: Signature = keypair.sign(message); //! # let public_key: PublicKey = keypair.public; -//! # let verified: bool = public_key.verify::(message, &signature).is_ok(); +//! # let verified: bool = public_key.verify(message, &signature).is_ok(); //! # let encoded_public_key: Vec = serialize(&public_key, Infinite).unwrap(); //! # let encoded_signature: Vec = serialize(&signature, Infinite).unwrap(); //! let decoded_public_key: PublicKey = deserialize(&encoded_public_key).unwrap(); @@ -246,7 +229,7 @@ //! # assert_eq!(public_key, decoded_public_key); //! # assert_eq!(signature, decoded_signature); //! # -//! let verified: bool = decoded_public_key.verify::(&message, &decoded_signature).is_ok(); +//! let verified: bool = decoded_public_key.verify(&message, &decoded_signature).is_ok(); //! //! assert!(verified); //! # } @@ -267,7 +250,6 @@ extern crate rand; #[macro_use] extern crate std; -#[cfg(any(test, feature = "sha2"))] extern crate sha2; #[cfg(test)] From 486f23f1ad75ebbf917c980faead84fcaf08faf9 Mon Sep 17 00:00:00 2001 From: Isis Lovecruft Date: Sun, 30 Dec 2018 02:25:19 +0000 Subject: [PATCH 18/43] Fix some inconsistent terminology in docstrings. --- src/ed25519.rs | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/src/ed25519.rs b/src/ed25519.rs index fe207df..9f881be 100644 --- a/src/ed25519.rs +++ b/src/ed25519.rs @@ -39,25 +39,25 @@ use curve25519_dalek::scalar::Scalar; use errors::SignatureError; use errors::InternalError; -/// The length of a curve25519 EdDSA `Signature`, in bytes. +/// The length of a ed25519 `Signature`, in bytes. pub const SIGNATURE_LENGTH: usize = 64; -/// The length of a curve25519 EdDSA `SecretKey`, in bytes. +/// The length of a ed25519 `SecretKey`, in bytes. pub const SECRET_KEY_LENGTH: usize = 32; -/// The length of an ed25519 EdDSA `PublicKey`, in bytes. +/// The length of an ed25519 `PublicKey`, in bytes. pub const PUBLIC_KEY_LENGTH: usize = 32; -/// The length of an ed25519 EdDSA `Keypair`, in bytes. +/// The length of an ed25519 `Keypair`, in bytes. pub const KEYPAIR_LENGTH: usize = SECRET_KEY_LENGTH + PUBLIC_KEY_LENGTH; -/// The length of the "key" portion of an "expanded" curve25519 EdDSA secret key, in bytes. +/// The length of the "key" portion of an "expanded" ed25519 secret key, in bytes. const EXPANDED_SECRET_KEY_KEY_LENGTH: usize = 32; -/// The length of the "nonce" portion of an "expanded" curve25519 EdDSA secret key, in bytes. +/// The length of the "nonce" portion of an "expanded" ed25519 secret key, in bytes. const EXPANDED_SECRET_KEY_NONCE_LENGTH: usize = 32; -/// The length of an "expanded" curve25519 EdDSA key, `ExpandedSecretKey`, in bytes. +/// The length of an "expanded" ed25519 key, `ExpandedSecretKey`, in bytes. pub const EXPANDED_SECRET_KEY_LENGTH: usize = EXPANDED_SECRET_KEY_KEY_LENGTH + EXPANDED_SECRET_KEY_NONCE_LENGTH; /// An EdDSA signature. From 4ee77b915ee42eaa47fa19619f8a2cf0b160c86b Mon Sep 17 00:00:00 2001 From: Isis Lovecruft Date: Sun, 30 Dec 2018 02:26:05 +0000 Subject: [PATCH 19/43] Avoid using deprecated import path for rand::rngs::OsRng. --- src/ed25519.rs | 2 +- src/lib.rs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/ed25519.rs b/src/ed25519.rs index 9f881be..d6d9553 100644 --- a/src/ed25519.rs +++ b/src/ed25519.rs @@ -1083,7 +1083,7 @@ impl Keypair { /// # fn main() { /// /// use rand::Rng; - /// use rand::OsRng; + /// use rand::rngs::OsRng; /// use ed25519_dalek::Keypair; /// use ed25519_dalek::Signature; /// diff --git a/src/lib.rs b/src/lib.rs index 6c92afb..90510d4 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -25,7 +25,7 @@ //! # #[cfg(feature = "std")] //! # fn main() { //! use rand::Rng; -//! use rand::OsRng; +//! use rand::rngs::OsRng; //! use ed25519_dalek::Keypair; //! use ed25519_dalek::Signature; //! From e88da5ea85959b3477e4f8d83a04cd50af55e8c7 Mon Sep 17 00:00:00 2001 From: Isis Lovecruft Date: Sun, 30 Dec 2018 01:59:24 +0000 Subject: [PATCH 20/43] Move integration tests to their own directory. --- src/ed25519.rs | 296 +---------------------------------------------- tests/ed25519.rs | 294 ++++++++++++++++++++++++++++++++++++++++++++++ tests/mod.rs | 17 +++ 3 files changed, 313 insertions(+), 294 deletions(-) create mode 100644 tests/ed25519.rs create mode 100644 tests/mod.rs diff --git a/src/ed25519.rs b/src/ed25519.rs index d6d9553..8622fcb 100644 --- a/src/ed25519.rs +++ b/src/ed25519.rs @@ -1347,234 +1347,8 @@ impl<'d> Deserialize<'d> for Keypair { #[cfg(test)] mod test { - use std::io::BufReader; - use std::io::BufRead; - use std::fs::File; - use std::string::String; - use std::vec::Vec; - use rand::thread_rng; - use rand::rngs::ThreadRng; - use hex::FromHex; - use sha2::Sha512; use super::*; - #[cfg(all(test, feature = "serde"))] - static PUBLIC_KEY_BYTES: [u8; PUBLIC_KEY_LENGTH] = [ - 130, 039, 155, 015, 062, 076, 188, 063, - 124, 122, 026, 251, 233, 253, 225, 220, - 014, 041, 166, 120, 108, 035, 254, 077, - 160, 083, 172, 058, 219, 042, 086, 120, ]; - - #[cfg(all(test, feature = "serde"))] - static SECRET_KEY: SecretKey = SecretKey([ - 062, 070, 027, 163, 092, 182, 011, 003, - 077, 234, 098, 004, 011, 127, 079, 228, - 243, 187, 150, 073, 201, 137, 076, 022, - 085, 251, 152, 002, 241, 042, 072, 054, ]); - - /// Signature with the above keypair of a blank message. - #[cfg(all(test, feature = "serde"))] - static SIGNATURE_BYTES: [u8; SIGNATURE_LENGTH] = [ - 010, 126, 151, 143, 157, 064, 047, 001, - 196, 140, 179, 058, 226, 152, 018, 102, - 160, 123, 080, 016, 210, 086, 196, 028, - 053, 231, 012, 157, 169, 019, 158, 063, - 045, 154, 238, 007, 053, 185, 227, 229, - 079, 108, 213, 080, 124, 252, 084, 167, - 216, 085, 134, 144, 129, 149, 041, 081, - 063, 120, 126, 100, 092, 059, 050, 011, ]; - - #[test] - fn sign_verify() { // TestSignVerify - let mut csprng: ThreadRng; - let keypair: Keypair; - let good_sig: Signature; - let bad_sig: Signature; - - let good: &[u8] = "test message".as_bytes(); - let bad: &[u8] = "wrong message".as_bytes(); - - csprng = thread_rng(); - keypair = Keypair::generate(&mut csprng); - good_sig = keypair.sign(&good); - bad_sig = keypair.sign(&bad); - - assert!(keypair.verify(&good, &good_sig).is_ok(), - "Verification of a valid signature failed!"); - assert!(keypair.verify(&good, &bad_sig).is_err(), - "Verification of a signature on a different message passed!"); - assert!(keypair.verify(&bad, &good_sig).is_err(), - "Verification of a signature on a different message passed!"); - } - - // TESTVECTORS is taken from sign.input.gz in agl's ed25519 Golang - // package. It is a selection of test cases from - // http://ed25519.cr.yp.to/python/sign.input - #[cfg(test)] - #[cfg(not(release))] - #[test] - fn golden() { // TestGolden - let mut line: String; - let mut lineno: usize = 0; - - let f = File::open("TESTVECTORS"); - if f.is_err() { - println!("This test is only available when the code has been cloned \ - from the git repository, since the TESTVECTORS file is large \ - and is therefore not included within the distributed crate."); - panic!(); - } - let file = BufReader::new(f.unwrap()); - - for l in file.lines() { - lineno += 1; - line = l.unwrap(); - - let parts: Vec<&str> = line.split(':').collect(); - assert_eq!(parts.len(), 5, "wrong number of fields in line {}", lineno); - - let sec_bytes: Vec = FromHex::from_hex(&parts[0]).unwrap(); - let pub_bytes: Vec = FromHex::from_hex(&parts[1]).unwrap(); - let msg_bytes: Vec = FromHex::from_hex(&parts[2]).unwrap(); - let sig_bytes: Vec = FromHex::from_hex(&parts[3]).unwrap(); - - let secret: SecretKey = SecretKey::from_bytes(&sec_bytes[..SECRET_KEY_LENGTH]).unwrap(); - let public: PublicKey = PublicKey::from_bytes(&pub_bytes[..PUBLIC_KEY_LENGTH]).unwrap(); - let keypair: Keypair = Keypair{ secret: secret, public: public }; - - // The signatures in the test vectors also include the message - // at the end, but we just want R and S. - let sig1: Signature = Signature::from_bytes(&sig_bytes[..64]).unwrap(); - let sig2: Signature = keypair.sign(&msg_bytes); - - assert!(sig1 == sig2, "Signature bytes not equal on line {}", lineno); - assert!(keypair.verify(&msg_bytes, &sig2).is_ok(), - "Signature verification failed on line {}", lineno); - } - } - - // From https://tools.ietf.org/html/rfc8032#section-7.3 - #[test] - fn ed25519ph_rf8032_test_vector() { - let secret_key: &[u8] = b"833fe62409237b9d62ec77587520911e9a759cec1d19755b7da901b96dca3d42"; - let public_key: &[u8] = b"ec172b93ad5e563bf4932c70e1245034c35467ef2efd4d64ebf819683467e2bf"; - let message: &[u8] = b"616263"; - let signature: &[u8] = b"98a70222f0b8121aa9d30f813d683f809e462b469c7ff87639499bb94e6dae4131f85042463c2a355a2003d062adf5aaa10b8c61e636062aaad11c2a26083406"; - - let sec_bytes: Vec = FromHex::from_hex(secret_key).unwrap(); - let pub_bytes: Vec = FromHex::from_hex(public_key).unwrap(); - let msg_bytes: Vec = FromHex::from_hex(message).unwrap(); - let sig_bytes: Vec = FromHex::from_hex(signature).unwrap(); - - let secret: SecretKey = SecretKey::from_bytes(&sec_bytes[..SECRET_KEY_LENGTH]).unwrap(); - let public: PublicKey = PublicKey::from_bytes(&pub_bytes[..PUBLIC_KEY_LENGTH]).unwrap(); - let keypair: Keypair = Keypair{ secret: secret, public: public }; - let sig1: Signature = Signature::from_bytes(&sig_bytes[..]).unwrap(); - - let mut prehash_for_signing: Sha512 = Sha512::default(); - let mut prehash_for_verifying: Sha512 = Sha512::default(); - - prehash_for_signing.input(&msg_bytes[..]); - prehash_for_verifying.input(&msg_bytes[..]); - - let sig2: Signature = keypair.sign_prehashed(prehash_for_signing, None); - - assert!(sig1 == sig2, - "Original signature from test vectors doesn't equal signature produced:\ - \noriginal:\n{:?}\nproduced:\n{:?}", sig1, sig2); - assert!(keypair.verify_prehashed(prehash_for_verifying, None, &sig2).is_ok(), - "Could not verify ed25519ph signature!"); - } - - #[test] - fn ed25519ph_sign_verify() { - let mut csprng: ThreadRng; - let keypair: Keypair; - let good_sig: Signature; - let bad_sig: Signature; - - let good: &[u8] = b"test message"; - let bad: &[u8] = b"wrong message"; - - // ugh… there's no `impl Copy for Sha512`… i hope we can all agree these are the same hashes - let mut prehashed_good1: Sha512 = Sha512::default(); - prehashed_good1.input(good); - let mut prehashed_good2: Sha512 = Sha512::default(); - prehashed_good2.input(good); - let mut prehashed_good3: Sha512 = Sha512::default(); - prehashed_good3.input(good); - - let mut prehashed_bad1: Sha512 = Sha512::default(); - prehashed_bad1.input(bad); - let mut prehashed_bad2: Sha512 = Sha512::default(); - prehashed_bad2.input(bad); - - let context: &[u8] = b"testing testing 1 2 3"; - - csprng = thread_rng(); - keypair = Keypair::generate(&mut csprng); - good_sig = keypair.sign_prehashed(prehashed_good1, Some(context)); - bad_sig = keypair.sign_prehashed(prehashed_bad1, Some(context)); - - assert!(keypair.verify_prehashed(prehashed_good2, Some(context), &good_sig).is_ok(), - "Verification of a valid signature failed!"); - assert!(keypair.verify_prehashed(prehashed_good3, Some(context), &bad_sig).is_err(), - "Verification of a signature on a different message passed!"); - assert!(keypair.verify_prehashed(prehashed_bad2, Some(context), &good_sig).is_err(), - "Verification of a signature on a different message passed!"); - } - - #[test] - fn verify_batch_seven_signatures() { - let messages: [&[u8]; 7] = [ - b"Watch closely everyone, I'm going to show you how to kill a god.", - b"I'm not a cryptographer I just encrypt a lot.", - b"Still not a cryptographer.", - b"This is a test of the tsunami alert system. This is only a test.", - b"Fuck dumbin' it down, spit ice, skip jewellery: Molotov cocktails on me like accessories.", - b"Hey, I never cared about your bucks, so if I run up with a mask on, probably got a gas can too.", - b"And I'm not here to fill 'er up. Nope, we came to riot, here to incite, we don't want any of your stuff.", ]; - let mut csprng: ThreadRng = thread_rng(); - let mut keypairs: Vec = Vec::new(); - let mut signatures: Vec = Vec::new(); - - for i in 0..messages.len() { - let keypair: Keypair = Keypair::generate(&mut csprng); - signatures.push(keypair.sign(&messages[i])); - keypairs.push(keypair); - } - let public_keys: Vec = keypairs.iter().map(|key| key.public).collect(); - - let result = verify_batch(&messages, &signatures[..], &public_keys[..]); - - assert!(result.is_ok()); - } - - #[test] - fn public_key_from_bytes() { - // Make another function so that we can test the ? operator. - fn do_the_test() -> Result { - let public_key_bytes: [u8; PUBLIC_KEY_LENGTH] = [ - 215, 090, 152, 001, 130, 177, 010, 183, - 213, 075, 254, 211, 201, 100, 007, 058, - 014, 225, 114, 243, 218, 166, 035, 037, - 175, 002, 026, 104, 247, 007, 081, 026, ]; - let public_key = PublicKey::from_bytes(&public_key_bytes)?; - - Ok(public_key) - } - assert_eq!(do_the_test(), Ok(PublicKey(CompressedEdwardsY([ - 215, 090, 152, 001, 130, 177, 010, 183, - 213, 075, 254, 211, 201, 100, 007, 058, - 014, 225, 114, 243, 218, 166, 035, 037, - 175, 002, 026, 104, 247, 007, 081, 026, ]), - CompressedEdwardsY([ - 215, 090, 152, 001, 130, 177, 010, 183, - 213, 075, 254, 211, 201, 100, 007, 058, - 014, 225, 114, 243, 218, 166, 035, 037, - 175, 002, 026, 104, 247, 007, 081, 026, ]).decompress().unwrap()))) - } - #[test] fn keypair_clear_on_drop() { let mut keypair: Keypair = Keypair::from_bytes(&[1u8; KEYPAIR_LENGTH][..]).unwrap(); @@ -1582,8 +1356,8 @@ mod test { keypair.clear(); fn as_bytes(x: &T) -> &[u8] { - use core::mem; - use core::slice; + use std::mem; + use std::slice; unsafe { slice::from_raw_parts(x as *const T as *const u8, mem::size_of_val(x)) @@ -1592,70 +1366,4 @@ mod test { assert!(!as_bytes(&keypair).contains(&0x15)); } - - #[test] - fn pubkey_from_secret_and_expanded_secret() { - let mut csprng = thread_rng(); - let secret: SecretKey = SecretKey::generate(&mut csprng); - let expanded_secret: ExpandedSecretKey = (&secret).into(); - let public_from_secret: PublicKey = (&secret).into(); // XXX eww - let public_from_expanded_secret: PublicKey = (&expanded_secret).into(); // XXX eww - - assert!(public_from_secret == public_from_expanded_secret); - } - - #[cfg(all(test, feature = "serde"))] - use bincode::{serialize, serialized_size, deserialize, Infinite}; - - #[cfg(all(test, feature = "serde"))] - #[test] - fn serialize_deserialize_signature() { - let signature: Signature = Signature::from_bytes(&SIGNATURE_BYTES).unwrap(); - let encoded_signature: Vec = serialize(&signature, Infinite).unwrap(); - let decoded_signature: Signature = deserialize(&encoded_signature).unwrap(); - - assert_eq!(signature, decoded_signature); - } - - #[cfg(all(test, feature = "serde"))] - #[test] - fn serialize_deserialize_public_key() { - let public_key: PublicKey = PublicKey::from_bytes(&PUBLIC_KEY_BYTES).unwrap(); - let encoded_public_key: Vec = serialize(&public_key, Infinite).unwrap(); - let decoded_public_key: PublicKey = deserialize(&encoded_public_key).unwrap(); - - assert_eq!(&PUBLIC_KEY_BYTES[..], &encoded_public_key[encoded_public_key.len() - 32..]); - assert_eq!(public_key, decoded_public_key); - } - - #[cfg(all(test, feature = "serde"))] - #[test] - fn serialize_deserialize_secret_key() { - let encoded_secret_key: Vec = serialize(&SECRET_KEY, Infinite).unwrap(); - let decoded_secret_key: SecretKey = deserialize(&encoded_secret_key).unwrap(); - - for i in 0..32 { - assert_eq!(SECRET_KEY.0[i], decoded_secret_key.0[i]); - } - } - - #[cfg(all(test, feature = "serde"))] - #[test] - fn serialize_public_key_size() { - let public_key: PublicKey = PublicKey::from_bytes(&PUBLIC_KEY_BYTES).unwrap(); - assert_eq!(serialized_size(&public_key) as usize, 40); // These sizes are specific to bincode==1.0.1 - } - - #[cfg(all(test, feature = "serde"))] - #[test] - fn serialize_signature_size() { - let signature: Signature = Signature::from_bytes(&SIGNATURE_BYTES).unwrap(); - assert_eq!(serialized_size(&signature) as usize, 72); // These sizes are specific to bincode==1.0.1 - } - - #[cfg(all(test, feature = "serde"))] - #[test] - fn serialize_secret_key_size() { - assert_eq!(serialized_size(&SECRET_KEY) as usize, 40); // These sizes are specific to bincode==1.0.1 - } } diff --git a/tests/ed25519.rs b/tests/ed25519.rs new file mode 100644 index 0000000..f0a63c7 --- /dev/null +++ b/tests/ed25519.rs @@ -0,0 +1,294 @@ +// -*- mode: rust; -*- +// +// This file is part of ed25519-dalek. +// Copyright (c) 2017-2018 isis lovecruft +// See LICENSE for licensing information. +// +// Authors: +// - isis agora lovecruft + +//! Integration tests for ed25519-dalek. + +extern crate clear_on_drop; +extern crate ed25519_dalek; +extern crate hex; +extern crate rand; +extern crate sha2; + +use std::io::BufReader; +use std::io::BufRead; +use std::fs::File; +use std::string::String; +use std::vec::Vec; + +use ed25519_dalek::*; + +use hex::FromHex; + +use rand::thread_rng; +use rand::rngs::ThreadRng; + +use sha2::Sha512; + +#[cfg(test)] +mod integrations { + use super::*; + + #[cfg(all(test, feature = "serde"))] + static PUBLIC_KEY_BYTES: [u8; PUBLIC_KEY_LENGTH] = [ + 130, 039, 155, 015, 062, 076, 188, 063, + 124, 122, 026, 251, 233, 253, 225, 220, + 014, 041, 166, 120, 108, 035, 254, 077, + 160, 083, 172, 058, 219, 042, 086, 120, ]; + + #[cfg(all(test, feature = "serde"))] + static SECRET_KEY: SecretKey = SecretKey([ + 062, 070, 027, 163, 092, 182, 011, 003, + 077, 234, 098, 004, 011, 127, 079, 228, + 243, 187, 150, 073, 201, 137, 076, 022, + 085, 251, 152, 002, 241, 042, 072, 054, ]); + + /// Signature with the above keypair of a blank message. + #[cfg(all(test, feature = "serde"))] + static SIGNATURE_BYTES: [u8; SIGNATURE_LENGTH] = [ + 010, 126, 151, 143, 157, 064, 047, 001, + 196, 140, 179, 058, 226, 152, 018, 102, + 160, 123, 080, 016, 210, 086, 196, 028, + 053, 231, 012, 157, 169, 019, 158, 063, + 045, 154, 238, 007, 053, 185, 227, 229, + 079, 108, 213, 080, 124, 252, 084, 167, + 216, 085, 134, 144, 129, 149, 041, 081, + 063, 120, 126, 100, 092, 059, 050, 011, ]; + + #[test] + fn sign_verify() { // TestSignVerify + let mut csprng: ThreadRng; + let keypair: Keypair; + let good_sig: Signature; + let bad_sig: Signature; + + let good: &[u8] = "test message".as_bytes(); + let bad: &[u8] = "wrong message".as_bytes(); + + csprng = thread_rng(); + keypair = Keypair::generate(&mut csprng); + good_sig = keypair.sign(&good); + bad_sig = keypair.sign(&bad); + + assert!(keypair.verify(&good, &good_sig).is_ok(), + "Verification of a valid signature failed!"); + assert!(keypair.verify(&good, &bad_sig).is_err(), + "Verification of a signature on a different message passed!"); + assert!(keypair.verify(&bad, &good_sig).is_err(), + "Verification of a signature on a different message passed!"); + } + + // TESTVECTORS is taken from sign.input.gz in agl's ed25519 Golang + // package. It is a selection of test cases from + // http://ed25519.cr.yp.to/python/sign.input + #[cfg(test)] + #[cfg(not(release))] + #[test] + fn golden() { // TestGolden + let mut line: String; + let mut lineno: usize = 0; + + let f = File::open("TESTVECTORS"); + if f.is_err() { + println!("This test is only available when the code has been cloned \ + from the git repository, since the TESTVECTORS file is large \ + and is therefore not included within the distributed crate."); + panic!(); + } + let file = BufReader::new(f.unwrap()); + + for l in file.lines() { + lineno += 1; + line = l.unwrap(); + + let parts: Vec<&str> = line.split(':').collect(); + assert_eq!(parts.len(), 5, "wrong number of fields in line {}", lineno); + + let sec_bytes: Vec = FromHex::from_hex(&parts[0]).unwrap(); + let pub_bytes: Vec = FromHex::from_hex(&parts[1]).unwrap(); + let msg_bytes: Vec = FromHex::from_hex(&parts[2]).unwrap(); + let sig_bytes: Vec = FromHex::from_hex(&parts[3]).unwrap(); + + let secret: SecretKey = SecretKey::from_bytes(&sec_bytes[..SECRET_KEY_LENGTH]).unwrap(); + let public: PublicKey = PublicKey::from_bytes(&pub_bytes[..PUBLIC_KEY_LENGTH]).unwrap(); + let keypair: Keypair = Keypair{ secret: secret, public: public }; + + // The signatures in the test vectors also include the message + // at the end, but we just want R and S. + let sig1: Signature = Signature::from_bytes(&sig_bytes[..64]).unwrap(); + let sig2: Signature = keypair.sign(&msg_bytes); + + assert!(sig1 == sig2, "Signature bytes not equal on line {}", lineno); + assert!(keypair.verify(&msg_bytes, &sig2).is_ok(), + "Signature verification failed on line {}", lineno); + } + } + + // From https://tools.ietf.org/html/rfc8032#section-7.3 + #[test] + fn ed25519ph_rf8032_test_vector() { + let secret_key: &[u8] = b"833fe62409237b9d62ec77587520911e9a759cec1d19755b7da901b96dca3d42"; + let public_key: &[u8] = b"ec172b93ad5e563bf4932c70e1245034c35467ef2efd4d64ebf819683467e2bf"; + let message: &[u8] = b"616263"; + let signature: &[u8] = b"98a70222f0b8121aa9d30f813d683f809e462b469c7ff87639499bb94e6dae4131f85042463c2a355a2003d062adf5aaa10b8c61e636062aaad11c2a26083406"; + + let sec_bytes: Vec = FromHex::from_hex(secret_key).unwrap(); + let pub_bytes: Vec = FromHex::from_hex(public_key).unwrap(); + let msg_bytes: Vec = FromHex::from_hex(message).unwrap(); + let sig_bytes: Vec = FromHex::from_hex(signature).unwrap(); + + let secret: SecretKey = SecretKey::from_bytes(&sec_bytes[..SECRET_KEY_LENGTH]).unwrap(); + let public: PublicKey = PublicKey::from_bytes(&pub_bytes[..PUBLIC_KEY_LENGTH]).unwrap(); + let keypair: Keypair = Keypair{ secret: secret, public: public }; + let sig1: Signature = Signature::from_bytes(&sig_bytes[..]).unwrap(); + + let mut prehash_for_signing: Sha512 = Sha512::default(); + let mut prehash_for_verifying: Sha512 = Sha512::default(); + + prehash_for_signing.input(&msg_bytes[..]); + prehash_for_verifying.input(&msg_bytes[..]); + + let sig2: Signature = keypair.sign_prehashed(prehash_for_signing, None); + + assert!(sig1 == sig2, + "Original signature from test vectors doesn't equal signature produced:\ + \noriginal:\n{:?}\nproduced:\n{:?}", sig1, sig2); + assert!(keypair.verify_prehashed(prehash_for_verifying, None, &sig2).is_ok(), + "Could not verify ed25519ph signature!"); + } + + #[test] + fn ed25519ph_sign_verify() { + let mut csprng: ThreadRng; + let keypair: Keypair; + let good_sig: Signature; + let bad_sig: Signature; + + let good: &[u8] = b"test message"; + let bad: &[u8] = b"wrong message"; + + // ugh… there's no `impl Copy for Sha512`… i hope we can all agree these are the same hashes + let mut prehashed_good1: Sha512 = Sha512::default(); + prehashed_good1.input(good); + let mut prehashed_good2: Sha512 = Sha512::default(); + prehashed_good2.input(good); + let mut prehashed_good3: Sha512 = Sha512::default(); + prehashed_good3.input(good); + + let mut prehashed_bad1: Sha512 = Sha512::default(); + prehashed_bad1.input(bad); + let mut prehashed_bad2: Sha512 = Sha512::default(); + prehashed_bad2.input(bad); + + let context: &[u8] = b"testing testing 1 2 3"; + + csprng = thread_rng(); + keypair = Keypair::generate(&mut csprng); + good_sig = keypair.sign_prehashed(prehashed_good1, Some(context)); + bad_sig = keypair.sign_prehashed(prehashed_bad1, Some(context)); + + assert!(keypair.verify_prehashed(prehashed_good2, Some(context), &good_sig).is_ok(), + "Verification of a valid signature failed!"); + assert!(keypair.verify_prehashed(prehashed_good3, Some(context), &bad_sig).is_err(), + "Verification of a signature on a different message passed!"); + assert!(keypair.verify_prehashed(prehashed_bad2, Some(context), &good_sig).is_err(), + "Verification of a signature on a different message passed!"); + } + + #[test] + fn verify_batch_seven_signatures() { + let messages: [&[u8]; 7] = [ + b"Watch closely everyone, I'm going to show you how to kill a god.", + b"I'm not a cryptographer I just encrypt a lot.", + b"Still not a cryptographer.", + b"This is a test of the tsunami alert system. This is only a test.", + b"Fuck dumbin' it down, spit ice, skip jewellery: Molotov cocktails on me like accessories.", + b"Hey, I never cared about your bucks, so if I run up with a mask on, probably got a gas can too.", + b"And I'm not here to fill 'er up. Nope, we came to riot, here to incite, we don't want any of your stuff.", ]; + let mut csprng: ThreadRng = thread_rng(); + let mut keypairs: Vec = Vec::new(); + let mut signatures: Vec = Vec::new(); + + for i in 0..messages.len() { + let keypair: Keypair = Keypair::generate(&mut csprng); + signatures.push(keypair.sign(&messages[i])); + keypairs.push(keypair); + } + let public_keys: Vec = keypairs.iter().map(|key| key.public).collect(); + + let result = verify_batch(&messages, &signatures[..], &public_keys[..]); + + assert!(result.is_ok()); + } + + #[test] + fn pubkey_from_secret_and_expanded_secret() { + let mut csprng = thread_rng(); + let secret: SecretKey = SecretKey::generate(&mut csprng); + let expanded_secret: ExpandedSecretKey = (&secret).into(); + let public_from_secret: PublicKey = (&secret).into(); // XXX eww + let public_from_expanded_secret: PublicKey = (&expanded_secret).into(); // XXX eww + + assert!(public_from_secret == public_from_expanded_secret); + } + + #[cfg(all(test, feature = "serde"))] + use bincode::{serialize, serialized_size, deserialize, Infinite}; + + #[cfg(all(test, feature = "serde"))] + #[test] + fn serialize_deserialize_signature() { + let signature: Signature = Signature::from_bytes(&SIGNATURE_BYTES).unwrap(); + let encoded_signature: Vec = serialize(&signature, Infinite).unwrap(); + let decoded_signature: Signature = deserialize(&encoded_signature).unwrap(); + + assert_eq!(signature, decoded_signature); + } + + #[cfg(all(test, feature = "serde"))] + #[test] + fn serialize_deserialize_public_key() { + let public_key: PublicKey = PublicKey::from_bytes(&PUBLIC_KEY_BYTES).unwrap(); + let encoded_public_key: Vec = serialize(&public_key, Infinite).unwrap(); + let decoded_public_key: PublicKey = deserialize(&encoded_public_key).unwrap(); + + assert_eq!(&PUBLIC_KEY_BYTES[..], &encoded_public_key[encoded_public_key.len() - 32..]); + assert_eq!(public_key, decoded_public_key); + } + + #[cfg(all(test, feature = "serde"))] + #[test] + fn serialize_deserialize_secret_key() { + let encoded_secret_key: Vec = serialize(&SECRET_KEY, Infinite).unwrap(); + let decoded_secret_key: SecretKey = deserialize(&encoded_secret_key).unwrap(); + + for i in 0..32 { + assert_eq!(SECRET_KEY.0[i], decoded_secret_key.0[i]); + } + } + + #[cfg(all(test, feature = "serde"))] + #[test] + fn serialize_public_key_size() { + let public_key: PublicKey = PublicKey::from_bytes(&PUBLIC_KEY_BYTES).unwrap(); + assert_eq!(serialized_size(&public_key) as usize, 40); // These sizes are specific to bincode==1.0.1 + } + + #[cfg(all(test, feature = "serde"))] + #[test] + fn serialize_signature_size() { + let signature: Signature = Signature::from_bytes(&SIGNATURE_BYTES).unwrap(); + assert_eq!(serialized_size(&signature) as usize, 72); // These sizes are specific to bincode==1.0.1 + } + + #[cfg(all(test, feature = "serde"))] + #[test] + fn serialize_secret_key_size() { + assert_eq!(serialized_size(&SECRET_KEY) as usize, 40); // These sizes are specific to bincode==1.0.1 + } +} diff --git a/tests/mod.rs b/tests/mod.rs new file mode 100644 index 0000000..8b3a9bb --- /dev/null +++ b/tests/mod.rs @@ -0,0 +1,17 @@ +// -*- mode: rust; -*- +// +// This file is part of ed25519-dalek. +// Copyright (c) 2017-2018 isis lovecruft +// See LICENSE for licensing information. +// +// Authors: +// - isis agora lovecruft + +//! Integration tests for ed25519-dalek. + +extern crate ed25519_dalek; +extern crate hex; +extern crate rand; +extern crate sha2; + +mod ed25519; From eb8ab9f06bd536ffdb67c9f17896a97d3ecccf7e Mon Sep 17 00:00:00 2001 From: Isis Lovecruft Date: Sun, 30 Dec 2018 02:17:56 +0000 Subject: [PATCH 21/43] Organise integration tests into modules. --- tests/ed25519.rs | 140 +++++++++++++++++++++++------------------------ 1 file changed, 70 insertions(+), 70 deletions(-) diff --git a/tests/ed25519.rs b/tests/ed25519.rs index f0a63c7..ff89b90 100644 --- a/tests/ed25519.rs +++ b/tests/ed25519.rs @@ -9,18 +9,14 @@ //! Integration tests for ed25519-dalek. +#[cfg(all(test, feature = "serde"))] +extern crate bincode; extern crate clear_on_drop; extern crate ed25519_dalek; extern crate hex; extern crate rand; extern crate sha2; -use std::io::BufReader; -use std::io::BufRead; -use std::fs::File; -use std::string::String; -use std::vec::Vec; - use ed25519_dalek::*; use hex::FromHex; @@ -31,65 +27,18 @@ use rand::rngs::ThreadRng; use sha2::Sha512; #[cfg(test)] -mod integrations { +mod vectors { + use std::io::BufReader; + use std::io::BufRead; + use std::fs::File; + use super::*; - #[cfg(all(test, feature = "serde"))] - static PUBLIC_KEY_BYTES: [u8; PUBLIC_KEY_LENGTH] = [ - 130, 039, 155, 015, 062, 076, 188, 063, - 124, 122, 026, 251, 233, 253, 225, 220, - 014, 041, 166, 120, 108, 035, 254, 077, - 160, 083, 172, 058, 219, 042, 086, 120, ]; - - #[cfg(all(test, feature = "serde"))] - static SECRET_KEY: SecretKey = SecretKey([ - 062, 070, 027, 163, 092, 182, 011, 003, - 077, 234, 098, 004, 011, 127, 079, 228, - 243, 187, 150, 073, 201, 137, 076, 022, - 085, 251, 152, 002, 241, 042, 072, 054, ]); - - /// Signature with the above keypair of a blank message. - #[cfg(all(test, feature = "serde"))] - static SIGNATURE_BYTES: [u8; SIGNATURE_LENGTH] = [ - 010, 126, 151, 143, 157, 064, 047, 001, - 196, 140, 179, 058, 226, 152, 018, 102, - 160, 123, 080, 016, 210, 086, 196, 028, - 053, 231, 012, 157, 169, 019, 158, 063, - 045, 154, 238, 007, 053, 185, 227, 229, - 079, 108, 213, 080, 124, 252, 084, 167, - 216, 085, 134, 144, 129, 149, 041, 081, - 063, 120, 126, 100, 092, 059, 050, 011, ]; - - #[test] - fn sign_verify() { // TestSignVerify - let mut csprng: ThreadRng; - let keypair: Keypair; - let good_sig: Signature; - let bad_sig: Signature; - - let good: &[u8] = "test message".as_bytes(); - let bad: &[u8] = "wrong message".as_bytes(); - - csprng = thread_rng(); - keypair = Keypair::generate(&mut csprng); - good_sig = keypair.sign(&good); - bad_sig = keypair.sign(&bad); - - assert!(keypair.verify(&good, &good_sig).is_ok(), - "Verification of a valid signature failed!"); - assert!(keypair.verify(&good, &bad_sig).is_err(), - "Verification of a signature on a different message passed!"); - assert!(keypair.verify(&bad, &good_sig).is_err(), - "Verification of a signature on a different message passed!"); - } - // TESTVECTORS is taken from sign.input.gz in agl's ed25519 Golang // package. It is a selection of test cases from // http://ed25519.cr.yp.to/python/sign.input - #[cfg(test)] - #[cfg(not(release))] #[test] - fn golden() { // TestGolden + fn against_reference_implementation() { // TestGolden let mut line: String; let mut lineno: usize = 0; @@ -161,6 +110,34 @@ mod integrations { assert!(keypair.verify_prehashed(prehash_for_verifying, None, &sig2).is_ok(), "Could not verify ed25519ph signature!"); } +} + +#[cfg(test)] +mod integrations { + use super::*; + + #[test] + fn sign_verify() { // TestSignVerify + let mut csprng: ThreadRng; + let keypair: Keypair; + let good_sig: Signature; + let bad_sig: Signature; + + let good: &[u8] = "test message".as_bytes(); + let bad: &[u8] = "wrong message".as_bytes(); + + csprng = thread_rng(); + keypair = Keypair::generate(&mut csprng); + good_sig = keypair.sign(&good); + bad_sig = keypair.sign(&bad); + + assert!(keypair.verify(&good, &good_sig).is_ok(), + "Verification of a valid signature failed!"); + assert!(keypair.verify(&good, &bad_sig).is_err(), + "Verification of a signature on a different message passed!"); + assert!(keypair.verify(&bad, &good_sig).is_err(), + "Verification of a signature on a different message passed!"); + } #[test] fn ed25519ph_sign_verify() { @@ -236,11 +213,37 @@ mod integrations { assert!(public_from_secret == public_from_expanded_secret); } +} - #[cfg(all(test, feature = "serde"))] - use bincode::{serialize, serialized_size, deserialize, Infinite}; +#[cfg(all(test, feature = "serde"))] +mod serialisation { + use super::*; + + use self::bincode::{serialize, serialized_size, deserialize, Infinite}; + + static PUBLIC_KEY_BYTES: [u8; PUBLIC_KEY_LENGTH] = [ + 130, 039, 155, 015, 062, 076, 188, 063, + 124, 122, 026, 251, 233, 253, 225, 220, + 014, 041, 166, 120, 108, 035, 254, 077, + 160, 083, 172, 058, 219, 042, 086, 120, ]; + + static SECRET_KEY_BYTES: [u8; SECRET_KEY_LENGTH] = [ + 062, 070, 027, 163, 092, 182, 011, 003, + 077, 234, 098, 004, 011, 127, 079, 228, + 243, 187, 150, 073, 201, 137, 076, 022, + 085, 251, 152, 002, 241, 042, 072, 054, ]; + + /// Signature with the above keypair of a blank message. + static SIGNATURE_BYTES: [u8; SIGNATURE_LENGTH] = [ + 010, 126, 151, 143, 157, 064, 047, 001, + 196, 140, 179, 058, 226, 152, 018, 102, + 160, 123, 080, 016, 210, 086, 196, 028, + 053, 231, 012, 157, 169, 019, 158, 063, + 045, 154, 238, 007, 053, 185, 227, 229, + 079, 108, 213, 080, 124, 252, 084, 167, + 216, 085, 134, 144, 129, 149, 041, 081, + 063, 120, 126, 100, 092, 059, 050, 011, ]; - #[cfg(all(test, feature = "serde"))] #[test] fn serialize_deserialize_signature() { let signature: Signature = Signature::from_bytes(&SIGNATURE_BYTES).unwrap(); @@ -250,7 +253,6 @@ mod integrations { assert_eq!(signature, decoded_signature); } - #[cfg(all(test, feature = "serde"))] #[test] fn serialize_deserialize_public_key() { let public_key: PublicKey = PublicKey::from_bytes(&PUBLIC_KEY_BYTES).unwrap(); @@ -261,34 +263,32 @@ mod integrations { assert_eq!(public_key, decoded_public_key); } - #[cfg(all(test, feature = "serde"))] #[test] fn serialize_deserialize_secret_key() { - let encoded_secret_key: Vec = serialize(&SECRET_KEY, Infinite).unwrap(); + let secret_key: SecretKey = SecretKey::from_bytes(&SECRET_KEY_BYTES).unwrap(); + let encoded_secret_key: Vec = serialize(&secret_key, Infinite).unwrap(); let decoded_secret_key: SecretKey = deserialize(&encoded_secret_key).unwrap(); for i in 0..32 { - assert_eq!(SECRET_KEY.0[i], decoded_secret_key.0[i]); + assert_eq!(SECRET_KEY_BYTES[i], decoded_secret_key.as_bytes()[i]); } } - #[cfg(all(test, feature = "serde"))] #[test] fn serialize_public_key_size() { let public_key: PublicKey = PublicKey::from_bytes(&PUBLIC_KEY_BYTES).unwrap(); assert_eq!(serialized_size(&public_key) as usize, 40); // These sizes are specific to bincode==1.0.1 } - #[cfg(all(test, feature = "serde"))] #[test] fn serialize_signature_size() { let signature: Signature = Signature::from_bytes(&SIGNATURE_BYTES).unwrap(); assert_eq!(serialized_size(&signature) as usize, 72); // These sizes are specific to bincode==1.0.1 } - #[cfg(all(test, feature = "serde"))] #[test] fn serialize_secret_key_size() { - assert_eq!(serialized_size(&SECRET_KEY) as usize, 40); // These sizes are specific to bincode==1.0.1 + let secret_key: SecretKey = SecretKey::from_bytes(&SECRET_KEY_BYTES).unwrap(); + assert_eq!(serialized_size(&secret_key) as usize, 40); // These sizes are specific to bincode==1.0.1 } } From 80e72db67765509be7f74464868c6b4b4a11b5c0 Mon Sep 17 00:00:00 2001 From: Isis Lovecruft Date: Sun, 30 Dec 2018 02:36:49 +0000 Subject: [PATCH 22/43] Create new module for constants. --- src/constants.rs | 31 +++++++++++++++++++++++++++++++ src/ed25519.rs | 27 ++++----------------------- src/lib.rs | 1 + 3 files changed, 36 insertions(+), 23 deletions(-) create mode 100644 src/constants.rs diff --git a/src/constants.rs b/src/constants.rs new file mode 100644 index 0000000..783ffb2 --- /dev/null +++ b/src/constants.rs @@ -0,0 +1,31 @@ +// -*- mode: rust; -*- +// +// This file is part of ed25519-dalek. +// Copyright (c) 2017-2018 isis lovecruft +// See LICENSE for licensing information. +// +// Authors: +// - isis agora lovecruft + +//! Common constants such as buffer sizes for keypairs and signatures. + +/// The length of a ed25519 `Signature`, in bytes. +pub const SIGNATURE_LENGTH: usize = 64; + +/// The length of a ed25519 `SecretKey`, in bytes. +pub const SECRET_KEY_LENGTH: usize = 32; + +/// The length of an ed25519 `PublicKey`, in bytes. +pub const PUBLIC_KEY_LENGTH: usize = 32; + +/// The length of an ed25519 `Keypair`, in bytes. +pub const KEYPAIR_LENGTH: usize = SECRET_KEY_LENGTH + PUBLIC_KEY_LENGTH; + +/// The length of the "key" portion of an "expanded" ed25519 secret key, in bytes. +const EXPANDED_SECRET_KEY_KEY_LENGTH: usize = 32; + +/// The length of the "nonce" portion of an "expanded" ed25519 secret key, in bytes. +const EXPANDED_SECRET_KEY_NONCE_LENGTH: usize = 32; + +/// The length of an "expanded" ed25519 key, `ExpandedSecretKey`, in bytes. +pub const EXPANDED_SECRET_KEY_LENGTH: usize = EXPANDED_SECRET_KEY_KEY_LENGTH + EXPANDED_SECRET_KEY_NONCE_LENGTH; diff --git a/src/ed25519.rs b/src/ed25519.rs index 8622fcb..a4d82fc 100644 --- a/src/ed25519.rs +++ b/src/ed25519.rs @@ -1,11 +1,11 @@ // -*- mode: rust; -*- // // This file is part of ed25519-dalek. -// Copyright (c) 2017-2018 Isis Lovecruft +// Copyright (c) 2017-2018 isis lovecruft // See LICENSE for licensing information. // // Authors: -// - Isis Agora Lovecruft +// - isis agora lovecruft //! A Rust implementation of ed25519 key generation, signing, and verification. @@ -36,30 +36,11 @@ use curve25519_dalek::edwards::CompressedEdwardsY; use curve25519_dalek::edwards::EdwardsPoint; use curve25519_dalek::scalar::Scalar; +pub use constants::*; + use errors::SignatureError; use errors::InternalError; -/// The length of a ed25519 `Signature`, in bytes. -pub const SIGNATURE_LENGTH: usize = 64; - -/// The length of a ed25519 `SecretKey`, in bytes. -pub const SECRET_KEY_LENGTH: usize = 32; - -/// The length of an ed25519 `PublicKey`, in bytes. -pub const PUBLIC_KEY_LENGTH: usize = 32; - -/// The length of an ed25519 `Keypair`, in bytes. -pub const KEYPAIR_LENGTH: usize = SECRET_KEY_LENGTH + PUBLIC_KEY_LENGTH; - -/// The length of the "key" portion of an "expanded" ed25519 secret key, in bytes. -const EXPANDED_SECRET_KEY_KEY_LENGTH: usize = 32; - -/// The length of the "nonce" portion of an "expanded" ed25519 secret key, in bytes. -const EXPANDED_SECRET_KEY_NONCE_LENGTH: usize = 32; - -/// The length of an "expanded" ed25519 key, `ExpandedSecretKey`, in bytes. -pub const EXPANDED_SECRET_KEY_LENGTH: usize = EXPANDED_SECRET_KEY_KEY_LENGTH + EXPANDED_SECRET_KEY_NONCE_LENGTH; - /// An EdDSA signature. /// /// # Note diff --git a/src/lib.rs b/src/lib.rs index 90510d4..72df455 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -261,6 +261,7 @@ extern crate serde; #[cfg(all(test, feature = "serde"))] extern crate bincode; +mod constants; mod ed25519; pub mod errors; From d748a41894758bf7a4a44b42c26c6530613381c3 Mon Sep 17 00:00:00 2001 From: Isis Lovecruft Date: Sun, 30 Dec 2018 02:43:01 +0000 Subject: [PATCH 23/43] Create new module for Signature type. --- src/ed25519.rs | 109 ++------------------------------------- src/lib.rs | 1 + src/signature.rs | 129 +++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 133 insertions(+), 106 deletions(-) create mode 100644 src/signature.rs diff --git a/src/ed25519.rs b/src/ed25519.rs index a4d82fc..9f000c7 100644 --- a/src/ed25519.rs +++ b/src/ed25519.rs @@ -10,7 +10,7 @@ //! A Rust implementation of ed25519 key generation, signing, and verification. use core::default::Default; -use core::fmt::{Debug}; +use core::fmt::Debug; use rand::CryptoRng; use rand::Rng; @@ -37,111 +37,8 @@ use curve25519_dalek::edwards::EdwardsPoint; use curve25519_dalek::scalar::Scalar; pub use constants::*; - -use errors::SignatureError; -use errors::InternalError; - -/// An EdDSA signature. -/// -/// # Note -/// -/// These signatures, unlike the ed25519 signature reference implementation, are -/// "detached"—that is, they do **not** include a copy of the message which has -/// been signed. -#[allow(non_snake_case)] -#[derive(Copy, Eq, PartialEq)] -pub struct Signature { - /// `R` is an `EdwardsPoint`, formed by using an hash function with - /// 512-bits output to produce the digest of: - /// - /// - the nonce half of the `ExpandedSecretKey`, and - /// - the message to be signed. - /// - /// This digest is then interpreted as a `Scalar` and reduced into an - /// element in ℤ/lℤ. The scalar is then multiplied by the distinguished - /// basepoint to produce `R`, and `EdwardsPoint`. - pub (crate) R: CompressedEdwardsY, - - /// `s` is a `Scalar`, formed by using an hash function with 512-bits output - /// to produce the digest of: - /// - /// - the `r` portion of this `Signature`, - /// - the `PublicKey` which should be used to verify this `Signature`, and - /// - the message to be signed. - /// - /// This digest is then interpreted as a `Scalar` and reduced into an - /// element in ℤ/lℤ. - pub (crate) s: Scalar, -} - -impl Clone for Signature { - fn clone(&self) -> Self { *self } -} - -impl Debug for Signature { - fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result { - write!(f, "Signature( R: {:?}, s: {:?} )", &self.R, &self.s) - } -} - -impl Signature { - /// Convert this `Signature` to a byte array. - #[inline] - pub fn to_bytes(&self) -> [u8; SIGNATURE_LENGTH] { - let mut signature_bytes: [u8; SIGNATURE_LENGTH] = [0u8; SIGNATURE_LENGTH]; - - signature_bytes[..32].copy_from_slice(&self.R.as_bytes()[..]); - signature_bytes[32..].copy_from_slice(&self.s.as_bytes()[..]); - signature_bytes - } - - /// Construct a `Signature` from a slice of bytes. - #[inline] - pub fn from_bytes(bytes: &[u8]) -> Result { - if bytes.len() != SIGNATURE_LENGTH { - return Err(SignatureError(InternalError::BytesLengthError{ - name: "Signature", length: SIGNATURE_LENGTH })); - } - let mut lower: [u8; 32] = [0u8; 32]; - let mut upper: [u8; 32] = [0u8; 32]; - - lower.copy_from_slice(&bytes[..32]); - upper.copy_from_slice(&bytes[32..]); - - if upper[31] & 224 != 0 { - return Err(SignatureError(InternalError::ScalarFormatError)); - } - - Ok(Signature{ R: CompressedEdwardsY(lower), s: Scalar::from_bits(upper) }) - } -} - -#[cfg(feature = "serde")] -impl Serialize for Signature { - fn serialize(&self, serializer: S) -> Result where S: Serializer { - serializer.serialize_bytes(&self.to_bytes()[..]) - } -} - -#[cfg(feature = "serde")] -impl<'d> Deserialize<'d> for Signature { - fn deserialize(deserializer: D) -> Result where D: Deserializer<'d> { - struct SignatureVisitor; - - impl<'d> Visitor<'d> for SignatureVisitor { - type Value = Signature; - - fn expecting(&self, formatter: &mut ::core::fmt::Formatter) -> ::core::fmt::Result { - formatter.write_str("An ed25519 signature as 64 bytes, as specified in RFC8032.") - } - - fn visit_bytes(self, bytes: &[u8]) -> Result where E: SerdeError{ - Signature::from_bytes(bytes).or(Err(SerdeError::invalid_length(bytes.len(), &self))) - } - } - deserializer.deserialize_bytes(SignatureVisitor) - } -} +pub use errors::*; +pub use signature::*; /// An EdDSA secret key. #[derive(Default)] // we derive Default in order to use the clear() method in Drop diff --git a/src/lib.rs b/src/lib.rs index 72df455..521b34f 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -263,6 +263,7 @@ extern crate bincode; mod constants; mod ed25519; +mod signature; pub mod errors; diff --git a/src/signature.rs b/src/signature.rs new file mode 100644 index 0000000..f2f2316 --- /dev/null +++ b/src/signature.rs @@ -0,0 +1,129 @@ +// -*- mode: rust; -*- +// +// This file is part of ed25519-dalek. +// Copyright (c) 2017-2018 isis lovecruft +// See LICENSE for licensing information. +// +// Authors: +// - isis agora lovecruft + +//! An ed25519 signature. + +use core::fmt::Debug; + +use curve25519_dalek::edwards::CompressedEdwardsY; +use curve25519_dalek::scalar::Scalar; + +#[cfg(feature = "serde")] +use serde::{Serialize, Deserialize}; +#[cfg(feature = "serde")] +use serde::{Serializer, Deserializer}; +#[cfg(feature = "serde")] +use serde::de::Error as SerdeError; +#[cfg(feature = "serde")] +use serde::de::Visitor; + +use constants::*; +use errors::*; + +/// An ed25519 signature. +/// +/// # Note +/// +/// These signatures, unlike the ed25519 signature reference implementation, are +/// "detached"—that is, they do **not** include a copy of the message which has +/// been signed. +#[allow(non_snake_case)] +#[derive(Copy, Eq, PartialEq)] +pub struct Signature { + /// `R` is an `EdwardsPoint`, formed by using an hash function with + /// 512-bits output to produce the digest of: + /// + /// - the nonce half of the `ExpandedSecretKey`, and + /// - the message to be signed. + /// + /// This digest is then interpreted as a `Scalar` and reduced into an + /// element in ℤ/lℤ. The scalar is then multiplied by the distinguished + /// basepoint to produce `R`, and `EdwardsPoint`. + pub (crate) R: CompressedEdwardsY, + + /// `s` is a `Scalar`, formed by using an hash function with 512-bits output + /// to produce the digest of: + /// + /// - the `r` portion of this `Signature`, + /// - the `PublicKey` which should be used to verify this `Signature`, and + /// - the message to be signed. + /// + /// This digest is then interpreted as a `Scalar` and reduced into an + /// element in ℤ/lℤ. + pub (crate) s: Scalar, +} + +impl Clone for Signature { + fn clone(&self) -> Self { *self } +} + +impl Debug for Signature { + fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result { + write!(f, "Signature( R: {:?}, s: {:?} )", &self.R, &self.s) + } +} + +impl Signature { + /// Convert this `Signature` to a byte array. + #[inline] + pub fn to_bytes(&self) -> [u8; SIGNATURE_LENGTH] { + let mut signature_bytes: [u8; SIGNATURE_LENGTH] = [0u8; SIGNATURE_LENGTH]; + + signature_bytes[..32].copy_from_slice(&self.R.as_bytes()[..]); + signature_bytes[32..].copy_from_slice(&self.s.as_bytes()[..]); + signature_bytes + } + + /// Construct a `Signature` from a slice of bytes. + #[inline] + pub fn from_bytes(bytes: &[u8]) -> Result { + if bytes.len() != SIGNATURE_LENGTH { + return Err(SignatureError(InternalError::BytesLengthError{ + name: "Signature", length: SIGNATURE_LENGTH })); + } + let mut lower: [u8; 32] = [0u8; 32]; + let mut upper: [u8; 32] = [0u8; 32]; + + lower.copy_from_slice(&bytes[..32]); + upper.copy_from_slice(&bytes[32..]); + + if upper[31] & 224 != 0 { + return Err(SignatureError(InternalError::ScalarFormatError)); + } + + Ok(Signature{ R: CompressedEdwardsY(lower), s: Scalar::from_bits(upper) }) + } +} + +#[cfg(feature = "serde")] +impl Serialize for Signature { + fn serialize(&self, serializer: S) -> Result where S: Serializer { + serializer.serialize_bytes(&self.to_bytes()[..]) + } +} + +#[cfg(feature = "serde")] +impl<'d> Deserialize<'d> for Signature { + fn deserialize(deserializer: D) -> Result where D: Deserializer<'d> { + struct SignatureVisitor; + + impl<'d> Visitor<'d> for SignatureVisitor { + type Value = Signature; + + fn expecting(&self, formatter: &mut ::core::fmt::Formatter) -> ::core::fmt::Result { + formatter.write_str("An ed25519 signature as 64 bytes, as specified in RFC8032.") + } + + fn visit_bytes(self, bytes: &[u8]) -> Result where E: SerdeError{ + Signature::from_bytes(bytes).or(Err(SerdeError::invalid_length(bytes.len(), &self))) + } + } + deserializer.deserialize_bytes(SignatureVisitor) + } +} From ce857a50e79a2587db0ca981bce1192d720f5705 Mon Sep 17 00:00:00 2001 From: Isis Lovecruft Date: Sun, 30 Dec 2018 03:11:28 +0000 Subject: [PATCH 24/43] Remove unnecessary #![allow(unused_features)] lint. --- src/lib.rs | 1 - 1 file changed, 1 deletion(-) diff --git a/src/lib.rs b/src/lib.rs index 521b34f..dff7e27 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -238,7 +238,6 @@ //! ``` #![no_std] -#![allow(unused_features)] #![deny(missing_docs)] // refuse to compile if documentation is missing extern crate clear_on_drop; From 1cf581d67d0b33b731316c930b7b33890faf9d59 Mon Sep 17 00:00:00 2001 From: Isis Lovecruft Date: Sun, 30 Dec 2018 03:13:13 +0000 Subject: [PATCH 25/43] Add lints (and fix warnings) for Rust 2018 code. --- src/ed25519.rs | 18 +++++++++--------- src/errors.rs | 6 +++--- src/lib.rs | 12 ++++-------- src/signature.rs | 8 ++++---- 4 files changed, 20 insertions(+), 24 deletions(-) diff --git a/src/ed25519.rs b/src/ed25519.rs index 9f000c7..6938374 100644 --- a/src/ed25519.rs +++ b/src/ed25519.rs @@ -36,16 +36,16 @@ use curve25519_dalek::edwards::CompressedEdwardsY; use curve25519_dalek::edwards::EdwardsPoint; use curve25519_dalek::scalar::Scalar; -pub use constants::*; -pub use errors::*; -pub use signature::*; +pub use crate::constants::*; +pub use crate::errors::*; +pub use crate::signature::*; /// An EdDSA secret key. #[derive(Default)] // we derive Default in order to use the clear() method in Drop pub struct SecretKey(pub (crate) [u8; SECRET_KEY_LENGTH]); impl Debug for SecretKey { - fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result { + fn fmt(&self, f: &mut ::core::fmt::Formatter<'_>) -> ::core::fmt::Result { write!(f, "SecretKey: {:?}", &self.0[..]) } } @@ -198,7 +198,7 @@ impl<'d> Deserialize<'d> for SecretKey { impl<'d> Visitor<'d> for SecretKeyVisitor { type Value = SecretKey; - fn expecting(&self, formatter: &mut ::core::fmt::Formatter) -> ::core::fmt::Result { + fn expecting(&self, formatter: &mut ::core::fmt::Formatter<'_>) -> ::core::fmt::Result { formatter.write_str("An ed25519 secret key as 32 bytes, as specified in RFC8032.") } @@ -528,7 +528,7 @@ impl<'d> Deserialize<'d> for ExpandedSecretKey { impl<'d> Visitor<'d> for ExpandedSecretKeyVisitor { type Value = ExpandedSecretKey; - fn expecting(&self, formatter: &mut ::core::fmt::Formatter) -> ::core::fmt::Result { + fn expecting(&self, formatter: &mut ::core::fmt::Formatter<'_>) -> ::core::fmt::Result { formatter.write_str("An ed25519 expanded secret key as 64 bytes, as specified in RFC8032.") } @@ -548,7 +548,7 @@ pub struct PublicKey( ); impl Debug for PublicKey { - fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result { + fn fmt(&self, f: &mut ::core::fmt::Formatter<'_>) -> ::core::fmt::Result { write!(f, "PublicKey({:?}), {:?})", self.0, self.1) } } @@ -880,7 +880,7 @@ impl<'d> Deserialize<'d> for PublicKey { impl<'d> Visitor<'d> for PublicKeyVisitor { type Value = PublicKey; - fn expecting(&self, formatter: &mut ::core::fmt::Formatter) -> ::core::fmt::Result { + fn expecting(&self, formatter: &mut ::core::fmt::Formatter<'_>) -> ::core::fmt::Result { formatter.write_str("An ed25519 public key as a 32-byte compressed point, as specified in RFC8032") } @@ -1202,7 +1202,7 @@ impl<'d> Deserialize<'d> for Keypair { impl<'d> Visitor<'d> for KeypairVisitor { type Value = Keypair; - fn expecting(&self, formatter: &mut ::core::fmt::Formatter) -> ::core::fmt::Result { + fn expecting(&self, formatter: &mut ::core::fmt::Formatter<'_>) -> ::core::fmt::Result { formatter.write_str("An ed25519 keypair, 64 bytes in total where the secret key is \ the first 32 bytes and is in unexpanded form, and the second \ 32 bytes is a compressed point for a public key.") diff --git a/src/errors.rs b/src/errors.rs index bf568a6..f531849 100644 --- a/src/errors.rs +++ b/src/errors.rs @@ -33,7 +33,7 @@ pub (crate) enum InternalError { } impl Display for InternalError { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { match *self { InternalError::PointDecompressionError => write!(f, "Cannot decompress Edwards point"), @@ -67,13 +67,13 @@ impl ::failure::Fail for InternalError {} pub struct SignatureError(pub (crate) InternalError); impl Display for SignatureError { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { write!(f, "{}", self.0) } } impl ::failure::Fail for SignatureError { - fn cause(&self) -> Option<&::failure::Fail> { + fn cause(&self) -> Option<&dyn (::failure::Fail)> { Some(&self.0) } } diff --git a/src/lib.rs b/src/lib.rs index dff7e27..462ae40 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -238,6 +238,9 @@ //! ``` #![no_std] +#![warn(future_incompatible)] +#![warn(rust_2018_compatibility)] +#![warn(rust_2018_idioms)] #![deny(missing_docs)] // refuse to compile if documentation is missing extern crate clear_on_drop; @@ -251,15 +254,9 @@ extern crate std; extern crate sha2; -#[cfg(test)] -extern crate hex; - #[cfg(feature = "serde")] extern crate serde; -#[cfg(all(test, feature = "serde"))] -extern crate bincode; - mod constants; mod ed25519; mod signature; @@ -267,5 +264,4 @@ mod signature; pub mod errors; // Export everything public in ed25519. -pub use ed25519::*; -pub use errors::*; +pub use crate::ed25519::*; diff --git a/src/signature.rs b/src/signature.rs index f2f2316..d93b572 100644 --- a/src/signature.rs +++ b/src/signature.rs @@ -23,8 +23,8 @@ use serde::de::Error as SerdeError; #[cfg(feature = "serde")] use serde::de::Visitor; -use constants::*; -use errors::*; +use crate::constants::*; +use crate::errors::*; /// An ed25519 signature. /// @@ -64,7 +64,7 @@ impl Clone for Signature { } impl Debug for Signature { - fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result { + fn fmt(&self, f: &mut ::core::fmt::Formatter<'_>) -> ::core::fmt::Result { write!(f, "Signature( R: {:?}, s: {:?} )", &self.R, &self.s) } } @@ -116,7 +116,7 @@ impl<'d> Deserialize<'d> for Signature { impl<'d> Visitor<'d> for SignatureVisitor { type Value = Signature; - fn expecting(&self, formatter: &mut ::core::fmt::Formatter) -> ::core::fmt::Result { + fn expecting(&self, formatter: &mut ::core::fmt::Formatter<'_>) -> ::core::fmt::Result { formatter.write_str("An ed25519 signature as 64 bytes, as specified in RFC8032.") } From f6ec28c077e73e8b16989483025984636eb3c38c Mon Sep 17 00:00:00 2001 From: Isis Lovecruft Date: Sun, 30 Dec 2018 03:40:32 +0000 Subject: [PATCH 26/43] Create module for secret key types. --- src/ed25519.rs | 505 +-------------------------------------------- src/lib.rs | 1 + src/secret.rs | 540 +++++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 544 insertions(+), 502 deletions(-) create mode 100644 src/secret.rs diff --git a/src/ed25519.rs b/src/ed25519.rs index 6938374..e992c17 100644 --- a/src/ed25519.rs +++ b/src/ed25519.rs @@ -26,8 +26,6 @@ use serde::de::Visitor; pub use sha2::Sha512; -use clear_on_drop::clear::Clear; - pub use curve25519_dalek::digest::Digest; use curve25519_dalek::digest::generic_array::typenum::U64; @@ -38,508 +36,9 @@ use curve25519_dalek::scalar::Scalar; pub use crate::constants::*; pub use crate::errors::*; +pub use crate::secret::*; pub use crate::signature::*; -/// An EdDSA secret key. -#[derive(Default)] // we derive Default in order to use the clear() method in Drop -pub struct SecretKey(pub (crate) [u8; SECRET_KEY_LENGTH]); - -impl Debug for SecretKey { - fn fmt(&self, f: &mut ::core::fmt::Formatter<'_>) -> ::core::fmt::Result { - write!(f, "SecretKey: {:?}", &self.0[..]) - } -} - -/// Overwrite secret key material with null bytes when it goes out of scope. -impl Drop for SecretKey { - fn drop(&mut self) { - self.0.clear(); - } -} - -impl AsRef<[u8]> for SecretKey { - fn as_ref(&self) -> &[u8] { - self.as_bytes() - } -} - -impl SecretKey { - /// Convert this secret key to a byte array. - #[inline] - pub fn to_bytes(&self) -> [u8; SECRET_KEY_LENGTH] { - self.0 - } - - /// View this secret key as a byte array. - #[inline] - pub fn as_bytes<'a>(&'a self) -> &'a [u8; SECRET_KEY_LENGTH] { - &self.0 - } - - /// Construct a `SecretKey` from a slice of bytes. - /// - /// # Example - /// - /// ``` - /// # extern crate ed25519_dalek; - /// # - /// use ed25519_dalek::SecretKey; - /// use ed25519_dalek::SECRET_KEY_LENGTH; - /// use ed25519_dalek::SignatureError; - /// - /// # fn doctest() -> Result { - /// let secret_key_bytes: [u8; SECRET_KEY_LENGTH] = [ - /// 157, 097, 177, 157, 239, 253, 090, 096, - /// 186, 132, 074, 244, 146, 236, 044, 196, - /// 068, 073, 197, 105, 123, 050, 105, 025, - /// 112, 059, 172, 003, 028, 174, 127, 096, ]; - /// - /// let secret_key: SecretKey = SecretKey::from_bytes(&secret_key_bytes)?; - /// # - /// # Ok(secret_key) - /// # } - /// # - /// # fn main() { - /// # let result = doctest(); - /// # assert!(result.is_ok()); - /// # } - /// ``` - /// - /// # Returns - /// - /// A `Result` whose okay value is an EdDSA `SecretKey` or whose error value - /// is an `SignatureError` wrapping the internal error that occurred. - #[inline] - pub fn from_bytes(bytes: &[u8]) -> Result { - if bytes.len() != SECRET_KEY_LENGTH { - return Err(SignatureError(InternalError::BytesLengthError{ - name: "SecretKey", length: SECRET_KEY_LENGTH })); - } - let mut bits: [u8; 32] = [0u8; 32]; - bits.copy_from_slice(&bytes[..32]); - - Ok(SecretKey(bits)) - } - - /// Generate a `SecretKey` from a `csprng`. - /// - /// # Example - /// - /// ``` - /// extern crate rand; - /// extern crate sha2; - /// extern crate ed25519_dalek; - /// - /// # #[cfg(feature = "std")] - /// # fn main() { - /// # - /// use rand::Rng; - /// use rand::rngs::OsRng; - /// use sha2::Sha512; - /// use ed25519_dalek::PublicKey; - /// use ed25519_dalek::SecretKey; - /// use ed25519_dalek::Signature; - /// - /// let mut csprng: OsRng = OsRng::new().unwrap(); - /// let secret_key: SecretKey = SecretKey::generate(&mut csprng); - /// # } - /// # - /// # #[cfg(not(feature = "std"))] - /// # fn main() { } - /// ``` - /// - /// Afterwards, you can generate the corresponding public: - /// - /// ``` - /// # extern crate rand; - /// # extern crate ed25519_dalek; - /// # - /// # fn main() { - /// # - /// # use rand::Rng; - /// # use rand::thread_rng; - /// # use ed25519_dalek::PublicKey; - /// # use ed25519_dalek::SecretKey; - /// # use ed25519_dalek::Signature; - /// # - /// # let mut csprng = thread_rng(); - /// # let secret_key: SecretKey = SecretKey::generate(&mut csprng); - /// - /// let public_key: PublicKey = (&secret_key).into(); - /// # } - /// ``` - /// - /// # Input - /// - /// A CSPRNG with a `fill_bytes()` method, e.g. `rand::OsRng` - pub fn generate(csprng: &mut T) -> SecretKey - where T: CryptoRng + Rng, - { - let mut sk: SecretKey = SecretKey([0u8; 32]); - - csprng.fill_bytes(&mut sk.0); - - sk - } -} - -#[cfg(feature = "serde")] -impl Serialize for SecretKey { - fn serialize(&self, serializer: S) -> Result where S: Serializer { - serializer.serialize_bytes(self.as_bytes()) - } -} - -#[cfg(feature = "serde")] -impl<'d> Deserialize<'d> for SecretKey { - fn deserialize(deserializer: D) -> Result where D: Deserializer<'d> { - struct SecretKeyVisitor; - - impl<'d> Visitor<'d> for SecretKeyVisitor { - type Value = SecretKey; - - fn expecting(&self, formatter: &mut ::core::fmt::Formatter<'_>) -> ::core::fmt::Result { - formatter.write_str("An ed25519 secret key as 32 bytes, as specified in RFC8032.") - } - - fn visit_bytes(self, bytes: &[u8]) -> Result where E: SerdeError { - SecretKey::from_bytes(bytes).or(Err(SerdeError::invalid_length(bytes.len(), &self))) - } - } - deserializer.deserialize_bytes(SecretKeyVisitor) - } -} - -/// An "expanded" secret key. -/// -/// This is produced by using an hash function with 512-bits output to digest a -/// `SecretKey`. The output digest is then split in half, the lower half being -/// the actual `key` used to sign messages, after twiddling with some bits.¹ The -/// upper half is used a sort of half-baked, ill-designed² pseudo-domain-separation -/// "nonce"-like thing, which is used during signature production by -/// concatenating it with the message to be signed before the message is hashed. -// -// ¹ This results in a slight bias towards non-uniformity at one spectrum of -// the range of valid keys. Oh well: not my idea; not my problem. -// -// ² It is the author's view (specifically, isis agora lovecruft, in the event -// you'd like to complain about me, again) that this is "ill-designed" because -// this doesn't actually provide true hash domain separation, in that in many -// real-world applications a user wishes to have one key which is used in -// several contexts (such as within tor, which does does domain separation -// manually by pre-concatenating static strings to messages to achieve more -// robust domain separation). In other real-world applications, such as -// bitcoind, a user might wish to have one master keypair from which others are -// derived (à la BIP32) and different domain separators between keys derived at -// different levels (and similarly for tree-based key derivation constructions, -// such as hash-based signatures). Leaving the domain separation to -// application designers, who thus far have produced incompatible, -// slightly-differing, ad hoc domain separation (at least those application -// designers who knew enough cryptographic theory to do so!), is therefore a -// bad design choice on the part of the cryptographer designing primitives -// which should be simple and as foolproof as possible to use for -// non-cryptographers. Further, later in the ed25519 signature scheme, as -// specified in RFC8032, the public key is added into *another* hash digest -// (along with the message, again); it is unclear to this author why there's -// not only one but two poorly-thought-out attempts at domain separation in the -// same signature scheme, and which both fail in exactly the same way. For a -// better-designed, Schnorr-based signature scheme, see Trevor Perrin's work on -// "generalised EdDSA" and "VXEdDSA". -#[derive(Default)] // we derive Default in order to use the clear() method in Drop -pub struct ExpandedSecretKey { - pub (crate) key: Scalar, - pub (crate) nonce: [u8; 32], -} - -/// Overwrite secret key material with null bytes when it goes out of scope. -impl Drop for ExpandedSecretKey { - fn drop(&mut self) { - self.key.clear(); - self.nonce.clear(); - } -} - -impl<'a> From<&'a SecretKey> for ExpandedSecretKey { - /// Construct an `ExpandedSecretKey` from a `SecretKey`. - /// - /// # Examples - /// - /// ``` - /// # extern crate rand; - /// # extern crate sha2; - /// # extern crate ed25519_dalek; - /// # - /// # fn main() { - /// # - /// use rand::Rng; - /// use rand::thread_rng; - /// use sha2::Sha512; - /// use ed25519_dalek::{SecretKey, ExpandedSecretKey}; - /// - /// let mut csprng = thread_rng(); - /// let secret_key: SecretKey = SecretKey::generate(&mut csprng); - /// let expanded_secret_key: ExpandedSecretKey = ExpandedSecretKey::from(&secret_key); - /// # } - /// ``` - fn from(secret_key: &'a SecretKey) -> ExpandedSecretKey { - let mut h: Sha512 = Sha512::default(); - let mut hash: [u8; 64] = [0u8; 64]; - let mut lower: [u8; 32] = [0u8; 32]; - let mut upper: [u8; 32] = [0u8; 32]; - - h.input(secret_key.as_bytes()); - hash.copy_from_slice(h.result().as_slice()); - - lower.copy_from_slice(&hash[00..32]); - upper.copy_from_slice(&hash[32..64]); - - lower[0] &= 248; - lower[31] &= 63; - lower[31] |= 64; - - ExpandedSecretKey{ key: Scalar::from_bits(lower), nonce: upper, } - } -} - -impl ExpandedSecretKey { - /// Convert this `ExpandedSecretKey` into an array of 64 bytes. - /// - /// # Returns - /// - /// An array of 64 bytes. The first 32 bytes represent the "expanded" - /// secret key, and the last 32 bytes represent the "domain-separation" - /// "nonce". - /// - /// # Examples - /// - /// ``` - /// # extern crate rand; - /// # extern crate sha2; - /// # extern crate ed25519_dalek; - /// # - /// # #[cfg(all(feature = "sha2", feature = "std"))] - /// # fn main() { - /// # - /// use rand::Rng; - /// use rand::rngs::OsRng; - /// use sha2::Sha512; - /// use ed25519_dalek::{SecretKey, ExpandedSecretKey}; - /// - /// let mut csprng: OsRng = OsRng::new().unwrap(); - /// let secret_key: SecretKey = SecretKey::generate(&mut csprng); - /// let expanded_secret_key: ExpandedSecretKey = ExpandedSecretKey::from(&secret_key); - /// let expanded_secret_key_bytes: [u8; 64] = expanded_secret_key.to_bytes(); - /// - /// assert!(&expanded_secret_key_bytes[..] != &[0u8; 64][..]); - /// # } - /// # - /// # #[cfg(any(not(feature = "sha2"), not(feature = "std")))] - /// # fn main() { } - /// ``` - #[inline] - pub fn to_bytes(&self) -> [u8; EXPANDED_SECRET_KEY_LENGTH] { - let mut bytes: [u8; 64] = [0u8; 64]; - - bytes[..32].copy_from_slice(self.key.as_bytes()); - bytes[32..].copy_from_slice(&self.nonce[..]); - bytes - } - - /// Construct an `ExpandedSecretKey` from a slice of bytes. - /// - /// # Returns - /// - /// A `Result` whose okay value is an EdDSA `ExpandedSecretKey` or whose - /// error value is an `SignatureError` describing the error that occurred. - /// - /// # Examples - /// - /// ``` - /// # extern crate rand; - /// # extern crate sha2; - /// # extern crate ed25519_dalek; - /// # - /// # use ed25519_dalek::{ExpandedSecretKey, SignatureError}; - /// # - /// # #[cfg(all(feature = "sha2", feature = "std"))] - /// # fn do_test() -> Result { - /// # - /// use rand::Rng; - /// use rand::rngs::OsRng; - /// use ed25519_dalek::{SecretKey, ExpandedSecretKey}; - /// use ed25519_dalek::SignatureError; - /// - /// let mut csprng: OsRng = OsRng::new().unwrap(); - /// let secret_key: SecretKey = SecretKey::generate(&mut csprng); - /// let expanded_secret_key: ExpandedSecretKey = ExpandedSecretKey::from(&secret_key); - /// let bytes: [u8; 64] = expanded_secret_key.to_bytes(); - /// let expanded_secret_key_again = ExpandedSecretKey::from_bytes(&bytes)?; - /// # - /// # Ok(expanded_secret_key_again) - /// # } - /// # - /// # #[cfg(all(feature = "sha2", feature = "std"))] - /// # fn main() { - /// # let result = do_test(); - /// # assert!(result.is_ok()); - /// # } - /// # - /// # #[cfg(any(not(feature = "sha2"), not(feature = "std")))] - /// # fn main() { } - /// ``` - #[inline] - pub fn from_bytes(bytes: &[u8]) -> Result { - if bytes.len() != EXPANDED_SECRET_KEY_LENGTH { - return Err(SignatureError(InternalError::BytesLengthError{ - name: "ExpandedSecretKey", length: EXPANDED_SECRET_KEY_LENGTH })); - } - let mut lower: [u8; 32] = [0u8; 32]; - let mut upper: [u8; 32] = [0u8; 32]; - - lower.copy_from_slice(&bytes[00..32]); - upper.copy_from_slice(&bytes[32..64]); - - Ok(ExpandedSecretKey{ key: Scalar::from_bits(lower), - nonce: upper }) - } - - /// Sign a message with this `ExpandedSecretKey`. - #[allow(non_snake_case)] - pub fn sign(&self, message: &[u8], public_key: &PublicKey) -> Signature { - let mut h: Sha512 = Sha512::new(); - let R: CompressedEdwardsY; - let r: Scalar; - let s: Scalar; - let k: Scalar; - - h.input(&self.nonce); - h.input(&message); - - r = Scalar::from_hash(h); - R = (&r * &constants::ED25519_BASEPOINT_TABLE).compress(); - - h = Sha512::new(); - h.input(R.as_bytes()); - h.input(public_key.as_bytes()); - h.input(&message); - - k = Scalar::from_hash(h); - s = &(&k * &self.key) + &r; - - Signature{ R, s } - } - - /// Sign a `prehashed_message` with this `ExpandedSecretKey` using the - /// Ed25519ph algorithm defined in [RFC8032 §5.1][rfc8032]. - /// - /// # Inputs - /// - /// * `prehashed_message` is an instantiated hash digest with 512-bits of - /// output which has had the message to be signed previously fed into its - /// state. - /// * `public_key` is a [`PublicKey`] which corresponds to this secret key. - /// * `context` is an optional context string, up to 255 bytes inclusive, - /// which may be used to provide additional domain separation. If not - /// set, this will default to an empty string. - /// - /// # Returns - /// - /// An Ed25519ph [`Signature`] on the `prehashed_message`. - /// - /// [rfc8032]: https://tools.ietf.org/html/rfc8032#section-5.1 - #[allow(non_snake_case)] - pub fn sign_prehashed( - &self, - prehashed_message: D, - public_key: &PublicKey, - context: Option<&'static [u8]>, - ) -> Signature - where - D: Digest, - { - let mut h: Sha512; - let mut prehash: [u8; 64] = [0u8; 64]; - let R: CompressedEdwardsY; - let r: Scalar; - let s: Scalar; - let k: Scalar; - - let ctx: &[u8] = context.unwrap_or(b""); // By default, the context is an empty string. - - debug_assert!(ctx.len() <= 255, "The context must not be longer than 255 octets."); - - let ctx_len: u8 = ctx.len() as u8; - - // Get the result of the pre-hashed message. - prehash.copy_from_slice(prehashed_message.result().as_slice()); - - // This is the dumbest, ten-years-late, non-admission of fucking up the - // domain separation I have ever seen. Why am I still required to put - // the upper half "prefix" of the hashed "secret key" in here? Why - // can't the user just supply their own nonce and decide for themselves - // whether or not they want a deterministic signature scheme? Why does - // the message go into what's ostensibly the signature domain separation - // hash? Why wasn't there always a way to provide a context string? - // - // ... - // - // This is a really fucking stupid bandaid, and the damned scheme is - // still bleeding from malleability, for fuck's sake. - h = Sha512::new() - .chain(b"SigEd25519 no Ed25519 collisions") - .chain(&[1]) // Ed25519ph - .chain(&[ctx_len]) - .chain(ctx) - .chain(&self.nonce) - .chain(&prehash[..]); - - r = Scalar::from_hash(h); - R = (&r * &constants::ED25519_BASEPOINT_TABLE).compress(); - - h = Sha512::new() - .chain(b"SigEd25519 no Ed25519 collisions") - .chain(&[1]) // Ed25519ph - .chain(&[ctx_len]) - .chain(ctx) - .chain(R.as_bytes()) - .chain(public_key.as_bytes()) - .chain(&prehash[..]); - - k = Scalar::from_hash(h); - s = &(&k * &self.key) + &r; - - Signature{ R, s } - } - -} - -#[cfg(feature = "serde")] -impl Serialize for ExpandedSecretKey { - fn serialize(&self, serializer: S) -> Result where S: Serializer { - serializer.serialize_bytes(&self.to_bytes()[..]) - } -} - -#[cfg(feature = "serde")] -impl<'d> Deserialize<'d> for ExpandedSecretKey { - fn deserialize(deserializer: D) -> Result where D: Deserializer<'d> { - struct ExpandedSecretKeyVisitor; - - impl<'d> Visitor<'d> for ExpandedSecretKeyVisitor { - type Value = ExpandedSecretKey; - - fn expecting(&self, formatter: &mut ::core::fmt::Formatter<'_>) -> ::core::fmt::Result { - formatter.write_str("An ed25519 expanded secret key as 64 bytes, as specified in RFC8032.") - } - - fn visit_bytes(self, bytes: &[u8]) -> Result where E: SerdeError { - ExpandedSecretKey::from_bytes(bytes).or(Err(SerdeError::invalid_length(bytes.len(), &self))) - } - } - deserializer.deserialize_bytes(ExpandedSecretKeyVisitor) - } -} - /// An ed25519 public key. #[derive(Copy, Clone, Default, Eq, PartialEq)] pub struct PublicKey( @@ -1227,6 +726,8 @@ impl<'d> Deserialize<'d> for Keypair { mod test { use super::*; + use clear_on_drop::clear::Clear; + #[test] fn keypair_clear_on_drop() { let mut keypair: Keypair = Keypair::from_bytes(&[1u8; KEYPAIR_LENGTH][..]).unwrap(); diff --git a/src/lib.rs b/src/lib.rs index 462ae40..b12a0f6 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -259,6 +259,7 @@ extern crate serde; mod constants; mod ed25519; +mod secret; mod signature; pub mod errors; diff --git a/src/secret.rs b/src/secret.rs new file mode 100644 index 0000000..e953baa --- /dev/null +++ b/src/secret.rs @@ -0,0 +1,540 @@ +// -*- mode: rust; -*- +// +// This file is part of ed25519-dalek. +// Copyright (c) 2017-2018 isis lovecruft +// See LICENSE for licensing information. +// +// Authors: +// - isis agora lovecruft + +//! ed25519 secret key types. + +use core::fmt::Debug; + +use clear_on_drop::clear::Clear; + +use curve25519_dalek::constants; +use curve25519_dalek::digest::Digest; +use curve25519_dalek::digest::generic_array::typenum::U64; +use curve25519_dalek::edwards::CompressedEdwardsY; +use curve25519_dalek::scalar::Scalar; + +use rand::CryptoRng; +use rand::Rng; + +use sha2::Sha512; + +#[cfg(feature = "serde")] +use serde::{Serialize, Deserialize}; +#[cfg(feature = "serde")] +use serde::{Serializer, Deserializer}; +#[cfg(feature = "serde")] +use serde::de::Error as SerdeError; +#[cfg(feature = "serde")] +use serde::de::Visitor; + +use crate::constants::*; +use crate::errors::*; +use crate::signature::*; + +use crate::PublicKey; + +/// An EdDSA secret key. +#[derive(Default)] // we derive Default in order to use the clear() method in Drop +pub struct SecretKey(pub (crate) [u8; SECRET_KEY_LENGTH]); + +impl Debug for SecretKey { + fn fmt(&self, f: &mut ::core::fmt::Formatter<'_>) -> ::core::fmt::Result { + write!(f, "SecretKey: {:?}", &self.0[..]) + } +} + +/// Overwrite secret key material with null bytes when it goes out of scope. +impl Drop for SecretKey { + fn drop(&mut self) { + self.0.clear(); + } +} + +impl AsRef<[u8]> for SecretKey { + fn as_ref(&self) -> &[u8] { + self.as_bytes() + } +} + +impl SecretKey { + /// Convert this secret key to a byte array. + #[inline] + pub fn to_bytes(&self) -> [u8; SECRET_KEY_LENGTH] { + self.0 + } + + /// View this secret key as a byte array. + #[inline] + pub fn as_bytes<'a>(&'a self) -> &'a [u8; SECRET_KEY_LENGTH] { + &self.0 + } + + /// Construct a `SecretKey` from a slice of bytes. + /// + /// # Example + /// + /// ``` + /// # extern crate ed25519_dalek; + /// # + /// use ed25519_dalek::SecretKey; + /// use ed25519_dalek::SECRET_KEY_LENGTH; + /// use ed25519_dalek::SignatureError; + /// + /// # fn doctest() -> Result { + /// let secret_key_bytes: [u8; SECRET_KEY_LENGTH] = [ + /// 157, 097, 177, 157, 239, 253, 090, 096, + /// 186, 132, 074, 244, 146, 236, 044, 196, + /// 068, 073, 197, 105, 123, 050, 105, 025, + /// 112, 059, 172, 003, 028, 174, 127, 096, ]; + /// + /// let secret_key: SecretKey = SecretKey::from_bytes(&secret_key_bytes)?; + /// # + /// # Ok(secret_key) + /// # } + /// # + /// # fn main() { + /// # let result = doctest(); + /// # assert!(result.is_ok()); + /// # } + /// ``` + /// + /// # Returns + /// + /// A `Result` whose okay value is an EdDSA `SecretKey` or whose error value + /// is an `SignatureError` wrapping the internal error that occurred. + #[inline] + pub fn from_bytes(bytes: &[u8]) -> Result { + if bytes.len() != SECRET_KEY_LENGTH { + return Err(SignatureError(InternalError::BytesLengthError{ + name: "SecretKey", length: SECRET_KEY_LENGTH })); + } + let mut bits: [u8; 32] = [0u8; 32]; + bits.copy_from_slice(&bytes[..32]); + + Ok(SecretKey(bits)) + } + + /// Generate a `SecretKey` from a `csprng`. + /// + /// # Example + /// + /// ``` + /// extern crate rand; + /// extern crate sha2; + /// extern crate ed25519_dalek; + /// + /// # #[cfg(feature = "std")] + /// # fn main() { + /// # + /// use rand::Rng; + /// use rand::rngs::OsRng; + /// use sha2::Sha512; + /// use ed25519_dalek::PublicKey; + /// use ed25519_dalek::SecretKey; + /// use ed25519_dalek::Signature; + /// + /// let mut csprng: OsRng = OsRng::new().unwrap(); + /// let secret_key: SecretKey = SecretKey::generate(&mut csprng); + /// # } + /// # + /// # #[cfg(not(feature = "std"))] + /// # fn main() { } + /// ``` + /// + /// Afterwards, you can generate the corresponding public: + /// + /// ``` + /// # extern crate rand; + /// # extern crate ed25519_dalek; + /// # + /// # fn main() { + /// # + /// # use rand::Rng; + /// # use rand::thread_rng; + /// # use ed25519_dalek::PublicKey; + /// # use ed25519_dalek::SecretKey; + /// # use ed25519_dalek::Signature; + /// # + /// # let mut csprng = thread_rng(); + /// # let secret_key: SecretKey = SecretKey::generate(&mut csprng); + /// + /// let public_key: PublicKey = (&secret_key).into(); + /// # } + /// ``` + /// + /// # Input + /// + /// A CSPRNG with a `fill_bytes()` method, e.g. `rand::OsRng` + pub fn generate(csprng: &mut T) -> SecretKey + where T: CryptoRng + Rng, + { + let mut sk: SecretKey = SecretKey([0u8; 32]); + + csprng.fill_bytes(&mut sk.0); + + sk + } +} + +#[cfg(feature = "serde")] +impl Serialize for SecretKey { + fn serialize(&self, serializer: S) -> Result where S: Serializer { + serializer.serialize_bytes(self.as_bytes()) + } +} + +#[cfg(feature = "serde")] +impl<'d> Deserialize<'d> for SecretKey { + fn deserialize(deserializer: D) -> Result where D: Deserializer<'d> { + struct SecretKeyVisitor; + + impl<'d> Visitor<'d> for SecretKeyVisitor { + type Value = SecretKey; + + fn expecting(&self, formatter: &mut ::core::fmt::Formatter<'_>) -> ::core::fmt::Result { + formatter.write_str("An ed25519 secret key as 32 bytes, as specified in RFC8032.") + } + + fn visit_bytes(self, bytes: &[u8]) -> Result where E: SerdeError { + SecretKey::from_bytes(bytes).or(Err(SerdeError::invalid_length(bytes.len(), &self))) + } + } + deserializer.deserialize_bytes(SecretKeyVisitor) + } +} + +/// An "expanded" secret key. +/// +/// This is produced by using an hash function with 512-bits output to digest a +/// `SecretKey`. The output digest is then split in half, the lower half being +/// the actual `key` used to sign messages, after twiddling with some bits.¹ The +/// upper half is used a sort of half-baked, ill-designed² pseudo-domain-separation +/// "nonce"-like thing, which is used during signature production by +/// concatenating it with the message to be signed before the message is hashed. +// +// ¹ This results in a slight bias towards non-uniformity at one spectrum of +// the range of valid keys. Oh well: not my idea; not my problem. +// +// ² It is the author's view (specifically, isis agora lovecruft, in the event +// you'd like to complain about me, again) that this is "ill-designed" because +// this doesn't actually provide true hash domain separation, in that in many +// real-world applications a user wishes to have one key which is used in +// several contexts (such as within tor, which does does domain separation +// manually by pre-concatenating static strings to messages to achieve more +// robust domain separation). In other real-world applications, such as +// bitcoind, a user might wish to have one master keypair from which others are +// derived (à la BIP32) and different domain separators between keys derived at +// different levels (and similarly for tree-based key derivation constructions, +// such as hash-based signatures). Leaving the domain separation to +// application designers, who thus far have produced incompatible, +// slightly-differing, ad hoc domain separation (at least those application +// designers who knew enough cryptographic theory to do so!), is therefore a +// bad design choice on the part of the cryptographer designing primitives +// which should be simple and as foolproof as possible to use for +// non-cryptographers. Further, later in the ed25519 signature scheme, as +// specified in RFC8032, the public key is added into *another* hash digest +// (along with the message, again); it is unclear to this author why there's +// not only one but two poorly-thought-out attempts at domain separation in the +// same signature scheme, and which both fail in exactly the same way. For a +// better-designed, Schnorr-based signature scheme, see Trevor Perrin's work on +// "generalised EdDSA" and "VXEdDSA". +#[derive(Default)] // we derive Default in order to use the clear() method in Drop +pub struct ExpandedSecretKey { + pub (crate) key: Scalar, + pub (crate) nonce: [u8; 32], +} + +/// Overwrite secret key material with null bytes when it goes out of scope. +impl Drop for ExpandedSecretKey { + fn drop(&mut self) { + self.key.clear(); + self.nonce.clear(); + } +} + +impl<'a> From<&'a SecretKey> for ExpandedSecretKey { + /// Construct an `ExpandedSecretKey` from a `SecretKey`. + /// + /// # Examples + /// + /// ``` + /// # extern crate rand; + /// # extern crate sha2; + /// # extern crate ed25519_dalek; + /// # + /// # fn main() { + /// # + /// use rand::Rng; + /// use rand::thread_rng; + /// use sha2::Sha512; + /// use ed25519_dalek::{SecretKey, ExpandedSecretKey}; + /// + /// let mut csprng = thread_rng(); + /// let secret_key: SecretKey = SecretKey::generate(&mut csprng); + /// let expanded_secret_key: ExpandedSecretKey = ExpandedSecretKey::from(&secret_key); + /// # } + /// ``` + fn from(secret_key: &'a SecretKey) -> ExpandedSecretKey { + let mut h: Sha512 = Sha512::default(); + let mut hash: [u8; 64] = [0u8; 64]; + let mut lower: [u8; 32] = [0u8; 32]; + let mut upper: [u8; 32] = [0u8; 32]; + + h.input(secret_key.as_bytes()); + hash.copy_from_slice(h.result().as_slice()); + + lower.copy_from_slice(&hash[00..32]); + upper.copy_from_slice(&hash[32..64]); + + lower[0] &= 248; + lower[31] &= 63; + lower[31] |= 64; + + ExpandedSecretKey{ key: Scalar::from_bits(lower), nonce: upper, } + } +} + +impl ExpandedSecretKey { + /// Convert this `ExpandedSecretKey` into an array of 64 bytes. + /// + /// # Returns + /// + /// An array of 64 bytes. The first 32 bytes represent the "expanded" + /// secret key, and the last 32 bytes represent the "domain-separation" + /// "nonce". + /// + /// # Examples + /// + /// ``` + /// # extern crate rand; + /// # extern crate sha2; + /// # extern crate ed25519_dalek; + /// # + /// # #[cfg(all(feature = "sha2", feature = "std"))] + /// # fn main() { + /// # + /// use rand::Rng; + /// use rand::rngs::OsRng; + /// use sha2::Sha512; + /// use ed25519_dalek::{SecretKey, ExpandedSecretKey}; + /// + /// let mut csprng: OsRng = OsRng::new().unwrap(); + /// let secret_key: SecretKey = SecretKey::generate(&mut csprng); + /// let expanded_secret_key: ExpandedSecretKey = ExpandedSecretKey::from(&secret_key); + /// let expanded_secret_key_bytes: [u8; 64] = expanded_secret_key.to_bytes(); + /// + /// assert!(&expanded_secret_key_bytes[..] != &[0u8; 64][..]); + /// # } + /// # + /// # #[cfg(any(not(feature = "sha2"), not(feature = "std")))] + /// # fn main() { } + /// ``` + #[inline] + pub fn to_bytes(&self) -> [u8; EXPANDED_SECRET_KEY_LENGTH] { + let mut bytes: [u8; 64] = [0u8; 64]; + + bytes[..32].copy_from_slice(self.key.as_bytes()); + bytes[32..].copy_from_slice(&self.nonce[..]); + bytes + } + + /// Construct an `ExpandedSecretKey` from a slice of bytes. + /// + /// # Returns + /// + /// A `Result` whose okay value is an EdDSA `ExpandedSecretKey` or whose + /// error value is an `SignatureError` describing the error that occurred. + /// + /// # Examples + /// + /// ``` + /// # extern crate rand; + /// # extern crate sha2; + /// # extern crate ed25519_dalek; + /// # + /// # use ed25519_dalek::{ExpandedSecretKey, SignatureError}; + /// # + /// # #[cfg(all(feature = "sha2", feature = "std"))] + /// # fn do_test() -> Result { + /// # + /// use rand::Rng; + /// use rand::rngs::OsRng; + /// use ed25519_dalek::{SecretKey, ExpandedSecretKey}; + /// use ed25519_dalek::SignatureError; + /// + /// let mut csprng: OsRng = OsRng::new().unwrap(); + /// let secret_key: SecretKey = SecretKey::generate(&mut csprng); + /// let expanded_secret_key: ExpandedSecretKey = ExpandedSecretKey::from(&secret_key); + /// let bytes: [u8; 64] = expanded_secret_key.to_bytes(); + /// let expanded_secret_key_again = ExpandedSecretKey::from_bytes(&bytes)?; + /// # + /// # Ok(expanded_secret_key_again) + /// # } + /// # + /// # #[cfg(all(feature = "sha2", feature = "std"))] + /// # fn main() { + /// # let result = do_test(); + /// # assert!(result.is_ok()); + /// # } + /// # + /// # #[cfg(any(not(feature = "sha2"), not(feature = "std")))] + /// # fn main() { } + /// ``` + #[inline] + pub fn from_bytes(bytes: &[u8]) -> Result { + if bytes.len() != EXPANDED_SECRET_KEY_LENGTH { + return Err(SignatureError(InternalError::BytesLengthError{ + name: "ExpandedSecretKey", length: EXPANDED_SECRET_KEY_LENGTH })); + } + let mut lower: [u8; 32] = [0u8; 32]; + let mut upper: [u8; 32] = [0u8; 32]; + + lower.copy_from_slice(&bytes[00..32]); + upper.copy_from_slice(&bytes[32..64]); + + Ok(ExpandedSecretKey{ key: Scalar::from_bits(lower), + nonce: upper }) + } + + /// Sign a message with this `ExpandedSecretKey`. + #[allow(non_snake_case)] + pub fn sign(&self, message: &[u8], public_key: &PublicKey) -> Signature { + let mut h: Sha512 = Sha512::new(); + let R: CompressedEdwardsY; + let r: Scalar; + let s: Scalar; + let k: Scalar; + + h.input(&self.nonce); + h.input(&message); + + r = Scalar::from_hash(h); + R = (&r * &constants::ED25519_BASEPOINT_TABLE).compress(); + + h = Sha512::new(); + h.input(R.as_bytes()); + h.input(public_key.as_bytes()); + h.input(&message); + + k = Scalar::from_hash(h); + s = &(&k * &self.key) + &r; + + Signature{ R, s } + } + + /// Sign a `prehashed_message` with this `ExpandedSecretKey` using the + /// Ed25519ph algorithm defined in [RFC8032 §5.1][rfc8032]. + /// + /// # Inputs + /// + /// * `prehashed_message` is an instantiated hash digest with 512-bits of + /// output which has had the message to be signed previously fed into its + /// state. + /// * `public_key` is a [`PublicKey`] which corresponds to this secret key. + /// * `context` is an optional context string, up to 255 bytes inclusive, + /// which may be used to provide additional domain separation. If not + /// set, this will default to an empty string. + /// + /// # Returns + /// + /// An Ed25519ph [`Signature`] on the `prehashed_message`. + /// + /// [rfc8032]: https://tools.ietf.org/html/rfc8032#section-5.1 + #[allow(non_snake_case)] + pub fn sign_prehashed( + &self, + prehashed_message: D, + public_key: &PublicKey, + context: Option<&'static [u8]>, + ) -> Signature + where + D: Digest, + { + let mut h: Sha512; + let mut prehash: [u8; 64] = [0u8; 64]; + let R: CompressedEdwardsY; + let r: Scalar; + let s: Scalar; + let k: Scalar; + + let ctx: &[u8] = context.unwrap_or(b""); // By default, the context is an empty string. + + debug_assert!(ctx.len() <= 255, "The context must not be longer than 255 octets."); + + let ctx_len: u8 = ctx.len() as u8; + + // Get the result of the pre-hashed message. + prehash.copy_from_slice(prehashed_message.result().as_slice()); + + // This is the dumbest, ten-years-late, non-admission of fucking up the + // domain separation I have ever seen. Why am I still required to put + // the upper half "prefix" of the hashed "secret key" in here? Why + // can't the user just supply their own nonce and decide for themselves + // whether or not they want a deterministic signature scheme? Why does + // the message go into what's ostensibly the signature domain separation + // hash? Why wasn't there always a way to provide a context string? + // + // ... + // + // This is a really fucking stupid bandaid, and the damned scheme is + // still bleeding from malleability, for fuck's sake. + h = Sha512::new() + .chain(b"SigEd25519 no Ed25519 collisions") + .chain(&[1]) // Ed25519ph + .chain(&[ctx_len]) + .chain(ctx) + .chain(&self.nonce) + .chain(&prehash[..]); + + r = Scalar::from_hash(h); + R = (&r * &constants::ED25519_BASEPOINT_TABLE).compress(); + + h = Sha512::new() + .chain(b"SigEd25519 no Ed25519 collisions") + .chain(&[1]) // Ed25519ph + .chain(&[ctx_len]) + .chain(ctx) + .chain(R.as_bytes()) + .chain(public_key.as_bytes()) + .chain(&prehash[..]); + + k = Scalar::from_hash(h); + s = &(&k * &self.key) + &r; + + Signature{ R, s } + } + +} + +#[cfg(feature = "serde")] +impl Serialize for ExpandedSecretKey { + fn serialize(&self, serializer: S) -> Result where S: Serializer { + serializer.serialize_bytes(&self.to_bytes()[..]) + } +} + +#[cfg(feature = "serde")] +impl<'d> Deserialize<'d> for ExpandedSecretKey { + fn deserialize(deserializer: D) -> Result where D: Deserializer<'d> { + struct ExpandedSecretKeyVisitor; + + impl<'d> Visitor<'d> for ExpandedSecretKeyVisitor { + type Value = ExpandedSecretKey; + + fn expecting(&self, formatter: &mut ::core::fmt::Formatter<'_>) -> ::core::fmt::Result { + formatter.write_str("An ed25519 expanded secret key as 64 bytes, as specified in RFC8032.") + } + + fn visit_bytes(self, bytes: &[u8]) -> Result where E: SerdeError { + ExpandedSecretKey::from_bytes(bytes).or(Err(SerdeError::invalid_length(bytes.len(), &self))) + } + } + deserializer.deserialize_bytes(ExpandedSecretKeyVisitor) + } +} From 6fea2e1ea0866a118679e3cc051ee273430f2a3e Mon Sep 17 00:00:00 2001 From: Isis Lovecruft Date: Sun, 30 Dec 2018 03:41:00 +0000 Subject: [PATCH 27/43] Realphabetise extern crates. --- src/lib.rs | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/src/lib.rs b/src/lib.rs index b12a0f6..806979d 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -243,17 +243,15 @@ #![warn(rust_2018_idioms)] #![deny(missing_docs)] // refuse to compile if documentation is missing -extern crate clear_on_drop; -extern crate curve25519_dalek; -extern crate failure; -extern crate rand; - #[cfg(any(feature = "std", test))] #[macro_use] extern crate std; +extern crate clear_on_drop; +extern crate curve25519_dalek; +extern crate failure; +extern crate rand; extern crate sha2; - #[cfg(feature = "serde")] extern crate serde; From e3d7c16aaccc9dd87426f6ebacc469541c1d87a1 Mon Sep 17 00:00:00 2001 From: Isis Lovecruft Date: Sun, 30 Dec 2018 03:41:13 +0000 Subject: [PATCH 28/43] Make errors module private. --- src/lib.rs | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/lib.rs b/src/lib.rs index 806979d..db1b291 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -257,10 +257,9 @@ extern crate serde; mod constants; mod ed25519; +mod errors; mod secret; mod signature; -pub mod errors; - // Export everything public in ed25519. pub use crate::ed25519::*; From e6528bd68305c04c90c088a086773cc22a1cb71e Mon Sep 17 00:00:00 2001 From: Isis Lovecruft Date: Sun, 30 Dec 2018 03:53:11 +0000 Subject: [PATCH 29/43] Create new module for public key code. --- src/ed25519.rs | 242 +------------------------------------------ src/lib.rs | 1 + src/public.rs | 272 +++++++++++++++++++++++++++++++++++++++++++++++++ src/secret.rs | 3 +- 4 files changed, 275 insertions(+), 243 deletions(-) create mode 100644 src/public.rs diff --git a/src/ed25519.rs b/src/ed25519.rs index e992c17..a6d5f31 100644 --- a/src/ed25519.rs +++ b/src/ed25519.rs @@ -10,7 +10,6 @@ //! A Rust implementation of ed25519 key generation, signing, and verification. use core::default::Default; -use core::fmt::Debug; use rand::CryptoRng; use rand::Rng; @@ -30,226 +29,15 @@ pub use curve25519_dalek::digest::Digest; use curve25519_dalek::digest::generic_array::typenum::U64; use curve25519_dalek::constants; -use curve25519_dalek::edwards::CompressedEdwardsY; use curve25519_dalek::edwards::EdwardsPoint; use curve25519_dalek::scalar::Scalar; pub use crate::constants::*; pub use crate::errors::*; +pub use crate::public::*; pub use crate::secret::*; pub use crate::signature::*; -/// An ed25519 public key. -#[derive(Copy, Clone, Default, Eq, PartialEq)] -pub struct PublicKey( - pub (crate) CompressedEdwardsY, - pub (crate) EdwardsPoint, -); - -impl Debug for PublicKey { - fn fmt(&self, f: &mut ::core::fmt::Formatter<'_>) -> ::core::fmt::Result { - write!(f, "PublicKey({:?}), {:?})", self.0, self.1) - } -} - -impl AsRef<[u8]> for PublicKey { - fn as_ref(&self) -> &[u8] { - self.as_bytes() - } -} - -impl PublicKey { - /// Convert this public key to a byte array. - #[inline] - pub fn to_bytes(&self) -> [u8; PUBLIC_KEY_LENGTH] { - self.0.to_bytes() - } - - /// View this public key as a byte array. - #[inline] - pub fn as_bytes<'a>(&'a self) -> &'a [u8; PUBLIC_KEY_LENGTH] { - &(self.0).0 - } - - /// Construct a `PublicKey` from a slice of bytes. - /// - /// # Warning - /// - /// The caller is responsible for ensuring that the bytes passed into this - /// method actually represent a `curve25519_dalek::curve::CompressedEdwardsY` - /// and that said compressed point is actually a point on the curve. - /// - /// # Example - /// - /// ``` - /// # extern crate ed25519_dalek; - /// # - /// use ed25519_dalek::PublicKey; - /// use ed25519_dalek::PUBLIC_KEY_LENGTH; - /// use ed25519_dalek::SignatureError; - /// - /// # fn doctest() -> Result { - /// let public_key_bytes: [u8; PUBLIC_KEY_LENGTH] = [ - /// 215, 90, 152, 1, 130, 177, 10, 183, 213, 75, 254, 211, 201, 100, 7, 58, - /// 14, 225, 114, 243, 218, 166, 35, 37, 175, 2, 26, 104, 247, 7, 81, 26]; - /// - /// let public_key = PublicKey::from_bytes(&public_key_bytes)?; - /// # - /// # Ok(public_key) - /// # } - /// # - /// # fn main() { - /// # doctest(); - /// # } - /// ``` - /// - /// # Returns - /// - /// A `Result` whose okay value is an EdDSA `PublicKey` or whose error value - /// is an `SignatureError` describing the error that occurred. - #[inline] - pub fn from_bytes(bytes: &[u8]) -> Result { - if bytes.len() != PUBLIC_KEY_LENGTH { - return Err(SignatureError(InternalError::BytesLengthError{ - name: "PublicKey", length: PUBLIC_KEY_LENGTH })); - } - let mut bits: [u8; 32] = [0u8; 32]; - bits.copy_from_slice(&bytes[..32]); - - let compressed = CompressedEdwardsY(bits); - let point = compressed.decompress().ok_or(SignatureError(InternalError::PointDecompressionError))?; - - Ok(PublicKey(compressed, point)) - } -} - -impl<'a> From<&'a SecretKey> for PublicKey { - /// Derive this public key from its corresponding `SecretKey`. - fn from(secret_key: &SecretKey) -> PublicKey { - let mut h: Sha512 = Sha512::new(); - let mut hash: [u8; 64] = [0u8; 64]; - let mut digest: [u8; 32] = [0u8; 32]; - - h.input(secret_key.as_bytes()); - hash.copy_from_slice(h.result().as_slice()); - - digest.copy_from_slice(&hash[..32]); - - PublicKey::mangle_scalar_bits_and_multiply_by_basepoint_to_produce_public_key(&mut digest) - } -} - -impl<'a> From<&'a ExpandedSecretKey> for PublicKey { - /// Derive this public key from its corresponding `ExpandedSecretKey`. - fn from(expanded_secret_key: &ExpandedSecretKey) -> PublicKey { - let mut bits: [u8; 32] = expanded_secret_key.key.to_bytes(); - - PublicKey::mangle_scalar_bits_and_multiply_by_basepoint_to_produce_public_key(&mut bits) - } -} - -impl PublicKey { - /// Internal utility function for mangling the bits of a (formerly - /// mathematically well-defined) "scalar" and multiplying it to produce a - /// public key. - fn mangle_scalar_bits_and_multiply_by_basepoint_to_produce_public_key(bits: &mut [u8; 32]) -> PublicKey { - bits[0] &= 248; - bits[31] &= 127; - bits[31] |= 64; - - let point = &Scalar::from_bits(*bits) * &constants::ED25519_BASEPOINT_TABLE; - let compressed = point.compress(); - - PublicKey(compressed, point) - } - - /// Verify a signature on a message with this keypair's public key. - /// - /// # Return - /// - /// Returns `Ok(())` if the signature is valid, and `Err` otherwise. - #[allow(non_snake_case)] - pub fn verify( - &self, - message: &[u8], - signature: &Signature - ) -> Result<(), SignatureError> - { - let mut h: Sha512 = Sha512::new(); - let R: EdwardsPoint; - let k: Scalar; - let minus_A: EdwardsPoint = -self.1; - - h.input(signature.R.as_bytes()); - h.input(self.as_bytes()); - h.input(&message); - - k = Scalar::from_hash(h); - R = EdwardsPoint::vartime_double_scalar_mul_basepoint(&k, &(minus_A), &signature.s); - - if R.compress() == signature.R { - Ok(()) - } else { - Err(SignatureError(InternalError::VerifyError)) - } - } - - /// Verify a `signature` on a `prehashed_message` using the Ed25519ph algorithm. - /// - /// # Inputs - /// - /// * `prehashed_message` is an instantiated hash digest with 512-bits of - /// output which has had the message to be signed previously fed into its - /// state. - /// * `context` is an optional context string, up to 255 bytes inclusive, - /// which may be used to provide additional domain separation. If not - /// set, this will default to an empty string. - /// * `signature` is a purported Ed25519ph [`Signature`] on the `prehashed_message`. - /// - /// # Returns - /// - /// Returns `true` if the `signature` was a valid signature created by this - /// `Keypair` on the `prehashed_message`. - /// - /// [rfc8032]: https://tools.ietf.org/html/rfc8032#section-5.1 - #[allow(non_snake_case)] - pub fn verify_prehashed( - &self, - prehashed_message: D, - context: Option<&[u8]>, - signature: &Signature, - ) -> Result<(), SignatureError> - where - D: Digest, - { - let mut h: Sha512 = Sha512::default(); - let R: EdwardsPoint; - let k: Scalar; - - let ctx: &[u8] = context.unwrap_or(b""); - debug_assert!(ctx.len() <= 255, "The context must not be longer than 255 octets."); - - let minus_A: EdwardsPoint = -self.1; - - h.input(b"SigEd25519 no Ed25519 collisions"); - h.input(&[1]); // Ed25519ph - h.input(&[ctx.len() as u8]); - h.input(ctx); - h.input(signature.R.as_bytes()); - h.input(self.as_bytes()); - h.input(prehashed_message.result().as_slice()); - - k = Scalar::from_hash(h); - R = EdwardsPoint::vartime_double_scalar_mul_basepoint(&k, &(minus_A), &signature.s); - - if R.compress() == signature.R { - Ok(()) - } else { - Err(SignatureError(InternalError::VerifyError)) - } - } -} - /// Verify a batch of `signatures` on `messages` with their respective `public_keys`. /// /// # Inputs @@ -363,34 +151,6 @@ pub fn verify_batch( } } -#[cfg(feature = "serde")] -impl Serialize for PublicKey { - fn serialize(&self, serializer: S) -> Result where S: Serializer { - serializer.serialize_bytes(self.as_bytes()) - } -} - -#[cfg(feature = "serde")] -impl<'d> Deserialize<'d> for PublicKey { - fn deserialize(deserializer: D) -> Result where D: Deserializer<'d> { - - struct PublicKeyVisitor; - - impl<'d> Visitor<'d> for PublicKeyVisitor { - type Value = PublicKey; - - fn expecting(&self, formatter: &mut ::core::fmt::Formatter<'_>) -> ::core::fmt::Result { - formatter.write_str("An ed25519 public key as a 32-byte compressed point, as specified in RFC8032") - } - - fn visit_bytes(self, bytes: &[u8]) -> Result where E: SerdeError { - PublicKey::from_bytes(bytes).or(Err(SerdeError::invalid_length(bytes.len(), &self))) - } - } - deserializer.deserialize_bytes(PublicKeyVisitor) - } -} - /// An ed25519 keypair. #[derive(Debug, Default)] // we derive Default in order to use the clear() method in Drop pub struct Keypair { diff --git a/src/lib.rs b/src/lib.rs index db1b291..de05f8b 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -258,6 +258,7 @@ extern crate serde; mod constants; mod ed25519; mod errors; +mod public; mod secret; mod signature; diff --git a/src/public.rs b/src/public.rs new file mode 100644 index 0000000..60e504a --- /dev/null +++ b/src/public.rs @@ -0,0 +1,272 @@ +// -*- mode: rust; -*- +// +// This file is part of ed25519-dalek. +// Copyright (c) 2017-2018 isis lovecruft +// See LICENSE for licensing information. +// +// Authors: +// - isis agora lovecruft + +//! ed25519 public keys. + +use core::fmt::Debug; + +use curve25519_dalek::constants; +use curve25519_dalek::digest::Digest; +use curve25519_dalek::digest::generic_array::typenum::U64; +use curve25519_dalek::edwards::CompressedEdwardsY; +use curve25519_dalek::edwards::EdwardsPoint; +use curve25519_dalek::scalar::Scalar; + +pub use sha2::Sha512; + +#[cfg(feature = "serde")] +use serde::{Serialize, Deserialize}; +#[cfg(feature = "serde")] +use serde::{Serializer, Deserializer}; +#[cfg(feature = "serde")] +use serde::de::Error as SerdeError; +#[cfg(feature = "serde")] +use serde::de::Visitor; + +use crate::constants::*; +use crate::errors::*; +use crate::secret::*; +use crate::signature::*; + +/// An ed25519 public key. +#[derive(Copy, Clone, Default, Eq, PartialEq)] +pub struct PublicKey( + pub (crate) CompressedEdwardsY, + pub (crate) EdwardsPoint, +); + +impl Debug for PublicKey { + fn fmt(&self, f: &mut ::core::fmt::Formatter<'_>) -> ::core::fmt::Result { + write!(f, "PublicKey({:?}), {:?})", self.0, self.1) + } +} + +impl AsRef<[u8]> for PublicKey { + fn as_ref(&self) -> &[u8] { + self.as_bytes() + } +} + +impl<'a> From<&'a SecretKey> for PublicKey { + /// Derive this public key from its corresponding `SecretKey`. + fn from(secret_key: &SecretKey) -> PublicKey { + let mut h: Sha512 = Sha512::new(); + let mut hash: [u8; 64] = [0u8; 64]; + let mut digest: [u8; 32] = [0u8; 32]; + + h.input(secret_key.as_bytes()); + hash.copy_from_slice(h.result().as_slice()); + + digest.copy_from_slice(&hash[..32]); + + PublicKey::mangle_scalar_bits_and_multiply_by_basepoint_to_produce_public_key(&mut digest) + } +} + +impl<'a> From<&'a ExpandedSecretKey> for PublicKey { + /// Derive this public key from its corresponding `ExpandedSecretKey`. + fn from(expanded_secret_key: &ExpandedSecretKey) -> PublicKey { + let mut bits: [u8; 32] = expanded_secret_key.key.to_bytes(); + + PublicKey::mangle_scalar_bits_and_multiply_by_basepoint_to_produce_public_key(&mut bits) + } +} + +impl PublicKey { + /// Convert this public key to a byte array. + #[inline] + pub fn to_bytes(&self) -> [u8; PUBLIC_KEY_LENGTH] { + self.0.to_bytes() + } + + /// View this public key as a byte array. + #[inline] + pub fn as_bytes<'a>(&'a self) -> &'a [u8; PUBLIC_KEY_LENGTH] { + &(self.0).0 + } + + /// Construct a `PublicKey` from a slice of bytes. + /// + /// # Warning + /// + /// The caller is responsible for ensuring that the bytes passed into this + /// method actually represent a `curve25519_dalek::curve::CompressedEdwardsY` + /// and that said compressed point is actually a point on the curve. + /// + /// # Example + /// + /// ``` + /// # extern crate ed25519_dalek; + /// # + /// use ed25519_dalek::PublicKey; + /// use ed25519_dalek::PUBLIC_KEY_LENGTH; + /// use ed25519_dalek::SignatureError; + /// + /// # fn doctest() -> Result { + /// let public_key_bytes: [u8; PUBLIC_KEY_LENGTH] = [ + /// 215, 90, 152, 1, 130, 177, 10, 183, 213, 75, 254, 211, 201, 100, 7, 58, + /// 14, 225, 114, 243, 218, 166, 35, 37, 175, 2, 26, 104, 247, 7, 81, 26]; + /// + /// let public_key = PublicKey::from_bytes(&public_key_bytes)?; + /// # + /// # Ok(public_key) + /// # } + /// # + /// # fn main() { + /// # doctest(); + /// # } + /// ``` + /// + /// # Returns + /// + /// A `Result` whose okay value is an EdDSA `PublicKey` or whose error value + /// is an `SignatureError` describing the error that occurred. + #[inline] + pub fn from_bytes(bytes: &[u8]) -> Result { + if bytes.len() != PUBLIC_KEY_LENGTH { + return Err(SignatureError(InternalError::BytesLengthError{ + name: "PublicKey", length: PUBLIC_KEY_LENGTH })); + } + let mut bits: [u8; 32] = [0u8; 32]; + bits.copy_from_slice(&bytes[..32]); + + let compressed = CompressedEdwardsY(bits); + let point = compressed.decompress().ok_or(SignatureError(InternalError::PointDecompressionError))?; + + Ok(PublicKey(compressed, point)) + } + + /// Internal utility function for mangling the bits of a (formerly + /// mathematically well-defined) "scalar" and multiplying it to produce a + /// public key. + fn mangle_scalar_bits_and_multiply_by_basepoint_to_produce_public_key(bits: &mut [u8; 32]) -> PublicKey { + bits[0] &= 248; + bits[31] &= 127; + bits[31] |= 64; + + let point = &Scalar::from_bits(*bits) * &constants::ED25519_BASEPOINT_TABLE; + let compressed = point.compress(); + + PublicKey(compressed, point) + } + + /// Verify a signature on a message with this keypair's public key. + /// + /// # Return + /// + /// Returns `Ok(())` if the signature is valid, and `Err` otherwise. + #[allow(non_snake_case)] + pub fn verify( + &self, + message: &[u8], + signature: &Signature + ) -> Result<(), SignatureError> + { + let mut h: Sha512 = Sha512::new(); + let R: EdwardsPoint; + let k: Scalar; + let minus_A: EdwardsPoint = -self.1; + + h.input(signature.R.as_bytes()); + h.input(self.as_bytes()); + h.input(&message); + + k = Scalar::from_hash(h); + R = EdwardsPoint::vartime_double_scalar_mul_basepoint(&k, &(minus_A), &signature.s); + + if R.compress() == signature.R { + Ok(()) + } else { + Err(SignatureError(InternalError::VerifyError)) + } + } + + /// Verify a `signature` on a `prehashed_message` using the Ed25519ph algorithm. + /// + /// # Inputs + /// + /// * `prehashed_message` is an instantiated hash digest with 512-bits of + /// output which has had the message to be signed previously fed into its + /// state. + /// * `context` is an optional context string, up to 255 bytes inclusive, + /// which may be used to provide additional domain separation. If not + /// set, this will default to an empty string. + /// * `signature` is a purported Ed25519ph [`Signature`] on the `prehashed_message`. + /// + /// # Returns + /// + /// Returns `true` if the `signature` was a valid signature created by this + /// `Keypair` on the `prehashed_message`. + /// + /// [rfc8032]: https://tools.ietf.org/html/rfc8032#section-5.1 + #[allow(non_snake_case)] + pub fn verify_prehashed( + &self, + prehashed_message: D, + context: Option<&[u8]>, + signature: &Signature, + ) -> Result<(), SignatureError> + where + D: Digest, + { + let mut h: Sha512 = Sha512::default(); + let R: EdwardsPoint; + let k: Scalar; + + let ctx: &[u8] = context.unwrap_or(b""); + debug_assert!(ctx.len() <= 255, "The context must not be longer than 255 octets."); + + let minus_A: EdwardsPoint = -self.1; + + h.input(b"SigEd25519 no Ed25519 collisions"); + h.input(&[1]); // Ed25519ph + h.input(&[ctx.len() as u8]); + h.input(ctx); + h.input(signature.R.as_bytes()); + h.input(self.as_bytes()); + h.input(prehashed_message.result().as_slice()); + + k = Scalar::from_hash(h); + R = EdwardsPoint::vartime_double_scalar_mul_basepoint(&k, &(minus_A), &signature.s); + + if R.compress() == signature.R { + Ok(()) + } else { + Err(SignatureError(InternalError::VerifyError)) + } + } +} + +#[cfg(feature = "serde")] +impl Serialize for PublicKey { + fn serialize(&self, serializer: S) -> Result where S: Serializer { + serializer.serialize_bytes(self.as_bytes()) + } +} + +#[cfg(feature = "serde")] +impl<'d> Deserialize<'d> for PublicKey { + fn deserialize(deserializer: D) -> Result where D: Deserializer<'d> { + + struct PublicKeyVisitor; + + impl<'d> Visitor<'d> for PublicKeyVisitor { + type Value = PublicKey; + + fn expecting(&self, formatter: &mut ::core::fmt::Formatter<'_>) -> ::core::fmt::Result { + formatter.write_str("An ed25519 public key as a 32-byte compressed point, as specified in RFC8032") + } + + fn visit_bytes(self, bytes: &[u8]) -> Result where E: SerdeError { + PublicKey::from_bytes(bytes).or(Err(SerdeError::invalid_length(bytes.len(), &self))) + } + } + deserializer.deserialize_bytes(PublicKeyVisitor) + } +} diff --git a/src/secret.rs b/src/secret.rs index e953baa..d5c3e67 100644 --- a/src/secret.rs +++ b/src/secret.rs @@ -35,10 +35,9 @@ use serde::de::Visitor; use crate::constants::*; use crate::errors::*; +use crate::public::*; use crate::signature::*; -use crate::PublicKey; - /// An EdDSA secret key. #[derive(Default)] // we derive Default in order to use the clear() method in Drop pub struct SecretKey(pub (crate) [u8; SECRET_KEY_LENGTH]); From 144e87bfc809aff581c92de186f5051376eb45ee Mon Sep 17 00:00:00 2001 From: Isis Lovecruft Date: Sun, 30 Dec 2018 04:01:39 +0000 Subject: [PATCH 30/43] Remove unnecessary tests/mod.rs file. --- tests/mod.rs | 17 ----------------- 1 file changed, 17 deletions(-) delete mode 100644 tests/mod.rs diff --git a/tests/mod.rs b/tests/mod.rs deleted file mode 100644 index 8b3a9bb..0000000 --- a/tests/mod.rs +++ /dev/null @@ -1,17 +0,0 @@ -// -*- mode: rust; -*- -// -// This file is part of ed25519-dalek. -// Copyright (c) 2017-2018 isis lovecruft -// See LICENSE for licensing information. -// -// Authors: -// - isis agora lovecruft - -//! Integration tests for ed25519-dalek. - -extern crate ed25519_dalek; -extern crate hex; -extern crate rand; -extern crate sha2; - -mod ed25519; From a1418635423c0f6bb96f34de8c4d9034265e7d62 Mon Sep 17 00:00:00 2001 From: Isis Lovecruft Date: Sun, 30 Dec 2018 04:05:20 +0000 Subject: [PATCH 31/43] Run rustfmt on src/signature.rs. --- src/signature.rs | 42 +++++++++++++++++++++++++++++------------- 1 file changed, 29 insertions(+), 13 deletions(-) diff --git a/src/signature.rs b/src/signature.rs index d93b572..3dbc478 100644 --- a/src/signature.rs +++ b/src/signature.rs @@ -14,14 +14,14 @@ use core::fmt::Debug; use curve25519_dalek::edwards::CompressedEdwardsY; use curve25519_dalek::scalar::Scalar; -#[cfg(feature = "serde")] -use serde::{Serialize, Deserialize}; -#[cfg(feature = "serde")] -use serde::{Serializer, Deserializer}; #[cfg(feature = "serde")] use serde::de::Error as SerdeError; #[cfg(feature = "serde")] use serde::de::Visitor; +#[cfg(feature = "serde")] +use serde::{Deserialize, Serialize}; +#[cfg(feature = "serde")] +use serde::{Deserializer, Serializer}; use crate::constants::*; use crate::errors::*; @@ -45,7 +45,7 @@ pub struct Signature { /// This digest is then interpreted as a `Scalar` and reduced into an /// element in ℤ/lℤ. The scalar is then multiplied by the distinguished /// basepoint to produce `R`, and `EdwardsPoint`. - pub (crate) R: CompressedEdwardsY, + pub(crate) R: CompressedEdwardsY, /// `s` is a `Scalar`, formed by using an hash function with 512-bits output /// to produce the digest of: @@ -56,11 +56,13 @@ pub struct Signature { /// /// This digest is then interpreted as a `Scalar` and reduced into an /// element in ℤ/lℤ. - pub (crate) s: Scalar, + pub(crate) s: Scalar, } impl Clone for Signature { - fn clone(&self) -> Self { *self } + fn clone(&self) -> Self { + *self + } } impl Debug for Signature { @@ -84,8 +86,10 @@ impl Signature { #[inline] pub fn from_bytes(bytes: &[u8]) -> Result { if bytes.len() != SIGNATURE_LENGTH { - return Err(SignatureError(InternalError::BytesLengthError{ - name: "Signature", length: SIGNATURE_LENGTH })); + return Err(SignatureError(InternalError::BytesLengthError { + name: "Signature", + length: SIGNATURE_LENGTH, + })); } let mut lower: [u8; 32] = [0u8; 32]; let mut upper: [u8; 32] = [0u8; 32]; @@ -97,20 +101,29 @@ impl Signature { return Err(SignatureError(InternalError::ScalarFormatError)); } - Ok(Signature{ R: CompressedEdwardsY(lower), s: Scalar::from_bits(upper) }) + Ok(Signature { + R: CompressedEdwardsY(lower), + s: Scalar::from_bits(upper), + }) } } #[cfg(feature = "serde")] impl Serialize for Signature { - fn serialize(&self, serializer: S) -> Result where S: Serializer { + fn serialize(&self, serializer: S) -> Result + where + S: Serializer, + { serializer.serialize_bytes(&self.to_bytes()[..]) } } #[cfg(feature = "serde")] impl<'d> Deserialize<'d> for Signature { - fn deserialize(deserializer: D) -> Result where D: Deserializer<'d> { + fn deserialize(deserializer: D) -> Result + where + D: Deserializer<'d>, + { struct SignatureVisitor; impl<'d> Visitor<'d> for SignatureVisitor { @@ -120,7 +133,10 @@ impl<'d> Deserialize<'d> for Signature { formatter.write_str("An ed25519 signature as 64 bytes, as specified in RFC8032.") } - fn visit_bytes(self, bytes: &[u8]) -> Result where E: SerdeError{ + fn visit_bytes(self, bytes: &[u8]) -> Result + where + E: SerdeError, + { Signature::from_bytes(bytes).or(Err(SerdeError::invalid_length(bytes.len(), &self))) } } From d853856c3653abf49d0508557ce79093e9555e8f Mon Sep 17 00:00:00 2001 From: Isis Lovecruft Date: Sun, 30 Dec 2018 04:07:50 +0000 Subject: [PATCH 32/43] Run rustfmt on src/public.rs. --- src/public.rs | 59 +++++++++++++++++++++++++++++++-------------------- 1 file changed, 36 insertions(+), 23 deletions(-) diff --git a/src/public.rs b/src/public.rs index 60e504a..4ff2353 100644 --- a/src/public.rs +++ b/src/public.rs @@ -12,22 +12,22 @@ use core::fmt::Debug; use curve25519_dalek::constants; -use curve25519_dalek::digest::Digest; use curve25519_dalek::digest::generic_array::typenum::U64; +use curve25519_dalek::digest::Digest; use curve25519_dalek::edwards::CompressedEdwardsY; use curve25519_dalek::edwards::EdwardsPoint; use curve25519_dalek::scalar::Scalar; pub use sha2::Sha512; -#[cfg(feature = "serde")] -use serde::{Serialize, Deserialize}; -#[cfg(feature = "serde")] -use serde::{Serializer, Deserializer}; #[cfg(feature = "serde")] use serde::de::Error as SerdeError; #[cfg(feature = "serde")] use serde::de::Visitor; +#[cfg(feature = "serde")] +use serde::{Deserialize, Serialize}; +#[cfg(feature = "serde")] +use serde::{Deserializer, Serializer}; use crate::constants::*; use crate::errors::*; @@ -36,10 +36,7 @@ use crate::signature::*; /// An ed25519 public key. #[derive(Copy, Clone, Default, Eq, PartialEq)] -pub struct PublicKey( - pub (crate) CompressedEdwardsY, - pub (crate) EdwardsPoint, -); +pub struct PublicKey(pub(crate) CompressedEdwardsY, pub(crate) EdwardsPoint); impl Debug for PublicKey { fn fmt(&self, f: &mut ::core::fmt::Formatter<'_>) -> ::core::fmt::Result { @@ -56,8 +53,8 @@ impl AsRef<[u8]> for PublicKey { impl<'a> From<&'a SecretKey> for PublicKey { /// Derive this public key from its corresponding `SecretKey`. fn from(secret_key: &SecretKey) -> PublicKey { - let mut h: Sha512 = Sha512::new(); - let mut hash: [u8; 64] = [0u8; 64]; + let mut h: Sha512 = Sha512::new(); + let mut hash: [u8; 64] = [0u8; 64]; let mut digest: [u8; 32] = [0u8; 32]; h.input(secret_key.as_bytes()); @@ -130,14 +127,18 @@ impl PublicKey { #[inline] pub fn from_bytes(bytes: &[u8]) -> Result { if bytes.len() != PUBLIC_KEY_LENGTH { - return Err(SignatureError(InternalError::BytesLengthError{ - name: "PublicKey", length: PUBLIC_KEY_LENGTH })); + return Err(SignatureError(InternalError::BytesLengthError { + name: "PublicKey", + length: PUBLIC_KEY_LENGTH, + })); } let mut bits: [u8; 32] = [0u8; 32]; bits.copy_from_slice(&bytes[..32]); let compressed = CompressedEdwardsY(bits); - let point = compressed.decompress().ok_or(SignatureError(InternalError::PointDecompressionError))?; + let point = compressed + .decompress() + .ok_or(SignatureError(InternalError::PointDecompressionError))?; Ok(PublicKey(compressed, point)) } @@ -145,8 +146,10 @@ impl PublicKey { /// Internal utility function for mangling the bits of a (formerly /// mathematically well-defined) "scalar" and multiplying it to produce a /// public key. - fn mangle_scalar_bits_and_multiply_by_basepoint_to_produce_public_key(bits: &mut [u8; 32]) -> PublicKey { - bits[0] &= 248; + fn mangle_scalar_bits_and_multiply_by_basepoint_to_produce_public_key( + bits: &mut [u8; 32], + ) -> PublicKey { + bits[0] &= 248; bits[31] &= 127; bits[31] |= 64; @@ -212,8 +215,8 @@ impl PublicKey { context: Option<&[u8]>, signature: &Signature, ) -> Result<(), SignatureError> - where - D: Digest, + where + D: Digest, { let mut h: Sha512 = Sha512::default(); let R: EdwardsPoint; @@ -245,25 +248,35 @@ impl PublicKey { #[cfg(feature = "serde")] impl Serialize for PublicKey { - fn serialize(&self, serializer: S) -> Result where S: Serializer { + fn serialize(&self, serializer: S) -> Result + where + S: Serializer, + { serializer.serialize_bytes(self.as_bytes()) } } #[cfg(feature = "serde")] impl<'d> Deserialize<'d> for PublicKey { - fn deserialize(deserializer: D) -> Result where D: Deserializer<'d> { - + fn deserialize(deserializer: D) -> Result + where + D: Deserializer<'d>, + { struct PublicKeyVisitor; impl<'d> Visitor<'d> for PublicKeyVisitor { type Value = PublicKey; fn expecting(&self, formatter: &mut ::core::fmt::Formatter<'_>) -> ::core::fmt::Result { - formatter.write_str("An ed25519 public key as a 32-byte compressed point, as specified in RFC8032") + formatter.write_str( + "An ed25519 public key as a 32-byte compressed point, as specified in RFC8032", + ) } - fn visit_bytes(self, bytes: &[u8]) -> Result where E: SerdeError { + fn visit_bytes(self, bytes: &[u8]) -> Result + where + E: SerdeError, + { PublicKey::from_bytes(bytes).or(Err(SerdeError::invalid_length(bytes.len(), &self))) } } From 811793ba2b532791b605bd27f12a20135f8bf0b4 Mon Sep 17 00:00:00 2001 From: Isis Lovecruft Date: Sun, 30 Dec 2018 04:10:09 +0000 Subject: [PATCH 33/43] Run rustfmt on src/secret.rs. --- src/secret.rs | 83 ++++++++++++++++++++++++++++++++++----------------- 1 file changed, 55 insertions(+), 28 deletions(-) diff --git a/src/secret.rs b/src/secret.rs index d5c3e67..4519ab5 100644 --- a/src/secret.rs +++ b/src/secret.rs @@ -14,8 +14,8 @@ use core::fmt::Debug; use clear_on_drop::clear::Clear; use curve25519_dalek::constants; -use curve25519_dalek::digest::Digest; use curve25519_dalek::digest::generic_array::typenum::U64; +use curve25519_dalek::digest::Digest; use curve25519_dalek::edwards::CompressedEdwardsY; use curve25519_dalek::scalar::Scalar; @@ -24,14 +24,14 @@ use rand::Rng; use sha2::Sha512; -#[cfg(feature = "serde")] -use serde::{Serialize, Deserialize}; -#[cfg(feature = "serde")] -use serde::{Serializer, Deserializer}; #[cfg(feature = "serde")] use serde::de::Error as SerdeError; #[cfg(feature = "serde")] use serde::de::Visitor; +#[cfg(feature = "serde")] +use serde::{Deserialize, Serialize}; +#[cfg(feature = "serde")] +use serde::{Deserializer, Serializer}; use crate::constants::*; use crate::errors::*; @@ -40,7 +40,7 @@ use crate::signature::*; /// An EdDSA secret key. #[derive(Default)] // we derive Default in order to use the clear() method in Drop -pub struct SecretKey(pub (crate) [u8; SECRET_KEY_LENGTH]); +pub struct SecretKey(pub(crate) [u8; SECRET_KEY_LENGTH]); impl Debug for SecretKey { fn fmt(&self, f: &mut ::core::fmt::Formatter<'_>) -> ::core::fmt::Result { @@ -110,8 +110,10 @@ impl SecretKey { #[inline] pub fn from_bytes(bytes: &[u8]) -> Result { if bytes.len() != SECRET_KEY_LENGTH { - return Err(SignatureError(InternalError::BytesLengthError{ - name: "SecretKey", length: SECRET_KEY_LENGTH })); + return Err(SignatureError(InternalError::BytesLengthError { + name: "SecretKey", + length: SECRET_KEY_LENGTH, + })); } let mut bits: [u8; 32] = [0u8; 32]; bits.copy_from_slice(&bytes[..32]); @@ -171,7 +173,8 @@ impl SecretKey { /// /// A CSPRNG with a `fill_bytes()` method, e.g. `rand::OsRng` pub fn generate(csprng: &mut T) -> SecretKey - where T: CryptoRng + Rng, + where + T: CryptoRng + Rng, { let mut sk: SecretKey = SecretKey([0u8; 32]); @@ -183,14 +186,20 @@ impl SecretKey { #[cfg(feature = "serde")] impl Serialize for SecretKey { - fn serialize(&self, serializer: S) -> Result where S: Serializer { + fn serialize(&self, serializer: S) -> Result + where + S: Serializer, + { serializer.serialize_bytes(self.as_bytes()) } } #[cfg(feature = "serde")] impl<'d> Deserialize<'d> for SecretKey { - fn deserialize(deserializer: D) -> Result where D: Deserializer<'d> { + fn deserialize(deserializer: D) -> Result + where + D: Deserializer<'d>, + { struct SecretKeyVisitor; impl<'d> Visitor<'d> for SecretKeyVisitor { @@ -200,7 +209,10 @@ impl<'d> Deserialize<'d> for SecretKey { formatter.write_str("An ed25519 secret key as 32 bytes, as specified in RFC8032.") } - fn visit_bytes(self, bytes: &[u8]) -> Result where E: SerdeError { + fn visit_bytes(self, bytes: &[u8]) -> Result + where + E: SerdeError, + { SecretKey::from_bytes(bytes).or(Err(SerdeError::invalid_length(bytes.len(), &self))) } } @@ -245,8 +257,8 @@ impl<'d> Deserialize<'d> for SecretKey { // "generalised EdDSA" and "VXEdDSA". #[derive(Default)] // we derive Default in order to use the clear() method in Drop pub struct ExpandedSecretKey { - pub (crate) key: Scalar, - pub (crate) nonce: [u8; 32], + pub(crate) key: Scalar, + pub(crate) nonce: [u8; 32], } /// Overwrite secret key material with null bytes when it goes out of scope. @@ -388,8 +400,10 @@ impl ExpandedSecretKey { #[inline] pub fn from_bytes(bytes: &[u8]) -> Result { if bytes.len() != EXPANDED_SECRET_KEY_LENGTH { - return Err(SignatureError(InternalError::BytesLengthError{ - name: "ExpandedSecretKey", length: EXPANDED_SECRET_KEY_LENGTH })); + return Err(SignatureError(InternalError::BytesLengthError { + name: "ExpandedSecretKey", + length: EXPANDED_SECRET_KEY_LENGTH, + })); } let mut lower: [u8; 32] = [0u8; 32]; let mut upper: [u8; 32] = [0u8; 32]; @@ -397,8 +411,10 @@ impl ExpandedSecretKey { lower.copy_from_slice(&bytes[00..32]); upper.copy_from_slice(&bytes[32..64]); - Ok(ExpandedSecretKey{ key: Scalar::from_bits(lower), - nonce: upper }) + Ok(ExpandedSecretKey { + key: Scalar::from_bits(lower), + nonce: upper, + }) } /// Sign a message with this `ExpandedSecretKey`. @@ -424,7 +440,7 @@ impl ExpandedSecretKey { k = Scalar::from_hash(h); s = &(&k * &self.key) + &r; - Signature{ R, s } + Signature { R, s } } /// Sign a `prehashed_message` with this `ExpandedSecretKey` using the @@ -452,8 +468,8 @@ impl ExpandedSecretKey { public_key: &PublicKey, context: Option<&'static [u8]>, ) -> Signature - where - D: Digest, + where + D: Digest, { let mut h: Sha512; let mut prehash: [u8; 64] = [0u8; 64]; @@ -506,32 +522,43 @@ impl ExpandedSecretKey { k = Scalar::from_hash(h); s = &(&k * &self.key) + &r; - Signature{ R, s } + Signature { R, s } } - } #[cfg(feature = "serde")] impl Serialize for ExpandedSecretKey { - fn serialize(&self, serializer: S) -> Result where S: Serializer { + fn serialize(&self, serializer: S) -> Result + where + S: Serializer, + { serializer.serialize_bytes(&self.to_bytes()[..]) } } #[cfg(feature = "serde")] impl<'d> Deserialize<'d> for ExpandedSecretKey { - fn deserialize(deserializer: D) -> Result where D: Deserializer<'d> { + fn deserialize(deserializer: D) -> Result + where + D: Deserializer<'d>, + { struct ExpandedSecretKeyVisitor; impl<'d> Visitor<'d> for ExpandedSecretKeyVisitor { type Value = ExpandedSecretKey; fn expecting(&self, formatter: &mut ::core::fmt::Formatter<'_>) -> ::core::fmt::Result { - formatter.write_str("An ed25519 expanded secret key as 64 bytes, as specified in RFC8032.") + formatter.write_str( + "An ed25519 expanded secret key as 64 bytes, as specified in RFC8032.", + ) } - fn visit_bytes(self, bytes: &[u8]) -> Result where E: SerdeError { - ExpandedSecretKey::from_bytes(bytes).or(Err(SerdeError::invalid_length(bytes.len(), &self))) + fn visit_bytes(self, bytes: &[u8]) -> Result + where + E: SerdeError, + { + ExpandedSecretKey::from_bytes(bytes) + .or(Err(SerdeError::invalid_length(bytes.len(), &self))) } } deserializer.deserialize_bytes(ExpandedSecretKeyVisitor) From ad49d31bbc3c6a3603eabb9b7bbe6ff219e8e508 Mon Sep 17 00:00:00 2001 From: Isis Lovecruft Date: Sun, 30 Dec 2018 04:10:59 +0000 Subject: [PATCH 34/43] Run rustfmt on src/errors.rs. --- src/errors.rs | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/src/errors.rs b/src/errors.rs index f531849..30f821f 100644 --- a/src/errors.rs +++ b/src/errors.rs @@ -19,7 +19,7 @@ use core::fmt::Display; /// Internal errors. Most application-level developers will likely not /// need to pay any attention to these. #[derive(Clone, Copy, Debug, Eq, PartialEq, Hash)] -pub (crate) enum InternalError { +pub(crate) enum InternalError { PointDecompressionError, ScalarFormatError, /// An error in the length of bytes handed to a constructor. @@ -27,7 +27,10 @@ pub (crate) enum InternalError { /// To use this, pass a string specifying the `name` of the type which is /// returning the error, and the `length` in bytes which its constructor /// expects. - BytesLengthError{ name: &'static str, length: usize }, + BytesLengthError { + name: &'static str, + length: usize, + }, /// The verification equation wasn't satisfied VerifyError, } @@ -64,7 +67,7 @@ impl ::failure::Fail for InternalError {} /// /// * Failure of a signature to satisfy the verification equation. #[derive(Clone, Copy, Eq, PartialEq, Hash, Debug)] -pub struct SignatureError(pub (crate) InternalError); +pub struct SignatureError(pub(crate) InternalError); impl Display for SignatureError { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { From fa726cfdccf9014d3e825ac68bd4d225383d01d7 Mon Sep 17 00:00:00 2001 From: Isis Lovecruft Date: Sun, 30 Dec 2018 04:12:33 +0000 Subject: [PATCH 35/43] Run rustfmt on src/lib.rs. --- src/lib.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/lib.rs b/src/lib.rs index de05f8b..70e8ef0 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -251,9 +251,9 @@ extern crate clear_on_drop; extern crate curve25519_dalek; extern crate failure; extern crate rand; -extern crate sha2; #[cfg(feature = "serde")] extern crate serde; +extern crate sha2; mod constants; mod ed25519; From 8b30d4084ac3323ae1e7ef510a8f4fdcfe2358b1 Mon Sep 17 00:00:00 2001 From: Isis Lovecruft Date: Sun, 30 Dec 2018 04:16:03 +0000 Subject: [PATCH 36/43] Run rustfmt on src/ed25519.rs. --- src/ed25519.rs | 56 ++++++++++++++++++++++++++++---------------------- 1 file changed, 32 insertions(+), 24 deletions(-) diff --git a/src/ed25519.rs b/src/ed25519.rs index a6d5f31..5708108 100644 --- a/src/ed25519.rs +++ b/src/ed25519.rs @@ -14,19 +14,19 @@ use core::default::Default; use rand::CryptoRng; use rand::Rng; -#[cfg(feature = "serde")] -use serde::{Serialize, Deserialize}; -#[cfg(feature = "serde")] -use serde::{Serializer, Deserializer}; #[cfg(feature = "serde")] use serde::de::Error as SerdeError; #[cfg(feature = "serde")] use serde::de::Visitor; +#[cfg(feature = "serde")] +use serde::{Deserialize, Serialize}; +#[cfg(feature = "serde")] +use serde::{Deserializer, Serializer}; pub use sha2::Sha512; -pub use curve25519_dalek::digest::Digest; use curve25519_dalek::digest::generic_array::typenum::U64; +pub use curve25519_dalek::digest::Digest; use curve25519_dalek::constants; use curve25519_dalek::edwards::EdwardsPoint; @@ -199,8 +199,10 @@ impl Keypair { /// is an `SignatureError` describing the error that occurred. pub fn from_bytes<'a>(bytes: &'a [u8]) -> Result { if bytes.len() != KEYPAIR_LENGTH { - return Err(SignatureError(InternalError::BytesLengthError{ - name: "Keypair", length: KEYPAIR_LENGTH})); + return Err(SignatureError(InternalError::BytesLengthError { + name: "Keypair", + length: KEYPAIR_LENGTH, + })); } let secret = SecretKey::from_bytes(&bytes[..SECRET_KEY_LENGTH])?; let public = PublicKey::from_bytes(&bytes[SECRET_KEY_LENGTH..])?; @@ -243,7 +245,8 @@ impl Keypair { /// which is available with `use sha2::Sha512` as in the example above. /// Other suitable hash functions include Keccak-512 and Blake2b-512. pub fn generate(csprng: &mut R) -> Keypair - where R: CryptoRng + Rng, + where + R: CryptoRng + Rng, { let sk: SecretKey = SecretKey::generate(csprng); let pk: PublicKey = (&sk).into(); @@ -252,8 +255,7 @@ impl Keypair { } /// Sign a message with this keypair's secret key. - pub fn sign(&self, message: &[u8]) -> Signature - { + pub fn sign(&self, message: &[u8]) -> Signature { let expanded: ExpandedSecretKey = (&self.secret).into(); expanded.sign(&message, &self.public) @@ -356,12 +358,12 @@ impl Keypair { pub fn sign_prehashed( &self, prehashed_message: D, - context: Option<&'static [u8]> + context: Option<&'static [u8]>, ) -> Signature - where - D: Digest, + where + D: Digest, { - let expanded: ExpandedSecretKey = (&self.secret).into(); // xxx thanks i hate this + let expanded: ExpandedSecretKey = (&self.secret).into(); // xxx thanks i hate this expanded.sign_prehashed(prehashed_message, &self.public, context) } @@ -436,10 +438,10 @@ impl Keypair { &self, prehashed_message: D, context: Option<&[u8]>, - signature: &Signature + signature: &Signature, ) -> Result<(), SignatureError> - where - D: Digest, + where + D: Digest, { self.public.verify_prehashed(prehashed_message, context, signature) } @@ -447,15 +449,20 @@ impl Keypair { #[cfg(feature = "serde")] impl Serialize for Keypair { - fn serialize(&self, serializer: S) -> Result where S: Serializer { + fn serialize(&self, serializer: S) -> Result + where + S: Serializer, + { serializer.serialize_bytes(&self.to_bytes()[..]) } } #[cfg(feature = "serde")] impl<'d> Deserialize<'d> for Keypair { - fn deserialize(deserializer: D) -> Result where D: Deserializer<'d> { - + fn deserialize(deserializer: D) -> Result + where + D: Deserializer<'d>, + { struct KeypairVisitor; impl<'d> Visitor<'d> for KeypairVisitor { @@ -467,7 +474,10 @@ impl<'d> Deserialize<'d> for Keypair { 32 bytes is a compressed point for a public key.") } - fn visit_bytes(self, bytes: &[u8]) -> Result where E: SerdeError { + fn visit_bytes(self, bytes: &[u8]) -> Result + where + E: SerdeError, + { let secret_key = SecretKey::from_bytes(&bytes[..SECRET_KEY_LENGTH]); let public_key = PublicKey::from_bytes(&bytes[SECRET_KEY_LENGTH..]); @@ -498,9 +508,7 @@ mod test { use std::mem; use std::slice; - unsafe { - slice::from_raw_parts(x as *const T as *const u8, mem::size_of_val(x)) - } + unsafe { slice::from_raw_parts(x as *const T as *const u8, mem::size_of_val(x)) } } assert!(!as_bytes(&keypair).contains(&0x15)); From 82cdcb9cc934fbbbff1ab1b27dfb29382b276059 Mon Sep 17 00:00:00 2001 From: Isis Lovecruft Date: Sun, 30 Dec 2018 04:26:22 +0000 Subject: [PATCH 37/43] Fix benchmarks after merging #64. --- benches/ed25519_benchmarks.rs | 26 ++++++++++++-------------- 1 file changed, 12 insertions(+), 14 deletions(-) diff --git a/benches/ed25519_benchmarks.rs b/benches/ed25519_benchmarks.rs index 79575c9..c628bd7 100644 --- a/benches/ed25519_benchmarks.rs +++ b/benches/ed25519_benchmarks.rs @@ -11,7 +11,6 @@ extern crate criterion; extern crate ed25519_dalek; extern crate rand; -extern crate sha2; use criterion::Criterion; @@ -24,37 +23,36 @@ mod ed25519_benches { use ed25519_dalek::verify_batch; use rand::thread_rng; use rand::rngs::ThreadRng; - use sha2::Sha512; fn sign(c: &mut Criterion) { let mut csprng: ThreadRng = thread_rng(); - let keypair: Keypair = Keypair::generate::(&mut csprng); + let keypair: Keypair = Keypair::generate(&mut csprng); let msg: &[u8] = b""; c.bench_function("Ed25519 signing", move |b| { - b.iter(| | keypair.sign::(msg)) + b.iter(| | keypair.sign(msg)) }); } fn sign_expanded_key(c: &mut Criterion) { let mut csprng: ThreadRng = thread_rng(); - let keypair: Keypair = Keypair::generate::(&mut csprng); - let expanded: ExpandedSecretKey = keypair.secret.expand::(); + let keypair: Keypair = Keypair::generate(&mut csprng); + let expanded: ExpandedSecretKey = (&keypair.secret).into(); let msg: &[u8] = b""; c.bench_function("Ed25519 signing with an expanded secret key", move |b| { - b.iter(| | expanded.sign::(msg, &keypair.public)) + b.iter(| | expanded.sign(msg, &keypair.public)) }); } fn verify(c: &mut Criterion) { let mut csprng: ThreadRng = thread_rng(); - let keypair: Keypair = Keypair::generate::(&mut csprng); + let keypair: Keypair = Keypair::generate(&mut csprng); let msg: &[u8] = b""; - let sig: Signature = keypair.sign::(msg); + let sig: Signature = keypair.sign(msg); c.bench_function("Ed25519 signature verification", move |b| { - b.iter(| | keypair.verify::(msg, &sig)) + b.iter(| | keypair.verify(msg, &sig)) }); } @@ -65,13 +63,13 @@ mod ed25519_benches { "Ed25519 batch signature verification", |b, &&size| { let mut csprng: ThreadRng = thread_rng(); - let keypairs: Vec = (0..size).map(|_| Keypair::generate::(&mut csprng)).collect(); + let keypairs: Vec = (0..size).map(|_| Keypair::generate(&mut csprng)).collect(); let msg: &[u8] = b"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"; let messages: Vec<&[u8]> = (0..size).map(|_| msg).collect(); - let signatures: Vec = keypairs.iter().map(|key| key.sign::(&msg)).collect(); + let signatures: Vec = keypairs.iter().map(|key| key.sign(&msg)).collect(); let public_keys: Vec = keypairs.iter().map(|key| key.public).collect(); - b.iter(|| verify_batch::(&messages[..], &signatures[..], &public_keys[..])); + b.iter(|| verify_batch(&messages[..], &signatures[..], &public_keys[..])); }, &BATCH_SIZES, ); @@ -81,7 +79,7 @@ mod ed25519_benches { let mut csprng: ThreadRng = thread_rng(); c.bench_function("Ed25519 keypair generation", move |b| { - b.iter(| | Keypair::generate::(&mut csprng)) + b.iter(| | Keypair::generate(&mut csprng)) }); } From 42b571eb24d77877ea933d7d87dff6f08650df57 Mon Sep 17 00:00:00 2001 From: Isis Lovecruft Date: Sun, 30 Dec 2018 04:26:56 +0000 Subject: [PATCH 38/43] Remove unused clear_on_drop import from tests. --- tests/ed25519.rs | 1 - 1 file changed, 1 deletion(-) diff --git a/tests/ed25519.rs b/tests/ed25519.rs index ff89b90..c7e358a 100644 --- a/tests/ed25519.rs +++ b/tests/ed25519.rs @@ -11,7 +11,6 @@ #[cfg(all(test, feature = "serde"))] extern crate bincode; -extern crate clear_on_drop; extern crate ed25519_dalek; extern crate hex; extern crate rand; From 0ddf39e44371a961bfe4669832deef23c5a3c412 Mon Sep 17 00:00:00 2001 From: Isis Lovecruft Date: Sun, 30 Dec 2018 04:27:33 +0000 Subject: [PATCH 39/43] Revise some module descriptions. --- src/ed25519.rs | 2 +- src/lib.rs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/ed25519.rs b/src/ed25519.rs index 5708108..6b7e3cc 100644 --- a/src/ed25519.rs +++ b/src/ed25519.rs @@ -7,7 +7,7 @@ // Authors: // - isis agora lovecruft -//! A Rust implementation of ed25519 key generation, signing, and verification. +//! ed25519 keypairs and batch verification. use core::default::Default; diff --git a/src/lib.rs b/src/lib.rs index 70e8ef0..d6ab121 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -7,7 +7,7 @@ // Authors: // - Isis Agora Lovecruft -//! ed25519 signatures and verification +//! A Rust implementation of ed25519 key generation, signing, and verification. //! //! # Example //! From 6d1d3ff5ea8f40b0d19e88c9c5c3e67870b05618 Mon Sep 17 00:00:00 2001 From: Isis Lovecruft Date: Thu, 17 Jan 2019 20:39:23 +0000 Subject: [PATCH 40/43] Remove outdated comment about Fuchsia dependencies from Cargo.toml. --- Cargo.toml | 1 - 1 file changed, 1 deletion(-) diff --git a/Cargo.toml b/Cargo.toml index 5d5cc94..c64aa9c 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -49,7 +49,6 @@ harness = false [features] default = ["std", "u64_backend"] -# We don't add "rand/std" here because it would enable a bunch of Fuchsia dependencies. std = ["curve25519-dalek/std", "rand/std", "sha2/std"] alloc = ["curve25519-dalek/alloc"] nightly = ["curve25519-dalek/nightly", "rand/nightly", "clear_on_drop/nightly"] From 131fc2b07f7e5197a14ba3ab938f574def5205f2 Mon Sep 17 00:00:00 2001 From: Isis Lovecruft Date: Thu, 17 Jan 2019 20:52:32 +0000 Subject: [PATCH 41/43] Bump ed25519-dalek version to 1.0.0-pre.1. --- Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Cargo.toml b/Cargo.toml index c64aa9c..bba552a 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "ed25519-dalek" -version = "1.0.0-pre.0" +version = "1.0.0-pre.1" authors = ["Isis Lovecruft "] readme = "README.md" license = "BSD-3-Clause" From ae8764fbeff32ac0fef41850864761226b670cdd Mon Sep 17 00:00:00 2001 From: Isis Lovecruft Date: Thu, 17 Jan 2019 23:28:13 +0000 Subject: [PATCH 42/43] Update copyright year to 2019 and destroy capitalism. --- Cargo.toml | 2 +- LICENSE | 2 +- benches/ed25519_benchmarks.rs | 4 ++-- src/constants.rs | 2 +- src/ed25519.rs | 2 +- src/errors.rs | 4 ++-- src/lib.rs | 4 ++-- src/public.rs | 2 +- src/secret.rs | 2 +- src/signature.rs | 2 +- tests/ed25519.rs | 2 +- 11 files changed, 14 insertions(+), 14 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index bba552a..fbf67f8 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,7 +1,7 @@ [package] name = "ed25519-dalek" version = "1.0.0-pre.1" -authors = ["Isis Lovecruft "] +authors = ["isis lovecruft "] readme = "README.md" license = "BSD-3-Clause" repository = "https://github.com/dalek-cryptography/ed25519-dalek" diff --git a/LICENSE b/LICENSE index 0d9a49e..acf8498 100644 --- a/LICENSE +++ b/LICENSE @@ -1,4 +1,4 @@ -Copyright (c) 2017-2018 Isis Agora Lovecruft. All rights reserved. +Copyright (c) 2017-2019 isis agora lovecruft. All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are diff --git a/benches/ed25519_benchmarks.rs b/benches/ed25519_benchmarks.rs index c628bd7..52cb597 100644 --- a/benches/ed25519_benchmarks.rs +++ b/benches/ed25519_benchmarks.rs @@ -1,11 +1,11 @@ // -*- mode: rust; -*- // // This file is part of ed25519-dalek. -// Copyright (c) 2018 Isis Lovecruft +// Copyright (c) 2018-2019 isis lovecruft // See LICENSE for licensing information. // // Authors: -// - Isis Agora Lovecruft +// - isis agora lovecruft #[macro_use] extern crate criterion; diff --git a/src/constants.rs b/src/constants.rs index 783ffb2..f8ccb84 100644 --- a/src/constants.rs +++ b/src/constants.rs @@ -1,7 +1,7 @@ // -*- mode: rust; -*- // // This file is part of ed25519-dalek. -// Copyright (c) 2017-2018 isis lovecruft +// Copyright (c) 2017-2019 isis lovecruft // See LICENSE for licensing information. // // Authors: diff --git a/src/ed25519.rs b/src/ed25519.rs index 6b7e3cc..2d144ce 100644 --- a/src/ed25519.rs +++ b/src/ed25519.rs @@ -1,7 +1,7 @@ // -*- mode: rust; -*- // // This file is part of ed25519-dalek. -// Copyright (c) 2017-2018 isis lovecruft +// Copyright (c) 2017-2019 isis lovecruft // See LICENSE for licensing information. // // Authors: diff --git a/src/errors.rs b/src/errors.rs index 30f821f..6597f73 100644 --- a/src/errors.rs +++ b/src/errors.rs @@ -1,11 +1,11 @@ // -*- mode: rust; -*- // // This file is part of ed25519-dalek. -// Copyright (c) 2017 Isis Lovecruft +// Copyright (c) 2017-2019 isis lovecruft // See LICENSE for licensing information. // // Authors: -// - Isis Agora Lovecruft +// - isis agora lovecruft //! Errors which may occur when parsing keys and/or signatures to or from wire formats. diff --git a/src/lib.rs b/src/lib.rs index d6ab121..faf6873 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1,11 +1,11 @@ // -*- mode: rust; -*- // // This file is part of ed25519-dalek. -// Copyright (c) 2017-2018 Isis Lovecruft +// Copyright (c) 2017-2019 isis lovecruft // See LICENSE for licensing information. // // Authors: -// - Isis Agora Lovecruft +// - isis agora lovecruft //! A Rust implementation of ed25519 key generation, signing, and verification. //! diff --git a/src/public.rs b/src/public.rs index 4ff2353..ae3bfa3 100644 --- a/src/public.rs +++ b/src/public.rs @@ -1,7 +1,7 @@ // -*- mode: rust; -*- // // This file is part of ed25519-dalek. -// Copyright (c) 2017-2018 isis lovecruft +// Copyright (c) 2017-2019 isis lovecruft // See LICENSE for licensing information. // // Authors: diff --git a/src/secret.rs b/src/secret.rs index 4519ab5..3bfeb7c 100644 --- a/src/secret.rs +++ b/src/secret.rs @@ -1,7 +1,7 @@ // -*- mode: rust; -*- // // This file is part of ed25519-dalek. -// Copyright (c) 2017-2018 isis lovecruft +// Copyright (c) 2017-2019 isis lovecruft // See LICENSE for licensing information. // // Authors: diff --git a/src/signature.rs b/src/signature.rs index 3dbc478..d5079fd 100644 --- a/src/signature.rs +++ b/src/signature.rs @@ -1,7 +1,7 @@ // -*- mode: rust; -*- // // This file is part of ed25519-dalek. -// Copyright (c) 2017-2018 isis lovecruft +// Copyright (c) 2017-2019 isis lovecruft // See LICENSE for licensing information. // // Authors: diff --git a/tests/ed25519.rs b/tests/ed25519.rs index c7e358a..d849e41 100644 --- a/tests/ed25519.rs +++ b/tests/ed25519.rs @@ -1,7 +1,7 @@ // -*- mode: rust; -*- // // This file is part of ed25519-dalek. -// Copyright (c) 2017-2018 isis lovecruft +// Copyright (c) 2017-2019 isis lovecruft // See LICENSE for licensing information. // // Authors: From e527280d2e5781e070da269893cc514392312fdd Mon Sep 17 00:00:00 2001 From: Isis Lovecruft Date: Thu, 17 Jan 2019 23:34:29 +0000 Subject: [PATCH 43/43] Remove TravisCI test for the sha2 feature which was removed. --- .travis.yml | 3 --- 1 file changed, 3 deletions(-) diff --git a/.travis.yml b/.travis.yml index 82c3918..f7f92d7 100644 --- a/.travis.yml +++ b/.travis.yml @@ -20,9 +20,6 @@ matrix: # Test serde support on stable, assuming that if it works there it'll work everywhere: - rust: stable env: TEST_COMMAND=test FEATURE='--features=serde' - # Test with the optional sha2 feature enabled: - - rust: stable - env: TEST_COMMAND=test FEATURE='--features=sha2' script: - cargo $TEST_COMMAND $FEATURES