FLINT3.7.0-dev
Module · 111 functions

aprcl.h

#include <flint/aprcl.h>

This module implements the APRCL primality test of Adleman, Pomerance and Rumely [APR1983] in the Jacobi sum form of Cohen and Lenstra [CL1984; CL1987], following Cohen's book [Coh1996, §9.1]. It proves or disproves the primality of integers of up to about 6000 digits, in time (log⁡n)O(log⁡log⁡log⁡n)(\log n)^{O(\log \log \log n)}, and its main step consists of many independent tests that run in parallel when threads are available. fmpz_is_prime uses it for its final proof below the size from which ECPP is faster (250 bits with one thread, more with several), and as a fallback.

Most users should call fmpz_is_prime, which also handles the easy cases by n−1n - 1 and n+1n + 1 tests. aprcl_is_prime is the entry point of this module; the rest of it exposes the configuration of the test, the individual checks, and the arithmetic in the rings Z[ζpk]/(n)\mathbb{Z}[\zeta_{p^k}]/(n) (unity_zp) and Z[ζq,ζp]/(n)\mathbb{Z}[\zeta_q, \zeta_p]/(n) (unity_zpq) on which the test is built. The module also contains the older Gauss sum version of the test, which is slower and is kept for reference. The module was written by Vladimir Glazachev (Google Summer of Code 2015).

The test is described in Primality proving: APRCL and ECPP.

AlgorithmPrimality proving: APRCL and ECPPHow FLINT proves the primality of large integers, by n±1n \pm 1 tests when the factorisations allow it, by the APRCL test with Jacobi sums, and by elliptic curve primality proving with verifiable certificates.

Primality tests#

int aprcl_is_prime(const fmpz_t n)

Return 1 if nn is prime and 0 if it is not (in particular for n<2n < 2), using the Jacobi sum test with the parameters chosen by aprcl_config_jacobi_init. aprcl_is_prime is the same function. If the test cannot decide (which would require that no suitable auxiliary prime exists for one of the additional tests, and has not been observed), an exception is thrown; _aprcl_is_prime_jacobi returns UNKNOWN instead. Above about 20000 bits (6000 digits) the configuration extends the tabulated RR so that s2>ns^2 > n still holds, but ecpp_is_prime is then usually much faster.

Full documentation

The result of _aprcl_is_prime_jacobi and _aprcl_is_prime_gauss: one of PRIME, COMPOSITE, PROBABPRIME (all checks passed but primality could not be concluded) and UNKNOWN (the test could not decide).

The Jacobi sum test for nn with the given configuration. Returns PRIME, COMPOSITE or UNKNOWN, the latter also when the configuration does not satisfy s2>ns^2 > n.

More

Return 1 if nn is prime and 0 otherwise, using the Gauss sum test in the form described by Schoof [Sch2008], with the minimum value RR respectively 180. If the conditions (Lp)(\mathcal L_p) cannot be verified, aprcl_is_prime_gauss retries with RR multiplied by 2, 3 and 5 before throwing an exception. This version is much slower than the Jacobi sum test.

The Gauss sum test for nn with the given configuration. Returns PRIME, COMPOSITE or PROBABPRIME (if primality could not be proved with this RR, or the configuration does not satisfy s2>ns^2 > n).

The final step of the test: given that every divisor of nn is congruent to ni mod sn^i \bmod s for some 0≤i<r0 \le i < r, and gcd⁡(n,s)=1\gcd(n, s) = 1, returns 0 if nn is divisible by one of the residues a=ni mod sa = n^i \bmod s with 1<a≤n1 < a \le \sqrt n, 1≤i<r1 \le i < r, and 1 otherwise. If s2>ns^2 > n, a return value of 1 proves that nn is prime. The walk through the residues is parallelised when threads are available.

Configuration#

The test needs an integer RR and the product ss of prime powers qeq^e with q−1∣Rq - 1 \mid R, such that aR≡1(mods)a^R \equiv 1 \pmod s for all aa coprime to ss and s2>ns^2 > n.

The parameters of the test: R, s, the factorisation rs of RR (an n_factor_t), the factorisation qs of ss, and flags qs_used telling which prime powers of qs are used in the reduced ss.

Returns the value of RR from a precomputed table, chosen by the bit size of nn so that the corresponding ss satisfies s2>ns^2 > n and the test is fast: from R=6R = 6 for n<217n < 2^{17} to R=1396755360R = 1396755360 up to 12713 bits, and R=6983776800R = 6983776800 (for which ss has about 10000 bits, enough up to 20004 bits) beyond. For larger nn this ss is too small, and aprcl_config_jacobi_init extends RR. On 32-bit machines inputs beyond 12713 bits raise an exception.

Initialise conf for the Jacobi sum test of nn, with RR from aprcl_R_value respectively the given RR, and free it. If the value of aprcl_R_value does not give s2>ns^2 > n, aprcl_config_jacobi_init multiplies RR by the next primes after its largest prime factor until it does (throwing an exception if RR would overflow a word). The full ss for RR is reduced by dropping the prime powers qeq^e whose tests are the most expensive per bit contributed to ss (estimated from the sizes of φ(pk)\varphi(p^k) for pk∥q−1p^k \| q - 1, and very large qq first) as long as s2>ns^2 > n remains.

Initialise conf for the Gauss sum test of nn, choosing the least suitable RR (respectively the least suitable RR that is a multiple of the given one) with s2>ns^2 > n, and free it.

Return 1 if gcd⁡(xy,n)=1\gcd(xy, n) = 1 and 0 otherwise.

Returns the exponent of the prime pp in q>0q > 0.

int _aprcl_p_ind(const aprcl_config conf, ulong p)

Returns the index of the prime pp in the factorisation of RR stored in conf, or −1-1 if p∤Rp \nmid R.

The individual checks#

Here pk∥q−1p^k \| q - 1, J(p,q)J(p, q) denotes a Jacobi sum (see unity_zp_jacobi_sum_pq), and u,vu, v are the quantities of Cohen's Algorithm 9.1.28, step 4: n=pku+vn = p^k u + v with 0≤v<pk0 \le v < p^k. Each check computes J0uJvJ_0^u J_v and returns hh if it equals ζpkh\zeta_{p^k}^h, and −1-1 if it is not a root of unity (which proves nn composite).

slong _aprcl_is_prime_jacobi_check_2k(const unity_zp j, const unity_zp j2_1, const unity_zp j2_2, const fmpz_t u, ulong v)

The check for odd pp (with j=J(p,q)j = J(p, q)), for pk=2p^k = 2 (which reduces to (−q)(n−1)/2≡±1(modn)(-q)^{(n-1)/2} \equiv \pm 1 \pmod n, returning 0 for +1+1, 1 for −1-1 and −1-1 otherwise), for pk=4p^k = 4 (with j=J(2,q)j = J(2, q); hh gives ζ4h∈{1,i,−1,−i}\zeta_4^h \in \{1, i, -1, -i\}), and for p=2p = 2, k≥3k \ge 3 (with j=J(2,q)j = J(2, q), j2,1=J3(q)j_{2,1} = J_3(q) and j2,2=J2(q)j_{2,2} = J_2(q)).

int _aprcl_is_prime_jacobi_check_2k_mpn(slong * h, const unity_zp j, const unity_zp j2_1, const unity_zp j2_2, const fmpz_t u, ulong v)

The same checks with unity_zp_mpn arithmetic. They return 0 without computing anything if the modulus is not supported by mpn_mod (fewer than 2 or more than 16 limbs), in which case the caller falls back to the unity_zp versions; otherwise they return 1 and store the result in *h.

The additional test of step 5 for a prime p∣Rp \mid R for which (Lp)(\mathcal L_p) was not established: looks for a prime q≡1(mod2p)q \equiv 1 \pmod{2p} (with 4∥q−14 \| q - 1 if p=2p = 2) such that n(q−1)/p≢1(modq)n^{(q-1)/p} \not\equiv 1 \pmod q and checks that the corresponding hh is a primitive root of unity (and for p=2p = 2 that q(n−1)/2≡−1(modn)q^{(n-1)/2} \equiv -1 \pmod n). Returns 2 if nn is proved composite, 1 if the condition holds, and 0 if no suitable qq was found.

Checks of the Gauss sum test, for the Gauss sum τ(χ)\tau(\chi) of a character χ\chi of conductor qq: whether (χ(−1)q)(n−1)/2≡−1(modn)(\chi(-1) q)^{(n-1)/2} \equiv -1 \pmod n and whether q(n−1)/2≡−1(modn)q^{(n-1)/2} \equiv -1 \pmod n (for the quadratic character, returning 1 or 0), and for a character of order rr, returns ii such that τ(χn)=ζriτ(χ)n\tau(\chi^n) = \zeta_r^i \tau(\chi)^n, or −1-1 if there is none.

Arithmetic in Z[ζpk]/(n)\mathbb{Z}[\zeta_{p^k}]/(n)#

An element of Z[ζpk]/(n)\mathbb{Z}[\zeta_{p^k}]/(n), represented by an fmpz_mod_poly_t (field poly) together with pp (p), kk (exp) and the modulus context ctx. The polynomial is reduced modulo xpk−1x^{p^k} - 1, and modulo the cyclotomic polynomial Φpk\Phi_{p^k} after unity_zp_reduce_cyclotomic. Unless stated otherwise, the operands of a function must have been initialised with the same pp, kk and nn.

UNITY_ZP_MUL_BEGIN(t, glen, hlen)

The size (70) of the temporary arrays of fmpz used by the in-place multiplications, and macros that set up and release such an array of glen+hlen−1\mathit{glen} + \mathit{hlen} - 1 entries, on the stack if it fits.

void unity_zp_init(unity_zp f, ulong p, ulong exp, const fmpz_t n)

Initialise ff as the zero element of Z[ζpexp]/(n)\mathbb{Z}[\zeta_{p^{exp}}]/(n), and free it.

Copy, swap and set to zero.

unity_zp_is_unity returns hh if f=ζhf = \zeta^h and −1-1 otherwise; unity_zp_equal returns whether f=gf = g after reduction by Φpexp\Phi_{p^{exp}}.

Set, add to, increment or decrement the coefficient of ζind\zeta^{ind}, for ind<pexp\mathit{ind} < p^{exp}. The added xx must be less than nn.

void unity_zp_add(unity_zp f, const unity_zp g, const unity_zp h)

Set ff to sgsg, respectively g+hg + h.

void unity_zp_mul(unity_zp f, const unity_zp g, const unity_zp h)
void unity_zp_sqr(unity_zp f, const unity_zp g)
void unity_zp_mul_inplace(unity_zp f, const unity_zp g, const unity_zp h, fmpz_t * t)

Set ff to ghgh, respectively g2g^2, reduced by Φpexp\Phi_{p^{exp}} and nn. The inplace versions use the preallocated array tt of SQUARING_SPACE values as temporary space when it is large enough.

void _unity_zp_mul_reduce(unity_zp f, const unity_zp g, const unity_zp h, fmpz * t)

Sets ff to ghgh (or g2g^2 if hh is gg) reduced by Φpexp\Phi_{p^{exp}} and modulo nn: the product over the integers is computed by _fmpz_poly_mul or _fmpz_poly_sqr into tt (which must hold at least g->poly->length + h->poly->length - 1 initialised values), the cyclotomic reduction is done there with additions and subtractions (first by xpexp=1x^{p^{exp}} = 1, then by Φpexp(x)=Φp(xpexp−1)\Phi_{p^{exp}}(x) = \Phi_p(x^{p^{exp-1}})), and each of the φ(pexp)\varphi(p^{exp}) remaining coefficients is reduced modulo nn once. The operands need not be reduced by Φpexp\Phi_{p^{exp}}.

int _unity_zp_mul_special(unity_zp f, const unity_zp g, const unity_zp h, fmpz * t)

If a hand-optimised straight-line program exists for pexpp^{exp} (currently 3, 4, 5, 7, 8, 9 and 16), the operands have full length φ(pexp)\varphi(p^{exp}) and the modulus is small enough (a few thousand bits) that the smaller number of multiplications pays off, compute the reduced product (or square) using tt (at least SQUARING_SPACE values) as temporary space and return 1; otherwise return 0.

void unity_zp_pow_fmpz(unity_zp f, const unity_zp g, const fmpz_t pow)
void unity_zp_pow_ui(unity_zp f, const unity_zp g, ulong pow)
void unity_zp_pow_2k_fmpz(unity_zp f, const unity_zp g, const fmpz_t pow)

Set ff to gpowg^{\mathit{pow}}, by binary exponentiation, by the 2k2^k-ary method with kk from _unity_zp_pow_select_k, and by sliding window exponentiation.

Returns the least kk with log⁡n<k(k+1)22k/(2k+1−k−2)+1\log n < k(k + 1) 2^{2k} / (2^{k + 1} - k - 2) + 1, the window size for an exponent of the size of nn.

Set f=g mod Φpexpf = g \bmod \Phi_{p^{exp}}, respectively reduce ff in place (by additions, or by polynomial division); the in-place versions require ff to be reduced modulo xpexp−1x^{p^{exp}} - 1.

void unity_zp_aut(unity_zp f, const unity_zp g, ulong x)

Set f=σx(g)f = \sigma_x(g) for the automorphism σx(ζ)=ζx\sigma_x(\zeta) = \zeta^x, respectively f=σx−1(g)f = \sigma_x^{-1}(g); for the latter gg must be reduced by Φpexp\Phi_{p^{exp}}.

Jacobi sums#

Here χp,q\chi_{p,q} is the character modulo the prime qq defined by χp,q(gx)=ζpkx\chi_{p,q}(g^x) = \zeta_{p^k}^x, where gg is a primitive root modulo qq and pk∥q−1p^k \| q - 1, and j(χ1,χ2)=∑xχ1(x)χ2(1−x)j(\chi_1, \chi_2) = \sum_x \chi_1(x) \chi_2(1 - x).

Sets ff to J(p,q)=j(χp,q,χp,q)J(p, q) = j(\chi_{p,q}, \chi_{p,q}).

For p=2p = 2, set ff to J2(q)=j(χ2,q2k−3,χ2,q3⋅2k−3)2J_2(q) = j(\chi_{2,q}^{2^{k-3}}, \chi_{2,q}^{3 \cdot 2^{k-3}})^2, respectively J3(q)=j(χ2,q,χ2,q,χ2,q)=J(2,q) j(χ2,q2,χ2,q)J_3(q) = j(\chi_{2,q}, \chi_{2,q}, \chi_{2,q}) = J(2, q)\, j(\chi_{2,q}^2, \chi_{2,q}).

Returns a table (allocated with _nmod_vec_init) of the discrete logarithms f(x)f(x) with gf(x)=1−gx(modq)g^{f(x)} = 1 - g^x \pmod q for a primitive root gg modulo the prime qq, from which the Jacobi sums are computed.

Sets ff to ∑x=1q−2ζpkax+bf(x)\sum_{x=1}^{q-2} \zeta_{p^k}^{ax + b f(x)}, given the table of aprcl_f_table.

Fixed-size coefficients#

A dense analogue of unity_zp with coefficients in an mpn_mod ring, used by the Jacobi sum checks for moduli of 2 to 16 limbs. An element is a vector of d=φ(pexp)d = \varphi(p^{exp}) residues (field coeffs), always reduced by Φpexp\Phi_{p^{exp}}, together with pp, kk, pkp^k, pk−1p^{k-1}, dd, the borrowed mpn_mod context ctx, and data for the products, which are computed with a single modular reduction per output coefficient on top of _flint_mpn_poly_mulmid (classical or Karatsuba).

Initialise ff as the zero element of Z[ζpexp]/(n)\mathbb{Z}[\zeta_{p^{exp}}]/(n), where ctx is an mpn_mod context with modulus nn (borrowed: it must outlive ff), and free it.

Set to zero, swap, copy, set the coefficient of ζind\zeta^{ind} to xx (for any ind<pexp\mathit{ind} < p^{exp}, exponents of at least φ(pexp)\varphi(p^{exp}) being folded by the cyclotomic relation), and convert from a unity_zp with the same pp, kk and nn.

Product, square, scalar multiple and powers (the last by sliding window exponentiation). The output may alias the inputs.

f=σx−1(g)f = \sigma_x^{-1}(g) (ff and gg must not be aliased), and the exponent hh with f=ζhf = \zeta^h, or −1-1.

Arithmetic in Z[ζq,ζp]/(n)\mathbb{Z}[\zeta_q, \zeta_p]/(n)#

These are used by the Gauss sum test only.

An element of Z[ζq,ζp]/(n)\mathbb{Z}[\zeta_q, \zeta_p]/(n), represented by pp polynomials in ζq\zeta_q (field polys, of type fmpz_mod_poly_t), the jj-th one holding the coefficient of ζpj\zeta_p^j.

void unity_zpq_init(unity_zpq f, ulong q, ulong p, const fmpz_t n)
int unity_zpq_equal(const unity_zpq f, const unity_zpq g)

Initialise as zero, free, copy, swap and compare.

Set or add to the coefficient of ζqiζpj\zeta_q^i \zeta_p^j, for i<qi < q and j<pj < p; the added xx must be less than nn.

void unity_zpq_add(unity_zpq f, const unity_zpq g, const unity_zpq h)
void unity_zpq_mul(unity_zpq f, const unity_zpq g, const unity_zpq h)
void unity_zpq_pow(unity_zpq f, const unity_zpq g, const fmpz_t p)

Sum, product, multiplication of ff by ζp\zeta_p in place, f=gζpkf = g \zeta_p^k (the last argument being kk), and powers.

Set ff to the Gauss sum τ(χp,q)=∑xχp,q(x)ζqx\tau(\chi_{p,q}) = \sum_x \chi_{p,q}(x) \zeta_q^x, to τ(χp,qpow)\tau(\chi_{p,q}^{\mathit{pow}}), and to σn(τ(χp,q))\sigma_n(\tau(\chi_{p,q})).

References#

  • [APR1983] L. M. Adleman, C. Pomerance and R. S. Rumely. On distinguishing prime numbers from composite numbers. Annals of Mathematics 117 (1983), 173–206.
  • [CL1984] H. Cohen and H. W. Lenstra, Jr. Primality testing and Jacobi sums. Mathematics of Computation 42 (1984), 297–330.
  • [CL1987] H. Cohen and A. K. Lenstra. Implementation of a new primality test. Mathematics of Computation 48 (1987), 103–121.
  • [Coh1996] Cohen, Henri : A course in computational algebraic number theory, Springer, 1996
  • [Sch2008] R. Schoof. Four primality testing algorithms. In: J. P. Buhler and P. Stevenhagen (eds.), Algorithmic Number Theory, MSRI Publications 44, Cambridge University Press, 2008, 101–126.
Cite this page

The FLINT team, “aprcl.h (module overview),” FLINT: Fast Library for Number Theory, documentation, version 3.7.0-dev, 2026. https://flintlib.org/doc/aprcl/index.html (generated 2026-11-02).