1
0
mirror of https://git.tartarus.org/simon/putty.git synced 2025-06-30 19:12:48 -05:00

Add some tests of Miller-Rabin to cryptsuite.

I'm about to rewrite the Miller-Rabin testing code, so let's start by
introducing a test suite that the old version passes, and then I can
make sure the new one does too.
This commit is contained in:
Simon Tatham
2021-08-27 17:43:40 +01:00
parent 59409d0947
commit 23431f8ff4
6 changed files with 112 additions and 8 deletions

View File

@ -1188,6 +1188,73 @@ class keygen(MyTestBase):
self.assertEqual(pockle_add_prime(po, 1, [2], 1),
'POCKLE_PRIME_SMALLER_THAN_2')
def testMillerRabin(self):
# A prime congruent to 3 mod 4, so M-R can only do one
# iteration: either a^{(p-1)/2} == +1, or -1. Either counts as
# a pass; the latter also means the number is potentially a
# primitive root.
n = 0xe76e6aaa42b5d7423aa4da5613eb21c3
mr = miller_rabin_new(n)
self.assertEqual(miller_rabin_test(mr, 2), "passed+ppr")
self.assertEqual(miller_rabin_test(mr, 4), "passed")
# The 'potential primitive root' test only means that M-R
# didn't _rule out_ the number being a primitive root, by
# finding that any of the powers _it tested_ less than n-1
# came out to be 1. In this case, 2 really is a primitive
# root, but since 13 | n-1, the 13th powers mod n form a
# multiplicative subgroup. So 2^13 is not a primitive root,
# and yet, M-R can't tell the difference, because it only
# tried the exponent (n-1)/2, not the actual counterexample
# (n-1)/13.
self.assertEqual(miller_rabin_test(mr, 2**13), "passed+ppr")
# A prime congruent to 1 mod a reasonably large power of 2, so
# M-R has lots of scope to have different things happen. 3 is
# a primitive root, so we expect that 3, 3^2, 3^4, ..., 3^256
# should all pass for different reasons, with only the first
# of them returning passed+ppr.
n = 0xb1b65ebe489ff0ab4597bb67c3d22d01
mr = miller_rabin_new(n)
w = 3
self.assertEqual(miller_rabin_test(mr, w), "passed+ppr")
for i in range(1, 10):
w = w * w % n
self.assertEqual(miller_rabin_test(mr, w), "passed")
# A prime with an _absurdly_ large power-of-2 factor in its
# multiplicative group.
n = 0x600000000000000000000000000000000000000000000001
mr = miller_rabin_new(n)
w = 10
self.assertEqual(miller_rabin_test(mr, w), "passed+ppr")
for i in range(1, 200):
w = w * w % n
self.assertEqual(miller_rabin_test(mr, w), "passed")
# A blatantly composite number. But we still expect to see a
# pass if we give the witness 1 (which will give a maximal
# trailing string of 1s), or -1 (which will give -1 when
# raised to the maximal odd factor of n-1, or indeed any other
# odd power).
n = 0x1010101010101010101010101010101
mr = miller_rabin_new(n)
self.assertEqual(miller_rabin_test(mr, 1), "passed")
self.assertEqual(miller_rabin_test(mr, n-1), "passed")
self.assertEqual(miller_rabin_test(mr, 2), "failed")
# A Carmichael number, as a proper test that M-R detects
# things the Fermat test would not.
#
# (Its prime factorisation is 26823115100268314289505807 *
# 53646230200536628579011613 * 80469345300804942868517419,
# which is enough to re-check its Carmichaelness.)
n = 0xffffffffffffffffcf8032f3e044b4a8b1b1bf0b526538eae953d90f44d65511
mr = miller_rabin_new(n)
self.assertEqual(miller_rabin_test(mr, 16), "passed")
assert(pow(2, n-1, n) == 1) # Fermat test would pass, but ...
self.assertEqual(miller_rabin_test(mr, 2), "failed") # ... this fails
class crypt(MyTestBase):
def testSSH1Fingerprint(self):
# Example key and reference fingerprint value generated by

View File

@ -235,7 +235,7 @@ 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":
elif rettype in {"pocklestatus", "mr_result"}:
return word.decode("ASCII")
raise TypeError("Can't deal with return value {!r} of type {!r}"
.format(word, rettype))