/* Random oracles mix. * Based on RFC 7914: scrypt PBKDF. * * x Data to mix. * v Temporary buffer. * y Temporary buffer for the block mix. * r Block size parameter. * n CPU/Memory cost parameter. */ static void scryptROMix(byte* x, byte* v, byte* y, int r, word32 n) { word32 i; word32 j; word32 k; word32 bSz = 128 * r; #ifdef WORD64_AVAILABLE word64* x64 = (word64*)x; word64* v64 = (word64*)v; #else word32* x32 = (word32*)x; word32* v32 = (word32*)v; #endif /* Step 1. X = B (B not needed therefore not implemented) */ /* Step 2. */ for (i = 0; i < n; i++) { XMEMCPY(v + i * bSz, x, bSz); scryptBlockMix(x, y, r); } /* Step 3. */ for (i = 0; i < n; i++) { #ifdef LITTLE_ENDIAN_ORDER #ifdef WORD64_AVAILABLE j = *(word64*)(x + (2*r - 1) * 64) & (n-1); #else j = *(word32*)(x + (2*r - 1) * 64) & (n-1); #endif #else byte* t = x + (2*r - 1) * 64; j = (t[0] | (t[1] << 8) | (t[2] << 16) | (t[3] << 24)) & (n-1); #endif #ifdef WORD64_AVAILABLE for (k = 0; k < bSz / 8; k++) x64[k] ^= v64[j * bSz / 8 + k]; #else for (k = 0; k < bSz / 4; k++) x32[k] ^= v32[j * bSz / 4 + k]; #endif scryptBlockMix(x, y, r); } /* Step 4. B' = X (B = X = B' so not needed, therefore not implemented) */ }
// scryptROMix implements the function described in RFC 7914, section 5. |B| is // an scrypt block (2 * |r| Salsa20 blocks) and is modified in-place. |T| and // |V| are scratch space allocated by the caller. |T| must have space for one // scrypt block (2 * |r| Salsa20 blocks). |V| must have space for |N| scrypt // blocks (2 * |r| * |N| Salsa20 blocks). static void scryptROMix(block_t *B, uint64_t r, uint64_t N, block_t *T, block_t *V) { // Steps 1 and 2. OPENSSL_memcpy(V, B, 2 * r * sizeof(block_t)); for (uint64_t i = 1; i < N; i++) { scryptBlockMix(&V[2 * r * i /* scrypt block i */], &V[2 * r * (i - 1) /* scrypt block i-1 */], r); } scryptBlockMix(B, &V[2 * r * (N - 1) /* scrypt block N-1 */], r); // Step 3. for (uint64_t i = 0; i < N; i++) { // Note this assumes |N| <= 2^32 and is a power of 2. uint32_t j = B[2 * r - 1].words[0] & (N - 1); for (size_t k = 0; k < 2 * r; k++) { xor_block(&T[k], &B[k], &V[2 * r * j + k]); } scryptBlockMix(B, T, r); } }
static void scryptROMix(unsigned char *B, uint64_t r, uint64_t N, uint32_t *X, uint32_t *T, uint32_t *V) { unsigned char *pB; uint32_t *pV; uint64_t i, k; /* Convert from little endian input */ for (pV = V, i = 0, pB = B; i < 32 * r; i++, pV++) { *pV = *pB++; *pV |= *pB++ << 8; *pV |= *pB++ << 16; *pV |= (uint32_t)*pB++ << 24; } for (i = 1; i < N; i++, pV += 32 * r) scryptBlockMix(pV, pV - 32 * r, r); scryptBlockMix(X, V + (N - 1) * 32 * r, r); for (i = 0; i < N; i++) { uint32_t j; j = X[16 * (2 * r - 1)] % N; pV = V + 32 * r * j; for (k = 0; k < 32 * r; k++) T[k] = X[k] ^ *pV++; scryptBlockMix(X, T, r); } /* Convert output to little endian */ for (i = 0, pB = B; i < 32 * r; i++) { uint32_t xtmp = X[i]; *pB++ = xtmp & 0xff; *pB++ = (xtmp >> 8) & 0xff; *pB++ = (xtmp >> 16) & 0xff; *pB++ = (xtmp >> 24) & 0xff; } }