Brad Bishop | 316dfdd | 2018-06-25 12:45:53 -0400 | [diff] [blame] | 1 | Replace murmurhash algorithm with Robert Jenkin's hash algorithm |
| 2 | |
| 3 | Upstream-Status: Pending |
| 4 | |
| 5 | From test result, murmurhash algorithm does not work in big endian |
| 6 | processor, so replace it with Robert Jenkin's hash which has worked |
| 7 | in linux kernel for many years and has more adaptability. |
| 8 | |
| 9 | Signed-off-by: Roy.Li <rongqing.li@windriver.com> |
| 10 | --- |
| 11 | libfdproto/ostr.c | 192 +++++++++++++++++++++-------------------------------- |
| 12 | 1 file changed, 74 insertions(+), 118 deletions(-) |
| 13 | |
| 14 | diff --git a/libfdproto/ostr.c b/libfdproto/ostr.c |
| 15 | index 8f29b48..ce1f4dd 100644 |
| 16 | --- a/libfdproto/ostr.c |
| 17 | +++ b/libfdproto/ostr.c |
| 18 | @@ -430,128 +430,84 @@ after_proto: |
| 19 | |
| 20 | |
| 21 | /********************************************************************************************************/ |
| 22 | -/* Hash function -- credits to Austin Appleby, thank you ^^ */ |
| 23 | -/* See http://murmurhash.googlepages.com for more information on this function */ |
| 24 | - |
| 25 | -/* the strings are NOT always aligned properly (ex: received in RADIUS message), so we use the aligned MurmurHash2 function as needed */ |
| 26 | -#define _HASH_MIX(h,k,m) { k *= m; k ^= k >> r; k *= m; h *= m; h ^= k; } |
| 27 | -uint32_t fd_os_hash ( uint8_t * string, size_t len ) |
| 28 | +/* |
| 29 | + * Robert Jenkin's hash function. |
| 30 | + * http://burtleburtle.net/bob/hash/evahash.html |
| 31 | + * This is in the public domain. |
| 32 | + */ |
| 33 | +#define mix(a, b, c) \ |
| 34 | + do { \ |
| 35 | + a = a - b; a = a - c; a = a ^ (c >> 13); \ |
| 36 | + b = b - c; b = b - a; b = b ^ (a << 8); \ |
| 37 | + c = c - a; c = c - b; c = c ^ (b >> 13); \ |
| 38 | + a = a - b; a = a - c; a = a ^ (c >> 12); \ |
| 39 | + b = b - c; b = b - a; b = b ^ (a << 16); \ |
| 40 | + c = c - a; c = c - b; c = c ^ (b >> 5); \ |
| 41 | + a = a - b; a = a - c; a = a ^ (c >> 3); \ |
| 42 | + b = b - c; b = b - a; b = b ^ (a << 10); \ |
| 43 | + c = c - a; c = c - b; c = c ^ (b >> 15); \ |
| 44 | + } while (0) |
| 45 | + |
| 46 | +unsigned hash_rjenkins(const char *str, unsigned length) |
| 47 | { |
| 48 | - uint32_t hash = len; |
| 49 | - uint8_t * data = string; |
| 50 | - |
| 51 | - const unsigned int m = 0x5bd1e995; |
| 52 | - const int r = 24; |
| 53 | - int align = (long)string & 3; |
| 54 | - |
| 55 | - if (!align || (len < 4)) { |
| 56 | - /* In case data is aligned, MurmurHash2 function */ |
| 57 | - while(len >= 4) |
| 58 | - { |
| 59 | - /* Mix 4 bytes at a time into the hash */ |
| 60 | - uint32_t k = *(uint32_t *)data; /* We don't care about the byte order */ |
| 61 | - |
| 62 | - _HASH_MIX(hash, k, m); |
| 63 | - |
| 64 | - data += 4; |
| 65 | - len -= 4; |
| 66 | - } |
| 67 | - |
| 68 | - /* Handle the last few bytes of the input */ |
| 69 | - switch(len) { |
| 70 | - case 3: hash ^= data[2] << 16; |
| 71 | - case 2: hash ^= data[1] << 8; |
| 72 | - case 1: hash ^= data[0]; |
| 73 | - hash *= m; |
| 74 | - } |
| 75 | - |
| 76 | - } else { |
| 77 | - /* Unaligned data, use alignment-safe slower version */ |
| 78 | - |
| 79 | - /* Pre-load the temp registers */ |
| 80 | - uint32_t t = 0, d = 0; |
| 81 | - switch(align) |
| 82 | - { |
| 83 | - case 1: t |= data[2] << 16; |
| 84 | - case 2: t |= data[1] << 8; |
| 85 | - case 3: t |= data[0]; |
| 86 | - } |
| 87 | - t <<= (8 * align); |
| 88 | - |
| 89 | - data += 4-align; |
| 90 | - len -= 4-align; |
| 91 | - |
| 92 | - /* From this point, "data" can be read by chunks of 4 bytes */ |
| 93 | - |
| 94 | - int sl = 8 * (4-align); |
| 95 | - int sr = 8 * align; |
| 96 | - |
| 97 | - /* Mix */ |
| 98 | - while(len >= 4) |
| 99 | - { |
| 100 | - uint32_t k; |
| 101 | - |
| 102 | - d = *(unsigned int *)data; |
| 103 | - k = (t >> sr) | (d << sl); |
| 104 | - |
| 105 | - _HASH_MIX(hash, k, m); |
| 106 | - |
| 107 | - t = d; |
| 108 | - |
| 109 | - data += 4; |
| 110 | - len -= 4; |
| 111 | - } |
| 112 | - |
| 113 | - /* Handle leftover data in temp registers */ |
| 114 | - d = 0; |
| 115 | - if(len >= align) |
| 116 | - { |
| 117 | - uint32_t k; |
| 118 | - |
| 119 | - switch(align) |
| 120 | - { |
| 121 | - case 3: d |= data[2] << 16; |
| 122 | - case 2: d |= data[1] << 8; |
| 123 | - case 1: d |= data[0]; |
| 124 | - } |
| 125 | - |
| 126 | - k = (t >> sr) | (d << sl); |
| 127 | - _HASH_MIX(hash, k, m); |
| 128 | - |
| 129 | - data += align; |
| 130 | - len -= align; |
| 131 | - |
| 132 | - /* Handle tail bytes */ |
| 133 | - |
| 134 | - switch(len) |
| 135 | - { |
| 136 | - case 3: hash ^= data[2] << 16; |
| 137 | - case 2: hash ^= data[1] << 8; |
| 138 | - case 1: hash ^= data[0]; |
| 139 | - hash *= m; |
| 140 | - }; |
| 141 | - } |
| 142 | - else |
| 143 | - { |
| 144 | - switch(len) |
| 145 | - { |
| 146 | - case 3: d |= data[2] << 16; |
| 147 | - case 2: d |= data[1] << 8; |
| 148 | - case 1: d |= data[0]; |
| 149 | - case 0: hash ^= (t >> sr) | (d << sl); |
| 150 | - hash *= m; |
| 151 | - } |
| 152 | - } |
| 153 | - |
| 154 | + const unsigned char *k = (const unsigned char *)str; |
| 155 | + uint32_t a, b, c; /* the internal state */ |
| 156 | + uint32_t len; /* how many key bytes still need mixing */ |
| 157 | + |
| 158 | + /* Set up the internal state */ |
| 159 | + len = length; |
| 160 | + a = 0x9e3779b9; /* the golden ratio; an arbitrary value */ |
| 161 | + b = a; |
| 162 | + c = 0; /* variable initialization of internal state */ |
| 163 | + |
| 164 | + /* handle most of the key */ |
| 165 | + while (len >= 12) { |
| 166 | + a = a + (k[0] + ((uint32_t)k[1] << 8) + ((uint32_t)k[2] << 16) + |
| 167 | + ((uint32_t)k[3] << 24)); |
| 168 | + b = b + (k[4] + ((uint32_t)k[5] << 8) + ((uint32_t)k[6] << 16) + |
| 169 | + ((uint32_t)k[7] << 24)); |
| 170 | + c = c + (k[8] + ((uint32_t)k[9] << 8) + ((uint32_t)k[10] << 16) + |
| 171 | + ((uint32_t)k[11] << 24)); |
| 172 | + mix(a, b, c); |
| 173 | + k = k + 12; |
| 174 | + len = len - 12; |
| 175 | + } |
| 176 | |
| 177 | + /* handle the last 11 bytes */ |
| 178 | + c = c + length; |
| 179 | + switch (len) { /* all the case statements fall through */ |
| 180 | + case 11: |
| 181 | + c = c + ((uint32_t)k[10] << 24); |
| 182 | + case 10: |
| 183 | + c = c + ((uint32_t)k[9] << 16); |
| 184 | + case 9: |
| 185 | + c = c + ((uint32_t)k[8] << 8); |
| 186 | + /* the first byte of c is reserved for the length */ |
| 187 | + case 8: |
| 188 | + b = b + ((uint32_t)k[7] << 24); |
| 189 | + case 7: |
| 190 | + b = b + ((uint32_t)k[6] << 16); |
| 191 | + case 6: |
| 192 | + b = b + ((uint32_t)k[5] << 8); |
| 193 | + case 5: |
| 194 | + b = b + k[4]; |
| 195 | + case 4: |
| 196 | + a = a + ((uint32_t)k[3] << 24); |
| 197 | + case 3: |
| 198 | + a = a + ((uint32_t)k[2] << 16); |
| 199 | + case 2: |
| 200 | + a = a + ((uint32_t)k[1] << 8); |
| 201 | + case 1: |
| 202 | + a = a + k[0]; |
| 203 | + /* case 0: nothing left to add */ |
| 204 | } |
| 205 | + mix(a, b, c); |
| 206 | |
| 207 | - /* Do a few final mixes of the hash to ensure the last few |
| 208 | - bytes are well-incorporated. */ |
| 209 | - hash ^= hash >> 13; |
| 210 | - hash *= m; |
| 211 | - hash ^= hash >> 15; |
| 212 | + return c; |
| 213 | +} |
| 214 | |
| 215 | - return hash; |
| 216 | +uint32_t fd_os_hash ( uint8_t * string, size_t len ) |
| 217 | +{ |
| 218 | + return hash_rjenkins(string, len); |
| 219 | } |
| 220 | |
| 221 | -- |
| 222 | 1.7.10.4 |
| 223 | |