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.ByteString ( ByteString )
import Data.ByteString.Base58.Internal
import Data.Char (chr, ord)
import Data.Maybe
import Numeric

import qualified Data.ByteString as BS
import qualified Data.ByteString.Char8 as BC


encodeBase58I :: Alphabet -> Integer -> ByteString
encodeBase58I :: Alphabet -> Integer -> ByteString
encodeBase58I Alphabet
alpha Integer
i =
    String -> ByteString
BC.pack (String -> ByteString) -> String -> ByteString
forall a b. (a -> b) -> a -> b
$ Integer -> (Int -> Char) -> Integer -> ShowS
forall a. (Integral a, Show a) => a -> (Int -> Char) -> a -> ShowS
showIntAtBase Integer
58 Int -> Char
f Integer
i String
""
  where
    f :: Int -> Char
    f :: Int -> Char
f = Int -> Char
chr (Int -> Char) -> (Int -> Int) -> Int -> Char
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Word8 -> Int
forall a b. (Integral a, Num b) => a -> b
fromIntegral (Word8 -> Int) -> (Int -> Word8) -> Int -> Int
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Alphabet -> Int -> Word8
b58 Alphabet
alpha (Int -> Word8) -> (Int -> Int) -> Int -> Word8
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Int -> Int
forall a b. (Integral a, Num b) => a -> b
fromIntegral

decodeBase58I :: Alphabet -> ByteString -> Maybe Integer
decodeBase58I :: Alphabet -> ByteString -> Maybe Integer
decodeBase58I Alphabet
alpha ByteString
s =
    let c :: Char -> Maybe Int
c = Alphabet -> Word8 -> Maybe Int
b58' Alphabet
alpha (Word8 -> Maybe Int) -> (Char -> Word8) -> Char -> Maybe Int
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Int -> Word8
forall a b. (Integral a, Num b) => a -> b
fromIntegral (Int -> Word8) -> (Char -> Int) -> Char -> Word8
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Char -> Int
ord
        p :: Char -> Bool
p = Maybe Int -> Bool
forall a. Maybe a -> Bool
isJust (Maybe Int -> Bool) -> (Char -> Maybe Int) -> Char -> Bool
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Char -> Maybe Int
c
        f :: Char -> Int
f = Int -> Int
forall a b. (Integral a, Num b) => a -> b
fromIntegral (Int -> Int) -> (Char -> Int) -> Char -> Int
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Maybe Int -> Int
forall a. HasCallStack => Maybe a -> a
fromJust (Maybe Int -> Int) -> (Char -> Maybe Int) -> Char -> Int
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Char -> Maybe Int
c
    in case Integer -> (Char -> Bool) -> (Char -> Int) -> ReadS Integer
forall a. Num a => a -> (Char -> Bool) -> (Char -> Int) -> ReadS a
readInt Integer
58 Char -> Bool
p Char -> Int
f (ByteString -> String
BC.unpack ByteString
s) of
        [(Integer
r,[])] -> Integer -> Maybe Integer
forall a. a -> Maybe a
Just Integer
r
        [(Integer, String)]
_        -> Maybe Integer
forall a. Maybe a
Nothing

-- | Encode a bytestring to a base 58 representation.
encodeBase58 :: Alphabet -> ByteString -> ByteString
encodeBase58 :: Alphabet -> ByteString -> ByteString
encodeBase58 Alphabet
alpha ByteString
bs =
    let (ByteString
z, ByteString
b) = (Word8 -> Bool) -> ByteString -> (ByteString, ByteString)
BS.span (Word8 -> Word8 -> Bool
forall a. Eq a => a -> a -> Bool
== Word8
0) ByteString
bs
        l :: ByteString
l = [Word8] -> ByteString
BS.pack
            ([Word8] -> ByteString) -> [Word8] -> ByteString
forall a b. (a -> b) -> a -> b
$ Int -> Word8 -> [Word8]
forall a. Int -> a -> [a]
replicate (ByteString -> Int
BS.length ByteString
z)
            (Word8 -> [Word8]) -> Word8 -> [Word8]
forall a b. (a -> b) -> a -> b
$ Alphabet -> Int -> Word8
b58 Alphabet
alpha Int
0
        r :: ByteString
r | ByteString -> Bool
BS.null ByteString
b = ByteString
BS.empty
          | Bool
otherwise = Alphabet -> Integer -> ByteString
encodeBase58I Alphabet
alpha
                        (Integer -> ByteString) -> Integer -> ByteString
forall a b. (a -> b) -> a -> b
$ ByteString -> Integer
bsToInteger ByteString
b
    in ByteString -> ByteString -> ByteString
BS.append ByteString
l ByteString
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 :: Alphabet -> ByteString -> Maybe ByteString
decodeBase58 Alphabet
alpha ByteString
bs =
    let (ByteString
z, ByteString
b) = (Word8 -> Bool) -> ByteString -> (ByteString, ByteString)
BS.span (Word8 -> Word8 -> Bool
forall a. Eq a => a -> a -> Bool
== (Alphabet -> Int -> Word8
b58 Alphabet
alpha Int
0)) ByteString
bs
        prefix :: ByteString
prefix = [Word8] -> ByteString
BS.pack
                 ([Word8] -> ByteString) -> [Word8] -> ByteString
forall a b. (a -> b) -> a -> b
$ Int -> Word8 -> [Word8]
forall a. Int -> a -> [a]
replicate (ByteString -> Int
BS.length ByteString
z) Word8
0
        r :: Maybe ByteString
r | ByteString -> Bool
BS.null ByteString
b = ByteString -> Maybe ByteString
forall a. a -> Maybe a
Just ByteString
BS.empty
          | Bool
otherwise = Integer -> ByteString
integerToBS (Integer -> ByteString) -> Maybe Integer -> Maybe ByteString
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> Alphabet -> ByteString -> Maybe Integer
decodeBase58I Alphabet
alpha ByteString
b
    in ByteString -> ByteString -> ByteString
BS.append ByteString
prefix (ByteString -> ByteString) -> Maybe ByteString -> Maybe ByteString
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> Maybe ByteString
r