diff --git a/README.md b/README.md
index 3a70a52..898d705 100644
--- a/README.md
+++ b/README.md
@@ -9,8 +9,11 @@ BLAKE2 was introduced in 2015 as IETF RFC 7693. You can visit
 This module:
 
 - [x] Supports BLAKE2b-512 and BLAKE2s-256.
-- [x] Supports custom hash sizes.
-- [ ] Supports HMAC. (WIP!)
+- [x] Supports custom digest sizes.
+- [x] Supports keying.
+- [ ] Supports BLAKE2bp and BLAKE2sp.
+
+NOTE: May be incompatible with HMAC.
 
 Compatible and tested with DMD, GDC, and LDC.
 
@@ -39,13 +42,12 @@ BLAKE2b512 b2b512;
 b2b512.put("abc");
 assert(b2b512.finish() == cast(ubyte[]) hexString!(
 	"ba80a53f981c4d0d6a2797b69f12f6e94c212f14685ac4b74b12bb6fdbffa2d1"~
-        "7d87c5392aab792dc252d5de4533cc9518d38aa8dbf1925ab92386edd4009923"
-	));
+        "7d87c5392aab792dc252d5de4533cc9518d38aa8dbf1925ab92386edd4009923"));
 b2b512.start(); // reset
 b2b512.put("abcdef");
 assert(b2b512.finish() == cast(ubyte[]) hexString!(
 	"dde410524e3569b303e494aa82a3afb3e426f9df24c1398e9ff87aafbc2f5b7b"~
-	"3c1a4c9400409de3b45d37a00e5eae2a93cc9c4a108b00f05217d41a424d2b8a");
+	"3c1a4c9400409de3b45d37a00e5eae2a93cc9c4a108b00f05217d41a424d2b8a"));
 ```
 
 ### OOP API
@@ -59,18 +61,34 @@ Digest dgst = new BLAKE2b512Digest();
 dgst.put("abc");
 assert(dgst.finish() == cast(ubyte[]) hexString!(
 	"ba80a53f981c4d0d6a2797b69f12f6e94c212f14685ac4b74b12bb6fdbffa2d1"~
-        "7d87c5392aab792dc252d5de4533cc9518d38aa8dbf1925ab92386edd4009923"
-	));
+        "7d87c5392aab792dc252d5de4533cc9518d38aa8dbf1925ab92386edd4009923"));
 dgst.start(); // reset
 dgst.put("abcdef");
 assert(dgst.finish() == cast(ubyte[]) hexString!(
 	"dde410524e3569b303e494aa82a3afb3e426f9df24c1398e9ff87aafbc2f5b7b"~
-	"3c1a4c9400409de3b45d37a00e5eae2a93cc9c4a108b00f05217d41a424d2b8a");
+	"3c1a4c9400409de3b45d37a00e5eae2a93cc9c4a108b00f05217d41a424d2b8a"));
 ```
 
 There are numerous ways to avoid GC allocation. For example when only using a
 digest for a one-time use in a short scope, there's `std.typecons.scoped`.
 
+### Keying
+
+Currently, the only way to supply a key is with the `key` function:
+
+```d
+import std.string : representation;
+import std.conv : hexString;
+
+auto secret2s = hexString!(
+    "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f")
+    .representation;
+auto data = hexString!("000102").representation;
+
+BLAKE2s256 b2s;
+b2s.key(secret);
+```
+
 # License
 
 Published under the Boost License 1.0.
\ No newline at end of file
diff --git a/dub.sdl b/dub.sdl
index a78b5f1..250afc0 100644
--- a/dub.sdl
+++ b/dub.sdl
@@ -1,5 +1,5 @@
 name "blake2-d"
-description "BLAKE2s and BLAKEb implementations."
+description "BLAKE2 implementation."
 authors "dd86k <dd@dax.moe>"
 copyright "Copyright © 2021, dd86k"
 license "BSL-1.0"
diff --git a/source/blake2d.d b/source/blake2d.d
index 2ebbc26..ef4b509 100644
--- a/source/blake2d.d
+++ b/source/blake2d.d
@@ -4,7 +4,7 @@
 /// Authors: $(LINK2 github.com/dd86k, dd86k)
 module blake2d;
 
-public enum BLAKE2D_VERSION_STRING = "0.1.0";
+public enum BLAKE2D_VERSION_STRING = "0.2.0";
 
 private import std.digest;
 private import core.bitop : ror, bswap;
@@ -65,10 +65,7 @@ enum BLAKE2Variant {
 //   key = HMAC key. This is a temporary hack to allow HMAC usage.
 struct BLAKE2(BLAKE2Variant var, uint digestSize/*, const(ubyte)[] key = null*/)
 {
-    @safe:
-    @nogc:
-    nothrow:
-    pure:
+    @safe: @nogc: nothrow: pure:
     
     static assert(digestSize > 0,
         "Digest size must be non-zero.");
@@ -80,8 +77,9 @@ struct BLAKE2(BLAKE2Variant var, uint digestSize/*, const(ubyte)[] key = null*/)
         static assert(digestSize >= 8 && digestSize <= 512,
             "BLAKE2b digest size must be between 8 and 512 bits.");
         
+        private enum MAXKEYSIZE = 32; // In bytes
         private enum MAXED = digestSize == 512;
-        private enum BSIZE = 128;   /// bb
+        private enum BSIZE = 128;   /// Buffer size, "bb" variable
         private enum ROUNDS = 12;
         private enum R1 = 32;
         private enum R2 = 24;
@@ -94,8 +92,9 @@ struct BLAKE2(BLAKE2Variant var, uint digestSize/*, const(ubyte)[] key = null*/)
         static assert(digestSize >= 8 && digestSize <= 256,
             "BLAKE2s digest size must be between 8 and 256 bits.");
         
+        private enum MAXKEYSIZE = 32; // In bytes
         private enum MAXED = digestSize == 256;
-        private enum BSIZE = 64;    /// bb
+        private enum BSIZE = 64;    /// Buffer size, "bb" variable
         private enum ROUNDS = 10;
         private enum R1 = 16;
         private enum R2 = 12;
@@ -113,6 +112,20 @@ struct BLAKE2(BLAKE2Variant var, uint digestSize/*, const(ubyte)[] key = null*/)
         this = typeof(this).init;
     }
     
+    /// Initiates a key with digest.
+    /// This is meant to be used after the digest initiation.
+    /// The key limit is 64 bytes for BLAKE2b and 32 bytes for
+    /// BLAKE2s. If the limit is reached, it fails silenty by truncating
+    /// key data.
+    /// Params: input = Key.
+    void key(scope const(ubyte)[] input)
+    {
+        enum MASK  = BSIZE - 1;
+        h[0] ^= ((input.length & MASK) << 8);
+        put(input.length > BSIZE ? input[0..BSIZE] : input);
+        c = BSIZE;
+    }
+    
     /// Feed the algorithm with data.
     /// Also implements the $(REF isOutputRange, std,range,primitives)
     /// interface for `ubyte` and `const(ubyte)[]`.
@@ -167,7 +180,7 @@ struct BLAKE2(BLAKE2Variant var, uint digestSize/*, const(ubyte)[] key = null*/)
         // Clear out possible sensitive data
         t[0] = t[1] = c = 0; // clear size information
         mz[] = 0; // clear input message buffer
-        // Only clear remaining of state if digest not at maximum.
+        // Only clear remaining of state if digest isn't fulled used.
         // e.g., BLAKE2b-512 has a digest size of 64 bytes
         //       ulong[8] (8*8) is 64 bytes of state
         //       So is BLAKE2x-256 is used, a digest of 32 bytes
@@ -179,22 +192,13 @@ struct BLAKE2(BLAKE2Variant var, uint digestSize/*, const(ubyte)[] key = null*/)
     }
     
 private:
-
-    /*static if (key)
-    {
-        enum KEYLEN = key.length;
-    }
-    else
-        enum KEYLEN = 0;*/
-    
-    //public ubyte[32] key;
     
     enum digestSizeBytes = digestSize / 8;
     //           3 2 1 0
     // p[0] = 0x0101kknn
     // kk - Key size. Set to zero since HMAC is done elsewhere.
     // nn - Digest size in bytes.
-    enum p0 = 0x0101_0000 ^ (0 << 8) ^ digestSizeBytes;
+    enum p0 = 0x0101_0000 ^ digestSizeBytes;
     enum msz = 16 * inner_t.sizeof; /// message size in bytes
     enum hsz = 8 * inner_t.sizeof;  /// state size in bytes
     
@@ -249,7 +253,7 @@ private:
         v[14] = last ? ~IV[6] : IV[6];
         v[15] = IV[7];
         
-        // See i=0 v[16]
+        // Assert i=0 v[16]
         
         for (size_t round; round < ROUNDS; ++round)
         {
@@ -263,7 +267,7 @@ private:
             G(v, 2, 7,  8, 13, m[SIGMA[round][12]], m[SIGMA[round][13]]);
             G(v, 3, 4,  9, 14, m[SIGMA[round][14]], m[SIGMA[round][15]]);
             
-            // See i=1..i=10/12 v[16]
+            // Assert i=1..i=10/12 v[16]
         }
         
         h[0] ^= v[0] ^ v[8];
@@ -275,7 +279,7 @@ private:
         h[6] ^= v[6] ^ v[14];
         h[7] ^= v[7] ^ v[15];
         
-        // See h[8]
+        // Assert h[8]
     }
     
     static void G(ref inner_t[16] v, uint a, uint b, uint c, uint d, inner_t x, inner_t y)
@@ -315,16 +319,20 @@ public alias BLAKE2s256Digest = WrapperDigest!BLAKE2s256;
     assert(isDigest!BLAKE2s256);
 }
 
+/// Of course they have a blockSize!
+@safe unittest
+{
+    assert(hasBlockSize!BLAKE2b512);
+    assert(hasBlockSize!BLAKE2s256);
+}
+
 /// Testing "Of" wrappers against digest wrappers.
 @safe unittest
 {
     enum TEXT = "abc";
     
-    ubyte[64] b2b = blake2b_Of(TEXT);
-    assert(b2b == digest!BLAKE2b512(TEXT));
-    
-    ubyte[32] b2s = blake2s_Of(TEXT);
-    assert(b2s == digest!BLAKE2s256(TEXT));
+    assert(blake2b_Of(TEXT) == digest!BLAKE2b512(TEXT));
+    assert(blake2s_Of(TEXT) == digest!BLAKE2s256(TEXT));
 }
 
 /// Testing template API
@@ -388,13 +396,13 @@ public alias BLAKE2s256Digest = WrapperDigest!BLAKE2s256;
     
     ubyte[] s = ['a', 'b', 'c'];
     
-    BLAKE2b512Digest b2b = new BLAKE2b512Digest();
+    Digest b2b = new BLAKE2b512Digest();
     b2b.put(s);
     assert(b2b.finish() == cast(ubyte[]) hexString!(
         "ba80a53f981c4d0d6a2797b69f12f6e94c212f14685ac4b74b12bb6fdbffa2d1"~
         "7d87c5392aab792dc252d5de4533cc9518d38aa8dbf1925ab92386edd4009923"));
     
-    BLAKE2s256Digest b2s = new BLAKE2s256Digest();
+    Digest b2s = new BLAKE2s256Digest();
     b2s.put(s);
     assert(b2s.finish() == cast(ubyte[]) hexString!(
         "508c5e8c327c14e2e1a72ba34eeb452f37458b209ed63a294d999b4c86675982"));
@@ -425,28 +433,37 @@ public alias BLAKE2s256Digest = WrapperDigest!BLAKE2s256;
         "508c5e8c327c14e2e1a72ba34eeb452f37458b209ed63a294d999b4c86675982"));
 }
 
-/// Testing with HMAC
-/*@system unittest
+/// Keying digests
+@system unittest
 {
+    // NOTE: BLAKE2 is a keyed hash and therefore not compatible with
+    //       the hmac/HMAC templates, or OpenSSL does it differently.
+    
     import std.ascii : LetterCase;
-    import std.digest.hmac : hmac;
     import std.string : representation;
+    import std.conv : hexString;
     
-    auto secret = "secret".representation;
+    auto secret2b = hexString!(
+        "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f"~
+        "202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f")
+        .representation;
+    auto secret2s = hexString!(
+        "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f")
+        .representation;
+    auto data = hexString!("000102").representation;
     
-    // Temporary hack
-    //alias HMACBLAKE2b512 = BLAKE2!(BLAKE2Variant.b, 512, "secret".representation);
-    //alias HMACBLAKE2s256 = BLAKE2!(BLAKE2Variant.s, 256, "secret".representation);
-
-    assert("The quick brown fox jumps over the lazy dog"
-        .representation
-        .hmac!BLAKE2b512(secret)
-        .toHexString!(LetterCase.lower) ==
-        "97504d0493aaaa40b08cf700fd380f17fe32e26e008fa20f9f3f04901d9f5bf3"~
-        "3e826ea234f93bedfe7c5c50a540ad61454eb011581194cd68bff57938760ae0");
-    assert("The quick brown fox jumps over the lazy dog"
-        .representation
-        .hmac!BLAKE2s256(secret)
-        .toHexString!(LetterCase.lower) ==
-        "e95b806f87e9477966cd5f0ca2d496bfdfa424c69e820d33e4f1007aeb6c9de1");
-}*/
\ No newline at end of file
+    BLAKE2b512 b2b;
+    b2b.key(secret2b);
+    b2b.put(data);
+    assert(b2b.finish().toHexString!(LetterCase.lower) ==
+        "33d0825dddf7ada99b0e7e307104ad07ca9cfd9692214f1561356315e784f3e5"~
+        "a17e364ae9dbb14cb2036df932b77f4b292761365fb328de7afdc6d8998f5fc1"
+        , "BLAKE2b+secret failed");
+    
+    BLAKE2s256 b2s;
+    b2s.key(secret2s);
+    b2s.put(data);
+    assert(b2s.finish().toHexString!(LetterCase.lower) ==
+        "1d220dbe2ee134661fdf6d9e74b41704710556f2f6e5a091b227697445dbea6b"
+        , "BLAKE2s+secret failed");
+}
\ No newline at end of file