base58

Pure Haskell base58, base58check encoding/decoding (docs.ppad.tech/base58).
git clone git://git.ppad.tech/base58.git
Log | Files | Refs | README | LICENSE

Base58Check.hs (1577B)


      1 {-# LANGUAGE ViewPatterns #-}
      2 
      3 -- |
      4 -- Module: Data.ByteString.Base58Check
      5 -- Copyright: (c) 2024 Jared Tobin
      6 -- License: MIT
      7 -- Maintainer: Jared Tobin <jared@ppad.tech>
      8 --
      9 -- base58check encoding and decoding of strict bytestrings.
     10 --
     11 -- base58check is a versioned, checksummed base58 encoding. A payload is
     12 -- constructed from a leading version byte and some base256 input, and
     13 -- then a checksum is computed by SHA256d-ing the payload, appending its
     14 -- first 4 bytes, and base58-encoding the result.
     15 
     16 module Data.ByteString.Base58Check (
     17     encode
     18   , decode
     19   ) where
     20 
     21 import Control.Monad (guard)
     22 import qualified Crypto.Hash.SHA256 as SHA256
     23 import qualified Data.ByteString as BS
     24 import qualified Data.ByteString.Base58 as B58
     25 import Data.Word (Word8)
     26 
     27 -- | Encode a version byte and base256 'ByteString' as base58check.
     28 --
     29 --   >>> encode 0x00 "hello world"
     30 --   "13vQB7B6MrGQZaxCqW9KER"
     31 encode :: Word8 -> BS.ByteString -> BS.ByteString
     32 encode ver dat =
     33   let pay = BS.cons ver dat
     34       kek = BS.take 4 (SHA256.hash (SHA256.hash pay))
     35   in  B58.encode (pay <> kek)
     36 
     37 -- | Validate and decode a base58check-encoded string. Invalid
     38 --   base58check inputs will produce 'Nothing'.
     39 --
     40 --   >>> decode "13vQB7B6MrGQZaxCqW9KER"
     41 --   Just (0,"hello world")
     42 --   >>> decode "13uQB7B6MrGQZaxCqW9KER" -- s/v/u
     43 --   Nothing
     44 decode :: BS.ByteString -> Maybe (Word8, BS.ByteString)
     45 decode mb = do
     46   bs <- B58.decode mb
     47   let len = BS.length bs
     48       (pay, kek) = BS.splitAt (len - 4) bs
     49       man = BS.take 4 (SHA256.hash (SHA256.hash pay))
     50   guard (kek == man)
     51   BS.uncons pay
     52