summaryrefslogtreecommitdiff
path: root/src/lib/container/bloomfilt.c
diff options
context:
space:
mode:
authorNick Mathewson <nickm@torproject.org>2018-06-26 13:18:23 -0400
committerNick Mathewson <nickm@torproject.org>2018-06-26 13:27:23 -0400
commitbf89278c799e718a3b6c1ea139a6069db054ac09 (patch)
treeaddcdf08f01a3aff7645ea42606d2cc7ed5e1a25 /src/lib/container/bloomfilt.c
parent860b9a991879c5be2b32cf98766adf5fdd349d41 (diff)
downloadtor-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.c79
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;