1#[cfg(feature = "extra-sizes")]
4pub use extra_sizes::*;
5
6pub(crate) use ref_type::UintRef;
7
8use crate::{
9 Bounded, Choice, ConstOne, ConstZero, Constants, CtEq, CtOption, EncodedUint, FixedInteger,
10 Int, Integer, Limb, NonZero, Odd, One, Unsigned, UnsignedWithMontyForm, Word, Zero, bitlen,
11 limb::nlimbs, modular::FixedMontyForm, traits::sealed::Sealed,
12};
13use core::fmt;
14
15#[cfg(feature = "serde")]
16use crate::Encoding;
17#[cfg(feature = "serde")]
18use serdect::serde::{Deserialize, Deserializer, Serialize, Serializer};
19#[cfg(feature = "zeroize")]
20use zeroize::DefaultIsZeroes;
21
22#[cfg(doc)]
23use crate::{NonZeroUint, OddUint};
24
25#[macro_use]
26mod macros;
27
28mod add;
29mod add_mod;
30mod bit_and;
31mod bit_not;
32mod bit_or;
33mod bit_xor;
34mod bits;
35mod cmp;
36mod concat;
37mod ct;
38mod div;
39pub(crate) mod div_limb;
40pub(crate) mod encoding;
41mod from;
42pub(crate) mod gcd;
43mod invert_mod;
44pub(crate) mod lcm;
45mod mod_symbol;
46pub(crate) mod mul;
47mod mul_mod;
48mod mul_signed;
49mod neg;
50mod neg_mod;
51mod pow;
52pub(crate) mod ref_type;
53mod resize;
54mod root;
55mod shl;
56mod shr;
57mod split;
58mod sqrt;
59mod sub;
60mod sub_mod;
61
62#[cfg(feature = "hybrid-array")]
63mod array;
64#[cfg(feature = "alloc")]
65pub(crate) mod boxed;
66#[cfg(feature = "extra-sizes")]
67mod extra_sizes;
68#[cfg(feature = "rand_core")]
69mod rand;
70
71#[allow(clippy::derived_hash_with_manual_eq)]
90#[derive(Copy, Clone, Hash)]
91pub struct Uint<const LIMBS: usize> {
92 pub(crate) limbs: [Limb; LIMBS],
94}
95
96impl<const LIMBS: usize> Uint<LIMBS> {
97 pub const ZERO: Self = Self::from_u8(0);
99
100 pub const ONE: Self = Self::from_u8(1);
102
103 pub const MAX: Self = Self {
105 limbs: [Limb::MAX; LIMBS],
106 };
107
108 pub const BITS: u32 = bitlen::from_limbs(LIMBS);
110
111 pub const BYTES: usize = LIMBS * Limb::BYTES;
113
114 pub const LIMBS: usize = LIMBS;
116
117 #[must_use]
119 pub const fn new(limbs: [Limb; LIMBS]) -> Self {
120 Self { limbs }
121 }
122
123 #[inline]
126 #[must_use]
127 pub const fn from_words(arr: [Word; LIMBS]) -> Self {
128 let mut limbs = [Limb::ZERO; LIMBS];
129 let mut i = 0;
130
131 while i < LIMBS {
132 limbs[i] = Limb(arr[i]);
133 i += 1;
134 }
135
136 Self { limbs }
137 }
138
139 #[inline]
142 #[must_use]
143 pub const fn to_words(self) -> [Word; LIMBS] {
144 let mut arr = [0; LIMBS];
145 let mut i = 0;
146
147 while i < LIMBS {
148 arr[i] = self.limbs[i].0;
149 i += 1;
150 }
151
152 arr
153 }
154
155 #[must_use]
157 pub const fn as_words(&self) -> &[Word; LIMBS] {
158 Limb::array_as_words(&self.limbs)
159 }
160
161 pub const fn as_mut_words(&mut self) -> &mut [Word; LIMBS] {
163 Limb::array_as_mut_words(&mut self.limbs)
164 }
165
166 #[deprecated(since = "0.7.0", note = "please use `as_mut_words` instead")]
168 pub const fn as_words_mut(&mut self) -> &mut [Word] {
169 self.as_mut_words()
170 }
171
172 #[must_use]
174 pub const fn as_limbs(&self) -> &[Limb; LIMBS] {
175 &self.limbs
176 }
177
178 pub const fn as_mut_limbs(&mut self) -> &mut [Limb; LIMBS] {
180 &mut self.limbs
181 }
182
183 #[deprecated(since = "0.7.0", note = "please use `as_mut_limbs` instead")]
185 pub const fn as_limbs_mut(&mut self) -> &mut [Limb] {
186 self.as_mut_limbs()
187 }
188
189 #[must_use]
191 pub const fn to_limbs(self) -> [Limb; LIMBS] {
192 self.limbs
193 }
194
195 #[inline]
197 #[must_use]
198 pub const fn as_uint_ref(&self) -> &UintRef {
199 UintRef::new(&self.limbs)
200 }
201
202 #[inline]
204 #[must_use]
205 pub const fn as_mut_uint_ref(&mut self) -> &mut UintRef {
206 UintRef::new_mut(&mut self.limbs)
207 }
208
209 #[inline]
211 #[must_use]
212 pub const fn as_nz_vartime(&self) -> Option<&NonZero<Self>> {
213 if self.is_zero_vartime() {
214 None
215 } else {
216 Some(NonZero::new_ref_unchecked(self))
217 }
218 }
219
220 #[must_use]
224 pub const fn to_nz(&self) -> CtOption<NonZero<Self>> {
225 let (nz, self_nz) = self.to_nz_or_one();
226 CtOption::new(nz, self_nz)
227 }
228
229 #[must_use]
233 pub const fn to_nz_vartime(&self) -> Option<NonZero<Self>> {
234 if self.is_zero_vartime() {
235 None
236 } else {
237 Some(NonZero::new_unchecked(*self))
238 }
239 }
240
241 #[inline(always)]
246 #[must_use]
247 pub(crate) const fn to_nz_or_one(self) -> (NonZero<Self>, Choice) {
248 let is_nz = self.is_nonzero();
249 (
250 NonZero::new_unchecked(Self::select(&Self::ONE, &self, is_nz)),
251 is_nz,
252 )
253 }
254
255 #[must_use]
259 pub const fn to_odd(&self) -> CtOption<Odd<Self>> {
260 let (odd, self_odd) = self.to_odd_or_one();
261 CtOption::new(odd, self_odd)
262 }
263
264 #[inline(always)]
269 #[must_use]
270 pub(crate) const fn to_odd_or_one(self) -> (Odd<Self>, Choice) {
271 let is_odd = self.is_odd();
272 (
273 Odd::new_unchecked(Self::select(&Self::ONE, &self, is_odd)),
274 is_odd,
275 )
276 }
277
278 #[must_use]
282 pub const fn as_int(&self) -> &Int<LIMBS> {
283 #[allow(unsafe_code)]
286 unsafe {
287 &*core::ptr::from_ref(self).cast::<Int<LIMBS>>()
288 }
289 }
290
291 #[must_use]
295 pub const fn try_into_int(self) -> CtOption<Int<LIMBS>> {
296 Int::new_from_abs_sign(self, Choice::FALSE)
297 }
298
299 #[must_use]
301 pub const fn is_zero(&self) -> Choice {
302 self.is_nonzero().not()
303 }
304}
305
306impl<const LIMBS: usize> AsRef<[Word; LIMBS]> for Uint<LIMBS> {
307 fn as_ref(&self) -> &[Word; LIMBS] {
308 self.as_words()
309 }
310}
311
312impl<const LIMBS: usize> AsMut<[Word; LIMBS]> for Uint<LIMBS> {
313 fn as_mut(&mut self) -> &mut [Word; LIMBS] {
314 self.as_mut_words()
315 }
316}
317
318impl<const LIMBS: usize> AsRef<[Limb]> for Uint<LIMBS> {
319 fn as_ref(&self) -> &[Limb] {
320 self.as_limbs()
321 }
322}
323
324impl<const LIMBS: usize> AsMut<[Limb]> for Uint<LIMBS> {
325 fn as_mut(&mut self) -> &mut [Limb] {
326 self.as_mut_limbs()
327 }
328}
329
330impl<const LIMBS: usize> AsRef<UintRef> for Uint<LIMBS> {
331 fn as_ref(&self) -> &UintRef {
332 self.as_uint_ref()
333 }
334}
335
336impl<const LIMBS: usize> AsMut<UintRef> for Uint<LIMBS> {
337 fn as_mut(&mut self) -> &mut UintRef {
338 self.as_mut_uint_ref()
339 }
340}
341
342impl<const LIMBS: usize> Bounded for Uint<LIMBS> {
343 const BITS: u32 = Self::BITS;
344 const BYTES: usize = Self::BYTES;
345}
346
347impl<const LIMBS: usize> Constants for Uint<LIMBS> {
348 const MAX: Self = Self::MAX;
349}
350
351impl<const LIMBS: usize> Default for Uint<LIMBS> {
352 fn default() -> Self {
353 Self::ZERO
354 }
355}
356
357impl<const LIMBS: usize> FixedInteger for Uint<LIMBS> {
358 const LIMBS: usize = LIMBS;
359}
360
361impl<const LIMBS: usize> Integer for Uint<LIMBS> {
362 fn as_limbs(&self) -> &[Limb] {
363 &self.limbs
364 }
365
366 fn as_mut_limbs(&mut self) -> &mut [Limb] {
367 &mut self.limbs
368 }
369
370 fn nlimbs(&self) -> usize {
371 Self::LIMBS
372 }
373}
374
375impl<const LIMBS: usize> Sealed for Uint<LIMBS> {}
376
377impl<const LIMBS: usize> Unsigned for Uint<LIMBS> {
378 fn as_uint_ref(&self) -> &UintRef {
379 self.as_uint_ref()
380 }
381
382 fn as_mut_uint_ref(&mut self) -> &mut UintRef {
383 self.as_mut_uint_ref()
384 }
385
386 fn from_limb_like(limb: Limb, _other: &Self) -> Self {
387 Self::from(limb)
388 }
389}
390
391impl<const LIMBS: usize> UnsignedWithMontyForm for Uint<LIMBS> {
392 type MontyForm = FixedMontyForm<LIMBS>;
393}
394
395impl<const LIMBS: usize> num_traits::Num for Uint<LIMBS> {
396 type FromStrRadixErr = crate::DecodeError;
397
398 fn from_str_radix(str: &str, radix: u32) -> Result<Self, Self::FromStrRadixErr> {
404 Self::from_str_radix_vartime(str, radix)
405 }
406}
407
408impl<const LIMBS: usize> ConstZero for Uint<LIMBS> {
409 const ZERO: Self = Self::ZERO;
410}
411
412impl<const LIMBS: usize> ConstOne for Uint<LIMBS> {
413 const ONE: Self = Self::ONE;
414}
415
416impl<const LIMBS: usize> Zero for Uint<LIMBS> {
417 #[inline(always)]
418 fn zero() -> Self {
419 Self::ZERO
420 }
421}
422
423impl<const LIMBS: usize> One for Uint<LIMBS> {
424 #[inline(always)]
425 fn one() -> Self {
426 Self::ONE
427 }
428}
429
430impl<const LIMBS: usize> num_traits::Zero for Uint<LIMBS> {
431 #[inline(always)]
432 fn zero() -> Self {
433 Self::ZERO
434 }
435
436 fn is_zero(&self) -> bool {
437 self.ct_eq(&Self::ZERO).into()
438 }
439}
440
441impl<const LIMBS: usize> num_traits::One for Uint<LIMBS> {
442 #[inline(always)]
443 fn one() -> Self {
444 Self::ONE
445 }
446
447 fn is_one(&self) -> bool {
448 self.ct_eq(&Self::ONE).into()
449 }
450}
451
452impl<const LIMBS: usize> fmt::Debug for Uint<LIMBS> {
453 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
454 write!(f, "Uint(0x{:X})", self.as_uint_ref())
455 }
456}
457
458impl<const LIMBS: usize> fmt::Binary for Uint<LIMBS> {
459 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
460 fmt::Binary::fmt(self.as_uint_ref(), f)
461 }
462}
463
464impl<const LIMBS: usize> fmt::Display for Uint<LIMBS> {
465 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
466 fmt::UpperHex::fmt(self, f)
467 }
468}
469
470impl<const LIMBS: usize> fmt::LowerHex for Uint<LIMBS> {
471 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
472 fmt::LowerHex::fmt(self.as_uint_ref(), f)
473 }
474}
475
476impl<const LIMBS: usize> fmt::UpperHex for Uint<LIMBS> {
477 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
478 fmt::UpperHex::fmt(self.as_uint_ref(), f)
479 }
480}
481
482#[cfg(feature = "serde")]
483impl<'de, const LIMBS: usize> Deserialize<'de> for Uint<LIMBS>
484where
485 Uint<LIMBS>: Encoding,
486{
487 fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
488 where
489 D: Deserializer<'de>,
490 {
491 let mut buffer = Encoding::to_le_bytes(&Self::ZERO);
492 serdect::array::deserialize_hex_or_bin(buffer.as_mut(), deserializer)?;
493
494 Ok(Encoding::from_le_bytes(buffer))
495 }
496}
497
498#[cfg(feature = "serde")]
499impl<const LIMBS: usize> Serialize for Uint<LIMBS>
500where
501 Uint<LIMBS>: Encoding,
502{
503 fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
504 where
505 S: Serializer,
506 {
507 serdect::slice::serialize_hex_lower_or_bin(&Encoding::to_le_bytes(self), serializer)
508 }
509}
510
511#[cfg(feature = "zeroize")]
512impl<const LIMBS: usize> DefaultIsZeroes for Uint<LIMBS> {}
513
514impl_uint_aliases! {
516 (U64, 64, "64-bit"),
517 (U128, 128, "128-bit"),
518 (U192, 192, "192-bit"),
519 (U256, 256, "256-bit"),
520 (U320, 320, "320-bit"),
521 (U384, 384, "384-bit"),
522 (U448, 448, "448-bit"),
523 (U512, 512, "512-bit"),
524 (U576, 576, "576-bit"),
525 (U640, 640, "640-bit"),
526 (U704, 704, "704-bit"),
527 (U768, 768, "768-bit"),
528 (U832, 832, "832-bit"),
529 (U896, 896, "896-bit"),
530 (U960, 960, "960-bit"),
531 (U1024, 1024, "1024-bit"),
532 (U1280, 1280, "1280-bit"),
533 (U1536, 1536, "1536-bit"),
534 (U1792, 1792, "1792-bit"),
535 (U2048, 2048, "2048-bit"),
536 (U3072, 3072, "3072-bit"),
537 (U3584, 3584, "3584-bit"),
538 (U4096, 4096, "4096-bit"),
539 (U4224, 4224, "4224-bit"),
540 (U4352, 4352, "4352-bit"),
541 (U6144, 6144, "6144-bit"),
542 (U8192, 8192, "8192-bit"),
543 (U16384, 16384, "16384-bit"),
544 (U32768, 32768, "32768-bit")
545}
546
547cpubits::cpubits! {
548 32 => {
549 impl_uint_aliases! {
550 (U224, 224, "224-bit"), (U544, 544, "544-bit") }
553 impl_uint_concat_split_even! {
554 U64,
555 }
556 }
557}
558
559impl_uint_concat_split_even! {
562 U128,
563 U256,
564 U384,
565 U512,
566 U640,
567 U768,
568 U896,
569 U1024,
570 U1280,
571 U1536,
572 U1792,
573 U2048,
574 U3072,
575 U3584,
576 U4096,
577 U4224,
578 U4352,
579 U6144,
580 U8192,
581 U16384,
582}
583
584impl_uint_concat_split_mixed! {
590 (U192, [1, 2]),
591 (U256, [1, 3]),
592 (U320, [1, 2, 3, 4]),
593 (U384, [1, 2, 4, 5]),
594 (U448, [1, 2, 3, 4, 5, 6]),
595 (U512, [1, 2, 3, 5, 6, 7]),
596 (U576, [1, 2, 3, 4, 5, 6, 7, 8]),
597 (U640, [1, 2, 3, 4, 6, 7, 8, 9]),
598 (U704, [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]),
599 (U768, [1, 2, 3, 4, 5, 7, 8, 9, 10, 11]),
600 (U832, [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12]),
601 (U896, [1, 2, 3, 4, 5, 6, 8, 9, 10, 11, 12, 13]),
602 (U960, [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14]),
603 (U1024, [1, 2, 3, 4, 5, 6, 7, 9, 10, 11, 12, 13, 14, 15]),
604}
605
606#[cfg(test)]
607#[allow(clippy::unwrap_used)]
608mod tests {
609 use crate::{Encoding, I128, Int, U128};
610
611 #[cfg(feature = "alloc")]
612 use alloc::format;
613
614 cpubits::cpubits! {
615 64 => {
616 #[test]
617 fn as_words() {
618 let n = U128::from_be_hex("AAAAAAAABBBBBBBBCCCCCCCCDDDDDDDD");
619 assert_eq!(n.as_words(), &[0xCCCCCCCCDDDDDDDD, 0xAAAAAAAABBBBBBBB]);
620 }
621
622 #[test]
623 fn as_words_mut() {
624 let mut n = U128::from_be_hex("AAAAAAAABBBBBBBBCCCCCCCCDDDDDDDD");
625 assert_eq!(n.as_mut_words(), &[0xCCCCCCCCDDDDDDDD, 0xAAAAAAAABBBBBBBB]);
626 }
627 }
628 }
629
630 #[cfg(feature = "alloc")]
631 #[test]
632 fn debug() {
633 let n = U128::from_be_hex("AAAAAAAABBBBBBBBCCCCCCCCDDDDDDDD");
634
635 assert_eq!(format!("{n:?}"), "Uint(0xAAAAAAAABBBBBBBBCCCCCCCCDDDDDDDD)");
636 }
637
638 #[cfg(feature = "alloc")]
639 #[test]
640 fn display() {
641 let hex = "AAAAAAAABBBBBBBBCCCCCCCCDDDDDDDD";
642 let n = U128::from_be_hex(hex);
643
644 use alloc::string::ToString;
645 assert_eq!(hex, n.to_string());
646
647 let hex = "AAAAAAAABBBBBBBB0000000000000000";
648 let n = U128::from_be_hex(hex);
649 assert_eq!(hex, n.to_string());
650
651 let hex = "AAAAAAAABBBBBBBB00000000DDDDDDDD";
652 let n = U128::from_be_hex(hex);
653 assert_eq!(hex, n.to_string());
654
655 let hex = "AAAAAAAABBBBBBBB0CCCCCCCDDDDDDDD";
656 let n = U128::from_be_hex(hex);
657 assert_eq!(hex, n.to_string());
658 }
659
660 #[cfg(feature = "alloc")]
661 #[test]
662 fn fmt_lower_hex() {
663 let n = U128::from_be_hex("AAAAAAAABBBBBBBBCCCCCCCCDDDDDDDD");
664 assert_eq!(format!("{n:x}"), "aaaaaaaabbbbbbbbccccccccdddddddd");
665 assert_eq!(format!("{n:#x}"), "0xaaaaaaaabbbbbbbbccccccccdddddddd");
666 }
667
668 #[cfg(feature = "alloc")]
669 #[test]
670 fn fmt_lower_hex_from_trait() {
671 fn format_int<T: crate::Integer>(n: T) -> alloc::string::String {
672 format!("{n:x}")
673 }
674 let n = U128::from_be_hex("AAAAAAAABBBBBBBBCCCCCCCCDDDDDDDD");
675 assert_eq!(format_int(n), "aaaaaaaabbbbbbbbccccccccdddddddd");
676 }
677
678 #[cfg(feature = "alloc")]
679 #[test]
680 fn fmt_upper_hex() {
681 let n = U128::from_be_hex("aaaaaaaabbbbbbbbccccccccdddddddd");
682 assert_eq!(format!("{n:X}"), "AAAAAAAABBBBBBBBCCCCCCCCDDDDDDDD");
683 assert_eq!(format!("{n:#X}"), "0xAAAAAAAABBBBBBBBCCCCCCCCDDDDDDDD");
684 }
685
686 #[cfg(feature = "alloc")]
687 #[test]
688 fn fmt_upper_hex_from_trait() {
689 fn format_int<T: crate::Integer>(n: T) -> alloc::string::String {
690 format!("{n:X}")
691 }
692 let n = U128::from_be_hex("aaaaaaaabbbbbbbbccccccccdddddddd");
693 assert_eq!(format_int(n), "AAAAAAAABBBBBBBBCCCCCCCCDDDDDDDD");
694 }
695
696 #[cfg(feature = "alloc")]
697 #[test]
698 fn fmt_binary() {
699 let n = U128::from_be_hex("AAAAAAAABBBBBBBBCCCCCCCCDDDDDDDD");
700 assert_eq!(
701 format!("{n:b}"),
702 "10101010101010101010101010101010101110111011101110111011101110111100110011001100110011001100110011011101110111011101110111011101"
703 );
704 assert_eq!(
705 format!("{n:#b}"),
706 "0b10101010101010101010101010101010101110111011101110111011101110111100110011001100110011001100110011011101110111011101110111011101"
707 );
708 }
709
710 #[cfg(feature = "alloc")]
711 #[test]
712 fn fmt_binary_from_trait() {
713 fn format_int<T: crate::Integer>(n: T) -> alloc::string::String {
714 format!("{n:b}")
715 }
716 let n = U128::from_be_hex("aaaaaaaabbbbbbbbccccccccdddddddd");
717 assert_eq!(
718 format_int(n),
719 "10101010101010101010101010101010101110111011101110111011101110111100110011001100110011001100110011011101110111011101110111011101"
720 );
721 }
722
723 #[test]
724 fn from_bytes() {
725 let a = U128::from_be_hex("AAAAAAAABBBBBBBB0CCCCCCCDDDDDDDD");
726
727 let be_bytes = a.to_be_bytes();
728 let le_bytes = a.to_le_bytes();
729 for i in 0..16 {
730 assert_eq!(le_bytes.as_ref()[i], be_bytes.as_ref()[15 - i]);
731 }
732
733 let a_from_be = U128::from_be_bytes(be_bytes);
734 let a_from_le = U128::from_le_bytes(le_bytes);
735 assert_eq!(a_from_be, a_from_le);
736 assert_eq!(a_from_be, a);
737 }
738
739 #[test]
740 fn as_int() {
741 assert_eq!(*U128::ZERO.as_int(), Int::ZERO);
742 assert_eq!(*U128::ONE.as_int(), Int::ONE);
743 assert_eq!(*U128::MAX.as_int(), Int::MINUS_ONE);
744 }
745
746 #[test]
747 fn to_int() {
748 assert_eq!(U128::ZERO.try_into_int().unwrap(), Int::ZERO);
749 assert_eq!(U128::ONE.try_into_int().unwrap(), Int::ONE);
750 assert_eq!(I128::MAX.as_uint().try_into_int().unwrap(), Int::MAX);
751 assert!(bool::from(U128::MAX.try_into_int().is_none()));
752 }
753
754 #[test]
755 fn test_unsigned() {
756 crate::traits::tests::test_unsigned(U128::ZERO, U128::MAX);
757 }
758
759 #[test]
760 fn test_unsigned_monty_form() {
761 crate::traits::tests::test_unsigned_monty_form::<U128>();
762 }
763}