adding a GNUNET_memcmp_priv for constant-time comparing of data; fixes #6152 (modulo...
[oweals/gnunet.git] / src / set / gnunet-set-ibf-profiler.c
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
21 /**
22  * @file set/gnunet-set-ibf-profiler.c
23  * @brief tool for profiling the invertible bloom filter implementation
24  * @author Florian Dold
25  */
26
27 #include "platform.h"
28 #include "gnunet_util_lib.h"
29
30 #include "ibf.h"
31
32 static unsigned int asize = 10;
33 static unsigned int bsize = 10;
34 static unsigned int csize = 10;
35 static unsigned int hash_num = 4;
36 static unsigned int ibf_size = 80;
37
38 /* FIXME: add parameter for this */
39 static enum GNUNET_CRYPTO_Quality random_quality = GNUNET_CRYPTO_QUALITY_WEAK;
40
41 static struct GNUNET_CONTAINER_MultiHashMap *set_a;
42 static struct GNUNET_CONTAINER_MultiHashMap *set_b;
43 /* common elements in a and b */
44 static struct GNUNET_CONTAINER_MultiHashMap *set_c;
45
46 static struct GNUNET_CONTAINER_MultiHashMap *key_to_hashcode;
47
48 static struct InvertibleBloomFilter *ibf_a;
49 static struct InvertibleBloomFilter *ibf_b;
50
51
52 static void
53 register_hashcode (struct GNUNET_HashCode *hash)
54 {
55   struct GNUNET_HashCode replicated;
56   struct IBF_Key key;
57
58   key = ibf_key_from_hashcode (hash);
59   ibf_hashcode_from_key (key, &replicated);
60   (void) GNUNET_CONTAINER_multihashmap_put (
61     key_to_hashcode,
62     &replicated,
63     GNUNET_memdup (hash, sizeof *hash),
64     GNUNET_CONTAINER_MULTIHASHMAPOPTION_MULTIPLE);
65 }
66
67
68 static void
69 iter_hashcodes (struct IBF_Key key,
70                 GNUNET_CONTAINER_MulitHashMapIteratorCallback iter,
71                 void *cls)
72 {
73   struct GNUNET_HashCode replicated;
74
75   ibf_hashcode_from_key (key, &replicated);
76   GNUNET_CONTAINER_multihashmap_get_multiple (key_to_hashcode,
77                                               &replicated,
78                                               iter,
79                                               cls);
80 }
81
82
83 static int
84 insert_iterator (void *cls, const struct GNUNET_HashCode *key, void *value)
85 {
86   struct InvertibleBloomFilter *ibf = cls;
87
88   ibf_insert (ibf, ibf_key_from_hashcode (key));
89   return GNUNET_YES;
90 }
91
92
93 static int
94 remove_iterator (void *cls, const struct GNUNET_HashCode *key, void *value)
95 {
96   struct GNUNET_CONTAINER_MultiHashMap *hashmap = cls;
97
98   /* if remove fails, there just was a collision with another key */
99   (void) GNUNET_CONTAINER_multihashmap_remove (hashmap, value, NULL);
100   return GNUNET_YES;
101 }
102
103
104 static void
105 run (void *cls,
106      char *const *args,
107      const char *cfgfile,
108      const struct GNUNET_CONFIGURATION_Handle *cfg)
109 {
110   struct GNUNET_HashCode id;
111   struct IBF_Key ibf_key;
112   int i;
113   int side;
114   int res;
115   struct GNUNET_TIME_Absolute start_time;
116   struct GNUNET_TIME_Relative delta_time;
117
118   set_a =
119     GNUNET_CONTAINER_multihashmap_create (((asize == 0) ? 1 : (asize + csize)),
120                                           GNUNET_NO);
121   set_b =
122     GNUNET_CONTAINER_multihashmap_create (((bsize == 0) ? 1 : (bsize + csize)),
123                                           GNUNET_NO);
124   set_c = GNUNET_CONTAINER_multihashmap_create (((csize == 0) ? 1 : csize),
125                                                 GNUNET_NO);
126
127   key_to_hashcode =
128     GNUNET_CONTAINER_multihashmap_create (((asize + bsize + csize == 0)
129                                            ? 1
130                                            : (asize + bsize + csize)),
131                                           GNUNET_NO);
132
133   printf ("hash-num=%u, size=%u, #(A-B)=%u, #(B-A)=%u, #(A&B)=%u\n",
134           hash_num,
135           ibf_size,
136           asize,
137           bsize,
138           csize);
139
140   i = 0;
141   while (i < asize)
142   {
143     GNUNET_CRYPTO_hash_create_random (random_quality, &id);
144     if (GNUNET_YES == GNUNET_CONTAINER_multihashmap_contains (set_a, &id))
145       continue;
146     GNUNET_break (GNUNET_OK ==
147                   GNUNET_CONTAINER_multihashmap_put (
148                     set_a,
149                     &id,
150                     NULL,
151                     GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY));
152     register_hashcode (&id);
153     i++;
154   }
155   i = 0;
156   while (i < bsize)
157   {
158     GNUNET_CRYPTO_hash_create_random (random_quality, &id);
159     if (GNUNET_YES == GNUNET_CONTAINER_multihashmap_contains (set_a, &id))
160       continue;
161     if (GNUNET_YES == GNUNET_CONTAINER_multihashmap_contains (set_b, &id))
162       continue;
163     GNUNET_break (GNUNET_OK ==
164                   GNUNET_CONTAINER_multihashmap_put (
165                     set_b,
166                     &id,
167                     NULL,
168                     GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY));
169     register_hashcode (&id);
170     i++;
171   }
172   i = 0;
173   while (i < csize)
174   {
175     GNUNET_CRYPTO_hash_create_random (random_quality, &id);
176     if (GNUNET_YES == GNUNET_CONTAINER_multihashmap_contains (set_a, &id))
177       continue;
178     if (GNUNET_YES == GNUNET_CONTAINER_multihashmap_contains (set_b, &id))
179       continue;
180     if (GNUNET_YES == GNUNET_CONTAINER_multihashmap_contains (set_c, &id))
181       continue;
182     GNUNET_break (GNUNET_OK ==
183                   GNUNET_CONTAINER_multihashmap_put (
184                     set_c,
185                     &id,
186                     NULL,
187                     GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY));
188     register_hashcode (&id);
189     i++;
190   }
191
192   ibf_a = ibf_create (ibf_size, hash_num);
193   ibf_b = ibf_create (ibf_size, hash_num);
194   if ((NULL == ibf_a) || (NULL == ibf_b))
195   {
196     /* insufficient memory */
197     GNUNET_break (0);
198     GNUNET_SCHEDULER_shutdown ();
199     return;
200   }
201
202
203   printf ("generated sets\n");
204
205   start_time = GNUNET_TIME_absolute_get ();
206
207   GNUNET_CONTAINER_multihashmap_iterate (set_a, &insert_iterator, ibf_a);
208   GNUNET_CONTAINER_multihashmap_iterate (set_b, &insert_iterator, ibf_b);
209   GNUNET_CONTAINER_multihashmap_iterate (set_c, &insert_iterator, ibf_a);
210   GNUNET_CONTAINER_multihashmap_iterate (set_c, &insert_iterator, ibf_b);
211
212   delta_time = GNUNET_TIME_absolute_get_duration (start_time);
213
214   printf ("encoded in: %s\n",
215           GNUNET_STRINGS_relative_time_to_string (delta_time, GNUNET_NO));
216
217   ibf_subtract (ibf_a, ibf_b);
218
219
220   start_time = GNUNET_TIME_absolute_get ();
221
222   for (i = 0; i <= asize + bsize; i++)
223   {
224     res = ibf_decode (ibf_a, &side, &ibf_key);
225     if (GNUNET_SYSERR == res)
226     {
227       printf ("decode failed, %u/%u elements left\n",
228               GNUNET_CONTAINER_multihashmap_size (set_a)
229               + GNUNET_CONTAINER_multihashmap_size (set_b),
230               asize + bsize);
231       return;
232     }
233     if (GNUNET_NO == res)
234     {
235       if ((0 == GNUNET_CONTAINER_multihashmap_size (set_b)) &&
236           (0 == GNUNET_CONTAINER_multihashmap_size (set_a)))
237       {
238         delta_time = GNUNET_TIME_absolute_get_duration (start_time);
239         printf ("decoded successfully in: %s\n",
240                 GNUNET_STRINGS_relative_time_to_string (delta_time, GNUNET_NO));
241       }
242       else
243       {
244         printf ("decode missed elements (should never happen)\n");
245       }
246       return;
247     }
248
249     if (side == 1)
250       iter_hashcodes (ibf_key, remove_iterator, set_a);
251     if (side == -1)
252       iter_hashcodes (ibf_key, remove_iterator, set_b);
253   }
254   printf ("cyclic IBF, %u/%u elements left\n",
255           GNUNET_CONTAINER_multihashmap_size (set_a)
256           + GNUNET_CONTAINER_multihashmap_size (set_b),
257           asize + bsize);
258 }
259
260
261 int
262 main (int argc, char **argv)
263 {
264   struct GNUNET_GETOPT_CommandLineOption options[] = {
265     GNUNET_GETOPT_option_uint ('A',
266                                "asize",
267                                NULL,
268                                gettext_noop ("number of element in set A-B"),
269                                &asize),
270
271     GNUNET_GETOPT_option_uint ('B',
272                                "bsize",
273                                NULL,
274                                gettext_noop ("number of element in set B-A"),
275                                &bsize),
276
277     GNUNET_GETOPT_option_uint ('C',
278                                "csize",
279                                NULL,
280                                gettext_noop (
281                                  "number of common elements in A and B"),
282                                &csize),
283
284     GNUNET_GETOPT_option_uint ('k',
285                                "hash-num",
286                                NULL,
287                                gettext_noop ("hash num"),
288                                &hash_num),
289
290     GNUNET_GETOPT_option_uint ('s',
291                                "ibf-size",
292                                NULL,
293                                gettext_noop ("ibf size"),
294                                &ibf_size),
295
296     GNUNET_GETOPT_OPTION_END
297   };
298
299   GNUNET_PROGRAM_run2 (argc,
300                        argv,
301                        "gnunet-consensus-ibf",
302                        "help",
303                        options,
304                        &run,
305                        NULL,
306                        GNUNET_YES);
307   return 0;
308 }