base58string 0.9.1 → 0.10.0
raw patch · 4 files changed
+132/−71 lines, 4 filesPVP ok
version bump matches the API change (PVP)
API changes (from Hackage documentation)
- Data.Base58String: instance FromJSON Base58String
- Data.Base58String: instance ToJSON Base58String
+ Data.Base58String.Bitcoin: b58String :: ByteString -> Base58String
+ Data.Base58String.Bitcoin: data Base58String
+ Data.Base58String.Bitcoin: fromBinary :: Binary a => a -> Base58String
+ Data.Base58String.Bitcoin: fromBytes :: ByteString -> Base58String
+ Data.Base58String.Bitcoin: fromText :: Text -> Base58String
+ Data.Base58String.Bitcoin: instance FromJSON Base58String
+ Data.Base58String.Bitcoin: instance ToJSON Base58String
+ Data.Base58String.Bitcoin: toBinary :: Binary a => Base58String -> a
+ Data.Base58String.Bitcoin: toBytes :: Base58String -> ByteString
+ Data.Base58String.Bitcoin: toText :: Base58String -> Text
- Data.Base58String: b58String :: ByteString -> Base58String
+ Data.Base58String: b58String :: ByteString -> ByteString -> Base58String
- Data.Base58String: fromBinary :: Binary a => a -> Base58String
+ Data.Base58String: fromBinary :: Binary a => ByteString -> a -> Base58String
- Data.Base58String: fromBytes :: ByteString -> Base58String
+ Data.Base58String: fromBytes :: ByteString -> ByteString -> Base58String
- Data.Base58String: fromText :: Text -> Base58String
+ Data.Base58String: fromText :: ByteString -> Text -> Base58String
- Data.Base58String: toBinary :: Binary a => Base58String -> a
+ Data.Base58String: toBinary :: Binary a => ByteString -> Base58String -> a
- Data.Base58String: toBytes :: Base58String -> ByteString
+ Data.Base58String: toBytes :: ByteString -> Base58String -> ByteString
Files
- base58string.cabal +2/−1
- src/Data/Base58String.hs +73/−67
- src/Data/Base58String/Bitcoin.hs +54/−0
- test/Data/Base58StringSpec.hs +3/−3
base58string.cabal view
@@ -1,6 +1,6 @@ name: base58string category: Data -version: 0.9.1 +version: 0.10.0 license: MIT license-file: LICENSE copyright: (c) 2015 Leon Mergen @@ -25,6 +25,7 @@ default-language: Haskell2010 exposed-modules: Data.Base58String + Data.Base58String.Bitcoin build-depends: base >= 4.3 && < 5 , binary
src/Data/Base58String.hs view
@@ -7,28 +7,28 @@ , toText , fromText ) where -import Control.Applicative ((<$>), pure) -import Control.Monad (liftM) +import Control.Applicative (pure, (<$>)) +import Control.Monad (liftM) -import Data.Char (ord, chr) -import Data.Bits ((.|.), shiftL, shiftR) -import Data.List (unfoldr) +import Data.Bits (shiftL, shiftR, (.|.)) +import Data.Char (chr, ord) +import Data.List (unfoldr) -import Data.Maybe (fromJust, isJust, listToMaybe, fromMaybe) +import Data.Maybe (fromJust, fromMaybe, isJust, + listToMaybe) -import Data.Aeson -import Data.Word (Word8) -import Numeric (showIntAtBase, readInt) -import Data.String (fromString) +import Data.String (fromString) +import Data.Word (Word8) +import Numeric (readInt, showIntAtBase) -import qualified Data.ByteString as BS -import qualified Data.ByteString.Char8 as BS8 -import qualified Data.ByteString.Lazy as BSL +import qualified Data.ByteString as BS +import qualified Data.ByteString.Char8 as BS8 +import qualified Data.ByteString.Lazy as BSL -import qualified Data.Text as T -import qualified Data.Text.Encoding as TE +import qualified Data.Text as T +import qualified Data.Text.Encoding as TE -import qualified Data.Binary as B (Binary, decode, encode) +import qualified Data.Binary as B (Binary, decode, encode) -- | Represents a Base58 string. Guarantees that all characters it contains -- are valid base58 characters. @@ -36,97 +36,103 @@ Base58String BS.ByteString deriving ( Show, Eq, Ord ) -instance FromJSON Base58String where - parseJSON = withText "Base58tring" $ pure . b58String . TE.encodeUtf8 - -instance ToJSON Base58String where - toJSON = String . toText - -- | Smart constructor which validates that all the text are actually -- base-58 characters. -b58String :: BS.ByteString -> Base58String -b58String bs = - if BS.all isValidBase58 bs +b58String :: BS.ByteString -- ^ Our Base58 mapping table + -> BS.ByteString -- ^ Our Base58 string + -> Base58String +b58String table bs = + if BS.all (isValidBase58 table) bs then Base58String bs else error ("Not a valid base58 string: " ++ show bs) -- | Converts a 'B.Binary' to a 'Base58String' value -fromBinary :: B.Binary a => a -> Base58String -fromBinary = b58String . b58Encode . BSL.toStrict . B.encode +fromBinary :: B.Binary a + => BS.ByteString -- ^ Our Base58 mapping table + -> a -- ^ Input object that is convertable to binary + -> Base58String -- ^ Base58 representation of binary data +fromBinary table = (b58String table) . (b58Encode table) . BSL.toStrict . B.encode -- | Converts a 'Base58String' to a 'B.Binary' value -toBinary :: B.Binary a => Base58String -> a -toBinary (Base58String bs) = B.decode . BSL.fromStrict . fromMaybe (error "not a valid base58 input") $ b58Decode bs +toBinary :: B.Binary a + => BS.ByteString -- ^ Base58 mapping table + -> Base58String -- ^ Base58 representation + -> a -- ^ Converted object +toBinary table (Base58String bs) = B.decode . BSL.fromStrict . fromMaybe (error "not a valid base58 input") $ b58Decode table bs -- | Reads a 'BS.ByteString' as raw bytes and converts to base58 representation. We -- cannot use the instance Binary of 'BS.ByteString' because it provides -- a leading length, which is not what we want when dealing with raw bytes. -fromBytes :: BS.ByteString -> Base58String -fromBytes = b58String . b58Encode +fromBytes :: BS.ByteString -- ^ Our Base58 mapping table + -> BS.ByteString -- ^ Raw binary bytes + -> Base58String -- ^ Base58 representation of raw binary bytes +fromBytes table = (b58String table) . (b58Encode table) -- | Access to the raw bytes in a 'BS.ByteString' format. -toBytes :: Base58String -> BS.ByteString -toBytes (Base58String bs) = fromMaybe (error "not a valid base58 input") $ b58Decode bs +toBytes :: BS.ByteString -- ^ Base58 mapping table + -> Base58String -- ^ Base58 string we wish to get binary data from + -> BS.ByteString -- ^ Raw binary representation +toBytes table (Base58String bs) = fromMaybe (error "not a valid base58 input") $ b58Decode table bs -- | Access to a 'T.Text' representation of the 'Base58String' toText :: Base58String -> T.Text toText (Base58String bs) = TE.decodeUtf8 bs -- | Converts a 'T.Text' representation to a 'Base58String' -fromText :: T.Text -> Base58String -fromText = b58String . TE.encodeUtf8 - --- | Our mapping table from binary to base58, based on Bitcoin's table -bitcoinTable :: BS.ByteString -bitcoinTable = BS.pack - $ [49..57] - ++ [65..72] - ++ [74..78] - ++ [80..90] - ++ [97..107] - ++ [109..122] +fromText :: BS.ByteString -- ^ Base58 mapping table + -> T.Text -- ^ Text representation + -> Base58String -- ^ Base58 classified representation +fromText table = (b58String table) . TE.encodeUtf8 -isValidBase58 :: Word8 -> Bool -isValidBase58 c = - BS.elem c bitcoinTable +isValidBase58 :: BS.ByteString -> Word8 -> Bool +isValidBase58 table c = + BS.elem c table -b58 :: Word8 -> Word8 -b58 i = BS.index bitcoinTable (fromIntegral i) +b58 :: BS.ByteString -> Word8 -> Word8 +b58 table i = BS.index table (fromIntegral i) -b58' :: Word8 -> Maybe Word8 -b58' w = fromIntegral <$> BS.elemIndex w bitcoinTable +b58' :: BS.ByteString -> Word8 -> Maybe Word8 +b58' table w = fromIntegral <$> BS.elemIndex w table -b58EncodeInt :: Integer -> BS.ByteString -b58EncodeInt i = +b58EncodeInt :: BS.ByteString -- ^ Base58 mapping table + -> Integer + -> BS.ByteString +b58EncodeInt table i = fromString $ showIntAtBase (58 :: Integer) f (fromIntegral i) "" where - f = chr . fromIntegral . b58 . fromIntegral + f = chr . fromIntegral . (b58 table) . fromIntegral -b58DecodeInt :: BS.ByteString -> Maybe Integer -b58DecodeInt s = case go of +b58DecodeInt :: BS.ByteString -- ^ Base58 mapping table + -> BS.ByteString + -> Maybe Integer +b58DecodeInt table s = case go of Just (r,[]) -> Just r _ -> Nothing where - c = b58' . fromIntegral . ord + c = (b58' table) . fromIntegral . ord p = isJust . c f = fromIntegral . fromJust . c go = listToMaybe $ readInt 58 p f (BS8.unpack s) -b58Encode :: BS.ByteString -> BS.ByteString -b58Encode input = BS.append l r +b58Encode :: BS.ByteString -- ^ Base58 mapping table + -> BS.ByteString + -> BS.ByteString +b58Encode table input = BS.append l r where (z,b) = BS.span (== 0) input - l = BS.map b58 z -- preserve leading 0's + l = BS.map (b58 table) z -- preserve leading 0's r | BS.null b = BS.empty - | otherwise = b58EncodeInt $ bsToInteger b + | otherwise = b58EncodeInt table $ bsToInteger b -b58Decode :: BS.ByteString -> Maybe BS.ByteString -b58Decode input = liftM (BS.append prefix) r +b58Decode :: BS.ByteString -- ^ Base58 mapping table + -> BS.ByteString + -> Maybe BS.ByteString +b58Decode table input = liftM (BS.append prefix) r where - (z,b) = BS.span (== b58 0) input - prefix = BS.map (fromJust . b58') z -- preserve leading 1's + (z,b) = BS.span (== (b58 table) 0) input + prefix = BS.map (fromJust . (b58' table)) z -- preserve leading 1's r | BS.null b = Just BS.empty - | otherwise = integerToBS <$> b58DecodeInt b + | otherwise = integerToBS <$> (b58DecodeInt table) b -- | Decode a big endian Integer from a bytestring bsToInteger :: BS.ByteString -> Integer
+ src/Data/Base58String/Bitcoin.hs view
@@ -0,0 +1,54 @@+module Data.Base58String.Bitcoin ( B58.Base58String + , b58String + , fromBinary + , toBinary + , fromBytes + , toBytes + , fromText + , toText ) where + +import Control.Applicative (pure) +import Data.Aeson +import qualified Data.Binary as B (Binary) +import qualified Data.ByteString as BS +import qualified Data.Text as T +import qualified Data.Text.Encoding as TE + +import qualified Data.Base58String as B58 + +-- | Our mapping table from binary to base58, based on Bitcoin's table +table :: BS.ByteString +table = BS.pack + $ [49..57] + ++ [65..72] + ++ [74..78] + ++ [80..90] + ++ [97..107] + ++ [109..122] + +instance FromJSON B58.Base58String where + parseJSON = withText "Base58tring" $ pure . b58String . TE.encodeUtf8 + +instance ToJSON B58.Base58String where + toJSON = String . toText + +b58String :: BS.ByteString -> B58.Base58String +b58String = B58.b58String table + +fromBinary :: B.Binary a => a -> B58.Base58String +fromBinary = B58.fromBinary table + +toBinary :: B.Binary a => B58.Base58String -> a +toBinary = B58.toBinary table + +fromBytes :: BS.ByteString -> B58.Base58String +fromBytes = B58.fromBytes table + +toBytes :: B58.Base58String -> BS.ByteString +toBytes = B58.toBytes table + +fromText :: T.Text -> B58.Base58String +fromText = B58.fromText table + +toText :: B58.Base58String -> T.Text +toText = B58.toText
test/Data/Base58StringSpec.hs view
@@ -1,8 +1,8 @@ module Data.Base58StringSpec where -import Data.Base58String ( b58String - , fromBytes - , toBytes ) +import Data.Base58String.Bitcoin ( b58String + , fromBytes + , toBytes ) import qualified Data.ByteString.Char8 as BS8