From 2be70baa0d6bf727c815c0a3f98402d8d4d3b95c Mon Sep 17 00:00:00 2001 From: Simon Tatham Date: Sun, 23 Feb 2020 15:16:30 +0000 Subject: [PATCH] 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. --- Recipe | 2 +- pockle.c | 343 +++++++++++++++++++++++++++++++++++++++++++++ sshkeygen.h | 62 ++++++++ test/cryptsuite.py | 146 +++++++++++++++++++ test/testcrypt.py | 10 ++ testcrypt.c | 59 +++++++- testcrypt.h | 5 + 7 files changed, 621 insertions(+), 6 deletions(-) create mode 100644 pockle.c diff --git a/Recipe b/Recipe index 51b8c21c..7d6de75f 100644 --- a/Recipe +++ b/Recipe @@ -282,7 +282,7 @@ UXSSH = SSH uxnoise uxagentc uxgss uxshare SFTP = psftpcommon sftp sftpcommon logging cmdline # Components of the prime-generation system. -SSHPRIME = sshprime smallprimes primecandidate millerrabin mpunsafe +SSHPRIME = sshprime smallprimes primecandidate millerrabin pockle mpunsafe # Miscellaneous objects appearing in all the utilities, or all the # network ones, or the Unix or Windows subsets of those in turn. diff --git a/pockle.c b/pockle.c new file mode 100644 index 00000000..0aca8ecf --- /dev/null +++ b/pockle.c @@ -0,0 +1,343 @@ +#include +#include "ssh.h" +#include "sshkeygen.h" +#include "mpint.h" +#include "mpunsafe.h" +#include "tree234.h" + +struct Pockle { + tree234 *tree; + + mp_int **list; + size_t nlist, listsize; +}; + +static int mpcmp(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); +} + +Pockle *pockle_new(void) +{ + Pockle *pockle = snew(Pockle); + pockle->tree = newtree234(mpcmp); + pockle->list = NULL; + pockle->nlist = pockle->listsize = 0; + return pockle; +} + +void pockle_free(Pockle *pockle) +{ + for (mp_int *mp; (mp = delpos234(pockle->tree, 0)) != NULL ;) + mp_free(mp); + freetree234(pockle->tree); + sfree(pockle->list); + sfree(pockle); +} + +static PockleStatus pockle_insert(Pockle *pockle, mp_int *p) +{ + mp_int *copy = mp_copy(p); + mp_int *found = add234(pockle->tree, copy); + if (copy != found) { + mp_free(copy); /* it was already in there */ + return POCKLE_OK; + } + sgrowarray(pockle->list, pockle->listsize, pockle->nlist); + pockle->list[pockle->nlist++] = copy; + return POCKLE_OK; +} + +size_t pockle_mark(Pockle *pockle) +{ + return pockle->nlist; +} + +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); + } +} + +PockleStatus pockle_add_small_prime(Pockle *pockle, mp_int *p) +{ + if (mp_hs_integer(p, (1ULL << 32))) + return POCKLE_SMALL_PRIME_NOT_SMALL; + + uint32_t val = mp_get_integer(p); + + if (val < 2) + return POCKLE_PRIME_SMALLER_THAN_2; + + init_smallprimes(); + for (size_t i = 0; i < NSMALLPRIMES; i++) { + if (val == smallprimes[i]) + break; /* success */ + if (val % smallprimes[i] == 0) + return POCKLE_SMALL_PRIME_NOT_PRIME; + } + + return pockle_insert(pockle, p); +} + +PockleStatus pockle_add_prime(Pockle *pockle, mp_int *p, + mp_int **factors, size_t nfactors, + mp_int *witness) +{ + MontyContext *mc = NULL; + mp_int *x = NULL, *f = NULL, *w = NULL; + PockleStatus status; + + /* + * We're going to try to verify that p is prime by using + * Pocklington's theorem. The idea is that we're given w such that + * w^{p-1} == 1 (mod p) (1) + * and for a collection of primes q | p-1, + * w^{(p-1)/q} - 1 is coprime to p. (2) + * + * Suppose r is a prime factor of p itself. Consider the + * multiplicative order of w mod r. By (1), r | w^{p-1}-1. But by + * (2), r does not divide w^{(p-1)/q}-1. So the order of w mod r + * is a factor of p-1, but not a factor of (p-1)/q. Hence, the + * largest power of q that divides p-1 must also divide ord w. + * + * Repeating this reasoning for all q, we find that the product of + * all the q (which we'll denote f) must divide ord w, which in + * turn divides r-1. So f | r-1 for any r | p. + * + * In particular, this means f < r. That is, all primes r | p are + * bigger than f. So if f > sqrt(p), then we've shown p is prime, + * because otherwise it would have to be the product of at least + * two factors bigger than its own square root. + * + * With an extra check, we can also show p to be prime even if + * we're only given enough factors to make f > cbrt(p). See below + * for that part, when we come to it. + */ + + /* + * Start by checking p > 1. It certainly can't be prime otherwise! + * (And since we're going to prove it prime by showing all its + * prime factors are large, we do also have to know it _has_ at + * least one prime factor for that to tell us anything.) + */ + if (!mp_hs_integer(p, 2)) + return POCKLE_PRIME_SMALLER_THAN_2; + + /* + * Check that all the factors we've been given really are primes + * (in the sense that we already had them in our index). Make the + * product f, and check it really does divide p-1. + */ + x = mp_copy(p); + mp_sub_integer_into(x, x, 1); + f = mp_from_integer(1); + for (size_t i = 0; i < nfactors; i++) { + mp_int *q = factors[i]; + + if (!find234(pockle->tree, q, NULL)) { + status = POCKLE_FACTOR_NOT_KNOWN_PRIME; + goto out; + } + + mp_int *quotient = mp_new(mp_max_bits(x)); + mp_int *residue = mp_new(mp_max_bits(q)); + mp_divmod_into(x, q, quotient, residue); + + unsigned exact = mp_eq_integer(residue, 0); + mp_free(residue); + + mp_free(x); + x = quotient; + + if (!exact) { + status = POCKLE_FACTOR_NOT_A_FACTOR; + goto out; + } + + mp_int *tmp = f; + f = mp_unsafe_shrink(mp_mul(tmp, q)); + mp_free(tmp); + } + + /* + * Check that f > cbrt(p). + */ + mp_int *f2 = mp_mul(f, f); + mp_int *f3 = mp_mul(f2, f); + bool too_big = mp_cmp_hs(p, f3); + mp_free(f3); + mp_free(f2); + if (too_big) { + status = POCKLE_PRODUCT_OF_FACTORS_TOO_SMALL; + goto out; + } + + /* + * Now do the extra check that allows us to get away with only + * having f > cbrt(p) instead of f > sqrt(p). + * + * If we can show that f | r-1 for any r | p, then we've ruled out + * p being a product of _more_ than two primes (because then it + * would be the product of at least three things bigger than its + * own cube root). But we still have to rule out it being a + * product of exactly two. + * + * Suppose for the sake of contradiction that p is the product of + * two prime factors. We know both of those factors would have to + * be congruent to 1 mod f. So we'd have to have + * + * p = (uf+1)(vf+1) = (uv)f^2 + (u+v)f + 1 (3) + * + * We can't have uv >= f, or else that expression would come to at + * least f^3, i.e. it would exceed p. So uv < f. Hence, u,v < f as + * well. + * + * Can we have u+v >= f? If we did, then we could write v >= f-u, + * and hence f > uv >= u(f-u). That can be rearranged to show that + * u^2 > (u-1)f; decrementing the LHS makes the inequality no + * longer necessarily strict, so we have u^2-1 >= (u-1)f, and + * dividing off u-1 gives u+1 >= f. But we know u < f, so the only + * way this could happen would be if u=f-1, which makes v=1. But + * _then_ (3) gives us p = (f-1)f^2 + f^2 + 1 = f^3+1. But that + * can't be true if f^3 > p. So we can't have u+v >= f either, by + * contradiction. + * + * After all that, what have we shown? We've shown that we can + * write p = (uv)f^2 + (u+v)f + 1, with both uv and u+v strictly + * less than f. In other words, if you write down p in base f, it + * has exactly three digits, and they are uv, u+v and 1. + * + * But that means we can _find_ u and v: we know p and f, so we + * can just extract those digits of p's base-f representation. + * Once we've done so, they give the sum and product of the + * potential u,v. And given the sum and product of two numbers, + * you can make a quadratic which has those numbers as roots. + * + * We don't actually have to _solve_ the quadratic: all we have to + * do is check if its discriminant is a perfect square. If not, + * we'll know that no integers u,v can match this description. + */ + { + /* We already have x = (p-1)/f. So we just need to write x in + * the form aF + b, and then we have a=uv and b=u+v. */ + mp_int *a = mp_new(mp_max_bits(x)); + mp_int *b = mp_new(mp_max_bits(f)); + mp_divmod_into(x, f, a, b); + assert(!mp_cmp_hs(a, f)); + assert(!mp_cmp_hs(b, f)); + + /* If a=0, then that means p < f^2, so we don't need to do + * this check at all: the straightforward Pocklington theorem + * is all we need. */ + if (!mp_eq_integer(a, 0)) { + /* Compute the discriminant b^2 - 4a. */ + mp_int *bsq = mp_mul(b, b); + mp_lshift_fixed_into(a, a, 2); + mp_int *discriminant = mp_sub(bsq, a); + + /* See if it's a perfect square. */ + mp_int *remainder = mp_new(mp_max_bits(discriminant)); + mp_int *root = mp_nthroot(discriminant, 2, remainder); + unsigned perfect_square = mp_eq_integer(remainder, 0); + mp_free(bsq); + mp_free(discriminant); + mp_free(root); + mp_free(remainder); + + if (perfect_square) { + mp_free(b); + mp_free(a); + status = POCKLE_DISCRIMINANT_IS_SQUARE; + goto out; + } + } + mp_free(b); + mp_free(a); + } + + /* + * Now we've done all the checks that are cheaper than a modpow, + * so we've ruled out as many things as possible before having to + * do any hard work. But there's nothing for it now: make a + * MontyContext. + */ + mc = monty_new(p); + w = monty_import(mc, witness); + + /* + * The initial Fermat check: is w^{p-1} itself congruent to 1 mod + * p? + */ + { + mp_int *pm1 = mp_copy(p); + mp_sub_integer_into(pm1, pm1, 1); + mp_int *power = monty_pow(mc, w, pm1); + unsigned fermat_pass = mp_cmp_eq(power, monty_identity(mc)); + mp_free(power); + mp_free(pm1); + + if (!fermat_pass) { + status = POCKLE_FERMAT_TEST_FAILED; + goto out; + } + } + + /* + * And now, for each factor q, is w^{(p-1)/q}-1 coprime to p? + */ + for (size_t i = 0; i < nfactors; i++) { + mp_int *q = factors[i]; + mp_int *exponent = mp_unsafe_shrink(mp_div(p, q)); + mp_int *power = monty_pow(mc, w, exponent); + mp_int *power_extracted = monty_export(mc, power); + mp_sub_integer_into(power_extracted, power_extracted, 1); + + unsigned coprime = mp_coprime(power_extracted, p); + if (!coprime) { + /* + * If w^{(p-1)/q}-1 is not coprime to p, the test has + * failed. But it makes a difference why. If the power of + * w turned out to be 1, so that we took gcd(1-1,p) = + * gcd(0,p) = p, that's like an inconclusive Fermat or M-R + * test: it might just mean you picked a witness integer + * that wasn't a primitive root. But if the power is any + * _other_ value mod p that is not coprime to p, it means + * we've detected that the number is *actually not prime*! + */ + if (mp_eq_integer(power_extracted, 0)) + status = POCKLE_WITNESS_POWER_IS_1; + else + status = POCKLE_WITNESS_POWER_NOT_COPRIME; + } + + mp_free(exponent); + mp_free(power); + mp_free(power_extracted); + + if (!coprime) + goto out; /* with the status we set up above */ + } + + /* + * Success! p is prime. Insert it into our tree234 of known + * primes, so that future calls to this function can cite it in + * evidence of larger numbers' primality. + */ + status = pockle_insert(pockle, p); + + out: + if (x) + mp_free(x); + if (f) + mp_free(f); + if (w) + mp_free(w); + if (mc) + monty_free(mc); + return status; +} diff --git a/sshkeygen.h b/sshkeygen.h index 2565302a..cccb1fb2 100644 --- a/sshkeygen.h +++ b/sshkeygen.h @@ -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. diff --git a/test/cryptsuite.py b/test/cryptsuite.py index 190324ef..225b69e4 100755 --- a/test/cryptsuite.py +++ b/test/cryptsuite.py @@ -970,6 +970,152 @@ class keygen(MyTestBase): for p in [2,3,5,7,11,13,17,19,23,29,31,37,41,43,47,53,59,61]: self.assertNotEqual(n % p, 0) + def testPocklePositive(self): + def add_small(po, *ps): + for p in ps: + self.assertEqual(pockle_add_small_prime(po, p), 'POCKLE_OK') + def add(po, *args): + self.assertEqual(pockle_add_prime(po, *args), 'POCKLE_OK') + + # Transcription of the proof that 2^130-5 is prime from + # Theorem 3.1 from http://cr.yp.to/mac/poly1305-20050329.pdf + po = pockle_new() + p1 = (2**130 - 6) // 1517314646 + p2 = (p1 - 1) // 222890620702 + add_small(po, 37003, 221101) + add(po, p2, [37003, 221101], 2) + add(po, p1, [p2], 2) + add(po, 2**130 - 5, [p1], 2) + + # My own proof that 2^255-19 is prime + po = pockle_new() + p1 = 8574133 + p2 = 1919519569386763 + p3 = 75445702479781427272750846543864801 + p4 = (2**255 - 20) // (65147*12) + p = 2**255 - 19 + add_small(po, p1) + add(po, p2, [p1], 2) + add(po, p3, [p2], 2) + add(po, p4, [p3], 2) + add(po, p, [p4], 2) + + # And the prime used in Ed448, while I'm here + po = pockle_new() + p1 = 379979 + p2 = 1764234391 + p3 = 97859369123353 + p4 = 34741861125639557 + p5 = 36131535570665139281 + p6 = 167773885276849215533569 + p7 = 596242599987116128415063 + p = 2**448 - 2**224 - 1 + add_small(po, p1, p2) + add(po, p3, [p1], 2) + add(po, p4, [p2], 2) + add(po, p5, [p4], 2) + add(po, p6, [p3], 3) + add(po, p7, [p5], 3) + add(po, p, [p6, p7], 2) + + p = 4095744004479977 + factors = [2, 79999] # just enough factors to exceed cbrt(p) + po = pockle_new() + for q in factors: + add_small(po, q) + add(po, p, factors, 3) + + # The order of the generator in Ed25519 + po = pockle_new() + p1a, p1b = 132667, 137849 + p2 = 3044861653679985063343 + p3 = 198211423230930754013084525763697 + p = 2**252 + 0x14def9dea2f79cd65812631a5cf5d3ed + add_small(po, p1a, p1b) + add(po, p2, [p1a, p1b], 2) + add(po, p3, [p2], 2) + add(po, p, [p3], 2) + + # And the one in Ed448 + po = pockle_new() + p1 = 766223 + p2 = 3009341 + p3 = 7156907 + p4 = 671065561 + p5 = 342682509629 + p6 = 6730519843040614479184435237013 + p = 2**446 - 0x8335dc163bb124b65129c96fde933d8d723a70aadc873d6d54a7bb0d + add_small(po, p1, p2, p3, p4) + add(po, p5, [p1], 2) + add(po, p6, [p3,p4], 2) + add(po, p, [p2,p5,p6], 2) + + def testPockleNegative(self): + def add_small(po, p): + self.assertEqual(pockle_add_small_prime(po, p), 'POCKLE_OK') + + po = pockle_new() + self.assertEqual(pockle_add_small_prime(po, 0), + 'POCKLE_PRIME_SMALLER_THAN_2') + self.assertEqual(pockle_add_small_prime(po, 1), + 'POCKLE_PRIME_SMALLER_THAN_2') + self.assertEqual(pockle_add_small_prime(po, 2**61 - 1), + 'POCKLE_SMALL_PRIME_NOT_SMALL') + self.assertEqual(pockle_add_small_prime(po, 4), + 'POCKLE_SMALL_PRIME_NOT_PRIME') + + po = pockle_new() + self.assertEqual(pockle_add_prime(po, 1919519569386763, [8574133], 2), + 'POCKLE_FACTOR_NOT_KNOWN_PRIME') + + po = pockle_new() + add_small(po, 8574133) + self.assertEqual(pockle_add_prime(po, 1919519569386765, [8574133], 2), + 'POCKLE_FACTOR_NOT_A_FACTOR') + + p = 4095744004479977 + factors = [2, 79997] # not quite enough factors to reach cbrt(p) + po = pockle_new() + for q in factors: + add_small(po, q) + self.assertEqual(pockle_add_prime(po, p, factors, 3), + 'POCKLE_PRODUCT_OF_FACTORS_TOO_SMALL') + + p = 1999527 * 3999053 + factors = [999763] + po = pockle_new() + for q in factors: + add_small(po, q) + self.assertEqual(pockle_add_prime(po, p, factors, 3), + 'POCKLE_DISCRIMINANT_IS_SQUARE') + + p = 9999929 * 9999931 + factors = [257, 2593] + po = pockle_new() + for q in factors: + add_small(po, q) + self.assertEqual(pockle_add_prime(po, p, factors, 3), + 'POCKLE_FERMAT_TEST_FAILED') + + p = 1713000920401 # a Carmichael number + po = pockle_new() + add_small(po, 561787) + self.assertEqual(pockle_add_prime(po, p, [561787], 2), + 'POCKLE_WITNESS_POWER_IS_1') + + p = 4294971121 + factors = [3, 5, 11, 17] + po = pockle_new() + for q in factors: + add_small(po, q) + self.assertEqual(pockle_add_prime(po, p, factors, 17), + 'POCKLE_WITNESS_POWER_NOT_COPRIME') + + po = pockle_new() + add_small(po, 2) + self.assertEqual(pockle_add_prime(po, 1, [2], 1), + 'POCKLE_PRIME_SMALLER_THAN_2') + class crypt(MyTestBase): def testSSH1Fingerprint(self): # Example key and reference fingerprint value generated by diff --git a/test/testcrypt.py b/test/testcrypt.py index de27ee38..5767f558 100644 --- a/test/testcrypt.py +++ b/test/testcrypt.py @@ -105,6 +105,7 @@ method_prefixes = { 'val_rsakex': 'ssh_rsakex_', 'val_prng': 'prng_', 'val_pcs': 'pcs_', + 'val_pockle': 'pockle_', } method_lists = {t: [] for t in method_prefixes} @@ -181,6 +182,13 @@ def make_argword(arg, argtype, fnname, argindex, to_preserve): arg = unicode_to_bytes(arg) if isinstance(arg, bytes) and b" " not in arg: return arg + if typename == "mpint_list": + sublist = [make_argword(len(arg), ("uint", False), + fnname, argindex, to_preserve)] + for val in arg: + sublist.append(make_argword(val, ("val_mpint", False), + fnname, argindex, to_preserve)) + return b" ".join(unicode_to_bytes(sub) for sub in sublist) raise TypeError( "Can't convert {}() argument {:d} to {} (value was {!r})".format( fnname, argindex, typename, arg)) @@ -227,6 +235,8 @@ def make_retval(rettype, word, unpack_strings): elif rettype == "boolean": assert word == b"true" or word == b"false" return word == b"true" + elif rettype == "pocklestatus": + return word.decode("ASCII") raise TypeError("Can't deal with return value {!r} of type {!r}" .format(word, rettype)) diff --git a/testcrypt.c b/testcrypt.c index c2c1e3cd..40108704 100644 --- a/testcrypt.c +++ b/testcrypt.c @@ -96,6 +96,7 @@ uint64_t prng_reseed_time_ms(void) X(keycomponents, key_components *, key_components_free(v)) \ X(pcs, PrimeCandidateSource *, pcs_free(v)) \ X(pgc, PrimeGenerationContext *, primegen_free_context(v)) \ + X(pockle, Pockle *, pockle_free(v)) \ /* end of list */ typedef struct Value Value; @@ -440,6 +441,11 @@ static void finaliser_return_value(strbuf *out, void *ctx) put_byte(out, '\n'); } +static void finaliser_sfree(strbuf *out, void *ctx) +{ + sfree(ctx); +} + #define VALTYPE_GETFN(n,t,f) \ static Value *unwrap_value_##n(Value *val) { \ ValueType expected = VT_##n; \ @@ -483,6 +489,26 @@ static mp_int **get_out_val_mpint(BinarySource *in) return &val->vu_mpint; } +struct mpint_list { + size_t n; + mp_int **integers; +}; + +static struct mpint_list get_mpint_list(BinarySource *in) +{ + size_t n = get_uint(in); + + struct mpint_list mpl; + mpl.n = n; + + mpl.integers = snewn(n, mp_int *); + for (size_t i = 0; i < n; i++) + mpl.integers[i] = get_val_mpint(in); + + add_finaliser(finaliser_sfree, mpl.integers); + return mpl; +} + static void finaliser_return_uint(strbuf *out, void *ctx) { unsigned *uval = (unsigned *)ctx; @@ -546,11 +572,6 @@ static const char **get_out_opt_val_string_asciz_const(BinarySource *in) return valp; } -static void finaliser_sfree(strbuf *out, void *ctx) -{ - sfree(ctx); -} - static BinarySource *get_val_string_binarysource(BinarySource *in) { strbuf *sb = get_val_string(in); @@ -588,6 +609,25 @@ static void return_boolean(strbuf *out, bool b) strbuf_catf(out, "%s\n", b ? "true" : "false"); } +static void return_pocklestatus(strbuf *out, PockleStatus status) +{ + switch (status) { + default: + strbuf_catf(out, "POCKLE_BAD_STATUS_VALUE\n"); + break; + +#define STATUS_CASE(id) \ + case id: \ + strbuf_catf(out, "%s\n", #id); \ + break; + + POCKLE_STATUSES(STATUS_CASE); + +#undef STATUS_CASE + + } +} + static void return_val_string_asciz_const(strbuf *out, const char *s) { strbuf *sb = strbuf_new(); @@ -1147,6 +1187,13 @@ mp_int *key_components_nth_mp(key_components *kc, size_t n) mp_copy(kc->components[n].mp)); } +PockleStatus pockle_add_prime_wrapper(Pockle *pockle, mp_int *p, + struct mpint_list mpl, mp_int *witness) +{ + return pockle_add_prime(pockle, p, mpl.integers, mpl.n, witness); +} +#define pockle_add_prime pockle_add_prime_wrapper + #define OPTIONAL_PTR_FUNC(type) \ typedef TD_val_##type TD_opt_val_##type; \ static TD_opt_val_##type get_opt_val_##type(BinarySource *in) { \ @@ -1179,6 +1226,8 @@ typedef const ssh_kex *TD_ecdh_alg; typedef RsaSsh1Order TD_rsaorder; typedef key_components *TD_keycomponents; typedef const PrimeGenerationPolicy *TD_primegenpolicy; +typedef struct mpint_list TD_mpint_list; +typedef PockleStatus TD_pocklestatus; #define FUNC0(rettype, function) \ static void handle_##function(BinarySource *in, strbuf *out) { \ diff --git a/testcrypt.h b/testcrypt.h index 1eca3759..89cbaadf 100644 --- a/testcrypt.h +++ b/testcrypt.h @@ -277,6 +277,11 @@ FUNC3(void, pcs_avoid_residue_small, val_pcs, uint, uint) 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) +FUNC0(val_pockle, pockle_new) +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) /* * Miscellaneous.