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