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, ConstZero, Constants, Encoding, FixedInteger, Int,
20 Integer, Limb, NonZero, Odd, Word, 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 ONE: Self = Self::ONE;
290 const MAX: Self = Self::MAX;
291}
292
293impl<const LIMBS: usize> Default for Uint<LIMBS> {
294 fn default() -> Self {
295 Self::ZERO
296 }
297}
298
299impl<const LIMBS: usize> FixedInteger for Uint<LIMBS> {
300 const LIMBS: usize = LIMBS;
301}
302
303impl<const LIMBS: usize> Integer for Uint<LIMBS> {
304 type Monty = MontyForm<LIMBS>;
305
306 fn one() -> Self {
307 Self::ONE
308 }
309
310 fn from_limb_like(limb: Limb, _other: &Self) -> Self {
311 Self::from(limb)
312 }
313
314 fn nlimbs(&self) -> usize {
315 Self::LIMBS
316 }
317}
318
319impl<const LIMBS: usize> num_traits::Num for Uint<LIMBS> {
320 type FromStrRadixErr = crate::DecodeError;
321
322 fn from_str_radix(str: &str, radix: u32) -> Result<Self, Self::FromStrRadixErr> {
324 Self::from_str_radix_vartime(str, radix)
325 }
326}
327
328impl<const LIMBS: usize> ConstZero for Uint<LIMBS> {
329 const ZERO: Self = Self::ZERO;
330}
331
332impl<const LIMBS: usize> num_traits::Zero for Uint<LIMBS> {
333 fn zero() -> Self {
334 Self::ZERO
335 }
336
337 fn is_zero(&self) -> bool {
338 self.ct_eq(&Self::ZERO).into()
339 }
340}
341
342impl<const LIMBS: usize> num_traits::One for Uint<LIMBS> {
343 fn one() -> Self {
344 Self::ONE
345 }
346
347 fn is_one(&self) -> bool {
348 self.ct_eq(&Self::ONE).into()
349 }
350}
351
352impl<const LIMBS: usize> fmt::Debug for Uint<LIMBS> {
353 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
354 write!(f, "Uint(0x{:X})", self.as_uint_ref())
355 }
356}
357
358impl<const LIMBS: usize> fmt::Binary for Uint<LIMBS> {
359 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
360 fmt::Binary::fmt(self.as_uint_ref(), f)
361 }
362}
363
364impl<const LIMBS: usize> fmt::Display for Uint<LIMBS> {
365 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
366 fmt::UpperHex::fmt(self, f)
367 }
368}
369
370impl<const LIMBS: usize> fmt::LowerHex for Uint<LIMBS> {
371 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
372 fmt::LowerHex::fmt(self.as_uint_ref(), f)
373 }
374}
375
376impl<const LIMBS: usize> fmt::UpperHex for Uint<LIMBS> {
377 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
378 fmt::UpperHex::fmt(self.as_uint_ref(), f)
379 }
380}
381
382#[cfg(feature = "serde")]
383impl<'de, const LIMBS: usize> Deserialize<'de> for Uint<LIMBS>
384where
385 Uint<LIMBS>: Encoding,
386{
387 fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
388 where
389 D: Deserializer<'de>,
390 {
391 let mut buffer = Self::ZERO.to_le_bytes();
392 serdect::array::deserialize_hex_or_bin(buffer.as_mut(), deserializer)?;
393
394 Ok(Self::from_le_bytes(buffer))
395 }
396}
397
398#[cfg(feature = "serde")]
399impl<const LIMBS: usize> Serialize for Uint<LIMBS>
400where
401 Uint<LIMBS>: Encoding,
402{
403 fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
404 where
405 S: Serializer,
406 {
407 serdect::array::serialize_hex_lower_or_bin(&Encoding::to_le_bytes(self), serializer)
408 }
409}
410
411#[cfg(feature = "zeroize")]
412impl<const LIMBS: usize> DefaultIsZeroes for Uint<LIMBS> {}
413
414impl_uint_aliases! {
416 (U64, 64, "64-bit"),
417 (U128, 128, "128-bit"),
418 (U192, 192, "192-bit"),
419 (U256, 256, "256-bit"),
420 (U320, 320, "320-bit"),
421 (U384, 384, "384-bit"),
422 (U448, 448, "448-bit"),
423 (U512, 512, "512-bit"),
424 (U576, 576, "576-bit"),
425 (U640, 640, "640-bit"),
426 (U704, 704, "704-bit"),
427 (U768, 768, "768-bit"),
428 (U832, 832, "832-bit"),
429 (U896, 896, "896-bit"),
430 (U960, 960, "960-bit"),
431 (U1024, 1024, "1024-bit"),
432 (U1280, 1280, "1280-bit"),
433 (U1536, 1536, "1536-bit"),
434 (U1792, 1792, "1792-bit"),
435 (U2048, 2048, "2048-bit"),
436 (U3072, 3072, "3072-bit"),
437 (U3584, 3584, "3584-bit"),
438 (U4096, 4096, "4096-bit"),
439 (U4224, 4224, "4224-bit"),
440 (U4352, 4352, "4352-bit"),
441 (U6144, 6144, "6144-bit"),
442 (U8192, 8192, "8192-bit"),
443 (U16384, 16384, "16384-bit"),
444 (U32768, 32768, "32768-bit")
445}
446
447#[cfg(target_pointer_width = "32")]
448impl_uint_aliases! {
449 (U224, 224, "224-bit"), (U544, 544, "544-bit") }
452
453#[cfg(target_pointer_width = "32")]
454impl_uint_concat_split_even! {
455 U64,
456}
457
458impl_uint_concat_split_even! {
461 U128,
462 U256,
463 U384,
464 U512,
465 U640,
466 U768,
467 U896,
468 U1024,
469 U1280,
470 U1536,
471 U1792,
472 U2048,
473 U3072,
474 U3584,
475 U4096,
476 U4224,
477 U4352,
478 U6144,
479 U8192,
480 U16384,
481}
482
483impl_uint_concat_split_mixed! {
489 (U192, [1, 2]),
490 (U256, [1, 3]),
491 (U320, [1, 2, 3, 4]),
492 (U384, [1, 2, 4, 5]),
493 (U448, [1, 2, 3, 4, 5, 6]),
494 (U512, [1, 2, 3, 5, 6, 7]),
495 (U576, [1, 2, 3, 4, 5, 6, 7, 8]),
496 (U640, [1, 2, 3, 4, 6, 7, 8, 9]),
497 (U704, [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]),
498 (U768, [1, 2, 3, 4, 5, 7, 8, 9, 10, 11]),
499 (U832, [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12]),
500 (U896, [1, 2, 3, 4, 5, 6, 8, 9, 10, 11, 12, 13]),
501 (U960, [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14]),
502 (U1024, [1, 2, 3, 4, 5, 6, 7, 9, 10, 11, 12, 13, 14, 15]),
503}
504
505#[cfg(feature = "extra-sizes")]
506mod extra_sizes;
507mod mul_int;
508mod ref_type;
509
510#[cfg(test)]
511#[allow(clippy::unwrap_used)]
512mod tests {
513 use crate::{Encoding, I128, Int, U128};
514 use subtle::ConditionallySelectable;
515
516 #[cfg(feature = "alloc")]
517 use alloc::format;
518
519 #[cfg(target_pointer_width = "64")]
520 #[test]
521 fn as_words() {
522 let n = U128::from_be_hex("AAAAAAAABBBBBBBBCCCCCCCCDDDDDDDD");
523 assert_eq!(n.as_words(), &[0xCCCCCCCCDDDDDDDD, 0xAAAAAAAABBBBBBBB]);
524 }
525
526 #[cfg(target_pointer_width = "64")]
527 #[test]
528 fn as_words_mut() {
529 let mut n = U128::from_be_hex("AAAAAAAABBBBBBBBCCCCCCCCDDDDDDDD");
530 assert_eq!(n.as_mut_words(), &[0xCCCCCCCCDDDDDDDD, 0xAAAAAAAABBBBBBBB]);
531 }
532
533 #[cfg(feature = "alloc")]
534 #[test]
535 fn debug() {
536 let n = U128::from_be_hex("AAAAAAAABBBBBBBBCCCCCCCCDDDDDDDD");
537
538 assert_eq!(format!("{n:?}"), "Uint(0xAAAAAAAABBBBBBBBCCCCCCCCDDDDDDDD)");
539 }
540
541 #[cfg(feature = "alloc")]
542 #[test]
543 fn display() {
544 let hex = "AAAAAAAABBBBBBBBCCCCCCCCDDDDDDDD";
545 let n = U128::from_be_hex(hex);
546
547 use alloc::string::ToString;
548 assert_eq!(hex, n.to_string());
549
550 let hex = "AAAAAAAABBBBBBBB0000000000000000";
551 let n = U128::from_be_hex(hex);
552 assert_eq!(hex, n.to_string());
553
554 let hex = "AAAAAAAABBBBBBBB00000000DDDDDDDD";
555 let n = U128::from_be_hex(hex);
556 assert_eq!(hex, n.to_string());
557
558 let hex = "AAAAAAAABBBBBBBB0CCCCCCCDDDDDDDD";
559 let n = U128::from_be_hex(hex);
560 assert_eq!(hex, n.to_string());
561 }
562
563 #[cfg(feature = "alloc")]
564 #[test]
565 fn fmt_lower_hex() {
566 let n = U128::from_be_hex("AAAAAAAABBBBBBBBCCCCCCCCDDDDDDDD");
567 assert_eq!(format!("{n:x}"), "aaaaaaaabbbbbbbbccccccccdddddddd");
568 assert_eq!(format!("{n:#x}"), "0xaaaaaaaabbbbbbbbccccccccdddddddd");
569 }
570
571 #[cfg(feature = "alloc")]
572 #[test]
573 fn fmt_lower_hex_from_trait() {
574 fn format_int<T: crate::Integer>(n: T) -> alloc::string::String {
575 format!("{n:x}")
576 }
577 let n = U128::from_be_hex("AAAAAAAABBBBBBBBCCCCCCCCDDDDDDDD");
578 assert_eq!(format_int(n), "aaaaaaaabbbbbbbbccccccccdddddddd");
579 }
580
581 #[cfg(feature = "alloc")]
582 #[test]
583 fn fmt_upper_hex() {
584 let n = U128::from_be_hex("aaaaaaaabbbbbbbbccccccccdddddddd");
585 assert_eq!(format!("{n:X}"), "AAAAAAAABBBBBBBBCCCCCCCCDDDDDDDD");
586 assert_eq!(format!("{n:#X}"), "0xAAAAAAAABBBBBBBBCCCCCCCCDDDDDDDD");
587 }
588
589 #[cfg(feature = "alloc")]
590 #[test]
591 fn fmt_upper_hex_from_trait() {
592 fn format_int<T: crate::Integer>(n: T) -> alloc::string::String {
593 format!("{n:X}")
594 }
595 let n = U128::from_be_hex("aaaaaaaabbbbbbbbccccccccdddddddd");
596 assert_eq!(format_int(n), "AAAAAAAABBBBBBBBCCCCCCCCDDDDDDDD");
597 }
598
599 #[cfg(feature = "alloc")]
600 #[test]
601 fn fmt_binary() {
602 let n = U128::from_be_hex("AAAAAAAABBBBBBBBCCCCCCCCDDDDDDDD");
603 assert_eq!(
604 format!("{n:b}"),
605 "10101010101010101010101010101010101110111011101110111011101110111100110011001100110011001100110011011101110111011101110111011101"
606 );
607 assert_eq!(
608 format!("{n:#b}"),
609 "0b10101010101010101010101010101010101110111011101110111011101110111100110011001100110011001100110011011101110111011101110111011101"
610 );
611 }
612
613 #[cfg(feature = "alloc")]
614 #[test]
615 fn fmt_binary_from_trait() {
616 fn format_int<T: crate::Integer>(n: T) -> alloc::string::String {
617 format!("{n:b}")
618 }
619 let n = U128::from_be_hex("aaaaaaaabbbbbbbbccccccccdddddddd");
620 assert_eq!(
621 format_int(n),
622 "10101010101010101010101010101010101110111011101110111011101110111100110011001100110011001100110011011101110111011101110111011101"
623 );
624 }
625
626 #[test]
627 fn from_bytes() {
628 let a = U128::from_be_hex("AAAAAAAABBBBBBBB0CCCCCCCDDDDDDDD");
629
630 let be_bytes = a.to_be_bytes();
631 let le_bytes = a.to_le_bytes();
632 for i in 0..16 {
633 assert_eq!(le_bytes[i], be_bytes[15 - i]);
634 }
635
636 let a_from_be = U128::from_be_bytes(be_bytes);
637 let a_from_le = U128::from_le_bytes(le_bytes);
638 assert_eq!(a_from_be, a_from_le);
639 assert_eq!(a_from_be, a);
640 }
641
642 #[test]
643 fn conditional_select() {
644 let a = U128::from_be_hex("00002222444466668888AAAACCCCEEEE");
645 let b = U128::from_be_hex("11113333555577779999BBBBDDDDFFFF");
646
647 let select_0 = U128::conditional_select(&a, &b, 0.into());
648 assert_eq!(a, select_0);
649
650 let select_1 = U128::conditional_select(&a, &b, 1.into());
651 assert_eq!(b, select_1);
652 }
653
654 #[test]
655 fn as_int() {
656 assert_eq!(*U128::ZERO.as_int(), Int::ZERO);
657 assert_eq!(*U128::ONE.as_int(), Int::ONE);
658 assert_eq!(*U128::MAX.as_int(), Int::MINUS_ONE);
659 }
660
661 #[test]
662 fn to_int() {
663 assert_eq!(U128::ZERO.try_into_int().unwrap(), Int::ZERO);
664 assert_eq!(U128::ONE.try_into_int().unwrap(), Int::ONE);
665 assert_eq!(I128::MAX.as_uint().try_into_int().unwrap(), Int::MAX);
666 assert!(bool::from(U128::MAX.try_into_int().is_none()));
667 }
668}