libcrux_traits/aead/
slice.rs

1//! This module contains the trait and related errors for an Authenticated
2//! Encryption with Associated Data (AEAD) scheme that takes slices
3//! as arguments and writes outputs to mutable slices.
4
5use libcrux_secrets::U8;
6
7/// An Authenticated Encryption with Associated Data (AEAD) scheme.
8///
9/// Some implementors of this trait may impose stronger restrictions on the inputs than described
10/// here. Check the documentation of the types implementing this trait to make sure which inputs
11/// are valid.
12pub trait Aead {
13    /// Generate a new key. Consumes the entire randomnes. It is the responsibility of the caller
14    /// to ensure `rand` is random and long enough (usually as long as `key`).
15    fn keygen(key: &mut [U8], rand: &[U8]) -> Result<(), KeyGenError>;
16
17    /// Encrypt a plaintext message, producing a ciphertext and an authentication tag.
18    /// The arguments `plaintext` and `ciphertext` must have the same length.
19    fn encrypt(
20        ciphertext: &mut [u8],
21        tag: &mut [U8],
22        key: &[U8],
23        nonce: &[U8],
24        aad: &[u8],
25        plaintext: &[U8],
26    ) -> Result<(), EncryptError>;
27
28    /// Decrypt a ciphertext, verifying its authenticity.
29    /// The arguments `plaintext` and `ciphertext` must have the same length.
30    fn decrypt(
31        plaintext: &mut [U8],
32        key: &[U8],
33        nonce: &[U8],
34        aad: &[u8],
35        ciphertext: &[u8],
36        tag: &[U8],
37    ) -> Result<(), DecryptError>;
38}
39
40/// Error that can orrur during key generation
41pub enum KeyGenError {
42    /// The provided key has the wrong length
43    WrongKeyLength,
44
45    /// The provided randomness is too short
46    InsufficientRandomness,
47
48    /// The provided randomness is not suitable. Usually this is resolved by trying again with
49    /// different randomness (which would do rejection sampling).
50    UnsuitableRandomness,
51}
52
53/// Error that can occur during encryption.
54#[derive(Debug, PartialEq, Eq)]
55pub enum EncryptError {
56    /// The ciphertext buffer has the wrong length.
57    WrongCiphertextLength,
58
59    /// The plaintext is too long for this algorithm or implementation.
60    PlaintextTooLong,
61
62    /// The AAD is too long for this algorithm or implementation.
63    AadTooLong,
64
65    /// The key has the wrong length.
66    WrongKeyLength,
67
68    /// The tag has the wrong length.
69    WrongTagLength,
70
71    /// The nonce has the wrong length.
72    WrongNonceLength,
73
74    /// An unknown error occurred during encryption.
75    Unknown,
76}
77
78/// Error that can occur during decryption.
79#[derive(Debug, PartialEq, Eq)]
80pub enum DecryptError {
81    /// The authentication tag is invalid; the ciphertext has been tampered with
82    /// or the key/nonce/aad is incorrect.
83    InvalidTag,
84
85    /// The plaintext buffer has the wrong length.
86    WrongPlaintextLength,
87
88    /// The plaintext is too long for this algorithm or implementation.
89    PlaintextTooLong,
90
91    /// The AAD is too long for this algorithm or implementation.
92    AadTooLong,
93
94    /// The key has the wrong length.
95    WrongKeyLength,
96
97    /// The tag has the wrong length.
98    WrongTagLength,
99
100    /// The nonce has the wrong length.
101    WrongNonceLength,
102
103    /// An unknown error occurred during decryption.
104    Unknown,
105}
106
107impl From<super::arrayref::EncryptError> for EncryptError {
108    fn from(value: super::arrayref::EncryptError) -> Self {
109        match value {
110            super::arrayref::EncryptError::WrongCiphertextLength => {
111                EncryptError::WrongCiphertextLength
112            }
113            super::arrayref::EncryptError::PlaintextTooLong => EncryptError::PlaintextTooLong,
114            super::arrayref::EncryptError::AadTooLong => EncryptError::AadTooLong,
115            super::arrayref::EncryptError::Unknown => EncryptError::Unknown,
116        }
117    }
118}
119
120impl From<super::arrayref::DecryptError> for DecryptError {
121    fn from(value: super::arrayref::DecryptError) -> Self {
122        match value {
123            super::arrayref::DecryptError::InvalidTag => DecryptError::InvalidTag,
124            super::arrayref::DecryptError::WrongPlaintextLength => {
125                DecryptError::WrongPlaintextLength
126            }
127            super::arrayref::DecryptError::PlaintextTooLong => DecryptError::PlaintextTooLong,
128            super::arrayref::DecryptError::AadTooLong => DecryptError::AadTooLong,
129            super::arrayref::DecryptError::Unknown => DecryptError::Unknown,
130        }
131    }
132}
133
134impl core::fmt::Display for EncryptError {
135    fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
136        let text = match self {
137            EncryptError::WrongCiphertextLength => "ciphertext buffer has wrong length",
138            EncryptError::PlaintextTooLong => {
139                "plaintext is too long for algorithm or implementation"
140            }
141            EncryptError::AadTooLong => "aad is too long for algorithm or implementation",
142            EncryptError::Unknown => "an unknown error occurred",
143            EncryptError::WrongKeyLength => "key has wrong length",
144            EncryptError::WrongTagLength => "tag has wrong length",
145            EncryptError::WrongNonceLength => "nonce has wrong length",
146        };
147
148        f.write_str(text)
149    }
150}
151
152impl core::fmt::Display for DecryptError {
153    fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
154        let text = match self {
155            DecryptError::InvalidTag => "invalid authentication tag",
156            DecryptError::WrongPlaintextLength => "plaintext buffer has wrong length",
157            DecryptError::PlaintextTooLong => {
158                "plaintext is too long for algorithm or implementation"
159            }
160            DecryptError::AadTooLong => "aad is too long for algorithm or implementation",
161            DecryptError::Unknown => "an unknown error occurred",
162            DecryptError::WrongKeyLength => "key has wrong length",
163            DecryptError::WrongTagLength => "tag has wrong length",
164            DecryptError::WrongNonceLength => "nonce has wrong length",
165        };
166
167        f.write_str(text)
168    }
169}
170
171#[cfg(feature = "error-in-core")]
172/// Here we implement the Error trait. This has only been added to core relatively recently, so we
173/// are hiding that behind a feature.
174mod error_in_core {
175    impl core::error::Error for super::EncryptError {}
176    impl core::error::Error for super::DecryptError {}
177}
178
179/// Implements [`slice::Aead`] based on [`arrayref::Aead`].
180///
181/// [`slice::Aead`]: Aead
182/// [`arrayref::Aead`]: super::arrayref::Aead
183#[macro_export]
184macro_rules! impl_aead_slice_trait {
185    ($type:ty => $key:expr, $tag:expr, $nonce:expr) => {
186        impl $crate::aead::slice::Aead for $type {
187            fn keygen(
188                key: &mut [$crate::libcrux_secrets::U8],
189                rand: &[$crate::libcrux_secrets::U8],
190            ) -> Result<(), $crate::aead::slice::KeyGenError> {
191                let key: &mut [$crate::libcrux_secrets::U8; $key] = key
192                    .try_into()
193                    .map_err(|_| $crate::aead::slice::KeyGenError::WrongKeyLength)?;
194                if rand.len() < $key {
195                    return Err($crate::aead::slice::KeyGenError::InsufficientRandomness);
196                }
197
198                Ok(key.copy_from_slice(rand))
199            }
200
201            fn encrypt(
202                ciphertext: &mut [u8],
203                tag: &mut [$crate::libcrux_secrets::U8],
204                key: &[$crate::libcrux_secrets::U8],
205                nonce: &[$crate::libcrux_secrets::U8],
206                aad: &[u8],
207                plaintext: &[$crate::libcrux_secrets::U8],
208            ) -> Result<(), $crate::aead::slice::EncryptError> {
209                let key: &[$crate::libcrux_secrets::U8; $key] = key
210                    .try_into()
211                    .map_err(|_| $crate::aead::slice::EncryptError::WrongKeyLength)?;
212                let tag: &mut [$crate::libcrux_secrets::U8; $tag] = tag
213                    .try_into()
214                    .map_err(|_| $crate::aead::slice::EncryptError::WrongTagLength)?;
215                let nonce: &[$crate::libcrux_secrets::U8; $nonce] = nonce
216                    .try_into()
217                    .map_err(|_| $crate::aead::slice::EncryptError::WrongNonceLength)?;
218
219                <Self as $crate::aead::arrayref::Aead<$key, $tag, $nonce>>::encrypt(
220                    ciphertext, tag, key, nonce, aad, plaintext,
221                )
222                .map_err($crate::aead::slice::EncryptError::from)
223            }
224
225            fn decrypt(
226                plaintext: &mut [$crate::libcrux_secrets::U8],
227                key: &[$crate::libcrux_secrets::U8],
228                nonce: &[$crate::libcrux_secrets::U8],
229                aad: &[u8],
230                ciphertext: &[u8],
231                tag: &[$crate::libcrux_secrets::U8],
232            ) -> Result<(), $crate::aead::slice::DecryptError> {
233                let key: &[$crate::libcrux_secrets::U8; $key] = key
234                    .try_into()
235                    .map_err(|_| $crate::aead::slice::DecryptError::WrongKeyLength)?;
236                let tag: &[$crate::libcrux_secrets::U8; $tag] = tag
237                    .try_into()
238                    .map_err(|_| $crate::aead::slice::DecryptError::WrongTagLength)?;
239                let nonce: &[$crate::libcrux_secrets::U8; $nonce] = nonce
240                    .try_into()
241                    .map_err(|_| $crate::aead::slice::DecryptError::WrongNonceLength)?;
242
243                <Self as $crate::aead::arrayref::Aead<$key, $tag, $nonce>>::decrypt(
244                    plaintext, key, nonce, aad, ciphertext, tag,
245                )
246                .map_err($crate::aead::slice::DecryptError::from)
247            }
248        }
249
250        #[cfg(test)]
251        #[test]
252        fn simple_aead_test() {
253            $crate::aead::tests::simple::<$key, $tag, $nonce, $type>();
254        }
255    };
256}
257
258pub use impl_aead_slice_trait;