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 = "alloc")]
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(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(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        wrapping_add(&self, &rhs)
231    }
232}
233
234impl Add for &U {
235    type Output = U;
236
237    fn add(self, rhs: &U) -> U {
238        wrapping_add(&self, rhs)
239    }
240}
241
242impl Sub for U {
243    type Output = U;
244
245    fn sub(self, rhs: U) -> U {
246        wrapping_sub(&self, &rhs)
247    }
248}
249
250impl Sub for &U {
251    type Output = U;
252
253    fn sub(self, rhs: &U) -> U {
254        wrapping_sub(self, rhs)
255    }
256}
257
258impl Mul for U {
259    type Output = U;
260
261    fn mul(self, rhs: U) -> U {
262        wrapping_mul(&self, &rhs)
263    }
264}
265
266impl Mul for &U {
267    type Output = U;
268
269    fn mul(self, rhs: &U) -> U {
270        wrapping_mul(self, rhs)
271    }
272}
273
274impl Div for U {
275    type Output = U;
276
277    fn div(self, rhs: U) -> U {
278        wrapping_div(&self, &rhs)
279    }
280}
281
282impl Div for &U {
283    type Output = U;
284
285    fn div(self, rhs: &U) -> U {
286        wrapping_div(self, rhs)
287    }
288}
289
290impl Rem for U {
291    type Output = U;
292
293    fn rem(self, rhs: U) -> U {
294        modd(&self, &rhs)
295    }
296}
297
298impl Rem for &U {
299    type Output = U;
300
301    fn rem(self, rhs: &U) -> U {
302        modd(self, rhs)
303    }
304}
305
306impl Eq for U {}
307
308impl PartialOrd for U {
309    fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
310        Some(self.cmp(other))
311    }
312}
313
314impl Ord for U {
315    fn cmp(&self, other: &Self) -> Ordering {
316        self.0.cmp(&other.0)
317    }
318}
319
320impl U {
321    pub const ZERO: Self = U([0u8; 32]);
322
323    pub const MAX: Self = U([u8::MAX; 32]);
324
325    pub const ONE: Self = U([
326        0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
327        0, 1,
328    ]);
329
330    pub fn is_true(&self) -> bool {
331        self.0[31] == 1
332    }
333
334    pub fn is_zero(&self) -> bool {
335        *self == Self::ZERO
336    }
337
338    pub fn is_some(&self) -> bool {
339        !self.is_zero()
340    }
341
342    pub fn as_slice(&self) -> &[u8; 32] {
343        &self.0
344    }
345
346    pub fn checked_add(&self, y: &Self) -> Option<Self> {
347        checked_add(self, y)
348    }
349
350    pub fn mul_mod(&self, y: &Self, z: &Self) -> Self {
351        let mut b = self.0;
352        unsafe { math_mul_mod(b.as_mut_ptr(), y.as_ptr(), z.as_ptr()) }
353        Self(b)
354    }
355
356    pub fn add_mod(&self, y: &Self, z: &Self) -> Self {
357        let mut b = self.0;
358        unsafe { math_add_mod(b.as_mut_ptr(), y.as_ptr(), z.as_ptr()) }
359        Self(b)
360    }
361
362    pub fn widening_mul(&self, y: &U) -> (U, U) {
363        let shift_128 = &U([
364            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,
365            0, 0, 0,
366        ]);
367        let x_hi = self / shift_128;
368        let x_lo = self % shift_128;
369        let y_hi = y / shift_128;
370        let y_lo = y % shift_128;
371        let t0 = x_lo.mul_mod(&y_lo, &U::MAX);
372        let t1 = x_hi.mul_mod(&y_lo, &U::MAX);
373        let t2 = x_lo.mul_mod(&y_hi, &U::MAX);
374        let t3 = x_hi.mul_mod(&y_hi, &U::MAX);
375        let t0_hi = &t0 / shift_128;
376        let t0_lo = &t0 % shift_128;
377        let t1_hi = &t1 / shift_128;
378        let t1_lo = &t1 % shift_128;
379        let t2_hi = &t2 / shift_128;
380        let t2_lo = &t2 % shift_128;
381        let mid = (t0_hi + t1_lo) + t2_lo;
382        let mid_hi = &mid / shift_128;
383        let mid_lo = &mid % shift_128;
384        let mid_lo_shifted = mid_lo.mul_mod(&shift_128, &U::MAX);
385        let out_low = t0_lo + mid_lo_shifted;
386        let out_high = t3 + t1_hi + t2_hi + mid_hi;
387        (out_high, out_low)
388    }
389
390    pub fn mul_div(&self, y: &U, denom: &U) -> Option<(U, bool)> {
391        todo!()
392    }
393
394    pub fn mul_div_round_up(&self, y: &U, denom_and_rem: &U) -> Option<U> {
395        let (x, y) = self.mul_div(y, denom_and_rem)?;
396        Some(if y { x + U::ONE } else { x })
397    }
398}
399
400#[cfg(feature = "alloc")]
401impl Display for U {
402    fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
403        let mut result = vec![0u8];
404        for &byte in &self.0 {
405            let mut carry = byte as u32;
406            for digit in result.iter_mut() {
407                let temp = (*digit as u32) * 256 + carry;
408                *digit = (temp % 10) as u8;
409                carry = temp / 10;
410            }
411            while carry > 0 {
412                result.push((carry % 10) as u8);
413                carry /= 10;
414            }
415        }
416        if result.iter().all(|&d| d == 0) {
417            return write!(f, "0");
418        }
419        write!(
420            f,
421            "{}",
422            result
423                .iter()
424                .rev()
425                .skip_while(|&&d| d == 0)
426                .map(|&d| (d + b'0') as char)
427                .collect::<String>()
428        )
429    }
430}
431
432impl From<U> for [u8; 32] {
433    fn from(x: U) -> Self {
434        x.0
435    }
436}
437
438impl From<&[u8; 32]> for &U {
439    fn from(x: &[u8; 32]) -> Self {
440        unsafe { &*(x as *const [u8; 32] as *const U) }
441    }
442}
443
444impl From<[u8; 32]> for U {
445    fn from(x: [u8; 32]) -> Self {
446        U(x)
447    }
448}
449
450impl Deref for U {
451    type Target = [u8; 32];
452
453    fn deref(&self) -> &Self::Target {
454        &self.0
455    }
456}
457
458impl DerefMut for U {
459    fn deref_mut(&mut self) -> &mut Self::Target {
460        &mut self.0
461    }
462}
463
464impl From<bool> for U {
465    fn from(x: bool) -> Self {
466        U::from(&[x as u8])
467    }
468}
469
470impl From<U> for Address {
471    fn from(x: U) -> Self {
472        unsafe { *(x.as_ptr().add(32 - 20) as *const [u8; 20]) }
473    }
474}
475
476impl Zero for U {
477    fn zero() -> Self {
478        U::ZERO
479    }
480
481    fn is_zero(&self) -> bool {
482        self.0.iter().all(|&b| b == 0)
483    }
484}
485
486impl Default for U {
487    fn default() -> Self {
488        U::ZERO
489    }
490}
491
492impl One for U {
493    fn one() -> Self {
494        U::ONE
495    }
496}
497
498impl Index<usize> for U {
499    type Output = u8;
500
501    fn index(&self, index: usize) -> &Self::Output {
502        &self.0[index]
503    }
504}
505
506impl I {
507    fn is_neg(&self) -> bool {
508        self.0[0] & 0x80 != 0
509    }
510
511    pub fn is_zero(&self) -> bool {
512        *self == Self::ZERO
513    }
514
515    pub fn is_some(&self) -> bool {
516        !self.is_zero()
517    }
518
519    pub fn as_slice(&self) -> &[u8; 32] {
520        &self.0
521    }
522
523    fn neg(&self) -> Self {
524        let x = wrapping_add(&U(self.0.map(|b| !b)), &U::ONE);
525        I(x.0)
526    }
527
528    fn abs(self) -> U {
529        if self.is_neg() {
530            U(self.neg().0)
531        } else {
532            U(self.0)
533        }
534    }
535}
536
537macro_rules! from_slices {
538    ($($n:expr),+ $(,)?) => {
539        $(
540            impl From<&[u8; $n]> for U {
541                fn from(x: &[u8; $n]) -> Self {
542                    let mut b = [0u8; 32];
543                    b[32 - $n..].copy_from_slice(x);
544                    U(b)
545                }
546            }
547
548            impl From<[u8; $n]> for U {
549                fn from(x: [u8; $n]) -> Self {
550                    U::from(&x)
551                }
552            }
553        )+
554    };
555}
556
557from_slices!(
558    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,
559    27, 28, 29, 30, 31
560);
561
562macro_rules! from_ints {
563    ($($t:ty),+ $(,)?) => {
564        $(
565            impl From<$t> for U {
566                fn from(x: $t) -> Self {
567                    let mut b = [0u8; 32];
568                    b[32 - core::mem::size_of::<$t>()..].copy_from_slice(&x.to_be_bytes());
569                    U(b)
570                }
571            }
572        )+
573    };
574}
575
576from_ints! { u8, u16, u32, u64, u128 }
577
578impl From<I> for [u8; 32] {
579    fn from(x: I) -> Self {
580        x.0
581    }
582}
583
584impl From<[u8; 32]> for I {
585    fn from(x: [u8; 32]) -> Self {
586        I(x)
587    }
588}
589
590fn i_add(x: &I, y: &I) -> I {
591    I(wrapping_add(&U(x.0), &U(y.0)).0)
592}
593
594fn i_sub(x: &I, y: &I) -> I {
595    I(wrapping_sub(&U(x.0), &U(y.0)).0)
596}
597
598fn i_mul(x: &I, y: &I) -> I {
599    let result = wrapping_mul(&U(x.0), &U(y.0));
600    I(result.0)
601}
602
603fn i_div(x: &I, y: &I) -> I {
604    let r = wrapping_div(&x.abs(), &y.abs());
605    if x.is_neg() ^ y.is_neg() {
606        I(r.0).neg()
607    } else {
608        I(r.0)
609    }
610}
611
612fn i_rem(x: &I, y: &I) -> I {
613    let r = modd(&x.abs(), &y.abs());
614    if x.is_neg() {
615        I(r.0).neg()
616    } else {
617        I(r.0)
618    }
619}
620
621impl Add for I {
622    type Output = I;
623    fn add(self, rhs: I) -> I {
624        i_add(&self, &rhs)
625    }
626}
627
628impl Add for &I {
629    type Output = I;
630    fn add(self, rhs: &I) -> I {
631        i_add(self, rhs)
632    }
633}
634
635impl Sub for I {
636    type Output = I;
637    fn sub(self, rhs: I) -> I {
638        i_sub(&self, &rhs)
639    }
640}
641
642impl Sub for &I {
643    type Output = I;
644    fn sub(self, rhs: &I) -> I {
645        i_sub(self, rhs)
646    }
647}
648
649impl Mul for I {
650    type Output = I;
651    fn mul(self, rhs: I) -> I {
652        i_mul(&self, &rhs)
653    }
654}
655
656impl Mul for &I {
657    type Output = I;
658    fn mul(self, rhs: &I) -> I {
659        i_mul(self, rhs)
660    }
661}
662
663impl Div for I {
664    type Output = I;
665    fn div(self, rhs: I) -> I {
666        i_div(&self, &rhs)
667    }
668}
669
670impl Div for &I {
671    type Output = I;
672    fn div(self, rhs: &I) -> I {
673        i_div(self, rhs)
674    }
675}
676
677impl Rem for I {
678    type Output = I;
679    fn rem(self, rhs: I) -> I {
680        i_rem(&self, &rhs)
681    }
682}
683
684impl Eq for I {}
685
686impl PartialOrd for I {
687    fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
688        Some(self.cmp(other))
689    }
690}
691
692impl Ord for I {
693    fn cmp(&self, other: &Self) -> Ordering {
694        let self_sign = self.0[0] & 0x80;
695        let other_sign = other.0[0] & 0x80;
696        match (self_sign, other_sign) {
697            (0, 0x80) => Ordering::Greater,
698            (0x80, 0) => Ordering::Less,
699            _ => self.0.cmp(&other.0),
700        }
701    }
702}
703
704impl Rem for &I {
705    type Output = I;
706    fn rem(self, rhs: &I) -> I {
707        i_rem(self, rhs)
708    }
709}
710
711impl I {
712    pub const ZERO: Self = I([0u8; 32]);
713
714    pub const ONE: Self = I([
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, 0, 0,
716        0, 1,
717    ]);
718}
719
720impl Zero for I {
721    fn zero() -> Self {
722        I::ZERO
723    }
724    fn is_zero(&self) -> bool {
725        self.0.iter().all(|&b| b == 0)
726    }
727}
728
729impl Default for I {
730    fn default() -> Self {
731        I::ZERO
732    }
733}
734
735impl One for I {
736    fn one() -> Self {
737        I::ONE
738    }
739}
740
741#[test]
742fn test_is_zeroes() {
743    assert!(U::ZERO.is_zero());
744    assert!(U::ONE.is_some());
745    assert!(I::ZERO.is_zero());
746    assert!(I::ONE.is_some());
747}
748
749#[cfg(all(test, feature = "alloy-enabled", feature = "std"))]
750mod test {
751    use proptest::prelude::*;
752
753    use super::*;
754
755    proptest! {
756        #[test]
757        fn test_u_is_zero(x in any::<[u8; 32]>()) {
758            let x = U::from(x);
759            let ex = U256::from_be_bytes(x.0);
760            assert_eq!(ex.is_zero(), x.is_zero());
761        }
762
763        #[test]
764        fn test_u_div(x in any::<U>(), y in any::<U>()) {
765            let ex = U256::from_be_bytes(x.0);
766            let ey = U256::from_be_bytes(y.0);
767            assert_eq!((ex.wrapping_div(ey)).to_be_bytes(), (x / y).0);
768        }
769
770        #[test]
771        fn test_u_mul(x in any::<U>(), y in any::<U>()) {
772            let ex = U256::from_be_bytes(x.0);
773            let ey = U256::from_be_bytes(y.0);
774            assert_eq!((ex.wrapping_mul(ey)).to_be_bytes(), (x * y).0);
775        }
776
777        #[test]
778        fn test_u_mod(x in any::<U>(), y in any::<U>()) {
779            let ex = U256::from_be_bytes(x.0);
780            let ey = U256::from_be_bytes(y.0);
781            assert_eq!((ex % ey).to_be_bytes(), (x % y).0);
782        }
783
784        #[test]
785        fn test_u_add(x in any::<U>(), y in any::<U>()) {
786            let ex = U256::from_be_bytes(x.0);
787            let ey = U256::from_be_bytes(y.0);
788            let e = U::from(ex.wrapping_add(ey).to_be_bytes::<32>());
789            assert_eq!(e, x + y, "{e} != {}", x + y);
790        }
791
792        #[test]
793        fn test_u_sub(x in any::<U>(), y in any::<U>()) {
794            let ex = U256::from_be_bytes(x.0);
795            let ey = U256::from_be_bytes(y.0);
796            assert_eq!((ex.wrapping_sub(ey)).to_be_bytes(), (x - y).0);
797        }
798
799        #[test]
800        fn test_u_cmp(x in any::<U>(), y in any::<U>()) {
801            let ex = U256::from_be_bytes(x.0);
802            let ey = U256::from_be_bytes(y.0);
803            assert_eq!(ex.cmp(&ey), x.cmp(&y));
804        }
805
806        #[test]
807        #[cfg(feature = "alloc")]
808        fn test_u_str(x in any::<U>()) {
809            assert_eq!(U256::from_be_bytes(x.0).to_string(), x.to_string());
810        }
811
812        #[test]
813        fn test_i_is_zero(x in any::<U>()) {
814            let ex = I256::from_be_bytes(x.0);
815            assert_eq!(ex.is_zero(), x.is_zero());
816        }
817
818        #[test]
819        fn test_i_div(x in any::<I>(), y in any::<I>()) {
820            let ex = I256::from_be_bytes(x.0);
821            let ey = I256::from_be_bytes(y.0);
822            assert_eq!((ex / ey).to_be_bytes(), (x / y).0);
823        }
824
825        #[test]
826        fn test_i_mul(x in any::<I>(), y in any::<I>()) {
827            let ex = I256::from_be_bytes(x.0);
828            let ey = I256::from_be_bytes(y.0);
829            assert_eq!((ex.wrapping_mul(ey)).to_be_bytes(), (x * y).0);
830        }
831
832        #[test]
833        fn test_i_mod(x in any::<I>(), y in any::<I>()) {
834            let ex = I256::from_be_bytes(x.0);
835            let ey = I256::from_be_bytes(y.0);
836            assert_eq!((ex % ey).to_be_bytes(), (x % y).0);
837        }
838
839        #[test]
840        fn test_i_add(x in any::<I>(), y in any::<I>()) {
841            let ex = I256::from_be_bytes(x.0);
842            let ey = I256::from_be_bytes(y.0);
843            assert_eq!((ex.wrapping_add(ey)).to_be_bytes(), (x + y).0);
844        }
845
846        #[test]
847        fn test_i_sub(x in any::<I>(), y in any::<I>()) {
848            let ex = I256::from_be_bytes(x.0);
849            let ey = I256::from_be_bytes(y.0);
850            assert_eq!((ex.wrapping_sub(ey)).to_be_bytes(), (x - y).0);
851        }
852
853        #[test]
854        fn test_i_cmp(x in any::<I>(), y in any::<I>()) {
855            let ex = I256::from_be_bytes(x.0);
856            let ey = I256::from_be_bytes(y.0);
857            assert_eq!(ex.cmp(&ey), x.cmp(&y));
858        }
859
860        #[test]
861        fn test_u_u8(x in any::<u8>()) {
862            let mut b = [0u8; 32];
863            b[32-std::mem::size_of::<u8>()..].copy_from_slice(&x.to_be_bytes());
864            assert_eq!(&U256::from_be_bytes(b).to_be_bytes(), U::from(x).as_slice());
865        }
866
867        #[test]
868        fn test_u_u16(x in any::<u16>()) {
869            let mut b = [0u8; 32];
870            b[32-std::mem::size_of::<u16>()..].copy_from_slice(&x.to_be_bytes());
871            assert_eq!(&U256::from_be_bytes(b).to_be_bytes(), U::from(x).as_slice());
872        }
873
874        #[test]
875        fn test_u_u32(x in any::<u32>()) {
876            let mut b = [0u8; 32];
877            b[32-std::mem::size_of::<u32>()..].copy_from_slice(&x.to_be_bytes());
878            assert_eq!(&U256::from_be_bytes(b).to_be_bytes(), U::from(x).as_slice());
879        }
880
881        #[test]
882        fn test_u_u64(x in any::<u64>()) {
883            let mut b = [0u8; 32];
884            b[32-std::mem::size_of::<u64>()..].copy_from_slice(&x.to_be_bytes());
885            assert_eq!(&U256::from_be_bytes(b).to_be_bytes(), U::from(x).as_slice());
886        }
887
888        #[test]
889        fn test_u_u128(x in any::<u128>()) {
890            let mut b = [0u8; 32];
891            b[32-std::mem::size_of::<u128>()..].copy_from_slice(&x.to_be_bytes());
892            assert_eq!(&U256::from_be_bytes(b).to_be_bytes(), U::from(x).as_slice());
893        }
894
895        #[test]
896        fn test_to_and_from_addrs(x in any::<Address>()) {
897            let y: [u8; 20] = U::from(x).into();
898            assert_eq!(x, y)
899        }
900    }
901}