GNUnet 0.21.1
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
47struct IBF_Key
49{
50 return *(struct IBF_Key *) hash;
51}
52
53
61void
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
84ibf_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
122static 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;
140try_next:
141 x = ((uint64_t) bucket << 32) | i;
142 bucket = GNUNET_CRYPTO_crc32_n (&x, sizeof x);
143 }
144}
145
146
147static 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
161 }
162}
163
164
171void
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
189void
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
204static 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
220int
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 {
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
286uint8_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
311void
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
348void
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
412void
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
493void
494ibf_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;
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
533void
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;
544 ibf1->key_sum[i].key_val ^= ibf2->key_sum[i].key_val;
545 }
546}
547
548
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
578void
580{
581 GNUNET_free (ibf->key_sum);
583 GNUNET_free (ibf->count);
584 GNUNET_free (ibf);
585}
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
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
struct InvertibleBloomFilter * ibf_create(uint32_t size, uint8_t hash_num)
Create an invertible bloom filter.
Definition: ibf.c:80
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
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 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
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