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_quo_rem_b<const C: usize>(x: &[u8; C], denom: &[u8; C]) -> ([u8; C], [u8; C]) {
108 if denom == &[0u8; C] {
109 return ([0u8; C], [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, r)
131}
132
133pub fn const_wrapping_div(x: &U, y: &U) -> U {
134 U(wrapping_div_quo_rem_b::<32>(&x.0, &y.0).0)
135}
136
137#[cfg_attr(test, mutants::skip)]
138pub fn checked_div(x: &U, y: &U) -> Option<U> {
139 if y.is_zero() {
140 None
141 } else {
142 Some(wrapping_div(x, y))
143 }
144}
145
146pub fn modd(x: &U, y: &U) -> U {
147 let mut b = *x;
148 unsafe { math_mod(b.as_mut_ptr(), y.as_ptr()) }
149 b
150}
151
152const fn wrapping_add_b<const C: usize>(x: &[u8; C], y: &[u8; C]) -> [u8; C] {
153 let mut r = [0u8; C];
154 let mut c = 0;
155 let mut i = C - 1;
156 loop {
157 let s = x[i] as u16 + y[i] as u16 + c;
158 r[i] = s as u8;
159 c = s >> 8;
160 if i == 0 {
161 break;
162 }
163 i -= 1;
164 }
165 r
166}
167
168pub const fn wrapping_add(x: &U, y: &U) -> U {
169 U(wrapping_add_b(&x.0, &y.0))
170}
171
172#[cfg_attr(test, mutants::skip)]
173pub fn checked_add(x: &U, y: &U) -> Option<U> {
174 if x > &(U::MAX - *y) {
175 None
176 } else {
177 let z = x.add_mod(y, &U::MAX);
178 if z.is_zero() && (x.is_some() || y.is_some()) {
179 Some(U::MAX)
180 } else {
181 Some(z)
182 }
183 }
184}
185
186#[cfg_attr(test, mutants::skip)]
187pub fn saturating_add(x: &U, y: &U) -> U {
188 checked_add(x, y).unwrap_or(U::MAX)
189}
190
191const fn wrapping_sub_b<const C: usize>(x: &[u8; C], y: &[u8; C]) -> [u8; C] {
192 let mut neg_y = *y;
193 let mut i = 0;
194 while i < C {
195 neg_y[i] = !neg_y[i];
196 i += 1;
197 }
198 let mut c = 1u16;
199 let mut i = C - 1;
200 loop {
201 let sum = neg_y[i] as u16 + c;
202 neg_y[i] = sum as u8;
203 c = sum >> 8;
204 if i == 0 {
205 break;
206 }
207 i -= 1;
208 }
209 wrapping_add_b(x, &neg_y)
210}
211
212pub const fn wrapping_sub(x: &U, y: &U) -> U {
213 U(wrapping_sub_b::<32>(&x.0, &y.0))
214}
215
216pub fn saturating_sub(x: &U, y: &U) -> U {
217 checked_sub(x, y).unwrap_or(U::ZERO)
218}
219
220#[cfg_attr(test, mutants::skip)]
221pub fn checked_sub(x: &U, y: &U) -> Option<U> {
222 if x < y {
223 None
224 } else {
225 Some(wrapping_sub(x, y))
226 }
227}
228
229pub const fn wrapping_mul_b<const C: usize>(x: &[u8; C], y: &[u8; C]) -> [u8; C] {
230 let mut r = [0u8; C];
231 let mut i = 0;
232 while i < C {
233 let mut c = 0u16;
234 let mut j = 0;
235 while j < C {
236 let i_r = i + j;
237 if i_r >= C {
238 break;
239 }
240 let r_idx = C - 1 - i_r;
241 let xi = x[C - 1 - i] as u16;
242 let yj = y[C - 1 - j] as u16;
243 let prod = xi * yj + r[r_idx] as u16 + c;
244 r[r_idx] = prod as u8;
245 c = prod >> 8;
246 j += 1;
247 }
248 if i + j < C {
249 let idx = 31 - (i + j);
250 r[idx] = r[idx] + c as u8;
251 }
252 i += 1;
253 }
254 r
255}
256
257pub const fn wrapping_mul(x: &U, y: &U) -> U {
258 U(wrapping_mul_b(&x.0, &y.0))
259}
260
261#[cfg_attr(test, mutants::skip)]
262pub fn checked_mul(x: &U, y: &U) -> Option<U> {
263 if x.is_zero() || y.is_zero() {
264 return Some(U::ZERO);
265 }
266 if x > &(U::MAX / *y) {
267 None
268 } else {
269 let z = x.mul_mod(y, &U::MAX);
270 if z.is_zero() { Some(U::MAX) } else { Some(z) }
271 }
272}
273
274pub fn saturating_mul(x: &U, y: &U) -> U {
275 checked_mul(x, y).unwrap_or(U::MAX)
276}
277
278impl Add for U {
279 type Output = U;
280
281 fn add(self, rhs: U) -> U {
282 cfg_if::cfg_if! {
283 if #[cfg(debug_assertions)] {
284 checked_add(&self, &rhs).expect("overflow when add")
285 } else {
286 wrapping_add(&self, &rhs)
287 }
288 }
289 }
290}
291
292impl Add for &U {
293 type Output = U;
294
295 fn add(self, rhs: &U) -> U {
296 cfg_if::cfg_if! {
297 if #[cfg(debug_assertions)] {
298 checked_add(self, rhs).expect("overflow when add")
299 } else {
300 wrapping_add(self, rhs)
301 }
302 }
303 }
304}
305
306impl Sub for U {
307 type Output = U;
308
309 fn sub(self, rhs: U) -> U {
310 cfg_if::cfg_if! {
311 if #[cfg(debug_assertions)] {
312 checked_sub(&self, &rhs).expect("overflow when sub")
313 } else {
314 wrapping_sub(&self, &rhs)
315 }
316 }
317 }
318}
319
320impl Sub for &U {
321 type Output = U;
322
323 fn sub(self, rhs: &U) -> U {
324 cfg_if::cfg_if! {
325 if #[cfg(debug_assertions)] {
326 checked_sub(self, rhs).expect("overflow when sub")
327 } else {
328 wrapping_sub(self, rhs)
329 }
330 }
331 }
332}
333
334impl Mul for U {
335 type Output = U;
336
337 fn mul(self, rhs: U) -> U {
338 cfg_if::cfg_if! {
339 if #[cfg(debug_assertions)] {
340 checked_mul(&self, &rhs).expect("overflow when mul")
341 } else {
342 wrapping_mul(&self, &rhs)
343 }
344 }
345 }
346}
347
348impl Mul for &U {
349 type Output = U;
350
351 fn mul(self, rhs: &U) -> U {
352 cfg_if::cfg_if! {
353 if #[cfg(debug_assertions)] {
354 checked_mul(self, rhs).expect("overflow when mul")
355 } else {
356 wrapping_mul(self, rhs)
357 }
358 }
359 }
360}
361
362impl Div for U {
363 type Output = U;
364
365 fn div(self, rhs: U) -> U {
366 cfg_if::cfg_if! {
367 if #[cfg(debug_assertions)] {
368 checked_div(&self, &rhs).expect("overflow when div")
369 } else {
370 wrapping_div(&self, &rhs)
371 }
372 }
373 }
374}
375
376impl Div for &U {
377 type Output = U;
378
379 fn div(self, rhs: &U) -> U {
380 cfg_if::cfg_if! {
381 if #[cfg(debug_assertions)] {
382 checked_div(self, rhs).expect("overflow when div")
383 } else {
384 wrapping_div(self, rhs)
385 }
386 }
387 }
388}
389
390impl Rem for U {
391 type Output = U;
392
393 fn rem(self, rhs: U) -> U {
394 modd(&self, &rhs)
395 }
396}
397
398impl Rem for &U {
399 type Output = U;
400
401 fn rem(self, rhs: &U) -> U {
402 modd(self, rhs)
403 }
404}
405
406impl Eq for U {}
407
408impl PartialOrd for U {
409 fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
410 Some(self.cmp(other))
411 }
412}
413
414impl Ord for U {
415 fn cmp(&self, other: &Self) -> Ordering {
416 self.0.cmp(&other.0)
417 }
418}
419
420impl U {
421 pub const ZERO: Self = U([0u8; 32]);
422
423 pub const MAX: Self = U([u8::MAX; 32]);
424
425 pub const ONE: Self = U([
426 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,
427 0, 1,
428 ]);
429
430 pub fn is_true(&self) -> bool {
431 self.0[31] == 1
432 }
433
434 pub fn is_zero(&self) -> bool {
435 *self == Self::ZERO
436 }
437
438 pub fn is_some(&self) -> bool {
439 !self.is_zero()
440 }
441
442 pub fn as_slice(&self) -> &[u8; 32] {
443 &self.0
444 }
445
446 pub fn checked_add(&self, y: &Self) -> Option<Self> {
447 checked_add(self, y)
448 }
449
450 pub fn checked_mul(&self, y: &Self) -> Option<Self> {
451 checked_mul(self, y)
452 }
453
454 pub fn checked_sub(&self, y: &Self) -> Option<Self> {
455 checked_sub(self, y)
456 }
457
458 pub fn checked_div(&self, y: &Self) -> Option<Self> {
459 checked_div(self, y)
460 }
461
462 pub fn wrapping_add(&self, y: &Self) -> U {
463 wrapping_add(self, y)
464 }
465
466 pub fn wrapping_sub(&self, y: &Self) -> U {
467 wrapping_sub(self, y)
468 }
469
470 pub fn wrapping_mul(&self, y: &Self) -> U {
471 wrapping_mul(self, y)
472 }
473
474 pub fn wrapping_div(&self, y: &Self) -> U {
475 wrapping_div(self, y)
476 }
477
478 pub fn saturating_add(&self, y: &Self) -> U {
479 saturating_add(self, y)
480 }
481
482 pub fn saturating_sub(&self, y: &Self) -> U {
483 saturating_sub(self, y)
484 }
485
486 pub fn saturating_mul(&self, y: &Self) -> U {
487 saturating_mul(self, y)
488 }
489
490 pub fn mul_mod(&self, y: &Self, z: &Self) -> Self {
491 let mut b = self.0;
492 unsafe { math_mul_mod(b.as_mut_ptr(), y.as_ptr(), z.as_ptr()) }
493 Self(b)
494 }
495
496 pub fn add_mod(&self, y: &Self, z: &Self) -> Self {
497 let mut b = self.0;
498 unsafe { math_add_mod(b.as_mut_ptr(), y.as_ptr(), z.as_ptr()) }
499 Self(b)
500 }
501
502 pub fn widening_mul(&self, y: &U) -> [u8; 64] {
503 let shift_128 = &U([
504 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,
505 0, 0, 0,
506 ]);
507 let x_hi = self / shift_128;
508 let x_lo = self % shift_128;
509 let y_hi = y / shift_128;
510 let y_lo = y % shift_128;
511 let t0 = x_lo.mul_mod(&y_lo, &U::MAX);
512 let t1 = x_hi.mul_mod(&y_lo, &U::MAX);
513 let t2 = x_lo.mul_mod(&y_hi, &U::MAX);
514 let t3 = x_hi.mul_mod(&y_hi, &U::MAX);
515 let t0_hi = &t0 / shift_128;
516 let t0_lo = &t0 % shift_128;
517 let t1_hi = &t1 / shift_128;
518 let t1_lo = &t1 % shift_128;
519 let t2_hi = &t2 / shift_128;
520 let t2_lo = &t2 % shift_128;
521 let mid = (t0_hi + t1_lo) + t2_lo;
522 let mid_hi = &mid / shift_128;
523 let mid_lo = &mid % shift_128;
524 let mid_lo_shifted = mid_lo.mul_mod(shift_128, &U::MAX);
525 let out_low = t0_lo + mid_lo_shifted;
526 let out_high = t3 + t1_hi + t2_hi + mid_hi;
527 let mut o = [0u8; 64];
528 o[..32].copy_from_slice(&out_high.0);
529 o[32..].copy_from_slice(&out_low.0);
530 o
531 }
532
533 pub fn mul_div(&self, y: &U, denom: &U) -> Option<(U, bool)> {
534 if denom.is_zero() {
536 return None;
537 }
538 let x = self.widening_mul(y);
539 let mut d = [0u8; 64];
540 d[32..].copy_from_slice(&denom.0);
541 let (q, rem) = wrapping_div_quo_rem_b::<64>(&x, &d);
542 if q[..32] != [0u8; 32] {
543 return None;
544 }
545 let l: [u8; 32] = q[32..].try_into().unwrap();
546 let l = U::from(l);
547 let has_carry = rem[32..] != [0u8; 32];
548 Some((l, has_carry))
549 }
550
551 pub fn mul_div_round_up(&self, y: &U, denom_and_rem: &U) -> Option<U> {
552 let (x, y) = self.mul_div(y, denom_and_rem)?;
553 Some(if y { x + U::ONE } else { x })
554 }
555}
556
557#[cfg(feature = "std")]
558impl Display for U {
559 fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
560 let mut result = vec![0u8];
561 for &byte in &self.0 {
562 let mut carry = byte as u32;
563 for digit in result.iter_mut() {
564 let temp = (*digit as u32) * 256 + carry;
565 *digit = (temp % 10) as u8;
566 carry = temp / 10;
567 }
568 while carry > 0 {
569 result.push((carry % 10) as u8);
570 carry /= 10;
571 }
572 }
573 if result.iter().all(|&d| d == 0) {
574 return write!(f, "0");
575 }
576 write!(
577 f,
578 "{}",
579 result
580 .iter()
581 .rev()
582 .skip_while(|&&d| d == 0)
583 .map(|&d| (d + b'0') as char)
584 .collect::<String>()
585 )
586 }
587}
588
589impl From<U> for [u8; 32] {
590 fn from(x: U) -> Self {
591 x.0
592 }
593}
594
595impl From<U> for bool {
596 fn from(x: U) -> Self {
597 x.0[31] == 1
598 }
599}
600
601impl From<&[u8; 32]> for &U {
602 fn from(x: &[u8; 32]) -> Self {
603 unsafe { &*(x as *const [u8; 32] as *const U) }
604 }
605}
606
607impl From<[u8; 32]> for U {
608 fn from(x: [u8; 32]) -> Self {
609 U(x)
610 }
611}
612
613impl Deref for U {
614 type Target = [u8; 32];
615
616 fn deref(&self) -> &Self::Target {
617 &self.0
618 }
619}
620
621impl DerefMut for U {
622 fn deref_mut(&mut self) -> &mut Self::Target {
623 &mut self.0
624 }
625}
626
627impl From<bool> for U {
628 fn from(x: bool) -> Self {
629 U::from(&[x as u8])
630 }
631}
632
633impl Zero for U {
634 fn zero() -> Self {
635 U::ZERO
636 }
637
638 fn is_zero(&self) -> bool {
639 self.0.iter().all(|&b| b == 0)
640 }
641}
642
643impl Default for U {
644 fn default() -> Self {
645 U::ZERO
646 }
647}
648
649impl One for U {
650 fn one() -> Self {
651 U::ONE
652 }
653}
654
655impl Index<usize> for U {
656 type Output = u8;
657
658 fn index(&self, index: usize) -> &Self::Output {
659 &self.0[index]
660 }
661}
662
663impl I {
664 fn is_neg(&self) -> bool {
665 self.0[0] & 0x80 != 0
666 }
667
668 pub fn is_zero(&self) -> bool {
669 *self == Self::ZERO
670 }
671
672 pub fn is_some(&self) -> bool {
673 !self.is_zero()
674 }
675
676 pub fn as_slice(&self) -> &[u8; 32] {
677 &self.0
678 }
679
680 fn neg(&self) -> Self {
681 let x = wrapping_add(&U(self.0.map(|b| !b)), &U::ONE);
682 I(x.0)
683 }
684
685 fn abs(self) -> U {
686 if self.is_neg() {
687 U(self.neg().0)
688 } else {
689 U(self.0)
690 }
691 }
692}
693
694macro_rules! from_slices {
695 ($($n:expr),+ $(,)?) => {
696 $(
697 impl From<&[u8; $n]> for U {
698 fn from(x: &[u8; $n]) -> Self {
699 let mut b = [0u8; 32];
700 b[32 - $n..].copy_from_slice(x);
701 U(b)
702 }
703 }
704
705 impl From<[u8; $n]> for U {
706 fn from(x: [u8; $n]) -> Self {
707 U::from(&x)
708 }
709 }
710
711 impl From<U> for [u8; $n] {
712 fn from(x: U) -> Self {
713 unsafe { *(x.as_ptr().add(32 - $n) as *const [u8; $n]) }
714 }
715 }
716 )+
717 };
718}
719
720from_slices!(
721 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,
722 27, 28, 29, 30, 31
723);
724
725impl From<&U> for Address {
726 fn from(x: &U) -> Self {
727 (*x).into()
728 }
729}
730
731macro_rules! from_ints {
732 ($($t:ty),+ $(,)?) => {
733 $(
734 impl From<$t> for U {
735 fn from(x: $t) -> Self {
736 let mut b = [0u8; 32];
737 b[32 - core::mem::size_of::<$t>()..].copy_from_slice(&x.to_be_bytes());
738 U(b)
739 }
740 }
741
742 impl From<U> for $t {
743 fn from(x: U) -> Self {
744 Self::from_be_bytes(x.into())
745 }
746 }
747 )+
748 };
749}
750
751from_ints! { u8, u16, u32, u64, u128, usize }
752
753impl From<I> for [u8; 32] {
754 fn from(x: I) -> Self {
755 x.0
756 }
757}
758
759impl From<[u8; 32]> for I {
760 fn from(x: [u8; 32]) -> Self {
761 I(x)
762 }
763}
764
765fn i_add(x: &I, y: &I) -> I {
766 I(wrapping_add(&U(x.0), &U(y.0)).0)
767}
768
769fn i_sub(x: &I, y: &I) -> I {
770 I(wrapping_sub(&U(x.0), &U(y.0)).0)
771}
772
773fn i_mul(x: &I, y: &I) -> I {
774 let result = wrapping_mul(&U(x.0), &U(y.0));
775 I(result.0)
776}
777
778fn i_div(x: &I, y: &I) -> I {
779 let r = wrapping_div(&x.abs(), &y.abs());
780 if x.is_neg() ^ y.is_neg() {
781 I(r.0).neg()
782 } else {
783 I(r.0)
784 }
785}
786
787fn i_rem(x: &I, y: &I) -> I {
788 let r = modd(&x.abs(), &y.abs());
789 if x.is_neg() { I(r.0).neg() } else { I(r.0) }
790}
791
792impl Add for I {
793 type Output = I;
794 fn add(self, rhs: I) -> I {
795 i_add(&self, &rhs)
796 }
797}
798
799impl Add for &I {
800 type Output = I;
801 fn add(self, rhs: &I) -> I {
802 i_add(self, rhs)
803 }
804}
805
806impl Sub for I {
807 type Output = I;
808 fn sub(self, rhs: I) -> I {
809 i_sub(&self, &rhs)
810 }
811}
812
813impl Sub for &I {
814 type Output = I;
815 fn sub(self, rhs: &I) -> I {
816 i_sub(self, rhs)
817 }
818}
819
820impl Mul for I {
821 type Output = I;
822 fn mul(self, rhs: I) -> I {
823 i_mul(&self, &rhs)
824 }
825}
826
827impl Mul for &I {
828 type Output = I;
829 fn mul(self, rhs: &I) -> I {
830 i_mul(self, rhs)
831 }
832}
833
834impl Div for I {
835 type Output = I;
836 fn div(self, rhs: I) -> I {
837 i_div(&self, &rhs)
838 }
839}
840
841impl Div for &I {
842 type Output = I;
843 fn div(self, rhs: &I) -> I {
844 i_div(self, rhs)
845 }
846}
847
848impl Rem for I {
849 type Output = I;
850 fn rem(self, rhs: I) -> I {
851 i_rem(&self, &rhs)
852 }
853}
854
855impl Eq for I {}
856
857impl PartialOrd for I {
858 fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
859 Some(self.cmp(other))
860 }
861}
862
863impl Ord for I {
864 fn cmp(&self, other: &Self) -> Ordering {
865 let self_sign = self.0[0] & 0x80;
866 let other_sign = other.0[0] & 0x80;
867 match (self_sign, other_sign) {
868 (0, 0x80) => Ordering::Greater,
869 (0x80, 0) => Ordering::Less,
870 _ => self.0.cmp(&other.0),
871 }
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 I {
883 pub const ZERO: Self = I([0u8; 32]);
884
885 pub const ONE: Self = I([
886 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,
887 0, 1,
888 ]);
889}
890
891impl Zero for I {
892 fn zero() -> Self {
893 I::ZERO
894 }
895 fn is_zero(&self) -> bool {
896 self.0.iter().all(|&b| b == 0)
897 }
898}
899
900impl Default for I {
901 fn default() -> Self {
902 I::ZERO
903 }
904}
905
906impl One for I {
907 fn one() -> Self {
908 I::ONE
909 }
910}
911
912#[test]
913fn test_is_zeroes() {
914 assert!(U::ZERO.is_zero());
915 assert!(U::ONE.is_some());
916 assert!(I::ZERO.is_zero());
917 assert!(I::ONE.is_some());
918}
919
920#[cfg(all(
921 test,
922 feature = "alloy-enabled",
923 feature = "proptest-enabled",
924 feature = "std",
925 not(target_arch = "wasm32")
926))]
927mod test {
928 use proptest::prelude::*;
929
930 use super::*;
931
932 fn u_from_u64(value: u64) -> U {
933 U::from(value)
934 }
935
936 proptest! {
937 #[test]
938 fn wrapping_div_b_zero_denominator_yields_zero(numerator in any::<[u8; 4]>()) {
939 let zero = [0u8; 4];
940 prop_assert_eq!(wrapping_div_quo_rem_b::<4>(&numerator, &zero).0, zero);
941 }
942
943 #[test]
944 fn wrapping_div_b_matches_integer_division(
945 numerator in any::<[u8; 4]>(),
946 denominator in any::<[u8; 4]>().prop_filter("denominator must be non-zero", |d| *d != [0u8; 4])
947 ) {
948 let numerator_u32 = u32::from_be_bytes(numerator);
949 let denominator_u32 = u32::from_be_bytes(denominator);
950 let expected = numerator_u32 / denominator_u32;
951 prop_assert_eq!(
952 wrapping_div_quo_rem_b::<4>(&numerator, &denominator).0,
953 expected.to_be_bytes()
954 );
955 }
956
957 #[test]
958 fn wrapping_mod_b_matches_integer_modulo(
959 numerator in any::<[u8; 4]>(),
960 denominator in any::<[u8; 4]>().prop_filter("denominator must be non-zero", |d| *d != [0u8; 4])
961 ) {
962 let numerator_u32 = u32::from_be_bytes(numerator);
963 let denominator_u32 = u32::from_be_bytes(denominator);
964 let expected = numerator_u32 % denominator_u32;
965 prop_assert_eq!(
966 wrapping_div_quo_rem_b::<4>(&numerator, &denominator).1,
967 expected.to_be_bytes()
968 );
969 }
970
971 #[test]
972 fn wrapping_add_b_handles_carry(lhs in any::<[u8; 4]>(), rhs in any::<[u8; 4]>()) {
973 let lhs_u32 = u32::from_be_bytes(lhs);
974 let rhs_u32 = u32::from_be_bytes(rhs);
975 let expected = lhs_u32.wrapping_add(rhs_u32);
976 prop_assert_eq!(wrapping_add_b::<4>(&lhs, &rhs), expected.to_be_bytes());
977 }
978
979 #[test]
980 fn wrapping_sub_b_handles_borrow(lhs in any::<[u8; 4]>(), rhs in any::<[u8; 4]>()) {
981 let lhs_u32 = u32::from_be_bytes(lhs);
982 let rhs_u32 = u32::from_be_bytes(rhs);
983 let expected = lhs_u32.wrapping_sub(rhs_u32);
984 prop_assert_eq!(wrapping_sub_b::<4>(&lhs, &rhs), expected.to_be_bytes());
985 }
986
987 #[test]
988 fn wrapping_mul_b_matches_wrapping_arithmetic(lhs in any::<[u8; 32]>(), rhs in any::<[u8; 32]>()) {
989 let lhs_u = U::from(lhs);
990 let rhs_u = U::from(rhs);
991 let expected = lhs_u.wrapping_mul(&rhs_u);
992 prop_assert_eq!(wrapping_mul_b::<32>(&lhs, &rhs), expected.0);
993 }
994
995 #[test]
996 fn const_wrapping_div_agrees_with_wrapping_div_b(
997 numerator in any::<[u8; 32]>(),
998 denominator in any::<[u8; 32]>().prop_filter("denominator must be non-zero", |d| *d != [0u8; 32])
999 ) {
1000 let numerator_u = U::from(numerator);
1001 let denominator_u = U::from(denominator);
1002 prop_assert_eq!(
1003 const_wrapping_div(&numerator_u, &denominator_u).0,
1004 wrapping_div_quo_rem_b::<32>(&numerator, &denominator).0
1005 );
1006 }
1007
1008 #[test]
1009 fn u_predicates_track_zero_and_true(bytes in any::<[u8; 32]>()) {
1010 let value = U::from(bytes);
1011 let is_zero = bytes.iter().all(|&b| b == 0);
1012 prop_assert_eq!(value.is_zero(), is_zero);
1013 prop_assert_eq!(value.is_some(), !is_zero);
1014 prop_assert_eq!(value.is_true(), bytes[31] == 1);
1015 }
1016
1017 #[test]
1018 fn mul_div_returns_expected_quotient_and_carry(
1019 lhs in any::<u64>(),
1020 rhs in any::<u64>(),
1021 denom in any::<u64>().prop_filter("denominator must be non-zero", |d| *d != 0)
1022 ) {
1023 let lhs_u = u_from_u64(lhs);
1024 let rhs_u = u_from_u64(rhs);
1025 let denom_u = u_from_u64(denom);
1026 let (q, carry) = lhs_u.mul_div(&rhs_u, &denom_u).expect("division should succeed");
1027
1028 let product = (lhs as u128) * (rhs as u128);
1029 let denom_u128 = denom as u128;
1030 let expected_q = product / denom_u128;
1031 let expected_rem = product % denom_u128;
1032
1033 prop_assert_eq!(u128::from(q), expected_q);
1034 prop_assert_eq!(carry, expected_rem != 0);
1035 }
1036
1037 #[test]
1038 fn mul_div_round_up_accounts_for_carry(
1039 lhs in any::<u64>(),
1040 rhs in any::<u64>(),
1041 denom in any::<u64>().prop_filter("denominator must be non-zero", |d| *d != 0)
1042 ) {
1043 let lhs_u = u_from_u64(lhs);
1044 let rhs_u = u_from_u64(rhs);
1045 let denom_u = u_from_u64(denom);
1046 let rounded = lhs_u
1047 .mul_div_round_up(&rhs_u, &denom_u)
1048 .expect("rounding should succeed");
1049
1050 let product = (lhs as u128) * (rhs as u128);
1051 let denom_u128 = denom as u128;
1052 let expected = if product % denom_u128 == 0 {
1053 product / denom_u128
1054 } else {
1055 (product / denom_u128) + 1
1056 };
1057
1058 prop_assert_eq!(u128::from(rounded), expected);
1059 }
1060
1061 #[test]
1062 fn test_u_is_zero(x in any::<[u8; 32]>()) {
1063 let x = U::from(x);
1064 let ex = U256::from_be_bytes(x.0);
1065 assert_eq!(ex.is_zero(), x.is_zero());
1066 }
1067
1068 #[test]
1069 fn test_u_div(x in any::<U>(), y in any::<U>()) {
1070 let ex = U256::from_be_bytes(x.0);
1071 let ey = U256::from_be_bytes(y.0);
1072 assert_eq!((ex.wrapping_div(ey)).to_be_bytes(), x.wrapping_div(&y).0);
1073 }
1074
1075 #[test]
1076 fn test_u_mul(x in any::<U>(), y in any::<U>()) {
1077 let ex = U256::from_be_bytes(x.0);
1078 let ey = U256::from_be_bytes(y.0);
1079 assert_eq!((ex.wrapping_mul(ey)).to_be_bytes(), wrapping_mul(&x, &y).0);
1080 }
1081
1082 #[test]
1083 fn test_u_mod(x in any::<U>(), y in any::<U>()) {
1084 let ex = U256::from_be_bytes(x.0);
1085 let ey = U256::from_be_bytes(y.0);
1086 assert_eq!((ex % ey).to_be_bytes(), (x % y).0);
1087 }
1088
1089 #[test]
1090 fn test_u_add(x in any::<U>(), y in any::<U>()) {
1091 let ex = U256::from_be_bytes(x.0);
1092 let ey = U256::from_be_bytes(y.0);
1093 let e = U::from(ex.wrapping_add(ey).to_be_bytes::<32>());
1094 assert_eq!(e, x.wrapping_add(&y), "{e} != {}", x + y);
1095 }
1096
1097 #[test]
1098 fn test_u_sub(x in any::<U>(), y in any::<U>()) {
1099 let ex = U256::from_be_bytes(x.0);
1100 let ey = U256::from_be_bytes(y.0);
1101 assert_eq!((ex.wrapping_sub(ey)).to_be_bytes(), x.wrapping_sub(&y).0);
1102 }
1103
1104 #[test]
1105 fn test_u_cmp(x in any::<U>(), y in any::<U>()) {
1106 let ex = U256::from_be_bytes(x.0);
1107 let ey = U256::from_be_bytes(y.0);
1108 assert_eq!(ex.cmp(&ey), x.cmp(&y));
1109 }
1110
1111 #[test]
1112 #[cfg(feature = "alloc")]
1113 fn test_u_str(x in any::<U>()) {
1114 assert_eq!(U256::from_be_bytes(x.0).to_string(), x.to_string());
1115 }
1116
1117 #[test]
1118 fn test_i_is_zero(x in any::<U>()) {
1119 let ex = I256::from_be_bytes(x.0);
1120 assert_eq!(ex.is_zero(), x.is_zero());
1121 }
1122
1123 #[test]
1124 fn test_i_div(x in any::<I>(), y in any::<I>()) {
1125 let ex = I256::from_be_bytes(x.0);
1126 let ey = I256::from_be_bytes(y.0);
1127 assert_eq!((ex / ey).to_be_bytes(), (x / y).0);
1128 }
1129
1130 #[test]
1131 fn test_i_mul(x in any::<I>(), y in any::<I>()) {
1132 let ex = I256::from_be_bytes(x.0);
1133 let ey = I256::from_be_bytes(y.0);
1134 assert_eq!((ex.wrapping_mul(ey)).to_be_bytes(), (x * y).0);
1135 }
1136
1137 #[test]
1138 fn test_i_mod(x in any::<I>(), y in any::<I>()) {
1139 let ex = I256::from_be_bytes(x.0);
1140 let ey = I256::from_be_bytes(y.0);
1141 assert_eq!((ex % ey).to_be_bytes(), (x % y).0);
1142 }
1143
1144 #[test]
1145 fn test_i_add(x in any::<I>(), y in any::<I>()) {
1146 let ex = I256::from_be_bytes(x.0);
1147 let ey = I256::from_be_bytes(y.0);
1148 assert_eq!((ex.wrapping_add(ey)).to_be_bytes(), (x + y).0);
1149 }
1150
1151 #[test]
1152 fn test_i_sub(x in any::<I>(), y in any::<I>()) {
1153 let ex = I256::from_be_bytes(x.0);
1154 let ey = I256::from_be_bytes(y.0);
1155 assert_eq!((ex.wrapping_sub(ey)).to_be_bytes(), (x - y).0);
1156 }
1157
1158 #[test]
1159 fn test_i_cmp(x in any::<I>(), y in any::<I>()) {
1160 let ex = I256::from_be_bytes(x.0);
1161 let ey = I256::from_be_bytes(y.0);
1162 assert_eq!(ex.cmp(&ey), x.cmp(&y));
1163 }
1164
1165 #[test]
1166 fn test_u_u8(x in any::<u8>()) {
1167 let mut b = [0u8; 32];
1168 b[32-std::mem::size_of::<u8>()..].copy_from_slice(&x.to_be_bytes());
1169 assert_eq!(&U256::from_be_bytes(b).to_be_bytes(), U::from(x).as_slice());
1170 }
1171
1172 #[test]
1173 fn test_u_u16(x in any::<u16>()) {
1174 let mut b = [0u8; 32];
1175 b[32-std::mem::size_of::<u16>()..].copy_from_slice(&x.to_be_bytes());
1176 assert_eq!(&U256::from_be_bytes(b).to_be_bytes(), U::from(x).as_slice());
1177 }
1178
1179 #[test]
1180 fn test_u_u32(x in any::<u32>()) {
1181 let mut b = [0u8; 32];
1182 b[32-std::mem::size_of::<u32>()..].copy_from_slice(&x.to_be_bytes());
1183 assert_eq!(&U256::from_be_bytes(b).to_be_bytes(), U::from(x).as_slice());
1184 }
1185
1186 #[test]
1187 fn test_u_u64(x in any::<u64>()) {
1188 let mut b = [0u8; 32];
1189 b[32-std::mem::size_of::<u64>()..].copy_from_slice(&x.to_be_bytes());
1190 assert_eq!(&U256::from_be_bytes(b).to_be_bytes(), U::from(x).as_slice());
1191 }
1192
1193 #[test]
1194 fn test_u_u128(x in any::<u128>()) {
1195 let mut b = [0u8; 32];
1196 b[32-std::mem::size_of::<u128>()..].copy_from_slice(&x.to_be_bytes());
1197 assert_eq!(&U256::from_be_bytes(b).to_be_bytes(), U::from(x).as_slice());
1198 }
1199
1200 #[test]
1201 fn test_to_and_from_addrs(x in any::<Address>()) {
1202 let y: Address = U::from(x).into();
1203 assert_eq!(x, y)
1204 }
1205
1206 #[test]
1207 fn test_u_conv_to_and_from_u8(x in any::<u8>()) {
1208 assert_eq!(x.wrapping_add(1), U::from(x).wrapping_add(&U::ONE).into());
1209 }
1210 }
1211}