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 (1395B)


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