Permalink
Browse files

Implement universal hashing for niecza hashes

It appears to be a few percent slower than the builtin string.GetHashCode,
but proof against hash-based algorithmic complexity attacks is hard to
replace...
  • Loading branch information...
1 parent b4b916a commit e08dd76336acddb22ca0c956ffa62897f3a8ff9a @sorear committed Mar 30, 2012
Showing with 46 additions and 19 deletions.
  1. +1 −1 lib/CodeGen.cs
  2. +11 −2 lib/Kernel.cs
  3. +34 −16 lib/Utils.cs
View
@@ -3652,7 +3652,7 @@ public class DowncallReceiver : CallReceiver {
Kernel.TraceFlags = Kernel.TRACE_CUR;
Kernel.TraceCount = Kernel.TraceFreq = 1;
}
- Kernel.SetTrace();
+ Kernel.InitGlobal();
Backend.obj_dir = (string)args[1];
Builtins.upcall_receiver = (System.Collections.IDictionary)args[2];
return null;
View
@@ -4740,6 +4740,15 @@ public class Kernel {
[CompartmentGlobal] internal static SubInfo CommonGrep_I;
[CompartmentGlobal] internal static SubInfo TEMP_SI;
+ internal static void InitGlobal() {
+ Random r = new Random();
+ VarHash.string_hash_argument =
+ (uint)r.Next(VarHash.HASH_ARG_MAX + 1);
+ VarHash.hash_automorphism =
+ ((uint)r.Next(int.MaxValue)) * 2 + 1;
+ SetTrace();
+ }
+
internal static void InitCompartment() {
RuntimeUnit.reg = new ObjectRegistry();
@@ -6518,7 +6527,7 @@ class LastFrameNode {
public static void MainHandler(string uname, string[] args) {
InitCompartment();
- SetTrace();
+ InitGlobal();
commandArgs = args;
RuntimeUnit ru = (RuntimeUnit)
@@ -6555,7 +6564,7 @@ class LastFrameNode {
string cmd = args.Length > 0 ? args[0] : "-help";
InitCompartment();
- SetTrace();
+ InitGlobal();
if (cmd == "-field-inventory") {
foreach (Type ty in typeof(Kernel).Assembly.GetTypes()) {
View
@@ -204,16 +204,35 @@ public sealed class VarHash : IEnumerable<KeyValuePair<string,Variable>>,
VarHashLink[] heap;
int[] htab;
- const int INITIAL = 5;
- const int THRESHOLD = 11;
-
- [Immutable]
- static int[] grow = new int[] {
- 5, 11, 17, 37, 67, 131, 257, 521, 1031, 2053, 4099, 8209, 16411,
- 32771, 65537, 131101, 262147, 524309, 1048583, 2097169, 4194319,
- 8388617, 16777259, 33554467, 67108879, 134217757, 268435459,
- 536870923, 1073741827
- };
+ const int INITIAL = 4;
+ const int THRESHOLD = 8;
+
+ // sacrifices a bit of universality to save a reduction step
+ public const int HASH_ARG_MAX = 1073709057;
+ [TrueGlobal]
+ public static uint string_hash_argument;
+ public static uint hash_automorphism;
+
+ public static unsafe int UniversalHash(int buckets, string str) {
+ fixed(char *c = str) {
+ char *cc = c;
+ char *end = cc + str.Length;
+ uint accum = 0;
+ while (cc < end) {
+ // accum <= 2^32-1-65535
+ accum += *(cc++);
+ // accum <= 2^32-1
+ ulong temp = (ulong)accum * string_hash_argument;
+ // temp <= (2^32-1) * HASH_ARG_MAX
+ // temp <= 4611545284160290815
+ accum = (uint)((temp & 0x7FFFFFFF) + (temp >> 31));
+ // accum <= floor(temp / 2^31) + (2^31-1)
+ // accum <= 4294901760 = 2^32-1-65535
+ }
+ ulong temp2 = (ulong)accum * (uint)buckets;
+ return (int) (temp2 >> 32);
+ }
+ }
public VarHash() { Clear(); }
@@ -255,8 +274,7 @@ public sealed class VarHash : IEnumerable<KeyValuePair<string,Variable>>,
return;
}
- int bkt = (int)(((uint) key.GetHashCode()) %
- ((uint) htab.Length));
+ int bkt = UniversalHash(htab.Length, key);
int ptr = htab[bkt];
if (ptr < 0) {
@@ -307,11 +325,11 @@ public sealed class VarHash : IEnumerable<KeyValuePair<string,Variable>>,
void rehash(int ordel) {
int rank = 0;
- while (heap.Length != grow[rank]) rank++;
+ while (heap.Length != (1 << (rank + 2))) rank++;
rank += ordel;
VarHashLink[] oheap = heap;
- init(grow[rank]);
+ init(1 << (rank + 2));
foreach (VarHashLink vhl in oheap)
if (vhl.key != null)
@@ -338,7 +356,7 @@ public sealed class VarHash : IEnumerable<KeyValuePair<string,Variable>>,
return false;
}
- int bkt = (int)(((uint) key.GetHashCode()) % ((uint) htab.Length));
+ int bkt = UniversalHash(htab.Length, key);
int ptr = htab[bkt];
if (ptr < 0)
@@ -419,7 +437,7 @@ public sealed class VarHash : IEnumerable<KeyValuePair<string,Variable>>,
return false;
}
- int ptr = htab[((uint) key.GetHashCode()) % ((uint) htab.Length)];
+ int ptr = htab[UniversalHash(htab.Length, key)];
while (ptr >= 0) {
if (heap[ptr].key == key) {

0 comments on commit e08dd76

Please sign in to comment.