Skip to content

Commit b5cfb05

Browse files
authored
kem: Kem trait for the whole algorithm type family (#2243)
Adds a `Kem` trait intended to be impl'd by ZSTs that describe the whole type family, including the decapsulation key, encapsulation key, and the sizes of the ciphertext and shared secret previously defined on the `KemParams` trait (which this subsumes). The remaining traits have been changed to be generic around `K: Kem` and now use it to source their constants or relevant types. `DecapsulationKey<K>` and `EncapsulationKey<K>` type aliases have been added, similar to the ones in `elliptic-curve`, which take care of doing `K as Kem` for you when accessing the associated types. The design of this trait largely matches the bespoke traits that people were defining different but similarly shaped-versions of in individual crates in https://github.com/RustCrypto/KEMs
1 parent 0e210cd commit b5cfb05

1 file changed

Lines changed: 58 additions & 49 deletions

File tree

kem/src/lib.rs

Lines changed: 58 additions & 49 deletions
Original file line numberDiff line numberDiff line change
@@ -13,74 +13,82 @@ pub use common::{
1313
};
1414

1515
use common::array::{self, ArraySize};
16+
use core::fmt::Debug;
1617
use core::{array::TryFromSliceError, convert::Infallible};
1718
use rand_core::CryptoRng;
1819

1920
#[cfg(feature = "getrandom")]
2021
use common::getrandom::{SysRng, rand_core::UnwrapErr};
2122

23+
/// KEM decryption key (i.e. private key) which can decrypt encrypted shared secret ciphertexts
24+
/// which were encrypted by [`EncapsulationKey<K>`].
25+
pub type DecapsulationKey<K> = <K as Kem>::DecapsulationKey;
26+
27+
/// KEM encryption key (i.e. public key) which encrypts shared secrets into ciphertexts which
28+
/// can be decrypted by [`DecapsulationKey<K>`].
29+
pub type EncapsulationKey<K> = <K as Kem>::EncapsulationKey;
30+
31+
/// Shared key: plaintext produced after decapsulation by [`Decapsulate::decapsulate`] which is
32+
/// also returned by [`Encapsulate::encapsulate`], which is the shared secret resulting from the
33+
/// key encapsulation algorithm.
34+
pub type SharedKey<K> = array::Array<u8, <K as Kem>::SharedKeySize>;
35+
2236
/// Ciphertext message (a.k.a. "encapsulated key") produced by [`Encapsulate::encapsulate`] which is
23-
/// an encrypted [`SharedSecret`] that can be decrypted using [`Decapsulate::decapsulate`].
24-
///
25-
/// `K` is expected to be a type that impls [`KemParams`], such as an encapsulator or decapsulator.
26-
pub type Ciphertext<K> = array::Array<u8, <K as KemParams>::CiphertextSize>;
37+
/// an encrypted [`SharedKey`] that can be decrypted using [`Decapsulate::decapsulate`].
38+
pub type Ciphertext<K> = array::Array<u8, <K as Kem>::CiphertextSize>;
2739

28-
/// Shared secret: plaintext produced after decapsulation by [`Decapsulate::decapsulate`] which is
29-
/// also returned by [`Encapsulate::encapsulate`].
40+
/// Key encapsulation mechanism.
3041
///
31-
/// `K` is expected to be a type that impls [`KemParams`], such as an encapsulator or decapsulator.
32-
pub type SharedSecret<K> = array::Array<u8, <K as KemParams>::SharedSecretSize>;
42+
/// This trait describes the entire type family used by a KEM.
43+
pub trait Kem: Copy + Clone + Debug + Default + Eq + Ord + Send + Sync + 'static {
44+
/// KEM decryption key (i.e. private key) which can decrypt encrypted shared secret ciphertexts
45+
/// which were encrypted by [`Kem::EncapsulationKey`].
46+
type DecapsulationKey: TryDecapsulate<Self> + Generate;
3347

34-
/// Key encapsulation mechanism parameters: sizes of the ciphertext and decrypted plaintext.
35-
///
36-
/// This trait is impl'd by types that impl either [`Encapsulate`] or [`Decapsulate`] and defines
37-
/// the sizes of the encapsulated key and shared secret.
38-
pub trait KemParams {
39-
/// Size of the ciphertext (a.k.a. "encapsulated key") produced by [`Encapsulate::encapsulate`].
48+
/// KEM encryption key (i.e. public key) which encrypts shared secrets into ciphertexts which
49+
/// can be decrypted by [`Kem::DecapsulationKey`].
50+
type EncapsulationKey: Encapsulate<Self> + Clone + Debug + Eq;
51+
52+
/// Size of the shared key/secret returned by both encapsulation and decapsulation.
53+
type SharedKeySize: ArraySize;
54+
55+
/// Size of the ciphertext (a.k.a. "encapsulated key") produced by [`Self::EncapsulationKey`].
4056
type CiphertextSize: ArraySize;
4157

42-
/// Size of the shared secret after decapsulation by [`Decapsulate::decapsulate`].
43-
type SharedSecretSize: ArraySize;
58+
/// Generate a random KEM keypair using the provided random number generator.
59+
fn generate_keypair_from_rng<R: CryptoRng>(
60+
rng: &mut R,
61+
) -> (Self::DecapsulationKey, Self::EncapsulationKey) {
62+
let dk = Self::DecapsulationKey::generate_from_rng(rng);
63+
let ek = dk.as_ref().clone();
64+
(dk, ek)
65+
}
66+
67+
/// Generate a random KEM keypair using the system's secure RNG.
68+
#[cfg(feature = "getrandom")]
69+
fn generate_keypair() -> (Self::DecapsulationKey, Self::EncapsulationKey) {
70+
Self::generate_keypair_from_rng(&mut UnwrapErr(SysRng))
71+
}
4472
}
4573

4674
/// Encapsulator for shared secrets.
4775
///
4876
/// Often, this will just be a public key. However, it can also be a bundle of public keys, or it
4977
/// can include a sender's private key for authenticated encapsulation.
50-
pub trait Encapsulate: KemParams + TryKeyInit + KeyExport {
51-
/// Encapsulates a fresh [`SharedSecret`] generated using the supplied random number
78+
pub trait Encapsulate<K: Kem>: TryKeyInit + KeyExport {
79+
/// Encapsulates a fresh [`SharedKey`] generated using the supplied random number
5280
/// generator `R`.
53-
fn encapsulate_with_rng<R>(&self, rng: &mut R) -> (Ciphertext<Self>, SharedSecret<Self>)
81+
fn encapsulate_with_rng<R>(&self, rng: &mut R) -> (Ciphertext<K>, SharedKey<K>)
5482
where
5583
R: CryptoRng + ?Sized;
5684

5785
/// Encapsulate a fresh shared secret generated using the system's secure RNG.
5886
#[cfg(feature = "getrandom")]
59-
fn encapsulate(&self) -> (Ciphertext<Self>, SharedSecret<Self>) {
87+
fn encapsulate(&self) -> (Ciphertext<K>, SharedKey<K>) {
6088
self.encapsulate_with_rng(&mut UnwrapErr(SysRng))
6189
}
6290
}
6391

64-
/// Trait for decapsulators, which is a supertrait bound of both [`Decapsulate`] and
65-
/// [`TryDecapsulate`].
66-
pub trait Decapsulator:
67-
KemParams<
68-
CiphertextSize = <Self::Encapsulator as KemParams>::CiphertextSize,
69-
SharedSecretSize = <Self::Encapsulator as KemParams>::SharedSecretSize,
70-
>
71-
{
72-
/// Encapsulator which corresponds to this decapsulator.
73-
type Encapsulator: Encapsulate + Clone + KemParams;
74-
75-
/// Retrieve the encapsulator associated with this decapsulator.
76-
fn encapsulator(&self) -> &Self::Encapsulator;
77-
}
78-
79-
impl<K: Decapsulator> KemParams for K {
80-
type CiphertextSize = <K::Encapsulator as KemParams>::CiphertextSize;
81-
type SharedSecretSize = <K::Encapsulator as KemParams>::SharedSecretSize;
82-
}
83-
8492
/// Decapsulator for encapsulated keys, with an associated `Encapsulator` bounded by the
8593
/// [`Encapsulate`] trait.
8694
///
@@ -90,15 +98,15 @@ impl<K: Decapsulator> KemParams for K {
9098
///
9199
/// When possible (i.e. for software / non-HSM implementations) types which impl this trait should
92100
/// also impl the [`Generate`] trait to support key generation.
93-
pub trait Decapsulate: Decapsulator + TryDecapsulate<Error = Infallible> {
101+
pub trait Decapsulate<K: Kem>: TryDecapsulate<K, Error = Infallible> {
94102
/// Decapsulates the given [`Ciphertext`] a.k.a. "encapsulated key".
95-
fn decapsulate(&self, ct: &Ciphertext<Self>) -> SharedSecret<Self>;
103+
fn decapsulate(&self, ct: &Ciphertext<K>) -> SharedKey<K>;
96104

97105
/// Decapsulate the given byte slice containing a [`Ciphertext`] a.k.a. "encapsulated key".
98106
///
99107
/// # Errors
100108
/// - If the length of `ct` is not equal to `<Self as Kem>::CiphertextSize`.
101-
fn decapsulate_slice(&self, ct: &[u8]) -> Result<SharedSecret<Self>, TryFromSliceError> {
109+
fn decapsulate_slice(&self, ct: &[u8]) -> Result<SharedKey<K>, TryFromSliceError> {
102110
ct.try_into().map(|ct| self.decapsulate(&ct))
103111
}
104112
}
@@ -108,32 +116,33 @@ pub trait Decapsulate: Decapsulator + TryDecapsulate<Error = Infallible> {
108116
///
109117
/// Prefer to implement the [`Decapsulate`] trait if possible. See that trait's documentation for
110118
/// more information.
111-
pub trait TryDecapsulate: Decapsulator {
119+
pub trait TryDecapsulate<K: Kem>: AsRef<K::EncapsulationKey> {
112120
/// Decapsulation error
113121
type Error: core::error::Error;
114122

115123
/// Decapsulates the given [`Ciphertext`] a.k.a. "encapsulated key".
116-
fn try_decapsulate(&self, ct: &Ciphertext<Self>) -> Result<SharedSecret<Self>, Self::Error>;
124+
fn try_decapsulate(&self, ct: &Ciphertext<K>) -> Result<SharedKey<K>, Self::Error>;
117125

118126
/// Decapsulate the given byte slice containing a [`Ciphertext`] a.k.a. "encapsulated key".
119127
///
120128
/// # Errors
121129
/// - If the length of `ct` is not equal to `<Self as Kem>::CiphertextSize`.
122-
fn try_decapsulate_slice(&self, ct: &[u8]) -> Result<SharedSecret<Self>, Self::Error>
130+
fn try_decapsulate_slice(&self, ct: &[u8]) -> Result<SharedKey<K>, Self::Error>
123131
where
124132
Self::Error: From<TryFromSliceError>,
125133
{
126134
self.try_decapsulate(ct.try_into()?)
127135
}
128136
}
129137

130-
impl<D> TryDecapsulate for D
138+
impl<D, K> TryDecapsulate<K> for D
131139
where
132-
D: Decapsulate,
140+
D: Decapsulate<K>,
141+
K: Kem,
133142
{
134143
type Error = Infallible;
135144

136-
fn try_decapsulate(&self, ct: &Ciphertext<Self>) -> Result<SharedSecret<Self>, Infallible> {
145+
fn try_decapsulate(&self, ct: &Ciphertext<K>) -> Result<SharedKey<K>, Infallible> {
137146
Ok(self.decapsulate(ct))
138147
}
139148
}

0 commit comments

Comments
 (0)