diff --git a/saltine.cabal b/saltine.cabal
--- a/saltine.cabal
+++ b/saltine.cabal
@@ -1,6 +1,6 @@
 name:                saltine
-version:             0.0.0.1
-synopsis:            A Haskell libsodium binding
+version:             0.0.0.2
+synopsis:            Cryptography that's easy to digest (NaCl/libsodium bindings).
 description:
 
   /NaCl/ (pronounced \"salt\") is a new easy-to-use high-speed software
@@ -55,7 +55,7 @@
   default-language:   Haskell2010
   build-depends:       
     base >= 4.5 && < 4.7,
-    vector,
+    bytestring,
     profunctors
     
 test-suite tests
diff --git a/src/Crypto/Saltine/Class.hs b/src/Crypto/Saltine/Class.hs
--- a/src/Crypto/Saltine/Class.hs
+++ b/src/Crypto/Saltine/Class.hs
@@ -14,8 +14,8 @@
   ) where
 
 import Data.Profunctor
-import Data.Word
-import qualified Data.Vector.Storable as V
+import qualified Data.ByteString as S
+import           Data.ByteString (ByteString)
 import Control.Applicative
 
 -- | Class for all keys and nonces in Saltine which have a
@@ -23,10 +23,10 @@
 -- type @Prism' (V.Vector Word8) a@ compatible with "Control.Lens" and
 -- is automatically deduced.
 class IsEncoding a where
-  encode  :: a -> V.Vector Word8
-  decode  :: V.Vector Word8 -> Maybe a
+  encode  :: a -> ByteString
+  decode  :: ByteString -> Maybe a
   encoded :: (Choice p, Applicative f)
-             => p a (f a) -> p (V.Vector Word8) (f (V.Vector Word8))
+             => p a (f a) -> p ByteString (f ByteString)
   encoded = prism' encode decode
   {-# INLINE encoded #-}
 
diff --git a/src/Crypto/Saltine/Core/Auth.hs b/src/Crypto/Saltine/Core/Auth.hs
--- a/src/Crypto/Saltine/Core/Auth.hs
+++ b/src/Crypto/Saltine/Core/Auth.hs
@@ -10,7 +10,7 @@
 -- Secret-key message authentication: 
 -- "Crypto.Saltine.Core.Auth"
 -- 
--- The 'auth' function authenticates a message 'V.Vector' using a
+-- The 'auth' function authenticates a message 'ByteString' using a
 -- secret key The function returns an authenticator. The 'verify'
 -- function checks if it's passed a correct authenticator of a message
 -- under the given secret key.
@@ -49,21 +49,21 @@
 
 import Foreign.C
 import Foreign.Ptr
-import Data.Word
-import qualified Data.Vector.Storable as V
+import qualified Data.ByteString as S
+import           Data.ByteString (ByteString)
 
 import Control.Applicative
 
 -- $types
 
 -- | An opaque 'auth' cryptographic key.
-newtype Key = Key (V.Vector Word8) deriving (Eq, Ord)
+newtype Key = Key ByteString deriving (Eq, Ord)
 
 -- | An opaque 'auth' authenticator.
-newtype Authenticator = Au (V.Vector Word8) deriving (Eq, Ord)
+newtype Authenticator = Au ByteString deriving (Eq, Ord)
 
 instance IsEncoding Key where
-  decode v = case V.length v == Bytes.authKey of
+  decode v = case S.length v == Bytes.authKey of
     True -> Just (Key v)
     False -> Nothing
   {-# INLINE decode #-}
@@ -71,7 +71,7 @@
   {-# INLINE encode #-}
 
 instance IsEncoding Authenticator where
-  decode v = case V.length v == Bytes.auth of
+  decode v = case S.length v == Bytes.auth of
     True -> Just (Au v)
     False -> Nothing
   {-# INLINE decode #-}
@@ -82,39 +82,39 @@
 newKey :: IO Key
 newKey = Key <$> randomVector Bytes.authKey
 
--- | Computes an keyed authenticator 'V.Vector' from a message. It is
--- infeasible to forge these authenticators without the key, even if
--- an attacker observes many authenticators and messages and has the
--- ability to influence the messages sent.
+-- | Computes an keyed authenticator 'ByteString' from a message. It
+-- is infeasible to forge these authenticators without the key, even
+-- if an attacker observes many authenticators and messages and has
+-- the ability to influence the messages sent.
 auth :: Key 
-        -> V.Vector Word8
+        -> ByteString
         -- ^ Message
         -> Authenticator
 auth (Key key) msg =
   Au . snd . buildUnsafeCVector Bytes.auth $ \pa ->
-    constVectors [key, msg] $ \[pk, pm] ->
-    c_auth pa pm (fromIntegral $ V.length msg) pk
+    constVectors [key, msg] $ \[(pk, _), (pm, mlen)] ->
+    c_auth pa pm (fromIntegral mlen) pk
 
 -- | Checks to see if an authenticator is a correct proof that a
 -- message was signed by some key.
 verify :: Key
           -> Authenticator
-          -> V.Vector Word8
+          -> ByteString
           -- ^ Message
           -> Bool
           -- ^ Is this message authentic?
 verify (Key key) (Au a) msg =
-  unsafeDidSucceed $ constVectors [key, msg, a] $ \[pk, pm, pa] ->
-  return $ c_auth_verify pa pm (fromIntegral $ V.length msg) pk
+  unsafeDidSucceed $ constVectors [key, msg, a] $ \[(pk, _), (pm, mlen), (pa, _)] ->
+  return $ c_auth_verify pa pm (fromIntegral mlen) pk
 
 foreign import ccall "crypto_auth"
-  c_auth :: Ptr Word8
+  c_auth :: Ptr CChar
             -- ^ Authenticator output buffer
-            -> Ptr Word8
+            -> Ptr CChar
             -- ^ Constant message buffer
             -> CULLong
             -- ^ Length of message buffer
-            -> Ptr Word8
+            -> Ptr CChar
             -- ^ Constant key buffer
             -> IO CInt
             -- ^ Always 0
@@ -122,13 +122,13 @@
 -- | We don't even include this in the IO monad since all of the
 -- buffers are constant.
 foreign import ccall "crypto_auth_verify"
-  c_auth_verify :: Ptr Word8
+  c_auth_verify :: Ptr CChar
                    -- ^ Constant authenticator buffer
-                   -> Ptr Word8
+                   -> Ptr CChar
                    -- ^ Constant message buffer
                    -> CULLong
                    -- ^ Length of message buffer
-                   -> Ptr Word8
+                   -> Ptr CChar
                    -- ^ Constant key buffer
                    -> CInt
                    -- ^ Success if 0, failure if -1
diff --git a/src/Crypto/Saltine/Core/Box.hs b/src/Crypto/Saltine/Core/Box.hs
--- a/src/Crypto/Saltine/Core/Box.hs
+++ b/src/Crypto/Saltine/Core/Box.hs
@@ -10,12 +10,12 @@
 -- Public-key authenticated encryption:
 -- "Crypto.Saltine.Core.Box"
 -- 
--- The 'box' function encrypts and authenticates a message 'V.Vector'
--- using the sender's secret key, the receiver's public key, and a
--- nonce. The 'boxOpen' function verifies and decrypts a ciphertext
--- 'V.Vector' using the receiver's secret key, the sender's public
--- key, and a nonce. If the ciphertext fails verification, 'boxOpen'
--- returns 'Nothing'.
+-- The 'box' function encrypts and authenticates a message
+-- 'ByteString' using the sender's secret key, the receiver's public
+-- key, and a nonce. The 'boxOpen' function verifies and decrypts a
+-- ciphertext 'ByteString' using the receiver's secret key, the
+-- sender's public key, and a nonce. If the ciphertext fails
+-- verification, 'boxOpen' returns 'Nothing'.
 -- 
 -- The "Crypto.Saltine.Core.Box" module is designed to meet the
 -- standard notions of privacy and third-party unforgeability for a
@@ -77,18 +77,18 @@
 
 import Foreign.C
 import Foreign.Ptr
-import Data.Word
-import qualified Data.Vector.Storable as V
+import qualified Data.ByteString as S
+import           Data.ByteString (ByteString)
 
 import Control.Applicative
 
 -- $types
 
 -- | An opaque 'box' cryptographic secret key.
-newtype SecretKey = SK (V.Vector Word8) deriving (Eq, Ord)
+newtype SecretKey = SK ByteString deriving (Eq, Ord)
 
 instance IsEncoding SecretKey where
-  decode v = case V.length v == Bytes.boxSK of
+  decode v = case S.length v == Bytes.boxSK of
     True -> Just (SK v)
     False -> Nothing
   {-# INLINE decode #-}
@@ -96,10 +96,10 @@
   {-# INLINE encode #-}
 
 -- | An opaque 'box' cryptographic public key.
-newtype PublicKey = PK (V.Vector Word8) deriving (Eq, Ord)
+newtype PublicKey = PK ByteString deriving (Eq, Ord)
 
 instance IsEncoding PublicKey where
-  decode v = case V.length v == Bytes.boxPK of
+  decode v = case S.length v == Bytes.boxPK of
     True -> Just (PK v)
     False -> Nothing
   {-# INLINE decode #-}
@@ -110,10 +110,10 @@
 type Keypair = (SecretKey, PublicKey)
 
 -- | An opaque 'boxAfterNM' cryptographic combined key.
-newtype CombinedKey = CK (V.Vector Word8) deriving (Eq, Ord)
+newtype CombinedKey = CK ByteString deriving (Eq, Ord)
 
 instance IsEncoding CombinedKey where
-  decode v = case V.length v == Bytes.boxBeforeNM of
+  decode v = case S.length v == Bytes.boxBeforeNM of
     True -> Just (CK v)
     False -> Nothing
   {-# INLINE decode #-}
@@ -121,10 +121,10 @@
   {-# INLINE encode #-}
 
 -- | An opaque 'box' nonce.
-newtype Nonce = Nonce (V.Vector Word8) deriving (Eq, Ord)
+newtype Nonce = Nonce ByteString deriving (Eq, Ord)
 
 instance IsEncoding Nonce where
-  decode v = case V.length v == Bytes.boxNonce of
+  decode v = case S.length v == Bytes.boxNonce of
     True -> Just (Nonce v)
     False -> Nothing
   {-# INLINE decode #-}
@@ -132,8 +132,8 @@
   {-# INLINE encode #-}
 
 instance IsNonce Nonce where
-  zero = Nonce (V.replicate Bytes.boxNonce 0)
-  nudge (Nonce n) = Nonce (nudgeVector n)
+  zero = Nonce (S.replicate Bytes.boxNonce 0)
+  nudge (Nonce n) = Nonce (nudgeBS n)
 
 -- | Randomly generates a secret key and a corresponding public key.
 newKeypair :: IO Keypair
@@ -154,7 +154,7 @@
 -- later encryption calls.
 beforeNM :: SecretKey -> PublicKey -> CombinedKey
 beforeNM (SK sk) (PK pk) = CK $ snd $ buildUnsafeCVector Bytes.boxBeforeNM $ \ckbuf ->
-  constVectors [pk, sk] $ \[ppk, psk] ->
+  constVectors [pk, sk] $ \[(ppk, _), (psk, _)] ->
   c_box_beforenm ckbuf ppk psk
 
 -- | Encrypts a message for sending to the owner of the public
@@ -162,15 +162,16 @@
 -- message. It is infeasible for an attacker to decrypt the message so
 -- long as the 'Nonce' is not repeated.
 box :: PublicKey -> SecretKey -> Nonce
-       -> V.Vector Word8
+       -> ByteString
        -- ^ Message
-       -> V.Vector Word8
+       -> ByteString
        -- ^ Ciphertext
 box (PK pk) (SK sk) (Nonce nonce) msg =
   unpad' . snd . buildUnsafeCVector len $ \pc ->
-    constVectors [pk, sk, pad' msg, nonce] $ \[ppk, psk, pm, pn] ->
-    c_box pc pm (fromIntegral len) pn ppk psk
-  where len    = V.length msg + Bytes.boxZero
+    constVectors [pk, sk, pad' msg, nonce] $ \
+      [(ppk, _), (psk, _), (pm, _), (pn, _)] ->
+      c_box pc pm (fromIntegral len) pn ppk psk
+  where len    = S.length msg + Bytes.boxZero
         pad'   = pad Bytes.boxZero
         unpad' = unpad Bytes.boxBoxZero
 
@@ -178,129 +179,132 @@
 -- must have encrypted it using your secret key. Returns 'Nothing' if
 -- the keys and message do not match.
 boxOpen :: PublicKey -> SecretKey -> Nonce
-           -> V.Vector Word8
+           -> ByteString
            -- ^ Ciphertext
-           -> Maybe (V.Vector Word8)
+           -> Maybe ByteString
            -- ^ Message
 boxOpen (PK pk) (SK sk) (Nonce nonce) cipher =
   let (err, vec) = buildUnsafeCVector len $ \pm ->
-        constVectors [pk, sk, pad' cipher, nonce] $ \[ppk, psk, pc, pn] ->
-        c_box_open pm pc (fromIntegral len) pn ppk psk
+        constVectors [pk, sk, pad' cipher, nonce] $ \
+          [(ppk, _), (psk, _), (pc, _), (pn, _)] ->
+          c_box_open pm pc (fromIntegral len) pn ppk psk
   in hush . handleErrno err $ unpad' vec
-  where len    = V.length cipher + Bytes.boxBoxZero
+  where len    = S.length cipher + Bytes.boxBoxZero
         pad'   = pad Bytes.boxBoxZero
         unpad' = unpad Bytes.boxZero
 
 -- | 'box' using a 'CombinedKey' and is thus faster.
 boxAfterNM :: CombinedKey -> Nonce
-              -> V.Vector Word8
+              -> ByteString
               -- ^ Message
-              -> V.Vector Word8
+              -> ByteString
               -- ^ Ciphertext
 boxAfterNM (CK ck) (Nonce nonce) msg =
   unpad' . snd . buildUnsafeCVector len $ \pc ->
-    constVectors [ck, pad' msg, nonce] $ \[pck, pm, pn] ->
-    c_box_afternm pc pm (fromIntegral len) pn pck
-  where len    = V.length msg + Bytes.boxZero
+    constVectors [ck, pad' msg, nonce] $ \
+      [(pck, _), (pm, _), (pn, _)] ->
+      c_box_afternm pc pm (fromIntegral len) pn pck
+  where len    = S.length msg + Bytes.boxZero
         pad'   = pad Bytes.boxZero
         unpad' = unpad Bytes.boxBoxZero
 
 -- | 'boxOpen' using a 'CombinedKey' and is thus faster.
 boxOpenAfterNM :: CombinedKey -> Nonce
-           -> V.Vector Word8
+           -> ByteString
            -- ^ Ciphertext
-           -> Maybe (V.Vector Word8)
+           -> Maybe ByteString
            -- ^ Message
 boxOpenAfterNM (CK ck) (Nonce nonce) cipher =
   let (err, vec) = buildUnsafeCVector len $ \pm ->
-        constVectors [ck, pad' cipher, nonce] $ \[pck, pc, pn] ->
-        c_box_open_afternm pm pc (fromIntegral len) pn pck
+        constVectors [ck, pad' cipher, nonce] $ \
+          [(pck, _), (pc, _), (pn, _)] ->
+          c_box_open_afternm pm pc (fromIntegral len) pn pck
   in hush . handleErrno err $ unpad' vec
-  where len    = V.length cipher + Bytes.boxBoxZero
+  where len    = S.length cipher + Bytes.boxBoxZero
         pad'   = pad Bytes.boxBoxZero
         unpad' = unpad Bytes.boxZero
 
 
 -- | Should always return a 0.
 foreign import ccall "crypto_box_keypair"
-  c_box_keypair :: Ptr Word8
+  c_box_keypair :: Ptr CChar
                    -- ^ Public key
-                   -> Ptr Word8
+                   -> Ptr CChar
                    -- ^ Secret key
                    -> IO CInt
                    -- ^ Always 0
 
 -- | The secretbox C API uses 0-padded C strings.
 foreign import ccall "crypto_box"
-  c_box :: Ptr Word8
+  c_box :: Ptr CChar
            -- ^ Cipher 0-padded output buffer
-           -> Ptr Word8
+           -> Ptr CChar
            -- ^ Constant 0-padded message input buffer
            -> CULLong
            -- ^ Length of message input buffer (incl. 0s)
-           -> Ptr Word8
+           -> Ptr CChar
            -- ^ Constant nonce buffer
-           -> Ptr Word8
+           -> Ptr CChar
            -- ^ Constant public key buffer
-           -> Ptr Word8
+           -> Ptr CChar
            -- ^ Constant secret key buffer
            -> IO CInt
            -- ^ Always 0
 
 -- | The secretbox C API uses 0-padded C strings.
 foreign import ccall "crypto_box_open"
-  c_box_open :: Ptr Word8
+  c_box_open :: Ptr CChar
                 -- ^ Message 0-padded output buffer
-                -> Ptr Word8
+                -> Ptr CChar
                 -- ^ Constant 0-padded ciphertext input buffer
                 -> CULLong
                 -- ^ Length of message input buffer (incl. 0s)
-                -> Ptr Word8
+                -> Ptr CChar
                 -- ^ Constant nonce buffer
-                -> Ptr Word8
+                -> Ptr CChar
                 -- ^ Constant public key buffer
-                -> Ptr Word8
+                -> Ptr CChar
                 -- ^ Constant secret key buffer
                 -> IO CInt
                 -- ^ 0 for success, -1 for failure to verify
 
 -- | Single target key precompilation.
 foreign import ccall "crypto_box_beforenm"
-  c_box_beforenm :: Ptr Word8
+  c_box_beforenm :: Ptr CChar
                     -- ^ Combined key output buffer
-                    -> Ptr Word8
+                    -> Ptr CChar
                     -- ^ Constant public key buffer
-                    -> Ptr Word8
+                    -> Ptr CChar
                     -- ^ Constant secret key buffer
                     -> IO CInt
                     -- ^ Always 0
 
 -- | Precompiled key crypto box. Uses 0-padded C strings.
 foreign import ccall "crypto_box_afternm"
-  c_box_afternm :: Ptr Word8
+  c_box_afternm :: Ptr CChar
                    -- ^ Cipher 0-padded output buffer
-                   -> Ptr Word8
+                   -> Ptr CChar
                    -- ^ Constant 0-padded message input buffer
                    -> CULLong
                    -- ^ Length of message input buffer (incl. 0s)
-                   -> Ptr Word8
+                   -> Ptr CChar
                    -- ^ Constant nonce buffer
-                   -> Ptr Word8
+                   -> Ptr CChar
                    -- ^ Constant combined key buffer
                    -> IO CInt
                    -- ^ Always 0
 
 -- | The secretbox C API uses 0-padded C strings.
 foreign import ccall "crypto_box_open_afternm"
-  c_box_open_afternm :: Ptr Word8
+  c_box_open_afternm :: Ptr CChar
                         -- ^ Message 0-padded output buffer
-                        -> Ptr Word8
+                        -> Ptr CChar
                         -- ^ Constant 0-padded ciphertext input buffer
                         -> CULLong
                         -- ^ Length of message input buffer (incl. 0s)
-                        -> Ptr Word8
+                        -> Ptr CChar
                         -- ^ Constant nonce buffer
-                        -> Ptr Word8
+                        -> Ptr CChar
                         -- ^ Constant combined key buffer
                         -> IO CInt
                         -- ^ 0 for success, -1 for failure to verify
diff --git a/src/Crypto/Saltine/Core/Hash.hs b/src/Crypto/Saltine/Core/Hash.hs
--- a/src/Crypto/Saltine/Core/Hash.hs
+++ b/src/Crypto/Saltine/Core/Hash.hs
@@ -9,9 +9,9 @@
 -- 
 -- Hashing: "Crypto.Saltine.Core.Hash"
 -- 
--- The 'hash' function hashes a message 'V.Vector' and returns a
+-- The 'hash' function hashes a message 'ByteString' and returns a
 -- hash. Hashes are always of length 'Bytes.hash'. The 'shorthash'
--- function hashes a message 'V.Vector' with respect to a secret key
+-- function hashes a message 'ByteString' with respect to a secret key
 -- and returns a very short hash. Short hashes are always of length
 -- 'Bytes.shorthash'.
 -- 
@@ -52,26 +52,26 @@
 
 import Foreign.C
 import Foreign.Ptr
-import Data.Word
-import qualified Data.Vector.Storable as V
+import qualified Data.ByteString as S
+import           Data.ByteString (ByteString)
 
 import Control.Applicative
 
 -- | Computes a cryptographically collision-resistant hash making
 -- @hash m == hash m' ==> m == m'@ highly likely even when under
 -- attack.
-hash :: V.Vector Word8
+hash :: ByteString
         -- ^ Message
-        -> V.Vector Word8
+        -> ByteString
         -- ^ Hash
 hash m = snd . buildUnsafeCVector Bytes.hash $ \ph ->
-  constVectors [m] $ \[pm] -> c_hash ph pm (fromIntegral $ V.length m)
+  constVectors [m] $ \[(pm, _)] -> c_hash ph pm (fromIntegral $ S.length m)
 
 -- | An opaque 'shorthash' cryptographic secret key.
-newtype ShorthashKey = ShK (V.Vector Word8) deriving (Eq, Ord)
+newtype ShorthashKey = ShK ByteString deriving (Eq, Ord)
 
 instance IsEncoding ShorthashKey where
-  decode v = case V.length v == Bytes.shorthashKey of
+  decode v = case S.length v == Bytes.shorthashKey of
     True -> Just (ShK v)
     False -> Nothing
   {-# INLINE decode #-}
@@ -84,18 +84,18 @@
 
 -- | Computes a very short, fast keyed hash.
 shorthash :: ShorthashKey
-             -> V.Vector Word8
+             -> ByteString
              -- ^ Message
-             -> V.Vector Word8
+             -> ByteString
              -- ^ Hash
 shorthash (ShK k) m = snd . buildUnsafeCVector Bytes.shorthash $ \ph ->
-  constVectors [k, m] $ \[pk, pm] ->
-  c_shorthash ph pm (fromIntegral $ V.length m) pk
+  constVectors [k, m] $ \[(pk, _), (pm, _)] ->
+  c_shorthash ph pm (fromIntegral $ S.length m) pk
              
 foreign import ccall "crypto_hash"
-  c_hash :: Ptr Word8
+  c_hash :: Ptr CChar
             -- ^ Output hash buffer
-            -> Ptr Word8
+            -> Ptr CChar
             -- ^ Constant message buffer
             -> CULLong
             -- ^ Constant message buffer length
@@ -103,13 +103,13 @@
             -- ^ Always 0
 
 foreign import ccall "crypto_shorthash"
-  c_shorthash :: Ptr Word8
+  c_shorthash :: Ptr CChar
                  -- ^ Output hash buffer
-                 -> Ptr Word8
+                 -> Ptr CChar
                  -- ^ Constant message buffer
                  -> CULLong
                  -- ^ Message buffer length
-                 -> Ptr Word8
+                 -> Ptr CChar
                  -- ^ Constant Key buffer
                  -> IO CInt
                  -- ^ Always 0
diff --git a/src/Crypto/Saltine/Core/OneTimeAuth.hs b/src/Crypto/Saltine/Core/OneTimeAuth.hs
--- a/src/Crypto/Saltine/Core/OneTimeAuth.hs
+++ b/src/Crypto/Saltine/Core/OneTimeAuth.hs
@@ -10,7 +10,7 @@
 -- Secret-key single-message authentication:
 -- "Crypto.Saltine.Core.OneTimeAuth"
 -- 
--- The 'auth' function authenticates a message 'V.Vector' using a
+-- The 'auth' function authenticates a message 'ByteString' using a
 -- secret key The function returns an authenticator. The 'verify'
 -- function checks if it's passed a correct authenticator of a message
 -- under the given secret key.
@@ -45,21 +45,21 @@
 
 import Foreign.C
 import Foreign.Ptr
-import Data.Word
-import qualified Data.Vector.Storable as V
+import qualified Data.ByteString as S
+import           Data.ByteString (ByteString)
 
 import Control.Applicative
 
 -- $types
 
 -- | An opaque 'auth' cryptographic key.
-newtype Key = Key (V.Vector Word8) deriving (Eq, Ord)
+newtype Key = Key ByteString deriving (Eq, Ord)
 
 -- | An opaque 'auth' authenticator.
-newtype Authenticator = Au (V.Vector Word8) deriving (Eq, Ord)
+newtype Authenticator = Au ByteString deriving (Eq, Ord)
 
 instance IsEncoding Key where
-  decode v = case V.length v == Bytes.onetimeKey of
+  decode v = case S.length v == Bytes.onetimeKey of
     True -> Just (Key v)
     False -> Nothing
   {-# INLINE decode #-}
@@ -67,7 +67,7 @@
   {-# INLINE encode #-}
 
 instance IsEncoding Authenticator where
-  decode v = case V.length v == Bytes.onetime of
+  decode v = case S.length v == Bytes.onetime of
     True -> Just (Au v)
     False -> Nothing
   {-# INLINE decode #-}
@@ -82,33 +82,34 @@
 -- 'Authenticator' is /impossible/ to forge so long as the 'Key' is
 -- never used twice.
 auth :: Key
-        -> V.Vector Word8
+        -> ByteString
         -- ^ Message
         -> Authenticator
 auth (Key key) msg =
   Au . snd . buildUnsafeCVector Bytes.onetime $ \pa ->
-    constVectors [key, msg] $ \[pk, pm] ->
-    c_onetimeauth pa pm (fromIntegral $ V.length msg) pk
+    constVectors [key, msg] $ \[(pk, _), (pm, _)] ->
+    c_onetimeauth pa pm (fromIntegral $ S.length msg) pk
 
 -- | Verifies that an 'Authenticator' matches a given message and key.
 verify :: Key
           -> Authenticator
-          -> V.Vector Word8
+          -> ByteString
           -- ^ Message
           -> Bool
           -- ^ Is this message authentic?
 verify (Key key) (Au a) msg =
-  unsafeDidSucceed $ constVectors [key, msg, a] $ \[pk, pm, pa] ->
-  return $ c_onetimeauth_verify pa pm (fromIntegral $ V.length msg) pk
+  unsafeDidSucceed $ constVectors [key, msg, a] $ \
+    [(pk, _), (pm, _), (pa, _)] ->
+    return $ c_onetimeauth_verify pa pm (fromIntegral $ S.length msg) pk
 
 foreign import ccall "crypto_onetimeauth"
-  c_onetimeauth :: Ptr Word8
+  c_onetimeauth :: Ptr CChar
                    -- ^ Authenticator output buffer
-                   -> Ptr Word8
+                   -> Ptr CChar
                    -- ^ Constant message buffer
                    -> CULLong
                    -- ^ Length of message buffer
-                   -> Ptr Word8
+                   -> Ptr CChar
                    -- ^ Constant key buffer
                    -> IO CInt
                    -- ^ Always 0
@@ -116,13 +117,13 @@
 -- | We don't even include this in the IO monad since all of the
 -- buffers are constant.
 foreign import ccall "crypto_onetimeauth_verify"
-  c_onetimeauth_verify :: Ptr Word8
+  c_onetimeauth_verify :: Ptr CChar
                           -- ^ Constant authenticator buffer
-                          -> Ptr Word8
+                          -> Ptr CChar
                           -- ^ Constant message buffer
                           -> CULLong
                           -- ^ Length of message buffer
-                          -> Ptr Word8
+                          -> Ptr CChar
                           -- ^ Constant key buffer
                           -> CInt
                           -- ^ Success if 0, failure if -1
diff --git a/src/Crypto/Saltine/Core/ScalarMult.hs b/src/Crypto/Saltine/Core/ScalarMult.hs
--- a/src/Crypto/Saltine/Core/ScalarMult.hs
+++ b/src/Crypto/Saltine/Core/ScalarMult.hs
@@ -61,19 +61,19 @@
 
 import Foreign.C
 import Foreign.Ptr
-import Data.Word
-import qualified Data.Vector.Storable as V
+import qualified Data.ByteString as S
+import           Data.ByteString (ByteString)
 
 -- $types
 
 -- | A group element.
-newtype GroupElement = GE (V.Vector Word8) deriving (Eq)
+newtype GroupElement = GE ByteString deriving (Eq)
 
 -- | A scalar integer.
-newtype Scalar = Sc (V.Vector Word8) deriving (Eq)
+newtype Scalar = Sc ByteString deriving (Eq)
 
 instance IsEncoding GroupElement where
-  decode v = case V.length v == Bytes.mult of
+  decode v = case S.length v == Bytes.mult of
     True -> Just (GE v)
     False -> Nothing
   {-# INLINE decode #-}
@@ -81,7 +81,7 @@
   {-# INLINE encode #-}
 
 instance IsEncoding Scalar where
-  decode v = case V.length v == Bytes.multScalar of
+  decode v = case S.length v == Bytes.multScalar of
     True -> Just (Sc v)
     False -> Nothing
   {-# INLINE decode #-}
@@ -90,28 +90,28 @@
 
 mult :: Scalar -> GroupElement -> GroupElement
 mult (Sc n) (GE p) = GE . snd . buildUnsafeCVector Bytes.mult $ \pq ->
-  constVectors [n, p] $ \[pn, pp] ->
+  constVectors [n, p] $ \[(pn, _), (pp, _)] ->
   c_scalarmult pq pn pp
 
 multBase :: Scalar -> GroupElement
 multBase (Sc n) = GE . snd . buildUnsafeCVector Bytes.mult $ \pq ->
-  constVectors [n] $ \[pn] ->
+  constVectors [n] $ \[(pn, _)] ->
   c_scalarmult_base pq pn
 
 foreign import ccall "crypto_scalarmult"
-  c_scalarmult :: Ptr Word8
+  c_scalarmult :: Ptr CChar
                   -- ^ Output group element buffer
-                  -> Ptr Word8
+                  -> Ptr CChar
                   -- ^ Input integer buffer
-                  -> Ptr Word8
+                  -> Ptr CChar
                   -- ^ Input group element buffer
                   -> IO CInt
                   -- ^ Always 0
 
 foreign import ccall "crypto_scalarmult"
-  c_scalarmult_base :: Ptr Word8
+  c_scalarmult_base :: Ptr CChar
                        -- ^ Output group element buffer
-                       -> Ptr Word8
+                       -> Ptr CChar
                        -- ^ Input integer buffer
                        -> IO CInt
                        -- ^ Always 0
diff --git a/src/Crypto/Saltine/Core/SecretBox.hs b/src/Crypto/Saltine/Core/SecretBox.hs
--- a/src/Crypto/Saltine/Core/SecretBox.hs
+++ b/src/Crypto/Saltine/Core/SecretBox.hs
@@ -11,9 +11,9 @@
 -- "Crypto.Saltine.Core.SecretBox"
 -- 
 -- The 'secretbox' function encrypts and authenticates a message
--- 'V.Vector' using a secret key and a nonce. The 'secretboxOpen'
--- function verifies and decrypts a ciphertext 'V.Vector' using a secret
--- key and a nonce. If the ciphertext fails validation,
+-- 'ByteString' using a secret key and a nonce. The 'secretboxOpen'
+-- function verifies and decrypts a ciphertext 'ByteString' using a
+-- secret key and a nonce. If the ciphertext fails validation,
 -- 'secretboxOpen' returns 'Nothing'.
 -- 
 -- The "Crypto.Saltine.Core.SecretBox" module is designed to meet
@@ -49,18 +49,18 @@
 
 import Foreign.C
 import Foreign.Ptr
-import Data.Word
-import qualified Data.Vector.Storable as V
+import qualified Data.ByteString as S
+import           Data.ByteString (ByteString)
 
 import Control.Applicative
 
 -- $types
 
 -- | An opaque 'secretbox' cryptographic key.
-newtype Key = Key (V.Vector Word8) deriving (Eq, Ord)
+newtype Key = Key ByteString deriving (Eq, Ord)
 
 instance IsEncoding Key where
-  decode v = case V.length v == Bytes.secretBoxKey of
+  decode v = case S.length v == Bytes.secretBoxKey of
     True -> Just (Key v)
     False -> Nothing
   {-# INLINE decode #-}
@@ -68,10 +68,10 @@
   {-# INLINE encode #-}
 
 -- | An opaque 'secretbox' nonce.
-newtype Nonce = Nonce (V.Vector Word8) deriving (Eq, Ord)
+newtype Nonce = Nonce ByteString deriving (Eq, Ord)
 
 instance IsEncoding Nonce where
-  decode v = case V.length v == Bytes.secretBoxNonce of
+  decode v = case S.length v == Bytes.secretBoxNonce of
     True -> Just (Nonce v)
     False -> Nothing
   {-# INLINE decode #-}
@@ -79,8 +79,8 @@
   {-# INLINE encode #-}
 
 instance IsNonce Nonce where
-  zero = Nonce (V.replicate Bytes.secretBoxNonce 0)
-  nudge (Nonce n) = Nonce (nudgeVector n)
+  zero = Nonce (S.replicate Bytes.secretBoxNonce 0)
+  nudge (Nonce n) = Nonce (nudgeBS n)
 
 -- | Creates a random key of the correct size for 'secretbox'.
 newKey :: IO Key
@@ -93,59 +93,61 @@
 -- | Encrypts a message. It is infeasible for an attacker to decrypt
 -- the message so long as the 'Nonce' is never repeated.
 secretbox :: Key -> Nonce
-             -> V.Vector Word8
+             -> ByteString
              -- ^ Message
-             -> V.Vector Word8
+             -> ByteString
              -- ^ Ciphertext
 secretbox (Key key) (Nonce nonce) msg =
   unpad' . snd . buildUnsafeCVector len $ \pc ->
-    constVectors [key, pad' msg, nonce] $ \[pk, pm, pn] ->
-    c_secretbox pc pm (fromIntegral len) pn pk
-  where len    = V.length msg + Bytes.secretBoxZero
+    constVectors [key, pad' msg, nonce] $ \
+      [(pk, _), (pm, _), (pn, _)] ->
+      c_secretbox pc pm (fromIntegral len) pn pk
+  where len    = S.length msg + Bytes.secretBoxZero
         pad'   = pad Bytes.secretBoxZero
         unpad' = unpad Bytes.secretBoxBoxZero
 
 -- | Decrypts a message. Returns 'Nothing' if the keys and message do
 -- not match.
 secretboxOpen :: Key -> Nonce 
-                 -> V.Vector Word8
+                 -> ByteString
                  -- ^ Ciphertext
-                 -> Maybe (V.Vector Word8)
+                 -> Maybe ByteString
                  -- ^ Message
 secretboxOpen (Key key) (Nonce nonce) cipher =
   let (err, vec) = buildUnsafeCVector len $ \pm ->
-        constVectors [key, pad' cipher, nonce] $ \[pk, pc, pn] ->
-        c_secretbox_open pm pc (fromIntegral len) pn pk
+        constVectors [key, pad' cipher, nonce] $ \
+          [(pk, _), (pc, _), (pn, _)] ->
+          c_secretbox_open pm pc (fromIntegral len) pn pk
   in hush . handleErrno err $ unpad' vec
-  where len    = V.length cipher + Bytes.secretBoxBoxZero
+  where len    = S.length cipher + Bytes.secretBoxBoxZero
         pad'   = pad Bytes.secretBoxBoxZero
         unpad' = unpad Bytes.secretBoxZero
 
 -- | The secretbox C API uses 0-padded C strings. Always returns 0.
 foreign import ccall "crypto_secretbox"
-  c_secretbox :: Ptr Word8
+  c_secretbox :: Ptr CChar
                  -- ^ Cipher 0-padded output buffer
-                 -> Ptr Word8
+                 -> Ptr CChar
                  -- ^ Constant 0-padded message input buffer
                  -> CULLong
                  -- ^ Length of message input buffer (incl. 0s)
-                 -> Ptr Word8
+                 -> Ptr CChar
                  -- ^ Constant nonce buffer
-                 -> Ptr Word8
+                 -> Ptr CChar
                  -- ^ Constant key buffer
                  -> IO CInt
 
 -- | The secretbox C API uses 0-padded C strings. Returns 0 if
 -- successful or -1 if verification failed.
 foreign import ccall "crypto_secretbox_open"
-  c_secretbox_open :: Ptr Word8
+  c_secretbox_open :: Ptr CChar
                       -- ^ Message 0-padded output buffer
-                      -> Ptr Word8
+                      -> Ptr CChar
                       -- ^ Constant 0-padded message input buffer
                       -> CULLong
                       -- ^ Length of message input buffer (incl. 0s)
-                      -> Ptr Word8
+                      -> Ptr CChar
                       -- ^ Constant nonce buffer
-                      -> Ptr Word8
+                      -> Ptr CChar
                       -- ^ Constant key buffer
                       -> IO CInt
diff --git a/src/Crypto/Saltine/Core/Sign.hs b/src/Crypto/Saltine/Core/Sign.hs
--- a/src/Crypto/Saltine/Core/Sign.hs
+++ b/src/Crypto/Saltine/Core/Sign.hs
@@ -11,10 +11,10 @@
 -- 
 -- The 'newKeypair' function randomly generates a secret key and a
 -- corresponding public key. The 'sign' function signs a message
--- 'V.Vector' using the signer's secret key and returns the resulting
--- signed message. The 'signOpen' function verifies the signature in a
--- signed message using the signer's public key then returns the
--- message without its signature.
+-- 'ByteString' using the signer's secret key and returns the
+-- resulting signed message. The 'signOpen' function verifies the
+-- signature in a signed message using the signer's public key then
+-- returns the message without its signature.
 -- 
 -- "Crypto.Saltine.Core.Sign" is an EdDSA signature using
 -- elliptic-curve Curve25519 (see: <http://ed25519.cr.yp.to/>). See
@@ -40,16 +40,16 @@
 import Foreign.Marshal.Alloc
 import Foreign.Storable
 import System.IO.Unsafe
-import Data.Word
-import qualified Data.Vector.Storable as V
+import qualified Data.ByteString as S
+import           Data.ByteString (ByteString)
 
 -- $types
 
 -- | An opaque 'box' cryptographic secret key.
-newtype SecretKey = SK (V.Vector Word8) deriving (Eq, Ord)
+newtype SecretKey = SK ByteString deriving (Eq, Ord)
 
 instance IsEncoding SecretKey where
-  decode v = case V.length v == Bytes.signSK of
+  decode v = case S.length v == Bytes.signSK of
     True -> Just (SK v)
     False -> Nothing
   {-# INLINE decode #-}
@@ -57,10 +57,10 @@
   {-# INLINE encode #-}
 
 -- | An opaque 'box' cryptographic public key.
-newtype PublicKey = PK (V.Vector Word8) deriving (Eq, Ord)
+newtype PublicKey = PK ByteString deriving (Eq, Ord)
 
 instance IsEncoding PublicKey where
-  decode v = case V.length v == Bytes.signPK of
+  decode v = case S.length v == Bytes.signPK of
     True -> Just (PK v)
     False -> Nothing
   {-# INLINE decode #-}
@@ -84,71 +84,71 @@
 -- | Augments a message with a signature forming a \"signed
 -- message\".
 sign :: SecretKey
-        -> V.Vector Word8
+        -> ByteString
         -- ^ Message
-        -> V.Vector Word8
+        -> ByteString
         -- ^ Signed message
 sign (SK k) m = unsafePerformIO $ 
   alloca $ \psmlen -> do
     (_err, sm) <- buildUnsafeCVector' (len + Bytes.sign) $ \psmbuf ->
-      constVectors [k, m] $ \[pk, pm] ->
+      constVectors [k, m] $ \[(pk, _), (pm, _)] ->
       c_sign psmbuf psmlen pm (fromIntegral len) pk
     smlen <- peek psmlen
-    return $ V.take (fromIntegral smlen) sm
-  where len = V.length m
+    return $ S.take (fromIntegral smlen) sm
+  where len = S.length m
 
 -- | Checks a \"signed message\" returning 'Just' the original message
 -- iff the signature was generated using the 'SecretKey' corresponding
 -- to the given 'PublicKey'. Returns 'Nothing' otherwise.
 signOpen :: PublicKey
-            -> V.Vector Word8
+            -> ByteString
             -- ^ Signed message
-            -> Maybe (V.Vector Word8)
+            -> Maybe ByteString
             -- ^ Maybe the restored message
 signOpen (PK k) sm = unsafePerformIO $
   alloca $ \pmlen -> do
     (err, m) <- buildUnsafeCVector' smlen $ \pmbuf ->
-      constVectors [k, sm] $ \[pk, psm] ->
+      constVectors [k, sm] $ \[(pk, _), (psm, _)] ->
       c_sign_open pmbuf pmlen psm (fromIntegral smlen) pk
     mlen <- peek pmlen
     case err of
-      0 -> return $ Just $ V.take (fromIntegral mlen) m
+      0 -> return $ Just $ S.take (fromIntegral mlen) m
       _ -> return $ Nothing
-  where smlen = V.length sm
+  where smlen = S.length sm
 
 
 foreign import ccall "crypto_sign_keypair"
-  c_sign_keypair :: Ptr Word8
+  c_sign_keypair :: Ptr CChar
                     -- ^ Public key output buffer
-                    -> Ptr Word8
+                    -> Ptr CChar
                     -- ^ Secret key output buffer
                     -> IO CInt
                     -- ^ Always 0
 
 foreign import ccall "crypto_sign"
-  c_sign :: Ptr Word8
+  c_sign :: Ptr CChar
             -- ^ Signed message output buffer
             -> Ptr CULLong
             -- ^ Length of signed message
-            -> Ptr Word8
+            -> Ptr CChar
             -- ^ Constant message buffer
             -> CULLong
             -- ^ Length of message input buffer
-            -> Ptr Word8
+            -> Ptr CChar
             -- ^ Constant secret key buffer
             -> IO CInt
             -- ^ Always 0
 
 foreign import ccall "crypto_sign_open"
-  c_sign_open :: Ptr Word8
+  c_sign_open :: Ptr CChar
                  -- ^ Message output buffer
                  -> Ptr CULLong
                  -- ^ Length of message
-                 -> Ptr Word8
+                 -> Ptr CChar
                  -- ^ Constant signed message buffer
                  -> CULLong
                  -- ^ Length of signed message buffer
-                 -> Ptr Word8
+                 -> Ptr CChar
                  -- ^ Public key buffer
                  -> IO CInt
                  -- ^ 0 if signature is verifiable, -1 otherwise
diff --git a/src/Crypto/Saltine/Core/Stream.hs b/src/Crypto/Saltine/Core/Stream.hs
--- a/src/Crypto/Saltine/Core/Stream.hs
+++ b/src/Crypto/Saltine/Core/Stream.hs
@@ -10,9 +10,9 @@
 -- Secret-key encryption:
 -- "Crypto.Saltine.Core.Stream"
 -- 
--- The 'stream' function produces a sized stream 'V.Vector' as a
+-- The 'stream' function produces a sized stream 'ByteString' as a
 -- function of a secret key and a nonce. The 'xor' function encrypts a
--- message 'V.Vector' using a secret key and a nonce.  The 'xor'
+-- message 'ByteString' using a secret key and a nonce.  The 'xor'
 -- function guarantees that the ciphertext has the same length as the
 -- plaintext, and is the @plaintext `xor` stream k n@. Consequently
 -- 'xor' can also be used to decrypt.
@@ -59,18 +59,18 @@
 
 import Foreign.C
 import Foreign.Ptr
-import Data.Word
-import qualified Data.Vector.Storable as V
+import qualified Data.ByteString as S
+import           Data.ByteString (ByteString)
 
 import Control.Applicative
 
 -- $types
 
 -- | An opaque 'stream' cryptographic key.
-newtype Key = Key (V.Vector Word8) deriving (Eq, Ord)
+newtype Key = Key ByteString deriving (Eq, Ord)
 
 instance IsEncoding Key where
-  decode v = case V.length v == Bytes.streamKey of
+  decode v = case S.length v == Bytes.streamKey of
     True -> Just (Key v)
     False -> Nothing
   {-# INLINE decode #-}
@@ -78,14 +78,14 @@
   {-# INLINE encode #-}
 
 -- | An opaque 'stream' nonce.
-newtype Nonce = Nonce (V.Vector Word8) deriving (Eq, Ord)
+newtype Nonce = Nonce ByteString deriving (Eq, Ord)
 
 instance IsNonce Nonce where
-  zero = Nonce (V.replicate Bytes.streamNonce 0)
-  nudge (Nonce n) = Nonce (nudgeVector n)
+  zero = Nonce (S.replicate Bytes.streamNonce 0)
+  nudge (Nonce n) = Nonce (nudgeBS n)
 
 instance IsEncoding Nonce where
-  decode v = case V.length v == Bytes.streamNonce of
+  decode v = case S.length v == Bytes.streamNonce of
     True -> Just (Nonce v)
     False -> Nothing
   {-# INLINE decode #-}
@@ -105,11 +105,11 @@
 -- 'Nonce'. These streams are indistinguishable from random noise so
 -- long as the 'Nonce' is not used more than once.
 stream :: Key -> Nonce -> Int
-          -> V.Vector Word8
+          -> ByteString
           -- ^ Cryptographic stream
 stream (Key key) (Nonce nonce) n =
   snd . buildUnsafeCVector n $ \ps ->
-    constVectors [key, nonce] $ \[pk, pn] ->
+    constVectors [key, nonce] $ \[(pk, _), (pn, _)] ->
     c_stream ps (fromIntegral n) pn pk
 
 -- | Computes the exclusive-or between a message and a cryptographic
@@ -120,38 +120,38 @@
 -- /manipulate the message in transit without detection/. USE AT YOUR
 -- OWN RISK.
 xor :: Key -> Nonce 
-       -> V.Vector Word8
+       -> ByteString
        -- ^ Message
-       -> V.Vector Word8
+       -> ByteString
        -- ^ Ciphertext
 xor (Key key) (Nonce nonce) msg =
   snd . buildUnsafeCVector len $ \pc ->
-    constVectors [key, nonce, msg] $ \[pk, pn, pm] ->
+    constVectors [key, nonce, msg] $ \[(pk, _), (pn, _), (pm, _)] ->
     c_stream_xor pc pm (fromIntegral len) pn pk
-  where len = V.length msg
+  where len = S.length msg
 
 foreign import ccall "crypto_stream"
-  c_stream :: Ptr Word8
+  c_stream :: Ptr CChar
               -- ^ Stream output buffer
               -> CULLong
               -- ^ Length of stream to generate
-              -> Ptr Word8
+              -> Ptr CChar
               -- ^ Constant nonce buffer
-              -> Ptr Word8
+              -> Ptr CChar
               -- ^ Constant key buffer
               -> IO CInt
               -- ^ Always 0
 
 foreign import ccall "crypto_stream_xor"
-  c_stream_xor :: Ptr Word8
+  c_stream_xor :: Ptr CChar
                   -- ^ Ciphertext output buffer
-                  -> Ptr Word8
+                  -> Ptr CChar
                   -- ^ Constant message buffer
                   -> CULLong
                   -- ^ Length of message buffer
-                  -> Ptr Word8
+                  -> Ptr CChar
                   -- ^ Constant nonce buffer
-                  -> Ptr Word8
+                  -> Ptr CChar
                   -- ^ Constant key buffer
                   -> IO CInt
                   -- ^ Always 0
diff --git a/src/Crypto/Saltine/Internal/Util.hs b/src/Crypto/Saltine/Internal/Util.hs
--- a/src/Crypto/Saltine/Internal/Util.hs
+++ b/src/Crypto/Saltine/Internal/Util.hs
@@ -2,43 +2,46 @@
 
 import Foreign.C
 import Foreign.Ptr
-import Foreign.ForeignPtr
 import System.IO.Unsafe
-import Data.Word
+
 import Data.Monoid
-import qualified Data.Vector.Storable as V
-import qualified Data.Vector.Storable.Mutable as VM
+import qualified Data.ByteString as S
+import Data.ByteString (ByteString)
+import Data.ByteString.Unsafe
 
-import Data.STRef
+-- | @snd . cycleSucc@ computes the 'succ' of a 'Bounded', 'Eq' 'Enum'
+-- with wraparound. The @fst . cycleSuc@ is whether the wraparound
+-- occurred (i.e. @fst . cycleSucc == (== maxBound)@).
+cycleSucc :: (Bounded a, Enum a, Eq a) => a -> (Bool, a)
+cycleSucc a = (top, if top then minBound else succ a)
+  where top = a == maxBound
 
-foreign import ccall "randombytes_buf"
-  c_randombytes_buf :: Ptr Word8 -> CInt -> IO ()
+-- | Treats a 'ByteString' as a little endian bitstring and increments
+-- it.
+nudgeBS :: ByteString -> ByteString
+nudgeBS i = fst $ S.unfoldrN (S.length i) go (True, i) where
+  go (toSucc, bs) =
+    do (hd, tl) <- S.uncons bs
+       let (top, hd') = cycleSucc hd
+       if toSucc
+         then return (hd', (top, tl))
+         else return (hd, (top && toSucc, tl))
 
--- | Increments a 'V.Vector' with 0 as the least-significant index.
-nudgeVector :: V.Vector Word8 -> V.Vector Word8
-nudgeVector v = V.modify go v
-  where go mv = do
-          iref <- newSTRef 0
-          loop iref mv
-        loop iref mv = do
-          i <- readSTRef iref
-          if i < len
-            then do val <- VM.read mv i
-                    if val == maxBound
-                       then do VM.write mv i minBound
-                               modifySTRef iref succ
-                               loop iref mv
-                      else VM.write mv i (succ val)
-            else return ()
-        len = V.length v
+-- | Computes the orbit of a endomorphism... in a very brute force
+-- manner. Exists just for the below property.
+-- 
+-- prop> length . orbit nudgeBS . S.pack . replicate 0 == (256^)
+orbit :: Eq a => (a -> a) -> a -> [a]
+orbit f a0 = orbit' (f a0) where
+  orbit' a = if a == a0 then [a0] else a : orbit' (f a)
 
--- | 0-pad a vector
-pad :: (VM.Storable a, Num a) => Int -> V.Vector a -> V.Vector a
-pad n = mappend (V.replicate n 0)
+-- | 0-pad a 'ByteString'
+pad :: Int -> ByteString -> ByteString
+pad n = mappend (S.replicate n 0)
 
--- | Remove a 0-padding from a vector
-unpad :: VM.Storable a => Int -> V.Vector a -> V.Vector a
-unpad = V.drop
+-- | Remove a 0-padding from a 'ByteString'
+unpad :: Int -> ByteString -> ByteString
+unpad = S.drop
 
 -- | Converts a C-convention errno to an Either
 handleErrno :: CInt -> (a -> Either String a)
@@ -53,33 +56,35 @@
         go _ = False
 
 -- | Convenience function for accessing constant C vectors
-constVectors :: VM.Storable a => [V.Vector a] -> ([Ptr a] -> IO b) -> IO b
 -- Manual unfold of: @constVectors = runContT . mapM (ContT . V.unsafeWith)@
-constVectors = foldr (\v kk -> \k -> (V.unsafeWith v) (\a -> kk (\as -> k (a:as)))) ($ [])
+constVectors :: [ByteString] -> ([CStringLen] -> IO b) -> IO b
+constVectors =
+  foldr (\v kk -> \k -> (unsafeUseAsCStringLen v) (\a -> kk (\as -> k (a:as)))) ($ [])
 
 -- | Slightly safer cousin to 'buildUnsafeCVector' that remains in the
 -- 'IO' monad.
-buildUnsafeCVector' :: VM.Storable a => Int -> (Ptr a -> IO b) -> IO (b, V.Vector a)
+buildUnsafeCVector' :: Int -> (Ptr CChar -> IO b) -> IO (b, ByteString)
 buildUnsafeCVector' n k = do
-  buf <- mallocForeignPtrArray n
-  b <- withForeignPtr buf k
-  vec <- V.unsafeFreeze (VM.unsafeFromForeignPtr buf 0 n)
-  return (b, vec)
+  let bs = S.replicate n 0
+  out <- unsafeUseAsCString bs k
+  return (out, bs)
 
 -- | Extremely unsafe function, use with utmost care! Builds a new
 -- Vector using a ccall which is given access to the raw underlying
 -- pointer. Overwrites are UNCHECKED and 'unsafePerformIO' is used so
--- it's difficult to predict the timing of the 'Vector' creation.
-buildUnsafeCVector :: VM.Storable a => Int -> (Ptr a -> IO b) -> (b, V.Vector a)
+-- it's difficult to predict the timing of the 'ByteString' creation.
+buildUnsafeCVector :: Int -> (Ptr CChar -> IO b) -> (b, ByteString)
 buildUnsafeCVector n = unsafePerformIO . buildUnsafeCVector' n
 
--- | Build a sized random 'V.Vector' using Sodium's bindings to
+-- | Build a sized random 'ByteString' using Sodium's bindings to
 -- @/dev/urandom@.
-randomVector :: Int -> IO (V.Vector Word8)
-randomVector n = do
-  (_, vec) <- buildUnsafeCVector' n (`c_randombytes_buf` fromIntegral n)
-  return vec
+randomVector :: Int -> IO ByteString
+randomVector n =
+  fmap snd $ buildUnsafeCVector' n (`c_randombytes_buf` fromIntegral n)
 
 -- | To prevent a dependency on package 'errors'
 hush :: Either s a -> Maybe a
 hush = either (const Nothing) Just
+
+foreign import ccall "randombytes_buf"
+  c_randombytes_buf :: Ptr CChar -> CInt -> IO ()
