Background
For fun, I'm trying to write a property for quick-check that can test the basic idea behind cryptography with RSA.
- Choose two distinct primes,
p
andq
. - Let
N = p*q
e
is some number relatively prime to(p-1)(q-1)
(in practice, e is usually 3 for fast encoding)d
is the modular inverse ofe
modulo(p-1)(q-1)
For all x
such that 1 < x < N
, it is always true that (x^e)^d = x modulo N
In other words, x
is the "message", raising it to the e
th power mod N
is the act of "encoding" the message, and raising the encoded message to the d
th power mod N
is the act of "decoding" it.
(The property is also trivially true for x = 1
, a case which is its own encryption)
Code
Here are the methods I have coded up so far:
import Test.QuickCheck
-- modular exponentiation
modExp :: Integral a => a -> a -> a -> a
modExp y z n = modExp' (y `mod` n) z `mod` n
where modExp' y z | z == 0 = 1
| even z = modExp (y*y) (z `div` 2) n
| odd z = (modExp (y*y) (z `div` 2) n) * y
-- relatively prime
rPrime :: Integral a => a -> a -> Bool
rPrime a b = gcd a b == 1
-- multiplicative inverse (modular)
mInverse :: Integral a => a -> a -> a
mInverse 1 _ = 1
mInverse x y = (n * y + 1) `div` x
where n = x - mInverse (y `mod` x) x
-- just a quick way to test for primality
n `divides` x = x `mod` n == 0
primes = 2:filter isPrime [3..]
isPrime x = null . filter (`divides` x) $ takeWhile (\y -> y*y <= x) primes
-- the property
prop_rsa (p,q,x) = isPrime p &&
isPrime q &&
p /= q &&
x > 1 &&
x < n &&
rPrime e t ==>
x == (x `powModN` e) `powModN` d
where e = 3
n = p*q
t = (p-1)*(q-1)
d = mInverse e t
a `powModN` b = modExp a b n
(Thanks, google and random blog, for the implementation of modular multiplicative inverse)
Question
The problem should be obvious: there are way too many conditions on the property to make it at all usable. Trying to invoke quickCheck prop_rsa
in ghci made my terminal hang.
So I've poked around the QuickCheck manual a bit, and it says:
Properties may take the form
forAll <generator> $ \<pattern> -> <property>
How do I make a <generator>
for prime numbers? Or with the other constraints, so that quickCheck
doesn't have to sift through a bunch of failed conditions?
Any other general advice (especially regarding QuickCheck) is welcome.
q
andp
must be distinct. Before I had that requirement, it was able to find examples that failed the prop whenq == p
– Timekeeper