Skip to content

Commit b80fd3f

Browse files
authored
Merge pull request #1839 from private-octopus/long-random-hash
Improve hash functions used by picohash tables
2 parents f3f7312 + dff7f5f commit b80fd3f

17 files changed

+513
-89
lines changed

CMakeLists.txt

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ else()
88
endif()
99

1010
project(picoquic
11-
VERSION 1.1.30.2
11+
VERSION 1.1.31.0
1212
DESCRIPTION "picoquic library"
1313
LANGUAGES C CXX)
1414

@@ -105,6 +105,7 @@ set(PICOQUIC_LIBRARY_FILES
105105
picoquic/sacks.c
106106
picoquic/sender.c
107107
picoquic/sim_link.c
108+
picoquic/siphash.c
108109
picoquic/sockloop.c
109110
picoquic/spinbit.c
110111
picoquic/ticket_store.c
@@ -124,7 +125,8 @@ set(PICOQUIC_CORE_HEADERS
124125
picoquic/picoquic_logger.h
125126
picoquic/picoquic_binlog.h
126127
picoquic/picoquic_config.h
127-
picoquic/picoquic_lb.h)
128+
picoquic/picoquic_lb.h
129+
picoquic/siphash.h)
128130

129131
set(LOGLIB_LIBRARY_FILES
130132
loglib/autoqlog.c

UnitTest1/unittest1.cpp

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,20 @@ namespace UnitTest1
4848
Assert::AreEqual(ret, 0);
4949
}
5050

51+
TEST_METHOD(picohash_bytes)
52+
{
53+
int ret = picohash_bytes_test();
54+
55+
Assert::AreEqual(ret, 0);
56+
}
57+
58+
TEST_METHOD(siphash)
59+
{
60+
int ret = siphash_test();
61+
62+
Assert::AreEqual(ret, 0);
63+
}
64+
5165
TEST_METHOD(picolog_basic)
5266
{
5367
int ret = picolog_basic_test();

loglib/cidset.c

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -24,10 +24,10 @@
2424
#include "picoquic_utils.h"
2525

2626
/* Hash and compare for CNX hash tables */
27-
static uint64_t picoquic_cid_hash(const void* key)
27+
static uint64_t picoquic_cid_hash(const void* key, const uint8_t * hash_seed)
2828
{
2929
const picoquic_connection_id_t* cid = (const picoquic_connection_id_t*)key;
30-
return picoquic_connection_id_hash(cid);
30+
return picoquic_connection_id_hash(cid, hash_seed);
3131
}
3232

3333
static int picoquic_cid_compare(const void* key0, const void* key1)

picoquic/picohash.c

Lines changed: 58 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -23,14 +23,17 @@
2323
* Basic hash implementation, like we have seen tons off already.
2424
*/
2525
#include "picohash.h"
26+
#include "siphash.h"
2627
#include <stdlib.h>
2728
#include <string.h>
2829

2930
picohash_table* picohash_create_ex(size_t nb_bin,
30-
uint64_t (*picohash_hash)(const void*),
31+
uint64_t (*picohash_hash)(const void*, const uint8_t *),
3132
int (*picohash_compare)(const void*, const void*),
32-
picohash_item * (*picohash_key_to_item)(const void*))
33+
picohash_item * (*picohash_key_to_item)(const void*),
34+
const uint8_t* hash_seed)
3335
{
36+
static const uint8_t null_seed[16] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
3437
picohash_table* t = (picohash_table*)malloc(sizeof(picohash_table));
3538
size_t items_length = sizeof(picohash_item*) * nb_bin;
3639
t->hash_bin = NULL;
@@ -48,21 +51,22 @@ picohash_table* picohash_create_ex(size_t nb_bin,
4851
t->picohash_hash = picohash_hash;
4952
t->picohash_compare = picohash_compare;
5053
t->picohash_key_to_item = picohash_key_to_item;
54+
t->hash_seed = (hash_seed == NULL)? null_seed: hash_seed;
5155
}
5256

5357
return t;
5458
}
5559

5660
picohash_table* picohash_create(size_t nb_bin,
57-
uint64_t(*picohash_hash)(const void*),
61+
uint64_t(*picohash_hash)(const void*, const uint8_t*),
5862
int (*picohash_compare)(const void*, const void*))
5963
{
60-
return picohash_create_ex(nb_bin, picohash_hash, picohash_compare, NULL);
64+
return picohash_create_ex(nb_bin, picohash_hash, picohash_compare, NULL, NULL);
6165
}
6266

6367
picohash_item* picohash_retrieve(picohash_table* hash_table, const void* key)
6468
{
65-
uint64_t hash = hash_table->picohash_hash(key);
69+
uint64_t hash = hash_table->picohash_hash(key, hash_table->hash_seed);
6670
uint32_t bin = (uint32_t)(hash % hash_table->nb_bin);
6771
picohash_item* item = hash_table->hash_bin[bin];
6872

@@ -79,7 +83,7 @@ picohash_item* picohash_retrieve(picohash_table* hash_table, const void* key)
7983

8084
int picohash_insert(picohash_table* hash_table, const void* key)
8185
{
82-
uint64_t hash = hash_table->picohash_hash(key);
86+
uint64_t hash = hash_table->picohash_hash(key, hash_table->hash_seed);
8387
uint32_t bin = (uint32_t)(hash % hash_table->nb_bin);
8488
int ret = 0;
8589
picohash_item* item;
@@ -150,19 +154,21 @@ void picohash_delete_key(picohash_table* hash_table, void* key, int delete_key_t
150154

151155
void picohash_delete(picohash_table* hash_table, int delete_key_too)
152156
{
153-
for (uint32_t i = 0; i < hash_table->nb_bin; i++) {
154-
picohash_item* item = hash_table->hash_bin[i];
155-
while (item != NULL) {
156-
picohash_item* tmp = item;
157-
const void* key_to_delete = tmp->key;
158-
159-
item = item->next_in_bin;
160-
161-
if (hash_table->picohash_key_to_item == NULL) {
162-
free(tmp);
163-
}
164-
if (delete_key_too) {
165-
free((void*)key_to_delete);
157+
if (hash_table->count > 0) {
158+
for (uint32_t i = 0; i < hash_table->nb_bin; i++) {
159+
picohash_item* item = hash_table->hash_bin[i];
160+
while (item != NULL) {
161+
picohash_item* tmp = item;
162+
const void* key_to_delete = tmp->key;
163+
164+
item = item->next_in_bin;
165+
166+
if (hash_table->picohash_key_to_item == NULL) {
167+
free(tmp);
168+
}
169+
if (delete_key_too) {
170+
free((void*)key_to_delete);
171+
}
166172
}
167173
}
168174
}
@@ -171,23 +177,43 @@ void picohash_delete(picohash_table* hash_table, int delete_key_too)
171177
free(hash_table);
172178
}
173179

174-
uint64_t picohash_hash_mix(uint64_t hash, uint64_t h2)
175-
{
176-
h2 ^= (hash << 17) ^ (hash >> 37);
177-
hash ^= ((h2 << 31) ^ (h2 >> 17));
178-
179-
return hash;
180-
}
181-
182-
uint64_t picohash_bytes(const uint8_t* key, uint32_t length)
180+
uint64_t picohash_bytes(const uint8_t* bytes, size_t length, const uint8_t* hash_seed)
183181
{
184-
uint64_t hash = 0xDEADBEEF;
182+
uint64_t hash =
183+
((uint64_t)hash_seed[8]) +
184+
(((uint64_t)hash_seed[9]) << 8) +
185+
(((uint64_t)hash_seed[10]) << 16) +
186+
(((uint64_t)hash_seed[11]) << 24) +
187+
(((uint64_t)hash_seed[12]) << 32) +
188+
(((uint64_t)hash_seed[13]) << 40) +
189+
(((uint64_t)hash_seed[14]) << 48) +
190+
(((uint64_t)hash_seed[15]) << 56);
191+
int rotate = 11;
185192

186193
for (uint32_t i = 0; i < length; i++) {
187-
hash ^= key[i];
188-
hash ^= ((hash << 31) ^ (hash >> 17));
194+
hash ^= bytes[i];
195+
hash ^= hash_seed[i & 15];
196+
hash ^= (hash << 8);
197+
hash += (hash >> rotate);
198+
rotate = (int)(hash & 31) + 11;
189199
}
190-
200+
hash ^= (hash >> rotate);
191201
return hash;
192202
}
193203

204+
uint64_t picohash_siphash(const uint8_t* bytes, size_t length, const uint8_t* hash_seed)
205+
{
206+
uint8_t sip_out[8];
207+
uint64_t hash;
208+
(void)siphash(bytes, length, hash_seed, sip_out, 8);
209+
hash =
210+
(uint64_t)sip_out[0] +
211+
(((uint64_t)sip_out[1]) << 8) +
212+
(((uint64_t)sip_out[2]) << 16) +
213+
(((uint64_t)sip_out[3]) << 24) +
214+
(((uint64_t)sip_out[4]) << 32) +
215+
(((uint64_t)sip_out[5]) << 40) +
216+
(((uint64_t)sip_out[6]) << 48) +
217+
(((uint64_t)sip_out[7]) << 56);
218+
return hash;
219+
}

picoquic/picohash.h

Lines changed: 8 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -44,19 +44,21 @@ typedef struct picohash_table {
4444
picohash_item** hash_bin;
4545
size_t nb_bin;
4646
size_t count;
47-
uint64_t (*picohash_hash)(const void*);
47+
const uint8_t* hash_seed;
48+
uint64_t (*picohash_hash)(const void*, const uint8_t*);
4849
int (*picohash_compare)(const void*, const void*);
4950
picohash_item* (*picohash_key_to_item)(const void*);
5051
} picohash_table;
5152

5253
picohash_table* picohash_create(size_t nb_bin,
53-
uint64_t (*picohash_hash)(const void*),
54+
uint64_t (*picohash_hash)(const void*, const uint8_t*),
5455
int (*picohash_compute)(const void*, const void*));
5556

5657
picohash_table* picohash_create_ex(size_t nb_bin,
57-
uint64_t(*picohash_hash)(const void*),
58+
uint64_t(*picohash_hash)(const void*, const uint8_t*),
5859
int (*picohash_compare)(const void*, const void*),
59-
picohash_item* (*picohash_key_to_item)(const void*));
60+
picohash_item* (*picohash_key_to_item)(const void*),
61+
const uint8_t* hash_seed);
6062

6163
picohash_item* picohash_retrieve(picohash_table* hash_table, const void* key);
6264

@@ -68,9 +70,9 @@ void picohash_delete_key(picohash_table* hash_table, void* key, int delete_key_t
6870

6971
void picohash_delete(picohash_table* hash_table, int delete_key_too);
7072

71-
uint64_t picohash_hash_mix(uint64_t hash, uint64_t h2);
73+
uint64_t picohash_bytes(const uint8_t* key, size_t length, const uint8_t* hash_seed);
7274

73-
uint64_t picohash_bytes(const uint8_t* key, uint32_t length);
75+
uint64_t picohash_siphash(const uint8_t* bytes, size_t length, const uint8_t* hash_seed);
7476

7577
#ifdef __cplusplus
7678
}

picoquic/picoquic.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,7 @@
4040
extern "C" {
4141
#endif
4242

43-
#define PICOQUIC_VERSION "1.1.30.2"
43+
#define PICOQUIC_VERSION "1.1.31.0"
4444
#define PICOQUIC_ERROR_CLASS 0x400
4545
#define PICOQUIC_ERROR_DUPLICATE (PICOQUIC_ERROR_CLASS + 1)
4646
#define PICOQUIC_ERROR_AEAD_CHECK (PICOQUIC_ERROR_CLASS + 3)

picoquic/picoquic.vcxproj

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -175,6 +175,7 @@
175175
<ClCompile Include="sender.c" />
176176
<ClCompile Include="bbr.c" />
177177
<ClCompile Include="sim_link.c" />
178+
<ClCompile Include="siphash.c" />
178179
<ClCompile Include="sockloop.c" />
179180
<ClCompile Include="spinbit.c" />
180181
<ClCompile Include="ticket_store.c" />

picoquic/picoquic.vcxproj.filters

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -138,6 +138,9 @@
138138
<ClCompile Include="pacing.c">
139139
<Filter>Source Files</Filter>
140140
</ClCompile>
141+
<ClCompile Include="siphash.c">
142+
<Filter>Source Files</Filter>
143+
</ClCompile>
141144
</ItemGroup>
142145
<ItemGroup>
143146
<ClInclude Include="picoquic.h">

picoquic/picoquic_internal.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -613,7 +613,7 @@ typedef struct st_picoquic_quic_t {
613613
uint8_t reset_seed[PICOQUIC_RESET_SECRET_SIZE];
614614
uint8_t retry_seed[PICOQUIC_RETRY_SECRET_SIZE];
615615
uint64_t* p_simulated_time;
616-
uint8_t hash_seed[8];
616+
uint8_t hash_seed[16];
617617
char const* ticket_file_name;
618618
char const* token_file_name;
619619
picoquic_stored_ticket_t * p_first_ticket;

picoquic/picoquic_utils.h

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -90,9 +90,10 @@ uint8_t picoquic_format_connection_id(uint8_t* bytes, size_t bytes_max, picoquic
9090
uint8_t picoquic_parse_connection_id(const uint8_t* bytes, uint8_t len, picoquic_connection_id_t *cnx_id);
9191
int picoquic_is_connection_id_null(const picoquic_connection_id_t * cnx_id);
9292
int picoquic_compare_connection_id(const picoquic_connection_id_t * cnx_id1, const picoquic_connection_id_t * cnx_id2);
93-
uint64_t picoquic_connection_id_hash(const picoquic_connection_id_t * cid);
93+
uint64_t picoquic_connection_id_hash(const picoquic_connection_id_t * cid, const uint8_t * hash_seed);
9494
uint64_t picoquic_val64_connection_id(picoquic_connection_id_t cnx_id);
95-
uint64_t picoquic_hash_addr(const struct sockaddr* addr);
95+
size_t picoquic_hash_addr_bytes(const struct sockaddr* addr, uint8_t* bytes);
96+
uint64_t picoquic_hash_addr(const struct sockaddr* addr, const uint8_t* hash_seed);
9697
size_t picoquic_parse_hexa(char const* hex_input, size_t input_length, uint8_t* bin_output, size_t output_max);
9798
uint8_t picoquic_parse_connection_id_hexa(char const * hex_input, size_t input_length, picoquic_connection_id_t * cnx_id);
9899
int picoquic_print_connection_id_hexa(char* buf, size_t buf_len, const picoquic_connection_id_t* cnxid);

0 commit comments

Comments
 (0)