ml_kem/lib.rs
1#![no_std]
2#![cfg_attr(docsrs, feature(doc_auto_cfg))]
3#![doc = include_str!("../README.md")]
4#![doc(
5 html_logo_url = "https://raw.githubusercontent.com/RustCrypto/meta/master/logo.svg",
6 html_favicon_url = "https://raw.githubusercontent.com/RustCrypto/meta/master/logo.svg"
7)]
8#![warn(clippy::pedantic)] // Be pedantic by default
9#![warn(clippy::integer_division_remainder_used)] // Be judicious about using `/` and `%`
10#![allow(non_snake_case)] // Allow notation matching the spec
11#![allow(clippy::clone_on_copy)] // Be explicit about moving data
12#![deny(missing_docs)] // Require all public interfaces to be documented
13
14//! # Usage
15//!
16//! This crate implements the Module-Latice-based Key Encapsulation Method (ML-KEM) algorithm
17//! being standardized by NIST in FIPS 203. ML-KEM is a KEM in the sense that it creates an
18//! (decapsulation key, encapsulation key) pair, such that anyone can use the encapsulation key to
19//! establish a shared key with the holder of the decapsulation key. ML-KEM is the first KEM
20//! algorithm standardized by NIST that is designed to be resistant to attacks using quantum
21//! computers.
22//!
23//! ```
24//! # use ml_kem::*;
25//! # use ::kem::{Decapsulate, Encapsulate};
26//! let mut rng = rand::thread_rng();
27//!
28//! // Generate a (decapsulation key, encapsulation key) pair
29//! let (dk, ek) = MlKem768::generate(&mut rng);
30//!
31//! // Encapsulate a shared key to the holder of the decapsulation key, receive the shared
32//! // secret `k_send` and the encapsulated form `ct`.
33//! let (ct, k_send) = ek.encapsulate(&mut rng).unwrap();
34//!
35//! // Decapsulate the shared key and verify that it was faithfully received.
36//! let k_recv = dk.decapsulate(&ct).unwrap();
37//! assert_eq!(k_send, k_recv);
38//! ```
39//!
40//! [RFC 9180]: https://www.rfc-editor.org/info/rfc9180
41
42/// The inevitable utility module
43mod util;
44
45/// Section 2.4. Interpreting the Pseudocode
46/// Section 4.2.2. Sampling algorithms
47/// Section 4.3. The Number-Theoretic Transform
48mod algebra;
49
50/// Section 4.1. Crytographic Functions
51mod crypto;
52
53/// Section 4.2.1. Conversion and Compression Algorithms, Compression and decompression
54mod compress;
55
56/// Section 4.2.1. Conversion and Compression Algorithms, Encoding and decoding
57mod encode;
58
59/// Section 5. The K-PKE Component Scheme
60mod pke;
61
62/// Section 6. The ML-KEM Key-Encapsulation Mechanism
63pub mod kem;
64
65/// Section 7. Parameter Sets
66mod param;
67
68use ::kem::{Decapsulate, Encapsulate};
69use core::fmt::Debug;
70use hybrid_array::{
71 typenum::{U10, U11, U2, U3, U4, U5},
72 Array,
73};
74use rand_core::CryptoRngCore;
75
76pub use hybrid_array as array;
77
78#[cfg(feature = "deterministic")]
79pub use util::B32;
80
81pub use param::{ArraySize, ParameterSet};
82
83/// An object that knows what size it is
84pub trait EncodedSizeUser {
85 /// The size of an encoded object
86 type EncodedSize: ArraySize;
87
88 /// Parse an object from its encoded form
89 fn from_bytes(enc: &Encoded<Self>) -> Self;
90
91 /// Serialize an object to its encoded form
92 fn as_bytes(&self) -> Encoded<Self>;
93}
94
95/// A byte array encoding a value the indicated size
96pub type Encoded<T> = Array<u8, <T as EncodedSizeUser>::EncodedSize>;
97
98/// A value that can be encapsulated to. Note that this interface is not safe: In order for the
99/// KEM to be secure, the `m` input must be randomly generated.
100#[cfg(feature = "deterministic")]
101pub trait EncapsulateDeterministic<EK, SS> {
102 /// Encapsulation error
103 type Error: Debug;
104
105 /// Encapsulates a fresh shared secret.
106 ///
107 /// # Errors
108 ///
109 /// Will vary depending on the underlying implementation.
110 fn encapsulate_deterministic(&self, m: &B32) -> Result<(EK, SS), Self::Error>;
111}
112
113/// A generic interface to a Key Encapsulation Method
114pub trait KemCore {
115 /// The size of a shared key generated by this KEM
116 type SharedKeySize: ArraySize;
117
118 /// The size of a ciphertext encapsulating a shared key
119 type CiphertextSize: ArraySize;
120
121 /// A decapsulation key for this KEM
122 type DecapsulationKey: Decapsulate<Ciphertext<Self>, SharedKey<Self>>
123 + EncodedSizeUser
124 + Debug
125 + PartialEq;
126
127 /// An encapsulation key for this KEM
128 #[cfg(not(feature = "deterministic"))]
129 type EncapsulationKey: Encapsulate<Ciphertext<Self>, SharedKey<Self>>
130 + EncodedSizeUser
131 + Debug
132 + PartialEq;
133
134 /// An encapsulation key for this KEM
135 #[cfg(feature = "deterministic")]
136 type EncapsulationKey: Encapsulate<Ciphertext<Self>, SharedKey<Self>>
137 + EncapsulateDeterministic<Ciphertext<Self>, SharedKey<Self>>
138 + EncodedSizeUser
139 + Debug
140 + PartialEq;
141
142 /// Generate a new (decapsulation, encapsulation) key pair
143 fn generate(rng: &mut impl CryptoRngCore) -> (Self::DecapsulationKey, Self::EncapsulationKey);
144
145 /// Generate a new (decapsulation, encapsulation) key pair deterministically
146 #[cfg(feature = "deterministic")]
147 fn generate_deterministic(d: &B32, z: &B32)
148 -> (Self::DecapsulationKey, Self::EncapsulationKey);
149}
150
151/// `MlKem512` is the parameter set for security category 1, corresponding to key search on a block
152/// cipher with a 128-bit key.
153#[derive(Default, Clone, Debug, PartialEq)]
154pub struct MlKem512Params;
155
156impl ParameterSet for MlKem512Params {
157 type K = U2;
158 type Eta1 = U3;
159 type Eta2 = U2;
160 type Du = U10;
161 type Dv = U4;
162}
163
164/// `MlKem768` is the parameter set for security category 3, corresponding to key search on a block
165/// cipher with a 192-bit key.
166#[derive(Default, Clone, Debug, PartialEq)]
167pub struct MlKem768Params;
168
169impl ParameterSet for MlKem768Params {
170 type K = U3;
171 type Eta1 = U2;
172 type Eta2 = U2;
173 type Du = U10;
174 type Dv = U4;
175}
176
177/// `MlKem1024` is the parameter set for security category 5, corresponding to key search on a block
178/// cipher with a 256-bit key.
179#[derive(Default, Clone, Debug, PartialEq)]
180pub struct MlKem1024Params;
181
182impl ParameterSet for MlKem1024Params {
183 type K = U4;
184 type Eta1 = U2;
185 type Eta2 = U2;
186 type Du = U11;
187 type Dv = U5;
188}
189
190/// A shared key produced by the KEM `K`
191pub type SharedKey<K> = Array<u8, <K as KemCore>::SharedKeySize>;
192
193/// A ciphertext produced by the KEM `K`
194pub type Ciphertext<K> = Array<u8, <K as KemCore>::CiphertextSize>;
195
196/// ML-KEM with the parameter set for security category 1, corresponding to key search on a block
197/// cipher with a 128-bit key.
198pub type MlKem512 = kem::Kem<MlKem512Params>;
199
200/// ML-KEM with the parameter set for security category 3, corresponding to key search on a block
201/// cipher with a 192-bit key.
202pub type MlKem768 = kem::Kem<MlKem768Params>;
203
204/// ML-KEM with the parameter set for security category 5, corresponding to key search on a block
205/// cipher with a 256-bit key.
206pub type MlKem1024 = kem::Kem<MlKem1024Params>;
207
208#[cfg(test)]
209mod test {
210 use super::*;
211
212 fn round_trip_test<K>()
213 where
214 K: KemCore,
215 {
216 let mut rng = rand::thread_rng();
217
218 let (dk, ek) = K::generate(&mut rng);
219
220 let (ct, k_send) = ek.encapsulate(&mut rng).unwrap();
221 let k_recv = dk.decapsulate(&ct).unwrap();
222 assert_eq!(k_send, k_recv);
223 }
224
225 #[test]
226 fn round_trip() {
227 round_trip_test::<MlKem512>();
228 round_trip_test::<MlKem768>();
229 round_trip_test::<MlKem1024>();
230 }
231}