1
0
mirror of https://git.tartarus.org/simon/putty.git synced 2025-01-08 08:58:00 +00:00

PrimeCandidateSource: add one-shot mode.

If you want to generate a Sophie Germain / safe prime pair with this
code, then after you've made p, you need to test the primality of
2p+1.

The easiest way to do that is to make a PrimeCandidateSource that is
so constrained as to only be able to deliver 2p+1 as a candidate, and
then run the ordinary prime generation system. The problem is that the
prime generation loops forever, so if 2p+1 _isn't_ prime, it will just
keep testing the same number over and over again and failing the test.

To solve this, I add a 'one-shot mode' to the PrimeCandidateSource
itself, which will cause it to return NULL if asked to generate a
second candidate. Then the prime-generation loops all detect that and
return NULL in turn. However, for clients that _don't_ set a pcs into
one-shot mode, the API remains unchanged: pcs_generate will not return
until it's found a prime (by its own criteria).

This feels like a bit of a bodge, API-wise. But the other two obvious
approaches turn out more awkward.

One option is to extract the Pockle from the PrimeGenerationContext
and use that to directly test primality of 2p+1 based on p - but that
way you don't get to _probabilistically_ generate safe primes, because
that kind of PGC has no Pockle in the first place. (And you can't make
one separately, because you can't convince it that an only
probabilistically generated p is prime!)

Another option is to add a test() method to PrimeGenerationPolicy,
that sits alongside generate(). Then, having generated p, you just
_test_ 2p+1. But then in the provable case you have to explain to it
that it should use p as part of the proof, so that API would get
awkward in its own way.

So this is actually the least disruptive way to do it!
This commit is contained in:
Simon Tatham 2020-02-29 06:47:12 +00:00
parent 6b1fbfe55c
commit 115686527c
4 changed files with 30 additions and 0 deletions

View File

@ -16,6 +16,7 @@ struct avoid {
struct PrimeCandidateSource {
unsigned bits;
bool ready, try_sophie_germain;
bool one_shot, thrown_away_my_shot;
/* We'll start by making up a random number strictly less than this ... */
mp_int *limit;
@ -48,6 +49,8 @@ PrimeCandidateSource *pcs_new_with_firstbits(unsigned bits,
s->bits = bits;
s->ready = false;
s->try_sophie_germain = false;
s->one_shot = false;
s->thrown_away_my_shot = false;
s->kps = NULL;
s->nkps = s->kpsize = 0;
@ -103,6 +106,11 @@ void pcs_try_sophie_germain(PrimeCandidateSource *s)
s->try_sophie_germain = true;
}
void pcs_set_oneshot(PrimeCandidateSource *s)
{
s->one_shot = true;
}
static void pcs_require_residue_inner(PrimeCandidateSource *s,
mp_int *mod, mp_int *res)
{
@ -360,6 +368,11 @@ void pcs_ready(PrimeCandidateSource *s)
mp_int *pcs_generate(PrimeCandidateSource *s)
{
assert(s->ready);
if (s->one_shot) {
if (s->thrown_away_my_shot)
return NULL;
s->thrown_away_my_shot = true;
}
while (true) {
mp_int *x = mp_random_upto(s->limit);

View File

@ -54,6 +54,10 @@ void pcs_avoid_residue_small(PrimeCandidateSource *s,
/* Exclude any prime that has no chance of being a Sophie Germain prime. */
void pcs_try_sophie_germain(PrimeCandidateSource *s);
/* Mark a PrimeCandidateSource as one-shot, so that the prime generation
* function will return NULL if an attempt fails, rather than looping. */
void pcs_set_oneshot(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. */

View File

@ -75,6 +75,10 @@ static mp_int *probprime_generate(
progress_report_attempt(prog);
mp_int *p = pcs_generate(pcs);
if (!p) {
pcs_free(pcs);
return NULL;
}
MillerRabin *mr = miller_rabin_new(p);
bool known_bad = false;
@ -259,6 +263,10 @@ static mp_int *primegen_small(Pockle *pockle, PrimeCandidateSource *pcs)
while (true) {
mp_int *p = pcs_generate(pcs);
if (!p) {
pcs_free(pcs);
return NULL;
}
if (pockle_add_small_prime(pockle, p) == POCKLE_OK) {
pcs_free(pcs);
return p;
@ -627,6 +635,10 @@ static mp_int *provableprime_generate_inner(
while (true) {
mp_int *p = pcs_generate(pcs);
if (!p) {
pcs_free(pcs);
return NULL;
}
debug_f_mp("provable_step p=", p);

View File

@ -277,6 +277,7 @@ 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_set_oneshot, 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)