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:
parent
6b1fbfe55c
commit
115686527c
@ -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);
|
||||
|
@ -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. */
|
||||
|
12
sshprime.c
12
sshprime.c
@ -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);
|
||||
|
||||
|
@ -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)
|
||||
|
Loading…
Reference in New Issue
Block a user