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/UNLICENSE b/UNLICENSE
new file mode 100644
--- /dev/null
+++ b/UNLICENSE
@@ -0,0 +1,24 @@
+This is free and unencumbered software released into the public domain.
+
+Anyone is free to copy, modify, publish, use, compile, sell, or
+distribute this software, either in source code form or as a compiled
+binary, for any purpose, commercial or non-commercial, and by any
+means.
+
+In jurisdictions that recognize copyright laws, the author or authors
+of this software dedicate any and all copyright interest in the
+software to the public domain. We make this dedication for the benefit
+of the public at large and to the detriment of our heirs and
+successors. We intend this dedication to be an overt act of
+relinquishment in perpetuity of all present and future rights to this
+software under copyright law.
+
+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 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.
+
+For more information, please refer to <http://unlicense.org/>
diff --git a/base58-bytestring.cabal b/base58-bytestring.cabal
new file mode 100644
--- /dev/null
+++ b/base58-bytestring.cabal
@@ -0,0 +1,51 @@
+name:                base58-bytestring
+version:             0.0.1
+synopsis:            Implementation of BASE58 transcoding for ByteStrings
+
+description: Implementation of BASE58 transcoding copy-pasted from
+             haskoin package
+
+homepage: https://bitbucket.org/s9gf4ult/base58-bytestring
+license:             PublicDomain
+license-file:        UNLICENSE
+author:              Philippe Laprade, Jean-Pierre Rupp
+maintainer:          s9gf4ult@gmail.com
+category:            Data, ByteStrings
+build-type:          Simple
+cabal-version:       >=1.10
+
+source-repository head
+  type:     git
+  location: https://s9gf4ult@bitbucket.org/s9gf4ult/base58-bytestring.git
+
+library
+  exposed-modules: Data.ByteString.Base58
+
+  default-extensions: OverloadedStrings
+                    , DeriveDataTypeable
+                    , DeriveGeneric
+                    , GeneralizedNewtypeDeriving
+
+  build-depends:       base >=4.6 && < 5
+                     , bytestring
+                     , containers
+
+
+  hs-source-dirs:      src
+  ghc-options: -Wall
+  default-language:    Haskell2010
+
+test-suite test
+  type:    exitcode-stdio-1.0
+  main-is: Main.hs
+
+  hs-source-dirs:  test
+  ghc-options:     -Wall -rtsopts -threaded
+
+  build-depends:       base >=4.6 && < 5
+                     , base58-bytestring
+                     , bytestring
+                     , quickcheck-assertions >= 0.2.0
+                     , quickcheck-instances
+                     , tasty
+                     , tasty-quickcheck
diff --git a/src/Data/ByteString/Base58.hs b/src/Data/ByteString/Base58.hs
new file mode 100644
--- /dev/null
+++ b/src/Data/ByteString/Base58.hs
@@ -0,0 +1,111 @@
+module Data.ByteString.Base58
+       ( -- * Alphabet
+         Alphabet(..)
+       , bitcoinAlphabet
+       , rippleAlphabet
+       , flickrAlphabet
+       -- * Encoding and decoding bytestrings
+       , encodeBase58
+       , decodeBase58
+       -- * Encoding and decoding integers
+       , encodeBase58I
+       , decodeBase58I
+       ) where
+
+import Control.Applicative
+import Data.Bits
+import Data.ByteString ( ByteString )
+import Data.Char (chr, ord)
+import Data.Map ( Map )
+import Data.Maybe
+import Data.String
+import Data.Typeable ( Typeable )
+import Data.Word
+import GHC.Generics ( Generic )
+import Numeric
+
+import qualified Data.ByteString as BS
+import qualified Data.ByteString.Char8 as BC
+import qualified Data.List as L
+import qualified Data.Map.Strict as M
+
+newtype Alphabet =
+    Alphabet
+    { unAlphabet  :: ByteString
+    } deriving (Ord, Eq, Show, Typeable, Generic, IsString)
+
+bitcoinAlphabet :: Alphabet
+bitcoinAlphabet =
+    "123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz"
+
+rippleAlphabet :: Alphabet
+rippleAlphabet =
+    "rpshnaf39wBUDNEGHJKLM4PQRST7VWXYZ2bcdeCg65jkm8oFqi1tuvAxyz"
+
+flickrAlphabet :: Alphabet
+flickrAlphabet =
+    "123456789abcdefghijkmnopqrstuvwxyzABCDEFGHJKLMNPQRSTUVWXYZ"
+
+-- | Take 'i' byte from alphabet
+b58 :: Alphabet -> Int -> Word8
+b58 a i = BS.index (unAlphabet a) i
+
+-- | Lookup position of byte 'w' in alphabet
+b58' :: Alphabet -> Word8 -> Maybe Int
+b58' a w = BS.elemIndex w (unAlphabet a)
+
+encodeBase58I :: Alphabet -> Integer -> ByteString
+encodeBase58I alpha i =
+    BC.pack $ showIntAtBase 58 f i ""
+  where
+    f :: Int -> Char
+    f = chr . fromIntegral . b58 alpha . fromIntegral
+
+decodeBase58I :: Alphabet -> ByteString -> Maybe Integer
+decodeBase58I alpha s = case go of
+    Just (r,[]) -> Just r
+    _           -> Nothing
+  where
+    c = b58' alpha . fromIntegral . ord
+    p = isJust . c
+    f = fromIntegral . fromJust . c
+    go = listToMaybe $ readInt 58 p f (BC.unpack s)
+
+-- | Encode a bytestring to a base 58 representation.
+encodeBase58 :: Alphabet -> ByteString -> ByteString
+encodeBase58 alpha bs =
+    let (z, b) = BS.span (== 0) bs
+        l = BS.pack
+            $ replicate (BS.length z)
+            $ b58 alpha 0
+        r | BS.null b = BS.empty
+          | otherwise = encodeBase58I alpha
+                        $ bsToInteger b
+    in BS.append l r
+
+-- | Decode a base 58 encoded bytestring. This can fail if the input bytestring
+-- contains invalid base 58 characters such as 0,O,l,I
+decodeBase58 :: Alphabet -> ByteString -> Maybe ByteString
+decodeBase58 alpha bs =
+    let (z, b) = BS.span (== (b58 alpha 0)) bs
+        prefix = BS.pack
+                 $ replicate (BS.length z) 0
+        r | BS.null b = Just BS.empty
+          | otherwise = integerToBS <$> decodeBase58I alpha b
+    in BS.append prefix <$> r
+
+-- | Decode a big endian Integer from a bytestring
+bsToInteger :: ByteString -> Integer
+bsToInteger = (L.foldl' f 0) . BS.unpack
+  where
+    f n w = (toInteger w) .|. shiftL n 8
+
+-- | Encode an Integer to a bytestring as big endian
+integerToBS :: Integer -> ByteString
+integerToBS 0 = BS.pack [0]
+integerToBS i
+    | i > 0     = BS.pack $ reverse $ L.unfoldr f i
+    | otherwise = error "integerToBS not defined for negative values"
+  where
+    f 0 = Nothing
+    f x = Just $ (fromInteger x :: Word8, x `shiftR` 8)
diff --git a/test/Main.hs b/test/Main.hs
new file mode 100644
--- /dev/null
+++ b/test/Main.hs
@@ -0,0 +1,32 @@
+module Main where
+
+import Data.ByteString ( ByteString )
+import Data.ByteString.Base58
+import Data.Monoid
+import Test.QuickCheck.Assertions
+import Test.QuickCheck.Instances ()
+import Test.Tasty
+import Test.Tasty.QuickCheck
+
+prop_EncodeDecode :: Alphabet -> ByteString -> Result
+prop_EncodeDecode alpha bs =
+    (decodeBase58 alpha $ encodeBase58 alpha bs) ?== (Just bs)
+
+prop_EncodeDecodeInt :: Alphabet -> (NonNegative Integer) -> Result
+prop_EncodeDecodeInt alpha (NonNegative i) =
+    (decodeBase58I alpha $ encodeBase58I alpha i) ?== (Just i)
+
+
+main :: IO ()
+main = do
+    defaultMain
+        $ testGroup "base58 transcoding"
+        $ [ ("bitcoinAlphabet", bitcoinAlphabet)
+          , ("rippleAlphabet", rippleAlphabet)
+          , ("flickrAlphabet", flickrAlphabet)
+          ] >>= \(aname, alpha) ->
+                    [ testProperty (aname <> ": decode . encode ~ id")
+                      $ prop_EncodeDecode alpha
+                    , testProperty (aname <> ": encode . decode ~ id")
+                      $ prop_EncodeDecodeInt alpha
+                    ]
