/* * Modifies the given bnq to return a prime slightly larger, and then * modifies the given bnp to be a prime which is == 1 (mod bnq). * This is done by decreasing bnp until it is == 1 (mod 2*bnq), and * then searching forward in steps of 2*bnq. * Returns >=0 on success or -1 on failure (out of memory). On * success, the return value is the number of modular exponentiations * performed (excluding the final confirmation). * This never gives up searching. * * int (*f)(void *arg, int c), void *arg * The function f argument, if non-NULL, is called with progress indicator * characters for printing. A dot (.) is written every time a primality test * is failed, a star (*) every time one is passed, and a slash (/) in the * case that the sieve was emptied without finding a prime and is being * refilled. f is also passed the void *arg argument for private * context storage. If f returns < 0, the test aborts and returns * that value immediately. * * Apologies to structured programmers for all the GOTOs. */ int dsaPrimeGen(BigNum *bnq, BigNum *bnp, int (*f)(void *arg, int c), void *arg) { int retval; unsigned p, prev; BigNum a, e; int modexps = 0; #ifdef MSDOS unsigned char *sieve; #else unsigned char sieve[SIEVE]; #endif #ifdef MSDOS sieve = bniMemAlloc(SIEVE); if (!sieve) return -1; #endif bnBegin(&a); bnBegin(&e); /* Phase 1: Search forwards from bnq for a suitable prime. */ /* First, make sure that bnq is odd. */ (void)bnAddQ(bnq, ~bnLSWord(bnq) & 1); for (;;) { if (sieveBuild(sieve, SIEVE, bnq, 2, 1) < 0) goto failed; p = prev = 0; if (sieve[0] & 1 || (p = sieveSearch(sieve, SIEVE, p)) != 0) { do { /* * Adjust bn to have the right value, * incrementing in steps of < 65536. * 32767 = 65535/2. */ pgpAssert(p >= prev); prev = p-prev; /* Delta - add 2*prev to bn */ #if SIEVE*8*2 >= 65536 while (prev > 32767) { if (bnAddQ(bnq, 2*32767) < 0) goto failed; prev -= 32767; } #endif if (bnAddQ(bnq, 2*prev) < 0) goto failed; prev = p; retval = primeTest(bnq, &e, &a, f, arg); if (retval <= 0) goto phase2; /* Success! */ modexps += retval; if (f && (retval = f(arg, '.')) < 0) goto done; /* And try again */ p = sieveSearch(sieve, SIEVE, p); } while (p); } /* Ran out of sieve space - increase bn and keep trying. */ #if SIEVE*8*2 >= 65536 p = ((SIEVE-1)*8+7) - prev; /* Number of steps (of 2) */ while (p >= 32737) { if (bnAddQ(bnq, 2*32767) < 0) goto failed; p -= 32767; } if (bnAddQ(bnq, 2*(p+1)) < 0) goto failed; #else if (bnAddQ(bnq, SIEVE*8*2 - prev) < 0) goto failed; #endif if (f && (retval = f(arg, '/')) < 0) goto done; } /* for (;;) */ /* * Phase 2: find a suitable prime bnp == 1 (mod bnq). */ /* * Since bnp will be, and bnq is, odd, bnp-1 must be a multiple * of 2*bnq. So start by subtracting the excess. */ phase2: /* Double bnq until end of bnp search. */ if (bnAdd(bnq, bnq) < 0) goto failed; bnMod(&a, bnp, bnq); if (bnBits(&a)) { /* Will always be true, but... */ (void)bnSubQ(&a, 1); if (bnSub(bnp, &a)) /* Also error on underflow */ goto failed; } /* Okay, now we're ready. */ for (;;) { if (sieveBuildBig(sieve, SIEVE, bnp, bnq, 0) < 0) goto failed; if (f && (retval = f(arg, '/')) < 0) goto done; p = prev = 0; if (sieve[0] & 1 || (p = sieveSearch(sieve, SIEVE, p)) != 0) { do { /* * Adjust bn to have the right value, * adding (p-prev) * 2*bnq. */ pgpAssert(p >= prev); /* Compute delta into a */ if (bnMulQ(&a, bnq, p-prev) < 0) goto failed; if (bnAdd(bnp, &a) < 0) goto failed; prev = p; retval = primeTest(bnp, &e, &a, f, arg); if (retval <= 0) goto done; /* Success! */ modexps += retval; if (f && (retval = f(arg, '.')) < 0) goto done; /* And try again */ p = sieveSearch(sieve, SIEVE, p); } while (p); } /* Ran out of sieve space - increase bn and keep trying. */ #if SIEVE*8 == 65536 if (prev) { p = (unsigned)(SIEVE*8ul - prev); } else { /* Corner case that will never actually happen */ if (bnAdd(bnp, bnq) < 0) goto failed; p = 65535; } #else p = SIEVE*8 - prev; #endif /* Add p * bnq to bnp */ if (bnMulQ(&a, bnq, p) < 0) goto failed; if (bnAdd(bnp, &a) < 0) goto failed; } /* for (;;) */ failed: retval = -1; done: /* Shift bnq back down by the extra bit again. */ bnRShift(bnq, 1); /* Harmless even if bnq is random */ bnEnd(&e); bnEnd(&a); #ifdef MSDOS bniMemFree(sieve, SIEVE); #else bniMemWipe(sieve, sizeof(sieve)); #endif return retval < 0 ? retval : modexps + 2*CONFIRMTESTS; }
/* * Similar, but searches forward from the given starting value in steps of * "step" rather than 1. The step size must be even, and bn must be odd. * Among other possibilities, this can be used to generate "strong" * primes, where p-1 has a large prime factor. */ int bnPrimeGenStrong(BigNum *bn, BigNum const *step, int (*f)(void *arg, int c), void *arg) { int retval; unsigned p, prev; BigNum a, e; int modexps = 0; #ifdef MSDOS unsigned char *sieve; #else unsigned char sieve[SIEVE]; #endif PGPBoolean isSecure = bn->isSecure; PGPMemoryMgrRef mgr = bn->mgr; #ifdef MSDOS sieve = bniMemAlloc(SIEVE); if (!sieve) return -1; #endif /* Step must be even and bn must be odd */ pgpAssert((bnLSWord(step) & 1) == 0); pgpAssert((bnLSWord(bn) & 1) == 1); bnBegin(&a, mgr, isSecure); bnBegin(&e, mgr, isSecure); for (;;) { if (sieveBuildBig(sieve, SIEVE, bn, step, 0) < 0) goto failed; p = prev = 0; if (sieve[0] & 1 || (p = sieveSearch(sieve, SIEVE, p)) != 0) { do { /* * Adjust bn to have the right value, * adding (p-prev) * 2*step. */ pgpAssert(p >= prev); /* Compute delta into a */ if (bnMulQ(&a, step, p-prev) < 0) goto failed; if (bnAdd(bn, &a) < 0) goto failed; prev = p; retval = primeTest(bn, &e, &a, f, arg); if (retval <= 0) goto done; /* Success! */ modexps += retval; if (f && (retval = f(arg, '.')) < 0) goto done; /* And try again */ p = sieveSearch(sieve, SIEVE, p); } while (p); } /* Ran out of sieve space - increase bn and keep trying. */ #if SIEVE*8 == 65536 /* Corner case that will never actually happen */ if (!prev) { if (bnAdd(bn, step) < 0) goto failed; p = 65535; } else { p = (unsigned)(SIEVE*8 - prev); } #else p = SIEVE*8 - prev; #endif if (bnMulQ(&a, step, p) < 0 || bnAdd(bn, &a) < 0) goto failed; if (f && (retval = f(arg, '/')) < 0) goto done; } /* for (;;) */ failed: retval = -1; done: bnEnd(&e); bnEnd(&a); #ifdef MSDOS bniMemFree(sieve, SIEVE); #else bniMemWipe(sieve, sizeof(sieve)); #endif return retval < 0 ? retval : modexps + CONFIRMTESTS; }
static int genDH(struct BigNum *bn, unsigned bits, unsigned char *seed, unsigned len, FILE *f) { #if CLOCK_AVAIL timetype start, stop; unsigned long s; #endif int i; unsigned char s1[1024], s2[1024]; unsigned p1, p2; struct BigNum step; struct Progress progress; if (f) fprintf(f, "Generating a %u-bit D-H prime with \"%.*s\"\n", bits, (int)len, (char *)seed); progress.f = f; progress.column = 0; progress.wrap = 78; /* Find p - choose a starting place */ if (genRandBn(bn, bits, 0xC0, 3, seed, len) < 0) return -1; #if BNDEBUG /* DEBUG - check that sieve works properly */ bnBegin(&step); bnSetQ(&step, 2); sieveBuild(s1, 1024, bn, 2, 0); sieveBuildBig(s2, 1024, bn, &step, 0); p1 = p2 = 0; if (s1[0] != s2[0]) printf("Difference: s1[0] = %x s2[0] = %x\n", s1[0], s2[0]); do { p1 = sieveSearch(s1, 1024, p1); p2 = sieveSearch(s2, 1024, p2); if (p1 != p2) printf("Difference: p1 = %u p2 = %u\n", p1, p2); } while (p1 && p2); bnEnd(&step); #endif /* And search for a prime */ #if CLOCK_AVAIL gettime(&start); #endif i = germainPrimeGen(bn, 1, f ? genProgress : 0, (void *)&progress); if (i < 0) return -1; #if CLOCK_AVAIL gettime(&stop); #endif if (f) { putc('\n', f); fprintf(f, "%d modular exponentiations performed.\n", i); } #if CLOCK_AVAIL subtime(stop, start); s = sec(stop); bndPrintf("%u-bit time = %lu.%03u sec.", bits, s, msec(stop)); if (s > 60) { putchar(' '); putchar('('); if (s > 3600) printf("%u:%02u", (unsigned)(s/3600), (unsigned)(s/60%60)); else printf("%u", (unsigned)(s/60)); printf(":%02u)", (unsigned)(s%60)); } putchar('\n'); #endif bndPut("p = ", bn); return 0; }