version 1.1, 2003/07/28 09:49:56 |
version 1.1.4.2, 2004/03/04 18:18:15 |
|
|
|
|
#include <openssl/bn.h> |
#include <openssl/bn.h> |
|
|
|
|
/* |
/* |
* Debugging defines |
|
*/ |
|
|
|
/* define DEBUG_LARGE 1 */ |
|
/* define DEBUG_SMALL 1 */ |
|
/* define DEBUG_TEST 1 */ |
|
|
|
/* |
|
* File output defines |
* File output defines |
*/ |
*/ |
|
|
|
|
#define QTEST_JACOBI (0x08) |
#define QTEST_JACOBI (0x08) |
#define QTEST_ELLIPTIC (0x10) |
#define QTEST_ELLIPTIC (0x10) |
|
|
/* Size: decimal. |
/* |
|
* Size: decimal. |
* Specifies the number of the most significant bit (0 to M). |
* Specifies the number of the most significant bit (0 to M). |
** WARNING: internally, usually 1 to N. |
* WARNING: internally, usually 1 to N. |
*/ |
*/ |
#define QSIZE_MINIMUM (511) |
#define QSIZE_MINIMUM (511) |
|
|
|
|
|
|
time(&time_now); |
time(&time_now); |
gtm = gmtime(&time_now); |
gtm = gmtime(&time_now); |
|
|
res = fprintf(ofile, "%04d%02d%02d%02d%02d%02d %u %u %u %u %x ", |
res = fprintf(ofile, "%04d%02d%02d%02d%02d%02d %u %u %u %u %x ", |
gtm->tm_year + 1900, gtm->tm_mon + 1, gtm->tm_mday, |
gtm->tm_year + 1900, gtm->tm_mon + 1, gtm->tm_mday, |
gtm->tm_hour, gtm->tm_min, gtm->tm_sec, |
gtm->tm_hour, gtm->tm_min, gtm->tm_sec, |
|
|
{ |
{ |
u_int32_t r, u; |
u_int32_t r, u; |
|
|
debug2("sieve_large %u", s); |
debug3("sieve_large %u", s); |
largetries++; |
largetries++; |
/* r = largebase mod s */ |
/* r = largebase mod s */ |
r = BN_mod_word(largebase, s); |
r = BN_mod_word(largebase, s); |
|
|
largememory = memory; |
largememory = memory; |
|
|
/* |
/* |
* Set power to the length in bits of the prime to be generated. |
* Set power to the length in bits of the prime to be generated. |
* This is changed to 1 less than the desired safe prime moduli p. |
* This is changed to 1 less than the desired safe prime moduli p. |
*/ |
*/ |
if (power > TEST_MAXIMUM) { |
if (power > TEST_MAXIMUM) { |
error("Too many bits: %u > %lu", power, TEST_MAXIMUM); |
error("Too many bits: %u > %lu", power, TEST_MAXIMUM); |
return (-1); |
return (-1); |
|
|
power--; /* decrement before squaring */ |
power--; /* decrement before squaring */ |
|
|
/* |
/* |
* The density of ordinary primes is on the order of 1/bits, so the |
* The density of ordinary primes is on the order of 1/bits, so the |
* density of safe primes should be about (1/bits)**2. Set test range |
* density of safe primes should be about (1/bits)**2. Set test range |
* to something well above bits**2 to be reasonably sure (but not |
* to something well above bits**2 to be reasonably sure (but not |
* guaranteed) of catching at least one safe prime. |
* guaranteed) of catching at least one safe prime. |
*/ |
*/ |
largewords = ((power * power) >> (SHIFT_WORD - TEST_POWER)); |
largewords = ((power * power) >> (SHIFT_WORD - TEST_POWER)); |
|
|
/* |
/* |
* Need idea of how much memory is available. We don't have to use all |
* Need idea of how much memory is available. We don't have to use all |
* of it. |
* of it. |
*/ |
*/ |
if (largememory > LARGE_MAXIMUM) { |
if (largememory > LARGE_MAXIMUM) { |
logit("Limited memory: %u MB; limit %lu MB", |
logit("Limited memory: %u MB; limit %lu MB", |
|
|
q = BN_new(); |
q = BN_new(); |
|
|
/* |
/* |
* Generate random starting point for subprime search, or use |
* Generate random starting point for subprime search, or use |
* specified parameter. |
* specified parameter. |
*/ |
*/ |
largebase = BN_new(); |
largebase = BN_new(); |
if (start == NULL) |
if (start == NULL) |
|
|
|
|
time(&time_start); |
time(&time_start); |
|
|
logit("%.24s Sieve next %u plus %u-bit", ctime(&time_start), |
logit("%.24s Sieve next %u plus %u-bit", ctime(&time_start), |
largenumbers, power); |
largenumbers, power); |
debug2("start point: 0x%s", BN_bn2hex(largebase)); |
debug2("start point: 0x%s", BN_bn2hex(largebase)); |
|
|
/* |
/* |
* TinySieve |
* TinySieve |
*/ |
*/ |
for (i = 0; i < tinybits; i++) { |
for (i = 0; i < tinybits; i++) { |
if (BIT_TEST(TinySieve, i)) |
if (BIT_TEST(TinySieve, i)) |
continue; /* 2*i+3 is composite */ |
continue; /* 2*i+3 is composite */ |
|
|
} |
} |
|
|
/* |
/* |
* Start the small block search at the next possible prime. To avoid |
* Start the small block search at the next possible prime. To avoid |
* fencepost errors, the last pass is skipped. |
* fencepost errors, the last pass is skipped. |
*/ |
*/ |
for (smallbase = TINY_NUMBER + 3; |
for (smallbase = TINY_NUMBER + 3; |
smallbase < (SMALL_MAXIMUM - TINY_NUMBER); |
smallbase < (SMALL_MAXIMUM - TINY_NUMBER); |
smallbase += TINY_NUMBER) { |
smallbase += TINY_NUMBER) { |
|
|
} |
} |
|
|
/* |
/* |
* SmallSieve |
* SmallSieve |
*/ |
*/ |
for (i = 0; i < smallbits; i++) { |
for (i = 0; i < smallbits; i++) { |
if (BIT_TEST(SmallSieve, i)) |
if (BIT_TEST(SmallSieve, i)) |
continue; /* 2*i+smallbase is composite */ |
continue; /* 2*i+smallbase is composite */ |
|
|
* The result is a list of so-call "safe" primes |
* The result is a list of so-call "safe" primes |
*/ |
*/ |
int |
int |
prime_test(FILE *in, FILE *out, u_int32_t trials, |
prime_test(FILE *in, FILE *out, u_int32_t trials, |
u_int32_t generator_wanted) |
u_int32_t generator_wanted) |
{ |
{ |
BIGNUM *q, *p, *a; |
BIGNUM *q, *p, *a; |
|
|
debug2("%10u: known composite", count_in); |
debug2("%10u: known composite", count_in); |
continue; |
continue; |
} |
} |
|
|
/* tries */ |
/* tries */ |
in_tries = strtoul(cp, &cp, 10); |
in_tries = strtoul(cp, &cp, 10); |
|
|
|
|
in_size += 1; |
in_size += 1; |
generator_known = 0; |
generator_known = 0; |
break; |
break; |
default: |
case QTYPE_UNSTRUCTURED: |
|
case QTYPE_SAFE: |
|
case QTYPE_SCHNOOR: |
|
case QTYPE_STRONG: |
|
case QTYPE_UNKNOWN: |
debug2("%10u: (%u)", count_in, in_type); |
debug2("%10u: (%u)", count_in, in_type); |
a = p; |
a = p; |
BN_hex2bn(&a, cp); |
BN_hex2bn(&a, cp); |
/* q = (p-1) / 2 */ |
/* q = (p-1) / 2 */ |
BN_rshift(q, p, 1); |
BN_rshift(q, p, 1); |
break; |
break; |
|
default: |
|
debug2("Unknown prime type"); |
|
break; |
} |
} |
|
|
/* |
/* |
|
|
in_tries += trials; |
in_tries += trials; |
else |
else |
in_tries = trials; |
in_tries = trials; |
|
|
/* |
/* |
* guess unknown generator |
* guess unknown generator |
*/ |
*/ |
|
|
else { |
else { |
u_int32_t r = BN_mod_word(p, 10); |
u_int32_t r = BN_mod_word(p, 10); |
|
|
if (r == 3 || r == 7) { |
if (r == 3 || r == 7) |
generator_known = 5; |
generator_known = 5; |
} |
|
} |
} |
} |
} |
/* |
/* |
|
|
continue; |
continue; |
} |
} |
|
|
|
/* |
|
* Primes with no known generator are useless for DH, so |
|
* skip those. |
|
*/ |
|
if (generator_known == 0) { |
|
debug2("%10u: no known generator", count_in); |
|
continue; |
|
} |
|
|
count_possible++; |
count_possible++; |
|
|
/* |
/* |
* The (1/4)^N performance bound on Miller-Rabin is |
* The (1/4)^N performance bound on Miller-Rabin is |
* extremely pessimistic, so don't spend a lot of time |
* extremely pessimistic, so don't spend a lot of time |
* really verifying that q is prime until after we know |
* really verifying that q is prime until after we know |
* that p is also prime. A single pass will weed out the |
* that p is also prime. A single pass will weed out the |
* vast majority of composite q's. |
* vast majority of composite q's. |
*/ |
*/ |
if (BN_is_prime(q, 1, NULL, ctx, NULL) <= 0) { |
if (BN_is_prime(q, 1, NULL, ctx, NULL) <= 0) { |
debug2("%10u: q failed first possible prime test", |
debug("%10u: q failed first possible prime test", |
count_in); |
count_in); |
continue; |
continue; |
} |
} |
|
|
/* |
/* |
* q is possibly prime, so go ahead and really make sure |
* q is possibly prime, so go ahead and really make sure |
* that p is prime. If it is, then we can go back and do |
* that p is prime. If it is, then we can go back and do |
* the same for q. If p is composite, chances are that |
* the same for q. If p is composite, chances are that |
* will show up on the first Rabin-Miller iteration so it |
* will show up on the first Rabin-Miller iteration so it |
* doesn't hurt to specify a high iteration count. |
* doesn't hurt to specify a high iteration count. |
*/ |
*/ |
if (!BN_is_prime(p, trials, NULL, ctx, NULL)) { |
if (!BN_is_prime(p, trials, NULL, ctx, NULL)) { |
debug2("%10u: p is not prime", count_in); |
debug("%10u: p is not prime", count_in); |
continue; |
continue; |
} |
} |
debug("%10u: p is almost certainly prime", count_in); |
debug("%10u: p is almost certainly prime", count_in); |
|
|
} |
} |
debug("%10u: q is almost certainly prime", count_in); |
debug("%10u: q is almost certainly prime", count_in); |
|
|
if (qfileout(out, QTYPE_SAFE, (in_tests | QTEST_MILLER_RABIN), |
if (qfileout(out, QTYPE_SAFE, (in_tests | QTEST_MILLER_RABIN), |
in_tries, in_size, generator_known, p)) { |
in_tries, in_size, generator_known, p)) { |
res = -1; |
res = -1; |
break; |
break; |
|
|
BN_CTX_free(ctx); |
BN_CTX_free(ctx); |
|
|
logit("%.24s Found %u safe primes of %u candidates in %ld seconds", |
logit("%.24s Found %u safe primes of %u candidates in %ld seconds", |
ctime(&time_stop), count_out, count_possible, |
ctime(&time_stop), count_out, count_possible, |
(long) (time_stop - time_start)); |
(long) (time_stop - time_start)); |
|
|
return (res); |
return (res); |