packages feed

base58-bytestring (empty) → 0.0.1

raw patch · 5 files changed

+220/−0 lines, 5 filesdep +basedep +base58-bytestringdep +bytestringsetup-changed

Dependencies added: base, base58-bytestring, bytestring, containers, quickcheck-assertions, quickcheck-instances, tasty, tasty-quickcheck

Files

+ Setup.hs view
@@ -0,0 +1,2 @@+import Distribution.Simple+main = defaultMain
+ UNLICENSE view
@@ -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/>
+ base58-bytestring.cabal view
@@ -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
+ src/Data/ByteString/Base58.hs view
@@ -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)
+ test/Main.hs view
@@ -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+                    ]