diff --git a/.travis.yml b/.travis.yml new file mode 100644 index 0000000..d3b9866 --- /dev/null +++ b/.travis.yml @@ -0,0 +1,23 @@ +language: rust + +rust: + - stable + - beta + - nightly + +env: + - TEST_COMMAND=test FEATURES='' + +matrix: + include: + - rust: nightly + env: TEST_COMMAND=build FEATURES='--no-default-features' + - rust: nightly + env: TEST_COMMAND=test FEATURES='--features="nightly"' + - rust: nightly + env: TEST_COMMAND=bench FEATURES='--features="bench"' + - rust: nightly + env: TEST_COMMAND=bench FEATURES='--features="nightly bench"' + +script: + - cargo $TEST_COMMAND $FEATURES diff --git a/Cargo.toml b/Cargo.toml index 06e004d..f5166ef 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "ed25519-dalek" -version = "0.2.3" +version = "0.3.0" authors = ["Isis Lovecruft "] readme = "README.md" license = "CC0-1.0" @@ -10,11 +10,13 @@ documentation = "https://docs.rs/ed25519-dalek" keywords = ["cryptography", "ed25519", "curve25519", "signature", "ECC"] categories = ["cryptography", "no-std"] description = "Fast and efficient ed25519 signing and verification in pure Rust." -exclude = [ ".gitignore", "TESTVECTORS" ] +exclude = [ ".gitignore", "TESTVECTORS", "res/*" ] + +[badges] +travis-ci = { repository = "isislovecruft/ed25519-dalek", branch = "master"} [dependencies] arrayref = "0.3.3" -sha2 = "^0.4" [dependencies.curve25519-dalek] version = "^0.6" @@ -24,9 +26,19 @@ default-features = false optional = true version = "^0.3" +[dependencies.digest] +version = "0.4" + +[dependencies.generic-array] +# same version that digest depends on +version = "^0.6" + [dev-dependencies] rustc-serialize = "0.3" +sha2 = "^0.4" [features] default = ["std"] -std = ["rand"] +std = ["rand", "curve25519-dalek/std"] +bench = [] +nightly = ["curve25519-dalek/nightly"] diff --git a/README.md b/README.md index 3397bbb..544b48d 100644 --- a/README.md +++ b/README.md @@ -1,28 +1,38 @@ -# ed25519-dalek ![](https://img.shields.io/crates/v/ed25519-dalek.svg) ![](https://docs.rs/ed25519-dalek/badge.svg) +# ed25519-dalek ![](https://img.shields.io/crates/v/ed25519-dalek.svg) ![](https://docs.rs/ed25519-dalek/badge.svg) ![](https://travis-ci.org/isislovecruft/ed25519-dalek.svg?branch=master) Fast and efficient Rust implementation of ed25519 key generation, signing, and verification in Rust. +# Documentation + +Documentation is available [here](https://docs.rs/ed25519-dalek). + # Benchmarks +You need to pass the `--features="bench"` flag to run the benchmarks. The +reason for feature-gating the benchmarks is that Rust's `test::Bencher` is +unstable, and thus only works on the nightly channel. (We'd like people to be +able to compile and test on the stable and beta channels too!) + On an Intel i5 Sandy Bridge running at 2.6 GHz, with TurboBoost enabled (and also running in QubesOS with *lots* of other VMs executing), this code achieves the following performance benchmarks: - ∃!isisⒶwintermute:(release/0.1.0 *$)~/code/rust/ed25519 ∴ cargo bench - Finished release [optimized] target(s) in 0.0 secs - Running target/release/deps/ed25519-0135748522c518d8 + ∃!isisⒶwintermute:(develop *$)~/code/rust/ed25519 ∴ cargo bench --features="bench" + Finished release [optimized] target(s) in 0.0 secs + Running target/release/deps/ed25519_dalek-281c2d7a2379edae - running 5 tests - test ed25519::test::test_sign_verify ... ignored - test ed25519::test::test_unmarshal_marshal ... ignored - test ed25519::test::bench_key_generation ... bench: 54,837 ns/iter (+/- 11,613) - test ed25519::test::bench_sign ... bench: 69,735 ns/iter (+/- 21,902) - test ed25519::test::bench_verify ... bench: 183,891 ns/iter (+/- 75,304) + running 6 tests + test ed25519::test::golden ... ignored + test ed25519::test::sign_verify ... ignored + test ed25519::test::unmarshal_marshal ... ignored + test ed25519::bench::key_generation ... bench: 54,571 ns/iter (+/- 7,861) + test ed25519::bench::sign ... bench: 70,009 ns/iter (+/- 22,812) + test ed25519::bench::verify ... bench: 185,619 ns/iter (+/- 24,117) - test result: ok. 0 passed; 0 failed; 2 ignored; 3 measured + test result: ok. 0 passed; 0 failed; 3 ignored; 3 measured -In comparision, the equivalent package in Golang performs as follows: +In comparison, the equivalent package in Golang performs as follows: ∃!isisⒶwintermute:(master *=)~/code/go/src/github.com/agl/ed25519 ∴ go test -bench . PASS @@ -34,37 +44,109 @@ In comparision, the equivalent package in Golang performs as follows: Making key generation, signing, and verification a rough average of one third faster, one fifth faster, and one eighth faster respectively. Of course, this is just my machine, and these results—nowhere near rigorous—should be taken -with a fistful of salt. +with a handful of salt. -## Warning +Additionally, if you're on the Rust nightly channel, be sure to build with +`cargo build --features="nightly"`, which uses Rust's experimental support for +the `u128` type in curve25519-dalek to speed up field arithmetic by roughly a +factor of two. The benchmarks using nightly (on the same machine as above) +are: -[Our elliptic curve library](https://github.com/isislovecruft/curve25519-dalek) -(which this code uses) has **not** yet received sufficient peer review by -other qualified cryptographers to be considered in any way, shape, or form, -safe. + ∃!isisⒶwintermute:(develop *$)~/code/rust/ed25519 ∴ cargo bench --features="bench nightly" + Finished release [optimized] target(s) in 0.0 secs + Running target/release/deps/ed25519_dalek-9d7f8674ae11ac39 -**USE AT YOUR OWN RISK** + running 6 tests + test ed25519::test::golden ... ignored + test ed25519::test::sign_verify ... ignored + test ed25519::test::unmarshal_marshal ... ignored + test ed25519::bench::key_generation ... bench: 31,160 ns/iter (+/- 8,597) + test ed25519::bench::sign ... bench: 40,565 ns/iter (+/- 4,758) + test ed25519::bench::verify ... bench: 106,146 ns/iter (+/- 2,796) -# Documentation + test result: ok. 0 passed; 0 failed; 3 ignored; 3 measured -Documentation is available [here](https://docs.rs/ed25519-dalek). +Translating to a rough cycle count: we multiply by a factor of 2.6 to convert +nanoseconds to cycles per second on a 2.6 GHz CPU, that's 275979 cycles for +verification and 105469 for signing, which is +[competitive with the optimised assembly version](https://ed25519.cr.yp.to/) +included in the SUPERCOP benchmarking suite (albeit their numbers are for the +older Nehalem microarchitecture). + +Additionally, thanks to Rust, this implementation has both type and memory +safety. It's also easily readable a much larger set of people than those who +can read qhasm, making it more readily and more easily auditable. We're of +the opinion that, ultimately, these features—combined with speed—are more +valuable than simply cycle counts alone. + +# Warnings + +ed25519-dalek and +[our elliptic curve library](https://github.com/isislovecruft/curve25519-dalek) +(which this code uses) have received *one* formal cryptographic and security +review. Neither have yet received what we would consider *sufficient* peer +review by other qualified cryptographers to be considered in any way, shape, +or form, safe. + +**USE AT YOUR OWN RISK.** + + +### A Note on Signature Malleability + +The signatures produced by this library are malleable, as discussed in +[the original paper](https://ed25519.cr.yp.to/ed25519-20110926.pdf): + +![](https://github.com/isislovecruft/ed25519-dalek/blob/develop/res/ed25519-malleability.png) + +We could eliminate the malleability property by multiplying by the curve +cofactor, however, this would cause our implementation to *not* match the +behaviour of every other implementation in existence. As of this writing, +[RFC 8032](https://tools.ietf.org/html/rfc8032), "Edwards-Curve Digital +Signature Algorithm (EdDSA)," advises that the stronger check should be done. +While we agree that the stronger check should be done, it is our opinion that +one shouldn't get to change the definition of "ed25519 verification" a decade +after the fact, breaking compatibility with every other implementation. + +In short, if malleable signatures are bad for your protocol, don't use them. +Consider using a curve25519-based Verifiable Random Function (VRF), such as +[Trevor Perrin's VXEdDSA](https://www.whispersystems.org/docs/specifications/xeddsa/), +instead. We +[plan](https://github.com/isislovecruft/curve25519-dalek/issues/9) to +eventually support VXEdDSA in curve25519-dalek. # Installation -To install, add the following to the dependencies section of your project's -`Cargo.toml`: +To install, add the following to your project's `Cargo.toml`: - ed25519-dalek = "^0.2" + [dependencies.ed25519-dalek] + version = "^0.3" Then, in your library or executable source, add: extern crate ed25519_dalek +To cause your application to build `ed25519-dalek` with the nightly feature +enabled by default, instead do: + + [dependencies.ed25519-dalek] + version = "^0.3" + features = ["nightly"] + +To cause your application to instead build with the nightly feature enabled +when someone builds with `cargo build --features="nightly"` add the following +to the `Cargo.toml`: + + [features] + nightly = ["ed25519-dalek/nightly"] + + # TODO - * Maybe add methods to make exporting keys for backup easier. - * Benchmark in comparison to the ed25519_ref10 code. + * Maybe add methods to make exporting keys for backup easier. Maybe using + serde? * We can probably make this go even faster if we implement SHA512, rather than using the rust-crypto implementation whose API requires that we allocate memory and memzero it before mutating to store the digest. + * Incorporate ed25519-dalek into Brian Smith's + [crypto-bench](https://github.com/briansmith/crypto-bench). diff --git a/res/ed25519-malleability.png b/res/ed25519-malleability.png new file mode 100644 index 0000000..fe5896e Binary files /dev/null and b/res/ed25519-malleability.png differ diff --git a/src/ed25519.rs b/src/ed25519.rs index f431563..c7f183c 100644 --- a/src/ed25519.rs +++ b/src/ed25519.rs @@ -12,11 +12,12 @@ use core::fmt::Debug; -use sha2::{Digest, Sha512}; - #[cfg(feature = "std")] use rand::Rng; +use digest::Digest; +use generic_array::typenum::U64; + use curve25519_dalek::curve; use curve25519_dalek::curve::BasepointMult; use curve25519_dalek::curve::CompressedEdwardsY; @@ -25,6 +26,7 @@ use curve25519_dalek::curve::ProjectivePoint; use curve25519_dalek::scalar::Scalar; use curve25519_dalek::subtle::arrays_equal_ct; +/// The length of an ed25519 `Signature`, in bytes. pub const SIGNATURE_LENGTH: usize = 64; /// An ed25519 signature. @@ -129,14 +131,15 @@ impl SecretKey { /// /// A `SecretKey`. #[inline] - #[allow(dead_code)] - fn from_bytes(bytes: &[u8]) -> SecretKey { + pub fn from_bytes(bytes: &[u8]) -> SecretKey { SecretKey(*array_ref!(bytes, 0, 64)) } /// Sign a message with this keypair's secret key. - pub fn sign(&self, message: &[u8]) -> Signature { - let mut h: Sha512 = Sha512::new(); + pub fn sign(&self, message: &[u8]) -> Signature + where D: Digest + Default { + + let mut h: D = D::default(); let mut hash: [u8; 64] = [0u8; 64]; let mut signature_bytes: [u8; 64] = [0u8; SIGNATURE_LENGTH]; let mut expanded_key_secret: Scalar; @@ -157,7 +160,7 @@ impl SecretKey { expanded_key_secret[31] &= 63; expanded_key_secret[31] |= 64; - h = Sha512::new(); + h = D::default(); h.input(&hash[32..]); h.input(&message); hash.copy_from_slice(h.result().as_slice()); @@ -166,7 +169,7 @@ impl SecretKey { r = ExtendedPoint::basepoint_mult(&mesg_digest); - h = Sha512::new(); + h = D::default(); h.input(&r.compress_edwards().to_bytes()[..]); h.input(public_key); h.input(&message); @@ -225,8 +228,7 @@ impl PublicKey { /// /// A `PublicKey`. #[inline] - #[allow(dead_code)] - fn from_bytes(bytes: &[u8]) -> PublicKey { + pub fn from_bytes(bytes: &[u8]) -> PublicKey { PublicKey(CompressedEdwardsY(*array_ref!(bytes, 0, 32))) } @@ -242,12 +244,14 @@ impl PublicKey { /// /// Returns true if the signature was successfully verified, and /// false otherwise. - pub fn verify(&self, message: &[u8], signature: &Signature) -> bool { - let mut h: Sha512 = Sha512::new(); + pub fn verify(&self, message: &[u8], signature: &Signature) -> bool + where D: Digest + Default { + + let mut h: D = D::default(); let mut a: ExtendedPoint; let ao: Option; let r: ProjectivePoint; - let mut digest: [u8; 64]; + let digest: [u8; 64]; let digest_reduced: Scalar; if signature.0[63] & 224 != 0 { @@ -262,16 +266,15 @@ impl PublicKey { } a = -(&a); - digest = [0u8; 64]; - let top_half: &[u8; 32] = array_ref!(&signature.0, 32, 32); let bottom_half: &[u8; 32] = array_ref!(&signature.0, 0, 32); h.input(&bottom_half[..]); h.input(&self.to_bytes()); h.input(&message); - digest.copy_from_slice(h.result().as_slice()); + let digest_bytes = h.result(); + digest = *array_ref!(digest_bytes, 0, 64); digest_reduced = Scalar::reduce(&digest); r = curve::double_scalar_mult_vartime(&digest_reduced, &a, &Scalar(*top_half)); @@ -295,15 +298,45 @@ pub struct Keypair { impl Keypair { /// Generate an ed25519 keypair. /// + /// # Example + /// + /// ``` + /// extern crate rand; + /// extern crate sha2; + /// extern crate ed25519_dalek; + /// + /// # fn main() { + /// + /// use rand::Rng; + /// use rand::OsRng; + /// use sha2::Sha512; + /// use ed25519_dalek::Keypair; + /// use ed25519_dalek::Signature; + /// + /// let mut cspring: OsRng = OsRng::new().unwrap(); + /// let keypair: Keypair = Keypair::generate::(&mut cspring); + /// + /// # } + /// ``` + /// /// # Input /// /// A CSPRING with a `fill_bytes()` method, e.g. the one returned /// from `rand::OsRng::new()` (in the `rand` crate). + /// + /// The caller must also supply a hash function which implements the + /// `Digest` and `Default` traits, and which returns 512 bits of output. + /// 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. + /// // we reassign 0 bytes to the temp variable t to overwrite it #[cfg(feature = "std")] #[allow(unused_assignments)] - pub fn generate(cspring: &mut T) -> Keypair { - let mut h: Sha512 = Sha512::new(); + pub fn generate(cspring: &mut Rng) -> Keypair + where D: Digest + Default { + + let mut h: D = D::default(); let mut hash: [u8; 64] = [0u8; 64]; let mut t: [u8; 32] = [0u8; 32]; let mut sk: [u8; 64] = [0u8; 64]; @@ -335,13 +368,15 @@ impl Keypair { } /// Sign a message with this keypair's secret key. - pub fn sign(&self, message: &[u8]) -> Signature { - self.secret.sign(message) + pub fn sign(&self, message: &[u8]) -> Signature + where D: Digest + Default { + self.secret.sign::(message) } /// Verify a signature on a message with this keypair's public key. - pub fn verify(&self, message: &[u8], signature: &Signature) -> bool { - self.public.verify(message, signature) + pub fn verify(&self, message: &[u8], signature: &Signature) -> bool + where D: Digest + Default { + self.public.verify::(message, signature) } } @@ -352,34 +387,14 @@ mod test { use std::fs::File; use std::string::String; use std::vec::Vec; - use test::Bencher; use curve25519_dalek::curve::ExtendedPoint; use rand::OsRng; - use rand::Rng; use rustc_serialize::hex::FromHex; + use sha2::Sha512; use super::*; - /// A fake RNG which simply returns zeroes. - struct ZeroRng; - - impl ZeroRng { - fn new() -> ZeroRng { - ZeroRng - } - } - - impl Rng for ZeroRng { - fn next_u32(&mut self) -> u32 { 0u32 } - - fn fill_bytes(&mut self, bytes: &mut [u8]) { - for i in 0 .. bytes.len() { - bytes[i] = 0; - } - } - } - #[test] - fn test_unmarshal_marshal() { // TestUnmarshalMarshal + fn unmarshal_marshal() { // TestUnmarshalMarshal let mut cspring: OsRng; let mut keypair: Keypair; let mut x: Option; @@ -390,7 +405,7 @@ mod test { // from_bytes() fails if vx²-u=0 and vx²+u=0 loop { - keypair = Keypair::generate(&mut cspring); + keypair = Keypair::generate::(&mut cspring); x = keypair.public.decompress(); if x.is_some() { @@ -404,7 +419,7 @@ mod test { } #[test] - fn test_sign_verify() { // TestSignVerify + fn sign_verify() { // TestSignVerify let mut cspring: OsRng; let keypair: Keypair; let good_sig: Signature; @@ -414,15 +429,15 @@ mod test { let bad: &[u8] = "wrong message".as_bytes(); cspring = OsRng::new().unwrap(); - keypair = Keypair::generate(&mut cspring); - good_sig = keypair.sign(&good); - bad_sig = keypair.sign(&bad); + keypair = Keypair::generate::(&mut cspring); + good_sig = keypair.sign::(&good); + bad_sig = keypair.sign::(&bad); - assert!(keypair.verify(&good, &good_sig) == true, + assert!(keypair.verify::(&good, &good_sig) == true, "Verification of a valid signature failed!"); - assert!(keypair.verify(&good, &bad_sig) == false, + assert!(keypair.verify::(&good, &bad_sig) == false, "Verification of a signature on a different message passed!"); - assert!(keypair.verify(&bad, &good_sig) == false, + assert!(keypair.verify::(&bad, &good_sig) == false, "Verification of a signature on a different message passed!"); } @@ -432,7 +447,7 @@ mod test { #[cfg(test)] #[cfg(not(release))] #[test] - fn test_golden() { // TestGolden + fn golden() { // TestGolden let mut line: String; let mut lineno: usize = 0; @@ -465,40 +480,67 @@ mod test { let secret_key: SecretKey = SecretKey::from_bytes(&sec_bytes); let public_key: PublicKey = PublicKey::from_bytes(&pub_bytes); - let sig2: Signature = secret_key.sign(&message); + let sig2: Signature = secret_key.sign::(&message); println!("{:?}", sec_bytes); println!("{:?}", pub_bytes); assert!(sig1 == sig2, "Signature bytes not equal on line {}", lineno); - assert!(public_key.verify(&message, &sig2), "Signature verification failed on line {}", lineno); + assert!(public_key.verify::(&message, &sig2), + "Signature verification failed on line {}", lineno); + } + } +} +#[cfg(all(test, feature = "bench"))] +mod bench { + use test::Bencher; + use rand::OsRng; + use sha2::Sha512; + use super::*; + + /// A fake RNG which simply returns zeroes. + struct ZeroRng; + + impl ZeroRng { + pub fn new() -> ZeroRng { + ZeroRng + } + } + + impl Rng for ZeroRng { + fn next_u32(&mut self) -> u32 { 0u32 } + + fn fill_bytes(&mut self, bytes: &mut [u8]) { + for i in 0 .. bytes.len() { + bytes[i] = 0; + } } } #[bench] - fn bench_sign(b: &mut Bencher) { + fn sign(b: &mut Bencher) { let mut cspring: OsRng = OsRng::new().unwrap(); - let keypair: Keypair = Keypair::generate(&mut cspring); - let msg: &[u8] = "test message".as_bytes(); + let keypair: Keypair = Keypair::generate::(&mut cspring); + let msg: &[u8] = b""; - b.iter(| | keypair.sign(msg)); + b.iter(| | keypair.sign::(msg)); } #[bench] - fn bench_verify(b: &mut Bencher) { + fn verify(b: &mut Bencher) { let mut cspring: OsRng = OsRng::new().unwrap(); - let keypair: Keypair = Keypair::generate(&mut cspring); - let msg: &[u8] = "test message".as_bytes(); - let sig: Signature = keypair.sign(msg); + let keypair: Keypair = Keypair::generate::(&mut cspring); + let msg: &[u8] = b""; + let sig: Signature = keypair.sign::(msg); - b.iter(| | keypair.verify(msg, &sig)); + b.iter(| | keypair.verify::(msg, &sig)); } #[bench] - fn bench_key_generation(b: &mut Bencher) { + fn key_generation(b: &mut Bencher) { let mut rng: ZeroRng = ZeroRng::new(); - b.iter(| | Keypair::generate(&mut rng)); + b.iter(| | Keypair::generate::(&mut rng)); } } diff --git a/src/lib.rs b/src/lib.rs index 59e545a..a10ac2f 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -14,60 +14,107 @@ //! //! Creating an ed25519 signature on a message is simple. //! -//! 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 random number generator (CSPRING). For -//! this example, we'll use the operating system's builtin PRNG to -//! generate a keypair: +//! 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 (CSPRING), 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: //! -//! ```ignore +//! ``` //! extern crate rand; -//! extern crate ed25519; +//! extern crate sha2; +//! extern crate ed25519_dalek; //! +//! # fn main() { //! use rand::Rng; //! use rand::OsRng; -//! use ed25519::Keypair; -//! use ed25519::Signature; +//! use sha2::Sha512; +//! use ed25519_dalek::Keypair; +//! use ed25519_dalek::Signature; //! //! let mut cspring: OsRng = OsRng::new().unwrap(); -//! let keypair: Keypair = Keypair::generate(&mut cspring); +//! let keypair: Keypair = Keypair::generate::(&mut cspring); +//! # } //! ``` //! //! We can now use this `keypair` to sign a message: //! -//! ```ignore +//! ``` +//! # extern crate rand; +//! # extern crate sha2; +//! # extern crate ed25519_dalek; +//! # fn main() { +//! # use rand::Rng; +//! # use rand::OsRng; +//! # use sha2::Sha512; +//! # use ed25519_dalek::Keypair; +//! # use ed25519_dalek::Signature; +//! # let mut cspring: OsRng = OsRng::new().unwrap(); +//! # let keypair: Keypair = Keypair::generate::(&mut cspring); //! let message: &[u8] = "This is a test of the tsunami alert system.".as_bytes(); -//! let signature: Signature = keypair.sign(message); +//! let signature: Signature = keypair.sign::(message); +//! # } //! ``` //! //! As well as to verify that this is, indeed, a valid signature on //! that `message`: //! -//! ```ignore -//! let verified: bool = keypair.verify(message, &signature); +//! ``` +//! # extern crate rand; +//! # extern crate sha2; +//! # extern crate ed25519_dalek; +//! # fn main() { +//! # use rand::Rng; +//! # use rand::OsRng; +//! # use sha2::Sha512; +//! # use ed25519_dalek::Keypair; +//! # use ed25519_dalek::Signature; +//! # let mut cspring: OsRng = OsRng::new().unwrap(); +//! # let keypair: Keypair = Keypair::generate::(&mut cspring); +//! # let message: &[u8] = "This is a test of the tsunami alert system.".as_bytes(); +//! # let signature: Signature = keypair.sign::(message); +//! let verified: bool = keypair.verify::(message, &signature); //! //! assert!(verified); +//! # } //! ``` //! //! Anyone else, given the `public` half of the `keypair` can also easily //! verify this signature: //! -//! ```ignore +//! ``` +//! # extern crate rand; +//! # extern crate sha2; +//! # extern crate ed25519_dalek; +//! # fn main() { +//! # use rand::Rng; +//! # use rand::OsRng; +//! # use sha2::Sha512; +//! # use ed25519_dalek::Keypair; +//! # use ed25519_dalek::Signature; +//! use ed25519_dalek::PublicKey; +//! # let mut cspring: OsRng = OsRng::new().unwrap(); +//! # let keypair: Keypair = Keypair::generate::(&mut cspring); +//! # 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); //! //! assert!(verified); +//! # } //! ``` #![no_std] -#![feature(rand)] +#![cfg_attr(feature = "nightly", feature(rand))] #![allow(unused_features)] -#![feature(test)] +#![cfg_attr(feature = "bench", feature(test))] +#![deny(missing_docs)] // refuse to compile if documentation is missing #[macro_use] extern crate arrayref; -extern crate sha2; extern crate curve25519_dalek; +extern crate generic_array; +extern crate digest; #[cfg(feature = "std")] extern crate rand; @@ -75,11 +122,17 @@ extern crate rand; #[cfg(test)] #[macro_use] extern crate std; + #[cfg(test)] -extern crate test; +extern crate sha2; + #[cfg(test)] extern crate rustc_serialize; +#[cfg(all(test, feature = "bench"))] +extern crate test; + + mod ed25519; // Export everything public in ed25519.