Merge branch 'master' of git+ssh://gnunet.org/gnunet
[oweals/gnunet.git] / src / scalarproduct / gnunet-service-scalarproduct-ecc_bob.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_bob.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-bob", __VA_ARGS__)
40
41
42 /**
43  * An encrypted element key-value pair.
44  */
45 struct MpiElement
46 {
47   /**
48    * Key used to identify matching pairs of values to multiply.
49    * Points into an existing data structure, to avoid copying
50    * and doubling memory use.
51    */
52   const struct GNUNET_HashCode *key;
53
54   /**
55    * Value represented (a).
56    */
57   gcry_mpi_t value;
58 };
59
60
61 /**
62  * An incoming session from CADET.
63  */
64 struct CadetIncomingSession;
65
66
67 /**
68  * A scalarproduct session which tracks an offer for a
69  * multiplication service by a local client.
70  */
71 struct BobServiceSession
72 {
73
74   /**
75    * (hopefully) unique transaction ID
76    */
77   struct GNUNET_HashCode session_id;
78
79   /**
80    * The client this request is related to.
81    */
82   struct GNUNET_SERVICE_Client *client;
83
84   /**
85    * Client message queue.
86    */
87   struct GNUNET_MQ_Handle *client_mq;
88
89   /**
90    * All non-0-value'd elements transmitted to us.
91    */
92   struct GNUNET_CONTAINER_MultiHashMap *intersected_elements;
93
94   /**
95    * Set of elements for which we will be conducting an intersection.
96    * The resulting elements are then used for computing the scalar product.
97    */
98   struct GNUNET_SET_Handle *intersection_set;
99
100   /**
101    * Set of elements for which will conduction an intersection.
102    * the resulting elements are then used for computing the scalar product.
103    */
104   struct GNUNET_SET_OperationHandle *intersection_op;
105
106   /**
107    * Our open port.
108    */
109   struct GNUNET_CADET_Port *port;
110
111   /**
112    * b(Bob)
113    */
114   struct MpiElement *sorted_elements;
115
116   /**
117    * Product of the g_i^{b_i}
118    */
119   gcry_mpi_point_t prod_g_i_b_i;
120
121   /**
122    * Product of the h_i^{b_i}
123    */
124   gcry_mpi_point_t prod_h_i_b_i;
125
126   /**
127    * Handle for our associated incoming CADET session, or NULL
128    * if we have not gotten one yet.
129    */
130   struct CadetIncomingSession *cadet;
131
132   /**
133    * How many elements will be supplied in total from the client.
134    */
135   uint32_t total;
136
137   /**
138    * Already transferred elements (received) for multipart
139    * messages from client. Always less than @e total.
140    */
141   uint32_t client_received_element_count;
142
143   /**
144    * How many elements actually are used for the scalar product.
145    * Size of the arrays in @e r and @e r_prime.  Also sometimes
146    * used as an index into the arrays during construction.
147    */
148   uint32_t used_element_count;
149
150   /**
151    * Counts the number of values received from Alice by us.
152    * Always less than @e used_element_count.
153    */
154   uint32_t cadet_received_element_count;
155
156   /**
157    * State of this session.   In
158    * #GNUNET_SCALARPRODUCT_STATUS_ACTIVE while operation is
159    * ongoing, afterwards in #GNUNET_SCALARPRODUCT_STATUS_SUCCESS or
160    * #GNUNET_SCALARPRODUCT_STATUS_FAILURE.
161    */
162   enum GNUNET_SCALARPRODUCT_ResponseStatus status;
163
164   /**
165    * Are we already in #destroy_service_session()?
166    */
167   int in_destroy;
168
169 };
170
171
172 /**
173  * An incoming session from CADET.
174  */
175 struct CadetIncomingSession
176 {
177
178   /**
179    * Associated client session, or NULL.
180    */
181   struct BobServiceSession *s;
182
183   /**
184    * The CADET channel.
185    */
186   struct GNUNET_CADET_Channel *channel;
187
188   /**
189    * Originator's peer identity. (Only for diagnostics.)
190    */
191   struct GNUNET_PeerIdentity peer;
192
193   /**
194    * (hopefully) unique transaction ID
195    */
196   struct GNUNET_HashCode session_id;
197
198   /**
199    * The message queue for this channel.
200    */
201   struct GNUNET_MQ_Handle *cadet_mq;
202
203   /**
204    * Has this CADET session been added to the map yet?
205    * #GNUNET_YES if so, in which case @e session_id is
206    * the key.
207    */
208   int in_map;
209
210   /**
211    * Are we already in #destroy_cadet_session()?
212    */
213   int in_destroy;
214
215 };
216
217
218 /**
219  * GNUnet configuration handle
220  */
221 static const struct GNUNET_CONFIGURATION_Handle *cfg;
222
223 /**
224  * Map of `struct BobServiceSession`, by session keys.
225  */
226 static struct GNUNET_CONTAINER_MultiHashMap *client_sessions;
227
228 /**
229  * Map of `struct CadetIncomingSession`, by session keys.
230  */
231 static struct GNUNET_CONTAINER_MultiHashMap *cadet_sessions;
232
233 /**
234  * Handle to the CADET service.
235  */
236 static struct GNUNET_CADET_Handle *my_cadet;
237
238 /**
239  * Context for DLOG operations on a curve.
240  */
241 static struct GNUNET_CRYPTO_EccDlogContext *edc;
242
243
244 /**
245  * Finds a not terminated client session in the respective map based on
246  * session key.
247  *
248  * @param key the session key we want to search for
249  * @return the matching session, or NULL for none
250  */
251 static struct BobServiceSession *
252 find_matching_client_session (const struct GNUNET_HashCode *key)
253 {
254   return GNUNET_CONTAINER_multihashmap_get (client_sessions,
255                                             key);
256 }
257
258
259 /**
260  * Finds a CADET session in the respective map based on session key.
261  *
262  * @param key the session key we want to search for
263  * @return the matching session, or NULL for none
264  */
265 static struct CadetIncomingSession *
266 find_matching_cadet_session (const struct GNUNET_HashCode *key)
267 {
268   return GNUNET_CONTAINER_multihashmap_get (cadet_sessions,
269                                             key);
270 }
271
272
273 /**
274  * Callback used to free the elements in the map.
275  *
276  * @param cls NULL
277  * @param key key of the element
278  * @param value the value to free
279  */
280 static int
281 free_element_cb (void *cls,
282                  const struct GNUNET_HashCode *key,
283                  void *value)
284 {
285   struct GNUNET_SCALARPRODUCT_Element *element = value;
286
287   GNUNET_free (element);
288   return GNUNET_OK;
289 }
290
291
292 /**
293  * Destroy session state, we are done with it.
294  *
295  * @param session the session to free elements from
296  */
297 static void
298 destroy_cadet_session (struct CadetIncomingSession *s);
299
300
301 /**
302  * Destroy session state, we are done with it.
303  *
304  * @param session the session to free elements from
305  */
306 static void
307 destroy_service_session (struct BobServiceSession *s)
308 {
309   struct CadetIncomingSession *in;
310   unsigned int i;
311
312   if (GNUNET_YES == s->in_destroy)
313     return;
314   s->in_destroy = GNUNET_YES;
315   if (NULL != (in = s->cadet))
316   {
317     s->cadet = NULL;
318     destroy_cadet_session (in);
319   }
320   if (NULL != s->client)
321   {
322     struct GNUNET_SERVICE_Client *c = s->client;
323     
324     s->client = NULL;
325     GNUNET_SERVICE_client_drop (c);
326   }
327   GNUNET_assert (GNUNET_YES ==
328                  GNUNET_CONTAINER_multihashmap_remove (client_sessions,
329                                                        &s->session_id,
330                                                        s));
331   if (NULL != s->intersected_elements)
332   {
333     GNUNET_CONTAINER_multihashmap_iterate (s->intersected_elements,
334                                            &free_element_cb,
335                                            NULL);
336     GNUNET_CONTAINER_multihashmap_destroy (s->intersected_elements);
337     s->intersected_elements = NULL;
338   }
339   if (NULL != s->intersection_op)
340   {
341     GNUNET_SET_operation_cancel (s->intersection_op);
342     s->intersection_op = NULL;
343   }
344   if (NULL != s->intersection_set)
345   {
346     GNUNET_SET_destroy (s->intersection_set);
347     s->intersection_set = NULL;
348   }
349   if (NULL != s->sorted_elements)
350   {
351     for (i=0;i<s->used_element_count;i++)
352       gcry_mpi_release (s->sorted_elements[i].value);
353     GNUNET_free (s->sorted_elements);
354     s->sorted_elements = NULL;
355   }
356   if (NULL != s->prod_g_i_b_i)
357   {
358     gcry_mpi_point_release (s->prod_g_i_b_i);
359     s->prod_g_i_b_i = NULL;
360   }
361   if (NULL != s->prod_h_i_b_i)
362   {
363     gcry_mpi_point_release (s->prod_h_i_b_i);
364     s->prod_h_i_b_i = NULL;
365   }
366   GNUNET_CADET_close_port (s->port);
367   GNUNET_free (s);
368 }
369
370
371 /**
372  * Destroy incoming CADET session state, we are done with it.
373  *
374  * @param in the session to free elements from
375  */
376 static void
377 destroy_cadet_session (struct CadetIncomingSession *in)
378 {
379   struct BobServiceSession *s;
380
381   if (GNUNET_YES == in->in_destroy)
382     return;
383   in->in_destroy = GNUNET_YES;
384   if (NULL != (s = in->s))
385   {
386     in->s = NULL;
387     destroy_service_session (s);
388   }
389   if (GNUNET_YES == in->in_map)
390   {
391     GNUNET_assert (GNUNET_YES ==
392                    GNUNET_CONTAINER_multihashmap_remove (cadet_sessions,
393                                                          &in->session_id,
394                                                          in));
395     in->in_map = GNUNET_NO;
396   }
397   if (NULL != in->cadet_mq)
398   {
399     GNUNET_MQ_destroy (in->cadet_mq);
400     in->cadet_mq = NULL;
401   }
402   if (NULL != in->channel)
403   {
404     GNUNET_CADET_channel_destroy (in->channel);
405     in->channel = NULL;
406   }
407   GNUNET_free (in);
408 }
409
410
411 /**
412  * Notify the client that the session has succeeded or failed.  This
413  * message gets sent to Bob's client if the operation completed or
414  * Alice disconnected.
415  *
416  * @param session the associated client session to fail or succeed
417  */
418 static void
419 prepare_client_end_notification (struct BobServiceSession *session)
420 {
421   struct ClientResponseMessage *msg;
422   struct GNUNET_MQ_Envelope *e;
423
424   if (NULL == session->client_mq)
425     return; /* no client left to be notified */
426   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
427               "Sending session-end notification with status %d to client for session %s\n",
428               session->status,
429               GNUNET_h2s (&session->session_id));
430   e = GNUNET_MQ_msg (msg,
431                      GNUNET_MESSAGE_TYPE_SCALARPRODUCT_RESULT);
432   msg->range = 0;
433   msg->product_length = htonl (0);
434   msg->status = htonl (session->status);
435   GNUNET_MQ_send (session->client_mq,
436                   e);
437 }
438
439
440 /**
441  * Function called whenever a channel is destroyed.  Should clean up
442  * any associated state.
443  *
444  * It must NOT call #GNUNET_CADET_channel_destroy() on the channel.
445  *
446  * @param cls closure (set from #GNUNET_CADET_connect())
447  * @param channel connection to the other end (henceforth invalid)
448  * @param channel_ctx place where local state associated
449  *                   with the channel is stored
450  */
451 static void
452 cb_channel_destruction (void *cls,
453                         const struct GNUNET_CADET_Channel *channel,
454                         void *channel_ctx)
455 {
456   struct CadetIncomingSession *in = channel_ctx;
457   struct BobServiceSession *s;
458
459   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
460               "Peer disconnected, terminating session %s with peer %s\n",
461               GNUNET_h2s (&in->session_id),
462               GNUNET_i2s (&in->peer));
463   if (NULL != in->cadet_mq)
464   {
465     GNUNET_MQ_destroy (in->cadet_mq);
466     in->cadet_mq = NULL;
467   }
468   in->channel = NULL;
469   if (NULL != (s = in->s))
470   {
471     if (GNUNET_SCALARPRODUCT_STATUS_ACTIVE == s->status)
472     {
473       s->status = GNUNET_SCALARPRODUCT_STATUS_FAILURE;
474       prepare_client_end_notification (s);
475     }
476   }
477   destroy_cadet_session (in);
478 }
479
480
481 /**
482  * MQ finished giving our last message to CADET, now notify
483  * the client that we are finished.
484  */
485 static void
486 bob_cadet_done_cb (void *cls)
487 {
488   struct BobServiceSession *session = cls;
489
490   session->status = GNUNET_SCALARPRODUCT_STATUS_SUCCESS;
491   prepare_client_end_notification (session);
492 }
493
494
495 /**
496  * Bob generates the response message to be sent to Alice.
497  *
498  * @param s the associated requesting session with Alice
499  */
500 static void
501 transmit_bobs_cryptodata_message (struct BobServiceSession *s)
502 {
503   struct EccBobCryptodataMessage *msg;
504   struct GNUNET_MQ_Envelope *e;
505
506   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
507               "Sending response to Alice\n");
508   e = GNUNET_MQ_msg (msg,
509                      GNUNET_MESSAGE_TYPE_SCALARPRODUCT_ECC_BOB_CRYPTODATA);
510   msg->contained_element_count = htonl (2);
511   if (NULL != s->prod_g_i_b_i)
512     GNUNET_CRYPTO_ecc_point_to_bin (edc,
513                                     s->prod_g_i_b_i,
514                                     &msg->prod_g_i_b_i);
515   if (NULL != s->prod_h_i_b_i)
516     GNUNET_CRYPTO_ecc_point_to_bin (edc,
517                                     s->prod_h_i_b_i,
518                                     &msg->prod_h_i_b_i);
519   GNUNET_MQ_notify_sent (e,
520                          &bob_cadet_done_cb,
521                          s);
522   GNUNET_MQ_send (s->cadet->cadet_mq,
523                   e);
524 }
525
526
527 /**
528  * Iterator to copy over messages from the hash map
529  * into an array for sorting.
530  *
531  * @param cls the `struct BobServiceSession *`
532  * @param key the key (unused)
533  * @param value the `struct GNUNET_SCALARPRODUCT_Element *`
534  * TODO: code duplication with Alice!
535  */
536 static int
537 copy_element_cb (void *cls,
538                  const struct GNUNET_HashCode *key,
539                  void *value)
540 {
541   struct BobServiceSession *s = cls;
542   struct GNUNET_SCALARPRODUCT_Element *e = value;
543   gcry_mpi_t mval;
544   int64_t val;
545
546   mval = gcry_mpi_new (0);
547   val = (int64_t) GNUNET_ntohll (e->value);
548   if (0 > val)
549     gcry_mpi_sub_ui (mval, mval, -val);
550   else
551     gcry_mpi_add_ui (mval, mval, val);
552   s->sorted_elements [s->used_element_count].value = mval;
553   s->sorted_elements [s->used_element_count].key = &e->key;
554   s->used_element_count++;
555   return GNUNET_OK;
556 }
557
558
559 /**
560  * Compare two `struct MpiValue`s by key for sorting.
561  *
562  * @param a pointer to first `struct MpiValue *`
563  * @param b pointer to first `struct MpiValue *`
564  * @return -1 for a < b, 0 for a=b, 1 for a > b.
565  * TODO: code duplication with Alice!
566  */
567 static int
568 element_cmp (const void *a,
569              const void *b)
570 {
571   const struct MpiElement *ma = a;
572   const struct MpiElement *mb = b;
573
574   return GNUNET_CRYPTO_hash_cmp (ma->key,
575                                  mb->key);
576 }
577
578
579 /**
580  * Handle a multipart-chunk of a request from another service to
581  * calculate a scalarproduct with us.
582  *
583  * @param cls closure (set from #GNUNET_CADET_connect)
584  * @param channel connection to the other end
585  * @param channel_ctx place to store local state associated with the @a channel
586  * @param message the actual message
587  * @return #GNUNET_OK to keep the connection open,
588  *         #GNUNET_SYSERR to close it (signal serious error)
589  */
590 static int
591 handle_alices_cryptodata_message (void *cls,
592                                   struct GNUNET_CADET_Channel *channel,
593                                   void **channel_ctx,
594                                   const struct GNUNET_MessageHeader *message)
595 {
596   struct CadetIncomingSession *in = *channel_ctx;
597   struct BobServiceSession *s;
598   const struct EccAliceCryptodataMessage *msg;
599   const struct GNUNET_CRYPTO_EccPoint *payload;
600   uint32_t contained_elements;
601   size_t msg_length;
602   uint16_t msize;
603   unsigned int max;
604   unsigned int i;
605   const struct MpiElement *b_i;
606   gcry_mpi_point_t tmp;
607   gcry_mpi_point_t g_i;
608   gcry_mpi_point_t h_i;
609   gcry_mpi_point_t g_i_b_i;
610   gcry_mpi_point_t h_i_b_i;
611
612   /* sanity checks */
613   if (NULL == in)
614   {
615     GNUNET_break_op (0);
616     return GNUNET_SYSERR;
617   }
618   s = in->s;
619   if (NULL == s)
620   {
621     GNUNET_break_op (0);
622     return GNUNET_SYSERR;
623   }
624   /* sort our vector for the computation */
625   if (NULL == s->sorted_elements)
626   {
627     s->sorted_elements
628       = GNUNET_malloc (GNUNET_CONTAINER_multihashmap_size (s->intersected_elements) *
629                        sizeof (struct MpiElement));
630     s->used_element_count = 0;
631     GNUNET_CONTAINER_multihashmap_iterate (s->intersected_elements,
632                                            &copy_element_cb,
633                                            s);
634     qsort (s->sorted_elements,
635            s->used_element_count,
636            sizeof (struct MpiElement),
637            &element_cmp);
638   }
639
640   /* parse message */
641   msize = ntohs (message->size);
642   if (msize <= sizeof (struct EccAliceCryptodataMessage))
643   {
644     GNUNET_break_op (0);
645     return GNUNET_SYSERR;
646   }
647   msg = (const struct EccAliceCryptodataMessage *) message;
648   contained_elements = ntohl (msg->contained_element_count);
649   /* Our intersection may still be ongoing, but this is nevertheless
650      an upper bound on the required array size */
651   max = GNUNET_CONTAINER_multihashmap_size (s->intersected_elements);
652   msg_length = sizeof (struct EccAliceCryptodataMessage)
653     + contained_elements * sizeof (struct GNUNET_CRYPTO_EccPoint) * 2;
654   if ( (msize != msg_length) ||
655        (0 == contained_elements) ||
656        (contained_elements > UINT16_MAX) ||
657        (max < contained_elements + s->cadet_received_element_count) )
658   {
659     GNUNET_break_op (0);
660     return GNUNET_SYSERR;
661   }
662   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
663               "Received %u crypto values from Alice\n",
664               (unsigned int) contained_elements);
665   payload = (const struct GNUNET_CRYPTO_EccPoint *) &msg[1];
666
667   for (i=0;i<contained_elements;i++)
668   {
669     b_i = &s->sorted_elements[i + s->cadet_received_element_count];
670     g_i = GNUNET_CRYPTO_ecc_bin_to_point (edc,
671                                           &payload[i * 2]);
672     g_i_b_i = GNUNET_CRYPTO_ecc_pmul_mpi (edc,
673                                           g_i,
674                                           b_i->value);
675     gcry_mpi_point_release (g_i);
676     h_i = GNUNET_CRYPTO_ecc_bin_to_point (edc,
677                                           &payload[i * 2 + 1]);
678     h_i_b_i = GNUNET_CRYPTO_ecc_pmul_mpi (edc,
679                                           h_i,
680                                           b_i->value);
681     gcry_mpi_point_release (h_i);
682     if (0 == i + s->cadet_received_element_count)
683     {
684       /* first iteration, nothing to add */
685       s->prod_g_i_b_i = g_i_b_i;
686       s->prod_h_i_b_i = h_i_b_i;
687     }
688     else
689     {
690       /* further iterations, cummulate resulting value */
691       tmp = GNUNET_CRYPTO_ecc_add (edc,
692                                    s->prod_g_i_b_i,
693                                    g_i_b_i);
694       gcry_mpi_point_release (s->prod_g_i_b_i);
695       gcry_mpi_point_release (g_i_b_i);
696       s->prod_g_i_b_i = tmp;
697       tmp = GNUNET_CRYPTO_ecc_add (edc,
698                                    s->prod_h_i_b_i,
699                                    h_i_b_i);
700       gcry_mpi_point_release (s->prod_h_i_b_i);
701       gcry_mpi_point_release (h_i_b_i);
702       s->prod_h_i_b_i = tmp;
703     }
704   }
705   s->cadet_received_element_count += contained_elements;
706   if ( (s->cadet_received_element_count == max) &&
707        (NULL == s->intersection_op) )
708   {
709     /* intersection has finished also on our side, and
710        we got the full set, so we can proceed with the
711        CADET response(s) */
712     transmit_bobs_cryptodata_message (s);
713   }
714   GNUNET_CADET_receive_done (s->cadet->channel);
715   return GNUNET_OK;
716 }
717
718
719 /**
720  * Callback for set operation results. Called for each element
721  * that needs to be removed from the result set.
722  *
723  * @param cls closure with the `struct BobServiceSession`
724  * @param element a result element, only valid if status is #GNUNET_SET_STATUS_OK
725  * @param status what has happened with the set intersection?
726  */
727 static void
728 cb_intersection_element_removed (void *cls,
729                                  const struct GNUNET_SET_Element *element,
730                                  enum GNUNET_SET_Status status)
731 {
732   struct BobServiceSession *s = cls;
733   struct GNUNET_SCALARPRODUCT_Element *se;
734
735   switch (status)
736   {
737   case GNUNET_SET_STATUS_OK:
738     /* this element has been removed from the set */
739     se = GNUNET_CONTAINER_multihashmap_get (s->intersected_elements,
740                                             element->data);
741     GNUNET_assert (NULL != se);
742     LOG (GNUNET_ERROR_TYPE_DEBUG,
743          "Removed element with key %s and value %lld\n",
744          GNUNET_h2s (&se->key),
745          (long long) GNUNET_ntohll (se->value));
746     GNUNET_assert (GNUNET_YES ==
747                    GNUNET_CONTAINER_multihashmap_remove (s->intersected_elements,
748                                                          element->data,
749                                                          se));
750     GNUNET_free (se);
751     return;
752   case GNUNET_SET_STATUS_DONE:
753     s->intersection_op = NULL;
754     GNUNET_break (NULL == s->intersection_set);
755     GNUNET_CADET_receive_done (s->cadet->channel);
756     LOG (GNUNET_ERROR_TYPE_DEBUG,
757          "Finished intersection, %d items remain\n",
758          GNUNET_CONTAINER_multihashmap_size (s->intersected_elements));
759     if (s->client_received_element_count ==
760         GNUNET_CONTAINER_multihashmap_size (s->intersected_elements))
761     {
762       /* CADET transmission from Alice is also already done,
763          start with our own reply */
764       transmit_bobs_cryptodata_message (s);
765     }
766     return;
767   case GNUNET_SET_STATUS_HALF_DONE:
768     /* unexpected for intersection */
769     GNUNET_break (0);
770     return;
771   case GNUNET_SET_STATUS_FAILURE:
772     /* unhandled status code */
773     LOG (GNUNET_ERROR_TYPE_DEBUG,
774          "Set intersection failed!\n");
775     s->intersection_op = NULL;
776     if (NULL != s->intersection_set)
777     {
778       GNUNET_SET_destroy (s->intersection_set);
779       s->intersection_set = NULL;
780     }
781     s->status = GNUNET_SCALARPRODUCT_STATUS_FAILURE;
782     prepare_client_end_notification (s);
783     return;
784   default:
785     GNUNET_break (0);
786     return;
787   }
788 }
789
790
791 /**
792  * We've paired up a client session with an incoming CADET request.
793  * Initiate set intersection work.
794  *
795  * @param s client session to start intersection for
796  */
797 static void
798 start_intersection (struct BobServiceSession *s)
799 {
800   struct GNUNET_HashCode set_sid;
801
802   GNUNET_CRYPTO_hash (&s->session_id,
803                       sizeof (struct GNUNET_HashCode),
804                       &set_sid);
805   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
806               "Got session with key %s and %u elements, starting intersection.\n",
807               GNUNET_h2s (&s->session_id),
808               (unsigned int) s->total);
809
810   s->intersection_op
811     = GNUNET_SET_prepare (&s->cadet->peer,
812                           &set_sid,
813                           NULL,
814                           GNUNET_SET_RESULT_REMOVED,
815                           &cb_intersection_element_removed,
816                           s);
817   if (GNUNET_OK !=
818       GNUNET_SET_commit (s->intersection_op,
819                          s->intersection_set))
820   {
821     GNUNET_break (0);
822     s->status = GNUNET_SCALARPRODUCT_STATUS_FAILURE;
823     prepare_client_end_notification (s);
824     return;
825   }
826   GNUNET_SET_destroy (s->intersection_set);
827   s->intersection_set = NULL;
828 }
829
830
831 /**
832  * Handle a request from Alice to calculate a scalarproduct with us (Bob).
833  *
834  * @param cls closure (set from #GNUNET_CADET_connect)
835  * @param channel connection to the other end
836  * @param channel_ctx place to store the `struct CadetIncomingSession *`
837  * @param message the actual message
838  * @return #GNUNET_OK to keep the connection open,
839  *         #GNUNET_SYSERR to close it (signal serious error)
840  */
841 static int
842 handle_alices_computation_request (void *cls,
843                                    struct GNUNET_CADET_Channel *channel,
844                                    void **channel_ctx,
845                                    const struct GNUNET_MessageHeader *message)
846 {
847   struct CadetIncomingSession *in = *channel_ctx;
848   struct BobServiceSession *s;
849   const struct EccServiceRequestMessage *msg;
850
851   msg = (const struct EccServiceRequestMessage *) message;
852   if (GNUNET_YES == in->in_map)
853   {
854     GNUNET_break_op (0);
855     return GNUNET_SYSERR;
856   }
857   if (NULL != find_matching_cadet_session (&msg->session_id))
858   {
859     /* not unique, got one like this already */
860     GNUNET_break_op (0);
861     return GNUNET_SYSERR;
862   }
863   in->session_id = msg->session_id;
864   GNUNET_assert (GNUNET_YES ==
865                  GNUNET_CONTAINER_multihashmap_put (cadet_sessions,
866                                                     &in->session_id,
867                                                     in,
868                                                     GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY));
869   s = find_matching_client_session (&in->session_id);
870   if (NULL == s)
871   {
872     /* no client waiting for this request, wait for client */
873     return GNUNET_OK;
874   }
875   GNUNET_assert (NULL == s->cadet);
876   /* pair them up */
877   in->s = s;
878   s->cadet = in;
879   if (s->client_received_element_count == s->total)
880     start_intersection (s);
881   return GNUNET_OK;
882 }
883
884
885 /**
886  * Function called for inbound channels on Bob's end.  Does some
887  * preliminary initialization, more happens after we get Alice's first
888  * message.
889  *
890  * @param cls closure
891  * @param channel new handle to the channel
892  * @param initiator peer that started the channel
893  * @param port unused
894  * @param options unused
895  * @return session associated with the channel
896  */
897 static void *
898 cb_channel_incoming (void *cls,
899                      struct GNUNET_CADET_Channel *channel,
900                      const struct GNUNET_PeerIdentity *initiator,
901                      const struct GNUNET_HashCode *port,
902                      enum GNUNET_CADET_ChannelOption options)
903 {
904   struct CadetIncomingSession *in;
905
906   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
907               "New incoming channel from peer %s.\n",
908               GNUNET_i2s (initiator));
909   in = GNUNET_new (struct CadetIncomingSession);
910   in->peer = *initiator;
911   in->channel = channel;
912   in->cadet_mq = GNUNET_CADET_mq_create (in->channel);
913   return in;
914 }
915
916
917 /**
918  * We're receiving additional set data. Check it is well-formed.
919  *
920  * @param cls identification of the client
921  * @param msg the actual message
922  * @return #GNUNET_OK if @a msg is well-formed
923  */
924 static int
925 check_bob_client_message_multipart (void *cls,
926                                     const struct ComputationBobCryptodataMultipartMessage *msg)
927 {
928   struct BobServiceSession *s = cls;
929   uint32_t contained_count;
930   uint16_t msize;
931
932   msize = ntohs (msg->header.size);
933   contained_count = ntohl (msg->element_count_contained);
934   if ( (msize != (sizeof (struct ComputationBobCryptodataMultipartMessage) +
935                   contained_count * sizeof (struct GNUNET_SCALARPRODUCT_Element))) ||
936        (0 == contained_count) ||
937        (UINT16_MAX < contained_count) ||
938        (s->total == s->client_received_element_count) ||
939        (s->total < s->client_received_element_count + contained_count) )
940   {
941     GNUNET_break (0);
942     return GNUNET_SYSERR;
943   }
944   return GNUNET_OK;
945 }
946
947
948 /**
949  * We're receiving additional set data. Add it to our
950  * set and if we are done, initiate the transaction.
951  *
952  * @param cls identification of the client
953  * @param msg the actual message
954  */
955 static void
956 handle_bob_client_message_multipart (void *cls,
957                                      const struct ComputationBobCryptodataMultipartMessage *msg)
958 {
959   struct BobServiceSession *s = cls;
960   uint32_t contained_count;
961   const struct GNUNET_SCALARPRODUCT_Element *elements;
962   struct GNUNET_SET_Element set_elem;
963   struct GNUNET_SCALARPRODUCT_Element *elem;
964
965   contained_count = ntohl (msg->element_count_contained);
966   elements = (const struct GNUNET_SCALARPRODUCT_Element *) &msg[1];
967   for (uint32_t i = 0; i < contained_count; i++)
968   {
969     elem = GNUNET_new (struct GNUNET_SCALARPRODUCT_Element);
970     GNUNET_memcpy (elem,
971                    &elements[i],
972                    sizeof (struct GNUNET_SCALARPRODUCT_Element));
973     if (GNUNET_SYSERR ==
974         GNUNET_CONTAINER_multihashmap_put (s->intersected_elements,
975                                            &elem->key,
976                                            elem,
977                                            GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY))
978     {
979       GNUNET_break (0);
980       GNUNET_free (elem);
981       continue;
982     }
983     set_elem.data = &elem->key;
984     set_elem.size = sizeof (elem->key);
985     set_elem.element_type = 0;
986     GNUNET_SET_add_element (s->intersection_set,
987                             &set_elem,
988                             NULL, NULL);
989   }
990   s->client_received_element_count += contained_count;
991   GNUNET_SERVICE_client_continue (s->client);
992   if (s->total != s->client_received_element_count)
993   {
994     /* more to come */
995     return;
996   }
997   if (NULL == s->cadet)
998   {
999     /* no Alice waiting for this request, wait for Alice */
1000     return;
1001   }
1002   start_intersection (s);
1003 }
1004
1005
1006 /**
1007  * Handler for Bob's a client request message.  Check @a msg is
1008  * well-formed.
1009  *
1010  * @param cls identification of the client
1011  * @param msg the actual message
1012  * @return #GNUNET_OK if @a msg is well-formed
1013  */
1014 static int
1015 check_bob_client_message (void *cls,
1016                           const struct BobComputationMessage *msg)
1017 {
1018   struct BobServiceSession *s = cls;
1019   uint32_t contained_count;
1020   uint32_t total_count;
1021   uint16_t msize;
1022
1023   if (GNUNET_SCALARPRODUCT_STATUS_INIT != s->status)
1024   {
1025     GNUNET_break (0);
1026     return GNUNET_SYSERR;
1027   }
1028   msize = ntohs (msg->header.size);
1029   total_count = ntohl (msg->element_count_total);
1030   contained_count = ntohl (msg->element_count_contained);
1031   if ( (0 == total_count) ||
1032        (0 == contained_count) ||
1033        (UINT16_MAX < contained_count) ||
1034        (msize != (sizeof (struct BobComputationMessage) +
1035                   contained_count * sizeof (struct GNUNET_SCALARPRODUCT_Element))) )
1036   {
1037     GNUNET_break_op (0);
1038     return GNUNET_SYSERR;
1039   }
1040   if (NULL != find_matching_client_session (&msg->session_key))
1041   {
1042     GNUNET_break (0);
1043     return GNUNET_SYSERR;
1044   }
1045   return GNUNET_OK;
1046 }
1047
1048
1049 /**
1050  * Handler for Bob's a client request message.  Bob is in the response
1051  * role, keep the values + session and waiting for a matching session
1052  * or process a waiting request from Alice.
1053  *
1054  * @param cls identification of the client
1055  * @param msg the actual message
1056  */
1057 static void
1058 handle_bob_client_message (void *cls,
1059                            const struct BobComputationMessage *msg)
1060 {
1061   struct BobServiceSession *s = cls;
1062   struct CadetIncomingSession *in;
1063   uint32_t contained_count;
1064   uint32_t total_count;
1065   const struct GNUNET_SCALARPRODUCT_Element *elements;
1066   struct GNUNET_SET_Element set_elem;
1067   struct GNUNET_SCALARPRODUCT_Element *elem;
1068
1069   total_count = ntohl (msg->element_count_total);
1070   contained_count = ntohl (msg->element_count_contained);
1071
1072   s->status = GNUNET_SCALARPRODUCT_STATUS_ACTIVE;
1073   s->total = total_count;
1074   s->client_received_element_count = contained_count;
1075   s->session_id = msg->session_key;
1076   s->port = GNUNET_CADET_open_port (my_cadet,
1077                                     &msg->session_key,
1078                                     &cb_channel_incoming,
1079                                     s);
1080   if (NULL == s->port)
1081   {
1082     GNUNET_break (0);
1083     GNUNET_SERVICE_client_drop (s->client);
1084     return;
1085   }
1086   GNUNET_break (GNUNET_YES ==
1087                 GNUNET_CONTAINER_multihashmap_put (client_sessions,
1088                                                    &s->session_id,
1089                                                    s,
1090                                                    GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY));
1091   elements = (const struct GNUNET_SCALARPRODUCT_Element *) &msg[1];
1092   s->intersected_elements
1093     = GNUNET_CONTAINER_multihashmap_create (s->total,
1094                                             GNUNET_YES);
1095   s->intersection_set
1096     = GNUNET_SET_create (cfg,
1097                          GNUNET_SET_OPERATION_INTERSECTION);
1098   for (uint32_t i = 0; i < contained_count; i++)
1099   {
1100     if (0 == GNUNET_ntohll (elements[i].value))
1101       continue;
1102     elem = GNUNET_new (struct GNUNET_SCALARPRODUCT_Element);
1103     GNUNET_memcpy (elem,
1104             &elements[i],
1105             sizeof (struct GNUNET_SCALARPRODUCT_Element));
1106     if (GNUNET_SYSERR ==
1107         GNUNET_CONTAINER_multihashmap_put (s->intersected_elements,
1108                                            &elem->key,
1109                                            elem,
1110                                            GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY))
1111     {
1112       GNUNET_break (0);
1113       GNUNET_free (elem);
1114       continue;
1115     }
1116     set_elem.data = &elem->key;
1117     set_elem.size = sizeof (elem->key);
1118     set_elem.element_type = 0;
1119     GNUNET_SET_add_element (s->intersection_set,
1120                             &set_elem,
1121                             NULL, NULL);
1122     s->used_element_count++;
1123   }
1124   GNUNET_SERVICE_client_continue (s->client);
1125   if (s->total != s->client_received_element_count)
1126   {
1127     /* multipart msg */
1128     return;
1129   }
1130   in = find_matching_cadet_session (&s->session_id);
1131   if (NULL == in)
1132   {
1133     /* nothing yet, wait for Alice */
1134     return;
1135   }
1136   GNUNET_assert (NULL == in->s);
1137   /* pair them up */
1138   in->s = s;
1139   s->cadet = in;
1140   start_intersection (s);
1141 }
1142
1143
1144 /**
1145  * Task run during shutdown.
1146  *
1147  * @param cls unused
1148  */
1149 static void
1150 shutdown_task (void *cls)
1151 {
1152   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1153               "Shutting down, initiating cleanup.\n");
1154   // FIXME: we have to cut our connections to CADET first!
1155   if (NULL != my_cadet)
1156   {
1157     GNUNET_CADET_disconnect (my_cadet);
1158     my_cadet = NULL;
1159   }
1160   if (NULL != edc)
1161   {
1162     GNUNET_CRYPTO_ecc_dlog_release (edc);
1163     edc = NULL;
1164   }
1165   GNUNET_CONTAINER_multihashmap_destroy (client_sessions);
1166   client_sessions = NULL;
1167   GNUNET_CONTAINER_multihashmap_destroy (cadet_sessions);
1168   cadet_sessions = NULL;
1169 }
1170
1171
1172 /**
1173  * A client connected.
1174  *
1175  * Setup the associated data structure.
1176  *
1177  * @param cls closure, NULL
1178  * @param client identification of the client
1179  * @param mq message queue to communicate with @a client
1180  * @return our `struct BobServiceSession`
1181  */
1182 static void *
1183 client_connect_cb (void *cls,
1184                    struct GNUNET_SERVICE_Client *client,
1185                    struct GNUNET_MQ_Handle *mq)
1186 {
1187   struct BobServiceSession *s;
1188
1189   s = GNUNET_new (struct BobServiceSession);
1190   s->client = client;
1191   s->client_mq = mq;
1192   return s;
1193 }
1194
1195
1196 /**
1197  * A client disconnected.
1198  *
1199  * Remove the associated session(s), release data structures
1200  * and cancel pending outgoing transmissions to the client.
1201  *
1202  * @param cls closure, NULL
1203  * @param client identification of the client
1204  * @param app_cls our `struct BobServiceSession`
1205  */
1206 static void
1207 client_disconnect_cb (void *cls,
1208                       struct GNUNET_SERVICE_Client *client,
1209                       void *app_cls)
1210 {
1211   struct BobServiceSession *s = app_cls;
1212
1213   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1214               "Client disconnected from us.\n");
1215   s->client = NULL;
1216   destroy_service_session (s);
1217 }
1218
1219
1220 /**
1221  * Initialization of the program and message handlers
1222  *
1223  * @param cls closure
1224  * @param c configuration to use
1225  * @param service the initialized service
1226  */
1227 static void
1228 run (void *cls,
1229      const struct GNUNET_CONFIGURATION_Handle *c,
1230      struct GNUNET_SERVICE_Handle *service)
1231 {
1232   static const struct GNUNET_CADET_MessageHandler cadet_handlers[] = {
1233     { &handle_alices_computation_request,
1234       GNUNET_MESSAGE_TYPE_SCALARPRODUCT_ECC_SESSION_INITIALIZATION,
1235       sizeof (struct EccServiceRequestMessage) },
1236     { &handle_alices_cryptodata_message,
1237       GNUNET_MESSAGE_TYPE_SCALARPRODUCT_ECC_ALICE_CRYPTODATA,
1238       0},
1239     { NULL, 0, 0}
1240   };
1241
1242   cfg = c;
1243   /* We don't really do DLOG, so we can setup with very minimal resources */
1244   edc = GNUNET_CRYPTO_ecc_dlog_prepare (4 /* max value */,
1245                                         2 /* RAM */);
1246   client_sessions = GNUNET_CONTAINER_multihashmap_create (128,
1247                                                           GNUNET_YES);
1248   cadet_sessions = GNUNET_CONTAINER_multihashmap_create (128,
1249                                                          GNUNET_YES);
1250   my_cadet = GNUNET_CADET_connect (cfg, 
1251                                    NULL,
1252                                    &cb_channel_destruction,
1253                                    cadet_handlers);
1254   GNUNET_SCHEDULER_add_shutdown (&shutdown_task,
1255                                  NULL);
1256   if (NULL == my_cadet)
1257   {
1258     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1259                 _("Connect to CADET failed\n"));
1260     GNUNET_SCHEDULER_shutdown ();
1261     return;
1262   }
1263 }
1264
1265
1266 /**
1267  * Define "main" method using service macro.
1268  */
1269 GNUNET_SERVICE_MAIN
1270 ("scalarproduct-bob",
1271  GNUNET_SERVICE_OPTION_NONE,
1272  &run,
1273  &client_connect_cb,
1274  &client_disconnect_cb,
1275  NULL,
1276  GNUNET_MQ_hd_var_size (bob_client_message,
1277                         GNUNET_MESSAGE_TYPE_SCALARPRODUCT_CLIENT_TO_BOB,
1278                         struct BobComputationMessage,
1279                         NULL),
1280 GNUNET_MQ_hd_var_size (bob_client_message_multipart,
1281                        GNUNET_MESSAGE_TYPE_SCALARPRODUCT_CLIENT_MULTIPART_BOB,
1282                        struct ComputationBobCryptodataMultipartMessage,
1283                        NULL),
1284  GNUNET_MQ_handler_end ());
1285
1286
1287 /* end of gnunet-service-scalarproduct-ecc_bob.c */