cosmwasm_std/math/
uint512.rs

1use alloc::string::{String, ToString};
2use core::fmt;
3use core::ops::{
4    Add, AddAssign, Div, DivAssign, Mul, MulAssign, Not, Rem, RemAssign, Shl, ShlAssign, Shr,
5    ShrAssign, Sub, SubAssign,
6};
7use core::str::FromStr;
8
9use crate::errors::{
10    ConversionOverflowError, DivideByZeroError, OverflowError, OverflowOperation, StdError,
11};
12use crate::forward_ref::{forward_ref_binop, forward_ref_op_assign};
13use crate::{
14    Int128, Int256, Int512, Int64, Uint128, Uint256, Uint64, __internal::forward_ref_partial_eq,
15};
16
17/// Used internally - we don't want to leak this type since we might change
18/// the implementation in the future.
19use bnum::types::U512;
20
21use super::conversion::{forward_try_from, primitive_to_wrapped_int, try_from_int_to_uint};
22use super::impl_int_serde;
23use super::num_consts::NumConsts;
24
25/// An implementation of u512 that is using strings for JSON encoding/decoding,
26/// such that the full u512 range can be used for clients that convert JSON numbers to floats,
27/// like JavaScript and jq.
28///
29/// # Examples
30///
31/// Use `from` to create instances out of primitive uint types or `new` to provide big
32/// endian bytes:
33///
34/// ```
35/// # use cosmwasm_std::Uint512;
36/// let a = Uint512::from(258u128);
37/// let b = Uint512::new([
38///     0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8,
39///     0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8,
40///     0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8,
41///     0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8,
42///     0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8,
43///     0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8,
44///     0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8,
45///     0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 1u8, 2u8,
46/// ]);
47/// assert_eq!(a, b);
48/// ```
49#[derive(Copy, Clone, Default, Debug, PartialEq, Eq, PartialOrd, Ord, schemars::JsonSchema)]
50pub struct Uint512(#[schemars(with = "String")] pub(crate) U512);
51
52impl_int_serde!(Uint512);
53forward_ref_partial_eq!(Uint512, Uint512);
54
55impl Uint512 {
56    pub const MAX: Uint512 = Uint512(U512::MAX);
57    pub const MIN: Uint512 = Uint512(U512::ZERO);
58
59    /// Creates a Uint512(value) from a big endian representation. It's just an alias for
60    /// `from_be_bytes`.
61    pub const fn new(value: [u8; 64]) -> Self {
62        Self::from_be_bytes(value)
63    }
64
65    /// Creates a Uint512(0)
66    #[inline]
67    pub const fn zero() -> Self {
68        Uint512(U512::ZERO)
69    }
70
71    /// Creates a Uint512(1)
72    #[inline]
73    pub const fn one() -> Self {
74        Self(U512::ONE)
75    }
76
77    #[must_use]
78    pub const fn from_be_bytes(data: [u8; 64]) -> Self {
79        let words: [u64; 8] = [
80            u64::from_le_bytes([
81                data[63], data[62], data[61], data[60], data[59], data[58], data[57], data[56],
82            ]),
83            u64::from_le_bytes([
84                data[55], data[54], data[53], data[52], data[51], data[50], data[49], data[48],
85            ]),
86            u64::from_le_bytes([
87                data[47], data[46], data[45], data[44], data[43], data[42], data[41], data[40],
88            ]),
89            u64::from_le_bytes([
90                data[39], data[38], data[37], data[36], data[35], data[34], data[33], data[32],
91            ]),
92            u64::from_le_bytes([
93                data[31], data[30], data[29], data[28], data[27], data[26], data[25], data[24],
94            ]),
95            u64::from_le_bytes([
96                data[23], data[22], data[21], data[20], data[19], data[18], data[17], data[16],
97            ]),
98            u64::from_le_bytes([
99                data[15], data[14], data[13], data[12], data[11], data[10], data[9], data[8],
100            ]),
101            u64::from_le_bytes([
102                data[7], data[6], data[5], data[4], data[3], data[2], data[1], data[0],
103            ]),
104        ];
105        Self(U512::from_digits(words))
106    }
107
108    #[must_use]
109    pub const fn from_le_bytes(data: [u8; 64]) -> Self {
110        let words: [u64; 8] = [
111            u64::from_le_bytes([
112                data[0], data[1], data[2], data[3], data[4], data[5], data[6], data[7],
113            ]),
114            u64::from_le_bytes([
115                data[8], data[9], data[10], data[11], data[12], data[13], data[14], data[15],
116            ]),
117            u64::from_le_bytes([
118                data[16], data[17], data[18], data[19], data[20], data[21], data[22], data[23],
119            ]),
120            u64::from_le_bytes([
121                data[24], data[25], data[26], data[27], data[28], data[29], data[30], data[31],
122            ]),
123            u64::from_le_bytes([
124                data[32], data[33], data[34], data[35], data[36], data[37], data[38], data[39],
125            ]),
126            u64::from_le_bytes([
127                data[40], data[41], data[42], data[43], data[44], data[45], data[46], data[47],
128            ]),
129            u64::from_le_bytes([
130                data[48], data[49], data[50], data[51], data[52], data[53], data[54], data[55],
131            ]),
132            u64::from_le_bytes([
133                data[56], data[57], data[58], data[59], data[60], data[61], data[62], data[63],
134            ]),
135        ];
136        Self(U512::from_digits(words))
137    }
138
139    /// A conversion from `Uint256` that, unlike the one provided by the `From` trait,
140    /// can be used in a `const` context.
141    #[must_use]
142    pub const fn from_uint256(num: Uint256) -> Self {
143        let bytes = num.to_le_bytes();
144        Self::from_le_bytes([
145            bytes[0], bytes[1], bytes[2], bytes[3], bytes[4], bytes[5], bytes[6], bytes[7],
146            bytes[8], bytes[9], bytes[10], bytes[11], bytes[12], bytes[13], bytes[14], bytes[15],
147            bytes[16], bytes[17], bytes[18], bytes[19], bytes[20], bytes[21], bytes[22], bytes[23],
148            bytes[24], bytes[25], bytes[26], bytes[27], bytes[28], bytes[29], bytes[30], bytes[31],
149            0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
150            0, 0, 0,
151        ])
152    }
153
154    /// Returns a copy of the number as big endian bytes.
155    #[must_use = "this returns the result of the operation, without modifying the original"]
156    pub const fn to_be_bytes(self) -> [u8; 64] {
157        let words = self.0.digits();
158        let words = [
159            words[7].to_be_bytes(),
160            words[6].to_be_bytes(),
161            words[5].to_be_bytes(),
162            words[4].to_be_bytes(),
163            words[3].to_be_bytes(),
164            words[2].to_be_bytes(),
165            words[1].to_be_bytes(),
166            words[0].to_be_bytes(),
167        ];
168        unsafe { core::mem::transmute::<[[u8; 8]; 8], [u8; 64]>(words) }
169    }
170
171    /// Returns a copy of the number as little endian bytes.
172    #[must_use = "this returns the result of the operation, without modifying the original"]
173    pub const fn to_le_bytes(self) -> [u8; 64] {
174        let words = self.0.digits();
175        let words = [
176            words[0].to_le_bytes(),
177            words[1].to_le_bytes(),
178            words[2].to_le_bytes(),
179            words[3].to_le_bytes(),
180            words[4].to_le_bytes(),
181            words[5].to_le_bytes(),
182            words[6].to_le_bytes(),
183            words[7].to_le_bytes(),
184        ];
185        unsafe { core::mem::transmute::<[[u8; 8]; 8], [u8; 64]>(words) }
186    }
187
188    #[must_use]
189    pub const fn is_zero(&self) -> bool {
190        self.0.is_zero()
191    }
192
193    #[must_use = "this returns the result of the operation, without modifying the original"]
194    pub const fn pow(self, exp: u32) -> Self {
195        match self.0.checked_pow(exp) {
196            Some(val) => Self(val),
197            None => panic!("attempt to exponentiate with overflow"),
198        }
199    }
200
201    /// Returns the base 2 logarithm of the number, rounded down.
202    ///
203    /// # Panics
204    ///
205    /// This function will panic if `self` is zero.
206    #[must_use = "this returns the result of the operation, without modifying the original"]
207    pub fn ilog2(self) -> u32 {
208        self.0.checked_ilog2().unwrap()
209    }
210
211    pub fn checked_add(self, other: Self) -> Result<Self, OverflowError> {
212        self.0
213            .checked_add(other.0)
214            .map(Self)
215            .ok_or_else(|| OverflowError::new(OverflowOperation::Add))
216    }
217
218    pub fn checked_sub(self, other: Self) -> Result<Self, OverflowError> {
219        self.0
220            .checked_sub(other.0)
221            .map(Self)
222            .ok_or_else(|| OverflowError::new(OverflowOperation::Sub))
223    }
224
225    pub fn checked_mul(self, other: Self) -> Result<Self, OverflowError> {
226        self.0
227            .checked_mul(other.0)
228            .map(Self)
229            .ok_or_else(|| OverflowError::new(OverflowOperation::Mul))
230    }
231
232    pub fn checked_pow(self, exp: u32) -> Result<Self, OverflowError> {
233        self.0
234            .checked_pow(exp)
235            .map(Self)
236            .ok_or_else(|| OverflowError::new(OverflowOperation::Pow))
237    }
238
239    pub fn checked_div(self, other: Self) -> Result<Self, DivideByZeroError> {
240        self.0
241            .checked_div(other.0)
242            .map(Self)
243            .ok_or(DivideByZeroError)
244    }
245
246    pub fn checked_div_euclid(self, other: Self) -> Result<Self, DivideByZeroError> {
247        self.checked_div(other)
248    }
249
250    pub fn checked_rem(self, other: Self) -> Result<Self, DivideByZeroError> {
251        self.0
252            .checked_rem(other.0)
253            .map(Self)
254            .ok_or(DivideByZeroError)
255    }
256
257    pub fn checked_shr(self, other: u32) -> Result<Self, OverflowError> {
258        self.0
259            .checked_shr(other)
260            .map(Self)
261            .ok_or_else(|| OverflowError::new(OverflowOperation::Shr))
262    }
263
264    pub fn checked_shl(self, other: u32) -> Result<Self, OverflowError> {
265        if other >= 512 {
266            return Err(OverflowError::new(OverflowOperation::Shl));
267        }
268
269        Ok(Self(self.0.shl(other)))
270    }
271
272    #[must_use = "this returns the result of the operation, without modifying the original"]
273    #[inline]
274    pub fn wrapping_add(self, other: Self) -> Self {
275        Self(self.0.wrapping_add(other.0))
276    }
277
278    #[must_use = "this returns the result of the operation, without modifying the original"]
279    #[inline]
280    pub fn wrapping_sub(self, other: Self) -> Self {
281        Self(self.0.wrapping_sub(other.0))
282    }
283
284    #[must_use = "this returns the result of the operation, without modifying the original"]
285    #[inline]
286    pub fn wrapping_mul(self, other: Self) -> Self {
287        Self(self.0.wrapping_mul(other.0))
288    }
289
290    #[must_use = "this returns the result of the operation, without modifying the original"]
291    #[inline]
292    pub fn wrapping_pow(self, other: u32) -> Self {
293        Self(self.0.wrapping_pow(other))
294    }
295
296    #[must_use = "this returns the result of the operation, without modifying the original"]
297    pub fn saturating_add(self, other: Self) -> Self {
298        Self(self.0.saturating_add(other.0))
299    }
300
301    #[must_use = "this returns the result of the operation, without modifying the original"]
302    pub fn saturating_sub(self, other: Self) -> Self {
303        Self(self.0.saturating_sub(other.0))
304    }
305
306    #[must_use = "this returns the result of the operation, without modifying the original"]
307    pub fn saturating_mul(self, other: Self) -> Self {
308        Self(self.0.saturating_mul(other.0))
309    }
310
311    #[must_use = "this returns the result of the operation, without modifying the original"]
312    pub fn saturating_pow(self, exp: u32) -> Self {
313        Self(self.0.saturating_pow(exp))
314    }
315
316    /// Strict integer addition. Computes `self + rhs`, panicking if overflow occurred.
317    ///
318    /// This is the same as [`Uint512::add`] but const.
319    #[must_use = "this returns the result of the operation, without modifying the original"]
320    pub const fn strict_add(self, rhs: Self) -> Self {
321        match self.0.checked_add(rhs.0) {
322            None => panic!("attempt to add with overflow"),
323            Some(sum) => Self(sum),
324        }
325    }
326
327    /// Strict integer subtraction. Computes `self - rhs`, panicking if overflow occurred.
328    ///
329    /// This is the same as [`Uint512::sub`] but const.
330    #[must_use = "this returns the result of the operation, without modifying the original"]
331    pub const fn strict_sub(self, other: Self) -> Self {
332        match self.0.checked_sub(other.0) {
333            None => panic!("attempt to subtract with overflow"),
334            Some(diff) => Self(diff),
335        }
336    }
337
338    #[must_use = "this returns the result of the operation, without modifying the original"]
339    pub const fn abs_diff(self, other: Self) -> Self {
340        Self(self.0.abs_diff(other.0))
341    }
342}
343
344impl NumConsts for Uint512 {
345    const ZERO: Self = Self::zero();
346    const ONE: Self = Self::one();
347    const MAX: Self = Self::MAX;
348    const MIN: Self = Self::MIN;
349}
350
351// uint to Uint
352primitive_to_wrapped_int!(u8, Uint512);
353primitive_to_wrapped_int!(u16, Uint512);
354primitive_to_wrapped_int!(u32, Uint512);
355primitive_to_wrapped_int!(u64, Uint512);
356primitive_to_wrapped_int!(u128, Uint512);
357
358impl From<Uint256> for Uint512 {
359    fn from(val: Uint256) -> Self {
360        let mut bytes = [0u8; 64];
361        bytes[32..].copy_from_slice(&val.to_be_bytes());
362
363        Self::from_be_bytes(bytes)
364    }
365}
366
367impl From<Uint128> for Uint512 {
368    fn from(val: Uint128) -> Self {
369        val.u128().into()
370    }
371}
372
373impl From<Uint64> for Uint512 {
374    fn from(val: Uint64) -> Self {
375        val.u64().into()
376    }
377}
378
379impl TryFrom<Uint512> for Uint256 {
380    type Error = ConversionOverflowError;
381
382    fn try_from(value: Uint512) -> Result<Self, Self::Error> {
383        let bytes = value.to_be_bytes();
384        let (first_bytes, last_bytes) = bytes.split_at(32);
385
386        if first_bytes != [0u8; 32] {
387            return Err(ConversionOverflowError::new("Uint512", "Uint256"));
388        }
389
390        Ok(Self::from_be_bytes(last_bytes.try_into().unwrap()))
391    }
392}
393
394forward_try_from!(Uint512, Uint128);
395forward_try_from!(Uint512, Uint64);
396
397// Int to Uint
398try_from_int_to_uint!(Int64, Uint512);
399try_from_int_to_uint!(Int128, Uint512);
400try_from_int_to_uint!(Int256, Uint512);
401try_from_int_to_uint!(Int512, Uint512);
402
403impl TryFrom<&str> for Uint512 {
404    type Error = StdError;
405
406    fn try_from(val: &str) -> Result<Self, Self::Error> {
407        Self::from_str(val)
408    }
409}
410
411impl FromStr for Uint512 {
412    type Err = StdError;
413
414    fn from_str(s: &str) -> Result<Self, Self::Err> {
415        match U512::from_str_radix(s, 10) {
416            Ok(u) => Ok(Self(u)),
417            Err(e) => Err(StdError::generic_err(format!("Parsing u512: {e}"))),
418        }
419    }
420}
421
422impl From<Uint512> for String {
423    fn from(original: Uint512) -> Self {
424        original.to_string()
425    }
426}
427
428impl fmt::Display for Uint512 {
429    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
430        self.0.fmt(f)
431    }
432}
433
434impl Add<Uint512> for Uint512 {
435    type Output = Self;
436
437    fn add(self, rhs: Self) -> Self {
438        self.strict_add(rhs)
439    }
440}
441forward_ref_binop!(impl Add, add for Uint512, Uint512);
442
443impl Sub<Uint512> for Uint512 {
444    type Output = Self;
445
446    fn sub(self, rhs: Self) -> Self {
447        self.strict_sub(rhs)
448    }
449}
450forward_ref_binop!(impl Sub, sub for Uint512, Uint512);
451
452impl SubAssign<Uint512> for Uint512 {
453    fn sub_assign(&mut self, rhs: Uint512) {
454        self.0 = self.0.checked_sub(rhs.0).unwrap();
455    }
456}
457forward_ref_op_assign!(impl SubAssign, sub_assign for Uint512, Uint512);
458
459impl Div<Uint512> for Uint512 {
460    type Output = Self;
461
462    fn div(self, rhs: Self) -> Self::Output {
463        Self(self.0.checked_div(rhs.0).unwrap())
464    }
465}
466
467impl<'a> Div<&'a Uint512> for Uint512 {
468    type Output = Self;
469
470    fn div(self, rhs: &'a Uint512) -> Self::Output {
471        Self(self.0.checked_div(rhs.0).unwrap())
472    }
473}
474
475impl Rem for Uint512 {
476    type Output = Self;
477
478    /// # Panics
479    ///
480    /// This operation will panic if `rhs` is zero.
481    #[inline]
482    fn rem(self, rhs: Self) -> Self {
483        Self(self.0.rem(rhs.0))
484    }
485}
486forward_ref_binop!(impl Rem, rem for Uint512, Uint512);
487
488impl Not for Uint512 {
489    type Output = Self;
490
491    fn not(self) -> Self::Output {
492        Self(!self.0)
493    }
494}
495
496impl RemAssign<Uint512> for Uint512 {
497    fn rem_assign(&mut self, rhs: Uint512) {
498        *self = *self % rhs;
499    }
500}
501forward_ref_op_assign!(impl RemAssign, rem_assign for Uint512, Uint512);
502
503impl Mul<Uint512> for Uint512 {
504    type Output = Self;
505
506    fn mul(self, rhs: Self) -> Self::Output {
507        Self(self.0.checked_mul(rhs.0).unwrap())
508    }
509}
510forward_ref_binop!(impl Mul, mul for Uint512, Uint512);
511
512impl MulAssign<Uint512> for Uint512 {
513    fn mul_assign(&mut self, rhs: Self) {
514        self.0 = self.0.checked_mul(rhs.0).unwrap();
515    }
516}
517forward_ref_op_assign!(impl MulAssign, mul_assign for Uint512, Uint512);
518
519impl Shr<u32> for Uint512 {
520    type Output = Self;
521
522    fn shr(self, rhs: u32) -> Self::Output {
523        self.checked_shr(rhs).unwrap_or_else(|_| {
524            panic!(
525                "right shift error: {rhs} is larger or equal than the number of bits in Uint512",
526            )
527        })
528    }
529}
530
531impl<'a> Shr<&'a u32> for Uint512 {
532    type Output = Self;
533
534    fn shr(self, rhs: &'a u32) -> Self::Output {
535        Shr::<u32>::shr(self, *rhs)
536    }
537}
538
539impl Shl<u32> for Uint512 {
540    type Output = Self;
541
542    fn shl(self, rhs: u32) -> Self::Output {
543        self.checked_shl(rhs)
544            .expect("attempt to shift left with overflow")
545    }
546}
547
548impl<'a> Shl<&'a u32> for Uint512 {
549    type Output = Self;
550
551    fn shl(self, rhs: &'a u32) -> Self::Output {
552        self.shl(*rhs)
553    }
554}
555
556impl AddAssign<Uint512> for Uint512 {
557    fn add_assign(&mut self, rhs: Uint512) {
558        self.0 = self.0.checked_add(rhs.0).unwrap();
559    }
560}
561
562impl<'a> AddAssign<&'a Uint512> for Uint512 {
563    fn add_assign(&mut self, rhs: &'a Uint512) {
564        self.0 = self.0.checked_add(rhs.0).unwrap();
565    }
566}
567
568impl DivAssign<Uint512> for Uint512 {
569    fn div_assign(&mut self, rhs: Self) {
570        self.0 = self.0.checked_div(rhs.0).unwrap();
571    }
572}
573
574impl<'a> DivAssign<&'a Uint512> for Uint512 {
575    fn div_assign(&mut self, rhs: &'a Uint512) {
576        self.0 = self.0.checked_div(rhs.0).unwrap();
577    }
578}
579
580impl ShrAssign<u32> for Uint512 {
581    fn shr_assign(&mut self, rhs: u32) {
582        *self = Shr::<u32>::shr(*self, rhs);
583    }
584}
585
586impl<'a> ShrAssign<&'a u32> for Uint512 {
587    fn shr_assign(&mut self, rhs: &'a u32) {
588        *self = Shr::<u32>::shr(*self, *rhs);
589    }
590}
591
592impl ShlAssign<u32> for Uint512 {
593    fn shl_assign(&mut self, rhs: u32) {
594        *self = self.shl(rhs);
595    }
596}
597
598impl<'a> ShlAssign<&'a u32> for Uint512 {
599    fn shl_assign(&mut self, rhs: &'a u32) {
600        *self = self.shl(*rhs);
601    }
602}
603
604impl<A> core::iter::Sum<A> for Uint512
605where
606    Self: Add<A, Output = Self>,
607{
608    fn sum<I: Iterator<Item = A>>(iter: I) -> Self {
609        iter.fold(Self::zero(), Add::add)
610    }
611}
612
613#[cfg(test)]
614mod tests {
615    use super::*;
616    use crate::math::conversion::test_try_from_int_to_uint;
617
618    #[test]
619    fn size_of_works() {
620        assert_eq!(core::mem::size_of::<Uint512>(), 64);
621    }
622
623    #[test]
624    fn uint512_new_works() {
625        let num = Uint512::new([1; 64]);
626        let a: [u8; 64] = num.to_be_bytes();
627        assert_eq!(a, [1; 64]);
628
629        let be_bytes = [
630            0u8, 222u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8,
631            0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8,
632            0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8,
633            0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 1u8, 2u8, 3u8,
634        ];
635        let num = Uint512::new(be_bytes);
636        let resulting_bytes: [u8; 64] = num.to_be_bytes();
637        assert_eq!(be_bytes, resulting_bytes);
638    }
639
640    #[test]
641    fn uint512_not_works() {
642        let num = Uint512::new([1; 64]);
643        let a = (!num).to_be_bytes();
644        assert_eq!(a, [254; 64]);
645
646        assert_eq!(!Uint512::MAX, Uint512::MIN);
647        assert_eq!(!Uint512::MIN, Uint512::MAX);
648    }
649
650    #[test]
651    fn uint512_zero_works() {
652        let zero = Uint512::zero();
653        assert_eq!(
654            zero.to_be_bytes(),
655            [
656                0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
657                0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
658                0, 0, 0, 0, 0, 0, 0, 0
659            ]
660        );
661    }
662
663    #[test]
664    fn uin512_one_works() {
665        let one = Uint512::one();
666        assert_eq!(
667            one.to_be_bytes(),
668            [
669                0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
670                0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
671                0, 0, 0, 0, 0, 0, 0, 1
672            ]
673        );
674    }
675
676    #[test]
677    fn uint512_endianness() {
678        let be_bytes = [
679            0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8,
680            0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8,
681            0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8,
682            0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 1u8, 2u8, 3u8,
683        ];
684        let le_bytes = [
685            3u8, 2u8, 1u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8,
686            0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8,
687            0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8,
688            0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8,
689        ];
690
691        // These should all be the same.
692        let num1 = Uint512::new(be_bytes);
693        let num2 = Uint512::from_be_bytes(be_bytes);
694        let num3 = Uint512::from_le_bytes(le_bytes);
695        assert_eq!(num1, Uint512::from(65536u32 + 512 + 3));
696        assert_eq!(num1, num2);
697        assert_eq!(num1, num3);
698    }
699
700    #[test]
701    fn uint512_convert_from() {
702        let a = Uint512::from(5u128);
703        assert_eq!(a.0, U512::from(5u32));
704
705        let a = Uint512::from(5u64);
706        assert_eq!(a.0, U512::from(5u32));
707
708        let a = Uint512::from(5u32);
709        assert_eq!(a.0, U512::from(5u32));
710
711        let a = Uint512::from(5u16);
712        assert_eq!(a.0, U512::from(5u32));
713
714        let a = Uint512::from(5u8);
715        assert_eq!(a.0, U512::from(5u32));
716
717        let result = Uint512::try_from("34567");
718        assert_eq!(
719            result.unwrap().0,
720            U512::from_str_radix("34567", 10).unwrap()
721        );
722
723        let result = Uint512::try_from("1.23");
724        assert!(result.is_err());
725    }
726
727    #[test]
728    fn uint512_try_from_signed_works() {
729        test_try_from_int_to_uint::<Int64, Uint512>("Int64", "Uint512");
730        test_try_from_int_to_uint::<Int128, Uint512>("Int128", "Uint512");
731        test_try_from_int_to_uint::<Int256, Uint512>("Int256", "Uint512");
732        test_try_from_int_to_uint::<Int512, Uint512>("Int512", "Uint512");
733    }
734
735    #[test]
736    fn uint512_try_into() {
737        assert!(Uint64::try_from(Uint512::MAX).is_err());
738        assert!(Uint128::try_from(Uint512::MAX).is_err());
739        assert!(Uint256::try_from(Uint512::MAX).is_err());
740
741        assert_eq!(Uint64::try_from(Uint512::zero()), Ok(Uint64::zero()));
742        assert_eq!(Uint128::try_from(Uint512::zero()), Ok(Uint128::zero()));
743        assert_eq!(Uint256::try_from(Uint512::zero()), Ok(Uint256::zero()));
744
745        assert_eq!(
746            Uint64::try_from(Uint512::from(42u64)),
747            Ok(Uint64::from(42u64))
748        );
749        assert_eq!(
750            Uint128::try_from(Uint512::from(42u128)),
751            Ok(Uint128::from(42u128))
752        );
753        assert_eq!(
754            Uint256::try_from(Uint512::from(42u128)),
755            Ok(Uint256::from(42u128))
756        );
757    }
758
759    #[test]
760    fn uint512_convert_to_uint128() {
761        let source = Uint512::from(42u128);
762        let target = Uint128::try_from(source);
763        assert_eq!(target, Ok(Uint128::new(42u128)));
764
765        let source = Uint512::MAX;
766        let target = Uint128::try_from(source);
767        assert_eq!(
768            target,
769            Err(ConversionOverflowError::new("Uint512", "Uint128"))
770        );
771    }
772
773    #[test]
774    fn uint512_from_uint256() {
775        assert_eq!(
776            Uint512::from_uint256(Uint256::from_str("123").unwrap()),
777            Uint512::from_str("123").unwrap()
778        );
779
780        assert_eq!(
781            Uint512::from_uint256(Uint256::from_str("9785746283745").unwrap()),
782            Uint512::from_str("9785746283745").unwrap()
783        );
784
785        assert_eq!(
786            Uint512::from_uint256(
787                Uint256::from_str(
788                    "97857462837575757832978493758398593853985452378423874623874628736482736487236"
789                )
790                .unwrap()
791            ),
792            Uint512::from_str(
793                "97857462837575757832978493758398593853985452378423874623874628736482736487236"
794            )
795            .unwrap()
796        );
797    }
798
799    #[test]
800    fn uint512_implements_display() {
801        let a = Uint512::from(12345u32);
802        assert_eq!(format!("Embedded: {a}"), "Embedded: 12345");
803        assert_eq!(a.to_string(), "12345");
804
805        let a = Uint512::zero();
806        assert_eq!(format!("Embedded: {a}"), "Embedded: 0");
807        assert_eq!(a.to_string(), "0");
808    }
809
810    #[test]
811    fn uint512_display_padding_works() {
812        // width > natural representation
813        let a = Uint512::from(123u64);
814        assert_eq!(format!("Embedded: {a:05}"), "Embedded: 00123");
815
816        // width < natural representation
817        let a = Uint512::from(123u64);
818        assert_eq!(format!("Embedded: {a:02}"), "Embedded: 123");
819    }
820
821    #[test]
822    fn uint512_to_be_bytes_works() {
823        assert_eq!(
824            Uint512::zero().to_be_bytes(),
825            [
826                0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
827                0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
828                0, 0, 0, 0, 0, 0, 0, 0,
829            ]
830        );
831        assert_eq!(
832            Uint512::MAX.to_be_bytes(),
833            [
834                0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
835                0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
836                0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
837                0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
838                0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
839            ]
840        );
841        assert_eq!(
842            Uint512::from(1u128).to_be_bytes(),
843            [
844                0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
845                0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
846                0, 0, 0, 0, 0, 0, 0, 1
847            ]
848        );
849        // Python: `[b for b in (240282366920938463463374607431768124608).to_bytes(64, "big")]`
850        assert_eq!(
851            Uint512::from(240282366920938463463374607431768124608u128).to_be_bytes(),
852            [
853                0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
854                0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 180, 196, 179, 87, 165,
855                121, 59, 133, 246, 117, 221, 191, 255, 254, 172, 192
856            ]
857        );
858        assert_eq!(
859            Uint512::from_be_bytes([
860                17, 4, 23, 32, 87, 67, 123, 200, 58, 91, 0, 38, 33, 21, 67, 78, 87, 76, 65, 54,
861                211, 201, 192, 7, 42, 233, 2, 240, 200, 115, 150, 240, 218, 88, 106, 45, 208, 134,
862                238, 119, 85, 22, 14, 88, 166, 195, 154, 73, 64, 10, 44, 59, 13, 22, 47, 12, 99, 8,
863                252, 96, 230, 187, 38, 29
864            ])
865            .to_be_bytes(),
866            [
867                17, 4, 23, 32, 87, 67, 123, 200, 58, 91, 0, 38, 33, 21, 67, 78, 87, 76, 65, 54,
868                211, 201, 192, 7, 42, 233, 2, 240, 200, 115, 150, 240, 218, 88, 106, 45, 208, 134,
869                238, 119, 85, 22, 14, 88, 166, 195, 154, 73, 64, 10, 44, 59, 13, 22, 47, 12, 99, 8,
870                252, 96, 230, 187, 38, 29
871            ]
872        );
873    }
874
875    #[test]
876    fn uint512_to_le_bytes_works() {
877        assert_eq!(
878            Uint512::zero().to_le_bytes(),
879            [
880                0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
881                0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
882                0, 0, 0, 0, 0, 0, 0, 0
883            ]
884        );
885        assert_eq!(
886            Uint512::MAX.to_le_bytes(),
887            [
888                0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
889                0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
890                0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
891                0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
892                0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff
893            ]
894        );
895        assert_eq!(
896            Uint512::from(1u128).to_le_bytes(),
897            [
898                1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
899                0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
900                0, 0, 0, 0, 0, 0, 0, 0
901            ]
902        );
903        // Python: `[b for b in (240282366920938463463374607431768124608).to_bytes(64, "little")]`
904        assert_eq!(
905            Uint512::from(240282366920938463463374607431768124608u128).to_le_bytes(),
906            [
907                192, 172, 254, 255, 191, 221, 117, 246, 133, 59, 121, 165, 87, 179, 196, 180, 0, 0,
908                0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
909                0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
910            ]
911        );
912        assert_eq!(
913            Uint512::from_be_bytes([
914                17, 4, 23, 32, 87, 67, 123, 200, 58, 91, 0, 38, 33, 21, 67, 78, 87, 76, 65, 54,
915                211, 201, 192, 7, 42, 233, 2, 240, 200, 115, 150, 240, 218, 88, 106, 45, 208, 134,
916                238, 119, 85, 22, 14, 88, 166, 195, 154, 73, 64, 10, 44, 59, 13, 22, 47, 12, 99, 8,
917                252, 96, 230, 187, 38, 29
918            ])
919            .to_le_bytes(),
920            [
921                29, 38, 187, 230, 96, 252, 8, 99, 12, 47, 22, 13, 59, 44, 10, 64, 73, 154, 195,
922                166, 88, 14, 22, 85, 119, 238, 134, 208, 45, 106, 88, 218, 240, 150, 115, 200, 240,
923                2, 233, 42, 7, 192, 201, 211, 54, 65, 76, 87, 78, 67, 21, 33, 38, 0, 91, 58, 200,
924                123, 67, 87, 32, 23, 4, 17
925            ]
926        );
927    }
928
929    #[test]
930    fn uint512_is_zero_works() {
931        assert!(Uint512::zero().is_zero());
932        assert!(Uint512(U512::from(0u32)).is_zero());
933
934        assert!(!Uint512::from(1u32).is_zero());
935        assert!(!Uint512::from(123u32).is_zero());
936    }
937
938    #[test]
939    fn uint512_wrapping_methods() {
940        // wrapping_add
941        assert_eq!(
942            Uint512::from(2u32).wrapping_add(Uint512::from(2u32)),
943            Uint512::from(4u32)
944        ); // non-wrapping
945        assert_eq!(
946            Uint512::MAX.wrapping_add(Uint512::from(1u32)),
947            Uint512::from(0u32)
948        ); // wrapping
949
950        // wrapping_sub
951        assert_eq!(
952            Uint512::from(7u32).wrapping_sub(Uint512::from(5u32)),
953            Uint512::from(2u32)
954        ); // non-wrapping
955        assert_eq!(
956            Uint512::from(0u32).wrapping_sub(Uint512::from(1u32)),
957            Uint512::MAX
958        ); // wrapping
959
960        // wrapping_mul
961        assert_eq!(
962            Uint512::from(3u32).wrapping_mul(Uint512::from(2u32)),
963            Uint512::from(6u32)
964        ); // non-wrapping
965        assert_eq!(
966            Uint512::MAX.wrapping_mul(Uint512::from(2u32)),
967            Uint512::MAX - Uint512::one()
968        ); // wrapping
969
970        // wrapping_pow
971        assert_eq!(Uint512::from(2u32).wrapping_pow(3), Uint512::from(8u32)); // non-wrapping
972        assert_eq!(Uint512::MAX.wrapping_pow(2), Uint512::from(1u32)); // wrapping
973    }
974
975    #[test]
976    fn uint512_json() {
977        let orig = Uint512::from(1234567890987654321u128);
978        let serialized = serde_json::to_vec(&orig).unwrap();
979        assert_eq!(serialized.as_slice(), b"\"1234567890987654321\"");
980        let parsed: Uint512 = serde_json::from_slice(&serialized).unwrap();
981        assert_eq!(parsed, orig);
982    }
983
984    #[test]
985    fn uint512_compare() {
986        let a = Uint512::from(12345u32);
987        let b = Uint512::from(23456u32);
988
989        assert!(a < b);
990        assert!(b > a);
991        assert_eq!(a, Uint512::from(12345u32));
992    }
993
994    #[test]
995    #[allow(clippy::op_ref)]
996    fn uint512_math() {
997        let a = Uint512::from(12345u32);
998        let b = Uint512::from(23456u32);
999
1000        // test += with owned and reference right hand side
1001        let mut c = Uint512::from(300000u32);
1002        c += b;
1003        assert_eq!(c, Uint512::from(323456u32));
1004        let mut d = Uint512::from(300000u32);
1005        d += &b;
1006        assert_eq!(d, Uint512::from(323456u32));
1007
1008        // test -= with owned and reference right hand side
1009        let mut c = Uint512::from(300000u32);
1010        c -= b;
1011        assert_eq!(c, Uint512::from(276544u32));
1012        let mut d = Uint512::from(300000u32);
1013        d -= &b;
1014        assert_eq!(d, Uint512::from(276544u32));
1015
1016        // error result on underflow (- would produce negative result)
1017        let underflow_result = a.checked_sub(b);
1018        let OverflowError { operation } = underflow_result.unwrap_err();
1019        assert_eq!(operation, OverflowOperation::Sub);
1020    }
1021
1022    #[test]
1023    #[allow(clippy::op_ref)]
1024    fn uint512_add_works() {
1025        assert_eq!(
1026            Uint512::from(2u32) + Uint512::from(1u32),
1027            Uint512::from(3u32)
1028        );
1029        assert_eq!(
1030            Uint512::from(2u32) + Uint512::from(0u32),
1031            Uint512::from(2u32)
1032        );
1033
1034        // works for refs
1035        let a = Uint512::from(10u32);
1036        let b = Uint512::from(3u32);
1037        let expected = Uint512::from(13u32);
1038        assert_eq!(a + b, expected);
1039        assert_eq!(a + &b, expected);
1040        assert_eq!(&a + b, expected);
1041        assert_eq!(&a + &b, expected);
1042    }
1043
1044    #[test]
1045    #[should_panic(expected = "attempt to add with overflow")]
1046    fn uint512_add_overflow_panics() {
1047        let max = Uint512::MAX;
1048        let _ = max + Uint512::from(12u32);
1049    }
1050
1051    #[test]
1052    #[allow(clippy::op_ref)]
1053    fn uint512_sub_works() {
1054        assert_eq!(
1055            Uint512::from(2u32) - Uint512::from(1u32),
1056            Uint512::from(1u32)
1057        );
1058        assert_eq!(
1059            Uint512::from(2u32) - Uint512::from(0u32),
1060            Uint512::from(2u32)
1061        );
1062        assert_eq!(
1063            Uint512::from(2u32) - Uint512::from(2u32),
1064            Uint512::from(0u32)
1065        );
1066
1067        // works for refs
1068        let a = Uint512::from(10u32);
1069        let b = Uint512::from(3u32);
1070        let expected = Uint512::from(7u32);
1071        assert_eq!(a - b, expected);
1072        assert_eq!(a - &b, expected);
1073        assert_eq!(&a - b, expected);
1074        assert_eq!(&a - &b, expected);
1075    }
1076
1077    #[test]
1078    #[should_panic]
1079    fn uint512_sub_overflow_panics() {
1080        let _ = Uint512::from(1u32) - Uint512::from(2u32);
1081    }
1082
1083    #[test]
1084    fn uint512_sub_assign_works() {
1085        let mut a = Uint512::from(14u32);
1086        a -= Uint512::from(2u32);
1087        assert_eq!(a, Uint512::from(12u32));
1088
1089        // works for refs
1090        let mut a = Uint512::from(10u32);
1091        let b = Uint512::from(3u32);
1092        let expected = Uint512::from(7u32);
1093        a -= &b;
1094        assert_eq!(a, expected);
1095    }
1096
1097    #[test]
1098    #[allow(clippy::op_ref)]
1099    fn uint512_mul_works() {
1100        assert_eq!(
1101            Uint512::from(2u32) * Uint512::from(3u32),
1102            Uint512::from(6u32)
1103        );
1104        assert_eq!(Uint512::from(2u32) * Uint512::zero(), Uint512::zero());
1105
1106        // works for refs
1107        let a = Uint512::from(11u32);
1108        let b = Uint512::from(3u32);
1109        let expected = Uint512::from(33u32);
1110        assert_eq!(a * b, expected);
1111        assert_eq!(a * &b, expected);
1112        assert_eq!(&a * b, expected);
1113        assert_eq!(&a * &b, expected);
1114    }
1115
1116    #[test]
1117    fn uint512_mul_assign_works() {
1118        let mut a = Uint512::from(14u32);
1119        a *= Uint512::from(2u32);
1120        assert_eq!(a, Uint512::from(28u32));
1121
1122        // works for refs
1123        let mut a = Uint512::from(10u32);
1124        let b = Uint512::from(3u32);
1125        a *= &b;
1126        assert_eq!(a, Uint512::from(30u32));
1127    }
1128
1129    #[test]
1130    fn uint512_pow_works() {
1131        assert_eq!(Uint512::from(2u32).pow(2), Uint512::from(4u32));
1132        assert_eq!(Uint512::from(2u32).pow(10), Uint512::from(1024u32));
1133    }
1134
1135    #[test]
1136    #[should_panic]
1137    fn uint512_pow_overflow_panics() {
1138        _ = Uint512::MAX.pow(2u32);
1139    }
1140
1141    #[test]
1142    fn uint512_shr_works() {
1143        let original = Uint512::new([
1144            0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8,
1145            0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8,
1146            0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8,
1147            0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 2u8, 0u8, 4u8, 2u8,
1148        ]);
1149
1150        let shifted = Uint512::new([
1151            0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8,
1152            0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8,
1153            0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8,
1154            0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 128u8, 1u8, 0u8,
1155        ]);
1156
1157        assert_eq!(original >> 2u32, shifted);
1158    }
1159
1160    #[test]
1161    #[should_panic]
1162    fn uint512_shr_overflow_panics() {
1163        let _ = Uint512::from(1u32) >> 512u32;
1164    }
1165
1166    #[test]
1167    fn uint512_shl_works() {
1168        let original = Uint512::new([
1169            64u8, 128u8, 1u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8,
1170            0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8,
1171            0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8,
1172            0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8,
1173        ]);
1174
1175        let shifted = Uint512::new([
1176            2u8, 0u8, 4u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8,
1177            0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8,
1178            0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8,
1179            0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8,
1180        ]);
1181
1182        assert_eq!(original << 2u32, shifted);
1183    }
1184
1185    #[test]
1186    #[should_panic]
1187    fn uint512_shl_overflow_panics() {
1188        let _ = Uint512::from(1u32) << 512u32;
1189    }
1190
1191    #[test]
1192    fn sum_works() {
1193        let nums = vec![
1194            Uint512::from(17u32),
1195            Uint512::from(123u32),
1196            Uint512::from(540u32),
1197            Uint512::from(82u32),
1198        ];
1199        let expected = Uint512::from(762u32);
1200
1201        let sum_as_ref: Uint512 = nums.iter().sum();
1202        assert_eq!(expected, sum_as_ref);
1203
1204        let sum_as_owned: Uint512 = nums.into_iter().sum();
1205        assert_eq!(expected, sum_as_owned);
1206    }
1207
1208    #[test]
1209    fn uint512_methods() {
1210        // checked_*
1211        assert!(matches!(
1212            Uint512::MAX.checked_add(Uint512::from(1u32)),
1213            Err(OverflowError { .. })
1214        ));
1215        assert_eq!(
1216            Uint512::from(1u32).checked_add(Uint512::from(1u32)),
1217            Ok(Uint512::from(2u32)),
1218        );
1219        assert!(matches!(
1220            Uint512::from(0u32).checked_sub(Uint512::from(1u32)),
1221            Err(OverflowError { .. })
1222        ));
1223        assert_eq!(
1224            Uint512::from(2u32).checked_sub(Uint512::from(1u32)),
1225            Ok(Uint512::from(1u32)),
1226        );
1227        assert!(matches!(
1228            Uint512::MAX.checked_mul(Uint512::from(2u32)),
1229            Err(OverflowError { .. })
1230        ));
1231        assert_eq!(
1232            Uint512::from(2u32).checked_mul(Uint512::from(2u32)),
1233            Ok(Uint512::from(4u32)),
1234        );
1235        assert!(matches!(
1236            Uint512::MAX.checked_pow(2u32),
1237            Err(OverflowError { .. })
1238        ));
1239        assert_eq!(
1240            Uint512::from(2u32).checked_pow(3u32),
1241            Ok(Uint512::from(8u32)),
1242        );
1243        assert!(matches!(
1244            Uint512::MAX.checked_div(Uint512::from(0u32)),
1245            Err(DivideByZeroError { .. })
1246        ));
1247        assert_eq!(
1248            Uint512::from(6u32).checked_div(Uint512::from(2u32)),
1249            Ok(Uint512::from(3u32)),
1250        );
1251        assert!(matches!(
1252            Uint512::MAX.checked_div_euclid(Uint512::from(0u32)),
1253            Err(DivideByZeroError { .. })
1254        ));
1255        assert_eq!(
1256            Uint512::from(6u32).checked_div_euclid(Uint512::from(2u32)),
1257            Ok(Uint512::from(3u32)),
1258        );
1259        assert_eq!(
1260            Uint512::from(7u32).checked_div_euclid(Uint512::from(2u32)),
1261            Ok(Uint512::from(3u32)),
1262        );
1263        assert!(matches!(
1264            Uint512::MAX.checked_rem(Uint512::from(0u32)),
1265            Err(DivideByZeroError { .. })
1266        ));
1267
1268        // saturating_*
1269        assert_eq!(
1270            Uint512::MAX.saturating_add(Uint512::from(1u32)),
1271            Uint512::MAX
1272        );
1273        assert_eq!(
1274            Uint512::from(0u32).saturating_sub(Uint512::from(1u32)),
1275            Uint512::from(0u32)
1276        );
1277        assert_eq!(
1278            Uint512::MAX.saturating_mul(Uint512::from(2u32)),
1279            Uint512::MAX
1280        );
1281        assert_eq!(
1282            Uint512::from(4u32).saturating_pow(2u32),
1283            Uint512::from(16u32)
1284        );
1285        assert_eq!(Uint512::MAX.saturating_pow(2u32), Uint512::MAX);
1286    }
1287
1288    #[test]
1289    #[allow(clippy::op_ref)]
1290    fn uint512_implements_rem() {
1291        let a = Uint512::from(10u32);
1292        assert_eq!(a % Uint512::from(10u32), Uint512::zero());
1293        assert_eq!(a % Uint512::from(2u32), Uint512::zero());
1294        assert_eq!(a % Uint512::from(1u32), Uint512::zero());
1295        assert_eq!(a % Uint512::from(3u32), Uint512::from(1u32));
1296        assert_eq!(a % Uint512::from(4u32), Uint512::from(2u32));
1297
1298        // works for refs
1299        let a = Uint512::from(10u32);
1300        let b = Uint512::from(3u32);
1301        let expected = Uint512::from(1u32);
1302        assert_eq!(a % b, expected);
1303        assert_eq!(a % &b, expected);
1304        assert_eq!(&a % b, expected);
1305        assert_eq!(&a % &b, expected);
1306    }
1307
1308    #[test]
1309    #[should_panic(expected = "divisor of zero")]
1310    fn uint512_rem_panics_for_zero() {
1311        let _ = Uint512::from(10u32) % Uint512::zero();
1312    }
1313
1314    #[test]
1315    #[allow(clippy::op_ref)]
1316    fn uint512_rem_works() {
1317        assert_eq!(
1318            Uint512::from(12u32) % Uint512::from(10u32),
1319            Uint512::from(2u32)
1320        );
1321        assert_eq!(Uint512::from(50u32) % Uint512::from(5u32), Uint512::zero());
1322
1323        // works for refs
1324        let a = Uint512::from(42u32);
1325        let b = Uint512::from(5u32);
1326        let expected = Uint512::from(2u32);
1327        assert_eq!(a % b, expected);
1328        assert_eq!(a % &b, expected);
1329        assert_eq!(&a % b, expected);
1330        assert_eq!(&a % &b, expected);
1331    }
1332
1333    #[test]
1334    fn uint512_rem_assign_works() {
1335        let mut a = Uint512::from(30u32);
1336        a %= Uint512::from(4u32);
1337        assert_eq!(a, Uint512::from(2u32));
1338
1339        // works for refs
1340        let mut a = Uint512::from(25u32);
1341        let b = Uint512::from(6u32);
1342        a %= &b;
1343        assert_eq!(a, Uint512::from(1u32));
1344    }
1345
1346    #[test]
1347    fn uint512_strict_add_works() {
1348        let a = Uint512::from(5u32);
1349        let b = Uint512::from(3u32);
1350        assert_eq!(a.strict_add(b), Uint512::from(8u32));
1351        assert_eq!(b.strict_add(a), Uint512::from(8u32));
1352    }
1353
1354    #[test]
1355    #[should_panic(expected = "attempt to add with overflow")]
1356    fn uint512_strict_add_panics_on_overflow() {
1357        let a = Uint512::MAX;
1358        let b = Uint512::ONE;
1359        let _ = a.strict_add(b);
1360    }
1361
1362    #[test]
1363    fn uint512_strict_sub_works() {
1364        let a = Uint512::from(5u32);
1365        let b = Uint512::from(3u32);
1366        assert_eq!(a.strict_sub(b), Uint512::from(2u32));
1367    }
1368
1369    #[test]
1370    #[should_panic(expected = "attempt to subtract with overflow")]
1371    fn uint512_strict_sub_panics_on_overflow() {
1372        let a = Uint512::ZERO;
1373        let b = Uint512::ONE;
1374        let _ = a.strict_sub(b);
1375    }
1376
1377    #[test]
1378    fn uint512_abs_diff_works() {
1379        let a = Uint512::from(42u32);
1380        let b = Uint512::from(5u32);
1381        let expected = Uint512::from(37u32);
1382        assert_eq!(a.abs_diff(b), expected);
1383        assert_eq!(b.abs_diff(a), expected);
1384    }
1385
1386    #[test]
1387    fn uint512_partial_eq() {
1388        let test_cases = [(1, 1, true), (42, 42, true), (42, 24, false), (0, 0, true)]
1389            .into_iter()
1390            .map(|(lhs, rhs, expected): (u64, u64, bool)| {
1391                (Uint512::from(lhs), Uint512::from(rhs), expected)
1392            });
1393
1394        #[allow(clippy::op_ref)]
1395        for (lhs, rhs, expected) in test_cases {
1396            assert_eq!(lhs == rhs, expected);
1397            assert_eq!(&lhs == rhs, expected);
1398            assert_eq!(lhs == &rhs, expected);
1399            assert_eq!(&lhs == &rhs, expected);
1400        }
1401    }
1402}