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