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