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, bitlen,
11    limb::nlimbs, modular::FixedMontyForm, traits::sealed::Sealed,
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    pub const BITS: u32 = bitlen::from_limbs(LIMBS);
110
111    /// Total size of the represented integer in bytes.
112    pub const BYTES: usize = LIMBS * Limb::BYTES;
113
114    /// The number of limbs used on this platform.
115    pub const LIMBS: usize = LIMBS;
116
117    /// Const-friendly [`Uint`] constructor.
118    #[must_use]
119    pub const fn new(limbs: [Limb; LIMBS]) -> Self {
120        Self { limbs }
121    }
122
123    /// Create a [`Uint`] from an array of [`Word`]s (i.e. word-sized unsigned
124    /// integers).
125    #[inline]
126    #[must_use]
127    pub const fn from_words(arr: [Word; LIMBS]) -> Self {
128        let mut limbs = [Limb::ZERO; LIMBS];
129        let mut i = 0;
130
131        while i < LIMBS {
132            limbs[i] = Limb(arr[i]);
133            i += 1;
134        }
135
136        Self { limbs }
137    }
138
139    /// Create an array of [`Word`]s (i.e. word-sized unsigned integers) from
140    /// a [`Uint`].
141    #[inline]
142    #[must_use]
143    pub const fn to_words(self) -> [Word; LIMBS] {
144        let mut arr = [0; LIMBS];
145        let mut i = 0;
146
147        while i < LIMBS {
148            arr[i] = self.limbs[i].0;
149            i += 1;
150        }
151
152        arr
153    }
154
155    /// Borrow the inner limbs as an array of [`Word`]s.
156    #[must_use]
157    pub const fn as_words(&self) -> &[Word; LIMBS] {
158        Limb::array_as_words(&self.limbs)
159    }
160
161    /// Borrow the inner limbs as a mutable array of [`Word`]s.
162    pub const fn as_mut_words(&mut self) -> &mut [Word; LIMBS] {
163        Limb::array_as_mut_words(&mut self.limbs)
164    }
165
166    /// Borrow the inner limbs as a mutable slice of [`Word`]s.
167    #[deprecated(since = "0.7.0", note = "please use `as_mut_words` instead")]
168    pub const fn as_words_mut(&mut self) -> &mut [Word] {
169        self.as_mut_words()
170    }
171
172    /// Borrow the limbs of this [`Uint`].
173    #[must_use]
174    pub const fn as_limbs(&self) -> &[Limb; LIMBS] {
175        &self.limbs
176    }
177
178    /// Borrow the limbs of this [`Uint`] mutably.
179    pub const fn as_mut_limbs(&mut self) -> &mut [Limb; LIMBS] {
180        &mut self.limbs
181    }
182
183    /// Borrow the limbs of this [`Uint`] mutably.
184    #[deprecated(since = "0.7.0", note = "please use `as_mut_limbs` instead")]
185    pub const fn as_limbs_mut(&mut self) -> &mut [Limb] {
186        self.as_mut_limbs()
187    }
188
189    /// Convert this [`Uint`] into its inner limbs.
190    #[must_use]
191    pub const fn to_limbs(self) -> [Limb; LIMBS] {
192        self.limbs
193    }
194
195    /// Borrow the limbs of this [`Uint`] as a [`UintRef`].
196    #[inline]
197    #[must_use]
198    pub const fn as_uint_ref(&self) -> &UintRef {
199        UintRef::new(&self.limbs)
200    }
201
202    /// Mutably borrow the limbs of this [`Uint`] as a [`UintRef`].
203    #[inline]
204    #[must_use]
205    pub const fn as_mut_uint_ref(&mut self) -> &mut UintRef {
206        UintRef::new_mut(&mut self.limbs)
207    }
208
209    /// Construct a [`NonZero`] reference, returning [`None`] in the event `self` is `0`.
210    #[inline]
211    #[must_use]
212    pub const fn as_nz_vartime(&self) -> Option<&NonZero<Self>> {
213        if self.is_zero_vartime() {
214            None
215        } else {
216            Some(NonZero::new_ref_unchecked(self))
217        }
218    }
219
220    /// Convert to a [`NonZeroUint<LIMBS>`].
221    ///
222    /// Returns some if the original value is non-zero, and none otherwise.
223    #[must_use]
224    pub const fn to_nz(&self) -> CtOption<NonZero<Self>> {
225        let (nz, self_nz) = self.to_nz_or_one();
226        CtOption::new(nz, self_nz)
227    }
228
229    /// Convert to a [`NonZeroUint<LIMBS>`].
230    ///
231    /// Returns Some if the original value is non-zero, and none otherwise.
232    #[must_use]
233    pub const fn to_nz_vartime(&self) -> Option<NonZero<Self>> {
234        if self.is_zero_vartime() {
235            None
236        } else {
237            Some(NonZero::new_unchecked(*self))
238        }
239    }
240
241    /// Convert to a [`NonZeroUint<LIMBS>`], defaulting to `Self::ONE`.
242    ///
243    /// Returns a pair consisting of a [`NonZeroUint<LIMBS>`], and a [`Choice`]
244    /// indicating whether the original value was non-zero (and preserved).
245    #[inline(always)]
246    #[must_use]
247    pub(crate) const fn to_nz_or_one(self) -> (NonZero<Self>, Choice) {
248        let is_nz = self.is_nonzero();
249        (
250            NonZero::new_unchecked(Self::select(&Self::ONE, &self, is_nz)),
251            is_nz,
252        )
253    }
254
255    /// Convert to a [`OddUint<LIMBS>`].
256    ///
257    /// Returns some if the original value is odd, and none otherwise.
258    #[must_use]
259    pub const fn to_odd(&self) -> CtOption<Odd<Self>> {
260        let (odd, self_odd) = self.to_odd_or_one();
261        CtOption::new(odd, self_odd)
262    }
263
264    /// Convert to a [`OddUint<LIMBS>`], defaulting to `Self::ONE`.
265    ///
266    /// Returns a pair consisting of a [`OddUint<LIMBS>`], and a [`Choice`]
267    /// indicating whether the original value was non-zero (and preserved).
268    #[inline(always)]
269    #[must_use]
270    pub(crate) const fn to_odd_or_one(self) -> (Odd<Self>, Choice) {
271        let is_odd = self.is_odd();
272        (
273            Odd::new_unchecked(Self::select(&Self::ONE, &self, is_odd)),
274            is_odd,
275        )
276    }
277
278    /// Interpret this object as an [`Int`] instead.
279    ///
280    /// Note: this is a casting operation. See [`Self::try_into_int`] for the checked equivalent.
281    #[must_use]
282    pub const fn as_int(&self) -> &Int<LIMBS> {
283        // SAFETY: `Int` is a `repr(transparent)` newtype for `Uint`, and this operation is intended
284        // to be a reinterpreting cast between the two types.
285        #[allow(unsafe_code)]
286        unsafe {
287            &*core::ptr::from_ref(self).cast::<Int<LIMBS>>()
288        }
289    }
290
291    /// Convert this type into an [`Int`]; returns `None` if this value is greater than [`Int::MAX`].
292    ///
293    /// Note: this is the conversion operation. See [`Self::as_int`] for the unchecked equivalent.
294    #[must_use]
295    pub const fn try_into_int(self) -> CtOption<Int<LIMBS>> {
296        Int::new_from_abs_sign(self, Choice::FALSE)
297    }
298
299    /// Is this [`Uint`] equal to [`Uint::ZERO`]?
300    #[must_use]
301    pub const fn is_zero(&self) -> Choice {
302        self.is_nonzero().not()
303    }
304}
305
306impl<const LIMBS: usize> AsRef<[Word; LIMBS]> for Uint<LIMBS> {
307    fn as_ref(&self) -> &[Word; LIMBS] {
308        self.as_words()
309    }
310}
311
312impl<const LIMBS: usize> AsMut<[Word; LIMBS]> for Uint<LIMBS> {
313    fn as_mut(&mut self) -> &mut [Word; LIMBS] {
314        self.as_mut_words()
315    }
316}
317
318impl<const LIMBS: usize> AsRef<[Limb]> for Uint<LIMBS> {
319    fn as_ref(&self) -> &[Limb] {
320        self.as_limbs()
321    }
322}
323
324impl<const LIMBS: usize> AsMut<[Limb]> for Uint<LIMBS> {
325    fn as_mut(&mut self) -> &mut [Limb] {
326        self.as_mut_limbs()
327    }
328}
329
330impl<const LIMBS: usize> AsRef<UintRef> for Uint<LIMBS> {
331    fn as_ref(&self) -> &UintRef {
332        self.as_uint_ref()
333    }
334}
335
336impl<const LIMBS: usize> AsMut<UintRef> for Uint<LIMBS> {
337    fn as_mut(&mut self) -> &mut UintRef {
338        self.as_mut_uint_ref()
339    }
340}
341
342impl<const LIMBS: usize> Bounded for Uint<LIMBS> {
343    const BITS: u32 = Self::BITS;
344    const BYTES: usize = Self::BYTES;
345}
346
347impl<const LIMBS: usize> Constants for Uint<LIMBS> {
348    const MAX: Self = Self::MAX;
349}
350
351impl<const LIMBS: usize> Default for Uint<LIMBS> {
352    fn default() -> Self {
353        Self::ZERO
354    }
355}
356
357impl<const LIMBS: usize> FixedInteger for Uint<LIMBS> {
358    const LIMBS: usize = LIMBS;
359}
360
361impl<const LIMBS: usize> Integer for Uint<LIMBS> {
362    fn as_limbs(&self) -> &[Limb] {
363        &self.limbs
364    }
365
366    fn as_mut_limbs(&mut self) -> &mut [Limb] {
367        &mut self.limbs
368    }
369
370    fn nlimbs(&self) -> usize {
371        Self::LIMBS
372    }
373}
374
375impl<const LIMBS: usize> Sealed for Uint<LIMBS> {}
376
377impl<const LIMBS: usize> Unsigned for Uint<LIMBS> {
378    fn as_uint_ref(&self) -> &UintRef {
379        self.as_uint_ref()
380    }
381
382    fn as_mut_uint_ref(&mut self) -> &mut UintRef {
383        self.as_mut_uint_ref()
384    }
385
386    fn from_limb_like(limb: Limb, _other: &Self) -> Self {
387        Self::from(limb)
388    }
389}
390
391impl<const LIMBS: usize> UnsignedWithMontyForm for Uint<LIMBS> {
392    type MontyForm = FixedMontyForm<LIMBS>;
393}
394
395impl<const LIMBS: usize> num_traits::Num for Uint<LIMBS> {
396    type FromStrRadixErr = crate::DecodeError;
397
398    /// <div class="warning">
399    /// <b>WARNING: variable-time!</b>
400    ///
401    /// `from_str_radix` impl operates in variable-time with respect to the input.
402    /// </div>
403    fn from_str_radix(str: &str, radix: u32) -> Result<Self, Self::FromStrRadixErr> {
404        Self::from_str_radix_vartime(str, radix)
405    }
406}
407
408impl<const LIMBS: usize> ConstZero for Uint<LIMBS> {
409    const ZERO: Self = Self::ZERO;
410}
411
412impl<const LIMBS: usize> ConstOne for Uint<LIMBS> {
413    const ONE: Self = Self::ONE;
414}
415
416impl<const LIMBS: usize> Zero for Uint<LIMBS> {
417    #[inline(always)]
418    fn zero() -> Self {
419        Self::ZERO
420    }
421}
422
423impl<const LIMBS: usize> One for Uint<LIMBS> {
424    #[inline(always)]
425    fn one() -> Self {
426        Self::ONE
427    }
428}
429
430impl<const LIMBS: usize> num_traits::Zero for Uint<LIMBS> {
431    #[inline(always)]
432    fn zero() -> Self {
433        Self::ZERO
434    }
435
436    fn is_zero(&self) -> bool {
437        self.ct_eq(&Self::ZERO).into()
438    }
439}
440
441impl<const LIMBS: usize> num_traits::One for Uint<LIMBS> {
442    #[inline(always)]
443    fn one() -> Self {
444        Self::ONE
445    }
446
447    fn is_one(&self) -> bool {
448        self.ct_eq(&Self::ONE).into()
449    }
450}
451
452impl<const LIMBS: usize> fmt::Debug for Uint<LIMBS> {
453    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
454        write!(f, "Uint(0x{:X})", self.as_uint_ref())
455    }
456}
457
458impl<const LIMBS: usize> fmt::Binary for Uint<LIMBS> {
459    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
460        fmt::Binary::fmt(self.as_uint_ref(), f)
461    }
462}
463
464impl<const LIMBS: usize> fmt::Display for Uint<LIMBS> {
465    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
466        fmt::UpperHex::fmt(self, f)
467    }
468}
469
470impl<const LIMBS: usize> fmt::LowerHex for Uint<LIMBS> {
471    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
472        fmt::LowerHex::fmt(self.as_uint_ref(), f)
473    }
474}
475
476impl<const LIMBS: usize> fmt::UpperHex for Uint<LIMBS> {
477    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
478        fmt::UpperHex::fmt(self.as_uint_ref(), f)
479    }
480}
481
482#[cfg(feature = "serde")]
483impl<'de, const LIMBS: usize> Deserialize<'de> for Uint<LIMBS>
484where
485    Uint<LIMBS>: Encoding,
486{
487    fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
488    where
489        D: Deserializer<'de>,
490    {
491        let mut buffer = Encoding::to_le_bytes(&Self::ZERO);
492        serdect::array::deserialize_hex_or_bin(buffer.as_mut(), deserializer)?;
493
494        Ok(Encoding::from_le_bytes(buffer))
495    }
496}
497
498#[cfg(feature = "serde")]
499impl<const LIMBS: usize> Serialize for Uint<LIMBS>
500where
501    Uint<LIMBS>: Encoding,
502{
503    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
504    where
505        S: Serializer,
506    {
507        serdect::slice::serialize_hex_lower_or_bin(&Encoding::to_le_bytes(self), serializer)
508    }
509}
510
511#[cfg(feature = "zeroize")]
512impl<const LIMBS: usize> DefaultIsZeroes for Uint<LIMBS> {}
513
514// TODO(tarcieri): use `generic_const_exprs` when stable to make generic around bits.
515impl_uint_aliases! {
516    (U64, 64, "64-bit"),
517    (U128, 128, "128-bit"),
518    (U192, 192, "192-bit"),
519    (U256, 256, "256-bit"),
520    (U320, 320, "320-bit"),
521    (U384, 384, "384-bit"),
522    (U448, 448, "448-bit"),
523    (U512, 512, "512-bit"),
524    (U576, 576, "576-bit"),
525    (U640, 640, "640-bit"),
526    (U704, 704, "704-bit"),
527    (U768, 768, "768-bit"),
528    (U832, 832, "832-bit"),
529    (U896, 896, "896-bit"),
530    (U960, 960, "960-bit"),
531    (U1024, 1024, "1024-bit"),
532    (U1280, 1280, "1280-bit"),
533    (U1536, 1536, "1536-bit"),
534    (U1792, 1792, "1792-bit"),
535    (U2048, 2048, "2048-bit"),
536    (U3072, 3072, "3072-bit"),
537    (U3584, 3584, "3584-bit"),
538    (U4096, 4096, "4096-bit"),
539    (U4224, 4224, "4224-bit"),
540    (U4352, 4352, "4352-bit"),
541    (U6144, 6144, "6144-bit"),
542    (U8192, 8192, "8192-bit"),
543    (U16384, 16384, "16384-bit"),
544    (U32768, 32768, "32768-bit")
545}
546
547cpubits::cpubits! {
548    32 => {
549        impl_uint_aliases! {
550            (U224, 224, "224-bit"), // For NIST P-224
551            (U544, 544, "544-bit")  // For NIST P-521
552        }
553        impl_uint_concat_split_even! {
554            U64,
555        }
556    }
557}
558
559// Implement concat and split for double-width Uint sizes: these should be
560// multiples of 128 bits.
561impl_uint_concat_split_even! {
562    U128,
563    U256,
564    U384,
565    U512,
566    U640,
567    U768,
568    U896,
569    U1024,
570    U1280,
571    U1536,
572    U1792,
573    U2048,
574    U3072,
575    U3584,
576    U4096,
577    U4224,
578    U4352,
579    U6144,
580    U8192,
581    U16384,
582}
583
584// Implement mixed concat, split and reduce for combinations not implemented by
585// impl_uint_concat_split_even. The numbers represent the size of each
586// component Uint in multiple of 64 bits. For example,
587// (U256, [1, 3]) will allow splitting U256 into (U64, U192) as well as
588// (U192, U64), while the (U128, U128) combination is already covered.
589impl_uint_concat_split_mixed! {
590    (U192, [1, 2]),
591    (U256, [1, 3]),
592    (U320, [1, 2, 3, 4]),
593    (U384, [1, 2, 4, 5]),
594    (U448, [1, 2, 3, 4, 5, 6]),
595    (U512, [1, 2, 3, 5, 6, 7]),
596    (U576, [1, 2, 3, 4, 5, 6, 7, 8]),
597    (U640, [1, 2, 3, 4, 6, 7, 8, 9]),
598    (U704, [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]),
599    (U768, [1, 2, 3, 4, 5, 7, 8, 9, 10, 11]),
600    (U832, [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12]),
601    (U896, [1, 2, 3, 4, 5, 6, 8, 9, 10, 11, 12, 13]),
602    (U960, [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14]),
603    (U1024, [1, 2, 3, 4, 5, 6, 7, 9, 10, 11, 12, 13, 14, 15]),
604}
605
606#[cfg(test)]
607#[allow(clippy::unwrap_used)]
608mod tests {
609    use crate::{Encoding, I128, Int, U128};
610
611    #[cfg(feature = "alloc")]
612    use alloc::format;
613
614    cpubits::cpubits! {
615        64 => {
616            #[test]
617            fn as_words() {
618                let n = U128::from_be_hex("AAAAAAAABBBBBBBBCCCCCCCCDDDDDDDD");
619                assert_eq!(n.as_words(), &[0xCCCCCCCCDDDDDDDD, 0xAAAAAAAABBBBBBBB]);
620            }
621
622            #[test]
623            fn as_words_mut() {
624                let mut n = U128::from_be_hex("AAAAAAAABBBBBBBBCCCCCCCCDDDDDDDD");
625                assert_eq!(n.as_mut_words(), &[0xCCCCCCCCDDDDDDDD, 0xAAAAAAAABBBBBBBB]);
626            }
627        }
628    }
629
630    #[cfg(feature = "alloc")]
631    #[test]
632    fn debug() {
633        let n = U128::from_be_hex("AAAAAAAABBBBBBBBCCCCCCCCDDDDDDDD");
634
635        assert_eq!(format!("{n:?}"), "Uint(0xAAAAAAAABBBBBBBBCCCCCCCCDDDDDDDD)");
636    }
637
638    #[cfg(feature = "alloc")]
639    #[test]
640    fn display() {
641        let hex = "AAAAAAAABBBBBBBBCCCCCCCCDDDDDDDD";
642        let n = U128::from_be_hex(hex);
643
644        use alloc::string::ToString;
645        assert_eq!(hex, n.to_string());
646
647        let hex = "AAAAAAAABBBBBBBB0000000000000000";
648        let n = U128::from_be_hex(hex);
649        assert_eq!(hex, n.to_string());
650
651        let hex = "AAAAAAAABBBBBBBB00000000DDDDDDDD";
652        let n = U128::from_be_hex(hex);
653        assert_eq!(hex, n.to_string());
654
655        let hex = "AAAAAAAABBBBBBBB0CCCCCCCDDDDDDDD";
656        let n = U128::from_be_hex(hex);
657        assert_eq!(hex, n.to_string());
658    }
659
660    #[cfg(feature = "alloc")]
661    #[test]
662    fn fmt_lower_hex() {
663        let n = U128::from_be_hex("AAAAAAAABBBBBBBBCCCCCCCCDDDDDDDD");
664        assert_eq!(format!("{n:x}"), "aaaaaaaabbbbbbbbccccccccdddddddd");
665        assert_eq!(format!("{n:#x}"), "0xaaaaaaaabbbbbbbbccccccccdddddddd");
666    }
667
668    #[cfg(feature = "alloc")]
669    #[test]
670    fn fmt_lower_hex_from_trait() {
671        fn format_int<T: crate::Integer>(n: T) -> alloc::string::String {
672            format!("{n:x}")
673        }
674        let n = U128::from_be_hex("AAAAAAAABBBBBBBBCCCCCCCCDDDDDDDD");
675        assert_eq!(format_int(n), "aaaaaaaabbbbbbbbccccccccdddddddd");
676    }
677
678    #[cfg(feature = "alloc")]
679    #[test]
680    fn fmt_upper_hex() {
681        let n = U128::from_be_hex("aaaaaaaabbbbbbbbccccccccdddddddd");
682        assert_eq!(format!("{n:X}"), "AAAAAAAABBBBBBBBCCCCCCCCDDDDDDDD");
683        assert_eq!(format!("{n:#X}"), "0xAAAAAAAABBBBBBBBCCCCCCCCDDDDDDDD");
684    }
685
686    #[cfg(feature = "alloc")]
687    #[test]
688    fn fmt_upper_hex_from_trait() {
689        fn format_int<T: crate::Integer>(n: T) -> alloc::string::String {
690            format!("{n:X}")
691        }
692        let n = U128::from_be_hex("aaaaaaaabbbbbbbbccccccccdddddddd");
693        assert_eq!(format_int(n), "AAAAAAAABBBBBBBBCCCCCCCCDDDDDDDD");
694    }
695
696    #[cfg(feature = "alloc")]
697    #[test]
698    fn fmt_binary() {
699        let n = U128::from_be_hex("AAAAAAAABBBBBBBBCCCCCCCCDDDDDDDD");
700        assert_eq!(
701            format!("{n:b}"),
702            "10101010101010101010101010101010101110111011101110111011101110111100110011001100110011001100110011011101110111011101110111011101"
703        );
704        assert_eq!(
705            format!("{n:#b}"),
706            "0b10101010101010101010101010101010101110111011101110111011101110111100110011001100110011001100110011011101110111011101110111011101"
707        );
708    }
709
710    #[cfg(feature = "alloc")]
711    #[test]
712    fn fmt_binary_from_trait() {
713        fn format_int<T: crate::Integer>(n: T) -> alloc::string::String {
714            format!("{n:b}")
715        }
716        let n = U128::from_be_hex("aaaaaaaabbbbbbbbccccccccdddddddd");
717        assert_eq!(
718            format_int(n),
719            "10101010101010101010101010101010101110111011101110111011101110111100110011001100110011001100110011011101110111011101110111011101"
720        );
721    }
722
723    #[test]
724    fn from_bytes() {
725        let a = U128::from_be_hex("AAAAAAAABBBBBBBB0CCCCCCCDDDDDDDD");
726
727        let be_bytes = a.to_be_bytes();
728        let le_bytes = a.to_le_bytes();
729        for i in 0..16 {
730            assert_eq!(le_bytes.as_ref()[i], be_bytes.as_ref()[15 - i]);
731        }
732
733        let a_from_be = U128::from_be_bytes(be_bytes);
734        let a_from_le = U128::from_le_bytes(le_bytes);
735        assert_eq!(a_from_be, a_from_le);
736        assert_eq!(a_from_be, a);
737    }
738
739    #[test]
740    fn as_int() {
741        assert_eq!(*U128::ZERO.as_int(), Int::ZERO);
742        assert_eq!(*U128::ONE.as_int(), Int::ONE);
743        assert_eq!(*U128::MAX.as_int(), Int::MINUS_ONE);
744    }
745
746    #[test]
747    fn to_int() {
748        assert_eq!(U128::ZERO.try_into_int().unwrap(), Int::ZERO);
749        assert_eq!(U128::ONE.try_into_int().unwrap(), Int::ONE);
750        assert_eq!(I128::MAX.as_uint().try_into_int().unwrap(), Int::MAX);
751        assert!(bool::from(U128::MAX.try_into_int().is_none()));
752    }
753
754    #[test]
755    fn test_unsigned() {
756        crate::traits::tests::test_unsigned(U128::ZERO, U128::MAX);
757    }
758
759    #[test]
760    fn test_unsigned_monty_form() {
761        crate::traits::tests::test_unsigned_monty_form::<U128>();
762    }
763}