mirror of
https://git.tartarus.org/simon/putty.git
synced 2025-01-09 17:38:00 +00:00
Generate MPU certificates for proven primes.
Conveniently checkable certificates of primality aren't a new concept. I didn't invent them, and I wasn't the first to implement them. Given that, I thought it might be useful to be able to independently verify a prime generated by PuTTY's provable prime system. Then, even if you don't trust _this_ code, you might still trust someone else's verifier, or at least be less willing to believe that both were colluding. The Perl module Math::Prime::Util is the only free software I've found that defines a specific text-file format for certificates of primality. The MPU format (as it calls it) supports various different methods of certifying the primality of a number (most of which, like Pockle's, depend on having previously proved some smaller number(s) to be prime). The system implemented by Pockle is on its list: MPU calls it by the name "BLS5". So this commit introduces extra stored data inside Pockle so that it remembers not just _that_ it believes certain numbers to be prime, but also _why_ it believed each one to be prime. Then there's an extra method in the Pockle API to translate its internal data structures into the text of an MPU certificate for any number it knows about. Math::Prime::Util doesn't come with a command-line verification tool, unfortunately; only a Perl function which you feed a string argument. So also in this commit I add test/mpu-check.pl, which is a trivial command-line client of that function. At the moment, this new piece of API is only exposed via testcrypt. I could easily put some user interface into the key generation tools that would save a few primality certificates alongside the private key, but I have yet to think of any good reason to do it. Mostly this facility is intended for debugging and cross-checking of the _algorithm_, not of any particular prime.
This commit is contained in:
parent
2ec2b796ed
commit
18fd47b618
140
pockle.c
140
pockle.c
@ -5,23 +5,42 @@
|
||||
#include "mpunsafe.h"
|
||||
#include "tree234.h"
|
||||
|
||||
typedef struct PocklePrimeRecord PocklePrimeRecord;
|
||||
|
||||
struct Pockle {
|
||||
tree234 *tree;
|
||||
|
||||
mp_int **list;
|
||||
PocklePrimeRecord **list;
|
||||
size_t nlist, listsize;
|
||||
};
|
||||
|
||||
static int mpcmp(void *av, void *bv)
|
||||
struct PocklePrimeRecord {
|
||||
mp_int *prime;
|
||||
PocklePrimeRecord **factors;
|
||||
size_t nfactors;
|
||||
mp_int *witness;
|
||||
|
||||
size_t index; /* index in pockle->list */
|
||||
};
|
||||
|
||||
static int ppr_cmp(void *av, void *bv)
|
||||
{
|
||||
mp_int *a = (mp_int *)av, *b = (mp_int *)bv;
|
||||
return mp_cmp_hs(a, b) - mp_cmp_hs(b, a);
|
||||
PocklePrimeRecord *a = (PocklePrimeRecord *)av;
|
||||
PocklePrimeRecord *b = (PocklePrimeRecord *)bv;
|
||||
return mp_cmp_hs(a->prime, b->prime) - mp_cmp_hs(b->prime, a->prime);
|
||||
}
|
||||
|
||||
static int ppr_find(void *av, void *bv)
|
||||
{
|
||||
mp_int *a = (mp_int *)av;
|
||||
PocklePrimeRecord *b = (PocklePrimeRecord *)bv;
|
||||
return mp_cmp_hs(a, b->prime) - mp_cmp_hs(b->prime, a);
|
||||
}
|
||||
|
||||
Pockle *pockle_new(void)
|
||||
{
|
||||
Pockle *pockle = snew(Pockle);
|
||||
pockle->tree = newtree234(mpcmp);
|
||||
pockle->tree = newtree234(ppr_cmp);
|
||||
pockle->list = NULL;
|
||||
pockle->nlist = pockle->listsize = 0;
|
||||
return pockle;
|
||||
@ -29,23 +48,44 @@ Pockle *pockle_new(void)
|
||||
|
||||
void pockle_free(Pockle *pockle)
|
||||
{
|
||||
for (mp_int *mp; (mp = delpos234(pockle->tree, 0)) != NULL ;)
|
||||
mp_free(mp);
|
||||
pockle_release(pockle, 0);
|
||||
assert(count234(pockle->tree) == 0);
|
||||
freetree234(pockle->tree);
|
||||
sfree(pockle->list);
|
||||
sfree(pockle);
|
||||
}
|
||||
|
||||
static PockleStatus pockle_insert(Pockle *pockle, mp_int *p)
|
||||
static PockleStatus pockle_insert(Pockle *pockle, mp_int *p, mp_int **factors,
|
||||
size_t nfactors, mp_int *w)
|
||||
{
|
||||
mp_int *copy = mp_copy(p);
|
||||
mp_int *found = add234(pockle->tree, copy);
|
||||
if (copy != found) {
|
||||
mp_free(copy); /* it was already in there */
|
||||
PocklePrimeRecord *pr = snew(PocklePrimeRecord);
|
||||
pr->prime = mp_copy(p);
|
||||
|
||||
PocklePrimeRecord *found = add234(pockle->tree, pr);
|
||||
if (pr != found) {
|
||||
/* it was already in there */
|
||||
mp_free(pr->prime);
|
||||
sfree(pr);
|
||||
return POCKLE_OK;
|
||||
}
|
||||
|
||||
if (w) {
|
||||
pr->factors = snewn(nfactors, PocklePrimeRecord *);
|
||||
for (size_t i = 0; i < nfactors; i++) {
|
||||
pr->factors[i] = find234(pockle->tree, factors[i], ppr_find);
|
||||
assert(pr->factors[i]);
|
||||
}
|
||||
pr->nfactors = nfactors;
|
||||
pr->witness = mp_copy(w);
|
||||
} else {
|
||||
pr->factors = NULL;
|
||||
pr->nfactors = 0;
|
||||
pr->witness = NULL;
|
||||
}
|
||||
pr->index = pockle->nlist;
|
||||
|
||||
sgrowarray(pockle->list, pockle->listsize, pockle->nlist);
|
||||
pockle->list[pockle->nlist++] = copy;
|
||||
pockle->list[pockle->nlist++] = pr;
|
||||
return POCKLE_OK;
|
||||
}
|
||||
|
||||
@ -57,9 +97,13 @@ size_t pockle_mark(Pockle *pockle)
|
||||
void pockle_release(Pockle *pockle, size_t mark)
|
||||
{
|
||||
while (pockle->nlist > mark) {
|
||||
mp_int *val = pockle->list[--pockle->nlist];
|
||||
del234(pockle->tree, val);
|
||||
mp_free(val);
|
||||
PocklePrimeRecord *pr = pockle->list[--pockle->nlist];
|
||||
del234(pockle->tree, pr);
|
||||
mp_free(pr->prime);
|
||||
if (pr->witness)
|
||||
mp_free(pr->witness);
|
||||
sfree(pr->factors);
|
||||
sfree(pr);
|
||||
}
|
||||
}
|
||||
|
||||
@ -81,7 +125,7 @@ PockleStatus pockle_add_small_prime(Pockle *pockle, mp_int *p)
|
||||
return POCKLE_SMALL_PRIME_NOT_PRIME;
|
||||
}
|
||||
|
||||
return pockle_insert(pockle, p);
|
||||
return pockle_insert(pockle, p, NULL, 0, NULL);
|
||||
}
|
||||
|
||||
PockleStatus pockle_add_prime(Pockle *pockle, mp_int *p,
|
||||
@ -139,7 +183,7 @@ PockleStatus pockle_add_prime(Pockle *pockle, mp_int *p,
|
||||
for (size_t i = 0; i < nfactors; i++) {
|
||||
mp_int *q = factors[i];
|
||||
|
||||
if (!find234(pockle->tree, q, NULL)) {
|
||||
if (!find234(pockle->tree, q, ppr_find)) {
|
||||
status = POCKLE_FACTOR_NOT_KNOWN_PRIME;
|
||||
goto out;
|
||||
}
|
||||
@ -328,7 +372,7 @@ PockleStatus pockle_add_prime(Pockle *pockle, mp_int *p,
|
||||
* primes, so that future calls to this function can cite it in
|
||||
* evidence of larger numbers' primality.
|
||||
*/
|
||||
status = pockle_insert(pockle, p);
|
||||
status = pockle_insert(pockle, p, factors, nfactors, witness);
|
||||
|
||||
out:
|
||||
if (x)
|
||||
@ -341,3 +385,61 @@ PockleStatus pockle_add_prime(Pockle *pockle, mp_int *p,
|
||||
monty_free(mc);
|
||||
return status;
|
||||
}
|
||||
|
||||
static void mp_write_decimal(strbuf *sb, mp_int *x)
|
||||
{
|
||||
char *s = mp_get_decimal(x);
|
||||
ptrlen pl = ptrlen_from_asciz(s);
|
||||
put_datapl(sb, pl);
|
||||
smemclr(s, pl.len);
|
||||
sfree(s);
|
||||
}
|
||||
|
||||
strbuf *pockle_mpu(Pockle *pockle, mp_int *p)
|
||||
{
|
||||
strbuf *sb = strbuf_new_nm();
|
||||
PocklePrimeRecord *pr = find234(pockle->tree, p, ppr_find);
|
||||
assert(pr);
|
||||
|
||||
bool *needed = snewn(pockle->nlist, bool);
|
||||
memset(needed, 0, pockle->nlist * sizeof(bool));
|
||||
needed[pr->index] = true;
|
||||
|
||||
strbuf_catf(sb, "[MPU - Primality Certificate]\nVersion 1.0\nBase 10\n\n"
|
||||
"Proof for:\nN ");
|
||||
mp_write_decimal(sb, p);
|
||||
strbuf_catf(sb, "\n");
|
||||
|
||||
for (size_t index = pockle->nlist; index-- > 0 ;) {
|
||||
if (!needed[index])
|
||||
continue;
|
||||
pr = pockle->list[index];
|
||||
|
||||
if (mp_get_nbits(pr->prime) <= 64) {
|
||||
strbuf_catf(sb, "\nType Small\nN ");
|
||||
mp_write_decimal(sb, pr->prime);
|
||||
strbuf_catf(sb, "\n");
|
||||
} else {
|
||||
assert(pr->witness);
|
||||
strbuf_catf(sb, "\nType BLS5\nN ");
|
||||
mp_write_decimal(sb, pr->prime);
|
||||
strbuf_catf(sb, "\n");
|
||||
for (size_t i = 0; i < pr->nfactors; i++) {
|
||||
strbuf_catf(sb, "Q[%"SIZEu"] ", i+1);
|
||||
mp_write_decimal(sb, pr->factors[i]->prime);
|
||||
assert(pr->factors[i]->index < index);
|
||||
needed[pr->factors[i]->index] = true;
|
||||
strbuf_catf(sb, "\n");
|
||||
}
|
||||
for (size_t i = 0; i < pr->nfactors + 1; i++) {
|
||||
strbuf_catf(sb, "A[%"SIZEu"] ", i);
|
||||
mp_write_decimal(sb, pr->witness);
|
||||
strbuf_catf(sb, "\n");
|
||||
}
|
||||
strbuf_catf(sb, "----\n");
|
||||
}
|
||||
}
|
||||
sfree(needed);
|
||||
|
||||
return sb;
|
||||
}
|
||||
|
@ -161,6 +161,10 @@ void pockle_release(Pockle *pockle, size_t mark);
|
||||
/* Free a Pockle. */
|
||||
void pockle_free(Pockle *pockle);
|
||||
|
||||
/* Generate a certificate of primality for a prime already known to
|
||||
* the Pockle, in a format acceptable to Math::Prime::Util. */
|
||||
strbuf *pockle_mpu(Pockle *pockle, mp_int *p);
|
||||
|
||||
/* ----------------------------------------------------------------------
|
||||
* Callback API that allows key generation to report progress to its
|
||||
* caller.
|
||||
@ -243,6 +247,7 @@ struct PrimeGenerationPolicy {
|
||||
mp_int *(*generate)(
|
||||
PrimeGenerationContext *ctx,
|
||||
PrimeCandidateSource *pcs, ProgressReceiver *prog);
|
||||
strbuf *(*mpu_certificate)(PrimeGenerationContext *ctx, mp_int *p);
|
||||
|
||||
const void *extra; /* additional data a particular impl might need */
|
||||
};
|
||||
@ -259,6 +264,9 @@ static inline mp_int *primegen_generate(
|
||||
PrimeGenerationContext *ctx,
|
||||
PrimeCandidateSource *pcs, ProgressReceiver *prog)
|
||||
{ return ctx->vt->generate(ctx, pcs, prog); }
|
||||
static inline strbuf *primegen_mpu_certificate(
|
||||
PrimeGenerationContext *ctx, mp_int *p)
|
||||
{ return ctx->vt->mpu_certificate(ctx, p); }
|
||||
|
||||
extern const PrimeGenerationPolicy primegen_probabilistic;
|
||||
extern const PrimeGenerationPolicy primegen_provable_fast;
|
||||
|
14
sshprime.c
14
sshprime.c
@ -99,11 +99,17 @@ static mp_int *probprime_generate(
|
||||
}
|
||||
}
|
||||
|
||||
static strbuf *null_mpu_certificate(PrimeGenerationContext *ctx, mp_int *p)
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
const PrimeGenerationPolicy primegen_probabilistic = {
|
||||
probprime_add_progress_phase,
|
||||
probprime_new_context,
|
||||
probprime_free_context,
|
||||
probprime_generate,
|
||||
null_mpu_certificate,
|
||||
};
|
||||
|
||||
/* ----------------------------------------------------------------------
|
||||
@ -679,6 +685,13 @@ static mp_int *provableprime_generate(
|
||||
return p;
|
||||
}
|
||||
|
||||
static inline strbuf *provableprime_mpu_certificate(
|
||||
PrimeGenerationContext *ctx, mp_int *p)
|
||||
{
|
||||
ProvablePrimeContext *ppc = container_of(ctx, ProvablePrimeContext, pgc);
|
||||
return pockle_mpu(ppc->pockle, p);
|
||||
}
|
||||
|
||||
#define DECLARE_POLICY(name, policy) \
|
||||
static const struct ProvablePrimePolicyExtra \
|
||||
pppextra_##name = {policy}; \
|
||||
@ -687,6 +700,7 @@ static mp_int *provableprime_generate(
|
||||
provableprime_new_context, \
|
||||
provableprime_free_context, \
|
||||
provableprime_generate, \
|
||||
provableprime_mpu_certificate, \
|
||||
&pppextra_##name, \
|
||||
}
|
||||
|
||||
|
19
test/mpu-check.pl
Executable file
19
test/mpu-check.pl
Executable file
@ -0,0 +1,19 @@
|
||||
#!/usr/bin/perl
|
||||
|
||||
# Trivial command-line client for the function
|
||||
# Math::Prime::Util::verify_prime, which checks a certificate of
|
||||
# primality in MPU format.
|
||||
|
||||
use strict;
|
||||
use warnings;
|
||||
use Math::Prime::Util;
|
||||
|
||||
Math::Prime::Util::prime_set_config(verbose => 1);
|
||||
|
||||
my $cert = "";
|
||||
$cert .= $_ while <<>>;
|
||||
|
||||
my $success = Math::Prime::Util::verify_prime($cert);
|
||||
|
||||
die "verification failed\n" unless $success;
|
||||
warn "verification succeeded\n";
|
@ -269,6 +269,7 @@ FUNC1(opt_val_key, eddsa_generate, uint)
|
||||
FUNC2(val_rsa, rsa1_generate, uint, val_pgc)
|
||||
FUNC1(val_pgc, primegen_new_context, primegenpolicy)
|
||||
FUNC2(opt_val_mpint, primegen_generate, val_pgc, consumed_val_pcs)
|
||||
FUNC2(val_string, primegen_mpu_certificate, val_pgc, val_mpint)
|
||||
FUNC1(val_pcs, pcs_new, uint)
|
||||
FUNC3(val_pcs, pcs_new_with_firstbits, uint, uint, uint)
|
||||
FUNC3(void, pcs_require_residue, val_pcs, val_mpint, val_mpint)
|
||||
@ -283,6 +284,7 @@ FUNC1(uint, pockle_mark, val_pockle)
|
||||
FUNC2(void, pockle_release, val_pockle, uint)
|
||||
FUNC2(pocklestatus, pockle_add_small_prime, val_pockle, val_mpint)
|
||||
FUNC4(pocklestatus, pockle_add_prime, val_pockle, val_mpint, mpint_list, val_mpint)
|
||||
FUNC2(val_string, pockle_mpu, val_pockle, val_mpint)
|
||||
|
||||
/*
|
||||
* Miscellaneous.
|
||||
|
Loading…
Reference in New Issue
Block a user