Discrete logarithms modulo a multiprecision prime
#include <flint/fmpz_mod.h>void fmpz_mod_discrete_log_pohlig_hellman_init(fmpz_mod_discrete_log_pohlig_hellman_t L)sourcevoid fmpz_mod_discrete_log_pohlig_hellman_clear(fmpz_mod_discrete_log_pohlig_hellman_t L)sourceInitialise L, which is not ready for computation until fmpz_mod_discrete_log_pohlig_hellman_precompute_prime is called, and free the memory used by L.
double fmpz_mod_discrete_log_pohlig_hellman_precompute_prime(fmpz_mod_discrete_log_pohlig_hellman_t L, const fmpz_t p)sourceConfigures L for logarithms modulo to the base of the least primitive root modulo , and returns an estimate of the number of multiplications modulo that one call of fmpz_mod_discrete_log_pohlig_hellman_run needs. must be prime, which is not checked.
This factors (with fmpz_factor) and throws an exception if a prime factor does not fit in a word. The cost of the precomputation is dominated by this factorisation, and the tables for each prime factor have at most 100 entries.
const fmpz * fmpz_mod_discrete_log_pohlig_hellman_primitive_root(fmpz_mod_discrete_log_pohlig_hellman_t L)sourceReturns a pointer to the primitive root used as the base of the logarithms.
void fmpz_mod_discrete_log_pohlig_hellman_run(fmpz_t x, const fmpz_mod_discrete_log_pohlig_hellman_t L, const fmpz_t y)sourceSets to the logarithm of to the base , the integer with . must be reduced modulo and nonzero (not checked); if no logarithm is found, which can only happen for invalid input, an exception is thrown.
Sets to a prime for which is smooth and returns 1, or sets to 0 and returns 0 if there is none. Such primes are suitable for fmpz_mod_discrete_log_pohlig_hellman_precompute_prime.
The primes come from a fixed table of primes with : four to eleven primes in every interval for (the least is 33857), and twelve each in and . The function returns the least table entry greater than , which need not be the least prime with this property (for it is a prime above ), and returns 0 for beyond the last entry, about . The exact set of primes should not be relied upon.
These functions solve for a prime of any size and a fixed primitive root , by the method of Pohlig and Hellman [PohHel1978]: the logarithm is computed modulo each prime power dividing , one base- digit at a time with Shanks' baby-step giant-step search in the subgroup of order , and the results are combined by the Chinese remainder theorem. This is fast when every prime factor of is small; the cost grows like for the largest . The method and its analysis are described in Discrete logarithms modulo a prime (Pohlig–Hellman); the word-size version is nmod_discrete_log_pohlig_hellman_run.
Usage#
- Initialise an
fmpz_mod_discrete_log_pohlig_hellman_twithfmpz_mod_discrete_log_pohlig_hellman_init. - Call
fmpz_mod_discrete_log_pohlig_hellman_precompute_primewith the prime . It factors , finds the least primitive root , whichfmpz_mod_discrete_log_pohlig_hellman_primitive_rootreturns, and precomputes the tables. The return value estimates the number of multiplications modulo per logarithm, which a caller can use to decide whether is suitable. - Call
fmpz_mod_discrete_log_pohlig_hellman_runfor each nonzero residue ; the result is the logarithm in . The precomputed object is not modified, so several threads may share it. - Free the memory with
fmpz_mod_discrete_log_pohlig_hellman_clear.
The function does not check that is prime or that is nonzero and reduced. The precomputation throws an exception if has a prime factor that does not fit in a word, and the search throws one if it finds no logarithm, which can only happen for invalid input. The factorisation of dominates the precomputation unless is known to be smooth; fmpz_next_smooth_prime provides primes for which it is, with a product of powers of 2, 5, 7, 11, 13, 17, 19 and 23.
The tables for a prime have at most 100 entries: a giant step is about for below about and is doubled until the table is small enough for larger , so the number of baby steps grows from to about for large .
Example#
The program takes the next smooth prime after (a 128-bit prime; the table of smooth primes has no entries between and ), computes a power of the primitive root and recovers the exponent.
#include <flint/fmpz.h>
#include <flint/fmpz_mod.h>
int main(void)
{
fmpz_t p, x, y, e;
fmpz_mod_ctx_t ctx;
fmpz_mod_discrete_log_pohlig_hellman_t L;
double cost;
fmpz_init(p);
fmpz_init(x);
fmpz_init(y);
fmpz_init(e);
/* a prime p > 10^30 with p - 1 smooth */
fmpz_set_str(x, "1000000000000000000000000000000", 10);
if (!fmpz_next_smooth_prime(p, x))
return 1;
printf("p = "); fmpz_print(p); printf("\n");
fmpz_mod_discrete_log_pohlig_hellman_init(L);
cost = fmpz_mod_discrete_log_pohlig_hellman_precompute_prime(L, p);
printf("base = ");
fmpz_print(fmpz_mod_discrete_log_pohlig_hellman_primitive_root(L));
printf(", cost estimate %s 2000\n", cost < 2000 ? "<" : ">=");
/* y = base^e mod p, then recover e */
fmpz_mod_ctx_init(ctx, p);
fmpz_set_str(e, "123456789012345678901234567890", 10);
fmpz_mod_pow_fmpz(y, fmpz_mod_discrete_log_pohlig_hellman_primitive_root(L), e, ctx);
fmpz_mod_discrete_log_pohlig_hellman_run(x, L, y);
printf("log = "); fmpz_print(x); printf("\n");
fmpz_mod_ctx_clear(ctx);
fmpz_mod_discrete_log_pohlig_hellman_clear(L);
fmpz_clear(p);
fmpz_clear(x);
fmpz_clear(y);
fmpz_clear(e);
return 0;
}p = 201315753943344863644036821430284967937 base = 3, cost estimate < 2000 log = 123456789012345678901234567890
References#
- [PohHel1978] S. C. Pohlig and M. E. Hellman, "An improved algorithm for computing logarithms over GF(p) and its cryptographic significance", IEEE Transactions on Information Theory 24 (1978), 106–110, https://doi.org/10.1109/TIT.1978.1055817
The FLINT team, “Discrete logarithms modulo a multiprecision prime (fmpz_mod.h),” FLINT: Fast Library for Number Theory, documentation, version 3.7.0-dev, 2026. https://flintlib.org/doc/fmpz_mod/discrete-log.html (generated 2026-11-02).
@misc{flint-doc-fmpz-mod-discrete-log,
author = {{The FLINT team}},
title = {{Discrete logarithms modulo a multiprecision prime (fmpz\_mod.h)}},
howpublished = {FLINT: Fast Library for Number Theory, documentation, version 3.7.0-dev},
year = {2026},
url = {https://flintlib.org/doc/fmpz_mod/discrete-log.html},
note = {Generated 2026-11-02}
}