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 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 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}