diff --git a/LICENSE b/LICENSE
new file mode 100644
--- /dev/null
+++ b/LICENSE
@@ -0,0 +1,29 @@
+BSD 3-Clause License
+
+Copyright (c) 2017, Dimitri DeFigueiredo
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+
+* Redistributions of source code must retain the above copyright notice, this
+  list of conditions and the following disclaimer.
+
+* 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.
+
+* Neither the name of the copyright holder nor the names of its
+  contributors may be used to endorse or promote products derived from
+  this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "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 COPYRIGHT HOLDER 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/README.md b/README.md
new file mode 100644
--- /dev/null
+++ b/README.md
@@ -0,0 +1,51 @@
+# stego-uuid
+A generator and verifier for steganographic numbers that look random
+
+The standard use of this package is to generate a 64-bit number and use
+this, along with a secret key, as input to the marking function.
+
+Example:
+
+```haskell
+
+secretHi = KeyHi64 12345  -- secret key hi  64 bits
+secretLo = KeyLo64 67890  -- secret key low 64 bits
+
+main :: IO ()
+main = do
+
+  putStrLn "Is this marked?"
+  r  <- randomIO :: IO Word64           -- get 64-bit random number
+  let x = mark secretHi secretLo r      -- produce marked 128-bit UUID
+  print x                               
+  print (isMarked secretHi secretLo x)  -- True
+```
+
+## Security considerations
+This is a poor man's MAC. We use SHA256 to generate the second half of the UUID from the 64-bit
+random looking input and the secret key. The small number of bits limits the security.
+
+We will start getting collisions on the 64-bit random number after about 2^32 numbers are used.
+But this just means we will be providing the function with the same input, so the same output
+will be produced.
+
+### False Negatives
+This is zero. If you produced the number with the `mark` function, this number will always be
+detected with `isMarked` as long as you provide the correct key.
+
+### False positives
+This is false detection. We worry about a UUID that was *not* generated using `mark` but is
+detected as marked by `isMarked`. (A malicious adversary can always replay any UUIDs known as
+marked. Thus, we will consider only new UUIDs.)
+
+Assuming SHA256 is a perfect pseudo-random function, its truncated output, i.e. the last 64 bits of
+the UUID, does not leak any information about the secret key. Given a fixed secret key, for any
+64-bit input (corresponding to the the first half of the UUID), there is a unique 64-bit output
+(corresponding to the second half of the UUID). There is only one such output per 64-bit input. So,
+the probability of finding such input from a random draw is 2^(-64). The adversary would have more
+than a 1/2 chance of finding it after 2^63 guesses.
+
+### Information leakage
+The adversary can only know a UUID is marked if it is able to differentiate the output of truncated
+SHA256 from a pseudo-random function. I am unaware of any significant results in doing so. The key
+is 128-bits in length, so going through all possible values is currently unfeasible.
diff --git a/Setup.hs b/Setup.hs
new file mode 100644
--- /dev/null
+++ b/Setup.hs
@@ -0,0 +1,2 @@
+import Distribution.Simple
+main = defaultMain
diff --git a/src/Crypto/Stego/UUID.hs b/src/Crypto/Stego/UUID.hs
new file mode 100644
--- /dev/null
+++ b/src/Crypto/Stego/UUID.hs
@@ -0,0 +1,47 @@
+{- |
+Module: Crypto.Stego.UUID
+See README.md for an example and security considerations.
+-}
+
+module Crypto.Stego.UUID (
+  mark ,
+  isMarked,
+  StegoKeyHi (..),
+  StegoKeyLo (..)
+  ) where
+
+
+import           Data.Maybe
+import           Data.Word
+
+import           Data.UUID
+import           Crypto.Hash
+
+import qualified Data.ByteArray             as BA
+import qualified Data.ByteString.Builder    as BSB
+import qualified Data.ByteString            as BS
+import qualified Data.ByteString.Lazy       as BSL
+
+-- | Secret key, high 64 bits.
+newtype StegoKeyHi = KeyHi64 Word64
+-- | Secret key, low 64 bits.
+newtype StegoKeyLo = KeyLo64 Word64
+
+-- | Creates a secretly "marked" UUID given a two-part secret key and random input
+mark :: StegoKeyHi -> StegoKeyLo -> Word64 -> UUID
+mark (KeyHi64 selfKeyHi) (KeyLo64 selfKeyLo) rand =
+  let selfKeyHiAsLazyBS = BSB.toLazyByteString (BSB.word64BE selfKeyHi)
+      selfKeyLoAsLazyBS = BSB.toLazyByteString (BSB.word64BE selfKeyLo)
+      randAsLazyBS      = BSB.toLazyByteString (BSB.word64BE rand)
+      hashInput         = BSL.concat [randAsLazyBS, selfKeyHiAsLazyBS, selfKeyLoAsLazyBS]
+      digest            = hash (BSL.toStrict hashInput) :: Digest SHA256
+      hashBitsStrict    = BS.take 8  (BA.convert digest)
+      halfAndHalf       = BSL.concat [randAsLazyBS, BSL.fromStrict hashBitsStrict]
+   in fromJust (fromByteString halfAndHalf)
+
+-- | Detects UUIDs previously marked with the given key
+isMarked :: StegoKeyHi -> StegoKeyLo -> UUID -> Bool
+isMarked selfKeyHi selfKeyLo uuid =
+  let (rHi, rLo, _, _) = toWords uuid
+      r = fromIntegral rHi * 2^(32 :: Int) + fromIntegral rLo
+  in mark selfKeyHi selfKeyLo r == uuid
diff --git a/stego-uuid.cabal b/stego-uuid.cabal
new file mode 100644
--- /dev/null
+++ b/stego-uuid.cabal
@@ -0,0 +1,51 @@
+name:                stego-uuid
+version:             1.0.0.0
+synopsis:            Generator and verifier for steganographic numbers
+description:
+  `stego-uuid` allows one to mark 128-bit UUIDs. If created from a random 64-bit number, the
+  whole 128-bit UUID will look random to everyone, except those who know the secret detection key.
+
+homepage:            https://github.com/dimitri-xyz/stego-uuid#readme
+author:              Dimitri DeFigueiredo
+maintainer:          defigueiredo@ucdavis.edu
+Bug-Reports:         https://github.com/dimitri-xyz/stego-uuid/issues
+copyright:           2017 Dimitri DeFigueiredo
+license:             BSD3
+license-file:        LICENSE
+category:            Steganography, Cryptography
+build-type:          Simple
+extra-doc-files:     README.md
+cabal-version:       >=1.20
+
+library
+  hs-source-dirs:     src
+  exposed-modules:    Crypto.Stego.UUID
+
+  default-language:   Haskell2010
+  build-depends:      base        >= 4.9.1  && < 5
+                    , uuid        >= 1.3.13 && < 1.4
+                    , cryptonite  >= 0.21   && < 0.22
+                    , bytestring  >= 0.10.8 && < 0.11
+                    , memory      >= 0.14.1 && < 0.15
+
+  ghc-options: -Wall -fwarn-incomplete-record-updates -fwarn-incomplete-patterns -fwarn-incomplete-uni-patterns -j
+
+
+test-suite test-stego-uuid
+
+  type:             exitcode-stdio-1.0
+  hs-source-dirs:   test
+  main-is:          Test.hs
+
+  build-depends:      base        >= 4.9.1  && < 5
+                    , stego-uuid
+                    , random      >= 1.1    && < 1.2
+                    , uuid        >= 1.3.13 && < 1.4
+
+  ghc-options: -Wall -fwarn-incomplete-record-updates -fwarn-incomplete-patterns -fwarn-incomplete-uni-patterns -j -threaded -rtsopts -with-rtsopts=-N
+
+  default-language: Haskell2010
+
+source-repository head
+  type:     git
+  location: https://github.com/dimitri-xyz/stego-uuid
diff --git a/test/Test.hs b/test/Test.hs
new file mode 100644
--- /dev/null
+++ b/test/Test.hs
@@ -0,0 +1,22 @@
+import System.Random
+import Data.Word
+import Data.UUID
+
+import Crypto.Stego.UUID
+
+
+secretHi = KeyHi64 12345
+secretLo = KeyLo64 67890
+
+main :: IO ()
+main = do
+
+  putStrLn ""
+  r  <- randomIO :: IO Word64
+  let x = mark secretHi secretLo r
+  print x
+  print (isMarked secretHi secretLo x)  -- True
+
+  y <- randomIO :: IO UUID
+  print y
+  print (isMarked secretHi secretLo y)  -- False
