diff --git a/CHANGELOG.md b/CHANGELOG.md
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,3 +1,17 @@
+0.1.2
+=====
+
+*   Add support for PCG as PRNG in addition to MWC.
+
+    The module `Data.ByteString.Random.PCG` uses PCG. The module
+    `Data.ByteString.Random.MWC` uses MWC. The module `Data.ByteString.Random`
+    uses MWC for backward compatibility.
+
+*   Support usage of custom PRNGs through the type class `RandomWords` and the
+    function `generate` in the module `Data.ByteString.Random.Internal`.
+
+*   Add some benchmark results to package description
+
 0.1.1
 =====
 
diff --git a/benchmark/Benchmarks.hs b/benchmark/Benchmarks.hs
--- a/benchmark/Benchmarks.hs
+++ b/benchmark/Benchmarks.hs
@@ -14,6 +14,7 @@
 ( Impl(..)
 , benchmarks
 , largeBenchmarks
+, compareBenchmarks
 ) where
 
 import Criterion
@@ -42,7 +43,7 @@
         [ singleThreaded impls 1024
         , singleThreaded impls (1024 * 1024)
         , singleThreaded impls (1024 * 1024 * 10)
-        , singleThreaded impls (1024 * 1024 * 100)
+        -- , singleThreaded impls (1024 * 1024 * 100)
         ]
     , bgroup "multi-threaded"
         [ concurrent impls 10 1024
@@ -52,14 +53,21 @@
         ]
     ]
 
+compareBenchmarks ∷ [Impl] →  [Benchmark]
+compareBenchmarks impls =
+    [ singleThreaded impls (1024 * 1024)
+    , singleThreaded impls (1024 * 1024 * 10)
+    -- , singleThreaded impls (1024 * 1024 * 100)
+    ]
+
 concurrent ∷ [Impl] → Natural → Natural → Benchmark
-concurrent impls c n = bgroup (show c <> "-" <> show n)
+concurrent impls c n = bgroup (show c <> "-" <> show n <> "-bytes")
     [ cgo label f | (Impl label f) ←  impls ]
   where
     cgo s f = bench s $ nfIO $
         forConcurrently [0..(c-1)] (const $ f n)
 
 singleThreaded ∷ [Impl] → Natural → Benchmark
-singleThreaded impls n = bgroup (show n)
+singleThreaded impls n = bgroup (show n <> "-bytes")
     [ bench label $ nfIO $ f n | (Impl label f) ←  impls ]
 
diff --git a/benchmark/Implementations.hs b/benchmark/Implementations.hs
--- a/benchmark/Implementations.hs
+++ b/benchmark/Implementations.hs
@@ -19,6 +19,8 @@
 
 , random
 , entropy
+, cryptoSystem
+, cryptoChaCha
 , mwcUnfoldr
 , mwcUnfoldrIO
 
@@ -26,11 +28,16 @@
 , mwcMalloc8
 , mwcMalloc32
 , mwcMalloc64
+
+--
+, pcgMalloc64
 ) where
 
 import Control.Exception (bracketOnError)
 import Control.Monad.Primitive
 
+import Crypto.Random (getRandomBytes, drgNew, getSystemDRG, withDRG)
+
 import Data.ByteString (ByteString, pack, unfoldrN)
 import Data.ByteString.Unsafe (unsafePackAddressLen)
 import Data.Word (Word8, Word32, Word64)
@@ -44,7 +51,8 @@
 
 import System.Entropy (getEntropy)
 import System.Random (randoms, getStdGen)
-import System.Random.MWC (uniform, create, Gen)
+import qualified System.Random.MWC as MWC (uniform, create, Gen)
+import qualified System.Random.PCG as PCG (uniform, create, Gen)
 
 import Benchmarks
 
@@ -55,11 +63,14 @@
 allImplementations =
     [ Impl "random" random
     , Impl "entropy" entropy
+    , Impl "cryptonite-system" cryptoSystem
+    , Impl "cryptonite-chacha" cryptoChaCha
     , Impl "mwc-unfoldr" mwcUnfoldr
     , Impl "mwc-unfoldr-io" mwcUnfoldrIO
     , Impl "mwc-malloc-8" mwcMalloc8
     , Impl "mwc-malloc-32" mwcMalloc32
     , Impl "mwc-malloc-64" mwcMalloc64
+    , Impl "pcg-malloc-64" pcgMalloc64
     ]
 
 -- -------------------------------------------------------------------------- --
@@ -75,11 +86,24 @@
 entropy n = getEntropy (fromIntegral n)
 
 -- -------------------------------------------------------------------------- --
+-- cryptonite getRandomBytes
+
+cryptoSystem ∷ Natural → IO ByteString
+cryptoSystem n = do
+    gen ← getSystemDRG
+    return $ fst (withDRG gen $ getRandomBytes (fromIntegral n))
+
+cryptoChaCha ∷ Natural → IO ByteString
+cryptoChaCha n = do
+    gen ← drgNew
+    return $ fst (withDRG gen $ getRandomBytes (fromIntegral n))
+
+-- -------------------------------------------------------------------------- --
 -- Malloc8
 
 mwcMalloc8 ∷ Natural → IO ByteString
 mwcMalloc8 n = do
-    !gen ← create
+    !gen ← MWC.create
     bracketOnError (mallocBytes len) free $ \ptr@(Ptr !addr) → do
         go gen ptr
         unsafePackAddressLen len addr
@@ -93,7 +117,7 @@
         loop !i
             | i == pred len = return ()
             | otherwise = do
-                !b ← uniform gen ∷ IO Word8
+                !b ← MWC.uniform gen ∷ IO Word8
                 poke (ptr `plusPtr` i) b
                 loop (succ i)
 
@@ -102,7 +126,7 @@
 
 mwcMalloc32 ∷ Natural → IO ByteString
 mwcMalloc32 n = do
-    !gen ← create
+    !gen ← MWC.create
     bracketOnError (mallocBytes len8) free $ \ptr@(Ptr !addr) → do
         go gen ptr
         unsafePackAddressLen len8 addr
@@ -116,7 +140,7 @@
         !fin32Ptr = startPtr `plusPtr` (len32 * 4)
         loop32 !curPtr
             | curPtr < fin32Ptr = do
-                !b ← uniform gen ∷ IO Word32
+                !b ← MWC.uniform gen ∷ IO Word32
                 poke curPtr b
                 loop32 $ curPtr `plusPtr` 4
             | otherwise = loop8 $ castPtr curPtr
@@ -124,7 +148,7 @@
         !fin8Ptr = startPtr `plusPtr` len8
         loop8 !curPtr
             | curPtr < fin8Ptr = do
-                !b ← uniform gen ∷ IO Word8
+                !b ← MWC.uniform gen ∷ IO Word8
                 poke curPtr b
                 loop8 $ curPtr `plusPtr` 1
             | otherwise = return ()
@@ -135,7 +159,7 @@
 
 mwcMalloc64 ∷ Natural → IO ByteString
 mwcMalloc64 n = do
-    !gen ← create
+    !gen ← MWC.create
     bracketOnError (mallocBytes len8) free $ \ptr@(Ptr !addr) → do
         go gen ptr
         unsafePackAddressLen len8 addr
@@ -144,7 +168,7 @@
     !len8 = fromIntegral n
     !len64 = len8 `div` 8
 
-    go ∷ Gen (PrimState IO) → Ptr Word64 → IO ()
+    go ∷ MWC.Gen (PrimState IO) → Ptr Word64 → IO ()
     go !gen !startPtr = loop64 startPtr
       where
         fin64Ptr ∷ Ptr Word64
@@ -153,7 +177,7 @@
         loop64 ∷ Ptr Word64 → IO ()
         loop64 !curPtr
             | curPtr < fin64Ptr = do
-                !b ← uniform gen ∷ IO Word64
+                !b ← MWC.uniform gen ∷ IO Word64
                 poke curPtr b
                 loop64 $ curPtr `plusPtr` 8
             | otherwise = loop8 $ castPtr curPtr
@@ -164,7 +188,7 @@
         loop8 ∷ Ptr Word8 → IO ()
         loop8 !curPtr
             | curPtr < fin8Ptr = do
-                !b ← uniform gen ∷ IO Word8
+                !b ← MWC.uniform gen ∷ IO Word8
                 poke curPtr b
                 loop8 $ curPtr `plusPtr` 1
             | otherwise = return ()
@@ -176,11 +200,11 @@
 
 mwcUnfoldr ∷ ∀ m . (PrimMonad m, PrimBase m) ⇒ Natural → m ByteString
 mwcUnfoldr n = do
-    !gen ← create
+    !gen ← MWC.create
     primitive $ go gen
   where
     go
-        ∷ Gen (PrimState m)
+        ∷ MWC.Gen (PrimState m)
         → State# (PrimState m)
         → (# State# (PrimState m), ByteString #)
     go !gen !st =
@@ -188,11 +212,11 @@
         in (# st', b #)
 
     step
-        ∷ Gen (PrimState m)
+        ∷ MWC.Gen (PrimState m)
         → Box m
         → Maybe (Word8, Box m)
     step !gen (Box !s) =
-        let !(# !s', !b #) = internal (uniform gen ∷ m Word8) s
+        let !(# !s', !b #) = internal (MWC.uniform gen ∷ m Word8) s
         in Just (b, Box s')
 
 -- -------------------------------------------------------------------------- --
@@ -200,11 +224,11 @@
 
 mwcUnfoldrIO ∷ Natural → IO ByteString
 mwcUnfoldrIO n = do
-    !gen ← create
+    !gen ← MWC.create
     primitive $ go gen
   where
     go
-        ∷ Gen (PrimState IO)
+        ∷ MWC.Gen (PrimState IO)
         → State# (PrimState IO)
         → (# State# (PrimState IO), ByteString #)
     go !gen !st =
@@ -212,10 +236,49 @@
         in (# st', b #)
 
     step
-        ∷ Gen (PrimState IO)
+        ∷ MWC.Gen (PrimState IO)
         → Box IO
         → Maybe (Word8, Box IO)
     step !gen (Box !s) =
-        let !(# !s', !b #) = internal (uniform gen ∷ IO Word8) s
+        let !(# !s', !b #) = internal (MWC.uniform gen ∷ IO Word8) s
         in Just (b, Box s')
+
+-- -------------------------------------------------------------------------- --
+-- PCG Malloc64
+
+pcgMalloc64 ∷ Natural → IO ByteString
+pcgMalloc64 n = do
+    !gen ← PCG.create
+    bracketOnError (mallocBytes len8) free $ \ptr@(Ptr !addr) → do
+        go gen ptr
+        unsafePackAddressLen len8 addr
+  where
+    len8, len64 ∷ Int
+    !len8 = fromIntegral n
+    !len64 = len8 `div` 8
+
+    go ∷ PCG.Gen (PrimState IO) → Ptr Word64 → IO ()
+    go !gen !startPtr = loop64 startPtr
+      where
+        fin64Ptr ∷ Ptr Word64
+        !fin64Ptr = startPtr `plusPtr` (len64 * 8)
+
+        loop64 ∷ Ptr Word64 → IO ()
+        loop64 !curPtr
+            | curPtr < fin64Ptr = do
+                !b ← PCG.uniform gen ∷ IO Word64
+                poke curPtr b
+                loop64 $ curPtr `plusPtr` 8
+            | otherwise = loop8 $ castPtr curPtr
+
+        fin8Ptr ∷ Ptr Word8
+        !fin8Ptr = startPtr `plusPtr` len8
+
+        loop8 ∷ Ptr Word8 → IO ()
+        loop8 !curPtr
+            | curPtr < fin8Ptr = do
+                !b ← PCG.uniform gen ∷ IO Word8
+                poke curPtr b
+                loop8 $ curPtr `plusPtr` 1
+            | otherwise = return ()
 
diff --git a/benchmark/benchmark-compare.hs b/benchmark/benchmark-compare.hs
--- a/benchmark/benchmark-compare.hs
+++ b/benchmark/benchmark-compare.hs
@@ -19,5 +19,5 @@
 import Implementations
 
 main ∷ IO ()
-main = defaultMain $ benchmarks allImplementations
+main = defaultMain $ compareBenchmarks allImplementations
 
diff --git a/benchmark/benchmark.hs b/benchmark/benchmark.hs
--- a/benchmark/benchmark.hs
+++ b/benchmark/benchmark.hs
@@ -16,8 +16,12 @@
 
 import Benchmarks
 import Criterion.Main
-import Data.ByteString.Random
+import qualified Data.ByteString.Random.MWC as MWC
+import qualified Data.ByteString.Random.PCG as PCG
 
 main ∷ IO ()
-main = defaultMain $ largeBenchmarks [Impl "Data.ByteString.Random" random]
+main = defaultMain $ compareBenchmarks
+    [ Impl "random-bytestring+mwc" MWC.random
+    , Impl "random-bytestring+pcg" PCG.random
+    ]
 
diff --git a/benchmarks-details.png b/benchmarks-details.png
new file mode 100644
Binary files /dev/null and b/benchmarks-details.png differ
diff --git a/benchmarks.png b/benchmarks.png
new file mode 100644
Binary files /dev/null and b/benchmarks.png differ
diff --git a/random-bytestring.cabal b/random-bytestring.cabal
--- a/random-bytestring.cabal
+++ b/random-bytestring.cabal
@@ -1,15 +1,26 @@
 Name: random-bytestring
-Version: 0.1.1
+Version: 0.1.2
 Synopsis: Efficient generation of random bytestrings
 Description:
     Efficient generation of random bytestrings. The implementation
     populates uninitialized memory with uniformily distributed random
-    64 bit words. The words are generated using the PRNG from the
-    mwc-random package.
-
+    64 bit words (and 8 bit words for remaining bytes at the end of
+    the bytestring).
+    .
+    Random words are generated using the PRNG from
+    the [mwc-random](https://hackage.haskell.org/package/mwc-random) package
+    or the [pcg-random](https://hackage.haskell.org/package/pcg-random)
+    package. It is also possible to use a custom PRNG by providing
+    an instance for the 'RandomWords' type class and using the function
+    'generate' from the module "Data.ByteString.Random.Internal".
+    .
     The generated byte strings are suitable for statistical
     applications. They are /not/ suitable for cryptographic
     applications.
+    .
+    ![benchmarks](https://hackage.haskell.org/package/random-bytestring-0.1.2/src/benchmarks.png)
+    .
+    ![detailed benchmarks](https://hackage.haskell.org/package/random-bytestring-0.1.2/src/benchmarks-details.png)
 
 Homepage: https://www.github.com/larskuhtz/random-bytestring
 License: MIT
@@ -25,6 +36,8 @@
 extra-doc-files:
     README.md,
     CHANGELOG.md
+    benchmarks.png
+    benchmarks-details.png
 
 source-repository head
     type: git
@@ -36,17 +49,21 @@
 
     exposed-modules:
         Data.ByteString.Random
+        Data.ByteString.Random.Internal
+        Data.ByteString.Random.PCG
+        Data.ByteString.Random.MWC
 
     build-depends:
         base >= 4.7 && < 4.11,
         bytestring >= 0.10,
-        mwc-random >= 0.13
+        mwc-random >= 0.13,
+        pcg-random >= 0.1
 
     if impl(ghc < 7.10)
         build-depends:
             nats >= 1.1
 
-    ghc-options: -Wall
+    ghc-options: -Wall -O2
 
 Benchmark benchmark
     default-language: Haskell2010
@@ -59,7 +76,14 @@
         async >= 2.1,
         base >= 4.7 && < 4.11,
         bytestring >= 0.10,
-        criterion >= 1.1
+        criterion >= 1.1,
+        entropy >= 0.3,
+        ghc-prim >= 0.3,
+        mwc-random >= 0.13,
+        pcg-random >= 0.1,
+        primitive >= 0.6,
+        random >= 1.1,
+        cryptonite >= 0.24
 
     if impl(ghc < 7.10)
         build-depends:
@@ -70,6 +94,7 @@
 
     other-modules:
         Benchmarks
+        Implementations
 
 Benchmark benchmark-compare
     default-language: Haskell2010
@@ -86,8 +111,10 @@
         entropy >= 0.3,
         ghc-prim >= 0.3,
         mwc-random >= 0.13,
+        pcg-random >= 0.1,
         primitive >= 0.6,
-        random >= 1.1
+        random >= 1.1,
+        cryptonite >= 0.24
 
     if impl(ghc < 7.10)
         build-depends:
@@ -115,8 +142,10 @@
         entropy >= 0.3,
         ghc-prim >= 0.3,
         mwc-random >= 0.13,
+        pcg-random >= 0.1,
         primitive >= 0.6,
-        random >= 1.1
+        random >= 1.1,
+        cryptonite >= 0.24
 
     if impl(ghc < 7.10)
         build-depends:
diff --git a/src/Data/ByteString/Random.hs b/src/Data/ByteString/Random.hs
--- a/src/Data/ByteString/Random.hs
+++ b/src/Data/ByteString/Random.hs
@@ -1,5 +1,4 @@
 {-# LANGUAGE UnicodeSyntax #-}
-{-# LANGUAGE BangPatterns #-}
 
 -- -------------------------------------------------------------------------- --
 -- |
@@ -8,88 +7,10 @@
 -- License: MIT
 -- Maintainer: lakuhtz@gmail.com
 -- Stability: experimental
--- -------------------------------------------------------------------------- --
 
 module Data.ByteString.Random
-( random
-, randomGen
+( module Data.ByteString.Random.MWC
 ) where
 
-import Control.Exception (bracketOnError)
-
-import Data.ByteString (ByteString)
-import Data.ByteString.Unsafe (unsafePackAddressLen)
-import Data.Word (Word8, Word64)
-
-import Foreign (mallocBytes, poke, plusPtr, free, castPtr)
-
-import GHC.Ptr (Ptr(..))
-
-import Numeric.Natural (Natural)
-
-import System.Random.MWC (uniform, GenIO, withSystemRandom)
-
--- $setup
--- >>> import qualified Data.ByteString as B
--- >>> import Test.QuickCheck
-
--- | Generate a random bytestring of length n. The PRNG is seeded
--- from the system randomness source.
---
--- prop> ioProperty $ ((fromIntegral n ===) . B.length) <$> random n
--- prop> n > 4 ==> ioProperty $ (/=) <$> random n <*> random n
---
-random
-    ∷ Natural
-        -- ^ Length of the result bytestring in bytes
-    → IO ByteString
-random n = withSystemRandom $ \gen → randomGen gen n
-
--- | Generate a random bytestring of length n using the given
--- PRNG.
---
-randomGen
-    ∷ GenIO
-        -- ^ A PRNG that is used to generate random bytes.
-    → Natural
-        -- ^ Length of the result bytestring in bytes
-    → IO ByteString
-randomGen gen n =
-    bracketOnError (mallocBytes len8) free $ \ptr@(Ptr !addr) → do
-        {-# SCC "go" #-} go ptr
-        {-# SCC "pack" #-} unsafePackAddressLen len8 addr
-  where
-    len8, len64 ∷ Int
-    !len8 = fromIntegral n
-    !len64 = len8 `div` 8
-
-    go ∷ Ptr Word64 → IO ()
-    go !startPtr = loop64 startPtr
-      where
-        -- Would it help to add more manual unrolling levels?
-        -- How smart is the compiler about unrolling loops?
-
-        -- Generate 64bit values
-        fin64Ptr ∷ Ptr Word64
-        !fin64Ptr = startPtr `plusPtr` (len64 * 8)
-
-        loop64 ∷ Ptr Word64 → IO ()
-        loop64 !curPtr
-            | curPtr < fin64Ptr = {-# SCC "loop64" #-} do
-                !b ← uniform gen ∷ IO Word64
-                {-# SCC "poke64" #-} poke curPtr b
-                loop64 $ {-# SCC "ptr_inc" #-} curPtr `plusPtr` 8
-            | otherwise = loop8 $ castPtr curPtr
-
-        -- Generate 8bit values
-        fin8Ptr ∷ Ptr Word8
-        !fin8Ptr = startPtr `plusPtr` len8
-
-        loop8 ∷ Ptr Word8 → IO ()
-        loop8 !curPtr
-            | curPtr < fin8Ptr = {-# SCC "loop8" #-} do
-                !b ← uniform gen ∷ IO Word8
-                poke curPtr b
-                loop8 $ curPtr `plusPtr` 1
-            | otherwise = return ()
+import Data.ByteString.Random.MWC
 
diff --git a/src/Data/ByteString/Random/Internal.hs b/src/Data/ByteString/Random/Internal.hs
new file mode 100644
--- /dev/null
+++ b/src/Data/ByteString/Random/Internal.hs
@@ -0,0 +1,92 @@
+{-# LANGUAGE BangPatterns #-}
+{-# LANGUAGE UnicodeSyntax #-}
+
+-- -------------------------------------------------------------------------- --
+-- |
+-- Module: Data.ByteString.Random.Internal
+-- Copyright: (c) Lars Kuhtz <lakuhtz@gmail.com> 2017
+-- License: MIT
+-- Maintainer: lakuhtz@gmail.com
+-- Stability: experimental
+
+module Data.ByteString.Random.Internal
+( generate
+, RandomWords(..)
+) where
+
+import Control.Exception (bracketOnError)
+
+import Data.ByteString (ByteString)
+import Data.ByteString.Unsafe (unsafePackAddressLen)
+import Data.Word (Word8, Word64)
+
+import Foreign (mallocBytes, poke, plusPtr, free, castPtr)
+
+import GHC.Ptr (Ptr(..))
+
+import Numeric.Natural (Natural)
+
+-- -------------------------------------------------------------------------- --
+
+class RandomWords g where
+    uniformW8 ∷ g → IO Word8
+        -- ^ function that generates uniformily distributed random 8 bit words
+    uniformW64 ∷ g → IO Word64
+        -- ^ function that generates uniformily distributed random 64 bit words
+
+-- The reason why a type class is used instead of passing the IO functions
+-- directoy to generate, is that we can force GHC to inline these methods by
+-- using a SPECIALIZE pragma.
+
+-- -------------------------------------------------------------------------- --
+
+-- | Generates uniformily distributed random bytestrings of length n using the
+-- given PRNG.
+--
+generate
+    ∷ RandomWords g
+    ⇒ g
+        -- ^ PRNG
+    → Natural
+        -- ^ Length of the result bytestring in bytes
+    → IO ByteString
+generate g n =
+    bracketOnError (mallocBytes len8) free $ \ptr@(Ptr !addr) → do
+        {-# SCC "go" #-} go ptr
+        {-# SCC "pack" #-} unsafePackAddressLen len8 addr
+  where
+    len8, len64 ∷ Int
+    !len8 = fromIntegral n
+    !len64 = len8 `div` 8
+
+    go ∷ Ptr Word64 → IO ()
+    go !startPtr = loop64 startPtr
+      where
+        -- Would it help to add more manual unrolling levels?
+        -- How smart is the compiler about unrolling loops?
+
+        -- Generate 64bit values
+        fin64Ptr ∷ Ptr Word64
+        !fin64Ptr = startPtr `plusPtr` (len64 * 8)
+
+        loop64 ∷ Ptr Word64 → IO ()
+        loop64 !curPtr
+            | curPtr < fin64Ptr = {-# SCC "loop64" #-} do
+                !b ← uniformW64 g
+                {-# SCC "poke64" #-} poke curPtr b
+                loop64 $ {-# SCC "ptr_inc" #-} curPtr `plusPtr` 8
+            | otherwise = loop8 $ castPtr curPtr
+
+        -- Generate 8bit values
+        fin8Ptr ∷ Ptr Word8
+        !fin8Ptr = startPtr `plusPtr` len8
+
+        loop8 ∷ Ptr Word8 → IO ()
+        loop8 !curPtr
+            | curPtr < fin8Ptr = {-# SCC "loop8" #-} do
+                !b ← uniformW8 g
+                poke curPtr b
+                loop8 $ curPtr `plusPtr` 1
+            | otherwise = return ()
+{-# INLINEABLE generate #-}
+
diff --git a/src/Data/ByteString/Random/MWC.hs b/src/Data/ByteString/Random/MWC.hs
new file mode 100644
--- /dev/null
+++ b/src/Data/ByteString/Random/MWC.hs
@@ -0,0 +1,65 @@
+{-# LANGUAGE FlexibleInstances #-}
+{-# LANGUAGE TypeFamilies #-}
+{-# LANGUAGE UnicodeSyntax #-}
+{-# OPTIONS_GHC -fno-warn-orphans #-}
+
+-- -------------------------------------------------------------------------- --
+-- |
+-- Module: Data.ByteString.Random.MWC
+-- Copyright: (c) Lars Kuhtz <lakuhtz@gmail.com> 2017
+-- License: MIT
+-- Maintainer: lakuhtz@gmail.com
+-- Stability: experimental
+
+module Data.ByteString.Random.MWC
+( random
+, randomGen
+) where
+
+import Data.ByteString (ByteString)
+
+import Numeric.Natural (Natural)
+
+import System.Random.MWC (uniform, GenIO, withSystemRandom)
+
+-- internal imports
+
+import Data.ByteString.Random.Internal
+
+-- -------------------------------------------------------------------------- --
+
+instance (g ~ GenIO) ⇒ RandomWords g where
+    uniformW8 = uniform
+    {-# INLINE uniformW8 #-}
+    uniformW64 = uniform
+    {-# INLINE uniformW64 #-}
+
+{-# SPECIALIZE generate ∷ GenIO → Natural → IO ByteString #-}
+
+-- -------------------------------------------------------------------------- --
+
+randomGen
+    ∷ GenIO
+        -- ^ PRNG
+    → Natural
+        -- ^ Length of the result bytestring in bytes
+    → IO ByteString
+randomGen = generate
+{-# INLINE randomGen #-}
+
+-- $setup
+-- >>> import qualified Data.ByteString as B
+-- >>> import Test.QuickCheck
+
+-- | Generate a random bytestring of length n. The PRNG is seeded
+-- from the system randomness source.
+--
+-- prop> ioProperty $ ((fromIntegral n ===) . B.length) <$> random n
+-- prop> n > 4 ==> ioProperty $ (/=) <$> random n <*> random n
+--
+random
+    ∷ Natural
+        -- ^ Length of the result bytestring in bytes
+    → IO ByteString
+random = withSystemRandom . flip randomGen
+
diff --git a/src/Data/ByteString/Random/PCG.hs b/src/Data/ByteString/Random/PCG.hs
new file mode 100644
--- /dev/null
+++ b/src/Data/ByteString/Random/PCG.hs
@@ -0,0 +1,65 @@
+{-# LANGUAGE FlexibleInstances #-}
+{-# LANGUAGE TypeFamilies #-}
+{-# LANGUAGE UnicodeSyntax #-}
+{-# OPTIONS_GHC -fno-warn-orphans #-}
+
+-- -------------------------------------------------------------------------- --
+-- |
+-- Module: Data.ByteString.Random.PCG
+-- Copyright: (c) Lars Kuhtz <lakuhtz@gmail.com> 2017
+-- License: MIT
+-- Maintainer: lakuhtz@gmail.com
+-- Stability: experimental
+
+module Data.ByteString.Random.PCG
+( random
+, randomGen
+) where
+
+import Data.ByteString (ByteString)
+
+import Numeric.Natural (Natural)
+
+import System.Random.PCG (uniform, GenIO, withSystemRandom)
+
+-- internal imports
+
+import Data.ByteString.Random.Internal
+
+-- -------------------------------------------------------------------------- --
+
+instance (g ~ GenIO) ⇒ RandomWords g where
+    uniformW8 = uniform
+    {-# INLINE uniformW8 #-}
+    uniformW64 = uniform
+    {-# INLINE uniformW64 #-}
+
+{-# SPECIALIZE generate ∷ GenIO → Natural → IO ByteString #-}
+
+-- -------------------------------------------------------------------------- --
+
+randomGen
+    ∷ GenIO
+        -- ^ PRNG
+    → Natural
+        -- ^ Length of the result bytestring in bytes
+    → IO ByteString
+randomGen = generate
+{-# INLINE randomGen #-}
+
+-- $setup
+-- >>> import qualified Data.ByteString as B
+-- >>> import Test.QuickCheck
+
+-- | Generate a random bytestring of length n. The PRNG is seeded
+-- from the system randomness source.
+--
+-- prop> ioProperty $ ((fromIntegral n ===) . B.length) <$> random n
+-- prop> n > 4 ==> ioProperty $ (/=) <$> random n <*> random n
+--
+random
+    ∷ Natural
+        -- ^ Length of the result bytestring in bytes
+    → IO ByteString
+random n = withSystemRandom $ flip randomGen n
+
