- fix coverity
[oweals/gnunet.git] / src / scalarproduct / gnunet-service-scalarproduct_bob.c
1 /*
2      This file is part of GNUnet.
3      Copyright (C) 2013, 2014 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_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.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_SERVER_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    * a(Alice)
108    */
109   struct MpiElement *sorted_elements;
110
111   /**
112    * E(ai)(Bob) after applying the mask
113    */
114   struct GNUNET_CRYPTO_PaillierCiphertext *e_a;
115
116   /**
117    * Bob's permutation p of R
118    */
119   struct GNUNET_CRYPTO_PaillierCiphertext *r;
120
121   /**
122    * Bob's permutation q of R
123    */
124   struct GNUNET_CRYPTO_PaillierCiphertext *r_prime;
125
126   /**
127    * Bob's "s"
128    */
129   struct GNUNET_CRYPTO_PaillierCiphertext s;
130
131   /**
132    * Bob's "s'"
133    */
134   struct GNUNET_CRYPTO_PaillierCiphertext s_prime;
135
136   /**
137    * Handle for our associated incoming CADET session, or NULL
138    * if we have not gotten one yet.
139    */
140   struct CadetIncomingSession *cadet;
141
142   /**
143    * How many elements will be supplied in total from the client.
144    */
145   uint32_t total;
146
147   /**
148    * Already transferred elements (received) for multipart
149    * messages from client. Always less than @e total.
150    */
151   uint32_t client_received_element_count;
152
153   /**
154    * How many elements actually are used for the scalar product.
155    * Size of the arrays in @e r and @e r_prime.  Also sometimes
156    * used as an index into the arrays during construction.
157    */
158   uint32_t used_element_count;
159
160   /**
161    * Counts the number of values received from Alice by us.
162    * Always less than @e used_element_count.
163    */
164   uint32_t cadet_received_element_count;
165
166   /**
167    * Counts the number of values transmitted from us to Alice.
168    * Always less than @e used_element_count.
169    */
170   uint32_t cadet_transmitted_element_count;
171
172   /**
173    * State of this session.   In
174    * #GNUNET_SCALARPRODUCT_STATUS_ACTIVE while operation is
175    * ongoing, afterwards in #GNUNET_SCALARPRODUCT_STATUS_SUCCESS or
176    * #GNUNET_SCALARPRODUCT_STATUS_FAILURE.
177    */
178   enum GNUNET_SCALARPRODUCT_ResponseStatus status;
179
180   /**
181    * Are we already in #destroy_service_session()?
182    */
183   int in_destroy;
184
185 };
186
187
188 /**
189  * An incoming session from CADET.
190  */
191 struct CadetIncomingSession
192 {
193
194   /**
195    * Associated client session, or NULL.
196    */
197   struct BobServiceSession *s;
198
199   /**
200    * The CADET channel.
201    */
202   struct GNUNET_CADET_Channel *channel;
203
204   /**
205    * Originator's peer identity. (Only for diagnostics.)
206    */
207   struct GNUNET_PeerIdentity peer;
208
209   /**
210    * (hopefully) unique transaction ID
211    */
212   struct GNUNET_HashCode session_id;
213
214   /**
215    * Public key of the remote service.
216    */
217   struct GNUNET_CRYPTO_PaillierPublicKey remote_pubkey;
218
219   /**
220    * The message queue for this channel.
221    */
222   struct GNUNET_MQ_Handle *cadet_mq;
223
224   /**
225    * Has this CADET session been added to the map yet?
226    * #GNUNET_YES if so, in which case @e session_id is
227    * the key.
228    */
229   int in_map;
230
231   /**
232    * Are we already in #destroy_cadet_session()?
233    */
234   int in_destroy;
235
236 };
237
238
239 /**
240  * GNUnet configuration handle
241  */
242 static const struct GNUNET_CONFIGURATION_Handle *cfg;
243
244 /**
245  * Service's own public key
246  */
247 static struct GNUNET_CRYPTO_PaillierPublicKey my_pubkey;
248
249 /**
250  * Service's own private key
251  */
252 static struct GNUNET_CRYPTO_PaillierPrivateKey my_privkey;
253
254 /**
255  * Service's offset for values that could possibly be negative but are plaintext for encryption.
256  */
257 static gcry_mpi_t my_offset;
258
259 /**
260  * Map of `struct BobServiceSession`, by session keys.
261  */
262 static struct GNUNET_CONTAINER_MultiHashMap *client_sessions;
263
264 /**
265  * Map of `struct CadetIncomingSession`, by session keys.
266  */
267 static struct GNUNET_CONTAINER_MultiHashMap *cadet_sessions;
268
269 /**
270  * Handle to the CADET service.
271  */
272 static struct GNUNET_CADET_Handle *my_cadet;
273
274
275
276 /**
277  * Finds a not terminated client session in the respective map based on
278  * session key.
279  *
280  * @param key the session key we want to search for
281  * @return the matching session, or NULL for none
282  */
283 static struct BobServiceSession *
284 find_matching_client_session (const struct GNUNET_HashCode *key)
285 {
286   return GNUNET_CONTAINER_multihashmap_get (client_sessions,
287                                             key);
288 }
289
290
291 /**
292  * Finds a CADET session in the respective map based on session key.
293  *
294  * @param key the session key we want to search for
295  * @return the matching session, or NULL for none
296  */
297 static struct CadetIncomingSession *
298 find_matching_cadet_session (const struct GNUNET_HashCode *key)
299 {
300   return GNUNET_CONTAINER_multihashmap_get (cadet_sessions,
301                                             key);
302 }
303
304
305 /**
306  * Callback used to free the elements in the map.
307  *
308  * @param cls NULL
309  * @param key key of the element
310  * @param value the value to free
311  */
312 static int
313 free_element_cb (void *cls,
314                  const struct GNUNET_HashCode *key,
315                  void *value)
316 {
317   struct GNUNET_SCALARPRODUCT_Element *element = value;
318
319   GNUNET_free (element);
320   return GNUNET_OK;
321 }
322
323
324 /**
325  * Destroy session state, we are done with it.
326  *
327  * @param session the session to free elements from
328  */
329 static void
330 destroy_cadet_session (struct CadetIncomingSession *s);
331
332
333 /**
334  * Destroy session state, we are done with it.
335  *
336  * @param session the session to free elements from
337  */
338 static void
339 destroy_service_session (struct BobServiceSession *s)
340 {
341   struct CadetIncomingSession *in;
342   unsigned int i;
343
344   if (GNUNET_YES == s->in_destroy)
345     return;
346   s->in_destroy = GNUNET_YES;
347   if (NULL != (in = s->cadet))
348   {
349     s->cadet = NULL;
350     destroy_cadet_session (in);
351   }
352   if (NULL != s->client_mq)
353   {
354     GNUNET_MQ_destroy (s->client_mq);
355     s->client_mq = NULL;
356   }
357   if (NULL != s->client)
358   {
359     GNUNET_SERVER_client_disconnect (s->client);
360     s->client = NULL;
361   }
362   GNUNET_assert (GNUNET_YES ==
363                  GNUNET_CONTAINER_multihashmap_remove (client_sessions,
364                                                        &s->session_id,
365                                                        s));
366   if (NULL != s->intersected_elements)
367   {
368     GNUNET_CONTAINER_multihashmap_iterate (s->intersected_elements,
369                                            &free_element_cb,
370                                            NULL);
371     GNUNET_CONTAINER_multihashmap_destroy (s->intersected_elements);
372     s->intersected_elements = NULL;
373   }
374   if (NULL != s->intersection_op)
375   {
376     GNUNET_SET_operation_cancel (s->intersection_op);
377     s->intersection_op = NULL;
378   }
379   if (NULL != s->intersection_set)
380   {
381     GNUNET_SET_destroy (s->intersection_set);
382     s->intersection_set = NULL;
383   }
384   if (NULL != s->e_a)
385   {
386     GNUNET_free (s->e_a);
387     s->e_a = NULL;
388   }
389   if (NULL != s->sorted_elements)
390   {
391     for (i=0;i<s->used_element_count;i++)
392       gcry_mpi_release (s->sorted_elements[i].value);
393     GNUNET_free (s->sorted_elements);
394     s->sorted_elements = NULL;
395   }
396   if (NULL != s->r)
397   {
398     GNUNET_free (s->r);
399     s->r = NULL;
400   }
401   if (NULL != s->r_prime)
402   {
403     GNUNET_free (s->r_prime);
404     s->r_prime = NULL;
405   }
406   GNUNET_free (s);
407 }
408
409
410 /**
411  * Destroy incoming CADET session state, we are done with it.
412  *
413  * @param in the session to free elements from
414  */
415 static void
416 destroy_cadet_session (struct CadetIncomingSession *in)
417 {
418   struct BobServiceSession *s;
419
420   if (GNUNET_YES == in->in_destroy)
421     return;
422   in->in_destroy = GNUNET_YES;
423   if (NULL != (s = in->s))
424   {
425     in->s = NULL;
426     destroy_service_session (s);
427   }
428   if (GNUNET_YES == in->in_map)
429   {
430     GNUNET_assert (GNUNET_YES ==
431                    GNUNET_CONTAINER_multihashmap_remove (cadet_sessions,
432                                                          &in->session_id,
433                                                          in));
434     in->in_map = GNUNET_NO;
435   }
436   if (NULL != in->cadet_mq)
437   {
438     GNUNET_MQ_destroy (in->cadet_mq);
439     in->cadet_mq = NULL;
440   }
441   if (NULL != in->channel)
442   {
443     GNUNET_CADET_channel_destroy (in->channel);
444     in->channel = NULL;
445   }
446   GNUNET_free (in);
447 }
448
449
450 /**
451  * Notify the client that the session has succeeded or failed.  This
452  * message gets sent to Bob's client if the operation completed or
453  * Alice disconnected.
454  *
455  * @param session the associated client session to fail or succeed
456  */
457 static void
458 prepare_client_end_notification (struct BobServiceSession *session)
459 {
460   struct ClientResponseMessage *msg;
461   struct GNUNET_MQ_Envelope *e;
462
463   if (NULL == session->client_mq)
464     return; /* no client left to be notified */
465   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
466               "Sending session-end notification with status %d to client for session %s\n",
467               session->status,
468               GNUNET_h2s (&session->session_id));
469   e = GNUNET_MQ_msg (msg,
470                      GNUNET_MESSAGE_TYPE_SCALARPRODUCT_RESULT);
471   msg->range = 0;
472   msg->product_length = htonl (0);
473   msg->status = htonl (session->status);
474   GNUNET_MQ_send (session->client_mq,
475                   e);
476 }
477
478
479 /**
480  * Function called whenever a channel is destroyed.  Should clean up
481  * any associated state.
482  *
483  * It must NOT call #GNUNET_CADET_channel_destroy() on the channel.
484  *
485  * @param cls closure (set from #GNUNET_CADET_connect())
486  * @param channel connection to the other end (henceforth invalid)
487  * @param channel_ctx place where local state associated
488  *                   with the channel is stored
489  */
490 static void
491 cb_channel_destruction (void *cls,
492                         const struct GNUNET_CADET_Channel *channel,
493                         void *channel_ctx)
494 {
495   struct CadetIncomingSession *in = channel_ctx;
496   struct BobServiceSession *s;
497
498   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
499               "Peer disconnected, terminating session %s with peer %s\n",
500               GNUNET_h2s (&in->session_id),
501               GNUNET_i2s (&in->peer));
502   if (NULL != (s = in->s))
503   {
504     if (GNUNET_SCALARPRODUCT_STATUS_ACTIVE == s->status)
505     {
506       s->status = GNUNET_SCALARPRODUCT_STATUS_FAILURE;
507       prepare_client_end_notification (s);
508     }
509   }
510   if (NULL != in->cadet_mq)
511   {
512     GNUNET_MQ_destroy (in->cadet_mq);
513     in->cadet_mq = NULL;
514   }
515   in->channel = NULL;
516   destroy_cadet_session (in);
517 }
518
519
520 /**
521  * MQ finished giving our last message to CADET, now notify
522  * the client that we are finished.
523  */
524 static void
525 bob_cadet_done_cb (void *cls)
526 {
527   struct BobServiceSession *session = cls;
528
529   session->status = GNUNET_SCALARPRODUCT_STATUS_SUCCESS;
530   prepare_client_end_notification (session);
531 }
532
533
534 /**
535  * Maximum count of elements we can put into a multipart message
536  */
537 #define ELEMENT_CAPACITY ((GNUNET_CONSTANTS_MAX_CADET_MESSAGE_SIZE - 1 - sizeof (struct BobCryptodataMultipartMessage)) / sizeof (struct GNUNET_CRYPTO_PaillierCiphertext))
538
539
540 /**
541  * Send a multipart chunk of a service response from Bob to Alice.
542  * This element only contains the two permutations of R, R'.
543  *
544  * @param s the associated service session
545  */
546 static void
547 transmit_bobs_cryptodata_message_multipart (struct BobServiceSession *s)
548 {
549   struct GNUNET_CRYPTO_PaillierCiphertext *payload;
550   struct BobCryptodataMultipartMessage *msg;
551   struct GNUNET_MQ_Envelope *e;
552   unsigned int i;
553   unsigned int j;
554   uint32_t todo_count;
555
556   while (s->cadet_transmitted_element_count != s->used_element_count)
557   {
558     todo_count = s->used_element_count - s->cadet_transmitted_element_count;
559     if (todo_count > ELEMENT_CAPACITY / 2)
560       todo_count = ELEMENT_CAPACITY / 2;
561
562     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
563                 "Sending %u additional crypto values to Alice\n",
564                 (unsigned int) todo_count);
565     e = GNUNET_MQ_msg_extra (msg,
566                              todo_count * sizeof (struct GNUNET_CRYPTO_PaillierCiphertext) * 2,
567                              GNUNET_MESSAGE_TYPE_SCALARPRODUCT_BOB_CRYPTODATA_MULTIPART);
568     msg->contained_element_count = htonl (todo_count);
569     payload = (struct GNUNET_CRYPTO_PaillierCiphertext *) &msg[1];
570     for (i = s->cadet_transmitted_element_count, j = 0; i < s->cadet_transmitted_element_count + todo_count; i++)
571     {
572       //r[i][p] and r[i][q]
573       memcpy (&payload[j++],
574               &s->r[i],
575               sizeof (struct GNUNET_CRYPTO_PaillierCiphertext));
576       memcpy (&payload[j++],
577               &s->r_prime[i],
578               sizeof (struct GNUNET_CRYPTO_PaillierCiphertext));
579     }
580     s->cadet_transmitted_element_count += todo_count;
581     if (s->cadet_transmitted_element_count == s->used_element_count)
582       GNUNET_MQ_notify_sent (e,
583                              &bob_cadet_done_cb,
584                              s);
585     GNUNET_MQ_send (s->cadet->cadet_mq,
586                     e);
587   }
588   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
589               "All values queued for Alice, Bob is done\n");
590 }
591
592
593 /**
594  * Bob generates the response message to be sent to Alice after
595  * computing the values (1), (2), S and S'.
596  *
597  *  (1)[]: $E_A(a_{pi(i)}) times E_A(- r_{pi(i)} - b_{pi(i)}) &= E_A(a_{pi(i)} - r_{pi(i)} - b_{pi(i)})$
598  *  (2)[]: $E_A(a_{pi'(i)}) times E_A(- r_{pi'(i)}) &= E_A(a_{pi'(i)} - r_{pi'(i)})$
599  *      S: $S := E_A(sum (r_i + b_i)^2)$
600  *     S': $S' := E_A(sum r_i^2)$
601  *
602  * @param s the associated requesting session with Alice
603  */
604 static void
605 transmit_bobs_cryptodata_message (struct BobServiceSession *s)
606 {
607   struct BobCryptodataMessage *msg;
608   struct GNUNET_MQ_Envelope *e;
609   struct GNUNET_CRYPTO_PaillierCiphertext *payload;
610   unsigned int i;
611
612   s->cadet_transmitted_element_count
613     = ((GNUNET_CONSTANTS_MAX_CADET_MESSAGE_SIZE - 1 - sizeof (struct BobCryptodataMessage))
614        / sizeof (struct GNUNET_CRYPTO_PaillierCiphertext) / 2) - 1;
615   if (s->cadet_transmitted_element_count > s->used_element_count)
616     s->cadet_transmitted_element_count = s->used_element_count;
617
618   e = GNUNET_MQ_msg_extra (msg,
619                            (2 + s->cadet_transmitted_element_count * 2)
620                            * sizeof (struct GNUNET_CRYPTO_PaillierCiphertext),
621                            GNUNET_MESSAGE_TYPE_SCALARPRODUCT_BOB_CRYPTODATA);
622   msg->contained_element_count = htonl (s->cadet_transmitted_element_count);
623
624   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
625               "Sending %u/%u crypto values to Alice\n",
626               (unsigned int) s->cadet_transmitted_element_count,
627               (unsigned int) s->used_element_count);
628
629   payload = (struct GNUNET_CRYPTO_PaillierCiphertext *) &msg[1];
630   memcpy (&payload[0],
631           &s->s,
632           sizeof (struct GNUNET_CRYPTO_PaillierCiphertext));
633   memcpy (&payload[1],
634           &s->s_prime,
635           sizeof (struct GNUNET_CRYPTO_PaillierCiphertext));
636
637   payload = &payload[2];
638   // convert k[][]
639   for (i = 0; i < s->cadet_transmitted_element_count; i++)
640   {
641     //k[i][p] and k[i][q]
642     memcpy (&payload[i * 2],
643             &s->r[i],
644             sizeof (struct GNUNET_CRYPTO_PaillierCiphertext));
645     memcpy (&payload[i * 2 + 1],
646             &s->r_prime[i],
647             sizeof (struct GNUNET_CRYPTO_PaillierCiphertext));
648   }
649   if (s->cadet_transmitted_element_count == s->used_element_count)
650     GNUNET_MQ_notify_sent (e,
651                            &bob_cadet_done_cb,
652                            s);
653   GNUNET_MQ_send (s->cadet->cadet_mq,
654                   e);
655   transmit_bobs_cryptodata_message_multipart (s);
656 }
657 #undef ELEMENT_CAPACITY
658
659
660 /**
661  * Computes the square sum over a vector of a given length.
662  *
663  * @param vector the vector to compute over
664  * @param length the length of the vector
665  * @return an MPI value containing the calculated sum, never NULL
666  * TODO: code duplication with Alice!
667  */
668 static gcry_mpi_t
669 compute_square_sum (const gcry_mpi_t *vector,
670                     uint32_t length)
671 {
672   gcry_mpi_t elem;
673   gcry_mpi_t sum;
674   uint32_t i;
675
676   GNUNET_assert (NULL != (sum = gcry_mpi_new (0)));
677   GNUNET_assert (NULL != (elem = gcry_mpi_new (0)));
678   for (i = 0; i < length; i++)
679   {
680     gcry_mpi_mul (elem, vector[i], vector[i]);
681     gcry_mpi_add (sum, sum, elem);
682   }
683   gcry_mpi_release (elem);
684   return sum;
685 }
686
687
688 /**
689  * Compute the values
690  *  (1)[]: $E_A(a_{pi(i)}) otimes E_A(- r_{pi(i)} - b_{pi(i)}) &= E_A(a_{pi(i)} - r_{pi(i)} - b_{pi(i)})$
691  *  (2)[]: $E_A(a_{pi'(i)}) otimes E_A(- r_{pi'(i)}) &= E_A(a_{pi'(i)} - r_{pi'(i)})$
692  *      S: $S := E_A(sum (r_i + b_i)^2)$
693  *     S': $S' := E_A(sum r_i^2)$
694  *
695  * @param request the requesting session + bob's requesting peer
696  * @return #GNUNET_OK on success
697  */
698 static int
699 compute_service_response (struct BobServiceSession *session)
700 {
701   uint32_t i;
702   unsigned int *p;
703   unsigned int *q;
704   uint32_t count;
705   gcry_mpi_t *rand;
706   gcry_mpi_t tmp;
707   const struct MpiElement *b;
708   struct GNUNET_CRYPTO_PaillierCiphertext *a;
709   struct GNUNET_CRYPTO_PaillierCiphertext *r;
710   struct GNUNET_CRYPTO_PaillierCiphertext *r_prime;
711
712   count = session->used_element_count;
713   a = session->e_a;
714   b = session->sorted_elements;
715   q = GNUNET_CRYPTO_random_permute (GNUNET_CRYPTO_QUALITY_WEAK,
716                                     count);
717   p = GNUNET_CRYPTO_random_permute (GNUNET_CRYPTO_QUALITY_WEAK,
718                                     count);
719   rand = GNUNET_malloc (sizeof (gcry_mpi_t) * count);
720   for (i = 0; i < count; i++)
721     GNUNET_assert (NULL != (rand[i] = gcry_mpi_new (0)));
722   r = GNUNET_malloc (sizeof (struct GNUNET_CRYPTO_PaillierCiphertext) * count);
723   r_prime = GNUNET_malloc (sizeof (struct GNUNET_CRYPTO_PaillierCiphertext) * count);
724
725   for (i = 0; i < count; i++)
726   {
727     int32_t svalue;
728
729     svalue = (int32_t) GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_WEAK,
730                                                  UINT32_MAX);
731     // long to gcry_mpi_t
732     if (svalue < 0)
733       gcry_mpi_sub_ui (rand[i],
734                        rand[i],
735                        - svalue);
736     else
737       rand[i] = gcry_mpi_set_ui (rand[i], svalue);
738   }
739
740   tmp = gcry_mpi_new (0);
741   // encrypt the element
742   // for the sake of readability I decided to have dedicated permutation
743   // vectors, which get rid of all the lookups in p/q.
744   // however, ap/aq are not absolutely necessary but are just abstraction
745   // Calculate Kp = E(S + a_pi) (+) E(S - r_pi - b_pi)
746   for (i = 0; i < count; i++)
747   {
748     // E(S - r_pi - b_pi)
749     gcry_mpi_sub (tmp, my_offset, rand[p[i]]);
750     gcry_mpi_sub (tmp, tmp, b[p[i]].value);
751     GNUNET_assert (2 ==
752                    GNUNET_CRYPTO_paillier_encrypt (&session->cadet->remote_pubkey,
753                                                    tmp,
754                                                    2,
755                                                    &r[i]));
756
757     // E(S - r_pi - b_pi) * E(S + a_pi) ==  E(2*S + a - r - b)
758     if (GNUNET_OK !=
759         GNUNET_CRYPTO_paillier_hom_add (&session->cadet->remote_pubkey,
760                                         &r[i],
761                                         &a[p[i]],
762                                         &r[i]))
763     {
764       GNUNET_break_op (0);
765       goto error_cleanup;
766     }
767   }
768
769   // Calculate Kq = E(S + a_qi) (+) E(S - r_qi)
770   for (i = 0; i < count; i++)
771   {
772     // E(S - r_qi)
773     gcry_mpi_sub (tmp, my_offset, rand[q[i]]);
774     GNUNET_assert (2 ==
775                    GNUNET_CRYPTO_paillier_encrypt (&session->cadet->remote_pubkey,
776                                                    tmp,
777                                                    2,
778                                                    &r_prime[i]));
779
780     // E(S - r_qi) * E(S + a_qi) == E(2*S + a_qi - r_qi)
781     if (GNUNET_OK !=
782         GNUNET_CRYPTO_paillier_hom_add (&session->cadet->remote_pubkey,
783                                         &r_prime[i],
784                                         &a[q[i]],
785                                         &r_prime[i]))
786     {
787       GNUNET_break_op (0);
788       goto error_cleanup;
789     }
790   }
791   gcry_mpi_release (tmp);
792
793   // Calculate S' =  E(SUM( r_i^2 ))
794   tmp = compute_square_sum (rand, count);
795   GNUNET_assert (1 ==
796                  GNUNET_CRYPTO_paillier_encrypt (&session->cadet->remote_pubkey,
797                                                  tmp,
798                                                  1,
799                                                  &session->s_prime));
800   gcry_mpi_release (tmp);
801
802   // Calculate S = E(SUM( (r_i + b_i)^2 ))
803   for (i = 0; i < count; i++)
804     gcry_mpi_add (rand[i], rand[i], b[i].value);
805   tmp = compute_square_sum (rand, count);
806   GNUNET_assert (1 ==
807                  GNUNET_CRYPTO_paillier_encrypt (&session->cadet->remote_pubkey,
808                                                  tmp,
809                                                  1,
810                                                  &session->s));
811   gcry_mpi_release (tmp);
812
813   session->r = r;
814   session->r_prime = r_prime;
815
816   for (i = 0; i < count; i++)
817     gcry_mpi_release (rand[i]);
818   GNUNET_free (session->e_a);
819   session->e_a = NULL;
820   GNUNET_free (p);
821   GNUNET_free (q);
822   GNUNET_free (rand);
823   return GNUNET_OK;
824
825  error_cleanup:
826   GNUNET_free (r);
827   GNUNET_free (r_prime);
828   gcry_mpi_release (tmp);
829   GNUNET_free (p);
830   GNUNET_free (q);
831   for (i = 0; i < count; i++)
832     gcry_mpi_release (rand[i]);
833   GNUNET_free (rand);
834   return GNUNET_SYSERR;
835 }
836
837
838 /**
839  * Iterator to copy over messages from the hash map
840  * into an array for sorting.
841  *
842  * @param cls the `struct BobServiceSession *`
843  * @param key the key (unused)
844  * @param value the `struct GNUNET_SCALARPRODUCT_Element *`
845  * TODO: code duplication with Alice!
846  */
847 static int
848 copy_element_cb (void *cls,
849                  const struct GNUNET_HashCode *key,
850                  void *value)
851 {
852   struct BobServiceSession *s = cls;
853   struct GNUNET_SCALARPRODUCT_Element *e = value;
854   gcry_mpi_t mval;
855   int64_t val;
856
857   mval = gcry_mpi_new (0);
858   val = (int64_t) GNUNET_ntohll (e->value);
859   if (0 > val)
860     gcry_mpi_sub_ui (mval, mval, -val);
861   else
862     gcry_mpi_add_ui (mval, mval, val);
863   s->sorted_elements [s->used_element_count].value = mval;
864   s->sorted_elements [s->used_element_count].key = &e->key;
865   s->used_element_count++;
866   return GNUNET_OK;
867 }
868
869
870 /**
871  * Compare two `struct MpiValue`s by key for sorting.
872  *
873  * @param a pointer to first `struct MpiValue *`
874  * @param b pointer to first `struct MpiValue *`
875  * @return -1 for a < b, 0 for a=b, 1 for a > b.
876  * TODO: code duplication with Alice!
877  */
878 static int
879 element_cmp (const void *a,
880              const void *b)
881 {
882   const struct MpiElement *ma = a;
883   const struct MpiElement *mb = b;
884
885   return GNUNET_CRYPTO_hash_cmp (ma->key,
886                                  mb->key);
887 }
888
889
890 /**
891  * Intersection operation and receiving data via CADET from
892  * Alice are both done, compute and transmit our reply via
893  * CADET.
894  *
895  * @param s session to transmit reply for.
896  */
897 static void
898 transmit_cryptographic_reply (struct BobServiceSession *s)
899 {
900   struct GNUNET_CADET_Channel *channel;
901
902   /* TODO: code duplication with Alice! */
903   LOG (GNUNET_ERROR_TYPE_DEBUG,
904        "Received everything, building reply for Alice\n");
905   s->sorted_elements
906     = GNUNET_malloc (GNUNET_CONTAINER_multihashmap_size (s->intersected_elements) *
907                      sizeof (struct MpiElement));
908   s->used_element_count = 0;
909   GNUNET_CONTAINER_multihashmap_iterate (s->intersected_elements,
910                                          &copy_element_cb,
911                                          s);
912   qsort (s->sorted_elements,
913          s->used_element_count,
914          sizeof (struct MpiElement),
915          &element_cmp);
916   if (GNUNET_OK !=
917       compute_service_response (s))
918   {
919     channel = s->cadet->channel;
920     s->cadet->channel = NULL;
921     GNUNET_CADET_channel_destroy (channel);
922     return;
923   }
924   transmit_bobs_cryptodata_message (s);
925 }
926
927
928 /**
929  * Handle a multipart-chunk of a request from another service to
930  * calculate a scalarproduct with us.
931  *
932  * @param cls closure (set from #GNUNET_CADET_connect)
933  * @param channel connection to the other end
934  * @param channel_ctx place to store local state associated with the @a channel
935  * @param message the actual message
936  * @return #GNUNET_OK to keep the connection open,
937  *         #GNUNET_SYSERR to close it (signal serious error)
938  */
939 static int
940 handle_alices_cryptodata_message (void *cls,
941                                   struct GNUNET_CADET_Channel *channel,
942                                   void **channel_ctx,
943                                   const struct GNUNET_MessageHeader *message)
944 {
945   struct CadetIncomingSession *in = *channel_ctx;
946   struct BobServiceSession *s;
947   const struct AliceCryptodataMessage *msg;
948   const struct GNUNET_CRYPTO_PaillierCiphertext *payload;
949   uint32_t contained_elements;
950   size_t msg_length;
951   uint16_t msize;
952   unsigned int max;
953
954   if (NULL == in)
955   {
956     GNUNET_break_op (0);
957     return GNUNET_SYSERR;
958   }
959   s = in->s;
960   if (NULL == s)
961   {
962     GNUNET_break_op (0);
963     return GNUNET_SYSERR;
964   }
965   msize = ntohs (message->size);
966   if (msize <= sizeof (struct AliceCryptodataMessage))
967   {
968     GNUNET_break_op (0);
969     return GNUNET_SYSERR;
970   }
971   msg = (const struct AliceCryptodataMessage *) message;
972   contained_elements = ntohl (msg->contained_element_count);
973   /* Our intersection may still be ongoing, but this is nevertheless
974      an upper bound on the required array size */
975   max = GNUNET_CONTAINER_multihashmap_size (s->intersected_elements);
976   msg_length = sizeof (struct AliceCryptodataMessage)
977     + contained_elements * sizeof (struct GNUNET_CRYPTO_PaillierCiphertext);
978   if ( (msize != msg_length) ||
979        (0 == contained_elements) ||
980        (contained_elements > UINT16_MAX) ||
981        (max < contained_elements + s->cadet_received_element_count) )
982   {
983     GNUNET_break_op (0);
984     return GNUNET_SYSERR;
985   }
986   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
987               "Received %u crypto values from Alice\n",
988               (unsigned int) contained_elements);
989
990   payload = (const struct GNUNET_CRYPTO_PaillierCiphertext *) &msg[1];
991   if (NULL == s->e_a)
992     s->e_a = GNUNET_malloc (sizeof (struct GNUNET_CRYPTO_PaillierCiphertext) *
993                             max);
994   memcpy (&s->e_a[s->cadet_received_element_count],
995           payload,
996           sizeof (struct GNUNET_CRYPTO_PaillierCiphertext) * contained_elements);
997   s->cadet_received_element_count += contained_elements;
998
999   if ( (s->cadet_received_element_count == max) &&
1000        (NULL == s->intersection_op) )
1001   {
1002     /* intersection has finished also on our side, and
1003        we got the full set, so we can proceed with the
1004        CADET response(s) */
1005     transmit_cryptographic_reply (s);
1006   }
1007   GNUNET_CADET_receive_done (s->cadet->channel);
1008   return GNUNET_OK;
1009 }
1010
1011
1012 /**
1013  * Callback for set operation results. Called for each element
1014  * that needs to be removed from the result set.
1015  *
1016  * @param cls closure with the `struct BobServiceSession`
1017  * @param element a result element, only valid if status is #GNUNET_SET_STATUS_OK
1018  * @param status what has happened with the set intersection?
1019  */
1020 static void
1021 cb_intersection_element_removed (void *cls,
1022                                  const struct GNUNET_SET_Element *element,
1023                                  enum GNUNET_SET_Status status)
1024 {
1025   struct BobServiceSession *s = cls;
1026   struct GNUNET_SCALARPRODUCT_Element *se;
1027
1028   switch (status)
1029   {
1030   case GNUNET_SET_STATUS_OK:
1031     /* this element has been removed from the set */
1032     se = GNUNET_CONTAINER_multihashmap_get (s->intersected_elements,
1033                                             element->data);
1034     GNUNET_assert (NULL != se);
1035     LOG (GNUNET_ERROR_TYPE_DEBUG,
1036          "Removed element with key %s and value %lld\n",
1037          GNUNET_h2s (&se->key),
1038          (long long) GNUNET_ntohll (se->value));
1039     GNUNET_assert (GNUNET_YES ==
1040                    GNUNET_CONTAINER_multihashmap_remove (s->intersected_elements,
1041                                                          element->data,
1042                                                          se));
1043     GNUNET_free (se);
1044     return;
1045   case GNUNET_SET_STATUS_DONE:
1046     s->intersection_op = NULL;
1047     GNUNET_break (NULL == s->intersection_set);
1048     GNUNET_CADET_receive_done (s->cadet->channel);
1049     LOG (GNUNET_ERROR_TYPE_DEBUG,
1050          "Finished intersection, %d items remain\n",
1051          GNUNET_CONTAINER_multihashmap_size (s->intersected_elements));
1052     if (s->client_received_element_count ==
1053         GNUNET_CONTAINER_multihashmap_size (s->intersected_elements))
1054     {
1055       /* CADET transmission from Alice is also already done,
1056          start with our own reply */
1057       transmit_cryptographic_reply (s);
1058     }
1059     return;
1060   case GNUNET_SET_STATUS_HALF_DONE:
1061     /* unexpected for intersection */
1062     GNUNET_break (0);
1063     return;
1064   case GNUNET_SET_STATUS_FAILURE:
1065     /* unhandled status code */
1066     LOG (GNUNET_ERROR_TYPE_DEBUG,
1067          "Set intersection failed!\n");
1068     s->intersection_op = NULL;
1069     if (NULL != s->intersection_set)
1070     {
1071       GNUNET_SET_destroy (s->intersection_set);
1072       s->intersection_set = NULL;
1073     }
1074     s->status = GNUNET_SCALARPRODUCT_STATUS_FAILURE;
1075     prepare_client_end_notification (s);
1076     return;
1077   default:
1078     GNUNET_break (0);
1079     return;
1080   }
1081 }
1082
1083
1084 /**
1085  * We've paired up a client session with an incoming CADET request.
1086  * Initiate set intersection work.
1087  *
1088  * @param s client session to start intersection for
1089  */
1090 static void
1091 start_intersection (struct BobServiceSession *s)
1092 {
1093   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1094               "Got session with key %s and %u elements, starting intersection.\n",
1095               GNUNET_h2s (&s->session_id),
1096               (unsigned int) s->total);
1097
1098   s->intersection_op
1099     = GNUNET_SET_prepare (&s->cadet->peer,
1100                           &s->session_id,
1101                           NULL,
1102                           GNUNET_SET_RESULT_REMOVED,
1103                           &cb_intersection_element_removed,
1104                           s);
1105   if (GNUNET_OK !=
1106       GNUNET_SET_commit (s->intersection_op,
1107                          s->intersection_set))
1108   {
1109     GNUNET_break (0);
1110     s->status = GNUNET_SCALARPRODUCT_STATUS_FAILURE;
1111     prepare_client_end_notification (s);
1112     return;
1113   }
1114   GNUNET_SET_destroy (s->intersection_set);
1115   s->intersection_set = NULL;
1116 }
1117
1118
1119 /**
1120  * Handle a request from Alice to calculate a scalarproduct with us (Bob).
1121  *
1122  * @param cls closure (set from #GNUNET_CADET_connect)
1123  * @param channel connection to the other end
1124  * @param channel_ctx place to store the `struct CadetIncomingSession *`
1125  * @param message the actual message
1126  * @return #GNUNET_OK to keep the connection open,
1127  *         #GNUNET_SYSERR to close it (signal serious error)
1128  */
1129 static int
1130 handle_alices_computation_request (void *cls,
1131                                    struct GNUNET_CADET_Channel *channel,
1132                                    void **channel_ctx,
1133                                    const struct GNUNET_MessageHeader *message)
1134 {
1135   struct CadetIncomingSession *in = *channel_ctx;
1136   struct BobServiceSession *s;
1137   const struct ServiceRequestMessage *msg;
1138
1139   msg = (const struct ServiceRequestMessage *) message;
1140   if (GNUNET_YES == in->in_map)
1141   {
1142     GNUNET_break_op (0);
1143     return GNUNET_SYSERR;
1144   }
1145   if (NULL != find_matching_cadet_session (&msg->session_id))
1146   {
1147     /* not unique, got one like this already */
1148     GNUNET_break_op (0);
1149     return GNUNET_SYSERR;
1150   }
1151   in->session_id = msg->session_id;
1152   in->remote_pubkey = msg->public_key;
1153   GNUNET_assert (GNUNET_YES ==
1154                  GNUNET_CONTAINER_multihashmap_put (cadet_sessions,
1155                                                     &in->session_id,
1156                                                     in,
1157                                                     GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY));
1158   s = find_matching_client_session (&in->session_id);
1159   if (NULL == s)
1160   {
1161     /* no client waiting for this request, wait for client */
1162     return GNUNET_OK;
1163   }
1164   GNUNET_assert (NULL == s->cadet);
1165   /* pair them up */
1166   in->s = s;
1167   s->cadet = in;
1168   if (s->client_received_element_count == s->total)
1169     start_intersection (s);
1170   return GNUNET_OK;
1171 }
1172
1173
1174 /**
1175  * Function called for inbound channels on Bob's end.  Does some
1176  * preliminary initialization, more happens after we get Alice's first
1177  * message.
1178  *
1179  * @param cls closure
1180  * @param channel new handle to the channel
1181  * @param initiator peer that started the channel
1182  * @param port unused
1183  * @param options unused
1184  * @return session associated with the channel
1185  */
1186 static void *
1187 cb_channel_incoming (void *cls,
1188                      struct GNUNET_CADET_Channel *channel,
1189                      const struct GNUNET_PeerIdentity *initiator,
1190                      uint32_t port,
1191                      enum GNUNET_CADET_ChannelOption options)
1192 {
1193   struct CadetIncomingSession *in;
1194
1195   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1196               "New incoming channel from peer %s.\n",
1197               GNUNET_i2s (initiator));
1198   in = GNUNET_new (struct CadetIncomingSession);
1199   in->peer = *initiator;
1200   in->channel = channel;
1201   in->cadet_mq = GNUNET_CADET_mq_create (in->channel);
1202   return in;
1203 }
1204
1205
1206 /**
1207  * We're receiving additional set data. Add it to our
1208  * set and if we are done, initiate the transaction.
1209  *
1210  * @param cls closure
1211  * @param client identification of the client
1212  * @param message the actual message
1213  */
1214 static void
1215 GSS_handle_bob_client_message_multipart (void *cls,
1216                                          struct GNUNET_SERVER_Client *client,
1217                                          const struct GNUNET_MessageHeader *message)
1218 {
1219   const struct ComputationBobCryptodataMultipartMessage * msg;
1220   struct BobServiceSession *s;
1221   uint32_t contained_count;
1222   const struct GNUNET_SCALARPRODUCT_Element *elements;
1223   uint32_t i;
1224   uint16_t msize;
1225   struct GNUNET_SET_Element set_elem;
1226   struct GNUNET_SCALARPRODUCT_Element *elem;
1227
1228   s = GNUNET_SERVER_client_get_user_context (client,
1229                                              struct BobServiceSession);
1230   if (NULL == s)
1231   {
1232     /* session needs to already exist */
1233     GNUNET_break (0);
1234     GNUNET_SERVER_receive_done (client,
1235                                 GNUNET_SYSERR);
1236     return;
1237   }
1238   msize = ntohs (message->size);
1239   if (msize < sizeof (struct ComputationBobCryptodataMultipartMessage))
1240   {
1241     GNUNET_break (0);
1242     GNUNET_SERVER_receive_done (client,
1243                                 GNUNET_SYSERR);
1244     return;
1245   }
1246   msg = (const struct ComputationBobCryptodataMultipartMessage *) message;
1247   contained_count = ntohl (msg->element_count_contained);
1248
1249   if ( (msize != (sizeof (struct ComputationBobCryptodataMultipartMessage) +
1250                   contained_count * sizeof (struct GNUNET_SCALARPRODUCT_Element))) ||
1251        (0 == contained_count) ||
1252        (UINT16_MAX < contained_count) ||
1253        (s->total == s->client_received_element_count) ||
1254        (s->total < s->client_received_element_count + contained_count) )
1255   {
1256     GNUNET_break_op (0);
1257     GNUNET_SERVER_receive_done (client,
1258                                 GNUNET_SYSERR);
1259     return;
1260   }
1261   elements = (const struct GNUNET_SCALARPRODUCT_Element *) &msg[1];
1262   for (i = 0; i < contained_count; i++)
1263   {
1264     elem = GNUNET_new (struct GNUNET_SCALARPRODUCT_Element);
1265     memcpy (elem,
1266             &elements[i],
1267             sizeof (struct GNUNET_SCALARPRODUCT_Element));
1268     if (GNUNET_SYSERR ==
1269         GNUNET_CONTAINER_multihashmap_put (s->intersected_elements,
1270                                            &elem->key,
1271                                            elem,
1272                                            GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY))
1273     {
1274       GNUNET_break (0);
1275       GNUNET_free (elem);
1276       continue;
1277     }
1278     set_elem.data = &elem->key;
1279     set_elem.size = sizeof (elem->key);
1280     set_elem.element_type = 0;
1281     GNUNET_SET_add_element (s->intersection_set,
1282                             &set_elem,
1283                             NULL, NULL);
1284   }
1285   s->client_received_element_count += contained_count;
1286   GNUNET_SERVER_receive_done (client,
1287                               GNUNET_OK);
1288   if (s->total != s->client_received_element_count)
1289   {
1290     /* more to come */
1291     return;
1292   }
1293   if (NULL == s->cadet)
1294   {
1295     /* no Alice waiting for this request, wait for Alice */
1296     return;
1297   }
1298   start_intersection (s);
1299 }
1300
1301
1302 /**
1303  * Handler for Bob's a client request message.  Bob is in the response
1304  * role, keep the values + session and waiting for a matching session
1305  * or process a waiting request from Alice.
1306  *
1307  * @param cls closure
1308  * @param client identification of the client
1309  * @param message the actual message
1310  */
1311 static void
1312 GSS_handle_bob_client_message (void *cls,
1313                                struct GNUNET_SERVER_Client *client,
1314                                const struct GNUNET_MessageHeader *message)
1315 {
1316   const struct BobComputationMessage *msg;
1317   struct BobServiceSession *s;
1318   struct CadetIncomingSession *in;
1319   uint32_t contained_count;
1320   uint32_t total_count;
1321   const struct GNUNET_SCALARPRODUCT_Element *elements;
1322   uint32_t i;
1323   struct GNUNET_SET_Element set_elem;
1324   struct GNUNET_SCALARPRODUCT_Element *elem;
1325   uint16_t msize;
1326
1327   s = GNUNET_SERVER_client_get_user_context (client,
1328                                              struct BobServiceSession);
1329   if (NULL != s)
1330   {
1331     /* only one concurrent session per client connection allowed,
1332        simplifies logic a lot... */
1333     GNUNET_break (0);
1334     GNUNET_SERVER_receive_done (client,
1335                                 GNUNET_SYSERR);
1336     return;
1337   }
1338   msize = ntohs (message->size);
1339   if (msize < sizeof (struct BobComputationMessage))
1340   {
1341     GNUNET_break (0);
1342     GNUNET_SERVER_receive_done (client,
1343                                 GNUNET_SYSERR);
1344     return;
1345   }
1346   msg = (const struct BobComputationMessage *) message;
1347   total_count = ntohl (msg->element_count_total);
1348   contained_count = ntohl (msg->element_count_contained);
1349   if ( (0 == total_count) ||
1350        (0 == contained_count) ||
1351        (UINT16_MAX < contained_count) ||
1352        (msize != (sizeof (struct BobComputationMessage) +
1353                   contained_count * sizeof (struct GNUNET_SCALARPRODUCT_Element))) )
1354   {
1355     GNUNET_break_op (0);
1356     GNUNET_SERVER_receive_done (client,
1357                                 GNUNET_SYSERR);
1358     return;
1359   }
1360   if (NULL != find_matching_client_session (&msg->session_key))
1361   {
1362     GNUNET_break (0);
1363     GNUNET_SERVER_receive_done (client,
1364                                 GNUNET_SYSERR);
1365     return;
1366   }
1367
1368   s = GNUNET_new (struct BobServiceSession);
1369   s->status = GNUNET_SCALARPRODUCT_STATUS_ACTIVE;
1370   s->client = client;
1371   s->client_mq = GNUNET_MQ_queue_for_server_client (client);
1372   s->total = total_count;
1373   s->client_received_element_count = contained_count;
1374   s->session_id = msg->session_key;
1375   GNUNET_break (GNUNET_YES ==
1376                 GNUNET_CONTAINER_multihashmap_put (client_sessions,
1377                                                    &s->session_id,
1378                                                    s,
1379                                                    GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY));
1380   elements = (const struct GNUNET_SCALARPRODUCT_Element *) &msg[1];
1381   s->intersected_elements = GNUNET_CONTAINER_multihashmap_create (s->total,
1382                                                                   GNUNET_YES);
1383   s->intersection_set = GNUNET_SET_create (cfg,
1384                                            GNUNET_SET_OPERATION_INTERSECTION);
1385   for (i = 0; i < contained_count; i++)
1386   {
1387     if (0 == GNUNET_ntohll (elements[i].value))
1388       continue;
1389     elem = GNUNET_new (struct GNUNET_SCALARPRODUCT_Element);
1390     memcpy (elem,
1391             &elements[i],
1392             sizeof (struct GNUNET_SCALARPRODUCT_Element));
1393     if (GNUNET_SYSERR ==
1394         GNUNET_CONTAINER_multihashmap_put (s->intersected_elements,
1395                                            &elem->key,
1396                                            elem,
1397                                            GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY))
1398     {
1399       GNUNET_break (0);
1400       GNUNET_free (elem);
1401       continue;
1402     }
1403     set_elem.data = &elem->key;
1404     set_elem.size = sizeof (elem->key);
1405     set_elem.element_type = 0;
1406     GNUNET_SET_add_element (s->intersection_set,
1407                             &set_elem,
1408                             NULL, NULL);
1409     s->used_element_count++;
1410   }
1411   GNUNET_SERVER_client_set_user_context (client,
1412                                          s);
1413   GNUNET_SERVER_receive_done (client,
1414                               GNUNET_YES);
1415   if (s->total != s->client_received_element_count)
1416   {
1417     /* multipart msg */
1418     return;
1419   }
1420   in = find_matching_cadet_session (&s->session_id);
1421   if (NULL == in)
1422   {
1423     /* nothing yet, wait for Alice */
1424     return;
1425   }
1426   GNUNET_assert (NULL == in->s);
1427   /* pair them up */
1428   in->s = s;
1429   s->cadet = in;
1430   start_intersection (s);
1431 }
1432
1433
1434 /**
1435  * Task run during shutdown.
1436  *
1437  * @param cls unused
1438  */
1439 static void
1440 shutdown_task (void *cls)
1441 {
1442   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1443               "Shutting down, initiating cleanup.\n");
1444   // FIXME: we have to cut our connections to CADET first!
1445   if (NULL != my_cadet)
1446   {
1447     GNUNET_CADET_disconnect (my_cadet);
1448     my_cadet = NULL;
1449   }
1450   GNUNET_CONTAINER_multihashmap_destroy (client_sessions);
1451   client_sessions = NULL;
1452   GNUNET_CONTAINER_multihashmap_destroy (cadet_sessions);
1453   cadet_sessions = NULL;
1454 }
1455
1456
1457 /**
1458  * A client disconnected.
1459  *
1460  * Remove the associated session(s), release data structures
1461  * and cancel pending outgoing transmissions to the client.
1462  *
1463  * @param cls closure, NULL
1464  * @param client identification of the client
1465  */
1466 static void
1467 handle_client_disconnect (void *cls,
1468                           struct GNUNET_SERVER_Client *client)
1469 {
1470   struct BobServiceSession *s;
1471
1472   if (NULL == client)
1473     return;
1474   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1475               "Client disconnected from us.\n");
1476   s = GNUNET_SERVER_client_get_user_context (client,
1477                                              struct BobServiceSession);
1478   if (NULL == s)
1479     return;
1480   s->client = NULL;
1481   destroy_service_session (s);
1482 }
1483
1484
1485 /**
1486  * Initialization of the program and message handlers
1487  *
1488  * @param cls closure
1489  * @param server the initialized server
1490  * @param c configuration to use
1491  */
1492 static void
1493 run (void *cls,
1494      struct GNUNET_SERVER_Handle *server,
1495      const struct GNUNET_CONFIGURATION_Handle *c)
1496 {
1497   static const struct GNUNET_SERVER_MessageHandler server_handlers[] = {
1498     { &GSS_handle_bob_client_message, NULL,
1499       GNUNET_MESSAGE_TYPE_SCALARPRODUCT_CLIENT_TO_BOB,
1500       0},
1501     { &GSS_handle_bob_client_message_multipart, NULL,
1502       GNUNET_MESSAGE_TYPE_SCALARPRODUCT_CLIENT_MUTLIPART_BOB,
1503       0},
1504     { NULL, NULL, 0, 0}
1505   };
1506   static const struct GNUNET_CADET_MessageHandler cadet_handlers[] = {
1507     { &handle_alices_computation_request,
1508       GNUNET_MESSAGE_TYPE_SCALARPRODUCT_SESSION_INITIALIZATION,
1509       sizeof (struct ServiceRequestMessage) },
1510     { &handle_alices_cryptodata_message,
1511       GNUNET_MESSAGE_TYPE_SCALARPRODUCT_ALICE_CRYPTODATA,
1512       0},
1513     { NULL, 0, 0}
1514   };
1515   static const uint32_t ports[] = {
1516     GNUNET_APPLICATION_TYPE_SCALARPRODUCT,
1517     0
1518   };
1519
1520   cfg = c;
1521   /*
1522     offset has to be sufficiently small to allow computation of:
1523     m1+m2 mod n == (S + a) + (S + b) mod n,
1524     if we have more complex operations, this factor needs to be lowered */
1525   my_offset = gcry_mpi_new (GNUNET_CRYPTO_PAILLIER_BITS / 3);
1526   gcry_mpi_set_bit (my_offset,
1527                     GNUNET_CRYPTO_PAILLIER_BITS / 3);
1528
1529   GNUNET_CRYPTO_paillier_create (&my_pubkey,
1530                                  &my_privkey);
1531   GNUNET_SERVER_add_handlers (server,
1532                               server_handlers);
1533   GNUNET_SERVER_disconnect_notify (server,
1534                                    &handle_client_disconnect,
1535                                    NULL);
1536   client_sessions = GNUNET_CONTAINER_multihashmap_create (128,
1537                                                           GNUNET_YES);
1538   cadet_sessions = GNUNET_CONTAINER_multihashmap_create (128,
1539                                                          GNUNET_YES);
1540   my_cadet = GNUNET_CADET_connect (cfg, NULL,
1541                                    &cb_channel_incoming,
1542                                    &cb_channel_destruction,
1543                                    cadet_handlers,
1544                                    ports);
1545   if (NULL == my_cadet)
1546   {
1547     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1548                 _("Connect to CADET failed\n"));
1549     GNUNET_SCHEDULER_shutdown ();
1550     return;
1551   }
1552   GNUNET_SCHEDULER_add_shutdown (&shutdown_task,
1553                                  NULL);
1554 }
1555
1556
1557 /**
1558  * The main function for the scalarproduct service.
1559  *
1560  * @param argc number of arguments from the command line
1561  * @param argv command line arguments
1562  * @return 0 ok, 1 on error
1563  */
1564 int
1565 main (int argc,
1566       char *const *argv)
1567 {
1568   return (GNUNET_OK ==
1569           GNUNET_SERVICE_run (argc, argv,
1570                               "scalarproduct-bob",
1571                               GNUNET_SERVICE_OPTION_NONE,
1572                               &run, NULL)) ? 0 : 1;
1573 }
1574
1575 /* end of gnunet-service-scalarproduct_bob.c */