1macro_rules! kem_api {
43 (
44 algorithm:
45 $algo:literal,classic:
46 $classic:ident,public_key_bytes:
47 $pk_bytes:expr,secret_key_bytes:
48 $sk_bytes:expr,ciphertext_bytes:
49 $ct_bytes:expr,shared_secret_bytes:
50 $ss_bytes:expr,seed_bytes:
51 $seed_bytes:expr,seed_keypair:
52 $seed_keypair:ident,enc:
53 $enc:ident,public_key_of: |
54 $sk:ident,
55 $pk:ident |
56 $public_key_of:expr,dec: |
57 $dec_ss:ident,
58 $dec_ct:ident,
59 $dec_sk:ident |
60 $dec:expr $(,)?
61 ) => {
62 use core::fmt;
63
64 #[cfg(feature = "serde")]
65 use serde::{Deserialize, Serialize};
66 use zeroize::{Zeroize, ZeroizeOnDrop, Zeroizing};
67
68 use crate::classic::$classic::{$enc, $seed_keypair};
69 use crate::error::Error;
70 use crate::rng::copy_randombytes;
71 use crate::types::*;
72
73 #[doc = concat!("Stack-allocated ", $algo, " public key.")]
74 pub type PublicKey = StackByteArray<{ $pk_bytes }>;
75 #[doc = concat!("Stack-allocated ", $algo, " secret key.")]
76 pub type SecretKey = StackByteArray<{ $sk_bytes }>;
77 #[doc = concat!("Stack-allocated ", $algo, " ciphertext.")]
78 pub type Ciphertext = StackByteArray<{ $ct_bytes }>;
79 #[doc = concat!("Stack-allocated ", $algo, " shared secret.")]
80 pub type SharedSecret = StackByteArray<{ $ss_bytes }>;
81 #[doc = concat!("Stack-allocated ", $algo, " key-generation seed.")]
82 pub type Seed = StackByteArray<{ $seed_bytes }>;
83 pub type StackKeyPair = KeyPair<PublicKey, SecretKey>;
85
86 #[derive(Zeroize, ZeroizeOnDrop, Clone)]
87 #[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
88 #[doc = concat!("An ", $algo, " key pair.")]
89 pub struct KeyPair<
90 PublicKey: ByteArray<{ $pk_bytes }> + Zeroize,
91 SecretKey: ByteArray<{ $sk_bytes }> + Zeroize,
92 > {
93 pub public_key: PublicKey,
95 pub secret_key: SecretKey,
97 }
98
99 impl<
100 PublicKey: ByteArray<{ $pk_bytes }> + Zeroize,
101 SecretKey: ByteArray<{ $sk_bytes }> + Zeroize,
102 > fmt::Debug for KeyPair<PublicKey, SecretKey>
103 {
104 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
105 f.debug_struct("KeyPair")
106 .field("public_key", &"[REDACTED]")
107 .field("secret_key", &"[REDACTED]")
108 .finish()
109 }
110 }
111
112 impl<
113 PublicKey: NewByteArray<{ $pk_bytes }> + Zeroize,
114 SecretKey: NewByteArray<{ $sk_bytes }> + Zeroize,
115 > KeyPair<PublicKey, SecretKey>
116 {
117 #[must_use]
119 pub fn generate() -> Self {
120 let mut seed = Zeroizing::new([0u8; $seed_bytes]);
121 copy_randombytes(seed.as_mut_slice());
122 Self::from_seed(&*seed)
123 }
124
125 #[must_use]
127 pub fn from_seed<Seed: ByteArray<{ $seed_bytes }>>(seed: &Seed) -> Self {
128 let mut public_key = PublicKey::new_byte_array();
129 let mut secret_key = SecretKey::new_byte_array();
130 $seed_keypair(
131 public_key.as_mut_array(),
132 secret_key.as_mut_array(),
133 seed.as_array(),
134 );
135 Self {
136 public_key,
137 secret_key,
138 }
139 }
140 }
141
142 impl<
143 PublicKey: NewByteArray<{ $pk_bytes }> + Zeroize,
144 SecretKey: ByteArray<{ $sk_bytes }> + Zeroize,
145 > KeyPair<PublicKey, SecretKey>
146 {
147 #[must_use]
149 pub fn from_secret_key(secret_key: SecretKey) -> Self {
150 let mut public_key = PublicKey::new_byte_array();
151 {
152 let $sk = secret_key.as_array();
153 let $pk = public_key.as_mut_array();
154 $public_key_of;
155 }
156 Self {
157 public_key,
158 secret_key,
159 }
160 }
161 }
162
163 impl<
164 PublicKey: ByteArray<{ $pk_bytes }> + Zeroize,
165 SecretKey: ByteArray<{ $sk_bytes }> + Zeroize,
166 > KeyPair<PublicKey, SecretKey>
167 {
168 pub fn decapsulate<
181 SharedSecret: NewByteArray<{ $ss_bytes }>,
182 Ciphertext: ByteArray<{ $ct_bytes }>,
183 >(
184 &self,
185 ciphertext: &Ciphertext,
186 ) -> Result<SharedSecret, Error> {
187 let mut shared_secret = SharedSecret::new_byte_array();
188 {
189 let $dec_ss = shared_secret.as_mut_array();
190 let $dec_ct = ciphertext.as_array();
191 let $dec_sk = self.secret_key.as_array();
192 $dec?;
193 }
194 Ok(shared_secret)
195 }
196 }
197
198 #[doc = concat!(
199 "Creates a random shared secret for `public_key`, returning the ", $algo,
200 "\nciphertext to send to its owner and the shared secret."
201 )]
202 pub fn encapsulate<
208 Ciphertext: NewByteArray<{ $ct_bytes }>,
209 SharedSecret: NewByteArray<{ $ss_bytes }>,
210 PublicKey: ByteArray<{ $pk_bytes }>,
211 >(
212 public_key: &PublicKey,
213 ) -> Result<(Ciphertext, SharedSecret), Error> {
214 let mut ciphertext = Ciphertext::new_byte_array();
215 let mut shared_secret = SharedSecret::new_byte_array();
216 $enc(
217 ciphertext.as_mut_array(),
218 shared_secret.as_mut_array(),
219 public_key.as_array(),
220 )?;
221 Ok((ciphertext, shared_secret))
222 }
223
224 #[cfg(any(all(feature = "protected", any(unix, windows)), all(doc, not(doctest), feature = "std")))]
225 #[cfg_attr(all(feature = "nightly", doc), doc(cfg(feature = "protected")))]
226 pub mod protected {
227 use super::*;
234 pub use crate::protected::*;
235
236 pub type PublicKey = HeapByteArray<{ $pk_bytes }>;
238 pub type SecretKey = HeapByteArray<{ $sk_bytes }>;
240 pub type SharedSecret = HeapByteArray<{ $ss_bytes }>;
242 pub type LockedKeyPair = KeyPair<Locked<PublicKey>, Locked<SecretKey>>;
244 pub type LockedROKeyPair = KeyPair<LockedRO<PublicKey>, LockedRO<SecretKey>>;
246
247 fn generate_locked_parts() -> Result<(Locked<PublicKey>, Locked<SecretKey>), Error> {
249 let mut seed = HeapByteArray::<{ $seed_bytes }>::new_locked()?;
250 copy_randombytes(seed.as_mut_slice());
251 let mut public_key = PublicKey::new_locked()?;
252 let mut secret_key = SecretKey::new_locked()?;
253 $seed_keypair(
254 public_key.as_mut_array(),
255 secret_key.as_mut_array(),
256 seed.as_array(),
257 );
258 Ok((public_key, secret_key))
259 }
260
261 impl LockedKeyPair {
262 pub fn generate_locked_keypair() -> Result<Self, Error> {
268 let (public_key, secret_key) = generate_locked_parts()?;
269 Ok(Self {
270 public_key,
271 secret_key,
272 })
273 }
274 }
275
276 impl LockedROKeyPair {
277 pub fn generate_readonly_locked_keypair() -> Result<Self, Error> {
284 let (public_key, secret_key) = generate_locked_parts()?;
285 Ok(Self {
286 public_key: public_key.mprotect_readonly()?,
287 secret_key: secret_key.mprotect_readonly()?,
288 })
289 }
290 }
291 }
292 };
293}
294
295pub mod xwing {
296 use crate::classic::crypto_kem_xwing::crypto_kem_xwing_dec;
302 use crate::constants::{
303 CRYPTO_KEM_XWING_CIPHERTEXTBYTES, CRYPTO_KEM_XWING_PUBLICKEYBYTES,
304 CRYPTO_KEM_XWING_SECRETKEYBYTES, CRYPTO_KEM_XWING_SEEDBYTES,
305 CRYPTO_KEM_XWING_SHAREDSECRETBYTES,
306 };
307
308 kem_api! {
309 algorithm: "X-Wing",
310 classic: crypto_kem_xwing,
311 public_key_bytes: CRYPTO_KEM_XWING_PUBLICKEYBYTES,
312 secret_key_bytes: CRYPTO_KEM_XWING_SECRETKEYBYTES,
313 ciphertext_bytes: CRYPTO_KEM_XWING_CIPHERTEXTBYTES,
314 shared_secret_bytes: CRYPTO_KEM_XWING_SHAREDSECRETBYTES,
315 seed_bytes: CRYPTO_KEM_XWING_SEEDBYTES,
316 seed_keypair: crypto_kem_xwing_seed_keypair_inplace,
317 enc: crypto_kem_xwing_enc,
318 public_key_of: |sk, pk| crypto_kem_xwing_seed_keypair_inplace(
320 pk,
321 &mut Zeroizing::new([0u8; CRYPTO_KEM_XWING_SECRETKEYBYTES]),
322 sk,
323 ),
324 dec: |ss, ct, sk| crypto_kem_xwing_dec(ss, ct, sk),
325 }
326}
327
328pub mod mlkem768 {
329 use crate::classic::crypto_kem_mlkem768::crypto_kem_mlkem768_dec;
336 use crate::constants::{
337 CRYPTO_KEM_MLKEM768_CIPHERTEXTBYTES, CRYPTO_KEM_MLKEM768_PUBLICKEYBYTES,
338 CRYPTO_KEM_MLKEM768_SECRETKEYBYTES, CRYPTO_KEM_MLKEM768_SEEDBYTES,
339 CRYPTO_KEM_MLKEM768_SHAREDSECRETBYTES,
340 };
341
342 const PUBLIC_KEY_OFFSET: usize =
344 CRYPTO_KEM_MLKEM768_SECRETKEYBYTES - CRYPTO_KEM_MLKEM768_PUBLICKEYBYTES - 64;
345
346 kem_api! {
347 algorithm: "ML-KEM-768",
348 classic: crypto_kem_mlkem768,
349 public_key_bytes: CRYPTO_KEM_MLKEM768_PUBLICKEYBYTES,
350 secret_key_bytes: CRYPTO_KEM_MLKEM768_SECRETKEYBYTES,
351 ciphertext_bytes: CRYPTO_KEM_MLKEM768_CIPHERTEXTBYTES,
352 shared_secret_bytes: CRYPTO_KEM_MLKEM768_SHAREDSECRETBYTES,
353 seed_bytes: CRYPTO_KEM_MLKEM768_SEEDBYTES,
354 seed_keypair: crypto_kem_mlkem768_seed_keypair_inplace,
355 enc: crypto_kem_mlkem768_enc,
356 public_key_of: |sk, pk| pk.copy_from_slice(
357 &sk[PUBLIC_KEY_OFFSET..PUBLIC_KEY_OFFSET + CRYPTO_KEM_MLKEM768_PUBLICKEYBYTES]
358 ),
359 dec: |ss, ct, sk| {
360 crypto_kem_mlkem768_dec(ss, ct, sk);
361 Ok::<(), Error>(())
362 },
363 }
364}
365
366pub use xwing::*;