ciphertext :: Chain
           -> Word32
           -> Maybe Header
           -> ByteString
           -> IO (Ciphertext, Chain)
ciphertext (Chain chain) pad hdr plaintext = do
  padding <- randombytes (fromIntegral pad)
  let
    (chainOut, macKey, encText)
      = ( B.take 32 block
        , B.take 32 $ B.drop 32 block
        , B.drop 64 block)
      where
        block = ncipher datum (SecretKey chain)
        datum = B.replicate 64 0x0
             <> encode pad
             <> padding
             <> plaintext
    mac = Poly1305.authenticate (SecretKey macKey) dataBlock
      where dataBlock = maybe B.empty encode hdr <> encText

  return (Ciphertext encText mac, Chain chainOut)
ciphertext :: Chain
           -> Word32
           -> Maybe Header
           -> ByteString
           -> IO (Ciphertext, Chain)
ciphertext (Chain chain) pad hdr plaintext = do
  padding <- randombytes (fromIntegral pad)
  let
    (chainOut, macKey, encText)
      = ( B.take 32 block
        , B.take 32 $ B.drop 32 block
        , B.drop 64 block)
      where
        block = ncipher datum (SecretKey chain)
        datum = B.replicate 64 0x0
             <> encode pad
             <> padding
             <> plaintext
    mac = Poly1305.authenticate (SecretKey macKey) dataBlock
      where dataBlock = maybe B.empty encode hdr <> encText

  return (Ciphertext encText mac, Chain chainOut)
ciphertext (Chain chain) pad hdr plaintext = do
  padding <- randombytes (fromIntegral pad)
  let
    (chainOut, macKey, encText)
      = ( B.take 32 block
        , B.take 32 $ B.drop 32 block
        , B.drop 64 block)
      where
        block = ncipher datum (SecretKey chain)
        datum = B.replicate 64 0x0
             <> encode pad
             <> padding
             <> plaintext
    mac = Poly1305.authenticate (SecretKey macKey) dataBlock
      where dataBlock = maybe B.empty encode hdr <> encText

  return (Ciphertext encText mac, Chain chainOut)