crypto-numbers 0.2.2 → 0.2.3
raw patch · 8 files changed
+117/−15 lines, 8 filesdep ~base
Dependency ranges changed: base
Files
- Crypto/Number/Basic.hs +3/−0
- Crypto/Number/F2m.hs +3/−0
- Crypto/Number/ModArithmetic.hs +3/−0
- Crypto/Number/Prime.hs +3/−0
- Crypto/Number/Serialize.hs +82/−9
- LICENSE +1/−1
- Tests/Tests.hs +21/−4
- crypto-numbers.cabal +1/−1
Crypto/Number/Basic.hs view
@@ -1,5 +1,8 @@ {-# LANGUAGE BangPatterns #-} {-# LANGUAGE CPP #-}+#ifndef MIN_VERSION_integer_gmp+#define MIN_VERSION_integer_gmp(a,b,c) 0+#endif #if MIN_VERSION_integer_gmp(0,5,1) {-# LANGUAGE UnboxedTuples #-} #endif
Crypto/Number/F2m.hs view
@@ -1,4 +1,7 @@ {-# LANGUAGE CPP #-}+#ifndef MIN_VERSION_integer_gmp+#define MIN_VERSION_integer_gmp(a,b,c) 0+#endif #ifdef VERSION_integer_gmp {-# LANGUAGE MagicHash #-} #endif
Crypto/Number/ModArithmetic.hs view
@@ -1,6 +1,9 @@ {-# LANGUAGE BangPatterns #-} {-# LANGUAGE DeriveDataTypeable #-} {-# LANGUAGE CPP #-}+#ifndef MIN_VERSION_integer_gmp+#define MIN_VERSION_integer_gmp(a,b,c) 0+#endif -- | -- Module : Crypto.Number.ModArithmetic -- License : BSD-style
Crypto/Number/Prime.hs view
@@ -1,5 +1,8 @@ {-# LANGUAGE CPP #-} {-# LANGUAGE BangPatterns #-}+#ifndef MIN_VERSION_integer_gmp+#define MIN_VERSION_integer_gmp(a,b,c) 0+#endif #if MIN_VERSION_integer_gmp(0,5,1) {-# LANGUAGE MagicHash #-} #endif
Crypto/Number/Serialize.hs view
@@ -1,3 +1,18 @@+{-# LANGUAGE CPP #-}+#ifndef MIN_VERSION_integer_gmp+#define MIN_VERSION_integer_gmp(a,b,c) 0+#endif+#if MIN_VERSION_integer_gmp(0,5,1)+{-# LANGUAGE MagicHash, UnboxedTuples, BangPatterns #-}+#endif+-- |+-- Module : Crypto.Number.Serialize+-- License : BSD-style+-- Maintainer : Vincent Hanquez <vincent@snarc.org>+-- Stability : experimental+-- Portability : Good+--+-- fast serialization primitives for integer module Crypto.Number.Serialize ( i2osp , os2ip@@ -7,28 +22,55 @@ ) where import Data.ByteString (ByteString)-import qualified Data.ByteString as B import qualified Data.ByteString.Internal as B-import Data.Bits-import Foreign.Storable import Foreign.Ptr +#if MIN_VERSION_integer_gmp(0,5,1)+import GHC.Integer.GMP.Internals+import GHC.Base+import GHC.Ptr+import System.IO.Unsafe+import Foreign.ForeignPtr+#else+import qualified Data.ByteString as B+import Foreign.Storable+import Data.Bits+#endif++#if !MIN_VERSION_integer_gmp(0,5,1) {-# INLINE divMod256 #-} divMod256 :: Integer -> (Integer, Integer) divMod256 n = (n `shiftR` 8, n .&. 0xff)+#endif -- | os2ip converts a byte string into a positive integer-{-# INLINE os2ip #-} os2ip :: ByteString -> Integer+#if MIN_VERSION_integer_gmp(0,5,1)+os2ip bs = unsafePerformIO $ withForeignPtr fptr $ \ptr ->+ let !(Ptr ad) = (ptr `plusPtr` ofs)+ in IO $ \s -> importIntegerFromAddr ad (int2Word# n) 1# s+ where !(fptr, ofs, !(I# n)) = B.toForeignPtr bs+{-# NOINLINE os2ip #-}+#else os2ip = B.foldl' (\a b -> (256 * a) .|. (fromIntegral b)) 0+{-# INLINE os2ip #-}+#endif -- | i2osp converts a positive integer into a byte string i2osp :: Integer -> ByteString+#if MIN_VERSION_integer_gmp(0,5,1)+i2osp m = B.unsafeCreate (I# (word2Int# sz)) fillPtr+ where !sz = sizeInBaseInteger m 256#+ fillPtr (Ptr srcAddr) = IO $ \s -> case exportIntegerToAddr m srcAddr 1# s of+ (# s2, _ #) -> (# s2, () #)+{-# NOINLINE i2osp #-}+#else i2osp m | m < 0 = error "i2osp: cannot convert a negative integer to a bytestring" | otherwise = B.reverse $ B.unfoldr fdivMod256 m where fdivMod256 0 = Nothing fdivMod256 n = Just (fromIntegral a,b) where (b,a) = divMod256 n+#endif -- | just like i2osp, but take an extra parameter for size.@@ -37,19 +79,44 @@ -- -- FIXME: use unsafeCreate to fill the bytestring i2ospOf :: Int -> Integer -> Maybe ByteString+#if MIN_VERSION_integer_gmp(0,5,1) i2ospOf len m+ | sz <= len = Just $ i2ospOf_ len m+ | otherwise = Nothing+ where !sz = I# (word2Int# (sizeInBaseInteger m 256#))+#else+i2ospOf len m | lenbytes < len = Just $ B.replicate (len - lenbytes) 0 `B.append` bytes | lenbytes == len = Just bytes | otherwise = Nothing- where- lenbytes = B.length bytes+ where lenbytes = B.length bytes bytes = i2osp m+#endif --- | just like i2ospOf except that it doesn't expect a failure.+-- | just like i2ospOf except that it doesn't expect a failure: i.e.+-- an integer larger than the number of output bytes requested+-- -- for example if you just took a modulo of the number that represent -- the size (example the RSA modulo n).-{-# INLINE i2ospOf_ #-} i2ospOf_ :: Int -> Integer -> ByteString+#if MIN_VERSION_integer_gmp(0,5,1)+i2ospOf_ len m = unsafePerformIO $ B.create len fillPtr+ where !sz = (sizeInBaseInteger m 256#)+ isz = I# (word2Int# sz)+ fillPtr ptr+ | len < isz = error "cannot compute i2ospOf_ with integer larger than output bytes"+ | len == isz =+ let !(Ptr srcAddr) = ptr in+ IO $ \s -> case exportIntegerToAddr m srcAddr 1# s of+ (# s2, _ #) -> (# s2, () #)+ | otherwise = do+ let z = len-isz+ _ <- B.memset ptr 0 (fromIntegral len)+ let !(Ptr addr) = ptr `plusPtr` z+ IO $ \s -> case exportIntegerToAddr m addr 1# s of+ (# s2, _ #) -> (# s2, () #)+{-# NOINLINE i2ospOf_ #-}+#else i2ospOf_ len m = B.unsafeCreate len fillPtr where fillPtr srcPtr = loop m (srcPtr `plusPtr` (len-1)) where loop n ptr = do@@ -63,11 +130,17 @@ if ptr == srcPtr then return () else fillerLoop (ptr `plusPtr` (-1))+{-# INLINE i2ospOf_ #-}+#endif -- | returns the number of bytes to store an integer with i2osp ----- FIXME: really slow implementation. use log or bigger shifts.+-- with integer-simple, this function is really slow. lengthBytes :: Integer -> Int+#if MIN_VERSION_integer_gmp(0,5,1)+lengthBytes n = I# (word2Int# (sizeInBaseInteger n 256#))+#else lengthBytes n | n < 256 = 1 | otherwise = 1 + lengthBytes (n `shiftR` 8)+#endif
LICENSE view
@@ -1,4 +1,4 @@-Copyright (c) 2010-2012 Vincent Hanquez <vincent@snarc.org>+Copyright (c) 2010-2013 Vincent Hanquez <vincent@snarc.org> All rights reserved.
Tests/Tests.hs view
@@ -1,11 +1,11 @@ {-# LANGUAGE OverloadedStrings #-} -import Test.Framework (defaultMain, testGroup)+import Test.Framework (defaultMain, testGroup, Test) import Test.Framework.Providers.QuickCheck2 (testProperty) import Test.Framework.Providers.HUnit (testCase) import Test.QuickCheck-import Test.HUnit+import Test.HUnit ((@?=)) --import Test.QuickCheck.Test import Control.Applicative ((<$>))@@ -45,12 +45,14 @@ prop_sqrti_valid :: Positive Integer -> Bool prop_sqrti_valid (Positive i) = l*l <= i && i <= u*u where (l, u) = sqrti i +{- prop_generate_prime_valid :: Seed -> Bool prop_generate_prime_valid i = -- because of the next naive test, we can't generate easily number above 32 bits -- otherwise it slows down the tests to uselessness. when AKS or ECPP is implemented -- we can revisit the number here primalityTestNaive $ withRNG i (\g -> generatePrime g 32)+-} prop_miller_rabin_valid :: (Seed, PositiveSmall) -> Bool prop_miller_rabin_valid (seed, PositiveSmall i)@@ -121,9 +123,10 @@ instance Arbitrary Seed where arbitrary = arbitrary >>= \(Positive i) -> return (Seed i) +serializationKATTests :: [Test] serializationKATTests = concatMap f vectors- where f (v, bs) = [ testCase ("i2osp " ++ show v) (i2osp v @=? bs)- , testCase ("os2ip " ++ show v) (os2ip bs @=? v)+ where f (v, bs) = [ testCase ("i2osp " ++ show v) (i2osp v @?= bs)+ , testCase ("os2ip " ++ show v) (os2ip bs @?= v) ] vectors = [ (0x10000, "\SOH\NUL\NUL")@@ -133,12 +136,26 @@ , (0x7521908421feabd21490, "u!\144\132!\254\171\210\DC4\144") ] +serializationOfKATTests :: [Test]+serializationOfKATTests = concatMap f vectors+ where f (elen, v, bs) = [ testCase ("i2osp " ++ show v) (i2ospOf elen v @?= Just bs)+ , testCase ("os2ip " ++ show v) (os2ip bs @?= v)+ ]+ vectors =+ [ (5, 0x10000, "\NUL\NUL\SOH\NUL\NUL")+ , (3, 0x1234, "\NUL\DC24")+ , (8, 0xf123456, "\NUL\NUL\NUL\NUL\SI\DC24V")+ , (10, 0xf21908421feabd21490, "\SI!\144\132!\254\171\210\DC4\144")+ , (12, 0x7521908421feabd21490, "\NUL\NULu!\144\132!\254\171\210\DC4\144")+ ]+ main :: IO () main = defaultMain [ testGroup "serialization" [ testProperty "unbinary.binary==id" (\(Positive i) -> os2ip (i2osp i) == i) , testProperty "length integer" (\(Positive i) -> B.length (i2osp i) == lengthBytes i) , testGroup "KAT" serializationKATTests+ , testGroup "KAT2" serializationOfKATTests ] , testGroup "gcde binary" [ testProperty "gcde" prop_gcde_binary_valid
crypto-numbers.cabal view
@@ -1,5 +1,5 @@ Name: crypto-numbers-Version: 0.2.2+Version: 0.2.3 Description: Cryptographic numbers: functions and algorithms License: BSD3 License-file: LICENSE