diff --git a/kem/src/lib.rs b/kem/src/lib.rs index cbb57226b..da02d50aa 100644 --- a/kem/src/lib.rs +++ b/kem/src/lib.rs @@ -13,74 +13,82 @@ pub use common::{ }; use common::array::{self, ArraySize}; +use core::fmt::Debug; use core::{array::TryFromSliceError, convert::Infallible}; use rand_core::CryptoRng; #[cfg(feature = "getrandom")] use common::getrandom::{SysRng, rand_core::UnwrapErr}; +/// KEM decryption key (i.e. private key) which can decrypt encrypted shared secret ciphertexts +/// which were encrypted by [`EncapsulationKey`]. +pub type DecapsulationKey = ::DecapsulationKey; + +/// KEM encryption key (i.e. public key) which encrypts shared secrets into ciphertexts which +/// can be decrypted by [`DecapsulationKey`]. +pub type EncapsulationKey = ::EncapsulationKey; + +/// Shared key: plaintext produced after decapsulation by [`Decapsulate::decapsulate`] which is +/// also returned by [`Encapsulate::encapsulate`], which is the shared secret resulting from the +/// key encapsulation algorithm. +pub type SharedKey = array::Array::SharedKeySize>; + /// Ciphertext message (a.k.a. "encapsulated key") produced by [`Encapsulate::encapsulate`] which is -/// an encrypted [`SharedSecret`] that can be decrypted using [`Decapsulate::decapsulate`]. -/// -/// `K` is expected to be a type that impls [`KemParams`], such as an encapsulator or decapsulator. -pub type Ciphertext = array::Array::CiphertextSize>; +/// an encrypted [`SharedKey`] that can be decrypted using [`Decapsulate::decapsulate`]. +pub type Ciphertext = array::Array::CiphertextSize>; -/// Shared secret: plaintext produced after decapsulation by [`Decapsulate::decapsulate`] which is -/// also returned by [`Encapsulate::encapsulate`]. +/// Key encapsulation mechanism. /// -/// `K` is expected to be a type that impls [`KemParams`], such as an encapsulator or decapsulator. -pub type SharedSecret = array::Array::SharedSecretSize>; +/// This trait describes the entire type family used by a KEM. +pub trait Kem: Copy + Clone + Debug + Default + Eq + Ord + Send + Sync + 'static { + /// KEM decryption key (i.e. private key) which can decrypt encrypted shared secret ciphertexts + /// which were encrypted by [`Kem::EncapsulationKey`]. + type DecapsulationKey: TryDecapsulate + Generate; -/// Key encapsulation mechanism parameters: sizes of the ciphertext and decrypted plaintext. -/// -/// This trait is impl'd by types that impl either [`Encapsulate`] or [`Decapsulate`] and defines -/// the sizes of the encapsulated key and shared secret. -pub trait KemParams { - /// Size of the ciphertext (a.k.a. "encapsulated key") produced by [`Encapsulate::encapsulate`]. + /// KEM encryption key (i.e. public key) which encrypts shared secrets into ciphertexts which + /// can be decrypted by [`Kem::DecapsulationKey`]. + type EncapsulationKey: Encapsulate + Clone + Debug + Eq; + + /// Size of the shared key/secret returned by both encapsulation and decapsulation. + type SharedKeySize: ArraySize; + + /// Size of the ciphertext (a.k.a. "encapsulated key") produced by [`Self::EncapsulationKey`]. type CiphertextSize: ArraySize; - /// Size of the shared secret after decapsulation by [`Decapsulate::decapsulate`]. - type SharedSecretSize: ArraySize; + /// Generate a random KEM keypair using the provided random number generator. + fn generate_keypair_from_rng( + rng: &mut R, + ) -> (Self::DecapsulationKey, Self::EncapsulationKey) { + let dk = Self::DecapsulationKey::generate_from_rng(rng); + let ek = dk.as_ref().clone(); + (dk, ek) + } + + /// Generate a random KEM keypair using the system's secure RNG. + #[cfg(feature = "getrandom")] + fn generate_keypair() -> (Self::DecapsulationKey, Self::EncapsulationKey) { + Self::generate_keypair_from_rng(&mut UnwrapErr(SysRng)) + } } /// Encapsulator for shared secrets. /// /// Often, this will just be a public key. However, it can also be a bundle of public keys, or it /// can include a sender's private key for authenticated encapsulation. -pub trait Encapsulate: KemParams + TryKeyInit + KeyExport { - /// Encapsulates a fresh [`SharedSecret`] generated using the supplied random number +pub trait Encapsulate: TryKeyInit + KeyExport { + /// Encapsulates a fresh [`SharedKey`] generated using the supplied random number /// generator `R`. - fn encapsulate_with_rng(&self, rng: &mut R) -> (Ciphertext, SharedSecret) + fn encapsulate_with_rng(&self, rng: &mut R) -> (Ciphertext, SharedKey) where R: CryptoRng + ?Sized; /// Encapsulate a fresh shared secret generated using the system's secure RNG. #[cfg(feature = "getrandom")] - fn encapsulate(&self) -> (Ciphertext, SharedSecret) { + fn encapsulate(&self) -> (Ciphertext, SharedKey) { self.encapsulate_with_rng(&mut UnwrapErr(SysRng)) } } -/// Trait for decapsulators, which is a supertrait bound of both [`Decapsulate`] and -/// [`TryDecapsulate`]. -pub trait Decapsulator: - KemParams< - CiphertextSize = ::CiphertextSize, - SharedSecretSize = ::SharedSecretSize, - > -{ - /// Encapsulator which corresponds to this decapsulator. - type Encapsulator: Encapsulate + Clone + KemParams; - - /// Retrieve the encapsulator associated with this decapsulator. - fn encapsulator(&self) -> &Self::Encapsulator; -} - -impl KemParams for K { - type CiphertextSize = ::CiphertextSize; - type SharedSecretSize = ::SharedSecretSize; -} - /// Decapsulator for encapsulated keys, with an associated `Encapsulator` bounded by the /// [`Encapsulate`] trait. /// @@ -90,15 +98,15 @@ impl KemParams for K { /// /// When possible (i.e. for software / non-HSM implementations) types which impl this trait should /// also impl the [`Generate`] trait to support key generation. -pub trait Decapsulate: Decapsulator + TryDecapsulate { +pub trait Decapsulate: TryDecapsulate { /// Decapsulates the given [`Ciphertext`] a.k.a. "encapsulated key". - fn decapsulate(&self, ct: &Ciphertext) -> SharedSecret; + fn decapsulate(&self, ct: &Ciphertext) -> SharedKey; /// Decapsulate the given byte slice containing a [`Ciphertext`] a.k.a. "encapsulated key". /// /// # Errors /// - If the length of `ct` is not equal to `::CiphertextSize`. - fn decapsulate_slice(&self, ct: &[u8]) -> Result, TryFromSliceError> { + fn decapsulate_slice(&self, ct: &[u8]) -> Result, TryFromSliceError> { ct.try_into().map(|ct| self.decapsulate(&ct)) } } @@ -108,18 +116,18 @@ pub trait Decapsulate: Decapsulator + TryDecapsulate { /// /// Prefer to implement the [`Decapsulate`] trait if possible. See that trait's documentation for /// more information. -pub trait TryDecapsulate: Decapsulator { +pub trait TryDecapsulate: AsRef { /// Decapsulation error type Error: core::error::Error; /// Decapsulates the given [`Ciphertext`] a.k.a. "encapsulated key". - fn try_decapsulate(&self, ct: &Ciphertext) -> Result, Self::Error>; + fn try_decapsulate(&self, ct: &Ciphertext) -> Result, Self::Error>; /// Decapsulate the given byte slice containing a [`Ciphertext`] a.k.a. "encapsulated key". /// /// # Errors /// - If the length of `ct` is not equal to `::CiphertextSize`. - fn try_decapsulate_slice(&self, ct: &[u8]) -> Result, Self::Error> + fn try_decapsulate_slice(&self, ct: &[u8]) -> Result, Self::Error> where Self::Error: From, { @@ -127,13 +135,14 @@ pub trait TryDecapsulate: Decapsulator { } } -impl TryDecapsulate for D +impl TryDecapsulate for D where - D: Decapsulate, + D: Decapsulate, + K: Kem, { type Error = Infallible; - fn try_decapsulate(&self, ct: &Ciphertext) -> Result, Infallible> { + fn try_decapsulate(&self, ct: &Ciphertext) -> Result, Infallible> { Ok(self.decapsulate(ct)) } }