wolf_crypto/aead/
aad.rs

1use crate::{can_cast_u32, const_can_cast_u32, to_u32};
2use crate::sealed::AadSealed as Sealed;
3use core::fmt;
4
5
6/// A generic representation of additional authenticated data (AAD)
7#[allow(clippy::missing_safety_doc)]
8pub unsafe trait Aad: Sealed {
9    /// Returns the length of the [`ptr`] result, represented as a `u32`.
10    ///
11    /// # Trait Safety
12    ///
13    /// - This must return the length as a `u32`, if the length is too large to be represented as
14    ///   a `u32` then it should return `None`.
15    /// - This returns `None` **if and only if** the length cannot be represented as a `u32`.
16    ///   If no AAD is being provided, the returned length should **always** be zero. `None` is
17    ///   reserved only for when casting the `usize` to a `u32` would overflow.
18    #[doc(hidden)]
19    #[must_use]
20    fn try_size(&self) -> Option<u32>;
21
22    /// Returns a pointer valid for the length of the [`try_size`] result.
23    ///
24    /// # Trait Safety
25    ///
26    /// - This must provide a valid pointer if the result of [`try_size`] is not `Some(0)`. If
27    ///   `Some(0)` is returned from [`try_size`] it is acceptable for the result of this to be
28    ///   null.
29    /// - This must return a pointer which is valid for the result of [`try_size`], any less will
30    ///   result in undefined behavior.
31    ///
32    /// [`try_size`]: Aad::try_size
33    #[doc(hidden)]
34    #[must_use]
35    fn ptr(&self) -> *const u8;
36
37    /// # Trait Safety
38    ///
39    /// Same invariants as [`try_size`], just this function does not need to check for overflow
40    /// as to safely invoke this, the caller must ensure [`is_valid_size`] returns true.
41    ///
42    /// # Safety
43    ///
44    /// The caller must ensure the [`is_valid_size`] returns true prior to invoking this.
45    ///
46    /// [`try_size`]: Aad::try_size
47    /// [`is_valid_size`]: Aad::is_valid_size
48    #[doc(hidden)]
49    #[must_use]
50    unsafe fn size(&self) -> u32;
51
52    /// Returns `true` IFF the result of [`try_size`] would be `Some`.
53    ///
54    /// [`try_size`]: Aad::try_size
55    #[doc(hidden)]
56    #[must_use]
57    fn is_valid_size(&self) -> bool;
58}
59
60/// Represents Additional Authenticated Data (AAD) Slice.
61#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
62#[repr(transparent)]
63pub struct AadSlice<'s> {
64    inner: Option<&'s [u8]>
65}
66
67impl<'s> fmt::Debug for AadSlice<'s> {
68    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
69        f.write_str("AadSlice(")
70            .and_then(|()| match self.inner {
71                None => f.write_str("EMPTY"),
72                Some(inner) => <[u8] as fmt::Debug>::fmt(inner, f)
73            })
74            .and_then(|()| f.write_str(")"))
75    }
76}
77
78impl<'a> PartialEq<[u8]> for AadSlice<'a> {
79    #[inline]
80    fn eq(&self, other: &[u8]) -> bool {
81        self.inner.is_some_and(|inner| inner == other)
82    }
83}
84
85impl<'s> AadSlice<'s> {
86    /// An empty AAD.
87    pub const EMPTY: Self = Self { inner: None };
88
89    /// Create a new AAD instance from a byte slice.
90    pub const fn new(aad: &'s [u8]) -> Self {
91        Self { inner: Some(aad) }
92    }
93
94    /// Pointer may be null of the option was None
95    #[inline]
96    pub(crate) const fn as_ptr(&self) -> *const u8 {
97        match self.inner {
98            Some(inner) => inner.as_ptr(),
99            None => core::ptr::null()
100        }
101    }
102    
103    /// Returns the length of the underlying slice if it can be represented as a [`u32`].
104    /// 
105    /// # Note
106    /// 
107    /// [`AadSlice::EMPTY`] will always return `Some(0)`.
108    #[inline(always)]
109    #[must_use]
110    pub const fn size(&self) -> Option<u32> {
111        match self.inner {
112            None => Some(0),
113            Some(val) => to_u32(val.len())
114        }
115    }
116
117    /// Returns `true` if the length of the underlying slice can be safely represented as a [`u32`].
118    #[inline]
119    #[must_use]
120    pub const fn valid_size(&self) -> bool {
121        match self.inner {
122            Some(inner) => can_cast_u32(inner.len()),
123            None => true
124        }
125    }
126}
127
128impl<'a> From<&'a [u8]> for AadSlice<'a> {
129    #[inline]
130    fn from(value: &'a [u8]) -> Self {
131        Self::new(value)
132    }
133}
134
135impl<'a> Sealed for AadSlice<'a> {}
136
137unsafe impl<'a> Aad for AadSlice<'a> {
138    #[inline]
139    fn try_size(&self) -> Option<u32> { self.size() }
140    #[inline]
141    fn ptr(&self) -> *const u8 { self.as_ptr() }
142
143    #[inline]
144    unsafe fn size(&self) -> u32 {
145        debug_assert!(self.is_valid_size());
146        self.inner.map_or(0, |inner| inner.len() as u32)
147    }
148
149    #[inline]
150    fn is_valid_size(&self) -> bool { self.valid_size() }
151}
152
153impl<T: ?Sized + Sealed> Sealed for &T {}
154unsafe impl<T: ?Sized + Aad> Aad for &T {
155    #[inline]
156    fn try_size(&self) -> Option<u32> {
157        T::try_size(self)
158    }
159    #[inline]
160    fn ptr(&self) -> *const u8 {
161        T::ptr(self)
162    }
163    #[inline]
164    #[cfg_attr(debug_assertions, track_caller)]
165    unsafe fn size(&self) -> u32 {
166        T::size(self)
167    }
168    #[inline]
169    fn is_valid_size(&self) -> bool {
170        T::is_valid_size(self)
171    }
172}
173impl<T: ?Sized + Sealed> Sealed for &mut T {}
174unsafe impl<T: ?Sized + Aad> Aad for &mut T {
175    #[inline]
176    fn try_size(&self) -> Option<u32> {
177        T::try_size(self)
178    }
179    #[inline]
180    fn ptr(&self) -> *const u8 {
181        T::ptr(self)
182    }
183    #[inline]
184    #[cfg_attr(debug_assertions, track_caller)]
185    unsafe fn size(&self) -> u32 {
186        T::size(self)
187    }
188    #[inline]
189    fn is_valid_size(&self) -> bool {
190        T::is_valid_size(self)
191    }
192}
193
194impl Sealed for [u8] {}
195
196unsafe impl Aad for [u8] {
197    #[inline]
198    fn try_size(&self) -> Option<u32> {
199        to_u32(self.len())
200    }
201    #[inline]
202    fn ptr(&self) -> *const u8 {
203        self.as_ptr()
204    }
205    #[inline]
206    #[cfg_attr(debug_assertions, track_caller)]
207    unsafe fn size(&self) -> u32 {
208        debug_assert!(self.is_valid_size());
209        self.len() as u32
210    }
211    #[inline]
212    fn is_valid_size(&self) -> bool {
213        can_cast_u32(self.len())
214    }
215}
216
217impl<const C: usize> Sealed for [u8; C] {}
218
219unsafe impl<const C: usize> Aad for [u8; C] {
220    #[inline]
221    fn try_size(&self) -> Option<u32> {
222        if const_can_cast_u32::<C>() {
223            Some(C as u32)
224        } else {
225            None
226        }
227    }
228    #[inline]
229    fn ptr(&self) -> *const u8 {
230        self.as_ptr()
231    }
232    #[inline]
233    #[cfg_attr(debug_assertions, track_caller)]
234    unsafe fn size(&self) -> u32 {
235        debug_assert!(const_can_cast_u32::<C>());
236        C as u32
237    }
238    #[inline]
239    fn is_valid_size(&self) -> bool {
240        const_can_cast_u32::<C>()
241    }
242}
243
244impl Sealed for str {}
245
246unsafe impl Aad for str {
247    #[inline]
248    fn try_size(&self) -> Option<u32> {
249        to_u32(self.len())
250    }
251    #[inline]
252    fn ptr(&self) -> *const u8 {
253        self.as_ptr()
254    }
255    #[inline]
256    #[cfg_attr(debug_assertions, track_caller)]
257    unsafe fn size(&self) -> u32 {
258        debug_assert!(self.is_valid_size());
259        self.len() as u32
260    }
261    #[inline]
262    fn is_valid_size(&self) -> bool {
263        can_cast_u32(self.len())
264    }
265}
266
267impl Sealed for () {}
268
269unsafe impl Aad for () {
270    #[inline]
271    fn try_size(&self) -> Option<u32> {
272        Some(0)
273    }
274    #[inline]
275    fn ptr(&self) -> *const u8 {
276        core::ptr::null()
277    }
278    #[inline]
279    unsafe fn size(&self) -> u32 {
280        0
281    }
282    #[inline]
283    fn is_valid_size(&self) -> bool {
284        true
285    }
286}
287
288impl<T: Sealed> Sealed for Option<T> {}
289
290unsafe impl<T: Aad> Aad for Option<T> {
291    #[inline]
292    fn try_size(&self) -> Option<u32> {
293        self.as_ref().map_or(Some(0), Aad::try_size)
294    }
295    #[inline]
296    fn ptr(&self) -> *const u8 {
297        self.as_ref().map_or(core::ptr::null(), Aad::ptr)
298    }
299    #[inline]
300    unsafe fn size(&self) -> u32 {
301        #[allow(clippy::option_if_let_else)]
302        match self {
303            None => 0,
304            Some(inner) => inner.size()
305        }
306    }
307    #[inline]
308    fn is_valid_size(&self) -> bool {
309        self.as_ref().map_or(true, Aad::is_valid_size)
310    }
311}
312
313alloc! {
314    impl Sealed for Vec<u8> {}
315
316    unsafe impl Aad for Vec<u8> {
317        #[inline]
318        fn try_size(&self) -> Option<u32> {
319            to_u32(self.len())
320        }
321        #[inline]
322        fn ptr(&self) -> *const u8 {
323            self.as_ptr()
324        }
325        #[inline]
326        #[cfg_attr(debug_assertions, track_caller)]
327        unsafe fn size(&self) -> u32 {
328            debug_assert!(self.is_valid_size());
329            self.len() as u32
330        }
331        #[inline]
332        fn is_valid_size(&self) -> bool {
333            can_cast_u32(self.len())
334        }
335    }
336
337    impl Sealed for String {}
338
339    unsafe impl Aad for String {
340        #[inline]
341        fn try_size(&self) -> Option<u32> {
342            to_u32(self.len())
343        }
344        #[inline]
345        fn ptr(&self) -> *const u8 {
346            self.as_ptr()
347        }
348        #[inline]
349        #[cfg_attr(debug_assertions, track_caller)]
350        unsafe fn size(&self) -> u32 {
351            debug_assert!(self.is_valid_size());
352            self.len() as u32
353        }
354        #[inline]
355        fn is_valid_size(&self) -> bool {
356            can_cast_u32(self.len())
357        }
358    }
359}