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
29 #include "gnunet_common.h"
36 struct PureCells *next;
37 struct PureCells *prev;
40 struct InvertibleBloomFilter
43 * How many cells does this IBF have?
48 * In how many cells do we hash one element?
54 * Salt for mingling hashes
59 * How many times has a bucket been hit?
60 * Can be negative, as a result of IBF subtraction.
65 * xor sums of the elements' hash codes, used to identify the elements.
67 GNUNET_HashCode *id_sum;
70 * xor sums of the "hash of the hash".
72 GNUNET_HashCode *hash_sum;
74 struct PureCells *pure_head;
75 struct PureCells *pure_tail;
78 * GNUNET_YES: fresh list is deprecated
79 * GNUNET_NO: fresh list is up to date
86 * Create an invertible bloom filter.
88 struct InvertibleBloomFilter *
89 ibf_create(int size, int hash_num)
91 struct InvertibleBloomFilter *ibf;
93 ibf = GNUNET_malloc (sizeof (struct InvertibleBloomFilter));
94 ibf->count = GNUNET_malloc (size * sizeof uint8_t);
95 ibf->id_sum = GNUNET_malloc (size * sizeof (struct GNUNET_HashCode));
96 ibf->hash_sum = GNUNET_malloc (size * sizeof (struct GNUNET_HashCode));
98 ibf->hash_num = hash_num;
103 * Insert an element into an IBF.
106 ibf_insert (struct InvertibleBloomFilter *ibf, struct GNUNET_HashCode *id)
108 struct GNUNET_HashCode key;
109 struct GNUNET_HashCode id_hash;
113 GNUNET_hash (id, sizeof (struct GNUNET_HashCode), &id_hash);
115 for (i = 0; i < ibf->hash_num; i++)
119 if ((i != 0) && (i % 16) == 0)
121 GNUNET_hash (&key, sizeof (struct GNUNET_HashCode), &key);
123 bucket = hash.bits[i%16] % ibf->size;
125 /* count<0 can happen after ibf subtraction, but then no insert should be done */
126 GNUNET_assert (ibf->count[bucket] >= 0);
128 ibf->count[bucket]++;
130 for (j=0; j < 16; j++)
132 ibf->id_sum.bits[j] ^= &id;
133 ibf->hash_sum.bits[j] ^= &id_hash;
141 * Update the linked list of pure cells, if not fresh anymore
144 update_pure (struct InvertibleBloomFilter *ibf)
146 if (GNUNET_YES == ibf->pure_fresh)
151 ibf->pure_fresh = GNUNET_YES;
155 * Decode and remove an element from the IBF, if possible.
157 * @param ibf the invertible bloom filter to decode
158 * @param ret_id the hash code of the decoded element, if successful
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 resides in an IBF
161 * that was previously subtracted from.
162 * @return GNUNET_YES if decoding an element was successful, GNUNET_NO if the IBF is empty,
163 * GNUNET_SYSERR if the decoding has faile
166 ibf_decode (struct InvertibleBloomFilter *ibf, int *ret_side, struct GNUNET_HashCode *ret_id)
168 struct GNUNET_HashCode hash;
169 struct PureCells *pure;
172 GNUNET_assert (NULL != ibf);
173 GNUNET_assert (NULL != red_id);
174 GNUNET_assert (NULL != side);
178 pure = ibf->pure_head;
179 ibf->pure_head = pure->next;
184 for (i = 0; i < ibf->size; i++)
187 if (0 != ibf->count[i])
188 return GNUNET_SYSERR;
189 for (j = 0; j < 16; ++j)
190 if ((0 != ibf->hash_sum[i].bits[j]) || (0 != ibf->id_sum[i].bits[j]))
191 return GNUNET_SYSERR;
196 GNUNET_CRYPTO_hash (ibf->id_sum[pure->idx], sizeof (struct GNUNET_HashCode), &hash);
198 if (0 == memcmp (&hash, ibf->hash_sum[pure->idx]))
200 struct GNUNET_HashCode key;
203 *ret_side = ibf->count[pure->index];
204 *ret_id = ibf->id_sum[pure->index];
206 key = *ibf->id_sum[pure->index];
208 /* delete the item from all buckets */
209 for (i = 0; i < ibf->hash_num; i++)
213 if ((i != 0) && (i % 16) == 0)
215 GNUNET_hash (&key, sizeof (struct GNUNET_HashCode), &key);
217 bucket = hash.bits[i%16] % ibf->size;
219 ibf->count[bucket] -= count;
221 for (j=0; j < 16; j++)
223 ibf->id_sum.bits[j] ^= &id;
224 ibf->hash_sum.bits[j] ^= &id_hash;
228 return GNUNET_SYSERR;
234 * Subtract ibf2 from ibf1, storing the result in ibf1.
235 * The two IBF's must have the same parameters size and hash_num.
237 * @return a newly allocated invertible bloom filter
240 ibf_subtract (struct InvertibleBloomFilter *ibf1, struct InvertibleBloomFilter *ibf2)