/* CryptoNight Step 4: Sequentially pass through the mixing buffer
         * and use 10 rounds of AES encryption to mix the random data back
         * into the 'text' buffer.
         */
        private static void EncryptScratchpadToText(CNState cnState,
                                                    ICryptoNight cnParams,
                                                    byte[] scratchpad)
        {
            /* Reinitialize text from state */
            byte[] text = cnState.GetText();

            /* Expand our initial key into many for each round of pseudo aes */
            byte[] expandedKeys = AES.ExpandKey(cnState.GetAESKey2(), false);

            for (int i = 0; i < cnParams.InitRounds; i++)
            {
                for (int j = 0; j < Constants.INIT_SIZE_BLOCK; j++)
                {
                    int offsetA = j * AES.BLOCK_SIZE;
                    int offsetB = (i * Constants.INIT_SIZE_BYTE) + offsetA;

                    XORBlocks(text, scratchpad, offsetA, offsetB);

                    /* Need to pass the array with an offset because we manip
                     * it in place */
                    AES.AESBPseudoRound(expandedKeys, text, offsetA);
                }
            }

            cnState.SetText(text);
        }
Example #2
0
        public static byte[] VariantOneInit(CNState state, byte[] input)
        {
            byte[] tweak = state.GetTweak();

            XOR64(tweak, input, 0, 35);

            return(tweak);
        }
Example #3
0
        public static byte[] CryptoNightV2(byte[] input, ICryptoNight cnParams)
        {
            /* CryptoNight Step 1: Use Keccak1600 to initialize the 'state'
             * buffer, encapsulated in cnState
             */
            CNState cnState = new CNState(Keccak.Keccak1600(input));

            byte[] scratchpad = CryptoNight.FillScratchpad(cnState, cnParams);

            MixScratchpadV2(cnState, cnParams, scratchpad);

            EncryptScratchpadToText(cnState, cnParams, scratchpad);

            return(CryptoNight.HashFinalState(cnState));
        }
Example #4
0
        /* CryptoNight Step 4: Sequentially pass through the mixing buffer
         * and use 10 rounds of AES encryption to mix the random data back
         * into the 'text' buffer.
         */
        private static void EncryptScratchpadToText(CNState cnState,
                                                    ICryptoNight cnParams,
                                                    byte[] scratchpad)
        {
            /* Reinitialize text from state */
            byte[] text = cnState.GetText();

            /* Expand our initial key into many for each round of pseudo aes */
            byte[] expandedKeys = AES.ExpandKey(cnState.GetAESKey2(), true);

            for (int i = 0; i < cnParams.InitRounds; i++)
            {
                AES.AESPseudoRoundXOR(
                    expandedKeys,
                    text,
                    scratchpad,
                    i * Constants.INIT_SIZE_BYTE
                    );
            }

            cnState.SetText(text);
        }
Example #5
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));
            }
            }
        }
Example #6
0
        /* CryptoNight Step 2:  Iteratively encrypt the results from Keccak
         * to fill the large scratchpad
         */
        public static byte[] FillScratchpad(CNState cnState, ICryptoNight cnParams)
        {
            /* Expand our initial key into many for each round of pseudo aes */
            byte[] expandedKeys = AES.ExpandKey(cnState.GetAESKey(), cnParams.Intrinsics);

            /* Our large scratchpad, 2MB in default CN */
            byte[] scratchpad = new byte[cnParams.Memory];

            byte[] text = cnState.GetText();

            if (cnParams.Intrinsics && Aes.IsSupported && Sse2.IsSupported)
            {
                /* Fill the scratchpad with AES encryption of text */
                for (int i = 0; i < cnParams.InitRounds; i++)
                {
                    AES.AESPseudoRoundNative(expandedKeys, text);

                    /* Write text to the scratchpad, at the offset
                     * i * InitSizeByte */
                    Buffer.BlockCopy(text, 0, scratchpad, i * Constants.INIT_SIZE_BYTE, text.Length);
                }
            }
            else
            {
                /* Fill the scratchpad with AES encryption of text */
                for (int i = 0; i < cnParams.InitRounds; i++)
                {
                    AES.AESPseudoRound(expandedKeys, text, cnParams.Intrinsics);

                    /* Write text to the scratchpad, at the offset
                     * i * InitSizeByte */
                    Buffer.BlockCopy(text, 0, scratchpad, i * Constants.INIT_SIZE_BYTE, text.Length);
                }
            }

            return(scratchpad);
        }
Example #7
0
        public static byte[] CryptoNightV1(byte[] input, ICryptoNight cnParams)
        {
            if (input.Length < 43)
            {
                throw new ArgumentException(
                          "Input to CryptoNightV1 must be at least 43 bytes!"
                          );
            }

            /* CryptoNight Step 1: Use Keccak1600 to initialize the 'state'
             * buffer, encapsulated in cnState
             */
            CNState cnState = new CNState(Keccak.Keccak1600(input));

            byte[] scratchpad = CryptoNight.FillScratchpad(cnState, cnParams);

            byte[] tweak = CryptoNight.VariantOneInit(cnState, input);

            MixScratchpadV1(cnState, cnParams, scratchpad, tweak);

            EncryptScratchpadToText(cnState, cnParams, scratchpad);

            return(CryptoNight.HashFinalState(cnState));
        }
Example #8
0
        /* 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);
                }
            }
        }