diff --git a/CHANGELOG.md b/CHANGELOG.md
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,5 +1,9 @@
 # CHANGELOG for crypton
 
+## 1.0.7
++ Stop depending on basement, use upstream dependencies instead
++ Stop transitively depending on basement by depending on ram.
+
 ## 1.0.6
 
 * Fix test failures on less common 64-bit arches.
diff --git a/Crypto/Error/Types.hs b/Crypto/Error/Types.hs
--- a/Crypto/Error/Types.hs
+++ b/Crypto/Error/Types.hs
@@ -22,7 +22,6 @@
 import qualified Control.Exception as E
 import Data.Data
 
-import Basement.Monad (MonadFailure (..))
 
 -- | Enumeration of all possible errors that can be found in this library
 data CryptoError
@@ -86,10 +85,6 @@
         case m1 of
             CryptoPassed a -> m2 a
             CryptoFailed e -> CryptoFailed e
-
-instance MonadFailure CryptoFailable where
-    type Failure CryptoFailable = CryptoError
-    mFail = CryptoFailed
 
 -- | Throw an CryptoError as exception on CryptoFailed result,
 -- otherwise return the computed value
diff --git a/Crypto/Hash.hs b/Crypto/Hash.hs
--- a/Crypto/Hash.hs
+++ b/Crypto/Hash.hs
@@ -47,18 +47,14 @@
     module Crypto.Hash.Algorithms,
 ) where
 
-import Basement.Block (Block, unsafeFreeze)
-import Basement.Block.Mutable (copyFromPtr, new)
-import Basement.Types.OffsetSize (CountOf (..))
 import Crypto.Hash.Algorithms
 import Crypto.Hash.Types
-import Crypto.Internal.ByteArray (ByteArrayAccess)
+import Crypto.Internal.ByteArray (ByteArrayAccess, allocAndFreezePrim)
 import qualified Crypto.Internal.ByteArray as B
-import Crypto.Internal.Compat (unsafeDoIO)
 import qualified Data.ByteString.Lazy as L
 import Data.Int (Int32)
-import Data.Word (Word8)
-import Foreign.Ptr (Ptr, plusPtr)
+import qualified Foreign.Marshal.Utils as FMU
+import Foreign.Ptr (Ptr, castPtr, plusPtr)
 
 -- | Hash a strict bytestring into a digest.
 hash :: (ByteArrayAccess ba, HashAlgorithm a) => ba -> Digest a
@@ -117,8 +113,8 @@
      . HashAlgorithm a
     => Context a
     -> Digest a
-hashFinalize !c =
-    Digest $ B.allocAndFreeze (hashDigestSize (undefined :: a)) $ \(dig :: Ptr (Digest a)) -> do
+hashFinalize !c = Digest $ allocAndFreezePrim (hashDigestSize (undefined :: a)) $
+    \(dig :: Ptr (Digest a)) -> do
         ((!_) :: B.Bytes) <- B.copy c $ \(ctx :: Ptr (Context a)) -> hashInternalFinalize ctx dig
         return ()
 
@@ -135,8 +131,8 @@
     -> ba
     -> Int
     -> Digest a
-hashFinalizePrefix !c b len =
-    Digest $ B.allocAndFreeze (hashDigestSize (undefined :: a)) $ \(dig :: Ptr (Digest a)) -> do
+hashFinalizePrefix !c b len = Digest $ allocAndFreezePrim (hashDigestSize (undefined :: a)) $
+    \(dig :: Ptr (Digest a)) -> do
         ((!_) :: B.Bytes) <- B.copy c $ \(ctx :: Ptr (Context a)) ->
             B.withByteArray b $ \d ->
                 hashInternalFinalizePrefix
@@ -171,13 +167,9 @@
     from :: a -> ba -> Maybe (Digest a)
     from alg bs
         | B.length bs == (hashDigestSize alg) =
-            Just $ Digest $ unsafeDoIO $ copyBytes bs
+            Just $ Digest $ copyByteArray bs
         | otherwise = Nothing
 
-    copyBytes :: ba -> IO (Block Word8)
-    copyBytes ba = do
-        muArray <- new count
-        B.withByteArray ba $ \ptr -> copyFromPtr ptr muArray 0 count
-        unsafeFreeze muArray
-      where
-        count = CountOf (B.length ba)
+    copyByteArray ba = allocAndFreezePrim (B.length ba) $ \dst ->
+        B.withByteArray ba $ \src ->
+            FMU.copyBytes dst (castPtr src) (B.length ba)
diff --git a/Crypto/Hash/IO.hs b/Crypto/Hash/IO.hs
--- a/Crypto/Hash/IO.hs
+++ b/Crypto/Hash/IO.hs
@@ -20,6 +20,7 @@
 ) where
 
 import Crypto.Hash.Types
+import Crypto.Internal.ByteArray (allocAndFreezePrimIO)
 import qualified Crypto.Internal.ByteArray as B
 import Foreign.Ptr
 
@@ -66,8 +67,10 @@
 hashMutableFinalize
     :: forall a. HashAlgorithm a => MutableContext a -> IO (Digest a)
 hashMutableFinalize mc = do
-    b <- B.alloc (hashDigestSize (undefined :: a)) $ \dig -> B.withByteArray mc $ \(ctx :: Ptr (Context a)) -> hashInternalFinalize ctx dig
-    return $ Digest b
+    ba <- allocAndFreezePrimIO (hashDigestSize (undefined :: a)) $
+        \(dig :: Ptr (Digest a)) ->
+            B.withByteArray mc $ \(ctx :: Ptr (Context a)) -> hashInternalFinalize ctx dig
+    return (Digest ba)
 
 -- | Reset the mutable context to the initial state of the hash
 hashMutableReset :: HashAlgorithm a => MutableContext a -> IO ()
diff --git a/Crypto/Hash/Types.hs b/Crypto/Hash/Types.hs
--- a/Crypto/Hash/Types.hs
+++ b/Crypto/Hash/Types.hs
@@ -20,18 +20,21 @@
     Digest (..),
 ) where
 
-import Basement.Block (Block, unsafeFreeze)
-import Basement.Block.Mutable (MutableBlock, new, unsafeWrite)
-import Basement.NormalForm (deepseq)
-import Basement.Types.OffsetSize (CountOf (..), Offset (..))
+import Data.Primitive.ByteArray (ByteArray, MutableByteArray, writeByteArray, newPinnedByteArray, sizeofByteArray, unsafeFreezeByteArray, withByteArrayContents)
+import Control.Monad.Primitive (PrimMonad (..))
+import Control.DeepSeq (deepseq)
 import Control.Monad.ST
-import Crypto.Internal.ByteArray (ByteArrayAccess, Bytes)
+import Crypto.Internal.ByteArray (ByteArrayAccess (..), Bytes)
 import qualified Crypto.Internal.ByteArray as B
 import Crypto.Internal.Imports
 import Data.Char (digitToInt, isHexDigit)
 import Data.Data (Data)
-import Foreign.Ptr (Ptr)
+import Foreign.Ptr (Ptr, castPtr)
 import GHC.TypeLits (Nat)
+import Data.Base16.Types (extractBase16)
+import Data.ByteString (ByteString)
+import Data.ByteString.Base16 (encodeBase16)
+import qualified Data.Text as Text
 
 -- | Class representing hashing algorithms.
 --
@@ -104,34 +107,38 @@
 --
 -- Creating a digest from a bytearray is also possible with function
 -- 'Crypto.Hash.digestFromByteString'.
-newtype Digest a = Digest (Block Word8)
-    deriving (Eq, Ord, ByteArrayAccess, Data)
+newtype Digest a = Digest ByteArray
+    deriving (Eq, Ord, Data)
 
 type role Digest nominal
 
 instance NFData (Digest a) where
     rnf (Digest u) = u `deepseq` ()
 
+instance ByteArrayAccess (Digest a) where
+    length (Digest ba) = sizeofByteArray ba
+    withByteArray (Digest ba) f = withByteArrayContents ba (f . castPtr)
+
 instance Show (Digest a) where
-    show (Digest bs) =
-        map (toEnum . fromIntegral) $
-            B.unpack (B.convertToBase B.Base16 bs :: Bytes)
+    show d =
+            Text.unpack (extractBase16 $ encodeBase16 (B.convert d :: ByteString))
 
 instance HashAlgorithm a => Read (Digest a) where
     readsPrec _ str = runST $ do
-        mut <- new (CountOf len)
-        loop mut len str
+        mut <- newPinnedByteArray len
+        loop len mut len str
       where
         len = hashDigestSize (undefined :: a)
 
-        loop :: MutableBlock Word8 s -> Int -> String -> ST s [(Digest a, String)]
-        loop mut 0 cs = (\b -> [(Digest b, cs)]) <$> unsafeFreeze mut
-        loop _ _ [] = return []
-        loop _ _ [_] = return []
-        loop mut n (c : (d : ds))
+loop :: Int -> MutableByteArray (PrimState (ST s)) -> Int -> String -> ST s [(Digest a, String)]
+loop _ mut 0 cs = (\b -> [(Digest b, cs)]) <$> unsafeFreezeByteArray mut
+loop _ _ _ [] = return []
+loop _ _ _ [_] = return []
+loop len mut n (c : (d : ds))
             | not (isHexDigit c) = return []
             | not (isHexDigit d) = return []
             | otherwise = do
-                let w8 = fromIntegral $ digitToInt c * 16 + digitToInt d
-                unsafeWrite mut (Offset $ len - n) w8
-                loop mut (n - 1) ds
+                let  w8 :: Word8
+                     w8 = fromIntegral $ digitToInt c * 16 + digitToInt d
+                writeByteArray mut (len - n) w8
+                loop len mut (n - 1) ds
diff --git a/Crypto/Internal/ByteArray.hs b/Crypto/Internal/ByteArray.hs
--- a/Crypto/Internal/ByteArray.hs
+++ b/Crypto/Internal/ByteArray.hs
@@ -14,6 +14,8 @@
     module Data.ByteArray.Mapping,
     module Data.ByteArray.Encoding,
     constAllZero,
+    allocAndFreezePrimIO,
+    allocAndFreezePrim,
 ) where
 
 import Data.ByteArray
@@ -22,10 +24,25 @@
 
 import Data.Bits ((.|.))
 import Data.Word (Word8)
-import Foreign.Ptr (Ptr)
+import Foreign.Ptr (Ptr, castPtr)
 import Foreign.Storable (peekByteOff)
+import qualified Data.Primitive.ByteArray as Prim
 
 import Crypto.Internal.Compat (unsafeDoIO)
+
+-- | Allocate a pinned 'Prim.ByteArray' of the given size, populate it via a
+-- 'Ptr', then freeze and return it.  The pointer must not be retained after
+-- the action returns.
+allocAndFreezePrimIO :: Int -> (Ptr p -> IO ()) -> IO Prim.ByteArray
+allocAndFreezePrimIO n f = do
+    mba <- Prim.newPinnedByteArray n
+    f (castPtr (Prim.mutableByteArrayContents mba))
+    Prim.unsafeFreezeByteArray mba
+
+-- | The allocation is strictly local,
+-- the computation is deterministic, and no IO effects escape.
+allocAndFreezePrim :: Int -> (Ptr p -> IO ()) -> Prim.ByteArray
+allocAndFreezePrim n = unsafeDoIO . allocAndFreezePrimIO n
 
 constAllZero :: ByteArrayAccess ba => ba -> Bool
 constAllZero b = unsafeDoIO $ withByteArray b $ \p -> loop p 0 0
diff --git a/Crypto/KDF/BCryptPBKDF.hs b/Crypto/KDF/BCryptPBKDF.hs
--- a/Crypto/KDF/BCryptPBKDF.hs
+++ b/Crypto/KDF/BCryptPBKDF.hs
@@ -13,11 +13,6 @@
 )
 where
 
-import Basement.Block (MutableBlock)
-import qualified Basement.Block as Block
-import qualified Basement.Block.Mutable as Block
-import Basement.Monad (PrimState)
-import Basement.Types.OffsetSize (CountOf (..), Offset (..))
 import Control.Exception (finally)
 import Control.Monad (when)
 import qualified Crypto.Cipher.Blowfish.Box as Blowfish
@@ -34,9 +29,11 @@
 import Crypto.Internal.Compat (unsafeDoIO)
 import Data.Bits
 import qualified Data.ByteArray as B
+import qualified Data.ByteString.Internal as BSI
 import Data.Foldable (forM_)
 import Data.Memory.PtrMethods (memCopy, memSet, memXor)
 import Data.Word
+import Foreign.ForeignPtr (ForeignPtr, mallocForeignPtrBytes, withForeignPtr)
 import Foreign.Ptr (Ptr, castPtr)
 import Foreign.Storable (peekByteOff, pokeByteOff)
 
@@ -76,70 +73,70 @@
 
     deriveKey :: Ptr Word8 -> IO ()
     deriveKey keyPtr = do
-        -- Allocate all necessary memory. The algorihm shall not allocate
-        -- any more dynamic memory after this point. Blocks need to be pinned
-        -- as pointers to them are passed to the SHA512 implementation.
-        ksClean <- Blowfish.createKeySchedule
-        ksDirty <- Blowfish.createKeySchedule
-        ctxMBlock <- Block.newPinned (CountOf ctxLen :: CountOf Word8)
-        outMBlock <- Block.newPinned (CountOf outLen :: CountOf Word8)
-        tmpMBlock <- Block.newPinned (CountOf tmpLen :: CountOf Word8)
-        blkMBlock <- Block.newPinned (CountOf blkLen :: CountOf Word8)
-        passHashMBlock <- Block.newPinned (CountOf hashLen :: CountOf Word8)
-        saltHashMBlock <- Block.newPinned (CountOf hashLen :: CountOf Word8)
+        -- Allocate all necessary memory. The algorithm shall not allocate
+        -- any more dynamic memory after this point. ForeignPtrs allocate
+        -- pinned memory, so raw pointers to them are stable.
+        ksClean      <- Blowfish.createKeySchedule
+        ksDirty      <- Blowfish.createKeySchedule
+        ctxFP        <- mallocForeignPtrBytes ctxLen  :: IO (ForeignPtr Word8)
+        outFP        <- mallocForeignPtrBytes outLen  :: IO (ForeignPtr Word8)
+        tmpFP        <- mallocForeignPtrBytes tmpLen  :: IO (ForeignPtr Word8)
+        blkFP        <- mallocForeignPtrBytes blkLen  :: IO (ForeignPtr Word8)
+        passHashFP   <- mallocForeignPtrBytes hashLen :: IO (ForeignPtr Word8)
+        saltHashFP   <- mallocForeignPtrBytes hashLen :: IO (ForeignPtr Word8)
         -- Finally erase all memory areas that contain information from
         -- which the derived key could be reconstructed.
-        -- As all MutableBlocks are pinned it shall be guaranteed that
-        -- no temporary trampoline buffers are allocated.
-        finallyErase outMBlock $
-            finallyErase passHashMBlock $
+        finallyErase outFP outLen $
+            finallyErase passHashFP hashLen $
                 B.withByteArray pass $ \passPtr ->
                     B.withByteArray salt $ \saltPtr ->
-                        Block.withMutablePtr ctxMBlock $ \ctxPtr ->
-                            Block.withMutablePtr outMBlock $ \outPtr ->
-                                Block.withMutablePtr tmpMBlock $ \tmpPtr ->
-                                    Block.withMutablePtr blkMBlock $ \blkPtr ->
-                                        Block.withMutablePtr passHashMBlock $ \passHashPtr ->
-                                            Block.withMutablePtr saltHashMBlock $ \saltHashPtr -> do
-                                                -- Hash the password.
-                                                let shaPtr = castPtr ctxPtr :: Ptr (Context SHA512)
-                                                hashInternalInit shaPtr
-                                                hashInternalUpdate shaPtr passPtr (fromIntegral passLen)
-                                                hashInternalFinalize shaPtr (castPtr passHashPtr)
-                                                passHashBlock <- Block.unsafeFreeze passHashMBlock
-                                                forM_ [1 .. blocks] $ \block -> do
-                                                    -- Poke the increased block counter.
-                                                    Block.unsafeWrite blkMBlock 0 (fromIntegral $ block `shiftR` 24)
-                                                    Block.unsafeWrite blkMBlock 1 (fromIntegral $ block `shiftR` 16)
-                                                    Block.unsafeWrite blkMBlock 2 (fromIntegral $ block `shiftR` 8)
-                                                    Block.unsafeWrite blkMBlock 3 (fromIntegral $ block `shiftR` 0)
-                                                    -- First round (slightly different).
-                                                    hashInternalInit shaPtr
-                                                    hashInternalUpdate shaPtr saltPtr (fromIntegral saltLen)
-                                                    hashInternalUpdate shaPtr blkPtr (fromIntegral blkLen)
-                                                    hashInternalFinalize shaPtr (castPtr saltHashPtr)
-                                                    Block.unsafeFreeze saltHashMBlock >>= \x -> do
-                                                        Blowfish.copyKeySchedule ksDirty ksClean
-                                                        hashInternalMutable ksDirty passHashBlock x tmpMBlock
-                                                    memCopy outPtr tmpPtr outLen
-                                                    -- Remaining rounds.
-                                                    forM_ [2 .. iterCounts params] $ const $ do
-                                                        hashInternalInit shaPtr
-                                                        hashInternalUpdate shaPtr tmpPtr (fromIntegral tmpLen)
-                                                        hashInternalFinalize shaPtr (castPtr saltHashPtr)
-                                                        Block.unsafeFreeze saltHashMBlock >>= \x -> do
-                                                            Blowfish.copyKeySchedule ksDirty ksClean
-                                                            hashInternalMutable ksDirty passHashBlock x tmpMBlock
-                                                        memXor outPtr outPtr tmpPtr outLen
-                                                    -- Spread the current out buffer evenly over the key buffer.
-                                                    -- After both loops have run every byte of the key buffer
-                                                    -- will have been written to exactly once and every byte
-                                                    -- of the output will have been used.
-                                                    forM_ [0 .. outLen - 1] $ \outIdx -> do
-                                                        let keyIdx = outIdx * blocks + block - 1
-                                                        when (keyIdx < keyLen) $ do
-                                                            w8 <- peekByteOff outPtr outIdx :: IO Word8
-                                                            pokeByteOff keyPtr keyIdx w8
+                        withForeignPtr ctxFP      $ \ctxPtr'     ->
+                        withForeignPtr outFP      $ \outPtr      ->
+                        withForeignPtr tmpFP      $ \tmpPtr      ->
+                        withForeignPtr blkFP      $ \blkPtr      ->
+                        withForeignPtr passHashFP $ \passHashPtr ->
+                        withForeignPtr saltHashFP $ \saltHashPtr -> do
+                            -- Hash the password.
+                            let shaPtr = castPtr ctxPtr' :: Ptr (Context SHA512)
+                            hashInternalInit shaPtr
+                            hashInternalUpdate shaPtr passPtr (fromIntegral passLen)
+                            hashInternalFinalize shaPtr (castPtr passHashPtr)
+                            -- Create a stable ByteString view of the password hash
+                            -- (passHashFP is not modified after this point).
+                            let passHashBS = BSI.fromForeignPtr passHashFP 0 hashLen
+                            forM_ [1 .. blocks] $ \block -> do
+                                -- Poke the increased block counter.
+                                pokeByteOff blkPtr 0 (fromIntegral (block `shiftR` 24) :: Word8)
+                                pokeByteOff blkPtr 1 (fromIntegral (block `shiftR` 16) :: Word8)
+                                pokeByteOff blkPtr 2 (fromIntegral (block `shiftR` 8) :: Word8)
+                                pokeByteOff blkPtr 3 (fromIntegral (block `shiftR` 0 :: Int) :: Word8)
+                                -- First round (slightly different).
+                                hashInternalInit shaPtr
+                                hashInternalUpdate shaPtr saltPtr (fromIntegral saltLen)
+                                hashInternalUpdate shaPtr blkPtr (fromIntegral blkLen)
+                                hashInternalFinalize shaPtr (castPtr saltHashPtr)
+                                let saltHashBS = BSI.fromForeignPtr saltHashFP 0 hashLen
+                                Blowfish.copyKeySchedule ksDirty ksClean
+                                hashInternalMutable ksDirty passHashBS saltHashBS tmpPtr
+                                memCopy outPtr tmpPtr outLen
+                                -- Remaining rounds.
+                                forM_ [2 .. iterCounts params] $ const $ do
+                                    hashInternalInit shaPtr
+                                    hashInternalUpdate shaPtr tmpPtr (fromIntegral tmpLen)
+                                    hashInternalFinalize shaPtr (castPtr saltHashPtr)
+                                    let saltHashBS2 = BSI.fromForeignPtr saltHashFP 0 hashLen
+                                    Blowfish.copyKeySchedule ksDirty ksClean
+                                    hashInternalMutable ksDirty passHashBS saltHashBS2 tmpPtr
+                                    memXor outPtr outPtr tmpPtr outLen
+                                -- Spread the current out buffer evenly over the key buffer.
+                                -- After both loops have run every byte of the key buffer
+                                -- will have been written to exactly once and every byte
+                                -- of the output will have been used.
+                                forM_ [0 .. outLen - 1] $ \outIdx -> do
+                                    let keyIdx = outIdx * blocks + block - 1
+                                    when (keyIdx < keyLen) $ do
+                                        w8 <- peekByteOff outPtr outIdx :: IO Word8
+                                        pokeByteOff keyPtr keyIdx w8
 
 -- | Internal hash function used by `generate`.
 --
@@ -154,18 +151,16 @@
     | B.length saltHash /= 64 = error "saltHash must be 512 bits"
     | otherwise = unsafeDoIO $ do
         ks0 <- Blowfish.createKeySchedule
-        outMBlock <- Block.newPinned 32
-        hashInternalMutable ks0 passHash saltHash outMBlock
-        B.convert `fmap` Block.freeze outMBlock
+        B.alloc 32 $ \outPtr -> hashInternalMutable ks0 passHash saltHash outPtr
 
 hashInternalMutable
     :: (B.ByteArrayAccess pass, B.ByteArrayAccess salt)
     => Blowfish.KeySchedule
     -> pass
     -> salt
-    -> MutableBlock Word8 (PrimState IO)
+    -> Ptr Word8
     -> IO ()
-hashInternalMutable bfks passHash saltHash outMBlock = do
+hashInternalMutable bfks passHash saltHash outPtr = do
     Blowfish.expandKeyWithSalt bfks passHash saltHash
     forM_ [0 .. 63 :: Int] $ const $ do
         Blowfish.expandKey bfks saltHash
@@ -176,22 +171,20 @@
     store 16 =<< cipher 64 0x6669736853776174
     store 24 =<< cipher 64 0x44796e616d697465
   where
-    store :: Offset Word8 -> Word64 -> IO ()
+    store :: Int -> Word64 -> IO ()
     store o w64 = do
-        Block.unsafeWrite outMBlock (o + 0) (fromIntegral $ w64 `shiftR` 32)
-        Block.unsafeWrite outMBlock (o + 1) (fromIntegral $ w64 `shiftR` 40)
-        Block.unsafeWrite outMBlock (o + 2) (fromIntegral $ w64 `shiftR` 48)
-        Block.unsafeWrite outMBlock (o + 3) (fromIntegral $ w64 `shiftR` 56)
-        Block.unsafeWrite outMBlock (o + 4) (fromIntegral $ w64 `shiftR` 0)
-        Block.unsafeWrite outMBlock (o + 5) (fromIntegral $ w64 `shiftR` 8)
-        Block.unsafeWrite outMBlock (o + 6) (fromIntegral $ w64 `shiftR` 16)
-        Block.unsafeWrite outMBlock (o + 7) (fromIntegral $ w64 `shiftR` 24)
+        pokeByteOff outPtr (o + 0) (fromIntegral (w64 `shiftR` 32) :: Word8)
+        pokeByteOff outPtr (o + 1) (fromIntegral (w64 `shiftR` 40) :: Word8)
+        pokeByteOff outPtr (o + 2) (fromIntegral (w64 `shiftR` 48) :: Word8)
+        pokeByteOff outPtr (o + 3) (fromIntegral (w64 `shiftR` 56) :: Word8)
+        pokeByteOff outPtr (o + 4) (fromIntegral (w64 `shiftR` 0)  :: Word8)
+        pokeByteOff outPtr (o + 5) (fromIntegral (w64 `shiftR` 8)  :: Word8)
+        pokeByteOff outPtr (o + 6) (fromIntegral (w64 `shiftR` 16) :: Word8)
+        pokeByteOff outPtr (o + 7) (fromIntegral (w64 `shiftR` 24) :: Word8)
     cipher :: Int -> Word64 -> IO Word64
     cipher 0 block = return block
     cipher i block = Blowfish.cipherBlockMutable bfks block >>= cipher (i - 1)
 
-finallyErase :: MutableBlock Word8 (PrimState IO) -> IO () -> IO ()
-finallyErase mblock action =
-    action `finally` Block.withMutablePtr mblock (\ptr -> memSet ptr 0 len)
-  where
-    CountOf len = Block.mutableLengthBytes mblock
+finallyErase :: ForeignPtr Word8 -> Int -> IO () -> IO ()
+finallyErase fp len action =
+    action `finally` withForeignPtr fp (\ptr -> memSet ptr 0 len)
diff --git a/Crypto/MAC/KMAC.hs b/Crypto/MAC/KMAC.hs
--- a/Crypto/MAC/KMAC.hs
+++ b/Crypto/MAC/KMAC.hs
@@ -29,6 +29,7 @@
 import Crypto.Hash.Types (Digest (..), HashAlgorithm (..))
 import qualified Crypto.Hash.Types as H
 import Crypto.Internal.Builder
+import Crypto.Internal.ByteArray (allocAndFreezePrim)
 import Crypto.Internal.Imports
 import Data.Bits (shiftR)
 import Data.ByteArray (ByteArrayAccess)
@@ -69,8 +70,8 @@
     :: forall a suffix
      . (HashSHAKE a, ByteArrayAccess suffix)
     => H.Context a -> suffix -> Digest a
-cshakeFinalize !c s =
-    Digest $ B.allocAndFreeze (hashDigestSize (undefined :: a)) $ \dig -> do
+cshakeFinalize !c s = Digest $ allocAndFreezePrim (hashDigestSize (undefined :: a)) $
+    \(dig :: Ptr (Digest a)) -> do
         ((!_) :: B.Bytes) <- B.copy c $ \(ctx :: Ptr (H.Context a)) -> do
             B.withByteArray s $ \d ->
                 hashInternalUpdate ctx d (fromIntegral $ B.length s)
diff --git a/Crypto/PubKey/ECDSA.hs b/Crypto/PubKey/ECDSA.hs
--- a/Crypto/PubKey/ECDSA.hs
+++ b/Crypto/PubKey/ECDSA.hs
@@ -261,8 +261,9 @@
 tHashDigest
     :: (EllipticCurveECDSA curve, HashAlgorithm hash)
     => proxy curve -> Digest hash -> Scalar curve
-tHashDigest prx (Digest digest) = throwCryptoError $ decodeScalar prx encoded
+tHashDigest prx dig = throwCryptoError $ decodeScalar prx encoded
   where
+    digest = B.convert dig :: B.Bytes
     m = curveOrderBits prx
     d = m - B.length digest * 8
     (n, r) = m `divMod` 8
diff --git a/crypton.cabal b/crypton.cabal
--- a/crypton.cabal
+++ b/crypton.cabal
@@ -1,13 +1,13 @@
 cabal-version:      1.18
 name:               crypton
-version:            1.0.6
+version:            1.1.0
 license:            BSD3
 license-file:       LICENSE
 copyright:          Vincent Hanquez <vincent@snarc.org>
 maintainer:         Kazu Yamamoto <kazu@iij.ad.jp>
 author:             Vincent Hanquez <vincent@snarc.org>
 stability:          experimental
-tested-with:        GHC ==8.8.4 || ==8.10.7 || ==9.0.2 || ==9.2.2
+tested-with:        GHC ==9.2.8 || ==9.4.8 || ==9.6.7 || ==9.8.4 || ==9.10.1 || ==9.12.1
 homepage:           https://github.com/kazu-yamamoto/crypton
 bug-reports:        https://github.com/kazu-yamamoto/crypton/issues
 synopsis:           Cryptography Primitives sink
@@ -303,9 +303,13 @@
     ghc-options:      -Wall -fwarn-tabs -optc-O3
     build-depends:
           base        >=4.13    && <5
-        , basement    >=0.0.6
         , bytestring
-        , memory      >=0.14.18
+        , primitive   >=0.9
+        , deepseq
+        , base16      >=1.0
+        , bytestring
+        , text
+        , ram >=0.20.1 && < 0.22
 
     if flag(old_toolchain_inliner)
         cc-options: -fgnu89-inline
@@ -502,7 +506,7 @@
           base              >=4.13 && <5
         , bytestring
         , crypton
-        , memory
+        , ram
         , tasty
         , tasty-hunit
         , tasty-kat
@@ -521,7 +525,7 @@
         , crypton
         , deepseq
         , gauge
-        , memory
+        , ram
         , random
 
 -- cabal-fmt: indent 4
