From ff514271741cdb0743f547de1cf115e85c948048 Mon Sep 17 00:00:00 2001 From: Tony Arcieri Date: Tue, 17 Mar 2020 10:25:33 -0700 Subject: [PATCH] Use `ed25519` + `signature` interop crates The `signature` crate provides `Signer` and `Verifier` traits generic over signature types: https://github.com/RustCrypto/traits/tree/master/signature There's presently an open call to stabilize the parts of its API needed by Ed25519 signatures and release a 1.0 version: https://github.com/RustCrypto/traits/issues/78 The `ed25519` crate, based on the `signature` crate, provides an `ed25519::Signature` type which can be shared across multiple Ed25519 crates (e.g. it is also used by the `yubihsm` crate): https://github.com/RustCrypto/signatures/tree/master/ed25519 This commit integrates the `ed25519::Signature` type, and changes the existing `sign` and `verify` methods (where applicable) to use the `Signer` and `Verifier` traits from the `signature` crate. Additionally, it replaces `SignatureError` with the `signature` crate's error type. This has the drawback of requiring the `Signer` and/or `Verifier` traits are in scope in order to create and/or verify signatures, but with the benefit of supporting interoperability with other Ed25519 crates which also make use of these traits. --- Cargo.toml | 6 ++- src/batch.rs | 20 +++++--- src/errors.rs | 18 +++---- src/{ed25519.rs => keypair.rs} | 51 ++++++++++--------- src/lib.rs | 47 +++++++++++------- src/public.rs | 91 +++++++++++++++++++--------------- src/secret.rs | 16 +++--- src/signature.rs | 67 +++++++------------------ tests/ed25519.rs | 6 ++- 9 files changed, 167 insertions(+), 155 deletions(-) rename src/{ed25519.rs => keypair.rs} (94%) diff --git a/Cargo.toml b/Cargo.toml index 2931ff5b..1258d32a 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -23,10 +23,11 @@ features = ["nightly", "batch"] [dependencies] curve25519-dalek = { version = "2", default-features = false } +ed25519 = { version = "= 1.0.0-pre.4", default-features = false } merlin = { version = "1", default-features = false, optional = true, git = "https://github.com/isislovecruft/merlin", branch = "develop" } rand = { version = "0.7", default-features = false, optional = true } rand_core = { version = "0.5", default-features = false, optional = true } -serde = { version = "1.0", default-features = false, optional = true } +serde_crate = { package = "serde", version = "1.0", default-features = false, optional = true } sha2 = { version = "0.8", default-features = false } zeroize = { version = "1", default-features = false, features = ["zeroize_derive"] } @@ -45,9 +46,10 @@ harness = false [features] default = ["std", "u64_backend"] -std = ["curve25519-dalek/std", "serde/std", "sha2/std", "rand/std"] +std = ["curve25519-dalek/std", "ed25519/std", "serde_crate/std", "sha2/std", "rand/std"] alloc = ["curve25519-dalek/alloc", "rand/alloc", "zeroize/alloc"] nightly = ["curve25519-dalek/nightly", "rand/nightly"] +serde = ["serde_crate", "ed25519/serde"] batch = ["merlin", "rand"] # This feature enables deterministic batch verification. batch_deterministic = ["merlin", "rand", "rand_core"] diff --git a/src/batch.rs b/src/batch.rs index 90d28ef5..d7816eb1 100644 --- a/src/batch.rs +++ b/src/batch.rs @@ -14,6 +14,7 @@ use alloc::vec::Vec; #[cfg(feature = "std")] use std::vec::Vec; +use core::convert::TryFrom; use core::iter::once; use curve25519_dalek::constants; @@ -37,7 +38,7 @@ use sha2::Sha512; use crate::errors::InternalError; use crate::errors::SignatureError; use crate::public::PublicKey; -use crate::signature::Signature; +use crate::signature::InternalSignature; trait BatchTranscript { fn append_hrams(&mut self, hrams: &Vec); @@ -127,6 +128,7 @@ fn zero_rng() -> ZeroRng { /// use ed25519_dalek::verify_batch; /// use ed25519_dalek::Keypair; /// use ed25519_dalek::PublicKey; +/// use ed25519_dalek::Signer; /// use ed25519_dalek::Signature; /// use rand::rngs::OsRng; /// @@ -147,7 +149,7 @@ fn zero_rng() -> ZeroRng { #[allow(non_snake_case)] pub fn verify_batch( messages: &[&[u8]], - signatures: &[Signature], + signatures: &[ed25519::Signature], public_keys: &[PublicKey], ) -> Result<(), SignatureError> { @@ -155,13 +157,19 @@ pub fn verify_batch( if signatures.len() != messages.len() || signatures.len() != public_keys.len() || public_keys.len() != messages.len() { - return Err(SignatureError(InternalError::ArrayLengthError{ + return Err(InternalError::ArrayLengthError{ name_a: "signatures", length_a: signatures.len(), name_b: "messages", length_b: messages.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::, _>>()?; + // Compute H(R || A || M) for each (signature, public_key, message) triplet let hrams: Vec = (0..signatures.len()).map(|i| { let mut h: Sha512 = Sha512::default(); @@ -213,11 +221,11 @@ pub fn verify_batch( let id = EdwardsPoint::optional_multiscalar_mul( once(-B_coefficient).chain(zs.iter().cloned()).chain(zhrams), B.chain(Rs).chain(As), - ).ok_or_else(|| SignatureError(InternalError::VerifyError))?; + ).ok_or(InternalError::VerifyError)?; if id.is_identity() { Ok(()) } else { - Err(SignatureError(InternalError::VerifyError)) + Err(InternalError::VerifyError.into()) } } diff --git a/src/errors.rs b/src/errors.rs index 1d147591..108ca1fd 100644 --- a/src/errors.rs +++ b/src/errors.rs @@ -80,18 +80,16 @@ impl Error for InternalError { } /// only be constructed from 255-bit integers.) /// /// * Failure of a signature to satisfy the verification equation. -#[derive(Clone, Copy, Eq, PartialEq, Hash, Debug)] -pub struct SignatureError(pub(crate) InternalError); +pub type SignatureError = ed25519::signature::Error; -impl Display for SignatureError { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - write!(f, "{}", self.0) +impl From for SignatureError { + #[cfg(not(feature = "std"))] + fn from(_err: InternalError) -> SignatureError { + SignatureError::new() } -} -#[cfg(feature = "std")] -impl Error for SignatureError { - fn source(&self) -> Option<&(dyn Error + 'static)> { - Some(&self.0) + #[cfg(feature = "std")] + fn from(err: InternalError) -> SignatureError { + SignatureError::from_source(err) } } diff --git a/src/ed25519.rs b/src/keypair.rs similarity index 94% rename from src/ed25519.rs rename to src/keypair.rs index 076d30c2..4fd63df1 100644 --- a/src/ed25519.rs +++ b/src/keypair.rs @@ -9,8 +9,6 @@ //! ed25519 keypairs. -use core::default::Default; - #[cfg(feature = "rand")] use rand::{CryptoRng, RngCore}; @@ -26,13 +24,12 @@ pub use sha2::Sha512; use curve25519_dalek::digest::generic_array::typenum::U64; pub use curve25519_dalek::digest::Digest; -#[cfg(all(feature = "batch", any(feature = "std", feature = "alloc")))] -pub use crate::batch::*; -pub use crate::constants::*; -pub use crate::errors::*; -pub use crate::public::*; -pub use crate::secret::*; -pub use crate::signature::*; +use ed25519::signature::{Signer, Verifier}; + +use crate::constants::*; +use crate::errors::*; +use crate::public::*; +use crate::secret::*; /// An ed25519 keypair. #[derive(Debug)] @@ -82,10 +79,10 @@ impl Keypair { /// is an `SignatureError` describing the error that occurred. pub fn from_bytes<'a>(bytes: &'a [u8]) -> Result { if bytes.len() != KEYPAIR_LENGTH { - return Err(SignatureError(InternalError::BytesLengthError { + return Err(InternalError::BytesLengthError { name: "Keypair", length: KEYPAIR_LENGTH, - })); + }.into()); } let secret = SecretKey::from_bytes(&bytes[..SECRET_KEY_LENGTH])?; let public = PublicKey::from_bytes(&bytes[SECRET_KEY_LENGTH..])?; @@ -136,13 +133,6 @@ impl Keypair { 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 /// Ed25519ph algorithm defined in [RFC8032 ยง5.1][rfc8032]. /// @@ -241,20 +231,20 @@ impl Keypair { &self, prehashed_message: D, context: Option<&[u8]>, - ) -> Signature + ) -> ed25519::Signature where D: Digest, { 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. pub fn verify( &self, message: &[u8], - signature: &Signature + signature: &ed25519::Signature ) -> Result<(), SignatureError> { self.public.verify(message, signature) @@ -320,7 +310,7 @@ impl Keypair { &self, prehashed_message: D, context: Option<&[u8]>, - signature: &Signature, + signature: &ed25519::Signature, ) -> Result<(), SignatureError> where D: Digest, @@ -394,13 +384,28 @@ impl Keypair { pub fn verify_strict( &self, message: &[u8], - signature: &Signature, + signature: &ed25519::Signature, ) -> Result<(), SignatureError> { self.public.verify_strict(message, signature) } } +impl Signer for Keypair { + /// Sign a message with this keypair's secret key. + fn try_sign(&self, message: &[u8]) -> Result { + let expanded: ExpandedSecretKey = (&self.secret).into(); + Ok(expanded.sign(&message, &self.public).into()) + } +} + +impl Verifier 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")] impl Serialize for Keypair { fn serialize(&self, serializer: S) -> Result diff --git a/src/lib.rs b/src/lib.rs index bee0f7c4..22cd7e9e 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -44,9 +44,9 @@ //! # fn main() { //! # use rand::rngs::OsRng; //! # use ed25519_dalek::Keypair; -//! # use ed25519_dalek::Signature; //! # let mut csprng = OsRng{}; //! # 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 signature: Signature = keypair.sign(message); //! # } @@ -60,12 +60,12 @@ //! # extern crate ed25519_dalek; //! # fn main() { //! # use rand::rngs::OsRng; -//! # use ed25519_dalek::Keypair; -//! # use ed25519_dalek::Signature; +//! # use ed25519_dalek::{Keypair, Signature, Signer}; //! # let mut csprng = OsRng{}; //! # let keypair: Keypair = Keypair::generate(&mut csprng); //! # let message: &[u8] = b"This is a test of the tsunami alert system."; //! # let signature: Signature = keypair.sign(message); +//! use ed25519_dalek::Verifier; //! assert!(keypair.verify(message, &signature).is_ok()); //! # } //! ``` @@ -80,7 +80,8 @@ //! # use rand::rngs::OsRng; //! # use ed25519_dalek::Keypair; //! # use ed25519_dalek::Signature; -//! use ed25519_dalek::PublicKey; +//! # use ed25519_dalek::Signer; +//! use ed25519_dalek::{PublicKey, Verifier}; //! # let mut csprng = OsRng{}; //! # let keypair: Keypair = Keypair::generate(&mut csprng); //! # let message: &[u8] = b"This is a test of the tsunami alert system."; @@ -104,7 +105,7 @@ //! # extern crate ed25519_dalek; //! # fn main() { //! # 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}; //! # let mut csprng = OsRng{}; //! # let keypair: Keypair = Keypair::generate(&mut csprng); @@ -124,8 +125,9 @@ //! ``` //! # extern crate rand; //! # extern crate ed25519_dalek; +//! # use std::convert::TryFrom; //! # 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}; //! # fn do_test() -> Result<(SecretKey, PublicKey, Keypair, Signature), SignatureError> { //! # let mut csprng = OsRng{}; @@ -140,7 +142,7 @@ //! let public_key: PublicKey = PublicKey::from_bytes(&public_key_bytes)?; //! let secret_key: SecretKey = SecretKey::from_bytes(&secret_key_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)) //! # } @@ -166,14 +168,14 @@ //! # extern crate rand; //! # extern crate ed25519_dalek; //! # #[cfg(feature = "serde")] -//! extern crate serde; +//! # extern crate serde_crate as serde; //! # #[cfg(feature = "serde")] -//! extern crate bincode; +//! # extern crate bincode; //! //! # #[cfg(feature = "serde")] //! # fn main() { //! # use rand::rngs::OsRng; -//! # use ed25519_dalek::{Keypair, Signature, PublicKey}; +//! # use ed25519_dalek::{Keypair, Signature, Signer, Verifier, PublicKey}; //! use bincode::{serialize, Infinite}; //! # let mut csprng = OsRng{}; //! # let keypair: Keypair = Keypair::generate(&mut csprng); @@ -196,16 +198,16 @@ //! # extern crate rand; //! # extern crate ed25519_dalek; //! # #[cfg(feature = "serde")] -//! # extern crate serde; +//! # extern crate serde_crate as serde; //! # #[cfg(feature = "serde")] //! # extern crate bincode; //! # //! # #[cfg(feature = "serde")] //! # fn main() { //! # use rand::rngs::OsRng; -//! # use ed25519_dalek::{Keypair, Signature, PublicKey}; +//! # use ed25519_dalek::{Keypair, Signature, Signer, Verifier, PublicKey}; //! # use bincode::{serialize, Infinite}; -//! use bincode::{deserialize}; +//! use bincode::deserialize; //! //! # let mut csprng = OsRng{}; //! # let keypair: Keypair = Keypair::generate(&mut csprng); @@ -237,6 +239,8 @@ #[macro_use] extern crate std; +pub extern crate ed25519; + #[cfg(all(feature = "alloc", not(feature = "std")))] extern crate alloc; extern crate curve25519_dalek; @@ -245,20 +249,29 @@ extern crate merlin; #[cfg(any(feature = "batch", feature = "std", feature = "alloc", test))] extern crate rand; #[cfg(feature = "serde")] -extern crate serde; +extern crate serde_crate as serde; extern crate sha2; extern crate zeroize; #[cfg(all(any(feature = "batch", feature = "batch_deterministic"), any(feature = "std", feature = "alloc")))] mod batch; mod constants; -mod ed25519; +mod keypair; mod errors; mod public; mod secret; mod signature; -// Export everything public in ed25519. -pub use crate::ed25519::*; +pub use curve25519_dalek::digest::Digest; + #[cfg(all(any(feature = "batch", feature = "batch_deterministic"), any(feature = "std", feature = "alloc")))] 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; diff --git a/src/public.rs b/src/public.rs index f901fcfb..0fb41880 100644 --- a/src/public.rs +++ b/src/public.rs @@ -9,6 +9,7 @@ //! ed25519 public keys. +use core::convert::TryFrom; use core::fmt::Debug; use curve25519_dalek::constants; @@ -18,6 +19,8 @@ use curve25519_dalek::edwards::CompressedEdwardsY; use curve25519_dalek::edwards::EdwardsPoint; use curve25519_dalek::scalar::Scalar; +use ed25519::signature::Verifier; + pub use sha2::Sha512; #[cfg(feature = "serde")] @@ -127,10 +130,10 @@ impl PublicKey { #[inline] pub fn from_bytes(bytes: &[u8]) -> Result { if bytes.len() != PUBLIC_KEY_LENGTH { - return Err(SignatureError(InternalError::BytesLengthError { + return Err(InternalError::BytesLengthError { name: "PublicKey", length: PUBLIC_KEY_LENGTH, - })); + }.into()); } let mut bits: [u8; 32] = [0u8; 32]; bits.copy_from_slice(&bytes[..32]); @@ -138,7 +141,7 @@ impl PublicKey { let compressed = CompressedEdwardsY(bits); let point = compressed .decompress() - .ok_or(SignatureError(InternalError::PointDecompressionError))?; + .ok_or(InternalError::PointDecompressionError)?; Ok(PublicKey(compressed, point)) } @@ -159,37 +162,6 @@ impl PublicKey { 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 @@ -213,11 +185,13 @@ impl PublicKey { &self, prehashed_message: D, context: Option<&[u8]>, - signature: &Signature, + signature: &ed25519::Signature, ) -> Result<(), SignatureError> where D: Digest, { + let signature = InternalSignature::try_from(signature)?; + let mut h: Sha512 = Sha512::default(); let R: EdwardsPoint; let k: Scalar; @@ -241,7 +215,7 @@ impl PublicKey { if R.compress() == signature.R { Ok(()) } else { - Err(SignatureError(InternalError::VerifyError)) + Err(InternalError::VerifyError.into()) } } @@ -311,9 +285,11 @@ impl PublicKey { pub fn verify_strict( &self, message: &[u8], - signature: &Signature, + signature: &ed25519::Signature, ) -> Result<(), SignatureError> { + let signature = InternalSignature::try_from(signature)?; + let mut h: Sha512 = Sha512::new(); let R: EdwardsPoint; let k: Scalar; @@ -321,13 +297,13 @@ impl PublicKey { let signature_R: EdwardsPoint; match signature.R.decompress() { - None => return Err(SignatureError(InternalError::VerifyError)), + None => return Err(InternalError::VerifyError.into()), Some(x) => signature_R = x, } // 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() { - return Err(SignatureError(InternalError::VerifyError)); + return Err(InternalError::VerifyError.into()); } h.input(signature.R.as_bytes()); @@ -340,7 +316,42 @@ impl PublicKey { if R == signature_R { Ok(()) } else { - Err(SignatureError(InternalError::VerifyError)) + Err(InternalError::VerifyError.into()) + } + } +} + +impl Verifier 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()) } } } diff --git a/src/secret.rs b/src/secret.rs index f1e751d4..50665690 100644 --- a/src/secret.rs +++ b/src/secret.rs @@ -106,10 +106,10 @@ impl SecretKey { #[inline] pub fn from_bytes(bytes: &[u8]) -> Result { if bytes.len() != SECRET_KEY_LENGTH { - return Err(SignatureError(InternalError::BytesLengthError { + return Err(InternalError::BytesLengthError { name: "SecretKey", length: SECRET_KEY_LENGTH, - })); + }.into()); } let mut bits: [u8; 32] = [0u8; 32]; bits.copy_from_slice(&bytes[..32]); @@ -383,10 +383,10 @@ impl ExpandedSecretKey { #[inline] pub fn from_bytes(bytes: &[u8]) -> Result { if bytes.len() != EXPANDED_SECRET_KEY_LENGTH { - return Err(SignatureError(InternalError::BytesLengthError { + return Err(InternalError::BytesLengthError { name: "ExpandedSecretKey", length: EXPANDED_SECRET_KEY_LENGTH, - })); + }.into()); } let mut lower: [u8; 32] = [0u8; 32]; let mut upper: [u8; 32] = [0u8; 32]; @@ -402,7 +402,7 @@ impl ExpandedSecretKey { /// Sign a message with this `ExpandedSecretKey`. #[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 R: CompressedEdwardsY; let r: Scalar; @@ -423,7 +423,7 @@ impl ExpandedSecretKey { k = Scalar::from_hash(h); s = &(&k * &self.key) + &r; - Signature { R, s } + InternalSignature { R, s }.into() } /// Sign a `prehashed_message` with this `ExpandedSecretKey` using the @@ -450,7 +450,7 @@ impl ExpandedSecretKey { prehashed_message: D, public_key: &PublicKey, context: Option<&'a [u8]>, - ) -> Signature + ) -> ed25519::Signature where D: Digest, { @@ -505,7 +505,7 @@ impl ExpandedSecretKey { k = Scalar::from_hash(h); s = &(&k * &self.key) + &r; - Signature { R, s } + InternalSignature { R, s }.into() } } diff --git a/src/signature.rs b/src/signature.rs index 59da2255..c01e7541 100644 --- a/src/signature.rs +++ b/src/signature.rs @@ -9,19 +9,12 @@ //! An ed25519 signature. +use core::convert::TryFrom; 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 ed25519::signature::Signature as _; use crate::constants::*; use crate::errors::*; @@ -35,7 +28,7 @@ use crate::errors::*; /// been signed. #[allow(non_snake_case)] #[derive(Copy, Eq, PartialEq)] -pub struct Signature { +pub(crate) struct InternalSignature { /// `R` is an `EdwardsPoint`, formed by using an hash function with /// 512-bits output to produce the digest of: /// @@ -59,13 +52,13 @@ pub struct Signature { pub(crate) s: Scalar, } -impl Clone for Signature { +impl Clone for InternalSignature { fn clone(&self) -> Self { *self } } -impl Debug for Signature { +impl Debug for InternalSignature { fn fmt(&self, f: &mut ::core::fmt::Formatter<'_>) -> ::core::fmt::Result { write!(f, "Signature( R: {:?}, s: {:?} )", &self.R, &self.s) } @@ -103,12 +96,12 @@ fn check_scalar(bytes: [u8; 32]) -> Result { } match Scalar::from_canonical_bytes(bytes) { - None => return Err(SignatureError(InternalError::ScalarFormatError)), + None => return Err(InternalError::ScalarFormatError.into()), Some(x) => return Ok(x), }; } -impl Signature { +impl InternalSignature { /// Convert this `Signature` to a byte array. #[inline] pub fn to_bytes(&self) -> [u8; SIGNATURE_LENGTH] { @@ -170,12 +163,12 @@ impl Signature { /// only checking the most significant three bits. (See also the /// documentation for `PublicKey.verify_strict`.) #[inline] - pub fn from_bytes(bytes: &[u8]) -> Result { + pub fn from_bytes(bytes: &[u8]) -> Result { if bytes.len() != SIGNATURE_LENGTH { - return Err(SignatureError(InternalError::BytesLengthError { + return Err(InternalError::BytesLengthError { name: "Signature", length: SIGNATURE_LENGTH, - })); + }.into()); } let mut lower: [u8; 32] = [0u8; 32]; let mut upper: [u8; 32] = [0u8; 32]; @@ -190,45 +183,23 @@ impl Signature { Err(x) => return Err(x), } - Ok(Signature { + Ok(InternalSignature { R: CompressedEdwardsY(lower), s: s, }) } } -#[cfg(feature = "serde")] -impl Serialize for Signature { - fn serialize(&self, serializer: S) -> Result - where - S: Serializer, - { - serializer.serialize_bytes(&self.to_bytes()[..]) +impl TryFrom<&ed25519::Signature> for InternalSignature { + type Error = SignatureError; + + fn try_from(sig: &ed25519::Signature) -> Result { + InternalSignature::from_bytes(sig.as_bytes()) } } -#[cfg(feature = "serde")] -impl<'d> Deserialize<'d> for Signature { - fn deserialize(deserializer: D) -> Result - 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(self, bytes: &[u8]) -> Result - where - E: SerdeError, - { - Signature::from_bytes(bytes).or(Err(SerdeError::invalid_length(bytes.len(), &self))) - } - } - deserializer.deserialize_bytes(SignatureVisitor) +impl From for ed25519::Signature { + fn from(sig: InternalSignature) -> ed25519::Signature { + ed25519::Signature::from_bytes(&sig.to_bytes()).unwrap() } } diff --git a/tests/ed25519.rs b/tests/ed25519.rs index 88a24df1..2d429979 100644 --- a/tests/ed25519.rs +++ b/tests/ed25519.rs @@ -24,6 +24,8 @@ use sha2::Sha512; #[cfg(test)] mod vectors { + use ed25519::signature::Signature as _; + use std::io::BufReader; use std::io::BufRead; use std::fs::File; @@ -219,6 +221,8 @@ mod serialisation { use self::bincode::{serialize, serialized_size, deserialize, Infinite}; + use ed25519::signature::Signature as _; + static PUBLIC_KEY_BYTES: [u8; PUBLIC_KEY_LENGTH] = [ 130, 039, 155, 015, 062, 076, 188, 063, 124, 122, 026, 251, 233, 253, 225, 220, @@ -281,7 +285,7 @@ mod serialisation { #[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 + assert_eq!(serialized_size(&signature) as usize, 64); // These sizes are specific to bincode==1.0.1 } #[test]