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, primitives, 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(crate) const LOG2_BITS: u32 = primitives::u32_bits(Self::BITS) - 1;
113
114 pub const BYTES: usize = LIMBS * Limb::BYTES;
116
117 pub const LIMBS: usize = LIMBS;
119
120 #[must_use]
122 pub const fn new(limbs: [Limb; LIMBS]) -> Self {
123 Self { limbs }
124 }
125
126 #[inline]
129 #[must_use]
130 pub const fn from_words(arr: [Word; LIMBS]) -> Self {
131 let mut limbs = [Limb::ZERO; LIMBS];
132 let mut i = 0;
133
134 while i < LIMBS {
135 limbs[i] = Limb(arr[i]);
136 i += 1;
137 }
138
139 Self { limbs }
140 }
141
142 #[inline]
145 #[must_use]
146 pub const fn to_words(self) -> [Word; LIMBS] {
147 let mut arr = [0; LIMBS];
148 let mut i = 0;
149
150 while i < LIMBS {
151 arr[i] = self.limbs[i].0;
152 i += 1;
153 }
154
155 arr
156 }
157
158 #[must_use]
160 pub const fn as_words(&self) -> &[Word; LIMBS] {
161 Limb::array_as_words(&self.limbs)
162 }
163
164 pub const fn as_mut_words(&mut self) -> &mut [Word; LIMBS] {
166 Limb::array_as_mut_words(&mut self.limbs)
167 }
168
169 #[deprecated(since = "0.7.0", note = "please use `as_mut_words` instead")]
171 pub const fn as_words_mut(&mut self) -> &mut [Word] {
172 self.as_mut_words()
173 }
174
175 #[must_use]
177 pub const fn as_limbs(&self) -> &[Limb; LIMBS] {
178 &self.limbs
179 }
180
181 pub const fn as_mut_limbs(&mut self) -> &mut [Limb; LIMBS] {
183 &mut self.limbs
184 }
185
186 #[deprecated(since = "0.7.0", note = "please use `as_mut_limbs` instead")]
188 pub const fn as_limbs_mut(&mut self) -> &mut [Limb] {
189 self.as_mut_limbs()
190 }
191
192 #[must_use]
194 pub const fn to_limbs(self) -> [Limb; LIMBS] {
195 self.limbs
196 }
197
198 #[inline]
200 #[must_use]
201 pub const fn as_uint_ref(&self) -> &UintRef {
202 UintRef::new(&self.limbs)
203 }
204
205 #[inline]
207 #[must_use]
208 pub const fn as_mut_uint_ref(&mut self) -> &mut UintRef {
209 UintRef::new_mut(&mut self.limbs)
210 }
211
212 #[inline]
214 #[must_use]
215 pub const fn as_nz_vartime(&self) -> Option<&NonZero<Self>> {
216 if self.is_zero_vartime() {
217 None
218 } else {
219 Some(NonZero::new_ref_unchecked(self))
220 }
221 }
222
223 #[must_use]
227 pub const fn to_nz(&self) -> CtOption<NonZero<Self>> {
228 let (nz, self_nz) = self.to_nz_or_one();
229 CtOption::new(nz, self_nz)
230 }
231
232 #[must_use]
236 pub const fn to_nz_vartime(&self) -> Option<NonZero<Self>> {
237 if self.is_zero_vartime() {
238 None
239 } else {
240 Some(NonZero::new_unchecked(*self))
241 }
242 }
243
244 #[inline(always)]
249 #[must_use]
250 pub(crate) const fn to_nz_or_one(self) -> (NonZero<Self>, Choice) {
251 let is_nz = self.is_nonzero();
252 (
253 NonZero::new_unchecked(Self::select(&Self::ONE, &self, is_nz)),
254 is_nz,
255 )
256 }
257
258 #[must_use]
262 pub const fn to_odd(&self) -> CtOption<Odd<Self>> {
263 let (odd, self_odd) = self.to_odd_or_one();
264 CtOption::new(odd, self_odd)
265 }
266
267 #[inline(always)]
272 #[must_use]
273 pub(crate) const fn to_odd_or_one(self) -> (Odd<Self>, Choice) {
274 let is_odd = self.is_odd();
275 (
276 Odd::new_unchecked(Self::select(&Self::ONE, &self, is_odd)),
277 is_odd,
278 )
279 }
280
281 #[must_use]
285 pub const fn as_int(&self) -> &Int<LIMBS> {
286 #[allow(unsafe_code)]
289 unsafe {
290 &*core::ptr::from_ref(self).cast::<Int<LIMBS>>()
291 }
292 }
293
294 #[must_use]
298 pub const fn try_into_int(self) -> CtOption<Int<LIMBS>> {
299 Int::new_from_abs_sign(self, Choice::FALSE)
300 }
301
302 #[must_use]
304 pub const fn is_zero(&self) -> Choice {
305 self.is_nonzero().not()
306 }
307}
308
309impl<const LIMBS: usize> AsRef<[Word; LIMBS]> for Uint<LIMBS> {
310 fn as_ref(&self) -> &[Word; LIMBS] {
311 self.as_words()
312 }
313}
314
315impl<const LIMBS: usize> AsMut<[Word; LIMBS]> for Uint<LIMBS> {
316 fn as_mut(&mut self) -> &mut [Word; LIMBS] {
317 self.as_mut_words()
318 }
319}
320
321impl<const LIMBS: usize> AsRef<[Limb]> for Uint<LIMBS> {
322 fn as_ref(&self) -> &[Limb] {
323 self.as_limbs()
324 }
325}
326
327impl<const LIMBS: usize> AsMut<[Limb]> for Uint<LIMBS> {
328 fn as_mut(&mut self) -> &mut [Limb] {
329 self.as_mut_limbs()
330 }
331}
332
333impl<const LIMBS: usize> AsRef<UintRef> for Uint<LIMBS> {
334 fn as_ref(&self) -> &UintRef {
335 self.as_uint_ref()
336 }
337}
338
339impl<const LIMBS: usize> AsMut<UintRef> for Uint<LIMBS> {
340 fn as_mut(&mut self) -> &mut UintRef {
341 self.as_mut_uint_ref()
342 }
343}
344
345impl<const LIMBS: usize> Bounded for Uint<LIMBS> {
346 const BITS: u32 = Self::BITS;
347 const BYTES: usize = Self::BYTES;
348}
349
350impl<const LIMBS: usize> Constants for Uint<LIMBS> {
351 const MAX: Self = Self::MAX;
352}
353
354impl<const LIMBS: usize> Default for Uint<LIMBS> {
355 fn default() -> Self {
356 Self::ZERO
357 }
358}
359
360impl<const LIMBS: usize> FixedInteger for Uint<LIMBS> {
361 const LIMBS: usize = LIMBS;
362}
363
364impl<const LIMBS: usize> Integer for Uint<LIMBS> {
365 fn as_limbs(&self) -> &[Limb] {
366 &self.limbs
367 }
368
369 fn as_mut_limbs(&mut self) -> &mut [Limb] {
370 &mut self.limbs
371 }
372
373 fn nlimbs(&self) -> usize {
374 Self::LIMBS
375 }
376}
377
378impl<const LIMBS: usize> Sealed for Uint<LIMBS> {}
379
380impl<const LIMBS: usize> Unsigned for Uint<LIMBS> {
381 fn as_uint_ref(&self) -> &UintRef {
382 self.as_uint_ref()
383 }
384
385 fn as_mut_uint_ref(&mut self) -> &mut UintRef {
386 self.as_mut_uint_ref()
387 }
388
389 fn from_limb_like(limb: Limb, _other: &Self) -> Self {
390 Self::from(limb)
391 }
392}
393
394impl<const LIMBS: usize> UnsignedWithMontyForm for Uint<LIMBS> {
395 type MontyForm = FixedMontyForm<LIMBS>;
396}
397
398impl<const LIMBS: usize> num_traits::Num for Uint<LIMBS> {
399 type FromStrRadixErr = crate::DecodeError;
400
401 fn from_str_radix(str: &str, radix: u32) -> Result<Self, Self::FromStrRadixErr> {
407 Self::from_str_radix_vartime(str, radix)
408 }
409}
410
411impl<const LIMBS: usize> ConstZero for Uint<LIMBS> {
412 const ZERO: Self = Self::ZERO;
413}
414
415impl<const LIMBS: usize> ConstOne for Uint<LIMBS> {
416 const ONE: Self = Self::ONE;
417}
418
419impl<const LIMBS: usize> Zero for Uint<LIMBS> {
420 #[inline(always)]
421 fn zero() -> Self {
422 Self::ZERO
423 }
424}
425
426impl<const LIMBS: usize> One for Uint<LIMBS> {
427 #[inline(always)]
428 fn one() -> Self {
429 Self::ONE
430 }
431}
432
433impl<const LIMBS: usize> num_traits::Zero for Uint<LIMBS> {
434 #[inline(always)]
435 fn zero() -> Self {
436 Self::ZERO
437 }
438
439 fn is_zero(&self) -> bool {
440 self.ct_eq(&Self::ZERO).into()
441 }
442}
443
444impl<const LIMBS: usize> num_traits::One for Uint<LIMBS> {
445 #[inline(always)]
446 fn one() -> Self {
447 Self::ONE
448 }
449
450 fn is_one(&self) -> bool {
451 self.ct_eq(&Self::ONE).into()
452 }
453}
454
455impl<const LIMBS: usize> fmt::Debug for Uint<LIMBS> {
456 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
457 write!(f, "Uint(0x{:X})", self.as_uint_ref())
458 }
459}
460
461impl<const LIMBS: usize> fmt::Binary for Uint<LIMBS> {
462 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
463 fmt::Binary::fmt(self.as_uint_ref(), f)
464 }
465}
466
467impl<const LIMBS: usize> fmt::Display for Uint<LIMBS> {
468 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
469 fmt::UpperHex::fmt(self, f)
470 }
471}
472
473impl<const LIMBS: usize> fmt::LowerHex for Uint<LIMBS> {
474 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
475 fmt::LowerHex::fmt(self.as_uint_ref(), f)
476 }
477}
478
479impl<const LIMBS: usize> fmt::UpperHex for Uint<LIMBS> {
480 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
481 fmt::UpperHex::fmt(self.as_uint_ref(), f)
482 }
483}
484
485#[cfg(feature = "serde")]
486impl<'de, const LIMBS: usize> Deserialize<'de> for Uint<LIMBS>
487where
488 Uint<LIMBS>: Encoding,
489{
490 fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
491 where
492 D: Deserializer<'de>,
493 {
494 let mut buffer = Encoding::to_le_bytes(&Self::ZERO);
495 serdect::array::deserialize_hex_or_bin(buffer.as_mut(), deserializer)?;
496
497 Ok(Encoding::from_le_bytes(buffer))
498 }
499}
500
501#[cfg(feature = "serde")]
502impl<const LIMBS: usize> Serialize for Uint<LIMBS>
503where
504 Uint<LIMBS>: Encoding,
505{
506 fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
507 where
508 S: Serializer,
509 {
510 serdect::slice::serialize_hex_lower_or_bin(&Encoding::to_le_bytes(self), serializer)
511 }
512}
513
514#[cfg(feature = "zeroize")]
515impl<const LIMBS: usize> DefaultIsZeroes for Uint<LIMBS> {}
516
517impl_uint_aliases! {
519 (U64, 64, "64-bit"),
520 (U128, 128, "128-bit"),
521 (U192, 192, "192-bit"),
522 (U256, 256, "256-bit"),
523 (U320, 320, "320-bit"),
524 (U384, 384, "384-bit"),
525 (U448, 448, "448-bit"),
526 (U512, 512, "512-bit"),
527 (U576, 576, "576-bit"),
528 (U640, 640, "640-bit"),
529 (U704, 704, "704-bit"),
530 (U768, 768, "768-bit"),
531 (U832, 832, "832-bit"),
532 (U896, 896, "896-bit"),
533 (U960, 960, "960-bit"),
534 (U1024, 1024, "1024-bit"),
535 (U1280, 1280, "1280-bit"),
536 (U1536, 1536, "1536-bit"),
537 (U1792, 1792, "1792-bit"),
538 (U2048, 2048, "2048-bit"),
539 (U3072, 3072, "3072-bit"),
540 (U3584, 3584, "3584-bit"),
541 (U4096, 4096, "4096-bit"),
542 (U4224, 4224, "4224-bit"),
543 (U4352, 4352, "4352-bit"),
544 (U6144, 6144, "6144-bit"),
545 (U8192, 8192, "8192-bit"),
546 (U16384, 16384, "16384-bit"),
547 (U32768, 32768, "32768-bit")
548}
549
550cpubits::cpubits! {
551 32 => {
552 impl_uint_aliases! {
553 (U224, 224, "224-bit"), (U544, 544, "544-bit") }
556 impl_uint_concat_split_even! {
557 U64,
558 }
559 }
560}
561
562impl_uint_concat_split_even! {
565 U128,
566 U256,
567 U384,
568 U512,
569 U640,
570 U768,
571 U896,
572 U1024,
573 U1280,
574 U1536,
575 U1792,
576 U2048,
577 U3072,
578 U3584,
579 U4096,
580 U4224,
581 U4352,
582 U6144,
583 U8192,
584 U16384,
585}
586
587impl_uint_concat_split_mixed! {
593 (U192, [1, 2]),
594 (U256, [1, 3]),
595 (U320, [1, 2, 3, 4]),
596 (U384, [1, 2, 4, 5]),
597 (U448, [1, 2, 3, 4, 5, 6]),
598 (U512, [1, 2, 3, 5, 6, 7]),
599 (U576, [1, 2, 3, 4, 5, 6, 7, 8]),
600 (U640, [1, 2, 3, 4, 6, 7, 8, 9]),
601 (U704, [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]),
602 (U768, [1, 2, 3, 4, 5, 7, 8, 9, 10, 11]),
603 (U832, [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12]),
604 (U896, [1, 2, 3, 4, 5, 6, 8, 9, 10, 11, 12, 13]),
605 (U960, [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14]),
606 (U1024, [1, 2, 3, 4, 5, 6, 7, 9, 10, 11, 12, 13, 14, 15]),
607}
608
609#[cfg(test)]
610#[allow(clippy::unwrap_used)]
611mod tests {
612 use crate::{Encoding, I128, Int, U128};
613
614 #[cfg(feature = "alloc")]
615 use alloc::format;
616
617 cpubits::cpubits! {
618 64 => {
619 #[test]
620 fn as_words() {
621 let n = U128::from_be_hex("AAAAAAAABBBBBBBBCCCCCCCCDDDDDDDD");
622 assert_eq!(n.as_words(), &[0xCCCCCCCCDDDDDDDD, 0xAAAAAAAABBBBBBBB]);
623 }
624
625 #[test]
626 fn as_words_mut() {
627 let mut n = U128::from_be_hex("AAAAAAAABBBBBBBBCCCCCCCCDDDDDDDD");
628 assert_eq!(n.as_mut_words(), &[0xCCCCCCCCDDDDDDDD, 0xAAAAAAAABBBBBBBB]);
629 }
630 }
631 }
632
633 #[cfg(feature = "alloc")]
634 #[test]
635 fn debug() {
636 let n = U128::from_be_hex("AAAAAAAABBBBBBBBCCCCCCCCDDDDDDDD");
637
638 assert_eq!(format!("{n:?}"), "Uint(0xAAAAAAAABBBBBBBBCCCCCCCCDDDDDDDD)");
639 }
640
641 #[cfg(feature = "alloc")]
642 #[test]
643 fn display() {
644 let hex = "AAAAAAAABBBBBBBBCCCCCCCCDDDDDDDD";
645 let n = U128::from_be_hex(hex);
646
647 use alloc::string::ToString;
648 assert_eq!(hex, n.to_string());
649
650 let hex = "AAAAAAAABBBBBBBB0000000000000000";
651 let n = U128::from_be_hex(hex);
652 assert_eq!(hex, n.to_string());
653
654 let hex = "AAAAAAAABBBBBBBB00000000DDDDDDDD";
655 let n = U128::from_be_hex(hex);
656 assert_eq!(hex, n.to_string());
657
658 let hex = "AAAAAAAABBBBBBBB0CCCCCCCDDDDDDDD";
659 let n = U128::from_be_hex(hex);
660 assert_eq!(hex, n.to_string());
661 }
662
663 #[cfg(feature = "alloc")]
664 #[test]
665 fn fmt_lower_hex() {
666 let n = U128::from_be_hex("AAAAAAAABBBBBBBBCCCCCCCCDDDDDDDD");
667 assert_eq!(format!("{n:x}"), "aaaaaaaabbbbbbbbccccccccdddddddd");
668 assert_eq!(format!("{n:#x}"), "0xaaaaaaaabbbbbbbbccccccccdddddddd");
669 }
670
671 #[cfg(feature = "alloc")]
672 #[test]
673 fn fmt_lower_hex_from_trait() {
674 fn format_int<T: crate::Integer>(n: T) -> alloc::string::String {
675 format!("{n:x}")
676 }
677 let n = U128::from_be_hex("AAAAAAAABBBBBBBBCCCCCCCCDDDDDDDD");
678 assert_eq!(format_int(n), "aaaaaaaabbbbbbbbccccccccdddddddd");
679 }
680
681 #[cfg(feature = "alloc")]
682 #[test]
683 fn fmt_upper_hex() {
684 let n = U128::from_be_hex("aaaaaaaabbbbbbbbccccccccdddddddd");
685 assert_eq!(format!("{n:X}"), "AAAAAAAABBBBBBBBCCCCCCCCDDDDDDDD");
686 assert_eq!(format!("{n:#X}"), "0xAAAAAAAABBBBBBBBCCCCCCCCDDDDDDDD");
687 }
688
689 #[cfg(feature = "alloc")]
690 #[test]
691 fn fmt_upper_hex_from_trait() {
692 fn format_int<T: crate::Integer>(n: T) -> alloc::string::String {
693 format!("{n:X}")
694 }
695 let n = U128::from_be_hex("aaaaaaaabbbbbbbbccccccccdddddddd");
696 assert_eq!(format_int(n), "AAAAAAAABBBBBBBBCCCCCCCCDDDDDDDD");
697 }
698
699 #[cfg(feature = "alloc")]
700 #[test]
701 fn fmt_binary() {
702 let n = U128::from_be_hex("AAAAAAAABBBBBBBBCCCCCCCCDDDDDDDD");
703 assert_eq!(
704 format!("{n:b}"),
705 "10101010101010101010101010101010101110111011101110111011101110111100110011001100110011001100110011011101110111011101110111011101"
706 );
707 assert_eq!(
708 format!("{n:#b}"),
709 "0b10101010101010101010101010101010101110111011101110111011101110111100110011001100110011001100110011011101110111011101110111011101"
710 );
711 }
712
713 #[cfg(feature = "alloc")]
714 #[test]
715 fn fmt_binary_from_trait() {
716 fn format_int<T: crate::Integer>(n: T) -> alloc::string::String {
717 format!("{n:b}")
718 }
719 let n = U128::from_be_hex("aaaaaaaabbbbbbbbccccccccdddddddd");
720 assert_eq!(
721 format_int(n),
722 "10101010101010101010101010101010101110111011101110111011101110111100110011001100110011001100110011011101110111011101110111011101"
723 );
724 }
725
726 #[test]
727 fn from_bytes() {
728 let a = U128::from_be_hex("AAAAAAAABBBBBBBB0CCCCCCCDDDDDDDD");
729
730 let be_bytes = a.to_be_bytes();
731 let le_bytes = a.to_le_bytes();
732 for i in 0..16 {
733 assert_eq!(le_bytes.as_ref()[i], be_bytes.as_ref()[15 - i]);
734 }
735
736 let a_from_be = U128::from_be_bytes(be_bytes);
737 let a_from_le = U128::from_le_bytes(le_bytes);
738 assert_eq!(a_from_be, a_from_le);
739 assert_eq!(a_from_be, a);
740 }
741
742 #[test]
743 fn as_int() {
744 assert_eq!(*U128::ZERO.as_int(), Int::ZERO);
745 assert_eq!(*U128::ONE.as_int(), Int::ONE);
746 assert_eq!(*U128::MAX.as_int(), Int::MINUS_ONE);
747 }
748
749 #[test]
750 fn to_int() {
751 assert_eq!(U128::ZERO.try_into_int().unwrap(), Int::ZERO);
752 assert_eq!(U128::ONE.try_into_int().unwrap(), Int::ONE);
753 assert_eq!(I128::MAX.as_uint().try_into_int().unwrap(), Int::MAX);
754 assert!(bool::from(U128::MAX.try_into_int().is_none()));
755 }
756
757 #[test]
758 fn test_unsigned() {
759 crate::traits::tests::test_unsigned(U128::ZERO, U128::MAX);
760 }
761
762 #[test]
763 fn test_unsigned_monty_form() {
764 crate::traits::tests::test_unsigned_monty_form::<U128>();
765 }
766}