diff --git a/CHANGELOG.md b/CHANGELOG.md
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,3 +1,14 @@
+## 0.11
+
+* Truncate hashing correctly for DSA
+* Add support for HKDF (RFC 5869)
+* Add support for Ed448
+* Extends support for Blake2s to 224 bits version.
+* Compilation workaround for old distribution (RHEL 4.1)
+* Compilation fix for AIX
+* Compilation fix with AESNI and ghci compiling C source in a weird order.
+* Fix example compilation, typo, and warning
+
 ## 0.10
 
 * Add reference implementation of blake2 for non-SSE2 platform
diff --git a/Crypto/Cipher/ChaChaPoly1305.hs b/Crypto/Cipher/ChaChaPoly1305.hs
--- a/Crypto/Cipher/ChaChaPoly1305.hs
+++ b/Crypto/Cipher/ChaChaPoly1305.hs
@@ -5,7 +5,8 @@
 -- Stability   : stable
 -- Portability : good
 --
--- A simple AEAD scheme using ChaCha20 and Poly1305. See RFC7539.
+-- A simple AEAD scheme using ChaCha20 and Poly1305. See
+-- <https://tools.ietf.org/html/rfc7539 RFC 7539>.
 --
 -- The State is not modified in place, so each function changing the State,
 -- returns a new State.
@@ -15,12 +16,24 @@
 --
 -- Once 'finalizeAAD' has been called, no further 'appendAAD' call should be make.
 --
--- > encrypt nonce key hdr inp =
--- >    let st1        = ChaChaPoly1305.initialize key nonce
--- >        st2        = ChaChaPoly1305.finalizeAAD $ ChaChaPoly1305.appendAAD hdr st1
--- >        (out, st3) = ChaChaPoly1305.encrypt inp st2
--- >        auth       = ChaChaPoly1305.finalize st3
--- >     in out `B.append` Data.ByteArray.convert auth
+-- >import Data.ByteString.Char8 as B
+-- >import Data.ByteArray
+-- >import Crypto.Error
+-- >import Crypto.Cipher.ChaChaPoly1305 as C
+-- >
+-- >encrypt
+-- >    :: ByteString -- nonce (12 random bytes)
+-- >    -> ByteString -- symmetric key
+-- >    -> ByteString -- optional associated data (won't be encrypted)
+-- >    -> ByteString -- input plaintext to be encrypted
+-- >    -> CryptoFailable ByteString -- ciphertext with a 128-bit tag attached
+-- >encrypt nonce key header plaintext = do
+-- >    st1 <- C.nonce12 nonce >>= C.initialize key
+-- >    let
+-- >        st2 = C.finalizeAAD $ C.appendAAD header st1
+-- >        (out, st3) = C.encrypt plaintext st2
+-- >        auth = C.finalize st3
+-- >    return $ out `B.append` Data.ByteArray.convert auth
 --
 module Crypto.Cipher.ChaChaPoly1305
     ( State
diff --git a/Crypto/Hash/Algorithms.hs b/Crypto/Hash/Algorithms.hs
--- a/Crypto/Hash/Algorithms.hs
+++ b/Crypto/Hash/Algorithms.hs
@@ -11,6 +11,8 @@
 module Crypto.Hash.Algorithms
     ( HashAlgorithm
     -- * hash algorithms
+    , Blake2s_224(..)
+    , Blake2sp_224(..)
     , Blake2s_256(..)
     , Blake2sp_256(..)
     , Blake2b_512(..)
diff --git a/Crypto/Hash/Blake2s.hs b/Crypto/Hash/Blake2s.hs
--- a/Crypto/Hash/Blake2s.hs
+++ b/Crypto/Hash/Blake2s.hs
@@ -10,13 +10,25 @@
 --
 {-# LANGUAGE ForeignFunctionInterface #-}
 module Crypto.Hash.Blake2s
-    (  Blake2s_256 (..)
+    (  Blake2s_224 (..), Blake2s_256 (..)
     ) where
 
 import           Crypto.Hash.Types
 import           Foreign.Ptr (Ptr)
 import           Data.Word (Word8, Word32)
 
+
+-- | Blake2s (224 bits) cryptographic hash algorithm
+data Blake2s_224 = Blake2s_224
+    deriving (Show)
+
+instance HashAlgorithm Blake2s_224 where
+    hashBlockSize  _          = 64
+    hashDigestSize _          = 28
+    hashInternalContextSize _ = 185
+    hashInternalInit p        = c_blake2s_init p 224
+    hashInternalUpdate        = c_blake2s_update
+    hashInternalFinalize p    = c_blake2s_finalize p 224
 
 -- | Blake2s (256 bits) cryptographic hash algorithm
 data Blake2s_256 = Blake2s_256
diff --git a/Crypto/Hash/Blake2sp.hs b/Crypto/Hash/Blake2sp.hs
--- a/Crypto/Hash/Blake2sp.hs
+++ b/Crypto/Hash/Blake2sp.hs
@@ -10,13 +10,25 @@
 --
 {-# LANGUAGE ForeignFunctionInterface #-}
 module Crypto.Hash.Blake2sp
-    (  Blake2sp_256 (..)
+    (  Blake2sp_224 (..), Blake2sp_256 (..)
     ) where
 
 import           Crypto.Hash.Types
 import           Foreign.Ptr (Ptr)
 import           Data.Word (Word8, Word32)
 
+
+-- | Blake2sp (224 bits) cryptographic hash algorithm
+data Blake2sp_224 = Blake2sp_224
+    deriving (Show)
+
+instance HashAlgorithm Blake2sp_224 where
+    hashBlockSize  _          = 64
+    hashDigestSize _          = 28
+    hashInternalContextSize _ = 2185
+    hashInternalInit p        = c_blake2sp_init p 224
+    hashInternalUpdate        = c_blake2sp_update
+    hashInternalFinalize p    = c_blake2sp_finalize p 224
 
 -- | Blake2sp (256 bits) cryptographic hash algorithm
 data Blake2sp_256 = Blake2sp_256
diff --git a/Crypto/KDF/HKDF.hs b/Crypto/KDF/HKDF.hs
new file mode 100644
--- /dev/null
+++ b/Crypto/KDF/HKDF.hs
@@ -0,0 +1,77 @@
+-- |
+-- Module      : Crypto.KDF.HKDF
+-- License     : BSD-style
+-- Maintainer  : Vincent Hanquez <vincent@snarc.org>
+-- Stability   : experimental
+-- Portability : unknown
+--
+-- Key Derivation Function based on HMAC
+--
+-- See rfc5869
+--
+{-# LANGUAGE BangPatterns #-}
+{-# LANGUAGE GeneralizedNewtypeDeriving #-}
+module Crypto.KDF.HKDF
+    ( PRK
+    , extract
+    , extractSkip
+    , expand
+    ) where
+
+import           Data.Word
+import           Crypto.Hash 
+import           Crypto.MAC.HMAC
+import           Crypto.Internal.ByteArray (ScrubbedBytes, Bytes, ByteArray, ByteArrayAccess)
+import qualified Crypto.Internal.ByteArray as B
+
+-- | Pseudo Random Key
+data PRK a = PRK (HMAC a) | PRK_NoExpand ScrubbedBytes
+    deriving (Eq)
+
+-- | Extract a Pseudo Random Key using the parameter and the underlaying hash mechanism
+extract :: (HashAlgorithm a, ByteArrayAccess salt, ByteArrayAccess ikm)
+        => salt  -- ^ Salt
+        -> ikm   -- ^ Input Keying Material
+        -> PRK a -- ^ Pseudo random key
+extract salt ikm = PRK $ hmac salt ikm
+
+-- | Create a PRK directly from the input key material, skipping any hmacing
+extractSkip :: (HashAlgorithm a, ByteArrayAccess ikm)
+            => ikm
+            -> PRK a
+extractSkip ikm = PRK_NoExpand $ B.convert ikm
+
+-- | Expand key material of specific length out of the parameters
+expand :: (HashAlgorithm a, ByteArrayAccess info, ByteArray out)
+       => PRK a      -- ^ Pseudo Random Key
+       -> info       -- ^ Optional context and application specific information
+       -> Int        -- ^ Output length in bytes
+       -> out        -- ^ Output data
+expand prkAt infoAt outputLength =
+    let hF = hFGet prkAt
+     in B.concat $ loop hF B.empty outputLength 1
+  where
+    hFGet :: (HashAlgorithm a, ByteArrayAccess b) => PRK a -> (b -> HMAC a)
+    hFGet prk = case prk of
+             PRK hmacKey      -> hmac hmacKey
+             PRK_NoExpand ikm -> hmac ikm
+
+    info :: ScrubbedBytes
+    info = B.convert infoAt
+
+    loop :: HashAlgorithm a
+         => (ScrubbedBytes -> HMAC a)
+         -> ScrubbedBytes
+         -> Int
+         -> Word8
+         -> [ScrubbedBytes]
+    loop hF tim1 n i
+        | n <= 0    = []
+        | otherwise =
+            let input   = B.concat [tim1,info,B.singleton i] :: ScrubbedBytes
+                ti      = B.convert $ hF input
+                hashLen = B.length ti
+                r       = n - hashLen
+             in (if n >= hashLen then ti else B.take n ti)
+              : loop hF ti r (i+1)
+
diff --git a/Crypto/MAC/HMAC.hs b/Crypto/MAC/HMAC.hs
--- a/Crypto/MAC/HMAC.hs
+++ b/Crypto/MAC/HMAC.hs
@@ -40,7 +40,7 @@
     (HMAC b1) == (HMAC b2) = B.constEq b1 b2
 
 -- | compute a MAC using the supplied hashing function
-hmac :: (ByteArrayAccess key, ByteArray message, HashAlgorithm a)
+hmac :: (ByteArrayAccess key, ByteArrayAccess message, HashAlgorithm a)
      => key     -- ^ Secret key
      -> message -- ^ Message to MAC
      -> HMAC a
diff --git a/Crypto/Number/Compat.hs b/Crypto/Number/Compat.hs
--- a/Crypto/Number/Compat.hs
+++ b/Crypto/Number/Compat.hs
@@ -71,7 +71,7 @@
 -- time wise through GMP
 gmpPowModSecInteger :: Integer -> Integer -> Integer -> GmpSupported Integer
 #if MIN_VERSION_integer_gmp(1,0,0)
-gmpPowModSecInteger b e m = GmpUnsupported
+gmpPowModSecInteger _ _ _ = GmpUnsupported
 #elif MIN_VERSION_integer_gmp(0,5,1)
 gmpPowModSecInteger b e m = GmpSupported (powModSecInteger b e m)
 #else
diff --git a/Crypto/PubKey/DSA.hs b/Crypto/PubKey/DSA.hs
--- a/Crypto/PubKey/DSA.hs
+++ b/Crypto/PubKey/DSA.hs
@@ -29,14 +29,17 @@
     ) where
 
 import           Crypto.Random.Types
+import           Data.Bits (testBit)
 import           Data.Data
 import           Data.Maybe
+import           Crypto.Number.Basic (numBits)
 import           Crypto.Number.ModArithmetic (expFast, expSafe, inverse)
 import           Crypto.Number.Serialize
 import           Crypto.Number.Generate
-import           Crypto.Internal.ByteArray (ByteArrayAccess)
+import           Crypto.Internal.ByteArray (ByteArrayAccess(length), convert, index, dropView, takeView)
 import           Crypto.Internal.Imports
 import           Crypto.Hash
+import           Prelude hiding (length)
 
 -- | DSA Public Number, usually embedded in DSA Public Key
 type PublicNumber = Integer
@@ -145,9 +148,11 @@
     | otherwise                            = v == r
     where (Params p g q) = public_params pk
           y       = public_y pk
-          hm      = os2ip $ hashWith hashAlg m
+          hm      = os2ip . truncateHash $ hashWith hashAlg m
 
           w       = fromJust $ inverse s q
           u1      = (hm*w) `mod` q
           u2      = (r*w) `mod` q
           v       = ((expFast g u1 p) * (expFast y u2 p)) `mod` p `mod` q
+          -- if the hash is larger than the size of q, truncate it; FIXME: deal with the case of a q not evenly divisible by 8
+          truncateHash h = if numBits (os2ip h) > numBits q then takeView h (numBits q `div` 8) else dropView h 0
diff --git a/Crypto/PubKey/Ed448.hs b/Crypto/PubKey/Ed448.hs
new file mode 100644
--- /dev/null
+++ b/Crypto/PubKey/Ed448.hs
@@ -0,0 +1,102 @@
+-- |
+-- Module      : Crypto.PubKey.Ed448
+-- License     : BSD-style
+-- Maintainer  : John Galt <jgalt@centromere.net>
+-- Stability   : experimental
+-- Portability : unknown
+--
+-- Ed448 support
+--
+{-# LANGUAGE GeneralizedNewtypeDeriving #-}
+{-# LANGUAGE MagicHash #-}
+module Crypto.PubKey.Ed448
+    ( SecretKey
+    , PublicKey
+    , DhSecret
+    -- * Smart constructors
+    , dhSecret
+    , publicKey
+    , secretKey
+    -- * methods
+    , dh
+    , toPublic
+    ) where
+
+import           Data.Word
+import           Foreign.Ptr
+import           GHC.Ptr
+
+import           Crypto.Error
+import           Crypto.Internal.Compat
+import           Crypto.Internal.Imports
+import           Crypto.Internal.ByteArray (ByteArrayAccess, ScrubbedBytes, Bytes, withByteArray)
+import qualified Crypto.Internal.ByteArray as B
+
+-- | A Ed448 Secret key
+newtype SecretKey = SecretKey ScrubbedBytes
+    deriving (Show,Eq,ByteArrayAccess,NFData)
+
+-- | A Ed448 public key
+newtype PublicKey = PublicKey Bytes
+    deriving (Show,Eq,ByteArrayAccess,NFData)
+
+-- | A Ed448 Diffie Hellman secret related to a
+-- public key and a secret key.
+newtype DhSecret = DhSecret ScrubbedBytes
+    deriving (Show,Eq,ByteArrayAccess,NFData)
+
+-- | Try to build a public key from a bytearray
+publicKey :: ByteArrayAccess bs => bs -> CryptoFailable PublicKey
+publicKey bs
+    | B.length bs == x448_bytes = CryptoPassed $ PublicKey $ B.copyAndFreeze bs (\_ -> return ())
+    | otherwise                 = CryptoFailed CryptoError_PublicKeySizeInvalid
+
+-- | Try to build a secret key from a bytearray
+secretKey :: ByteArrayAccess bs => bs -> CryptoFailable SecretKey
+secretKey bs
+    | B.length bs == x448_bytes = unsafeDoIO $
+        withByteArray bs $ \inp -> do
+            valid <- isValidPtr inp
+            if valid
+                then (CryptoPassed . SecretKey) <$> B.copy bs (\_ -> return ())
+                else return $ CryptoFailed CryptoError_SecretKeyStructureInvalid
+    | otherwise = CryptoFailed CryptoError_SecretKeySizeInvalid
+  where
+        isValidPtr :: Ptr Word8 -> IO Bool
+        isValidPtr _ =
+            return True
+{-# NOINLINE secretKey #-}
+
+-- | Create a DhSecret from a bytearray object
+dhSecret :: ByteArrayAccess b => b -> CryptoFailable DhSecret
+dhSecret bs
+    | B.length bs == x448_bytes = CryptoPassed $ DhSecret $ B.copyAndFreeze bs (\_ -> return ())
+    | otherwise                 = CryptoFailed CryptoError_SharedSecretSizeInvalid
+
+-- | Compute the Diffie Hellman secret from a public key and a secret key
+dh :: PublicKey -> SecretKey -> DhSecret
+dh (PublicKey pub) (SecretKey sec) = DhSecret <$>
+    B.allocAndFreeze x448_bytes $ \result ->
+    withByteArray sec           $ \psec   ->
+    withByteArray pub           $ \ppub   ->
+        ccryptonite_ed448 result psec ppub
+{-# NOINLINE dh #-}
+
+-- | Create a public key from a secret key
+toPublic :: SecretKey -> PublicKey
+toPublic (SecretKey sec) = PublicKey <$>
+    B.allocAndFreeze x448_bytes     $ \result ->
+    withByteArray sec               $ \psec   ->
+        ccryptonite_ed448 result psec basePoint
+  where
+        basePoint = Ptr "\x05\x00\x00\x00\x00\x00\x00\x00\x00x00\x00\x00\x00\x00\x00\x00\x00x00\x00\x00\x00\x00\x00\x00\x00x00\x00\x00\x00\x00\x00\x00\x00x00\x00\x00\x00\x00\x00\x00\x00x00\x00\x00\x00\x00\x00\x00\x00x00\x00\x00\x00\x00\x00\x00"#
+{-# NOINLINE toPublic #-}
+
+x448_bytes :: Int
+x448_bytes = 448 `quot` 8
+
+foreign import ccall "cryptonite_x448"
+    ccryptonite_ed448 :: Ptr Word8 -- ^ public
+                      -> Ptr Word8 -- ^ secret
+                      -> Ptr Word8 -- ^ basepoint
+                      -> IO ()
diff --git a/cbits/cryptonite_bitfn.h b/cbits/cryptonite_bitfn.h
--- a/cbits/cryptonite_bitfn.h
+++ b/cbits/cryptonite_bitfn.h
@@ -188,6 +188,8 @@
 #elif defined( __QNXNTO__ ) && defined( __BIGENDIAN__ )
   # define BIG_ENDIAN 1234
   # define BYTE_ORDER    BIG_ENDIAN
+#elif defined( _AIX )
+  # include <sys/machine.h>
 #else
   # include <endian.h>
 #endif
diff --git a/cbits/cryptonite_sysrand.c b/cbits/cryptonite_sysrand.c
deleted file mode 100644
--- a/cbits/cryptonite_sysrand.c
+++ /dev/null
@@ -1,46 +0,0 @@
-/*
- * Copyright (C) 2015 Vincent Hanquez <tab@snarc.org>
- *
- * All rights reserved.
- * 
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- *    notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- *    notice, this list of conditions and the following disclaimer in the
- *    documentation and/or other materials provided with the distribution.
- * 3. Neither the name of the author nor the names of his contributors
- *    may be used to endorse or promote products derived from this software
- *    without specific prior written permission.
- * 
- * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
- * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
- * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE
- * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
- * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
- * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
- * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
- * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
- * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
- * SUCH DAMAGE.
- */
-
-#include <stdlib.h>
-#include <stdint.h>
-#include <sys/time.h>
-#include "cryptonite_sha512.h"
-
-void cryptonite_sysrand_init(uint8_t *buf, uint32_t sz)
-{
-	struct timeval tv;
-	struct sha512_ctx ctx;
-	uint8_t out[64];
-	
-	gettimeofday(&tv, NULL);
-	cryptonite_sha512_init(&ctx);
-	cryptonite_sha512_update(&ctx, (uint8_t *) &tv, sizeof(tv));
-	cryptonite_sha512_finalize(&ctx, out);
-}
diff --git a/cbits/ed448/x448.c b/cbits/ed448/x448.c
new file mode 100644
--- /dev/null
+++ b/cbits/ed448/x448.c
@@ -0,0 +1,306 @@
+/* Copyright (c) 2015 Cryptography Research, Inc.
+ * Released under the MIT License.  See LICENSE.txt for license information.
+ */
+
+/**
+ * @file decaf.c
+ * @author Mike Hamburg
+ * @brief Decaf high-level functions.
+ */
+
+#include <stdint.h>
+#include "x448.h"
+
+#define WBITS 64 /* TODO */
+#define LBITS (WBITS * 7 / 8)
+#define X448_LIMBS (448/LBITS)
+
+#if WBITS == 64
+typedef uint64_t decaf_word_t;
+typedef int64_t decaf_sword_t;
+typedef __uint128_t decaf_dword_t;
+typedef __int128_t decaf_sdword_t;
+#elif WBITS == 32
+typedef uint32_t decaf_word_t;
+typedef int32_t decaf_sword_t;
+typedef uint64_t decaf_dword_t;
+typedef int64_t decaf_sdword_t;
+#else
+#error "WBITS must be 32 or 64"
+#endif
+
+typedef struct { decaf_word_t limb[X448_LIMBS]; } gf_s, gf[1];
+
+const unsigned char X448_BASE_POINT[X448_BYTES] = {5};
+
+static const gf ZERO = {{{0}}}, ONE = {{{1}}};
+
+#define LMASK ((((decaf_word_t)1)<<LBITS)-1)
+#if WBITS == 64
+static const gf P = {{{ LMASK, LMASK, LMASK, LMASK, LMASK-1, LMASK, LMASK, LMASK }}};
+#else
+static const gf P = {{{ LMASK,   LMASK, LMASK, LMASK, LMASK, LMASK, LMASK, LMASK,
+		      LMASK-1, LMASK, LMASK, LMASK, LMASK, LMASK, LMASK, LMASK }}};
+#endif
+static const int EDWARDS_D = -39081;
+
+#if (defined(__OPTIMIZE__) && !defined(__OPTIMIZE_SIZE__)) || defined(DECAF_FORCE_UNROLL)
+    #if X448_LIMBS==8
+    #define FOR_LIMB_U(i,op) { unsigned int i=0; \
+       op;i++; op;i++; op;i++; op;i++; op;i++; op;i++; op;i++; op;i++; \
+    }
+    #elif X448_LIMBS==16
+    #define FOR_LIMB_U(i,op) { unsigned int i=0; \
+       op;i++; op;i++; op;i++; op;i++; op;i++; op;i++; op;i++; op;i++; \
+       op;i++; op;i++; op;i++; op;i++; op;i++; op;i++; op;i++; op;i++; \
+    }
+    #else
+    #define FOR_LIMB_U(i,op) { unsigned int i=0; for (i=0; i<X448_LIMBS; i++)  { op; }}
+    #endif
+#else
+#define FOR_LIMB_U(i,op) { unsigned int i=0; for (i=0; i<X448_LIMBS; i++)  { op; }}
+#endif
+
+#define FOR_LIMB(i,op) { unsigned int i=0; for (i=0; i<X448_LIMBS; i++)  { op; }}
+
+/** Copy x = y */
+static void gf_cpy(gf x, const gf y) {
+    FOR_LIMB_U(i, x->limb[i] = y->limb[i]);
+}
+
+/** Mostly-unoptimized multiply (PERF), but at least it's unrolled. */
+static void
+gf_mul (gf c, const gf a, const gf b) {
+    gf aa;
+    gf_cpy(aa,a);
+
+    decaf_dword_t accum[X448_LIMBS] = {0};
+    FOR_LIMB_U(i, {
+        FOR_LIMB_U(j,{ accum[(i+j)%X448_LIMBS] += (decaf_dword_t)b->limb[i] * aa->limb[j]; });
+        aa->limb[(X448_LIMBS-1-i)^(X448_LIMBS/2)] += aa->limb[X448_LIMBS-1-i];
+    });
+
+    accum[X448_LIMBS-1] += accum[X448_LIMBS-2] >> LBITS;
+    accum[X448_LIMBS-2] &= LMASK;
+    accum[X448_LIMBS/2] += accum[X448_LIMBS-1] >> LBITS;
+    FOR_LIMB_U(j,{
+        accum[j] += accum[(j-1)%X448_LIMBS] >> LBITS;
+        accum[(j-1)%X448_LIMBS] &= LMASK;
+    });
+    FOR_LIMB_U(j, c->limb[j] = accum[j] );
+}
+
+/** No dedicated square (PERF) */
+#define gf_sqr(c,a) gf_mul(c,a,a)
+
+/** Inverse square root using addition chain. */
+static void
+gf_isqrt(gf y, const gf x) {
+    int i;
+#define STEP(s,m,n) gf_mul(s,m,c); gf_cpy(c,s); for (i=0;i<n;i++) gf_sqr(c,c);
+    gf a, b, c;
+    gf_sqr ( c,   x );
+    STEP(b,x,1);
+    STEP(b,x,3);
+    STEP(a,b,3);
+    STEP(a,b,9);
+    STEP(b,a,1);
+    STEP(a,x,18);
+    STEP(a,b,37);
+    STEP(b,a,37);
+    STEP(b,a,111);
+    STEP(a,b,1);
+    STEP(b,x,223);
+    gf_mul(y,a,c);
+}
+
+static void
+gf_inv(gf y, const gf x) {
+    gf z,w;
+    gf_sqr(z,x); /* x^2 */
+    gf_isqrt(w,z); /* +- 1/sqrt(x^2) = +- 1/x */
+    gf_sqr(z,w); /* 1/x^2 */
+    gf_mul(w,x,z); /* 1/x */
+    gf_cpy(y,w);
+}
+
+/** Weak reduce mod p. */
+static void
+gf_reduce(gf x) {
+    x->limb[X448_LIMBS/2] += x->limb[X448_LIMBS-1] >> LBITS;
+    FOR_LIMB_U(j,{
+        x->limb[j] += x->limb[(j-1)%X448_LIMBS] >> LBITS;
+        x->limb[(j-1)%X448_LIMBS] &= LMASK;
+    });
+}
+
+/** Add mod p.  Conservatively always weak-reduce. (PERF) */
+static void
+gf_add ( gf x, const gf y, const gf z ) {
+    FOR_LIMB_U(i, x->limb[i] = y->limb[i] + z->limb[i] );
+    gf_reduce(x);
+}
+
+/** Subtract mod p.  Conservatively always weak-reduce. (PERF) */
+static void
+gf_sub ( gf x, const gf y, const gf z ) {
+    FOR_LIMB_U(i, x->limb[i] = y->limb[i] - z->limb[i] + 2*P->limb[i] );
+    gf_reduce(x);
+}
+
+/** Constant time, if (swap) (x,y) = (y,x); */
+static void
+cond_swap(gf x, gf_s *__restrict__ y, decaf_word_t swap) {
+    FOR_LIMB_U(i, {
+        decaf_word_t s = (x->limb[i] ^ y->limb[i]) & swap;
+        x->limb[i] ^= s;
+        y->limb[i] ^= s;
+    });
+}
+
+/**
+ * Mul by signed int.  Not constant-time WRT the sign of that int.
+ * Just uses a full mul (PERF)
+ */
+static inline void
+gf_mlw(gf a, const gf b, int w) {
+    if (w>0) {
+        gf ww = {{{w}}};
+        gf_mul(a,b,ww);
+    } else {
+        gf ww = {{{-w}}};
+        gf_mul(a,b,ww);
+        gf_sub(a,ZERO,a);
+    }
+}
+
+/** Canonicalize */
+static void gf_canon ( gf a ) {
+    gf_reduce(a);
+
+    /* subtract p with borrow */
+    decaf_sdword_t carry = 0;
+    FOR_LIMB(i, {
+        carry = carry + a->limb[i] - P->limb[i];
+        a->limb[i] = carry & LMASK;
+        carry >>= LBITS;
+    });
+
+    decaf_word_t addback = carry;
+    carry = 0;
+
+    /* add it back */
+    FOR_LIMB(i, {
+        carry = carry + a->limb[i] + (P->limb[i] & addback);
+        a->limb[i] = carry & LMASK;
+        carry >>= LBITS;
+    });
+}
+
+/* Deserialize */
+static decaf_word_t
+gf_deser(gf s, const unsigned char ser[X448_BYTES]) {
+    unsigned int i, k=0, bits=0;
+    decaf_dword_t buf=0;
+    for (i=0; i<X448_BYTES; i++) {
+        buf |= (decaf_dword_t)ser[i]<<bits;
+        for (bits += 8; (bits>=LBITS || i==X448_BYTES-1) && k<X448_LIMBS; bits-=LBITS, buf>>=LBITS) {
+            s->limb[k++] = buf & LMASK;
+        }
+    }
+
+    decaf_sdword_t accum = 0;
+    FOR_LIMB(i, accum = (accum + s->limb[i] - P->limb[i]) >> WBITS );
+    return accum;
+}
+
+/* Serialize */
+static void
+gf_ser(uint8_t ser[X448_BYTES], gf a) {
+    gf_canon(a);
+    int k=0, bits=0;
+    decaf_dword_t buf=0;
+    FOR_LIMB(i, {
+        buf |= (decaf_dword_t)a->limb[i]<<bits;
+        for (bits += LBITS; (bits>=8 || i==X448_LIMBS-1) && k<X448_BYTES; bits-=8, buf>>=8) {
+            ser[k++]=buf;
+        }
+    });
+}
+
+int __attribute__((visibility("default"))) cryptonite_x448 (
+    unsigned char out[X448_BYTES],
+    const unsigned char scalar[X448_BYTES],
+    const unsigned char base[X448_BYTES]
+) {
+    gf x1, x2, z2, x3, z3, t1, t2;
+    gf_deser(x1,base);
+    gf_cpy(x2,ONE);
+    gf_cpy(z2,ZERO);
+    gf_cpy(x3,x1);
+    gf_cpy(z3,ONE);
+
+    int t;
+    decaf_word_t swap = 0;
+
+    for (t = 448-1; t>=0; t--) {
+        uint8_t sb = scalar[t/8];
+
+        /* Scalar conditioning */
+        if (t/8==0) sb &= 0xFC;
+        else if (t/8 == X448_BYTES-1) sb |= 0x80;
+
+        decaf_word_t k_t = (sb>>(t%8)) & 1;
+        k_t = -k_t; /* set to all 0s or all 1s */
+
+        swap ^= k_t;
+        cond_swap(x2,x3,swap);
+        cond_swap(z2,z3,swap);
+        swap = k_t;
+
+        gf_add(t1,x2,z2); /* A = x2 + z2 */
+        gf_sub(t2,x2,z2); /* B = x2 - z2 */
+        gf_sub(z2,x3,z3); /* D = x3 - z3 */
+        gf_mul(x2,t1,z2); /* DA */
+        gf_add(z2,z3,x3); /* C = x3 + z3 */
+        gf_mul(x3,t2,z2); /* CB */
+        gf_sub(z3,x2,x3); /* DA-CB */
+        gf_sqr(z2,z3);    /* (DA-CB)^2 */
+        gf_mul(z3,x1,z2); /* z3 = x1(DA-CB)^2 */
+        gf_add(z2,x2,x3); /* (DA+CB) */
+        gf_sqr(x3,z2);    /* x3 = (DA+CB)^2 */
+
+        gf_sqr(z2,t1);    /* AA = A^2 */
+        gf_sqr(t1,t2);    /* BB = B^2 */
+        gf_mul(x2,z2,t1); /* x2 = AA*BB */
+        gf_sub(t2,z2,t1); /* E = AA-BB */
+
+        gf_mlw(t1,t2,-EDWARDS_D); /* E*-d = a24*E */
+        gf_add(t1,t1,z2); /* AA + a24*E */
+        gf_mul(z2,t2,t1); /* z2 = E(AA+a24*E) */
+    }
+
+    /* Finish */
+    cond_swap(x2,x3,swap);
+    cond_swap(z2,z3,swap);
+    gf_inv(z2,z2);
+    gf_mul(x1,x2,z2);
+    gf_ser(out,x1);
+
+    decaf_sword_t nz = 0;
+    for (t=0; t<X448_BYTES; t++) {
+        nz |= out[t];
+    }
+    nz = (nz-1)>>8; /* 0 = succ, -1 = fail */
+
+    /* return value: 0 = succ, -1 = fail */
+    return nz;
+}
+
+int __attribute__((visibility("default")))
+cryptonite_x448_base (
+    unsigned char out[X448_BYTES],
+    const unsigned char scalar[X448_BYTES]
+) {
+    return cryptonite_x448(out,scalar,X448_BASE_POINT);
+}
diff --git a/cbits/ed448/x448.h b/cbits/ed448/x448.h
new file mode 100644
--- /dev/null
+++ b/cbits/ed448/x448.h
@@ -0,0 +1,25 @@
+
+#define X448_BYTES (448/8)
+
+/* The base point (5) */
+extern const unsigned char X448_BASE_POINT[X448_BYTES];
+
+/* Returns 0 on success, -1 on failure */
+int __attribute__((visibility("default")))
+cryptonite_x448 (
+    unsigned char out[X448_BYTES],
+    const unsigned char scalar[X448_BYTES],
+    const unsigned char base[X448_BYTES]
+);
+
+/* Returns 0 on success, -1 on failure
+ *
+ * Same as x448(out,scalar,X448_BASE_POINT), except that
+ * an implementation may optimize it.
+ */
+int __attribute__((visibility("default")))
+cryptonite_x448_base (
+    unsigned char out[X448_BYTES],
+    const unsigned char scalar[X448_BYTES]
+);
+
diff --git a/cryptonite.cabal b/cryptonite.cabal
--- a/cryptonite.cabal
+++ b/cryptonite.cabal
@@ -1,5 +1,5 @@
 Name:                cryptonite
-Version:             0.10
+Version:             0.11
 Synopsis:            Cryptography Primitives sink
 Description:
     A repository of cryptographic primitives.
@@ -12,7 +12,7 @@
     .
     * Assymmetric crypto: DSA, RSA, DH, ECDH, ECDSA, ECC, Curve25519, Ed25519
     .
-    * Key Derivation Function: PBKDF2, Scrypt
+    * Key Derivation Function: PBKDF2, Scrypt, HKDF
     .
     * Cryptographic Random generation: System Entropy, Deterministic Random Generator
     .
@@ -38,6 +38,7 @@
 extra-source-files:  cbits/*.h
                      cbits/aes/*.h
                      cbits/ed25519/*.h
+                     cbits/ed448/*.h
                      cbits/p256/*.h
                      cbits/blake2/ref/*.h
                      cbits/blake2/ref/*.c
@@ -80,6 +81,11 @@
   Default:           True
   Manual:            True
 
+Flag old_toolchain_inliner
+  Description:       use -fgnu89-inline to workaround an old compiler / linker / glibc issue.
+  Default:           False
+  Manual:            True
+
 Library
   Exposed-modules:   Crypto.Cipher.AES
                      Crypto.Cipher.Blowfish
@@ -106,6 +112,7 @@
                      Crypto.KDF.PBKDF2
                      Crypto.KDF.Scrypt
                      Crypto.KDF.BCrypt
+                     Crypto.KDF.HKDF
                      Crypto.Hash
                      Crypto.Hash.IO
                      Crypto.Hash.Algorithms
@@ -120,6 +127,7 @@
                      Crypto.PubKey.ECC.P256
                      Crypto.PubKey.ECC.Types
                      Crypto.PubKey.Ed25519
+                     Crypto.PubKey.Ed448
                      Crypto.PubKey.RSA
                      Crypto.PubKey.RSA.PKCS15
                      Crypto.PubKey.RSA.Prim
@@ -186,15 +194,15 @@
   ghc-options:       -Wall -fwarn-tabs -optc-O3 -fno-warn-unused-imports
   default-language:  Haskell2010
   cc-options:        -std=gnu99
+  if flag(old_toolchain_inliner)
+    cc-options:      -fgnu89-inline
   C-sources:         cbits/cryptonite_chacha.c
                    , cbits/cryptonite_salsa.c
                    , cbits/cryptonite_rc4.c
                    , cbits/cryptonite_cpu.c
-                   , cbits/aes/generic.c
-                   , cbits/aes/gf.c
-                   , cbits/cryptonite_aes.c
                    , cbits/curve25519/curve25519-donna.c
                    , cbits/ed25519/ed25519.c
+                   , cbits/ed448/x448.c
                    , cbits/p256/p256.c
                    , cbits/p256/p256_ec.c
                    , cbits/cryptonite_blake2s.c
@@ -216,7 +224,6 @@
                    , cbits/cryptonite_tiger.c
                    , cbits/cryptonite_whirlpool.c
                    , cbits/cryptonite_scrypt.c
-                   , cbits/cryptonite_sysrand.c
   include-dirs:  cbits cbits/ed25519
 
   -- FIXME armel or mispel is also little endian.
@@ -238,7 +245,14 @@
     CC-options:     -mssse3 -maes -DWITH_AESNI
     if flag(support_pclmuldq)
        CC-options:  -msse4.1 -mpclmul -DWITH_PCLMUL
-    C-sources:      cbits/aes/x86ni.c
+    C-sources:       cbits/aes/x86ni.c
+                   , cbits/aes/generic.c
+                   , cbits/aes/gf.c
+                   , cbits/cryptonite_aes.c
+  else
+    C-sources:       cbits/aes/generic.c
+                   , cbits/aes/gf.c
+                   , cbits/cryptonite_aes.c
 
   if arch(x86_64) || flag(support_blake2_sse)
     C-sources:      cbits/blake2/sse/blake2s.c
diff --git a/tests/KAT_Ed448.hs b/tests/KAT_Ed448.hs
new file mode 100644
--- /dev/null
+++ b/tests/KAT_Ed448.hs
@@ -0,0 +1,23 @@
+{-# LANGUAGE OverloadedStrings #-}
+module KAT_Ed448 ( tests ) where
+
+import           Crypto.Error
+import qualified Crypto.PubKey.Ed448 as Ed448
+import           Data.ByteArray as B
+import           Imports
+
+alicePrivate = throwCryptoError $ Ed448.secretKey ("\x9a\x8f\x49\x25\xd1\x51\x9f\x57\x75\xcf\x46\xb0\x4b\x58\x00\xd4\xee\x9e\xe8\xba\xe8\xbc\x55\x65\xd4\x98\xc2\x8d\xd9\xc9\xba\xf5\x74\xa9\x41\x97\x44\x89\x73\x91\x00\x63\x82\xa6\xf1\x27\xab\x1d\x9a\xc2\xd8\xc0\xa5\x98\x72\x6b" :: ByteString)
+alicePublic  = throwCryptoError $ Ed448.publicKey ("\x9b\x08\xf7\xcc\x31\xb7\xe3\xe6\x7d\x22\xd5\xae\xa1\x21\x07\x4a\x27\x3b\xd2\xb8\x3d\xe0\x9c\x63\xfa\xa7\x3d\x2c\x22\xc5\xd9\xbb\xc8\x36\x64\x72\x41\xd9\x53\xd4\x0c\x5b\x12\xda\x88\x12\x0d\x53\x17\x7f\x80\xe5\x32\xc4\x1f\xa0" :: ByteString)
+bobPrivate   = throwCryptoError $ Ed448.secretKey ("\x1c\x30\x6a\x7a\xc2\xa0\xe2\xe0\x99\x0b\x29\x44\x70\xcb\xa3\x39\xe6\x45\x37\x72\xb0\x75\x81\x1d\x8f\xad\x0d\x1d\x69\x27\xc1\x20\xbb\x5e\xe8\x97\x2b\x0d\x3e\x21\x37\x4c\x9c\x92\x1b\x09\xd1\xb0\x36\x6f\x10\xb6\x51\x73\x99\x2d" :: ByteString)
+bobPublic    = throwCryptoError $ Ed448.publicKey ("\x3e\xb7\xa8\x29\xb0\xcd\x20\xf5\xbc\xfc\x0b\x59\x9b\x6f\xec\xcf\x6d\xa4\x62\x71\x07\xbd\xb0\xd4\xf3\x45\xb4\x30\x27\xd8\xb9\x72\xfc\x3e\x34\xfb\x42\x32\xa1\x3c\xa7\x06\xdc\xb5\x7a\xec\x3d\xae\x07\xbd\xc1\xc6\x7b\xf3\x36\x09" :: ByteString)
+aliceMultBob = "\x07\xff\xf4\x18\x1a\xc6\xcc\x95\xec\x1c\x16\xa9\x4a\x0f\x74\xd1\x2d\xa2\x32\xce\x40\xa7\x75\x52\x28\x1d\x28\x2b\xb6\x0c\x0b\x56\xfd\x24\x64\xc3\x35\x54\x39\x36\x52\x1c\x24\x40\x30\x85\xd5\x9a\x44\x9a\x50\x37\x51\x4a\x87\x9d" :: ByteString
+
+katTests :: [TestTree]
+katTests =
+    [ testCase "0" (aliceMultBob @=? B.convert (Ed448.dh alicePublic bobPrivate))
+    , testCase "1" (aliceMultBob @=? B.convert (Ed448.dh bobPublic alicePrivate))
+    ]
+
+tests = testGroup "Ed448"
+    [ testGroup "KATs" katTests
+    ]
diff --git a/tests/KAT_HKDF.hs b/tests/KAT_HKDF.hs
new file mode 100644
--- /dev/null
+++ b/tests/KAT_HKDF.hs
@@ -0,0 +1,54 @@
+{-# LANGUAGE OverloadedStrings #-}
+module KAT_HKDF (tests) where
+
+import qualified Crypto.KDF.HKDF as HKDF
+import Crypto.Hash (MD5(..), SHA1(..), SHA256(..)
+                   , Keccak_224(..), Keccak_256(..), Keccak_384(..), Keccak_512(..)
+                   , SHA3_224(..), SHA3_256(..), SHA3_384(..), SHA3_512(..)
+                   , HashAlgorithm, digestFromByteString)
+import qualified Data.ByteString as B
+
+import Imports
+
+
+data KDFVector hash = KDFVector
+    { kdfIKM    :: ByteString
+    , kdfSalt   :: ByteString
+    , kdfInfo   :: ByteString
+    , kdfResult :: ByteString
+    }
+
+sha256KDFVectors :: [KDFVector SHA256]
+sha256KDFVectors =
+    [ KDFVector
+        "\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b"
+        (B.pack [0x00,0x01,0x02,0x03,0x04,0x05,0x06,0x07,0x08,0x09,0x0a,0x0b,0x0c])
+        "\xf0\xf1\xf2\xf3\xf4\xf5\xf6\xf7\xf8\xf9"
+        "\x3c\xb2\x5f\x25\xfa\xac\xd5\x7a\x90\x43\x4f\x64\xd0\x36\x2f\x2a\x2d\x2d\x0a\x90\xcf\x1a\x5a\x4c\x5d\xb0\x2d\x56\xec\xc4\xc5\xbf\x34\x00\x72\x08\xd5\xb8\x87\x18\x58\x65"
+    , KDFVector
+        (B.pack [0x00,0x01,0x02,0x03,0x04,0x05,0x06,0x07,0x08,0x09,0x0a,0x0b,0x0c,0x0d,0x0e,0x0f,0x10,0x11,0x12,0x13,0x14,0x15,0x16,0x17,0x18,0x19,0x1a,0x1b,0x1c,0x1d,0x1e,0x1f,0x20,0x21,0x22,0x23,0x24,0x25,0x26,0x27,0x28,0x29,0x2a,0x2b,0x2c,0x2d,0x2e,0x2f,0x30,0x31,0x32,0x33,0x34,0x35,0x36,0x37,0x38,0x39,0x3a,0x3b,0x3c,0x3d,0x3e,0x3f,0x40,0x41,0x42,0x43,0x44,0x45,0x46,0x47,0x48,0x49,0x4a,0x4b,0x4c,0x4d,0x4e,0x4f])
+        (B.pack [0x60,0x61,0x62,0x63,0x64,0x65,0x66,0x67,0x68,0x69,0x6a,0x6b,0x6c,0x6d,0x6e,0x6f,0x70,0x71,0x72,0x73,0x74,0x75,0x76,0x77,0x78,0x79,0x7a,0x7b,0x7c,0x7d,0x7e,0x7f,0x80,0x81,0x82,0x83,0x84,0x85,0x86,0x87,0x88,0x89,0x8a,0x8b,0x8c,0x8d,0x8e,0x8f,0x90,0x91,0x92,0x93,0x94,0x95,0x96,0x97,0x98,0x99,0x9a,0x9b,0x9c,0x9d,0x9e,0x9f,0xa0,0xa1,0xa2,0xa3,0xa4,0xa5,0xa6,0xa7,0xa8,0xa9,0xaa,0xab,0xac,0xad,0xae,0xaf])
+        (B.pack [0xb0,0xb1,0xb2,0xb3,0xb4,0xb5,0xb6,0xb7,0xb8,0xb9,0xba,0xbb,0xbc,0xbd,0xbe,0xbf,0xc0,0xc1,0xc2,0xc3,0xc4,0xc5,0xc6,0xc7,0xc8,0xc9,0xca,0xcb,0xcc,0xcd,0xce,0xcf,0xd0,0xd1,0xd2,0xd3,0xd4,0xd5,0xd6,0xd7,0xd8,0xd9,0xda,0xdb,0xdc,0xdd,0xde,0xdf,0xe0,0xe1,0xe2,0xe3,0xe4,0xe5,0xe6,0xe7,0xe8,0xe9,0xea,0xeb,0xec,0xed,0xee,0xef,0xf0,0xf1,0xf2,0xf3,0xf4,0xf5,0xf6,0xf7,0xf8,0xf9,0xfa,0xfb,0xfc,0xfd,0xfe,0xff])
+        (B.pack [0xb1,0x1e,0x39,0x8d,0xc8,0x03,0x27,0xa1,0xc8,0xe7,0xf7,0x8c,0x59,0x6a,0x49,0x34,0x4f,0x01,0x2e,0xda,0x2d,0x4e,0xfa,0xd8,0xa0,0x50,0xcc,0x4c,0x19,0xaf,0xa9,0x7c,0x59,0x04,0x5a,0x99,0xca,0xc7,0x82,0x72,0x71,0xcb,0x41,0xc6,0x5e,0x59,0x0e,0x09,0xda,0x32,0x75,0x60,0x0c,0x2f,0x09,0xb8,0x36,0x77,0x93,0xa9,0xac,0xa3,0xdb,0x71,0xcc,0x30,0xc5,0x81,0x79,0xec,0x3e,0x87,0xc1,0x4c,0x01,0xd5,0xc1,0xf3,0x43,0x4f,0x1d,0x87])
+    ]
+
+kdfTests :: [TestTree]
+kdfTests =
+    [ testGroup "sha256" $ concatMap toKDFTest $ zip is sha256KDFVectors
+    ]
+  where toKDFTest (i, kdfVector) =
+            [ testCase (show i) (t HKDF.extract kdfVector)
+            ]
+
+        t :: HashAlgorithm a => (ByteString -> ByteString -> HKDF.PRK a) -> KDFVector a -> Assertion
+        t ext v =
+            let prk = ext (kdfSalt v) (kdfIKM v)
+             in kdfResult v @=? HKDF.expand prk (kdfInfo v) (B.length $ kdfResult v)
+
+        is :: [Int]
+        is = [1..]
+
+
+tests = testGroup "HKDF"
+    [ testGroup "KATs" kdfTests
+    ]
diff --git a/tests/Tests.hs b/tests/Tests.hs
--- a/tests/Tests.hs
+++ b/tests/Tests.hs
@@ -11,8 +11,10 @@
 import qualified ChaCha
 import qualified ChaChaPoly1305
 import qualified KAT_HMAC
+import qualified KAT_HKDF
 import qualified KAT_PBKDF2
 import qualified KAT_Curve25519
+import qualified KAT_Ed448
 import qualified KAT_Ed25519
 import qualified KAT_PubKey
 import qualified KAT_Scrypt
@@ -36,12 +38,14 @@
         , KAT_HMAC.tests
         ]
     , KAT_Curve25519.tests
+    , KAT_Ed448.tests
     , KAT_Ed25519.tests
     , KAT_PubKey.tests
     , testGroup "KDF"
         [ KAT_PBKDF2.tests
         , KAT_Scrypt.tests
         , BCrypt.tests
+        , KAT_HKDF.tests
         ]
     , testGroup "block-cipher"
         [ KAT_AES.tests
