/*
Copyright (C) 2015 Kushagra Singh
This file is part of FLINT.
FLINT is free software: you can redistribute it and/or modify it under
the terms of the GNU Lesser General Public License (LGPL) as published
by the Free Software Foundation; either version 2.1 of the License, or
(at your option) any later version. See .
*/
#include
#include "flint.h"
#include "ulong_extras.h"
mp_limb_t
n_sqr_and_add_a(mp_limb_t y, mp_limb_t a, mp_limb_t n, mp_limb_t ninv,
mp_limb_t normbits)
{
mp_limb_t hi, lo;
y = n_mulmod_preinv(y, y, n, ninv, normbits);
add_ssaaaa(hi, lo, UWORD(0), y, UWORD(0), a);
if (hi == 0)
{
y = lo;
if (y > n)
y -= n;
}
else
sub_ddmmss(hi, y, hi, lo, 0, n);
return y;
}
int
n_factor_pollard_brent_single(mp_limb_t *factor, mp_limb_t n, mp_limb_t ninv,
mp_limb_t ai, mp_limb_t xi, mp_limb_t normbits,
mp_limb_t max_iters)
{
mp_limb_t iter, i, k, j, minval, m, one_shift_norm, x, y, a, q, ys, subval;
int ret;
if (n < 4)
return 0;
/* one shifted by normbits, used for comparisions */
one_shift_norm = UWORD(1) << normbits;
q = one_shift_norm;
(*factor) = one_shift_norm;
y = xi;
a = ai;
m = 100;
iter = 1;
do {
x = y;
k = 0;
for (i = 0; i < iter; i++)
y = n_sqr_and_add_a(y, a, n, ninv, normbits);
do {
minval = iter - k;
if (m < minval)
minval = m;
ys = y;
for (i = 0; i < minval; i++)
{
y = n_sqr_and_add_a(y, a, n, ninv, normbits);
if (x > y)
subval = x - y;
else
subval = y - x;
q = n_mulmod_preinv(q, subval, n, ninv, normbits);
}
if (q == 0)
(*factor) = n;
else
(*factor) = n_gcd(q, n);
k += m;
j = ((*factor) == one_shift_norm);
} while ((k < iter) && (j));
if (iter > max_iters)
break;
iter *= 2;
} while (j);
if ((*factor) == n)
{
do {
ys = n_sqr_and_add_a(ys, a, n, ninv, normbits);
if (x > ys)
subval = x - ys;
else
subval = ys - x;
if (q == 0)
(*factor) = n;
else
(*factor) = n_gcd(q, n);
(*factor) = n_gcd(subval, n);
} while ((*factor) == one_shift_norm); /* gcd == 1 */
}
ret = 1;
if ((*factor) == one_shift_norm) /* gcd == 1 */
ret = 0;
else if ((*factor) == n) /* gcd == n*/
ret = 0;
return ret;
}
int
n_factor_pollard_brent(mp_limb_t *factor, flint_rand_t state, mp_limb_t n_in,
mp_limb_t max_tries, mp_limb_t max_iters)
{
mp_limb_t normbits, a, x, n, ninv, max;
int ret;
ret = 0;
max = n_in -3; /* 1 <= a <= n - 3 */
count_leading_zeros(normbits, n_in);
n = n_in;
n <<= normbits;
ninv = n_preinvert_limb(n);
while (max_tries--)
{
a = n_randint(state, max);
a += 1;
max += 1; /* 1 <= x <= n - 1 */
x = n_randint(state, max);
x += 1;
a <<= normbits;
x <<= normbits;
ret = n_factor_pollard_brent_single(factor, n, ninv, a, x, normbits, max_iters);
if (ret == 1)
{
if (normbits)
(*factor) >>= normbits;
return 1;
}
}
return ret;
}