bobcat_maths/
lib.rs

1#![cfg_attr(not(feature = "std"), no_std)]
2
3use core::{
4    cmp::{Eq, Ordering},
5    ops::{Add, Deref, DerefMut, Div, Index, Mul, Rem, Sub},
6};
7
8use num_traits::{One, Zero};
9
10#[cfg(feature = "borsh")]
11use borsh::{BorshDeserialize, BorshSerialize};
12
13#[cfg(feature = "alloc")]
14extern crate alloc;
15
16#[cfg(feature = "std")]
17use core::fmt::{Display, Formatter};
18
19pub type Address = [u8; 20];
20
21#[link(wasm_import_module = "vm_hooks")]
22#[cfg(not(feature = "alloy-enabled"))]
23unsafe extern "C" {
24    fn math_div(x: *mut u8, y: *const u8);
25    fn math_mod(x: *mut u8, y: *const u8);
26    fn math_add_mod(a: *mut u8, b: *const u8, c: *const u8);
27    fn math_mul_mod(a: *mut u8, b: *const u8, c: *const u8);
28}
29
30#[cfg(feature = "alloy-enabled")]
31mod alloy {
32    use core::ptr::copy_nonoverlapping;
33
34    pub(crate) use alloy_primitives::U256;
35
36    #[cfg(test)]
37    pub(crate) use alloy_primitives::I256;
38
39    pub(crate) unsafe fn math_div(out: *mut u8, y: *const u8) {
40        unsafe {
41            let x = U256::from_be_slice(&*(out as *const [u8; 32]));
42            let y = U256::from_be_slice(&*(y as *const [u8; 32]));
43            let z = if y.is_zero() {
44                // TODO: I think the node returns 0 when this is the case.
45                U256::ZERO
46            } else {
47                x / y
48            };
49            copy_nonoverlapping(z.to_be_bytes::<32>().as_ptr(), out, 32);
50        }
51    }
52
53    pub(crate) unsafe fn math_mod(out: *mut u8, y: *const u8) {
54        unsafe {
55            let x = U256::from_be_slice(&*(out as *const [u8; 32]));
56            let y = U256::from_be_slice(&*(y as *const [u8; 32]));
57            let z = x % y;
58            copy_nonoverlapping(z.to_be_bytes::<32>().as_ptr(), out, 32);
59        }
60    }
61
62    pub(crate) unsafe fn math_add_mod(a: *mut u8, b: *const u8, c: *const u8) {
63        unsafe {
64            let x = U256::from_be_slice(&*(a as *const [u8; 32]));
65            let y = U256::from_be_slice(&*(b as *const [u8; 32]));
66            let z = U256::from_be_slice(&*(c as *const [u8; 32]));
67            let x = x.add_mod(y, z);
68            copy_nonoverlapping(x.to_be_bytes::<32>().as_ptr(), a, 32);
69        }
70    }
71
72    pub(crate) unsafe fn math_mul_mod(a: *mut u8, b: *const u8, c: *const u8) {
73        unsafe {
74            let x = U256::from_be_slice(&*(a as *const [u8; 32]));
75            let y = U256::from_be_slice(&*(b as *const [u8; 32]));
76            let z = U256::from_be_slice(&*(c as *const [u8; 32]));
77            let x = x.mul_mod(y, z);
78            copy_nonoverlapping(x.to_be_bytes::<32>().as_ptr(), a, 32);
79        }
80    }
81}
82
83#[cfg(feature = "alloy-enabled")]
84use alloy::*;
85
86#[derive(Copy, Clone, Debug, PartialEq, Hash)]
87#[cfg_attr(feature = "proptest", derive(proptest_derive::Arbitrary))]
88#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))]
89#[cfg_attr(feature = "borsh", derive(BorshDeserialize, BorshSerialize))]
90#[repr(transparent)]
91pub struct U(pub [u8; 32]);
92
93#[derive(Copy, Clone, Debug, PartialEq, Hash)]
94#[cfg_attr(feature = "proptest", derive(proptest_derive::Arbitrary))]
95#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))]
96#[cfg_attr(feature = "borsh", derive(BorshDeserialize, BorshSerialize))]
97#[repr(transparent)]
98pub struct I(pub [u8; 32]);
99
100pub fn wrapping_div(x: &U, y: &U) -> U {
101    let mut b = *x;
102    unsafe { math_div(b.as_mut_ptr(), y.as_ptr()) }
103    b
104}
105
106#[cfg_attr(test, mutants::skip)]
107pub fn checked_div(x: &U, y: &U) -> Option<U> {
108    if y.is_zero() {
109        None
110    } else {
111        Some(wrapping_div(x, y))
112    }
113}
114
115pub fn modd(x: &U, y: &U) -> U {
116    let mut b = *x;
117    unsafe { math_mod(b.as_mut_ptr(), y.as_ptr()) }
118    b
119}
120
121pub const fn wrapping_add(x: &U, y: &U) -> U {
122    let mut r = [0u8; 32];
123    let mut c = 0;
124    let mut i = 31;
125    loop {
126        let s = x.0[i] as u16 + y.0[i] as u16 + c;
127        r[i] = s as u8;
128        c = s >> 8;
129        if i == 0 {
130            break;
131        }
132        i -= 1;
133    }
134    U(r)
135}
136
137#[cfg_attr(test, mutants::skip)]
138pub fn checked_add(x: &U, y: &U) -> Option<U> {
139    if x > &(U::MAX - *y) {
140        None
141    } else {
142        let z = x.add_mod(y, &U::MAX);
143        if z.is_zero() && (x.is_some() || y.is_some()) {
144            Some(U::MAX)
145        } else {
146            Some(z)
147        }
148    }
149}
150
151pub const fn wrapping_sub(x: &U, y: &U) -> U {
152    let mut neg_y = y.0;
153    let mut i = 0;
154    while i < 32 {
155        neg_y[i] = !neg_y[i];
156        i += 1;
157    }
158    let mut c = 1u16;
159    let mut i = 31;
160    loop {
161        let sum = neg_y[i] as u16 + c;
162        neg_y[i] = sum as u8;
163        c = sum >> 8;
164        if i == 0 {
165            break;
166        }
167        i -= 1;
168    }
169    wrapping_add(x, &U(neg_y))
170}
171
172#[cfg_attr(test, mutants::skip)]
173pub fn checked_sub(x: &U, y: &U) -> Option<U> {
174    if x < y {
175        None
176    } else {
177        Some(wrapping_sub(x, y))
178    }
179}
180
181pub const fn wrapping_mul(x: &U, y: &U) -> U {
182    let mut r = [0u8; 32];
183    let mut i = 0;
184    while i < 32 {
185        let mut c = 0u16;
186        let mut j = 0;
187        while j < 32 {
188            let i_r = i + j;
189            if i_r >= 32 {
190                break;
191            }
192            let r_idx = 31 - i_r;
193            let xi = x.0[31 - i] as u16;
194            let yj = y.0[31 - j] as u16;
195            let prod = xi * yj + r[r_idx] as u16 + c;
196            r[r_idx] = prod as u8;
197            c = prod >> 8;
198            j += 1;
199        }
200        if i + j < 32 {
201            let idx = 31 - (i + j);
202            r[idx] = r[idx] + c as u8;
203        }
204        i += 1;
205    }
206    U(r)
207}
208
209#[cfg_attr(test, mutants::skip)]
210pub fn checked_mul(x: &U, y: &U) -> Option<U> {
211    if x.is_zero() || y.is_zero() {
212        return Some(U::zero());
213    }
214    if x > &(U::MAX / *y) {
215        None
216    } else {
217        let z = x.mul_mod(y, &U::MAX);
218        if z.is_zero() {
219            Some(U::MAX)
220        } else {
221            Some(z)
222        }
223    }
224}
225
226impl Add for U {
227    type Output = U;
228
229    fn add(self, rhs: U) -> U {
230        cfg_if::cfg_if! {
231            if #[cfg(debug_assertions)] {
232                checked_add(&self, &rhs).expect("overflow when add")
233            } else {
234                wrapping_add(&self, &rhs)
235            }
236        }
237    }
238}
239
240impl Add for &U {
241    type Output = U;
242
243    fn add(self, rhs: &U) -> U {
244        cfg_if::cfg_if! {
245            if #[cfg(debug_assertions)] {
246                checked_add(self, rhs).expect("overflow when add")
247            } else {
248                wrapping_add(self, rhs)
249            }
250        }
251    }
252}
253
254impl Sub for U {
255    type Output = U;
256
257    fn sub(self, rhs: U) -> U {
258        cfg_if::cfg_if! {
259            if #[cfg(debug_assertions)] {
260                checked_sub(&self, &rhs).expect("overflow when sub")
261            } else {
262                wrapping_sub(&self, &rhs)
263            }
264        }
265    }
266}
267
268impl Sub for &U {
269    type Output = U;
270
271    fn sub(self, rhs: &U) -> U {
272        cfg_if::cfg_if! {
273            if #[cfg(debug_assertions)] {
274                checked_sub(self, rhs).expect("overflow when sub")
275            } else {
276                wrapping_sub(self, rhs)
277            }
278        }
279    }
280}
281
282impl Mul for U {
283    type Output = U;
284
285    fn mul(self, rhs: U) -> U {
286        cfg_if::cfg_if! {
287            if #[cfg(debug_assertions)] {
288                checked_mul(&self, &rhs).expect("overflow when mul")
289            } else {
290                wrapping_mul(&self, &rhs)
291            }
292        }
293    }
294}
295
296impl Mul for &U {
297    type Output = U;
298
299    fn mul(self, rhs: &U) -> U {
300        cfg_if::cfg_if! {
301            if #[cfg(debug_assertions)] {
302                checked_mul(self, rhs).expect("overflow when mul")
303            } else {
304                wrapping_mul(self, rhs)
305            }
306        }
307    }
308}
309
310impl Div for U {
311    type Output = U;
312
313    fn div(self, rhs: U) -> U {
314        cfg_if::cfg_if! {
315            if #[cfg(debug_assertions)] {
316                checked_div(&self, &rhs).expect("overflow when div")
317            } else {
318                wrapping_div(&self, &rhs)
319            }
320        }
321    }
322}
323
324impl Div for &U {
325    type Output = U;
326
327    fn div(self, rhs: &U) -> U {
328        cfg_if::cfg_if! {
329            if #[cfg(debug_assertions)] {
330                checked_div(self, rhs).expect("overflow when div")
331            } else {
332                wrapping_div(self, rhs)
333            }
334        }
335    }
336}
337
338impl Rem for U {
339    type Output = U;
340
341    fn rem(self, rhs: U) -> U {
342        modd(&self, &rhs)
343    }
344}
345
346impl Rem for &U {
347    type Output = U;
348
349    fn rem(self, rhs: &U) -> U {
350        modd(self, rhs)
351    }
352}
353
354impl Eq for U {}
355
356impl PartialOrd for U {
357    fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
358        Some(self.cmp(other))
359    }
360}
361
362impl Ord for U {
363    fn cmp(&self, other: &Self) -> Ordering {
364        self.0.cmp(&other.0)
365    }
366}
367
368impl U {
369    pub const ZERO: Self = U([0u8; 32]);
370
371    pub const MAX: Self = U([u8::MAX; 32]);
372
373    pub const ONE: Self = U([
374        0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
375        0, 1,
376    ]);
377
378    pub fn is_true(&self) -> bool {
379        self.0[31] == 1
380    }
381
382    pub fn is_zero(&self) -> bool {
383        *self == Self::ZERO
384    }
385
386    pub fn is_some(&self) -> bool {
387        !self.is_zero()
388    }
389
390    pub fn as_slice(&self) -> &[u8; 32] {
391        &self.0
392    }
393
394    pub fn wrapping_add(&self, y: &Self) -> U {
395        wrapping_add(self, y)
396    }
397
398    pub fn checked_add(&self, y: &Self) -> Option<Self> {
399        checked_add(self, y)
400    }
401
402    pub fn wrapping_sub(&self, y: &Self) -> U {
403        wrapping_sub(self, y)
404    }
405
406    pub fn checked_sub(&self, y: &Self) -> Option<Self> {
407        checked_sub(self, y)
408    }
409
410    pub fn wrapping_mul(&self, y: &Self) -> U {
411        wrapping_mul(self, y)
412    }
413
414    pub fn checked_mul(&self, y: &Self) -> Option<Self> {
415        checked_mul(self, y)
416    }
417
418    pub fn wrapping_div(&self, y: &Self) -> U {
419        wrapping_div(self, y)
420    }
421
422    pub fn checked_div(&self, y: &Self) -> Option<Self> {
423        checked_div(self, y)
424    }
425
426    pub fn mul_mod(&self, y: &Self, z: &Self) -> Self {
427        let mut b = self.0;
428        unsafe { math_mul_mod(b.as_mut_ptr(), y.as_ptr(), z.as_ptr()) }
429        Self(b)
430    }
431
432    pub fn add_mod(&self, y: &Self, z: &Self) -> Self {
433        let mut b = self.0;
434        unsafe { math_add_mod(b.as_mut_ptr(), y.as_ptr(), z.as_ptr()) }
435        Self(b)
436    }
437
438    pub fn widening_mul(&self, y: &U) -> (U, U) {
439        let shift_128 = &U([
440            0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
441            0, 0, 0,
442        ]);
443        let x_hi = self / shift_128;
444        let x_lo = self % shift_128;
445        let y_hi = y / shift_128;
446        let y_lo = y % shift_128;
447        let t0 = x_lo.mul_mod(&y_lo, &U::MAX);
448        let t1 = x_hi.mul_mod(&y_lo, &U::MAX);
449        let t2 = x_lo.mul_mod(&y_hi, &U::MAX);
450        let t3 = x_hi.mul_mod(&y_hi, &U::MAX);
451        let t0_hi = &t0 / shift_128;
452        let t0_lo = &t0 % shift_128;
453        let t1_hi = &t1 / shift_128;
454        let t1_lo = &t1 % shift_128;
455        let t2_hi = &t2 / shift_128;
456        let t2_lo = &t2 % shift_128;
457        let mid = (t0_hi + t1_lo) + t2_lo;
458        let mid_hi = &mid / shift_128;
459        let mid_lo = &mid % shift_128;
460        let mid_lo_shifted = mid_lo.mul_mod(shift_128, &U::MAX);
461        let out_low = t0_lo + mid_lo_shifted;
462        let out_high = t3 + t1_hi + t2_hi + mid_hi;
463        (out_high, out_low)
464    }
465
466    pub fn mul_div(&self, _y: &U, _denom: &U) -> Option<(U, bool)> {
467        todo!()
468    }
469
470    pub fn mul_div_round_up(&self, y: &U, denom_and_rem: &U) -> Option<U> {
471        let (x, y) = self.mul_div(y, denom_and_rem)?;
472        Some(if y { x + U::ONE } else { x })
473    }
474}
475
476#[cfg(feature = "std")]
477impl Display for U {
478    fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
479        let mut result = vec![0u8];
480        for &byte in &self.0 {
481            let mut carry = byte as u32;
482            for digit in result.iter_mut() {
483                let temp = (*digit as u32) * 256 + carry;
484                *digit = (temp % 10) as u8;
485                carry = temp / 10;
486            }
487            while carry > 0 {
488                result.push((carry % 10) as u8);
489                carry /= 10;
490            }
491        }
492        if result.iter().all(|&d| d == 0) {
493            return write!(f, "0");
494        }
495        write!(
496            f,
497            "{}",
498            result
499                .iter()
500                .rev()
501                .skip_while(|&&d| d == 0)
502                .map(|&d| (d + b'0') as char)
503                .collect::<String>()
504        )
505    }
506}
507
508impl From<U> for [u8; 32] {
509    fn from(x: U) -> Self {
510        x.0
511    }
512}
513
514impl From<&[u8; 32]> for &U {
515    fn from(x: &[u8; 32]) -> Self {
516        unsafe { &*(x as *const [u8; 32] as *const U) }
517    }
518}
519
520impl From<[u8; 32]> for U {
521    fn from(x: [u8; 32]) -> Self {
522        U(x)
523    }
524}
525
526impl Deref for U {
527    type Target = [u8; 32];
528
529    fn deref(&self) -> &Self::Target {
530        &self.0
531    }
532}
533
534impl DerefMut for U {
535    fn deref_mut(&mut self) -> &mut Self::Target {
536        &mut self.0
537    }
538}
539
540impl From<bool> for U {
541    fn from(x: bool) -> Self {
542        U::from(&[x as u8])
543    }
544}
545
546impl Zero for U {
547    fn zero() -> Self {
548        U::ZERO
549    }
550
551    fn is_zero(&self) -> bool {
552        self.0.iter().all(|&b| b == 0)
553    }
554}
555
556impl Default for U {
557    fn default() -> Self {
558        U::ZERO
559    }
560}
561
562impl One for U {
563    fn one() -> Self {
564        U::ONE
565    }
566}
567
568impl Index<usize> for U {
569    type Output = u8;
570
571    fn index(&self, index: usize) -> &Self::Output {
572        &self.0[index]
573    }
574}
575
576impl I {
577    fn is_neg(&self) -> bool {
578        self.0[0] & 0x80 != 0
579    }
580
581    pub fn is_zero(&self) -> bool {
582        *self == Self::ZERO
583    }
584
585    pub fn is_some(&self) -> bool {
586        !self.is_zero()
587    }
588
589    pub fn as_slice(&self) -> &[u8; 32] {
590        &self.0
591    }
592
593    fn neg(&self) -> Self {
594        let x = wrapping_add(&U(self.0.map(|b| !b)), &U::ONE);
595        I(x.0)
596    }
597
598    fn abs(self) -> U {
599        if self.is_neg() {
600            U(self.neg().0)
601        } else {
602            U(self.0)
603        }
604    }
605}
606
607macro_rules! from_slices {
608    ($($n:expr),+ $(,)?) => {
609        $(
610            impl From<&[u8; $n]> for U {
611                fn from(x: &[u8; $n]) -> Self {
612                    let mut b = [0u8; 32];
613                    b[32 - $n..].copy_from_slice(x);
614                    U(b)
615                }
616            }
617
618            impl From<[u8; $n]> for U {
619                fn from(x: [u8; $n]) -> Self {
620                    U::from(&x)
621                }
622            }
623
624            impl From<U> for [u8; $n] {
625                fn from(x: U) -> Self {
626                    unsafe { *(x.as_ptr().add(32 - $n) as *const [u8; $n]) }
627                }
628            }
629        )+
630    };
631}
632
633from_slices!(
634    1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26,
635    27, 28, 29, 30, 31
636);
637
638macro_rules! from_ints {
639    ($($t:ty),+ $(,)?) => {
640        $(
641            impl From<$t> for U {
642                fn from(x: $t) -> Self {
643                    let mut b = [0u8; 32];
644                    b[32 - core::mem::size_of::<$t>()..].copy_from_slice(&x.to_be_bytes());
645                    U(b)
646                }
647            }
648
649            impl From<U> for $t {
650                fn from(x: U) -> Self {
651                    Self::from_be_bytes(x.into())
652                }
653            }
654        )+
655    };
656}
657
658from_ints! { u8, u16, u32, u64, u128 }
659
660impl From<I> for [u8; 32] {
661    fn from(x: I) -> Self {
662        x.0
663    }
664}
665
666impl From<[u8; 32]> for I {
667    fn from(x: [u8; 32]) -> Self {
668        I(x)
669    }
670}
671
672fn i_add(x: &I, y: &I) -> I {
673    I(wrapping_add(&U(x.0), &U(y.0)).0)
674}
675
676fn i_sub(x: &I, y: &I) -> I {
677    I(wrapping_sub(&U(x.0), &U(y.0)).0)
678}
679
680fn i_mul(x: &I, y: &I) -> I {
681    let result = wrapping_mul(&U(x.0), &U(y.0));
682    I(result.0)
683}
684
685fn i_div(x: &I, y: &I) -> I {
686    let r = wrapping_div(&x.abs(), &y.abs());
687    if x.is_neg() ^ y.is_neg() {
688        I(r.0).neg()
689    } else {
690        I(r.0)
691    }
692}
693
694fn i_rem(x: &I, y: &I) -> I {
695    let r = modd(&x.abs(), &y.abs());
696    if x.is_neg() {
697        I(r.0).neg()
698    } else {
699        I(r.0)
700    }
701}
702
703impl Add for I {
704    type Output = I;
705    fn add(self, rhs: I) -> I {
706        i_add(&self, &rhs)
707    }
708}
709
710impl Add for &I {
711    type Output = I;
712    fn add(self, rhs: &I) -> I {
713        i_add(self, rhs)
714    }
715}
716
717impl Sub for I {
718    type Output = I;
719    fn sub(self, rhs: I) -> I {
720        i_sub(&self, &rhs)
721    }
722}
723
724impl Sub for &I {
725    type Output = I;
726    fn sub(self, rhs: &I) -> I {
727        i_sub(self, rhs)
728    }
729}
730
731impl Mul for I {
732    type Output = I;
733    fn mul(self, rhs: I) -> I {
734        i_mul(&self, &rhs)
735    }
736}
737
738impl Mul for &I {
739    type Output = I;
740    fn mul(self, rhs: &I) -> I {
741        i_mul(self, rhs)
742    }
743}
744
745impl Div for I {
746    type Output = I;
747    fn div(self, rhs: I) -> I {
748        i_div(&self, &rhs)
749    }
750}
751
752impl Div for &I {
753    type Output = I;
754    fn div(self, rhs: &I) -> I {
755        i_div(self, rhs)
756    }
757}
758
759impl Rem for I {
760    type Output = I;
761    fn rem(self, rhs: I) -> I {
762        i_rem(&self, &rhs)
763    }
764}
765
766impl Eq for I {}
767
768impl PartialOrd for I {
769    fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
770        Some(self.cmp(other))
771    }
772}
773
774impl Ord for I {
775    fn cmp(&self, other: &Self) -> Ordering {
776        let self_sign = self.0[0] & 0x80;
777        let other_sign = other.0[0] & 0x80;
778        match (self_sign, other_sign) {
779            (0, 0x80) => Ordering::Greater,
780            (0x80, 0) => Ordering::Less,
781            _ => self.0.cmp(&other.0),
782        }
783    }
784}
785
786impl Rem for &I {
787    type Output = I;
788    fn rem(self, rhs: &I) -> I {
789        i_rem(self, rhs)
790    }
791}
792
793impl I {
794    pub const ZERO: Self = I([0u8; 32]);
795
796    pub const ONE: Self = I([
797        0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
798        0, 1,
799    ]);
800}
801
802impl Zero for I {
803    fn zero() -> Self {
804        I::ZERO
805    }
806    fn is_zero(&self) -> bool {
807        self.0.iter().all(|&b| b == 0)
808    }
809}
810
811impl Default for I {
812    fn default() -> Self {
813        I::ZERO
814    }
815}
816
817impl One for I {
818    fn one() -> Self {
819        I::ONE
820    }
821}
822
823#[test]
824fn test_is_zeroes() {
825    assert!(U::ZERO.is_zero());
826    assert!(U::ONE.is_some());
827    assert!(I::ZERO.is_zero());
828    assert!(I::ONE.is_some());
829}
830
831#[cfg(all(test, feature = "alloy-enabled", feature = "std"))]
832mod test {
833    use proptest::prelude::*;
834
835    use super::*;
836
837    proptest! {
838        #[test]
839        fn test_u_is_zero(x in any::<[u8; 32]>()) {
840            let x = U::from(x);
841            let ex = U256::from_be_bytes(x.0);
842            assert_eq!(ex.is_zero(), x.is_zero());
843        }
844
845        #[test]
846        fn test_u_div(x in any::<U>(), y in any::<U>()) {
847            let ex = U256::from_be_bytes(x.0);
848            let ey = U256::from_be_bytes(y.0);
849            assert_eq!((ex.wrapping_div(ey)).to_be_bytes(), x.wrapping_div(&y).0);
850        }
851
852        #[test]
853        fn test_u_mul(x in any::<U>(), y in any::<U>()) {
854            let ex = U256::from_be_bytes(x.0);
855            let ey = U256::from_be_bytes(y.0);
856            assert_eq!((ex.wrapping_mul(ey)).to_be_bytes(), wrapping_mul(&x,  &y).0);
857        }
858
859        #[test]
860        fn test_u_mod(x in any::<U>(), y in any::<U>()) {
861            let ex = U256::from_be_bytes(x.0);
862            let ey = U256::from_be_bytes(y.0);
863            assert_eq!((ex % ey).to_be_bytes(), (x % y).0);
864        }
865
866        #[test]
867        fn test_u_add(x in any::<U>(), y in any::<U>()) {
868            let ex = U256::from_be_bytes(x.0);
869            let ey = U256::from_be_bytes(y.0);
870            let e = U::from(ex.wrapping_add(ey).to_be_bytes::<32>());
871            assert_eq!(e, x.wrapping_add(&y), "{e} != {}", x + y);
872        }
873
874        #[test]
875        fn test_u_sub(x in any::<U>(), y in any::<U>()) {
876            let ex = U256::from_be_bytes(x.0);
877            let ey = U256::from_be_bytes(y.0);
878            assert_eq!((ex.wrapping_sub(ey)).to_be_bytes(), x.wrapping_sub(&y).0);
879        }
880
881        #[test]
882        fn test_u_cmp(x in any::<U>(), y in any::<U>()) {
883            let ex = U256::from_be_bytes(x.0);
884            let ey = U256::from_be_bytes(y.0);
885            assert_eq!(ex.cmp(&ey), x.cmp(&y));
886        }
887
888        #[test]
889        #[cfg(feature = "alloc")]
890        fn test_u_str(x in any::<U>()) {
891            assert_eq!(U256::from_be_bytes(x.0).to_string(), x.to_string());
892        }
893
894        #[test]
895        fn test_i_is_zero(x in any::<U>()) {
896            let ex = I256::from_be_bytes(x.0);
897            assert_eq!(ex.is_zero(), x.is_zero());
898        }
899
900        #[test]
901        fn test_i_div(x in any::<I>(), y in any::<I>()) {
902            let ex = I256::from_be_bytes(x.0);
903            let ey = I256::from_be_bytes(y.0);
904            assert_eq!((ex / ey).to_be_bytes(), (x / y).0);
905        }
906
907        #[test]
908        fn test_i_mul(x in any::<I>(), y in any::<I>()) {
909            let ex = I256::from_be_bytes(x.0);
910            let ey = I256::from_be_bytes(y.0);
911            assert_eq!((ex.wrapping_mul(ey)).to_be_bytes(), (x * y).0);
912        }
913
914        #[test]
915        fn test_i_mod(x in any::<I>(), y in any::<I>()) {
916            let ex = I256::from_be_bytes(x.0);
917            let ey = I256::from_be_bytes(y.0);
918            assert_eq!((ex % ey).to_be_bytes(), (x % y).0);
919        }
920
921        #[test]
922        fn test_i_add(x in any::<I>(), y in any::<I>()) {
923            let ex = I256::from_be_bytes(x.0);
924            let ey = I256::from_be_bytes(y.0);
925            assert_eq!((ex.wrapping_add(ey)).to_be_bytes(), (x + y).0);
926        }
927
928        #[test]
929        fn test_i_sub(x in any::<I>(), y in any::<I>()) {
930            let ex = I256::from_be_bytes(x.0);
931            let ey = I256::from_be_bytes(y.0);
932            assert_eq!((ex.wrapping_sub(ey)).to_be_bytes(), (x - y).0);
933        }
934
935        #[test]
936        fn test_i_cmp(x in any::<I>(), y in any::<I>()) {
937            let ex = I256::from_be_bytes(x.0);
938            let ey = I256::from_be_bytes(y.0);
939            assert_eq!(ex.cmp(&ey), x.cmp(&y));
940        }
941
942        #[test]
943        fn test_u_u8(x in any::<u8>()) {
944            let mut b = [0u8; 32];
945            b[32-std::mem::size_of::<u8>()..].copy_from_slice(&x.to_be_bytes());
946            assert_eq!(&U256::from_be_bytes(b).to_be_bytes(), U::from(x).as_slice());
947        }
948
949        #[test]
950        fn test_u_u16(x in any::<u16>()) {
951            let mut b = [0u8; 32];
952            b[32-std::mem::size_of::<u16>()..].copy_from_slice(&x.to_be_bytes());
953            assert_eq!(&U256::from_be_bytes(b).to_be_bytes(), U::from(x).as_slice());
954        }
955
956        #[test]
957        fn test_u_u32(x in any::<u32>()) {
958            let mut b = [0u8; 32];
959            b[32-std::mem::size_of::<u32>()..].copy_from_slice(&x.to_be_bytes());
960            assert_eq!(&U256::from_be_bytes(b).to_be_bytes(), U::from(x).as_slice());
961        }
962
963        #[test]
964        fn test_u_u64(x in any::<u64>()) {
965            let mut b = [0u8; 32];
966            b[32-std::mem::size_of::<u64>()..].copy_from_slice(&x.to_be_bytes());
967            assert_eq!(&U256::from_be_bytes(b).to_be_bytes(), U::from(x).as_slice());
968        }
969
970        #[test]
971        fn test_u_u128(x in any::<u128>()) {
972            let mut b = [0u8; 32];
973            b[32-std::mem::size_of::<u128>()..].copy_from_slice(&x.to_be_bytes());
974            assert_eq!(&U256::from_be_bytes(b).to_be_bytes(), U::from(x).as_slice());
975        }
976
977        #[test]
978        fn test_to_and_from_addrs(x in any::<Address>()) {
979            let y: [u8; 20] = U::from(x).into();
980            assert_eq!(x, y)
981        }
982
983        #[test]
984        fn test_u_conv_to_and_from_u8(x in any::<u8>()) {
985            assert_eq!(x.wrapping_add(1), U::from(x).wrapping_add(&U::ONE).into());
986        }
987    }
988}