diff --git a/LICENSE b/LICENSE
new file mode 100644
--- /dev/null
+++ b/LICENSE
@@ -0,0 +1,30 @@
+Copyright Marcello Seri (c) 2016
+
+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 Marcello Seri 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/README.md b/README.md
new file mode 100644
--- /dev/null
+++ b/README.md
@@ -0,0 +1,37 @@
+# Crypto Multihash
+
+Multihash library implemented on top of [cryptonite](https://hackage.haskell.org/package/cryptonite) cryptographic library. 
+Multihash is a protocol for encoding the hash algorithm and digest length at the start of the digest, see the official [multihash github page](https://github.com/jbenet/multihash/).
+
+This library is still experimental and the api is not guaranteed stable. 
+I will increment the version number appropriately in case of breaking changes.
+
+For the moment the library implements all the expected hashing algorithms with the exception of shake-128 and shake-256. A Multihash can be encoded in hex (`Base16`), bitcoin base58 (`Base58`) and base64 (`Base64`). 
+
+The `Base32` encoding is not yet supported due to discrepancy between the encoding from `Data.ByteArray.Encoding` and the one appearing in the official multihash page.
+
+# Usage
+
+```{.haskell}
+{-# LANGUAGE OverloadedStrings #-}
+
+import Crypto.Multihash
+import Data.ByteString (ByteString)
+
+main = do
+    let m = multihash SHA256 ("test"::ByteString)
+    putStrLn $ "Base16: " ++ (encode Base16 m)
+    putStrLn $ "Base58: " ++ (encode Base58 m)
+    putStrLn $ "Base64: " ++ (encode Base64 m)
+```
+
+# Test
+
+Some preliminary tests can be performed with `stack test`.
+A simple example encoder is in `app/Main.hs`. You can run it on files (e.g. `echo -n test | stack exec mh -- somefile someotherfile`) or read data from the standard input (e.g. `echo -n test | stack exec mh -- -`)
+
+# TODO
+- Implement hash checker that takes some data and an encoded multihash and check that the multihash corresponds to the data (inferring automatically the appropriate hash function)
+- Evaluate if throwing an error in the encode function is the wanted behaviour and anyway implement a safe version returning an Either type
+- Implement `shake-128` and `shake-256` multihashes
+- Implement `Base32` encoding
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/app/Main.hs b/app/Main.hs
new file mode 100644
--- /dev/null
+++ b/app/Main.hs
@@ -0,0 +1,65 @@
+{-# LANGUAGE OverloadedStrings #-}
+
+module Main where
+
+import Control.Monad
+import Crypto.Multihash
+import Data.ByteString (ByteString)
+import qualified Data.ByteString as B
+import Data.List
+import System.Console.GetOpt
+import System.IO hiding (withFile)
+import System.Environment
+import System.Exit
+import Text.Printf (printf)
+
+main :: IO ()
+main = do
+  (args, files) <- getArgs >>= parse
+  mapM_ printers files
+  putStrLn "Done! Note: shake-128/256 and Base32 are not yet part of the library"
+ 
+printer :: (HashAlgorithm a, Codable a, Show a) => a -> ByteString -> IO ()
+printer alg bs = do
+  let m = multihash alg bs
+  putStrLn $ printf "Hash algorithm: %s" (show alg)
+  putStrLn $ printf "Base16: %s" (encode Base16 m)
+  -- Base32 missing
+  putStrLn $ printf "Base58: %s" (encode Base58 m)
+  putStrLn $ printf "Base64: %s" (encode Base64 m)
+  putStrLn ""
+
+printers f = do
+  d <- withFile f
+  putStrLn $ printf "Hashing %s\n" (if f == "-" then show d else show f)
+  printer SHA1 d
+  printer SHA256 d
+  printer SHA512 d
+  printer SHA3_512 d
+  printer SHA3_384 d
+  printer SHA3_256 d
+  printer SHA3_224 d
+  printer Blake2b_512 d
+  printer Blake2s_256 d
+  putStrLn ""
+  where withFile f = if f == "-" then B.getContents else B.readFile f
+
+data Flag = Help                  -- --help
+          deriving (Eq,Ord,Enum,Show,Bounded)
+ 
+flags = [Option [] ["help"] (NoArg Help) "Print this help message"]
+ 
+parse argv = case getOpt Permute flags argv of
+    (args,fs,[]) -> do
+        let files = if null fs then ["-"] else fs
+        if Help `elem` args
+            then do hPutStrLn stderr (usageInfo header flags)
+                    exitWith ExitSuccess
+            else return (nub (concatMap set args), files)
+ 
+    (_,_,errs)   -> do
+        hPutStrLn stderr (concat errs ++ usageInfo header flags)
+        exitWith (ExitFailure 1)
+ 
+    where header = "Usage: mh [file ...]"
+          set f  = [f]
diff --git a/crypto-multihash.cabal b/crypto-multihash.cabal
new file mode 100644
--- /dev/null
+++ b/crypto-multihash.cabal
@@ -0,0 +1,53 @@
+name:                crypto-multihash
+version:             0.1.0.0
+synopsis:            Multihash library on top of cryptonite crypto library
+description:         Multihash is a protocol for encoding the hash algorithm
+                     and digest length at the start of the digest, see the official
+                     <https://github.com/jbenet/multihash/ multihash github>.
+                     Usage and additional informations are on README.md
+homepage:            https://github.com/mseri/crypto-multihash#readme
+license:             BSD3
+license-file:        LICENSE
+author:              Marcello Seri
+maintainer:          marcello.seri@gmail.com
+copyright:           2016 Marcello Seri
+category:            Cryptography
+stability:           Experimental
+build-type:          Simple
+extra-source-files:  README.md
+cabal-version:       >=1.10
+
+library
+  hs-source-dirs:      src
+  exposed-modules:     Crypto.Multihash
+  build-depends:       base >= 4.7 && < 5
+                     , base58-bytestring
+                     , bytestring
+                     , containers
+                     , cryptonite
+                     , memory
+  default-language:    Haskell2010
+
+executable mh
+  hs-source-dirs:      app
+  main-is:             Main.hs
+  ghc-options:         -threaded -rtsopts -with-rtsopts=-N
+  build-depends:       base
+                     , bytestring
+                     , crypto-multihash
+  default-language:    Haskell2010
+
+test-suite crypto-multihash-test
+  type:                exitcode-stdio-1.0
+  hs-source-dirs:      test
+  main-is:             Spec.hs
+  build-depends:       base
+                     , bytestring
+                     , crypto-multihash
+                     , hspec
+  ghc-options:         -threaded -rtsopts -with-rtsopts=-N
+  default-language:    Haskell2010
+
+source-repository head
+  type:     git
+  location: https://github.com/mseri/crypto-multihash
diff --git a/src/Crypto/Multihash.hs b/src/Crypto/Multihash.hs
new file mode 100644
--- /dev/null
+++ b/src/Crypto/Multihash.hs
@@ -0,0 +1,129 @@
+module Crypto.Multihash
+  ( MultihashDigest
+  , Base            (..)
+  , Codable         (..)
+  , HashAlgorithm   (..)
+  , SHA1(..)
+  , SHA256(..)
+  , SHA512(..)
+  , SHA3_512(..)
+  , SHA3_384(..)
+  , SHA3_256(..)
+  , SHA3_224(..)
+  , Blake2b_512(..)
+  , Blake2s_256(..)
+  , encode
+  , multihash
+  , multihashlazy
+  ) where
+
+import Crypto.Hash (HashAlgorithm(..), Digest(..), hash, hashlazy)
+import Crypto.Hash.Algorithms
+import Crypto.Hash.IO
+import Data.ByteArray (ByteArrayAccess, Bytes)
+import qualified Data.ByteArray as BA
+import qualified Data.ByteArray.Encoding as BE
+import qualified Data.ByteString as BS
+import qualified Data.ByteString.Lazy as BL
+import qualified Data.ByteString.Base58 as B58
+import Data.Word (Word8)
+import Text.Printf (printf)
+
+data Base = Base16  -- ^ Hex encoding
+          | Base32  -- ^ Not implemented. For reasons that I did not investigate, the instance in Data.ByteArray produces output not conformant with the multihash spec.
+          | Base58  -- ^ Bitcoin Base58 encoding, the one used also by IPFS
+          | Base64  -- ^ Base64 encoding
+          deriving (Eq)
+
+-- | Multihash Digest container
+data MultihashDigest a = MultihashDigest
+  { getAlgorithm :: a
+  , getLength :: Int
+  , getDigest :: Digest a
+  }
+
+class Codable a where
+  toCode :: a -> Int
+
+instance Codable SHA1 where
+  toCode SHA1 = 0x11
+instance Codable SHA256 where
+  toCode SHA256 = 0x12
+instance Codable SHA512 where
+  toCode SHA512 = 0x13
+instance Codable SHA3_512 where
+  toCode SHA3_512 = 0x14
+instance Codable SHA3_384 where
+  toCode SHA3_384 = 0x15
+instance Codable SHA3_256 where
+  toCode SHA3_256 = 0x16
+instance Codable SHA3_224 where
+  toCode SHA3_224 = 0x17
+instance Codable Blake2b_512 where
+  toCode Blake2b_512 = 0x40
+instance Codable Blake2s_256 where
+  toCode Blake2s_256 = 0x41
+
+-- TODO: add shake-128/256 to Codable. Probably
+-- fromCode 0x18 = Keccak_256
+-- fromCode 0x19 = Keccak_512
+
+instance Show (MultihashDigest a) where
+    show (MultihashDigest _ _ d) = show d
+
+multihashlazy :: (HashAlgorithm a, Codable a) => a -> BL.ByteString -> MultihashDigest a
+multihashlazy alg bs = let digest = (hashlazy bs) 
+                       in MultihashDigest alg (BA.length digest) digest
+
+multihash :: (HashAlgorithm a, Codable a, ByteArrayAccess bs) => a -> bs -> MultihashDigest a
+multihash alg bs = let digest = (hash bs) 
+                   in MultihashDigest alg (BA.length digest) digest
+
+-- | Encoder for 'Multihash'es.
+--   Throws an error if the Multihash length field does not match the Digest length
+encode :: (HashAlgorithm a, Codable a, Show a) => Base -> MultihashDigest a -> String
+encode base (MultihashDigest alg len md) = if len == len'
+    then map (toEnum . fromIntegral) fullDigestUnpacked
+    else error $ printf "Corrupted %s MultihashDigest. Lenght is %d but should be %d." (show alg) len len'
+  where
+    len' :: Int
+    len' = BA.length md
+
+    fullDigestUnpacked :: [Word8]
+    fullDigestUnpacked = BA.unpack $ encoder fullDigest
+      where 
+        encoder :: ByteArrayAccess a => a -> Bytes
+        encoder bs = case base of
+                    --Base2  -> BA.convert $ bs
+                    Base16 -> BE.convertToBase BE.Base16 bs
+                    Base32 -> error "Base32 encoder not implemented"
+                    Base58 -> BA.convert $ B58.encodeBase58 B58.bitcoinAlphabet $ (BA.convert bs :: BS.ByteString)
+                    Base64 -> BE.convertToBase BE.Base64 bs
+
+    fullDigest :: Bytes
+    fullDigest = BA.pack [dHead, dSize] `BA.append` dTail
+      where
+        dHead :: Word8
+        dHead = fromIntegral $ toCode alg
+        dSize :: Word8
+        dSize = fromIntegral $ len'
+        dTail :: Bytes
+        dTail = BA.convert md
+
+--checkHash :: Base -> String -> 
+
+-- data MultihashAlgorithm = S1 SHA1 | S256 SHA256 | S512 SHA512 
+--                         | S3512 SHA3_512 | S3384 SHA3_384 | S3256 SHA3_256 | S3224 SHA3_224
+--                         | B2b Blake2b_512 | B2s Blake2s_256
+
+-- toCode :: MultihashAlgorithm -> Int
+-- toCode (S1 SHA1)        = 0x11
+-- toCode (S256 SHA256)      = 0x12
+-- toCode (S512 SHA512)      = 0x13
+-- toCode (S3512 SHA3_512)    = 0x14
+-- toCode (S3384 SHA3_384)    = 0x15
+-- toCode (S3256 SHA3_256)    = 0x16
+-- toCode (S3224 SHA3_224)    = 0x17
+-- toCode (B2b Blake2b_512) = 0x40
+-- toCode (B2s Blake2s_256) = 0x41
+-- toCode _           = error "Multihash: unknown or unimplemented hash function code"
diff --git a/test/Spec.hs b/test/Spec.hs
new file mode 100644
--- /dev/null
+++ b/test/Spec.hs
@@ -0,0 +1,50 @@
+{-# LANGUAGE OverloadedStrings #-}
+
+import Crypto.Multihash
+import Data.ByteString (ByteString)
+import Test.Hspec
+import Text.Printf (printf)
+
+main :: IO ()
+main = hspec $ do
+  testMHEncoding SHA1 ( "1114a94a8fe5ccb19ba61c4c0873d391e987982fbbd3"
+                      , "5dt9CqvXK9qs7vazf7k7ZRqe28VPTg"
+                      , "ERSpSo/lzLGbphxMCHPTkemHmC+70w==")
+  testMHEncoding SHA256 ( "12209f86d081884c7d659a2feaa0c55ad015a3bf4f1b2b0b822cd15d6c15b0f00a08"
+                        , "QmZ5NmGeStdit7tV6gdak1F8FyZhPsfA843YS9f2ywKH6w"
+                        , "EiCfhtCBiEx9ZZov6qDFWtAVo79PGysLgizRXWwVsPAKCA==")
+  testMHEncoding SHA512 ( "1340ee26b0dd4af7e749aa1a8ee3c10ae9923f618980772e473f8819a5d4940e0db27ac185f8a0e1d5f84f88bc887fd67b143732c304cc5fa9ad8e6f57f50028a8ff"
+                        , "8VxYhLL7s5BvLogtUGgNJ7DebZ5Ba9mG3izfc7v6o4RZ28x469vJaifa3TQ13Z9DycmAuJWnp7ErkZofm4rsMo78fQ"
+                        , "E0DuJrDdSvfnSaoajuPBCumSP2GJgHcuRz+IGaXUlA4NsnrBhfig4dX4T4i8iH/WexQ3MsMEzF+prY5vV/UAKKj/")
+  testMHEncoding SHA3_512 ( "14409ece086e9bac491fac5c1d1046ca11d737b92a2b2ebd93f005d7b710110c0a678288166e7fbe796883a4f2e9b3ca9f484f521d0ce464345cc1aec96779149c14"
+                          , "8tXEcJyq2MCx27UHYbZxmte37ezBawV35QhfKPtq5QeSnX66q4DDf1cwMYUh2pUVbxdQgrDaSjbrPrfNxzvSSLQAtT"
+                          , "FECezghum6xJH6xcHRBGyhHXN7kqKy69k/AF17cQEQwKZ4KIFm5/vnlog6Ty6bPKn0hPUh0M5GQ0XMGuyWd5FJwU")
+  testMHEncoding SHA3_384 ( "1530e516dabb23b6e30026863543282780a3ae0dccf05551cf0295178d7ff0f1b41eecb9db3ff219007c4e097260d58621bd"
+                          , "G9LerVN7c3uUAAymoAGkCGZPn53PZi1SHwPJ2nznLp82jcM2M1KLwpfrZh3F1QRVG3f2"
+                          , "FTDlFtq7I7bjACaGNUMoJ4Cjrg3M8FVRzwKVF41/8PG0Huy52z/yGQB8TglyYNWGIb0=")
+  testMHEncoding SHA3_256 ( "162036f028580bb02cc8272a9a020f4200e346e276ae664e45ee80745574e2f5ab80"
+                          , "W1d9SeHn1mCnY3jZMs5YeqfFbwEnq5gQy1VDymGoPK28RD"
+                          , "FiA28ChYC7AsyCcqmgIPQgDjRuJ2rmZORe6AdFV04vWrgA==")
+  testMHEncoding SHA3_224 ( "171c3797bf0afbbfca4a7bbba7602a2b552746876517a7f9b7ce2db0ae7b"
+                          , "5daZNVMeTfSuCvu7rBKsFkzEMebnuGjNpos1ThF1c"
+                          , "Fxw3l78K+7/KSnu7p2AqK1UnRodlF6f5t84tsK57")
+  testMHEncoding Blake2b_512 ( "4040a71079d42853dea26e453004338670a53814b78137ffbed07603a41d76a483aa9bc33b582f77d30a65e6f29a896c0411f38312e1d66e0bf16386c86a89bea572"
+                             , "S2XUqUDxz3MHMZtJpCZKt5oRjXHQ34gsyDBT759qNwoSP9rDBHVHxjQUQtXfExotxTqf4rMEXQkNmXE3N9mhoZX6wK"
+                             , "QECnEHnUKFPeom5FMAQzhnClOBS3gTf/vtB2A6QddqSDqpvDO1gvd9MKZebymolsBBHzgxLh1m4L8WOGyGqJvqVy")
+  testMHEncoding Blake2s_256 ( "4120f308fc02ce9172ad02a7d75800ecfc027109bc67987ea32aba9b8dcc7b10150e"
+                             , "2UPuEK7FVakwP3yUak5jKQhZb6pgpbcqYoRZ2tDzgeCfVr5"
+                             , "QSDzCPwCzpFyrQKn11gA7PwCcQm8Z5h+oyq6m43MexAVDg==")
+  where
+    testMHEncoding :: (HashAlgorithm a, Codable a, Show a) => a 
+                      -> (String, String, String) -> SpecWith ()
+    testMHEncoding alg (sm16, sm58, sm64) = do
+        describe (printf "Encoding %s multihash" (show alg)) $ do
+          it "returns the correct Base16 hash" $ 
+            encode Base16 m `shouldBe` sm16
+          it "returns the correct Base58 hash" $ 
+            encode Base58 m `shouldBe` sm58
+          it "returns the correct Base64 hash" $ 
+            encode Base64 m `shouldBe` sm64
+      where 
+        m = multihash alg ("test"::ByteString)
+  
