バックグラウンド
楽しみのために、RSAを使用した暗号化の背後にある基本的な考え方をテストできるクイックチェック用のプロパティを作成しようとしています。
- 2つの異なる素数、
p
およびを選択しq
ます。 - させて
N = p*q
e
互いに素な数です(p-1)(q-1)
(実際には、高速エンコーディングの場合、eは通常3です)d
モジュロのモジュラ逆数ですe
(p-1)(q-1)
x
そのようなすべてのために1 < x < N
、それは常に真実です(x^e)^d = x modulo N
言い換えると、x
は「メッセージ」であり、それをe
3乗modに上げることN
はメッセージを「エンコード」する行為であり、エンコードされたメッセージをd
3乗modに上げることN
はそれを「デコード」する行為です。
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
(モジュラ逆数の実装に感謝します、グーグルとランダムブログ)
質問
問題は明らかなはずです。プロパティには条件が多すぎて、まったく使用できない状態になっています。quickCheck prop_rsa
ghciで呼び出そうとすると、端末がハングしました。
そこで、QuickCheckのマニュアルを少し調べてみたところ、次のようになっています。
プロパティは次の形式をとることがあります
forAll <generator> $ \<pattern> -> <property>
<generator>
素数のを作成するにはどうすればよいですか?または他の制約があるので、quickCheck
失敗した状態の束をふるいにかける必要はありませんか?
その他の一般的なアドバイス(特にQuickCheckに関する)は大歓迎です。