286 lines
8.4 KiB
C
286 lines
8.4 KiB
C
|
/*=============================================================================
|
||
|
|
||
|
This file is part of FLINT.
|
||
|
|
||
|
FLINT is free software; you can redistribute it and/or modify
|
||
|
it under the terms of the GNU General Public License as published by
|
||
|
the Free Software Foundation; either version 2 of the License, or
|
||
|
(at your option) any later version.
|
||
|
|
||
|
FLINT is distributed in the hope that it will be useful,
|
||
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||
|
GNU General Public License for more details.
|
||
|
|
||
|
You should have received a copy of the GNU General Public License
|
||
|
along with FLINT; if not, write to the Free Software
|
||
|
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||
|
|
||
|
=============================================================================*/
|
||
|
/******************************************************************************
|
||
|
|
||
|
Copyright (C) 2006, 2011 William Hart
|
||
|
|
||
|
******************************************************************************/
|
||
|
|
||
|
#define ulong ulongxx /* interferes with system includes */
|
||
|
#include <stdio.h>
|
||
|
#undef ulong
|
||
|
#define ulong mp_limb_t
|
||
|
|
||
|
#include <gmp.h>
|
||
|
#include "flint.h"
|
||
|
#include "ulong_extras.h"
|
||
|
#include "qsieve.h"
|
||
|
#include "fmpz.h"
|
||
|
|
||
|
/*
|
||
|
Factor n = (hi, lo). Returns a factor of n.
|
||
|
Assumes n is not prime and not a perfect power.
|
||
|
Returns 0 if n is too large to be factored by this function.
|
||
|
*/
|
||
|
mp_limb_t qsieve_ll_factor(mp_limb_t hi, mp_limb_t lo)
|
||
|
{
|
||
|
qs_t qs_inf;
|
||
|
mp_limb_t factor = 0, t;
|
||
|
slong rels_found = 0;
|
||
|
char * sieve;
|
||
|
slong ncols, nrows, i, count;
|
||
|
uint64_t * nullrows;
|
||
|
uint64_t mask;
|
||
|
flint_rand_t state;
|
||
|
fmpz_t X, Y;
|
||
|
|
||
|
/************************************************************************
|
||
|
INITIALISATION:
|
||
|
|
||
|
Initialise the qs_t structure.
|
||
|
************************************************************************/
|
||
|
#if QS_DEBUG
|
||
|
flint_printf("\nStart:\n");
|
||
|
#endif
|
||
|
|
||
|
qsieve_ll_init(qs_inf, hi, lo);
|
||
|
|
||
|
#if QS_DEBUG /* print some diagnostic information */
|
||
|
{
|
||
|
mpz_t _n;
|
||
|
mpz_init(_n);
|
||
|
flint_mpz_set_ui(_n, hi);
|
||
|
mpz_mul_2exp(_n, _n, FLINT_BITS);
|
||
|
flint_mpz_add_ui(_n, _n, lo);
|
||
|
gmp_printf("Factoring %Zd of %wd bits\n", _n, qs_inf->bits);
|
||
|
mpz_clear(_n);
|
||
|
}
|
||
|
#endif
|
||
|
|
||
|
/************************************************************************
|
||
|
KNUTH SCHROEPPEL:
|
||
|
|
||
|
Try to compute a multiplier k such that there are a lot of small primes
|
||
|
which are quadratic residues modulo kn. If a small factor of n is found
|
||
|
during this process it is returned.
|
||
|
************************************************************************/
|
||
|
#if QS_DEBUG
|
||
|
flint_printf("\nKnuth-Schroeppel:\n");
|
||
|
#endif
|
||
|
|
||
|
factor = qsieve_ll_knuth_schroeppel(qs_inf);
|
||
|
if (factor)
|
||
|
{
|
||
|
#if QS_DEBUG
|
||
|
flint_printf("Found small factor %wd in Knuth-Schroeppel\n", factor);
|
||
|
#endif
|
||
|
qsieve_ll_clear(qs_inf);
|
||
|
return factor;
|
||
|
}
|
||
|
|
||
|
/* compute kn */
|
||
|
fmpz_set_ui(qs_inf->kn, hi);
|
||
|
fmpz_mul_2exp(qs_inf->kn, qs_inf->kn, FLINT_BITS);
|
||
|
fmpz_add_ui(qs_inf->kn, qs_inf->kn, lo);
|
||
|
fmpz_mul_ui(qs_inf->kn, qs_inf->kn, qs_inf->k);
|
||
|
|
||
|
/* refine qs_inf->bits */
|
||
|
qs_inf->bits = fmpz_bits(qs_inf->kn);
|
||
|
if (qs_inf->bits > 2*FLINT_BITS)
|
||
|
{
|
||
|
qsieve_ll_clear(qs_inf);
|
||
|
return 0; /* kn is too large to factor */
|
||
|
}
|
||
|
|
||
|
/************************************************************************
|
||
|
COMPUTE FACTOR BASE:
|
||
|
|
||
|
Try to compute a multiplier k such that there are a lot of small primes
|
||
|
which are quadratic residues modulo kn. If a small factor of n is found
|
||
|
during this process it is returned.
|
||
|
************************************************************************/
|
||
|
#if QS_DEBUG
|
||
|
flint_printf("\nCompute factor base:\n");
|
||
|
#endif
|
||
|
|
||
|
/* compute factor base primes and associated data*/
|
||
|
factor = qsieve_ll_primes_init(qs_inf);
|
||
|
if (factor)
|
||
|
{
|
||
|
#if QS_DEBUG
|
||
|
flint_printf("Found small factor %wd whilst generating factor base\n", factor);
|
||
|
#endif
|
||
|
qsieve_ll_clear(qs_inf);
|
||
|
return factor;
|
||
|
}
|
||
|
|
||
|
/************************************************************************
|
||
|
INITIALISE POLYNOMIAL DATA:
|
||
|
|
||
|
Create space for all the polynomial information
|
||
|
************************************************************************/
|
||
|
#if QS_DEBUG
|
||
|
flint_printf("\nInitialise poly:\n");
|
||
|
#endif
|
||
|
|
||
|
/* set (hi, lo) to kn */
|
||
|
umul_ppmm(t, lo, lo, qs_inf->k);
|
||
|
hi = hi*qs_inf->k + t;
|
||
|
qs_inf->hi = hi;
|
||
|
qs_inf->lo = lo;
|
||
|
|
||
|
qsieve_ll_poly_init(qs_inf);
|
||
|
|
||
|
/************************************************************************
|
||
|
INITIALISE RELATION/LINAXYXYXYXY DATA:
|
||
|
|
||
|
Create space for all the relations and matrix information
|
||
|
************************************************************************/
|
||
|
#if QS_DEBUG
|
||
|
flint_printf("\nInitialise relations and linear algebra:\n");
|
||
|
#endif
|
||
|
|
||
|
qsieve_ll_linalg_init(qs_inf);
|
||
|
|
||
|
/************************************************************************
|
||
|
SIEVE:
|
||
|
|
||
|
Sieve for relations
|
||
|
************************************************************************/
|
||
|
#if QS_DEBUG
|
||
|
flint_printf("\nSieve:\n");
|
||
|
#endif
|
||
|
|
||
|
sieve = flint_malloc(qs_inf->sieve_size + sizeof(ulong));
|
||
|
|
||
|
while (rels_found < qs_inf->num_primes + qs_inf->extra_rels)
|
||
|
{
|
||
|
rels_found += qsieve_ll_collect_relations(qs_inf, sieve);
|
||
|
|
||
|
#if (QS_DEBUG & 128)
|
||
|
flint_printf("%wd/%wd relations.\n", rels_found, qs_inf->num_primes + qs_inf->extra_rels);
|
||
|
#endif
|
||
|
}
|
||
|
|
||
|
flint_free(sieve);
|
||
|
|
||
|
/************************************************************************
|
||
|
REDUCE MATRIX:
|
||
|
|
||
|
Perform some light filtering on the matrix
|
||
|
************************************************************************/
|
||
|
|
||
|
ncols = qs_inf->num_primes + qs_inf->extra_rels;
|
||
|
nrows = qs_inf->num_primes;
|
||
|
|
||
|
#if QS_DEBUG
|
||
|
flint_printf("Reduce matrix:\n");
|
||
|
#endif
|
||
|
|
||
|
reduce_matrix(qs_inf, &nrows, &ncols, qs_inf->matrix);
|
||
|
|
||
|
/************************************************************************
|
||
|
BLOCK LANCZOS:
|
||
|
|
||
|
Find extra_rels nullspace vectors (if they exist)
|
||
|
************************************************************************/
|
||
|
|
||
|
#if QS_DEBUG
|
||
|
flint_printf("Block lanczos:\n");
|
||
|
#endif
|
||
|
|
||
|
flint_randinit(state); /* initialise the random generator */
|
||
|
|
||
|
do /* repeat block lanczos until it succeeds */
|
||
|
{
|
||
|
nullrows = block_lanczos(state, nrows, 0, ncols, qs_inf->matrix);
|
||
|
} while (nullrows == NULL);
|
||
|
|
||
|
for (i = 0, mask = 0; i < ncols; i++) /* create mask of nullspace vectors */
|
||
|
mask |= nullrows[i];
|
||
|
|
||
|
for (i = count = 0; i < 64; i++) /* count nullspace vectors found */
|
||
|
{
|
||
|
if (mask & ((uint64_t)(1) << i))
|
||
|
count++;
|
||
|
}
|
||
|
|
||
|
flint_randclear(state); /* clean up random state */
|
||
|
|
||
|
#if QS_DEBUG
|
||
|
flint_printf("%wd nullspace vectors found\n", count);
|
||
|
#endif
|
||
|
|
||
|
/************************************************************************
|
||
|
SQUARE ROOT:
|
||
|
|
||
|
Compute the square root and take the GCD of X-Y with N
|
||
|
************************************************************************/
|
||
|
|
||
|
#if QS_DEBUG
|
||
|
flint_printf("Square root:\n");
|
||
|
#endif
|
||
|
|
||
|
fmpz_fdiv_q_ui(qs_inf->kn, qs_inf->kn, qs_inf->k); /* divide kn by multiplier */
|
||
|
|
||
|
fmpz_init(X);
|
||
|
fmpz_init(Y);
|
||
|
|
||
|
for (count = 0; count < 64; count++)
|
||
|
{
|
||
|
if (mask & ((uint64_t)(1) << count))
|
||
|
{
|
||
|
qsieve_ll_square_root(X, Y, qs_inf, nullrows, ncols, count, qs_inf->kn);
|
||
|
fmpz_sub(X, X, Y);
|
||
|
fmpz_gcd(X, X, qs_inf->kn);
|
||
|
|
||
|
if (fmpz_cmp(X, qs_inf->kn) != 0 && fmpz_cmp_ui(X, 1) != 0) /* have a factor */
|
||
|
{
|
||
|
if (fmpz_size(X)!= 1)
|
||
|
fmpz_fdiv_q(X, qs_inf->kn, X); /* take smaller of two factors */
|
||
|
factor = fmpz_get_ui(X);
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
fmpz_clear(X);
|
||
|
fmpz_clear(Y);
|
||
|
flint_free(nullrows);
|
||
|
|
||
|
/************************************************************************
|
||
|
CLEAN UP:
|
||
|
|
||
|
Free all used memory
|
||
|
************************************************************************/
|
||
|
|
||
|
#if QS_DEBUG
|
||
|
flint_printf("\nClean up:\n");
|
||
|
#endif
|
||
|
|
||
|
qsieve_ll_clear(qs_inf);
|
||
|
|
||
|
#if QS_DEBUG
|
||
|
flint_printf("\nDone.\n");
|
||
|
#endif
|
||
|
|
||
|
return factor;
|
||
|
}
|