Merge branch 'release/1.0.0-pre.4'

This commit is contained in:
Isis Lovecruft 2020-07-16 23:31:08 +00:00
commit ae0b48b0cd
No known key found for this signature in database
GPG key ID: AB41313533E8E812
10 changed files with 327 additions and 222 deletions

View file

@ -1,6 +1,6 @@
[package] [package]
name = "ed25519-dalek" name = "ed25519-dalek"
version = "1.0.0-pre.3" version = "1.0.0-pre.4"
edition = "2018" edition = "2018"
authors = ["isis lovecruft <isis@patternsinthevoid.net>"] authors = ["isis lovecruft <isis@patternsinthevoid.net>"]
readme = "README.md" readme = "README.md"
@ -22,19 +22,22 @@ travis-ci = { repository = "dalek-cryptography/ed25519-dalek", branch = "master"
features = ["nightly", "batch"] features = ["nightly", "batch"]
[dependencies] [dependencies]
clear_on_drop = { version = "0.2" }
curve25519-dalek = { version = "2", default-features = false } curve25519-dalek = { version = "2", default-features = false }
merlin = { version = "1", default-features = false, optional = true, git = "https://github.com/isislovecruft/merlin", branch = "develop" } ed25519 = { version = "1", default-features = false }
merlin = { version = "2", default-features = false, optional = true }
rand = { version = "0.7", default-features = false, optional = true } rand = { version = "0.7", default-features = false, optional = true }
rand_core = { version = "0.5", default-features = false, optional = true } rand_core = { version = "0.5", default-features = false, optional = true }
serde = { version = "1.0", optional = true } serde_crate = { package = "serde", version = "1.0", default-features = false, optional = true }
sha2 = { version = "0.8", default-features = false } sha2 = { version = "0.8", default-features = false }
zeroize = { version = "1", default-features = false, features = ["zeroize_derive"] }
[dev-dependencies] [dev-dependencies]
hex = "^0.4" hex = "^0.4"
bincode = "^0.9" bincode = "^0.9"
criterion = "0.3" criterion = "0.3"
rand = "0.7" rand = "0.7"
serde_crate = { package = "serde", version = "1.0", features = ["derive"] }
toml = { version = "0.5" }
[[bench]] [[bench]]
name = "ed25519_benchmarks" name = "ed25519_benchmarks"
@ -45,9 +48,10 @@ harness = false
[features] [features]
default = ["std", "u64_backend"] default = ["std", "u64_backend"]
std = ["curve25519-dalek/std", "sha2/std", "rand/std"] std = ["curve25519-dalek/std", "ed25519/std", "serde_crate/std", "sha2/std", "rand/std"]
alloc = ["curve25519-dalek/alloc", "rand/alloc"] alloc = ["curve25519-dalek/alloc", "rand/alloc", "zeroize/alloc"]
nightly = ["curve25519-dalek/nightly", "clear_on_drop/nightly", "rand/nightly"] nightly = ["curve25519-dalek/nightly", "rand/nightly"]
serde = ["serde_crate", "ed25519/serde"]
batch = ["merlin", "rand"] batch = ["merlin", "rand"]
# This feature enables deterministic batch verification. # This feature enables deterministic batch verification.
batch_deterministic = ["merlin", "rand", "rand_core"] batch_deterministic = ["merlin", "rand", "rand_core"]

View file

@ -20,6 +20,7 @@ mod ed25519_benches {
use ed25519_dalek::Keypair; use ed25519_dalek::Keypair;
use ed25519_dalek::PublicKey; use ed25519_dalek::PublicKey;
use ed25519_dalek::Signature; use ed25519_dalek::Signature;
use ed25519_dalek::Signer;
use ed25519_dalek::verify_batch; use ed25519_dalek::verify_batch;
use rand::thread_rng; use rand::thread_rng;
use rand::prelude::ThreadRng; use rand::prelude::ThreadRng;

View file

@ -9,11 +9,14 @@
//! Batch signature verification. //! Batch signature verification.
#[cfg(feature = "alloc")]
extern crate alloc;
#[cfg(feature = "alloc")] #[cfg(feature = "alloc")]
use alloc::vec::Vec; use alloc::vec::Vec;
#[cfg(feature = "std")] #[cfg(all(not(feature = "alloc"), feature = "std"))]
use std::vec::Vec; use std::vec::Vec;
use core::convert::TryFrom;
use core::iter::once; use core::iter::once;
use curve25519_dalek::constants; use curve25519_dalek::constants;
@ -37,7 +40,7 @@ use sha2::Sha512;
use crate::errors::InternalError; use crate::errors::InternalError;
use crate::errors::SignatureError; use crate::errors::SignatureError;
use crate::public::PublicKey; use crate::public::PublicKey;
use crate::signature::Signature; use crate::signature::InternalSignature;
trait BatchTranscript { trait BatchTranscript {
fn append_hrams(&mut self, hrams: &Vec<Scalar>); fn append_hrams(&mut self, hrams: &Vec<Scalar>);
@ -111,7 +114,6 @@ fn zero_rng() -> ZeroRng {
/// * `messages` is a slice of byte slices, one per signed message. /// * `messages` is a slice of byte slices, one per signed message.
/// * `signatures` is a slice of `Signature`s. /// * `signatures` is a slice of `Signature`s.
/// * `public_keys` is a slice of `PublicKey`s. /// * `public_keys` is a slice of `PublicKey`s.
/// * `csprng` is an implementation of `Rng + CryptoRng`.
/// ///
/// # Returns /// # Returns
/// ///
@ -128,6 +130,7 @@ fn zero_rng() -> ZeroRng {
/// use ed25519_dalek::verify_batch; /// use ed25519_dalek::verify_batch;
/// use ed25519_dalek::Keypair; /// use ed25519_dalek::Keypair;
/// use ed25519_dalek::PublicKey; /// use ed25519_dalek::PublicKey;
/// use ed25519_dalek::Signer;
/// use ed25519_dalek::Signature; /// use ed25519_dalek::Signature;
/// use rand::rngs::OsRng; /// use rand::rngs::OsRng;
/// ///
@ -148,7 +151,7 @@ fn zero_rng() -> ZeroRng {
#[allow(non_snake_case)] #[allow(non_snake_case)]
pub fn verify_batch( pub fn verify_batch(
messages: &[&[u8]], messages: &[&[u8]],
signatures: &[Signature], signatures: &[ed25519::Signature],
public_keys: &[PublicKey], public_keys: &[PublicKey],
) -> Result<(), SignatureError> ) -> Result<(), SignatureError>
{ {
@ -156,13 +159,19 @@ pub fn verify_batch(
if signatures.len() != messages.len() || if signatures.len() != messages.len() ||
signatures.len() != public_keys.len() || signatures.len() != public_keys.len() ||
public_keys.len() != messages.len() { public_keys.len() != messages.len() {
return Err(SignatureError(InternalError::ArrayLengthError{ return Err(InternalError::ArrayLengthError{
name_a: "signatures", length_a: signatures.len(), name_a: "signatures", length_a: signatures.len(),
name_b: "messages", length_b: messages.len(), name_b: "messages", length_b: messages.len(),
name_c: "public_keys", length_c: public_keys.len(), name_c: "public_keys", length_c: public_keys.len(),
})); }.into());
} }
// Convert all signatures to `InternalSignature`
let signatures = signatures
.iter()
.map(InternalSignature::try_from)
.collect::<Result<Vec<_>, _>>()?;
// Compute H(R || A || M) for each (signature, public_key, message) triplet // Compute H(R || A || M) for each (signature, public_key, message) triplet
let hrams: Vec<Scalar> = (0..signatures.len()).map(|i| { let hrams: Vec<Scalar> = (0..signatures.len()).map(|i| {
let mut h: Sha512 = Sha512::default(); let mut h: Sha512 = Sha512::default();
@ -195,7 +204,6 @@ pub fn verify_batch(
.map(|_| Scalar::from(prng.gen::<u128>())) .map(|_| Scalar::from(prng.gen::<u128>()))
.collect(); .collect();
// Compute the basepoint coefficient, ∑ s[i]z[i] (mod l) // Compute the basepoint coefficient, ∑ s[i]z[i] (mod l)
let B_coefficient: Scalar = signatures let B_coefficient: Scalar = signatures
.iter() .iter()
@ -215,11 +223,11 @@ pub fn verify_batch(
let id = EdwardsPoint::optional_multiscalar_mul( let id = EdwardsPoint::optional_multiscalar_mul(
once(-B_coefficient).chain(zs.iter().cloned()).chain(zhrams), once(-B_coefficient).chain(zs.iter().cloned()).chain(zhrams),
B.chain(Rs).chain(As), B.chain(Rs).chain(As),
).ok_or_else(|| SignatureError(InternalError::VerifyError))?; ).ok_or(InternalError::VerifyError)?;
if id.is_identity() { if id.is_identity() {
Ok(()) Ok(())
} else { } else {
Err(SignatureError(InternalError::VerifyError)) Err(InternalError::VerifyError.into())
} }
} }

View file

@ -41,6 +41,8 @@ pub(crate) enum InternalError {
ArrayLengthError{ name_a: &'static str, length_a: usize, ArrayLengthError{ name_a: &'static str, length_a: usize,
name_b: &'static str, length_b: usize, name_b: &'static str, length_b: usize,
name_c: &'static str, length_c: usize, }, name_c: &'static str, length_c: usize, },
/// An ed25519ph signature can only take up to 255 octets of context.
PrehashedContextLengthError,
} }
impl Display for InternalError { impl Display for InternalError {
@ -59,6 +61,8 @@ impl Display for InternalError {
name_c: nc, length_c: lc, } name_c: nc, length_c: lc, }
=> write!(f, "Arrays must be the same length: {} has length {}, => write!(f, "Arrays must be the same length: {} has length {},
{} has length {}, {} has length {}.", na, la, nb, lb, nc, lc), {} has length {}, {} has length {}.", na, la, nb, lb, nc, lc),
InternalError::PrehashedContextLengthError
=> write!(f, "An ed25519ph signature can only take up to 255 octets of context"),
} }
} }
} }
@ -80,18 +84,16 @@ impl Error for InternalError { }
/// only be constructed from 255-bit integers.) /// only be constructed from 255-bit integers.)
/// ///
/// * 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)] pub type SignatureError = ed25519::signature::Error;
pub struct SignatureError(pub(crate) InternalError);
impl Display for SignatureError { impl From<InternalError> for SignatureError {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { #[cfg(not(feature = "std"))]
write!(f, "{}", self.0) fn from(_err: InternalError) -> SignatureError {
} SignatureError::new()
} }
#[cfg(feature = "std")] #[cfg(feature = "std")]
impl Error for SignatureError { fn from(err: InternalError) -> SignatureError {
fn source(&self) -> Option<&(dyn Error + 'static)> { SignatureError::from_source(err)
Some(&self.0)
} }
} }

View file

@ -9,8 +9,7 @@
//! ed25519 keypairs. //! ed25519 keypairs.
use core::default::Default; #[cfg(feature = "rand")]
use rand::{CryptoRng, RngCore}; use rand::{CryptoRng, RngCore};
#[cfg(feature = "serde")] #[cfg(feature = "serde")]
@ -18,6 +17,8 @@ use serde::de::Error as SerdeError;
#[cfg(feature = "serde")] #[cfg(feature = "serde")]
use serde::de::Visitor; use serde::de::Visitor;
#[cfg(feature = "serde")] #[cfg(feature = "serde")]
use serde::de::SeqAccess;
#[cfg(feature = "serde")]
use serde::{Deserialize, Deserializer, Serialize, Serializer}; use serde::{Deserialize, Deserializer, Serialize, Serializer};
pub use sha2::Sha512; pub use sha2::Sha512;
@ -25,16 +26,15 @@ pub use sha2::Sha512;
use curve25519_dalek::digest::generic_array::typenum::U64; use curve25519_dalek::digest::generic_array::typenum::U64;
pub use curve25519_dalek::digest::Digest; pub use curve25519_dalek::digest::Digest;
#[cfg(all(feature = "batch", any(feature = "std", feature = "alloc")))] use ed25519::signature::{Signer, Verifier};
pub use crate::batch::*;
pub use crate::constants::*; use crate::constants::*;
pub use crate::errors::*; use crate::errors::*;
pub use crate::public::*; use crate::public::*;
pub use crate::secret::*; use crate::secret::*;
pub use crate::signature::*;
/// An ed25519 keypair. /// An ed25519 keypair.
#[derive(Debug, Default)] // we derive Default in order to use the clear() method in Drop #[derive(Debug)]
pub struct Keypair { pub struct Keypair {
/// The secret half of this keypair. /// The secret half of this keypair.
pub secret: SecretKey, pub secret: SecretKey,
@ -81,10 +81,10 @@ impl Keypair {
/// is an `SignatureError` describing the error that occurred. /// is an `SignatureError` describing the error that occurred.
pub fn from_bytes<'a>(bytes: &'a [u8]) -> Result<Keypair, SignatureError> { pub fn from_bytes<'a>(bytes: &'a [u8]) -> Result<Keypair, SignatureError> {
if bytes.len() != KEYPAIR_LENGTH { if bytes.len() != KEYPAIR_LENGTH {
return Err(SignatureError(InternalError::BytesLengthError { return Err(InternalError::BytesLengthError {
name: "Keypair", name: "Keypair",
length: KEYPAIR_LENGTH, length: KEYPAIR_LENGTH,
})); }.into());
} }
let secret = SecretKey::from_bytes(&bytes[..SECRET_KEY_LENGTH])?; let secret = SecretKey::from_bytes(&bytes[..SECRET_KEY_LENGTH])?;
let public = PublicKey::from_bytes(&bytes[SECRET_KEY_LENGTH..])?; let public = PublicKey::from_bytes(&bytes[SECRET_KEY_LENGTH..])?;
@ -135,13 +135,6 @@ impl Keypair {
Keypair{ public: pk, secret: sk } Keypair{ public: pk, secret: sk }
} }
/// Sign a message with this keypair's secret key.
pub fn sign(&self, message: &[u8]) -> Signature {
let expanded: ExpandedSecretKey = (&self.secret).into();
expanded.sign(&message, &self.public)
}
/// Sign a `prehashed_message` with this `Keypair` using the /// Sign a `prehashed_message` with this `Keypair` using the
/// Ed25519ph algorithm defined in [RFC8032 §5.1][rfc8032]. /// Ed25519ph algorithm defined in [RFC8032 §5.1][rfc8032].
/// ///
@ -214,11 +207,11 @@ impl Keypair {
/// # use ed25519_dalek::Digest; /// # use ed25519_dalek::Digest;
/// # use ed25519_dalek::Keypair; /// # use ed25519_dalek::Keypair;
/// # use ed25519_dalek::Signature; /// # use ed25519_dalek::Signature;
/// # use ed25519_dalek::SignatureError;
/// # use ed25519_dalek::Sha512; /// # use ed25519_dalek::Sha512;
/// # use rand::rngs::OsRng; /// # use rand::rngs::OsRng;
/// # /// #
/// # #[cfg(feature = "std")] /// # fn do_test() -> Result<Signature, SignatureError> {
/// # fn main() {
/// # let mut csprng = OsRng{}; /// # let mut csprng = OsRng{};
/// # let keypair: Keypair = Keypair::generate(&mut csprng); /// # let keypair: Keypair = Keypair::generate(&mut csprng);
/// # let message: &[u8] = b"All I want is to pet all of the dogs."; /// # let message: &[u8] = b"All I want is to pet all of the dogs.";
@ -227,7 +220,13 @@ impl Keypair {
/// # /// #
/// let context: &[u8] = b"Ed25519DalekSignPrehashedDoctest"; /// let context: &[u8] = b"Ed25519DalekSignPrehashedDoctest";
/// ///
/// let sig: Signature = keypair.sign_prehashed(prehashed, Some(context)); /// let sig: Signature = keypair.sign_prehashed(prehashed, Some(context))?;
/// #
/// # Ok(sig)
/// # }
/// # #[cfg(feature = "std")]
/// # fn main() {
/// # do_test();
/// # } /// # }
/// # /// #
/// # #[cfg(not(feature = "std"))] /// # #[cfg(not(feature = "std"))]
@ -240,20 +239,20 @@ impl Keypair {
&self, &self,
prehashed_message: D, prehashed_message: D,
context: Option<&[u8]>, context: Option<&[u8]>,
) -> Signature ) -> Result<ed25519::Signature, SignatureError>
where where
D: Digest<OutputSize = U64>, D: Digest<OutputSize = U64>,
{ {
let expanded: ExpandedSecretKey = (&self.secret).into(); // xxx thanks i hate this let expanded: ExpandedSecretKey = (&self.secret).into(); // xxx thanks i hate this
expanded.sign_prehashed(prehashed_message, &self.public, context) expanded.sign_prehashed(prehashed_message, &self.public, context).into()
} }
/// Verify a signature on a message with this keypair's public key. /// Verify a signature on a message with this keypair's public key.
pub fn verify( pub fn verify(
&self, &self,
message: &[u8], message: &[u8],
signature: &Signature signature: &ed25519::Signature
) -> Result<(), SignatureError> ) -> Result<(), SignatureError>
{ {
self.public.verify(message, signature) self.public.verify(message, signature)
@ -285,11 +284,11 @@ impl Keypair {
/// use ed25519_dalek::Digest; /// use ed25519_dalek::Digest;
/// use ed25519_dalek::Keypair; /// use ed25519_dalek::Keypair;
/// use ed25519_dalek::Signature; /// use ed25519_dalek::Signature;
/// use ed25519_dalek::SignatureError;
/// use ed25519_dalek::Sha512; /// use ed25519_dalek::Sha512;
/// use rand::rngs::OsRng; /// use rand::rngs::OsRng;
/// ///
/// # #[cfg(feature = "std")] /// # fn do_test() -> Result<(), SignatureError> {
/// # fn main() {
/// let mut csprng = OsRng{}; /// let mut csprng = OsRng{};
/// let keypair: Keypair = Keypair::generate(&mut csprng); /// let keypair: Keypair = Keypair::generate(&mut csprng);
/// let message: &[u8] = b"All I want is to pet all of the dogs."; /// let message: &[u8] = b"All I want is to pet all of the dogs.";
@ -299,7 +298,7 @@ impl Keypair {
/// ///
/// let context: &[u8] = b"Ed25519DalekSignPrehashedDoctest"; /// let context: &[u8] = b"Ed25519DalekSignPrehashedDoctest";
/// ///
/// let sig: Signature = keypair.sign_prehashed(prehashed, Some(context)); /// let sig: Signature = keypair.sign_prehashed(prehashed, Some(context))?;
/// ///
/// // The sha2::Sha512 struct doesn't implement Copy, so we'll have to create a new one: /// // The sha2::Sha512 struct doesn't implement Copy, so we'll have to create a new one:
/// let mut prehashed_again: Sha512 = Sha512::default(); /// let mut prehashed_again: Sha512 = Sha512::default();
@ -308,6 +307,13 @@ impl Keypair {
/// let verified = keypair.public.verify_prehashed(prehashed_again, Some(context), &sig); /// let verified = keypair.public.verify_prehashed(prehashed_again, Some(context), &sig);
/// ///
/// assert!(verified.is_ok()); /// assert!(verified.is_ok());
///
/// # verified
/// # }
/// #
/// # #[cfg(feature = "std")]
/// # fn main() {
/// # do_test();
/// # } /// # }
/// # /// #
/// # #[cfg(not(feature = "std"))] /// # #[cfg(not(feature = "std"))]
@ -319,7 +325,7 @@ impl Keypair {
&self, &self,
prehashed_message: D, prehashed_message: D,
context: Option<&[u8]>, context: Option<&[u8]>,
signature: &Signature, signature: &ed25519::Signature,
) -> Result<(), SignatureError> ) -> Result<(), SignatureError>
where where
D: Digest<OutputSize = U64>, D: Digest<OutputSize = U64>,
@ -393,13 +399,28 @@ impl Keypair {
pub fn verify_strict( pub fn verify_strict(
&self, &self,
message: &[u8], message: &[u8],
signature: &Signature, signature: &ed25519::Signature,
) -> Result<(), SignatureError> ) -> Result<(), SignatureError>
{ {
self.public.verify_strict(message, signature) self.public.verify_strict(message, signature)
} }
} }
impl Signer<ed25519::Signature> for Keypair {
/// Sign a message with this keypair's secret key.
fn try_sign(&self, message: &[u8]) -> Result<ed25519::Signature, SignatureError> {
let expanded: ExpandedSecretKey = (&self.secret).into();
Ok(expanded.sign(&message, &self.public).into())
}
}
impl Verifier<ed25519::Signature> for Keypair {
/// Verify a signature on a message with this keypair's public key.
fn verify(&self, message: &[u8], signature: &ed25519::Signature) -> Result<(), SignatureError> {
self.public.verify(message, signature)
}
}
#[cfg(feature = "serde")] #[cfg(feature = "serde")]
impl Serialize for Keypair { impl Serialize for Keypair {
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error> fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
@ -431,39 +452,48 @@ impl<'d> Deserialize<'d> for Keypair {
where where
E: SerdeError, E: SerdeError,
{ {
if bytes.len() != KEYPAIR_LENGTH {
return Err(SerdeError::invalid_length(bytes.len(), &self));
}
let secret_key = SecretKey::from_bytes(&bytes[..SECRET_KEY_LENGTH]); let secret_key = SecretKey::from_bytes(&bytes[..SECRET_KEY_LENGTH]);
let public_key = PublicKey::from_bytes(&bytes[SECRET_KEY_LENGTH..]); let public_key = PublicKey::from_bytes(&bytes[SECRET_KEY_LENGTH..]);
if secret_key.is_ok() && public_key.is_ok() { if let (Ok(secret), Ok(public)) = (secret_key, public_key) {
Ok(Keypair{ secret: secret_key.unwrap(), public: public_key.unwrap() }) Ok(Keypair{ secret, public })
} else { } else {
Err(SerdeError::invalid_length(bytes.len(), &self)) Err(SerdeError::invalid_length(bytes.len(), &self))
} }
} }
fn visit_seq<A>(self, mut seq: A) -> Result<Keypair, A::Error>
where
A: SeqAccess<'d>
{
if let Some(len) = seq.size_hint() {
if len != KEYPAIR_LENGTH {
return Err(SerdeError::invalid_length(len, &self));
}
}
// TODO: We could do this with `MaybeUninit` to avoid unnecessary initialization costs
let mut bytes: [u8; KEYPAIR_LENGTH] = [0u8; KEYPAIR_LENGTH];
for i in 0..KEYPAIR_LENGTH {
bytes[i] = seq.next_element()?.ok_or_else(|| SerdeError::invalid_length(i, &self))?;
}
let secret_key = SecretKey::from_bytes(&bytes[..SECRET_KEY_LENGTH]);
let public_key = PublicKey::from_bytes(&bytes[SECRET_KEY_LENGTH..]);
if let (Ok(secret), Ok(public)) = (secret_key, public_key) {
Ok(Keypair{ secret, public })
} else {
Err(SerdeError::invalid_length(bytes.len(), &self))
}
}
} }
deserializer.deserialize_bytes(KeypairVisitor) deserializer.deserialize_bytes(KeypairVisitor)
} }
} }
#[cfg(test)]
mod test {
use super::*;
use clear_on_drop::clear::Clear;
#[test]
fn keypair_clear_on_drop() {
let mut keypair: Keypair = Keypair::from_bytes(&[1u8; KEYPAIR_LENGTH][..]).unwrap();
keypair.clear();
fn as_bytes<T>(x: &T) -> &[u8] {
use std::mem;
use std::slice;
unsafe { slice::from_raw_parts(x as *const T as *const u8, mem::size_of_val(x)) }
}
assert!(!as_bytes(&keypair).contains(&0x15));
}
}

View file

@ -44,9 +44,9 @@
//! # fn main() { //! # fn main() {
//! # use rand::rngs::OsRng; //! # use rand::rngs::OsRng;
//! # use ed25519_dalek::Keypair; //! # use ed25519_dalek::Keypair;
//! # use ed25519_dalek::Signature;
//! # let mut csprng = OsRng{}; //! # let mut csprng = OsRng{};
//! # let keypair: Keypair = Keypair::generate(&mut csprng); //! # let keypair: Keypair = Keypair::generate(&mut csprng);
//! use ed25519_dalek::{Signature, Signer};
//! let message: &[u8] = b"This is a test of the tsunami alert system."; //! let message: &[u8] = b"This is a test of the tsunami alert system.";
//! let signature: Signature = keypair.sign(message); //! let signature: Signature = keypair.sign(message);
//! # } //! # }
@ -60,12 +60,12 @@
//! # extern crate ed25519_dalek; //! # extern crate ed25519_dalek;
//! # fn main() { //! # fn main() {
//! # use rand::rngs::OsRng; //! # use rand::rngs::OsRng;
//! # use ed25519_dalek::Keypair; //! # use ed25519_dalek::{Keypair, Signature, Signer};
//! # use ed25519_dalek::Signature;
//! # let mut csprng = OsRng{}; //! # let mut csprng = OsRng{};
//! # let keypair: Keypair = Keypair::generate(&mut csprng); //! # let keypair: Keypair = Keypair::generate(&mut csprng);
//! # let message: &[u8] = b"This is a test of the tsunami alert system."; //! # let message: &[u8] = b"This is a test of the tsunami alert system.";
//! # let signature: Signature = keypair.sign(message); //! # let signature: Signature = keypair.sign(message);
//! use ed25519_dalek::Verifier;
//! assert!(keypair.verify(message, &signature).is_ok()); //! assert!(keypair.verify(message, &signature).is_ok());
//! # } //! # }
//! ``` //! ```
@ -80,7 +80,8 @@
//! # use rand::rngs::OsRng; //! # use rand::rngs::OsRng;
//! # use ed25519_dalek::Keypair; //! # use ed25519_dalek::Keypair;
//! # use ed25519_dalek::Signature; //! # use ed25519_dalek::Signature;
//! use ed25519_dalek::PublicKey; //! # use ed25519_dalek::Signer;
//! use ed25519_dalek::{PublicKey, Verifier};
//! # let mut csprng = OsRng{}; //! # let mut csprng = OsRng{};
//! # let keypair: Keypair = Keypair::generate(&mut csprng); //! # let keypair: Keypair = Keypair::generate(&mut csprng);
//! # let message: &[u8] = b"This is a test of the tsunami alert system."; //! # let message: &[u8] = b"This is a test of the tsunami alert system.";
@ -104,7 +105,7 @@
//! # extern crate ed25519_dalek; //! # extern crate ed25519_dalek;
//! # fn main() { //! # fn main() {
//! # use rand::rngs::OsRng; //! # use rand::rngs::OsRng;
//! # use ed25519_dalek::{Keypair, Signature, PublicKey}; //! # use ed25519_dalek::{Keypair, Signature, Signer, 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 = OsRng{}; //! # let mut csprng = OsRng{};
//! # let keypair: Keypair = Keypair::generate(&mut csprng); //! # let keypair: Keypair = Keypair::generate(&mut csprng);
@ -124,8 +125,9 @@
//! ``` //! ```
//! # extern crate rand; //! # extern crate rand;
//! # extern crate ed25519_dalek; //! # extern crate ed25519_dalek;
//! # use std::convert::TryFrom;
//! # use rand::rngs::OsRng; //! # use rand::rngs::OsRng;
//! # use ed25519_dalek::{Keypair, Signature, PublicKey, SecretKey, SignatureError}; //! # use ed25519_dalek::{Keypair, Signature, Signer, 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 = OsRng{}; //! # let mut csprng = OsRng{};
@ -140,7 +142,7 @@
//! let public_key: PublicKey = PublicKey::from_bytes(&public_key_bytes)?; //! let public_key: PublicKey = PublicKey::from_bytes(&public_key_bytes)?;
//! let secret_key: SecretKey = SecretKey::from_bytes(&secret_key_bytes)?; //! let secret_key: SecretKey = SecretKey::from_bytes(&secret_key_bytes)?;
//! let keypair: Keypair = Keypair::from_bytes(&keypair_bytes)?; //! let keypair: Keypair = Keypair::from_bytes(&keypair_bytes)?;
//! let signature: Signature = Signature::from_bytes(&signature_bytes)?; //! let signature: Signature = Signature::try_from(&signature_bytes[..])?;
//! # //! #
//! # Ok((secret_key, public_key, keypair, signature)) //! # Ok((secret_key, public_key, keypair, signature))
//! # } //! # }
@ -166,14 +168,14 @@
//! # extern crate rand; //! # extern crate rand;
//! # extern crate ed25519_dalek; //! # extern crate ed25519_dalek;
//! # #[cfg(feature = "serde")] //! # #[cfg(feature = "serde")]
//! extern crate serde; //! # extern crate serde_crate as serde;
//! # #[cfg(feature = "serde")] //! # #[cfg(feature = "serde")]
//! extern crate bincode; //! # extern crate bincode;
//! //!
//! # #[cfg(feature = "serde")] //! # #[cfg(feature = "serde")]
//! # fn main() { //! # fn main() {
//! # use rand::rngs::OsRng; //! # use rand::rngs::OsRng;
//! # use ed25519_dalek::{Keypair, Signature, PublicKey}; //! # use ed25519_dalek::{Keypair, Signature, Signer, Verifier, PublicKey};
//! use bincode::{serialize, Infinite}; //! use bincode::{serialize, Infinite};
//! # let mut csprng = OsRng{}; //! # let mut csprng = OsRng{};
//! # let keypair: Keypair = Keypair::generate(&mut csprng); //! # let keypair: Keypair = Keypair::generate(&mut csprng);
@ -196,16 +198,16 @@
//! # extern crate rand; //! # extern crate rand;
//! # extern crate ed25519_dalek; //! # extern crate ed25519_dalek;
//! # #[cfg(feature = "serde")] //! # #[cfg(feature = "serde")]
//! # extern crate serde; //! # extern crate serde_crate as serde;
//! # #[cfg(feature = "serde")] //! # #[cfg(feature = "serde")]
//! # extern crate bincode; //! # extern crate bincode;
//! # //! #
//! # #[cfg(feature = "serde")] //! # #[cfg(feature = "serde")]
//! # fn main() { //! # fn main() {
//! # use rand::rngs::OsRng; //! # use rand::rngs::OsRng;
//! # use ed25519_dalek::{Keypair, Signature, PublicKey}; //! # use ed25519_dalek::{Keypair, Signature, Signer, Verifier, PublicKey};
//! # use bincode::{serialize, Infinite}; //! # use bincode::{serialize, Infinite};
//! use bincode::{deserialize}; //! use bincode::deserialize;
//! //!
//! # let mut csprng = OsRng{}; //! # let mut csprng = OsRng{};
//! # let keypair: Keypair = Keypair::generate(&mut csprng); //! # let keypair: Keypair = Keypair::generate(&mut csprng);
@ -237,28 +239,39 @@
#[macro_use] #[macro_use]
extern crate std; extern crate std;
pub extern crate ed25519;
#[cfg(all(feature = "alloc", not(feature = "std")))] #[cfg(all(feature = "alloc", not(feature = "std")))]
extern crate alloc; extern crate alloc;
extern crate clear_on_drop;
extern crate curve25519_dalek; extern crate curve25519_dalek;
#[cfg(all(any(feature = "batch", feature = "batch_deterministic"), any(feature = "std", feature = "alloc")))] #[cfg(all(any(feature = "batch", feature = "batch_deterministic"), any(feature = "std", feature = "alloc")))]
extern crate merlin; extern crate merlin;
#[cfg(any(feature = "batch", feature = "std", feature = "alloc", test))] #[cfg(any(feature = "batch", feature = "std", feature = "alloc", test))]
extern crate rand; extern crate rand;
#[cfg(feature = "serde")] #[cfg(feature = "serde")]
extern crate serde; extern crate serde_crate as serde;
extern crate sha2; extern crate sha2;
extern crate zeroize;
#[cfg(all(any(feature = "batch", feature = "batch_deterministic"), any(feature = "std", feature = "alloc")))] #[cfg(all(any(feature = "batch", feature = "batch_deterministic"), any(feature = "std", feature = "alloc")))]
mod batch; mod batch;
mod constants; mod constants;
mod ed25519; mod keypair;
mod errors; mod errors;
mod public; mod public;
mod secret; mod secret;
mod signature; mod signature;
// Export everything public in ed25519. pub use curve25519_dalek::digest::Digest;
pub use crate::ed25519::*;
#[cfg(all(any(feature = "batch", feature = "batch_deterministic"), any(feature = "std", feature = "alloc")))] #[cfg(all(any(feature = "batch", feature = "batch_deterministic"), any(feature = "std", feature = "alloc")))]
pub use crate::batch::*; pub use crate::batch::*;
pub use crate::constants::*;
pub use crate::errors::*;
pub use crate::keypair::*;
pub use crate::public::*;
pub use crate::secret::*;
// Re-export the `Signer` and `Verifier` traits from the `signature` crate
pub use ed25519::signature::{Signer, Verifier};
pub use ed25519::Signature;

View file

@ -9,6 +9,7 @@
//! ed25519 public keys. //! ed25519 public keys.
use core::convert::TryFrom;
use core::fmt::Debug; use core::fmt::Debug;
use curve25519_dalek::constants; use curve25519_dalek::constants;
@ -18,6 +19,8 @@ use curve25519_dalek::edwards::CompressedEdwardsY;
use curve25519_dalek::edwards::EdwardsPoint; use curve25519_dalek::edwards::EdwardsPoint;
use curve25519_dalek::scalar::Scalar; use curve25519_dalek::scalar::Scalar;
use ed25519::signature::Verifier;
pub use sha2::Sha512; pub use sha2::Sha512;
#[cfg(feature = "serde")] #[cfg(feature = "serde")]
@ -127,10 +130,10 @@ impl PublicKey {
#[inline] #[inline]
pub fn from_bytes(bytes: &[u8]) -> Result<PublicKey, SignatureError> { pub fn from_bytes(bytes: &[u8]) -> Result<PublicKey, SignatureError> {
if bytes.len() != PUBLIC_KEY_LENGTH { if bytes.len() != PUBLIC_KEY_LENGTH {
return Err(SignatureError(InternalError::BytesLengthError { return Err(InternalError::BytesLengthError {
name: "PublicKey", name: "PublicKey",
length: PUBLIC_KEY_LENGTH, length: PUBLIC_KEY_LENGTH,
})); }.into());
} }
let mut bits: [u8; 32] = [0u8; 32]; let mut bits: [u8; 32] = [0u8; 32];
bits.copy_from_slice(&bytes[..32]); bits.copy_from_slice(&bytes[..32]);
@ -138,7 +141,7 @@ impl PublicKey {
let compressed = CompressedEdwardsY(bits); let compressed = CompressedEdwardsY(bits);
let point = compressed let point = compressed
.decompress() .decompress()
.ok_or(SignatureError(InternalError::PointDecompressionError))?; .ok_or(InternalError::PointDecompressionError)?;
Ok(PublicKey(compressed, point)) Ok(PublicKey(compressed, point))
} }
@ -159,37 +162,6 @@ impl PublicKey {
PublicKey(compressed, point) 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. /// Verify a `signature` on a `prehashed_message` using the Ed25519ph algorithm.
/// ///
/// # Inputs /// # Inputs
@ -213,11 +185,13 @@ impl PublicKey {
&self, &self,
prehashed_message: D, prehashed_message: D,
context: Option<&[u8]>, context: Option<&[u8]>,
signature: &Signature, signature: &ed25519::Signature,
) -> Result<(), SignatureError> ) -> Result<(), SignatureError>
where where
D: Digest<OutputSize = U64>, D: Digest<OutputSize = U64>,
{ {
let signature = InternalSignature::try_from(signature)?;
let mut h: Sha512 = Sha512::default(); let mut h: Sha512 = Sha512::default();
let R: EdwardsPoint; let R: EdwardsPoint;
let k: Scalar; let k: Scalar;
@ -241,7 +215,7 @@ impl PublicKey {
if R.compress() == signature.R { if R.compress() == signature.R {
Ok(()) Ok(())
} else { } else {
Err(SignatureError(InternalError::VerifyError)) Err(InternalError::VerifyError.into())
} }
} }
@ -311,9 +285,11 @@ impl PublicKey {
pub fn verify_strict( pub fn verify_strict(
&self, &self,
message: &[u8], message: &[u8],
signature: &Signature, signature: &ed25519::Signature,
) -> Result<(), SignatureError> ) -> Result<(), SignatureError>
{ {
let signature = InternalSignature::try_from(signature)?;
let mut h: Sha512 = Sha512::new(); let mut h: Sha512 = Sha512::new();
let R: EdwardsPoint; let R: EdwardsPoint;
let k: Scalar; let k: Scalar;
@ -321,13 +297,13 @@ impl PublicKey {
let signature_R: EdwardsPoint; let signature_R: EdwardsPoint;
match signature.R.decompress() { match signature.R.decompress() {
None => return Err(SignatureError(InternalError::VerifyError)), None => return Err(InternalError::VerifyError.into()),
Some(x) => signature_R = x, Some(x) => signature_R = x,
} }
// Logical OR is fine here as we're not trying to be constant time. // Logical OR is fine here as we're not trying to be constant time.
if signature_R.is_small_order() || self.1.is_small_order() { if signature_R.is_small_order() || self.1.is_small_order() {
return Err(SignatureError(InternalError::VerifyError)); return Err(InternalError::VerifyError.into());
} }
h.input(signature.R.as_bytes()); h.input(signature.R.as_bytes());
@ -340,7 +316,42 @@ impl PublicKey {
if R == signature_R { if R == signature_R {
Ok(()) Ok(())
} else { } else {
Err(SignatureError(InternalError::VerifyError)) Err(InternalError::VerifyError.into())
}
}
}
impl Verifier<ed25519::Signature> for PublicKey {
/// 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)]
fn verify(
&self,
message: &[u8],
signature: &ed25519::Signature
) -> Result<(), SignatureError>
{
let signature = InternalSignature::try_from(signature)?;
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(InternalError::VerifyError.into())
} }
} }
} }

View file

@ -11,8 +11,6 @@
use core::fmt::Debug; use core::fmt::Debug;
use clear_on_drop::clear::Clear;
use curve25519_dalek::constants; use curve25519_dalek::constants;
use curve25519_dalek::digest::generic_array::typenum::U64; use curve25519_dalek::digest::generic_array::typenum::U64;
use curve25519_dalek::digest::Digest; use curve25519_dalek::digest::Digest;
@ -32,13 +30,19 @@ use serde::{Deserialize, Serialize};
#[cfg(feature = "serde")] #[cfg(feature = "serde")]
use serde::{Deserializer, Serializer}; use serde::{Deserializer, Serializer};
use zeroize::Zeroize;
use crate::constants::*; use crate::constants::*;
use crate::errors::*; use crate::errors::*;
use crate::public::*; use crate::public::*;
use crate::signature::*; use crate::signature::*;
/// An EdDSA secret key. /// An EdDSA secret key.
#[derive(Default)] // we derive Default in order to use the clear() method in Drop ///
/// Instances of this secret are automatically overwritten with zeroes when they
/// fall out of scope.
#[derive(Zeroize)]
#[zeroize(drop)] // Overwrite secret key material with null bytes when it goes out of scope.
pub struct SecretKey(pub(crate) [u8; SECRET_KEY_LENGTH]); pub struct SecretKey(pub(crate) [u8; SECRET_KEY_LENGTH]);
impl Debug for SecretKey { impl Debug for SecretKey {
@ -47,13 +51,6 @@ impl Debug for SecretKey {
} }
} }
/// 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 { impl AsRef<[u8]> for SecretKey {
fn as_ref(&self) -> &[u8] { fn as_ref(&self) -> &[u8] {
self.as_bytes() self.as_bytes()
@ -109,10 +106,10 @@ impl SecretKey {
#[inline] #[inline]
pub fn from_bytes(bytes: &[u8]) -> Result<SecretKey, SignatureError> { pub fn from_bytes(bytes: &[u8]) -> Result<SecretKey, SignatureError> {
if bytes.len() != SECRET_KEY_LENGTH { if bytes.len() != SECRET_KEY_LENGTH {
return Err(SignatureError(InternalError::BytesLengthError { return Err(InternalError::BytesLengthError {
name: "SecretKey", name: "SecretKey",
length: SECRET_KEY_LENGTH, length: SECRET_KEY_LENGTH,
})); }.into());
} }
let mut bits: [u8; 32] = [0u8; 32]; let mut bits: [u8; 32] = [0u8; 32];
bits.copy_from_slice(&bytes[..32]); bits.copy_from_slice(&bytes[..32]);
@ -223,6 +220,9 @@ impl<'d> Deserialize<'d> for SecretKey {
/// upper half is used a sort of half-baked, ill-designed² pseudo-domain-separation /// upper half is used a sort of half-baked, ill-designed² pseudo-domain-separation
/// "nonce"-like thing, which is used during signature production by /// "nonce"-like thing, which is used during signature production by
/// concatenating it with the message to be signed before the message is hashed. /// concatenating it with the message to be signed before the message is hashed.
///
/// Instances of this secret are automatically overwritten with zeroes when they
/// fall out of scope.
// //
// ¹ This results in a slight bias towards non-uniformity at one spectrum of // ¹ 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. // the range of valid keys. Oh well: not my idea; not my problem.
@ -250,20 +250,13 @@ impl<'d> Deserialize<'d> for SecretKey {
// same signature scheme, and which both fail in exactly the same way. For a // 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 // better-designed, Schnorr-based signature scheme, see Trevor Perrin's work on
// "generalised EdDSA" and "VXEdDSA". // "generalised EdDSA" and "VXEdDSA".
#[derive(Default)] // we derive Default in order to use the clear() method in Drop #[derive(Zeroize)]
#[zeroize(drop)] // Overwrite secret key material with null bytes when it goes out of scope.
pub struct ExpandedSecretKey { pub struct ExpandedSecretKey {
pub(crate) key: Scalar, pub(crate) key: Scalar,
pub(crate) nonce: [u8; 32], 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 { impl<'a> From<&'a SecretKey> for ExpandedSecretKey {
/// Construct an `ExpandedSecretKey` from a `SecretKey`. /// Construct an `ExpandedSecretKey` from a `SecretKey`.
/// ///
@ -390,10 +383,10 @@ impl ExpandedSecretKey {
#[inline] #[inline]
pub fn from_bytes(bytes: &[u8]) -> Result<ExpandedSecretKey, SignatureError> { pub fn from_bytes(bytes: &[u8]) -> Result<ExpandedSecretKey, SignatureError> {
if bytes.len() != EXPANDED_SECRET_KEY_LENGTH { if bytes.len() != EXPANDED_SECRET_KEY_LENGTH {
return Err(SignatureError(InternalError::BytesLengthError { return Err(InternalError::BytesLengthError {
name: "ExpandedSecretKey", name: "ExpandedSecretKey",
length: EXPANDED_SECRET_KEY_LENGTH, length: EXPANDED_SECRET_KEY_LENGTH,
})); }.into());
} }
let mut lower: [u8; 32] = [0u8; 32]; let mut lower: [u8; 32] = [0u8; 32];
let mut upper: [u8; 32] = [0u8; 32]; let mut upper: [u8; 32] = [0u8; 32];
@ -409,7 +402,7 @@ impl ExpandedSecretKey {
/// Sign a message with this `ExpandedSecretKey`. /// Sign a message with this `ExpandedSecretKey`.
#[allow(non_snake_case)] #[allow(non_snake_case)]
pub fn sign(&self, message: &[u8], public_key: &PublicKey) -> Signature { pub fn sign(&self, message: &[u8], public_key: &PublicKey) -> ed25519::Signature {
let mut h: Sha512 = Sha512::new(); let mut h: Sha512 = Sha512::new();
let R: CompressedEdwardsY; let R: CompressedEdwardsY;
let r: Scalar; let r: Scalar;
@ -430,7 +423,7 @@ impl ExpandedSecretKey {
k = Scalar::from_hash(h); k = Scalar::from_hash(h);
s = &(&k * &self.key) + &r; s = &(&k * &self.key) + &r;
Signature { R, s } InternalSignature { R, s }.into()
} }
/// Sign a `prehashed_message` with this `ExpandedSecretKey` using the /// Sign a `prehashed_message` with this `ExpandedSecretKey` using the
@ -448,7 +441,9 @@ impl ExpandedSecretKey {
/// ///
/// # Returns /// # Returns
/// ///
/// An Ed25519ph [`Signature`] on the `prehashed_message`. /// A `Result` whose `Ok` value is an Ed25519ph [`Signature`] on the
/// `prehashed_message` if the context was 255 bytes or less, otherwise
/// a `SignatureError`.
/// ///
/// [rfc8032]: https://tools.ietf.org/html/rfc8032#section-5.1 /// [rfc8032]: https://tools.ietf.org/html/rfc8032#section-5.1
#[allow(non_snake_case)] #[allow(non_snake_case)]
@ -457,7 +452,7 @@ impl ExpandedSecretKey {
prehashed_message: D, prehashed_message: D,
public_key: &PublicKey, public_key: &PublicKey,
context: Option<&'a [u8]>, context: Option<&'a [u8]>,
) -> Signature ) -> Result<ed25519::Signature, SignatureError>
where where
D: Digest<OutputSize = U64>, D: Digest<OutputSize = U64>,
{ {
@ -470,7 +465,9 @@ impl ExpandedSecretKey {
let ctx: &[u8] = context.unwrap_or(b""); // By default, the context is an empty string. 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."); if ctx.len() > 255 {
return Err(SignatureError::from(InternalError::PrehashedContextLengthError));
}
let ctx_len: u8 = ctx.len() as u8; let ctx_len: u8 = ctx.len() as u8;
@ -512,7 +509,7 @@ impl ExpandedSecretKey {
k = Scalar::from_hash(h); k = Scalar::from_hash(h);
s = &(&k * &self.key) + &r; s = &(&k * &self.key) + &r;
Signature { R, s } Ok(InternalSignature { R, s }.into())
} }
} }
@ -554,3 +551,23 @@ impl<'d> Deserialize<'d> for ExpandedSecretKey {
deserializer.deserialize_bytes(ExpandedSecretKeyVisitor) deserializer.deserialize_bytes(ExpandedSecretKeyVisitor)
} }
} }
#[cfg(test)]
mod test {
use super::*;
#[test]
fn secret_key_zeroize_on_drop() {
let secret_ptr: *const u8;
{ // scope for the secret to ensure it's been dropped
let secret = SecretKey::from_bytes(&[0x15u8; 32][..]).unwrap();
secret_ptr = secret.0.as_ptr();
}
let memory: &[u8] = unsafe { ::std::slice::from_raw_parts(secret_ptr, 32) };
assert!(!memory.contains(&0x15));
}
}

View file

@ -9,19 +9,12 @@
//! An ed25519 signature. //! An ed25519 signature.
use core::convert::TryFrom;
use core::fmt::Debug; use core::fmt::Debug;
use curve25519_dalek::edwards::CompressedEdwardsY; use curve25519_dalek::edwards::CompressedEdwardsY;
use curve25519_dalek::scalar::Scalar; use curve25519_dalek::scalar::Scalar;
use ed25519::signature::Signature as _;
#[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::constants::*;
use crate::errors::*; use crate::errors::*;
@ -35,7 +28,7 @@ use crate::errors::*;
/// been signed. /// been signed.
#[allow(non_snake_case)] #[allow(non_snake_case)]
#[derive(Copy, Eq, PartialEq)] #[derive(Copy, Eq, PartialEq)]
pub struct Signature { pub(crate) struct InternalSignature {
/// `R` is an `EdwardsPoint`, formed by using an hash function with /// `R` is an `EdwardsPoint`, formed by using an hash function with
/// 512-bits output to produce the digest of: /// 512-bits output to produce the digest of:
/// ///
@ -59,13 +52,13 @@ pub struct Signature {
pub(crate) s: Scalar, pub(crate) s: Scalar,
} }
impl Clone for Signature { impl Clone for InternalSignature {
fn clone(&self) -> Self { fn clone(&self) -> Self {
*self *self
} }
} }
impl Debug for Signature { impl Debug for InternalSignature {
fn fmt(&self, f: &mut ::core::fmt::Formatter<'_>) -> ::core::fmt::Result { fn fmt(&self, f: &mut ::core::fmt::Formatter<'_>) -> ::core::fmt::Result {
write!(f, "Signature( R: {:?}, s: {:?} )", &self.R, &self.s) write!(f, "Signature( R: {:?}, s: {:?} )", &self.R, &self.s)
} }
@ -103,12 +96,12 @@ fn check_scalar(bytes: [u8; 32]) -> Result<Scalar, SignatureError> {
} }
match Scalar::from_canonical_bytes(bytes) { match Scalar::from_canonical_bytes(bytes) {
None => return Err(SignatureError(InternalError::ScalarFormatError)), None => return Err(InternalError::ScalarFormatError.into()),
Some(x) => return Ok(x), Some(x) => return Ok(x),
}; };
} }
impl Signature { impl InternalSignature {
/// Convert this `Signature` to a byte array. /// Convert this `Signature` to a byte array.
#[inline] #[inline]
pub fn to_bytes(&self) -> [u8; SIGNATURE_LENGTH] { pub fn to_bytes(&self) -> [u8; SIGNATURE_LENGTH] {
@ -170,12 +163,12 @@ impl Signature {
/// only checking the most significant three bits. (See also the /// only checking the most significant three bits. (See also the
/// documentation for `PublicKey.verify_strict`.) /// documentation for `PublicKey.verify_strict`.)
#[inline] #[inline]
pub fn from_bytes(bytes: &[u8]) -> Result<Signature, SignatureError> { pub fn from_bytes(bytes: &[u8]) -> Result<InternalSignature, SignatureError> {
if bytes.len() != SIGNATURE_LENGTH { if bytes.len() != SIGNATURE_LENGTH {
return Err(SignatureError(InternalError::BytesLengthError { return Err(InternalError::BytesLengthError {
name: "Signature", name: "Signature",
length: SIGNATURE_LENGTH, length: SIGNATURE_LENGTH,
})); }.into());
} }
let mut lower: [u8; 32] = [0u8; 32]; let mut lower: [u8; 32] = [0u8; 32];
let mut upper: [u8; 32] = [0u8; 32]; let mut upper: [u8; 32] = [0u8; 32];
@ -190,45 +183,23 @@ impl Signature {
Err(x) => return Err(x), Err(x) => return Err(x),
} }
Ok(Signature { Ok(InternalSignature {
R: CompressedEdwardsY(lower), R: CompressedEdwardsY(lower),
s: s, s: s,
}) })
} }
} }
#[cfg(feature = "serde")] impl TryFrom<&ed25519::Signature> for InternalSignature {
impl Serialize for Signature { type Error = SignatureError;
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where fn try_from(sig: &ed25519::Signature) -> Result<InternalSignature, SignatureError> {
S: Serializer, InternalSignature::from_bytes(sig.as_bytes())
{
serializer.serialize_bytes(&self.to_bytes()[..])
} }
} }
#[cfg(feature = "serde")] impl From<InternalSignature> for ed25519::Signature {
impl<'d> Deserialize<'d> for Signature { fn from(sig: InternalSignature) -> ed25519::Signature {
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error> ed25519::Signature::from_bytes(&sig.to_bytes()).unwrap()
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)
} }
} }

View file

@ -15,6 +15,10 @@ extern crate ed25519_dalek;
extern crate hex; extern crate hex;
extern crate sha2; extern crate sha2;
extern crate rand; extern crate rand;
#[cfg(all(test, feature = "serde"))]
extern crate serde_crate;
#[cfg(all(test, feature = "serde"))]
extern crate toml;
use ed25519_dalek::*; use ed25519_dalek::*;
@ -24,6 +28,8 @@ use sha2::Sha512;
#[cfg(test)] #[cfg(test)]
mod vectors { mod vectors {
use ed25519::signature::Signature as _;
use std::io::BufReader; use std::io::BufReader;
use std::io::BufRead; use std::io::BufRead;
use std::fs::File; use std::fs::File;
@ -98,7 +104,7 @@ mod vectors {
prehash_for_signing.input(&msg_bytes[..]); prehash_for_signing.input(&msg_bytes[..]);
prehash_for_verifying.input(&msg_bytes[..]); prehash_for_verifying.input(&msg_bytes[..]);
let sig2: Signature = keypair.sign_prehashed(prehash_for_signing, None); let sig2: Signature = keypair.sign_prehashed(prehash_for_signing, None).unwrap();
assert!(sig1 == sig2, assert!(sig1 == sig2,
"Original signature from test vectors doesn't equal signature produced:\ "Original signature from test vectors doesn't equal signature produced:\
@ -163,8 +169,8 @@ mod integrations {
let context: &[u8] = b"testing testing 1 2 3"; let context: &[u8] = b"testing testing 1 2 3";
keypair = Keypair::generate(&mut csprng); keypair = Keypair::generate(&mut csprng);
good_sig = keypair.sign_prehashed(prehashed_good1, Some(context)); good_sig = keypair.sign_prehashed(prehashed_good1, Some(context)).unwrap();
bad_sig = keypair.sign_prehashed(prehashed_bad1, Some(context)); bad_sig = keypair.sign_prehashed(prehashed_bad1, Some(context)).unwrap();
assert!(keypair.verify_prehashed(prehashed_good2, Some(context), &good_sig).is_ok(), assert!(keypair.verify_prehashed(prehashed_good2, Some(context), &good_sig).is_ok(),
"Verification of a valid signature failed!"); "Verification of a valid signature failed!");
@ -213,11 +219,21 @@ mod integrations {
} }
} }
#[serde(crate = "serde_crate")]
#[cfg(all(test, feature = "serde"))]
#[derive(Debug, serde_crate::Serialize, serde_crate::Deserialize)]
struct Demo {
keypair: Keypair
}
#[cfg(all(test, feature = "serde"))] #[cfg(all(test, feature = "serde"))]
mod serialisation { mod serialisation {
use super::*; use super::*;
use self::bincode::{serialize, serialized_size, deserialize, Infinite}; use self::bincode::{serialize, serialized_size, deserialize, Infinite};
use self::toml;
use ed25519::signature::Signature as _;
static PUBLIC_KEY_BYTES: [u8; PUBLIC_KEY_LENGTH] = [ static PUBLIC_KEY_BYTES: [u8; PUBLIC_KEY_LENGTH] = [
130, 039, 155, 015, 062, 076, 188, 063, 130, 039, 155, 015, 062, 076, 188, 063,
@ -242,6 +258,16 @@ mod serialisation {
216, 085, 134, 144, 129, 149, 041, 081, 216, 085, 134, 144, 129, 149, 041, 081,
063, 120, 126, 100, 092, 059, 050, 011, ]; 063, 120, 126, 100, 092, 059, 050, 011, ];
static KEYPAIR_BYTES: [u8; KEYPAIR_LENGTH] = [
239, 085, 017, 235, 167, 103, 034, 062,
007, 010, 032, 146, 113, 039, 096, 174,
003, 219, 232, 166, 240, 121, 167, 013,
098, 238, 122, 116, 193, 114, 215, 213,
175, 181, 075, 166, 224, 164, 140, 146,
053, 120, 010, 037, 104, 094, 136, 225,
249, 102, 171, 160, 097, 132, 015, 071,
035, 056, 000, 074, 130, 168, 225, 071, ];
#[test] #[test]
fn serialize_deserialize_signature() { fn serialize_deserialize_signature() {
let signature: Signature = Signature::from_bytes(&SIGNATURE_BYTES).unwrap(); let signature: Signature = Signature::from_bytes(&SIGNATURE_BYTES).unwrap();
@ -272,6 +298,28 @@ mod serialisation {
} }
} }
#[test]
fn serialize_deserialize_keypair_bincode() {
let keypair = Keypair::from_bytes(&KEYPAIR_BYTES).unwrap();
let encoded_keypair: Vec<u8> = serialize(&keypair, Infinite).unwrap();
let decoded_keypair: Keypair = deserialize(&encoded_keypair).unwrap();
for i in 0..64 {
assert_eq!(KEYPAIR_BYTES[i], decoded_keypair.to_bytes()[i]);
}
}
#[test]
fn serialize_deserialize_keypair_toml() {
let demo = Demo { keypair: Keypair::from_bytes(&KEYPAIR_BYTES).unwrap() };
println!("\n\nWrite to toml");
let demo_toml = toml::to_string(&demo).unwrap();
println!("{}", demo_toml);
let demo_toml_rebuild: Result<Demo, _> = toml::from_str(&demo_toml);
println!("{:?}", demo_toml_rebuild);
}
#[test] #[test]
fn serialize_public_key_size() { fn serialize_public_key_size() {
let public_key: PublicKey = PublicKey::from_bytes(&PUBLIC_KEY_BYTES).unwrap(); let public_key: PublicKey = PublicKey::from_bytes(&PUBLIC_KEY_BYTES).unwrap();
@ -281,7 +329,7 @@ mod serialisation {
#[test] #[test]
fn serialize_signature_size() { fn serialize_signature_size() {
let signature: Signature = Signature::from_bytes(&SIGNATURE_BYTES).unwrap(); 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 assert_eq!(serialized_size(&signature) as usize, 64); // These sizes are specific to bincode==1.0.1
} }
#[test] #[test]