繁体   English   中英

通过生成素数来使用QuickCheck

[英]Use QuickCheck by generating primes

背景

为了好玩,我正在尝试编写一个用于快速检查的属性,可以使用RSA测试加密技术背后的基本思想。

  • 选择两个不同的素数, pq
  • N = p*q
  • e(p-1)(q-1)一些相对素数 (p-1)(q-1)实际上,对于快速编码,e通常为3)
  • de modulo (p-1)(q-1)模逆

对于所有x使得1 < x < N(x^e)^d = x modulo N总是正确的

换句话说, x是“消息”,将其提升到e th power mod N是“编码”消息的行为,并且将编码消息提升到d th power 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

(谢谢,google和随机博客,用于模块乘法逆实现

问题应该是显而易见的:财产上有太多条件使其完全可用。 试图在ghci中调用quickCheck prop_rsa使我的终端挂起。

所以我在QuickCheck手册上略微探讨了一下,它说:

属性可以采取形式

forAll <generator> $ \\<pattern> -> <property>

如何为素数制作<generator> 或者使用其他约束,以便quickCheck不必筛选出一堆失败的条件?

欢迎任何其他一般性建议(特别是关于QuickCheck)。

这是制作与QuickCheck兼容的素数生成器的一种方法(从http://en.literateprograms.org/Sieve_of_Eratosthenes_(Haskell )窃取Eratosthenes实施的Sieve):

import Test.QuickCheck

newtype Prime = Prime Int deriving Show

primes = sieve [2..]
    where
      sieve (p:xs) = Prime p : sieve [x | x <- xs, x `mod` p > 0]

instance Arbitrary Prime where
    arbitrary = do i <- arbitrary
                   return $ primes!!(abs i)

它可以在QuickCheck中使用,如下所示:

prop_primes_dont_divide (Prime x) (Prime y) = x == y || x `mod` y > 0

为了您的使用,您可以在您的财产中用(Prime p)(Prime q)替换pq

好的,这就是我做的。

文件顶部

{-# LANGUAGE NoMonomorphismRestriction #-}

import Test.QuickCheck
import Control.Applicative

问题中给出的所有代码,prop_rsa除外。 那(显然)经过了大量修改:

prop_rsa = forAll primePair $ \(p,q) ->
           let n = p*q
           in forAll (genUnder n) $ \x  ->
              let e = 3
                  t = (p-1)*(q-1)
                  d = mInverse e t
                  a `powModN` b = modExp a b n
              in p /= q &&
                 rPrime e t ==>
                 x == (x `powModN` e) `powModN` d

primePair的类型是Gen (Int, Int)genUnder的类型是Int -> Gen Int 我不太确定神奇的是背后究竟forAll但我敢肯定,这是正确的。 我已经做了一些临时调整1)确保它失败如果我弄乱条件和2)确保嵌套的forAllforAll中改变x的值。

所以这里是如何编写这些生成器。 一旦我意识到文档中的<generator>只是意味着Gen a的类型,那就是蛋糕。

genNonzero = (\x -> if x == 0 then 1 else x) `fmap` arbitrary
genUnder :: Int -> Gen Int
genUnder n = ((`mod` n) . abs) `fmap` genNonzero

genSmallPrime = ((\x -> (primes !! (x `mod` 2500))) . abs) `fmap` arbitrary

primePair :: Gen (Int, Int)
primePair = (,) <$> genSmallPrime <*> genSmallPrime

primePair采取了一些试验和错误让我做对了; 我知道像这样的组合器应该可以工作,但我仍然不像我想的那样熟悉fmap<$><*> 我将计算限制为仅从前2500个素数中选择; 否则它显然想要选择一些非常重要的产品。

随意的事情要注意

由于懒惰,除非满足条件,否则不计算d = mInverse et 哪个好,因为当条件rPrime et为假时,它是未定义的。 在英语中,当ab是相对素数时,整数a仅具有乘法逆(mod b)。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM