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 @e 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 @e secret_ready_cb.
59 void *secret_ready_cls;
64 * Handle to cancel a cooperative decryption operation.
66 struct GNUNET_SECRETSHARING_DecryptionHandle
69 * Client connected to the secretsharing service.
71 struct GNUNET_CLIENT_Connection *client;
74 * Message queue for @e client.
76 struct GNUNET_MQ_Handle *mq;
79 * Called when the secret sharing is done.
81 GNUNET_SECRETSHARING_DecryptCallback decrypt_cb;
84 * Closure for @e decrypt_cb.
91 * The ElGamal prime field order as libgcrypt mpi.
92 * Initialized in #init_crypto_constants.
94 static gcry_mpi_t elgamal_q;
97 * Modulus of the prime field used for ElGamal.
98 * Initialized in #init_crypto_constants.
100 static gcry_mpi_t elgamal_p;
103 * Generator for prime field of order 'elgamal_q'.
104 * Initialized in #init_crypto_constants.
106 static gcry_mpi_t elgamal_g;
110 * Function to initialize #elgamal_q, #elgamal_p and #elgamal_g.
113 ensure_elgamal_initialized (void)
115 if (NULL != elgamal_q)
116 return; /* looks like crypto is already initialized */
118 GNUNET_assert (0 == gcry_mpi_scan (&elgamal_q, GCRYMPI_FMT_HEX,
119 GNUNET_SECRETSHARING_ELGAMAL_Q_HEX, 0, NULL));
120 GNUNET_assert (0 == gcry_mpi_scan (&elgamal_p, GCRYMPI_FMT_HEX,
121 GNUNET_SECRETSHARING_ELGAMAL_P_HEX, 0, NULL));
122 GNUNET_assert (0 == gcry_mpi_scan (&elgamal_g, GCRYMPI_FMT_HEX,
123 GNUNET_SECRETSHARING_ELGAMAL_G_HEX, 0, NULL));
128 * Callback invoked when there is an error communicating with
129 * the service. Notifies the application about the error.
131 * @param cls the `struct GNUNET_SECRETSHARING_Session`
132 * @param error error code
135 handle_session_client_error (void *cls,
136 enum GNUNET_MQ_Error error)
138 struct GNUNET_SECRETSHARING_Session *s = cls;
140 s->secret_ready_cb (s->secret_ready_cls, NULL, NULL, 0, NULL);
141 GNUNET_SECRETSHARING_session_destroy (s);
146 * Callback invoked when there is an error communicating with
147 * the service. Notifies the application about the error.
149 * @param cls the `struct GNUNET_SECRETSHARING_DecryptionHandle`
150 * @param error error code
153 handle_decrypt_client_error (void *cls,
154 enum GNUNET_MQ_Error error)
156 struct GNUNET_SECRETSHARING_DecryptionHandle *dh = cls;
158 dh->decrypt_cb (dh->decrypt_cls, NULL);
159 GNUNET_SECRETSHARING_decrypt_cancel (dh);
164 * Handler invoked with the final result message from
165 * secret sharing. Decodes the message and passes the
166 * result to the application.
168 * @param cls the `struct GNUNET_SECRETSHARING_Session`
169 * @param msg message with the result
172 handle_secret_ready (void *cls,
173 const struct GNUNET_MessageHeader *msg)
175 struct GNUNET_SECRETSHARING_Session *s = cls;
176 const struct GNUNET_SECRETSHARING_SecretReadyMessage *m;
177 struct GNUNET_SECRETSHARING_Share *share;
180 LOG (GNUNET_ERROR_TYPE_DEBUG,
181 "Got secret ready message of size %u\n",
183 if (ntohs (msg->size) < sizeof (struct GNUNET_SECRETSHARING_SecretReadyMessage))
186 s->secret_ready_cb (s->secret_ready_cls, NULL, NULL, 0, NULL);
187 GNUNET_SECRETSHARING_session_destroy (s);
190 m = (const struct GNUNET_SECRETSHARING_SecretReadyMessage *) msg;
191 share_size = ntohs (m->header.size) - sizeof (struct GNUNET_SECRETSHARING_SecretReadyMessage);
193 share = GNUNET_SECRETSHARING_share_read (&m[1],
196 s->secret_ready_cb (s->secret_ready_cls,
200 (struct GNUNET_PeerIdentity *) &m[1]);
201 GNUNET_SECRETSHARING_session_destroy (s);
206 * Destroy a secret sharing session.
207 * The secret ready callback will not be called.
209 * @param s session to destroy
212 GNUNET_SECRETSHARING_session_destroy (struct GNUNET_SECRETSHARING_Session *s)
214 GNUNET_MQ_destroy (s->mq);
216 GNUNET_CLIENT_disconnect (s->client);
223 * Create a session that will eventually establish a shared secret
224 * with the other peers.
226 * @param cfg configuration to use
227 * @param num_peers number of peers in @a peers
228 * @param peers array of peers that we will share secrets with, can optionally contain the local peer
229 * @param session_id unique session id
230 * @param start When should all peers be available for sharing the secret?
231 * Random number generation can take place before the start time.
232 * @param deadline point in time where the session must be established; taken as hint
233 * by underlying consensus sessions
234 * @param threshold minimum number of peers that must cooperate to decrypt a value
235 * @param cb called when the secret has been established
236 * @param cls closure for @a cb
238 struct GNUNET_SECRETSHARING_Session *
239 GNUNET_SECRETSHARING_create_session (const struct GNUNET_CONFIGURATION_Handle *cfg,
240 unsigned int num_peers,
241 const struct GNUNET_PeerIdentity *peers,
242 const struct GNUNET_HashCode *session_id,
243 struct GNUNET_TIME_Absolute start,
244 struct GNUNET_TIME_Absolute deadline,
245 unsigned int threshold,
246 GNUNET_SECRETSHARING_SecretReadyCallback cb,
249 struct GNUNET_SECRETSHARING_Session *s;
250 struct GNUNET_MQ_Envelope *ev;
251 struct GNUNET_SECRETSHARING_CreateMessage *msg;
252 static const struct GNUNET_MQ_MessageHandler mq_handlers[] = {
253 { &handle_secret_ready,
254 GNUNET_MESSAGE_TYPE_SECRETSHARING_CLIENT_SECRET_READY, 0},
255 GNUNET_MQ_HANDLERS_END
258 s = GNUNET_new (struct GNUNET_SECRETSHARING_Session);
259 s->client = GNUNET_CLIENT_connect ("secretsharing", cfg);
260 if (NULL == s->client)
262 /* secretsharing not configured correctly */
267 s->secret_ready_cb = cb;
268 s->secret_ready_cls = cls;
269 s->mq = GNUNET_MQ_queue_for_connection_client (s->client, mq_handlers,
270 &handle_session_client_error,
272 GNUNET_assert (NULL != s->mq);
274 ev = GNUNET_MQ_msg_extra (msg,
275 num_peers * sizeof (struct GNUNET_PeerIdentity),
276 GNUNET_MESSAGE_TYPE_SECRETSHARING_CLIENT_GENERATE);
278 msg->threshold = htons (threshold);
279 msg->num_peers = htons (num_peers);
280 msg->session_id = *session_id;
281 msg->start = GNUNET_TIME_absolute_hton (start);
282 msg->deadline = GNUNET_TIME_absolute_hton (deadline);
283 memcpy (&msg[1], peers, num_peers * sizeof (struct GNUNET_PeerIdentity));
285 GNUNET_MQ_send (s->mq, ev);
287 LOG (GNUNET_ERROR_TYPE_DEBUG,
288 "Secretsharing session created with %u peers\n",
295 handle_decrypt_done (void *cls,
296 const struct GNUNET_MessageHeader *msg)
298 struct GNUNET_SECRETSHARING_DecryptionHandle *dh = cls;
299 const struct GNUNET_SECRETSHARING_DecryptResponseMessage *m =
300 (const void *) msg; // FIXME: size check!?
301 const struct GNUNET_SECRETSHARING_Plaintext *plaintext;
306 plaintext = (void *) &m->plaintext;
308 dh->decrypt_cb (dh->decrypt_cls, plaintext);
310 GNUNET_SECRETSHARING_decrypt_cancel (dh);
315 * Publish the given ciphertext for decryption. Once a sufficient (>=k) number of peers has
316 * published the same value, it will be decrypted.
318 * When the operation is canceled, the decrypt_cb is not called anymore, but the calling
319 * peer may already have irrevocably contributed his share for the decryption of the value.
321 * @param share our secret share to use for decryption
322 * @param ciphertext ciphertext to publish in order to decrypt it (if enough peers agree)
323 * @param decrypt_cb callback called once the decryption succeeded
324 * @param decrypt_cb_cls closure for @a decrypt_cb
325 * @return handle to cancel the operation
327 struct GNUNET_SECRETSHARING_DecryptionHandle *
328 GNUNET_SECRETSHARING_decrypt (const struct GNUNET_CONFIGURATION_Handle *cfg,
329 struct GNUNET_SECRETSHARING_Share *share,
330 const struct GNUNET_SECRETSHARING_Ciphertext *ciphertext,
331 struct GNUNET_TIME_Absolute start,
332 struct GNUNET_TIME_Absolute deadline,
333 GNUNET_SECRETSHARING_DecryptCallback decrypt_cb,
334 void *decrypt_cb_cls)
336 struct GNUNET_SECRETSHARING_DecryptionHandle *s;
337 struct GNUNET_MQ_Envelope *ev;
338 struct GNUNET_SECRETSHARING_DecryptRequestMessage *msg;
339 static const struct GNUNET_MQ_MessageHandler mq_handlers[] = {
340 {handle_decrypt_done, GNUNET_MESSAGE_TYPE_SECRETSHARING_CLIENT_DECRYPT_DONE, 0},
341 GNUNET_MQ_HANDLERS_END
346 s = GNUNET_new (struct GNUNET_SECRETSHARING_DecryptionHandle);
347 s->client = GNUNET_CLIENT_connect ("secretsharing", cfg);
348 s->decrypt_cb = decrypt_cb;
349 s->decrypt_cls = decrypt_cb_cls;
350 GNUNET_assert (NULL != s->client);
352 s->mq = GNUNET_MQ_queue_for_connection_client (s->client, mq_handlers,
353 &handle_decrypt_client_error,
355 GNUNET_assert (NULL != s->mq);
357 GNUNET_assert (GNUNET_OK == GNUNET_SECRETSHARING_share_write (share, NULL, 0, &share_size));
359 ev = GNUNET_MQ_msg_extra (msg,
361 GNUNET_MESSAGE_TYPE_SECRETSHARING_CLIENT_DECRYPT);
363 GNUNET_assert (GNUNET_OK == GNUNET_SECRETSHARING_share_write (share, &msg[1], share_size, NULL));
365 msg->start = GNUNET_TIME_absolute_hton (start);
366 msg->deadline = GNUNET_TIME_absolute_hton (deadline);
367 msg->ciphertext = *ciphertext;
369 GNUNET_MQ_send (s->mq, ev);
371 LOG (GNUNET_ERROR_TYPE_DEBUG, "decrypt session created\n");
377 GNUNET_SECRETSHARING_plaintext_generate_i (struct GNUNET_SECRETSHARING_Plaintext *plaintext,
383 ensure_elgamal_initialized ();
385 GNUNET_assert (NULL != (x = gcry_mpi_new (0)));
387 negative = GNUNET_NO;
390 negative = GNUNET_YES;
391 exponent = -exponent;
394 gcry_mpi_set_ui (x, exponent);
396 gcry_mpi_powm (x, elgamal_g, x, elgamal_p);
398 if (GNUNET_YES == negative)
401 res = gcry_mpi_invm (x, x, elgamal_p);
403 return GNUNET_SYSERR;
406 GNUNET_CRYPTO_mpi_print_unsigned (plaintext, sizeof (struct GNUNET_SECRETSHARING_Plaintext), x);
413 * Encrypt a value. This operation is executed locally, no communication is
416 * This is a helper function, encryption can be done soley with a session's public key
417 * and the crypto system parameters.
419 * @param public_key public key to use for decryption
420 * @param message message to encrypt
421 * @param message_size number of bytes in @a message
422 * @param result_ciphertext pointer to store the resulting ciphertext
423 * @return #GNUNET_YES on succes, #GNUNET_SYSERR if the message is invalid (invalid range)
426 GNUNET_SECRETSHARING_encrypt (const struct GNUNET_SECRETSHARING_PublicKey *public_key,
427 const struct GNUNET_SECRETSHARING_Plaintext *plaintext,
428 struct GNUNET_SECRETSHARING_Ciphertext *result_ciphertext)
434 /* plaintext message */
439 ensure_elgamal_initialized ();
441 GNUNET_assert (NULL != (h = gcry_mpi_new (0)));
442 GNUNET_assert (NULL != (y = gcry_mpi_new (0)));
443 GNUNET_assert (NULL != (tmp = gcry_mpi_new (0)));
445 GNUNET_CRYPTO_mpi_scan_unsigned (&h, public_key, sizeof *public_key);
446 GNUNET_CRYPTO_mpi_scan_unsigned (&m, plaintext, sizeof *plaintext);
448 // Randomize y such that 0 < y < elgamal_q.
449 // The '- 1' is necessary as bitlength(q) = bitlength(p) - 1.
452 gcry_mpi_randomize (y, GNUNET_SECRETSHARING_ELGAMAL_BITS - 1, GCRY_WEAK_RANDOM);
453 } while ((gcry_mpi_cmp_ui (y, 0) == 0) || (gcry_mpi_cmp (y, elgamal_q) >= 0));
456 gcry_mpi_powm (tmp, elgamal_g, y, elgamal_p);
458 GNUNET_CRYPTO_mpi_print_unsigned (&result_ciphertext->c1_bits,
459 GNUNET_SECRETSHARING_ELGAMAL_BITS / 8, tmp);
462 gcry_mpi_powm (tmp, h, y, elgamal_p);
464 gcry_mpi_mulm (tmp, tmp, m, elgamal_p);
466 GNUNET_CRYPTO_mpi_print_unsigned (&result_ciphertext->c2_bits,
467 GNUNET_SECRETSHARING_ELGAMAL_BITS / 8, tmp);
474 * Cancel a decryption.
476 * The decrypt_cb is not called anymore, but the calling
477 * peer may already have irrevocably contributed his share for the decryption of the value.
479 * @param dh to cancel
482 GNUNET_SECRETSHARING_decrypt_cancel (struct GNUNET_SECRETSHARING_DecryptionHandle *dh)
484 GNUNET_MQ_destroy (dh->mq);
486 GNUNET_CLIENT_disconnect (dh->client);
491 /* end of secretsharing_api.c */