public unsafe void TestAESBSingleRound() { byte[] expandedKeys1 = HexStringToByteArray( "4d54c79ab1e27ae04bfe734df26877d7bab89ecbffe598f87d23bbf5ceddc04d97e893355e4d537c4066085159a5515fcfdc9a3a3fe840b61175a446ea75dfb5d7bc2a7a66a268e5e96607e813b8666b443acaff24742a3bed7feaafd78854e170c10468125e99855850588dada7a7f7baf193b754136d748fca760b20628180ece674cfbd44d22168f105d320909d933336f4ffd5afc27eaf8f02b3b289b4e5c8584b928e0ce9b62871f9feae271d4183237e03b88a53c92c549c62366c141599a9995681d612d1206a26eb1559d61f29998383cffce1178c9d1a2c1ba4e8be22b081a7802960dfa6811fe45cf77741" ); byte[] input1 = HexStringToByteArray( "f77f10a5fb1a52a2b466751c3a858dc3" ); /* Test the unsafe version */ fixed(byte *input = input1, expandedKeys = expandedKeys1) { AES.AESBSingleRound((uint *)input, (uint *)expandedKeys); Assert.AreEqual <string>("d3f15e41a16af6931839a8e818cb9abd", ByteArrayToHexString(input1)); } byte[] expandedKeys2 = HexStringToByteArray( "af7a7e743ead40cfbc04e390d359ed70f9bd891c25d72aa78f27dba3d0b2922689550342cc1c5616e234a7478551c31c12716645e5b2d4e6dadd251413f3348a221a71868bfb3f18f79cf62b154374c7d8b1ef504288b360652b8fe8a4ee8017397c38b73121778bafc7e24368dedf0c0048789395d40d1d04595bccac8d48b188e0192f7dcb2eb9a0132d2d7eb748a882b53685414cea08de50d83fdf52eba61c5cbe4b9d03e4b0aa674850b485dec2ca8bb8787f90fa9f254292a11d65825ff30d417a56d898721d507d6b1e6b66aa009cc3082ed1c451215b9e9992abba51d4f6a3655a69e43b4e65b99a415c0a75" ); byte[] input2 = HexStringToByteArray( "f6ab72cec832b4070711b7e3b8700d6a" ); fixed(byte *input = input2, expandedKeys = expandedKeys2) { AES.AESBSingleRound((uint *)input, (uint *)expandedKeys); Assert.AreEqual <string>("e59c503c34b319b45b66a344316cd109", ByteArrayToHexString(input2)); } byte[] expandedKeys3 = HexStringToByteArray( "6a8fd2a6c65c036133649dab4eb09b54148512fc83f1ea9f61aaa0e260848e6320adb182e16bcae13422161f5ca9e600132aaca1be8873dbe5e641eb18412072d41bcbe74c174b4d557acf6e2aeff71f5ec94249f0e781bfd4f9b0d54172d188a17db5c4e69fa309f53a474ebb9640790296d1006f0bfaa223176e74cf4d51116e476b58e8f801e2ddc458e38abeb46ce49f19a9cb1740be0e021b691d59a221d8cd4ff700a1e301f3c8f3edd94956ff1dbacfc925b57a32ea90575548d2a0d6d8dfb8fcfa2130751f7882b984a0d1fa0e6383d1522f9dba6e84365d3236e9564f088cb6fe7b16236fbe65ef61b61eeb" ); byte[] input3 = HexStringToByteArray( "ac2432e2f84f5f244ef7e5d977c9f19e" ); fixed(byte *input = input3, expandedKeys = expandedKeys3) { AES.AESBSingleRound((uint *)input, (uint *)expandedKeys); Assert.AreEqual <string>("16767345c5adc04004b973481f5682c3", ByteArrayToHexString(input3)); } }
/* 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); } } }