1#![cfg_attr(not(feature = "std"), no_std)]
2
3use core::{
4 cmp::{Eq, Ordering},
5 fmt::{Debug, Display, Error as FmtError, Formatter},
6 ops::{
7 Add, AddAssign, BitAnd, BitOr, BitOrAssign, BitXor, Deref, DerefMut, Div, Index, IndexMut,
8 Mul, MulAssign, Neg, Not, Rem, Shl, ShlAssign, Shr, ShrAssign, Sub, SubAssign,
9 },
10 str::FromStr,
11};
12
13#[allow(unused)]
14use core::ptr::copy_nonoverlapping;
15
16#[cfg(feature = "std")]
17use clap::builder::TypedValueParser;
18
19use bobcat_panic::{panic_on_err_div_by_zero, panic_on_err_overflow};
20
21use num_traits::{One, Zero};
22
23#[cfg(feature = "borsh")]
24use borsh::{BorshDeserialize, BorshSerialize};
25
26#[cfg(feature = "serde")]
27use serde::{Deserialize as SerdeDeserialize, Serialize as SerdeSerialize};
28
29#[cfg(feature = "proptest")]
30pub mod strategies;
31
32#[cfg(feature = "alloc")]
33extern crate alloc;
34
35#[cfg(all(
36 any(feature = "wasm-bindgen", feature = "wasm-bindgen-wasi"),
37 target_arch = "wasm32"
38))]
39use alloc::boxed::Box;
40
41type Address = [u8; 20];
42
43#[link(wasm_import_module = "vm_hooks")]
44#[cfg(not(feature = "alloy-enabled"))]
45unsafe extern "C" {
46 fn math_div(x: *mut u8, y: *const u8);
47 fn math_mod(x: *mut u8, y: *const u8);
48 fn math_add_mod(a: *mut u8, b: *const u8, c: *const u8);
49 fn math_mul_mod(a: *mut u8, b: *const u8, c: *const u8);
50}
51
52#[cfg(feature = "ruint-enabled")]
53use alloy_primitives::{ruint, U256};
54
55#[cfg(any(
56 all(
57 feature = "wasm-bindgen-wasi",
58 target_os = "wasi",
59 any(target_env = "p1", target_env = "p2")
60 ),
61 all(feature = "wasm-bindgen", target_arch = "wasm32")
62))]
63use wasm_bindgen::{
64 convert::{FromWasmAbi, IntoWasmAbi},
65 describe::WasmDescribe,
66};
67
68#[cfg(feature = "alloy-enabled")]
69mod alloy {
70 use super::copy_nonoverlapping;
71
72 pub(crate) use alloy_primitives::U256;
73
74 #[cfg(test)]
75 pub(crate) use alloy_primitives::I256;
76
77 pub(crate) unsafe fn math_div(out: *mut u8, y: *const u8) {
78 unsafe {
79 let x = U256::from_be_slice(&*(out as *const [u8; 32]));
80 let y = U256::from_be_slice(&*(y as *const [u8; 32]));
81 let z = if y.is_zero() {
82 U256::ZERO
84 } else {
85 x / y
86 };
87 copy_nonoverlapping(z.to_be_bytes::<32>().as_ptr(), out, 32);
88 }
89 }
90
91 pub(crate) unsafe fn math_mod(out: *mut u8, y: *const u8) {
92 unsafe {
93 let x = U256::from_be_slice(&*(out as *const [u8; 32]));
94 let y = U256::from_be_slice(&*(y as *const [u8; 32]));
95 let z = x % y;
96 copy_nonoverlapping(z.to_be_bytes::<32>().as_ptr(), out, 32);
97 }
98 }
99
100 pub(crate) unsafe fn math_add_mod(a: *mut u8, b: *const u8, c: *const u8) {
101 unsafe {
102 let x = U256::from_be_slice(&*(a as *const [u8; 32]));
103 let y = U256::from_be_slice(&*(b as *const [u8; 32]));
104 let z = U256::from_be_slice(&*(c as *const [u8; 32]));
105 let x = x.add_mod(y, z);
106 copy_nonoverlapping(x.to_be_bytes::<32>().as_ptr(), a, 32);
107 }
108 }
109
110 pub(crate) unsafe fn math_mul_mod(a: *mut u8, b: *const u8, c: *const u8) {
111 unsafe {
112 let x = U256::from_be_slice(&*(a as *const [u8; 32]));
113 let y = U256::from_be_slice(&*(b as *const [u8; 32]));
114 let z = U256::from_be_slice(&*(c as *const [u8; 32]));
115 let x = x.mul_mod(y, z);
116 copy_nonoverlapping(x.to_be_bytes::<32>().as_ptr(), a, 32);
117 }
118 }
119}
120
121#[cfg(feature = "alloy-enabled")]
122use alloy::*;
123
124#[derive(Copy, Clone, PartialEq, Hash)]
125#[cfg_attr(feature = "proptest", derive(proptest_derive::Arbitrary))]
126#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))]
127#[cfg_attr(feature = "borsh", derive(BorshDeserialize, BorshSerialize))]
128#[cfg_attr(feature = "serde", derive(SerdeSerialize, SerdeDeserialize))]
129#[repr(transparent)]
130pub struct U(pub [u8; 32]);
131
132#[derive(Copy, Clone, PartialEq, Hash, Debug)]
133#[cfg_attr(feature = "proptest", derive(proptest_derive::Arbitrary))]
134#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))]
135#[cfg_attr(feature = "borsh", derive(BorshDeserialize, BorshSerialize))]
136#[cfg_attr(feature = "serde", derive(SerdeSerialize, SerdeDeserialize))]
137#[repr(transparent)]
138pub struct I(pub [u8; 32]);
139
140#[cfg(feature = "std")]
141impl clap::builder::ValueParserFactory for U {
142 type Parser = UValueParser;
143
144 fn value_parser() -> Self::Parser {
145 UValueParser
146 }
147}
148
149#[derive(Clone)]
150pub struct UValueParser;
151
152#[cfg(feature = "std")]
153impl TypedValueParser for UValueParser {
154 type Value = U;
155
156 fn parse_ref(
157 &self,
158 _: &clap::Command,
159 _: Option<&clap::Arg>,
160 value: &std::ffi::OsStr,
161 ) -> Result<Self::Value, clap::Error> {
162 let s = value
163 .to_str()
164 .ok_or_else(|| clap::Error::raw(clap::error::ErrorKind::InvalidUtf8, "bad utf8"))?;
165 U::from_str(s).map_err(|e| {
166 clap::Error::raw(
167 clap::error::ErrorKind::ValueValidation,
168 format!("invalid u256: {e}\n"),
169 )
170 })
171 }
172}
173
174#[cfg(any(
175 all(
176 feature = "wasm-bindgen-wasi",
177 target_os = "wasi",
178 any(target_env = "p1", target_env = "p2")
179 ),
180 all(feature = "wasm-bindgen", target_arch = "wasm32")
181))]
182impl WasmDescribe for U {
183 fn describe() {
184 <Box<[u8]> as WasmDescribe>::describe()
185 }
186}
187
188#[cfg(any(
189 all(
190 feature = "wasm-bindgen-wasi",
191 target_os = "wasi",
192 any(target_env = "p1", target_env = "p2")
193 ),
194 all(feature = "wasm-bindgen", target_arch = "wasm32")
195))]
196impl FromWasmAbi for U {
197 type Abi = u32;
198
199 #[inline]
200 unsafe fn from_abi(js: u32) -> Self {
201 let ptr = js as *const u8;
202 let mut bytes = [0u8; 32];
203 unsafe { copy_nonoverlapping(ptr, bytes.as_mut_ptr(), 32) }
204 U(bytes)
205 }
206}
207
208#[cfg(any(
209 all(
210 feature = "wasm-bindgen-wasi",
211 target_os = "wasi",
212 any(target_env = "p1", target_env = "p2")
213 ),
214 all(feature = "wasm-bindgen", target_arch = "wasm32")
215))]
216impl IntoWasmAbi for U {
217 type Abi = u32;
218
219 #[inline]
220 fn into_abi(self) -> u32 {
221 let ptr = Box::into_raw(Box::new(self.0)) as *const u8;
222 ptr as u32
223 }
224}
225
226pub fn wrapping_div(x: &U, y: &U) -> U {
227 assert!(y.is_some(), "divide by zero");
228 let mut b = *x;
229 unsafe { math_div(b.as_mut_ptr(), y.as_ptr()) }
230 b
231}
232
233fn wrapping_div_quo_rem_b<const C: usize>(x: &[u8; C], denom: &[u8; C]) -> ([u8; C], [u8; C]) {
234 if denom == &[0u8; C] {
235 return ([0u8; C], [0u8; C]);
236 }
237 let mut q = [0u8; C];
238 let mut r = [0u8; C];
239 let mut one = [0u8; C];
240 one[C - 1] = 1;
241 let mut two = [0u8; C];
242 two[C - 1] = 2;
243 let mut i = 0;
244 while i < C * 8 {
245 let bit = (x[i / 8] >> (7 - (i % 8))) & 1;
246 r = wrapping_mul_b::<C>(&r, &two);
247 if bit == 1 {
248 r = wrapping_add_b::<C>(&r, &one);
249 }
250 if r >= *denom {
251 r = wrapping_sub_b::<C>(&r, denom);
252 q[i / 8] |= 1 << (7 - (i % 8));
253 }
254 i += 1;
255 }
256 (q, r)
257}
258
259pub fn const_wrapping_div(x: &U, y: &U) -> U {
260 U(wrapping_div_quo_rem_b::<32>(&x.0, &y.0).0)
261}
262
263#[cfg_attr(test, mutants::skip)]
264pub fn checked_div_opt(x: &U, y: &U) -> Option<U> {
265 if y.is_zero() {
266 None
267 } else {
268 Some(wrapping_div(x, y))
269 }
270}
271
272#[cfg_attr(test, mutants::skip)]
273pub fn checked_div(x: &U, y: &U) -> U {
274 panic_on_err_div_by_zero!(checked_div_opt(x, y), "Division by zero: {x}")
275}
276
277pub fn modd(x: &U, y: &U) -> U {
278 let mut b = *x;
279 unsafe { math_mod(b.as_mut_ptr(), y.as_ptr()) }
280 b
281}
282
283pub fn mul_mod(mut x: U, y: &U, z: &U) -> U {
284 unsafe { math_mul_mod(x.as_mut_ptr(), y.as_ptr(), z.as_ptr()) }
285 x
286}
287
288const fn wrapping_add_b<const C: usize>(x: &[u8; C], y: &[u8; C]) -> [u8; C] {
289 let mut r = [0u8; C];
290 let mut c = 0;
291 let mut i = C - 1;
292 loop {
293 let s = x[i] as u16 + y[i] as u16 + c;
294 r[i] = s as u8;
295 c = s >> 8;
296 if i == 0 {
297 break;
298 }
299 i -= 1;
300 }
301 r
302}
303
304pub const fn wrapping_add(x: &U, y: &U) -> U {
305 U(wrapping_add_b(&x.0, &y.0))
306}
307
308#[cfg_attr(test, mutants::skip)]
309pub fn checked_add_opt(x: &U, y: &U) -> Option<U> {
310 if x > &(U::MAX - *y) {
311 None
312 } else {
313 let z = x.add_mod(y, &U::MAX);
314 if z.is_zero() && (x.is_some() || y.is_some()) {
315 Some(U::MAX)
316 } else {
317 Some(z)
318 }
319 }
320}
321
322#[cfg_attr(test, mutants::skip)]
323pub fn checked_add(x: &U, y: &U) -> U {
324 panic_on_err_overflow!(checked_add_opt(x, y), "Checked add overflow: {x}, y: {y}")
325}
326
327#[cfg_attr(test, mutants::skip)]
328pub fn saturating_add(x: &U, y: &U) -> U {
329 checked_add_opt(x, y).unwrap_or(U::MAX)
330}
331
332const fn wrapping_sub_b<const C: usize>(x: &[u8; C], y: &[u8; C]) -> [u8; C] {
333 let mut neg_y = *y;
334 let mut i = 0;
335 while i < C {
336 neg_y[i] = !neg_y[i];
337 i += 1;
338 }
339 let mut c = 1u16;
340 let mut i = C - 1;
341 loop {
342 let sum = neg_y[i] as u16 + c;
343 neg_y[i] = sum as u8;
344 c = sum >> 8;
345 if i == 0 {
346 break;
347 }
348 i -= 1;
349 }
350 wrapping_add_b(x, &neg_y)
351}
352
353pub const fn wrapping_sub(x: &U, y: &U) -> U {
354 U(wrapping_sub_b::<32>(&x.0, &y.0))
355}
356
357pub fn saturating_sub(x: &U, y: &U) -> U {
358 checked_sub_opt(x, y).unwrap_or(U::ZERO)
359}
360
361#[cfg_attr(test, mutants::skip)]
362pub fn checked_sub_opt(x: &U, y: &U) -> Option<U> {
363 if x < y {
364 None
365 } else {
366 Some(wrapping_sub(x, y))
367 }
368}
369
370#[cfg_attr(test, mutants::skip)]
371pub fn checked_sub(x: &U, y: &U) -> U {
372 panic_on_err_overflow!(checked_sub_opt(x, y), "Checked sub overflow: {x}, y: {y}")
373}
374
375pub const fn wrapping_mul_b<const C: usize>(x: &[u8; C], y: &[u8; C]) -> [u8; C] {
376 let mut r = [0u8; C];
377 let mut i = 0;
378 while i < C {
379 let mut c = 0u16;
380 let mut j = 0;
381 while j < C {
382 let i_r = i + j;
383 if i_r >= C {
384 break;
385 }
386 let r_idx = C - 1 - i_r;
387 let xi = x[C - 1 - i] as u16;
388 let yj = y[C - 1 - j] as u16;
389 let prod = xi * yj + r[r_idx] as u16 + c;
390 r[r_idx] = prod as u8;
391 c = prod >> 8;
392 j += 1;
393 }
394 if i + j < C {
395 let idx = 31 - (i + j);
396 r[idx] = r[idx] + c as u8;
397 }
398 i += 1;
399 }
400 r
401}
402
403pub const fn wrapping_mul(x: &U, y: &U) -> U {
404 U(wrapping_mul_b(&x.0, &y.0))
405}
406
407#[cfg_attr(test, mutants::skip)]
408pub fn checked_mul_opt(x: &U, y: &U) -> Option<U> {
409 if x.is_zero() || y.is_zero() {
410 return Some(U::ZERO);
411 }
412 if x > &(U::MAX / *y) {
413 None
414 } else {
415 let z = x.mul_mod(y, &U::MAX);
416 if z.is_zero() {
417 Some(U::MAX)
418 } else {
419 Some(z)
420 }
421 }
422}
423
424pub fn checked_mul(x: &U, y: &U) -> U {
425 panic_on_err_overflow!(checked_mul_opt(x, y), "Checked mul overflow: {x}, y: {y}")
426}
427
428pub fn saturating_mul(x: &U, y: &U) -> U {
429 checked_mul_opt(x, y).unwrap_or(U::MAX)
430}
431
432pub fn saturating_div(x: &U, y: &U) -> U {
433 checked_div_opt(x, y).unwrap_or(U::MAX)
434}
435
436pub fn widening_mul(x: &U, y: &U) -> [u8; 64] {
437 let shift_128 = &U([
438 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,
439 0, 0,
440 ]);
441 let x_hi = x / shift_128;
442 let x_lo = x % shift_128;
443 let y_hi = y / shift_128;
444 let y_lo = y % shift_128;
445 let t0 = x_lo.mul_mod(&y_lo, &U::MAX);
446 let t1 = x_hi.mul_mod(&y_lo, &U::MAX);
447 let t2 = x_lo.mul_mod(&y_hi, &U::MAX);
448 let t3 = x_hi.mul_mod(&y_hi, &U::MAX);
449 let t0_hi = &t0 / shift_128;
450 let t0_lo = &t0 % shift_128;
451 let t1_hi = &t1 / shift_128;
452 let t1_lo = &t1 % shift_128;
453 let t2_hi = &t2 / shift_128;
454 let t2_lo = &t2 % shift_128;
455 let mid = (t0_hi + t1_lo) + t2_lo;
456 let mid_hi = &mid / shift_128;
457 let mid_lo = &mid % shift_128;
458 let mid_lo_shifted = mid_lo.mul_mod(shift_128, &U::MAX);
459 let out_low = t0_lo + mid_lo_shifted;
460 let out_high = t3 + t1_hi + t2_hi + mid_hi;
461 let mut o = [0u8; 64];
462 o[..32].copy_from_slice(&out_high.0);
463 o[32..].copy_from_slice(&out_low.0);
464 o
465}
466
467pub fn widening_mul_div(x: &U, y: &U, denom: U) -> Option<(U, bool)> {
470 if denom.is_zero() {
471 return None;
472 }
473 if x.is_zero() {
474 return Some((U::ZERO, false));
475 }
476 if wrapping_div(&U::MAX, x) >= *y {
478 let l = wrapping_mul(x, y);
479 let carry = x.mul_mod(y, &denom).is_some();
480 return Some((wrapping_div(&l, &denom), carry));
481 }
482 let x = widening_mul(x, y);
483 let mut d = [0u8; 64];
484 d[32..].copy_from_slice(&denom.0);
485 let (q, rem) = wrapping_div_quo_rem_b::<64>(&x, &d);
486 if q[..32] != [0u8; 32] {
487 return None;
488 }
489 let l: [u8; 32] = q[32..].try_into().unwrap();
490 let l = U::from(l);
491 let has_carry = rem[32..] != [0u8; 32];
492 Some((l, has_carry))
493}
494
495pub fn widening_mul_div_round_up(x: &U, y: &U, denom: U) -> Option<U> {
496 let (x, y) = widening_mul_div(x, y, denom)?;
497 if x.is_max() && y {
498 return None;
499 }
500 Some(if y { x + U::ONE } else { x })
501}
502
503pub fn mul_div(x: &U, y: &U, mut denom: U) -> Option<(U, bool)> {
506 if denom.is_zero() {
508 return None;
509 }
510 if x.is_zero() {
511 return Some((U::ZERO, false));
512 }
513 let mut prod0 = wrapping_mul(x, y);
514 let mm = mul_mod(*x, y, &U::MAX);
515 let mut prod1 = wrapping_sub(
516 &wrapping_sub(&mm, &prod0),
517 &if prod0 > mm { U::ONE } else { U::ZERO },
518 );
519 if prod1.is_zero() {
520 let carry = mul_mod(*x, y, &denom).is_some();
521 return Some((wrapping_div(&prod0, &denom), carry));
522 }
523 if prod1 >= denom {
524 return None;
525 }
526 let remainder = mul_mod(*x, y, &denom);
527 let carry = remainder.is_some();
528 if remainder > prod0 {
529 prod1 -= U::ONE;
530 }
531 prod0 = wrapping_sub(&prod0, &remainder);
532 let mut twos = wrapping_sub(&U::ZERO, &denom) & denom;
533 denom = wrapping_div(&denom, &twos);
534 prod0 = wrapping_div(&prod0, &twos);
535 twos = wrapping_add(
536 &wrapping_div(&wrapping_sub(&U::ZERO, &twos), &twos),
537 &U::ONE,
538 );
539 prod0 = prod0 | wrapping_mul(&prod1, &twos);
540 let mut inv = wrapping_mul(&U::from(3u32), &denom) ^ U::from(2u32);
541 for _ in 0..6 {
542 inv = wrapping_mul(
543 &inv,
544 &wrapping_sub(&U::from(2u32), &wrapping_mul(&denom, &inv)),
545 );
546 }
547 Some((wrapping_mul(&prod0, &inv), carry))
548}
549
550pub fn mul_div_round_up(x: &U, y: &U, denom_and_rem: U) -> Option<U> {
551 let (x, y) = mul_div(x, y, denom_and_rem)?;
552 if x.is_max() && y {
553 return None;
554 }
555 Some(if y { x + U::ONE } else { x })
556}
557
558#[cfg(feature = "ruint-enabled")]
560pub fn ruint_mul_div(x: &U, y: &U, denom: U) -> Option<(U, bool)> {
561 if denom.is_zero() {
562 return None;
563 }
564 let x = U256::from_be_slice(x.as_slice());
565 let y = U256::from_be_slice(y.as_slice());
566 let mut denom = U256::from_be_slice(denom.as_slice());
567 let mut mul_and_quo = x.widening_mul::<256, 4, 512, 8>(y);
568 unsafe {
569 ruint::algorithms::div(mul_and_quo.as_limbs_mut(), denom.as_limbs_mut());
570 }
571 let limbs = mul_and_quo.into_limbs();
572 if limbs[4..] != [0_u64; 4] {
573 return None;
574 }
575 let has_carry = !denom.is_zero();
576 let r = U(U256::from_limbs_slice(&limbs[0..4]).to_be_bytes::<32>());
577 Some((r, has_carry))
578}
579
580#[cfg(feature = "ruint-enabled")]
581pub fn ruint_mul_div_round_up(x: &U, y: &U, denom: U) -> Option<U> {
582 let (x, y) = ruint_mul_div(x, y, denom)?;
583 if x.is_max() && y {
584 return None;
585 }
586 Some(if y { x + U::ONE } else { x })
587}
588
589pub fn checked_rooti(x: U, n: u32) -> Option<U> {
592 if n == 0 {
593 return None;
594 }
595 if x.is_zero() {
596 return Some(U::ZERO);
597 }
598 if n == 1 {
599 return Some(x);
600 }
601 if x == U::from(4u32) && n == 2 {
604 return Some(U::from(2u32));
605 }
606 let n_u256 = U::from(n);
607 let n_1 = n_u256 - U::ONE;
608 let mut b = 0;
610 let mut t = x;
611 while t.is_some() {
612 b += 1;
613 t >>= 1;
614 }
615 let shift = (b + n as usize - 1) / n as usize;
616 let mut z = U::ONE << shift;
617 let mut y = x;
618 while z < y {
620 y = z;
621 let p = z.checked_pow(&n_1)?;
622 z = ((x / p) + (z * n_1)) / n_u256;
623 }
624 if y.checked_pow(&n_u256)? > x {
626 y -= U::ONE;
627 }
628 Some(y)
629}
630
631pub fn wrapping_pow(x: &U, exp: &U) -> U {
632 let mut r = U::ONE;
633 let mut i = U::ZERO;
634 while &i < exp {
635 r = wrapping_mul(&r, x);
636 i += U::ONE;
637 }
638 r
639}
640
641pub fn checked_pow(x: &U, exp: &U) -> Option<U> {
642 let mut r = U::ONE;
643 let mut i = U::ZERO;
644 while &i < exp {
645 r = checked_mul_opt(&r, x)?;
646 i += U::ONE;
647 }
648 Some(r)
649}
650
651impl Add for U {
652 type Output = U;
653
654 fn add(self, rhs: U) -> U {
655 cfg_if::cfg_if! {
656 if #[cfg(debug_assertions)] {
657 checked_add_opt(&self, &rhs).expect("overflow when add")
658 } else {
659 wrapping_add(&self, &rhs)
660 }
661 }
662 }
663}
664
665impl Add for &U {
666 type Output = U;
667
668 fn add(self, rhs: &U) -> U {
669 cfg_if::cfg_if! {
670 if #[cfg(debug_assertions)] {
671 checked_add_opt(self, rhs).expect("overflow when add")
672 } else {
673 wrapping_add(self, rhs)
674 }
675 }
676 }
677}
678
679impl AddAssign for U {
680 fn add_assign(&mut self, o: Self) {
681 *self = *self + o;
682 }
683}
684
685impl Sub for U {
686 type Output = U;
687
688 fn sub(self, rhs: U) -> U {
689 cfg_if::cfg_if! {
690 if #[cfg(debug_assertions)] {
691 checked_sub_opt(&self, &rhs).expect("overflow when sub")
692 } else {
693 wrapping_sub(&self, &rhs)
694 }
695 }
696 }
697}
698
699impl Sub for &U {
700 type Output = U;
701
702 fn sub(self, rhs: &U) -> U {
703 cfg_if::cfg_if! {
704 if #[cfg(debug_assertions)] {
705 checked_sub_opt(self, rhs).expect("overflow when sub")
706 } else {
707 wrapping_sub(self, rhs)
708 }
709 }
710 }
711}
712
713impl SubAssign for U {
714 fn sub_assign(&mut self, o: Self) {
715 *self = *self - o;
716 }
717}
718
719impl Mul for U {
720 type Output = U;
721
722 fn mul(self, rhs: U) -> U {
723 cfg_if::cfg_if! {
724 if #[cfg(debug_assertions)] {
725 checked_mul_opt(&self, &rhs).expect("overflow when mul")
726 } else {
727 wrapping_mul(&self, &rhs)
728 }
729 }
730 }
731}
732
733impl Mul for &U {
734 type Output = U;
735
736 fn mul(self, rhs: &U) -> U {
737 cfg_if::cfg_if! {
738 if #[cfg(debug_assertions)] {
739 checked_mul_opt(self, rhs).expect("overflow when mul")
740 } else {
741 wrapping_mul(self, rhs)
742 }
743 }
744 }
745}
746
747impl MulAssign for U {
748 fn mul_assign(&mut self, rhs: Self) {
749 *self = *self * rhs
750 }
751}
752
753impl Div for U {
754 type Output = U;
755
756 fn div(self, rhs: U) -> U {
757 cfg_if::cfg_if! {
758 if #[cfg(debug_assertions)] {
759 checked_div_opt(&self, &rhs).expect("overflow when div")
760 } else {
761 wrapping_div(&self, &rhs)
762 }
763 }
764 }
765}
766
767impl Div for &U {
768 type Output = U;
769
770 fn div(self, rhs: &U) -> U {
771 cfg_if::cfg_if! {
772 if #[cfg(debug_assertions)] {
773 checked_div_opt(self, rhs).expect("overflow when div")
774 } else {
775 wrapping_div(self, rhs)
776 }
777 }
778 }
779}
780
781impl Rem for U {
782 type Output = U;
783
784 fn rem(self, rhs: U) -> U {
785 modd(&self, &rhs)
786 }
787}
788
789impl Rem for &U {
790 type Output = U;
791
792 fn rem(self, rhs: &U) -> U {
793 modd(self, rhs)
794 }
795}
796
797impl Shl<usize> for U {
798 type Output = Self;
799
800 fn shl(self, shift: usize) -> Self::Output {
801 if shift >= 256 {
802 return U::ZERO;
803 }
804 let mut result = [0u8; 32];
805 let byte_shift = shift / 8;
806 let bit_shift = shift % 8;
807 if bit_shift == 0 {
808 for i in 0..(32 - byte_shift) {
809 result[i] = self.0[i + byte_shift];
810 }
811 } else {
812 let mut carry = 0u8;
813 for i in (byte_shift..32).rev() {
814 let src_idx = i;
815 let dst_idx = i - byte_shift;
816 let byte = self.0[src_idx];
817 result[dst_idx] = (byte << bit_shift) | carry;
818 carry = byte >> (8 - bit_shift);
819 }
820 }
821 U(result)
822 }
823}
824
825impl ShlAssign<usize> for U {
826 fn shl_assign(&mut self, rhs: usize) {
827 *self = *self << rhs
828 }
829}
830
831impl BitAnd for U {
832 type Output = Self;
833
834 fn bitand(self, rhs: Self) -> Self::Output {
835 let mut r = U::ZERO;
836 for i in 0..32 {
837 r[i] = self[i] & rhs[i];
838 }
839 r
840 }
841}
842
843impl BitOr for U {
844 type Output = Self;
845
846 fn bitor(self, rhs: Self) -> Self::Output {
847 let mut r = U::ZERO;
848 for i in 0..32 {
849 r[i] = self[i] | rhs[i];
850 }
851 r
852 }
853}
854
855impl BitXor for U {
856 type Output = Self;
857 fn bitxor(self, rhs: Self) -> Self::Output {
858 let mut r = U::ZERO;
859 for i in 0..32 {
860 r[i] = self[i] ^ rhs[i];
861 }
862 r
863 }
864}
865
866impl BitOrAssign for U {
867 fn bitor_assign(&mut self, rhs: Self) {
868 *self = *self | rhs
869 }
870}
871
872impl Shr<usize> for U {
873 type Output = Self;
874
875 fn shr(self, shift: usize) -> Self::Output {
876 if shift >= 256 {
877 return U::ZERO;
878 }
879 let mut result = U::ZERO;
880 let byte_shift = shift / 8;
881 let bit_shift = shift % 8;
882 if bit_shift == 0 {
883 for i in byte_shift..32 {
884 result[i] = self.0[i - byte_shift];
885 }
886 } else {
887 let mut carry = 0u8;
888 for i in 0..(32 - byte_shift) {
889 let src_idx = i;
890 let dst_idx = i + byte_shift;
891 let byte = self.0[src_idx];
892 result[dst_idx] = (byte >> bit_shift) | carry;
893 carry = byte << (8 - bit_shift);
894 }
895 }
896 result
897 }
898}
899
900impl ShrAssign<usize> for U {
901 fn shr_assign(&mut self, rhs: usize) {
902 *self = *self >> rhs
903 }
904}
905
906impl Eq for U {}
907
908impl PartialOrd for U {
909 fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
910 Some(self.cmp(other))
911 }
912}
913
914impl Ord for U {
915 fn cmp(&self, other: &Self) -> Ordering {
916 self.0.cmp(&other.0)
917 }
918}
919
920impl Debug for U {
921 fn fmt(&self, f: &mut Formatter<'_>) -> Result<(), FmtError> {
922 let mut b = [0u8; 32 * 2];
923 let Ok(s) = const_hex::encode_to_str(self.0, &mut b) else {
924 return Err(FmtError);
925 };
926 write!(f, "{s}")
927 }
928}
929
930impl Not for U {
931 type Output = Self;
932
933 fn not(mut self) -> Self::Output {
934 for i in 0..32 {
935 self[i] = !self[i]
936 }
937 self
938 }
939}
940
941impl Neg for U {
942 type Output = Self;
943
944 fn neg(self) -> Self {
945 let mut r = U::ZERO;
946 let mut carry = 1u16;
947 for i in (0..32).rev() {
948 let inverted = !self.0[i] as u16;
949 let sum = inverted + carry;
950 r[i] = sum as u8;
951 carry = sum >> 8;
952 }
953 r
954 }
955}
956
957#[derive(Debug, Clone, PartialEq)]
958pub enum UFromStrErr {
959 InvalidChar(char),
960 Overflow,
961 Empty,
962}
963
964impl Display for UFromStrErr {
965 fn fmt(&self, f: &mut Formatter<'_>) -> core::fmt::Result {
966 write!(f, "{self:?}")
967 }
968}
969
970impl core::error::Error for UFromStrErr {}
971
972impl FromStr for U {
973 type Err = UFromStrErr;
974
975 fn from_str(s: &str) -> Result<Self, Self::Err> {
976 if s.is_empty() {
977 return Err(UFromStrErr::Empty);
978 }
979 let mut r = U::ZERO;
980 for c in s.chars() {
981 r *= U::from_u32(10);
982 r += match c {
983 '0'..='9' => U::from(c as u8 - b'0'),
984 _ => return Err(UFromStrErr::InvalidChar(c)),
985 };
986 }
987 Ok(r)
988 }
989}
990
991impl U {
992 pub const ZERO: Self = U([0u8; 32]);
993
994 pub const MAX: Self = U([u8::MAX; 32]);
995
996 pub const ONE: Self = U([
997 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,
998 0, 1,
999 ]);
1000
1001 pub fn is_true(&self) -> bool {
1002 self.0[31] == 1
1003 }
1004
1005 pub const fn is_zero(&self) -> bool {
1006 let mut i = 0;
1007 while i < 32 {
1008 if self.0[i] != 0 {
1009 return false;
1010 }
1011 i += 1;
1012 }
1013 true
1014 }
1015
1016 pub fn abs_diff(&self, y: &U) -> U {
1017 if self > y {
1018 self - y
1019 } else {
1020 y - self
1021 }
1022 }
1023
1024 pub const fn const_addr(self) -> Address {
1025 self.const_20_slice()
1026 }
1027
1028 pub const fn is_max(&self) -> bool {
1029 let mut i = 0;
1030 while i < 32 {
1031 if self.0[i] != u8::MAX {
1032 return false;
1033 }
1034 i += 1;
1035 }
1036 true
1037 }
1038
1039 pub fn is_some(&self) -> bool {
1040 !self.is_zero()
1041 }
1042
1043 pub fn trailing_zeros(&self) -> usize {
1044 let mut count = 0;
1045 for i in (0..32).rev() {
1046 if self[i] == 0 {
1047 count += 8;
1048 } else {
1049 count += self[i].trailing_zeros() as usize;
1050 break;
1051 }
1052 }
1053 count
1054 }
1055
1056 pub fn as_slice(&self) -> &[u8; 32] {
1057 &self.0
1058 }
1059
1060 #[cfg(feature = "alloc")]
1061 pub fn as_vec(self) -> alloc::vec::Vec<u8> {
1062 self.0.to_vec()
1063 }
1064
1065 pub fn checked_add_opt(&self, y: &Self) -> Option<Self> {
1066 checked_add_opt(self, y)
1067 }
1068
1069 pub fn checked_add(&self, y: &Self) -> Self {
1070 checked_add(self, y)
1071 }
1072
1073 pub fn checked_mul_opt(&self, y: &Self) -> Option<Self> {
1074 checked_mul_opt(self, y)
1075 }
1076
1077 pub fn checked_mul(&self, y: &Self) -> Self {
1078 checked_mul(self, y)
1079 }
1080
1081 pub fn checked_sub_opt(&self, y: &Self) -> Option<Self> {
1082 checked_sub_opt(self, y)
1083 }
1084
1085 pub fn checked_sub(&self, y: &Self) -> Self {
1086 checked_sub(self, y)
1087 }
1088
1089 pub fn checked_div_opt(&self, y: &Self) -> Option<Self> {
1090 checked_div_opt(self, y)
1091 }
1092
1093 pub fn checked_div(&self, y: &Self) -> Self {
1094 checked_div(self, y)
1095 }
1096
1097 pub fn checked_pow(&self, exp: &U) -> Option<Self> {
1098 checked_pow(self, exp)
1099 }
1100
1101 pub fn wrapping_add(&self, y: &Self) -> U {
1102 wrapping_add(self, y)
1103 }
1104
1105 pub fn wrapping_sub(&self, y: &Self) -> U {
1106 wrapping_sub(self, y)
1107 }
1108
1109 pub fn wrapping_mul(&self, y: &Self) -> U {
1110 wrapping_mul(self, y)
1111 }
1112
1113 pub fn wrapping_div(&self, y: &Self) -> U {
1114 wrapping_div(self, y)
1115 }
1116
1117 pub fn saturating_add(&self, y: &Self) -> U {
1118 saturating_add(self, y)
1119 }
1120
1121 pub fn saturating_sub(&self, y: &Self) -> U {
1122 saturating_sub(self, y)
1123 }
1124
1125 pub fn saturating_mul(&self, y: &Self) -> U {
1126 saturating_mul(self, y)
1127 }
1128
1129 pub fn saturating_div(&self, y: &Self) -> Self {
1130 saturating_div(self, y)
1131 }
1132
1133 pub fn wrapping_neg(self) -> Self {
1134 let mut x = self;
1135 let mut carry = 1u8;
1136 for b in x.iter_mut().rev() {
1137 *b = (!*b).wrapping_add(carry);
1138 carry = b.is_zero() as u8;
1139 }
1140 x
1141 }
1142
1143 pub fn mul_div(&self, y: &Self, z: Self) -> Option<(Self, bool)> {
1144 mul_div(self, y, z)
1145 }
1146
1147 pub fn mul_div_round_up(&self, y: &Self, z: Self) -> Option<Self> {
1148 mul_div_round_up(self, y, z)
1149 }
1150
1151 pub fn widening_mul_div(&self, y: &Self, z: Self) -> Option<(Self, bool)> {
1152 widening_mul_div(self, y, z)
1153 }
1154
1155 pub fn widening_mul_div_round_up(&self, y: &Self, z: Self) -> Option<Self> {
1156 widening_mul_div_round_up(self, y, z)
1157 }
1158
1159 #[cfg(feature = "ruint-enabled")]
1160 pub fn ruint_mul_div(&self, y: &Self, z: Self) -> Option<(Self, bool)> {
1161 ruint_mul_div(self, y, z)
1162 }
1163
1164 #[cfg(feature = "ruint-enabled")]
1165 pub fn ruint_mul_div_round_up(&self, y: &Self, z: Self) -> Option<Self> {
1166 ruint_mul_div_round_up(self, y, z)
1167 }
1168
1169 pub fn mul_mod(&self, y: &Self, z: &Self) -> Self {
1170 mul_mod(*self, y, z)
1171 }
1172
1173 pub fn add_mod(&self, y: &Self, z: &Self) -> Self {
1174 let mut b = self.0;
1175 unsafe { math_add_mod(b.as_mut_ptr(), y.as_ptr(), z.as_ptr()) }
1176 Self(b)
1177 }
1178
1179 pub fn checked_rooti(self, x: u32) -> Option<Self> {
1180 checked_rooti(self, x)
1181 }
1182
1183 pub fn from_hex(x: &str) -> Option<U> {
1184 match const_hex::decode_to_array::<_, 32>(x) {
1185 Ok(v) => Some(U(v)),
1186 Err(_) => None
1187 }
1188 }
1189
1190 pub const fn const_from_hex(x: &[u8; 64]) -> Option<U> {
1191 match const_hex::const_decode_to_array::<32>(x) {
1192 Ok(v) => Some(U(v)),
1193 Err(_) => None
1194 }
1195 }
1196}
1197
1198impl Display for U {
1199 fn fmt(&self, f: &mut Formatter<'_>) -> core::fmt::Result {
1200 if self.is_zero() {
1201 return write!(f, "0");
1202 }
1203 let mut result = [0u8; 78];
1204 let mut i = 0;
1205 for byte in self.0 {
1206 let mut carry = byte as u32;
1207 for digit in result[..i].iter_mut() {
1208 let temp = (*digit as u32) * 256 + carry;
1209 *digit = (temp % 10) as u8;
1210 carry = temp / 10;
1211 }
1212 while carry > 0 {
1213 result[i] = (carry % 10) as u8;
1214 i += 1;
1215 debug_assert!(78 >= i, "{} > {i}", result.len());
1216 carry /= 10;
1217 }
1218 }
1219 for &digit in result[..i].iter().rev() {
1220 write!(f, "{}", digit)?;
1221 }
1222 Ok(())
1223 }
1224}
1225
1226impl From<U> for [u8; 32] {
1227 fn from(x: U) -> Self {
1228 x.0
1229 }
1230}
1231
1232impl From<&U> for U {
1233 fn from(x: &U) -> Self {
1234 *x
1235 }
1236}
1237
1238impl From<U> for bool {
1239 fn from(x: U) -> Self {
1240 x.0[31] == 1
1241 }
1242}
1243
1244impl From<&[u8]> for U {
1245 fn from(x: &[u8]) -> Self {
1246 let x: &[u8; 32] = x.try_into().unwrap();
1247 (*x).into()
1248 }
1249}
1250
1251impl From<&[u8; 32]> for &U {
1252 fn from(x: &[u8; 32]) -> Self {
1253 unsafe { &*(x as *const [u8; 32] as *const U) }
1254 }
1255}
1256
1257impl From<[u8; 32]> for U {
1258 fn from(x: [u8; 32]) -> Self {
1259 U(x)
1260 }
1261}
1262
1263impl Deref for U {
1264 type Target = [u8; 32];
1265
1266 fn deref(&self) -> &Self::Target {
1267 &self.0
1268 }
1269}
1270
1271impl DerefMut for U {
1272 fn deref_mut(&mut self) -> &mut Self::Target {
1273 &mut self.0
1274 }
1275}
1276
1277impl From<bool> for U {
1278 fn from(x: bool) -> Self {
1279 U::from(&[x as u8])
1280 }
1281}
1282
1283impl Zero for U {
1284 fn zero() -> Self {
1285 U::ZERO
1286 }
1287
1288 fn is_zero(&self) -> bool {
1289 self.0.iter().all(|&b| b == 0)
1290 }
1291}
1292
1293impl Default for U {
1294 fn default() -> Self {
1295 U::ZERO
1296 }
1297}
1298
1299impl One for U {
1300 fn one() -> Self {
1301 U::ONE
1302 }
1303}
1304
1305impl Index<usize> for U {
1306 type Output = u8;
1307
1308 fn index(&self, index: usize) -> &Self::Output {
1309 &self.0[index]
1310 }
1311}
1312
1313impl IndexMut<usize> for U {
1314 fn index_mut(&mut self, index: usize) -> &mut Self::Output {
1315 &mut self.0[index]
1316 }
1317}
1318
1319impl I {
1320 fn is_neg(&self) -> bool {
1321 self.0[0] & 0x80 != 0
1322 }
1323
1324 pub fn is_zero(&self) -> bool {
1325 *self == Self::ZERO
1326 }
1327
1328 pub fn is_some(&self) -> bool {
1329 !self.is_zero()
1330 }
1331
1332 pub fn as_slice(&self) -> &[u8; 32] {
1333 &self.0
1334 }
1335
1336 fn neg(&self) -> Self {
1337 let x = wrapping_add(&U(self.0.map(|b| !b)), &U::ONE);
1338 I(x.0)
1339 }
1340
1341 fn abs(self) -> U {
1342 if self.is_neg() {
1343 U(self.neg().0)
1344 } else {
1345 U(self.0)
1346 }
1347 }
1348}
1349
1350macro_rules! from_slices {
1351 ($($n:expr),+ $(,)?) => {
1352 $(
1353 paste::paste! {
1354 impl From<&[u8; $n]> for U {
1355 fn from(x: &[u8; $n]) -> Self {
1356 let mut b = [0u8; 32];
1357 b[32 - $n..].copy_from_slice(x);
1358 U(b)
1359 }
1360 }
1361
1362 impl From<[u8; $n]> for U {
1363 fn from(x: [u8; $n]) -> Self {
1364 U::from(&x)
1365 }
1366 }
1367
1368 impl U {
1369 pub const fn [<const_ $n _slice>](self) -> [u8; $n] {
1370 let mut b = [0u8; $n];
1371 let mut i = 0;
1372 while i < $n {
1373 b[i] = self.0[32-$n+i];
1374 i += 1;
1375 }
1376 b
1377 }
1378 }
1379
1380 impl From<U> for [u8; $n] {
1381 fn from(x: U) -> Self {
1382 unsafe { *(x.as_ptr().add(32 - $n) as *const [u8; $n]) }
1383 }
1384 }
1385 }
1386 )+
1387 };
1388}
1389
1390from_slices!(
1391 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,
1392 27, 28, 29, 30, 31
1393);
1394
1395impl From<&U> for Address {
1396 fn from(x: &U) -> Self {
1397 (*x).into()
1398 }
1399}
1400
1401macro_rules! from_ints {
1402 ($($t:ty),+ $(,)?) => {
1403 $(
1404 paste::paste! {
1405 impl U {
1406 pub const fn [<from_ $t>](x: $t) -> U {
1407 U(array_concat::concat_arrays!(
1408 [0u8; 32-core::mem::size_of::<$t>()],
1409 x.to_be_bytes())
1410 )
1411 }
1412 }
1413
1414 impl From<$t> for U {
1415 fn from(x: $t) -> Self {
1416 U::[<from_ $t>](x)
1417 }
1418 }
1419
1420 impl From<U> for $t {
1421 fn from(x: U) -> Self {
1422 Self::from_be_bytes(x.into())
1423 }
1424 }
1425 }
1426 )+
1427 };
1428}
1429
1430#[macro_export]
1431macro_rules! u {
1432 ($e:expr) => {
1433 $crate::U::from_u32($e)
1434 };
1435}
1436
1437from_ints! { u8, u16, u32, u64, u128, usize }
1438
1439impl From<I> for [u8; 32] {
1440 fn from(x: I) -> Self {
1441 x.0
1442 }
1443}
1444
1445impl From<[u8; 32]> for I {
1446 fn from(x: [u8; 32]) -> Self {
1447 I(x)
1448 }
1449}
1450
1451fn i_add(x: &I, y: &I) -> I {
1452 I(wrapping_add(&U(x.0), &U(y.0)).0)
1453}
1454
1455fn i_sub(x: &I, y: &I) -> I {
1456 I(wrapping_sub(&U(x.0), &U(y.0)).0)
1457}
1458
1459fn i_mul(x: &I, y: &I) -> I {
1460 let result = wrapping_mul(&U(x.0), &U(y.0));
1461 I(result.0)
1462}
1463
1464fn i_div(x: &I, y: &I) -> I {
1465 let r = wrapping_div(&x.abs(), &y.abs());
1466 if x.is_neg() ^ y.is_neg() {
1467 I(r.0).neg()
1468 } else {
1469 I(r.0)
1470 }
1471}
1472
1473fn i_rem(x: &I, y: &I) -> I {
1474 let r = modd(&x.abs(), &y.abs());
1475 if x.is_neg() {
1476 I(r.0).neg()
1477 } else {
1478 I(r.0)
1479 }
1480}
1481
1482impl Add for I {
1483 type Output = I;
1484 fn add(self, rhs: I) -> I {
1485 i_add(&self, &rhs)
1486 }
1487}
1488
1489impl Add for &I {
1490 type Output = I;
1491 fn add(self, rhs: &I) -> I {
1492 i_add(self, rhs)
1493 }
1494}
1495
1496impl Sub for I {
1497 type Output = I;
1498 fn sub(self, rhs: I) -> I {
1499 i_sub(&self, &rhs)
1500 }
1501}
1502
1503impl Sub for &I {
1504 type Output = I;
1505 fn sub(self, rhs: &I) -> I {
1506 i_sub(self, rhs)
1507 }
1508}
1509
1510impl Mul for I {
1511 type Output = I;
1512 fn mul(self, rhs: I) -> I {
1513 i_mul(&self, &rhs)
1514 }
1515}
1516
1517impl Mul for &I {
1518 type Output = I;
1519 fn mul(self, rhs: &I) -> I {
1520 i_mul(self, rhs)
1521 }
1522}
1523
1524impl Div for I {
1525 type Output = I;
1526 fn div(self, rhs: I) -> I {
1527 i_div(&self, &rhs)
1528 }
1529}
1530
1531impl Div for &I {
1532 type Output = I;
1533 fn div(self, rhs: &I) -> I {
1534 i_div(self, rhs)
1535 }
1536}
1537
1538impl Rem for I {
1539 type Output = I;
1540 fn rem(self, rhs: I) -> I {
1541 i_rem(&self, &rhs)
1542 }
1543}
1544
1545impl Eq for I {}
1546
1547impl PartialOrd for I {
1548 fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
1549 Some(self.cmp(other))
1550 }
1551}
1552
1553impl Ord for I {
1554 fn cmp(&self, other: &Self) -> Ordering {
1555 let self_sign = self.0[0] & 0x80;
1556 let other_sign = other.0[0] & 0x80;
1557 match (self_sign, other_sign) {
1558 (0, 0x80) => Ordering::Greater,
1559 (0x80, 0) => Ordering::Less,
1560 _ => self.0.cmp(&other.0),
1561 }
1562 }
1563}
1564
1565impl Rem for &I {
1566 type Output = I;
1567 fn rem(self, rhs: &I) -> I {
1568 i_rem(self, rhs)
1569 }
1570}
1571
1572impl I {
1573 pub const ZERO: Self = I([0u8; 32]);
1574
1575 pub const ONE: Self = I([
1576 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,
1577 0, 1,
1578 ]);
1579}
1580
1581impl Zero for I {
1582 fn zero() -> Self {
1583 I::ZERO
1584 }
1585 fn is_zero(&self) -> bool {
1586 self.0.iter().all(|&b| b == 0)
1587 }
1588}
1589
1590impl Default for I {
1591 fn default() -> Self {
1592 I::ZERO
1593 }
1594}
1595
1596impl One for I {
1597 fn one() -> Self {
1598 I::ONE
1599 }
1600}
1601
1602#[test]
1603fn test_is_zeroes() {
1604 assert!(U::ZERO.is_zero());
1605 assert!(U::ONE.is_some());
1606 assert!(I::ZERO.is_zero());
1607 assert!(I::ONE.is_some());
1608}
1609
1610#[cfg(all(
1611 test,
1612 feature = "alloy-enabled",
1613 feature = "proptest",
1614 feature = "std",
1615 not(target_arch = "wasm32")
1616))]
1617mod test {
1618 use proptest::prelude::*;
1619
1620 use super::*;
1621
1622 fn strat_any_u256() -> impl Strategy<Value = U256> {
1623 any::<[u8; 32]>().prop_map(U256::from_be_bytes)
1625 }
1626
1627 proptest! {
1628 #[test]
1629 fn wrapping_div_b_zero_denominator_yields_zero(numerator in any::<[u8; 4]>()) {
1630 let zero = [0u8; 4];
1631 prop_assert_eq!(wrapping_div_quo_rem_b::<4>(&numerator, &zero).0, zero);
1632 }
1633
1634 #[test]
1635 fn wrapping_div_b_matches_integer_division(
1636 numerator in any::<[u8; 4]>(),
1637 denominator in any::<[u8; 4]>().prop_filter("denominator must be non-zero", |d| *d != [0u8; 4])
1638 ) {
1639 let numerator_u32 = u32::from_be_bytes(numerator);
1640 let denominator_u32 = u32::from_be_bytes(denominator);
1641 let expected = numerator_u32 / denominator_u32;
1642 prop_assert_eq!(
1643 wrapping_div_quo_rem_b::<4>(&numerator, &denominator).0,
1644 expected.to_be_bytes()
1645 );
1646 }
1647
1648 #[test]
1649 fn wrapping_mod_b_matches_integer_modulo(
1650 numerator in any::<[u8; 4]>(),
1651 denominator in any::<[u8; 4]>().prop_filter("denominator must be non-zero", |d| *d != [0u8; 4])
1652 ) {
1653 let numerator_u32 = u32::from_be_bytes(numerator);
1654 let denominator_u32 = u32::from_be_bytes(denominator);
1655 let expected = numerator_u32 % denominator_u32;
1656 prop_assert_eq!(
1657 wrapping_div_quo_rem_b::<4>(&numerator, &denominator).1,
1658 expected.to_be_bytes()
1659 );
1660 }
1661
1662 #[test]
1663 fn wrapping_add_b_handles_carry(lhs in any::<[u8; 4]>(), rhs in any::<[u8; 4]>()) {
1664 let lhs_u32 = u32::from_be_bytes(lhs);
1665 let rhs_u32 = u32::from_be_bytes(rhs);
1666 let expected = lhs_u32.wrapping_add(rhs_u32);
1667 prop_assert_eq!(wrapping_add_b::<4>(&lhs, &rhs), expected.to_be_bytes());
1668 }
1669
1670 #[test]
1671 fn wrapping_sub_b_handles_borrow(lhs in any::<[u8; 4]>(), rhs in any::<[u8; 4]>()) {
1672 let lhs_u32 = u32::from_be_bytes(lhs);
1673 let rhs_u32 = u32::from_be_bytes(rhs);
1674 let expected = lhs_u32.wrapping_sub(rhs_u32);
1675 prop_assert_eq!(wrapping_sub_b::<4>(&lhs, &rhs), expected.to_be_bytes());
1676 }
1677
1678 #[test]
1679 fn wrapping_mul_b_matches_wrapping_arithmetic(lhs in any::<[u8; 32]>(), rhs in any::<[u8; 32]>()) {
1680 let lhs_u = U::from(lhs);
1681 let rhs_u = U::from(rhs);
1682 let expected = lhs_u.wrapping_mul(&rhs_u);
1683 prop_assert_eq!(wrapping_mul_b::<32>(&lhs, &rhs), expected.0);
1684 }
1685
1686 #[test]
1687 fn const_wrapping_div_agrees_with_wrapping_div_b(
1688 numerator in any::<[u8; 32]>(),
1689 denominator in any::<[u8; 32]>().prop_filter("denominator must be non-zero", |d| *d != [0u8; 32])
1690 ) {
1691 let numerator_u = U::from(numerator);
1692 let denominator_u = U::from(denominator);
1693 prop_assert_eq!(
1694 const_wrapping_div(&numerator_u, &denominator_u).0,
1695 wrapping_div_quo_rem_b::<32>(&numerator, &denominator).0
1696 );
1697 }
1698
1699 #[test]
1700 fn u_predicates_track_zero_and_true(bytes in any::<[u8; 32]>()) {
1701 let value = U::from(bytes);
1702 let is_zero = bytes.iter().all(|&b| b == 0);
1703 prop_assert_eq!(value.is_zero(), is_zero);
1704 prop_assert_eq!(value.is_some(), !is_zero);
1705 prop_assert_eq!(value.is_true(), bytes[31] == 1);
1706 }
1707
1708 #[test]
1709 fn test_u_is_zero(x in any::<[u8; 32]>()) {
1710 let x = U::from(x);
1711 let ex = U256::from_be_bytes(x.0);
1712 assert_eq!(ex.is_zero(), x.is_zero());
1713 }
1714
1715 #[test]
1716 fn test_u_div(x in any::<U>(), y in any::<U>()) {
1717 let ex = U256::from_be_bytes(x.0);
1718 let ey = U256::from_be_bytes(y.0);
1719 assert_eq!((ex.wrapping_div(ey)).to_be_bytes(), x.wrapping_div(&y).0);
1720 }
1721
1722 #[test]
1723 fn test_u_mul(x in any::<U>(), y in any::<U>()) {
1724 let ex = U256::from_be_bytes(x.0);
1725 let ey = U256::from_be_bytes(y.0);
1726 assert_eq!((ex.wrapping_mul(ey)).to_be_bytes(), wrapping_mul(&x, &y).0);
1727 }
1728
1729 #[test]
1730 fn test_u_mod(x in any::<U>(), y in any::<U>()) {
1731 let ex = U256::from_be_bytes(x.0);
1732 let ey = U256::from_be_bytes(y.0);
1733 assert_eq!((ex % ey).to_be_bytes(), (x % y).0);
1734 }
1735
1736 #[test]
1737 fn test_u_add(x in any::<U>(), y in any::<U>()) {
1738 let ex = U256::from_be_bytes(x.0);
1739 let ey = U256::from_be_bytes(y.0);
1740 let e = U::from(ex.wrapping_add(ey).to_be_bytes::<32>());
1741 assert_eq!(e, x.wrapping_add(&y), "{e} != {}", x + y);
1742 }
1743
1744 #[test]
1745 fn test_u_sub(x in any::<U>(), y in any::<U>()) {
1746 let ex = U256::from_be_bytes(x.0);
1747 let ey = U256::from_be_bytes(y.0);
1748 assert_eq!((ex.wrapping_sub(ey)).to_be_bytes(), x.wrapping_sub(&y).0);
1749 }
1750
1751 #[test]
1752 fn test_u_cmp(x in any::<U>(), y in any::<U>()) {
1753 let ex = U256::from_be_bytes(x.0);
1754 let ey = U256::from_be_bytes(y.0);
1755 assert_eq!(ex.cmp(&ey), x.cmp(&y));
1756 }
1757
1758 #[test]
1759 fn test_u_to_str(x in any::<U>()) {
1760 assert_eq!(U256::from_be_bytes(x.0).to_string(), x.to_string());
1761 }
1762
1763 #[test]
1764 fn test_u_shl(x in any::<U>(), i in any::<usize>()) {
1765 let l = U((U256::from_be_bytes(x.0) << i).to_be_bytes::<32>());
1766 assert_eq!(l, x << i);
1767 }
1768
1769 #[test]
1770 fn test_u_shr(x in any::<U>(), i in any::<usize>()) {
1771 let l = U((U256::from_be_bytes(x.0) >> i).to_be_bytes::<32>());
1772 assert_eq!(l, x >> i);
1773 }
1774
1775 #[test]
1776 fn test_trailing_zeros(x in any::<U>()) {
1777 assert_eq!(U256::from_be_bytes(x.0).trailing_zeros(), x.trailing_zeros());
1778 }
1779
1780 #[test]
1781 fn test_i_is_zero(x in any::<U>()) {
1782 let ex = I256::from_be_bytes(x.0);
1783 assert_eq!(ex.is_zero(), x.is_zero());
1784 }
1785
1786 #[test]
1787 fn test_i_div(x in any::<I>(), y in any::<I>()) {
1788 let ex = I256::from_be_bytes(x.0);
1789 let ey = I256::from_be_bytes(y.0);
1790 assert_eq!((ex / ey).to_be_bytes(), (x / y).0);
1791 }
1792
1793 #[test]
1794 fn test_i_mul(x in any::<I>(), y in any::<I>()) {
1795 let ex = I256::from_be_bytes(x.0);
1796 let ey = I256::from_be_bytes(y.0);
1797 assert_eq!((ex.wrapping_mul(ey)).to_be_bytes(), (x * y).0);
1798 }
1799
1800 #[test]
1801 fn test_i_mod(x in any::<I>(), y in any::<I>()) {
1802 let ex = I256::from_be_bytes(x.0);
1803 let ey = I256::from_be_bytes(y.0);
1804 assert_eq!((ex % ey).to_be_bytes(), (x % y).0);
1805 }
1806
1807 #[test]
1808 fn test_i_add(x in any::<I>(), y in any::<I>()) {
1809 let ex = I256::from_be_bytes(x.0);
1810 let ey = I256::from_be_bytes(y.0);
1811 assert_eq!((ex.wrapping_add(ey)).to_be_bytes(), (x + y).0);
1812 }
1813
1814 #[test]
1815 fn test_i_sub(x in any::<I>(), y in any::<I>()) {
1816 let ex = I256::from_be_bytes(x.0);
1817 let ey = I256::from_be_bytes(y.0);
1818 assert_eq!((ex.wrapping_sub(ey)).to_be_bytes(), (x - y).0);
1819 }
1820
1821 #[test]
1822 fn test_i_cmp(x in any::<I>(), y in any::<I>()) {
1823 let ex = I256::from_be_bytes(x.0);
1824 let ey = I256::from_be_bytes(y.0);
1825 assert_eq!(ex.cmp(&ey), x.cmp(&y));
1826 }
1827
1828 #[test]
1829 fn test_u_u8(x in any::<u8>()) {
1830 let mut b = [0u8; 32];
1831 b[32-size_of::<u8>()..].copy_from_slice(&x.to_be_bytes());
1832 assert_eq!(&U256::from_be_bytes(b).to_be_bytes(), U::from(x).as_slice());
1833 }
1834
1835 #[test]
1836 fn test_u_u16(x in any::<u16>()) {
1837 let mut b = [0u8; 32];
1838 b[32-size_of::<u16>()..].copy_from_slice(&x.to_be_bytes());
1839 assert_eq!(&U256::from_be_bytes(b).to_be_bytes(), U::from(x).as_slice());
1840 }
1841
1842 #[test]
1843 fn test_u_u32(x in any::<u32>()) {
1844 let mut b = [0u8; 32];
1845 b[32-size_of::<u32>()..].copy_from_slice(&x.to_be_bytes());
1846 assert_eq!(&U256::from_be_bytes(b).to_be_bytes(), U::from(x).as_slice());
1847 }
1848
1849 #[test]
1850 fn test_u_u64(x in any::<u64>()) {
1851 let mut b = [0u8; 32];
1852 b[32-size_of::<u64>()..].copy_from_slice(&x.to_be_bytes());
1853 assert_eq!(&U256::from_be_bytes(b).to_be_bytes(), U::from(x).as_slice());
1854 }
1855
1856 #[test]
1857 fn test_u_u128(x in any::<u128>()) {
1858 let mut b = [0u8; 32];
1859 b[32-size_of::<u128>()..].copy_from_slice(&x.to_be_bytes());
1860 assert_eq!(&U256::from_be_bytes(b).to_be_bytes(), U::from(x).as_slice());
1861 }
1862
1863 #[test]
1864 fn test_to_and_from_addrs(x in any::<Address>()) {
1865 let y: Address = U::from(x).into();
1866 assert_eq!(x, y)
1867 }
1868
1869 #[test]
1870 fn test_u_conv_to_and_from_u8(x in any::<u8>()) {
1871 assert_eq!(x.wrapping_add(1), U::from(x).wrapping_add(&U::ONE).into());
1872 }
1873
1874 #[test]
1875 fn test_print_to_and_from(x in any::<[u8; 32]>()) {
1876 let e = format!("{}", U256::from_be_bytes(x));
1877 let v = format!("{}", U(x));
1878 assert_eq!(e, v);
1879 }
1880
1881 #[test]
1882 fn test_u_from_str(x in strat_any_u256()) {
1883 let v = U::from_str(x.to_string().as_str()).unwrap();
1884 assert_eq!(
1885 U::from(x.to_be_bytes::<32>()),
1886 v,
1887 "{x} != {v}",
1888 )
1889 }
1890
1891 #[test]
1892 fn array_truncate(x in any::<[u8; 20]>()) {
1893 assert_eq!(x, U::from(x).const_addr());
1894 }
1895 }
1896}