Skip to content

Commit 62a42bc

Browse files
authored
kem: move Kem for *Decapsulate/Encapsulate to associated type (#2282)
Also adds (back) a `Decapsulator` trait. This is effectively a followup to #2243 which added the `Kem` trait but made it a generic argument to `*Decapsulate`/`Encapsulate`, and removed the previous `Decapsulator` trait. Having it be a generic argument is annoying: these types should simply know what KEM algorithm they implement. The only reason I didn't do it that way at the time was I was having trouble making it work, and that was a fairly large refactor to begin with. This adds an associated `Kem` to `Encapsulate`, but for `Decapsulate`/`TryDecapsulate` we need a common trait to hang it off of, so this adds back the `Decapsulator` trait. It's not so bad as the previous hack introduced in #2243 of using `AsRef` to obtain an `EncapsulationKey` from a `Decapsulator` has been replaced with a semantically clear `Decapsulator::encapsulation_key` method.
1 parent 61a9586 commit 62a42bc

File tree

1 file changed

+34
-16
lines changed

1 file changed

+34
-16
lines changed

kem/src/lib.rs

Lines changed: 34 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -43,11 +43,11 @@ pub type Ciphertext<K> = array::Array<u8, <K as Kem>::CiphertextSize>;
4343
pub trait Kem: Copy + Clone + Debug + Default + Eq + Ord + Send + Sync + 'static {
4444
/// KEM decryption key (i.e. private key) which can decrypt encrypted shared secret ciphertexts
4545
/// which were encrypted by [`Kem::EncapsulationKey`].
46-
type DecapsulationKey: TryDecapsulate<Self> + Generate;
46+
type DecapsulationKey: TryDecapsulate<Kem = Self> + Generate;
4747

4848
/// KEM encryption key (i.e. public key) which encrypts shared secrets into ciphertexts which
4949
/// can be decrypted by [`Kem::DecapsulationKey`].
50-
type EncapsulationKey: Encapsulate<Self> + Clone + Debug + Eq;
50+
type EncapsulationKey: Encapsulate<Kem = Self> + Clone + Debug + Eq;
5151

5252
/// Size of the shared key/secret returned by both encapsulation and decapsulation.
5353
type SharedKeySize: ArraySize;
@@ -60,7 +60,7 @@ pub trait Kem: Copy + Clone + Debug + Default + Eq + Ord + Send + Sync + 'static
6060
rng: &mut R,
6161
) -> (Self::DecapsulationKey, Self::EncapsulationKey) {
6262
let dk = Self::DecapsulationKey::generate_from_rng(rng);
63-
let ek = dk.as_ref().clone();
63+
let ek = dk.encapsulation_key().clone();
6464
(dk, ek)
6565
}
6666

@@ -75,20 +75,33 @@ pub trait Kem: Copy + Clone + Debug + Default + Eq + Ord + Send + Sync + 'static
7575
///
7676
/// Often, this will just be a public key. However, it can also be a bundle of public keys, or it
7777
/// can include a sender's private key for authenticated encapsulation.
78-
pub trait Encapsulate<K: Kem>: TryKeyInit + KeyExport {
78+
pub trait Encapsulate: TryKeyInit + KeyExport {
79+
/// KEM algorithm this encapsulator is for.
80+
type Kem: Kem;
81+
7982
/// Encapsulates a fresh [`SharedKey`] generated using the supplied random number
8083
/// generator `R`.
81-
fn encapsulate_with_rng<R>(&self, rng: &mut R) -> (Ciphertext<K>, SharedKey<K>)
84+
fn encapsulate_with_rng<R>(&self, rng: &mut R) -> (Ciphertext<Self::Kem>, SharedKey<Self::Kem>)
8285
where
8386
R: CryptoRng + ?Sized;
8487

8588
/// Encapsulate a fresh shared secret generated using the system's secure RNG.
8689
#[cfg(feature = "getrandom")]
87-
fn encapsulate(&self) -> (Ciphertext<K>, SharedKey<K>) {
90+
fn encapsulate(&self) -> (Ciphertext<Self::Kem>, SharedKey<Self::Kem>) {
8891
self.encapsulate_with_rng(&mut UnwrapErr(SysRng))
8992
}
9093
}
9194

95+
/// Decapsulator with an associated encapsulation key which can be used for encrypting shared keys
96+
/// that this decapsulator can decrypt.
97+
pub trait Decapsulator {
98+
/// KEM algorithm this decapsulator is for.
99+
type Kem: Kem;
100+
101+
/// Encapsulation key which can encrypt ciphertexts this decapsulator can decrypt.
102+
fn encapsulation_key(&self) -> &EncapsulationKey<Self::Kem>;
103+
}
104+
92105
/// Decapsulator for encapsulated keys, with an associated `Encapsulator` bounded by the
93106
/// [`Encapsulate`] trait.
94107
///
@@ -98,15 +111,15 @@ pub trait Encapsulate<K: Kem>: TryKeyInit + KeyExport {
98111
///
99112
/// When possible (i.e. for software / non-HSM implementations) types which impl this trait should
100113
/// also impl the [`Generate`] trait to support key generation.
101-
pub trait Decapsulate<K: Kem>: TryDecapsulate<K, Error = Infallible> {
114+
pub trait Decapsulate: TryDecapsulate<Error = Infallible> {
102115
/// Decapsulates the given [`Ciphertext`] a.k.a. "encapsulated key".
103-
fn decapsulate(&self, ct: &Ciphertext<K>) -> SharedKey<K>;
116+
fn decapsulate(&self, ct: &Ciphertext<Self::Kem>) -> SharedKey<Self::Kem>;
104117

105118
/// Decapsulate the given byte slice containing a [`Ciphertext`] a.k.a. "encapsulated key".
106119
///
107120
/// # Errors
108121
/// - If the length of `ct` is not equal to `<Self as Kem>::CiphertextSize`.
109-
fn decapsulate_slice(&self, ct: &[u8]) -> Result<SharedKey<K>, TryFromSliceError> {
122+
fn decapsulate_slice(&self, ct: &[u8]) -> Result<SharedKey<Self::Kem>, TryFromSliceError> {
110123
ct.try_into().map(|ct| self.decapsulate(&ct))
111124
}
112125
}
@@ -116,33 +129,38 @@ pub trait Decapsulate<K: Kem>: TryDecapsulate<K, Error = Infallible> {
116129
///
117130
/// Prefer to implement the [`Decapsulate`] trait if possible. See that trait's documentation for
118131
/// more information.
119-
pub trait TryDecapsulate<K: Kem>: AsRef<K::EncapsulationKey> {
132+
pub trait TryDecapsulate: Decapsulator {
120133
/// Decapsulation error
121134
type Error: core::error::Error;
122135

123136
/// Decapsulates the given [`Ciphertext`] a.k.a. "encapsulated key".
124-
fn try_decapsulate(&self, ct: &Ciphertext<K>) -> Result<SharedKey<K>, Self::Error>;
137+
fn try_decapsulate(
138+
&self,
139+
ct: &Ciphertext<Self::Kem>,
140+
) -> Result<SharedKey<Self::Kem>, Self::Error>;
125141

126142
/// Decapsulate the given byte slice containing a [`Ciphertext`] a.k.a. "encapsulated key".
127143
///
128144
/// # Errors
129145
/// - If the length of `ct` is not equal to `<Self as Kem>::CiphertextSize`.
130-
fn try_decapsulate_slice(&self, ct: &[u8]) -> Result<SharedKey<K>, Self::Error>
146+
fn try_decapsulate_slice(&self, ct: &[u8]) -> Result<SharedKey<Self::Kem>, Self::Error>
131147
where
132148
Self::Error: From<TryFromSliceError>,
133149
{
134150
self.try_decapsulate(ct.try_into()?)
135151
}
136152
}
137153

138-
impl<D, K> TryDecapsulate<K> for D
154+
impl<D> TryDecapsulate for D
139155
where
140-
D: Decapsulate<K>,
141-
K: Kem,
156+
D: Decapsulate + Decapsulator,
142157
{
143158
type Error = Infallible;
144159

145-
fn try_decapsulate(&self, ct: &Ciphertext<K>) -> Result<SharedKey<K>, Infallible> {
160+
fn try_decapsulate(
161+
&self,
162+
ct: &Ciphertext<Self::Kem>,
163+
) -> Result<SharedKey<Self::Kem>, Infallible> {
146164
Ok(self.decapsulate(ct))
147165
}
148166
}

0 commit comments

Comments
 (0)