2016-12-01 00:40:48 +00:00
|
|
|
// -*- mode: rust; -*-
|
|
|
|
|
//
|
2017-10-05 06:19:55 +00:00
|
|
|
// This file is part of ed25519-dalek.
|
|
|
|
|
// Copyright (c) 2017 Isis Lovecruft
|
|
|
|
|
// See LICENSE for licensing information.
|
2016-12-01 00:40:48 +00:00
|
|
|
//
|
|
|
|
|
// Authors:
|
|
|
|
|
// - Isis Agora Lovecruft <isis@patternsinthevoid.net>
|
|
|
|
|
|
2017-08-01 03:35:38 +00:00
|
|
|
//! A Rust implementation of ed25519 EdDSA key generation, signing, and
|
|
|
|
|
//! verification.
|
2016-12-01 00:40:48 +00:00
|
|
|
|
2017-02-06 21:45:08 +00:00
|
|
|
use core::fmt::Debug;
|
2016-12-01 00:40:48 +00:00
|
|
|
|
2017-02-06 21:45:08 +00:00
|
|
|
#[cfg(feature = "std")]
|
2016-12-01 00:40:48 +00:00
|
|
|
use rand::Rng;
|
|
|
|
|
|
2017-08-01 06:52:10 +00:00
|
|
|
use digest::BlockInput;
|
|
|
|
|
use digest::Digest;
|
2017-05-08 07:54:56 +00:00
|
|
|
use digest::Input;
|
|
|
|
|
use digest::FixedOutput;
|
2017-08-01 06:52:10 +00:00
|
|
|
|
2017-03-14 21:36:35 +00:00
|
|
|
use generic_array::typenum::U64;
|
|
|
|
|
|
2017-05-14 10:57:59 +00:00
|
|
|
use curve25519_dalek::constants;
|
2017-08-15 05:30:53 +00:00
|
|
|
use curve25519_dalek::edwards::CompressedEdwardsY;
|
|
|
|
|
use curve25519_dalek::edwards::ExtendedPoint;
|
2016-12-01 00:40:48 +00:00
|
|
|
use curve25519_dalek::scalar::Scalar;
|
2017-08-01 06:52:10 +00:00
|
|
|
|
|
|
|
|
use subtle::slices_equal;
|
2016-12-01 00:40:48 +00:00
|
|
|
|
2017-08-01 03:35:38 +00:00
|
|
|
/// The length of an ed25519 EdDSA `Signature`, in bytes.
|
2017-02-06 21:45:08 +00:00
|
|
|
pub const SIGNATURE_LENGTH: usize = 64;
|
2016-12-01 00:40:48 +00:00
|
|
|
|
2017-08-01 03:35:38 +00:00
|
|
|
/// The length of an ed25519 EdDSA `SecretKey`, in bytes.
|
|
|
|
|
pub const SECRET_KEY_LENGTH: usize = 32;
|
|
|
|
|
|
|
|
|
|
/// The length of an ed25519 EdDSA `PublicKey`, in bytes.
|
|
|
|
|
pub const PUBLIC_KEY_LENGTH: usize = 32;
|
|
|
|
|
|
|
|
|
|
/// An EdDSA signature.
|
2016-12-09 00:52:38 +00:00
|
|
|
///
|
|
|
|
|
/// # Note
|
|
|
|
|
///
|
2017-08-01 03:35:38 +00:00
|
|
|
/// These signatures, unlike the ed25519 signature reference implementation, are
|
|
|
|
|
/// "detached"—that is, they do **not** include a copy of the message which has
|
|
|
|
|
/// been signed.
|
2016-12-01 00:40:48 +00:00
|
|
|
#[derive(Copy)]
|
2017-08-01 03:35:38 +00:00
|
|
|
#[repr(C)]
|
2017-02-06 21:45:08 +00:00
|
|
|
pub struct Signature(pub [u8; SIGNATURE_LENGTH]);
|
2016-12-01 00:40:48 +00:00
|
|
|
|
|
|
|
|
impl Clone for Signature {
|
|
|
|
|
fn clone(&self) -> Self { *self }
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
impl Debug for Signature {
|
2017-02-06 21:45:08 +00:00
|
|
|
fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result {
|
2017-08-01 03:35:38 +00:00
|
|
|
write!(f, "Signature([{:?}])", &self.0[..])
|
2016-12-01 00:40:48 +00:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2016-12-09 00:52:38 +00:00
|
|
|
impl Eq for Signature {}
|
|
|
|
|
|
|
|
|
|
impl PartialEq for Signature {
|
|
|
|
|
fn eq(&self, other: &Signature) -> bool {
|
|
|
|
|
let mut equal: u8 = 0;
|
|
|
|
|
|
|
|
|
|
for i in 0..64 {
|
|
|
|
|
equal |= self.0[i] ^ other.0[i];
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if equal == 0 {
|
|
|
|
|
return true;
|
|
|
|
|
} else {
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2016-12-01 00:40:48 +00:00
|
|
|
impl Signature {
|
2017-08-01 03:35:38 +00:00
|
|
|
/// View this `Signature` as a byte array.
|
2016-12-01 00:40:48 +00:00
|
|
|
#[inline]
|
2017-02-06 21:45:08 +00:00
|
|
|
pub fn to_bytes(&self) -> [u8; SIGNATURE_LENGTH] {
|
2016-12-01 00:40:48 +00:00
|
|
|
self.0
|
|
|
|
|
}
|
2016-12-09 00:52:38 +00:00
|
|
|
|
2017-08-01 03:35:38 +00:00
|
|
|
/// View this `Signature` as a byte array.
|
|
|
|
|
#[inline]
|
|
|
|
|
pub fn as_bytes<'a>(&'a self) -> &'a [u8; SIGNATURE_LENGTH] {
|
|
|
|
|
&self.0
|
|
|
|
|
}
|
|
|
|
|
|
2016-12-09 00:52:38 +00:00
|
|
|
/// Construct a `Signature` from a slice of bytes.
|
|
|
|
|
#[inline]
|
|
|
|
|
pub fn from_bytes(bytes: &[u8]) -> Signature {
|
2017-02-06 21:45:08 +00:00
|
|
|
Signature(*array_ref!(bytes, 0, SIGNATURE_LENGTH))
|
2016-12-09 00:52:38 +00:00
|
|
|
}
|
2016-12-01 00:40:48 +00:00
|
|
|
}
|
|
|
|
|
|
2017-08-01 03:35:38 +00:00
|
|
|
/// An EdDSA secret key.
|
|
|
|
|
#[repr(C)]
|
|
|
|
|
pub struct SecretKey(pub [u8; SECRET_KEY_LENGTH]);
|
2016-12-01 00:40:48 +00:00
|
|
|
|
|
|
|
|
impl Debug for SecretKey {
|
2017-02-06 21:45:08 +00:00
|
|
|
fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result {
|
2016-12-01 00:40:48 +00:00
|
|
|
write!(f, "SecretKey: {:?}", &self.0[..])
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
impl SecretKey {
|
2017-08-01 03:35:38 +00:00
|
|
|
/// Convert this secret key to a byte array.
|
2016-12-01 00:40:48 +00:00
|
|
|
#[inline]
|
2017-08-01 03:35:38 +00:00
|
|
|
pub fn to_bytes(&self) -> [u8; SECRET_KEY_LENGTH] {
|
2016-12-01 00:40:48 +00:00
|
|
|
self.0
|
|
|
|
|
}
|
|
|
|
|
|
2017-08-01 03:35:38 +00:00
|
|
|
/// View this secret key as a byte array.
|
|
|
|
|
#[inline]
|
|
|
|
|
pub fn as_bytes<'a>(&'a self) -> &'a [u8; SECRET_KEY_LENGTH] {
|
|
|
|
|
&self.0
|
|
|
|
|
}
|
|
|
|
|
|
2016-12-09 00:52:38 +00:00
|
|
|
/// Construct a `SecretKey` from a slice of bytes.
|
|
|
|
|
///
|
|
|
|
|
/// # Example
|
|
|
|
|
///
|
2017-08-01 03:35:38 +00:00
|
|
|
/// ```
|
|
|
|
|
/// # extern crate ed25519_dalek;
|
|
|
|
|
/// # fn main() {
|
2016-12-09 00:52:38 +00:00
|
|
|
/// use ed25519_dalek::SecretKey;
|
2017-08-01 03:35:38 +00:00
|
|
|
/// use ed25519_dalek::SECRET_KEY_LENGTH;
|
2016-12-09 00:52:38 +00:00
|
|
|
///
|
2017-08-01 03:35:38 +00:00
|
|
|
/// 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, ];
|
2016-12-09 00:52:38 +00:00
|
|
|
///
|
2017-08-01 03:35:38 +00:00
|
|
|
/// let secret_key: SecretKey = SecretKey::from_bytes(&secret_key_bytes[..]);
|
|
|
|
|
/// # }
|
2016-12-09 00:52:38 +00:00
|
|
|
/// ```
|
|
|
|
|
///
|
|
|
|
|
/// # Returns
|
|
|
|
|
///
|
2017-08-01 03:35:38 +00:00
|
|
|
/// An EdDSA `SecretKey`.
|
2016-12-09 00:52:38 +00:00
|
|
|
#[inline]
|
2017-03-14 21:49:07 +00:00
|
|
|
pub fn from_bytes(bytes: &[u8]) -> SecretKey {
|
2017-08-01 03:35:38 +00:00
|
|
|
SecretKey(*array_ref!(bytes, 0, SECRET_KEY_LENGTH))
|
2016-12-09 00:52:38 +00:00
|
|
|
}
|
|
|
|
|
|
2017-08-01 03:35:38 +00:00
|
|
|
/// Generate a `SecretKey` from a `csprng`.
|
|
|
|
|
///
|
|
|
|
|
/// # Example
|
|
|
|
|
///
|
|
|
|
|
/// ```
|
|
|
|
|
/// extern crate rand;
|
|
|
|
|
/// extern crate sha2;
|
|
|
|
|
/// extern crate ed25519_dalek;
|
|
|
|
|
///
|
|
|
|
|
/// # fn main() {
|
|
|
|
|
///
|
|
|
|
|
/// use rand::Rng;
|
|
|
|
|
/// use rand::OsRng;
|
|
|
|
|
/// use sha2::Sha512;
|
|
|
|
|
/// use ed25519_dalek::PublicKey;
|
|
|
|
|
/// use ed25519_dalek::SecretKey;
|
|
|
|
|
/// use ed25519_dalek::Signature;
|
|
|
|
|
///
|
|
|
|
|
/// let mut csprng: OsRng = OsRng::new().unwrap();
|
|
|
|
|
/// let secret_key: SecretKey = SecretKey::generate(&mut csprng);
|
|
|
|
|
///
|
|
|
|
|
/// # }
|
|
|
|
|
/// ```
|
|
|
|
|
///
|
|
|
|
|
/// Afterwards, you can generate the corresponding public—provided you also
|
|
|
|
|
/// supply a hash function which implements the `Digest` and `Default`
|
|
|
|
|
/// traits, and which returns 512 bits of output—via:
|
|
|
|
|
///
|
|
|
|
|
/// ```
|
|
|
|
|
/// # extern crate rand;
|
|
|
|
|
/// # extern crate sha2;
|
|
|
|
|
/// # extern crate ed25519_dalek;
|
|
|
|
|
/// #
|
|
|
|
|
/// # fn main() {
|
|
|
|
|
/// #
|
|
|
|
|
/// # use rand::Rng;
|
|
|
|
|
/// # use rand::OsRng;
|
|
|
|
|
/// # use sha2::Sha512;
|
|
|
|
|
/// # use ed25519_dalek::PublicKey;
|
|
|
|
|
/// # use ed25519_dalek::SecretKey;
|
|
|
|
|
/// # use ed25519_dalek::Signature;
|
|
|
|
|
/// #
|
|
|
|
|
/// # let mut csprng: OsRng = OsRng::new().unwrap();
|
|
|
|
|
/// # let secret_key: SecretKey = SecretKey::generate(&mut csprng);
|
|
|
|
|
///
|
|
|
|
|
/// let public_key: PublicKey = PublicKey::from_secret::<Sha512>(&secret_key);
|
|
|
|
|
/// # }
|
|
|
|
|
/// ```
|
|
|
|
|
///
|
|
|
|
|
/// 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.
|
|
|
|
|
///
|
|
|
|
|
/// # Input
|
|
|
|
|
///
|
|
|
|
|
/// A CSPRING with a `fill_bytes()` method, e.g. the one returned
|
|
|
|
|
/// from `rand::OsRng::new()` (in the `rand` crate).
|
|
|
|
|
///
|
|
|
|
|
#[cfg(feature = "std")]
|
|
|
|
|
pub fn generate(csprng: &mut Rng) -> SecretKey {
|
|
|
|
|
let mut sk: SecretKey = SecretKey([0u8; 32]);
|
2016-12-01 00:40:48 +00:00
|
|
|
|
2017-08-01 03:35:38 +00:00
|
|
|
csprng.fill_bytes(&mut sk.0);
|
2016-12-01 00:40:48 +00:00
|
|
|
|
2017-08-01 03:35:38 +00:00
|
|
|
sk
|
2016-12-01 00:40:48 +00:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// An ed25519 public key.
|
|
|
|
|
#[derive(Copy, Clone)]
|
2017-08-01 03:35:38 +00:00
|
|
|
#[repr(C)]
|
2017-02-06 21:43:37 +00:00
|
|
|
pub struct PublicKey(pub CompressedEdwardsY);
|
2016-12-01 00:40:48 +00:00
|
|
|
|
|
|
|
|
impl Debug for PublicKey {
|
2017-02-06 21:45:08 +00:00
|
|
|
fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result {
|
|
|
|
|
write!(f, "PublicKey( CompressedPoint( {:?} ))", self.0)
|
2016-12-01 00:40:48 +00:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
impl PublicKey {
|
2017-08-01 03:35:38 +00:00
|
|
|
/// Convert this public key to a byte array.
|
2016-12-01 00:40:48 +00:00
|
|
|
#[inline]
|
2017-08-01 03:35:38 +00:00
|
|
|
pub fn to_bytes(&self) -> [u8; PUBLIC_KEY_LENGTH] {
|
2016-12-01 00:40:48 +00:00
|
|
|
self.0.to_bytes()
|
|
|
|
|
}
|
|
|
|
|
|
2017-08-01 03:35:38 +00:00
|
|
|
/// View this public key as a byte array.
|
|
|
|
|
#[inline]
|
|
|
|
|
pub fn as_bytes<'a>(&'a self) -> &'a [u8; PUBLIC_KEY_LENGTH] {
|
|
|
|
|
&(self.0).0
|
|
|
|
|
}
|
|
|
|
|
|
2016-12-09 00:52:38 +00:00
|
|
|
/// Construct a `PublicKey` from a slice of bytes.
|
|
|
|
|
///
|
|
|
|
|
/// # Warning
|
|
|
|
|
///
|
|
|
|
|
/// The caller is responsible for ensuring that the bytes passed into this
|
2017-02-06 21:43:37 +00:00
|
|
|
/// method actually represent a `curve25519_dalek::curve::CompressedEdwardsY`
|
2016-12-09 00:52:38 +00:00
|
|
|
/// and that said compressed point is actually a point on the curve.
|
|
|
|
|
///
|
|
|
|
|
/// # Example
|
|
|
|
|
///
|
2017-08-01 03:35:38 +00:00
|
|
|
/// ```
|
|
|
|
|
/// # extern crate ed25519_dalek;
|
|
|
|
|
/// # fn main() {
|
2016-12-09 00:52:38 +00:00
|
|
|
/// use ed25519_dalek::PublicKey;
|
2017-08-01 03:35:38 +00:00
|
|
|
/// use ed25519_dalek::PUBLIC_KEY_LENGTH;
|
2016-12-09 00:52:38 +00:00
|
|
|
///
|
2017-08-01 03:35:38 +00:00
|
|
|
/// let public_key_bytes: [u8; PUBLIC_KEY_LENGTH] = [
|
2016-12-09 00:52:38 +00:00
|
|
|
/// 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 = PublicKey::from_bytes(&public_key_bytes);
|
2017-08-01 03:35:38 +00:00
|
|
|
/// # }
|
2016-12-09 00:52:38 +00:00
|
|
|
/// ```
|
|
|
|
|
///
|
|
|
|
|
/// # Returns
|
|
|
|
|
///
|
|
|
|
|
/// A `PublicKey`.
|
|
|
|
|
#[inline]
|
2017-03-14 21:49:07 +00:00
|
|
|
pub fn from_bytes(bytes: &[u8]) -> PublicKey {
|
2017-02-06 21:43:37 +00:00
|
|
|
PublicKey(CompressedEdwardsY(*array_ref!(bytes, 0, 32)))
|
2016-12-09 00:52:38 +00:00
|
|
|
}
|
|
|
|
|
|
2016-12-01 00:40:48 +00:00
|
|
|
/// Convert this public key to its underlying extended twisted Edwards coordinate.
|
|
|
|
|
#[inline]
|
|
|
|
|
fn decompress(&self) -> Option<ExtendedPoint> {
|
|
|
|
|
self.0.decompress()
|
|
|
|
|
}
|
|
|
|
|
|
2017-08-01 03:35:38 +00:00
|
|
|
/// Derive this public key from its corresponding `SecretKey`.
|
|
|
|
|
#[cfg(feature = "std")]
|
|
|
|
|
#[allow(unused_assignments)]
|
|
|
|
|
pub fn from_secret<D>(secret_key: &SecretKey) -> PublicKey
|
2017-08-01 06:52:10 +00:00
|
|
|
where D: Digest<OutputSize = U64> + Default {
|
2017-08-01 03:35:38 +00:00
|
|
|
|
|
|
|
|
let mut h: D = D::default();
|
|
|
|
|
let mut hash: [u8; 64] = [0u8; 64];
|
|
|
|
|
let pk: [u8; 32];
|
|
|
|
|
let mut digest: &mut [u8; 32];
|
|
|
|
|
|
2017-08-01 06:52:10 +00:00
|
|
|
h.input(secret_key.as_bytes());
|
2017-08-01 03:35:38 +00:00
|
|
|
hash.copy_from_slice(h.fixed_result().as_slice());
|
|
|
|
|
|
|
|
|
|
digest = array_mut_ref!(&mut hash, 0, 32);
|
|
|
|
|
digest[0] &= 248;
|
|
|
|
|
digest[31] &= 127;
|
|
|
|
|
digest[31] |= 64;
|
|
|
|
|
|
2017-10-05 07:03:35 +00:00
|
|
|
pk = (&Scalar(*digest) * &constants::ED25519_BASEPOINT_TABLE).compress().to_bytes();
|
2017-08-01 03:35:38 +00:00
|
|
|
|
|
|
|
|
PublicKey(CompressedEdwardsY(pk))
|
|
|
|
|
}
|
|
|
|
|
|
2016-12-01 00:40:48 +00:00
|
|
|
/// Verify a signature on a message with this keypair's public key.
|
|
|
|
|
///
|
|
|
|
|
/// # Return
|
|
|
|
|
///
|
|
|
|
|
/// Returns true if the signature was successfully verified, and
|
|
|
|
|
/// false otherwise.
|
2017-03-14 23:43:02 +00:00
|
|
|
pub fn verify<D>(&self, message: &[u8], signature: &Signature) -> bool
|
2017-08-01 06:52:10 +00:00
|
|
|
where D: Digest<OutputSize = U64> + Default {
|
2017-03-14 23:43:02 +00:00
|
|
|
|
2017-08-15 05:30:53 +00:00
|
|
|
use curve25519_dalek::edwards::vartime;
|
|
|
|
|
|
2017-03-14 23:43:02 +00:00
|
|
|
let mut h: D = D::default();
|
2016-12-01 00:40:48 +00:00
|
|
|
let mut a: ExtendedPoint;
|
|
|
|
|
let ao: Option<ExtendedPoint>;
|
2017-05-14 10:57:59 +00:00
|
|
|
let r: ExtendedPoint;
|
2017-03-15 18:42:58 +00:00
|
|
|
let digest: [u8; 64];
|
2016-12-01 00:40:48 +00:00
|
|
|
let digest_reduced: Scalar;
|
|
|
|
|
|
|
|
|
|
if signature.0[63] & 224 != 0 {
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
ao = self.decompress();
|
|
|
|
|
|
|
|
|
|
if ao.is_some() {
|
|
|
|
|
a = ao.unwrap();
|
|
|
|
|
} else {
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
a = -(&a);
|
|
|
|
|
|
|
|
|
|
let top_half: &[u8; 32] = array_ref!(&signature.0, 32, 32);
|
|
|
|
|
let bottom_half: &[u8; 32] = array_ref!(&signature.0, 0, 32);
|
|
|
|
|
|
2017-08-01 06:52:10 +00:00
|
|
|
h.input(&bottom_half[..]);
|
|
|
|
|
h.input(&self.to_bytes());
|
|
|
|
|
h.input(&message);
|
2016-12-01 00:40:48 +00:00
|
|
|
|
2017-05-08 07:54:56 +00:00
|
|
|
let digest_bytes = h.fixed_result();
|
2017-03-15 18:42:58 +00:00
|
|
|
digest = *array_ref!(digest_bytes, 0, 64);
|
2016-12-01 00:40:48 +00:00
|
|
|
digest_reduced = Scalar::reduce(&digest);
|
2017-08-15 05:30:53 +00:00
|
|
|
r = vartime::double_scalar_mult_basepoint(&digest_reduced, &a, &Scalar(*top_half));
|
2016-12-01 00:40:48 +00:00
|
|
|
|
2017-10-05 07:03:35 +00:00
|
|
|
slices_equal(bottom_half, &r.compress().to_bytes()) == 1
|
2016-12-01 00:40:48 +00:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// An ed25519 keypair.
|
|
|
|
|
#[derive(Debug)]
|
2017-08-01 03:35:38 +00:00
|
|
|
#[repr(C)]
|
2016-12-01 00:40:48 +00:00
|
|
|
pub struct Keypair {
|
|
|
|
|
/// The public half of this keypair.
|
|
|
|
|
pub public: PublicKey,
|
|
|
|
|
/// The secret half of this keypair.
|
|
|
|
|
pub secret: SecretKey,
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
impl Keypair {
|
2017-08-01 03:35:38 +00:00
|
|
|
/// Construct a `Keypair` from the bytes of a `PublicKey` and `SecretKey`.
|
|
|
|
|
///
|
|
|
|
|
/// # Inputs
|
|
|
|
|
///
|
|
|
|
|
/// * `public`: a `[u8; 32]` representing the compressed Edwards-Y
|
|
|
|
|
/// coordinate of a point on curve25519.
|
|
|
|
|
/// * `secret`: a `[u8; 32]` representing the corresponding secret key.
|
|
|
|
|
///
|
|
|
|
|
/// # Warning
|
|
|
|
|
///
|
|
|
|
|
/// Absolutely no validation is done on the key. If you give this function
|
|
|
|
|
/// bytes which do not represent a valid point, or which do not represent
|
|
|
|
|
/// corresponding parts of the key, then your `Keypair` will be broken and
|
|
|
|
|
/// it will be your fault.
|
|
|
|
|
///
|
|
|
|
|
/// # Returns
|
|
|
|
|
///
|
|
|
|
|
/// A `Keypair`.
|
|
|
|
|
pub fn from_bytes<'a>(public: &'a [u8; 32], secret: &'a [u8; 32]) -> Keypair {
|
|
|
|
|
Keypair{ public: PublicKey::from_bytes(public),
|
|
|
|
|
secret: SecretKey::from_bytes(secret), }
|
|
|
|
|
}
|
|
|
|
|
|
2016-12-01 00:40:48 +00:00
|
|
|
/// Generate an ed25519 keypair.
|
|
|
|
|
///
|
2017-03-14 21:36:35 +00:00
|
|
|
/// # Example
|
|
|
|
|
///
|
|
|
|
|
/// ```
|
|
|
|
|
/// extern crate rand;
|
|
|
|
|
/// extern crate sha2;
|
2017-03-14 21:50:17 +00:00
|
|
|
/// extern crate ed25519_dalek;
|
2017-03-14 21:36:35 +00:00
|
|
|
///
|
|
|
|
|
/// # fn main() {
|
|
|
|
|
///
|
|
|
|
|
/// use rand::Rng;
|
|
|
|
|
/// use rand::OsRng;
|
|
|
|
|
/// use sha2::Sha512;
|
2017-03-14 21:50:17 +00:00
|
|
|
/// use ed25519_dalek::Keypair;
|
|
|
|
|
/// use ed25519_dalek::Signature;
|
2017-03-14 21:36:35 +00:00
|
|
|
///
|
|
|
|
|
/// let mut cspring: OsRng = OsRng::new().unwrap();
|
|
|
|
|
/// let keypair: Keypair = Keypair::generate::<Sha512>(&mut cspring);
|
|
|
|
|
///
|
|
|
|
|
/// # }
|
|
|
|
|
/// ```
|
|
|
|
|
///
|
2016-12-01 00:40:48 +00:00
|
|
|
/// # Input
|
|
|
|
|
///
|
2017-08-01 03:35:38 +00:00
|
|
|
/// A CSPRNG with a `fill_bytes()` method, e.g. the one returned
|
2016-12-01 00:40:48 +00:00
|
|
|
/// from `rand::OsRng::new()` (in the `rand` crate).
|
2017-03-14 21:36:35 +00:00
|
|
|
///
|
|
|
|
|
/// 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.
|
2017-02-06 21:45:08 +00:00
|
|
|
#[cfg(feature = "std")]
|
2017-08-01 03:35:38 +00:00
|
|
|
pub fn generate<D>(csprng: &mut Rng) -> Keypair
|
2017-08-01 06:52:10 +00:00
|
|
|
where D: Digest<OutputSize = U64> + Default {
|
2017-08-01 03:35:38 +00:00
|
|
|
let sk: SecretKey = SecretKey::generate(csprng);
|
|
|
|
|
let pk: PublicKey = PublicKey::from_secret::<D>(&sk);
|
2017-03-14 21:36:35 +00:00
|
|
|
|
2017-08-01 03:35:38 +00:00
|
|
|
Keypair{ public: pk, secret: sk }
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// Sign a message with this keypair's secret key.
|
|
|
|
|
pub fn sign<D>(&self, message: &[u8]) -> Signature
|
2017-08-01 06:52:10 +00:00
|
|
|
where D: Digest<OutputSize = U64> + Default {
|
2017-08-01 03:35:38 +00:00
|
|
|
|
|
|
|
|
let mut h: D = D::default();
|
2016-12-01 00:40:48 +00:00
|
|
|
let mut hash: [u8; 64] = [0u8; 64];
|
2017-08-01 03:35:38 +00:00
|
|
|
let mut signature_bytes: [u8; 64] = [0u8; SIGNATURE_LENGTH];
|
|
|
|
|
let mut expanded_key_secret: Scalar;
|
|
|
|
|
let mesg_digest: Scalar;
|
|
|
|
|
let hram_digest: Scalar;
|
|
|
|
|
let r: ExtendedPoint;
|
|
|
|
|
let s: Scalar;
|
|
|
|
|
let t: CompressedEdwardsY;
|
2016-12-01 00:40:48 +00:00
|
|
|
|
2017-08-01 03:35:38 +00:00
|
|
|
let secret_key: &[u8; 32] = self.secret.as_bytes();
|
|
|
|
|
let public_key: &[u8; 32] = self.public.as_bytes();
|
2016-12-01 00:40:48 +00:00
|
|
|
|
2017-08-01 06:52:10 +00:00
|
|
|
h.input(secret_key);
|
2017-05-08 07:54:56 +00:00
|
|
|
hash.copy_from_slice(h.fixed_result().as_slice());
|
2016-12-01 00:40:48 +00:00
|
|
|
|
2017-08-01 03:35:38 +00:00
|
|
|
expanded_key_secret = Scalar(*array_ref!(&hash, 0, 32));
|
|
|
|
|
expanded_key_secret[0] &= 248;
|
|
|
|
|
expanded_key_secret[31] &= 63;
|
|
|
|
|
expanded_key_secret[31] |= 64;
|
2016-12-01 00:40:48 +00:00
|
|
|
|
2017-08-01 03:35:38 +00:00
|
|
|
h = D::default();
|
2017-08-01 06:52:10 +00:00
|
|
|
h.input(&hash[32..]);
|
|
|
|
|
h.input(&message);
|
2017-08-01 03:35:38 +00:00
|
|
|
hash.copy_from_slice(h.fixed_result().as_slice());
|
2016-12-01 00:40:48 +00:00
|
|
|
|
2017-08-01 03:35:38 +00:00
|
|
|
mesg_digest = Scalar::reduce(&hash);
|
2016-12-01 00:40:48 +00:00
|
|
|
|
2017-08-15 05:30:53 +00:00
|
|
|
r = &mesg_digest * &constants::ED25519_BASEPOINT_TABLE;
|
2016-12-01 00:40:48 +00:00
|
|
|
|
2017-08-01 03:35:38 +00:00
|
|
|
h = D::default();
|
2017-10-05 07:03:35 +00:00
|
|
|
h.input(&r.compress().to_bytes()[..]);
|
2017-08-01 06:52:10 +00:00
|
|
|
h.input(public_key);
|
|
|
|
|
h.input(&message);
|
2017-08-01 03:35:38 +00:00
|
|
|
hash.copy_from_slice(h.fixed_result().as_slice());
|
|
|
|
|
|
|
|
|
|
hram_digest = Scalar::reduce(&hash);
|
|
|
|
|
|
|
|
|
|
s = Scalar::multiply_add(&hram_digest, &expanded_key_secret, &mesg_digest);
|
2017-10-05 07:03:35 +00:00
|
|
|
t = r.compress();
|
2017-08-01 03:35:38 +00:00
|
|
|
|
|
|
|
|
signature_bytes[..32].copy_from_slice(&t.0);
|
|
|
|
|
signature_bytes[32..64].copy_from_slice(&s.0);
|
|
|
|
|
Signature(*array_ref!(&signature_bytes, 0, 64))
|
2016-12-01 00:40:48 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// Verify a signature on a message with this keypair's public key.
|
2017-03-14 23:43:02 +00:00
|
|
|
pub fn verify<D>(&self, message: &[u8], signature: &Signature) -> bool
|
2017-08-01 06:52:10 +00:00
|
|
|
where D: FixedOutput<OutputSize = U64> + BlockInput + Default + Input {
|
2017-03-14 23:43:02 +00:00
|
|
|
self.public.verify::<D>(message, signature)
|
2016-12-01 00:40:48 +00:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#[cfg(test)]
|
|
|
|
|
mod test {
|
2016-12-09 00:52:38 +00:00
|
|
|
use std::io::BufReader;
|
|
|
|
|
use std::io::BufRead;
|
|
|
|
|
use std::fs::File;
|
2017-02-06 21:45:08 +00:00
|
|
|
use std::string::String;
|
|
|
|
|
use std::vec::Vec;
|
2017-08-15 05:30:53 +00:00
|
|
|
use curve25519_dalek::edwards::ExtendedPoint;
|
2016-12-01 00:40:48 +00:00
|
|
|
use rand::OsRng;
|
2017-06-23 22:42:58 +00:00
|
|
|
use hex::FromHex;
|
2017-03-15 19:01:03 +00:00
|
|
|
use sha2::Sha512;
|
2016-12-01 00:40:48 +00:00
|
|
|
use super::*;
|
|
|
|
|
|
|
|
|
|
#[test]
|
2017-03-14 23:19:38 +00:00
|
|
|
fn unmarshal_marshal() { // TestUnmarshalMarshal
|
2016-12-01 00:40:48 +00:00
|
|
|
let mut cspring: OsRng;
|
|
|
|
|
let mut keypair: Keypair;
|
|
|
|
|
let mut x: Option<ExtendedPoint>;
|
|
|
|
|
let a: ExtendedPoint;
|
|
|
|
|
let public: PublicKey;
|
|
|
|
|
|
|
|
|
|
cspring = OsRng::new().unwrap();
|
|
|
|
|
|
|
|
|
|
// from_bytes() fails if vx²-u=0 and vx²+u=0
|
|
|
|
|
loop {
|
2017-03-14 21:36:35 +00:00
|
|
|
keypair = Keypair::generate::<Sha512>(&mut cspring);
|
2016-12-01 00:40:48 +00:00
|
|
|
x = keypair.public.decompress();
|
|
|
|
|
|
|
|
|
|
if x.is_some() {
|
|
|
|
|
a = x.unwrap();
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
2017-10-05 07:03:35 +00:00
|
|
|
public = PublicKey(a.compress());
|
2016-12-01 00:40:48 +00:00
|
|
|
|
|
|
|
|
assert!(keypair.public.0 == public.0);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#[test]
|
2017-03-14 23:19:38 +00:00
|
|
|
fn sign_verify() { // TestSignVerify
|
2016-12-01 00:40:48 +00:00
|
|
|
let mut cspring: OsRng;
|
|
|
|
|
let keypair: Keypair;
|
|
|
|
|
let good_sig: Signature;
|
|
|
|
|
let bad_sig: Signature;
|
|
|
|
|
|
|
|
|
|
let good: &[u8] = "test message".as_bytes();
|
|
|
|
|
let bad: &[u8] = "wrong message".as_bytes();
|
|
|
|
|
|
|
|
|
|
cspring = OsRng::new().unwrap();
|
2017-03-14 21:36:35 +00:00
|
|
|
keypair = Keypair::generate::<Sha512>(&mut cspring);
|
2017-03-14 23:54:43 +00:00
|
|
|
good_sig = keypair.sign::<Sha512>(&good);
|
|
|
|
|
bad_sig = keypair.sign::<Sha512>(&bad);
|
2016-12-01 00:40:48 +00:00
|
|
|
|
2017-03-14 23:43:02 +00:00
|
|
|
assert!(keypair.verify::<Sha512>(&good, &good_sig) == true,
|
2016-12-01 00:40:48 +00:00
|
|
|
"Verification of a valid signature failed!");
|
2017-03-14 23:43:02 +00:00
|
|
|
assert!(keypair.verify::<Sha512>(&good, &bad_sig) == false,
|
2016-12-01 00:40:48 +00:00
|
|
|
"Verification of a signature on a different message passed!");
|
2017-03-14 23:43:02 +00:00
|
|
|
assert!(keypair.verify::<Sha512>(&bad, &good_sig) == false,
|
2016-12-01 00:40:48 +00:00
|
|
|
"Verification of a signature on a different message passed!");
|
|
|
|
|
}
|
|
|
|
|
|
2016-12-09 00:52:38 +00:00
|
|
|
// TESTVECTORS is taken from sign.input.gz in agl's ed25519 Golang
|
|
|
|
|
// package. It is a selection of test cases from
|
|
|
|
|
// http://ed25519.cr.yp.to/python/sign.input
|
|
|
|
|
#[cfg(test)]
|
|
|
|
|
#[cfg(not(release))]
|
|
|
|
|
#[test]
|
2017-03-14 23:19:38 +00:00
|
|
|
fn golden() { // TestGolden
|
2016-12-09 00:52:38 +00:00
|
|
|
let mut line: String;
|
|
|
|
|
let mut lineno: usize = 0;
|
|
|
|
|
|
|
|
|
|
let f = File::open("TESTVECTORS");
|
|
|
|
|
if f.is_err() {
|
|
|
|
|
println!("This test is only available when the code has been cloned \
|
|
|
|
|
from the git repository, since the TESTVECTORS file is large \
|
|
|
|
|
and is therefore not included within the distributed crate.");
|
|
|
|
|
panic!();
|
|
|
|
|
}
|
|
|
|
|
let file = BufReader::new(f.unwrap());
|
|
|
|
|
|
|
|
|
|
for l in file.lines() {
|
|
|
|
|
lineno += 1;
|
|
|
|
|
line = l.unwrap();
|
|
|
|
|
|
|
|
|
|
let parts: Vec<&str> = line.split(':').collect();
|
|
|
|
|
assert_eq!(parts.len(), 5, "wrong number of fields in line {}", lineno);
|
|
|
|
|
|
2017-06-23 22:42:58 +00:00
|
|
|
let sec_bytes: Vec<u8>= FromHex::from_hex(&parts[0]).unwrap();
|
|
|
|
|
let pub_bytes: Vec<u8> = FromHex::from_hex(&parts[1]).unwrap();
|
|
|
|
|
let message: Vec<u8> = FromHex::from_hex(&parts[2]).unwrap();
|
|
|
|
|
let sig_bytes: Vec<u8> = FromHex::from_hex(&parts[3]).unwrap();
|
2016-12-09 00:52:38 +00:00
|
|
|
|
|
|
|
|
// The signatures in the test vectors also include the message
|
|
|
|
|
// at the end, but we just want R and S.
|
2017-06-23 22:42:58 +00:00
|
|
|
let sig1: Signature = Signature::from_bytes(sig_bytes.as_ref());
|
2016-12-09 00:52:38 +00:00
|
|
|
|
2017-08-01 03:35:38 +00:00
|
|
|
let keypair: Keypair = Keypair::from_bytes(
|
|
|
|
|
array_ref!(*pub_bytes, 0, PUBLIC_KEY_LENGTH),
|
|
|
|
|
array_ref!(*sec_bytes, 0, SECRET_KEY_LENGTH));
|
2016-12-09 00:52:38 +00:00
|
|
|
|
2017-08-01 03:35:38 +00:00
|
|
|
let sig2: Signature = keypair.sign::<Sha512>(&message);
|
2016-12-09 00:52:38 +00:00
|
|
|
|
|
|
|
|
assert!(sig1 == sig2, "Signature bytes not equal on line {}", lineno);
|
2017-08-01 03:35:38 +00:00
|
|
|
assert!(keypair.verify::<Sha512>(&message, &sig2),
|
2017-03-14 23:43:02 +00:00
|
|
|
"Signature verification failed on line {}", lineno);
|
2016-12-09 00:52:38 +00:00
|
|
|
}
|
|
|
|
|
}
|
2017-03-14 21:37:46 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#[cfg(all(test, feature = "bench"))]
|
|
|
|
|
mod bench {
|
|
|
|
|
use test::Bencher;
|
|
|
|
|
use rand::OsRng;
|
2017-03-15 19:01:03 +00:00
|
|
|
use sha2::Sha512;
|
2017-03-14 21:37:46 +00:00
|
|
|
use super::*;
|
|
|
|
|
|
|
|
|
|
/// A fake RNG which simply returns zeroes.
|
2017-03-14 23:43:50 +00:00
|
|
|
struct ZeroRng;
|
2017-03-14 21:37:46 +00:00
|
|
|
|
|
|
|
|
impl ZeroRng {
|
|
|
|
|
pub fn new() -> ZeroRng {
|
|
|
|
|
ZeroRng
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
impl Rng for ZeroRng {
|
|
|
|
|
fn next_u32(&mut self) -> u32 { 0u32 }
|
|
|
|
|
|
|
|
|
|
fn fill_bytes(&mut self, bytes: &mut [u8]) {
|
|
|
|
|
for i in 0 .. bytes.len() {
|
|
|
|
|
bytes[i] = 0;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
2016-12-09 00:52:38 +00:00
|
|
|
|
2016-12-01 00:40:48 +00:00
|
|
|
#[bench]
|
2017-03-14 21:37:46 +00:00
|
|
|
fn sign(b: &mut Bencher) {
|
2016-12-01 00:40:48 +00:00
|
|
|
let mut cspring: OsRng = OsRng::new().unwrap();
|
2017-03-14 21:36:35 +00:00
|
|
|
let keypair: Keypair = Keypair::generate::<Sha512>(&mut cspring);
|
2017-03-15 22:34:06 +00:00
|
|
|
let msg: &[u8] = b"";
|
2016-12-01 00:40:48 +00:00
|
|
|
|
2017-03-14 23:54:43 +00:00
|
|
|
b.iter(| | keypair.sign::<Sha512>(msg));
|
2016-12-01 00:40:48 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#[bench]
|
2017-03-14 21:37:46 +00:00
|
|
|
fn verify(b: &mut Bencher) {
|
2016-12-01 00:40:48 +00:00
|
|
|
let mut cspring: OsRng = OsRng::new().unwrap();
|
2017-03-14 21:36:35 +00:00
|
|
|
let keypair: Keypair = Keypair::generate::<Sha512>(&mut cspring);
|
2017-03-15 22:34:06 +00:00
|
|
|
let msg: &[u8] = b"";
|
2017-03-14 23:54:43 +00:00
|
|
|
let sig: Signature = keypair.sign::<Sha512>(msg);
|
2016-12-01 00:40:48 +00:00
|
|
|
|
2017-03-14 23:43:02 +00:00
|
|
|
b.iter(| | keypair.verify::<Sha512>(msg, &sig));
|
2016-12-01 00:40:48 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#[bench]
|
2017-03-14 21:37:46 +00:00
|
|
|
fn key_generation(b: &mut Bencher) {
|
2016-12-01 00:40:48 +00:00
|
|
|
let mut rng: ZeroRng = ZeroRng::new();
|
|
|
|
|
|
2017-03-14 21:36:35 +00:00
|
|
|
b.iter(| | Keypair::generate::<Sha512>(&mut rng));
|
2016-12-01 00:40:48 +00:00
|
|
|
}
|
2017-08-16 04:19:04 +00:00
|
|
|
|
|
|
|
|
#[bench]
|
|
|
|
|
fn underlying_scalar_mult_basepoint(b: &mut Bencher) {
|
|
|
|
|
use curve25519_dalek::constants::ED25519_BASEPOINT_TABLE;
|
|
|
|
|
|
|
|
|
|
let scalar: Scalar = Scalar([ 20, 130, 129, 196, 247, 182, 211, 102,
|
|
|
|
|
11, 168, 169, 131, 159, 69, 126, 35,
|
|
|
|
|
109, 193, 175, 54, 118, 234, 138, 81,
|
|
|
|
|
60, 183, 80, 186, 92, 248, 132, 13, ]);
|
|
|
|
|
|
|
|
|
|
b.iter(| | &scalar * &ED25519_BASEPOINT_TABLE);
|
|
|
|
|
}
|
2016-12-01 00:40:48 +00:00
|
|
|
}
|