diff --git a/CHANGELOG.md b/CHANGELOG.md
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,3 +1,6 @@
+## 0.4.1 (2023-02-15)
+  * bump blake3 dependency to 0.3
+
 ## 0.4.0 (2022-07-08)
   * lots of refactoring, breaking, removing
   * clean up FunctorRec into standalone HFunctorList module
diff --git a/app/BytePatch.hs b/app/BytePatch.hs
--- a/app/BytePatch.hs
+++ b/app/BytePatch.hs
@@ -91,7 +91,7 @@
 liftProcessError action =
     runExceptT action >>= \case
       Left  e -> quit e
-      Right a -> return a
+      Right a -> pure a
 
 liftMapProcessError :: MonadError Error m => (e -> Error) -> Either e a -> m a
 liftMapProcessError f = liftEither . mapLeft f
@@ -207,7 +207,7 @@
     bsIn <- readStream si
     case Apply.runPureBinCompareFwd ps bsIn of
       Left  e     -> quit $ ErrorProcessApply $ show e
-      Right bsOut -> return $ BL.toStrict bsOut
+      Right bsOut -> pure $ BL.toStrict bsOut
 
 cmdPatchBinCompareFwd
     :: forall v m
@@ -261,7 +261,7 @@
     -> Bytes
     -> m [Patch Int '[Compare.Meta v, Bin.Meta] Bytes]
 prep c bs = case c.cPsFmtData of
-  CDataBytes -> prep' @HexByteString c (return . fmap unHexPatch) bs
+  CDataBytes -> prep' @HexByteString c (pure . fmap unHexPatch) bs
   CDataTextBin BR.Text.UTF8 BR.ByteString.C ->
       prep' @Text @(AsByteString 'BR.ByteString.C) c (binTextifyPatches @'BR.Text.UTF8) bs
   CDataAsm Asm.ArmV8ThumbLE -> prep' c (processAsm @'Asm.ArmV8ThumbLE) bs
@@ -291,7 +291,7 @@
 binTextifyPatch p = liftEither $ do
     pTextEnc <- liftMapProcessError (Error . show) $ traverse (refine @enc) p
     pBs <- liftMapProcessError (Error . show) $ traverse (BR.Text.encodeToRep @rep) pTextEnc
-    return pBs
+    pure pBs
 
 -- Binrep-compare, parsing @a@ and failably converting to @b@, In many cases,
 -- you may want to parse and binrep the same type -- in such cases, use 'pure'.
@@ -315,7 +315,7 @@
                 >>= processBin @b
                 >>= processLinearize
       CNoAlign ->     processDecode bs
-                  >>= return . map Simple.convertBin
+                  >>= pure . map Simple.convertBin
                   >>= fBin
                   >>= processBin @b
                   >>= processLinearize
diff --git a/bytepatch.cabal b/bytepatch.cabal
--- a/bytepatch.cabal
+++ b/bytepatch.cabal
@@ -1,11 +1,11 @@
 cabal-version: 1.12
 
--- This file has been generated from package.yaml by hpack version 0.34.4.
+-- This file has been generated from package.yaml by hpack version 0.35.1.
 --
 -- see: https://github.com/sol/hpack
 
 name:           bytepatch
-version:        0.4.0
+version:        0.4.1
 synopsis:       Patch byte-representable data in a bytestream
 description:    Please see README.md.
 category:       CLI
@@ -17,7 +17,7 @@
 license-file:   LICENSE
 build-type:     Simple
 tested-with:
-    GHC ==9.2.3
+    GHC ==9.2.4
 extra-source-files:
     README.md
     CHANGELOG.md
@@ -87,8 +87,8 @@
   build-depends:
       aeson >=2.0.2.0 && <2.1
     , base >=4.12 && <5
-    , binrep
-    , blake3 ==0.2.*
+    , binrep >=0.3.1 && <0.4
+    , blake3 ==0.3.*
     , bytestring >=0.10 && <0.12
     , either >=5.0.1.1 && <5.1
     , generic-optics >=2.2.1.0 && <2.3
@@ -103,7 +103,7 @@
     , text >=1.2.4.1 && <1.3
     , text-short >=0.1.5 && <0.2
     , vinyl >=0.14.1 && <0.15
-  default-language: Haskell2010
+  default-language: GHC2021
 
 executable bytepatch
   main-is: Main.hs
@@ -151,8 +151,8 @@
   build-depends:
       aeson >=2.0.2.0 && <2.1
     , base >=4.12 && <5
-    , binrep
-    , blake3 ==0.2.*
+    , binrep >=0.3.1 && <0.4
+    , blake3 ==0.3.*
     , bytepatch
     , bytestring >=0.10 && <0.12
     , either >=5.0.1.1 && <5.1
@@ -163,7 +163,7 @@
     , mtl >=2.2.2 && <2.3
     , optics >=0.3 && <0.5
     , optparse-applicative ==0.17.*
-    , refined ==0.7.*
+    , refined >=0.7 && <0.9
     , singletons ==3.0.*
     , singletons-base ==3.1.*
     , singletons-th ==3.1.*
@@ -171,7 +171,7 @@
     , text-short >=0.1.5 && <0.2
     , vinyl >=0.14.1 && <0.15
     , yaml >=0.11.6.0 && <0.12
-  default-language: Haskell2010
+  default-language: GHC2021
 
 test-suite spec
   type: exitcode-stdio-1.0
@@ -223,8 +223,8 @@
       QuickCheck >=2.14.2 && <2.15
     , aeson >=2.0.2.0 && <2.1
     , base >=4.12 && <5
-    , binrep
-    , blake3 ==0.2.*
+    , binrep >=0.3.1 && <0.4
+    , blake3 ==0.3.*
     , bytepatch
     , bytestring >=0.10 && <0.12
     , either >=5.0.1.1 && <5.1
@@ -241,4 +241,4 @@
     , text >=1.2.4.1 && <1.3
     , text-short >=0.1.5 && <0.2
     , vinyl >=0.14.1 && <0.15
-  default-language: Haskell2010
+  default-language: GHC2021
diff --git a/src/Binrep/Type/Assembly/Assemble.hs b/src/Binrep/Type/Assembly/Assemble.hs
--- a/src/Binrep/Type/Assembly/Assemble.hs
+++ b/src/Binrep/Type/Assembly/Assemble.hs
@@ -64,5 +64,5 @@
         -- x>1 weird error, if x<1 check errno->strerror
         liftIO (Keystone.runAssembler out') >>= \case
           Left e -> err $ "error while assembling: "<>show e
-          Right (mc, _count) -> return $ Right mc
-  where err = return . Left
+          Right (mc, _count) -> pure $ Right mc
+  where err = pure . Left
diff --git a/src/StreamPatch/Apply.hs b/src/StreamPatch/Apply.hs
--- a/src/StreamPatch/Apply.hs
+++ b/src/StreamPatch/Apply.hs
@@ -50,17 +50,17 @@
   where
     err = throwError
     doCompare bs' = \case
-      Nothing   -> return ()
+      Nothing   -> pure ()
       Just cmp -> do
         case compareTo @v cmp bs' of
-          Nothing -> return ()
+          Nothing -> pure ()
           Just e -> err $ ErrorCompare e
     doNullTermCheck bs' = \case
-      Nothing -> return bs'
+      Nothing -> pure bs'
       Just nt ->
         let (bs'', bsNulls) = BS.splitAt (fromIntegral nt) bs'
          in if   bsNulls == BS.replicate (BS.length bsNulls) 0x00
-            then return bs''
+            then pure bs''
             else err $ ErrorBinUnexpectedNonNull bs'
 
 runPureBinCompareFwd
@@ -104,10 +104,10 @@
     case Compare.mCompare cm of
       Nothing   -> do
         x <- overwrite a
-        return $ Right x
+        pure $ Right x
       Just aCmp -> case compareTo @v aCmp aStream of
-                     Nothing -> return $ Right ()
-                     Just e  -> return $ Left $ ErrorCompare e
+                     Nothing -> pure $ Right ()
+                     Just e  -> pure $ Left $ ErrorCompare e
 
 runPureFwdCompareString
     :: Compare v String
diff --git a/src/StreamPatch/Patch/Binary.hs b/src/StreamPatch/Patch/Binary.hs
--- a/src/StreamPatch/Patch/Binary.hs
+++ b/src/StreamPatch/Patch/Binary.hs
@@ -65,16 +65,16 @@
     checkMeta m
     let bs = runPut a
         bsms = fmap runPut ms'
-    return $ Patch bs s bsms
+    pure $ Patch bs s bsms
   where
     checkMeta m =
         case mpMaxBytes m of
-          Nothing       -> return ()
+          Nothing       -> pure ()
           Just maxBytes ->
             let maxBytes' = natToBLen maxBytes
              in if   blen a > maxBytes'
                 then Left $ ErrorBinRepOverlong (blen a) maxBytes' a Nothing
-                else return ()
+                else pure ()
 
 -- | Treat the nulls field as a "this is how many extra nulls there are", and
 --   amend the compare meta for a patch by appending those nulls, and strip that
diff --git a/src/StreamPatch/Patch/Compare.hs b/src/StreamPatch/Patch/Compare.hs
--- a/src/StreamPatch/Patch/Compare.hs
+++ b/src/StreamPatch/Patch/Compare.hs
@@ -33,7 +33,7 @@
 import Text.Megaparsec.Char.Lexer qualified as MCL
 
 import BLAKE3 qualified as B3
-import Data.ByteArray qualified as BA
+import Data.ByteArray.Sized qualified as BA
 import Data.ByteString qualified as B
 import Data.Word ( Word8 )
 
@@ -196,7 +196,7 @@
 -- I unpack to '[Word8]' then repack to 'ByteString' because the memory library
 -- is very keen on complicated unsafe IO. cheers no thanks
 hashB3 :: BS.ByteString -> BS.ByteString
-hashB3 bs = BS.pack $ BA.unpack $ B3.hash @B3.DEFAULT_DIGEST_LEN [bs]
+hashB3 bs = BA.unSizedByteArray $ B3.hash @B3.DEFAULT_DIGEST_LEN Nothing [bs]
 
 class SwapCompare a (vFrom :: Via) (vTo :: Via) where
     swapCompare :: CompareRep vFrom a -> Either String (CompareRep vTo a)
diff --git a/src/StreamPatch/Patch/Linearize/InPlace.hs b/src/StreamPatch/Patch/Linearize/InPlace.hs
--- a/src/StreamPatch/Patch/Linearize/InPlace.hs
+++ b/src/StreamPatch/Patch/Linearize/InPlace.hs
@@ -50,9 +50,9 @@
         let skip = s - cursor
         if skip < 0 then do
             -- next absolute seek is before cursor: current patch overlaps prev
-            return $ Left $ ErrorOverlap cursor p pPrev
+            pure $ Left $ ErrorOverlap cursor p pPrev
         else do
             let cursor' = cursor + skip + getLength a
                 p' = p { patchSeek = skip }
             put (cursor', p)
-            return $ Right p'
+            pure $ Right p'
diff --git a/src/StreamPatch/Patch/Linearize/Insert.hs b/src/StreamPatch/Patch/Linearize/Insert.hs
--- a/src/StreamPatch/Patch/Linearize/Insert.hs
+++ b/src/StreamPatch/Patch/Linearize/Insert.hs
@@ -34,8 +34,8 @@
         a' <- get
         let s' = fromIntegral $ f a - f a'
         if s' == 0
-        then return $ Left (a, a')
-        else put a >> return (Right (g s' a))
+        then pure $ Left (a, a')
+        else put a >> pure (Right (g s' a))
 
 linearize' :: (Integral sf, Integral st) => [sf] -> Either (sf, sf) (Maybe (sf, [st]))
 linearize' = linearize id const
diff --git a/src/StreamPatch/Stream.hs b/src/StreamPatch/Stream.hs
--- a/src/StreamPatch/Stream.hs
+++ b/src/StreamPatch/Stream.hs
@@ -53,7 +53,7 @@
 instance Monad m => FwdInplaceStream (StateT (B.ByteString, BB.Builder, Int) m) where
     type Chunk (StateT (B.ByteString, BB.Builder, Int) m) = B.ByteString
     type Index (StateT (B.ByteString, BB.Builder, Int) m) = Int
-    readahead n = get >>= \(src, _, _) -> return $ B.take n src
+    readahead n = get >>= \(src, _, _) -> pure $ B.take n src
     overwrite bs = do
         (src, out, pos) <- get
         let (_, src') = B.splitAt (B.length bs) src
@@ -66,7 +66,7 @@
             out' = out <> BB.byteString bs
             pos' = pos + n
         put (src', out', pos')
-    getCursor = get >>= \(_, _, pos) -> return pos
+    getCursor = get >>= \(_, _, pos) -> pure pos
 
 instance MonadIO m => FwdInplaceStream (ReaderT IO.Handle m) where
     type Chunk (ReaderT IO.Handle m) = B.ByteString
@@ -85,14 +85,14 @@
     getCursor = do
         hdl <- ask
         pos <- liftIO $ IO.hTell hdl
-        return $ fromInteger pos
+        pure $ fromInteger pos
 
 -- TODO Need MonoTraversable to define for Text, ByteString etc easily. Bleh. I
 -- think Snoyman's advice is to reimplement. Also bleh.
 instance Monad m => FwdInplaceStream (StateT ([a], [a], Int) m) where
     type Chunk (StateT ([a], [a], Int) m) = [a]
     type Index (StateT ([a], [a], Int) m) = Int
-    readahead n = get >>= \(src, _, _) -> return $ List.take n src
+    readahead n = get >>= \(src, _, _) -> pure $ List.take n src
     overwrite bs = do
         (src, out, pos) <- get
         let (_, src') = List.splitAt (List.length bs) src
@@ -105,7 +105,7 @@
             out' = out <> bs
             pos' = pos + n
         put (src', out', pos')
-    getCursor = get >>= \(_, _, pos) -> return pos
+    getCursor = get >>= \(_, _, pos) -> pure pos
 
 -- | Streams supporting forward seeking and arbitrary edits.
 class FwdInplaceStream m => FwdStream m where
diff --git a/test/StreamPatch/ApplySpec.hs b/test/StreamPatch/ApplySpec.hs
--- a/test/StreamPatch/ApplySpec.hs
+++ b/test/StreamPatch/ApplySpec.hs
@@ -37,7 +37,7 @@
         -- why no Random Natural...
         nSkip <- choose (0, naturalToInteger n)
         gen ps (naturalFromInteger nSkip) $ n - (fromIntegral nSkip)
-    gen ps _     0 = return ps
+    gen ps _     0 = pure ps
     gen ps nSkip n = do
         a <- genBoundList n 1
         let n' = n - (fromIntegral (length a))
