mirror of
https://github.com/saymrwulf/curve25519-dalek-source.git
synced 2026-09-04 20:24:10 +00:00
Merge branch 'release/0.3.0'
This commit is contained in:
commit
b8df6454a3
6 changed files with 328 additions and 116 deletions
23
.travis.yml
Normal file
23
.travis.yml
Normal file
|
|
@ -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
|
||||
20
Cargo.toml
20
Cargo.toml
|
|
@ -1,6 +1,6 @@
|
|||
[package]
|
||||
name = "ed25519-dalek"
|
||||
version = "0.2.3"
|
||||
version = "0.3.0"
|
||||
authors = ["Isis Lovecruft <isis@torproject.org>"]
|
||||
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"]
|
||||
|
|
|
|||
134
README.md
134
README.md
|
|
@ -1,28 +1,38 @@
|
|||
# ed25519-dalek  
|
||||
# ed25519-dalek   
|
||||
|
||||
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):
|
||||
|
||||

|
||||
|
||||
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).
|
||||
|
|
|
|||
BIN
res/ed25519-malleability.png
Normal file
BIN
res/ed25519-malleability.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 43 KiB |
174
src/ed25519.rs
174
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<D>(&self, message: &[u8]) -> Signature
|
||||
where D: Digest<OutputSize = U64> + 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<D>(&self, message: &[u8], signature: &Signature) -> bool
|
||||
where D: Digest<OutputSize = U64> + Default {
|
||||
|
||||
let mut h: D = D::default();
|
||||
let mut a: ExtendedPoint;
|
||||
let ao: Option<ExtendedPoint>;
|
||||
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::<Sha512>(&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<T: Rng>(cspring: &mut T) -> Keypair {
|
||||
let mut h: Sha512 = Sha512::new();
|
||||
pub fn generate<D>(cspring: &mut Rng) -> Keypair
|
||||
where D: Digest<OutputSize = U64> + 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<D>(&self, message: &[u8]) -> Signature
|
||||
where D: Digest<OutputSize = U64> + Default {
|
||||
self.secret.sign::<D>(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<D>(&self, message: &[u8], signature: &Signature) -> bool
|
||||
where D: Digest<OutputSize = U64> + Default {
|
||||
self.public.verify::<D>(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<ExtendedPoint>;
|
||||
|
|
@ -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::<Sha512>(&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::<Sha512>(&mut cspring);
|
||||
good_sig = keypair.sign::<Sha512>(&good);
|
||||
bad_sig = keypair.sign::<Sha512>(&bad);
|
||||
|
||||
assert!(keypair.verify(&good, &good_sig) == true,
|
||||
assert!(keypair.verify::<Sha512>(&good, &good_sig) == true,
|
||||
"Verification of a valid signature failed!");
|
||||
assert!(keypair.verify(&good, &bad_sig) == false,
|
||||
assert!(keypair.verify::<Sha512>(&good, &bad_sig) == false,
|
||||
"Verification of a signature on a different message passed!");
|
||||
assert!(keypair.verify(&bad, &good_sig) == false,
|
||||
assert!(keypair.verify::<Sha512>(&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::<Sha512>(&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::<Sha512>(&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::<Sha512>(&mut cspring);
|
||||
let msg: &[u8] = b"";
|
||||
|
||||
b.iter(| | keypair.sign(msg));
|
||||
b.iter(| | keypair.sign::<Sha512>(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::<Sha512>(&mut cspring);
|
||||
let msg: &[u8] = b"";
|
||||
let sig: Signature = keypair.sign::<Sha512>(msg);
|
||||
|
||||
b.iter(| | keypair.verify(msg, &sig));
|
||||
b.iter(| | keypair.verify::<Sha512>(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::<Sha512>(&mut rng));
|
||||
}
|
||||
}
|
||||
|
|
|
|||
93
src/lib.rs
93
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::<Sha512>(&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::<Sha512>(&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::<Sha512>(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::<Sha512>(&mut cspring);
|
||||
//! # let message: &[u8] = "This is a test of the tsunami alert system.".as_bytes();
|
||||
//! # let signature: Signature = keypair.sign::<Sha512>(message);
|
||||
//! let verified: bool = keypair.verify::<Sha512>(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::<Sha512>(&mut cspring);
|
||||
//! # let message: &[u8] = "This is a test of the tsunami alert system.".as_bytes();
|
||||
//! # let signature: Signature = keypair.sign::<Sha512>(message);
|
||||
//! let public_key: PublicKey = keypair.public;
|
||||
//! let verified: bool = public_key.verify(message, &signature);
|
||||
//! let verified: bool = public_key.verify::<Sha512>(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.
|
||||
|
|
|
|||
Loading…
Reference in a new issue