wolf_crypto/kdf/
mod.rs

1//! Key Derivation Functions
2
3use crate::{can_cast_i32, can_cast_u32, const_can_cast_i32, const_can_cast_u32, to_u32};
4use crate::sealed::AadSealed as Sealed;
5use core::num::NonZeroU32;
6use core::convert::Infallible;
7use crate::buf::InvalidSize;
8use crate::error::InvalidIters;
9use core::fmt;
10
11non_fips! {
12    mod hmac;
13    pub use hmac::hkdf;
14    pub use hmac::hkdf_into;
15}
16
17pub mod pbkdf;
18#[doc(inline)]
19pub use pbkdf::{pbkdf2, pbkdf2_into, FipsPbkdf2};
20
21non_fips! {
22    #[doc(inline)]
23    pub use pbkdf::{pbkdf1, pbkdf1_into};
24}
25
26#[doc(inline)]
27pub use crate::mac::hmac::algo::{
28    InsecureKey,
29    KeySlice,
30    Sha224, Sha256, Sha384, Sha512,
31    Sha3_224, Sha3_256, Sha3_384, Sha3_512
32};
33
34non_fips! {
35    #[doc(inline)]
36    pub use crate::mac::hmac::algo::{
37        Sha, Md5
38    };
39}
40
41/// The number of iterations for PBKDF.
42///
43/// The general rule is bigger is better (in terms of security), however, bigger is also more
44/// computationally expensive.
45///
46/// `OWASP` recommends using at least 600,000 iterations with `SHA256` for passwords, a FIPS
47/// requirement. [`NIST SP 800-132, Section 5.2`][1], back in 2010, recommends anywhere from 1,000
48/// to 10,000,000 iterations (10,000,000 for critical secrets). **However** `SP 800-132` is under
49/// [active revision][2], and the lower bound of 1,000 iterations is now considered inadequate for
50/// modern security needs.
51///
52/// [1]: https://nvlpubs.nist.gov/nistpubs/Legacy/SP/nistspecialpublication800-132.pdf#%5B%7B%22num%22%3A18%2C%22gen%22%3A0%7D%2C%7B%22name%22%3A%22XYZ%22%7D%2C0%2C316%2Cnull%5D
53/// [2]: https://csrc.nist.gov/News/2023/decision-to-revise-nist-sp-800-132
54#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord)]
55#[repr(transparent)]
56pub struct Iters { count: NonZeroU32 }
57
58impl fmt::Display for Iters {
59    #[inline]
60    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
61        f.write_fmt(format_args!("Iters({})", self.count))
62    }
63}
64
65impl fmt::Debug for Iters {
66    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
67        <Self as fmt::Display>::fmt(self, f)
68    }
69}
70
71impl Iters {
72    /// Create a new `Iters` instance.
73    ///
74    /// # Note
75    ///
76    /// Please see the [`Iters`] type documentation for more information and sources to assist in
77    /// picking the correct value. The value is context dependent, are you hashing a password?
78    /// You'll need a very large value, minimum 600,000. For key derivation, again it is context
79    /// dependent, how critical is this key? How powerful is the host machine? The general rule
80    /// is the bigger the value, the better in terms of security.
81    ///
82    /// # Arguments
83    ///
84    /// * `iters` - The desired number of iterations (must be non-zero).
85    ///
86    /// # Returns
87    ///
88    /// - `Some(Iters)`: The new `Iters` instance.
89    /// - `None`: The provided `iters` argument was zero.
90    pub const fn new(iters: u32) -> Option<Self> {
91        // Cool optimization rustc:
92        //
93        // define noundef i32 @new(i32 noundef returned %iters) unnamed_addr #0 {
94        // start:
95        //   ret i32 %iters
96        // }
97        //
98        // This is practically a no-op due to NPO.
99        match NonZeroU32::new(iters) {
100            Some(count) => Some(Self { count }),
101            None => None
102        }
103    }
104
105    /// Create a new `Iters` instance without any safety checks.
106    ///
107    /// # Safety
108    ///
109    /// This will cause undefined behavior if the provided `iters` argument is `0`. Iters
110    /// may only be constructed with non-zero values (as the underlying type is [`NonZeroU32`]).
111    pub const unsafe fn new_unchecked(iters: u32) -> Self {
112        Self { count: NonZeroU32::new_unchecked(iters) }
113    }
114
115    /// Returns `true` if the iteration count can safely be cast to an `i32`.
116    ///
117    /// Certain KDFs (such as the PBKDF family) take the iteration count as an `i32`, and check
118    /// at runtime if the iteration count is greater than 0. This most likely is an older design
119    /// choice which they must keep for stability reasons.
120    ///
121    /// For ergonomic reasons, we will represent the iteration count as an unsigned int.
122    pub const fn is_valid_size(&self) -> bool {
123        self.get() <= i32::MAX as u32
124    }
125
126    /// Returns the contained iteration count as a `u32`.
127    #[inline]
128    #[must_use]
129    pub const fn get(&self) -> u32 {
130        self.count.get()
131    }
132}
133
134impl From<NonZeroU32> for Iters {
135    #[inline]
136    fn from(value: NonZeroU32) -> Self {
137        Self { count: value }
138    }
139}
140
141impl TryFrom<u32> for Iters {
142    type Error = InvalidIters;
143
144    /// Create a new `Iters` instance from a `u32`.
145    ///
146    /// # Errors
147    ///
148    /// If the number of iterations was zero.
149    #[inline]
150    fn try_from(value: u32) -> Result<Self, Self::Error> {
151        Self::new(value).ok_or(InvalidIters)
152    }
153}
154
155impl TryFrom<usize> for Iters {
156    type Error = InvalidIters;
157
158    /// Create a new `Iters` instance from a `usize`.
159    ///
160    /// # Errors
161    ///
162    /// - If the number of iterations was zero.
163    /// - If the number of iterations was greater than [`u32::MAX`].
164    #[inline]
165    fn try_from(value: usize) -> Result<Self, Self::Error> {
166        to_u32(value).and_then(Self::new).ok_or(InvalidIters)
167    }
168}
169
170pub mod salt {
171    //! Salt requirement marker types.
172    use super::{InvalidSize, Infallible, Salt, Sealed};
173    use core::marker::PhantomData;
174    use core::fmt;
175
176    /// Represents the minimum size for the [`Salt`].
177    ///
178    /// [`Salt`]: super::Salt
179    pub trait MinSize : Sealed {
180        /// The associated error type for creating a [`SaltSlice`] with this constraint.
181        ///
182        /// [`SaltSlice`]: super::SaltSlice
183        type CreateError;
184
185        /// Returns the minimum size for the [`Salt`].
186        ///
187        /// [`Salt`]: super::Salt
188        fn min_size() -> u32;
189    }
190
191    macro_rules! def_sz {
192        ($(
193            $(#[$meta:meta])*
194            $name:ident => $sz:literal => $err:ident
195        ),* $(,)?) => {
196            $(
197                $(#[$meta])*
198                pub struct $name;
199
200                impl super::Sealed for $name {}
201                impl MinSize for $name {
202                    type CreateError = $err;
203
204                    #[inline]
205                    fn min_size() -> u32 {
206                        $sz
207                    }
208                }
209            )*
210        };
211    }
212
213    def_sz! {
214        /// Indicates that the [`Salt`] may be empty / optional.
215        ///
216        /// [`Salt`]: super::Salt
217        #[derive(Copy, Clone, Debug, PartialEq, Eq)]
218        Empty => 0 => Infallible,
219        /// Indicates that the [`Salt`] **must** not be empty.
220        ///
221        /// [`Salt`]: super::Salt
222        #[derive(Copy, Clone, Debug, PartialEq, Eq)]
223        NonEmpty => 1 => InvalidSize,
224        /// Indicates that the [`Salt`] **must** be at least 128 bits (16 bytes).
225        ///
226        /// [`Salt`]: super::Salt
227        #[derive(Copy, Clone, Debug, PartialEq, Eq)]
228        Min16 => 16 => InvalidSize
229    }
230
231    /// Implemented for salt constraints which must not be empty ([`NonEmpty`] + [`Min16`]).
232    pub trait NonEmptySize<SZ: MinSize> : Salt<SZ> {}
233    impl<S: Salt<NonEmpty>> NonEmptySize<NonEmpty> for S {}
234    impl<S: Salt<Min16>> NonEmptySize<Min16> for S {}
235
236    mark_fips! { Min16, Sealed }
237
238    /// A [`Salt`] with runtime flexibility.
239    ///
240    /// The [`Salt`] trait, with its associated constraints, is implemented for most common types
241    /// which meet the marker constraint for pure compile-time checks. However, this can be
242    /// limiting, this type moves these compile-time checks to runtime.
243    #[repr(transparent)]
244    pub struct Slice<'s, SZ> {
245        raw: &'s [u8],
246        _min_size: PhantomData<SZ>
247    }
248
249    impl<'s, SZ: MinSize> Clone for Slice<'s, SZ> {
250        #[inline]
251        fn clone(&self) -> Self { Self::create(self.raw) }
252    }
253
254    impl<'s, SZ: MinSize> AsRef<[u8]> for Slice<'s, SZ> {
255        #[inline]
256        fn as_ref(&self) -> &[u8] { self.raw }
257    }
258
259    impl<'s, SZ: MinSize> fmt::Debug for Slice<'s, SZ> {
260        fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
261            f.debug_tuple("Slice").field(&self.raw).finish()
262        }
263    }
264
265    macro_rules! impl_salt_for {
266        ($sz:ty => { $item:item }) => {
267            impl<'s> Slice<'s, $sz> {
268                $item
269            }
270        };
271    }
272
273    impl_salt_for! { Empty => {
274        /// Create a new `SaltSlice` instance.
275        ///
276        /// # Arguments
277        ///
278        /// * `slice` - The [`Salt`] (if any) to use.
279        ///
280        /// # Errors
281        ///
282        /// This is infallible, the only reason this returns a result is to keep this `new`
283        /// implementation in sync with other [`Salt`] constraints (this being the weakest / most
284        /// permissive constraint).
285        pub const fn new(slice: &'s [u8]) -> Result<Self, Infallible> {
286            Ok(Self::create(slice))
287        }
288    }}
289
290    impl_salt_for! { NonEmpty => {
291        /// Create a new `SaltSlice` instance.
292        ///
293        /// # Arguments
294        ///
295        /// * `slice` - The [`Salt`], which must be non-empty.
296        ///
297        /// # Errors
298        ///
299        /// This requires the provided slice to be **non-empty**, this is the second-weakest
300        /// constraint, and only leveraged with `allow-non-fips` enabled. In general, for KDFs such
301        /// as PBKDF it is **strongly recommended** to use at least a 128 bit (16 byte) salt
302        /// generated from a valid `CSPRNG`.
303        pub const fn new(slice: &'s [u8]) -> Result<Self, InvalidSize> {
304            if !slice.is_empty() {
305                Ok(Self::create(slice))
306            } else {
307                Err(InvalidSize)
308            }
309        }
310    }}
311
312    impl_salt_for! { Min16 => {
313        /// Create a new `SaltSlice` instance.
314        ///
315        /// # Arguments
316        ///
317        /// * `slice` - The [`Salt`], which must be at least 128 bits (16 bytes).
318        ///
319        /// # Errors
320        ///
321        /// This requires that the provided slice is **at least** 128 bits (16 bytes), this is the
322        /// strongest constraint as it enforces this best practice (as well as FIPS requirement).
323        /// Regardless if the interface requires this constraint it is **strongly recommended** to
324        /// use a 128 bit salt generated from a valid `CSPRNG`.
325        pub const fn new(slice: &'s [u8]) -> Result<Self, InvalidSize> {
326            if slice.len() >= 16 {
327                Ok(Self::create(slice))
328            } else {
329                Err(InvalidSize)
330            }
331        }
332    }}
333
334    impl<'s, SZ: MinSize> Slice<'s, SZ> {
335        #[inline]
336        const fn create(raw: &'s [u8]) -> Self {
337            Self { raw, _min_size: PhantomData }
338        }
339    }
340
341    macro_rules! impl_salt_try_from {
342        ($ty:ty) => {
343            impl<'s> TryFrom<&'s [u8]> for Slice<'s, $ty> {
344                type Error = <$ty as MinSize>::CreateError;
345
346                #[inline]
347                fn try_from(value: &'s [u8]) -> Result<Self, Self::Error> {
348                    Self::new(value)
349                }
350            }
351        };
352    }
353
354    impl_salt_try_from! { NonEmpty }
355    impl_salt_try_from! { Min16 }
356
357    impl<'s> From<&'s [u8]> for Slice<'s, Empty> {
358        #[inline]
359        fn from(value: &'s [u8]) -> Self {
360            Self::create(value)
361        }
362    }
363
364    impl<'s> From<&'s [u8; 16]> for Slice<'s, Min16> {
365        #[inline]
366        fn from(value: &'s [u8; 16]) -> Self {
367            Self::create(value)
368        }
369    }
370
371    impl<'s, SZ: MinSize> Sealed for Slice<'s, SZ> {}
372
373    macro_rules! impl_salt_slice {
374        ($for:ident allows $with:ident) => {
375            impl<'s> Salt<$for> for Slice<'s, $with> {
376                #[inline]
377                fn size(&self) -> u32 {
378                    debug_assert!($crate::can_cast_u32(self.raw.len()));
379                    self.raw.len() as u32
380                }
381
382                #[inline]
383                fn is_valid_size(&self) -> bool {
384                    $crate::can_cast_u32(self.raw.len())
385                }
386
387                #[inline]
388                fn i_size(&self) -> i32 {
389                    debug_assert!($crate::can_cast_i32(self.raw.len()));
390                    self.raw.len() as i32
391                }
392
393                #[inline]
394                fn i_is_valid_size(&self) -> bool {
395                    $crate::can_cast_i32(self.raw.len())
396                }
397
398                #[inline]
399                fn ptr(&self) -> *const u8 {
400                    self.raw.as_ptr()
401                }
402            }
403        };
404    }
405
406    impl_salt_slice! { Empty allows Empty }
407    impl_salt_slice! { Empty allows NonEmpty }
408    impl_salt_slice! { Empty allows Min16 }
409
410    impl_salt_slice! { NonEmpty allows NonEmpty }
411
412    impl_salt_slice! { Min16 allows Min16 }
413}
414
415/// Represents a salt value used in key derivation functions (KDFs).
416///
417/// This is only implemented for `HKDF`, as other KDFs require salts (such as the `PBKDF`
418/// family), and for FIPS compliance, as per [NIST SP 800-132, Section 5.1, The Salt (S)][1]
419/// this salt must be at least 128 bits from a valid CSPRNG.
420///
421/// Salt is a critical component in KDFs, used to:
422/// - Increase the complexity of the derived key
423/// - Mitigate rainbow table attacks
424/// - Ensure unique keys even when the same input is used multiple times
425///
426/// Salts may be optional, this depends on the `MinSz` type.
427///
428/// [1]: https://nvlpubs.nist.gov/nistpubs/Legacy/SP/nistspecialpublication800-132.pdf#%5B%7B%22num%22%3A18%2C%22gen%22%3A0%7D%2C%7B%22name%22%3A%22XYZ%22%7D%2C0%2C475%2Cnull%5D
429pub trait Salt<SZ: salt::MinSize>: Sealed {
430    #[doc(hidden)]
431    #[must_use]
432    fn size(&self) -> u32;
433
434    #[doc(hidden)]
435    #[must_use]
436    fn is_valid_size(&self) -> bool;
437
438    #[doc(hidden)]
439    #[must_use]
440    fn i_size(&self) -> i32;
441
442    #[doc(hidden)]
443    #[must_use]
444    fn i_is_valid_size(&self) -> bool;
445
446    #[doc(hidden)]
447    #[must_use]
448    fn ptr(&self) -> *const u8;
449}
450
451impl<T: Salt<salt::Min16>> Salt<salt::NonEmpty> for T {
452    #[inline]
453    fn size(&self) -> u32 {
454        <T as Salt<salt::Min16>>::size(self)
455    }
456
457    #[inline]
458    fn is_valid_size(&self) -> bool {
459        <T as Salt<salt::Min16>>::is_valid_size(self)
460    }
461
462    #[inline]
463    fn i_size(&self) -> i32 {
464        <T as Salt<salt::Min16>>::i_size(self)
465    }
466
467    #[inline]
468    fn i_is_valid_size(&self) -> bool {
469        <T as Salt<salt::Min16>>::i_is_valid_size(self)
470    }
471
472    #[inline]
473    fn ptr(&self) -> *const u8 {
474        <T as Salt<salt::Min16>>::ptr(self)
475    }
476}
477
478impl Salt<salt::Empty> for &[u8] {
479    #[inline]
480    fn size(&self) -> u32 {
481        debug_assert!(can_cast_u32(self.len()));
482        self.len() as u32
483    }
484
485    #[inline]
486    fn is_valid_size(&self) -> bool {
487        can_cast_u32(self.len())
488    }
489
490    #[inline]
491    fn i_size(&self) -> i32 {
492        debug_assert!(can_cast_i32(self.len()));
493        self.len() as i32
494    }
495
496    #[inline]
497    fn i_is_valid_size(&self) -> bool {
498        can_cast_i32(self.len())
499    }
500
501    #[inline]
502    fn ptr(&self) -> *const u8 {
503        self.as_ptr()
504    }
505}
506
507impl<const C: usize> Salt<salt::Empty> for [u8; C] {
508    #[inline]
509    fn size(&self) -> u32 {
510        debug_assert!(const_can_cast_u32::<C>());
511        self.len() as u32
512    }
513
514    #[inline]
515    fn is_valid_size(&self) -> bool {
516        const_can_cast_u32::<C>()
517    }
518
519    #[inline]
520    fn i_size(&self) -> i32 {
521        debug_assert!(const_can_cast_i32::<C>());
522        C as i32
523    }
524
525    #[inline]
526    fn i_is_valid_size(&self) -> bool {
527        const_can_cast_i32::<C>()
528    }
529
530    #[inline]
531    fn ptr(&self) -> *const u8 {
532        self.as_ptr()
533    }
534}
535
536macro_rules! impl_salt_for_sizes {
537    ($constraint:ty => [$($sz:literal),*]) => {
538        $(
539            impl Salt<$constraint> for [u8; $sz] {
540                #[inline]
541                fn size(&self) -> u32 { $sz }
542                #[inline]
543                fn is_valid_size(&self) -> bool { true }
544                #[inline]
545                fn i_size(&self) -> i32 { $sz }
546                #[inline]
547                fn i_is_valid_size(&self) -> bool { true }
548                #[inline]
549                fn ptr(&self) -> *const u8 { self.as_ptr() }
550            }
551            impl Salt<$constraint> for &[u8; $sz] {
552                #[inline]
553                fn size(&self) -> u32 { $sz }
554                #[inline]
555                fn is_valid_size(&self) -> bool { true }
556                #[inline]
557                fn i_size(&self) -> i32 { $sz }
558                #[inline]
559                fn i_is_valid_size(&self) -> bool { true }
560                #[inline]
561                fn ptr(&self) -> *const u8 { self.as_ptr() }
562            }
563        )*
564    };
565}
566
567impl_salt_for_sizes! { salt::Min16 => [
568    16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 48, 64
569]}
570
571impl_salt_for_sizes! { salt::NonEmpty => [
572    1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15
573]}
574
575impl Salt<salt::Empty> for () {
576    #[inline]
577    fn size(&self) -> u32 {
578        0
579    }
580
581    #[inline]
582    fn is_valid_size(&self) -> bool {
583        true
584    }
585
586    #[inline]
587    fn i_size(&self) -> i32 {
588        0
589    }
590
591    #[inline]
592    fn i_is_valid_size(&self) -> bool {
593        true
594    }
595
596    #[inline]
597    fn ptr(&self) -> *const u8 {
598        core::ptr::null()
599    }
600}
601
602impl<T: Salt<salt::Empty>> Salt<salt::Empty> for &T {
603    #[inline]
604    fn size(&self) -> u32 {
605        <T as Salt<salt::Empty>>::size(self)
606    }
607
608    #[inline]
609    fn is_valid_size(&self) -> bool {
610        <T as Salt<salt::Empty>>::is_valid_size(self)
611    }
612
613    #[inline]
614    fn i_size(&self) -> i32 {
615        <T as Salt<salt::Empty>>::i_size(self)
616    }
617
618    #[inline]
619    fn i_is_valid_size(&self) -> bool {
620        <T as Salt<salt::Empty>>::i_is_valid_size(self)
621    }
622
623    #[inline]
624    fn ptr(&self) -> *const u8 {
625        <T as Salt<salt::Empty>>::ptr(self)
626    }
627}
628
629impl<T: Salt<salt::Empty>> Salt<salt::Empty> for &mut T {
630    #[inline]
631    fn size(&self) -> u32 {
632        <T as Salt<salt::Empty>>::size(self)
633    }
634
635    #[inline]
636    fn is_valid_size(&self) -> bool {
637        <T as Salt<salt::Empty>>::is_valid_size(self)
638    }
639
640    #[inline]
641    fn i_size(&self) -> i32 {
642        <T as Salt<salt::Empty>>::i_size(self)
643    }
644
645    #[inline]
646    fn i_is_valid_size(&self) -> bool {
647        <T as Salt<salt::Empty>>::i_is_valid_size(self)
648    }
649
650    #[inline]
651    fn ptr(&self) -> *const u8 {
652        <T as Salt<salt::Empty>>::ptr(self)
653    }
654}
655
656impl<T: Salt<salt::Empty>> Salt<salt::Empty> for Option<T> {
657    #[inline]
658    fn size(&self) -> u32 {
659        self.as_ref().map_or(0, <T as Salt<salt::Empty>>::size)
660    }
661
662    #[inline]
663    fn is_valid_size(&self) -> bool {
664        self.as_ref().map_or(true, <T as Salt<salt::Empty>>::is_valid_size)
665    }
666
667    #[inline]
668    fn i_size(&self) -> i32 {
669        self.as_ref().map_or(0, <T as Salt<salt::Empty>>::i_size)
670    }
671
672    #[inline]
673    fn i_is_valid_size(&self) -> bool {
674        self.as_ref().map_or(true, <T as Salt<salt::Empty>>::i_is_valid_size)
675    }
676
677    #[inline]
678    fn ptr(&self) -> *const u8 {
679        self.as_ref().map_or_else(core::ptr::null, <T as Salt<salt::Empty>>::ptr)
680    }
681}
682
683/// A [`salt::Slice`] which meets the FIPS requirement (128 bits) in length.
684pub type FipsSaltSlice<'s> = salt::Slice<'s, salt::Min16>;
685/// A [`salt::Slice`] which must not be empty.
686pub type SaltSlice<'s> = salt::Slice<'s, salt::NonEmpty>;
687/// A [`salt::Slice`] which may be left empty.
688pub type MaybeSaltSlice<'s> = salt::Slice<'s, salt::Empty>;
689
690#[cfg(not(feature = "allow-non-fips"))]
691/// A [`salt::Slice`] which will be a [`FipsSaltSlice`] if the `allow-non-fips` feature is disabled,
692/// or a [`SaltSlice`] if the feature is enabled.
693///
694/// # Notes
695///
696/// - In FIPS mode (`allow-non-fips` is disabled), this type ensures that the salt meets the
697///   FIPS minimum requirement of 128 bits.
698/// - In non-FIPS mode (`allow-non-fips` is enabled), this type allows more relaxed salt constraints.
699pub type DynSaltSlice<'s> = FipsSaltSlice<'s>;
700#[cfg(feature = "allow-non-fips")]
701/// A [`salt::Slice`] which will be a [`FipsSaltSlice`] if the `allow-non-fips` feature is disabled,
702/// or a [`SaltSlice`] if the feature is enabled.
703///
704/// # Notes
705///
706/// - In FIPS mode (`allow-non-fips` is disabled), this type ensures that the salt meets the
707///   FIPS minimum requirement of 128 bits.
708/// - In non-FIPS mode (`allow-non-fips` is enabled), this type allows more relaxed salt constraints.
709pub type DynSaltSlice<'s> = SaltSlice<'s>;
710
711impl<T: Salt<salt::Min16>> crate::sealed::FipsSealed for T {}
712impl<T: Salt<salt::Min16>> crate::Fips for T {}
713
714#[cfg(test)]
715mod foolery {
716    use core::mem;
717    use super::*;
718
719    #[test]
720    fn foolery() {
721        dbg!(mem::size_of::<Option<NonZeroU32>>());
722        dbg!(mem::size_of::<Option<Iters>>());
723        dbg!(mem::align_of::<Option<Iters>>());
724        dbg!(mem::align_of::<Option<NonZeroU32>>());
725    }
726}