From ddc9e92d9217d665615fcd1424d219fdb97cb020 Mon Sep 17 00:00:00 2001 From: Will Song Date: Wed, 17 Apr 2024 12:25:35 -0400 Subject: [PATCH 1/2] add kem traits --- Cargo.lock | 11 ++++++++ elliptic-curve/Cargo.toml | 2 ++ elliptic-curve/src/ecdh_kem.rs | 50 ++++++++++++++++++++++++++++++++++ elliptic-curve/src/lib.rs | 2 ++ 4 files changed, 65 insertions(+) create mode 100644 elliptic-curve/src/ecdh_kem.rs diff --git a/Cargo.lock b/Cargo.lock index 1cf9a41f1..8b271acb7 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -552,6 +552,7 @@ dependencies = [ "hex-literal", "hkdf 0.13.0-pre.3", "hybrid-array", + "kem 0.3.0-pre.0 (registry+https://github.com/rust-lang/crates.io-index)", "pem-rfc7468 1.0.0-pre.0", "pkcs8 0.11.0-pre.0", "rand_core 0.6.4", @@ -844,6 +845,16 @@ dependencies = [ "zeroize", ] +[[package]] +name = "kem" +version = "0.3.0-pre.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2b8645470337db67b01a7f966decf7d0bafedbae74147d33e641c67a91df239f" +dependencies = [ + "rand_core 0.6.4", + "zeroize", +] + [[package]] name = "libc" version = "0.2.153" diff --git a/elliptic-curve/Cargo.toml b/elliptic-curve/Cargo.toml index 388c12a1a..641469e7b 100644 --- a/elliptic-curve/Cargo.toml +++ b/elliptic-curve/Cargo.toml @@ -19,6 +19,7 @@ rust-version = "1.73" base16ct = "0.2" crypto-bigint = { version = "=0.6.0-pre.12", default-features = false, features = ["rand_core", "hybrid-array", "zeroize"] } hybrid-array = { version = "0.2.0-rc.8", default-features = false, features = ["zeroize"] } +kem = { version = "=0.3.0-pre.0", optional = true } rand_core = { version = "0.6.4", default-features = false } subtle = { version = "2", default-features = false } zeroize = { version = "1.7", default-features = false } @@ -64,6 +65,7 @@ bits = ["arithmetic", "ff/bits", "dep:tap"] dev = ["arithmetic", "dep:hex-literal", "pem", "pkcs8"] hash2curve = ["arithmetic", "digest"] ecdh = ["arithmetic", "digest", "dep:hkdf"] +ecdh-kem = ["ecdh", "kem"] group = ["dep:group", "ff"] hazmat = [] jwk = ["dep:base64ct", "dep:serde_json", "alloc", "serde", "zeroize/alloc"] diff --git a/elliptic-curve/src/ecdh_kem.rs b/elliptic-curve/src/ecdh_kem.rs new file mode 100644 index 000000000..dcc3f175e --- /dev/null +++ b/elliptic-curve/src/ecdh_kem.rs @@ -0,0 +1,50 @@ +//! # ECDH as a KEM +//! +//! This module turns the existing ECDH implementation into a suitable KEM by +//! modeling encapsulation of `g^x` as the generation of another ephemeral secret +//! `y`, computing the encapsulated ciphertext as `g^y`, and computing the shared +//! secret `g^xy`. Decapsulation of `x` is modelled as computing the shared secret +//! `g^xy` from `g^y`. +//! +//! # ECDH-KEM Usage +//! +//! ECDH-KEM allows for an unauthenticated key agreement protocol as follows +//! +//! 1. The client generates an [`EphemeralSecret`] value +//! 2. The client sends the corresponding [`PublicKey`] for their secret +//! 3. The server runs [`encapsulate`](Encapsulate::encapsulate) on the given +//! [`PublicKey`] and holds on to the resulting [`SharedSecret`] +//! 4. The client runs [`decapsulate`](Decapsulate::decapsulate) on the +//! "encapsulated" [`PublicKey`] returned by the server and uses the resulting +//! [`SharedSecret`] + +use crate::{CurveArithmetic, PublicKey}; +use crate::ecdh::{EphemeralSecret, SharedSecret}; +use kem::{Decapsulate, Encapsulate}; + +impl Decapsulate, SharedSecret> for EphemeralSecret +where + C: CurveArithmetic, +{ + type Error = (); + + fn decapsulate(&self, encapsulated_key: &PublicKey) -> Result, Self::Error> { + Ok(self.diffie_hellman(encapsulated_key)) + } +} + +impl Encapsulate, SharedSecret> for EphemeralSecret +where + C: CurveArithmetic, +{ + type Error = (); + + fn encapsulate(&self, rng: &mut impl rand_core::CryptoRngCore) -> Result<(PublicKey, SharedSecret), Self::Error> { + // generate another ephemeral ecdh secret + let secret = EphemeralSecret::::random(rng); + let pk = secret.public_key(); + let ss = self.diffie_hellman(&pk); + + Ok((pk, ss)) + } +} diff --git a/elliptic-curve/src/lib.rs b/elliptic-curve/src/lib.rs index 32ce2fa1a..0459b745c 100644 --- a/elliptic-curve/src/lib.rs +++ b/elliptic-curve/src/lib.rs @@ -88,6 +88,8 @@ pub mod scalar; pub mod dev; #[cfg(feature = "ecdh")] pub mod ecdh; +#[cfg(feature = "ecdh-kem")] +pub mod ecdh_kem; #[cfg(feature = "hash2curve")] pub mod hash2curve; #[cfg(feature = "arithmetic")] From 27f1f2c2b849b513c96dc3762b34af3d5458bf78 Mon Sep 17 00:00:00 2001 From: Will Song Date: Wed, 17 Apr 2024 12:39:02 -0400 Subject: [PATCH 2/2] cargo fmt --- elliptic-curve/src/ecdh_kem.rs | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/elliptic-curve/src/ecdh_kem.rs b/elliptic-curve/src/ecdh_kem.rs index dcc3f175e..9e31dbcac 100644 --- a/elliptic-curve/src/ecdh_kem.rs +++ b/elliptic-curve/src/ecdh_kem.rs @@ -18,8 +18,8 @@ //! "encapsulated" [`PublicKey`] returned by the server and uses the resulting //! [`SharedSecret`] -use crate::{CurveArithmetic, PublicKey}; use crate::ecdh::{EphemeralSecret, SharedSecret}; +use crate::{CurveArithmetic, PublicKey}; use kem::{Decapsulate, Encapsulate}; impl Decapsulate, SharedSecret> for EphemeralSecret @@ -39,7 +39,10 @@ where { type Error = (); - fn encapsulate(&self, rng: &mut impl rand_core::CryptoRngCore) -> Result<(PublicKey, SharedSecret), Self::Error> { + fn encapsulate( + &self, + rng: &mut impl rand_core::CryptoRngCore, + ) -> Result<(PublicKey, SharedSecret), Self::Error> { // generate another ephemeral ecdh secret let secret = EphemeralSecret::::random(rng); let pk = secret.public_key();