wiki

Cantor–Zassenhaus algorithm

The Cantor–Zassenhaus algorithm factors polynomials over a finite field by a randomized, divide-and-conquer method[1]. It works in three stages. Square-free factorization removes repeated factors. Distinct-degree factorization separates the remaining irreducible factors into groups of equal degree, by taking gcds with . Equal-degree factorization splits each group: for a random polynomial , the gcd of the group with collects a random subset of its irreducible factors, and repeating on the pieces separates all of them in an expected logarithmic number of rounds. David Cantor and Hans Zassenhaus published the method in 1981[1], building on Berlekamp's randomized algorithm and Rabin's work on probabilistic algorithms in finite fields[2][7]. Factoring over finite fields is the first step of factoring over the integers by Hensel lifting.

§ 01

Distinct-degree factorization

Over , the polynomial is the product of all monic irreducible polynomials whose degree divides , because its roots are exactly the elements of . For a square-free , the gcd of with is therefore the product of its linear factors; removing them and taking the gcd with gives the product of its quadratic factors, and so on[3]. The powers are computed by repeated -th powering modulo , never expanding itself.

§ 02

Equal-degree factorization

Let be a product of distinct monic irreducibles of degree , with odd. By the Chinese remainder theorem,

In a finite field of odd order , the power is 1 for the nonzero squares, for the non-squares and 0 for 0, and half of the nonzero elements are squares. For a random of degree less than , the components of are independent and each is with probability close to . The gcd of with is the product of the whose component is 1[1][3].

aᵉ in 𝔽ₚ[x]/(f) ≅ 𝔽(q) × 𝔽(q) × 𝔽(q) × 𝔽(q), q = pᵈ, e = (q − 1)/2mod f₁+1mod f₂−1mod f₃+1mod f₄−1gcd(f, aᵉ − 1) = f₁ f₃the components where aᵉ = 1 are exactly the factors of the gcd
Under the Chinese remainder isomorphism, the power of a random element is +1 in some components and −1 in others. The gcd with that power minus 1 picks out the factors where it is +1.

The split is nontrivial unless all components agree, which happens with probability about . The pieces are split recursively with fresh random elements until each is irreducible. For , the power is replaced by the trace map , which takes each value in half the time[3].

Distinct-degree factorization and Cantor–Zassenhaus splitting over F_p for odd p.

(* Factoring a square-free polynomial over F_p, p an odd prime:
distinct-degree factorization, then Cantor–Zassenhaus equal-degree
splitting. *)
open Modp
(* Split f into products of the irreducible factors of each degree d,
using gcd(f, x^(p^d) - x). *)
let distinct_degree p f =
let rec go f xp d acc =
if deg f < 2 * d then (if deg f > 0 then (deg f, monic p f) :: acc else acc)
else begin
let xp = powmod p xp p f in (* x^(p^d) mod f *)
let g = gcd p f (sub p xp [| 0; 1 |]) in
if deg g > 0 then go (fst (divmod p f g)) (rem p xp (fst (divmod p f g))) (d + 1) ((d, g) :: acc)
else go f xp (d + 1) acc
end
in
List.rev (go (monic p f) [| 0; 1 |] 1 [])
let attempts = ref 0
(* f is a product of irreducibles of degree d. A random a gives
a^((p^d - 1)/2) = +1 or -1 in each factor's field independently, so
gcd(f, a^((p^d-1)/2) - 1) splits f with probability about 1/2. *)
let rec equal_degree p d f =
if deg f <= d then [ monic p f ]
else begin
incr attempts;
let a = norm (Array.init (deg f) (fun _ -> Random.int p)) in
let pd = Z.pow (Z.of_int p) d in
let exponent = Z.div (Z.sub pd Z.one) (Z.of_int 2) in
let rec powz acc b n = if Z.equal n Z.zero then acc
else powz (if Z.is_odd n then rem p (mul p acc b) f else acc) (rem p (mul p b b) f) (Z.shift_right n 1) in
let b = powz [| 1 |] (rem p a f) exponent in
let g = gcd p f (sub p b [| 1 |]) in
if deg g > 0 && deg g < deg f then equal_degree p d g @ equal_degree p d (fst (divmod p f g))
else equal_degree p d f
end
let factor p f =
List.concat_map (fun (d, g) -> equal_degree p d g) (distinct_degree p f)

Factoring x¹⁵ − 1 over two prime fields.

(* Factor x^15 - 1 over F_31 and over F_101, showing the degree groups
produced by distinct-degree factorization. *)

Running it.

x^15 - 1 over F_31
degree-1 part: x^15 + 30
15 factors, 21 random trials: (x + 26) (x + 13) (x + 15) (x + 6) (x + 11) (x + 21) (x + 24) (x + 12) (x + 3) (x + 27) (x + 17) (x + 30) (x + 29) (x + 22) (x + 23)
x^15 - 1 over F_101
degree-1 part: x^5 + 100
degree-2 part: x^10 + x^5 + 1
10 factors, 12 random trials: (x + 100) (x + 17) (x + 14) (x + 6) (x + 65) (x^2 + 87x + 95) (x^2 + x + 1) (x^2 + 36x + 84) (x^2 + 95x + 36) (x^2 + 84x + 87)

Both results agree with SymPy. The degrees of the factors are determined by arithmetic: a root of unity of order lies in exactly when . Since , all fifteen roots are in ; since but , over the fifth roots are linear and the other ten roots pair into quadratics.

Measuring how often a single random element splits a product of r irreducible quadratics over F₁₀₀₀₇.

(* How often does one random element split a product of r irreducible
quadratics over F_10007? A split fails when all r components agree. *)
let p = 10007
let random_irreducible d =
let rec try_ () =
let f = Modp.norm (Array.init (d + 1) (fun i -> if i = d then 1 else Random.int p)) in
if List.length (Cz.factor p f) = 1 then f else try_ () in
try_ ()

Running it.

r splits per 1000 trials predicted 1 - 2^(1-r)
2 517 500
3 777 750
4 865 875
6 959 969
8 996 992
§ 03

Cost

The dominant cost is computing powers and , each needing multiplications of polynomials of degree less than . With classical arithmetic the whole algorithm takes expected operations in up to logarithmic factors. Von zur Gathen and Shoup reduced the cost of the Frobenius powers with modular composition[5], Kaltofen and Shoup obtained subquadratic exponents in [4], and Kedlaya and Umans a nearly optimal exponent of [6]. Shoup's NTL implementation made factoring polynomials of degree in the thousands routine[8].

§ 04

Comparison with Berlekamp's algorithm

Berlekamp's algorithm solves a linear system to find the subalgebra of fixed by the Frobenius map, whose dimension is the number of factors, and splits with gcds of its elements[2]. Its linear algebra is cubic in the degree. Cantor–Zassenhaus avoids the matrix and replaces it with powering, which is simpler and parallels the probabilistic version of Berlekamp's own method for large fields. For small , Berlekamp's deterministic algorithm remains competitive; for large , no deterministic polynomial-time algorithm is known, and randomization is essential.

§ 05

History

Berlekamp gave the first practical factoring algorithm for finite fields in 1967 and a randomized variant for large fields in 1970[2]. Rabin analyzed probabilistic algorithms for finding roots and irreducible factors in 1980[7]. Cantor and Zassenhaus's paper of 1981 combined distinct-degree factorization with the equal-degree splitting now named after them[1]. The asymptotically faster algorithms of von zur Gathen, Kaltofen, Shoup, Kedlaya and Umans followed between 1992 and 2011[5][4][6].

see also

further reading

  1. [1]D. G. Cantor, H. Zassenhaus, “A new algorithm for factoring polynomials over finite fields”, Mathematics of Computation 36 (1981).
  2. [2]E. R. Berlekamp, “Factoring polynomials over large finite fields”, Mathematics of Computation 24 (1970).
  3. [3]J. von zur Gathen, J. Gerhard, Modern Computer Algebra, ch. 14, Cambridge University Press (3rd ed., 2013).
  4. [4]E. Kaltofen, V. Shoup, “Subquadratic-time factoring of polynomials over finite fields”, Mathematics of Computation 67 (1998).
  5. [5]J. von zur Gathen, V. Shoup, “Computing Frobenius maps and factoring polynomials”, Computational Complexity 2 (1992).
  6. [6]K. S. Kedlaya, C. Umans, “Fast polynomial factorization and modular composition”, SIAM Journal on Computing 40 (2011).
  7. [7]M. O. Rabin, “Probabilistic algorithms in finite fields”, SIAM Journal on Computing 9 (1980).
  8. [8]V. Shoup, “A new polynomial factorization algorithm and its implementation”, Journal of Symbolic Computation 20 (1995).

last updated