2 This file is part of GNUnet.
3 (C) 2012 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/secretsharing_api.c
24 * @author Florian Dold
27 #include "gnunet_util_lib.h"
28 #include "gnunet_secretsharing_service.h"
29 #include "secretsharing.h"
33 #define LOG(kind,...) GNUNET_log_from (kind, "secretsharing-api",__VA_ARGS__)
36 * Session that will eventually establish a shared secred between
37 * the involved peers and allow encryption and cooperative decryption.
39 struct GNUNET_SECRETSHARING_Session
42 * Client connected to the secretsharing service.
44 struct GNUNET_CLIENT_Connection *client;
47 * Message queue for 'client'.
49 struct GNUNET_MQ_Handle *mq;
52 * Called when the secret sharing is done.
54 GNUNET_SECRETSHARING_SecretReadyCallback secret_ready_cb;
57 * Closure for 'secret_ready_cb'.
59 void *secret_ready_cls;
63 struct GNUNET_SECRETSHARING_DecryptionHandle
66 * Client connected to the secretsharing service.
68 struct GNUNET_CLIENT_Connection *client;
71 * Message queue for 'client'.
73 struct GNUNET_MQ_Handle *mq;
76 * Called when the secret sharing is done.
78 GNUNET_SECRETSHARING_DecryptCallback decrypt_cb;
81 * Closure for 'decrypt_cb'.
88 * The ElGamal prime field order as libgcrypt mpi.
89 * Initialized in #init_crypto_constants.
91 static gcry_mpi_t elgamal_q;
94 * Modulus of the prime field used for ElGamal.
95 * Initialized in #init_crypto_constants.
97 static gcry_mpi_t elgamal_p;
100 * Generator for prime field of order 'elgamal_q'.
101 * Initialized in #init_crypto_constants.
103 static gcry_mpi_t elgamal_g;
107 ensure_elgamal_initialized (void)
109 if (NULL != elgamal_q)
110 return; /* looks like crypto is already initialized */
112 GNUNET_assert (0 == gcry_mpi_scan (&elgamal_q, GCRYMPI_FMT_HEX,
113 GNUNET_SECRETSHARING_ELGAMAL_Q_HEX, 0, NULL));
114 GNUNET_assert (0 == gcry_mpi_scan (&elgamal_p, GCRYMPI_FMT_HEX,
115 GNUNET_SECRETSHARING_ELGAMAL_P_HEX, 0, NULL));
116 GNUNET_assert (0 == gcry_mpi_scan (&elgamal_g, GCRYMPI_FMT_HEX,
117 GNUNET_SECRETSHARING_ELGAMAL_G_HEX, 0, NULL));
122 handle_session_client_error (void *cls, enum GNUNET_MQ_Error error)
124 struct GNUNET_SECRETSHARING_Session *s = cls;
126 s->secret_ready_cb (s->secret_ready_cls, NULL, NULL, 0, NULL);
131 handle_decrypt_client_error (void *cls, enum GNUNET_MQ_Error error)
133 struct GNUNET_SECRETSHARING_DecryptionHandle *dh = cls;
135 dh->decrypt_cb (dh->decrypt_cls, NULL);
140 handle_secret_ready (void *cls, const struct GNUNET_MessageHeader *msg)
142 struct GNUNET_SECRETSHARING_Session *session = cls;
143 struct GNUNET_SECRETSHARING_Share *share;
144 const struct GNUNET_SECRETSHARING_SecretReadyMessage *m = (const void *) msg;
147 LOG (GNUNET_ERROR_TYPE_DEBUG, "got secret ready message of size %u\n",
148 ntohs (m->header.size));
150 share_size = ntohs (m->header.size) - sizeof *m;
152 share = GNUNET_SECRETSHARING_share_read (&m[1], share_size, NULL);
154 session->secret_ready_cb (session->secret_ready_cls,
158 (struct GNUNET_PeerIdentity *) &m[1]);
160 GNUNET_SECRETSHARING_session_destroy (session);
165 GNUNET_SECRETSHARING_session_destroy (struct GNUNET_SECRETSHARING_Session *session)
167 GNUNET_MQ_destroy (session->mq);
169 GNUNET_CLIENT_disconnect (session->client);
170 session->client = NULL;
171 GNUNET_free (session);
175 struct GNUNET_SECRETSHARING_Session *
176 GNUNET_SECRETSHARING_create_session (const struct GNUNET_CONFIGURATION_Handle *cfg,
177 unsigned int num_peers,
178 const struct GNUNET_PeerIdentity *peers,
179 const struct GNUNET_HashCode *session_id,
180 struct GNUNET_TIME_Absolute start,
181 struct GNUNET_TIME_Absolute deadline,
182 unsigned int threshold,
183 GNUNET_SECRETSHARING_SecretReadyCallback cb,
186 struct GNUNET_SECRETSHARING_Session *s;
187 struct GNUNET_MQ_Envelope *ev;
188 struct GNUNET_SECRETSHARING_CreateMessage *msg;
189 static const struct GNUNET_MQ_MessageHandler mq_handlers[] = {
190 {handle_secret_ready, GNUNET_MESSAGE_TYPE_SECRETSHARING_CLIENT_SECRET_READY, 0},
191 GNUNET_MQ_HANDLERS_END
195 s = GNUNET_new (struct GNUNET_SECRETSHARING_Session);
196 s->client = GNUNET_CLIENT_connect ("secretsharing", cfg);
197 s->secret_ready_cb = cb;
198 s->secret_ready_cls = cls;
199 GNUNET_assert (NULL != s->client);
201 s->mq = GNUNET_MQ_queue_for_connection_client (s->client, mq_handlers,
202 handle_session_client_error, s);
203 GNUNET_assert (NULL != s->mq);
205 ev = GNUNET_MQ_msg_extra (msg,
206 num_peers * sizeof (struct GNUNET_PeerIdentity),
207 GNUNET_MESSAGE_TYPE_SECRETSHARING_CLIENT_GENERATE);
209 msg->threshold = htons (threshold);
210 msg->num_peers = htons (num_peers);
211 msg->session_id = *session_id;
212 msg->start = GNUNET_TIME_absolute_hton (start);
213 msg->deadline = GNUNET_TIME_absolute_hton (deadline);
214 memcpy (&msg[1], peers, num_peers * sizeof (struct GNUNET_PeerIdentity));
216 GNUNET_MQ_send (s->mq, ev);
218 LOG (GNUNET_ERROR_TYPE_DEBUG, "secretsharing session created with %u peers\n",
225 handle_decrypt_done (void *cls, const struct GNUNET_MessageHeader *msg)
227 struct GNUNET_SECRETSHARING_DecryptionHandle *dh = cls;
228 const struct GNUNET_SECRETSHARING_DecryptResponseMessage *m =
231 const struct GNUNET_SECRETSHARING_Plaintext *plaintext;
236 plaintext = (void *) &m->plaintext;
238 dh->decrypt_cb (dh->decrypt_cls, plaintext);
240 GNUNET_SECRETSHARING_decrypt_cancel (dh);
245 * Publish the given ciphertext for decryption. Once a sufficient (>=k) number of peers has
246 * published the same value, it will be decrypted.
248 * When the operation is canceled, the decrypt_cb is not called anymore, but the calling
249 * peer may already have irrevocably contributed his share for the decryption of the value.
251 * @param share our secret share to use for decryption
252 * @param ciphertext ciphertext to publish in order to decrypt it (if enough peers agree)
253 * @param decrypt_cb callback called once the decryption succeeded
254 * @param decrypt_cb_cls closure for @a decrypt_cb
255 * @return handle to cancel the operation
257 struct GNUNET_SECRETSHARING_DecryptionHandle *
258 GNUNET_SECRETSHARING_decrypt (const struct GNUNET_CONFIGURATION_Handle *cfg,
259 struct GNUNET_SECRETSHARING_Share *share,
260 const struct GNUNET_SECRETSHARING_Ciphertext *ciphertext,
261 struct GNUNET_TIME_Absolute start,
262 struct GNUNET_TIME_Absolute deadline,
263 GNUNET_SECRETSHARING_DecryptCallback decrypt_cb,
264 void *decrypt_cb_cls)
266 struct GNUNET_SECRETSHARING_DecryptionHandle *s;
267 struct GNUNET_MQ_Envelope *ev;
268 struct GNUNET_SECRETSHARING_DecryptRequestMessage *msg;
269 static const struct GNUNET_MQ_MessageHandler mq_handlers[] = {
270 {handle_decrypt_done, GNUNET_MESSAGE_TYPE_SECRETSHARING_CLIENT_DECRYPT_DONE, 0},
271 GNUNET_MQ_HANDLERS_END
276 s = GNUNET_new (struct GNUNET_SECRETSHARING_DecryptionHandle);
277 s->client = GNUNET_CLIENT_connect ("secretsharing", cfg);
278 s->decrypt_cb = decrypt_cb;
279 s->decrypt_cls = decrypt_cb_cls;
280 GNUNET_assert (NULL != s->client);
282 s->mq = GNUNET_MQ_queue_for_connection_client (s->client, mq_handlers,
283 handle_decrypt_client_error, s);
284 GNUNET_assert (NULL != s->mq);
286 GNUNET_assert (GNUNET_OK == GNUNET_SECRETSHARING_share_write (share, NULL, 0, &share_size));
288 ev = GNUNET_MQ_msg_extra (msg,
290 GNUNET_MESSAGE_TYPE_SECRETSHARING_CLIENT_DECRYPT);
292 GNUNET_assert (GNUNET_OK == GNUNET_SECRETSHARING_share_write (share, &msg[1], share_size, NULL));
294 msg->start = GNUNET_TIME_absolute_hton (start);
295 msg->deadline = GNUNET_TIME_absolute_hton (deadline);
296 msg->ciphertext = *ciphertext;
298 GNUNET_MQ_send (s->mq, ev);
300 LOG (GNUNET_ERROR_TYPE_DEBUG, "decrypt session created\n");
306 GNUNET_SECRETSHARING_plaintext_generate_i (struct GNUNET_SECRETSHARING_Plaintext *plaintext,
312 ensure_elgamal_initialized ();
314 GNUNET_assert (NULL != (x = gcry_mpi_new (0)));
316 negative = GNUNET_NO;
319 negative = GNUNET_YES;
320 exponent = -exponent;
323 gcry_mpi_set_ui (x, exponent);
325 gcry_mpi_powm (x, elgamal_g, x, elgamal_p);
327 if (GNUNET_YES == negative)
330 res = gcry_mpi_invm (x, x, elgamal_p);
332 return GNUNET_SYSERR;
335 GNUNET_CRYPTO_mpi_print_unsigned (plaintext, sizeof (struct GNUNET_SECRETSHARING_Plaintext), x);
342 * Encrypt a value. This operation is executed locally, no communication is
345 * This is a helper function, encryption can be done soley with a session's public key
346 * and the crypto system parameters.
348 * @param public_key public key to use for decryption
349 * @param message message to encrypt
350 * @param message_size number of bytes in @a message
351 * @param result_ciphertext pointer to store the resulting ciphertext
352 * @return #GNUNET_YES on succes, #GNUNET_SYSERR if the message is invalid (invalid range)
355 GNUNET_SECRETSHARING_encrypt (const struct GNUNET_SECRETSHARING_PublicKey *public_key,
356 const struct GNUNET_SECRETSHARING_Plaintext *plaintext,
357 struct GNUNET_SECRETSHARING_Ciphertext *result_ciphertext)
363 /* plaintext message */
368 ensure_elgamal_initialized ();
370 GNUNET_assert (NULL != (h = gcry_mpi_new (0)));
371 GNUNET_assert (NULL != (y = gcry_mpi_new (0)));
372 GNUNET_assert (NULL != (tmp = gcry_mpi_new (0)));
374 GNUNET_CRYPTO_mpi_scan_unsigned (&h, public_key, sizeof *public_key);
375 GNUNET_CRYPTO_mpi_scan_unsigned (&m, plaintext, sizeof *plaintext);
377 // Randomize y such that 0 < y < elgamal_q.
378 // The '- 1' is necessary as bitlength(q) = bitlength(p) - 1.
381 gcry_mpi_randomize (y, GNUNET_SECRETSHARING_ELGAMAL_BITS - 1, GCRY_WEAK_RANDOM);
382 } while ((gcry_mpi_cmp_ui (y, 0) == 0) || (gcry_mpi_cmp (y, elgamal_q) >= 0));
385 gcry_mpi_powm (tmp, elgamal_g, y, elgamal_p);
387 GNUNET_CRYPTO_mpi_print_unsigned (&result_ciphertext->c1_bits,
388 GNUNET_SECRETSHARING_ELGAMAL_BITS / 8, tmp);
391 gcry_mpi_powm (tmp, h, y, elgamal_p);
393 gcry_mpi_mulm (tmp, tmp, m, elgamal_p);
395 GNUNET_CRYPTO_mpi_print_unsigned (&result_ciphertext->c2_bits,
396 GNUNET_SECRETSHARING_ELGAMAL_BITS / 8, tmp);
403 GNUNET_SECRETSHARING_decrypt_cancel (struct GNUNET_SECRETSHARING_DecryptionHandle *h)
405 GNUNET_MQ_destroy (h->mq);
407 GNUNET_CLIENT_disconnect (h->client);