diff --git a/LICENSE b/LICENSE
new file mode 100644
--- /dev/null
+++ b/LICENSE
@@ -0,0 +1,30 @@
+Copyright (c) 2017, Gregor Kleen
+
+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 Gregor Kleen nor the names of other
+      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
+OWNER 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/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/changes.md b/changes.md
new file mode 100644
--- /dev/null
+++ b/changes.md
@@ -0,0 +1,3 @@
+# 1.0.0
+
+First published version
diff --git a/src/Data/UUID/Cryptographic.hs b/src/Data/UUID/Cryptographic.hs
new file mode 100644
--- /dev/null
+++ b/src/Data/UUID/Cryptographic.hs
@@ -0,0 +1,102 @@
+{-# LANGUAGE ScopedTypeVariables #-}
+
+{-|
+Description: Reversably generate UUIDs from arbitrary serializable types in a secure fashion
+License: BSD3
+
+Given a value of a serializable type (like 'Int') we perform serialization and
+compute a cryptographic hash of the associated namespace (carried as a phantom
+type of kind 'Symbol').
+The serialized payload is then encrypted using the a symmetric cipher in CBC
+mode using the hashed namespace as an initialization vector (IV).
+
+Since the serialized payload is padded to the length of an UUID we can detect
+namespace mismatches by checking that all bytes expected to have been inserted
+during padding are nil.
+The probability of detecting a namespace mismatch is thus \(1 - 2^{128-l}\)
+where \(l\) is the length of the serialized payload.
+-}
+module Data.UUID.Cryptographic
+  ( CryptoID(..)
+  , CryptoUUID
+  , encrypt
+  , decrypt
+  , CryptoIDError(..)
+  ) where
+
+import Data.CryptoID
+import Data.CryptoID.Poly hiding (encrypt, decrypt)
+import qualified Data.CryptoID.Poly as Poly (encrypt, decrypt)
+
+import Data.UUID (UUID, toByteString, fromByteString)
+import Data.Binary
+
+import Data.ByteString (ByteString)
+import qualified Data.ByteString as ByteString
+
+import qualified Data.ByteString.Lazy as Lazy.ByteString
+
+import Data.ByteArray (ByteArrayAccess)
+import qualified Data.ByteArray as ByteArray
+
+import Control.Monad.Except
+
+import GHC.TypeLits
+
+
+type CryptoUUID (namespace :: Symbol) = CryptoID namespace UUID
+
+
+_ciphertext :: Functor m => (a -> m b) -> CryptoID n a -> m (CryptoID n b)
+_ciphertext f (CryptoID x) = CryptoID <$> f x
+
+
+-- | @pad err size src@ appends null bytes to @src@ until it has length @size@.
+--
+-- If @src@ is already longer than @size@ @err@ is thrown instead.
+pad :: (MonadError CryptoIDError m, ByteArrayAccess a) => Int -> a -> m ByteString
+pad n (ByteArray.unpack -> src)
+  | l > n     = throwError CiphertextConversionFailed
+  | otherwise = return . ByteString.pack $ src ++ replicate (n - l) 0
+  where
+    l = length src
+
+-- | Encrypt an arbitrary serializable value
+--
+-- We only expect to fail if the given value is not serialized in such a fashion
+-- that it fits within one 'CryptoCipher'-block.
+--
+-- Larger values could likely not be contained wholly within 128 bits (the size
+-- of an 'UUID') in any case.
+encrypt :: forall a m namespace.
+           ( KnownSymbol namespace
+           , Binary a
+           , MonadError CryptoIDError m
+           ) => CryptoIDKey -> a -> m (CryptoUUID namespace)
+encrypt key val = do
+  plaintext <- pad 16 . Lazy.ByteString.toStrict $ encode val
+  
+  _ciphertext uuidConversion =<< Poly.encrypt key plaintext
+    where
+      uuidConversion = maybe (throwError CiphertextConversionFailed) return . fromByteString . Lazy.ByteString.fromStrict
+
+
+-- | Decrypt an arbitrary serializable value
+--
+-- Since no integrity guarantees can be made (we do not sign the values we
+-- 'encrypt') it is likely that deserialization will fail emitting
+-- 'DeserializationError' or 'InvalidNamespaceDetected'.
+decrypt :: forall a m namespace.
+           ( KnownSymbol namespace
+           , Binary a
+           , MonadError CryptoIDError m
+           ) => CryptoIDKey -> CryptoUUID namespace -> m a
+decrypt key cId = do
+  cId' <- _ciphertext (return . Lazy.ByteString.toStrict . toByteString) cId
+  plaintext <- Lazy.ByteString.fromStrict <$> Poly.decrypt key cId'
+
+  case decodeOrFail plaintext of
+    Left err -> throwError $ DeserializationError err
+    Right (rem, _, res)
+      | Lazy.ByteString.all (== 0) rem -> return res
+      | otherwise -> throwError InvalidNamespaceDetected
diff --git a/uuid-crypto.cabal b/uuid-crypto.cabal
new file mode 100644
--- /dev/null
+++ b/uuid-crypto.cabal
@@ -0,0 +1,39 @@
+name: uuid-crypto
+version: 1.0.0
+cabal-version: >=1.10
+build-type: Simple
+license: BSD3
+license-file: LICENSE
+maintainer: aethoago@141.li
+synopsis: Reversable and secure encoding of object ids as uuids
+category: cryptography
+author: Gregor Kleen
+extra-source-files:
+    changes.md
+
+source-repository head
+    type: git
+    location: https://git.rheperire.org/cryptoids
+    subdir: uuid-crypto
+
+library
+    exposed-modules:
+        Data.UUID.Cryptographic
+    build-depends:
+        base >=4.9 && <4.11,
+        cryptoids-types ==0.0.0,
+        cryptoids ==0.0.0,
+        uuid >=1.3.13 && <1.4,
+        cryptonite >=0.23 && <0.25,
+        binary >=0.8.3.0 && <0.9,
+        memory >=0.14.6 && <0.15,
+        bytestring >=0.10.8.1 && <0.11,
+        mtl >=2.2.1 && <2.3
+    default-language: Haskell2010
+    default-extensions: KindSignatures ViewPatterns FlexibleContexts
+                        GeneralizedNewtypeDeriving PatternGuards RecordWildCards DataKinds
+                        DeriveDataTypeable DeriveGeneric
+    other-extensions: ScopedTypeVariables
+    hs-source-dirs: src
+    ghc-options: -Wall -fno-warn-name-shadowing
+
