示例#1
0
        /* CryptoNight Step 5: Apply Keccak to the state again, and then
         * use the resulting data to select which of four finalizer
         * hash functions to apply to the data (Blake, Groestl, JH,
         * or Skein). Use this hash to squeeze the state array down
         * to the final 32 byte hash output.
         */
        public static byte[] HashFinalState(CNState cnState)
        {
            /* Get the state buffer as an array of ulongs rather than bytes */
            ulong[] hashState = cnState.GetHashState();

            Keccak.Keccakf(hashState, 24);

            /* Set the state buffer from the coerced hash state */
            cnState.SetHashState(hashState);

            /* Get the actual state buffer finally */
            byte[] state = cnState.GetState();

            /* Choose the final hashing function to use based on the value of
             * state[0] */
            switch (state[0] % 4)
            {
            case 0:
            {
                return(new Blake().Hash(state));
            }

            case 1:
            {
                return(new Groestl().Hash(state));
            }

            case 2:
            {
                return(new JH().Hash(state));
            }

            default:
            {
                return(new Skein().Hash(state));
            }
            }
        }
        /* 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 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];

            fixed(byte *scratchpadPtr = scratchpad,
                  aByte     = aArray,
                  bByte     = bArray,
                  cByte     = cArray,
                  k         = cnState.GetK(),
                  hashState = cnState.GetState())
            {
                ulong lo;
                ulong hi;

                ulong *loPtr = &lo;
                ulong *p;

                ulong *a = (ulong *)aByte;
                ulong *b = (ulong *)bByte;
                ulong *c = (ulong *)cByte;

                CryptoNight.InitMixingState((ulong *)a, (ulong *)b, (ulong *)k);

                int j;

                ulong *w = (ulong *)hashState;

                b[2] = w[8] ^ w[10];
                b[3] = w[9] ^ w[11];

                ulong divisionResult = w[12];
                ulong sqrtResult     = w[13];

                Vector128 <byte> _a;
                Vector128 <byte> _b  = Sse2.LoadVector128(bByte);
                Vector128 <byte> _b1 = Sse2.LoadVector128(bByte + 16);
                Vector128 <byte> _c;

                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);

                    VariantTwoShuffleAdd(
                        scratchpadPtr,
                        j,
                        _b1,
                        _b,
                        _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];

                    VariantTwoIntegerMath(b, c, ref divisionResult, ref sqrtResult);

                    /* 64 bit multiply the low parts of C and B */
                    hi = Bmi2.X64.MultiplyNoFlags(c[0], b[0], loPtr);

                    *(ulong *)(scratchpadPtr + (j ^ 0x10))       ^= hi;
                    *((ulong *)(scratchpadPtr + (j ^ 0x10)) + 1) ^= lo;
                    hi ^= *(ulong *)(scratchpadPtr + (j ^ 0x20));
                    lo ^= *((ulong *)(scratchpadPtr + (j ^ 0x20)) + 1);

                    VariantTwoShuffleAdd(
                        scratchpadPtr,
                        j,
                        _b1,
                        _b,
                        _a
                        );

                    /* 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];

                    _b1 = _b;
                    /* Store C in B */
                    _b = _c;
                }
            }
        }
示例#3
0
        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);
                }
            }
        }