Modular multiplication with a multiword modulus
- Cost
- One -limb product, one high product and one low product of limbs, and subtractions per modular product; a fixed multiplier saves the high product of the reduction (Shoup) or replaces both products by an matrix-vector product and a two-limb reduction (matrix method).
FLINT computes for residues when has limbs in three places: in mpn_mod (mpn_mod_mul), in mpn_extras (flint_mpn_mulmod_preinvn and its relatives, which mpn_mod, fmpz and the primality tests use) and in fmpz_mod for two-limb moduli. All methods follow Barrett's idea [Bar1987] of replacing the division by with multiplications by a precomputed approximation of ; for a single limb, the analogous methods are described in Division by an invariant word, Barrett and Lemire reduction and Multiplication by a fixed operand (Shoup). A textbook treatment of multiword Barrett and Montgomery reduction is [BZ2011, §2.4].
Throughout, , has exactly limbs (), and is the number of leading zero bits of its top limb.
Normalisation#
The reduction works with the normalised modulus , which satisfies . Reducing modulo is enough, since for every integer
To reduce a product , one reduces modulo and shifts the remainder right by bits. mpn_mod stores in its context (MPN_MOD_CTX_MODULUS_NORMED) and shifts before the multiplication; flint_mpn_mulmod_preinvn instead expects operands that are already shifted.
The precomputed inverse#
flint_mpn_preinvn computes the -limb number
Since , the quotient lies in , so and is an approximation of from below whose leading 1 need not be stored. (For , .) This is the -limb analogue of the one-limb inverse of Möller and Granlund [GraMol2010]. It costs one division of a -limb number, which mpn_mod performs once per context.
Reduction of a product#
Input: normalised, as above, and . Output: .
- Write with .
- Compute , the high half of plus .
- Compute from the low limbs of and of (a low product).
- While , set . Then, if , set . Return .
The input bound holds for with , since then . It implies .
Theorem 1. Let . Then . Consequently , step 3 computes exactly, and step 4 performs at most five subtractions and returns .
Proof. Since and ,
so . In the other direction, and give
while . Hence
using and . So . In particular , so is determined by , which only involves the low limbs of and of . Also , so has limbs and the carry of the addition in step 2 is zero. Each subtraction in step 4 keeps and ; after the loop , and the final subtraction gives .
The bound 5 is crude; it only matters that the number of corrections is bounded by a small constant. The cost is one product (to form ), one high product and one low product of limbs, which is about three products when all three are computed in full. flint_mpn_mul_or_mulhigh_n and flint_mpn_mul_or_mullow_n compute the high and low products with the short product algorithms of mpn_extras when these are faster (High, low and middle products of integers). The approximate high product is a lower bound that is short by at most one unit (flint_mpn_mulhigh_n), so is still at most and the loop in step 4 runs at most once more.
For , flint_mpn_mulmod_preinvn_2 (used by mpn_mod_mul and the two-limb vector loops) is the same algorithm written with inline two-limb arithmetic; the low product is computed as three limbs.
Variants#
flint_mpn_fmmamod_preinvncomputes . The shifted sum is less than ; one conditional subtraction of (from the high half) brings it below , and the algorithm above finishes. This costs two products and one reduction, against two products and two reductions for separate modular products.flint_mpn_mod_preinvnandflint_mpn_divrem_preinvnreduce numbers of any length by applying the algorithm to limbs of the dividend at a time, from the top.mpn_mod_set_mpn, which reduces unreduced sums inmpn_mod, usesflint_mpn_mod_preinvnfor and GMP'smpn_divrem_2for .
Two-limb Barrett reduction in fmpz_mod#
For , fmpz_mod_ctx_init precomputes the three-limb number , and fmpz_mod_mul (through _fmpz_mod_mul2) reduces by classical Barrett reduction:
Proposition 2. , so at most two subtractions of give .
Proof. Let and . Then , so . Also , and (since ), so
using . Hence , and .
The code computes the five-limb product with ten word products, skipping only the low half of the lowest one (which cannot carry into the limbs that are used), and the low three limbs of . The remainder fits in three limbs, so the corrections are three-limb comparisons. The modulus has its own code (_fmpz_mod_mul2s, a wrapping product), and one-limb moduli use nmod_mul.
A fixed multiplier#
When the same multiplies many , as in scaling a vector or in the division steps of Euclid's algorithm, precomputation for pays off. flint_mpn_mulmod_want_precond chooses the method from and the number of products: none for fewer than 4 products, Shoup's method for (and for with at most 12 products), the matrix method for larger up to 64 limbs (and beyond with enough products), so that mpn_mod uses Shoup's method up to 10 limbs and the matrix method for 11 to 16 limbs. For with the top bit of set, no precomputation is used through this function, but the vector functions of mpn_mod have their own inlined two-limb Shoup code.
Shoup's method#
Shoup's method [Sho2021; Har2014] precomputes the -limb quotient
(flint_mpn_mulmod_precond_shoup_precompute, one division). A product is then computed as
where is obtained from the low halves of and alone.
Proposition 3. .
Proof. Write with and with . Then
so , which is nonnegative and less than .
The cost per product is one high product and two low products of limbs, against one full, one high and one low product without precomputation. If (), then fits in limbs and one conditional subtraction finishes.
The implementation computes with the approximate high product flint_mpn_mulhigh_n, a lower bound which may be . This can only happen when for a small constant (the error of the approximation, a few units of the limb below the high half). Then the computed remainder is when , so for one subtraction still suffices. If the top bit of is set, may exceed ; the code then computes modulo and subtracts up to twice (for it uses an exact high product and one subtraction).
The matrix method#
The matrix method precomputes the residues
(flint_mpn_mulmod_precond_matrix_precompute, one-limb shifts and reductions). For ,
and the right-hand side is a matrix-vector product of word products, less than . It is reduced modulo with two steps of one-limb quotient estimation (flint_mpn_mod_preinv1) and shifted right by bits. Compared with the full product followed by the reduction of Algorithm 1, the high and low products of the reduction are replaced by work, at the price of limbs of precomputed data. The fused version flint_mpn_fmmamod_precond_matrix adds two such matrix-vector products before reducing.
Inversion and powering#
Inverses modulo a multiword are computed with GMP's extended Euclidean algorithm (mpn_gcdext in mpn_mod_inv, fmpz_gcdinv in fmpz_mod_inv), which is subquadratic for large operands. Powers with large exponents use GMP's mpz_powm (in mpn_mod_pow_fmpz, and through fmpz_powm in fmpz_mod_pow_fmpz for moduli below 70000 bits). It uses Montgomery's representation [Mon1985], in which no quotient estimate is needed, with sliding windows; mpn_mod uses it for exponents with more than 6 bits. For moduli of 70000 bits and more (and when fft_small is available), fmpz_mod_pow_fmpz switches to generic sliding-window exponentiation with fmpz_mod_mul, whose products use the FFT.
Use in FLINT#
mpn_mod_mul,mpn_mod_sqr,_mpn_mod_vec_mul: Algorithm 1, for throughflint_mpn_mulmod_preinvn_2.mpn_mod_fmmaand the length-2 dot products:flint_mpn_fmmamod_preinvn._mpn_mod_vec_mul_scalar,_mpn_mod_vec_addmul_scalar,_mpn_mod_vec_submul_scalar: Shoup's method or the matrix method for vectors of at least 4 (or 6) elements._mpn_mod_poly_divrem_q1_preinv1_fmma_precondand_mpn_mod_poly_divrem_q1_preinv1_karatsuba_precond: the matrix method for the two quotient coefficients of a Euclidean step.fmpz_mod_mulfor : Proposition 2.flint_mpn_mulmod_preinvn,flint_mpn_powmod_preinvnandflint_mpn_sqrtmod_preinvinmpn_extras, used bympn_mod_sqrtand the integer square root modulo a prime.- Sums of many products are not reduced one product at a time; see Delayed reduction for multiword moduli.
int mpn_mod_mul(nn_ptr res, nn_srcptr x, nn_srcptr y, gr_ctx_t ctx)void flint_mpn_mulmod_preinvn(mp_ptr r, mp_srcptr a, mp_srcptr b, mp_size_t n, mp_srcptr d, mp_srcptr dinv, ulong norm)void flint_mpn_preinvn(mp_ptr dinv, mp_srcptr d, mp_size_t n)void flint_mpn_mulmod_precond_shoup(mp_ptr res, mp_srcptr a, mp_srcptr apre, mp_srcptr b, mp_size_t n, mp_srcptr d, ulong norm)void flint_mpn_mulmod_precond_matrix(mp_ptr rp, mp_srcptr apre, mp_srcptr b, mp_size_t n, mp_srcptr dnormed, mp_srcptr dinv, ulong norm)Referenced from#
- Delayed reduction for multiword moduli (algorithm)
- Arithmetic modulo multiword integers (overview)
fmpz_mod_ctx_init,fmpz_mod_ctx_init_uifmpz_mod_mul_fmpz_mod_add2,_fmpz_mod_sub2,_fmpz_mod_mul2flint_mpn_preinvn- mpn_extras.h (module)
flint_mpn_mulmod_precond_matrix_alloc,flint_mpn_mulmod_precond_matrix_precompute,flint_mpn_mulmod_precond_matrix,flint_mpn_fmmamod_precond_matrix- mpn_mod.h (module)
mpn_mod_mul,mpn_mod_sqr_mpn_mod_vec_mul_scalar,_mpn_mod_scalar_mul_vec,_mpn_mod_vec_addmul_scalar,_mpn_mod_vec_submul_scalar
References#
- [Bar1987] P. Barrett, "Implementing the Rivest Shamir and Adleman public key encryption algorithm on a standard digital signal processor", Advances in Cryptology – CRYPTO '86, LNCS 263 (1987), 311–323
- [BZ2011] R. P. Brent and P. Zimmermann, Modern Computer Arithmetic, Cambridge University Press (2011), http://www.loria.fr/~zimmerma/mca/pub226.html
- [GraMol2010] N. Möller and T. Granlund, "Improved division by invariant integers", IEEE Transactions on Computers 60 (2011), 165–175, https://gmplib.org/~tege/division-paper.pdf
- [Sho2021] V. Shoup, "Arithmetic software libraries", chapter 9 of Computational Cryptography, Cambridge University Press (2021), https://doi.org/10.1017/9781108854207.012
- [Har2014] D. Harvey, "Faster arithmetic for number-theoretic transforms", Journal of Symbolic Computation 60 (2014), 113–119, https://doi.org/10.1016/j.jsc.2013.09.002
- [Mon1985] P. L. Montgomery, "Modular multiplication without trial division", Mathematics of Computation 44 (1985), 519–521
The FLINT team, “Modular multiplication with a multiword modulus,” FLINT: Fast Library for Number Theory, documentation, version 3.7.0-dev, 2026. https://flintlib.org/doc/algorithms/arithmetic/multiword-mulmod.html (generated 2026-11-02).
@misc{flint-doc-algorithms-arithmetic-multiword-mulmod,
author = {{The FLINT team}},
title = {{Modular multiplication with a multiword modulus}},
howpublished = {FLINT: Fast Library for Number Theory, documentation, version 3.7.0-dev},
year = {2026},
url = {https://flintlib.org/doc/algorithms/arithmetic/multiword-mulmod.html},
note = {Generated 2026-11-02}
}