Rename Keypair => SigningKey; PublicKey => VerifyingKey (#242)

* Rename `signing` and `verifying` modules

Renames the following modules:

- `keypair` => `signing`
- `public` => `verifying`

Renaming these in an individual commit preserves the commit history.

This is in anticipation of renaming the following per #225:

- `Keypair` => `SigningKey`
- `PublicKey` => `VerifyingKey`

* Rename `Keypair` => `SigningKey`; `PublicKey` => `VerifyingKey`

As proposed in #225, renames key types after their roles:

- `SigningKey` produces signatures
- `VerifyingKey` verifies signatures

The `SecretKey` type is changed to a type alias for `[u8; 32]`, which
matches the RFC8032 definition:

https://www.rfc-editor.org/rfc/rfc8032#section-5.1.5

> The private key is 32 octets (256 bits, corresponding to b) of
> cryptographically secure random data.
This commit is contained in:
Tony Arcieri
2022-12-17 23:24:58 -07:00
committed by GitHub
parent 55620dcde5
commit 52da7353b8
9 changed files with 1045 additions and 1230 deletions

View File

@@ -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<Keypair> =
(0..size).map(|_| Keypair::generate(&mut csprng)).collect();
let keypairs: Vec<SigningKey> = (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<Signature> =
keypairs.iter().map(|key| key.sign(&msg)).collect();
let public_keys: Vec<PublicKey> =
keypairs.iter().map(|key| key.public_key()).collect();
let verifying_keys: Vec<VerifyingKey> =
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))
});
}

View File

@@ -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<Scalar>);
@@ -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<Keypair> = (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<Signature> = keypairs.iter().map(|key| key.sign(&msg)).collect();
/// let public_keys: Vec<PublicKey> = keypairs.iter().map(|key| key.public_key()).collect();
/// let signatures: Vec<Signature> = signing_keys.iter().map(|key| key.sign(&msg)).collect();
/// let verifying_keys: Vec<VerifyingKey> = 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

View File

@@ -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 <isis@patternsinthevoid.net>
//! 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<SecretKey> 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<Keypair, SignatureError> {
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<R>(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<Signature, 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))?;
/// #
/// # 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<D>(
&self,
prehashed_message: D,
context: Option<&[u8]>,
) -> Result<ed25519::Signature, SignatureError>
where
D: Digest<OutputSize = U64>,
{
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<D>(
&self,
prehashed_message: D,
context: Option<&[u8]>,
signature: &ed25519::Signature,
) -> Result<(), SignatureError>
where
D: Digest<OutputSize = U64>,
{
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<ed25519::Signature> for Keypair {
/// Sign a message with this keypair's secret key.
fn try_sign(&self, message: &[u8]) -> Result<ed25519::Signature, SignatureError> {
let expanded: ExpandedSecretKey = (&self.secret).into();
Ok(expanded.sign(&message, &self.public).into())
}
}
impl Verifier<ed25519::Signature> for Keypair {
/// Verify a signature on a message with this keypair's public key.
fn verify(&self, message: &[u8], signature: &ed25519::Signature) -> Result<(), SignatureError> {
self.public.verify(message, signature)
}
}
impl TryFrom<&[u8]> for Keypair {
type Error = SignatureError;
fn try_from(bytes: &[u8]) -> Result<Keypair, SignatureError> {
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::SecretDocument> {
pkcs8::KeypairBytes::from(self).to_pkcs8_der()
}
}
#[cfg(feature = "pkcs8")]
impl TryFrom<pkcs8::KeypairBytes> for Keypair {
type Error = pkcs8::Error;
fn try_from(pkcs8_key: pkcs8::KeypairBytes) -> pkcs8::Result<Self> {
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<Self> {
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<Keypair> 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<pkcs8::PrivateKeyInfo<'_>> for Keypair {
type Error = pkcs8::Error;
fn try_from(private_key: pkcs8::PrivateKeyInfo<'_>) -> pkcs8::Result<Self> {
pkcs8::KeypairBytes::try_from(private_key)?.try_into()
}
}
#[cfg(feature = "serde")]
impl Serialize for Keypair {
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where
S: Serializer,
{
let bytes = &self.to_bytes()[..];
SerdeBytes::new(bytes).serialize(serializer)
}
}
#[cfg(feature = "serde")]
impl<'d> Deserialize<'d> for Keypair {
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
where
D: Deserializer<'d>,
{
let bytes = <SerdeByteBuf>::deserialize(deserializer)?;
Keypair::from_bytes(bytes.as_ref()).map_err(SerdeError::custom)
}
}

View File

@@ -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<u8> = serialize(&public_key).unwrap();
//! let encoded_verifying_key: Vec<u8> = serialize(&verifying_key).unwrap();
//! let encoded_signature: Vec<u8> = 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<u8> = 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<u8> = serialize(&verifying_key).unwrap();
//! # let encoded_signature: Vec<u8> = 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};

View File

@@ -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 <isis@patternsinthevoid.net>
//! 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<SecretKey, SignatureError> {
/// let secret_key_bytes: [u8; SECRET_KEY_LENGTH] = [
/// 157, 097, 177, 157, 239, 253, 090, 096,
/// 186, 132, 074, 244, 146, 236, 044, 196,
/// 068, 073, 197, 105, 123, 050, 105, 025,
/// 112, 059, 172, 003, 028, 174, 127, 096, ];
///
/// let secret_key: SecretKey = SecretKey::from_bytes(&secret_key_bytes)?;
/// #
/// # Ok(secret_key)
/// # }
/// #
/// # fn main() {
/// # let result = doctest();
/// # assert!(result.is_ok());
/// # }
/// ```
///
/// # Returns
///
/// A `Result` whose okay value is an EdDSA `SecretKey` or whose error value
/// is an `SignatureError` wrapping the internal error that occurred.
#[inline]
pub fn from_bytes(bytes: &[u8]) -> Result<SecretKey, SignatureError> {
if bytes.len() != SECRET_KEY_LENGTH {
return Err(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<T>(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<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where
S: Serializer,
{
SerdeBytes::new(self.as_bytes()).serialize(serializer)
}
}
#[cfg(feature = "serde")]
impl<'d> Deserialize<'d> for SecretKey {
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
where
D: Deserializer<'d>,
{
let bytes = <SerdeByteBuf>::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<ed25519::Signature, SignatureError>
where
D: Digest<OutputSize = U64>,
{
let mut h: Sha512;
let mut prehash: [u8; 64] = [0u8; 64];
let R: CompressedEdwardsY;
let r: Scalar;
let s: Scalar;
let k: Scalar;
let ctx: &[u8] = context.unwrap_or(b""); // By default, the context is an empty string.
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);
}
}

818
src/signing.rs Normal file
View File

@@ -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 <isis@patternsinthevoid.net>
//! 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<SigningKey, SignatureError> {
/// let secret_key_bytes: [u8; SECRET_KEY_LENGTH] = [
/// 157, 097, 177, 157, 239, 253, 090, 096,
/// 186, 132, 074, 244, 146, 236, 044, 196,
/// 068, 073, 197, 105, 123, 050, 105, 025,
/// 112, 059, 172, 003, 028, 174, 127, 096, ];
///
/// let 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<SigningKey, SignatureError> {
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<R>(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<Signature, 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))?;
/// #
/// # 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<D>(
&self,
prehashed_message: D,
context: Option<&[u8]>,
) -> Result<ed25519::Signature, SignatureError>
where
D: Digest<OutputSize = U64>,
{
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<D>(
&self,
prehashed_message: D,
context: Option<&[u8]>,
signature: &ed25519::Signature,
) -> Result<(), SignatureError>
where
D: Digest<OutputSize = U64>,
{
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<VerifyingKey> for SigningKey {
fn as_ref(&self) -> &VerifyingKey {
&self.verifying_key
}
}
impl KeypairRef for SigningKey {
type VerifyingKey = VerifyingKey;
}
impl Signer<ed25519::Signature> for SigningKey {
/// Sign a message with this signing key's secret key.
fn try_sign(&self, message: &[u8]) -> Result<ed25519::Signature, SignatureError> {
let expanded: ExpandedSecretKey = (&self.secret_key).into();
Ok(expanded.sign(&message, &self.verifying_key).into())
}
}
impl Verifier<ed25519::Signature> 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<SecretKey> 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<SigningKey, SignatureError> {
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::SecretDocument> {
pkcs8::KeypairBytes::from(self).to_pkcs8_der()
}
}
#[cfg(feature = "pkcs8")]
impl TryFrom<pkcs8::KeypairBytes> for SigningKey {
type Error = pkcs8::Error;
fn try_from(pkcs8_key: pkcs8::KeypairBytes) -> pkcs8::Result<Self> {
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<Self> {
// 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<SigningKey> 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<pkcs8::PrivateKeyInfo<'_>> for SigningKey {
type Error = pkcs8::Error;
fn try_from(private_key: pkcs8::PrivateKeyInfo<'_>) -> pkcs8::Result<Self> {
pkcs8::KeypairBytes::try_from(private_key)?.try_into()
}
}
#[cfg(feature = "serde")]
impl Serialize for SigningKey {
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where
S: Serializer,
{
SerdeBytes::new(&self.secret_key).serialize(serializer)
}
}
#[cfg(feature = "serde")]
impl<'d> Deserialize<'d> for SigningKey {
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
where
D: Deserializer<'d>,
{
let bytes = <SerdeByteBuf>::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<ed25519::Signature, SignatureError>
where
D: Digest<OutputSize = U64>,
{
let mut h: Sha512;
let mut prehash: [u8; 64] = [0u8; 64];
let R: CompressedEdwardsY;
let r: Scalar;
let s: Scalar;
let k: Scalar;
let ctx: &[u8] = context.unwrap_or(b""); // By default, the context is an empty string.
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())
}
}

View File

@@ -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<PublicKey, SignatureError> {
/// # fn doctest() -> Result<VerifyingKey, SignatureError> {
/// let public_key_bytes: [u8; PUBLIC_KEY_LENGTH] = [
/// 215, 90, 152, 1, 130, 177, 10, 183, 213, 75, 254, 211, 201, 100, 7, 58,
/// 14, 225, 114, 243, 218, 166, 35, 37, 175, 2, 26, 104, 247, 7, 81, 26];
///
/// let public_key = PublicKey::from_bytes(&public_key_bytes)?;
/// 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<PublicKey, SignatureError> {
pub fn from_bytes(bytes: &[u8]) -> Result<VerifyingKey, SignatureError> {
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<ed25519::Signature> for PublicKey {
impl Verifier<ed25519::Signature> for VerifyingKey {
/// Verify a signature on a message with this keypair's public key.
///
/// # Return
@@ -353,58 +355,58 @@ impl Verifier<ed25519::Signature> for PublicKey {
}
}
impl TryFrom<&[u8]> for PublicKey {
impl TryFrom<&[u8]> for VerifyingKey {
type Error = SignatureError;
fn try_from(bytes: &[u8]) -> Result<PublicKey, SignatureError> {
PublicKey::from_bytes(bytes)
fn try_from(bytes: &[u8]) -> Result<VerifyingKey, SignatureError> {
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::Document> {
pkcs8::PublicKeyBytes::from(self).to_public_key_der()
}
}
#[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<Self> {
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<Self> {
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<PublicKey> for pkcs8::PublicKeyBytes {
fn from(public_key: PublicKey) -> pkcs8::PublicKeyBytes {
pkcs8::PublicKeyBytes::from(&public_key)
impl From<VerifyingKey> 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<pkcs8::spki::SubjectPublicKeyInfo<'_>> for PublicKey {
impl TryFrom<pkcs8::spki::SubjectPublicKeyInfo<'_>> for VerifyingKey {
type Error = pkcs8::spki::Error;
fn try_from(public_key: pkcs8::spki::SubjectPublicKeyInfo<'_>) -> pkcs8::spki::Result<Self> {
@@ -413,7 +415,7 @@ impl TryFrom<pkcs8::spki::SubjectPublicKeyInfo<'_>> for PublicKey {
}
#[cfg(feature = "serde")]
impl Serialize for PublicKey {
impl Serialize for VerifyingKey {
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
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<D>(deserializer: D) -> Result<Self, D::Error>
where
D: Deserializer<'d>,
{
let bytes = <SerdeByteBuf>::deserialize(deserializer)?;
PublicKey::from_bytes(bytes.as_ref()).map_err(SerdeError::custom)
VerifyingKey::from_bytes(bytes.as_ref()).map_err(SerdeError::custom)
}
}

View File

@@ -61,20 +61,19 @@ mod vectors {
let msg_bytes: Vec<u8> = FromHex::from_hex(&parts[2]).unwrap();
let sig_bytes: Vec<u8> = FromHex::from_hex(&parts[3]).unwrap();
let secret: SecretKey = SecretKey::from_bytes(&sec_bytes[..SECRET_KEY_LENGTH]).unwrap();
let 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<u8> = FromHex::from_hex(secret_key).unwrap();
let pub_bytes: Vec<u8> = FromHex::from_hex(public_key).unwrap();
let pub_bytes: Vec<u8> = FromHex::from_hex(verifying_key).unwrap();
let msg_bytes: Vec<u8> = FromHex::from_hex(message).unwrap();
let sig_bytes: Vec<u8> = FromHex::from_hex(signature).unwrap();
let secret: SecretKey = SecretKey::from_bytes(&sec_bytes[..SECRET_KEY_LENGTH]).unwrap();
let 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<Keypair> = Vec::new();
let mut signing_keys: Vec<SigningKey> = Vec::new();
let mut signatures: Vec<Signature> = Vec::new();
for i in 0..messages.len() {
let keypair: Keypair = Keypair::generate(&mut csprng);
signatures.push(keypair.sign(&messages[i]));
keypairs.push(keypair);
let signing_key: SigningKey = SigningKey::generate(&mut csprng);
signatures.push(signing_key.sign(&messages[i]));
signing_keys.push(signing_key);
}
let public_keys: Vec<PublicKey> = keypairs.iter().map(|key| key.public_key()).collect();
let verifying_keys: Vec<VerifyingKey> =
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<u8> = 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<u8> = 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<u8> = 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<u8> = 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<u8> = 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
);
}
}

View File

@@ -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);
}