Multiplication by a fixed operand (Shoup)
- Cost
- One high product, two low products and one conditional subtraction per multiplication; one division per fixed operand.
When the same a and n are used for many products ab \bmod n, as in scaling a vector or applying a fixed twiddle factor in a number-theoretic transform, a quotient can be precomputed for a so that each product needs no division at all. The method was introduced in NTL by Shoup [Sho2021] and is analysed by Harvey [Har2014].
Throughout, B = 2^{\mathtt{FLINT\_BITS}} and the modulus satisfies n < B/2. This restriction is what makes the final correction a single comparison.
Multiplication#
The precomputed data for 0 \le a < n is \hat a = \lfloor aB/n \rfloor, which fits in a word because a < n. We write aB = \hat a n + \check a with 0 \le \check a < n.
Input: a < n < B/2, \hat a = \lfloor aB/n \rfloor and any 0 \le b < B.
Output: ab \bmod n.
- p \gets \lfloor \hat a b / B \rfloor (the high word of \hat a b).
- c \gets (ab - pn) \bmod B (two low products).
- If c \ge n, set c \gets c - n. Return c.
Lemma 1. p = \lfloor ab/n \rfloor or p = \lfloor ab/n \rfloor - 1.
Proof. From aB = \hat a n + \check a we get \hat a b / B = ab/n - \check a b/(nB). Since 0 \le \check a < n and 0 \le b < B, the subtracted term lies in [0, 1), so ab/n - 1 < \hat a b / B \le ab/n. Taking floors gives the claim.
Theorem 2. Algorithm 1 returns ab \bmod n.
Proof. By Lemma 1, the exact value ab - pn equals either ab \bmod n or (ab \bmod n) + n. Both are less than 2n < B, so the computation modulo B in step 2 is exact, and the comparison in step 3 tells the two cases apart. If n were allowed to be as large as B, then c and c + n could not be distinguished after reduction modulo B.
Updating the precomputation#
To multiply by ab \bmod n repeatedly, for example when building a table of powers a, a^2, a^3, \ldots, we also need its precomputed quotient. n_mulmod_and_precomp_shoup computes it without a division. Now let also b < n and bB = \hat b n + \check b.
Input: a, b < n < B/2, \hat a, \check a and \hat b.
Output: c = ab \bmod n and \hat c = \lfloor cB/n \rfloor.
- Compute the two-word product \hat a b = p B + e.
- c \gets (ab - pn) \bmod B; if c \ge n, set c \gets c - n.
- q \gets \lfloor \hat b \check a / B \rfloor.
- h \gets (b \check a - qn) \bmod B; if h \ge n, set q \gets q + 1.
- Return c and \hat c = (e + q) \bmod B.
Theorem 3. Algorithm 2 is correct.
Proof. Steps 1 and 2 are Algorithm 1, so c = ab \bmod n. For the quotient,
Since c = ab - \lfloor ab/n \rfloor n, we have \lfloor cB/n \rfloor = \lfloor abB/n \rfloor - \lfloor ab/n \rfloor B, and so \lfloor cB/n \rfloor \equiv e + \lfloor \check a b/n \rfloor \pmod B. As c < n, the left side is less than B, so it equals the right side reduced modulo B.
It remains to see that steps 3 and 4 compute \lfloor \check a b / n \rfloor. This is Lemma 1 with the roles of a and b exchanged (valid because b < n): the value q of step 3 is the correct quotient or one less, and \check a b - qn < 2n detects which.
Use in FLINT#
The macro NMOD_CAN_USE_SHOUP(mod) tests the condition n < 2^{\mathtt{FLINT\_BITS} - 1} for an nmod_t. Besides the functions in ulong_extras, the method is used by:
_nmod_vec_scalar_mul_nmod_shoupand_nmod_vec_scalar_addmul_nmod_shoup, which_nmod_vec_scalar_mul_nmodand_nmod_vec_scalar_addmul_nmodselect above a tuned length (see Multiplication by a fixed scalar);_nmod_vec_invert_shoup, which builds the prefix products of Simultaneous inversion together with their precomputed quotients using Algorithm 2;- scalar multiplication in
nmod_mat, evaluation of polynomials at a point and at geometric progressions innmod_poly, and modular multiplication by a fixed multiplier and Chinese remaindering inmpn_extras.
On SIMD hardware the same multiply-by-a-constant pattern is usually handled in floating point instead (Modular arithmetic in floating point).
Referenced from#
- Simultaneous inversion (algorithm)
- Choosing a method for modular arithmetic (overview)
- Montgomery multiplication (REDC) (algorithm)
- Modular multiplication with a multiword modulus (algorithm)
- Matrix multiplication kernels modulo n (algorithm)
- Multipoint evaluation and interpolation (algorithm)
flint_mpn_mulmod_precond_shoup_precompute,flint_mpn_mulmod_precond_shoupnmod_mat_scalar_mul- nmod_poly.h (module)
_nmod_poly_evaluate_nmod,nmod_poly_evaluate_nmod- Inverting all entries
- Multiplication by a fixed scalar
- Shoup multiplication
References#
- [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
The FLINT team, “Multiplication by a fixed operand (Shoup),” FLINT: Fast Library for Number Theory, documentation, version 3.7.0-dev, 2026. https://flintlib.org/doc/algorithms/arithmetic/shoup.html (generated 2026-10-20).
@misc{flint-doc-algorithms-arithmetic-shoup,
author = {{The FLINT team}},
title = {{Multiplication by a fixed operand (Shoup)}},
howpublished = {FLINT: Fast Library for Number Theory, documentation, version 3.7.0-dev},
year = {2026},
url = {https://flintlib.org/doc/algorithms/arithmetic/shoup.html},
note = {Generated 2026-10-20}
}