The KMAC Algorithm
KMAC is the message authentication code built on SHA-3. It needs no HMAC-style double hashing, because the Keccak sponge resists length extension. Learn how cSHAKE, the key block, and the encoded output length work, with every NIST sample checked.
Pashalis Laoutaris 15 min read
Try it
Interactive KMAC Visualizer
🔐 KMAC
The KMAC Algorithm
Introduction
KMAC is the Keccak message authentication code. It is part of NIST SP 800-185, a standard that builds new tools out of the SHA-3 family. Where HMAC wraps a hash function in two layers, KMAC is just a keyed call of the Keccak sponge. This is possible because the sponge has a property that older hashes lack: it does not suffer from length extension.
KMAC has three ideas. The first is cSHAKE, a version of SHAKE that can be customized with a function name and a string, so that different uses of Keccak never give the same output. The second is a key block. The key is encoded, padded to a whole number of blocks of the sponge, and absorbed first. The third is the output length, which is encoded and absorbed at the end, so that a 16-byte tag is not the beginning of a 32-byte tag. This guide covers each of them, with the encodings written out in bytes.
Table of Contents
- History and Standards
- The Sponge in Brief
- The Encodings
- cSHAKE
- KMAC
- Interactive Visualizer
- A Worked Example
- Python Implementation
- Security Status
- FAQ
- References
History and Standards
NIST published SP 800-185, “SHA-3 Derived Functions: cSHAKE, KMAC, TupleHash, and ParallelHash”, in December 2016. It adds four functions to the SHA-3 standard. The first two, cSHAKE and KMAC, are the base. TupleHash hashes a list of strings without ambiguity, and ParallelHash hashes a long message in parallel pieces.
KMAC comes in two strengths, KMAC128 and KMAC256. They are built on cSHAKE128 and cSHAKE256, and they have a security level of 128 and 256 bits. The output length is a parameter, and the NIST examples use 256-bit and 512-bit tags. There is also a variant called KMACXOF, which works like an extendable-output function, with no output length in the input.
NIST announced a draft revision of SP 800-185 on 8 October 2026. Revision 1 adds streaming interfaces for the extendable-output functions, so an application can feed input and read output in pieces. The public comment period is open until 7 December 2026. This guide describes the 2016 standard, which is the final version at the time of writing.
The Sponge in Brief
SHA-3 is built on a sponge that has a 1600-bit state. The state is split into a rate, which is the part that input is XORed into, and a capacity, which is never touched directly. The rate is 168 bytes for the 128-bit security level and 136 bytes for the 256-bit level. To absorb a block, the sponge XORs it into the rate part, and then runs the permutation Keccak-f[1600] on the whole state. To output data, it reads bytes from the rate part and runs the permutation again when it needs more.
The hidden capacity is the reason why length extension does not work. In a hash like SHA-256, the digest is the whole internal state, so an attacker who knows the digest can keep hashing from it. In the sponge, the output shows only the rate part. The attacker cannot restart the computation without the capacity. See the SHA-3 guide and the SHAKE guide for more on the sponge.
The Encodings
SP 800-185 needs four small encoding functions. They turn numbers and strings into unambiguous byte strings.
left_encode(x)writes the numberxin as few big-endian bytes as possible, at least one, and puts the count of those bytes in front. Soleft_encode(0)is0100, andleft_encode(300)is02012c.right_encode(x)does the same, with the count at the end. Soright_encode(0)is0001, andright_encode(300)is012c02.encode_string(S)isleft_encodeof the length ofSin bits, followed byS. For example, the nameKMAChas 4 bytes and 32 bits, so its encoding is01204b4d4143.bytepad(X, w)isleft_encode(w), thenX, then zero bytes up to a multiple ofwbytes.
Because the lengths are encoded, two different lists of strings can never produce the same byte string. This is the main protection against a quiet kind of attack, in which data is moved from one field to another.
cSHAKE
cSHAKE takes the input X, the output length, a function name N, and a customization string S. If both N and S are empty, cSHAKE is exactly SHAKE. If either is set, cSHAKE runs the sponge on:
bytepad( encode_string(N) || encode_string(S), rate ) || X
and it ends the input with two domain bits 00. SHAKE ends its input with the bits 1111. These different endings keep cSHAKE and SHAKE apart. In bytes, the padding of cSHAKE starts with the byte 0x04, and the padding of SHAKE starts with 0x1F. A final bit 1 at the end of the block completes the usual Keccak padding.
The name and the customization string give domain separation. Two applications of cSHAKE with different S produce unrelated outputs for the same data, so a tag made for one purpose cannot be reused for another.
KMAC in Full
KMAC is cSHAKE with the function name KMAC:
KMAC(K, X, L, S) = cSHAKE( bytepad(encode_string(K), rate) || X || right_encode(L), L, "KMAC", S )
The key K is encoded and padded to a whole number of blocks, so that the message X starts on a block boundary. After the message comes right_encode(L), where L is the tag length in bits. NIST always measures L in bits. The Python code below takes a length in bytes and multiplies it by 8. The customization string S is optional and can carry an application name.
In KMACXOF, the encoded length is right_encode(0), so the tag can be as long as you want, and longer tags start with the shorter ones.
Interactive Visualizer
The visualizer above runs this exact algorithm. Choose KMAC128 or KMAC256 and a tag length. Then enter a key in hex, a customization string, and a message of up to 127 bytes, and click Compute tag. The log shows each encoding, and each block that the sponge absorbs, with the first four of its 25 lanes after the permutation. Finally, it shows the squeezed tag. The defaults are the key and the customization string from NIST’s own samples. When it ends, the page tells you how many tag bits change when one bit of your message is flipped.
A Worked Example
This computes KMAC128 with a 256-bit tag. The key is the 32 bytes 404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f, the customization string is My Tagged Application, and the message is abc. The rate is 168 bytes.
The first block. The name KMAC is encoded as 01204b4d4143, which is a length of 32 bits, 01 20, and the four bytes. The customization string has 21 bytes, so it is encoded as 01a84d7920546167676564204170706c69636174696f6e. The first block is bytepad(encode_string(N) || encode_string(S), rate), the cSHAKE customization block, and it starts with left_encode(168) = 01a8:
01a801204b4d414301a84d7920546167676564204170706c69636174696f6e
and then 137 zero bytes. The sponge XORs this block into the state, which was all zeros, and runs Keccak-f. The first four lanes of the state are now 7443ee5f9b4ed80c b40c9f9d1c926a9b 79184509dc2f7b96 41c6e8b9396ffef8.
The key block. This is the second full block, and it comes from KMAC itself. The key has 256 bits, so left_encode(256) = 020100, and the encoded key is that, followed by the key. With left_encode(168) in front, the block is:
01a8020100404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f
and then 131 zero bytes. After the permutation, the first lanes are 72016d05d40545ca d775759f5f7ba1f6 dbf91bd8388e1b94 1e5f2539112b5686.
The message block. The message 616263 is followed by right_encode(256) = 010002, then the domain byte 04, then zeros, and then 80 in the last byte of the block:
61626301000204 ... (160 zero bytes) ... 80
After the last permutation, the first lanes are c4b9545f218e683c 2bd0f67f238a7a09 5d0c39d70b3c229b aba39ad53a63c1b9.
The tag. The first 32 bytes of the state are the tag:
3c688e215f54b9c4097a8a237ff6d02b9b223c0bd7390c5db9c1633ad59aa3ab
Changing the last letter to d gives 0ab12daf779dbfb93cb7f05a49c6b25b4247729debc1b5b2aafe4ba2da3a82b6, which differs in 126 of the 256 bits. About half is what a good pseudorandom function should give. Without the customization string, the tag is 8d86ee7dad69c94a1413222da3d1a9dcfb9757ccd5b6f4aa81086c9cc6305b0e. A 16-byte tag for the same inputs is 4708212752522a5b6507b7367e7ccec7, which is not the first half of the 32-byte tag, because the length is part of the input. A KMAC256 tag of 64 bytes is 398ed759372d877429f0fd6f6a1bd6f4072cb64ab95a1b3554412dcd8bbddf714ad94dbc0f67c13721f6244a4a9bb49f64f2cb9d271fff07b4a3a91d81211dc1.
The NIST sample. With the same key and customization string, but with the four message bytes 00 01 02 03, KMAC128 gives 3b1fba963cd8b0b59e8c1a6d71888b7143651af8ba0a7070c0979e2811324aa5. This is Sample 2 in NIST’s examples for KMAC.
Python Implementation
This is a complete KMAC128 and KMAC256, with the Keccak permutation written from the definition. The round constants come from a shift register, as in the Keccak specification, and the rotation offsets from a walk around the state. The function sponge is shared by SHA-3, SHAKE, and cSHAKE. The function kmac takes the tag length in bytes, and it rejects any security level other than 128 and 256.
# kmac.py
#
# KMAC, the Keccak-based message authentication code of NIST SP 800-185.
# It is built on cSHAKE, a customizable version of SHAKE, which in turn runs on
# the Keccak sponge of SHA-3. The key is absorbed first, padded to one block of
# the sponge. Then comes the message, then the requested output length, so that
# outputs of different lengths are unrelated. Everything is written from the
# definition: the permutation Keccak-f[1600] makes its own round constants.
MASK = (1 << 64) - 1
def rol(x, n):
n %= 64
return ((x << n) | (x >> (64 - n))) & MASK if n else x
def round_constants():
"""The 24 round constants come from a small shift register, as in the Keccak specification."""
constants = []
lfsr = 1
for _ in range(24):
constant = 0
for j in range(7):
if lfsr & 1:
constant |= 1 << ((1 << j) - 1)
lfsr = ((lfsr << 1) ^ 0x71) & 0xFF if lfsr & 0x80 else (lfsr << 1) & 0xFF
constants.append(constant)
return constants
ROUND_CONSTANTS = round_constants()
def rotation_offsets():
"""The rotation of every lane, from the triangular numbers walk around the 5 x 5 array."""
offsets = [[0] * 5 for _ in range(5)]
x, y = 1, 0
for t in range(24):
offsets[x][y] = ((t + 1) * (t + 2) // 2) % 64
x, y = y, (2 * x + 3 * y) % 5
return offsets
ROTATIONS = rotation_offsets()
def keccak_f(a):
"""The permutation Keccak-f[1600] on 25 lanes of 64 bits. Lane (x, y) is a[x + 5 * y]."""
a = list(a)
for rc in ROUND_CONSTANTS:
# theta: mix every column into its neighbours
c = [a[x] ^ a[x + 5] ^ a[x + 10] ^ a[x + 15] ^ a[x + 20] for x in range(5)]
d = [c[(x - 1) % 5] ^ rol(c[(x + 1) % 5], 1) for x in range(5)]
a = [a[i] ^ d[i % 5] for i in range(25)]
# rho and pi: rotate every lane and move it to a new place
b = [0] * 25
for x in range(5):
for y in range(5):
b[y + 5 * ((2 * x + 3 * y) % 5)] = rol(a[x + 5 * y], ROTATIONS[x][y])
# chi: the only nonlinear step
a = [b[x + 5 * y] ^ (~b[(x + 1) % 5 + 5 * y] & b[(x + 2) % 5 + 5 * y]) & MASK for y in range(5) for x in range(5)]
# iota: break the symmetry with the round constant
a[0] ^= rc
return a
def sponge(rate, suffix, message, out_len):
"""Absorb the message in blocks of `rate` bytes, then squeeze out_len bytes. suffix is the domain byte."""
padded = bytearray(message) + bytes([suffix])
padded += bytes(-len(padded) % rate)
padded[-1] |= 0x80 # the final 1 bit of the Keccak padding rule (the suffix byte holds the domain bits and the first 1)
state = [0] * 25
for i in range(0, len(padded), rate):
for j in range(rate // 8):
state[j] ^= int.from_bytes(padded[i + 8 * j:i + 8 * j + 8], "little")
state = keccak_f(state)
out = b""
while True:
out += b"".join(state[j].to_bytes(8, "little") for j in range(rate // 8))
if len(out) >= out_len:
return out[:out_len]
state = keccak_f(state)
def left_encode(x):
"""The number x as bytes, preceded by the count of those bytes."""
n = max(1, (x.bit_length() + 7) // 8)
return bytes([n]) + x.to_bytes(n, "big")
def right_encode(x):
"""The number x as bytes, followed by the count of those bytes."""
n = max(1, (x.bit_length() + 7) // 8)
return x.to_bytes(n, "big") + bytes([n])
def encode_string(s):
"""A byte string, preceded by its length in bits."""
return left_encode(8 * len(s)) + s
def bytepad(x, w):
"""Prefix x with the number w, and fill with zeros to a multiple of w bytes."""
z = left_encode(w) + x
return z + bytes(-len(z) % w)
def rate_for(security):
"""The rate in bytes: 168 for the 128-bit level, 136 for the 256-bit level."""
if security not in (128, 256):
raise ValueError("security must be 128 or 256")
return 168 if security == 128 else 136
def cshake(security, data, out_len, name=b"", custom=b""):
"""cSHAKE128 or cSHAKE256 (security is 128 or 256). With no name and no customization it is SHAKE."""
rate = rate_for(security)
if not name and not custom:
return sponge(rate, 0x1F, data, out_len)
return sponge(rate, 0x04, bytepad(encode_string(name) + encode_string(custom), rate) + data, out_len)
def kmac(security, key, message, out_len, custom=b""):
"""KMAC128 or KMAC256. out_len is in bytes, and it is part of the input, so different lengths are unrelated.
NIST's L is in bits, so the encoded length below is 8 * out_len.
"""
rate = rate_for(security)
data = bytepad(encode_string(key), rate) + message + right_encode(8 * out_len)
return cshake(security, data, out_len, b"KMAC", custom)
if __name__ == "__main__":
key = bytes(range(0x40, 0x60))
print("KMAC128: " + kmac(128, key, bytes([0, 1, 2, 3]), 32).hex())
print("KMAC128: " + kmac(128, key, bytes([0, 1, 2, 3]), 32, b"My Tagged Application").hex())
print("KMAC256: " + kmac(256, key, bytes([0, 1, 2, 3]), 64, b"My Tagged Application").hex())
Running it produces this output:
KMAC128: e5780b0d3ea6f7d3a429c5706aa43a00fadbd7d49628839e3187243f456ee14e
KMAC128: 3b1fba963cd8b0b59e8c1a6d71888b7143651af8ba0a7070c0979e2811324aa5
KMAC256: 20c570c31346f703c9ac36c61c03cb64c3970d0cfc787e9b79599d273a68d2f7f69d4cc3de9d104a351689f27cf6f5951f0103f33f4f24871024d9c27773a8dd
I checked this code against several independent sources before writing it up. The permutation and the sponge match Python’s own SHA3-256, SHA3-512, SHAKE128, and SHAKE256 on 1,608 outputs, with inputs of every length from 0 to 399 bytes, which cover all the block boundaries. The encodings follow the values in SP 800-185. The cSHAKE results match the NIST samples in Botan’s test file. The KMAC results match the six NIST samples and eight more vectors in that file, which were generated with OpenSSL and test keys at the edge of a block.
Security Status
SP 800-185 describes KMAC as a pseudorandom function and keyed hash with variable-length output. Because it is built on the sponge, it is not open to length extension. The security level is 128 bits for KMAC128 and 256 bits for KMAC256. For an output of L bits, the standard says that a collision attack needs about min(2^(L/2), 2^128) work for the 128-bit function, and a preimage attack at least min(2^L, 2^128). A short tag is therefore easier to attack.
A few rules apply. The standard says that an application must not choose a key shorter than its required security strength. The customization string should name the application, so that tags are not reused across purposes. A receiver must compare tags in constant time. The Python code in this guide does not run in constant time, so it is for learning only.
A plain hash of the key and the message, such as SHA3-256 of key || message, is not KMAC. For the key and message above, it gives 80965b1b70cc85ea548a75fd638d159c9bf9e8b93788e29254313c17c6dec891. It is likely to be secure, because the sponge resists length extension, but it lacks the domain separation, the block alignment, and the encoded lengths that make KMAC safe against confusion between fields.
FAQ
Why does KMAC not need a construction like HMAC?
HMAC hashes twice with two derived keys, because a plain hash like SHA-256 allows length extension. A sponge hides its capacity, so a keyed hash is safe in one pass. KMAC only adds careful encodings.
What is the point of the customization string?
It keeps different uses apart. Two systems that share a key by mistake still get different tags if their customization strings differ. It is also a place to put a protocol name or a version.
Why is the key padded to a full block?
So that the message starts on a block boundary. A short key takes one block, which is one call of the permutation. It also means a message cannot be mistaken for part of a key.
What is the difference between KMAC and KMACXOF?
KMAC encodes the output length into its input, so tags of different lengths can be treated as unrelated functions. KMACXOF encodes zero instead, so a longer output starts with the shorter one. KMACXOF is useful as a key derivation function or a stream of pseudorandom bytes.
Is KMAC better than HMAC-SHA3?
Both are secure, but KMAC is simpler, because it needs one call of the sponge and no wrapper. HMAC is more widely supported. Choose based on the library and on what a protocol requires.
References
-
Kelsey, J., Chang, S., and Perlner, R. “SHA-3 Derived Functions: cSHAKE, KMAC, TupleHash, and ParallelHash.” NIST Special Publication 800-185, 2016. Available at: https://nvlpubs.nist.gov/nistpubs/SpecialPublications/NIST.SP.800-185.pdf
-
NIST. “SHA-3 Standard: Permutation-Based Hash and Extendable-Output Functions.” FIPS 202, 2015. Available at: https://csrc.nist.gov/pubs/fips/202/final
-
Bertoni, G., Daemen, J., Peeters, M., and Van Assche, G. “The Keccak Reference.” Version 3.0, 2011. Available at: https://keccak.team/
-
NIST. “KMAC and cSHAKE example values.” Cryptographic Standards and Guidelines. Available at: https://csrc.nist.gov/projects/cryptographic-standards-and-guidelines/example-values
-
Botan project. “KMAC and cSHAKE test vectors.” Available at: https://github.com/randombit/botan