int main(void) { DIGIT_T x, y, g; DIGIT_T m, e, n, c, z, t; DIGIT_T p, v, u, w, a, q; int res, i, ntries; DIGIT_T primes32[] = { 5, 17, 65, 99 }; DIGIT_T primes16[] = { 15, 17, 39 }; /* Test greatest common divisor (gcd) */ printf("Test spGcd:\n"); /* simple one */ x = 15; y = 27; g = spGcd(x, y); printf("gcd(%" PRIuBIGD ", %" PRIuBIGD ") = %" PRIuBIGD "\n", x, y, g); assert(g == 3); /* contrived using small primes */ x = 53 * 37; y = 53 * 83; g = spGcd(x, y); printf("gcd(%" PRIuBIGD ", %" PRIuBIGD ") = %" PRIuBIGD "\n", x, y, g); assert(g == 53); /* contrived using bigger primes */ x = 0x0345 * 0xfedc; y = 0xfedc * 0x0871; g = spGcd(x, y); printf("gcd(0x%" PRIxBIGD ", 0x%" PRIxBIGD ") = 0x%" PRIxBIGD "\n", x, y, g); assert(g == 0xfedc); /* Known primes: 2^16-15, 2^32-5 */ y = 0x10000 - 15; x = spSimpleRand(1, y); g = spGcd(x, y); printf("gcd(0x%" PRIxBIGD ", 0x%" PRIxBIGD ") = %" PRIxBIGD "\n", x, y, g); assert(g == 1); y = 0xffffffff - 5 + 1; x = spSimpleRand(1, y); g = spGcd(x, y); printf("gcd(0x%" PRIxBIGD ", 0x%" PRIxBIGD ") = %" PRIxBIGD "\n", x, y, g); assert(g == 1); /* Test spModExp */ printf("Test spModExp:\n"); /* Verify that (m^e mod n).(z^e mod n) == (m.z)^e mod n for random m, e, n, z */ /* Generate some random numbers */ n = spSimpleRand(MAX_DIGIT / 2, MAX_DIGIT); m = spSimpleRand(1, n -1); e = spSimpleRand(1, n -1); z = spSimpleRand(1, n -1); /* Compute c = m^e mod n */ spModExp(&c, m, e, n); printf("c=m^e mod n=%" PRIxBIGD "^%" PRIxBIGD " mod %" PRIxBIGD "=%" PRIxBIGD "\n", m, e, n, c); /* Compute x = c.z^e mod n */ printf("z=%" PRIxBIGD "\n", z); spModExp(&t, z, e, n); spModMult(&x, c, t, n); printf("x = c.z^e mod n = %" PRIxBIGD "\n", x); /* Compute y = (m.z)^e mod n */ spModMult(&t, m, z, n); spModExp(&y, t, e, n); printf("y = (m.z)^e mod n = %" PRIxBIGD "\n", x); /* Check they are equal */ assert(x == y); /* Test spModInv */ printf("Test spModInv:\n"); /* Use identity that (vp-1)^-1 mod p = p-1 for prime p and integer v */ /* known prime */ p = 0x10000 - 15; /* small multiplier */ v = spSimpleRand(2, 10); u = v * p - 1; printf("u = vp-1 = %" PRIuBIGD " * %" PRIuBIGD " - 1 = %" PRIuBIGD "\n", v, p, u); /* compute w = u^-1 mod p */ spModInv(&w, u, p); printf("w = u^-1 mod p = %" PRIuBIGD "\n", w); /* check wu mod p == 1 */ spModMult(&c, w, u, p); printf("Check 1 == wu mod p = %" PRIuBIGD "\n", c); assert(c == 1); /* Try mod inversion that should fail */ /* Set u = pq so that gcd(u, p) != 1 */ q = 31; u = p * q; printf("p=%" PRIuBIGD " q=%" PRIuBIGD " pq=%" PRIuBIGD "\n", p, q, u); printf("gcd(pq, p) = %" PRIuBIGD " (i.e. not 1)\n", spGcd(u, p)); res = spModInv(&w, u, p); printf("w = (pq)^-1 mod p returns error %d (expected 1)\n", res); assert(res != 0); /* Test spIsPrime */ printf("Test spIsPrime:\n"); /* Find primes just less than 2^32. Ref: Knuth p408 */ for (n = 0xffffffff, a = 1; a < 100; a++, n--) { if (spIsPrime(n, 50)) { printf("2^32-%" PRIuBIGD " is prime\n", a); assert(is_in_list(a, primes32, NELEMS(primes32))); } } /* And just less than 2^16 */ for (n = 0xffff, a = 1; a < 50; a++, n--) { if (spIsPrime(n, 50)) { printf("2^16-%" PRIuBIGD " is prime\n", a); assert(is_in_list(a, primes16, NELEMS(primes16))); } } /* Generate a random prime < MAX_DIGIT */ n = spSimpleRand(0, MAX_DIGIT); /* make sure odd */ n |= 0x01; /* expect to find a prime approx every lg(n) numbers, so for sure within 100 times that */ ntries = BITS_PER_DIGIT * 100; for (i = 0; i < ntries; i++) { if (spIsPrime(n, 50)) break; n += 2; } printf("Random prime, n = %" PRIuBIGD " (0x%" PRIxBIGD ")\n", n, n); printf("found after %d candidates\n", i+1); if (i >= ntries) printf("Didn't manage to find a prime in %d tries!\n", ntries); else assert(spIsPrime(n, 50)); res = spIsPrime(n, 50); printf("spIsPrime(%" PRIuBIGD ") is %s\n", n, (res ? "TRUE" : "FALSE")); /* Check using (less accurate) Fermat test (these could fail) */ w = 2; spModExp(&x, w, n-1, n); printf("Fermat test: %" PRIxBIGD "^(n-1) mod n = %" PRIxBIGD " (%s)\n", w, x, (x == 1 ? "PASSED" : "FAILED!")); w = 3; spModExp(&x, w, n-1, n); printf("Fermat test: %" PRIxBIGD "^(n-1) mod n = %" PRIxBIGD " (%s)\n", w, x, (x == 1 ? "PASSED" : "FAILED!")); w = 5; spModExp(&x, w, n-1, n); printf("Fermat test: %" PRIxBIGD "^(n-1) mod n = %" PRIxBIGD " (%s)\n", w, x, (x == 1 ? "PASSED" : "FAILED!")); /* Try a known Fermat liar (Carmichael number) */ n = 561; printf("Try n = 561 = 3.11.17 (a `Fermat liar')\n"); w = 5; spModExp(&x, w, n-1, n); printf("Fermat test: %" PRIxBIGD "^(n-1) mod n = %" PRIxBIGD " (%s)\n", w, x, (x == 1 ? "PASSED" : "FAILED!")); res = spIsPrime(n, 50); printf("spIsPrime(%" PRIuBIGD ") is %s\n", n, (res ? "TRUE" : "FALSE")); assert(!res); return 0; }
int spIsPrime(DIGIT_T w, size_t t) { /* Returns true if w is a probable prime Carries out t iterations (Use t = 50 for DSS Standard) */ /* Uses Rabin-Miller Probabilistic Primality Test, Ref: FIPS-186-2 Appendix 2. Also Schneier 2nd ed p 260 & Knuth Vol 2, p 379 and ANSI 9.42-2003 Annex B.1.1. */ unsigned int i, j; DIGIT_T m, a, b, z; int failed; /* First check for small primes */ for (i = 0; i < N_SMALL_PRIMES; i++) { if (w % SMALL_PRIMES[i] == 0) return 0; /* Failed */ } /* Now do Rabin-Miller */ /* Step 2. Find a and m where w = 1 + (2^a)m m is odd and 2^a is largest power of 2 dividing w - 1 */ m = w - 1; for (a = 0; ISEVEN(m); a++) m >>= 1; /* Divide by 2 until m is odd */ /* assert((1 << a) * m + 1 == w); */ for (i = 0; i < t; i++) { failed = 1; /* Assume fail unless passed in loop */ /* Step 3. Generate a random integer 1 < b < w */ /* [v2.1] changed to 1 < b < w-1 */ b = spSimpleRand(2, w - 2); /* assert(1 < b && b < w-1); */ /* Step 4. Set j = 0 and z = b^m mod w */ j = 0; spModExp(&z, b, m, w); do { /* Step 5. If j = 0 and z = 1, or if z = w - 1 */ if ((j == 0 && z == 1) || (z == w - 1)) { /* Passes on this loop - go to Step 9 */ failed = 0; break; } /* Step 6. If j > 0 and z = 1 */ if (j > 0 && z == 1) { /* Fails - go to Step 8 */ failed = 1; break; } /* Step 7. j = j + 1. If j < a set z = z^2 mod w */ j++; if (j < a) spModMult(&z, z, z, w); /* Loop: if j < a go to Step 5 */ } while (j < a); if (failed) { /* Step 8. Not a prime - stop */ return 0; } } /* Step 9. Go to Step 3 until i >= n */ /* If got here, probably prime => success */ return 1; }
void trial_divide_Q_siqs(uint32 report_num, uint8 parity, uint32 poly_id, uint32 bnum, static_conf_t *sconf, dynamic_conf_t *dconf) { //we have flagged this sieve offset as likely to produce a relation //nothing left to do now but check and see. uint64 q64, f64; int j,it; uint32 prime; int smooth_num; uint32 *fb_offsets; uint32 polya_factors[20]; sieve_fb *fb; uint32 offset, block_loc; fb_offsets = &dconf->fb_offsets[report_num][0]; smooth_num = dconf->smooth_num[report_num]; block_loc = dconf->reports[report_num]; #ifdef QS_TIMING gettimeofday(&qs_timing_start, NULL); #endif offset = (bnum << sconf->qs_blockbits) + block_loc; if (parity) fb = dconf->fb_sieve_n; else fb = dconf->fb_sieve_p; #ifdef USE_YAFU_TDIV z32_to_mpz(&dconf->Qvals32[report_num], dconf->Qvals[report_num]); #endif //check for additional factors of the a-poly factors //make a separate list then merge it with fb_offsets it=0; //max 20 factors allocated for - should be overkill for (j = 0; (j < dconf->curr_poly->s) && (it < 20); j++) { //fbptr = fb + dconf->curr_poly->qlisort[j]; //prime = fbptr->prime; prime = fb[dconf->curr_poly->qlisort[j]].prime; while ((mpz_tdiv_ui(dconf->Qvals[report_num],prime) == 0) && (it < 20)) { mpz_tdiv_q_ui(dconf->Qvals[report_num], dconf->Qvals[report_num], prime); polya_factors[it++] = dconf->curr_poly->qlisort[j]; } } //check if it completely factored by looking at the unfactored portion in tmp //if ((mpz_size(dconf->Qvals[report_num]) == 1) && //(mpz_get_64(dconf->Qvals[report_num]) < (uint64)sconf->large_prime_max)) if ((mpz_size(dconf->Qvals[report_num]) == 1) && (mpz_cmp_ui(dconf->Qvals[report_num], sconf->large_prime_max) < 0)) { uint32 large_prime[2]; large_prime[0] = (uint32)mpz_get_ui(dconf->Qvals[report_num]); //Q->val[0]; large_prime[1] = 1; //add this one if (sconf->is_tiny) { // we need to encode both the a_poly and b_poly index // in poly_id poly_id |= (sconf->total_poly_a << 16); buffer_relation(offset,large_prime,smooth_num+1, fb_offsets,poly_id,parity,dconf,polya_factors,it); } else buffer_relation(offset,large_prime,smooth_num+1, fb_offsets,poly_id,parity,dconf,polya_factors,it); #ifdef QS_TIMING gettimeofday (&qs_timing_stop, NULL); qs_timing_diff = my_difftime (&qs_timing_start, &qs_timing_stop); TF_STG6 += ((double)qs_timing_diff->secs + (double)qs_timing_diff->usecs / 1000000); free(qs_timing_diff); #endif return; } if (sconf->use_dlp == 0) return; //quick check if Q is way too big for DLP (more than 64 bits) if (mpz_sizeinbase(dconf->Qvals[report_num], 2) >= 64) return; q64 = mpz_get_64(dconf->Qvals[report_num]); if ((q64 > sconf->max_fb2) && (q64 < sconf->large_prime_max2)) { //quick prime check: compute 2^(residue-1) mod residue. uint64 res; //printf("%llu\n",q64); #if BITS_PER_DIGIT == 32 mpz_set_64(dconf->gmptmp1, q64); mpz_set_64(dconf->gmptmp2, 2); mpz_set_64(dconf->gmptmp3, q64-1); mpz_powm(dconf->gmptmp1, dconf->gmptmp2, dconf->gmptmp3, dconf->gmptmp1); res = mpz_get_64(dconf->gmptmp1); #else spModExp(2, q64 - 1, q64, &res); #endif //if equal to 1, assume it is prime. this may be wrong sometimes, but we don't care. //more important to quickly weed out probable primes than to spend more time to be //more sure. if (res == 1) { #ifdef QS_TIMING gettimeofday (&qs_timing_stop, NULL); qs_timing_diff = my_difftime (&qs_timing_start, &qs_timing_stop); TF_STG6 += ((double)qs_timing_diff->secs + (double)qs_timing_diff->usecs / 1000000); free(qs_timing_diff); #endif dconf->dlp_prp++; return; } //try to find a double large prime #ifdef HAVE_CUDA { uint32 large_prime[2] = {1,1}; // remember the residue and the relation it is associated with dconf->buf_id[dconf->num_squfof_cand] = dconf->buffered_rels; dconf->squfof_candidates[dconf->num_squfof_cand++] = q64; // buffer the relation buffer_relation(offset,large_prime,smooth_num+1, fb_offsets,poly_id,parity,dconf,polya_factors,it); } #else dconf->attempted_squfof++; mpz_set_64(dconf->gmptmp1, q64); f64 = sp_shanks_loop(dconf->gmptmp1, sconf->obj); if (f64 > 1 && f64 != q64) { uint32 large_prime[2]; large_prime[0] = (uint32)f64; large_prime[1] = (uint32)(q64 / f64); if (large_prime[0] < sconf->large_prime_max && large_prime[1] < sconf->large_prime_max) { //add this one dconf->dlp_useful++; buffer_relation(offset,large_prime,smooth_num+1, fb_offsets,poly_id,parity,dconf,polya_factors,it); } } else { dconf->failed_squfof++; //printf("squfof failure: %" PRIu64 "\n", q64); } #endif } else dconf->dlp_outside_range++; #ifdef QS_TIMING gettimeofday (&qs_timing_stop, NULL); qs_timing_diff = my_difftime (&qs_timing_start, &qs_timing_stop); TF_STG6 += ((double)qs_timing_diff->secs + (double)qs_timing_diff->usecs / 1000000); free(qs_timing_diff); #endif return; }