FLINT3.7.0-dev

Precomputed discrete logarithms

Synopsis#include <flint/dlog.h>
void dlog_precomp_n_init(dlog_precomp_t pre, ulong a, ulong mod, ulong n, ulong num)source

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.

void dlog_precomp_p_init(dlog_precomp_t pre, ulong a, ulong mod, ulong p, ulong num)source

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.

void dlog_precomp_pe_init(dlog_precomp_t pre, ulong a, ulong mod, ulong p, ulong e, ulong pe, ulong num)source

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).

void dlog_precomp_modpe_init(dlog_precomp_t pre, ulong a, ulong p, ulong e, ulong pe, ulong num)source

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.

void dlog_precomp_small_init(dlog_precomp_t pre, ulong a, ulong mod, ulong n, ulong num)source

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).

ulong dlog_precomp(const dlog_precomp_t pre, ulong b)source

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

void dlog_precomp_clear(dlog_precomp_t pre)source

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

A dlog_precomp_t holds the data for computing many discrete logarithms to a fixed base aa modulo a word-size mm. It is initialised with the base, the modulus, what is known about the order of aa, and the expected number num of logarithms; then each call to dlog_precomp returns one logarithm, and dlog_precomp_clear frees the data. The choice of the initialisation function tells the module what it may assume:

FunctionAssumption
dlog_precomp_n_init(pre, a, mod, n, num)aa has order nn modulo mod
dlog_precomp_p_init(pre, a, mod, p, num)aa has prime order pp
dlog_precomp_pe_init(pre, a, mod, p, e, pe, num)aa has order pe=pe\mathit{pe} = p^e
dlog_precomp_modpe_init(pre, a, p, e, pe, num)aa is a primitive root modulo pe=pe\mathit{pe} = p^e
dlog_precomp_small_init(pre, a, mod, n, num)the order nn is small: tabulate everything

The order must be exact and the modulus a word; neither is checked. dlog_precomp_n_init factors nn when it is large, so passing a known structure saves that work and lets the function pick the best method.

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.

Cost and memory#

The precomputation is sized for num queries. In a group of prime order p≥50p \ge 50 it stores a baby-step giant-step table of about p⋅num\sqrt{p \cdot \mathit{num}} entries (16 bytes each), and each query costs about p/num\sqrt{p/\mathit{num}} multiplications and binary searches. For num≥p/2\mathit{num} \ge p/2 the whole group is tabulated and a query is one search. For composite orders the work is split over the prime factors by the Pohlig–Hellman decomposition, so a logarithm in (Z/pZ)×(\mathbb{Z}/p\mathbb{Z})^\times with smooth p−1p - 1 is cheap, and for prime powers pep^e the logarithm reduces to one modulo pp plus O(e)O(e) modular powers. The field pre->cost estimates the number of multiplications of one query.

For a single logarithm use dlog_once, and for the logarithms of all integers below a bound dlog_vec, which sieves with the logarithms of the primes.

Example#

The program computes 1000 logarithms modulo the prime 106+310^6 + 3, whose group order p−1=2⋅3⋅166667p - 1 = 2 \cdot 3 \cdot 166667 is decomposed (type DLOG_CRT), one logarithm modulo 757^5 with the pp-adic method, and the logarithms to the base 2 of the integers below 12 modulo 13 with dlog_vec.

Exampledlog_precomp_basic.cchecked by make checkdoc
#include <flint/flint.h>
#include <flint/ulong_extras.h>
#include <flint/nmod.h>
#include <flint/dlog.h>

int main(void)
{
    dlog_precomp_t pre;
    nmod_t mod, order;
    ulong p = 1000003, g, b, x, k;
    ulong v[12];
    int ok = 1;

    g = n_primitive_root_prime(p);
    nmod_init(&mod, p);

    /* tables for about 1000 logarithms in a group of order p - 1 */
    dlog_precomp_n_init(pre, g, p, p - 1, 1000);
    for (k = 1; k <= 1000; k++)
    {
        b = nmod_pow_ui(k, 3, mod);
        x = dlog_precomp(pre, b);
        ok = ok && (nmod_pow_ui(g, x, mod) == b);
    }
    flint_printf("g = %wu, CRT: %d, cost %wu, 1000 logarithms ok: %d\n",
        g, pre->type == DLOG_CRT, pre->cost, ok);
    dlog_precomp_clear(pre);

    /* modulus 7^5 with the primitive root 3 */
    dlog_precomp_modpe_init(pre, 3, 7, 5, 16807, 10);
    x = dlog_precomp(pre, 2);
    nmod_init(&mod, 16807);
    flint_printf("log_3(2) mod 7^5 = %wu, 3^%wu = %wu\n",
        x, x, nmod_pow_ui(3, x, mod));
    dlog_precomp_clear(pre);

    /* logarithms of 0, ..., 11 modulo 13 to the base 2, of order 12 */
    nmod_init(&mod, 13);
    nmod_init(&order, 12);
    dlog_vec(v, 12, 2, 1, mod, 12, order);
    flint_printf("log_2 mod 13:");
    for (k = 0; k < 12; k++)
    {
        if (v[k] == DLOG_NONE)
            flint_printf(" -");
        else
            flint_printf(" %wu", v[k]);
    }
    flint_printf("\n");
    return 0;
}
Output
g = 2, CRT: 1, cost 13, 1000 logarithms ok: 1
log_3(2) mod 7^5 = 9308, 3^9308 = 2
log_2 mod 13: - 0 1 4 2 9 5 11 3 8 10 7
Cite this page

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