Audited & minimal 0-dependency JS implementation of SHA, RIPEMD, BLAKE, HMAC, HKDF, PBKDF & Scrypt
Advanced Keccak-based cryptographic functions from NIST SP 800-185 and IETF drafts, including customizable SHAKE (cSHAKE), Keccak MAC (KMAC), TurboSHAKE, KangarooTwelve, TupleHash, ParallelHash, and a Keccak-based pseudo-random generator.
import {
cshake128, cshake256,
kmac128, kmac256, kmac128xof, kmac256xof,
tuplehash128, tuplehash256, tuplehash128xof, tuplehash256xof,
parallelhash128, parallelhash256, parallelhash128xof, parallelhash256xof,
turboshake128, turboshake256,
kt128, kt256,
HopMAC128, HopMAC256,
keccakprg
} from '@noble/hashes/sha3-addons.js';Customizable SHAKE allows domain separation through customization strings, preventing hash collisions between different protocol contexts.
/**
* cSHAKE128 - Customizable SHAKE128
* @param msg - Input data as Uint8Array
* @param opts - Customization options
* @param opts.personalization - Domain separation string
* @param opts.NISTfn - NIST function name (string or Uint8Array)
* @param opts.dkLen - Desired output length in bytes
* @returns Hash digest of specified length
*/
function cshake128(msg: Uint8Array, opts?: cShakeOpts): Uint8Array;
// Properties
cshake128.outputLen: undefined; // Variable output length
cshake128.blockLen: 168; // Block length in bytes
// Create incremental hasher
function create(opts?: cShakeOpts): Keccak;
/**
* cSHAKE256 - Customizable SHAKE256
* @param msg - Input data as Uint8Array
* @param opts - Customization options
* @param opts.personalization - Domain separation string
* @param opts.NISTfn - NIST function name (string or Uint8Array)
* @param opts.dkLen - Desired output length in bytes
* @returns Hash digest of specified length
*/
function cshake256(msg: Uint8Array, opts?: cShakeOpts): Uint8Array;
// Properties
cshake256.outputLen: undefined; // Variable output length
cshake256.blockLen: 136; // Block length in bytes
// Create incremental hasher
function create(opts?: cShakeOpts): Keccak;
/**
* Options for cSHAKE functions
*/
interface cShakeOpts {
/** Domain separation / personalization string */
personalization?: Uint8Array;
/** NIST function name for domain separation */
NISTfn?: string | Uint8Array;
/** Desired output length in bytes */
dkLen?: number;
}Usage:
import { cshake256 } from '@noble/hashes/sha3-addons.js';
import { utf8ToBytes } from '@noble/hashes/utils.js';
// Domain-separated hashing for different contexts
const emailHash = cshake256(data, {
personalization: utf8ToBytes('email-verification'),
dkLen: 32
});
const authHash = cshake256(data, {
personalization: utf8ToBytes('authentication-token'),
dkLen: 32
});
// These produce different outputs even for the same inputKeccak-based MAC that provides authentication with optional XOF mode.
/**
* KMAC128 - 128-bit Keccak MAC
* @param key - Secret key as Uint8Array
* @param message - Message to authenticate as Uint8Array
* @param opts - Options
* @param opts.personalization - Domain separation string
* @param opts.dkLen - Desired output length in bytes (default: 32)
* @returns MAC tag
*/
function kmac128(key: Uint8Array, message: Uint8Array, opts?: KMACOpts): Uint8Array;
// Create incremental MAC
function create(key: Uint8Array, opts?: KMACOpts): Keccak;
/**
* KMAC256 - 256-bit Keccak MAC
* @param key - Secret key as Uint8Array
* @param message - Message to authenticate as Uint8Array
* @param opts - Options
* @param opts.personalization - Domain separation string
* @param opts.dkLen - Desired output length in bytes (default: 64)
* @returns MAC tag
*/
function kmac256(key: Uint8Array, message: Uint8Array, opts?: KMACOpts): Uint8Array;
// Create incremental MAC
function create(key: Uint8Array, opts?: KMACOpts): Keccak;
/**
* KMAC128 XOF - 128-bit Keccak MAC with extendable output
* @param key - Secret key as Uint8Array
* @param message - Message to authenticate as Uint8Array
* @param opts - Options
* @param opts.personalization - Domain separation string
* @param opts.dkLen - Desired output length in bytes
* @returns MAC tag
*/
function kmac128xof(key: Uint8Array, message: Uint8Array, opts?: KMACOpts): Uint8Array;
// Create incremental MAC
function create(key: Uint8Array, opts?: KMACOpts): Keccak;
/**
* KMAC256 XOF - 256-bit Keccak MAC with extendable output
* @param key - Secret key as Uint8Array
* @param message - Message to authenticate as Uint8Array
* @param opts - Options
* @param opts.personalization - Domain separation string
* @param opts.dkLen - Desired output length in bytes
* @returns MAC tag
*/
function kmac256xof(key: Uint8Array, message: Uint8Array, opts?: KMACOpts): Uint8Array;
// Create incremental MAC
function create(key: Uint8Array, opts?: KMACOpts): Keccak;
/**
* Options for KMAC functions
*/
interface KMACOpts {
/** Domain separation / personalization string */
personalization?: Uint8Array;
/** Desired output length in bytes */
dkLen?: number;
}Usage:
import { kmac256 } from '@noble/hashes/sha3-addons.js';
import { utf8ToBytes } from '@noble/hashes/utils.js';
const key = new Uint8Array(32).fill(0x42);
const message = utf8ToBytes('Hello, World!');
// Simple MAC
const mac = kmac256(key, message);
// MAC with custom output length
const longMac = kmac256(key, message, { dkLen: 64 });
// MAC with domain separation
const authMac = kmac256(key, message, {
personalization: utf8ToBytes('auth-v1'),
dkLen: 32
});
// Incremental MAC
const macHasher = kmac256.create(key, { dkLen: 32 });
macHasher.update(chunk1);
macHasher.update(chunk2);
const result = macHasher.digest();TupleHash provides unambiguous hashing of tuples, ensuring that different tuple structures produce different hashes.
/**
* TupleHash128 - 128-bit unambiguous tuple hashing
* @param messages - Array of messages to hash
* @param opts - Options
* @param opts.personalization - Domain separation string
* @param opts.dkLen - Desired output length in bytes (default: 32)
* @returns Hash digest
*/
function tuplehash128(messages: Uint8Array[], opts?: TupleHashOpts): Uint8Array;
// Create incremental hasher
function create(opts?: TupleHashOpts): TupleHashInstance;
/**
* TupleHash256 - 256-bit unambiguous tuple hashing
* @param messages - Array of messages to hash
* @param opts - Options
* @param opts.personalization - Domain separation string
* @param opts.dkLen - Desired output length in bytes (default: 64)
* @returns Hash digest
*/
function tuplehash256(messages: Uint8Array[], opts?: TupleHashOpts): Uint8Array;
// Create incremental hasher
function create(opts?: TupleHashOpts): TupleHashInstance;
/**
* TupleHash128 XOF - 128-bit tuple hashing with extendable output
* @param messages - Array of messages to hash
* @param opts - Options
* @param opts.personalization - Domain separation string
* @param opts.dkLen - Desired output length in bytes
* @returns Hash digest
*/
function tuplehash128xof(messages: Uint8Array[], opts?: TupleHashOpts): Uint8Array;
// Create incremental hasher
function create(opts?: TupleHashOpts): TupleHashInstance;
/**
* TupleHash256 XOF - 256-bit tuple hashing with extendable output
* @param messages - Array of messages to hash
* @param opts - Options
* @param opts.personalization - Domain separation string
* @param opts.dkLen - Desired output length in bytes
* @returns Hash digest
*/
function tuplehash256xof(messages: Uint8Array[], opts?: TupleHashOpts): Uint8Array;
// Create incremental hasher
function create(opts?: TupleHashOpts): TupleHashInstance;
/**
* Options for TupleHash functions
*/
interface TupleHashOpts {
/** Domain separation / personalization string */
personalization?: Uint8Array;
/** Desired output length in bytes */
dkLen?: number;
}Usage:
import { tuplehash256 } from '@noble/hashes/sha3-addons.js';
import { utf8ToBytes } from '@noble/hashes/utils.js';
// Unambiguous tuple hashing
const tuple1 = [utf8ToBytes('ab'), utf8ToBytes('c')];
const tuple2 = [utf8ToBytes('a'), utf8ToBytes('bc')];
const hash1 = tuplehash256(tuple1);
const hash2 = tuplehash256(tuple2);
// hash1 !== hash2 even though concatenation is the same
// With personalization
const hash3 = tuplehash256(tuple1, {
personalization: utf8ToBytes('my-protocol-v1')
});ParallelHash enables parallel processing of large inputs (though JavaScript implementation is not actually parallel, it's included for compatibility).
/**
* ParallelHash128 - 128-bit parallel hashing
* @param msg - Input data as Uint8Array
* @param opts - Options
* @param opts.blockLen - Block size for parallel processing (default: 8)
* @param opts.personalization - Domain separation string
* @param opts.dkLen - Desired output length in bytes (default: 32)
* @returns Hash digest
*/
function parallelhash128(msg: Uint8Array, opts?: ParallelOpts): Uint8Array;
// Create incremental hasher
function create(opts?: ParallelOpts): Keccak;
/**
* ParallelHash256 - 256-bit parallel hashing
* @param msg - Input data as Uint8Array
* @param opts - Options
* @param opts.blockLen - Block size for parallel processing (default: 8)
* @param opts.personalization - Domain separation string
* @param opts.dkLen - Desired output length in bytes (default: 64)
* @returns Hash digest
*/
function parallelhash256(msg: Uint8Array, opts?: ParallelOpts): Uint8Array;
// Create incremental hasher
function create(opts?: ParallelOpts): Keccak;
/**
* ParallelHash128 XOF - 128-bit parallel hashing with extendable output
* @param msg - Input data as Uint8Array
* @param opts - Options
* @param opts.blockLen - Block size for parallel processing
* @param opts.personalization - Domain separation string
* @param opts.dkLen - Desired output length in bytes
* @returns Hash digest
*/
function parallelhash128xof(msg: Uint8Array, opts?: ParallelOpts): Uint8Array;
// Create incremental hasher
function create(opts?: ParallelOpts): Keccak;
/**
* ParallelHash256 XOF - 256-bit parallel hashing with extendable output
* @param msg - Input data as Uint8Array
* @param opts - Options
* @param opts.blockLen - Block size for parallel processing
* @param opts.personalization - Domain separation string
* @param opts.dkLen - Desired output length in bytes
* @returns Hash digest
*/
function parallelhash256xof(msg: Uint8Array, opts?: ParallelOpts): Uint8Array;
// Create incremental hasher
function create(opts?: ParallelOpts): Keccak;
/**
* Options for ParallelHash functions
*/
interface ParallelOpts {
/** Block size for parallel processing (in bytes) */
blockLen?: number;
/** Domain separation / personalization string */
personalization?: Uint8Array;
/** Desired output length in bytes */
dkLen?: number;
}Usage:
import { parallelhash256 } from '@noble/hashes/sha3-addons.js';
import { utf8ToBytes } from '@noble/hashes/utils.js';
const largeData = new Uint8Array(1024 * 1024); // 1MB
const hash = parallelhash256(largeData, {
blockLen: 8192, // 8KB blocks
dkLen: 32
});TurboSHAKE is a faster variant using 12 rounds instead of 24, trading some security margin for performance.
/**
* TurboSHAKE128 - 12-round reduced Keccak (128-bit)
* @param msg - Input data as Uint8Array
* @param opts - Options
* @param opts.D - Domain separation byte (default: 0x1f)
* @param opts.dkLen - Desired output length in bytes
* @returns Hash digest
*/
function turboshake128(msg: Uint8Array, opts?: TurboshakeOpts): Uint8Array;
// Properties
turboshake128.outputLen: undefined; // Variable output length
turboshake128.blockLen: 168; // Block length in bytes
// Create incremental hasher
function create(opts?: TurboshakeOpts): Keccak;
/**
* TurboSHAKE256 - 12-round reduced Keccak (256-bit)
* @param msg - Input data as Uint8Array
* @param opts - Options
* @param opts.D - Domain separation byte (default: 0x1f)
* @param opts.dkLen - Desired output length in bytes
* @returns Hash digest
*/
function turboshake256(msg: Uint8Array, opts?: TurboshakeOpts): Uint8Array;
// Properties
turboshake256.outputLen: undefined; // Variable output length
turboshake256.blockLen: 136; // Block length in bytes
// Create incremental hasher
function create(opts?: TurboshakeOpts): Keccak;
/**
* Options for TurboSHAKE functions
*/
interface TurboshakeOpts {
/** Domain separation byte (0x01-0x7f) */
D?: number;
/** Desired output length in bytes */
dkLen?: number;
}Usage:
import { turboshake256 } from '@noble/hashes/sha3-addons.js';
// Fast hashing with reduced rounds
const hash = turboshake256(data, { dkLen: 32 });
// With custom domain separation
const hash2 = turboshake256(data, {
D: 0x05,
dkLen: 64
});KangarooTwelve combines reduced rounds with a tree structure for very fast hashing.
/**
* KangarooTwelve 128-bit (K12-128)
* @param msg - Input data as Uint8Array
* @param opts - Options
* @param opts.personalization - Domain separation string
* @param opts.dkLen - Desired output length in bytes (default: 32)
* @returns Hash digest
*/
function kt128(msg: Uint8Array, opts?: KangarooOpts): Uint8Array;
// Properties
kt128.outputLen: 32; // Default output length in bytes
kt128.blockLen: undefined; // Variable block length
// Create incremental hasher
function create(opts?: KangarooOpts): _KangarooTwelve;
/**
* KangarooTwelve 256-bit (K12-256)
* @param msg - Input data as Uint8Array
* @param opts - Options
* @param opts.personalization - Domain separation string
* @param opts.dkLen - Desired output length in bytes (default: 64)
* @returns Hash digest
*/
function kt256(msg: Uint8Array, opts?: KangarooOpts): Uint8Array;
// Properties
kt256.outputLen: 64; // Default output length in bytes
kt256.blockLen: undefined; // Variable block length
// Create incremental hasher
function create(opts?: KangarooOpts): _KangarooTwelve;
/**
* Options for KangarooTwelve functions
*/
interface KangarooOpts {
/** Domain separation / personalization string */
personalization?: Uint8Array;
/** Desired output length in bytes */
dkLen?: number;
}
/**
* HopMAC128 - KangarooTwelve-based MAC (128-bit)
* @param key - Secret key as Uint8Array
* @param message - Message to authenticate as Uint8Array
* @param personalization - Optional domain separation string
* @param dkLen - Desired output length in bytes (default: 32)
* @returns MAC tag
*/
function HopMAC128(
key: Uint8Array,
message: Uint8Array,
personalization?: Uint8Array,
dkLen?: number
): Uint8Array;
/**
* HopMAC256 - KangarooTwelve-based MAC (256-bit)
* @param key - Secret key as Uint8Array
* @param message - Message to authenticate as Uint8Array
* @param personalization - Optional domain separation string
* @param dkLen - Desired output length in bytes (default: 64)
* @returns MAC tag
*/
function HopMAC256(
key: Uint8Array,
message: Uint8Array,
personalization?: Uint8Array,
dkLen?: number
): Uint8Array;Usage:
import { kt128, HopMAC128 } from '@noble/hashes/sha3-addons.js';
import { utf8ToBytes } from '@noble/hashes/utils.js';
// Fast hashing
const hash = kt128(largeData, { dkLen: 32 });
// With personalization
const hash2 = kt128(data, {
personalization: utf8ToBytes('app-v1'),
dkLen: 32
});
// MAC using HopMAC
const key = new Uint8Array(32).fill(0x42);
const message = utf8ToBytes('authenticate this');
const mac = HopMAC128(key, message);Keccak-based pseudo-random generator for generating cryptographically secure random bytes.
/**
* Creates a Keccak-based pseudo-random generator
* @param capacity - Security capacity in bits (default: 254 for 128-bit security)
* @returns PRG instance
*/
function keccakprg(capacity?: number): _KeccakPRG;
/**
* Keccak PRG instance
*/
class _KeccakPRG {
/**
* Adds entropy to the PRG state
* @param seed - Entropy source as Uint8Array
*/
addEntropy(seed: Uint8Array): void;
/**
* Generates random bytes
* @param length - Number of bytes to generate
* @returns Cryptographically secure random bytes
*/
randomBytes(length: number): Uint8Array;
/**
* Clears internal state
*/
clean(): void;
}Usage:
import { keccakprg } from '@noble/hashes/sha3-addons.js';
import { randomBytes } from '@noble/hashes/utils.js';
// Create PRG with 254-bit capacity (128-bit security)
const prg = keccakprg(254);
// Add initial entropy
prg.addEntropy(randomBytes(32));
// Generate random bytes
const random1 = prg.randomBytes(32);
const random2 = prg.randomBytes(64);
const random3 = prg.randomBytes(16);
// Add more entropy periodically
prg.addEntropy(randomBytes(32));
// Clean up when done
prg.clean();import { cshake256 } from '@noble/hashes/sha3-addons.js';
import { utf8ToBytes } from '@noble/hashes/utils.js';
function deriveKey(
masterKey: Uint8Array,
context: string,
keyId: number,
keyLen: number
): Uint8Array {
const hasher = cshake256.create({
personalization: utf8ToBytes(`${context}-v1`),
dkLen: keyLen
});
hasher.update(masterKey);
hasher.update(new Uint8Array([keyId]));
return hasher.digest();
}
const masterKey = new Uint8Array(32).fill(0x42);
const encKey = deriveKey(masterKey, 'encryption', 1, 32);
const authKey = deriveKey(masterKey, 'authentication', 2, 32);import { kmac256 } from '@noble/hashes/sha3-addons.js';
import { utf8ToBytes, concatBytes } from '@noble/hashes/utils.js';
function encryptAndAuthenticate(
key: Uint8Array,
plaintext: Uint8Array,
nonce: Uint8Array
): { ciphertext: Uint8Array; tag: Uint8Array } {
// Derive encryption key
const encKey = kmac256(key, concatBytes(utf8ToBytes('enc'), nonce), { dkLen: 32 });
// XOR encryption (for demonstration - use proper cipher in production)
const ciphertext = plaintext.map((b, i) => b ^ encKey[i % 32]);
// Generate authentication tag
const tag = kmac256(key, concatBytes(nonce, ciphertext), {
personalization: utf8ToBytes('auth'),
dkLen: 32
});
return { ciphertext, tag };
}import { turboshake256 } from '@noble/hashes/sha3-addons.js';
function fastHash(data: Uint8Array): Uint8Array {
// Use TurboSHAKE for non-critical hashing where speed matters
return turboshake256(data, { dkLen: 32 });
}
function criticalHash(data: Uint8Array): Uint8Array {
// Use standard SHA3-256 for security-critical operations
return sha3_256(data);
}cSHAKE, KMAC, TupleHash, and ParallelHash conform to NIST SP 800-185 specifications.
cSHAKE: Domain separation, custom hash functions KMAC: Message authentication, keyed hashing TupleHash: Unambiguous tuple/list hashing ParallelHash: Large data hashing (compatibility) TurboSHAKE: Fast hashing with acceptable security KangarooTwelve: Very fast hashing for large data KeccakPRG: Deterministic random generation