Skip to content

Commit 2f5cace

Browse files
authored
Merge pull request #47 from GabrielTofvesson/master
Non-allocating hashing
2 parents 5be6a02 + 7bb5e4f commit 2f5cace

File tree

4 files changed

+149
-23
lines changed

4 files changed

+149
-23
lines changed

MLAPI/Data/NetworkConfig.cs

Lines changed: 8 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
1+
using MLAPI.NetworkingManagerComponents.Binary;
2+
using MLAPI.NetworkingManagerComponents.Cryptography;
13
using MLAPI.Data.Transports.UNET;
2-
using MLAPI.NetworkingManagerComponents.Binary;
34
using System;
45
using System.Collections.Generic;
56
using System.Security.Cryptography;
@@ -180,16 +181,16 @@ public byte[] GetConfig(bool cache = true)
180181
writer.WriteBool(EnableSceneSwitching);
181182
writer.WriteBool(SignKeyExchange);
182183

183-
using (SHA256Managed sha256 = new SHA256Managed())
184-
{
185-
//Returns a 256 bit / 32 byte long checksum of the config
184+
//using (SHA256Managed sha256 = new SHA256Managed())
185+
//{
186+
// Returns a 160 bit / 20 byte / 5 int checksum of the config
186187
if (cache)
187188
{
188-
ConfigHash = sha256.ComputeHash(writer.Finalize());
189+
ConfigHash = MessageDigest.SHA1_Opt(writer.Finalize()).ToArray(); //sha256.ComputeHash(writer.Finalize());
189190
return ConfigHash;
190191
}
191-
return sha256.ComputeHash(writer.Finalize());
192-
}
192+
return MessageDigest.SHA1_Opt(writer.Finalize()).ToArray(); //sha256.ComputeHash(writer.Finalize());
193+
//}
193194
}
194195
}
195196

MLAPI/MLAPI.csproj

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -108,6 +108,7 @@
108108
<Compile Include="NetworkingManagerComponents\Core\NetworkPoolManager.cs" />
109109
<Compile Include="NetworkingManagerComponents\Core\NetworkSceneManager.cs" />
110110
<Compile Include="NetworkingManagerComponents\Core\SpawnManager.cs" />
111+
<Compile Include="NetworkingManagerComponents\Cryptography\MessageDigest.cs" />
111112
<Compile Include="Properties\AssemblyInfo.cs" />
112113
<Compile Include="Data\Transports\UNET\NetId.cs" />
113114
<Compile Include="NetworkingManagerComponents\Binary\MessageChunker.cs" />
Lines changed: 17 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
1-
using System.Collections.Generic;
1+
using MLAPI.NetworkingManagerComponents.Cryptography;
2+
using System.Collections.Generic;
23
using System.Security.Cryptography;
34
using System.Text;
45

@@ -15,44 +16,44 @@ public static ulong GetULongHash(string input, bool cache = false)
1516
if (cache && ulongCachedHashes.ContainsKey(input))
1617
return ulongCachedHashes[input];
1718

18-
using (SHA256Managed sha = new SHA256Managed())
19-
{
20-
byte[] hash = sha.ComputeHash(Encoding.UTF8.GetBytes(input));
21-
ulong value = hash[0] | ((ulong)hash[1] << 8) | ((ulong)hash[2] << 16) | ((ulong)hash[3] << 24) | ((ulong)hash[4] << 32) | ((ulong)hash[5] << 40) | ((ulong)hash[6] << 48) | ((ulong)hash[7] << 56);
19+
//using (SHA256Managed sha = new SHA256Managed())
20+
//{
21+
//byte[] hash = sha.ComputeHash(Encoding.UTF8.GetBytes(input));
22+
ulong value = MessageDigest.SHA1_Opt(Encoding.UTF8.GetBytes(input)).CastULong(); //hash[0] | ((ulong)hash[1] << 8) | ((ulong)hash[2] << 16) | ((ulong)hash[3] << 24) | ((ulong)hash[4] << 32) | ((ulong)hash[5] << 40) | ((ulong)hash[6] << 48) | ((ulong)hash[7] << 56);
2223
if (cache)
2324
ulongCachedHashes.Add(input, value);
2425
return value;
25-
}
26+
//}
2627
}
2728

2829
public static ulong GetUIntHash(string input, bool cache = false)
2930
{
3031
if (cache && uintCachedHashes.ContainsKey(input))
3132
return uintCachedHashes[input];
3233

33-
using (SHA256Managed sha = new SHA256Managed())
34-
{
35-
byte[] hash = sha.ComputeHash(Encoding.UTF8.GetBytes(input));
36-
uint value = hash[0] | ((uint)hash[1] << 8) | ((uint)hash[2] << 16) | ((uint)hash[3] << 24);
34+
//using (SHA256Managed sha = new SHA256Managed())
35+
//{
36+
//byte[] hash = sha.ComputeHash(Encoding.UTF8.GetBytes(input));
37+
uint value = MessageDigest.SHA1_Opt(Encoding.UTF8.GetBytes(input)).CastUInt(); //hash[0] | ((uint)hash[1] << 8) | ((uint)hash[2] << 16) | ((uint)hash[3] << 24);
3738
if (cache)
3839
uintCachedHashes.Add(input, value);
3940
return value;
40-
}
41+
//}
4142
}
4243

4344
public static ushort GetUShortHash(string input, bool cache = false)
4445
{
4546
if (cache && ushortCachedHashes.ContainsKey(input))
4647
return ushortCachedHashes[input];
4748

48-
using (SHA256Managed sha = new SHA256Managed())
49-
{
50-
byte[] hash = sha.ComputeHash(Encoding.UTF8.GetBytes(input));
51-
ushort value = (ushort)(hash[0] | (ushort)(hash[1] << 8));
49+
//using (SHA256Managed sha = new SHA256Managed())
50+
//{
51+
//byte[] hash = sha.ComputeHash(Encoding.UTF8.GetBytes(input));
52+
ushort value = MessageDigest.SHA1_Opt(Encoding.UTF8.GetBytes(input)).CastUShort(); //(ushort)(hash[0] | (ushort)(hash[1] << 8));
5253
if (cache)
5354
ushortCachedHashes.Add(input, value);
5455
return value;
55-
}
56+
//}
5657
}
5758
}
5859
}
Lines changed: 123 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,123 @@
1+
using MLAPI.NetworkingManagerComponents.Binary;
2+
using System;
3+
using System.Collections.Generic;
4+
using System.Linq;
5+
using System.Text;
6+
7+
namespace MLAPI.NetworkingManagerComponents.Cryptography
8+
{
9+
public static class MessageDigest
10+
{
11+
public struct SHA1Result
12+
{
13+
public uint i0, i1, i2, i3, i4;
14+
public byte Get(int idx) => (byte)((idx < 4 ? i0 : idx < 8 ? i1 : idx < 12 ? i2 : idx < 16 ? i3 : i4) >> (8 * (idx % 4)));
15+
public byte[] ToArray()
16+
{
17+
byte[] b = new byte[20];
18+
for (int i = 0; i < 20; ++i) b[i] = Get(i);
19+
return b;
20+
}
21+
private ulong Collect(int bytes)
22+
{
23+
ulong u = 0;
24+
for (int i = 0; i < bytes; ++i) u |= (ulong)Get(i) << (8*i);
25+
return u;
26+
}
27+
public byte CastByte() => Get(0);
28+
public ushort CastUShort() => (ushort)Collect(2);
29+
public uint CastUInt() => (uint)Collect(4);
30+
public ulong CastULong() => (ulong)Collect(8);
31+
}
32+
public static SHA1Result SHA1_Opt(byte[] message)
33+
{
34+
SHA1Result result = new SHA1Result
35+
{
36+
// Initialize buffers
37+
i0 = 0x67452301,
38+
i1 = 0xEFCDAB89,
39+
i2 = 0x98BADCFE,
40+
i3 = 0x10325476,
41+
i4 = 0xC3D2E1F0
42+
};
43+
44+
// Pad message
45+
long len = message.Length * 8;
46+
int
47+
ml = message.Length + 1,
48+
max = ml + ((960 - (ml * 8 % 512)) % 512) / 8 + 8;
49+
50+
// Replaces the allocation of a lot of bytes
51+
byte GetMsg(int idx)
52+
{
53+
if (idx < message.Length)
54+
return message[idx];
55+
else if (idx == message.Length)
56+
return 0x80;
57+
else if (max - idx <= 8)
58+
return (byte)((len >> ((max - 1 - idx) * 8)) & 255);
59+
return 0;
60+
}
61+
62+
int chunks = max / 64;
63+
64+
// Replaces the recurring allocation of 80 uints
65+
uint ComputeIndex(int block, int idx)
66+
{
67+
if (idx < 16)
68+
return (uint)((GetMsg(block * 64 + idx * 4) << 24) | (GetMsg(block * 64 + idx * 4 + 1) << 16) | (GetMsg(block * 64 + idx * 4 + 2) << 8) | (GetMsg(block * 64 + idx * 4 + 3) << 0));
69+
else
70+
return Rot(ComputeIndex(block, idx - 3) ^ ComputeIndex(block, idx - 8) ^ ComputeIndex(block, idx - 14) ^ ComputeIndex(block, idx - 16), 1);
71+
}
72+
73+
// Perform hashing for each 512-bit block
74+
for (int i = 0; i < chunks; ++i)
75+
{
76+
77+
// Initialize chunk-hash
78+
uint
79+
a = result.i0,
80+
b = result.i1,
81+
c = result.i2,
82+
d = result.i3,
83+
e = result.i4;
84+
85+
// Do hash rounds
86+
for (int t = 0; t < 80; ++t)
87+
{
88+
uint tmp = Rot(a, 5) + func(t, b, c, d) + e + K(t) + ComputeIndex(i, t);
89+
e = d;
90+
d = c;
91+
c = Rot(b, 30);
92+
b = a;
93+
a = tmp;
94+
}
95+
result.i0 += a;
96+
result.i1 += b;
97+
result.i2 += c;
98+
result.i3 += d;
99+
result.i4 += e;
100+
}
101+
result.i0 = BinaryHelpers.SwapEndian(result.i0);
102+
result.i1 = BinaryHelpers.SwapEndian(result.i1);
103+
result.i2 = BinaryHelpers.SwapEndian(result.i2);
104+
result.i3 = BinaryHelpers.SwapEndian(result.i3);
105+
result.i4 = BinaryHelpers.SwapEndian(result.i4);
106+
return result;
107+
}
108+
109+
private static uint func(int t, uint b, uint c, uint d) =>
110+
t < 20 ? (b & c) | ((~b) & d) :
111+
t < 40 ? b ^ c ^ d :
112+
t < 60 ? (b & c) | (b & d) | (c & d) :
113+
/*t<80*/ b ^ c ^ d;
114+
115+
private static uint K(int t) =>
116+
t < 20 ? 0x5A827999 :
117+
t < 40 ? 0x6ED9EBA1 :
118+
t < 60 ? 0x8F1BBCDC :
119+
/*t<80*/ 0xCA62C1D6;
120+
121+
private static uint Rot(uint val, int by) => (val << by) | (val >> (32 - by));
122+
}
123+
}

0 commit comments

Comments
 (0)