wolf_crypto/mac/poly1305/
mod.rs

1//! The `Poly1305` Message Authentication Code
2//!
3//! ```
4//! use wolf_crypto::mac::{Poly1305, poly1305::Key};
5//!
6//! # fn main() -> Result<(), wolf_crypto::Unspecified> {
7//! let key = Key::new([0u8; 32]);
8//!
9//! let tag = Poly1305::new(key.as_ref())
10//!     .aead_padding()
11//!     .update(b"hello world")?
12//!     .finalize();
13//!
14//! let o_tag = Poly1305::new(key)
15//!     .mac(b"Different message", ()).unwrap();
16//!
17//! assert_eq!(
18//!     tag, o_tag,
19//!     "All of our coefficients are zero!"
20//! );
21//!
22//! let key = Key::new([42u8; 32]);
23//!
24//! let tag = Poly1305::new(key.as_ref())
25//!     .aead_padding_ct()
26//!     .update_ct(b"thankfully this ")
27//!     .update_ct(b"is only the case ")
28//!     .update_ct(b"with a key of all zeroes.")
29//!     .finalize(/* errors are accumulated in constant-time, so we handle them here */)?;
30//!
31//! let o_tag = Poly1305::new(key.as_ref())
32//!     .mac(b"thankfully this is only the case with a key of all zeroes.", ())?;
33//!
34//! assert_eq!(tag, o_tag);
35//!
36//! let bad_tag = Poly1305::new(key)
37//!     .update(b"This tag will not be the same.")?
38//!     .finalize();
39//!
40//! assert_ne!(bad_tag, tag);
41//! # Ok(()) }
42//! ```
43//!
44//! ## Note
45//!
46//! The first test may be concerning, it is not. `Poly1305` was originally designed to be
47//! [paired with `AES`][1], this example only would take place if the cipher it is paired with
48//! is fundamentally broken. More explicitly, the cipher would need to be an identity function for
49//! the first 32 bytes, meaning not encrypt the first 32 bytes in any way shape or form.
50//!
51//! The author of `Poly1305` ([Daniel J. Bernstein][2]) also created [`Salsa20` (`Snuffle 2005`)][3],
52//! and then [`ChaCha`][4], which `Poly1305` generally complements for authentication.
53//!
54//! ## Security
55//!
56//! `Poly1305` is meant to be used with a **one-time key**, key reuse in `Poly1305` can be
57//! devastating. When pairing with something like [`ChaCha20Poly1305`] this requirement is handled
58//! via the discreteness of the initialization vector (more reason to never reuse initialization
59//! vectors).
60//!
61//! If you are using `Poly1305` directly, each discrete message you authenticate must leverage
62//! fresh key material.
63//!
64//! [1]: https://cr.yp.to/mac/poly1305-20050329.pdf
65//! [2]: https://cr.yp.to/djb.html
66//! [3]: https://cr.yp.to/snuffle.html
67//! [4]: https://cr.yp.to/chacha/chacha-20080128.pdf
68//! [`ChaCha20Poly1305`]: crate::aead::ChaCha20Poly1305
69
70use wolf_crypto_sys::{
71    Poly1305 as wc_Poly1305,
72    wc_Poly1305SetKey, wc_Poly1305Update, wc_Poly1305Final,
73    wc_Poly1305_Pad, wc_Poly1305_EncodeSizes,
74    wc_Poly1305_MAC
75};
76
77mod key;
78pub mod state;
79
80pub use key::{GenericKey, Key, KeyRef, KEY_SIZE};
81use key::KEY_SIZE_U32;
82
83use core::mem::MaybeUninit;
84use core::ptr::addr_of_mut;
85use state::{Poly1305State, Init, Ready, Streaming};
86use crate::opaque_res::Res;
87use crate::{can_cast_u32, to_u32, Unspecified};
88use core::marker::PhantomData;
89use crate::aead::{Aad, Tag};
90use crate::ct;
91
92// INFALLIBILITY COMMENTARY
93//
94// — poly1305_blocks
95//
96// SRC: https://github.com/wolfSSL/wolfssl/blob/master/wolfcrypt/src/poly1305.c#L277
97//
98// Only can fail under SMALL_STACK /\ W64WRAPPER via OOM. We do not enable either of these
99// features, and both must be enabled for this to be fallible.
100//
101// — poly1305_block
102//
103// SRC: https://github.com/wolfSSL/wolfssl/blob/master/wolfcrypt/src/poly1305.c#L483
104//
105// Returns 0 OR returns the result of poly1305_blocks. Which again is infallible unless the
106// aforementioned features are both enabled.
107//
108// — wc_Poly1305SetKey
109//
110// SRC: https://github.com/wolfSSL/wolfssl/blob/master/wolfcrypt/src/poly1305.c#L496
111//
112// Only can fail if these preconditions are not met:
113//
114//   key != null /\ KeySz == 32 /\ ctx != null
115//
116// Which our types guarantee this is satisfied.
117//
118// — wc_Poly1305Final
119//
120// SRC: https://github.com/wolfSSL/wolfssl/blob/master/wolfcrypt/src/poly1305.c#L584
121//
122// Only can fail if these preconditions are not met:
123//
124//   ctx != null /\ mac != null
125//
126// With an implicit, unchecked precondition (observed in the wc_Poly1305_MAC function)
127//
128//   macSz == 16
129//
130// Which, again, our types guarantee this precondition is satisfied.
131//
132// — wc_Poly1305Update
133//
134// SRC: https://github.com/wolfSSL/wolfssl/blob/master/wolfcrypt/src/poly1305.c#L794
135//
136// This depends on the infallibility of poly1305_blocks, which we have already showed
137// is infallible.
138//
139// So, this can only fail if the following preconditions are not met:
140//
141//  ctx != null /\ (bytes > 0 -> bytes != null)
142//
143// Which again, our types guarantee this is satisfied.
144//
145// — wc_Poly1305_Pad (invoked in finalize)
146//
147// SRC: https://github.com/wolfSSL/wolfssl/blob/master/wolfcrypt/src/poly1305.c#L913
148//
149// This depends on the success of wc_Poly1305Update, which we have already shown to be
150// infallible.
151//
152// This is only fallible if the provided ctx is null, which again our types are not
153// able to represent.
154//
155// Regarding the wc_Poly1305Update invocation, this is clearly infallible.
156//
157// We have this:
158//   paddingLen = (-(int)lenToPad) & (WC_POLY1305_PAD_SZ - 1);
159//
160// Where they are just computing the compliment of lenToPad, masking it against 15, which gives
161// us the offset to 16 byte alignment.
162// For example, let's say our length to pad is 13 (for ease of reading over a single octet):
163//   13 to -13     (00001101 to 11110011)
164//   -13 & 15 to 3 (11110011 & 00001111 to 00000011)
165//
166// For all values, this will never exceed 15 bytes, which is what is the amount of padding living
167// on the stack. Again, this usage of wc_Poly1305Update is clearly infallible with our
168// configuration.
169//
170// — wc_Poly1305_EncodeSizes (invoked in finalize)
171//
172// SRC: https://github.com/wolfSSL/wolfssl/blob/master/wolfcrypt/src/poly1305.c#L941
173//
174// Similar to wc_Poly1305_Pad, this depends on the infallibility of wc_Poly1305Update. Which again,
175// in this circumstance is infallible. The usage within this function is infallible with our
176// configuration of wolfcrypt. The only precondition again is ctx being non-null, which again
177// is guaranteed via our types.
178//
179// — wc_Poly1305_MAC
180//
181// SRC: https://github.com/wolfSSL/wolfssl/blob/master/wolfcrypt/src/poly1305.c#L995
182//
183// Building on the above commentary, this is infallible as well.
184//
185// We have the precondition:
186//
187//   ctx != null /\ input != null /\ tag != null /\ tagSz >= 16
188//     /\ (additionalSz != 0 -> additional != null)
189//
190// Which again, our types ensure that this is satisfied.
191//   #1 ctx must not be null as we would never be able to invoke this function otherwise.
192//   #2 input must not be null, this is guaranteed via Rust's type system.
193//   #3 Our Tag type is never null, and the size of Tag is always 16/
194//   #4 Our Aad trait ensures that if the size is non-zero that the ptr method never returns a
195//      null pointer.
196//
197// END COMMENTARY
198
199
200/// The `Poly1305` Message Authentication Code (MAC)
201///
202/// # Example
203///
204/// ```
205/// use wolf_crypto::{mac::{Poly1305, poly1305::Key}, aead::Tag};
206///
207/// let key: Key = [7u8; 32].into();
208///
209/// let tag = Poly1305::new(key.as_ref())
210///     .aead_padding_ct()
211///     .update_ct(b"hello world")
212///     .update_ct(b", how are you")
213///     .finalize()
214///     .unwrap();
215///
216/// let o_tag = Poly1305::new(key.as_ref())
217///     .mac(b"hello world, how are you", b"")
218///     .unwrap();
219///
220/// assert_eq!(tag, o_tag);
221/// ```
222#[repr(transparent)]
223pub struct Poly1305<State: Poly1305State = Init> {
224    inner: wc_Poly1305,
225    _state: PhantomData<State>
226}
227
228impl<State: Poly1305State> From<Poly1305<State>> for Unspecified {
229    #[inline]
230    fn from(_value: Poly1305<State>) -> Self {
231        Self
232    }
233}
234
235opaque_dbg! { Poly1305 }
236
237impl Poly1305<Init> {
238    /// Creates a new `Poly1305` instance with the provided key.
239    ///
240    /// # Arguments
241    ///
242    /// * `key` - The secret key material used for MAC computation.
243    ///
244    /// # Example
245    ///
246    /// ```
247    /// use wolf_crypto::mac::{Poly1305, poly1305::Key};
248    ///
249    /// let key: Key = [42u8; 32].into();
250    /// let poly = Poly1305::new(key.as_ref());
251    /// ```
252    pub fn new<K: GenericKey>(key: K) -> Poly1305<Ready> {
253        let mut poly1305 = MaybeUninit::<wc_Poly1305>::uninit();
254
255        unsafe {
256            // infallible, see commentary at start of file.
257            let _res = wc_Poly1305SetKey(
258                poly1305.as_mut_ptr(),
259                key.ptr(),
260                KEY_SIZE_U32
261            );
262
263            debug_assert_eq!(_res, 0);
264
265            Poly1305::<Ready> {
266                inner: poly1305.assume_init(),
267                _state: PhantomData
268            }
269        }
270    }
271}
272
273impl<State: Poly1305State> Poly1305<State> {
274    /// Transitions the `Poly1305` instance to a new state.
275    ///
276    /// # Type Parameters
277    ///
278    /// * `N` - The new state type.
279    ///
280    /// # Returns
281    ///
282    /// A `Poly1305` instance in the new state.
283    #[inline]
284    const fn with_state<N: Poly1305State>(self) -> Poly1305<N> {
285        unsafe { core::mem::transmute(self) }
286    }
287
288    /// Updates the `Poly1305` instance with additional input without performing checks.
289    ///
290    /// # Safety
291    ///
292    /// The length of the input must not be truncated / overflow a `u32`.
293    ///
294    /// # Arguments
295    ///
296    /// * `input` - A byte slice representing the data to include in the MAC computation.
297    #[inline]
298    unsafe fn update_unchecked(&mut self, input: &[u8]) {
299        // infallible, see commentary at beginning of file.
300        let _res = wc_Poly1305Update(
301            addr_of_mut!(self.inner),
302            input.as_ptr(),
303            input.len() as u32
304        );
305
306        debug_assert_eq!(_res, 0);
307    }
308}
309
310impl Poly1305<Ready> {
311    /// Computes the MAC for the given input and additional data without performing input length checks.
312    ///
313    /// # Safety
314    ///
315    /// Both the `input` and `additional` arguments length must be less than `u32::MAX`.
316    ///
317    /// # Arguments
318    ///
319    /// * `input` - A byte slice representing the message to authenticate.
320    /// * `additional` - A byte slice representing optional additional authenticated data (AAD).
321    ///
322    /// # Returns
323    ///
324    /// The associated authentication tag.
325    unsafe fn mac_unchecked<A: Aad>(mut self, input: &[u8], aad: A) -> Tag {
326        debug_assert!(can_cast_u32(input.len()));
327        debug_assert!(aad.is_valid_size());
328
329        let mut tag = Tag::new_zeroed();
330
331        // Infallible, see final section of commentary at beginning of file.
332        let _res = wc_Poly1305_MAC(
333            addr_of_mut!(self.inner),
334            aad.ptr(),
335            aad.size(),
336            input.as_ptr(),
337            input.len() as u32,
338            tag.as_mut_ptr(),
339            Tag::SIZE
340        );
341
342        assert_eq!(_res, 0);
343
344        debug_assert_eq!(_res, 0);
345
346        tag
347    }
348
349    /// Computes the MAC for the given input and additional data. This uses the TLS AEAD padding
350    /// scheme. If this is undesirable, consider calling `update` followed by `finalize` manually.
351    ///
352    /// # Arguments
353    ///
354    /// * `input` - A byte slice representing the message to authenticate.
355    /// * `aad` - Any additional authenticated data.
356    ///
357    /// # Returns
358    ///
359    /// The associated authentication tag.
360    ///
361    /// # Errors
362    ///
363    /// - The length of the `aad` is greater than [`u32::MAX`].
364    /// - The length of the `input` is greater than [`u32::MAX`].
365    ///
366    /// # Example
367    ///
368    /// ```
369    /// use wolf_crypto::{mac::{Poly1305, poly1305::Key}, aead::Tag};
370    ///
371    /// let key: Key = [42u8; 32].into();
372    /// let tag = Poly1305::new(key.as_ref())
373    ///     .mac(b"message", b"aad")
374    ///     .unwrap();
375    /// # assert_ne!(tag, Tag::new_zeroed());
376    /// ```
377    #[inline]
378    pub fn mac<A: Aad>(self, input: &[u8], aad: A) -> Result<Tag, Unspecified> {
379        if can_cast_u32(input.len()) && aad.is_valid_size() {
380            Ok(unsafe { self.mac_unchecked(input, aad) })
381        } else {
382            Err(Unspecified)
383        }
384    }
385
386    /// Transitions the `Poly1305` instance into the streaming state with the TLS AEAD padding
387    /// scheme.
388    ///
389    /// # Returns
390    ///
391    /// A [`StreamPoly1305Aead`] instance for continued updates.
392    ///
393    /// # Example
394    ///
395    /// ```
396    /// use wolf_crypto::{mac::{Poly1305, poly1305::Key}, aead::Tag};
397    ///
398    /// # fn main() -> Result<(), wolf_crypto::Unspecified> {
399    /// let key: Key = [42u8; 32].into();
400    /// let stream = Poly1305::new(key.as_ref())
401    ///     .aead_padding()
402    ///     .update(b"chunk1")?
403    ///     .update(b"chunk2")?;
404    /// # Ok(()) }
405    /// ```
406    pub const fn aead_padding(self) -> StreamPoly1305Aead {
407        StreamPoly1305Aead::from_parts(self.with_state(), 0)
408    }
409
410    /// Transitions the `Poly1305` instance into the streaming state.
411    ///
412    /// # Returns
413    ///
414    /// A [`StreamPoly1305`] instance for continued updates.
415    ///
416    /// # Example
417    ///
418    /// ```
419    /// use wolf_crypto::{mac::{Poly1305, poly1305::Key}, aead::Tag};
420    ///
421    /// # fn main() -> Result<(), wolf_crypto::Unspecified> {
422    /// let key: Key = [42u8; 32].into();
423    /// let stream = Poly1305::new(key.as_ref()).normal()
424    ///     .update(b"chunk1")?
425    ///     .update(b"chunk2")?;
426    /// # Ok(()) }
427    /// ```
428    pub const fn normal(self) -> StreamPoly1305 {
429        StreamPoly1305::from_parts(self.with_state(), 0)
430    }
431
432    /// Transitions the `Poly1305` instance into the streaming state with the TLS AEAD padding
433    /// scheme.
434    ///
435    /// The distinction between this and the standard [`aead_padding`] is that this accumulates
436    /// errors up until the point of finalization in constant time.
437    ///
438    /// # Returns
439    ///
440    /// A [`CtPoly1305Aead`] instance for continued updates.
441    ///
442    /// # Example
443    ///
444    /// ```
445    /// use wolf_crypto::{mac::{Poly1305, poly1305::Key}, aead::Tag};
446    ///
447    /// # fn main() -> Result<(), wolf_crypto::Unspecified> {
448    /// let key: Key = [42u8; 32].into();
449    /// let stream = Poly1305::new(key.as_ref())
450    ///     .aead_padding_ct()
451    ///     .update_ct(b"chunk1")
452    ///     .update_ct(b"chunk2");
453    /// # Ok(()) }
454    /// ```
455    ///
456    /// [`aead_padding`]: Self::aead_padding
457    pub const fn aead_padding_ct(self) -> CtPoly1305Aead {
458        CtPoly1305Aead::from_parts(self.with_state(), Res::OK, 0)
459    }
460
461    /// Transitions the `Poly1305` instance into the streaming state.
462    ///
463    /// The distinction between this and the standard [`normal`] is that this accumulates
464    /// errors up until the point of finalization in constant time.
465    ///
466    /// # Returns
467    ///
468    /// A [`CtPoly1305`] instance for continued updates.
469    ///
470    /// # Example
471    ///
472    /// ```
473    /// use wolf_crypto::{mac::{Poly1305, poly1305::Key}, aead::Tag};
474    ///
475    /// # fn main() -> Result<(), wolf_crypto::Unspecified> {
476    /// let key: Key = [42u8; 32].into();
477    /// let stream = Poly1305::new(key.as_ref()).normal_ct()
478    ///     .update_ct(b"chunk1")
479    ///     .update_ct(b"chunk2");
480    /// # Ok(()) }
481    /// ```
482    ///
483    /// [`normal`]: Self::normal
484    pub const fn normal_ct(self) -> CtPoly1305 {
485        CtPoly1305::from_parts(self.with_state(), Res::OK, 0)
486    }
487
488    /// Updates the `Poly1305` instance with additional input, transitioning it to a streaming
489    /// state.
490    ///
491    /// # Arguments
492    ///
493    /// * `input` - A byte slice representing the data to include in the MAC computation.
494    ///
495    /// # Returns
496    ///
497    /// A `StreamPoly1305` instance for continued updates.
498    ///
499    /// # Errors
500    ///
501    /// If the length of `input` is greater than [`u32::MAX`].
502    ///
503    /// # Example
504    ///
505    /// ```
506    /// use wolf_crypto::{mac::{Poly1305, poly1305::Key}, aead::Tag};
507    ///
508    /// # fn main() -> Result<(), wolf_crypto::Unspecified> {
509    /// let key: Key = [42u8; 32].into();
510    /// let stream = Poly1305::new(key.as_ref())
511    ///     .update(b"chunk1")?
512    ///     .update(b"chunk2")?;
513    /// # Ok(()) }
514    /// ```
515    #[inline]
516    pub fn update(mut self, input: &[u8]) -> Result<StreamPoly1305, Unspecified> {
517        to_u32(input.len()).map_or(
518            Err(Unspecified),
519            |len| unsafe {
520                self.update_unchecked(input);
521                Ok(StreamPoly1305::from_parts(self.with_state(), len))
522            }
523        )
524    }
525
526    /// Updates the `Poly1305` instance with additional input in a constant-time manner.
527    ///
528    /// # Arguments
529    ///
530    /// * `input` - A byte slice representing the data to include in the MAC computation.
531    ///
532    /// # Returns
533    ///
534    /// A `CtPoly1305` instance containing the updated state.
535    ///
536    /// # Example
537    ///
538    /// ```
539    /// use wolf_crypto::{mac::{Poly1305, poly1305::Key}, aead::Tag};
540    ///
541    /// let key: Key = [42u8; 32].into();
542    /// let tag = Poly1305::new(key.as_ref())
543    ///     .update_ct(b"sensitive ")
544    ///     .update_ct(b"chunks")
545    ///     .finalize()
546    ///     .unwrap();
547    ///
548    /// let o_tag = Poly1305::new(key.as_ref())
549    ///     .update_ct(b"sensitive chunks")
550    ///     .finalize().unwrap();
551    ///
552    /// assert_eq!(tag, o_tag);
553    /// ```
554    pub fn update_ct(mut self, input: &[u8]) -> CtPoly1305 {
555        let (adjusted, res) = adjust_slice(input);
556        unsafe { self.update_unchecked(adjusted) };
557        // adjusted length will always be below u32::MAX
558        CtPoly1305::from_parts(self.with_state(), res, adjusted.len() as u32)
559    }
560}
561
562/// Finalizes the `Poly1305` MAC computation using the TLS AEAD padding scheme.
563///
564/// # Arguments
565///
566/// * `poly` - The `Poly1305` instance.
567/// * `accum_len` - The accumulated length of the input data.
568///
569/// # Returns
570///
571/// The associated authentication [`Tag`].
572#[inline]
573fn finalize_aead<S: Poly1305State>(mut poly: Poly1305<S>, accum_len: u32) -> Tag {
574    // Regarding fallibility for all functions invoked, and debug_asserted to have succeeded,
575    // see the commentary at the beginning of the document.
576    unsafe {
577        let _res = wc_Poly1305_Pad(
578            addr_of_mut!(poly.inner),
579            accum_len
580        );
581
582        debug_assert_eq!(_res, 0);
583
584        let _res = wc_Poly1305_EncodeSizes(
585            addr_of_mut!(poly.inner),
586            0u32,
587            accum_len
588        );
589
590        debug_assert_eq!(_res, 0);
591
592        finalize_no_pad(poly)
593    }
594}
595
596/// Finalizes the `Poly1305` MAC computation with padding.
597///
598/// # Arguments
599///
600/// * `poly` - The `Poly1305` instance.
601/// * `to_pad` - Either the length of the input, or the accumulated output of [`update_to_pad`].
602///
603/// # Returns
604///
605/// The associated authentication [`Tag`].
606#[inline]
607fn finalize<S: Poly1305State>(mut poly: Poly1305<S>, to_pad: u32) -> Tag {
608    unsafe {
609        let _res = wc_Poly1305_Pad(
610            addr_of_mut!(poly.inner),
611            to_pad
612        );
613
614        debug_assert_eq!(_res, 0);
615
616        finalize_no_pad(poly)
617    }
618}
619
620/// Finalizes the `Poly1305` MAC computation without padding.
621///
622/// # Arguments
623///
624/// * `poly` - The `Poly1305` instance.
625///
626/// # Returns
627///
628/// The associated authentication [`Tag`].
629#[inline]
630fn finalize_no_pad<S: Poly1305State>(mut poly: Poly1305<S>) -> Tag {
631    unsafe {
632        let mut tag = Tag::new_zeroed();
633
634        let _res = wc_Poly1305Final(
635            addr_of_mut!(poly.inner),
636            tag.as_mut_ptr()
637        );
638
639        debug_assert_eq!(_res, 0);
640
641        tag
642    }
643}
644
645#[inline(always)]
646#[must_use]
647const fn update_to_pad(to_pad: u8, new_len: u32) -> u8 {
648    // this is the same as (num + num) & 15, where num is a number of any possible size, not bound
649    // to a concrete type like u32.
650
651    // With wolfcrypt's padding algorithm this will always result in the same output as providing
652    // the total length. See kani verification at the bottom of the file.
653    to_pad.wrapping_add((new_len & 15) as u8) & 15
654}
655
656/// Represents an ongoing streaming MAC computation, allowing incremental updates.
657///
658/// This uses the TLS AEAD padding scheme.
659///
660/// # Example
661///
662/// ```
663/// use wolf_crypto::{mac::{Poly1305, poly1305::Key}, aead::Tag};
664///
665/// # fn main() -> Result<(), wolf_crypto::Unspecified> {
666/// let key: Key = [42u8; 32].into();
667/// let tag = Poly1305::new(key.as_ref())
668///     .aead_padding()
669///     .update(b"chunk1")?
670///     .update(b"chunk2")?
671///     .update(b"chunk3")?
672///     .finalize();
673/// # Ok(()) }
674/// ```
675pub struct StreamPoly1305Aead {
676    poly1305: Poly1305<Streaming>,
677    accum_len: u32
678}
679
680impl From<StreamPoly1305Aead> for Unspecified {
681    #[inline]
682    fn from(value: StreamPoly1305Aead) -> Self {
683        value.poly1305.into()
684    }
685}
686
687opaque_dbg! { StreamPoly1305Aead }
688
689impl StreamPoly1305Aead {
690    /// Creates a new `StreamPoly1305` instance from its parts.
691    ///
692    /// # Arguments
693    ///
694    /// * `poly1305` - The `Poly1305` instance in the `Streaming` state.
695    /// * `accum_len` - The accumulated length of the input data.
696    ///
697    /// # Returns
698    ///
699    /// A new `StreamPoly1305` instance.
700    const fn from_parts(poly1305: Poly1305<Streaming>, accum_len: u32) -> Self {
701        Self { poly1305, accum_len }
702    }
703
704    /// Increments the accumulated length with the provided length.
705    ///
706    /// # Arguments
707    ///
708    /// * `len` - The length to add to the accumulator.
709    ///
710    /// # Returns
711    ///
712    /// A `Res` indicating the success or failure of the operation.
713    #[inline(always)]
714    fn incr_accum(&mut self, len: u32) -> Res {
715        let (accum_len, res) = ct::add_no_wrap(self.accum_len, len);
716        self.accum_len = accum_len;
717        res
718    }
719
720    /// Updates the streaming MAC computation with additional input.
721    ///
722    /// # Arguments
723    ///
724    /// * `input` - A byte slice representing the additional data to include.
725    ///
726    /// # Errors
727    ///
728    /// - The length of the `input` was greater than [`u32::MAX`].
729    /// - The total length that has been processed is greater than [`u32::MAX`],
730    ///
731    /// # Example
732    ///
733    /// ```
734    /// use wolf_crypto::{mac::{Poly1305, poly1305::Key}, aead::Tag};
735    ///
736    /// # fn main() -> Result<(), wolf_crypto::Unspecified> {
737    /// let key: Key = [42u8; 32].into();
738    ///
739    /// let tag = Poly1305::new(key.as_ref())
740    ///     .aead_padding()
741    ///     .update(b"chunk1")?
742    ///     .update(b"chunk2")?
743    ///     .update(b"chunk3")?
744    ///     .finalize();
745    /// # Ok(()) }
746    /// ```
747    pub fn update(mut self, input: &[u8]) -> Result<Self, Self> {
748        if let Some(input_len) = to_u32(input.len()) {
749            into_result!(self.incr_accum(input_len),
750                ok => {
751                    // We MUST only invoke this AFTER knowing that the incr_accum succeeded.
752                    // incr_accum uses the ct_add_no_wrap function, which may sound like it performs
753                    // some form of saturating addition, but it does not. If the operation would
754                    // overflow, no addition would take place. So, we can return self under the
755                    // error case, and the state will not be corrupted.
756                    unsafe { self.poly1305.update_unchecked(input) };
757                    self
758                },
759                err => self
760            )
761        } else {
762            Err(self)
763        }
764    }
765
766    /// Finalizes the streaming MAC computation and returns the resulting `Tag`.
767    ///
768    /// # Returns
769    ///
770    /// The associated authentication [`Tag`].
771    ///
772    /// # Example
773    ///
774    /// ```
775    /// use wolf_crypto::{mac::{Poly1305, poly1305::Key}, aead::Tag};
776    ///
777    /// # fn main() -> Result<(), wolf_crypto::Unspecified> {
778    /// let key: Key = [42u8; 32].into();
779    ///
780    /// let tag = Poly1305::new(key.as_ref())
781    ///     .aead_padding()
782    ///     .update(b"chunk1")?
783    ///     .update(b"chunk2")?
784    ///     .update(b"chunk3")?
785    ///     .finalize();
786    /// # Ok(()) }
787    /// ```
788    pub fn finalize(self) -> Tag {
789        finalize_aead(self.poly1305, self.accum_len)
790    }
791}
792
793/// Represents an ongoing streaming MAC computation, allowing incremental updates.
794///
795/// # Example
796///
797/// ```
798/// use wolf_crypto::{mac::{Poly1305, poly1305::Key}, aead::Tag};
799///
800/// # fn main() -> Result<(), wolf_crypto::Unspecified> {
801/// let key: Key = [42u8; 32].into();
802/// let tag = Poly1305::new(key.as_ref())
803///     .update(b"chunk1")?
804///     .update(b"chunk2")?
805///     .update(b"chunk3")?
806///     .finalize();
807/// # Ok(()) }
808/// ```
809pub struct StreamPoly1305 {
810    poly1305: Poly1305<Streaming>,
811    to_pad: u8
812}
813
814impl From<StreamPoly1305> for Unspecified {
815    #[inline]
816    fn from(value: StreamPoly1305) -> Self {
817        value.poly1305.into()
818    }
819}
820
821opaque_dbg! { StreamPoly1305 }
822
823impl StreamPoly1305 {
824    /// Creates a new `StreamPoly1305` instance from its parts.
825    ///
826    /// # Arguments
827    ///
828    /// * `poly1305` - The `Poly1305` instance in the `Streaming` state.
829    /// * `accum_len` - The accumulated length of the input data.
830    ///
831    /// # Returns
832    ///
833    /// A new `StreamPoly1305` instance.
834    const fn from_parts(poly1305: Poly1305<Streaming>, len: u32) -> Self {
835        Self { poly1305, to_pad: update_to_pad(0, len) }
836    }
837
838    /// Updates the streaming MAC computation with additional input.
839    ///
840    /// # Arguments
841    ///
842    /// * `input` - A byte slice representing the additional data to include.
843    ///
844    /// # Errors
845    ///
846    /// The length of the `input` was greater than [`u32::MAX`].
847    ///
848    /// # Example
849    ///
850    /// ```
851    /// use wolf_crypto::{mac::{Poly1305, poly1305::Key}, aead::Tag};
852    ///
853    /// # fn main() -> Result<(), wolf_crypto::Unspecified> {
854    /// let key: Key = [42u8; 32].into();
855    ///
856    /// let tag = Poly1305::new(key.as_ref())
857    ///     .update(b"chunk1")?
858    ///     .update(b"chunk2")?
859    ///     .update(b"chunk3")?
860    ///     .finalize();
861    /// # Ok(()) }
862    /// ```
863    pub fn update(mut self, input: &[u8]) -> Result<Self, Self> {
864        if let Some(len) = to_u32(input.len()) {
865            self.to_pad = update_to_pad(self.to_pad, len);
866            unsafe { self.poly1305.update_unchecked(input) };
867            Ok(self)
868        } else {
869            Err(self)
870        }
871    }
872
873    /// Finalizes the streaming MAC computation and returns the resulting `Tag`.
874    ///
875    /// # Returns
876    ///
877    /// The associated authentication [`Tag`].
878    ///
879    /// # Example
880    ///
881    /// ```
882    /// use wolf_crypto::{mac::{Poly1305, poly1305::Key}, aead::Tag};
883    ///
884    /// # fn main() -> Result<(), wolf_crypto::Unspecified> {
885    /// let key: Key = [42u8; 32].into();
886    ///
887    /// let tag = Poly1305::new(key.as_ref())
888    ///     .update(b"chunk1")?
889    ///     .update(b"chunk2")?
890    ///     .update(b"chunk3")?
891    ///     .finalize();
892    /// # Ok(()) }
893    /// ```
894    #[inline]
895    pub fn finalize(self) -> Tag {
896        finalize(self.poly1305, self.to_pad as u32)
897    }
898
899    /// Finalizes the constant-time streaming MAC computation and returns the resulting `Tag`.
900    ///
901    /// # Note
902    ///
903    /// It is far more common in practice to use to pad the [`finalize`] method. This is only here
904    /// for `XSalsa20Poly1305`.
905    ///
906    /// # Returns
907    ///
908    /// The associated authentication [`Tag`] representing all updates and the total length of the
909    /// updates.
910    ///
911    /// # Example
912    ///
913    /// ```
914    /// use wolf_crypto::{mac::{Poly1305, poly1305::Key}, aead::Tag};
915    ///
916    /// let key: Key = [42u8; 32].into();
917    /// let tag = Poly1305::new(key.as_ref())
918    ///     .update(b"chunk1").unwrap()
919    ///     .update(b"chunk2").unwrap()
920    ///     .finalize_no_padding();
921    /// ```
922    ///
923    /// [`finalize`]: Self::finalize
924    #[inline]
925    pub fn finalize_no_padding(self) -> Tag {
926        finalize_no_pad(self.poly1305)
927    }
928}
929
930/// Provides a constant-time interface for updating the MAC computation, enhancing resistance
931/// against side-channel attacks.
932///
933/// This uses the recent TLS AEAD padding scheme on finalization, if this is not desired see
934/// [`CtPoly1305`].
935///
936/// # Example
937///
938/// ```
939/// use wolf_crypto::{mac::{Poly1305, poly1305::Key}, aead::Tag};
940///
941/// let key: Key = [42u8; 32].into();
942/// let ct_poly = Poly1305::new(key.as_ref())
943///     .aead_padding_ct()
944///     .update_ct(b"constant time ")
945///     .update_ct(b"chunk")
946///     .finalize()
947///     .unwrap();
948/// ```
949#[must_use]
950pub struct CtPoly1305Aead {
951    poly1305: Poly1305<Streaming>,
952    result: Res,
953    accum_len: u32
954}
955
956opaque_dbg! { CtPoly1305Aead }
957
958/// Creates a mask based on the slice length for constant-time adjustments.
959///
960/// # Arguments
961///
962/// * `len` - The length of the slice.
963///
964/// # Returns
965///
966/// If the length of the slice is greater than [`u32::MAX`] this will return all zeroes,
967/// otherwise this will return all ones.
968#[inline(always)]
969#[must_use]
970const fn slice_len_mask(len: usize) -> usize {
971    (can_cast_u32(len) as usize).wrapping_neg()
972}
973
974/// Adjusts the input slice based on the mask to ensure constant-time operations.
975///
976/// # Arguments
977///
978/// * `slice` - The input byte slice to adjust.
979///
980/// # Returns
981///
982/// A tuple containing the adjusted slice and the resulting `Res` state.
983#[inline(always)]
984fn adjust_slice(slice: &[u8]) -> (&[u8], Res) {
985    let mask = slice_len_mask(slice.len());
986
987    // So, of course, this isn't pure constant time. It has variable timing for lengths,
988    // though so does poly1305, and practically everything. Only way to avoid this is masking
989    // the computation which will never be perfect.
990    //
991    // Though, it does allow us to not need any early exit, the position of this error across
992    // multiple updates is not leaked via timing.
993    //
994    // So, there is variance in timing under this error yes, but this is given as at some point
995    // (finalize) there must be some branch to ensure the operation was successful and that
996    // the authentication code genuinely corresponds to the provided messages. With this
997    // approach there is a **reduction** in timing leakage, not a complete elimination of it.
998    (&slice[..(slice.len() & mask)], Res(mask != 0))
999}
1000
1001impl CtPoly1305Aead {
1002    /// Creates a new `CtPoly1305` instance from its parts.
1003    ///
1004    /// # Arguments
1005    ///
1006    /// * `poly1305` - The `Poly1305` instance in the `Streaming` state.
1007    /// * `result` - The current `Res` state.
1008    /// * `accum_len` - The accumulated length of the input data.
1009    ///
1010    /// # Returns
1011    ///
1012    /// A new `CtPoly1305` instance.
1013    const fn from_parts(poly1305: Poly1305<Streaming>, result: Res, accum_len: u32) -> Self {
1014        Self {
1015            poly1305,
1016            result,
1017            accum_len
1018        }
1019    }
1020
1021    /// Increments the accumulated length with the provided length without wrapping on overflow.
1022    ///
1023    /// # Arguments
1024    ///
1025    /// * `len` - The length to add to the accumulator.
1026    ///
1027    /// # Returns
1028    ///
1029    /// `Res` indicating if the operation would have overflowed the internal length.
1030    #[inline(always)]
1031    fn incr_accum(&mut self, len: u32) -> Res {
1032        let (accum_len, res) = ct::add_no_wrap(self.accum_len, len);
1033        self.accum_len = accum_len;
1034        res
1035    }
1036
1037    /// Adds more data to the constant-time streaming MAC computation.
1038    ///
1039    /// # Arguments
1040    ///
1041    /// * `input` - A byte slice representing the additional data to include.
1042    ///
1043    /// # Returns
1044    ///
1045    /// The updated `CtPoly1305` instance.
1046    ///
1047    /// # Example
1048    ///
1049    /// ```
1050    /// use wolf_crypto::{mac::{Poly1305, poly1305::Key}, aead::Tag};
1051    ///
1052    /// let key: Key = [42u8; 32].into();
1053    /// let ct_poly = Poly1305::new(key.as_ref())
1054    ///     .aead_padding_ct()
1055    ///     .update_ct(b"chunk1")
1056    ///     .update_ct(b"chunk2")
1057    ///     .finalize()
1058    ///     .unwrap();
1059    /// ```
1060    pub fn update_ct(mut self, input: &[u8]) -> Self {
1061        let (adjusted, mut res) = adjust_slice(input);
1062        res.ensure(self.incr_accum(adjusted.len() as u32));
1063
1064        unsafe { self.poly1305.update_unchecked(adjusted) };
1065
1066        self.result.ensure(res);
1067        self
1068    }
1069
1070    /// Returns `true` if no errors have been encountered to this point.
1071    #[must_use]
1072    pub const fn is_ok(&self) -> bool {
1073        self.result.is_ok()
1074    }
1075
1076    /// Returns `true` if an error has been encountered at some point.
1077    #[must_use]
1078    pub const fn is_err(&self) -> bool {
1079        self.result.is_err()
1080    }
1081
1082    /// Finalizes the constant-time streaming MAC computation and returns the resulting `Tag`.
1083    ///
1084    /// # Returns
1085    ///
1086    /// The associated authentication tag representing all updates and the total length of the
1087    /// updates.
1088    ///
1089    /// # Errors
1090    ///
1091    /// The `CtPoly1305` instance accumulates errors throughout the updating process without
1092    /// branching. There are two ways that this will return an error based on prior updates:
1093    ///
1094    /// - One of the provided inputs had a length which was greater than [`u32::MAX`].
1095    /// - The total length, accumulated from all inputs, is greater than [`u32::MAX`].
1096    ///
1097    /// # Example
1098    ///
1099    /// ```
1100    /// use wolf_crypto::{mac::{Poly1305, poly1305::Key}, aead::Tag};
1101    ///
1102    /// let key: Key = [42u8; 32].into();
1103    /// let tag = Poly1305::new(key.as_ref())
1104    ///     .aead_padding_ct()
1105    ///     .update_ct(b"chunk1")
1106    ///     .update_ct(b"chunk2")
1107    ///     .finalize()
1108    ///     .unwrap();
1109    /// ```
1110    pub fn finalize(self) -> Result<Tag, Unspecified> {
1111        let tag = finalize_aead(self.poly1305, self.accum_len);
1112        self.result.unit_err(tag)
1113    }
1114}
1115
1116/// Provides a constant-time interface for updating the MAC computation, enhancing resistance
1117/// against side-channel attacks.
1118///
1119/// # Example
1120///
1121/// ```
1122/// use wolf_crypto::{mac::{Poly1305, poly1305::Key}, aead::Tag};
1123///
1124/// let key: Key = [42u8; 32].into();
1125/// let ct_poly = Poly1305::new(key.as_ref())
1126///     .update_ct(b"constant time ")
1127///     .update_ct(b"chunk")
1128///     .finalize()
1129///     .unwrap();
1130/// ```
1131#[must_use]
1132pub struct CtPoly1305 {
1133    poly1305: Poly1305<Streaming>,
1134    result: Res,
1135    to_pad: u8
1136}
1137
1138opaque_dbg! { CtPoly1305 }
1139
1140impl CtPoly1305 {
1141    /// Creates a new `CtPoly1305` instance from its parts.
1142    ///
1143    /// # Arguments
1144    ///
1145    /// * `poly1305` - The `Poly1305` instance in the `Streaming` state.
1146    /// * `result` - The current `Res` state.
1147    /// * `len` - The length of the input data. Used to compute the amount needed for padding
1148    ///   overtime.
1149    ///
1150    /// # Returns
1151    ///
1152    /// A new `CtPoly1305` instance.
1153    const fn from_parts(poly1305: Poly1305<Streaming>, result: Res, len: u32) -> Self {
1154        Self {
1155            poly1305,
1156            result,
1157            to_pad: update_to_pad(0, len)
1158        }
1159    }
1160
1161    /// Adds more data to the constant-time streaming MAC computation.
1162    ///
1163    /// # Arguments
1164    ///
1165    /// * `input` - A byte slice representing the additional data to include.
1166    ///
1167    /// # Returns
1168    ///
1169    /// The updated `CtPoly1305` instance.
1170    ///
1171    /// # Example
1172    ///
1173    /// ```
1174    /// use wolf_crypto::{mac::{Poly1305, poly1305::Key}, aead::Tag};
1175    ///
1176    /// let key: Key = [42u8; 32].into();
1177    /// let ct_poly = Poly1305::new(key.as_ref())
1178    ///     .update_ct(b"chunk1")
1179    ///     .update_ct(b"chunk2")
1180    ///     .finalize()
1181    ///     .unwrap();
1182    /// ```
1183    pub fn update_ct(mut self, input: &[u8]) -> Self {
1184        let (adjusted, res) = adjust_slice(input);
1185
1186        // adjusted length will always be less than u32::MAX
1187        self.to_pad = update_to_pad(self.to_pad, adjusted.len() as u32);
1188
1189        unsafe { self.poly1305.update_unchecked(adjusted) };
1190
1191        self.result.ensure(res);
1192        self
1193    }
1194
1195    /// Returns `true` if no errors have been encountered to this point.
1196    #[must_use]
1197    pub const fn is_ok(&self) -> bool { self.result.is_ok() }
1198
1199    /// Returns `true` if an error has been encountered at some point.
1200    #[must_use]
1201    pub const fn is_err(&self) -> bool {
1202        self.result.is_err()
1203    }
1204
1205    /// Finalizes the constant-time streaming MAC computation and returns the resulting `Tag`.
1206    ///
1207    /// # Returns
1208    ///
1209    /// The associated authentication [`Tag`] representing all updates and the total length of the
1210    /// updates.
1211    ///
1212    /// # Errors
1213    ///
1214    /// The `CtPoly1305` instance accumulates errors throughout the updating process without
1215    /// branching. The only error which could occur:
1216    ///
1217    /// One of the provided inputs had a length which was greater than [`u32::MAX`].
1218    ///
1219    /// # Example
1220    ///
1221    /// ```
1222    /// use wolf_crypto::{mac::{Poly1305, poly1305::Key}, aead::Tag};
1223    ///
1224    /// let key: Key = [42u8; 32].into();
1225    /// let tag = Poly1305::new(key.as_ref())
1226    ///     .update_ct(b"chunk1")
1227    ///     .update_ct(b"chunk2")
1228    ///     .finalize()
1229    ///     .unwrap();
1230    /// ```
1231    pub fn finalize(self) -> Result<Tag, Unspecified> {
1232        let tag = finalize(self.poly1305, self.to_pad as u32);
1233        self.result.unit_err(tag)
1234    }
1235
1236    /// Finalizes the constant-time streaming MAC computation and returns the resulting `Tag`.
1237    ///
1238    /// # Note
1239    ///
1240    /// It is far more common in practice to use to pad the [`finalize`] method. This is only here
1241    /// for `XSalsa20Poly1305`.
1242    ///
1243    /// # Returns
1244    ///
1245    /// The associated authentication [`Tag`] representing all updates and the total length of the
1246    /// updates.
1247    ///
1248    /// # Errors
1249    ///
1250    /// The `CtPoly1305` instance accumulates errors throughout the updating process without
1251    /// branching. The only error which could occur:
1252    ///
1253    /// One of the provided inputs had a length which was greater than [`u32::MAX`].
1254    ///
1255    /// # Example
1256    ///
1257    /// ```
1258    /// use wolf_crypto::{mac::{Poly1305, poly1305::Key}, aead::Tag};
1259    ///
1260    /// let key: Key = [42u8; 32].into();
1261    /// let tag = Poly1305::new(key.as_ref())
1262    ///     .update_ct(b"chunk1")
1263    ///     .update_ct(b"chunk2")
1264    ///     .finalize_no_padding()
1265    ///     .unwrap();
1266    /// ```
1267    ///
1268    /// [`finalize`]: Self::finalize
1269    pub fn finalize_no_padding(self) -> Result<Tag, Unspecified> {
1270        let tag = finalize_no_pad(self.poly1305);
1271        self.result.unit_err(tag)
1272    }
1273}
1274
1275#[cfg(test)]
1276use poly1305::universal_hash::generic_array::{GenericArray, ArrayLength};
1277
1278#[cfg(test)]
1279const fn rc_to_blocks<T, N: ArrayLength<T>>(data: &[T]) -> (&[GenericArray<T, N>], &[T]) {
1280    let nb = data.len() / N::USIZE;
1281    let (left, right) = data.split_at(nb * N::USIZE);
1282    let p = left.as_ptr().cast::<GenericArray<T, N>>();
1283    // SAFETY: we guarantee that `blocks` does not point outside `data`
1284    // and `p` is valid for reads
1285    #[allow(unsafe_code)]
1286    let blocks = unsafe { core::slice::from_raw_parts(p, nb) };
1287    (blocks, right)
1288}
1289
1290#[cfg(test)]
1291use poly1305::{Poly1305 as rc_Poly1305, universal_hash::{KeyInit, UniversalHash}};
1292
1293#[cfg(test)]
1294fn construct_polys(key: [u8; 32]) -> (rc_Poly1305, Poly1305<Ready>) {
1295    let rc_key = poly1305::Key::from_slice(key.as_slice());
1296    (rc_Poly1305::new(rc_key), Poly1305::new(KeyRef::new(&key)))
1297}
1298
1299#[cfg(test)]
1300mod tests {
1301    use super::*;
1302
1303    #[test]
1304    fn smoke() {
1305        let key: Key = [42u8; 32].into();
1306        let tag = Poly1305::new(key.as_ref())
1307            .aead_padding_ct()
1308            .update_ct(b"hello world")
1309            .update_ct(b"good day to you")
1310            .update_ct(b"mmm yes mm yes indeed mm")
1311            .update_ct(b"hmm...")
1312            .finalize()
1313            .unwrap();
1314
1315        let o_tag = Poly1305::new(key.as_ref())
1316            .mac(b"hello worldgood day to yoummm yes mm yes indeed mmhmm...", b"")
1317            .unwrap();
1318
1319        assert_eq!(tag, o_tag);
1320    }
1321
1322    #[test]
1323    fn rust_crypto_aligned() {
1324        let key = [42u8; 32];
1325        let (mut rc, wc) = construct_polys(key);
1326        let data = b"hello world we operate equivalen";
1327
1328        let (blocks, _rem) = rc_to_blocks(data);
1329
1330        rc.update(blocks);
1331        let rc_out = rc.finalize();
1332
1333        let wc_out = wc.update(data).unwrap().finalize();
1334
1335        assert_eq!(wc_out, rc_out.as_slice());
1336    }
1337
1338    #[test]
1339    fn rust_crypto_unaligned() {
1340        let key = [42u8; 32];
1341        let (mut rc, wc) = construct_polys(key);
1342        let data = b"hello world we operate equivalently";
1343
1344        rc.update_padded(data);
1345        let rc_tag = rc.finalize();
1346        let tag = wc.update(data).unwrap().finalize();
1347
1348        assert_eq!(tag, rc_tag.as_slice());
1349    }
1350}
1351
1352#[cfg(kani)]
1353const fn wc_to_pad(len_to_pad: u32) -> u32 {
1354    ((-(len_to_pad as isize)) & 15) as u32
1355}
1356
1357#[cfg(kani)]
1358const fn wc_to_pad_64(len_to_pad: u64) -> u32 {
1359    ((-(len_to_pad as i128)) & 15) as u32
1360}
1361
1362#[cfg(test)]
1363mod property_tests {
1364    use super::*;
1365    use proptest::prelude::*;
1366    use crate::aes::test_utils::{BoundList, AnyList};
1367
1368    proptest! {
1369        #![proptest_config(ProptestConfig::with_cases(5_000))]
1370
1371        #[test]
1372        fn wc_poly_is_eq_to_rc_poly(
1373            key in any::<[u8; 32]>(),
1374            data in any::<BoundList<1024>>()
1375        ) {
1376            let (mut rc, wc) = construct_polys(key);
1377
1378            rc.update_padded(data.as_slice());
1379
1380            let tag = wc.update(data.as_slice()).unwrap().finalize();
1381            let rc_tag = rc.finalize();
1382
1383            prop_assert_eq!(tag, rc_tag.as_slice());
1384        }
1385
1386        #[test]
1387        fn wc_poly_multi_updates_is_eq_to_rc_poly_oneshot(
1388            key in any::<[u8; 32]>(),
1389            data in any::<AnyList<32, BoundList<256>>>()
1390        ) {
1391            let (mut rc, wc) = construct_polys(key);
1392
1393            let mut wc = wc.normal();
1394
1395            for input in data.as_slice() {
1396                wc = wc.update(input.as_slice()).unwrap();
1397            }
1398
1399            let joined = data.join();
1400            rc.update_padded(joined.as_slice());
1401
1402            let tag = wc.finalize();
1403            let rc_tag = rc.finalize();
1404
1405            prop_assert_eq!(tag, rc_tag.as_slice());
1406        }
1407
1408        #[test]
1409        fn multi_updates_is_eq_to_oneshot_tls_aead_scheme(
1410            key in any::<Key>(),
1411            data in any::<AnyList<32, BoundList<256>>>()
1412        ) {
1413            let mut updates = Poly1305::new(key.as_ref()).aead_padding();
1414
1415            for input in data.as_slice() {
1416                updates = updates.update(input.as_slice()).unwrap();
1417            }
1418
1419            let tag = updates.finalize();
1420
1421            let joined = data.join();
1422            let m_tag = Poly1305::new(key).mac(joined.as_slice(), ()).unwrap();
1423
1424            prop_assert_eq!(tag, m_tag);
1425        }
1426
1427        #[test]
1428        fn multi_updates_ct_is_eq_to_normal(
1429            key in any::<Key>(),
1430            data in any::<AnyList<32, BoundList<256>>>()
1431        ) {
1432            let mut poly = Poly1305::new(key.as_ref()).normal();
1433            let mut poly_ct = Poly1305::new(key.as_ref()).normal_ct();
1434
1435            for input in data.as_slice() {
1436                poly = poly.update(input.as_slice()).unwrap();
1437                poly_ct = poly_ct.update_ct(input.as_slice());
1438            }
1439
1440            let tag = poly.finalize();
1441            let tag_ct = poly_ct.finalize().unwrap();
1442
1443            prop_assert_eq!(tag, tag_ct);
1444        }
1445
1446        #[test]
1447        fn multi_updates_is_eq_oneshot(
1448            key in any::<Key>(),
1449            data in any::<AnyList<32, BoundList<256>>>()
1450        ) {
1451            let mut poly = Poly1305::new(key.as_ref()).normal();
1452
1453            for input in data.as_slice() {
1454                poly = poly.update(input.as_slice()).unwrap();
1455            }
1456
1457            let tag = poly.finalize();
1458
1459            let joined = data.join();
1460            let o_tag = Poly1305::new(key)
1461                .update(joined.as_slice()).unwrap()
1462                .finalize();
1463
1464            prop_assert_eq!(tag, o_tag);
1465        }
1466
1467        #[test]
1468        fn multi_updates_ct_is_eq_oneshot(
1469            key in any::<Key>(),
1470            data in any::<AnyList<32, BoundList<256>>>()
1471        ) {
1472            let mut poly = Poly1305::new(key.as_ref()).normal_ct();
1473
1474            for input in data.as_slice() {
1475                poly = poly.update_ct(input.as_slice());
1476            }
1477
1478            let tag = poly.finalize().unwrap();
1479
1480            let joined = data.join();
1481            let o_tag = Poly1305::new(key)
1482                .update(joined.as_slice()).unwrap()
1483                .finalize();
1484
1485            prop_assert_eq!(tag, o_tag);
1486        }
1487    }
1488}
1489
1490#[cfg(kani)]
1491mod proofs {
1492    use kani::proof;
1493    use super::*;
1494
1495    #[proof]
1496    fn univ_update_to_pad_is_no_wrap_mask() {
1497        let existing: u32 = kani::any();
1498        let to_add: u32 = kani::any();
1499
1500        let utp = update_to_pad((existing & 15) as u8, to_add) as u64;
1501        let genuine = ((existing as u64) + (to_add as u64)) & 15;
1502
1503        kani::assert(
1504            utp == genuine,
1505            "The wrapping addition must always be equivalent to non-wrapping output"
1506        );
1507    }
1508
1509    #[proof]
1510    fn univ_update_to_pad_holds_for_wc_pad_algo() {
1511        let start: u32 = kani::any();
1512        let end: u32 = kani::any();
1513
1514        let utp = update_to_pad((start & 15) as u8, end);
1515
1516        kani::assert(
1517            wc_to_pad(utp as u32) == wc_to_pad_64((start as u64) + (end as u64)),
1518            "update_to_pad must be equivalent to the total length in the eyes of the wolfcrypt \
1519            padding algorithm."
1520        );
1521    }
1522
1523    #[proof]
1524    fn univ_mask_is_no_mask_to_wc_pad_algo() {
1525        let some_num: u64 = kani::any();
1526
1527        kani::assert(
1528            wc_to_pad_64(some_num & 15) == wc_to_pad_64(some_num),
1529            "wolfcrypt's to pad must result in the same output for the input mask 15 and raw input"
1530        )
1531    }
1532}