frodo_kem/
lib.rs

1//! ## Usage
2//!
3//! The standard safe method for FrodoKEM is to use [`Algorithm`],
4//! `encapsulate` a randomly generated value,
5//! and `decapsulate` it on the other side.
6//!
7//! ```
8//! use frodo_kem::Algorithm;
9//! use rand_core::OsRng;
10//!
11//! let alg = Algorithm::FrodoKem640Shake;
12//! let (ek, dk) = alg.generate_keypair(OsRng);
13//! let (ct, enc_ss) = alg.encapsulate_with_rng(&ek, OsRng).unwrap();
14//! let (dec_ss, msg) = alg.decapsulate(&dk, &ct).unwrap();
15//!
16//! assert_eq!(enc_ss, dec_ss);
17//! ```
18//! If the `message` is known, it can be passed to the `encapsulate`.
19//! `encapsulate` will error if the `message` is not the correct size. This method also requires
20//! a `salt` for non-ephemeral algorithms, and the `salt` is considered public information.
21//!
22//! Ephemeral variants are meant to be used one-time only and thus do not require a `salt`.
23//!
24//! ## ☢️️ WARNING: HAZARDOUS ☢️
25//! It is considered unsafe to use Ephemeral algorithms more than once.
26//! For more information see [ISO Standard Annex](https://frodokem.org/files/FrodoKEM-annex-20230418.pdf).
27//!
28//! ```
29//! use frodo_kem::Algorithm;
30//! use rand_core::{RngCore, OsRng};
31//!
32//! let alg = Algorithm::FrodoKem1344Shake;
33//! let params = alg.params();
34//! let (ek, dk) = alg.generate_keypair(OsRng);
35//! // Key is known, generate
36//! let aes_256_key = vec![3u8; params.message_length];
37//! let mut salt = vec![0u8; params.salt_length];
38//! OsRng.fill_bytes(&mut salt);
39//! let (ct, enc_ss) = alg.encapsulate(&ek, &aes_256_key, &salt).unwrap();
40//! let (dec_ss, dec_msg) = alg.decapsulate(&dk, &ct).unwrap();
41//!
42//! // Ephemeral method, no salt required
43//! let alg = Algorithm::EphemeralFrodoKem1344Shake;
44//! let (ct, enc_ss) = alg.encapsulate(&ek, &aes_256_key, &[]).unwrap();
45//! let (dec_ss, dec_msg) = alg.decapsulate(&dk, &ct).unwrap();
46//!
47//! assert_eq!(enc_ss, dec_ss);
48//! assert_eq!(&aes_256_key[..], dec_msg.as_slice());
49//! ```
50//!
51//! ## Features
52//! Each algorithm can be conditionally included/excluded as needed.
53//!
54//! The structs used in this crate all optionally support the `serde` feature.
55//!
56//! ## Custom
57//!
58//! To create a custom implementation of FrodoKEM, use the `hazmat` feature, to access
59//! the necessary traits and models for creating a custom implementation.
60//! Be warned, this is not recommended unless you are sure of what you are doing.
61#![cfg_attr(docsrs, feature(doc_auto_cfg))]
62#![warn(
63    missing_docs,
64    missing_debug_implementations,
65    missing_copy_implementations,
66    trivial_casts,
67    trivial_numeric_casts,
68    unused,
69    clippy::mod_module_files
70)]
71#![deny(clippy::unwrap_used)]
72
73#[cfg(not(any(
74    feature = "efrodo640aes",
75    feature = "frodo640aes",
76    feature = "efrodo976aes",
77    feature = "frodo976aes",
78    feature = "efrodo1344aes",
79    feature = "frodo1344aes",
80    feature = "efrodo640shake",
81    feature = "frodo640shake",
82    feature = "efrodo976shake",
83    feature = "frodo976shake",
84    feature = "efrodo1344shake",
85    feature = "frodo1344shake",
86)))]
87compile_error!("no algorithm feature enabled");
88
89mod error;
90pub use error::*;
91
92#[cfg(feature = "hazmat")]
93pub mod hazmat;
94#[cfg(not(feature = "hazmat"))]
95mod hazmat;
96
97use hazmat::*;
98
99use rand_core::CryptoRngCore;
100use std::marker::PhantomData;
101use subtle::{Choice, ConstantTimeEq};
102use zeroize::{Zeroize, ZeroizeOnDrop};
103
104macro_rules! serde_impl {
105    ($name:ident, $from_method:ident) => {
106        #[cfg(feature = "serde")]
107        impl serde::Serialize for $name {
108            fn serialize<S>(&self, s: S) -> Result<S::Ok, S::Error>
109            where
110                S: serde::Serializer,
111            {
112                if s.is_human_readable() {
113                    use serde::ser::SerializeStruct;
114
115                    let mut map = s.serialize_struct(stringify!($name), 2)?;
116                    map.serialize_field("algorithm", &self.algorithm.to_string())?;
117                    map.serialize_field("value", &hex::encode(&self.value))?;
118                    map.end()
119                } else {
120                    let mut seq = vec![u8::from(self.algorithm)];
121                    seq.extend_from_slice(self.value.as_slice());
122                    s.serialize_bytes(&seq)
123                }
124            }
125        }
126
127        #[cfg(feature = "serde")]
128        impl<'de> serde::Deserialize<'de> for $name {
129            fn deserialize<D>(d: D) -> Result<Self, D::Error>
130            where
131                D: serde::Deserializer<'de>,
132            {
133                if d.is_human_readable() {
134                    struct FieldVisitor;
135                    #[derive(serde::Deserialize)]
136                    #[serde(field_identifier, rename_all = "snake_case")]
137                    enum Field {
138                        Algorithm,
139                        Value,
140                    }
141
142                    impl<'de> serde::de::Visitor<'de> for FieldVisitor {
143                        type Value = $name;
144
145                        fn expecting(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
146                            write!(f, "a struct with two fields")
147                        }
148
149                        fn visit_map<A>(self, mut map: A) -> Result<Self::Value, A::Error>
150                        where
151                            A: serde::de::MapAccess<'de>,
152                        {
153                            let mut algorithm = Option::<Algorithm>::None;
154                            let mut value = Option::<String>::None;
155                            while let Some(key) = map.next_key()? {
156                                match key {
157                                    Field::Algorithm => {
158                                        if algorithm.is_some() {
159                                            return Err(serde::de::Error::duplicate_field(
160                                                "algorithm",
161                                            ));
162                                        }
163                                        algorithm = Some(map.next_value()?);
164                                    }
165                                    Field::Value => {
166                                        if value.is_some() {
167                                            return Err(serde::de::Error::duplicate_field("value"));
168                                        }
169                                        value = Some(map.next_value()?);
170                                    }
171                                }
172                            }
173
174                            let algorithm = algorithm
175                                .ok_or_else(|| serde::de::Error::missing_field("algorithm"))?;
176                            let value =
177                                value.ok_or_else(|| serde::de::Error::missing_field("value"))?;
178                            let value = hex::decode(&value).map_err(serde::de::Error::custom)?;
179                            algorithm
180                                .$from_method(&value)
181                                .map_err(serde::de::Error::custom)
182                        }
183                    }
184                    const FIELDS: &[&str] = &["algorithm", "value"];
185                    d.deserialize_struct("Ciphertext", FIELDS, FieldVisitor)
186                } else {
187                    struct BytesVisitor;
188
189                    impl<'de> serde::de::Visitor<'de> for BytesVisitor {
190                        type Value = $name;
191
192                        fn expecting(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
193                            write!(f, "a byte sequence")
194                        }
195
196                        fn visit_bytes<E>(self, v: &[u8]) -> Result<Self::Value, E>
197                        where
198                            E: serde::de::Error,
199                        {
200                            let algorithm =
201                                Algorithm::try_from(v[0]).map_err(serde::de::Error::custom)?;
202
203                            let value = &v[1..];
204                            algorithm
205                                .$from_method(value)
206                                .map_err(serde::de::Error::custom)
207                        }
208                    }
209
210                    d.deserialize_bytes(BytesVisitor)
211                }
212            }
213        }
214    };
215}
216
217macro_rules! ct_eq_imp {
218    ($name:ident) => {
219        impl ConstantTimeEq for $name {
220            fn ct_eq(&self, other: &Self) -> Choice {
221                self.algorithm.ct_eq(&other.algorithm) & ct_eq_bytes(&self.value, &other.value)
222            }
223        }
224
225        impl Eq for $name {}
226
227        impl PartialEq for $name {
228            fn eq(&self, other: &Self) -> bool {
229                self.ct_eq(other).unwrap_u8() == 1
230            }
231        }
232    };
233}
234
235/// A FrodoKEM ciphertext key
236#[derive(Debug, Clone, Default)]
237pub struct Ciphertext {
238    pub(crate) algorithm: Algorithm,
239    pub(crate) value: Vec<u8>,
240}
241
242impl AsRef<[u8]> for Ciphertext {
243    fn as_ref(&self) -> &[u8] {
244        self.value.as_ref()
245    }
246}
247
248ct_eq_imp!(Ciphertext);
249
250serde_impl!(Ciphertext, ciphertext_from_bytes);
251
252impl Ciphertext {
253    /// Get the algorithm
254    pub fn algorithm(&self) -> Algorithm {
255        self.algorithm
256    }
257
258    /// Get the value
259    pub fn value(&self) -> &[u8] {
260        self.value.as_slice()
261    }
262
263    /// Convert a slice of bytes into a [`Ciphertext`] according to the specified [`Algorithm`].
264    pub fn from_bytes<B: AsRef<[u8]>>(algorithm: Algorithm, value: B) -> FrodoResult<Self> {
265        algorithm.ciphertext_from_bytes(value.as_ref())
266    }
267}
268
269/// A FrodoKEM public key
270#[derive(Debug, Clone, Default)]
271pub struct EncryptionKey {
272    pub(crate) algorithm: Algorithm,
273    pub(crate) value: Vec<u8>,
274}
275
276impl AsRef<[u8]> for EncryptionKey {
277    fn as_ref(&self) -> &[u8] {
278        self.value.as_ref()
279    }
280}
281
282impl From<&DecryptionKey> for EncryptionKey {
283    fn from(secret_key: &DecryptionKey) -> Self {
284        secret_key
285            .algorithm
286            .encryption_key_from_decryption_key(secret_key)
287    }
288}
289
290ct_eq_imp!(EncryptionKey);
291
292serde_impl!(EncryptionKey, encryption_key_from_bytes);
293
294impl EncryptionKey {
295    /// Get the algorithm
296    pub fn algorithm(&self) -> Algorithm {
297        self.algorithm
298    }
299
300    /// Get the value
301    pub fn value(&self) -> &[u8] {
302        self.value.as_slice()
303    }
304
305    /// Convert a slice of bytes into a [`EncryptionKey`] according to the specified [`Algorithm`].
306    pub fn from_bytes<B: AsRef<[u8]>>(algorithm: Algorithm, value: B) -> FrodoResult<Self> {
307        algorithm.encryption_key_from_bytes(value.as_ref())
308    }
309
310    /// Encapsulate a random value to generate a [`SharedSecret`] and a [`Ciphertext`].
311    pub fn encapsulate_with_rng(
312        &self,
313        rng: impl CryptoRngCore,
314    ) -> FrodoResult<(Ciphertext, SharedSecret)> {
315        self.algorithm.encapsulate_with_rng(self, rng)
316    }
317
318    /// Encapsulate with given message to generate a [`SharedSecret`] and a [`Ciphertext`].
319    ///
320    /// NOTE: The message must be of the correct length for the algorithm.
321    /// Also, this method is deterministic, meaning that using the same message
322    /// will yield the same [`SharedSecret`] and [`Ciphertext`]
323    pub fn encapsulate<B: AsRef<[u8]>, S: AsRef<[u8]>>(
324        &self,
325        message: B,
326        salt: S,
327    ) -> FrodoResult<(Ciphertext, SharedSecret)> {
328        self.algorithm.encapsulate(self, message, salt)
329    }
330}
331
332/// A FrodoKEM secret key
333#[derive(Debug, Clone, Default)]
334pub struct DecryptionKey {
335    pub(crate) algorithm: Algorithm,
336    pub(crate) value: Vec<u8>,
337}
338
339impl AsRef<[u8]> for DecryptionKey {
340    fn as_ref(&self) -> &[u8] {
341        self.value.as_ref()
342    }
343}
344
345ct_eq_imp!(DecryptionKey);
346
347serde_impl!(DecryptionKey, decryption_key_from_bytes);
348
349impl Zeroize for DecryptionKey {
350    fn zeroize(&mut self) {
351        self.value.zeroize();
352    }
353}
354
355impl ZeroizeOnDrop for DecryptionKey {}
356
357impl DecryptionKey {
358    /// Get the algorithm
359    pub fn algorithm(&self) -> Algorithm {
360        self.algorithm
361    }
362
363    /// Get the value
364    pub fn value(&self) -> &[u8] {
365        self.value.as_slice()
366    }
367
368    /// Convert a slice of bytes into a [`DecryptionKey`] according to the specified [`Algorithm`].
369    pub fn from_bytes<B: AsRef<[u8]>>(algorithm: Algorithm, value: B) -> FrodoResult<Self> {
370        algorithm.decryption_key_from_bytes(value.as_ref())
371    }
372
373    /// Decapsulate the [`Ciphertext`] to return the [`SharedSecret`] and
374    /// message generated during encapsulation.
375    pub fn decapsulate<B: AsRef<[u8]>>(
376        &self,
377        ciphertext: &Ciphertext,
378    ) -> FrodoResult<(SharedSecret, Vec<u8>)> {
379        self.algorithm.decapsulate(self, ciphertext)
380    }
381}
382
383/// A FrodoKEM shared secret
384#[derive(Debug, Clone, Default)]
385pub struct SharedSecret {
386    pub(crate) algorithm: Algorithm,
387    pub(crate) value: Vec<u8>,
388}
389
390impl AsRef<[u8]> for SharedSecret {
391    fn as_ref(&self) -> &[u8] {
392        self.value.as_ref()
393    }
394}
395
396ct_eq_imp!(SharedSecret);
397
398serde_impl!(SharedSecret, shared_secret_from_bytes);
399
400impl Zeroize for SharedSecret {
401    fn zeroize(&mut self) {
402        self.value.zeroize();
403    }
404}
405
406impl ZeroizeOnDrop for SharedSecret {}
407
408impl SharedSecret {
409    /// Get the algorithm
410    pub fn algorithm(&self) -> Algorithm {
411        self.algorithm
412    }
413
414    /// Get the value
415    pub fn value(&self) -> &[u8] {
416        self.value.as_slice()
417    }
418
419    /// Convert a slice of bytes into a [`SharedSecret`] according to the specified [`Algorithm`].
420    pub fn from_bytes<B: AsRef<[u8]>>(algorithm: Algorithm, value: B) -> FrodoResult<Self> {
421        algorithm.shared_secret_from_bytes(value.as_ref())
422    }
423}
424
425/// The supported FrodoKem algorithms
426#[derive(Debug, Clone, Copy, PartialEq, Eq, Ord, PartialOrd, Hash)]
427pub enum Algorithm {
428    #[cfg(feature = "frodo640aes")]
429    /// The FrodoKEM-640-AES algorithm
430    FrodoKem640Aes,
431    #[cfg(feature = "frodo976aes")]
432    /// The FrodoKEM-976-AES algorithm
433    FrodoKem976Aes,
434    #[cfg(feature = "frodo1344aes")]
435    /// The FrodoKEM-1344-AES algorithm
436    FrodoKem1344Aes,
437    #[cfg(feature = "frodo640shake")]
438    /// The FrodoKEM-640-SHAKE algorithm
439    FrodoKem640Shake,
440    #[cfg(feature = "frodo976shake")]
441    /// The FrodoKEM-976-SHAKE algorithm
442    FrodoKem976Shake,
443    #[cfg(feature = "frodo1344shake")]
444    /// The FrodoKEM-1344-SHAKE algorithm
445    FrodoKem1344Shake,
446    #[cfg(feature = "efrodo640aes")]
447    /// The FrodoKEM-640-AES algorithm
448    EphemeralFrodoKem640Aes,
449    #[cfg(feature = "efrodo976aes")]
450    /// The FrodoKEM-976-AES algorithm
451    EphemeralFrodoKem976Aes,
452    #[cfg(feature = "efrodo1344aes")]
453    /// The FrodoKEM-1344-AES algorithm
454    EphemeralFrodoKem1344Aes,
455    #[cfg(feature = "efrodo640shake")]
456    /// The FrodoKEM-640-SHAKE algorithm
457    EphemeralFrodoKem640Shake,
458    #[cfg(feature = "efrodo976shake")]
459    /// The FrodoKEM-976-SHAKE algorithm
460    EphemeralFrodoKem976Shake,
461    #[cfg(feature = "efrodo1344shake")]
462    /// The FrodoKEM-1344-SHAKE algorithm
463    EphemeralFrodoKem1344Shake,
464}
465
466impl ConstantTimeEq for Algorithm {
467    fn ct_eq(&self, other: &Self) -> Choice {
468        match (self, other) {
469            #[cfg(feature = "efrodo640aes")]
470            (Self::EphemeralFrodoKem640Aes, Self::EphemeralFrodoKem640Aes) => Choice::from(1),
471            #[cfg(feature = "efrodo976aes")]
472            (Self::EphemeralFrodoKem976Aes, Self::EphemeralFrodoKem976Aes) => Choice::from(1),
473            #[cfg(feature = "efrodo1344aes")]
474            (Self::EphemeralFrodoKem1344Aes, Self::EphemeralFrodoKem1344Aes) => Choice::from(1),
475            #[cfg(feature = "efrodo640shake")]
476            (Self::EphemeralFrodoKem640Shake, Self::EphemeralFrodoKem640Shake) => Choice::from(1),
477            #[cfg(feature = "efrodo976shake")]
478            (Self::EphemeralFrodoKem976Shake, Self::EphemeralFrodoKem976Shake) => Choice::from(1),
479            #[cfg(feature = "efrodo1344shake")]
480            (Self::EphemeralFrodoKem1344Shake, Self::EphemeralFrodoKem1344Shake) => Choice::from(1),
481            #[cfg(feature = "frodo640aes")]
482            (Self::FrodoKem640Aes, Self::FrodoKem640Aes) => Choice::from(1),
483            #[cfg(feature = "frodo976aes")]
484            (Self::FrodoKem976Aes, Self::FrodoKem976Aes) => Choice::from(1),
485            #[cfg(feature = "frodo1344aes")]
486            (Self::FrodoKem1344Aes, Self::FrodoKem1344Aes) => Choice::from(1),
487            #[cfg(feature = "frodo640shake")]
488            (Self::FrodoKem640Shake, Self::FrodoKem640Shake) => Choice::from(1),
489            #[cfg(feature = "frodo976shake")]
490            (Self::FrodoKem976Shake, Self::FrodoKem976Shake) => Choice::from(1),
491            #[cfg(feature = "frodo1344shake")]
492            (Self::FrodoKem1344Shake, Self::FrodoKem1344Shake) => Choice::from(1),
493            _ => Choice::from(0),
494        }
495    }
496}
497
498impl Default for Algorithm {
499    fn default() -> Self {
500        Self::enabled_algorithms()[0]
501    }
502}
503
504impl std::fmt::Display for Algorithm {
505    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
506        static ALGORITHMS: std::sync::LazyLock<std::collections::HashMap<Algorithm, String>> =
507            std::sync::LazyLock::new(|| {
508                let mut set = std::collections::HashMap::new();
509                #[cfg(feature = "frodo640aes")]
510                set.insert(
511                    Algorithm::FrodoKem640Aes,
512                    FrodoKem640Aes::default().algorithm(),
513                );
514                #[cfg(feature = "frodo976aes")]
515                set.insert(
516                    Algorithm::FrodoKem976Aes,
517                    FrodoKem976Aes::default().algorithm(),
518                );
519                #[cfg(feature = "frodo1344aes")]
520                set.insert(
521                    Algorithm::FrodoKem1344Aes,
522                    FrodoKem1344Aes::default().algorithm(),
523                );
524                #[cfg(feature = "frodo640shake")]
525                set.insert(
526                    Algorithm::FrodoKem640Shake,
527                    FrodoKem640Shake::default().algorithm(),
528                );
529                #[cfg(feature = "frodo976shake")]
530                set.insert(
531                    Algorithm::FrodoKem976Shake,
532                    FrodoKem976Shake::default().algorithm(),
533                );
534                #[cfg(feature = "frodo1344shake")]
535                set.insert(
536                    Algorithm::FrodoKem1344Shake,
537                    FrodoKem1344Shake::default().algorithm(),
538                );
539                #[cfg(feature = "efrodo640aes")]
540                set.insert(
541                    Algorithm::EphemeralFrodoKem640Aes,
542                    EphemeralFrodoKem640Aes::default().algorithm(),
543                );
544                #[cfg(feature = "efrodo976aes")]
545                set.insert(
546                    Algorithm::EphemeralFrodoKem976Aes,
547                    EphemeralFrodoKem976Aes::default().algorithm(),
548                );
549                #[cfg(feature = "efrodo1344aes")]
550                set.insert(
551                    Algorithm::EphemeralFrodoKem1344Aes,
552                    EphemeralFrodoKem1344Aes::default().algorithm(),
553                );
554                #[cfg(feature = "efrodo640shake")]
555                set.insert(
556                    Algorithm::EphemeralFrodoKem640Shake,
557                    EphemeralFrodoKem640Shake::default().algorithm(),
558                );
559                #[cfg(feature = "efrodo976shake")]
560                set.insert(
561                    Algorithm::EphemeralFrodoKem976Shake,
562                    EphemeralFrodoKem976Shake::default().algorithm(),
563                );
564                #[cfg(feature = "efrodo1344shake")]
565                set.insert(
566                    Algorithm::EphemeralFrodoKem1344Shake,
567                    EphemeralFrodoKem1344Shake::default().algorithm(),
568                );
569
570                set
571            });
572        let ss = &(*ALGORITHMS)[self];
573        write!(f, "{}", ss)
574    }
575}
576
577impl std::str::FromStr for Algorithm {
578    type Err = Error;
579
580    fn from_str(s: &str) -> Result<Self, Self::Err> {
581        static ALGORITHMS: std::sync::LazyLock<std::collections::HashMap<String, Algorithm>> =
582            std::sync::LazyLock::new(|| {
583                let mut set = std::collections::HashMap::new();
584                #[cfg(feature = "frodo640aes")]
585                set.insert(
586                    FrodoKem640Aes::default().algorithm(),
587                    Algorithm::FrodoKem640Aes,
588                );
589                #[cfg(feature = "frodo976aes")]
590                set.insert(
591                    FrodoKem976Aes::default().algorithm(),
592                    Algorithm::FrodoKem976Aes,
593                );
594                #[cfg(feature = "frodo1344aes")]
595                set.insert(
596                    FrodoKem1344Aes::default().algorithm(),
597                    Algorithm::FrodoKem1344Aes,
598                );
599                #[cfg(feature = "frodo640shake")]
600                set.insert(
601                    FrodoKem640Shake::default().algorithm(),
602                    Algorithm::FrodoKem640Shake,
603                );
604                #[cfg(feature = "frodo976shake")]
605                set.insert(
606                    FrodoKem976Shake::default().algorithm(),
607                    Algorithm::FrodoKem976Shake,
608                );
609                #[cfg(feature = "frodo1344shake")]
610                set.insert(
611                    FrodoKem1344Shake::default().algorithm(),
612                    Algorithm::FrodoKem1344Shake,
613                );
614                #[cfg(feature = "efrodo640aes")]
615                set.insert(
616                    EphemeralFrodoKem640Aes::default().algorithm(),
617                    Algorithm::EphemeralFrodoKem640Aes,
618                );
619                #[cfg(feature = "efrodo976aes")]
620                set.insert(
621                    EphemeralFrodoKem976Aes::default().algorithm(),
622                    Algorithm::EphemeralFrodoKem976Aes,
623                );
624                #[cfg(feature = "efrodo1344aes")]
625                set.insert(
626                    EphemeralFrodoKem1344Aes::default().algorithm(),
627                    Algorithm::EphemeralFrodoKem1344Aes,
628                );
629                #[cfg(feature = "efrodo640shake")]
630                set.insert(
631                    EphemeralFrodoKem640Shake::default().algorithm(),
632                    Algorithm::EphemeralFrodoKem640Shake,
633                );
634                #[cfg(feature = "efrodo976shake")]
635                set.insert(
636                    EphemeralFrodoKem976Shake::default().algorithm(),
637                    Algorithm::EphemeralFrodoKem976Shake,
638                );
639                #[cfg(feature = "efrodo1344shake")]
640                set.insert(
641                    EphemeralFrodoKem1344Shake::default().algorithm(),
642                    Algorithm::EphemeralFrodoKem1344Shake,
643                );
644
645                set
646            });
647        (*ALGORITHMS)
648            .get(s)
649            .copied()
650            .ok_or(Error::UnsupportedAlgorithm)
651    }
652}
653
654impl From<Algorithm> for u8 {
655    fn from(alg: Algorithm) -> u8 {
656        match alg {
657            #[cfg(feature = "frodo640aes")]
658            Algorithm::FrodoKem640Aes => 1,
659            #[cfg(feature = "frodo976aes")]
660            Algorithm::FrodoKem976Aes => 2,
661            #[cfg(feature = "frodo1344aes")]
662            Algorithm::FrodoKem1344Aes => 3,
663            #[cfg(feature = "frodo640shake")]
664            Algorithm::FrodoKem640Shake => 4,
665            #[cfg(feature = "frodo976shake")]
666            Algorithm::FrodoKem976Shake => 5,
667            #[cfg(feature = "frodo1344shake")]
668            Algorithm::FrodoKem1344Shake => 6,
669            #[cfg(feature = "efrodo640aes")]
670            Algorithm::EphemeralFrodoKem640Aes => 7,
671            #[cfg(feature = "efrodo976aes")]
672            Algorithm::EphemeralFrodoKem976Aes => 8,
673            #[cfg(feature = "efrodo1344aes")]
674            Algorithm::EphemeralFrodoKem1344Aes => 9,
675            #[cfg(feature = "efrodo640shake")]
676            Algorithm::EphemeralFrodoKem640Shake => 10,
677            #[cfg(feature = "efrodo976shake")]
678            Algorithm::EphemeralFrodoKem976Shake => 11,
679            #[cfg(feature = "efrodo1344shake")]
680            Algorithm::EphemeralFrodoKem1344Shake => 12,
681        }
682    }
683}
684
685impl From<Algorithm> for u16 {
686    fn from(alg: Algorithm) -> u16 {
687        u8::from(alg) as u16
688    }
689}
690
691impl From<Algorithm> for u32 {
692    fn from(alg: Algorithm) -> u32 {
693        u8::from(alg) as u32
694    }
695}
696
697impl From<Algorithm> for u64 {
698    fn from(alg: Algorithm) -> u64 {
699        u8::from(alg) as u64
700    }
701}
702
703#[cfg(target_pointer_width = "64")]
704impl From<Algorithm> for u128 {
705    fn from(alg: Algorithm) -> u128 {
706        u8::from(alg) as u128
707    }
708}
709
710impl From<Algorithm> for usize {
711    fn from(alg: Algorithm) -> usize {
712        u8::from(alg) as usize
713    }
714}
715
716impl TryFrom<u8> for Algorithm {
717    type Error = Error;
718
719    fn try_from(value: u8) -> Result<Self, Self::Error> {
720        match value {
721            #[cfg(feature = "frodo640aes")]
722            1 => Ok(Algorithm::FrodoKem640Aes),
723            #[cfg(feature = "frodo976aes")]
724            2 => Ok(Algorithm::FrodoKem976Aes),
725            #[cfg(feature = "frodo1344aes")]
726            3 => Ok(Algorithm::FrodoKem1344Aes),
727            #[cfg(feature = "frodo640shake")]
728            4 => Ok(Algorithm::FrodoKem640Shake),
729            #[cfg(feature = "frodo976shake")]
730            5 => Ok(Algorithm::FrodoKem976Shake),
731            #[cfg(feature = "frodo1344shake")]
732            6 => Ok(Algorithm::FrodoKem1344Shake),
733            #[cfg(feature = "efrodo640aes")]
734            7 => Ok(Algorithm::EphemeralFrodoKem640Aes),
735            #[cfg(feature = "efrodo976aes")]
736            8 => Ok(Algorithm::EphemeralFrodoKem976Aes),
737            #[cfg(feature = "efrodo1344aes")]
738            9 => Ok(Algorithm::EphemeralFrodoKem1344Aes),
739            #[cfg(feature = "efrodo640shake")]
740            10 => Ok(Algorithm::EphemeralFrodoKem640Shake),
741            #[cfg(feature = "efrodo976shake")]
742            11 => Ok(Algorithm::EphemeralFrodoKem976Shake),
743            #[cfg(feature = "efrodo1344shake")]
744            12 => Ok(Algorithm::EphemeralFrodoKem1344Shake),
745            _ => Err(Error::UnsupportedAlgorithm),
746        }
747    }
748}
749
750impl TryFrom<u16> for Algorithm {
751    type Error = Error;
752
753    fn try_from(value: u16) -> Result<Self, Self::Error> {
754        let v = u8::try_from(value).map_err(|_| Error::UnsupportedAlgorithm)?;
755        v.try_into()
756    }
757}
758
759impl TryFrom<u32> for Algorithm {
760    type Error = Error;
761
762    fn try_from(value: u32) -> Result<Self, Self::Error> {
763        let v = u8::try_from(value).map_err(|_| Error::UnsupportedAlgorithm)?;
764        v.try_into()
765    }
766}
767
768impl TryFrom<u64> for Algorithm {
769    type Error = Error;
770
771    fn try_from(value: u64) -> Result<Self, Self::Error> {
772        let v = u8::try_from(value).map_err(|_| Error::UnsupportedAlgorithm)?;
773        v.try_into()
774    }
775}
776
777#[cfg(target_pointer_width = "64")]
778impl TryFrom<u128> for Algorithm {
779    type Error = Error;
780
781    fn try_from(value: u128) -> Result<Self, Self::Error> {
782        let v = u8::try_from(value).map_err(|_| Error::UnsupportedAlgorithm)?;
783        v.try_into()
784    }
785}
786
787impl TryFrom<usize> for Algorithm {
788    type Error = Error;
789
790    fn try_from(value: usize) -> Result<Self, Self::Error> {
791        let v = u8::try_from(value).map_err(|_| Error::UnsupportedAlgorithm)?;
792        v.try_into()
793    }
794}
795
796#[cfg(feature = "serde")]
797impl serde::Serialize for Algorithm {
798    fn serialize<S>(&self, s: S) -> Result<S::Ok, S::Error>
799    where
800        S: serde::Serializer,
801    {
802        if s.is_human_readable() {
803            s.serialize_str(&self.to_string())
804        } else {
805            s.serialize_u8(u8::from(*self))
806        }
807    }
808}
809
810#[cfg(feature = "serde")]
811impl<'de> serde::Deserialize<'de> for Algorithm {
812    fn deserialize<D>(d: D) -> Result<Algorithm, D::Error>
813    where
814        D: serde::Deserializer<'de>,
815    {
816        if d.is_human_readable() {
817            let s = String::deserialize(d)?;
818            s.parse().map_err(serde::de::Error::custom)
819        } else {
820            let v = u8::deserialize(d)?;
821            v.try_into().map_err(serde::de::Error::custom)
822        }
823    }
824}
825
826impl Algorithm {
827    /// Get the enabled algorithms
828    pub fn enabled_algorithms() -> &'static [Algorithm] {
829        &[
830            #[cfg(feature = "frodo640aes")]
831            Self::FrodoKem640Aes,
832            #[cfg(feature = "frodo976aes")]
833            Self::FrodoKem976Aes,
834            #[cfg(feature = "frodo1344aes")]
835            Self::FrodoKem1344Aes,
836            #[cfg(feature = "frodo640shake")]
837            Self::FrodoKem640Shake,
838            #[cfg(feature = "frodo976shake")]
839            Self::FrodoKem976Shake,
840            #[cfg(feature = "frodo1344shake")]
841            Self::FrodoKem1344Shake,
842            #[cfg(feature = "efrodo640aes")]
843            Self::EphemeralFrodoKem640Aes,
844            #[cfg(feature = "efrodo976aes")]
845            Self::EphemeralFrodoKem976Aes,
846            #[cfg(feature = "efrodo1344aes")]
847            Self::EphemeralFrodoKem1344Aes,
848            #[cfg(feature = "efrodo640shake")]
849            Self::EphemeralFrodoKem640Shake,
850            #[cfg(feature = "efrodo976shake")]
851            Self::EphemeralFrodoKem976Shake,
852            #[cfg(feature = "efrodo1344shake")]
853            Self::EphemeralFrodoKem1344Shake,
854        ]
855    }
856
857    /// Get the parameters for this algorithm
858    pub const fn params(&self) -> AlgorithmParams {
859        match self {
860            #[cfg(feature = "frodo640aes")]
861            Self::FrodoKem640Aes => self.inner_params::<FrodoKem640Aes>(),
862            #[cfg(feature = "frodo976aes")]
863            Self::FrodoKem976Aes => self.inner_params::<FrodoKem976Aes>(),
864            #[cfg(feature = "frodo1344aes")]
865            Self::FrodoKem1344Aes => self.inner_params::<FrodoKem1344Aes>(),
866            #[cfg(feature = "frodo640shake")]
867            Self::FrodoKem640Shake => self.inner_params::<FrodoKem640Shake>(),
868            #[cfg(feature = "frodo976shake")]
869            Self::FrodoKem976Shake => self.inner_params::<FrodoKem976Shake>(),
870            #[cfg(feature = "frodo1344shake")]
871            Self::FrodoKem1344Shake => self.inner_params::<FrodoKem1344Shake>(),
872            #[cfg(feature = "efrodo640aes")]
873            Self::EphemeralFrodoKem640Aes => self.inner_params::<EphemeralFrodoKem640Aes>(),
874            #[cfg(feature = "efrodo976aes")]
875            Self::EphemeralFrodoKem976Aes => self.inner_params::<EphemeralFrodoKem976Aes>(),
876            #[cfg(feature = "efrodo1344aes")]
877            Self::EphemeralFrodoKem1344Aes => self.inner_params::<EphemeralFrodoKem1344Aes>(),
878            #[cfg(feature = "efrodo640shake")]
879            Self::EphemeralFrodoKem640Shake => self.inner_params::<EphemeralFrodoKem640Shake>(),
880            #[cfg(feature = "efrodo976shake")]
881            Self::EphemeralFrodoKem976Shake => self.inner_params::<EphemeralFrodoKem976Shake>(),
882            #[cfg(feature = "efrodo1344shake")]
883            Self::EphemeralFrodoKem1344Shake => self.inner_params::<EphemeralFrodoKem1344Shake>(),
884        }
885    }
886
887    const fn inner_params<B: Params>(&self) -> AlgorithmParams {
888        AlgorithmParams {
889            n: B::N,
890            n_bar: B::N_BAR,
891            log_q: B::LOG_Q,
892            q: B::Q,
893            extracted_bits: B::EXTRACTED_BITS,
894            stripe_step: B::STRIPE_STEP,
895            bytes_seed_a: B::BYTES_SEED_A,
896            bytes_pk_hash: B::BYTES_PK_HASH,
897            cdf_table: B::CDF_TABLE,
898            claimed_nist_level: B::CLAIMED_NIST_LEVEL,
899            shared_secret_length: B::SHARED_SECRET_LENGTH,
900            message_length: B::BYTES_MU,
901            salt_length: B::BYTES_SALT,
902            encryption_key_length: B::PUBLIC_KEY_LENGTH,
903            decryption_key_length: B::SECRET_KEY_LENGTH,
904            ciphertext_length: B::CIPHERTEXT_LENGTH,
905        }
906    }
907
908    /// Get the [`EncryptionKey`] from a [`DecryptionKey`]
909    pub fn encryption_key_from_decryption_key(&self, secret_key: &DecryptionKey) -> EncryptionKey {
910        match self {
911            #[cfg(feature = "frodo640aes")]
912            Self::FrodoKem640Aes => {
913                self.inner_encryption_key_from_decryption_key::<FrodoKem640Aes>(secret_key)
914            }
915            #[cfg(feature = "frodo976aes")]
916            Self::FrodoKem976Aes => {
917                self.inner_encryption_key_from_decryption_key::<FrodoKem976Aes>(secret_key)
918            }
919            #[cfg(feature = "frodo1344aes")]
920            Self::FrodoKem1344Aes => {
921                self.inner_encryption_key_from_decryption_key::<FrodoKem1344Aes>(secret_key)
922            }
923            #[cfg(feature = "frodo640shake")]
924            Self::FrodoKem640Shake => {
925                self.inner_encryption_key_from_decryption_key::<FrodoKem640Shake>(secret_key)
926            }
927            #[cfg(feature = "frodo976shake")]
928            Self::FrodoKem976Shake => {
929                self.inner_encryption_key_from_decryption_key::<FrodoKem976Shake>(secret_key)
930            }
931            #[cfg(feature = "frodo1344shake")]
932            Self::FrodoKem1344Shake => {
933                self.inner_encryption_key_from_decryption_key::<FrodoKem1344Shake>(secret_key)
934            }
935            #[cfg(feature = "efrodo640aes")]
936            Self::EphemeralFrodoKem640Aes => {
937                self.inner_encryption_key_from_decryption_key::<EphemeralFrodoKem640Aes>(secret_key)
938            }
939            #[cfg(feature = "efrodo976aes")]
940            Self::EphemeralFrodoKem976Aes => {
941                self.inner_encryption_key_from_decryption_key::<EphemeralFrodoKem976Aes>(secret_key)
942            }
943            #[cfg(feature = "efrodo1344aes")]
944            Self::EphemeralFrodoKem1344Aes => self
945                .inner_encryption_key_from_decryption_key::<EphemeralFrodoKem1344Aes>(secret_key),
946            #[cfg(feature = "efrodo640shake")]
947            Self::EphemeralFrodoKem640Shake => self
948                .inner_encryption_key_from_decryption_key::<EphemeralFrodoKem640Shake>(secret_key),
949            #[cfg(feature = "efrodo976shake")]
950            Self::EphemeralFrodoKem976Shake => self
951                .inner_encryption_key_from_decryption_key::<EphemeralFrodoKem976Shake>(secret_key),
952            #[cfg(feature = "efrodo1344shake")]
953            Self::EphemeralFrodoKem1344Shake => self
954                .inner_encryption_key_from_decryption_key::<EphemeralFrodoKem1344Shake>(secret_key),
955        }
956    }
957
958    fn inner_encryption_key_from_decryption_key<B: Params>(
959        &self,
960        secret_key: &DecryptionKey,
961    ) -> EncryptionKey {
962        let sk = DecryptionKeyRef::<B>(secret_key.value.as_slice(), PhantomData);
963        EncryptionKey {
964            algorithm: *self,
965            value: sk.public_key().to_vec(),
966        }
967    }
968
969    /// Obtain a secret key from a byte slice
970    ///
971    /// Returns Err if the byte slice is not the correct length
972    pub fn decryption_key_from_bytes<B: AsRef<[u8]>>(&self, buf: B) -> FrodoResult<DecryptionKey> {
973        let buf = buf.as_ref();
974        match self {
975            #[cfg(feature = "frodo640aes")]
976            Self::FrodoKem640Aes => self.inner_decryption_key_from_bytes::<FrodoKem640Aes>(buf),
977            #[cfg(feature = "frodo976aes")]
978            Self::FrodoKem976Aes => self.inner_decryption_key_from_bytes::<FrodoKem976Aes>(buf),
979            #[cfg(feature = "frodo1344aes")]
980            Self::FrodoKem1344Aes => self.inner_decryption_key_from_bytes::<FrodoKem1344Aes>(buf),
981            #[cfg(feature = "frodo640shake")]
982            Self::FrodoKem640Shake => self.inner_decryption_key_from_bytes::<FrodoKem640Shake>(buf),
983            #[cfg(feature = "frodo976shake")]
984            Self::FrodoKem976Shake => self.inner_decryption_key_from_bytes::<FrodoKem976Shake>(buf),
985            #[cfg(feature = "frodo1344shake")]
986            Self::FrodoKem1344Shake => {
987                self.inner_decryption_key_from_bytes::<FrodoKem1344Shake>(buf)
988            }
989            #[cfg(feature = "efrodo640aes")]
990            Self::EphemeralFrodoKem640Aes => {
991                self.inner_decryption_key_from_bytes::<EphemeralFrodoKem640Aes>(buf)
992            }
993            #[cfg(feature = "efrodo976aes")]
994            Self::EphemeralFrodoKem976Aes => {
995                self.inner_decryption_key_from_bytes::<EphemeralFrodoKem976Aes>(buf)
996            }
997            #[cfg(feature = "efrodo1344aes")]
998            Self::EphemeralFrodoKem1344Aes => {
999                self.inner_decryption_key_from_bytes::<EphemeralFrodoKem1344Aes>(buf)
1000            }
1001            #[cfg(feature = "efrodo640shake")]
1002            Self::EphemeralFrodoKem640Shake => {
1003                self.inner_decryption_key_from_bytes::<EphemeralFrodoKem640Shake>(buf)
1004            }
1005            #[cfg(feature = "efrodo976shake")]
1006            Self::EphemeralFrodoKem976Shake => {
1007                self.inner_decryption_key_from_bytes::<EphemeralFrodoKem976Shake>(buf)
1008            }
1009            #[cfg(feature = "efrodo1344shake")]
1010            Self::EphemeralFrodoKem1344Shake => {
1011                self.inner_decryption_key_from_bytes::<EphemeralFrodoKem1344Shake>(buf)
1012            }
1013        }
1014    }
1015
1016    fn inner_decryption_key_from_bytes<P: Params>(&self, buf: &[u8]) -> FrodoResult<DecryptionKey> {
1017        hazmat::DecryptionKey::<P>::from_slice(buf).map(|s| DecryptionKey {
1018            algorithm: *self,
1019            value: s.0,
1020        })
1021    }
1022
1023    /// Obtain a public key from a byte slice
1024    ///
1025    /// Returns Err if the byte slice is not the correct length
1026    pub fn encryption_key_from_bytes<B: AsRef<[u8]>>(&self, buf: B) -> FrodoResult<EncryptionKey> {
1027        let buf = buf.as_ref();
1028        match self {
1029            #[cfg(feature = "frodo640aes")]
1030            Self::FrodoKem640Aes => self.inner_encryption_key_from_bytes::<FrodoKem640Aes>(buf),
1031            #[cfg(feature = "frodo976aes")]
1032            Self::FrodoKem976Aes => self.inner_encryption_key_from_bytes::<FrodoKem976Aes>(buf),
1033            #[cfg(feature = "frodo1344aes")]
1034            Self::FrodoKem1344Aes => self.inner_encryption_key_from_bytes::<FrodoKem1344Aes>(buf),
1035            #[cfg(feature = "frodo640shake")]
1036            Self::FrodoKem640Shake => self.inner_encryption_key_from_bytes::<FrodoKem640Shake>(buf),
1037            #[cfg(feature = "frodo976shake")]
1038            Self::FrodoKem976Shake => self.inner_encryption_key_from_bytes::<FrodoKem976Shake>(buf),
1039            #[cfg(feature = "frodo1344shake")]
1040            Self::FrodoKem1344Shake => {
1041                self.inner_encryption_key_from_bytes::<FrodoKem1344Shake>(buf)
1042            }
1043            #[cfg(feature = "efrodo640aes")]
1044            Self::EphemeralFrodoKem640Aes => {
1045                self.inner_encryption_key_from_bytes::<EphemeralFrodoKem640Aes>(buf)
1046            }
1047            #[cfg(feature = "efrodo976aes")]
1048            Self::EphemeralFrodoKem976Aes => {
1049                self.inner_encryption_key_from_bytes::<EphemeralFrodoKem976Aes>(buf)
1050            }
1051            #[cfg(feature = "efrodo1344aes")]
1052            Self::EphemeralFrodoKem1344Aes => {
1053                self.inner_encryption_key_from_bytes::<EphemeralFrodoKem1344Aes>(buf)
1054            }
1055            #[cfg(feature = "efrodo640shake")]
1056            Self::EphemeralFrodoKem640Shake => {
1057                self.inner_encryption_key_from_bytes::<EphemeralFrodoKem640Shake>(buf)
1058            }
1059            #[cfg(feature = "efrodo976shake")]
1060            Self::EphemeralFrodoKem976Shake => {
1061                self.inner_encryption_key_from_bytes::<EphemeralFrodoKem976Shake>(buf)
1062            }
1063            #[cfg(feature = "efrodo1344shake")]
1064            Self::EphemeralFrodoKem1344Shake => {
1065                self.inner_encryption_key_from_bytes::<EphemeralFrodoKem1344Shake>(buf)
1066            }
1067        }
1068    }
1069
1070    fn inner_encryption_key_from_bytes<P: Params>(&self, buf: &[u8]) -> FrodoResult<EncryptionKey> {
1071        hazmat::EncryptionKey::<P>::from_slice(buf).map(|s| EncryptionKey {
1072            algorithm: *self,
1073            value: s.0,
1074        })
1075    }
1076
1077    /// Obtain a ciphertext from a byte slice
1078    ///
1079    /// Returns Err if the byte slice is not the correct length
1080    pub fn ciphertext_from_bytes(&self, buf: &[u8]) -> FrodoResult<Ciphertext> {
1081        match self {
1082            #[cfg(feature = "frodo640aes")]
1083            Self::FrodoKem640Aes => {
1084                hazmat::Ciphertext::<FrodoKem640Aes>::from_slice(buf).map(|s| Ciphertext {
1085                    algorithm: *self,
1086                    value: s.0,
1087                })
1088            }
1089            #[cfg(feature = "frodo976aes")]
1090            Self::FrodoKem976Aes => {
1091                hazmat::Ciphertext::<FrodoKem976Aes>::from_slice(buf).map(|s| Ciphertext {
1092                    algorithm: *self,
1093                    value: s.0,
1094                })
1095            }
1096            #[cfg(feature = "frodo1344aes")]
1097            Self::FrodoKem1344Aes => {
1098                hazmat::Ciphertext::<FrodoKem1344Aes>::from_slice(buf).map(|s| Ciphertext {
1099                    algorithm: *self,
1100                    value: s.0,
1101                })
1102            }
1103            #[cfg(feature = "frodo640shake")]
1104            Self::FrodoKem640Shake => {
1105                hazmat::Ciphertext::<FrodoKem640Shake>::from_slice(buf).map(|s| Ciphertext {
1106                    algorithm: *self,
1107                    value: s.0,
1108                })
1109            }
1110            #[cfg(feature = "frodo976shake")]
1111            Self::FrodoKem976Shake => {
1112                hazmat::Ciphertext::<FrodoKem976Shake>::from_slice(buf).map(|s| Ciphertext {
1113                    algorithm: *self,
1114                    value: s.0,
1115                })
1116            }
1117            #[cfg(feature = "frodo1344shake")]
1118            Self::FrodoKem1344Shake => hazmat::Ciphertext::<FrodoKem1344Shake>::from_slice(buf)
1119                .map(|s| Ciphertext {
1120                    algorithm: *self,
1121                    value: s.0,
1122                }),
1123            #[cfg(feature = "efrodo640aes")]
1124            Self::EphemeralFrodoKem640Aes => {
1125                hazmat::Ciphertext::<EphemeralFrodoKem640Aes>::from_slice(buf).map(|s| Ciphertext {
1126                    algorithm: *self,
1127                    value: s.0,
1128                })
1129            }
1130            #[cfg(feature = "efrodo976aes")]
1131            Self::EphemeralFrodoKem976Aes => {
1132                hazmat::Ciphertext::<EphemeralFrodoKem976Aes>::from_slice(buf).map(|s| Ciphertext {
1133                    algorithm: *self,
1134                    value: s.0,
1135                })
1136            }
1137            #[cfg(feature = "efrodo1344aes")]
1138            Self::EphemeralFrodoKem1344Aes => {
1139                hazmat::Ciphertext::<EphemeralFrodoKem1344Aes>::from_slice(buf).map(|s| {
1140                    Ciphertext {
1141                        algorithm: *self,
1142                        value: s.0,
1143                    }
1144                })
1145            }
1146            #[cfg(feature = "efrodo640shake")]
1147            Self::EphemeralFrodoKem640Shake => {
1148                hazmat::Ciphertext::<EphemeralFrodoKem640Shake>::from_slice(buf).map(|s| {
1149                    Ciphertext {
1150                        algorithm: *self,
1151                        value: s.0,
1152                    }
1153                })
1154            }
1155            #[cfg(feature = "efrodo976shake")]
1156            Self::EphemeralFrodoKem976Shake => {
1157                hazmat::Ciphertext::<EphemeralFrodoKem976Shake>::from_slice(buf).map(|s| {
1158                    Ciphertext {
1159                        algorithm: *self,
1160                        value: s.0,
1161                    }
1162                })
1163            }
1164            #[cfg(feature = "efrodo1344shake")]
1165            Self::EphemeralFrodoKem1344Shake => {
1166                hazmat::Ciphertext::<EphemeralFrodoKem1344Shake>::from_slice(buf).map(|s| {
1167                    Ciphertext {
1168                        algorithm: *self,
1169                        value: s.0,
1170                    }
1171                })
1172            }
1173        }
1174    }
1175
1176    /// Obtain a shared secret from a byte slice
1177    ///
1178    /// Returns Err if the byte slice is not the correct length
1179    pub fn shared_secret_from_bytes(&self, buf: &[u8]) -> FrodoResult<SharedSecret> {
1180        match self {
1181            #[cfg(feature = "frodo640aes")]
1182            Self::FrodoKem640Aes => {
1183                hazmat::SharedSecret::<FrodoKem640Aes>::from_slice(buf).map(|s| SharedSecret {
1184                    algorithm: *self,
1185                    value: s.0,
1186                })
1187            }
1188            #[cfg(feature = "frodo976aes")]
1189            Self::FrodoKem976Aes => {
1190                hazmat::SharedSecret::<FrodoKem976Aes>::from_slice(buf).map(|s| SharedSecret {
1191                    algorithm: *self,
1192                    value: s.0,
1193                })
1194            }
1195            #[cfg(feature = "frodo1344aes")]
1196            Self::FrodoKem1344Aes => {
1197                hazmat::SharedSecret::<FrodoKem1344Aes>::from_slice(buf).map(|s| SharedSecret {
1198                    algorithm: *self,
1199                    value: s.0,
1200                })
1201            }
1202            #[cfg(feature = "frodo640shake")]
1203            Self::FrodoKem640Shake => hazmat::SharedSecret::<FrodoKem640Shake>::from_slice(buf)
1204                .map(|s| SharedSecret {
1205                    algorithm: *self,
1206                    value: s.0,
1207                }),
1208            #[cfg(feature = "frodo976shake")]
1209            Self::FrodoKem976Shake => hazmat::SharedSecret::<FrodoKem976Shake>::from_slice(buf)
1210                .map(|s| SharedSecret {
1211                    algorithm: *self,
1212                    value: s.0,
1213                }),
1214            #[cfg(feature = "frodo1344shake")]
1215            Self::FrodoKem1344Shake => hazmat::SharedSecret::<FrodoKem1344Shake>::from_slice(buf)
1216                .map(|s| SharedSecret {
1217                    algorithm: *self,
1218                    value: s.0,
1219                }),
1220            #[cfg(feature = "efrodo640aes")]
1221            Self::EphemeralFrodoKem640Aes => {
1222                hazmat::SharedSecret::<EphemeralFrodoKem640Aes>::from_slice(buf).map(|s| {
1223                    SharedSecret {
1224                        algorithm: *self,
1225                        value: s.0,
1226                    }
1227                })
1228            }
1229            #[cfg(feature = "efrodo976aes")]
1230            Self::EphemeralFrodoKem976Aes => {
1231                hazmat::SharedSecret::<EphemeralFrodoKem976Aes>::from_slice(buf).map(|s| {
1232                    SharedSecret {
1233                        algorithm: *self,
1234                        value: s.0,
1235                    }
1236                })
1237            }
1238            #[cfg(feature = "efrodo1344aes")]
1239            Self::EphemeralFrodoKem1344Aes => {
1240                hazmat::SharedSecret::<EphemeralFrodoKem1344Aes>::from_slice(buf).map(|s| {
1241                    SharedSecret {
1242                        algorithm: *self,
1243                        value: s.0,
1244                    }
1245                })
1246            }
1247            #[cfg(feature = "efrodo640shake")]
1248            Self::EphemeralFrodoKem640Shake => {
1249                hazmat::SharedSecret::<EphemeralFrodoKem640Shake>::from_slice(buf).map(|s| {
1250                    SharedSecret {
1251                        algorithm: *self,
1252                        value: s.0,
1253                    }
1254                })
1255            }
1256            #[cfg(feature = "efrodo976shake")]
1257            Self::EphemeralFrodoKem976Shake => {
1258                hazmat::SharedSecret::<EphemeralFrodoKem976Shake>::from_slice(buf).map(|s| {
1259                    SharedSecret {
1260                        algorithm: *self,
1261                        value: s.0,
1262                    }
1263                })
1264            }
1265            #[cfg(feature = "efrodo1344shake")]
1266            Self::EphemeralFrodoKem1344Shake => {
1267                hazmat::SharedSecret::<EphemeralFrodoKem1344Shake>::from_slice(buf).map(|s| {
1268                    SharedSecret {
1269                        algorithm: *self,
1270                        value: s.0,
1271                    }
1272                })
1273            }
1274        }
1275    }
1276
1277    /// Generate a new keypair consisting of a [`EncryptionKey`] and a [`DecryptionKey`]
1278    pub fn generate_keypair(&self, rng: impl CryptoRngCore) -> (EncryptionKey, DecryptionKey) {
1279        match self {
1280            #[cfg(feature = "frodo640aes")]
1281            Self::FrodoKem640Aes => self.inner_generate_keypair::<FrodoKem640Aes>(rng),
1282            #[cfg(feature = "frodo976aes")]
1283            Self::FrodoKem976Aes => self.inner_generate_keypair::<FrodoKem976Aes>(rng),
1284            #[cfg(feature = "frodo1344aes")]
1285            Self::FrodoKem1344Aes => self.inner_generate_keypair::<FrodoKem1344Aes>(rng),
1286            #[cfg(feature = "frodo640shake")]
1287            Self::FrodoKem640Shake => self.inner_generate_keypair::<FrodoKem640Shake>(rng),
1288            #[cfg(feature = "frodo976shake")]
1289            Self::FrodoKem976Shake => self.inner_generate_keypair::<FrodoKem976Shake>(rng),
1290            #[cfg(feature = "frodo1344shake")]
1291            Self::FrodoKem1344Shake => self.inner_generate_keypair::<FrodoKem1344Shake>(rng),
1292            #[cfg(feature = "efrodo640aes")]
1293            Self::EphemeralFrodoKem640Aes => {
1294                self.inner_generate_keypair::<EphemeralFrodoKem640Aes>(rng)
1295            }
1296            #[cfg(feature = "efrodo976aes")]
1297            Self::EphemeralFrodoKem976Aes => {
1298                self.inner_generate_keypair::<EphemeralFrodoKem976Aes>(rng)
1299            }
1300            #[cfg(feature = "efrodo1344aes")]
1301            Self::EphemeralFrodoKem1344Aes => {
1302                self.inner_generate_keypair::<EphemeralFrodoKem1344Aes>(rng)
1303            }
1304            #[cfg(feature = "efrodo640shake")]
1305            Self::EphemeralFrodoKem640Shake => {
1306                self.inner_generate_keypair::<EphemeralFrodoKem640Shake>(rng)
1307            }
1308            #[cfg(feature = "efrodo976shake")]
1309            Self::EphemeralFrodoKem976Shake => {
1310                self.inner_generate_keypair::<EphemeralFrodoKem976Shake>(rng)
1311            }
1312            #[cfg(feature = "efrodo1344shake")]
1313            Self::EphemeralFrodoKem1344Shake => {
1314                self.inner_generate_keypair::<EphemeralFrodoKem1344Shake>(rng)
1315            }
1316        }
1317    }
1318
1319    fn inner_generate_keypair<K: Kem>(
1320        &self,
1321        rng: impl CryptoRngCore,
1322    ) -> (EncryptionKey, DecryptionKey) {
1323        let (pk, sk) = K::default().generate_keypair(rng);
1324        (
1325            EncryptionKey {
1326                algorithm: *self,
1327                value: pk.0,
1328            },
1329            DecryptionKey {
1330                algorithm: *self,
1331                value: sk.0,
1332            },
1333        )
1334    }
1335
1336    /// Encapsulate with given message to generate a [`SharedSecret`] and a [`Ciphertext`].
1337    ///
1338    /// NOTE: The message and salt must be of the correct length for the algorithm.
1339    /// Also, this method is deterministic, meaning that using the same message and salt
1340    /// will yield the same [`SharedSecret`] and [`Ciphertext`]
1341    pub fn encapsulate<B: AsRef<[u8]>, S: AsRef<[u8]>>(
1342        &self,
1343        public_key: &EncryptionKey,
1344        msg: B,
1345        salt: S,
1346    ) -> FrodoResult<(Ciphertext, SharedSecret)> {
1347        let msg = msg.as_ref();
1348        let salt = salt.as_ref();
1349        match self {
1350            #[cfg(feature = "frodo640aes")]
1351            Self::FrodoKem640Aes => self.inner_encapsulate::<FrodoKem640Aes>(public_key, msg, salt),
1352            #[cfg(feature = "frodo976aes")]
1353            Self::FrodoKem976Aes => self.inner_encapsulate::<FrodoKem976Aes>(public_key, msg, salt),
1354            #[cfg(feature = "frodo1344aes")]
1355            Self::FrodoKem1344Aes => {
1356                self.inner_encapsulate::<FrodoKem1344Aes>(public_key, msg, salt)
1357            }
1358            #[cfg(feature = "frodo640shake")]
1359            Self::FrodoKem640Shake => {
1360                self.inner_encapsulate::<FrodoKem640Shake>(public_key, msg, salt)
1361            }
1362            #[cfg(feature = "frodo976shake")]
1363            Self::FrodoKem976Shake => {
1364                self.inner_encapsulate::<FrodoKem976Shake>(public_key, msg, salt)
1365            }
1366            #[cfg(feature = "frodo1344shake")]
1367            Self::FrodoKem1344Shake => {
1368                self.inner_encapsulate::<FrodoKem1344Shake>(public_key, msg, salt)
1369            }
1370            #[cfg(feature = "efrodo640aes")]
1371            Self::EphemeralFrodoKem640Aes => {
1372                self.inner_encapsulate::<EphemeralFrodoKem640Aes>(public_key, msg, salt)
1373            }
1374            #[cfg(feature = "efrodo976aes")]
1375            Self::EphemeralFrodoKem976Aes => {
1376                self.inner_encapsulate::<EphemeralFrodoKem976Aes>(public_key, msg, salt)
1377            }
1378            #[cfg(feature = "efrodo1344aes")]
1379            Self::EphemeralFrodoKem1344Aes => {
1380                self.inner_encapsulate::<EphemeralFrodoKem1344Aes>(public_key, msg, salt)
1381            }
1382            #[cfg(feature = "efrodo640shake")]
1383            Self::EphemeralFrodoKem640Shake => {
1384                self.inner_encapsulate::<EphemeralFrodoKem640Shake>(public_key, msg, salt)
1385            }
1386            #[cfg(feature = "efrodo976shake")]
1387            Self::EphemeralFrodoKem976Shake => {
1388                self.inner_encapsulate::<EphemeralFrodoKem976Shake>(public_key, msg, salt)
1389            }
1390            #[cfg(feature = "efrodo1344shake")]
1391            Self::EphemeralFrodoKem1344Shake => {
1392                self.inner_encapsulate::<EphemeralFrodoKem1344Shake>(public_key, msg, salt)
1393            }
1394        }
1395    }
1396
1397    fn inner_encapsulate<K: Kem>(
1398        &self,
1399        encryption_key: &EncryptionKey,
1400        msg: &[u8],
1401        salt: &[u8],
1402    ) -> FrodoResult<(Ciphertext, SharedSecret)> {
1403        if K::BYTES_MU != msg.len() {
1404            return Err(Error::InvalidMessageLength(msg.len()));
1405        }
1406        let pk = EncryptionKeyRef::from_slice(encryption_key.value.as_slice())?;
1407        let (ct, ss) = K::default().encapsulate(pk, msg, salt);
1408        Ok((
1409            Ciphertext {
1410                algorithm: *self,
1411                value: ct.0,
1412            },
1413            SharedSecret {
1414                algorithm: *self,
1415                value: ss.0,
1416            },
1417        ))
1418    }
1419
1420    /// Encapsulate a random value to generate a [`SharedSecret`] and a [`Ciphertext`].
1421    pub fn encapsulate_with_rng(
1422        &self,
1423        public_key: &EncryptionKey,
1424        rng: impl CryptoRngCore,
1425    ) -> FrodoResult<(Ciphertext, SharedSecret)> {
1426        match self {
1427            #[cfg(feature = "frodo640aes")]
1428            Self::FrodoKem640Aes => {
1429                self.inner_encapsulate_with_rng::<FrodoKem640Aes>(public_key, rng)
1430            }
1431            #[cfg(feature = "frodo976aes")]
1432            Self::FrodoKem976Aes => {
1433                self.inner_encapsulate_with_rng::<FrodoKem976Aes>(public_key, rng)
1434            }
1435            #[cfg(feature = "frodo1344aes")]
1436            Self::FrodoKem1344Aes => {
1437                self.inner_encapsulate_with_rng::<FrodoKem1344Aes>(public_key, rng)
1438            }
1439            #[cfg(feature = "frodo640shake")]
1440            Self::FrodoKem640Shake => {
1441                self.inner_encapsulate_with_rng::<FrodoKem640Shake>(public_key, rng)
1442            }
1443            #[cfg(feature = "frodo976shake")]
1444            Self::FrodoKem976Shake => {
1445                self.inner_encapsulate_with_rng::<FrodoKem976Shake>(public_key, rng)
1446            }
1447            #[cfg(feature = "frodo1344shake")]
1448            Self::FrodoKem1344Shake => {
1449                self.inner_encapsulate_with_rng::<FrodoKem1344Shake>(public_key, rng)
1450            }
1451            #[cfg(feature = "efrodo640aes")]
1452            Self::EphemeralFrodoKem640Aes => {
1453                self.inner_encapsulate_with_rng::<EphemeralFrodoKem640Aes>(public_key, rng)
1454            }
1455            #[cfg(feature = "efrodo976aes")]
1456            Self::EphemeralFrodoKem976Aes => {
1457                self.inner_encapsulate_with_rng::<EphemeralFrodoKem976Aes>(public_key, rng)
1458            }
1459            #[cfg(feature = "efrodo1344aes")]
1460            Self::EphemeralFrodoKem1344Aes => {
1461                self.inner_encapsulate_with_rng::<EphemeralFrodoKem1344Aes>(public_key, rng)
1462            }
1463            #[cfg(feature = "efrodo640shake")]
1464            Self::EphemeralFrodoKem640Shake => {
1465                self.inner_encapsulate_with_rng::<EphemeralFrodoKem640Shake>(public_key, rng)
1466            }
1467            #[cfg(feature = "efrodo976shake")]
1468            Self::EphemeralFrodoKem976Shake => {
1469                self.inner_encapsulate_with_rng::<EphemeralFrodoKem976Shake>(public_key, rng)
1470            }
1471            #[cfg(feature = "efrodo1344shake")]
1472            Self::EphemeralFrodoKem1344Shake => {
1473                self.inner_encapsulate_with_rng::<EphemeralFrodoKem1344Shake>(public_key, rng)
1474            }
1475        }
1476    }
1477
1478    fn inner_encapsulate_with_rng<K: Kem>(
1479        &self,
1480        encryption_key: &EncryptionKey,
1481        rng: impl CryptoRngCore,
1482    ) -> FrodoResult<(Ciphertext, SharedSecret)> {
1483        let pk = EncryptionKeyRef::from_slice(encryption_key.value.as_slice())?;
1484        let (ct, ss) = K::default().encapsulate_with_rng(pk, rng);
1485        Ok((
1486            Ciphertext {
1487                algorithm: *self,
1488                value: ct.0,
1489            },
1490            SharedSecret {
1491                algorithm: *self,
1492                value: ss.0,
1493            },
1494        ))
1495    }
1496
1497    /// Decapsulate the [`Ciphertext`] to return the [`SharedSecret`] and
1498    /// message generated during encapsulation.
1499    pub fn decapsulate(
1500        &self,
1501        secret_key: &DecryptionKey,
1502        ciphertext: &Ciphertext,
1503    ) -> FrodoResult<(SharedSecret, Vec<u8>)> {
1504        match self {
1505            #[cfg(feature = "frodo640aes")]
1506            Self::FrodoKem640Aes => {
1507                self.inner_decapsulate::<FrodoKem640Aes>(secret_key, ciphertext)
1508            }
1509            #[cfg(feature = "frodo976aes")]
1510            Self::FrodoKem976Aes => {
1511                self.inner_decapsulate::<FrodoKem976Aes>(secret_key, ciphertext)
1512            }
1513            #[cfg(feature = "frodo1344aes")]
1514            Self::FrodoKem1344Aes => {
1515                self.inner_decapsulate::<FrodoKem1344Aes>(secret_key, ciphertext)
1516            }
1517            #[cfg(feature = "frodo640shake")]
1518            Self::FrodoKem640Shake => {
1519                self.inner_decapsulate::<FrodoKem640Shake>(secret_key, ciphertext)
1520            }
1521            #[cfg(feature = "frodo976shake")]
1522            Self::FrodoKem976Shake => {
1523                self.inner_decapsulate::<FrodoKem976Shake>(secret_key, ciphertext)
1524            }
1525            #[cfg(feature = "frodo1344shake")]
1526            Self::FrodoKem1344Shake => {
1527                self.inner_decapsulate::<FrodoKem1344Shake>(secret_key, ciphertext)
1528            }
1529            #[cfg(feature = "efrodo640aes")]
1530            Self::EphemeralFrodoKem640Aes => {
1531                self.inner_decapsulate::<EphemeralFrodoKem640Aes>(secret_key, ciphertext)
1532            }
1533            #[cfg(feature = "efrodo976aes")]
1534            Self::EphemeralFrodoKem976Aes => {
1535                self.inner_decapsulate::<EphemeralFrodoKem976Aes>(secret_key, ciphertext)
1536            }
1537            #[cfg(feature = "efrodo1344aes")]
1538            Self::EphemeralFrodoKem1344Aes => {
1539                self.inner_decapsulate::<EphemeralFrodoKem1344Aes>(secret_key, ciphertext)
1540            }
1541            #[cfg(feature = "efrodo640shake")]
1542            Self::EphemeralFrodoKem640Shake => {
1543                self.inner_decapsulate::<EphemeralFrodoKem640Shake>(secret_key, ciphertext)
1544            }
1545            #[cfg(feature = "efrodo976shake")]
1546            Self::EphemeralFrodoKem976Shake => {
1547                self.inner_decapsulate::<EphemeralFrodoKem976Shake>(secret_key, ciphertext)
1548            }
1549            #[cfg(feature = "efrodo1344shake")]
1550            Self::EphemeralFrodoKem1344Shake => {
1551                self.inner_decapsulate::<EphemeralFrodoKem1344Shake>(secret_key, ciphertext)
1552            }
1553        }
1554    }
1555
1556    fn inner_decapsulate<K: Kem>(
1557        &self,
1558        secret_key: &DecryptionKey,
1559        ciphertext: &Ciphertext,
1560    ) -> FrodoResult<(SharedSecret, Vec<u8>)> {
1561        let sk = DecryptionKeyRef::from_slice(secret_key.value.as_slice())?;
1562        let ct = CiphertextRef::from_slice(ciphertext.value.as_slice())?;
1563        let (ss, mu) = K::default().decapsulate(sk, ct);
1564        Ok((
1565            SharedSecret {
1566                algorithm: *self,
1567                value: ss.0,
1568            },
1569            mu,
1570        ))
1571    }
1572}
1573
1574/// The algorithm underlying parameters
1575#[derive(Debug, Clone, Copy)]
1576pub struct AlgorithmParams {
1577    /// Number of elements in the ring
1578    pub n: usize,
1579    /// Number of rows in the matrix
1580    pub n_bar: usize,
1581    /// The log of the modulus
1582    pub log_q: usize,
1583    /// The modulus
1584    pub q: usize,
1585    /// The number of bits to extract when packing/unpacking
1586    /// encoding/decoding
1587    pub extracted_bits: usize,
1588    /// The number of steps for striping
1589    pub stripe_step: usize,
1590    /// The number of bytes in the seed for generating the matrix A
1591    pub bytes_seed_a: usize,
1592    /// The number of bytes in the public key hash
1593    pub bytes_pk_hash: usize,
1594    /// The CDF sampling table
1595    pub cdf_table: &'static [u16],
1596    /// The claimed NIST level
1597    pub claimed_nist_level: usize,
1598    /// The byte length of the shared secret
1599    pub shared_secret_length: usize,
1600    /// The byte length of an encrypted message
1601    pub message_length: usize,
1602    /// The byte length of the salt
1603    pub salt_length: usize,
1604    /// The byte length of the encryption key
1605    pub encryption_key_length: usize,
1606    /// The byte length of the decryption key
1607    pub decryption_key_length: usize,
1608    /// The byte length of the ciphertext
1609    pub ciphertext_length: usize,
1610}
1611
1612fn ct_eq_bytes(lhs: &[u8], rhs: &[u8]) -> Choice {
1613    if lhs.len() != rhs.len() {
1614        return 0u8.into();
1615    }
1616
1617    let mut eq = 0u8;
1618    for i in 0..lhs.len() {
1619        eq |= lhs[i] ^ rhs[i];
1620    }
1621
1622    let eq = ((eq | eq.wrapping_neg()) >> 7).wrapping_add(1);
1623    Choice::from(eq)
1624}
1625
1626#[cfg(test)]
1627mod tests {
1628    use super::*;
1629    use rand_core::{RngCore, SeedableRng};
1630    use rstest::*;
1631    use safe_oqs::kem;
1632
1633    #[rstest]
1634    #[case::aes640(Algorithm::EphemeralFrodoKem640Aes, kem::Algorithm::FrodoKem640Aes)]
1635    #[case::aes976(Algorithm::EphemeralFrodoKem976Aes, kem::Algorithm::FrodoKem976Aes)]
1636    #[case::aes1344(Algorithm::EphemeralFrodoKem1344Aes, kem::Algorithm::FrodoKem1344Aes)]
1637    #[case::shake640(Algorithm::EphemeralFrodoKem640Shake, kem::Algorithm::FrodoKem640Shake)]
1638    #[case::shake976(Algorithm::EphemeralFrodoKem976Shake, kem::Algorithm::FrodoKem976Shake)]
1639    #[case::shake1344(
1640        Algorithm::EphemeralFrodoKem1344Shake,
1641        kem::Algorithm::FrodoKem1344Shake
1642    )]
1643    fn ephemeral_works(#[case] alg: Algorithm, #[case] safe_alg: kem::Algorithm) {
1644        let mut rng = rand_chacha::ChaCha8Rng::from_seed([1u8; 32]);
1645        let (our_pk, our_sk) = alg.generate_keypair(&mut rng);
1646        let kem = kem::Kem::new(safe_alg).unwrap();
1647
1648        let opt_pk = kem.public_key_from_bytes(&our_pk.value);
1649        assert!(opt_pk.is_some());
1650        let opt_sk = kem.secret_key_from_bytes(&our_sk.value);
1651        assert!(opt_sk.is_some());
1652
1653        let their_pk = opt_pk.unwrap();
1654        let their_sk = opt_sk.unwrap();
1655
1656        let mut mu = vec![0u8; alg.params().message_length];
1657        rng.fill_bytes(&mut mu);
1658        let (our_ct, our_ess) = alg.encapsulate(&our_pk, &mu, &[]).unwrap();
1659        let (our_dss, mu_prime) = alg.decapsulate(&our_sk, &our_ct).unwrap();
1660        assert_eq!(our_ess.value, our_dss.value);
1661        assert_eq!(mu, mu_prime);
1662
1663        let their_ct = kem.ciphertext_from_bytes(&our_ct.value).unwrap();
1664        let their_ss = kem.decapsulate(&their_sk, &their_ct).unwrap();
1665        assert_eq!(our_dss.value, their_ss.as_ref());
1666
1667        let (their_ct, their_ess) = kem.encapsulate(&their_pk).unwrap();
1668
1669        let our_ct = alg.ciphertext_from_bytes(&their_ct.as_ref()).unwrap();
1670
1671        let (their_dss, _) = alg.decapsulate(&our_sk, &our_ct).unwrap();
1672        assert_eq!(their_ess.as_ref(), their_dss.value);
1673    }
1674
1675    #[rstest]
1676    #[case::aes640(Algorithm::FrodoKem640Aes)]
1677    #[case::aes976(Algorithm::FrodoKem976Aes)]
1678    #[case::aes1344(Algorithm::FrodoKem1344Aes)]
1679    #[case::shake640(Algorithm::FrodoKem640Shake)]
1680    #[case::shake976(Algorithm::FrodoKem976Shake)]
1681    #[case::shake1344(Algorithm::FrodoKem1344Shake)]
1682    fn works(#[case] alg: Algorithm) {
1683        let mut rng = rand_chacha::ChaCha8Rng::from_seed([1u8; 32]);
1684        let (our_pk, our_sk) = alg.generate_keypair(&mut rng);
1685
1686        let mut mu = vec![0u8; alg.params().message_length];
1687        rng.fill_bytes(&mut mu);
1688        let mut salt = vec![0u8; alg.params().salt_length];
1689        rng.fill_bytes(&mut salt);
1690        let (our_ct, our_ess) = alg.encapsulate(&our_pk, &mu, &salt).unwrap();
1691        let (our_dss, mu_prime) = alg.decapsulate(&our_sk, &our_ct).unwrap();
1692        assert_eq!(our_ess.value, our_dss.value);
1693        assert_eq!(mu, mu_prime);
1694    }
1695
1696    macro_rules! serde_test {
1697        ($name:ident, $ser:path, $de:path) => {
1698            #[cfg(feature = "serde")]
1699            #[rstest]
1700            #[case::aes640(Algorithm::FrodoKem640Aes)]
1701            #[case::aes976(Algorithm::FrodoKem976Aes)]
1702            #[case::aes1344(Algorithm::FrodoKem1344Aes)]
1703            #[case::shake640(Algorithm::FrodoKem640Shake)]
1704            #[case::shake976(Algorithm::FrodoKem976Shake)]
1705            #[case::shake1344(Algorithm::FrodoKem1344Shake)]
1706            #[case::aes640(Algorithm::EphemeralFrodoKem640Aes)]
1707            #[case::aes976(Algorithm::EphemeralFrodoKem976Aes)]
1708            #[case::aes1344(Algorithm::EphemeralFrodoKem1344Aes)]
1709            #[case::shake640(Algorithm::EphemeralFrodoKem640Shake)]
1710            #[case::shake976(Algorithm::EphemeralFrodoKem976Shake)]
1711            #[case::shake1344(Algorithm::EphemeralFrodoKem1344Shake)]
1712            fn $name(#[case] alg: Algorithm) {
1713                let mut rng = rand_chacha::ChaCha8Rng::from_seed([3u8; 32]);
1714                let (pk, sk) = alg.generate_keypair(&mut rng);
1715                let (ct, ss) = alg.encapsulate_with_rng(&pk, &mut rng).unwrap();
1716
1717                let pk_str = $ser(&pk);
1718                let sk_str = $ser(&sk);
1719                let ct_str = $ser(&ct);
1720                let ss_str = $ser(&ss);
1721
1722                assert!(pk_str.is_ok());
1723                assert!(sk_str.is_ok());
1724                assert!(ct_str.is_ok());
1725                assert!(ss_str.is_ok());
1726
1727                let pk_str = pk_str.unwrap();
1728                let sk_str = sk_str.unwrap();
1729                let ct_str = ct_str.unwrap();
1730                let ss_str = ss_str.unwrap();
1731
1732                let pk2 = $de(&pk_str);
1733                let sk2 = $de(&sk_str);
1734                let ct2 = $de(&ct_str);
1735                let ss2 = $de(&ss_str);
1736
1737                assert!(pk2.is_ok());
1738                assert!(sk2.is_ok());
1739                assert!(ct2.is_ok());
1740                assert!(ss2.is_ok());
1741
1742                let pk2 = pk2.unwrap();
1743                let sk2 = sk2.unwrap();
1744                let ct2 = ct2.unwrap();
1745                let ss2 = ss2.unwrap();
1746
1747                assert_eq!(pk, pk2);
1748                assert_eq!(sk, sk2);
1749                assert_eq!(ct, ct2);
1750                assert_eq!(ss, ss2);
1751            }
1752        };
1753    }
1754
1755    serde_test!(
1756        serialization_json,
1757        serde_json::to_string,
1758        serde_json::from_str
1759    );
1760    serde_test!(serialization_toml, toml::to_string, toml::from_str);
1761    serde_test!(
1762        serialization_yaml,
1763        serde_yaml::to_string,
1764        serde_yaml::from_str
1765    );
1766    serde_test!(
1767        serialization_bare,
1768        serde_bare::to_vec,
1769        serde_bare::from_slice
1770    );
1771    serde_test!(
1772        serialization_cbor,
1773        serde_cbor::to_vec,
1774        serde_cbor::from_slice
1775    );
1776    serde_test!(
1777        serialization_postcard,
1778        postcard::to_stdvec,
1779        postcard::from_bytes
1780    );
1781    serde_test!(
1782        serialization_bincode,
1783        bincode::serialize,
1784        bincode::deserialize
1785    );
1786}