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