- fix coverity
[oweals/gnunet.git] / src / scalarproduct / gnunet-service-scalarproduct-ecc_alice.c
1 /*
2      This file is part of GNUnet.
3      Copyright (C) 2013-2015 GNUnet e.V.
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., 51 Franklin Street, Fifth Floor,
18      Boston, MA 02110-1301, USA.
19  */
20 /**
21  * @file scalarproduct/gnunet-service-scalarproduct-ecc_alice.c
22  * @brief scalarproduct service implementation
23  * @author Christian M. Fuchs
24  * @author Christian Grothoff
25  */
26 #include "platform.h"
27 #include <limits.h>
28 #include <gcrypt.h>
29 #include "gnunet_util_lib.h"
30 #include "gnunet_core_service.h"
31 #include "gnunet_cadet_service.h"
32 #include "gnunet_applications.h"
33 #include "gnunet_protocols.h"
34 #include "gnunet_scalarproduct_service.h"
35 #include "gnunet_set_service.h"
36 #include "scalarproduct.h"
37 #include "gnunet-service-scalarproduct-ecc.h"
38
39 #define LOG(kind,...) GNUNET_log_from (kind, "scalarproduct-alice", __VA_ARGS__)
40
41 /**
42  * Maximum allowed result value for the scalarproduct computation.
43  * DLOG will fail if the result is bigger.  At 1 million, the
44  * precomputation takes about 2s on a fast machine.
45  */
46 #define MAX_RESULT (1024 * 1024)
47
48 /**
49  * How many values should DLOG store in memory (determines baseline
50  * RAM consumption, roughly 100 bytes times the value given here).
51  * Should be about SQRT (MAX_RESULT), larger values will make the
52  * online computation faster.
53  */
54 #define MAX_RAM (1024)
55
56 /**
57  * An encrypted element key-value pair.
58  */
59 struct MpiElement
60 {
61   /**
62    * Key used to identify matching pairs of values to multiply.
63    * Points into an existing data structure, to avoid copying
64    * and doubling memory use.
65    */
66   const struct GNUNET_HashCode *key;
67
68   /**
69    * a_i value, not disclosed to Bob.
70    */
71   gcry_mpi_t value;
72
73 };
74
75
76 /**
77  * A scalarproduct session which tracks
78  * a request form the client to our final response.
79  */
80 struct AliceServiceSession
81 {
82
83   /**
84    * (hopefully) unique transaction ID
85    */
86   struct GNUNET_HashCode session_id;
87
88   /**
89    * Alice or Bob's peerID
90    */
91   struct GNUNET_PeerIdentity peer;
92
93   /**
94    * The client this request is related to.
95    */
96   struct GNUNET_SERVER_Client *client;
97
98   /**
99    * The message queue for the client.
100    */
101   struct GNUNET_MQ_Handle *client_mq;
102
103   /**
104    * The message queue for CADET.
105    */
106   struct GNUNET_MQ_Handle *cadet_mq;
107
108   /**
109    * all non-0-value'd elements transmitted to us.
110    * Values are of type `struct GNUNET_SCALARPRODUCT_Element *`
111    */
112   struct GNUNET_CONTAINER_MultiHashMap *intersected_elements;
113
114   /**
115    * Set of elements for which will conduction an intersection.
116    * the resulting elements are then used for computing the scalar product.
117    */
118   struct GNUNET_SET_Handle *intersection_set;
119
120   /**
121    * Set of elements for which will conduction an intersection.
122    * the resulting elements are then used for computing the scalar product.
123    */
124   struct GNUNET_SET_OperationHandle *intersection_op;
125
126   /**
127    * Handle to Alice's Intersection operation listening for Bob
128    */
129   struct GNUNET_SET_ListenHandle *intersection_listen;
130
131   /**
132    * channel-handle associated with our cadet handle
133    */
134   struct GNUNET_CADET_Channel *channel;
135
136   /**
137    * a(Alice), sorted array by key of length @e used_element_count.
138    */
139   struct MpiElement *sorted_elements;
140
141   /**
142    * The computed scalar
143    */
144   gcry_mpi_t product;
145
146   /**
147    * How many elements we were supplied with from the client (total
148    * count before intersection).
149    */
150   uint32_t total;
151
152   /**
153    * How many elements actually are used for the scalar product.
154    * Size of the arrays in @e r and @e r_prime.  Sometimes also
155    * reset to 0 and used as a counter!
156    */
157   uint32_t used_element_count;
158
159   /**
160    * Already transferred elements from client to us.
161    * Less or equal than @e total.
162    */
163   uint32_t client_received_element_count;
164
165   /**
166    * State of this session.   In
167    * #GNUNET_SCALARPRODUCT_STATUS_ACTIVE while operation is
168    * ongoing, afterwards in #GNUNET_SCALARPRODUCT_STATUS_SUCCESS or
169    * #GNUNET_SCALARPRODUCT_STATUS_FAILURE.
170    */
171   enum GNUNET_SCALARPRODUCT_ResponseStatus status;
172
173   /**
174    * Flag to prevent recursive calls to #destroy_service_session() from
175    * doing harm.
176    */
177   int in_destroy;
178
179 };
180
181
182 /**
183  * GNUnet configuration handle
184  */
185 static const struct GNUNET_CONFIGURATION_Handle *cfg;
186
187 /**
188  * Context for DLOG operations on a curve.
189  */
190 static struct GNUNET_CRYPTO_EccDlogContext *edc;
191
192 /**
193  * Alice's private key ('a').
194  */
195 static gcry_mpi_t my_privkey;
196
197 /**
198  * Inverse of Alice's private key ('a_inv').
199  */
200 static gcry_mpi_t my_privkey_inv;
201
202 /**
203  * Handle to the CADET service.
204  */
205 static struct GNUNET_CADET_Handle *my_cadet;
206
207
208 /**
209  * Iterator called to free elements.
210  *
211  * @param cls the `struct AliceServiceSession *` (unused)
212  * @param key the key (unused)
213  * @param value value to free
214  * @return #GNUNET_OK (continue to iterate)
215  */
216 static int
217 free_element_cb (void *cls,
218                  const struct GNUNET_HashCode *key,
219                  void *value)
220 {
221   struct GNUNET_SCALARPRODUCT_Element *e = value;
222
223   GNUNET_free (e);
224   return GNUNET_OK;
225 }
226
227
228 /**
229  * Destroy session state, we are done with it.
230  *
231  * @param s the session to free elements from
232  */
233 static void
234 destroy_service_session (struct AliceServiceSession *s)
235 {
236   unsigned int i;
237
238   if (GNUNET_YES == s->in_destroy)
239     return;
240   s->in_destroy = GNUNET_YES;
241   if (NULL != s->client_mq)
242   {
243     GNUNET_MQ_destroy (s->client_mq);
244     s->client_mq = NULL;
245   }
246   if (NULL != s->cadet_mq)
247   {
248     GNUNET_MQ_destroy (s->cadet_mq);
249     s->cadet_mq = NULL;
250   }
251   if (NULL != s->client)
252   {
253     GNUNET_SERVER_client_set_user_context (s->client,
254                                            NULL);
255     GNUNET_SERVER_client_disconnect (s->client);
256     s->client = NULL;
257   }
258   if (NULL != s->channel)
259   {
260     GNUNET_CADET_channel_destroy (s->channel);
261     s->channel = NULL;
262   }
263   if (NULL != s->intersected_elements)
264   {
265     GNUNET_CONTAINER_multihashmap_iterate (s->intersected_elements,
266                                            &free_element_cb,
267                                            s);
268     GNUNET_CONTAINER_multihashmap_destroy (s->intersected_elements);
269     s->intersected_elements = NULL;
270   }
271   if (NULL != s->intersection_listen)
272   {
273     GNUNET_SET_listen_cancel (s->intersection_listen);
274     s->intersection_listen = NULL;
275   }
276   if (NULL != s->intersection_op)
277   {
278     GNUNET_SET_operation_cancel (s->intersection_op);
279     s->intersection_op = NULL;
280   }
281   if (NULL != s->intersection_set)
282   {
283     GNUNET_SET_destroy (s->intersection_set);
284     s->intersection_set = NULL;
285   }
286   if (NULL != s->sorted_elements)
287   {
288     for (i=0;i<s->used_element_count;i++)
289       gcry_mpi_release (s->sorted_elements[i].value);
290     GNUNET_free (s->sorted_elements);
291     s->sorted_elements = NULL;
292   }
293   if (NULL != s->product)
294   {
295     gcry_mpi_release (s->product);
296     s->product = NULL;
297   }
298   GNUNET_free (s);
299 }
300
301
302 /**
303  * Notify the client that the session has failed.  A message gets sent
304  * to Alice's client if we encountered any error.
305  *
306  * @param session the associated client session to fail or succeed
307  */
308 static void
309 prepare_client_end_notification (struct AliceServiceSession *session)
310 {
311   struct ClientResponseMessage *msg;
312   struct GNUNET_MQ_Envelope *e;
313
314   if (NULL == session->client_mq)
315     return; /* no client left to be notified */
316   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
317               "Sending session-end notification with status %d to client for session %s\n",
318               session->status,
319               GNUNET_h2s (&session->session_id));
320   e = GNUNET_MQ_msg (msg,
321                      GNUNET_MESSAGE_TYPE_SCALARPRODUCT_RESULT);
322   msg->product_length = htonl (0);
323   msg->status = htonl (session->status);
324   GNUNET_MQ_send (session->client_mq,
325                   e);
326 }
327
328
329 /**
330  * Prepare the final (positive) response we will send to Alice's
331  * client.
332  *
333  * @param s the session associated with our client.
334  */
335 static void
336 transmit_client_response (struct AliceServiceSession *s)
337 {
338   struct ClientResponseMessage *msg;
339   struct GNUNET_MQ_Envelope *e;
340   unsigned char *product_exported = NULL;
341   size_t product_length = 0;
342   int32_t range;
343   gcry_error_t rc;
344   int sign;
345   gcry_mpi_t value;
346
347   if (NULL == s->product)
348   {
349     GNUNET_break (0);
350     prepare_client_end_notification (s);
351     return;
352   }
353   value = gcry_mpi_new (0);
354   sign = gcry_mpi_cmp_ui (s->product, 0);
355   if (0 > sign)
356   {
357     range = -1;
358     gcry_mpi_sub (value,
359                   value,
360                   s->product);
361   }
362   else if (0 < sign)
363   {
364     range = 1;
365     gcry_mpi_add (value, value, s->product);
366   }
367   else
368   {
369     /* result is exactly zero */
370     range = 0;
371   }
372   gcry_mpi_release (s->product);
373   s->product = NULL;
374
375   if ( (0 != range) &&
376        (0 != (rc = gcry_mpi_aprint (GCRYMPI_FMT_STD,
377                                     &product_exported,
378                                     &product_length,
379                                     value))))
380   {
381     LOG_GCRY (GNUNET_ERROR_TYPE_ERROR,
382               "gcry_mpi_scan",
383               rc);
384     prepare_client_end_notification (s);
385     return;
386   }
387   gcry_mpi_release (value);
388   e = GNUNET_MQ_msg_extra (msg,
389                            product_length,
390                            GNUNET_MESSAGE_TYPE_SCALARPRODUCT_RESULT);
391   msg->status = htonl (GNUNET_SCALARPRODUCT_STATUS_SUCCESS);
392   msg->range = htonl (range);
393   msg->product_length = htonl (product_length);
394   if (NULL != product_exported)
395   {
396     memcpy (&msg[1],
397             product_exported,
398             product_length);
399     GNUNET_free (product_exported);
400   }
401   GNUNET_MQ_send (s->client_mq,
402                   e);
403   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
404               "Sent result to client, session %s has ended!\n",
405               GNUNET_h2s (&s->session_id));
406 }
407
408
409
410 /**
411  * Function called whenever a channel is destroyed.  Should clean up
412  * any associated state.
413  *
414  * It must NOT call #GNUNET_CADET_channel_destroy() on the channel.
415  *
416  * @param cls closure (set from #GNUNET_CADET_connect())
417  * @param channel connection to the other end (henceforth invalid)
418  * @param channel_ctx place where local state associated
419  *                   with the channel is stored
420  */
421 static void
422 cb_channel_destruction (void *cls,
423                         const struct GNUNET_CADET_Channel *channel,
424                         void *channel_ctx)
425 {
426   struct AliceServiceSession *s = channel_ctx;
427
428   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
429               "Peer disconnected, terminating session %s with peer %s\n",
430               GNUNET_h2s (&s->session_id),
431               GNUNET_i2s (&s->peer));
432   if (NULL != s->cadet_mq)
433   {
434     GNUNET_MQ_destroy (s->cadet_mq);
435     s->cadet_mq = NULL;
436   }
437   s->channel = NULL;
438   if (GNUNET_SCALARPRODUCT_STATUS_ACTIVE == s->status)
439   {
440     /* We didn't get an answer yet, fail with error */
441     s->status = GNUNET_SCALARPRODUCT_STATUS_FAILURE;
442     prepare_client_end_notification (s);
443   }
444 }
445
446
447 /**
448  * Compute our scalar product, done by Alice
449  *
450  * @param session the session associated with this computation
451  * @param prod_g_i_b_i value from Bob
452  * @param prod_h_i_b_i value from Bob
453  * @return product as MPI, never NULL
454  */
455 static gcry_mpi_t
456 compute_scalar_product (struct AliceServiceSession *session,
457                         gcry_mpi_point_t prod_g_i_b_i,
458                         gcry_mpi_point_t prod_h_i_b_i)
459 {
460   gcry_mpi_point_t g_i_b_i_a_inv;
461   gcry_mpi_point_t g_ai_bi;
462   int ai_bi;
463   gcry_mpi_t ret;
464
465   g_i_b_i_a_inv = GNUNET_CRYPTO_ecc_pmul_mpi (edc,
466                                               prod_g_i_b_i,
467                                               my_privkey_inv);
468   g_ai_bi = GNUNET_CRYPTO_ecc_add (edc,
469                                    g_i_b_i_a_inv,
470                                    prod_h_i_b_i);
471   gcry_mpi_point_release (g_i_b_i_a_inv);
472   ai_bi = GNUNET_CRYPTO_ecc_dlog (edc,
473                                   g_ai_bi);
474   gcry_mpi_point_release (g_ai_bi);
475   if (INT_MAX == ai_bi)
476   {
477     /* result too big */
478     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
479                 "Scalar product result out of range\n");
480     return NULL;
481   }
482   ret = gcry_mpi_new (0);
483   if (ai_bi > 0)
484   {
485     gcry_mpi_set_ui (ret, ai_bi);
486   }
487   else
488   {
489     gcry_mpi_set_ui (ret, - ai_bi);
490     gcry_mpi_neg (ret, ret);
491   }
492   return ret;
493 }
494
495
496 /**
497  * Handle a response we got from another service we wanted to
498  * calculate a scalarproduct with.
499  *
500  * @param cls closure (set from #GNUNET_CADET_connect)
501  * @param channel connection to the other end
502  * @param channel_ctx place to store local state associated with the channel
503  * @param message the actual message
504  * @return #GNUNET_OK to keep the connection open,
505  *         #GNUNET_SYSERR to close it (we are done)
506  */
507 static int
508 handle_bobs_cryptodata_message (void *cls,
509                                 struct GNUNET_CADET_Channel *channel,
510                                 void **channel_ctx,
511                                 const struct GNUNET_MessageHeader *message)
512 {
513   struct AliceServiceSession *s = *channel_ctx;
514   const struct EccBobCryptodataMessage *msg;
515   uint32_t contained;
516   uint16_t msg_size;
517   gcry_mpi_point_t prod_g_i_b_i;
518   gcry_mpi_point_t prod_h_i_b_i;
519
520   if (NULL == s)
521   {
522     GNUNET_break_op (0);
523     return GNUNET_SYSERR;
524   }
525   msg_size = ntohs (message->size);
526   if (sizeof (struct EccBobCryptodataMessage) > msg_size)
527   {
528     GNUNET_break_op (0);
529     return GNUNET_SYSERR;
530   }
531   msg = (const struct EccBobCryptodataMessage *) message;
532   contained = ntohl (msg->contained_element_count);
533   if (2 != contained)
534   {
535     GNUNET_break_op (0);
536     return GNUNET_SYSERR;
537   }
538   if (NULL == s->sorted_elements)
539   {
540     /* we're not ready yet, how can Bob be? */
541     GNUNET_break_op (0);
542     return GNUNET_SYSERR;
543   }
544   if (s->total != s->client_received_element_count)
545   {
546     /* we're not ready yet, how can Bob be? */
547     GNUNET_break_op (0);
548     return GNUNET_SYSERR;
549   }
550   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
551               "Received %u crypto values from Bob\n",
552               (unsigned int) contained);
553   GNUNET_CADET_receive_done (s->channel);
554   prod_g_i_b_i = GNUNET_CRYPTO_ecc_bin_to_point (edc,
555                                                  &msg->prod_g_i_b_i);
556   prod_h_i_b_i = GNUNET_CRYPTO_ecc_bin_to_point (edc,
557                                                  &msg->prod_h_i_b_i);
558   s->product = compute_scalar_product (s,
559                                        prod_g_i_b_i,
560                                        prod_h_i_b_i);
561   gcry_mpi_point_release (prod_g_i_b_i);
562   gcry_mpi_point_release (prod_h_i_b_i);
563   transmit_client_response (s);
564   return GNUNET_OK;
565 }
566
567
568 /**
569  * Iterator to copy over messages from the hash map
570  * into an array for sorting.
571  *
572  * @param cls the `struct AliceServiceSession *`
573  * @param key the key (unused)
574  * @param value the `struct GNUNET_SCALARPRODUCT_Element *`
575  */
576 static int
577 copy_element_cb (void *cls,
578                  const struct GNUNET_HashCode *key,
579                  void *value)
580 {
581   struct AliceServiceSession *s = cls;
582   struct GNUNET_SCALARPRODUCT_Element *e = value;
583   gcry_mpi_t mval;
584   int64_t val;
585
586   mval = gcry_mpi_new (0);
587   val = (int64_t) GNUNET_ntohll (e->value);
588   if (0 > val)
589     gcry_mpi_sub_ui (mval, mval, -val);
590   else
591     gcry_mpi_add_ui (mval, mval, val);
592   s->sorted_elements [s->used_element_count].value = mval;
593   s->sorted_elements [s->used_element_count].key = &e->key;
594   s->used_element_count++;
595   return GNUNET_OK;
596 }
597
598
599 /**
600  * Compare two `struct MpiValue`s by key for sorting.
601  *
602  * @param a pointer to first `struct MpiValue *`
603  * @param b pointer to first `struct MpiValue *`
604  * @return -1 for a < b, 0 for a=b, 1 for a > b.
605  */
606 static int
607 element_cmp (const void *a,
608              const void *b)
609 {
610   const struct MpiElement *ma = a;
611   const struct MpiElement *mb = b;
612
613   return GNUNET_CRYPTO_hash_cmp (ma->key,
614                                  mb->key);
615 }
616
617
618 /**
619  * Maximum number of elements we can put into a single cryptodata
620  * message
621  */
622 #define ELEMENT_CAPACITY ((GNUNET_CONSTANTS_MAX_CADET_MESSAGE_SIZE - 1 - sizeof (struct EccAliceCryptodataMessage)) / sizeof (struct GNUNET_CRYPTO_EccPoint))
623
624
625 /**
626  * Send the cryptographic data from Alice to Bob.
627  * Does nothing if we already transferred all elements.
628  *
629  * @param s the associated service session
630  */
631 static void
632 send_alices_cryptodata_message (struct AliceServiceSession *s)
633 {
634   struct EccAliceCryptodataMessage *msg;
635   struct GNUNET_MQ_Envelope *e;
636   struct GNUNET_CRYPTO_EccPoint *payload;
637   gcry_mpi_t r_ia;
638   gcry_mpi_t r_ia_ai;
639   unsigned int i;
640   unsigned int off;
641   unsigned int todo_count;
642
643   s->sorted_elements
644     = GNUNET_malloc (GNUNET_CONTAINER_multihashmap_size (s->intersected_elements) *
645                      sizeof (struct MpiElement));
646   s->used_element_count = 0;
647   GNUNET_CONTAINER_multihashmap_iterate (s->intersected_elements,
648                                          &copy_element_cb,
649                                          s);
650   LOG (GNUNET_ERROR_TYPE_DEBUG,
651        "Finished intersection, %d items remain\n",
652        s->used_element_count);
653   qsort (s->sorted_elements,
654          s->used_element_count,
655          sizeof (struct MpiElement),
656          &element_cmp);
657   off = 0;
658   while (off < s->used_element_count)
659   {
660     todo_count = s->used_element_count - off;
661     if (todo_count > ELEMENT_CAPACITY)
662       todo_count = ELEMENT_CAPACITY;
663     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
664                 "Sending %u/%u crypto values to Bob\n",
665                 (unsigned int) todo_count,
666                 (unsigned int) s->used_element_count);
667
668     e = GNUNET_MQ_msg_extra (msg,
669                              todo_count * 2 * sizeof (struct GNUNET_CRYPTO_EccPoint),
670                              GNUNET_MESSAGE_TYPE_SCALARPRODUCT_ECC_ALICE_CRYPTODATA);
671     msg->contained_element_count = htonl (todo_count);
672     payload = (struct GNUNET_CRYPTO_EccPoint *) &msg[1];
673     r_ia = gcry_mpi_new (0);
674     r_ia_ai = gcry_mpi_new (0);
675     for (i = off; i < off + todo_count; i++)
676     {
677       gcry_mpi_t r_i;
678       gcry_mpi_point_t g_i;
679       gcry_mpi_point_t h_i;
680
681       r_i = GNUNET_CRYPTO_ecc_random_mod_n (edc);
682       g_i = GNUNET_CRYPTO_ecc_dexp_mpi (edc,
683                                         r_i);
684       /* r_ia = r_i * a */
685       gcry_mpi_mul (r_ia,
686                     r_i,
687                     my_privkey);
688       gcry_mpi_release (r_i);
689       /* r_ia_ai = r_ia + a_i */
690       gcry_mpi_add (r_ia_ai,
691                     r_ia,
692                     s->sorted_elements[i].value);
693       h_i = GNUNET_CRYPTO_ecc_dexp_mpi (edc,
694                                         r_ia_ai);
695       GNUNET_CRYPTO_ecc_point_to_bin (edc,
696                                       g_i,
697                                       &payload[(i - off) * 2]);
698       GNUNET_CRYPTO_ecc_point_to_bin (edc,
699                                       h_i,
700                                       &payload[(i - off) * 2 + 1]);
701       gcry_mpi_point_release (g_i);
702       gcry_mpi_point_release (h_i);
703     }
704     gcry_mpi_release (r_ia);
705     gcry_mpi_release (r_ia_ai);
706     off += todo_count;
707     GNUNET_MQ_send (s->cadet_mq,
708                     e);
709   }
710 }
711
712
713 /**
714  * Callback for set operation results. Called for each element
715  * that should be removed from the result set, and then once
716  * to indicate that the set intersection operation is done.
717  *
718  * @param cls closure with the `struct AliceServiceSession`
719  * @param element a result element, only valid if status is #GNUNET_SET_STATUS_OK
720  * @param status what has happened with the set intersection?
721  */
722 static void
723 cb_intersection_element_removed (void *cls,
724                                  const struct GNUNET_SET_Element *element,
725                                  enum GNUNET_SET_Status status)
726 {
727   struct AliceServiceSession *s = cls;
728   struct GNUNET_SCALARPRODUCT_Element *se;
729
730   switch (status)
731   {
732   case GNUNET_SET_STATUS_OK:
733     /* this element has been removed from the set */
734     se = GNUNET_CONTAINER_multihashmap_get (s->intersected_elements,
735                                             element->data);
736     GNUNET_assert (NULL != se);
737     LOG (GNUNET_ERROR_TYPE_DEBUG,
738          "Intersection removed element with key %s and value %lld\n",
739          GNUNET_h2s (&se->key),
740          (long long) GNUNET_ntohll (se->value));
741     GNUNET_assert (GNUNET_YES ==
742                    GNUNET_CONTAINER_multihashmap_remove (s->intersected_elements,
743                                                          element->data,
744                                                          se));
745     GNUNET_free (se);
746     return;
747   case GNUNET_SET_STATUS_DONE:
748     s->intersection_op = NULL;
749     if (NULL != s->intersection_set)
750     {
751       GNUNET_SET_destroy (s->intersection_set);
752       s->intersection_set = NULL;
753     }
754     send_alices_cryptodata_message (s);
755     return;
756   case GNUNET_SET_STATUS_HALF_DONE:
757     /* unexpected for intersection */
758     GNUNET_break (0);
759     return;
760   case GNUNET_SET_STATUS_FAILURE:
761     /* unhandled status code */
762     LOG (GNUNET_ERROR_TYPE_DEBUG,
763          "Set intersection failed!\n");
764     if (NULL != s->intersection_listen)
765     {
766       GNUNET_SET_listen_cancel (s->intersection_listen);
767       s->intersection_listen = NULL;
768     }
769     s->intersection_op = NULL;
770     if (NULL != s->intersection_set)
771     {
772       GNUNET_SET_destroy (s->intersection_set);
773       s->intersection_set = NULL;
774     }
775     s->status = GNUNET_SCALARPRODUCT_STATUS_FAILURE;
776     prepare_client_end_notification (s);
777     return;
778   default:
779     GNUNET_break (0);
780     return;
781   }
782 }
783
784
785 /**
786  * Called when another peer wants to do a set operation with the
787  * local peer. If a listen error occurs, the @a request is NULL.
788  *
789  * @param cls closure with the `struct AliceServiceSession *`
790  * @param other_peer the other peer
791  * @param context_msg message with application specific information from
792  *        the other peer
793  * @param request request from the other peer (never NULL), use GNUNET_SET_accept()
794  *        to accept it, otherwise the request will be refused
795  *        Note that we can't just return value from the listen callback,
796  *        as it is also necessary to specify the set we want to do the
797  *        operation with, whith sometimes can be derived from the context
798  *        message. It's necessary to specify the timeout.
799  */
800 static void
801 cb_intersection_request_alice (void *cls,
802                                const struct GNUNET_PeerIdentity *other_peer,
803                                const struct GNUNET_MessageHeader *context_msg,
804                                struct GNUNET_SET_Request *request)
805 {
806   struct AliceServiceSession *s = cls;
807
808   if (0 != memcmp (other_peer,
809                    &s->peer,
810                    sizeof (struct GNUNET_PeerIdentity)))
811   {
812     GNUNET_break_op (0);
813     return;
814   }
815   s->intersection_op
816     = GNUNET_SET_accept (request,
817                          GNUNET_SET_RESULT_REMOVED,
818                          &cb_intersection_element_removed,
819                          s);
820   if (NULL == s->intersection_op)
821   {
822     GNUNET_break (0);
823     s->status = GNUNET_SCALARPRODUCT_STATUS_FAILURE;
824     prepare_client_end_notification (s);
825     return;
826   }
827   if (GNUNET_OK !=
828       GNUNET_SET_commit (s->intersection_op,
829                          s->intersection_set))
830   {
831     GNUNET_break (0);
832     s->status = GNUNET_SCALARPRODUCT_STATUS_FAILURE;
833     prepare_client_end_notification (s);
834     return;
835   }
836   GNUNET_SET_destroy (s->intersection_set);
837   s->intersection_set = NULL;
838   GNUNET_SET_listen_cancel (s->intersection_listen);
839   s->intersection_listen = NULL;
840 }
841
842
843 /**
844  * Our client has finished sending us its multipart message.
845  *
846  * @param session the service session context
847  */
848 static void
849 client_request_complete_alice (struct AliceServiceSession *s)
850 {
851   struct EccServiceRequestMessage *msg;
852   struct GNUNET_MQ_Envelope *e;
853
854   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
855               "Creating new channel for session with key %s.\n",
856               GNUNET_h2s (&s->session_id));
857   s->channel
858     = GNUNET_CADET_channel_create (my_cadet,
859                                    s,
860                                    &s->peer,
861                                    GNUNET_APPLICATION_TYPE_SCALARPRODUCT_ECC,
862                                    GNUNET_CADET_OPTION_RELIABLE);
863   if (NULL == s->channel)
864   {
865     s->status = GNUNET_SCALARPRODUCT_STATUS_FAILURE;
866     prepare_client_end_notification (s);
867     return;
868   }
869   s->cadet_mq = GNUNET_CADET_mq_create (s->channel);
870   s->intersection_listen
871     = GNUNET_SET_listen (cfg,
872                          GNUNET_SET_OPERATION_INTERSECTION,
873                          &s->session_id,
874                          &cb_intersection_request_alice,
875                          s);
876   if (NULL == s->intersection_listen)
877   {
878     s->status = GNUNET_SCALARPRODUCT_STATUS_FAILURE;
879     GNUNET_CADET_channel_destroy (s->channel);
880     s->channel = NULL;
881     prepare_client_end_notification (s);
882     return;
883   }
884
885   e = GNUNET_MQ_msg (msg,
886                      GNUNET_MESSAGE_TYPE_SCALARPRODUCT_ECC_SESSION_INITIALIZATION);
887   msg->session_id = s->session_id;
888   GNUNET_MQ_send (s->cadet_mq,
889                   e);
890 }
891
892
893 /**
894  * We're receiving additional set data. Add it to our
895  * set and if we are done, initiate the transaction.
896  *
897  * @param cls closure
898  * @param client identification of the client
899  * @param message the actual message
900  */
901 static void
902 GSS_handle_alice_client_message_multipart (void *cls,
903                                            struct GNUNET_SERVER_Client *client,
904                                            const struct GNUNET_MessageHeader *message)
905 {
906   const struct ComputationBobCryptodataMultipartMessage * msg;
907   struct AliceServiceSession *s;
908   uint32_t contained_count;
909   const struct GNUNET_SCALARPRODUCT_Element *elements;
910   uint32_t i;
911   uint16_t msize;
912   struct GNUNET_SET_Element set_elem;
913   struct GNUNET_SCALARPRODUCT_Element *elem;
914
915   s = GNUNET_SERVER_client_get_user_context (client,
916                                              struct AliceServiceSession);
917   if (NULL == s)
918   {
919     /* session needs to already exist */
920     GNUNET_break (0);
921     GNUNET_SERVER_receive_done (client,
922                                 GNUNET_SYSERR);
923     return;
924   }
925   msize = ntohs (message->size);
926   if (msize < sizeof (struct ComputationBobCryptodataMultipartMessage))
927   {
928     GNUNET_break (0);
929     GNUNET_SERVER_receive_done (client,
930                                 GNUNET_SYSERR);
931     return;
932   }
933   msg = (const struct ComputationBobCryptodataMultipartMessage *) message;
934   contained_count = ntohl (msg->element_count_contained);
935
936   if ( (msize != (sizeof (struct ComputationBobCryptodataMultipartMessage) +
937                   contained_count * sizeof (struct GNUNET_SCALARPRODUCT_Element))) ||
938        (0 == contained_count) ||
939        (s->total == s->client_received_element_count) ||
940        (s->total < s->client_received_element_count + contained_count) )
941   {
942     GNUNET_break_op (0);
943     GNUNET_SERVER_receive_done (client,
944                                 GNUNET_SYSERR);
945     return;
946   }
947   s->client_received_element_count += contained_count;
948   elements = (const struct GNUNET_SCALARPRODUCT_Element *) &msg[1];
949   for (i = 0; i < contained_count; i++)
950   {
951     elem = GNUNET_new (struct GNUNET_SCALARPRODUCT_Element);
952     memcpy (elem,
953             &elements[i],
954             sizeof (struct GNUNET_SCALARPRODUCT_Element));
955     if (GNUNET_SYSERR ==
956         GNUNET_CONTAINER_multihashmap_put (s->intersected_elements,
957                                            &elem->key,
958                                            elem,
959                                            GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY))
960     {
961       GNUNET_break (0);
962       GNUNET_free (elem);
963       continue;
964     }
965     set_elem.data = &elem->key;
966     set_elem.size = sizeof (elem->key);
967     set_elem.element_type = 0;
968     GNUNET_SET_add_element (s->intersection_set,
969                             &set_elem,
970                             NULL, NULL);
971     s->used_element_count++;
972   }
973   GNUNET_SERVER_receive_done (client,
974                               GNUNET_OK);
975   if (s->total != s->client_received_element_count)
976   {
977     /* more to come */
978     return;
979   }
980   client_request_complete_alice (s);
981 }
982
983
984 /**
985  * Handler for Alice's client request message.
986  * We are doing request-initiation to compute a scalar product with a peer.
987  *
988  * @param cls closure
989  * @param client identification of the client
990  * @param message the actual message
991  */
992 static void
993 GSS_handle_alice_client_message (void *cls,
994                                  struct GNUNET_SERVER_Client *client,
995                                  const struct GNUNET_MessageHeader *message)
996 {
997   const struct AliceComputationMessage *msg;
998   struct AliceServiceSession *s;
999   uint32_t contained_count;
1000   uint32_t total_count;
1001   const struct GNUNET_SCALARPRODUCT_Element *elements;
1002   uint32_t i;
1003   uint16_t msize;
1004   struct GNUNET_SET_Element set_elem;
1005   struct GNUNET_SCALARPRODUCT_Element *elem;
1006
1007   s = GNUNET_SERVER_client_get_user_context (client,
1008                                              struct AliceServiceSession);
1009   if (NULL != s)
1010   {
1011     /* only one concurrent session per client connection allowed,
1012        simplifies logic a lot... */
1013     GNUNET_break (0);
1014     GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
1015     return;
1016   }
1017   msize = ntohs (message->size);
1018   if (msize < sizeof (struct AliceComputationMessage))
1019   {
1020     GNUNET_break (0);
1021     GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
1022     return;
1023   }
1024   msg = (const struct AliceComputationMessage *) message;
1025   total_count = ntohl (msg->element_count_total);
1026   contained_count = ntohl (msg->element_count_contained);
1027   if ( (0 == total_count) ||
1028        (0 == contained_count) ||
1029        (msize != (sizeof (struct AliceComputationMessage) +
1030                   contained_count * sizeof (struct GNUNET_SCALARPRODUCT_Element))) )
1031   {
1032     GNUNET_break_op (0);
1033     GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
1034     return;
1035   }
1036
1037   s = GNUNET_new (struct AliceServiceSession);
1038   s->peer = msg->peer;
1039   s->status = GNUNET_SCALARPRODUCT_STATUS_ACTIVE;
1040   s->client = client;
1041   s->client_mq = GNUNET_MQ_queue_for_server_client (client);
1042   s->total = total_count;
1043   s->client_received_element_count = contained_count;
1044   s->session_id = msg->session_key;
1045   elements = (const struct GNUNET_SCALARPRODUCT_Element *) &msg[1];
1046   s->intersected_elements = GNUNET_CONTAINER_multihashmap_create (s->total,
1047                                                                   GNUNET_YES);
1048   s->intersection_set = GNUNET_SET_create (cfg,
1049                                            GNUNET_SET_OPERATION_INTERSECTION);
1050   for (i = 0; i < contained_count; i++)
1051   {
1052     if (0 == GNUNET_ntohll (elements[i].value))
1053       continue;
1054     elem = GNUNET_new (struct GNUNET_SCALARPRODUCT_Element);
1055     memcpy (elem,
1056             &elements[i],
1057             sizeof (struct GNUNET_SCALARPRODUCT_Element));
1058     if (GNUNET_SYSERR ==
1059         GNUNET_CONTAINER_multihashmap_put (s->intersected_elements,
1060                                            &elem->key,
1061                                            elem,
1062                                            GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY))
1063     {
1064       /* element with same key encountered twice! */
1065       GNUNET_break (0);
1066       GNUNET_free (elem);
1067       continue;
1068     }
1069     set_elem.data = &elem->key;
1070     set_elem.size = sizeof (elem->key);
1071     set_elem.element_type = 0;
1072     GNUNET_SET_add_element (s->intersection_set,
1073                             &set_elem,
1074                             NULL, NULL);
1075     s->used_element_count++;
1076   }
1077   GNUNET_SERVER_client_set_user_context (client,
1078                                          s);
1079   GNUNET_SERVER_receive_done (client,
1080                               GNUNET_OK);
1081   if (s->total != s->client_received_element_count)
1082   {
1083     /* wait for multipart msg */
1084     return;
1085   }
1086   client_request_complete_alice (s);
1087 }
1088
1089
1090 /**
1091  * Task run during shutdown.
1092  *
1093  * @param cls unused
1094  * @param tc unused
1095  */
1096 static void
1097 shutdown_task (void *cls)
1098 {
1099   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1100               "Shutting down, initiating cleanup.\n");
1101   // FIXME: we have to cut our connections to CADET first!
1102   if (NULL != my_cadet)
1103   {
1104     GNUNET_CADET_disconnect (my_cadet);
1105     my_cadet = NULL;
1106   }
1107   if (NULL != edc)
1108   {
1109     GNUNET_CRYPTO_ecc_dlog_release (edc);
1110     edc = NULL;
1111   }
1112 }
1113
1114
1115 /**
1116  * A client disconnected.
1117  *
1118  * Remove the associated session(s), release data structures
1119  * and cancel pending outgoing transmissions to the client.
1120  *
1121  * @param cls closure, NULL
1122  * @param client identification of the client
1123  */
1124 static void
1125 handle_client_disconnect (void *cls,
1126                           struct GNUNET_SERVER_Client *client)
1127 {
1128   struct AliceServiceSession *s;
1129
1130   if (NULL == client)
1131     return;
1132   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1133               "Client %p disconnected from us.\n",
1134               client);
1135   s = GNUNET_SERVER_client_get_user_context (client,
1136                                              struct AliceServiceSession);
1137   if (NULL == s)
1138     return;
1139   s->client = NULL;
1140   GNUNET_SERVER_client_set_user_context (client,
1141                                          NULL);
1142   destroy_service_session (s);
1143 }
1144
1145
1146 /**
1147  * Initialization of the program and message handlers
1148  *
1149  * @param cls closure
1150  * @param server the initialized server
1151  * @param c configuration to use
1152  */
1153 static void
1154 run (void *cls,
1155      struct GNUNET_SERVER_Handle *server,
1156      const struct GNUNET_CONFIGURATION_Handle *c)
1157 {
1158   static const struct GNUNET_CADET_MessageHandler cadet_handlers[] = {
1159     { &handle_bobs_cryptodata_message,
1160       GNUNET_MESSAGE_TYPE_SCALARPRODUCT_ECC_BOB_CRYPTODATA,
1161       0},
1162     { NULL, 0, 0}
1163   };
1164   static const struct GNUNET_SERVER_MessageHandler server_handlers[] = {
1165     { &GSS_handle_alice_client_message, NULL,
1166       GNUNET_MESSAGE_TYPE_SCALARPRODUCT_CLIENT_TO_ALICE,
1167       0},
1168     { &GSS_handle_alice_client_message_multipart, NULL,
1169       GNUNET_MESSAGE_TYPE_SCALARPRODUCT_CLIENT_MUTLIPART_ALICE,
1170       0},
1171     { NULL, NULL, 0, 0}
1172   };
1173
1174   cfg = c;
1175   edc = GNUNET_CRYPTO_ecc_dlog_prepare (MAX_RESULT,
1176                                         MAX_RAM);
1177   /* Select a random 'a' value for Alice */
1178   GNUNET_CRYPTO_ecc_rnd_mpi (edc,
1179                              &my_privkey,
1180                              &my_privkey_inv);
1181   GNUNET_SERVER_add_handlers (server,
1182                               server_handlers);
1183   GNUNET_SERVER_disconnect_notify (server,
1184                                    &handle_client_disconnect,
1185                                    NULL);
1186   my_cadet = GNUNET_CADET_connect (cfg, NULL,
1187                                    NULL /* no incoming supported */,
1188                                    &cb_channel_destruction,
1189                                    cadet_handlers,
1190                                    NULL);
1191   if (NULL == my_cadet)
1192   {
1193     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1194                 _("Connect to CADET failed\n"));
1195     GNUNET_SCHEDULER_shutdown ();
1196     return;
1197   }
1198   GNUNET_SCHEDULER_add_shutdown (&shutdown_task,
1199                                  NULL);
1200
1201 }
1202
1203
1204 /**
1205  * The main function for the scalarproduct service.
1206  *
1207  * @param argc number of arguments from the command line
1208  * @param argv command line arguments
1209  * @return 0 ok, 1 on error
1210  */
1211 int
1212 main (int argc,
1213       char *const *argv)
1214 {
1215   return (GNUNET_OK ==
1216           GNUNET_SERVICE_run (argc, argv,
1217                               "scalarproduct-alice",
1218                               GNUNET_SERVICE_OPTION_NONE,
1219                               &run, NULL)) ? 0 : 1;
1220 }
1221
1222 /* end of gnunet-service-scalarproduct-ecc_alice.c */