/*--------------------------------------------------------------------*/ static void build_factor_base(mp_t *n, prime_list_t *prime_list, fb_t **out_fb, uint32 **out_modsqrt, uint32 *out_fb_size, uint32 *out_multiplier) { /* Fills in all the factor base information */ uint32 i, j; fb_t *fb_array, *fbptr; uint32 fb_size = *out_fb_size; uint32 num_primes = prime_list->num_primes; uint32 *modsqrt_array; *out_multiplier = choose_multiplier(n, prime_list, fb_size); mp_mul_1(n, *out_multiplier, n); fb_array = (fb_t *)xmalloc(fb_size * sizeof(fb_t)); modsqrt_array = (uint32 *)xmalloc(fb_size * sizeof(uint32)); fbptr = fb_array + MIN_FB_OFFSET; fbptr->prime = 2; fbptr++; for (i = 1, j = MIN_FB_OFFSET+1; i < num_primes; i++) { uint32 prime = prime_list->list[i]; uint32 nmodp; if (j == fb_size) break; /* if n is a quadratic residue mod 'prime', then 'prime' belongs in the factor base */ nmodp = mp_mod_1(n, prime); if (nmodp == 0 || mp_legendre_1(nmodp, prime) == 1) { fbptr->prime = prime; fbptr->logprime = (uint8)(log((double)prime) / M_LN2 + .5); /* find x such that x^2 mod prime = n mod prime */ if (nmodp != 0) { modsqrt_array[j] = mp_modsqrt_1(nmodp, prime); } fbptr++; j++; } } *out_fb_size = j; *out_fb = fb_array; *out_modsqrt = modsqrt_array; }
static uint8 choose_multiplier(mp_t *n, prime_list_t *prime_list, uint32 fb_size) { uint32 i, j; uint32 num_primes = MIN(2 * fb_size, NUM_TEST_PRIMES); double best_score; uint8 best_mult; double scores[NUM_MULTIPLIERS]; uint32 num_multipliers; double log2n = mp_log(n); num_primes = MIN(num_primes, prime_list->num_primes); /* measure the contribution of 2 as a factor of sieve values. The multiplier itself must also be taken into account in the score. scores[i] is the correction that is implicitly applied to the size of sieve values for multiplier i; a negative score makes sieve values smaller, and so is better */ for (i = 0; i < NUM_MULTIPLIERS; i++) { uint8 curr_mult = mult_list[i]; uint8 knmod8 = (curr_mult * n->val[0]) % 8; double logmult = log((double)curr_mult); /* only consider multipliers k such than k*n will not overflow an mp_t */ if (log2n + logmult > (32 * MAX_MP_WORDS - 2) * M_LN2) break; scores[i] = 0.5 * logmult; switch (knmod8) { case 1: scores[i] -= 2 * M_LN2; break; case 5: scores[i] -= M_LN2; break; case 3: case 7: scores[i] -= 0.5 * M_LN2; break; /* even multipliers start with a handicap */ } } num_multipliers = i; /* for the rest of the small factor base primes */ for (i = 1; i < num_primes; i++) { uint32 prime = prime_list->list[i]; double contrib = log((double)prime) / (prime - 1); uint32 modp = mp_mod_1(n, prime); for (j = 0; j < num_multipliers; j++) { uint8 curr_mult = mult_list[j]; uint32 knmodp = mp_modmul_1(modp, curr_mult, prime); /* if prime i is actually in the factor base for k * n ... */ if (knmodp == 0 || mp_legendre_1(knmodp, prime) == 1) { /* ...add its contribution. A prime p con- tributes log(p) to 1 in p sieve values, plus log(p) to 1 in p^2 sieve values, etc. The average contribution of all multiples of p to a random sieve value is thus log(p) * (1/p + 1/p^2 + 1/p^3 + ...) = (log(p) / p) * 1 / (1 - (1/p)) = log(p) / (p-1) This contribution occurs once for each square root used for sieving. There are two roots for each factor base prime, unless the prime divides k*n. In that case there is only one root */ if (knmodp == 0) scores[j] -= contrib; else scores[j] -= 2 * contrib; } } } /* use the multiplier that generates the best score */ best_score = 1000.0; best_mult = 1; for (i = 0; i < num_multipliers; i++) { double score = scores[i]; if (score < best_score) { best_score = score; best_mult = mult_list[i]; } } return best_mult; }
static inline u_int32_t mp_modsqrt_1(u_int32_t a, u_int32_t p) { u_int32_t a0 = a; if((p & 7) == 3 || (p & 7) == 7) { return mp_expo_1(a0, (p+1)/4, p); } else if((p & 7) == 5) { u_int32_t x, y; if(a0 >= p) a0 = a0 % p; x = mp_expo_1(a0, (p+3)/8, p); if(mp_modmul_1(x, x, p) == a0) return x; y = mp_expo_1(2, (p-1)/4, p); return mp_modmul_1(x, y, p); } else { u_int32_t d0, d1, a1, s, t, m; u_int32_t i; if(a0 == 1) return 1; for(d0 = 2; d0 < p; d0++) { if(mp_legendre_1(d0, p) != -1) continue; t = p - 1; s = 0; while(!(t & 1)) { s++; t = t / 2; } a1 = mp_expo_1(a0, t, p); d1 = mp_expo_1(d0, t, p); for(i = 0, m = 0; i < s; i++) { u_int32_t ad; ad = mp_expo_1(d1, m, p); ad = mp_modmul_1(ad, a1, p); ad = mp_expo_1(ad, (u_int32_t)(1) << (s-1-i), p); if(ad == (p - 1)) m += (1 << i); } a1 = mp_expo_1(a0, (t+1)/2, p); d1 = mp_expo_1(d1, m/2, p); return mp_modmul_1(a1, d1, p); } } printf("modsqrt_1 failed\n"); exit(-1); return 0; }