diff --git a/LICENSE b/LICENSE
new file mode 100644
--- /dev/null
+++ b/LICENSE
@@ -0,0 +1,22 @@
+The MIT License (MIT)
+
+Copyright (c) 2015 Sam Rijs
+
+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,2 @@
+coholos
+=======
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/hwsl2.cabal b/hwsl2.cabal
new file mode 100644
--- /dev/null
+++ b/hwsl2.cabal
@@ -0,0 +1,86 @@
+-- Initial hwsl2.cabal generated by cabal init.  For further documentation,
+--  see http://haskell.org/cabal/users-guide/
+
+-- The name of the package.
+name:                hwsl2
+
+-- The package version.  See the Haskell package versioning policy (PVP) 
+-- for standards guiding when and how versions should be incremented.
+-- http://www.haskell.org/haskellwiki/Package_versioning_policy
+-- PVP summary:      +-+------- breaking API changes
+--                   | | +----- non-breaking API additions
+--                   | | | +--- code changes with no API change
+version:             0.1.0.0
+
+-- A short (one-line) description of the package.
+synopsis:            Hashing with SL2
+
+-- A longer description of the package.
+description:
+  An algebraic hash function, inspired by the paper "Hashing with SL2" by Tillich and Zemor.
+  .
+  The hash function is based on matrix multiplication in the special linear group
+  of degree 2, over a Galois field of order 2^127,  with all computations modulo
+  the polynomial x^127 + x^63 + 1.
+  .
+  This construction gives some nice properties, which traditional "bit-scambling"
+  hash functions don't possess, including it being composable. It holds:
+  .
+  > hash (m1 <> m2) == hash m1 <> hash m2
+  .
+  All operations in this package are implemented in a very efficient manner using SSE instructions.
+
+-- URL for the project homepage or repository.
+homepage:            https://github.com/srijs/hwsl2
+
+-- The license under which the package is released.
+license:             MIT
+
+-- The file containing the license text.
+license-file:        LICENSE
+
+-- The package author(s).
+author:              Sam Rijs
+
+-- An email address to which users can send suggestions, bug reports, and 
+-- patches.
+maintainer:          srijs@airpost.net
+
+-- A copyright notice.
+-- copyright:           
+
+category:            Data
+
+build-type:          Simple
+
+-- Extra files to be distributed with the package, such as examples or a 
+-- README.
+extra-source-files:  README.md
+
+-- Constraint on the version of Cabal needed to build this package.
+cabal-version:       >=1.10
+
+
+library
+  -- Modules exported by the library.
+  exposed-modules:     Data.Hash.SL2
+  
+  -- Modules included in this library but not exported.
+  -- other-modules:       
+  
+  -- LANGUAGE extensions used by modules in this package.
+  other-extensions:    ForeignFunctionInterface, EmptyDataDecls
+  
+  -- Other library packages from which modules are imported.
+  build-depends:       base >=4.7 && <4.8, bytestring >=0.10 && <0.11
+  
+  -- Directories containing source files.
+  hs-source-dirs:      src
+
+  -- Options for foreign source files.
+  c-sources:           src/tillich-zemor.c
+  cc-options:          -msse2 -msse4.1 -mpclmul
+  
+  -- Base language which the package is written in.
+  default-language:    Haskell2010
+  
diff --git a/src/Data/Hash/SL2.hs b/src/Data/Hash/SL2.hs
new file mode 100644
--- /dev/null
+++ b/src/Data/Hash/SL2.hs
@@ -0,0 +1,110 @@
+{-# LANGUAGE ForeignFunctionInterface, EmptyDataDecls #-}
+
+-- |
+-- Module     : Data.Hash.SL2
+-- License    : MIT
+-- Maintainer : Sam Rijs <srijs@airpost.net>
+--
+-- An algebraic hash function, inspired by the paper "Hashing with SL2" by
+-- Tillich and Zemor.
+--
+-- The hash function is based on matrix multiplication in the special linear group
+-- of degree 2, over a Galois field of order 2^127,  with all computations modulo
+-- the polynomial x^127 + x^63 + 1.
+--
+-- This construction gives some nice properties, which traditional "bit-scambling"
+-- hash functions don't possess, including it being composable. It holds:
+--
+-- prop> hash (m1 <> m2) == hash m1 <> hash m2
+--
+-- All operations in this package are implemented in a very efficient manner using SSE instructions.
+--
+
+module Data.Hash.SL2 (Hash, hash, (<+), (+>), parse) where
+
+import Prelude hiding (concat)
+
+import Foreign
+import Foreign.Ptr
+import Foreign.C.Types
+import Foreign.C.String
+import Foreign.Marshal.Array
+import Foreign.Marshal.Utils
+import Foreign.ForeignPtr
+import System.IO.Unsafe
+
+import Data.ByteString (ByteString)
+import Data.ByteString.Unsafe
+
+import Data.Monoid
+import Data.Functor
+
+foreign import ccall "tillich-zemor.h tz_hash_eq"
+  tzHashEq :: Ptr () -> Ptr () -> IO CInt
+
+foreign import ccall "tillich-zemor.h tz_hash_unit"
+  tzHashUnit :: Ptr () -> IO ()
+
+foreign import ccall "tillich-zemor.h tz_hash_append"
+  tzHashAppend :: Ptr () -> Ptr CChar -> CSize -> IO ()
+
+foreign import ccall "tillich-zemor.h tz_hash_prepend"
+  tzHashPrepend :: Ptr () -> Ptr CChar -> CSize -> IO ()
+
+foreign import ccall "tillich-zemor.h tz_hash_concat"
+  tzHashConcat :: Ptr () -> Ptr () -> Ptr () -> IO ()
+
+foreign import ccall "tillich-zemor.h tz_hash_serialize"
+  tzHashSerialize :: Ptr () -> Ptr CChar -> IO ()
+
+foreign import ccall "tillich-zemor.h tz_hash_unserialize"
+  tzHashUnserialize :: Ptr () -> Ptr CChar -> IO ()
+
+-- | Opaque representation of a 512 bit hash.
+newtype Hash = H (ForeignPtr ())
+
+tzHashSize = 64
+tzHashLen = 86
+
+withHashPtr :: Hash -> (Ptr () -> IO a) -> IO a
+withHashPtr (H fp) = withForeignPtr fp
+
+withHashPtr2 :: Hash -> Hash -> (Ptr () -> Ptr () -> IO a) -> IO a
+withHashPtr2 a b f = withHashPtr a (withHashPtr b . f)
+
+withHashPtrNew :: (Ptr () -> IO a) -> IO (Hash, a)
+withHashPtrNew f = mallocForeignPtrBytes tzHashSize >>= \fp -> (\r -> (H fp, r)) <$> withForeignPtr fp f
+
+withHashPtrCopy :: Hash -> (Ptr () -> IO a) -> IO (Hash, a)
+withHashPtrCopy h f = withHashPtr h $ \hp -> withHashPtrNew $ \hp' -> copyBytes hp' hp tzHashSize >> f hp'
+
+instance Show Hash where
+  show h = unsafePerformIO $ allocaBytes tzHashLen $ \p -> withHashPtr h (flip tzHashSerialize p) >> peekCStringLen (p, tzHashLen)
+
+instance Eq Hash where
+  a == b = toBool $ unsafePerformIO $ withHashPtr2 a b tzHashEq
+
+instance Monoid Hash where
+  mempty = fst $ unsafePerformIO $ withHashPtrNew tzHashUnit
+  mappend a b = fst $ unsafePerformIO $ withHashPtrNew (withHashPtr2 a b . tzHashConcat)
+
+-- | /O(n)/ Calculate the hash of the 'ByteString'. Alias for @('mempty' '<+')@.
+hash :: ByteString -> Hash
+hash = (<+) mempty
+
+-- | /O(n)/ Append the hash of the 'ByteString' to the existing 'Hash'.
+-- A significantly faster equivalent of @(flip ('<>') . 'hash')@.
+(<+) :: Hash -> ByteString -> Hash
+(<+) h s = fst $ unsafePerformIO $ unsafeUseAsCStringLen s $ \(s', len) ->
+  withHashPtrCopy h $ \hp -> tzHashAppend hp s' $ fromIntegral len
+
+-- | /O(n)/ Prepend the hash of the 'ByteString' to the existing 'Hash'.
+-- A significantly faster equivalent of @(('<>') . 'hash')@.
+(+>) :: ByteString -> Hash -> Hash
+(+>) s h = fst $ unsafePerformIO $ unsafeUseAsCStringLen s $ \(s', len) ->
+  withHashPtrCopy h $ \hp -> tzHashPrepend hp s' $ fromIntegral len
+
+-- | /O(1)/ Parse the representation generated by 'show'.
+parse :: String -> Maybe Hash
+parse s = (\(h, r) -> h <$ r) $ unsafePerformIO $ withHashPtrNew $ \hp -> withCAStringLen s $ \(s', len) ->
+  if len == tzHashLen then Just <$> tzHashUnserialize hp s' else return Nothing
diff --git a/src/tillich-zemor.c b/src/tillich-zemor.c
new file mode 100644
--- /dev/null
+++ b/src/tillich-zemor.c
@@ -0,0 +1,44 @@
+#include "tillich-zemor.h"
+#include "sl2-inl.h"
+
+struct tz_hash_struct {
+  sl2_t sl2;
+};
+
+int tz_hash_eq(tz_hash_t a, tz_hash_t b) {
+  return sl2_eq(a->sl2, b->sl2);
+}
+
+void tz_hash_copy(tz_hash_t dst, tz_hash_t src) {
+  sl2_copy(dst->sl2, src->sl2);
+}
+
+void tz_hash_unit(tz_hash_t h) {
+  sl2_unit(h->sl2);
+}
+
+void tz_hash_append(tz_hash_t h, unsigned char *buf, size_t n) {
+  size_t i;
+  for (i = 0; i < n; i++) {
+    sl2_mul_bits_right(h->sl2, buf[i]);
+  }
+}
+
+void tz_hash_prepend(tz_hash_t h, unsigned char *buf, size_t n) {
+  size_t i;
+  for (i = n; i > 0; i--) {
+    sl2_mul_bits_left(h->sl2, buf[i - 1]);
+  }
+}
+
+void tz_hash_concat(tz_hash_t c, tz_hash_t a, tz_hash_t b) {
+  sl2_mul(c->sl2, a->sl2, b->sl2);
+}
+
+void tz_hash_serialize(tz_hash_t h, unsigned char buf[86]) {
+  sl2_serialize(h->sl2, buf);
+}
+
+void tz_hash_unserialize(tz_hash_t h, unsigned char buf[86]) {
+  sl2_unserialize(h->sl2, buf);
+}
