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