1#![allow(clippy::needless_range_loop, clippy::many_single_char_names)]
4
5#[macro_use]
6mod macros;
7
8mod add;
9mod add_mod;
10mod bit_and;
11mod bit_not;
12mod bit_or;
13mod bit_xor;
14mod bits;
15mod cmp;
16mod concat;
17mod div;
18pub(crate) mod div_limb;
19mod encoding;
20mod from;
21mod inv_mod;
22mod mul;
23mod mul_mod;
24mod neg;
25mod neg_mod;
26mod resize;
27mod shl;
28mod shr;
29mod split;
30mod sqrt;
31mod sub;
32mod sub_mod;
33
34pub mod modular;
36
37#[cfg(feature = "generic-array")]
38mod array;
39
40#[cfg(feature = "rand_core")]
41mod rand;
42
43use crate::{Bounded, Encoding, Integer, Limb, Word, Zero};
44use core::fmt;
45use subtle::{Choice, ConditionallySelectable};
46
47#[cfg(feature = "serde")]
48use serdect::serde::{Deserialize, Deserializer, Serialize, Serializer};
49
50#[cfg(feature = "zeroize")]
51use zeroize::DefaultIsZeroes;
52
53#[allow(clippy::derived_hash_with_manual_eq)]
72#[derive(Copy, Clone, Hash)]
73pub struct Uint<const LIMBS: usize> {
74 limbs: [Limb; LIMBS],
76}
77
78impl<const LIMBS: usize> Uint<LIMBS> {
79 pub const ZERO: Self = Self::from_u8(0);
81
82 pub const ONE: Self = Self::from_u8(1);
84
85 pub const MAX: Self = Self {
87 limbs: [Limb::MAX; LIMBS],
88 };
89
90 pub const BITS: usize = LIMBS * Limb::BITS;
92
93 pub(crate) const LOG2_BITS: usize = (usize::BITS - Self::BITS.leading_zeros()) as usize;
96
97 pub const BYTES: usize = LIMBS * Limb::BYTES;
99
100 pub const LIMBS: usize = LIMBS;
102
103 pub const fn new(limbs: [Limb; LIMBS]) -> Self {
105 Self { limbs }
106 }
107
108 #[inline]
111 pub const fn from_words(arr: [Word; LIMBS]) -> Self {
112 let mut limbs = [Limb::ZERO; LIMBS];
113 let mut i = 0;
114
115 while i < LIMBS {
116 limbs[i] = Limb(arr[i]);
117 i += 1;
118 }
119
120 Self { limbs }
121 }
122
123 #[inline]
126 pub const fn to_words(self) -> [Word; LIMBS] {
127 let mut arr = [0; LIMBS];
128 let mut i = 0;
129
130 while i < LIMBS {
131 arr[i] = self.limbs[i].0;
132 i += 1;
133 }
134
135 arr
136 }
137
138 pub const fn as_words(&self) -> &[Word; LIMBS] {
140 #[allow(trivial_casts, unsafe_code)]
142 unsafe {
143 &*((&self.limbs as *const _) as *const [Word; LIMBS])
144 }
145 }
146
147 pub fn as_words_mut(&mut self) -> &mut [Word; LIMBS] {
149 #[allow(trivial_casts, unsafe_code)]
151 unsafe {
152 &mut *((&mut self.limbs as *mut _) as *mut [Word; LIMBS])
153 }
154 }
155
156 pub const fn as_limbs(&self) -> &[Limb; LIMBS] {
158 &self.limbs
159 }
160
161 pub fn as_limbs_mut(&mut self) -> &mut [Limb; LIMBS] {
163 &mut self.limbs
164 }
165
166 pub const fn to_limbs(self) -> [Limb; LIMBS] {
168 self.limbs
169 }
170}
171
172impl<const LIMBS: usize> AsRef<[Word; LIMBS]> for Uint<LIMBS> {
173 fn as_ref(&self) -> &[Word; LIMBS] {
174 self.as_words()
175 }
176}
177
178impl<const LIMBS: usize> AsMut<[Word; LIMBS]> for Uint<LIMBS> {
179 fn as_mut(&mut self) -> &mut [Word; LIMBS] {
180 self.as_words_mut()
181 }
182}
183
184impl<const LIMBS: usize> AsRef<[Limb]> for Uint<LIMBS> {
185 fn as_ref(&self) -> &[Limb] {
186 self.as_limbs()
187 }
188}
189
190impl<const LIMBS: usize> AsMut<[Limb]> for Uint<LIMBS> {
191 fn as_mut(&mut self) -> &mut [Limb] {
192 self.as_limbs_mut()
193 }
194}
195
196impl<const LIMBS: usize> ConditionallySelectable for Uint<LIMBS> {
197 fn conditional_select(a: &Self, b: &Self, choice: Choice) -> Self {
198 let mut limbs = [Limb::ZERO; LIMBS];
199
200 for i in 0..LIMBS {
201 limbs[i] = Limb::conditional_select(&a.limbs[i], &b.limbs[i], choice);
202 }
203
204 Self { limbs }
205 }
206}
207
208impl<const LIMBS: usize> Default for Uint<LIMBS> {
209 fn default() -> Self {
210 Self::ZERO
211 }
212}
213
214impl<const LIMBS: usize> Integer for Uint<LIMBS> {
215 const ONE: Self = Self::ONE;
216 const MAX: Self = Self::MAX;
217 const BITS: usize = Self::BITS;
218 const BYTES: usize = Self::BYTES;
219 const LIMBS: usize = Self::LIMBS;
220
221 fn is_odd(&self) -> Choice {
222 self.limbs
223 .first()
224 .map(|limb| limb.is_odd())
225 .unwrap_or_else(|| Choice::from(0))
226 }
227}
228
229impl<const LIMBS: usize> Zero for Uint<LIMBS> {
230 const ZERO: Self = Self::ZERO;
231}
232
233impl<const LIMBS: usize> Bounded for Uint<LIMBS> {
234 const BITS: usize = Self::BITS;
235 const BYTES: usize = Self::BYTES;
236}
237
238impl<const LIMBS: usize> fmt::Debug for Uint<LIMBS> {
239 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
240 write!(f, "Uint(0x{self:X})")
241 }
242}
243
244impl<const LIMBS: usize> fmt::Display for Uint<LIMBS> {
245 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
246 fmt::UpperHex::fmt(self, f)
247 }
248}
249
250impl<const LIMBS: usize> fmt::LowerHex for Uint<LIMBS> {
251 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
252 for limb in self.limbs.iter().rev() {
253 fmt::LowerHex::fmt(limb, f)?;
254 }
255 Ok(())
256 }
257}
258
259impl<const LIMBS: usize> fmt::UpperHex for Uint<LIMBS> {
260 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
261 for limb in self.limbs.iter().rev() {
262 fmt::UpperHex::fmt(limb, f)?;
263 }
264 Ok(())
265 }
266}
267
268#[cfg(feature = "serde")]
269impl<'de, const LIMBS: usize> Deserialize<'de> for Uint<LIMBS>
270where
271 Uint<LIMBS>: Encoding,
272{
273 fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
274 where
275 D: Deserializer<'de>,
276 {
277 let mut buffer = Self::ZERO.to_le_bytes();
278 serdect::array::deserialize_hex_or_bin(buffer.as_mut(), deserializer)?;
279
280 Ok(Self::from_le_bytes(buffer))
281 }
282}
283
284#[cfg(feature = "serde")]
285impl<const LIMBS: usize> Serialize for Uint<LIMBS>
286where
287 Uint<LIMBS>: Encoding,
288{
289 fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
290 where
291 S: Serializer,
292 {
293 serdect::array::serialize_hex_lower_or_bin(&Encoding::to_le_bytes(self), serializer)
294 }
295}
296
297#[cfg(feature = "zeroize")]
298impl<const LIMBS: usize> DefaultIsZeroes for Uint<LIMBS> {}
299
300impl_uint_aliases! {
302 (U64, 64, "64-bit"),
303 (U128, 128, "128-bit"),
304 (U192, 192, "192-bit"),
305 (U256, 256, "256-bit"),
306 (U320, 320, "320-bit"),
307 (U384, 384, "384-bit"),
308 (U448, 448, "448-bit"),
309 (U512, 512, "512-bit"),
310 (U576, 576, "576-bit"),
311 (U640, 640, "640-bit"),
312 (U704, 704, "704-bit"),
313 (U768, 768, "768-bit"),
314 (U832, 832, "832-bit"),
315 (U896, 896, "896-bit"),
316 (U960, 960, "960-bit"),
317 (U1024, 1024, "1024-bit"),
318 (U1280, 1280, "1280-bit"),
319 (U1536, 1536, "1536-bit"),
320 (U1792, 1792, "1792-bit"),
321 (U2048, 2048, "2048-bit"),
322 (U3072, 3072, "3072-bit"),
323 (U3584, 3584, "3584-bit"),
324 (U4096, 4096, "4096-bit"),
325 (U4224, 4224, "4224-bit"),
326 (U4352, 4352, "4352-bit"),
327 (U6144, 6144, "6144-bit"),
328 (U8192, 8192, "8192-bit"),
329 (U16384, 16384, "16384-bit"),
330 (U32768, 32768, "32768-bit")
331}
332
333#[cfg(target_pointer_width = "32")]
334impl_uint_aliases! {
335 (U224, 224, "224-bit"), (U544, 544, "544-bit") }
338
339#[cfg(target_pointer_width = "32")]
340impl_uint_concat_split_even! {
341 U64,
342}
343
344impl_uint_concat_split_even! {
347 U128,
348 U256,
349 U384,
350 U512,
351 U640,
352 U768,
353 U896,
354 U1024,
355 U1280,
356 U1536,
357 U1792,
358 U2048,
359 U3072,
360 U3584,
361 U4096,
362 U4224,
363 U4352,
364 U6144,
365 U8192,
366 U16384,
367}
368
369impl_uint_concat_split_mixed! {
375 (U192, [1, 2]),
376 (U256, [1, 3]),
377 (U320, [1, 2, 3, 4]),
378 (U384, [1, 2, 4, 5]),
379 (U448, [1, 2, 3, 4, 5, 6]),
380 (U512, [1, 2, 3, 5, 6, 7]),
381 (U576, [1, 2, 3, 4, 5, 6, 7, 8]),
382 (U640, [1, 2, 3, 4, 6, 7, 8, 9]),
383 (U704, [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]),
384 (U768, [1, 2, 3, 4, 5, 7, 8, 9, 10, 11]),
385 (U832, [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12]),
386 (U896, [1, 2, 3, 4, 5, 6, 8, 9, 10, 11, 12, 13]),
387 (U960, [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14]),
388 (U1024, [1, 2, 3, 4, 5, 6, 7, 9, 10, 11, 12, 13, 14, 15]),
389}
390
391#[cfg(feature = "extra-sizes")]
392mod extra_sizes;
393#[cfg(feature = "extra-sizes")]
394pub use extra_sizes::*;
395
396#[cfg(test)]
397#[allow(clippy::unwrap_used)]
398mod tests {
399 use crate::{Encoding, U128};
400 use subtle::ConditionallySelectable;
401
402 #[cfg(feature = "alloc")]
403 use alloc::format;
404
405 #[cfg(feature = "serde")]
406 use crate::U64;
407
408 #[cfg(feature = "alloc")]
409 #[test]
410 fn debug() {
411 let hex = "AAAAAAAABBBBBBBBCCCCCCCCDDDDDDDD";
412 let n = U128::from_be_hex(hex);
413
414 assert_eq!(
415 format!("{:?}", n),
416 "Uint(0xAAAAAAAABBBBBBBBCCCCCCCCDDDDDDDD)"
417 );
418 }
419
420 #[cfg(feature = "alloc")]
421 #[test]
422 fn display() {
423 let hex = "AAAAAAAABBBBBBBBCCCCCCCCDDDDDDDD";
424 let n = U128::from_be_hex(hex);
425
426 use alloc::string::ToString;
427 assert_eq!(hex, n.to_string());
428
429 let hex = "AAAAAAAABBBBBBBB0000000000000000";
430 let n = U128::from_be_hex(hex);
431 assert_eq!(hex, n.to_string());
432
433 let hex = "AAAAAAAABBBBBBBB00000000DDDDDDDD";
434 let n = U128::from_be_hex(hex);
435 assert_eq!(hex, n.to_string());
436
437 let hex = "AAAAAAAABBBBBBBB0CCCCCCCDDDDDDDD";
438 let n = U128::from_be_hex(hex);
439 assert_eq!(hex, n.to_string());
440 }
441
442 #[test]
443 fn from_bytes() {
444 let a = U128::from_be_hex("AAAAAAAABBBBBBBB0CCCCCCCDDDDDDDD");
445
446 let be_bytes = a.to_be_bytes();
447 let le_bytes = a.to_le_bytes();
448 for i in 0..16 {
449 assert_eq!(le_bytes[i], be_bytes[15 - i]);
450 }
451
452 let a_from_be = U128::from_be_bytes(be_bytes);
453 let a_from_le = U128::from_le_bytes(le_bytes);
454 assert_eq!(a_from_be, a_from_le);
455 assert_eq!(a_from_be, a);
456 }
457
458 #[test]
459 fn conditional_select() {
460 let a = U128::from_be_hex("00002222444466668888AAAACCCCEEEE");
461 let b = U128::from_be_hex("11113333555577779999BBBBDDDDFFFF");
462
463 let select_0 = U128::conditional_select(&a, &b, 0.into());
464 assert_eq!(a, select_0);
465
466 let select_1 = U128::conditional_select(&a, &b, 1.into());
467 assert_eq!(b, select_1);
468 }
469
470 #[cfg(feature = "serde")]
471 #[test]
472 fn serde() {
473 const TEST: U64 = U64::from_u64(0x0011223344556677);
474
475 let serialized = bincode::serialize(&TEST).unwrap();
476 let deserialized: U64 = bincode::deserialize(&serialized).unwrap();
477
478 assert_eq!(TEST, deserialized);
479 }
480
481 #[cfg(feature = "serde")]
482 #[test]
483 fn serde_owned() {
484 const TEST: U64 = U64::from_u64(0x0011223344556677);
485
486 let serialized = bincode::serialize(&TEST).unwrap();
487 let deserialized: U64 = bincode::deserialize_from(serialized.as_slice()).unwrap();
488
489 assert_eq!(TEST, deserialized);
490 }
491}