use libcrux_secrets::U8;
pub trait Aead {
fn keygen(key: &mut [U8], rand: &[U8]) -> Result<(), KeyGenError>;
fn encrypt(
ciphertext: &mut [u8],
tag: &mut [U8],
key: &[U8],
nonce: &[U8],
aad: &[u8],
plaintext: &[U8],
) -> Result<(), EncryptError>;
fn decrypt(
plaintext: &mut [U8],
key: &[U8],
nonce: &[U8],
aad: &[u8],
ciphertext: &[u8],
tag: &[U8],
) -> Result<(), DecryptError>;
}
pub enum KeyGenError {
WrongKeyLength,
InsufficientRandomness,
UnsuitableRandomness,
}
#[derive(Debug, PartialEq, Eq)]
pub enum EncryptError {
WrongCiphertextLength,
PlaintextTooLong,
AadTooLong,
WrongKeyLength,
WrongTagLength,
WrongNonceLength,
Unknown,
}
#[derive(Debug, PartialEq, Eq)]
pub enum DecryptError {
InvalidTag,
WrongPlaintextLength,
PlaintextTooLong,
AadTooLong,
WrongKeyLength,
WrongTagLength,
WrongNonceLength,
Unknown,
}
impl From<super::arrayref::EncryptError> for EncryptError {
fn from(value: super::arrayref::EncryptError) -> Self {
match value {
super::arrayref::EncryptError::WrongCiphertextLength => {
EncryptError::WrongCiphertextLength
}
super::arrayref::EncryptError::PlaintextTooLong => EncryptError::PlaintextTooLong,
super::arrayref::EncryptError::AadTooLong => EncryptError::AadTooLong,
super::arrayref::EncryptError::Unknown => EncryptError::Unknown,
}
}
}
impl From<super::arrayref::DecryptError> for DecryptError {
fn from(value: super::arrayref::DecryptError) -> Self {
match value {
super::arrayref::DecryptError::InvalidTag => DecryptError::InvalidTag,
super::arrayref::DecryptError::WrongPlaintextLength => {
DecryptError::WrongPlaintextLength
}
super::arrayref::DecryptError::PlaintextTooLong => DecryptError::PlaintextTooLong,
super::arrayref::DecryptError::AadTooLong => DecryptError::AadTooLong,
super::arrayref::DecryptError::Unknown => DecryptError::Unknown,
}
}
}
impl core::fmt::Display for EncryptError {
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
let text = match self {
EncryptError::WrongCiphertextLength => "ciphertext buffer has wrong length",
EncryptError::PlaintextTooLong => {
"plaintext is too long for algorithm or implementation"
}
EncryptError::AadTooLong => "aad is too long for algorithm or implementation",
EncryptError::Unknown => "an unknown error occurred",
EncryptError::WrongKeyLength => "key has wrong length",
EncryptError::WrongTagLength => "tag has wrong length",
EncryptError::WrongNonceLength => "nonce has wrong length",
};
f.write_str(text)
}
}
impl core::fmt::Display for DecryptError {
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
let text = match self {
DecryptError::InvalidTag => "invalid authentication tag",
DecryptError::WrongPlaintextLength => "plaintext buffer has wrong length",
DecryptError::PlaintextTooLong => {
"plaintext is too long for algorithm or implementation"
}
DecryptError::AadTooLong => "aad is too long for algorithm or implementation",
DecryptError::Unknown => "an unknown error occurred",
DecryptError::WrongKeyLength => "key has wrong length",
DecryptError::WrongTagLength => "tag has wrong length",
DecryptError::WrongNonceLength => "nonce has wrong length",
};
f.write_str(text)
}
}
#[cfg(feature = "error-in-core")]
mod error_in_core {
impl core::error::Error for super::EncryptError {}
impl core::error::Error for super::DecryptError {}
}
#[macro_export]
macro_rules! impl_aead_slice_trait {
($type:ty => $key:expr, $tag:expr, $nonce:expr) => {
impl $crate::aead::slice::Aead for $type {
fn keygen(
key: &mut [$crate::libcrux_secrets::U8],
rand: &[$crate::libcrux_secrets::U8],
) -> Result<(), $crate::aead::slice::KeyGenError> {
let key: &mut [$crate::libcrux_secrets::U8; $key] = key
.try_into()
.map_err(|_| $crate::aead::slice::KeyGenError::WrongKeyLength)?;
if rand.len() < $key {
return Err($crate::aead::slice::KeyGenError::InsufficientRandomness);
}
Ok(key.copy_from_slice(rand))
}
fn encrypt(
ciphertext: &mut [u8],
tag: &mut [$crate::libcrux_secrets::U8],
key: &[$crate::libcrux_secrets::U8],
nonce: &[$crate::libcrux_secrets::U8],
aad: &[u8],
plaintext: &[$crate::libcrux_secrets::U8],
) -> Result<(), $crate::aead::slice::EncryptError> {
let key: &[$crate::libcrux_secrets::U8; $key] = key
.try_into()
.map_err(|_| $crate::aead::slice::EncryptError::WrongKeyLength)?;
let tag: &mut [$crate::libcrux_secrets::U8; $tag] = tag
.try_into()
.map_err(|_| $crate::aead::slice::EncryptError::WrongTagLength)?;
let nonce: &[$crate::libcrux_secrets::U8; $nonce] = nonce
.try_into()
.map_err(|_| $crate::aead::slice::EncryptError::WrongNonceLength)?;
<Self as $crate::aead::arrayref::Aead<$key, $tag, $nonce>>::encrypt(
ciphertext, tag, key, nonce, aad, plaintext,
)
.map_err($crate::aead::slice::EncryptError::from)
}
fn decrypt(
plaintext: &mut [$crate::libcrux_secrets::U8],
key: &[$crate::libcrux_secrets::U8],
nonce: &[$crate::libcrux_secrets::U8],
aad: &[u8],
ciphertext: &[u8],
tag: &[$crate::libcrux_secrets::U8],
) -> Result<(), $crate::aead::slice::DecryptError> {
let key: &[$crate::libcrux_secrets::U8; $key] = key
.try_into()
.map_err(|_| $crate::aead::slice::DecryptError::WrongKeyLength)?;
let tag: &[$crate::libcrux_secrets::U8; $tag] = tag
.try_into()
.map_err(|_| $crate::aead::slice::DecryptError::WrongTagLength)?;
let nonce: &[$crate::libcrux_secrets::U8; $nonce] = nonce
.try_into()
.map_err(|_| $crate::aead::slice::DecryptError::WrongNonceLength)?;
<Self as $crate::aead::arrayref::Aead<$key, $tag, $nonce>>::decrypt(
plaintext, key, nonce, aad, ciphertext, tag,
)
.map_err($crate::aead::slice::DecryptError::from)
}
}
#[cfg(test)]
#[test]
fn simple_aead_test() {
$crate::aead::tests::simple::<$key, $tag, $nonce, $type>();
}
};
}
pub use impl_aead_slice_trait;