tr-kmac
v1.0.1
Published
KMAC and cSHAKE (NIST SP 800-185) for Node.js with zero dependencies
Maintainers
Readme
tr-kmac
KMAC and cSHAKE (NIST SP 800-185) for Node.js with zero dependencies.
Node's built-in node:crypto exposes plain SHAKE but not cSHAKE or
KMAC, and KMAC cannot be constructed from plain SHAKE (cSHAKE uses a
different domain-separation padding). In particular, KMAC is not
HMAC with a SHA-3 digest; the two constructions produce unrelated
output. This package implements the real SP 800-185 functions on a
self-contained Keccak-f[1600] core and verifies them against the
official NIST sample vectors, NIST ACVP test cases, and vectors
generated with OpenSSL 3.
The interface is byte-oriented: all inputs and outputs are whole byte strings, as permitted by SP 800-185. Bit-granular strings are not supported.
Reference
Installation
npm install tr-kmacNode.js >=18.0.0 is required.
Exports
const { kmac128, kmac256, kmac128xof, kmac256xof, cshake128, cshake256 } = require('tr-kmac');kmac128(key, data, outputLength, customization) / kmac256(key, data, outputLength, customization)
Computes KMAC128 or KMAC256 (SP 800-185 section 4) and returns a
Buffer of outputLength bytes.
key:Buffer,Uint8Array, or UTF-8string; any length including empty (for security the key should be at least 16 bytes for KMAC128 and 32 bytes for KMAC256)data:Buffer,Uint8Array, or UTF-8stringoutputLength: output length in bytes (positive integer). The requested length is bound into the computation: different lengths produce unrelated outputs.customization: optionalBuffer,Uint8Array, or UTF-8string(SP 800-185 customization stringS); defaults to empty
Example:
const { kmac256 } = require('tr-kmac');
const mac = kmac256(key, message, 32, 'My Tagged Application');kmac128xof(key, data, outputLength, customization) / kmac256xof(key, data, outputLength, customization)
The KMACXOF variants (SP 800-185 section 4.3.1). Arguments are as
above, but the output behaves as an extendable-output function: a
shorter output is a prefix of a longer one for the same inputs. Use
these when a KDF-style stream of output is wanted; use plain
kmac128/kmac256 when the MAC length itself must be authenticated.
cshake128(data, outputLength, functionName, customization) / cshake256(data, outputLength, functionName, customization)
Computes cSHAKE128 or cSHAKE256 (SP 800-185 section 3) and returns a
Buffer of outputLength bytes.
functionName: optional NIST function-name stringN; leave empty unless implementing a NIST-defined derived functioncustomization: optional customization stringS
When both functionName and customization are empty, the output
equals plain SHAKE128/SHAKE256 of the data, per SP 800-185.
Errors
Invalid argument types and invalid output lengths throw
Error('Invalid ...'). Inputs are never coerced silently except
strings, which are interpreted as UTF-8.
Test vectors
npm test verifies the implementation against committed vectors:
- All official NIST SP 800-185 sample vectors (KMAC samples #1–#6, KMACXOF samples #1–#6, cSHAKE samples #1–#4) from the NIST "SHA-3 Derived Functions" example files.
- The byte-aligned test cases from the NIST ACVP-Server KMAC-128 and KMAC-256 sample vector sets (AFT and MVT). The remaining ACVP cases exercise bit-granular string lengths, which this byte-oriented implementation intentionally does not support.
- 172 differential vectors generated with OpenSSL 3.6.3 (an independent implementation), sweeping message, key, output, and customization lengths across all internal block boundaries for all four KMAC variants.
- Cross-validation of the Keccak core against
node:cryptoSHAKE128/SHAKE256 at sponge-rate boundaries. - Structural property and invalid-input checks.
Performance
The Keccak core uses BigInt lanes and favors auditability over raw speed. Throughput is in the megabytes-per-second range, which is ample for MAC, KDF, and other short-input use. It is not intended for hashing bulk data.
Security notes
This is not a constant-time implementation: BigInt arithmetic is data-dependent in time, so the Keccak permutation may leak timing information about its inputs. This is acceptable for typical MAC/KDF use (including KDFs over ephemeral, per-message secrets), but avoid building remotely observable, high-frequency operations keyed by a long-term secret directly on this primitive.
Author
Timo J. Rinne [email protected] — https://github.com/rinne/
Copyright
Copyright © 2026 Timo J. Rinne [email protected].
See COPYING for the full MIT license text.
License
MIT License
