Extendable output functions
An extendable output function (XOF) is similar to a hash function, but its output can be extended to any desired length.
Unlike a hash function where the output size is fixed, a XOF can produce output of arbitrary length from the same input, making it useful for key derivation, stream generation, and applications where variable-length output is needed.
libsodium provides two families of XOFs:
SHAKE: NIST-standardized XOFs from FIPS 202
TurboSHAKE: Faster variants using reduced-round Keccak, standardized in RFC 9861
Single-part example
#define MESSAGE ((const unsigned char *) "Arbitrary data to hash")
#define MESSAGE_LEN 22
unsigned char out[32];
crypto_xof_turboshake128(out, sizeof out, MESSAGE, MESSAGE_LEN);Multi-part example
#define MESSAGE_PART1 \
((const unsigned char *) "Arbitrary data to hash")
#define MESSAGE_PART1_LEN 22
#define MESSAGE_PART2 \
((const unsigned char *) "is longer than expected")
#define MESSAGE_PART2_LEN 23
unsigned char out[32];
crypto_xof_turboshake128_state state;
crypto_xof_turboshake128_init(&state);
crypto_xof_turboshake128_update(&state, MESSAGE_PART1, MESSAGE_PART1_LEN);
crypto_xof_turboshake128_update(&state, MESSAGE_PART2, MESSAGE_PART2_LEN);
crypto_xof_turboshake128_squeeze(&state, out, sizeof out);Incremental output
Unlike regular hash functions, XOFs can be squeezed multiple times to produce additional output. The concatenation of all squeezed outputs is identical to squeezing the total length at once.
Purpose
XOFs can be used as:
Hash functions: producing fixed-length digests
Key derivation functions: deriving multiple keys from a seed
Deterministic random generators: expanding a seed into arbitrary-length output
Domain-separated hashing: using custom domain separators
Real-world use cases
Deriving multiple keys from a master secret
XOFs naturally support deriving multiple independent keys by squeezing repeatedly:
Generating deterministic test vectors
Expand a short seed into reproducible test data:
Hashing with context/domain separation
Use domain separators to create independent hash functions from the same primitive:
Hash-to-curve or hash-to-field
XOFs simplify protocols that need to hash into mathematical structures by providing arbitrary-length output without awkward padding or multiple hash calls:
Replacing HKDF-Expand
When you have a uniformly random key and need to derive multiple outputs, a XOF is simpler than HKDF:
SHAKE
SHAKE128 and SHAKE256 are XOFs defined in FIPS 202, based on the Keccak permutation with 24 rounds.
Single-part API
The crypto_xof_shake256() function hashes inlen bytes from in and writes outlen bytes into out.
The output length can be any value. Common choices are 32 or 64 bytes, but the output can be much longer when the XOF is used for key derivation or as a deterministic random generator.
Multi-part API
The multi-part API allows hashing data provided in chunks, and squeezing output incrementally.
After calling crypto_xof_shake256_init(), crypto_xof_shake256_update() can be called repeatedly to absorb data. Once all data has been absorbed, crypto_xof_shake256_squeeze() can be called repeatedly to produce output.
After squeezing begins, no more data can be absorbed into the state.
SHAKE128 has equivalent functions with shake128 instead of shake256 in the names.
Custom domain separation
The crypto_xof_shake256_init_with_domain() function initializes the state with a custom domain separator instead of the standard one. This produces outputs unrelated to the standard variant, allowing different applications to use the same underlying XOF without risk of collisions.
The domain separator must be between 0x01 and 0x7F.
Constants
crypto_xof_shake256_BLOCKBYTES(136)crypto_xof_shake256_STATEBYTES(256)crypto_xof_shake128_BLOCKBYTES(168)crypto_xof_shake128_STATEBYTES(256)
Data types
crypto_xof_shake256_statecrypto_xof_shake128_state
TurboSHAKE
TurboSHAKE128 and TurboSHAKE256 are faster variants of SHAKE that use 12 rounds of the Keccak permutation instead of 24. They are roughly twice as fast as SHAKE while maintaining the same security claims.
TurboSHAKE is the underlying function of KangarooTwelve. Both are standardized in RFC 9861.
Single-part API
Multi-part API
TurboSHAKE128 has equivalent functions with turboshake128 instead of turboshake256 in the names.
Custom domain separation
Domain-separated hashing is useful for deriving independent functions from the same primitive:
The domain separator must be between 0x01 and 0x7F.
Constants
crypto_xof_turboshake256_BLOCKBYTES(136)crypto_xof_turboshake256_STATEBYTES(256)crypto_xof_turboshake128_BLOCKBYTES(168)crypto_xof_turboshake128_STATEBYTES(256)
Data types
crypto_xof_turboshake256_statecrypto_xof_turboshake128_state
Which variant to use
TurboSHAKE128 is the recommended choice for most applications. It offers:
Great performance (~2x faster than SHAKE)
128-bit security, which is more than sufficient for virtually all use cases
Built-in domain separation support
Standardized in RFC 9861
Use a different variant only if you have specific requirements:
SHAKE256 or TurboSHAKE256: When you need 256-bit collision resistance
SHAKE128/SHAKE256: When NIST FIPS 202 compliance is mandated
The “128” and “256” in the names refer to security levels, not output sizes. All variants can produce output of any length.
Security considerations:
When using a XOF as a hash function (collision resistance matters), the output should be at least twice the security level. TurboSHAKE128 with a 32-byte output provides full 128-bit collision resistance. Shorter outputs reduce collision resistance proportionally: a 16-byte output only provides 64-bit collision resistance.
When using a XOF for key derivation or as a PRF (preimage resistance matters), the output length doesn’t affect security as long as you’re using it correctly. TurboSHAKE128 provides 128-bit preimage resistance regardless of output length.
Algorithm details
All four XOFs are based on the Keccak-p (SHA-3) permutation:
SHAKE128
128-bit
168 bytes
24
SHAKE256
256-bit
136 bytes
24
TurboSHAKE128
128-bit
168 bytes
12
TurboSHAKE256
256-bit
136 bytes
12
The security level indicates resistance to generic attacks:
128-bit security: collision resistance up to 2^64 work, preimage resistance up to 2^128 work
256-bit security: collision resistance up to 2^128 work, preimage resistance up to 2^256 work
Notes
XOFs differ from hash functions in an important way: for the same input, requesting different output lengths produces related outputs. Specifically, shorter outputs are prefixes of longer outputs. If this property is undesirable for your application, include the intended output length in the input.
The state should not be used after the object has been squeezed unless it is reinitialized using the init function.
These functions are deterministic: the same input always produces the same output. They are not suitable for password hashing. For that purpose, use the password hashing API.
These functions were introduced in libsodium 1.0.21.
Last updated