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