1
0
mirror of https://git.tartarus.org/simon/putty.git synced 2025-07-05 13:32:48 -05:00

New 'Pockle' object, for verifying primality.

This implements an extended form of primality verification using
certificates based on Pocklington's theorem. You make a Pockle object,
and then try to convince it that one number after another is prime, by
means of providing it with a list of prime factors of p-1 and a
primitive root. (Or just by saying 'this prime is small enough for you
to check yourself'.)

Pocklington's theorem requires you to have factors of p-1 whose
product is at least the square root of p. I've extended that to
support factorisations only as big as the cube root, via an extension
of the theorem given in Maurer's paper on generating provable primes.

The Pockle object is more or less write-only: it has no methods for
reading out its contents. Its only output channel is the return value
when you try to insert a prime into it: if it isn't sufficiently
convinced that your prime is prime, it will return an error code. So
anything for which it returns POCKLE_OK you can be confident of.

I'm going to use this for provable prime generation. But exposing this
part of the system as an object in its own right means I can write a
set of unit tests for this specifically. My negative tests exercise
all the different ways a certification can be erroneous or inadequate;
the positive tests include proofs of primality of various primes used
in elliptic-curve crypto. The Poly1305 proof in particular is taken
from a proof in DJB's paper, which has exactly the form of a
Pocklington certificate only written in English.
This commit is contained in:
Simon Tatham
2020-02-23 15:16:30 +00:00
parent 20a9912c7c
commit 2be70baa0d
7 changed files with 621 additions and 6 deletions

View File

@ -92,6 +92,68 @@ unsigned miller_rabin_checks_needed(unsigned bits);
* that proves the number to be composite. */
mp_int *miller_rabin_find_potential_primitive_root(MillerRabin *mr);
/* ----------------------------------------------------------------------
* A system for proving numbers to be prime, using the Pocklington
* test, which requires knowing a partial factorisation of p-1
* (specifically, factors whose product is at least cbrt(p)) and a
* primitive root.
*
* The API consists of instantiating a 'Pockle' object, which
* internally stores a list of numbers you've already convinced it is
* prime, and can accept further primes if you give a satisfactory
* certificate of their primality based on primes it already knows
* about.
*/
typedef struct Pockle Pockle;
/* In real use, you only really need to know whether the Pockle
* successfully accepted your prime. But for testcrypt, it's useful to
* expose many different failure modes so we can try to provoke them
* all in unit tests and check they're working. */
#define POCKLE_STATUSES(X) \
X(POCKLE_OK) \
X(POCKLE_SMALL_PRIME_NOT_SMALL) \
X(POCKLE_SMALL_PRIME_NOT_PRIME) \
X(POCKLE_PRIME_SMALLER_THAN_2) \
X(POCKLE_FACTOR_NOT_KNOWN_PRIME) \
X(POCKLE_FACTOR_NOT_A_FACTOR) \
X(POCKLE_PRODUCT_OF_FACTORS_TOO_SMALL) \
X(POCKLE_FERMAT_TEST_FAILED) \
X(POCKLE_DISCRIMINANT_IS_SQUARE) \
X(POCKLE_WITNESS_POWER_IS_1) \
X(POCKLE_WITNESS_POWER_NOT_COPRIME) \
/* end of list */
#define DEFINE_ENUM(id) id,
typedef enum PockleStatus { POCKLE_STATUSES(DEFINE_ENUM) } PockleStatus;
#undef DEFINE_ENUM
/* Make a new empty Pockle, containing no primes. */
Pockle *pockle_new(void);
/* Insert a prime below 2^32 into the Pockle. No evidence is required:
* Pockle will check it itself. */
PockleStatus pockle_add_small_prime(Pockle *pockle, mp_int *p);
/* Insert a general prime into the Pockle. You must provide a list of
* prime factors of p-1, whose product exceeds the cube root of p, and
* also a primitive root mod p. */
PockleStatus pockle_add_prime(Pockle *pockle, mp_int *p,
mp_int **factors, size_t nfactors,
mp_int *primitive_root);
/* If you call pockle_mark, and later pass the returned value to
* pockle_release, it will free all the primes that were added to the
* Pockle between those two calls. Useful in recursive algorithms, to
* stop the Pockle growing unboundedly if the recursion keeps having
* to backtrack. */
size_t pockle_mark(Pockle *pockle);
void pockle_release(Pockle *pockle, size_t mark);
/* Free a Pockle. */
void pockle_free(Pockle *pockle);
/* ----------------------------------------------------------------------
* Callback API that allows key generation to report progress to its
* caller.