1#![cfg_attr(not(feature = "std"), no_std)]
2
3use core::{
4 cmp::{Eq, Ordering},
5 fmt::{Debug, Error as FmtError, Formatter},
6 ops::{
7 Add, AddAssign, Deref, DerefMut, Div, Index, IndexMut, Mul, Rem, Shl, ShlAssign, Shr,
8 ShrAssign, Sub, SubAssign,
9 },
10};
11
12use num_traits::{One, Zero};
13
14#[cfg(feature = "borsh")]
15use borsh::{BorshDeserialize, BorshSerialize};
16
17#[cfg(feature = "alloc")]
18extern crate alloc;
19
20#[cfg(feature = "alloc")]
21use alloc::{string::String, vec};
22
23pub type Address = [u8; 20];
24
25#[link(wasm_import_module = "vm_hooks")]
26#[cfg(not(feature = "alloy-enabled"))]
27unsafe extern "C" {
28 fn math_div(x: *mut u8, y: *const u8);
29 fn math_mod(x: *mut u8, y: *const u8);
30 fn math_add_mod(a: *mut u8, b: *const u8, c: *const u8);
31 fn math_mul_mod(a: *mut u8, b: *const u8, c: *const u8);
32}
33
34#[cfg(feature = "alloy-enabled")]
35mod alloy {
36 use core::ptr::copy_nonoverlapping;
37
38 pub(crate) use alloy_primitives::U256;
39
40 #[cfg(test)]
41 pub(crate) use alloy_primitives::I256;
42
43 pub(crate) unsafe fn math_div(out: *mut u8, y: *const u8) {
44 unsafe {
45 let x = U256::from_be_slice(&*(out as *const [u8; 32]));
46 let y = U256::from_be_slice(&*(y as *const [u8; 32]));
47 let z = if y.is_zero() {
48 U256::ZERO
50 } else {
51 x / y
52 };
53 copy_nonoverlapping(z.to_be_bytes::<32>().as_ptr(), out, 32);
54 }
55 }
56
57 pub(crate) unsafe fn math_mod(out: *mut u8, y: *const u8) {
58 unsafe {
59 let x = U256::from_be_slice(&*(out as *const [u8; 32]));
60 let y = U256::from_be_slice(&*(y as *const [u8; 32]));
61 let z = x % y;
62 copy_nonoverlapping(z.to_be_bytes::<32>().as_ptr(), out, 32);
63 }
64 }
65
66 pub(crate) unsafe fn math_add_mod(a: *mut u8, b: *const u8, c: *const u8) {
67 unsafe {
68 let x = U256::from_be_slice(&*(a as *const [u8; 32]));
69 let y = U256::from_be_slice(&*(b as *const [u8; 32]));
70 let z = U256::from_be_slice(&*(c as *const [u8; 32]));
71 let x = x.add_mod(y, z);
72 copy_nonoverlapping(x.to_be_bytes::<32>().as_ptr(), a, 32);
73 }
74 }
75
76 pub(crate) unsafe fn math_mul_mod(a: *mut u8, b: *const u8, c: *const u8) {
77 unsafe {
78 let x = U256::from_be_slice(&*(a as *const [u8; 32]));
79 let y = U256::from_be_slice(&*(b as *const [u8; 32]));
80 let z = U256::from_be_slice(&*(c as *const [u8; 32]));
81 let x = x.mul_mod(y, z);
82 copy_nonoverlapping(x.to_be_bytes::<32>().as_ptr(), a, 32);
83 }
84 }
85}
86
87#[cfg(feature = "alloy-enabled")]
88use alloy::*;
89
90#[derive(Copy, Clone, PartialEq, Hash)]
91#[cfg_attr(feature = "proptest", derive(proptest_derive::Arbitrary))]
92#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))]
93#[cfg_attr(feature = "borsh", derive(BorshDeserialize, BorshSerialize))]
94#[repr(transparent)]
95pub struct U(pub [u8; 32]);
96
97#[derive(Copy, Clone, PartialEq, Hash, Debug)]
98#[cfg_attr(feature = "proptest", derive(proptest_derive::Arbitrary))]
99#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))]
100#[cfg_attr(feature = "borsh", derive(BorshDeserialize, BorshSerialize))]
101#[repr(transparent)]
102pub struct I(pub [u8; 32]);
103
104pub fn wrapping_div(x: &U, y: &U) -> U {
105 assert!(y.is_some(), "divide by zero");
106 let mut b = *x;
107 unsafe { math_div(b.as_mut_ptr(), y.as_ptr()) }
108 b
109}
110
111fn wrapping_div_quo_rem_b<const C: usize>(x: &[u8; C], denom: &[u8; C]) -> ([u8; C], [u8; C]) {
112 if denom == &[0u8; C] {
113 return ([0u8; C], [0u8; C]);
114 }
115 let mut q = [0u8; C];
116 let mut r = [0u8; C];
117 let mut one = [0u8; C];
118 one[C - 1] = 1;
119 let mut two = [0u8; C];
120 two[C - 1] = 2;
121 let mut i = 0;
122 while i < C * 8 {
123 let bit = (x[i / 8] >> (7 - (i % 8))) & 1;
124 r = wrapping_mul_b::<C>(&r, &two);
125 if bit == 1 {
126 r = wrapping_add_b::<C>(&r, &one);
127 }
128 if r >= *denom {
129 r = wrapping_sub_b::<C>(&r, denom);
130 q[i / 8] |= 1 << (7 - (i % 8));
131 }
132 i += 1;
133 }
134 (q, r)
135}
136
137pub fn const_wrapping_div(x: &U, y: &U) -> U {
138 U(wrapping_div_quo_rem_b::<32>(&x.0, &y.0).0)
139}
140
141#[cfg_attr(test, mutants::skip)]
142pub fn checked_div(x: &U, y: &U) -> Option<U> {
143 if y.is_zero() {
144 None
145 } else {
146 Some(wrapping_div(x, y))
147 }
148}
149
150pub fn modd(x: &U, y: &U) -> U {
151 let mut b = *x;
152 unsafe { math_mod(b.as_mut_ptr(), y.as_ptr()) }
153 b
154}
155
156const fn wrapping_add_b<const C: usize>(x: &[u8; C], y: &[u8; C]) -> [u8; C] {
157 let mut r = [0u8; C];
158 let mut c = 0;
159 let mut i = C - 1;
160 loop {
161 let s = x[i] as u16 + y[i] as u16 + c;
162 r[i] = s as u8;
163 c = s >> 8;
164 if i == 0 {
165 break;
166 }
167 i -= 1;
168 }
169 r
170}
171
172pub const fn wrapping_add(x: &U, y: &U) -> U {
173 U(wrapping_add_b(&x.0, &y.0))
174}
175
176#[cfg_attr(test, mutants::skip)]
177pub fn checked_add(x: &U, y: &U) -> Option<U> {
178 if x > &(U::MAX - *y) {
179 None
180 } else {
181 let z = x.add_mod(y, &U::MAX);
182 if z.is_zero() && (x.is_some() || y.is_some()) {
183 Some(U::MAX)
184 } else {
185 Some(z)
186 }
187 }
188}
189
190#[cfg_attr(test, mutants::skip)]
191pub fn saturating_add(x: &U, y: &U) -> U {
192 checked_add(x, y).unwrap_or(U::MAX)
193}
194
195const fn wrapping_sub_b<const C: usize>(x: &[u8; C], y: &[u8; C]) -> [u8; C] {
196 let mut neg_y = *y;
197 let mut i = 0;
198 while i < C {
199 neg_y[i] = !neg_y[i];
200 i += 1;
201 }
202 let mut c = 1u16;
203 let mut i = C - 1;
204 loop {
205 let sum = neg_y[i] as u16 + c;
206 neg_y[i] = sum as u8;
207 c = sum >> 8;
208 if i == 0 {
209 break;
210 }
211 i -= 1;
212 }
213 wrapping_add_b(x, &neg_y)
214}
215
216pub const fn wrapping_sub(x: &U, y: &U) -> U {
217 U(wrapping_sub_b::<32>(&x.0, &y.0))
218}
219
220pub fn saturating_sub(x: &U, y: &U) -> U {
221 checked_sub(x, y).unwrap_or(U::ZERO)
222}
223
224#[cfg_attr(test, mutants::skip)]
225pub fn checked_sub(x: &U, y: &U) -> Option<U> {
226 if x < y {
227 None
228 } else {
229 Some(wrapping_sub(x, y))
230 }
231}
232
233pub const fn wrapping_mul_b<const C: usize>(x: &[u8; C], y: &[u8; C]) -> [u8; C] {
234 let mut r = [0u8; C];
235 let mut i = 0;
236 while i < C {
237 let mut c = 0u16;
238 let mut j = 0;
239 while j < C {
240 let i_r = i + j;
241 if i_r >= C {
242 break;
243 }
244 let r_idx = C - 1 - i_r;
245 let xi = x[C - 1 - i] as u16;
246 let yj = y[C - 1 - j] as u16;
247 let prod = xi * yj + r[r_idx] as u16 + c;
248 r[r_idx] = prod as u8;
249 c = prod >> 8;
250 j += 1;
251 }
252 if i + j < C {
253 let idx = 31 - (i + j);
254 r[idx] = r[idx] + c as u8;
255 }
256 i += 1;
257 }
258 r
259}
260
261pub const fn wrapping_mul(x: &U, y: &U) -> U {
262 U(wrapping_mul_b(&x.0, &y.0))
263}
264
265#[cfg_attr(test, mutants::skip)]
266pub fn checked_mul(x: &U, y: &U) -> Option<U> {
267 if x.is_zero() || y.is_zero() {
268 return Some(U::ZERO);
269 }
270 if x > &(U::MAX / *y) {
271 None
272 } else {
273 let z = x.mul_mod(y, &U::MAX);
274 if z.is_zero() {
275 Some(U::MAX)
276 } else {
277 Some(z)
278 }
279 }
280}
281
282pub fn saturating_mul(x: &U, y: &U) -> U {
283 checked_mul(x, y).unwrap_or(U::MAX)
284}
285
286pub fn widening_mul(x: &U, y: &U) -> [u8; 64] {
287 let shift_128 = &U([
288 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, 0,
289 0, 0,
290 ]);
291 let x_hi = x / shift_128;
292 let x_lo = x % shift_128;
293 let y_hi = y / shift_128;
294 let y_lo = y % shift_128;
295 let t0 = x_lo.mul_mod(&y_lo, &U::MAX);
296 let t1 = x_hi.mul_mod(&y_lo, &U::MAX);
297 let t2 = x_lo.mul_mod(&y_hi, &U::MAX);
298 let t3 = x_hi.mul_mod(&y_hi, &U::MAX);
299 let t0_hi = &t0 / shift_128;
300 let t0_lo = &t0 % shift_128;
301 let t1_hi = &t1 / shift_128;
302 let t1_lo = &t1 % shift_128;
303 let t2_hi = &t2 / shift_128;
304 let t2_lo = &t2 % shift_128;
305 let mid = (t0_hi + t1_lo) + t2_lo;
306 let mid_hi = &mid / shift_128;
307 let mid_lo = &mid % shift_128;
308 let mid_lo_shifted = mid_lo.mul_mod(shift_128, &U::MAX);
309 let out_low = t0_lo + mid_lo_shifted;
310 let out_high = t3 + t1_hi + t2_hi + mid_hi;
311 let mut o = [0u8; 64];
312 o[..32].copy_from_slice(&out_high.0);
313 o[32..].copy_from_slice(&out_low.0);
314 o
315}
316
317pub fn mul_div(x: &U, y: &U, denom: &U) -> Option<(U, bool)> {
318 if denom.is_zero() {
320 return None;
321 }
322 let x = widening_mul(x, y);
323 let mut d = [0u8; 64];
324 d[32..].copy_from_slice(&denom.0);
325 let (q, rem) = wrapping_div_quo_rem_b::<64>(&x, &d);
326 if q[..32] != [0u8; 32] {
327 return None;
328 }
329 let l: [u8; 32] = q[32..].try_into().unwrap();
330 let l = U::from(l);
331 let has_carry = rem[32..] != [0u8; 32];
332 Some((l, has_carry))
333}
334
335pub fn mul_div_round_up(x: &U, y: &U, denom_and_rem: &U) -> Option<U> {
336 let (x, y) = mul_div(x, y, denom_and_rem)?;
337 if x.is_max() && y {
338 return None;
339 }
340 Some(if y { x + U::ONE } else { x })
341}
342
343pub fn checked_rooti(x: U, n: u32) -> Option<U> {
346 if n == 0 {
347 return None;
348 }
349 if x.is_zero() {
350 return Some(U::ZERO);
351 }
352 if n == 1 {
353 return Some(x);
354 }
355 if x == U::from(4u32) && n == 2 {
358 return Some(U::from(2u32));
359 }
360 let n_u256 = U::from(n);
361 let n_1 = n_u256 - U::ONE;
362 let mut b = 0;
364 let mut t = x;
365 while t.is_some() {
366 b += 1;
367 t >>= 1;
368 }
369 let shift = (b + n as usize - 1) / n as usize;
370 let mut z = U::ONE << shift;
371 let mut y = x;
372 while z < y {
374 y = z;
375 let p = z.checked_pow(&n_1)?;
376 z = ((x / p) + (z * n_1)) / n_u256;
377 }
378 if y.checked_pow(&n_u256)? > x {
380 y -= U::ONE;
381 }
382 Some(y)
383}
384
385pub fn checked_pow(x: &U, exp: &U) -> Option<U> {
386 let mut r = U::ONE;
387 let mut i = U::ZERO;
388 while &i < exp {
389 r = checked_mul(&r, x)?;
390 i += U::ONE;
391 }
392 Some(r)
393}
394
395impl Add for U {
396 type Output = U;
397
398 fn add(self, rhs: U) -> U {
399 cfg_if::cfg_if! {
400 if #[cfg(debug_assertions)] {
401 checked_add(&self, &rhs).expect("overflow when add")
402 } else {
403 wrapping_add(&self, &rhs)
404 }
405 }
406 }
407}
408
409impl Add for &U {
410 type Output = U;
411
412 fn add(self, rhs: &U) -> U {
413 cfg_if::cfg_if! {
414 if #[cfg(debug_assertions)] {
415 checked_add(self, rhs).expect("overflow when add")
416 } else {
417 wrapping_add(self, rhs)
418 }
419 }
420 }
421}
422
423impl AddAssign for U {
424 fn add_assign(&mut self, o: Self) {
425 *self = *self + o;
426 }
427}
428
429impl Sub for U {
430 type Output = U;
431
432 fn sub(self, rhs: U) -> U {
433 cfg_if::cfg_if! {
434 if #[cfg(debug_assertions)] {
435 checked_sub(&self, &rhs).expect("overflow when sub")
436 } else {
437 wrapping_sub(&self, &rhs)
438 }
439 }
440 }
441}
442
443impl Sub for &U {
444 type Output = U;
445
446 fn sub(self, rhs: &U) -> U {
447 cfg_if::cfg_if! {
448 if #[cfg(debug_assertions)] {
449 checked_sub(self, rhs).expect("overflow when sub")
450 } else {
451 wrapping_sub(self, rhs)
452 }
453 }
454 }
455}
456
457impl SubAssign for U {
458 fn sub_assign(&mut self, o: Self) {
459 *self = *self - o;
460 }
461}
462
463impl Mul for U {
464 type Output = U;
465
466 fn mul(self, rhs: U) -> U {
467 cfg_if::cfg_if! {
468 if #[cfg(debug_assertions)] {
469 checked_mul(&self, &rhs).expect("overflow when mul")
470 } else {
471 wrapping_mul(&self, &rhs)
472 }
473 }
474 }
475}
476
477impl Mul for &U {
478 type Output = U;
479
480 fn mul(self, rhs: &U) -> U {
481 cfg_if::cfg_if! {
482 if #[cfg(debug_assertions)] {
483 checked_mul(self, rhs).expect("overflow when mul")
484 } else {
485 wrapping_mul(self, rhs)
486 }
487 }
488 }
489}
490
491impl Div for U {
492 type Output = U;
493
494 fn div(self, rhs: U) -> U {
495 cfg_if::cfg_if! {
496 if #[cfg(debug_assertions)] {
497 checked_div(&self, &rhs).expect("overflow when div")
498 } else {
499 wrapping_div(&self, &rhs)
500 }
501 }
502 }
503}
504
505impl Div for &U {
506 type Output = U;
507
508 fn div(self, rhs: &U) -> U {
509 cfg_if::cfg_if! {
510 if #[cfg(debug_assertions)] {
511 checked_div(self, rhs).expect("overflow when div")
512 } else {
513 wrapping_div(self, rhs)
514 }
515 }
516 }
517}
518
519impl Rem for U {
520 type Output = U;
521
522 fn rem(self, rhs: U) -> U {
523 modd(&self, &rhs)
524 }
525}
526
527impl Rem for &U {
528 type Output = U;
529
530 fn rem(self, rhs: &U) -> U {
531 modd(self, rhs)
532 }
533}
534
535impl Shl<usize> for U {
536 type Output = Self;
537
538 fn shl(self, shift: usize) -> Self::Output {
539 if shift >= 256 {
540 return U::ZERO;
541 }
542 let mut result = [0u8; 32];
543 let byte_shift = shift / 8;
544 let bit_shift = shift % 8;
545 if bit_shift == 0 {
546 for i in 0..(32 - byte_shift) {
547 result[i] = self.0[i + byte_shift];
548 }
549 } else {
550 let mut carry = 0u8;
551 for i in (byte_shift..32).rev() {
552 let src_idx = i;
553 let dst_idx = i - byte_shift;
554 let byte = self.0[src_idx];
555 result[dst_idx] = (byte << bit_shift) | carry;
556 carry = byte >> (8 - bit_shift);
557 }
558 }
559 U(result)
560 }
561}
562
563impl ShlAssign<usize> for U {
564 fn shl_assign(&mut self, rhs: usize) {
565 *self = *self << rhs
566 }
567}
568
569impl Shr<usize> for U {
570 type Output = Self;
571
572 fn shr(self, shift: usize) -> Self::Output {
573 if shift >= 256 {
574 return U::ZERO;
575 }
576 let mut result = U::ZERO;
577 let byte_shift = shift / 8;
578 let bit_shift = shift % 8;
579 if bit_shift == 0 {
580 for i in byte_shift..32 {
581 result[i] = self.0[i - byte_shift];
582 }
583 } else {
584 let mut carry = 0u8;
585 for i in 0..(32 - byte_shift) {
586 let src_idx = i;
587 let dst_idx = i + byte_shift;
588 let byte = self.0[src_idx];
589 result[dst_idx] = (byte >> bit_shift) | carry;
590 carry = byte << (8 - bit_shift);
591 }
592 }
593 result
594 }
595}
596
597impl ShrAssign<usize> for U {
598 fn shr_assign(&mut self, rhs: usize) {
599 *self = *self >> rhs
600 }
601}
602
603impl Eq for U {}
604
605impl PartialOrd for U {
606 fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
607 Some(self.cmp(other))
608 }
609}
610
611impl Ord for U {
612 fn cmp(&self, other: &Self) -> Ordering {
613 self.0.cmp(&other.0)
614 }
615}
616
617impl Debug for U {
618 fn fmt(&self, f: &mut Formatter<'_>) -> Result<(), FmtError> {
619 let mut b = [0u8; 20 * 2];
620 let Ok(s) = const_hex::encode_to_str(self.0, &mut b) else {
621 return Err(FmtError);
622 };
623 write!(f, "{s}")
624 }
625}
626
627impl U {
628 pub const ZERO: Self = U([0u8; 32]);
629
630 pub const MAX: Self = U([u8::MAX; 32]);
631
632 pub const ONE: Self = U([
633 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,
634 0, 1,
635 ]);
636
637 pub fn is_true(&self) -> bool {
638 self.0[31] == 1
639 }
640
641 pub const fn is_zero(&self) -> bool {
642 let mut i = 0;
643 while i < 32 {
644 if self.0[i] != 0 {
645 return false;
646 }
647 i += 1;
648 }
649 true
650 }
651
652 pub const fn is_max(&self) -> bool {
653 let mut i = 0;
654 while i < 32 {
655 if self.0[i] != u8::MAX {
656 return false;
657 }
658 i += 1;
659 }
660 true
661 }
662
663 pub fn is_some(&self) -> bool {
664 !self.is_zero()
665 }
666
667 pub fn as_slice(&self) -> &[u8; 32] {
668 &self.0
669 }
670
671 pub fn checked_add(&self, y: &Self) -> Option<Self> {
672 checked_add(self, y)
673 }
674
675 pub fn checked_mul(&self, y: &Self) -> Option<Self> {
676 checked_mul(self, y)
677 }
678
679 pub fn checked_sub(&self, y: &Self) -> Option<Self> {
680 checked_sub(self, y)
681 }
682
683 pub fn checked_div(&self, y: &Self) -> Option<Self> {
684 checked_div(self, y)
685 }
686
687 pub fn checked_pow(&self, exp: &U) -> Option<Self> {
688 checked_pow(self, exp)
689 }
690
691 pub fn wrapping_add(&self, y: &Self) -> U {
692 wrapping_add(self, y)
693 }
694
695 pub fn wrapping_sub(&self, y: &Self) -> U {
696 wrapping_sub(self, y)
697 }
698
699 pub fn wrapping_mul(&self, y: &Self) -> U {
700 wrapping_mul(self, y)
701 }
702
703 pub fn wrapping_div(&self, y: &Self) -> U {
704 wrapping_div(self, y)
705 }
706
707 pub fn saturating_add(&self, y: &Self) -> U {
708 saturating_add(self, y)
709 }
710
711 pub fn saturating_sub(&self, y: &Self) -> U {
712 saturating_sub(self, y)
713 }
714
715 pub fn saturating_mul(&self, y: &Self) -> U {
716 saturating_mul(self, y)
717 }
718
719 pub fn widening_mul(&self, y: &Self) -> [u8; 64] {
720 widening_mul(self, y)
721 }
722
723 pub fn mul_div(&self, y: &Self, z: &Self) -> Option<(Self, bool)> {
724 mul_div(self, y, z)
725 }
726
727 pub fn mul_div_round_up(&self, y: &Self, z: &Self) -> Option<Self> {
728 mul_div_round_up(self, y, z)
729 }
730
731 pub fn mul_mod(&self, y: &Self, z: &Self) -> Self {
732 let mut b = self.0;
733 unsafe { math_mul_mod(b.as_mut_ptr(), y.as_ptr(), z.as_ptr()) }
734 Self(b)
735 }
736
737 pub fn add_mod(&self, y: &Self, z: &Self) -> Self {
738 let mut b = self.0;
739 unsafe { math_add_mod(b.as_mut_ptr(), y.as_ptr(), z.as_ptr()) }
740 Self(b)
741 }
742
743 pub fn checked_rooti(self, x: u32) -> Option<Self> {
744 checked_rooti(self, x)
745 }
746}
747
748#[cfg(feature = "alloc")]
749impl core::fmt::Display for U {
750 fn fmt(&self, f: &mut Formatter<'_>) -> core::fmt::Result {
751 let mut result = vec![0u8];
752 for &byte in &self.0 {
753 let mut carry = byte as u32;
754 for digit in result.iter_mut() {
755 let temp = (*digit as u32) * 256 + carry;
756 *digit = (temp % 10) as u8;
757 carry = temp / 10;
758 }
759 while carry > 0 {
760 result.push((carry % 10) as u8);
761 carry /= 10;
762 }
763 }
764 if result.iter().all(|&d| d == 0) {
765 return write!(f, "0");
766 }
767 write!(
768 f,
769 "{}",
770 result
771 .iter()
772 .rev()
773 .skip_while(|&&d| d == 0)
774 .map(|&d| (d + b'0') as char)
775 .collect::<String>()
776 )
777 }
778}
779
780impl From<U> for [u8; 32] {
781 fn from(x: U) -> Self {
782 x.0
783 }
784}
785
786impl From<U> for bool {
787 fn from(x: U) -> Self {
788 x.0[31] == 1
789 }
790}
791
792impl From<&[u8; 32]> for &U {
793 fn from(x: &[u8; 32]) -> Self {
794 unsafe { &*(x as *const [u8; 32] as *const U) }
795 }
796}
797
798impl From<[u8; 32]> for U {
799 fn from(x: [u8; 32]) -> Self {
800 U(x)
801 }
802}
803
804impl Deref for U {
805 type Target = [u8; 32];
806
807 fn deref(&self) -> &Self::Target {
808 &self.0
809 }
810}
811
812impl DerefMut for U {
813 fn deref_mut(&mut self) -> &mut Self::Target {
814 &mut self.0
815 }
816}
817
818impl From<bool> for U {
819 fn from(x: bool) -> Self {
820 U::from(&[x as u8])
821 }
822}
823
824impl Zero for U {
825 fn zero() -> Self {
826 U::ZERO
827 }
828
829 fn is_zero(&self) -> bool {
830 self.0.iter().all(|&b| b == 0)
831 }
832}
833
834impl Default for U {
835 fn default() -> Self {
836 U::ZERO
837 }
838}
839
840impl One for U {
841 fn one() -> Self {
842 U::ONE
843 }
844}
845
846impl Index<usize> for U {
847 type Output = u8;
848
849 fn index(&self, index: usize) -> &Self::Output {
850 &self.0[index]
851 }
852}
853
854impl IndexMut<usize> for U {
855 fn index_mut(&mut self, index: usize) -> &mut Self::Output {
856 &mut self.0[index]
857 }
858}
859
860impl I {
861 fn is_neg(&self) -> bool {
862 self.0[0] & 0x80 != 0
863 }
864
865 pub fn is_zero(&self) -> bool {
866 *self == Self::ZERO
867 }
868
869 pub fn is_some(&self) -> bool {
870 !self.is_zero()
871 }
872
873 pub fn as_slice(&self) -> &[u8; 32] {
874 &self.0
875 }
876
877 fn neg(&self) -> Self {
878 let x = wrapping_add(&U(self.0.map(|b| !b)), &U::ONE);
879 I(x.0)
880 }
881
882 fn abs(self) -> U {
883 if self.is_neg() {
884 U(self.neg().0)
885 } else {
886 U(self.0)
887 }
888 }
889}
890
891macro_rules! from_slices {
892 ($($n:expr),+ $(,)?) => {
893 $(
894 impl From<&[u8; $n]> for U {
895 fn from(x: &[u8; $n]) -> Self {
896 let mut b = [0u8; 32];
897 b[32 - $n..].copy_from_slice(x);
898 U(b)
899 }
900 }
901
902 impl From<[u8; $n]> for U {
903 fn from(x: [u8; $n]) -> Self {
904 U::from(&x)
905 }
906 }
907
908 impl From<U> for [u8; $n] {
909 fn from(x: U) -> Self {
910 unsafe { *(x.as_ptr().add(32 - $n) as *const [u8; $n]) }
911 }
912 }
913 )+
914 };
915}
916
917from_slices!(
918 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,
919 27, 28, 29, 30, 31
920);
921
922impl From<&U> for Address {
923 fn from(x: &U) -> Self {
924 (*x).into()
925 }
926}
927
928macro_rules! from_ints {
929 ($($t:ty),+ $(,)?) => {
930 $(
931 impl From<$t> for U {
932 fn from(x: $t) -> Self {
933 let mut b = [0u8; 32];
934 b[32 - core::mem::size_of::<$t>()..].copy_from_slice(&x.to_be_bytes());
935 U(b)
936 }
937 }
938
939 impl From<U> for $t {
940 fn from(x: U) -> Self {
941 Self::from_be_bytes(x.into())
942 }
943 }
944 )+
945 };
946}
947
948from_ints! { u8, u16, u32, u64, u128, usize }
949
950impl From<I> for [u8; 32] {
951 fn from(x: I) -> Self {
952 x.0
953 }
954}
955
956impl From<[u8; 32]> for I {
957 fn from(x: [u8; 32]) -> Self {
958 I(x)
959 }
960}
961
962fn i_add(x: &I, y: &I) -> I {
963 I(wrapping_add(&U(x.0), &U(y.0)).0)
964}
965
966fn i_sub(x: &I, y: &I) -> I {
967 I(wrapping_sub(&U(x.0), &U(y.0)).0)
968}
969
970fn i_mul(x: &I, y: &I) -> I {
971 let result = wrapping_mul(&U(x.0), &U(y.0));
972 I(result.0)
973}
974
975fn i_div(x: &I, y: &I) -> I {
976 let r = wrapping_div(&x.abs(), &y.abs());
977 if x.is_neg() ^ y.is_neg() {
978 I(r.0).neg()
979 } else {
980 I(r.0)
981 }
982}
983
984fn i_rem(x: &I, y: &I) -> I {
985 let r = modd(&x.abs(), &y.abs());
986 if x.is_neg() {
987 I(r.0).neg()
988 } else {
989 I(r.0)
990 }
991}
992
993impl Add for I {
994 type Output = I;
995 fn add(self, rhs: I) -> I {
996 i_add(&self, &rhs)
997 }
998}
999
1000impl Add for &I {
1001 type Output = I;
1002 fn add(self, rhs: &I) -> I {
1003 i_add(self, rhs)
1004 }
1005}
1006
1007impl Sub for I {
1008 type Output = I;
1009 fn sub(self, rhs: I) -> I {
1010 i_sub(&self, &rhs)
1011 }
1012}
1013
1014impl Sub for &I {
1015 type Output = I;
1016 fn sub(self, rhs: &I) -> I {
1017 i_sub(self, rhs)
1018 }
1019}
1020
1021impl Mul for I {
1022 type Output = I;
1023 fn mul(self, rhs: I) -> I {
1024 i_mul(&self, &rhs)
1025 }
1026}
1027
1028impl Mul for &I {
1029 type Output = I;
1030 fn mul(self, rhs: &I) -> I {
1031 i_mul(self, rhs)
1032 }
1033}
1034
1035impl Div for I {
1036 type Output = I;
1037 fn div(self, rhs: I) -> I {
1038 i_div(&self, &rhs)
1039 }
1040}
1041
1042impl Div for &I {
1043 type Output = I;
1044 fn div(self, rhs: &I) -> I {
1045 i_div(self, rhs)
1046 }
1047}
1048
1049impl Rem for I {
1050 type Output = I;
1051 fn rem(self, rhs: I) -> I {
1052 i_rem(&self, &rhs)
1053 }
1054}
1055
1056impl Eq for I {}
1057
1058impl PartialOrd for I {
1059 fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
1060 Some(self.cmp(other))
1061 }
1062}
1063
1064impl Ord for I {
1065 fn cmp(&self, other: &Self) -> Ordering {
1066 let self_sign = self.0[0] & 0x80;
1067 let other_sign = other.0[0] & 0x80;
1068 match (self_sign, other_sign) {
1069 (0, 0x80) => Ordering::Greater,
1070 (0x80, 0) => Ordering::Less,
1071 _ => self.0.cmp(&other.0),
1072 }
1073 }
1074}
1075
1076impl Rem for &I {
1077 type Output = I;
1078 fn rem(self, rhs: &I) -> I {
1079 i_rem(self, rhs)
1080 }
1081}
1082
1083impl I {
1084 pub const ZERO: Self = I([0u8; 32]);
1085
1086 pub const ONE: Self = I([
1087 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,
1088 0, 1,
1089 ]);
1090}
1091
1092impl Zero for I {
1093 fn zero() -> Self {
1094 I::ZERO
1095 }
1096 fn is_zero(&self) -> bool {
1097 self.0.iter().all(|&b| b == 0)
1098 }
1099}
1100
1101impl Default for I {
1102 fn default() -> Self {
1103 I::ZERO
1104 }
1105}
1106
1107impl One for I {
1108 fn one() -> Self {
1109 I::ONE
1110 }
1111}
1112
1113#[test]
1114fn test_is_zeroes() {
1115 assert!(U::ZERO.is_zero());
1116 assert!(U::ONE.is_some());
1117 assert!(I::ZERO.is_zero());
1118 assert!(I::ONE.is_some());
1119}
1120
1121#[cfg(all(
1122 test,
1123 feature = "alloy-enabled",
1124 feature = "proptest-enabled",
1125 feature = "std",
1126 not(target_arch = "wasm32")
1127))]
1128mod test {
1129 use proptest::prelude::*;
1130
1131 use super::*;
1132
1133 fn u_from_u64(value: u64) -> U {
1134 U::from(value)
1135 }
1136
1137 proptest! {
1138 #[test]
1139 fn wrapping_div_b_zero_denominator_yields_zero(numerator in any::<[u8; 4]>()) {
1140 let zero = [0u8; 4];
1141 prop_assert_eq!(wrapping_div_quo_rem_b::<4>(&numerator, &zero).0, zero);
1142 }
1143
1144 #[test]
1145 fn wrapping_div_b_matches_integer_division(
1146 numerator in any::<[u8; 4]>(),
1147 denominator in any::<[u8; 4]>().prop_filter("denominator must be non-zero", |d| *d != [0u8; 4])
1148 ) {
1149 let numerator_u32 = u32::from_be_bytes(numerator);
1150 let denominator_u32 = u32::from_be_bytes(denominator);
1151 let expected = numerator_u32 / denominator_u32;
1152 prop_assert_eq!(
1153 wrapping_div_quo_rem_b::<4>(&numerator, &denominator).0,
1154 expected.to_be_bytes()
1155 );
1156 }
1157
1158 #[test]
1159 fn wrapping_mod_b_matches_integer_modulo(
1160 numerator in any::<[u8; 4]>(),
1161 denominator in any::<[u8; 4]>().prop_filter("denominator must be non-zero", |d| *d != [0u8; 4])
1162 ) {
1163 let numerator_u32 = u32::from_be_bytes(numerator);
1164 let denominator_u32 = u32::from_be_bytes(denominator);
1165 let expected = numerator_u32 % denominator_u32;
1166 prop_assert_eq!(
1167 wrapping_div_quo_rem_b::<4>(&numerator, &denominator).1,
1168 expected.to_be_bytes()
1169 );
1170 }
1171
1172 #[test]
1173 fn wrapping_add_b_handles_carry(lhs in any::<[u8; 4]>(), rhs in any::<[u8; 4]>()) {
1174 let lhs_u32 = u32::from_be_bytes(lhs);
1175 let rhs_u32 = u32::from_be_bytes(rhs);
1176 let expected = lhs_u32.wrapping_add(rhs_u32);
1177 prop_assert_eq!(wrapping_add_b::<4>(&lhs, &rhs), expected.to_be_bytes());
1178 }
1179
1180 #[test]
1181 fn wrapping_sub_b_handles_borrow(lhs in any::<[u8; 4]>(), rhs in any::<[u8; 4]>()) {
1182 let lhs_u32 = u32::from_be_bytes(lhs);
1183 let rhs_u32 = u32::from_be_bytes(rhs);
1184 let expected = lhs_u32.wrapping_sub(rhs_u32);
1185 prop_assert_eq!(wrapping_sub_b::<4>(&lhs, &rhs), expected.to_be_bytes());
1186 }
1187
1188 #[test]
1189 fn wrapping_mul_b_matches_wrapping_arithmetic(lhs in any::<[u8; 32]>(), rhs in any::<[u8; 32]>()) {
1190 let lhs_u = U::from(lhs);
1191 let rhs_u = U::from(rhs);
1192 let expected = lhs_u.wrapping_mul(&rhs_u);
1193 prop_assert_eq!(wrapping_mul_b::<32>(&lhs, &rhs), expected.0);
1194 }
1195
1196 #[test]
1197 fn const_wrapping_div_agrees_with_wrapping_div_b(
1198 numerator in any::<[u8; 32]>(),
1199 denominator in any::<[u8; 32]>().prop_filter("denominator must be non-zero", |d| *d != [0u8; 32])
1200 ) {
1201 let numerator_u = U::from(numerator);
1202 let denominator_u = U::from(denominator);
1203 prop_assert_eq!(
1204 const_wrapping_div(&numerator_u, &denominator_u).0,
1205 wrapping_div_quo_rem_b::<32>(&numerator, &denominator).0
1206 );
1207 }
1208
1209 #[test]
1210 fn u_predicates_track_zero_and_true(bytes in any::<[u8; 32]>()) {
1211 let value = U::from(bytes);
1212 let is_zero = bytes.iter().all(|&b| b == 0);
1213 prop_assert_eq!(value.is_zero(), is_zero);
1214 prop_assert_eq!(value.is_some(), !is_zero);
1215 prop_assert_eq!(value.is_true(), bytes[31] == 1);
1216 }
1217
1218 #[test]
1219 fn mul_div_returns_expected_quotient_and_carry(
1220 lhs in any::<u64>(),
1221 rhs in any::<u64>(),
1222 denom in any::<u64>().prop_filter("denominator must be non-zero", |d| *d != 0)
1223 ) {
1224 let lhs_u = u_from_u64(lhs);
1225 let rhs_u = u_from_u64(rhs);
1226 let denom_u = u_from_u64(denom);
1227 let (q, carry) = lhs_u.mul_div(&rhs_u, &denom_u).expect("division should succeed");
1228
1229 let product = (lhs as u128) * (rhs as u128);
1230 let denom_u128 = denom as u128;
1231 let expected_q = product / denom_u128;
1232 let expected_rem = product % denom_u128;
1233
1234 prop_assert_eq!(u128::from(q), expected_q);
1235 prop_assert_eq!(carry, expected_rem != 0);
1236 }
1237
1238 #[test]
1239 fn mul_div_round_up_accounts_for_carry(
1240 lhs in any::<u64>(),
1241 rhs in any::<u64>(),
1242 denom in any::<u64>().prop_filter("denominator must be non-zero", |d| *d != 0)
1243 ) {
1244 let lhs_u = u_from_u64(lhs);
1245 let rhs_u = u_from_u64(rhs);
1246 let denom_u = u_from_u64(denom);
1247 let rounded = lhs_u
1248 .mul_div_round_up(&rhs_u, &denom_u)
1249 .expect("rounding should succeed");
1250
1251 let product = (lhs as u128) * (rhs as u128);
1252 let denom_u128 = denom as u128;
1253 let expected = if product % denom_u128 == 0 {
1254 product / denom_u128
1255 } else {
1256 (product / denom_u128) + 1
1257 };
1258
1259 prop_assert_eq!(u128::from(rounded), expected);
1260 }
1261
1262 #[test]
1263 fn test_u_is_zero(x in any::<[u8; 32]>()) {
1264 let x = U::from(x);
1265 let ex = U256::from_be_bytes(x.0);
1266 assert_eq!(ex.is_zero(), x.is_zero());
1267 }
1268
1269 #[test]
1270 fn test_u_div(x in any::<U>(), y in any::<U>()) {
1271 let ex = U256::from_be_bytes(x.0);
1272 let ey = U256::from_be_bytes(y.0);
1273 assert_eq!((ex.wrapping_div(ey)).to_be_bytes(), x.wrapping_div(&y).0);
1274 }
1275
1276 #[test]
1277 fn test_u_mul(x in any::<U>(), y in any::<U>()) {
1278 let ex = U256::from_be_bytes(x.0);
1279 let ey = U256::from_be_bytes(y.0);
1280 assert_eq!((ex.wrapping_mul(ey)).to_be_bytes(), wrapping_mul(&x, &y).0);
1281 }
1282
1283 #[test]
1284 fn test_u_mod(x in any::<U>(), y in any::<U>()) {
1285 let ex = U256::from_be_bytes(x.0);
1286 let ey = U256::from_be_bytes(y.0);
1287 assert_eq!((ex % ey).to_be_bytes(), (x % y).0);
1288 }
1289
1290 #[test]
1291 fn test_u_add(x in any::<U>(), y in any::<U>()) {
1292 let ex = U256::from_be_bytes(x.0);
1293 let ey = U256::from_be_bytes(y.0);
1294 let e = U::from(ex.wrapping_add(ey).to_be_bytes::<32>());
1295 assert_eq!(e, x.wrapping_add(&y), "{e} != {}", x + y);
1296 }
1297
1298 #[test]
1299 fn test_u_sub(x in any::<U>(), y in any::<U>()) {
1300 let ex = U256::from_be_bytes(x.0);
1301 let ey = U256::from_be_bytes(y.0);
1302 assert_eq!((ex.wrapping_sub(ey)).to_be_bytes(), x.wrapping_sub(&y).0);
1303 }
1304
1305 #[test]
1306 fn test_u_cmp(x in any::<U>(), y in any::<U>()) {
1307 let ex = U256::from_be_bytes(x.0);
1308 let ey = U256::from_be_bytes(y.0);
1309 assert_eq!(ex.cmp(&ey), x.cmp(&y));
1310 }
1311
1312 #[test]
1313 #[cfg(feature = "alloc")]
1314 fn test_u_str(x in any::<U>()) {
1315 assert_eq!(U256::from_be_bytes(x.0).to_string(), x.to_string());
1316 }
1317
1318 #[test]
1319 fn test_i_is_zero(x in any::<U>()) {
1320 let ex = I256::from_be_bytes(x.0);
1321 assert_eq!(ex.is_zero(), x.is_zero());
1322 }
1323
1324 #[test]
1325 fn test_i_div(x in any::<I>(), y in any::<I>()) {
1326 let ex = I256::from_be_bytes(x.0);
1327 let ey = I256::from_be_bytes(y.0);
1328 assert_eq!((ex / ey).to_be_bytes(), (x / y).0);
1329 }
1330
1331 #[test]
1332 fn test_i_mul(x in any::<I>(), y in any::<I>()) {
1333 let ex = I256::from_be_bytes(x.0);
1334 let ey = I256::from_be_bytes(y.0);
1335 assert_eq!((ex.wrapping_mul(ey)).to_be_bytes(), (x * y).0);
1336 }
1337
1338 #[test]
1339 fn test_i_mod(x in any::<I>(), y in any::<I>()) {
1340 let ex = I256::from_be_bytes(x.0);
1341 let ey = I256::from_be_bytes(y.0);
1342 assert_eq!((ex % ey).to_be_bytes(), (x % y).0);
1343 }
1344
1345 #[test]
1346 fn test_i_add(x in any::<I>(), y in any::<I>()) {
1347 let ex = I256::from_be_bytes(x.0);
1348 let ey = I256::from_be_bytes(y.0);
1349 assert_eq!((ex.wrapping_add(ey)).to_be_bytes(), (x + y).0);
1350 }
1351
1352 #[test]
1353 fn test_i_sub(x in any::<I>(), y in any::<I>()) {
1354 let ex = I256::from_be_bytes(x.0);
1355 let ey = I256::from_be_bytes(y.0);
1356 assert_eq!((ex.wrapping_sub(ey)).to_be_bytes(), (x - y).0);
1357 }
1358
1359 #[test]
1360 fn test_i_cmp(x in any::<I>(), y in any::<I>()) {
1361 let ex = I256::from_be_bytes(x.0);
1362 let ey = I256::from_be_bytes(y.0);
1363 assert_eq!(ex.cmp(&ey), x.cmp(&y));
1364 }
1365
1366 #[test]
1367 fn test_u_u8(x in any::<u8>()) {
1368 let mut b = [0u8; 32];
1369 b[32-std::mem::size_of::<u8>()..].copy_from_slice(&x.to_be_bytes());
1370 assert_eq!(&U256::from_be_bytes(b).to_be_bytes(), U::from(x).as_slice());
1371 }
1372
1373 #[test]
1374 fn test_u_u16(x in any::<u16>()) {
1375 let mut b = [0u8; 32];
1376 b[32-std::mem::size_of::<u16>()..].copy_from_slice(&x.to_be_bytes());
1377 assert_eq!(&U256::from_be_bytes(b).to_be_bytes(), U::from(x).as_slice());
1378 }
1379
1380 #[test]
1381 fn test_u_u32(x in any::<u32>()) {
1382 let mut b = [0u8; 32];
1383 b[32-std::mem::size_of::<u32>()..].copy_from_slice(&x.to_be_bytes());
1384 assert_eq!(&U256::from_be_bytes(b).to_be_bytes(), U::from(x).as_slice());
1385 }
1386
1387 #[test]
1388 fn test_u_u64(x in any::<u64>()) {
1389 let mut b = [0u8; 32];
1390 b[32-std::mem::size_of::<u64>()..].copy_from_slice(&x.to_be_bytes());
1391 assert_eq!(&U256::from_be_bytes(b).to_be_bytes(), U::from(x).as_slice());
1392 }
1393
1394 #[test]
1395 fn test_u_u128(x in any::<u128>()) {
1396 let mut b = [0u8; 32];
1397 b[32-std::mem::size_of::<u128>()..].copy_from_slice(&x.to_be_bytes());
1398 assert_eq!(&U256::from_be_bytes(b).to_be_bytes(), U::from(x).as_slice());
1399 }
1400
1401 #[test]
1402 fn test_to_and_from_addrs(x in any::<Address>()) {
1403 let y: Address = U::from(x).into();
1404 assert_eq!(x, y)
1405 }
1406
1407 #[test]
1408 fn test_u_conv_to_and_from_u8(x in any::<u8>()) {
1409 assert_eq!(x.wrapping_add(1), U::from(x).wrapping_add(&U::ONE).into());
1410 }
1411 }
1412}