/*--------------------------------------------------------------------*/ 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 void get_zeros_rec(u_int32_t *zeros, u_int32_t shift, u_int32_t *num_zeros, poly_t f, u_int32_t p) { /* get the zeros of a poly, f, that is known to split completely over Z/pZ. Many thanks to Bob Silverman for a neat implementation of Cantor-Zassenhaus splitting */ poly_t g, xpow; u_int32_t degree1, degree2; /* base cases of the recursion: we can find the roots of linear and quadratic polynomials immediately */ if (f->degree == 1) { u_int32_t w = f->coef[1]; if (w != 1) { w = mp_modinv_1(w, p); zeros[(*num_zeros)++] = mp_modmul_1(p - f->coef[0],w,p); } else { zeros[(*num_zeros)++] = (f->coef[0] == 0 ? 0 : p - f->coef[0]); } return; } else if (f->degree == 2) { /* if f is a quadratic polynomial, then it will always have two distinct nonzero roots or else we wouldn't have gotten to this point. The two roots are the solution of a general quadratic equation, mod p */ u_int32_t d = mp_modmul_1(f->coef[0], f->coef[2], p); u_int32_t root1 = p - f->coef[1]; u_int32_t root2 = root1; u_int32_t ainv = mp_modinv_1( mp_modadd_1(f->coef[2], f->coef[2], p), p); d = mp_modsub_1(mp_modmul_1(f->coef[1], f->coef[1], p), mp_modmul_1(4, d, p), p); d = mp_modsqrt_1(d, p); root1 = mp_modadd_1(root1, d, p); root2 = mp_modsub_1(root2, d, p); zeros[(*num_zeros)++] = mp_modmul_1(root1, ainv, p); zeros[(*num_zeros)++] = mp_modmul_1(root2, ainv, p); return; } /* For an increasing sequence of integers 's', compute the polynomial gcd((x-s)^(p-1)/2 - 1, f). If the result is not g = 1 or g = f, this is a nontrivial splitting of f. References require choosing s randomly, but however s is chosen there is a 50% chance that it will split f. Since only 0 <= s < p is valid, we choose each s in turn; choosing random s allows the possibility that the same s gets chosen twice (mod p), which would waste time */ while (shift < p) { poly_xpow(xpow, shift, (p-1)/2, f, p); poly_cp(g, xpow); g->coef[0] = mp_modsub_1(g->coef[0], 1, p); poly_fix_degree(g); poly_gcd(g, f, p); if (g->degree > 0) break; shift++; } /* f was split; repeat the splitting process on the two halves of f. The linear factors of f are either somewhere in x^((p-1)/2) - 1, in x^((p-1)/2) + 1, or 'shift' itself is a linear factor. Test each of these possibilities in turn. In the first two cases, begin trying values of s strictly greater than have been tried thus far */ degree1 = g->degree; get_zeros_rec(zeros, shift + 1, num_zeros, g, p); poly_cp(g, xpow); g->coef[0] = mp_modadd_1(g->coef[0], 1, p); poly_fix_degree(g); poly_gcd(g, f, p); degree2 = g->degree; if (degree2 > 0) get_zeros_rec(zeros, shift + 1, num_zeros, g, p); if (degree1 + degree2 < f->degree) zeros[(*num_zeros)++] = (shift == 0 ? 0 : p - shift); }