#![no_std]
#![cfg_attr(docsrs, feature(doc_cfg))]
#![doc = include_str!("../README.md")]
#![doc(
html_logo_url = "https://raw.githubusercontent.com/RustCrypto/meta/master/logo.svg",
html_favicon_url = "https://raw.githubusercontent.com/RustCrypto/meta/master/logo.svg"
)]
#![allow(
clippy::cast_possible_truncation,
clippy::cast_possible_wrap,
clippy::cast_sign_loss,
clippy::doc_markdown,
clippy::integer_division_remainder_used,
clippy::missing_errors_doc,
clippy::trivially_copy_pass_by_ref,
clippy::undocumented_unsafe_blocks,
reason = "TODO"
)]
#[cfg(not(any(
feature = "efrodo640aes",
feature = "frodo640aes",
feature = "efrodo976aes",
feature = "frodo976aes",
feature = "efrodo1344aes",
feature = "frodo1344aes",
feature = "efrodo640shake",
feature = "frodo640shake",
feature = "efrodo976shake",
feature = "frodo976shake",
feature = "efrodo1344shake",
feature = "frodo1344shake",
)))]
compile_error!("no algorithm feature enabled");
#[macro_use]
extern crate alloc;
#[cfg(feature = "std")]
extern crate std;
#[cfg(feature = "hazmat")]
pub mod hazmat;
#[cfg(not(feature = "hazmat"))]
mod hazmat;
mod error;
pub use error::*;
use alloc::vec::Vec;
use core::marker::PhantomData;
use hazmat::*;
use rand_core::CryptoRng;
use subtle::{Choice, ConstantTimeEq};
use zeroize::{Zeroize, ZeroizeOnDrop};
#[cfg(feature = "serde")]
use alloc::string::{String, ToString};
macro_rules! serde_impl {
($name:ident, $from_method:ident) => {
#[cfg(feature = "serde")]
impl serde::Serialize for $name {
fn serialize<S>(&self, s: S) -> Result<S::Ok, S::Error>
where
S: serde::Serializer,
{
if s.is_human_readable() {
use serde::ser::SerializeStruct;
let mut map = s.serialize_struct(stringify!($name), 2)?;
map.serialize_field("algorithm", &self.algorithm.to_string())?;
map.serialize_field("value", &hex::encode(&self.value))?;
map.end()
} else {
let mut seq = vec![u8::from(self.algorithm)];
seq.extend_from_slice(self.value.as_slice());
s.serialize_bytes(&seq)
}
}
}
#[cfg(feature = "serde")]
impl<'de> serde::Deserialize<'de> for $name {
fn deserialize<D>(d: D) -> Result<Self, D::Error>
where
D: serde::Deserializer<'de>,
{
if d.is_human_readable() {
struct FieldVisitor;
#[derive(serde::Deserialize)]
#[serde(field_identifier, rename_all = "snake_case")]
enum Field {
Algorithm,
Value,
}
impl<'de> serde::de::Visitor<'de> for FieldVisitor {
type Value = $name;
fn expecting(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
write!(f, "a struct with two fields")
}
fn visit_map<A>(self, mut map: A) -> Result<Self::Value, A::Error>
where
A: serde::de::MapAccess<'de>,
{
let mut algorithm = Option::<Algorithm>::None;
let mut value = Option::<String>::None;
while let Some(key) = map.next_key()? {
match key {
Field::Algorithm => {
if algorithm.is_some() {
return Err(serde::de::Error::duplicate_field(
"algorithm",
));
}
algorithm = Some(map.next_value()?);
}
Field::Value => {
if value.is_some() {
return Err(serde::de::Error::duplicate_field("value"));
}
value = Some(map.next_value()?);
}
}
}
let algorithm = algorithm
.ok_or_else(|| serde::de::Error::missing_field("algorithm"))?;
let value =
value.ok_or_else(|| serde::de::Error::missing_field("value"))?;
let value = hex::decode(&value).map_err(serde::de::Error::custom)?;
algorithm
.$from_method(&value)
.map_err(serde::de::Error::custom)
}
}
const FIELDS: &[&str] = &["algorithm", "value"];
d.deserialize_struct("Ciphertext", FIELDS, FieldVisitor)
} else {
struct BytesVisitor;
impl<'de> serde::de::Visitor<'de> for BytesVisitor {
type Value = $name;
fn expecting(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
write!(f, "a byte sequence")
}
fn visit_bytes<E>(self, v: &[u8]) -> Result<Self::Value, E>
where
E: serde::de::Error,
{
let (&tag, value) = v
.split_first()
.ok_or_else(|| serde::de::Error::custom("empty input"))?;
let algorithm =
Algorithm::try_from(tag).map_err(serde::de::Error::custom)?;
algorithm
.$from_method(value)
.map_err(serde::de::Error::custom)
}
}
d.deserialize_bytes(BytesVisitor)
}
}
}
};
}
macro_rules! ct_eq_imp {
($name:ident) => {
impl ConstantTimeEq for $name {
fn ct_eq(&self, other: &Self) -> Choice {
self.algorithm.ct_eq(&other.algorithm) & self.value.ct_eq(&other.value)
}
}
impl Eq for $name {}
impl PartialEq for $name {
fn eq(&self, other: &Self) -> bool {
self.ct_eq(other).unwrap_u8() == 1
}
}
};
}
#[derive(Debug, Clone, Default)]
pub struct Ciphertext {
pub(crate) algorithm: Algorithm,
pub(crate) value: Vec<u8>,
}
impl AsRef<[u8]> for Ciphertext {
fn as_ref(&self) -> &[u8] {
self.value.as_ref()
}
}
ct_eq_imp!(Ciphertext);
serde_impl!(Ciphertext, ciphertext_from_bytes);
impl Ciphertext {
#[must_use]
pub fn algorithm(&self) -> Algorithm {
self.algorithm
}
#[must_use]
pub fn value(&self) -> &[u8] {
self.value.as_slice()
}
pub fn from_bytes<B: AsRef<[u8]>>(algorithm: Algorithm, value: B) -> FrodoResult<Self> {
algorithm.ciphertext_from_bytes(value.as_ref())
}
}
#[derive(Debug, Clone, Default)]
pub struct EncryptionKey {
pub(crate) algorithm: Algorithm,
pub(crate) value: Vec<u8>,
}
impl AsRef<[u8]> for EncryptionKey {
fn as_ref(&self) -> &[u8] {
self.value.as_ref()
}
}
impl From<&DecryptionKey> for EncryptionKey {
fn from(secret_key: &DecryptionKey) -> Self {
secret_key
.algorithm
.encryption_key_from_decryption_key(secret_key)
}
}
ct_eq_imp!(EncryptionKey);
serde_impl!(EncryptionKey, encryption_key_from_bytes);
impl EncryptionKey {
#[must_use]
pub fn algorithm(&self) -> Algorithm {
self.algorithm
}
#[must_use]
pub fn value(&self) -> &[u8] {
self.value.as_slice()
}
pub fn from_bytes<B: AsRef<[u8]>>(algorithm: Algorithm, value: B) -> FrodoResult<Self> {
algorithm.encryption_key_from_bytes(value.as_ref())
}
pub fn encapsulate_with_rng<R: CryptoRng + ?Sized>(
&self,
rng: &mut R,
) -> FrodoResult<(Ciphertext, SharedSecret)> {
self.algorithm.encapsulate_with_rng(self, rng)
}
pub fn encapsulate<B: AsRef<[u8]>, S: AsRef<[u8]>>(
&self,
message: B,
salt: S,
) -> FrodoResult<(Ciphertext, SharedSecret)> {
self.algorithm.encapsulate(self, message, salt)
}
}
#[derive(Debug, Clone, Default)]
pub struct DecryptionKey {
pub(crate) algorithm: Algorithm,
pub(crate) value: Vec<u8>,
}
impl AsRef<[u8]> for DecryptionKey {
fn as_ref(&self) -> &[u8] {
self.value.as_ref()
}
}
ct_eq_imp!(DecryptionKey);
serde_impl!(DecryptionKey, decryption_key_from_bytes);
impl Zeroize for DecryptionKey {
fn zeroize(&mut self) {
self.value.zeroize();
}
}
impl ZeroizeOnDrop for DecryptionKey {}
impl DecryptionKey {
#[must_use]
pub fn algorithm(&self) -> Algorithm {
self.algorithm
}
#[must_use]
pub fn value(&self) -> &[u8] {
self.value.as_slice()
}
pub fn from_bytes<B: AsRef<[u8]>>(algorithm: Algorithm, value: B) -> FrodoResult<Self> {
algorithm.decryption_key_from_bytes(value.as_ref())
}
pub fn decapsulate<B: AsRef<[u8]>>(
&self,
ciphertext: &Ciphertext,
) -> FrodoResult<(SharedSecret, Vec<u8>)> {
self.algorithm.decapsulate(self, ciphertext)
}
}
#[derive(Debug, Clone, Default)]
pub struct SharedSecret {
pub(crate) algorithm: Algorithm,
pub(crate) value: Vec<u8>,
}
impl AsRef<[u8]> for SharedSecret {
fn as_ref(&self) -> &[u8] {
self.value.as_ref()
}
}
ct_eq_imp!(SharedSecret);
serde_impl!(SharedSecret, shared_secret_from_bytes);
impl Zeroize for SharedSecret {
fn zeroize(&mut self) {
self.value.zeroize();
}
}
impl ZeroizeOnDrop for SharedSecret {}
impl SharedSecret {
#[must_use]
pub fn algorithm(&self) -> Algorithm {
self.algorithm
}
#[must_use]
pub fn value(&self) -> &[u8] {
self.value.as_slice()
}
pub fn from_bytes<B: AsRef<[u8]>>(algorithm: Algorithm, value: B) -> FrodoResult<Self> {
algorithm.shared_secret_from_bytes(value.as_ref())
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Ord, PartialOrd, Hash)]
pub enum Algorithm {
#[cfg(feature = "frodo640aes")]
FrodoKem640Aes,
#[cfg(feature = "frodo976aes")]
FrodoKem976Aes,
#[cfg(feature = "frodo1344aes")]
FrodoKem1344Aes,
#[cfg(feature = "frodo640shake")]
FrodoKem640Shake,
#[cfg(feature = "frodo976shake")]
FrodoKem976Shake,
#[cfg(feature = "frodo1344shake")]
FrodoKem1344Shake,
#[cfg(feature = "efrodo640aes")]
EphemeralFrodoKem640Aes,
#[cfg(feature = "efrodo976aes")]
EphemeralFrodoKem976Aes,
#[cfg(feature = "efrodo1344aes")]
EphemeralFrodoKem1344Aes,
#[cfg(feature = "efrodo640shake")]
EphemeralFrodoKem640Shake,
#[cfg(feature = "efrodo976shake")]
EphemeralFrodoKem976Shake,
#[cfg(feature = "efrodo1344shake")]
EphemeralFrodoKem1344Shake,
}
impl ConstantTimeEq for Algorithm {
fn ct_eq(&self, other: &Self) -> Choice {
match (self, other) {
#[cfg(feature = "efrodo640aes")]
(Self::EphemeralFrodoKem640Aes, Self::EphemeralFrodoKem640Aes) => Choice::from(1),
#[cfg(feature = "efrodo976aes")]
(Self::EphemeralFrodoKem976Aes, Self::EphemeralFrodoKem976Aes) => Choice::from(1),
#[cfg(feature = "efrodo1344aes")]
(Self::EphemeralFrodoKem1344Aes, Self::EphemeralFrodoKem1344Aes) => Choice::from(1),
#[cfg(feature = "efrodo640shake")]
(Self::EphemeralFrodoKem640Shake, Self::EphemeralFrodoKem640Shake) => Choice::from(1),
#[cfg(feature = "efrodo976shake")]
(Self::EphemeralFrodoKem976Shake, Self::EphemeralFrodoKem976Shake) => Choice::from(1),
#[cfg(feature = "efrodo1344shake")]
(Self::EphemeralFrodoKem1344Shake, Self::EphemeralFrodoKem1344Shake) => Choice::from(1),
#[cfg(feature = "frodo640aes")]
(Self::FrodoKem640Aes, Self::FrodoKem640Aes) => Choice::from(1),
#[cfg(feature = "frodo976aes")]
(Self::FrodoKem976Aes, Self::FrodoKem976Aes) => Choice::from(1),
#[cfg(feature = "frodo1344aes")]
(Self::FrodoKem1344Aes, Self::FrodoKem1344Aes) => Choice::from(1),
#[cfg(feature = "frodo640shake")]
(Self::FrodoKem640Shake, Self::FrodoKem640Shake) => Choice::from(1),
#[cfg(feature = "frodo976shake")]
(Self::FrodoKem976Shake, Self::FrodoKem976Shake) => Choice::from(1),
#[cfg(feature = "frodo1344shake")]
(Self::FrodoKem1344Shake, Self::FrodoKem1344Shake) => Choice::from(1),
#[allow(unreachable_patterns)]
_ => Choice::from(0),
}
}
}
impl Default for Algorithm {
fn default() -> Self {
Self::enabled_algorithms()[0]
}
}
#[cfg(feature = "std")]
impl core::fmt::Display for Algorithm {
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
static ALGORITHMS: std::sync::LazyLock<std::collections::HashMap<Algorithm, String>> =
std::sync::LazyLock::new(|| {
let mut set = std::collections::HashMap::new();
#[cfg(feature = "frodo640aes")]
set.insert(
Algorithm::FrodoKem640Aes,
FrodoKem640Aes::default().algorithm(),
);
#[cfg(feature = "frodo976aes")]
set.insert(
Algorithm::FrodoKem976Aes,
FrodoKem976Aes::default().algorithm(),
);
#[cfg(feature = "frodo1344aes")]
set.insert(
Algorithm::FrodoKem1344Aes,
FrodoKem1344Aes::default().algorithm(),
);
#[cfg(feature = "frodo640shake")]
set.insert(
Algorithm::FrodoKem640Shake,
FrodoKem640Shake::default().algorithm(),
);
#[cfg(feature = "frodo976shake")]
set.insert(
Algorithm::FrodoKem976Shake,
FrodoKem976Shake::default().algorithm(),
);
#[cfg(feature = "frodo1344shake")]
set.insert(
Algorithm::FrodoKem1344Shake,
FrodoKem1344Shake::default().algorithm(),
);
#[cfg(feature = "efrodo640aes")]
set.insert(
Algorithm::EphemeralFrodoKem640Aes,
EphemeralFrodoKem640Aes::default().algorithm(),
);
#[cfg(feature = "efrodo976aes")]
set.insert(
Algorithm::EphemeralFrodoKem976Aes,
EphemeralFrodoKem976Aes::default().algorithm(),
);
#[cfg(feature = "efrodo1344aes")]
set.insert(
Algorithm::EphemeralFrodoKem1344Aes,
EphemeralFrodoKem1344Aes::default().algorithm(),
);
#[cfg(feature = "efrodo640shake")]
set.insert(
Algorithm::EphemeralFrodoKem640Shake,
EphemeralFrodoKem640Shake::default().algorithm(),
);
#[cfg(feature = "efrodo976shake")]
set.insert(
Algorithm::EphemeralFrodoKem976Shake,
EphemeralFrodoKem976Shake::default().algorithm(),
);
#[cfg(feature = "efrodo1344shake")]
set.insert(
Algorithm::EphemeralFrodoKem1344Shake,
EphemeralFrodoKem1344Shake::default().algorithm(),
);
set
});
let ss = &(*ALGORITHMS)[self];
write!(f, "{}", ss)
}
}
#[cfg(feature = "std")]
impl core::str::FromStr for Algorithm {
type Err = Error;
fn from_str(s: &str) -> Result<Self, Self::Err> {
static ALGORITHMS: std::sync::LazyLock<std::collections::HashMap<String, Algorithm>> =
std::sync::LazyLock::new(|| {
let mut set = std::collections::HashMap::new();
#[cfg(feature = "frodo640aes")]
set.insert(
FrodoKem640Aes::default().algorithm(),
Algorithm::FrodoKem640Aes,
);
#[cfg(feature = "frodo976aes")]
set.insert(
FrodoKem976Aes::default().algorithm(),
Algorithm::FrodoKem976Aes,
);
#[cfg(feature = "frodo1344aes")]
set.insert(
FrodoKem1344Aes::default().algorithm(),
Algorithm::FrodoKem1344Aes,
);
#[cfg(feature = "frodo640shake")]
set.insert(
FrodoKem640Shake::default().algorithm(),
Algorithm::FrodoKem640Shake,
);
#[cfg(feature = "frodo976shake")]
set.insert(
FrodoKem976Shake::default().algorithm(),
Algorithm::FrodoKem976Shake,
);
#[cfg(feature = "frodo1344shake")]
set.insert(
FrodoKem1344Shake::default().algorithm(),
Algorithm::FrodoKem1344Shake,
);
#[cfg(feature = "efrodo640aes")]
set.insert(
EphemeralFrodoKem640Aes::default().algorithm(),
Algorithm::EphemeralFrodoKem640Aes,
);
#[cfg(feature = "efrodo976aes")]
set.insert(
EphemeralFrodoKem976Aes::default().algorithm(),
Algorithm::EphemeralFrodoKem976Aes,
);
#[cfg(feature = "efrodo1344aes")]
set.insert(
EphemeralFrodoKem1344Aes::default().algorithm(),
Algorithm::EphemeralFrodoKem1344Aes,
);
#[cfg(feature = "efrodo640shake")]
set.insert(
EphemeralFrodoKem640Shake::default().algorithm(),
Algorithm::EphemeralFrodoKem640Shake,
);
#[cfg(feature = "efrodo976shake")]
set.insert(
EphemeralFrodoKem976Shake::default().algorithm(),
Algorithm::EphemeralFrodoKem976Shake,
);
#[cfg(feature = "efrodo1344shake")]
set.insert(
EphemeralFrodoKem1344Shake::default().algorithm(),
Algorithm::EphemeralFrodoKem1344Shake,
);
set
});
(*ALGORITHMS)
.get(s)
.copied()
.ok_or(Error::UnsupportedAlgorithm)
}
}
impl From<Algorithm> for u8 {
fn from(alg: Algorithm) -> u8 {
match alg {
#[cfg(feature = "frodo640aes")]
Algorithm::FrodoKem640Aes => 1,
#[cfg(feature = "frodo976aes")]
Algorithm::FrodoKem976Aes => 2,
#[cfg(feature = "frodo1344aes")]
Algorithm::FrodoKem1344Aes => 3,
#[cfg(feature = "frodo640shake")]
Algorithm::FrodoKem640Shake => 4,
#[cfg(feature = "frodo976shake")]
Algorithm::FrodoKem976Shake => 5,
#[cfg(feature = "frodo1344shake")]
Algorithm::FrodoKem1344Shake => 6,
#[cfg(feature = "efrodo640aes")]
Algorithm::EphemeralFrodoKem640Aes => 7,
#[cfg(feature = "efrodo976aes")]
Algorithm::EphemeralFrodoKem976Aes => 8,
#[cfg(feature = "efrodo1344aes")]
Algorithm::EphemeralFrodoKem1344Aes => 9,
#[cfg(feature = "efrodo640shake")]
Algorithm::EphemeralFrodoKem640Shake => 10,
#[cfg(feature = "efrodo976shake")]
Algorithm::EphemeralFrodoKem976Shake => 11,
#[cfg(feature = "efrodo1344shake")]
Algorithm::EphemeralFrodoKem1344Shake => 12,
}
}
}
impl From<Algorithm> for u16 {
fn from(alg: Algorithm) -> u16 {
u16::from(u8::from(alg))
}
}
impl From<Algorithm> for u32 {
fn from(alg: Algorithm) -> u32 {
u32::from(u8::from(alg))
}
}
impl From<Algorithm> for u64 {
fn from(alg: Algorithm) -> u64 {
u64::from(u8::from(alg))
}
}
#[cfg(target_pointer_width = "64")]
impl From<Algorithm> for u128 {
fn from(alg: Algorithm) -> u128 {
u128::from(u8::from(alg))
}
}
impl From<Algorithm> for usize {
fn from(alg: Algorithm) -> usize {
u8::from(alg) as usize
}
}
impl TryFrom<u8> for Algorithm {
type Error = Error;
fn try_from(value: u8) -> Result<Self, Self::Error> {
match value {
#[cfg(feature = "frodo640aes")]
1 => Ok(Algorithm::FrodoKem640Aes),
#[cfg(feature = "frodo976aes")]
2 => Ok(Algorithm::FrodoKem976Aes),
#[cfg(feature = "frodo1344aes")]
3 => Ok(Algorithm::FrodoKem1344Aes),
#[cfg(feature = "frodo640shake")]
4 => Ok(Algorithm::FrodoKem640Shake),
#[cfg(feature = "frodo976shake")]
5 => Ok(Algorithm::FrodoKem976Shake),
#[cfg(feature = "frodo1344shake")]
6 => Ok(Algorithm::FrodoKem1344Shake),
#[cfg(feature = "efrodo640aes")]
7 => Ok(Algorithm::EphemeralFrodoKem640Aes),
#[cfg(feature = "efrodo976aes")]
8 => Ok(Algorithm::EphemeralFrodoKem976Aes),
#[cfg(feature = "efrodo1344aes")]
9 => Ok(Algorithm::EphemeralFrodoKem1344Aes),
#[cfg(feature = "efrodo640shake")]
10 => Ok(Algorithm::EphemeralFrodoKem640Shake),
#[cfg(feature = "efrodo976shake")]
11 => Ok(Algorithm::EphemeralFrodoKem976Shake),
#[cfg(feature = "efrodo1344shake")]
12 => Ok(Algorithm::EphemeralFrodoKem1344Shake),
_ => Err(Error::UnsupportedAlgorithm),
}
}
}
impl TryFrom<u16> for Algorithm {
type Error = Error;
fn try_from(value: u16) -> Result<Self, Self::Error> {
let v = u8::try_from(value).map_err(|_| Error::UnsupportedAlgorithm)?;
v.try_into()
}
}
impl TryFrom<u32> for Algorithm {
type Error = Error;
fn try_from(value: u32) -> Result<Self, Self::Error> {
let v = u8::try_from(value).map_err(|_| Error::UnsupportedAlgorithm)?;
v.try_into()
}
}
impl TryFrom<u64> for Algorithm {
type Error = Error;
fn try_from(value: u64) -> Result<Self, Self::Error> {
let v = u8::try_from(value).map_err(|_| Error::UnsupportedAlgorithm)?;
v.try_into()
}
}
#[cfg(target_pointer_width = "64")]
impl TryFrom<u128> for Algorithm {
type Error = Error;
fn try_from(value: u128) -> Result<Self, Self::Error> {
let v = u8::try_from(value).map_err(|_| Error::UnsupportedAlgorithm)?;
v.try_into()
}
}
impl TryFrom<usize> for Algorithm {
type Error = Error;
fn try_from(value: usize) -> Result<Self, Self::Error> {
let v = u8::try_from(value).map_err(|_| Error::UnsupportedAlgorithm)?;
v.try_into()
}
}
#[cfg(feature = "serde")]
impl serde::Serialize for Algorithm {
fn serialize<S>(&self, s: S) -> Result<S::Ok, S::Error>
where
S: serde::Serializer,
{
if s.is_human_readable() {
s.serialize_str(&self.to_string())
} else {
s.serialize_u8(u8::from(*self))
}
}
}
#[cfg(feature = "serde")]
impl<'de> serde::Deserialize<'de> for Algorithm {
fn deserialize<D>(d: D) -> Result<Algorithm, D::Error>
where
D: serde::Deserializer<'de>,
{
if d.is_human_readable() {
let s = String::deserialize(d)?;
s.parse().map_err(serde::de::Error::custom)
} else {
let v = u8::deserialize(d)?;
v.try_into().map_err(serde::de::Error::custom)
}
}
}
impl Algorithm {
#[must_use]
pub fn enabled_algorithms() -> &'static [Algorithm] {
&[
#[cfg(feature = "frodo640aes")]
Self::FrodoKem640Aes,
#[cfg(feature = "frodo976aes")]
Self::FrodoKem976Aes,
#[cfg(feature = "frodo1344aes")]
Self::FrodoKem1344Aes,
#[cfg(feature = "frodo640shake")]
Self::FrodoKem640Shake,
#[cfg(feature = "frodo976shake")]
Self::FrodoKem976Shake,
#[cfg(feature = "frodo1344shake")]
Self::FrodoKem1344Shake,
#[cfg(feature = "efrodo640aes")]
Self::EphemeralFrodoKem640Aes,
#[cfg(feature = "efrodo976aes")]
Self::EphemeralFrodoKem976Aes,
#[cfg(feature = "efrodo1344aes")]
Self::EphemeralFrodoKem1344Aes,
#[cfg(feature = "efrodo640shake")]
Self::EphemeralFrodoKem640Shake,
#[cfg(feature = "efrodo976shake")]
Self::EphemeralFrodoKem976Shake,
#[cfg(feature = "efrodo1344shake")]
Self::EphemeralFrodoKem1344Shake,
]
}
#[must_use]
pub const fn params(&self) -> AlgorithmParams {
match self {
#[cfg(feature = "frodo640aes")]
Self::FrodoKem640Aes => self.inner_params::<FrodoKem640Aes>(),
#[cfg(feature = "frodo976aes")]
Self::FrodoKem976Aes => self.inner_params::<FrodoKem976Aes>(),
#[cfg(feature = "frodo1344aes")]
Self::FrodoKem1344Aes => self.inner_params::<FrodoKem1344Aes>(),
#[cfg(feature = "frodo640shake")]
Self::FrodoKem640Shake => self.inner_params::<FrodoKem640Shake>(),
#[cfg(feature = "frodo976shake")]
Self::FrodoKem976Shake => self.inner_params::<FrodoKem976Shake>(),
#[cfg(feature = "frodo1344shake")]
Self::FrodoKem1344Shake => self.inner_params::<FrodoKem1344Shake>(),
#[cfg(feature = "efrodo640aes")]
Self::EphemeralFrodoKem640Aes => self.inner_params::<EphemeralFrodoKem640Aes>(),
#[cfg(feature = "efrodo976aes")]
Self::EphemeralFrodoKem976Aes => self.inner_params::<EphemeralFrodoKem976Aes>(),
#[cfg(feature = "efrodo1344aes")]
Self::EphemeralFrodoKem1344Aes => self.inner_params::<EphemeralFrodoKem1344Aes>(),
#[cfg(feature = "efrodo640shake")]
Self::EphemeralFrodoKem640Shake => self.inner_params::<EphemeralFrodoKem640Shake>(),
#[cfg(feature = "efrodo976shake")]
Self::EphemeralFrodoKem976Shake => self.inner_params::<EphemeralFrodoKem976Shake>(),
#[cfg(feature = "efrodo1344shake")]
Self::EphemeralFrodoKem1344Shake => self.inner_params::<EphemeralFrodoKem1344Shake>(),
}
}
const fn inner_params<B: Params>(&self) -> AlgorithmParams {
AlgorithmParams {
n: B::N,
n_bar: B::N_BAR,
log_q: B::LOG_Q,
q: B::Q,
extracted_bits: B::EXTRACTED_BITS,
stripe_step: B::STRIPE_STEP,
bytes_seed_a: B::BYTES_SEED_A,
bytes_pk_hash: B::BYTES_PK_HASH,
cdf_table: B::CDF_TABLE,
claimed_nist_level: B::CLAIMED_NIST_LEVEL,
shared_secret_length: B::SHARED_SECRET_LENGTH,
message_length: B::BYTES_MU,
salt_length: B::BYTES_SALT,
encryption_key_length: B::PUBLIC_KEY_LENGTH,
decryption_key_length: B::SECRET_KEY_LENGTH,
ciphertext_length: B::CIPHERTEXT_LENGTH,
}
}
#[must_use]
pub fn encryption_key_from_decryption_key(&self, secret_key: &DecryptionKey) -> EncryptionKey {
match self {
#[cfg(feature = "frodo640aes")]
Self::FrodoKem640Aes => {
self.inner_encryption_key_from_decryption_key::<FrodoKem640Aes>(secret_key)
}
#[cfg(feature = "frodo976aes")]
Self::FrodoKem976Aes => {
self.inner_encryption_key_from_decryption_key::<FrodoKem976Aes>(secret_key)
}
#[cfg(feature = "frodo1344aes")]
Self::FrodoKem1344Aes => {
self.inner_encryption_key_from_decryption_key::<FrodoKem1344Aes>(secret_key)
}
#[cfg(feature = "frodo640shake")]
Self::FrodoKem640Shake => {
self.inner_encryption_key_from_decryption_key::<FrodoKem640Shake>(secret_key)
}
#[cfg(feature = "frodo976shake")]
Self::FrodoKem976Shake => {
self.inner_encryption_key_from_decryption_key::<FrodoKem976Shake>(secret_key)
}
#[cfg(feature = "frodo1344shake")]
Self::FrodoKem1344Shake => {
self.inner_encryption_key_from_decryption_key::<FrodoKem1344Shake>(secret_key)
}
#[cfg(feature = "efrodo640aes")]
Self::EphemeralFrodoKem640Aes => {
self.inner_encryption_key_from_decryption_key::<EphemeralFrodoKem640Aes>(secret_key)
}
#[cfg(feature = "efrodo976aes")]
Self::EphemeralFrodoKem976Aes => {
self.inner_encryption_key_from_decryption_key::<EphemeralFrodoKem976Aes>(secret_key)
}
#[cfg(feature = "efrodo1344aes")]
Self::EphemeralFrodoKem1344Aes => self
.inner_encryption_key_from_decryption_key::<EphemeralFrodoKem1344Aes>(secret_key),
#[cfg(feature = "efrodo640shake")]
Self::EphemeralFrodoKem640Shake => self
.inner_encryption_key_from_decryption_key::<EphemeralFrodoKem640Shake>(secret_key),
#[cfg(feature = "efrodo976shake")]
Self::EphemeralFrodoKem976Shake => self
.inner_encryption_key_from_decryption_key::<EphemeralFrodoKem976Shake>(secret_key),
#[cfg(feature = "efrodo1344shake")]
Self::EphemeralFrodoKem1344Shake => self
.inner_encryption_key_from_decryption_key::<EphemeralFrodoKem1344Shake>(secret_key),
}
}
fn inner_encryption_key_from_decryption_key<B: Params>(
&self,
secret_key: &DecryptionKey,
) -> EncryptionKey {
let sk = DecryptionKeyRef::<B>(secret_key.value.as_slice(), PhantomData);
EncryptionKey {
algorithm: *self,
value: sk.public_key().to_vec(),
}
}
pub fn decryption_key_from_bytes<B: AsRef<[u8]>>(&self, buf: B) -> FrodoResult<DecryptionKey> {
let buf = buf.as_ref();
match self {
#[cfg(feature = "frodo640aes")]
Self::FrodoKem640Aes => self.inner_decryption_key_from_bytes::<FrodoKem640Aes>(buf),
#[cfg(feature = "frodo976aes")]
Self::FrodoKem976Aes => self.inner_decryption_key_from_bytes::<FrodoKem976Aes>(buf),
#[cfg(feature = "frodo1344aes")]
Self::FrodoKem1344Aes => self.inner_decryption_key_from_bytes::<FrodoKem1344Aes>(buf),
#[cfg(feature = "frodo640shake")]
Self::FrodoKem640Shake => self.inner_decryption_key_from_bytes::<FrodoKem640Shake>(buf),
#[cfg(feature = "frodo976shake")]
Self::FrodoKem976Shake => self.inner_decryption_key_from_bytes::<FrodoKem976Shake>(buf),
#[cfg(feature = "frodo1344shake")]
Self::FrodoKem1344Shake => {
self.inner_decryption_key_from_bytes::<FrodoKem1344Shake>(buf)
}
#[cfg(feature = "efrodo640aes")]
Self::EphemeralFrodoKem640Aes => {
self.inner_decryption_key_from_bytes::<EphemeralFrodoKem640Aes>(buf)
}
#[cfg(feature = "efrodo976aes")]
Self::EphemeralFrodoKem976Aes => {
self.inner_decryption_key_from_bytes::<EphemeralFrodoKem976Aes>(buf)
}
#[cfg(feature = "efrodo1344aes")]
Self::EphemeralFrodoKem1344Aes => {
self.inner_decryption_key_from_bytes::<EphemeralFrodoKem1344Aes>(buf)
}
#[cfg(feature = "efrodo640shake")]
Self::EphemeralFrodoKem640Shake => {
self.inner_decryption_key_from_bytes::<EphemeralFrodoKem640Shake>(buf)
}
#[cfg(feature = "efrodo976shake")]
Self::EphemeralFrodoKem976Shake => {
self.inner_decryption_key_from_bytes::<EphemeralFrodoKem976Shake>(buf)
}
#[cfg(feature = "efrodo1344shake")]
Self::EphemeralFrodoKem1344Shake => {
self.inner_decryption_key_from_bytes::<EphemeralFrodoKem1344Shake>(buf)
}
}
}
fn inner_decryption_key_from_bytes<P: Params>(&self, buf: &[u8]) -> FrodoResult<DecryptionKey> {
hazmat::DecryptionKey::<P>::from_slice(buf).map(|s| DecryptionKey {
algorithm: *self,
value: s.0,
})
}
pub fn encryption_key_from_bytes<B: AsRef<[u8]>>(&self, buf: B) -> FrodoResult<EncryptionKey> {
let buf = buf.as_ref();
match self {
#[cfg(feature = "frodo640aes")]
Self::FrodoKem640Aes => self.inner_encryption_key_from_bytes::<FrodoKem640Aes>(buf),
#[cfg(feature = "frodo976aes")]
Self::FrodoKem976Aes => self.inner_encryption_key_from_bytes::<FrodoKem976Aes>(buf),
#[cfg(feature = "frodo1344aes")]
Self::FrodoKem1344Aes => self.inner_encryption_key_from_bytes::<FrodoKem1344Aes>(buf),
#[cfg(feature = "frodo640shake")]
Self::FrodoKem640Shake => self.inner_encryption_key_from_bytes::<FrodoKem640Shake>(buf),
#[cfg(feature = "frodo976shake")]
Self::FrodoKem976Shake => self.inner_encryption_key_from_bytes::<FrodoKem976Shake>(buf),
#[cfg(feature = "frodo1344shake")]
Self::FrodoKem1344Shake => {
self.inner_encryption_key_from_bytes::<FrodoKem1344Shake>(buf)
}
#[cfg(feature = "efrodo640aes")]
Self::EphemeralFrodoKem640Aes => {
self.inner_encryption_key_from_bytes::<EphemeralFrodoKem640Aes>(buf)
}
#[cfg(feature = "efrodo976aes")]
Self::EphemeralFrodoKem976Aes => {
self.inner_encryption_key_from_bytes::<EphemeralFrodoKem976Aes>(buf)
}
#[cfg(feature = "efrodo1344aes")]
Self::EphemeralFrodoKem1344Aes => {
self.inner_encryption_key_from_bytes::<EphemeralFrodoKem1344Aes>(buf)
}
#[cfg(feature = "efrodo640shake")]
Self::EphemeralFrodoKem640Shake => {
self.inner_encryption_key_from_bytes::<EphemeralFrodoKem640Shake>(buf)
}
#[cfg(feature = "efrodo976shake")]
Self::EphemeralFrodoKem976Shake => {
self.inner_encryption_key_from_bytes::<EphemeralFrodoKem976Shake>(buf)
}
#[cfg(feature = "efrodo1344shake")]
Self::EphemeralFrodoKem1344Shake => {
self.inner_encryption_key_from_bytes::<EphemeralFrodoKem1344Shake>(buf)
}
}
}
fn inner_encryption_key_from_bytes<P: Params>(&self, buf: &[u8]) -> FrodoResult<EncryptionKey> {
hazmat::EncryptionKey::<P>::from_slice(buf).map(|s| EncryptionKey {
algorithm: *self,
value: s.0,
})
}
pub fn ciphertext_from_bytes(&self, buf: &[u8]) -> FrodoResult<Ciphertext> {
match self {
#[cfg(feature = "frodo640aes")]
Self::FrodoKem640Aes => {
hazmat::Ciphertext::<FrodoKem640Aes>::from_slice(buf).map(|s| Ciphertext {
algorithm: *self,
value: s.0,
})
}
#[cfg(feature = "frodo976aes")]
Self::FrodoKem976Aes => {
hazmat::Ciphertext::<FrodoKem976Aes>::from_slice(buf).map(|s| Ciphertext {
algorithm: *self,
value: s.0,
})
}
#[cfg(feature = "frodo1344aes")]
Self::FrodoKem1344Aes => {
hazmat::Ciphertext::<FrodoKem1344Aes>::from_slice(buf).map(|s| Ciphertext {
algorithm: *self,
value: s.0,
})
}
#[cfg(feature = "frodo640shake")]
Self::FrodoKem640Shake => {
hazmat::Ciphertext::<FrodoKem640Shake>::from_slice(buf).map(|s| Ciphertext {
algorithm: *self,
value: s.0,
})
}
#[cfg(feature = "frodo976shake")]
Self::FrodoKem976Shake => {
hazmat::Ciphertext::<FrodoKem976Shake>::from_slice(buf).map(|s| Ciphertext {
algorithm: *self,
value: s.0,
})
}
#[cfg(feature = "frodo1344shake")]
Self::FrodoKem1344Shake => hazmat::Ciphertext::<FrodoKem1344Shake>::from_slice(buf)
.map(|s| Ciphertext {
algorithm: *self,
value: s.0,
}),
#[cfg(feature = "efrodo640aes")]
Self::EphemeralFrodoKem640Aes => {
hazmat::Ciphertext::<EphemeralFrodoKem640Aes>::from_slice(buf).map(|s| Ciphertext {
algorithm: *self,
value: s.0,
})
}
#[cfg(feature = "efrodo976aes")]
Self::EphemeralFrodoKem976Aes => {
hazmat::Ciphertext::<EphemeralFrodoKem976Aes>::from_slice(buf).map(|s| Ciphertext {
algorithm: *self,
value: s.0,
})
}
#[cfg(feature = "efrodo1344aes")]
Self::EphemeralFrodoKem1344Aes => {
hazmat::Ciphertext::<EphemeralFrodoKem1344Aes>::from_slice(buf).map(|s| {
Ciphertext {
algorithm: *self,
value: s.0,
}
})
}
#[cfg(feature = "efrodo640shake")]
Self::EphemeralFrodoKem640Shake => {
hazmat::Ciphertext::<EphemeralFrodoKem640Shake>::from_slice(buf).map(|s| {
Ciphertext {
algorithm: *self,
value: s.0,
}
})
}
#[cfg(feature = "efrodo976shake")]
Self::EphemeralFrodoKem976Shake => {
hazmat::Ciphertext::<EphemeralFrodoKem976Shake>::from_slice(buf).map(|s| {
Ciphertext {
algorithm: *self,
value: s.0,
}
})
}
#[cfg(feature = "efrodo1344shake")]
Self::EphemeralFrodoKem1344Shake => {
hazmat::Ciphertext::<EphemeralFrodoKem1344Shake>::from_slice(buf).map(|s| {
Ciphertext {
algorithm: *self,
value: s.0,
}
})
}
}
}
pub fn shared_secret_from_bytes(&self, buf: &[u8]) -> FrodoResult<SharedSecret> {
match self {
#[cfg(feature = "frodo640aes")]
Self::FrodoKem640Aes => {
hazmat::SharedSecret::<FrodoKem640Aes>::from_slice(buf).map(|s| SharedSecret {
algorithm: *self,
value: s.0,
})
}
#[cfg(feature = "frodo976aes")]
Self::FrodoKem976Aes => {
hazmat::SharedSecret::<FrodoKem976Aes>::from_slice(buf).map(|s| SharedSecret {
algorithm: *self,
value: s.0,
})
}
#[cfg(feature = "frodo1344aes")]
Self::FrodoKem1344Aes => {
hazmat::SharedSecret::<FrodoKem1344Aes>::from_slice(buf).map(|s| SharedSecret {
algorithm: *self,
value: s.0,
})
}
#[cfg(feature = "frodo640shake")]
Self::FrodoKem640Shake => hazmat::SharedSecret::<FrodoKem640Shake>::from_slice(buf)
.map(|s| SharedSecret {
algorithm: *self,
value: s.0,
}),
#[cfg(feature = "frodo976shake")]
Self::FrodoKem976Shake => hazmat::SharedSecret::<FrodoKem976Shake>::from_slice(buf)
.map(|s| SharedSecret {
algorithm: *self,
value: s.0,
}),
#[cfg(feature = "frodo1344shake")]
Self::FrodoKem1344Shake => hazmat::SharedSecret::<FrodoKem1344Shake>::from_slice(buf)
.map(|s| SharedSecret {
algorithm: *self,
value: s.0,
}),
#[cfg(feature = "efrodo640aes")]
Self::EphemeralFrodoKem640Aes => {
hazmat::SharedSecret::<EphemeralFrodoKem640Aes>::from_slice(buf).map(|s| {
SharedSecret {
algorithm: *self,
value: s.0,
}
})
}
#[cfg(feature = "efrodo976aes")]
Self::EphemeralFrodoKem976Aes => {
hazmat::SharedSecret::<EphemeralFrodoKem976Aes>::from_slice(buf).map(|s| {
SharedSecret {
algorithm: *self,
value: s.0,
}
})
}
#[cfg(feature = "efrodo1344aes")]
Self::EphemeralFrodoKem1344Aes => {
hazmat::SharedSecret::<EphemeralFrodoKem1344Aes>::from_slice(buf).map(|s| {
SharedSecret {
algorithm: *self,
value: s.0,
}
})
}
#[cfg(feature = "efrodo640shake")]
Self::EphemeralFrodoKem640Shake => {
hazmat::SharedSecret::<EphemeralFrodoKem640Shake>::from_slice(buf).map(|s| {
SharedSecret {
algorithm: *self,
value: s.0,
}
})
}
#[cfg(feature = "efrodo976shake")]
Self::EphemeralFrodoKem976Shake => {
hazmat::SharedSecret::<EphemeralFrodoKem976Shake>::from_slice(buf).map(|s| {
SharedSecret {
algorithm: *self,
value: s.0,
}
})
}
#[cfg(feature = "efrodo1344shake")]
Self::EphemeralFrodoKem1344Shake => {
hazmat::SharedSecret::<EphemeralFrodoKem1344Shake>::from_slice(buf).map(|s| {
SharedSecret {
algorithm: *self,
value: s.0,
}
})
}
}
}
pub fn generate_keypair<R: CryptoRng + ?Sized>(
&self,
rng: &mut R,
) -> (EncryptionKey, DecryptionKey) {
match self {
#[cfg(feature = "frodo640aes")]
Self::FrodoKem640Aes => self.inner_generate_keypair::<FrodoKem640Aes, R>(rng),
#[cfg(feature = "frodo976aes")]
Self::FrodoKem976Aes => self.inner_generate_keypair::<FrodoKem976Aes, R>(rng),
#[cfg(feature = "frodo1344aes")]
Self::FrodoKem1344Aes => self.inner_generate_keypair::<FrodoKem1344Aes, R>(rng),
#[cfg(feature = "frodo640shake")]
Self::FrodoKem640Shake => self.inner_generate_keypair::<FrodoKem640Shake, R>(rng),
#[cfg(feature = "frodo976shake")]
Self::FrodoKem976Shake => self.inner_generate_keypair::<FrodoKem976Shake, R>(rng),
#[cfg(feature = "frodo1344shake")]
Self::FrodoKem1344Shake => self.inner_generate_keypair::<FrodoKem1344Shake, R>(rng),
#[cfg(feature = "efrodo640aes")]
Self::EphemeralFrodoKem640Aes => {
self.inner_generate_keypair::<EphemeralFrodoKem640Aes, R>(rng)
}
#[cfg(feature = "efrodo976aes")]
Self::EphemeralFrodoKem976Aes => {
self.inner_generate_keypair::<EphemeralFrodoKem976Aes, R>(rng)
}
#[cfg(feature = "efrodo1344aes")]
Self::EphemeralFrodoKem1344Aes => {
self.inner_generate_keypair::<EphemeralFrodoKem1344Aes, R>(rng)
}
#[cfg(feature = "efrodo640shake")]
Self::EphemeralFrodoKem640Shake => {
self.inner_generate_keypair::<EphemeralFrodoKem640Shake, R>(rng)
}
#[cfg(feature = "efrodo976shake")]
Self::EphemeralFrodoKem976Shake => {
self.inner_generate_keypair::<EphemeralFrodoKem976Shake, R>(rng)
}
#[cfg(feature = "efrodo1344shake")]
Self::EphemeralFrodoKem1344Shake => {
self.inner_generate_keypair::<EphemeralFrodoKem1344Shake, R>(rng)
}
}
}
fn inner_generate_keypair<K: Kem, R: CryptoRng + ?Sized>(
&self,
rng: &mut R,
) -> (EncryptionKey, DecryptionKey) {
let (pk, sk) = K::default().generate_keypair(rng);
(
EncryptionKey {
algorithm: *self,
value: pk.0,
},
DecryptionKey {
algorithm: *self,
value: sk.0,
},
)
}
pub fn encapsulate<B: AsRef<[u8]>, S: AsRef<[u8]>>(
&self,
public_key: &EncryptionKey,
msg: B,
salt: S,
) -> FrodoResult<(Ciphertext, SharedSecret)> {
let msg = msg.as_ref();
let salt = salt.as_ref();
match self {
#[cfg(feature = "frodo640aes")]
Self::FrodoKem640Aes => self.inner_encapsulate::<FrodoKem640Aes>(public_key, msg, salt),
#[cfg(feature = "frodo976aes")]
Self::FrodoKem976Aes => self.inner_encapsulate::<FrodoKem976Aes>(public_key, msg, salt),
#[cfg(feature = "frodo1344aes")]
Self::FrodoKem1344Aes => {
self.inner_encapsulate::<FrodoKem1344Aes>(public_key, msg, salt)
}
#[cfg(feature = "frodo640shake")]
Self::FrodoKem640Shake => {
self.inner_encapsulate::<FrodoKem640Shake>(public_key, msg, salt)
}
#[cfg(feature = "frodo976shake")]
Self::FrodoKem976Shake => {
self.inner_encapsulate::<FrodoKem976Shake>(public_key, msg, salt)
}
#[cfg(feature = "frodo1344shake")]
Self::FrodoKem1344Shake => {
self.inner_encapsulate::<FrodoKem1344Shake>(public_key, msg, salt)
}
#[cfg(feature = "efrodo640aes")]
Self::EphemeralFrodoKem640Aes => {
self.inner_encapsulate::<EphemeralFrodoKem640Aes>(public_key, msg, salt)
}
#[cfg(feature = "efrodo976aes")]
Self::EphemeralFrodoKem976Aes => {
self.inner_encapsulate::<EphemeralFrodoKem976Aes>(public_key, msg, salt)
}
#[cfg(feature = "efrodo1344aes")]
Self::EphemeralFrodoKem1344Aes => {
self.inner_encapsulate::<EphemeralFrodoKem1344Aes>(public_key, msg, salt)
}
#[cfg(feature = "efrodo640shake")]
Self::EphemeralFrodoKem640Shake => {
self.inner_encapsulate::<EphemeralFrodoKem640Shake>(public_key, msg, salt)
}
#[cfg(feature = "efrodo976shake")]
Self::EphemeralFrodoKem976Shake => {
self.inner_encapsulate::<EphemeralFrodoKem976Shake>(public_key, msg, salt)
}
#[cfg(feature = "efrodo1344shake")]
Self::EphemeralFrodoKem1344Shake => {
self.inner_encapsulate::<EphemeralFrodoKem1344Shake>(public_key, msg, salt)
}
}
}
fn inner_encapsulate<K: Kem>(
&self,
encryption_key: &EncryptionKey,
msg: &[u8],
salt: &[u8],
) -> FrodoResult<(Ciphertext, SharedSecret)> {
if K::BYTES_MU != msg.len() {
return Err(Error::InvalidMessageLength(msg.len()));
}
let pk = EncryptionKeyRef::from_slice(encryption_key.value.as_slice())?;
let (ct, ss) = K::default().encapsulate(pk, msg, salt);
Ok((
Ciphertext {
algorithm: *self,
value: ct.0,
},
SharedSecret {
algorithm: *self,
value: ss.0,
},
))
}
pub fn encapsulate_with_rng<R: CryptoRng + ?Sized>(
&self,
public_key: &EncryptionKey,
rng: &mut R,
) -> FrodoResult<(Ciphertext, SharedSecret)> {
match self {
#[cfg(feature = "frodo640aes")]
Self::FrodoKem640Aes => {
self.inner_encapsulate_with_rng::<FrodoKem640Aes, R>(public_key, rng)
}
#[cfg(feature = "frodo976aes")]
Self::FrodoKem976Aes => {
self.inner_encapsulate_with_rng::<FrodoKem976Aes, R>(public_key, rng)
}
#[cfg(feature = "frodo1344aes")]
Self::FrodoKem1344Aes => {
self.inner_encapsulate_with_rng::<FrodoKem1344Aes, R>(public_key, rng)
}
#[cfg(feature = "frodo640shake")]
Self::FrodoKem640Shake => {
self.inner_encapsulate_with_rng::<FrodoKem640Shake, R>(public_key, rng)
}
#[cfg(feature = "frodo976shake")]
Self::FrodoKem976Shake => {
self.inner_encapsulate_with_rng::<FrodoKem976Shake, R>(public_key, rng)
}
#[cfg(feature = "frodo1344shake")]
Self::FrodoKem1344Shake => {
self.inner_encapsulate_with_rng::<FrodoKem1344Shake, R>(public_key, rng)
}
#[cfg(feature = "efrodo640aes")]
Self::EphemeralFrodoKem640Aes => {
self.inner_encapsulate_with_rng::<EphemeralFrodoKem640Aes, R>(public_key, rng)
}
#[cfg(feature = "efrodo976aes")]
Self::EphemeralFrodoKem976Aes => {
self.inner_encapsulate_with_rng::<EphemeralFrodoKem976Aes, R>(public_key, rng)
}
#[cfg(feature = "efrodo1344aes")]
Self::EphemeralFrodoKem1344Aes => {
self.inner_encapsulate_with_rng::<EphemeralFrodoKem1344Aes, R>(public_key, rng)
}
#[cfg(feature = "efrodo640shake")]
Self::EphemeralFrodoKem640Shake => {
self.inner_encapsulate_with_rng::<EphemeralFrodoKem640Shake, R>(public_key, rng)
}
#[cfg(feature = "efrodo976shake")]
Self::EphemeralFrodoKem976Shake => {
self.inner_encapsulate_with_rng::<EphemeralFrodoKem976Shake, R>(public_key, rng)
}
#[cfg(feature = "efrodo1344shake")]
Self::EphemeralFrodoKem1344Shake => {
self.inner_encapsulate_with_rng::<EphemeralFrodoKem1344Shake, R>(public_key, rng)
}
}
}
fn inner_encapsulate_with_rng<K: Kem, R: CryptoRng + ?Sized>(
&self,
encryption_key: &EncryptionKey,
rng: &mut R,
) -> FrodoResult<(Ciphertext, SharedSecret)> {
let pk = EncryptionKeyRef::from_slice(encryption_key.value.as_slice())?;
let (ct, ss) = K::default().encapsulate_with_rng(pk, rng);
Ok((
Ciphertext {
algorithm: *self,
value: ct.0,
},
SharedSecret {
algorithm: *self,
value: ss.0,
},
))
}
pub fn decapsulate(
&self,
secret_key: &DecryptionKey,
ciphertext: &Ciphertext,
) -> FrodoResult<(SharedSecret, Vec<u8>)> {
match self {
#[cfg(feature = "frodo640aes")]
Self::FrodoKem640Aes => {
self.inner_decapsulate::<FrodoKem640Aes>(secret_key, ciphertext)
}
#[cfg(feature = "frodo976aes")]
Self::FrodoKem976Aes => {
self.inner_decapsulate::<FrodoKem976Aes>(secret_key, ciphertext)
}
#[cfg(feature = "frodo1344aes")]
Self::FrodoKem1344Aes => {
self.inner_decapsulate::<FrodoKem1344Aes>(secret_key, ciphertext)
}
#[cfg(feature = "frodo640shake")]
Self::FrodoKem640Shake => {
self.inner_decapsulate::<FrodoKem640Shake>(secret_key, ciphertext)
}
#[cfg(feature = "frodo976shake")]
Self::FrodoKem976Shake => {
self.inner_decapsulate::<FrodoKem976Shake>(secret_key, ciphertext)
}
#[cfg(feature = "frodo1344shake")]
Self::FrodoKem1344Shake => {
self.inner_decapsulate::<FrodoKem1344Shake>(secret_key, ciphertext)
}
#[cfg(feature = "efrodo640aes")]
Self::EphemeralFrodoKem640Aes => {
self.inner_decapsulate::<EphemeralFrodoKem640Aes>(secret_key, ciphertext)
}
#[cfg(feature = "efrodo976aes")]
Self::EphemeralFrodoKem976Aes => {
self.inner_decapsulate::<EphemeralFrodoKem976Aes>(secret_key, ciphertext)
}
#[cfg(feature = "efrodo1344aes")]
Self::EphemeralFrodoKem1344Aes => {
self.inner_decapsulate::<EphemeralFrodoKem1344Aes>(secret_key, ciphertext)
}
#[cfg(feature = "efrodo640shake")]
Self::EphemeralFrodoKem640Shake => {
self.inner_decapsulate::<EphemeralFrodoKem640Shake>(secret_key, ciphertext)
}
#[cfg(feature = "efrodo976shake")]
Self::EphemeralFrodoKem976Shake => {
self.inner_decapsulate::<EphemeralFrodoKem976Shake>(secret_key, ciphertext)
}
#[cfg(feature = "efrodo1344shake")]
Self::EphemeralFrodoKem1344Shake => {
self.inner_decapsulate::<EphemeralFrodoKem1344Shake>(secret_key, ciphertext)
}
}
}
fn inner_decapsulate<K: Kem>(
&self,
secret_key: &DecryptionKey,
ciphertext: &Ciphertext,
) -> FrodoResult<(SharedSecret, Vec<u8>)> {
let sk = DecryptionKeyRef::from_slice(secret_key.value.as_slice())?;
let ct = CiphertextRef::from_slice(ciphertext.value.as_slice())?;
let (ss, mu) = K::default().decapsulate(sk, ct);
Ok((
SharedSecret {
algorithm: *self,
value: ss.0,
},
mu,
))
}
}
#[derive(Debug, Clone, Copy)]
pub struct AlgorithmParams {
pub n: usize,
pub n_bar: usize,
pub log_q: usize,
pub q: usize,
pub extracted_bits: usize,
pub stripe_step: usize,
pub bytes_seed_a: usize,
pub bytes_pk_hash: usize,
pub cdf_table: &'static [u16],
pub claimed_nist_level: usize,
pub shared_secret_length: usize,
pub message_length: usize,
pub salt_length: usize,
pub encryption_key_length: usize,
pub decryption_key_length: usize,
pub ciphertext_length: usize,
}
#[cfg(test)]
#[allow(clippy::unwrap_used)]
mod tests {
use super::*;
use rand_core::{Rng, SeedableRng};
use rstest::*;
#[rstest]
#[case::aes640(Algorithm::FrodoKem640Aes)]
#[case::aes976(Algorithm::FrodoKem976Aes)]
#[case::aes1344(Algorithm::FrodoKem1344Aes)]
#[case::shake640(Algorithm::FrodoKem640Shake)]
#[case::shake976(Algorithm::FrodoKem976Shake)]
#[case::shake1344(Algorithm::FrodoKem1344Shake)]
fn works(#[case] alg: Algorithm) {
let mut rng = chacha20::ChaCha8Rng::from_seed([1u8; 32]);
let (our_pk, our_sk) = alg.generate_keypair(&mut rng);
let mut mu = vec![0u8; alg.params().message_length];
rng.fill_bytes(&mut mu);
let mut salt = vec![0u8; alg.params().salt_length];
rng.fill_bytes(&mut salt);
let (our_ct, our_ess) = alg.encapsulate(&our_pk, &mu, &salt).unwrap();
let (our_dss, mu_prime) = alg.decapsulate(&our_sk, &our_ct).unwrap();
assert_eq!(our_ess.value, our_dss.value);
assert_eq!(mu, mu_prime);
}
macro_rules! serde_test {
($name:ident, $ser:path, $de:path) => {
#[cfg(feature = "serde")]
#[rstest]
#[case::aes640(Algorithm::FrodoKem640Aes)]
#[case::aes976(Algorithm::FrodoKem976Aes)]
#[case::aes1344(Algorithm::FrodoKem1344Aes)]
#[case::shake640(Algorithm::FrodoKem640Shake)]
#[case::shake976(Algorithm::FrodoKem976Shake)]
#[case::shake1344(Algorithm::FrodoKem1344Shake)]
#[case::aes640(Algorithm::EphemeralFrodoKem640Aes)]
#[case::aes976(Algorithm::EphemeralFrodoKem976Aes)]
#[case::aes1344(Algorithm::EphemeralFrodoKem1344Aes)]
#[case::shake640(Algorithm::EphemeralFrodoKem640Shake)]
#[case::shake976(Algorithm::EphemeralFrodoKem976Shake)]
#[case::shake1344(Algorithm::EphemeralFrodoKem1344Shake)]
fn $name(#[case] alg: Algorithm) {
let mut rng = chacha20::ChaCha8Rng::from_seed([3u8; 32]);
let (pk, sk) = alg.generate_keypair(&mut rng);
let (ct, ss) = alg.encapsulate_with_rng(&pk, &mut rng).unwrap();
let pk_str = $ser(&pk);
let sk_str = $ser(&sk);
let ct_str = $ser(&ct);
let ss_str = $ser(&ss);
assert!(pk_str.is_ok());
assert!(sk_str.is_ok());
assert!(ct_str.is_ok());
assert!(ss_str.is_ok());
let pk_str = pk_str.unwrap();
let sk_str = sk_str.unwrap();
let ct_str = ct_str.unwrap();
let ss_str = ss_str.unwrap();
let pk2 = $de(&pk_str);
let sk2 = $de(&sk_str);
let ct2 = $de(&ct_str);
let ss2 = $de(&ss_str);
assert!(pk2.is_ok());
assert!(sk2.is_ok());
assert!(ct2.is_ok());
assert!(ss2.is_ok());
let pk2 = pk2.unwrap();
let sk2 = sk2.unwrap();
let ct2 = ct2.unwrap();
let ss2 = ss2.unwrap();
assert_eq!(pk, pk2);
assert_eq!(sk, sk2);
assert_eq!(ct, ct2);
assert_eq!(ss, ss2);
}
};
}
serde_test!(
serialization_json,
serde_json::to_string,
serde_json::from_str
);
serde_test!(serialization_toml, toml::to_string, toml::from_str);
serde_test!(
serialization_yaml,
serde_yaml::to_string,
serde_yaml::from_str
);
serde_test!(
serialization_bare,
serde_bare::to_vec,
serde_bare::from_slice
);
serde_test!(
serialization_cbor,
serde_cbor::to_vec,
serde_cbor::from_slice
);
serde_test!(
serialization_postcard,
postcard::to_stdvec,
postcard::from_bytes
);
}