thruput_u256/math.rs
1//! Integer math utilities: OpenZeppelin's `Math.sol`, in Rust.
2//!
3//! Contract authors porting from Solidity reach for `Math.mulDiv`,
4//! `Math.sqrt`, `Math.log10` and the rounding modes by name, so the names
5//! here are the same modulo Rust casing, and each function is documented
6//! against the Solidity one it mirrors.
7//!
8//! Three groups of `Math.sol`'s members have no function here, because Rust
9//! already spells them:
10//!
11//! * `tryAdd`/`trySub`/`tryMul`/`tryDiv`/`tryMod` are
12//! [`checked_add`](U256::checked_add) and friends. Solidity returns
13//! `(bool, uint256)` because it has no `Option`.
14//! * `ternary` is a branchless-select trick for the EVM's gas model. In Rust
15//! it is `if`.
16//! * `clz` is [`leading_zeros`](U256::leading_zeros), which already answers
17//! 256 for zero exactly as `Math.clz` does.
18//!
19//! One name differs: `Math.sqrt` is [`integer_sqrt`](U256::integer_sqrt), the
20//! spelling this crate shipped with, plus
21//! [`sqrt_rounding`](U256::sqrt_rounding) for the variant that takes a
22//! direction.
23//!
24//! # 512-bit values
25//!
26//! There is no `U512` here, and none is needed for parity: Solidity has no type
27//! wider than `uint256` either, so `Math.sol` returns its two 512-bit results
28//! as a `(high, low)` pair of `uint256`s. Both have a counterpart --
29//! `Math.mul512` is [`widening_mul`](U256::widening_mul) and
30//! `Math.add512` is [`overflowing_add`](U256::overflowing_add), each ordered
31//! `(low, high)` to match `u128::widening_mul` rather than Solidity.
32//!
33//! The only consumers of a 512-bit intermediate in `Math.sol` are `mulDiv` and
34//! `mulShr`, and both are here whole, so the pair never has to be arithmetic
35//! the caller does themselves.
36//!
37//! # Code size
38//!
39//! [`mul_div`](U256::mul_div) and the other full-precision entry points link
40//! their own instantiation of Knuth D, sized to a 512-bit dividend, plus the
41//! 512-bit multiply that the narrower [`U256::widening_mul_u128`] does not need.
42//! Measured by `scripts/bigint-bench.sh -o mul_div`, rv32: **3,992 bytes** of
43//! `.text` and 4712 gas per call, against 2,572 and 972 for a plain `/`. The
44//! same operation over Parity's `uint` -- which has no full-precision `mulDiv`,
45//! so the baseline widens to a `construct_uint!(PU512(8))` by hand, as a
46//! contract author there would -- costs 21,568 bytes and 22,625 gas: a third of
47//! the 64 KiB artifact code cap, for one operation.
48//!
49//! A contract that uses both `/` and this family links Knuth D twice; `div`'s
50//! `knuth_d` documents why that beats sharing one copy, with the numbers.
51//! [`mod_exp`](U256::mod_exp) and [`inv_mod`](U256::inv_mod) are loops over
52//! the multiply-divide pair -- reach for them knowingly.
53
54use crate::div::{WIDE_LIMBS, div_rem_512, low_limbs};
55use crate::{LIMBS, U256};
56
57/// The rounding direction of an inexact result.
58///
59/// `Math.Rounding` in Solidity, with the same four cases and the same
60/// discriminant order.
61#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Default)]
62pub enum Rounding {
63 /// Toward negative infinity. For an unsigned value, the same as
64 /// [`Trunc`](Self::Trunc).
65 #[default]
66 Floor,
67 /// Toward positive infinity. For an unsigned value, the same as
68 /// [`Expand`](Self::Expand).
69 Ceil,
70 /// Toward zero.
71 Trunc,
72 /// Away from zero.
73 Expand,
74}
75
76impl Rounding {
77 /// Whether this direction rounds an inexact *unsigned* result up.
78 ///
79 /// `Math.unsignedRoundsUp`. Both signed directions collapse for a value
80 /// that cannot be negative: rounding toward positive infinity and rounding
81 /// away from zero are the same instruction.
82 #[inline]
83 pub const fn unsigned_rounds_up(self) -> bool {
84 matches!(self, Self::Ceil | Self::Expand)
85 }
86
87 /// Whether this direction rounds an inexact result of the given sign
88 /// *away from zero*.
89 ///
90 /// The signed counterpart of [`unsigned_rounds_up`](Self::unsigned_rounds_up):
91 /// [`Floor`](Self::Floor) grows a negative magnitude, [`Ceil`](Self::Ceil)
92 /// a positive one.
93 #[inline]
94 pub const fn rounds_away_from_zero(self, negative: bool) -> bool {
95 match self {
96 Self::Floor => negative,
97 Self::Ceil => !negative,
98 Self::Trunc => false,
99 Self::Expand => true,
100 }
101 }
102}
103
104impl U256 {
105 // -----------------------------------------------------------------------
106 // Comparison and averaging
107 // -----------------------------------------------------------------------
108
109 /// The smaller of two values. `Math.min`.
110 ///
111 /// Shadows [`Ord::min`] in method position, which resolves to the same
112 /// answer; this one is a `const fn`.
113 #[inline]
114 pub const fn min(self, other: Self) -> Self {
115 if self.const_lt(other) { self } else { other }
116 }
117
118 /// The larger of two values. `Math.max`.
119 ///
120 /// Shadows [`Ord::max`] in method position, which resolves to the same
121 /// answer; this one is a `const fn`.
122 #[inline]
123 pub const fn max(self, other: Self) -> Self {
124 if self.const_gt(other) { self } else { other }
125 }
126
127 /// Clamps to the inclusive range `min..=max`.
128 ///
129 /// # Panics
130 ///
131 /// If `min > max`, matching [`Ord::clamp`].
132 #[inline]
133 pub const fn clamp(self, min: Self, max: Self) -> Self {
134 if min.const_gt(max) {
135 panic!("min must be less than or equal to max");
136 }
137 self.max(min).min(max)
138 }
139
140 /// The average of two values, rounded toward zero, without an
141 /// intermediate that overflows. `Math.average`.
142 ///
143 /// `(a + b) / 2` would wrap; `(a & b) + (a ^ b) / 2` is the same value and
144 /// never leaves the range.
145 #[inline]
146 pub const fn average(self, other: Self) -> Self {
147 self.const_bitand(other)
148 .wrapping_add(self.const_bitxor(other).wrapping_shr(1))
149 }
150
151 // -----------------------------------------------------------------------
152 // Division
153 // -----------------------------------------------------------------------
154
155 /// Division rounding toward positive infinity, returning `None` if `rhs`
156 /// is zero. `Math.ceilDiv`.
157 #[inline]
158 pub const fn checked_ceil_div(self, rhs: Self) -> Option<Self> {
159 if self.is_zero() {
160 // Guard the `self - 1` below, and skip the division entirely.
161 // Also the one input for which the divisor being zero is *not*
162 // reported -- so check that first.
163 if rhs.is_zero() {
164 return None;
165 }
166 return Some(Self::ZERO);
167 }
168 // `self >= 1`, so `self - 1` cannot wrap, and the largest possible
169 // result is `(MAX - 1) / 1 + 1 == MAX`: the `+ 1` cannot overflow
170 // either.
171 match self.wrapping_sub(Self::ONE).checked_div(rhs) {
172 Some(q) => Some(q.wrapping_add(Self::ONE)),
173 None => None,
174 }
175 }
176
177 /// Division rounding toward positive infinity. `Math.ceilDiv`.
178 ///
179 /// # Panics
180 ///
181 /// If `rhs` is zero, matching `/`.
182 #[inline]
183 pub const fn ceil_div(self, rhs: Self) -> Self {
184 match self.checked_ceil_div(rhs) {
185 Some(v) => v,
186 None => panic!("attempt to divide by zero"),
187 }
188 }
189
190 /// Division following `rounding`, returning `None` if `rhs` is zero.
191 #[inline]
192 pub const fn checked_div_rounding(
193 self,
194 rhs: Self,
195 rounding: Rounding,
196 ) -> Option<Self> {
197 match self.checked_div_rem(rhs) {
198 Some((q, r)) => {
199 if rounding.unsigned_rounds_up() && !r.is_zero() {
200 Some(q.wrapping_add(Self::ONE))
201 } else {
202 Some(q)
203 }
204 }
205 None => None,
206 }
207 }
208
209 /// Division following `rounding`.
210 ///
211 /// # Panics
212 ///
213 /// If `rhs` is zero, matching `/`.
214 #[inline]
215 pub const fn div_rounding(self, rhs: Self, rounding: Rounding) -> Self {
216 match self.checked_div_rounding(rhs, rounding) {
217 Some(v) => v,
218 None => panic!("attempt to divide by zero"),
219 }
220 }
221
222 // -----------------------------------------------------------------------
223 // Full-precision multiply-divide
224 // -----------------------------------------------------------------------
225
226 /// `floor(x * y / d)` computed on the exact 512-bit product, returning
227 /// `None` if `d` is zero or the quotient exceeds [`U256::MAX`].
228 ///
229 /// `Math.mulDiv`. The intermediate never has to fit in 256 bits, which is
230 /// the whole point: `x * y` may be far past [`U256::MAX`] as long as the
231 /// quotient is not.
232 #[inline]
233 pub const fn checked_mul_div(x: Self, y: Self, d: Self) -> Option<Self> {
234 match Self::mul_div_parts(x, y, d) {
235 Some((q, _)) => Some(q),
236 None => None,
237 }
238 }
239
240 /// `floor(x * y / d)` computed on the exact 512-bit product. `Math.mulDiv`.
241 ///
242 /// # Panics
243 ///
244 /// If `d` is zero, or if the quotient does not fit in a `U256`. Both
245 /// panics are unconditional rather than `overflow-checks`-gated, for the
246 /// reason [`mul_div_u128`](crate::mul_div_u128) gives: this is an explicit
247 /// exact-arithmetic call, not an operator with primitive behaviour to
248 /// match.
249 #[inline]
250 pub const fn mul_div(x: Self, y: Self, d: Self) -> Self {
251 match Self::checked_mul_div(x, y, d) {
252 Some(v) => v,
253 None => {
254 if d.is_zero() {
255 panic!("attempt to divide by zero");
256 }
257 panic!("mul_div quotient exceeds U256");
258 }
259 }
260 }
261
262 /// `x * y / d` computed on the exact 512-bit product, following
263 /// `rounding`. Returns `None` if `d` is zero or the result exceeds
264 /// [`U256::MAX`]. `Math.mulDiv` with a rounding argument.
265 #[inline]
266 pub const fn checked_mul_div_rounding(
267 x: Self,
268 y: Self,
269 d: Self,
270 rounding: Rounding,
271 ) -> Option<Self> {
272 match Self::mul_div_parts(x, y, d) {
273 Some((q, r)) => {
274 if rounding.unsigned_rounds_up() && !r.is_zero() {
275 // Rounding up can leave the 256-bit range that the floor
276 // quotient just fit into.
277 q.checked_add(Self::ONE)
278 } else {
279 Some(q)
280 }
281 }
282 None => None,
283 }
284 }
285
286 /// `x * y / d` computed on the exact 512-bit product, following
287 /// `rounding`.
288 ///
289 /// # Panics
290 ///
291 /// As [`mul_div`](Self::mul_div).
292 #[inline]
293 pub const fn mul_div_rounding(
294 x: Self,
295 y: Self,
296 d: Self,
297 rounding: Rounding,
298 ) -> Self {
299 match Self::checked_mul_div_rounding(x, y, d, rounding) {
300 Some(v) => v,
301 None => {
302 if d.is_zero() {
303 panic!("attempt to divide by zero");
304 }
305 panic!("mul_div quotient exceeds U256");
306 }
307 }
308 }
309
310 /// The floor quotient and remainder of `x * y / d`, or `None` when `d` is
311 /// zero or the quotient needs more than 256 bits.
312 ///
313 /// The one place the 512-bit product meets the divider; every public
314 /// `mul_div`/`mul_mod` entry point is a thin wrapper on this.
315 #[inline]
316 pub(crate) const fn mul_div_parts(
317 x: Self,
318 y: Self,
319 d: Self,
320 ) -> Option<(Self, Self)> {
321 let (lo, hi) = x.widening_mul(y);
322 let (q, r) = match div_rem_512(hi, lo, d) {
323 Some(v) => v,
324 None => return None,
325 };
326 // The quotient of a 512-bit dividend genuinely needs 512 bits when
327 // `d <= hi`; that is the overflow case, not a representable answer.
328 let mut i = LIMBS;
329 while i < WIDE_LIMBS {
330 if q[i] != 0 {
331 return None;
332 }
333 i += 1;
334 }
335 Some((Self::from_limbs(low_limbs(&q)), r))
336 }
337
338 /// `floor(x * y >> n)` computed on the exact 512-bit product, returning
339 /// `None` if the result exceeds [`U256::MAX`] or `n` is at least 256.
340 ///
341 /// `Math.mulShr`, whose `n` is a `uint8` and so cannot reach 256 at all.
342 #[inline]
343 pub const fn checked_mul_shr(x: Self, y: Self, n: u32) -> Option<Self> {
344 match Self::mul_shr_parts(x, y, n) {
345 Some((v, _)) => Some(v),
346 None => None,
347 }
348 }
349
350 /// The shifted product and whether any set bit was shifted out, or `None`
351 /// when the result does not fit.
352 ///
353 /// One place the 512-bit product is formed, so the rounding entry point
354 /// does not have to build it a second time -- `widening_mul` is
355 /// `inline(never)` on rv32 and sixty-four `mul`/`mulhu` pairs, which is
356 /// not a thing to pay twice for a single `Ceil`.
357 #[inline]
358 const fn mul_shr_parts(x: Self, y: Self, n: u32) -> Option<(Self, bool)> {
359 if n >= Self::BITS {
360 return None;
361 }
362 let (lo, hi) = x.widening_mul(y);
363 // `hi >= 1 << n` is exactly `hi` needing more than `n` bits, spelled
364 // without a shift that would have to special-case `n == 0`.
365 if hi.bit_len() > n {
366 return None;
367 }
368 if n == 0 {
369 // Nothing is shifted out, so nothing is lost.
370 return Some((lo, false));
371 }
372 // Only the low half can carry a dropped bit, since `n < 256`.
373 let dropped = !lo
374 .const_bitand(Self::MAX.wrapping_shr(Self::BITS - n))
375 .is_zero();
376 Some((
377 hi.wrapping_shl(Self::BITS - n)
378 .const_bitor(lo.wrapping_shr(n)),
379 dropped,
380 ))
381 }
382
383 /// `floor(x * y >> n)` computed on the exact 512-bit product.
384 /// `Math.mulShr`.
385 ///
386 /// # Panics
387 ///
388 /// If `n` is at least 256, or if the result does not fit in a `U256`.
389 #[inline]
390 pub const fn mul_shr(x: Self, y: Self, n: u32) -> Self {
391 match Self::checked_mul_shr(x, y, n) {
392 Some(v) => v,
393 None => {
394 if n >= Self::BITS {
395 panic!("attempt to shift right with overflow");
396 }
397 panic!("mul_shr result exceeds U256");
398 }
399 }
400 }
401
402 /// `x * y >> n` computed on the exact 512-bit product, following
403 /// `rounding`. `Math.mulShr` with a rounding argument.
404 #[inline]
405 pub const fn checked_mul_shr_rounding(
406 x: Self,
407 y: Self,
408 n: u32,
409 rounding: Rounding,
410 ) -> Option<Self> {
411 let (v, dropped) = match Self::mul_shr_parts(x, y, n) {
412 Some(pair) => pair,
413 None => return None,
414 };
415 if dropped && rounding.unsigned_rounds_up() {
416 // Rounding up can leave the range the truncated value just fit.
417 v.checked_add(Self::ONE)
418 } else {
419 Some(v)
420 }
421 }
422
423 /// `x * y >> n` computed on the exact 512-bit product, following
424 /// `rounding`.
425 ///
426 /// # Panics
427 ///
428 /// As [`mul_shr`](Self::mul_shr).
429 #[inline]
430 pub const fn mul_shr_rounding(
431 x: Self,
432 y: Self,
433 n: u32,
434 rounding: Rounding,
435 ) -> Self {
436 match Self::checked_mul_shr_rounding(x, y, n, rounding) {
437 Some(v) => v,
438 None => {
439 if n >= Self::BITS {
440 panic!("attempt to shift right with overflow");
441 }
442 panic!("mul_shr result exceeds U256");
443 }
444 }
445 }
446
447 // -----------------------------------------------------------------------
448 // Modular arithmetic
449 // -----------------------------------------------------------------------
450
451 /// `(x + y) % m`, computed on the exact 257-bit sum. Returns `None` if `m`
452 /// is zero.
453 ///
454 /// The EVM's `addmod`, which `Math.sol` uses but does not re-export.
455 #[inline]
456 pub const fn checked_add_mod(x: Self, y: Self, m: Self) -> Option<Self> {
457 let (x, y) = match (x.checked_rem(m), y.checked_rem(m)) {
458 (Some(x), Some(y)) => (x, y),
459 _ => return None,
460 };
461 // Both are below `m`, so the true sum is below `2m` and one
462 // conditional subtraction lands in range.
463 let (sum, carry) = x.overflowing_add(y);
464 if carry || sum.const_ge(m) {
465 // On carry the true sum is `sum + 2^256`, and `true - m` is below
466 // `2^256`, so the wrapping subtraction is exact.
467 Some(sum.wrapping_sub(m))
468 } else {
469 Some(sum)
470 }
471 }
472
473 /// `(x + y) % m`, computed on the exact 257-bit sum.
474 ///
475 /// # Panics
476 ///
477 /// If `m` is zero.
478 #[inline]
479 pub const fn add_mod(x: Self, y: Self, m: Self) -> Self {
480 match Self::checked_add_mod(x, y, m) {
481 Some(v) => v,
482 None => panic!("attempt to divide by zero"),
483 }
484 }
485
486 /// `(x * y) % m`, computed on the exact 512-bit product. Returns `None` if
487 /// `m` is zero.
488 ///
489 /// The EVM's `mulmod`, which `Math.sol` uses but does not re-export.
490 #[inline]
491 pub const fn checked_mul_mod(x: Self, y: Self, m: Self) -> Option<Self> {
492 let (lo, hi) = x.widening_mul(y);
493 match div_rem_512(hi, lo, m) {
494 Some((_, r)) => Some(r),
495 None => None,
496 }
497 }
498
499 /// `(x * y) % m`, computed on the exact 512-bit product.
500 ///
501 /// # Panics
502 ///
503 /// If `m` is zero.
504 #[inline]
505 pub const fn mul_mod(x: Self, y: Self, m: Self) -> Self {
506 match Self::checked_mul_mod(x, y, m) {
507 Some(v) => v,
508 None => panic!("attempt to divide by zero"),
509 }
510 }
511
512 /// `b.pow(e) % m`, returning `None` if `m` is zero. `Math.tryModExp`.
513 ///
514 /// The zero-modulus refusal follows OpenZeppelin rather than the
515 /// precompile it calls: EIP-198 treats a zero modulus as defined and
516 /// answers zero, and `tryModExp` guards it in Solidity *before* the
517 /// `staticcall`. A port is written against the library, so this matches
518 /// the library.
519 ///
520 /// Square-and-multiply over [`checked_mul_mod`](Self::checked_mul_mod):
521 /// one full-precision multiply-divide per bit of `e`, plus one more per
522 /// set bit -- up to 512 for a full-width exponent. See
523 /// [`mod_exp`](Self::mod_exp) for what that costs and why an
524 /// attacker-chosen exponent is a gas-exhaustion surface.
525 pub const fn checked_mod_exp(b: Self, e: Self, m: Self) -> Option<Self> {
526 if m.is_zero() {
527 return None;
528 }
529 if m.const_eq(Self::ONE) {
530 // Everything is congruent to zero, including `0^0`.
531 return Some(Self::ZERO);
532 }
533
534 let mut result = Self::ONE;
535 let mut base = match b.checked_rem(m) {
536 Some(v) => v,
537 None => return None,
538 };
539
540 let bits = e.bit_len();
541 let mut i = 0;
542 while i < bits {
543 if e.bit(i) {
544 result = match Self::checked_mul_mod(result, base, m) {
545 Some(v) => v,
546 None => return None,
547 };
548 }
549 i += 1;
550 // Skip the final squaring: nothing reads it.
551 if i < bits {
552 base = match Self::checked_mul_mod(base, base, m) {
553 Some(v) => v,
554 None => return None,
555 };
556 }
557 }
558 Some(result)
559 }
560
561 /// `b.pow(e) % m`. `Math.modExp`.
562 ///
563 /// # Cost
564 ///
565 /// **This is the most expensive function in the crate, by a wide margin,
566 /// and the one place where being a library rather than a precompile
567 /// really costs.**
568 ///
569 /// `Math.modExp` in Solidity is not an implementation: it is a
570 /// `staticcall` to the EIP-198 precompile at address `0x05`, so the
571 /// bignum runs as native client code at a flat fee. Thruput's syscall
572 /// table -- the actual analogue of the EVM's precompile slots -- carries
573 /// `kSHA256` and `kVerifySignature` (EVM `0x02` and `0x01`) but nothing
574 /// for modular exponentiation, so this runs *inside* the contract.
575 ///
576 /// That means the loop is real work: once per bit of `e`, with one
577 /// full-precision multiply-divide per bit and another per set bit, up to
578 /// 512 of them for a full-width exponent. At the 4,712 gas the bench
579 /// measures for one `mul_div`, a 256-bit exponent is on the order of two
580 /// million. An entrypoint that lets a caller choose `e` or `m` is
581 /// therefore a gas-exhaustion surface: bound the exponent, or charge for
582 /// it.
583 ///
584 /// If modular exponentiation ever becomes load-bearing here -- RSA
585 /// verification, anything with a pairing behind it -- the answer is a host
586 /// syscall alongside `kSHA256`, not a better loop. That is a protocol
587 /// change rather than an SDK one, and it is tracked as
588 /// <https://github.com/thruputchain/thruput-sdk-rs/issues/383>.
589 ///
590 /// Two things this does have over the Solidity version. It is a
591 /// `const fn`, where `Math.modExp` must be `view` because a `staticcall`
592 /// is not `pure`. And it cannot silently answer zero: OpenZeppelin's own
593 /// documentation warns that on a chain without the precompile the
594 /// `staticcall` succeeds and the result "may be incorrectly interpreted as
595 /// 0", which is not a failure mode an in-contract loop has.
596 ///
597 /// # Panics
598 ///
599 /// If `m` is zero.
600 pub const fn mod_exp(b: Self, e: Self, m: Self) -> Self {
601 match Self::checked_mod_exp(b, e, m) {
602 Some(v) => v,
603 None => panic!("attempt to divide by zero"),
604 }
605 }
606
607 /// The modular multiplicative inverse of `a` in `Z/nZ`, or zero when `a`
608 /// has no inverse (including when `n` is zero or one). `Math.invMod`.
609 ///
610 /// Iterative extended Euclid. The Bézout coefficient is carried as a
611 /// magnitude with an implied alternating sign, rather than as a signed
612 /// value: consecutive coefficients always have opposite signs, so the
613 /// recurrence on magnitudes is `t[k+1] = t[k-1] + q * t[k]`, and the
614 /// standard bound `t <= n / gcd` keeps every intermediate inside a
615 /// `U256`.
616 pub const fn inv_mod(a: Self, n: Self) -> Self {
617 if n.is_zero() {
618 return Self::ZERO;
619 }
620
621 // (r0, r1) = (r[k-1], r[k]) and (t0, t1) = (|t[k-1]|, |t[k]|), k = 1.
622 let mut r0 = n;
623 let mut r1 = match a.checked_rem(n) {
624 Some(v) => v,
625 None => return Self::ZERO,
626 };
627 let mut t0 = Self::ZERO;
628 let mut t1 = Self::ONE;
629 // `t[k]` is positive for odd `k`, negative for even `k`.
630 let mut k_odd = true;
631
632 while !r1.is_zero() {
633 let (q, r) = match r0.checked_div_rem(r1) {
634 Some(v) => v,
635 None => return Self::ZERO,
636 };
637 r0 = r1;
638 r1 = r;
639 // Bounded above by `n`, per the identity `|t[final + 1]| = n / gcd`
640 // -- so the wrapping forms never actually wrap.
641 let t2 = t0.wrapping_add(q.wrapping_mul(t1));
642 t0 = t1;
643 t1 = t2;
644 k_odd = !k_odd;
645 }
646
647 // `r0` is now the gcd and `t0` the coefficient of `a`, at index k - 1.
648 if !r0.const_eq(Self::ONE) {
649 return Self::ZERO;
650 }
651 // Index `k - 1` is odd -- so the coefficient is positive -- exactly
652 // when `k` is even, which is when `k_odd` is now false.
653 if !k_odd || t0.is_zero() {
654 // `t0` is zero only for `n == 1`, where the inverse is zero too.
655 t0
656 } else {
657 n.wrapping_sub(t0)
658 }
659 }
660
661 /// The modular multiplicative inverse of `a` in `Z/pZ` for a prime `p`
662 /// greater than two. `Math.invModPrime`.
663 ///
664 /// Fermat's little theorem: `a^(p-2) = a^-1 (mod p)`. **`p` is not checked
665 /// for primality**; a composite modulus produces a wrong answer rather
666 /// than an error, exactly as in Solidity. Use
667 /// [`inv_mod`](Self::inv_mod) when the modulus is not known to be prime.
668 ///
669 /// # Cost
670 ///
671 /// This is [`mod_exp`](Self::mod_exp) with a full-width exponent, so it is
672 /// as expensive as that function's worst case. It reads like a cheap
673 /// helper and is not one.
674 ///
675 /// # Panics
676 ///
677 /// If `p` is zero. Note that this differs from [`inv_mod`](Self::inv_mod),
678 /// which is total and answers zero for a degenerate modulus: swapping one
679 /// for the other after establishing primality elsewhere turns that zero
680 /// into an abort.
681 pub const fn inv_mod_prime(a: Self, p: Self) -> Self {
682 Self::mod_exp(a, p.wrapping_sub(Self::from_u32(2)), p)
683 }
684
685 // -----------------------------------------------------------------------
686 // Exponentiation
687 // -----------------------------------------------------------------------
688
689 /// Exponentiation, with a flag reporting whether it wrapped.
690 ///
691 /// `0.pow(0)` is one, matching the primitives.
692 pub const fn overflowing_pow(self, exp: u32) -> (Self, bool) {
693 let mut base = self;
694 let mut exp = exp;
695 let mut acc = Self::ONE;
696 let mut overflow = false;
697
698 while exp > 0 {
699 if exp & 1 == 1 {
700 let (v, o) = acc.overflowing_mul(base);
701 acc = v;
702 overflow |= o;
703 }
704 exp >>= 1;
705 // Skip the final squaring: nothing reads it, and squaring an
706 // already-large base would report an overflow the result does not
707 // have.
708 if exp > 0 {
709 let (v, o) = base.overflowing_mul(base);
710 base = v;
711 overflow |= o;
712 }
713 }
714
715 (acc, overflow)
716 }
717
718 /// Exponentiation, returning `None` on overflow.
719 #[inline]
720 pub const fn checked_pow(self, exp: u32) -> Option<Self> {
721 match self.overflowing_pow(exp) {
722 (v, false) => Some(v),
723 (_, true) => None,
724 }
725 }
726
727 /// Exponentiation, wrapping on overflow.
728 #[inline]
729 pub const fn wrapping_pow(self, exp: u32) -> Self {
730 self.overflowing_pow(exp).0
731 }
732
733 /// Exponentiation, saturating at [`U256::MAX`].
734 #[inline]
735 pub const fn saturating_pow(self, exp: u32) -> Self {
736 match self.overflowing_pow(exp) {
737 (v, false) => v,
738 (_, true) => Self::MAX,
739 }
740 }
741
742 /// Exponentiation.
743 ///
744 /// # Panics
745 ///
746 /// On overflow, if `overflow-checks` is on -- otherwise it wraps, like the
747 /// operators and like the primitives' `pow`.
748 #[inline]
749 pub const fn pow(self, exp: u32) -> Self {
750 let (v, overflow) = self.overflowing_pow(exp);
751 if crate::arith::OVERFLOW_CHECKS && overflow {
752 panic!("attempt to multiply with overflow");
753 }
754 v
755 }
756
757 // -----------------------------------------------------------------------
758 // Roots and logarithms
759 // -----------------------------------------------------------------------
760
761 /// The integer square root, following `rounding`. `Math.sqrt` with a
762 /// rounding argument.
763 #[inline]
764 pub const fn sqrt_rounding(self, rounding: Rounding) -> Self {
765 let r = self.integer_sqrt();
766 // `r <= 2^128 - 1`, so `r * r` cannot overflow and `r + 1` cannot
767 // either.
768 if rounding.unsigned_rounds_up() && !r.wrapping_mul(r).const_eq(self) {
769 r.wrapping_add(Self::ONE)
770 } else {
771 r
772 }
773 }
774
775 /// `floor(log2(self))`, or zero for zero. `Math.log2`.
776 #[inline]
777 pub const fn log2(self) -> u32 {
778 self.bit_len().saturating_sub(1)
779 }
780
781 /// `log2(self)` following `rounding`, or zero for zero. `Math.log2` with a
782 /// rounding argument.
783 #[inline]
784 pub const fn log2_rounding(self, rounding: Rounding) -> u32 {
785 let r = self.log2();
786 if rounding.unsigned_rounds_up()
787 && Self::ONE.wrapping_shl(r).const_lt(self)
788 {
789 r + 1
790 } else {
791 r
792 }
793 }
794
795 /// `floor(log10(self))`, or zero for zero. `Math.log10`.
796 ///
797 /// Peels eight digits at a time with [`div_rem_small`](Self::div_rem_small)
798 /// -- `10^8` is the largest power of ten that is both a `u32` and a whole
799 /// number of digits -- so this never links Knuth D, unlike the ladder of
800 /// 256-bit constants Solidity uses.
801 pub const fn log10(self) -> u32 {
802 self.log10_parts().0
803 }
804
805 /// `floor(log10(self))`, and whether `10^that` is strictly below `self`.
806 ///
807 /// The second value is what [`log10_rounding`](Self::log10_rounding)
808 /// needs, and it falls out of this loop for free: the result is a power of
809 /// ten exactly when every peeled chunk divided exactly and what is left is
810 /// itself one. Recomputing `10^r` afterwards to compare would instead link
811 /// [`pow`](Self::pow) -- and through it the general 256x256 multiply --
812 /// into a function built specifically to avoid dragging in that class of
813 /// code.
814 const fn log10_parts(self) -> (u32, bool) {
815 /// The largest power of ten fitting in a `u32`'s divisor slot.
816 const P8: u32 = 100_000_000;
817
818 // `log10(0)` is defined as 0 here, and `10^0 == 1` is above zero
819 // rather than below it, so zero never rounds up. Every path below
820 // assumes `self >= 1`.
821 if self.is_zero() {
822 return (0, false);
823 }
824
825 let mut v = self;
826 let mut r = 0u32;
827 let mut exact = true;
828 // `limb_len() > 1` means `v >= 2^32 > 10^8`, so the second test only
829 // ever runs on a single-limb value.
830 while v.limb_len() > 1 || v.to_limbs()[0] >= P8 {
831 let (q, rem) = v.div_rem_small(P8);
832 if rem != 0 {
833 exact = false;
834 }
835 v = q;
836 r += 8;
837 }
838 let (tail, tail_exact) = log10_u32(v.to_limbs()[0]);
839 (r + tail, !(exact && tail_exact))
840 }
841
842 /// `log10(self)` following `rounding`, or zero for zero. `Math.log10` with
843 /// a rounding argument.
844 #[inline]
845 pub const fn log10_rounding(self, rounding: Rounding) -> u32 {
846 let (r, inexact) = self.log10_parts();
847 if rounding.unsigned_rounds_up() && inexact {
848 r + 1
849 } else {
850 r
851 }
852 }
853
854 /// `floor(log256(self))`, or zero for zero. `Math.log256`.
855 ///
856 /// One more than this is the number of bytes needed to write `self`.
857 #[inline]
858 pub const fn log256(self) -> u32 {
859 self.bit_len().saturating_sub(1) / 8
860 }
861
862 /// `log256(self)` following `rounding`, or zero for zero. `Math.log256`
863 /// with a rounding argument.
864 #[inline]
865 pub const fn log256_rounding(self, rounding: Rounding) -> u32 {
866 let r = self.log256();
867 if rounding.unsigned_rounds_up()
868 && Self::ONE.wrapping_shl(r * 8).const_lt(self)
869 {
870 r + 1
871 } else {
872 r
873 }
874 }
875}
876
877/// `floor(log10(x))`, and whether `x` is exactly that power of ten.
878///
879/// `x` is at least 1 and below `10^8` at the only call site, which is what
880/// lets the final value decide exactness: after the ladder it is a single
881/// digit, and a power of ten only if that digit is 1.
882#[inline]
883const fn log10_u32(x: u32) -> (u32, bool) {
884 let mut x = x;
885 let mut r = 0;
886 let mut exact = true;
887 if x >= 10_000 {
888 exact &= x.is_multiple_of(10_000);
889 x /= 10_000;
890 r += 4;
891 }
892 if x >= 100 {
893 exact &= x.is_multiple_of(100);
894 x /= 100;
895 r += 2;
896 }
897 if x >= 10 {
898 exact &= x.is_multiple_of(10);
899 x /= 10;
900 r += 1;
901 }
902 (r, exact && x == 1)
903}