| @@ -1,203 +0,0 @@ |
| 1 | //****************************************************************************************************** | | |
| 2 | // GuidSHA1Helper.cs - Gbtc | | |
| 3 | // | | |
| 4 | // Copyright © 2014, Grid Protection Alliance. All Rights Reserved. | | |
| 5 | // | | |
| 6 | // Licensed to the Grid Protection Alliance (GPA) under one or more contributor license agreements. See | | |
| 7 | // the NOTICE file distributed with this work for additional information regarding copyright ownership. | | |
| 8 | // The GPA licenses this file to you under the Eclipse Public License -v 1.0 (the "License"); you may | | |
| 9 | // not use this file except in compliance with the License. You may obtain a copy of the License at: | | |
| 10 | // | | |
| 11 | // http://www.opensource.org/licenses/eclipse-1.0.php | | |
| 12 | // | | |
| 13 | // Unless agreed to in writing, the subject software distributed under the License is distributed on an | | |
| 14 | // "AS-IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. Refer to the | | |
| 15 | // License for the specific language governing permissions and limitations. | | |
| 16 | // | | |
| 17 | // Code Modification History: | | |
| 18 | // ---------------------------------------------------------------------------------------------------- | | |
| 19 | // 04/27/2014 - Steven E. Chisholm | | |
| 20 | // Generated original version of source code. | | |
| 21 | // | | |
| 22 | //****************************************************************************************************** | | |
| 23 | | | |
| 24 | using System; | | |
| 25 | | | |
| 26 | namespace GSF.IO.Checksums | | |
| 27 | { | | |
| 28 | /// <summary> | | |
| 29 | /// This class is a helper class to quickly generate a strong hash code for a GUID type. | | |
| 30 | /// </summary> | | |
| 31 | /// <remarks> | | |
| 32 | /// A strong hash function is important in Dictionary Lookups. If the hash is sufficently strong, | | |
| 33 | /// a mod operation over the largest prime can be avoided, thus allowing for faster customized dictionary lookups. | | |
| 34 | /// | | |
| 35 | /// Method is the same as taking the first 4 bytes of a SHA1 hashsum, except zero is reserved and converted to 1. | | |
| 36 | /// | | |
| 37 | /// Customized implementation is about twice as fast as .NET's and requires no class allocation. | | |
| 38 | /// All memory is allocated on the stack (approximately 400 bytes) | | |
| 39 | /// </remarks> | | |
| 40 | public unsafe class GuidSHA1Helper | | |
| 41 | { | | |
| 42 | private const uint Y1 = 0x5a827999; | | |
| 43 | private const uint Y2 = 0x6ed9eba1; | | |
| 44 | private const uint Y3 = 0x8f1bbcdc; | | |
| 45 | private const uint Y4 = 0xca62c1d6; | | |
| 46 | | | |
| 47 | /// <summary> | | |
| 48 | /// Computes the non-zero hashcode of the <see cref="input"/>. | | |
| 49 | /// </summary> | | |
| 50 | /// <param name="input"></param> | | |
| 51 | /// <returns> | | |
| 52 | /// A Non-zero hash of the <see cref="input"/>. If the hash would have been 0, the value 1 is substituded. | | |
| 53 | /// </returns> | | |
| 54 | public static int ComputeHashCode(Guid input) | | |
| 55 | { | | |
| 56 | uint* hash = stackalloc uint[5]; | | |
| 57 | byte* hashBlock = stackalloc byte[80 * 4]; | | |
| 58 | | | |
| 59 | //Initialize | | |
| 60 | hash[0] = 0x67452301; | | |
| 61 | hash[1] = 0xefcdab89; | | |
| 62 | hash[2] = 0x98badcfe; | | |
| 63 | hash[3] = 0x10325476; | | |
| 64 | hash[4] = 0xc3d2e1f0; | | |
| 65 | | | |
| 66 | //Write GUID to buffer | | |
| 67 | *(Guid*)(hashBlock) = input; | | |
| 68 | | | |
| 69 | const long bitLength = (16 << 3); | | |
| 70 | hashBlock[16] = 128; | | |
| 71 | | | |
| 72 | //Clear hash | | |
| 73 | for (int x = 17; x < 56; x++) | | |
| 74 | hashBlock[x] = 0; | | |
| 75 | | | |
| 76 | hashBlock[56] = (byte)(bitLength >> 56); | | |
| 77 | hashBlock[57] = (byte)(bitLength >> 48); | | |
| 78 | hashBlock[58] = (byte)(bitLength >> 40); | | |
| 79 | hashBlock[59] = (byte)(bitLength >> 32); | | |
| 80 | hashBlock[60] = (byte)(bitLength >> 24); | | |
| 81 | hashBlock[61] = (byte)(bitLength >> 16); | | |
| 82 | hashBlock[62] = (byte)(bitLength >> 8); | | |
| 83 | hashBlock[63] = (byte)(bitLength); | | |
| 84 | | | |
| 85 | if (BitConverter.IsLittleEndian) | | |
| 86 | SwapEndianSha((ulong*)hashBlock, (ulong*)hashBlock); | | |
| 87 | InternalHashBlock(hash, (uint*)hashBlock); | | |
| 88 | | | |
| 89 | //Checksum is bigEndian, read as an interger. | | |
| 90 | //Read big endian | | |
| 91 | int sum = *((byte*)hash + 0) << 24 | | | |
| 92 | *((byte*)hash + 1) << 16 | | | |
| 93 | *((byte*)hash + 2) << 8 | | | |
| 94 | *((byte*)hash + 3); | | |
| 95 | | | |
| 96 | if (sum == 0) | | |
| 97 | return 1; | | |
| 98 | return sum; | | |
| 99 | } | | |
| 100 | | | |
| 101 | /// <summary> | | |
| 102 | /// Computes the hash of the blocks. Words must already be in big endian format. | | |
| 103 | /// </summary> | | |
| 104 | /// <param name="hash">the current values of the hash</param> | | |
| 105 | /// <param name="words">16 words that are already in big endian format.</param> | | |
| 106 | static void InternalHashBlock(uint* hash, uint* words) | | |
| 107 | { | | |
| 108 | uint a = hash[0]; | | |
| 109 | uint b = hash[1]; | | |
| 110 | uint c = hash[2]; | | |
| 111 | uint d = hash[3]; | | |
| 112 | uint e = hash[4]; | | |
| 113 | uint* x = words; | | |
| 114 | int i; | | |
| 115 | // | | |
| 116 | // expand 16 word block into 80 word block. | | |
| 117 | // | | |
| 118 | for (i = 0; i < 64; i++) | | |
| 119 | { | | |
| 120 | uint t = x[13] ^ x[8] ^ x[2] ^ x[0]; | | |
| 121 | x[16] = t << 1 | t >> 31; | | |
| 122 | x++; | | |
| 123 | } | | |
| 124 | | | |
| 125 | // | | |
| 126 | // round 1 | | |
| 127 | // | | |
| 128 | x = words; | | |
| 129 | | | |
| 130 | for (i = 0; i < 4; i++) | | |
| 131 | { | | |
| 132 | // E = rotateLeft(A, 5) + F(B, C, D) + E + X[idx++] + Y1 | | |
| 133 | // B = rotateLeft(B, 30) | | |
| 134 | e += (a << 5 | (a >> 27)) + ((b & c) | (~b & d)) + x[0] + Y1; b = b << 30 | (b >> 2); | | |
| 135 | d += (e << 5 | (e >> 27)) + ((a & b) | (~a & c)) + x[1] + Y1; a = a << 30 | (a >> 2); | | |
| 136 | c += (d << 5 | (d >> 27)) + ((e & a) | (~e & b)) + x[2] + Y1; e = e << 30 | (e >> 2); | | |
| 137 | b += (c << 5 | (c >> 27)) + ((d & e) | (~d & a)) + x[3] + Y1; d = d << 30 | (d >> 2); | | |
| 138 | a += (b << 5 | (b >> 27)) + ((c & d) | (~c & e)) + x[4] + Y1; c = c << 30 | (c >> 2); x += 5; | | |
| 139 | } | | |
| 140 | | | |
| 141 | // | | |
| 142 | // round 2 | | |
| 143 | // | | |
| 144 | for (i = 0; i < 4; i++) | | |
| 145 | { | | |
| 146 | // E = rotateLeft(A, 5) + H(B, C, D) + E + X[idx++] + Y2 | | |
| 147 | // B = rotateLeft(B, 30) | | |
| 148 | e += (a << 5 | (a >> 27)) + (b ^ c ^ d) + x[0] + Y2; b = b << 30 | (b >> 2); | | |
| 149 | d += (e << 5 | (e >> 27)) + (a ^ b ^ c) + x[1] + Y2; a = a << 30 | (a >> 2); | | |
| 150 | c += (d << 5 | (d >> 27)) + (e ^ a ^ b) + x[2] + Y2; e = e << 30 | (e >> 2); | | |
| 151 | b += (c << 5 | (c >> 27)) + (d ^ e ^ a) + x[3] + Y2; d = d << 30 | (d >> 2); | | |
| 152 | a += (b << 5 | (b >> 27)) + (c ^ d ^ e) + x[4] + Y2; c = c << 30 | (c >> 2); x += 5; | | |
| 153 | } | | |
| 154 | | | |
| 155 | // | | |
| 156 | // round 3 | | |
| 157 | // | | |
| 158 | for (i = 0; i < 4; i++) | | |
| 159 | { | | |
| 160 | // E = rotateLeft(A, 5) + G(B, C, D) + E + X[idx++] + Y3 | | |
| 161 | // B = rotateLeft(B, 30) | | |
| 162 | e += (a << 5 | (a >> 27)) + ((b & c) | (b & d) | (c & d)) + x[0] + Y3; b = b << 30 | (b >> 2); | | |
| 163 | d += (e << 5 | (e >> 27)) + ((a & b) | (a & c) | (b & c)) + x[1] + Y3; a = a << 30 | (a >> 2); | | |
| 164 | c += (d << 5 | (d >> 27)) + ((e & a) | (e & b) | (a & b)) + x[2] + Y3; e = e << 30 | (e >> 2); | | |
| 165 | b += (c << 5 | (c >> 27)) + ((d & e) | (d & a) | (e & a)) + x[3] + Y3; d = d << 30 | (d >> 2); | | |
| 166 | a += (b << 5 | (b >> 27)) + ((c & d) | (c & e) | (d & e)) + x[4] + Y3; c = c << 30 | (c >> 2); x += 5; | | |
| 167 | } | | |
| 168 | | | |
| 169 | // | | |
| 170 | // round 4 | | |
| 171 | // | | |
| 172 | for (i = 0; i < 4; i++) | | |
| 173 | { | | |
| 174 | // E = rotateLeft(A, 5) + H(B, C, D) + E + X[idx++] + Y4 | | |
| 175 | // B = rotateLeft(B, 30) | | |
| 176 | e += (a << 5 | (a >> 27)) + (b ^ c ^ d) + x[0] + Y4; b = b << 30 | (b >> 2); | | |
| 177 | d += (e << 5 | (e >> 27)) + (a ^ b ^ c) + x[1] + Y4; a = a << 30 | (a >> 2); | | |
| 178 | c += (d << 5 | (d >> 27)) + (e ^ a ^ b) + x[2] + Y4; e = e << 30 | (e >> 2); | | |
| 179 | b += (c << 5 | (c >> 27)) + (d ^ e ^ a) + x[3] + Y4; d = d << 30 | (d >> 2); | | |
| 180 | a += (b << 5 | (b >> 27)) + (c ^ d ^ e) + x[4] + Y4; c = c << 30 | (c >> 2); x += 5; | | |
| 181 | } | | |
| 182 | | | |
| 183 | hash[0] += a; | | |
| 184 | hash[1] += b; | | |
| 185 | hash[2] += c; | | |
| 186 | hash[3] += d; | | |
| 187 | hash[4] += e; | | |
| 188 | } | | |
| 189 | | | |
| 190 | static unsafe void SwapEndianSha(ulong* src, ulong* dst) | | |
| 191 | { | | |
| 192 | ulong value; | | |
| 193 | value = src[0]; dst[0] = ((0xFF000000FF000000 & value) >> 24) | ((0x00FF000000FF0000 & value) >> 8) | ((0x0000FF000000FF00 & value) << 8) | ((0x000000FF000000FF & value) << 24); | | |
| 194 | value = src[1]; dst[1] = ((0xFF000000FF000000 & value) >> 24) | ((0x00FF000000FF0000 & value) >> 8) | ((0x0000FF000000FF00 & value) << 8) | ((0x000000FF000000FF & value) << 24); | | |
| 195 | value = src[2]; dst[2] = ((0xFF000000FF000000 & value) >> 24) | ((0x00FF000000FF0000 & value) >> 8) | ((0x0000FF000000FF00 & value) << 8) | ((0x000000FF000000FF & value) << 24); | | |
| 196 | value = src[3]; dst[3] = ((0xFF000000FF000000 & value) >> 24) | ((0x00FF000000FF0000 & value) >> 8) | ((0x0000FF000000FF00 & value) << 8) | ((0x000000FF000000FF & value) << 24); | | |
| 197 | value = src[4]; dst[4] = ((0xFF000000FF000000 & value) >> 24) | ((0x00FF000000FF0000 & value) >> 8) | ((0x0000FF000000FF00 & value) << 8) | ((0x000000FF000000FF & value) << 24); | | |
| 198 | value = src[5]; dst[5] = ((0xFF000000FF000000 & value) >> 24) | ((0x00FF000000FF0000 & value) >> 8) | ((0x0000FF000000FF00 & value) << 8) | ((0x000000FF000000FF & value) << 24); | | |
| 199 | value = src[6]; dst[6] = ((0xFF000000FF000000 & value) >> 24) | ((0x00FF000000FF0000 & value) >> 8) | ((0x0000FF000000FF00 & value) << 8) | ((0x000000FF000000FF & value) << 24); | | |
| 200 | value = src[7]; dst[7] = ((0xFF000000FF000000 & value) >> 24) | ((0x00FF000000FF0000 & value) >> 8) | ((0x0000FF000000FF00 & value) << 8) | ((0x000000FF000000FF & value) << 24); | | |
| 201 | } | | |
| 202 | } | | |
| 203 | } | | |