Skip to main content

kem/
lib.rs

1#![no_std]
2#![cfg_attr(docsrs, feature(doc_cfg))]
3#![doc = include_str!("../README.md")]
4#![doc(
5    html_logo_url = "https://raw.githubusercontent.com/RustCrypto/media/8f1a9894/logo.svg",
6    html_favicon_url = "https://raw.githubusercontent.com/RustCrypto/media/8f1a9894/logo.svg"
7)]
8#![forbid(unsafe_code)]
9#![warn(missing_docs, unused_qualifications, missing_debug_implementations)]
10
11//! # Usage
12//!
13//! There are two roles in a KEM:
14//!
15//! - Encapsulator: the holder of the public key (a.k.a. encapsulation key), which provides an
16//!   operation that simultaneously generates both the plaintext and ciphertext of a random
17//!   "shared key" whose ciphertext (a.k.a. encapsulation) can be sent to the party with the
18//!   decapsulator key.
19//! - Decapsulator: holder secret/private key (a.k.a. decapsulation key), which can be used to
20//!   decrypt the encrypted (a.k.a. encapsulated) "shared key" which was randomly generated by
21//!   the encapsulator.
22//!
23//! The following example illustrates the workflow of using this crate's traits with a hypothetical
24//! KEM named `K` :
25//!
26#![cfg_attr(feature = "getrandom", doc = "```")]
27#![cfg_attr(not(feature = "getrandom"), doc = "```ignore")]
28//! // NOTE: requires the `getrandom` feature is enabled
29//!
30//! use kem::{Decapsulate, Encapsulate, Kem};
31//!
32//! # pub fn kem_workflow_example<K: Kem<DecapsulationKey: Decapsulate>>() {
33//! // Generate a decapsulation/encapsulation keypair. The first one is the secret one.
34//! let (dk, ek) = K::generate_keypair();
35//!
36//! // Encapsulator:
37//! //
38//! // Randomly generates and encapsulates/encrypts a shared key which can be decrypted by the
39//! // holder of the decapsulation key, obtaining the ciphertext and plaintext of the shared key.
40//! let (ct, k_send) = ek.encapsulate();
41//!
42//! // Decapsulator:
43//! //
44//! // Decapsulates the encrypted/encapsulated shared key, obtaining its plaintext.
45//! let k_recv = dk.decapsulate(&ct);
46//!
47//! // We've now established a shared key.
48//! assert_eq!(k_send, k_recv);
49//! # }
50//! ```
51//!
52//! ## Serialization
53//!
54//! The [`KeyInit`] and [`KeyExport`] traits can be used to load and store encoded decapsulation
55//! and encapsulation keys from their byte serialization.
56//!
57//! Decapsulation keys are often initialized from a compact representation known as a [`Seed`].
58//! The [`FromSeed`] trait provides an extension to the [`Kem`] trait for initializing keypairs
59//! from a seed value. We recommend the [`KeyInit`] and [`KeyExport`] trait impls on
60//! decapsulation keys operate on seed values when there is a choice of multiple key formats
61//! (e.g. expanded decapsulation keys).
62//!
63//! [RFC 9180]: https://www.rfc-editor.org/info/rfc9180
64
65pub use common::{
66    self, Generate, InvalidKey, Key, KeyExport, KeyInit, KeySizeUser, TryKeyInit, typenum::consts,
67};
68
69use common::array::{self, ArraySize};
70use core::fmt::Debug;
71use core::{array::TryFromSliceError, convert::Infallible};
72use rand_core::CryptoRng;
73
74#[cfg(feature = "getrandom")]
75use common::getrandom::{SysRng, rand_core::UnwrapErr};
76
77/// Seed value which can be used to deterministically initialize a KEM keypair.
78pub type Seed<K> = array::Array<u8, <K as FromSeed>::SeedSize>;
79
80/// KEM decryption key (i.e. private key) which can decrypt encrypted shared secret ciphertexts
81/// which were encrypted by [`EncapsulationKey<K>`].
82pub type DecapsulationKey<K> = <K as Kem>::DecapsulationKey;
83
84/// KEM encryption key (i.e. public key) which encrypts shared secrets into ciphertexts which
85/// can be decrypted by [`DecapsulationKey<K>`].
86pub type EncapsulationKey<K> = <K as Kem>::EncapsulationKey;
87
88/// Shared key: plaintext produced after decapsulation by [`Decapsulate::decapsulate`] which is
89/// also returned by [`Encapsulate::encapsulate`], which is the shared secret resulting from the
90/// key encapsulation algorithm.
91pub type SharedKey<K> = array::Array<u8, <K as Kem>::SharedKeySize>;
92
93/// Ciphertext message (a.k.a. "encapsulated key") produced by [`Encapsulate::encapsulate`] which is
94/// an encrypted [`SharedKey`] that can be decrypted using [`Decapsulate::decapsulate`].
95pub type Ciphertext<K> = array::Array<u8, <K as Kem>::CiphertextSize>;
96
97/// Key encapsulation mechanism.
98///
99/// This trait describes the entire type family used by a KEM.
100pub trait Kem: Copy + Clone + Debug + Default + Eq + Ord + Send + Sync + 'static {
101    /// KEM decryption key (i.e. private key) which can decrypt encrypted shared secret ciphertexts
102    /// which were encrypted by [`Kem::EncapsulationKey`].
103    type DecapsulationKey: TryDecapsulate<Kem = Self> + Generate;
104
105    /// KEM encryption key (i.e. public key) which encrypts shared secrets into ciphertexts which
106    /// can be decrypted by [`Kem::DecapsulationKey`].
107    type EncapsulationKey: Encapsulate<Kem = Self> + Clone + Debug + Eq;
108
109    /// Size of the shared key/secret returned by both encapsulation and decapsulation.
110    type SharedKeySize: ArraySize;
111
112    /// Size of the ciphertext (a.k.a. "encapsulated key") produced by [`Self::EncapsulationKey`].
113    type CiphertextSize: ArraySize;
114
115    /// Generate a random KEM keypair using the provided random number generator.
116    fn generate_keypair_from_rng<R: CryptoRng>(
117        rng: &mut R,
118    ) -> (DecapsulationKey<Self>, EncapsulationKey<Self>) {
119        let dk = DecapsulationKey::<Self>::generate_from_rng(rng);
120        let ek = dk.encapsulation_key().clone();
121        (dk, ek)
122    }
123
124    /// Generate a random KEM keypair using the system's secure RNG.
125    #[cfg(feature = "getrandom")]
126    fn generate_keypair() -> (DecapsulationKey<Self>, EncapsulationKey<Self>) {
127        Self::generate_keypair_from_rng(&mut UnwrapErr(SysRng))
128    }
129}
130
131/// Initialize a KEM from a [`Seed`].
132///
133/// Many KEMs support a fully deterministic and infallible initialization from a short seed value.
134///
135/// This trait is blanket impl'd for any [`Kem`] whose [`DecapsulationKey`] impls the [`KeyInit`]
136/// trait.
137pub trait FromSeed: Kem {
138    /// Size of the seed value in bytes.
139    type SeedSize: ArraySize;
140
141    /// Using the provided seed value, create a KEM keypair.
142    fn from_seed(seed: &Seed<Self>) -> (DecapsulationKey<Self>, EncapsulationKey<Self>);
143}
144
145impl<K> FromSeed for K
146where
147    K: Kem,
148    K::DecapsulationKey: KeyInit,
149{
150    type SeedSize = <K::DecapsulationKey as KeySizeUser>::KeySize;
151
152    fn from_seed(seed: &Seed<Self>) -> (DecapsulationKey<Self>, EncapsulationKey<Self>) {
153        let dk = DecapsulationKey::<Self>::new(seed);
154        let ek = dk.encapsulation_key().clone();
155        (dk, ek)
156    }
157}
158
159/// Decapsulator with an associated encapsulation key which can be used for encrypting shared keys
160/// that this decapsulator can decrypt.
161pub trait Decapsulator {
162    /// KEM algorithm this decapsulator is for.
163    type Kem: Kem;
164
165    /// Encapsulation key which can encrypt ciphertexts this decapsulator can decrypt.
166    fn encapsulation_key(&self) -> &EncapsulationKey<Self::Kem>;
167}
168
169/// Decapsulator for encapsulated keys, with an associated `Encapsulator` bounded by the
170/// [`Encapsulate`] trait.
171///
172/// Often, this will just be a secret key. But, as with [`Encapsulate`], it can be a bundle
173/// of secret keys, or it can include a sender's private key for authenticated encapsulation.
174/// It could also be a hardware device like an HSM, TPM, or SEP.
175///
176/// When possible (i.e. for software / non-HSM implementations) types which impl this trait should
177/// also impl the [`Generate`] trait to support key generation.
178pub trait Decapsulate: TryDecapsulate<Error = Infallible> {
179    /// Decapsulates the given [`Ciphertext`] a.k.a. "encapsulated key".
180    fn decapsulate(&self, ct: &Ciphertext<Self::Kem>) -> SharedKey<Self::Kem>;
181
182    /// Decapsulate the given byte slice containing a  [`Ciphertext`] a.k.a. "encapsulated key".
183    ///
184    /// # Errors
185    /// - If the length of `ct` is not equal to `<Self as Kem>::CiphertextSize`.
186    fn decapsulate_slice(&self, ct: &[u8]) -> Result<SharedKey<Self::Kem>, TryFromSliceError> {
187        ct.try_into().map(|ct| self.decapsulate(&ct))
188    }
189}
190
191/// Decapsulator for encapsulated keys with failure handling, with an associated `Encapsulator`
192/// bounded by the [`Encapsulate`] trait.
193///
194/// Prefer to implement the [`Decapsulate`] trait if possible. See that trait's documentation for
195/// more information.
196pub trait TryDecapsulate: Decapsulator {
197    /// Decapsulation error
198    type Error: core::error::Error;
199
200    /// Decapsulates the given [`Ciphertext`] a.k.a. "encapsulated key".
201    fn try_decapsulate(
202        &self,
203        ct: &Ciphertext<Self::Kem>,
204    ) -> Result<SharedKey<Self::Kem>, Self::Error>;
205
206    /// Decapsulate the given byte slice containing a  [`Ciphertext`] a.k.a. "encapsulated key".
207    ///
208    /// # Errors
209    /// - If the length of `ct` is not equal to `<Self as Kem>::CiphertextSize`.
210    fn try_decapsulate_slice(&self, ct: &[u8]) -> Result<SharedKey<Self::Kem>, Self::Error>
211    where
212        Self::Error: From<TryFromSliceError>,
213    {
214        self.try_decapsulate(ct.try_into()?)
215    }
216}
217
218impl<D> TryDecapsulate for D
219where
220    D: Decapsulate + Decapsulator,
221{
222    type Error = Infallible;
223
224    fn try_decapsulate(
225        &self,
226        ct: &Ciphertext<Self::Kem>,
227    ) -> Result<SharedKey<Self::Kem>, Infallible> {
228        Ok(self.decapsulate(ct))
229    }
230}
231
232/// Encapsulator for shared secrets.
233///
234/// Often, this will just be a public key. However, it can also be a bundle of public keys, or it
235/// can include a sender's private key for authenticated encapsulation.
236pub trait Encapsulate: TryKeyInit + KeyExport {
237    /// KEM algorithm this encapsulator is for.
238    type Kem: Kem;
239
240    /// Encapsulates a fresh [`SharedKey`] generated using the supplied random number
241    /// generator `R`.
242    fn encapsulate_with_rng<R>(&self, rng: &mut R) -> (Ciphertext<Self::Kem>, SharedKey<Self::Kem>)
243    where
244        R: CryptoRng + ?Sized;
245
246    /// Encapsulate a fresh shared secret generated using the system's secure RNG.
247    #[cfg(feature = "getrandom")]
248    fn encapsulate(&self) -> (Ciphertext<Self::Kem>, SharedKey<Self::Kem>) {
249        self.encapsulate_with_rng(&mut UnwrapErr(SysRng))
250    }
251}