mirror of
https://git.tartarus.org/simon/putty.git
synced 2025-06-30 19:12: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:
@ -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
|
||||
|
@ -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))
|
||||
|
||||
|
Reference in New Issue
Block a user