This is a live mirror of the Perl 5 development currently hosted at https://github.com/perl/perl5
add a hardened one-at-a-time hash variant
[perl5.git] / hv_func.h
index fdb4ad8..df39808 100644 (file)
--- a/hv_func.h
+++ b/hv_func.h
         || defined(PERL_HASH_FUNC_SUPERFAST) \
         || defined(PERL_HASH_FUNC_MURMUR3) \
         || defined(PERL_HASH_FUNC_ONE_AT_A_TIME) \
+        || defined(PERL_HASH_FUNC_ONE_AT_A_TIME_HARD) \
         || defined(PERL_HASH_FUNC_ONE_AT_A_TIME_OLD) \
     )
 #ifdef HAS_QUAD
 #define PERL_HASH_FUNC_SIPHASH
 #else
-#define PERL_HASH_FUNC_ONE_AT_A_TIME
+#define PERL_HASH_FUNC_ONE_AT_A_TIME_HARD
 #endif
 #endif
 
 #   define PERL_HASH_FUNC "SDBM"
 #   define PERL_HASH_SEED_BYTES 4
 #   define PERL_HASH(hash,str,len) (hash)= S_perl_hash_sdbm(PERL_HASH_SEED,(U8*)(str),(len))
+#elif defined(PERL_HASH_FUNC_ONE_AT_A_TIME_HARD)
+#   define PERL_HASH_FUNC "ONE_AT_A_TIME_HARD"
+#   define PERL_HASH_SEED_BYTES 8
+#   define PERL_HASH(hash,str,len) (hash)= S_perl_hash_one_at_a_time_hard(PERL_HASH_SEED,(U8*)(str),(len))
 #elif defined(PERL_HASH_FUNC_ONE_AT_A_TIME)
 #   define PERL_HASH_FUNC "ONE_AT_A_TIME"
 #   define PERL_HASH_SEED_BYTES 4
@@ -460,9 +465,11 @@ S_perl_hash_sdbm(const unsigned char * const seed, const unsigned char *str, con
 }
 
 
-/* FYI: This is the "One-at-a-Time" algorithm by Bob Jenkins
+/* This is the "One-at-a-Time" algorithm by Bob Jenkins
  * from requirements by Colin Plumb.
- * (http://burtleburtle.net/bob/hash/doobs.html) */
+ * (http://burtleburtle.net/bob/hash/doobs.html)
+ * With seed/len tweak.
+ * */
 PERL_STATIC_INLINE U32
 S_perl_hash_one_at_a_time(const unsigned char * const seed, const unsigned char *str, const STRLEN len) {
     const unsigned char * const end = (const unsigned char *)str + len;
@@ -477,6 +484,42 @@ S_perl_hash_one_at_a_time(const unsigned char * const seed, const unsigned char
     return (hash + (hash << 15));
 }
 
+/* Derived from "One-at-a-Time" algorithm by Bob Jenkins */
+PERL_STATIC_INLINE U32
+S_perl_hash_one_at_a_time_hard(const unsigned char * const seed, const unsigned char *str, const STRLEN len) {
+    const unsigned char * const end = (const unsigned char *)str + len;
+    U32 hash = *((U32*)seed) + len;
+    
+    while (str < end) {
+        hash += (hash << 10);
+        hash ^= (hash >> 6);
+        hash += *str++;
+    }
+    
+    hash += (hash << 10);
+    hash ^= (hash >> 6);
+    hash += seed[4];
+    
+    hash += (hash << 10);
+    hash ^= (hash >> 6);
+    hash += seed[5];
+    
+    hash += (hash << 10);
+    hash ^= (hash >> 6);
+    hash += seed[6];
+    
+    hash += (hash << 10);
+    hash ^= (hash >> 6);
+    hash += seed[7];
+    
+    hash += (hash << 10);
+    hash ^= (hash >> 6);
+
+    hash += (hash << 3);
+    hash ^= (hash >> 11);
+    return (hash + (hash << 15));
+}
+
 PERL_STATIC_INLINE U32
 S_perl_hash_old_one_at_a_time(const unsigned char * const seed, const unsigned char *str, const STRLEN len) {
     const unsigned char * const end = (const unsigned char *)str + len;