SHAKE-256 Security-Focused API Documentation
Algorithm: SHAKE-256 (Secure Hash Algorithm Keccak 256)
Type: Extensible Output Function (XOF)
Security Level: 256-bit (min(d/2, 256) for d-bit output)
Specification: FIPS 202
Security Contract
shake256(data: Uint8Array, outputLength: number): Uint8Array
Preconditions:
- Input data: Any length (0 to unlimited)
- Output length: 1 to 2^32 bytes (practical limit)
- Output length should match security requirements
Postconditions:
- Returns exactly
outputLengthbytes - Output is deterministic
- Acts as random oracle up to 256-bit security
- No length extension vulnerabilities
Side Effects:
- None - pure function
- No internal state between calls
- Input data unchanged
Attack Resistance Matrix
| Attack Type | Resistance | Notes |
|---|---|---|
| Collision | ✅ 2^128 | For ≥256-bit output |
| Preimage | ✅ 2^256 | Full security |
| Second Preimage | ✅ 2^256 | Strong resistance |
| Length Extension | ✅ Immune | Sponge construction |
| State Recovery | ✅ 2^256 | From output |
| Timing Attacks | ✅ Resistant | Constant-time |
| Quantum | ⚠️ 2^128 | Grover’s algorithm |
Secure Usage Examples
✅ CORRECT: Variable-Length Key Derivation
import { shake256 } from 'metamui-shake256';
// Derive multiple keys from master secret
function deriveKeys(
masterSecret: Uint8Array,
context: string
): {
encryptionKey: Uint8Array;
authenticationKey: Uint8Array;
ivKey: Uint8Array;
} {
// Derive 96 bytes total (3 × 32-byte keys)
const derived = shake256.xof(
concat(masterSecret, stringToBytes(context)),
96
);
return {
encryptionKey: derived.slice(0, 32),
authenticationKey: derived.slice(32, 64),
ivKey: derived.slice(64, 96)
};
}
✅ CORRECT: Domain-Separated Hashing
import { shake256 } from 'metamui-shake256';
// NIST SP 800-185 compliant domain separation
function cshake256(
data: Uint8Array,
outputLength: number,
functionName: string,
customization: string
): Uint8Array {
// Encode strings as per NIST standard
const fnEncoded = encodeString(functionName);
const custEncoded = encodeString(customization);
// Prepend domain separation
const input = concat(
fnEncoded,
custEncoded,
data
);
return shake256.xof(input, outputLength);
}
// Usage
const hash = cshake256(
data,
32,
"EmailSignature",
"MyApp v1.0"
);
✅ CORRECT: Randomness Expansion
import { shake256 } from 'metamui-shake256';
// Expand seed to arbitrary length
function expandSeed(
seed: Uint8Array,
outputBytes: number
): Uint8Array {
// SHAKE-256 as deterministic random generator
return shake256.xof(seed, outputBytes);
}
// Generate deterministic random values
const expanded = expandSeed(seed, 1024); // 1KB of randomness
✅ CORRECT: Post-Quantum KDF
import { shake256 } from 'metamui-shake256';
// Kyber/ML-KEM key derivation
function kyberKdf(
sharedSecret: Uint8Array,
publicKey: Uint8Array
): Uint8Array {
// Standard post-quantum KDF construction
const input = concat(sharedSecret, publicKey);
return shake256.xof(input, 32);
}
Common Mistakes to Avoid
❌ WRONG: Output Too Short for Security
// NEVER DO THIS - Output too short
const key = shake256.xof(secret, 8); // Only 64 bits!
// ✅ CORRECT: Use adequate output length
const key = shake256.xof(secret, 32); // 256 bits
❌ WRONG: Using as Regular Hash
// NEVER DO THIS - Inefficient for fixed output
function hashFile(data: Uint8Array): Uint8Array {
return shake256.xof(data, 32); // Works but SHA3-256 is better
}
// ✅ CORRECT: Use SHA3-256 for fixed-length hashing
import { sha3_256 } from 'metamui-sha3';
function hashFile(data: Uint8Array): Uint8Array {
return sha3_256.hash(data);
}
❌ WRONG: Reusing Output Stream
// NEVER DO THIS - Security boundary violation
const stream = shake256.xof(secret, 1000);
const key1 = stream.slice(0, 32);
const key2 = stream.slice(32, 64); // Related to key1!
// ✅ CORRECT: Use domain separation
const key1 = shake256.xof(concat(secret, [0x01]), 32);
const key2 = shake256.xof(concat(secret, [0x02]), 32);
Implementation Security
Sponge Construction Security
class Shake256 {
private state: Uint8Array;
private rate: number = 136; // 1088 bits
private capacity: number = 64; // 512 bits
constructor() {
// 1600-bit state (Keccak-f[1600])
this.state = new Uint8Array(200);
}
absorb(data: Uint8Array): void {
// Process in rate-sized blocks
for (let i = 0; i < data.length; i += this.rate) {
const block = data.slice(i, i + this.rate);
this.xorIntoState(block);
this.keccakF1600();
}
}
squeeze(outputLength: number): Uint8Array {
const output = new Uint8Array(outputLength);
let outputOffset = 0;
while (outputOffset < outputLength) {
// Extract rate bytes
const block = this.state.slice(0, this.rate);
const copyLength = Math.min(
this.rate,
outputLength - outputOffset
);
output.set(
block.slice(0, copyLength),
outputOffset
);
outputOffset += copyLength;
if (outputOffset < outputLength) {
this.keccakF1600(); // Permute for more output
}
}
return output;
}
}
Streaming API for Large Outputs
import { shake256 } from 'metamui-shake256';
// Memory-efficient streaming
class Shake256Stream {
private hasher: Shake256Instance;
private buffer: Uint8Array;
private position: number = 0;
constructor(data: Uint8Array) {
this.hasher = shake256.create();
this.hasher.update(data);
this.hasher.finalize(); // Switch to squeeze mode
this.buffer = new Uint8Array(136); // Rate size
}
read(length: number): Uint8Array {
const output = new Uint8Array(length);
let filled = 0;
while (filled < length) {
if (this.position === 0) {
this.hasher.squeeze(this.buffer);
}
const available = this.buffer.length - this.position;
const needed = length - filled;
const toCopy = Math.min(available, needed);
output.set(
this.buffer.slice(this.position, this.position + toCopy),
filled
);
filled += toCopy;
this.position = (this.position + toCopy) % this.buffer.length;
}
return output;
}
}
Platform-Specific Notes
JavaScript/TypeScript
- Pure JS implementation available
- WebCrypto API support limited
- WASM recommended for performance
Python
hashlib.shake_256()in standard library- Supports arbitrary output length
- C implementation for speed
Rust
sha3crate withShake256- Streaming API available
no_stdcompatible
Comparison with Other XOFs
| Feature | SHAKE-256 | BLAKE3 XOF | ChaCha20 |
|---|---|---|---|
| Security | 256-bit | 128-bit | 256-bit |
| Speed | Moderate | Fastest | Fast |
| Standardization | NIST | Industry | IETF |
| Quantum Resistance | 128-bit | 64-bit | 128-bit |
| Parallelizable | No | Yes | No |
When to Use SHAKE-256
✅ Appropriate Uses:
- Key derivation with variable output
- Post-quantum cryptography (ML-KEM, Dilithium)
- Randomness expansion
- Domain-separated hashing (cSHAKE)
- Protocol-specific hash functions
- Mask generation functions
❌ Inappropriate Uses:
- Fixed-length hashing (use SHA3-256)
- High-performance requirements (use BLAKE3)
- Stream cipher (use ChaCha20)
- Password hashing (use Argon2)
Advanced Features
TupleHash (NIST SP 800-185)
function tupleHash256(
tuples: Uint8Array[],
outputLength: number,
customization: string = ""
): Uint8Array {
// Encode each tuple with length prefix
const encoded = tuples.map(tuple =>
concat(encodeLength(tuple.length), tuple)
);
return cshake256(
concat(...encoded),
outputLength,
"TupleHash",
customization
);
}
ParallelHash (NIST SP 800-185)
function parallelHash256(
data: Uint8Array,
blockSize: number,
outputLength: number,
customization: string = ""
): Uint8Array {
// Split into blocks for parallel processing
const blocks: Uint8Array[] = [];
for (let i = 0; i < data.length; i += blockSize) {
blocks.push(data.slice(i, i + blockSize));
}
// Hash blocks in parallel
const blockHashes = blocks.map(block =>
shake256.xof(block, 32)
);
// Combine with domain separation
return cshake256(
concat(...blockHashes),
outputLength,
"ParallelHash",
customization
);
}
Security Checklist
- Use minimum 32-byte output for cryptographic keys
- Apply domain separation for different uses
- Don’t reuse output bytes for different purposes
- Consider cSHAKE for protocol-specific hashing
- Verify output length matches security requirements
- Clear sensitive outputs from memory
- Use constant-time operations throughout
Security Analysis
Threat Model: SHAKE-256 Threat Model
The comprehensive threat analysis covers:
- Algorithm-specific attack vectors
- Implementation vulnerabilities
- Side-channel considerations
- Quantum resistance analysis (where applicable)
- Deployment recommendations
For complete security analysis and risk assessment, see the dedicated threat model documentation.