crypto_bigint/
uint.rs

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