Skip to main content

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}