背景
为了好玩,我正在尝试编写一个 quick-check 属性,可以测试 使用 RSA 进行加密 的基本思想。
- 选择两个不同的质数
p
和q
。 - 令
N = p*q
e
是与(p-1)(q-1)
互质 的某个数字(实践中,e 通常取 3 以实现快速编码)。d
是对于模(p-1)(q-1)
,e
的 模反元素。
对于所有使得 1 < x < N
的 x
,恒有 (x^e)^d = x 模 N
换句话说,x
是“消息”,将其提高到模 N
的 e
次方是“编码”消息的行为,而将已编码的消息提高到模 N
的 d
次方是“解码”它的行为。
(该属性对于 x=1
也是显然成立的,这种情况下是自身加密)
代码
以下是我目前编写的方法:
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
(感谢Google和随机博客,提供模数乘法逆元的实现)
问题
问题显而易见:属性上有太多限制,使其无法使用。 尝试在ghci中调用quickCheck prop_rsa
会让我的终端挂起。
所以我在QuickCheck手册中找了一些信息,它说:
属性可以采取以下形式
forAll <generator> $ \<pattern> -> <property>
如何为质数创建一个<generator>
? 或者其他限制条件,这样quickCheck
就不必筛选出大量失败的条件了吗?
欢迎任何其他一般建议(特别是关于QuickCheck)。
q
和p
必须是不同的。在我有这个要求之前,它能够找到q == p
时失败的示例。 - Dan Burton