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