- secretsharing api test for single peer
[oweals/gnunet.git] / src / secretsharing / secretsharing_api.c
1 /*
2      This file is part of GNUnet.
3      (C) 2012 Christian Grothoff (and other contributing authors)
4
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.
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      General Public License for more details.
14
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.
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  */
39 struct GNUNET_SECRETSHARING_Session
40 {
41   /**
42    * Client connected to the secretsharing service.
43    */
44   struct GNUNET_CLIENT_Connection *client;
45
46   /**
47    * Message queue for 'client'.
48    */
49   struct GNUNET_MQ_Handle *mq;
50
51   /**
52    * Called when the secret sharing is done.
53    */
54   GNUNET_SECRETSHARING_SecretReadyCallback secret_ready_cb;
55
56   /**
57    * Closure for 'secret_ready_cb'.
58    */
59   void *secret_ready_cls;
60 };
61
62
63 struct GNUNET_SECRETSHARING_DecryptionHandle
64 {
65   /**
66    * Client connected to the secretsharing service.
67    */
68   struct GNUNET_CLIENT_Connection *client;
69
70   /**
71    * Message queue for 'client'.
72    */
73   struct GNUNET_MQ_Handle *mq;
74
75   /**
76    * Called when the secret sharing is done.
77    */
78   GNUNET_SECRETSHARING_DecryptCallback decrypt_cb;
79
80   /**
81    * Closure for 'decrypt_cb'.
82    */
83   void *decrypt_cls;
84 };
85
86
87 /**
88  * The ElGamal prime field order as libgcrypt mpi.
89  * Initialized in #init_crypto_constants.
90  */
91 static gcry_mpi_t elgamal_q;
92
93 /**
94  * Modulus of the prime field used for ElGamal.
95  * Initialized in #init_crypto_constants.
96  */
97 static gcry_mpi_t elgamal_p;
98
99 /**
100  * Generator for prime field of order 'elgamal_q'.
101  * Initialized in #init_crypto_constants.
102  */
103 static gcry_mpi_t elgamal_g;
104
105
106 static void
107 ensure_elgamal_initialized (void)
108 {
109   if (NULL != elgamal_q)
110     return; /* looks like crypto is already initialized */
111
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));
118 }
119
120
121 static void
122 handle_session_client_error (void *cls, enum GNUNET_MQ_Error error)
123 {
124   struct GNUNET_SECRETSHARING_Session *s = cls;
125
126   s->secret_ready_cb (s->secret_ready_cls, NULL, NULL, 0, NULL);
127 }
128
129
130 static void
131 handle_decrypt_client_error (void *cls, enum GNUNET_MQ_Error error)
132 {
133   struct GNUNET_SECRETSHARING_DecryptionHandle *dh = cls;
134   
135   dh->decrypt_cb (dh->decrypt_cls, NULL);
136 }
137
138
139 static void
140 handle_secret_ready (void *cls, const struct GNUNET_MessageHeader *msg)
141 {
142   struct GNUNET_SECRETSHARING_Session *session = cls;
143   struct GNUNET_SECRETSHARING_Share *share;
144   const struct GNUNET_SECRETSHARING_SecretReadyMessage *m = (const void *) msg;
145   size_t share_size;
146
147   LOG (GNUNET_ERROR_TYPE_DEBUG, "got secret ready message of size %u\n",
148        ntohs (m->header.size));
149
150   share_size = ntohs (m->header.size) - sizeof *m;
151
152   share = GNUNET_SECRETSHARING_share_read (&m[1], share_size, NULL);
153
154   session->secret_ready_cb (session->secret_ready_cls,
155                       share, /* FIXME */
156                       &share->public_key,
157                       share->num_peers,
158                       (struct GNUNET_PeerIdentity *) &m[1]);
159
160   GNUNET_SECRETSHARING_session_destroy (session);
161 }
162
163
164 void
165 GNUNET_SECRETSHARING_session_destroy (struct GNUNET_SECRETSHARING_Session *session)
166 {
167   GNUNET_MQ_destroy (session->mq);
168   session->mq = NULL;
169   GNUNET_CLIENT_disconnect (session->client);
170   session->client = NULL;
171   GNUNET_free (session);
172 }
173
174
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,
184                                      void *cls)
185 {
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
192   };
193
194
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);
200
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);
204
205   ev = GNUNET_MQ_msg_extra (msg,
206                             num_peers * sizeof (struct GNUNET_PeerIdentity),
207                             GNUNET_MESSAGE_TYPE_SECRETSHARING_CLIENT_GENERATE);
208
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));
215
216   GNUNET_MQ_send (s->mq, ev);
217
218   LOG (GNUNET_ERROR_TYPE_DEBUG, "secretsharing session created with %u peers\n",
219        num_peers);
220   return s;
221 }
222
223
224 static void
225 handle_decrypt_done (void *cls, const struct GNUNET_MessageHeader *msg)
226 {
227   struct GNUNET_SECRETSHARING_DecryptionHandle *dh = cls;
228   const struct GNUNET_SECRETSHARING_DecryptResponseMessage *m =
229       (const void *) msg;
230
231   const struct GNUNET_SECRETSHARING_Plaintext *plaintext;
232
233   if (m->success == 0)
234     plaintext = NULL;
235   else
236     plaintext = (void *) &m->plaintext;
237
238   dh->decrypt_cb (dh->decrypt_cls, plaintext);
239
240   GNUNET_SECRETSHARING_decrypt_cancel (dh);
241 }
242
243
244 /**
245  * Publish the given ciphertext for decryption.  Once a sufficient (>=k) number of peers has
246  * published the same value, it will be decrypted.
247  *
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.
250  *
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
256  */
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)
265 {
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
272   };
273   size_t share_size;
274
275
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);
281
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);
285
286   GNUNET_assert (GNUNET_OK == GNUNET_SECRETSHARING_share_write (share, NULL, 0, &share_size));
287
288   ev = GNUNET_MQ_msg_extra (msg,
289                             share_size,
290                             GNUNET_MESSAGE_TYPE_SECRETSHARING_CLIENT_DECRYPT);
291
292   GNUNET_assert (GNUNET_OK == GNUNET_SECRETSHARING_share_write (share, &msg[1], share_size, NULL));
293
294   msg->start = GNUNET_TIME_absolute_hton (start);
295   msg->deadline = GNUNET_TIME_absolute_hton (deadline);
296   msg->ciphertext = *ciphertext;
297
298   GNUNET_MQ_send (s->mq, ev);
299
300   LOG (GNUNET_ERROR_TYPE_DEBUG, "decrypt session created\n");
301   return s;
302 }
303
304
305 int
306 GNUNET_SECRETSHARING_plaintext_generate_i (struct GNUNET_SECRETSHARING_Plaintext *plaintext,
307                                            int64_t exponent)
308 {
309   int negative;
310   gcry_mpi_t x;
311
312   ensure_elgamal_initialized ();
313
314   GNUNET_assert (NULL != (x = gcry_mpi_new (0)));
315
316   negative = GNUNET_NO;
317   if (exponent < 0)
318   {
319     negative = GNUNET_YES;
320     exponent = -exponent;
321   }
322
323   gcry_mpi_set_ui (x, exponent);
324
325   gcry_mpi_powm (x, elgamal_g, x, elgamal_p);
326
327   if (GNUNET_YES == negative)
328   {
329     int res;
330     res = gcry_mpi_invm (x, x, elgamal_p);
331     if (0 == res)
332       return GNUNET_SYSERR;
333   }
334
335   GNUNET_CRYPTO_mpi_print_unsigned (plaintext, sizeof (struct GNUNET_SECRETSHARING_Plaintext), x);
336
337   return GNUNET_OK;
338 }
339
340
341 /**
342  * Encrypt a value.  This operation is executed locally, no communication is
343  * necessary.
344  *
345  * This is a helper function, encryption can be done soley with a session's public key
346  * and the crypto system parameters.
347  *
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)
353  */
354 int
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)
358 {
359   /* pubkey */
360   gcry_mpi_t h;
361   /* nonce */
362   gcry_mpi_t y;
363   /* plaintext message */
364   gcry_mpi_t m;
365   /* temp value */
366   gcry_mpi_t tmp;
367
368   ensure_elgamal_initialized ();
369
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)));
373
374   GNUNET_CRYPTO_mpi_scan_unsigned (&h, public_key, sizeof *public_key);
375   GNUNET_CRYPTO_mpi_scan_unsigned (&m, plaintext, sizeof *plaintext);
376
377   // Randomize y such that 0 < y < elgamal_q.
378   // The '- 1' is necessary as bitlength(q) = bitlength(p) - 1.
379   do 
380   {
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));
383
384   // tmp <- g^y
385   gcry_mpi_powm (tmp, elgamal_g, y, elgamal_p);
386   // write tmp to c1
387   GNUNET_CRYPTO_mpi_print_unsigned (&result_ciphertext->c1_bits,
388                                     GNUNET_SECRETSHARING_ELGAMAL_BITS / 8, tmp);
389   
390   // tmp <- h^y
391   gcry_mpi_powm (tmp, h, y, elgamal_p);
392   // tmp <- tmp * m 
393   gcry_mpi_mulm (tmp, tmp, m, elgamal_p);
394   // write tmp to c2
395   GNUNET_CRYPTO_mpi_print_unsigned (&result_ciphertext->c2_bits,
396                                     GNUNET_SECRETSHARING_ELGAMAL_BITS / 8, tmp);
397
398   return GNUNET_OK;
399 }
400
401
402 void
403 GNUNET_SECRETSHARING_decrypt_cancel (struct GNUNET_SECRETSHARING_DecryptionHandle *h)
404 {
405   GNUNET_MQ_destroy (h->mq);
406   h->mq = NULL;
407   GNUNET_CLIENT_disconnect (h->client);
408   h->client = NULL;
409   GNUNET_free (h);
410 }
411
412
413