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;
907 struct GNUNET_CRYPTO_PaillierPlaintext plaintext;
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_paillier_decrypt (&ks->paillier_private_key, &ks->info[ks->local_peer_idx].paillier_public_key,
974 (struct GNUNET_CRYPTO_PaillierCiphertext *) pos, &plaintext);
975 GNUNET_CRYPTO_mpi_scan_unsigned (&info->decrypted_preshare, &plaintext,
978 // TODO: validate zero knowledge proofs
980 if (ntohl (d->purpose.size) !=
981 element->size - offsetof (struct GNUNET_SECRETSHARING_KeygenRevealData, purpose))
983 GNUNET_log (GNUNET_ERROR_TYPE_WARNING, "keygen reveal data with wrong signature purpose size in consensus\n");
987 if (GNUNET_OK != GNUNET_CRYPTO_eddsa_verify (GNUNET_SIGNATURE_PURPOSE_SECRETSHARING_DKG2,
988 &d->purpose, &d->signature, &d->peer.public_key))
990 GNUNET_log (GNUNET_ERROR_TYPE_WARNING, "keygen reveal data with invalid signature in consensus\n");
994 info->round2_valid = GNUNET_YES;
999 * Called when the first consensus round has concluded.
1000 * Will initiate the second round.
1002 * @param cls closure
1005 keygen_round1_conclude (void *cls)
1007 struct KeygenSession *ks = cls;
1009 GNUNET_CONSENSUS_destroy (ks->consensus);
1011 ks->consensus = GNUNET_CONSENSUS_create (cfg, ks->num_peers, ks->peers, &ks->session_id,
1012 keygen_round2_new_element, ks);
1014 insert_round2_element (ks);
1016 GNUNET_CONSENSUS_conclude (ks->consensus,
1017 /* last round, thus conclude at DKG deadline */
1019 keygen_round2_conclude,
1025 * Insert the ephemeral key and the presecret commitment
1026 * of this peer in the consensus of the given session.
1028 * @param ks session to use
1031 insert_round1_element (struct KeygenSession *ks)
1033 struct GNUNET_SET_Element *element;
1034 struct GNUNET_SECRETSHARING_KeygenCommitData *d;
1037 // big-endian representation of 'v'
1038 unsigned char v_data[GNUNET_SECRETSHARING_ELGAMAL_BITS / 8];
1040 element = GNUNET_malloc (sizeof *element + sizeof *d);
1041 d = (void *) &element[1];
1043 element->size = sizeof *d;
1047 GNUNET_assert (0 != (v = gcry_mpi_new (GNUNET_SECRETSHARING_ELGAMAL_BITS)));
1049 gcry_mpi_powm (v, elgamal_g, ks->presecret_polynomial[0], elgamal_p);
1051 GNUNET_CRYPTO_mpi_print_unsigned (v_data, GNUNET_SECRETSHARING_ELGAMAL_BITS / 8, v);
1053 GNUNET_CRYPTO_hash (v_data, GNUNET_SECRETSHARING_ELGAMAL_BITS / 8, &d->commitment);
1055 d->pubkey = ks->info[ks->local_peer_idx].paillier_public_key;
1057 d->purpose.size = htonl ((sizeof *d) - offsetof (struct GNUNET_SECRETSHARING_KeygenCommitData, purpose));
1058 d->purpose.purpose = htonl (GNUNET_SIGNATURE_PURPOSE_SECRETSHARING_DKG1);
1059 GNUNET_assert (GNUNET_OK == GNUNET_CRYPTO_eddsa_sign (my_peer_private_key, &d->purpose, &d->signature));
1061 GNUNET_CONSENSUS_insert (ks->consensus, element, NULL, NULL);
1063 gcry_mpi_release (v);
1064 GNUNET_free (element);
1069 * Functions with this signature are called whenever a message is
1072 * @param cls closure
1073 * @param client identification of the client
1074 * @param message the actual message
1076 static void handle_client_keygen (void *cls,
1077 struct GNUNET_SERVER_Client *client,
1078 const struct GNUNET_MessageHeader
1081 const struct GNUNET_SECRETSHARING_CreateMessage *msg =
1082 (const struct GNUNET_SECRETSHARING_CreateMessage *) message;
1083 struct KeygenSession *ks;
1086 GNUNET_log (GNUNET_ERROR_TYPE_INFO, "client requested key generation\n");
1088 ks = GNUNET_new (struct KeygenSession);
1090 /* FIXME: check if client already has some session */
1092 GNUNET_CONTAINER_DLL_insert (keygen_sessions_head, keygen_sessions_tail, ks);
1094 ks->client = client;
1095 ks->client_mq = GNUNET_MQ_queue_for_server_client (client);
1097 ks->deadline = GNUNET_TIME_absolute_ntoh (msg->deadline);
1098 ks->threshold = ntohs (msg->threshold);
1099 ks->num_peers = ntohs (msg->num_peers);
1101 ks->peers = normalize_peers ((struct GNUNET_PeerIdentity *) &msg[1], ks->num_peers,
1102 &ks->num_peers, &ks->local_peer_idx);
1105 GNUNET_log (GNUNET_ERROR_TYPE_INFO, "first round of consensus with %u peers\n", ks->num_peers);
1106 ks->consensus = GNUNET_CONSENSUS_create (cfg, ks->num_peers, ks->peers, &msg->session_id,
1107 keygen_round1_new_element, ks);
1109 ks->info = GNUNET_new_array (ks->num_peers, struct KeygenPeerInfo);
1111 for (i = 0; i < ks->num_peers; i++)
1112 ks->info[i].peer = ks->peers[i];
1114 GNUNET_CRYPTO_paillier_create (&ks->info[ks->local_peer_idx].paillier_public_key,
1115 &ks->paillier_private_key);
1117 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "P%u: Generated paillier key pair\n", ks->local_peer_idx);
1119 generate_presecret_polynomial (ks);
1121 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "P%u: Generated presecret polynomial\n", ks->local_peer_idx);
1123 insert_round1_element (ks);
1125 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "P%u: Concluding for round 1\n", ks->local_peer_idx);
1127 GNUNET_CONSENSUS_conclude (ks->consensus,
1128 /* half the overall time */
1129 time_between (ks->start_time, ks->deadline, 1, 2),
1130 keygen_round1_conclude,
1133 GNUNET_SERVER_receive_done (client, GNUNET_OK);
1135 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "P%u: Waiting for round 1 elements ...\n", ks->local_peer_idx);
1140 * Called when the partial decryption consensus concludes.
1143 decrypt_conclude (void *cls)
1145 struct DecryptSession *ds = cls;
1146 struct GNUNET_SECRETSHARING_DecryptResponseMessage *msg;
1147 struct GNUNET_MQ_Envelope *ev;
1148 gcry_mpi_t lagrange;
1153 unsigned int *indices;
1158 GNUNET_assert (0 != (lagrange = gcry_mpi_new (0)));
1159 GNUNET_assert (0 != (m = gcry_mpi_new (0)));
1160 GNUNET_assert (0 != (tmp = gcry_mpi_new (0)));
1161 GNUNET_assert (0 != (prod = gcry_mpi_new (0)));
1164 for (i = 0; i < ds->share->num_peers; i++)
1165 if (NULL != ds->info[i].partial_decryption)
1168 indices = GNUNET_malloc (num * sizeof (unsigned int));
1170 for (i = 0; i < ds->share->num_peers; i++)
1171 if (NULL != ds->info[i].partial_decryption)
1172 indices[j++] = ds->info[i].original_index;
1174 GNUNET_log (GNUNET_ERROR_TYPE_INFO, "P%u: decrypt conclude, with %u peers\n",
1175 ds->share->my_peer, num);
1177 gcry_mpi_set_ui (prod, 1);
1178 for (i = 0; i < num; i++)
1181 GNUNET_log (GNUNET_ERROR_TYPE_INFO, "P%u: index of %u: %u\n",
1182 ds->share->my_peer, i, indices[i]);
1183 compute_lagrange_coefficient (lagrange, indices[i], indices, num);
1185 gcry_mpi_powm (tmp, ds->info[indices[i]].partial_decryption, lagrange, elgamal_p);
1187 // product of all exponentiated partiel decryptions ...
1188 gcry_mpi_mulm (prod, prod, tmp, elgamal_p);
1191 GNUNET_CRYPTO_mpi_scan_unsigned (&c_2, ds->ciphertext.c2_bits, GNUNET_SECRETSHARING_ELGAMAL_BITS / 8);
1193 GNUNET_assert (0 != gcry_mpi_invm (prod, prod, elgamal_p));
1194 gcry_mpi_mulm (m, c_2, prod, elgamal_p);
1195 ev = GNUNET_MQ_msg (msg, GNUNET_MESSAGE_TYPE_SECRETSHARING_CLIENT_DECRYPT_DONE);
1196 GNUNET_CRYPTO_mpi_print_unsigned (&msg->plaintext, GNUNET_SECRETSHARING_ELGAMAL_BITS / 8, m);
1197 msg->success = htonl (1);
1198 GNUNET_MQ_send (ds->client_mq, ev);
1200 GNUNET_log (GNUNET_ERROR_TYPE_INFO, "sent decrypt done to client\n");
1202 // FIXME: what if not enough peers participated?
1207 * Called when a new partial decryption arrives.
1210 decrypt_new_element (void *cls,
1211 const struct GNUNET_SET_Element *element)
1213 struct DecryptSession *session = cls;
1214 const struct GNUNET_SECRETSHARING_DecryptData *d;
1215 struct DecryptPeerInfo *info;
1217 if (NULL == element)
1219 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "decryption failed\n");
1220 /* FIXME: destroy */
1224 if (element->size != sizeof *d)
1226 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "element of wrong size in decrypt consensus\n");
1232 info = get_decrypt_peer_info (session, &d->peer);
1236 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "decrypt element from invalid peer (%s)\n",
1237 GNUNET_i2s (&d->peer));
1241 if (NULL != info->partial_decryption)
1243 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "decrypt element duplicate\n",
1244 GNUNET_i2s (&d->peer));
1248 // FIXME: check NIZP first
1250 GNUNET_CRYPTO_mpi_scan_unsigned (&info->partial_decryption, &d->partial_decryption,
1251 GNUNET_SECRETSHARING_ELGAMAL_BITS / 8);
1255 insert_decrypt_element (struct DecryptSession *ds)
1257 struct GNUNET_SECRETSHARING_DecryptData d;
1258 struct GNUNET_SET_Element element;
1262 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "P%u: Inserting decrypt element\n",
1263 ds->share->my_peer);
1265 GNUNET_CRYPTO_mpi_scan_unsigned (&x, &ds->ciphertext.c1_bits,
1266 GNUNET_SECRETSHARING_ELGAMAL_BITS / 8);
1267 GNUNET_CRYPTO_mpi_scan_unsigned (&s, &ds->share->my_share,
1268 GNUNET_SECRETSHARING_ELGAMAL_BITS / 8);
1270 gcry_mpi_powm (x, x, s, elgamal_p);
1272 element.data = (void *) &d;
1273 element.size = sizeof (struct GNUNET_SECRETSHARING_DecryptData);
1276 /* make vagrind happy until we implement the real deal ... */
1277 memset (&d.nizk_commit1, 0, sizeof d.nizk_commit1);
1278 memset (&d.nizk_commit2, 0, sizeof d.nizk_commit2);
1279 memset (&d.nizk_response, 0, sizeof d.nizk_response);
1281 d.ciphertext = ds->ciphertext;
1283 d.purpose.size = htonl (element.size - offsetof (struct GNUNET_SECRETSHARING_DecryptData, purpose));
1284 d.purpose.purpose = htonl (GNUNET_SIGNATURE_PURPOSE_SECRETSHARING_DECRYPTION);
1286 GNUNET_CRYPTO_eddsa_sign (my_peer_private_key, &d.purpose, &d.signature);
1288 GNUNET_CRYPTO_mpi_print_unsigned (&d.partial_decryption, GNUNET_SECRETSHARING_ELGAMAL_BITS / 8, x);
1290 GNUNET_CONSENSUS_insert (ds->consensus, &element, NULL, NULL);
1291 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "P%u: Inserting decrypt element done!\n",
1292 ds->share->my_peer);
1297 * Functions with this signature are called whenever a message is
1300 * @param cls closure
1301 * @param client identification of the client
1302 * @param message the actual message
1304 static void handle_client_decrypt (void *cls,
1305 struct GNUNET_SERVER_Client *client,
1306 const struct GNUNET_MessageHeader
1309 const struct GNUNET_SECRETSHARING_DecryptRequestMessage *msg =
1310 (const void *) message;
1311 struct DecryptSession *ds;
1312 struct GNUNET_HashCode session_id;
1315 ds = GNUNET_new (struct DecryptSession);
1316 // FIXME: check if session already exists
1317 GNUNET_CONTAINER_DLL_insert (decrypt_sessions_head, decrypt_sessions_tail, ds);
1318 ds->client = client;
1319 ds->client_mq = GNUNET_MQ_queue_for_server_client (client);
1320 ds->deadline = GNUNET_TIME_absolute_ntoh (msg->deadline);
1321 ds->ciphertext = msg->ciphertext;
1323 ds->share = GNUNET_SECRETSHARING_share_read (&msg[1], ntohs (msg->header.size) - sizeof *msg, NULL);
1324 // FIXME: probably should be break rather than assert
1325 GNUNET_assert (NULL != ds->share);
1327 // FIXME: this is probably sufficient, but kdf/hash with all values would be nicer ...
1328 GNUNET_CRYPTO_hash (&msg->ciphertext, sizeof (struct GNUNET_SECRETSHARING_Ciphertext), &session_id);
1330 ds->consensus = GNUNET_CONSENSUS_create (cfg,
1331 ds->share->num_peers,
1334 &decrypt_new_element,
1338 ds->info = GNUNET_new_array (ds->share->num_peers, struct DecryptPeerInfo);
1339 for (i = 0; i < ds->share->num_peers; i++)
1341 ds->info[i].peer = ds->share->peers[i];
1342 ds->info[i].original_index = ds->share->original_indices[i];
1345 insert_decrypt_element (ds);
1347 GNUNET_CONSENSUS_conclude (ds->consensus, ds->deadline, decrypt_conclude, ds);
1349 GNUNET_SERVER_receive_done (client, GNUNET_OK);
1351 GNUNET_log (GNUNET_ERROR_TYPE_INFO, "decrypting with %u peers\n",
1352 ds->share->num_peers);
1357 init_crypto_constants (void)
1359 GNUNET_assert (0 == gcry_mpi_scan (&elgamal_q, GCRYMPI_FMT_HEX,
1360 GNUNET_SECRETSHARING_ELGAMAL_Q_HEX, 0, NULL));
1361 GNUNET_assert (0 == gcry_mpi_scan (&elgamal_p, GCRYMPI_FMT_HEX,
1362 GNUNET_SECRETSHARING_ELGAMAL_P_HEX, 0, NULL));
1363 GNUNET_assert (0 == gcry_mpi_scan (&elgamal_g, GCRYMPI_FMT_HEX,
1364 GNUNET_SECRETSHARING_ELGAMAL_G_HEX, 0, NULL));
1368 static struct KeygenSession *
1369 keygen_session_get (struct GNUNET_SERVER_Client *client)
1371 struct KeygenSession *ks;
1372 for (ks = keygen_sessions_head; NULL != ks; ks = ks->next)
1373 if (ks->client == client)
1378 static struct DecryptSession *
1379 decrypt_session_get (struct GNUNET_SERVER_Client *client)
1381 struct DecryptSession *ds;
1382 for (ds = decrypt_sessions_head; NULL != ds; ds = ds->next)
1383 if (ds->client == client)
1390 * Clean up after a client has disconnected
1392 * @param cls closure, unused
1393 * @param client the client to clean up after
1396 handle_client_disconnect (void *cls, struct GNUNET_SERVER_Client *client)
1398 struct KeygenSession *ks;
1399 struct DecryptSession *ds;
1401 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "handling client disconnect\n");
1403 ks = keygen_session_get (client);
1405 keygen_session_destroy (ks);
1407 ds = decrypt_session_get (client);
1409 decrypt_session_destroy (ds);
1414 * Process template requests.
1416 * @param cls closure
1417 * @param server the initialized server
1418 * @param c configuration to use
1421 run (void *cls, struct GNUNET_SERVER_Handle *server,
1422 const struct GNUNET_CONFIGURATION_Handle *c)
1424 static const struct GNUNET_SERVER_MessageHandler handlers[] = {
1425 {handle_client_keygen, NULL, GNUNET_MESSAGE_TYPE_SECRETSHARING_CLIENT_GENERATE, 0},
1426 {handle_client_decrypt, NULL, GNUNET_MESSAGE_TYPE_SECRETSHARING_CLIENT_DECRYPT, 0},
1431 my_peer_private_key = GNUNET_CRYPTO_eddsa_key_create_from_configuration (c);
1432 if (NULL == my_peer_private_key)
1434 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "could not access host private key\n");
1436 GNUNET_SCHEDULER_shutdown ();
1439 init_crypto_constants ();
1440 if (GNUNET_OK != GNUNET_CRYPTO_get_peer_identity (cfg, &my_peer))
1442 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "could not retrieve host identity\n");
1444 GNUNET_SCHEDULER_shutdown ();
1447 GNUNET_SERVER_add_handlers (server, handlers);
1448 GNUNET_SERVER_disconnect_notify (server, &handle_client_disconnect, NULL);
1449 GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_FOREVER_REL, &cleanup_task,
1455 * The main function for the template service.
1457 * @param argc number of arguments from the command line
1458 * @param argv command line arguments
1459 * @return 0 ok, 1 on error
1462 main (int argc, char *const *argv)
1464 return (GNUNET_OK ==
1465 GNUNET_SERVICE_run (argc, argv, "secretsharing",
1466 GNUNET_SERVICE_OPTION_NONE, &run, NULL)) ? 0 : 1;