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