p3_field/
integers.rs

1//! A collection of traits and macros which convert primitive integer types into field elements.
2
3/// A macro which lets us define the function `from_Int`
4/// where `Int` can be replaced by any integer type.
5///
6/// Running, `from_integer_types!(Int)` adds the following code to a trait:
7///
8/// ```rust,ignore
9/// /// Given an integer `r`, return the sum of `r` copies of `ONE`:
10/// ///
11/// /// `r * Self::ONE =  Self::ONE + ... + Self::ONE (r times)`.
12/// ///
13/// /// Note that the output only depends on `r mod p`.
14/// ///
15/// /// This should be avoided in performance critical locations.
16/// fn from_Int(int: Int) -> Self {
17///     Self::from_prime_subfield(Self::PrimeSubfield::from_int(int))
18/// }
19/// ```
20///
21/// This macro can be run for any `Int` where `Self::PrimeSubfield` implements `QuotientMap<Int>`.
22/// It considerably cuts down on the amount of copy/pasted code.
23macro_rules! from_integer_types {
24    ($($type:ty),* $(,)? ) => {
25        $( paste::paste!{
26            /// Given an integer `r`, return the sum of `r` copies of `ONE`:
27            ///
28            /// `r * Self::ONE =  Self::ONE + ... + Self::ONE (r times)`.
29            ///
30            /// Note that the output only depends on `r mod p`.
31            ///
32            /// This should be avoided in performance critical locations.
33            fn [<from_ $type>](int: $type) -> Self {
34                Self::from_prime_subfield(Self::PrimeSubfield::from_int(int))
35            }
36        }
37        )*
38    };
39}
40
41pub(crate) use from_integer_types;
42
43/// Implementation of the quotient map `ℤ -> ℤ/p` which sends an integer `r` to its conjugacy class `[r]`.
44///
45/// This is the key trait allowing us to convert integers into field elements. Each prime field
46/// should implement this for all primitive integer types.
47pub trait QuotientMap<Int>: Sized {
48    /// Convert a given integer into an element of the field `ℤ/p`.
49    ///
50    /// This is the most generic method which makes no assumptions on the size of the input.
51    /// Where possible, this method should be used with the smallest possible integer type.
52    /// For example, if a 32-bit integer `x` is known to be less than `2^16`, then
53    /// `from_int(x as u16)` will often be faster than `from_int(x)`.
54    ///
55    /// This method is also strongly preferred over `from_canonical_checked/from_canonical_unchecked`.
56    /// It will usually be identical when `Int` is a small type, e.g. `u8/u16` and is safer for
57    /// larger types.
58    #[must_use]
59    fn from_int(int: Int) -> Self;
60
61    /// Convert a given integer into an element of the field `ℤ/p`. The input is checked to
62    /// ensure it lies within a given range.
63    /// - If `Int` is an unsigned integer type the input must lie in `[0, p - 1]`.
64    /// - If `Int` is a signed integer type the input must lie in `[-(p - 1)/2, (p - 1)/2]`.
65    ///
66    /// Return `None` if the input lies outside this range and `Some(val)` otherwise.
67    #[must_use]
68    fn from_canonical_checked(int: Int) -> Option<Self>;
69
70    /// Convert a given integer into an element of the field `ℤ/p`. The input is guaranteed
71    /// to lie within a specific range depending on `p`. If the input lies outside of this
72    /// range, the output is undefined.
73    ///
74    /// In general `from_canonical_unchecked` will be faster for either `signed` or `unsigned`
75    /// types but the specifics will depend on the field.
76    ///
77    /// # Safety
78    /// - If `Int` is an unsigned integer type then the allowed range will include `[0, p - 1]`.
79    /// - If `Int` is a signed integer type then the allowed range will include `[-(p - 1)/2, (p - 1)/2]`.
80    #[must_use]
81    unsafe fn from_canonical_unchecked(int: Int) -> Self;
82}
83
84/// This allows us to avoid some duplication which arises when working with fields which contain a generic parameter.
85///
86/// See `quotient_map_small_int` to see what this will expand to/how to call it. This is not intended for use outside of
87/// that macro.
88#[macro_export]
89macro_rules! quotient_map_small_internals {
90    ($field:ty, $field_size:ty, $small_int:ty) => {
91        #[doc = concat!("Convert a given `", stringify!($small_int), "` integer into an element of the `", stringify!($field), "` field.
92        \n Due to the integer type, the input value is always canonical.")]
93        #[inline]
94        fn from_int(int: $small_int) -> Self {
95            // Check at compile time.
96            const { assert!(size_of::<$small_int>() < size_of::<$field_size>()); }
97            unsafe {
98                Self::from_canonical_unchecked(int as $field_size)
99            }
100        }
101
102        #[doc = concat!("Convert a given `", stringify!($small_int), "` integer into an element of the `", stringify!($field), "` field.
103        \n Due to the integer type, the input value is always canonical.")]
104        #[inline]
105        fn from_canonical_checked(int: $small_int) -> Option<Self> {
106            // Check at compile time.
107            const { assert!(size_of::<$small_int>() < size_of::<$field_size>()); }
108            Some(unsafe {
109                Self::from_canonical_unchecked(int as $field_size)
110            })
111        }
112
113        #[doc = concat!("Convert a given `", stringify!($small_int), "` integer into an element of the `", stringify!($field), "` field.
114        \n Due to the integer type, the input value is always canonical.")]
115        #[inline]
116        unsafe fn from_canonical_unchecked(int: $small_int) -> Self {
117            // Check at compile time.
118            const { assert!(size_of::<$small_int>() < size_of::<$field_size>()); }
119            unsafe {
120                Self::from_canonical_unchecked(int as $field_size)
121            }
122        }
123    };
124}
125
126/// If the integer type is smaller than the field order all possible inputs are canonical.
127/// In such a case we can easily implement `QuotientMap<SmallInt>` as all three methods will coincide.
128///
129/// The range of acceptable integer types depends on the size of the field:
130/// - For 31 bit fields, `SmallInt = u8, u16, i8, i16`.
131/// - For 64 bit fields, `SmallInt = u8, u16, u32, i8, i16, i32`.
132/// - For large fields (E.g. `Bn254`), `SmallInt` can be anything except for the largest primitive integer type `u128/i128`
133///
134/// This macro accepts 3 inputs.
135/// - The name of the prime field `P`
136/// - The larger integer type `Int` which inputs should be cast to.
137/// - A list of smaller integer types to auto implement `QuotientMap<SmallInt>`.
138///
139/// Then `from_int`, `from_canonical_checked`, `from_canonical_unchecked` are all
140/// implemented by casting the input to an `Int` and using the `from_canonical_unchecked`
141/// method from `QuotientMap<Int>`.
142///
143/// For a concrete example, `quotient_map_small_int!(Mersenne31, u32, [u8])` produces the following code:
144///
145/// ```rust,ignore
146/// impl QuotientMap<u8> for Mersenne31 {
147///     /// Convert a given `u8` integer into an element of the `Mersenne31` field.
148///     ///
149///     /// Due to the integer type, the input value is always canonical.
150///     #[inline]
151///     fn from_int(int: u8) -> Mersenne31 {
152///         // Check at compile time.
153///         const { assert!(size_of::<u8>() < size_of::<u32>()); }
154///         unsafe {
155///             Self::from_canonical_unchecked(int as u32)
156///         }
157///     }
158///
159///     /// Convert a given `u8` integer into an element of the `Mersenne31` field.
160///     ///
161///     /// Due to the integer type, the input value is always canonical.
162///     #[inline]
163///     fn from_canonical_checked(int: u8) -> Option<Mersenne31> {
164///         // Check at compile time.
165///         const { assert!(size_of::<u8>() < size_of::<u32>()); }
166///         Some(unsafe {
167///             Self::from_canonical_unchecked(int as u32)
168///         })
169///     }
170///
171///     /// Convert a given `u8` integer into an element of the `Mersenne31` field.
172///     ///
173///     /// Due to the integer type, the input value is always canonical.
174///     #[inline]
175///     unsafe fn from_canonical_unchecked(int: u8) -> Mersenne31 {
176///         // Check at compile time.
177///         const { assert!(size_of::<u8>() < size_of::<u32>()); }
178///         unsafe {
179///             Self::from_canonical_unchecked(int as u32)
180///         }
181///     }
182/// }
183///```
184///
185/// Fields will often use this method twice. Once for unsigned ints and once for signed ints.
186///
187/// We need two slightly different versions for this macro as MontyField31 uses generic parameters.
188#[macro_export]
189macro_rules! quotient_map_small_int {
190    ($field:ty, $field_size:ty, [$($small_int:ty),*] ) => {
191        $(
192        paste::paste!{
193            impl QuotientMap<$small_int> for $field {
194                $crate::quotient_map_small_internals!($field, $field_size, $small_int);
195            }
196        }
197        )*
198    };
199
200    ($field:ty, $field_size:ty, $field_param:ty, [$($small_int:ty),*] ) => {
201        $(
202        paste::paste!{
203            impl<FP: $field_param> QuotientMap<$small_int> for $field<FP> {
204                $crate::quotient_map_small_internals!($field, $field_size, $small_int);
205            }
206        }
207        )*
208    };
209}
210
211/// If the unsigned integer type is large enough, there is often no method better for `from_int` than
212/// just doing a modular reduction to a smaller type.
213///
214/// This macro accepts 6 inputs.
215/// - The name of the prime field `P`
216/// - The smallest natural integer type large enough to contain the field characteristic.
217/// - The characteristic of the field.
218/// - A string giving the range for which from_canonical_checked produces the correct result.
219/// - A string giving the range for which from_canonical_unchecked produces the correct result.
220/// - A list of large integer types to auto implement `QuotientMap<LargeInt>`.
221///
222/// For a concrete example, `quotient_map_large_uint!(Mersenne31, u32, Mersenne31::ORDER_U32, "`\[0, 2^31 - 2\]`", "`\[0, 2^31 - 1\]`", [u128])` would produce the following code:
223///
224/// ```rust,ignore
225/// impl QuotientMap<u128> for Mersenne31 {
226///     /// Convert a given `u128` integer into an element of the `Mersenne31` field.
227///     ///
228///     /// Uses a modular reduction to reduce to canonical form.
229///     /// This should be avoided in performance critical locations.
230///     #[inline]
231///     fn from_int(int: u128) -> Mersenne31 {
232///         // Check at compile time.
233///         const { assert!(size_of::<u128>() > size_of::<u32>()); }
234///         let red = (int % (Mersenne31::ORDER_U32 as u128)) as u32;
235///            unsafe {
236///                // This is safe as red is less than the field order by assumption.
237///                Self::from_canonical_unchecked(red)
238///            }
239///     }
240///
241///     /// Convert a given `u128` integer into an element of the `Mersenne31` field.
242///     ///
243///     /// Returns `None` if the input does not lie in the range: [0, 2^31 - 2].
244///     #[inline]
245///     fn from_canonical_checked(int: u128) -> Option<Mersenne31> {
246///         if int < Mersenne31::ORDER_U32 as u128 {
247///             unsafe {
248///                 // This is safe as we just checked that int is less than the field order.
249///                 Some(Self::from_canonical_unchecked(int as u32))
250///             }
251///         } else {
252///             None
253///         }
254///     }
255///
256///     /// Convert a given `u128` integer into an element of the `Mersenne31` field.
257///     ///
258///     /// # Safety
259///     /// The input must lie in the range:", [0, 2^31 - 1].
260///     #[inline]
261///     unsafe fn from_canonical_unchecked(int: u128) -> Mersenne31 {
262///         unsafe {
263///             Self::from_canonical_unchecked(int as u32)
264///         }
265///     }
266/// }
267///```
268#[macro_export]
269macro_rules! quotient_map_large_uint {
270    ($field:ty, $field_size:ty, $field_order:expr, $checked_bounds:literal, $unchecked_bounds:literal, [$($large_int:ty),*] ) => {
271        $(
272        impl QuotientMap<$large_int> for $field {
273            #[doc = concat!("Convert a given `", stringify!($large_int), "` integer into an element of the `", stringify!($field), "` field.
274                \n Uses a modular reduction to reduce to canonical form. \n This should be avoided in performance critical locations.")]
275            #[inline]
276            fn from_int(int: $large_int) -> $field {
277                const { assert!(size_of::<$large_int>() > size_of::<$field_size>()); }
278                let red = (int % ($field_order as $large_int)) as $field_size;
279                unsafe {
280                    // This is safe as red is less than the field order by assumption.
281                    Self::from_canonical_unchecked(red)
282                }
283            }
284
285            #[doc = concat!("Convert a given `", stringify!($large_int), "` integer into an element of the `", stringify!($field), "` field.
286                \n Returns `None` if the input does not lie in the range:", $checked_bounds, ".")]
287            #[inline]
288            fn from_canonical_checked(int: $large_int) -> Option<$field> {
289                if int < $field_order as $large_int {
290                    unsafe {
291                        // This is safe as we just checked that int is less than the field order.
292                        Some(Self::from_canonical_unchecked(int as $field_size))
293                    }
294                } else {
295                    None
296                }
297            }
298
299            #[doc = concat!("Convert a given `", stringify!($large_int), "` integer into an element of the `", stringify!($field), "` field.")]
300            ///
301            /// # Safety
302            #[doc = concat!("The input must lie in the range:", $unchecked_bounds, ".")]
303            #[inline]
304            unsafe fn from_canonical_unchecked(int: $large_int) -> $field {
305                unsafe {
306                    Self::from_canonical_unchecked(int as $field_size)
307                }
308            }
309        }
310        )*
311    };
312}
313
314/// For large signed integer types, a simple method which is usually good enough is to simply check the sign and use this to
315/// pass to the equivalent unsigned method.
316///
317/// This will often not be the fastest implementation but should be good enough for most cases.
318///
319/// This macro accepts 4 inputs.
320/// - The name of the prime field `P`.
321/// - The smallest natural integer type large enough to contain the field characteristic.
322/// - A string giving the range for which from_canonical_checked produces the correct result.
323/// - A string giving the range for which from_canonical_unchecked produces the correct result.
324/// - A list of pairs of large sign and unsigned integer types to auto implement `QuotientMap<LargeSignInt>`.
325///
326/// For a concrete example, `quotient_map_large_iint!(Mersenne31, i32, "`\[-2^30, 2^30\]`", "`\[1 - 2^31, 2^31 - 1\]`", [(i128, u128)])` would produce the following code:
327///
328/// ```rust,ignore
329/// impl QuotientMap<i128> for Mersenne31 {
330///     /// Convert a given `i128` integer into an element of the `Mersenne31` field.
331///     ///
332///     /// This checks the sign and then makes use of the equivalent method for unsigned integers.
333///     /// This should be avoided in performance critical locations.
334///     #[inline]
335///     fn from_int(int: i128) -> Mersenne31 {
336///         if int >= 0 {
337///             Self::from_int(int as u128)
338///         } else {
339///            -Self::from_int(-int as u128)
340///         }
341///     }
342///
343///     /// Convert a given `i128` integer into an element of the `Mersenne31` field.
344///     ///
345///     /// Returns `None` if the input does not lie in the range: `[-2^30, 2^30]`.
346///     #[inline]
347///     fn from_canonical_checked(int: i128) -> Option<Mersenne31> {
348///         // We just check that int fits into an i32 now and then use the i32 method.
349///         let int_small = TryInto::<i32>::try_into(int);
350///         if int_small.is_ok() {
351///             Self::from_canonical_checked(int_small.unwrap())
352///         } else {
353///             None
354///         }
355///     }
356///
357///     /// Convert a given `i128` integer into an element of the `Mersenne31` field.
358///     ///
359///     /// # Safety
360///     /// The input must lie in the range:", `[1 - 2^31, 2^31 - 1]`.
361///     #[inline]
362///     unsafe fn from_canonical_unchecked(int: i128) -> Mersenne31 {
363///         unsafe {
364///             Self::from_canonical_unchecked(int as i32)
365///         }
366///     }
367/// }
368///```
369#[macro_export]
370macro_rules! quotient_map_large_iint {
371    ($field:ty, $field_size:ty, $checked_bounds:literal, $unchecked_bounds:literal, [$(($large_signed_int:ty, $large_int:ty)),*] ) => {
372        $(
373        impl QuotientMap<$large_signed_int> for $field {
374            #[doc = concat!("Convert a given `", stringify!($large_signed_int), "` integer into an element of the `", stringify!($field), "` field.
375                \n This checks the sign and then makes use of the equivalent method for unsigned integers. \n This should be avoided in performance critical locations.")]
376            #[inline]
377            fn from_int(int: $large_signed_int) -> $field {
378                if int >= 0 {
379                    Self::from_int(int as $large_int)
380                } else {
381                    -Self::from_int(-int as $large_int)
382                }
383            }
384
385            #[doc = concat!("Convert a given `", stringify!($large_int), "` integer into an element of the `", stringify!($field), "` field.
386                \n Returns `None` if the input does not lie in the range:", $checked_bounds, ".")]
387            #[inline]
388            fn from_canonical_checked(int: $large_signed_int) -> Option<$field> {
389                let int_small = TryInto::<$field_size>::try_into(int).ok();
390
391                // The type of the following is Option<Option<$field>>.
392                // We use the ? operator to convert it to Option<$field>, with
393                // None and Some(None) both becoming None.
394                int_small.map(Self::from_canonical_checked)?
395            }
396
397            #[doc = concat!("Convert a given `", stringify!($large_int), "` integer into an element of the `", stringify!($field), "` field.")]
398            ///
399            /// # Safety
400            #[doc = concat!("The input must lie in the range:", $unchecked_bounds, ".")]
401            #[inline]
402            unsafe fn from_canonical_unchecked(int: $large_signed_int) -> $field {
403                unsafe {
404                    Self::from_canonical_unchecked(int as $field_size)
405                }
406            }
407        }
408        )*
409    };
410}
411
412/// We implement `QuotientMap<usize>` (`QuotientMap<isize>`) by matching against the size of `usize` (`isize`)
413/// and then converting `usize` (`isize`) into the equivalent matching integer type.
414///
415/// The code is identical for both `usize` and `isize` outside of replacing some u's by i's so we use a macro
416/// to avoid the copy and paste.
417macro_rules! impl_u_i_size {
418    ($intsize:ty, $int8:ty, $int16:ty, $int32:ty, $int64:ty, $int128:ty) => {
419        impl<
420                F: QuotientMap<$int8>
421                    + QuotientMap<$int16>
422                    + QuotientMap<$int32>
423                    + QuotientMap<$int64>
424                    + QuotientMap<$int128>,
425            > QuotientMap<$intsize> for F
426        {
427            #[doc = concat!("We use the `from_int` method of the primitive integer type identical to `", stringify!($intsize), "` on this machine")]
428            fn from_int(int: $intsize) -> Self {
429                match size_of::<$intsize>() {
430                    1 => Self::from_int(int as $int8),
431                    2 => Self::from_int(int as $int16),
432                    4 => Self::from_int(int as $int32),
433                    8 => Self::from_int(int as $int64),
434                    16 => Self::from_int(int as $int128),
435                    _ => unreachable!(concat!(stringify!($intsize), "is not equivalent to any primitive integer types.")),
436                }
437            }
438
439            #[doc = concat!("We use the `from_canonical_checked` method of the primitive integer type identical to `", stringify!($intsize), "` on this machine")]
440            fn from_canonical_checked(int: $intsize) -> Option<Self> {
441                match size_of::<$intsize>() {
442                    1 => Self::from_canonical_checked(int as $int8),
443                    2 => Self::from_canonical_checked(int as $int16),
444                    4 => Self::from_canonical_checked(int as $int32),
445                    8 => Self::from_canonical_checked(int as $int64),
446                    16 => Self::from_canonical_checked(int as $int128),
447                    _ => unreachable!(concat!(stringify!($intsize), " is not equivalent to any primitive integer types.")),
448                }
449            }
450
451            #[doc = concat!("We use the `from_canonical_unchecked` method of the primitive integer type identical to `", stringify!($intsize), "` on this machine")]
452            unsafe fn from_canonical_unchecked(int: $intsize) -> Self {
453                unsafe {
454                    match size_of::<$intsize>() {
455                        1 => Self::from_canonical_unchecked(int as $int8),
456                        2 => Self::from_canonical_unchecked(int as $int16),
457                        4 => Self::from_canonical_unchecked(int as $int32),
458                        8 => Self::from_canonical_unchecked(int as $int64),
459                        16 => Self::from_canonical_unchecked(int as $int128),
460                        _ => unreachable!(concat!(stringify!($intsize), " is not equivalent to any primitive integer types.")),
461                    }
462                }
463            }
464        }
465    };
466}
467
468impl_u_i_size!(usize, u8, u16, u32, u64, u128);
469impl_u_i_size!(isize, i8, i16, i32, i64, i128);
470
471/// A simple macro which allows us to implement the `RawSerializable` trait for any 32-bit field.
472/// The field must implement PrimeField32.
473///
474/// This macro doesn't need any inputs as the implementation is identical for all 32-bit fields.
475#[macro_export]
476macro_rules! impl_raw_serializable_primefield32 {
477    () => {
478        const NUM_BYTES: usize = 4;
479
480        #[allow(refining_impl_trait)]
481        #[inline]
482        fn into_bytes(self) -> [u8; 4] {
483            self.to_unique_u32().to_le_bytes()
484        }
485
486        #[inline]
487        fn into_u32_stream(input: impl IntoIterator<Item = Self>) -> impl IntoIterator<Item = u32> {
488            // As every element is 32 bits, we can just convert the input to a unique u32.
489            input.into_iter().map(|x| x.to_unique_u32())
490        }
491
492        #[inline]
493        fn into_u64_stream(input: impl IntoIterator<Item = Self>) -> impl IntoIterator<Item = u64> {
494            let mut input = input.into_iter();
495            iter::from_fn(move || {
496                // If the first input.next() returns None, we return None.
497                let a = input.next()?;
498                // Otherwise we either pack 2 32 bit elements together if the iterator
499                // gives a second value or just cast the 32 bit element to 64 bits.
500                if let Some(b) = input.next() {
501                    Some(a.to_unique_u64() | b.to_unique_u64() << 32)
502                } else {
503                    Some(a.to_unique_u64())
504                }
505            })
506        }
507
508        #[inline]
509        fn into_parallel_byte_streams<const N: usize>(
510            input: impl IntoIterator<Item = [Self; N]>,
511        ) -> impl IntoIterator<Item = [u8; N]> {
512            input.into_iter().flat_map(|vector| {
513                let bytes = vector.map(|elem| elem.into_bytes());
514                (0..Self::NUM_BYTES).map(move |i| array::from_fn(|j| bytes[j][i]))
515            })
516        }
517
518        #[inline]
519        fn into_parallel_u32_streams<const N: usize>(
520            input: impl IntoIterator<Item = [Self; N]>,
521        ) -> impl IntoIterator<Item = [u32; N]> {
522            // As every element is 32 bits, we can just convert the input to a unique u32.
523            input.into_iter().map(|vec| vec.map(|x| x.to_unique_u32()))
524        }
525
526        #[inline]
527        fn into_parallel_u64_streams<const N: usize>(
528            input: impl IntoIterator<Item = [Self; N]>,
529        ) -> impl IntoIterator<Item = [u64; N]> {
530            let mut input = input.into_iter();
531            iter::from_fn(move || {
532                // If the first input.next() returns None, we return None.
533                let a = input.next()?;
534                // Otherwise we either pack pairs of 32 bit elements together if the iterator
535                // gives two arrays of or just cast the 32 bit elements to 64 bits.
536                if let Some(b) = input.next() {
537                    let ab = array::from_fn(|i| {
538                        let ai = a[i].to_unique_u64();
539                        let bi = b[i].to_unique_u64();
540                        ai | (bi << 32)
541                    });
542                    Some(ab)
543                } else {
544                    Some(a.map(|x| x.to_unique_u64()))
545                }
546            })
547        }
548    };
549}
550
551/// A simple macro which allows us to implement the `RawSerializable` trait for any 64-bit field.
552/// The field must implement PrimeField64 (and should not implement PrimeField32).
553///
554/// This macro doesn't need any inputs as the implementation is identical for all 64-bit fields.
555#[macro_export]
556macro_rules! impl_raw_serializable_primefield64 {
557    () => {
558        const NUM_BYTES: usize = 8;
559
560        #[allow(refining_impl_trait)]
561        #[inline]
562        fn into_bytes(self) -> [u8; 8] {
563            self.to_unique_u64().to_le_bytes()
564        }
565
566        #[inline]
567        fn into_u32_stream(input: impl IntoIterator<Item = Self>) -> impl IntoIterator<Item = u32> {
568            input.into_iter().flat_map(|x| {
569                let x_u64 = x.to_unique_u64();
570                [x_u64 as u32, (x_u64 >> 32) as u32]
571            })
572        }
573
574        #[inline]
575        fn into_u64_stream(input: impl IntoIterator<Item = Self>) -> impl IntoIterator<Item = u64> {
576            // As every element is 64 bits, we can just convert the input to a unique u64.
577            input.into_iter().map(|x| x.to_unique_u64())
578        }
579
580        #[inline]
581        fn into_parallel_byte_streams<const N: usize>(
582            input: impl IntoIterator<Item = [Self; N]>,
583        ) -> impl IntoIterator<Item = [u8; N]> {
584            input.into_iter().flat_map(|vector| {
585                let bytes = vector.map(|elem| elem.into_bytes());
586                (0..Self::NUM_BYTES).map(move |i| array::from_fn(|j| bytes[j][i]))
587            })
588        }
589
590        #[inline]
591        fn into_parallel_u32_streams<const N: usize>(
592            input: impl IntoIterator<Item = [Self; N]>,
593        ) -> impl IntoIterator<Item = [u32; N]> {
594            input.into_iter().flat_map(|vec| {
595                let vec_64 = vec.map(|x| x.to_unique_u64());
596                let vec_32_lo = vec_64.map(|x| x as u32);
597                let vec_32_hi = vec_64.map(|x| (x >> 32) as u32);
598                [vec_32_lo, vec_32_hi]
599            })
600        }
601
602        #[inline]
603        fn into_parallel_u64_streams<const N: usize>(
604            input: impl IntoIterator<Item = [Self; N]>,
605        ) -> impl IntoIterator<Item = [u64; N]> {
606            // As every element is 64 bits, we can just convert the input to a unique u64.
607            input.into_iter().map(|vec| vec.map(|x| x.to_unique_u64()))
608        }
609    };
610}