ruint/
bytes.rs

1use crate::Uint;
2use core::slice;
3
4#[cfg(feature = "alloc")]
5#[allow(unused_imports)]
6use alloc::{borrow::Cow, vec::Vec};
7
8// OPT: *_to_smallvec to avoid allocation.
9impl<const BITS: usize, const LIMBS: usize> Uint<BITS, LIMBS> {
10    /// The size of this integer type in bytes. Note that some bits may be
11    /// forced zero if BITS is not cleanly divisible by eight.
12    pub const BYTES: usize = BITS.div_ceil(8);
13
14    /// Access the underlying store as a little-endian slice of bytes.
15    ///
16    /// Only available on little-endian targets.
17    ///
18    /// If `BITS` does not evenly divide 8, it is padded with zero bits in the
19    /// most significant position.
20    #[cfg(target_endian = "little")]
21    #[must_use]
22    #[inline(always)]
23    pub const fn as_le_slice(&self) -> &[u8] {
24        unsafe { slice::from_raw_parts(self.limbs.as_ptr().cast(), Self::BYTES) }
25    }
26
27    /// Access the underlying store as a mutable little-endian slice of bytes.
28    ///
29    /// Only available on litte-endian targets.
30    ///
31    /// # Safety
32    ///
33    /// If `BITS` does not evenly divide 8, it is padded with zero bits in the
34    /// most significant position. Setting those bits puts the [`Uint`] in an
35    /// invalid state.
36    #[cfg(target_endian = "little")]
37    #[must_use]
38    #[inline(always)]
39    pub const unsafe fn as_le_slice_mut(&mut self) -> &mut [u8] {
40        unsafe { slice::from_raw_parts_mut(self.limbs.as_mut_ptr().cast(), Self::BYTES) }
41    }
42
43    /// Access the underlying store as a little-endian bytes.
44    ///
45    /// Uses an optimized implementation on little-endian targets.
46    #[cfg(feature = "alloc")]
47    #[must_use]
48    #[inline]
49    #[cfg_attr(target_endian = "little", allow(clippy::missing_const_for_fn))] // Not const in big-endian.
50    pub fn as_le_bytes(&self) -> Cow<'_, [u8]> {
51        // On little endian platforms this is a no-op.
52        #[cfg(target_endian = "little")]
53        return Cow::Borrowed(self.as_le_slice());
54
55        // In others, reverse each limb and return a copy.
56        #[cfg(target_endian = "big")]
57        return Cow::Owned({
58            let mut limbs = self.limbs;
59            for limb in &mut limbs {
60                *limb = limb.swap_bytes();
61            }
62            unsafe { slice::from_raw_parts(limbs.as_ptr().cast(), Self::BYTES).to_vec() }
63        });
64    }
65
66    /// Access the underlying store as a little-endian bytes with trailing zeros
67    /// removed.
68    ///
69    /// Uses an optimized implementation on little-endian targets.
70    #[cfg(feature = "alloc")]
71    #[must_use]
72    #[inline]
73    pub fn as_le_bytes_trimmed(&self) -> Cow<'_, [u8]> {
74        match self.as_le_bytes() {
75            Cow::Borrowed(slice) => Cow::Borrowed(crate::utils::trim_end_slice(slice, &0)),
76            Cow::Owned(mut vec) => {
77                crate::utils::trim_end_vec(&mut vec, &0);
78                Cow::Owned(vec)
79            }
80        }
81    }
82
83    /// Converts the [`Uint`] to a little-endian byte array of size exactly
84    /// [`Self::BYTES`].
85    ///
86    /// # Panics
87    ///
88    /// Panics if the generic parameter `BYTES` is not exactly [`Self::BYTES`].
89    /// Ideally this would be a compile time error, but this is blocked by
90    /// Rust issue [#60551].
91    ///
92    /// [#60551]: https://github.com/rust-lang/rust/issues/60551
93    #[inline]
94    #[must_use]
95    pub const fn to_le_bytes<const BYTES: usize>(&self) -> [u8; BYTES] {
96        const { Self::assert_bytes(BYTES) }
97
98        // Specialized impl
99        #[cfg(target_endian = "little")]
100        // SAFETY: BYTES == Self::BYTES == self.as_le_slice().len()
101        return unsafe { *self.as_le_slice().as_ptr().cast() };
102
103        // Generic impl
104        #[cfg(target_endian = "big")]
105        {
106            let mut limbs = self.limbs;
107            let mut i = 0;
108            while i < LIMBS {
109                limbs[i] = limbs[i].to_le();
110                i += 1;
111            }
112            // SAFETY: BYTES <= LIMBS * 8
113            unsafe { *limbs.as_ptr().cast() }
114        }
115    }
116
117    /// Converts the [`Uint`] to a little-endian byte vector of size exactly
118    /// [`Self::BYTES`].
119    ///
120    /// This method is useful when [`Self::to_le_bytes`] can not be used because
121    /// byte size is not known compile time.
122    #[cfg(feature = "alloc")]
123    #[must_use]
124    #[inline]
125    pub fn to_le_bytes_vec(&self) -> Vec<u8> {
126        self.as_le_bytes().into_owned()
127    }
128
129    /// Converts the [`Uint`] to a little-endian byte vector with trailing zeros
130    /// bytes removed.
131    #[cfg(feature = "alloc")]
132    #[must_use]
133    #[inline]
134    pub fn to_le_bytes_trimmed_vec(&self) -> Vec<u8> {
135        self.as_le_bytes_trimmed().into_owned()
136    }
137
138    /// Converts the [`Uint`] to a big-endian byte array of size exactly
139    /// [`Self::BYTES`].
140    ///
141    /// # Panics
142    ///
143    /// Panics if the generic parameter `BYTES` is not exactly [`Self::BYTES`].
144    /// Ideally this would be a compile time error, but this is blocked by
145    /// Rust issue [#60551].
146    ///
147    /// [#60551]: https://github.com/rust-lang/rust/issues/60551
148    #[must_use]
149    #[inline]
150    pub const fn to_be_bytes<const BYTES: usize>(&self) -> [u8; BYTES] {
151        let mut bytes = self.to_le_bytes::<BYTES>();
152
153        // bytes.reverse()
154        let len = bytes.len();
155        let half_len = len / 2;
156        let mut i = 0;
157        while i < half_len {
158            let tmp = bytes[i];
159            bytes[i] = bytes[len - 1 - i];
160            bytes[len - 1 - i] = tmp;
161            i += 1;
162        }
163
164        bytes
165    }
166
167    /// Converts the [`Uint`] to a big-endian byte vector of size exactly
168    /// [`Self::BYTES`].
169    ///
170    /// This method is useful when [`Self::to_be_bytes`] can not be used because
171    /// byte size is not known compile time.
172    #[cfg(feature = "alloc")]
173    #[must_use]
174    #[inline]
175    pub fn to_be_bytes_vec(&self) -> Vec<u8> {
176        let mut bytes = self.to_le_bytes_vec();
177        bytes.reverse();
178        bytes
179    }
180
181    /// Converts the [`Uint`] to a big-endian byte vector with leading zeros
182    /// bytes removed.
183    #[cfg(feature = "alloc")]
184    #[must_use]
185    #[inline]
186    pub fn to_be_bytes_trimmed_vec(&self) -> Vec<u8> {
187        let mut bytes = self.to_le_bytes_trimmed_vec();
188        bytes.reverse();
189        bytes
190    }
191
192    /// Converts a big-endian byte array of size exactly
193    /// [`Self::BYTES`] to [`Uint`].
194    ///
195    /// # Panics
196    ///
197    /// Panics if the generic parameter `BYTES` is not exactly [`Self::BYTES`].
198    /// Ideally this would be a compile time error, but this is blocked by
199    /// Rust issue [#60551].
200    ///
201    /// [#60551]: https://github.com/rust-lang/rust/issues/60551
202    ///
203    /// Panics if the value is too large for the bit-size of the Uint.
204    #[must_use]
205    #[track_caller]
206    #[inline]
207    pub const fn from_be_bytes<const BYTES: usize>(bytes: [u8; BYTES]) -> Self {
208        const { Self::assert_bytes(BYTES) }
209        Self::from_be_slice(&bytes)
210    }
211
212    /// Creates a new integer from a big endian slice of bytes.
213    ///
214    /// The slice is interpreted as a big endian number, and must be at most
215    /// [`Self::BYTES`] long.
216    ///
217    /// # Panics
218    ///
219    /// Panics if the value is larger than fits the [`Uint`].
220    #[must_use]
221    #[track_caller]
222    #[inline]
223    pub const fn from_be_slice(bytes: &[u8]) -> Self {
224        match Self::try_from_be_slice(bytes) {
225            Some(value) => value,
226            None => panic!("Value too large for Uint"),
227        }
228    }
229
230    /// Creates a new integer from a big endian slice of bytes.
231    ///
232    /// The slice is interpreted as a big endian number, and must be at most
233    /// [`Self::BYTES`] long.
234    ///
235    /// Returns [`None`] if the value is larger than fits the [`Uint`].
236    #[must_use]
237    #[inline]
238    pub const fn try_from_be_slice(bytes: &[u8]) -> Option<Self> {
239        if bytes.len() > Self::BYTES {
240            return None;
241        }
242
243        if Self::BYTES % 8 == 0 && bytes.len() == Self::BYTES {
244            // Optimized implementation for full-limb types.
245            let mut limbs = [0; LIMBS];
246            let end = bytes.as_ptr_range().end;
247            let mut i = 0;
248            while i < LIMBS {
249                limbs[i] = u64::from_be_bytes(unsafe { *end.sub((i + 1) * 8).cast() });
250                i += 1;
251            }
252            return Some(Self::from_limbs(limbs));
253        }
254
255        let mut limbs = [0; LIMBS];
256        let mut i = 0;
257        let mut c = bytes.len();
258        while i < bytes.len() {
259            c -= 1;
260            let (limb, byte) = (i / 8, i % 8);
261            limbs[limb] += (bytes[c] as u64) << (byte * 8);
262            i += 1;
263        }
264        if LIMBS > 0 && limbs[LIMBS - 1] > Self::MASK {
265            return None;
266        }
267        Some(Self::from_limbs(limbs))
268    }
269
270    /// Converts a little-endian byte array of size exactly
271    /// [`Self::BYTES`] to [`Uint`].
272    ///
273    /// # Panics
274    ///
275    /// Panics if the generic parameter `BYTES` is not exactly [`Self::BYTES`].
276    /// Ideally this would be a compile time error, but this is blocked by
277    /// Rust issue [#60551].
278    ///
279    /// [#60551]: https://github.com/rust-lang/rust/issues/60551
280    ///
281    /// Panics if the value is too large for the bit-size of the Uint.
282    #[must_use]
283    #[track_caller]
284    #[inline]
285    pub const fn from_le_bytes<const BYTES: usize>(bytes: [u8; BYTES]) -> Self {
286        const { Self::assert_bytes(BYTES) }
287        Self::from_le_slice(&bytes)
288    }
289
290    /// Creates a new integer from a little endian slice of bytes.
291    ///
292    /// The slice is interpreted as a little endian number, and must be at most
293    /// [`Self::BYTES`] long.
294    ///
295    /// # Panics
296    ///
297    /// Panics if the value is larger than fits the [`Uint`].
298    #[must_use]
299    #[track_caller]
300    #[inline]
301    pub const fn from_le_slice(bytes: &[u8]) -> Self {
302        match Self::try_from_le_slice(bytes) {
303            Some(value) => value,
304            None => panic!("Value too large for Uint"),
305        }
306    }
307
308    /// Creates a new integer from a little endian slice of bytes.
309    ///
310    /// The slice is interpreted as a little endian number, and must be at most
311    /// [`Self::BYTES`] long.
312    ///
313    /// Returns [`None`] if the value is larger than fits the [`Uint`].
314    #[must_use]
315    #[inline]
316    pub const fn try_from_le_slice(bytes: &[u8]) -> Option<Self> {
317        if bytes.len() > Self::BYTES {
318            return None;
319        }
320
321        if Self::BYTES % 8 == 0 && bytes.len() == Self::BYTES {
322            // Optimized implementation for full-limb types.
323            let mut limbs = [0; LIMBS];
324            let mut i = 0;
325            while i < LIMBS {
326                limbs[i] = u64::from_le_bytes(unsafe { *bytes.as_ptr().add(i * 8).cast() });
327                i += 1;
328            }
329            return Some(Self::from_limbs(limbs));
330        }
331
332        let mut limbs = [0; LIMBS];
333        let mut i = 0;
334        while i < bytes.len() {
335            let (limb, byte) = (i / 8, i % 8);
336            limbs[limb] += (bytes[i] as u64) << (byte * 8);
337            i += 1;
338        }
339        if LIMBS > 0 && limbs[LIMBS - 1] > Self::MASK {
340            return None;
341        }
342        Some(Self::from_limbs(limbs))
343    }
344
345    /// Writes the little-endian representation of the [`Uint`] to the given
346    /// buffer. The buffer must be large enough to hold [`Self::BYTES`] bytes.
347    ///
348    /// # Panics
349    ///
350    /// Panics if the buffer is not large enough to hold [`Self::BYTES`] bytes.
351    ///
352    /// # Returns
353    ///
354    /// The number of bytes written to the buffer (always equal to
355    /// [`Self::BYTES`], but often useful to make explicit for encoders).
356    #[inline]
357    pub fn copy_le_bytes_to(&self, buf: &mut [u8]) -> usize {
358        // This is debug only. Release panics occur later in copy_from_slice
359        debug_assert!(
360            buf.len() >= Self::BYTES,
361            "Buffer is too small to hold the bytes of the Uint"
362        );
363
364        #[cfg(target_endian = "little")]
365        buf[..Self::BYTES].copy_from_slice(self.as_le_slice());
366
367        #[cfg(target_endian = "big")]
368        {
369            let chunks = buf[..Self::BYTES].chunks_mut(8);
370
371            self.limbs.iter().zip(chunks).for_each(|(&limb, chunk)| {
372                let le = limb.to_le_bytes();
373                chunk.copy_from_slice(&le[..chunk.len()]);
374            });
375        }
376
377        Self::BYTES
378    }
379
380    /// Writes the little-endian representation of the [`Uint`] to the given
381    /// buffer. The buffer must be large enough to hold [`Self::BYTES`] bytes.
382    ///
383    /// # Returns
384    ///
385    /// [`None`], if the buffer is not large enough to hold [`Self::BYTES`]
386    /// bytes, and does not modify the buffer.
387    ///
388    /// [`Some`] with the number of bytes written to the buffer (always
389    /// equal to [`Self::BYTES`], but often useful to make explicit for
390    /// encoders).
391    #[inline]
392    pub fn checked_copy_le_bytes_to(&self, buf: &mut [u8]) -> Option<usize> {
393        if buf.len() < Self::BYTES {
394            return None;
395        }
396
397        Some(self.copy_le_bytes_to(buf))
398    }
399
400    /// Writes the big-endian representation of the [`Uint`] to the given
401    /// buffer. The buffer must be large enough to hold [`Self::BYTES`] bytes.
402    ///
403    /// # Panics
404    ///
405    /// Panics if the buffer is not large enough to hold [`Self::BYTES`] bytes.
406    ///
407    /// # Returns
408    ///
409    /// The number of bytes written to the buffer (always equal to
410    /// [`Self::BYTES`], but often useful to make explicit for encoders).
411    #[inline]
412    pub fn copy_be_bytes_to(&self, buf: &mut [u8]) -> usize {
413        // This is debug only. Release panics occur later in copy_from_slice
414        debug_assert!(
415            buf.len() >= Self::BYTES,
416            "Buffer is too small to hold the bytes of the Uint"
417        );
418
419        // start from the end of the slice
420        let chunks = buf[..Self::BYTES].rchunks_mut(8);
421
422        self.limbs.iter().zip(chunks).for_each(|(&limb, chunk)| {
423            let be = limb.to_be_bytes();
424            let copy_from = 8 - chunk.len();
425            chunk.copy_from_slice(&be[copy_from..]);
426        });
427
428        Self::BYTES
429    }
430
431    /// Writes the big-endian representation of the [`Uint`] to the given
432    /// buffer. The buffer must be large enough to hold [`Self::BYTES`] bytes.
433    ///
434    /// # Returns
435    ///
436    /// [`None`], if the buffer is not large enough to hold [`Self::BYTES`]
437    /// bytes, and does not modify the buffer.
438    ///
439    /// [`Some`] with the number of bytes written to the buffer (always
440    /// equal to [`Self::BYTES`], but often useful to make explicit for
441    /// encoders).
442    #[inline]
443    pub fn checked_copy_be_bytes_to(&self, buf: &mut [u8]) -> Option<usize> {
444        if buf.len() < Self::BYTES {
445            return None;
446        }
447
448        Some(self.copy_be_bytes_to(buf))
449    }
450
451    #[track_caller]
452    const fn assert_bytes(bytes: usize) {
453        assert!(bytes == Self::BYTES, "BYTES must be equal to Self::BYTES");
454    }
455}
456
457/// Number of bytes required to represent the given number of bits.
458///
459/// This needs to be public because it is used in the `Uint` type,
460/// specifically in the [`to_be_bytes()`][Uint::to_be_bytes] and related
461/// functions.
462#[inline]
463#[must_use]
464pub const fn nbytes(bits: usize) -> usize {
465    bits.div_ceil(8)
466}
467
468#[cfg(test)]
469mod tests {
470    use super::*;
471    use crate::{const_for, nlimbs};
472    use proptest::proptest;
473
474    const N: Uint<128, 2> =
475        Uint::from_limbs([0x7890_1234_5678_9012_u64, 0x1234_5678_9012_3456_u64]);
476    const BE: [u8; 16] = [
477        0x12, 0x34, 0x56, 0x78, 0x90, 0x12, 0x34, 0x56, 0x78, 0x90, 0x12, 0x34, 0x56, 0x78, 0x90,
478        0x12,
479    ];
480    const LE: [u8; 16] = [
481        0x12, 0x90, 0x78, 0x56, 0x34, 0x12, 0x90, 0x78, 0x56, 0x34, 0x12, 0x90, 0x78, 0x56, 0x34,
482        0x12,
483    ];
484
485    const K: Uint<72, 2> = Uint::from_limbs([0x3456_7890_1234_5678_u64, 0x12_u64]);
486    const KBE: [u8; 9] = [0x12, 0x34, 0x56, 0x78, 0x90, 0x12, 0x34, 0x56, 0x78];
487    const KLE: [u8; 9] = [0x78, 0x56, 0x34, 0x12, 0x90, 0x78, 0x56, 0x34, 0x12];
488
489    #[test]
490    const fn const_from_to_bytes() {
491        const NL: [u64; 2] = N.limbs;
492        const KL: [u64; 2] = K.limbs;
493        assert!(matches!(Uint::<128, 2>::from_be_bytes(BE).limbs, NL));
494        assert!(matches!(Uint::<128, 2>::from_le_bytes(LE).limbs, NL));
495        assert!(matches!(N.to_be_bytes::<{ BE.len() }>(), BE));
496        assert!(matches!(N.to_le_bytes::<{ LE.len() }>(), LE));
497
498        assert!(matches!(Uint::<72, 2>::from_be_bytes(KBE).limbs, KL));
499        assert!(matches!(Uint::<72, 2>::from_le_bytes(KLE).limbs, KL));
500        assert!(matches!(K.to_be_bytes::<{ KBE.len() }>(), KBE));
501        assert!(matches!(K.to_le_bytes::<{ KLE.len() }>(), KLE));
502
503        assert!(matches!(Uint::<0, 0>::ZERO.to_be_bytes::<0>(), []));
504        assert!(matches!(Uint::<1, 1>::ZERO.to_be_bytes::<1>(), [0]));
505        assert!(matches!(
506            Uint::<1, 1>::from_limbs([1]).to_be_bytes::<1>(),
507            [1]
508        ));
509        assert!(matches!(
510            Uint::<16, 1>::from_limbs([0x1234]).to_be_bytes::<2>(),
511            [0x12, 0x34]
512        ));
513
514        assert!(matches!(Uint::<0, 0>::ZERO.to_be_bytes::<0>(), []));
515        assert!(matches!(Uint::<0, 0>::ZERO.to_le_bytes::<0>(), []));
516        assert!(matches!(Uint::<1, 1>::ZERO.to_be_bytes::<1>(), [0]));
517        assert!(matches!(Uint::<1, 1>::ZERO.to_le_bytes::<1>(), [0]));
518        assert!(matches!(
519            Uint::<1, 1>::from_limbs([1]).to_be_bytes::<1>(),
520            [1]
521        ));
522        assert!(matches!(
523            Uint::<1, 1>::from_limbs([1]).to_le_bytes::<1>(),
524            [1]
525        ));
526        assert!(matches!(
527            Uint::<16, 1>::from_limbs([0x1234]).to_be_bytes::<2>(),
528            [0x12, 0x34]
529        ));
530        assert!(matches!(
531            Uint::<16, 1>::from_limbs([0x1234]).to_le_bytes::<2>(),
532            [0x34, 0x12]
533        ));
534
535        assert!(matches!(
536            Uint::<63, 1>::from_limbs([0x010203]).to_be_bytes::<8>(),
537            [0, 0, 0, 0, 0, 1, 2, 3]
538        ));
539        assert!(matches!(
540            Uint::<63, 1>::from_limbs([0x010203]).to_le_bytes::<8>(),
541            [3, 2, 1, 0, 0, 0, 0, 0]
542        ));
543    }
544
545    #[test]
546    fn test_from_bytes() {
547        assert_eq!(Uint::<0, 0>::from_be_bytes([]), Uint::ZERO);
548        assert_eq!(Uint::<0, 0>::from_le_bytes([]), Uint::ZERO);
549        assert_eq!(
550            Uint::<12, 1>::from_be_bytes([0x01, 0x23]),
551            Uint::from(0x0123)
552        );
553        assert_eq!(
554            Uint::<12, 1>::from_le_bytes([0x23, 0x01]),
555            Uint::from(0x0123)
556        );
557        assert_eq!(
558            Uint::<16, 1>::from_be_bytes([0x12, 0x34]),
559            Uint::from(0x1234)
560        );
561        assert_eq!(
562            Uint::<16, 1>::from_le_bytes([0x34, 0x12]),
563            Uint::from(0x1234)
564        );
565
566        assert_eq!(Uint::from_be_bytes(BE), N);
567        assert_eq!(Uint::from_le_bytes(LE), N);
568        assert_eq!(Uint::from_be_bytes(KBE), K);
569        assert_eq!(Uint::from_le_bytes(KLE), K);
570
571        assert_eq!(Uint::<128, 2>::try_from_be_slice(&BE), Some(N));
572        assert_eq!(
573            Uint::<128, 2>::try_from_be_slice(&[&BE[..], &[0xff][..]].concat()),
574            None
575        );
576        assert_eq!(Uint::<128, 2>::try_from_le_slice(&LE), Some(N));
577        assert_eq!(
578            Uint::<128, 2>::try_from_le_slice(&[&LE[..], &[0xff]].concat()),
579            None
580        );
581        assert_eq!(Uint::<72, 2>::try_from_be_slice(&KBE), Some(K));
582        assert_eq!(
583            Uint::<72, 2>::try_from_be_slice(&[&KBE[..], &[0xff][..]].concat()),
584            None
585        );
586        assert_eq!(Uint::<72, 2>::try_from_le_slice(&KLE), Some(K));
587        assert_eq!(
588            Uint::<72, 2>::try_from_le_slice(&[&KLE[..], &[0xff]].concat()),
589            None
590        );
591    }
592
593    #[test]
594    fn test_to_bytes() {
595        assert_eq!(Uint::<0, 0>::ZERO.to_le_bytes(), [0_u8; 0]);
596        assert_eq!(Uint::<0, 0>::ZERO.to_be_bytes(), [0_u8; 0]);
597        assert_eq!(Uint::<12, 1>::from(0x0123_u64).to_le_bytes(), [0x23, 0x01]);
598        assert_eq!(Uint::<12, 1>::from(0x0123_u64).to_be_bytes(), [0x01, 0x23]);
599        assert_eq!(Uint::<16, 1>::from(0x1234_u64).to_le_bytes(), [0x34, 0x12]);
600        assert_eq!(Uint::<16, 1>::from(0x1234_u64).to_be_bytes(), [0x12, 0x34]);
601        assert_eq!(K.to_be_bytes(), KBE);
602        assert_eq!(K.to_le_bytes(), KLE);
603    }
604
605    #[test]
606    fn test_bytes_roundtrip() {
607        const_for!(BITS in SIZES {
608            const LIMBS: usize = nlimbs(BITS);
609            const BYTES: usize = nbytes(BITS);
610            proptest!(|(value: Uint<BITS, LIMBS>)| {
611                assert_eq!(value, Uint::try_from_le_slice(&value.as_le_bytes()).unwrap());
612                assert_eq!(value, Uint::try_from_le_slice(&value.as_le_bytes_trimmed()).unwrap());
613                assert_eq!(value, Uint::try_from_be_slice(&value.to_be_bytes_trimmed_vec()).unwrap());
614                assert_eq!(value, Uint::try_from_le_slice(&value.to_le_bytes_trimmed_vec()).unwrap());
615                assert_eq!(value, Uint::from_be_bytes(value.to_be_bytes::<BYTES>()));
616                assert_eq!(value, Uint::from_le_bytes(value.to_le_bytes::<BYTES>()));
617            });
618        });
619    }
620
621    #[test]
622    fn copy_to() {
623        const_for!(BITS in SIZES {
624            const LIMBS: usize = nlimbs(BITS);
625            const BYTES: usize = nbytes(BITS);
626            proptest!(|(value: Uint<BITS, LIMBS>)|{
627                let mut buf = [0; BYTES];
628                value.copy_le_bytes_to(&mut buf);
629                assert_eq!(buf, value.to_le_bytes::<BYTES>());
630                assert_eq!(value, Uint::try_from_le_slice(&buf).unwrap());
631
632                let mut buf = [0; BYTES];
633                value.copy_be_bytes_to(&mut buf);
634                assert_eq!(buf, value.to_be_bytes::<BYTES>());
635                assert_eq!(value, Uint::try_from_be_slice(&buf).unwrap());
636            });
637        });
638    }
639
640    #[test]
641    fn checked_copy_to() {
642        const_for!(BITS in SIZES {
643            const LIMBS: usize = nlimbs(BITS);
644            const BYTES: usize = nbytes(BITS);
645            proptest!(|(value: Uint<BITS, LIMBS>)|{
646                if BYTES != 0 {
647                    let mut buf = [0; BYTES];
648                    let too_short = buf.len() - 1;
649
650                    assert_eq!(value.checked_copy_le_bytes_to(&mut buf[..too_short]), None);
651                    assert_eq!(buf, [0; BYTES], "buffer was modified");
652
653                    assert_eq!(value.checked_copy_be_bytes_to(&mut buf[..too_short]), None);
654                    assert_eq!(buf, [0; BYTES], "buffer was modified");
655                }
656            });
657        });
658    }
659}