yescrypt is a password-based key derivation function (KDF) and password hashing scheme. It builds upon Colin Percival's scrypt. This implementation is able to compute native yescrypt hashes as well as classic scrypt.
Right now, this is primarily a copy of the content from the PHC wiki, but it should probably be moved to a sub-page and this page reused for links to resources related to yescrypt.
The revised BlockMix, which uses mostly yescrypt's pwxform (parallel wide transformation) instead of scrypt's Salsa20/8, is enabled along with the YESCRYPT_RW flag.
This pseudocode illustrates yescrypt running with p=1 (no thread-level parallelism), g=0 (no hash upgrades performed yet), flags=YESCRYPT_RW (full native mode), and no ROM.
# ** Functions/symbols ** # || Concatenate two strings # HMAC(h, k, v) HMAC with hash function h and key k over value v # PBKDF2(prf, p, s, c, dklen) PBKDF2 key derivation function # substr(s, start, length) Substring from start (zero-based) of length bytes # le32dec(), le32enc() 32-bit little-endian decoding/encoding # SIMD_[un]shuffle() Salsa20 SIMD (un)shuffling of 32-bit words # Integerify(B, r) Parse B_{2r-1} as a little-endian integer # p2floor(x) Largest power of 2 not greater than x # ** Inputs ** string password string salt integer t_cost integer m_cost integer outlen # ** Algorithm ** N = 8 << m_cost r = 8 # ** Settings hard-coded/assumed below in this pseudocode ** # p = 1 # g = 0 # flags = YESCRYPT_RW # no ROM # If m_cost is 16 MB per thread or more, pre-hash using 1/64th of m_cost first, # to mitigate garbage collector attacks. yescrypt_prehash() is almost the same # as this function, but its personalization HMAC key is "yescrypt-prehash" # rather than "yescrypt", it skips builtin SCRAM finalization, and it will not # invoke another yescrypt_prehash(). if (N / p >= 0x100 && N / p * r >= 0x20000) password = yescrypt_prehash(password, salt, t_cost, m_cost / 64, 32) password = HMAC(SHA-256, "yescrypt", password) B = PBKDF2(HMAC-SHA-256, password, salt, 1, 128 * r) password = substr(B, 0, 32) # SMix1 invoked to initialize pwxform S-boxes X = SIMD_shuffle(le32dec(B)) for i = 0 to Sbytes/128 - 1 S[i] = X X = BlockMix_{Salsa20/8, 1}(X) # SMix1 invoked "for real" for i = 0 to N - 1 V[i] = X if (i > 1) j = Wrap(Integerify(X, r), i) X = X xor V[j] X = BlockMix_pwxform{Salsa20/2, S, r}(X) # SMix2 if (t_cost = 0) Nloop = (N + 2) / 3 else if (t_cost = 1) Nloop = (N * 2 + 2) / 3 else Nloop = N * (t - 1) for i = 0 to Nloop - 1 j = Integerify(X, r) mod N X = X xor V[j] V[j] = X X = BlockMix_pwxform{Salsa20/2, S, r}(X) B = le32enc(SIMD_unshuffle(X)) out = PBKDF2(HMAC-SHA-256, password, B, 1, outlen) # Builtin SCRAM (RFC 5802) support clen = min(outlen, 32) dk = PBKDF2(HMAC-SHA-256, password, B, 1, 32) dk = SHA-256(HMAC(SHA-256, dk, "Client Key")) out = substr(dk, 0, clen) || substr(out, clen, outlen - clen) return out # ** Helper functions ** # Wrap x to the range 0 to i-1 Wrap(x, i) n = p2floor(i) return (x mod n) + (i - n)
The BlockMix_{Salsa20/8, r}(X) function is exactly the same as in scrypt (and is invoked with hard-coded r=1 here, regardless of yescrypt's r). The BlockMix_pwxform{Salsa20/2, S, r}(X) function is yescrypt's own, and it uses yescrypt's own pwxform in place of most uses of Salsa20/2. Please refer to the yescrypt specification document and the deliberately mostly not optimized reference implementation (yescrypt-ref.c) for how these functions, as well as the SIMD (un)shuffling, are specified.