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, 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    #[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> Sealed for Uint<LIMBS> {}
348
349impl<const LIMBS: usize> Unsigned for Uint<LIMBS> {
350    fn as_uint_ref(&self) -> &UintRef {
351        self.as_uint_ref()
352    }
353
354    fn as_mut_uint_ref(&mut self) -> &mut UintRef {
355        self.as_mut_uint_ref()
356    }
357
358    fn from_limb_like(limb: Limb, _other: &Self) -> Self {
359        Self::from(limb)
360    }
361}
362
363impl<const LIMBS: usize> UnsignedWithMontyForm for Uint<LIMBS> {
364    type MontyForm = FixedMontyForm<LIMBS>;
365}
366
367impl<const LIMBS: usize> num_traits::Num for Uint<LIMBS> {
368    type FromStrRadixErr = crate::DecodeError;
369
370    /// <div class="warning">
371    /// <b>WARNING: variable-time!</b>
372    ///
373    /// `from_str_radix` impl operates in variable-time with respect to the input.
374    /// </div>
375    fn from_str_radix(str: &str, radix: u32) -> Result<Self, Self::FromStrRadixErr> {
376        Self::from_str_radix_vartime(str, radix)
377    }
378}
379
380impl<const LIMBS: usize> ConstZero for Uint<LIMBS> {
381    const ZERO: Self = Self::ZERO;
382}
383
384impl<const LIMBS: usize> ConstOne for Uint<LIMBS> {
385    const ONE: Self = Self::ONE;
386}
387
388impl<const LIMBS: usize> Zero for Uint<LIMBS> {
389    #[inline(always)]
390    fn zero() -> Self {
391        Self::ZERO
392    }
393}
394
395impl<const LIMBS: usize> One for Uint<LIMBS> {
396    #[inline(always)]
397    fn one() -> Self {
398        Self::ONE
399    }
400}
401
402impl<const LIMBS: usize> num_traits::Zero for Uint<LIMBS> {
403    #[inline(always)]
404    fn zero() -> Self {
405        Self::ZERO
406    }
407
408    fn is_zero(&self) -> bool {
409        self.ct_eq(&Self::ZERO).into()
410    }
411}
412
413impl<const LIMBS: usize> num_traits::One for Uint<LIMBS> {
414    #[inline(always)]
415    fn one() -> Self {
416        Self::ONE
417    }
418
419    fn is_one(&self) -> bool {
420        self.ct_eq(&Self::ONE).into()
421    }
422}
423
424impl<const LIMBS: usize> fmt::Debug for Uint<LIMBS> {
425    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
426        write!(f, "Uint(0x{:X})", self.as_uint_ref())
427    }
428}
429
430impl<const LIMBS: usize> fmt::Binary for Uint<LIMBS> {
431    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
432        fmt::Binary::fmt(self.as_uint_ref(), f)
433    }
434}
435
436impl<const LIMBS: usize> fmt::Display for Uint<LIMBS> {
437    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
438        fmt::UpperHex::fmt(self, f)
439    }
440}
441
442impl<const LIMBS: usize> fmt::LowerHex for Uint<LIMBS> {
443    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
444        fmt::LowerHex::fmt(self.as_uint_ref(), f)
445    }
446}
447
448impl<const LIMBS: usize> fmt::UpperHex for Uint<LIMBS> {
449    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
450        fmt::UpperHex::fmt(self.as_uint_ref(), f)
451    }
452}
453
454#[cfg(feature = "serde")]
455impl<'de, const LIMBS: usize> Deserialize<'de> for Uint<LIMBS>
456where
457    Uint<LIMBS>: Encoding,
458{
459    fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
460    where
461        D: Deserializer<'de>,
462    {
463        let mut buffer = Encoding::to_le_bytes(&Self::ZERO);
464        serdect::array::deserialize_hex_or_bin(buffer.as_mut(), deserializer)?;
465
466        Ok(Encoding::from_le_bytes(buffer))
467    }
468}
469
470#[cfg(feature = "serde")]
471impl<const LIMBS: usize> Serialize for Uint<LIMBS>
472where
473    Uint<LIMBS>: Encoding,
474{
475    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
476    where
477        S: Serializer,
478    {
479        serdect::slice::serialize_hex_lower_or_bin(&Encoding::to_le_bytes(self), serializer)
480    }
481}
482
483#[cfg(feature = "zeroize")]
484impl<const LIMBS: usize> DefaultIsZeroes for Uint<LIMBS> {}
485
486// TODO(tarcieri): use `generic_const_exprs` when stable to make generic around bits.
487impl_uint_aliases! {
488    (U64, 64, "64-bit"),
489    (U128, 128, "128-bit"),
490    (U192, 192, "192-bit"),
491    (U256, 256, "256-bit"),
492    (U320, 320, "320-bit"),
493    (U384, 384, "384-bit"),
494    (U448, 448, "448-bit"),
495    (U512, 512, "512-bit"),
496    (U576, 576, "576-bit"),
497    (U640, 640, "640-bit"),
498    (U704, 704, "704-bit"),
499    (U768, 768, "768-bit"),
500    (U832, 832, "832-bit"),
501    (U896, 896, "896-bit"),
502    (U960, 960, "960-bit"),
503    (U1024, 1024, "1024-bit"),
504    (U1280, 1280, "1280-bit"),
505    (U1536, 1536, "1536-bit"),
506    (U1792, 1792, "1792-bit"),
507    (U2048, 2048, "2048-bit"),
508    (U3072, 3072, "3072-bit"),
509    (U3584, 3584, "3584-bit"),
510    (U4096, 4096, "4096-bit"),
511    (U4224, 4224, "4224-bit"),
512    (U4352, 4352, "4352-bit"),
513    (U6144, 6144, "6144-bit"),
514    (U8192, 8192, "8192-bit"),
515    (U16384, 16384, "16384-bit"),
516    (U32768, 32768, "32768-bit")
517}
518
519cpubits::cpubits! {
520    32 => {
521        impl_uint_aliases! {
522            (U224, 224, "224-bit"), // For NIST P-224
523            (U544, 544, "544-bit")  // For NIST P-521
524        }
525        impl_uint_concat_split_even! {
526            U64,
527        }
528    }
529}
530
531// Implement concat and split for double-width Uint sizes: these should be
532// multiples of 128 bits.
533impl_uint_concat_split_even! {
534    U128,
535    U256,
536    U384,
537    U512,
538    U640,
539    U768,
540    U896,
541    U1024,
542    U1280,
543    U1536,
544    U1792,
545    U2048,
546    U3072,
547    U3584,
548    U4096,
549    U4224,
550    U4352,
551    U6144,
552    U8192,
553    U16384,
554}
555
556// Implement mixed concat, split and reduce for combinations not implemented by
557// impl_uint_concat_split_even. The numbers represent the size of each
558// component Uint in multiple of 64 bits. For example,
559// (U256, [1, 3]) will allow splitting U256 into (U64, U192) as well as
560// (U192, U64), while the (U128, U128) combination is already covered.
561impl_uint_concat_split_mixed! {
562    (U192, [1, 2]),
563    (U256, [1, 3]),
564    (U320, [1, 2, 3, 4]),
565    (U384, [1, 2, 4, 5]),
566    (U448, [1, 2, 3, 4, 5, 6]),
567    (U512, [1, 2, 3, 5, 6, 7]),
568    (U576, [1, 2, 3, 4, 5, 6, 7, 8]),
569    (U640, [1, 2, 3, 4, 6, 7, 8, 9]),
570    (U704, [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]),
571    (U768, [1, 2, 3, 4, 5, 7, 8, 9, 10, 11]),
572    (U832, [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12]),
573    (U896, [1, 2, 3, 4, 5, 6, 8, 9, 10, 11, 12, 13]),
574    (U960, [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14]),
575    (U1024, [1, 2, 3, 4, 5, 6, 7, 9, 10, 11, 12, 13, 14, 15]),
576}
577
578#[cfg(test)]
579#[allow(clippy::unwrap_used)]
580mod tests {
581    use crate::{Encoding, I128, Int, U128};
582
583    #[cfg(feature = "alloc")]
584    use alloc::format;
585
586    cpubits::cpubits! {
587        64 => {
588            #[test]
589            fn as_words() {
590                let n = U128::from_be_hex("AAAAAAAABBBBBBBBCCCCCCCCDDDDDDDD");
591                assert_eq!(n.as_words(), &[0xCCCCCCCCDDDDDDDD, 0xAAAAAAAABBBBBBBB]);
592            }
593
594            #[test]
595            fn as_words_mut() {
596                let mut n = U128::from_be_hex("AAAAAAAABBBBBBBBCCCCCCCCDDDDDDDD");
597                assert_eq!(n.as_mut_words(), &[0xCCCCCCCCDDDDDDDD, 0xAAAAAAAABBBBBBBB]);
598            }
599        }
600    }
601
602    #[cfg(feature = "alloc")]
603    #[test]
604    fn debug() {
605        let n = U128::from_be_hex("AAAAAAAABBBBBBBBCCCCCCCCDDDDDDDD");
606
607        assert_eq!(format!("{n:?}"), "Uint(0xAAAAAAAABBBBBBBBCCCCCCCCDDDDDDDD)");
608    }
609
610    #[cfg(feature = "alloc")]
611    #[test]
612    fn display() {
613        let hex = "AAAAAAAABBBBBBBBCCCCCCCCDDDDDDDD";
614        let n = U128::from_be_hex(hex);
615
616        use alloc::string::ToString;
617        assert_eq!(hex, n.to_string());
618
619        let hex = "AAAAAAAABBBBBBBB0000000000000000";
620        let n = U128::from_be_hex(hex);
621        assert_eq!(hex, n.to_string());
622
623        let hex = "AAAAAAAABBBBBBBB00000000DDDDDDDD";
624        let n = U128::from_be_hex(hex);
625        assert_eq!(hex, n.to_string());
626
627        let hex = "AAAAAAAABBBBBBBB0CCCCCCCDDDDDDDD";
628        let n = U128::from_be_hex(hex);
629        assert_eq!(hex, n.to_string());
630    }
631
632    #[cfg(feature = "alloc")]
633    #[test]
634    fn fmt_lower_hex() {
635        let n = U128::from_be_hex("AAAAAAAABBBBBBBBCCCCCCCCDDDDDDDD");
636        assert_eq!(format!("{n:x}"), "aaaaaaaabbbbbbbbccccccccdddddddd");
637        assert_eq!(format!("{n:#x}"), "0xaaaaaaaabbbbbbbbccccccccdddddddd");
638    }
639
640    #[cfg(feature = "alloc")]
641    #[test]
642    fn fmt_lower_hex_from_trait() {
643        fn format_int<T: crate::Integer>(n: T) -> alloc::string::String {
644            format!("{n:x}")
645        }
646        let n = U128::from_be_hex("AAAAAAAABBBBBBBBCCCCCCCCDDDDDDDD");
647        assert_eq!(format_int(n), "aaaaaaaabbbbbbbbccccccccdddddddd");
648    }
649
650    #[cfg(feature = "alloc")]
651    #[test]
652    fn fmt_upper_hex() {
653        let n = U128::from_be_hex("aaaaaaaabbbbbbbbccccccccdddddddd");
654        assert_eq!(format!("{n:X}"), "AAAAAAAABBBBBBBBCCCCCCCCDDDDDDDD");
655        assert_eq!(format!("{n:#X}"), "0xAAAAAAAABBBBBBBBCCCCCCCCDDDDDDDD");
656    }
657
658    #[cfg(feature = "alloc")]
659    #[test]
660    fn fmt_upper_hex_from_trait() {
661        fn format_int<T: crate::Integer>(n: T) -> alloc::string::String {
662            format!("{n:X}")
663        }
664        let n = U128::from_be_hex("aaaaaaaabbbbbbbbccccccccdddddddd");
665        assert_eq!(format_int(n), "AAAAAAAABBBBBBBBCCCCCCCCDDDDDDDD");
666    }
667
668    #[cfg(feature = "alloc")]
669    #[test]
670    fn fmt_binary() {
671        let n = U128::from_be_hex("AAAAAAAABBBBBBBBCCCCCCCCDDDDDDDD");
672        assert_eq!(
673            format!("{n:b}"),
674            "10101010101010101010101010101010101110111011101110111011101110111100110011001100110011001100110011011101110111011101110111011101"
675        );
676        assert_eq!(
677            format!("{n:#b}"),
678            "0b10101010101010101010101010101010101110111011101110111011101110111100110011001100110011001100110011011101110111011101110111011101"
679        );
680    }
681
682    #[cfg(feature = "alloc")]
683    #[test]
684    fn fmt_binary_from_trait() {
685        fn format_int<T: crate::Integer>(n: T) -> alloc::string::String {
686            format!("{n:b}")
687        }
688        let n = U128::from_be_hex("aaaaaaaabbbbbbbbccccccccdddddddd");
689        assert_eq!(
690            format_int(n),
691            "10101010101010101010101010101010101110111011101110111011101110111100110011001100110011001100110011011101110111011101110111011101"
692        );
693    }
694
695    #[test]
696    fn from_bytes() {
697        let a = U128::from_be_hex("AAAAAAAABBBBBBBB0CCCCCCCDDDDDDDD");
698
699        let be_bytes = a.to_be_bytes();
700        let le_bytes = a.to_le_bytes();
701        for i in 0..16 {
702            assert_eq!(le_bytes.as_ref()[i], be_bytes.as_ref()[15 - i]);
703        }
704
705        let a_from_be = U128::from_be_bytes(be_bytes);
706        let a_from_le = U128::from_le_bytes(le_bytes);
707        assert_eq!(a_from_be, a_from_le);
708        assert_eq!(a_from_be, a);
709    }
710
711    #[test]
712    fn as_int() {
713        assert_eq!(*U128::ZERO.as_int(), Int::ZERO);
714        assert_eq!(*U128::ONE.as_int(), Int::ONE);
715        assert_eq!(*U128::MAX.as_int(), Int::MINUS_ONE);
716    }
717
718    #[test]
719    fn to_int() {
720        assert_eq!(U128::ZERO.try_into_int().unwrap(), Int::ZERO);
721        assert_eq!(U128::ONE.try_into_int().unwrap(), Int::ONE);
722        assert_eq!(I128::MAX.as_uint().try_into_int().unwrap(), Int::MAX);
723        assert!(bool::from(U128::MAX.try_into_int().is_none()));
724    }
725
726    #[test]
727    fn test_unsigned() {
728        crate::traits::tests::test_unsigned(U128::ZERO, U128::MAX);
729    }
730
731    #[test]
732    fn test_unsigned_monty_form() {
733        crate::traits::tests::test_unsigned_monty_form::<U128>();
734    }
735}