From 02a5ce20ca900335c03f04b2a3a59eb84bebccc2 Mon Sep 17 00:00:00 2001 From: "pinkforest(she/her)" <36498018+pinkforest@users.noreply.github.com> Date: Tue, 21 Mar 2023 16:40:51 +1100 Subject: [PATCH] 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 --- Cargo.toml | 1 + README.md | 8 +++--- benches/x25519.rs | 4 +-- src/lib.rs | 18 ++++++------- src/x25519.rs | 59 ++++++++++++++++++++++++++++++++++++++----- tests/x25519_tests.rs | 50 ++++++++++++++++++++++++++++++++++++ 6 files changed, 117 insertions(+), 23 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index ac8be66..46e048c 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -54,6 +54,7 @@ harness = false [features] default = ["alloc", "precomputed-tables", "zeroize"] +getrandom = ["rand_core/getrandom"] zeroize = ["dep:zeroize", "curve25519-dalek/zeroize"] serde = ["dep:serde", "curve25519-dalek/serde"] alloc = ["curve25519-dalek/alloc", "serde?/alloc", "zeroize?/alloc"] diff --git a/README.md b/README.md index 7145f06..6bc217d 100644 --- a/README.md +++ b/README.md @@ -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 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: ```rust -use rand_core::OsRng; use x25519_dalek::{EphemeralSecret, PublicKey}; -let alice_secret = EphemeralSecret::new(OsRng); +let alice_secret = EphemeralSecret::random(); let alice_public = PublicKey::from(&alice_secret); ``` Bob does the same: ```rust -# use rand_core::OsRng; # use x25519_dalek::{EphemeralSecret, PublicKey}; -let bob_secret = EphemeralSecret::new(OsRng); +let bob_secret = EphemeralSecret::random(); let bob_public = PublicKey::from(&bob_secret); ``` diff --git a/benches/x25519.rs b/benches/x25519.rs index dfcee4a..77c832d 100644 --- a/benches/x25519.rs +++ b/benches/x25519.rs @@ -19,12 +19,12 @@ use x25519_dalek::EphemeralSecret; use x25519_dalek::PublicKey; 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); c.bench_function("diffie_hellman", move |b| { b.iter_with_setup( - || EphemeralSecret::new(OsRng), + || EphemeralSecret::random_from_rng(OsRng), |alice_secret| alice_secret.diffie_hellman(&bob_public), ) }); diff --git a/src/lib.rs b/src/lib.rs index 01369d0..7bcd8f4 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -50,14 +50,14 @@ //! kittens will be able to secretly organise to find their mittens, and then spend //! 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: //! //! ```rust //! use rand_core::OsRng; //! 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); //! ``` //! @@ -66,7 +66,7 @@ //! ```rust //! # use rand_core::OsRng; //! # 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); //! ``` //! @@ -77,9 +77,9 @@ //! ```rust //! # use rand_core::OsRng; //! # 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 bob_secret = EphemeralSecret::new(OsRng); +//! # let bob_secret = EphemeralSecret::random_from_rng(OsRng); //! # let bob_public = PublicKey::from(&bob_secret); //! let alice_shared_secret = alice_secret.diffie_hellman(&bob_public); //! ``` @@ -89,9 +89,9 @@ //! ```rust //! # use rand_core::OsRng; //! # 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 bob_secret = EphemeralSecret::new(OsRng); +//! # let bob_secret = EphemeralSecret::random_from_rng(OsRng); //! # let bob_public = PublicKey::from(&bob_secret); //! let bob_shared_secret = bob_secret.diffie_hellman(&alice_public); //! ``` @@ -101,9 +101,9 @@ //! ```rust //! # use rand_core::OsRng; //! # 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 bob_secret = EphemeralSecret::new(OsRng); +//! # let bob_secret = EphemeralSecret::random_from_rng(OsRng); //! # let bob_public = PublicKey::from(&bob_secret); //! # let alice_shared_secret = alice_secret.diffie_hellman(&bob_public); //! # let bob_shared_secret = bob_secret.diffie_hellman(&alice_public); diff --git a/src/x25519.rs b/src/x25519.rs index 25831c7..f161243 100644 --- a/src/x25519.rs +++ b/src/x25519.rs @@ -71,8 +71,8 @@ impl AsRef<[u8]> for PublicKey { /// This type is identical to the [`StaticSecret`] type, except that the /// [`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 -/// generated from fresh randomness by [`EphemeralSecret::new`] and the compiler statically checks -/// that the resulting secret is used at most once. +/// generated from fresh randomness where the compiler statically checks that the resulting +/// secret is used at most once. #[cfg_attr(feature = "zeroize", derive(Zeroize))] #[cfg_attr(feature = "zeroize", zeroize(drop))] pub struct EphemeralSecret(pub(crate) Scalar); @@ -84,14 +84,29 @@ impl EphemeralSecret { 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(mut csprng: T) -> Self { + Self::random_from_rng(&mut csprng) + } + + /// Generate a new [`EphemeralSecret`] with the supplied RNG. + pub fn random_from_rng(mut csprng: T) -> Self { let mut bytes = [0u8; 32]; csprng.fill_bytes(&mut 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 { @@ -133,14 +148,29 @@ impl ReusableSecret { 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(mut csprng: T) -> Self { + Self::random_from_rng(&mut csprng) + } + + /// Generate a new [`ReusableSecret`] with the supplied RNG. + pub fn random_from_rng(mut csprng: T) -> Self { let mut bytes = [0u8; 32]; csprng.fill_bytes(&mut 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")] @@ -180,8 +210,17 @@ impl StaticSecret { 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(mut csprng: T) -> Self { + Self::random_from_rng(&mut csprng) + } + + /// Generate a new [`StaticSecret`] with the supplied RNG. + pub fn random_from_rng(mut csprng: T) -> Self { let mut bytes = [0u8; 32]; csprng.fill_bytes(&mut bytes); @@ -189,6 +228,12 @@ impl StaticSecret { 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. #[inline] pub fn to_bytes(&self) -> [u8; 32] { @@ -307,11 +352,11 @@ impl AsRef<[u8]> for SharedSecret { /// use x25519_dalek::PublicKey; /// /// // 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); /// /// // 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); /// /// // Alice and Bob should now exchange their public keys. diff --git a/tests/x25519_tests.rs b/tests/x25519_tests.rs index 21eeb43..280978d 100644 --- a/tests/x25519_tests.rs +++ b/tests/x25519_tests.rs @@ -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(); + } +}