packages feed

dice-entropy-conduit 1.0.0.1 → 1.0.0.3

raw patch · 5 files changed

+122/−104 lines, 5 filesdep ~basePVP: major bump suggested

API removals or changes: PVP suggests a major version bump

Dependency ranges changed: base

API changes (from Hackage documentation)

- System.Random.Dice: testPerformance :: Int -> Int -> IO ()
- System.Random.Dice.Internal: testPerformance :: Int -> Int -> IO ()
- System.Random.Dice.Internal: dRoll :: Word64 -> Word64 -> Word64 -> Conduit Word8 IO (Int, Int)
+ System.Random.Dice.Internal: dRoll :: Word64 -> Word64 -> Word64 -> Int -> Conduit Word8 IO (Int, Int)

Files

+ ChangeLog.md view
@@ -0,0 +1,10 @@+# Changelog for dice-entropy-conduit++## Unreleased changes++* None++## 1.0.0.3++* Make it build with `stack`.+* Updated dependencies.
+ README.md view
@@ -0,0 +1,9 @@+This library uses rejection sampling to provide cryptographically secure `n`-sided dice rolls and random sampling (within a given range).++## Usage:++If we want to use the system-specific entropy source (`systemEntropy`) to+produce 10 dice rolls of a 6-sided dice (i.e. range [0,5]), you can write:++> systemEntropy $$ diceRolls 6 =$= CL.take 10+> [5,1,3,3,0,5,3,2,2,1]
dice-entropy-conduit.cabal view
@@ -1,62 +1,65 @@+cabal-version: 1.12++-- This file has been generated from package.yaml by hpack version 0.31.2.+--+-- see: https://github.com/sol/hpack+--+-- hash: 11ee8a59a75ff863ac20d50ebb04f19822218ed8af64635cc4666664a3bbfbb1+ name:           dice-entropy-conduit-version:        1.0.0.1-cabal-version:  >=1.8-build-type:     Simple+version:        1.0.0.3+synopsis:       Cryptographically secure n-sided dice via rejection sampling+description:    Please see the README on GitHub at <https://github.com/pwrobinson/dice-entropy-conduit#readme>+category:       Data, Cryptography+homepage:       https://github.com/pwrobinson/dice-entropy-conduit#readme+bug-reports:    https://github.com/pwrobinson/dice-entropy-conduit/issues+author:         Peter Robinson+maintainer:     pwr@lowerbound.io+copyright:      2014-2020 Peter Robinson license:        LGPL-2.1 license-file:   LICENSE-author:         Peter Robinson <peter.robinson@monoid.at>-maintainer:     peter.robinson@monoid.at-copyright:      Peter Robinson 2014-homepage:       http://monoid.at/code-tested-with:    GHC==7.8.3-stability:      experimental-category:       Cryptography, Data -synopsis:       Cryptographically secure n-sided dice via rejection sampling. -description:    -   This library uses rejection sampling to provide cryptographically secure -   @n@-sided dice rolls and random sampling (within a given range). -   The number of used random bits is close to the information-theoretic optimal-   bound.-   .-   /Usage:/-   .-   If we wanted to use the system-specific entropy source ('systemEntropy') to-   produce 10 dice rolls of a 6-sided dice (i.e. range [0,5]), we could write:-   .-   > > systemEntropy $$ diceRolls 6 =$= CL.take 10 -   > [5,1,3,3,0,5,3,2,2,1]-   .-   The function 'testPerformance' yields the actual number of consumed random-   bits:-   .-   > > testPerformance 12 10000-   > Generated 10000 random samples in range [0,11]-   > Average number of bits used: 3.5904-   > Entropy lower bound on the number of required bits: 3.5849625007211565-   > Performance ratio: 1.0015167520658164-   .-   Feedback is welcome!--library-  hs-source-dirs:  src-  build-depends:   base == 4.*-                  ,bytestring >= 0.9-                  ,entropy >= 0.3.2-                  ,conduit >= 1.1.7-                  ,transformers >= 0.4.0.0--  ghc-options:     -Wall -  exposed-modules: System.Random.Dice-                   System.Random.Dice.Internal+build-type:     Simple+extra-source-files:+    README.md+    ChangeLog.md +source-repository head+  type: git+  location: https://github.com/pwrobinson/dice-entropy-conduit -test-suite Main-  type:            exitcode-stdio-1.0-  x-uses-tf:       true-  build-depends:   base >= 4 && < 5,-                   QuickCheck >= 2.4,-                   test-framework >= 0.4.1,-                   test-framework-quickcheck2-  hs-source-dirs:  src, tests-  main-is:         Tests.hs+library+  exposed-modules:+      System.Random.Dice+      System.Random.Dice.Internal+  other-modules:+      Paths_dice_entropy_conduit+  hs-source-dirs:+      src+  build-depends:+      base >=4.6 && <5+    , bytestring >=0.9+    , conduit >=1.1.7+    , entropy >=0.3.2+    , transformers >=0.4.0.0+  default-language: Haskell2010 +test-suite dice-entropy-conduit-test+  type: exitcode-stdio-1.0+  main-is: Tests.hs+  other-modules:+      System.Random.Dice+      System.Random.Dice.Internal+      Paths_dice_entropy_conduit+  hs-source-dirs:+      tests+      src+  build-depends:+      QuickCheck >=2.4+    , base >=4 && <5+    , bytestring >=0.9+    , conduit >=1.1.7+    , entropy >=0.3.2+    , test-framework >=0.4.1+    , test-framework-quickcheck2+    , transformers >=0.4.0.0+  default-language: Haskell2010
src/System/Random/Dice.hs view
@@ -4,7 +4,7 @@ -- Module      :  System.Random.Dice -- Copyright   :  Peter Robinson 2014 -- License     :  LGPL--- +-- -- Maintainer  :  Peter Robinson <peter.robinson@monoid.at> -- Stability   :  experimental -- Portability :  portable@@ -14,24 +14,24 @@ -- The algorithm uses rejection sampling and attempts to keep the total number -- of used random bits as close as possible to the information theoretic lower -- bound of @ln(n) / ln(2)@ (for a range of size @n@).--- +-- -- The implementation exposes streams of random values as conduits, see -- 'diceRolls' and 'randomRs'. We also provide IO wrappers around these -- functions, see 'getDiceRolls' and 'getRandomRs'. -- The conduit interface allows us to use a specific entropy source, which has--- type 'Producer' 'IO' 'Word'. +-- type 'Producer' 'IO' 'Word'. -- -- /Usage:/--- +-- -- If we wanted to use the system-specific entropy source ('systemEntropy') to -- produce 10 dice rolls of a 6-sided dice (i.e. range [0,5]), we could write: ----- > > systemEntropy $$ diceRolls 6 =$= CL.take 10 +-- > > systemEntropy $$ diceRolls 6 =$= CL.take 10 -- > [5,1,3,3,0,5,3,2,2,1] -- -- The function 'testPerformance' yields the actual number of consumed random -- bits:--- +-- -- > > testPerformance 12 10000 -- > Generated 10000 random samples in range [0,11] -- > Average number of bits used: 3.5904@@ -43,9 +43,8 @@                          , randomRs                          , getDiceRolls                          , getRandomRs-                         , testPerformance+                         -- , testPerformance                          , systemEntropy                          ) where import System.Random.Dice.Internal-
src/System/Random/Dice/Internal.hs view
@@ -4,7 +4,7 @@ -- Module      :  System.Random.Dice.Internal -- Copyright   :  Peter Robinson 2014 -- License     :  LGPL--- +-- -- Maintainer  :  Peter Robinson <peter.robinson@monoid.at> -- Stability   :  experimental -- Portability :  portable@@ -21,25 +21,25 @@ import Data.Conduit import qualified Data.Conduit.List as CL --- | Converts a number to its base-2 representation (as a list of bits) +-- | Converts a number to its base-2 representation (as a list of bits) -- and prepends zeros to ensure the minimal size. integralToBits :: (Integral n,Integral m)                => Int  -- ^ minimal number of bits @b@                -> n    -- ^ the number @n@                -> [m]  -- ^ bit representation of @n@, length >= @b@-integralToBits b x = reverse $ integralToBits' 0 x +integralToBits b x = reverse $ integralToBits' 0 x   where   integralToBits' ns 0 = replicate (b-ns) 0-  integralToBits' ns y = -    let (a,res) = quotRem y 2 in +  integralToBits' ns y =+    let (a,res) = quotRem y 2 in     fromIntegral res : integralToBits' (ns+1) a-     + -- | Convert a list of bits to an integral bitsToIntegral :: (Integral n) =>[n] -> n-bitsToIntegral = extendIntegralWithBits 0 - +bitsToIntegral = extendIntegralWithBits 0 + extendIntegralWithBits :: (Integral n) => n -> [n] -> n extendIntegralWithBits n = foldr (\c r -> 2*r + c) n . reverse @@ -53,15 +53,15 @@ getDiceRolls :: Int  -- ^ @n:@ number of sides              -> Int  -- ^ @k:@ number of rolls              -> IO [Int]-getDiceRolls n len = -  systemEntropy $$ diceRolls n =$= CL.take len +getDiceRolls n len =+  systemEntropy $$ diceRolls n =$= CL.take len   -- | Generates a list of random integer values in the specified range. getRandomRs :: (Int,Int) -- ^ (inclusive) range          -> Int          -- ^ number of samples          -> IO [Int]-getRandomRs range len = +getRandomRs range len =   systemEntropy $$ randomRs range =$= CL.take len  @@ -73,10 +73,10 @@ diceRolls n   | fromIntegral n > upperBound || n <= 0     = throw $ AssertionFailed "diceRolls: n-sided dice are supported, for 1 <= n < 2^55."-  | n == 1    -    = CL.sourceList [0,0..] -  | otherwise -    = dRoll (fromIntegral n) 1 0 =$= CL.map fst+  | n == 1+    = CL.sourceList [0,0..]+  | otherwise+    = dRoll (fromIntegral n) 1 0 0 =$= CL.map fst   -- | Produces a stream of random integer values within a range.@@ -88,60 +88,57 @@   -- | A source of entropy. By default, we use the 'getEntropy' function from--- the entropy package, see 'systemEntropy'. +-- the entropy package, see 'systemEntropy'. -- -- /Warning:/ When combining a source of entropy with other conduits, it is--- important that there is no \"backflow\" due to leftover values that +-- important that there is no \"backflow\" due to leftover values that -- are being returned to the -- source from the conduit. This can be done by fusing the conduit with the -- identity map, e.g: @myEntropySrc $$ Data.Conduit.List.map id =$= myConduit@--- -systemEntropy :: Producer IO Word8 +--+systemEntropy :: Producer IO Word8 systemEntropy = do   bytes <- B.unpack `liftM` liftIO  (getEntropy 8)   forM_ bytes yield-  systemEntropy +  systemEntropy   --- | Internal function. Should not be invoked directly. -dRoll :: Word64 -> Word64 -> Word64 -> Conduit Word8 IO (Int,Int)-dRoll n m r = do---    | num > len = print ("end:",num,m,r) >> return []---  | otherwise = do-  let k = ceiling $ (logBase 2 (fromIntegral upperBound) - logBase 2 (fromIntegral m :: Double)) / 8 +-- | Internal function. Should not be invoked directly.+dRoll :: Word64 -> Word64 -> Word64 -> Int -> Conduit Word8 IO (Int,Int)+dRoll n m r cnt = do+  let k = ceiling $ (logBase 2 (fromIntegral upperBound) - logBase 2 (fromIntegral m :: Double)) / 8   let m' = 2^(8*k) * m-  bits <- (concatMap (integralToBits 8) . B.unpack) +  bits <- (concatMap (integralToBits 8) . B.unpack)           `liftM` (if k>0 then liftIO $ getEntropy k else return $ B.pack [])   let w64 = extendIntegralWithBits r bits   let q = m' `div` n-  if w64 < n * q +  if w64 < n * q     then do       yield (fromIntegral $ w64 `mod` n,k)-      dRoll n q (w64 `div` n)-    else  dRoll n (m' - n*q) (w64 - n*q)-+      dRoll n q (w64 `div` n) (cnt + k)+    else  dRoll n (m' - n*q) (w64 - n*q) (cnt + k) +{- -- | Compute the performance of the algorithm in terms of used random bits -- versus produced random values. testPerformance :: Int   -- ^ number of sides of dice                 -> Int   -- ^ number of samples used for computing average.                 -> IO ()-testPerformance n len +testPerformance n len   | fromIntegral n > upperBound     = throw $ AssertionFailed "dice: range must be within Word64 bounds."   | otherwise = do-    nbits <- systemEntropy $= dRoll (fromIntegral n) 1 0 -                           $$ CL.take len +    nbits <- systemEntropy $= dRoll (fromIntegral n) 1 0 0+                           $$ CL.take len                            >>= return . sum . map snd-    putStrLn $ "Generated " ++ show len +    putStrLn $ "Generated " ++ show len             ++ " random samples in range [0," ++ show (n-1) ++ "]"-    putStrLn $ "Average number of bits used: " +    putStrLn $ "Average number of bits used: "             ++ show (8*fromIntegral nbits/ fromIntegral len :: Double)     let lbound = logBase 2 (fromIntegral n) :: Double-    putStrLn $ "Entropy lower bound on the number of required bits: " +    putStrLn $ "Entropy lower bound on the number of required bits: "             ++ show lbound-    putStrLn $ "Performance ratio: " ++ show (((8*fromIntegral nbits +    putStrLn $ "Performance ratio: " ++ show (((8*fromIntegral nbits                                     / fromIntegral len) ::Double) / lbound)--+-}