commit 4da05856fb5f37f37170fa594f6b28ec2d07bdd4
parent ba6d5429cdbcfe1b5da2933ddd3b390313013b79
Author: Jared Tobin <jared@jtobin.io>
Date: Fri, 3 Jan 2025 15:39:11 -0330
lib: separate word5
Diffstat:
1 file changed, 77 insertions(+), 80 deletions(-)
diff --git a/lib/Data/ByteString/Base32.hs b/lib/Data/ByteString/Base32.hs
@@ -53,6 +53,9 @@ toStrict = BS.toStrict
bech32_charset :: BS.ByteString
bech32_charset = "qpzry9x8gf2tvdw0s3jn54khce6mua7l"
+word5 :: Word8 -> Maybe Word8
+word5 w8 = fmap fi (BS.elemIndex w8 bech32_charset)
+
arrange :: Word32 -> Word8 -> BSB.Builder
arrange w32 w8 =
let mask = 0b00011111 -- low 5-bit mask
@@ -203,90 +206,84 @@ decode = handle . go mempty where
finalize :: BS.ByteString -> Maybe BSB.Builder
finalize bs@(BI.PS _ _ l)
- | l == 0 = Just mempty
- | otherwise = do
- guard (l >= 2)
- w5_0 <- word5 0
- w5_1 <- word5 1
- let w8_0 = w5_0 `B.shiftL` 3
- .|. w5_1 `B.shiftR` 2
-
- -- https://datatracker.ietf.org/doc/html/rfc4648#section-6
- if | l == 2 -> do -- 2 w5's, need 1 w8 (XX final 2 bits?)
- guard (w5_1 `B.shiftL` 6 == 0) -- lowest 2 bits -- XX
- pure (BSB.word8 w8_0)
-
- | l == 4 -> do -- 4 w5's, need 2 w8's
- w5_2 <- word5 2
- w5_3 <- word5 3
- let w8_1 = w5_1 `B.shiftL` 6
- .|. w5_2 `B.shiftL` 1
- .|. w5_3 `B.shiftR` 4
-
- w16 = fi w8_1
- .|. fi w8_0 `B.shiftL` 8
-
- guard (w5_3 `B.shiftL` 4 == 0) -- lowest 4 bits
- pure (BSB.word16LE w16)
-
- | l == 5 -> do -- 5 w5's, need 3 w8's
- w5_2 <- word5 2
- w5_3 <- word5 3
- w5_4 <- word5 4
- let w8_1 = w5_1 `B.shiftL` 6
- .|. w5_2 `B.shiftL` 1
- .|. w5_3 `B.shiftR` 4
- w8_2 = w5_3 `B.shiftL` 4
- .|. w5_4 `B.shiftR` 1
-
- w16 = fi w8_1
- .|. fi w8_0 `B.shiftL` 8
-
- guard (w5_4 `B.shiftL` 7 == 0) -- lowest bit
- pure (BSB.word16LE w16 <> BSB.word8 w8_2)
-
- | l == 7 -> do -- 7 w5's, need 4 w8's
- w5_2 <- word5 2
- w5_3 <- word5 3
- w5_4 <- word5 4
- w5_5 <- word5 5
- w5_6 <- word5 6
- let w8_1 = w5_1 `B.shiftL` 6
- .|. w5_2 `B.shiftL` 1
- .|. w5_3 `B.shiftR` 4
- w8_2 = w5_3 `B.shiftL` 4
- .|. w5_4 `B.shiftR` 1
- w8_3 = w5_4 `B.shiftL` 7
- .|. w5_5 `B.shiftL` 2
- .|. w5_6 `B.shiftR` 3
-
- w32 = fi w8_3
- .|. fi w8_2 `B.shiftL` 8
- .|. fi w8_2 `B.shiftL` 16
- .|. fi w8_1 `B.shiftL` 24
-
- guard (w5_6 `B.shiftL` 5 == 0) -- lowest 3 bits
- pure (BSB.word32LE w32)
-
- | otherwise -> Nothing
-
- where
- word5 :: Int -> Maybe Word8
- word5 i = fmap fi (BS.elemIndex (fi (BU.unsafeIndex bs i)) bech32_charset)
+ | l == 0 = Just mempty
+ | otherwise = do
+ guard (l >= 2)
+ w5_0 <- word5 (BU.unsafeIndex bs 0)
+ w5_1 <- word5 (BU.unsafeIndex bs 1)
+ let w8_0 = w5_0 `B.shiftL` 3
+ .|. w5_1 `B.shiftR` 2
+
+ -- https://datatracker.ietf.org/doc/html/rfc4648#section-6
+ if | l == 2 -> do -- 2 w5's, need 1 w8 (XX final 2 bits?)
+ guard (w5_1 `B.shiftL` 6 == 0) -- lowest 2 bits -- XX
+ pure (BSB.word8 w8_0)
+
+ | l == 4 -> do -- 4 w5's, need 2 w8's
+ w5_2 <- word5 (BU.unsafeIndex bs 2)
+ w5_3 <- word5 (BU.unsafeIndex bs 3)
+ let w8_1 = w5_1 `B.shiftL` 6
+ .|. w5_2 `B.shiftL` 1
+ .|. w5_3 `B.shiftR` 4
+
+ w16 = fi w8_1
+ .|. fi w8_0 `B.shiftL` 8
+
+ guard (w5_3 `B.shiftL` 4 == 0) -- lowest 4 bits
+ pure (BSB.word16LE w16)
+
+ | l == 5 -> do -- 5 w5's, need 3 w8's
+ w5_2 <- word5 (BU.unsafeIndex bs 2)
+ w5_3 <- word5 (BU.unsafeIndex bs 3)
+ w5_4 <- word5 (BU.unsafeIndex bs 4)
+ let w8_1 = w5_1 `B.shiftL` 6
+ .|. w5_2 `B.shiftL` 1
+ .|. w5_3 `B.shiftR` 4
+ w8_2 = w5_3 `B.shiftL` 4
+ .|. w5_4 `B.shiftR` 1
+
+ w16 = fi w8_1
+ .|. fi w8_0 `B.shiftL` 8
+
+ guard (w5_4 `B.shiftL` 7 == 0) -- lowest bit
+ pure (BSB.word16LE w16 <> BSB.word8 w8_2)
+
+ | l == 7 -> do -- 7 w5's, need 4 w8's
+ w5_2 <- word5 (BU.unsafeIndex bs 2)
+ w5_3 <- word5 (BU.unsafeIndex bs 3)
+ w5_4 <- word5 (BU.unsafeIndex bs 4)
+ w5_5 <- word5 (BU.unsafeIndex bs 5)
+ w5_6 <- word5 (BU.unsafeIndex bs 6)
+ let w8_1 = w5_1 `B.shiftL` 6
+ .|. w5_2 `B.shiftL` 1
+ .|. w5_3 `B.shiftR` 4
+ w8_2 = w5_3 `B.shiftL` 4
+ .|. w5_4 `B.shiftR` 1
+ w8_3 = w5_4 `B.shiftL` 7
+ .|. w5_5 `B.shiftL` 2
+ .|. w5_6 `B.shiftR` 3
+
+ w32 = fi w8_3
+ .|. fi w8_2 `B.shiftL` 8
+ .|. fi w8_2 `B.shiftL` 16
+ .|. fi w8_1 `B.shiftL` 24
+
+ guard (w5_6 `B.shiftL` 5 == 0) -- lowest 3 bits
+ pure (BSB.word32LE w32)
+
+ | otherwise -> Nothing
-- assumes length 8 input
decode_chunk :: BS.ByteString -> Maybe BSB.Builder
decode_chunk bs = do
- let word5 i = BS.elemIndex (fi (BU.unsafeIndex bs i)) bech32_charset
-
- w5_0 <- word5 0
- w5_1 <- word5 1
- w5_2 <- word5 2
- w5_3 <- word5 3
- w5_4 <- word5 4
- w5_5 <- word5 5
- w5_6 <- word5 6
- w5_7 <- word5 7
+ w5_0 <- word5 (BU.unsafeIndex bs 0)
+ w5_1 <- word5 (BU.unsafeIndex bs 1)
+ w5_2 <- word5 (BU.unsafeIndex bs 2)
+ w5_3 <- word5 (BU.unsafeIndex bs 3)
+ w5_4 <- word5 (BU.unsafeIndex bs 4)
+ w5_5 <- word5 (BU.unsafeIndex bs 5)
+ w5_6 <- word5 (BU.unsafeIndex bs 6)
+ w5_7 <- word5 (BU.unsafeIndex bs 7)
let w40 :: Word64
w40 = fi w5_0 `B.shiftL` 35