curl: fix linking against libgnurl/libcurl
[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   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
315               "Sending session-end notification with status %d to client for session %s\n",
316               session->status,
317               GNUNET_h2s (&session->session_id));
318   e = GNUNET_MQ_msg (msg,
319                      GNUNET_MESSAGE_TYPE_SCALARPRODUCT_RESULT);
320   msg->product_length = htonl (0);
321   msg->status = htonl (session->status);
322   GNUNET_MQ_send (session->client_mq,
323                   e);
324 }
325
326
327 /**
328  * Prepare the final (positive) response we will send to Alice's
329  * client.
330  *
331  * @param s the session associated with our client.
332  */
333 static void
334 transmit_client_response (struct AliceServiceSession *s)
335 {
336   struct ClientResponseMessage *msg;
337   struct GNUNET_MQ_Envelope *e;
338   unsigned char *product_exported = NULL;
339   size_t product_length = 0;
340   int32_t range;
341   gcry_error_t rc;
342   int sign;
343   gcry_mpi_t value;
344
345   if (NULL == s->product)
346   {
347     GNUNET_break (0);
348     prepare_client_end_notification (s);
349     return;
350   }
351   value = gcry_mpi_new (0);
352   sign = gcry_mpi_cmp_ui (s->product, 0);
353   if (0 > sign)
354   {
355     range = -1;
356     gcry_mpi_sub (value,
357                   value,
358                   s->product);
359   }
360   else if (0 < sign)
361   {
362     range = 1;
363     gcry_mpi_add (value, value, s->product);
364   }
365   else
366   {
367     /* result is exactly zero */
368     range = 0;
369   }
370   gcry_mpi_release (s->product);
371   s->product = NULL;
372
373   if ( (0 != range) &&
374        (0 != (rc = gcry_mpi_aprint (GCRYMPI_FMT_STD,
375                                     &product_exported,
376                                     &product_length,
377                                     value))))
378   {
379     LOG_GCRY (GNUNET_ERROR_TYPE_ERROR,
380               "gcry_mpi_scan",
381               rc);
382     prepare_client_end_notification (s);
383     return;
384   }
385   gcry_mpi_release (value);
386   e = GNUNET_MQ_msg_extra (msg,
387                            product_length,
388                            GNUNET_MESSAGE_TYPE_SCALARPRODUCT_RESULT);
389   msg->status = htonl (GNUNET_SCALARPRODUCT_STATUS_SUCCESS);
390   msg->range = htonl (range);
391   msg->product_length = htonl (product_length);
392   if (NULL != product_exported)
393   {
394     memcpy (&msg[1],
395             product_exported,
396             product_length);
397     GNUNET_free (product_exported);
398   }
399   GNUNET_MQ_send (s->client_mq,
400                   e);
401   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
402               "Sent result to client, session %s has ended!\n",
403               GNUNET_h2s (&s->session_id));
404 }
405
406
407
408 /**
409  * Function called whenever a channel is destroyed.  Should clean up
410  * any associated state.
411  *
412  * It must NOT call #GNUNET_CADET_channel_destroy() on the channel.
413  *
414  * @param cls closure (set from #GNUNET_CADET_connect())
415  * @param channel connection to the other end (henceforth invalid)
416  * @param channel_ctx place where local state associated
417  *                   with the channel is stored
418  */
419 static void
420 cb_channel_destruction (void *cls,
421                         const struct GNUNET_CADET_Channel *channel,
422                         void *channel_ctx)
423 {
424   struct AliceServiceSession *s = channel_ctx;
425
426   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
427               "Peer disconnected, terminating session %s with peer %s\n",
428               GNUNET_h2s (&s->session_id),
429               GNUNET_i2s (&s->peer));
430   if (NULL != s->cadet_mq)
431   {
432     GNUNET_MQ_destroy (s->cadet_mq);
433     s->cadet_mq = NULL;
434   }
435   s->channel = NULL;
436   if (GNUNET_SCALARPRODUCT_STATUS_ACTIVE == s->status)
437   {
438     /* We didn't get an answer yet, fail with error */
439     s->status = GNUNET_SCALARPRODUCT_STATUS_FAILURE;
440     prepare_client_end_notification (s);
441   }
442 }
443
444
445 /**
446  * Compute our scalar product, done by Alice
447  *
448  * @param session the session associated with this computation
449  * @param prod_g_i_b_i value from Bob
450  * @param prod_h_i_b_i value from Bob
451  * @return product as MPI, never NULL
452  */
453 static gcry_mpi_t
454 compute_scalar_product (struct AliceServiceSession *session,
455                         gcry_mpi_point_t prod_g_i_b_i,
456                         gcry_mpi_point_t prod_h_i_b_i)
457 {
458   gcry_mpi_point_t g_i_b_i_a_inv;
459   gcry_mpi_point_t g_ai_bi;
460   int ai_bi;
461   gcry_mpi_t ret;
462
463   g_i_b_i_a_inv = GNUNET_CRYPTO_ecc_pmul_mpi (edc,
464                                               prod_g_i_b_i,
465                                               my_privkey_inv);
466   g_ai_bi = GNUNET_CRYPTO_ecc_add (edc,
467                                    g_i_b_i_a_inv,
468                                    prod_h_i_b_i);
469   gcry_mpi_point_release (g_i_b_i_a_inv);
470   ai_bi = GNUNET_CRYPTO_ecc_dlog (edc,
471                                   g_ai_bi);
472   gcry_mpi_point_release (g_ai_bi);
473   if (MAX_RESULT == ai_bi)
474   {
475     /* result too big */
476     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
477                 "Scalar product result out of range\n");
478     return NULL;
479   }
480   ret = gcry_mpi_new (0);
481   if (ai_bi > 0)
482   {
483     gcry_mpi_set_ui (ret, ai_bi);
484   }
485   else
486   {
487     gcry_mpi_set_ui (ret, - ai_bi);
488     gcry_mpi_neg (ret, ret);
489   }
490   return ret;
491 }
492
493
494 /**
495  * Handle a response we got from another service we wanted to
496  * calculate a scalarproduct with.
497  *
498  * @param cls closure (set from #GNUNET_CADET_connect)
499  * @param channel connection to the other end
500  * @param channel_ctx place to store local state associated with the channel
501  * @param message the actual message
502  * @return #GNUNET_OK to keep the connection open,
503  *         #GNUNET_SYSERR to close it (we are done)
504  */
505 static int
506 handle_bobs_cryptodata_message (void *cls,
507                                 struct GNUNET_CADET_Channel *channel,
508                                 void **channel_ctx,
509                                 const struct GNUNET_MessageHeader *message)
510 {
511   struct AliceServiceSession *s = *channel_ctx;
512   const struct EccBobCryptodataMessage *msg;
513   uint32_t contained;
514   uint16_t msg_size;
515   gcry_mpi_point_t prod_g_i_b_i;
516   gcry_mpi_point_t prod_h_i_b_i;
517
518   if (NULL == s)
519   {
520     GNUNET_break_op (0);
521     return GNUNET_SYSERR;
522   }
523   msg_size = ntohs (message->size);
524   if (sizeof (struct EccBobCryptodataMessage) > msg_size)
525   {
526     GNUNET_break_op (0);
527     return GNUNET_SYSERR;
528   }
529   msg = (const struct EccBobCryptodataMessage *) message;
530   contained = ntohl (msg->contained_element_count);
531   if (2 != contained)
532   {
533     GNUNET_break_op (0);
534     return GNUNET_SYSERR;
535   }
536   if (NULL == s->sorted_elements)
537   {
538     /* we're not ready yet, how can Bob be? */
539     GNUNET_break_op (0);
540     return GNUNET_SYSERR;
541   }
542   if (s->total != s->client_received_element_count)
543   {
544     /* we're not ready yet, how can Bob be? */
545     GNUNET_break_op (0);
546     return GNUNET_SYSERR;
547   }
548   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
549               "Received %u crypto values from Bob\n",
550               (unsigned int) contained);
551   GNUNET_CADET_receive_done (s->channel);
552   prod_g_i_b_i = GNUNET_CRYPTO_ecc_bin_to_point (edc,
553                                                  &msg->prod_g_i_b_i);
554   prod_h_i_b_i = GNUNET_CRYPTO_ecc_bin_to_point (edc,
555                                                  &msg->prod_h_i_b_i);
556   s->product = compute_scalar_product (s,
557                                        prod_g_i_b_i,
558                                        prod_h_i_b_i);
559   gcry_mpi_point_release (prod_g_i_b_i);
560   gcry_mpi_point_release (prod_h_i_b_i);
561   transmit_client_response (s);
562   return GNUNET_OK;
563 }
564
565
566 /**
567  * Iterator to copy over messages from the hash map
568  * into an array for sorting.
569  *
570  * @param cls the `struct AliceServiceSession *`
571  * @param key the key (unused)
572  * @param value the `struct GNUNET_SCALARPRODUCT_Element *`
573  */
574 static int
575 copy_element_cb (void *cls,
576                  const struct GNUNET_HashCode *key,
577                  void *value)
578 {
579   struct AliceServiceSession *s = cls;
580   struct GNUNET_SCALARPRODUCT_Element *e = value;
581   gcry_mpi_t mval;
582   int64_t val;
583
584   mval = gcry_mpi_new (0);
585   val = (int64_t) GNUNET_ntohll (e->value);
586   if (0 > val)
587     gcry_mpi_sub_ui (mval, mval, -val);
588   else
589     gcry_mpi_add_ui (mval, mval, val);
590   s->sorted_elements [s->used_element_count].value = mval;
591   s->sorted_elements [s->used_element_count].key = &e->key;
592   s->used_element_count++;
593   return GNUNET_OK;
594 }
595
596
597 /**
598  * Compare two `struct MpiValue`s by key for sorting.
599  *
600  * @param a pointer to first `struct MpiValue *`
601  * @param b pointer to first `struct MpiValue *`
602  * @return -1 for a < b, 0 for a=b, 1 for a > b.
603  */
604 static int
605 element_cmp (const void *a,
606              const void *b)
607 {
608   const struct MpiElement *ma = a;
609   const struct MpiElement *mb = b;
610
611   return GNUNET_CRYPTO_hash_cmp (ma->key,
612                                  mb->key);
613 }
614
615
616 /**
617  * Maximum number of elements we can put into a single cryptodata
618  * message
619  */
620 #define ELEMENT_CAPACITY ((GNUNET_CONSTANTS_MAX_CADET_MESSAGE_SIZE - 1 - sizeof (struct EccAliceCryptodataMessage)) / sizeof (struct GNUNET_CRYPTO_EccPoint))
621
622
623 /**
624  * Send the cryptographic data from Alice to Bob.
625  * Does nothing if we already transferred all elements.
626  *
627  * @param s the associated service session
628  */
629 static void
630 send_alices_cryptodata_message (struct AliceServiceSession *s)
631 {
632   struct EccAliceCryptodataMessage *msg;
633   struct GNUNET_MQ_Envelope *e;
634   struct GNUNET_CRYPTO_EccPoint *payload;
635   gcry_mpi_t r_ia;
636   gcry_mpi_t r_ia_ai;
637   unsigned int i;
638   unsigned int off;
639   unsigned int todo_count;
640
641   s->sorted_elements
642     = GNUNET_malloc (GNUNET_CONTAINER_multihashmap_size (s->intersected_elements) *
643                      sizeof (struct MpiElement));
644   s->used_element_count = 0;
645   GNUNET_CONTAINER_multihashmap_iterate (s->intersected_elements,
646                                          &copy_element_cb,
647                                          s);
648   LOG (GNUNET_ERROR_TYPE_DEBUG,
649        "Finished intersection, %d items remain\n",
650        s->used_element_count);
651   qsort (s->sorted_elements,
652          s->used_element_count,
653          sizeof (struct MpiElement),
654          &element_cmp);
655   off = 0;
656   while (off < s->used_element_count)
657   {
658     todo_count = s->used_element_count - off;
659     if (todo_count > ELEMENT_CAPACITY)
660       todo_count = ELEMENT_CAPACITY;
661     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
662                 "Sending %u/%u crypto values to Bob\n",
663                 (unsigned int) todo_count,
664                 (unsigned int) s->used_element_count);
665
666     e = GNUNET_MQ_msg_extra (msg,
667                              todo_count * 2 * sizeof (struct GNUNET_CRYPTO_EccPoint),
668                              GNUNET_MESSAGE_TYPE_SCALARPRODUCT_ECC_ALICE_CRYPTODATA);
669     msg->contained_element_count = htonl (todo_count);
670     payload = (struct GNUNET_CRYPTO_EccPoint *) &msg[1];
671     r_ia = gcry_mpi_new (0);
672     r_ia_ai = gcry_mpi_new (0);
673     for (i = off; i < off + todo_count; i++)
674     {
675       gcry_mpi_t r_i;
676       gcry_mpi_point_t g_i;
677       gcry_mpi_point_t h_i;
678
679       r_i = GNUNET_CRYPTO_ecc_random_mod_n (edc);
680       g_i = GNUNET_CRYPTO_ecc_dexp_mpi (edc,
681                                         r_i);
682       /* r_ia = r_i * a */
683       gcry_mpi_mul (r_ia,
684                     r_i,
685                     my_privkey);
686       gcry_mpi_release (r_i);
687       /* r_ia_ai = r_ia + a_i */
688       gcry_mpi_add (r_ia_ai,
689                     r_ia,
690                     s->sorted_elements[i].value);
691       h_i = GNUNET_CRYPTO_ecc_dexp_mpi (edc,
692                                         r_ia_ai);
693       GNUNET_CRYPTO_ecc_point_to_bin (edc,
694                                       g_i,
695                                       &payload[(i - off) * 2]);
696       GNUNET_CRYPTO_ecc_point_to_bin (edc,
697                                       h_i,
698                                       &payload[(i - off) * 2 + 1]);
699       gcry_mpi_point_release (g_i);
700       gcry_mpi_point_release (h_i);
701     }
702     gcry_mpi_release (r_ia);
703     gcry_mpi_release (r_ia_ai);
704     off += todo_count;
705     GNUNET_MQ_send (s->cadet_mq,
706                     e);
707   }
708 }
709
710
711 /**
712  * Callback for set operation results. Called for each element
713  * that should be removed from the result set, and then once
714  * to indicate that the set intersection operation is done.
715  *
716  * @param cls closure with the `struct AliceServiceSession`
717  * @param element a result element, only valid if status is #GNUNET_SET_STATUS_OK
718  * @param status what has happened with the set intersection?
719  */
720 static void
721 cb_intersection_element_removed (void *cls,
722                                  const struct GNUNET_SET_Element *element,
723                                  enum GNUNET_SET_Status status)
724 {
725   struct AliceServiceSession *s = cls;
726   struct GNUNET_SCALARPRODUCT_Element *se;
727
728   switch (status)
729   {
730   case GNUNET_SET_STATUS_OK:
731     /* this element has been removed from the set */
732     se = GNUNET_CONTAINER_multihashmap_get (s->intersected_elements,
733                                             element->data);
734     GNUNET_assert (NULL != se);
735     LOG (GNUNET_ERROR_TYPE_DEBUG,
736          "Intersection removed element with key %s and value %lld\n",
737          GNUNET_h2s (&se->key),
738          (long long) GNUNET_ntohll (se->value));
739     GNUNET_assert (GNUNET_YES ==
740                    GNUNET_CONTAINER_multihashmap_remove (s->intersected_elements,
741                                                          element->data,
742                                                          se));
743     GNUNET_free (se);
744     return;
745   case GNUNET_SET_STATUS_DONE:
746     s->intersection_op = NULL;
747     if (NULL != s->intersection_set)
748     {
749       GNUNET_SET_destroy (s->intersection_set);
750       s->intersection_set = NULL;
751     }
752     send_alices_cryptodata_message (s);
753     return;
754   case GNUNET_SET_STATUS_HALF_DONE:
755     /* unexpected for intersection */
756     GNUNET_break (0);
757     return;
758   case GNUNET_SET_STATUS_FAILURE:
759     /* unhandled status code */
760     LOG (GNUNET_ERROR_TYPE_DEBUG,
761          "Set intersection failed!\n");
762     if (NULL != s->intersection_listen)
763     {
764       GNUNET_SET_listen_cancel (s->intersection_listen);
765       s->intersection_listen = NULL;
766     }
767     s->intersection_op = NULL;
768     if (NULL != s->intersection_set)
769     {
770       GNUNET_SET_destroy (s->intersection_set);
771       s->intersection_set = NULL;
772     }
773     s->status = GNUNET_SCALARPRODUCT_STATUS_FAILURE;
774     prepare_client_end_notification (s);
775     return;
776   default:
777     GNUNET_break (0);
778     return;
779   }
780 }
781
782
783 /**
784  * Called when another peer wants to do a set operation with the
785  * local peer. If a listen error occurs, the @a request is NULL.
786  *
787  * @param cls closure with the `struct AliceServiceSession *`
788  * @param other_peer the other peer
789  * @param context_msg message with application specific information from
790  *        the other peer
791  * @param request request from the other peer (never NULL), use GNUNET_SET_accept()
792  *        to accept it, otherwise the request will be refused
793  *        Note that we can't just return value from the listen callback,
794  *        as it is also necessary to specify the set we want to do the
795  *        operation with, whith sometimes can be derived from the context
796  *        message. It's necessary to specify the timeout.
797  */
798 static void
799 cb_intersection_request_alice (void *cls,
800                                const struct GNUNET_PeerIdentity *other_peer,
801                                const struct GNUNET_MessageHeader *context_msg,
802                                struct GNUNET_SET_Request *request)
803 {
804   struct AliceServiceSession *s = cls;
805
806   if (0 != memcmp (other_peer,
807                    &s->peer,
808                    sizeof (struct GNUNET_PeerIdentity)))
809   {
810     GNUNET_break_op (0);
811     return;
812   }
813   s->intersection_op
814     = GNUNET_SET_accept (request,
815                          GNUNET_SET_RESULT_REMOVED,
816                          &cb_intersection_element_removed,
817                          s);
818   if (NULL == s->intersection_op)
819   {
820     GNUNET_break (0);
821     s->status = GNUNET_SCALARPRODUCT_STATUS_FAILURE;
822     prepare_client_end_notification (s);
823     return;
824   }
825   if (GNUNET_OK !=
826       GNUNET_SET_commit (s->intersection_op,
827                          s->intersection_set))
828   {
829     GNUNET_break (0);
830     s->status = GNUNET_SCALARPRODUCT_STATUS_FAILURE;
831     prepare_client_end_notification (s);
832     return;
833   }
834   GNUNET_SET_destroy (s->intersection_set);
835   s->intersection_set = NULL;
836   GNUNET_SET_listen_cancel (s->intersection_listen);
837   s->intersection_listen = NULL;
838 }
839
840
841 /**
842  * Our client has finished sending us its multipart message.
843  *
844  * @param session the service session context
845  */
846 static void
847 client_request_complete_alice (struct AliceServiceSession *s)
848 {
849   struct EccServiceRequestMessage *msg;
850   struct GNUNET_MQ_Envelope *e;
851
852   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
853               "Creating new channel for session with key %s.\n",
854               GNUNET_h2s (&s->session_id));
855   s->channel
856     = GNUNET_CADET_channel_create (my_cadet,
857                                    s,
858                                    &s->peer,
859                                    GNUNET_APPLICATION_TYPE_SCALARPRODUCT_ECC,
860                                    GNUNET_CADET_OPTION_RELIABLE);
861   if (NULL == s->channel)
862   {
863     s->status = GNUNET_SCALARPRODUCT_STATUS_FAILURE;
864     prepare_client_end_notification (s);
865     return;
866   }
867   s->cadet_mq = GNUNET_CADET_mq_create (s->channel);
868   s->intersection_listen
869     = GNUNET_SET_listen (cfg,
870                          GNUNET_SET_OPERATION_INTERSECTION,
871                          &s->session_id,
872                          &cb_intersection_request_alice,
873                          s);
874   if (NULL == s->intersection_listen)
875   {
876     s->status = GNUNET_SCALARPRODUCT_STATUS_FAILURE;
877     GNUNET_CADET_channel_destroy (s->channel);
878     s->channel = NULL;
879     prepare_client_end_notification (s);
880     return;
881   }
882
883   e = GNUNET_MQ_msg (msg,
884                      GNUNET_MESSAGE_TYPE_SCALARPRODUCT_ECC_SESSION_INITIALIZATION);
885   msg->session_id = s->session_id;
886   GNUNET_MQ_send (s->cadet_mq,
887                   e);
888 }
889
890
891 /**
892  * We're receiving additional set data. Add it to our
893  * set and if we are done, initiate the transaction.
894  *
895  * @param cls closure
896  * @param client identification of the client
897  * @param message the actual message
898  */
899 static void
900 GSS_handle_alice_client_message_multipart (void *cls,
901                                            struct GNUNET_SERVER_Client *client,
902                                            const struct GNUNET_MessageHeader *message)
903 {
904   const struct ComputationBobCryptodataMultipartMessage * msg;
905   struct AliceServiceSession *s;
906   uint32_t contained_count;
907   const struct GNUNET_SCALARPRODUCT_Element *elements;
908   uint32_t i;
909   uint16_t msize;
910   struct GNUNET_SET_Element set_elem;
911   struct GNUNET_SCALARPRODUCT_Element *elem;
912
913   s = GNUNET_SERVER_client_get_user_context (client,
914                                              struct AliceServiceSession);
915   if (NULL == s)
916   {
917     /* session needs to already exist */
918     GNUNET_break (0);
919     GNUNET_SERVER_receive_done (client,
920                                 GNUNET_SYSERR);
921     return;
922   }
923   msize = ntohs (message->size);
924   if (msize < sizeof (struct ComputationBobCryptodataMultipartMessage))
925   {
926     GNUNET_break (0);
927     GNUNET_SERVER_receive_done (client,
928                                 GNUNET_SYSERR);
929     return;
930   }
931   msg = (const struct ComputationBobCryptodataMultipartMessage *) message;
932   contained_count = ntohl (msg->element_count_contained);
933
934   if ( (msize != (sizeof (struct ComputationBobCryptodataMultipartMessage) +
935                   contained_count * sizeof (struct GNUNET_SCALARPRODUCT_Element))) ||
936        (0 == contained_count) ||
937        (s->total == s->client_received_element_count) ||
938        (s->total < s->client_received_element_count + contained_count) )
939   {
940     GNUNET_break_op (0);
941     GNUNET_SERVER_receive_done (client,
942                                 GNUNET_SYSERR);
943     return;
944   }
945   s->client_received_element_count += contained_count;
946   elements = (const struct GNUNET_SCALARPRODUCT_Element *) &msg[1];
947   for (i = 0; i < contained_count; i++)
948   {
949     elem = GNUNET_new (struct GNUNET_SCALARPRODUCT_Element);
950     memcpy (elem,
951             &elements[i],
952             sizeof (struct GNUNET_SCALARPRODUCT_Element));
953     if (GNUNET_SYSERR ==
954         GNUNET_CONTAINER_multihashmap_put (s->intersected_elements,
955                                            &elem->key,
956                                            elem,
957                                            GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY))
958     {
959       GNUNET_break (0);
960       GNUNET_free (elem);
961       continue;
962     }
963     set_elem.data = &elem->key;
964     set_elem.size = sizeof (elem->key);
965     set_elem.element_type = 0;
966     GNUNET_SET_add_element (s->intersection_set,
967                             &set_elem,
968                             NULL, NULL);
969     s->used_element_count++;
970   }
971   GNUNET_SERVER_receive_done (client,
972                               GNUNET_OK);
973   if (s->total != s->client_received_element_count)
974   {
975     /* more to come */
976     return;
977   }
978   client_request_complete_alice (s);
979 }
980
981
982 /**
983  * Handler for Alice's client request message.
984  * We are doing request-initiation to compute a scalar product with a peer.
985  *
986  * @param cls closure
987  * @param client identification of the client
988  * @param message the actual message
989  */
990 static void
991 GSS_handle_alice_client_message (void *cls,
992                                  struct GNUNET_SERVER_Client *client,
993                                  const struct GNUNET_MessageHeader *message)
994 {
995   const struct AliceComputationMessage *msg;
996   struct AliceServiceSession *s;
997   uint32_t contained_count;
998   uint32_t total_count;
999   const struct GNUNET_SCALARPRODUCT_Element *elements;
1000   uint32_t i;
1001   uint16_t msize;
1002   struct GNUNET_SET_Element set_elem;
1003   struct GNUNET_SCALARPRODUCT_Element *elem;
1004
1005   s = GNUNET_SERVER_client_get_user_context (client,
1006                                              struct AliceServiceSession);
1007   if (NULL != s)
1008   {
1009     /* only one concurrent session per client connection allowed,
1010        simplifies logic a lot... */
1011     GNUNET_break (0);
1012     GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
1013     return;
1014   }
1015   msize = ntohs (message->size);
1016   if (msize < sizeof (struct AliceComputationMessage))
1017   {
1018     GNUNET_break (0);
1019     GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
1020     return;
1021   }
1022   msg = (const struct AliceComputationMessage *) message;
1023   total_count = ntohl (msg->element_count_total);
1024   contained_count = ntohl (msg->element_count_contained);
1025   if ( (0 == total_count) ||
1026        (0 == contained_count) ||
1027        (msize != (sizeof (struct AliceComputationMessage) +
1028                   contained_count * sizeof (struct GNUNET_SCALARPRODUCT_Element))) )
1029   {
1030     GNUNET_break_op (0);
1031     GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
1032     return;
1033   }
1034
1035   s = GNUNET_new (struct AliceServiceSession);
1036   s->peer = msg->peer;
1037   s->status = GNUNET_SCALARPRODUCT_STATUS_ACTIVE;
1038   s->client = client;
1039   s->client_mq = GNUNET_MQ_queue_for_server_client (client);
1040   s->total = total_count;
1041   s->client_received_element_count = contained_count;
1042   s->session_id = msg->session_key;
1043   elements = (const struct GNUNET_SCALARPRODUCT_Element *) &msg[1];
1044   s->intersected_elements = GNUNET_CONTAINER_multihashmap_create (s->total,
1045                                                                   GNUNET_YES);
1046   s->intersection_set = GNUNET_SET_create (cfg,
1047                                            GNUNET_SET_OPERATION_INTERSECTION);
1048   for (i = 0; i < contained_count; i++)
1049   {
1050     if (0 == GNUNET_ntohll (elements[i].value))
1051       continue;
1052     elem = GNUNET_new (struct GNUNET_SCALARPRODUCT_Element);
1053     memcpy (elem,
1054             &elements[i],
1055             sizeof (struct GNUNET_SCALARPRODUCT_Element));
1056     if (GNUNET_SYSERR ==
1057         GNUNET_CONTAINER_multihashmap_put (s->intersected_elements,
1058                                            &elem->key,
1059                                            elem,
1060                                            GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY))
1061     {
1062       /* element with same key encountered twice! */
1063       GNUNET_break (0);
1064       GNUNET_free (elem);
1065       continue;
1066     }
1067     set_elem.data = &elem->key;
1068     set_elem.size = sizeof (elem->key);
1069     set_elem.element_type = 0;
1070     GNUNET_SET_add_element (s->intersection_set,
1071                             &set_elem,
1072                             NULL, NULL);
1073     s->used_element_count++;
1074   }
1075   GNUNET_SERVER_client_set_user_context (client,
1076                                          s);
1077   GNUNET_SERVER_receive_done (client,
1078                               GNUNET_OK);
1079   if (s->total != s->client_received_element_count)
1080   {
1081     /* wait for multipart msg */
1082     return;
1083   }
1084   client_request_complete_alice (s);
1085 }
1086
1087
1088 /**
1089  * Task run during shutdown.
1090  *
1091  * @param cls unused
1092  * @param tc unused
1093  */
1094 static void
1095 shutdown_task (void *cls)
1096 {
1097   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1098               "Shutting down, initiating cleanup.\n");
1099   // FIXME: we have to cut our connections to CADET first!
1100   if (NULL != my_cadet)
1101   {
1102     GNUNET_CADET_disconnect (my_cadet);
1103     my_cadet = NULL;
1104   }
1105   if (NULL != edc)
1106   {
1107     GNUNET_CRYPTO_ecc_dlog_release (edc);
1108     edc = NULL;
1109   }
1110 }
1111
1112
1113 /**
1114  * A client disconnected.
1115  *
1116  * Remove the associated session(s), release data structures
1117  * and cancel pending outgoing transmissions to the client.
1118  *
1119  * @param cls closure, NULL
1120  * @param client identification of the client
1121  */
1122 static void
1123 handle_client_disconnect (void *cls,
1124                           struct GNUNET_SERVER_Client *client)
1125 {
1126   struct AliceServiceSession *s;
1127
1128   if (NULL == client)
1129     return;
1130   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1131               "Client %p disconnected from us.\n",
1132               client);
1133   s = GNUNET_SERVER_client_get_user_context (client,
1134                                              struct AliceServiceSession);
1135   if (NULL == s)
1136     return;
1137   s->client = NULL;
1138   GNUNET_SERVER_client_set_user_context (client,
1139                                          NULL);
1140   destroy_service_session (s);
1141 }
1142
1143
1144 /**
1145  * Initialization of the program and message handlers
1146  *
1147  * @param cls closure
1148  * @param server the initialized server
1149  * @param c configuration to use
1150  */
1151 static void
1152 run (void *cls,
1153      struct GNUNET_SERVER_Handle *server,
1154      const struct GNUNET_CONFIGURATION_Handle *c)
1155 {
1156   static const struct GNUNET_CADET_MessageHandler cadet_handlers[] = {
1157     { &handle_bobs_cryptodata_message,
1158       GNUNET_MESSAGE_TYPE_SCALARPRODUCT_ECC_BOB_CRYPTODATA,
1159       0},
1160     { NULL, 0, 0}
1161   };
1162   static const struct GNUNET_SERVER_MessageHandler server_handlers[] = {
1163     { &GSS_handle_alice_client_message, NULL,
1164       GNUNET_MESSAGE_TYPE_SCALARPRODUCT_CLIENT_TO_ALICE,
1165       0},
1166     { &GSS_handle_alice_client_message_multipart, NULL,
1167       GNUNET_MESSAGE_TYPE_SCALARPRODUCT_CLIENT_MUTLIPART_ALICE,
1168       0},
1169     { NULL, NULL, 0, 0}
1170   };
1171
1172   cfg = c;
1173   edc = GNUNET_CRYPTO_ecc_dlog_prepare (MAX_RESULT,
1174                                         MAX_RAM);
1175   /* Select a random 'a' value for Alice */
1176   GNUNET_CRYPTO_ecc_rnd_mpi (edc,
1177                              &my_privkey,
1178                              &my_privkey_inv);
1179   GNUNET_SERVER_add_handlers (server,
1180                               server_handlers);
1181   GNUNET_SERVER_disconnect_notify (server,
1182                                    &handle_client_disconnect,
1183                                    NULL);
1184   my_cadet = GNUNET_CADET_connect (cfg, NULL,
1185                                    NULL /* no incoming supported */,
1186                                    &cb_channel_destruction,
1187                                    cadet_handlers,
1188                                    NULL);
1189   if (NULL == my_cadet)
1190   {
1191     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1192                 _("Connect to CADET failed\n"));
1193     GNUNET_SCHEDULER_shutdown ();
1194     return;
1195   }
1196   GNUNET_SCHEDULER_add_shutdown (&shutdown_task,
1197                                  NULL);
1198
1199 }
1200
1201
1202 /**
1203  * The main function for the scalarproduct service.
1204  *
1205  * @param argc number of arguments from the command line
1206  * @param argv command line arguments
1207  * @return 0 ok, 1 on error
1208  */
1209 int
1210 main (int argc,
1211       char *const *argv)
1212 {
1213   return (GNUNET_OK ==
1214           GNUNET_SERVICE_run (argc, argv,
1215                               "scalarproduct-alice",
1216                               GNUNET_SERVICE_OPTION_NONE,
1217                               &run, NULL)) ? 0 : 1;
1218 }
1219
1220 /* end of gnunet-service-scalarproduct-ecc_alice.c */