diff --git a/CHANGELOG.md b/CHANGELOG.md
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,3 +1,12 @@
+## 0.34
+
+* Hashing getRandomBytes before using as Seed for ChaChaDRG
+  [#24](https://github.com/kazu-yamamoto/crypton/pull/24)
+* Add support for XChaCha and XChaChaPoly1305
+  [#18](https://github.com/kazu-yamamoto/crypton/pull/18)
+* Strict byteArray of IV c
+  [#16](https://github.com/kazu-yamamoto/crypton/pull/16)
+
 ## 0.33
 
 * Add "crypton_" prefix to the final C symbols.
diff --git a/Crypto/Cipher/ChaCha.hs b/Crypto/Cipher/ChaCha.hs
--- a/Crypto/Cipher/ChaCha.hs
+++ b/Crypto/Cipher/ChaCha.hs
@@ -9,6 +9,7 @@
 {-# LANGUAGE GeneralizedNewtypeDeriving #-}
 module Crypto.Cipher.ChaCha
     ( initialize
+    , initializeX
     , combine
     , generate
     , State
@@ -53,6 +54,28 @@
   where kLen     = B.length key
         nonceLen = B.length nonce
 
+-- | Initialize a new XChaCha context with the number of rounds,
+-- the key and the nonce associated.
+--
+-- An XChaCha state can be used like a regular ChaCha state after initialisation.
+initializeX :: (ByteArrayAccess key, ByteArrayAccess nonce)
+            => Int   -- ^ number of rounds (8,12,20)
+            -> key   -- ^ the key (256 bits)
+            -> nonce -- ^ the nonce (192 bits)
+            -> State -- ^ the initial ChaCha state
+initializeX nbRounds key nonce
+    | kLen /= 32                      = error "XChaCha: key length should be 256 bits"
+    | nonceLen /= 24                  = error "XChaCha: nonce length should be 192 bits"
+    | nbRounds `notElem` [8,12,20]    = error "XChaCha: rounds should be 8, 12 or 20"
+    | otherwise                       = unsafeDoIO $ do
+        stPtr <- B.alloc 132 $ \stPtr ->
+            B.withByteArray nonce $ \noncePtr  ->
+            B.withByteArray key   $ \keyPtr ->
+                ccrypton_xchacha_init stPtr nbRounds keyPtr noncePtr
+        return $ State stPtr
+  where kLen     = B.length key
+        nonceLen = B.length nonce
+
 -- | Initialize simple ChaCha State
 --
 -- The seed need to be at least 40 bytes long
@@ -114,6 +137,9 @@
 
 foreign import ccall "crypton_chacha_init"
     ccrypton_chacha_init :: Ptr State -> Int -> Int -> Ptr Word8 -> Int -> Ptr Word8 -> IO ()
+
+foreign import ccall "crypton_xchacha_init"
+    ccrypton_xchacha_init :: Ptr State -> Int -> Ptr Word8 -> Ptr Word8 -> IO ()
 
 foreign import ccall "crypton_chacha_combine"
     ccrypton_chacha_combine :: Ptr Word8 -> Ptr State -> Ptr Word8 -> CUInt -> IO ()
diff --git a/Crypto/Cipher/ChaChaPoly1305.hs b/Crypto/Cipher/ChaChaPoly1305.hs
--- a/Crypto/Cipher/ChaChaPoly1305.hs
+++ b/Crypto/Cipher/ChaChaPoly1305.hs
@@ -38,10 +38,13 @@
 module Crypto.Cipher.ChaChaPoly1305
     ( State
     , Nonce
+    , XNonce
     , nonce12
     , nonce8
+    , nonce24
     , incrementNonce
     , initialize
+    , initializeX
     , appendAAD
     , finalizeAAD
     , encrypt
@@ -81,6 +84,14 @@
   withByteArray (Nonce8  n) = B.withByteArray n
   withByteArray (Nonce12 n) = B.withByteArray n
 
+-- | Extended nonce for XChaChaPoly1305.
+newtype XNonce = Nonce24 Bytes
+
+instance ByteArrayAccess XNonce where
+  length (Nonce24 n) = B.length n
+  withByteArray (Nonce24 n) = B.withByteArray n
+
+
 -- Based on the following pseudo code:
 --
 -- chacha20_aead_encrypt(aad, key, iv, constant, plaintext):
@@ -117,6 +128,13 @@
     | B.length iv       /= 8 = CryptoFailed CryptoError_IvSizeInvalid
     | otherwise              = CryptoPassed . Nonce8 . B.concat $ [constant, iv]
 
+-- | 24 bytes IV, extended nonce constructor
+nonce24 :: ByteArrayAccess ba
+        => ba -> CryptoFailable XNonce
+nonce24 iv
+    | B.length iv /= 24 = CryptoFailed CryptoError_IvSizeInvalid
+    | otherwise         = CryptoPassed . Nonce24 . B.convert $ iv
+
 -- | Increment a nonce
 incrementNonce :: Nonce -> Nonce
 incrementNonce (Nonce8  n) = Nonce8  $ incrementNonce' n 4
@@ -143,15 +161,33 @@
 initialize key (Nonce8  nonce) = initialize' key nonce
 initialize key (Nonce12 nonce) = initialize' key nonce
 
+
 initialize' :: ByteArrayAccess key
             => key -> Bytes -> CryptoFailable State
 initialize' key nonce
     | B.length key /= 32 = CryptoFailed CryptoError_KeySizeInvalid
-    | otherwise          = CryptoPassed $ State encState polyState 0 0
+    | otherwise          = CryptoPassed $ initFromRootState rootState
+  where rootState = ChaCha.initialize 20 key nonce
+
+
+initFromRootState :: ChaCha.State -> State
+initFromRootState rootState = State encState polyState 0 0
   where
-    rootState           = ChaCha.initialize 20 key nonce
     (polyKey, encState) = ChaCha.generate rootState 64
     polyState           = throwCryptoError $ Poly1305.initialize (B.take 32 polyKey :: ScrubbedBytes)
+
+
+-- | Initialize a new XChaChaPoly1305 State
+--
+-- The key length needs to be 256 bits, and the nonce
+-- procured using `nonce24`.
+initializeX :: ByteArrayAccess key
+            => key -> XNonce -> CryptoFailable State
+initializeX key (Nonce24 nonce)
+    | B.length key /= 32 = CryptoFailed CryptoError_KeySizeInvalid
+    | otherwise          = CryptoPassed $ initFromRootState rootState
+  where rootState = ChaCha.initializeX 20 key nonce
+
 
 -- | Append Authenticated Data to the State and return
 -- the new modified State.
diff --git a/Crypto/Cipher/Types/Block.hs b/Crypto/Cipher/Types/Block.hs
--- a/Crypto/Cipher/Types/Block.hs
+++ b/Crypto/Cipher/Types/Block.hs
@@ -50,7 +50,7 @@
 import           Foreign.Storable
 
 -- | an IV parametrized by the cipher
-data IV c = forall byteArray . ByteArray byteArray => IV byteArray
+data IV c = forall byteArray . ByteArray byteArray => IV !byteArray
 
 instance BlockCipher c => ByteArrayAccess (IV c) where
     withByteArray (IV z) f = withByteArray z f
diff --git a/Crypto/Hash/Blake2.hs b/Crypto/Hash/Blake2.hs
--- a/Crypto/Hash/Blake2.hs
+++ b/Crypto/Hash/Blake2.hs
@@ -33,7 +33,8 @@
 {-# LANGUAGE DataKinds #-}
 {-# LANGUAGE TypeFamilies #-}
 module Crypto.Hash.Blake2
-    ( Blake2s(..)
+    ( HashBlake2(..)
+    , Blake2s(..)
     , Blake2sp(..)
     , Blake2b(..)
     , Blake2bp(..)
@@ -46,6 +47,13 @@
 import           GHC.TypeLits (Nat, KnownNat)
 import           Crypto.Internal.Nat
 
+-- | Typeclass for the Blake2 family of digest functions.
+class HashAlgorithm a => HashBlake2 a where
+
+    -- | Init Blake2 algorithm with the specified key of the specified length.
+    -- The key length is specified in bytes.
+    blake2InternalKeyedInit :: Ptr (Context a) -> Ptr Word8 -> Word32 -> IO ()
+
 -- | Fast and secure alternative to SHA1 and HMAC-SHA1
 --
 -- It is espacially known to target 32bits architectures.
@@ -72,8 +80,16 @@
     hashInternalUpdate        = c_blake2s_update
     hashInternalFinalize p    = c_blake2s_finalize p (integralNatVal (Proxy :: Proxy bitlen))
 
+instance (IsDivisibleBy8 bitlen, KnownNat bitlen, IsAtLeast bitlen 8, IsAtMost bitlen 256)
+      => HashBlake2 (Blake2s bitlen)
+      where
+    blake2InternalKeyedInit p = c_blake2s_init_key p outLen
+        where outLen = integralNatVal (Proxy :: Proxy bitlen)
+
 foreign import ccall unsafe "crypton_blake2s_init"
     c_blake2s_init :: Ptr (Context a) -> Word32 -> IO ()
+foreign import ccall unsafe "crypton_blake2s_init_key"
+    c_blake2s_init_key :: Ptr (Context a) -> Word32 -> Ptr Word8 -> Word32 -> IO ()
 foreign import ccall "crypton_blake2s_update"
     c_blake2s_update :: Ptr (Context a) -> Ptr Word8 -> Word32 -> IO ()
 foreign import ccall unsafe "crypton_blake2s_finalize"
@@ -107,8 +123,16 @@
     hashInternalUpdate        = c_blake2b_update
     hashInternalFinalize p    = c_blake2b_finalize p (integralNatVal (Proxy :: Proxy bitlen))
 
+instance (IsDivisibleBy8 bitlen, KnownNat bitlen, IsAtLeast bitlen 8, IsAtMost bitlen 512)
+      => HashBlake2 (Blake2b bitlen)
+      where
+    blake2InternalKeyedInit p = c_blake2b_init_key p outLen
+        where outLen = integralNatVal (Proxy :: Proxy bitlen)
+
 foreign import ccall unsafe "crypton_blake2b_init"
     c_blake2b_init :: Ptr (Context a) -> Word32 -> IO ()
+foreign import ccall unsafe "crypton_blake2b_init_key"
+    c_blake2b_init_key :: Ptr (Context a) -> Word32 -> Ptr Word8 -> Word32 -> IO ()
 foreign import ccall "crypton_blake2b_update"
     c_blake2b_update :: Ptr (Context a) -> Ptr Word8 -> Word32 -> IO ()
 foreign import ccall unsafe "crypton_blake2b_finalize"
@@ -130,8 +154,16 @@
     hashInternalUpdate        = c_blake2sp_update
     hashInternalFinalize p    = c_blake2sp_finalize p (integralNatVal (Proxy :: Proxy bitlen))
 
+instance (IsDivisibleBy8 bitlen, KnownNat bitlen, IsAtLeast bitlen 8, IsAtMost bitlen 256)
+      => HashBlake2 (Blake2sp bitlen)
+      where
+    blake2InternalKeyedInit p = c_blake2sp_init_key p outLen
+        where outLen = integralNatVal (Proxy :: Proxy bitlen)
+
 foreign import ccall unsafe "crypton_blake2sp_init"
     c_blake2sp_init :: Ptr (Context a) -> Word32 -> IO ()
+foreign import ccall unsafe "crypton_blake2sp_init_key"
+    c_blake2sp_init_key :: Ptr (Context a) -> Word32 -> Ptr Word8 -> Word32 -> IO ()
 foreign import ccall "crypton_blake2sp_update"
     c_blake2sp_update :: Ptr (Context a) -> Ptr Word8 -> Word32 -> IO ()
 foreign import ccall unsafe "crypton_blake2sp_finalize"
@@ -153,9 +185,16 @@
     hashInternalUpdate        = c_blake2bp_update
     hashInternalFinalize p    = c_blake2bp_finalize p (integralNatVal (Proxy :: Proxy bitlen))
 
+instance (IsDivisibleBy8 bitlen, KnownNat bitlen, IsAtLeast bitlen 8, IsAtMost bitlen 512)
+      => HashBlake2 (Blake2bp bitlen)
+      where
+    blake2InternalKeyedInit p = c_blake2bp_init_key p outLen
+        where outLen = integralNatVal (Proxy :: Proxy bitlen)
 
 foreign import ccall unsafe "crypton_blake2bp_init"
     c_blake2bp_init :: Ptr (Context a) -> Word32 -> IO ()
+foreign import ccall unsafe "crypton_blake2bp_init_key"
+    c_blake2bp_init_key :: Ptr (Context a) -> Word32 -> Ptr Word8 -> Word32 -> IO ()
 foreign import ccall "crypton_blake2bp_update"
     c_blake2bp_update :: Ptr (Context a) -> Ptr Word8 -> Word32 -> IO ()
 foreign import ccall unsafe "crypton_blake2bp_finalize"
diff --git a/Crypto/MAC/KeyedBlake2.hs b/Crypto/MAC/KeyedBlake2.hs
new file mode 100644
--- /dev/null
+++ b/Crypto/MAC/KeyedBlake2.hs
@@ -0,0 +1,88 @@
+-- |
+-- Module      : Crypto.MAC.KeyedBlake2
+-- License     : BSD-style
+-- Maintainer  : Matthias Valvekens <dev@mvalvekens.be>
+-- Stability   : experimental
+-- Portability : unknown
+--
+-- Expose a MAC interface to the keyed Blake2 algorithms
+-- defined in RFC 7693.
+--
+{-# LANGUAGE GeneralizedNewtypeDeriving #-}
+{-# LANGUAGE ScopedTypeVariables #-}
+
+module Crypto.MAC.KeyedBlake2
+    ( HashBlake2
+    , KeyedBlake2(..)
+    , keyedBlake2
+    , keyedBlake2Lazy
+    -- * Incremental
+    , Context
+    , initialize
+    , update
+    , updates
+    , finalize
+    ) where
+
+import qualified Crypto.Hash as H
+import qualified Crypto.Hash.Types as H
+import           Crypto.Hash.Blake2
+import           Crypto.Internal.DeepSeq (NFData)
+import qualified Data.ByteArray as B
+import           Data.ByteArray (ByteArrayAccess)
+import qualified Data.ByteString.Lazy as L
+
+import           Foreign.Ptr (Ptr)
+
+
+-- Keyed Blake2b
+
+-- | Represent a Blake2b MAC that is a phantom type with the hash used to produce the
+-- MAC.
+--
+-- The Eq instance is constant time.  No Show instance is provided, to avoid
+-- printing by mistake.
+newtype KeyedBlake2 a = KeyedBlake2 { keyedBlake2GetDigest :: H.Digest a }
+    deriving (ByteArrayAccess,NFData)
+
+instance Eq (KeyedBlake2 a) where
+    KeyedBlake2 x == KeyedBlake2 y = B.constEq x y
+
+-- | Represent an ongoing Blake2 state, that can be appended with 'update' and
+-- finalized to a 'KeyedBlake2' with 'finalize'.
+newtype Context a = Context (H.Context a)
+
+-- | Initialize a new incremental keyed Blake2 context with the supplied key.
+initialize :: forall a key . (HashBlake2 a, ByteArrayAccess key)
+           => key -> Context a
+initialize k = Context $ H.Context $ B.allocAndFreeze ctxSz performInit
+    where ctxSz = H.hashInternalContextSize (undefined :: a)
+          digestSz = H.hashDigestSize (undefined :: a)
+          -- cap the number of key bytes at digestSz,
+          -- since that's the maximal key size
+          keyByteLen = min (B.length k) digestSz
+          performInit :: Ptr (H.Context a) -> IO ()
+          performInit ptr = B.withByteArray k
+            $ \keyPtr -> blake2InternalKeyedInit ptr keyPtr (fromIntegral keyByteLen)
+
+-- | Incrementally update a keyed Blake2 context.
+update :: (HashBlake2 a, ByteArrayAccess ba) => Context a -> ba -> Context a
+update (Context ctx) = Context . H.hashUpdate ctx
+
+-- | Incrementally update a keyed Blake2 context with multiple inputs.
+updates :: (HashBlake2 a, ByteArrayAccess ba) => Context a -> [ba] -> Context a
+updates (Context ctx) = Context . H.hashUpdates ctx
+
+-- | Finalize a keyed Blake2 context and return the computed MAC.
+finalize :: HashBlake2 a => Context a -> KeyedBlake2 a
+finalize (Context ctx) = KeyedBlake2 $ H.hashFinalize ctx
+
+-- | Compute a Blake2 MAC using the supplied key.
+keyedBlake2 :: (HashBlake2 a, ByteArrayAccess key, ByteArrayAccess ba)
+            => key -> ba -> KeyedBlake2 a
+keyedBlake2 key msg = finalize $ update (initialize key) msg
+
+-- | Compute a Blake2 MAC using the supplied key, for a lazy input.
+keyedBlake2Lazy :: (HashBlake2 a, ByteArrayAccess key)
+            => key -> L.ByteString -> KeyedBlake2 a
+keyedBlake2Lazy key msg = finalize $ updates (initialize key) (L.toChunks msg)
diff --git a/Crypto/Random.hs b/Crypto/Random.hs
--- a/Crypto/Random.hs
+++ b/Crypto/Random.hs
@@ -37,6 +37,7 @@
 import Data.ByteArray (ByteArray, ByteArrayAccess, ScrubbedBytes)
 import qualified Data.ByteArray as B
 import Crypto.Internal.Imports
+import Crypto.Hash (Digest, SHA512, hash)
 
 import qualified Crypto.Number.Serialize as Serialize
 
@@ -49,7 +50,13 @@
 
 -- | Create a new Seed from system entropy
 seedNew :: MonadRandom randomly => randomly Seed
-seedNew = Seed `fmap` getRandomBytes seedLength
+-- The degree of its randomness depends on the source, e.g. for iOS we
+-- have to compile with DoNotUseEntropy flag, as iOS doesn't allow
+-- using getentropy, and on some other systems it can be also
+-- potentially comprisable sources. Hashing of entropy before using
+-- it as a seed is a common mitigation for attacks via RNG/entropy
+-- source.
+seedNew = (Seed . B.take seedLength . B.convert . (hash :: ScrubbedBytes -> Digest SHA512)) `fmap` getRandomBytes 64
 
 -- | Convert a Seed to an integer
 seedToInteger :: Seed -> Integer
diff --git a/README.md b/README.md
--- a/README.md
+++ b/README.md
@@ -29,10 +29,6 @@
 Next version of `0.x` is `0.(x+1)`. There's no exceptions, or API related meaning
 behind the numbers.
 
-Each versions of stackage (going back 3 stable LTS) has a crypton version
-that we maintain with security fixes when necessary and are versioned with the
-following `0.x.y` scheme.
-
 Coding Style
 ------------
 
diff --git a/cbits/crypton_blake2b.c b/cbits/crypton_blake2b.c
--- a/cbits/crypton_blake2b.c
+++ b/cbits/crypton_blake2b.c
@@ -5,6 +5,11 @@
 	_crypton_blake2b_init(ctx, hashlen / 8);
 }
 
+void crypton_blake2b_init_key(blake2b_ctx *ctx, uint32_t hashlen, const uint8_t *key, size_t keylen)
+{
+	_crypton_blake2b_init_key(ctx, hashlen / 8, (const void *) key, keylen);
+}
+
 void crypton_blake2b_update(blake2b_ctx *ctx, const uint8_t *data, uint32_t len)
 {
 	_crypton_blake2b_update(ctx, data, len);
diff --git a/cbits/crypton_blake2b.h b/cbits/crypton_blake2b.h
--- a/cbits/crypton_blake2b.h
+++ b/cbits/crypton_blake2b.h
@@ -6,6 +6,7 @@
 typedef blake2b_state blake2b_ctx;
 
 void crypton_blake2b_init(blake2b_ctx *ctx, uint32_t hashlen);
+void crypton_blake2b_init_key(blake2b_ctx *ctx, uint32_t hashlen, const uint8_t *key, size_t keylen);
 void crypton_blake2b_update(blake2b_ctx *ctx, const uint8_t *data, uint32_t len);
 void crypton_blake2b_finalize(blake2b_ctx *ctx, uint32_t hashlen, uint8_t *out);
 
diff --git a/cbits/crypton_blake2bp.c b/cbits/crypton_blake2bp.c
--- a/cbits/crypton_blake2bp.c
+++ b/cbits/crypton_blake2bp.c
@@ -5,6 +5,11 @@
 	_crypton_blake2bp_init(ctx, hashlen / 8);
 }
 
+void crypton_blake2bp_init_key(blake2bp_ctx *ctx, uint32_t hashlen, const uint8_t *key, size_t keylen)
+{
+	_crypton_blake2bp_init_key(ctx, hashlen / 8, (const void *) key, keylen);
+}
+
 void crypton_blake2bp_update(blake2bp_ctx *ctx, const uint8_t *data, uint32_t len)
 {
 	_crypton_blake2bp_update(ctx, data, len);
diff --git a/cbits/crypton_blake2bp.h b/cbits/crypton_blake2bp.h
--- a/cbits/crypton_blake2bp.h
+++ b/cbits/crypton_blake2bp.h
@@ -6,6 +6,7 @@
 typedef blake2bp_state blake2bp_ctx;
 
 void crypton_blake2bp_init(blake2bp_ctx *ctx, uint32_t hashlen);
+void crypton_blake2bp_init_key(blake2bp_ctx *ctx, uint32_t hashlen, const uint8_t *key, size_t keylen);
 void crypton_blake2bp_update(blake2bp_ctx *ctx, const uint8_t *data, uint32_t len);
 void crypton_blake2bp_finalize(blake2bp_ctx *ctx, uint32_t hashlen, uint8_t *out);
 
diff --git a/cbits/crypton_blake2s.c b/cbits/crypton_blake2s.c
--- a/cbits/crypton_blake2s.c
+++ b/cbits/crypton_blake2s.c
@@ -5,6 +5,11 @@
 	_crypton_blake2s_init(ctx, hashlen / 8);
 }
 
+void crypton_blake2s_init_key(blake2s_ctx *ctx, uint32_t hashlen, const uint8_t *key, size_t keylen)
+{
+	_crypton_blake2s_init_key(ctx, hashlen / 8, (const void *) key, keylen);
+}
+
 void crypton_blake2s_update(blake2s_ctx *ctx, const uint8_t *data, uint32_t len)
 {
 	_crypton_blake2s_update(ctx, data, len);
diff --git a/cbits/crypton_blake2s.h b/cbits/crypton_blake2s.h
--- a/cbits/crypton_blake2s.h
+++ b/cbits/crypton_blake2s.h
@@ -6,6 +6,7 @@
 typedef blake2s_state blake2s_ctx;
 
 void crypton_blake2s_init(blake2s_ctx *ctx, uint32_t hashlen);
+void crypton_blake2s_init_key(blake2s_ctx *ctx, uint32_t hashlen, const uint8_t *key, size_t keylen);
 void crypton_blake2s_update(blake2s_ctx *ctx, const uint8_t *data, uint32_t len);
 void crypton_blake2s_finalize(blake2s_ctx *ctx, uint32_t hashlen, uint8_t *out);
 
diff --git a/cbits/crypton_blake2sp.c b/cbits/crypton_blake2sp.c
--- a/cbits/crypton_blake2sp.c
+++ b/cbits/crypton_blake2sp.c
@@ -5,6 +5,11 @@
 	_crypton_blake2sp_init(ctx, hashlen / 8);
 }
 
+void crypton_blake2sp_init_key(blake2sp_ctx *ctx, uint32_t hashlen, const uint8_t *key, size_t keylen)
+{
+	_crypton_blake2sp_init_key(ctx, hashlen / 8, (const void *) key, keylen);
+}
+
 void crypton_blake2sp_update(blake2sp_ctx *ctx, const uint8_t *data, uint32_t len)
 {
 	_crypton_blake2sp_update(ctx, data, len);
diff --git a/cbits/crypton_blake2sp.h b/cbits/crypton_blake2sp.h
--- a/cbits/crypton_blake2sp.h
+++ b/cbits/crypton_blake2sp.h
@@ -6,6 +6,7 @@
 typedef blake2sp_state blake2sp_ctx;
 
 void crypton_blake2sp_init(blake2sp_ctx *ctx, uint32_t hashlen);
+void crypton_blake2sp_init_key(blake2sp_ctx *ctx, uint32_t hashlen, const uint8_t *key, size_t keylen);
 void crypton_blake2sp_update(blake2sp_ctx *ctx, const uint8_t *data, uint32_t len);
 void crypton_blake2sp_finalize(blake2sp_ctx *ctx, uint32_t hashlen, uint8_t *out);
 
diff --git a/cbits/crypton_chacha.c b/cbits/crypton_chacha.c
--- a/cbits/crypton_chacha.c
+++ b/cbits/crypton_chacha.c
@@ -92,11 +92,44 @@
 	out->d[15] = cpu_to_le32(x15);
 }
 
-/* only 2 valids values are 256 (32) and 128 (16) */
-void crypton_chacha_init_core(crypton_chacha_state *st,
-                                 uint32_t keylen, const uint8_t *key,
-                                 uint32_t ivlen, const uint8_t *iv)
+static void hchacha_core(int rounds, uint32_t *out, const crypton_chacha_state *in)
 {
+	uint32_t x0, x1, x2, x3, x4, x5, x6, x7, x8, x9, x10, x11, x12, x13, x14, x15;
+	int i;
+
+	x0 = in->d[0]; x1 = in->d[1]; x2 = in->d[2]; x3 = in->d[3];
+	x4 = in->d[4]; x5 = in->d[5]; x6 = in->d[6]; x7 = in->d[7];
+	x8 = in->d[8]; x9 = in->d[9]; x10 = in->d[10]; x11 = in->d[11];
+	x12 = in->d[12]; x13 = in->d[13]; x14 = in->d[14]; x15 = in->d[15];
+
+	for (i = rounds; i > 0; i -= 2) {
+		QR(x0, x4, x8, x12);
+		QR(x1, x5, x9, x13);
+		QR(x2, x6, x10, x14);
+		QR(x3, x7, x11, x15);
+
+		QR(x0, x5, x10, x15);
+		QR(x1, x6, x11, x12);
+		QR(x2, x7, x8, x13);
+		QR(x3, x4, x9, x14);
+	}
+
+	/* HChaCha doesn't perform the final addition */
+
+	out[0] = cpu_to_le32(x0);
+	out[1] = cpu_to_le32(x1);
+	out[2] = cpu_to_le32(x2);
+	out[3] = cpu_to_le32(x3);
+	out[4] = cpu_to_le32(x12);
+	out[5] = cpu_to_le32(x13);
+	out[6] = cpu_to_le32(x14);
+	out[7] = cpu_to_le32(x15);
+}
+
+/* Common initialization logic for ChaCha20 and HChaCha20 */
+static void chacha_init_key_state(crypton_chacha_state *st,
+                                  uint32_t keylen, const uint8_t *key)
+{
 	const uint8_t *constants = (keylen == 32) ? sigma : tau;
 
 	ASSERT_ALIGNMENT(constants, 4);
@@ -117,6 +150,14 @@
 	st->d[9] = load_le32(key + 4);
 	st->d[10] = load_le32(key + 8);
 	st->d[11] = load_le32(key + 12);
+}
+
+/* only 2 valids values are 256 (32) and 128 (16) */
+void crypton_chacha_init_core(crypton_chacha_state *st,
+                              uint32_t keylen, const uint8_t *key,
+                              uint32_t ivlen, const uint8_t *iv)
+{
+	chacha_init_key_state(st, keylen, key);
 	st->d[12] = 0;
 	switch (ivlen) {
 	case 8:
@@ -133,6 +174,19 @@
 	}
 }
 
+void crypton_hchacha_init_core(crypton_chacha_state *st,
+                                  const uint8_t *key,
+                                  const uint8_t *iv)
+{
+	/* keylen is always 32 here */
+	chacha_init_key_state(st, 32, key);
+	/* fill the last 4 uint32s with the 128-bit nonce */
+	st->d[12] = load_le32(iv + 0);
+	st->d[13] = load_le32(iv + 4);
+	st->d[14] = load_le32(iv + 8);
+	st->d[15] = load_le32(iv + 12);
+}
+
 void crypton_chacha_init(crypton_chacha_context *ctx, uint8_t nb_rounds,
                             uint32_t keylen, const uint8_t *key,
                             uint32_t ivlen, const uint8_t *iv)
@@ -141,6 +195,39 @@
 	ctx->nb_rounds = nb_rounds;
 	crypton_chacha_init_core(&ctx->st, keylen, key, ivlen, iv);
 }
+
+void crypton_hchacha(uint8_t nb_rounds, const uint8_t *keyin, const uint8_t *iv,
+                        uint8_t *keyout)
+{
+	crypton_chacha_state st;
+
+	crypton_hchacha_init_core(&st, keyin, iv);
+	/* output to uint32_t* and do a memcpy to avoid
+	   violating the strict aliasing rule */
+	uint32_t keyout32[8];
+	hchacha_core(nb_rounds, keyout32, &st);
+	memset(&st, 0, sizeof(st));
+	memcpy(keyout, keyout32, 32);
+
+	memset(keyout32, 0, 32);
+}
+
+/* XChaCha: 256-bit key, 192-bit nonce version of ChaCha.*/
+void crypton_xchacha_init(crypton_chacha_context *ctx, uint8_t nb_rounds,
+                             const uint8_t *key, const uint8_t *iv)
+{
+	memset(ctx, 0, sizeof(*ctx));
+	ctx->nb_rounds = nb_rounds;
+
+	/* perform HChaCha with the key and the first 16 bytes of the nonce
+	to get the subkey */
+	uint8_t subkey[32];
+	crypton_hchacha(nb_rounds, key, iv, subkey);
+	/* perform regular ChaCha with the generated subkey and the last 8 bytes
+	of the input IV */
+	crypton_chacha_init_core(&ctx->st, 32, subkey, 8, iv + 16);
+}
+
 
 void crypton_chacha_combine(uint8_t *dst, crypton_chacha_context *ctx, const uint8_t *src, uint32_t bytes)
 {
diff --git a/cbits/crypton_chacha.h b/cbits/crypton_chacha.h
--- a/cbits/crypton_chacha.h
+++ b/cbits/crypton_chacha.h
@@ -48,6 +48,7 @@
 
 void crypton_chacha_init_core(crypton_chacha_state *st, uint32_t keylen, const uint8_t *key, uint32_t ivlen, const uint8_t *iv);
 void crypton_chacha_init(crypton_chacha_context *ctx, uint8_t nb_rounds, uint32_t keylen, const uint8_t *key, uint32_t ivlen, const uint8_t *iv);
+void crypton_xchacha_init(crypton_chacha_context *ctx, uint8_t nb_rounds, const uint8_t *key, const uint8_t *iv);
 void crypton_chacha_combine(uint8_t *dst, crypton_chacha_context *st, const uint8_t *src, uint32_t bytes);
 void crypton_chacha_generate(uint8_t *dst, crypton_chacha_context *st, uint32_t bytes);
 
diff --git a/crypton.cabal b/crypton.cabal
--- a/crypton.cabal
+++ b/crypton.cabal
@@ -1,7 +1,17 @@
-Name:                crypton
-version:             0.33
-Synopsis:            Cryptography Primitives sink
-Description:
+cabal-version:      1.18
+name:               crypton
+version:            0.34
+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 ==9.2.2 ghc ==9.0.2 ghc ==8.10.7 ghc ==8.8.4
+homepage:           https://github.com/kazu-yamamoto/crypton
+bug-reports:        https://github.com/kazu-yamamoto/crypton/issues
+synopsis:           Cryptography Primitives sink
+description:
     A repository of cryptographic primitives.
     .
     * Symmetric ciphers: AES, DES, 3DES, CAST5, Blowfish, Twofish, Camellia, RC4, Salsa, XSalsa, ChaCha.
@@ -25,463 +35,495 @@
     Evaluate the security related to your requirements before using.
     .
     Read "Crypto.Tutorial" for a quick start guide.
-License:             BSD3
-License-file:        LICENSE
-Copyright:           Vincent Hanquez <vincent@snarc.org>
-Author:              Vincent Hanquez <vincent@snarc.org>
-Maintainer:          Kazu Yamamoto <kazu@iij.ad.jp>
-Category:            Cryptography
-Stability:           experimental
-Build-Type:          Simple
-Homepage:            https://github.com/kazu-yamamoto/crypton
-Bug-reports:         https://github.com/kazu-yamamoto/crypton/issues
-Cabal-Version:       1.18
-tested-with:         GHC==9.2.2, GHC==9.0.2, GHC==8.10.7, GHC==8.8.4
-extra-doc-files:     README.md CHANGELOG.md
-extra-source-files:  cbits/*.h
-                     cbits/aes/*.h
-                     cbits/ed25519/*.h
-                     cbits/decaf/include/*.h
-                     cbits/decaf/include/decaf/*.h
-                     cbits/decaf/include/arch_32/*.h
-                     cbits/decaf/include/arch_ref64/*.h
-                     cbits/decaf/p448/arch_32/*.h
-                     cbits/decaf/p448/arch_ref64/*.h
-                     cbits/decaf/p448/*.h
-                     cbits/decaf/ed448goldilocks/decaf_tables.c
-                     cbits/decaf/ed448goldilocks/decaf.c
-                     cbits/include32/p256/*.h
-                     cbits/include64/p256/*.h
-                     cbits/blake2/ref/*.h
-                     cbits/blake2/sse/*.h
-                     cbits/argon2/*.h
-                     cbits/argon2/*.c
-                     cbits/aes/x86ni_impl.c
-                     cbits/crypton_hash_prefix.c
-                     tests/*.hs
 
+category:           Cryptography
+build-type:         Simple
+extra-source-files:
+    cbits/*.h
+    cbits/aes/*.h
+    cbits/ed25519/*.h
+    cbits/decaf/include/*.h
+    cbits/decaf/include/decaf/*.h
+    cbits/decaf/include/arch_32/*.h
+    cbits/decaf/include/arch_ref64/*.h
+    cbits/decaf/p448/arch_32/*.h
+    cbits/decaf/p448/arch_ref64/*.h
+    cbits/decaf/p448/*.h
+    cbits/decaf/ed448goldilocks/decaf_tables.c
+    cbits/decaf/ed448goldilocks/decaf.c
+    cbits/include32/p256/*.h
+    cbits/include64/p256/*.h
+    cbits/blake2/ref/*.h
+    cbits/blake2/sse/*.h
+    cbits/argon2/*.h
+    cbits/argon2/*.c
+    cbits/aes/x86ni_impl.c
+    cbits/crypton_hash_prefix.c
+    tests/*.hs
+
+extra-doc-files:
+    README.md
+    CHANGELOG.md
+
 source-repository head
-  type: git
-  location: https://github.com/kazu-yamamoto/crypton
+    type:     git
+    location: https://github.com/kazu-yamamoto/crypton
 
-Flag support_aesni
-  Description:       allow compilation with AESNI on system and architecture that supports it
-  Default:           True
-  Manual:            True
+flag support_aesni
+    description:
+        allow compilation with AESNI on system and architecture that supports it
 
-Flag support_rdrand
-  Description:       allow compilation with RDRAND on system and architecture that supports it
-  Default:           True
-  Manual:            True
+    manual:      True
 
-Flag support_pclmuldq
-  Description:       Allow compilation with pclmuldq on architecture that supports it
-  Default:           True
-  Manual:            True
+flag support_rdrand
+    description:
+        allow compilation with RDRAND on system and architecture that supports it
 
-Flag support_sse
-  Description:       Use SSE optimized version of (BLAKE2, ARGON2)
-  Default:           False
-  Manual:            True
+    manual:      True
 
-Flag integer-gmp
-  Description:       Whether or not to use GMP for some functions
-  Default:           True
-  Manual:            True
+flag support_pclmuldq
+    description:
+        Allow compilation with pclmuldq on architecture that supports it
 
-Flag support_deepseq
-  Description:       add deepseq instances for cryptographic types
-  Default:           True
-  Manual:            True
+    manual:      True
 
-Flag old_toolchain_inliner
-  Description:       use -fgnu89-inline to workaround an old compiler / linker / glibc issue.
-  Default:           False
-  Manual:            True
+flag support_sse
+    description: Use SSE optimized version of (BLAKE2, ARGON2)
+    default:     False
+    manual:      True
 
-Flag check_alignment
-  Description:       extra check on alignment in C layers, which cause lowlevel assert errors. for debugging only.
-  Default:           False
-  Manual:            True
+flag integer-gmp
+    description: Whether or not to use GMP for some functions
+    manual:      True
 
-Flag use_target_attributes
-  Description:       use GCC / clang function attributes instead of global target options.
-  Default:           True
-  Manual:            True
+flag support_deepseq
+    description: add deepseq instances for cryptographic types
+    manual:      True
 
-Library
-  Exposed-modules:   Crypto.Cipher.AES
-                     Crypto.Cipher.AESGCMSIV
-                     Crypto.Cipher.Blowfish
-                     Crypto.Cipher.CAST5
-                     Crypto.Cipher.Camellia
-                     Crypto.Cipher.ChaCha
-                     Crypto.Cipher.ChaChaPoly1305
-                     Crypto.Cipher.DES
-                     Crypto.Cipher.RC4
-                     Crypto.Cipher.Salsa
-                     Crypto.Cipher.TripleDES
-                     Crypto.Cipher.Twofish
-                     Crypto.Cipher.Types
-                     Crypto.Cipher.Utils
-                     Crypto.Cipher.XSalsa
-                     Crypto.ConstructHash.MiyaguchiPreneel
-                     Crypto.Data.AFIS
-                     Crypto.Data.Padding
-                     Crypto.ECC
-                     Crypto.ECC.Edwards25519
-                     Crypto.Error
-                     Crypto.MAC.CMAC
-                     Crypto.MAC.Poly1305
-                     Crypto.MAC.HMAC
-                     Crypto.MAC.KMAC
-                     Crypto.Number.Basic
-                     Crypto.Number.F2m
-                     Crypto.Number.Generate
-                     Crypto.Number.ModArithmetic
-                     Crypto.Number.Nat
-                     Crypto.Number.Prime
-                     Crypto.Number.Serialize
-                     Crypto.Number.Serialize.LE
-                     Crypto.Number.Serialize.Internal
-                     Crypto.Number.Serialize.Internal.LE
-                     Crypto.KDF.Argon2
-                     Crypto.KDF.PBKDF2
-                     Crypto.KDF.Scrypt
-                     Crypto.KDF.BCrypt
-                     Crypto.KDF.BCryptPBKDF
-                     Crypto.KDF.HKDF
-                     Crypto.Hash
-                     Crypto.Hash.IO
-                     Crypto.Hash.Algorithms
-                     Crypto.OTP
-                     Crypto.PubKey.Curve25519
-                     Crypto.PubKey.Curve448
-                     Crypto.PubKey.MaskGenFunction
-                     Crypto.PubKey.DH
-                     Crypto.PubKey.DSA
-                     Crypto.PubKey.ECC.Generate
-                     Crypto.PubKey.ECC.Prim
-                     Crypto.PubKey.ECC.DH
-                     Crypto.PubKey.ECC.ECDSA
-                     Crypto.PubKey.ECC.P256
-                     Crypto.PubKey.ECC.Types
-                     Crypto.PubKey.ECDSA
-                     Crypto.PubKey.ECIES
-                     Crypto.PubKey.Ed25519
-                     Crypto.PubKey.Ed448
-                     Crypto.PubKey.EdDSA
-                     Crypto.PubKey.RSA
-                     Crypto.PubKey.RSA.PKCS15
-                     Crypto.PubKey.RSA.Prim
-                     Crypto.PubKey.RSA.PSS
-                     Crypto.PubKey.RSA.OAEP
-                     Crypto.PubKey.RSA.Types
-                     Crypto.PubKey.Rabin.OAEP
-                     Crypto.PubKey.Rabin.Basic
-                     Crypto.PubKey.Rabin.Modified
-                     Crypto.PubKey.Rabin.RW
-                     Crypto.PubKey.Rabin.Types
-                     Crypto.Random
-                     Crypto.Random.Types
-                     Crypto.Random.Entropy
-                     Crypto.Random.EntropyPool
-                     Crypto.Random.Entropy.Unsafe
-                     Crypto.System.CPU
-                     Crypto.Tutorial
-  Other-modules:     Crypto.Cipher.AES.Primitive
-                     Crypto.Cipher.Blowfish.Box
-                     Crypto.Cipher.Blowfish.Primitive
-                     Crypto.Cipher.CAST5.Primitive
-                     Crypto.Cipher.Camellia.Primitive
-                     Crypto.Cipher.DES.Primitive
-                     Crypto.Cipher.Twofish.Primitive
-                     Crypto.Cipher.Types.AEAD
-                     Crypto.Cipher.Types.Base
-                     Crypto.Cipher.Types.Block
-                     Crypto.Cipher.Types.GF
-                     Crypto.Cipher.Types.Stream
-                     Crypto.Cipher.Types.Utils
-                     Crypto.Error.Types
-                     Crypto.Number.Compat
-                     Crypto.Hash.Types
-                     Crypto.Hash.Blake2
-                     Crypto.Hash.Blake2s
-                     Crypto.Hash.Blake2sp
-                     Crypto.Hash.Blake2b
-                     Crypto.Hash.Blake2bp
-                     Crypto.Hash.SHA1
-                     Crypto.Hash.SHA224
-                     Crypto.Hash.SHA256
-                     Crypto.Hash.SHA384
-                     Crypto.Hash.SHA512
-                     Crypto.Hash.SHA512t
-                     Crypto.Hash.SHA3
-                     Crypto.Hash.SHAKE
-                     Crypto.Hash.Keccak
-                     Crypto.Hash.MD2
-                     Crypto.Hash.MD4
-                     Crypto.Hash.MD5
-                     Crypto.Hash.RIPEMD160
-                     Crypto.Hash.Skein256
-                     Crypto.Hash.Skein512
-                     Crypto.Hash.Tiger
-                     Crypto.Hash.Whirlpool
-                     Crypto.Random.Entropy.Source
-                     Crypto.Random.Entropy.Backend
-                     Crypto.Random.ChaChaDRG
-                     Crypto.Random.SystemDRG
-                     Crypto.Random.Probabilistic
-                     Crypto.PubKey.Internal
-                     Crypto.PubKey.ElGamal
-                     Crypto.ECC.Simple.Types
-                     Crypto.ECC.Simple.Prim
-                     Crypto.Internal.Builder
-                     Crypto.Internal.ByteArray
-                     Crypto.Internal.Compat
-                     Crypto.Internal.CompatPrim
-                     Crypto.Internal.DeepSeq
-                     Crypto.Internal.Imports
-                     Crypto.Internal.Nat
-                     Crypto.Internal.Words
-                     Crypto.Internal.WordArray
-  if impl(ghc < 8.8)
-    Buildable: False
-  else
-    Build-depends:   base
+flag old_toolchain_inliner
+    description:
+        use -fgnu89-inline to workaround an old compiler / linker / glibc issue.
 
-  Build-depends:     bytestring
-                   , memory >= 0.14.18
-                   , basement >= 0.0.6
-                   , ghc-prim
-  ghc-options:       -Wall -fwarn-tabs -optc-O3
-  if os(linux)
-    extra-libraries: pthread
-  default-language:  Haskell2010
-  cc-options:        -std=gnu99
-  if flag(old_toolchain_inliner)
-    cc-options:      -fgnu89-inline
-  C-sources:         cbits/crypton_chacha.c
-                   , cbits/crypton_salsa.c
-                   , cbits/crypton_xsalsa.c
-                   , cbits/crypton_rc4.c
-                   , cbits/crypton_cpu.c
-                   , cbits/p256/p256.c
-                   , cbits/p256/p256_ec.c
-                   , cbits/crypton_blake2s.c
-                   , cbits/crypton_blake2sp.c
-                   , cbits/crypton_blake2b.c
-                   , cbits/crypton_blake2bp.c
-                   , cbits/crypton_poly1305.c
-                   , cbits/crypton_sha1.c
-                   , cbits/crypton_sha256.c
-                   , cbits/crypton_sha512.c
-                   , cbits/crypton_sha3.c
-                   , cbits/crypton_md2.c
-                   , cbits/crypton_md4.c
-                   , cbits/crypton_md5.c
-                   , cbits/crypton_ripemd.c
-                   , cbits/crypton_skein256.c
-                   , cbits/crypton_skein512.c
-                   , cbits/crypton_tiger.c
-                   , cbits/crypton_whirlpool.c
-                   , cbits/crypton_scrypt.c
-                   , cbits/crypton_pbkdf2.c
-                   , cbits/ed25519/ed25519.c
-  include-dirs:      cbits
-                   , cbits/ed25519
-                   , cbits/decaf/include
-                   , cbits/decaf/p448
+    default:     False
+    manual:      True
 
-  if arch(x86_64) || arch(aarch64)
-    include-dirs:      cbits/include64
-  else
-    include-dirs:      cbits/include32
+flag check_alignment
+    description:
+        extra check on alignment in C layers, which cause lowlevel assert errors. for debugging only.
 
-  if arch(x86_64) || arch(aarch64)
-    C-sources:         cbits/decaf/p448/arch_ref64/f_impl.c
-                     , cbits/decaf/p448/f_generic.c
-                     , cbits/decaf/p448/f_arithmetic.c
-                     , cbits/decaf/utils.c
-                     , cbits/decaf/ed448goldilocks/scalar.c
-                     , cbits/decaf/ed448goldilocks/decaf_all.c
-                     , cbits/decaf/ed448goldilocks/eddsa.c
+    default:     False
+    manual:      True
 
-    include-dirs:      cbits/decaf/include/arch_ref64
-                     , cbits/decaf/p448/arch_ref64
-  else
-    C-sources:         cbits/decaf/p448/arch_32/f_impl.c
-                     , cbits/decaf/p448/f_generic.c
-                     , cbits/decaf/p448/f_arithmetic.c
-                     , cbits/decaf/utils.c
-                     , cbits/decaf/ed448goldilocks/scalar.c
-                     , cbits/decaf/ed448goldilocks/decaf_all.c
-                     , cbits/decaf/ed448goldilocks/eddsa.c
+flag use_target_attributes
+    description:
+        use GCC / clang function attributes instead of global target options.
 
-    include-dirs:      cbits/decaf/include/arch_32
-                     , cbits/decaf/p448/arch_32
+    manual:      True
 
-  if arch(x86_64) || arch(aarch64)
-    C-sources: cbits/curve25519/curve25519-donna-c64.c
-  else
-    C-sources: cbits/curve25519/curve25519-donna.c
+library
+    exposed-modules:
+        Crypto.Cipher.AES
+        Crypto.Cipher.AESGCMSIV
+        Crypto.Cipher.Blowfish
+        Crypto.Cipher.CAST5
+        Crypto.Cipher.Camellia
+        Crypto.Cipher.ChaCha
+        Crypto.Cipher.ChaChaPoly1305
+        Crypto.Cipher.DES
+        Crypto.Cipher.RC4
+        Crypto.Cipher.Salsa
+        Crypto.Cipher.TripleDES
+        Crypto.Cipher.Twofish
+        Crypto.Cipher.Types
+        Crypto.Cipher.Utils
+        Crypto.Cipher.XSalsa
+        Crypto.ConstructHash.MiyaguchiPreneel
+        Crypto.Data.AFIS
+        Crypto.Data.Padding
+        Crypto.ECC
+        Crypto.ECC.Edwards25519
+        Crypto.Error
+        Crypto.MAC.CMAC
+        Crypto.MAC.Poly1305
+        Crypto.MAC.HMAC
+        Crypto.MAC.KeyedBlake2
+        Crypto.MAC.KMAC
+        Crypto.Number.Basic
+        Crypto.Number.F2m
+        Crypto.Number.Generate
+        Crypto.Number.ModArithmetic
+        Crypto.Number.Nat
+        Crypto.Number.Prime
+        Crypto.Number.Serialize
+        Crypto.Number.Serialize.LE
+        Crypto.Number.Serialize.Internal
+        Crypto.Number.Serialize.Internal.LE
+        Crypto.KDF.Argon2
+        Crypto.KDF.PBKDF2
+        Crypto.KDF.Scrypt
+        Crypto.KDF.BCrypt
+        Crypto.KDF.BCryptPBKDF
+        Crypto.KDF.HKDF
+        Crypto.Hash
+        Crypto.Hash.IO
+        Crypto.Hash.Algorithms
+        Crypto.OTP
+        Crypto.PubKey.Curve25519
+        Crypto.PubKey.Curve448
+        Crypto.PubKey.MaskGenFunction
+        Crypto.PubKey.DH
+        Crypto.PubKey.DSA
+        Crypto.PubKey.ECC.Generate
+        Crypto.PubKey.ECC.Prim
+        Crypto.PubKey.ECC.DH
+        Crypto.PubKey.ECC.ECDSA
+        Crypto.PubKey.ECC.P256
+        Crypto.PubKey.ECC.Types
+        Crypto.PubKey.ECDSA
+        Crypto.PubKey.ECIES
+        Crypto.PubKey.Ed25519
+        Crypto.PubKey.Ed448
+        Crypto.PubKey.EdDSA
+        Crypto.PubKey.RSA
+        Crypto.PubKey.RSA.PKCS15
+        Crypto.PubKey.RSA.Prim
+        Crypto.PubKey.RSA.PSS
+        Crypto.PubKey.RSA.OAEP
+        Crypto.PubKey.RSA.Types
+        Crypto.PubKey.Rabin.OAEP
+        Crypto.PubKey.Rabin.Basic
+        Crypto.PubKey.Rabin.Modified
+        Crypto.PubKey.Rabin.RW
+        Crypto.PubKey.Rabin.Types
+        Crypto.Random
+        Crypto.Random.Types
+        Crypto.Random.Entropy
+        Crypto.Random.EntropyPool
+        Crypto.Random.Entropy.Unsafe
+        Crypto.System.CPU
+        Crypto.Tutorial
 
-  -- FIXME armel or mispel is also little endian.
-  -- might be a good idea to also add a runtime autodetect mode.
-  -- ARCH_ENDIAN_UNKNOWN
-  if (arch(i386) || arch(x86_64))
-    CPP-options: -DARCH_IS_LITTLE_ENDIAN
+    cc-options:       -std=gnu99
+    c-sources:
+        cbits/crypton_chacha.c
+        cbits/crypton_salsa.c
+        cbits/crypton_xsalsa.c
+        cbits/crypton_rc4.c
+        cbits/crypton_cpu.c
+        cbits/p256/p256.c
+        cbits/p256/p256_ec.c
+        cbits/crypton_blake2s.c
+        cbits/crypton_blake2sp.c
+        cbits/crypton_blake2b.c
+        cbits/crypton_blake2bp.c
+        cbits/crypton_poly1305.c
+        cbits/crypton_sha1.c
+        cbits/crypton_sha256.c
+        cbits/crypton_sha512.c
+        cbits/crypton_sha3.c
+        cbits/crypton_md2.c
+        cbits/crypton_md4.c
+        cbits/crypton_md5.c
+        cbits/crypton_ripemd.c
+        cbits/crypton_skein256.c
+        cbits/crypton_skein512.c
+        cbits/crypton_tiger.c
+        cbits/crypton_whirlpool.c
+        cbits/crypton_scrypt.c
+        cbits/crypton_pbkdf2.c
+        cbits/ed25519/ed25519.c
+        cbits/argon2/argon2.c
 
-  if arch(i386)
-    CPP-options: -DARCH_X86
+    other-modules:
+        Crypto.Cipher.AES.Primitive
+        Crypto.Cipher.Blowfish.Box
+        Crypto.Cipher.Blowfish.Primitive
+        Crypto.Cipher.CAST5.Primitive
+        Crypto.Cipher.Camellia.Primitive
+        Crypto.Cipher.DES.Primitive
+        Crypto.Cipher.Twofish.Primitive
+        Crypto.Cipher.Types.AEAD
+        Crypto.Cipher.Types.Base
+        Crypto.Cipher.Types.Block
+        Crypto.Cipher.Types.GF
+        Crypto.Cipher.Types.Stream
+        Crypto.Cipher.Types.Utils
+        Crypto.Error.Types
+        Crypto.Number.Compat
+        Crypto.Hash.Types
+        Crypto.Hash.Blake2
+        Crypto.Hash.Blake2s
+        Crypto.Hash.Blake2sp
+        Crypto.Hash.Blake2b
+        Crypto.Hash.Blake2bp
+        Crypto.Hash.SHA1
+        Crypto.Hash.SHA224
+        Crypto.Hash.SHA256
+        Crypto.Hash.SHA384
+        Crypto.Hash.SHA512
+        Crypto.Hash.SHA512t
+        Crypto.Hash.SHA3
+        Crypto.Hash.SHAKE
+        Crypto.Hash.Keccak
+        Crypto.Hash.MD2
+        Crypto.Hash.MD4
+        Crypto.Hash.MD5
+        Crypto.Hash.RIPEMD160
+        Crypto.Hash.Skein256
+        Crypto.Hash.Skein512
+        Crypto.Hash.Tiger
+        Crypto.Hash.Whirlpool
+        Crypto.Random.Entropy.Source
+        Crypto.Random.Entropy.Backend
+        Crypto.Random.ChaChaDRG
+        Crypto.Random.SystemDRG
+        Crypto.Random.Probabilistic
+        Crypto.PubKey.Internal
+        Crypto.PubKey.ElGamal
+        Crypto.ECC.Simple.Types
+        Crypto.ECC.Simple.Prim
+        Crypto.Internal.Builder
+        Crypto.Internal.ByteArray
+        Crypto.Internal.Compat
+        Crypto.Internal.CompatPrim
+        Crypto.Internal.DeepSeq
+        Crypto.Internal.Imports
+        Crypto.Internal.Nat
+        Crypto.Internal.Words
+        Crypto.Internal.WordArray
 
-  if arch(x86_64)
-    CPP-options: -DARCH_X86_64
+    default-language: Haskell2010
+    include-dirs:
+        cbits cbits/ed25519 cbits/decaf/include cbits/decaf/p448
+        cbits/argon2
 
-  if flag(support_rdrand) && (arch(i386) || arch(x86_64)) && !os(windows)
-    CPP-options:    -DSUPPORT_RDRAND
-    Other-modules:  Crypto.Random.Entropy.RDRand
-    c-sources:      cbits/crypton_rdrand.c
+    ghc-options:      -Wall -fwarn-tabs -optc-O3
+    build-depends:
+        bytestring,
+        memory >=0.14.18,
+        basement >=0.0.6,
+        ghc-prim
 
-  if flag(support_aesni) && (os(linux) || os(freebsd) || os(osx)) && (arch(i386) || arch(x86_64))
-    CC-options:     -DWITH_AESNI
-    if !flag(use_target_attributes)
-      CC-options:     -mssse3 -maes
-    if flag(support_pclmuldq)
-      CC-options:   -DWITH_PCLMUL
-      if !flag(use_target_attributes)
-        CC-options:     -msse4.1 -mpclmul
-    C-sources:       cbits/aes/x86ni.c
-                   , cbits/aes/generic.c
-                   , cbits/aes/gf.c
-                   , cbits/crypton_aes.c
-  else
-    C-sources:       cbits/aes/generic.c
-                   , cbits/aes/gf.c
-                   , cbits/crypton_aes.c
+    if impl(ghc <8.8)
+        buildable: False
 
-  if arch(x86_64) || flag(support_sse)
-    C-sources:      cbits/blake2/sse/blake2s.c
-                  , cbits/blake2/sse/blake2sp.c
-                  , cbits/blake2/sse/blake2b.c
-                  , cbits/blake2/sse/blake2bp.c
-    include-dirs: cbits/blake2/sse
-  else
-    C-sources:      cbits/blake2/ref/blake2s-ref.c
-                  , cbits/blake2/ref/blake2sp-ref.c
-                  , cbits/blake2/ref/blake2b-ref.c
-                  , cbits/blake2/ref/blake2bp-ref.c
-    include-dirs: cbits/blake2/ref
+    else
+        build-depends: base
 
-  if arch(x86_64) || flag(support_sse)
-    CPP-options:    -DSUPPORT_SSE
+    if os(linux)
+        extra-libraries: pthread
+
+    if flag(old_toolchain_inliner)
+        cc-options: -fgnu89-inline
+
+    if (arch(x86_64) || arch(aarch64))
+        include-dirs: cbits/include64
+
+    else
+        include-dirs: cbits/include32
+
+    if (arch(x86_64) || arch(aarch64))
+        c-sources:
+            cbits/decaf/p448/arch_ref64/f_impl.c
+            cbits/decaf/p448/f_generic.c
+            cbits/decaf/p448/f_arithmetic.c
+            cbits/decaf/utils.c
+            cbits/decaf/ed448goldilocks/scalar.c
+            cbits/decaf/ed448goldilocks/decaf_all.c
+            cbits/decaf/ed448goldilocks/eddsa.c
+
+        include-dirs: cbits/decaf/include/arch_ref64 cbits/decaf/p448/arch_ref64
+
+    else
+        c-sources:
+            cbits/decaf/p448/arch_32/f_impl.c
+            cbits/decaf/p448/f_generic.c
+            cbits/decaf/p448/f_arithmetic.c
+            cbits/decaf/utils.c
+            cbits/decaf/ed448goldilocks/scalar.c
+            cbits/decaf/ed448goldilocks/decaf_all.c
+            cbits/decaf/ed448goldilocks/eddsa.c
+
+        include-dirs: cbits/decaf/include/arch_32 cbits/decaf/p448/arch_32
+
+    if (arch(x86_64) || arch(aarch64))
+        c-sources: cbits/curve25519/curve25519-donna-c64.c
+
+    else
+        c-sources: cbits/curve25519/curve25519-donna.c
+
+    if (arch(i386) || arch(x86_64))
+        cpp-options: -DARCH_IS_LITTLE_ENDIAN
+
     if arch(i386)
-      CC-options:   -msse2
+        cpp-options: -DARCH_X86
 
-  C-sources:      cbits/argon2/argon2.c
-  include-dirs:   cbits/argon2
+    if arch(x86_64)
+        cpp-options: -DARCH_X86_64
 
-  if os(windows)
-    cpp-options:    -DWINDOWS
-    Build-Depends:  Win32
-    Other-modules:  Crypto.Random.Entropy.Windows
-    extra-libraries: advapi32
-  else
-    Other-modules:  Crypto.Random.Entropy.Unix
+    if ((flag(support_rdrand) && (arch(i386) || arch(x86_64))) && !os(windows))
+        cpp-options:   -DSUPPORT_RDRAND
+        c-sources:     cbits/crypton_rdrand.c
+        other-modules: Crypto.Random.Entropy.RDRand
 
-  if impl(ghc) && flag(integer-gmp)
-    Build-depends:   integer-gmp
+    if ((flag(support_aesni) && ((os(linux) || os(freebsd)) || os(osx))) && (arch(i386) || arch(x86_64)))
+        cc-options: -DWITH_AESNI
+        c-sources:
+            cbits/aes/x86ni.c
+            cbits/aes/generic.c
+            cbits/aes/gf.c
+            cbits/crypton_aes.c
 
-  if flag(support_deepseq)
-    CPP-options:     -DWITH_DEEPSEQ_SUPPORT
-    Build-depends:   deepseq
-  if flag(check_alignment)
-    cc-options:     -DWITH_ASSERT_ALIGNMENT
-  if flag(use_target_attributes)
-    cc-options:     -DWITH_TARGET_ATTRIBUTES
+        if !flag(use_target_attributes)
+            cc-options: -mssse3 -maes
 
-Test-Suite test-crypton
-  type:              exitcode-stdio-1.0
-  hs-source-dirs:    tests
-  Main-is:           Tests.hs
-  Other-modules:     BlockCipher
-                     ChaCha
-                     BCrypt
-                     BCryptPBKDF
-                     ECC
-                     ECC.Edwards25519
-                     ECDSA
-                     Hash
-                     Imports
-                     KAT_AES.KATCBC
-                     KAT_AES.KATECB
-                     KAT_AES.KATGCM
-                     KAT_AES.KATCCM
-                     KAT_AES.KATOCB3
-                     KAT_AES.KATXTS
-                     KAT_AES
-                     KAT_AESGCMSIV
-                     KAT_AFIS
-                     KAT_Argon2
-                     KAT_Blowfish
-                     KAT_CAST5
-                     KAT_Camellia
-                     KAT_Curve25519
-                     KAT_Curve448
-                     KAT_DES
-                     KAT_Ed25519
-                     KAT_Ed448
-                     KAT_EdDSA
-                     KAT_CMAC
-                     KAT_HKDF
-                     KAT_HMAC
-                     KAT_KMAC
-                     KAT_MiyaguchiPreneel
-                     KAT_PBKDF2
-                     KAT_OTP
-                     KAT_PubKey.DSA
-                     KAT_PubKey.ECC
-                     KAT_PubKey.ECDSA
-                     KAT_PubKey.OAEP
-                     KAT_PubKey.PSS
-                     KAT_PubKey.P256
-                     KAT_PubKey.RSA
-                     KAT_PubKey.Rabin
-                     KAT_PubKey
-                     KAT_RC4
-                     KAT_Scrypt
-                     KAT_TripleDES
-                     KAT_Twofish
-                     ChaChaPoly1305
-                     Number
-                     Number.F2m
-                     Padding
-                     Poly1305
-                     Salsa
-                     Utils
-                     XSalsa
-  Build-Depends:     base >= 0 && < 10
-                   , bytestring
-                   , memory
-                   , tasty
-                   , tasty-quickcheck
-                   , tasty-hunit
-                   , tasty-kat
-                   , crypton
-  ghc-options:       -Wall -fno-warn-orphans -fno-warn-missing-signatures -rtsopts
-  default-language:  Haskell2010
+        if flag(support_pclmuldq)
+            cc-options: -DWITH_PCLMUL
 
-Benchmark bench-crypton
-  type:              exitcode-stdio-1.0
-  hs-source-dirs:    benchs
-  Main-is:           Bench.hs
-  Other-modules:     Number.F2m
-  Build-Depends:     base
-                   , bytestring
-                   , deepseq
-                   , memory
-                   , gauge
-                   , random
-                   , crypton
-  ghc-options:       -Wall -fno-warn-missing-signatures
-  default-language:  Haskell2010
+            if !flag(use_target_attributes)
+                cc-options: -msse4.1 -mpclmul
+
+    else
+        c-sources:
+            cbits/aes/generic.c
+            cbits/aes/gf.c
+            cbits/crypton_aes.c
+
+    if (arch(x86_64) || flag(support_sse))
+        c-sources:
+            cbits/blake2/sse/blake2s.c
+            cbits/blake2/sse/blake2sp.c
+            cbits/blake2/sse/blake2b.c
+            cbits/blake2/sse/blake2bp.c
+
+        include-dirs: cbits/blake2/sse
+
+    else
+        c-sources:
+            cbits/blake2/ref/blake2s-ref.c
+            cbits/blake2/ref/blake2sp-ref.c
+            cbits/blake2/ref/blake2b-ref.c
+            cbits/blake2/ref/blake2bp-ref.c
+
+        include-dirs: cbits/blake2/ref
+
+    if (arch(x86_64) || flag(support_sse))
+        cpp-options: -DSUPPORT_SSE
+
+        if arch(i386)
+            cc-options: -msse2
+
+    if os(windows)
+        cpp-options:     -DWINDOWS
+        other-modules:   Crypto.Random.Entropy.Windows
+        extra-libraries: advapi32
+        build-depends:   Win32
+
+    else
+        other-modules: Crypto.Random.Entropy.Unix
+
+    if (impl(ghc >=0) && flag(integer-gmp))
+        build-depends: integer-gmp
+
+    if flag(support_deepseq)
+        cpp-options:   -DWITH_DEEPSEQ_SUPPORT
+        build-depends: deepseq
+
+    if flag(check_alignment)
+        cc-options: -DWITH_ASSERT_ALIGNMENT
+
+    if flag(use_target_attributes)
+        cc-options: -DWITH_TARGET_ATTRIBUTES
+
+test-suite test-crypton
+    type:             exitcode-stdio-1.0
+    main-is:          Tests.hs
+    hs-source-dirs:   tests
+    other-modules:
+        BlockCipher
+        ChaCha
+        BCrypt
+        BCryptPBKDF
+        ECC
+        ECC.Edwards25519
+        ECDSA
+        Hash
+        Imports
+        KAT_AES.KATCBC
+        KAT_AES.KATECB
+        KAT_AES.KATGCM
+        KAT_AES.KATCCM
+        KAT_AES.KATOCB3
+        KAT_AES.KATXTS
+        KAT_AES
+        KAT_AESGCMSIV
+        KAT_AFIS
+        KAT_Argon2
+        KAT_Blowfish
+        KAT_CAST5
+        KAT_Camellia
+        KAT_Curve25519
+        KAT_Curve448
+        KAT_DES
+        KAT_Ed25519
+        KAT_Ed448
+        KAT_EdDSA
+        KAT_Blake2
+        KAT_CMAC
+        KAT_HKDF
+        KAT_HMAC
+        KAT_KMAC
+        KAT_MiyaguchiPreneel
+        KAT_PBKDF2
+        KAT_OTP
+        KAT_PubKey.DSA
+        KAT_PubKey.ECC
+        KAT_PubKey.ECDSA
+        KAT_PubKey.OAEP
+        KAT_PubKey.PSS
+        KAT_PubKey.P256
+        KAT_PubKey.RSA
+        KAT_PubKey.Rabin
+        KAT_PubKey
+        KAT_RC4
+        KAT_Scrypt
+        KAT_TripleDES
+        KAT_Twofish
+        ChaChaPoly1305
+        Number
+        Number.F2m
+        Padding
+        Poly1305
+        Salsa
+        Utils
+        XSalsa
+
+    default-language: Haskell2010
+    ghc-options:
+        -Wall -fno-warn-orphans -fno-warn-missing-signatures -rtsopts
+
+    build-depends:
+        base >=0 && <10,
+        bytestring,
+        memory,
+        tasty,
+        tasty-quickcheck,
+        tasty-hunit,
+        tasty-kat,
+        crypton
+
+benchmark bench-crypton
+    type:             exitcode-stdio-1.0
+    main-is:          Bench.hs
+    hs-source-dirs:   benchs
+    other-modules:    Number.F2m
+    default-language: Haskell2010
+    ghc-options:      -Wall -fno-warn-missing-signatures
+    build-depends:
+        base,
+        bytestring,
+        deepseq,
+        memory,
+        gauge,
+        random,
+        crypton
diff --git a/tests/ChaCha.hs b/tests/ChaCha.hs
--- a/tests/ChaCha.hs
+++ b/tests/ChaCha.hs
@@ -23,6 +23,18 @@
 b20_256_k0_i0 =
     "\x76\xb8\xe0\xad\xa0\xf1\x3d\x90\x40\x5d\x6a\xe5\x53\x86\xbd\x28\xbd\xd2\x19\xb8\xa0\x8d\xed\x1a\xa8\x36\xef\xcc\x8b\x77\x0d\xc7\xda\x41\x59\x7c\x51\x57\x48\x8d\x77\x24\xe0\x3f\xb8\xd8\x4a\x37\x6a\x43\xb8\xf4\x15\x18\xa1\x1c\xc3\x87\xb6\x69\xb2\xee\x65\x86\x9f\x07\xe7\xbe\x55\x51\x38\x7a\x98\xba\x97\x7c\x73\x2d\x08\x0d\xcb\x0f\x29\xa0\x48\xe3\x65\x69\x12\xc6\x53\x3e\x32\xee\x7a\xed\x29\xb7\x21\x76\x9c\xe6\x4e\x43\xd5\x71\x33\xb0\x74\xd8\x39\xd5\x31\xed\x1f\x28\x51\x0a\xfb\x45\xac\xe1\x0a\x1f\x4b\x79\x4d\x6f"
 
+-- XChaCha20 test vector from RFC draft: https://datatracker.ietf.org/doc/html/draft-arciszewski-xchacha
+
+xChaCha20_ExampleKAT = expected @=? fst (ChaCha.combine initState plaintext)
+    where iv = B.pack $ [0x40 .. 0x56] ++ [0x58]
+          key = B.pack [0x80 .. 0x9f]
+          initState = ChaCha.initializeX 20 key iv
+          plaintext :: B.ByteString
+          plaintext = "The dhole (pronounced \"dole\") is also known as the Asiatic wild dog, red dog, and whistling dog. It is about the size of a German shepherd but looks more like a long-legged fox. This highly elusive and skilled jumper is classified with wolves, coyotes, jackals, and foxes in the taxonomic family Canidae."
+          expected :: B.ByteString
+          expected = "\x45\x59\xab\xba\x4e\x48\xc1\x61\x02\xe8\xbb\x2c\x05\xe6\x94\x7f\x50\xa7\x86\xde\x16\x2f\x9b\x0b\x7e\x59\x2a\x9b\x53\xd0\xd4\xe9\x8d\x8d\x64\x10\xd5\x40\xa1\xa6\x37\x5b\x26\xd8\x0d\xac\xe4\xfa\xb5\x23\x84\xc7\x31\xac\xbf\x16\xa5\x92\x3c\x0c\x48\xd3\x57\x5d\x4d\x0d\x2c\x67\x3b\x66\x6f\xaa\x73\x10\x61\x27\x77\x01\x09\x3a\x6b\xf7\xa1\x58\xa8\x86\x42\x92\xa4\x1c\x48\xe3\xa9\xb4\xc0\xda\xec\xe0\xf8\xd9\x8d\x0d\x7e\x05\xb3\x7a\x30\x7b\xbb\x66\x33\x31\x64\xec\x9e\x1b\x24\xea\x0d\x6c\x3f\xfd\xdc\xec\x4f\x68\xe7\x44\x30\x56\x19\x3a\x03\xc8\x10\xe1\x13\x44\xca\x06\xd8\xed\x8a\x2b\xfb\x1e\x8d\x48\xcf\xa6\xbc\x0e\xb4\xe2\x46\x4b\x74\x81\x42\x40\x7c\x9f\x43\x1a\xee\x76\x99\x60\xe1\x5b\xa8\xb9\x68\x90\x46\x6e\xf2\x45\x75\x99\x85\x23\x85\xc6\x61\xf7\x52\xce\x20\xf9\xda\x0c\x09\xab\x6b\x19\xdf\x74\xe7\x6a\x95\x96\x74\x46\xf8\xd0\xfd\x41\x5e\x7b\xee\x2a\x12\xa1\x14\xc2\x0e\xb5\x29\x2a\xe7\xa3\x49\xae\x57\x78\x20\xd5\x52\x0a\x1f\x3f\xb6\x2a\x17\xce\x6a\x7e\x68\xfa\x7c\x79\x11\x1d\x88\x60\x92\x0b\xc0\x48\xef\x43\xfe\x84\x48\x6c\xcb\x87\xc2\x5f\x0a\xe0\x45\xf0\xcc\xe1\xe7\x98\x9a\x9a\xa2\x20\xa2\x8b\xdd\x48\x27\xe7\x51\xa2\x4a\x6d\x5c\x62\xd7\x90\xa6\x63\x93\xb9\x31\x11\xc1\xa5\x5d\xd7\x42\x1a\x10\x18\x49\x74\xc7\xc5"
+
+
 data Vector = Vector Int -- rounds
                      ByteString -- key
                      ByteString -- nonce
@@ -38,6 +50,7 @@
     , testCase "8-256-K0-I0"  (chachaRunSimple b8_256_k0_i0 8 32 8)
     , testCase "12-256-K0-I0" (chachaRunSimple b12_256_k0_i0 12 32 8)
     , testCase "20-256-K0-I0" (chachaRunSimple b20_256_k0_i0 20 32 8)
+    , testCase "XChaCha20 example KAT" xChaCha20_ExampleKAT
     , testProperty "generate-combine" chachaGenerateCombine
     , testProperty "chunking-generate" chachaGenerateChunks
     , testProperty "chunking-combine" chachaCombineChunks
diff --git a/tests/ChaChaPoly1305.hs b/tests/ChaChaPoly1305.hs
--- a/tests/ChaChaPoly1305.hs
+++ b/tests/ChaChaPoly1305.hs
@@ -9,14 +9,17 @@
 import qualified Data.ByteString as B
 import qualified Data.ByteArray as B (convert)
 
-plaintext, aad, key, iv, ciphertext, tag, nonce1, nonce2, nonce3, nonce4, nonce5, nonce6, nonce7, nonce8, nonce9, nonce10 :: B.ByteString
+plaintext, aad, key, iv, ivX, ciphertext, ciphertextX, tag, tagX, nonce1, nonce2, nonce3, nonce4, nonce5, nonce6, nonce7, nonce8, nonce9, nonce10 :: B.ByteString
 plaintext = "Ladies and Gentlemen of the class of '99: If I could offer you only one tip for the future, sunscreen would be it."
 aad = "\x50\x51\x52\x53\xc0\xc1\xc2\xc3\xc4\xc5\xc6\xc7"
 key = "\x80\x81\x82\x83\x84\x85\x86\x87\x88\x89\x8a\x8b\x8c\x8d\x8e\x8f\x90\x91\x92\x93\x94\x95\x96\x97\x98\x99\x9a\x9b\x9c\x9d\x9e\x9f"
 iv = "\x40\x41\x42\x43\x44\x45\x46\x47"
+ivX = B.pack [0x40 .. 0x57]
 constant = "\x07\x00\x00\x00"
 ciphertext = "\xd3\x1a\x8d\x34\x64\x8e\x60\xdb\x7b\x86\xaf\xbc\x53\xef\x7e\xc2\xa4\xad\xed\x51\x29\x6e\x08\xfe\xa9\xe2\xb5\xa7\x36\xee\x62\xd6\x3d\xbe\xa4\x5e\x8c\xa9\x67\x12\x82\xfa\xfb\x69\xda\x92\x72\x8b\x1a\x71\xde\x0a\x9e\x06\x0b\x29\x05\xd6\xa5\xb6\x7e\xcd\x3b\x36\x92\xdd\xbd\x7f\x2d\x77\x8b\x8c\x98\x03\xae\xe3\x28\x09\x1b\x58\xfa\xb3\x24\xe4\xfa\xd6\x75\x94\x55\x85\x80\x8b\x48\x31\xd7\xbc\x3f\xf4\xde\xf0\x8e\x4b\x7a\x9d\xe5\x76\xd2\x65\x86\xce\xc6\x4b\x61\x16"
+ciphertextX = "\xbd\x6d\x17\x9d\x3e\x83\xd4\x3b\x95\x76\x57\x94\x93\xc0\xe9\x39\x57\x2a\x17\x00\x25\x2b\xfa\xcc\xbe\xd2\x90\x2c\x21\x39\x6c\xbb\x73\x1c\x7f\x1b\x0b\x4a\xa6\x44\x0b\xf3\xa8\x2f\x4e\xda\x7e\x39\xae\x64\xc6\x70\x8c\x54\xc2\x16\xcb\x96\xb7\x2e\x12\x13\xb4\x52\x2f\x8c\x9b\xa4\x0d\xb5\xd9\x45\xb1\x1b\x69\xb9\x82\xc1\xbb\x9e\x3f\x3f\xac\x2b\xc3\x69\x48\x8f\x76\xb2\x38\x35\x65\xd3\xff\xf9\x21\xf9\x66\x4c\x97\x63\x7d\xa9\x76\x88\x12\xf6\x15\xc6\x8b\x13\xb5\x2e"
 tag = "\x1a\xe1\x0b\x59\x4f\x09\xe2\x6a\x7e\x90\x2e\xcb\xd0\x60\x06\x91"
+tagX = "\xc0\x87\x59\x24\xc1\xc7\x98\x79\x47\xde\xaf\xd8\x78\x0a\xcf\x49"
 nonce1  = "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"
 nonce2  = "\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"
 nonce3  = "\xff\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"
@@ -31,6 +34,8 @@
 tests = testGroup "ChaChaPoly1305"
     [ testCase "V1" runEncrypt
     , testCase "V1-decrypt" runDecrypt
+    , testCase "V1-extended" runEncryptX
+    , testCase "V1-extended-decrypt" runDecryptX
     , testCase "nonce increment" runNonceInc
     ]
   where runEncrypt =
@@ -41,6 +46,14 @@
              in propertyHoldCase [ eqTest "ciphertext" ciphertext out
                                  , eqTest "tag" tag (B.convert outtag)
                                  ]
+        runEncryptX =
+            let ini                 = throwCryptoError $ AEAD.initializeX key (throwCryptoError $ AEAD.nonce24 ivX)
+                afterAAD            = AEAD.finalizeAAD (AEAD.appendAAD aad ini)
+                (out, afterEncrypt) = AEAD.encrypt plaintext afterAAD
+                outtag              = AEAD.finalize afterEncrypt
+             in propertyHoldCase [ eqTest "ciphertext" ciphertextX out
+                                 , eqTest "tag" tagX (B.convert outtag)
+                                 ]
 
         runDecrypt =
             let ini                 = throwCryptoError $ AEAD.initialize key (throwCryptoError $ AEAD.nonce8 constant iv)
@@ -49,6 +62,15 @@
                 outtag              = AEAD.finalize afterDecrypt
              in propertyHoldCase [ eqTest "plaintext" plaintext out
                                  , eqTest "tag" tag (B.convert outtag)
+                                 ]
+
+        runDecryptX =
+            let ini                 = throwCryptoError $ AEAD.initializeX key (throwCryptoError $ AEAD.nonce24 ivX)
+                afterAAD            = AEAD.finalizeAAD (AEAD.appendAAD aad ini)
+                (out, afterDecrypt) = AEAD.decrypt ciphertextX afterAAD
+                outtag              = AEAD.finalize afterDecrypt
+             in propertyHoldCase [ eqTest "plaintext" plaintext out
+                                 , eqTest "tag" tagX (B.convert outtag)
                                  ]
 
         runNonceInc =
diff --git a/tests/KAT_Blake2.hs b/tests/KAT_Blake2.hs
new file mode 100644
--- /dev/null
+++ b/tests/KAT_Blake2.hs
@@ -0,0 +1,166 @@
+{-# LANGUAGE DataKinds #-}
+{-# LANGUAGE OverloadedStrings #-}
+{-# LANGUAGE RecordWildCards #-}
+module KAT_Blake2 (tests) where
+
+import           Crypto.Hash (digestFromByteString)
+import           Crypto.Hash.Algorithms
+import qualified Crypto.MAC.KeyedBlake2 as KB
+
+import qualified Data.ByteString as B
+
+import Imports
+
+
+data MACVector hash = MACVector
+    { macMessage :: ByteString
+    , macKey    :: ByteString
+    , macResult :: KB.KeyedBlake2 hash
+    }
+
+instance Show (KB.KeyedBlake2 hash) where
+    show (KB.KeyedBlake2 d) = show d
+
+digest :: KB.HashBlake2 hash => ByteString -> KB.KeyedBlake2 hash
+digest = maybe (error "cannot get digest") KB.KeyedBlake2 . digestFromByteString
+
+
+-- From: https://github.com/BLAKE2/BLAKE2/blob/master/testvectors/
+vectorsBlake2bKAT :: [MACVector (Blake2b 512)]
+vectorsBlake2bKAT =
+    [ MACVector
+        { macMessage = ""
+        , macKey     = fixedKey
+        , macResult  = digest "\x10\xeb\xb6\x77\x00\xb1\x86\x8e\xfb\x44\x17\x98\x7a\xcf\x46\x90\xae\x9d\x97\x2f\xb7\xa5\x90\xc2\xf0\x28\x71\x79\x9a\xaa\x47\x86\xb5\xe9\x96\xe8\xf0\xf4\xeb\x98\x1f\xc2\x14\xb0\x05\xf4\x2d\x2f\xf4\x23\x34\x99\x39\x16\x53\xdf\x7a\xef\xcb\xc1\x3f\xc5\x15\x68"
+        }
+    , MACVector
+        { macMessage = "\x00"
+        , macKey     = fixedKey
+        , macResult  = digest "\x96\x1f\x6d\xd1\xe4\xdd\x30\xf6\x39\x01\x69\x0c\x51\x2e\x78\xe4\xb4\x5e\x47\x42\xed\x19\x7c\x3c\x5e\x45\xc5\x49\xfd\x25\xf2\xe4\x18\x7b\x0b\xc9\xfe\x30\x49\x2b\x16\xb0\xd0\xbc\x4e\xf9\xb0\xf3\x4c\x70\x03\xfa\xc0\x9a\x5e\xf1\x53\x2e\x69\x43\x02\x34\xce\xbd"
+        }
+    , MACVector
+        { macMessage = B.pack [ 0x00 .. 0xfe ]
+        , macKey     = fixedKey
+        , macResult  = digest "\x14\x27\x09\xd6\x2e\x28\xfc\xcc\xd0\xaf\x97\xfa\xd0\xf8\x46\x5b\x97\x1e\x82\x20\x1d\xc5\x10\x70\xfa\xa0\x37\x2a\xa4\x3e\x92\x48\x4b\xe1\xc1\xe7\x3b\xa1\x09\x06\xd5\xd1\x85\x3d\xb6\xa4\x10\x6e\x0a\x7b\xf9\x80\x0d\x37\x3d\x6d\xee\x2d\x46\xd6\x2e\xf2\xa4\x61"
+        }
+    ]
+    where fixedKey = B.pack [ 0x00 .. 0x3f ]
+
+vectorsBlake2bpKAT :: [MACVector (Blake2bp 512)]
+vectorsBlake2bpKAT =
+    [ MACVector
+        { macMessage = ""
+        , macKey     = fixedKey
+        , macResult  = digest "\x9d\x94\x61\x07\x3e\x4e\xb6\x40\xa2\x55\x35\x7b\x83\x9f\x39\x4b\x83\x8c\x6f\xf5\x7c\x9b\x68\x6a\x3f\x76\x10\x7c\x10\x66\x72\x8f\x3c\x99\x56\xbd\x78\x5c\xbc\x3b\xf7\x9d\xc2\xab\x57\x8c\x5a\x0c\x06\x3b\x9d\x9c\x40\x58\x48\xde\x1d\xbe\x82\x1c\xd0\x5c\x94\x0a"
+        }
+    , MACVector
+        { macMessage = "\x00"
+        , macKey     = fixedKey
+        , macResult  = digest "\xff\x8e\x90\xa3\x7b\x94\x62\x39\x32\xc5\x9f\x75\x59\xf2\x60\x35\x02\x9c\x37\x67\x32\xcb\x14\xd4\x16\x02\x00\x1c\xbb\x73\xad\xb7\x92\x93\xa2\xdb\xda\x5f\x60\x70\x30\x25\x14\x4d\x15\x8e\x27\x35\x52\x95\x96\x25\x1c\x73\xc0\x34\x5c\xa6\xfc\xcb\x1f\xb1\xe9\x7e"
+        }
+    , MACVector
+        { macMessage = B.pack [ 0x00 .. 0xfe ]
+        , macKey     = fixedKey
+        , macResult  = digest "\x96\xfb\xcb\xb6\x0b\xd3\x13\xb8\x84\x50\x33\xe5\xbc\x05\x8a\x38\x02\x74\x38\x57\x2d\x7e\x79\x57\xf3\x68\x4f\x62\x68\xaa\xdd\x3a\xd0\x8d\x21\x76\x7e\xd6\x87\x86\x85\x33\x1b\xa9\x85\x71\x48\x7e\x12\x47\x0a\xad\x66\x93\x26\x71\x6e\x46\x66\x7f\x69\xf8\xd7\xe8"
+        }
+    ]
+    where fixedKey = B.pack [ 0x00 .. 0x3f ]
+
+vectorsBlake2sKAT :: [MACVector (Blake2s 256)]
+vectorsBlake2sKAT =
+    [ MACVector
+        { macMessage = ""
+        , macKey     = fixedKey
+        , macResult  = digest "\x48\xa8\x99\x7d\xa4\x07\x87\x6b\x3d\x79\xc0\xd9\x23\x25\xad\x3b\x89\xcb\xb7\x54\xd8\x6a\xb7\x1a\xee\x04\x7a\xd3\x45\xfd\x2c\x49"
+        }
+    , MACVector
+        { macMessage = "\x00"
+        , macKey     = fixedKey
+        , macResult  = digest "\x40\xd1\x5f\xee\x7c\x32\x88\x30\x16\x6a\xc3\xf9\x18\x65\x0f\x80\x7e\x7e\x01\xe1\x77\x25\x8c\xdc\x0a\x39\xb1\x1f\x59\x80\x66\xf1"
+        }
+    , MACVector
+        { macMessage = B.pack [ 0x00 .. 0xfe ]
+        , macKey     = fixedKey
+        , macResult  = digest "\x3f\xb7\x35\x06\x1a\xbc\x51\x9d\xfe\x97\x9e\x54\xc1\xee\x5b\xfa\xd0\xa9\xd8\x58\xb3\x31\x5b\xad\x34\xbd\xe9\x99\xef\xd7\x24\xdd"
+        }
+    ]
+    where fixedKey = B.pack [ 0x00 .. 0x1f ]
+
+vectorsBlake2spKAT :: [MACVector (Blake2sp 256)]
+vectorsBlake2spKAT =
+    [ MACVector
+        { macMessage = ""
+        , macKey     = fixedKey
+        , macResult  = digest "\x71\x5c\xb1\x38\x95\xae\xb6\x78\xf6\x12\x41\x60\xbf\xf2\x14\x65\xb3\x0f\x4f\x68\x74\x19\x3f\xc8\x51\xb4\x62\x10\x43\xf0\x9c\xc6"
+        }
+    , MACVector
+        { macMessage = "\x00"
+        , macKey     = fixedKey
+        , macResult  = digest "\x40\x57\x8f\xfa\x52\xbf\x51\xae\x18\x66\xf4\x28\x4d\x3a\x15\x7f\xc1\xbc\xd3\x6a\xc1\x3c\xbd\xcb\x03\x77\xe4\xd0\xcd\x0b\x66\x03"
+        }
+    , MACVector
+        { macMessage = B.pack [ 0x00 .. 0xfe ]
+        , macKey     = fixedKey
+        , macResult  = digest "\x0c\x8a\x36\x59\x7d\x74\x61\xc6\x3a\x94\x73\x28\x21\xc9\x41\x85\x6c\x66\x83\x76\x60\x6c\x86\xa5\x2d\xe0\xee\x41\x04\xc6\x15\xdb"
+        }
+    ]
+    where fixedKey = B.pack [ 0x00 .. 0x1f ]
+
+macTests :: [TestTree]
+macTests =
+    [ testGroup "Blake2b_512" (concatMap toMACTest $ zip is vectorsBlake2bKAT)
+    , testGroup "Blake2bp_512" (concatMap toMACTest $ zip is vectorsBlake2bpKAT)
+    , testGroup "Blake2s_512" (concatMap toMACTest $ zip is vectorsBlake2sKAT)
+    , testGroup "Blake2sp_512" (concatMap toMACTest $ zip is vectorsBlake2spKAT)
+    ]
+    where toMACTest (i, MACVector{..}) =
+            [ testCase (show i) (macResult @=? KB.keyedBlake2 macKey macMessage)
+            , testCase ("incr-" ++ show i) (macResult @=?
+                        KB.finalize (KB.update (KB.initialize macKey) macMessage))
+            ]
+          is :: [Int]
+          is = [1..]
+
+data MacIncremental a = MacIncremental ByteString ByteString (KB.KeyedBlake2 a)
+    deriving (Show,Eq)
+
+instance KB.HashBlake2 a => Arbitrary (MacIncremental a) where
+    arbitrary = do
+        key <- arbitraryBSof 32 64
+        msg <- arbitraryBSof 1 99
+        return $ MacIncremental key msg (KB.keyedBlake2 key msg)
+
+data MacIncrementalList a = MacIncrementalList ByteString [ByteString] (KB.KeyedBlake2 a)
+    deriving (Show,Eq)
+
+instance KB.HashBlake2 a => Arbitrary (MacIncrementalList a) where
+    arbitrary = do
+        key <- arbitraryBSof 32 64
+        msgs <- choose (1,20) >>= \n -> replicateM n (arbitraryBSof 1 99)
+        return $ MacIncrementalList key msgs (KB.keyedBlake2 key (B.concat msgs))
+
+macIncrementalTests :: [TestTree]
+macIncrementalTests =
+    [ testIncrProperties "Blake2b_512" (Blake2b :: Blake2b 512)
+    , testIncrProperties "Blake2bp_512" (Blake2bp :: Blake2bp 512)
+    , testIncrProperties "Blake2s_256" (Blake2s :: Blake2s 256)
+    , testIncrProperties "Blake2sp_256" (Blake2sp :: Blake2sp 256)
+    ]
+  where
+        testIncrProperties :: KB.HashBlake2 a => TestName -> a -> TestTree
+        testIncrProperties name a = testGroup name
+            [ testProperty "list-one" (prop_inc0 a)
+            , testProperty "list-multi" (prop_inc1 a)
+            ]
+
+        prop_inc0 :: KB.HashBlake2 a => a -> MacIncremental a -> Bool
+        prop_inc0 _ (MacIncremental secret msg result) =
+            result `assertEq` KB.finalize (KB.update (KB.initialize secret) msg)
+
+        prop_inc1 :: KB.HashBlake2 a => a -> MacIncrementalList a -> Bool
+        prop_inc1 _ (MacIncrementalList secret msgs result) =
+            result `assertEq` KB.finalize (foldl' KB.update (KB.initialize secret) msgs)
+
+tests = testGroup "Blake2"
+    [ testGroup "KATs" macTests
+    , testGroup "properties" macIncrementalTests ]
diff --git a/tests/Tests.hs b/tests/Tests.hs
--- a/tests/Tests.hs
+++ b/tests/Tests.hs
@@ -19,6 +19,7 @@
 import qualified ChaCha
 import qualified ChaChaPoly1305
 import qualified KAT_MiyaguchiPreneel
+import qualified KAT_Blake2
 import qualified KAT_CMAC
 import qualified KAT_HMAC
 import qualified KAT_KMAC
@@ -60,6 +61,7 @@
         ]
     , testGroup "MAC"
         [ Poly1305.tests
+        , KAT_Blake2.tests
         , KAT_CMAC.tests
         , KAT_HMAC.tests
         , KAT_KMAC.tests
