diff --git a/benches/ed25519_benchmarks.rs b/benches/ed25519_benchmarks.rs index 98afd16..ed01d49 100644 --- a/benches/ed25519_benchmarks.rs +++ b/benches/ed25519_benchmarks.rs @@ -12,16 +12,16 @@ use criterion::{criterion_group, criterion_main, Criterion}; mod ed25519_benches { use super::*; use ed25519_dalek::verify_batch; - use ed25519_dalek::Keypair; - use ed25519_dalek::PublicKey; use ed25519_dalek::Signature; use ed25519_dalek::Signer; + use ed25519_dalek::SigningKey; + use ed25519_dalek::VerifyingKey; use rand::prelude::ThreadRng; use rand::thread_rng; fn sign(c: &mut Criterion) { let mut csprng: ThreadRng = thread_rng(); - let keypair: Keypair = Keypair::generate(&mut csprng); + let keypair: SigningKey = SigningKey::generate(&mut csprng); let msg: &[u8] = b""; c.bench_function("Ed25519 signing", move |b| b.iter(|| keypair.sign(msg))); @@ -29,7 +29,7 @@ mod ed25519_benches { fn verify(c: &mut Criterion) { let mut csprng: ThreadRng = thread_rng(); - let keypair: Keypair = Keypair::generate(&mut csprng); + let keypair: SigningKey = SigningKey::generate(&mut csprng); let msg: &[u8] = b""; let sig: Signature = keypair.sign(msg); @@ -40,7 +40,7 @@ mod ed25519_benches { fn verify_strict(c: &mut Criterion) { let mut csprng: ThreadRng = thread_rng(); - let keypair: Keypair = Keypair::generate(&mut csprng); + let keypair: SigningKey = SigningKey::generate(&mut csprng); let msg: &[u8] = b""; let sig: Signature = keypair.sign(msg); @@ -58,16 +58,17 @@ mod ed25519_benches { "Ed25519 batch signature verification", |b, &&size| { let mut csprng: ThreadRng = thread_rng(); - let keypairs: Vec = - (0..size).map(|_| Keypair::generate(&mut csprng)).collect(); + let keypairs: Vec = (0..size) + .map(|_| SigningKey::generate(&mut csprng)) + .collect(); let msg: &[u8] = b"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"; let messages: Vec<&[u8]> = (0..size).map(|_| msg).collect(); let signatures: Vec = keypairs.iter().map(|key| key.sign(&msg)).collect(); - let public_keys: Vec = - keypairs.iter().map(|key| key.public_key()).collect(); + let verifying_keys: Vec = + keypairs.iter().map(|key| key.verifying_key()).collect(); - b.iter(|| verify_batch(&messages[..], &signatures[..], &public_keys[..])); + b.iter(|| verify_batch(&messages[..], &signatures[..], &verifying_keys[..])); }, &BATCH_SIZES, ); @@ -77,7 +78,7 @@ mod ed25519_benches { let mut csprng: ThreadRng = thread_rng(); c.bench_function("Ed25519 keypair generation", move |b| { - b.iter(|| Keypair::generate(&mut csprng)) + b.iter(|| SigningKey::generate(&mut csprng)) }); } diff --git a/src/batch.rs b/src/batch.rs index 63bb895..39af1ca 100644 --- a/src/batch.rs +++ b/src/batch.rs @@ -34,8 +34,8 @@ use sha2::Sha512; use crate::errors::InternalError; use crate::errors::SignatureError; -use crate::public::PublicKey; use crate::signature::InternalSignature; +use crate::VerifyingKey; trait BatchTranscript { fn append_scalars(&mut self, scalars: &Vec); @@ -112,13 +112,13 @@ fn zero_rng() -> ZeroRng { ZeroRng {} } -/// Verify a batch of `signatures` on `messages` with their respective `public_keys`. +/// Verify a batch of `signatures` on `messages` with their respective `verifying_keys`. /// /// # Inputs /// /// * `messages` is a slice of byte slices, one per signed message. /// * `signatures` is a slice of `Signature`s. -/// * `public_keys` is a slice of `PublicKey`s. +/// * `verifying_keys` is a slice of `VerifyingKey`s. /// /// # Returns /// @@ -183,27 +183,27 @@ fn zero_rng() -> ZeroRng { /// falsely "pass" the synthethic batch verification equation *for the same /// inputs*, but *only some crafted inputs* will pass the deterministic batch /// single, and neither of these will ever pass single signature verification, -/// see the documentation for [`PublicKey.validate()`]. +/// see the documentation for [`VerifyingKey.validate()`]. /// /// # Examples /// /// ``` /// use ed25519_dalek::verify_batch; -/// use ed25519_dalek::Keypair; -/// use ed25519_dalek::PublicKey; +/// use ed25519_dalek::SigningKey; +/// use ed25519_dalek::VerifyingKey; /// use ed25519_dalek::Signer; /// use ed25519_dalek::Signature; /// use rand::rngs::OsRng; /// /// # fn main() { /// let mut csprng = OsRng{}; -/// let keypairs: Vec = (0..64).map(|_| Keypair::generate(&mut csprng)).collect(); +/// let signing_keys: Vec<_> = (0..64).map(|_| SigningKey::generate(&mut csprng)).collect(); /// let msg: &[u8] = b"They're good dogs Brant"; /// let messages: Vec<&[u8]> = (0..64).map(|_| msg).collect(); -/// let signatures: Vec = keypairs.iter().map(|key| key.sign(&msg)).collect(); -/// let public_keys: Vec = keypairs.iter().map(|key| key.public_key()).collect(); +/// let signatures: Vec = signing_keys.iter().map(|key| key.sign(&msg)).collect(); +/// let verifying_keys: Vec = signing_keys.iter().map(|key| key.verifying_key()).collect(); /// -/// let result = verify_batch(&messages[..], &signatures[..], &public_keys[..]); +/// let result = verify_batch(&messages[..], &signatures[..], &verifying_keys[..]); /// assert!(result.is_ok()); /// # } /// ``` @@ -211,20 +211,20 @@ fn zero_rng() -> ZeroRng { pub fn verify_batch( messages: &[&[u8]], signatures: &[ed25519::Signature], - public_keys: &[PublicKey], + verifying_keys: &[VerifyingKey], ) -> Result<(), SignatureError> { // Return an Error if any of the vectors were not the same size as the others. if signatures.len() != messages.len() - || signatures.len() != public_keys.len() - || public_keys.len() != messages.len() + || signatures.len() != verifying_keys.len() + || verifying_keys.len() != messages.len() { 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(), + name_c: "verifying_keys", + length_c: verifying_keys.len(), } .into()); } @@ -240,7 +240,7 @@ pub fn verify_batch( .map(|i| { let mut h: Sha512 = Sha512::default(); h.update(signatures[i].R.as_bytes()); - h.update(public_keys[i].as_bytes()); + h.update(verifying_keys[i].as_bytes()); h.update(&messages[i]); Scalar::from_hash(h) }) @@ -284,7 +284,7 @@ pub fn verify_batch( let zhrams = hrams.iter().zip(zs.iter()).map(|(hram, z)| hram * z); let Rs = signatures.iter().map(|sig| sig.R.decompress()); - let As = public_keys.iter().map(|pk| Some(pk.1)); + let As = verifying_keys.iter().map(|pk| Some(pk.1)); let B = once(Some(constants::ED25519_BASEPOINT_POINT)); // Compute (-∑ z[i]s[i] (mod l)) B + ∑ z[i]R[i] + ∑ (z[i]H(R||A||M)[i] (mod l)) A[i] = 0 diff --git a/src/keypair.rs b/src/keypair.rs deleted file mode 100644 index 8c9c6c1..0000000 --- a/src/keypair.rs +++ /dev/null @@ -1,534 +0,0 @@ -// -*- mode: rust; -*- -// -// This file is part of ed25519-dalek. -// Copyright (c) 2017-2019 isis lovecruft -// See LICENSE for licensing information. -// -// Authors: -// - isis agora lovecruft - -//! ed25519 keypairs. - -#[cfg(feature = "pkcs8")] -use ed25519::pkcs8::{self, DecodePrivateKey}; - -#[cfg(feature = "rand")] -use rand::{CryptoRng, RngCore}; - -#[cfg(feature = "serde")] -use serde::de::Error as SerdeError; -#[cfg(feature = "serde")] -use serde::{Deserialize, Deserializer, Serialize, Serializer}; -#[cfg(feature = "serde")] -use serde_bytes::{ByteBuf as SerdeByteBuf, Bytes as SerdeBytes}; - -pub use sha2::Sha512; - -use curve25519_dalek::digest::generic_array::typenum::U64; -pub use curve25519_dalek::digest::Digest; - -use ed25519::signature::{Signer, Verifier}; - -use crate::constants::*; -use crate::errors::*; -use crate::public::*; -use crate::secret::*; - -/// An ed25519 keypair. -// Invariant: `public` is always the public key of `secret`. This prevents the signing function -// oracle attack described in https://github.com/MystenLabs/ed25519-unsafe-libs -#[derive(Debug)] -pub struct Keypair { - /// The secret half of this keypair. - pub(crate) secret: SecretKey, - /// The public half of this keypair. - pub(crate) public: PublicKey, -} - -impl From for Keypair { - fn from(secret: SecretKey) -> Self { - let public = PublicKey::from(&secret); - Self { secret, public } - } -} - -impl Keypair { - /// Get the secret key of this keypair. - pub fn secret_key(&self) -> SecretKey { - SecretKey(self.secret.0) - } - - /// Get the public key of this keypair. - pub fn public_key(&self) -> PublicKey { - self.public - } - - /// Convert this keypair to bytes. - /// - /// # Returns - /// - /// An array of bytes, `[u8; KEYPAIR_LENGTH]`. The first - /// `SECRET_KEY_LENGTH` of bytes is the `SecretKey`, and the next - /// `PUBLIC_KEY_LENGTH` bytes is the `PublicKey` (the same as other - /// libraries, such as [Adam Langley's ed25519 Golang - /// implementation](https://github.com/agl/ed25519/)). It is guaranteed that - /// the encoded public key is the one derived from the encoded secret key. - pub fn to_bytes(&self) -> [u8; KEYPAIR_LENGTH] { - let mut bytes: [u8; KEYPAIR_LENGTH] = [0u8; KEYPAIR_LENGTH]; - - bytes[..SECRET_KEY_LENGTH].copy_from_slice(self.secret.as_bytes()); - bytes[SECRET_KEY_LENGTH..].copy_from_slice(self.public.as_bytes()); - bytes - } - - /// Construct a `Keypair` from the bytes of a `PublicKey` and `SecretKey`. - /// - /// # Inputs - /// - /// * `bytes`: an `&[u8]` of length [`KEYPAIR_LENGTH`], representing the - /// scalar for the secret key, and a compressed Edwards-Y coordinate of a - /// point on curve25519, both as bytes. (As obtained from - /// [`Keypair::to_bytes`].) - /// - /// # Returns - /// - /// A `Result` whose okay value is an EdDSA `Keypair` or whose error value - /// is an `SignatureError` describing the error that occurred. - pub fn from_bytes(bytes: &[u8]) -> Result { - if bytes.len() != KEYPAIR_LENGTH { - 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..])?; - - if public != (&secret).into() { - return Err(InternalError::MismatchedKeypairError.into()); - } - - Ok(Keypair { secret, public }) - } - - /// Generate an ed25519 keypair. - /// - /// # Example - /// - /// ``` - /// # #[cfg(feature = "std")] - /// # 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); - /// - /// # } - /// # - /// # #[cfg(not(feature = "std"))] - /// # fn main() { } - /// ``` - /// - /// # Input - /// - /// A CSPRNG with a `fill_bytes()` method, e.g. `rand_os::OsRng`. - /// - /// The caller must also supply a hash function which implements the - /// `Digest` and `Default` traits, and which returns 512 bits of output. - /// The standard hash function used for most ed25519 libraries is SHA-512, - /// which is available with `use sha2::Sha512` as in the example above. - /// Other suitable hash functions include Keccak-512 and Blake2b-512. - #[cfg(feature = "rand")] - pub fn generate(csprng: &mut R) -> Keypair - where - R: CryptoRng + RngCore, - { - let sk: SecretKey = SecretKey::generate(csprng); - let pk: PublicKey = (&sk).into(); - - Keypair { - public: pk, - secret: sk, - } - } - - /// Sign a `prehashed_message` with this `Keypair` 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. - /// * `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`. - /// - /// # Examples - /// - /// ``` - /// use ed25519_dalek::Digest; - /// use ed25519_dalek::Keypair; - /// use ed25519_dalek::Sha512; - /// use ed25519_dalek::Signature; - /// use rand::rngs::OsRng; - /// - /// # #[cfg(feature = "std")] - /// # fn main() { - /// let mut csprng = OsRng{}; - /// let keypair: Keypair = Keypair::generate(&mut csprng); - /// let message: &[u8] = b"All I want is to pet all of the dogs."; - /// - /// // Create a hash digest object which we'll feed the message into: - /// let mut prehashed: Sha512 = Sha512::new(); - /// - /// prehashed.update(message); - /// # } - /// # - /// # #[cfg(not(feature = "std"))] - /// # fn main() { } - /// ``` - /// - /// If you want, you can optionally pass a "context". It is generally a - /// good idea to choose a context and try to make it unique to your project - /// and this specific usage of signatures. - /// - /// For example, without this, if you were to [convert your OpenPGP key - /// to a Bitcoin key][terrible_idea] (just as an example, and also Don't - /// Ever Do That) and someone tricked you into signing an "email" which was - /// actually a Bitcoin transaction moving all your magic internet money to - /// their address, it'd be a valid transaction. - /// - /// By adding a context, this trick becomes impossible, because the context - /// is concatenated into the hash, which is then signed. So, going with the - /// previous example, if your bitcoin wallet used a context of - /// "BitcoinWalletAppTxnSigning" and OpenPGP used a context (this is likely - /// the least of their safety problems) of "GPGsCryptoIsntConstantTimeLol", - /// then the signatures produced by both could never match the other, even - /// if they signed the exact same message with the same key. - /// - /// Let's add a context for good measure (remember, you'll want to choose - /// your own!): - /// - /// ``` - /// # use ed25519_dalek::Digest; - /// # use ed25519_dalek::Keypair; - /// # use ed25519_dalek::Signature; - /// # use ed25519_dalek::SignatureError; - /// # use ed25519_dalek::Sha512; - /// # use rand::rngs::OsRng; - /// # - /// # fn do_test() -> Result { - /// # let mut csprng = OsRng{}; - /// # let keypair: Keypair = Keypair::generate(&mut csprng); - /// # let message: &[u8] = b"All I want is to pet all of the dogs."; - /// # let mut prehashed: Sha512 = Sha512::new(); - /// # prehashed.update(message); - /// # - /// let context: &[u8] = b"Ed25519DalekSignPrehashedDoctest"; - /// - /// let sig: Signature = keypair.sign_prehashed(prehashed, Some(context))?; - /// # - /// # Ok(sig) - /// # } - /// # #[cfg(feature = "std")] - /// # fn main() { - /// # do_test(); - /// # } - /// # - /// # #[cfg(not(feature = "std"))] - /// # fn main() { } - /// ``` - /// - /// [rfc8032]: https://tools.ietf.org/html/rfc8032#section-5.1 - /// [terrible_idea]: https://github.com/isislovecruft/scripts/blob/master/gpgkey2bc.py - pub fn sign_prehashed( - &self, - prehashed_message: D, - context: Option<&[u8]>, - ) -> Result - where - D: Digest, - { - let expanded: ExpandedSecretKey = (&self.secret).into(); // xxx thanks i hate this - - 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: &ed25519::Signature, - ) -> Result<(), SignatureError> { - self.public.verify(message, signature) - } - - /// 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`. - /// - /// # Examples - /// - /// ``` - /// use ed25519_dalek::Digest; - /// use ed25519_dalek::Keypair; - /// use ed25519_dalek::Signature; - /// use ed25519_dalek::SignatureError; - /// use ed25519_dalek::Sha512; - /// use rand::rngs::OsRng; - /// - /// # fn do_test() -> Result<(), SignatureError> { - /// let mut csprng = OsRng{}; - /// let keypair: Keypair = Keypair::generate(&mut csprng); - /// let message: &[u8] = b"All I want is to pet all of the dogs."; - /// - /// let mut prehashed: Sha512 = Sha512::new(); - /// prehashed.update(message); - /// - /// let context: &[u8] = b"Ed25519DalekSignPrehashedDoctest"; - /// - /// 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: - /// let mut prehashed_again: Sha512 = Sha512::default(); - /// prehashed_again.update(message); - /// - /// let verified = keypair.public_key().verify_prehashed(prehashed_again, Some(context), &sig); - /// - /// assert!(verified.is_ok()); - /// - /// # verified - /// # } - /// # - /// # #[cfg(feature = "std")] - /// # fn main() { - /// # do_test(); - /// # } - /// # - /// # #[cfg(not(feature = "std"))] - /// # fn main() { } - /// ``` - /// - /// [rfc8032]: https://tools.ietf.org/html/rfc8032#section-5.1 - pub fn verify_prehashed( - &self, - prehashed_message: D, - context: Option<&[u8]>, - signature: &ed25519::Signature, - ) -> Result<(), SignatureError> - where - D: Digest, - { - self.public - .verify_prehashed(prehashed_message, context, signature) - } - - /// Strictly verify a signature on a message with this keypair's public key. - /// - /// # On The (Multiple) Sources of Malleability in Ed25519 Signatures - /// - /// This version of verification is technically non-RFC8032 compliant. The - /// following explains why. - /// - /// 1. Scalar Malleability - /// - /// The authors of the RFC explicitly stated that verification of an ed25519 - /// signature must fail if the scalar `s` is not properly reduced mod \ell: - /// - /// > To verify a signature on a message M using public key A, with F - /// > being 0 for Ed25519ctx, 1 for Ed25519ph, and if Ed25519ctx or - /// > Ed25519ph is being used, C being the context, first split the - /// > signature into two 32-octet halves. Decode the first half as a - /// > point R, and the second half as an integer S, in the range - /// > 0 <= s < L. Decode the public key A as point A'. If any of the - /// > decodings fail (including S being out of range), the signature is - /// > invalid.) - /// - /// All `verify_*()` functions within ed25519-dalek perform this check. - /// - /// 2. Point malleability - /// - /// The authors of the RFC added in a malleability check to step #3 in - /// §5.1.7, for small torsion components in the `R` value of the signature, - /// *which is not strictly required*, as they state: - /// - /// > Check the group equation \[8\]\[S\]B = \[8\]R + \[8\]\[k\]A'. It's - /// > sufficient, but not required, to instead check \[S\]B = R + \[k\]A'. - /// - /// # History of Malleability Checks - /// - /// As originally defined (cf. the "Malleability" section in the README of - /// this repo), ed25519 signatures didn't consider *any* form of - /// malleability to be an issue. Later the scalar malleability was - /// considered important. Still later, particularly with interests in - /// cryptocurrency design and in unique identities (e.g. for Signal users, - /// Tor onion services, etc.), the group element malleability became a - /// concern. - /// - /// However, libraries had already been created to conform to the original - /// definition. One well-used library in particular even implemented the - /// group element malleability check, *but only for batch verification*! - /// Which meant that even using the same library, a single signature could - /// verify fine individually, but suddenly, when verifying it with a bunch - /// of other signatures, the whole batch would fail! - /// - /// # "Strict" Verification - /// - /// This method performs *both* of the above signature malleability checks. - /// - /// It must be done as a separate method because one doesn't simply get to - /// change the definition of a cryptographic primitive ten years - /// after-the-fact with zero consideration for backwards compatibility in - /// hardware and protocols which have it already have the older definition - /// baked in. - /// - /// # Return - /// - /// Returns `Ok(())` if the signature is valid, and `Err` otherwise. - #[allow(non_snake_case)] - pub fn verify_strict( - &self, - message: &[u8], - 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) - } -} - -impl TryFrom<&[u8]> for Keypair { - type Error = SignatureError; - - fn try_from(bytes: &[u8]) -> Result { - Keypair::from_bytes(bytes) - } -} - -#[cfg(feature = "pkcs8")] -impl DecodePrivateKey for Keypair {} - -#[cfg(all(feature = "alloc", feature = "pkcs8"))] -impl pkcs8::EncodePrivateKey for Keypair { - fn to_pkcs8_der(&self) -> pkcs8::Result { - pkcs8::KeypairBytes::from(self).to_pkcs8_der() - } -} - -#[cfg(feature = "pkcs8")] -impl TryFrom for Keypair { - type Error = pkcs8::Error; - - fn try_from(pkcs8_key: pkcs8::KeypairBytes) -> pkcs8::Result { - Keypair::try_from(&pkcs8_key) - } -} - -#[cfg(feature = "pkcs8")] -impl TryFrom<&pkcs8::KeypairBytes> for Keypair { - type Error = pkcs8::Error; - - fn try_from(pkcs8_key: &pkcs8::KeypairBytes) -> pkcs8::Result { - let secret = SecretKey::from_bytes(&pkcs8_key.secret_key) - .map_err(|_| pkcs8::Error::KeyMalformed)?; - - let public = PublicKey::from(&secret); - - // Validate the public key in the PKCS#8 document if present - if let Some(public_bytes) = pkcs8_key.public_key { - let pk = PublicKey::from_bytes(public_bytes.as_ref()) - .map_err(|_| pkcs8::Error::KeyMalformed)?; - - if public != pk { - return Err(pkcs8::Error::KeyMalformed); - } - } - - Ok(Keypair { secret, public }) - } -} - -#[cfg(feature = "pkcs8")] -impl From for pkcs8::KeypairBytes { - fn from(keypair: Keypair) -> pkcs8::KeypairBytes { - pkcs8::KeypairBytes::from(&keypair) - } -} - -#[cfg(feature = "pkcs8")] -impl From<&Keypair> for pkcs8::KeypairBytes { - fn from(keypair: &Keypair) -> pkcs8::KeypairBytes { - pkcs8::KeypairBytes { - secret_key: keypair.secret.to_bytes(), - public_key: Some(pkcs8::PublicKeyBytes(keypair.public.to_bytes())), - } - } -} - -#[cfg(feature = "pkcs8")] -impl TryFrom> for Keypair { - type Error = pkcs8::Error; - - fn try_from(private_key: pkcs8::PrivateKeyInfo<'_>) -> pkcs8::Result { - pkcs8::KeypairBytes::try_from(private_key)?.try_into() - } -} - -#[cfg(feature = "serde")] -impl Serialize for Keypair { - fn serialize(&self, serializer: S) -> Result - where - S: Serializer, - { - let bytes = &self.to_bytes()[..]; - SerdeBytes::new(bytes).serialize(serializer) - } -} - -#[cfg(feature = "serde")] -impl<'d> Deserialize<'d> for Keypair { - fn deserialize(deserializer: D) -> Result - where - D: Deserializer<'d>, - { - let bytes = ::deserialize(deserializer)?; - Keypair::from_bytes(bytes.as_ref()).map_err(SerdeError::custom) - } -} diff --git a/src/lib.rs b/src/lib.rs index 07e9cbf..e6d051e 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -13,7 +13,7 @@ //! //! Creating an ed25519 signature on a message is simple. //! -//! First, we need to generate a `Keypair`, which includes both public and +//! First, we need to generate a `SigningKey`, which includes both public and //! secret halves of an asymmetric key. To do so, we need a cryptographically //! secure pseudorandom number generator (CSPRNG). For this example, we'll use //! the operating system's builtin PRNG: @@ -22,28 +22,28 @@ //! # #[cfg(feature = "std")] //! # fn main() { //! use rand::rngs::OsRng; -//! use ed25519_dalek::Keypair; +//! use ed25519_dalek::SigningKey; //! use ed25519_dalek::Signature; //! //! let mut csprng = OsRng{}; -//! let keypair: Keypair = Keypair::generate(&mut csprng); +//! let signing_key: SigningKey = SigningKey::generate(&mut csprng); //! # } //! # //! # #[cfg(not(feature = "std"))] //! # fn main() { } //! ``` //! -//! We can now use this `keypair` to sign a message: +//! We can now use this `signing_key` to sign a message: //! //! ``` //! # fn main() { //! # use rand::rngs::OsRng; -//! # use ed25519_dalek::Keypair; +//! # use ed25519_dalek::SigningKey; //! # let mut csprng = OsRng{}; -//! # let keypair: Keypair = Keypair::generate(&mut csprng); +//! # let signing_key: SigningKey = SigningKey::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); +//! let signature: Signature = signing_key.sign(message); //! # } //! ``` //! @@ -53,39 +53,39 @@ //! ``` //! # fn main() { //! # use rand::rngs::OsRng; -//! # use ed25519_dalek::{Keypair, Signature, Signer}; +//! # use ed25519_dalek::{SigningKey, Signature, Signer}; //! # let mut csprng = OsRng{}; -//! # let keypair: Keypair = Keypair::generate(&mut csprng); +//! # let signing_key: SigningKey = SigningKey::generate(&mut csprng); //! # let message: &[u8] = b"This is a test of the tsunami alert system."; -//! # let signature: Signature = keypair.sign(message); +//! # let signature: Signature = signing_key.sign(message); //! use ed25519_dalek::Verifier; -//! assert!(keypair.verify(message, &signature).is_ok()); +//! assert!(signing_key.verify(message, &signature).is_ok()); //! # } //! ``` //! -//! Anyone else, given the `public` half of the `keypair` can also easily +//! Anyone else, given the `public` half of the `signing_key` can also easily //! verify this signature: //! //! ``` //! # fn main() { //! # use rand::rngs::OsRng; -//! # use ed25519_dalek::Keypair; +//! # use ed25519_dalek::SigningKey; //! # use ed25519_dalek::Signature; //! # use ed25519_dalek::Signer; -//! use ed25519_dalek::{PublicKey, Verifier}; +//! use ed25519_dalek::{VerifyingKey, Verifier}; //! # let mut csprng = OsRng{}; -//! # let keypair: Keypair = Keypair::generate(&mut csprng); +//! # let signing_key: SigningKey = SigningKey::generate(&mut csprng); //! # let message: &[u8] = b"This is a test of the tsunami alert system."; -//! # let signature: Signature = keypair.sign(message); +//! # let signature: Signature = signing_key.sign(message); //! -//! let public_key: PublicKey = keypair.public_key(); -//! assert!(public_key.verify(message, &signature).is_ok()); +//! let verifying_key: VerifyingKey = signing_key.verifying_key(); +//! assert!(verifying_key.verify(message, &signature).is_ok()); //! # } //! ``` //! //! ## Serialisation //! -//! `PublicKey`s, `SecretKey`s, `Keypair`s, and `Signature`s can be serialised +//! `VerifyingKey`s, `SecretKey`s, `SigningKey`s, and `Signature`s can be serialised //! into byte-arrays by calling `.to_bytes()`. It's perfectly acceptible and //! safe to transfer and/or store those bytes. (Of course, never transfer your //! secret key to anyone else, since they will only need the public key to @@ -94,16 +94,16 @@ //! ``` //! # fn main() { //! # use rand::rngs::OsRng; -//! # use ed25519_dalek::{Keypair, Signature, Signer, PublicKey}; +//! # use ed25519_dalek::{SigningKey, Signature, Signer, VerifyingKey}; //! use ed25519_dalek::{PUBLIC_KEY_LENGTH, SECRET_KEY_LENGTH, KEYPAIR_LENGTH, SIGNATURE_LENGTH}; //! # let mut csprng = OsRng{}; -//! # let keypair: Keypair = Keypair::generate(&mut csprng); +//! # let signing_key: SigningKey = SigningKey::generate(&mut csprng); //! # let message: &[u8] = b"This is a test of the tsunami alert system."; -//! # let signature: Signature = keypair.sign(message); +//! # let signature: Signature = signing_key.sign(message); //! -//! let public_key_bytes: [u8; PUBLIC_KEY_LENGTH] = keypair.public_key().to_bytes(); -//! let secret_key_bytes: [u8; SECRET_KEY_LENGTH] = keypair.secret_key().to_bytes(); -//! let keypair_bytes: [u8; KEYPAIR_LENGTH] = keypair.to_bytes(); +//! let verifying_key_bytes: [u8; PUBLIC_KEY_LENGTH] = signing_key.verifying_key().to_bytes(); +//! let secret_key_bytes: [u8; SECRET_KEY_LENGTH] = signing_key.to_bytes(); +//! let signing_key_bytes: [u8; KEYPAIR_LENGTH] = signing_key.to_keypair_bytes(); //! let signature_bytes: [u8; SIGNATURE_LENGTH] = signature.to_bytes(); //! # } //! ``` @@ -114,24 +114,22 @@ //! # use std::convert::TryFrom; //! # use rand::rngs::OsRng; //! # use std::convert::TryInto; -//! # use ed25519_dalek::{Keypair, Signature, Signer, PublicKey, SecretKey, SignatureError}; +//! # use ed25519_dalek::{SigningKey, Signature, Signer, VerifyingKey, SecretKey, SignatureError}; //! # 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<(SigningKey, VerifyingKey, Signature), SignatureError> { //! # let mut csprng = OsRng{}; -//! # let keypair_orig: Keypair = Keypair::generate(&mut csprng); +//! # let signing_key_orig: SigningKey = SigningKey::generate(&mut csprng); //! # let message: &[u8] = b"This is a test of the tsunami alert system."; -//! # let signature_orig: Signature = keypair_orig.sign(message); -//! # let public_key_bytes: [u8; PUBLIC_KEY_LENGTH] = keypair_orig.public_key().to_bytes(); -//! # let secret_key_bytes: [u8; SECRET_KEY_LENGTH] = keypair_orig.secret_key().to_bytes(); -//! # let keypair_bytes: [u8; KEYPAIR_LENGTH] = keypair_orig.to_bytes(); +//! # let signature_orig: Signature = signing_key_orig.sign(message); +//! # let verifying_key_bytes: [u8; PUBLIC_KEY_LENGTH] = signing_key_orig.verifying_key().to_bytes(); +//! # let signing_key_bytes: [u8; SECRET_KEY_LENGTH] = signing_key_orig.to_bytes(); //! # let signature_bytes: [u8; SIGNATURE_LENGTH] = signature_orig.to_bytes(); //! # -//! 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::try_from(&signature_bytes[..])?; +//! let verifying_key: VerifyingKey = VerifyingKey::from_bytes(&verifying_key_bytes)?; +//! let signing_key: SigningKey = SigningKey::from_bytes(&signing_key_bytes); +//! let signature: Signature = Signature::try_from(&signature_bytes[..])?; //! # -//! # Ok((secret_key, public_key, keypair, signature)) +//! # Ok((signing_key, verifying_key, signature)) //! # } //! # fn main() { //! # do_test(); @@ -151,14 +149,14 @@ //! //! To use PKCS#8, you need to enable the `pkcs8` crate feature. //! -//! The following traits can be used to decode/encode [`Keypair`] and -//! [`PublicKey`] as PKCS#8. Note that [`pkcs8`] is re-exported from the +//! The following traits can be used to decode/encode [`SigningKey`] and +//! [`VerifyingKey`] as PKCS#8. Note that [`pkcs8`] is re-exported from the //! toplevel of the crate: //! //! - [`pkcs8::DecodePrivateKey`]: decode private keys from PKCS#8 //! - [`pkcs8::EncodePrivateKey`]: encode private keys to PKCS#8 -//! - [`pkcs8::DecodePublicKey`]: decode public keys from PKCS#8 -//! - [`pkcs8::EncodePublicKey`]: encode public keys to PKCS#8 +//! - [`pkcs8::DecodeVerifyingKey`]: decode public keys from PKCS#8 +//! - [`pkcs8::EncodeVerifyingKey`]: encode public keys to PKCS#8 //! //! #### Example //! @@ -166,13 +164,13 @@ //! #![cfg_attr(feature = "pem", doc = "```")] #![cfg_attr(not(feature = "pem"), doc = "```ignore")] -//! use ed25519_dalek::{PublicKey, pkcs8::DecodePublicKey}; +//! use ed25519_dalek::{VerifyingKey, pkcs8::DecodeVerifyingKey}; //! //! let pem = "-----BEGIN PUBLIC KEY----- //! MCowBQYDK2VwAyEAGb9ECWmEzf6FQbrBZ9w7lshQhqowtrbLDFw4rXAxZuE= //! -----END PUBLIC KEY-----"; //! -//! let public_key = PublicKey::from_public_key_pem(pem) +//! let verifying_key = VerifyingKey::from_verifying_key_pem(pem) //! .expect("invalid public key PEM"); //! ``` //! @@ -193,48 +191,48 @@ //! # #[cfg(feature = "serde")] //! # fn main() { //! # use rand::rngs::OsRng; -//! # use ed25519_dalek::{Keypair, Signature, Signer, Verifier, PublicKey}; +//! # use ed25519_dalek::{SigningKey, Signature, Signer, Verifier, VerifyingKey}; //! use bincode::serialize; //! # let mut csprng = OsRng{}; -//! # let keypair: Keypair = Keypair::generate(&mut csprng); +//! # let signing_key: SigningKey = SigningKey::generate(&mut csprng); //! # let message: &[u8] = b"This is a test of the tsunami alert system."; -//! # let signature: Signature = keypair.sign(message); -//! # let public_key: PublicKey = keypair.public_key(); -//! # let verified: bool = public_key.verify(message, &signature).is_ok(); +//! # let signature: Signature = signing_key.sign(message); +//! # let verifying_key: VerifyingKey = signing_key.verifying_key(); +//! # let verified: bool = verifying_key.verify(message, &signature).is_ok(); //! -//! let encoded_public_key: Vec = serialize(&public_key).unwrap(); +//! let encoded_verifying_key: Vec = serialize(&verifying_key).unwrap(); //! let encoded_signature: Vec = serialize(&signature).unwrap(); //! # } //! # #[cfg(not(feature = "serde"))] //! # fn main() {} //! ``` //! -//! After sending the `encoded_public_key` and `encoded_signature`, the +//! After sending the `encoded_verifying_key` and `encoded_signature`, the //! recipient may deserialise them and verify: //! //! ``` //! # #[cfg(feature = "serde")] //! # fn main() { //! # use rand::rngs::OsRng; -//! # use ed25519_dalek::{Keypair, Signature, Signer, Verifier, PublicKey}; +//! # use ed25519_dalek::{SigningKey, Signature, Signer, Verifier, VerifyingKey}; //! # use bincode::serialize; //! use bincode::deserialize; //! //! # let mut csprng = OsRng{}; -//! # let keypair: Keypair = Keypair::generate(&mut csprng); +//! # let signing_key: SigningKey = SigningKey::generate(&mut csprng); //! let message: &[u8] = b"This is a test of the tsunami alert system."; -//! # let signature: Signature = keypair.sign(message); -//! # let public_key: PublicKey = keypair.public_key(); -//! # let verified: bool = public_key.verify(message, &signature).is_ok(); -//! # let encoded_public_key: Vec = serialize(&public_key).unwrap(); +//! # let signature: Signature = signing_key.sign(message); +//! # let verifying_key: VerifyingKey = signing_key.verifying_key(); +//! # let verified: bool = verifying_key.verify(message, &signature).is_ok(); +//! # let encoded_verifying_key: Vec = serialize(&verifying_key).unwrap(); //! # let encoded_signature: Vec = serialize(&signature).unwrap(); -//! let decoded_public_key: PublicKey = deserialize(&encoded_public_key).unwrap(); +//! let decoded_verifying_key: VerifyingKey = deserialize(&encoded_verifying_key).unwrap(); //! let decoded_signature: Signature = deserialize(&encoded_signature).unwrap(); //! -//! # assert_eq!(public_key, decoded_public_key); +//! # assert_eq!(verifying_key, decoded_verifying_key); //! # assert_eq!(signature, decoded_signature); //! # -//! let verified: bool = decoded_public_key.verify(&message, &decoded_signature).is_ok(); +//! let verified: bool = decoded_verifying_key.verify(&message, &decoded_signature).is_ok(); //! //! assert!(verified); //! # } @@ -265,10 +263,9 @@ pub use ed25519; mod batch; mod constants; mod errors; -mod keypair; -mod public; -mod secret; mod signature; +mod signing; +mod verifying; pub use curve25519_dalek::digest::Digest; @@ -276,9 +273,8 @@ pub use curve25519_dalek::digest::Digest; pub use crate::batch::*; pub use crate::constants::*; pub use crate::errors::*; -pub use crate::keypair::*; -pub use crate::public::*; -pub use crate::secret::*; +pub use crate::signing::*; +pub use crate::verifying::*; // Re-export the `Signer` and `Verifier` traits from the `signature` crate pub use ed25519::signature::{Signer, Verifier}; diff --git a/src/secret.rs b/src/secret.rs deleted file mode 100644 index 8f00276..0000000 --- a/src/secret.rs +++ /dev/null @@ -1,432 +0,0 @@ -// -*- mode: rust; -*- -// -// This file is part of ed25519-dalek. -// Copyright (c) 2017-2019 isis lovecruft -// See LICENSE for licensing information. -// -// Authors: -// - isis agora lovecruft - -//! ed25519 secret key types. - -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::scalar::Scalar; - -#[cfg(feature = "rand")] -use rand::{CryptoRng, RngCore}; - -use sha2::Sha512; - -#[cfg(feature = "serde")] -use serde::de::Error as SerdeError; -#[cfg(feature = "serde")] -use serde::{Deserialize, Deserializer, Serialize, Serializer}; -#[cfg(feature = "serde")] -use serde_bytes::{ByteBuf as SerdeByteBuf, Bytes as SerdeBytes}; - -use zeroize::Zeroize; - -use crate::constants::*; -use crate::errors::*; -use crate::public::*; -use crate::signature::*; - -/// An EdDSA secret key. -/// -/// Instances of this secret are automatically overwritten with zeroes when they -/// fall out of scope. -pub struct SecretKey(pub(crate) [u8; SECRET_KEY_LENGTH]); - -impl Drop for SecretKey { - fn drop(&mut self) { - self.0.zeroize() - } -} - -impl Debug for SecretKey { - fn fmt(&self, f: &mut ::core::fmt::Formatter<'_>) -> ::core::fmt::Result { - write!(f, "SecretKey: {:?}", &self.0[..]) - } -} - -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 - /// - /// ``` - /// use ed25519_dalek::SecretKey; - /// use ed25519_dalek::SECRET_KEY_LENGTH; - /// use ed25519_dalek::SignatureError; - /// - /// # fn doctest() -> Result { - /// 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 { - if bytes.len() != SECRET_KEY_LENGTH { - return Err(InternalError::BytesLengthError { - name: "SecretKey", - length: SECRET_KEY_LENGTH, - } - .into()); - } - let mut bits: [u8; 32] = [0u8; 32]; - bits.copy_from_slice(&bytes[..32]); - - Ok(SecretKey(bits)) - } - - /// Generate a `SecretKey` from a `csprng`. - /// - /// # Example - /// - /// ``` - /// # #[cfg(feature = "std")] - /// # fn main() { - /// # - /// use rand::rngs::OsRng; - /// use ed25519_dalek::PublicKey; - /// use ed25519_dalek::SecretKey; - /// use ed25519_dalek::Signature; - /// - /// let mut csprng = OsRng{}; - /// let secret_key: SecretKey = SecretKey::generate(&mut csprng); - /// # } - /// # - /// # #[cfg(not(feature = "std"))] - /// # fn main() { } - /// ``` - /// - /// Afterwards, you can generate the corresponding public: - /// - /// ``` - /// # fn main() { - /// # - /// # use rand::rngs::OsRng; - /// # use ed25519_dalek::PublicKey; - /// # use ed25519_dalek::SecretKey; - /// # use ed25519_dalek::Signature; - /// # - /// # let mut csprng = OsRng{}; - /// # 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` - #[cfg(feature = "rand")] - pub fn generate(csprng: &mut T) -> SecretKey - where - T: CryptoRng + RngCore, - { - let mut sk: SecretKey = SecretKey([0u8; 32]); - - csprng.fill_bytes(&mut sk.0); - - sk - } -} - -#[cfg(feature = "serde")] -impl Serialize for SecretKey { - fn serialize(&self, serializer: S) -> Result - where - S: Serializer, - { - SerdeBytes::new(self.as_bytes()).serialize(serializer) - } -} - -#[cfg(feature = "serde")] -impl<'d> Deserialize<'d> for SecretKey { - fn deserialize(deserializer: D) -> Result - where - D: Deserializer<'d>, - { - let bytes = ::deserialize(deserializer)?; - SecretKey::from_bytes(bytes.as_ref()).map_err(SerdeError::custom) - } -} - -/// 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. -/// -/// 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 -// 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 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". -pub(crate) struct ExpandedSecretKey { - pub(crate) key: Scalar, - pub(crate) nonce: [u8; 32], -} - -impl Drop for ExpandedSecretKey { - fn drop(&mut self) { - self.key.zeroize(); - self.nonce.zeroize() - } -} - -impl<'a> From<&'a SecretKey> for ExpandedSecretKey { - /// Construct an `ExpandedSecretKey` from a `SecretKey`. - /// - /// # Examples - /// - /// ```ignore - /// # fn main() { - /// # - /// use rand::rngs::OsRng; - /// use ed25519_dalek::{SecretKey, ExpandedSecretKey}; - /// - /// let mut csprng = OsRng{}; - /// 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.update(secret_key.as_bytes()); - hash.copy_from_slice(h.finalize().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 { - /// Sign a message with this `ExpandedSecretKey`. - #[allow(non_snake_case)] - pub(crate) fn sign(&self, message: &[u8], public_key: &PublicKey) -> ed25519::Signature { - let mut h: Sha512 = Sha512::new(); - let R: CompressedEdwardsY; - let r: Scalar; - let s: Scalar; - let k: Scalar; - - h.update(&self.nonce); - h.update(&message); - - r = Scalar::from_hash(h); - R = (&r * &constants::ED25519_BASEPOINT_TABLE).compress(); - - h = Sha512::new(); - h.update(R.as_bytes()); - h.update(public_key.as_bytes()); - h.update(&message); - - k = Scalar::from_hash(h); - s = &(&k * &self.key) + &r; - - InternalSignature { R, s }.into() - } - - /// 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 - /// - /// 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 - #[allow(non_snake_case)] - pub(crate) fn sign_prehashed<'a, D>( - &self, - prehashed_message: D, - public_key: &PublicKey, - context: Option<&'a [u8]>, - ) -> Result - where - D: Digest, - { - 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. - - if ctx.len() > 255 { - return Err(SignatureError::from( - InternalError::PrehashedContextLengthError, - )); - } - - let ctx_len: u8 = ctx.len() as u8; - - // Get the result of the pre-hashed message. - prehash.copy_from_slice(prehashed_message.finalize().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_update(b"SigEd25519 no Ed25519 collisions") - .chain_update(&[1]) // Ed25519ph - .chain_update(&[ctx_len]) - .chain_update(ctx) - .chain_update(&self.nonce) - .chain_update(&prehash[..]); - - r = Scalar::from_hash(h); - R = (&r * &constants::ED25519_BASEPOINT_TABLE).compress(); - - h = Sha512::new() - .chain_update(b"SigEd25519 no Ed25519 collisions") - .chain_update(&[1]) // Ed25519ph - .chain_update(&[ctx_len]) - .chain_update(ctx) - .chain_update(R.as_bytes()) - .chain_update(public_key.as_bytes()) - .chain_update(&prehash[..]); - - k = Scalar::from_hash(h); - s = &(&k * &self.key) + &r; - - Ok(InternalSignature { R, s }.into()) - } -} - -#[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)); - } - - #[test] - fn pubkey_from_secret_and_expanded_secret() { - let mut csprng = rand::rngs::OsRng {}; - 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); - } -} diff --git a/src/signing.rs b/src/signing.rs new file mode 100644 index 0000000..719c18f --- /dev/null +++ b/src/signing.rs @@ -0,0 +1,818 @@ +// -*- mode: rust; -*- +// +// This file is part of ed25519-dalek. +// Copyright (c) 2017-2019 isis lovecruft +// See LICENSE for licensing information. +// +// Authors: +// - isis agora lovecruft + +//! ed25519 signing keys. + +#[cfg(feature = "pkcs8")] +use ed25519::pkcs8::{self, DecodePrivateKey}; + +#[cfg(feature = "rand")] +use rand::{CryptoRng, RngCore}; + +#[cfg(feature = "serde")] +use serde::de::Error as SerdeError; +#[cfg(feature = "serde")] +use serde::{Deserialize, Deserializer, Serialize, Serializer}; +#[cfg(feature = "serde")] +use serde_bytes::{ByteBuf as SerdeByteBuf, Bytes as SerdeBytes}; + +use sha2::Sha512; + +use curve25519_dalek::constants::ED25519_BASEPOINT_TABLE; +use curve25519_dalek::digest::generic_array::typenum::U64; +use curve25519_dalek::digest::Digest; +use curve25519_dalek::edwards::CompressedEdwardsY; +use curve25519_dalek::scalar::Scalar; + +use ed25519::signature::{KeypairRef, Signer, Verifier}; + +use zeroize::Zeroize; + +use crate::constants::*; +use crate::errors::*; +use crate::signature::*; +use crate::verifying::*; + +/// ed25519 secret key as defined in [RFC8032 § 5.1.5]: +/// +/// > The private key is 32 octets (256 bits, corresponding to b) of +/// > cryptographically secure random data. +/// +/// [RFC8032 § 5.1.5]: https://www.rfc-editor.org/rfc/rfc8032#section-5.1.5 +pub type SecretKey = [u8; SECRET_KEY_LENGTH]; + +/// ed25519 signing key which can be used to produce signatures. +// Invariant: `public` is always the public key of `secret`. This prevents the signing function +// oracle attack described in https://github.com/MystenLabs/ed25519-unsafe-libs +#[derive(Debug)] +pub struct SigningKey { + /// The secret half of this signing key. + pub(crate) secret_key: SecretKey, + /// The public half of this signing key. + pub(crate) verifying_key: VerifyingKey, +} + +impl SigningKey { + /// Construct a [`SigningKey`] from a slice of bytes. + /// + /// # Example + /// + /// ``` + /// # extern crate ed25519_dalek; + /// # + /// use ed25519_dalek::SigningKey; + /// use ed25519_dalek::SECRET_KEY_LENGTH; + /// use ed25519_dalek::SignatureError; + /// + /// # fn doctest() -> Result { + /// 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 signing_key: SigningKey = SigningKey::from_bytes(&secret_key_bytes); + /// # + /// # Ok(signing_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(secret_key: &SecretKey) -> Self { + let verifying_key = VerifyingKey::from(&ExpandedSecretKey::from(secret_key)); + Self { + secret_key: *secret_key, + verifying_key, + } + } + + /// Convert this secret key to a byte array. + #[inline] + pub fn to_bytes(&self) -> SecretKey { + self.secret_key + } + + /// Construct a [`SigningKey`] from the bytes of a `VerifyingKey` and `SecretKey`. + /// + /// # Inputs + /// + /// * `bytes`: an `&[u8]` of length [`KEYPAIR_LENGTH`], representing the + /// scalar for the secret key, and a compressed Edwards-Y coordinate of a + /// point on curve25519, both as bytes. (As obtained from + /// [`SigningKey::to_bytes`].) + /// + /// # Returns + /// + /// A `Result` whose okay value is an EdDSA [`SigningKey`] or whose error value + /// is an `SignatureError` describing the error that occurred. + #[inline] + pub fn from_keypair_bytes(bytes: &[u8; 64]) -> Result { + if bytes.len() != KEYPAIR_LENGTH { + return Err(InternalError::BytesLengthError { + name: "SigningKey", + length: KEYPAIR_LENGTH, + } + .into()); + } + + let secret_key = + SecretKey::try_from(&bytes[..SECRET_KEY_LENGTH]).map_err(|_| SignatureError::new())?; + let verifying_key = VerifyingKey::from_bytes(&bytes[SECRET_KEY_LENGTH..])?; + + if verifying_key != VerifyingKey::from(&secret_key) { + return Err(InternalError::MismatchedKeypairError.into()); + } + + Ok(SigningKey { + secret_key, + verifying_key, + }) + } + + /// Convert this signing key to bytes. + /// + /// # Returns + /// + /// An array of bytes, `[u8; KEYPAIR_LENGTH]`. The first + /// `SECRET_KEY_LENGTH` of bytes is the `SecretKey`, and the next + /// `PUBLIC_KEY_LENGTH` bytes is the `VerifyingKey` (the same as other + /// libraries, such as [Adam Langley's ed25519 Golang + /// implementation](https://github.com/agl/ed25519/)). It is guaranteed that + /// the encoded public key is the one derived from the encoded secret key. + pub fn to_keypair_bytes(&self) -> [u8; KEYPAIR_LENGTH] { + let mut bytes: [u8; KEYPAIR_LENGTH] = [0u8; KEYPAIR_LENGTH]; + + bytes[..SECRET_KEY_LENGTH].copy_from_slice(&self.secret_key); + bytes[SECRET_KEY_LENGTH..].copy_from_slice(self.verifying_key.as_bytes()); + bytes + } + + /// Get the [`VerifyingKey`] for this [`SigningKey`]. + pub fn verifying_key(&self) -> VerifyingKey { + self.verifying_key + } + + /// Generate an ed25519 signing key. + /// + /// # Example + /// + /// ``` + /// # #[cfg(feature = "std")] + /// # fn main() { + /// + /// use rand::rngs::OsRng; + /// use ed25519_dalek::SigningKey; + /// use ed25519_dalek::Signature; + /// + /// let mut csprng = OsRng{}; + /// let signing_key: SigningKey = SigningKey::generate(&mut csprng); + /// + /// # } + /// # + /// # #[cfg(not(feature = "std"))] + /// # fn main() { } + /// ``` + /// + /// # Input + /// + /// A CSPRNG with a `fill_bytes()` method, e.g. `rand_os::OsRng`. + /// + /// The caller must also supply a hash function which implements the + /// `Digest` and `Default` traits, and which returns 512 bits of output. + /// The standard hash function used for most ed25519 libraries is SHA-512, + /// which is available with `use sha2::Sha512` as in the example above. + /// Other suitable hash functions include Keccak-512 and Blake2b-512. + #[cfg(feature = "rand")] + pub fn generate(csprng: &mut R) -> SigningKey + where + R: CryptoRng + RngCore, + { + let mut secret = SecretKey::default(); + csprng.fill_bytes(&mut secret); + Self::from_bytes(&secret) + } + + /// Sign a `prehashed_message` with this [`SigningKey`] 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. + /// * `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`. + /// + /// # Examples + /// + /// ``` + /// use ed25519_dalek::Digest; + /// use ed25519_dalek::SigningKey; + /// use ed25519_dalek::Sha512; + /// use ed25519_dalek::Signature; + /// use rand::rngs::OsRng; + /// + /// # #[cfg(feature = "std")] + /// # fn main() { + /// let mut csprng = OsRng{}; + /// let signing_key: SigningKey = SigningKey::generate(&mut csprng); + /// let message: &[u8] = b"All I want is to pet all of the dogs."; + /// + /// // Create a hash digest object which we'll feed the message into: + /// let mut prehashed: Sha512 = Sha512::new(); + /// + /// prehashed.update(message); + /// # } + /// # + /// # #[cfg(not(feature = "std"))] + /// # fn main() { } + /// ``` + /// + /// If you want, you can optionally pass a "context". It is generally a + /// good idea to choose a context and try to make it unique to your project + /// and this specific usage of signatures. + /// + /// For example, without this, if you were to [convert your OpenPGP key + /// to a Bitcoin key][terrible_idea] (just as an example, and also Don't + /// Ever Do That) and someone tricked you into signing an "email" which was + /// actually a Bitcoin transaction moving all your magic internet money to + /// their address, it'd be a valid transaction. + /// + /// By adding a context, this trick becomes impossible, because the context + /// is concatenated into the hash, which is then signed. So, going with the + /// previous example, if your bitcoin wallet used a context of + /// "BitcoinWalletAppTxnSigning" and OpenPGP used a context (this is likely + /// the least of their safety problems) of "GPGsCryptoIsntConstantTimeLol", + /// then the signatures produced by both could never match the other, even + /// if they signed the exact same message with the same key. + /// + /// Let's add a context for good measure (remember, you'll want to choose + /// your own!): + /// + /// ``` + /// # use ed25519_dalek::Digest; + /// # use ed25519_dalek::SigningKey; + /// # use ed25519_dalek::Signature; + /// # use ed25519_dalek::SignatureError; + /// # use ed25519_dalek::Sha512; + /// # use rand::rngs::OsRng; + /// # + /// # fn do_test() -> Result { + /// # let mut csprng = OsRng{}; + /// # let signing_key: SigningKey = SigningKey::generate(&mut csprng); + /// # let message: &[u8] = b"All I want is to pet all of the dogs."; + /// # let mut prehashed: Sha512 = Sha512::new(); + /// # prehashed.update(message); + /// # + /// let context: &[u8] = b"Ed25519DalekSignPrehashedDoctest"; + /// + /// let sig: Signature = signing_key.sign_prehashed(prehashed, Some(context))?; + /// # + /// # Ok(sig) + /// # } + /// # #[cfg(feature = "std")] + /// # fn main() { + /// # do_test(); + /// # } + /// # + /// # #[cfg(not(feature = "std"))] + /// # fn main() { } + /// ``` + /// + /// [rfc8032]: https://tools.ietf.org/html/rfc8032#section-5.1 + /// [terrible_idea]: https://github.com/isislovecruft/scripts/blob/master/gpgkey2bc.py + pub fn sign_prehashed( + &self, + prehashed_message: D, + context: Option<&[u8]>, + ) -> Result + where + D: Digest, + { + let expanded: ExpandedSecretKey = (&self.secret_key).into(); // xxx thanks i hate this + + expanded + .sign_prehashed(prehashed_message, &self.verifying_key, context) + .into() + } + + /// Verify a signature on a message with this signing key's public key. + pub fn verify( + &self, + message: &[u8], + signature: &ed25519::Signature, + ) -> Result<(), SignatureError> { + self.verifying_key.verify(message, signature) + } + + /// 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 + /// [`SigningKey`] on the `prehashed_message`. + /// + /// # Examples + /// + /// ``` + /// use ed25519_dalek::Digest; + /// use ed25519_dalek::SigningKey; + /// use ed25519_dalek::Signature; + /// use ed25519_dalek::SignatureError; + /// use ed25519_dalek::Sha512; + /// use rand::rngs::OsRng; + /// + /// # fn do_test() -> Result<(), SignatureError> { + /// let mut csprng = OsRng{}; + /// let signing_key: SigningKey = SigningKey::generate(&mut csprng); + /// let message: &[u8] = b"All I want is to pet all of the dogs."; + /// + /// let mut prehashed: Sha512 = Sha512::new(); + /// prehashed.update(message); + /// + /// let context: &[u8] = b"Ed25519DalekSignPrehashedDoctest"; + /// + /// let sig: Signature = signing_key.sign_prehashed(prehashed, Some(context))?; + /// + /// // The sha2::Sha512 struct doesn't implement Copy, so we'll have to create a new one: + /// let mut prehashed_again: Sha512 = Sha512::default(); + /// prehashed_again.update(message); + /// + /// let verified = signing_key.verifying_key().verify_prehashed(prehashed_again, Some(context), &sig); + /// + /// assert!(verified.is_ok()); + /// + /// # verified + /// # } + /// # + /// # #[cfg(feature = "std")] + /// # fn main() { + /// # do_test(); + /// # } + /// # + /// # #[cfg(not(feature = "std"))] + /// # fn main() { } + /// ``` + /// + /// [rfc8032]: https://tools.ietf.org/html/rfc8032#section-5.1 + pub fn verify_prehashed( + &self, + prehashed_message: D, + context: Option<&[u8]>, + signature: &ed25519::Signature, + ) -> Result<(), SignatureError> + where + D: Digest, + { + self.verifying_key + .verify_prehashed(prehashed_message, context, signature) + } + + /// Strictly verify a signature on a message with this signing key's public key. + /// + /// # On The (Multiple) Sources of Malleability in Ed25519 Signatures + /// + /// This version of verification is technically non-RFC8032 compliant. The + /// following explains why. + /// + /// 1. Scalar Malleability + /// + /// The authors of the RFC explicitly stated that verification of an ed25519 + /// signature must fail if the scalar `s` is not properly reduced mod \ell: + /// + /// > To verify a signature on a message M using public key A, with F + /// > being 0 for Ed25519ctx, 1 for Ed25519ph, and if Ed25519ctx or + /// > Ed25519ph is being used, C being the context, first split the + /// > signature into two 32-octet halves. Decode the first half as a + /// > point R, and the second half as an integer S, in the range + /// > 0 <= s < L. Decode the public key A as point A'. If any of the + /// > decodings fail (including S being out of range), the signature is + /// > invalid.) + /// + /// All `verify_*()` functions within ed25519-dalek perform this check. + /// + /// 2. Point malleability + /// + /// The authors of the RFC added in a malleability check to step #3 in + /// §5.1.7, for small torsion components in the `R` value of the signature, + /// *which is not strictly required*, as they state: + /// + /// > Check the group equation \[8\]\[S\]B = \[8\]R + \[8\]\[k\]A'. It's + /// > sufficient, but not required, to instead check \[S\]B = R + \[k\]A'. + /// + /// # History of Malleability Checks + /// + /// As originally defined (cf. the "Malleability" section in the README of + /// this repo), ed25519 signatures didn't consider *any* form of + /// malleability to be an issue. Later the scalar malleability was + /// considered important. Still later, particularly with interests in + /// cryptocurrency design and in unique identities (e.g. for Signal users, + /// Tor onion services, etc.), the group element malleability became a + /// concern. + /// + /// However, libraries had already been created to conform to the original + /// definition. One well-used library in particular even implemented the + /// group element malleability check, *but only for batch verification*! + /// Which meant that even using the same library, a single signature could + /// verify fine individually, but suddenly, when verifying it with a bunch + /// of other signatures, the whole batch would fail! + /// + /// # "Strict" Verification + /// + /// This method performs *both* of the above signature malleability checks. + /// + /// It must be done as a separate method because one doesn't simply get to + /// change the definition of a cryptographic primitive ten years + /// after-the-fact with zero consideration for backwards compatibility in + /// hardware and protocols which have it already have the older definition + /// baked in. + /// + /// # Return + /// + /// Returns `Ok(())` if the signature is valid, and `Err` otherwise. + #[allow(non_snake_case)] + pub fn verify_strict( + &self, + message: &[u8], + signature: &ed25519::Signature, + ) -> Result<(), SignatureError> { + self.verifying_key.verify_strict(message, signature) + } +} + +impl AsRef for SigningKey { + fn as_ref(&self) -> &VerifyingKey { + &self.verifying_key + } +} + +impl KeypairRef for SigningKey { + type VerifyingKey = VerifyingKey; +} + +impl Signer for SigningKey { + /// Sign a message with this signing key's secret key. + fn try_sign(&self, message: &[u8]) -> Result { + let expanded: ExpandedSecretKey = (&self.secret_key).into(); + Ok(expanded.sign(&message, &self.verifying_key).into()) + } +} + +impl Verifier for SigningKey { + /// Verify a signature on a message with this signing key's public key. + fn verify(&self, message: &[u8], signature: &ed25519::Signature) -> Result<(), SignatureError> { + self.verifying_key.verify(message, signature) + } +} + +impl From for SigningKey { + #[inline] + fn from(secret: SecretKey) -> Self { + Self::from_bytes(&secret) + } +} + +impl From<&SecretKey> for SigningKey { + #[inline] + fn from(secret: &SecretKey) -> Self { + Self::from_bytes(secret) + } +} + +impl TryFrom<&[u8]> for SigningKey { + type Error = SignatureError; + + fn try_from(bytes: &[u8]) -> Result { + SecretKey::try_from(bytes) + .map(|bytes| Self::from_bytes(&bytes)) + .map_err(|_| { + InternalError::BytesLengthError { + name: "SecretKey", + length: SECRET_KEY_LENGTH, + } + .into() + }) + } +} + +#[cfg(feature = "pkcs8")] +impl DecodePrivateKey for SigningKey {} + +#[cfg(all(feature = "alloc", feature = "pkcs8"))] +impl pkcs8::EncodePrivateKey for SigningKey { + fn to_pkcs8_der(&self) -> pkcs8::Result { + pkcs8::KeypairBytes::from(self).to_pkcs8_der() + } +} + +#[cfg(feature = "pkcs8")] +impl TryFrom for SigningKey { + type Error = pkcs8::Error; + + fn try_from(pkcs8_key: pkcs8::KeypairBytes) -> pkcs8::Result { + SigningKey::try_from(&pkcs8_key) + } +} + +#[cfg(feature = "pkcs8")] +impl TryFrom<&pkcs8::KeypairBytes> for SigningKey { + type Error = pkcs8::Error; + + fn try_from(pkcs8_key: &pkcs8::KeypairBytes) -> pkcs8::Result { + // Validate the public key in the PKCS#8 document if present + if let Some(public_bytes) = pkcs8_key.public_key { + let expected_verifying_key = VerifyingKey::from(&pkcs8_key.secret_key); + + let pkcs8_verifying_key = VerifyingKey::from_bytes(public_bytes.as_ref()) + .map_err(|_| pkcs8::Error::KeyMalformed)?; + + if expected_verifying_key != pkcs8_verifying_key { + return Err(pkcs8::Error::KeyMalformed); + } + } + + Ok(SigningKey::from_bytes(&pkcs8_key.secret_key)) + } +} + +#[cfg(feature = "pkcs8")] +impl From for pkcs8::KeypairBytes { + fn from(signing_key: SigningKey) -> pkcs8::KeypairBytes { + pkcs8::KeypairBytes::from(&signing_key) + } +} + +#[cfg(feature = "pkcs8")] +impl From<&SigningKey> for pkcs8::KeypairBytes { + fn from(signing_key: &SigningKey) -> pkcs8::KeypairBytes { + pkcs8::KeypairBytes { + secret_key: signing_key.to_bytes(), + public_key: Some(pkcs8::PublicKeyBytes(signing_key.verifying_key.to_bytes())), + } + } +} + +#[cfg(feature = "pkcs8")] +impl TryFrom> for SigningKey { + type Error = pkcs8::Error; + + fn try_from(private_key: pkcs8::PrivateKeyInfo<'_>) -> pkcs8::Result { + pkcs8::KeypairBytes::try_from(private_key)?.try_into() + } +} + +#[cfg(feature = "serde")] +impl Serialize for SigningKey { + fn serialize(&self, serializer: S) -> Result + where + S: Serializer, + { + SerdeBytes::new(&self.secret_key).serialize(serializer) + } +} + +#[cfg(feature = "serde")] +impl<'d> Deserialize<'d> for SigningKey { + fn deserialize(deserializer: D) -> Result + where + D: Deserializer<'d>, + { + let bytes = ::deserialize(deserializer)?; + Self::try_from(bytes.as_ref()).map_err(SerdeError::custom) + } +} + +/// 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. +/// +/// 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 +// 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 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". +pub(crate) struct ExpandedSecretKey { + pub(crate) key: Scalar, + pub(crate) nonce: [u8; 32], +} + +impl Drop for ExpandedSecretKey { + fn drop(&mut self) { + self.key.zeroize(); + self.nonce.zeroize() + } +} + +impl From<&SecretKey> for ExpandedSecretKey { + /// Construct an `ExpandedSecretKey` from a `SecretKey`. + /// + /// # Examples + /// + /// ```ignore + /// # fn main() { + /// # + /// use rand::rngs::OsRng; + /// use ed25519_dalek::{SecretKey, ExpandedSecretKey}; + /// + /// let mut csprng = OsRng{}; + /// let secret_key: SecretKey = SecretKey::generate(&mut csprng); + /// let expanded_secret_key: ExpandedSecretKey = ExpandedSecretKey::from(&secret_key); + /// # } + /// ``` + fn from(secret_key: &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.update(secret_key); + hash.copy_from_slice(h.finalize().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 { + /// Sign a message with this `ExpandedSecretKey`. + #[allow(non_snake_case)] + pub(crate) fn sign(&self, message: &[u8], verifying_key: &VerifyingKey) -> ed25519::Signature { + let mut h: Sha512 = Sha512::new(); + let R: CompressedEdwardsY; + let r: Scalar; + let s: Scalar; + let k: Scalar; + + h.update(&self.nonce); + h.update(&message); + + r = Scalar::from_hash(h); + R = (&r * &ED25519_BASEPOINT_TABLE).compress(); + + h = Sha512::new(); + h.update(R.as_bytes()); + h.update(verifying_key.as_bytes()); + h.update(&message); + + k = Scalar::from_hash(h); + s = &(&k * &self.key) + &r; + + InternalSignature { R, s }.into() + } + + /// 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. + /// * `verifying_key` is a [`VerifyingKey`] 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 + /// + /// 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 + #[allow(non_snake_case)] + pub(crate) fn sign_prehashed<'a, D>( + &self, + prehashed_message: D, + verifying_key: &VerifyingKey, + context: Option<&'a [u8]>, + ) -> Result + where + D: Digest, + { + 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. + + if ctx.len() > 255 { + return Err(SignatureError::from( + InternalError::PrehashedContextLengthError, + )); + } + + let ctx_len: u8 = ctx.len() as u8; + + // Get the result of the pre-hashed message. + prehash.copy_from_slice(prehashed_message.finalize().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_update(b"SigEd25519 no Ed25519 collisions") + .chain_update(&[1]) // Ed25519ph + .chain_update(&[ctx_len]) + .chain_update(ctx) + .chain_update(&self.nonce) + .chain_update(&prehash[..]); + + r = Scalar::from_hash(h); + R = (&r * &ED25519_BASEPOINT_TABLE).compress(); + + h = Sha512::new() + .chain_update(b"SigEd25519 no Ed25519 collisions") + .chain_update(&[1]) // Ed25519ph + .chain_update(&[ctx_len]) + .chain_update(ctx) + .chain_update(R.as_bytes()) + .chain_update(verifying_key.as_bytes()) + .chain_update(&prehash[..]); + + k = Scalar::from_hash(h); + s = &(&k * &self.key) + &r; + + Ok(InternalSignature { R, s }.into()) + } +} diff --git a/src/public.rs b/src/verifying.rs similarity index 83% rename from src/public.rs rename to src/verifying.rs index a16dbed..f699798 100644 --- a/src/public.rs +++ b/src/verifying.rs @@ -35,51 +35,53 @@ use serde_bytes::{ByteBuf as SerdeByteBuf, Bytes as SerdeBytes}; use crate::constants::*; use crate::errors::*; -use crate::secret::*; use crate::signature::*; +use crate::signing::*; /// An ed25519 public key. #[derive(Copy, Clone, Default, Eq, PartialEq)] -pub struct PublicKey(pub(crate) CompressedEdwardsY, pub(crate) EdwardsPoint); +pub struct VerifyingKey(pub(crate) CompressedEdwardsY, pub(crate) EdwardsPoint); -impl Debug for PublicKey { +impl Debug for VerifyingKey { fn fmt(&self, f: &mut ::core::fmt::Formatter<'_>) -> ::core::fmt::Result { - write!(f, "PublicKey({:?}), {:?})", self.0, self.1) + write!(f, "VerifyingKey({:?}), {:?})", self.0, self.1) } } -impl AsRef<[u8]> for PublicKey { +impl AsRef<[u8]> for VerifyingKey { fn as_ref(&self) -> &[u8] { self.as_bytes() } } -impl<'a> From<&'a SecretKey> for PublicKey { +impl From<&SecretKey> for VerifyingKey { /// Derive this public key from its corresponding `SecretKey`. - fn from(secret_key: &SecretKey) -> PublicKey { + fn from(secret_key: &SecretKey) -> VerifyingKey { let mut h: Sha512 = Sha512::new(); let mut hash: [u8; 64] = [0u8; 64]; let mut digest: [u8; 32] = [0u8; 32]; - h.update(secret_key.as_bytes()); + h.update(secret_key); hash.copy_from_slice(h.finalize().as_slice()); digest.copy_from_slice(&hash[..32]); - PublicKey::mangle_scalar_bits_and_multiply_by_basepoint_to_produce_public_key(&mut digest) + VerifyingKey::mangle_scalar_bits_and_multiply_by_basepoint_to_produce_public_key( + &mut digest, + ) } } -impl<'a> From<&'a ExpandedSecretKey> for PublicKey { +impl From<&ExpandedSecretKey> for VerifyingKey { /// Derive this public key from its corresponding `ExpandedSecretKey`. - fn from(expanded_secret_key: &ExpandedSecretKey) -> PublicKey { + fn from(expanded_secret_key: &ExpandedSecretKey) -> VerifyingKey { 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) + VerifyingKey::mangle_scalar_bits_and_multiply_by_basepoint_to_produce_public_key(&mut bits) } } -impl PublicKey { +impl VerifyingKey { /// Convert this public key to a byte array. #[inline] pub fn to_bytes(&self) -> [u8; PUBLIC_KEY_LENGTH] { @@ -92,7 +94,7 @@ impl PublicKey { &(self.0).0 } - /// Construct a `PublicKey` from a slice of bytes. + /// Construct a `VerifyingKey` from a slice of bytes. /// /// # Warning /// @@ -103,16 +105,16 @@ impl PublicKey { /// # Example /// /// ``` - /// use ed25519_dalek::PublicKey; + /// use ed25519_dalek::VerifyingKey; /// use ed25519_dalek::PUBLIC_KEY_LENGTH; /// use ed25519_dalek::SignatureError; /// - /// # fn doctest() -> Result { + /// # fn doctest() -> Result { /// 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)?; + /// let public_key = VerifyingKey::from_bytes(&public_key_bytes)?; /// # /// # Ok(public_key) /// # } @@ -124,13 +126,13 @@ impl PublicKey { /// /// # Returns /// - /// A `Result` whose okay value is an EdDSA `PublicKey` or whose error value + /// A `Result` whose okay value is an EdDSA `VerifyingKey` or whose error value /// is an `SignatureError` describing the error that occurred. #[inline] - pub fn from_bytes(bytes: &[u8]) -> Result { + pub fn from_bytes(bytes: &[u8]) -> Result { if bytes.len() != PUBLIC_KEY_LENGTH { return Err(InternalError::BytesLengthError { - name: "PublicKey", + name: "VerifyingKey", length: PUBLIC_KEY_LENGTH, } .into()); @@ -143,7 +145,7 @@ impl PublicKey { .decompress() .ok_or(InternalError::PointDecompressionError)?; - Ok(PublicKey(compressed, point)) + Ok(VerifyingKey(compressed, point)) } /// Internal utility function for mangling the bits of a (formerly @@ -151,7 +153,7 @@ impl PublicKey { /// public key. fn mangle_scalar_bits_and_multiply_by_basepoint_to_produce_public_key( bits: &mut [u8; 32], - ) -> PublicKey { + ) -> VerifyingKey { bits[0] &= 248; bits[31] &= 127; bits[31] |= 64; @@ -159,7 +161,7 @@ impl PublicKey { let point = &Scalar::from_bits(*bits) * &constants::ED25519_BASEPOINT_TABLE; let compressed = point.compress(); - PublicKey(compressed, point) + VerifyingKey(compressed, point) } /// Verify a `signature` on a `prehashed_message` using the Ed25519ph algorithm. @@ -323,7 +325,7 @@ impl PublicKey { } } -impl Verifier for PublicKey { +impl Verifier for VerifyingKey { /// Verify a signature on a message with this keypair's public key. /// /// # Return @@ -353,58 +355,58 @@ impl Verifier for PublicKey { } } -impl TryFrom<&[u8]> for PublicKey { +impl TryFrom<&[u8]> for VerifyingKey { type Error = SignatureError; - fn try_from(bytes: &[u8]) -> Result { - PublicKey::from_bytes(bytes) + fn try_from(bytes: &[u8]) -> Result { + VerifyingKey::from_bytes(bytes) } } #[cfg(feature = "pkcs8")] -impl DecodePublicKey for PublicKey {} +impl DecodePublicKey for VerifyingKey {} #[cfg(all(feature = "alloc", feature = "pkcs8"))] -impl pkcs8::EncodePublicKey for PublicKey { +impl pkcs8::EncodePublicKey for VerifyingKey { fn to_public_key_der(&self) -> pkcs8::spki::Result { pkcs8::PublicKeyBytes::from(self).to_public_key_der() } } #[cfg(feature = "pkcs8")] -impl TryFrom for PublicKey { +impl TryFrom for VerifyingKey { type Error = pkcs8::spki::Error; fn try_from(pkcs8_key: pkcs8::PublicKeyBytes) -> pkcs8::spki::Result { - PublicKey::try_from(&pkcs8_key) + VerifyingKey::try_from(&pkcs8_key) } } #[cfg(feature = "pkcs8")] -impl TryFrom<&pkcs8::PublicKeyBytes> for PublicKey { +impl TryFrom<&pkcs8::PublicKeyBytes> for VerifyingKey { type Error = pkcs8::spki::Error; fn try_from(pkcs8_key: &pkcs8::PublicKeyBytes) -> pkcs8::spki::Result { - PublicKey::from_bytes(pkcs8_key.as_ref()).map_err(|_| pkcs8::spki::Error::KeyMalformed) + VerifyingKey::from_bytes(pkcs8_key.as_ref()).map_err(|_| pkcs8::spki::Error::KeyMalformed) } } #[cfg(feature = "pkcs8")] -impl From for pkcs8::PublicKeyBytes { - fn from(public_key: PublicKey) -> pkcs8::PublicKeyBytes { - pkcs8::PublicKeyBytes::from(&public_key) +impl From for pkcs8::PublicKeyBytes { + fn from(verifying_key: VerifyingKey) -> pkcs8::PublicKeyBytes { + pkcs8::PublicKeyBytes::from(&verifying_key) } } #[cfg(feature = "pkcs8")] -impl From<&PublicKey> for pkcs8::PublicKeyBytes { - fn from(public_key: &PublicKey) -> pkcs8::PublicKeyBytes { - pkcs8::PublicKeyBytes(public_key.to_bytes()) +impl From<&VerifyingKey> for pkcs8::PublicKeyBytes { + fn from(verifying_key: &VerifyingKey) -> pkcs8::PublicKeyBytes { + pkcs8::PublicKeyBytes(verifying_key.to_bytes()) } } #[cfg(feature = "pkcs8")] -impl TryFrom> for PublicKey { +impl TryFrom> for VerifyingKey { type Error = pkcs8::spki::Error; fn try_from(public_key: pkcs8::spki::SubjectPublicKeyInfo<'_>) -> pkcs8::spki::Result { @@ -413,7 +415,7 @@ impl TryFrom> for PublicKey { } #[cfg(feature = "serde")] -impl Serialize for PublicKey { +impl Serialize for VerifyingKey { fn serialize(&self, serializer: S) -> Result where S: Serializer, @@ -423,12 +425,12 @@ impl Serialize for PublicKey { } #[cfg(feature = "serde")] -impl<'d> Deserialize<'d> for PublicKey { +impl<'d> Deserialize<'d> for VerifyingKey { fn deserialize(deserializer: D) -> Result where D: Deserializer<'d>, { let bytes = ::deserialize(deserializer)?; - PublicKey::from_bytes(bytes.as_ref()).map_err(SerdeError::custom) + VerifyingKey::from_bytes(bytes.as_ref()).map_err(SerdeError::custom) } } diff --git a/tests/ed25519.rs b/tests/ed25519.rs index bd597db..87b8164 100644 --- a/tests/ed25519.rs +++ b/tests/ed25519.rs @@ -61,20 +61,19 @@ mod vectors { let msg_bytes: Vec = FromHex::from_hex(&parts[2]).unwrap(); let sig_bytes: Vec = FromHex::from_hex(&parts[3]).unwrap(); - let secret: SecretKey = SecretKey::from_bytes(&sec_bytes[..SECRET_KEY_LENGTH]).unwrap(); - let expected_public: PublicKey = - PublicKey::from_bytes(&pub_bytes[..PUBLIC_KEY_LENGTH]).unwrap(); - let keypair: Keypair = Keypair::from(secret); - assert_eq!(expected_public, keypair.public_key()); + let signing_key = SigningKey::try_from(&sec_bytes[..SECRET_KEY_LENGTH]).unwrap(); + let expected_verifying_key = + VerifyingKey::from_bytes(&pub_bytes[..PUBLIC_KEY_LENGTH]).unwrap(); + assert_eq!(expected_verifying_key, signing_key.verifying_key()); // The signatures in the test vectors also include the message // at the end, but we just want R and S. let sig1: Signature = Signature::try_from(&sig_bytes[..64]).unwrap(); - let sig2: Signature = keypair.sign(&msg_bytes); + let sig2: Signature = signing_key.sign(&msg_bytes); assert!(sig1 == sig2, "Signature bytes not equal on line {}", lineno); assert!( - keypair.verify(&msg_bytes, &sig2).is_ok(), + signing_key.verify(&msg_bytes, &sig2).is_ok(), "Signature verification failed on line {}", lineno ); @@ -85,20 +84,21 @@ mod vectors { #[test] fn ed25519ph_rf8032_test_vector() { let secret_key: &[u8] = b"833fe62409237b9d62ec77587520911e9a759cec1d19755b7da901b96dca3d42"; - let public_key: &[u8] = b"ec172b93ad5e563bf4932c70e1245034c35467ef2efd4d64ebf819683467e2bf"; + let verifying_key: &[u8] = + b"ec172b93ad5e563bf4932c70e1245034c35467ef2efd4d64ebf819683467e2bf"; let message: &[u8] = b"616263"; let signature: &[u8] = b"98a70222f0b8121aa9d30f813d683f809e462b469c7ff87639499bb94e6dae4131f85042463c2a355a2003d062adf5aaa10b8c61e636062aaad11c2a26083406"; let sec_bytes: Vec = FromHex::from_hex(secret_key).unwrap(); - let pub_bytes: Vec = FromHex::from_hex(public_key).unwrap(); + let pub_bytes: Vec = FromHex::from_hex(verifying_key).unwrap(); let msg_bytes: Vec = FromHex::from_hex(message).unwrap(); let sig_bytes: Vec = FromHex::from_hex(signature).unwrap(); - let secret: SecretKey = SecretKey::from_bytes(&sec_bytes[..SECRET_KEY_LENGTH]).unwrap(); - let expected_public: PublicKey = - PublicKey::from_bytes(&pub_bytes[..PUBLIC_KEY_LENGTH]).unwrap(); - let keypair: Keypair = Keypair::from(secret); - assert_eq!(expected_public, keypair.public_key()); + let signing_key: SigningKey = + SigningKey::try_from(&sec_bytes[..SECRET_KEY_LENGTH]).unwrap(); + let expected_verifying_key: VerifyingKey = + VerifyingKey::from_bytes(&pub_bytes[..PUBLIC_KEY_LENGTH]).unwrap(); + assert_eq!(expected_verifying_key, signing_key.verifying_key()); let sig1: Signature = Signature::try_from(&sig_bytes[..]).unwrap(); let mut prehash_for_signing: Sha512 = Sha512::default(); @@ -107,7 +107,9 @@ mod vectors { prehash_for_signing.update(&msg_bytes[..]); prehash_for_verifying.update(&msg_bytes[..]); - let sig2: Signature = keypair.sign_prehashed(prehash_for_signing, None).unwrap(); + let sig2: Signature = signing_key + .sign_prehashed(prehash_for_signing, None) + .unwrap(); assert!( sig1 == sig2, @@ -117,7 +119,7 @@ mod vectors { sig2 ); assert!( - keypair + signing_key .verify_prehashed(prehash_for_verifying, None, &sig2) .is_ok(), "Could not verify ed25519ph signature!" @@ -185,7 +187,7 @@ mod vectors { } let signature = serialize_signature(&r, &s); - let pk = PublicKey::from_bytes(&pub_key.compress().as_bytes()[..]).unwrap(); + let pk = VerifyingKey::from_bytes(&pub_key.compress().as_bytes()[..]).unwrap(); let sig = Signature::try_from(&signature[..]).unwrap(); // The same signature verifies for both messages assert!(pk.verify(message1, &sig).is_ok() && pk.verify(message2, &sig).is_ok()); @@ -204,7 +206,7 @@ mod integrations { #[test] fn sign_verify() { // TestSignVerify - let keypair: Keypair; + let signing_key: SigningKey; let good_sig: Signature; let bad_sig: Signature; @@ -213,27 +215,27 @@ mod integrations { let mut csprng = OsRng {}; - keypair = Keypair::generate(&mut csprng); - good_sig = keypair.sign(&good); - bad_sig = keypair.sign(&bad); + signing_key = SigningKey::generate(&mut csprng); + good_sig = signing_key.sign(&good); + bad_sig = signing_key.sign(&bad); assert!( - keypair.verify(&good, &good_sig).is_ok(), + signing_key.verify(&good, &good_sig).is_ok(), "Verification of a valid signature failed!" ); assert!( - keypair.verify(&good, &bad_sig).is_err(), + signing_key.verify(&good, &bad_sig).is_err(), "Verification of a signature on a different message passed!" ); assert!( - keypair.verify(&bad, &good_sig).is_err(), + signing_key.verify(&bad, &good_sig).is_err(), "Verification of a signature on a different message passed!" ); } #[test] fn ed25519ph_sign_verify() { - let keypair: Keypair; + let signing_key: SigningKey; let good_sig: Signature; let bad_sig: Signature; @@ -257,28 +259,28 @@ mod integrations { let context: &[u8] = b"testing testing 1 2 3"; - keypair = Keypair::generate(&mut csprng); - good_sig = keypair + signing_key = SigningKey::generate(&mut csprng); + good_sig = signing_key .sign_prehashed(prehashed_good1, Some(context)) .unwrap(); - bad_sig = keypair + bad_sig = signing_key .sign_prehashed(prehashed_bad1, Some(context)) .unwrap(); assert!( - keypair + signing_key .verify_prehashed(prehashed_good2, Some(context), &good_sig) .is_ok(), "Verification of a valid signature failed!" ); assert!( - keypair + signing_key .verify_prehashed(prehashed_good3, Some(context), &bad_sig) .is_err(), "Verification of a signature on a different message passed!" ); assert!( - keypair + signing_key .verify_prehashed(prehashed_bad2, Some(context), &good_sig) .is_err(), "Verification of a signature on a different message passed!" @@ -297,17 +299,18 @@ mod integrations { 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 = OsRng; - let mut keypairs: Vec = Vec::new(); + let mut signing_keys: Vec = Vec::new(); let mut signatures: Vec = 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 signing_key: SigningKey = SigningKey::generate(&mut csprng); + signatures.push(signing_key.sign(&messages[i])); + signing_keys.push(signing_key); } - let public_keys: Vec = keypairs.iter().map(|key| key.public_key()).collect(); + let verifying_keys: Vec = + signing_keys.iter().map(|key| key.verifying_key()).collect(); - let result = verify_batch(&messages, &signatures[..], &public_keys[..]); + let result = verify_batch(&messages, &signatures[..], &verifying_keys[..]); assert!(result.is_ok()); } @@ -317,7 +320,7 @@ mod integrations { #[derive(Debug, serde_crate::Serialize, serde_crate::Deserialize)] #[serde(crate = "serde_crate")] struct Demo { - keypair: Keypair, + signing_key: SigningKey, } #[cfg(all(test, feature = "serde"))] @@ -337,7 +340,7 @@ mod serialisation { 150, 073, 201, 137, 076, 022, 085, 251, 152, 002, 241, 042, 072, 054, ]; - /// Signature with the above keypair of a blank message. + /// Signature with the above signing_key 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, @@ -345,13 +348,6 @@ mod serialisation { 041, 081, 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] fn serialize_deserialize_signature_bincode() { let signature: Signature = Signature::from_bytes(&SIGNATURE_BYTES).unwrap(); @@ -371,75 +367,55 @@ mod serialisation { } #[test] - fn serialize_deserialize_public_key_bincode() { - let public_key: PublicKey = PublicKey::from_bytes(&PUBLIC_KEY_BYTES).unwrap(); - let encoded_public_key: Vec = bincode::serialize(&public_key).unwrap(); - let decoded_public_key: PublicKey = bincode::deserialize(&encoded_public_key).unwrap(); + fn serialize_deserialize_verifying_key_bincode() { + let verifying_key: VerifyingKey = VerifyingKey::from_bytes(&PUBLIC_KEY_BYTES).unwrap(); + let encoded_verifying_key: Vec = bincode::serialize(&verifying_key).unwrap(); + let decoded_verifying_key: VerifyingKey = + bincode::deserialize(&encoded_verifying_key).unwrap(); assert_eq!( &PUBLIC_KEY_BYTES[..], - &encoded_public_key[encoded_public_key.len() - PUBLIC_KEY_LENGTH..] + &encoded_verifying_key[encoded_verifying_key.len() - PUBLIC_KEY_LENGTH..] ); - assert_eq!(public_key, decoded_public_key); + assert_eq!(verifying_key, decoded_verifying_key); } #[test] - fn serialize_deserialize_public_key_json() { - let public_key: PublicKey = PublicKey::from_bytes(&PUBLIC_KEY_BYTES).unwrap(); - let encoded_public_key = serde_json::to_string(&public_key).unwrap(); - let decoded_public_key: PublicKey = serde_json::from_str(&encoded_public_key).unwrap(); + fn serialize_deserialize_verifying_key_json() { + let verifying_key: VerifyingKey = VerifyingKey::from_bytes(&PUBLIC_KEY_BYTES).unwrap(); + let encoded_verifying_key = serde_json::to_string(&verifying_key).unwrap(); + let decoded_verifying_key: VerifyingKey = + serde_json::from_str(&encoded_verifying_key).unwrap(); - assert_eq!(public_key, decoded_public_key); + assert_eq!(verifying_key, decoded_verifying_key); } #[test] - fn serialize_deserialize_secret_key_bincode() { - let secret_key: SecretKey = SecretKey::from_bytes(&SECRET_KEY_BYTES).unwrap(); - let encoded_secret_key: Vec = bincode::serialize(&secret_key).unwrap(); - let decoded_secret_key: SecretKey = bincode::deserialize(&encoded_secret_key).unwrap(); + fn serialize_deserialize_signing_key_bincode() { + let signing_key = SigningKey::from_bytes(&SECRET_KEY_BYTES); + let encoded_signing_key: Vec = bincode::serialize(&signing_key).unwrap(); + let decoded_signing_key: SigningKey = bincode::deserialize(&encoded_signing_key).unwrap(); for i in 0..SECRET_KEY_LENGTH { - assert_eq!(SECRET_KEY_BYTES[i], decoded_secret_key.as_bytes()[i]); + assert_eq!(SECRET_KEY_BYTES[i], decoded_signing_key.to_bytes()[i]); } } #[test] - fn serialize_deserialize_secret_key_json() { - let secret_key: SecretKey = SecretKey::from_bytes(&SECRET_KEY_BYTES).unwrap(); - let encoded_secret_key = serde_json::to_string(&secret_key).unwrap(); - let decoded_secret_key: SecretKey = serde_json::from_str(&encoded_secret_key).unwrap(); + fn serialize_deserialize_signing_key_json() { + let signing_key = SigningKey::from_bytes(&SECRET_KEY_BYTES); + let encoded_signing_key = serde_json::to_string(&signing_key).unwrap(); + let decoded_signing_key: SigningKey = serde_json::from_str(&encoded_signing_key).unwrap(); for i in 0..SECRET_KEY_LENGTH { - assert_eq!(SECRET_KEY_BYTES[i], decoded_secret_key.as_bytes()[i]); + assert_eq!(SECRET_KEY_BYTES[i], decoded_signing_key.to_bytes()[i]); } } #[test] - fn serialize_deserialize_keypair_bincode() { - let keypair = Keypair::from_bytes(&KEYPAIR_BYTES).unwrap(); - let encoded_keypair: Vec = bincode::serialize(&keypair).unwrap(); - let decoded_keypair: Keypair = bincode::deserialize(&encoded_keypair).unwrap(); - - for i in 0..KEYPAIR_LENGTH { - assert_eq!(KEYPAIR_BYTES[i], decoded_keypair.to_bytes()[i]); - } - } - - #[test] - fn serialize_deserialize_keypair_json() { - let keypair = Keypair::from_bytes(&KEYPAIR_BYTES).unwrap(); - let encoded_keypair = serde_json::to_string(&keypair).unwrap(); - let decoded_keypair: Keypair = serde_json::from_str(&encoded_keypair).unwrap(); - - for i in 0..KEYPAIR_LENGTH { - assert_eq!(KEYPAIR_BYTES[i], decoded_keypair.to_bytes()[i]); - } - } - - #[test] - fn serialize_deserialize_keypair_toml() { + fn serialize_deserialize_signing_key_toml() { let demo = Demo { - keypair: Keypair::from_bytes(&KEYPAIR_BYTES).unwrap(), + signing_key: SigningKey::from_bytes(&SECRET_KEY_BYTES), }; println!("\n\nWrite to toml"); @@ -450,10 +426,10 @@ mod serialisation { } #[test] - fn serialize_public_key_size() { - let public_key: PublicKey = PublicKey::from_bytes(&PUBLIC_KEY_BYTES).unwrap(); + fn serialize_verifying_key_size() { + let verifying_key: VerifyingKey = VerifyingKey::from_bytes(&PUBLIC_KEY_BYTES).unwrap(); assert_eq!( - bincode::serialized_size(&public_key).unwrap() as usize, + bincode::serialized_size(&verifying_key).unwrap() as usize, BINCODE_INT_LENGTH + PUBLIC_KEY_LENGTH ); } @@ -468,20 +444,11 @@ mod serialisation { } #[test] - fn serialize_secret_key_size() { - let secret_key: SecretKey = SecretKey::from_bytes(&SECRET_KEY_BYTES).unwrap(); + fn serialize_signing_key_size() { + let signing_key = SigningKey::from_bytes(&SECRET_KEY_BYTES); assert_eq!( - bincode::serialized_size(&secret_key).unwrap() as usize, + bincode::serialized_size(&signing_key).unwrap() as usize, BINCODE_INT_LENGTH + SECRET_KEY_LENGTH ); } - - #[test] - fn serialize_keypair_size() { - let keypair = Keypair::from_bytes(&KEYPAIR_BYTES).unwrap(); - assert_eq!( - bincode::serialized_size(&keypair).unwrap() as usize, - BINCODE_INT_LENGTH + KEYPAIR_LENGTH - ); - } } diff --git a/tests/pkcs8.rs b/tests/pkcs8.rs index 0af97f5..fecdba9 100644 --- a/tests/pkcs8.rs +++ b/tests/pkcs8.rs @@ -6,14 +6,11 @@ #![cfg(feature = "pkcs8")] use ed25519_dalek::pkcs8::{DecodePrivateKey, DecodePublicKey}; -use ed25519_dalek::{Keypair, PublicKey}; +use ed25519_dalek::{SigningKey, VerifyingKey}; use hex_literal::hex; #[cfg(feature = "alloc")] -use ed25519_dalek::{ - pkcs8::{EncodePrivateKey, EncodePublicKey}, - SecretKey, -}; +use ed25519_dalek::pkcs8::{EncodePrivateKey, EncodePublicKey}; /// Ed25519 PKCS#8 v1 private key encoded as ASN.1 DER. const PKCS8_V1_DER: &[u8] = include_bytes!("examples/pkcs8-v1.der"); @@ -21,7 +18,7 @@ const PKCS8_V1_DER: &[u8] = include_bytes!("examples/pkcs8-v1.der"); /// Ed25519 PKCS#8 v2 private key + public key encoded as ASN.1 DER. const PKCS8_V2_DER: &[u8] = include_bytes!("examples/pkcs8-v2.der"); -/// Ed25519 SubjectPublicKeyInfo encoded as ASN.1 DER. +/// Ed25519 SubjectVerifyingKeyInfo encoded as ASN.1 DER. const PUBLIC_KEY_DER: &[u8] = include_bytes!("examples/pubkey.der"); /// Secret key bytes. @@ -35,40 +32,40 @@ const PK_BYTES: [u8; 32] = hex!("19BF44096984CDFE8541BAC167DC3B96C85086AA30B6B6C #[test] fn decode_pkcs8_v1() { - let keypair = Keypair::from_pkcs8_der(PKCS8_V1_DER).unwrap(); - assert_eq!(SK_BYTES, keypair.secret_key().to_bytes()); - assert_eq!(PK_BYTES, keypair.public_key().to_bytes()); + let keypair = SigningKey::from_pkcs8_der(PKCS8_V1_DER).unwrap(); + assert_eq!(SK_BYTES, keypair.to_bytes()); + assert_eq!(PK_BYTES, keypair.verifying_key().to_bytes()); } #[test] fn decode_pkcs8_v2() { - let keypair = Keypair::from_pkcs8_der(PKCS8_V2_DER).unwrap(); - assert_eq!(SK_BYTES, keypair.secret_key().to_bytes()); - assert_eq!(PK_BYTES, keypair.public_key().to_bytes()); + let keypair = SigningKey::from_pkcs8_der(PKCS8_V2_DER).unwrap(); + assert_eq!(SK_BYTES, keypair.to_bytes()); + assert_eq!(PK_BYTES, keypair.verifying_key().to_bytes()); } #[test] -fn decode_public_key() { - let public_key = PublicKey::from_public_key_der(PUBLIC_KEY_DER).unwrap(); - assert_eq!(PK_BYTES, public_key.to_bytes()); +fn decode_verifying_key() { + let verifying_key = VerifyingKey::from_public_key_der(PUBLIC_KEY_DER).unwrap(); + assert_eq!(PK_BYTES, verifying_key.to_bytes()); } #[test] #[cfg(feature = "alloc")] fn encode_pkcs8() { - let keypair = Keypair::from(SecretKey::from_bytes(&SK_BYTES).unwrap()); + let keypair = SigningKey::from_bytes(&SK_BYTES); let pkcs8_key = keypair.to_pkcs8_der().unwrap(); - let keypair2 = Keypair::from_pkcs8_der(pkcs8_key.as_bytes()).unwrap(); + let keypair2 = SigningKey::from_pkcs8_der(pkcs8_key.as_bytes()).unwrap(); assert_eq!(keypair.to_bytes(), keypair2.to_bytes()); } #[test] #[cfg(feature = "alloc")] -fn encode_public_key() { - let public_key = PublicKey::from_bytes(&PK_BYTES).unwrap(); - let public_key_der = public_key.to_public_key_der().unwrap(); +fn encode_verifying_key() { + let verifying_key = VerifyingKey::from_bytes(&PK_BYTES).unwrap(); + let verifying_key_der = verifying_key.to_public_key_der().unwrap(); - let public_key2 = PublicKey::from_public_key_der(public_key_der.as_bytes()).unwrap(); - assert_eq!(public_key, public_key2); + let verifying_key2 = VerifyingKey::from_public_key_der(verifying_key_der.as_bytes()).unwrap(); + assert_eq!(verifying_key, verifying_key2); }