Line | Count | Source |
1 | | #![no_std] |
2 | | #![deny(clippy::pedantic, warnings, missing_docs, unsafe_code)] |
3 | | // Most of the 'allow' category... |
4 | | #![deny(absolute_paths_not_starting_with_crate, dead_code)] |
5 | | #![deny(elided_lifetimes_in_paths, explicit_outlives_requirements, keyword_idents)] |
6 | | #![deny(let_underscore_drop, macro_use_extern_crate, meta_variable_misuse, missing_abi)] |
7 | | #![deny(non_ascii_idents, rust_2021_incompatible_closure_captures)] |
8 | | #![deny(rust_2021_incompatible_or_patterns, rust_2021_prefixes_incompatible_syntax)] |
9 | | #![deny(rust_2021_prelude_collisions, single_use_lifetimes, trivial_casts)] |
10 | | #![deny(trivial_numeric_casts, unreachable_pub, unsafe_op_in_unsafe_fn, unstable_features)] |
11 | | #![deny(unused_extern_crates, unused_import_braces, unused_lifetimes, unused_macro_rules)] |
12 | | #![deny(unused_qualifications, unused_results, variant_size_differences)] |
13 | | // |
14 | | #![doc = include_str!("../README.md")] |
15 | | |
16 | | // Implements FIPS 203 Module-Lattice-based Key-Encapsulation Mechanism Standard. |
17 | | // See <https://nvlpubs.nist.gov/nistpubs/FIPS/NIST.FIPS.203.pdf> |
18 | | |
19 | | // TODO Roadmap |
20 | | // 1. Expand test coverage, looping test w/ check, add report badge |
21 | | // 2. Perf: optimize/minimize modular reductions, minimize u16 arith, consider avx2/aarch64 |
22 | | // (currently, code is 'optimized' for safety and change-support, with reasonable perf) |
23 | | // 3. Slightly more intelligent fuzzing (e.g., as dk contains h(ek)) |
24 | | |
25 | | // Functionality map per FIPS 203 |
26 | | // |
27 | | // Algorithm 1 ForExample() --> example only (byte_fns.rs) |
28 | | // Algorithm 2 SHAKE128example(str1, β¦, strπ, π_1, β¦, π_β) --> example only (byte_fns.rs) |
29 | | // Algorithm 3 BitsToBytes(b) on page 20 --> optimized out (byte_fns.rs) |
30 | | // Algorithm 4 BytesToBits(B) on page 20 --> optimized out (byte_fns.rs) |
31 | | // Algorithm 5 ByteEncode_d(F) on page 22 --> byte_fns.rs |
32 | | // Algorithm 6 ByteDecode_d(B) on page 22 --> byte_fns.rs |
33 | | // Algorithm 7 SampleNTT(B) on page 23 --> sampling.rs |
34 | | // Algorithm 8 SamplePolyCBD_Ξ·(B) on page 23 --> sampling.rs |
35 | | // Algorithm 9 NTT(f) on page 26 --> ntt.rs |
36 | | // Algorithm 10 NTTβ1(fΛ) on page 26 --> ntt.rs |
37 | | // Algorithm 11 MultiplyNTTs(fΛ,Δ) on page 27 --> ntt.rs |
38 | | // Algorithm 12 BaseCaseMultiply(a0,a1,b0,b1,Ξ³) on page 27 --> ntt.rs |
39 | | // Algorithm 13 K-PKE.KeyGen() on page 29 --> k_pke.rs |
40 | | // Algorithm 14 K-PKE.Encrypt(ek_PKE,m,r) on page 30 --> k_pke.rs |
41 | | // Algorithm 15 K-PKE.Decrypt(dk_PKE,c) on page 31 --> k_pke.rs |
42 | | // Algorithm 16 ML-KEM.KeyGen_internal(d,z) on page 32 --> ml_kem.rs |
43 | | // Algorithm 17 ML-KEM.Encaps_internal(ek,m) on page 33 --> ml_kem.rs |
44 | | // Algorithm 18 ML-KEM.Decaps_internal(dk,c) on page 34 --> ml_kem.rs |
45 | | // Algorithm 19 ML-KEM.KeyGen() on page 35 --> ml_kem.rs |
46 | | // Algorithm 20 ML-KEM.Encaps(ek) on page 37 --> ml_kem.rs |
47 | | // Algorithm 21 ML-KEM.Decaps(dk,c) on page 38 --> ml_kem.rs |
48 | | // PRF and XOF on page 18/19 --> helpers.rs |
49 | | // Three hash functions: G, H, J on page 18/19 --> helpers.rs |
50 | | // Compress and Decompress on page 21 --> helpers.rs |
51 | | // |
52 | | // The three security parameter sets are modules in this file with injected macro code that |
53 | | // connects them into the functionality in ml_kem.rs. Some of the 'obtuse' coding style is |
54 | | // driven by `clippy pedantic`. This code has been confirmed as constant-time (outside of |
55 | | // rho) via manual inspection, ./fips203/dudect and ./fips203/ct_cm4 functionality (other |
56 | | // than the `validate_keypair_vartime()` functions). |
57 | | // |
58 | | // Note that the use of generics has been constrained to storage allocation purposes, |
59 | | // only e.g. `[0u8; EK_LEN];` (where arithmetic expressions are not allowed), while the |
60 | | // remainder of the security parameters are generally passed as normal function parameters. |
61 | | // |
62 | | // The ensure!() instances are for validation purposes and cannot be turned off. The |
63 | | // debug_assert!() instances are (effectively) targeted by the fuzzer in /fips203/fuzz and |
64 | | // will support quicker future changes/fixes from any FIPS 203 specification update. |
65 | | |
66 | | |
67 | | /// These `rand_core` types are re-exported so that users of fips203 do not |
68 | | /// have to worry about using the exactly correct version of `rand_core`. |
69 | | pub use rand_core::{CryptoRng, Error as RngError, RngCore}; |
70 | | |
71 | | use crate::traits::SerDes; |
72 | | use subtle::ConstantTimeEq; |
73 | | use zeroize::{Zeroize, ZeroizeOnDrop}; |
74 | | |
75 | | mod byte_fns; |
76 | | mod helpers; |
77 | | mod k_pke; |
78 | | mod ml_kem; |
79 | | mod ntt; |
80 | | mod sampling; |
81 | | mod types; |
82 | | |
83 | | /// All functionality is covered by traits, such that consumers can utilize trait objects if desired. |
84 | | pub mod traits; |
85 | | |
86 | | // Relevant to all parameter sets |
87 | | const Q: u16 = 3329; |
88 | | const ZETA: u16 = 17; |
89 | | |
90 | | |
91 | | /// Shared Secret Key length for all ML-KEM variants (in bytes) |
92 | | pub const SSK_LEN: usize = 32; |
93 | | |
94 | | /// The (opaque) secret key that can be de/serialized by each party. |
95 | | #[derive(Clone, Debug, Zeroize, ZeroizeOnDrop)] |
96 | | pub struct SharedSecretKey([u8; SSK_LEN]); |
97 | | |
98 | | |
99 | | impl SerDes for SharedSecretKey { |
100 | | type ByteArray = [u8; SSK_LEN]; |
101 | | |
102 | 843 | fn into_bytes(self) -> Self::ByteArray { self.0 } |
103 | | |
104 | | // While this function never fails for `SharedSecretKey`, it includes the `try_` prefix |
105 | | // to maintain alignment with the SerDes trait (alongside all the other objects) and to |
106 | | // retains the opportunity for future validation. |
107 | 843 | fn try_from_bytes(ssk: Self::ByteArray) -> Result<Self, &'static str> { |
108 | 843 | Ok(SharedSecretKey(ssk)) |
109 | 843 | } |
110 | | } |
111 | | |
112 | | |
113 | | // Conservative constant-time support |
114 | | impl PartialEq for SharedSecretKey { |
115 | 732 | fn eq(&self, other: &Self) -> bool { bool::from(self.0.ct_eq(&other.0)) } |
116 | | } |
117 | | |
118 | | |
119 | | // This common functionality is injected into each parameter set module |
120 | | macro_rules! functionality { |
121 | | () => { |
122 | | use crate::byte_fns::byte_decode; |
123 | | use crate::helpers::{ensure, h}; |
124 | | use crate::ml_kem::{ |
125 | | ml_kem_decaps, ml_kem_encaps, ml_kem_key_gen, ml_kem_key_gen_internal, |
126 | | }; |
127 | | use crate::traits::{Decaps, Encaps, KeyGen, SerDes}; |
128 | | use crate::SharedSecretKey; |
129 | | use rand_core::CryptoRngCore; |
130 | | |
131 | | |
132 | | /// Correctly sized encapsulation key specific to the target security parameter set. |
133 | | pub type EncapsKey = crate::types::EncapsKey<EK_LEN>; |
134 | | |
135 | | /// Correctly sized decapsulation key specific to the target security parameter set. |
136 | | pub type DecapsKey = crate::types::DecapsKey<DK_LEN>; |
137 | | |
138 | | /// Correctly sized ciphertext specific to the target security parameter set. |
139 | | pub type CipherText = crate::types::CipherText<CT_LEN>; |
140 | | |
141 | | /// Supports the `KeyGen` trait, allowing for keypair generation |
142 | | pub struct KG(); |
143 | | |
144 | | |
145 | | impl KeyGen for KG { |
146 | | type DecapsByteArray = [u8; DK_LEN]; |
147 | | type DecapsKey = DecapsKey; |
148 | | type EncapsByteArray = [u8; EK_LEN]; |
149 | | type EncapsKey = EncapsKey; |
150 | | |
151 | 732 | fn try_keygen_with_rng( |
152 | 732 | rng: &mut impl CryptoRngCore, |
153 | 732 | ) -> Result<(EncapsKey, DecapsKey), &'static str> { |
154 | 732 | let (mut ek, mut dk) = ([0u8; EK_LEN], [0u8; DK_LEN]); |
155 | 732 | ml_kem_key_gen::<K, { ETA1 as usize * 64 }>(rng, &mut ek, &mut dk)?; |
156 | 732 | Ok((EncapsKey { 0: ek }, DecapsKey { 0: dk })) |
157 | 732 | } <fips203::ml_kem_512::KG as fips203::traits::KeyGen>::try_keygen_with_rng::<ml_kem_fuzz::_::__libfuzzer_sys_run::TestRng> Line | Count | Source | 151 | 244 | fn try_keygen_with_rng( | 152 | 244 | rng: &mut impl CryptoRngCore, | 153 | 244 | ) -> Result<(EncapsKey, DecapsKey), &'static str> { | 154 | 244 | let (mut ek, mut dk) = ([0u8; EK_LEN], [0u8; DK_LEN]); | 155 | 244 | ml_kem_key_gen::<K, { ETA1 as usize * 64 }>(rng, &mut ek, &mut dk)?; | 156 | 244 | Ok((EncapsKey { 0: ek }, DecapsKey { 0: dk })) | 157 | 244 | } |
<fips203::ml_kem_1024::KG as fips203::traits::KeyGen>::try_keygen_with_rng::<rand_core::os::OsRng> Line | Count | Source | 151 | 244 | fn try_keygen_with_rng( | 152 | 244 | rng: &mut impl CryptoRngCore, | 153 | 244 | ) -> Result<(EncapsKey, DecapsKey), &'static str> { | 154 | 244 | let (mut ek, mut dk) = ([0u8; EK_LEN], [0u8; DK_LEN]); | 155 | 244 | ml_kem_key_gen::<K, { ETA1 as usize * 64 }>(rng, &mut ek, &mut dk)?; | 156 | 244 | Ok((EncapsKey { 0: ek }, DecapsKey { 0: dk })) | 157 | 244 | } |
<fips203::ml_kem_768::KG as fips203::traits::KeyGen>::try_keygen_with_rng::<ml_kem_fuzz::_::__libfuzzer_sys_run::TestRng> Line | Count | Source | 151 | 244 | fn try_keygen_with_rng( | 152 | 244 | rng: &mut impl CryptoRngCore, | 153 | 244 | ) -> Result<(EncapsKey, DecapsKey), &'static str> { | 154 | 244 | let (mut ek, mut dk) = ([0u8; EK_LEN], [0u8; DK_LEN]); | 155 | 244 | ml_kem_key_gen::<K, { ETA1 as usize * 64 }>(rng, &mut ek, &mut dk)?; | 156 | 244 | Ok((EncapsKey { 0: ek }, DecapsKey { 0: dk })) | 157 | 244 | } |
Unexecuted instantiation: <fips203::ml_kem_512::KG as fips203::traits::KeyGen>::try_keygen_with_rng::<_> Unexecuted instantiation: <fips203::ml_kem_768::KG as fips203::traits::KeyGen>::try_keygen_with_rng::<_> Unexecuted instantiation: <fips203::ml_kem_1024::KG as fips203::traits::KeyGen>::try_keygen_with_rng::<_> |
158 | | |
159 | 1.41k | fn keygen_from_seed(d: [u8; 32], z: [u8; 32]) -> (EncapsKey, DecapsKey) { |
160 | 1.41k | let (mut ek, mut dk) = ([0u8; EK_LEN], [0u8; DK_LEN]); |
161 | 1.41k | ml_kem_key_gen_internal::<K, { ETA1 as usize * 64 }>(d, z, &mut ek, &mut dk); |
162 | 1.41k | (EncapsKey { 0: ek }, DecapsKey { 0: dk }) |
163 | 1.41k | } <fips203::ml_kem_512::KG as fips203::traits::KeyGen>::keygen_from_seed Line | Count | Source | 159 | 471 | fn keygen_from_seed(d: [u8; 32], z: [u8; 32]) -> (EncapsKey, DecapsKey) { | 160 | 471 | let (mut ek, mut dk) = ([0u8; EK_LEN], [0u8; DK_LEN]); | 161 | 471 | ml_kem_key_gen_internal::<K, { ETA1 as usize * 64 }>(d, z, &mut ek, &mut dk); | 162 | 471 | (EncapsKey { 0: ek }, DecapsKey { 0: dk }) | 163 | 471 | } |
<fips203::ml_kem_1024::KG as fips203::traits::KeyGen>::keygen_from_seed Line | Count | Source | 159 | 471 | fn keygen_from_seed(d: [u8; 32], z: [u8; 32]) -> (EncapsKey, DecapsKey) { | 160 | 471 | let (mut ek, mut dk) = ([0u8; EK_LEN], [0u8; DK_LEN]); | 161 | 471 | ml_kem_key_gen_internal::<K, { ETA1 as usize * 64 }>(d, z, &mut ek, &mut dk); | 162 | 471 | (EncapsKey { 0: ek }, DecapsKey { 0: dk }) | 163 | 471 | } |
<fips203::ml_kem_768::KG as fips203::traits::KeyGen>::keygen_from_seed Line | Count | Source | 159 | 471 | fn keygen_from_seed(d: [u8; 32], z: [u8; 32]) -> (EncapsKey, DecapsKey) { | 160 | 471 | let (mut ek, mut dk) = ([0u8; EK_LEN], [0u8; DK_LEN]); | 161 | 471 | ml_kem_key_gen_internal::<K, { ETA1 as usize * 64 }>(d, z, &mut ek, &mut dk); | 162 | 471 | (EncapsKey { 0: ek }, DecapsKey { 0: dk }) | 163 | 471 | } |
|
164 | | |
165 | 732 | fn validate_keypair_with_rng_vartime( |
166 | 732 | rng: &mut impl CryptoRngCore, ek: &Self::EncapsByteArray, |
167 | 732 | dk: &Self::DecapsByteArray, |
168 | 732 | ) -> bool { |
169 | | // Note that size is checked by only accepting a ref to a correctly sized byte array |
170 | 732 | let len_ek_pke = 384 * K + 32; |
171 | 732 | let len_dk_pke = 384 * K; |
172 | | // 1. dk should contain ek |
173 | 732 | if !(*ek == dk[len_dk_pke..(len_dk_pke + len_ek_pke)]) { |
174 | 0 | return false; |
175 | 732 | }; |
176 | | // 2. dk should contain hash of ek |
177 | 732 | if !(h(ek) == dk[(len_dk_pke + len_ek_pke)..(len_dk_pke + len_ek_pke + 32)]) { |
178 | 0 | return false; |
179 | 732 | }; |
180 | | // 3. ek and dk should deserialize ok |
181 | 732 | let ek = EncapsKey::try_from_bytes(*ek); |
182 | 732 | let dk = DecapsKey::try_from_bytes(*dk); |
183 | 732 | if ek.is_err() || dk.is_err() { |
184 | 0 | return false; |
185 | 732 | }; |
186 | | // 4. encaps should run without a problem |
187 | 732 | let ek_res = ek.unwrap().try_encaps_with_rng(rng); |
188 | 732 | if ek_res.is_err() { |
189 | 0 | return false; |
190 | 732 | }; |
191 | | // 5. decaps should run without a problem |
192 | 732 | let dk_res = dk.unwrap().try_decaps(&ek_res.as_ref().unwrap().1); |
193 | 732 | if dk_res.is_err() { |
194 | 0 | return false; |
195 | 732 | }; |
196 | | // 6. encaps and decaps should produce the same shared secret |
197 | 732 | return ek_res.unwrap().0 == dk_res.unwrap(); |
198 | 732 | } <fips203::ml_kem_512::KG as fips203::traits::KeyGen>::validate_keypair_with_rng_vartime::<ml_kem_fuzz::_::__libfuzzer_sys_run::TestRng> Line | Count | Source | 165 | 244 | fn validate_keypair_with_rng_vartime( | 166 | 244 | rng: &mut impl CryptoRngCore, ek: &Self::EncapsByteArray, | 167 | 244 | dk: &Self::DecapsByteArray, | 168 | 244 | ) -> bool { | 169 | | // Note that size is checked by only accepting a ref to a correctly sized byte array | 170 | 244 | let len_ek_pke = 384 * K + 32; | 171 | 244 | let len_dk_pke = 384 * K; | 172 | | // 1. dk should contain ek | 173 | 244 | if !(*ek == dk[len_dk_pke..(len_dk_pke + len_ek_pke)]) { | 174 | 0 | return false; | 175 | 244 | }; | 176 | | // 2. dk should contain hash of ek | 177 | 244 | if !(h(ek) == dk[(len_dk_pke + len_ek_pke)..(len_dk_pke + len_ek_pke + 32)]) { | 178 | 0 | return false; | 179 | 244 | }; | 180 | | // 3. ek and dk should deserialize ok | 181 | 244 | let ek = EncapsKey::try_from_bytes(*ek); | 182 | 244 | let dk = DecapsKey::try_from_bytes(*dk); | 183 | 244 | if ek.is_err() || dk.is_err() { | 184 | 0 | return false; | 185 | 244 | }; | 186 | | // 4. encaps should run without a problem | 187 | 244 | let ek_res = ek.unwrap().try_encaps_with_rng(rng); | 188 | 244 | if ek_res.is_err() { | 189 | 0 | return false; | 190 | 244 | }; | 191 | | // 5. decaps should run without a problem | 192 | 244 | let dk_res = dk.unwrap().try_decaps(&ek_res.as_ref().unwrap().1); | 193 | 244 | if dk_res.is_err() { | 194 | 0 | return false; | 195 | 244 | }; | 196 | | // 6. encaps and decaps should produce the same shared secret | 197 | 244 | return ek_res.unwrap().0 == dk_res.unwrap(); | 198 | 244 | } |
<fips203::ml_kem_1024::KG as fips203::traits::KeyGen>::validate_keypair_with_rng_vartime::<ml_kem_fuzz::_::__libfuzzer_sys_run::TestRng> Line | Count | Source | 165 | 244 | fn validate_keypair_with_rng_vartime( | 166 | 244 | rng: &mut impl CryptoRngCore, ek: &Self::EncapsByteArray, | 167 | 244 | dk: &Self::DecapsByteArray, | 168 | 244 | ) -> bool { | 169 | | // Note that size is checked by only accepting a ref to a correctly sized byte array | 170 | 244 | let len_ek_pke = 384 * K + 32; | 171 | 244 | let len_dk_pke = 384 * K; | 172 | | // 1. dk should contain ek | 173 | 244 | if !(*ek == dk[len_dk_pke..(len_dk_pke + len_ek_pke)]) { | 174 | 0 | return false; | 175 | 244 | }; | 176 | | // 2. dk should contain hash of ek | 177 | 244 | if !(h(ek) == dk[(len_dk_pke + len_ek_pke)..(len_dk_pke + len_ek_pke + 32)]) { | 178 | 0 | return false; | 179 | 244 | }; | 180 | | // 3. ek and dk should deserialize ok | 181 | 244 | let ek = EncapsKey::try_from_bytes(*ek); | 182 | 244 | let dk = DecapsKey::try_from_bytes(*dk); | 183 | 244 | if ek.is_err() || dk.is_err() { | 184 | 0 | return false; | 185 | 244 | }; | 186 | | // 4. encaps should run without a problem | 187 | 244 | let ek_res = ek.unwrap().try_encaps_with_rng(rng); | 188 | 244 | if ek_res.is_err() { | 189 | 0 | return false; | 190 | 244 | }; | 191 | | // 5. decaps should run without a problem | 192 | 244 | let dk_res = dk.unwrap().try_decaps(&ek_res.as_ref().unwrap().1); | 193 | 244 | if dk_res.is_err() { | 194 | 0 | return false; | 195 | 244 | }; | 196 | | // 6. encaps and decaps should produce the same shared secret | 197 | 244 | return ek_res.unwrap().0 == dk_res.unwrap(); | 198 | 244 | } |
<fips203::ml_kem_768::KG as fips203::traits::KeyGen>::validate_keypair_with_rng_vartime::<ml_kem_fuzz::_::__libfuzzer_sys_run::TestRng> Line | Count | Source | 165 | 244 | fn validate_keypair_with_rng_vartime( | 166 | 244 | rng: &mut impl CryptoRngCore, ek: &Self::EncapsByteArray, | 167 | 244 | dk: &Self::DecapsByteArray, | 168 | 244 | ) -> bool { | 169 | | // Note that size is checked by only accepting a ref to a correctly sized byte array | 170 | 244 | let len_ek_pke = 384 * K + 32; | 171 | 244 | let len_dk_pke = 384 * K; | 172 | | // 1. dk should contain ek | 173 | 244 | if !(*ek == dk[len_dk_pke..(len_dk_pke + len_ek_pke)]) { | 174 | 0 | return false; | 175 | 244 | }; | 176 | | // 2. dk should contain hash of ek | 177 | 244 | if !(h(ek) == dk[(len_dk_pke + len_ek_pke)..(len_dk_pke + len_ek_pke + 32)]) { | 178 | 0 | return false; | 179 | 244 | }; | 180 | | // 3. ek and dk should deserialize ok | 181 | 244 | let ek = EncapsKey::try_from_bytes(*ek); | 182 | 244 | let dk = DecapsKey::try_from_bytes(*dk); | 183 | 244 | if ek.is_err() || dk.is_err() { | 184 | 0 | return false; | 185 | 244 | }; | 186 | | // 4. encaps should run without a problem | 187 | 244 | let ek_res = ek.unwrap().try_encaps_with_rng(rng); | 188 | 244 | if ek_res.is_err() { | 189 | 0 | return false; | 190 | 244 | }; | 191 | | // 5. decaps should run without a problem | 192 | 244 | let dk_res = dk.unwrap().try_decaps(&ek_res.as_ref().unwrap().1); | 193 | 244 | if dk_res.is_err() { | 194 | 0 | return false; | 195 | 244 | }; | 196 | | // 6. encaps and decaps should produce the same shared secret | 197 | 244 | return ek_res.unwrap().0 == dk_res.unwrap(); | 198 | 244 | } |
Unexecuted instantiation: <fips203::ml_kem_512::KG as fips203::traits::KeyGen>::validate_keypair_with_rng_vartime::<_> Unexecuted instantiation: <fips203::ml_kem_768::KG as fips203::traits::KeyGen>::validate_keypair_with_rng_vartime::<_> Unexecuted instantiation: <fips203::ml_kem_1024::KG as fips203::traits::KeyGen>::validate_keypair_with_rng_vartime::<_> |
199 | | } |
200 | | |
201 | | |
202 | | impl Encaps for EncapsKey { |
203 | | type CipherText = CipherText; |
204 | | type SharedSecretKey = SharedSecretKey; |
205 | | |
206 | 1.81k | fn try_encaps_with_rng( |
207 | 1.81k | &self, rng: &mut impl CryptoRngCore, |
208 | 1.81k | ) -> Result<(Self::SharedSecretKey, Self::CipherText), &'static str> { |
209 | 1.81k | let mut ct = [0u8; CT_LEN]; |
210 | 1.81k | let ssk = ml_kem_encaps::<K, { ETA1 as usize * 64 }, { ETA2 as usize * 64 }>( |
211 | 1.81k | rng, DU, DV, &self.0, &mut ct, |
212 | 0 | )?; |
213 | 1.81k | Ok((ssk, CipherText { 0: ct })) |
214 | 1.81k | } <fips203::types::EncapsKey<800> as fips203::traits::Encaps>::try_encaps_with_rng::<fips203::traits::DummyRng> Line | Count | Source | 206 | 281 | fn try_encaps_with_rng( | 207 | 281 | &self, rng: &mut impl CryptoRngCore, | 208 | 281 | ) -> Result<(Self::SharedSecretKey, Self::CipherText), &'static str> { | 209 | 281 | let mut ct = [0u8; CT_LEN]; | 210 | 281 | let ssk = ml_kem_encaps::<K, { ETA1 as usize * 64 }, { ETA2 as usize * 64 }>( | 211 | 281 | rng, DU, DV, &self.0, &mut ct, | 212 | 0 | )?; | 213 | 281 | Ok((ssk, CipherText { 0: ct })) | 214 | 281 | } |
<fips203::types::EncapsKey<800> as fips203::traits::Encaps>::try_encaps_with_rng::<ml_kem_fuzz::_::__libfuzzer_sys_run::TestRng> Line | Count | Source | 206 | 244 | fn try_encaps_with_rng( | 207 | 244 | &self, rng: &mut impl CryptoRngCore, | 208 | 244 | ) -> Result<(Self::SharedSecretKey, Self::CipherText), &'static str> { | 209 | 244 | let mut ct = [0u8; CT_LEN]; | 210 | 244 | let ssk = ml_kem_encaps::<K, { ETA1 as usize * 64 }, { ETA2 as usize * 64 }>( | 211 | 244 | rng, DU, DV, &self.0, &mut ct, | 212 | 0 | )?; | 213 | 244 | Ok((ssk, CipherText { 0: ct })) | 214 | 244 | } |
<fips203::types::EncapsKey<1184> as fips203::traits::Encaps>::try_encaps_with_rng::<fips203::traits::DummyRng> Line | Count | Source | 206 | 281 | fn try_encaps_with_rng( | 207 | 281 | &self, rng: &mut impl CryptoRngCore, | 208 | 281 | ) -> Result<(Self::SharedSecretKey, Self::CipherText), &'static str> { | 209 | 281 | let mut ct = [0u8; CT_LEN]; | 210 | 281 | let ssk = ml_kem_encaps::<K, { ETA1 as usize * 64 }, { ETA2 as usize * 64 }>( | 211 | 281 | rng, DU, DV, &self.0, &mut ct, | 212 | 0 | )?; | 213 | 281 | Ok((ssk, CipherText { 0: ct })) | 214 | 281 | } |
<fips203::types::EncapsKey<1184> as fips203::traits::Encaps>::try_encaps_with_rng::<ml_kem_fuzz::_::__libfuzzer_sys_run::TestRng> Line | Count | Source | 206 | 244 | fn try_encaps_with_rng( | 207 | 244 | &self, rng: &mut impl CryptoRngCore, | 208 | 244 | ) -> Result<(Self::SharedSecretKey, Self::CipherText), &'static str> { | 209 | 244 | let mut ct = [0u8; CT_LEN]; | 210 | 244 | let ssk = ml_kem_encaps::<K, { ETA1 as usize * 64 }, { ETA2 as usize * 64 }>( | 211 | 244 | rng, DU, DV, &self.0, &mut ct, | 212 | 0 | )?; | 213 | 244 | Ok((ssk, CipherText { 0: ct })) | 214 | 244 | } |
<fips203::types::EncapsKey<1568> as fips203::traits::Encaps>::try_encaps_with_rng::<fips203::traits::DummyRng> Line | Count | Source | 206 | 281 | fn try_encaps_with_rng( | 207 | 281 | &self, rng: &mut impl CryptoRngCore, | 208 | 281 | ) -> Result<(Self::SharedSecretKey, Self::CipherText), &'static str> { | 209 | 281 | let mut ct = [0u8; CT_LEN]; | 210 | 281 | let ssk = ml_kem_encaps::<K, { ETA1 as usize * 64 }, { ETA2 as usize * 64 }>( | 211 | 281 | rng, DU, DV, &self.0, &mut ct, | 212 | 0 | )?; | 213 | 281 | Ok((ssk, CipherText { 0: ct })) | 214 | 281 | } |
<fips203::types::EncapsKey<1568> as fips203::traits::Encaps>::try_encaps_with_rng::<rand_core::os::OsRng> Line | Count | Source | 206 | 244 | fn try_encaps_with_rng( | 207 | 244 | &self, rng: &mut impl CryptoRngCore, | 208 | 244 | ) -> Result<(Self::SharedSecretKey, Self::CipherText), &'static str> { | 209 | 244 | let mut ct = [0u8; CT_LEN]; | 210 | 244 | let ssk = ml_kem_encaps::<K, { ETA1 as usize * 64 }, { ETA2 as usize * 64 }>( | 211 | 244 | rng, DU, DV, &self.0, &mut ct, | 212 | 0 | )?; | 213 | 244 | Ok((ssk, CipherText { 0: ct })) | 214 | 244 | } |
<fips203::types::EncapsKey<1568> as fips203::traits::Encaps>::try_encaps_with_rng::<ml_kem_fuzz::_::__libfuzzer_sys_run::TestRng> Line | Count | Source | 206 | 244 | fn try_encaps_with_rng( | 207 | 244 | &self, rng: &mut impl CryptoRngCore, | 208 | 244 | ) -> Result<(Self::SharedSecretKey, Self::CipherText), &'static str> { | 209 | 244 | let mut ct = [0u8; CT_LEN]; | 210 | 244 | let ssk = ml_kem_encaps::<K, { ETA1 as usize * 64 }, { ETA2 as usize * 64 }>( | 211 | 244 | rng, DU, DV, &self.0, &mut ct, | 212 | 0 | )?; | 213 | 244 | Ok((ssk, CipherText { 0: ct })) | 214 | 244 | } |
Unexecuted instantiation: <fips203::types::EncapsKey<800> as fips203::traits::Encaps>::try_encaps_with_rng::<_> Unexecuted instantiation: <fips203::types::EncapsKey<1184> as fips203::traits::Encaps>::try_encaps_with_rng::<_> Unexecuted instantiation: <fips203::types::EncapsKey<1568> as fips203::traits::Encaps>::try_encaps_with_rng::<_> |
215 | | } |
216 | | |
217 | | |
218 | | impl Decaps for DecapsKey { |
219 | | type CipherText = CipherText; |
220 | | type SharedSecretKey = SharedSecretKey; |
221 | | |
222 | 1.53k | fn try_decaps(&self, ct: &CipherText) -> Result<SharedSecretKey, &'static str> { |
223 | 1.53k | let ssk = ml_kem_decaps::< |
224 | 1.53k | K, |
225 | 1.53k | { ETA1 as usize * 64 }, |
226 | 1.53k | { ETA2 as usize * 64 }, |
227 | 1.53k | { 32 + 32 * (DU as usize * K + DV as usize) }, |
228 | 1.53k | CT_LEN, |
229 | 1.53k | >(DU, DV, &self.0, &ct.0); |
230 | 1.53k | ssk |
231 | 1.53k | } <fips203::types::DecapsKey<1632> as fips203::traits::Decaps>::try_decaps Line | Count | Source | 222 | 525 | fn try_decaps(&self, ct: &CipherText) -> Result<SharedSecretKey, &'static str> { | 223 | 525 | let ssk = ml_kem_decaps::< | 224 | 525 | K, | 225 | 525 | { ETA1 as usize * 64 }, | 226 | 525 | { ETA2 as usize * 64 }, | 227 | 525 | { 32 + 32 * (DU as usize * K + DV as usize) }, | 228 | 525 | CT_LEN, | 229 | 525 | >(DU, DV, &self.0, &ct.0); | 230 | 525 | ssk | 231 | 525 | } |
<fips203::types::DecapsKey<2400> as fips203::traits::Decaps>::try_decaps Line | Count | Source | 222 | 514 | fn try_decaps(&self, ct: &CipherText) -> Result<SharedSecretKey, &'static str> { | 223 | 514 | let ssk = ml_kem_decaps::< | 224 | 514 | K, | 225 | 514 | { ETA1 as usize * 64 }, | 226 | 514 | { ETA2 as usize * 64 }, | 227 | 514 | { 32 + 32 * (DU as usize * K + DV as usize) }, | 228 | 514 | CT_LEN, | 229 | 514 | >(DU, DV, &self.0, &ct.0); | 230 | 514 | ssk | 231 | 514 | } |
<fips203::types::DecapsKey<3168> as fips203::traits::Decaps>::try_decaps Line | Count | Source | 222 | 500 | fn try_decaps(&self, ct: &CipherText) -> Result<SharedSecretKey, &'static str> { | 223 | 500 | let ssk = ml_kem_decaps::< | 224 | 500 | K, | 225 | 500 | { ETA1 as usize * 64 }, | 226 | 500 | { ETA2 as usize * 64 }, | 227 | 500 | { 32 + 32 * (DU as usize * K + DV as usize) }, | 228 | 500 | CT_LEN, | 229 | 500 | >(DU, DV, &self.0, &ct.0); | 230 | 500 | ssk | 231 | 500 | } |
|
232 | | } |
233 | | |
234 | | |
235 | | impl SerDes for EncapsKey { |
236 | | type ByteArray = [u8; EK_LEN]; |
237 | | |
238 | 2.08k | fn into_bytes(self) -> Self::ByteArray { self.0 }<fips203::types::EncapsKey<800> as fips203::traits::SerDes>::into_bytes Line | Count | Source | 238 | 715 | fn into_bytes(self) -> Self::ByteArray { self.0 } |
<fips203::types::EncapsKey<1184> as fips203::traits::SerDes>::into_bytes Line | Count | Source | 238 | 690 | fn into_bytes(self) -> Self::ByteArray { self.0 } |
<fips203::types::EncapsKey<1568> as fips203::traits::SerDes>::into_bytes Line | Count | Source | 238 | 682 | fn into_bytes(self) -> Self::ByteArray { self.0 } |
|
239 | | |
240 | 3.94k | fn try_from_bytes(ek: Self::ByteArray) -> Result<Self, &'static str> { |
241 | | // Validation per pg 36 #2 "This check ensures that the integers encoded |
242 | | // in the public key are in the valid range [0, π β 1]". Note that |
243 | | // accepting a byte array of fixed size, rather than a slice of varied |
244 | | // size, addresses check #1. |
245 | 15.5k | for i in 0..K { |
246 | 11.6k | let _ek_hat = byte_decode(12, &ek[384 * i..384 * (i + 1)])?; |
247 | | } |
248 | 3.90k | Ok(EncapsKey { 0: ek }) |
249 | 3.94k | } <fips203::types::EncapsKey<800> as fips203::traits::SerDes>::try_from_bytes Line | Count | Source | 240 | 1.39k | fn try_from_bytes(ek: Self::ByteArray) -> Result<Self, &'static str> { | 241 | | // Validation per pg 36 #2 "This check ensures that the integers encoded | 242 | | // in the public key are in the valid range [0, π β 1]". Note that | 243 | | // accepting a byte array of fixed size, rather than a slice of varied | 244 | | // size, addresses check #1. | 245 | 4.11k | for i in 0..K { | 246 | 2.75k | let _ek_hat = byte_decode(12, &ek[384 * i..384 * (i + 1)])?; | 247 | | } | 248 | 1.36k | Ok(EncapsKey { 0: ek }) | 249 | 1.39k | } |
<fips203::types::EncapsKey<1184> as fips203::traits::SerDes>::try_from_bytes Line | Count | Source | 240 | 1.30k | fn try_from_bytes(ek: Self::ByteArray) -> Result<Self, &'static str> { | 241 | | // Validation per pg 36 #2 "This check ensures that the integers encoded | 242 | | // in the public key are in the valid range [0, π β 1]". Note that | 243 | | // accepting a byte array of fixed size, rather than a slice of varied | 244 | | // size, addresses check #1. | 245 | 5.21k | for i in 0..K { | 246 | 3.91k | let _ek_hat = byte_decode(12, &ek[384 * i..384 * (i + 1)])?; | 247 | | } | 248 | 1.29k | Ok(EncapsKey { 0: ek }) | 249 | 1.30k | } |
<fips203::types::EncapsKey<1568> as fips203::traits::SerDes>::try_from_bytes Line | Count | Source | 240 | 1.24k | fn try_from_bytes(ek: Self::ByteArray) -> Result<Self, &'static str> { | 241 | | // Validation per pg 36 #2 "This check ensures that the integers encoded | 242 | | // in the public key are in the valid range [0, π β 1]". Note that | 243 | | // accepting a byte array of fixed size, rather than a slice of varied | 244 | | // size, addresses check #1. | 245 | 6.22k | for i in 0..K { | 246 | 4.98k | let _ek_hat = byte_decode(12, &ek[384 * i..384 * (i + 1)])?; | 247 | | } | 248 | 1.24k | Ok(EncapsKey { 0: ek }) | 249 | 1.24k | } |
|
250 | | } |
251 | | |
252 | | |
253 | | impl SerDes for DecapsKey { |
254 | | type ByteArray = [u8; DK_LEN]; |
255 | | |
256 | 1.86k | fn into_bytes(self) -> Self::ByteArray { self.0 }<fips203::types::DecapsKey<1632> as fips203::traits::SerDes>::into_bytes Line | Count | Source | 256 | 675 | fn into_bytes(self) -> Self::ByteArray { self.0 } |
<fips203::types::DecapsKey<2400> as fips203::traits::SerDes>::into_bytes Line | Count | Source | 256 | 618 | fn into_bytes(self) -> Self::ByteArray { self.0 } |
<fips203::types::DecapsKey<3168> as fips203::traits::SerDes>::into_bytes Line | Count | Source | 256 | 567 | fn into_bytes(self) -> Self::ByteArray { self.0 } |
|
257 | | |
258 | 1.86k | fn try_from_bytes(dk: Self::ByteArray) -> Result<Self, &'static str> { |
259 | | // Validation per pg 31. Note that the two checks specify fixed sizes, and these |
260 | | // functions take only byte arrays of correct size. Nonetheless, we take the |
261 | | // opportunity to validate the ek and h(ek). |
262 | 1.86k | let len_ek_pke = 384 * K + 32; |
263 | 1.86k | let len_dk_pke = 384 * K; |
264 | 1.86k | let ek = &dk[len_dk_pke..len_dk_pke + EK_LEN]; |
265 | 1.85k | let _res = |
266 | 1.86k | EncapsKey::try_from_bytes(ek.try_into().map_err(|_| "Malformed encaps key")?)?; |
267 | 1.85k | ensure!( |
268 | 1.85k | h(ek) == dk[(len_dk_pke + len_ek_pke)..(len_dk_pke + len_ek_pke + 32)], |
269 | 143 | "Encaps hash wrong" |
270 | | ); |
271 | 1.71k | Ok(DecapsKey { 0: dk }) |
272 | 1.86k | } <fips203::types::DecapsKey<1632> as fips203::traits::SerDes>::try_from_bytes Line | Count | Source | 258 | 675 | fn try_from_bytes(dk: Self::ByteArray) -> Result<Self, &'static str> { | 259 | | // Validation per pg 31. Note that the two checks specify fixed sizes, and these | 260 | | // functions take only byte arrays of correct size. Nonetheless, we take the | 261 | | // opportunity to validate the ek and h(ek). | 262 | 675 | let len_ek_pke = 384 * K + 32; | 263 | 675 | let len_dk_pke = 384 * K; | 264 | 675 | let ek = &dk[len_dk_pke..len_dk_pke + EK_LEN]; | 265 | 671 | let _res = | 266 | 675 | EncapsKey::try_from_bytes(ek.try_into().map_err(|_| "Malformed encaps key")?)?; | 267 | 671 | ensure!( | 268 | 671 | h(ek) == dk[(len_dk_pke + len_ek_pke)..(len_dk_pke + len_ek_pke + 32)], | 269 | 53 | "Encaps hash wrong" | 270 | | ); | 271 | 618 | Ok(DecapsKey { 0: dk }) | 272 | 675 | } |
<fips203::types::DecapsKey<2400> as fips203::traits::SerDes>::try_from_bytes Line | Count | Source | 258 | 618 | fn try_from_bytes(dk: Self::ByteArray) -> Result<Self, &'static str> { | 259 | | // Validation per pg 31. Note that the two checks specify fixed sizes, and these | 260 | | // functions take only byte arrays of correct size. Nonetheless, we take the | 261 | | // opportunity to validate the ek and h(ek). | 262 | 618 | let len_ek_pke = 384 * K + 32; | 263 | 618 | let len_dk_pke = 384 * K; | 264 | 618 | let ek = &dk[len_dk_pke..len_dk_pke + EK_LEN]; | 265 | 617 | let _res = | 266 | 618 | EncapsKey::try_from_bytes(ek.try_into().map_err(|_| "Malformed encaps key")?)?; | 267 | 617 | ensure!( | 268 | 617 | h(ek) == dk[(len_dk_pke + len_ek_pke)..(len_dk_pke + len_ek_pke + 32)], | 269 | 50 | "Encaps hash wrong" | 270 | | ); | 271 | 567 | Ok(DecapsKey { 0: dk }) | 272 | 618 | } |
<fips203::types::DecapsKey<3168> as fips203::traits::SerDes>::try_from_bytes Line | Count | Source | 258 | 567 | fn try_from_bytes(dk: Self::ByteArray) -> Result<Self, &'static str> { | 259 | | // Validation per pg 31. Note that the two checks specify fixed sizes, and these | 260 | | // functions take only byte arrays of correct size. Nonetheless, we take the | 261 | | // opportunity to validate the ek and h(ek). | 262 | 567 | let len_ek_pke = 384 * K + 32; | 263 | 567 | let len_dk_pke = 384 * K; | 264 | 567 | let ek = &dk[len_dk_pke..len_dk_pke + EK_LEN]; | 265 | 565 | let _res = | 266 | 567 | EncapsKey::try_from_bytes(ek.try_into().map_err(|_| "Malformed encaps key")?)?; | 267 | 565 | ensure!( | 268 | 565 | h(ek) == dk[(len_dk_pke + len_ek_pke)..(len_dk_pke + len_ek_pke + 32)], | 269 | 40 | "Encaps hash wrong" | 270 | | ); | 271 | 525 | Ok(DecapsKey { 0: dk }) | 272 | 567 | } |
|
273 | | } |
274 | | |
275 | | |
276 | | impl SerDes for CipherText { |
277 | | type ByteArray = [u8; CT_LEN]; |
278 | | |
279 | 843 | fn into_bytes(self) -> Self::ByteArray { self.0 }<fips203::types::CipherText<768> as fips203::traits::SerDes>::into_bytes Line | Count | Source | 279 | 281 | fn into_bytes(self) -> Self::ByteArray { self.0 } |
<fips203::types::CipherText<1088> as fips203::traits::SerDes>::into_bytes Line | Count | Source | 279 | 281 | fn into_bytes(self) -> Self::ByteArray { self.0 } |
<fips203::types::CipherText<1568> as fips203::traits::SerDes>::into_bytes Line | Count | Source | 279 | 281 | fn into_bytes(self) -> Self::ByteArray { self.0 } |
|
280 | | |
281 | 843 | fn try_from_bytes(ct: Self::ByteArray) -> Result<Self, &'static str> { |
282 | | // Validation per pg 31. Note that the two checks specify fixed sizes, and these |
283 | | // functions take only byte arrays of correct size. Nonetheless, we use a Result |
284 | | // here in case future opportunities for further validation arise. |
285 | 843 | Ok(CipherText { 0: ct }) |
286 | 843 | } <fips203::types::CipherText<768> as fips203::traits::SerDes>::try_from_bytes Line | Count | Source | 281 | 281 | fn try_from_bytes(ct: Self::ByteArray) -> Result<Self, &'static str> { | 282 | | // Validation per pg 31. Note that the two checks specify fixed sizes, and these | 283 | | // functions take only byte arrays of correct size. Nonetheless, we use a Result | 284 | | // here in case future opportunities for further validation arise. | 285 | 281 | Ok(CipherText { 0: ct }) | 286 | 281 | } |
<fips203::types::CipherText<1088> as fips203::traits::SerDes>::try_from_bytes Line | Count | Source | 281 | 281 | fn try_from_bytes(ct: Self::ByteArray) -> Result<Self, &'static str> { | 282 | | // Validation per pg 31. Note that the two checks specify fixed sizes, and these | 283 | | // functions take only byte arrays of correct size. Nonetheless, we use a Result | 284 | | // here in case future opportunities for further validation arise. | 285 | 281 | Ok(CipherText { 0: ct }) | 286 | 281 | } |
<fips203::types::CipherText<1568> as fips203::traits::SerDes>::try_from_bytes Line | Count | Source | 281 | 281 | fn try_from_bytes(ct: Self::ByteArray) -> Result<Self, &'static str> { | 282 | | // Validation per pg 31. Note that the two checks specify fixed sizes, and these | 283 | | // functions take only byte arrays of correct size. Nonetheless, we use a Result | 284 | | // here in case future opportunities for further validation arise. | 285 | 281 | Ok(CipherText { 0: ct }) | 286 | 281 | } |
|
287 | | } |
288 | | |
289 | | |
290 | | #[cfg(test)] |
291 | | mod tests { |
292 | | use super::*; |
293 | | use crate::types::EncapsKey; |
294 | | use rand_chacha::rand_core::SeedableRng; |
295 | | |
296 | | #[test] |
297 | | fn smoke_test() { |
298 | | let mut rng = rand_chacha::ChaCha8Rng::seed_from_u64(123); |
299 | | let (ek, dk) = KG::keygen_from_seed([1u8; 32], [2u8; 32]); |
300 | | let (ssk1, ct) = ek.encaps_from_seed(&[3u8; 32]); |
301 | | let ssk2 = dk.try_decaps(&ct).unwrap(); |
302 | | assert_eq!(ssk1, ssk2); |
303 | | for _i in 0..100 { |
304 | | let (ek, dk) = KG::try_keygen_with_rng(&mut rng).unwrap(); |
305 | | let (ssk1, ct) = ek.try_encaps_with_rng(&mut rng).unwrap(); |
306 | | let ssk2 = dk.try_decaps(&ct).unwrap(); |
307 | | assert!(KG::validate_keypair_with_rng_vartime( |
308 | | &mut rng, |
309 | | &ek.clone().into_bytes(), |
310 | | &dk.clone().into_bytes() |
311 | | )); |
312 | | assert_eq!(ssk1, ssk2); |
313 | | assert_eq!(ek.clone().0, EncapsKey::try_from_bytes(ek.into_bytes()).unwrap().0); |
314 | | assert_eq!(dk.clone().0, DecapsKey::try_from_bytes(dk.into_bytes()).unwrap().0); |
315 | | } |
316 | | } |
317 | | } |
318 | | }; |
319 | | } |
320 | | |
321 | | |
322 | | #[cfg(feature = "ml-kem-512")] |
323 | | pub mod ml_kem_512 { |
324 | | //! Functionality for the ML-KEM-512 security parameter set, which is claimed to be in security category 1, see |
325 | | //! table 2 & 3 on page 39 of spec. |
326 | | //! |
327 | | //! See <https://nvlpubs.nist.gov/nistpubs/FIPS/NIST.FIPS.203.pdf> |
328 | | //! |
329 | | //! Typical usage flow entails: |
330 | | //! 1. The originator runs `try_keygen()` to get an encaps key `encapsKey` and decaps key `decapsKey`. |
331 | | //! 2. The originator serializes the encaps key via `encapsKey.into_bytes()` and sends to the remote party. |
332 | | //! 3. The remote party deserializes the bytes via `try_from_bytes(<bytes>)` and runs `try_encaps()` to get the |
333 | | //! shared secret key `ssk` and ciphertext `cipherText`. |
334 | | //! 4. The remote party serializes the cipertext via `cipherText.into_bytes()` and sends to the originator. |
335 | | //! 5. The originator deserializes the ciphertext via `try_from_bytes(<bytes>)` then |
336 | | //! runs `decapsKey.try_decaps(cipherText)` to the get shared secret ket `ssk`. |
337 | | //! 6. Both the originator and remote party now have the same shared secret key `ssk`. |
338 | | //! |
339 | | //! **--> See [`crate::traits`] for the keygen, encapsulation, decapsulation, and serialization/deserialization functionality.** |
340 | | |
341 | | const K: usize = 2; |
342 | | const ETA1: u32 = 3; |
343 | | const ETA2: u32 = 2; |
344 | | const DU: u32 = 10; |
345 | | const DV: u32 = 4; |
346 | | |
347 | | /// Serialized Encapsulation Key Length (in bytes) |
348 | | pub const EK_LEN: usize = 800; |
349 | | /// Serialized Decapsulation Key Length (in bytes) |
350 | | pub const DK_LEN: usize = 1632; |
351 | | /// Serialized Ciphertext Key Length (in bytes) |
352 | | pub const CT_LEN: usize = 768; |
353 | | |
354 | | functionality!(); |
355 | | } |
356 | | |
357 | | |
358 | | #[cfg(feature = "ml-kem-768")] |
359 | | pub mod ml_kem_768 { |
360 | | //! Functionality for the ML-KEM-768 security parameter set, which is claimed to be in security category 3, see |
361 | | //! table 2 & 3 on page 39 of spec. |
362 | | //! |
363 | | //! See <https://nvlpubs.nist.gov/nistpubs/FIPS/NIST.FIPS.203.pdf> |
364 | | //! |
365 | | //! Typical usage flow entails: |
366 | | //! 1. The originator runs `try_keygen()` to get an encaps key `encapsKey` and decaps key `decapsKey`. |
367 | | //! 2. The originator serializes the encaps key via `encapsKey.into_bytes()` and sends to the remote party. |
368 | | //! 3. The remote party deserializes the bytes via `try_from_bytes(<bytes>)` and runs `try_encaps()` to get the |
369 | | //! shared secret key `ssk` and ciphertext `cipherText`. |
370 | | //! 4. The remote party serializes the cipertext via `cipherText.into_bytes()` and sends to the originator. |
371 | | //! 5. The originator deserializes the ciphertext via `try_from_bytes(<bytes>)` then |
372 | | //! runs `decapsKey.try_decaps(cipherText)` to the get shared secret ket `ssk`. |
373 | | //! 6. Both the originator and remote party now have the same shared secret key `ssk`. |
374 | | //! |
375 | | //! **--> See [`crate::traits`] for the keygen, encapsulation, decapsulation, and serialization/deserialization functionality.** |
376 | | |
377 | | const K: usize = 3; |
378 | | const ETA1: u32 = 2; |
379 | | const ETA2: u32 = 2; |
380 | | const DU: u32 = 10; |
381 | | const DV: u32 = 4; |
382 | | |
383 | | /// Serialized Encapsulation Key Length (in bytes) |
384 | | pub const EK_LEN: usize = 1184; |
385 | | /// Serialized Decapsulation Key Length (in bytes) |
386 | | pub const DK_LEN: usize = 2400; |
387 | | /// Serialized Ciphertext Key Length (in bytes) |
388 | | pub const CT_LEN: usize = 1088; |
389 | | |
390 | | functionality!(); |
391 | | } |
392 | | |
393 | | #[cfg(feature = "ml-kem-1024")] |
394 | | pub mod ml_kem_1024 { |
395 | | //! Functionality for the ML-KEM-1024 security parameter set, which is claimed to be in security category 5, see |
396 | | //! table 2 & 3 on page 39 of spec. |
397 | | //! |
398 | | //! See <https://nvlpubs.nist.gov/nistpubs/FIPS/NIST.FIPS.203.pdf> |
399 | | //! |
400 | | //! Typical usage flow entails: |
401 | | //! 1. The originator runs `try_keygen()` to get an encaps key `encapsKey` and decaps key `decapsKey`. |
402 | | //! 2. The originator serializes the encaps key via `encapsKey.into_bytes()` and sends to the remote party. |
403 | | //! 3. The remote party deserializes the bytes via `try_from_bytes(<bytes>)` and runs `try_encaps()` to get the |
404 | | //! shared secret key `ssk` and ciphertext `cipherText`. |
405 | | //! 4. The remote party serializes the cipertext via `cipherText.into_bytes()` and sends to the originator. |
406 | | //! 5. The originator deserializes the ciphertext via `try_from_bytes(<bytes>)` then |
407 | | //! runs `decapsKey.try_decaps(cipherText)` to the get shared secret ket `ssk`. |
408 | | //! 6. Both the originator and remote party now have the same shared secret key `ssk`. |
409 | | //! |
410 | | //! **--> See [`crate::traits`] for the keygen, encapsulation, decapsulation, and serialization/deserialization functionality.** |
411 | | |
412 | | const K: usize = 4; |
413 | | const ETA1: u32 = 2; |
414 | | const ETA2: u32 = 2; |
415 | | const DU: u32 = 11; |
416 | | const DV: u32 = 5; |
417 | | |
418 | | /// Serialized Encapsulation Key Length (in bytes) |
419 | | pub const EK_LEN: usize = 1568; |
420 | | /// Serialized Decapsulation Key Length (in bytes) |
421 | | pub const DK_LEN: usize = 3168; |
422 | | /// Serialized Ciphertext Key Length (in bytes) |
423 | | pub const CT_LEN: usize = 1568; |
424 | | |
425 | | functionality!(); |
426 | | } |