diff options
author | Nick Mathewson <nickm@torproject.org> | 2018-06-26 13:18:23 -0400 |
---|---|---|
committer | Nick Mathewson <nickm@torproject.org> | 2018-06-26 13:27:23 -0400 |
commit | bf89278c799e718a3b6c1ea139a6069db054ac09 (patch) | |
tree | addcdf08f01a3aff7645ea42606d2cc7ed5e1a25 /src/lib/container/bloomfilt.c | |
parent | 860b9a991879c5be2b32cf98766adf5fdd349d41 (diff) | |
download | tor-bf89278c799e718a3b6c1ea139a6069db054ac09.tar.gz tor-bf89278c799e718a3b6c1ea139a6069db054ac09.zip |
Refactor bloom filter logic not to be digest-specific.
Now the address-set code and the digest-set code share the same
backend.
Closes ticket 26510
Diffstat (limited to 'src/lib/container/bloomfilt.c')
-rw-r--r-- | src/lib/container/bloomfilt.c | 79 |
1 files changed, 73 insertions, 6 deletions
diff --git a/src/lib/container/bloomfilt.c b/src/lib/container/bloomfilt.c index 2133c280a5..1cab817e18 100644 --- a/src/lib/container/bloomfilt.c +++ b/src/lib/container/bloomfilt.c @@ -9,14 +9,75 @@ **/ #include <stdlib.h> + #include "lib/malloc/util_malloc.h" #include "lib/container/bloomfilt.h" #include "lib/intmath/bits.h" +#include "lib/log/util_bug.h" +#include "siphash.h" + +/** How many bloom-filter bits we set per address. This is twice the + * BLOOMFILT_N_HASHES value, since we split the siphash output into two 32-bit + * values. */ +#define N_BITS_PER_ITEM (BLOOMFILT_N_HASHES * 2) + +struct bloomfilt_t { + /** siphash keys to make BLOOMFILT_N_HASHES independent hashes for each + * items. */ + struct sipkey key[BLOOMFILT_N_HASHES]; + bloomfilt_hash_fn hashfn; /**< Function used to generate hashes */ + uint32_t mask; /**< One less than the number of bits in <b>ba</b>; always + * one less than a power of two. */ + bitarray_t *ba; /**< A bit array to implement the Bloom filter. */ +}; + +#define BIT(set, n) ((n) & (set)->mask) + +/** Add the element <b>item</b> to <b>set</b>. */ +void +bloomfilt_add(bloomfilt_t *set, + const void *item) +{ + int i; + for (i = 0; i < BLOOMFILT_N_HASHES; ++i) { + uint64_t h = set->hashfn(&set->key[i], item); + uint32_t high_bits = (uint32_t)(h >> 32); + uint32_t low_bits = (uint32_t)(h); + bitarray_set(set->ba, BIT(set, high_bits)); + bitarray_set(set->ba, BIT(set, low_bits)); + } +} -/** Return a newly allocated digestset_t, optimized to hold a total of - * <b>max_elements</b> digests with a reasonably low false positive weight. */ -digestset_t * -digestset_new(int max_elements) +/** If <b>item</b> is in <b>set</b>, return nonzero. Otherwise, + * <em>probably</em> return zero. */ +int +bloomfilt_probably_contains(const bloomfilt_t *set, + const void *item) +{ + int i, matches = 0; + for (i = 0; i < BLOOMFILT_N_HASHES; ++i) { + uint64_t h = set->hashfn(&set->key[i], item); + uint32_t high_bits = (uint32_t)(h >> 32); + uint32_t low_bits = (uint32_t)(h); + // Note that !! is necessary here, since bitarray_is_set does not + // necessarily return 1 on true. + matches += !! bitarray_is_set(set->ba, BIT(set, high_bits)); + matches += !! bitarray_is_set(set->ba, BIT(set, low_bits)); + } + return matches == N_BITS_PER_ITEM; +} + +/** Return a newly allocated bloomfilt_t, optimized to hold a total of + * <b>max_elements</b> elements with a reasonably low false positive weight. + * + * Uses the siphash-based function <b>hashfn</b> to compute hard-to-collide + * functions of the items, and the key material <b>random_key</b> to + * key the hash. There must be BLOOMFILT_KEY_LEN bytes in the supplied key. + **/ +bloomfilt_t * +bloomfilt_new(int max_elements, + bloomfilt_hash_fn hashfn, + const uint8_t *random_key) { /* The probability of false positives is about P=(1 - exp(-kn/m))^k, where k * is the number of hash functions per entry, m is the bits in the array, @@ -29,15 +90,21 @@ digestset_new(int max_elements) * conserve CPU, and k==13 is pretty big. */ int n_bits = 1u << (tor_log2(max_elements)+5); - digestset_t *r = tor_malloc(sizeof(digestset_t)); + bloomfilt_t *r = tor_malloc(sizeof(bloomfilt_t)); r->mask = n_bits - 1; r->ba = bitarray_init_zero(n_bits); + + tor_assert(sizeof(r->key) == BLOOMFILT_KEY_LEN); + memcpy(r->key, random_key, sizeof(r->key)); + + r->hashfn = hashfn; + return r; } /** Free all storage held in <b>set</b>. */ void -digestset_free_(digestset_t *set) +bloomfilt_free_(bloomfilt_t *set) { if (!set) return; |