wolf_crypto/aead/
chacha20_poly1305.rs

1//! The `ChaCha20Poly1305` Authenticated Encryption with Associated Data (AEAD).
2//!
3//! This module offers both one-shot encryption/decryption functions and a stateful API that can be
4//! used to perform streaming encryption/decryption with optional associated data (AAD). The
5//! stateful API ensures correct usage through a compile-time state machine.
6//!
7//! # Examples
8//!
9//! Using the one-shot encryption function:
10//!
11//! ```
12//! use wolf_crypto::aead::chacha20_poly1305::{encrypt, decrypt_in_place, Key};
13//!
14//! # fn main() -> Result<(), wolf_crypto::Unspecified> {
15//! let key = Key::new([0u8; 32]);
16//! let iv = [0u8; 12];
17//! let plaintext = b"Secret message";
18//! let mut ciphertext = [0u8; 14];
19//!
20//! let tag = encrypt(key.as_ref(), &iv, plaintext, &mut ciphertext, ())?;
21//! decrypt_in_place(key, iv, &mut ciphertext, (), tag)?;
22//!
23//! assert_eq!(ciphertext, *plaintext);
24//! # Ok(()) }
25//! ```
26//!
27//! Using the stateful API:
28//!
29//! ```
30//! use wolf_crypto::{aead::ChaCha20Poly1305, MakeOpaque};
31//! use wolf_crypto::mac::poly1305::Key;
32//!
33//! # fn main() -> Result<(), wolf_crypto::Unspecified> {
34//! let plaintext = b"Secret message";
35//! let aad = "Additional data";
36//! let mut ciphertext = [0u8; 14];
37//!
38//! let tag = ChaCha20Poly1305::new_encrypt(Key::new([7u8; 32]), [7u8; 12])
39//!     .set_aad(aad).opaque()?
40//!     .update(plaintext, &mut ciphertext).opaque()?
41//!     .finalize();
42//!
43//! let d_tag = ChaCha20Poly1305::new_decrypt(Key::new([7u8; 32]), [7u8; 12])
44//!     .update_aad("Additional ")
45//!     .opaque_bind(|aead| aead.update_aad("data"))
46//!     .opaque_bind(|aead| aead.update_in_place(&mut ciphertext))
47//!     .opaque_map(|aead| aead.finalize())?;
48//!
49//! assert_eq!(tag, d_tag);
50//! assert_eq!(ciphertext, *plaintext);
51//! # Ok(())}
52//! ```
53
54pub mod states;
55
56io_impls! {
57    #[doc(hidden)]
58    pub mod io;
59
60    #[doc(inline)]
61    pub use io::Aad as IoAad;
62
63    #[doc(inline)]
64    pub use io::Data as IoData;
65}
66
67use wolf_crypto_sys::{
68    ChaChaPoly_Aead,
69    wc_ChaCha20Poly1305_UpdateData, wc_ChaCha20Poly1305_UpdateAad,
70    wc_ChaCha20Poly1305_Init, wc_ChaCha20Poly1305_Final,
71    wc_ChaCha20Poly1305_Decrypt, wc_ChaCha20Poly1305_Encrypt,
72    CHACHA20_POLY1305_AEAD_DECRYPT, CHACHA20_POLY1305_AEAD_ENCRYPT,
73};
74
75#[cfg(feature = "llvm-assume")]
76use wolf_crypto_sys::{
77    CHACHA20_POLY1305_STATE_READY, CHACHA20_POLY1305_STATE_AAD, CHACHA20_POLY1305_STATE_DATA,
78    byte
79};
80
81use states::{
82    State, Init, CanUpdate, CanSetAad, CanUpdateAad,
83    Updating, UpdatingAad,
84
85    EncryptMaybeAad, DecryptMaybeAad,
86    EncryptAad, DecryptAad,
87};
88
89#[doc(inline)]
90pub use states::{Decrypt, Encrypt};
91
92use core::mem::MaybeUninit;
93use core::marker::PhantomData;
94use core::ptr::addr_of_mut;
95use crate::aead::{Aad, Tag};
96use crate::buf::{GenericIv, U12};
97use crate::mac::poly1305::GenericKey;
98use crate::opaque_res::Res;
99use crate::{can_cast_u32, const_can_cast_u32, Unspecified};
100
101#[doc(inline)]
102pub use crate::mac::poly1305::{Key, KeyRef};
103
104opaque_dbg! { ChaCha20Poly1305<Init> }
105opaque_dbg! { ChaCha20Poly1305<EncryptMaybeAad> }
106opaque_dbg! { ChaCha20Poly1305<DecryptMaybeAad> }
107opaque_dbg! { ChaCha20Poly1305<EncryptAad> }
108opaque_dbg! { ChaCha20Poly1305<DecryptAad> }
109opaque_dbg! { ChaCha20Poly1305<Encrypt> }
110opaque_dbg! { ChaCha20Poly1305<Decrypt> }
111
112#[inline(always)]
113#[must_use]
114fn oneshot_predicate<A: Aad>(plain: &[u8], out: &[u8], aad: &A) -> bool {
115    can_cast_u32(plain.len()) && out.len() >= plain.len() && aad.is_valid_size()
116}
117
118/// Encrypts data using the `ChaCha20Poly1305` AEAD.
119///
120/// # Arguments
121///
122/// * `key` - The 32-byte key material.
123/// * `iv` - The 12-byte initialization vector.
124/// * `plain` - The plaintext data to encrypt.
125/// * `out` - The buffer to store the resulting ciphertext. The buffer must be at least as large
126///   as `plain`.
127/// * `aad` - The associated data, which is authenticated but not encrypted.
128///
129/// # Returns
130///
131/// The authentication [`Tag`] for the ciphertext, used to verify the integrity and authenticity
132/// of the data during decryption.
133///
134/// # Errors
135///
136/// - The length of the plaintext is greater than [`u32::MAX`].
137/// - The length of the output buffer is less than the plaintext length.
138/// - The length of the associated data is greater than [`u32::MAX`].
139///
140/// # Example
141///
142/// ```
143/// use wolf_crypto::{aead::chacha20_poly1305::encrypt, mac::poly1305::Key};
144///
145/// let mut out = [0u8; 12];
146///
147/// let tag = encrypt(
148///     Key::new([7u8; 32]), [42u8; 12],
149///     b"hello world!", &mut out,
150///     "Some additional data"
151/// ).unwrap();
152///
153/// assert_ne!(&out, b"hello world!");
154/// # let _ = tag;
155/// ```
156pub fn encrypt<K, IV, A>(
157    key: K, iv: IV,
158    plain: &[u8], out: &mut [u8],
159    aad: A
160) -> Result<Tag, Unspecified>
161    where
162        K: GenericKey,
163        IV: GenericIv<Size = U12>,
164        A: Aad
165{
166    if !oneshot_predicate(plain, out, &aad) { return Err(Unspecified) }
167    let mut res = Res::new();
168    let mut tag = Tag::new_zeroed();
169
170    unsafe {
171        res.ensure_0(wc_ChaCha20Poly1305_Encrypt(
172            key.ptr(),
173            iv.as_slice().as_ptr(),
174            aad.ptr(),
175            aad.size(),
176            plain.as_ptr(),
177            plain.len() as u32,
178            out.as_mut_ptr(),
179            tag.as_mut_ptr()
180        ));
181    }
182
183    res.unit_err(tag)
184}
185
186/// Encrypts data in-place using the `ChaCha20Poly1305` AEAD.
187///
188/// # Arguments
189///
190/// * `key` - The 32-byte key material.
191/// * `iv` - The 12-byte initialization vector.
192/// * `in_out` - A mutable buffer containing the plaintext, which is overwritten with the ciphertext.
193/// * `aad` - The associated data, which is authenticated but not encrypted.
194///
195/// # Returns
196///
197/// The authentication [`Tag`] for the ciphertext, used to verify the integrity and authenticity
198/// of the data during decryption.
199///
200/// # Errors
201///
202/// - The length of the plaintext is greater than [`u32::MAX`].
203/// - The length of the associated data is greater than [`u32::MAX`].
204///
205/// # Example
206///
207/// ```
208/// use wolf_crypto::aead::chacha20_poly1305::{encrypt_in_place, Key};
209///
210/// let mut in_out = *b"Hello, world!";
211/// let tag = encrypt_in_place(Key::new([7u8; 32]), [42u8; 12], &mut in_out, "additional").unwrap();
212///
213/// assert_ne!(&in_out, b"Hello, world!");
214/// # let _ = tag;
215/// ```
216pub fn encrypt_in_place<K, IV, A>(key: K, iv: IV, in_out: &mut [u8], aad: A) -> Result<Tag, Unspecified>
217    where
218        K: GenericKey,
219        IV: GenericIv<Size = U12>,
220        A: Aad
221{
222    if !(can_cast_u32(in_out.len()) && aad.is_valid_size()) { return Err(Unspecified) }
223    let mut res = Res::new();
224    let mut tag = Tag::new_zeroed();
225
226    unsafe {
227        res.ensure_0(wc_ChaCha20Poly1305_Encrypt(
228            key.ptr(),
229            iv.as_slice().as_ptr(),
230            aad.ptr(),
231            aad.size(),
232            in_out.as_ptr(),
233            in_out.len() as u32,
234            in_out.as_ptr().cast_mut(),
235            tag.as_mut_ptr()
236        ));
237    }
238
239    res.unit_err(tag)
240}
241
242/// Decrypts data using the `ChaCha20Poly1305` AEAD.
243///
244/// # Arguments
245///
246/// * `key` - The 32-byte key material.
247/// * `iv` - The 12-byte initialization vector.
248/// * `cipher` - The ciphertext to decrypt.
249/// * `out` - The buffer to store the resulting plaintext. The buffer must be at least as large as
250///   `cipher`.
251/// * `aad` - The associated data, which is authenticated but not encrypted.
252/// * `tag` - The authentication tag to verify.
253///
254/// # Errors
255///
256/// - The length of the ciphertext is greater than [`u32::MAX`].
257/// - The length of the output buffer is less than the plaintext length.
258/// - The length of the associated data is greater than [`u32::MAX`].
259/// - The verification of the authentication tag failed, indicating tampering.
260///
261/// # Example
262///
263/// ```
264/// use wolf_crypto::aead::chacha20_poly1305::{encrypt_in_place, decrypt, Key};
265///
266/// let (key, iv, mut cipher) = (Key::new([7u8; 32]), [42u8; 12], *b"plaintext");
267/// let tag = encrypt_in_place(key.as_ref(), &iv, &mut cipher, "additional data").unwrap();
268///
269/// let mut plain = [0u8; 9];
270/// decrypt(key, iv, &cipher, &mut plain, "additional data", tag).unwrap();
271///
272/// assert_eq!(plain, *b"plaintext");
273/// ```
274pub fn decrypt<K, IV, A>(
275    key: K, iv: IV,
276    cipher: &[u8], out: &mut [u8],
277    aad: A, tag: Tag
278) -> Result<(), Unspecified>
279    where
280        K: GenericKey,
281        IV: GenericIv<Size = U12>,
282        A: Aad
283{
284    if !oneshot_predicate(cipher, out, &aad) { return Err(Unspecified) }
285    let mut res = Res::new();
286
287    unsafe {
288        res.ensure_0(wc_ChaCha20Poly1305_Decrypt(
289            key.ptr(),
290            iv.as_slice().as_ptr(),
291            aad.ptr(),
292            aad.size(),
293            cipher.as_ptr(),
294            cipher.len() as u32,
295            tag.as_ptr(),
296            out.as_mut_ptr()
297        ));
298    }
299
300    res.unit_err(())
301}
302
303/// Decrypts data in-place using the `ChaCha20Poly1305` AEAD.
304///
305/// # Arguments
306///
307/// * `key` - The 32-byte key material.
308/// * `iv` - The 12-byte initialization vector.
309/// * `in_out` - A mutable buffer containing the ciphertext, which is overwritten with the plaintext.
310/// * `aad` - The associated data, which is authenticated but not encrypted.
311/// * `tag` - The authentication tag to verify.
312///
313/// # Errors
314///
315/// - The length of the ciphertext is greater than [`u32::MAX`].
316/// - The length of the associated data is greater than [`u32::MAX`].
317/// - The verification of the authentication tag failed, indicating tampering.
318///
319/// # Example
320///
321/// ```
322/// use wolf_crypto::aead::chacha20_poly1305::{encrypt_in_place, decrypt_in_place, Key};
323///
324/// let (key, iv, mut in_out) = (Key::new([7u8; 32]), [42u8; 12], *b"plaintext");
325/// let tag = encrypt_in_place(key.as_ref(), &iv, &mut in_out, "additional data").unwrap();
326///
327/// decrypt_in_place(key, iv, &mut in_out, "additional data", tag).unwrap();
328///
329/// assert_eq!(in_out, *b"plaintext");
330/// ```
331pub fn decrypt_in_place<K, IV, A>(
332    key: K, iv: IV,
333    in_out: &mut [u8],
334    aad: A, tag: Tag
335) -> Result<(), Unspecified>
336where
337    K: GenericKey,
338    IV: GenericIv<Size = U12>,
339    A: Aad
340{
341    if !(can_cast_u32(in_out.len()) && aad.is_valid_size()) { return Err(Unspecified) }
342    let mut res = Res::new();
343
344    unsafe {
345        res.ensure_0(wc_ChaCha20Poly1305_Decrypt(
346            key.ptr(),
347            iv.as_slice().as_ptr(),
348            aad.ptr(),
349            aad.size(),
350            in_out.as_ptr(),
351            in_out.len() as u32,
352            tag.as_ptr(),
353            in_out.as_ptr().cast_mut()
354        ));
355    }
356
357    res.unit_err(())
358}
359
360/// The `ChaCha20Poly1305` ([`RFC8439`][1]) [AEAD][2].
361///
362/// `ChaCha20Poly1305` combines the [`ChaCha20`][3] stream cipher with the [`Poly1305`][4] message
363/// authentication code. `ChaCha20Poly1305` is well-regarded for efficiency and performance, with
364/// or without hardware acceleration, making it amenable to resource constrained environments.
365///
366/// # Interface
367///
368/// This crate's interface for `ChaCha20Poly1305` is designed as a compile-time state machine,
369/// ensuring errors / misuse is caught early, and without any runtime overhead.
370///
371/// The state machine for both encryption and decryption follows the following flow
372///
373/// ```txt
374///                       set_aad(...)
375///   +--------------------------------------+
376///   |           +---+                      |
377///   |           |   v                      v           finalize()
378/// +------+     +-----+   finish()        +----------+        +-----+
379/// | Init | --> | AAD | ----------------> |          | -----> | Tag |
380/// +------+     +-----+                   | Updating |        +-----+
381///   |                   update(...)      |          |
382///   +----------------------------------> |          |
383///                                        +----------+
384///                                          ^      |
385///                                          +------+
386/// ```
387///
388/// The state machine is initialized in either decryption or encryption mode, this initial state
389/// has the following three possible transitions:
390///
391/// ```txt
392///                 +------------------+
393///   +------------ |       Init       | --------+
394///   |             +------------------+         |
395///   |               |                          |
396///   |               | update_aad(...)          |
397///   |               v                          |
398///   |             +------------------+         |
399///   |             |                  |--+      |
400///   |             |       AAD        |  |      |
401///   |             |                  |<-+      |
402///   |             +------------------+         |
403///   |               |                          |
404///   | update(...)   | finish()                 | set_aad(...)
405///   |               v                          |
406///   |             +------------------+         |
407///   +-----------> |     Updating     | <-------+
408///                 +------------------+
409///                          |
410///                          v
411///                         ...
412/// ```
413///
414/// - [`update(...)`][5] path:
415///     The user encrypts or decrypts data without providing any AAD. This method is used
416///     to process the main body of the message. After processing the plaintext or ciphertext,
417///     the user can either continue updating with more data, or invoke [`finalize()`][6]
418///     to return the authentication tag.
419/// - [`set_aad`][6] path:
420///     Similar to the [`update(...)`][5] path, but this method sets the associated data (AAD),
421///     which is data that is authenticated but not encrypted. The AAD is processed first
422///     before transitioning to the `Updating` state, where data is encrypted or decrypted.
423///     AAD helps verify the integrity of the message.
424/// - [`update_aad(...)`][7] path:
425///     This method transitions to the `AAD` state, allowing the user to process associated
426///     data in chunks. It is useful in cases where the complete AAD is not available at once,
427///     and the user needs to progressively update it. Once all AAD is processed, the state
428///     transitions to `Updating` by invoking [`finish()`][8].
429///
430/// # Examples
431///
432/// ```
433/// use wolf_crypto::{aead::ChaCha20Poly1305, mac::poly1305::Key, MakeOpaque};
434///
435/// # fn main() -> Result<(), wolf_crypto::Unspecified> {
436/// let mut in_out = [7u8; 42];
437/// let key = Key::new([3u8; 32]);
438///
439/// let tag = ChaCha20Poly1305::new_encrypt(key.as_ref(), [7u8; 12])
440///     .update_in_place(&mut in_out).opaque()?
441///     .finalize();
442///
443/// assert_ne!(in_out, [7u8; 42]);
444///
445/// let d_tag = ChaCha20Poly1305::new_decrypt(key.as_ref(), [7u8; 12])
446///     .update_in_place(&mut in_out).opaque()?
447///     .finalize();
448///
449/// // PartialEq for tags is constant time
450/// assert_eq!(tag, d_tag);
451/// assert_eq!(in_out, [7u8; 42]);
452/// #
453/// # Ok(()) }
454/// ```
455///
456/// **With AAD**
457///
458/// ```
459/// use wolf_crypto::{aead::ChaCha20Poly1305, mac::poly1305::Key, MakeOpaque};
460///
461/// # fn main() -> Result<(), wolf_crypto::Unspecified> {
462/// let mut in_out = [7u8; 42];
463/// let key = Key::new([3u8; 32]);
464///
465/// let tag = ChaCha20Poly1305::new_encrypt(key.as_ref(), [7u8; 12])
466///     .set_aad("hello world").opaque()?
467///     .update_in_place(&mut in_out).opaque()?
468///     .finalize();
469///
470/// assert_ne!(in_out, [7u8; 42]);
471///
472/// let d_tag = ChaCha20Poly1305::new_decrypt(key.as_ref(), [7u8; 12])
473///     .set_aad("hello world")
474///     .opaque_bind(|aead| aead.update_in_place(&mut in_out))
475///     .opaque_map(|aead| aead.finalize())?;
476///
477/// // PartialEq for tags is constant time
478/// assert_eq!(tag, d_tag);
479/// assert_eq!(in_out, [7u8; 42]);
480/// #
481/// # Ok(()) }
482/// ```
483///
484/// # Errors
485///
486/// To guarantee that the state machine is correctly used, all methods take ownership over the
487/// `ChaCha20Poly1305` instance. The `ChaCha20Poly1305` instance is always returned whether the
488/// operation failed or not, allowing for retries.
489///
490/// For example, with the [`set_aad(...)`][6] method:
491///
492/// ```txt
493///     Error!
494///   +----------+
495///   v          |
496/// +--------------+  Success!   +----------------+
497/// | set_aad(...) | ----------> | Updating State |
498/// +--------------+             +----------------+
499/// ```
500///
501/// While this serves its purpose in allowing retries, it can be annoying for error propagation. To
502/// remedy this, there is the [`MakeOpaque`] trait, which will convert the error type into the
503/// [`Unspecified`] type via the [`opaque`] method, as well as provide common combinatorics such as
504/// [`opaque_bind`] and [`opaque_map`].
505///
506/// [1]: https://datatracker.ietf.org/doc/html/rfc8439
507/// [2]: https://en.wikipedia.org/wiki/Authenticated_encryption
508/// [3]: crate::chacha::ChaCha20
509/// [4]: crate::mac::Poly1305
510/// [5]: ChaCha20Poly1305::update
511/// [6]: ChaCha20Poly1305::set_aad
512/// [7]: ChaCha20Poly1305::update_aad
513/// [8]: ChaCha20Poly1305::finish
514///
515/// [`MakeOpaque`]: crate::MakeOpaque
516/// [`opaque`]: crate::MakeOpaque::opaque
517/// [`opaque_bind`]: crate::MakeOpaque::opaque_bind
518/// [`opaque_map`]: crate::MakeOpaque::opaque_map
519#[must_use]
520#[repr(transparent)]
521pub struct ChaCha20Poly1305<S: State = Init> {
522    inner: ChaChaPoly_Aead,
523    _state: PhantomData<S>
524}
525
526impl ChaCha20Poly1305<Init> {
527    /// Creates a new `ChaCha20Poly1305` instance with the specified direction.
528    ///
529    /// # Arguments
530    ///
531    /// * `key` - The 32-byte key material.
532    /// * `iv` - The 12-byte initialization vector.
533    /// * `dir` - The direction of the operation (`CHACHA20_POLY1305_AEAD_ENCRYPT` or
534    ///   `CHACHA20_POLY1305_AEAD_DECRYPT`).
535    ///
536    /// # Safety
537    ///
538    /// This function is unsafe as it assumes that the provided `dir` is valid.
539    fn new_with_dir<K, IV, S>(key: K, iv: IV, dir: core::ffi::c_int) -> ChaCha20Poly1305<S>
540        where
541            K: GenericKey,
542            IV: GenericIv<Size = U12>,
543            S: State
544    {
545        debug_assert!(matches!(
546            dir as core::ffi::c_uint,
547            CHACHA20_POLY1305_AEAD_ENCRYPT | CHACHA20_POLY1305_AEAD_DECRYPT
548        ));
549
550        let mut inner = MaybeUninit::<ChaChaPoly_Aead>::uninit();
551
552        unsafe {
553            let _res = wc_ChaCha20Poly1305_Init(
554                inner.as_mut_ptr(),
555                key.ptr(),
556                iv.as_slice().as_ptr(),
557                dir
558            );
559
560            debug_assert_eq!(_res, 0);
561
562            ChaCha20Poly1305::<S> {
563                inner: inner.assume_init(),
564                _state: PhantomData
565            }
566        }
567    }
568
569    /// Create a new [`ChaCha20Poly1305`] instance for either encryption or decryption.
570    ///
571    /// # Generic
572    ///
573    /// The provided `Mode` generic denotes whether this instance will be used for encryption or
574    /// decryption. The possible types are:
575    ///
576    /// * [`Decrypt`] - Initialize the instance for decryption, there is also the [`new_decrypt`][1]
577    ///   convenience associated function.
578    /// * [`Encrypt`] - Initialize the instance for encryption, there is also the [`new_encrypt`][2]
579    ///   convenience associated function.
580    ///
581    /// # Arguments
582    ///
583    /// * `key` - The 32 byte key material to use.
584    /// * `iv`  - The 12 byte initialization vector to use.
585    ///
586    /// # Examples
587    ///
588    /// **Decryption**
589    /// ```
590    /// use wolf_crypto::{aead::chacha20_poly1305::{ChaCha20Poly1305, Decrypt}, mac::poly1305::Key};
591    ///
592    /// # let _ = {
593    /// ChaCha20Poly1305::new::<Decrypt>(Key::new([7u8; 32]), [42u8; 12])
594    /// # };
595    /// ```
596    ///
597    /// **Encryption**
598    /// ```
599    /// use wolf_crypto::{aead::chacha20_poly1305::{ChaCha20Poly1305, Encrypt}, mac::poly1305::Key};
600    ///
601    /// # let _ = {
602    /// ChaCha20Poly1305::new::<Encrypt>(Key::new([7u8; 32]), [42u8; 12])
603    /// # };
604    /// ```
605    ///
606    /// [1]: Self::new_decrypt
607    /// [2]: Self::new_encrypt
608    #[inline]
609    pub fn new<Mode: Updating>(key: impl GenericKey, iv: impl GenericIv<Size = U12>) -> ChaCha20Poly1305<Mode::InitState> {
610        Self::new_with_dir(key, iv, Mode::direction())
611    }
612
613    /// Create a new [`ChaCha20Poly1305`] instance for encryption.
614    ///
615    /// # Arguments
616    ///
617    /// * `key` - The 32 byte key material to use.
618    /// * `iv`  - The 12 byte initialization vector to use.
619    ///
620    /// # Example
621    ///
622    /// ```
623    /// use wolf_crypto::{aead::ChaCha20Poly1305, mac::poly1305::Key};
624    ///
625    /// # let _ = {
626    /// ChaCha20Poly1305::new_encrypt(Key::new([7u8; 32]), [42u8; 12])
627    /// # };
628    /// ```
629    ///
630    /// # Note
631    ///
632    /// This is a convenience associated function for calling [`ChaCha20Poly1305::new::<Encrypt>(...)`][1],
633    /// circumventing the need for importing the [`Encrypt`] marker type.
634    ///
635    /// [1]: Self::new
636    #[inline]
637    pub fn new_encrypt<K, IV>(key: K, iv: IV) -> ChaCha20Poly1305<<Encrypt as Updating>::InitState>
638        where
639            K: GenericKey,
640            IV: GenericIv<Size = U12>
641    {
642        Self::new::<Encrypt>(key, iv)
643    }
644
645    /// Create a new [`ChaCha20Poly1305`] instance for decryption.
646    ///
647    /// # Arguments
648    ///
649    /// * `key` - The 32 byte key material to use.
650    /// * `iv`  - The 12 byte initialization vector to use.
651    ///
652    /// # Example
653    ///
654    /// ```
655    /// use wolf_crypto::{aead::ChaCha20Poly1305, mac::poly1305::Key};
656    ///
657    /// # let _ = {
658    /// ChaCha20Poly1305::new_decrypt(Key::new([7u8; 32]), [42u8; 12])
659    /// # };
660    /// ```
661    ///
662    /// # Note
663    ///
664    /// This is a convenience associated function for calling [`ChaCha20Poly1305::new::<Decrypt>(...)`][1],
665    /// circumventing the need for importing the [`Decrypt`] marker type.
666    ///
667    /// [1]: Self::new
668    #[inline]
669    pub fn new_decrypt<K, IV>(key: K, iv: IV) -> ChaCha20Poly1305<<Decrypt as Updating>::InitState>
670        where
671            K: GenericKey,
672            IV: GenericIv<Size = U12>
673    {
674        Self::new::<Decrypt>(key, iv)
675    }
676}
677
678impl<S: State> ChaCha20Poly1305<S> {
679    /// Transitions the state of the `ChaCha20Poly1305` instance to a new state.
680    ///
681    /// # Type Parameters
682    ///
683    /// * `N` - The new state type.
684    ///
685    /// # Returns
686    ///
687    /// A new `ChaCha20Poly1305` instance with the updated state.
688    #[inline]
689    pub(crate) const fn with_state<N: State>(self) -> ChaCha20Poly1305<N> {
690        // SAFETY: we're just updating the phantom data state, same everything
691        unsafe { core::mem::transmute(self) }
692    }
693}
694
695impl<S: CanUpdateAad> ChaCha20Poly1305<S> {
696    /// Updates the AAD (Additional Authenticated Data) without performing any safety checks in
697    /// release builds.
698    ///
699    /// # Safety
700    ///
701    /// The caller must ensure that the AAD length is safely representable as a `u32`.
702    ///
703    /// # Arguments
704    ///
705    /// * `aad` - The additional authenticated data to include in the authentication tag.
706    ///
707    /// # Panics
708    ///
709    /// Panics in debug mode if the AAD size is invalid or if the internal state is incorrect.
710    #[cfg_attr(debug_assertions, track_caller)]
711    #[inline]
712    unsafe fn update_aad_unchecked<A: Aad>(&mut self, aad: A) {
713        debug_assert!(aad.is_valid_size());
714
715        #[cfg(feature = "llvm-assume")] {
716            // Guaranteed via trait based state machine
717            core::hint::assert_unchecked(
718                self.inner.state == CHACHA20_POLY1305_STATE_READY as byte ||
719                    self.inner.state == CHACHA20_POLY1305_STATE_AAD as byte
720            );
721
722            core::hint::assert_unchecked(
723                self.inner.state != CHACHA20_POLY1305_STATE_DATA as byte
724            );
725        }
726
727        let _res = wc_ChaCha20Poly1305_UpdateAad(
728            addr_of_mut!(self.inner),
729            aad.ptr(),
730            aad.size()
731        );
732
733        debug_assert_eq!(_res, 0);
734    }
735
736    io_impls! {
737        /// Returns an `Aad<S::Updating, IO>` struct which implements the `Read` and `Write` traits
738        /// for processing Additional Authenticated Data (AAD).
739        ///
740        /// This method allows for streaming AAD processing, which is useful when the entire AAD
741        /// is not available at once or when working with I/O streams.
742        ///
743        /// # Arguments
744        ///
745        /// * `io`: An implementor of the `Read` or `Write` traits. The data passed to and from
746        ///   this `io` implementor will be authenticated as AAD.
747        ///
748        /// # Returns
749        ///
750        /// An `Aad<S::Updating, IO>` struct that wraps the ChaCha20Poly1305 instance and the
751        /// provided IO type.
752        ///
753        /// # Example
754        ///
755        /// ```
756        /// use wolf_crypto::aead::chacha20_poly1305::{ChaCha20Poly1305, Key};
757        /// use wolf_crypto::MakeOpaque;
758        #[cfg_attr(all(feature = "embedded-io", not(feature = "std")), doc = "use embedded_io::Write;")]
759        #[cfg_attr(feature = "std", doc = "use std::io::Write;")]
760        ///
761        #[cfg_attr(
762            all(feature = "embedded-io", not(feature = "std")),
763            doc = "# fn main() -> Result<(), wolf_crypto::Unspecified> {"
764        )]
765        #[cfg_attr(feature = "std", doc = "# fn main() -> Result<(), Box<dyn std::error::Error>> {")]
766        /// let (key, iv) = (Key::new([7u8; 32]), [42; 12]);
767        /// let mut some_io_write_implementor = [7u8; 64];
768        ///
769        /// let mut io = ChaCha20Poly1305::new_encrypt(key, iv)
770        ///     .aad_io(some_io_write_implementor.as_mut_slice());
771        ///
772        /// let read = io.write(b"hello world")?;
773        /// let (aead, _my_writer) = io.finish();
774        ///
775        /// assert_eq!(&some_io_write_implementor[..read], b"hello world");
776        ///
777        /// let tag = aead.finalize();
778        /// # assert_ne!(tag, wolf_crypto::aead::Tag::new_zeroed()); // no warnings
779        /// # Ok(()) }
780        /// ```
781        #[inline]
782        pub const fn aad_io<IO>(self, io: IO) -> IoAad<S::Updating, IO> {
783            io::Aad::new(self.with_state(), io)
784        }
785    }
786
787    /// Update the underlying message authentication code without encrypting the data.
788    ///
789    /// This transitions to the streaming state for updating the AAD, allowing for partial updates.
790    /// If you already have the entire AAD, consider using [`set_aad`] instead.
791    ///
792    /// # Arguments
793    ///
794    /// * `aad` - The additional authenticated data to include in the authentication [`Tag`].
795    ///
796    /// # Errors
797    ///
798    /// If the length of the AAD is greater than [`u32::MAX`].
799    ///
800    /// # Example
801    ///
802    /// ```
803    /// use wolf_crypto::{aead::chacha20_poly1305::{ChaCha20Poly1305, Key}, MakeOpaque};
804    ///
805    /// # fn main() -> Result<(), wolf_crypto::Unspecified> {
806    /// let tag = ChaCha20Poly1305::new_encrypt(Key::new([7u8; 32]), [42u8; 12])
807    ///     .update_aad("hello world").opaque()?
808    ///     .update_aad("!").opaque()?
809    ///     .finish()
810    ///     .finalize();
811    ///
812    /// let d_tag = ChaCha20Poly1305::new_decrypt(Key::new([7u8; 32]), [42u8; 12])
813    ///     .update_aad("hello world!").opaque()? // equivalent to processing in parts
814    ///     .finish()
815    ///     .finalize();
816    ///
817    /// assert_eq!(tag, d_tag);
818    /// # Ok(()) }
819    /// ```
820    ///
821    /// [`set_aad`]: ChaCha20Poly1305::set_aad
822    #[inline]
823    pub fn update_aad<A: Aad>(mut self, aad: A) -> Result<ChaCha20Poly1305<S::Updating>, Self> {
824        if !aad.is_valid_size() { return Err(self) }
825        unsafe { self.update_aad_unchecked(aad); }
826        Ok(self.with_state())
827    }
828}
829
830impl<S: CanUpdate> ChaCha20Poly1305<S> {
831    /// Performs an unchecked in-place update of the `data` buffer.
832    ///
833    /// # Safety
834    ///
835    /// The caller must ensure that the length of `data` can be safely cast to `u32`.
836    #[inline]
837    unsafe fn update_in_place_unchecked(&mut self, data: &mut [u8]) {
838        debug_assert!(can_cast_u32(data.len()));
839
840        #[cfg(feature = "llvm-assume")]
841            // Guaranteed via trait based state machine
842            core::hint::assert_unchecked(!( // written like this to be an exact negation of
843                                            // the failure condition
844                   self.inner.state != CHACHA20_POLY1305_STATE_READY as byte
845                && self.inner.state != CHACHA20_POLY1305_STATE_AAD as byte
846                && self.inner.state != CHACHA20_POLY1305_STATE_DATA as byte
847            ));
848
849        // INFALLIBLE
850        //
851        // https://github.com/wolfSSL/wolfssl/blob/master/wolfcrypt/src/chacha20_poly1305.c#L247
852        //
853        // The functions preconditions are as follows:
854        //
855        // - aead != NULL /\ inData != NULL /\ outData != NULL
856        // - state == CHACHA20_POLY1305_STATE_READY
857        //   /\ state == CHACHA20_POLY1305_STATE_AAD
858        //   /\ state == CHACHA20_POLY1305_STATE_DATA
859        //
860        // Which we satisfy via the type system.
861        //
862        // The internal function calls we have also already shown to be infallible. These being:
863        //
864        // - wc_Poly1305_Pad (see this crates poly1305 implementations infallibility commentary)
865        // - wc_Poly1305_Update (see this crates poly1305 implementations infallibility commentary)
866        // - wc_ChaCha_Process (see this crates chacha implementation's process_unchecked commentary)
867        //
868        // Which means both update_in_place_unchecked and update_unchecked are infallible.
869
870        let _res = wc_ChaCha20Poly1305_UpdateData(
871            addr_of_mut!(self.inner),
872            // See comment at:
873            // https://github.com/wolfSSL/wolfssl/blob/master/wolfcrypt/src/chacha20_poly1305.c#L246
874            // if you were wondering if it is safe to have the in and out ptr be the same.
875            data.as_ptr(),
876            data.as_ptr().cast_mut(),
877            data.len() as u32
878        );
879
880        debug_assert_eq!(_res, 0);
881    }
882
883    /// Performs an unchecked update of the `data`, writing the `output` to a separate buffer.
884    ///
885    /// # Safety
886    ///
887    /// The caller must ensure that:
888    /// - `data.len() <= output.len()`
889    /// - The length of `data` can be safely cast to `u32`.
890    #[inline]
891    unsafe fn update_unchecked(&mut self, data: &[u8], output: &mut [u8]) {
892        debug_assert!(data.len() <= output.len());
893        debug_assert!(can_cast_u32(data.len()));
894
895        #[cfg(feature = "llvm-assume")] {
896            // Guaranteed via trait based state machine
897            core::hint::assert_unchecked(
898                self.inner.state == CHACHA20_POLY1305_STATE_READY as byte
899                    || self.inner.state == CHACHA20_POLY1305_STATE_AAD as byte
900                    || self.inner.state == CHACHA20_POLY1305_STATE_DATA as byte
901            );
902        }
903
904        // See the update_in_place_unchecked commentary regarding the infallibility of this.
905
906        let _res = wc_ChaCha20Poly1305_UpdateData(
907            addr_of_mut!(self.inner),
908            data.as_ptr(),
909            output.as_mut_ptr(),
910            data.len() as u32
911        );
912
913        debug_assert_eq!(_res, 0);
914    }
915
916    /// Predicate to check if the update operation can proceed.
917    ///
918    /// Ensures that the `input` length can be cast to `u32` and that the `output` buffer is large
919    /// enough.
920    #[inline]
921    #[must_use]
922    const fn update_predicate(input: &[u8], output: &[u8]) -> bool {
923        can_cast_u32(input.len()) && output.len() >= input.len()
924    }
925
926    /// Encrypt / Decrypt the provided `in_out` data in-place.
927    ///
928    /// # Arguments
929    ///
930    /// * `in_out` - A mutable slice of data to be encrypted / decrypted in place.
931    ///
932    /// # Errors
933    ///
934    /// If the length of `in_out` is greater than `u32::MAX`.
935    ///
936    /// # Example
937    ///
938    /// ```
939    /// use wolf_crypto::{aead::ChaCha20Poly1305, mac::poly1305::Key, MakeOpaque};
940    ///
941    /// # fn main() -> Result<(), wolf_crypto::Unspecified> {
942    /// let mut in_out = [7u8; 42];
943    /// let key = Key::new([3u8; 32]);
944    ///
945    /// let tag = ChaCha20Poly1305::new_encrypt(key.as_ref(), [7u8; 12])
946    ///     .set_aad("hello world").opaque()?
947    ///     .update_in_place(&mut in_out).opaque()?
948    ///     .finalize();
949    ///
950    /// assert_ne!(in_out, [7u8; 42]);
951    ///
952    /// let d_tag = ChaCha20Poly1305::new_decrypt(key.as_ref(), [7u8; 12])
953    ///     .set_aad("hello world")
954    ///     .opaque_bind(|aead| aead.update_in_place(&mut in_out))
955    ///     .opaque_map(|aead| aead.finalize())?;
956    ///
957    /// assert_eq!(tag, d_tag);
958    /// assert_eq!(in_out, [7u8; 42]);
959    /// # Ok(()) }
960    /// ```
961    #[inline]
962    pub fn update_in_place(mut self, in_out: &mut [u8]) -> Result<ChaCha20Poly1305<S::Mode>, Self> {
963        if can_cast_u32(in_out.len()) {
964            unsafe { self.update_in_place_unchecked(in_out) };
965            Ok(self.with_state())
966        } else {
967            Err(self)
968        }
969    }
970
971    /// Encrypt / Decrypt the provided `in_out` data in-place.
972    ///
973    /// This method is similar to [`update_in_place`], but accepts a fixed-size array, allowing for
974    /// potential optimizations and compile-time checks.
975    ///
976    /// # Arguments
977    ///
978    /// * `in_out` - A mutable fixed-size array of data to be encrypted or decrypted in place.
979    ///
980    /// # Errors
981    ///
982    /// If the length of `in_out` is greater than `u32::MAX`.
983    ///
984    /// # Example
985    ///
986    /// ```
987    /// use wolf_crypto::aead::{ChaCha20Poly1305};
988    /// use wolf_crypto::mac::poly1305::Key;
989    /// use wolf_crypto::MakeOpaque;
990    ///
991    /// let mut data = [42u8; 64];
992    /// let key = Key::new([0u8; 32]);
993    /// let iv = [0u8; 12];
994    ///
995    /// let tag = ChaCha20Poly1305::new_encrypt(key.as_ref(), iv)
996    ///     .update_in_place_sized(&mut data).unwrap()
997    ///     .finalize();
998    ///
999    /// assert_ne!(data, [42u8; 64]);
1000    ///
1001    /// let d_tag = ChaCha20Poly1305::new_decrypt(key, iv)
1002    ///     .update_in_place_sized(&mut data).unwrap()
1003    ///     .finalize();
1004    ///
1005    /// assert_eq!(data, [42u8; 64]);
1006    /// assert_eq!(tag, d_tag);
1007    /// ```
1008    ///
1009    /// [`update_in_place`]: Self::update_in_place
1010    #[inline]
1011    pub fn update_in_place_sized<const C: usize>(mut self, in_out: &mut [u8; C]) -> Result<ChaCha20Poly1305<S::Mode>, Self> {
1012        if const_can_cast_u32::<C>() {
1013            unsafe { self.update_in_place_unchecked(in_out) };
1014            Ok(self.with_state())
1015        } else {
1016            Err(self)
1017        }
1018    }
1019
1020    /// Encrypt / Decrypt the provided `data` into the `output` buffer.
1021    ///
1022    /// # Arguments
1023    ///
1024    /// * `data` - A slice of data to be encrypted or decrypted.
1025    /// * `output` - A mutable slice where the result will be written. It must be at least as large
1026    ///   as `data`.
1027    ///
1028    /// # Errors
1029    ///
1030    /// - The length of `data` is greater than `u32::MAX`.
1031    /// - The `output` buffer is smaller than the `data` buffer.
1032    ///
1033    /// # Example
1034    ///
1035    /// ```
1036    /// use wolf_crypto::aead::{ChaCha20Poly1305};
1037    /// use wolf_crypto::mac::poly1305::Key;
1038    /// use wolf_crypto::MakeOpaque;
1039    ///
1040    /// let data = [42u8; 64];
1041    /// let mut out = [0u8; 64];
1042    /// let key = Key::new([0u8; 32]);
1043    /// let iv = [0u8; 12];
1044    ///
1045    /// let tag = ChaCha20Poly1305::new_encrypt(key.as_ref(), iv)
1046    ///     .update(&data, &mut out).unwrap()
1047    ///     .finalize();
1048    ///
1049    /// assert_ne!(out, data);
1050    ///
1051    /// let d_tag = ChaCha20Poly1305::new_decrypt(key, iv)
1052    ///     .update_in_place(&mut out).unwrap()
1053    ///     .finalize();
1054    ///
1055    /// assert_eq!(out, data);
1056    /// assert_eq!(tag, d_tag);
1057    /// ```
1058    pub fn update(mut self, data: &[u8], output: &mut [u8]) -> Result<ChaCha20Poly1305<S::Mode>, Self> {
1059        if Self::update_predicate(data, output) {
1060            unsafe { self.update_unchecked(data, output) };
1061            Ok(self.with_state())
1062        } else {
1063            Err(self)
1064        }
1065    }
1066
1067    io_impls! {
1068        /// Returns a `Data<S::Mode, IO>` struct which implements the `Read` trait for
1069        /// encrypting / decrypting data.
1070        ///
1071        /// This method allows for streaming data processing, which is useful when working
1072        /// with large amounts of data or I/O streams.
1073        ///
1074        /// # Arguments
1075        ///
1076        /// * `io`: An implementor of the `Read` trait. The data read from this `io` implementor
1077        ///   will be encrypted or decrypted depending on the mode of the ChaCha20Poly1305 instance.
1078        ///
1079        /// # Returns
1080        ///
1081        /// A `Data<S::Mode, IO>` struct that wraps the ChaCha20Poly1305 instance and the
1082        /// provided IO type.
1083        ///
1084        /// # Example
1085        ///
1086        /// ```
1087        /// use wolf_crypto::aead::chacha20_poly1305::{ChaCha20Poly1305, Key};
1088        /// use wolf_crypto::MakeOpaque;
1089        #[cfg_attr(all(feature = "embedded-io", not(feature = "std")), doc = "use embedded_io::Read;")]
1090        #[cfg_attr(feature = "std", doc = "use std::io::Read;")]
1091        ///
1092        #[cfg_attr(
1093            all(feature = "embedded-io", not(feature = "std")),
1094            doc = "# fn main() -> Result<(), wolf_crypto::Unspecified> {"
1095        )]
1096        #[cfg_attr(feature = "std", doc = "# fn main() -> Result<(), Box<dyn std::error::Error>> {")]
1097        /// let (key, iv) = (Key::new([7u8; 32]), [42; 12]);
1098        /// let plaintext = b"hello world";
1099        ///
1100        /// // Encrypt
1101        /// let mut encrypted = [0u8; 32];
1102        /// let mut encrypt_io = ChaCha20Poly1305::new_encrypt(key.as_ref(), iv)
1103        ///     .data_io(&plaintext[..]);
1104        /// let encrypted_len = encrypt_io.read(&mut encrypted)?;
1105        /// let (aead, _) = encrypt_io.finish();
1106        /// let tag = aead.finalize();
1107        ///
1108        /// // Decrypt
1109        /// let mut decrypted = [0u8; 32];
1110        /// let mut decrypt_io = ChaCha20Poly1305::new_decrypt(key, iv)
1111        ///     .data_io(&encrypted[..encrypted_len]);
1112        /// let decrypted_len = decrypt_io.read(&mut decrypted)?;
1113        /// let (aead, _) = decrypt_io.finish();
1114        /// let decrypted_tag = aead.finalize();
1115        ///
1116        /// assert_eq!(&decrypted[..decrypted_len], plaintext);
1117        /// assert_eq!(tag, decrypted_tag);
1118        /// # Ok(()) }
1119        /// ```
1120        pub const fn data_io<IO>(self, io: IO) -> IoData<S::Mode, IO> {
1121            io::Data::new(self.with_state(), io)
1122        }
1123    }
1124}
1125
1126impl<S: CanSetAad> ChaCha20Poly1305<S> {
1127    /// Sets the Additional Authenticated Data (AAD) for the AEAD operation.
1128    ///
1129    /// # Arguments
1130    ///
1131    /// * `aad` - The additional authenticated data to include in the authentication tag.
1132    ///
1133    /// # Example
1134    ///
1135    /// ```
1136    /// use wolf_crypto::aead::chacha20_poly1305::{ChaCha20Poly1305, Key};
1137    ///
1138    /// let key = Key::new([7u8; 32]);
1139    /// let iv = [42u8; 12];
1140    ///
1141    /// let aead = ChaCha20Poly1305::new_encrypt(key, iv)
1142    ///     .set_aad("additional data").unwrap();
1143    /// # drop(aead);
1144    /// ```
1145    ///
1146    /// # Errors
1147    ///
1148    /// If the length of the AAD is greater than `u32::MAX`.
1149    ///
1150    /// # Notes
1151    ///
1152    /// - The AAD contributes to the authentication tag but is not part of the encrypted output.
1153    /// - If you need to provide the AAD in multiple parts, consider using [`update_aad`] instead.
1154    ///
1155    /// [`update_aad`]: ChaCha20Poly1305::update_aad
1156    #[inline]
1157    pub fn set_aad<A: Aad>(
1158        mut self,
1159        aad: A
1160    ) -> Result<ChaCha20Poly1305<<S as CanSetAad>::Mode>, Self>
1161    {
1162        if aad.is_valid_size() {
1163            unsafe { self.update_aad_unchecked(aad); }
1164            Ok(self.with_state())
1165        } else {
1166            Err(self)
1167        }
1168    }
1169}
1170
1171impl<S: UpdatingAad> ChaCha20Poly1305<S> {
1172    /// Signals that no more Additional Authenticated Data (AAD) will be provided, transitioning the
1173    /// cipher to the data processing state.
1174    ///
1175    /// This method finalizes the AAD input phase. After calling `finish`, you may [`finalize`] the
1176    /// state machine, or begin updating the cipher with data to be encrypted / decrypted.
1177    ///
1178    /// # Example
1179    ///
1180    /// ```
1181    /// use wolf_crypto::aead::chacha20_poly1305::{ChaCha20Poly1305, Key};
1182    /// use wolf_crypto::MakeOpaque;
1183    ///
1184    /// let (key, iv) = (Key::new([7u8; 32]), [42; 12]);
1185    ///
1186    /// let tag = ChaCha20Poly1305::new_encrypt(key, iv)
1187    ///     .update_aad("additional ")
1188    ///     .opaque_bind(|aead| aead.update_aad("data"))
1189    ///     .opaque_bind(|aead| aead.update_aad("..."))
1190    ///     .opaque_map(|aead| aead.finish())
1191    ///      // (just use Poly1305 directly if you're doing this)
1192    ///     .opaque_map(|aead| aead.finalize()).unwrap();
1193    /// # assert_ne!(tag, wolf_crypto::aead::Tag::new_zeroed()); // no warnings
1194    /// ```
1195    ///
1196    /// [`finalize`]: ChaCha20Poly1305::finalize
1197    pub const fn finish(self) -> ChaCha20Poly1305<S::Mode> {
1198        self.with_state()
1199    }
1200
1201    /// Update the underlying message authentication code without encrypting the data or taking
1202    /// ownership of the [`ChaCha20Poly1305`] instance.
1203    ///
1204    /// This method is only available in the streaming state, making partial updates less of a
1205    /// hassle.
1206    ///
1207    /// # Arguments
1208    ///
1209    /// * `aad` - The additional authenticated data to include in the authentication [`Tag`].
1210    ///
1211    /// # Errors
1212    ///
1213    /// If the length of the AAD is greater than [`u32::MAX`].
1214    ///
1215    /// # Example
1216    ///
1217    /// ```
1218    /// use wolf_crypto::{aead::chacha20_poly1305::{ChaCha20Poly1305, Key}, MakeOpaque};
1219    ///
1220    /// # fn main() -> Result<(), wolf_crypto::Unspecified> {
1221    /// let tag = ChaCha20Poly1305::new_encrypt(Key::new([7u8; 32]), [42u8; 12])
1222    ///     .set_aad("hello world! Beautiful weather.")
1223    ///     .opaque_map(|aead| aead.finalize())?;
1224    ///
1225    /// let mut d_cipher = ChaCha20Poly1305::new_decrypt(Key::new([7u8; 32]), [42u8; 12])
1226    ///     .update_aad("hello world").opaque()?;
1227    ///
1228    /// // does not take ownership
1229    /// d_cipher.update_aad_streaming("! ")?;
1230    /// d_cipher.update_aad_streaming("Beautiful weather.")?;
1231    ///
1232    /// let d_tag = d_cipher.finish().finalize();
1233    ///
1234    /// assert_eq!(tag, d_tag);
1235    /// # Ok(()) }
1236    /// ```
1237    pub fn update_aad_streaming<A: Aad>(&mut self, aad: A) -> Result<(), Unspecified> {
1238        if aad.is_valid_size() {
1239            unsafe { self.update_aad_unchecked(aad); }
1240            Ok(())
1241        } else {
1242            Err(Unspecified)
1243        }
1244    }
1245}
1246
1247impl<S: Updating> ChaCha20Poly1305<S> {
1248    /// Finalizes the AEAD operation computing and returning the authentication [`Tag`].
1249    ///
1250    /// # Returns
1251    ///
1252    /// The authentication [`Tag`], resulting from the processed AAD and encryption / decryption
1253    /// operations.
1254    ///
1255    /// # Security
1256    ///
1257    /// On decryption, the returned [`Tag`] should be ensured to be equivalent to the [`Tag`]
1258    /// associated with the ciphertext. The decrypted ciphertext **should not be trusted** if
1259    /// the tags do not match.
1260    ///
1261    /// Also, the comparison should not be done outside the [`Tag`] type, you **must not** call
1262    /// `as_slice()` or anything for the comparison. **ALWAYS** leverage the [`Tag`]'s `PartialEq`
1263    /// implementation.
1264    ///
1265    /// # Example
1266    ///
1267    /// ```
1268    /// use wolf_crypto::aead::chacha20_poly1305::{ChaCha20Poly1305, Key};
1269    ///
1270    /// let key = Key::new([7u8; 32]);
1271    /// let iv = [42u8; 12];
1272    /// let mut data = [0u8; 64];
1273    ///
1274    /// let tag = ChaCha20Poly1305::new_encrypt(key.as_ref(), iv)
1275    ///     .set_aad("additional data").unwrap()
1276    ///     .update_in_place(&mut data).unwrap()
1277    ///     .finalize();
1278    ///
1279    /// // be sure to keep the tag around! important!
1280    ///
1281    /// // On decryption, we **must** ensure that the resulting tag matches
1282    /// // the provided tag.
1283    ///
1284    /// let d_tag = ChaCha20Poly1305::new_decrypt(key, iv)
1285    ///     .set_aad("additional data").unwrap()
1286    ///     .update_in_place(&mut data).unwrap()
1287    ///     .finalize();
1288    ///
1289    /// assert_eq!(data, [0u8; 64]);
1290    ///
1291    /// // most importantly!
1292    /// assert_eq!(tag, d_tag);
1293    /// ```
1294    #[inline]
1295    pub fn finalize(mut self) -> Tag {
1296        let mut tag = Tag::new_zeroed();
1297
1298        // INFALLIBLE
1299        //
1300        // The only way this function can fail is via the preconditions or an internal function
1301        // failing. All internal functions are infallible, as described in this crate's poly1305
1302        // commentary.
1303        //
1304        // The preconditions are as follows:
1305        //
1306        // - state == CHACHA20_POLY1305_STATE_AAD \/ state == CHACHA20_POLY1305_STATE_DATA
1307        // - aead != null /\ outAuthTag != null
1308        //
1309        // The inherited preconditions from the internal function calls are respected in the same
1310        // way that we respect them in the Poly1305 module, using the same types, et cetera.
1311
1312        unsafe {
1313            let _res = wc_ChaCha20Poly1305_Final(
1314                addr_of_mut!(self.inner),
1315                tag.as_mut_ptr()
1316            );
1317
1318            debug_assert_eq!(_res, 0);
1319        }
1320
1321        tag
1322    }
1323
1324    /// Encrypt / Decrypt the provided `in_out` data in-place without taking ownership of the AEAD
1325    /// instance.
1326    ///
1327    /// # Arguments
1328    ///
1329    /// * `in_out` - A mutable slice of data to be encrypted / decrypted in place.
1330    ///
1331    /// # Returns
1332    ///
1333    /// A reference to the updated `in_out` slice on success.
1334    ///
1335    /// # Errors
1336    ///
1337    /// Returns `Unspecified` if the length of `in_out` is greater than `u32::MAX`.
1338    ///
1339    /// # Example
1340    ///
1341    /// ```
1342    /// # use wolf_crypto::{aead::ChaCha20Poly1305, mac::poly1305::Key, MakeOpaque};
1343    /// #
1344    /// # fn main() -> Result<(), wolf_crypto::Unspecified> {
1345    /// # let mut in_out1 = [7u8; 42];
1346    /// # let mut in_out2 = [8u8; 42];
1347    /// # let key = Key::new([3u8; 32]);
1348    /// #
1349    /// let mut aead = ChaCha20Poly1305::new_encrypt(key.as_ref(), [7u8; 12])
1350    ///     .set_aad("hello world").opaque()?;
1351    ///
1352    /// aead.update_in_place_streaming(&mut in_out1)?;
1353    /// aead.update_in_place_streaming(&mut in_out2)?;
1354    ///
1355    /// let tag = aead.finalize();
1356    ///
1357    /// assert_ne!(in_out1, [7u8; 42]);
1358    /// assert_ne!(in_out2, [8u8; 42]);
1359    /// # Ok(()) }
1360    /// ```
1361    pub fn update_in_place_streaming<'io>(&mut self, in_out: &'io mut [u8]) -> Result<&'io mut [u8], Unspecified> {
1362        if can_cast_u32(in_out.len()) {
1363            unsafe { self.update_in_place_unchecked(in_out) };
1364            Ok(in_out)
1365        } else {
1366            Err(Unspecified)
1367        }
1368    }
1369
1370    /// Encrypt / Decrypt the provided `input` data into the `output` buffer without taking
1371    /// ownership of the AEAD instance.
1372    ///
1373    /// # Arguments
1374    ///
1375    /// * `input` - A slice of data to be encrypted / decrypted.
1376    /// * `output` - A mutable slice where the result will be written. It must be at least as large
1377    ///   as `input`.
1378    ///
1379    /// # Errors
1380    ///
1381    /// - The length of `input` is greater than `u32::MAX`.
1382    /// - The `output` buffer is smaller than the `input` buffer.
1383    ///
1384    /// # Example
1385    ///
1386    /// ```
1387    /// # use wolf_crypto::aead::{ChaCha20Poly1305};
1388    /// # use wolf_crypto::mac::poly1305::Key;
1389    /// # use wolf_crypto::MakeOpaque;
1390    /// #
1391    /// # fn main() -> Result<(), wolf_crypto::Unspecified> {
1392    /// # let data1 = [42u8; 32];
1393    /// # let data2 = [43u8; 32];
1394    /// # let mut out1 = [0u8; 32];
1395    /// # let mut out2 = [0u8; 32];
1396    /// # let key = Key::new([0u8; 32]);
1397    /// # let iv = [0u8; 12];
1398    /// #
1399    /// let mut aead = ChaCha20Poly1305::new_encrypt(key.as_ref(), iv)
1400    ///     .set_aad("additional data").opaque()?;
1401    ///
1402    /// aead.update_streaming(&data1, &mut out1)?;
1403    /// aead.update_streaming(&data2, &mut out2)?;
1404    ///
1405    /// let tag = aead.finalize();
1406    ///
1407    /// assert_ne!(out1, data1);
1408    /// assert_ne!(out2, data2);
1409    /// # Ok(()) }
1410    /// ```
1411    pub fn update_streaming(&mut self, input: &[u8], output: &mut [u8]) -> Result<(), Unspecified> {
1412        if Self::update_predicate(input, output) {
1413            unsafe { self.update_unchecked(input, output) };
1414            Ok(())
1415        } else {
1416            Err(Unspecified)
1417        }
1418    }
1419}
1420
1421#[cfg(test)]
1422mod tests {
1423    use crate::mac::poly1305::Key;
1424    use core::{
1425        slice,
1426    };
1427    use super::*;
1428
1429    #[test]
1430    fn type_state_machine() {
1431        let key = Key::new([0u8; 32]);
1432
1433        let mut cipher = [69, 69, 69, 69];
1434
1435        let tag = ChaCha20Poly1305::new::<Encrypt>(key.as_ref(), [0u8; 12])
1436            .set_aad(Some(Some(Some(())))).unwrap()
1437            .update_in_place(cipher.as_mut_slice()).unwrap()
1438            .finalize();
1439
1440        let new_tag = ChaCha20Poly1305::new::<Decrypt>(key.as_ref(), [0u8; 12])
1441            .set_aad(()).unwrap()
1442            .update_in_place(cipher.as_mut_slice()).unwrap()
1443            .finalize();
1444
1445        assert_eq!(tag, new_tag);
1446        assert_eq!(cipher, [69, 69, 69, 69]);
1447    }
1448
1449    macro_rules! bogus_slice {
1450        ($size:expr) => {{
1451            let src = b"hello world";
1452            unsafe { slice::from_raw_parts(src.as_ptr(), $size) }
1453        }};
1454    }
1455
1456    #[test]
1457    fn oneshot_size_predicate_fail() {
1458        // I am not allocating the maximum number for u32
1459        let slice = bogus_slice!(u32::MAX as usize + 1);
1460        let out = slice;
1461        assert!(!oneshot_predicate(slice, out, &()))
1462    }
1463
1464    #[test]
1465    fn oneshot_size_predicate() {
1466        let slice = bogus_slice!(u32::MAX as usize - 1);
1467        let out = slice;
1468        assert!(oneshot_predicate(slice, out, &()))
1469    }
1470
1471    #[test]
1472    fn oneshot_size_predicate_too_small_out() {
1473        let slice = bogus_slice!(u32::MAX as usize - 1);
1474        let out = bogus_slice!(u32::MAX as usize - 2);
1475        assert!(!oneshot_predicate(slice, out, &()));
1476    }
1477}
1478
1479#[cfg(test)]
1480mod property_tests {
1481    use super::*;
1482    use crate::aes::test_utils::{BoundList};
1483    use crate::buf::Nonce;
1484    use crate::mac::poly1305::Key;
1485    use proptest::{prelude::*, proptest};
1486
1487    proptest! {
1488        // these take some time. I ran with 50k cases once, but I cannot wait for these to pass
1489        // each time I run the tests.
1490        #![proptest_config(ProptestConfig::with_cases(5_000))]
1491
1492        #[test]
1493        fn bijectivity(
1494            input in any::<BoundList<1024>>(),
1495            key in any::<Key>(),
1496            iv in any::<Nonce>()
1497        ) {
1498            let mut output = input.create_self();
1499            let tag = ChaCha20Poly1305::new::<Encrypt>(key.as_ref(), iv.copy())
1500                .update(input.as_slice(), output.as_mut_slice()).unwrap()
1501                .finalize();
1502
1503            if output.len() >= 6 {
1504                prop_assert_ne!(output.as_slice(), input.as_slice());
1505            }
1506
1507            let mut decrypted = output.create_self();
1508            let d_tag = ChaCha20Poly1305::new::<Decrypt>(key.as_ref(), iv)
1509                .update(output.as_slice(), decrypted.as_mut_slice()).unwrap()
1510                .finalize();
1511
1512            prop_assert_eq!(tag, d_tag);
1513            prop_assert_eq!(decrypted.as_slice(), input.as_slice());
1514        }
1515
1516        #[test]
1517        fn bijectivity_with_aad(
1518            input in any::<BoundList<1024>>(),
1519            key in any::<Key>(),
1520            iv in any::<Nonce>(),
1521            aad in any::<Option<String>>()
1522        ) {
1523            let mut output = input.create_self();
1524            let tag = ChaCha20Poly1305::new::<Encrypt>(key.as_ref(), iv.copy())
1525                .set_aad(aad.as_ref()).unwrap()
1526                .update(input.as_slice(), output.as_mut_slice()).unwrap()
1527                .finalize();
1528
1529            if output.len() >= 6 {
1530                prop_assert_ne!(output.as_slice(), input.as_slice());
1531            }
1532
1533            let mut decrypted = output.create_self();
1534            let d_tag = ChaCha20Poly1305::new::<Decrypt>(key.as_ref(), iv)
1535                .set_aad(aad.as_ref()).unwrap()
1536                .update(output.as_slice(), decrypted.as_mut_slice()).unwrap()
1537                .finalize();
1538
1539            prop_assert_eq!(tag, d_tag);
1540            prop_assert_eq!(decrypted.as_slice(), input.as_slice());
1541        }
1542
1543        #[test]
1544        fn oneshot_bijectivity(
1545            input in any::<BoundList<1024>>(),
1546            key in any::<Key>(),
1547            iv in any::<Nonce>()
1548        ) {
1549            let mut output = input.create_self();
1550
1551            let tag = encrypt(
1552                key.as_ref(), iv.copy(),
1553                input.as_slice(), output.as_mut_slice(),
1554                ()
1555            ).unwrap();
1556
1557            if output.len() >= 6 {
1558                prop_assert_ne!(output.as_slice(), input.as_slice());
1559            }
1560
1561            let mut decrypted = output.create_self();
1562            prop_assert!(decrypt(
1563                key.as_ref(), iv,
1564                output.as_slice(), decrypted.as_mut_slice(),
1565                (), tag
1566            ).is_ok());
1567
1568            prop_assert_eq!(input.as_slice(), decrypted.as_slice());
1569        }
1570
1571        #[test]
1572        fn oneshot_bijectivity_with_aad(
1573            input in any::<BoundList<1024>>(),
1574            key in any::<Key>(),
1575            iv in any::<Nonce>(),
1576            aad in any::<Option<String>>()
1577        ) {
1578            let mut output = input.create_self();
1579
1580            let tag = encrypt(
1581                key.as_ref(), iv.copy(),
1582                input.as_slice(), output.as_mut_slice(),
1583                aad.as_ref()
1584            ).unwrap();
1585
1586            if output.len() >= 6 {
1587                prop_assert_ne!(output.as_slice(), input.as_slice());
1588            }
1589
1590            let mut decrypted = output.create_self();
1591            prop_assert!(decrypt(
1592                key.as_ref(), iv,
1593                output.as_slice(), decrypted.as_mut_slice(),
1594                aad.as_ref(), tag
1595            ).is_ok());
1596
1597            prop_assert_eq!(input.as_slice(), decrypted.as_slice());
1598        }
1599    }
1600}