1use 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#[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
43macro_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 #[must_use]
71 pub const fn new(limbs: [Limb; N]) -> Self {
72 Self { limbs }
73 }
74
75 #[must_use]
77 pub const fn as_limbs(&self) -> &Limbs<N> {
78 &self.limbs
79 }
80
81 #[must_use]
83 pub const fn into_limbs(self) -> Limbs<N> {
84 self.limbs
85 }
86
87 #[doc(hidden)]
89 #[inline]
90 #[must_use]
91 pub const fn is_odd(&self) -> bool {
92 self.limbs[0] & 1 == 1
93 }
94
95 #[doc(hidden)]
97 #[inline]
98 #[must_use]
99 pub const fn is_even(&self) -> bool {
100 self.limbs[0] & 1 == 0
101 }
102
103 #[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 #[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 #[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 #[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 #[must_use]
173 #[inline(always)]
174 pub const fn is_zero(&self) -> bool {
175 self.eq(&Self::ZERO)
176 }
177
178 #[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 #[must_use]
192 #[inline(always)]
193 pub const fn ne(&self, rhs: &Self) -> bool {
194 !self.eq(rhs)
195 }
196
197 #[doc(hidden)]
201 #[must_use]
202 pub const fn num_bits(&self) -> usize {
203 if self.is_zero() {
205 return 1;
206 }
207
208 let mut num_bits = Self::BITS;
210
211 const_rev_for!((index in 0..N) {
213 let leading = self.limbs[index].leading_zeros() as usize;
215 num_bits -= leading;
216
217 if leading != 64 {
219 break;
220 }
221 });
222
223 num_bits
225 }
226
227 #[must_use]
229 pub const fn get_bit(&self, i: usize) -> bool {
230 if i >= Self::BITS {
232 return false;
233 }
234
235 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 #[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 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 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 #[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 #[inline(always)]
300 #[must_use]
301 pub const fn wrapping_sub(&self, rhs: &Self) -> Self {
302 self.checked_sub(rhs).0
303 }
304
305 #[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 #[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 #[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 #[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 const_for_unroll6!((i in 0..N) {
361 let mut carry = 0;
362 const_for_unroll6!((j in 0..N) {
364 let k = i + j;
366 if k >= N {
367 (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 hi[i] = carry;
385 });
386
387 (Self::new(lo), Self::new(hi))
388 }
389
390 #[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 #[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 #[must_use]
411 pub const fn wrapping_add(&self, rhs: &Self) -> Self {
412 let (low, _) = self.adc(rhs, false);
413 low
414 }
415
416 #[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 #[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 #[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
471macro_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
497impl<const N: usize> Uint<N> {
500 #[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 N >= 2 {
513 let mut res = Self::ZERO;
515 res.limbs[0] = lo;
516 res.limbs[1] = hi;
517 res
518 } else if hi == Limb::ZERO {
519 let mut res = Self::ZERO;
521 res.limbs[0] = lo;
522 res
523 } else {
524 panic!("u128 is too large to fit");
526 }
527 }
528}
529
530macro_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
549macro_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 const_for!((i in 1..N) {
567 assert!(self.limbs[i] == 0, "Uint type is to large to fit");
569 });
570 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 #[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 const_for!((i in 2..N) {
604 assert!(self.limbs[i] == 0, "Uint type is to large to fit");
606 });
607
608 let res0 = self.limbs[0] as u128;
610 let res1 = (self.limbs[1] as u128) << 64;
611 res0 | res1
612 }
613 }
614 }
615}
616
617macro_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 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 ruint::Uint::from_le_slice(&value.into_bytes_le())
653 }
654}
655
656impl<const N: usize> UpperHex for Uint<N> {
659 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> Result {
660 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 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 let index2_shift = shift / bits;
806 let index1_shift = index2_shift + 1;
807
808 let limb_right_shift = (shift % bits) as u32;
811 let limb_left_shift = (bits - shift % bits) as u32;
812
813 for index in 0..N {
816 let current_limb = core::mem::take(&mut self.limbs[index]);
818
819 if index1_shift <= index {
820 let index1 = index - index1_shift;
821 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 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 let index1_shift = shift / bits;
862 let index2_shift = index1_shift + 1;
863
864 let limb_left_shift = (shift % bits) as u32;
867 let limb_right_shift = (bits - shift % bits) as u32;
868
869 for index in (0..N).rev() {
872 let current_limb = core::mem::take(&mut self.limbs[index]);
874
875 let index1 = index + index1_shift;
876 if index1 < N {
877 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 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#[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 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 uint = uint.add(&digit.mul(&order));
976
977 if index == 0 {
979 return uint;
980 }
981
982 order = uint_radix.mul(&order);
984
985 index -= 1;
987 }
988}
989
990#[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 let mut index = bytes.len() - 1;
1010
1011 let mut num = [Limb::ZERO; LIMBS];
1014 let mut num_index = 0;
1015
1016 let digit_radix = 16;
1017 let digit_size = 4; 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 num[limb_index] |= digit << ((num_index % digits_in_limb) * digit_size);
1029
1030 if index == 0 {
1032 return Uint::new(num);
1033 }
1034
1035 index -= 1;
1037 num_index += 1;
1038 }
1039}
1040
1041const 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
1052pub(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#[macro_export]
1073macro_rules! from_num {
1074 ($num:literal) => {
1075 $crate::arithmetic::uint::from_str_radix($num, 10)
1076 };
1077}
1078
1079#[macro_export]
1081macro_rules! from_hex {
1082 ($num:literal) => {
1083 $crate::arithmetic::uint::from_str_hex($num)
1084 };
1085}
1086
1087#[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 #[must_use]
1097 pub const fn new(low: Uint<N>, high: Uint<N>) -> Self {
1098 Self { low, high }
1099 }
1100
1101 #[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 const_rev_for!((index in 0..num_bits) {
1117 let (result, carry) = remainder.checked_mul2();
1119 remainder = result;
1120
1121 remainder.limbs[0] |= self.get_bit(index) as Limb;
1123
1124 if remainder.ge(rhs) || carry {
1126 (remainder, _) = remainder.checked_sub(rhs);
1127 }
1128 });
1129
1130 remainder
1131 }
1132
1133 #[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 #[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 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 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 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 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 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 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 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 let _uint_from_ruint: U256 = ruint_origin.into();
1458 }
1459
1460 #[test]
1461 fn from_uint() {
1462 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}