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