bobcat_maths/
lib.rs

1#![cfg_attr(not(feature = "std"), no_std)]
2
3use core::{
4    cmp::{Eq, Ordering},
5    fmt::{Debug, Error as FmtError, Formatter},
6    ops::{
7        Add, AddAssign, Deref, DerefMut, Div, Index, IndexMut, Mul, Rem, Shl, ShlAssign, Shr,
8        ShrAssign, Sub, SubAssign,
9    },
10};
11
12use num_traits::{One, Zero};
13
14#[cfg(feature = "borsh")]
15use borsh::{BorshDeserialize, BorshSerialize};
16
17#[cfg(feature = "alloc")]
18extern crate alloc;
19
20#[cfg(feature = "alloc")]
21use alloc::{string::String, vec};
22
23pub type Address = [u8; 20];
24
25#[link(wasm_import_module = "vm_hooks")]
26#[cfg(not(feature = "alloy-enabled"))]
27unsafe extern "C" {
28    fn math_div(x: *mut u8, y: *const u8);
29    fn math_mod(x: *mut u8, y: *const u8);
30    fn math_add_mod(a: *mut u8, b: *const u8, c: *const u8);
31    fn math_mul_mod(a: *mut u8, b: *const u8, c: *const u8);
32}
33
34#[cfg(feature = "alloy-enabled")]
35mod alloy {
36    use core::ptr::copy_nonoverlapping;
37
38    pub(crate) use alloy_primitives::U256;
39
40    #[cfg(test)]
41    pub(crate) use alloy_primitives::I256;
42
43    pub(crate) unsafe fn math_div(out: *mut u8, y: *const u8) {
44        unsafe {
45            let x = U256::from_be_slice(&*(out as *const [u8; 32]));
46            let y = U256::from_be_slice(&*(y as *const [u8; 32]));
47            let z = if y.is_zero() {
48                // TODO: I think the node returns 0 when this is the case.
49                U256::ZERO
50            } else {
51                x / y
52            };
53            copy_nonoverlapping(z.to_be_bytes::<32>().as_ptr(), out, 32);
54        }
55    }
56
57    pub(crate) unsafe fn math_mod(out: *mut u8, y: *const u8) {
58        unsafe {
59            let x = U256::from_be_slice(&*(out as *const [u8; 32]));
60            let y = U256::from_be_slice(&*(y as *const [u8; 32]));
61            let z = x % y;
62            copy_nonoverlapping(z.to_be_bytes::<32>().as_ptr(), out, 32);
63        }
64    }
65
66    pub(crate) unsafe fn math_add_mod(a: *mut u8, b: *const u8, c: *const u8) {
67        unsafe {
68            let x = U256::from_be_slice(&*(a as *const [u8; 32]));
69            let y = U256::from_be_slice(&*(b as *const [u8; 32]));
70            let z = U256::from_be_slice(&*(c as *const [u8; 32]));
71            let x = x.add_mod(y, z);
72            copy_nonoverlapping(x.to_be_bytes::<32>().as_ptr(), a, 32);
73        }
74    }
75
76    pub(crate) unsafe fn math_mul_mod(a: *mut u8, b: *const u8, c: *const u8) {
77        unsafe {
78            let x = U256::from_be_slice(&*(a as *const [u8; 32]));
79            let y = U256::from_be_slice(&*(b as *const [u8; 32]));
80            let z = U256::from_be_slice(&*(c as *const [u8; 32]));
81            let x = x.mul_mod(y, z);
82            copy_nonoverlapping(x.to_be_bytes::<32>().as_ptr(), a, 32);
83        }
84    }
85}
86
87#[cfg(feature = "alloy-enabled")]
88use alloy::*;
89
90#[derive(Copy, Clone, PartialEq, Hash)]
91#[cfg_attr(feature = "proptest", derive(proptest_derive::Arbitrary))]
92#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))]
93#[cfg_attr(feature = "borsh", derive(BorshDeserialize, BorshSerialize))]
94#[repr(transparent)]
95pub struct U(pub [u8; 32]);
96
97#[derive(Copy, Clone, PartialEq, Hash, Debug)]
98#[cfg_attr(feature = "proptest", derive(proptest_derive::Arbitrary))]
99#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))]
100#[cfg_attr(feature = "borsh", derive(BorshDeserialize, BorshSerialize))]
101#[repr(transparent)]
102pub struct I(pub [u8; 32]);
103
104pub fn wrapping_div(x: &U, y: &U) -> U {
105    assert!(y.is_some(), "divide by zero");
106    let mut b = *x;
107    unsafe { math_div(b.as_mut_ptr(), y.as_ptr()) }
108    b
109}
110
111fn wrapping_div_quo_rem_b<const C: usize>(x: &[u8; C], denom: &[u8; C]) -> ([u8; C], [u8; C]) {
112    if denom == &[0u8; C] {
113        return ([0u8; C], [0u8; C]);
114    }
115    let mut q = [0u8; C];
116    let mut r = [0u8; C];
117    let mut one = [0u8; C];
118    one[C - 1] = 1;
119    let mut two = [0u8; C];
120    two[C - 1] = 2;
121    let mut i = 0;
122    while i < C * 8 {
123        let bit = (x[i / 8] >> (7 - (i % 8))) & 1;
124        r = wrapping_mul_b::<C>(&r, &two);
125        if bit == 1 {
126            r = wrapping_add_b::<C>(&r, &one);
127        }
128        if r >= *denom {
129            r = wrapping_sub_b::<C>(&r, denom);
130            q[i / 8] |= 1 << (7 - (i % 8));
131        }
132        i += 1;
133    }
134    (q, r)
135}
136
137pub fn const_wrapping_div(x: &U, y: &U) -> U {
138    U(wrapping_div_quo_rem_b::<32>(&x.0, &y.0).0)
139}
140
141#[cfg_attr(test, mutants::skip)]
142pub fn checked_div(x: &U, y: &U) -> Option<U> {
143    if y.is_zero() {
144        None
145    } else {
146        Some(wrapping_div(x, y))
147    }
148}
149
150pub fn modd(x: &U, y: &U) -> U {
151    let mut b = *x;
152    unsafe { math_mod(b.as_mut_ptr(), y.as_ptr()) }
153    b
154}
155
156const fn wrapping_add_b<const C: usize>(x: &[u8; C], y: &[u8; C]) -> [u8; C] {
157    let mut r = [0u8; C];
158    let mut c = 0;
159    let mut i = C - 1;
160    loop {
161        let s = x[i] as u16 + y[i] as u16 + c;
162        r[i] = s as u8;
163        c = s >> 8;
164        if i == 0 {
165            break;
166        }
167        i -= 1;
168    }
169    r
170}
171
172pub const fn wrapping_add(x: &U, y: &U) -> U {
173    U(wrapping_add_b(&x.0, &y.0))
174}
175
176#[cfg_attr(test, mutants::skip)]
177pub fn checked_add(x: &U, y: &U) -> Option<U> {
178    if x > &(U::MAX - *y) {
179        None
180    } else {
181        let z = x.add_mod(y, &U::MAX);
182        if z.is_zero() && (x.is_some() || y.is_some()) {
183            Some(U::MAX)
184        } else {
185            Some(z)
186        }
187    }
188}
189
190#[cfg_attr(test, mutants::skip)]
191pub fn saturating_add(x: &U, y: &U) -> U {
192    checked_add(x, y).unwrap_or(U::MAX)
193}
194
195const fn wrapping_sub_b<const C: usize>(x: &[u8; C], y: &[u8; C]) -> [u8; C] {
196    let mut neg_y = *y;
197    let mut i = 0;
198    while i < C {
199        neg_y[i] = !neg_y[i];
200        i += 1;
201    }
202    let mut c = 1u16;
203    let mut i = C - 1;
204    loop {
205        let sum = neg_y[i] as u16 + c;
206        neg_y[i] = sum as u8;
207        c = sum >> 8;
208        if i == 0 {
209            break;
210        }
211        i -= 1;
212    }
213    wrapping_add_b(x, &neg_y)
214}
215
216pub const fn wrapping_sub(x: &U, y: &U) -> U {
217    U(wrapping_sub_b::<32>(&x.0, &y.0))
218}
219
220pub fn saturating_sub(x: &U, y: &U) -> U {
221    checked_sub(x, y).unwrap_or(U::ZERO)
222}
223
224#[cfg_attr(test, mutants::skip)]
225pub fn checked_sub(x: &U, y: &U) -> Option<U> {
226    if x < y {
227        None
228    } else {
229        Some(wrapping_sub(x, y))
230    }
231}
232
233pub const fn wrapping_mul_b<const C: usize>(x: &[u8; C], y: &[u8; C]) -> [u8; C] {
234    let mut r = [0u8; C];
235    let mut i = 0;
236    while i < C {
237        let mut c = 0u16;
238        let mut j = 0;
239        while j < C {
240            let i_r = i + j;
241            if i_r >= C {
242                break;
243            }
244            let r_idx = C - 1 - i_r;
245            let xi = x[C - 1 - i] as u16;
246            let yj = y[C - 1 - j] as u16;
247            let prod = xi * yj + r[r_idx] as u16 + c;
248            r[r_idx] = prod as u8;
249            c = prod >> 8;
250            j += 1;
251        }
252        if i + j < C {
253            let idx = 31 - (i + j);
254            r[idx] = r[idx] + c as u8;
255        }
256        i += 1;
257    }
258    r
259}
260
261pub const fn wrapping_mul(x: &U, y: &U) -> U {
262    U(wrapping_mul_b(&x.0, &y.0))
263}
264
265#[cfg_attr(test, mutants::skip)]
266pub fn checked_mul(x: &U, y: &U) -> Option<U> {
267    if x.is_zero() || y.is_zero() {
268        return Some(U::ZERO);
269    }
270    if x > &(U::MAX / *y) {
271        None
272    } else {
273        let z = x.mul_mod(y, &U::MAX);
274        if z.is_zero() {
275            Some(U::MAX)
276        } else {
277            Some(z)
278        }
279    }
280}
281
282pub fn saturating_mul(x: &U, y: &U) -> U {
283    checked_mul(x, y).unwrap_or(U::MAX)
284}
285
286pub fn widening_mul(x: &U, y: &U) -> [u8; 64] {
287    let shift_128 = &U([
288        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, 0,
289        0, 0,
290    ]);
291    let x_hi = x / shift_128;
292    let x_lo = x % shift_128;
293    let y_hi = y / shift_128;
294    let y_lo = y % shift_128;
295    let t0 = x_lo.mul_mod(&y_lo, &U::MAX);
296    let t1 = x_hi.mul_mod(&y_lo, &U::MAX);
297    let t2 = x_lo.mul_mod(&y_hi, &U::MAX);
298    let t3 = x_hi.mul_mod(&y_hi, &U::MAX);
299    let t0_hi = &t0 / shift_128;
300    let t0_lo = &t0 % shift_128;
301    let t1_hi = &t1 / shift_128;
302    let t1_lo = &t1 % shift_128;
303    let t2_hi = &t2 / shift_128;
304    let t2_lo = &t2 % shift_128;
305    let mid = (t0_hi + t1_lo) + t2_lo;
306    let mid_hi = &mid / shift_128;
307    let mid_lo = &mid % shift_128;
308    let mid_lo_shifted = mid_lo.mul_mod(shift_128, &U::MAX);
309    let out_low = t0_lo + mid_lo_shifted;
310    let out_high = t3 + t1_hi + t2_hi + mid_hi;
311    let mut o = [0u8; 64];
312    o[..32].copy_from_slice(&out_high.0);
313    o[32..].copy_from_slice(&out_low.0);
314    o
315}
316
317pub fn mul_div(x: &U, y: &U, denom: &U) -> Option<(U, bool)> {
318    // TODO: this most certainly could be more efficient!
319    if denom.is_zero() {
320        return None;
321    }
322    let x = widening_mul(x, y);
323    let mut d = [0u8; 64];
324    d[32..].copy_from_slice(&denom.0);
325    let (q, rem) = wrapping_div_quo_rem_b::<64>(&x, &d);
326    if q[..32] != [0u8; 32] {
327        return None;
328    }
329    let l: [u8; 32] = q[32..].try_into().unwrap();
330    let l = U::from(l);
331    let has_carry = rem[32..] != [0u8; 32];
332    Some((l, has_carry))
333}
334
335pub fn mul_div_round_up(x: &U, y: &U, denom_and_rem: &U) -> Option<U> {
336    let (x, y) = mul_div(x, y, denom_and_rem)?;
337    if x.is_max() && y {
338        return None;
339    }
340    Some(if y { x + U::ONE } else { x })
341}
342
343/// Rooti iterative method based on the 9lives implementation. Using this
344/// operation is the equivalent of pow(x, 1/n).
345pub fn checked_rooti(x: U, n: u32) -> Option<U> {
346    if n == 0 {
347        return None;
348    }
349    if x.is_zero() {
350        return Some(U::ZERO);
351    }
352    if n == 1 {
353        return Some(x);
354    }
355    // Due to the nature of this iterative method, we hardcode some
356    // values to have consistency with the 9lives reference.
357    if x == U::from(4u32) && n == 2 {
358        return Some(U::from(2u32));
359    }
360    let n_u256 = U::from(n);
361    let n_1 = n_u256 - U::ONE;
362    // Initial guess: 2^ceil(bits(x)/n)
363    let mut b = 0;
364    let mut t = x;
365    while t.is_some() {
366        b += 1;
367        t >>= 1;
368    }
369    let shift = (b + n as usize - 1) / n as usize;
370    let mut z = U::ONE << shift;
371    let mut y = x;
372    // Newton's method:
373    while z < y {
374        y = z;
375        let p = z.checked_pow(&n_1)?;
376        z = ((x / p) + (z * n_1)) / n_u256;
377    }
378    // Correct overshoot:
379    if y.checked_pow(&n_u256)? > x {
380        y -= U::ONE;
381    }
382    Some(y)
383}
384
385pub fn checked_pow(x: &U, exp: &U) -> Option<U> {
386    let mut r = U::ONE;
387    let mut i = U::ZERO;
388    while &i < exp {
389        r = checked_mul(&r, x)?;
390        i += U::ONE;
391    }
392    Some(r)
393}
394
395impl Add for U {
396    type Output = U;
397
398    fn add(self, rhs: U) -> U {
399        cfg_if::cfg_if! {
400            if #[cfg(debug_assertions)] {
401                checked_add(&self, &rhs).expect("overflow when add")
402            } else {
403                wrapping_add(&self, &rhs)
404            }
405        }
406    }
407}
408
409impl Add for &U {
410    type Output = U;
411
412    fn add(self, rhs: &U) -> U {
413        cfg_if::cfg_if! {
414            if #[cfg(debug_assertions)] {
415                checked_add(self, rhs).expect("overflow when add")
416            } else {
417                wrapping_add(self, rhs)
418            }
419        }
420    }
421}
422
423impl AddAssign for U {
424    fn add_assign(&mut self, o: Self) {
425        *self = *self + o;
426    }
427}
428
429impl Sub for U {
430    type Output = U;
431
432    fn sub(self, rhs: U) -> U {
433        cfg_if::cfg_if! {
434            if #[cfg(debug_assertions)] {
435                checked_sub(&self, &rhs).expect("overflow when sub")
436            } else {
437                wrapping_sub(&self, &rhs)
438            }
439        }
440    }
441}
442
443impl Sub for &U {
444    type Output = U;
445
446    fn sub(self, rhs: &U) -> U {
447        cfg_if::cfg_if! {
448            if #[cfg(debug_assertions)] {
449                checked_sub(self, rhs).expect("overflow when sub")
450            } else {
451                wrapping_sub(self, rhs)
452            }
453        }
454    }
455}
456
457impl SubAssign for U {
458    fn sub_assign(&mut self, o: Self) {
459        *self = *self - o;
460    }
461}
462
463impl Mul for U {
464    type Output = U;
465
466    fn mul(self, rhs: U) -> U {
467        cfg_if::cfg_if! {
468            if #[cfg(debug_assertions)] {
469                checked_mul(&self, &rhs).expect("overflow when mul")
470            } else {
471                wrapping_mul(&self, &rhs)
472            }
473        }
474    }
475}
476
477impl Mul for &U {
478    type Output = U;
479
480    fn mul(self, rhs: &U) -> U {
481        cfg_if::cfg_if! {
482            if #[cfg(debug_assertions)] {
483                checked_mul(self, rhs).expect("overflow when mul")
484            } else {
485                wrapping_mul(self, rhs)
486            }
487        }
488    }
489}
490
491impl Div for U {
492    type Output = U;
493
494    fn div(self, rhs: U) -> U {
495        cfg_if::cfg_if! {
496            if #[cfg(debug_assertions)] {
497                checked_div(&self, &rhs).expect("overflow when div")
498            } else {
499                wrapping_div(&self, &rhs)
500            }
501        }
502    }
503}
504
505impl Div for &U {
506    type Output = U;
507
508    fn div(self, rhs: &U) -> U {
509        cfg_if::cfg_if! {
510            if #[cfg(debug_assertions)] {
511                checked_div(self, rhs).expect("overflow when div")
512            } else {
513                wrapping_div(self, rhs)
514            }
515        }
516    }
517}
518
519impl Rem for U {
520    type Output = U;
521
522    fn rem(self, rhs: U) -> U {
523        modd(&self, &rhs)
524    }
525}
526
527impl Rem for &U {
528    type Output = U;
529
530    fn rem(self, rhs: &U) -> U {
531        modd(self, rhs)
532    }
533}
534
535impl Shl<usize> for U {
536    type Output = Self;
537
538    fn shl(self, shift: usize) -> Self::Output {
539        if shift >= 256 {
540            return U::ZERO;
541        }
542        let mut result = [0u8; 32];
543        let byte_shift = shift / 8;
544        let bit_shift = shift % 8;
545        if bit_shift == 0 {
546            for i in 0..(32 - byte_shift) {
547                result[i] = self.0[i + byte_shift];
548            }
549        } else {
550            let mut carry = 0u8;
551            for i in (byte_shift..32).rev() {
552                let src_idx = i;
553                let dst_idx = i - byte_shift;
554                let byte = self.0[src_idx];
555                result[dst_idx] = (byte << bit_shift) | carry;
556                carry = byte >> (8 - bit_shift);
557            }
558        }
559        U(result)
560    }
561}
562
563impl ShlAssign<usize> for U {
564    fn shl_assign(&mut self, rhs: usize) {
565        *self = *self << rhs
566    }
567}
568
569impl Shr<usize> for U {
570    type Output = Self;
571
572    fn shr(self, shift: usize) -> Self::Output {
573        if shift >= 256 {
574            return U::ZERO;
575        }
576        let mut result = U::ZERO;
577        let byte_shift = shift / 8;
578        let bit_shift = shift % 8;
579        if bit_shift == 0 {
580            for i in byte_shift..32 {
581                result[i] = self.0[i - byte_shift];
582            }
583        } else {
584            let mut carry = 0u8;
585            for i in 0..(32 - byte_shift) {
586                let src_idx = i;
587                let dst_idx = i + byte_shift;
588                let byte = self.0[src_idx];
589                result[dst_idx] = (byte >> bit_shift) | carry;
590                carry = byte << (8 - bit_shift);
591            }
592        }
593        result
594    }
595}
596
597impl ShrAssign<usize> for U {
598    fn shr_assign(&mut self, rhs: usize) {
599        *self = *self >> rhs
600    }
601}
602
603impl Eq for U {}
604
605impl PartialOrd for U {
606    fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
607        Some(self.cmp(other))
608    }
609}
610
611impl Ord for U {
612    fn cmp(&self, other: &Self) -> Ordering {
613        self.0.cmp(&other.0)
614    }
615}
616
617impl Debug for U {
618    fn fmt(&self, f: &mut Formatter<'_>) -> Result<(), FmtError> {
619        let mut b = [0u8; 20 * 2];
620        let Ok(s) = const_hex::encode_to_str(self.0, &mut b) else {
621            return Err(FmtError);
622        };
623        write!(f, "{s}")
624    }
625}
626
627impl U {
628    pub const ZERO: Self = U([0u8; 32]);
629
630    pub const MAX: Self = U([u8::MAX; 32]);
631
632    pub const ONE: Self = U([
633        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,
634        0, 1,
635    ]);
636
637    pub fn is_true(&self) -> bool {
638        self.0[31] == 1
639    }
640
641    pub const fn is_zero(&self) -> bool {
642        let mut i = 0;
643        while i < 32 {
644            if self.0[i] != 0 {
645                return false;
646            }
647            i += 1;
648        }
649        true
650    }
651
652    pub const fn is_max(&self) -> bool {
653        let mut i = 0;
654        while i < 32 {
655            if self.0[i] != u8::MAX {
656                return false;
657            }
658            i += 1;
659        }
660        true
661    }
662
663    pub fn is_some(&self) -> bool {
664        !self.is_zero()
665    }
666
667    pub fn as_slice(&self) -> &[u8; 32] {
668        &self.0
669    }
670
671    pub fn checked_add(&self, y: &Self) -> Option<Self> {
672        checked_add(self, y)
673    }
674
675    pub fn checked_mul(&self, y: &Self) -> Option<Self> {
676        checked_mul(self, y)
677    }
678
679    pub fn checked_sub(&self, y: &Self) -> Option<Self> {
680        checked_sub(self, y)
681    }
682
683    pub fn checked_div(&self, y: &Self) -> Option<Self> {
684        checked_div(self, y)
685    }
686
687    pub fn checked_pow(&self, exp: &U) -> Option<Self> {
688        checked_pow(self, exp)
689    }
690
691    pub fn wrapping_add(&self, y: &Self) -> U {
692        wrapping_add(self, y)
693    }
694
695    pub fn wrapping_sub(&self, y: &Self) -> U {
696        wrapping_sub(self, y)
697    }
698
699    pub fn wrapping_mul(&self, y: &Self) -> U {
700        wrapping_mul(self, y)
701    }
702
703    pub fn wrapping_div(&self, y: &Self) -> U {
704        wrapping_div(self, y)
705    }
706
707    pub fn saturating_add(&self, y: &Self) -> U {
708        saturating_add(self, y)
709    }
710
711    pub fn saturating_sub(&self, y: &Self) -> U {
712        saturating_sub(self, y)
713    }
714
715    pub fn saturating_mul(&self, y: &Self) -> U {
716        saturating_mul(self, y)
717    }
718
719    pub fn widening_mul(&self, y: &Self) -> [u8; 64] {
720        widening_mul(self, y)
721    }
722
723    pub fn mul_div(&self, y: &Self, z: &Self) -> Option<(Self, bool)> {
724        mul_div(self, y, z)
725    }
726
727    pub fn mul_div_round_up(&self, y: &Self, z: &Self) -> Option<Self> {
728        mul_div_round_up(self, y, z)
729    }
730
731    pub fn mul_mod(&self, y: &Self, z: &Self) -> Self {
732        let mut b = self.0;
733        unsafe { math_mul_mod(b.as_mut_ptr(), y.as_ptr(), z.as_ptr()) }
734        Self(b)
735    }
736
737    pub fn add_mod(&self, y: &Self, z: &Self) -> Self {
738        let mut b = self.0;
739        unsafe { math_add_mod(b.as_mut_ptr(), y.as_ptr(), z.as_ptr()) }
740        Self(b)
741    }
742
743    pub fn checked_rooti(self, x: u32) -> Option<Self> {
744        checked_rooti(self, x)
745    }
746}
747
748#[cfg(feature = "alloc")]
749impl core::fmt::Display for U {
750    fn fmt(&self, f: &mut Formatter<'_>) -> core::fmt::Result {
751        let mut result = vec![0u8];
752        for &byte in &self.0 {
753            let mut carry = byte as u32;
754            for digit in result.iter_mut() {
755                let temp = (*digit as u32) * 256 + carry;
756                *digit = (temp % 10) as u8;
757                carry = temp / 10;
758            }
759            while carry > 0 {
760                result.push((carry % 10) as u8);
761                carry /= 10;
762            }
763        }
764        if result.iter().all(|&d| d == 0) {
765            return write!(f, "0");
766        }
767        write!(
768            f,
769            "{}",
770            result
771                .iter()
772                .rev()
773                .skip_while(|&&d| d == 0)
774                .map(|&d| (d + b'0') as char)
775                .collect::<String>()
776        )
777    }
778}
779
780impl From<U> for [u8; 32] {
781    fn from(x: U) -> Self {
782        x.0
783    }
784}
785
786impl From<U> for bool {
787    fn from(x: U) -> Self {
788        x.0[31] == 1
789    }
790}
791
792impl From<&[u8; 32]> for &U {
793    fn from(x: &[u8; 32]) -> Self {
794        unsafe { &*(x as *const [u8; 32] as *const U) }
795    }
796}
797
798impl From<[u8; 32]> for U {
799    fn from(x: [u8; 32]) -> Self {
800        U(x)
801    }
802}
803
804impl Deref for U {
805    type Target = [u8; 32];
806
807    fn deref(&self) -> &Self::Target {
808        &self.0
809    }
810}
811
812impl DerefMut for U {
813    fn deref_mut(&mut self) -> &mut Self::Target {
814        &mut self.0
815    }
816}
817
818impl From<bool> for U {
819    fn from(x: bool) -> Self {
820        U::from(&[x as u8])
821    }
822}
823
824impl Zero for U {
825    fn zero() -> Self {
826        U::ZERO
827    }
828
829    fn is_zero(&self) -> bool {
830        self.0.iter().all(|&b| b == 0)
831    }
832}
833
834impl Default for U {
835    fn default() -> Self {
836        U::ZERO
837    }
838}
839
840impl One for U {
841    fn one() -> Self {
842        U::ONE
843    }
844}
845
846impl Index<usize> for U {
847    type Output = u8;
848
849    fn index(&self, index: usize) -> &Self::Output {
850        &self.0[index]
851    }
852}
853
854impl IndexMut<usize> for U {
855    fn index_mut(&mut self, index: usize) -> &mut Self::Output {
856        &mut self.0[index]
857    }
858}
859
860impl I {
861    fn is_neg(&self) -> bool {
862        self.0[0] & 0x80 != 0
863    }
864
865    pub fn is_zero(&self) -> bool {
866        *self == Self::ZERO
867    }
868
869    pub fn is_some(&self) -> bool {
870        !self.is_zero()
871    }
872
873    pub fn as_slice(&self) -> &[u8; 32] {
874        &self.0
875    }
876
877    fn neg(&self) -> Self {
878        let x = wrapping_add(&U(self.0.map(|b| !b)), &U::ONE);
879        I(x.0)
880    }
881
882    fn abs(self) -> U {
883        if self.is_neg() {
884            U(self.neg().0)
885        } else {
886            U(self.0)
887        }
888    }
889}
890
891macro_rules! from_slices {
892    ($($n:expr),+ $(,)?) => {
893        $(
894            impl From<&[u8; $n]> for U {
895                fn from(x: &[u8; $n]) -> Self {
896                    let mut b = [0u8; 32];
897                    b[32 - $n..].copy_from_slice(x);
898                    U(b)
899                }
900            }
901
902            impl From<[u8; $n]> for U {
903                fn from(x: [u8; $n]) -> Self {
904                    U::from(&x)
905                }
906            }
907
908            impl From<U> for [u8; $n] {
909                fn from(x: U) -> Self {
910                    unsafe { *(x.as_ptr().add(32 - $n) as *const [u8; $n]) }
911                }
912            }
913        )+
914    };
915}
916
917from_slices!(
918    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,
919    27, 28, 29, 30, 31
920);
921
922impl From<&U> for Address {
923    fn from(x: &U) -> Self {
924        (*x).into()
925    }
926}
927
928macro_rules! from_ints {
929    ($($t:ty),+ $(,)?) => {
930        $(
931            impl From<$t> for U {
932                fn from(x: $t) -> Self {
933                    let mut b = [0u8; 32];
934                    b[32 - core::mem::size_of::<$t>()..].copy_from_slice(&x.to_be_bytes());
935                    U(b)
936                }
937            }
938
939            impl From<U> for $t {
940                fn from(x: U) -> Self {
941                    Self::from_be_bytes(x.into())
942                }
943            }
944        )+
945    };
946}
947
948from_ints! { u8, u16, u32, u64, u128, usize }
949
950impl From<I> for [u8; 32] {
951    fn from(x: I) -> Self {
952        x.0
953    }
954}
955
956impl From<[u8; 32]> for I {
957    fn from(x: [u8; 32]) -> Self {
958        I(x)
959    }
960}
961
962fn i_add(x: &I, y: &I) -> I {
963    I(wrapping_add(&U(x.0), &U(y.0)).0)
964}
965
966fn i_sub(x: &I, y: &I) -> I {
967    I(wrapping_sub(&U(x.0), &U(y.0)).0)
968}
969
970fn i_mul(x: &I, y: &I) -> I {
971    let result = wrapping_mul(&U(x.0), &U(y.0));
972    I(result.0)
973}
974
975fn i_div(x: &I, y: &I) -> I {
976    let r = wrapping_div(&x.abs(), &y.abs());
977    if x.is_neg() ^ y.is_neg() {
978        I(r.0).neg()
979    } else {
980        I(r.0)
981    }
982}
983
984fn i_rem(x: &I, y: &I) -> I {
985    let r = modd(&x.abs(), &y.abs());
986    if x.is_neg() {
987        I(r.0).neg()
988    } else {
989        I(r.0)
990    }
991}
992
993impl Add for I {
994    type Output = I;
995    fn add(self, rhs: I) -> I {
996        i_add(&self, &rhs)
997    }
998}
999
1000impl Add for &I {
1001    type Output = I;
1002    fn add(self, rhs: &I) -> I {
1003        i_add(self, rhs)
1004    }
1005}
1006
1007impl Sub for I {
1008    type Output = I;
1009    fn sub(self, rhs: I) -> I {
1010        i_sub(&self, &rhs)
1011    }
1012}
1013
1014impl Sub for &I {
1015    type Output = I;
1016    fn sub(self, rhs: &I) -> I {
1017        i_sub(self, rhs)
1018    }
1019}
1020
1021impl Mul for I {
1022    type Output = I;
1023    fn mul(self, rhs: I) -> I {
1024        i_mul(&self, &rhs)
1025    }
1026}
1027
1028impl Mul for &I {
1029    type Output = I;
1030    fn mul(self, rhs: &I) -> I {
1031        i_mul(self, rhs)
1032    }
1033}
1034
1035impl Div for I {
1036    type Output = I;
1037    fn div(self, rhs: I) -> I {
1038        i_div(&self, &rhs)
1039    }
1040}
1041
1042impl Div for &I {
1043    type Output = I;
1044    fn div(self, rhs: &I) -> I {
1045        i_div(self, rhs)
1046    }
1047}
1048
1049impl Rem for I {
1050    type Output = I;
1051    fn rem(self, rhs: I) -> I {
1052        i_rem(&self, &rhs)
1053    }
1054}
1055
1056impl Eq for I {}
1057
1058impl PartialOrd for I {
1059    fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
1060        Some(self.cmp(other))
1061    }
1062}
1063
1064impl Ord for I {
1065    fn cmp(&self, other: &Self) -> Ordering {
1066        let self_sign = self.0[0] & 0x80;
1067        let other_sign = other.0[0] & 0x80;
1068        match (self_sign, other_sign) {
1069            (0, 0x80) => Ordering::Greater,
1070            (0x80, 0) => Ordering::Less,
1071            _ => self.0.cmp(&other.0),
1072        }
1073    }
1074}
1075
1076impl Rem for &I {
1077    type Output = I;
1078    fn rem(self, rhs: &I) -> I {
1079        i_rem(self, rhs)
1080    }
1081}
1082
1083impl I {
1084    pub const ZERO: Self = I([0u8; 32]);
1085
1086    pub const ONE: Self = I([
1087        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,
1088        0, 1,
1089    ]);
1090}
1091
1092impl Zero for I {
1093    fn zero() -> Self {
1094        I::ZERO
1095    }
1096    fn is_zero(&self) -> bool {
1097        self.0.iter().all(|&b| b == 0)
1098    }
1099}
1100
1101impl Default for I {
1102    fn default() -> Self {
1103        I::ZERO
1104    }
1105}
1106
1107impl One for I {
1108    fn one() -> Self {
1109        I::ONE
1110    }
1111}
1112
1113#[test]
1114fn test_is_zeroes() {
1115    assert!(U::ZERO.is_zero());
1116    assert!(U::ONE.is_some());
1117    assert!(I::ZERO.is_zero());
1118    assert!(I::ONE.is_some());
1119}
1120
1121#[cfg(all(
1122    test,
1123    feature = "alloy-enabled",
1124    feature = "proptest-enabled",
1125    feature = "std",
1126    not(target_arch = "wasm32")
1127))]
1128mod test {
1129    use proptest::prelude::*;
1130
1131    use super::*;
1132
1133    fn u_from_u64(value: u64) -> U {
1134        U::from(value)
1135    }
1136
1137    proptest! {
1138        #[test]
1139        fn wrapping_div_b_zero_denominator_yields_zero(numerator in any::<[u8; 4]>()) {
1140            let zero = [0u8; 4];
1141            prop_assert_eq!(wrapping_div_quo_rem_b::<4>(&numerator, &zero).0, zero);
1142        }
1143
1144        #[test]
1145        fn wrapping_div_b_matches_integer_division(
1146            numerator in any::<[u8; 4]>(),
1147            denominator in any::<[u8; 4]>().prop_filter("denominator must be non-zero", |d| *d != [0u8; 4])
1148        ) {
1149            let numerator_u32 = u32::from_be_bytes(numerator);
1150            let denominator_u32 = u32::from_be_bytes(denominator);
1151            let expected = numerator_u32 / denominator_u32;
1152            prop_assert_eq!(
1153                wrapping_div_quo_rem_b::<4>(&numerator, &denominator).0,
1154                expected.to_be_bytes()
1155            );
1156        }
1157
1158        #[test]
1159        fn wrapping_mod_b_matches_integer_modulo(
1160            numerator in any::<[u8; 4]>(),
1161            denominator in any::<[u8; 4]>().prop_filter("denominator must be non-zero", |d| *d != [0u8; 4])
1162        ) {
1163            let numerator_u32 = u32::from_be_bytes(numerator);
1164            let denominator_u32 = u32::from_be_bytes(denominator);
1165            let expected = numerator_u32 % denominator_u32;
1166            prop_assert_eq!(
1167                wrapping_div_quo_rem_b::<4>(&numerator, &denominator).1,
1168                expected.to_be_bytes()
1169            );
1170        }
1171
1172        #[test]
1173        fn wrapping_add_b_handles_carry(lhs in any::<[u8; 4]>(), rhs in any::<[u8; 4]>()) {
1174            let lhs_u32 = u32::from_be_bytes(lhs);
1175            let rhs_u32 = u32::from_be_bytes(rhs);
1176            let expected = lhs_u32.wrapping_add(rhs_u32);
1177            prop_assert_eq!(wrapping_add_b::<4>(&lhs, &rhs), expected.to_be_bytes());
1178        }
1179
1180        #[test]
1181        fn wrapping_sub_b_handles_borrow(lhs in any::<[u8; 4]>(), rhs in any::<[u8; 4]>()) {
1182            let lhs_u32 = u32::from_be_bytes(lhs);
1183            let rhs_u32 = u32::from_be_bytes(rhs);
1184            let expected = lhs_u32.wrapping_sub(rhs_u32);
1185            prop_assert_eq!(wrapping_sub_b::<4>(&lhs, &rhs), expected.to_be_bytes());
1186        }
1187
1188        #[test]
1189        fn wrapping_mul_b_matches_wrapping_arithmetic(lhs in any::<[u8; 32]>(), rhs in any::<[u8; 32]>()) {
1190            let lhs_u = U::from(lhs);
1191            let rhs_u = U::from(rhs);
1192            let expected = lhs_u.wrapping_mul(&rhs_u);
1193            prop_assert_eq!(wrapping_mul_b::<32>(&lhs, &rhs), expected.0);
1194        }
1195
1196        #[test]
1197        fn const_wrapping_div_agrees_with_wrapping_div_b(
1198            numerator in any::<[u8; 32]>(),
1199            denominator in any::<[u8; 32]>().prop_filter("denominator must be non-zero", |d| *d != [0u8; 32])
1200        ) {
1201            let numerator_u = U::from(numerator);
1202            let denominator_u = U::from(denominator);
1203            prop_assert_eq!(
1204                const_wrapping_div(&numerator_u, &denominator_u).0,
1205                wrapping_div_quo_rem_b::<32>(&numerator, &denominator).0
1206            );
1207        }
1208
1209        #[test]
1210        fn u_predicates_track_zero_and_true(bytes in any::<[u8; 32]>()) {
1211            let value = U::from(bytes);
1212            let is_zero = bytes.iter().all(|&b| b == 0);
1213            prop_assert_eq!(value.is_zero(), is_zero);
1214            prop_assert_eq!(value.is_some(), !is_zero);
1215            prop_assert_eq!(value.is_true(), bytes[31] == 1);
1216        }
1217
1218        #[test]
1219        fn mul_div_returns_expected_quotient_and_carry(
1220            lhs in any::<u64>(),
1221            rhs in any::<u64>(),
1222            denom in any::<u64>().prop_filter("denominator must be non-zero", |d| *d != 0)
1223        ) {
1224            let lhs_u = u_from_u64(lhs);
1225            let rhs_u = u_from_u64(rhs);
1226            let denom_u = u_from_u64(denom);
1227            let (q, carry) = lhs_u.mul_div(&rhs_u, &denom_u).expect("division should succeed");
1228
1229            let product = (lhs as u128) * (rhs as u128);
1230            let denom_u128 = denom as u128;
1231            let expected_q = product / denom_u128;
1232            let expected_rem = product % denom_u128;
1233
1234            prop_assert_eq!(u128::from(q), expected_q);
1235            prop_assert_eq!(carry, expected_rem != 0);
1236        }
1237
1238        #[test]
1239        fn mul_div_round_up_accounts_for_carry(
1240            lhs in any::<u64>(),
1241            rhs in any::<u64>(),
1242            denom in any::<u64>().prop_filter("denominator must be non-zero", |d| *d != 0)
1243        ) {
1244            let lhs_u = u_from_u64(lhs);
1245            let rhs_u = u_from_u64(rhs);
1246            let denom_u = u_from_u64(denom);
1247            let rounded = lhs_u
1248                .mul_div_round_up(&rhs_u, &denom_u)
1249                .expect("rounding should succeed");
1250
1251            let product = (lhs as u128) * (rhs as u128);
1252            let denom_u128 = denom as u128;
1253            let expected = if product % denom_u128 == 0 {
1254                product / denom_u128
1255            } else {
1256                (product / denom_u128) + 1
1257            };
1258
1259            prop_assert_eq!(u128::from(rounded), expected);
1260        }
1261
1262        #[test]
1263        fn test_u_is_zero(x in any::<[u8; 32]>()) {
1264            let x = U::from(x);
1265            let ex = U256::from_be_bytes(x.0);
1266            assert_eq!(ex.is_zero(), x.is_zero());
1267        }
1268
1269        #[test]
1270        fn test_u_div(x in any::<U>(), y in any::<U>()) {
1271            let ex = U256::from_be_bytes(x.0);
1272            let ey = U256::from_be_bytes(y.0);
1273            assert_eq!((ex.wrapping_div(ey)).to_be_bytes(), x.wrapping_div(&y).0);
1274        }
1275
1276        #[test]
1277        fn test_u_mul(x in any::<U>(), y in any::<U>()) {
1278            let ex = U256::from_be_bytes(x.0);
1279            let ey = U256::from_be_bytes(y.0);
1280            assert_eq!((ex.wrapping_mul(ey)).to_be_bytes(), wrapping_mul(&x,  &y).0);
1281        }
1282
1283        #[test]
1284        fn test_u_mod(x in any::<U>(), y in any::<U>()) {
1285            let ex = U256::from_be_bytes(x.0);
1286            let ey = U256::from_be_bytes(y.0);
1287            assert_eq!((ex % ey).to_be_bytes(), (x % y).0);
1288        }
1289
1290        #[test]
1291        fn test_u_add(x in any::<U>(), y in any::<U>()) {
1292            let ex = U256::from_be_bytes(x.0);
1293            let ey = U256::from_be_bytes(y.0);
1294            let e = U::from(ex.wrapping_add(ey).to_be_bytes::<32>());
1295            assert_eq!(e, x.wrapping_add(&y), "{e} != {}", x + y);
1296        }
1297
1298        #[test]
1299        fn test_u_sub(x in any::<U>(), y in any::<U>()) {
1300            let ex = U256::from_be_bytes(x.0);
1301            let ey = U256::from_be_bytes(y.0);
1302            assert_eq!((ex.wrapping_sub(ey)).to_be_bytes(), x.wrapping_sub(&y).0);
1303        }
1304
1305        #[test]
1306        fn test_u_cmp(x in any::<U>(), y in any::<U>()) {
1307            let ex = U256::from_be_bytes(x.0);
1308            let ey = U256::from_be_bytes(y.0);
1309            assert_eq!(ex.cmp(&ey), x.cmp(&y));
1310        }
1311
1312        #[test]
1313        #[cfg(feature = "alloc")]
1314        fn test_u_str(x in any::<U>()) {
1315            assert_eq!(U256::from_be_bytes(x.0).to_string(), x.to_string());
1316        }
1317
1318        #[test]
1319        fn test_i_is_zero(x in any::<U>()) {
1320            let ex = I256::from_be_bytes(x.0);
1321            assert_eq!(ex.is_zero(), x.is_zero());
1322        }
1323
1324        #[test]
1325        fn test_i_div(x in any::<I>(), y in any::<I>()) {
1326            let ex = I256::from_be_bytes(x.0);
1327            let ey = I256::from_be_bytes(y.0);
1328            assert_eq!((ex / ey).to_be_bytes(), (x / y).0);
1329        }
1330
1331        #[test]
1332        fn test_i_mul(x in any::<I>(), y in any::<I>()) {
1333            let ex = I256::from_be_bytes(x.0);
1334            let ey = I256::from_be_bytes(y.0);
1335            assert_eq!((ex.wrapping_mul(ey)).to_be_bytes(), (x * y).0);
1336        }
1337
1338        #[test]
1339        fn test_i_mod(x in any::<I>(), y in any::<I>()) {
1340            let ex = I256::from_be_bytes(x.0);
1341            let ey = I256::from_be_bytes(y.0);
1342            assert_eq!((ex % ey).to_be_bytes(), (x % y).0);
1343        }
1344
1345        #[test]
1346        fn test_i_add(x in any::<I>(), y in any::<I>()) {
1347            let ex = I256::from_be_bytes(x.0);
1348            let ey = I256::from_be_bytes(y.0);
1349            assert_eq!((ex.wrapping_add(ey)).to_be_bytes(), (x + y).0);
1350        }
1351
1352        #[test]
1353        fn test_i_sub(x in any::<I>(), y in any::<I>()) {
1354            let ex = I256::from_be_bytes(x.0);
1355            let ey = I256::from_be_bytes(y.0);
1356            assert_eq!((ex.wrapping_sub(ey)).to_be_bytes(), (x - y).0);
1357        }
1358
1359        #[test]
1360        fn test_i_cmp(x in any::<I>(), y in any::<I>()) {
1361            let ex = I256::from_be_bytes(x.0);
1362            let ey = I256::from_be_bytes(y.0);
1363            assert_eq!(ex.cmp(&ey), x.cmp(&y));
1364        }
1365
1366        #[test]
1367        fn test_u_u8(x in any::<u8>()) {
1368            let mut b = [0u8; 32];
1369            b[32-std::mem::size_of::<u8>()..].copy_from_slice(&x.to_be_bytes());
1370            assert_eq!(&U256::from_be_bytes(b).to_be_bytes(), U::from(x).as_slice());
1371        }
1372
1373        #[test]
1374        fn test_u_u16(x in any::<u16>()) {
1375            let mut b = [0u8; 32];
1376            b[32-std::mem::size_of::<u16>()..].copy_from_slice(&x.to_be_bytes());
1377            assert_eq!(&U256::from_be_bytes(b).to_be_bytes(), U::from(x).as_slice());
1378        }
1379
1380        #[test]
1381        fn test_u_u32(x in any::<u32>()) {
1382            let mut b = [0u8; 32];
1383            b[32-std::mem::size_of::<u32>()..].copy_from_slice(&x.to_be_bytes());
1384            assert_eq!(&U256::from_be_bytes(b).to_be_bytes(), U::from(x).as_slice());
1385        }
1386
1387        #[test]
1388        fn test_u_u64(x in any::<u64>()) {
1389            let mut b = [0u8; 32];
1390            b[32-std::mem::size_of::<u64>()..].copy_from_slice(&x.to_be_bytes());
1391            assert_eq!(&U256::from_be_bytes(b).to_be_bytes(), U::from(x).as_slice());
1392        }
1393
1394        #[test]
1395        fn test_u_u128(x in any::<u128>()) {
1396            let mut b = [0u8; 32];
1397            b[32-std::mem::size_of::<u128>()..].copy_from_slice(&x.to_be_bytes());
1398            assert_eq!(&U256::from_be_bytes(b).to_be_bytes(), U::from(x).as_slice());
1399        }
1400
1401        #[test]
1402        fn test_to_and_from_addrs(x in any::<Address>()) {
1403            let y: Address = U::from(x).into();
1404            assert_eq!(x, y)
1405        }
1406
1407        #[test]
1408        fn test_u_conv_to_and_from_u8(x in any::<u8>()) {
1409            assert_eq!(x.wrapping_add(1), U::from(x).wrapping_add(&U::ONE).into());
1410        }
1411    }
1412}