Skip to content

Commit

Permalink
✨ invMod (#1183)
Browse files Browse the repository at this point in the history
  • Loading branch information
Vectorized authored Nov 28, 2024
1 parent 82e14c6 commit a48b94e
Show file tree
Hide file tree
Showing 2 changed files with 35 additions and 0 deletions.
20 changes: 20 additions & 0 deletions src/utils/FixedPointMathLib.sol
Original file line number Diff line number Diff line change
Expand Up @@ -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) {
Expand Down
15 changes: 15 additions & 0 deletions test/FixedPointMathLib.t.sol
Original file line number Diff line number Diff line change
Expand Up @@ -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);
}
}

0 comments on commit a48b94e

Please sign in to comment.