module Data.ByteString.Base58
(
Alphabet(..)
, bitcoinAlphabet
, rippleAlphabet
, flickrAlphabet
, encodeBase58
, decodeBase58
, 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
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
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