{-# OPTIONS_HADDOCK prune #-}
{-# LANGUAGE BangPatterns #-}
{-# LANGUAGE BinaryLiterals #-}
{-# LANGUAGE LambdaCase #-}
{-# LANGUAGE MultiWayIf #-}
{-# LANGUAGE OverloadedStrings #-}
{-# LANGUAGE ViewPatterns #-}

-- |
-- Module: Data.ByteString.Base32
-- Copyright: (c) 2024 Jared Tobin
-- License: MIT
-- Maintainer: Jared Tobin <jared@ppad.tech>
--
-- Unpadded base32 encoding & decoding using the bech32 character set.

-- this module is an adaptation of emilypi's 'base32' library

module Data.ByteString.Base32 (
    -- * base32 encoding and decoding
    encode
  , decode
  ) where

import Control.Monad (guard)
import Data.Bits ((.|.), (.&.))
import qualified Data.Bits as B
import qualified Data.ByteString as BS
import qualified Data.ByteString.Builder as BSB
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 (Word8, Word32, Word64)

fi :: (Integral a, Num b) => a -> b
fi :: forall a b. (Integral a, Num b) => a -> b
fi = a -> b
forall a b. (Integral a, Num b) => a -> b
fromIntegral
{-# INLINE fi #-}

word32be :: BS.ByteString -> Word32
word32be :: ByteString -> Word32
word32be ByteString
s =
  (Word8 -> Word32
forall a b. (Integral a, Num b) => a -> b
fi (ByteString
s ByteString -> Int -> Word8
`BU.unsafeIndex` Int
0) Word32 -> Int -> Word32
forall a. Bits a => a -> Int -> a
`B.shiftL` Int
24) Word32 -> Word32 -> Word32
forall a. Bits a => a -> a -> a
.|.
  (Word8 -> Word32
forall a b. (Integral a, Num b) => a -> b
fi (ByteString
s ByteString -> Int -> Word8
`BU.unsafeIndex` Int
1) Word32 -> Int -> Word32
forall a. Bits a => a -> Int -> a
`B.shiftL` Int
16) Word32 -> Word32 -> Word32
forall a. Bits a => a -> a -> a
.|.
  (Word8 -> Word32
forall a b. (Integral a, Num b) => a -> b
fi (ByteString
s ByteString -> Int -> Word8
`BU.unsafeIndex` Int
2) Word32 -> Int -> Word32
forall a. Bits a => a -> Int -> a
`B.shiftL`  Int
8) Word32 -> Word32 -> Word32
forall a. Bits a => a -> a -> a
.|.
  (Word8 -> Word32
forall a b. (Integral a, Num b) => a -> b
fi (ByteString
s ByteString -> Int -> Word8
`BU.unsafeIndex` Int
3))
{-# INLINE word32be #-}

-- realization for small builders
toStrict :: BSB.Builder -> BS.ByteString
toStrict :: Builder -> ByteString
toStrict = ByteString -> ByteString
BS.toStrict
  (ByteString -> ByteString)
-> (Builder -> ByteString) -> Builder -> ByteString
forall b c a. (b -> c) -> (a -> b) -> a -> c
. AllocationStrategy -> ByteString -> Builder -> ByteString
BE.toLazyByteStringWith (Int -> Int -> AllocationStrategy
BE.safeStrategy Int
128 Int
BE.smallChunkSize) ByteString
forall a. Monoid a => a
mempty
{-# INLINE toStrict #-}

bech32_charset :: BS.ByteString
bech32_charset :: ByteString
bech32_charset = ByteString
"qpzry9x8gf2tvdw0s3jn54khce6mua7l"

word5 :: Word8 -> Maybe Word8
word5 :: Word8 -> Maybe Word8
word5 Word8
w8 = (Int -> Word8) -> Maybe Int -> Maybe Word8
forall a b. (a -> b) -> Maybe a -> Maybe b
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap Int -> Word8
forall a b. (Integral a, Num b) => a -> b
fi (Word8 -> ByteString -> Maybe Int
BS.elemIndex Word8
w8 ByteString
bech32_charset)

arrange :: Word32 -> Word8 -> BSB.Builder
arrange :: Word32 -> Word8 -> Builder
arrange Word32
w32 Word8
w8 =
  let mask :: Word32
mask = Word32
0b00011111                                 -- low 5-bit mask
      bech32_char :: Word32 -> Word64
bech32_char = Word8 -> Word64
forall a b. (Integral a, Num b) => a -> b
fi (Word8 -> Word64) -> (Word32 -> Word8) -> Word32 -> Word64
forall b c a. (b -> c) -> (a -> b) -> a -> c
. HasCallStack => ByteString -> Int -> Word8
ByteString -> Int -> Word8
BS.index ByteString
bech32_charset (Int -> Word8) -> (Word32 -> Int) -> Word32 -> Word8
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Word32 -> Int
forall a b. (Integral a, Num b) => a -> b
fi   -- word5 -> bech32

      -- split 40 bits into 8 w5's
      w5_0 :: Word32
w5_0 = Word32
mask Word32 -> Word32 -> Word32
forall a. Bits a => a -> a -> a
.&. (Word32
w32 Word32 -> Int -> Word32
forall a. Bits a => a -> Int -> a
`B.shiftR` Int
27) -- highest 5 bits
      w5_1 :: Word32
w5_1 = Word32
mask Word32 -> Word32 -> Word32
forall a. Bits a => a -> a -> a
.&. (Word32
w32 Word32 -> Int -> Word32
forall a. Bits a => a -> Int -> a
`B.shiftR` Int
22)
      w5_2 :: Word32
w5_2 = Word32
mask Word32 -> Word32 -> Word32
forall a. Bits a => a -> a -> a
.&. (Word32
w32 Word32 -> Int -> Word32
forall a. Bits a => a -> Int -> a
`B.shiftR` Int
17)
      w5_3 :: Word32
w5_3 = Word32
mask Word32 -> Word32 -> Word32
forall a. Bits a => a -> a -> a
.&. (Word32
w32 Word32 -> Int -> Word32
forall a. Bits a => a -> Int -> a
`B.shiftR` Int
12)
      w5_4 :: Word32
w5_4 = Word32
mask Word32 -> Word32 -> Word32
forall a. Bits a => a -> a -> a
.&. (Word32
w32 Word32 -> Int -> Word32
forall a. Bits a => a -> Int -> a
`B.shiftR` Int
07)
      w5_5 :: Word32
w5_5 = Word32
mask Word32 -> Word32 -> Word32
forall a. Bits a => a -> a -> a
.&. (Word32
w32 Word32 -> Int -> Word32
forall a. Bits a => a -> Int -> a
`B.shiftR` Int
02)
      -- combine lowest 2 bits of w32 with highest 3 bits of w8
      w5_6 :: Word32
w5_6 = Word32
mask Word32 -> Word32 -> Word32
forall a. Bits a => a -> a -> a
.&. (Word32
w32 Word32 -> Int -> Word32
forall a. Bits a => a -> Int -> a
`B.shiftL` Int
03 Word32 -> Word32 -> Word32
forall a. Bits a => a -> a -> a
.|. Word8 -> Word32
forall a b. (Integral a, Num b) => a -> b
fi Word8
w8 Word32 -> Int -> Word32
forall a. Bits a => a -> Int -> a
`B.shiftR` Int
05)
      -- lowest 5 bits of w8
      w5_7 :: Word32
w5_7 = Word32
mask Word32 -> Word32 -> Word32
forall a. Bits a => a -> a -> a
.&. Word8 -> Word32
forall a b. (Integral a, Num b) => a -> b
fi Word8
w8

      -- get (w8) bech32 char for each w5, pack all into little-endian w64
      !w64 :: Word64
w64 = Word32 -> Word64
bech32_char Word32
w5_0
         Word64 -> Word64 -> Word64
forall a. Bits a => a -> a -> a
.|. Word32 -> Word64
bech32_char Word32
w5_1 Word64 -> Int -> Word64
forall a. Bits a => a -> Int -> a
`B.shiftL` Int
8
         Word64 -> Word64 -> Word64
forall a. Bits a => a -> a -> a
.|. Word32 -> Word64
bech32_char Word32
w5_2 Word64 -> Int -> Word64
forall a. Bits a => a -> Int -> a
`B.shiftL` Int
16
         Word64 -> Word64 -> Word64
forall a. Bits a => a -> a -> a
.|. Word32 -> Word64
bech32_char Word32
w5_3 Word64 -> Int -> Word64
forall a. Bits a => a -> Int -> a
`B.shiftL` Int
24
         Word64 -> Word64 -> Word64
forall a. Bits a => a -> a -> a
.|. Word32 -> Word64
bech32_char Word32
w5_4 Word64 -> Int -> Word64
forall a. Bits a => a -> Int -> a
`B.shiftL` Int
32
         Word64 -> Word64 -> Word64
forall a. Bits a => a -> a -> a
.|. Word32 -> Word64
bech32_char Word32
w5_5 Word64 -> Int -> Word64
forall a. Bits a => a -> Int -> a
`B.shiftL` Int
40
         Word64 -> Word64 -> Word64
forall a. Bits a => a -> a -> a
.|. Word32 -> Word64
bech32_char Word32
w5_6 Word64 -> Int -> Word64
forall a. Bits a => a -> Int -> a
`B.shiftL` Int
48
         Word64 -> Word64 -> Word64
forall a. Bits a => a -> a -> a
.|. Word32 -> Word64
bech32_char Word32
w5_7 Word64 -> Int -> Word64
forall a. Bits a => a -> Int -> a
`B.shiftL` Int
56

  in  Word64 -> Builder
BSB.word64LE Word64
w64
{-# INLINE arrange #-}

-- | Encode a base256-encoded 'ByteString' as a base32-encoded
--   'ByteString', using the bech32 character set.
--
--   >>> encode "jtobin was here!"
--   "df6x7cnfdcs8wctnyp5x2un9yy"
encode
  :: BS.ByteString -- ^ base256-encoded bytestring
  -> BS.ByteString -- ^ base32-encoded bytestring
encode :: ByteString -> ByteString
encode ByteString
dat = Builder -> ByteString
toStrict (ByteString -> Builder
go ByteString
dat) where
  bech32_char :: Word8 -> Word8
bech32_char = Word8 -> Word8
forall a b. (Integral a, Num b) => a -> b
fi (Word8 -> Word8) -> (Word8 -> Word8) -> Word8 -> Word8
forall b c a. (b -> c) -> (a -> b) -> a -> c
. HasCallStack => ByteString -> Int -> Word8
ByteString -> Int -> Word8
BS.index ByteString
bech32_charset (Int -> Word8) -> (Word8 -> Int) -> Word8 -> Word8
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Word8 -> Int
forall a b. (Integral a, Num b) => a -> b
fi

  go :: ByteString -> Builder
go bs :: ByteString
bs@(BI.PS ForeignPtr Word8
_ Int
_ Int
l)
    | Int
l Int -> Int -> Bool
forall a. Ord a => a -> a -> Bool
>= Int
5 = case Int -> ByteString -> (ByteString, ByteString)
BS.splitAt Int
5 ByteString
bs of
        (ByteString
chunk, ByteString
etc) -> case ByteString -> Maybe (ByteString, Word8)
BS.unsnoc ByteString
chunk of
          Maybe (ByteString, Word8)
Nothing -> [Char] -> Builder
forall a. HasCallStack => [Char] -> a
error [Char]
"impossible, chunk length is 5"
          Just (ByteString -> Word32
word32be -> Word32
w32, Word8
w8) -> Word32 -> Word8 -> Builder
arrange Word32
w32 Word8
w8 Builder -> Builder -> Builder
forall a. Semigroup a => a -> a -> a
<> ByteString -> Builder
go ByteString
etc
    | Int
l Int -> Int -> Bool
forall a. Eq a => a -> a -> Bool
== Int
0 = Builder
forall a. Monoid a => a
mempty
    | Int
l Int -> Int -> Bool
forall a. Eq a => a -> a -> Bool
== Int
1 =
        let a :: Word8
a = ByteString -> Int -> Word8
BU.unsafeIndex ByteString
bs Int
0
            t :: Word8
t = Word8 -> Word8
bech32_char ((Word8
a Word8 -> Word8 -> Word8
forall a. Bits a => a -> a -> a
.&. Word8
0b11111000) Word8 -> Int -> Word8
forall a. Bits a => a -> Int -> a
`B.shiftR` Int
3)
            u :: Word8
u = Word8 -> Word8
bech32_char ((Word8
a Word8 -> Word8 -> Word8
forall a. Bits a => a -> a -> a
.&. Word8
0b00000111) Word8 -> Int -> Word8
forall a. Bits a => a -> Int -> a
`B.shiftL` Int
2)

            !w16 :: Word16
w16 = Word8 -> Word16
forall a b. (Integral a, Num b) => a -> b
fi Word8
t
               Word16 -> Word16 -> Word16
forall a. Bits a => a -> a -> a
.|. Word8 -> Word16
forall a b. (Integral a, Num b) => a -> b
fi Word8
u Word16 -> Int -> Word16
forall a. Bits a => a -> Int -> a
`B.shiftL` Int
8

        in  Word16 -> Builder
BSB.word16LE Word16
w16
    | Int
l Int -> Int -> Bool
forall a. Eq a => a -> a -> Bool
== Int
2 =
        let a :: Word8
a = ByteString -> Int -> Word8
BU.unsafeIndex ByteString
bs Int
0
            b :: Word8
b = ByteString -> Int -> Word8
BU.unsafeIndex ByteString
bs Int
1
            t :: Word8
t = Word8 -> Word8
bech32_char ((Word8
a Word8 -> Word8 -> Word8
forall a. Bits a => a -> a -> a
.&. Word8
0b11111000) Word8 -> Int -> Word8
forall a. Bits a => a -> Int -> a
`B.shiftR` Int
3)
            u :: Word8
u = Word8 -> Word8
bech32_char (Word8 -> Word8) -> Word8 -> Word8
forall a b. (a -> b) -> a -> b
$
                      ((Word8
a Word8 -> Word8 -> Word8
forall a. Bits a => a -> a -> a
.&. Word8
0b00000111) Word8 -> Int -> Word8
forall a. Bits a => a -> Int -> a
`B.shiftL` Int
2)
                  Word8 -> Word8 -> Word8
forall a. Bits a => a -> a -> a
.|. ((Word8
b Word8 -> Word8 -> Word8
forall a. Bits a => a -> a -> a
.&. Word8
0b11000000) Word8 -> Int -> Word8
forall a. Bits a => a -> Int -> a
`B.shiftR` Int
6)
            v :: Word8
v = Word8 -> Word8
bech32_char ((Word8
b Word8 -> Word8 -> Word8
forall a. Bits a => a -> a -> a
.&. Word8
0b00111110) Word8 -> Int -> Word8
forall a. Bits a => a -> Int -> a
`B.shiftR` Int
1)
            w :: Word8
w = Word8 -> Word8
bech32_char ((Word8
b Word8 -> Word8 -> Word8
forall a. Bits a => a -> a -> a
.&. Word8
0b00000001) Word8 -> Int -> Word8
forall a. Bits a => a -> Int -> a
`B.shiftL` Int
4)

            !w32 :: Word32
w32 = Word8 -> Word32
forall a b. (Integral a, Num b) => a -> b
fi Word8
t
               Word32 -> Word32 -> Word32
forall a. Bits a => a -> a -> a
.|. Word8 -> Word32
forall a b. (Integral a, Num b) => a -> b
fi Word8
u Word32 -> Int -> Word32
forall a. Bits a => a -> Int -> a
`B.shiftL` Int
8
               Word32 -> Word32 -> Word32
forall a. Bits a => a -> a -> a
.|. Word8 -> Word32
forall a b. (Integral a, Num b) => a -> b
fi Word8
v Word32 -> Int -> Word32
forall a. Bits a => a -> Int -> a
`B.shiftL` Int
16
               Word32 -> Word32 -> Word32
forall a. Bits a => a -> a -> a
.|. Word8 -> Word32
forall a b. (Integral a, Num b) => a -> b
fi Word8
w Word32 -> Int -> Word32
forall a. Bits a => a -> Int -> a
`B.shiftL` Int
24

        in  Word32 -> Builder
BSB.word32LE Word32
w32
    | Int
l Int -> Int -> Bool
forall a. Eq a => a -> a -> Bool
== Int
3 =
        let a :: Word8
a = ByteString -> Int -> Word8
BU.unsafeIndex ByteString
bs Int
0
            b :: Word8
b = ByteString -> Int -> Word8
BU.unsafeIndex ByteString
bs Int
1
            c :: Word8
c = ByteString -> Int -> Word8
BU.unsafeIndex ByteString
bs Int
2
            t :: Word8
t = Word8 -> Word8
bech32_char ((Word8
a Word8 -> Word8 -> Word8
forall a. Bits a => a -> a -> a
.&. Word8
0b11111000) Word8 -> Int -> Word8
forall a. Bits a => a -> Int -> a
`B.shiftR` Int
3)
            u :: Word8
u = Word8 -> Word8
bech32_char (Word8 -> Word8) -> Word8 -> Word8
forall a b. (a -> b) -> a -> b
$
                      ((Word8
a Word8 -> Word8 -> Word8
forall a. Bits a => a -> a -> a
.&. Word8
0b00000111) Word8 -> Int -> Word8
forall a. Bits a => a -> Int -> a
`B.shiftL` Int
2)
                  Word8 -> Word8 -> Word8
forall a. Bits a => a -> a -> a
.|. ((Word8
b Word8 -> Word8 -> Word8
forall a. Bits a => a -> a -> a
.&. Word8
0b11000000) Word8 -> Int -> Word8
forall a. Bits a => a -> Int -> a
`B.shiftR` Int
6)
            v :: Word8
v = Word8 -> Word8
bech32_char ((Word8
b Word8 -> Word8 -> Word8
forall a. Bits a => a -> a -> a
.&. Word8
0b00111110) Word8 -> Int -> Word8
forall a. Bits a => a -> Int -> a
`B.shiftR` Int
1)
            w :: Word8
w = Word8 -> Word8
bech32_char (Word8 -> Word8) -> Word8 -> Word8
forall a b. (a -> b) -> a -> b
$
                      ((Word8
b Word8 -> Word8 -> Word8
forall a. Bits a => a -> a -> a
.&. Word8
0b00000001) Word8 -> Int -> Word8
forall a. Bits a => a -> Int -> a
`B.shiftL` Int
4)
                  Word8 -> Word8 -> Word8
forall a. Bits a => a -> a -> a
.|. ((Word8
c Word8 -> Word8 -> Word8
forall a. Bits a => a -> a -> a
.&. Word8
0b11110000) Word8 -> Int -> Word8
forall a. Bits a => a -> Int -> a
`B.shiftR` Int
4)
            x :: Word8
x = Word8 -> Word8
bech32_char ((Word8
c Word8 -> Word8 -> Word8
forall a. Bits a => a -> a -> a
.&. Word8
0b00001111) Word8 -> Int -> Word8
forall a. Bits a => a -> Int -> a
`B.shiftL` Int
1)

            !w32 :: Word32
w32 = Word8 -> Word32
forall a b. (Integral a, Num b) => a -> b
fi Word8
t
               Word32 -> Word32 -> Word32
forall a. Bits a => a -> a -> a
.|. Word8 -> Word32
forall a b. (Integral a, Num b) => a -> b
fi Word8
u Word32 -> Int -> Word32
forall a. Bits a => a -> Int -> a
`B.shiftL` Int
8
               Word32 -> Word32 -> Word32
forall a. Bits a => a -> a -> a
.|. Word8 -> Word32
forall a b. (Integral a, Num b) => a -> b
fi Word8
v Word32 -> Int -> Word32
forall a. Bits a => a -> Int -> a
`B.shiftL` Int
16
               Word32 -> Word32 -> Word32
forall a. Bits a => a -> a -> a
.|. Word8 -> Word32
forall a b. (Integral a, Num b) => a -> b
fi Word8
w Word32 -> Int -> Word32
forall a. Bits a => a -> Int -> a
`B.shiftL` Int
24

        in  Word32 -> Builder
BSB.word32LE Word32
w32 Builder -> Builder -> Builder
forall a. Semigroup a => a -> a -> a
<> Word8 -> Builder
BSB.word8 Word8
x
    | Int
l Int -> Int -> Bool
forall a. Eq a => a -> a -> Bool
== Int
4 =
        let a :: Word8
a = ByteString -> Int -> Word8
BU.unsafeIndex ByteString
bs Int
0
            b :: Word8
b = ByteString -> Int -> Word8
BU.unsafeIndex ByteString
bs Int
1
            c :: Word8
c = ByteString -> Int -> Word8
BU.unsafeIndex ByteString
bs Int
2
            d :: Word8
d = ByteString -> Int -> Word8
BU.unsafeIndex ByteString
bs Int
3
            t :: Word8
t = Word8 -> Word8
bech32_char ((Word8
a Word8 -> Word8 -> Word8
forall a. Bits a => a -> a -> a
.&. Word8
0b11111000) Word8 -> Int -> Word8
forall a. Bits a => a -> Int -> a
`B.shiftR` Int
3)
            u :: Word8
u = Word8 -> Word8
bech32_char (Word8 -> Word8) -> Word8 -> Word8
forall a b. (a -> b) -> a -> b
$
                      ((Word8
a Word8 -> Word8 -> Word8
forall a. Bits a => a -> a -> a
.&. Word8
0b00000111) Word8 -> Int -> Word8
forall a. Bits a => a -> Int -> a
`B.shiftL` Int
2)
                  Word8 -> Word8 -> Word8
forall a. Bits a => a -> a -> a
.|. ((Word8
b Word8 -> Word8 -> Word8
forall a. Bits a => a -> a -> a
.&. Word8
0b11000000) Word8 -> Int -> Word8
forall a. Bits a => a -> Int -> a
`B.shiftR` Int
6)
            v :: Word8
v = Word8 -> Word8
bech32_char ((Word8
b Word8 -> Word8 -> Word8
forall a. Bits a => a -> a -> a
.&. Word8
0b00111110) Word8 -> Int -> Word8
forall a. Bits a => a -> Int -> a
`B.shiftR` Int
1)
            w :: Word8
w = Word8 -> Word8
bech32_char (Word8 -> Word8) -> Word8 -> Word8
forall a b. (a -> b) -> a -> b
$
                      ((Word8
b Word8 -> Word8 -> Word8
forall a. Bits a => a -> a -> a
.&. Word8
0b00000001) Word8 -> Int -> Word8
forall a. Bits a => a -> Int -> a
`B.shiftL` Int
4)
                  Word8 -> Word8 -> Word8
forall a. Bits a => a -> a -> a
.|. ((Word8
c Word8 -> Word8 -> Word8
forall a. Bits a => a -> a -> a
.&. Word8
0b11110000) Word8 -> Int -> Word8
forall a. Bits a => a -> Int -> a
`B.shiftR` Int
4)
            x :: Word8
x = Word8 -> Word8
bech32_char (Word8 -> Word8) -> Word8 -> Word8
forall a b. (a -> b) -> a -> b
$
                      ((Word8
c Word8 -> Word8 -> Word8
forall a. Bits a => a -> a -> a
.&. Word8
0b00001111) Word8 -> Int -> Word8
forall a. Bits a => a -> Int -> a
`B.shiftL` Int
1)
                  Word8 -> Word8 -> Word8
forall a. Bits a => a -> a -> a
.|. ((Word8
d Word8 -> Word8 -> Word8
forall a. Bits a => a -> a -> a
.&. Word8
0b10000000) Word8 -> Int -> Word8
forall a. Bits a => a -> Int -> a
`B.shiftR` Int
7)
            y :: Word8
y = Word8 -> Word8
bech32_char ((Word8
d Word8 -> Word8 -> Word8
forall a. Bits a => a -> a -> a
.&. Word8
0b01111100) Word8 -> Int -> Word8
forall a. Bits a => a -> Int -> a
`B.shiftR` Int
2)
            z :: Word8
z = Word8 -> Word8
bech32_char ((Word8
d Word8 -> Word8 -> Word8
forall a. Bits a => a -> a -> a
.&. Word8
0b00000011) Word8 -> Int -> Word8
forall a. Bits a => a -> Int -> a
`B.shiftL` Int
3)

            !w32 :: Word32
w32 = Word8 -> Word32
forall a b. (Integral a, Num b) => a -> b
fi Word8
t
               Word32 -> Word32 -> Word32
forall a. Bits a => a -> a -> a
.|. Word8 -> Word32
forall a b. (Integral a, Num b) => a -> b
fi Word8
u Word32 -> Int -> Word32
forall a. Bits a => a -> Int -> a
`B.shiftL` Int
8
               Word32 -> Word32 -> Word32
forall a. Bits a => a -> a -> a
.|. Word8 -> Word32
forall a b. (Integral a, Num b) => a -> b
fi Word8
v Word32 -> Int -> Word32
forall a. Bits a => a -> Int -> a
`B.shiftL` Int
16
               Word32 -> Word32 -> Word32
forall a. Bits a => a -> a -> a
.|. Word8 -> Word32
forall a b. (Integral a, Num b) => a -> b
fi Word8
w Word32 -> Int -> Word32
forall a. Bits a => a -> Int -> a
`B.shiftL` Int
24

            !w16 :: Word16
w16 = Word8 -> Word16
forall a b. (Integral a, Num b) => a -> b
fi Word8
x
               Word16 -> Word16 -> Word16
forall a. Bits a => a -> a -> a
.|. Word8 -> Word16
forall a b. (Integral a, Num b) => a -> b
fi Word8
y Word16 -> Int -> Word16
forall a. Bits a => a -> Int -> a
`B.shiftL` Int
8

        in  Word32 -> Builder
BSB.word32LE Word32
w32 Builder -> Builder -> Builder
forall a. Semigroup a => a -> a -> a
<> Word16 -> Builder
BSB.word16LE Word16
w16 Builder -> Builder -> Builder
forall a. Semigroup a => a -> a -> a
<> Word8 -> Builder
BSB.word8 Word8
z

    | Bool
otherwise =
        [Char] -> Builder
forall a. HasCallStack => [Char] -> a
error [Char]
"impossible"

-- | Decode a 'ByteString', encoded as base32 using the bech32 character
--   set, to a base256-encoded 'ByteString'.
--
--   >>> decode "df6x7cnfdcs8wctnyp5x2un9yy"
--   Just "jtobin was here!"
--   >>> decode "dfOx7cnfdcs8wctnyp5x2un9yy" -- s/6/O (non-bech32 character)
--   Nothing
decode
  :: BS.ByteString        -- ^ base32-encoded bytestring
  -> Maybe BS.ByteString  -- ^ base256-encoded bytestring
decode :: ByteString -> Maybe ByteString
decode = (Builder -> ByteString) -> Maybe Builder -> Maybe ByteString
forall a b. (a -> b) -> Maybe a -> Maybe b
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap Builder -> ByteString
toStrict (Maybe Builder -> Maybe ByteString)
-> (ByteString -> Maybe Builder) -> ByteString -> Maybe ByteString
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Builder -> ByteString -> Maybe Builder
go Builder
forall a. Monoid a => a
mempty where
  go :: Builder -> ByteString -> Maybe Builder
go Builder
acc bs :: ByteString
bs@(BI.PS ForeignPtr Word8
_ Int
_ Int
l)
    | Int
l Int -> Int -> Bool
forall a. Ord a => a -> a -> Bool
< Int
8 = do
        Builder
fin <- ByteString -> Maybe Builder
finalize ByteString
bs
        Builder -> Maybe Builder
forall a. a -> Maybe a
forall (f :: * -> *) a. Applicative f => a -> f a
pure (Builder
acc Builder -> Builder -> Builder
forall a. Semigroup a => a -> a -> a
<> Builder
fin)
    | Bool
otherwise = case Int -> ByteString -> (ByteString, ByteString)
BS.splitAt Int
8 ByteString
bs of
        (ByteString
chunk, ByteString
etc) -> do
           Builder
res <- ByteString -> Maybe Builder
decode_chunk ByteString
chunk
           Builder -> ByteString -> Maybe Builder
go (Builder
acc Builder -> Builder -> Builder
forall a. Semigroup a => a -> a -> a
<> Builder
res) ByteString
etc

finalize :: BS.ByteString -> Maybe BSB.Builder
finalize :: ByteString -> Maybe Builder
finalize bs :: ByteString
bs@(BI.PS ForeignPtr Word8
_ Int
_ Int
l)
  | Int
l Int -> Int -> Bool
forall a. Eq a => a -> a -> Bool
== Int
0 = Builder -> Maybe Builder
forall a. a -> Maybe a
Just Builder
forall a. Monoid a => a
mempty
  | Bool
otherwise = do
      Bool -> Maybe ()
forall (f :: * -> *). Alternative f => Bool -> f ()
guard (Int
l Int -> Int -> Bool
forall a. Ord a => a -> a -> Bool
>= Int
2)
      Word8
w5_0 <- Word8 -> Maybe Word8
word5 (ByteString -> Int -> Word8
BU.unsafeIndex ByteString
bs Int
0)
      Word8
w5_1 <- Word8 -> Maybe Word8
word5 (ByteString -> Int -> Word8
BU.unsafeIndex ByteString
bs Int
1)
      let w8_0 :: Word8
w8_0 = Word8
w5_0 Word8 -> Int -> Word8
forall a. Bits a => a -> Int -> a
`B.shiftL` Int
3
             Word8 -> Word8 -> Word8
forall a. Bits a => a -> a -> a
.|. Word8
w5_1 Word8 -> Int -> Word8
forall a. Bits a => a -> Int -> a
`B.shiftR` Int
2

      -- https://datatracker.ietf.org/doc/html/rfc4648#section-6
      if | Int
l Int -> Int -> Bool
forall a. Eq a => a -> a -> Bool
== Int
2 -> do -- 2 w5's, need 1 w8; 2 bits remain
             Bool -> Maybe ()
forall (f :: * -> *). Alternative f => Bool -> f ()
guard (Word8
w5_1 Word8 -> Int -> Word8
forall a. Bits a => a -> Int -> a
`B.shiftL` Int
6 Word8 -> Word8 -> Bool
forall a. Eq a => a -> a -> Bool
== Word8
0)
             Builder -> Maybe Builder
forall a. a -> Maybe a
forall (f :: * -> *) a. Applicative f => a -> f a
pure (Word8 -> Builder
BSB.word8 Word8
w8_0)

         | Int
l Int -> Int -> Bool
forall a. Eq a => a -> a -> Bool
== Int
4 -> do -- 4 w5's, need 2 w8's; 4 bits remain
             Word8
w5_2 <- Word8 -> Maybe Word8
word5 (ByteString -> Int -> Word8
BU.unsafeIndex ByteString
bs Int
2)
             Word8
w5_3 <- Word8 -> Maybe Word8
word5 (ByteString -> Int -> Word8
BU.unsafeIndex ByteString
bs Int
3)
             let w8_1 :: Word8
w8_1 = Word8
w5_1 Word8 -> Int -> Word8
forall a. Bits a => a -> Int -> a
`B.shiftL` Int
6
                    Word8 -> Word8 -> Word8
forall a. Bits a => a -> a -> a
.|. Word8
w5_2 Word8 -> Int -> Word8
forall a. Bits a => a -> Int -> a
`B.shiftL` Int
1
                    Word8 -> Word8 -> Word8
forall a. Bits a => a -> a -> a
.|. Word8
w5_3 Word8 -> Int -> Word8
forall a. Bits a => a -> Int -> a
`B.shiftR` Int
4

                 !w16 :: Word16
w16 = Word8 -> Word16
forall a b. (Integral a, Num b) => a -> b
fi Word8
w8_1
                    Word16 -> Word16 -> Word16
forall a. Bits a => a -> a -> a
.|. Word8 -> Word16
forall a b. (Integral a, Num b) => a -> b
fi Word8
w8_0 Word16 -> Int -> Word16
forall a. Bits a => a -> Int -> a
`B.shiftL` Int
8

             Bool -> Maybe ()
forall (f :: * -> *). Alternative f => Bool -> f ()
guard (Word8
w5_3 Word8 -> Int -> Word8
forall a. Bits a => a -> Int -> a
`B.shiftL` Int
4 Word8 -> Word8 -> Bool
forall a. Eq a => a -> a -> Bool
== Word8
0)
             Builder -> Maybe Builder
forall a. a -> Maybe a
forall (f :: * -> *) a. Applicative f => a -> f a
pure (Word16 -> Builder
BSB.word16BE Word16
w16)

         | Int
l Int -> Int -> Bool
forall a. Eq a => a -> a -> Bool
== Int
5 -> do -- 5 w5's, need 3 w8's; 1 bit remains
             Word8
w5_2 <- Word8 -> Maybe Word8
word5 (ByteString -> Int -> Word8
BU.unsafeIndex ByteString
bs Int
2)
             Word8
w5_3 <- Word8 -> Maybe Word8
word5 (ByteString -> Int -> Word8
BU.unsafeIndex ByteString
bs Int
3)
             Word8
w5_4 <- Word8 -> Maybe Word8
word5 (ByteString -> Int -> Word8
BU.unsafeIndex ByteString
bs Int
4)
             let w8_1 :: Word8
w8_1 = Word8
w5_1 Word8 -> Int -> Word8
forall a. Bits a => a -> Int -> a
`B.shiftL` Int
6
                    Word8 -> Word8 -> Word8
forall a. Bits a => a -> a -> a
.|. Word8
w5_2 Word8 -> Int -> Word8
forall a. Bits a => a -> Int -> a
`B.shiftL` Int
1
                    Word8 -> Word8 -> Word8
forall a. Bits a => a -> a -> a
.|. Word8
w5_3 Word8 -> Int -> Word8
forall a. Bits a => a -> Int -> a
`B.shiftR` Int
4
                 w8_2 :: Word8
w8_2 = Word8
w5_3 Word8 -> Int -> Word8
forall a. Bits a => a -> Int -> a
`B.shiftL` Int
4
                    Word8 -> Word8 -> Word8
forall a. Bits a => a -> a -> a
.|. Word8
w5_4 Word8 -> Int -> Word8
forall a. Bits a => a -> Int -> a
`B.shiftR` Int
1

                 w16 :: Word16
w16  = Word8 -> Word16
forall a b. (Integral a, Num b) => a -> b
fi Word8
w8_1
                    Word16 -> Word16 -> Word16
forall a. Bits a => a -> a -> a
.|. Word8 -> Word16
forall a b. (Integral a, Num b) => a -> b
fi Word8
w8_0 Word16 -> Int -> Word16
forall a. Bits a => a -> Int -> a
`B.shiftL` Int
8

             Bool -> Maybe ()
forall (f :: * -> *). Alternative f => Bool -> f ()
guard (Word8
w5_4 Word8 -> Int -> Word8
forall a. Bits a => a -> Int -> a
`B.shiftL` Int
7 Word8 -> Word8 -> Bool
forall a. Eq a => a -> a -> Bool
== Word8
0)
             Builder -> Maybe Builder
forall a. a -> Maybe a
forall (f :: * -> *) a. Applicative f => a -> f a
pure (Word16 -> Builder
BSB.word16BE Word16
w16 Builder -> Builder -> Builder
forall a. Semigroup a => a -> a -> a
<> Word8 -> Builder
BSB.word8 Word8
w8_2)

         | Int
l Int -> Int -> Bool
forall a. Eq a => a -> a -> Bool
== Int
7 -> do -- 7 w5's, need 4 w8's; 3 bits remain
             Word8
w5_2 <- Word8 -> Maybe Word8
word5 (ByteString -> Int -> Word8
BU.unsafeIndex ByteString
bs Int
2)
             Word8
w5_3 <- Word8 -> Maybe Word8
word5 (ByteString -> Int -> Word8
BU.unsafeIndex ByteString
bs Int
3)
             Word8
w5_4 <- Word8 -> Maybe Word8
word5 (ByteString -> Int -> Word8
BU.unsafeIndex ByteString
bs Int
4)
             Word8
w5_5 <- Word8 -> Maybe Word8
word5 (ByteString -> Int -> Word8
BU.unsafeIndex ByteString
bs Int
5)
             Word8
w5_6 <- Word8 -> Maybe Word8
word5 (ByteString -> Int -> Word8
BU.unsafeIndex ByteString
bs Int
6)
             let w8_1 :: Word8
w8_1 = Word8
w5_1 Word8 -> Int -> Word8
forall a. Bits a => a -> Int -> a
`B.shiftL` Int
6
                    Word8 -> Word8 -> Word8
forall a. Bits a => a -> a -> a
.|. Word8
w5_2 Word8 -> Int -> Word8
forall a. Bits a => a -> Int -> a
`B.shiftL` Int
1
                    Word8 -> Word8 -> Word8
forall a. Bits a => a -> a -> a
.|. Word8
w5_3 Word8 -> Int -> Word8
forall a. Bits a => a -> Int -> a
`B.shiftR` Int
4
                 w8_2 :: Word8
w8_2 = Word8
w5_3 Word8 -> Int -> Word8
forall a. Bits a => a -> Int -> a
`B.shiftL` Int
4
                    Word8 -> Word8 -> Word8
forall a. Bits a => a -> a -> a
.|. Word8
w5_4 Word8 -> Int -> Word8
forall a. Bits a => a -> Int -> a
`B.shiftR` Int
1
                 w8_3 :: Word8
w8_3 = Word8
w5_4 Word8 -> Int -> Word8
forall a. Bits a => a -> Int -> a
`B.shiftL` Int
7
                    Word8 -> Word8 -> Word8
forall a. Bits a => a -> a -> a
.|. Word8
w5_5 Word8 -> Int -> Word8
forall a. Bits a => a -> Int -> a
`B.shiftL` Int
2
                    Word8 -> Word8 -> Word8
forall a. Bits a => a -> a -> a
.|. Word8
w5_6 Word8 -> Int -> Word8
forall a. Bits a => a -> Int -> a
`B.shiftR` Int
3

                 w32 :: Word32
w32  = Word8 -> Word32
forall a b. (Integral a, Num b) => a -> b
fi Word8
w8_3
                    Word32 -> Word32 -> Word32
forall a. Bits a => a -> a -> a
.|. Word8 -> Word32
forall a b. (Integral a, Num b) => a -> b
fi Word8
w8_2 Word32 -> Int -> Word32
forall a. Bits a => a -> Int -> a
`B.shiftL` Int
8
                    Word32 -> Word32 -> Word32
forall a. Bits a => a -> a -> a
.|. Word8 -> Word32
forall a b. (Integral a, Num b) => a -> b
fi Word8
w8_1 Word32 -> Int -> Word32
forall a. Bits a => a -> Int -> a
`B.shiftL` Int
16
                    Word32 -> Word32 -> Word32
forall a. Bits a => a -> a -> a
.|. Word8 -> Word32
forall a b. (Integral a, Num b) => a -> b
fi Word8
w8_0 Word32 -> Int -> Word32
forall a. Bits a => a -> Int -> a
`B.shiftL` Int
24

             Bool -> Maybe ()
forall (f :: * -> *). Alternative f => Bool -> f ()
guard (Word8
w5_6 Word8 -> Int -> Word8
forall a. Bits a => a -> Int -> a
`B.shiftL` Int
5 Word8 -> Word8 -> Bool
forall a. Eq a => a -> a -> Bool
== Word8
0)
             Builder -> Maybe Builder
forall a. a -> Maybe a
forall (f :: * -> *) a. Applicative f => a -> f a
pure (Word32 -> Builder
BSB.word32BE Word32
w32)

         | Bool
otherwise -> Maybe Builder
forall a. Maybe a
Nothing

-- assumes length 8 input
decode_chunk :: BS.ByteString -> Maybe BSB.Builder
decode_chunk :: ByteString -> Maybe Builder
decode_chunk ByteString
bs = do
  Word8
w5_0 <- Word8 -> Maybe Word8
word5 (ByteString -> Int -> Word8
BU.unsafeIndex ByteString
bs Int
0)
  Word8
w5_1 <- Word8 -> Maybe Word8
word5 (ByteString -> Int -> Word8
BU.unsafeIndex ByteString
bs Int
1)
  Word8
w5_2 <- Word8 -> Maybe Word8
word5 (ByteString -> Int -> Word8
BU.unsafeIndex ByteString
bs Int
2)
  Word8
w5_3 <- Word8 -> Maybe Word8
word5 (ByteString -> Int -> Word8
BU.unsafeIndex ByteString
bs Int
3)
  Word8
w5_4 <- Word8 -> Maybe Word8
word5 (ByteString -> Int -> Word8
BU.unsafeIndex ByteString
bs Int
4)
  Word8
w5_5 <- Word8 -> Maybe Word8
word5 (ByteString -> Int -> Word8
BU.unsafeIndex ByteString
bs Int
5)
  Word8
w5_6 <- Word8 -> Maybe Word8
word5 (ByteString -> Int -> Word8
BU.unsafeIndex ByteString
bs Int
6)
  Word8
w5_7 <- Word8 -> Maybe Word8
word5 (ByteString -> Int -> Word8
BU.unsafeIndex ByteString
bs Int
7)

  let w40 :: Word64
      !w40 :: Word64
w40 = Word8 -> Word64
forall a b. (Integral a, Num b) => a -> b
fi Word8
w5_0 Word64 -> Int -> Word64
forall a. Bits a => a -> Int -> a
`B.shiftL` Int
35
         Word64 -> Word64 -> Word64
forall a. Bits a => a -> a -> a
.|. Word8 -> Word64
forall a b. (Integral a, Num b) => a -> b
fi Word8
w5_1 Word64 -> Int -> Word64
forall a. Bits a => a -> Int -> a
`B.shiftL` Int
30
         Word64 -> Word64 -> Word64
forall a. Bits a => a -> a -> a
.|. Word8 -> Word64
forall a b. (Integral a, Num b) => a -> b
fi Word8
w5_2 Word64 -> Int -> Word64
forall a. Bits a => a -> Int -> a
`B.shiftL` Int
25
         Word64 -> Word64 -> Word64
forall a. Bits a => a -> a -> a
.|. Word8 -> Word64
forall a b. (Integral a, Num b) => a -> b
fi Word8
w5_3 Word64 -> Int -> Word64
forall a. Bits a => a -> Int -> a
`B.shiftL` Int
20
         Word64 -> Word64 -> Word64
forall a. Bits a => a -> a -> a
.|. Word8 -> Word64
forall a b. (Integral a, Num b) => a -> b
fi Word8
w5_4 Word64 -> Int -> Word64
forall a. Bits a => a -> Int -> a
`B.shiftL` Int
15
         Word64 -> Word64 -> Word64
forall a. Bits a => a -> a -> a
.|. Word8 -> Word64
forall a b. (Integral a, Num b) => a -> b
fi Word8
w5_5 Word64 -> Int -> Word64
forall a. Bits a => a -> Int -> a
`B.shiftL` Int
10
         Word64 -> Word64 -> Word64
forall a. Bits a => a -> a -> a
.|. Word8 -> Word64
forall a b. (Integral a, Num b) => a -> b
fi Word8
w5_6 Word64 -> Int -> Word64
forall a. Bits a => a -> Int -> a
`B.shiftL` Int
05
         Word64 -> Word64 -> Word64
forall a. Bits a => a -> a -> a
.|. Word8 -> Word64
forall a b. (Integral a, Num b) => a -> b
fi Word8
w5_7
      !w32 :: Word32
w32 = Word64 -> Word32
forall a b. (Integral a, Num b) => a -> b
fi (Word64
w40 Word64 -> Int -> Word64
forall a. Bits a => a -> Int -> a
`B.shiftR` Int
8)   :: Word32
      !w8 :: Word8
w8  = Word64 -> Word8
forall a b. (Integral a, Num b) => a -> b
fi (Word64
0b11111111 Word64 -> Word64 -> Word64
forall a. Bits a => a -> a -> a
.&. Word64
w40) :: Word8

  Builder -> Maybe Builder
forall a. a -> Maybe a
forall (f :: * -> *) a. Applicative f => a -> f a
pure (Builder -> Maybe Builder) -> Builder -> Maybe Builder
forall a b. (a -> b) -> a -> b
$ Word32 -> Builder
BSB.word32BE Word32
w32 Builder -> Builder -> Builder
forall a. Semigroup a => a -> a -> a
<> Word8 -> Builder
BSB.word8 Word8
w8