openzeppelin_crypto/arithmetic/
uint.rs

1//! This module contains the [`Uint`] unsigned big integer used for
2//! cryptographic applications, altogether with its exact implementations
3//! [`U64`] for 64 bits, [`U128`] for 128 bits, and so on.
4
5use alloc::vec::Vec;
6use core::{
7    borrow::Borrow,
8    cmp::Ordering,
9    fmt::{Debug, Display, Result, UpperHex},
10    ops::{
11        BitAnd, BitAndAssign, BitOr, BitOrAssign, BitXor, BitXorAssign, Not,
12        Shl, ShlAssign, Shr, ShrAssign,
13    },
14};
15
16use num_traits::ConstZero;
17use zeroize::Zeroize;
18
19use crate::{
20    arithmetic::{
21        limb,
22        limb::{Limb, Limbs},
23        BigInteger,
24    },
25    bits::BitIteratorBE,
26    const_for, const_for_unroll6, const_rev_for,
27};
28
29/// Stack-allocated big unsigned integer.
30///
31/// Generic over number `N` of [`Limb`]s.
32#[derive(Copy, Clone, PartialEq, Eq, Hash, Zeroize)]
33pub struct Uint<const N: usize> {
34    pub(crate) limbs: Limbs<N>,
35}
36
37impl<const N: usize> Default for Uint<N> {
38    fn default() -> Self {
39        Self { limbs: [Limb::ZERO; N] }
40    }
41}
42
43/// Declare [`Uint`] types for different bit sizes.
44macro_rules! declare_num {
45    ($num:ident, $bits:expr) => {
46        #[doc = "Unsigned integer with "]
47        #[doc = stringify!($bits)]
48        #[doc = "bits size."]
49        pub type $num = $crate::arithmetic::uint::Uint<
50            { usize::div_ceil($bits, $crate::arithmetic::Limb::BITS as usize) },
51        >;
52    };
53}
54
55declare_num!(U64, 64);
56declare_num!(U128, 128);
57declare_num!(U192, 192);
58declare_num!(U256, 256);
59declare_num!(U384, 384);
60declare_num!(U448, 448);
61declare_num!(U512, 512);
62declare_num!(U576, 576);
63declare_num!(U640, 640);
64declare_num!(U704, 704);
65declare_num!(U768, 768);
66declare_num!(U832, 832);
67
68impl<const N: usize> Uint<N> {
69    /// Create a new [`Uint`] from the provided `limbs` (constant).
70    #[must_use]
71    pub const fn new(limbs: [Limb; N]) -> Self {
72        Self { limbs }
73    }
74
75    /// Returns reference to the inner [`Limbs`] array (constant).
76    #[must_use]
77    pub const fn as_limbs(&self) -> &Limbs<N> {
78        &self.limbs
79    }
80
81    /// Returns inner [`Limbs`] array (constant).
82    #[must_use]
83    pub const fn into_limbs(self) -> Limbs<N> {
84        self.limbs
85    }
86
87    /// Returns true if this number is odd (constant).
88    #[doc(hidden)]
89    #[inline]
90    #[must_use]
91    pub const fn is_odd(&self) -> bool {
92        self.limbs[0] & 1 == 1
93    }
94
95    /// Returns true if this number is even (constant).
96    #[doc(hidden)]
97    #[inline]
98    #[must_use]
99    pub const fn is_even(&self) -> bool {
100        self.limbs[0] & 1 == 0
101    }
102
103    /// Checks `self` is greater or equal then `rhs` (constant).
104    #[must_use]
105    #[inline(always)]
106    pub const fn ge(&self, rhs: &Self) -> bool {
107        let mut result = true;
108        const_for_unroll6!((i in 0..N) {
109            let a = self.limbs[i];
110            let b = rhs.limbs[i];
111            if a > b {
112                result = true;
113            } else if a < b {
114                result = false;
115            }
116        });
117        result
118    }
119
120    /// Checks `self` is greater then `rhs` (constant).
121    #[must_use]
122    #[inline(always)]
123    pub const fn gt(&self, rhs: &Self) -> bool {
124        let mut result = false;
125        const_for_unroll6!((i in 0..N) {
126            let a = self.limbs[i];
127            let b = rhs.limbs[i];
128            if a > b {
129                result = true;
130            } else if a < b {
131                result = false;
132            }
133        });
134        result
135    }
136
137    /// Checks `self` is less or equal then `rhs` (constant).
138    #[must_use]
139    #[inline(always)]
140    pub const fn le(&self, rhs: &Self) -> bool {
141        let mut result = true;
142        const_for_unroll6!((i in 0..N) {
143            let a = self.limbs[i];
144            let b = rhs.limbs[i];
145            if a < b {
146                result = true;
147            } else if a > b {
148                result = false;
149            }
150        });
151        result
152    }
153
154    /// Checks `self` is less then `rhs` (constant).
155    #[must_use]
156    #[inline(always)]
157    pub const fn lt(&self, rhs: &Self) -> bool {
158        let mut result = false;
159        const_for_unroll6!((i in 0..N) {
160            let a = self.limbs[i];
161            let b = rhs.limbs[i];
162            if a < b {
163                result = true;
164            } else if a > b {
165                result = false;
166            }
167        });
168        result
169    }
170
171    /// Checks `self` is zero (constant).
172    #[must_use]
173    #[inline(always)]
174    pub const fn is_zero(&self) -> bool {
175        self.eq(&Self::ZERO)
176    }
177
178    /// Checks if `self` is equal to `rhs` (constant).
179    #[must_use]
180    #[inline(always)]
181    pub const fn eq(&self, rhs: &Self) -> bool {
182        const_for!((i in 0..N) {
183            if self.limbs[i] != rhs.limbs[i] {
184                return false;
185            }
186        });
187        true
188    }
189
190    /// Checks if `self` is not equal to `rhs` (constant).
191    #[must_use]
192    #[inline(always)]
193    pub const fn ne(&self, rhs: &Self) -> bool {
194        !self.eq(rhs)
195    }
196
197    /// Return the minimum number of bits needed to encode this number.
198    ///
199    /// One bit is necessary to encode zero.
200    #[doc(hidden)]
201    #[must_use]
202    pub const fn num_bits(&self) -> usize {
203        // One bit is necessary to encode zero.
204        if self.is_zero() {
205            return 1;
206        }
207
208        // Total number of bits.
209        let mut num_bits = Self::BITS;
210
211        // Start with the last (highest) limb.
212        const_rev_for!((index in 0..N) {
213            // Subtract leading zeroes, from the total number of limbs.
214            let leading = self.limbs[index].leading_zeros() as usize;
215            num_bits -= leading;
216
217            // If the limb is not empty, stop processing other limbs.
218            if leading != 64 {
219                break;
220            }
221        });
222
223        // And return the result.
224        num_bits
225    }
226
227    /// Find the `i`-th bit of `self`.
228    #[must_use]
229    pub const fn get_bit(&self, i: usize) -> bool {
230        // If `i` is more than total bits, return `false`.
231        if i >= Self::BITS {
232            return false;
233        }
234
235        // Otherwise find `limb` and `bit` indices and get the bit.
236        let bits_in_limb = Limb::BITS as usize;
237        let limb = i / bits_in_limb;
238        let bit = i - bits_in_limb * limb;
239        let mask = 1 << bit;
240        (self.limbs[limb] & mask) != 0
241    }
242
243    /// Multiplies `self` by `2` in-place, returning whether overflow occurred.
244    #[inline(always)]
245    #[allow(unused)]
246    pub fn checked_mul2_assign(&mut self) -> bool {
247        let mut last = 0;
248        const_for_unroll6!((i in 0..N) {
249            let a = &mut self.limbs[i];
250            let tmp = *a >> 63;
251            *a <<= 1;
252            *a |= last;
253            last = tmp;
254        });
255        last != 0
256    }
257
258    /// Multiplies `self` by `2`, returning the result and whether overflow
259    /// occurred (constant).
260    const fn checked_mul2(mut self) -> (Self, bool) {
261        let mut last = 0;
262        const_for!((i in 0..N) {
263            let a = self.limbs[i];
264            let tmp = a >> 63;
265            self.limbs[i] <<= 1;
266            self.limbs[i] |= last;
267            last = tmp;
268        });
269        (self, last != 0)
270    }
271
272    /// Divide `self` by `2` in-place.
273    pub fn div2_assign(&mut self) {
274        let mut t = 0;
275        for a in self.limbs.iter_mut().rev() {
276            let t2 = *a << 63;
277            *a >>= 1;
278            *a |= t;
279            t = t2;
280        }
281    }
282
283    /// Subtract `rhs` from `self`, returning the result and whether overflow
284    /// occurred (constant).
285    #[inline(always)]
286    #[must_use]
287    pub const fn checked_sub(mut self, rhs: &Self) -> (Self, bool) {
288        let mut borrow = false;
289
290        const_for_unroll6!((i in 0..N) {
291            (self.limbs[i], borrow) = limb::sbb(self.limbs[i], rhs.limbs[i], borrow);
292        });
293
294        (self, borrow)
295    }
296
297    /// Subtract `rhs` from `self`, returning the result wrapping around the
298    /// lower boundary (constant).
299    #[inline(always)]
300    #[must_use]
301    pub const fn wrapping_sub(&self, rhs: &Self) -> Self {
302        self.checked_sub(rhs).0
303    }
304
305    /// Add `rhs` to `self`, returning the result and whether overflow occurred
306    /// (constant).
307    #[inline]
308    #[must_use]
309    pub const fn checked_add(mut self, rhs: &Self) -> (Self, bool) {
310        let mut carry = false;
311
312        const_for!((i in 0..N) {
313            (self.limbs[i], carry) = limb::adc(self.limbs[i], rhs.limbs[i], carry);
314        });
315
316        (self, carry)
317    }
318
319    /// Add `rhs` to `self` in-place, returning whether overflow occurred.
320    #[inline(always)]
321    pub fn checked_add_assign(&mut self, rhs: &Self) -> bool {
322        let mut carry = false;
323
324        const_for_unroll6!((i in 0..N) {
325            carry = limb::adc_assign(&mut self.limbs[i], rhs.limbs[i], carry);
326        });
327
328        carry
329    }
330
331    /// Subtract `rhs` from `self` in-place, returning whether overflow
332    /// occurred.
333    #[inline(always)]
334    pub fn checked_sub_assign(&mut self, rhs: &Self) -> bool {
335        let mut borrow = false;
336
337        const_for_unroll6!((i in 0..N) {
338            borrow =
339                limb::sbb_assign(&mut self.limbs[i], rhs.limbs[i], borrow);
340        });
341
342        borrow
343    }
344
345    /// Compute "wide" multiplication, with a product twice the size of the
346    /// input.
347    ///
348    /// Returns a tuple containing the `(lo, hi)` components of the product.
349    ///
350    /// Basic multiplication algorithm described in [wiki].
351    /// It is fast enough for runtime use when optimized with loop "unrolls",
352    /// like [`const_for_unroll6`].
353    ///
354    /// [wiki]: https://en.wikipedia.org/wiki/Multiplication_algorithm
355    #[inline(always)]
356    #[must_use]
357    pub const fn widening_mul(&self, rhs: &Self) -> (Self, Self) {
358        let (mut lo, mut hi) = ([0u64; N], [0u64; N]);
359        // For each digit of the first number,
360        const_for_unroll6!((i in 0..N) {
361            let mut carry = 0;
362            // perform multiplication of each digit from the second.
363            const_for_unroll6!((j in 0..N) {
364                // And if the multiplication result is too big,
365                let k = i + j;
366                if k >= N {
367                    // it should go to the high (hi) part.
368                    (hi[k - N], carry) = limb::carrying_mac(
369                        hi[k - N],
370                        self.limbs[i],
371                        rhs.limbs[j],
372                        carry
373                    );
374                } else {
375                    (lo[k], carry) = limb::carrying_mac(
376                        lo[k],
377                        self.limbs[i],
378                        rhs.limbs[j],
379                        carry
380                    );
381                }
382            });
383            // Set the last carry to the next limb.
384            hi[i] = carry;
385        });
386
387        (Self::new(lo), Self::new(hi))
388    }
389
390    /// Multiply two numbers and panic on overflow.
391    #[allow(clippy::missing_panics_doc)]
392    #[must_use]
393    #[allow(clippy::missing_panics_doc)]
394    pub const fn mul(&self, rhs: &Self) -> Self {
395        let (low, high) = self.widening_mul(rhs);
396        assert!(high.eq(&Uint::<N>::ZERO), "overflow on multiplication");
397        low
398    }
399
400    /// Add two numbers and panic on overflow.
401    #[must_use]
402    #[allow(clippy::missing_panics_doc)]
403    pub const fn add(&self, rhs: &Self) -> Self {
404        let (low, carry) = self.adc(rhs, false);
405        assert!(!carry, "overflow on addition");
406        low
407    }
408
409    /// Add two numbers wrapping around the upper boundary.
410    #[must_use]
411    pub const fn wrapping_add(&self, rhs: &Self) -> Self {
412        let (low, _) = self.adc(rhs, false);
413        low
414    }
415
416    /// Computes `a + b + carry`, returning the result along with the new carry.
417    #[inline(always)]
418    #[must_use]
419    pub const fn adc(&self, rhs: &Uint<N>, mut carry: bool) -> (Self, bool) {
420        let mut limbs = [Limb::ZERO; N];
421
422        const_for!((i in 0..N) {
423            (limbs[i], carry) = limb::adc(self.limbs[i], rhs.limbs[i], carry);
424        });
425
426        (Self { limbs }, carry)
427    }
428
429    /// Create a new [`Uint`] from the provided little endian bytes.
430    #[must_use]
431    #[allow(clippy::missing_panics_doc)]
432    pub const fn from_le_slice(bytes: &[u8]) -> Self {
433        const LIMB_BYTES: usize = Limb::BITS as usize / 8;
434        assert!(
435            bytes.len() == LIMB_BYTES * N,
436            "bytes are not the expected size"
437        );
438
439        let mut res = [Limb::ZERO; N];
440        let mut buf = [0u8; LIMB_BYTES];
441
442        const_for!((i in 0..N) {
443            const_for!((j in 0..LIMB_BYTES) {
444                buf[j] = bytes[i * LIMB_BYTES + j];
445            });
446            res[i] = Limb::from_le_bytes(buf);
447        });
448
449        Self::new(res)
450    }
451
452    /// Construct `Self` from the other [`Uint`] of different size (constant).
453    ///
454    /// # Panics
455    ///
456    /// * If `value` is bigger than `Self` maximum size.
457    #[must_use]
458    pub const fn from_uint<const N2: usize>(value: Uint<N2>) -> Self {
459        let mut res = Uint::<N>::ZERO;
460        const_for!((i in 0..{value.limbs.len()}) {
461            if i < res.limbs.len() {
462                res.limbs[i] = value.limbs[i];
463            } else if value.limbs[i] != Limb::ZERO {
464                panic!("converted element is too large")
465            }
466        });
467        res
468    }
469}
470
471// ----------- From Impls -----------
472
473/// Constant conversions from primitive types.
474macro_rules! impl_from_primitive {
475    ($int:ty, $func_name:ident) => {
476        impl<const N: usize> Uint<N> {
477            #[doc = "Create a [`Uint`] from"]
478            #[doc = stringify!($int)]
479            #[doc = "integer (constant)."]
480            #[must_use]
481            #[allow(clippy::cast_lossless)]
482            pub const fn $func_name(val: $int) -> Self {
483                assert!(N >= 1, "number of limbs must be greater than zero");
484                let mut repr = Self::ZERO;
485                repr.limbs[0] = val as Limb;
486                repr
487            }
488        }
489    };
490}
491impl_from_primitive!(u8, from_u8);
492impl_from_primitive!(u16, from_u16);
493impl_from_primitive!(u32, from_u32);
494impl_from_primitive!(u64, from_u64);
495impl_from_primitive!(usize, from_usize);
496
497// Logic for `u128` conversion is different from `u8`..`u64`, due to the size of
498// the `Limb`.
499impl<const N: usize> Uint<N> {
500    /// Create a [`Uint`] from a `u128` integer (constant).
501    #[must_use]
502    #[allow(clippy::cast_possible_truncation)]
503    #[allow(clippy::cast_lossless)]
504    #[allow(clippy::missing_panics_doc)]
505    pub const fn from_u128(val: u128) -> Self {
506        assert!(N >= 1, "number of limbs must be greater than zero");
507
508        let lo = val as Limb;
509        let hi = (val >> 64) as Limb;
510
511        // If there are at least 2 limbs,
512        if N >= 2 {
513            // we can fit `lo` and `hi`,
514            let mut res = Self::ZERO;
515            res.limbs[0] = lo;
516            res.limbs[1] = hi;
517            res
518        } else if hi == Limb::ZERO {
519            // or if `hi` is zero, we can fit `lo`
520            let mut res = Self::ZERO;
521            res.limbs[0] = lo;
522            res
523        } else {
524            // otherwise, we panic.
525            panic!("u128 is too large to fit");
526        }
527    }
528}
529
530/// From traits implementation for primitives.
531macro_rules! impl_from_primitive {
532    ($int:ty, $func_name:ident) => {
533        impl<const N: usize> From<$int> for Uint<N> {
534            #[inline]
535            fn from(val: $int) -> Uint<N> {
536                Uint::<N>::$func_name(val)
537            }
538        }
539    };
540}
541
542impl_from_primitive!(u8, from_u8);
543impl_from_primitive!(u16, from_u16);
544impl_from_primitive!(u32, from_u32);
545impl_from_primitive!(u64, from_u64);
546impl_from_primitive!(usize, from_usize);
547impl_from_primitive!(u128, from_u128);
548
549/// Constant conversions into primitive types.
550///
551/// Implements conversion [`Uint`] -> `$int` for `$int` not bigger than `Limb`'s
552/// max size.
553macro_rules! impl_into_primitive {
554    ($int:ty, $func_name:ident) => {
555        impl<const N: usize> Uint<N> {
556            #[doc = "Create a"]
557            #[doc = stringify!($int)]
558            #[doc = "integer from [`Uint`] (constant)."]
559            #[doc = "# Panics"]
560            #[doc = "* If [`Uint`] type is too large to fit into primitive integer."]
561            #[must_use]
562            #[allow(clippy::cast_possible_truncation)]
563            pub const fn $func_name(self) -> $int {
564                assert!(N >= 1, "number of limbs must be greater than zero");
565                // Each limb besides the first one should be zero,
566                const_for!((i in 1..N) {
567                    // otherwise panic with overflow.
568                    assert!(self.limbs[i] == 0, "Uint type is to large to fit");
569                });
570                // Panic if the first limb's value is bigger than maximum of resulted integer.
571                assert!(
572                    self.limbs[0] <= <$int>::MAX as Limb,
573                    "Uint type is to large to fit"
574                );
575
576                self.limbs[0] as $int
577            }
578        }
579    };
580}
581
582impl_into_primitive!(u8, into_u8);
583impl_into_primitive!(u16, into_u16);
584impl_into_primitive!(u32, into_u32);
585impl_into_primitive!(u64, into_u64);
586impl_into_primitive!(usize, into_usize);
587
588impl<const N: usize> Uint<N> {
589    /// Create a `u128` integer from [`Uint`] (constant).
590    ///
591    /// # Panics
592    ///
593    /// * If [`Uint`] type is too large to fit into primitive integer.
594    #[must_use]
595    pub const fn into_u128(self) -> u128 {
596        match N {
597            0 => {
598                panic!("number of limbs must be greater than zero")
599            }
600            1 => self.limbs[0] as u128,
601            _ => {
602                // Each limb besides the first two should be zero,
603                const_for!((i in 2..N) {
604                    // otherwise panic with overflow.
605                    assert!(self.limbs[i] == 0, "Uint type is to large to fit");
606                });
607
608                // Type u128 can be safely packed in two `64-bit` limbs.
609                let res0 = self.limbs[0] as u128;
610                let res1 = (self.limbs[1] as u128) << 64;
611                res0 | res1
612            }
613        }
614    }
615}
616
617/// From traits implementation for [`Uint`] into primitive types.
618macro_rules! impl_from_uint {
619    ($int:ty, $func_name:ident) => {
620        impl<const N: usize> From<Uint<N>> for $int {
621            #[inline]
622            fn from(val: Uint<N>) -> $int {
623                val.$func_name()
624            }
625        }
626    };
627}
628
629impl_from_uint!(u8, into_u8);
630impl_from_uint!(u16, into_u16);
631impl_from_uint!(u32, into_u32);
632impl_from_uint!(u64, into_u64);
633impl_from_uint!(usize, into_usize);
634impl_from_uint!(u128, into_u128);
635
636#[cfg(feature = "ruint")]
637impl<const B: usize, const L: usize> From<ruint::Uint<B, L>> for Uint<L> {
638    fn from(value: ruint::Uint<B, L>) -> Self {
639        // Padding ruint integer bytes.
640        let mut bytes = alloc::vec![0u8; Uint::<L>::BYTES];
641        let value_bytes = value.as_le_slice();
642        bytes[0..value_bytes.len()].copy_from_slice(value_bytes);
643
644        Uint::from_bytes_le(&bytes)
645    }
646}
647
648#[cfg(feature = "ruint")]
649impl<const B: usize, const L: usize> From<Uint<L>> for ruint::Uint<B, L> {
650    fn from(value: Uint<L>) -> Self {
651        // Panics if ruint::Uint size is too small.
652        ruint::Uint::from_le_slice(&value.into_bytes_le())
653    }
654}
655
656// ----------- Traits Impls -----------
657
658impl<const N: usize> UpperHex for Uint<N> {
659    fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> Result {
660        // Concatenate hex representation of limbs in reversed order without
661        // allocations.
662        // By the end, it will produce actual hex of `Uint`.
663        for limb in self.limbs.iter().rev() {
664            write!(f, "{limb:016X}")?;
665        }
666        Ok(())
667    }
668}
669
670impl<const N: usize> Display for Uint<N> {
671    fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> Result {
672        // Use upper hex by default.
673        write!(f, "{self:X}")
674    }
675}
676
677impl<const N: usize> Debug for Uint<N> {
678    fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> Result {
679        write!(f, "{self}")
680    }
681}
682
683impl<const N: usize> Ord for Uint<N> {
684    #[inline]
685    fn cmp(&self, rhs: &Self) -> Ordering {
686        let mut result = Ordering::Equal;
687        const_for_unroll6!((i in 0..N) {
688            let a = &self.limbs[i];
689            let b = &rhs.limbs[i];
690            match a.cmp(b) {
691                Ordering::Equal => {}
692                order => {result = order},
693            }
694        });
695
696        result
697    }
698}
699
700impl<const N: usize> PartialOrd for Uint<N> {
701    #[inline]
702    fn partial_cmp(&self, rhs: &Self) -> Option<Ordering> {
703        Some(self.cmp(rhs))
704    }
705}
706
707impl<const N: usize> AsMut<[u64]> for Uint<N> {
708    #[inline]
709    fn as_mut(&mut self) -> &mut [u64] {
710        &mut self.limbs
711    }
712}
713
714impl<const N: usize> AsRef<[u64]> for Uint<N> {
715    #[inline]
716    fn as_ref(&self) -> &[u64] {
717        &self.limbs
718    }
719}
720
721impl<B: Borrow<Self>, const N: usize> BitXorAssign<B> for Uint<N> {
722    fn bitxor_assign(&mut self, rhs: B) {
723        for i in 0..N {
724            self.limbs[i] ^= rhs.borrow().limbs[i];
725        }
726    }
727}
728
729impl<B: Borrow<Self>, const N: usize> BitXor<B> for Uint<N> {
730    type Output = Self;
731
732    fn bitxor(mut self, rhs: B) -> Self::Output {
733        self ^= rhs;
734        self
735    }
736}
737
738impl<B: Borrow<Self>, const N: usize> BitAndAssign<B> for Uint<N> {
739    fn bitand_assign(&mut self, rhs: B) {
740        for i in 0..N {
741            self.limbs[i] &= rhs.borrow().limbs[i];
742        }
743    }
744}
745
746impl<B: Borrow<Self>, const N: usize> BitAnd<B> for Uint<N> {
747    type Output = Self;
748
749    fn bitand(mut self, rhs: B) -> Self::Output {
750        self &= rhs;
751        self
752    }
753}
754
755impl<B: Borrow<Self>, const N: usize> BitOrAssign<B> for Uint<N> {
756    fn bitor_assign(&mut self, rhs: B) {
757        for i in 0..N {
758            self.limbs[i] |= rhs.borrow().limbs[i];
759        }
760    }
761}
762
763impl<B: Borrow<Self>, const N: usize> BitOr<B> for Uint<N> {
764    type Output = Self;
765
766    fn bitor(mut self, rhs: B) -> Self::Output {
767        self |= rhs;
768        self
769    }
770}
771
772impl<const N: usize> Not for Uint<N> {
773    type Output = Self;
774
775    fn not(self) -> Self::Output {
776        let mut result = Self::ZERO;
777        for i in 0..N {
778            result.limbs[i] = !self.limbs[i];
779        }
780        result
781    }
782}
783
784impl<const N: usize> Shr<u32> for Uint<N> {
785    type Output = Self;
786
787    fn shr(mut self, rhs: u32) -> Self::Output {
788        self >>= rhs;
789        self
790    }
791}
792
793impl<const N: usize> ShrAssign<u32> for Uint<N> {
794    #[allow(clippy::similar_names)]
795    #[allow(clippy::cast_possible_truncation)]
796    fn shr_assign(&mut self, rhs: u32) {
797        let shift = rhs as usize;
798        let bits = Limb::BITS as usize;
799
800        assert!(N * bits > shift, "attempt to shift right with overflow");
801
802        // Limb shift will probably affect changes between two adjacent limbs.
803        // Compute indexes of both limbs that can be changed during a single
804        // iteration.
805        let index2_shift = shift / bits;
806        let index1_shift = index2_shift + 1;
807
808        // The following shifts can overflow.
809        // Overflow should be interpreted with zero output.
810        let limb_right_shift = (shift % bits) as u32;
811        let limb_left_shift = (bits - shift % bits) as u32;
812
813        // Shift bits in limbs array in-place.
814        // Start from the lowest order limb.
815        for index in 0..N {
816            // Take limb from index leaving 0.
817            let current_limb = core::mem::take(&mut self.limbs[index]);
818
819            if index1_shift <= index {
820                let index1 = index - index1_shift;
821                // Possible to copy the first part of limb with bit AND
822                // operation, since the previous limbs were left zero.
823                self.limbs[index1] |= current_limb
824                    .checked_shl(limb_left_shift)
825                    .unwrap_or_default();
826            }
827
828            if index2_shift <= index {
829                let index2 = index - index2_shift;
830                // Possible to copy the second part of limb with bit AND
831                // operation, since the previous limbs were left zero.
832                self.limbs[index2] |= current_limb
833                    .checked_shr(limb_right_shift)
834                    .unwrap_or_default();
835            }
836        }
837    }
838}
839
840impl<const N: usize> Shl<u32> for Uint<N> {
841    type Output = Self;
842
843    fn shl(mut self, rhs: u32) -> Self::Output {
844        self <<= rhs;
845        self
846    }
847}
848
849impl<const N: usize> ShlAssign<u32> for Uint<N> {
850    #[allow(clippy::similar_names)]
851    #[allow(clippy::cast_possible_truncation)]
852    fn shl_assign(&mut self, rhs: u32) {
853        let shift = rhs as usize;
854        let bits = Limb::BITS as usize;
855
856        assert!(N * bits > shift, "attempt to shift left with overflow");
857
858        // Limb shift will probably affect changes between two adjacent limbs.
859        // Compute indexes of both limbs that can be changed during a single
860        // iteration.
861        let index1_shift = shift / bits;
862        let index2_shift = index1_shift + 1;
863
864        // The following shifts can overflow.
865        // Overflow should be interpreted with zero output.
866        let limb_left_shift = (shift % bits) as u32;
867        let limb_right_shift = (bits - shift % bits) as u32;
868
869        // Shift bits in limbs array in-place.
870        // Start from the highest order limb.
871        for index in (0..N).rev() {
872            // Take limb from index leaving 0.
873            let current_limb = core::mem::take(&mut self.limbs[index]);
874
875            let index1 = index + index1_shift;
876            if index1 < N {
877                // Possible to copy the first part of limb with bit AND
878                // operation, since the previous limbs were left zero.
879                self.limbs[index1] |= current_limb
880                    .checked_shl(limb_left_shift)
881                    .unwrap_or_default();
882            }
883
884            let index2 = index + index2_shift;
885            if index2 < N {
886                // Possible to copy the second part of limb with bit AND
887                // operation, since the previous limbs were left zero.
888                self.limbs[index2] |= current_limb
889                    .checked_shr(limb_right_shift)
890                    .unwrap_or_default();
891            }
892        }
893    }
894}
895
896impl<const N: usize> BigInteger for Uint<N> {
897    const LIMB_BITS: usize = Limb::BITS as usize;
898    const MAX: Self = Self { limbs: [u64::MAX; N] };
899    const NUM_LIMBS: usize = N;
900    const ONE: Self = {
901        let mut one = Self::ZERO;
902        one.limbs[0] = 1;
903        one
904    };
905    const ZERO: Self = Self { limbs: [0u64; N] };
906
907    fn is_odd(&self) -> bool {
908        self.is_odd()
909    }
910
911    fn is_even(&self) -> bool {
912        self.is_even()
913    }
914
915    fn is_zero(&self) -> bool {
916        self.is_zero()
917    }
918
919    fn num_bits(&self) -> usize {
920        self.num_bits()
921    }
922
923    fn get_bit(&self, i: usize) -> bool {
924        self.get_bit(i)
925    }
926
927    fn from_bytes_le(bytes: &[u8]) -> Self {
928        Self::from_le_slice(bytes)
929    }
930
931    fn into_bytes_le(self) -> Vec<u8> {
932        self.limbs.iter().flat_map(|&limb| limb.to_le_bytes()).collect()
933    }
934}
935
936impl<const N: usize> BitIteratorBE for Uint<N> {
937    fn bit_be_iter(self) -> impl Iterator<Item = bool> {
938        self.into_limbs().into_iter().rev().flat_map(Limb::bit_be_iter)
939    }
940}
941
942impl BitIteratorBE for &[Limb] {
943    fn bit_be_iter(self) -> impl Iterator<Item = bool> {
944        self.iter().rev().copied().flat_map(Limb::bit_be_iter)
945    }
946}
947
948/// Parse a number from a string in a given radix.
949///
950/// This implementation can be slow on big numbers and possibly fail constant
951/// compilation by timeout.
952///
953/// I.e., convert string encoded integer `s` to base-`radix` number.
954#[must_use]
955#[allow(clippy::missing_panics_doc)]
956pub const fn from_str_radix<const LIMBS: usize>(
957    s: &str,
958    radix: u32,
959) -> Uint<LIMBS> {
960    let bytes = s.as_bytes();
961    assert!(!bytes.is_empty(), "empty string");
962
963    // The lowest order number is at the end of the string.
964    // Begin parsing from the last index of the string.
965    let mut index = bytes.len() - 1;
966
967    let mut uint = Uint::from_u32(0);
968    let mut order = Uint::from_u32(1);
969    let uint_radix = Uint::from_u32(radix);
970
971    loop {
972        let digit = Uint::from_u32(parse_digit(bytes[index], radix));
973
974        // Add a digit multiplied by order.
975        uint = uint.add(&digit.mul(&order));
976
977        // If we reached the beginning of the string, return the number.
978        if index == 0 {
979            return uint;
980        }
981
982        // Increase the order of magnitude.
983        order = uint_radix.mul(&order);
984
985        // Move to the next digit.
986        index -= 1;
987    }
988}
989
990/// Parse a number from a hex string.
991///
992/// This implementation performs faster than [`from_str_radix`], since it
993/// assumes the radix is already `16`.
994///
995/// If the string number is shorter, then [`Uint`] can store, returns a [`Uint`]
996/// with leading zeroes.
997///
998/// # Panics
999///
1000/// * If hex encoded number is too large to fit in [`Uint`].
1001#[must_use]
1002#[allow(clippy::missing_panics_doc)]
1003pub const fn from_str_hex<const LIMBS: usize>(s: &str) -> Uint<LIMBS> {
1004    let bytes = s.as_bytes();
1005    assert!(!bytes.is_empty(), "empty string");
1006
1007    // The lowest order number is at the end of the string.
1008    // Begin parsing from the last index of the string.
1009    let mut index = bytes.len() - 1;
1010
1011    // The lowest order limb is at the beginning of the `num` array.
1012    // Begin indexing from `0`.
1013    let mut num = [Limb::ZERO; LIMBS];
1014    let mut num_index = 0;
1015
1016    let digit_radix = 16;
1017    let digit_size = 4; // Size of a hex digit in bits (2^4 = 16).
1018    let digits_in_limb = Limb::BITS / digit_size;
1019
1020    loop {
1021        let digit = parse_digit(bytes[index], digit_radix) as Limb;
1022
1023        let limb_index = (num_index / digits_in_limb) as usize;
1024        assert!(limb_index < num.len(), "hex number is too large");
1025
1026        // Since a base-16 digit can be represented with the same bits, we can
1027        // copy these bits.
1028        num[limb_index] |= digit << ((num_index % digits_in_limb) * digit_size);
1029
1030        // If we reached the beginning of the string, return the number.
1031        if index == 0 {
1032            return Uint::new(num);
1033        }
1034
1035        // Move to the next digit.
1036        index -= 1;
1037        num_index += 1;
1038    }
1039}
1040
1041// Try to parse a digit from utf-8 byte.
1042const fn parse_digit(utf8_digit: u8, digit_radix: u32) -> u32 {
1043    let ch = parse_utf8_byte(utf8_digit);
1044    match ch.to_digit(digit_radix) {
1045        None => {
1046            panic!("invalid digit");
1047        }
1048        Some(digit) => digit,
1049    }
1050}
1051
1052/// Parse a single UTF-8 byte into a char.
1053///
1054/// Converts bytes to characters during compile-time string evaluation.
1055/// Only handles ASCII bytes (0x00-0x7F).
1056///
1057/// # Arguments
1058///
1059/// * `byte` - Byte to convert.
1060///
1061/// # Panics
1062///
1063/// * If the byte is non-ASCII (>= 0x80).
1064pub(crate) const fn parse_utf8_byte(byte: u8) -> char {
1065    match byte {
1066        0x00..=0x7F => byte as char,
1067        _ => panic!("non-ASCII character found"),
1068    }
1069}
1070
1071/// This macro converts a string base-10 number to a big integer.
1072#[macro_export]
1073macro_rules! from_num {
1074    ($num:literal) => {
1075        $crate::arithmetic::uint::from_str_radix($num, 10)
1076    };
1077}
1078
1079/// This macro converts a string hex number to a big integer.
1080#[macro_export]
1081macro_rules! from_hex {
1082    ($num:literal) => {
1083        $crate::arithmetic::uint::from_str_hex($num)
1084    };
1085}
1086
1087/// Integer that uses twice more limbs than `Uint` for the same `N` parameter.
1088#[derive(Copy, Clone, PartialEq, Eq, Hash, Zeroize)]
1089pub struct WideUint<const N: usize> {
1090    low: Uint<N>,
1091    high: Uint<N>,
1092}
1093
1094impl<const N: usize> WideUint<N> {
1095    /// Construct new [`WideUint`] from `low` and `high` parts.
1096    #[must_use]
1097    pub const fn new(low: Uint<N>, high: Uint<N>) -> Self {
1098        Self { low, high }
1099    }
1100
1101    /// Compute the remainder of division `self` by `rhs` (constant).
1102    ///
1103    /// Basic division algorithm based on [wiki].
1104    /// Fine to be used for constant evaluation, but slow in runtime.
1105    ///
1106    /// [wiki]: https://en.wikipedia.org/wiki/Division_algorithm
1107    #[must_use]
1108    #[allow(clippy::missing_panics_doc)]
1109    pub const fn rem(&self, rhs: &Uint<N>) -> Uint<N> {
1110        assert!(!rhs.is_zero(), "should not divide by zero");
1111
1112        let mut remainder = Uint::<N>::ZERO;
1113        let num_bits = self.num_bits();
1114
1115        // Start from the last bit.
1116        const_rev_for!((index in 0..num_bits) {
1117            // Shift the remainder to the left by 1,
1118            let (result, carry) = remainder.checked_mul2();
1119            remainder = result;
1120
1121            // and set the first bit to remainder from the dividend.
1122            remainder.limbs[0] |= self.get_bit(index) as Limb;
1123
1124            // If the remainder overflows, subtract the divisor.
1125            if remainder.ge(rhs) || carry {
1126                (remainder, _) = remainder.checked_sub(rhs);
1127            }
1128        });
1129
1130        remainder
1131    }
1132
1133    /// Find the number of bits in the binary decomposition of `self`.
1134    ///
1135    /// One bit is necessary to encode zero.
1136    #[must_use]
1137    pub const fn num_bits(&self) -> usize {
1138        if self.high.is_zero() {
1139            self.low.num_bits()
1140        } else {
1141            self.high.num_bits() + Uint::<N>::BITS
1142        }
1143    }
1144
1145    /// Compute the `i`-th bit of `self`.
1146    #[must_use]
1147    pub const fn get_bit(&self, i: usize) -> bool {
1148        if i >= Uint::<N>::BITS {
1149            self.high.get_bit(i - Uint::<N>::BITS)
1150        } else {
1151            self.low.get_bit(i)
1152        }
1153    }
1154}
1155
1156#[cfg(test)]
1157mod test {
1158    use proptest::prelude::*;
1159
1160    use crate::{
1161        arithmetic::{
1162            uint::{
1163                from_str_hex, from_str_radix, Uint, WideUint, U256, U512, U64,
1164            },
1165            BigInteger, Limb,
1166        },
1167        bits::BitIteratorBE,
1168    };
1169
1170    #[test]
1171    fn convert_from_str_radix() {
1172        let uint_from_base10: Uint<4> = from_str_radix(
1173            "28948022309329048855892746252171976963363056481941647379679742748393362948097",
1174            10,
1175        );
1176        #[allow(clippy::unreadable_literal)]
1177        let expected = Uint::<4>::new([
1178            10108024940646105089u64,
1179            2469829653919213789u64,
1180            0u64,
1181            4611686018427387904u64,
1182        ]);
1183        assert_eq!(uint_from_base10, expected);
1184
1185        let uint_from_base10: Uint<1> =
1186            from_str_radix("18446744069414584321", 10);
1187        let uint_from_binary: Uint<1> = from_str_radix(
1188            "1111111111111111111111111111111100000000000000000000000000000001",
1189            2,
1190        );
1191        assert_eq!(uint_from_base10, uint_from_binary);
1192    }
1193
1194    #[test]
1195    fn convert_from_str_hex() {
1196        // Test different implementations of hex parsing on random hex inputs.
1197        proptest!(|(hex in "[0-9a-fA-F]{1,64}")| {
1198            let uint_from_hex: Uint<4> = from_str_hex(&hex);
1199            let expected: Uint<4> = from_str_radix(&hex, 16);
1200            prop_assert_eq!(uint_from_hex, expected);
1201        });
1202    }
1203
1204    #[test]
1205    #[should_panic = "hex number is too large"]
1206    fn from_str_hex_should_panic_on_overflow() {
1207        let _ = from_str_hex::<4>(
1208            "ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0",
1209        );
1210    }
1211
1212    #[test]
1213    fn parse_and_display_hex() {
1214        // Test parsing from upper hex against displaying in upper hex.
1215        proptest!(|(upper_hex in "[0-9A-F]{64}")| {
1216            let uint_from_hex: Uint<4> = from_str_hex(&upper_hex);
1217            let hex_from_uint = format!("{uint_from_hex:X}");
1218            prop_assert_eq!(hex_from_uint, upper_hex);
1219        });
1220    }
1221
1222    #[test]
1223    fn uint_bit_iterator_be() {
1224        let words: [Limb; 4] = [0b1100, 0, 0, 0];
1225        let num = Uint::<4>::new(words);
1226        let bits: Vec<bool> = num.bit_be_trimmed_iter().collect();
1227
1228        assert_eq!(bits.len(), 4);
1229        assert_eq!(bits, vec![true, true, false, false]);
1230    }
1231
1232    #[test]
1233    fn num_bits() {
1234        let words: [Limb; 4] = [0b1100, 0, 0, 0];
1235        let num = Uint::<4>::new(words);
1236        assert_eq!(num.num_bits(), 4);
1237
1238        let words: [Limb; 4] = [0, 0b1100, 0, 0];
1239        let num = Uint::<4>::new(words);
1240        assert_eq!(num.num_bits(), 64 + 4);
1241
1242        let words: [Limb; 4] = [0b11, 0b11, 0b11, 0b11];
1243        let num = Uint::<4>::new(words);
1244        assert_eq!(num.num_bits(), 64 + 64 + 64 + 2);
1245    }
1246
1247    #[test]
1248    fn rem() {
1249        let dividend = from_num!("43129923721897334698312931");
1250        let divisor = from_num!("375923422");
1251        let result =
1252            WideUint::<4>::new(dividend, Uint::<4>::ZERO).rem(&divisor);
1253        assert_eq!(result, from_num!("216456157"));
1254    }
1255
1256    #[test]
1257    #[should_panic = "should not divide by zero"]
1258    fn rem_zero() {
1259        let zero = Uint::<4>::ZERO;
1260        let divisor = from_num!("375923422");
1261        let result = WideUint::<4>::new(zero, zero).rem(&divisor);
1262        assert_eq!(result, zero);
1263
1264        let dividend = from_num!("43129923721897334698312931");
1265        let divisor = zero;
1266        let _ = WideUint::<4>::new(dividend, zero).rem(&divisor);
1267    }
1268
1269    #[test]
1270    fn ge_le_gt_lt_eq_ne() {
1271        let a: Uint<4> = Uint::new([0, 0, 0, 5]);
1272        let b: Uint<4> = Uint::new([4, 0, 0, 0]);
1273        assert!(a.ge(&b));
1274        assert!(a.gt(&b));
1275        assert!(!a.le(&b));
1276        assert!(!a.lt(&b));
1277        assert!(!a.eq(&b));
1278        assert!(a.ne(&b));
1279
1280        let a: Uint<4> = Uint::new([0, 0, 0, 5]);
1281        let b: Uint<4> = Uint::new([0, 0, 0, 6]);
1282        assert!(!a.ge(&b));
1283        assert!(!a.gt(&b));
1284        assert!(a.le(&b));
1285        assert!(a.lt(&b));
1286        assert!(!a.eq(&b));
1287        assert!(a.ne(&b));
1288
1289        let a: Uint<4> = Uint::new([0, 0, 1, 2]);
1290        let b: Uint<4> = Uint::new([0, 0, 1, 2]);
1291        assert!(a.ge(&b));
1292        assert!(!a.gt(&b));
1293        assert!(a.le(&b));
1294        assert!(!a.lt(&b));
1295        assert!(a.eq(&b));
1296        assert!(!a.ne(&b));
1297    }
1298
1299    #[test]
1300    fn shl() {
1301        // The first limb is the lowest order part of the number.
1302        let num = Uint::<4>::new([0b1100000000, 0, 0, 0]);
1303
1304        let expected = Uint::<4>::new([0, 0b11000000, 0, 0]);
1305        assert_eq!(num << 62, expected);
1306
1307        let expected = Uint::<4>::new([0, 0, 0b110000, 0]);
1308        assert_eq!(num << (60 + 64), expected);
1309
1310        let expected = Uint::<4>::new([0, 0, 0, 0b1100]);
1311        assert_eq!(num << (58 + 64 + 64), expected);
1312
1313        // edge case to make shift the number into all zeroes
1314        let expected = Uint::<4>::new([0, 0, 0, 0]);
1315        assert_eq!(num << (56 + 64 + 64 + 64), expected);
1316    }
1317
1318    #[test]
1319    #[should_panic = "attempt to shift left with overflow"]
1320    fn shl_overflow_should_panic() {
1321        let num = Uint::<4>::ONE;
1322        let _ = num << (64 * 4);
1323    }
1324
1325    #[test]
1326    fn shr() {
1327        // The last limb is the highest order part of the number.
1328        let num = Uint::<4>::new([0, 0, 0, 0b11]);
1329
1330        let expected = Uint::<4>::new([0, 0, 0b1100, 0]);
1331        assert_eq!(num >> 62, expected);
1332
1333        let expected = Uint::<4>::new([0, 0b110000, 0, 0]);
1334        assert_eq!(num >> (60 + 64), expected);
1335
1336        let expected = Uint::<4>::new([0b11000000, 0, 0, 0]);
1337        assert_eq!(num >> (58 + 64 + 64), expected);
1338
1339        // edge case to make shift the number into all zeroes
1340        let expected = Uint::<4>::new([0, 0, 0, 0]);
1341        assert_eq!(num >> (2 + 64 + 64 + 64), expected);
1342    }
1343
1344    #[test]
1345    #[should_panic = "attempt to shift right with overflow"]
1346    fn shr_overflow_should_panic() {
1347        let num = Uint::<4>::ONE;
1348        let _ = num >> (64 * 4);
1349    }
1350
1351    #[test]
1352    fn shr_shl_edge_case() {
1353        let num = Uint::<4>::ONE;
1354        assert_eq!(num >> 0, num);
1355        assert_eq!(num << 0, num);
1356
1357        let num = Uint::<4>::new([
1358            0xffffffffffffffff,
1359            0xffffffffffffffff,
1360            0,
1361            0xffffffffffffffff,
1362        ]);
1363
1364        assert_eq!(
1365            num >> 64,
1366            Uint::<4>::new([0xffffffffffffffff, 0, 0xffffffffffffffff, 0])
1367        );
1368
1369        assert_eq!(
1370            num << 64,
1371            Uint::<4>::new([0, 0xffffffffffffffff, 0xffffffffffffffff, 0])
1372        );
1373    }
1374
1375    #[test]
1376    fn test_process_single_element_masks_correctly() {
1377        let low_part_bits = 248;
1378        let low_part_mask: U256 = from_str_hex(
1379            "00ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff",
1380        );
1381        let element: U256 = from_str_hex(
1382            "01ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff",
1383        );
1384        let high_part = element >> low_part_bits;
1385        let low_part = element & low_part_mask;
1386        assert_eq!(high_part, U256::ONE);
1387        assert_eq!(low_part, low_part_mask);
1388    }
1389
1390    #[cfg(feature = "ruint")]
1391    mod ruint_conversion_test {
1392        use super::*;
1393
1394        /// This macro generates property-based tests for bidirectional
1395        /// conversions between [`ruint::Uint`] and [`Uint`] types.
1396        ///
1397        /// Each test verifies that round-trip conversions preserve the original
1398        /// value: `ruint::Uint -> Uint -> ruint::Uint` should equal the
1399        /// original value.
1400        ///
1401        /// The number of limbs is automatically calculated using
1402        /// `usize::div_ceil(bits, Limb::BITS)`.
1403        macro_rules! test_ruint_conversion {
1404            ($test_name:ident, $uint_type:ident, $bits:expr) => {
1405                #[test]
1406                fn $test_name() {
1407                    proptest!(|(value: ruint::Uint<$bits, { usize::div_ceil($bits, $crate::arithmetic::Limb::BITS as usize) }>)| {
1408                        let uint_from_ruint: crate::arithmetic::uint::$uint_type = value.into();
1409                        let expected: ruint::Uint<$bits, { usize::div_ceil($bits, $crate::arithmetic::Limb::BITS as usize) }> = uint_from_ruint.into();
1410                        prop_assert_eq!(value, expected);
1411                    });
1412                }
1413            };
1414        }
1415
1416        test_ruint_conversion!(ruint_u64, U64, 64);
1417        test_ruint_conversion!(ruint_u128, U128, 128);
1418        test_ruint_conversion!(ruint_u256, U256, 256);
1419    }
1420
1421    mod primitive_conversion_test {
1422        use super::*;
1423
1424        macro_rules! test_uint_conversion {
1425            ($test_name:ident, $type:ty) => {
1426                #[test]
1427                fn $test_name() {
1428                    proptest!(|(expected_primitive_num: $type)| {
1429                        let num: U256 = expected_primitive_num.into();
1430                        let primitive_num: $type = num.into();
1431                        assert_eq!(expected_primitive_num, primitive_num);
1432                    });
1433                }
1434            };
1435        }
1436
1437        test_uint_conversion!(uint_u8, u8);
1438        test_uint_conversion!(uint_u16, u16);
1439        test_uint_conversion!(uint_u32, u32);
1440        test_uint_conversion!(uint_u64, u64);
1441        test_uint_conversion!(uint_u128, u128);
1442        test_uint_conversion!(uint_usize, usize);
1443
1444        #[test]
1445        fn edge_case_u64_to_u128() {
1446            let uint_origin: U64 = from_str_hex("ff");
1447            let tmp: u128 = uint_origin.into();
1448            assert_eq!(tmp, 0xff);
1449        }
1450    }
1451
1452    #[cfg(feature = "ruint")]
1453    #[test]
1454    fn test_ruint_to_uint_conversion_unexpected_panic() {
1455        let ruint_origin: ruint::Uint<200, 4> = ruint::Uint::from(42);
1456        // 256 > 200, Should success
1457        let _uint_from_ruint: U256 = ruint_origin.into();
1458    }
1459
1460    #[test]
1461    fn from_uint() {
1462        // Check that conversion between integers with different bit size works.
1463        proptest!(|(limbs: [u64; 4])|{
1464            let expected_uint = U256::new(limbs);
1465            let wide_uint = U512::from_uint(expected_uint);
1466            let uint = U256::from_uint(wide_uint);
1467
1468            assert_eq!(uint, expected_uint);
1469        });
1470    }
1471}