diff --git a/ChangeLog.md b/ChangeLog.md
new file mode 100644
--- /dev/null
+++ b/ChangeLog.md
@@ -0,0 +1,4 @@
+0.1.1.1
+=======
+
+First public version
diff --git a/LICENSE b/LICENSE
new file mode 100644
--- /dev/null
+++ b/LICENSE
@@ -0,0 +1,21 @@
+The MIT License (MIT)
+
+Copyright (c) 2015 FP Complete
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+SOFTWARE.
diff --git a/README.md b/README.md
new file mode 100644
--- /dev/null
+++ b/README.md
@@ -0,0 +1,35 @@
+# executable-hash
+
+Provides the SHA1 hash of the executable.  This hash can either be
+injected into the executable as a step after compilation, or
+calculated at runtime.
+
+## Usage
+
+The main function expected to be used by the user is
+`System.Executable.Hash.executableHash`.  This function yields a SHA1
+hash determined by the contents of the executable.  However, note that
+this may not be the actual SHA1 of the executable, since the hash can
+be injected into the executable (which changes its "actual" hash).
+
+Installing this package will also install the `inject-executable-hash`
+executable.  Running this program on a binary, like
+`inject-executable-hash <binary-name>` will replace a dummy
+`ByteString` (via the `file-embed` package) in the binary with its
+hash.
+
+Alternatively, you can put this in a `Setup.hs` file, and set
+`build-type: Custom` in your `.cabal`:
+
+```haskell
+import Distribution.Simple
+import System.Executable.Hash.Internal (maybeInjectExecutableHash)
+
+main :: IO ()
+main = defaultMainWithHooks $ simpleUserHooks
+    { postBuild = \_ _ _ _ ->
+        maybeInjectExecutableHash "dist/build/path-to/your-executable"
+    }
+```
+
+(Note: you'll need to change the executable path)
diff --git a/Setup.hs b/Setup.hs
new file mode 100644
--- /dev/null
+++ b/Setup.hs
@@ -0,0 +1,9 @@
+import Distribution.Simple
+import System.Executable.Hash.Internal (maybeInjectExecutableHash)
+
+main :: IO ()
+main = defaultMainWithHooks $ simpleUserHooks
+    { postBuild = \_ _ _ _ ->
+        maybeInjectExecutableHash "dist/build/test-inject/test-inject"
+    }
+
diff --git a/System/Executable/Hash.hs b/System/Executable/Hash.hs
new file mode 100644
--- /dev/null
+++ b/System/Executable/Hash.hs
@@ -0,0 +1,60 @@
+{-# LANGUAGE TemplateHaskell #-}
+
+-- | This module provides functions for accessing or computing a SHA1
+-- hash of the program's executable.  Most users are expected to use
+-- the 'executableHash' function.
+--
+-- To inject the hash into the executable, you can use the
+-- @inject-executable-hash@ program installed along with this package.
+-- Alternatively, to do this automatically with cabal, place this in
+-- your @Setup.hs@:
+--
+-- @
+--      import Distribution.Simple
+--      import System.Executable.Hash.Internal (maybeInjectExecutableHash)
+--
+--      main :: IO ()
+--      main = defaultMainWithHooks $ simpleUserHooks
+--          { postBuild = \_ _ _ _ ->
+--              maybeInjectExecutableHash "dist\/build\/path-to\/your-executable"
+--          }
+-- @
+--
+-- (Note: you'll need to change the executable path)
+module System.Executable.Hash
+    ( executableHash
+    , computeExecutableHash
+    ) where
+
+import           Control.Applicative ((<$>))
+import           Crypto.Hash.SHA1 (hash)
+import qualified Data.ByteString as BS
+import           System.Environment.Executable (getScriptPath, ScriptPath(..))
+import           System.Executable.Hash.Internal
+
+-- | If a SHA1 hash of the executable has been injected into it, then
+-- it's directly yielded by this function.  Otherwise, a hash is
+-- computed with 'computeExecutableHash'.
+--
+-- Note that you shouldn't rely on the result being the actual SHA1
+-- hash of the executable, because injecting the hash modifies the
+-- binary, and so changes the result of 'computeExecutableHash'.
+-- Instead, this should only be used as a way to uniquely identify the
+-- contents of the executable.
+--
+-- This yields 'Nothing' when run with @runhaskell@ or @ghci@.
+executableHash :: IO (Maybe BS.ByteString)
+executableHash =
+    case injectedExecutableHash of
+        Just x -> return (Just x)
+        Nothing -> computeExecutableHash
+
+-- | Computes the SHA1 hash of the program executable.
+--
+-- This yields 'Nothing' when run with @runhaskell@ or @ghci@.
+computeExecutableHash :: IO (Maybe BS.ByteString)
+computeExecutableHash = do
+    sp <- getScriptPath
+    case sp of
+        Executable fp -> Just . hash <$> BS.readFile fp
+        _ -> return Nothing
diff --git a/System/Executable/Hash/Internal.hs b/System/Executable/Hash/Internal.hs
new file mode 100644
--- /dev/null
+++ b/System/Executable/Hash/Internal.hs
@@ -0,0 +1,50 @@
+{-# LANGUAGE TemplateHaskell #-}
+{-# LANGUAGE OverloadedStrings #-}
+
+-- | Internals related to reading and writing an injected executable
+-- hash.
+module System.Executable.Hash.Internal where
+
+import           Crypto.Hash.SHA1 (hash)
+import qualified Data.ByteString as BS
+import           Data.FileEmbed (dummySpaceWith, injectWith)
+import           System.Directory (doesFileExist)
+
+-- | Yields a 'Just' value of a hash which has been injected into the
+-- executable via 'injectExecutableHash'.
+injectedExecutableHash :: Maybe BS.ByteString
+injectedExecutableHash
+    | BS.all (== toEnum (fromEnum '0')) bs = Nothing
+    | otherwise = Just bs
+  where
+    bs = $(dummySpaceWith "executable-hash" 20)
+
+-- | Given the path to an executable, computes its hash and injects it
+-- into the binary, such that when that program demands the value of
+-- 'injectedExecutableHash', it yields a 'Just' value.
+--
+-- See the documentation in "System.Executable.Hash" for an example of
+-- how to use this with a cabal @postBuild@ hook
+injectExecutableHash :: FilePath -> IO ()
+injectExecutableHash fp = do
+    binary <- BS.readFile fp
+    let sha1 = hash binary
+    case injectWith "executable-hash" sha1 binary of
+        Nothing -> fail "Impossible: dummy space too small for executable-hash."
+        Just binary' -> do
+            BS.writeFile fp binary'
+            putStrLn $ "Successfully wrote " ++ fp ++ " with injected hash."
+
+-- | Injects an executable hash into the specified binary.  If it
+-- doesn't exist, then this prints a message to stdout indicating that
+-- it failed to inject the hash.
+maybeInjectExecutableHash :: FilePath -> IO ()
+maybeInjectExecutableHash fp = do
+    exists <- doesFileExist fp
+    if exists
+        then injectExecutableHash fp
+        else putStrLn $ concat
+            [ "Not injecting executable hash into "
+            , fp
+            , ", as it doesn't exist."
+            ]
diff --git a/app/inject-executable-hash.hs b/app/inject-executable-hash.hs
new file mode 100644
--- /dev/null
+++ b/app/inject-executable-hash.hs
@@ -0,0 +1,11 @@
+module Main where
+
+import System.Environment (getArgs)
+import System.Executable.Hash.Internal (injectExecutableHash)
+
+main :: IO ()
+main = do
+    args <- getArgs
+    case args of
+        [exe] -> injectExecutableHash exe
+        _ -> error "Usage: inject-executable-hash <executable>"
diff --git a/executable-hash.cabal b/executable-hash.cabal
new file mode 100644
--- /dev/null
+++ b/executable-hash.cabal
@@ -0,0 +1,64 @@
+name:                executable-hash
+version:             0.1.1.1
+synopsis:            Provides the SHA1 hash of the program executable
+description:         See README.md
+homepage:            https://github.com/fpco/executable-hash
+license:             MIT
+license-file:        LICENSE
+copyright:           2015 FP Complete
+author:              Michael Sloan
+maintainer:          FP Complete <sloan@fpcomplete.com>
+homepage:            http://github.com/fpco/executable-hash
+bug-reports:         http://github.com/fpco/executable-hash/issues
+category:            System
+stability:           Stable
+build-type:          Custom
+extra-source-files:  README.md, ChangeLog.md
+cabal-version:       >= 1.10
+source-repository head
+  type: git
+  location: git://github.com/fpco/executable-hash
+
+library
+  exposed-modules:     System.Executable.Hash
+                     , System.Executable.Hash.Internal
+  build-depends:       base >= 4.0 && < 5.0
+                     , executable-path >= 0.0.3 && < 0.1
+                     , file-embed >= 0.0.8 && < 0.1
+                     , bytestring
+                     , cryptohash
+                     , directory
+  default-language:    Haskell2010
+  ghc-options:         -Wall
+
+
+executable inject-executable-hash
+  main-is:             inject-executable-hash.hs
+  hs-source-dirs:      app
+  default-language:    Haskell2010
+  build-depends:       base, executable-hash
+  ghc-options:         -Wall
+
+test-suite test-compute
+  type:                exitcode-stdio-1.0
+  hs-source-dirs:      test
+  main-is:             test-compute.hs
+  build-depends:       base, executable-hash
+  default-language:    Haskell2010
+  ghc-options:         -Wall
+
+test-suite test-inject
+  type:                exitcode-stdio-1.0
+  hs-source-dirs:      test
+  main-is:             test-inject.hs
+  build-depends:       base, executable-hash
+  default-language:    Haskell2010
+  ghc-options:         -Wall
+
+test-suite test-no-inject
+  type:                exitcode-stdio-1.0
+  hs-source-dirs:      test
+  main-is:             test-no-inject.hs
+  build-depends:       base, executable-hash
+  default-language:    Haskell2010
+  ghc-options:         -Wall
diff --git a/test/test-compute.hs b/test/test-compute.hs
new file mode 100644
--- /dev/null
+++ b/test/test-compute.hs
@@ -0,0 +1,9 @@
+import System.Executable.Hash
+
+main :: IO ()
+main = do
+    mhash <- computeExecutableHash
+    case mhash of
+        Nothing ->
+            fail "Failed to compute executable hash. This should only happen when running in GHCI."
+        Just _ -> return ()
diff --git a/test/test-inject.hs b/test/test-inject.hs
new file mode 100644
--- /dev/null
+++ b/test/test-inject.hs
@@ -0,0 +1,7 @@
+import System.Executable.Hash.Internal (injectedExecutableHash)
+
+main :: IO ()
+main =
+    case injectedExecutableHash of
+        Nothing -> fail "Expected executable hash."
+        Just _ -> return ()
diff --git a/test/test-no-inject.hs b/test/test-no-inject.hs
new file mode 100644
--- /dev/null
+++ b/test/test-no-inject.hs
@@ -0,0 +1,7 @@
+import System.Executable.Hash.Internal (injectedExecutableHash)
+
+main :: IO ()
+main =
+    case injectedExecutableHash of
+        Nothing -> return ()
+        Just x -> fail $ "Expected no injected executable hash. Instead got: " ++ show x
