- re-added testcase for crypto-paillier
[oweals/gnunet.git] / src / secretsharing / gnunet-service-secretsharing.c
1 /*
2      This file is part of GNUnet.
3      (C) 2013 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-service-secretsharing.c
23  * @brief secret sharing service
24  * @author Florian Dold
25  */
26 #include "platform.h"
27 #include "gnunet_util_lib.h"
28 #include "gnunet_time_lib.h"
29 #include "gnunet_signatures.h"
30 #include "gnunet_consensus_service.h"
31 #include "secretsharing.h"
32 #include "secretsharing_protocol.h"
33 #include <gcrypt.h>
34
35
36 #define EXTRA_CHECKS 1
37
38
39 /**
40  * Info about a peer in a key generation session.
41  */
42 struct KeygenPeerInfo
43 {
44   /**
45    * Peer identity of the peer.
46    */
47   struct GNUNET_PeerIdentity peer;
48
49   /**
50    * The peer's paillier public key.
51    * Freshly generated for each keygen session.
52    */
53   struct GNUNET_CRYPTO_PaillierPublicKey paillier_public_key;
54
55   /**
56    * The peer's commitment to his presecret.
57    */
58   gcry_mpi_t presecret_commitment;
59
60   /**
61    * The peer's preshare that we decrypted
62    * with out private key.
63    */
64   gcry_mpi_t decrypted_preshare;
65
66   /**
67    * Multiplicative share of the public key.
68    */
69   gcry_mpi_t public_key_share;
70
71   /**
72    * Did we successfully receive the round1 element
73    * of the peer?
74    */
75   int round1_valid;
76
77   /**
78    * Did we successfully receive the round2 element
79    * of the peer?
80    */
81   int round2_valid;
82 };
83
84
85 /**
86  * Information about a peer in a decrypt session.
87  */
88 struct DecryptPeerInfo
89 {
90   /**
91    * Identity of the peer.
92    */
93   struct GNUNET_PeerIdentity peer;
94
95   /**
96    * Original index in the key generation round.
97    * Necessary for computing the lagrange coefficients.
98    */
99   unsigned int original_index;
100
101   /**
102    * Set to the partial decryption of
103    * this peer, or NULL if we did not
104    * receive a partial decryption from this
105    * peer or the zero knowledge proof failed.
106    */
107   gcry_mpi_t partial_decryption;
108 };
109
110
111 /**
112  * Session to establish a threshold-shared secret.
113  */
114 struct KeygenSession
115 {
116   /**
117    * Keygen sessions are held in a linked list.
118    */
119   struct KeygenSession *next;
120
121   /**
122    * Keygen sessions are held in a linked list.
123    */
124   struct KeygenSession *prev;
125
126   /**
127    * Current consensus, used for both DKG rounds.
128    */
129   struct GNUNET_CONSENSUS_Handle *consensus;
130
131   /**
132    * Client that is interested in the result
133    * of this key generation session.
134    */
135   struct GNUNET_SERVER_Client *client;
136
137   /**
138    * Message queue for 'client'
139    */
140   struct GNUNET_MQ_Handle *client_mq;
141
142   /**
143    * Randomly generated coefficients of the polynomial for sharing our
144    * pre-secret, where 'preshares[0]' is our pre-secret.  Contains 'threshold'
145    * elements, thus represents a polynomial of degree 'threshold-1', which can
146    * be interpolated with 'threshold' data points.
147    *
148    * The pre-secret-shares 'i=1,...,num_peers' are given by evaluating this
149    * polyomial at 'i' for share i.
150    */
151   gcry_mpi_t *presecret_polynomial;
152
153   /**
154    * Minimum number of shares required to restore the secret.
155    * Also the number of coefficients for the polynomial representing
156    * the sharing.  Obviously, the polynomial then has degree threshold-1.
157    */
158   unsigned int threshold;
159
160   /**
161    * Total number of peers.
162    */
163   unsigned int num_peers;
164
165   /**
166    * Index of the local peer.
167    */
168   unsigned int local_peer;
169
170   /**
171    * Information about all participating peers.
172    * Array of size 'num_peers'.
173    */
174   struct KeygenPeerInfo *info;
175
176   /**
177    * List of all peers involved in the secret sharing session.
178    */
179   struct GNUNET_PeerIdentity *peers;
180
181   /**
182    * Identifier for this session.
183    */
184   struct GNUNET_HashCode session_id;
185
186   /**
187    * Paillier private key of our peer.
188    */
189   struct GNUNET_CRYPTO_PaillierPrivateKey paillier_private_key;
190
191   /**
192    * When would we like the key to be established?
193    */
194   struct GNUNET_TIME_Absolute deadline;
195
196   /**
197    * When does the DKG start?  Necessary to compute fractions of the
198    * operation's desired time interval.
199    */
200   struct GNUNET_TIME_Absolute start_time;
201
202   /**
203    * Index of the local peer in the ordered list
204    * of peers in the session.
205    */
206   unsigned int local_peer_idx;
207 };
208
209
210 /**
211  * Session to cooperatively decrypt a value.
212  */
213 struct DecryptSession
214 {
215   /**
216    * Decrypt sessions are stored in a linked list.
217    */
218   struct DecryptSession *next;
219
220   /**
221    * Decrypt sessions are stored in a linked list.
222    */
223   struct DecryptSession *prev;
224
225   /**
226    * Handle to the consensus over partial decryptions.
227    */
228   struct GNUNET_CONSENSUS_Handle *consensus;
229
230   /**
231    * Client connected to us.
232    */
233   struct GNUNET_SERVER_Client *client;
234
235   /**
236    * Message queue for 'client'.
237    */
238   struct GNUNET_MQ_Handle *client_mq;
239
240   /**
241    * When would we like the ciphertext to be
242    * decrypted?
243    */
244   struct GNUNET_TIME_Absolute deadline;
245
246   /**
247    * Ciphertext we want to decrypt.
248    */
249   struct GNUNET_SECRETSHARING_Ciphertext ciphertext;
250
251   /**
252    * Share of the local peer.
253    * Containts other important information, such as
254    * the list of other peers.
255    */
256   struct GNUNET_SECRETSHARING_Share *share;
257
258   /**
259    * State information about other peers.
260    */
261   struct DecryptPeerInfo *info;
262 };
263
264
265 /**
266  * Decrypt sessions are held in a linked list.
267  */
268 static struct DecryptSession *decrypt_sessions_head;
269
270 /**
271  * Decrypt sessions are held in a linked list.
272  */
273 static struct DecryptSession *decrypt_sessions_tail;
274
275 /**
276  * Decrypt sessions are held in a linked list.
277  */
278 static struct KeygenSession *keygen_sessions_head;
279
280 /**
281  * Decrypt sessions are held in a linked list.
282  */
283 static struct KeygenSession *keygen_sessions_tail;
284
285 /**
286  * The ElGamal prime field order as libgcrypt mpi.
287  * Initialized in #init_crypto_constants.
288  */
289 static gcry_mpi_t elgamal_q;
290
291 /**
292  * Modulus of the prime field used for ElGamal.
293  * Initialized in #init_crypto_constants.
294  */
295 static gcry_mpi_t elgamal_p;
296
297 /**
298  * Generator for prime field of order 'elgamal_q'.
299  * Initialized in #init_crypto_constants.
300  */
301 static gcry_mpi_t elgamal_g;
302
303 /**
304  * Peer that runs this service.
305  */
306 static struct GNUNET_PeerIdentity my_peer;
307
308 /**
309  * Peer that runs this service.
310  */
311 static struct GNUNET_CRYPTO_EddsaPrivateKey *my_peer_private_key;
312
313 /**
314  * Configuration of this service.
315  */
316 static const struct GNUNET_CONFIGURATION_Handle *cfg;
317
318 /**
319  * Server for this service.
320  */
321 static struct GNUNET_SERVER_Handle *srv;
322
323
324 /**
325  * Get the peer info belonging to a peer identity in a keygen session.
326  *
327  * @param ks The keygen session.
328  * @param peer The peer identity.
329  * @return The Keygen peer info, or NULL if the peer could not be found.
330  */
331 static struct KeygenPeerInfo *
332 get_keygen_peer_info (const struct KeygenSession *ks,
333                       const struct GNUNET_PeerIdentity *peer)
334 {
335   unsigned int i;
336   for (i = 0; i < ks->num_peers; i++)
337     if (0 == memcmp (peer, &ks->info[i].peer, sizeof (struct GNUNET_PeerIdentity)))
338       return &ks->info[i];
339   return NULL;
340 }
341
342
343 /**
344  * Get the peer info belonging to a peer identity in a decrypt session.
345  *
346  * @param ds The decrypt session.
347  * @param peer The peer identity.
348  * @return The decrypt peer info, or NULL if the peer could not be found.
349  */
350 static struct DecryptPeerInfo *
351 get_decrypt_peer_info (const struct DecryptSession *ds,
352                        const struct GNUNET_PeerIdentity *peer)
353 {
354   unsigned int i;
355   for (i = 0; i < ds->share->num_peers; i++)
356     if (0 == memcmp (peer, &ds->info[i].peer, sizeof (struct GNUNET_PeerIdentity)))
357       return &ds->info[i];
358   return NULL;
359 }
360
361
362 /**
363  * Interpolate between two points in time.
364  *
365  * @param start start time
366  * @param end end time
367  * @param num numerator of the scale factor
368  * @param denum denumerator of the scale factor
369  */
370 static struct GNUNET_TIME_Absolute
371 time_between (struct GNUNET_TIME_Absolute start,
372               struct GNUNET_TIME_Absolute end,
373               int num, int denum)
374 {
375   struct GNUNET_TIME_Absolute result;
376   uint64_t diff;
377
378   GNUNET_assert (start.abs_value_us <= end.abs_value_us);
379   diff = end.abs_value_us - start.abs_value_us;
380   result.abs_value_us = start.abs_value_us + ((diff * num) / denum);
381
382   return result;
383 }
384
385
386 /**
387  * Compare two peer identities.  Indended to be used with qsort or bsearch.
388  *
389  * @param p1 Some peer identity.
390  * @param p2 Some peer identity.
391  * @return 1 if p1 > p2, -1 if p1 < p2 and 0 if p1 == p2.
392  */
393 static int
394 peer_id_cmp (const void *p1, const void *p2)
395 {
396   return memcmp (p1, p2, sizeof (struct GNUNET_PeerIdentity));
397 }
398
399
400 /**
401  * Get the index of a peer in an array of peers
402  *
403  * @param haystack Array of peers.
404  * @param n Size of @a haystack.
405  * @param needle Peer to find
406  * @return Index of @a needle in @a haystack, or -1 if peer
407  *         is not in the list.
408  */
409 static int
410 peer_find (const struct GNUNET_PeerIdentity *haystack, unsigned int n,
411            const struct GNUNET_PeerIdentity *needle)
412 {
413   unsigned int i;
414   for (i = 0; i < n; i++)
415     if (0 == memcmp (&haystack[i], needle, sizeof (struct GNUNET_PeerIdentity)))
416       return i;
417   return -1;
418 }
419
420
421 /**
422  * Normalize the given list of peers, by including the local peer
423  * (if it is missing) and sorting the peers by their identity.
424  *
425  * @param listed Peers in the unnormalized list.
426  * @param num_listed Peers in the un-normalized list.
427  * @param[out] num_normalized Number of peers in the normalized list.
428  * @param[out] my_peer_idx Index of the local peer in the normalized list.
429  * @return Normalized list, must be free'd by the caller.
430  */
431 static struct GNUNET_PeerIdentity *
432 normalize_peers (struct GNUNET_PeerIdentity *listed,
433                  unsigned int num_listed,
434                  unsigned int *num_normalized,
435                  unsigned int *my_peer_idx)
436 {
437   unsigned int local_peer_in_list;
438   /* number of peers in the normalized list */
439   unsigned int n;
440   struct GNUNET_PeerIdentity *normalized;
441
442   local_peer_in_list = GNUNET_YES;
443   n = num_listed;
444   if (peer_find (listed, num_listed, &my_peer) < 0)
445   {
446     local_peer_in_list = GNUNET_NO;
447     n += 1;
448   }
449
450   normalized = GNUNET_new_array (n, struct GNUNET_PeerIdentity);
451
452   if (GNUNET_NO == local_peer_in_list)
453     normalized[n - 1] = my_peer;
454
455   memcpy (normalized, listed, num_listed * sizeof (struct GNUNET_PeerIdentity));
456   qsort (normalized, n, sizeof (struct GNUNET_PeerIdentity), &peer_id_cmp);
457
458   if (NULL != my_peer_idx)
459     *my_peer_idx = peer_find (normalized, n, &my_peer);
460   if (NULL != num_normalized)
461     *num_normalized = n;
462
463   return normalized;
464 }
465
466
467 /**
468  * Get a the j-th lagrange coefficient for a set of indices.
469  *
470  * @param[out] coeff the lagrange coefficient
471  * @param j lagrange coefficient we want to compute
472  * @param indices indices
473  * @param num number of indices in @a indices
474  */
475 static void
476 compute_lagrange_coefficient (gcry_mpi_t coeff, unsigned int j,
477                               unsigned int *indices,
478                               unsigned int num)
479 {
480   unsigned int i;
481   /* numerator */
482   gcry_mpi_t n;
483   /* denominator */
484   gcry_mpi_t d;
485   /* temp value for l-j */
486   gcry_mpi_t tmp;
487
488   GNUNET_assert (0 != coeff);
489
490   GNUNET_assert (0 != (n = gcry_mpi_new (0)));
491   GNUNET_assert (0 != (d = gcry_mpi_new (0)));
492   GNUNET_assert (0 != (tmp = gcry_mpi_new (0)));
493
494   gcry_mpi_set_ui (n, 1);
495   gcry_mpi_set_ui (d, 1);
496
497   for (i = 0; i < num; i++)
498   {
499     unsigned int l = indices[i];
500     if (l == j)
501       continue;
502     gcry_mpi_mul_ui (n, n, l + 1);
503     // d <- d * (l-j)
504     gcry_mpi_set_ui (tmp, l + 1);
505     gcry_mpi_sub_ui (tmp, tmp, j + 1);
506     gcry_mpi_mul (d, d, tmp);
507   }
508
509   // gcry_mpi_invm does not like negative numbers ...
510   gcry_mpi_mod (d, d, elgamal_q);
511
512   GNUNET_assert (gcry_mpi_cmp_ui (d, 0) > 0);
513
514   // now we do the actual division, with everything mod q, as we
515   // are not operating on elements from <g>, but on exponents
516   GNUNET_assert (0 != gcry_mpi_invm (d, d, elgamal_q));
517
518   gcry_mpi_mulm (coeff, n, d, elgamal_q);
519
520   gcry_mpi_release (n);
521   gcry_mpi_release (d);
522   gcry_mpi_release (tmp);
523 }
524
525
526 static void
527 decrypt_session_destroy (struct DecryptSession *ds)
528 {
529   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "destroying decrypt session\n");
530
531   GNUNET_CONTAINER_DLL_remove (decrypt_sessions_head, decrypt_sessions_tail, ds);
532
533   if (NULL != ds->client_mq)
534   {
535     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "destroying decrypt MQ\n");
536     GNUNET_MQ_destroy (ds->client_mq);
537     ds->client_mq = NULL;
538   }
539
540   if (NULL != ds->client)
541   {
542     GNUNET_SERVER_client_disconnect (ds->client);
543     ds->client = NULL;
544   }
545
546   GNUNET_free (ds);
547 }
548
549
550 static void
551 keygen_session_destroy (struct KeygenSession *ks)
552 {
553   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "destroying keygen session\n");
554
555   GNUNET_CONTAINER_DLL_remove (keygen_sessions_head, keygen_sessions_tail, ks);
556
557   if (NULL != ks->client_mq)
558   {
559     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "destroying keygen MQ\n");
560     GNUNET_MQ_destroy (ks->client_mq);
561     ks->client_mq = NULL;
562   }
563
564   if (NULL != ks->client)
565   {
566     GNUNET_SERVER_client_disconnect (ks->client);
567     ks->client = NULL;
568   }
569
570   GNUNET_free (ks);
571 }
572
573
574 /**
575  * Task run during shutdown.
576  *
577  * @param cls unused
578  * @param tc unused
579  */
580 static void
581 cleanup_task (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
582 {
583   while (NULL != decrypt_sessions_head)
584     decrypt_session_destroy (decrypt_sessions_head);
585
586   while (NULL != keygen_sessions_head)
587     keygen_session_destroy (keygen_sessions_head);
588 }
589
590
591 /**
592  * Generate the random coefficients of our pre-secret polynomial
593  *
594  * @param ks the session
595  */
596 static void
597 generate_presecret_polynomial (struct KeygenSession *ks)
598 {
599   int i;
600   gcry_mpi_t v;
601
602   GNUNET_assert (NULL == ks->presecret_polynomial);
603   ks->presecret_polynomial = GNUNET_new_array (ks->threshold, gcry_mpi_t);
604   for (i = 0; i < ks->threshold; i++)
605   {
606     v = ks->presecret_polynomial[i] = gcry_mpi_new (GNUNET_SECRETSHARING_ELGAMAL_BITS);
607     GNUNET_assert (NULL != v);
608     // Randomize v such that 0 < v < elgamal_q.
609     // The '- 1' is necessary as bitlength(q) = bitlength(p) - 1.
610     do 
611     {
612       gcry_mpi_randomize (v, GNUNET_SECRETSHARING_ELGAMAL_BITS - 1, GCRY_WEAK_RANDOM);
613     } while ((gcry_mpi_cmp_ui (v, 0) == 0) || (gcry_mpi_cmp (v, elgamal_q) >= 0));
614   }
615 }
616
617
618 /**
619  * Consensus element handler for round one.
620  * We should get one ephemeral key for each peer.
621  *
622  * @param cls Closure (keygen session).
623  * @param element The element from consensus, or
624  *                NULL if consensus failed.
625  */
626 static void
627 keygen_round1_new_element (void *cls,
628                            const struct GNUNET_SET_Element *element)
629 {
630   const struct GNUNET_SECRETSHARING_KeygenCommitData *d;
631   struct KeygenSession *ks = cls;
632   struct KeygenPeerInfo *info;
633
634   if (NULL == element)
635   {
636     GNUNET_log (GNUNET_ERROR_TYPE_WARNING, "round1 consensus failed\n");
637     return;
638   }
639
640   /* elements have fixed size */
641   if (element->size != sizeof (struct GNUNET_SECRETSHARING_KeygenCommitData))
642   {
643     GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
644                 "keygen commit data with wrong size (%u) in consensus, "
645                 " %u expected\n",
646                 element->size, sizeof (struct GNUNET_SECRETSHARING_KeygenCommitData));
647     return;
648   }
649
650   GNUNET_log (GNUNET_ERROR_TYPE_INFO, "got round1 element\n");
651
652   d = element->data;
653   info = get_keygen_peer_info (ks, &d->peer);
654
655   if (NULL == info)
656   {
657     GNUNET_log (GNUNET_ERROR_TYPE_WARNING, "keygen commit data with wrong peer identity (%s) in consensus\n",
658                 GNUNET_i2s (&d->peer));
659     return;
660   }
661
662   /* Check that the right amount of data has been signed. */
663   if (d->purpose.size !=
664       htonl (element->size - offsetof (struct GNUNET_SECRETSHARING_KeygenCommitData, purpose)))
665   {
666     GNUNET_log (GNUNET_ERROR_TYPE_WARNING, "keygen commit data with wrong signature purpose size in consensus\n");
667     return;
668   }
669
670   if (GNUNET_OK != GNUNET_CRYPTO_eddsa_verify (GNUNET_SIGNATURE_PURPOSE_SECRETSHARING_DKG1,
671                                                &d->purpose, &d->signature, &d->peer.public_key))
672   {
673     GNUNET_log (GNUNET_ERROR_TYPE_WARNING, "keygen commit data with invalid signature in consensus\n");
674     return;
675   }
676   info->paillier_public_key = d->pubkey;
677   // FIXME: does not make any sense / is wrong
678   GNUNET_CRYPTO_mpi_scan_unsigned (&info->presecret_commitment, &d->pubkey.n, GNUNET_CRYPTO_PAILLIER_BITS / 8);
679   info->round1_valid = GNUNET_YES;
680 }
681
682
683 /**
684  * Evaluate the polynomial with coefficients @a coeff at @a x.
685  * The i-th element in @a coeff corresponds to the coefficient of x^i.
686  *
687  * @param[out] z result of the evaluation
688  * @param coeff array of coefficients
689  * @param num_coeff number of coefficients
690  * @param x where to evaluate the polynomial
691  * @param m what group are we operating in?
692  */
693 static void
694 horner_eval (gcry_mpi_t z, gcry_mpi_t *coeff, unsigned int num_coeff, gcry_mpi_t x, gcry_mpi_t m)
695 {
696   unsigned int i;
697
698   gcry_mpi_set_ui (z, 0);
699   for (i = 0; i < num_coeff; i++)
700   {
701     // z <- zx + c
702     gcry_mpi_mul (z, z, x);
703     gcry_mpi_addm (z, z, coeff[num_coeff - i - 1], m);
704   }
705 }
706
707
708 static void
709 keygen_round2_conclude (void *cls)
710 {
711   struct KeygenSession *ks = cls;
712   struct GNUNET_SECRETSHARING_SecretReadyMessage *m;
713   struct GNUNET_MQ_Envelope *ev;
714   size_t share_size;
715   unsigned int i;
716   unsigned int j;
717   struct GNUNET_SECRETSHARING_Share *share;
718   /* our share */
719   gcry_mpi_t s;
720   /* public key */
721   gcry_mpi_t h;
722
723   GNUNET_log (GNUNET_ERROR_TYPE_INFO, "round2 conclude\n");
724
725   GNUNET_assert (0 != (s = gcry_mpi_new (GNUNET_SECRETSHARING_ELGAMAL_BITS)));
726   GNUNET_assert (0 != (h = gcry_mpi_new (GNUNET_SECRETSHARING_ELGAMAL_BITS)));
727
728   // multiplicative identity
729   gcry_mpi_set_ui (h, 1);
730   // additive identity
731   gcry_mpi_set_ui (s, 0);
732
733   share = GNUNET_new (struct GNUNET_SECRETSHARING_Share);
734
735   share->num_peers = 0;
736
737   for (i = 0; i < ks->num_peers; i++)
738     if (GNUNET_YES == ks->info[i].round2_valid)
739       share->num_peers++;
740
741   share->peers = GNUNET_new_array (share->num_peers, struct GNUNET_PeerIdentity);
742   share->hom_share_commitments =
743       GNUNET_new_array (share->num_peers, struct GNUNET_SECRETSHARING_FieldElement);
744   share->original_indices = GNUNET_new_array (share->num_peers, uint16_t);
745
746   /* maybe we're not even in the list of peers? */
747   share->my_peer = share->num_peers;
748
749   j = 0;
750   for (i = 0; i < ks->num_peers; i++)
751   {
752     if (GNUNET_YES == ks->info[i].round2_valid)
753     {
754       gcry_mpi_addm (s, s, ks->info[i].decrypted_preshare, elgamal_p);
755       gcry_mpi_mulm (h, h, ks->info[i].public_key_share, elgamal_p);
756       share->peers[i] = ks->info[i].peer;
757       share->original_indices[i] = j++;
758       if (0 == memcmp (&share->peers[i], &my_peer, sizeof (struct GNUNET_PeerIdentity)))
759         share->my_peer = i;
760     }
761   }
762
763   GNUNET_CRYPTO_mpi_print_unsigned (&share->my_share, GNUNET_SECRETSHARING_ELGAMAL_BITS / 8, s);
764   GNUNET_CRYPTO_mpi_print_unsigned (&share->public_key, GNUNET_SECRETSHARING_ELGAMAL_BITS / 8, h);
765
766   GNUNET_log (GNUNET_ERROR_TYPE_INFO, "keygen completed with %u peers\n", share->num_peers);
767
768   /* Write the share. If 0 peers completed the dkg, an empty
769    * share will be sent. */
770
771   m = GNUNET_malloc (sizeof (struct GNUNET_SECRETSHARING_SecretReadyMessage) +
772                      ks->num_peers * sizeof (struct GNUNET_PeerIdentity));
773
774   GNUNET_assert (GNUNET_OK == GNUNET_SECRETSHARING_share_write (share, NULL, 0, &share_size));
775
776   ev = GNUNET_MQ_msg_extra (m, share_size,
777                             GNUNET_MESSAGE_TYPE_SECRETSHARING_CLIENT_SECRET_READY);
778
779   GNUNET_assert (GNUNET_OK == GNUNET_SECRETSHARING_share_write (share, &m[1], share_size, NULL));
780
781   GNUNET_MQ_send (ks->client_mq, ev);
782 }
783
784
785 /**
786  * Insert round 2 element in the consensus, consisting of
787  * (1) The exponentiated pre-share polynomial coefficients A_{i,l}=g^{a_{i,l}}
788  * (2) The exponentiated pre-shares y_{i,j}=g^{s_{i,j}}
789  * (3) The encrypted pre-shares Y_{i,j}
790  * (4) The zero knowledge proof for correctness of
791  *    the encryption
792  *
793  * @param ks session to use
794  */
795 static void
796 insert_round2_element (struct KeygenSession *ks)
797 {
798   struct GNUNET_SET_Element *element;
799   struct GNUNET_SECRETSHARING_KeygenRevealData *d;
800   unsigned char *pos;
801   unsigned char *last_pos;
802   size_t element_size;
803   unsigned int i;
804   gcry_mpi_t idx;
805   gcry_mpi_t v;
806   gcry_mpi_t c;
807
808   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "P%u: Inserting round2 element\n",
809               ks->local_peer_idx);
810
811   GNUNET_assert (NULL != (v = gcry_mpi_new (GNUNET_SECRETSHARING_ELGAMAL_BITS)));
812   GNUNET_assert (NULL != (idx = gcry_mpi_new (GNUNET_SECRETSHARING_ELGAMAL_BITS)));
813   GNUNET_assert (NULL != (c = gcry_mpi_new (GNUNET_SECRETSHARING_ELGAMAL_BITS)));
814
815   element_size = (sizeof (struct GNUNET_SECRETSHARING_KeygenRevealData) +
816                   GNUNET_SECRETSHARING_ELGAMAL_BITS / 8 * ks->num_peers +
817                   GNUNET_SECRETSHARING_ELGAMAL_BITS / 8 * ks->threshold +
818                   GNUNET_CRYPTO_PAILLIER_BITS * 2 / 8 * ks->num_peers);
819
820   element = GNUNET_malloc (sizeof (struct GNUNET_SET_Element) + element_size);
821   element->size = element_size;
822   element->data = (void *) &element[1];
823
824   d = (void *) element->data;
825   d->peer = my_peer;
826
827   // start inserting vector elements
828   // after the fixed part of the element's data
829   pos = (void *) &d[1];
830   last_pos = pos + element_size;
831
832   // exponentiated pre-shares
833   for (i = 0; i < ks->num_peers; i++)
834   {
835     ptrdiff_t remaining = last_pos - pos;
836     GNUNET_assert (remaining > 0);
837     gcry_mpi_set_ui (idx, i + 1);
838     // evaluate the polynomial
839     horner_eval (v, ks->presecret_polynomial, ks->threshold, idx, elgamal_q);
840     // take g to the result
841     gcry_mpi_powm (v, elgamal_g, v, elgamal_p);
842     GNUNET_CRYPTO_mpi_print_unsigned (pos, GNUNET_SECRETSHARING_ELGAMAL_BITS / 8, v);
843     pos += GNUNET_SECRETSHARING_ELGAMAL_BITS / 8;
844   }
845
846   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "P%u: computed exp preshares\n",
847               ks->local_peer_idx);
848
849   // encrypted pre-shares
850   for (i = 0; i < ks->num_peers; i++)
851   {
852     ptrdiff_t remaining = last_pos - pos;
853     struct GNUNET_CRYPTO_PaillierCiphertext *ciphertext;
854
855     GNUNET_assert (remaining > 0);
856     ciphertext = (void *) pos;
857     memset (ciphertext, 0, sizeof *ciphertext);
858     if (GNUNET_YES == ks->info[i].round1_valid)
859     {
860       struct GNUNET_CRYPTO_PaillierPlaintext plaintext;
861       gcry_mpi_set_ui (idx, i + 1);
862       // evaluate the polynomial
863       horner_eval (v, ks->presecret_polynomial, ks->threshold, idx, elgamal_q);
864       GNUNET_CRYPTO_mpi_print_unsigned (&plaintext, sizeof plaintext, v);
865       // encrypt the result
866       GNUNET_CRYPTO_paillier_encrypt (&ks->info[i].paillier_public_key, &plaintext, ciphertext);
867     }
868     pos += sizeof *ciphertext;
869   }
870
871   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "P%u: computed enc preshares\n",
872               ks->local_peer_idx);
873
874   // exponentiated coefficients
875   for (i = 0; i < ks->threshold; i++)
876   {
877     ptrdiff_t remaining = last_pos - pos;
878     GNUNET_assert (remaining > 0);
879     gcry_mpi_powm (v, elgamal_g, ks->presecret_polynomial[i], elgamal_p);
880     GNUNET_CRYPTO_mpi_print_unsigned (pos, GNUNET_SECRETSHARING_ELGAMAL_BITS / 8, v);
881     pos += GNUNET_SECRETSHARING_ELGAMAL_BITS / 8;
882   }
883
884   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "P%u: computed exp coefficients\n",
885               ks->local_peer_idx);
886
887   d->purpose.size = htonl (element_size - offsetof (struct GNUNET_SECRETSHARING_KeygenRevealData, purpose));
888   d->purpose.purpose = htonl (GNUNET_SIGNATURE_PURPOSE_SECRETSHARING_DKG2);
889   GNUNET_CRYPTO_eddsa_sign (my_peer_private_key, &d->purpose, &d->signature);
890
891   GNUNET_CONSENSUS_insert (ks->consensus, element, NULL, NULL);
892   GNUNET_free (element); /* FIXME: maybe stack-allocate instead? */
893
894   gcry_mpi_release (v);
895   gcry_mpi_release (idx);
896 }
897
898
899 static void
900 keygen_round2_new_element (void *cls,
901                            const struct GNUNET_SET_Element *element)
902 {
903   struct KeygenSession *ks = cls;
904   const struct GNUNET_SECRETSHARING_KeygenRevealData *d;
905   struct KeygenPeerInfo *info;
906   unsigned char *pos;
907   struct GNUNET_CRYPTO_PaillierPlaintext plaintext;
908   size_t expected_element_size;
909
910   if (NULL == element)
911   {
912     GNUNET_log (GNUNET_ERROR_TYPE_WARNING, "round2 consensus failed\n");
913     return;
914   }
915
916   expected_element_size = (sizeof (struct GNUNET_SECRETSHARING_KeygenRevealData) +
917                   GNUNET_SECRETSHARING_ELGAMAL_BITS / 8 * ks->num_peers +
918                   GNUNET_CRYPTO_PAILLIER_BITS / 8 * 2 * ks->num_peers +
919                   GNUNET_SECRETSHARING_ELGAMAL_BITS / 8 * ks->threshold);
920
921   if (element->size != expected_element_size)
922   {
923     GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
924                 "keygen round2 data with wrong size (%u) in consensus, "
925                 " %u expected\n",
926                 element->size, expected_element_size);
927     return;
928   }
929
930   d = (const void *) element->data;
931
932   info = get_keygen_peer_info (ks, &d->peer);
933
934   if (NULL == info)
935   {
936     GNUNET_log (GNUNET_ERROR_TYPE_WARNING, "keygen commit data with wrong peer identity (%s) in consensus\n",
937                 GNUNET_i2s (&d->peer));
938     return;
939   }
940
941   if (GNUNET_NO == info->round1_valid)
942   {
943     GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
944                 "ignoring round2 element from peer with invalid round1 element (%s)\n",
945                 GNUNET_i2s (&d->peer));
946     return;
947   }
948
949   if (GNUNET_YES == info->round2_valid)
950   {
951     GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
952                 "ignoring duplicate round2 element (%s)\n",
953                 GNUNET_i2s (&d->peer));
954     return;
955   }
956
957   GNUNET_log (GNUNET_ERROR_TYPE_INFO, "got round2 element\n");
958
959   pos = (void *) &d[1];
960   // skip exponentiated pre-shares
961   pos += GNUNET_SECRETSHARING_ELGAMAL_BITS / 8 * ks->num_peers;
962   // skip encrypted pre-shares
963   pos += GNUNET_CRYPTO_PAILLIER_BITS * 2 / 8 * ks->num_peers;
964   // the first exponentiated coefficient is the public key share
965   GNUNET_CRYPTO_mpi_scan_unsigned (&info->public_key_share, pos, GNUNET_SECRETSHARING_ELGAMAL_BITS / 8);
966
967   pos = (void *) &d[1];
968   // skip exp. pre-shares
969   pos += GNUNET_SECRETSHARING_ELGAMAL_BITS / 8 * ks->num_peers;
970   // skip to the encrypted value for our peer
971   pos += GNUNET_CRYPTO_PAILLIER_BITS * 2 / 8 * ks->local_peer_idx;
972
973   GNUNET_CRYPTO_paillier_decrypt (&ks->paillier_private_key, &ks->info[ks->local_peer_idx].paillier_public_key,
974                                   (struct GNUNET_CRYPTO_PaillierCiphertext *) pos, &plaintext);
975   GNUNET_CRYPTO_mpi_scan_unsigned (&info->decrypted_preshare, &plaintext,
976                                    sizeof plaintext);
977
978   // TODO: validate zero knowledge proofs
979
980   if (ntohl (d->purpose.size) !=
981       element->size - offsetof (struct GNUNET_SECRETSHARING_KeygenRevealData, purpose))
982   {
983     GNUNET_log (GNUNET_ERROR_TYPE_WARNING, "keygen reveal data with wrong signature purpose size in consensus\n");
984     return;
985   }
986
987   if (GNUNET_OK != GNUNET_CRYPTO_eddsa_verify (GNUNET_SIGNATURE_PURPOSE_SECRETSHARING_DKG2,
988                                                &d->purpose, &d->signature, &d->peer.public_key))
989   {
990     GNUNET_log (GNUNET_ERROR_TYPE_WARNING, "keygen reveal data with invalid signature in consensus\n");
991     return;
992   }
993   
994   info->round2_valid = GNUNET_YES;
995 }
996
997
998 /**
999  * Called when the first consensus round has concluded.
1000  * Will initiate the second round.
1001  *
1002  * @param cls closure
1003  */
1004 static void
1005 keygen_round1_conclude (void *cls)
1006 {
1007   struct KeygenSession *ks = cls;
1008
1009   GNUNET_CONSENSUS_destroy (ks->consensus);
1010
1011   ks->consensus = GNUNET_CONSENSUS_create (cfg, ks->num_peers, ks->peers, &ks->session_id,
1012                                            keygen_round2_new_element, ks);
1013
1014   insert_round2_element (ks);
1015
1016   GNUNET_CONSENSUS_conclude (ks->consensus,
1017                              /* last round, thus conclude at DKG deadline */
1018                              ks->deadline,
1019                              keygen_round2_conclude,
1020                              ks);
1021 }
1022
1023
1024 /**
1025  * Insert the ephemeral key and the presecret commitment
1026  * of this peer in the consensus of the given session.
1027  *
1028  * @param ks session to use
1029  */
1030 static void
1031 insert_round1_element (struct KeygenSession *ks)
1032 {
1033   struct GNUNET_SET_Element *element;
1034   struct GNUNET_SECRETSHARING_KeygenCommitData *d;
1035   // g^a_{i,0}
1036   gcry_mpi_t v;
1037   // big-endian representation of 'v'
1038   unsigned char v_data[GNUNET_SECRETSHARING_ELGAMAL_BITS / 8];
1039
1040   element = GNUNET_malloc (sizeof *element + sizeof *d);
1041   d = (void *) &element[1];
1042   element->data = d;
1043   element->size = sizeof *d;
1044
1045   d->peer = my_peer;
1046
1047   GNUNET_assert (0 != (v = gcry_mpi_new (GNUNET_SECRETSHARING_ELGAMAL_BITS)));
1048
1049   gcry_mpi_powm (v, elgamal_g, ks->presecret_polynomial[0], elgamal_p);
1050
1051   GNUNET_CRYPTO_mpi_print_unsigned (v_data, GNUNET_SECRETSHARING_ELGAMAL_BITS / 8, v);
1052
1053   GNUNET_CRYPTO_hash (v_data, GNUNET_SECRETSHARING_ELGAMAL_BITS / 8, &d->commitment);
1054
1055   d->pubkey = ks->info[ks->local_peer_idx].paillier_public_key;
1056
1057   d->purpose.size = htonl ((sizeof *d) - offsetof (struct GNUNET_SECRETSHARING_KeygenCommitData, purpose));
1058   d->purpose.purpose = htonl (GNUNET_SIGNATURE_PURPOSE_SECRETSHARING_DKG1);
1059   GNUNET_assert (GNUNET_OK == GNUNET_CRYPTO_eddsa_sign (my_peer_private_key, &d->purpose, &d->signature));
1060
1061   GNUNET_CONSENSUS_insert (ks->consensus, element, NULL, NULL);
1062
1063   gcry_mpi_release (v);
1064   GNUNET_free (element);
1065 }
1066
1067
1068 /**
1069  * Functions with this signature are called whenever a message is
1070  * received.
1071  *
1072  * @param cls closure
1073  * @param client identification of the client
1074  * @param message the actual message
1075  */
1076 static void handle_client_keygen (void *cls,
1077                                   struct GNUNET_SERVER_Client *client,
1078                                   const struct GNUNET_MessageHeader
1079                                   *message)
1080 {
1081   const struct GNUNET_SECRETSHARING_CreateMessage *msg =
1082       (const struct GNUNET_SECRETSHARING_CreateMessage *) message;
1083   struct KeygenSession *ks;
1084   unsigned int i;
1085
1086   GNUNET_log (GNUNET_ERROR_TYPE_INFO, "client requested key generation\n");
1087
1088   ks = GNUNET_new (struct KeygenSession);
1089
1090   /* FIXME: check if client already has some session */
1091
1092   GNUNET_CONTAINER_DLL_insert (keygen_sessions_head, keygen_sessions_tail, ks);
1093
1094   ks->client = client;
1095   ks->client_mq = GNUNET_MQ_queue_for_server_client (client);
1096
1097   ks->deadline = GNUNET_TIME_absolute_ntoh (msg->deadline);
1098   ks->threshold = ntohs (msg->threshold);
1099   ks->num_peers = ntohs (msg->num_peers);
1100
1101   ks->peers = normalize_peers ((struct GNUNET_PeerIdentity *) &msg[1], ks->num_peers,
1102                                &ks->num_peers, &ks->local_peer_idx);
1103
1104
1105   GNUNET_log (GNUNET_ERROR_TYPE_INFO, "first round of consensus with %u peers\n", ks->num_peers);
1106   ks->consensus = GNUNET_CONSENSUS_create (cfg, ks->num_peers, ks->peers, &msg->session_id,
1107                                            keygen_round1_new_element, ks);
1108
1109   ks->info = GNUNET_new_array (ks->num_peers, struct KeygenPeerInfo);
1110
1111   for (i = 0; i < ks->num_peers; i++)
1112     ks->info[i].peer = ks->peers[i];
1113
1114   GNUNET_CRYPTO_paillier_create (&ks->info[ks->local_peer_idx].paillier_public_key,
1115                                  &ks->paillier_private_key);
1116
1117   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "P%u: Generated paillier key pair\n", ks->local_peer_idx);
1118
1119   generate_presecret_polynomial (ks);
1120
1121   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "P%u: Generated presecret polynomial\n", ks->local_peer_idx);
1122
1123   insert_round1_element (ks);
1124
1125   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "P%u: Concluding for round 1\n", ks->local_peer_idx);
1126
1127   GNUNET_CONSENSUS_conclude (ks->consensus,
1128                              /* half the overall time */
1129                              time_between (ks->start_time, ks->deadline, 1, 2),
1130                              keygen_round1_conclude,
1131                              ks);
1132
1133   GNUNET_SERVER_receive_done (client, GNUNET_OK);
1134
1135   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "P%u: Waiting for round 1 elements ...\n", ks->local_peer_idx);
1136 }
1137
1138
1139 /**
1140  * Called when the partial decryption consensus concludes.
1141  */
1142 static void
1143 decrypt_conclude (void *cls)
1144 {
1145   struct DecryptSession *ds = cls;
1146   struct GNUNET_SECRETSHARING_DecryptResponseMessage *msg;
1147   struct GNUNET_MQ_Envelope *ev;
1148   gcry_mpi_t lagrange;
1149   gcry_mpi_t m;
1150   gcry_mpi_t tmp;
1151   gcry_mpi_t c_2;
1152   gcry_mpi_t prod;
1153   unsigned int *indices;
1154   unsigned int num;
1155   unsigned int i;
1156   unsigned int j;
1157
1158   GNUNET_assert (0 != (lagrange = gcry_mpi_new (0)));
1159   GNUNET_assert (0 != (m = gcry_mpi_new (0)));
1160   GNUNET_assert (0 != (tmp = gcry_mpi_new (0)));
1161   GNUNET_assert (0 != (prod = gcry_mpi_new (0)));
1162
1163   num = 0;
1164   for (i = 0; i < ds->share->num_peers; i++)
1165     if (NULL != ds->info[i].partial_decryption)
1166       num++;
1167
1168   indices = GNUNET_malloc (num * sizeof (unsigned int));
1169   j = 0;
1170   for (i = 0; i < ds->share->num_peers; i++)
1171     if (NULL != ds->info[i].partial_decryption)
1172       indices[j++] = ds->info[i].original_index;
1173
1174   GNUNET_log (GNUNET_ERROR_TYPE_INFO, "P%u: decrypt conclude, with %u peers\n",
1175               ds->share->my_peer, num);
1176
1177   gcry_mpi_set_ui (prod, 1);
1178   for (i = 0; i < num; i++)
1179   {
1180
1181     GNUNET_log (GNUNET_ERROR_TYPE_INFO, "P%u: index of %u: %u\n",
1182                 ds->share->my_peer, i, indices[i]);
1183     compute_lagrange_coefficient (lagrange, indices[i], indices, num);
1184     // w_i^{\lambda_i}
1185     gcry_mpi_powm (tmp, ds->info[indices[i]].partial_decryption, lagrange, elgamal_p);
1186
1187     // product of all exponentiated partiel decryptions ...
1188     gcry_mpi_mulm (prod, prod, tmp, elgamal_p);
1189   }
1190
1191   GNUNET_CRYPTO_mpi_scan_unsigned (&c_2, ds->ciphertext.c2_bits, GNUNET_SECRETSHARING_ELGAMAL_BITS / 8);
1192
1193   GNUNET_assert (0 != gcry_mpi_invm (prod, prod, elgamal_p));
1194   gcry_mpi_mulm (m, c_2, prod, elgamal_p);
1195   ev = GNUNET_MQ_msg (msg, GNUNET_MESSAGE_TYPE_SECRETSHARING_CLIENT_DECRYPT_DONE);
1196   GNUNET_CRYPTO_mpi_print_unsigned (&msg->plaintext, GNUNET_SECRETSHARING_ELGAMAL_BITS / 8, m);
1197   msg->success = htonl (1);
1198   GNUNET_MQ_send (ds->client_mq, ev);
1199
1200   GNUNET_log (GNUNET_ERROR_TYPE_INFO, "sent decrypt done to client\n");
1201
1202   // FIXME: what if not enough peers participated?
1203 }
1204
1205
1206 /**
1207  * Called when a new partial decryption arrives.
1208  */
1209 static void
1210 decrypt_new_element (void *cls,
1211                      const struct GNUNET_SET_Element *element)
1212 {
1213   struct DecryptSession *session = cls;
1214   const struct GNUNET_SECRETSHARING_DecryptData *d;
1215   struct DecryptPeerInfo *info;
1216
1217   if (NULL == element)
1218   {
1219     GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "decryption failed\n");
1220     /* FIXME: destroy */
1221     return;
1222   }
1223
1224   if (element->size != sizeof *d)
1225   {
1226     GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "element of wrong size in decrypt consensus\n");
1227     return;
1228   }
1229
1230   d = element->data;
1231
1232   info = get_decrypt_peer_info (session, &d->peer);
1233   
1234   if (NULL == info)
1235   {
1236     GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "decrypt element from invalid peer (%s)\n",
1237                 GNUNET_i2s (&d->peer));
1238     return;
1239   }
1240
1241   if (NULL != info->partial_decryption)
1242   {
1243     GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "decrypt element duplicate\n",
1244                 GNUNET_i2s (&d->peer));
1245     return;
1246   }
1247
1248   // FIXME: check NIZP first
1249
1250   GNUNET_CRYPTO_mpi_scan_unsigned (&info->partial_decryption, &d->partial_decryption,
1251                                    GNUNET_SECRETSHARING_ELGAMAL_BITS / 8);
1252 }
1253
1254 static void
1255 insert_decrypt_element (struct DecryptSession *ds)
1256 {
1257   struct GNUNET_SECRETSHARING_DecryptData d;
1258   struct GNUNET_SET_Element element;
1259   gcry_mpi_t x;
1260   gcry_mpi_t s;
1261
1262   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "P%u: Inserting decrypt element\n",
1263               ds->share->my_peer);
1264
1265   GNUNET_CRYPTO_mpi_scan_unsigned (&x, &ds->ciphertext.c1_bits,
1266                                    GNUNET_SECRETSHARING_ELGAMAL_BITS / 8);
1267   GNUNET_CRYPTO_mpi_scan_unsigned (&s, &ds->share->my_share,
1268                                    GNUNET_SECRETSHARING_ELGAMAL_BITS / 8);
1269
1270   gcry_mpi_powm (x, x, s, elgamal_p);
1271
1272   element.data = (void *) &d;
1273   element.size = sizeof (struct GNUNET_SECRETSHARING_DecryptData);
1274   element.type = 0;
1275
1276   /* make vagrind happy until we implement the real deal ... */
1277   memset (&d.nizk_commit1, 0, sizeof d.nizk_commit1);
1278   memset (&d.nizk_commit2, 0, sizeof d.nizk_commit2);
1279   memset (&d.nizk_response, 0, sizeof d.nizk_response);
1280
1281   d.ciphertext = ds->ciphertext;
1282   d.peer = my_peer;
1283   d.purpose.size = htonl (element.size - offsetof (struct GNUNET_SECRETSHARING_DecryptData, purpose));
1284   d.purpose.purpose = htonl (GNUNET_SIGNATURE_PURPOSE_SECRETSHARING_DECRYPTION);
1285   
1286   GNUNET_CRYPTO_eddsa_sign (my_peer_private_key, &d.purpose, &d.signature);
1287
1288   GNUNET_CRYPTO_mpi_print_unsigned (&d.partial_decryption, GNUNET_SECRETSHARING_ELGAMAL_BITS / 8, x);
1289
1290   GNUNET_CONSENSUS_insert (ds->consensus, &element, NULL, NULL);
1291   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "P%u: Inserting decrypt element done!\n",
1292               ds->share->my_peer);
1293 }
1294
1295
1296 /**
1297  * Functions with this signature are called whenever a message is
1298  * received.
1299  *
1300  * @param cls closure
1301  * @param client identification of the client
1302  * @param message the actual message
1303  */
1304 static void handle_client_decrypt (void *cls,
1305                                    struct GNUNET_SERVER_Client *client,
1306                                    const struct GNUNET_MessageHeader
1307                                    *message)
1308 {
1309   const struct GNUNET_SECRETSHARING_DecryptRequestMessage *msg =
1310       (const void *) message;
1311   struct DecryptSession *ds;
1312   struct GNUNET_HashCode session_id;
1313   unsigned int i;
1314
1315   ds = GNUNET_new (struct DecryptSession);
1316   // FIXME: check if session already exists
1317   GNUNET_CONTAINER_DLL_insert (decrypt_sessions_head, decrypt_sessions_tail, ds);
1318   ds->client = client;
1319   ds->client_mq = GNUNET_MQ_queue_for_server_client (client);
1320   ds->deadline = GNUNET_TIME_absolute_ntoh (msg->deadline);
1321   ds->ciphertext = msg->ciphertext;
1322
1323   ds->share = GNUNET_SECRETSHARING_share_read (&msg[1], ntohs (msg->header.size) - sizeof *msg, NULL);
1324   // FIXME: probably should be break rather than assert
1325   GNUNET_assert (NULL != ds->share);
1326
1327   // FIXME: this is probably sufficient, but kdf/hash with all values would be nicer ...
1328   GNUNET_CRYPTO_hash (&msg->ciphertext, sizeof (struct GNUNET_SECRETSHARING_Ciphertext), &session_id);
1329
1330   ds->consensus = GNUNET_CONSENSUS_create (cfg,
1331                                            ds->share->num_peers,
1332                                            ds->share->peers,
1333                                            &session_id,
1334                                            &decrypt_new_element,
1335                                            ds);
1336
1337
1338   ds->info = GNUNET_new_array (ds->share->num_peers, struct DecryptPeerInfo);
1339   for (i = 0; i < ds->share->num_peers; i++)
1340   {
1341     ds->info[i].peer = ds->share->peers[i];
1342     ds->info[i].original_index = ds->share->original_indices[i];
1343   }
1344
1345   insert_decrypt_element (ds);
1346
1347   GNUNET_CONSENSUS_conclude (ds->consensus, ds->deadline, decrypt_conclude, ds);
1348
1349   GNUNET_SERVER_receive_done (client, GNUNET_OK);
1350
1351   GNUNET_log (GNUNET_ERROR_TYPE_INFO, "decrypting with %u peers\n",
1352               ds->share->num_peers);
1353 }
1354
1355
1356 static void
1357 init_crypto_constants (void)
1358 {
1359   GNUNET_assert (0 == gcry_mpi_scan (&elgamal_q, GCRYMPI_FMT_HEX,
1360                                      GNUNET_SECRETSHARING_ELGAMAL_Q_HEX, 0, NULL));
1361   GNUNET_assert (0 == gcry_mpi_scan (&elgamal_p, GCRYMPI_FMT_HEX,
1362                                      GNUNET_SECRETSHARING_ELGAMAL_P_HEX, 0, NULL));
1363   GNUNET_assert (0 == gcry_mpi_scan (&elgamal_g, GCRYMPI_FMT_HEX,
1364                                      GNUNET_SECRETSHARING_ELGAMAL_G_HEX, 0, NULL));
1365 }
1366
1367
1368 static struct KeygenSession *
1369 keygen_session_get (struct GNUNET_SERVER_Client *client)
1370 {
1371   struct KeygenSession *ks;
1372   for (ks = keygen_sessions_head; NULL != ks; ks = ks->next)
1373     if (ks->client == client)
1374       return ks;
1375   return NULL;
1376 }
1377
1378 static struct DecryptSession *
1379 decrypt_session_get (struct GNUNET_SERVER_Client *client)
1380 {
1381   struct DecryptSession *ds;
1382   for (ds = decrypt_sessions_head; NULL != ds; ds = ds->next)
1383     if (ds->client == client)
1384       return ds;
1385   return NULL;
1386 }
1387
1388
1389 /**
1390  * Clean up after a client has disconnected
1391  *
1392  * @param cls closure, unused
1393  * @param client the client to clean up after
1394  */
1395 static void
1396 handle_client_disconnect (void *cls, struct GNUNET_SERVER_Client *client)
1397 {
1398   struct KeygenSession *ks;
1399   struct DecryptSession *ds;
1400
1401   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "handling client disconnect\n");
1402
1403   ks = keygen_session_get (client);
1404   if (NULL != ks)
1405     keygen_session_destroy (ks);
1406
1407   ds = decrypt_session_get (client);
1408   if (NULL != ds)
1409     decrypt_session_destroy (ds);
1410 }
1411
1412
1413 /**
1414  * Process template requests.
1415  *
1416  * @param cls closure
1417  * @param server the initialized server
1418  * @param c configuration to use
1419  */
1420 static void
1421 run (void *cls, struct GNUNET_SERVER_Handle *server,
1422      const struct GNUNET_CONFIGURATION_Handle *c)
1423 {
1424   static const struct GNUNET_SERVER_MessageHandler handlers[] = {
1425     {handle_client_keygen, NULL, GNUNET_MESSAGE_TYPE_SECRETSHARING_CLIENT_GENERATE, 0},
1426     {handle_client_decrypt, NULL, GNUNET_MESSAGE_TYPE_SECRETSHARING_CLIENT_DECRYPT, 0},
1427     {NULL, NULL, 0, 0}
1428   };
1429   cfg = c;
1430   srv = server;
1431   my_peer_private_key = GNUNET_CRYPTO_eddsa_key_create_from_configuration (c);
1432   if (NULL == my_peer_private_key)
1433   {
1434     GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "could not access host private key\n");
1435     GNUNET_break (0);
1436     GNUNET_SCHEDULER_shutdown ();
1437     return;
1438   }
1439   init_crypto_constants ();
1440   if (GNUNET_OK != GNUNET_CRYPTO_get_peer_identity (cfg, &my_peer))
1441   {
1442     GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "could not retrieve host identity\n");
1443     GNUNET_break (0);
1444     GNUNET_SCHEDULER_shutdown ();
1445     return;
1446   }
1447   GNUNET_SERVER_add_handlers (server, handlers);
1448   GNUNET_SERVER_disconnect_notify (server, &handle_client_disconnect, NULL);
1449   GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_FOREVER_REL, &cleanup_task,
1450                                 NULL);
1451 }
1452
1453
1454 /**
1455  * The main function for the template service.
1456  *
1457  * @param argc number of arguments from the command line
1458  * @param argv command line arguments
1459  * @return 0 ok, 1 on error
1460  */
1461 int
1462 main (int argc, char *const *argv)
1463 {
1464   return (GNUNET_OK ==
1465           GNUNET_SERVICE_run (argc, argv, "secretsharing",
1466                               GNUNET_SERVICE_OPTION_NONE, &run, NULL)) ? 0 : 1;
1467 }
1468