diff --git a/CHANGELOG.md b/CHANGELOG.md
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,5 +1,16 @@
 # Revision history for base32
 
+## 0.4
+
+* Support for GHC 9.8
+* Drop support for GHC <9.x
+* Bump `bytestring` lower bound to 0.11 (thanks @vlix!)
+
+## 0.3.1.0
+
+* Small bug fix
+* Doc updates
+
 ## 0.3
 
 * Bump lower bounds for `bytestring` and `text` to latest significant major/major version
diff --git a/README.md b/README.md
--- a/README.md
+++ b/README.md
@@ -24,4 +24,4 @@
 - Optics for handling more complex structures with Base32 representations via the `base32-lens` package
 - Checks for both validity and correctness of Base32 and Base32hex encodings
 
-There are no dependencies aside from those bundled with GHC, `text-short`, and the `ghc-byteorder` re-export.
+There are no dependencies aside from those bundled with GHC, `text-short`.
diff --git a/base32.cabal b/base32.cabal
--- a/base32.cabal
+++ b/base32.cabal
@@ -1,6 +1,6 @@
-cabal-version:      2.0
+cabal-version:      3.0
 name:               base32
-version:            0.3
+version:            0.4
 synopsis:           Fast RFC 4648-compliant Base32 encoding
 description:
   RFC 4648-compliant Base32 encodings and decodings.
@@ -8,7 +8,7 @@
 
 homepage:           https://github.com/emilypi/base32
 bug-reports:        https://github.com/emilypi/base32/issues
-license:            BSD3
+license:            BSD-3-Clause
 license-file:       LICENSE
 author:             Emily Pillmore
 maintainer:         emilypi@cohomolo.gy
@@ -20,7 +20,7 @@
   README.md
 
 tested-with:
-  GHC ==8.10.7 || ==9.0.2 || ==9.2.5 || ==9.4.5 || ==9.6.2
+  GHC ==9.0.2 || ==9.2.8 || ==9.4.7 || ==9.6.3 || ==9.8.1
 
 source-repository head
   type:     git
@@ -51,10 +51,10 @@
     Data.ByteString.Base32.Internal.Utils
 
   build-depends:
-      base            >=4.14     && <4.19
+      base            >=4.15     && <4.20
     , bytestring     ^>=0.11
-    , deepseq        ^>=1.4.4.0
-    , text           ^>=2.0
+    , deepseq         >=1.4.4.0  && <1.6
+    , text            >=2.0      && <2.2
     , text-short     ^>=0.1
 
   hs-source-dirs:   src
@@ -68,7 +68,7 @@
   other-modules:    Internal
   main-is:          Main.hs
   build-depends:
-      base               >=4.14 && <4.19
+      base               >=4.15 && <4.20
     , base32
     , bytestring        ^>=0.11
     , memory
@@ -86,7 +86,7 @@
   hs-source-dirs:   benchmarks
   main-is:          Base32Bench.hs
   build-depends:
-      base               >=4.14 && <4.19
+      base               >=4.15 && <4.20
     , base32
     , bytestring        ^>=0.11
     , criterion
diff --git a/src/Data/ByteString/Base32.hs b/src/Data/ByteString/Base32.hs
--- a/src/Data/ByteString/Base32.hs
+++ b/src/Data/ByteString/Base32.hs
@@ -89,7 +89,7 @@
 -- Left "Base32-encoded bytestring has invalid padding"
 --
 decodeBase32 :: ByteString -> Either Text ByteString
-decodeBase32 bs@(PS _ _ !l)
+decodeBase32 bs@(BS _ !l)
     | l == 0 = Right bs
     | r == 0 = unsafeDupablePerformIO $ decodeBase32_ stdDecodeTable bs
     | r == 2 = unsafeDupablePerformIO $ decodeBase32_ stdDecodeTable (BS.append bs "======")
@@ -140,7 +140,7 @@
 -- Left "Base32-encoded bytestring has invalid padding"
 --
 decodeBase32Unpadded :: ByteString -> Either Text ByteString
-decodeBase32Unpadded bs@(PS _ _ !l)
+decodeBase32Unpadded bs@(BS _ !l)
     | l == 0 = Right bs
     | r == 0 = validateLastNPads 1 bs $ decodeBase32_ stdDecodeTable bs
     | r == 2 = unsafeDupablePerformIO $ decodeBase32_ stdDecodeTable (BS.append bs "======")
@@ -165,7 +165,7 @@
 -- Left "Base32-encoded bytestring requires padding"
 --
 decodeBase32Padded :: ByteString -> Either Text ByteString
-decodeBase32Padded bs@(PS _ _ !l)
+decodeBase32Padded bs@(BS _ !l)
     | l == 0 = Right bs
     | r == 1 = Left "Base32-encoded bytestring has invalid size"
     | r == 3 = Left "Base32-encoded bytestring has invalid size"
diff --git a/src/Data/ByteString/Base32/Hex.hs b/src/Data/ByteString/Base32/Hex.hs
--- a/src/Data/ByteString/Base32/Hex.hs
+++ b/src/Data/ByteString/Base32/Hex.hs
@@ -89,7 +89,7 @@
 -- Left "Base32-encoded bytestring has invalid padding"
 --
 decodeBase32 :: ByteString -> Either Text ByteString
-decodeBase32 bs@(PS _ _ !l)
+decodeBase32 bs@(BS _ !l)
     | l == 0 = Right bs
     | r == 0 = unsafeDupablePerformIO $ decodeBase32_ hexDecodeTable bs
     | r == 2 = unsafeDupablePerformIO $ decodeBase32_ hexDecodeTable (BS.append bs "======")
@@ -140,7 +140,7 @@
 -- Left "Base32-encoded bytestring has invalid padding"
 --
 decodeBase32Unpadded :: ByteString -> Either Text ByteString
-decodeBase32Unpadded bs@(PS _ _ !l)
+decodeBase32Unpadded bs@(BS _ !l)
     | l == 0 = Right bs
     | r == 0 = validateLastNPads 1 bs $ decodeBase32_ hexDecodeTable bs
     | r == 2 = unsafeDupablePerformIO $ decodeBase32_ hexDecodeTable (BS.append bs "======")
@@ -165,7 +165,7 @@
 -- Left "Base32-encoded bytestring requires padding"
 --
 decodeBase32Padded :: ByteString -> Either Text ByteString
-decodeBase32Padded bs@(PS _ _ !l)
+decodeBase32Padded bs@(BS _ !l)
     | l == 0 = Right bs
     | r == 1 = Left "Base32-encoded bytestring has invalid size"
     | r == 3 = Left "Base32-encoded bytestring has invalid size"
diff --git a/src/Data/ByteString/Base32/Internal.hs b/src/Data/ByteString/Base32/Internal.hs
--- a/src/Data/ByteString/Base32/Internal.hs
+++ b/src/Data/ByteString/Base32/Internal.hs
@@ -1,8 +1,5 @@
 {-# LANGUAGE BangPatterns #-}
-{-# LANGUAGE CPP #-}
-{-# LANGUAGE MagicHash #-}
 {-# LANGUAGE OverloadedStrings #-}
-{-# LANGUAGE TypeApplications #-}
 -- |
 -- Module       : Data.ByteString.Base32.Internal
 -- Copyright 	: (c) 2020 Emily Pillmore
@@ -43,7 +40,7 @@
 -- | Validate a base32-encoded bytestring against some alphabet.
 --
 validateBase32 :: ByteString -> ByteString -> Bool
-validateBase32 !alphabet bs@(PS _ _ l)
+validateBase32 !alphabet bs@(BS _ l)
     | l == 0 = True
     | r == 0 = f bs
     | r == 2 = f (BS.append bs "======")
@@ -54,8 +51,8 @@
   where
     r = l `rem` 8
 
-    f (PS fp o l') = accursedUnutterablePerformIO $ withForeignPtr fp $ \p ->
-      go (plusPtr p o) (plusPtr p (l' + o))
+    f (BS fp l') = accursedUnutterablePerformIO $ withForeignPtr fp $ \p ->
+      go p (plusPtr p l')
 
     go !p !end
       | p == end = return True
@@ -105,13 +102,12 @@
     -> ByteString
     -> IO (Either Text ByteString)
     -> Either Text ByteString
-validateLastNPads !n (PS !fp !o !l) io
+validateLastNPads !n (BS !fp !l) io
     | not valid = Left "Base32-encoded bytestring has invalid padding"
     | otherwise = unsafeDupablePerformIO io
   where
-    !lo = l + o
     valid = accursedUnutterablePerformIO $ withForeignPtr fp $ \p -> do
-      let end = plusPtr p lo
+      let end = plusPtr p l
 
       let go :: Ptr Word8 -> IO Bool
           go !q
@@ -120,5 +116,5 @@
               a <- peek q
               if a == 0x3d then return False else go (plusPtr q 1)
 
-      go (plusPtr p (lo - n))
+      go (plusPtr p (l - n))
 {-# INLINE validateLastNPads #-}
diff --git a/src/Data/ByteString/Base32/Internal/Head.hs b/src/Data/ByteString/Base32/Internal/Head.hs
--- a/src/Data/ByteString/Base32/Internal/Head.hs
+++ b/src/Data/ByteString/Base32/Internal/Head.hs
@@ -1,6 +1,6 @@
-{-# LANGUAGE TypeApplications #-}
 {-# LANGUAGE BangPatterns #-}
 {-# LANGUAGE MagicHash #-}
+{-# LANGUAGE TypeApplications #-}
 module Data.ByteString.Base32.Internal.Head
 ( encodeBase32_
 , encodeBase32NoPad_
@@ -30,13 +30,13 @@
 -- executes the inner encoding loop against that data.
 --
 encodeBase32_ :: Addr# -> ByteString -> ByteString
-encodeBase32_ !lut (PS !sfp !o !l) = unsafeDupablePerformIO $ do
+encodeBase32_ !lut (BS !sfp !l) = unsafeDupablePerformIO $ do
     dfp <- mallocPlainForeignPtrBytes dlen
     withForeignPtr dfp $ \dptr ->
       withForeignPtr sfp $ \sptr -> do
-        let !end = plusPtr sptr (l + o)
+        let !end = plusPtr sptr l
         innerLoop lut
-          (castPtr dptr) (plusPtr sptr o)
+          (castPtr dptr) sptr
           end (loopTail lut dfp dptr end)
   where
     !dlen = ceiling (fromIntegral @_ @Double l / 5) * 8
@@ -48,13 +48,13 @@
 -- executes the inner encoding loop against that data.
 --
 encodeBase32NoPad_ :: Addr# -> ByteString -> ByteString
-encodeBase32NoPad_ !lut (PS !sfp !o !l) = unsafeDupablePerformIO $ do
+encodeBase32NoPad_ !lut (BS !sfp !l) = unsafeDupablePerformIO $ do
     !dfp <- mallocPlainForeignPtrBytes dlen
     withForeignPtr dfp $ \dptr ->
       withForeignPtr sfp $ \sptr -> do
-        let !end = plusPtr sptr (l + o)
+        let !end = plusPtr sptr l
         innerLoop lut
-          (castPtr dptr) (plusPtr sptr o)
+          (castPtr dptr) sptr
           end (loopTailNoPad lut dfp dptr end)
   where
     !dlen = ceiling (fromIntegral @_ @Double l / 5) * 8
@@ -66,11 +66,11 @@
 -- and executes the inner decoding loop against that data.
 --
 decodeBase32_ :: Ptr Word8 -> ByteString -> IO (Either Text ByteString)
-decodeBase32_ (Ptr !dtable) (PS !sfp !soff !slen) =
+decodeBase32_ (Ptr !dtable) (BS !sfp !slen) =
     withForeignPtr sfp $ \sptr -> do
       dfp <- mallocPlainForeignPtrBytes dlen
       withForeignPtr dfp $ \dptr -> do
-        let !end = plusPtr sptr (soff + slen)
-        decodeLoop dtable dfp dptr (plusPtr sptr soff) end
+        let !end = plusPtr sptr slen
+        decodeLoop dtable dfp dptr sptr end
   where
     !dlen = ceiling (fromIntegral @_ @Double slen / 1.6)
diff --git a/src/Data/ByteString/Base32/Internal/Loop.hs b/src/Data/ByteString/Base32/Internal/Loop.hs
--- a/src/Data/ByteString/Base32/Internal/Loop.hs
+++ b/src/Data/ByteString/Base32/Internal/Loop.hs
@@ -1,7 +1,5 @@
 {-# LANGUAGE BangPatterns #-}
-{-# LANGUAGE CPP #-}
 {-# LANGUAGE MagicHash #-}
-{-# LANGUAGE MultiWayIf #-}
 {-# LANGUAGE TypeApplications #-}
 module Data.ByteString.Base32.Internal.Loop
 ( innerLoop
@@ -72,43 +70,41 @@
     :: Addr#
     -> ForeignPtr Word8
     -> Ptr Word8
-    -> Ptr Word64
     -> Ptr Word8
+    -> Ptr Word8
     -> IO (Either Text ByteString)
 decodeLoop !lut !dfp !dptr !sptr !end = go dptr sptr
   where
     lix a = w64 (aix (fromIntegral a) lut)
 
-    err :: Ptr Word64 -> IO (Either Text ByteString)
+    err :: Ptr Word8 -> IO (Either Text ByteString)
     err p = return . Left . T.pack
       $ "invalid character at offset: "
       ++ show (p `minusPtr` sptr)
 
-    padErr :: Ptr Word64 -> IO (Either Text ByteString)
+    padErr :: Ptr Word8 -> IO (Either Text ByteString)
     padErr p =  return . Left . T.pack
       $ "invalid padding at offset: "
       ++ show (p `minusPtr` sptr)
 
     look :: Ptr Word8 -> IO Word64
-    look !p = lix . w64 <$> peek @Word8 p
+    look !p = lix <$> peek @Word8 p
 
     go !dst !src
       | plusPtr src 8 >= end = do
 
-        let src' = castPtr src
-
-        a <- look src'
-        b <- look (plusPtr src' 1)
-        c <- look (plusPtr src' 2)
-        d <- look (plusPtr src' 3)
-        e <- look (plusPtr src' 4)
-        f <- look (plusPtr src' 5)
-        g <- look (plusPtr src' 6)
-        h <- look (plusPtr src' 7)
+        a <- look src
+        b <- look (plusPtr src 1)
+        c <- look (plusPtr src 2)
+        d <- look (plusPtr src 3)
+        e <- look (plusPtr src 4)
+        f <- look (plusPtr src 5)
+        g <- look (plusPtr src 6)
+        h <- look (plusPtr src 7)
         finalChunk dst src a b c d e f g h
 
       | otherwise = do
-        !t <- peekWord64BE src
+        !t <- peekWord64BE (castPtr src)
 
         let a = lix (unsafeShiftR t 56)
             b = lix (unsafeShiftR t 48)
@@ -149,18 +145,18 @@
 
         case (c,d,e,f,g,h) of
           (0x63,0x63,0x63,0x63,0x63,0x63) ->
-            return (Right (PS dfp 0 (1 + minusPtr dst dptr)))
+            return (Right (BS dfp (1 + minusPtr dst dptr)))
           (0x63,_,_,_,_,_) -> padErr (plusPtr src 3)
           (_,0x63,0x63,0x63,0x63,0x63) -> padErr (plusPtr src 3)
           (_,0x63,_,_,_,_) -> padErr (plusPtr src 4)
           (_,_,0x63,0x63,0x63,0x63) -> do
             poke @Word8 (plusPtr dst 2) o3
-            return (Right (PS dfp 0 (2 + minusPtr dst dptr)))
+            return (Right (BS dfp (2 + minusPtr dst dptr)))
           (_,_,0x63,_,_,_) -> padErr (plusPtr src 5)
           (_,_,_,0x63,0x63,0x63) -> do
             poke @Word8 (plusPtr dst 2) o3
             poke @Word8 (plusPtr dst 3) o4
-            return (Right (PS dfp 0 (3 + minusPtr dst dptr)))
+            return (Right (BS dfp (3 + minusPtr dst dptr)))
           (_,_,_,0x63,_,_) -> padErr (plusPtr src 6)
           (_,_,_,_,0x63,0x63) -> padErr (plusPtr src 6)
           (_,_,_,_,0x63,_) -> padErr (plusPtr src 7)
@@ -168,12 +164,12 @@
             poke @Word8 (plusPtr dst 2) o3
             poke @Word8 (plusPtr dst 3) o4
             poke @Word8 (plusPtr dst 4) o5
-            return (Right (PS dfp 0 (4 + minusPtr dst dptr)))
+            return (Right (BS dfp (4 + minusPtr dst dptr)))
           (_,_,_,_,_,_) -> do
             poke @Word8 (plusPtr dst 2) o3
             poke @Word8 (plusPtr dst 3) o4
             poke @Word8 (plusPtr dst 4) o5
-            return (Right (PS dfp 0 (5 + minusPtr dst dptr)))
+            return (Right (BS dfp (5 + minusPtr dst dptr)))
 
     decodeChunk !dst !src !a !b !c !d !e !f !g !h
       | a == 0x63 = padErr src
diff --git a/src/Data/ByteString/Base32/Internal/Tables.hs b/src/Data/ByteString/Base32/Internal/Tables.hs
--- a/src/Data/ByteString/Base32/Internal/Tables.hs
+++ b/src/Data/ByteString/Base32/Internal/Tables.hs
@@ -1,4 +1,3 @@
-{-# LANGUAGE MagicHash #-}
 {-# LANGUAGE TypeApplications #-}
 module Data.ByteString.Base32.Internal.Tables
 ( stdDecodeTable
@@ -6,9 +5,9 @@
 ) where
 
 
-import Data.ByteString.Base32.Internal.Utils
+import Data.ByteString.Base32.Internal.Utils (writeNPlainPtrBytes)
 
-import GHC.Word
+import GHC.Word (Word8)
 import GHC.Ptr (Ptr)
 
 
diff --git a/src/Data/ByteString/Base32/Internal/Tail.hs b/src/Data/ByteString/Base32/Internal/Tail.hs
--- a/src/Data/ByteString/Base32/Internal/Tail.hs
+++ b/src/Data/ByteString/Base32/Internal/Tail.hs
@@ -1,9 +1,5 @@
 {-# LANGUAGE BangPatterns #-}
-{-# LANGUAGE LambdaCase #-}
 {-# LANGUAGE MagicHash #-}
-{-# LANGUAGE MultiWayIf #-}
-{-# LANGUAGE OverloadedStrings #-}
-{-# LANGUAGE TypeApplications #-}
 module Data.ByteString.Base32.Internal.Tail
 ( loopTail
 , loopTailNoPad
@@ -33,7 +29,7 @@
     -> Ptr Word8
     -> IO ByteString
 loopTail !lut !dfp !dptr !end !dst !src
-    | src == end = return (PS dfp 0 (minusPtr dst dptr))
+    | src == end = return (BS dfp (minusPtr dst dptr))
     | plusPtr src 1 == end = do -- 2 6
       !a <- peek src
 
@@ -44,13 +40,13 @@
       poke (plusPtr dst 1) u
       padN (plusPtr dst 2) 6
 
-      return (PS dfp 0 (8 + minusPtr dst dptr))
+      return (BS dfp (8 + minusPtr dst dptr))
     | plusPtr src 2 == end = do -- 4 4
       !a <- peek src
       !b <- peek (plusPtr src 1)
 
       let !t = look (unsafeShiftR (a .&. 0xf8) 3)
-          !u = look ((unsafeShiftL (a .&. 0x07) 2) .|. (unsafeShiftR (b .&. 0xc0) 6))
+          !u = look (unsafeShiftL (a .&. 0x07) 2 .|. unsafeShiftR (b .&. 0xc0) 6)
           !v = look (unsafeShiftR (b .&. 0x3e) 1)
           !w = look (unsafeShiftL (b .&. 0x01) 4)
 
@@ -60,16 +56,16 @@
       poke (plusPtr dst 3) w
       padN (plusPtr dst 4) 4
 
-      return (PS dfp 0 (8 + minusPtr dst dptr))
+      return (BS dfp (8 + minusPtr dst dptr))
     | plusPtr src 3 == end = do -- 5 3
       !a <- peek src
       !b <- peek (plusPtr src 1)
       !c <- peek (plusPtr src 2)
 
       let !t = look (unsafeShiftR (a .&. 0xf8) 3)
-          !u = look ((unsafeShiftL (a .&. 0x07) 2) .|. (unsafeShiftR (b .&. 0xc0) 6))
+          !u = look (unsafeShiftL (a .&. 0x07) 2 .|. unsafeShiftR (b .&. 0xc0) 6)
           !v = look (unsafeShiftR (b .&. 0x3e) 1)
-          !w = look ((unsafeShiftL (b .&. 0x01) 4) .|. (unsafeShiftR (c .&. 0xf0) 4))
+          !w = look (unsafeShiftL (b .&. 0x01) 4 .|. unsafeShiftR (c .&. 0xf0) 4)
           !x = look (unsafeShiftL (c .&. 0x0f) 1)
 
       poke dst t
@@ -78,7 +74,7 @@
       poke (plusPtr dst 3) w
       poke (plusPtr dst 4) x
       padN (plusPtr dst 5) 3
-      return (PS dfp 0 (8 + minusPtr dst dptr))
+      return (BS dfp (8 + minusPtr dst dptr))
 
     | otherwise = do -- 7 1
       !a <- peek src
@@ -87,10 +83,10 @@
       !d <- peek (plusPtr src 3)
 
       let !t = look (unsafeShiftR (a .&. 0xf8) 3)
-          !u = look ((unsafeShiftL (a .&. 0x07) 2) .|. (unsafeShiftR (b .&. 0xc0) 6))
+          !u = look (unsafeShiftL (a .&. 0x07) 2 .|. unsafeShiftR (b .&. 0xc0) 6)
           !v = look (unsafeShiftR (b .&. 0x3e) 1)
-          !w = look ((unsafeShiftL (b .&. 0x01) 4) .|. (unsafeShiftR (c .&. 0xf0) 4))
-          !x = look ((unsafeShiftL (c .&. 0x0f) 1) .|. (unsafeShiftR (d .&. 0x80) 7))
+          !w = look (unsafeShiftL (b .&. 0x01) 4 .|. unsafeShiftR (c .&. 0xf0) 4)
+          !x = look (unsafeShiftL (c .&. 0x0f) 1 .|. unsafeShiftR (d .&. 0x80) 7)
           !y = look (unsafeShiftR (d .&. 0x7c) 2)
           !z = look (unsafeShiftL (d .&. 0x03) 3)
 
@@ -102,7 +98,7 @@
       poke (plusPtr dst 5) y
       poke (plusPtr dst 6) z
       padN (plusPtr dst 7) 1
-      return (PS dfp 0 (8 + minusPtr dst dptr))
+      return (BS dfp (8 + minusPtr dst dptr))
   where
     look !n = aix n lut
 
@@ -122,7 +118,7 @@
     -> Ptr Word8
     -> IO ByteString
 loopTailNoPad !lut !dfp !dptr !end !dst !src
-  | src == end = return (PS dfp 0 (minusPtr dst dptr))
+  | src == end = return (BS dfp (minusPtr dst dptr))
   | plusPtr src 1 == end = do -- 2 6
       !a <- peek src
 
@@ -132,14 +128,14 @@
       poke dst t
       poke (plusPtr dst 1) u
 
-      return (PS dfp 0 (2 + minusPtr dst dptr))
+      return (BS dfp (2 + minusPtr dst dptr))
 
     | plusPtr src 2 == end = do -- 4 4
       !a <- peek src
       !b <- peek (plusPtr src 1)
 
       let !t = look (unsafeShiftR (a .&. 0xf8) 3)
-          !u = look ((unsafeShiftL (a .&. 0x07) 2) .|. (unsafeShiftR (b .&. 0xc0) 6))
+          !u = look (unsafeShiftL (a .&. 0x07) 2 .|. unsafeShiftR (b .&. 0xc0) 6)
           !v = look (unsafeShiftR (b .&. 0x3e) 1)
           !w = look (unsafeShiftL (b .&. 0x01) 4)
 
@@ -148,7 +144,7 @@
       poke (plusPtr dst 2) v
       poke (plusPtr dst 3) w
 
-      return (PS dfp 0 (4 + minusPtr dst dptr))
+      return (BS dfp (4 + minusPtr dst dptr))
 
     | plusPtr src 3 == end = do -- 5 3
       !a <- peek src
@@ -156,9 +152,9 @@
       !c <- peek (plusPtr src 2)
 
       let !t = look (unsafeShiftR (a .&. 0xf8) 3)
-          !u = look ((unsafeShiftL (a .&. 0x07) 2) .|. (unsafeShiftR (b .&. 0xc0) 6))
+          !u = look (unsafeShiftL (a .&. 0x07) 2 .|. unsafeShiftR (b .&. 0xc0) 6)
           !v = look (unsafeShiftR (b .&. 0x3e) 1)
-          !w = look ((unsafeShiftL (b .&. 0x01) 4) .|. (unsafeShiftR (c .&. 0xf0) 4))
+          !w = look (unsafeShiftL (b .&. 0x01) 4 .|. unsafeShiftR (c .&. 0xf0) 4)
           !x = look (unsafeShiftL (c .&. 0x0f) 1)
 
       poke dst t
@@ -166,7 +162,7 @@
       poke (plusPtr dst 2) v
       poke (plusPtr dst 3) w
       poke (plusPtr dst 4) x
-      return (PS dfp 0 (5 + minusPtr dst dptr))
+      return (BS dfp (5 + minusPtr dst dptr))
 
     | otherwise = do -- 7 1
       !a <- peek src
@@ -175,10 +171,10 @@
       !d <- peek (plusPtr src 3)
 
       let !t = look (unsafeShiftR (a .&. 0xf8) 3)
-          !u = look ((unsafeShiftL (a .&. 0x07) 2) .|. (unsafeShiftR (b .&. 0xc0) 6))
+          !u = look (unsafeShiftL (a .&. 0x07) 2 .|. unsafeShiftR (b .&. 0xc0) 6)
           !v = look (unsafeShiftR (b .&. 0x3e) 1)
-          !w = look ((unsafeShiftL (b .&. 0x01) 4) .|. (unsafeShiftR (c .&. 0xf0) 4))
-          !x = look ((unsafeShiftL (c .&. 0x0f) 1) .|. (unsafeShiftR (d .&. 0x80) 7))
+          !w = look (unsafeShiftL (b .&. 0x01) 4 .|. unsafeShiftR (c .&. 0xf0) 4)
+          !x = look (unsafeShiftL (c .&. 0x0f) 1 .|. unsafeShiftR (d .&. 0x80) 7)
           !y = look (unsafeShiftR (d .&. 0x7c) 2)
           !z = look (unsafeShiftL (d .&. 0x03) 3)
 
@@ -189,7 +185,7 @@
       poke (plusPtr dst 4) x
       poke (plusPtr dst 5) y
       poke (plusPtr dst 6) z
-      return (PS dfp 0 (7 + minusPtr dst dptr))
+      return (BS dfp (7 + minusPtr dst dptr))
   where
     look !i = aix i lut
 {-# INLINE loopTailNoPad #-}
diff --git a/src/Data/ByteString/Lazy/Base32.hs b/src/Data/ByteString/Lazy/Base32.hs
--- a/src/Data/ByteString/Lazy/Base32.hs
+++ b/src/Data/ByteString/Lazy/Base32.hs
@@ -1,4 +1,3 @@
-{-# LANGUAGE BangPatterns #-}
 {-# LANGUAGE OverloadedStrings #-}
 {-# LANGUAGE Trustworthy #-}
 -- |
diff --git a/src/Data/ByteString/Lazy/Base32/Hex.hs b/src/Data/ByteString/Lazy/Base32/Hex.hs
--- a/src/Data/ByteString/Lazy/Base32/Hex.hs
+++ b/src/Data/ByteString/Lazy/Base32/Hex.hs
@@ -1,4 +1,3 @@
-{-# LANGUAGE BangPatterns #-}
 {-# LANGUAGE OverloadedStrings #-}
 {-# LANGUAGE Trustworthy #-}
 -- |
diff --git a/src/Data/Text/Encoding/Base32.hs b/src/Data/Text/Encoding/Base32.hs
--- a/src/Data/Text/Encoding/Base32.hs
+++ b/src/Data/Text/Encoding/Base32.hs
@@ -54,7 +54,7 @@
 -- 4 for safe decoding as base32 encodings are optionally padded.
 --
 -- /Note:/ This function makes sure that decoding is total by deferring to
--- 'T.decodeLatin1'. This will always round trip for any valid Base32-encoded
+-- 'T.decodeUtf8'. This will always round trip for any valid Base32-encoded
 -- text value, but it may not round trip for bad inputs. The onus is on the
 -- caller to make sure inputs are valid. If unsure, defer to `decodeBase32With`
 -- and pass in a custom decode function.
@@ -73,7 +73,7 @@
 -- Left "Base32-encoded bytestring has invalid padding"
 --
 decodeBase32 :: Text -> Either Text Text
-decodeBase32 = fmap T.decodeLatin1
+decodeBase32 = fmap T.decodeUtf8
     . B32.decodeBase32
     . T.encodeUtf8
 {-# INLINE decodeBase32 #-}
@@ -118,7 +118,7 @@
 -- | Decode an unpadded Base32 encoded 'Text' value.
 --
 -- /Note:/ This function makes sure that decoding is total by deferring to
--- 'T.decodeLatin1'. This will always round trip for any valid Base32-encoded
+-- 'T.decodeUtf8'. This will always round trip for any valid Base32-encoded
 -- text value, but it may not round trip for bad inputs. The onus is on the
 -- caller to make sure inputs are valid. If unsure, defer to `decodeBase32WUnpaddedWith`
 -- and pass in a custom decode function.
@@ -134,7 +134,7 @@
 -- Left "Base32-encoded bytestring has invalid padding"
 --
 decodeBase32Unpadded :: Text -> Either Text Text
-decodeBase32Unpadded = fmap T.decodeLatin1
+decodeBase32Unpadded = fmap T.decodeUtf8
     . B32.decodeBase32Unpadded
     . T.encodeUtf8
 {-# INLINE decodeBase32Unpadded #-}
@@ -167,7 +167,7 @@
 -- | Decode an padded Base32 encoded 'Text' value
 --
 -- /Note:/ This function makes sure that decoding is total by deferring to
--- 'T.decodeLatin1'. This will always round trip for any valid Base32-encoded
+-- 'T.decodeUtf8'. This will always round trip for any valid Base32-encoded
 -- text value, but it may not round trip for bad inputs. The onus is on the
 -- caller to make sure inputs are valid. If unsure, defer to `decodeBase32PaddedWith`
 -- and pass in a custom decode function.
@@ -183,7 +183,7 @@
 -- Left "Base32-encoded bytestring requires padding"
 --
 decodeBase32Padded :: Text -> Either Text Text
-decodeBase32Padded = fmap T.decodeLatin1
+decodeBase32Padded = fmap T.decodeUtf8
     . B32.decodeBase32Padded
     . T.encodeUtf8
 {-# INLINE decodeBase32Padded #-}
