Modular Inverse
Presentation: https://youtu.be/eEU1v1ZPHe0
Modular Inverse
Suppose we want to find the modular inverse of some element modulo , that is:
The inverse exists if and only if , i.e., when is coprime with .
When is a prime number, the field forms a finite field, and every nonzero element has an inverse. In that case, Fermat’s Little Theorem can be used to compute the inverse efficiently:
Note: This method only works when is prime. For general modulus (not necessarily prime), the modular inverse of (if it exists) can be computed using the Extended Euclidean Algorithm.
Modular Inverse using Binary Extended Euclidean Algorithm
However, a more efficient method is to use the Extended Euclidean Algorithm, which solves the following equation:
Taking both sides modulo yields:
Therefore, is the modular inverse of modulo .
Core Idea
Let be an odd prime, and let and be coprime. Starting with and , we apply the Binary GCD rules and reduce until either or becomes 1. The case where both and are even has already been handled in the previous stage and is thus excluded here.
Meanwhile, as in the Binary Extended Euclidean Algorithm, we initialize the variables as , and maintain the following two invariants:
If we take both sides modulo , we obtain simpler invariants:
At each step, we update the expressions while maintaining these invariants. Let’s examine just case 2 and case 4 as examples.
Case 2: is even
If is even, we update as:
If is odd, we update as:
Case 4: and both and are odd
We update as:
Code
Here is the Python implementation of Algorithm 16: BEA for Inversion in 𝔽ₚ (Binary Extended Euclidean Algorithm for computing the modular inverse in a prime field) from here. Each step is annotated with comments to aid understanding.
def binary_inverse_fp(a: int, p: int) -> int:
"""
Computes the modular inverse of a modulo prime p using Binary Extended Euclidean Algorithm.
Parameters: a ∈ 𝔽ₚ, prime p greater than 2
Returns: a⁻¹ mod p
"""
u, v = a, p # Step 1: Initialize u ← a, v ← p
b, c = 1, 0 # Initialize Bézout coefficients: b for u, c for v
while u != 1 and v != 1: # Step 2
# Step 3-10: Make u odd
while u % 2 == 0:
u //= 2
if b % 2 == 0:
b //= 2
else:
b = (b + p) // 2
# Step 11-18: Make v odd
while v % 2 == 0:
v //= 2
if c % 2 == 0:
c //= 2
else:
c = (c + p) // 2
# Step 19-23: Subtract the smaller from the larger and update coefficients
if u >= v:
u -= v
b -= c
else:
v -= u
c -= b
# Step 25-29: Return the correct inverse mod p
if u == 1:
return b % p
else:
return c % p
For Montgomery Domain
A value is transformed to its Montgomery representation as follows:
Therefore, if we naively compute the modular inverse of , we get:
However, the form we actually want is:
To achieve this, instead of initializing with , we can set , and then return the result of the inversion algorithm.
Montgomery Inversion Algorithm
Another efficient algorithm for computing modular Inverse is Kaliski's Montgomery Inverse algorithm.
Kaliski’s Montgomery Inverse consists of two phases:
Almost Inverse phase
where
Correction phase
Core Idea
TODO(chokoble): Add reason why this code works.
Code
Here is the Python implementation of Algorithm 17: Montgomery Inversion in 𝔽ₚ from here.
def montgomery_inverse_fp(a: int, p: int, n: int) -> tuple[int, int]:
"""
Computes Montgomery Inverse of a mod p.
Returns r ≡ a⁻¹ · 2^k mod p, where n ≤ k ≤ 2n.
Parameters:
a (int): element in 𝔽ₚ
p (int): prime modulus
n (int): expected bit-length of p (e.g., n = p.bit_length())
Returns:
(r, k): Montgomery inverse r and the exponent k
"""
# Step 1: Initialization
u = p
v = a
r = 0
s = 1
k = 0
# Step 2–11: Main loop
while v > 0:
if u % 2 == 0:
u //= 2
s *= 2
elif u > v:
u = (u - v) // 2
r += s
s *= 2
else: # v >= u
v = (v - u) // 2
s += r
r *= 2
k += 1
# Step 12–14: Reduce r if needed (Almost Inverse)
if r >= p:
r -= p
# Step 15–21: Final division loop to normalize r
for _ in range(k - n):
if r % 2 == 0:
r //= 2
else:
r = (r + p) // 2
# Step 22: Return Montgomery inverse and k
return r, k
Last updated