1#![allow(clippy::needless_range_loop, clippy::many_single_char_names)]
4
5use core::fmt;
6
7#[cfg(feature = "serde")]
8use serdect::serde::{Deserialize, Deserializer, Serialize, Serializer};
9use subtle::{Choice, ConditionallySelectable, ConstantTimeEq};
10#[cfg(feature = "zeroize")]
11use zeroize::DefaultIsZeroes;
12
13#[cfg(feature = "extra-sizes")]
14pub use extra_sizes::*;
15
16pub(crate) use ref_type::UintRef;
17
18use crate::{
19 Bounded, ConstChoice, ConstCtOption, ConstOne, ConstZero, Constants, Encoding, FixedInteger,
20 Int, Integer, Limb, NonZero, Odd, One, Unsigned, Word, Zero, modular::MontyForm,
21};
22
23#[macro_use]
24mod macros;
25
26mod add;
27mod add_mod;
28mod bit_and;
29mod bit_not;
30mod bit_or;
31mod bit_xor;
32mod bits;
33mod cmp;
34mod concat;
35mod div;
36pub(crate) mod div_limb;
37pub(crate) mod encoding;
38mod from;
39pub(crate) mod gcd;
40mod invert_mod;
41mod mod_symbol;
42pub(crate) mod mul;
43mod mul_mod;
44mod neg;
45mod neg_mod;
46mod resize;
47mod shl;
48mod shr;
49mod split;
50mod sqrt;
51mod sub;
52mod sub_mod;
53
54#[cfg(feature = "hybrid-array")]
55mod array;
56#[cfg(feature = "alloc")]
57pub(crate) mod boxed;
58#[cfg(feature = "rand_core")]
59mod rand;
60
61#[allow(clippy::derived_hash_with_manual_eq)]
80#[derive(Copy, Clone, Hash)]
81pub struct Uint<const LIMBS: usize> {
82 pub(crate) limbs: [Limb; LIMBS],
84}
85
86impl<const LIMBS: usize> Uint<LIMBS> {
87 pub const ZERO: Self = Self::from_u8(0);
89
90 pub const ONE: Self = Self::from_u8(1);
92
93 pub const MAX: Self = Self {
95 limbs: [Limb::MAX; LIMBS],
96 };
97
98 pub const BITS: u32 = LIMBS as u32 * Limb::BITS;
100
101 pub(crate) const LOG2_BITS: u32 = u32::BITS - Self::BITS.leading_zeros() - 1;
104
105 pub const BYTES: usize = LIMBS * Limb::BYTES;
107
108 pub const LIMBS: usize = LIMBS;
110
111 pub const fn new(limbs: [Limb; LIMBS]) -> Self {
113 Self { limbs }
114 }
115
116 #[inline]
119 pub const fn from_words(arr: [Word; LIMBS]) -> Self {
120 let mut limbs = [Limb::ZERO; LIMBS];
121 let mut i = 0;
122
123 while i < LIMBS {
124 limbs[i] = Limb(arr[i]);
125 i += 1;
126 }
127
128 Self { limbs }
129 }
130
131 #[inline]
134 pub const fn to_words(self) -> [Word; LIMBS] {
135 let mut arr = [0; LIMBS];
136 let mut i = 0;
137
138 while i < LIMBS {
139 arr[i] = self.limbs[i].0;
140 i += 1;
141 }
142
143 arr
144 }
145
146 pub const fn as_words(&self) -> &[Word; LIMBS] {
148 #[allow(unsafe_code)]
150 unsafe {
151 &*self.limbs.as_ptr().cast()
152 }
153 }
154
155 pub const fn as_mut_words(&mut self) -> &mut [Word; LIMBS] {
157 #[allow(unsafe_code)]
159 unsafe {
160 &mut *self.limbs.as_mut_ptr().cast()
161 }
162 }
163
164 #[deprecated(since = "0.7.0", note = "please use `as_mut_words` instead")]
166 pub const fn as_words_mut(&mut self) -> &mut [Word] {
167 self.as_mut_words()
168 }
169
170 pub const fn as_limbs(&self) -> &[Limb; LIMBS] {
172 &self.limbs
173 }
174
175 pub const fn as_mut_limbs(&mut self) -> &mut [Limb; LIMBS] {
177 &mut self.limbs
178 }
179
180 #[deprecated(since = "0.7.0", note = "please use `as_mut_limbs` instead")]
182 pub const fn as_limbs_mut(&mut self) -> &mut [Limb] {
183 self.as_mut_limbs()
184 }
185
186 pub const fn to_limbs(self) -> [Limb; LIMBS] {
188 self.limbs
189 }
190
191 #[inline(always)]
193 pub(crate) const fn as_uint_ref(&self) -> &UintRef {
194 UintRef::new(&self.limbs)
195 }
196
197 #[inline(always)]
199 pub(crate) const fn as_mut_uint_ref(&mut self) -> &mut UintRef {
200 UintRef::new_mut(&mut self.limbs)
201 }
202
203 pub const fn to_nz(self) -> ConstCtOption<NonZero<Self>> {
207 ConstCtOption::new(NonZero(self), self.is_nonzero())
208 }
209
210 pub const fn to_odd(self) -> ConstCtOption<Odd<Self>> {
214 ConstCtOption::new(Odd(self), self.is_odd())
215 }
216
217 pub const fn as_int(&self) -> &Int<LIMBS> {
221 #[allow(trivial_casts, unsafe_code)]
222 unsafe {
223 &*(self as *const Uint<LIMBS> as *const Int<LIMBS>)
224 }
225 }
226
227 pub const fn try_into_int(self) -> ConstCtOption<Int<LIMBS>> {
231 Int::new_from_abs_sign(self, ConstChoice::FALSE)
232 }
233}
234
235impl<const LIMBS: usize> AsRef<[Word; LIMBS]> for Uint<LIMBS> {
236 fn as_ref(&self) -> &[Word; LIMBS] {
237 self.as_words()
238 }
239}
240
241impl<const LIMBS: usize> AsMut<[Word; LIMBS]> for Uint<LIMBS> {
242 fn as_mut(&mut self) -> &mut [Word; LIMBS] {
243 self.as_mut_words()
244 }
245}
246
247impl<const LIMBS: usize> AsRef<[Limb]> for Uint<LIMBS> {
248 fn as_ref(&self) -> &[Limb] {
249 self.as_limbs()
250 }
251}
252
253impl<const LIMBS: usize> AsMut<[Limb]> for Uint<LIMBS> {
254 fn as_mut(&mut self) -> &mut [Limb] {
255 self.as_mut_limbs()
256 }
257}
258
259impl<const LIMBS: usize> AsRef<UintRef> for Uint<LIMBS> {
260 fn as_ref(&self) -> &UintRef {
261 self.as_uint_ref()
262 }
263}
264
265impl<const LIMBS: usize> AsMut<UintRef> for Uint<LIMBS> {
266 fn as_mut(&mut self) -> &mut UintRef {
267 self.as_mut_uint_ref()
268 }
269}
270
271impl<const LIMBS: usize> ConditionallySelectable for Uint<LIMBS> {
272 fn conditional_select(a: &Self, b: &Self, choice: Choice) -> Self {
273 let mut limbs = [Limb::ZERO; LIMBS];
274
275 for i in 0..LIMBS {
276 limbs[i] = Limb::conditional_select(&a.limbs[i], &b.limbs[i], choice);
277 }
278
279 Self { limbs }
280 }
281}
282
283impl<const LIMBS: usize> Bounded for Uint<LIMBS> {
284 const BITS: u32 = Self::BITS;
285 const BYTES: usize = Self::BYTES;
286}
287
288impl<const LIMBS: usize> Constants for Uint<LIMBS> {
289 const MAX: Self = Self::MAX;
290}
291
292impl<const LIMBS: usize> Default for Uint<LIMBS> {
293 fn default() -> Self {
294 Self::ZERO
295 }
296}
297
298impl<const LIMBS: usize> FixedInteger for Uint<LIMBS> {
299 const LIMBS: usize = LIMBS;
300}
301
302impl<const LIMBS: usize> Integer for Uint<LIMBS> {
303 fn as_limbs(&self) -> &[Limb] {
304 &self.limbs
305 }
306
307 fn as_mut_limbs(&mut self) -> &mut [Limb] {
308 &mut self.limbs
309 }
310
311 fn nlimbs(&self) -> usize {
312 Self::LIMBS
313 }
314}
315
316impl<const LIMBS: usize> Unsigned for Uint<LIMBS> {
317 type Monty = MontyForm<LIMBS>;
318
319 fn from_limb_like(limb: Limb, _other: &Self) -> Self {
320 Self::from(limb)
321 }
322}
323
324impl<const LIMBS: usize> num_traits::Num for Uint<LIMBS> {
325 type FromStrRadixErr = crate::DecodeError;
326
327 fn from_str_radix(str: &str, radix: u32) -> Result<Self, Self::FromStrRadixErr> {
329 Self::from_str_radix_vartime(str, radix)
330 }
331}
332
333impl<const LIMBS: usize> ConstZero for Uint<LIMBS> {
334 const ZERO: Self = Self::ZERO;
335}
336
337impl<const LIMBS: usize> ConstOne for Uint<LIMBS> {
338 const ONE: Self = Self::ONE;
339}
340
341impl<const LIMBS: usize> Zero for Uint<LIMBS> {
342 #[inline(always)]
343 fn zero() -> Self {
344 Self::ZERO
345 }
346}
347
348impl<const LIMBS: usize> One for Uint<LIMBS> {
349 #[inline(always)]
350 fn one() -> Self {
351 Self::ONE
352 }
353}
354
355impl<const LIMBS: usize> num_traits::Zero for Uint<LIMBS> {
356 #[inline(always)]
357 fn zero() -> Self {
358 Self::ZERO
359 }
360
361 fn is_zero(&self) -> bool {
362 self.ct_eq(&Self::ZERO).into()
363 }
364}
365
366impl<const LIMBS: usize> num_traits::One for Uint<LIMBS> {
367 #[inline(always)]
368 fn one() -> Self {
369 Self::ONE
370 }
371
372 fn is_one(&self) -> bool {
373 self.ct_eq(&Self::ONE).into()
374 }
375}
376
377impl<const LIMBS: usize> fmt::Debug for Uint<LIMBS> {
378 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
379 write!(f, "Uint(0x{:X})", self.as_uint_ref())
380 }
381}
382
383impl<const LIMBS: usize> fmt::Binary for Uint<LIMBS> {
384 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
385 fmt::Binary::fmt(self.as_uint_ref(), f)
386 }
387}
388
389impl<const LIMBS: usize> fmt::Display for Uint<LIMBS> {
390 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
391 fmt::UpperHex::fmt(self, f)
392 }
393}
394
395impl<const LIMBS: usize> fmt::LowerHex for Uint<LIMBS> {
396 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
397 fmt::LowerHex::fmt(self.as_uint_ref(), f)
398 }
399}
400
401impl<const LIMBS: usize> fmt::UpperHex for Uint<LIMBS> {
402 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
403 fmt::UpperHex::fmt(self.as_uint_ref(), f)
404 }
405}
406
407#[cfg(feature = "serde")]
408impl<'de, const LIMBS: usize> Deserialize<'de> for Uint<LIMBS>
409where
410 Uint<LIMBS>: Encoding,
411{
412 fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
413 where
414 D: Deserializer<'de>,
415 {
416 let mut buffer = Self::ZERO.to_le_bytes();
417 serdect::array::deserialize_hex_or_bin(buffer.as_mut(), deserializer)?;
418
419 Ok(Self::from_le_bytes(buffer))
420 }
421}
422
423#[cfg(feature = "serde")]
424impl<const LIMBS: usize> Serialize for Uint<LIMBS>
425where
426 Uint<LIMBS>: Encoding,
427{
428 fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
429 where
430 S: Serializer,
431 {
432 serdect::array::serialize_hex_lower_or_bin(&Encoding::to_le_bytes(self), serializer)
433 }
434}
435
436#[cfg(feature = "zeroize")]
437impl<const LIMBS: usize> DefaultIsZeroes for Uint<LIMBS> {}
438
439impl_uint_aliases! {
441 (U64, 64, "64-bit"),
442 (U128, 128, "128-bit"),
443 (U192, 192, "192-bit"),
444 (U256, 256, "256-bit"),
445 (U320, 320, "320-bit"),
446 (U384, 384, "384-bit"),
447 (U448, 448, "448-bit"),
448 (U512, 512, "512-bit"),
449 (U576, 576, "576-bit"),
450 (U640, 640, "640-bit"),
451 (U704, 704, "704-bit"),
452 (U768, 768, "768-bit"),
453 (U832, 832, "832-bit"),
454 (U896, 896, "896-bit"),
455 (U960, 960, "960-bit"),
456 (U1024, 1024, "1024-bit"),
457 (U1280, 1280, "1280-bit"),
458 (U1536, 1536, "1536-bit"),
459 (U1792, 1792, "1792-bit"),
460 (U2048, 2048, "2048-bit"),
461 (U3072, 3072, "3072-bit"),
462 (U3584, 3584, "3584-bit"),
463 (U4096, 4096, "4096-bit"),
464 (U4224, 4224, "4224-bit"),
465 (U4352, 4352, "4352-bit"),
466 (U6144, 6144, "6144-bit"),
467 (U8192, 8192, "8192-bit"),
468 (U16384, 16384, "16384-bit"),
469 (U32768, 32768, "32768-bit")
470}
471
472#[cfg(target_pointer_width = "32")]
473impl_uint_aliases! {
474 (U224, 224, "224-bit"), (U544, 544, "544-bit") }
477
478#[cfg(target_pointer_width = "32")]
479impl_uint_concat_split_even! {
480 U64,
481}
482
483impl_uint_concat_split_even! {
486 U128,
487 U256,
488 U384,
489 U512,
490 U640,
491 U768,
492 U896,
493 U1024,
494 U1280,
495 U1536,
496 U1792,
497 U2048,
498 U3072,
499 U3584,
500 U4096,
501 U4224,
502 U4352,
503 U6144,
504 U8192,
505 U16384,
506}
507
508impl_uint_concat_split_mixed! {
514 (U192, [1, 2]),
515 (U256, [1, 3]),
516 (U320, [1, 2, 3, 4]),
517 (U384, [1, 2, 4, 5]),
518 (U448, [1, 2, 3, 4, 5, 6]),
519 (U512, [1, 2, 3, 5, 6, 7]),
520 (U576, [1, 2, 3, 4, 5, 6, 7, 8]),
521 (U640, [1, 2, 3, 4, 6, 7, 8, 9]),
522 (U704, [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]),
523 (U768, [1, 2, 3, 4, 5, 7, 8, 9, 10, 11]),
524 (U832, [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12]),
525 (U896, [1, 2, 3, 4, 5, 6, 8, 9, 10, 11, 12, 13]),
526 (U960, [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14]),
527 (U1024, [1, 2, 3, 4, 5, 6, 7, 9, 10, 11, 12, 13, 14, 15]),
528}
529
530#[cfg(feature = "extra-sizes")]
531mod extra_sizes;
532mod mul_int;
533mod ref_type;
534
535#[cfg(test)]
536#[allow(clippy::unwrap_used)]
537mod tests {
538 use crate::{Encoding, I128, Int, U128};
539 use subtle::ConditionallySelectable;
540
541 #[cfg(feature = "alloc")]
542 use alloc::format;
543
544 #[cfg(target_pointer_width = "64")]
545 #[test]
546 fn as_words() {
547 let n = U128::from_be_hex("AAAAAAAABBBBBBBBCCCCCCCCDDDDDDDD");
548 assert_eq!(n.as_words(), &[0xCCCCCCCCDDDDDDDD, 0xAAAAAAAABBBBBBBB]);
549 }
550
551 #[cfg(target_pointer_width = "64")]
552 #[test]
553 fn as_words_mut() {
554 let mut n = U128::from_be_hex("AAAAAAAABBBBBBBBCCCCCCCCDDDDDDDD");
555 assert_eq!(n.as_mut_words(), &[0xCCCCCCCCDDDDDDDD, 0xAAAAAAAABBBBBBBB]);
556 }
557
558 #[cfg(feature = "alloc")]
559 #[test]
560 fn debug() {
561 let n = U128::from_be_hex("AAAAAAAABBBBBBBBCCCCCCCCDDDDDDDD");
562
563 assert_eq!(format!("{n:?}"), "Uint(0xAAAAAAAABBBBBBBBCCCCCCCCDDDDDDDD)");
564 }
565
566 #[cfg(feature = "alloc")]
567 #[test]
568 fn display() {
569 let hex = "AAAAAAAABBBBBBBBCCCCCCCCDDDDDDDD";
570 let n = U128::from_be_hex(hex);
571
572 use alloc::string::ToString;
573 assert_eq!(hex, n.to_string());
574
575 let hex = "AAAAAAAABBBBBBBB0000000000000000";
576 let n = U128::from_be_hex(hex);
577 assert_eq!(hex, n.to_string());
578
579 let hex = "AAAAAAAABBBBBBBB00000000DDDDDDDD";
580 let n = U128::from_be_hex(hex);
581 assert_eq!(hex, n.to_string());
582
583 let hex = "AAAAAAAABBBBBBBB0CCCCCCCDDDDDDDD";
584 let n = U128::from_be_hex(hex);
585 assert_eq!(hex, n.to_string());
586 }
587
588 #[cfg(feature = "alloc")]
589 #[test]
590 fn fmt_lower_hex() {
591 let n = U128::from_be_hex("AAAAAAAABBBBBBBBCCCCCCCCDDDDDDDD");
592 assert_eq!(format!("{n:x}"), "aaaaaaaabbbbbbbbccccccccdddddddd");
593 assert_eq!(format!("{n:#x}"), "0xaaaaaaaabbbbbbbbccccccccdddddddd");
594 }
595
596 #[cfg(feature = "alloc")]
597 #[test]
598 fn fmt_lower_hex_from_trait() {
599 fn format_int<T: crate::Integer>(n: T) -> alloc::string::String {
600 format!("{n:x}")
601 }
602 let n = U128::from_be_hex("AAAAAAAABBBBBBBBCCCCCCCCDDDDDDDD");
603 assert_eq!(format_int(n), "aaaaaaaabbbbbbbbccccccccdddddddd");
604 }
605
606 #[cfg(feature = "alloc")]
607 #[test]
608 fn fmt_upper_hex() {
609 let n = U128::from_be_hex("aaaaaaaabbbbbbbbccccccccdddddddd");
610 assert_eq!(format!("{n:X}"), "AAAAAAAABBBBBBBBCCCCCCCCDDDDDDDD");
611 assert_eq!(format!("{n:#X}"), "0xAAAAAAAABBBBBBBBCCCCCCCCDDDDDDDD");
612 }
613
614 #[cfg(feature = "alloc")]
615 #[test]
616 fn fmt_upper_hex_from_trait() {
617 fn format_int<T: crate::Integer>(n: T) -> alloc::string::String {
618 format!("{n:X}")
619 }
620 let n = U128::from_be_hex("aaaaaaaabbbbbbbbccccccccdddddddd");
621 assert_eq!(format_int(n), "AAAAAAAABBBBBBBBCCCCCCCCDDDDDDDD");
622 }
623
624 #[cfg(feature = "alloc")]
625 #[test]
626 fn fmt_binary() {
627 let n = U128::from_be_hex("AAAAAAAABBBBBBBBCCCCCCCCDDDDDDDD");
628 assert_eq!(
629 format!("{n:b}"),
630 "10101010101010101010101010101010101110111011101110111011101110111100110011001100110011001100110011011101110111011101110111011101"
631 );
632 assert_eq!(
633 format!("{n:#b}"),
634 "0b10101010101010101010101010101010101110111011101110111011101110111100110011001100110011001100110011011101110111011101110111011101"
635 );
636 }
637
638 #[cfg(feature = "alloc")]
639 #[test]
640 fn fmt_binary_from_trait() {
641 fn format_int<T: crate::Integer>(n: T) -> alloc::string::String {
642 format!("{n:b}")
643 }
644 let n = U128::from_be_hex("aaaaaaaabbbbbbbbccccccccdddddddd");
645 assert_eq!(
646 format_int(n),
647 "10101010101010101010101010101010101110111011101110111011101110111100110011001100110011001100110011011101110111011101110111011101"
648 );
649 }
650
651 #[test]
652 fn from_bytes() {
653 let a = U128::from_be_hex("AAAAAAAABBBBBBBB0CCCCCCCDDDDDDDD");
654
655 let be_bytes = a.to_be_bytes();
656 let le_bytes = a.to_le_bytes();
657 for i in 0..16 {
658 assert_eq!(le_bytes[i], be_bytes[15 - i]);
659 }
660
661 let a_from_be = U128::from_be_bytes(be_bytes);
662 let a_from_le = U128::from_le_bytes(le_bytes);
663 assert_eq!(a_from_be, a_from_le);
664 assert_eq!(a_from_be, a);
665 }
666
667 #[test]
668 fn conditional_select() {
669 let a = U128::from_be_hex("00002222444466668888AAAACCCCEEEE");
670 let b = U128::from_be_hex("11113333555577779999BBBBDDDDFFFF");
671
672 let select_0 = U128::conditional_select(&a, &b, 0.into());
673 assert_eq!(a, select_0);
674
675 let select_1 = U128::conditional_select(&a, &b, 1.into());
676 assert_eq!(b, select_1);
677 }
678
679 #[test]
680 fn as_int() {
681 assert_eq!(*U128::ZERO.as_int(), Int::ZERO);
682 assert_eq!(*U128::ONE.as_int(), Int::ONE);
683 assert_eq!(*U128::MAX.as_int(), Int::MINUS_ONE);
684 }
685
686 #[test]
687 fn to_int() {
688 assert_eq!(U128::ZERO.try_into_int().unwrap(), Int::ZERO);
689 assert_eq!(U128::ONE.try_into_int().unwrap(), Int::ONE);
690 assert_eq!(I128::MAX.as_uint().try_into_int().unwrap(), Int::MAX);
691 assert!(bool::from(U128::MAX.try_into_int().is_none()));
692 }
693}