/* CryptoNight Step 3: Bounce randomly 1,048,576 times (1<<20) * through the mixing scratchpad, using 524,288 iterations of the * following mixing function. Each execution performs two reads * and writes from the mixing scratchpad. */ private unsafe static void MixScratchpadV1( CNState cnState, ICryptoNight cnParams, byte[] scratchpad, byte[] tweak) { byte[] aArray = new byte[AES.BLOCK_SIZE]; byte[] bArray = new byte[AES.BLOCK_SIZE * 2]; byte[] cArray = new byte[AES.BLOCK_SIZE]; fixed(byte *scratchpadPtr = scratchpad, aByte = aArray, bByte = bArray, cByte = cArray, k = cnState.GetK(), tweakByte = tweak) { ulong lo; ulong hi; ulong *loPtr = &lo; ulong *p; ulong *a = (ulong *)aByte; ulong *b = (ulong *)bByte; ulong *c = (ulong *)cByte; ulong *tweak1_2 = (ulong *)tweakByte; CryptoNight.InitMixingState(a, b, (ulong *)k); Vector128 <byte> _a; Vector128 <byte> _b = Sse2.LoadVector128(bByte); Vector128 <byte> _c; int j; for (int i = 0; i < cnParams.AesRounds; i++) { /* Get our 'memory' address we're using for this round */ j = CryptoNight.StateIndex(*a, cnParams.ScratchModulus); /* Load C from the memory address in the scratchpad */ _c = Sse2.LoadVector128(scratchpadPtr + j); /* Reload A from the buffer */ _a = Sse2.LoadVector128(aByte); /* Use AES to mix scratchpad into c */ _c = Aes.Encrypt(_c, _a); /* Store C back in it's original spot */ Sse2.Store(cByte, _c); /* XOR b and C, and store back at the 'memory' address * in the scratchpad */ Sse2.Store(scratchpadPtr + j, Sse2.Xor(_b, _c)); CryptoNight.VariantOneStepOne(scratchpadPtr + j); /* Get the new 'memory' address we're using for this round */ j = CryptoNight.StateIndex(*c, cnParams.ScratchModulus); /* Grab a pointer to the spot of memory we're interested */ p = (ulong *)(scratchpadPtr + j); /* Load b from the memory address in the scratchpad */ b[0] = p[0]; b[1] = p[1]; /* 64 bit multiply the low parts of C and B */ hi = Bmi2.X64.MultiplyNoFlags(c[0], b[0], loPtr); /* Sum the result halves of the multiplication with each half of A */ a[0] += hi; a[1] += lo; /* Write the modified A back to the scratchpad */ p[0] = a[0]; p[1] = a[1]; /* Xor the two 64 bit halves of A and B */ a[0] ^= b[0]; a[1] ^= b[1]; CryptoNight.VariantOneStepTwo(p + 1, tweak1_2); /* Store C in B */ _b = _c; } } }
/* CryptoNight Step 3: Bounce randomly 1,048,576 times (1<<20) * through the mixing scratchpad, using 524,288 iterations of the * following mixing function. Each execution performs two reads * and writes from the mixing scratchpad. */ private static unsafe void MixScratchpadV1( CNState cnState, ICryptoNight cnParams, byte[] scratchpad, byte[] tweak) { byte[] aArray = new byte[AES.BLOCK_SIZE]; byte[] bArray = new byte[AES.BLOCK_SIZE * 2]; byte[] cArray = new byte[AES.BLOCK_SIZE]; byte[] c1Array = new byte[AES.BLOCK_SIZE]; byte[] dArray = new byte[AES.BLOCK_SIZE]; fixed(byte *scratchpadPtr = scratchpad, a = aArray, b = bArray, c = cArray, c1 = c1Array, d = dArray, k = cnState.GetK(), tweakByte = tweak) { CryptoNight.InitMixingState((ulong *)a, (ulong *)b, (ulong *)k); for (int i = 0; i < cnParams.AesRounds; i++) { /* ITERATION ONE */ /* Get the memory address */ int j = CryptoNight.StateIndex(*(ulong *)a, cnParams.ScratchModulus); /* Get a pointer to the memory address in the scratchpad */ ulong *p = (ulong *)(scratchpadPtr + j); /* Perform AES round from/to scratchpad, with A as the * expanded key */ AES.AESBSingleRound((uint *)p, (uint *)a); /* Copy a block from p to c1 */ CopyBlock(c1, p); XORBlocks(p, (ulong *)b); CryptoNight.VariantOneStepOne((byte *)p); /* ITERATION TWO */ /* Get new memory address */ j = CryptoNight.StateIndex(*(ulong *)c1, cnParams.ScratchModulus); /* Update pointer to scratchpad */ p = (ulong *)(scratchpadPtr + j); /* Copy a block from p to c */ CopyBlock(c, p); Multiply64((ulong *)c1, (ulong *)c, (ulong *)d); /* Sum half blocks */ ((ulong *)a)[0] += ((ulong *)d)[0]; ((ulong *)a)[1] += ((ulong *)d)[1]; SwapBlocks((ulong *)a, (ulong *)c); XORBlocks((ulong *)a, (ulong *)c); CryptoNight.VariantOneStepTwo((ulong *)(c + 8), (ulong *)tweakByte); /* Copy a block from c to p */ CopyBlock(p, c); /* Copy a block from c1 to b */ CopyBlock(b, c1); } } }