LogoLogo
LogoLogo
  • Introduction
    • About Us
    • Notations & Definitions
      • MPC
      • ZK
    • Contribute to this Site!
  • Primitives
    • Multiplication
      • Karatsuba Multiplication
      • Toom-Cook Multiplication
    • NAF (Non-adjacent form)
    • Chinese Remainder Theorem (CRT)
    • Euclidean Algorithm
      • Extended Euclidean Algorithm
      • Binary Euclidean Algorithm
      • Extended Binary Euclidean Algorithm
    • Coding Theory
      • Linear Code
    • Number Theoretic Transform
    • Abstract Algebra
      • Group
        • -Morphisms
        • Batch Inverse
      • Elliptic Curve
        • Weierstrass Curve
          • Coordinate Forms
          • Fast Elliptic Curve Arithmetic and Improved WEIL Pairing Evaluation
        • Edwards Curve
          • Coordinate Forms
          • Twisted Edwards ↔ Short Weierstrass Transformation
        • Batch Inverse for Batch Point Additions
        • Scalar Multiplication
          • Double-and-add
          • GLV Decomposition
        • MSM
          • Pippenger's Algorithm
          • Signed Bucket Index
          • CycloneMSM
          • EdMSM
          • cuZK
        • 2-Chain and 2-Cycle of Elliptic Curves
    • Encryption Scheme
      • ElGamal Encryption
    • Modular Arithmetic
      • Modular Reduction
        • Barrett Reduction
        • Montgomery Reduction
      • Modular Inverse
        • Bernstein-Yang's Inverse
    • Multiset Check
    • Sumcheck
    • Commitment Scheme
      • Fflonk
      • SHPlonk
      • Zeromorph
  • MPC
    • Yao's Garbled Circuits
    • GMW
    • BMR
  • ZK
    • Arithmetization
      • R1CS
      • PLONK
      • AIR
    • Folding
      • LatticeFold
      • Nova
        • Nova over Cycles of Curves
    • Lookup
      • Lasso
      • LogUp-GKR
    • SNARK
      • Groth16
      • HyperPlonk
      • Spartan
        • SPARK
    • STARK
      • Additive NTT
      • Basefold
      • Binius
      • Brakedown
      • CircleSTARK
      • FRI
        • FRI Security Features and Optimizations
      • DEEP FRI
      • STIR
      • WHIR
    • Distributed ZK
      • Ryan's Trick for Distributed Groth16
  • Application
    • zkLogin
    • zkHoldem
    • zkTLS
      • DECO
      • Proxying is enough
  • zkVM
Powered by GitBook
On this page
  • Modular Inverse
  • Modular Inverse using Binary Extended Euclidean Algorithm
  • Core Idea
  • Code
  • For Montgomery Domain
  • Montgomery Inversion Algorithm
  • Core Idea
  • Code
Export as PDF
  1. Primitives
  2. Modular Arithmetic

Modular Inverse

Presentation: https://youtu.be/eEU1v1ZPHe0

PreviousMontgomery ReductionNextBernstein-Yang's Inverse

Last updated 1 month ago

Modular Inverse

Suppose we want to find the modular inverse x=a−1x = a^{-1}x=a−1 of some element aaa modulo ppp, that is:

ax≡1mod  pax \equiv 1 \mod pax≡1modp

The inverse exists if and only if gcd⁡(a,p)=1\gcd(a, p) = 1gcd(a,p)=1, i.e., when aaa is coprime with ppp.

When ppp is a prime number, the field Fp\mathbb{F}_pFp​ forms a finite field, and every nonzero element has an inverse. In that case, can be used to compute the inverse efficiently:

x≡ap−2mod  px \equiv a^{p-2} \mod px≡ap−2modp

Note: This method only works when ppp is prime. For general modulus mmm (not necessarily prime), the modular inverse of aaa (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 , which solves the following equation:

ax+py=gcd⁡(a,p)=1ax + py = \gcd(a, p) = 1ax+py=gcd(a,p)=1

Core Idea

At each step, we update the expressions while maintaining these invariants. Let’s examine just case 2 and case 4 as examples.

We update as:

Code

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

However, the form we actually want is:

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

  • Correction phase

Core Idea

TODO(chokoble): Add reason why this code works.

Code

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

Taking both sides modulo ppp yields:

ax≡1mod  pax \equiv 1 \mod pax≡1modp

Therefore, xxx is the modular inverse of aaa modulo ppp.

Let ppp be an odd prime, and let aaa and ppp be coprime. Starting with u=au = au=a and v=pv = pv=p, we apply the Binary GCD rules and reduce until either uuu or vvv becomes 1. The case where both uuu and vvv are even has already been handled in the previous stage and is thus excluded here.

gcd⁡(u,v)={1 if u=1∨v=1gcd⁡(u2,v) if u≡0(mod2)gcd⁡(u,v2) if v≡0(mod2)gcd⁡(u−v,v) if u≥v∧u≡1(mod2)∧ v≡1(mod2)gcd⁡(u,v−u) if v>u∧u≡1(mod2)∧ v≡1(mod2)\gcd(u, v) = \begin{cases} 1 & \text{ if } u = 1 \lor v = 1 \\ \gcd \left(\frac{u}{2}, v \right) & \text{ if } u \equiv 0 \pmod 2 \\ \gcd \left(u, \frac{v}{2} \right) & \text{ if } v \equiv 0 \pmod 2 \\ \gcd \left(u - v, v \right) & \text{ if } u \ge v \land u \equiv 1 \pmod 2 \land \ v \equiv 1 \pmod 2 \\ \gcd \left(u, v - u \right) & \text{ if } v > u \land u \equiv 1 \pmod 2 \land \ v \equiv 1 \pmod 2 \\ \end{cases}gcd(u,v)=⎩⎨⎧​1gcd(2u​,v)gcd(u,2v​)gcd(u−v,v)gcd(u,v−u)​ if u=1∨v=1 if u≡0(mod2) if v≡0(mod2) if u≥v∧u≡1(mod2)∧ v≡1(mod2) if v>u∧u≡1(mod2)∧ v≡1(mod2)​

Meanwhile, as in the Binary Extended Euclidean Algorithm, we initialize the variables as x1=1,y1=0,x2=0,y2=1x_1 = 1, y_1 = 0, x_2 = 0, y_2 = 1x1​=1,y1​=0,x2​=0,y2​=1, and maintain the following two invariants:

ax1+py1=u,ax2+py2=vax_1 + p y_1 = u, \quad a x_2 + p y_2 = vax1​+py1​=u,ax2​+py2​=v

If we take both sides modulo ppp, we obtain simpler invariants:

ax1≡umod  p,ax2≡vmod  pa x_1 \equiv u \mod p, \quad a x_2 \equiv v \mod pax1​≡umodp,ax2​≡vmodp

Case 2: uuu is even

If x1x_1x1​​ is even, we update as:

ax1≡umod  p⇔a⋅x12≡u2mod  pa x_1 \equiv u \mod p \quad \Leftrightarrow \quad a \cdot \frac{x_1}{2} \equiv \frac{u}{2} \mod p ax1​≡umodp⇔a⋅2x1​​≡2u​modp

If x1x_1x1​​ is odd, we update as:

ax1≡umod  p⇔a⋅x1+p2≡u2mod  pa x_1 \equiv u \mod p \quad \Leftrightarrow \quad a \cdot \frac{x_1 + p}{2} \equiv \frac{u}{2} \mod pax1​≡umodp⇔a⋅2x1​+p​≡2u​modp

Case 4: u≥vu \ge vu≥v and both uuu and vvv are odd

ax1≡umod  p,ax2≡vmod  p⇔a(x1−x2)≡u−vmod  pa x_1 \equiv u \mod p, \quad a x_2 \equiv v \mod p \quad \Leftrightarrow \quad a(x_1 - x_2) \equiv u - v \mod pax1​≡umodp,ax2​≡vmodp⇔a(x1​−x2​)≡u−vmodp

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 . Each step is annotated with comments to aid understanding.

A value aaa is transformed to its as follows:

toMont(a)=aR=a2n\mathsf{toMont}(a) = aR = a2^ntoMont(a)=aR=a2n

Therefore, if we naively compute the modular inverse of aRaRaR, we get:

ModInv(aR)=a−1R−1=a−12−n\mathsf{ModInv}(aR) = a^{-1}R^{-1} = a^{-1}2^{-n}ModInv(aR)=a−1R−1=a−12−n
toMont(a−1)=a−1R\mathsf{toMont}(a^{-1}) = a^{-1}RtoMont(a−1)=a−1R

To achieve this, instead of initializing with b=1b = 1b=1, we can set b=R2mod  pb = R^2 \mod pb=R2modp, and then return the result of the inversion algorithm.

ModInv(aR)×R2=a−1R\mathsf{ModInv}(aR) \times R^2 = a^{-1}RModInv(aR)×R2=a−1R
AlmostInv(a)=a−1⋅2k\mathsf{AlmostInv}(a) = a^{-1} \cdot 2^kAlmostInv(a)=a−1⋅2k

where n≤k≤2nn \le k \le 2nn≤k≤2n

Correction(a−1⋅2k)=a−1⋅2n\mathsf{Correction}(a^{-1} \cdot 2^k) = a^{-1} \cdot 2^nCorrection(a−1⋅2k)=a−1⋅2n

Here is the Python implementation of Algorithm 17: Montgomery Inversion in 𝔽ₚ from .

Written by from

here
here
A41
ryan Kim
Montgomery representation
Fermat’s Little Theorem
Extended Euclidean Algorithm