int isPrime(z *n) { // translate into gmp's test mpz_t gmpz; int i; mpz_init(gmpz); mp2gmp(n, gmpz); i = is_mpz_prp(gmpz); mpz_clear(gmpz); return (i > 0); }
/*-------------------------------------------------------------------*/ static void relation_to_poly(abpair_t *abpair, mp_t *c, gmp_poly_t *poly) { /* given a and b in abpair, along with c, compute poly(x) = a*c - b*x */ mp2gmp(c, poly->coeff[0]); int64_2gmp(abpair->a, poly->coeff[1]); mpz_mul(poly->coeff[0], poly->coeff[0], poly->coeff[1]); mpz_set_ui(poly->coeff[1], (unsigned long)abpair->b); poly->degree = 0; if (abpair->b > 0) { poly->degree = 1; mpz_neg(poly->coeff[1], poly->coeff[1]); } }
/*------------------------------------------------------------------*/ static void relation_to_gmp(relation_batch_t *rb, uint32 index, mpz_t out) { /* multiply together the unfactored parts of an NFS relation, then convert to an mpz_t */ uint32 i, nwords; cofactor_t *c = rb->relations + index; uint32 *f = rb->factors + c->factor_list_word + c->num_factors_r + c->num_factors_a; mp_t num1, num2, num3; if (c->lp_r_num_words > 1 && c->lp_a_num_words > 1) { /* rational and algebraic parts need to be multiplied together first */ mp_clear(&num1); mp_clear(&num2); num1.nwords = c->lp_r_num_words; for (i = 0; i < c->lp_r_num_words; i++) num1.val[i] = f[i]; num2.nwords = c->lp_a_num_words; f += c->lp_r_num_words; for (i = 0; i < c->lp_a_num_words; i++) num2.val[i] = f[i]; mp_mul(&num1, &num2, &num3); } else { /* no multiply necesary */ mp_clear(&num3); nwords = c->lp_r_num_words; if (c->lp_a_num_words > 1) { nwords = c->lp_a_num_words; f += c->lp_r_num_words; } num3.nwords = nwords; for (i = 0; i < nwords; i++) num3.val[i] = f[i]; } mp2gmp(&num3, out); }
/*-------------------------------------------------------------------*/ static void convert_to_integer(gmp_poly_t *alg_sqrt, mp_t *n, mp_t *c, signed_mp_t *m1, signed_mp_t *m0, mp_t *res) { /* given the completed square root, apply the homomorphism to convert the polynomial to an integer. We do this by evaluating alg_sqrt at c*m0/m1, with all calculations performed mod n */ uint32 i; mpz_t gmp_n; mp_t m1_pow; mp_t m1_tmp; mp_t m0_tmp; mp_t next_coeff; mpz_init(gmp_n); mp2gmp(n, gmp_n); gmp_poly_mod_q(alg_sqrt, gmp_n, alg_sqrt); mpz_clear(gmp_n); mp_copy(&m1->num, &m1_tmp); if (m1->sign == NEGATIVE) mp_sub(n, &m1_tmp, &m1_tmp); mp_copy(&m1_tmp, &m1_pow); mp_modmul(&m0->num, c, n, &m0_tmp); if (m0->sign == POSITIVE) mp_sub(n, &m0_tmp, &m0_tmp); i = alg_sqrt->degree; gmp2mp(alg_sqrt->coeff[i], res); for (i--; (int32)i >= 0; i--) { mp_modmul(res, &m0_tmp, n, res); gmp2mp(alg_sqrt->coeff[i], &next_coeff); mp_modmul(&next_coeff, &m1_pow, n, &next_coeff); mp_add(res, &next_coeff, res); if (i > 0) mp_modmul(&m1_pow, &m1_tmp, n, &m1_pow); } if (mp_cmp(res, n) > 0) mp_sub(res, n, res); }
/*-------------------------------------------------------------------*/ void alg_square_root(msieve_obj *obj, mp_poly_t *mp_alg_poly, mp_t *n, mp_t *c, signed_mp_t *m1, signed_mp_t *m0, abpair_t *rlist, uint32 num_relations, uint32 check_q, mp_t *sqrt_a) { /* external interface for computing the algebraic square root */ uint32 i; gmp_poly_t alg_poly; gmp_poly_t d_alg_poly; gmp_poly_t prod; gmp_poly_t alg_sqrt; relation_prod_t prodinfo; double log2_prodsize; mpz_t q; /* initialize */ mpz_init(q); gmp_poly_init(&alg_poly); gmp_poly_init(&d_alg_poly); gmp_poly_init(&prod); gmp_poly_init(&alg_sqrt); /* convert the algebraic poly to arbitrary precision */ for (i = 0; i < mp_alg_poly->degree; i++) { signed_mp_t *coeff = mp_alg_poly->coeff + i; mp2gmp(&coeff->num, alg_poly.coeff[i]); if (coeff->sign == NEGATIVE) mpz_neg(alg_poly.coeff[i], alg_poly.coeff[i]); } alg_poly.degree = mp_alg_poly->degree - 1; /* multiply all the relations together */ prodinfo.monic_poly = &alg_poly; prodinfo.rlist = rlist; prodinfo.c = c; logprintf(obj, "multiplying %u relations\n", num_relations); multiply_relations(&prodinfo, 0, num_relations - 1, &prod); logprintf(obj, "multiply complete, coefficients have about " "%3.2lf million bits\n", (double)mpz_sizeinbase(prod.coeff[0], 2) / 1e6); /* perform a sanity check on the result */ i = verify_product(&prod, rlist, num_relations, check_q, c, mp_alg_poly); free(rlist); if (i == 0) { logprintf(obj, "error: relation product is incorrect\n"); goto finished; } /* multiply by the square of the derivative of alg_poly; this will guarantee that the square root of prod actually is an element of the number field defined by alg_poly. If we didn't do this, we run the risk of the main Newton iteration not converging */ gmp_poly_monic_derivative(&alg_poly, &d_alg_poly); gmp_poly_mul(&d_alg_poly, &d_alg_poly, &alg_poly, 0); gmp_poly_mul(&prod, &d_alg_poly, &alg_poly, 1); /* pick the initial small prime to start the Newton iteration. To save both time and memory, choose an initial prime such that squaring it a large number of times will produce a value just a little larger than we need to calculate the square root. Note that contrary to what some authors write, pretty much any starting prime is okay. The Newton iteration has a division by 2, so that 2 must be invertible mod the prime (this is guaranteed for odd primes). Also, the Newton iteration will fail if both square roots have the same value mod the prime; however, even a 16-bit prime makes this very unlikely */ i = mpz_size(prod.coeff[0]); log2_prodsize = (double)GMP_LIMB_BITS * (i - 2) + log(mpz_getlimbn(prod.coeff[0], (mp_size_t)(i-1)) * pow(2.0, (double)GMP_LIMB_BITS) + mpz_getlimbn(prod.coeff[0], (mp_size_t)(i-2))) / M_LN2 + 10000; while (log2_prodsize > 31.5) log2_prodsize *= 0.5; mpz_set_d(q, (uint32)pow(2.0, log2_prodsize) + 1); /* get the initial inverse square root */ if (!get_initial_inv_sqrt(obj, mp_alg_poly, &prod, &alg_sqrt, q)) { goto finished; } /* compute the actual square root */ if (get_final_sqrt(obj, &alg_poly, &prod, &alg_sqrt, q)) convert_to_integer(&alg_sqrt, n, c, m1, m0, sqrt_a); finished: gmp_poly_clear(&prod); gmp_poly_clear(&alg_sqrt); gmp_poly_clear(&alg_poly); gmp_poly_clear(&d_alg_poly); mpz_clear(q); }
uint32 ecm_pp1_pm1(msieve_obj *obj, mp_t *n, mp_t *reduced_n, factor_list_t *factor_list) { uint32 i, j, max_digits; uint32 bits; mpz_t gmp_n, gmp_factor; pm1_pp1_t non_ecm_vals[NUM_NON_ECM]; uint32 factor_found = 0; uint32 num_trivial = 0; ecm_params params; /* factorization will continue until any remaining composite cofactors are smaller than the cutoff for using other methods */ /* initialize */ mpz_init(gmp_n); mpz_init(gmp_factor); for (i = 0; i < NUM_NON_ECM; i++) { pm1_pp1_t *tmp = non_ecm_vals + i; tmp->stage_1_done = 1.0; mpz_init_set_ui(tmp->start_val, (unsigned long)0); } ecm_init(params); gmp_randseed_ui(params->rng, get_rand(&obj->seed1, &obj->seed2)); mp2gmp(n, gmp_n); max_digits = choose_max_digits(obj, mp_bits(n)); /* for each digit level */ for (i = 0; i < NUM_TABLE_ENTRIES; i++) { const work_t *curr_work = work_table + i; uint32 log_rate, next_log; int status; if (curr_work->digits > max_digits) break; logprintf(obj, "searching for %u-digit factors\n", curr_work->digits); /* perform P-1. Stage 1 runs much faster for this algorithm than it does for ECM, so crank up the stage 1 bound We save the stage 1 output to reduce the work at the next digit level */ for (j = 0; j < NUM_PM1_TRIALS; j++) { pm1_pp1_t *tmp = non_ecm_vals + j; params->method = ECM_PM1; params->B1done = tmp->stage_1_done; mpz_set(params->x, tmp->start_val); status = ecm_factor(gmp_factor, gmp_n, 10 * curr_work->stage_1_bound, params); tmp->stage_1_done = params->B1done; mpz_set(tmp->start_val, params->x); HANDLE_FACTOR_FOUND("P-1"); } /* perform P+1. Stage 1 runs somewhat faster for this algorithm than it does for ECM, so crank up the stage 1 bound We save the stage 1 output to reduce the work at the next digit level */ for (j = 0; j < NUM_PP1_TRIALS; j++) { pm1_pp1_t *tmp = non_ecm_vals + NUM_PM1_TRIALS + j; params->method = ECM_PP1; params->B1done = tmp->stage_1_done; mpz_set(params->x, tmp->start_val); status = ecm_factor(gmp_factor, gmp_n, 5 * curr_work->stage_1_bound, params); tmp->stage_1_done = params->B1done; mpz_set(tmp->start_val, params->x); HANDLE_FACTOR_FOUND("P+1"); } /* run the specified number of ECM curves. Because so many curves could be necessary, just start each one from scratch */ log_rate = 0; if (obj->flags & (MSIEVE_FLAG_USE_LOGFILE | MSIEVE_FLAG_LOG_TO_STDOUT)) { if (curr_work->digits >= 35) log_rate = 1; else if (curr_work->digits >= 30) log_rate = 5; else if (curr_work->digits >= 25) log_rate = 20; } next_log = log_rate; for (j = 0; j < curr_work->num_ecm_trials; j++) { params->method = ECM_ECM; params->B1done = 1.0; mpz_set_ui(params->x, (unsigned long)0); mpz_set_ui(params->sigma, (unsigned long)0); status = ecm_factor(gmp_factor, gmp_n, curr_work->stage_1_bound, params); HANDLE_FACTOR_FOUND("ECM"); if (log_rate && j == next_log) { next_log += log_rate; fprintf(stderr, "%u of %u curves\r", j, curr_work->num_ecm_trials); fflush(stderr); } } if (log_rate) fprintf(stderr, "\ncompleted %u ECM curves\n", j); } clean_up: ecm_clear(params); gmp2mp(gmp_n, reduced_n); mpz_clear(gmp_n); mpz_clear(gmp_factor); for (i = 0; i < NUM_NON_ECM; i++) mpz_clear(non_ecm_vals[i].start_val); return factor_found; }