This is an old revision of the document!
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.
yescrypt - password hashing scalable beyond bcrypt and scrypt presentation slides (May 2014), discussed on reddit.