From 6b8c2f56b6b79f4f8ef1273c1f36ce384c03499f Mon Sep 17 00:00:00 2001 From: inga-lovinde <52715130+inga-lovinde@users.noreply.github.com> Date: Sat, 1 Apr 2017 18:02:50 +0300 Subject: [PATCH] Code cleanup --- README.md | 4 + dotnet/WhiteRabbit/MD5Digest.cs | 160 ++++++++++++++++++-------------- 2 files changed, 93 insertions(+), 71 deletions(-) diff --git a/README.md b/README.md index cf619ad..3c86fcb 100644 --- a/README.md +++ b/README.md @@ -110,3 +110,7 @@ There is no need in processing all the words that are too large to be useful at 11. Filtering the original dictionary (e.g. throwing away all single-letter words) does not really improve the performance, thanks to the optimizations mentioned in notes 7-9. This solution finds all anagrams, including those with single-letter words. + +12. MD5 computation could be further optimized by: + * Using CPU instructions for rotation (implemented in not yet released version of RyuJIT): https://github.com/dotnet/coreclr/pull/1830 + * Computing several MD5 hashes in parallel on each core, using SSE (4 hashes / core) or AVX2 (8 hashes / core). However, even bit shifts on vectors are not yet supported by .NET: https://github.com/dotnet/coreclr/issues/3226 diff --git a/dotnet/WhiteRabbit/MD5Digest.cs b/dotnet/WhiteRabbit/MD5Digest.cs index 9f78782..6100ad6 100644 --- a/dotnet/WhiteRabbit/MD5Digest.cs +++ b/dotnet/WhiteRabbit/MD5Digest.cs @@ -1,9 +1,7 @@ -namespace WhiteRabbit -{ - using System; - using System.Linq; - using System.Reflection; +using System.Runtime.CompilerServices; +namespace WhiteRabbit +{ /** * Code taken from BouncyCastle and optimized for specific constraints (e.g. input is always larger than 4 bytes and smaller than 52 bytes). * Further optimization: input could be assumed to be smaller than 27 bytes (original phrase contains 18 letters, so that allows anagrams of 9 words) @@ -13,6 +11,7 @@ */ internal static class MD5Digest { + [MethodImpl(MethodImplOptions.AggressiveInlining)] public static unsafe uint[] Compute(Phrase input) { uint a = 0x67452301; @@ -20,73 +19,73 @@ uint c = 0x98badcfe; uint d = 0x10325476; - a = LeftRotate(input.Buffer[0] + 0xd76aa478 + a + ((b & c) | (~b & d)), 7, 32 - 7) + b; - d = LeftRotate(input.Buffer[1] + 0xe8c7b756 + d + ((a & b) | (~a & c)), 12, 32 - 12) + a; - c = LeftRotate(input.Buffer[2] + 0x242070db + c + ((d & a) | (~d & b)), 17, 32 - 17) + d; - b = LeftRotate(input.Buffer[3] + 0xc1bdceee + b + ((c & d) | (~c & a)), 22, 32 - 22) + c; - a = LeftRotate(input.Buffer[4] + 0xf57c0faf + a + ((b & c) | (~b & d)), 7, 32 - 7) + b; - d = LeftRotate(input.Buffer[5] + 0x4787c62a + d + ((a & b) | (~a & c)), 12, 32 - 12) + a; - c = LeftRotate(input.Buffer[6] + 0xa8304613 + c + ((d & a) | (~d & b)), 17, 32 - 17) + d; - b = LeftRotate(0xfd469501 + b + ((c & d) | (~c & a)), 22, 32 - 22) + c; - a = LeftRotate(0x698098d8 + a + ((b & c) | (~b & d)), 7, 32 - 7) + b; - d = LeftRotate(0x8b44f7af + d + ((a & b) | (~a & c)), 12, 32 - 12) + a; - c = LeftRotate(0xffff5bb1 + c + ((d & a) | (~d & b)), 17, 32 - 17) + d; - b = LeftRotate(0x895cd7be + b + ((c & d) | (~c & a)), 22, 32 - 22) + c; - a = LeftRotate(0x6b901122 + a + ((b & c) | (~b & d)), 7, 32 - 7) + b; - d = LeftRotate(0xfd987193 + d + ((a & b) | (~a & c)), 12, 32 - 12) + a; - c = LeftRotate(input.Buffer[7] + 0xa679438e + c + ((d & a) | (~d & b)), 17, 32 - 17) + d; - b = LeftRotate(0x49b40821 + b + ((c & d) | (~c & a)), 22, 32 - 22) + c; + a = b + LeftRotate(0xd76aa478 + a + Blend(d, c, b) + input.Buffer[0], 7); + d = a + LeftRotate(0xe8c7b756 + d + Blend(c, b, a) + input.Buffer[1], 12); + c = d + LeftRotate(0x242070db + c + Blend(b, a, d) + input.Buffer[2], 17); + b = c + LeftRotate(0xc1bdceee + b + Blend(a, d, c) + input.Buffer[3], 22); + a = b + LeftRotate(0xf57c0faf + a + Blend(d, c, b) + input.Buffer[4], 7); + d = a + LeftRotate(0x4787c62a + d + Blend(c, b, a) + input.Buffer[5], 12); + c = d + LeftRotate(0xa8304613 + c + Blend(b, a, d) + input.Buffer[6], 17); + b = c + LeftRotate(0xfd469501 + b + Blend(a, d, c), 22); + a = b + LeftRotate(0x698098d8 + a + Blend(d, c, b), 7); + d = a + LeftRotate(0x8b44f7af + d + Blend(c, b, a), 12); + c = d + LeftRotate(0xffff5bb1 + c + Blend(b, a, d), 17); + b = c + LeftRotate(0x895cd7be + b + Blend(a, d, c), 22); + a = b + LeftRotate(0x6b901122 + a + Blend(d, c, b), 7); + d = a + LeftRotate(0xfd987193 + d + Blend(c, b, a), 12); + c = d + LeftRotate(0xa679438e + c + Blend(b, a, d) + input.Buffer[7], 17); + b = c + LeftRotate(0x49b40821 + b + Blend(a, d, c), 22); - a = LeftRotate(input.Buffer[1] + 0xf61e2562 + a + ((b & d) | (c & ~d)), 5, 32 - 5) + b; - d = LeftRotate(input.Buffer[6] + 0xc040b340 + d + ((a & c) | (b & ~c)), 9, 32 - 9) + a; - c = LeftRotate(0x265e5a51 + c + ((d & b) | (a & ~b)), 14, 32 - 14) + d; - b = LeftRotate(input.Buffer[0] + 0xe9b6c7aa + b + ((c & a) | (d & ~a)), 20, 32 - 20) + c; - a = LeftRotate(input.Buffer[5] + 0xd62f105d + a + ((b & d) | (c & ~d)), 5, 32 - 5) + b; - d = LeftRotate(0x2441453 + d + ((a & c) | (b & ~c)), 9, 32 - 9) + a; - c = LeftRotate(0xd8a1e681 + c + ((d & b) | (a & ~b)), 14, 32 - 14) + d; - b = LeftRotate(input.Buffer[4] + 0xe7d3fbc8 + b + ((c & a) | (d & ~a)), 20, 32 - 20) + c; - a = LeftRotate(0x21e1cde6 + a + ((b & d) | (c & ~d)), 5, 32 - 5) + b; - d = LeftRotate(input.Buffer[7] + 0xc33707d6 + d + ((a & c) | (b & ~c)), 9, 32 - 9) + a; - c = LeftRotate(input.Buffer[3] + 0xf4d50d87 + c + ((d & b) | (a & ~b)), 14, 32 - 14) + d; - b = LeftRotate(0x455a14ed + b + ((c & a) | (d & ~a)), 20, 32 - 20) + c; - a = LeftRotate(0xa9e3e905 + a + ((b & d) | (c & ~d)), 5, 32 - 5) + b; - d = LeftRotate(input.Buffer[2] + 0xfcefa3f8 + d + ((a & c) | (b & ~c)), 9, 32 - 9) + a; - c = LeftRotate(0x676f02d9 + c + ((d & b) | (a & ~b)), 14, 32 - 14) + d; - b = LeftRotate(0x8d2a4c8a + b + ((c & a) | (d & ~a)), 20, 32 - 20) + c; + a = b + LeftRotate(0xf61e2562 + a + Blend(c, b, d) + input.Buffer[1], 5); + d = a + LeftRotate(0xc040b340 + d + Blend(b, a, c) + input.Buffer[6], 9); + c = d + LeftRotate(0x265e5a51 + c + Blend(a, d, b), 14); + b = c + LeftRotate(0xe9b6c7aa + b + Blend(d, c, a) + input.Buffer[0], 20); + a = b + LeftRotate(0xd62f105d + a + Blend(c, b, d) + input.Buffer[5], 5); + d = a + LeftRotate(0x02441453 + d + Blend(b, a, c), 9); + c = d + LeftRotate(0xd8a1e681 + c + Blend(a, d, b), 14); + b = c + LeftRotate(0xe7d3fbc8 + b + Blend(d, c, a) + input.Buffer[4], 20); + a = b + LeftRotate(0x21e1cde6 + a + Blend(c, b, d), 5); + d = a + LeftRotate(0xc33707d6 + d + Blend(b, a, c) + input.Buffer[7], 9); + c = d + LeftRotate(0xf4d50d87 + c + Blend(a, d, b) + input.Buffer[3], 14); + b = c + LeftRotate(0x455a14ed + b + Blend(d, c, a), 20); + a = b + LeftRotate(0xa9e3e905 + a + Blend(c, b, d), 5); + d = a + LeftRotate(0xfcefa3f8 + d + Blend(b, a, c) + input.Buffer[2], 9); + c = d + LeftRotate(0x676f02d9 + c + Blend(a, d, b), 14); + b = c + LeftRotate(0x8d2a4c8a + b + Blend(d, c, a), 20); - a = LeftRotate(input.Buffer[5] + 0xfffa3942 + a + (b ^ c ^ d), 4, 32 - 4) + b; - d = LeftRotate(0x8771f681 + d + (a ^ b ^ c), 11, 32 - 11) + a; - c = LeftRotate(0x6d9d6122 + c + (d ^ a ^ b), 16, 32 - 16) + d; - b = LeftRotate(input.Buffer[7] + 0xfde5380c + b + (c ^ d ^ a), 23, 32 - 23) + c; - a = LeftRotate(input.Buffer[1] + 0xa4beea44 + a + (b ^ c ^ d), 4, 32 - 4) + b; - d = LeftRotate(input.Buffer[4] + 0x4bdecfa9 + d + (a ^ b ^ c), 11, 32 - 11) + a; - c = LeftRotate(0xf6bb4b60 + c + (d ^ a ^ b), 16, 32 - 16) + d; - b = LeftRotate(0xbebfbc70 + b + (c ^ d ^ a), 23, 32 - 23) + c; - a = LeftRotate(0x289b7ec6 + a + (b ^ c ^ d), 4, 32 - 4) + b; - d = LeftRotate(input.Buffer[0] + 0xeaa127fa + d + (a ^ b ^ c), 11, 32 - 11) + a; - c = LeftRotate(input.Buffer[3] + 0xd4ef3085 + c + (d ^ a ^ b), 16, 32 - 16) + d; - b = LeftRotate(input.Buffer[6] + 0x4881d05 + b + (c ^ d ^ a), 23, 32 - 23) + c; - a = LeftRotate(0xd9d4d039 + a + (b ^ c ^ d), 4, 32 - 4) + b; - d = LeftRotate(0xe6db99e5 + d + (a ^ b ^ c), 11, 32 - 11) + a; - c = LeftRotate(0x1fa27cf8 + c + (d ^ a ^ b), 16, 32 - 16) + d; - b = LeftRotate(input.Buffer[2] + 0xc4ac5665 + b + (c ^ d ^ a), 23, 32 - 23) + c; + a = b + LeftRotate(0xfffa3942 + a + Xor(b, c, d) + input.Buffer[5], 4); + d = a + LeftRotate(0x8771f681 + d + Xor(a, b, c), 11); + c = d + LeftRotate(0x6d9d6122 + c + Xor(d, a, b), 16); + b = c + LeftRotate(0xfde5380c + b + Xor(c, d, a) + input.Buffer[7], 23); + a = b + LeftRotate(0xa4beea44 + a + Xor(b, c, d) + input.Buffer[1], 4); + d = a + LeftRotate(0x4bdecfa9 + d + Xor(a, b, c) + input.Buffer[4], 11); + c = d + LeftRotate(0xf6bb4b60 + c + Xor(d, a, b), 16); + b = c + LeftRotate(0xbebfbc70 + b + Xor(c, d, a), 23); + a = b + LeftRotate(0x289b7ec6 + a + Xor(b, c, d), 4); + d = a + LeftRotate(0xeaa127fa + d + Xor(a, b, c) + input.Buffer[0], 11); + c = d + LeftRotate(0xd4ef3085 + c + Xor(d, a, b) + input.Buffer[3], 16); + b = c + LeftRotate(0x04881d05 + b + Xor(c, d, a) + input.Buffer[6], 23); + a = b + LeftRotate(0xd9d4d039 + a + Xor(b, c, d), 4); + d = a + LeftRotate(0xe6db99e5 + d + Xor(a, b, c), 11); + c = d + LeftRotate(0x1fa27cf8 + c + Xor(d, a, b), 16); + b = c + LeftRotate(0xc4ac5665 + b + Xor(c, d, a) + input.Buffer[2], 23); - a = LeftRotate(input.Buffer[0] + 0xf4292244 + a + (c ^ (b | ~d)), 6, 32 - 6) + b; - d = LeftRotate(0x432aff97 + d + (b ^ (a | ~c)), 10, 32 - 10) + a; - c = LeftRotate(input.Buffer[7] + 0xab9423a7 + c + (a ^ (d | ~b)), 15, 32 - 15) + d; - b = LeftRotate(input.Buffer[5] + 0xfc93a039 + b + (d ^ (c | ~a)), 21, 32 - 21) + c; - a = LeftRotate(0x655b59c3 + a + (c ^ (b | ~d)), 6, 32 - 6) + b; - d = LeftRotate(input.Buffer[3] + 0x8f0ccc92 + d + (b ^ (a | ~c)), 10, 32 - 10) + a; - c = LeftRotate(0xffeff47d + c + (a ^ (d | ~b)), 15, 32 - 15) + d; - b = LeftRotate(input.Buffer[1] + 0x85845dd1 + b + (d ^ (c | ~a)), 21, 32 - 21) + c; - a = LeftRotate(0x6fa87e4f + a + (c ^ (b | ~d)), 6, 32 - 6) + b; - d = LeftRotate(0xfe2ce6e0 + d + (b ^ (a | ~c)), 10, 32 - 10) + a; - c = LeftRotate(input.Buffer[6] + 0xa3014314 + c + (a ^ (d | ~b)), 15, 32 - 15) + d; - b = LeftRotate(0x4e0811a1 + b + (d ^ (c | ~a)), 21, 32 - 21) + c; - a = LeftRotate(input.Buffer[4] + 0xf7537e82 + a + (c ^ (b | ~d)), 6, 32 - 6) + b; - d = LeftRotate(0xbd3af235 + d + (b ^ (a | ~c)), 10, 32 - 10) + a; - c = LeftRotate(input.Buffer[2] + 0x2ad7d2bb + c + (a ^ (d | ~b)), 15, 32 - 15) + d; - b = LeftRotate(0xeb86d391 + b + (d ^ (c | ~a)), 21, 32 - 21) + c; + a = b + LeftRotate(0xf4292244 + a + I(c, b, d) + input.Buffer[0], 6); + d = a + LeftRotate(0x432aff97 + d + I(b, a, c), 10); + c = d + LeftRotate(0xab9423a7 + c + I(a, d, b) + input.Buffer[7], 15); + b = c + LeftRotate(0xfc93a039 + b + I(d, c, a) + input.Buffer[5], 21); + a = b + LeftRotate(0x655b59c3 + a + I(c, b, d), 6); + d = a + LeftRotate(0x8f0ccc92 + d + I(b, a, c) + input.Buffer[3], 10); + c = d + LeftRotate(0xffeff47d + c + I(a, d, b), 15); + b = c + LeftRotate(0x85845dd1 + b + I(d, c, a) + input.Buffer[1], 21); + a = b + LeftRotate(0x6fa87e4f + a + I(c, b, d), 6); + d = a + LeftRotate(0xfe2ce6e0 + d + I(b, a, c), 10); + c = d + LeftRotate(0xa3014314 + c + I(a, d, b) + input.Buffer[6], 15); + b = c + LeftRotate(0x4e0811a1 + b + I(d, c, a), 21); + a = b + LeftRotate(0xf7537e82 + a + I(c, b, d) + input.Buffer[4], 6); + d = a + LeftRotate(0xbd3af235 + d + I(b, a, c), 10); + c = d + LeftRotate(0x2ad7d2bb + c + I(a, d, b) + input.Buffer[2], 15); + b = c + LeftRotate(0xeb86d391 + b + I(d, c, a), 21); return new[] { @@ -97,9 +96,28 @@ }; } - private static uint LeftRotate(uint x, int left, int right) + [MethodImpl(MethodImplOptions.AggressiveInlining)] + private static uint Blend(uint a, uint b, uint x) + { + return (x & b) | (~x & a); + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + private static uint Xor(uint a, uint b, uint c) + { + return a ^ b ^ c; + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + private static uint I(uint a, uint b, uint c) + { + return a ^ (b | ~c); + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + private static uint LeftRotate(uint x, int left) { - return (x << left) | (x >> right); + return (x << left) | (x >> 32 - left); } } }