FLINT3.7.0-dev
Module · 87 functions

dlog.h

#include <flint/dlog.h>

This module computes discrete logarithms in cyclic subgroups of (Z/mZ)×(\mathbb{Z}/m\mathbb{Z})^\times for word-size moduli mm, mostly primes and prime powers: given aa of order nn and b∈⟨a⟩b \in \langle a \rangle, it finds x∈[0,n)x \in [0, n) with ax≡b(modm)a^x \equiv b \pmod m. It was written for Dirichlet characters (dirichlet, acb_dirichlet), where many logarithms are taken in the same group, so its central object is a precomputation, dlog_precomp_t, built for a given base and an expected number of queries: the choice of method (complete table, baby-step giant-step, Pohlig–Hellman decomposition, pp-adic logarithm) and the amount of stored data depend on the structure of the group and on that number. The module also computes the logarithms of all integers 1,…,N−11, \ldots, N-1 at once, by enumeration or by sieving.

Little effort has been made for a single logarithm in a large group of prime order. For one-off logarithms modulo a prime with smooth p−1p - 1, see also nmod_discrete_log_pohlig_hellman (Discrete logarithms modulo a prime (Pohlig–Hellman)). Precomputed discrete logarithms explains how to set up a precomputation, and the algorithms are described in Discrete logarithm tables.

AlgorithmDiscrete logarithm tablesPrecomputations for many discrete logarithms in a fixed cyclic group modulo a word-size prime power, combining baby-step giant-step tables sized for the number of queries, the Pohlig–Hellman decomposition and p-adic logarithms, and a sieve for the logarithms of all small integers.

Conventions#

Logarithms are returned as ulong values in [0,n)[0, n), where nn is the order of the base. The base must have exactly the order passed to the functions, and the moduli must fit in a word; none of this is checked. The result for an argument bb outside the subgroup generated by the base is not specified (some methods throw, others return a wrong value).

The value UWORD_MAX, used in vectors of logarithms for the entries whose logarithm does not exist (integers not coprime to the modulus).

Single logarithms#

ulong dlog_once(ulong b, ulong a, const nmod_t mod, ulong n)

Returns xx with ax≡ba^x \equiv b modulo mod.n, where aa has order nn: by enumerating the powers of aa for n<50n < 50 (throwing if bb is not found), and otherwise with a precomputation for one query (dlog_precomp_n_init with num =1= 1), which is cleared afterwards.

Precomputed logarithms#

Precomputed data for logarithms to a fixed base: the method (type), an estimate of the cost of one logarithm (cost, in multiplications), and the data of the method. A dlog_precomp_t is an array of length one of dlog_precomp_struct.

Initialises pre for about num logarithms to the base aa of order nn modulo mod, with no further information on nn. If nn is an odd prime the function calls dlog_precomp_p_init; otherwise it uses a complete table for n<50n < 50, baby-step giant-step for n<500n < 500, and the Pohlig–Hellman decomposition (dlog_crt_init) above.

Full documentation

As dlog_precomp_n_init for a base of prime order pp: a complete table for p<50p < 50, otherwise baby-step giant-step with a table of dlog_bsgs_size(p, num) powers.

Full documentation

As dlog_precomp_n_init for a base of prime power order pe=pe\mathit{pe} = p^e: a complete table for pe<50p^e < 50, dlog_precomp_p_init for e=1e = 1, and otherwise the base-pp digit decomposition (dlog_power_init).

Full documentation

Initialises pre for logarithms to the base aa modulo pe=pe\mathit{pe} = p^e, where aa generates (Z/peZ)×(\mathbb{Z}/p^e\mathbb{Z})^\times (for odd pp), or, for p=2p = 2 and e≥3e \ge 3, a=5a = 5 generates the subgroup of elements congruent to 1 modulo 4. Uses a complete table for pe<50p^e < 50, the reduction to a logarithm modulo pp and a pp-adic logarithm (dlog_modpe_init) for e≥2e \ge 2, and dlog_precomp_n_init modulo pp for e=1e = 1.

Full documentation

Initialises pre for a group of small order nn: the trivial method for n≤3n \le 3, a complete table indexed by the residues if mod<50\mathit{mod} < 50, and otherwise a baby-step giant-step table containing all nn powers (so that a logarithm is one binary search).

Full documentation

Returns the logarithm of bb (reduced modulo the modulus) to the base of pre.

Full documentation

Frees the memory used by pre. Does nothing if pre is NULL.

Full documentation

Vectors of logarithms#

These functions compute, for all 0≤k<nv0 \le k < \mathit{nv}, the value valog⁡a(k) mod orderv_a \log_a(k) \bmod \mathit{order}, where log⁡a(k)\log_a(k) is the logarithm of k mod mk \bmod m to a base aa of order nan_a (na) generating (Z/mZ)×(\mathbb{Z}/m\mathbb{Z})^\times (so mm is a prime power or twice one). The modulus order must divide vanav_a n_a, so that the result is well defined; with va=1v_a = 1 and order=na\mathit{order} = n_a these are the plain logarithms. Entries for kk not coprime to mm are DLOG_NONE. This is the form needed for the exponents of Dirichlet characters.

void dlog_vec(ulong * v, ulong nv, ulong a, ulong va, nmod_t mod, ulong na, nmod_t order)
void dlog_vec_add(ulong * v, ulong nv, ulong a, ulong va, nmod_t mod, ulong na, nmod_t order)

Set v[k]v[k] to valog⁡a(k) mod orderv_a \log_a(k) \bmod \mathit{order}, or (the add version) add it to v[k]v[k] modulo order for every kk with v[k]≠v[k] \ne DLOG_NONE. They do nothing if va=0v_a = 0. Both use loop if 6na<nv6 n_a < \mathit{nv} and sieve otherwise.

void dlog_vec_loop(ulong * v, ulong nv, ulong a, ulong va, nmod_t mod, ulong na, nmod_t order)
void dlog_vec_loop_add(ulong * v, ulong nv, ulong a, ulong va, nmod_t mod, ulong na, nmod_t order)

As dlog_vec and dlog_vec_add, by enumerating the nan_a powers of aa and copying the values to the entries k≥mk \ge m by periodicity. Costs O(na+nv)O(n_a + \mathit{nv}) and needs no discrete logarithm.

void dlog_vec_sieve(ulong * v, ulong nv, ulong a, ulong va, nmod_t mod, ulong na, nmod_t order)
void dlog_vec_sieve_add(ulong * v, ulong nv, ulong a, ulong va, nmod_t mod, ulong na, nmod_t order)

As dlog_vec and dlog_vec_add, by computing the logarithms of the primes p<min⁡(nv,m)p < \min(\mathit{nv}, m) and extending them to all kk by complete multiplicativity. The logarithms of the primes are computed with a precomputation for 50 queries, except that for primes large enough a relation with smaller numbers is searched first (dlog_vec_pindex_factorgcd). The full index calculus method is not implemented.

void dlog_vec_sieve_precomp(ulong * v, ulong nv, dlog_precomp_t pre, ulong a, ulong va, nmod_t mod, ulong na, nmod_t order)
void dlog_vec_add_precomp(ulong * v, ulong nv, dlog_precomp_t pre, ulong a, ulong va, nmod_t mod, ulong na, nmod_t order)

As dlog_vec_sieve, dlog_vec_sieve_add and dlog_vec_add, with the logarithms of the primes taken from an existing precomputation pre for the base aa.

void dlog_vec_eratos(ulong * v, ulong nv, ulong a, ulong va, nmod_t mod, ulong na, nmod_t order)
void dlog_vec_eratos_add(ulong * v, ulong nv, ulong a, ulong va, nmod_t mod, ulong na, nmod_t order)

As dlog_vec and dlog_vec_add, by computing the logarithm of every prime below min⁡(nv,m)\min(\mathit{nv}, m) with a precomputation and adding it to all multiples of its powers, as in the sieve of Eratosthenes. The add version assumes that the entries not coprime to mm are already DLOG_NONE.

void dlog_vec_fill(ulong * v, ulong nv, ulong x)

Sets v[k]=xv[k] = x for 0≤k<nv0 \le k < \mathit{nv}.

Sets v[k]v[k] to DLOG_NONE for the 0<k<nv0 < k < \mathit{nv} divisible by a prime factor of the modulus.

ulong dlog_vec_pindex_factorgcd(ulong * v, ulong nv, ulong p, nmod_t mod, ulong a, ulong na, ulong loga, ulong logm1, nmod_t order, int maxtry)

Tries to find the logarithm of the prime pp from the logarithms already stored in vv: for i=1,2,…i = 1, 2, \ldots up to maxtry, writes pai≡±r/u(modm)p a^i \equiv \pm r/u \pmod m with r,ur, u about m\sqrt m by a partial extended Euclidean algorithm, and if rr and uu factor over the entries of vv already known (after removing primes below p/4p/4), returns log⁡r−log⁡u−ilog⁡a\log r - \log u - i \log a (adjusted by logm1, the logarithm of −1-1). Here loga is the value to use for log⁡a\log a. Returns DLOG_NOT_FOUND if no relation is found.

Methods#

Each method has a structure, an init function that returns an estimate of the cost of one logarithm, the logarithm function and a clear function. They are used through dlog_precomp_t, but can also be called directly. In all of them aa is the base and bb the argument.

Complete table#

A table of size mod giving the logarithm of every residue (for small moduli only).

Build the table of the logarithms of the powers of aa modulo mod (an array of mod words; aa must be invertible, which is not checked), free it, and look up log⁡a(b)\log_a(b). The cost estimate is 1.

Orders 2 and 3#

The base aa of a group of order at most 3.

Store aa, do nothing, and return 0 if b=1b = 1, 1 if b=ab = a, and 2 otherwise. The cost estimate is 0.

Baby-step giant-step#

A sorted table of mm pairs (k,ak)(k, a^k) (apow_t), for 0≤k<m0 \le k < m, together with a−ma^{-m} and the number of giant steps ⌊n/m⌋+1\lfloor n/m \rfloor + 1.

Initialises tt with the mm baby steps a0,…,am−1a^0, \ldots, a^{m-1} (or nn if m>nm > n), sorted by value, for a base of order nn. Returns the number of giant steps ⌊n/m⌋+1\lfloor n/m \rfloor + 1, the worst-case cost of one logarithm. For kk logarithms, m≈knm \approx \sqrt{kn} minimises the total cost.

Returns the table size used for num logarithms in a group of order nn: (1+⌊n⌋)(1+⌊num⌋)(1 + \lfloor\sqrt n\rfloor)(1 + \lfloor\sqrt{\mathit{num}}\rfloor) if 2 num<n2\,\mathit{num} < n, and nn otherwise.

Free the table, and return log⁡a(b)\log_a(b) by multiplying bb by a−ma^{-m} until the product is found in the table (by binary search). Throws if bb is not a power of aa.

int apow_cmp(const apow_t * x, const apow_t * y)

Comparison function of the pairs (k,ak)(k, a^k) by the value aka^k, for qsort and bsearch.

Pohlig–Hellman decomposition#

For a base aa of composite order n=∏piein = \prod p_i^{e_i}: for each prime power, the cofactor n/piein/p_i^{e_i}, the CRT coefficient and a precomputation in the subgroup of order pieip_i^{e_i}.

Initialise tt for num logarithms to the base aa of order nn modulo mod, by factoring nn and initialising dlog_precomp_pe_init for an/pea^{n/p^e} in each subgroup of prime power order (the returned cost is the sum of their costs); free it; and return log⁡a(b)\log_a(b), combining the logarithms of bn/peb^{n/p^e} by the Chinese remainder theorem.

Prime power order#

For a base aa of order pep^e: the powers a−pka^{-p^k}, 0≤k<e0 \le k < e, and a precomputation in the subgroup of order pp, generated by ape−1a^{p^{e-1}}.

Initialise tt for num logarithms to the base aa of order pep^e (the subgroup precomputation is made for e⋅nume \cdot \mathit{num} logarithms and the cost is ee times its cost); free it; and return log⁡a(b)\log_a(b), found one base-pp digit at a time, each digit a logarithm in the subgroup of order pp.

Prime power modulus#

For the modulus pep^e with a generator aa: a precomputation modulo pp (for odd pp) and the data for logarithms in the subgroup 1+pZ1 + p\mathbb{Z} of elements congruent to 1 modulo pp: (1+p)−1(1 + p)^{-1} and the inverse of the logarithm of ap−1a^{p-1} to the base 1+p1 + p.

Initialise tt for num logarithms to the base aa modulo pe=pe\mathit{pe} = p^e; free it; and return log⁡a(b)\log_a(b), combining the logarithm of b mod pb \bmod p modulo p−1p - 1 with the logarithm of bp−1b^{p-1} in 1+pZ1 + p\mathbb{Z}, which determines log⁡a(b)\log_a(b) modulo pe−1p^{e-1}. For p=2p = 2 the base must be 5 (or a generator of the elements congruent to 1 modulo 4) and b≡1(mod4)b \equiv 1 \pmod 4; this case uses dlog_mod2e.

For odd pp and a1≡1(modp)a_1 \equiv 1 \pmod p generating 1+pZ1 + p\mathbb{Z} modulo pep^e, precompute the inverse of the logarithm of a1a_1 to the base 1+p1 + p (throws if a1=1a_1 = 1 and e>1e > 1), and return the logarithm of b1≡1(modp)b_1 \equiv 1 \pmod p to the base a1a_1, modulo pe−1p^{e-1}.

Returns the logarithm x∈[0,pe−1)x \in [0, p^{e-1}) of b1≡1(modp)b_1 \equiv 1 \pmod p to the base 1+p1 + p modulo pep^e, given inv1p =(1+p)−1 mod pe= (1 + p)^{-1} \bmod p^e, determining one base-pp digit per step. Throws if b1≢1(modp)b_1 \not\equiv 1 \pmod p.

Return the logarithm of b1≡1(mod4)b_1 \equiv 1 \pmod 4 to the base 5 modulo 2e2^e, given inv5 =5−1 mod 2e= 5^{-1} \bmod 2^e, determining one bit per step (throws if b1≢1(mod4)b_1 \not\equiv 1 \pmod 4); and the logarithm for a dlog_modpe_t with p=2p = 2 (for e=2e = 2, whether b≡3(mod4)b \equiv 3 \pmod 4).

Pollard rho#

The data for Pollard's rho method: the base, its order and the modulus.

Initialise tt for the base aa of order nn modulo mod; do nothing; and return log⁡a(b)\log_a(b) with Pollard's rho method [Pol1978], using a random walk with 20 steps and Floyd's cycle detection, in expected time O(n)O(\sqrt n) and constant memory. For composite nn a relation that does not determine the logarithm is completed recursively. This method is not used by dlog_precomp_t.

Internal functions and constants#

Regroups the prime power factors in fac into products not exceeding bound, marking them DLOG_G_SMALL, and multiplies the remaining factors into one marked DLOG_G_BIG. Not used by the library.

Tuning constants: the limits (all 50) below which complete tables or enumeration are used, the limit (500) on the order below which baby-step giant-step is used without decomposition, and the factor (6) in the choice between dlog_vec_loop and dlog_vec_sieve.

References#

Cite this page

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