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 struct GNUNET_CRYPTO_PaillierPublicKey paillier_public_key;
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 * Paillier private key of our peer.
189 struct GNUNET_CRYPTO_PaillierPrivateKey paillier_private_key;
192 * When would we like the key to be established?
194 struct GNUNET_TIME_Absolute deadline;
197 * When does the DKG start? Necessary to compute fractions of the
198 * operation's desired time interval.
200 struct GNUNET_TIME_Absolute start_time;
203 * Index of the local peer in the ordered list
204 * of peers in the session.
206 unsigned int local_peer_idx;
211 * Session to cooperatively decrypt a value.
213 struct DecryptSession
216 * Decrypt sessions are stored in a linked list.
218 struct DecryptSession *next;
221 * Decrypt sessions are stored in a linked list.
223 struct DecryptSession *prev;
226 * Handle to the consensus over partial decryptions.
228 struct GNUNET_CONSENSUS_Handle *consensus;
231 * Client connected to us.
233 struct GNUNET_SERVER_Client *client;
236 * Message queue for 'client'.
238 struct GNUNET_MQ_Handle *client_mq;
241 * When would we like the ciphertext to be
244 struct GNUNET_TIME_Absolute deadline;
247 * Ciphertext we want to decrypt.
249 struct GNUNET_SECRETSHARING_Ciphertext ciphertext;
252 * Share of the local peer.
253 * Containts other important information, such as
254 * the list of other peers.
256 struct GNUNET_SECRETSHARING_Share *share;
259 * State information about other peers.
261 struct DecryptPeerInfo *info;
266 * Decrypt sessions are held in a linked list.
268 static struct DecryptSession *decrypt_sessions_head;
271 * Decrypt sessions are held in a linked list.
273 static struct DecryptSession *decrypt_sessions_tail;
276 * Decrypt sessions are held in a linked list.
278 static struct KeygenSession *keygen_sessions_head;
281 * Decrypt sessions are held in a linked list.
283 static struct KeygenSession *keygen_sessions_tail;
286 * The ElGamal prime field order as libgcrypt mpi.
287 * Initialized in #init_crypto_constants.
289 static gcry_mpi_t elgamal_q;
292 * Modulus of the prime field used for ElGamal.
293 * Initialized in #init_crypto_constants.
295 static gcry_mpi_t elgamal_p;
298 * Generator for prime field of order 'elgamal_q'.
299 * Initialized in #init_crypto_constants.
301 static gcry_mpi_t elgamal_g;
304 * Peer that runs this service.
306 static struct GNUNET_PeerIdentity my_peer;
309 * Peer that runs this service.
311 static struct GNUNET_CRYPTO_EddsaPrivateKey *my_peer_private_key;
314 * Configuration of this service.
316 static const struct GNUNET_CONFIGURATION_Handle *cfg;
319 * Server for this service.
321 static struct GNUNET_SERVER_Handle *srv;
325 * Get the peer info belonging to a peer identity in a keygen session.
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.
331 static struct KeygenPeerInfo *
332 get_keygen_peer_info (const struct KeygenSession *ks,
333 const struct GNUNET_PeerIdentity *peer)
336 for (i = 0; i < ks->num_peers; i++)
337 if (0 == memcmp (peer, &ks->info[i].peer, sizeof (struct GNUNET_PeerIdentity)))
344 * Get the peer info belonging to a peer identity in a decrypt session.
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.
350 static struct DecryptPeerInfo *
351 get_decrypt_peer_info (const struct DecryptSession *ds,
352 const struct GNUNET_PeerIdentity *peer)
355 for (i = 0; i < ds->share->num_peers; i++)
356 if (0 == memcmp (peer, &ds->info[i].peer, sizeof (struct GNUNET_PeerIdentity)))
363 * Interpolate between two points in time.
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
370 static struct GNUNET_TIME_Absolute
371 time_between (struct GNUNET_TIME_Absolute start,
372 struct GNUNET_TIME_Absolute end,
375 struct GNUNET_TIME_Absolute result;
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);
387 * Compare two peer identities. Indended to be used with qsort or bsearch.
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.
394 peer_id_cmp (const void *p1, const void *p2)
396 return memcmp (p1, p2, sizeof (struct GNUNET_PeerIdentity));
401 * Get the index of a peer in an array of peers
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.
410 peer_find (const struct GNUNET_PeerIdentity *haystack, unsigned int n,
411 const struct GNUNET_PeerIdentity *needle)
414 for (i = 0; i < n; i++)
415 if (0 == memcmp (&haystack[i], needle, sizeof (struct GNUNET_PeerIdentity)))
422 * Normalize the given list of peers, by including the local peer
423 * (if it is missing) and sorting the peers by their identity.
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.
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)
437 unsigned int local_peer_in_list;
438 /* number of peers in the normalized list */
440 struct GNUNET_PeerIdentity *normalized;
442 local_peer_in_list = GNUNET_YES;
444 if (peer_find (listed, num_listed, &my_peer) < 0)
446 local_peer_in_list = GNUNET_NO;
450 normalized = GNUNET_new_array (n, struct GNUNET_PeerIdentity);
452 if (GNUNET_NO == local_peer_in_list)
453 normalized[n - 1] = my_peer;
455 memcpy (normalized, listed, num_listed * sizeof (struct GNUNET_PeerIdentity));
456 qsort (normalized, n, sizeof (struct GNUNET_PeerIdentity), &peer_id_cmp);
458 if (NULL != my_peer_idx)
459 *my_peer_idx = peer_find (normalized, n, &my_peer);
460 if (NULL != num_normalized)
468 * Get a the j-th lagrange coefficient for a set of indices.
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
476 compute_lagrange_coefficient (gcry_mpi_t coeff, unsigned int j,
477 unsigned int *indices,
485 /* temp value for l-j */
488 GNUNET_assert (0 != coeff);
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)));
494 gcry_mpi_set_ui (n, 1);
495 gcry_mpi_set_ui (d, 1);
497 for (i = 0; i < num; i++)
499 unsigned int l = indices[i];
502 gcry_mpi_mul_ui (n, n, l + 1);
504 gcry_mpi_set_ui (tmp, l + 1);
505 gcry_mpi_sub_ui (tmp, tmp, j + 1);
506 gcry_mpi_mul (d, d, tmp);
509 // gcry_mpi_invm does not like negative numbers ...
510 gcry_mpi_mod (d, d, elgamal_q);
512 GNUNET_assert (gcry_mpi_cmp_ui (d, 0) > 0);
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));
518 gcry_mpi_mulm (coeff, n, d, elgamal_q);
520 gcry_mpi_release (n);
521 gcry_mpi_release (d);
522 gcry_mpi_release (tmp);
527 decrypt_session_destroy (struct DecryptSession *ds)
529 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "destroying decrypt session\n");
531 GNUNET_CONTAINER_DLL_remove (decrypt_sessions_head, decrypt_sessions_tail, ds);
533 if (NULL != ds->client_mq)
535 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "destroying decrypt MQ\n");
536 GNUNET_MQ_destroy (ds->client_mq);
537 ds->client_mq = NULL;
540 if (NULL != ds->client)
542 GNUNET_SERVER_client_disconnect (ds->client);
551 keygen_session_destroy (struct KeygenSession *ks)
553 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "destroying keygen session\n");
555 GNUNET_CONTAINER_DLL_remove (keygen_sessions_head, keygen_sessions_tail, ks);
557 if (NULL != ks->client_mq)
559 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "destroying keygen MQ\n");
560 GNUNET_MQ_destroy (ks->client_mq);
561 ks->client_mq = NULL;
564 if (NULL != ks->client)
566 GNUNET_SERVER_client_disconnect (ks->client);
575 * Task run during shutdown.
581 cleanup_task (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
583 while (NULL != decrypt_sessions_head)
584 decrypt_session_destroy (decrypt_sessions_head);
586 while (NULL != keygen_sessions_head)
587 keygen_session_destroy (keygen_sessions_head);
592 * Generate the random coefficients of our pre-secret polynomial
594 * @param ks the session
597 generate_presecret_polynomial (struct KeygenSession *ks)
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++)
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.
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));
619 * Consensus element handler for round one.
620 * We should get one ephemeral key for each peer.
622 * @param cls Closure (keygen session).
623 * @param element The element from consensus, or
624 * NULL if consensus failed.
627 keygen_round1_new_element (void *cls,
628 const struct GNUNET_SET_Element *element)
630 const struct GNUNET_SECRETSHARING_KeygenCommitData *d;
631 struct KeygenSession *ks = cls;
632 struct KeygenPeerInfo *info;
636 GNUNET_log (GNUNET_ERROR_TYPE_WARNING, "round1 consensus failed\n");
640 /* elements have fixed size */
641 if (element->size != sizeof (struct GNUNET_SECRETSHARING_KeygenCommitData))
643 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
644 "keygen commit data with wrong size (%u) in consensus, "
646 element->size, sizeof (struct GNUNET_SECRETSHARING_KeygenCommitData));
650 GNUNET_log (GNUNET_ERROR_TYPE_INFO, "got round1 element\n");
653 info = get_keygen_peer_info (ks, &d->peer);
657 GNUNET_log (GNUNET_ERROR_TYPE_WARNING, "keygen commit data with wrong peer identity (%s) in consensus\n",
658 GNUNET_i2s (&d->peer));
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)))
666 GNUNET_log (GNUNET_ERROR_TYPE_WARNING, "keygen commit data with wrong signature purpose size in consensus\n");
670 if (GNUNET_OK != GNUNET_CRYPTO_eddsa_verify (GNUNET_SIGNATURE_PURPOSE_SECRETSHARING_DKG1,
671 &d->purpose, &d->signature, &d->peer.public_key))
673 GNUNET_log (GNUNET_ERROR_TYPE_WARNING, "keygen commit data with invalid signature in consensus\n");
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;
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.
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?
694 horner_eval (gcry_mpi_t z, gcry_mpi_t *coeff, unsigned int num_coeff, gcry_mpi_t x, gcry_mpi_t m)
698 gcry_mpi_set_ui (z, 0);
699 for (i = 0; i < num_coeff; i++)
702 gcry_mpi_mul (z, z, x);
703 gcry_mpi_addm (z, z, coeff[num_coeff - i - 1], m);
709 keygen_round2_conclude (void *cls)
711 struct KeygenSession *ks = cls;
712 struct GNUNET_SECRETSHARING_SecretReadyMessage *m;
713 struct GNUNET_MQ_Envelope *ev;
717 struct GNUNET_SECRETSHARING_Share *share;
723 GNUNET_log (GNUNET_ERROR_TYPE_INFO, "round2 conclude\n");
725 GNUNET_assert (0 != (s = gcry_mpi_new (GNUNET_SECRETSHARING_ELGAMAL_BITS)));
726 GNUNET_assert (0 != (h = gcry_mpi_new (GNUNET_SECRETSHARING_ELGAMAL_BITS)));
728 // multiplicative identity
729 gcry_mpi_set_ui (h, 1);
731 gcry_mpi_set_ui (s, 0);
733 share = GNUNET_new (struct GNUNET_SECRETSHARING_Share);
735 share->num_peers = 0;
737 for (i = 0; i < ks->num_peers; i++)
738 if (GNUNET_YES == ks->info[i].round2_valid)
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);
746 /* maybe we're not even in the list of peers? */
747 share->my_peer = share->num_peers;
750 for (i = 0; i < ks->num_peers; i++)
752 if (GNUNET_YES == ks->info[i].round2_valid)
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)))
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);
766 GNUNET_log (GNUNET_ERROR_TYPE_INFO, "keygen completed with %u peers\n", share->num_peers);
768 /* Write the share. If 0 peers completed the dkg, an empty
769 * share will be sent. */
771 m = GNUNET_malloc (sizeof (struct GNUNET_SECRETSHARING_SecretReadyMessage) +
772 ks->num_peers * sizeof (struct GNUNET_PeerIdentity));
774 GNUNET_assert (GNUNET_OK == GNUNET_SECRETSHARING_share_write (share, NULL, 0, &share_size));
776 ev = GNUNET_MQ_msg_extra (m, share_size,
777 GNUNET_MESSAGE_TYPE_SECRETSHARING_CLIENT_SECRET_READY);
779 GNUNET_assert (GNUNET_OK == GNUNET_SECRETSHARING_share_write (share, &m[1], share_size, NULL));
781 GNUNET_MQ_send (ks->client_mq, ev);
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
793 * @param ks session to use
796 insert_round2_element (struct KeygenSession *ks)
798 struct GNUNET_SET_Element *element;
799 struct GNUNET_SECRETSHARING_KeygenRevealData *d;
801 unsigned char *last_pos;
808 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "P%u: Inserting round2 element\n",
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)));
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);
820 element = GNUNET_malloc (sizeof (struct GNUNET_SET_Element) + element_size);
821 element->size = element_size;
822 element->data = (void *) &element[1];
824 d = (void *) element->data;
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;
832 // exponentiated pre-shares
833 for (i = 0; i < ks->num_peers; i++)
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;
846 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "P%u: computed exp preshares\n",
849 // encrypted pre-shares
850 for (i = 0; i < ks->num_peers; i++)
852 ptrdiff_t remaining = last_pos - pos;
853 struct GNUNET_CRYPTO_PaillierCiphertext *ciphertext;
855 GNUNET_assert (remaining > 0);
856 ciphertext = (void *) pos;
857 memset (ciphertext, 0, sizeof *ciphertext);
858 if (GNUNET_YES == ks->info[i].round1_valid)
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);
868 pos += sizeof *ciphertext;
871 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "P%u: computed enc preshares\n",
874 // exponentiated coefficients
875 for (i = 0; i < ks->threshold; i++)
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;
884 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "P%u: computed exp coefficients\n",
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);
891 GNUNET_CONSENSUS_insert (ks->consensus, element, NULL, NULL);
892 GNUNET_free (element); /* FIXME: maybe stack-allocate instead? */
894 gcry_mpi_release (v);
895 gcry_mpi_release (idx);
900 keygen_round2_new_element (void *cls,
901 const struct GNUNET_SET_Element *element)
903 struct KeygenSession *ks = cls;
904 const struct GNUNET_SECRETSHARING_KeygenRevealData *d;
905 struct KeygenPeerInfo *info;
908 size_t expected_element_size;
912 GNUNET_log (GNUNET_ERROR_TYPE_WARNING, "round2 consensus failed\n");
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);
921 if (element->size != expected_element_size)
923 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
924 "keygen round2 data with wrong size (%u) in consensus, "
926 element->size, expected_element_size);
930 d = (const void *) element->data;
932 info = get_keygen_peer_info (ks, &d->peer);
936 GNUNET_log (GNUNET_ERROR_TYPE_WARNING, "keygen commit data with wrong peer identity (%s) in consensus\n",
937 GNUNET_i2s (&d->peer));
941 if (GNUNET_NO == info->round1_valid)
943 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
944 "ignoring round2 element from peer with invalid round1 element (%s)\n",
945 GNUNET_i2s (&d->peer));
949 if (GNUNET_YES == info->round2_valid)
951 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
952 "ignoring duplicate round2 element (%s)\n",
953 GNUNET_i2s (&d->peer));
957 GNUNET_log (GNUNET_ERROR_TYPE_INFO, "got round2 element\n");
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);
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;
973 GNUNET_CRYPTO_mpi_scan_unsigned (&c, pos, GNUNET_CRYPTO_PAILLIER_BITS * 2 / 8);
975 // FIXME: remove this ugly block once we changed all MPIs to containers
977 struct GNUNET_CRYPTO_PaillierPlaintext plaintext;
978 struct GNUNET_CRYPTO_PaillierCiphertext ciphertext;
980 GNUNET_CRYPTO_mpi_print_unsigned (&ciphertext, sizeof ciphertext, c);
983 GNUNET_CRYPTO_paillier_decrypt (&ks->paillier_private_key, &ks->info[ks->local_peer_idx].paillier_public_key,
984 &ciphertext, &plaintext);
985 GNUNET_CRYPTO_mpi_scan_unsigned (&info->decrypted_preshare, &plaintext,
989 // TODO: validate zero knowledge proofs
991 if (ntohl (d->purpose.size) !=
992 element->size - offsetof (struct GNUNET_SECRETSHARING_KeygenRevealData, purpose))
994 GNUNET_log (GNUNET_ERROR_TYPE_WARNING, "keygen reveal data with wrong signature purpose size in consensus\n");
998 if (GNUNET_OK != GNUNET_CRYPTO_eddsa_verify (GNUNET_SIGNATURE_PURPOSE_SECRETSHARING_DKG2,
999 &d->purpose, &d->signature, &d->peer.public_key))
1001 GNUNET_log (GNUNET_ERROR_TYPE_WARNING, "keygen reveal data with invalid signature in consensus\n");
1005 info->round2_valid = GNUNET_YES;
1010 * Called when the first consensus round has concluded.
1011 * Will initiate the second round.
1013 * @param cls closure
1016 keygen_round1_conclude (void *cls)
1018 struct KeygenSession *ks = cls;
1020 GNUNET_CONSENSUS_destroy (ks->consensus);
1022 ks->consensus = GNUNET_CONSENSUS_create (cfg, ks->num_peers, ks->peers, &ks->session_id,
1023 keygen_round2_new_element, ks);
1025 insert_round2_element (ks);
1027 GNUNET_CONSENSUS_conclude (ks->consensus,
1028 /* last round, thus conclude at DKG deadline */
1030 keygen_round2_conclude,
1036 * Insert the ephemeral key and the presecret commitment
1037 * of this peer in the consensus of the given session.
1039 * @param ks session to use
1042 insert_round1_element (struct KeygenSession *ks)
1044 struct GNUNET_SET_Element *element;
1045 struct GNUNET_SECRETSHARING_KeygenCommitData *d;
1048 // big-endian representation of 'v'
1049 unsigned char v_data[GNUNET_SECRETSHARING_ELGAMAL_BITS / 8];
1051 element = GNUNET_malloc (sizeof *element + sizeof *d);
1052 d = (void *) &element[1];
1054 element->size = sizeof *d;
1058 GNUNET_assert (0 != (v = gcry_mpi_new (GNUNET_SECRETSHARING_ELGAMAL_BITS)));
1060 gcry_mpi_powm (v, elgamal_g, ks->presecret_polynomial[0], elgamal_p);
1062 GNUNET_CRYPTO_mpi_print_unsigned (v_data, GNUNET_SECRETSHARING_ELGAMAL_BITS / 8, v);
1064 GNUNET_CRYPTO_hash (v_data, GNUNET_SECRETSHARING_ELGAMAL_BITS / 8, &d->commitment);
1066 d->pubkey = ks->info[ks->local_peer_idx].paillier_public_key;
1068 d->purpose.size = htonl ((sizeof *d) - offsetof (struct GNUNET_SECRETSHARING_KeygenCommitData, purpose));
1069 d->purpose.purpose = htonl (GNUNET_SIGNATURE_PURPOSE_SECRETSHARING_DKG1);
1070 GNUNET_assert (GNUNET_OK == GNUNET_CRYPTO_eddsa_sign (my_peer_private_key, &d->purpose, &d->signature));
1072 GNUNET_CONSENSUS_insert (ks->consensus, element, NULL, NULL);
1074 gcry_mpi_release (v);
1075 GNUNET_free (element);
1080 * Functions with this signature are called whenever a message is
1083 * @param cls closure
1084 * @param client identification of the client
1085 * @param message the actual message
1087 static void handle_client_keygen (void *cls,
1088 struct GNUNET_SERVER_Client *client,
1089 const struct GNUNET_MessageHeader
1092 const struct GNUNET_SECRETSHARING_CreateMessage *msg =
1093 (const struct GNUNET_SECRETSHARING_CreateMessage *) message;
1094 struct KeygenSession *ks;
1097 GNUNET_log (GNUNET_ERROR_TYPE_INFO, "client requested key generation\n");
1099 ks = GNUNET_new (struct KeygenSession);
1101 /* FIXME: check if client already has some session */
1103 GNUNET_CONTAINER_DLL_insert (keygen_sessions_head, keygen_sessions_tail, ks);
1105 ks->client = client;
1106 ks->client_mq = GNUNET_MQ_queue_for_server_client (client);
1108 ks->deadline = GNUNET_TIME_absolute_ntoh (msg->deadline);
1109 ks->threshold = ntohs (msg->threshold);
1110 ks->num_peers = ntohs (msg->num_peers);
1112 ks->peers = normalize_peers ((struct GNUNET_PeerIdentity *) &msg[1], ks->num_peers,
1113 &ks->num_peers, &ks->local_peer_idx);
1116 GNUNET_log (GNUNET_ERROR_TYPE_INFO, "first round of consensus with %u peers\n", ks->num_peers);
1117 ks->consensus = GNUNET_CONSENSUS_create (cfg, ks->num_peers, ks->peers, &msg->session_id,
1118 keygen_round1_new_element, ks);
1120 ks->info = GNUNET_new_array (ks->num_peers, struct KeygenPeerInfo);
1122 for (i = 0; i < ks->num_peers; i++)
1123 ks->info[i].peer = ks->peers[i];
1125 GNUNET_CRYPTO_paillier_create (&ks->info[ks->local_peer_idx].paillier_public_key,
1126 &ks->paillier_private_key);
1128 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "P%u: Generated paillier key pair\n", ks->local_peer_idx);
1130 generate_presecret_polynomial (ks);
1132 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "P%u: Generated presecret polynomial\n", ks->local_peer_idx);
1134 insert_round1_element (ks);
1136 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "P%u: Concluding for round 1\n", ks->local_peer_idx);
1138 GNUNET_CONSENSUS_conclude (ks->consensus,
1139 /* half the overall time */
1140 time_between (ks->start_time, ks->deadline, 1, 2),
1141 keygen_round1_conclude,
1144 GNUNET_SERVER_receive_done (client, GNUNET_OK);
1146 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "P%u: Waiting for round 1 elements ...\n", ks->local_peer_idx);
1151 * Called when the partial decryption consensus concludes.
1154 decrypt_conclude (void *cls)
1156 struct DecryptSession *ds = cls;
1157 struct GNUNET_SECRETSHARING_DecryptResponseMessage *msg;
1158 struct GNUNET_MQ_Envelope *ev;
1159 gcry_mpi_t lagrange;
1164 unsigned int *indices;
1169 GNUNET_assert (0 != (lagrange = gcry_mpi_new (0)));
1170 GNUNET_assert (0 != (m = gcry_mpi_new (0)));
1171 GNUNET_assert (0 != (tmp = gcry_mpi_new (0)));
1172 GNUNET_assert (0 != (prod = gcry_mpi_new (0)));
1175 for (i = 0; i < ds->share->num_peers; i++)
1176 if (NULL != ds->info[i].partial_decryption)
1179 indices = GNUNET_malloc (num * sizeof (unsigned int));
1181 for (i = 0; i < ds->share->num_peers; i++)
1182 if (NULL != ds->info[i].partial_decryption)
1183 indices[j++] = ds->info[i].original_index;
1185 GNUNET_log (GNUNET_ERROR_TYPE_INFO, "P%u: decrypt conclude, with %u peers\n",
1186 ds->share->my_peer, num);
1188 gcry_mpi_set_ui (prod, 1);
1189 for (i = 0; i < num; i++)
1192 GNUNET_log (GNUNET_ERROR_TYPE_INFO, "P%u: index of %u: %u\n",
1193 ds->share->my_peer, i, indices[i]);
1194 compute_lagrange_coefficient (lagrange, indices[i], indices, num);
1196 gcry_mpi_powm (tmp, ds->info[indices[i]].partial_decryption, lagrange, elgamal_p);
1198 // product of all exponentiated partiel decryptions ...
1199 gcry_mpi_mulm (prod, prod, tmp, elgamal_p);
1202 GNUNET_CRYPTO_mpi_scan_unsigned (&c_2, ds->ciphertext.c2_bits, GNUNET_SECRETSHARING_ELGAMAL_BITS / 8);
1204 GNUNET_assert (0 != gcry_mpi_invm (prod, prod, elgamal_p));
1205 gcry_mpi_mulm (m, c_2, prod, elgamal_p);
1206 ev = GNUNET_MQ_msg (msg, GNUNET_MESSAGE_TYPE_SECRETSHARING_CLIENT_DECRYPT_DONE);
1207 GNUNET_CRYPTO_mpi_print_unsigned (&msg->plaintext, GNUNET_SECRETSHARING_ELGAMAL_BITS / 8, m);
1208 msg->success = htonl (1);
1209 GNUNET_MQ_send (ds->client_mq, ev);
1211 GNUNET_log (GNUNET_ERROR_TYPE_INFO, "sent decrypt done to client\n");
1213 // FIXME: what if not enough peers participated?
1218 * Called when a new partial decryption arrives.
1221 decrypt_new_element (void *cls,
1222 const struct GNUNET_SET_Element *element)
1224 struct DecryptSession *session = cls;
1225 const struct GNUNET_SECRETSHARING_DecryptData *d;
1226 struct DecryptPeerInfo *info;
1228 if (NULL == element)
1230 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "decryption failed\n");
1231 /* FIXME: destroy */
1235 if (element->size != sizeof *d)
1237 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "element of wrong size in decrypt consensus\n");
1243 info = get_decrypt_peer_info (session, &d->peer);
1247 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "decrypt element from invalid peer (%s)\n",
1248 GNUNET_i2s (&d->peer));
1252 if (NULL != info->partial_decryption)
1254 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "decrypt element duplicate\n",
1255 GNUNET_i2s (&d->peer));
1259 // FIXME: check NIZP first
1261 GNUNET_CRYPTO_mpi_scan_unsigned (&info->partial_decryption, &d->partial_decryption,
1262 GNUNET_SECRETSHARING_ELGAMAL_BITS / 8);
1266 insert_decrypt_element (struct DecryptSession *ds)
1268 struct GNUNET_SECRETSHARING_DecryptData d;
1269 struct GNUNET_SET_Element element;
1273 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "P%u: Inserting decrypt element\n",
1274 ds->share->my_peer);
1276 GNUNET_CRYPTO_mpi_scan_unsigned (&x, &ds->ciphertext.c1_bits,
1277 GNUNET_SECRETSHARING_ELGAMAL_BITS / 8);
1278 GNUNET_CRYPTO_mpi_scan_unsigned (&s, &ds->share->my_share,
1279 GNUNET_SECRETSHARING_ELGAMAL_BITS / 8);
1281 gcry_mpi_powm (x, x, s, elgamal_p);
1283 element.data = (void *) &d;
1284 element.size = sizeof (struct GNUNET_SECRETSHARING_DecryptData);
1287 /* make vagrind happy until we implement the real deal ... */
1288 memset (&d.nizk_commit1, 0, sizeof d.nizk_commit1);
1289 memset (&d.nizk_commit2, 0, sizeof d.nizk_commit2);
1290 memset (&d.nizk_response, 0, sizeof d.nizk_response);
1292 d.ciphertext = ds->ciphertext;
1294 d.purpose.size = htonl (element.size - offsetof (struct GNUNET_SECRETSHARING_DecryptData, purpose));
1295 d.purpose.purpose = htonl (GNUNET_SIGNATURE_PURPOSE_SECRETSHARING_DECRYPTION);
1297 GNUNET_CRYPTO_eddsa_sign (my_peer_private_key, &d.purpose, &d.signature);
1299 GNUNET_CRYPTO_mpi_print_unsigned (&d.partial_decryption, GNUNET_SECRETSHARING_ELGAMAL_BITS / 8, x);
1301 GNUNET_CONSENSUS_insert (ds->consensus, &element, NULL, NULL);
1302 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "P%u: Inserting decrypt element done!\n",
1303 ds->share->my_peer);
1308 * Functions with this signature are called whenever a message is
1311 * @param cls closure
1312 * @param client identification of the client
1313 * @param message the actual message
1315 static void handle_client_decrypt (void *cls,
1316 struct GNUNET_SERVER_Client *client,
1317 const struct GNUNET_MessageHeader
1320 const struct GNUNET_SECRETSHARING_DecryptRequestMessage *msg =
1321 (const void *) message;
1322 struct DecryptSession *ds;
1323 struct GNUNET_HashCode session_id;
1326 ds = GNUNET_new (struct DecryptSession);
1327 // FIXME: check if session already exists
1328 GNUNET_CONTAINER_DLL_insert (decrypt_sessions_head, decrypt_sessions_tail, ds);
1329 ds->client = client;
1330 ds->client_mq = GNUNET_MQ_queue_for_server_client (client);
1331 ds->deadline = GNUNET_TIME_absolute_ntoh (msg->deadline);
1332 ds->ciphertext = msg->ciphertext;
1334 ds->share = GNUNET_SECRETSHARING_share_read (&msg[1], ntohs (msg->header.size) - sizeof *msg, NULL);
1335 // FIXME: probably should be break rather than assert
1336 GNUNET_assert (NULL != ds->share);
1338 // FIXME: this is probably sufficient, but kdf/hash with all values would be nicer ...
1339 GNUNET_CRYPTO_hash (&msg->ciphertext, sizeof (struct GNUNET_SECRETSHARING_Ciphertext), &session_id);
1341 ds->consensus = GNUNET_CONSENSUS_create (cfg,
1342 ds->share->num_peers,
1345 &decrypt_new_element,
1349 ds->info = GNUNET_new_array (ds->share->num_peers, struct DecryptPeerInfo);
1350 for (i = 0; i < ds->share->num_peers; i++)
1352 ds->info[i].peer = ds->share->peers[i];
1353 ds->info[i].original_index = ds->share->original_indices[i];
1356 insert_decrypt_element (ds);
1358 GNUNET_CONSENSUS_conclude (ds->consensus, ds->deadline, decrypt_conclude, ds);
1360 GNUNET_SERVER_receive_done (client, GNUNET_OK);
1362 GNUNET_log (GNUNET_ERROR_TYPE_INFO, "decrypting with %u peers\n",
1363 ds->share->num_peers);
1368 init_crypto_constants (void)
1370 GNUNET_assert (0 == gcry_mpi_scan (&elgamal_q, GCRYMPI_FMT_HEX,
1371 GNUNET_SECRETSHARING_ELGAMAL_Q_HEX, 0, NULL));
1372 GNUNET_assert (0 == gcry_mpi_scan (&elgamal_p, GCRYMPI_FMT_HEX,
1373 GNUNET_SECRETSHARING_ELGAMAL_P_HEX, 0, NULL));
1374 GNUNET_assert (0 == gcry_mpi_scan (&elgamal_g, GCRYMPI_FMT_HEX,
1375 GNUNET_SECRETSHARING_ELGAMAL_G_HEX, 0, NULL));
1379 static struct KeygenSession *
1380 keygen_session_get (struct GNUNET_SERVER_Client *client)
1382 struct KeygenSession *ks;
1383 for (ks = keygen_sessions_head; NULL != ks; ks = ks->next)
1384 if (ks->client == client)
1389 static struct DecryptSession *
1390 decrypt_session_get (struct GNUNET_SERVER_Client *client)
1392 struct DecryptSession *ds;
1393 for (ds = decrypt_sessions_head; NULL != ds; ds = ds->next)
1394 if (ds->client == client)
1401 * Clean up after a client has disconnected
1403 * @param cls closure, unused
1404 * @param client the client to clean up after
1407 handle_client_disconnect (void *cls, struct GNUNET_SERVER_Client *client)
1409 struct KeygenSession *ks;
1410 struct DecryptSession *ds;
1412 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "handling client disconnect\n");
1414 ks = keygen_session_get (client);
1416 keygen_session_destroy (ks);
1418 ds = decrypt_session_get (client);
1420 decrypt_session_destroy (ds);
1425 * Process template requests.
1427 * @param cls closure
1428 * @param server the initialized server
1429 * @param c configuration to use
1432 run (void *cls, struct GNUNET_SERVER_Handle *server,
1433 const struct GNUNET_CONFIGURATION_Handle *c)
1435 static const struct GNUNET_SERVER_MessageHandler handlers[] = {
1436 {handle_client_keygen, NULL, GNUNET_MESSAGE_TYPE_SECRETSHARING_CLIENT_GENERATE, 0},
1437 {handle_client_decrypt, NULL, GNUNET_MESSAGE_TYPE_SECRETSHARING_CLIENT_DECRYPT, 0},
1442 my_peer_private_key = GNUNET_CRYPTO_eddsa_key_create_from_configuration (c);
1443 if (NULL == my_peer_private_key)
1445 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "could not access host private key\n");
1447 GNUNET_SCHEDULER_shutdown ();
1450 init_crypto_constants ();
1451 if (GNUNET_OK != GNUNET_CRYPTO_get_peer_identity (cfg, &my_peer))
1453 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "could not retrieve host identity\n");
1455 GNUNET_SCHEDULER_shutdown ();
1458 GNUNET_SERVER_add_handlers (server, handlers);
1459 GNUNET_SERVER_disconnect_notify (server, &handle_client_disconnect, NULL);
1460 GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_FOREVER_REL, &cleanup_task,
1466 * The main function for the template service.
1468 * @param argc number of arguments from the command line
1469 * @param argv command line arguments
1470 * @return 0 ok, 1 on error
1473 main (int argc, char *const *argv)
1475 return (GNUNET_OK ==
1476 GNUNET_SERVICE_run (argc, argv, "secretsharing",
1477 GNUNET_SERVICE_OPTION_NONE, &run, NULL)) ? 0 : 1;