cosmwasm_std/math/
uint512.rs

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