/* 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 . */ /* Outer wrapper for ECM makes calls to stage I and stage II (one) */ #include #include "flint.h" #include "fmpz.h" #include "mpn_extras.h" static ulong n_ecm_primorial[] = { #ifdef FLINT64 UWORD(2), UWORD(6), UWORD(30), UWORD(210), UWORD(2310), UWORD(30030), UWORD(510510), UWORD(9699690), UWORD(223092870), UWORD(6469693230), UWORD(200560490130), UWORD(7420738134810), UWORD(304250263527210), UWORD(13082761331670030), UWORD(614889782588491410) /* 15 values */ #else UWORD(2), UWORD(6), UWORD(30), UWORD(210), UWORD(2310), UWORD(30030), UWORD(510510), UWORD(9699690) /* 9 values */ #endif }; #ifdef FLINT64 #define num_n_ecm_primorials 15 #else #define num_n_ecm_primorials 9 #endif int fmpz_factor_ecm(fmpz_t f, mp_limb_t curves, mp_limb_t B1, mp_limb_t B2, flint_rand_t state, const fmpz_t n_in) { fmpz_t sig, nm8; mp_limb_t P, num, maxP, mmin, mmax, mdiff, prod, maxj, n_size, cy; int i, j, ret; ecm_t ecm_inf; __mpz_struct *fac, *mpz_ptr; mp_ptr n, mpsig; TMP_INIT; const mp_limb_t *prime_array; n_size = fmpz_size(n_in); if (n_size == 1) { ret = n_factor_ecm(&P, curves, B1, B2, state, fmpz_get_ui(n_in)); fmpz_set_ui(f, P); return ret; } fmpz_factor_ecm_init(ecm_inf, n_size); TMP_START; n = TMP_ALLOC(n_size * sizeof(mp_limb_t)); mpsig = TMP_ALLOC(n_size * sizeof(mp_limb_t)); if ((!COEFF_IS_MPZ(* n_in))) { count_leading_zeros(ecm_inf->normbits, fmpz_get_ui(n_in)); n[0] = fmpz_get_ui(n_in); n[0] <<= ecm_inf->normbits; } else { mpz_ptr = COEFF_TO_PTR(* n_in); count_leading_zeros(ecm_inf->normbits, mpz_ptr->_mp_d[n_size - 1]); if (ecm_inf->normbits) mpn_lshift(n, mpz_ptr->_mp_d, n_size, ecm_inf->normbits); else flint_mpn_copyi(n, mpz_ptr->_mp_d, n_size); } flint_mpn_preinvn(ecm_inf->ninv, n, n_size); ecm_inf->one[0] = UWORD(1) << ecm_inf->normbits; fmpz_init(sig); fmpz_init(nm8); fmpz_sub_ui(nm8, n_in, 8); ret = 0; fac = _fmpz_promote(f); mpz_realloc(fac, fmpz_size(n_in)); /************************ STAGE I PRECOMPUTATIONS ************************/ num = n_prime_pi(B1); /* number of primes under B1 */ /* compute list of primes under B1 for stage I */ prime_array = n_primes_arr_readonly(num); /************************ STAGE II PRECOMPUTATIONS ***********************/ maxP = n_sqrt(B2); /* Selecting primorial */ j = 1; while ((j < num_n_ecm_primorials) && (n_ecm_primorial[j] < maxP)) j += 1; P = n_ecm_primorial[j - 1]; mmin = (B1 + (P/2)) / P; mmax = ((B2 - P/2) + P - 1)/P; /* ceil */ if (mmax < mmin) { flint_printf("Exception (ecm). B1 > B2 encountered.\n"); flint_abort(); } maxj = (P + 1)/2; mdiff = mmax - mmin + 1; /* compute GCD_table */ ecm_inf->GCD_table = flint_malloc(maxj + 1); for (j = 1; j <= maxj; j += 2) { if ((j%2) && n_gcd(j, P) == 1) ecm_inf->GCD_table[j] = 1; else ecm_inf->GCD_table[j] = 0; } /* compute prime table */ ecm_inf->prime_table = flint_malloc(mdiff * sizeof(unsigned char*)); for (i = 0; i < mdiff; i++) ecm_inf->prime_table[i] = flint_malloc((maxj + 1) * sizeof(unsigned char)); for (i = 0; i < mdiff; i++) { for (j = 1; j <= maxj; j += 2) { ecm_inf->prime_table[i][j] = 0; /* if (i + mmin)*P + j is prime, mark 1. Can be possibly prime only if gcd(j, P) = 1 */ if (ecm_inf->GCD_table[j] == 1) { prod = (i + mmin)*P + j; if (n_is_prime(prod)) ecm_inf->prime_table[i][j] = 1; prod = (i + mmin)*P - j; if (n_is_prime(prod)) ecm_inf->prime_table[i][j] = 1; } } } /****************************** TRY "CURVES" *****************************/ for (j = 0; j < curves; j++) { fmpz_randm(sig, state, nm8); fmpz_add_ui(sig, sig, 7); mpn_zero(mpsig, ecm_inf->n_size); if ((!COEFF_IS_MPZ(*sig))) { mpsig[0] = fmpz_get_ui(sig); if (ecm_inf->normbits) { cy = mpn_lshift(mpsig, mpsig, 1, ecm_inf->normbits); if (cy) mpsig[1] = cy; } } else { mpz_ptr = COEFF_TO_PTR(*sig); if (ecm_inf->normbits) { cy = mpn_lshift(mpsig, mpz_ptr->_mp_d, mpz_ptr->_mp_size, ecm_inf->normbits); if (cy) mpsig[mpz_ptr->_mp_size] = cy; } else { flint_mpn_copyi(mpsig, mpz_ptr->_mp_d, mpz_ptr->_mp_size); } } /************************ SELECT CURVE ************************/ ret = fmpz_factor_ecm_select_curve(fac->_mp_d, mpsig, n, ecm_inf); if (ret) { /* Found factor while selecting curve, very very lucky :) */ if (ecm_inf->normbits) mpn_rshift(fac->_mp_d, fac->_mp_d, ret, ecm_inf->normbits); MPN_NORM(fac->_mp_d, ret); fac->_mp_size = ret; _fmpz_demote_val(f); ret = -1; goto cleanup; } if (ret != -1) { /************************** STAGE I ***************************/ ret = fmpz_factor_ecm_stage_I(fac->_mp_d, prime_array, num, B1, n, ecm_inf); if (ret) { /* Found factor after stage I */ if (ecm_inf->normbits) mpn_rshift(fac->_mp_d, fac->_mp_d, ret, ecm_inf->normbits); MPN_NORM(fac->_mp_d, ret); fac->_mp_size = ret; _fmpz_demote_val(f); ret = 1; goto cleanup; } /************************** STAGE II ***************************/ ret = fmpz_factor_ecm_stage_II(fac->_mp_d, B1, B2, P, n, ecm_inf); if (ret) { /* Found factor after stage II */ if (ecm_inf->normbits) mpn_rshift(fac->_mp_d, fac->_mp_d, ret, ecm_inf->normbits); MPN_NORM(fac->_mp_d, ret); fac->_mp_size = ret; _fmpz_demote_val(f); ret = 2; goto cleanup; } } } cleanup: flint_free(ecm_inf->GCD_table); for (i = 0; i < mdiff; i++) flint_free(ecm_inf->prime_table[i]); flint_free(ecm_inf->prime_table); fmpz_factor_ecm_clear(ecm_inf); fmpz_clear(nm8); fmpz_clear(sig); TMP_END; return ret; }