diff --git a/kem/src/lib.rs b/kem/src/lib.rs index ccdadc51d..5a1e64f6e 100644 --- a/kem/src/lib.rs +++ b/kem/src/lib.rs @@ -20,6 +20,9 @@ use rand_core::CryptoRng; #[cfg(feature = "getrandom")] use common::getrandom::{SysRng, rand_core::UnwrapErr}; +/// Seed value which can be used to deterministically initialize a KEM keypair. +pub type Seed = array::Array::SeedSize>; + /// KEM decryption key (i.e. private key) which can decrypt encrypted shared secret ciphertexts /// which were encrypted by [`EncapsulationKey`]. pub type DecapsulationKey = ::DecapsulationKey; @@ -58,37 +61,44 @@ pub trait Kem: Copy + Clone + Debug + Default + Eq + Ord + Send + Sync + 'static /// 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); + ) -> (DecapsulationKey, EncapsulationKey) { + let dk = DecapsulationKey::::generate_from_rng(rng); let ek = dk.encapsulation_key().clone(); (dk, ek) } /// Generate a random KEM keypair using the system's secure RNG. #[cfg(feature = "getrandom")] - fn generate_keypair() -> (Self::DecapsulationKey, Self::EncapsulationKey) { + fn generate_keypair() -> (DecapsulationKey, EncapsulationKey) { Self::generate_keypair_from_rng(&mut UnwrapErr(SysRng)) } } -/// Encapsulator for shared secrets. +/// Initialize a KEM from a [`Seed`]. /// -/// 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: TryKeyInit + KeyExport { - /// KEM algorithm this encapsulator is for. - type Kem: Kem; +/// Many KEMs support a fully deterministic and infallible initialization from a short seed value. +/// +/// This trait is blanket impl'd for any [`Kem`] whose [`DecapsulationKey`] impls the [`KeyInit`] +/// trait. +pub trait FromSeed: Kem { + /// Size of the seed value in bytes. + type SeedSize: ArraySize; + + /// Using the provided seed value, create a KEM keypair. + fn from_seed(seed: &Seed) -> (DecapsulationKey, EncapsulationKey); +} - /// Encapsulates a fresh [`SharedKey`] generated using the supplied random number - /// generator `R`. - fn encapsulate_with_rng(&self, rng: &mut R) -> (Ciphertext, SharedKey) - where - R: CryptoRng + ?Sized; +impl FromSeed for K +where + K: Kem, + K::DecapsulationKey: KeyInit, +{ + type SeedSize = ::KeySize; - /// Encapsulate a fresh shared secret generated using the system's secure RNG. - #[cfg(feature = "getrandom")] - fn encapsulate(&self) -> (Ciphertext, SharedKey) { - self.encapsulate_with_rng(&mut UnwrapErr(SysRng)) + fn from_seed(seed: &Seed) -> (DecapsulationKey, EncapsulationKey) { + let dk = DecapsulationKey::::new(seed); + let ek = dk.encapsulation_key().clone(); + (dk, ek) } } @@ -164,3 +174,24 @@ where Ok(self.decapsulate(ct)) } } + +/// 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: TryKeyInit + KeyExport { + /// KEM algorithm this encapsulator is for. + type Kem: Kem; + + /// Encapsulates a fresh [`SharedKey`] generated using the supplied random number + /// generator `R`. + 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, SharedKey) { + self.encapsulate_with_rng(&mut UnwrapErr(SysRng)) + } +}