1
0
mirror of https://git.tartarus.org/simon/putty.git synced 2025-01-09 17:38:00 +00:00

PrimeCandidateSource: add Sophie Germain filtering.

A Sophie Germain prime is a prime p such that 2p+1 is also prime. The
larger prime of the pair 2p+1 is also known as a 'safe prime', and is
the preferred kind of modulus for conventional Diffie-Hellman.

Generating these is harder work than normal prime generation. There's
not really much of a technique except to just keep generating
candidate primes p and then testing 2p+1. But what you _can_ do to
speed things up is to get the prime-candidate generator to help a bit:
it's already enforcing that no small prime divides p, and it's easy to
get it to also enforce that no small prime divides 2p+1. That check
can filter out a lot of bad candidates early, before you waste time on
the more expensive checks, so you have a better chance of success with
each number that gets as far as Miller-Rabin.

Here I add an extra setup function for PrimeCandidateSource which
enables those extra checks. After you call pcs_try_sophie_germain(),
the PCS will only deliver you numbers for which both p and 2p+1 are
free of small factors.
This commit is contained in:
Simon Tatham 2020-02-29 06:46:13 +00:00
parent 18fd47b618
commit 6b1fbfe55c
3 changed files with 34 additions and 1 deletions

View File

@ -15,7 +15,7 @@ struct avoid {
struct PrimeCandidateSource { struct PrimeCandidateSource {
unsigned bits; unsigned bits;
bool ready; bool ready, try_sophie_germain;
/* We'll start by making up a random number strictly less than this ... */ /* We'll start by making up a random number strictly less than this ... */
mp_int *limit; mp_int *limit;
@ -47,6 +47,7 @@ PrimeCandidateSource *pcs_new_with_firstbits(unsigned bits,
s->bits = bits; s->bits = bits;
s->ready = false; s->ready = false;
s->try_sophie_germain = false;
s->kps = NULL; s->kps = NULL;
s->nkps = s->kpsize = 0; s->nkps = s->kpsize = 0;
@ -97,6 +98,11 @@ void pcs_free(PrimeCandidateSource *s)
sfree(s); sfree(s);
} }
void pcs_try_sophie_germain(PrimeCandidateSource *s)
{
s->try_sophie_germain = true;
}
static void pcs_require_residue_inner(PrimeCandidateSource *s, static void pcs_require_residue_inner(PrimeCandidateSource *s,
mp_int *mod, mp_int *res) 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++) for (size_t i = 0; i < NSMALLPRIMES && smallprimes[i] < limit; i++)
ADD_AVOID(smallprimes[i], 0); 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 * Finally, if there's a particular modulus and residue we've been
* told to avoid, put it on the list. * told to avoid, put it on the list.

View File

@ -51,6 +51,9 @@ void pcs_require_residue_1_mod_prime(PrimeCandidateSource *s, mp_int *mod);
void pcs_avoid_residue_small(PrimeCandidateSource *s, void pcs_avoid_residue_small(PrimeCandidateSource *s,
unsigned mod, unsigned res); 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 /* Prepare a PrimeCandidateSource to actually generate numbers. This
* function does last-minute computation that has to be delayed until * function does last-minute computation that has to be delayed until
* all constraints have been input. */ * all constraints have been input. */

View File

@ -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, val_pcs, val_mpint)
FUNC2(void, pcs_require_residue_1_mod_prime, 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) FUNC3(void, pcs_avoid_residue_small, val_pcs, uint, uint)
FUNC1(void, pcs_try_sophie_germain, val_pcs)
FUNC1(void, pcs_ready, val_pcs) FUNC1(void, pcs_ready, val_pcs)
FUNC4(void, pcs_inspect, val_pcs, out_val_mpint, out_val_mpint, out_val_mpint) FUNC4(void, pcs_inspect, val_pcs, out_val_mpint, out_val_mpint, out_val_mpint)
FUNC1(val_mpint, pcs_generate, val_pcs) FUNC1(val_mpint, pcs_generate, val_pcs)