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