- re-added testcase for crypto-paillier
[oweals/gnunet.git] / src / secretsharing / gnunet-secretsharing-profiler.c
1 /*
2       This file is part of GNUnet
3       (C) 2014 Christian Grothoff (and other contributing authors)
4
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 3, or (at your
8       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       General Public License for more details.
14
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.
19  */
20
21 /**
22  * @file secretsharing/gnunet-secretsharing-profiler.c
23  * @brief profiling tool for distributed key generation and decryption
24  * @author Florian Dold
25  */
26 #include "platform.h"
27 #include "gnunet_util_lib.h"
28 #include "gnunet_secretsharing_service.h"
29 #include "gnunet_testbed_service.h"
30
31 /**
32  * How many peers should participate in the key generation?
33  */
34 static unsigned int num_peers = 3;
35
36 /**
37  * What should the threshold for then key be?
38  */
39 static unsigned int threshold = 2;
40
41 /**
42  * Should we try to decrypt a value after the key generation?
43  */
44 static unsigned int decrypt = GNUNET_NO;
45
46 /**
47  * When would we like to see the operation finished?
48  */
49 static struct GNUNET_TIME_Relative timeout;
50
51 /**
52  * Handles for secretsharing sessions.
53  */
54 static struct GNUNET_SECRETSHARING_Session **session_handles;
55
56 static struct GNUNET_SECRETSHARING_DecryptionHandle **decrypt_handles;
57
58 /**
59  * Shares we got from the distributed key generation.
60  */
61 static struct GNUNET_SECRETSHARING_Share **shares;
62
63 static struct GNUNET_SECRETSHARING_PublicKey common_pubkey;
64
65 /**
66  * ???
67  */
68 static struct GNUNET_TESTBED_Operation **testbed_operations;
69
70 static unsigned int num_connected_sessions;
71
72 static unsigned int num_connected_decrypt;
73
74 static struct GNUNET_TESTBED_Peer **peers;
75
76 static struct GNUNET_PeerIdentity *peer_ids;
77
78 static unsigned int num_retrieved_peer_ids;
79
80 static unsigned int num_generated;
81
82 static unsigned int num_decrypted;
83
84 static struct GNUNET_HashCode session_id;
85
86 static int verbose;
87
88 struct GNUNET_SECRETSHARING_Plaintext reference_plaintext;
89
90 struct GNUNET_SECRETSHARING_Ciphertext ciphertext;
91
92
93 /**
94  * Signature of the event handler function called by the
95  * respective event controller.
96  *
97  * @param cls closure
98  * @param event information about the event
99  */
100 static void
101 controller_cb (void *cls,
102                const struct GNUNET_TESTBED_EventInformation *event)
103 {
104   GNUNET_assert (0);
105 }
106
107
108 /**
109  * Callback to be called when a service connect operation is completed
110  *
111  * @param cls the callback closure from functions generating an operation
112  * @param op the operation that has been finished
113  * @param ca_result the service handle returned from GNUNET_TESTBED_ConnectAdapter()
114  * @param emsg error message in case the operation has failed; will be NULL if
115  *          operation has executed successfully.
116  */
117 static void
118 session_connect_complete (void *cls,
119                           struct GNUNET_TESTBED_Operation *op,
120                           void *ca_result,
121                           const char *emsg)
122 {
123
124   if (NULL != emsg)
125   {
126     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
127                 "testbed connect emsg: %s\n",
128                 emsg);
129     GNUNET_assert (0);
130   }
131
132   num_connected_sessions++;
133
134   GNUNET_log (GNUNET_ERROR_TYPE_INFO,
135               "dkg: session connect complete\n");
136
137   if (num_connected_sessions == num_peers)
138   {
139     GNUNET_log (GNUNET_ERROR_TYPE_INFO,
140                 "dkg: all peers connected\n");
141   }
142 }
143
144
145 /**
146  * Callback to be called when a service connect operation is completed
147  *
148  * @param cls the callback closure from functions generating an operation
149  * @param op the operation that has been finished
150  * @param ca_result the service handle returned from GNUNET_TESTBED_ConnectAdapter()
151  * @param emsg error message in case the operation has failed; will be NULL if
152  *          operation has executed successfully.
153  */
154 static void
155 decrypt_connect_complete (void *cls,
156                           struct GNUNET_TESTBED_Operation *op,
157                           void *ca_result,
158                           const char *emsg)
159 {
160
161   if (NULL != emsg)
162   {
163     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
164                 "testbed connect emsg: %s\n",
165                 emsg);
166     GNUNET_assert (0);
167   }
168
169   num_connected_decrypt++;
170
171   GNUNET_log (GNUNET_ERROR_TYPE_INFO,
172               "decrypt: session connect complete\n");
173
174   if (num_connected_decrypt == num_peers)
175   {
176     GNUNET_log (GNUNET_ERROR_TYPE_INFO,
177                 "decrypt: all peers connected\n");
178   }
179 }
180
181
182 /**
183  * Called when a decryption has succeeded.
184  *
185  * @param cls Plaintext
186  * @param plaintext Plaintext
187  */
188 static void decrypt_cb (void *cls,
189                         const struct GNUNET_SECRETSHARING_Plaintext *plaintext)
190 {
191   struct GNUNET_SECRETSHARING_DecryptionHandle **dhp = cls;
192   unsigned int n = dhp - decrypt_handles;
193   num_decrypted++;
194
195   *dhp = NULL;
196
197   if (NULL == plaintext)
198   {
199     GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "decrypt failed for peer %u\n", n);
200     return;
201   }
202   else if (0 == memcmp (&reference_plaintext, plaintext, sizeof (struct GNUNET_SECRETSHARING_Plaintext)))
203     GNUNET_log (GNUNET_ERROR_TYPE_INFO, "decrypt got correct result for peer %u\n", n);
204   else
205     GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "decrypt got wrong result for peer %u\n", n);
206
207   if (num_decrypted == num_peers)
208   {
209     GNUNET_log (GNUNET_ERROR_TYPE_INFO, "every peer decrypted\n");
210     GNUNET_SCHEDULER_shutdown ();
211   }
212
213   *dhp = NULL;
214 }
215
216
217
218 /**
219  * Adapter function called to establish a connection to
220  * a service.
221  *
222  * @param cls closure
223  * @param cfg configuration of the peer to connect to; will be available until
224  *          GNUNET_TESTBED_operation_done() is called on the operation returned
225  *          from GNUNET_TESTBED_service_connect()
226  * @return service handle to return in 'op_result', NULL on error
227  */
228 static void *
229 decrypt_connect_adapter (void *cls,
230                  const struct GNUNET_CONFIGURATION_Handle *cfg)
231 {
232   struct GNUNET_SECRETSHARING_DecryptionHandle **hp = cls;
233   unsigned int n = hp - decrypt_handles;
234
235   GNUNET_log (GNUNET_ERROR_TYPE_INFO,
236               "decrypt connect adapter, %d peers\n",
237               num_peers);
238   *hp = GNUNET_SECRETSHARING_decrypt (cfg, shares[n], &ciphertext,
239                                       GNUNET_TIME_relative_to_absolute (GNUNET_TIME_UNIT_MINUTES),
240                                       decrypt_cb,
241                                       hp);
242
243   return *hp;
244 }
245
246
247 /**
248  * Adapter function called to destroy a connection to
249  * a service.
250  *
251  * @param cls closure
252  * @param op_result service handle returned from the connect adapter
253  */
254 static void
255 decrypt_disconnect_adapter(void *cls, void *op_result)
256 {
257   struct GNUNET_SECRETSHARING_DecryptionHandle **dh = cls;
258   if (NULL != *dh)
259   {
260     GNUNET_SECRETSHARING_decrypt_cancel (*dh);
261     *dh = NULL;
262   }
263 }
264
265
266 static void
267 secret_ready_cb (void *cls,
268                  struct GNUNET_SECRETSHARING_Share *my_share,
269                  struct GNUNET_SECRETSHARING_PublicKey *public_key,
270                  unsigned int num_ready_peers,
271                  struct GNUNET_PeerIdentity *ready_peers)
272 {
273   struct GNUNET_SECRETSHARING_Session **sp = cls;
274   unsigned int n = sp - session_handles;
275   char pubkey_str[1024];
276   char *ret;
277
278   num_generated++;
279   *sp = NULL;
280   shares[n] = my_share;
281   if (NULL == my_share)
282   {
283     GNUNET_log (GNUNET_ERROR_TYPE_INFO, "key generation failed for peer #%u\n", n);
284   }
285   else
286   {
287     GNUNET_log (GNUNET_ERROR_TYPE_INFO, "secret ready for peer #%u\n", n);
288     /* we're the first to get the key -> store it */
289     if (num_generated == 1)
290     {
291       common_pubkey = *public_key;
292     }
293     else if (0 != memcmp (public_key, &common_pubkey, sizeof (struct GNUNET_SECRETSHARING_PublicKey)))
294     {
295       GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "generated public keys do not match\n");
296       GNUNET_SCHEDULER_shutdown ();
297       return;
298     }
299   }
300
301   ret = GNUNET_STRINGS_data_to_string (public_key, sizeof *public_key, pubkey_str, 1024);
302   GNUNET_assert (NULL != ret);
303   *ret = '\0';
304   GNUNET_log (GNUNET_ERROR_TYPE_INFO, "key generation successful for peer #%u, pubkey %s\n", n,
305               pubkey_str);
306
307   // FIXME: destroy testbed operation
308
309   if (num_generated == num_peers)
310   {
311     int i;
312     if (GNUNET_NO == decrypt)
313     {
314       GNUNET_SCHEDULER_shutdown ();
315       return;
316     }
317
318     // compute g^42
319     GNUNET_SECRETSHARING_plaintext_generate_i (&reference_plaintext, 42);
320     GNUNET_SECRETSHARING_encrypt (&common_pubkey, &reference_plaintext, &ciphertext);
321
322     // FIXME: store the ops somewhere!
323     for (i = 0; i < num_peers; i++)
324       GNUNET_TESTBED_service_connect (NULL, peers[i], "secretsharing", &decrypt_connect_complete, NULL,
325                                       &decrypt_connect_adapter, &decrypt_disconnect_adapter, &decrypt_handles[i]);
326   }
327 }
328
329
330 /**
331  * Adapter function called to establish a connection to
332  * a service.
333  *
334  * @param cls closure
335  * @param cfg configuration of the peer to connect to; will be available until
336  *          GNUNET_TESTBED_operation_done() is called on the operation returned
337  *          from GNUNET_TESTBED_service_connect()
338  * @return service handle to return in 'op_result', NULL on error
339  */
340 static void *
341 session_connect_adapter (void *cls,
342                          const struct GNUNET_CONFIGURATION_Handle *cfg)
343 {
344   struct GNUNET_SECRETSHARING_Session **sp = cls;
345
346   GNUNET_log (GNUNET_ERROR_TYPE_INFO,
347               "connect adapter, %d peers\n",
348               num_peers);
349   *sp = GNUNET_SECRETSHARING_create_session (cfg,
350                                              num_peers,
351                                              peer_ids,
352                                              &session_id,
353                                              GNUNET_TIME_relative_to_absolute (timeout),
354                                              threshold,
355                                              &secret_ready_cb, sp);
356   return *sp;
357 }
358
359
360
361 /**
362  * Adapter function called to destroy a connection to
363  * a service.
364  *
365  * @param cls closure
366  * @param op_result service handle returned from the connect adapter
367  */
368 static void
369 session_disconnect_adapter (void *cls, void *op_result)
370 {
371   struct GNUNET_SECRETSHARING_Session **sp = cls;
372   if (NULL != *sp)
373   {
374     GNUNET_SECRETSHARING_session_destroy (*sp);
375     *sp = NULL;
376   }
377 }
378
379
380 /**
381  * Callback to be called when the requested peer information is available
382  *
383  * @param cb_cls the closure from GNUNET_TETSBED_peer_get_information()
384  * @param op the operation this callback corresponds to
385  * @param pinfo the result; will be NULL if the operation has failed
386  * @param emsg error message if the operation has failed; will be NULL if the
387  *          operation is successfull
388  */
389 static void
390 peer_info_cb (void *cb_cls,
391               struct GNUNET_TESTBED_Operation *op,
392               const struct GNUNET_TESTBED_PeerInformation *pinfo,
393               const char *emsg)
394 {
395   struct GNUNET_PeerIdentity *p;
396   int i;
397
398   GNUNET_assert (NULL == emsg);
399
400   p = (struct GNUNET_PeerIdentity *) cb_cls;
401
402   if (pinfo->pit == GNUNET_TESTBED_PIT_IDENTITY)
403   {
404     *p = *pinfo->result.id;
405     num_retrieved_peer_ids++;
406     if (num_retrieved_peer_ids == num_peers)
407       for (i = 0; i < num_peers; i++)
408         testbed_operations[i] =
409             GNUNET_TESTBED_service_connect (NULL, peers[i], "secretsharing", session_connect_complete, NULL,
410                                             session_connect_adapter, session_disconnect_adapter, &session_handles[i]);
411   }
412   else
413   {
414     GNUNET_assert (0);
415   }
416
417   GNUNET_TESTBED_operation_done (op);
418 }
419
420
421 /**
422  * Signature of a main function for a testcase.
423  *
424  * @param cls closure
425  * @param h the run handle
426  * @param num_peers number of peers in 'peers'
427  * @param started_peers handle to peers run in the testbed.  NULL upon timeout (see
428  *          GNUNET_TESTBED_test_run()).
429  * @param links_succeeded the number of overlay link connection attempts that
430  *          succeeded
431  * @param links_failed the number of overlay link connection attempts that
432  *          failed
433  */
434 static void
435 test_master (void *cls,
436              struct GNUNET_TESTBED_RunHandle *h,
437              unsigned int num_peers,
438              struct GNUNET_TESTBED_Peer **started_peers,
439              unsigned int links_succeeded,
440              unsigned int links_failed)
441 {
442   int i;
443
444   GNUNET_log_setup ("gnunet-secretsharing-profiler", "INFO", NULL);
445
446   GNUNET_log (GNUNET_ERROR_TYPE_INFO, "test master\n");
447
448   peers = started_peers;
449
450   peer_ids = GNUNET_malloc (num_peers * sizeof (struct GNUNET_PeerIdentity));
451
452   session_handles = GNUNET_new_array (num_peers, struct GNUNET_SECRETSHARING_Session *);
453   decrypt_handles = GNUNET_new_array (num_peers, struct GNUNET_SECRETSHARING_DecryptionHandle *);
454   testbed_operations = GNUNET_new_array (num_peers, struct GNUNET_TESTBED_Operation *);
455   shares = GNUNET_new_array (num_peers, struct GNUNET_SECRETSHARING_Share *);
456
457
458   for (i = 0; i < num_peers; i++)
459     GNUNET_TESTBED_peer_get_information (peers[i],
460                                          GNUNET_TESTBED_PIT_IDENTITY,
461                                          peer_info_cb,
462                                          &peer_ids[i]);
463 }
464
465
466 static void
467 run (void *cls, char *const *args, const char *cfgfile,
468      const struct GNUNET_CONFIGURATION_Handle *cfg)
469 {
470   static char *session_str = "gnunet-secretsharing/test";
471   char *topology;
472   int topology_cmp_result;
473
474   if (GNUNET_OK != GNUNET_CONFIGURATION_get_value_string (cfg, "testbed", "OVERLAY_TOPOLOGY", &topology))
475   {
476     fprintf (stderr,
477              "'OVERLAY_TOPOLOGY' not found in 'testbed' config section, "
478              "seems like you passed the wrong configuration file\n");
479     return;
480   }
481
482   topology_cmp_result = strcasecmp (topology, "NONE");
483   GNUNET_free (topology);
484
485   if (0 == topology_cmp_result)
486   {
487     fprintf (stderr,
488              "'OVERLAY_TOPOLOGY' set to 'NONE', "
489              "seems like you passed the wrong configuration file\n");
490     return;
491   }
492
493   GNUNET_log (GNUNET_ERROR_TYPE_INFO,
494               "running gnunet-secretsharing-profiler\n");
495
496   GNUNET_CRYPTO_hash (session_str, strlen (session_str), &session_id);
497
498   (void) GNUNET_TESTBED_test_run ("gnunet-secretsharing-profiler",
499                                   cfgfile,
500                                   num_peers,
501                                   0,
502                                   controller_cb,
503                                   NULL,
504                                   test_master,
505                                   NULL);
506 }
507
508
509 int
510 main (int argc, char **argv)
511 {
512    static const struct GNUNET_GETOPT_CommandLineOption options[] = {
513       { 'n', "num-peers", NULL,
514         gettext_noop ("number of peers in consensus"),
515         GNUNET_YES, &GNUNET_GETOPT_set_uint, &num_peers },
516       { 't', "timeout", NULL,
517         gettext_noop ("dkg timeout"),
518         GNUNET_YES, &GNUNET_GETOPT_set_relative_time, &timeout },
519       { 'k', "threshold", NULL,
520         gettext_noop ("threshold"),
521         GNUNET_YES, &GNUNET_GETOPT_set_uint, &threshold },
522       { 'd', "decrypt", NULL,
523         gettext_noop ("also profile decryption"),
524         GNUNET_NO, &GNUNET_GETOPT_set_one, &decrypt },
525       { 'V', "verbose", NULL,
526         gettext_noop ("be more verbose (print received values)"),
527         GNUNET_NO, &GNUNET_GETOPT_set_one, &verbose },
528       GNUNET_GETOPT_OPTION_END
529   };
530   timeout = GNUNET_TIME_UNIT_SECONDS;
531   GNUNET_PROGRAM_run2 (argc, argv, "gnunet-secretsharing-profiler",
532                       "help",
533                       options, &run, NULL, GNUNET_YES);
534   return 0;
535 }
536