aboutsummaryrefslogtreecommitdiff
path: root/src/secretsharing/secretsharing_api.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/secretsharing/secretsharing_api.c')
-rw-r--r--src/secretsharing/secretsharing_api.c518
1 files changed, 0 insertions, 518 deletions
diff --git a/src/secretsharing/secretsharing_api.c b/src/secretsharing/secretsharing_api.c
deleted file mode 100644
index 98f800c95..000000000
--- a/src/secretsharing/secretsharing_api.c
+++ /dev/null
@@ -1,518 +0,0 @@
1/*
2 This file is part of GNUnet.
3 Copyright (C) 2012, 2016 GNUnet e.V.
4
5 GNUnet is free software: you can redistribute it and/or modify it
6 under the terms of the GNU Affero General Public License as published
7 by the Free Software Foundation, either version 3 of the License,
8 or (at your option) any later version.
9
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 Affero General Public License for more details.
14
15 You should have received a copy of the GNU Affero General Public License
16 along with this program. If not, see <http://www.gnu.org/licenses/>.
17
18 SPDX-License-Identifier: AGPL3.0-or-later
19 */
20
21/**
22 * @file secretsharing/secretsharing_api.c
23 * @brief
24 * @author Florian Dold
25 */
26#include "platform.h"
27#include "gnunet_util_lib.h"
28#include "gnunet_secretsharing_service.h"
29#include "secretsharing.h"
30#include <gcrypt.h>
31
32
33#define LOG(kind, ...) GNUNET_log_from (kind, "secretsharing-api", __VA_ARGS__)
34
35/**
36 * Session that will eventually establish a shared secred between
37 * the involved peers and allow encryption and cooperative decryption.
38 */
39struct GNUNET_SECRETSHARING_Session
40{
41 /**
42 * Message queue for @e client.
43 */
44 struct GNUNET_MQ_Handle *mq;
45
46 /**
47 * Called when the secret sharing is done.
48 */
49 GNUNET_SECRETSHARING_SecretReadyCallback secret_ready_cb;
50
51 /**
52 * Closure for @e secret_ready_cb.
53 */
54 void *secret_ready_cls;
55};
56
57
58/**
59 * Handle to cancel a cooperative decryption operation.
60 */
61struct GNUNET_SECRETSHARING_DecryptionHandle
62{
63 /**
64 * Message queue for @e client.
65 */
66 struct GNUNET_MQ_Handle *mq;
67
68 /**
69 * Called when the secret sharing is done.
70 */
71 GNUNET_SECRETSHARING_DecryptCallback decrypt_cb;
72
73 /**
74 * Closure for @e decrypt_cb.
75 */
76 void *decrypt_cls;
77};
78
79
80/**
81 * The ElGamal prime field order as libgcrypt mpi.
82 * Initialized in #init_crypto_constants.
83 */
84static gcry_mpi_t elgamal_q;
85
86/**
87 * Modulus of the prime field used for ElGamal.
88 * Initialized in #init_crypto_constants.
89 */
90static gcry_mpi_t elgamal_p;
91
92/**
93 * Generator for prime field of order 'elgamal_q'.
94 * Initialized in #init_crypto_constants.
95 */
96static gcry_mpi_t elgamal_g;
97
98
99/**
100 * Function to initialize #elgamal_q, #elgamal_p and #elgamal_g.
101 */
102static void
103ensure_elgamal_initialized (void)
104{
105 if (NULL != elgamal_q)
106 return; /* looks like crypto is already initialized */
107
108 GNUNET_assert (0 == gcry_mpi_scan (&elgamal_q, GCRYMPI_FMT_HEX,
109 GNUNET_SECRETSHARING_ELGAMAL_Q_HEX, 0,
110 NULL));
111 GNUNET_assert (0 == gcry_mpi_scan (&elgamal_p, GCRYMPI_FMT_HEX,
112 GNUNET_SECRETSHARING_ELGAMAL_P_HEX, 0,
113 NULL));
114 GNUNET_assert (0 == gcry_mpi_scan (&elgamal_g, GCRYMPI_FMT_HEX,
115 GNUNET_SECRETSHARING_ELGAMAL_G_HEX, 0,
116 NULL));
117}
118
119
120/**
121 * Callback invoked when there is an error communicating with
122 * the service. Notifies the application about the error.
123 *
124 * @param cls the `struct GNUNET_SECRETSHARING_Session`
125 * @param error error code
126 */
127static void
128handle_session_client_error (void *cls,
129 enum GNUNET_MQ_Error error)
130{
131 struct GNUNET_SECRETSHARING_Session *s = cls;
132
133 s->secret_ready_cb (s->secret_ready_cls, NULL, NULL, 0, NULL);
134 GNUNET_SECRETSHARING_session_destroy (s);
135}
136
137
138/**
139 * Callback invoked when there is an error communicating with
140 * the service. Notifies the application about the error.
141 *
142 * @param cls the `struct GNUNET_SECRETSHARING_DecryptionHandle`
143 * @param error error code
144 */
145static void
146handle_decrypt_client_error (void *cls,
147 enum GNUNET_MQ_Error error)
148{
149 struct GNUNET_SECRETSHARING_DecryptionHandle *dh = cls;
150
151 dh->decrypt_cb (dh->decrypt_cls, NULL);
152 GNUNET_SECRETSHARING_decrypt_cancel (dh);
153}
154
155
156/**
157 * Handler invoked with the final result message from
158 * secret sharing. Decodes the message and passes the
159 * result to the application.
160 *
161 * @param cls the `struct GNUNET_SECRETSHARING_Session`
162 * @param m message with the result
163 */
164static int
165check_secret_ready (void *cls,
166 const struct GNUNET_SECRETSHARING_SecretReadyMessage *m)
167{
168 /* FIXME: actually check m is well-formed here! */
169 return GNUNET_OK;
170}
171
172
173/**
174 * Handler invoked with the final result message from
175 * secret sharing. Decodes the message and passes the
176 * result to the application.
177 *
178 * @param cls the `struct GNUNET_SECRETSHARING_Session`
179 * @param m message with the result
180 */
181static void
182handle_secret_ready (void *cls,
183 const struct GNUNET_SECRETSHARING_SecretReadyMessage *m)
184{
185 struct GNUNET_SECRETSHARING_Session *s = cls;
186 struct GNUNET_SECRETSHARING_Share *share;
187 size_t share_size;
188
189 LOG (GNUNET_ERROR_TYPE_DEBUG,
190 "Got secret ready message of size %u\n",
191 ntohs (m->header.size));
192 share_size = ntohs (m->header.size) - sizeof(struct
193 GNUNET_SECRETSHARING_SecretReadyMessage);
194
195 share = GNUNET_SECRETSHARING_share_read (&m[1],
196 share_size,
197 NULL);
198 GNUNET_assert (NULL != share); // FIXME: this can fail!
199 // should have been checked in #check_secret_ready!
200 // FIXME: below we never check &m[1] is valid!
201 // FIXME: do we leak 'share' here?
202 s->secret_ready_cb (s->secret_ready_cls,
203 share, /* FIXME */
204 &share->public_key,
205 share->num_peers,
206 (const struct GNUNET_PeerIdentity *) &m[1]);
207
208 GNUNET_SECRETSHARING_session_destroy (s);
209}
210
211
212/**
213 * Destroy a secret sharing session.
214 * The secret ready callback will not be called.
215 *
216 * @param s session to destroy
217 */
218void
219GNUNET_SECRETSHARING_session_destroy (struct GNUNET_SECRETSHARING_Session *s)
220{
221 GNUNET_MQ_destroy (s->mq);
222 s->mq = NULL;
223 GNUNET_free (s);
224}
225
226
227/**
228 * Create a session that will eventually establish a shared secret
229 * with the other peers.
230 *
231 * @param cfg configuration to use
232 * @param num_peers number of peers in @a peers
233 * @param peers array of peers that we will share secrets with, can optionally contain the local peer
234 * @param session_id unique session id
235 * @param start When should all peers be available for sharing the secret?
236 * Random number generation can take place before the start time.
237 * @param deadline point in time where the session must be established; taken as hint
238 * by underlying consensus sessions
239 * @param threshold minimum number of peers that must cooperate to decrypt a value
240 * @param cb called when the secret has been established
241 * @param cls closure for @a cb
242 */
243struct GNUNET_SECRETSHARING_Session *
244GNUNET_SECRETSHARING_create_session (const struct
245 GNUNET_CONFIGURATION_Handle *cfg,
246 unsigned int num_peers,
247 const struct GNUNET_PeerIdentity *peers,
248 const struct GNUNET_HashCode *session_id,
249 struct GNUNET_TIME_Absolute start,
250 struct GNUNET_TIME_Absolute deadline,
251 unsigned int threshold,
252 GNUNET_SECRETSHARING_SecretReadyCallback cb,
253 void *cls)
254{
255 struct GNUNET_SECRETSHARING_Session *s
256 = GNUNET_new (struct GNUNET_SECRETSHARING_Session);
257 struct GNUNET_MQ_MessageHandler mq_handlers[] = {
258 GNUNET_MQ_hd_var_size (secret_ready,
259 GNUNET_MESSAGE_TYPE_SECRETSHARING_CLIENT_SECRET_READY,
260 struct GNUNET_SECRETSHARING_SecretReadyMessage,
261 s),
262 GNUNET_MQ_handler_end ()
263 };
264 struct GNUNET_MQ_Envelope *ev;
265 struct GNUNET_SECRETSHARING_CreateMessage *msg;
266
267 s->mq = GNUNET_CLIENT_connect (cfg,
268 "secretsharing",
269 mq_handlers,
270 &handle_session_client_error,
271 s);
272 if (NULL == s->mq)
273 {
274 /* secretsharing not configured correctly */
275 GNUNET_break (0);
276 GNUNET_free (s);
277 return NULL;
278 }
279 s->secret_ready_cb = cb;
280 s->secret_ready_cls = cls;
281 ev = GNUNET_MQ_msg_extra (msg,
282 num_peers * sizeof(struct GNUNET_PeerIdentity),
283 GNUNET_MESSAGE_TYPE_SECRETSHARING_CLIENT_GENERATE);
284
285 msg->threshold = htons (threshold);
286 msg->num_peers = htons (num_peers);
287 msg->session_id = *session_id;
288 msg->start = GNUNET_TIME_absolute_hton (start);
289 msg->deadline = GNUNET_TIME_absolute_hton (deadline);
290 GNUNET_memcpy (&msg[1], peers, num_peers * sizeof(struct
291 GNUNET_PeerIdentity));
292
293 GNUNET_MQ_send (s->mq, ev);
294
295 LOG (GNUNET_ERROR_TYPE_DEBUG,
296 "Secretsharing session created with %u peers\n",
297 num_peers);
298 return s;
299}
300
301
302static void
303handle_decrypt_done (void *cls,
304 const struct
305 GNUNET_SECRETSHARING_DecryptResponseMessage *m)
306{
307 struct GNUNET_SECRETSHARING_DecryptionHandle *dh = cls;
308 const struct GNUNET_SECRETSHARING_Plaintext *plaintext;
309
310 if (m->success == 0)
311 plaintext = NULL;
312 else
313 plaintext = (void *) &m->plaintext;
314 dh->decrypt_cb (dh->decrypt_cls, plaintext);
315 GNUNET_SECRETSHARING_decrypt_cancel (dh);
316}
317
318
319/**
320 * Publish the given ciphertext for decryption. Once a sufficient (>=k) number of peers has
321 * published the same value, it will be decrypted.
322 *
323 * When the operation is canceled, the decrypt_cb is not called anymore, but the calling
324 * peer may already have irrevocably contributed its share for the decryption of the value.
325 *
326 * @param share our secret share to use for decryption
327 * @param ciphertext ciphertext to publish in order to decrypt it (if enough peers agree)
328 * @param decrypt_cb callback called once the decryption succeeded
329 * @param decrypt_cb_cls closure for @a decrypt_cb
330 * @return handle to cancel the operation
331 */
332struct GNUNET_SECRETSHARING_DecryptionHandle *
333GNUNET_SECRETSHARING_decrypt (const struct GNUNET_CONFIGURATION_Handle *cfg,
334 struct GNUNET_SECRETSHARING_Share *share,
335 const struct
336 GNUNET_SECRETSHARING_Ciphertext *ciphertext,
337 struct GNUNET_TIME_Absolute start,
338 struct GNUNET_TIME_Absolute deadline,
339 GNUNET_SECRETSHARING_DecryptCallback decrypt_cb,
340 void *decrypt_cb_cls)
341{
342 struct GNUNET_SECRETSHARING_DecryptionHandle *s
343 = GNUNET_new (struct GNUNET_SECRETSHARING_DecryptionHandle);
344 struct GNUNET_MQ_MessageHandler mq_handlers[] = {
345 GNUNET_MQ_hd_fixed_size (decrypt_done,
346 GNUNET_MESSAGE_TYPE_SECRETSHARING_CLIENT_DECRYPT_DONE,
347 struct GNUNET_SECRETSHARING_DecryptResponseMessage,
348 s),
349 GNUNET_MQ_handler_end ()
350 };
351 struct GNUNET_MQ_Envelope *ev;
352 struct GNUNET_SECRETSHARING_DecryptRequestMessage *msg;
353 size_t share_size;
354
355 s->decrypt_cb = decrypt_cb;
356 s->decrypt_cls = decrypt_cb_cls;
357 s->mq = GNUNET_CLIENT_connect (cfg,
358 "secretsharing",
359 mq_handlers,
360 &handle_decrypt_client_error,
361 s);
362 if (NULL == s->mq)
363 {
364 GNUNET_free (s);
365 return NULL;
366 }
367 GNUNET_assert (GNUNET_OK ==
368 GNUNET_SECRETSHARING_share_write (share, NULL, 0,
369 &share_size));
370
371 ev = GNUNET_MQ_msg_extra (msg,
372 share_size,
373 GNUNET_MESSAGE_TYPE_SECRETSHARING_CLIENT_DECRYPT);
374
375 GNUNET_assert (GNUNET_OK ==
376 GNUNET_SECRETSHARING_share_write (share,
377 &msg[1],
378 share_size,
379 NULL));
380
381 msg->start = GNUNET_TIME_absolute_hton (start);
382 msg->deadline = GNUNET_TIME_absolute_hton (deadline);
383 msg->ciphertext = *ciphertext;
384
385 GNUNET_MQ_send (s->mq, ev);
386
387 LOG (GNUNET_ERROR_TYPE_DEBUG,
388 "decrypt session created\n");
389 return s;
390}
391
392
393int
394GNUNET_SECRETSHARING_plaintext_generate_i (struct
395 GNUNET_SECRETSHARING_Plaintext *
396 plaintext,
397 int64_t exponent)
398{
399 int negative;
400 gcry_mpi_t x;
401
402 ensure_elgamal_initialized ();
403
404 GNUNET_assert (NULL != (x = gcry_mpi_new (0)));
405
406 negative = GNUNET_NO;
407 if (exponent < 0)
408 {
409 negative = GNUNET_YES;
410 exponent = -exponent;
411 }
412
413 gcry_mpi_set_ui (x, exponent);
414
415 gcry_mpi_powm (x, elgamal_g, x, elgamal_p);
416
417 if (GNUNET_YES == negative)
418 {
419 int res;
420 res = gcry_mpi_invm (x, x, elgamal_p);
421 if (0 == res)
422 return GNUNET_SYSERR;
423 }
424
425 GNUNET_CRYPTO_mpi_print_unsigned (plaintext,
426 sizeof(struct
427 GNUNET_SECRETSHARING_Plaintext),
428 x);
429
430 return GNUNET_OK;
431}
432
433
434/**
435 * Encrypt a value. This operation is executed locally, no communication is
436 * necessary.
437 *
438 * This is a helper function, encryption can be done solely with a session's public key
439 * and the crypto system parameters.
440 *
441 * @param public_key public key to use for decryption
442 * @param message message to encrypt
443 * @param message_size number of bytes in @a message
444 * @param result_ciphertext pointer to store the resulting ciphertext
445 * @return #GNUNET_YES on success, #GNUNET_SYSERR if the message is invalid (invalid range)
446 */
447int
448GNUNET_SECRETSHARING_encrypt (const struct
449 GNUNET_SECRETSHARING_PublicKey *public_key,
450 const struct
451 GNUNET_SECRETSHARING_Plaintext *plaintext,
452 struct GNUNET_SECRETSHARING_Ciphertext *
453 result_ciphertext)
454{
455 /* pubkey */
456 gcry_mpi_t h;
457 /* nonce */
458 gcry_mpi_t y;
459 /* plaintext message */
460 gcry_mpi_t m;
461 /* temp value */
462 gcry_mpi_t tmp;
463
464 ensure_elgamal_initialized ();
465
466 GNUNET_assert (NULL != (h = gcry_mpi_new (0)));
467 GNUNET_assert (NULL != (y = gcry_mpi_new (0)));
468 GNUNET_assert (NULL != (tmp = gcry_mpi_new (0)));
469
470 GNUNET_CRYPTO_mpi_scan_unsigned (&h, public_key, sizeof *public_key);
471 GNUNET_CRYPTO_mpi_scan_unsigned (&m, plaintext, sizeof *plaintext);
472
473 // Randomize y such that 0 < y < elgamal_q.
474 // The '- 1' is necessary as bitlength(q) = bitlength(p) - 1.
475 do
476 {
477 gcry_mpi_randomize (y, GNUNET_SECRETSHARING_ELGAMAL_BITS - 1,
478 GCRY_WEAK_RANDOM);
479 }
480 while ((gcry_mpi_cmp_ui (y, 0) == 0) || (gcry_mpi_cmp (y, elgamal_q) >= 0));
481
482 // tmp <- g^y
483 gcry_mpi_powm (tmp, elgamal_g, y, elgamal_p);
484 // write tmp to c1
485 GNUNET_CRYPTO_mpi_print_unsigned (&result_ciphertext->c1_bits,
486 GNUNET_SECRETSHARING_ELGAMAL_BITS / 8, tmp);
487
488 // tmp <- h^y
489 gcry_mpi_powm (tmp, h, y, elgamal_p);
490 // tmp <- tmp * m
491 gcry_mpi_mulm (tmp, tmp, m, elgamal_p);
492 // write tmp to c2
493 GNUNET_CRYPTO_mpi_print_unsigned (&result_ciphertext->c2_bits,
494 GNUNET_SECRETSHARING_ELGAMAL_BITS / 8, tmp);
495
496 return GNUNET_OK;
497}
498
499
500/**
501 * Cancel a decryption.
502 *
503 * The decrypt_cb is not called anymore, but the calling
504 * peer may already have irrevocably contributed its share for the decryption of the value.
505 *
506 * @param dh to cancel
507 */
508void
509GNUNET_SECRETSHARING_decrypt_cancel (struct
510 GNUNET_SECRETSHARING_DecryptionHandle *dh)
511{
512 GNUNET_MQ_destroy (dh->mq);
513 dh->mq = NULL;
514 GNUNET_free (dh);
515}
516
517
518/* end of secretsharing_api.c */