From a48b94e57e9065bb95fbed64e2d6e1b555043ed0 Mon Sep 17 00:00:00 2001 From: Vectorized Date: Fri, 29 Nov 2024 06:25:21 +0800 Subject: [PATCH] =?UTF-8?q?=E2=9C=A8=20invMod=20(#1183)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/utils/FixedPointMathLib.sol | 20 ++++++++++++++++++++ test/FixedPointMathLib.t.sol | 15 +++++++++++++++ 2 files changed, 35 insertions(+) diff --git a/src/utils/FixedPointMathLib.sol b/src/utils/FixedPointMathLib.sol index ccd24c665..6299d0dbe 100644 --- a/src/utils/FixedPointMathLib.sol +++ b/src/utils/FixedPointMathLib.sol @@ -620,6 +620,26 @@ library FixedPointMathLib { } } + /// @dev Returns `x`, the modular multiplicative inverse of `a`, such that `(a * x) % n == 1`. + function invMod(uint256 a, uint256 n) internal pure returns (uint256 x) { + /// @solidity memory-safe-assembly + assembly { + let g := n + let r := mod(a, n) + for { let y := 1 } 1 {} { + let q := div(g, r) + let t := g + g := r + r := sub(t, mul(r, q)) + let u := x + x := y + y := sub(u, mul(y, q)) + if iszero(r) { break } + } + x := mul(eq(g, 1), add(x, mul(slt(x, 0), n))) + } + } + /// @dev Returns `ceil(x / d)`. /// Reverts if `d` is zero. function divUp(uint256 x, uint256 d) internal pure returns (uint256 z) { diff --git a/test/FixedPointMathLib.t.sol b/test/FixedPointMathLib.t.sol index 367c0408a..61d31e1bc 100644 --- a/test/FixedPointMathLib.t.sol +++ b/test/FixedPointMathLib.t.sol @@ -2161,4 +2161,19 @@ contract FixedPointMathLibTest is SoladyTest { result := and(eq(xy, ab), eq(sub(z, add(xy, lt(z, xy))), sub(c, add(ab, lt(c, ab))))) } } + + function testInvMod(uint256 a, uint256 p) public { + uint256 x = FixedPointMathLib.invMod(a, p); + if (x != 0) { + assertEq(mulmod(a, x, p), 1); + } + } + + function testInvMod() public { + uint256 a = 0xe1b81abec8db239a5c843eff0a1c4472b02982433bb3f538d4e20eb8463330dc; + uint256 n = 0x4b4ecedb4964a40fe416b16c7bd8b46092040ec42ef0aa69e59f09872f105cf3; + uint256 x = 0x164a3ce484b95d23ce8552368f477627a85a1fce9882c3011eb38eda8bcc0dd2; + assertEq(FixedPointMathLib.invMod(a, n), x); + assertEq(FixedPointMathLib.invMod(a, 0), 0); + } }