2 This file is part of GNUnet.
3 (C) 2013 Christian Grothoff (and other contributing authors)
5 GNUnet is free software; you can redistribute it and/or modify
6 it under the terms of the GNU General Public License as published
7 by the Free Software Foundation; either version 3, or (at your
8 option) any later version.
10 GNUnet is distributed in the hope that it will be useful, but
11 WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 General Public License for more details.
15 You should have received a copy of the GNU General Public License
16 along with GNUnet; see the file COPYING. If not, write to the
17 Free Software Foundation, Inc., 59 Temple Place - Suite 330,
18 Boston, MA 02111-1307, USA.
22 * @file secretsharing/gnunet-service-secretsharing.c
23 * @brief secret sharing service
24 * @author Florian Dold
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"
36 #define EXTRA_CHECKS 1
40 * Info about a peer in a key generation session.
45 * Peer identity of the peer.
47 struct GNUNET_PeerIdentity peer;
50 * The peer's paillier public key.
51 * Freshly generated for each keygen session.
53 gcry_mpi_t paillier_n;
56 * The peer's commitment to his presecret.
58 gcry_mpi_t presecret_commitment;
61 * The peer's preshare that we decrypted
62 * with out private key.
64 gcry_mpi_t decrypted_preshare;
67 * Multiplicative share of the public key.
69 gcry_mpi_t public_key_share;
72 * Did we successfully receive the round1 element
78 * Did we successfully receive the round2 element
86 * Information about a peer in a decrypt session.
88 struct DecryptPeerInfo
91 * Identity of the peer.
93 struct GNUNET_PeerIdentity peer;
96 * Original index in the key generation round.
97 * Necessary for computing the lagrange coefficients.
99 unsigned int original_index;
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.
107 gcry_mpi_t partial_decryption;
112 * Session to establish a threshold-shared secret.
117 * Keygen sessions are held in a linked list.
119 struct KeygenSession *next;
122 * Keygen sessions are held in a linked list.
124 struct KeygenSession *prev;
127 * Current consensus, used for both DKG rounds.
129 struct GNUNET_CONSENSUS_Handle *consensus;
132 * Client that is interested in the result
133 * of this key generation session.
135 struct GNUNET_SERVER_Client *client;
138 * Message queue for 'client'
140 struct GNUNET_MQ_Handle *client_mq;
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.
148 * The pre-secret-shares 'i=1,...,num_peers' are given by evaluating this
149 * polyomial at 'i' for share i.
151 gcry_mpi_t *presecret_polynomial;
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.
158 unsigned int threshold;
161 * Total number of peers.
163 unsigned int num_peers;
166 * Index of the local peer.
168 unsigned int local_peer;
171 * Information about all participating peers.
172 * Array of size 'num_peers'.
174 struct KeygenPeerInfo *info;
177 * List of all peers involved in the secret sharing session.
179 struct GNUNET_PeerIdentity *peers;
182 * Identifier for this session.
184 struct GNUNET_HashCode session_id;
187 * lambda-component of our peer's paillier private key.
189 gcry_mpi_t paillier_lambda;
192 * mu-component of our peer's paillier private key.
194 gcry_mpi_t paillier_mu;
197 * When would we like the key to be established?
199 struct GNUNET_TIME_Absolute deadline;
202 * When does the DKG start? Necessary to compute fractions of the
203 * operation's desired time interval.
205 struct GNUNET_TIME_Absolute start_time;
208 * Index of the local peer in the ordered list
209 * of peers in the session.
211 unsigned int local_peer_idx;
216 * Session to cooperatively decrypt a value.
218 struct DecryptSession
221 * Decrypt sessions are stored in a linked list.
223 struct DecryptSession *next;
226 * Decrypt sessions are stored in a linked list.
228 struct DecryptSession *prev;
231 * Handle to the consensus over partial decryptions.
233 struct GNUNET_CONSENSUS_Handle *consensus;
236 * Client connected to us.
238 struct GNUNET_SERVER_Client *client;
241 * Message queue for 'client'.
243 struct GNUNET_MQ_Handle *client_mq;
246 * When would we like the ciphertext to be
249 struct GNUNET_TIME_Absolute deadline;
252 * Ciphertext we want to decrypt.
254 struct GNUNET_SECRETSHARING_Ciphertext ciphertext;
257 * Share of the local peer.
258 * Containts other important information, such as
259 * the list of other peers.
261 struct GNUNET_SECRETSHARING_Share *share;
264 * State information about other peers.
266 struct DecryptPeerInfo *info;
271 * Decrypt sessions are held in a linked list.
273 static struct DecryptSession *decrypt_sessions_head;
276 * Decrypt sessions are held in a linked list.
278 static struct DecryptSession *decrypt_sessions_tail;
281 * Decrypt sessions are held in a linked list.
283 static struct KeygenSession *keygen_sessions_head;
286 * Decrypt sessions are held in a linked list.
288 static struct KeygenSession *keygen_sessions_tail;
291 * The ElGamal prime field order as libgcrypt mpi.
292 * Initialized in #init_crypto_constants.
294 static gcry_mpi_t elgamal_q;
297 * Modulus of the prime field used for ElGamal.
298 * Initialized in #init_crypto_constants.
300 static gcry_mpi_t elgamal_p;
303 * Generator for prime field of order 'elgamal_q'.
304 * Initialized in #init_crypto_constants.
306 static gcry_mpi_t elgamal_g;
309 * Peer that runs this service.
311 static struct GNUNET_PeerIdentity my_peer;
314 * Peer that runs this service.
316 static struct GNUNET_CRYPTO_EddsaPrivateKey *my_peer_private_key;
319 * Configuration of this service.
321 static const struct GNUNET_CONFIGURATION_Handle *cfg;
324 * Server for this service.
326 static struct GNUNET_SERVER_Handle *srv;
330 * Get the peer info belonging to a peer identity in a keygen session.
332 * @param ks The keygen session.
333 * @param peer The peer identity.
334 * @return The Keygen peer info, or NULL if the peer could not be found.
336 static struct KeygenPeerInfo *
337 get_keygen_peer_info (const struct KeygenSession *ks,
338 const struct GNUNET_PeerIdentity *peer)
341 for (i = 0; i < ks->num_peers; i++)
342 if (0 == memcmp (peer, &ks->info[i].peer, sizeof (struct GNUNET_PeerIdentity)))
349 * Get the peer info belonging to a peer identity in a decrypt session.
351 * @param ds The decrypt session.
352 * @param peer The peer identity.
353 * @return The decrypt peer info, or NULL if the peer could not be found.
355 static struct DecryptPeerInfo *
356 get_decrypt_peer_info (const struct DecryptSession *ds,
357 const struct GNUNET_PeerIdentity *peer)
360 for (i = 0; i < ds->share->num_peers; i++)
361 if (0 == memcmp (peer, &ds->info[i].peer, sizeof (struct GNUNET_PeerIdentity)))
368 * Interpolate between two points in time.
370 * @param start start time
371 * @param end end time
372 * @param num numerator of the scale factor
373 * @param denum denumerator of the scale factor
375 static struct GNUNET_TIME_Absolute
376 time_between (struct GNUNET_TIME_Absolute start,
377 struct GNUNET_TIME_Absolute end,
380 struct GNUNET_TIME_Absolute result;
383 GNUNET_assert (start.abs_value_us <= end.abs_value_us);
384 diff = end.abs_value_us - start.abs_value_us;
385 result.abs_value_us = start.abs_value_us + ((diff * num) / denum);
392 * Compare two peer identities. Indended to be used with qsort or bsearch.
394 * @param p1 Some peer identity.
395 * @param p2 Some peer identity.
396 * @return 1 if p1 > p2, -1 if p1 < p2 and 0 if p1 == p2.
399 peer_id_cmp (const void *p1, const void *p2)
401 return memcmp (p1, p2, sizeof (struct GNUNET_PeerIdentity));
406 * Get the index of a peer in an array of peers
408 * @param haystack Array of peers.
409 * @param n Size of @a haystack.
410 * @param needle Peer to find
411 * @return Index of @a needle in @a haystack, or -1 if peer
412 * is not in the list.
415 peer_find (const struct GNUNET_PeerIdentity *haystack, unsigned int n,
416 const struct GNUNET_PeerIdentity *needle)
419 for (i = 0; i < n; i++)
420 if (0 == memcmp (&haystack[i], needle, sizeof (struct GNUNET_PeerIdentity)))
427 * Normalize the given list of peers, by including the local peer
428 * (if it is missing) and sorting the peers by their identity.
430 * @param listed Peers in the unnormalized list.
431 * @param num_listed Peers in the un-normalized list.
432 * @param[out] num_normalized Number of peers in the normalized list.
433 * @param[out] my_peer_idx Index of the local peer in the normalized list.
434 * @return Normalized list, must be free'd by the caller.
436 static struct GNUNET_PeerIdentity *
437 normalize_peers (struct GNUNET_PeerIdentity *listed,
438 unsigned int num_listed,
439 unsigned int *num_normalized,
440 unsigned int *my_peer_idx)
442 unsigned int local_peer_in_list;
443 /* number of peers in the normalized list */
445 struct GNUNET_PeerIdentity *normalized;
447 local_peer_in_list = GNUNET_YES;
449 if (peer_find (listed, num_listed, &my_peer) < 0)
451 local_peer_in_list = GNUNET_NO;
455 normalized = GNUNET_new_array (n, struct GNUNET_PeerIdentity);
457 if (GNUNET_NO == local_peer_in_list)
458 normalized[n - 1] = my_peer;
460 memcpy (normalized, listed, num_listed * sizeof (struct GNUNET_PeerIdentity));
461 qsort (normalized, n, sizeof (struct GNUNET_PeerIdentity), &peer_id_cmp);
463 if (NULL != my_peer_idx)
464 *my_peer_idx = peer_find (normalized, n, &my_peer);
465 if (NULL != num_normalized)
473 * Get a the j-th lagrange coefficient for a set of indices.
475 * @param[out] coeff the lagrange coefficient
476 * @param j lagrange coefficient we want to compute
477 * @param indices indices
478 * @param num number of indices in @a indices
481 compute_lagrange_coefficient (gcry_mpi_t coeff, unsigned int j,
482 unsigned int *indices,
490 /* temp value for l-j */
493 GNUNET_assert (0 != coeff);
495 GNUNET_assert (0 != (n = gcry_mpi_new (0)));
496 GNUNET_assert (0 != (d = gcry_mpi_new (0)));
497 GNUNET_assert (0 != (tmp = gcry_mpi_new (0)));
499 gcry_mpi_set_ui (n, 1);
500 gcry_mpi_set_ui (d, 1);
502 for (i = 0; i < num; i++)
504 unsigned int l = indices[i];
507 gcry_mpi_mul_ui (n, n, l + 1);
509 gcry_mpi_set_ui (tmp, l + 1);
510 gcry_mpi_sub_ui (tmp, tmp, j + 1);
511 gcry_mpi_mul (d, d, tmp);
514 // gcry_mpi_invm does not like negative numbers ...
515 gcry_mpi_mod (d, d, elgamal_q);
517 GNUNET_assert (gcry_mpi_cmp_ui (d, 0) > 0);
519 // now we do the actual division, with everything mod q, as we
520 // are not operating on elements from <g>, but on exponents
521 GNUNET_assert (0 != gcry_mpi_invm (d, d, elgamal_q));
523 gcry_mpi_mulm (coeff, n, d, elgamal_q);
525 gcry_mpi_release (n);
526 gcry_mpi_release (d);
527 gcry_mpi_release (tmp);
532 * Decrypt a ciphertext using Paillier's scheme.
534 * @param[out] m resulting plaintext
535 * @param c ciphertext to decrypt
536 * @param lambda lambda-component of private key
537 * @param mu mu-component of private key
538 * @param n n-component of public key
541 paillier_decrypt (gcry_mpi_t m, gcry_mpi_t c, gcry_mpi_t mu, gcry_mpi_t lambda, gcry_mpi_t n)
545 GNUNET_assert (0 != (n_square = gcry_mpi_new (0)));
547 gcry_mpi_mul (n_square, n, n);
548 // m = c^lambda mod n^2
549 gcry_mpi_powm (m, c, lambda, n_square);
551 gcry_mpi_sub_ui (m, m, 1);
553 gcry_mpi_div (m, NULL, m, n, 0);
554 gcry_mpi_mulm (m, m, mu, n);
555 gcry_mpi_release (n_square);
560 decrypt_session_destroy (struct DecryptSession *ds)
562 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "destroying decrypt session\n");
564 GNUNET_CONTAINER_DLL_remove (decrypt_sessions_head, decrypt_sessions_tail, ds);
566 if (NULL != ds->client_mq)
568 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "destroying decrypt MQ\n");
569 GNUNET_MQ_destroy (ds->client_mq);
570 ds->client_mq = NULL;
573 if (NULL != ds->client)
575 GNUNET_SERVER_client_disconnect (ds->client);
584 keygen_session_destroy (struct KeygenSession *ks)
586 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "destroying keygen session\n");
588 GNUNET_CONTAINER_DLL_remove (keygen_sessions_head, keygen_sessions_tail, ks);
590 if (NULL != ks->client_mq)
592 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "destroying keygen MQ\n");
593 GNUNET_MQ_destroy (ks->client_mq);
594 ks->client_mq = NULL;
597 if (NULL != ks->client)
599 GNUNET_SERVER_client_disconnect (ks->client);
608 * Task run during shutdown.
614 cleanup_task (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
616 while (NULL != decrypt_sessions_head)
617 decrypt_session_destroy (decrypt_sessions_head);
619 while (NULL != keygen_sessions_head)
620 keygen_session_destroy (keygen_sessions_head);
625 * Generate the random coefficients of our pre-secret polynomial
627 * @param ks the session
630 generate_presecret_polynomial (struct KeygenSession *ks)
635 GNUNET_assert (NULL == ks->presecret_polynomial);
636 ks->presecret_polynomial = GNUNET_new_array (ks->threshold, gcry_mpi_t);
637 for (i = 0; i < ks->threshold; i++)
639 v = ks->presecret_polynomial[i] = gcry_mpi_new (GNUNET_SECRETSHARING_ELGAMAL_BITS);
640 GNUNET_assert (NULL != v);
641 // Randomize v such that 0 < v < elgamal_q.
642 // The '- 1' is necessary as bitlength(q) = bitlength(p) - 1.
645 gcry_mpi_randomize (v, GNUNET_SECRETSHARING_ELGAMAL_BITS - 1, GCRY_WEAK_RANDOM);
646 } while ((gcry_mpi_cmp_ui (v, 0) == 0) || (gcry_mpi_cmp (v, elgamal_q) >= 0));
652 * Consensus element handler for round one.
653 * We should get one ephemeral key for each peer.
655 * @param cls Closure (keygen session).
656 * @param element The element from consensus, or
657 * NULL if consensus failed.
660 keygen_round1_new_element (void *cls,
661 const struct GNUNET_SET_Element *element)
663 const struct GNUNET_SECRETSHARING_KeygenCommitData *d;
664 struct KeygenSession *ks = cls;
665 struct KeygenPeerInfo *info;
669 GNUNET_log (GNUNET_ERROR_TYPE_WARNING, "round1 consensus failed\n");
673 /* elements have fixed size */
674 if (element->size != sizeof (struct GNUNET_SECRETSHARING_KeygenCommitData))
676 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
677 "keygen commit data with wrong size (%u) in consensus, "
679 element->size, sizeof (struct GNUNET_SECRETSHARING_KeygenCommitData));
683 GNUNET_log (GNUNET_ERROR_TYPE_INFO, "got round1 element\n");
686 info = get_keygen_peer_info (ks, &d->peer);
690 GNUNET_log (GNUNET_ERROR_TYPE_WARNING, "keygen commit data with wrong peer identity (%s) in consensus\n",
691 GNUNET_i2s (&d->peer));
695 /* Check that the right amount of data has been signed. */
696 if (d->purpose.size !=
697 htonl (element->size - offsetof (struct GNUNET_SECRETSHARING_KeygenCommitData, purpose)))
699 GNUNET_log (GNUNET_ERROR_TYPE_WARNING, "keygen commit data with wrong signature purpose size in consensus\n");
703 if (GNUNET_OK != GNUNET_CRYPTO_eddsa_verify (GNUNET_SIGNATURE_PURPOSE_SECRETSHARING_DKG1,
704 &d->purpose, &d->signature, &d->peer.public_key))
706 GNUNET_log (GNUNET_ERROR_TYPE_WARNING, "keygen commit data with invalid signature in consensus\n");
709 GNUNET_CRYPTO_mpi_scan_unsigned (&info->paillier_n, &d->pubkey.n, GNUNET_CRYPTO_PAILLIER_BITS / 8);
710 GNUNET_CRYPTO_mpi_scan_unsigned (&info->presecret_commitment, &d->pubkey.n, GNUNET_CRYPTO_PAILLIER_BITS / 8);
711 info->round1_valid = GNUNET_YES;
716 * Evaluate the polynomial with coefficients @a coeff at @a x.
717 * The i-th element in @a coeff corresponds to the coefficient of x^i.
719 * @param[out] z result of the evaluation
720 * @param coeff array of coefficients
721 * @param num_coeff number of coefficients
722 * @param x where to evaluate the polynomial
723 * @param m what group are we operating in?
726 horner_eval (gcry_mpi_t z, gcry_mpi_t *coeff, unsigned int num_coeff, gcry_mpi_t x, gcry_mpi_t m)
730 gcry_mpi_set_ui (z, 0);
731 for (i = 0; i < num_coeff; i++)
734 gcry_mpi_mul (z, z, x);
735 gcry_mpi_addm (z, z, coeff[num_coeff - i - 1], m);
741 keygen_round2_conclude (void *cls)
743 struct KeygenSession *ks = cls;
744 struct GNUNET_SECRETSHARING_SecretReadyMessage *m;
745 struct GNUNET_MQ_Envelope *ev;
749 struct GNUNET_SECRETSHARING_Share *share;
755 GNUNET_log (GNUNET_ERROR_TYPE_INFO, "round2 conclude\n");
757 GNUNET_assert (0 != (s = gcry_mpi_new (GNUNET_SECRETSHARING_ELGAMAL_BITS)));
758 GNUNET_assert (0 != (h = gcry_mpi_new (GNUNET_SECRETSHARING_ELGAMAL_BITS)));
760 // multiplicative identity
761 gcry_mpi_set_ui (h, 1);
763 gcry_mpi_set_ui (s, 0);
765 share = GNUNET_new (struct GNUNET_SECRETSHARING_Share);
767 share->num_peers = 0;
769 for (i = 0; i < ks->num_peers; i++)
770 if (GNUNET_YES == ks->info[i].round2_valid)
773 share->peers = GNUNET_new_array (share->num_peers, struct GNUNET_PeerIdentity);
774 share->hom_share_commitments =
775 GNUNET_new_array (share->num_peers, struct GNUNET_SECRETSHARING_FieldElement);
776 share->original_indices = GNUNET_new_array (share->num_peers, uint16_t);
778 /* maybe we're not even in the list of peers? */
779 share->my_peer = share->num_peers;
782 for (i = 0; i < ks->num_peers; i++)
784 if (GNUNET_YES == ks->info[i].round2_valid)
786 gcry_mpi_addm (s, s, ks->info[i].decrypted_preshare, elgamal_p);
787 gcry_mpi_mulm (h, h, ks->info[i].public_key_share, elgamal_p);
788 share->peers[i] = ks->info[i].peer;
789 share->original_indices[i] = j++;
790 if (0 == memcmp (&share->peers[i], &my_peer, sizeof (struct GNUNET_PeerIdentity)))
795 GNUNET_CRYPTO_mpi_print_unsigned (&share->my_share, GNUNET_SECRETSHARING_ELGAMAL_BITS / 8, s);
796 GNUNET_CRYPTO_mpi_print_unsigned (&share->public_key, GNUNET_SECRETSHARING_ELGAMAL_BITS / 8, h);
798 GNUNET_log (GNUNET_ERROR_TYPE_INFO, "keygen completed with %u peers\n", share->num_peers);
800 /* Write the share. If 0 peers completed the dkg, an empty
801 * share will be sent. */
803 m = GNUNET_malloc (sizeof (struct GNUNET_SECRETSHARING_SecretReadyMessage) +
804 ks->num_peers * sizeof (struct GNUNET_PeerIdentity));
806 GNUNET_assert (GNUNET_OK == GNUNET_SECRETSHARING_share_write (share, NULL, 0, &share_size));
808 ev = GNUNET_MQ_msg_extra (m, share_size,
809 GNUNET_MESSAGE_TYPE_SECRETSHARING_CLIENT_SECRET_READY);
811 GNUNET_assert (GNUNET_OK == GNUNET_SECRETSHARING_share_write (share, &m[1], share_size, NULL));
813 GNUNET_MQ_send (ks->client_mq, ev);
818 * Insert round 2 element in the consensus, consisting of
819 * (1) The exponentiated pre-share polynomial coefficients A_{i,l}=g^{a_{i,l}}
820 * (2) The exponentiated pre-shares y_{i,j}=g^{s_{i,j}}
821 * (3) The encrypted pre-shares Y_{i,j}
822 * (4) The zero knowledge proof for correctness of
825 * @param ks session to use
828 insert_round2_element (struct KeygenSession *ks)
830 struct GNUNET_SET_Element *element;
831 struct GNUNET_SECRETSHARING_KeygenRevealData *d;
833 unsigned char *last_pos;
840 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "P%u: Inserting round2 element\n",
843 GNUNET_assert (NULL != (v = gcry_mpi_new (GNUNET_SECRETSHARING_ELGAMAL_BITS)));
844 GNUNET_assert (NULL != (idx = gcry_mpi_new (GNUNET_SECRETSHARING_ELGAMAL_BITS)));
845 GNUNET_assert (NULL != (c = gcry_mpi_new (GNUNET_SECRETSHARING_ELGAMAL_BITS)));
847 element_size = (sizeof (struct GNUNET_SECRETSHARING_KeygenRevealData) +
848 GNUNET_SECRETSHARING_ELGAMAL_BITS / 8 * ks->num_peers +
849 GNUNET_SECRETSHARING_ELGAMAL_BITS / 8 * ks->threshold +
850 GNUNET_CRYPTO_PAILLIER_BITS * 2 / 8 * ks->num_peers);
852 element = GNUNET_malloc (sizeof (struct GNUNET_SET_Element) + element_size);
853 element->size = element_size;
854 element->data = (void *) &element[1];
856 d = (void *) element->data;
859 // start inserting vector elements
860 // after the fixed part of the element's data
861 pos = (void *) &d[1];
862 last_pos = pos + element_size;
864 // exponentiated pre-shares
865 for (i = 0; i < ks->num_peers; i++)
867 ptrdiff_t remaining = last_pos - pos;
868 GNUNET_assert (remaining > 0);
869 gcry_mpi_set_ui (idx, i + 1);
870 // evaluate the polynomial
871 horner_eval (v, ks->presecret_polynomial, ks->threshold, idx, elgamal_q);
872 // take g to the result
873 gcry_mpi_powm (v, elgamal_g, v, elgamal_p);
874 GNUNET_CRYPTO_mpi_print_unsigned (pos, GNUNET_SECRETSHARING_ELGAMAL_BITS / 8, v);
875 pos += GNUNET_SECRETSHARING_ELGAMAL_BITS / 8;
878 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "P%u: computed exp preshares\n",
881 // encrypted pre-shares
882 for (i = 0; i < ks->num_peers; i++)
884 ptrdiff_t remaining = last_pos - pos;
885 struct GNUNET_CRYPTO_PaillierCiphertext *ciphertext;
887 GNUNET_assert (remaining > 0);
888 ciphertext = (void *) pos;
889 memset (ciphertext, 0, sizeof *ciphertext);
890 if (GNUNET_YES == ks->info[i].round1_valid)
892 struct GNUNET_CRYPTO_PaillierPlaintext plaintext;
893 struct GNUNET_CRYPTO_PaillierPublicKey public_key;
894 gcry_mpi_set_ui (idx, i + 1);
895 // evaluate the polynomial
896 horner_eval (v, ks->presecret_polynomial, ks->threshold, idx, elgamal_q);
897 GNUNET_CRYPTO_mpi_print_unsigned (&plaintext, sizeof plaintext, v);
898 GNUNET_CRYPTO_mpi_print_unsigned (&public_key, sizeof public_key, ks->info[i].paillier_n);
899 // encrypt the result
900 GNUNET_CRYPTO_paillier_encrypt (&public_key, &plaintext, ciphertext);
902 pos += sizeof *ciphertext;
905 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "P%u: computed enc preshares\n",
908 // exponentiated coefficients
909 for (i = 0; i < ks->threshold; i++)
911 ptrdiff_t remaining = last_pos - pos;
912 GNUNET_assert (remaining > 0);
913 gcry_mpi_powm (v, elgamal_g, ks->presecret_polynomial[i], elgamal_p);
914 GNUNET_CRYPTO_mpi_print_unsigned (pos, GNUNET_SECRETSHARING_ELGAMAL_BITS / 8, v);
915 pos += GNUNET_SECRETSHARING_ELGAMAL_BITS / 8;
918 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "P%u: computed exp coefficients\n",
921 d->purpose.size = htonl (element_size - offsetof (struct GNUNET_SECRETSHARING_KeygenRevealData, purpose));
922 d->purpose.purpose = htonl (GNUNET_SIGNATURE_PURPOSE_SECRETSHARING_DKG2);
923 GNUNET_CRYPTO_eddsa_sign (my_peer_private_key, &d->purpose, &d->signature);
925 GNUNET_CONSENSUS_insert (ks->consensus, element, NULL, NULL);
926 GNUNET_free (element); /* FIXME: maybe stack-allocate instead? */
928 gcry_mpi_release (v);
929 gcry_mpi_release (idx);
934 keygen_round2_new_element (void *cls,
935 const struct GNUNET_SET_Element *element)
937 struct KeygenSession *ks = cls;
938 const struct GNUNET_SECRETSHARING_KeygenRevealData *d;
939 struct KeygenPeerInfo *info;
942 size_t expected_element_size;
946 GNUNET_log (GNUNET_ERROR_TYPE_WARNING, "round2 consensus failed\n");
950 expected_element_size = (sizeof (struct GNUNET_SECRETSHARING_KeygenRevealData) +
951 GNUNET_SECRETSHARING_ELGAMAL_BITS / 8 * ks->num_peers +
952 GNUNET_CRYPTO_PAILLIER_BITS / 8 * 2 * ks->num_peers +
953 GNUNET_SECRETSHARING_ELGAMAL_BITS / 8 * ks->threshold);
955 if (element->size != expected_element_size)
957 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
958 "keygen round2 data with wrong size (%u) in consensus, "
960 element->size, expected_element_size);
964 d = (const void *) element->data;
966 info = get_keygen_peer_info (ks, &d->peer);
970 GNUNET_log (GNUNET_ERROR_TYPE_WARNING, "keygen commit data with wrong peer identity (%s) in consensus\n",
971 GNUNET_i2s (&d->peer));
975 if (GNUNET_NO == info->round1_valid)
977 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
978 "ignoring round2 element from peer with invalid round1 element (%s)\n",
979 GNUNET_i2s (&d->peer));
983 if (GNUNET_YES == info->round2_valid)
985 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
986 "ignoring duplicate round2 element (%s)\n",
987 GNUNET_i2s (&d->peer));
991 GNUNET_log (GNUNET_ERROR_TYPE_INFO, "got round2 element\n");
994 pos = (void *) &d[1];
995 // skip exponentiated pre-shares
996 pos += GNUNET_SECRETSHARING_ELGAMAL_BITS / 8 * ks->num_peers;
997 // skip encrypted pre-shares
998 pos += GNUNET_CRYPTO_PAILLIER_BITS * 2 / 8 * ks->num_peers;
999 // the first exponentiated coefficient is the public key share
1000 GNUNET_CRYPTO_mpi_scan_unsigned (&info->public_key_share, pos, GNUNET_SECRETSHARING_ELGAMAL_BITS / 8);
1002 pos = (void *) &d[1];
1003 // skip exp. pre-shares
1004 pos += GNUNET_SECRETSHARING_ELGAMAL_BITS / 8 * ks->num_peers;
1005 // skip to the encrypted value for our peer
1006 pos += GNUNET_CRYPTO_PAILLIER_BITS * 2 / 8 * ks->local_peer_idx;
1008 GNUNET_CRYPTO_mpi_scan_unsigned (&c, pos, GNUNET_CRYPTO_PAILLIER_BITS * 2 / 8);
1010 GNUNET_assert (0 != (info->decrypted_preshare = mpi_new (0)));
1012 paillier_decrypt (info->decrypted_preshare, c, ks->paillier_mu, ks->paillier_lambda,
1013 ks->info[ks->local_peer_idx].paillier_n);
1014 // TODO: validate zero knowledge proofs
1016 if (ntohl (d->purpose.size) !=
1017 element->size - offsetof (struct GNUNET_SECRETSHARING_KeygenRevealData, purpose))
1019 GNUNET_log (GNUNET_ERROR_TYPE_WARNING, "keygen reveal data with wrong signature purpose size in consensus\n");
1023 if (GNUNET_OK != GNUNET_CRYPTO_eddsa_verify (GNUNET_SIGNATURE_PURPOSE_SECRETSHARING_DKG2,
1024 &d->purpose, &d->signature, &d->peer.public_key))
1026 GNUNET_log (GNUNET_ERROR_TYPE_WARNING, "keygen reveal data with invalid signature in consensus\n");
1030 info->round2_valid = GNUNET_YES;
1035 * Called when the first consensus round has concluded.
1036 * Will initiate the second round.
1038 * @param cls closure
1041 keygen_round1_conclude (void *cls)
1043 struct KeygenSession *ks = cls;
1045 GNUNET_CONSENSUS_destroy (ks->consensus);
1047 ks->consensus = GNUNET_CONSENSUS_create (cfg, ks->num_peers, ks->peers, &ks->session_id,
1048 keygen_round2_new_element, ks);
1050 insert_round2_element (ks);
1052 GNUNET_CONSENSUS_conclude (ks->consensus,
1053 /* last round, thus conclude at DKG deadline */
1055 keygen_round2_conclude,
1061 * Insert the ephemeral key and the presecret commitment
1062 * of this peer in the consensus of the given session.
1064 * @param ks session to use
1067 insert_round1_element (struct KeygenSession *ks)
1069 struct GNUNET_SET_Element *element;
1070 struct GNUNET_SECRETSHARING_KeygenCommitData *d;
1073 // big-endian representation of 'v'
1074 unsigned char v_data[GNUNET_SECRETSHARING_ELGAMAL_BITS / 8];
1076 element = GNUNET_malloc (sizeof *element + sizeof *d);
1077 d = (void *) &element[1];
1079 element->size = sizeof *d;
1083 GNUNET_assert (0 != (v = gcry_mpi_new (GNUNET_SECRETSHARING_ELGAMAL_BITS)));
1085 gcry_mpi_powm (v, elgamal_g, ks->presecret_polynomial[0], elgamal_p);
1087 GNUNET_CRYPTO_mpi_print_unsigned (v_data, GNUNET_SECRETSHARING_ELGAMAL_BITS / 8, v);
1089 GNUNET_CRYPTO_hash (v_data, GNUNET_SECRETSHARING_ELGAMAL_BITS / 8, &d->commitment);
1091 GNUNET_CRYPTO_mpi_print_unsigned (d->pubkey.n, GNUNET_CRYPTO_PAILLIER_BITS / 8,
1092 ks->info[ks->local_peer_idx].paillier_n);
1094 d->purpose.size = htonl ((sizeof *d) - offsetof (struct GNUNET_SECRETSHARING_KeygenCommitData, purpose));
1095 d->purpose.purpose = htonl (GNUNET_SIGNATURE_PURPOSE_SECRETSHARING_DKG1);
1096 GNUNET_assert (GNUNET_OK == GNUNET_CRYPTO_eddsa_sign (my_peer_private_key, &d->purpose, &d->signature));
1098 GNUNET_CONSENSUS_insert (ks->consensus, element, NULL, NULL);
1100 gcry_mpi_release (v);
1101 GNUNET_free (element);
1106 * Functions with this signature are called whenever a message is
1109 * @param cls closure
1110 * @param client identification of the client
1111 * @param message the actual message
1113 static void handle_client_keygen (void *cls,
1114 struct GNUNET_SERVER_Client *client,
1115 const struct GNUNET_MessageHeader
1118 const struct GNUNET_SECRETSHARING_CreateMessage *msg =
1119 (const struct GNUNET_SECRETSHARING_CreateMessage *) message;
1120 struct KeygenSession *ks;
1122 struct GNUNET_CRYPTO_PaillierPrivateKey private_key;
1123 struct GNUNET_CRYPTO_PaillierPublicKey public_key;
1125 GNUNET_log (GNUNET_ERROR_TYPE_INFO, "client requested key generation\n");
1127 ks = GNUNET_new (struct KeygenSession);
1129 /* FIXME: check if client already has some session */
1131 GNUNET_CONTAINER_DLL_insert (keygen_sessions_head, keygen_sessions_tail, ks);
1133 ks->client = client;
1134 ks->client_mq = GNUNET_MQ_queue_for_server_client (client);
1136 ks->deadline = GNUNET_TIME_absolute_ntoh (msg->deadline);
1137 ks->threshold = ntohs (msg->threshold);
1138 ks->num_peers = ntohs (msg->num_peers);
1140 ks->peers = normalize_peers ((struct GNUNET_PeerIdentity *) &msg[1], ks->num_peers,
1141 &ks->num_peers, &ks->local_peer_idx);
1144 GNUNET_log (GNUNET_ERROR_TYPE_INFO, "first round of consensus with %u peers\n", ks->num_peers);
1145 ks->consensus = GNUNET_CONSENSUS_create (cfg, ks->num_peers, ks->peers, &msg->session_id,
1146 keygen_round1_new_element, ks);
1148 ks->info = GNUNET_new_array (ks->num_peers, struct KeygenPeerInfo);
1150 for (i = 0; i < ks->num_peers; i++)
1151 ks->info[i].peer = ks->peers[i];
1153 GNUNET_assert (0 != (ks->info[ks->local_peer_idx].paillier_n = mpi_new (0)));
1154 GNUNET_assert (0 != (ks->paillier_lambda = mpi_new (0)));
1155 GNUNET_assert (0 != (ks->paillier_mu = mpi_new (0)));
1157 GNUNET_CRYPTO_paillier_create (&public_key, &private_key);
1159 GNUNET_CRYPTO_mpi_scan_unsigned (&ks->info[ks->local_peer_idx].paillier_n,
1160 &public_key, sizeof public_key);
1161 GNUNET_CRYPTO_mpi_scan_unsigned (&ks->paillier_lambda,
1162 &private_key.lambda, sizeof private_key.lambda);
1163 GNUNET_CRYPTO_mpi_scan_unsigned (&ks->paillier_mu,
1164 &private_key.mu, sizeof private_key.mu);
1166 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "P%u: Generated paillier key pair\n", ks->local_peer_idx);
1168 generate_presecret_polynomial (ks);
1170 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "P%u: Generated presecret polynomial\n", ks->local_peer_idx);
1172 insert_round1_element (ks);
1174 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "P%u: Concluding for round 1\n", ks->local_peer_idx);
1176 GNUNET_CONSENSUS_conclude (ks->consensus,
1177 /* half the overall time */
1178 time_between (ks->start_time, ks->deadline, 1, 2),
1179 keygen_round1_conclude,
1182 GNUNET_SERVER_receive_done (client, GNUNET_OK);
1184 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "P%u: Waiting for round 1 elements ...\n", ks->local_peer_idx);
1189 * Called when the partial decryption consensus concludes.
1192 decrypt_conclude (void *cls)
1194 struct DecryptSession *ds = cls;
1195 struct GNUNET_SECRETSHARING_DecryptResponseMessage *msg;
1196 struct GNUNET_MQ_Envelope *ev;
1197 gcry_mpi_t lagrange;
1202 unsigned int *indices;
1207 GNUNET_assert (0 != (lagrange = gcry_mpi_new (0)));
1208 GNUNET_assert (0 != (m = gcry_mpi_new (0)));
1209 GNUNET_assert (0 != (tmp = gcry_mpi_new (0)));
1210 GNUNET_assert (0 != (prod = gcry_mpi_new (0)));
1213 for (i = 0; i < ds->share->num_peers; i++)
1214 if (NULL != ds->info[i].partial_decryption)
1217 indices = GNUNET_malloc (num * sizeof (unsigned int));
1219 for (i = 0; i < ds->share->num_peers; i++)
1220 if (NULL != ds->info[i].partial_decryption)
1221 indices[j++] = ds->info[i].original_index;
1223 GNUNET_log (GNUNET_ERROR_TYPE_INFO, "P%u: decrypt conclude, with %u peers\n",
1224 ds->share->my_peer, num);
1226 gcry_mpi_set_ui (prod, 1);
1227 for (i = 0; i < num; i++)
1230 GNUNET_log (GNUNET_ERROR_TYPE_INFO, "P%u: index of %u: %u\n",
1231 ds->share->my_peer, i, indices[i]);
1232 compute_lagrange_coefficient (lagrange, indices[i], indices, num);
1234 gcry_mpi_powm (tmp, ds->info[indices[i]].partial_decryption, lagrange, elgamal_p);
1236 // product of all exponentiated partiel decryptions ...
1237 gcry_mpi_mulm (prod, prod, tmp, elgamal_p);
1240 GNUNET_CRYPTO_mpi_scan_unsigned (&c_2, ds->ciphertext.c2_bits, GNUNET_SECRETSHARING_ELGAMAL_BITS / 8);
1242 GNUNET_assert (0 != gcry_mpi_invm (prod, prod, elgamal_p));
1243 gcry_mpi_mulm (m, c_2, prod, elgamal_p);
1244 ev = GNUNET_MQ_msg (msg, GNUNET_MESSAGE_TYPE_SECRETSHARING_CLIENT_DECRYPT_DONE);
1245 GNUNET_CRYPTO_mpi_print_unsigned (&msg->plaintext, GNUNET_SECRETSHARING_ELGAMAL_BITS / 8, m);
1246 msg->success = htonl (1);
1247 GNUNET_MQ_send (ds->client_mq, ev);
1249 GNUNET_log (GNUNET_ERROR_TYPE_INFO, "sent decrypt done to client\n");
1251 // FIXME: what if not enough peers participated?
1256 * Called when a new partial decryption arrives.
1259 decrypt_new_element (void *cls,
1260 const struct GNUNET_SET_Element *element)
1262 struct DecryptSession *session = cls;
1263 const struct GNUNET_SECRETSHARING_DecryptData *d;
1264 struct DecryptPeerInfo *info;
1266 if (NULL == element)
1268 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "decryption failed\n");
1269 /* FIXME: destroy */
1273 if (element->size != sizeof *d)
1275 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "element of wrong size in decrypt consensus\n");
1281 info = get_decrypt_peer_info (session, &d->peer);
1285 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "decrypt element from invalid peer (%s)\n",
1286 GNUNET_i2s (&d->peer));
1290 if (NULL != info->partial_decryption)
1292 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "decrypt element duplicate\n",
1293 GNUNET_i2s (&d->peer));
1297 // FIXME: check NIZP first
1299 GNUNET_CRYPTO_mpi_scan_unsigned (&info->partial_decryption, &d->partial_decryption,
1300 GNUNET_SECRETSHARING_ELGAMAL_BITS / 8);
1304 insert_decrypt_element (struct DecryptSession *ds)
1306 struct GNUNET_SECRETSHARING_DecryptData d;
1307 struct GNUNET_SET_Element element;
1311 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "P%u: Inserting decrypt element\n",
1312 ds->share->my_peer);
1314 GNUNET_CRYPTO_mpi_scan_unsigned (&x, &ds->ciphertext.c1_bits,
1315 GNUNET_SECRETSHARING_ELGAMAL_BITS / 8);
1316 GNUNET_CRYPTO_mpi_scan_unsigned (&s, &ds->share->my_share,
1317 GNUNET_SECRETSHARING_ELGAMAL_BITS / 8);
1319 gcry_mpi_powm (x, x, s, elgamal_p);
1321 element.data = (void *) &d;
1322 element.size = sizeof (struct GNUNET_SECRETSHARING_DecryptData);
1325 /* make vagrind happy until we implement the real deal ... */
1326 memset (&d.nizk_commit1, 0, sizeof d.nizk_commit1);
1327 memset (&d.nizk_commit2, 0, sizeof d.nizk_commit2);
1328 memset (&d.nizk_response, 0, sizeof d.nizk_response);
1330 d.ciphertext = ds->ciphertext;
1332 d.purpose.size = htonl (element.size - offsetof (struct GNUNET_SECRETSHARING_DecryptData, purpose));
1333 d.purpose.purpose = htonl (GNUNET_SIGNATURE_PURPOSE_SECRETSHARING_DECRYPTION);
1335 GNUNET_CRYPTO_eddsa_sign (my_peer_private_key, &d.purpose, &d.signature);
1337 GNUNET_CRYPTO_mpi_print_unsigned (&d.partial_decryption, GNUNET_SECRETSHARING_ELGAMAL_BITS / 8, x);
1339 GNUNET_CONSENSUS_insert (ds->consensus, &element, NULL, NULL);
1340 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "P%u: Inserting decrypt element done!\n",
1341 ds->share->my_peer);
1346 * Functions with this signature are called whenever a message is
1349 * @param cls closure
1350 * @param client identification of the client
1351 * @param message the actual message
1353 static void handle_client_decrypt (void *cls,
1354 struct GNUNET_SERVER_Client *client,
1355 const struct GNUNET_MessageHeader
1358 const struct GNUNET_SECRETSHARING_DecryptRequestMessage *msg =
1359 (const void *) message;
1360 struct DecryptSession *ds;
1361 struct GNUNET_HashCode session_id;
1364 ds = GNUNET_new (struct DecryptSession);
1365 // FIXME: check if session already exists
1366 GNUNET_CONTAINER_DLL_insert (decrypt_sessions_head, decrypt_sessions_tail, ds);
1367 ds->client = client;
1368 ds->client_mq = GNUNET_MQ_queue_for_server_client (client);
1369 ds->deadline = GNUNET_TIME_absolute_ntoh (msg->deadline);
1370 ds->ciphertext = msg->ciphertext;
1372 ds->share = GNUNET_SECRETSHARING_share_read (&msg[1], ntohs (msg->header.size) - sizeof *msg, NULL);
1373 // FIXME: probably should be break rather than assert
1374 GNUNET_assert (NULL != ds->share);
1376 // FIXME: this is probably sufficient, but kdf/hash with all values would be nicer ...
1377 GNUNET_CRYPTO_hash (&msg->ciphertext, sizeof (struct GNUNET_SECRETSHARING_Ciphertext), &session_id);
1379 ds->consensus = GNUNET_CONSENSUS_create (cfg,
1380 ds->share->num_peers,
1383 &decrypt_new_element,
1387 ds->info = GNUNET_new_array (ds->share->num_peers, struct DecryptPeerInfo);
1388 for (i = 0; i < ds->share->num_peers; i++)
1390 ds->info[i].peer = ds->share->peers[i];
1391 ds->info[i].original_index = ds->share->original_indices[i];
1394 insert_decrypt_element (ds);
1396 GNUNET_CONSENSUS_conclude (ds->consensus, ds->deadline, decrypt_conclude, ds);
1398 GNUNET_SERVER_receive_done (client, GNUNET_OK);
1400 GNUNET_log (GNUNET_ERROR_TYPE_INFO, "decrypting with %u peers\n",
1401 ds->share->num_peers);
1406 init_crypto_constants (void)
1408 GNUNET_assert (0 == gcry_mpi_scan (&elgamal_q, GCRYMPI_FMT_HEX,
1409 GNUNET_SECRETSHARING_ELGAMAL_Q_HEX, 0, NULL));
1410 GNUNET_assert (0 == gcry_mpi_scan (&elgamal_p, GCRYMPI_FMT_HEX,
1411 GNUNET_SECRETSHARING_ELGAMAL_P_HEX, 0, NULL));
1412 GNUNET_assert (0 == gcry_mpi_scan (&elgamal_g, GCRYMPI_FMT_HEX,
1413 GNUNET_SECRETSHARING_ELGAMAL_G_HEX, 0, NULL));
1417 static struct KeygenSession *
1418 keygen_session_get (struct GNUNET_SERVER_Client *client)
1420 struct KeygenSession *ks;
1421 for (ks = keygen_sessions_head; NULL != ks; ks = ks->next)
1422 if (ks->client == client)
1427 static struct DecryptSession *
1428 decrypt_session_get (struct GNUNET_SERVER_Client *client)
1430 struct DecryptSession *ds;
1431 for (ds = decrypt_sessions_head; NULL != ds; ds = ds->next)
1432 if (ds->client == client)
1439 * Clean up after a client has disconnected
1441 * @param cls closure, unused
1442 * @param client the client to clean up after
1445 handle_client_disconnect (void *cls, struct GNUNET_SERVER_Client *client)
1447 struct KeygenSession *ks;
1448 struct DecryptSession *ds;
1450 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "handling client disconnect\n");
1452 ks = keygen_session_get (client);
1454 keygen_session_destroy (ks);
1456 ds = decrypt_session_get (client);
1458 decrypt_session_destroy (ds);
1463 * Process template requests.
1465 * @param cls closure
1466 * @param server the initialized server
1467 * @param c configuration to use
1470 run (void *cls, struct GNUNET_SERVER_Handle *server,
1471 const struct GNUNET_CONFIGURATION_Handle *c)
1473 static const struct GNUNET_SERVER_MessageHandler handlers[] = {
1474 {handle_client_keygen, NULL, GNUNET_MESSAGE_TYPE_SECRETSHARING_CLIENT_GENERATE, 0},
1475 {handle_client_decrypt, NULL, GNUNET_MESSAGE_TYPE_SECRETSHARING_CLIENT_DECRYPT, 0},
1480 my_peer_private_key = GNUNET_CRYPTO_eddsa_key_create_from_configuration (c);
1481 if (NULL == my_peer_private_key)
1483 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "could not access host private key\n");
1485 GNUNET_SCHEDULER_shutdown ();
1488 init_crypto_constants ();
1489 if (GNUNET_OK != GNUNET_CRYPTO_get_peer_identity (cfg, &my_peer))
1491 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "could not retrieve host identity\n");
1493 GNUNET_SCHEDULER_shutdown ();
1496 GNUNET_SERVER_add_handlers (server, handlers);
1497 GNUNET_SERVER_disconnect_notify (server, &handle_client_disconnect, NULL);
1498 GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_FOREVER_REL, &cleanup_task,
1504 * The main function for the template service.
1506 * @param argc number of arguments from the command line
1507 * @param argv command line arguments
1508 * @return 0 ok, 1 on error
1511 main (int argc, char *const *argv)
1513 return (GNUNET_OK ==
1514 GNUNET_SERVICE_run (argc, argv, "secretsharing",
1515 GNUNET_SERVICE_OPTION_NONE, &run, NULL)) ? 0 : 1;