Skip to main content

crypto_bigint/
uint.rs

1//! Stack-allocated big unsigned integers.
2
3#[cfg(feature = "extra-sizes")]
4pub use extra_sizes::*;
5
6pub(crate) use ref_type::UintRef;
7
8use crate::{
9    Bounded, Choice, ConstOne, ConstZero, Constants, CtEq, CtOption, EncodedUint, FixedInteger,
10    Int, Integer, Limb, NonZero, Odd, One, Unsigned, UnsignedWithMontyForm, Word, Zero,
11    limb::nlimbs, modular::FixedMontyForm, primitives::u32_bits,
12};
13use core::fmt;
14
15#[cfg(feature = "serde")]
16use crate::Encoding;
17#[cfg(feature = "serde")]
18use serdect::serde::{Deserialize, Deserializer, Serialize, Serializer};
19#[cfg(feature = "zeroize")]
20use zeroize::DefaultIsZeroes;
21
22#[cfg(doc)]
23use crate::{NonZeroUint, OddUint};
24
25#[macro_use]
26mod macros;
27
28mod add;
29mod add_mod;
30mod bit_and;
31mod bit_not;
32mod bit_or;
33mod bit_xor;
34mod bits;
35mod cmp;
36mod concat;
37mod ct;
38mod div;
39pub(crate) mod div_limb;
40pub(crate) mod encoding;
41mod from;
42pub(crate) mod gcd;
43mod invert_mod;
44pub(crate) mod lcm;
45mod mod_symbol;
46pub(crate) mod mul;
47mod mul_mod;
48mod mul_signed;
49mod neg;
50mod neg_mod;
51mod pow;
52pub(crate) mod ref_type;
53mod resize;
54mod root;
55mod shl;
56mod shr;
57mod split;
58mod sqrt;
59mod sub;
60mod sub_mod;
61
62#[cfg(feature = "hybrid-array")]
63mod array;
64#[cfg(feature = "alloc")]
65pub(crate) mod boxed;
66#[cfg(feature = "extra-sizes")]
67mod extra_sizes;
68#[cfg(feature = "rand_core")]
69mod rand;
70
71/// Stack-allocated big unsigned integer.
72///
73/// Generic over the given number of `LIMBS`
74///
75/// # Encoding support
76/// This type supports many different types of encodings, either via the
77/// [`Encoding`][`crate::Encoding`] trait or various `const fn` decoding and
78/// encoding functions that can be used with [`Uint`] constants.
79///
80/// Optional crate features for encoding (off-by-default):
81/// - `hybrid-array`: enables [`ArrayEncoding`][`crate::ArrayEncoding`] trait which can be used to
82///   [`Uint`] as `Array<u8, N>` and a [`ArrayDecoding`][`crate::ArrayDecoding`] trait which
83///   can be used to `Array<u8, N>` as [`Uint`].
84/// - `rlp`: support for [Recursive Length Prefix (RLP)][RLP] encoding.
85///
86/// [RLP]: https://eth.wiki/fundamentals/rlp
87// TODO(tarcieri): make generic around a specified number of bits.
88// Our PartialEq impl only differs from the default one by being constant-time, so this is safe
89#[allow(clippy::derived_hash_with_manual_eq)]
90#[derive(Copy, Clone, Hash)]
91pub struct Uint<const LIMBS: usize> {
92    /// Inner limb array. Stored from least significant to most significant.
93    pub(crate) limbs: [Limb; LIMBS],
94}
95
96impl<const LIMBS: usize> Uint<LIMBS> {
97    /// The value `0`.
98    pub const ZERO: Self = Self::from_u8(0);
99
100    /// The value `1`.
101    pub const ONE: Self = Self::from_u8(1);
102
103    /// Maximum value this [`Uint`] can express.
104    pub const MAX: Self = Self {
105        limbs: [Limb::MAX; LIMBS],
106    };
107
108    /// Total size of the represented integer in bits.
109    #[allow(clippy::cast_possible_truncation)]
110    pub const BITS: u32 = LIMBS as u32 * Limb::BITS;
111
112    /// `floor(log2(Self::BITS))`.
113    // Note: assumes the type of `BITS` is `u32`. Any way to assert that?
114    pub(crate) const LOG2_BITS: u32 = u32_bits(Self::BITS) - 1;
115
116    /// Total size of the represented integer in bytes.
117    pub const BYTES: usize = LIMBS * Limb::BYTES;
118
119    /// The number of limbs used on this platform.
120    pub const LIMBS: usize = LIMBS;
121
122    /// Const-friendly [`Uint`] constructor.
123    #[must_use]
124    pub const fn new(limbs: [Limb; LIMBS]) -> Self {
125        Self { limbs }
126    }
127
128    /// Create a [`Uint`] from an array of [`Word`]s (i.e. word-sized unsigned
129    /// integers).
130    #[inline]
131    #[must_use]
132    pub const fn from_words(arr: [Word; LIMBS]) -> Self {
133        let mut limbs = [Limb::ZERO; LIMBS];
134        let mut i = 0;
135
136        while i < LIMBS {
137            limbs[i] = Limb(arr[i]);
138            i += 1;
139        }
140
141        Self { limbs }
142    }
143
144    /// Create an array of [`Word`]s (i.e. word-sized unsigned integers) from
145    /// a [`Uint`].
146    #[inline]
147    #[must_use]
148    pub const fn to_words(self) -> [Word; LIMBS] {
149        let mut arr = [0; LIMBS];
150        let mut i = 0;
151
152        while i < LIMBS {
153            arr[i] = self.limbs[i].0;
154            i += 1;
155        }
156
157        arr
158    }
159
160    /// Borrow the inner limbs as an array of [`Word`]s.
161    #[must_use]
162    pub const fn as_words(&self) -> &[Word; LIMBS] {
163        Limb::array_as_words(&self.limbs)
164    }
165
166    /// Borrow the inner limbs as a mutable array of [`Word`]s.
167    pub const fn as_mut_words(&mut self) -> &mut [Word; LIMBS] {
168        Limb::array_as_mut_words(&mut self.limbs)
169    }
170
171    /// Borrow the inner limbs as a mutable slice of [`Word`]s.
172    #[deprecated(since = "0.7.0", note = "please use `as_mut_words` instead")]
173    pub const fn as_words_mut(&mut self) -> &mut [Word] {
174        self.as_mut_words()
175    }
176
177    /// Borrow the limbs of this [`Uint`].
178    #[must_use]
179    pub const fn as_limbs(&self) -> &[Limb; LIMBS] {
180        &self.limbs
181    }
182
183    /// Borrow the limbs of this [`Uint`] mutably.
184    pub const fn as_mut_limbs(&mut self) -> &mut [Limb; LIMBS] {
185        &mut self.limbs
186    }
187
188    /// Borrow the limbs of this [`Uint`] mutably.
189    #[deprecated(since = "0.7.0", note = "please use `as_mut_limbs` instead")]
190    pub const fn as_limbs_mut(&mut self) -> &mut [Limb] {
191        self.as_mut_limbs()
192    }
193
194    /// Convert this [`Uint`] into its inner limbs.
195    #[must_use]
196    pub const fn to_limbs(self) -> [Limb; LIMBS] {
197        self.limbs
198    }
199
200    /// Borrow the limbs of this [`Uint`] as a [`UintRef`].
201    #[inline]
202    #[must_use]
203    pub const fn as_uint_ref(&self) -> &UintRef {
204        UintRef::new(&self.limbs)
205    }
206
207    /// Mutably borrow the limbs of this [`Uint`] as a [`UintRef`].
208    #[inline]
209    #[must_use]
210    pub const fn as_mut_uint_ref(&mut self) -> &mut UintRef {
211        UintRef::new_mut(&mut self.limbs)
212    }
213
214    /// Convert to a [`NonZeroUint<LIMBS>`].
215    ///
216    /// Returns some if the original value is non-zero, and none otherwise.
217    #[must_use]
218    pub const fn to_nz(&self) -> CtOption<NonZero<Self>> {
219        let is_nz = self.is_nonzero();
220
221        // Use `1` as a placeholder in the event this value is `0`
222        let ret = Self::select(&Self::ONE, self, is_nz);
223        CtOption::new(NonZero(ret), is_nz)
224    }
225
226    /// Convert to a [`NonZeroUint<LIMBS>`].
227    ///
228    /// Returns Some if the original value is non-zero, and none otherwise.
229    #[must_use]
230    pub const fn to_nz_vartime(&self) -> Option<NonZero<Self>> {
231        if !self.is_zero_vartime() {
232            Some(NonZero(*self))
233        } else {
234            None
235        }
236    }
237
238    /// Convert to a [`OddUint<LIMBS>`].
239    ///
240    /// Returns some if the original value is odd, and false otherwise.
241    #[must_use]
242    pub const fn to_odd(&self) -> CtOption<Odd<Self>> {
243        let is_odd = self.is_odd();
244
245        // Use `1` as a placeholder in the event this value is even
246        let ret = Self::select(&Self::ONE, self, is_odd);
247        CtOption::new(Odd(ret), is_odd)
248    }
249
250    /// Interpret this object as an [`Int`] instead.
251    ///
252    /// Note: this is a casting operation. See [`Self::try_into_int`] for the checked equivalent.
253    #[must_use]
254    pub const fn as_int(&self) -> &Int<LIMBS> {
255        // SAFETY: `Int` is a `repr(transparent)` newtype for `Uint`, and this operation is intended
256        // to be a reinterpreting cast between the two types.
257        #[allow(unsafe_code)]
258        unsafe {
259            &*core::ptr::from_ref(self).cast::<Int<LIMBS>>()
260        }
261    }
262
263    /// Convert this type into an [`Int`]; returns `None` if this value is greater than [`Int::MAX`].
264    ///
265    /// Note: this is the conversion operation. See [`Self::as_int`] for the unchecked equivalent.
266    #[must_use]
267    pub const fn try_into_int(self) -> CtOption<Int<LIMBS>> {
268        Int::new_from_abs_sign(self, Choice::FALSE)
269    }
270
271    /// Is this [`Uint`] equal to [`Uint::ZERO`]?
272    #[must_use]
273    pub const fn is_zero(&self) -> Choice {
274        self.is_nonzero().not()
275    }
276}
277
278impl<const LIMBS: usize> AsRef<[Word; LIMBS]> for Uint<LIMBS> {
279    fn as_ref(&self) -> &[Word; LIMBS] {
280        self.as_words()
281    }
282}
283
284impl<const LIMBS: usize> AsMut<[Word; LIMBS]> for Uint<LIMBS> {
285    fn as_mut(&mut self) -> &mut [Word; LIMBS] {
286        self.as_mut_words()
287    }
288}
289
290impl<const LIMBS: usize> AsRef<[Limb]> for Uint<LIMBS> {
291    fn as_ref(&self) -> &[Limb] {
292        self.as_limbs()
293    }
294}
295
296impl<const LIMBS: usize> AsMut<[Limb]> for Uint<LIMBS> {
297    fn as_mut(&mut self) -> &mut [Limb] {
298        self.as_mut_limbs()
299    }
300}
301
302impl<const LIMBS: usize> AsRef<UintRef> for Uint<LIMBS> {
303    fn as_ref(&self) -> &UintRef {
304        self.as_uint_ref()
305    }
306}
307
308impl<const LIMBS: usize> AsMut<UintRef> for Uint<LIMBS> {
309    fn as_mut(&mut self) -> &mut UintRef {
310        self.as_mut_uint_ref()
311    }
312}
313
314impl<const LIMBS: usize> Bounded for Uint<LIMBS> {
315    const BITS: u32 = Self::BITS;
316    const BYTES: usize = Self::BYTES;
317}
318
319impl<const LIMBS: usize> Constants for Uint<LIMBS> {
320    const MAX: Self = Self::MAX;
321}
322
323impl<const LIMBS: usize> Default for Uint<LIMBS> {
324    fn default() -> Self {
325        Self::ZERO
326    }
327}
328
329impl<const LIMBS: usize> FixedInteger for Uint<LIMBS> {
330    const LIMBS: usize = LIMBS;
331}
332
333impl<const LIMBS: usize> Integer for Uint<LIMBS> {
334    fn as_limbs(&self) -> &[Limb] {
335        &self.limbs
336    }
337
338    fn as_mut_limbs(&mut self) -> &mut [Limb] {
339        &mut self.limbs
340    }
341
342    fn nlimbs(&self) -> usize {
343        Self::LIMBS
344    }
345}
346
347impl<const LIMBS: usize> Unsigned for Uint<LIMBS> {
348    fn as_uint_ref(&self) -> &UintRef {
349        self.as_uint_ref()
350    }
351
352    fn as_mut_uint_ref(&mut self) -> &mut UintRef {
353        self.as_mut_uint_ref()
354    }
355
356    fn from_limb_like(limb: Limb, _other: &Self) -> Self {
357        Self::from(limb)
358    }
359}
360
361impl<const LIMBS: usize> UnsignedWithMontyForm for Uint<LIMBS> {
362    type MontyForm = FixedMontyForm<LIMBS>;
363}
364
365impl<const LIMBS: usize> num_traits::Num for Uint<LIMBS> {
366    type FromStrRadixErr = crate::DecodeError;
367
368    /// <div class="warning">
369    /// <b>WARNING: variable-time!</b>
370    ///
371    /// `from_str_radix` impl operates in variable-time with respect to the input.
372    /// </div>
373    fn from_str_radix(str: &str, radix: u32) -> Result<Self, Self::FromStrRadixErr> {
374        Self::from_str_radix_vartime(str, radix)
375    }
376}
377
378impl<const LIMBS: usize> ConstZero for Uint<LIMBS> {
379    const ZERO: Self = Self::ZERO;
380}
381
382impl<const LIMBS: usize> ConstOne for Uint<LIMBS> {
383    const ONE: Self = Self::ONE;
384}
385
386impl<const LIMBS: usize> Zero for Uint<LIMBS> {
387    #[inline(always)]
388    fn zero() -> Self {
389        Self::ZERO
390    }
391}
392
393impl<const LIMBS: usize> One for Uint<LIMBS> {
394    #[inline(always)]
395    fn one() -> Self {
396        Self::ONE
397    }
398}
399
400impl<const LIMBS: usize> num_traits::Zero for Uint<LIMBS> {
401    #[inline(always)]
402    fn zero() -> Self {
403        Self::ZERO
404    }
405
406    fn is_zero(&self) -> bool {
407        self.ct_eq(&Self::ZERO).into()
408    }
409}
410
411impl<const LIMBS: usize> num_traits::One for Uint<LIMBS> {
412    #[inline(always)]
413    fn one() -> Self {
414        Self::ONE
415    }
416
417    fn is_one(&self) -> bool {
418        self.ct_eq(&Self::ONE).into()
419    }
420}
421
422impl<const LIMBS: usize> fmt::Debug for Uint<LIMBS> {
423    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
424        write!(f, "Uint(0x{:X})", self.as_uint_ref())
425    }
426}
427
428impl<const LIMBS: usize> fmt::Binary for Uint<LIMBS> {
429    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
430        fmt::Binary::fmt(self.as_uint_ref(), f)
431    }
432}
433
434impl<const LIMBS: usize> fmt::Display for Uint<LIMBS> {
435    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
436        fmt::UpperHex::fmt(self, f)
437    }
438}
439
440impl<const LIMBS: usize> fmt::LowerHex for Uint<LIMBS> {
441    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
442        fmt::LowerHex::fmt(self.as_uint_ref(), f)
443    }
444}
445
446impl<const LIMBS: usize> fmt::UpperHex for Uint<LIMBS> {
447    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
448        fmt::UpperHex::fmt(self.as_uint_ref(), f)
449    }
450}
451
452#[cfg(feature = "serde")]
453impl<'de, const LIMBS: usize> Deserialize<'de> for Uint<LIMBS>
454where
455    Uint<LIMBS>: Encoding,
456{
457    fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
458    where
459        D: Deserializer<'de>,
460    {
461        let mut buffer = Encoding::to_le_bytes(&Self::ZERO);
462        serdect::array::deserialize_hex_or_bin(buffer.as_mut(), deserializer)?;
463
464        Ok(Encoding::from_le_bytes(buffer))
465    }
466}
467
468#[cfg(feature = "serde")]
469impl<const LIMBS: usize> Serialize for Uint<LIMBS>
470where
471    Uint<LIMBS>: Encoding,
472{
473    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
474    where
475        S: Serializer,
476    {
477        serdect::slice::serialize_hex_lower_or_bin(&Encoding::to_le_bytes(self), serializer)
478    }
479}
480
481#[cfg(feature = "zeroize")]
482impl<const LIMBS: usize> DefaultIsZeroes for Uint<LIMBS> {}
483
484// TODO(tarcieri): use `generic_const_exprs` when stable to make generic around bits.
485impl_uint_aliases! {
486    (U64, 64, "64-bit"),
487    (U128, 128, "128-bit"),
488    (U192, 192, "192-bit"),
489    (U256, 256, "256-bit"),
490    (U320, 320, "320-bit"),
491    (U384, 384, "384-bit"),
492    (U448, 448, "448-bit"),
493    (U512, 512, "512-bit"),
494    (U576, 576, "576-bit"),
495    (U640, 640, "640-bit"),
496    (U704, 704, "704-bit"),
497    (U768, 768, "768-bit"),
498    (U832, 832, "832-bit"),
499    (U896, 896, "896-bit"),
500    (U960, 960, "960-bit"),
501    (U1024, 1024, "1024-bit"),
502    (U1280, 1280, "1280-bit"),
503    (U1536, 1536, "1536-bit"),
504    (U1792, 1792, "1792-bit"),
505    (U2048, 2048, "2048-bit"),
506    (U3072, 3072, "3072-bit"),
507    (U3584, 3584, "3584-bit"),
508    (U4096, 4096, "4096-bit"),
509    (U4224, 4224, "4224-bit"),
510    (U4352, 4352, "4352-bit"),
511    (U6144, 6144, "6144-bit"),
512    (U8192, 8192, "8192-bit"),
513    (U16384, 16384, "16384-bit"),
514    (U32768, 32768, "32768-bit")
515}
516
517cpubits::cpubits! {
518    32 => {
519        impl_uint_aliases! {
520            (U224, 224, "224-bit"), // For NIST P-224
521            (U544, 544, "544-bit")  // For NIST P-521
522        }
523        impl_uint_concat_split_even! {
524            U64,
525        }
526    }
527}
528
529// Implement concat and split for double-width Uint sizes: these should be
530// multiples of 128 bits.
531impl_uint_concat_split_even! {
532    U128,
533    U256,
534    U384,
535    U512,
536    U640,
537    U768,
538    U896,
539    U1024,
540    U1280,
541    U1536,
542    U1792,
543    U2048,
544    U3072,
545    U3584,
546    U4096,
547    U4224,
548    U4352,
549    U6144,
550    U8192,
551    U16384,
552}
553
554// Implement mixed concat, split and reduce for combinations not implemented by
555// impl_uint_concat_split_even. The numbers represent the size of each
556// component Uint in multiple of 64 bits. For example,
557// (U256, [1, 3]) will allow splitting U256 into (U64, U192) as well as
558// (U192, U64), while the (U128, U128) combination is already covered.
559impl_uint_concat_split_mixed! {
560    (U192, [1, 2]),
561    (U256, [1, 3]),
562    (U320, [1, 2, 3, 4]),
563    (U384, [1, 2, 4, 5]),
564    (U448, [1, 2, 3, 4, 5, 6]),
565    (U512, [1, 2, 3, 5, 6, 7]),
566    (U576, [1, 2, 3, 4, 5, 6, 7, 8]),
567    (U640, [1, 2, 3, 4, 6, 7, 8, 9]),
568    (U704, [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]),
569    (U768, [1, 2, 3, 4, 5, 7, 8, 9, 10, 11]),
570    (U832, [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12]),
571    (U896, [1, 2, 3, 4, 5, 6, 8, 9, 10, 11, 12, 13]),
572    (U960, [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14]),
573    (U1024, [1, 2, 3, 4, 5, 6, 7, 9, 10, 11, 12, 13, 14, 15]),
574}
575
576#[cfg(test)]
577#[allow(clippy::unwrap_used)]
578mod tests {
579    use crate::{Encoding, I128, Int, U128};
580
581    #[cfg(feature = "alloc")]
582    use alloc::format;
583
584    cpubits::cpubits! {
585        64 => {
586            #[test]
587            fn as_words() {
588                let n = U128::from_be_hex("AAAAAAAABBBBBBBBCCCCCCCCDDDDDDDD");
589                assert_eq!(n.as_words(), &[0xCCCCCCCCDDDDDDDD, 0xAAAAAAAABBBBBBBB]);
590            }
591
592            #[test]
593            fn as_words_mut() {
594                let mut n = U128::from_be_hex("AAAAAAAABBBBBBBBCCCCCCCCDDDDDDDD");
595                assert_eq!(n.as_mut_words(), &[0xCCCCCCCCDDDDDDDD, 0xAAAAAAAABBBBBBBB]);
596            }
597        }
598    }
599
600    #[cfg(feature = "alloc")]
601    #[test]
602    fn debug() {
603        let n = U128::from_be_hex("AAAAAAAABBBBBBBBCCCCCCCCDDDDDDDD");
604
605        assert_eq!(format!("{n:?}"), "Uint(0xAAAAAAAABBBBBBBBCCCCCCCCDDDDDDDD)");
606    }
607
608    #[cfg(feature = "alloc")]
609    #[test]
610    fn display() {
611        let hex = "AAAAAAAABBBBBBBBCCCCCCCCDDDDDDDD";
612        let n = U128::from_be_hex(hex);
613
614        use alloc::string::ToString;
615        assert_eq!(hex, n.to_string());
616
617        let hex = "AAAAAAAABBBBBBBB0000000000000000";
618        let n = U128::from_be_hex(hex);
619        assert_eq!(hex, n.to_string());
620
621        let hex = "AAAAAAAABBBBBBBB00000000DDDDDDDD";
622        let n = U128::from_be_hex(hex);
623        assert_eq!(hex, n.to_string());
624
625        let hex = "AAAAAAAABBBBBBBB0CCCCCCCDDDDDDDD";
626        let n = U128::from_be_hex(hex);
627        assert_eq!(hex, n.to_string());
628    }
629
630    #[cfg(feature = "alloc")]
631    #[test]
632    fn fmt_lower_hex() {
633        let n = U128::from_be_hex("AAAAAAAABBBBBBBBCCCCCCCCDDDDDDDD");
634        assert_eq!(format!("{n:x}"), "aaaaaaaabbbbbbbbccccccccdddddddd");
635        assert_eq!(format!("{n:#x}"), "0xaaaaaaaabbbbbbbbccccccccdddddddd");
636    }
637
638    #[cfg(feature = "alloc")]
639    #[test]
640    fn fmt_lower_hex_from_trait() {
641        fn format_int<T: crate::Integer>(n: T) -> alloc::string::String {
642            format!("{n:x}")
643        }
644        let n = U128::from_be_hex("AAAAAAAABBBBBBBBCCCCCCCCDDDDDDDD");
645        assert_eq!(format_int(n), "aaaaaaaabbbbbbbbccccccccdddddddd");
646    }
647
648    #[cfg(feature = "alloc")]
649    #[test]
650    fn fmt_upper_hex() {
651        let n = U128::from_be_hex("aaaaaaaabbbbbbbbccccccccdddddddd");
652        assert_eq!(format!("{n:X}"), "AAAAAAAABBBBBBBBCCCCCCCCDDDDDDDD");
653        assert_eq!(format!("{n:#X}"), "0xAAAAAAAABBBBBBBBCCCCCCCCDDDDDDDD");
654    }
655
656    #[cfg(feature = "alloc")]
657    #[test]
658    fn fmt_upper_hex_from_trait() {
659        fn format_int<T: crate::Integer>(n: T) -> alloc::string::String {
660            format!("{n:X}")
661        }
662        let n = U128::from_be_hex("aaaaaaaabbbbbbbbccccccccdddddddd");
663        assert_eq!(format_int(n), "AAAAAAAABBBBBBBBCCCCCCCCDDDDDDDD");
664    }
665
666    #[cfg(feature = "alloc")]
667    #[test]
668    fn fmt_binary() {
669        let n = U128::from_be_hex("AAAAAAAABBBBBBBBCCCCCCCCDDDDDDDD");
670        assert_eq!(
671            format!("{n:b}"),
672            "10101010101010101010101010101010101110111011101110111011101110111100110011001100110011001100110011011101110111011101110111011101"
673        );
674        assert_eq!(
675            format!("{n:#b}"),
676            "0b10101010101010101010101010101010101110111011101110111011101110111100110011001100110011001100110011011101110111011101110111011101"
677        );
678    }
679
680    #[cfg(feature = "alloc")]
681    #[test]
682    fn fmt_binary_from_trait() {
683        fn format_int<T: crate::Integer>(n: T) -> alloc::string::String {
684            format!("{n:b}")
685        }
686        let n = U128::from_be_hex("aaaaaaaabbbbbbbbccccccccdddddddd");
687        assert_eq!(
688            format_int(n),
689            "10101010101010101010101010101010101110111011101110111011101110111100110011001100110011001100110011011101110111011101110111011101"
690        );
691    }
692
693    #[test]
694    fn from_bytes() {
695        let a = U128::from_be_hex("AAAAAAAABBBBBBBB0CCCCCCCDDDDDDDD");
696
697        let be_bytes = a.to_be_bytes();
698        let le_bytes = a.to_le_bytes();
699        for i in 0..16 {
700            assert_eq!(le_bytes.as_ref()[i], be_bytes.as_ref()[15 - i]);
701        }
702
703        let a_from_be = U128::from_be_bytes(be_bytes);
704        let a_from_le = U128::from_le_bytes(le_bytes);
705        assert_eq!(a_from_be, a_from_le);
706        assert_eq!(a_from_be, a);
707    }
708
709    #[test]
710    fn as_int() {
711        assert_eq!(*U128::ZERO.as_int(), Int::ZERO);
712        assert_eq!(*U128::ONE.as_int(), Int::ONE);
713        assert_eq!(*U128::MAX.as_int(), Int::MINUS_ONE);
714    }
715
716    #[test]
717    fn to_int() {
718        assert_eq!(U128::ZERO.try_into_int().unwrap(), Int::ZERO);
719        assert_eq!(U128::ONE.try_into_int().unwrap(), Int::ONE);
720        assert_eq!(I128::MAX.as_uint().try_into_int().unwrap(), Int::MAX);
721        assert!(bool::from(U128::MAX.try_into_int().is_none()));
722    }
723
724    #[test]
725    fn test_unsigned() {
726        crate::traits::tests::test_unsigned(U128::ZERO, U128::MAX);
727    }
728}