【问题标题】:Use QuickCheck by generating primes通过生成素数使用 QuickCheck
【发布时间】:2011-02-20 04:49:14
【问题描述】:

背景

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

  • 选择两个不同的素数,pq
  • N = p*q
  • erelatively prime(p-1)(q-1) 的某个数字(实际上,对于快速编码,e 通常为 3)
  • de(p-1)(q-1)modular inverse

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

换句话说,x 是“消息”,将其提升到 eth 幂 mod N 是“编码”消息的行为,并将编码后的消息提升到 dth 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

(感谢谷歌和随机博客,implementation of modular multiplicative inverse

问题

问题应该很明显:该属性的条件太多,无法使其完全可用。尝试在 ghci 中调用 quickCheck prop_rsa 使我的终端挂起。

所以我在QuickCheck manual 周围戳了一下,它说:

属性可以采用以下形式

forAll &lt;generator&gt; $ \&lt;pattern&gt; -&gt; &lt;property&gt;

如何为素数创建&lt;generator&gt;?或者使用其他约束,让quickCheck 不必筛选一堆失败的条件?

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

【问题讨论】:

  • 有趣的事实:QuickCheck 帮助我看到 qp 必须是不同的。在我有这个要求之前,它能够在q == p 时找到失败的例子
  • 道具人,这是一个很好的问题。很少有人会花这么多精力来传达他们想知道的东西。点赞。
  • 您可以使用 Rabin-Miller 概率检验; mathworld.wolfram.com/Rabin-MillerStrongPseudoprimeTest.html
  • 刚刚在这里找到了 Rabin-Miller 测试的实现:bonsaicode.wordpress.com/2009/05/01/…
  • @Paul 非常好!我一直在努力调整测试,使其只使用小的素数,主要是因为测试更大的素数变得很麻烦。我将看看将其应用到我的代码中。

标签: haskell properties rsa generator quickcheck


【解决方案1】:

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

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

为了您的使用,您可以在您的资源中将 pq 替换为 (Prime p)(Prime q)

【讨论】:

  • 您可能希望使用库代码作为素数,它应该会快很多:hackage.haskell.org/package/primes
  • @barsoap 可能比我或 jacobm 写的要好,但 isPrime 的文档目前说,“对于具有非常大的最小素因数的数字是不切实际的。”维基百科有很多关于更快primality tests 的有趣信息,我可能会尝试。
  • 这是一个很好的答案;我试了一下,效果还不错。但并不完全符合我的要求。我对在这里使用forAll 特别感兴趣。受您的回答启发,我实际上想出了一些东西,但我想在发布之前等待,看看其他人是否有深刻的见解。
【解决方案2】:

好的,这就是我所做的。

文件顶部

{-# 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 -&gt; Gen Int。我不确定forAll 背后的魔力是什么,但我很确定这是正确的。我已经对 1) 进行了一些临时调整,以确保在我弄乱条件时它会失败,以及 2) 确保嵌套的 forAll 在测试用例中改变 x 的值。

以下是如何编写这些生成器。一旦我意识到文档中的&lt;generator&gt; 只是意味着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&lt;$&gt;&lt;*&gt;。我将计算限制为仅从前 2500 个素数中选择;否则它显然想挑选一些需要很长时间才能生成的非常大的东西。

随机注意事项

由于懒惰,除非满足条件,否则不会计算 d = mInverse e t。这很好,因为当条件rPrime e t 为假时它是未定义的。在英语中,整数a 只有在ab 互质时才有乘法逆元(mod b)。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-02-11
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多