diff --git a/primecandidate.c b/primecandidate.c index 1f73307a..cf4416f9 100644 --- a/primecandidate.c +++ b/primecandidate.c @@ -15,7 +15,7 @@ struct avoid { struct PrimeCandidateSource { unsigned bits; - bool ready; + bool ready, try_sophie_germain; /* We'll start by making up a random number strictly less than this ... */ mp_int *limit; @@ -47,6 +47,7 @@ PrimeCandidateSource *pcs_new_with_firstbits(unsigned bits, s->bits = bits; s->ready = false; + s->try_sophie_germain = false; s->kps = NULL; s->nkps = s->kpsize = 0; @@ -97,6 +98,11 @@ void pcs_free(PrimeCandidateSource *s) sfree(s); } +void pcs_try_sophie_germain(PrimeCandidateSource *s) +{ + s->try_sophie_germain = true; +} + static void pcs_require_residue_inner(PrimeCandidateSource *s, mp_int *mod, mp_int *res) { @@ -270,6 +276,29 @@ void pcs_ready(PrimeCandidateSource *s) for (size_t i = 0; i < NSMALLPRIMES && smallprimes[i] < limit; i++) ADD_AVOID(smallprimes[i], 0); + if (s->try_sophie_germain) { + /* + * If we're aiming to generate a Sophie Germain prime (i.e. p + * such that 2p+1 is also prime), then we also want to ensure + * 2p+1 is not congruent to 0 mod any small prime, because if + * it is, we'll waste a lot of time generating a p for which + * 2p+1 can't possibly work. So we have to avoid an extra + * residue mod each odd q. + * + * We can simplify: 2p+1 == 0 (mod q) + * => 2p == -1 (mod q) + * => p == -2^{-1} (mod q) + * + * There's no need to do Euclid's algorithm to compute those + * inverses, because for any odd q, the modular inverse of -2 + * mod q is just (q-1)/2. (Proof: multiplying it by -2 gives + * 1-q, which is congruent to 1 mod q.) + */ + for (size_t i = 0; i < NSMALLPRIMES && smallprimes[i] < limit; i++) + if (smallprimes[i] != 2) + ADD_AVOID(smallprimes[i], (smallprimes[i] - 1) / 2); + } + /* * Finally, if there's a particular modulus and residue we've been * told to avoid, put it on the list. diff --git a/sshkeygen.h b/sshkeygen.h index 7dddcc5c..99e9ce76 100644 --- a/sshkeygen.h +++ b/sshkeygen.h @@ -51,6 +51,9 @@ void pcs_require_residue_1_mod_prime(PrimeCandidateSource *s, mp_int *mod); void pcs_avoid_residue_small(PrimeCandidateSource *s, unsigned mod, unsigned res); +/* Exclude any prime that has no chance of being a Sophie Germain prime. */ +void pcs_try_sophie_germain(PrimeCandidateSource *s); + /* Prepare a PrimeCandidateSource to actually generate numbers. This * function does last-minute computation that has to be delayed until * all constraints have been input. */ diff --git a/testcrypt.h b/testcrypt.h index 8dbe2a69..3040e0c6 100644 --- a/testcrypt.h +++ b/testcrypt.h @@ -276,6 +276,7 @@ FUNC3(void, pcs_require_residue, val_pcs, val_mpint, val_mpint) FUNC2(void, pcs_require_residue_1, val_pcs, val_mpint) FUNC2(void, pcs_require_residue_1_mod_prime, val_pcs, val_mpint) FUNC3(void, pcs_avoid_residue_small, val_pcs, uint, uint) +FUNC1(void, pcs_try_sophie_germain, val_pcs) FUNC1(void, pcs_ready, val_pcs) FUNC4(void, pcs_inspect, val_pcs, out_val_mpint, out_val_mpint, out_val_mpint) FUNC1(val_mpint, pcs_generate, val_pcs)