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, ConstZero, Constants, Encoding, FixedInteger, Int,
20    Integer, Limb, NonZero, Odd, Word, 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 ONE: Self = Self::ONE;
290    const MAX: Self = Self::MAX;
291}
292
293impl<const LIMBS: usize> Default for Uint<LIMBS> {
294    fn default() -> Self {
295        Self::ZERO
296    }
297}
298
299impl<const LIMBS: usize> FixedInteger for Uint<LIMBS> {
300    const LIMBS: usize = LIMBS;
301}
302
303impl<const LIMBS: usize> Integer for Uint<LIMBS> {
304    type Monty = MontyForm<LIMBS>;
305
306    fn one() -> Self {
307        Self::ONE
308    }
309
310    fn from_limb_like(limb: Limb, _other: &Self) -> Self {
311        Self::from(limb)
312    }
313
314    fn nlimbs(&self) -> usize {
315        Self::LIMBS
316    }
317}
318
319impl<const LIMBS: usize> num_traits::Num for Uint<LIMBS> {
320    type FromStrRadixErr = crate::DecodeError;
321
322    /// ⚠️ WARNING: `from_str_radix` impl operates in variable-time with respect to the input.
323    fn from_str_radix(str: &str, radix: u32) -> Result<Self, Self::FromStrRadixErr> {
324        Self::from_str_radix_vartime(str, radix)
325    }
326}
327
328impl<const LIMBS: usize> ConstZero for Uint<LIMBS> {
329    const ZERO: Self = Self::ZERO;
330}
331
332impl<const LIMBS: usize> num_traits::Zero for Uint<LIMBS> {
333    fn zero() -> Self {
334        Self::ZERO
335    }
336
337    fn is_zero(&self) -> bool {
338        self.ct_eq(&Self::ZERO).into()
339    }
340}
341
342impl<const LIMBS: usize> num_traits::One for Uint<LIMBS> {
343    fn one() -> Self {
344        Self::ONE
345    }
346
347    fn is_one(&self) -> bool {
348        self.ct_eq(&Self::ONE).into()
349    }
350}
351
352impl<const LIMBS: usize> fmt::Debug for Uint<LIMBS> {
353    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
354        write!(f, "Uint(0x{:X})", self.as_uint_ref())
355    }
356}
357
358impl<const LIMBS: usize> fmt::Binary for Uint<LIMBS> {
359    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
360        fmt::Binary::fmt(self.as_uint_ref(), f)
361    }
362}
363
364impl<const LIMBS: usize> fmt::Display for Uint<LIMBS> {
365    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
366        fmt::UpperHex::fmt(self, f)
367    }
368}
369
370impl<const LIMBS: usize> fmt::LowerHex for Uint<LIMBS> {
371    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
372        fmt::LowerHex::fmt(self.as_uint_ref(), f)
373    }
374}
375
376impl<const LIMBS: usize> fmt::UpperHex for Uint<LIMBS> {
377    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
378        fmt::UpperHex::fmt(self.as_uint_ref(), f)
379    }
380}
381
382#[cfg(feature = "serde")]
383impl<'de, const LIMBS: usize> Deserialize<'de> for Uint<LIMBS>
384where
385    Uint<LIMBS>: Encoding,
386{
387    fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
388    where
389        D: Deserializer<'de>,
390    {
391        let mut buffer = Self::ZERO.to_le_bytes();
392        serdect::array::deserialize_hex_or_bin(buffer.as_mut(), deserializer)?;
393
394        Ok(Self::from_le_bytes(buffer))
395    }
396}
397
398#[cfg(feature = "serde")]
399impl<const LIMBS: usize> Serialize for Uint<LIMBS>
400where
401    Uint<LIMBS>: Encoding,
402{
403    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
404    where
405        S: Serializer,
406    {
407        serdect::array::serialize_hex_lower_or_bin(&Encoding::to_le_bytes(self), serializer)
408    }
409}
410
411#[cfg(feature = "zeroize")]
412impl<const LIMBS: usize> DefaultIsZeroes for Uint<LIMBS> {}
413
414// TODO(tarcieri): use `generic_const_exprs` when stable to make generic around bits.
415impl_uint_aliases! {
416    (U64, 64, "64-bit"),
417    (U128, 128, "128-bit"),
418    (U192, 192, "192-bit"),
419    (U256, 256, "256-bit"),
420    (U320, 320, "320-bit"),
421    (U384, 384, "384-bit"),
422    (U448, 448, "448-bit"),
423    (U512, 512, "512-bit"),
424    (U576, 576, "576-bit"),
425    (U640, 640, "640-bit"),
426    (U704, 704, "704-bit"),
427    (U768, 768, "768-bit"),
428    (U832, 832, "832-bit"),
429    (U896, 896, "896-bit"),
430    (U960, 960, "960-bit"),
431    (U1024, 1024, "1024-bit"),
432    (U1280, 1280, "1280-bit"),
433    (U1536, 1536, "1536-bit"),
434    (U1792, 1792, "1792-bit"),
435    (U2048, 2048, "2048-bit"),
436    (U3072, 3072, "3072-bit"),
437    (U3584, 3584, "3584-bit"),
438    (U4096, 4096, "4096-bit"),
439    (U4224, 4224, "4224-bit"),
440    (U4352, 4352, "4352-bit"),
441    (U6144, 6144, "6144-bit"),
442    (U8192, 8192, "8192-bit"),
443    (U16384, 16384, "16384-bit"),
444    (U32768, 32768, "32768-bit")
445}
446
447#[cfg(target_pointer_width = "32")]
448impl_uint_aliases! {
449    (U224, 224, "224-bit"), // For NIST P-224
450    (U544, 544, "544-bit")  // For NIST P-521
451}
452
453#[cfg(target_pointer_width = "32")]
454impl_uint_concat_split_even! {
455    U64,
456}
457
458// Implement concat and split for double-width Uint sizes: these should be
459// multiples of 128 bits.
460impl_uint_concat_split_even! {
461    U128,
462    U256,
463    U384,
464    U512,
465    U640,
466    U768,
467    U896,
468    U1024,
469    U1280,
470    U1536,
471    U1792,
472    U2048,
473    U3072,
474    U3584,
475    U4096,
476    U4224,
477    U4352,
478    U6144,
479    U8192,
480    U16384,
481}
482
483// Implement mixed concat, split and reduce for combinations not implemented by
484// impl_uint_concat_split_even. The numbers represent the size of each
485// component Uint in multiple of 64 bits. For example,
486// (U256, [1, 3]) will allow splitting U256 into (U64, U192) as well as
487// (U192, U64), while the (U128, U128) combination is already covered.
488impl_uint_concat_split_mixed! {
489    (U192, [1, 2]),
490    (U256, [1, 3]),
491    (U320, [1, 2, 3, 4]),
492    (U384, [1, 2, 4, 5]),
493    (U448, [1, 2, 3, 4, 5, 6]),
494    (U512, [1, 2, 3, 5, 6, 7]),
495    (U576, [1, 2, 3, 4, 5, 6, 7, 8]),
496    (U640, [1, 2, 3, 4, 6, 7, 8, 9]),
497    (U704, [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]),
498    (U768, [1, 2, 3, 4, 5, 7, 8, 9, 10, 11]),
499    (U832, [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12]),
500    (U896, [1, 2, 3, 4, 5, 6, 8, 9, 10, 11, 12, 13]),
501    (U960, [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14]),
502    (U1024, [1, 2, 3, 4, 5, 6, 7, 9, 10, 11, 12, 13, 14, 15]),
503}
504
505#[cfg(feature = "extra-sizes")]
506mod extra_sizes;
507mod mul_int;
508mod ref_type;
509
510#[cfg(test)]
511#[allow(clippy::unwrap_used)]
512mod tests {
513    use crate::{Encoding, I128, Int, U128};
514    use subtle::ConditionallySelectable;
515
516    #[cfg(feature = "alloc")]
517    use alloc::format;
518
519    #[cfg(target_pointer_width = "64")]
520    #[test]
521    fn as_words() {
522        let n = U128::from_be_hex("AAAAAAAABBBBBBBBCCCCCCCCDDDDDDDD");
523        assert_eq!(n.as_words(), &[0xCCCCCCCCDDDDDDDD, 0xAAAAAAAABBBBBBBB]);
524    }
525
526    #[cfg(target_pointer_width = "64")]
527    #[test]
528    fn as_words_mut() {
529        let mut n = U128::from_be_hex("AAAAAAAABBBBBBBBCCCCCCCCDDDDDDDD");
530        assert_eq!(n.as_mut_words(), &[0xCCCCCCCCDDDDDDDD, 0xAAAAAAAABBBBBBBB]);
531    }
532
533    #[cfg(feature = "alloc")]
534    #[test]
535    fn debug() {
536        let n = U128::from_be_hex("AAAAAAAABBBBBBBBCCCCCCCCDDDDDDDD");
537
538        assert_eq!(format!("{n:?}"), "Uint(0xAAAAAAAABBBBBBBBCCCCCCCCDDDDDDDD)");
539    }
540
541    #[cfg(feature = "alloc")]
542    #[test]
543    fn display() {
544        let hex = "AAAAAAAABBBBBBBBCCCCCCCCDDDDDDDD";
545        let n = U128::from_be_hex(hex);
546
547        use alloc::string::ToString;
548        assert_eq!(hex, n.to_string());
549
550        let hex = "AAAAAAAABBBBBBBB0000000000000000";
551        let n = U128::from_be_hex(hex);
552        assert_eq!(hex, n.to_string());
553
554        let hex = "AAAAAAAABBBBBBBB00000000DDDDDDDD";
555        let n = U128::from_be_hex(hex);
556        assert_eq!(hex, n.to_string());
557
558        let hex = "AAAAAAAABBBBBBBB0CCCCCCCDDDDDDDD";
559        let n = U128::from_be_hex(hex);
560        assert_eq!(hex, n.to_string());
561    }
562
563    #[cfg(feature = "alloc")]
564    #[test]
565    fn fmt_lower_hex() {
566        let n = U128::from_be_hex("AAAAAAAABBBBBBBBCCCCCCCCDDDDDDDD");
567        assert_eq!(format!("{n:x}"), "aaaaaaaabbbbbbbbccccccccdddddddd");
568        assert_eq!(format!("{n:#x}"), "0xaaaaaaaabbbbbbbbccccccccdddddddd");
569    }
570
571    #[cfg(feature = "alloc")]
572    #[test]
573    fn fmt_lower_hex_from_trait() {
574        fn format_int<T: crate::Integer>(n: T) -> alloc::string::String {
575            format!("{n:x}")
576        }
577        let n = U128::from_be_hex("AAAAAAAABBBBBBBBCCCCCCCCDDDDDDDD");
578        assert_eq!(format_int(n), "aaaaaaaabbbbbbbbccccccccdddddddd");
579    }
580
581    #[cfg(feature = "alloc")]
582    #[test]
583    fn fmt_upper_hex() {
584        let n = U128::from_be_hex("aaaaaaaabbbbbbbbccccccccdddddddd");
585        assert_eq!(format!("{n:X}"), "AAAAAAAABBBBBBBBCCCCCCCCDDDDDDDD");
586        assert_eq!(format!("{n:#X}"), "0xAAAAAAAABBBBBBBBCCCCCCCCDDDDDDDD");
587    }
588
589    #[cfg(feature = "alloc")]
590    #[test]
591    fn fmt_upper_hex_from_trait() {
592        fn format_int<T: crate::Integer>(n: T) -> alloc::string::String {
593            format!("{n:X}")
594        }
595        let n = U128::from_be_hex("aaaaaaaabbbbbbbbccccccccdddddddd");
596        assert_eq!(format_int(n), "AAAAAAAABBBBBBBBCCCCCCCCDDDDDDDD");
597    }
598
599    #[cfg(feature = "alloc")]
600    #[test]
601    fn fmt_binary() {
602        let n = U128::from_be_hex("AAAAAAAABBBBBBBBCCCCCCCCDDDDDDDD");
603        assert_eq!(
604            format!("{n:b}"),
605            "10101010101010101010101010101010101110111011101110111011101110111100110011001100110011001100110011011101110111011101110111011101"
606        );
607        assert_eq!(
608            format!("{n:#b}"),
609            "0b10101010101010101010101010101010101110111011101110111011101110111100110011001100110011001100110011011101110111011101110111011101"
610        );
611    }
612
613    #[cfg(feature = "alloc")]
614    #[test]
615    fn fmt_binary_from_trait() {
616        fn format_int<T: crate::Integer>(n: T) -> alloc::string::String {
617            format!("{n:b}")
618        }
619        let n = U128::from_be_hex("aaaaaaaabbbbbbbbccccccccdddddddd");
620        assert_eq!(
621            format_int(n),
622            "10101010101010101010101010101010101110111011101110111011101110111100110011001100110011001100110011011101110111011101110111011101"
623        );
624    }
625
626    #[test]
627    fn from_bytes() {
628        let a = U128::from_be_hex("AAAAAAAABBBBBBBB0CCCCCCCDDDDDDDD");
629
630        let be_bytes = a.to_be_bytes();
631        let le_bytes = a.to_le_bytes();
632        for i in 0..16 {
633            assert_eq!(le_bytes[i], be_bytes[15 - i]);
634        }
635
636        let a_from_be = U128::from_be_bytes(be_bytes);
637        let a_from_le = U128::from_le_bytes(le_bytes);
638        assert_eq!(a_from_be, a_from_le);
639        assert_eq!(a_from_be, a);
640    }
641
642    #[test]
643    fn conditional_select() {
644        let a = U128::from_be_hex("00002222444466668888AAAACCCCEEEE");
645        let b = U128::from_be_hex("11113333555577779999BBBBDDDDFFFF");
646
647        let select_0 = U128::conditional_select(&a, &b, 0.into());
648        assert_eq!(a, select_0);
649
650        let select_1 = U128::conditional_select(&a, &b, 1.into());
651        assert_eq!(b, select_1);
652    }
653
654    #[test]
655    fn as_int() {
656        assert_eq!(*U128::ZERO.as_int(), Int::ZERO);
657        assert_eq!(*U128::ONE.as_int(), Int::ONE);
658        assert_eq!(*U128::MAX.as_int(), Int::MINUS_ONE);
659    }
660
661    #[test]
662    fn to_int() {
663        assert_eq!(U128::ZERO.try_into_int().unwrap(), Int::ZERO);
664        assert_eq!(U128::ONE.try_into_int().unwrap(), Int::ONE);
665        assert_eq!(I128::MAX.as_uint().try_into_int().unwrap(), Int::MAX);
666        assert!(bool::from(U128::MAX.try_into_int().is_none()));
667    }
668}