Montgomery multiplication (REDC)
- Cost
- One full product, one low product and one high or full product per multiplication, plus one conditional correction (none in the lazy variants). Conversions cost one division step with a precomputed inverse.
Montgomery's method [Mon1985] replaces the division in ab \bmod n by a division by a power of two, which is free. The price is that residues are kept in a scaled form, and that the modulus must be odd. FLINT implements it in nmod.h for full words (R = 2^{\mathtt{FLINT\_BITS}}) and half words (R = 2^{\mathtt{FLINT\_BITS}/2}). A textbook treatment is in [BZ2011].
Throughout, B = 2^{\mathtt{FLINT\_BITS}}, n is odd, and R is a power of two with n < R \le B.
Montgomery form#
The Montgomery form of x \in \mathbb{Z}/n\mathbb{Z} is \tilde x = xR \bmod n. Since R is invertible modulo n, this is a bijection, and
Addition and subtraction are therefore unchanged, and multiplication needs the map T \mapsto T R^{-1} \bmod n, called REDC. Conversion into Montgomery form costs one ordinary reduction of xR, and conversion back is one REDC of \tilde x.
Reduction#
Let n' = -n^{-1} \bmod R, which exists because n is odd. FLINT stores it in the field nred of an nmod_redc_ctx_t and computes it with n_binvert.
Input: 0 \le T < nR, and n' = -n^{-1} \bmod R.
Output: T R^{-1} \bmod n.
- m \gets (T \bmod R)\, n' \bmod R.
- t \gets (T + mn) / R.
- If t \ge n, set t \gets t - n. Return t.
Theorem 1. In Algorithm 1 the division in step 2 is exact, t \equiv T R^{-1} \pmod n, and 0 \le t < T/R + n before step 3. In particular, the result is correct for T < nR.
Proof. By the choice of m, mn \equiv -T n^{-1} n = -T \pmod R, so R divides T + mn. Then tR = T + mn \equiv T \pmod n, and multiplying by R^{-1} gives t \equiv T R^{-1}. Since 0 \le m \le R - 1, we have 0 \le tR < T + Rn, which is the bound. If T < nR, then t < 2n, so the single subtraction in step 3 brings t into [0, n).
With R = B and T = ab for reduced a and b, step 1 is a low product, mn is a full product, and the division by R is taking the high word.
The subtractive variant#
n_ll_redc, used by nmod_redc_mul, works with n^{-1} \bmod R = -n' instead of n'. This avoids the carry from the addition in step 2, which matters when n is close to B and T + mn does not fit in two words.
Input: 0 \le T < nB as two words T = T_1 B + T_0, and v = n^{-1} \bmod B.
Output: T B^{-1} \bmod n.
- m \gets T_0 v \bmod B.
- h \gets \lfloor mn / B \rfloor (a high product).
- If T_1 < h, return T_1 - h + n; otherwise return T_1 - h.
Theorem 2. Algorithm 2 is correct for every odd n < B.
Proof. We have mn \equiv T_0 v n = T_0 \pmod B, so the low word of mn equals T_0 and T - mn = (T_1 - h) B exactly. Hence T_1 - h \equiv T B^{-1} \pmod n. Both T_1 and h are in [0, n): the first because T < nB, the second because m < B. So T_1 - h \in (-n, n), and step 3 returns the representative in [0, n).
Every intermediate value fits in a word, so this works for all odd moduli up to B - 1. It is what the plain nmod_redc_ functions use.
Lazy reduction#
Skipping step 3 of Algorithm 1 saves a comparison and a conditional subtraction per multiplication, at the cost of an output in [0, 2n) instead of [0, n). Such lazy residues can be fed back into the next multiplication if the modulus is small enough. This observation is due to Walter [Wal1999].
Theorem 3 (Lazy multiplication). Let 4n \le R and let 0 \le a, b < 2n. Then REDC of T = ab without step 3 returns t \equiv ab R^{-1} \pmod n with 0 \le t < 2n.
Proof. By Theorem 1, t < T/R + n < 4n^2/R + n \le n + n = 2n.
The fast functions use this with R = B, so they require n < 2^{\mathtt{FLINT\_BITS} - 2}; nmod_redc_can_use_fast tests exactly this. The condition is needed: for 2^{\mathtt{FLINT\_BITS} - 2} < n < 2^{\mathtt{FLINT\_BITS} - 1} and a, b close to 2n, the output of nmod_redc_fast_mul can exceed 2n, and the sum T + mn can overflow two words, so that the result is not even congruent to ab R^{-1}. The bound also keeps all intermediate values in range: T + mn < 4n^2 + Bn < B^2, and 2n < B for the lazy addition and subtraction modulo 2n.
A lazy residue is turned into an ordinary one by subtracting n once if needed (nmod_redc_fast_normalise). Comparing two lazy residues for equality requires normalising both first.
Half-word arithmetic#
With R = 2^{\mathtt{FLINT\_BITS}/2} and n < R, the product T = ab of two reduced operands fits in one word, and so does T + mn provided that T + (R - 1) n < B. REDC then needs only single-word multiplications: step 1 is a product reduced modulo R (a mask), step 2 a product, an addition and a shift.
- For a, b < n (the
halffunctions) we need n^2 + (R - 1)n < B, which holds for n < R/2 = 2^{\mathtt{FLINT\_BITS}/2 - 1}. - For lazy a, b < 2n (the
half_fastfunctions) we need 4n \le R by Theorem 3, so n < 2^{\mathtt{FLINT\_BITS}/2 - 2}. Then also 4n^2 + Rn < B.
On 64-bit machines this limits the modulus to 31 or 30 bits. Whether the half-word version is faster depends on the processor; it saves the two-word arithmetic but not the number of multiplications.
Costs#
| Operation | Plain (n_mulmod2_preinv) | nmod_redc_mul | nmod_redc_fast_mul |
|---|---|---|---|
| Products | 2 full, 1 low | 1 full, 1 high, 1 low | 2 full, 1 low |
| Corrections | up to 2, and normalisation shifts | 1 | none |
| Allowed n | any | odd | odd, n < 2^{\mathtt{FLINT\_BITS} - 2} |
The number of products is the same as with Möller–Granlund reduction, but Montgomery reduction needs no normalisation shifts and fewer corrections. This shortens the chain of dependent operations, which matters most in exponentiation and other long chains of dependent products. The conversions cost about one ordinary modular multiplication each, so Montgomery arithmetic pays off only when many operations are done between them.
Use in FLINT#
nmod_pow_uiswitches to Montgomery arithmetic for odd n and exponents of at least 2^{11}, andnmod_2_pow_uifor exponents of at least 2^{20}. Both use the lazy variant when n < 2^{\mathtt{FLINT\_BITS} - 2}.n_is_primeperforms its strong probable prime tests for n \ge 2^{32} in Montgomery form, andn_factor_pollard_brent_singleiterates x \mapsto x^2 + c in Montgomery form.- The multimodular algorithms for Bell numbers (
arith_bell_number_multi_mod) and Euler numbers (inarb_euler_number_ui) use lazy Montgomery arithmetic modulo each prime. nmod_sqrtdoes all its arithmetic in Montgomery form, using thehalf_fast,fastor plain functions depending on the size of n._nmod_vec_scalar_mul_nmodusesnmod_redc_mulfor full-word odd moduli and vectors of length at least 8, where Shoup's method is not available.nmod_polycomputes Euclidean gcds and resultants of medium length in agr_ctx_init_nmod_redc_fastcontext when 2^{\mathtt{FLINT\_BITS}/2 - 1} \le n < 2^{\mathtt{FLINT\_BITS} - 2}.
ulong nmod_redc_mul(ulong x, ulong y, const nmod_redc_ctx_t ctx)ulong nmod_redc_fast_mul(ulong x, ulong y, const nmod_redc_ctx_t ctx)ulong nmod_redc_half_mul(ulong x, ulong y, const nmod_redc_ctx_t ctx)Referenced from#
- Factoring word-size integers (overview)
- Square roots modulo a prime (algorithm)
- Stirling and Bell numbers (algorithm)
- Strong probable prime test (algorithm)
- Half-GCD (algorithm)
- Basic arithmetic modulo n
nmod_pow_ui,nmod_pow_fmpz- nmod.h (module)
- Using Montgomery arithmetic
- Square roots modulo a prime
- nmod_poly.h (module)
References#
- [Mon1985] P. L. Montgomery, "Modular multiplication without trial division", Mathematics of Computation 44 (1985), 519–521
- [BZ2011] R. P. Brent and P. Zimmermann, Modern Computer Arithmetic, Cambridge University Press (2011), http://www.loria.fr/~zimmerma/mca/pub226.html
- [Wal1999] C. D. Walter, "Montgomery exponentiation needs no final subtractions", Electronics Letters 35 (1999), 1831–1832, https://doi.org/10.1049/el:19991230
The FLINT team, “Montgomery multiplication (REDC),” FLINT: Fast Library for Number Theory, documentation, version 3.7.0-dev, 2026. https://flintlib.org/doc/algorithms/arithmetic/montgomery.html (generated 2026-10-20).
@misc{flint-doc-algorithms-arithmetic-montgomery,
author = {{The FLINT team}},
title = {{Montgomery multiplication (REDC)}},
howpublished = {FLINT: Fast Library for Number Theory, documentation, version 3.7.0-dev},
year = {2026},
url = {https://flintlib.org/doc/algorithms/arithmetic/montgomery.html},
note = {Generated 2026-10-20}
}