GNUnet  0.20.0
ibf.c
Go to the documentation of this file.
1 /*
2  This file is part of GNUnet
3  Copyright (C) 2012 GNUnet e.V.
4 
5  GNUnet is free software: you can redistribute it and/or modify it
6  under the terms of the GNU Affero General Public License as published
7  by the Free Software Foundation, either version 3 of the License,
8  or (at your option) any later version.
9 
10  GNUnet is distributed in the hope that it will be useful, but
11  WITHOUT ANY WARRANTY; without even the implied warranty of
12  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13  Affero General Public License for more details.
14 
15  You should have received a copy of the GNU Affero General Public License
16  along with this program. If not, see <http://www.gnu.org/licenses/>.
17 
18  SPDX-License-Identifier: AGPL3.0-or-later
19  */
20 
28 #include "platform.h"
29 #include "ibf.h"
30 #include "gnunet_util_lib.h"
31 #define LOG(kind, ...) GNUNET_log_from (kind, "setu", __VA_ARGS__)
32 
33 
38 #define IBF_KEY_HASH_VAL(k) (GNUNET_CRYPTO_crc32_n (&(k), sizeof(struct \
39  IBF_KeyHash)))
40 
47 struct IBF_Key
48 ibf_key_from_hashcode (const struct GNUNET_HashCode *hash)
49 {
50  return *(struct IBF_Key *) hash;
51 }
52 
53 
61 void
63  struct GNUNET_HashCode *dst)
64 {
65  struct IBF_Key *p;
66  unsigned int i;
67  const unsigned int keys_per_hashcode = sizeof(struct GNUNET_HashCode)
68  / sizeof(struct IBF_Key);
69 
70  p = (struct IBF_Key *) dst;
71  for (i = 0; i < keys_per_hashcode; i++)
72  *p++ = key;
73 }
74 
75 
83 struct InvertibleBloomFilter *
84 ibf_create (uint32_t size, uint8_t hash_num)
85 {
86  struct InvertibleBloomFilter *ibf;
87 
88  GNUNET_assert (0 != size);
89 
90  ibf = GNUNET_new (struct InvertibleBloomFilter);
91  ibf->count = GNUNET_malloc_large (size * sizeof(uint64_t));
92  if (NULL == ibf->count)
93  {
94  GNUNET_free (ibf);
95  return NULL;
96  }
97  ibf->key_sum = GNUNET_malloc_large (size * sizeof(struct IBF_Key));
98  if (NULL == ibf->key_sum)
99  {
100  GNUNET_free (ibf->count);
101  GNUNET_free (ibf);
102  return NULL;
103  }
104  ibf->key_hash_sum = GNUNET_malloc_large (size * sizeof(struct IBF_KeyHash));
105  if (NULL == ibf->key_hash_sum)
106  {
107  GNUNET_free (ibf->key_sum);
108  GNUNET_free (ibf->count);
109  GNUNET_free (ibf);
110  return NULL;
111  }
112  ibf->size = size;
113  ibf->hash_num = hash_num;
114 
115  return ibf;
116 }
117 
118 
122 static void
124  struct IBF_Key key,
125  int *dst)
126 {
127  uint32_t filled;
128  uint32_t i;
129  uint32_t bucket;
130 
131  bucket = GNUNET_CRYPTO_crc32_n (&key, sizeof key);
132  for (i = 0, filled = 0; filled < ibf->hash_num; i++)
133  {
134  uint64_t x;
135 
136  for (unsigned int j = 0; j < filled; j++)
137  if (dst[j] == bucket % ibf->size)
138  goto try_next;
139  dst[filled++] = bucket % ibf->size;
140 try_next:
141  x = ((uint64_t) bucket << 32) | i;
142  bucket = GNUNET_CRYPTO_crc32_n (&x, sizeof x);
143  }
144 }
145 
146 
147 static void
149  struct IBF_Key key,
150  const int *buckets,
151  int side)
152 {
153  for (unsigned int i = 0; i < ibf->hash_num; i++)
154  {
155  const int bucket = buckets[i];
156 
157  ibf->count[bucket].count_val += side;
158  ibf->key_sum[bucket].key_val ^= key.key_val;
159  ibf->key_hash_sum[bucket].key_hash_val
160  ^= IBF_KEY_HASH_VAL (key);
161  }
162 }
163 
164 
171 void
173  struct IBF_Key key)
174 {
175  int buckets[ibf->hash_num];
176 
177  GNUNET_assert (ibf->hash_num <= ibf->size);
178  ibf_get_indices (ibf, key, buckets);
179  ibf_insert_into (ibf, key, buckets, 1);
180 }
181 
182 
189 void
191  struct IBF_Key key)
192 {
193  int buckets[ibf->hash_num];
194 
195  GNUNET_assert (ibf->hash_num <= ibf->size);
196  ibf_get_indices (ibf, key, buckets);
197  ibf_insert_into (ibf, key, buckets, -1);
198 }
199 
200 
204 static int
206 {
207  for (uint32_t i = 0; i < ibf->size; i++)
208  {
209  if (0 != ibf->count[i].count_val)
210  return GNUNET_NO;
211  if (0 != ibf->key_hash_sum[i].key_hash_val)
212  return GNUNET_NO;
213  if (0 != ibf->key_sum[i].key_val)
214  return GNUNET_NO;
215  }
216  return GNUNET_YES;
217 }
218 
219 
220 int
222  int *ret_side,
223  struct IBF_Key *ret_id)
224 {
225  struct IBF_KeyHash hash;
226  int buckets[ibf->hash_num];
227 
228  for (uint32_t i = 0; i < ibf->size; i++)
229  {
230  int hit;
231 
232  /* we can only decode from pure buckets */
233  if ( (1 != ibf->count[i].count_val) &&
234  (-1 != ibf->count[i].count_val) )
235  continue;
236 
237  hash.key_hash_val = IBF_KEY_HASH_VAL (ibf->key_sum[i]);
238 
239  /* test if the hash matches the key */
240  if (hash.key_hash_val != ibf->key_hash_sum[i].key_hash_val)
241  continue;
242 
243  /* test if key in bucket hits its own location,
244  * if not, the key hash was subject to collision */
245  hit = GNUNET_NO;
246  ibf_get_indices (ibf, ibf->key_sum[i], buckets);
247  for (int j = 0; j < ibf->hash_num; j++)
248  if (buckets[j] == i)
249  hit = GNUNET_YES;
250 
251  if (GNUNET_NO == hit)
252  continue;
253 
254  if (1 == ibf->count[i].count_val)
255  {
256  ibf->remote_decoded_count++;
257  }
258  else
259  {
260  ibf->local_decoded_count++;
261  }
262 
263 
264  if (NULL != ret_side)
265  *ret_side = ibf->count[i].count_val;
266  if (NULL != ret_id)
267  *ret_id = ibf->key_sum[i];
268 
269  /* insert on the opposite side, effectively removing the element */
270  ibf_insert_into (ibf, ibf->key_sum[i], buckets, -ibf->count[i].count_val);
271 
272  return GNUNET_YES;
273  }
274 
275  if (GNUNET_YES == ibf_is_empty (ibf))
276  return GNUNET_NO;
277  return GNUNET_SYSERR;
278 }
279 
280 
286 uint8_t
288 {
289  long long max_counter = 0;
290  for (uint64_t i = 0; i < ibf->size; i++)
291  {
292  if (ibf->count[i].count_val > max_counter)
293  {
294  max_counter = ibf->count[i].count_val;
295  }
296  }
297  return 64 - __builtin_clzll (max_counter);
298 }
299 
300 
311 void
313  uint32_t start,
314  uint64_t count,
315  void *buf,
316  uint8_t counter_max_length)
317 {
318  struct IBF_Key *key_dst;
319  struct IBF_KeyHash *key_hash_dst;
320 
321  GNUNET_assert (start + count <= ibf->size);
322 
323  /* copy keys */
324  key_dst = (struct IBF_Key *) buf;
325  GNUNET_memcpy (key_dst,
326  ibf->key_sum + start,
327  count * sizeof(*key_dst));
328  key_dst += count;
329  /* copy key hashes */
330  key_hash_dst = (struct IBF_KeyHash *) key_dst;
331  GNUNET_memcpy (key_hash_dst,
332  ibf->key_hash_sum + start,
333  count * sizeof(*key_hash_dst));
334  key_hash_dst += count;
335 
336  /* pack and copy counter */
337  pack_counter (ibf,
338  start,
339  count,
340  (uint8_t *) key_hash_dst,
341  counter_max_length);
342 
343 
344 }
345 
346 
347 
348 void
350  uint32_t start,
351  uint64_t count,
352  uint8_t *buf,
353  uint8_t counter_max_length)
354 {
355  uint8_t store_size = 0;
356  uint8_t store = 0;
357  uint16_t byte_ctr = 0;
358 
362  for (uint64_t i = start; i< (count + start);)
363  {
364  uint64_t count_val_to_write = ibf->count[i].count_val;
365  uint8_t count_len_to_write = counter_max_length;
366 
370  while ((count_len_to_write + store_size) >= 8)
371  {
372  uint8_t bit_shift = 0;
373 
378  if ((store_size > 0) || (count_len_to_write > 8))
379  {
380  uint8_t bit_unused = 8 - store_size;
381  bit_shift = count_len_to_write - bit_unused;
382  store = store << bit_unused;
383  }
384 
385  buf[byte_ctr] = ((count_val_to_write >> bit_shift) | store) & 0xFF;
386  byte_ctr++;
387  count_len_to_write -= (8 - store_size);
388  count_val_to_write = count_val_to_write & ((1ULL <<
389  count_len_to_write) - 1);
390  store = 0;
391  store_size = 0;
392  }
393  store = (store << count_len_to_write) | count_val_to_write;
394  store_size = store_size + count_len_to_write;
395  count_len_to_write = 0;
396  i++;
397  }
398 
402  if (store_size > 0)
403  {
404  buf[byte_ctr] = store << (8 - store_size);
405  byte_ctr++;
406  }
407 
408 }
409 
410 
411 
412 void
414  uint32_t start,
415  uint64_t count,
416  uint8_t *buf,
417  uint8_t counter_max_length)
418 {
419  uint64_t ibf_counter_ctr = 0;
420  uint64_t store = 0;
421  uint64_t store_bit_ctr = 0;
422  uint64_t byte_ctr = 0;
423 
427  while (true)
428  {
429  uint8_t byte_read = buf[byte_ctr];
430  uint8_t bit_to_read_left = 8;
431  byte_ctr++;
432 
436  while (true)
437  {
441  if (ibf_counter_ctr > (count - 1))
442  return;
443 
444  /*
445  * Unpack the counter
446  */
447  if ((store_bit_ctr + bit_to_read_left) >= counter_max_length)
448  {
449  uint8_t bytes_used = counter_max_length - store_bit_ctr;
450  if (store_bit_ctr > 0)
451  {
452  store = store << bytes_used;
453  }
454 
455  uint8_t bytes_to_shift = bit_to_read_left - bytes_used;
456  uint64_t counter_part = byte_read >> bytes_to_shift;
457  store = store | counter_part;
458  ibf->count[ibf_counter_ctr + start].count_val = store;
459  byte_read = byte_read & ((1 << bytes_to_shift) - 1);
460  bit_to_read_left -= bytes_used;
461  ibf_counter_ctr++;
462  store = 0;
463  store_bit_ctr = 0;
464  }
465  else
466  {
467  store_bit_ctr += bit_to_read_left;
468  if (0 == store)
469  {
470  store = byte_read;
471  }
472  else
473  {
474  store = store << bit_to_read_left;
475  store = store | byte_read;
476  }
477  break;
478  }
479  }
480  }
481 }
482 
483 
493 void
494 ibf_read_slice (const void *buf,
495  uint32_t start,
496  uint64_t count,
497  struct InvertibleBloomFilter *ibf,
498  uint8_t counter_max_length)
499 {
500  struct IBF_Key *key_src;
501  struct IBF_KeyHash *key_hash_src;
502  struct IBF_Count *count_src;
503 
504  GNUNET_assert (count > 0);
505  GNUNET_assert (start + count <= ibf->size);
506 
507  /* copy keys */
508  key_src = (struct IBF_Key *) buf;
509  GNUNET_memcpy (ibf->key_sum + start,
510  key_src,
511  count * sizeof *key_src);
512  key_src += count;
513  /* copy key hashes */
514  key_hash_src = (struct IBF_KeyHash *) key_src;
516  key_hash_src,
517  count * sizeof *key_hash_src);
518  key_hash_src += count;
519 
520  /* copy and unpack counts */
521  count_src = (struct IBF_Count *) key_hash_src;
522  unpack_counter (ibf,start,count,(uint8_t *) count_src,counter_max_length);
523 }
524 
525 
533 void
535  const struct InvertibleBloomFilter *ibf2)
536 {
537  GNUNET_assert (ibf1->size == ibf2->size);
538  GNUNET_assert (ibf1->hash_num == ibf2->hash_num);
539 
540  for (uint32_t i = 0; i < ibf1->size; i++)
541  {
542  ibf1->count[i].count_val -= ibf2->count[i].count_val;
543  ibf1->key_hash_sum[i].key_hash_val ^= ibf2->key_hash_sum[i].key_hash_val;
544  ibf1->key_sum[i].key_val ^= ibf2->key_sum[i].key_val;
545  }
546 }
547 
548 
554 struct InvertibleBloomFilter *
555 ibf_dup (const struct InvertibleBloomFilter *ibf)
556 {
557  struct InvertibleBloomFilter *copy;
558 
559  copy = GNUNET_malloc (sizeof *copy);
560  copy->hash_num = ibf->hash_num;
561  copy->size = ibf->size;
563  ibf->size * sizeof(struct IBF_KeyHash));
564  copy->key_sum = GNUNET_memdup (ibf->key_sum,
565  ibf->size * sizeof(struct IBF_Key));
566  copy->count = GNUNET_memdup (ibf->count,
567  ibf->size * sizeof(struct IBF_Count));
568  return copy;
569 }
570 
571 
578 void
580 {
581  GNUNET_free (ibf->key_sum);
582  GNUNET_free (ibf->key_hash_sum);
583  GNUNET_free (ibf->count);
584  GNUNET_free (ibf);
585 }
static int start
Set if we are to start default services (including ARM).
Definition: gnunet-arm.c:39
struct GNUNET_HashCode key
The key used in the DHT.
static char buf[2048]
static unsigned int hash_num
static struct GNUNET_OS_Process * p
Helper process we started.
Definition: gnunet-uri.c:38
int32_t GNUNET_CRYPTO_crc32_n(const void *buf, size_t len)
Compute the CRC32 checksum for the first len bytes of the buffer.
Definition: crypto_crc.c:99
#define GNUNET_memcpy(dst, src, n)
Call memcpy() but check for n being 0 first.
@ GNUNET_YES
@ GNUNET_NO
@ GNUNET_SYSERR
#define GNUNET_assert(cond)
Use this for fatal errors that cannot be handled.
#define GNUNET_malloc_large(size)
Wrapper around malloc.
#define GNUNET_new(type)
Allocate a struct or union of the given type.
#define GNUNET_malloc(size)
Wrapper around malloc.
#define GNUNET_free(ptr)
Wrapper around free.
#define GNUNET_memdup(buf, size)
Allocate and initialize a block of memory.
static unsigned int size
Size of the "table".
Definition: peer.c:68
void ibf_subtract(struct InvertibleBloomFilter *ibf1, const struct InvertibleBloomFilter *ibf2)
Subtract ibf2 from ibf1, storing the result in ibf1.
Definition: ibf.c:357
int ibf_decode(struct InvertibleBloomFilter *ibf, int *ret_side, struct IBF_Key *ret_id)
Decode and remove an element from the IBF, if possible.
Definition: ibf.c:229
void ibf_read_slice(const void *buf, uint32_t start, uint32_t count, struct InvertibleBloomFilter *ibf)
Read buckets from a buffer into an ibf.
Definition: ibf.c:324
struct IBF_Key ibf_key_from_hashcode(const struct GNUNET_HashCode *hash)
Create a key from a hashcode.
Definition: ibf.c:44
void ibf_write_slice(const struct InvertibleBloomFilter *ibf, uint32_t start, uint32_t count, void *buf)
Write buckets from an ibf to a buffer.
Definition: ibf.c:291
struct InvertibleBloomFilter * ibf_create(uint32_t size, uint8_t hash_num)
Create an invertible bloom filter.
Definition: ibf.c:80
void ibf_hashcode_from_key(struct IBF_Key key, struct GNUNET_HashCode *dst)
Create a hashcode from a key, by replicating the key until the hascode is filled.
Definition: ibf.c:58
void ibf_insert(struct InvertibleBloomFilter *ibf, struct IBF_Key key)
Insert a key into an IBF.
Definition: ibf.c:168
struct InvertibleBloomFilter * ibf_dup(const struct InvertibleBloomFilter *ibf)
Create a copy of an IBF, the copy has to be destroyed properly.
Definition: ibf.c:380
void ibf_remove(struct InvertibleBloomFilter *ibf, struct IBF_Key key)
Remove a key from an IBF.
Definition: ibf.c:185
void ibf_destroy(struct InvertibleBloomFilter *ibf)
Destroy all resources associated with the invertible bloom filter.
Definition: ibf.c:404
uint8_t ibf_get_max_counter(struct InvertibleBloomFilter *ibf)
Returns the minimal bytes needed to store the counter of the IBF.
Definition: ibf.c:287
void unpack_counter(const struct InvertibleBloomFilter *ibf, uint32_t start, uint64_t count, uint8_t *buf, uint8_t counter_max_length)
Unpacks the counter to transmit only the smallest possible amount of bytes and preventing overflow of...
Definition: ibf.c:413
#define IBF_KEY_HASH_VAL(k)
Compute the key's hash from the key.
Definition: ibf.c:38
static void ibf_get_indices(const struct InvertibleBloomFilter *ibf, struct IBF_Key key, int *dst)
Store unique bucket indices for the specified key in dst.
Definition: ibf.c:123
void pack_counter(const struct InvertibleBloomFilter *ibf, uint32_t start, uint64_t count, uint8_t *buf, uint8_t counter_max_length)
Packs the counter to transmit only the smallest possible amount of bytes and preventing overflow of t...
Definition: ibf.c:349
static void ibf_insert_into(struct InvertibleBloomFilter *ibf, struct IBF_Key key, const int *buckets, int side)
Definition: ibf.c:148
static int ibf_is_empty(struct InvertibleBloomFilter *ibf)
Test is the IBF is empty, i.e.
Definition: ibf.c:205
A 512-bit hashcode.
Type of the count field of IBF buckets.
Definition: ibf.h:64
int8_t count_val
Definition: ibf.h:65
Hash of an IBF key.
Definition: ibf.h:55
uint32_t key_hash_val
Definition: ibf.h:56
Keys that can be inserted into and removed from an IBF.
Definition: ibf.h:46
uint64_t key_val
Definition: ibf.h:47
Invertible bloom filter (IBF).
Definition: ibf.h:83
int remote_decoded_count
If an IBF is decoded this count stores how many elements are on the remote site.
Definition: ibf.h:108
int local_decoded_count
If an IBF is decoded this count stores how many elements are on the local site.
Definition: ibf.h:101
struct IBF_KeyHash * key_hash_sum
Xor sums of the hashes of the keys of inserted elements.
Definition: ibf.h:105
uint32_t size
How many cells does this IBF have?
Definition: ibf.h:87
struct IBF_Count * count
How many times has a bucket been hit? Can be negative, as a result of IBF subtraction.
Definition: ibf.h:112
struct IBF_Key * key_sum
Xor sums of the elements' keys, used to identify the elements.
Definition: ibf.h:99
uint8_t hash_num
In how many cells do we hash one element? Usually 4 or 3.
Definition: ibf.h:93