diff --git a/Cargo.toml b/Cargo.toml index 0bbd8de..103cb9a 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "ed25519-dalek" -version = "0.5.0" +version = "0.6.0" authors = ["Isis Lovecruft "] readme = "README.md" license = "BSD-3-Clause" @@ -42,6 +42,10 @@ optional = true version = "^0.6" optional = true +[dependencies.failure] +version = "^0.1.1" +default-features = false + [dev-dependencies] hex = "0.2" sha2 = "^0.6" @@ -49,7 +53,7 @@ bincode = "^0.9" [features] default = ["std"] -std = ["rand", "curve25519-dalek/std"] +std = ["rand", "curve25519-dalek/std", "failure/std"] bench = [] nightly = ["curve25519-dalek/nightly"] asm = ["sha2/asm"] diff --git a/src/ed25519.rs b/src/ed25519.rs index c38276e..988c278 100644 --- a/src/ed25519.rs +++ b/src/ed25519.rs @@ -10,7 +10,7 @@ //! A Rust implementation of ed25519 EdDSA key generation, signing, and //! verification. -use core::fmt::Debug; +use core::fmt::{self, Debug, Display}; #[cfg(feature = "std")] use rand::Rng; @@ -123,10 +123,8 @@ impl Signature { /// Construct a `Signature` from a slice of bytes. #[inline] - pub fn from_bytes(bytes: &[u8]) -> Result { - if bytes.len() != SIGNATURE_LENGTH { - return Err("Wrong length of bytes for signature! Need 64 bytes.") - } + pub fn from_bytes(bytes: &[u8]) -> Result { + check_bytes_len(bytes, SIGNATURE_LENGTH)?; let mut lower: [u8; 32] = [0u8; 32]; let mut upper: [u8; 32] = [0u8; 32]; @@ -206,8 +204,9 @@ impl SecretKey { /// # /// use ed25519_dalek::SecretKey; /// use ed25519_dalek::SECRET_KEY_LENGTH; + /// use ed25519_dalek::FromBytesError; /// - /// # fn doctest() -> Result { + /// # 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, @@ -228,12 +227,11 @@ impl SecretKey { /// # Returns /// /// A `Result` whose okay value is an EdDSA `SecretKey` or whose error value - /// is an `&'static str` describing the error that occurred. + /// is an `FromBytesError` describing the error that occurred. #[inline] - pub fn from_bytes(bytes: &[u8]) -> Result { - if bytes.len() != SECRET_KEY_LENGTH { - return Err("Wrong length of bytes for creating secret key!"); - } + pub fn from_bytes(bytes: &[u8]) -> Result { + check_bytes_len(bytes, SECRET_KEY_LENGTH)?; + let mut bits: [u8; 32] = [0u8; 32]; bits.copy_from_slice(&bytes[..32]); @@ -452,7 +450,7 @@ impl ExpandedSecretKey { /// # Returns /// /// A `Result` whose okay value is an EdDSA `ExpandedSecretKey` or whose - /// error value is an `&'static str` describing the error that occurred. + /// error value is an `FromBytesError` describing the error that occurred. /// /// # Examples /// @@ -463,9 +461,10 @@ impl ExpandedSecretKey { /// # /// use rand::{Rng, OsRng}; /// use ed25519_dalek::{SecretKey, ExpandedSecretKey}; + /// use ed25519_dalek::FromBytesError; /// /// # #[cfg(feature = "sha2")] - /// # fn do_test() -> Result { + /// # fn do_test() -> Result { /// # /// let mut csprng: OsRng = OsRng::new().unwrap(); /// let secret_key: SecretKey = SecretKey::generate(&mut csprng); @@ -486,10 +485,8 @@ impl ExpandedSecretKey { /// # fn main() {} /// ``` #[inline] - pub fn from_bytes(bytes: &[u8]) -> Result { - if bytes.len() != 64 { - return Err("Wrong length of bytes for creating expanded secret key!"); - } + pub fn from_bytes(bytes: &[u8]) -> Result { + check_bytes_len(bytes, 64)?; let mut lower: [u8; 32] = [0u8; 32]; let mut upper: [u8; 32] = [0u8; 32]; @@ -643,8 +640,9 @@ impl PublicKey { /// # /// use ed25519_dalek::PublicKey; /// use ed25519_dalek::PUBLIC_KEY_LENGTH; + /// use ed25519_dalek::FromBytesError; /// - /// # fn doctest() -> Result { + /// # 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]; @@ -662,12 +660,11 @@ impl PublicKey { /// # Returns /// /// A `Result` whose okay value is an EdDSA `PublicKey` or whose error value - /// is an `&'static str` describing the error that occurred. + /// is an `FromBytesError` describing the error that occurred. #[inline] - pub fn from_bytes(bytes: &[u8]) -> Result { - if bytes.len() != PUBLIC_KEY_LENGTH { - return Err("Wrong length of bytes for creating public key!"); - } + pub fn from_bytes(bytes: &[u8]) -> Result { + check_bytes_len(bytes, PUBLIC_KEY_LENGTH)?; + let mut bits: [u8; 32] = [0u8; 32]; bits.copy_from_slice(&bytes[..32]); @@ -817,11 +814,10 @@ impl Keypair { /// # Returns /// /// A `Result` whose okay value is an EdDSA `Keypair` or whose error value - /// is an `&'static str` describing the error that occurred. - pub fn from_bytes<'a>(bytes: &'a [u8]) -> Result { - if bytes.len() != KEYPAIR_LENGTH { - return Err("Wrong length of bytes for creating keypair!"); - } + /// is an `FromBytesError` describing the error that occurred. + pub fn from_bytes<'a>(bytes: &'a [u8]) -> Result { + check_bytes_len(bytes, KEYPAIR_LENGTH)?; + let secret = SecretKey::from_bytes(&bytes[..SECRET_KEY_LENGTH])?; let public = PublicKey::from_bytes(&bytes[SECRET_KEY_LENGTH..])?; @@ -917,6 +913,32 @@ impl<'d> Deserialize<'d> for Keypair { } } +/// An error which occurred when using the `from_bytes` constructor. +/// +/// This error will be returned if the byte slice given was not the correct +/// length for constructing that kind of object. +#[derive(Copy, Clone, Eq, PartialEq, Hash, Debug)] +pub struct FromBytesError { + _private: (), +} + +impl Display for FromBytesError { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + write!(f, "wrong length of bytes when constructing ed25519 object") + } +} + +impl ::failure::Fail for FromBytesError { } + +#[inline(always)] +fn check_bytes_len(bytes: &[u8], len: usize) -> Result<(), FromBytesError> { + if bytes.len() != len { + Err(FromBytesError { _private: () }) + } else { + Ok(()) + } +} + #[cfg(test)] mod test { use std::io::BufReader; @@ -1053,7 +1075,7 @@ mod test { #[test] fn public_key_from_bytes() { // Make another function so that we can test the ? operator. - fn do_the_test() -> Result { + 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, diff --git a/src/lib.rs b/src/lib.rs index 617f579..4e4da19 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -143,9 +143,9 @@ //! # extern crate ed25519_dalek; //! # use rand::{Rng, OsRng}; //! # use sha2::Sha512; -//! # use ed25519_dalek::{Keypair, Signature, PublicKey, SecretKey}; +//! # use ed25519_dalek::{Keypair, Signature, PublicKey, SecretKey, FromBytesError}; //! # use ed25519_dalek::{PUBLIC_KEY_LENGTH, SECRET_KEY_LENGTH, KEYPAIR_LENGTH, SIGNATURE_LENGTH}; -//! # fn do_test() -> Result<(SecretKey, PublicKey, Keypair, Signature), &'static str> { +//! # fn do_test() -> Result<(SecretKey, PublicKey, Keypair, Signature), FromBytesError> { //! # let mut cspring: OsRng = OsRng::new().unwrap(); //! # let keypair_orig: Keypair = Keypair::generate::(&mut cspring); //! # let message: &[u8] = "This is a test of the tsunami alert system.".as_bytes(); @@ -261,11 +261,12 @@ extern crate curve25519_dalek; extern crate generic_array; extern crate digest; extern crate subtle; +extern crate failure; #[cfg(feature = "std")] extern crate rand; -#[cfg(test)] +#[cfg(any(feature = "std", test))] #[macro_use] extern crate std;