ppad-bech32 0.2.2 → 0.2.3
raw patch · 5 files changed
+63/−15 lines, 5 filesPVP ok
version bump matches the API change (PVP)
API changes (from Hackage documentation)
Files
- CHANGELOG +3/−0
- lib/Data/ByteString/Bech32.hs +2/−1
- lib/Data/ByteString/Bech32/Internal.hs +55/−12
- lib/Data/ByteString/Bech32m.hs +2/−1
- ppad-bech32.cabal +1/−1
CHANGELOG view
@@ -1,5 +1,8 @@ # Changelog +- 0.2.3 (2025-06-21)+ * Minor performance improvements and internal housekeeping.+ - 0.2.2 (2025-02-28) * Various optimizations, including roughly 2x faster decoding performance.
lib/Data/ByteString/Bech32.hs view
@@ -50,7 +50,8 @@ -> Maybe BS.ByteString -- ^ bech32-encoded bytestring encode (B8.map C.toLower -> hrp) (B32.encode -> dat) = do guard (BI.valid_hrp hrp)- let check = create_checksum hrp (BI.as_word5 dat)+ ws <- BI.as_word5 dat+ let check = create_checksum hrp ws res = toStrict $ BSB.byteString hrp <> BSB.word8 49 -- 1
lib/Data/ByteString/Bech32/Internal.hs view
@@ -21,7 +21,7 @@ import qualified Data.ByteString.Builder.Extra as BE import qualified Data.ByteString.Internal as BI import qualified Data.ByteString.Unsafe as BU-import Data.Word (Word32)+import Data.Word (Word8, Word32) fi :: (Integral a, Num b) => a -> b fi = fromIntegral@@ -39,14 +39,53 @@ bech32_charset :: BS.ByteString bech32_charset = "qpzry9x8gf2tvdw0s3jn54khce6mua7l" --- naive base32 -> word5-as_word5 :: BS.ByteString -> BS.ByteString-as_word5 = BS.map f where- f b = case BS.elemIndex (fi b) bech32_charset of- Nothing -> error "ppad-bech32 (as_word5): input not bech32-encoded"- Just w -> fi w+word5 :: Word8 -> Maybe Word8+word5 = \case+ 113 -> pure $! 00 -- 'q'+ 112 -> pure $! 01 -- 'p'+ 122 -> pure $! 02 -- 'z'+ 114 -> pure $! 03 -- 'r'+ 121 -> pure $! 04 -- 'y'+ 57 -> pure $! 05 -- '9'+ 120 -> pure $! 06 -- 'x'+ 56 -> pure $! 07 -- '8'+ 103 -> pure $! 08 -- 'g'+ 102 -> pure $! 09 -- 'f'+ 50 -> pure $! 10 -- '2'+ 116 -> pure $! 11 -- 't'+ 118 -> pure $! 12 -- 'v'+ 100 -> pure $! 13 -- 'd'+ 119 -> pure $! 14 -- 'w'+ 48 -> pure $! 15 -- '0'+ 115 -> pure $! 16 -- 's'+ 51 -> pure $! 17 -- '3'+ 106 -> pure $! 18 -- 'j'+ 110 -> pure $! 19 -- 'n'+ 53 -> pure $! 20 -- '5'+ 52 -> pure $! 21 -- '4'+ 107 -> pure $! 22 -- 'k'+ 104 -> pure $! 23 -- 'h'+ 99 -> pure $! 24 -- 'c'+ 101 -> pure $! 25 -- 'e'+ 54 -> pure $! 26 -- '6'+ 109 -> pure $! 27 -- 'm'+ 117 -> pure $! 28 -- 'u'+ 97 -> pure $! 29 -- 'a'+ 55 -> pure $! 30 -- '7'+ 108 -> pure $! 31 -- 'l'+ _ -> Nothing+{-# INLINE word5 #-} --- naive word5 -> base32+-- base32 -> word5+as_word5 :: BS.ByteString -> Maybe BS.ByteString+as_word5 = go mempty where+ go acc bs = case BS.uncons bs of+ Nothing -> pure (toStrict acc)+ Just (h, t) -> do+ w5 <- word5 (fi h)+ go (acc <> BSB.word8 w5) t++-- word5 -> base32 as_base32 :: BS.ByteString -> BS.ByteString as_base32 = BS.map (BU.unsafeIndex bech32_charset . fi) @@ -107,8 +146,12 @@ Nothing -> False Just idx -> let (hrp, BU.unsafeDrop 1 -> dat) = BS.splitAt idx b32- bs = hrp_expand hrp <> as_word5 dat- in polymod bs == case enc of- Bech32 -> 1- Bech32m -> _BECH32M_CONST+ w5s = as_word5 dat+ in case w5s of+ Nothing -> False+ Just ws ->+ let bs = hrp_expand hrp <> ws+ in polymod bs == case enc of+ Bech32 -> 1+ Bech32m -> _BECH32M_CONST
lib/Data/ByteString/Bech32m.hs view
@@ -51,7 +51,8 @@ -> Maybe BS.ByteString -- ^ bech32m-encoded bytestring encode (B8.map C.toLower -> hrp) (B32.encode -> dat) = do guard (BI.valid_hrp hrp)- let check = create_checksum hrp (BI.as_word5 dat)+ ws <- BI.as_word5 dat+ let check = create_checksum hrp ws res = toStrict $ BSB.byteString hrp <> BSB.word8 49 -- 1
ppad-bech32.cabal view
@@ -1,6 +1,6 @@ cabal-version: 3.0 name: ppad-bech32-version: 0.2.2+version: 0.2.3 synopsis: bech32 and bech32m encoding/decoding, per BIPs 173 & 350. license: MIT license-file: LICENSE