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,
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> Unsigned for Uint<LIMBS> {
348 fn as_uint_ref(&self) -> &UintRef {
349 self.as_uint_ref()
350 }
351
352 fn as_mut_uint_ref(&mut self) -> &mut UintRef {
353 self.as_mut_uint_ref()
354 }
355
356 fn from_limb_like(limb: Limb, _other: &Self) -> Self {
357 Self::from(limb)
358 }
359}
360
361impl<const LIMBS: usize> UnsignedWithMontyForm for Uint<LIMBS> {
362 type MontyForm = FixedMontyForm<LIMBS>;
363}
364
365impl<const LIMBS: usize> num_traits::Num for Uint<LIMBS> {
366 type FromStrRadixErr = crate::DecodeError;
367
368 fn from_str_radix(str: &str, radix: u32) -> Result<Self, Self::FromStrRadixErr> {
374 Self::from_str_radix_vartime(str, radix)
375 }
376}
377
378impl<const LIMBS: usize> ConstZero for Uint<LIMBS> {
379 const ZERO: Self = Self::ZERO;
380}
381
382impl<const LIMBS: usize> ConstOne for Uint<LIMBS> {
383 const ONE: Self = Self::ONE;
384}
385
386impl<const LIMBS: usize> Zero for Uint<LIMBS> {
387 #[inline(always)]
388 fn zero() -> Self {
389 Self::ZERO
390 }
391}
392
393impl<const LIMBS: usize> One for Uint<LIMBS> {
394 #[inline(always)]
395 fn one() -> Self {
396 Self::ONE
397 }
398}
399
400impl<const LIMBS: usize> num_traits::Zero for Uint<LIMBS> {
401 #[inline(always)]
402 fn zero() -> Self {
403 Self::ZERO
404 }
405
406 fn is_zero(&self) -> bool {
407 self.ct_eq(&Self::ZERO).into()
408 }
409}
410
411impl<const LIMBS: usize> num_traits::One for Uint<LIMBS> {
412 #[inline(always)]
413 fn one() -> Self {
414 Self::ONE
415 }
416
417 fn is_one(&self) -> bool {
418 self.ct_eq(&Self::ONE).into()
419 }
420}
421
422impl<const LIMBS: usize> fmt::Debug for Uint<LIMBS> {
423 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
424 write!(f, "Uint(0x{:X})", self.as_uint_ref())
425 }
426}
427
428impl<const LIMBS: usize> fmt::Binary for Uint<LIMBS> {
429 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
430 fmt::Binary::fmt(self.as_uint_ref(), f)
431 }
432}
433
434impl<const LIMBS: usize> fmt::Display for Uint<LIMBS> {
435 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
436 fmt::UpperHex::fmt(self, f)
437 }
438}
439
440impl<const LIMBS: usize> fmt::LowerHex for Uint<LIMBS> {
441 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
442 fmt::LowerHex::fmt(self.as_uint_ref(), f)
443 }
444}
445
446impl<const LIMBS: usize> fmt::UpperHex for Uint<LIMBS> {
447 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
448 fmt::UpperHex::fmt(self.as_uint_ref(), f)
449 }
450}
451
452#[cfg(feature = "serde")]
453impl<'de, const LIMBS: usize> Deserialize<'de> for Uint<LIMBS>
454where
455 Uint<LIMBS>: Encoding,
456{
457 fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
458 where
459 D: Deserializer<'de>,
460 {
461 let mut buffer = Encoding::to_le_bytes(&Self::ZERO);
462 serdect::array::deserialize_hex_or_bin(buffer.as_mut(), deserializer)?;
463
464 Ok(Encoding::from_le_bytes(buffer))
465 }
466}
467
468#[cfg(feature = "serde")]
469impl<const LIMBS: usize> Serialize for Uint<LIMBS>
470where
471 Uint<LIMBS>: Encoding,
472{
473 fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
474 where
475 S: Serializer,
476 {
477 serdect::slice::serialize_hex_lower_or_bin(&Encoding::to_le_bytes(self), serializer)
478 }
479}
480
481#[cfg(feature = "zeroize")]
482impl<const LIMBS: usize> DefaultIsZeroes for Uint<LIMBS> {}
483
484impl_uint_aliases! {
486 (U64, 64, "64-bit"),
487 (U128, 128, "128-bit"),
488 (U192, 192, "192-bit"),
489 (U256, 256, "256-bit"),
490 (U320, 320, "320-bit"),
491 (U384, 384, "384-bit"),
492 (U448, 448, "448-bit"),
493 (U512, 512, "512-bit"),
494 (U576, 576, "576-bit"),
495 (U640, 640, "640-bit"),
496 (U704, 704, "704-bit"),
497 (U768, 768, "768-bit"),
498 (U832, 832, "832-bit"),
499 (U896, 896, "896-bit"),
500 (U960, 960, "960-bit"),
501 (U1024, 1024, "1024-bit"),
502 (U1280, 1280, "1280-bit"),
503 (U1536, 1536, "1536-bit"),
504 (U1792, 1792, "1792-bit"),
505 (U2048, 2048, "2048-bit"),
506 (U3072, 3072, "3072-bit"),
507 (U3584, 3584, "3584-bit"),
508 (U4096, 4096, "4096-bit"),
509 (U4224, 4224, "4224-bit"),
510 (U4352, 4352, "4352-bit"),
511 (U6144, 6144, "6144-bit"),
512 (U8192, 8192, "8192-bit"),
513 (U16384, 16384, "16384-bit"),
514 (U32768, 32768, "32768-bit")
515}
516
517cpubits::cpubits! {
518 32 => {
519 impl_uint_aliases! {
520 (U224, 224, "224-bit"), (U544, 544, "544-bit") }
523 impl_uint_concat_split_even! {
524 U64,
525 }
526 }
527}
528
529impl_uint_concat_split_even! {
532 U128,
533 U256,
534 U384,
535 U512,
536 U640,
537 U768,
538 U896,
539 U1024,
540 U1280,
541 U1536,
542 U1792,
543 U2048,
544 U3072,
545 U3584,
546 U4096,
547 U4224,
548 U4352,
549 U6144,
550 U8192,
551 U16384,
552}
553
554impl_uint_concat_split_mixed! {
560 (U192, [1, 2]),
561 (U256, [1, 3]),
562 (U320, [1, 2, 3, 4]),
563 (U384, [1, 2, 4, 5]),
564 (U448, [1, 2, 3, 4, 5, 6]),
565 (U512, [1, 2, 3, 5, 6, 7]),
566 (U576, [1, 2, 3, 4, 5, 6, 7, 8]),
567 (U640, [1, 2, 3, 4, 6, 7, 8, 9]),
568 (U704, [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]),
569 (U768, [1, 2, 3, 4, 5, 7, 8, 9, 10, 11]),
570 (U832, [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12]),
571 (U896, [1, 2, 3, 4, 5, 6, 8, 9, 10, 11, 12, 13]),
572 (U960, [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14]),
573 (U1024, [1, 2, 3, 4, 5, 6, 7, 9, 10, 11, 12, 13, 14, 15]),
574}
575
576#[cfg(test)]
577#[allow(clippy::unwrap_used)]
578mod tests {
579 use crate::{Encoding, I128, Int, U128};
580
581 #[cfg(feature = "alloc")]
582 use alloc::format;
583
584 cpubits::cpubits! {
585 64 => {
586 #[test]
587 fn as_words() {
588 let n = U128::from_be_hex("AAAAAAAABBBBBBBBCCCCCCCCDDDDDDDD");
589 assert_eq!(n.as_words(), &[0xCCCCCCCCDDDDDDDD, 0xAAAAAAAABBBBBBBB]);
590 }
591
592 #[test]
593 fn as_words_mut() {
594 let mut n = U128::from_be_hex("AAAAAAAABBBBBBBBCCCCCCCCDDDDDDDD");
595 assert_eq!(n.as_mut_words(), &[0xCCCCCCCCDDDDDDDD, 0xAAAAAAAABBBBBBBB]);
596 }
597 }
598 }
599
600 #[cfg(feature = "alloc")]
601 #[test]
602 fn debug() {
603 let n = U128::from_be_hex("AAAAAAAABBBBBBBBCCCCCCCCDDDDDDDD");
604
605 assert_eq!(format!("{n:?}"), "Uint(0xAAAAAAAABBBBBBBBCCCCCCCCDDDDDDDD)");
606 }
607
608 #[cfg(feature = "alloc")]
609 #[test]
610 fn display() {
611 let hex = "AAAAAAAABBBBBBBBCCCCCCCCDDDDDDDD";
612 let n = U128::from_be_hex(hex);
613
614 use alloc::string::ToString;
615 assert_eq!(hex, n.to_string());
616
617 let hex = "AAAAAAAABBBBBBBB0000000000000000";
618 let n = U128::from_be_hex(hex);
619 assert_eq!(hex, n.to_string());
620
621 let hex = "AAAAAAAABBBBBBBB00000000DDDDDDDD";
622 let n = U128::from_be_hex(hex);
623 assert_eq!(hex, n.to_string());
624
625 let hex = "AAAAAAAABBBBBBBB0CCCCCCCDDDDDDDD";
626 let n = U128::from_be_hex(hex);
627 assert_eq!(hex, n.to_string());
628 }
629
630 #[cfg(feature = "alloc")]
631 #[test]
632 fn fmt_lower_hex() {
633 let n = U128::from_be_hex("AAAAAAAABBBBBBBBCCCCCCCCDDDDDDDD");
634 assert_eq!(format!("{n:x}"), "aaaaaaaabbbbbbbbccccccccdddddddd");
635 assert_eq!(format!("{n:#x}"), "0xaaaaaaaabbbbbbbbccccccccdddddddd");
636 }
637
638 #[cfg(feature = "alloc")]
639 #[test]
640 fn fmt_lower_hex_from_trait() {
641 fn format_int<T: crate::Integer>(n: T) -> alloc::string::String {
642 format!("{n:x}")
643 }
644 let n = U128::from_be_hex("AAAAAAAABBBBBBBBCCCCCCCCDDDDDDDD");
645 assert_eq!(format_int(n), "aaaaaaaabbbbbbbbccccccccdddddddd");
646 }
647
648 #[cfg(feature = "alloc")]
649 #[test]
650 fn fmt_upper_hex() {
651 let n = U128::from_be_hex("aaaaaaaabbbbbbbbccccccccdddddddd");
652 assert_eq!(format!("{n:X}"), "AAAAAAAABBBBBBBBCCCCCCCCDDDDDDDD");
653 assert_eq!(format!("{n:#X}"), "0xAAAAAAAABBBBBBBBCCCCCCCCDDDDDDDD");
654 }
655
656 #[cfg(feature = "alloc")]
657 #[test]
658 fn fmt_upper_hex_from_trait() {
659 fn format_int<T: crate::Integer>(n: T) -> alloc::string::String {
660 format!("{n:X}")
661 }
662 let n = U128::from_be_hex("aaaaaaaabbbbbbbbccccccccdddddddd");
663 assert_eq!(format_int(n), "AAAAAAAABBBBBBBBCCCCCCCCDDDDDDDD");
664 }
665
666 #[cfg(feature = "alloc")]
667 #[test]
668 fn fmt_binary() {
669 let n = U128::from_be_hex("AAAAAAAABBBBBBBBCCCCCCCCDDDDDDDD");
670 assert_eq!(
671 format!("{n:b}"),
672 "10101010101010101010101010101010101110111011101110111011101110111100110011001100110011001100110011011101110111011101110111011101"
673 );
674 assert_eq!(
675 format!("{n:#b}"),
676 "0b10101010101010101010101010101010101110111011101110111011101110111100110011001100110011001100110011011101110111011101110111011101"
677 );
678 }
679
680 #[cfg(feature = "alloc")]
681 #[test]
682 fn fmt_binary_from_trait() {
683 fn format_int<T: crate::Integer>(n: T) -> alloc::string::String {
684 format!("{n:b}")
685 }
686 let n = U128::from_be_hex("aaaaaaaabbbbbbbbccccccccdddddddd");
687 assert_eq!(
688 format_int(n),
689 "10101010101010101010101010101010101110111011101110111011101110111100110011001100110011001100110011011101110111011101110111011101"
690 );
691 }
692
693 #[test]
694 fn from_bytes() {
695 let a = U128::from_be_hex("AAAAAAAABBBBBBBB0CCCCCCCDDDDDDDD");
696
697 let be_bytes = a.to_be_bytes();
698 let le_bytes = a.to_le_bytes();
699 for i in 0..16 {
700 assert_eq!(le_bytes.as_ref()[i], be_bytes.as_ref()[15 - i]);
701 }
702
703 let a_from_be = U128::from_be_bytes(be_bytes);
704 let a_from_le = U128::from_le_bytes(le_bytes);
705 assert_eq!(a_from_be, a_from_le);
706 assert_eq!(a_from_be, a);
707 }
708
709 #[test]
710 fn as_int() {
711 assert_eq!(*U128::ZERO.as_int(), Int::ZERO);
712 assert_eq!(*U128::ONE.as_int(), Int::ONE);
713 assert_eq!(*U128::MAX.as_int(), Int::MINUS_ONE);
714 }
715
716 #[test]
717 fn to_int() {
718 assert_eq!(U128::ZERO.try_into_int().unwrap(), Int::ZERO);
719 assert_eq!(U128::ONE.try_into_int().unwrap(), Int::ONE);
720 assert_eq!(I128::MAX.as_uint().try_into_int().unwrap(), Int::MAX);
721 assert!(bool::from(U128::MAX.try_into_int().is_none()));
722 }
723
724 #[test]
725 fn test_unsigned() {
726 crate::traits::tests::test_unsigned(U128::ZERO, U128::MAX);
727 }
728}