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