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_consensus_service.h"
30 #include "secretsharing.h"
31 #include "secretsharing_protocol.h"
36 * Info about a peer in a key generation session.
41 * Peer identity of the peer.
43 struct GNUNET_PeerIdentity peer;
46 * g-component of the peer's paillier public key.
48 gcry_mpi_t paillier_g;
51 * mu-component of the peer's paillier public key.
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 could decrypt
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 * GNUNET_YES if the peer has been disqualified,
73 * GNUNET_NO otherwise.
80 * Session to establish a threshold-shared secret.
85 * Keygen sessions are held in a linked list.
87 struct KeygenSession *next;
90 * Keygen sessions are held in a linked list.
92 struct KeygenSession *prev;
95 * Current consensus, used for both DKG rounds.
97 struct GNUNET_CONSENSUS_Handle *consensus;
100 * Client that is interested in the result
101 * of this key generation session.
103 struct GNUNET_SERVER_Client *client;
106 * Message queue for 'client'
108 struct GNUNET_MQ_Handle *client_mq;
111 * Randomly generated coefficients of the polynomial for sharing our
112 * pre-secret, where 'preshares[0]' is our pre-secret. Contains 'threshold'
113 * elements, thus represents a polynomial of degree 'threshold-1', which can
114 * be interpolated with 'threshold' data points.
116 * The pre-secret-shares 'i=1,...,num_peers' are given by evaluating this
117 * polyomial at 'i' for share i.
119 gcry_mpi_t *presecret_polynomial;
122 * Minimum number of shares required to restore the secret.
124 unsigned int threshold;
127 * Total number of peers.
129 unsigned int num_peers;
132 * Index of the local peer.
134 unsigned int local_peer;
137 * Information about all participating peers.
139 struct KeygenPeerInfo *info;
142 * List of all peers involved in the secret sharing session.
144 struct GNUNET_PeerIdentity *peers;
147 * Identifier for this session.
149 struct GNUNET_HashCode session_id;
152 * g-component of our peer's paillier private key.
154 gcry_mpi_t paillier_lambda;
157 * g-component of our peer's paillier private key.
159 gcry_mpi_t paillier_mu;
161 struct GNUNET_TIME_Absolute deadline;
164 * Index of the local peer in the ordered list
165 * of peers in the session.
167 unsigned int local_peer_idx;
171 struct DecryptSession
173 struct DecryptSession *next;
174 struct DecryptSession *prev;
176 struct GNUNET_CONSENSUS_Handle *consensus;
178 struct GNUNET_SERVER_Client *client;
182 * Decrypt sessions are held in a linked list.
184 //static struct DecryptSession *decrypt_sessions_head;
187 * Decrypt sessions are held in a linked list.
189 //static struct DecryptSession *decrypt_sessions_tail;
192 * Decrypt sessions are held in a linked list.
194 static struct KeygenSession *keygen_sessions_head;
197 * Decrypt sessions are held in a linked list.
199 static struct KeygenSession *keygen_sessions_tail;
202 * The ElGamal prime field order as libgcrypt mpi.
203 * Will be initialized to 'ELGAMAL_Q_DATA'.
205 static gcry_mpi_t elgamal_q;
208 * Modulus of the prime field used for ElGamal.
209 * Will be initialized to 'ELGAMAL_P_DATA'.
211 static gcry_mpi_t elgamal_p;
214 * Generator for prime field of order 'elgamal_q'.
215 * Will be initialized to 'ELGAMAL_G_DATA'.
217 static gcry_mpi_t elgamal_g;
220 * Peer that runs this service.
222 static struct GNUNET_PeerIdentity my_peer;
225 * Configuration of this service.
227 static const struct GNUNET_CONFIGURATION_Handle *cfg;
230 * Server for this service.
232 static struct GNUNET_SERVER_Handle *srv;
236 * Although GNUNET_CRYPTO_hash_cmp exisits, it does not have
237 * the correct signature to be used with e.g. qsort.
238 * We use this function instead.
240 * @param h1 some hash code
241 * @param h2 some hash code
242 * @return 1 if h1 > h2, -1 if h1 < h2 and 0 if h1 == h2.
245 hash_cmp (const void *h1, const void *h2)
247 return GNUNET_CRYPTO_hash_cmp ((struct GNUNET_HashCode *) h1, (struct GNUNET_HashCode *) h2);
252 * Normalize the given list of peers, by including the local peer
253 * (if it is missing) and sorting the peers by their identity.
255 * @param listed peers in the unnormalized list
256 * @param num_listed peers in the un-normalized list
257 * @param[out] num_normalized number of peers in the normalized list
258 * @param[out] my_peer_idx index of the local peer in the normalized list
259 * @return normalized list, must be free'd by the caller
261 static struct GNUNET_PeerIdentity *
262 normalize_peers (struct GNUNET_PeerIdentity *listed,
263 unsigned int num_listed,
264 unsigned int *num_normalized,
265 unsigned int *my_peer_idx)
267 unsigned int local_peer_in_list;
270 struct GNUNET_PeerIdentity *normalized;
272 local_peer_in_list = GNUNET_NO;
273 for (i = 0; i < num_listed; i++)
275 if (0 == memcmp (&listed[i], &my_peer, sizeof (struct GNUNET_PeerIdentity)))
277 local_peer_in_list = GNUNET_YES;
283 if (GNUNET_NO == local_peer_in_list)
286 normalized = GNUNET_malloc (n * sizeof (struct GNUNET_PeerIdentity));
288 if (GNUNET_NO == local_peer_in_list)
289 normalized[n - 1] = my_peer;
291 memcpy (normalized, listed, num_listed * sizeof (struct GNUNET_PeerIdentity));
292 qsort (normalized, n, sizeof (struct GNUNET_PeerIdentity), &hash_cmp);
294 if (NULL != my_peer_idx)
296 for (i = 0; i < num_listed; i++)
298 if (0 == memcmp (&normalized[i], &my_peer, sizeof (struct GNUNET_PeerIdentity)))
312 * Create a key pair for the paillier crypto system.
314 * Uses the simplified key generation of Jonathan Katz, Yehuda Lindell,
315 * "Introduction to Modern Cryptography: Principles and Protocols".
317 * @param g g-component of public key
318 * @param n n-component of public key
319 * @param lambda lambda-component of private key
320 * @param mu mu-componenent of private key
323 paillier_create (gcry_mpi_t g, gcry_mpi_t n, gcry_mpi_t lambda, gcry_mpi_t mu)
330 GNUNET_assert (0 != (phi = gcry_mpi_new (PAILLIER_BITS)));
331 GNUNET_assert (0 != (tmp = gcry_mpi_new (PAILLIER_BITS)));
333 // generate rsa modulus
334 GNUNET_assert (0 == gcry_prime_generate (&p, PAILLIER_BITS / 2, 0, NULL, NULL, NULL,
335 GCRY_WEAK_RANDOM, 0));
336 GNUNET_assert (0 == gcry_prime_generate (&q, PAILLIER_BITS / 2, 0, NULL, NULL, NULL,
337 GCRY_WEAK_RANDOM, 0));
338 gcry_mpi_mul (n, p, q);
339 gcry_mpi_add_ui (g, n, 1);
340 // compute phi(n) = (p-1)(q-1)
341 gcry_mpi_sub_ui (phi, p, 1);
342 gcry_mpi_sub_ui (tmp, q, 1);
343 gcry_mpi_mul (phi, phi, tmp);
344 gcry_mpi_set (lambda, phi);
346 GNUNET_assert (0 != gcry_mpi_invm (mu, phi, n));
348 gcry_mpi_release (p);
349 gcry_mpi_release (q);
350 gcry_mpi_release (phi);
351 gcry_mpi_release (tmp);
356 * Encrypt a value using Paillier's scheme.
358 * @param c resulting ciphertext
359 * @param m plaintext to encrypt
360 * @param g g-component of public key
361 * @param n n-component of public key
364 paillier_encrypt (gcry_mpi_t c, gcry_mpi_t m, gcry_mpi_t g, gcry_mpi_t n)
369 GNUNET_assert (0 != (n_square = gcry_mpi_new (0)));
370 GNUNET_assert (0 != (r = gcry_mpi_new (0)));
372 gcry_mpi_mul (n_square, n, n);
377 gcry_mpi_randomize (r, PAILLIER_BITS, GCRY_WEAK_RANDOM);
379 while (gcry_mpi_cmp (r, n) > 0);
381 gcry_mpi_powm (c, g, m, n_square);
382 gcry_mpi_powm (r, r, n, n_square);
383 gcry_mpi_mulm (c, r, c, n_square);
385 gcry_mpi_release (n_square);
386 gcry_mpi_release (r);
391 * Decrypt a ciphertext using Paillier's scheme.
393 * @param[out] m resulting plaintext
394 * @param c ciphertext to decrypt
395 * @param lambda lambda-component of private key
396 * @param mu mu-component of private key
397 * @param n n-component of public key
400 paillier_decrypt (gcry_mpi_t m, gcry_mpi_t c, gcry_mpi_t mu, gcry_mpi_t lambda, gcry_mpi_t n)
403 GNUNET_assert (0 != (n_square = gcry_mpi_new (0)));
404 gcry_mpi_mul (n_square, n, n);
405 gcry_mpi_powm (m, c, lambda, n_square);
406 gcry_mpi_sub_ui (m, m, 1);
408 gcry_mpi_div (m, NULL, m, n, 0);
409 gcry_mpi_mulm (m, m, mu, n);
410 gcry_mpi_release (n_square);
415 * Task run during shutdown.
421 cleanup_task (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
423 /* FIXME: do clean up here */
428 generate_presecret_polynomial (struct KeygenSession *ks)
431 GNUNET_assert (NULL == ks->presecret_polynomial);
432 ks->presecret_polynomial = GNUNET_malloc (ks->threshold * sizeof (gcry_mpi_t));
433 for (i = 0; i < ks->threshold; i++)
435 ks->presecret_polynomial[i] = gcry_mpi_new (PAILLIER_BITS);
436 gcry_mpi_randomize (ks->presecret_polynomial[i], PAILLIER_BITS,
443 keygen_round1_new_element (void *cls,
444 const struct GNUNET_SET_Element *element)
446 const struct GNUNET_SECRETSHARING_KeygenCommitData *d;
447 struct KeygenSession *ks = cls;
450 if (element->size != sizeof (struct GNUNET_SECRETSHARING_KeygenCommitData))
452 GNUNET_log (GNUNET_ERROR_TYPE_WARNING, "keygen commit data with wrong size in consensus\n");
458 for (i = 0; i < ks->num_peers; i++)
460 if (0 == memcmp (&d->peer, &ks->info[i].peer, sizeof (struct GNUNET_PeerIdentity)))
462 // TODO: check signature
463 GNUNET_assert (0 == gcry_mpi_scan (&ks->info[i].paillier_g, GCRYMPI_FMT_USG,
464 &d->pubkey.g, sizeof d->pubkey.g, NULL));
465 GNUNET_assert (0 == gcry_mpi_scan (&ks->info[i].paillier_n, GCRYMPI_FMT_USG,
466 &d->pubkey.n, sizeof d->pubkey.n, NULL));
467 GNUNET_assert (0 == gcry_mpi_scan (&ks->info[i].presecret_commitment, GCRYMPI_FMT_USG,
468 &d->commitment, sizeof d->commitment, NULL));
473 GNUNET_log (GNUNET_ERROR_TYPE_WARNING, "keygen commit data with wrong peer identity in consensus\n");
478 * Evaluate the polynomial with coefficients @a coeff at @a x.
479 * The i-th element in @a coeff corresponds to the coefficient of x^i.
481 * @param[out] z result of the evaluation
482 * @param coeff array of coefficients
483 * @param num_coeff number of coefficients
484 * @param x where to evaluate the polynomial
485 * @param m what group are we operating in?
488 horner_eval (gcry_mpi_t z, gcry_mpi_t *coeff, unsigned int num_coeff, gcry_mpi_t x, gcry_mpi_t m)
492 gcry_mpi_set_ui (z, 0);
493 for (i = 0; i < num_coeff; i++)
496 gcry_mpi_mul (z, z, x);
497 gcry_mpi_addm (z, z, coeff[num_coeff - i - 1], m);
503 keygen_round2_conclude (void *cls)
505 struct KeygenSession *ks = cls;
506 struct GNUNET_SECRETSHARING_SecretReadyMessage *m;
507 struct GNUNET_MQ_Envelope *ev;
512 GNUNET_assert (0 != (s = gcry_mpi_new (PAILLIER_BITS)));
513 GNUNET_assert (0 != (h = gcry_mpi_new (PAILLIER_BITS)));
515 // multiplicative identity
516 gcry_mpi_set_ui (s, 1);
518 for (i = 0; i < ks->num_peers; i++)
520 if (GNUNET_NO == ks->info[i].disqualified)
522 gcry_mpi_addm (s, s, ks->info[i].decrypted_preshare, elgamal_p);
523 gcry_mpi_mulm (h, h, ks->info[i].public_key_share, elgamal_p);
524 // m->num_secret_peers++; // FIXME: m not initialized here!
528 ev = GNUNET_MQ_msg (m, GNUNET_MESSAGE_TYPE_SECRETSHARING_CLIENT_SECRET_READY);
530 gcry_mpi_print (GCRYMPI_FMT_USG, (void *) &m->secret, PAILLIER_BITS / 8, NULL, s);
531 gcry_mpi_print (GCRYMPI_FMT_USG, (void *) &m->public_key, PAILLIER_BITS / 8, NULL, s);
533 GNUNET_MQ_send (ks->client_mq, ev);
538 * Insert round 2 element in the consensus, consisting of
539 * (1) The exponentiated pre-share polynomial coefficients A_{i,l}=g^{a_{i,l}}
540 * (2) The exponentiated pre-shares y_{i,j}=g^{s_{i,j}}
541 * (3) The encrypted pre-shares Y_{i,j}
542 * (4) The zero knowledge proof for correctness of
545 * @param ks session to use
548 insert_round2_element (struct KeygenSession *ks)
550 struct GNUNET_SET_Element *element;
551 struct GNUNET_SECRETSHARING_KeygenRevealData *msg;
553 unsigned char *last_pos;
560 GNUNET_assert (0 != (c = gcry_mpi_new (PAILLIER_BITS)));
561 // FIXME: c is never used...
562 GNUNET_assert (0 != (v = gcry_mpi_new (PAILLIER_BITS)));
563 GNUNET_assert (0 != (idx = gcry_mpi_new (PAILLIER_BITS)));
565 element_size = (sizeof (struct GNUNET_SECRETSHARING_KeygenRevealData) +
566 2 * PAILLIER_BITS / 8 * ks->num_peers +
567 1 * PAILLIER_BITS / 8 * ks->threshold);
569 element = GNUNET_malloc (sizeof (struct GNUNET_SET_Element) + element_size);
571 msg = (void *) element->data;
572 pos = (void *) &msg[1];
573 last_pos = pos + element_size;
575 // exponentiated pre-shares
576 for (i = 0; i <= ks->threshold; i++)
578 ptrdiff_t remaining = last_pos - pos;
579 GNUNET_assert (remaining > 0);
580 gcry_mpi_set_ui (idx, i);
581 // evaluate the polynomial
582 horner_eval (v, ks->presecret_polynomial, ks->threshold, idx, elgamal_p);
583 // take g to the result
584 gcry_mpi_powm (v, elgamal_g, v, elgamal_p);
585 gcry_mpi_print (GCRYMPI_FMT_USG, pos, (size_t) remaining, NULL, v);
586 pos += PAILLIER_BITS / 8;
589 // exponentiated coefficients
590 for (i = 0; i < ks->num_peers; i++)
592 ptrdiff_t remaining = last_pos - pos;
593 GNUNET_assert (remaining > 0);
594 gcry_mpi_powm (v, elgamal_g, ks->presecret_polynomial[0], elgamal_p);
595 gcry_mpi_print (GCRYMPI_FMT_USG, pos, (size_t) remaining, NULL, v);
596 pos += PAILLIER_BITS / 8;
599 // encrypted pre-shares
600 for (i = 0; i < ks->threshold; i++)
602 ptrdiff_t remaining = last_pos - pos;
603 GNUNET_assert (remaining > 0);
604 if (GNUNET_YES == ks->info[i].disqualified)
605 gcry_mpi_set_ui (v, 0);
607 paillier_encrypt (v, ks->presecret_polynomial[0],
608 ks->info[i].paillier_g, ks->info[i].paillier_g);
609 gcry_mpi_print (GCRYMPI_FMT_USG, pos, (size_t) remaining, NULL, v);
610 pos += PAILLIER_BITS / 8;
613 GNUNET_CONSENSUS_insert (ks->consensus, element, NULL, NULL);
614 GNUNET_free (element); /* FIXME: maybe stack-allocate instead? */
616 gcry_mpi_release (c);
617 gcry_mpi_release (v);
618 gcry_mpi_release (idx);
622 static struct KeygenPeerInfo *
623 get_keygen_peer_info (const struct KeygenSession *ks,
624 struct GNUNET_PeerIdentity *peer)
627 for (i = 0; i < ks->num_peers; i++)
628 if (0 == memcmp (peer, &ks->info[i].peer, sizeof (struct GNUNET_PeerIdentity)))
635 keygen_round2_new_element (void *cls,
636 const struct GNUNET_SET_Element *element)
638 struct KeygenSession *ks = cls;
639 struct GNUNET_SECRETSHARING_KeygenRevealData *msg;
640 struct KeygenPeerInfo *info;
642 unsigned char *last_pos;
645 msg = (void *) element->data;
646 pos = (void *) &msg[1];
647 // skip exp. pre-shares
648 pos += PAILLIER_BITS / 8 * ks->num_peers;
649 // skip exp. coefficients
650 pos += PAILLIER_BITS / 8 * ks->threshold;
651 // skip to the value for our peer
652 pos += PAILLIER_BITS / 8 * ks->local_peer_idx;
654 last_pos = element->size + (unsigned char *) element->data;
656 if ((pos >= last_pos) || ((last_pos - pos) < (PAILLIER_BITS / 8)))
662 GNUNET_assert (0 == gcry_mpi_scan (&c, GCRYMPI_FMT_USG,
663 pos, PAILLIER_BITS / 8, NULL));
665 info = get_keygen_peer_info (ks, &msg->peer);
673 paillier_decrypt (info->decrypted_preshare, c, ks->paillier_lambda, ks->paillier_mu,
674 ks->info[ks->local_peer_idx].paillier_n);
676 // TODO: validate signature and proofs
682 keygen_round1_conclude (void *cls)
684 struct KeygenSession *ks = cls;
686 // TODO: destroy old consensus
687 // TODO: mark peers without keys as disqualified
689 ks->consensus = GNUNET_CONSENSUS_create (cfg, ks->num_peers, ks->peers, &ks->session_id,
690 keygen_round2_new_element, ks);
692 insert_round2_element (ks);
694 GNUNET_CONSENSUS_conclude (ks->consensus, GNUNET_TIME_UNIT_FOREVER_REL /* FIXME */, keygen_round2_conclude, ks);
699 * Insert the ephemeral key and the presecret commitment
700 * of this peer in the consensus of the given session.
702 * @param ks session to use
705 insert_round1_element (struct KeygenSession *ks)
707 struct GNUNET_SET_Element *element;
708 struct GNUNET_SECRETSHARING_KeygenCommitData *d;
711 // big-endian representation of 'v'
712 unsigned char v_data[PAILLIER_BITS / 8];
714 element = GNUNET_malloc (sizeof *element + sizeof *d);
715 d = (void *) &element[1];
717 element->size = sizeof *d;
719 GNUNET_assert (0 != (v = gcry_mpi_new (PAILLIER_BITS)));
721 gcry_mpi_powm (v, elgamal_g, ks->presecret_polynomial[0], elgamal_p);
723 GNUNET_assert (0 == gcry_mpi_print (GCRYMPI_FMT_USG,
724 v_data, PAILLIER_BITS / 8, NULL,
727 GNUNET_CRYPTO_hash (v_data, PAILLIER_BITS / 8, &d->commitment);
729 GNUNET_assert (0 == gcry_mpi_print (GCRYMPI_FMT_USG,
730 (unsigned char *) d->pubkey.g, PAILLIER_BITS / 8, NULL,
731 ks->info[ks->local_peer_idx].paillier_g));
733 GNUNET_assert (0 == gcry_mpi_print (GCRYMPI_FMT_USG,
734 (unsigned char *) d->pubkey.n, PAILLIER_BITS / 8, NULL,
735 ks->info[ks->local_peer_idx].paillier_n));
741 GNUNET_CONSENSUS_insert (ks->consensus, element, NULL, NULL);
746 * Functions with this signature are called whenever a message is
750 * @param client identification of the client
751 * @param message the actual message
753 static void handle_client_keygen (void *cls,
754 struct GNUNET_SERVER_Client *client,
755 const struct GNUNET_MessageHeader
758 const struct GNUNET_SECRETSHARING_CreateMessage *msg =
759 (const struct GNUNET_SECRETSHARING_CreateMessage *) message;
760 struct KeygenSession *ks;
762 GNUNET_log (GNUNET_ERROR_TYPE_INFO, "client requested key generation\n");
764 ks = GNUNET_new (struct KeygenSession);
766 GNUNET_CONTAINER_DLL_insert (keygen_sessions_head, keygen_sessions_tail, ks);
768 ks->deadline = GNUNET_TIME_absolute_ntoh (msg->deadline);
769 ks->threshold = ntohs (msg->threshold);
770 ks->num_peers = ntohs (msg->num_peers);
772 ks->peers = normalize_peers ((struct GNUNET_PeerIdentity *) &msg[1], ks->num_peers,
773 &ks->num_peers, &ks->local_peer_idx);
775 // TODO: initialize MPIs in peer structure
777 ks->consensus = GNUNET_CONSENSUS_create (cfg, ks->num_peers, ks->peers, &msg->session_id,
778 keygen_round1_new_element, ks);
780 paillier_create (ks->info[ks->local_peer_idx].paillier_g,
781 ks->info[ks->local_peer_idx].paillier_n,
786 generate_presecret_polynomial (ks);
788 insert_round1_element (ks);
790 GNUNET_CONSENSUS_conclude (ks->consensus, GNUNET_TIME_UNIT_FOREVER_REL /* FIXME */, keygen_round1_conclude, ks);
795 * Functions with this signature are called whenever a message is
799 * @param client identification of the client
800 * @param message the actual message
802 static void handle_client_decrypt (void *cls,
803 struct GNUNET_SERVER_Client *client,
804 const struct GNUNET_MessageHeader
812 * Process template requests.
815 * @param server the initialized server
816 * @param c configuration to use
819 run (void *cls, struct GNUNET_SERVER_Handle *server,
820 const struct GNUNET_CONFIGURATION_Handle *c)
822 static const struct GNUNET_SERVER_MessageHandler handlers[] = {
823 {handle_client_keygen, NULL, GNUNET_MESSAGE_TYPE_SECRETSHARING_CLIENT_GENERATE, 0},
824 {handle_client_decrypt, NULL, GNUNET_MESSAGE_TYPE_SECRETSHARING_CLIENT_DECRYPT, 0},
829 if (GNUNET_OK != GNUNET_CRYPTO_get_peer_identity (cfg, &my_peer))
831 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "could not retrieve host identity\n");
833 GNUNET_SCHEDULER_shutdown ();
836 GNUNET_SERVER_add_handlers (server, handlers);
837 GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_FOREVER_REL, &cleanup_task,
843 * The main function for the template service.
845 * @param argc number of arguments from the command line
846 * @param argv command line arguments
847 * @return 0 ok, 1 on error
850 main (int argc, char *const *argv)
853 GNUNET_SERVICE_run (argc, argv, "secretsharing",
854 GNUNET_SERVICE_OPTION_NONE, &run, NULL)) ? 0 : 1;