1#![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#[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 pub fn algorithm(&self) -> Algorithm {
255 self.algorithm
256 }
257
258 pub fn value(&self) -> &[u8] {
260 self.value.as_slice()
261 }
262
263 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#[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 pub fn algorithm(&self) -> Algorithm {
297 self.algorithm
298 }
299
300 pub fn value(&self) -> &[u8] {
302 self.value.as_slice()
303 }
304
305 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 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 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#[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 pub fn algorithm(&self) -> Algorithm {
360 self.algorithm
361 }
362
363 pub fn value(&self) -> &[u8] {
365 self.value.as_slice()
366 }
367
368 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 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#[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 pub fn algorithm(&self) -> Algorithm {
411 self.algorithm
412 }
413
414 pub fn value(&self) -> &[u8] {
416 self.value.as_slice()
417 }
418
419 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#[derive(Debug, Clone, Copy, PartialEq, Eq, Ord, PartialOrd, Hash)]
427pub enum Algorithm {
428 #[cfg(feature = "frodo640aes")]
429 FrodoKem640Aes,
431 #[cfg(feature = "frodo976aes")]
432 FrodoKem976Aes,
434 #[cfg(feature = "frodo1344aes")]
435 FrodoKem1344Aes,
437 #[cfg(feature = "frodo640shake")]
438 FrodoKem640Shake,
440 #[cfg(feature = "frodo976shake")]
441 FrodoKem976Shake,
443 #[cfg(feature = "frodo1344shake")]
444 FrodoKem1344Shake,
446 #[cfg(feature = "efrodo640aes")]
447 EphemeralFrodoKem640Aes,
449 #[cfg(feature = "efrodo976aes")]
450 EphemeralFrodoKem976Aes,
452 #[cfg(feature = "efrodo1344aes")]
453 EphemeralFrodoKem1344Aes,
455 #[cfg(feature = "efrodo640shake")]
456 EphemeralFrodoKem640Shake,
458 #[cfg(feature = "efrodo976shake")]
459 EphemeralFrodoKem976Shake,
461 #[cfg(feature = "efrodo1344shake")]
462 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 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 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 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 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 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 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 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 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 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 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 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#[derive(Debug, Clone, Copy)]
1576pub struct AlgorithmParams {
1577 pub n: usize,
1579 pub n_bar: usize,
1581 pub log_q: usize,
1583 pub q: usize,
1585 pub extracted_bits: usize,
1588 pub stripe_step: usize,
1590 pub bytes_seed_a: usize,
1592 pub bytes_pk_hash: usize,
1594 pub cdf_table: &'static [u16],
1596 pub claimed_nist_level: usize,
1598 pub shared_secret_length: usize,
1600 pub message_length: usize,
1602 pub salt_length: usize,
1604 pub encryption_key_length: usize,
1606 pub decryption_key_length: usize,
1608 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}