Merge branch 'release/1.0.0-pre.1'

This commit is contained in:
Isis Lovecruft 2019-01-18 05:58:42 +00:00
commit a65683accd
No known key found for this signature in database
GPG key ID: AB41313533E8E812
13 changed files with 1542 additions and 1385 deletions

View file

@ -7,14 +7,19 @@ rust:
env: env:
- TEST_COMMAND=test FEATURES='' - TEST_COMMAND=test FEATURES=''
- TEST_COMMAND=test FEATURES=--features="serde"
matrix: matrix:
include: include:
# 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 - rust: nightly
env: TEST_COMMAND=build FEATURES="--no-default-features --features=u32_backend" env: TEST_COMMAND=build FEATURES='--no-default-features --features=u32_backend'
# Test any nightly gated features on nightly:
- rust: nightly - rust: nightly
env: TEST_COMMAND=test FEATURES=--features="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: script:
- cargo $TEST_COMMAND $FEATURES - cargo $TEST_COMMAND $FEATURES

View file

@ -1,7 +1,7 @@
[package] [package]
name = "ed25519-dalek" name = "ed25519-dalek"
version = "0.9.1" version = "1.0.0-pre.1"
authors = ["Isis Lovecruft <isis@patternsinthevoid.net>"] authors = ["isis lovecruft <isis@patternsinthevoid.net>"]
readme = "README.md" readme = "README.md"
license = "BSD-3-Clause" license = "BSD-3-Clause"
repository = "https://github.com/dalek-cryptography/ed25519-dalek" repository = "https://github.com/dalek-cryptography/ed25519-dalek"
@ -21,7 +21,6 @@ default-features = false
[dependencies.rand] [dependencies.rand]
version = "0.6" version = "0.6"
default-features = false
features = ["i128_support"] features = ["i128_support"]
[dependencies.serde] [dependencies.serde]
@ -30,7 +29,7 @@ optional = true
[dependencies.sha2] [dependencies.sha2]
version = "^0.8" version = "^0.8"
optional = true default-features = false
[dependencies.failure] [dependencies.failure]
version = "^0.1.1" version = "^0.1.1"
@ -41,7 +40,6 @@ version = "0.2"
[dev-dependencies] [dev-dependencies]
hex = "^0.3" hex = "^0.3"
sha2 = "^0.8"
bincode = "^0.9" bincode = "^0.9"
criterion = "0.2" criterion = "0.2"
@ -51,8 +49,7 @@ harness = false
[features] [features]
default = ["std", "u64_backend"] 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"]
std = ["curve25519-dalek/std"]
alloc = ["curve25519-dalek/alloc"] alloc = ["curve25519-dalek/alloc"]
nightly = ["curve25519-dalek/nightly", "rand/nightly", "clear_on_drop/nightly"] nightly = ["curve25519-dalek/nightly", "rand/nightly", "clear_on_drop/nightly"]
asm = ["sha2/asm"] asm = ["sha2/asm"]

View file

@ -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 Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are modification, are permitted provided that the following conditions are

View file

@ -118,7 +118,7 @@ To install, add the following to your project's `Cargo.toml`:
```toml ```toml
[dependencies.ed25519-dalek] [dependencies.ed25519-dalek]
version = "0.9" version = "1"
``` ```
Then, in your library or executable source, add: Then, in your library or executable source, add:
@ -134,7 +134,7 @@ enabled by default, instead do:
```toml ```toml
[dependencies.ed25519-dalek] [dependencies.ed25519-dalek]
version = "0.9" version = "1"
features = ["nightly"] features = ["nightly"]
``` ```
@ -151,7 +151,7 @@ To enable [serde](https://serde.rs) support, build `ed25519-dalek` with:
```toml ```toml
[dependencies.ed25519-dalek] [dependencies.ed25519-dalek]
version = "0.9" version = "1"
features = ["serde"] features = ["serde"]
``` ```

View file

@ -1,17 +1,16 @@
// -*- mode: rust; -*- // -*- mode: rust; -*-
// //
// This file is part of ed25519-dalek. // This file is part of ed25519-dalek.
// Copyright (c) 2018 Isis Lovecruft // Copyright (c) 2018-2019 isis lovecruft
// See LICENSE for licensing information. // See LICENSE for licensing information.
// //
// Authors: // Authors:
// - Isis Agora Lovecruft <isis@patternsinthevoid.net> // - isis agora lovecruft <isis@patternsinthevoid.net>
#[macro_use] #[macro_use]
extern crate criterion; extern crate criterion;
extern crate ed25519_dalek; extern crate ed25519_dalek;
extern crate rand; extern crate rand;
extern crate sha2;
use criterion::Criterion; use criterion::Criterion;
@ -23,38 +22,37 @@ mod ed25519_benches {
use ed25519_dalek::Signature; use ed25519_dalek::Signature;
use ed25519_dalek::verify_batch; use ed25519_dalek::verify_batch;
use rand::thread_rng; use rand::thread_rng;
use rand::ThreadRng; use rand::rngs::ThreadRng;
use sha2::Sha512;
fn sign(c: &mut Criterion) { fn sign(c: &mut Criterion) {
let mut csprng: ThreadRng = thread_rng(); let mut csprng: ThreadRng = thread_rng();
let keypair: Keypair = Keypair::generate::<Sha512, _>(&mut csprng); let keypair: Keypair = Keypair::generate(&mut csprng);
let msg: &[u8] = b""; let msg: &[u8] = b"";
c.bench_function("Ed25519 signing", move |b| { c.bench_function("Ed25519 signing", move |b| {
b.iter(| | keypair.sign::<Sha512>(msg)) b.iter(| | keypair.sign(msg))
}); });
} }
fn sign_expanded_key(c: &mut Criterion) { fn sign_expanded_key(c: &mut Criterion) {
let mut csprng: ThreadRng = thread_rng(); let mut csprng: ThreadRng = thread_rng();
let keypair: Keypair = Keypair::generate::<Sha512, _>(&mut csprng); let keypair: Keypair = Keypair::generate(&mut csprng);
let expanded: ExpandedSecretKey = keypair.secret.expand::<Sha512>(); let expanded: ExpandedSecretKey = (&keypair.secret).into();
let msg: &[u8] = b""; let msg: &[u8] = b"";
c.bench_function("Ed25519 signing with an expanded secret key", move |b| { c.bench_function("Ed25519 signing with an expanded secret key", move |b| {
b.iter(| | expanded.sign::<Sha512>(msg, &keypair.public)) b.iter(| | expanded.sign(msg, &keypair.public))
}); });
} }
fn verify(c: &mut Criterion) { fn verify(c: &mut Criterion) {
let mut csprng: ThreadRng = thread_rng(); let mut csprng: ThreadRng = thread_rng();
let keypair: Keypair = Keypair::generate::<Sha512, _>(&mut csprng); let keypair: Keypair = Keypair::generate(&mut csprng);
let msg: &[u8] = b""; let msg: &[u8] = b"";
let sig: Signature = keypair.sign::<Sha512>(msg); let sig: Signature = keypair.sign(msg);
c.bench_function("Ed25519 signature verification", move |b| { c.bench_function("Ed25519 signature verification", move |b| {
b.iter(| | keypair.verify::<Sha512>(msg, &sig)) b.iter(| | keypair.verify(msg, &sig))
}); });
} }
@ -65,13 +63,13 @@ mod ed25519_benches {
"Ed25519 batch signature verification", "Ed25519 batch signature verification",
|b, &&size| { |b, &&size| {
let mut csprng: ThreadRng = thread_rng(); let mut csprng: ThreadRng = thread_rng();
let keypairs: Vec<Keypair> = (0..size).map(|_| Keypair::generate::<Sha512, _>(&mut csprng)).collect(); let keypairs: Vec<Keypair> = (0..size).map(|_| Keypair::generate(&mut csprng)).collect();
let msg: &[u8] = b"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"; let msg: &[u8] = b"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa";
let messages: Vec<&[u8]> = (0..size).map(|_| msg).collect(); let messages: Vec<&[u8]> = (0..size).map(|_| msg).collect();
let signatures: Vec<Signature> = keypairs.iter().map(|key| key.sign::<Sha512>(&msg)).collect(); let signatures: Vec<Signature> = keypairs.iter().map(|key| key.sign(&msg)).collect();
let public_keys: Vec<PublicKey> = keypairs.iter().map(|key| key.public).collect(); let public_keys: Vec<PublicKey> = keypairs.iter().map(|key| key.public).collect();
b.iter(|| verify_batch::<Sha512>(&messages[..], &signatures[..], &public_keys[..])); b.iter(|| verify_batch(&messages[..], &signatures[..], &public_keys[..]));
}, },
&BATCH_SIZES, &BATCH_SIZES,
); );
@ -81,7 +79,7 @@ mod ed25519_benches {
let mut csprng: ThreadRng = thread_rng(); let mut csprng: ThreadRng = thread_rng();
c.bench_function("Ed25519 keypair generation", move |b| { c.bench_function("Ed25519 keypair generation", move |b| {
b.iter(| | Keypair::generate::<Sha512, _>(&mut csprng)) b.iter(| | Keypair::generate(&mut csprng))
}); });
} }

31
src/constants.rs Normal file
View file

@ -0,0 +1,31 @@
// -*- mode: rust; -*-
//
// This file is part of ed25519-dalek.
// Copyright (c) 2017-2019 isis lovecruft
// See LICENSE for licensing information.
//
// Authors:
// - isis agora lovecruft <isis@patternsinthevoid.net>
//! 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;

File diff suppressed because it is too large Load diff

View file

@ -1,11 +1,11 @@
// -*- mode: rust; -*- // -*- mode: rust; -*-
// //
// This file is part of ed25519-dalek. // This file is part of ed25519-dalek.
// Copyright (c) 2017 Isis Lovecruft // Copyright (c) 2017-2019 isis lovecruft
// See LICENSE for licensing information. // See LICENSE for licensing information.
// //
// Authors: // Authors:
// - Isis Agora Lovecruft <isis@patternsinthevoid.net> // - isis agora lovecruft <isis@patternsinthevoid.net>
//! Errors which may occur when parsing keys and/or signatures to or from wire formats. //! Errors which may occur when parsing keys and/or signatures to or from wire formats.
@ -19,7 +19,7 @@ use core::fmt::Display;
/// Internal errors. Most application-level developers will likely not /// Internal errors. Most application-level developers will likely not
/// need to pay any attention to these. /// need to pay any attention to these.
#[derive(Clone, Copy, Debug, Eq, PartialEq, Hash)] #[derive(Clone, Copy, Debug, Eq, PartialEq, Hash)]
pub (crate) enum InternalError { pub(crate) enum InternalError {
PointDecompressionError, PointDecompressionError,
ScalarFormatError, ScalarFormatError,
/// An error in the length of bytes handed to a constructor. /// An error in the length of bytes handed to a constructor.
@ -27,13 +27,16 @@ pub (crate) enum InternalError {
/// To use this, pass a string specifying the `name` of the type which is /// 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 /// returning the error, and the `length` in bytes which its constructor
/// expects. /// expects.
BytesLengthError{ name: &'static str, length: usize }, BytesLengthError {
name: &'static str,
length: usize,
},
/// The verification equation wasn't satisfied /// The verification equation wasn't satisfied
VerifyError, VerifyError,
} }
impl Display for 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 { match *self {
InternalError::PointDecompressionError InternalError::PointDecompressionError
=> write!(f, "Cannot decompress Edwards point"), => write!(f, "Cannot decompress Edwards point"),
@ -64,16 +67,16 @@ impl ::failure::Fail for InternalError {}
/// ///
/// * Failure of a signature to satisfy the verification equation. /// * Failure of a signature to satisfy the verification equation.
#[derive(Clone, Copy, Eq, PartialEq, Hash, Debug)] #[derive(Clone, Copy, Eq, PartialEq, Hash, Debug)]
pub struct SignatureError(pub (crate) InternalError); pub struct SignatureError(pub(crate) InternalError);
impl Display for SignatureError { 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) write!(f, "{}", self.0)
} }
} }
impl ::failure::Fail for SignatureError { impl ::failure::Fail for SignatureError {
fn cause(&self) -> Option<&::failure::Fail> { fn cause(&self) -> Option<&dyn (::failure::Fail)> {
Some(&self.0) Some(&self.0)
} }
} }

View file

@ -1,13 +1,13 @@
// -*- mode: rust; -*- // -*- mode: rust; -*-
// //
// This file is part of ed25519-dalek. // This file is part of ed25519-dalek.
// Copyright (c) 2017-2018 Isis Lovecruft // Copyright (c) 2017-2019 isis lovecruft
// See LICENSE for licensing information. // See LICENSE for licensing information.
// //
// Authors: // Authors:
// - Isis Agora Lovecruft <isis@patternsinthevoid.net> // - isis agora lovecruft <isis@patternsinthevoid.net>
//! ed25519 signatures and verification //! A Rust implementation of ed25519 key generation, signing, and verification.
//! //!
//! # Example //! # Example
//! //!
@ -15,28 +15,25 @@
//! //!
//! First, we need to generate a `Keypair`, which includes both public and //! 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 //! secret halves of an asymmetric key. To do so, we need a cryptographically
//! secure pseudorandom number generator (CSPRNG), and a hash function which //! secure pseudorandom number generator (CSPRNG). For this example, we'll use
//! has 512 bits of output. For this example, we'll use the operating //! the operating system's builtin PRNG:
//! system's builtin PRNG and SHA-512 to generate a keypair:
//! //!
//! ``` //! ```
//! extern crate rand; //! extern crate rand;
//! extern crate sha2;
//! extern crate ed25519_dalek; //! extern crate ed25519_dalek;
//! //!
//! # #[cfg(all(feature = "std", feature = "sha2"))] //! # #[cfg(feature = "std")]
//! # fn main() { //! # fn main() {
//! use rand::Rng; //! use rand::Rng;
//! use rand::OsRng; //! use rand::rngs::OsRng;
//! use sha2::Sha512;
//! use ed25519_dalek::Keypair; //! use ed25519_dalek::Keypair;
//! use ed25519_dalek::Signature; //! use ed25519_dalek::Signature;
//! //!
//! let mut csprng: OsRng = OsRng::new().unwrap(); //! let mut csprng: OsRng = OsRng::new().unwrap();
//! let keypair: Keypair = Keypair::generate::<Sha512, _>(&mut csprng); //! let keypair: Keypair = Keypair::generate(&mut csprng);
//! # } //! # }
//! # //! #
//! # #[cfg(any(not(feature = "std"), not(feature = "sha2")))] //! # #[cfg(not(feature = "std"))]
//! # fn main() { } //! # fn main() { }
//! ``` //! ```
//! //!
@ -44,19 +41,16 @@
//! //!
//! ``` //! ```
//! # extern crate rand; //! # extern crate rand;
//! # extern crate sha2;
//! # extern crate ed25519_dalek; //! # extern crate ed25519_dalek;
//! # fn main() { //! # fn main() {
//! # use rand::Rng; //! # use rand::Rng;
//! # use rand::ChaChaRng; //! # use rand::thread_rng;
//! # use rand::SeedableRng;
//! # use sha2::Sha512;
//! # use ed25519_dalek::Keypair; //! # use ed25519_dalek::Keypair;
//! # use ed25519_dalek::Signature; //! # use ed25519_dalek::Signature;
//! # let mut csprng: ChaChaRng = ChaChaRng::from_seed([0u8; 32]); //! # let mut csprng = thread_rng();
//! # let keypair: Keypair = Keypair::generate::<Sha512, _>(&mut csprng); //! # let keypair: Keypair = Keypair::generate(&mut csprng);
//! let message: &[u8] = "This is a test of the tsunami alert system.".as_bytes(); //! let message: &[u8] = b"This is a test of the tsunami alert system.";
//! let signature: Signature = keypair.sign::<Sha512>(message); //! let signature: Signature = keypair.sign(message);
//! # } //! # }
//! ``` //! ```
//! //!
@ -65,20 +59,17 @@
//! //!
//! ``` //! ```
//! # extern crate rand; //! # extern crate rand;
//! # extern crate sha2;
//! # extern crate ed25519_dalek; //! # extern crate ed25519_dalek;
//! # fn main() { //! # fn main() {
//! # use rand::Rng; //! # use rand::Rng;
//! # use rand::ChaChaRng; //! # use rand::thread_rng;
//! # use rand::SeedableRng;
//! # use sha2::Sha512;
//! # use ed25519_dalek::Keypair; //! # use ed25519_dalek::Keypair;
//! # use ed25519_dalek::Signature; //! # use ed25519_dalek::Signature;
//! # let mut csprng: ChaChaRng = ChaChaRng::from_seed([0u8; 32]); //! # let mut csprng = thread_rng();
//! # let keypair: Keypair = Keypair::generate::<Sha512, _>(&mut csprng); //! # let keypair: Keypair = Keypair::generate(&mut csprng);
//! # let message: &[u8] = "This is a test of the tsunami alert system.".as_bytes(); //! # let message: &[u8] = b"This is a test of the tsunami alert system.";
//! # let signature: Signature = keypair.sign::<Sha512>(message); //! # let signature: Signature = keypair.sign(message);
//! assert!(keypair.verify::<Sha512>(message, &signature).is_ok()); //! assert!(keypair.verify(message, &signature).is_ok());
//! # } //! # }
//! ``` //! ```
//! //!
@ -87,23 +78,20 @@
//! //!
//! ``` //! ```
//! # extern crate rand; //! # extern crate rand;
//! # extern crate sha2;
//! # extern crate ed25519_dalek; //! # extern crate ed25519_dalek;
//! # fn main() { //! # fn main() {
//! # use rand::Rng; //! # use rand::Rng;
//! # use rand::ChaChaRng; //! # use rand::thread_rng;
//! # use rand::SeedableRng;
//! # use sha2::Sha512;
//! # use ed25519_dalek::Keypair; //! # use ed25519_dalek::Keypair;
//! # use ed25519_dalek::Signature; //! # use ed25519_dalek::Signature;
//! use ed25519_dalek::PublicKey; //! use ed25519_dalek::PublicKey;
//! # let mut csprng: ChaChaRng = ChaChaRng::from_seed([0u8; 32]); //! # let mut csprng = thread_rng();
//! # let keypair: Keypair = Keypair::generate::<Sha512, _>(&mut csprng); //! # let keypair: Keypair = Keypair::generate(&mut csprng);
//! # let message: &[u8] = "This is a test of the tsunami alert system.".as_bytes(); //! # let message: &[u8] = b"This is a test of the tsunami alert system.";
//! # let signature: Signature = keypair.sign::<Sha512>(message); //! # let signature: Signature = keypair.sign(message);
//! //!
//! let public_key: PublicKey = keypair.public; //! let public_key: PublicKey = keypair.public;
//! assert!(public_key.verify::<Sha512>(message, &signature).is_ok()); //! assert!(public_key.verify(message, &signature).is_ok());
//! # } //! # }
//! ``` //! ```
//! //!
@ -117,17 +105,16 @@
//! //!
//! ``` //! ```
//! # extern crate rand; //! # extern crate rand;
//! # extern crate sha2;
//! # extern crate ed25519_dalek; //! # extern crate ed25519_dalek;
//! # fn main() { //! # fn main() {
//! # use rand::{Rng, ChaChaRng, SeedableRng}; //! # use rand::Rng;
//! # use sha2::Sha512; //! # use rand::thread_rng;
//! # use ed25519_dalek::{Keypair, Signature, PublicKey}; //! # use ed25519_dalek::{Keypair, Signature, PublicKey};
//! use ed25519_dalek::{PUBLIC_KEY_LENGTH, SECRET_KEY_LENGTH, KEYPAIR_LENGTH, SIGNATURE_LENGTH}; //! 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::<Sha512, _>(&mut csprng); //! # let keypair: Keypair = Keypair::generate(&mut csprng);
//! # let message: &[u8] = "This is a test of the tsunami alert system.".as_bytes(); //! # let message: &[u8] = b"This is a test of the tsunami alert system.";
//! # let signature: Signature = keypair.sign::<Sha512>(message); //! # let signature: Signature = keypair.sign(message);
//! # let public_key: PublicKey = keypair.public; //! # let public_key: PublicKey = keypair.public;
//! //!
//! let public_key_bytes: [u8; PUBLIC_KEY_LENGTH] = public_key.to_bytes(); //! let public_key_bytes: [u8; PUBLIC_KEY_LENGTH] = public_key.to_bytes();
@ -141,17 +128,16 @@
//! //!
//! ``` //! ```
//! # extern crate rand; //! # extern crate rand;
//! # extern crate sha2;
//! # extern crate ed25519_dalek; //! # extern crate ed25519_dalek;
//! # use rand::{Rng, ChaChaRng, SeedableRng}; //! # use rand::Rng;
//! # use sha2::Sha512; //! # use rand::thread_rng;
//! # use ed25519_dalek::{Keypair, Signature, PublicKey, SecretKey, SignatureError}; //! # use ed25519_dalek::{Keypair, Signature, PublicKey, SecretKey, SignatureError};
//! # use ed25519_dalek::{PUBLIC_KEY_LENGTH, SECRET_KEY_LENGTH, KEYPAIR_LENGTH, SIGNATURE_LENGTH}; //! # use ed25519_dalek::{PUBLIC_KEY_LENGTH, SECRET_KEY_LENGTH, KEYPAIR_LENGTH, SIGNATURE_LENGTH};
//! # fn do_test() -> Result<(SecretKey, PublicKey, Keypair, Signature), SignatureError> { //! # 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::<Sha512, _>(&mut csprng); //! # let keypair_orig: Keypair = Keypair::generate(&mut csprng);
//! # let message: &[u8] = "This is a test of the tsunami alert system.".as_bytes(); //! # let message: &[u8] = b"This is a test of the tsunami alert system.";
//! # let signature_orig: Signature = keypair_orig.sign::<Sha512>(message); //! # let signature_orig: Signature = keypair_orig.sign(message);
//! # let public_key_bytes: [u8; PUBLIC_KEY_LENGTH] = keypair_orig.public.to_bytes(); //! # 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 secret_key_bytes: [u8; SECRET_KEY_LENGTH] = keypair_orig.secret.to_bytes();
//! # let keypair_bytes: [u8; KEYPAIR_LENGTH] = keypair_orig.to_bytes(); //! # let keypair_bytes: [u8; KEYPAIR_LENGTH] = keypair_orig.to_bytes();
@ -184,7 +170,6 @@
//! //!
//! ``` //! ```
//! # extern crate rand; //! # extern crate rand;
//! # extern crate sha2;
//! # extern crate ed25519_dalek; //! # extern crate ed25519_dalek;
//! # #[cfg(feature = "serde")] //! # #[cfg(feature = "serde")]
//! extern crate serde; //! extern crate serde;
@ -193,16 +178,16 @@
//! //!
//! # #[cfg(feature = "serde")] //! # #[cfg(feature = "serde")]
//! # fn main() { //! # fn main() {
//! # use rand::{Rng, ChaChaRng, SeedableRng}; //! # use rand::Rng;
//! # use sha2::Sha512; //! # use rand::thread_rng;
//! # use ed25519_dalek::{Keypair, Signature, PublicKey}; //! # use ed25519_dalek::{Keypair, Signature, PublicKey};
//! use bincode::{serialize, Infinite}; //! use bincode::{serialize, Infinite};
//! # let mut csprng: ChaChaRng = ChaChaRng::from_seed([0u8; 32]); //! # let mut csprng = thread_rng();
//! # let keypair: Keypair = Keypair::generate::<Sha512>(&mut csprng); //! # let keypair: Keypair = Keypair::generate(&mut csprng);
//! # let message: &[u8] = "This is a test of the tsunami alert system.".as_bytes(); //! # let message: &[u8] = b"This is a test of the tsunami alert system.";
//! # let signature: Signature = keypair.sign::<Sha512>(message); //! # let signature: Signature = keypair.sign(message);
//! # let public_key: PublicKey = keypair.public; //! # let public_key: PublicKey = keypair.public;
//! # let verified: bool = public_key.verify::<Sha512>(message, &signature); //! # let verified: bool = public_key.verify(message, &signature).is_ok();
//! //!
//! let encoded_public_key: Vec<u8> = serialize(&public_key, Infinite).unwrap(); //! let encoded_public_key: Vec<u8> = serialize(&public_key, Infinite).unwrap();
//! let encoded_signature: Vec<u8> = serialize(&signature, Infinite).unwrap(); //! let encoded_signature: Vec<u8> = serialize(&signature, Infinite).unwrap();
@ -216,7 +201,6 @@
//! //!
//! ``` //! ```
//! # extern crate rand; //! # extern crate rand;
//! # extern crate sha2;
//! # extern crate ed25519_dalek; //! # extern crate ed25519_dalek;
//! # #[cfg(feature = "serde")] //! # #[cfg(feature = "serde")]
//! # extern crate serde; //! # extern crate serde;
@ -225,18 +209,18 @@
//! # //! #
//! # #[cfg(feature = "serde")] //! # #[cfg(feature = "serde")]
//! # fn main() { //! # fn main() {
//! # use rand::{Rng, ChaChaRng, SeedableRng}; //! # use rand::Rng;
//! # use sha2::Sha512; //! # use rand::thread_rng;
//! # use ed25519_dalek::{Keypair, Signature, PublicKey}; //! # use ed25519_dalek::{Keypair, Signature, PublicKey};
//! # use bincode::{serialize, Infinite}; //! # use bincode::{serialize, Infinite};
//! use bincode::{deserialize}; //! use bincode::{deserialize};
//! //!
//! # let mut csprng: ChaChaRng = ChaChaRng::from_seed([0u8; 32]); //! # let mut csprng = thread_rng();
//! # let keypair: Keypair = Keypair::generate::<Sha512>(&mut csprng); //! # let keypair: Keypair = Keypair::generate(&mut csprng);
//! let message: &[u8] = "This is a test of the tsunami alert system.".as_bytes(); //! let message: &[u8] = b"This is a test of the tsunami alert system.";
//! # let signature: Signature = keypair.sign::<Sha512>(message); //! # let signature: Signature = keypair.sign(message);
//! # let public_key: PublicKey = keypair.public; //! # let public_key: PublicKey = keypair.public;
//! # let verified: bool = public_key.verify::<Sha512>(message, &signature); //! # let verified: bool = public_key.verify(message, &signature).is_ok();
//! # let encoded_public_key: Vec<u8> = serialize(&public_key, Infinite).unwrap(); //! # let encoded_public_key: Vec<u8> = serialize(&public_key, Infinite).unwrap();
//! # let encoded_signature: Vec<u8> = serialize(&signature, Infinite).unwrap(); //! # let encoded_signature: Vec<u8> = serialize(&signature, Infinite).unwrap();
//! let decoded_public_key: PublicKey = deserialize(&encoded_public_key).unwrap(); //! let decoded_public_key: PublicKey = deserialize(&encoded_public_key).unwrap();
@ -245,7 +229,7 @@
//! # assert_eq!(public_key, decoded_public_key); //! # assert_eq!(public_key, decoded_public_key);
//! # assert_eq!(signature, decoded_signature); //! # assert_eq!(signature, decoded_signature);
//! # //! #
//! let verified: bool = decoded_public_key.verify::<Sha512>(&message, &decoded_signature); //! let verified: bool = decoded_public_key.verify(&message, &decoded_signature).is_ok();
//! //!
//! assert!(verified); //! assert!(verified);
//! # } //! # }
@ -254,34 +238,29 @@
//! ``` //! ```
#![no_std] #![no_std]
#![allow(unused_features)] #![warn(future_incompatible)]
#![warn(rust_2018_compatibility)]
#![warn(rust_2018_idioms)]
#![deny(missing_docs)] // refuse to compile if documentation is missing #![deny(missing_docs)] // refuse to compile if documentation is missing
extern crate curve25519_dalek;
extern crate failure;
extern crate rand;
extern crate clear_on_drop;
#[cfg(any(feature = "std", test))] #[cfg(any(feature = "std", test))]
#[macro_use] #[macro_use]
extern crate std; extern crate std;
#[cfg(any(test, feature = "sha2"))] extern crate clear_on_drop;
extern crate sha2; extern crate curve25519_dalek;
extern crate failure;
#[cfg(test)] extern crate rand;
extern crate hex;
#[cfg(feature = "serde")] #[cfg(feature = "serde")]
extern crate serde; extern crate serde;
extern crate sha2;
#[cfg(all(test, feature = "serde"))] mod constants;
extern crate bincode;
mod ed25519; mod ed25519;
mod errors;
pub mod errors; mod public;
mod secret;
mod signature;
// Export everything public in ed25519. // Export everything public in ed25519.
pub use ed25519::*; pub use crate::ed25519::*;
pub use errors::*;

285
src/public.rs Normal file
View file

@ -0,0 +1,285 @@
// -*- mode: rust; -*-
//
// This file is part of ed25519-dalek.
// Copyright (c) 2017-2019 isis lovecruft
// See LICENSE for licensing information.
//
// Authors:
// - isis agora lovecruft <isis@patternsinthevoid.net>
//! ed25519 public keys.
use core::fmt::Debug;
use curve25519_dalek::constants;
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::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::*;
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<PublicKey, SignatureError> {
/// 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<PublicKey, SignatureError> {
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<D>(
&self,
prehashed_message: D,
context: Option<&[u8]>,
signature: &Signature,
) -> Result<(), SignatureError>
where
D: Digest<OutputSize = U64>,
{
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<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where
S: Serializer,
{
serializer.serialize_bytes(self.as_bytes())
}
}
#[cfg(feature = "serde")]
impl<'d> Deserialize<'d> for PublicKey {
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
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<E>(self, bytes: &[u8]) -> Result<PublicKey, E>
where
E: SerdeError,
{
PublicKey::from_bytes(bytes).or(Err(SerdeError::invalid_length(bytes.len(), &self)))
}
}
deserializer.deserialize_bytes(PublicKeyVisitor)
}
}

566
src/secret.rs Normal file
View file

@ -0,0 +1,566 @@
// -*- mode: rust; -*-
//
// This file is part of ed25519-dalek.
// Copyright (c) 2017-2019 isis lovecruft
// See LICENSE for licensing information.
//
// Authors:
// - isis agora lovecruft <isis@patternsinthevoid.net>
//! ed25519 secret key types.
use core::fmt::Debug;
use clear_on_drop::clear::Clear;
use curve25519_dalek::constants;
use curve25519_dalek::digest::generic_array::typenum::U64;
use curve25519_dalek::digest::Digest;
use curve25519_dalek::edwards::CompressedEdwardsY;
use curve25519_dalek::scalar::Scalar;
use rand::CryptoRng;
use rand::Rng;
use sha2::Sha512;
#[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::*;
use crate::public::*;
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<SecretKey, SignatureError> {
/// 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<SecretKey, SignatureError> {
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<T>(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<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where
S: Serializer,
{
serializer.serialize_bytes(self.as_bytes())
}
}
#[cfg(feature = "serde")]
impl<'d> Deserialize<'d> for SecretKey {
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
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<E>(self, bytes: &[u8]) -> Result<SecretKey, E>
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<ExpandedSecretKey, SignatureError> {
/// #
/// 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<ExpandedSecretKey, SignatureError> {
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<D>(
&self,
prehashed_message: D,
public_key: &PublicKey,
context: Option<&'static [u8]>,
) -> Signature
where
D: Digest<OutputSize = U64>,
{
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<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where
S: Serializer,
{
serializer.serialize_bytes(&self.to_bytes()[..])
}
}
#[cfg(feature = "serde")]
impl<'d> Deserialize<'d> for ExpandedSecretKey {
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
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<E>(self, bytes: &[u8]) -> Result<ExpandedSecretKey, E>
where
E: SerdeError,
{
ExpandedSecretKey::from_bytes(bytes)
.or(Err(SerdeError::invalid_length(bytes.len(), &self)))
}
}
deserializer.deserialize_bytes(ExpandedSecretKeyVisitor)
}
}

145
src/signature.rs Normal file
View file

@ -0,0 +1,145 @@
// -*- mode: rust; -*-
//
// This file is part of ed25519-dalek.
// Copyright (c) 2017-2019 isis lovecruft
// See LICENSE for licensing information.
//
// Authors:
// - isis agora lovecruft <isis@patternsinthevoid.net>
//! An ed25519 signature.
use core::fmt::Debug;
use curve25519_dalek::edwards::CompressedEdwardsY;
use curve25519_dalek::scalar::Scalar;
#[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::*;
/// 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<Signature, SignatureError> {
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<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where
S: Serializer,
{
serializer.serialize_bytes(&self.to_bytes()[..])
}
}
#[cfg(feature = "serde")]
impl<'d> Deserialize<'d> for Signature {
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
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<E>(self, bytes: &[u8]) -> Result<Signature, E>
where
E: SerdeError,
{
Signature::from_bytes(bytes).or(Err(SerdeError::invalid_length(bytes.len(), &self)))
}
}
deserializer.deserialize_bytes(SignatureVisitor)
}
}

293
tests/ed25519.rs Normal file
View file

@ -0,0 +1,293 @@
// -*- mode: rust; -*-
//
// This file is part of ed25519-dalek.
// Copyright (c) 2017-2019 isis lovecruft
// See LICENSE for licensing information.
//
// Authors:
// - isis agora lovecruft <isis@patternsinthevoid.net>
//! Integration tests for ed25519-dalek.
#[cfg(all(test, feature = "serde"))]
extern crate bincode;
extern crate ed25519_dalek;
extern crate hex;
extern crate rand;
extern crate sha2;
use ed25519_dalek::*;
use hex::FromHex;
use rand::thread_rng;
use rand::rngs::ThreadRng;
use sha2::Sha512;
#[cfg(test)]
mod vectors {
use std::io::BufReader;
use std::io::BufRead;
use std::fs::File;
use super::*;
// 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
#[test]
fn against_reference_implementation() { // 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<u8> = FromHex::from_hex(&parts[0]).unwrap();
let pub_bytes: Vec<u8> = FromHex::from_hex(&parts[1]).unwrap();
let msg_bytes: Vec<u8> = FromHex::from_hex(&parts[2]).unwrap();
let sig_bytes: Vec<u8> = 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<u8> = FromHex::from_hex(secret_key).unwrap();
let pub_bytes: Vec<u8> = FromHex::from_hex(public_key).unwrap();
let msg_bytes: Vec<u8> = FromHex::from_hex(message).unwrap();
let sig_bytes: Vec<u8> = 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!");
}
}
#[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() {
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<Keypair> = Vec::new();
let mut signatures: Vec<Signature> = 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<PublicKey> = 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"))]
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, ];
#[test]
fn serialize_deserialize_signature() {
let signature: Signature = Signature::from_bytes(&SIGNATURE_BYTES).unwrap();
let encoded_signature: Vec<u8> = serialize(&signature, Infinite).unwrap();
let decoded_signature: Signature = deserialize(&encoded_signature).unwrap();
assert_eq!(signature, decoded_signature);
}
#[test]
fn serialize_deserialize_public_key() {
let public_key: PublicKey = PublicKey::from_bytes(&PUBLIC_KEY_BYTES).unwrap();
let encoded_public_key: Vec<u8> = 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);
}
#[test]
fn serialize_deserialize_secret_key() {
let secret_key: SecretKey = SecretKey::from_bytes(&SECRET_KEY_BYTES).unwrap();
let encoded_secret_key: Vec<u8> = serialize(&secret_key, Infinite).unwrap();
let decoded_secret_key: SecretKey = deserialize(&encoded_secret_key).unwrap();
for i in 0..32 {
assert_eq!(SECRET_KEY_BYTES[i], decoded_secret_key.as_bytes()[i]);
}
}
#[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
}
#[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
}
#[test]
fn serialize_secret_key_size() {
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
}
}