{-# LANGUAGE OverloadedStrings #-} module Network.EasyBitcoin.Internal.Base58 ( encodeBase58 , decodeBase58 , addRedundancy , liftRedundacy ) where import qualified Data.ByteString as BS import Data.Char (ord, chr) import Data.Word (Word8) import Data.Maybe (fromJust, isJust, listToMaybe) import Numeric (showIntAtBase, readInt) import Data.String (fromString) import qualified Data.ByteString as BS import qualified Data.ByteString.Char8 as B8 import qualified Data.Text as T import Control.Applicative import Data.Bits import Data.List(unfoldr) import Numeric (showIntAtBase, readInt) import Network.EasyBitcoin.Internal.HashFunctions import Network.EasyBitcoin.Internal.ByteString ------------------------------------------------------------------------------- ----------------------------------------------------- addRedundancy :: BS.ByteString -> BS.ByteString addRedundancy bs = BS.append bs (encode' $ chksum32 bs) liftRedundacy :: BS.ByteString -> Maybe BS.ByteString liftRedundacy bs = let (original,extra) = BS.splitAt (BS.length bs - 4) bs in if encode' (chksum32 original) == extra then Just original else Nothing encodeBase58::BS.ByteString -> String encodeBase58 bs = l++r where (z,b) = BS.span (== 0) bs l = replicate (BS.length z) '1' -- preserve leading 0's r | BS.null b = "" | otherwise = encodeBase58I $ bsToInteger b decodeBase58::String -> Maybe BS.ByteString decodeBase58 str = r >>= return . (BS.append prefix) where (z,b) = span (== '1') $ str prefix = BS.replicate (length z) 0 -- preserve leading 1's r | null b = Just BS.empty | otherwise = integerToBS <$> decodeBase58I b --------------------------------------------------------------------------------------------------------------------------------- --------------------------------------------------------------------------------------------------------------------------------- b58Data :: BS.ByteString b58Data = "123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz" b58 :: Word8 -> Word8 b58 i = BS.index b58Data (fromIntegral i) b58' :: Word8 -> Maybe Word8 b58' w = fromIntegral <$> BS.elemIndex w b58Data encodeBase58I :: Integer -> String encodeBase58I i = showIntAtBase (58 :: Integer) f (fromIntegral i) "" where f = chr . fromIntegral . b58 . fromIntegral decodeBase58I :: String -> Maybe Integer decodeBase58I s = case listToMaybe $ readInt 58 p f s of Just (r,[]) -> Just r _ -> Nothing where c = b58' . fromIntegral . ord p = isJust . c f = fromIntegral . fromJust . c ------------------------------------------------------------------------------------------------------------------------------------ ------------------------------------------------------------------------------------------------------------------------------------ -- | Transforms a string into a strict bytestring stringToBS :: String -> BS.ByteString stringToBS = B8.pack -- | Transform a strict bytestring to a string bsToString :: BS.ByteString -> String bsToString = B8.unpack