diff --git a/README.md b/README.md index cbf6a33..3d84aa7 100644 --- a/README.md +++ b/README.md @@ -25,8 +25,8 @@ 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 `x25519_dalek::Ephemeral::generate_secret()` and then -`x25519_dalek::Ephemeral::generate_public()` to produce her secret and public keys: +First, Alice uses `x25519_dalek::EphemeralSecret::new()` and then +`x25519_dalek::EphemeralPublic::generate_public()` to produce her secret and public keys: ```rust extern crate x25519_dalek; @@ -36,16 +36,16 @@ use x25519_dalek::Ephemeral; use rand::OsRng; let mut alice_csprng = OsRng::new().unwrap(); -let alice_secret = Ephemeral::generate_secret(&mut alice_csprng); -let alice_public = Ephemeral::generate_public(&alice_secret); +let alice_secret = EphemeralSecret::new(&mut alice_csprng); +let alice_public = EphemeralPublic::generate_public(&alice_secret); ``` Bob does the same: ```rust let mut bob_csprng = OsRng::new().unwrap(); -let bob_secret = Ephemeral::generate_secret(&mut bob_csprng); -let bob_public = Ephemeral::generate_public(&bob_secret); +let bob_secret = EphemeralSecret::new(&mut bob_csprng); +let bob_public = EphemeralPublic::generate_public(&bob_secret); ``` Alice meows across the room, telling `alice_public` to Bob, and Bob diff --git a/benches/x25519.rs b/benches/x25519.rs index 76cc00b..69bcda7 100644 --- a/benches/x25519.rs +++ b/benches/x25519.rs @@ -21,17 +21,18 @@ use curve25519_dalek::montgomery::MontgomeryPoint; use rand::OsRng; -use x25519_dalek::Ephemeral; +use x25519_dalek::EphemeralPublic; +use x25519_dalek::EphemeralSecret; fn bench_diffie_hellman(c: &mut Criterion) { let mut csprng: OsRng = OsRng::new().unwrap(); - let alice_secret: Ephemeral = Ephemeral::generate_secret(&mut csprng); - let bob_secret: Ephemeral = Ephemeral::generate_secret(&mut csprng); - let bob_public: MontgomeryPoint = Ephemeral::generate_public(&bob_secret); + let alice_secret: EphemeralSecret = EphemeralSecret::new(&mut csprng); + let bob_secret: EphemeralSecret = EphemeralSecret::new(&mut csprng); + let bob_public: EphemeralPublic = EphemeralPublic::from(&bob_secret); c.bench_function("diffie_hellman", move |b| { b.iter(|| - Ephemeral::diffie_hellman(&alice_secret, &bob_public) + EphemeralSecret::diffie_hellman(&alice_secret, &bob_public) ) }); } diff --git a/src/lib.rs b/src/lib.rs index 0c82e2b..cd34301 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -32,20 +32,21 @@ //! incantations, the 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 `x25519_dalek::Ephemeral::generate_secret()` and -//! `x25519_dalek::Ephemeral::generate_public()` to produce her secret and public keys: +//! First, Alice uses `x25519_dalek::EphemeralSecret::new()` and +//! `x25519_dalek::EphemeralPublic::from()` to produce her secret and public keys: //! //! ``` //! extern crate x25519_dalek; //! extern crate rand; //! //! # fn main() { -//! use x25519_dalek::Ephemeral; +//! use x25519_dalek::EphemeralPublic; +//! use x25519_dalek::EphemeralSecret; //! use rand::thread_rng; //! //! let mut alice_csprng = thread_rng(); -//! let alice_secret = Ephemeral::generate_secret(&mut alice_csprng); -//! let alice_public = Ephemeral::generate_public(&alice_secret); +//! let alice_secret = EphemeralSecret::new(&mut alice_csprng); +//! let alice_public = EphemeralPublic::from(&alice_secret); //! # } //! ``` //! @@ -56,12 +57,13 @@ //! # extern crate rand; //! # //! # fn main() { -//! # use x25519_dalek::Ephemeral; +//! # use x25519_dalek::EphemeralPublic; +//! # use x25519_dalek::EphemeralSecret; //! # use rand::thread_rng; //! # //! let mut bob_csprng = thread_rng(); -//! let bob_secret = Ephemeral::generate_secret(&mut bob_csprng); -//! let bob_public = Ephemeral::generate_public(&bob_secret); +//! let bob_secret = EphemeralSecret::new(&mut bob_csprng); +//! let bob_public = EphemeralPublic::from(&bob_secret); //! # } //! ``` //! @@ -74,19 +76,20 @@ //! # extern crate rand; //! # //! # fn main() { -//! # use x25519_dalek::Ephemeral; +//! # use x25519_dalek::EphemeralPublic; +//! # use x25519_dalek::EphemeralSecret; //! # use rand::thread_rng; //! # //! # let mut alice_csprng = thread_rng(); -//! # let alice_secret = Ephemeral::generate_secret(&mut alice_csprng); -//! # let alice_public = Ephemeral::generate_public(&alice_secret); +//! # let alice_secret = EphemeralSecret::new(&mut alice_csprng); +//! # let alice_public = EphemeralPublic::from(&alice_secret); //! # //! # let mut bob_csprng = thread_rng(); -//! # let bob_secret = Ephemeral::generate_secret(&mut bob_csprng); -//! # let bob_public = Ephemeral::generate_public(&bob_secret); +//! # let bob_secret = EphemeralSecret::new(&mut bob_csprng); +//! # let bob_public = EphemeralPublic::from(&bob_secret); //! # //! -//! let shared_secret = Ephemeral::diffie_hellman(&alice_secret, &bob_public); +//! let shared_secret = EphemeralSecret::diffie_hellman(&alice_secret, &bob_public); //! # } //! ``` //! @@ -97,18 +100,19 @@ //! # extern crate rand; //! # //! # fn main() { -//! # use x25519_dalek::Ephemeral; +//! # use x25519_dalek::EphemeralPublic; +//! # use x25519_dalek::EphemeralSecret; //! # use rand::thread_rng; //! # //! # let mut alice_csprng = thread_rng(); -//! # let alice_secret = Ephemeral::generate_secret(&mut alice_csprng); -//! # let alice_public = Ephemeral::generate_public(&alice_secret); +//! # let alice_secret = EphemeralSecret::new(&mut alice_csprng); +//! # let alice_public = EphemeralPublic::from(&alice_secret); //! # //! # let mut bob_csprng = thread_rng(); -//! # let bob_secret = Ephemeral::generate_secret(&mut bob_csprng); -//! # let bob_public = Ephemeral::generate_public(&bob_secret); +//! # let bob_secret = EphemeralSecret::new(&mut bob_csprng); +//! # let bob_public = EphemeralPublic::from(&bob_secret); //! # -//! let shared_secret = Ephemeral::diffie_hellman(&bob_secret, &alice_public); +//! let shared_secret = EphemeralSecret::diffie_hellman(&bob_secret, &alice_public); //! # } //! ``` //! diff --git a/src/x25519.rs b/src/x25519.rs index 6817c09..87cc187 100644 --- a/src/x25519.rs +++ b/src/x25519.rs @@ -23,61 +23,57 @@ use curve25519_dalek::scalar::Scalar; use rand_core::RngCore; use rand_core::CryptoRng; -/// A DH ephemeral key. +/// A DH ephemeral public key. +#[repr(C)] +pub struct EphemeralPublic(pub (crate) MontgomeryPoint); + +/// A DH ephemeral secret key. #[repr(C)] #[derive(Default)] // we derive Default in order to use the clear() method in Drop -pub struct Ephemeral(pub (crate) Scalar); +pub struct EphemeralSecret(pub (crate) Scalar); -/// Overwrite ephemeral key material with null bytes when it goes out of scope. -impl Drop for Ephemeral { +/// Overwrite ephemeral secret key material with null bytes when it goes out of scope. +impl Drop for EphemeralSecret { fn drop(&mut self) { self.0.clear(); } } -/// Multiply this `Ephemeral` key by a `MontgomeryPoint`. -impl<'a, 'b> Mul<&'b MontgomeryPoint> for &'a Ephemeral { - type Output = Ephemeral; +/// Multiply this `EphemeralPublic` key by a `EphemeralSecret` key. +impl<'a, 'b> Mul<&'b EphemeralSecret> for &'a EphemeralPublic { + type Output = EphemeralPublic; - fn mul(self, point: &'b MontgomeryPoint) -> Ephemeral { - Ephemeral(Scalar::from_bits((point * self.to_bytes()).to_bytes())) + fn mul(self, secret: &'b EphemeralSecret) -> EphemeralPublic { + EphemeralPublic(self.0 * secret.0) } } -impl Ephemeral { - /// Convert this `Ephemeral` key to a `Scalar`. - #[inline] - pub fn to_bytes(&self) -> Scalar { - self.0 - } - - /// View this `Ephemeral` key as a `Scalar`. - #[inline] - pub fn as_bytes<'a>(&'a self) -> &'a Scalar { - &self.0 - } - +impl EphemeralSecret { /// Utility function to make it easier to call `x25519()` with /// an ephemeral secret key and montegomery point as input and /// a shared secret as the output. - pub fn diffie_hellman(&self, their_public: &MontgomeryPoint) -> SharedSecret { - SharedSecret(x25519(self.as_bytes(), &MontgomeryPoint(*their_public.as_bytes()))) + pub fn diffie_hellman(&self, their_public: &EphemeralPublic) -> SharedSecret { + SharedSecret(x25519(&self.0, &MontgomeryPoint(*their_public.0.as_bytes()))) } - /// Generate an x25519 `Ephemeral` secret key. - pub fn generate_secret(csprng: &mut T) -> Self + /// Generate an x25519 `EphemeralSecret` key. + pub fn new(csprng: &mut T) -> Self where T: RngCore + CryptoRng { let mut bytes = [0u8; 32]; csprng.fill_bytes(&mut bytes); - Ephemeral(decode_scalar(&bytes)) + EphemeralSecret(decode_scalar(&bytes)) } - /// Given an x25519 `Ephemeral` secret key, compute its corresponding public key. - pub fn generate_public(&self) -> MontgomeryPoint { - (self.as_bytes() * &ED25519_BASEPOINT_TABLE).to_montgomery() +} + +impl From<&EphemeralSecret> for EphemeralPublic { + /// Given an x25519 `EphemeralSecret` key, compute its corresponding + /// `EphemeralPublic` key. + fn from(secret: &EphemeralSecret) -> EphemeralPublic { + EphemeralPublic((&ED25519_BASEPOINT_TABLE * &secret.0).to_montgomery()) } } @@ -94,6 +90,15 @@ impl Drop for SharedSecret { } } +impl SharedSecret { + + /// View this shared secret key as a byte array. + #[inline] + pub fn as_bytes<'a>(&'a self) -> &'a [u8; 32] { + &self.0.as_bytes() + } +} + /// "Decode" a scalar from a 32-byte array. /// /// By "decode" here, what is really meant is applying key clamping by twiddling