Skip to main content

frodo_kem/
lib.rs

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