FLINT3.7.0-dev

Square roots modulo a prime

Synopsis#include <flint/nmod.h>
int nmod_sqrt(ulong * res, ulong a, nmod_t mod)source

For prime nn and reduced aa: if aa is a square modulo nn, sets *res to the square root in [0,n/2][0, n/2] and returns 1; otherwise sets *res to 0 and returns 0. Primality is not checked. For composite nn, a return value of 1 still gives a genuine square root, but 0 does not prove that none exists.

int _nmod_sqrt_small(ulong * res, ulong a, ulong n)source

For odd nn and a<na < n, finds the least square root of aa modulo nn by exhaustive search in O(n)O(n) steps. Returns 1 and sets *res to the root, or returns 0 and sets *res to 0 if there is none. The answer is correct for composite nn too.

nmod_sqrt is the function to use for square roots modulo a word-size prime; _nmod_sqrt_small is the exhaustive search it falls back to for small odd moduli. Of the two square roots rr and n−rn - r of a nonzero square modulo a prime nn, both functions return the one in [0,n/2][0, n/2], so the result does not depend on the algorithm that found it.

Composite and even moduli#

nmod_sqrt does not check that nn is prime. For an arbitrary modulus it behaves as follows.

  • For a=0a = 0 and a=1a = 1 it returns 1 and sets *res to aa, for every nn.
  • For even nn and a≥2a \ge 2 it returns 0, even when aa is a square.
  • For odd n<128n < 128 it calls _nmod_sqrt_small, which is exact for every odd nn: it returns the least root, or 0 if there is none.
  • For odd composite n≥128n \ge 128, a return value of 1 comes with a genuine root (its square is aa modulo nn), but it need not be the least root, and a return value of 0 does not prove that aa is a non-square.

To find all square roots modulo a composite number, factor it and use n_sqrtmodn from ulong_extras.

Algorithm#

For odd n<128n < 128, the function searches through t=1,…,(n−1)/2t = 1, \ldots, (n-1)/2, computing t2t^2 incrementally. Otherwise all arithmetic is done in Montgomery form, with half-word, full-word lazy or full-word arithmetic depending on the size of nn, and the method depends on nn:

CaseMethodCost
n≡3(mod4)n \equiv 3 \pmod 4r=a(n+1)/4r = a^{(n+1)/4}one exponentiation
n≡5(mod8)n \equiv 5 \pmod 8Atkin's formulaone exponentiation
n≡1(mod8)n \equiv 1 \pmod 8, s<12s < 12Tonelli–Shanksone exponentiation and O(s2)O(s^2) dependent multiplications
n≡1(mod8)n \equiv 1 \pmod 8, s≥12s \ge 12Tonelli–Shanks by bitsone exponentiation and O(s2)O(s^2) independent multiplications
n≡1(mod8)n \equiv 1 \pmod 8, large ssMüller's Lucas sequence methodabout one exponentiation and a few Jacobi symbols

Here ss is the exponent of the largest power of 2 dividing n−1n - 1. Müller's method is used when 6s6s is at least the bit length of nn plus 120, which requires n≥225n \ge 2^{25}; it is typical of primes chosen for number-theoretic transforms, such as 469762049=7⋅226+1469762049 = 7 \cdot 2^{26} + 1.

None of the methods tests whether aa is a square first. Each produces a candidate root, which is accepted only if its square is aa. For prime nn this check is the residuosity test, and it is also what makes the result trustworthy for composite nn.

AlgorithmSquare roots modulo a primeHow nmod_sqrt finds a square root modulo a word-size prime nn. It uses one exponentiation when n≡3(mod4)n \equiv 3 \pmod 4 or n≡5(mod8)n \equiv 5 \pmod 8, and otherwise Tonelli–Shanks in two forms or Müller's variant of Cipolla–Lehmer, depending on the power of 2 dividing n−1n - 1. Every candidate root is checked by squaring.

Example#

The four primes below exercise the four main code paths: n≡3(mod4)n \equiv 3 \pmod 4, n≡5(mod8)n \equiv 5 \pmod 8, Tonelli–Shanks with s=5s = 5 (where 10 is not a square), and Müller's method with s=26s = 26.

Examplenmod_sqrt_basic.cchecked by make checkdoc
#include <flint/flint.h>
#include <flint/nmod.h>

int main(void)
{
    ulong primes[4] = { 1000003, 1000037, 1000033, 469762049 };
    nmod_t mod;
    ulong r, a;
    int i;

    for (i = 0; i < 4; i++)
    {
        nmod_init(&mod, primes[i]);
        a = nmod_set_ui(10, mod);

        if (nmod_sqrt(&r, a, mod))
            flint_printf("n = %wu: sqrt(10) = %wu, r^2 = %wu\n",
                         mod.n, r, nmod_mul(r, r, mod));
        else
            flint_printf("n = %wu: 10 is not a square\n", mod.n);
    }

    /* composite n: the root found is genuine */
    nmod_init(&mod, 135);
    if (nmod_sqrt(&r, 81, mod))
        flint_printf("n = 135: sqrt(81) = %wu\n", r);
    return 0;
}
Output
n = 1000003: sqrt(10) = 394215, r^2 = 10
n = 1000037: sqrt(10) = 122489, r^2 = 10
n = 1000033: 10 is not a square
n = 469762049: sqrt(10) = 115267370, r^2 = 10
n = 135: sqrt(81) = 54

Modulo 135, the square roots of 81 in [0,67][0, 67] are 9, 36 and 54. The function returns 54, a genuine root but not the least one.

Guides#

Cite this page

The FLINT team, “Square roots modulo a prime (nmod.h),” FLINT: Fast Library for Number Theory, documentation, version 3.7.0-dev, 2026. https://flintlib.org/doc/nmod/sqrt.html (generated 2026-11-02).