public unsafe MixScratchpadState(CNState cnState) { k = cnState.GetK(); fixed(byte *aPtr = a, bPtr = b, kPtr = k) { ulong *_a = (ulong *)aPtr; ulong *_b = (ulong *)bPtr; ulong *_k = (ulong *)kPtr; _a[0] = (_k + 0)[0] ^ (_k + 4)[0]; _a[1] = (_k + 0)[1] ^ (_k + 4)[1]; _b[0] = (_k + 2)[0] ^ (_k + 6)[0]; _b[1] = (_k + 2)[1] ^ (_k + 6)[1]; } }
/* 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 MixScratchpadV0( CNState cnState, ICryptoNight cnParams, byte[] scratchpad) { 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()) { ulong lo; ulong hi; ulong *loPtr = &lo; ulong *p; ulong *a = (ulong *)aByte; ulong *b = (ulong *)bByte; ulong *c = (ulong *)cByte; 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)); /* 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]; /* 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 MixScratchpadV0( CNState cnState, ICryptoNight cnParams, byte[] scratchpad) { 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()) { 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); /* 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); /* Copy a block from c to p */ CopyBlock(p, c); /* Copy a block from c1 to b */ CopyBlock(b, c1); } } }
private static unsafe void MixScratchpadV2( CNState cnState, ICryptoNight cnParams, byte[] scratchpad) { 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(), hashState = cnState.GetState()) { ulong divisionResult; ulong sqrtResult; CryptoNight.InitMixingState((ulong *)a, (ulong *)b, (ulong *)k); /* Init */ { ulong *_b = (ulong *)b; ulong *w = (ulong *)hashState; _b[2] = w[8] ^ w[10]; _b[3] = w[9] ^ w[11]; divisionResult = w[12]; sqrtResult = w[13]; } 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); VariantTwoShuffleAdd(scratchpadPtr, j, (ulong *)b, (ulong *)a); XORBlocks(p, (ulong *)b); /* 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); VariantTwoIntegerMath( (ulong *)c, (ulong *)c1, ref divisionResult, ref sqrtResult ); Multiply64((ulong *)c1, (ulong *)c, (ulong *)d); /* Variant 2 */ XORBlocks((ulong *)(scratchpadPtr + (j ^ 0x10)), (ulong *)d); XORBlocks((ulong *)d, (ulong *)(scratchpadPtr + (j ^ 0x20))); VariantTwoShuffleAdd(scratchpadPtr, j, (ulong *)b, (ulong *)a); /* 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); /* Copy a block from c to p */ CopyBlock(p, c); /* Copy first half of b to second half */ CopyBlock(b + AES.BLOCK_SIZE, b); /* Copy a block from c1 to b */ CopyBlock(b, c1); } } }