base58

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

commit 70dc813a0f10c820a41727dddf02af89ce93212c
parent 4188b0f40d6d9d36c927a94bc962a9eaedf8090d
Author: Jared Tobin <jared@jtobin.io>
Date:   Sat, 10 Oct 2026 15:24:32 +0400

lib: validate and decode base58 in a single pass

Diffstat:
Mlib/Data/ByteString/Base58.hs | 28+++++++++++-----------------
1 file changed, 11 insertions(+), 17 deletions(-)

diff --git a/lib/Data/ByteString/Base58.hs b/lib/Data/ByteString/Base58.hs @@ -15,7 +15,6 @@ module Data.ByteString.Base58 ( , decode ) where -import Control.Monad (guard) import qualified Data.Bits as B import Data.Bits ((.|.)) import qualified Data.ByteString as BS @@ -56,16 +55,9 @@ encode bs = ls <> unroll_base58 (roll_base256 bs) where -- Nothing decode :: BS.ByteString -> Maybe BS.ByteString decode bs = do - guard (verify_base58 bs) + n <- roll_base58 bs let ls = leading_zeros bs - pure $ ls <> unroll_base256 (roll_base58 bs) - -verify_base58 :: BS.ByteString -> Bool -verify_base58 bs = case BS.uncons bs of - Nothing -> True - Just (h, t) - | BS.elem h base58_charset -> verify_base58 t - | otherwise -> False + pure $ ls <> unroll_base256 n base58_charset :: BS.ByteString base58_charset = "123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz" @@ -111,11 +103,13 @@ unroll_base58 = BS.reverse . BS.unfoldr coalg where let (b, c) = quotRem a 58 in (BU.unsafeIndex base58_charset (fi c), b) --- from base58 -roll_base58 :: BS.ByteString -> Integer -roll_base58 bs = BS.foldl' alg 0 bs where - alg !b !a = case word6 a of - Just w -> b * 58 + fi w - Nothing -> - error "ppad-base58 (roll_base58): internal error" +-- from base58, failing on any non-base58 character +roll_base58 :: BS.ByteString -> Maybe Integer +roll_base58 bs = go 0 0 where + l = BS.length bs + go !acc !i + | i == l = Just acc + | otherwise = case word6 (BU.unsafeIndex bs i) of + Nothing -> Nothing + Just w -> go (acc * 58 + fi w) (i + 1)