Merge pull request #125 from colatkinson/fix_prime_size
Fix generated primes being too large
This commit is contained in:
commit
d2a8763918
2
.gitignore
vendored
2
.gitignore
vendored
@ -10,3 +10,5 @@ QA
|
|||||||
benchs/Bench
|
benchs/Bench
|
||||||
benchs/Hash
|
benchs/Hash
|
||||||
*.sublime-workspace
|
*.sublime-workspace
|
||||||
|
.cabal-sandbox/
|
||||||
|
cabal.sandbox.config
|
||||||
|
|||||||
@ -43,6 +43,8 @@ data CryptoError =
|
|||||||
-- Message authentification error
|
-- Message authentification error
|
||||||
| CryptoError_MacKeyInvalid
|
| CryptoError_MacKeyInvalid
|
||||||
| CryptoError_AuthenticationTagSizeInvalid
|
| CryptoError_AuthenticationTagSizeInvalid
|
||||||
|
-- Prime generation error
|
||||||
|
| CryptoError_PrimeSizeInvalid
|
||||||
deriving (Show,Eq,Enum,Data,Typeable)
|
deriving (Show,Eq,Enum,Data,Typeable)
|
||||||
|
|
||||||
instance E.Exception CryptoError
|
instance E.Exception CryptoError
|
||||||
|
|||||||
@ -27,6 +27,7 @@ import Crypto.Number.Basic (sqrti, gcde)
|
|||||||
import Crypto.Number.ModArithmetic (expSafe)
|
import Crypto.Number.ModArithmetic (expSafe)
|
||||||
import Crypto.Random.Types
|
import Crypto.Random.Types
|
||||||
import Crypto.Random.Probabilistic
|
import Crypto.Random.Probabilistic
|
||||||
|
import Crypto.Error
|
||||||
|
|
||||||
import Data.Bits
|
import Data.Bits
|
||||||
|
|
||||||
@ -37,25 +38,48 @@ import Data.Bits
|
|||||||
isProbablyPrime :: Integer -> Bool
|
isProbablyPrime :: Integer -> Bool
|
||||||
isProbablyPrime !n
|
isProbablyPrime !n
|
||||||
| any (\p -> p `divides` n) (filter (< n) firstPrimes) = False
|
| any (\p -> p `divides` n) (filter (< n) firstPrimes) = False
|
||||||
| primalityTestFermat 50 (n`div`2) n = primalityTestMillerRabin 30 n
|
| n >= 2 && n <= 2903 = True
|
||||||
|
| primalityTestFermat 50 (n `div` 2) n = primalityTestMillerRabin 30 n
|
||||||
| otherwise = False
|
| otherwise = False
|
||||||
|
|
||||||
-- | generate a prime number of the required bitsize
|
-- | generate a prime number of the required bitsize (i.e. in the range
|
||||||
|
-- [2^(b-1)+2^(b-2), 2^b)).
|
||||||
|
--
|
||||||
|
-- May throw a CryptoError_PrimeSizeInvalid if the requested size is less
|
||||||
|
-- than 5 bits, as the smallest prime meeting these conditions is 29.
|
||||||
|
-- This function requires that the two highest bits are set, so that when
|
||||||
|
-- multiplied with another prime to create a key, it is guaranteed to be of
|
||||||
|
-- the proper size.
|
||||||
generatePrime :: MonadRandom m => Int -> m Integer
|
generatePrime :: MonadRandom m => Int -> m Integer
|
||||||
generatePrime bits = do
|
generatePrime bits = do
|
||||||
sp <- generateParams bits (Just SetTwoHighest) True
|
if bits < 5 then
|
||||||
return $ findPrimeFrom sp
|
throwCryptoError $ CryptoFailed $ CryptoError_PrimeSizeInvalid
|
||||||
|
else do
|
||||||
|
sp <- generateParams bits (Just SetTwoHighest) True
|
||||||
|
let prime = findPrimeFrom sp
|
||||||
|
if prime < 1 `shiftL` bits then
|
||||||
|
return $ prime
|
||||||
|
else generatePrime bits
|
||||||
|
|
||||||
-- | generate a prime number of the form 2p+1 where p is also prime.
|
-- | generate a prime number of the form 2p+1 where p is also prime.
|
||||||
-- it is also knowed as a Sophie Germaine prime or safe prime.
|
-- it is also knowed as a Sophie Germaine prime or safe prime.
|
||||||
--
|
--
|
||||||
-- The number of safe prime is significantly smaller to the number of prime,
|
-- The number of safe prime is significantly smaller to the number of prime,
|
||||||
-- as such it shouldn't be used if this number is supposed to be kept safe.
|
-- as such it shouldn't be used if this number is supposed to be kept safe.
|
||||||
|
--
|
||||||
|
-- May throw a CryptoError_PrimeSizeInvalid if the requested size is less than
|
||||||
|
-- 6 bits, as the smallest safe prime with the two highest bits set is 59.
|
||||||
generateSafePrime :: MonadRandom m => Int -> m Integer
|
generateSafePrime :: MonadRandom m => Int -> m Integer
|
||||||
generateSafePrime bits = do
|
generateSafePrime bits = do
|
||||||
sp <- generateParams bits (Just SetTwoHighest) True
|
if bits < 6 then
|
||||||
let p = findPrimeFromWith (\i -> isProbablyPrime (2*i+1)) (sp `div` 2)
|
throwCryptoError $ CryptoFailed $ CryptoError_PrimeSizeInvalid
|
||||||
return (2*p+1)
|
else do
|
||||||
|
sp <- generateParams bits (Just SetTwoHighest) True
|
||||||
|
let p = findPrimeFromWith (\i -> isProbablyPrime (2*i+1)) (sp `div` 2)
|
||||||
|
let val = 2 * p + 1
|
||||||
|
if val < 1 `shiftL` bits then
|
||||||
|
return $ val
|
||||||
|
else generateSafePrime bits
|
||||||
|
|
||||||
-- | find a prime from a starting point where the property hold.
|
-- | find a prime from a starting point where the property hold.
|
||||||
findPrimeFromWith :: (Integer -> Bool) -> Integer -> Integer
|
findPrimeFromWith :: (Integer -> Bool) -> Integer -> Integer
|
||||||
|
|||||||
@ -42,17 +42,19 @@ tests = testGroup "number"
|
|||||||
in 0 <= r && r < range
|
in 0 <= r && r < range
|
||||||
, testProperty "generate-prime" $ \testDRG (Int0_2901 baseBits') ->
|
, testProperty "generate-prime" $ \testDRG (Int0_2901 baseBits') ->
|
||||||
let baseBits = baseBits' `mod` 800
|
let baseBits = baseBits' `mod` 800
|
||||||
bits = 48 + baseBits -- no point generating lower than 48 bits ..
|
bits = 5 + baseBits -- generating lower than 5 bits causes an error ..
|
||||||
prime = withTestDRG testDRG $ generatePrime bits
|
prime = withTestDRG testDRG $ generatePrime bits
|
||||||
-- with small base bits numbers, the probability that we "cross" this bit size ness
|
in bits == numBits prime
|
||||||
-- to the next is quite high, as the number generated has two highest bit set.
|
, testProperty "generate-safe-prime" $ \testDRG (Int0_2901 baseBits') ->
|
||||||
--
|
let baseBits = baseBits' `mod` 200
|
||||||
in bits == numBits prime || (if baseBits < 64 then (bits + 1) == numBits prime else False)
|
bits = 6 + baseBits
|
||||||
|
prime = withTestDRG testDRG $ generateSafePrime bits
|
||||||
|
in bits == numBits prime
|
||||||
, testProperty "marshalling" $ \qaInt ->
|
, testProperty "marshalling" $ \qaInt ->
|
||||||
getQAInteger qaInt == os2ip (i2osp (getQAInteger qaInt) :: Bytes)
|
getQAInteger qaInt == os2ip (i2osp (getQAInteger qaInt) :: Bytes)
|
||||||
, testGroup "marshalling-kat-to-bytearray" $ map toSerializationKat $ zip [katZero..] serializationVectors
|
, testGroup "marshalling-kat-to-bytearray" $ map toSerializationKat $ zip [katZero..] serializationVectors
|
||||||
, testGroup "marshalling-kat-to-integer" $ map toSerializationKatInteger $ zip [katZero..] serializationVectors
|
, testGroup "marshalling-kat-to-integer" $ map toSerializationKatInteger $ zip [katZero..] serializationVectors
|
||||||
]
|
]
|
||||||
where
|
where
|
||||||
toSerializationKat (i, (sz, n, ba)) = testCase (show i) (ba @=? i2ospOf_ sz n)
|
toSerializationKat (i, (sz, n, ba)) = testCase (show i) (ba @=? i2ospOf_ sz n)
|
||||||
toSerializationKatInteger (i, (_, n, ba)) = testCase (show i) (n @=? os2ip ba)
|
toSerializationKatInteger (i, (_, n, ba)) = testCase (show i) (n @=? os2ip ba)
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user