diff --git a/LICENSE b/LICENSE
new file mode 100644
--- /dev/null
+++ b/LICENSE
@@ -0,0 +1,30 @@
+Copyright (c) 2008 Adam Wick
+
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+
+1. Redistributions of source code must retain the above copyright
+   notice, this list of conditions and the following disclaimer.
+
+2. Redistributions in binary form must reproduce the above copyright
+   notice, this list of conditions and the following disclaimer in the
+   documentation and/or other materials provided with the distribution.
+
+3. Neither the name of the author nor the names of his contributors
+   may be used to endorse or promote products derived from this software
+   without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS OR
+IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED.  IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE FOR
+ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
+ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGE.
diff --git a/Main.hs b/Main.hs
new file mode 100644
--- /dev/null
+++ b/Main.hs
@@ -0,0 +1,113 @@
+{-# LANGUAGE ForeignFunctionInterface #-}
+
+import System.Random.Mersenne.Pure64
+import Control.Concurrent
+import Control.Monad
+import Data.Binary.Put
+import qualified Data.ByteString.Lazy as BS
+import qualified Data.ByteString      as S
+import Data.Word
+import Foreign.Marshal.Alloc
+import Foreign.Ptr
+import Foreign.Storable
+import System.Environment
+import GHC.Conc
+import Foreign.C.Types
+import Debug.Trace
+import System.IO
+
+
+--
+-- Parallel unfold and reduce.
+--
+-- -lcrypto
+--
+
+main :: IO ()
+main = do
+  args <- getArgs
+  case args of
+    [file, size]       -> checkReasonableAndGo (Just (show numCapabilities)) file size
+    [cpus, file, size] -> checkReasonableAndGo (Just cpus) file size
+    _                  -> dumpUsageAndQuit
+
+dumpUsageAndQuit :: IO ()
+dumpUsageAndQuit = mapM_ putStrLn
+    ["USAGE: genblock [cpus] filename size"
+    ,"where 'size' is given in gigabytes"
+    ,"and cpus defaults to the value of +RTS -N"]
+
+checkReasonableAndGo :: Maybe String -> String -> String -> IO ()
+checkReasonableAndGo mcpus file size =
+  case (maybe [(numCapabilities, "")] reads mcpus, reads size) of
+    ([(cpus, "")], [(size', "")]) -> go cpus file size'
+    _                             -> dumpUsageAndQuit
+
+go :: Int -> String -> Int -> IO ()
+go cpus filename size_in_gb = do
+  chan <- newChan
+  forM_ [1..cpus] $ \n -> forkIO {-n-} $ do
+    baseMT <- pureMT `fmap` getOpenSSLRand
+    writeList2Chan chan $
+            BS.toChunks $ runPut $ mersennePut baseMT
+
+  ls <- getChanContents chan    -- TODO need a LBS chan
+  BS.writeFile filename . BS.take size . BS.fromChunks $ ls
+
+ where
+  size = fromIntegral size_in_gb * 1024 * 1024 * 1024
+
+
+-- unroll the loop
+mersennePut :: PureMT -> Put
+mersennePut mt = do
+
+  let (k, mt1) = randomWord64 mt
+  putWord64host k
+  let (k, mt2) = randomWord64 mt1
+  putWord64host k
+  let (k, mt3) = randomWord64 mt2
+  putWord64host k
+  let (k, mt4) = randomWord64 mt3
+  putWord64host k
+  let (k, mt5) = randomWord64 mt4
+  putWord64host k
+  let (k, mt6) = randomWord64 mt5
+  putWord64host k
+  let (k, mt7) = randomWord64 mt6
+  putWord64host k
+  let (k, mt8) = randomWord64 mt7
+  putWord64host k
+  let (k, mt9) = randomWord64 mt8
+  putWord64host k
+  let (k, mt10) = randomWord64 mt9
+  putWord64host k
+  let (k, mt11) = randomWord64 mt10
+  putWord64host k
+  let (k, mt12) = randomWord64 mt11
+  putWord64host k
+  let (k, mt13) = randomWord64 mt12
+  putWord64host k
+  let (k, mt14) = randomWord64 mt13
+  putWord64host k
+  let (k, mt15) = randomWord64 mt14
+  putWord64host k
+  let (k, mt16) = randomWord64 mt15
+  putWord64host k
+  mersennePut mt16
+
+------------------------------------------------------------------------
+
+--
+-- Get a decent random seed
+--
+getOpenSSLRand :: IO Word64
+getOpenSSLRand = allocaBytes n $ \ ptr -> do
+  fill_RAND_bytes ptr (fromIntegral n)
+  peek $ castPtr ptr
+ where
+  n = sizeOf (undefined :: Word64)
+
+foreign import ccall unsafe "openssl/rand.h RAND_bytes"
+  fill_RAND_bytes :: Ptr Word8 -> CInt -> IO ()
+
diff --git a/Setup.lhs b/Setup.lhs
new file mode 100644
--- /dev/null
+++ b/Setup.lhs
@@ -0,0 +1,3 @@
+#!/usr/bin/env runhaskell
+> import Distribution.Simple
+> main = defaultMain
diff --git a/randomgen.cabal b/randomgen.cabal
new file mode 100644
--- /dev/null
+++ b/randomgen.cabal
@@ -0,0 +1,28 @@
+name:               randomgen
+version:            0.1
+homepage:           http://galois.com
+synopsis:           A fast, SMP parallel random data generator
+description:        A fast, SMP parallel random data generator
+                    .
+                    To generate 10G of high quality pseudorandom
+                    data, using 4 processors to fill the file:
+                    .
+                    $ randomgen "data" 10 +RTS -N4
+                    .
+category:           System
+license:            BSD3
+license-file:       LICENSE
+author:             Adam Wick
+maintainer:         awick@haskell.org
+cabal-version:      >= 1.2
+build-type:         Simple
+
+executable randomgen
+    main-is:            Main.hs
+    ghc-options:        -O2 -threaded
+    extensions:         ForeignFunctionInterface
+    build-depends:      base,
+                        mersenne-random-pure64,
+                        bytestring,
+                        binary
+    extra-libraries:    crypto
