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