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