int verify_bernoulli_mod_p(unsigned long *res, unsigned long p) { unsigned long N, i, product, sum, value, element; double p_inv; N = (p-1)/2; product = 1; sum = 0; p_inv = z_precompute_inverse(p); for(i = 0; i < N; i++) { element = res[i]; value = z_mulmod_precomp(z_mulmod_precomp(product, 2*i+1, p, p_inv), element, p, p_inv); sum = z_mod_precomp(sum + value, p, p_inv); product = z_mulmod_precomp(product, 4, p, p_inv); } if(z_mod_precomp(sum + 2, p, p_inv)) { return FALSE; } return TRUE; }
unsigned long compute_factor_base(QS_t * qs_inf) { unsigned long fb_prime = 2; unsigned long multiplier = qs_inf->k; prime_t * factor_base = qs_inf->factor_base; uint32_t * sqrts = qs_inf->sqrts; unsigned long num_primes = num_FB_primes(qs_inf->bits); unsigned long prime, nmod; double pinv; fmpz_t n = qs_inf->n; long kron; factor_base[0].p = multiplier; factor_base[0].pinv = z_precompute_inverse(multiplier); factor_base[1].p = 2; prime = 2; while (fb_prime < num_primes) { prime = z_nextprime(prime, 0); pinv = z_precompute_inverse(prime); nmod = mpn_mod_1(n + 1, n[0], prime); if (nmod == 0) { if (z_mod_precomp(multiplier, prime, pinv) != 0) return prime; } kron = z_jacobi(nmod, prime); if (kron == 1) { factor_base[fb_prime].p = prime; factor_base[fb_prime].pinv = pinv; sqrts[fb_prime] = z_sqrtmod(nmod, prime); fb_prime++; } } printf("Largest prime = %ld\n", prime); qs_inf->num_primes = fb_prime; return 0; }
void compute_B_terms(QS_t * qs_inf, poly_t * poly_inf) { unsigned long s = poly_inf->s; unsigned long * A_ind = poly_inf->A_ind; unsigned long * A_modp = poly_inf->A_modp; unsigned long * B_terms = poly_inf->B_terms; prime_t * factor_base = qs_inf->factor_base; unsigned long limbs = qs_inf->prec+1; unsigned long limbs2; unsigned long * A = poly_inf->A; unsigned long * B = poly_inf->B; unsigned long p, i; unsigned long * temp1 = (unsigned long *) flint_stack_alloc(limbs); unsigned long temp; mp_limb_t msl; double pinv; for (i = 0; i < s; i++) { p = factor_base[A_ind[i]].p; pinv = z_precompute_inverse(p); mpn_divmod_1(temp1 + 1, A + 1, A[0], p); temp1[0] = A[0] - (temp1[A[0]] == 0); A_modp[i] = (temp = mpn_mod_1(temp1 + 1, temp1[0], p)); temp = z_invert(temp, p); temp = z_mulmod_precomp(temp, qs_inf->sqrts[A_ind[i]], p, pinv); if (temp > p/2) temp = p - temp; msl = mpn_mul_1(B_terms + i*limbs + 1, temp1 + 1, temp1[0], temp); if (msl) { B_terms[i*limbs + temp1[0] + 1] = msl; B_terms[i*limbs] = temp1[0] + 1; } else B_terms[i*limbs] = temp1[0]; #if B_TERMS mpz_t temp; mpz_init(temp); fmpz_to_mpz(temp, B_terms + i*limbs); gmp_printf("B_%ld = %Zd\n", i, temp); mpz_clear(temp); #endif } F_mpn_copy(B, B_terms, B_terms[0]+1); // Set B to the sum of the B terms if (limbs > B_terms[0] + 1) F_mpn_clear(B + B_terms[0] + 1, limbs - B_terms[0] - 1); for (i = 1; i < s; i++) { limbs2 = B_terms[i*limbs]; msl = mpn_add_n(B+1, B+1, B_terms + i*limbs + 1, limbs2); if (msl) mpn_add_1(B + limbs2 + 1, B + limbs2 + 1, limbs - limbs2 - 1, msl); } B[0] = limbs - 1; while (!B[B[0]] && B[0]) B[0]--; #if B_TERMS mpz_t temp2; mpz_init(temp2); fmpz_to_mpz(temp2, B); gmp_printf("B = %Zd\n", temp2); mpz_clear(temp2); #endif flint_stack_release(); // release temp1 }
int bernoulli_mod_p_mpz(unsigned long *res, unsigned long p) { FLINT_ASSERT(p > 2); FLINT_ASSERT(z_isprime(p) == 1); unsigned long g, g_inv, g_sqr, g_sqr_inv; double p_inv = z_precompute_inverse(p); g = z_primitive_root(p); if(!g) { return FALSE; } g_inv = z_invert(g, p); g_sqr = z_mulmod_precomp(g, g, p, p_inv); g_sqr_inv = z_mulmod_precomp(g_inv, g_inv, p, p_inv); unsigned long poly_size = (p-1)/2; int is_odd = poly_size % 2; unsigned long g_power, g_power_inv; g_power = g_inv; g_power_inv = 1; // constant is (g-1)/2 mod p unsigned long constant; if(g % 2) { constant = (g-1)/2; } else { constant = (g+p-1)/2; } // fudge holds g^{i^2}, fudge_inv holds g^{-i^2} unsigned long fudge, fudge_inv; fudge = fudge_inv = 1; // compute the polynomials F(X) and G(X) mpz_poly_t F, G; mpz_poly_init2(F, poly_size); mpz_poly_init2(G, poly_size); unsigned long i, temp, h; for(i = 0; i < poly_size; i++) { // compute h(g^i)/g^i (h(x) is as in latex notes) temp = g * g_power; h = z_mulmod_precomp(p + constant - (temp / p), g_power_inv, p, p_inv); g_power = z_mod_precomp(temp, p, p_inv); g_power_inv = z_mulmod_precomp(g_power_inv, g_inv, p, p_inv); // store coefficient g^{i^2} h(g^i)/g^i mpz_poly_set_coeff_ui(G, i, z_mulmod_precomp(h, fudge, p, p_inv)); mpz_poly_set_coeff_ui(F, i, fudge_inv); // update fudge and fudge_inv fudge = z_mulmod_precomp(z_mulmod_precomp(fudge, g_power, p, p_inv), z_mulmod_precomp(g_power, g, p, p_inv), p, p_inv); fudge_inv = z_mulmod_precomp(z_mulmod_precomp(fudge_inv, g_power_inv, p, p_inv), z_mulmod_precomp(g_power_inv, g, p, p_inv), p, p_inv); } mpz_poly_set_coeff_ui(F, 0, 0); // step 2: multiply the polynomials... mpz_poly_t product; mpz_poly_init(product); mpz_poly_mul(product, G, F); // step 3: assemble the result... unsigned long g_sqr_power, value; g_sqr_power = g_sqr; fudge = g; res[0] = 1; mpz_t value_coeff; mpz_init(value_coeff); unsigned long value_coeff_ui; for(i = 1; i < poly_size; i++) { mpz_poly_get_coeff(value_coeff, product, i + poly_size); value = mpz_fdiv_ui(value_coeff, p); value = z_mod_precomp(mpz_poly_get_coeff_ui(product, i + poly_size), p, p_inv); mpz_poly_get_coeff(value_coeff, product, i); if(is_odd) { value = z_mod_precomp(mpz_poly_get_coeff_ui(G, i) + mpz_fdiv_ui(value_coeff, p) + p - value, p, p_inv); } else { value = z_mod_precomp(mpz_poly_get_coeff_ui(G, i) + mpz_fdiv_ui(value_coeff, p) + value, p, p_inv); } value = z_mulmod_precomp(z_mulmod_precomp(z_mulmod_precomp(4, i, p, p_inv), fudge, p, p_inv), value, p, p_inv); value = z_mulmod_precomp(value, z_invert(p+1-g_sqr_power, p), p, p_inv); res[i] = value; g_sqr_power = z_mulmod_precomp(g_sqr_power, g, p, p_inv); fudge = z_mulmod_precomp(fudge, g_sqr_power, p, p_inv); g_sqr_power = z_mulmod_precomp(g_sqr_power, g, p, p_inv); } mpz_clear(value_coeff); mpz_poly_clear(F); mpz_poly_clear(G); mpz_poly_clear(product); return TRUE; }
unsigned long knuth_schroeppel(QS_t * qs_inf) { float best_factor = -10.0f; unsigned long multiplier = 1; unsigned long nmod8, mod8, multindex, prime, nmod, mult; const unsigned long max_fb_primes = qs_inf->num_primes; unsigned long fb_prime = 2; // leave space for the multiplier and 2 float factors[NUMMULTS]; float logpdivp; double pinv; int kron; uint32_t * sqrts = qs_inf->sqrts; fmpz_t n = qs_inf->n; nmod8 = n[1]%8; mpz_t r; for (multindex = 0; multindex < NUMMULTS; multindex++) { mod8 = ((nmod8*multipliers[multindex])%8); factors[multindex] = 0.34657359; // ln2/2 if (mod8 == 1) factors[multindex] *= 4.0; if (mod8 == 5) factors[multindex] *= 2.0; factors[multindex] -= (log((float) multipliers[multindex]) / 2.0); } prime = 3; while (prime < KSMAX)// && (fb_prime < max_fb_primes)) { pinv = z_precompute_inverse(prime); logpdivp = log((float)prime) / (float)prime; // log p / p nmod = mpn_mod_1(n + 1, n[0], prime); if (nmod == 0) return prime; kron = z_jacobi(nmod, prime); for (multindex = 0; multindex < NUMMULTS; multindex++) { mult = multipliers[multindex]; if (mult >= prime) { if (mult >= prime*prime) mult = mult%prime; else mult = z_mod_precomp(mult, prime, pinv); } if (mult == 0) factors[multindex] += logpdivp; else if (kron*z_jacobi(mult, prime) == 1) factors[multindex] += 2.0*logpdivp; } prime = z_nextprime(prime, 0); } for (multindex=0; multindex<NUMMULTS; multindex++) { if (factors[multindex] > best_factor) { best_factor = factors[multindex]; multiplier = multipliers[multindex]; } } qs_inf->k = multiplier; return 0; }
void tiny_compute_A(QS_t * qs_inf, poly_t * poly_inf) { unsigned long min = poly_inf->min; unsigned long span = poly_inf->span; unsigned long s = poly_inf->s; unsigned long * A_ind = poly_inf->A_ind; prime_t * factor_base = qs_inf->factor_base; unsigned long factor, i, p; unsigned long diff, best_diff, best1, best2; unsigned long A; if (s <= 4) { A_ind[0] = z_randint(span) + min; do { A_ind[1] = z_randint(span) + min; } while (A_ind[0] == A_ind[1]); } if (s == 2) A = factor_base[A_ind[0]].p * factor_base[A_ind[1]].p; if ((s == 3) || (s == 4)) { do { A_ind[2] = z_randint(span) + min; } while ((A_ind[0] == A_ind[2]) || (A_ind[1] == A_ind[2])); A = factor_base[A_ind[0]].p * factor_base[A_ind[1]].p * factor_base[A_ind[2]].p; } if (s == 4) { factor = (poly_inf->target_A - 1) / A + 1; for (i = min; i < min+span; i++) { if ((factor_base[i].p > factor) && (i != A_ind[0]) && (i != A_ind[1]) && (i != A_ind[2])) break; } if (i == min + span) { i--; while ((i == A_ind[0]) || (i == A_ind[1]) || (i == A_ind[2])) i--; } A_ind[3] = i; A *= factor_base[A_ind[3]].p; } if (s == 5) { A_ind[0] = ((z_randint(span) + min) | 1); if (A_ind[0] == min + span) A_ind[0] -= 2; do { A_ind[1] = ((z_randint(span) + min) | 1); if (A_ind[1] == min + span) A_ind[1] -= 2; } while (A_ind[0] == A_ind[1]); do { A_ind[2] = ((z_randint(span) + min) | 1); if (A_ind[2] == min + span) A_ind[2] -= 2; } while ((A_ind[0] == A_ind[2]) || (A_ind[1] == A_ind[2])); A = factor_base[A_ind[0]].p * factor_base[A_ind[1]].p * factor_base[A_ind[2]].p; factor = poly_inf->target_A / A; for (i = 0; i < 8; i++) { A_ind[3] = ((z_randint(span) + min) & -2L); if (A_ind[3] < min) A_ind[3]+=2; do { A_ind[4] = ((z_randint(span) + min) & -2L); if (A_ind[4] < min) A_ind[4]+=2; } while (A_ind[3] == A_ind[4]); if (i == 0) { best_diff = FLINT_ABS(factor_base[A_ind[3]].p * factor_base[A_ind[4]].p - factor); best1 = A_ind[3]; best2 = A_ind[4]; continue; } diff = FLINT_ABS(factor_base[A_ind[3]].p * factor_base[A_ind[4]].p - factor); if (diff < best_diff) { best_diff = diff; best1 = A_ind[3]; best2 = A_ind[4]; } } A_ind[3] = best1; A_ind[4] = best2; A = A * factor_base[A_ind[3]].p * factor_base[A_ind[4]].p; } poly_inf->A = A; #if POLY_A if ((s == 4) || (s == 5)) printf("A = %ld, target A = %ld\n", A, poly_inf->target_A); #endif for (i = 0; i < s; i++) { p = factor_base[A_ind[i]].p; poly_inf->inv_p2[i] = z_precompute_inverse(p*p); } }