Add getrandom (#118)

* Add getrandom to bring convenience random init functions

* Fix doc name

* Rename new to random_from_rng

* Deprecate new() in favor of random_from_rng()

* Simplify constructors documentation

Co-authored-by: Ciprian Dorin Craciun <ciprian@volution.ro>
This commit is contained in:
pinkforest(she/her) 2023-03-21 16:40:51 +11:00 committed by GitHub
parent 6aabb9bf08
commit 02a5ce20ca
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
6 changed files with 117 additions and 23 deletions

View file

@ -54,6 +54,7 @@ harness = false
[features] [features]
default = ["alloc", "precomputed-tables", "zeroize"] default = ["alloc", "precomputed-tables", "zeroize"]
getrandom = ["rand_core/getrandom"]
zeroize = ["dep:zeroize", "curve25519-dalek/zeroize"] zeroize = ["dep:zeroize", "curve25519-dalek/zeroize"]
serde = ["dep:serde", "curve25519-dalek/serde"] serde = ["dep:serde", "curve25519-dalek/serde"]
alloc = ["curve25519-dalek/alloc", "serde?/alloc", "zeroize?/alloc"] alloc = ["curve25519-dalek/alloc", "serde?/alloc", "zeroize?/alloc"]

View file

@ -28,23 +28,21 @@ up on modern public key cryptography and have learned a nifty trick called
kittens will be able to secretly organise to find their mittens, and then spend kittens will be able to secretly organise to find their mittens, and then spend
the rest of the afternoon nomming some yummy pie! the rest of the afternoon nomming some yummy pie!
First, Alice uses `EphemeralSecret::new()` and then First, Alice uses `EphemeralSecret::random()` and then
`PublicKey::from()` to produce her secret and public keys: `PublicKey::from()` to produce her secret and public keys:
```rust ```rust
use rand_core::OsRng;
use x25519_dalek::{EphemeralSecret, PublicKey}; use x25519_dalek::{EphemeralSecret, PublicKey};
let alice_secret = EphemeralSecret::new(OsRng); let alice_secret = EphemeralSecret::random();
let alice_public = PublicKey::from(&alice_secret); let alice_public = PublicKey::from(&alice_secret);
``` ```
Bob does the same: Bob does the same:
```rust ```rust
# use rand_core::OsRng;
# use x25519_dalek::{EphemeralSecret, PublicKey}; # use x25519_dalek::{EphemeralSecret, PublicKey};
let bob_secret = EphemeralSecret::new(OsRng); let bob_secret = EphemeralSecret::random();
let bob_public = PublicKey::from(&bob_secret); let bob_public = PublicKey::from(&bob_secret);
``` ```

View file

@ -19,12 +19,12 @@ use x25519_dalek::EphemeralSecret;
use x25519_dalek::PublicKey; use x25519_dalek::PublicKey;
fn bench_diffie_hellman(c: &mut Criterion) { fn bench_diffie_hellman(c: &mut Criterion) {
let bob_secret = EphemeralSecret::new(OsRng); let bob_secret = EphemeralSecret::random_from_rng(OsRng);
let bob_public = PublicKey::from(&bob_secret); let bob_public = PublicKey::from(&bob_secret);
c.bench_function("diffie_hellman", move |b| { c.bench_function("diffie_hellman", move |b| {
b.iter_with_setup( b.iter_with_setup(
|| EphemeralSecret::new(OsRng), || EphemeralSecret::random_from_rng(OsRng),
|alice_secret| alice_secret.diffie_hellman(&bob_public), |alice_secret| alice_secret.diffie_hellman(&bob_public),
) )
}); });

View file

@ -50,14 +50,14 @@
//! kittens will be able to secretly organise to find their mittens, and then spend //! kittens will be able to secretly organise to find their mittens, and then spend
//! the rest of the afternoon nomming some yummy pie! //! the rest of the afternoon nomming some yummy pie!
//! //!
//! First, Alice uses `EphemeralSecret::new()` and then //! First, Alice uses `EphemeralSecret::random_from_rng` and then
//! `PublicKey::from()` to produce her secret and public keys: //! `PublicKey::from()` to produce her secret and public keys:
//! //!
//! ```rust //! ```rust
//! use rand_core::OsRng; //! use rand_core::OsRng;
//! use x25519_dalek::{EphemeralSecret, PublicKey}; //! use x25519_dalek::{EphemeralSecret, PublicKey};
//! //!
//! let alice_secret = EphemeralSecret::new(OsRng); //! let alice_secret = EphemeralSecret::random_from_rng(OsRng);
//! let alice_public = PublicKey::from(&alice_secret); //! let alice_public = PublicKey::from(&alice_secret);
//! ``` //! ```
//! //!
@ -66,7 +66,7 @@
//! ```rust //! ```rust
//! # use rand_core::OsRng; //! # use rand_core::OsRng;
//! # use x25519_dalek::{EphemeralSecret, PublicKey}; //! # use x25519_dalek::{EphemeralSecret, PublicKey};
//! let bob_secret = EphemeralSecret::new(OsRng); //! let bob_secret = EphemeralSecret::random_from_rng(OsRng);
//! let bob_public = PublicKey::from(&bob_secret); //! let bob_public = PublicKey::from(&bob_secret);
//! ``` //! ```
//! //!
@ -77,9 +77,9 @@
//! ```rust //! ```rust
//! # use rand_core::OsRng; //! # use rand_core::OsRng;
//! # use x25519_dalek::{EphemeralSecret, PublicKey}; //! # use x25519_dalek::{EphemeralSecret, PublicKey};
//! # let alice_secret = EphemeralSecret::new(OsRng); //! # let alice_secret = EphemeralSecret::random_from_rng(OsRng);
//! # let alice_public = PublicKey::from(&alice_secret); //! # let alice_public = PublicKey::from(&alice_secret);
//! # let bob_secret = EphemeralSecret::new(OsRng); //! # let bob_secret = EphemeralSecret::random_from_rng(OsRng);
//! # let bob_public = PublicKey::from(&bob_secret); //! # let bob_public = PublicKey::from(&bob_secret);
//! let alice_shared_secret = alice_secret.diffie_hellman(&bob_public); //! let alice_shared_secret = alice_secret.diffie_hellman(&bob_public);
//! ``` //! ```
@ -89,9 +89,9 @@
//! ```rust //! ```rust
//! # use rand_core::OsRng; //! # use rand_core::OsRng;
//! # use x25519_dalek::{EphemeralSecret, PublicKey}; //! # use x25519_dalek::{EphemeralSecret, PublicKey};
//! # let alice_secret = EphemeralSecret::new(OsRng); //! # let alice_secret = EphemeralSecret::random_from_rng(OsRng);
//! # let alice_public = PublicKey::from(&alice_secret); //! # let alice_public = PublicKey::from(&alice_secret);
//! # let bob_secret = EphemeralSecret::new(OsRng); //! # let bob_secret = EphemeralSecret::random_from_rng(OsRng);
//! # let bob_public = PublicKey::from(&bob_secret); //! # let bob_public = PublicKey::from(&bob_secret);
//! let bob_shared_secret = bob_secret.diffie_hellman(&alice_public); //! let bob_shared_secret = bob_secret.diffie_hellman(&alice_public);
//! ``` //! ```
@ -101,9 +101,9 @@
//! ```rust //! ```rust
//! # use rand_core::OsRng; //! # use rand_core::OsRng;
//! # use x25519_dalek::{EphemeralSecret, PublicKey}; //! # use x25519_dalek::{EphemeralSecret, PublicKey};
//! # let alice_secret = EphemeralSecret::new(OsRng); //! # let alice_secret = EphemeralSecret::random_from_rng(OsRng);
//! # let alice_public = PublicKey::from(&alice_secret); //! # let alice_public = PublicKey::from(&alice_secret);
//! # let bob_secret = EphemeralSecret::new(OsRng); //! # let bob_secret = EphemeralSecret::random_from_rng(OsRng);
//! # let bob_public = PublicKey::from(&bob_secret); //! # let bob_public = PublicKey::from(&bob_secret);
//! # let alice_shared_secret = alice_secret.diffie_hellman(&bob_public); //! # let alice_shared_secret = alice_secret.diffie_hellman(&bob_public);
//! # let bob_shared_secret = bob_secret.diffie_hellman(&alice_public); //! # let bob_shared_secret = bob_secret.diffie_hellman(&alice_public);

View file

@ -71,8 +71,8 @@ impl AsRef<[u8]> for PublicKey {
/// This type is identical to the [`StaticSecret`] type, except that the /// This type is identical to the [`StaticSecret`] type, except that the
/// [`EphemeralSecret::diffie_hellman`] method consumes and then wipes the secret key, and there /// [`EphemeralSecret::diffie_hellman`] method consumes and then wipes the secret key, and there
/// are no serialization methods defined. This means that [`EphemeralSecret`]s can only be /// are no serialization methods defined. This means that [`EphemeralSecret`]s can only be
/// generated from fresh randomness by [`EphemeralSecret::new`] and the compiler statically checks /// generated from fresh randomness where the compiler statically checks that the resulting
/// that the resulting secret is used at most once. /// secret is used at most once.
#[cfg_attr(feature = "zeroize", derive(Zeroize))] #[cfg_attr(feature = "zeroize", derive(Zeroize))]
#[cfg_attr(feature = "zeroize", zeroize(drop))] #[cfg_attr(feature = "zeroize", zeroize(drop))]
pub struct EphemeralSecret(pub(crate) Scalar); pub struct EphemeralSecret(pub(crate) Scalar);
@ -84,14 +84,29 @@ impl EphemeralSecret {
SharedSecret(self.0 * their_public.0) SharedSecret(self.0 * their_public.0)
} }
/// Generate an x25519 [`EphemeralSecret`] key. /// Generate a new [`EphemeralSecret`] with the supplied RNG.
#[deprecated(
since = "2.0.0",
note = "Renamed to `random_from_rng`. This will be removed in 2.1.0"
)]
pub fn new<T: RngCore + CryptoRng>(mut csprng: T) -> Self { pub fn new<T: RngCore + CryptoRng>(mut csprng: T) -> Self {
Self::random_from_rng(&mut csprng)
}
/// Generate a new [`EphemeralSecret`] with the supplied RNG.
pub fn random_from_rng<T: RngCore + CryptoRng>(mut csprng: T) -> Self {
let mut bytes = [0u8; 32]; let mut bytes = [0u8; 32];
csprng.fill_bytes(&mut bytes); csprng.fill_bytes(&mut bytes);
EphemeralSecret(Scalar::from_bits_clamped(bytes)) EphemeralSecret(Scalar::from_bits_clamped(bytes))
} }
/// Generate a new [`EphemeralSecret`].
#[cfg(feature = "getrandom")]
pub fn random() -> Self {
Self::random_from_rng(&mut rand_core::OsRng)
}
} }
impl<'a> From<&'a EphemeralSecret> for PublicKey { impl<'a> From<&'a EphemeralSecret> for PublicKey {
@ -133,14 +148,29 @@ impl ReusableSecret {
SharedSecret(self.0 * their_public.0) SharedSecret(self.0 * their_public.0)
} }
/// Generate a non-serializeable x25519 [`ReusableSecret`] key. /// Generate a new [`ReusableSecret`] with the supplied RNG.
#[deprecated(
since = "2.0.0",
note = "Renamed to `random_from_rng`. This will be removed in 2.1.0."
)]
pub fn new<T: RngCore + CryptoRng>(mut csprng: T) -> Self { pub fn new<T: RngCore + CryptoRng>(mut csprng: T) -> Self {
Self::random_from_rng(&mut csprng)
}
/// Generate a new [`ReusableSecret`] with the supplied RNG.
pub fn random_from_rng<T: RngCore + CryptoRng>(mut csprng: T) -> Self {
let mut bytes = [0u8; 32]; let mut bytes = [0u8; 32];
csprng.fill_bytes(&mut bytes); csprng.fill_bytes(&mut bytes);
ReusableSecret(Scalar::from_bits_clamped(bytes)) ReusableSecret(Scalar::from_bits_clamped(bytes))
} }
/// Generate a new [`ReusableSecret`].
#[cfg(feature = "getrandom")]
pub fn random() -> Self {
Self::random_from_rng(&mut rand_core::OsRng)
}
} }
#[cfg(feature = "reusable_secrets")] #[cfg(feature = "reusable_secrets")]
@ -180,8 +210,17 @@ impl StaticSecret {
SharedSecret(self.0 * their_public.0) SharedSecret(self.0 * their_public.0)
} }
/// Generate an x25519 key. /// Generate a new [`StaticSecret`] with the supplied RNG.
#[deprecated(
since = "2.0.0",
note = "Renamed to `random_from_rng`. This will be removed in 2.1.0"
)]
pub fn new<T: RngCore + CryptoRng>(mut csprng: T) -> Self { pub fn new<T: RngCore + CryptoRng>(mut csprng: T) -> Self {
Self::random_from_rng(&mut csprng)
}
/// Generate a new [`StaticSecret`] with the supplied RNG.
pub fn random_from_rng<T: RngCore + CryptoRng>(mut csprng: T) -> Self {
let mut bytes = [0u8; 32]; let mut bytes = [0u8; 32];
csprng.fill_bytes(&mut bytes); csprng.fill_bytes(&mut bytes);
@ -189,6 +228,12 @@ impl StaticSecret {
StaticSecret(Scalar::from_bits_clamped(bytes)) StaticSecret(Scalar::from_bits_clamped(bytes))
} }
/// Generate a new [`StaticSecret`].
#[cfg(feature = "getrandom")]
pub fn random() -> Self {
Self::random_from_rng(&mut rand_core::OsRng)
}
/// Extract this key's bytes for serialization. /// Extract this key's bytes for serialization.
#[inline] #[inline]
pub fn to_bytes(&self) -> [u8; 32] { pub fn to_bytes(&self) -> [u8; 32] {
@ -307,11 +352,11 @@ impl AsRef<[u8]> for SharedSecret {
/// use x25519_dalek::PublicKey; /// use x25519_dalek::PublicKey;
/// ///
/// // Generate Alice's key pair. /// // Generate Alice's key pair.
/// let alice_secret = StaticSecret::new(&mut OsRng); /// let alice_secret = StaticSecret::random_from_rng(&mut OsRng);
/// let alice_public = PublicKey::from(&alice_secret); /// let alice_public = PublicKey::from(&alice_secret);
/// ///
/// // Generate Bob's key pair. /// // Generate Bob's key pair.
/// let bob_secret = StaticSecret::new(&mut OsRng); /// let bob_secret = StaticSecret::random_from_rng(&mut OsRng);
/// let bob_public = PublicKey::from(&bob_secret); /// let bob_public = PublicKey::from(&bob_secret);
/// ///
/// // Alice and Bob should now exchange their public keys. /// // Alice and Bob should now exchange their public keys.

View file

@ -180,3 +180,53 @@ fn rfc7748_ladder_test2() {
] ]
); );
} }
mod rand_core {
use super::*;
use ::rand_core::OsRng;
#[test]
fn ephemeral_from_rng() {
#[allow(deprecated)]
EphemeralSecret::new(OsRng);
EphemeralSecret::random_from_rng(OsRng);
}
#[test]
#[cfg(feature = "reusable_secrets")]
fn reusable_from_rng() {
#[allow(deprecated)]
ReusableSecret::new(OsRng);
ReusableSecret::random_from_rng(OsRng);
}
#[test]
fn static_from_rng() {
#[allow(deprecated)]
StaticSecret::new(OsRng);
StaticSecret::random_from_rng(OsRng);
}
}
#[cfg(feature = "getrandom")]
mod getrandom {
use super::*;
#[test]
fn ephemeral_random() {
EphemeralSecret::random();
}
#[test]
#[cfg(feature = "reusable_secrets")]
fn reusable_random() {
ReusableSecret::random();
}
#[test]
fn static_random() {
StaticSecret::random();
}
}