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 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(wrapping_div(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(wrapping_sub(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 cfg_if::cfg_if! {
231 if #[cfg(debug_assertions)] {
232 checked_add(&self, &rhs).expect("overflow when add")
233 } else {
234 wrapping_add(&self, &rhs)
235 }
236 }
237 }
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 Sub for U {
255 type Output = U;
256
257 fn sub(self, rhs: U) -> U {
258 cfg_if::cfg_if! {
259 if #[cfg(debug_assertions)] {
260 checked_sub(&self, &rhs).expect("overflow when sub")
261 } else {
262 wrapping_sub(&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 Mul for U {
283 type Output = U;
284
285 fn mul(self, rhs: U) -> U {
286 cfg_if::cfg_if! {
287 if #[cfg(debug_assertions)] {
288 checked_mul(&self, &rhs).expect("overflow when mul")
289 } else {
290 wrapping_mul(&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 Div for U {
311 type Output = U;
312
313 fn div(self, rhs: U) -> U {
314 cfg_if::cfg_if! {
315 if #[cfg(debug_assertions)] {
316 checked_div(&self, &rhs).expect("overflow when div")
317 } else {
318 wrapping_div(&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 Rem for U {
339 type Output = U;
340
341 fn rem(self, rhs: U) -> U {
342 modd(&self, &rhs)
343 }
344}
345
346impl Rem for &U {
347 type Output = U;
348
349 fn rem(self, rhs: &U) -> U {
350 modd(self, rhs)
351 }
352}
353
354impl Eq for U {}
355
356impl PartialOrd for U {
357 fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
358 Some(self.cmp(other))
359 }
360}
361
362impl Ord for U {
363 fn cmp(&self, other: &Self) -> Ordering {
364 self.0.cmp(&other.0)
365 }
366}
367
368impl U {
369 pub const ZERO: Self = U([0u8; 32]);
370
371 pub const MAX: Self = U([u8::MAX; 32]);
372
373 pub const ONE: Self = U([
374 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,
375 0, 1,
376 ]);
377
378 pub fn is_true(&self) -> bool {
379 self.0[31] == 1
380 }
381
382 pub fn is_zero(&self) -> bool {
383 *self == Self::ZERO
384 }
385
386 pub fn is_some(&self) -> bool {
387 !self.is_zero()
388 }
389
390 pub fn as_slice(&self) -> &[u8; 32] {
391 &self.0
392 }
393
394 pub fn wrapping_add(&self, y: &Self) -> U {
395 wrapping_add(self, y)
396 }
397
398 pub fn checked_add(&self, y: &Self) -> Option<Self> {
399 checked_add(self, y)
400 }
401
402 pub fn wrapping_sub(&self, y: &Self) -> U {
403 wrapping_sub(self, y)
404 }
405
406 pub fn checked_sub(&self, y: &Self) -> Option<Self> {
407 checked_sub(self, y)
408 }
409
410 pub fn wrapping_mul(&self, y: &Self) -> U {
411 wrapping_mul(self, y)
412 }
413
414 pub fn checked_mul(&self, y: &Self) -> Option<Self> {
415 checked_mul(self, y)
416 }
417
418 pub fn wrapping_div(&self, y: &Self) -> U {
419 wrapping_div(self, y)
420 }
421
422 pub fn checked_div(&self, y: &Self) -> Option<Self> {
423 checked_div(self, y)
424 }
425
426 pub fn mul_mod(&self, y: &Self, z: &Self) -> Self {
427 let mut b = self.0;
428 unsafe { math_mul_mod(b.as_mut_ptr(), y.as_ptr(), z.as_ptr()) }
429 Self(b)
430 }
431
432 pub fn add_mod(&self, y: &Self, z: &Self) -> Self {
433 let mut b = self.0;
434 unsafe { math_add_mod(b.as_mut_ptr(), y.as_ptr(), z.as_ptr()) }
435 Self(b)
436 }
437
438 pub fn widening_mul(&self, y: &U) -> (U, U) {
439 let shift_128 = &U([
440 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,
441 0, 0, 0,
442 ]);
443 let x_hi = self / shift_128;
444 let x_lo = self % shift_128;
445 let y_hi = y / shift_128;
446 let y_lo = y % shift_128;
447 let t0 = x_lo.mul_mod(&y_lo, &U::MAX);
448 let t1 = x_hi.mul_mod(&y_lo, &U::MAX);
449 let t2 = x_lo.mul_mod(&y_hi, &U::MAX);
450 let t3 = x_hi.mul_mod(&y_hi, &U::MAX);
451 let t0_hi = &t0 / shift_128;
452 let t0_lo = &t0 % shift_128;
453 let t1_hi = &t1 / shift_128;
454 let t1_lo = &t1 % shift_128;
455 let t2_hi = &t2 / shift_128;
456 let t2_lo = &t2 % shift_128;
457 let mid = (t0_hi + t1_lo) + t2_lo;
458 let mid_hi = &mid / shift_128;
459 let mid_lo = &mid % shift_128;
460 let mid_lo_shifted = mid_lo.mul_mod(shift_128, &U::MAX);
461 let out_low = t0_lo + mid_lo_shifted;
462 let out_high = t3 + t1_hi + t2_hi + mid_hi;
463 (out_high, out_low)
464 }
465
466 pub fn mul_div(&self, _y: &U, _denom: &U) -> Option<(U, bool)> {
467 todo!()
468 }
469
470 pub fn mul_div_round_up(&self, y: &U, denom_and_rem: &U) -> Option<U> {
471 let (x, y) = self.mul_div(y, denom_and_rem)?;
472 Some(if y { x + U::ONE } else { x })
473 }
474}
475
476#[cfg(feature = "std")]
477impl Display for U {
478 fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
479 let mut result = vec![0u8];
480 for &byte in &self.0 {
481 let mut carry = byte as u32;
482 for digit in result.iter_mut() {
483 let temp = (*digit as u32) * 256 + carry;
484 *digit = (temp % 10) as u8;
485 carry = temp / 10;
486 }
487 while carry > 0 {
488 result.push((carry % 10) as u8);
489 carry /= 10;
490 }
491 }
492 if result.iter().all(|&d| d == 0) {
493 return write!(f, "0");
494 }
495 write!(
496 f,
497 "{}",
498 result
499 .iter()
500 .rev()
501 .skip_while(|&&d| d == 0)
502 .map(|&d| (d + b'0') as char)
503 .collect::<String>()
504 )
505 }
506}
507
508impl From<U> for [u8; 32] {
509 fn from(x: U) -> Self {
510 x.0
511 }
512}
513
514impl From<&[u8; 32]> for &U {
515 fn from(x: &[u8; 32]) -> Self {
516 unsafe { &*(x as *const [u8; 32] as *const U) }
517 }
518}
519
520impl From<[u8; 32]> for U {
521 fn from(x: [u8; 32]) -> Self {
522 U(x)
523 }
524}
525
526impl Deref for U {
527 type Target = [u8; 32];
528
529 fn deref(&self) -> &Self::Target {
530 &self.0
531 }
532}
533
534impl DerefMut for U {
535 fn deref_mut(&mut self) -> &mut Self::Target {
536 &mut self.0
537 }
538}
539
540impl From<bool> for U {
541 fn from(x: bool) -> Self {
542 U::from(&[x as u8])
543 }
544}
545
546impl Zero for U {
547 fn zero() -> Self {
548 U::ZERO
549 }
550
551 fn is_zero(&self) -> bool {
552 self.0.iter().all(|&b| b == 0)
553 }
554}
555
556impl Default for U {
557 fn default() -> Self {
558 U::ZERO
559 }
560}
561
562impl One for U {
563 fn one() -> Self {
564 U::ONE
565 }
566}
567
568impl Index<usize> for U {
569 type Output = u8;
570
571 fn index(&self, index: usize) -> &Self::Output {
572 &self.0[index]
573 }
574}
575
576impl I {
577 fn is_neg(&self) -> bool {
578 self.0[0] & 0x80 != 0
579 }
580
581 pub fn is_zero(&self) -> bool {
582 *self == Self::ZERO
583 }
584
585 pub fn is_some(&self) -> bool {
586 !self.is_zero()
587 }
588
589 pub fn as_slice(&self) -> &[u8; 32] {
590 &self.0
591 }
592
593 fn neg(&self) -> Self {
594 let x = wrapping_add(&U(self.0.map(|b| !b)), &U::ONE);
595 I(x.0)
596 }
597
598 fn abs(self) -> U {
599 if self.is_neg() {
600 U(self.neg().0)
601 } else {
602 U(self.0)
603 }
604 }
605}
606
607macro_rules! from_slices {
608 ($($n:expr),+ $(,)?) => {
609 $(
610 impl From<&[u8; $n]> for U {
611 fn from(x: &[u8; $n]) -> Self {
612 let mut b = [0u8; 32];
613 b[32 - $n..].copy_from_slice(x);
614 U(b)
615 }
616 }
617
618 impl From<[u8; $n]> for U {
619 fn from(x: [u8; $n]) -> Self {
620 U::from(&x)
621 }
622 }
623
624 impl From<U> for [u8; $n] {
625 fn from(x: U) -> Self {
626 unsafe { *(x.as_ptr().add(32 - $n) as *const [u8; $n]) }
627 }
628 }
629 )+
630 };
631}
632
633from_slices!(
634 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,
635 27, 28, 29, 30, 31
636);
637
638macro_rules! from_ints {
639 ($($t:ty),+ $(,)?) => {
640 $(
641 impl From<$t> for U {
642 fn from(x: $t) -> Self {
643 let mut b = [0u8; 32];
644 b[32 - core::mem::size_of::<$t>()..].copy_from_slice(&x.to_be_bytes());
645 U(b)
646 }
647 }
648
649 impl From<U> for $t {
650 fn from(x: U) -> Self {
651 Self::from_be_bytes(x.into())
652 }
653 }
654 )+
655 };
656}
657
658from_ints! { u8, u16, u32, u64, u128 }
659
660impl From<I> for [u8; 32] {
661 fn from(x: I) -> Self {
662 x.0
663 }
664}
665
666impl From<[u8; 32]> for I {
667 fn from(x: [u8; 32]) -> Self {
668 I(x)
669 }
670}
671
672fn i_add(x: &I, y: &I) -> I {
673 I(wrapping_add(&U(x.0), &U(y.0)).0)
674}
675
676fn i_sub(x: &I, y: &I) -> I {
677 I(wrapping_sub(&U(x.0), &U(y.0)).0)
678}
679
680fn i_mul(x: &I, y: &I) -> I {
681 let result = wrapping_mul(&U(x.0), &U(y.0));
682 I(result.0)
683}
684
685fn i_div(x: &I, y: &I) -> I {
686 let r = wrapping_div(&x.abs(), &y.abs());
687 if x.is_neg() ^ y.is_neg() {
688 I(r.0).neg()
689 } else {
690 I(r.0)
691 }
692}
693
694fn i_rem(x: &I, y: &I) -> I {
695 let r = modd(&x.abs(), &y.abs());
696 if x.is_neg() {
697 I(r.0).neg()
698 } else {
699 I(r.0)
700 }
701}
702
703impl Add for I {
704 type Output = I;
705 fn add(self, rhs: I) -> I {
706 i_add(&self, &rhs)
707 }
708}
709
710impl Add for &I {
711 type Output = I;
712 fn add(self, rhs: &I) -> I {
713 i_add(self, rhs)
714 }
715}
716
717impl Sub for I {
718 type Output = I;
719 fn sub(self, rhs: I) -> I {
720 i_sub(&self, &rhs)
721 }
722}
723
724impl Sub for &I {
725 type Output = I;
726 fn sub(self, rhs: &I) -> I {
727 i_sub(self, rhs)
728 }
729}
730
731impl Mul for I {
732 type Output = I;
733 fn mul(self, rhs: I) -> I {
734 i_mul(&self, &rhs)
735 }
736}
737
738impl Mul for &I {
739 type Output = I;
740 fn mul(self, rhs: &I) -> I {
741 i_mul(self, rhs)
742 }
743}
744
745impl Div for I {
746 type Output = I;
747 fn div(self, rhs: I) -> I {
748 i_div(&self, &rhs)
749 }
750}
751
752impl Div for &I {
753 type Output = I;
754 fn div(self, rhs: &I) -> I {
755 i_div(self, rhs)
756 }
757}
758
759impl Rem for I {
760 type Output = I;
761 fn rem(self, rhs: I) -> I {
762 i_rem(&self, &rhs)
763 }
764}
765
766impl Eq for I {}
767
768impl PartialOrd for I {
769 fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
770 Some(self.cmp(other))
771 }
772}
773
774impl Ord for I {
775 fn cmp(&self, other: &Self) -> Ordering {
776 let self_sign = self.0[0] & 0x80;
777 let other_sign = other.0[0] & 0x80;
778 match (self_sign, other_sign) {
779 (0, 0x80) => Ordering::Greater,
780 (0x80, 0) => Ordering::Less,
781 _ => self.0.cmp(&other.0),
782 }
783 }
784}
785
786impl Rem for &I {
787 type Output = I;
788 fn rem(self, rhs: &I) -> I {
789 i_rem(self, rhs)
790 }
791}
792
793impl I {
794 pub const ZERO: Self = I([0u8; 32]);
795
796 pub const ONE: Self = I([
797 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,
798 0, 1,
799 ]);
800}
801
802impl Zero for I {
803 fn zero() -> Self {
804 I::ZERO
805 }
806 fn is_zero(&self) -> bool {
807 self.0.iter().all(|&b| b == 0)
808 }
809}
810
811impl Default for I {
812 fn default() -> Self {
813 I::ZERO
814 }
815}
816
817impl One for I {
818 fn one() -> Self {
819 I::ONE
820 }
821}
822
823#[test]
824fn test_is_zeroes() {
825 assert!(U::ZERO.is_zero());
826 assert!(U::ONE.is_some());
827 assert!(I::ZERO.is_zero());
828 assert!(I::ONE.is_some());
829}
830
831#[cfg(all(test, feature = "alloy-enabled", feature = "std"))]
832mod test {
833 use proptest::prelude::*;
834
835 use super::*;
836
837 proptest! {
838 #[test]
839 fn test_u_is_zero(x in any::<[u8; 32]>()) {
840 let x = U::from(x);
841 let ex = U256::from_be_bytes(x.0);
842 assert_eq!(ex.is_zero(), x.is_zero());
843 }
844
845 #[test]
846 fn test_u_div(x in any::<U>(), y in any::<U>()) {
847 let ex = U256::from_be_bytes(x.0);
848 let ey = U256::from_be_bytes(y.0);
849 assert_eq!((ex.wrapping_div(ey)).to_be_bytes(), x.wrapping_div(&y).0);
850 }
851
852 #[test]
853 fn test_u_mul(x in any::<U>(), y in any::<U>()) {
854 let ex = U256::from_be_bytes(x.0);
855 let ey = U256::from_be_bytes(y.0);
856 assert_eq!((ex.wrapping_mul(ey)).to_be_bytes(), wrapping_mul(&x, &y).0);
857 }
858
859 #[test]
860 fn test_u_mod(x in any::<U>(), y in any::<U>()) {
861 let ex = U256::from_be_bytes(x.0);
862 let ey = U256::from_be_bytes(y.0);
863 assert_eq!((ex % ey).to_be_bytes(), (x % y).0);
864 }
865
866 #[test]
867 fn test_u_add(x in any::<U>(), y in any::<U>()) {
868 let ex = U256::from_be_bytes(x.0);
869 let ey = U256::from_be_bytes(y.0);
870 let e = U::from(ex.wrapping_add(ey).to_be_bytes::<32>());
871 assert_eq!(e, x.wrapping_add(&y), "{e} != {}", x + y);
872 }
873
874 #[test]
875 fn test_u_sub(x in any::<U>(), y in any::<U>()) {
876 let ex = U256::from_be_bytes(x.0);
877 let ey = U256::from_be_bytes(y.0);
878 assert_eq!((ex.wrapping_sub(ey)).to_be_bytes(), x.wrapping_sub(&y).0);
879 }
880
881 #[test]
882 fn test_u_cmp(x in any::<U>(), y in any::<U>()) {
883 let ex = U256::from_be_bytes(x.0);
884 let ey = U256::from_be_bytes(y.0);
885 assert_eq!(ex.cmp(&ey), x.cmp(&y));
886 }
887
888 #[test]
889 #[cfg(feature = "alloc")]
890 fn test_u_str(x in any::<U>()) {
891 assert_eq!(U256::from_be_bytes(x.0).to_string(), x.to_string());
892 }
893
894 #[test]
895 fn test_i_is_zero(x in any::<U>()) {
896 let ex = I256::from_be_bytes(x.0);
897 assert_eq!(ex.is_zero(), x.is_zero());
898 }
899
900 #[test]
901 fn test_i_div(x in any::<I>(), y in any::<I>()) {
902 let ex = I256::from_be_bytes(x.0);
903 let ey = I256::from_be_bytes(y.0);
904 assert_eq!((ex / ey).to_be_bytes(), (x / y).0);
905 }
906
907 #[test]
908 fn test_i_mul(x in any::<I>(), y in any::<I>()) {
909 let ex = I256::from_be_bytes(x.0);
910 let ey = I256::from_be_bytes(y.0);
911 assert_eq!((ex.wrapping_mul(ey)).to_be_bytes(), (x * y).0);
912 }
913
914 #[test]
915 fn test_i_mod(x in any::<I>(), y in any::<I>()) {
916 let ex = I256::from_be_bytes(x.0);
917 let ey = I256::from_be_bytes(y.0);
918 assert_eq!((ex % ey).to_be_bytes(), (x % y).0);
919 }
920
921 #[test]
922 fn test_i_add(x in any::<I>(), y in any::<I>()) {
923 let ex = I256::from_be_bytes(x.0);
924 let ey = I256::from_be_bytes(y.0);
925 assert_eq!((ex.wrapping_add(ey)).to_be_bytes(), (x + y).0);
926 }
927
928 #[test]
929 fn test_i_sub(x in any::<I>(), y in any::<I>()) {
930 let ex = I256::from_be_bytes(x.0);
931 let ey = I256::from_be_bytes(y.0);
932 assert_eq!((ex.wrapping_sub(ey)).to_be_bytes(), (x - y).0);
933 }
934
935 #[test]
936 fn test_i_cmp(x in any::<I>(), y in any::<I>()) {
937 let ex = I256::from_be_bytes(x.0);
938 let ey = I256::from_be_bytes(y.0);
939 assert_eq!(ex.cmp(&ey), x.cmp(&y));
940 }
941
942 #[test]
943 fn test_u_u8(x in any::<u8>()) {
944 let mut b = [0u8; 32];
945 b[32-std::mem::size_of::<u8>()..].copy_from_slice(&x.to_be_bytes());
946 assert_eq!(&U256::from_be_bytes(b).to_be_bytes(), U::from(x).as_slice());
947 }
948
949 #[test]
950 fn test_u_u16(x in any::<u16>()) {
951 let mut b = [0u8; 32];
952 b[32-std::mem::size_of::<u16>()..].copy_from_slice(&x.to_be_bytes());
953 assert_eq!(&U256::from_be_bytes(b).to_be_bytes(), U::from(x).as_slice());
954 }
955
956 #[test]
957 fn test_u_u32(x in any::<u32>()) {
958 let mut b = [0u8; 32];
959 b[32-std::mem::size_of::<u32>()..].copy_from_slice(&x.to_be_bytes());
960 assert_eq!(&U256::from_be_bytes(b).to_be_bytes(), U::from(x).as_slice());
961 }
962
963 #[test]
964 fn test_u_u64(x in any::<u64>()) {
965 let mut b = [0u8; 32];
966 b[32-std::mem::size_of::<u64>()..].copy_from_slice(&x.to_be_bytes());
967 assert_eq!(&U256::from_be_bytes(b).to_be_bytes(), U::from(x).as_slice());
968 }
969
970 #[test]
971 fn test_u_u128(x in any::<u128>()) {
972 let mut b = [0u8; 32];
973 b[32-std::mem::size_of::<u128>()..].copy_from_slice(&x.to_be_bytes());
974 assert_eq!(&U256::from_be_bytes(b).to_be_bytes(), U::from(x).as_slice());
975 }
976
977 #[test]
978 fn test_to_and_from_addrs(x in any::<Address>()) {
979 let y: [u8; 20] = U::from(x).into();
980 assert_eq!(x, y)
981 }
982
983 #[test]
984 fn test_u_conv_to_and_from_u8(x in any::<u8>()) {
985 assert_eq!(x.wrapping_add(1), U::from(x).wrapping_add(&U::ONE).into());
986 }
987 }
988}