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