michael@0: /* michael@0: * primegen.c michael@0: * michael@0: * Generates random integers which are prime with a high degree of michael@0: * probability using the Miller-Rabin probabilistic primality testing michael@0: * algorithm. michael@0: * michael@0: * Usage: michael@0: * primegen [] michael@0: * michael@0: * - number of significant bits each prime should have michael@0: * - number of primes to generate michael@0: * michael@0: * This Source Code Form is subject to the terms of the Mozilla Public michael@0: * License, v. 2.0. If a copy of the MPL was not distributed with this michael@0: * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ michael@0: michael@0: #include michael@0: #include michael@0: #include michael@0: #include michael@0: #include michael@0: michael@0: #include "mpi.h" michael@0: #include "mplogic.h" michael@0: #include "mpprime.h" michael@0: michael@0: #define NUM_TESTS 5 /* Number of Rabin-Miller iterations to test with */ michael@0: michael@0: #ifdef DEBUG michael@0: #define FPUTC(x,y) fputc(x,y) michael@0: #else michael@0: #define FPUTC(x,y) michael@0: #endif michael@0: michael@0: int main(int argc, char *argv[]) michael@0: { michael@0: unsigned char *raw; michael@0: char *out; michael@0: unsigned long nTries; michael@0: int rawlen, bits, outlen, ngen, ix, jx; michael@0: int g_strong = 0; michael@0: mp_int testval; michael@0: mp_err res; michael@0: clock_t start, end; michael@0: michael@0: /* We'll just use the C library's rand() for now, although this michael@0: won't be good enough for cryptographic purposes */ michael@0: if((out = getenv("SEED")) == NULL) { michael@0: srand((unsigned int)time(NULL)); michael@0: } else { michael@0: srand((unsigned int)atoi(out)); michael@0: } michael@0: michael@0: if(argc < 2) { michael@0: fprintf(stderr, "Usage: %s [ [strong]]\n", argv[0]); michael@0: return 1; michael@0: } michael@0: michael@0: if((bits = abs(atoi(argv[1]))) < CHAR_BIT) { michael@0: fprintf(stderr, "%s: please request at least %d bits.\n", michael@0: argv[0], CHAR_BIT); michael@0: return 1; michael@0: } michael@0: michael@0: /* If optional third argument is given, use that as the number of michael@0: primes to generate; otherwise generate one prime only. michael@0: */ michael@0: if(argc < 3) { michael@0: ngen = 1; michael@0: } else { michael@0: ngen = abs(atoi(argv[2])); michael@0: } michael@0: michael@0: /* If fourth argument is given, and is the word "strong", we'll michael@0: generate strong (Sophie Germain) primes. michael@0: */ michael@0: if(argc > 3 && strcmp(argv[3], "strong") == 0) michael@0: g_strong = 1; michael@0: michael@0: /* testval - candidate being tested; nTries - number tried so far */ michael@0: if ((res = mp_init(&testval)) != MP_OKAY) { michael@0: fprintf(stderr, "%s: error: %s\n", argv[0], mp_strerror(res)); michael@0: return 1; michael@0: } michael@0: michael@0: if(g_strong) { michael@0: printf("Requested %d strong prime value(s) of %d bits.\n", michael@0: ngen, bits); michael@0: } else { michael@0: printf("Requested %d prime value(s) of %d bits.\n", ngen, bits); michael@0: } michael@0: michael@0: rawlen = (bits / CHAR_BIT) + ((bits % CHAR_BIT) ? 1 : 0) + 1; michael@0: michael@0: if((raw = calloc(rawlen, sizeof(unsigned char))) == NULL) { michael@0: fprintf(stderr, "%s: out of memory, sorry.\n", argv[0]); michael@0: return 1; michael@0: } michael@0: michael@0: /* This loop is one for each prime we need to generate */ michael@0: for(jx = 0; jx < ngen; jx++) { michael@0: michael@0: raw[0] = 0; /* sign is positive */ michael@0: michael@0: /* Pack the initializer with random bytes */ michael@0: for(ix = 1; ix < rawlen; ix++) michael@0: raw[ix] = (rand() * rand()) & UCHAR_MAX; michael@0: michael@0: raw[1] |= 0x80; /* set high-order bit of test value */ michael@0: raw[rawlen - 1] |= 1; /* set low-order bit of test value */ michael@0: michael@0: /* Make an mp_int out of the initializer */ michael@0: mp_read_raw(&testval, (char *)raw, rawlen); michael@0: michael@0: /* Initialize candidate counter */ michael@0: nTries = 0; michael@0: michael@0: start = clock(); /* time generation for this prime */ michael@0: do { michael@0: res = mpp_make_prime(&testval, bits, g_strong, &nTries); michael@0: if (res != MP_NO) michael@0: break; michael@0: /* This code works whether digits are 16 or 32 bits */ michael@0: res = mp_add_d(&testval, 32 * 1024, &testval); michael@0: res = mp_add_d(&testval, 32 * 1024, &testval); michael@0: FPUTC(',', stderr); michael@0: } while (1); michael@0: end = clock(); michael@0: michael@0: if (res != MP_YES) { michael@0: break; michael@0: } michael@0: FPUTC('\n', stderr); michael@0: puts("The following value is probably prime:"); michael@0: outlen = mp_radix_size(&testval, 10); michael@0: out = calloc(outlen, sizeof(unsigned char)); michael@0: mp_toradix(&testval, (char *)out, 10); michael@0: printf("10: %s\n", out); michael@0: mp_toradix(&testval, (char *)out, 16); michael@0: printf("16: %s\n\n", out); michael@0: free(out); michael@0: michael@0: printf("Number of candidates tried: %lu\n", nTries); michael@0: printf("This computation took %ld clock ticks (%.2f seconds)\n", michael@0: (end - start), ((double)(end - start) / CLOCKS_PER_SEC)); michael@0: michael@0: FPUTC('\n', stderr); michael@0: } /* end of loop to generate all requested primes */ michael@0: michael@0: if(res != MP_OKAY) michael@0: fprintf(stderr, "%s: error: %s\n", argv[0], mp_strerror(res)); michael@0: michael@0: free(raw); michael@0: mp_clear(&testval); michael@0: michael@0: return 0; michael@0: }