2 This file is part of GNUnet
3 (C) 2012 Christian Grothoff (and other contributing authors)
5 GNUnet is free software; you can redistribute it and/or modify
6 it under the terms of the GNU General Public License as published
7 by the Free Software Foundation; either version 2, or (at your
8 option) any later version.
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 General Public License for more details.
15 You should have received a copy of the GNU General Public License
16 along with GNUnet; see the file COPYING. If not, write to the
17 Free Software Foundation, Inc., 59 Temple Place - Suite 330,
18 Boston, MA 02111-1307, USA.
23 * @file consensus/ibf.c
24 * @brief implementation of the invertible bloom filter
25 * @author Florian Dold
33 * Create an invertible bloom filter.
35 * @param size number of IBF buckets
36 * @param hash_num number of buckets one element is hashed in
37 * @param salt salt for mingling hashes, different salt may
38 * result in less (or more) collisions
39 * @return the newly created invertible bloom filter
41 struct InvertibleBloomFilter *
42 ibf_create (unsigned int size, unsigned int hash_num, uint32_t salt)
44 struct InvertibleBloomFilter *ibf;
46 ibf = GNUNET_malloc (sizeof (struct InvertibleBloomFilter));
47 ibf->count = GNUNET_malloc (size * sizeof (uint8_t));
48 ibf->id_sum = GNUNET_malloc (size * sizeof (struct GNUNET_HashCode));
49 ibf->hash_sum = GNUNET_malloc (size * sizeof (struct GNUNET_HashCode));
51 ibf->hash_num = hash_num;
59 * Insert an element into an IBF, with either positive or negative sign.
62 * @param id the element's hash code
63 * @param side the sign of side determines the sign of the
67 ibf_insert_on_side (struct InvertibleBloomFilter *ibf,
68 const struct GNUNET_HashCode *key,
71 struct GNUNET_HashCode bucket_indices;
72 struct GNUNET_HashCode key_copy;
73 struct GNUNET_HashCode key_hash;
77 GNUNET_assert ((1 == side) || (-1 == side));
78 GNUNET_assert (NULL != ibf);
81 int used_buckets[ibf->hash_num];
83 /* copy the key, if key and an entry in the IBF alias */
86 bucket_indices = key_copy;
87 GNUNET_CRYPTO_hash (key, sizeof (struct GNUNET_HashCode), &key_hash);
89 for (i = 0; i < ibf->hash_num; i++)
97 GNUNET_CRYPTO_hash (&bucket_indices, sizeof (struct GNUNET_HashCode),
100 bucket = bucket_indices.bits[i%16] % ibf->size;
101 collided = GNUNET_NO;
102 for (j = 0; j < i; j++)
103 if (used_buckets[j] == bucket)
104 collided = GNUNET_YES;
105 if (GNUNET_YES == collided)
107 used_buckets[i] = -1;
110 used_buckets[i] = bucket;
112 ibf->count[bucket] += side;
114 GNUNET_CRYPTO_hash_xor (&key_copy, &ibf->id_sum[bucket],
115 &ibf->id_sum[bucket]);
116 GNUNET_CRYPTO_hash_xor (&key_hash, &ibf->hash_sum[bucket],
117 &ibf->hash_sum[bucket]);
123 * Insert an element into an IBF.
126 * @param id the element's hash code
129 ibf_insert (struct InvertibleBloomFilter *ibf, const struct GNUNET_HashCode *key)
131 ibf_insert_on_side (ibf, key, 1);
135 ibf_is_empty (struct InvertibleBloomFilter *ibf)
138 for (i = 0; i < ibf->size; i++)
141 if (0 != ibf->count[i])
143 for (j = 0; j < 16; ++j)
145 if (0 != ibf->hash_sum[i].bits[j])
147 if (0 != ibf->id_sum[i].bits[j])
156 * Decode and remove an element from the IBF, if possible.
158 * @param ibf the invertible bloom filter to decode
159 * @param side sign of the cell's count where the decoded element came from.
160 * A negative sign indicates that the element was recovered
161 * resides in an IBF that was previously subtracted from.
162 * @param ret_id the hash code of the decoded element, if successful
163 * @return GNUNET_YES if decoding an element was successful,
164 * GNUNET_NO if the IBF is empty,
165 * GNUNET_SYSERR if the decoding has failed
168 ibf_decode (struct InvertibleBloomFilter *ibf,
169 int *ret_side, struct GNUNET_HashCode *ret_id)
171 struct GNUNET_HashCode hash;
174 GNUNET_assert (NULL != ibf);
176 for (i = 0; i < ibf->size; i++)
178 if ((1 != ibf->count[i]) && (-1 != ibf->count[i]))
181 GNUNET_CRYPTO_hash (&ibf->id_sum[i], sizeof (struct GNUNET_HashCode), &hash);
183 if (0 != memcmp (&hash, &ibf->hash_sum[i], sizeof (struct GNUNET_HashCode)))
186 if (NULL != ret_side)
187 *ret_side = ibf->count[i];
189 *ret_id = ibf->id_sum[i];
191 /* insert on the opposite side, effectively removing the element */
192 ibf_insert_on_side (ibf, &ibf->id_sum[i], -ibf->count[i]);
197 if (GNUNET_YES == ibf_is_empty (ibf))
199 return GNUNET_SYSERR;
205 * Subtract ibf2 from ibf1, storing the result in ibf1.
206 * The two IBF's must have the same parameters size and hash_num.
208 * @param ibf1 IBF that is subtracted from
209 * @param ibf2 IBF that will be subtracted from ibf1
212 ibf_subtract (struct InvertibleBloomFilter *ibf1, struct InvertibleBloomFilter *ibf2)
216 GNUNET_assert (ibf1->size == ibf2->size);
217 GNUNET_assert (ibf1->hash_num == ibf2->hash_num);
218 GNUNET_assert (ibf1->salt == ibf2->salt);
220 for (i = 0; i < ibf1->size; i++)
222 ibf1->count[i] -= ibf2->count[i];
223 GNUNET_CRYPTO_hash_xor (&ibf1->id_sum[i], &ibf2->id_sum[i],
225 GNUNET_CRYPTO_hash_xor (&ibf1->hash_sum[i], &ibf2->hash_sum[i],
231 * Create a copy of an IBF, the copy has to be destroyed properly.
233 * @param ibf the IBF to copy
235 struct InvertibleBloomFilter *
236 ibf_dup (struct InvertibleBloomFilter *ibf)
238 struct InvertibleBloomFilter *copy;
239 copy = GNUNET_malloc (sizeof *copy);
240 copy->hash_num = ibf->hash_num;
241 copy->salt = ibf->salt;
242 copy->size = ibf->size;
243 copy->hash_sum = GNUNET_memdup (ibf->hash_sum, ibf->size * sizeof (struct GNUNET_HashCode));
244 copy->id_sum = GNUNET_memdup (ibf->id_sum, ibf->size * sizeof (struct GNUNET_HashCode));
245 copy->count = GNUNET_memdup (ibf->count, ibf->size * sizeof (uint8_t));
250 * Destroy all resources associated with the invertible bloom filter.
251 * No more ibf_*-functions may be called on ibf after calling destroy.
253 * @param ibf the intertible bloom filter to destroy
256 ibf_destroy (struct InvertibleBloomFilter *ibf)
258 GNUNET_free (ibf->hash_sum);
259 GNUNET_free (ibf->id_sum);
260 GNUNET_free (ibf->count);