-simplify
[oweals/gnunet.git] / src / scalarproduct / gnunet-service-scalarproduct_bob.c
1 /*
2      This file is part of GNUnet.
3      Copyright (C) 2013, 2014 Christian Grothoff (and other contributing authors)
4
5      GNUnet is free software; you can redistribute it and/or modify
6      it under the terms of the GNU General Public License as published
7      by the Free Software Foundation; either version 3, or (at your
8      option) any later version.
9
10      GNUnet is distributed in the hope that it will be useful, but
11      WITHOUT ANY WARRANTY; without even the implied warranty of
12      MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13      General Public License for more details.
14
15      You should have received a copy of the GNU General Public License
16      along with GNUnet; see the file COPYING.  If not, write to the
17      Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
18      Boston, MA 02110-1301, USA.
19  */
20 /**
21  * @file scalarproduct/gnunet-service-scalarproduct_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   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
464               "Sending session-end notification with status %d to client for session %s\n",
465               session->status,
466               GNUNET_h2s (&session->session_id));
467   e = GNUNET_MQ_msg (msg,
468                      GNUNET_MESSAGE_TYPE_SCALARPRODUCT_RESULT);
469   msg->range = 0;
470   msg->product_length = htonl (0);
471   msg->status = htonl (session->status);
472   GNUNET_MQ_send (session->client_mq,
473                   e);
474 }
475
476
477 /**
478  * Function called whenever a channel is destroyed.  Should clean up
479  * any associated state.
480  *
481  * It must NOT call #GNUNET_CADET_channel_destroy() on the channel.
482  *
483  * @param cls closure (set from #GNUNET_CADET_connect())
484  * @param channel connection to the other end (henceforth invalid)
485  * @param channel_ctx place where local state associated
486  *                   with the channel is stored
487  */
488 static void
489 cb_channel_destruction (void *cls,
490                         const struct GNUNET_CADET_Channel *channel,
491                         void *channel_ctx)
492 {
493   struct CadetIncomingSession *in = channel_ctx;
494   struct BobServiceSession *s;
495
496   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
497               "Peer disconnected, terminating session %s with peer %s\n",
498               GNUNET_h2s (&in->session_id),
499               GNUNET_i2s (&in->peer));
500   if (NULL != in->cadet_mq)
501   {
502     GNUNET_MQ_destroy (in->cadet_mq);
503     in->cadet_mq = NULL;
504   }
505   in->channel = NULL;
506   if (NULL != (s = in->s))
507   {
508     if (GNUNET_SCALARPRODUCT_STATUS_ACTIVE == s->status)
509     {
510       s->status = GNUNET_SCALARPRODUCT_STATUS_FAILURE;
511       prepare_client_end_notification (s);
512     }
513   }
514   destroy_cadet_session (in);
515 }
516
517
518 /**
519  * MQ finished giving our last message to CADET, now notify
520  * the client that we are finished.
521  */
522 static void
523 bob_cadet_done_cb (void *cls)
524 {
525   struct BobServiceSession *session = cls;
526
527   session->status = GNUNET_SCALARPRODUCT_STATUS_SUCCESS;
528   prepare_client_end_notification (session);
529 }
530
531
532 /**
533  * Maximum count of elements we can put into a multipart message
534  */
535 #define ELEMENT_CAPACITY ((GNUNET_CONSTANTS_MAX_CADET_MESSAGE_SIZE - 1 - sizeof (struct BobCryptodataMultipartMessage)) / sizeof (struct GNUNET_CRYPTO_PaillierCiphertext))
536
537
538 /**
539  * Send a multipart chunk of a service response from Bob to Alice.
540  * This element only contains the two permutations of R, R'.
541  *
542  * @param s the associated service session
543  */
544 static void
545 transmit_bobs_cryptodata_message_multipart (struct BobServiceSession *s)
546 {
547   struct GNUNET_CRYPTO_PaillierCiphertext *payload;
548   struct BobCryptodataMultipartMessage *msg;
549   struct GNUNET_MQ_Envelope *e;
550   unsigned int i;
551   unsigned int j;
552   uint32_t todo_count;
553
554   while (s->cadet_transmitted_element_count != s->used_element_count)
555   {
556     todo_count = s->used_element_count - s->cadet_transmitted_element_count;
557     if (todo_count > ELEMENT_CAPACITY / 2)
558       todo_count = ELEMENT_CAPACITY / 2;
559
560     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
561                 "Sending %u additional crypto values to Alice\n",
562                 (unsigned int) todo_count);
563     e = GNUNET_MQ_msg_extra (msg,
564                              todo_count * sizeof (struct GNUNET_CRYPTO_PaillierCiphertext) * 2,
565                              GNUNET_MESSAGE_TYPE_SCALARPRODUCT_BOB_CRYPTODATA_MULTIPART);
566     msg->contained_element_count = htonl (todo_count);
567     payload = (struct GNUNET_CRYPTO_PaillierCiphertext *) &msg[1];
568     for (i = s->cadet_transmitted_element_count, j = 0; i < s->cadet_transmitted_element_count + todo_count; i++)
569     {
570       //r[i][p] and r[i][q]
571       memcpy (&payload[j++],
572               &s->r[i],
573               sizeof (struct GNUNET_CRYPTO_PaillierCiphertext));
574       memcpy (&payload[j++],
575               &s->r_prime[i],
576               sizeof (struct GNUNET_CRYPTO_PaillierCiphertext));
577     }
578     s->cadet_transmitted_element_count += todo_count;
579     if (s->cadet_transmitted_element_count == s->used_element_count)
580       GNUNET_MQ_notify_sent (e,
581                              &bob_cadet_done_cb,
582                              s);
583     GNUNET_MQ_send (s->cadet->cadet_mq,
584                     e);
585   }
586   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
587               "All values queued for Alice, Bob is done\n");
588 }
589
590
591 /**
592  * Bob generates the response message to be sent to Alice after
593  * computing the values (1), (2), S and S'.
594  *
595  *  (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)})$
596  *  (2)[]: $E_A(a_{pi'(i)}) times E_A(- r_{pi'(i)}) &= E_A(a_{pi'(i)} - r_{pi'(i)})$
597  *      S: $S := E_A(sum (r_i + b_i)^2)$
598  *     S': $S' := E_A(sum r_i^2)$
599  *
600  * @param s the associated requesting session with Alice
601  */
602 static void
603 transmit_bobs_cryptodata_message (struct BobServiceSession *s)
604 {
605   struct BobCryptodataMessage *msg;
606   struct GNUNET_MQ_Envelope *e;
607   struct GNUNET_CRYPTO_PaillierCiphertext *payload;
608   unsigned int i;
609
610   s->cadet_transmitted_element_count
611     = ((GNUNET_CONSTANTS_MAX_CADET_MESSAGE_SIZE - 1 - sizeof (struct BobCryptodataMessage))
612        / sizeof (struct GNUNET_CRYPTO_PaillierCiphertext) / 2) - 1;
613   if (s->cadet_transmitted_element_count > s->used_element_count)
614     s->cadet_transmitted_element_count = s->used_element_count;
615
616   e = GNUNET_MQ_msg_extra (msg,
617                            (2 + s->cadet_transmitted_element_count * 2)
618                            * sizeof (struct GNUNET_CRYPTO_PaillierCiphertext),
619                            GNUNET_MESSAGE_TYPE_SCALARPRODUCT_BOB_CRYPTODATA);
620   msg->contained_element_count = htonl (s->cadet_transmitted_element_count);
621
622   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
623               "Sending %u/%u crypto values to Alice\n",
624               (unsigned int) s->cadet_transmitted_element_count,
625               (unsigned int) s->used_element_count);
626
627   payload = (struct GNUNET_CRYPTO_PaillierCiphertext *) &msg[1];
628   memcpy (&payload[0],
629           &s->s,
630           sizeof (struct GNUNET_CRYPTO_PaillierCiphertext));
631   memcpy (&payload[1],
632           &s->s_prime,
633           sizeof (struct GNUNET_CRYPTO_PaillierCiphertext));
634
635   payload = &payload[2];
636   // convert k[][]
637   for (i = 0; i < s->cadet_transmitted_element_count; i++)
638   {
639     //k[i][p] and k[i][q]
640     memcpy (&payload[i * 2],
641             &s->r[i],
642             sizeof (struct GNUNET_CRYPTO_PaillierCiphertext));
643     memcpy (&payload[i * 2 + 1],
644             &s->r_prime[i],
645             sizeof (struct GNUNET_CRYPTO_PaillierCiphertext));
646   }
647   if (s->cadet_transmitted_element_count == s->used_element_count)
648     GNUNET_MQ_notify_sent (e,
649                            &bob_cadet_done_cb,
650                            s);
651   GNUNET_MQ_send (s->cadet->cadet_mq,
652                   e);
653   transmit_bobs_cryptodata_message_multipart (s);
654 }
655 #undef ELEMENT_CAPACITY
656
657
658 /**
659  * Computes the square sum over a vector of a given length.
660  *
661  * @param vector the vector to compute over
662  * @param length the length of the vector
663  * @return an MPI value containing the calculated sum, never NULL
664  * TODO: code duplication with Alice!
665  */
666 static gcry_mpi_t
667 compute_square_sum (const gcry_mpi_t *vector,
668                     uint32_t length)
669 {
670   gcry_mpi_t elem;
671   gcry_mpi_t sum;
672   uint32_t i;
673
674   GNUNET_assert (NULL != (sum = gcry_mpi_new (0)));
675   GNUNET_assert (NULL != (elem = gcry_mpi_new (0)));
676   for (i = 0; i < length; i++)
677   {
678     gcry_mpi_mul (elem, vector[i], vector[i]);
679     gcry_mpi_add (sum, sum, elem);
680   }
681   gcry_mpi_release (elem);
682   return sum;
683 }
684
685
686 /**
687  * Compute the values
688  *  (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)})$
689  *  (2)[]: $E_A(a_{pi'(i)}) otimes E_A(- r_{pi'(i)}) &= E_A(a_{pi'(i)} - r_{pi'(i)})$
690  *      S: $S := E_A(sum (r_i + b_i)^2)$
691  *     S': $S' := E_A(sum r_i^2)$
692  *
693  * @param request the requesting session + bob's requesting peer
694  * @return #GNUNET_OK on success
695  */
696 static int
697 compute_service_response (struct BobServiceSession *session)
698 {
699   uint32_t i;
700   unsigned int *p;
701   unsigned int *q;
702   uint32_t count;
703   gcry_mpi_t *rand;
704   gcry_mpi_t tmp;
705   const struct MpiElement *b;
706   struct GNUNET_CRYPTO_PaillierCiphertext *a;
707   struct GNUNET_CRYPTO_PaillierCiphertext *r;
708   struct GNUNET_CRYPTO_PaillierCiphertext *r_prime;
709
710   count = session->used_element_count;
711   a = session->e_a;
712   b = session->sorted_elements;
713   q = GNUNET_CRYPTO_random_permute (GNUNET_CRYPTO_QUALITY_WEAK,
714                                     count);
715   p = GNUNET_CRYPTO_random_permute (GNUNET_CRYPTO_QUALITY_WEAK,
716                                     count);
717   rand = GNUNET_malloc (sizeof (gcry_mpi_t) * count);
718   for (i = 0; i < count; i++)
719     GNUNET_assert (NULL != (rand[i] = gcry_mpi_new (0)));
720   r = GNUNET_malloc (sizeof (struct GNUNET_CRYPTO_PaillierCiphertext) * count);
721   r_prime = GNUNET_malloc (sizeof (struct GNUNET_CRYPTO_PaillierCiphertext) * count);
722
723   for (i = 0; i < count; i++)
724   {
725     int32_t svalue;
726
727     svalue = (int32_t) GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_WEAK,
728                                                  UINT32_MAX);
729     // long to gcry_mpi_t
730     if (svalue < 0)
731       gcry_mpi_sub_ui (rand[i],
732                        rand[i],
733                        - svalue);
734     else
735       rand[i] = gcry_mpi_set_ui (rand[i], svalue);
736   }
737
738   tmp = gcry_mpi_new (0);
739   // encrypt the element
740   // for the sake of readability I decided to have dedicated permutation
741   // vectors, which get rid of all the lookups in p/q.
742   // however, ap/aq are not absolutely necessary but are just abstraction
743   // Calculate Kp = E(S + a_pi) (+) E(S - r_pi - b_pi)
744   for (i = 0; i < count; i++)
745   {
746     // E(S - r_pi - b_pi)
747     gcry_mpi_sub (tmp, my_offset, rand[p[i]]);
748     gcry_mpi_sub (tmp, tmp, b[p[i]].value);
749     GNUNET_assert (2 ==
750                    GNUNET_CRYPTO_paillier_encrypt (&session->cadet->remote_pubkey,
751                                                    tmp,
752                                                    2,
753                                                    &r[i]));
754
755     // E(S - r_pi - b_pi) * E(S + a_pi) ==  E(2*S + a - r - b)
756     if (GNUNET_OK !=
757         GNUNET_CRYPTO_paillier_hom_add (&session->cadet->remote_pubkey,
758                                         &r[i],
759                                         &a[p[i]],
760                                         &r[i]))
761     {
762       GNUNET_break_op (0);
763       goto error_cleanup;
764     }
765   }
766
767   // Calculate Kq = E(S + a_qi) (+) E(S - r_qi)
768   for (i = 0; i < count; i++)
769   {
770     // E(S - r_qi)
771     gcry_mpi_sub (tmp, my_offset, rand[q[i]]);
772     GNUNET_assert (2 ==
773                    GNUNET_CRYPTO_paillier_encrypt (&session->cadet->remote_pubkey,
774                                                    tmp,
775                                                    2,
776                                                    &r_prime[i]));
777
778     // E(S - r_qi) * E(S + a_qi) == E(2*S + a_qi - r_qi)
779     if (GNUNET_OK !=
780         GNUNET_CRYPTO_paillier_hom_add (&session->cadet->remote_pubkey,
781                                         &r_prime[i],
782                                         &a[q[i]],
783                                         &r_prime[i]))
784     {
785       GNUNET_break_op (0);
786       goto error_cleanup;
787     }
788   }
789   gcry_mpi_release (tmp);
790
791   // Calculate S' =  E(SUM( r_i^2 ))
792   tmp = compute_square_sum (rand, count);
793   GNUNET_assert (1 ==
794                  GNUNET_CRYPTO_paillier_encrypt (&session->cadet->remote_pubkey,
795                                                  tmp,
796                                                  1,
797                                                  &session->s_prime));
798   gcry_mpi_release (tmp);
799
800   // Calculate S = E(SUM( (r_i + b_i)^2 ))
801   for (i = 0; i < count; i++)
802     gcry_mpi_add (rand[i], rand[i], b[i].value);
803   tmp = compute_square_sum (rand, count);
804   GNUNET_assert (1 ==
805                  GNUNET_CRYPTO_paillier_encrypt (&session->cadet->remote_pubkey,
806                                                  tmp,
807                                                  1,
808                                                  &session->s));
809   gcry_mpi_release (tmp);
810
811   session->r = r;
812   session->r_prime = r_prime;
813
814   for (i = 0; i < count; i++)
815     gcry_mpi_release (rand[i]);
816   GNUNET_free (session->e_a);
817   session->e_a = NULL;
818   GNUNET_free (p);
819   GNUNET_free (q);
820   GNUNET_free (rand);
821   return GNUNET_OK;
822
823  error_cleanup:
824   GNUNET_free (r);
825   GNUNET_free (r_prime);
826   gcry_mpi_release (tmp);
827   GNUNET_free (p);
828   GNUNET_free (q);
829   for (i = 0; i < count; i++)
830     gcry_mpi_release (rand[i]);
831   GNUNET_free (rand);
832   return GNUNET_SYSERR;
833 }
834
835
836 /**
837  * Iterator to copy over messages from the hash map
838  * into an array for sorting.
839  *
840  * @param cls the `struct BobServiceSession *`
841  * @param key the key (unused)
842  * @param value the `struct GNUNET_SCALARPRODUCT_Element *`
843  * TODO: code duplication with Alice!
844  */
845 static int
846 copy_element_cb (void *cls,
847                  const struct GNUNET_HashCode *key,
848                  void *value)
849 {
850   struct BobServiceSession *s = cls;
851   struct GNUNET_SCALARPRODUCT_Element *e = value;
852   gcry_mpi_t mval;
853   int64_t val;
854
855   mval = gcry_mpi_new (0);
856   val = (int64_t) GNUNET_ntohll (e->value);
857   if (0 > val)
858     gcry_mpi_sub_ui (mval, mval, -val);
859   else
860     gcry_mpi_add_ui (mval, mval, val);
861   s->sorted_elements [s->used_element_count].value = mval;
862   s->sorted_elements [s->used_element_count].key = &e->key;
863   s->used_element_count++;
864   return GNUNET_OK;
865 }
866
867
868 /**
869  * Compare two `struct MpiValue`s by key for sorting.
870  *
871  * @param a pointer to first `struct MpiValue *`
872  * @param b pointer to first `struct MpiValue *`
873  * @return -1 for a < b, 0 for a=b, 1 for a > b.
874  * TODO: code duplication with Alice!
875  */
876 static int
877 element_cmp (const void *a,
878              const void *b)
879 {
880   const struct MpiElement *ma = a;
881   const struct MpiElement *mb = b;
882
883   return GNUNET_CRYPTO_hash_cmp (ma->key,
884                                  mb->key);
885 }
886
887
888 /**
889  * Intersection operation and receiving data via CADET from
890  * Alice are both done, compute and transmit our reply via
891  * CADET.
892  *
893  * @param s session to transmit reply for.
894  */
895 static void
896 transmit_cryptographic_reply (struct BobServiceSession *s)
897 {
898   struct GNUNET_CADET_Channel *channel;
899
900   /* TODO: code duplication with Alice! */
901   LOG (GNUNET_ERROR_TYPE_DEBUG,
902        "Received everything, building reply for Alice\n");
903   s->sorted_elements
904     = GNUNET_malloc (GNUNET_CONTAINER_multihashmap_size (s->intersected_elements) *
905                      sizeof (struct MpiElement));
906   s->used_element_count = 0;
907   GNUNET_CONTAINER_multihashmap_iterate (s->intersected_elements,
908                                          &copy_element_cb,
909                                          s);
910   qsort (s->sorted_elements,
911          s->used_element_count,
912          sizeof (struct MpiElement),
913          &element_cmp);
914   if (GNUNET_OK !=
915       compute_service_response (s))
916   {
917     channel = s->cadet->channel;
918     s->cadet->channel = NULL;
919     GNUNET_CADET_channel_destroy (channel);
920     return;
921   }
922   transmit_bobs_cryptodata_message (s);
923 }
924
925
926 /**
927  * Handle a multipart-chunk of a request from another service to
928  * calculate a scalarproduct with us.
929  *
930  * @param cls closure (set from #GNUNET_CADET_connect)
931  * @param channel connection to the other end
932  * @param channel_ctx place to store local state associated with the @a channel
933  * @param message the actual message
934  * @return #GNUNET_OK to keep the connection open,
935  *         #GNUNET_SYSERR to close it (signal serious error)
936  */
937 static int
938 handle_alices_cryptodata_message (void *cls,
939                                   struct GNUNET_CADET_Channel *channel,
940                                   void **channel_ctx,
941                                   const struct GNUNET_MessageHeader *message)
942 {
943   struct CadetIncomingSession *in = *channel_ctx;
944   struct BobServiceSession *s;
945   const struct AliceCryptodataMessage *msg;
946   const struct GNUNET_CRYPTO_PaillierCiphertext *payload;
947   uint32_t contained_elements;
948   size_t msg_length;
949   uint16_t msize;
950   unsigned int max;
951
952   if (NULL == in)
953   {
954     GNUNET_break_op (0);
955     return GNUNET_SYSERR;
956   }
957   s = in->s;
958   if (NULL == s)
959   {
960     GNUNET_break_op (0);
961     return GNUNET_SYSERR;
962   }
963   msize = ntohs (message->size);
964   if (msize <= sizeof (struct AliceCryptodataMessage))
965   {
966     GNUNET_break_op (0);
967     return GNUNET_SYSERR;
968   }
969   msg = (const struct AliceCryptodataMessage *) message;
970   contained_elements = ntohl (msg->contained_element_count);
971   /* Our intersection may still be ongoing, but this is nevertheless
972      an upper bound on the required array size */
973   max = GNUNET_CONTAINER_multihashmap_size (s->intersected_elements);
974   msg_length = sizeof (struct AliceCryptodataMessage)
975     + contained_elements * sizeof (struct GNUNET_CRYPTO_PaillierCiphertext);
976   if ( (msize != msg_length) ||
977        (0 == contained_elements) ||
978        (contained_elements > UINT16_MAX) ||
979        (max < contained_elements + s->cadet_received_element_count) )
980   {
981     GNUNET_break_op (0);
982     return GNUNET_SYSERR;
983   }
984   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
985               "Received %u crypto values from Alice\n",
986               (unsigned int) contained_elements);
987
988   payload = (const struct GNUNET_CRYPTO_PaillierCiphertext *) &msg[1];
989   if (NULL == s->e_a)
990     s->e_a = GNUNET_malloc (sizeof (struct GNUNET_CRYPTO_PaillierCiphertext) *
991                             max);
992   memcpy (&s->e_a[s->cadet_received_element_count],
993           payload,
994           sizeof (struct GNUNET_CRYPTO_PaillierCiphertext) * contained_elements);
995   s->cadet_received_element_count += contained_elements;
996
997   if ( (s->cadet_received_element_count == max) &&
998        (NULL == s->intersection_op) )
999   {
1000     /* intersection has finished also on our side, and
1001        we got the full set, so we can proceed with the
1002        CADET response(s) */
1003     transmit_cryptographic_reply (s);
1004   }
1005   GNUNET_CADET_receive_done (s->cadet->channel);
1006   return GNUNET_OK;
1007 }
1008
1009
1010 /**
1011  * Callback for set operation results. Called for each element
1012  * that needs to be removed from the result set.
1013  *
1014  * @param cls closure with the `struct BobServiceSession`
1015  * @param element a result element, only valid if status is #GNUNET_SET_STATUS_OK
1016  * @param status what has happened with the set intersection?
1017  */
1018 static void
1019 cb_intersection_element_removed (void *cls,
1020                                  const struct GNUNET_SET_Element *element,
1021                                  enum GNUNET_SET_Status status)
1022 {
1023   struct BobServiceSession *s = cls;
1024   struct GNUNET_SCALARPRODUCT_Element *se;
1025
1026   switch (status)
1027   {
1028   case GNUNET_SET_STATUS_OK:
1029     /* this element has been removed from the set */
1030     se = GNUNET_CONTAINER_multihashmap_get (s->intersected_elements,
1031                                             element->data);
1032     GNUNET_assert (NULL != se);
1033     LOG (GNUNET_ERROR_TYPE_DEBUG,
1034          "Removed element with key %s and value %lld\n",
1035          GNUNET_h2s (&se->key),
1036          (long long) GNUNET_ntohll (se->value));
1037     GNUNET_assert (GNUNET_YES ==
1038                    GNUNET_CONTAINER_multihashmap_remove (s->intersected_elements,
1039                                                          element->data,
1040                                                          se));
1041     GNUNET_free (se);
1042     return;
1043   case GNUNET_SET_STATUS_DONE:
1044     s->intersection_op = NULL;
1045     GNUNET_break (NULL == s->intersection_set);
1046     GNUNET_CADET_receive_done (s->cadet->channel);
1047     LOG (GNUNET_ERROR_TYPE_DEBUG,
1048          "Finished intersection, %d items remain\n",
1049          GNUNET_CONTAINER_multihashmap_size (s->intersected_elements));
1050     if (s->client_received_element_count ==
1051         GNUNET_CONTAINER_multihashmap_size (s->intersected_elements))
1052     {
1053       /* CADET transmission from Alice is also already done,
1054          start with our own reply */
1055       transmit_cryptographic_reply (s);
1056     }
1057     return;
1058   case GNUNET_SET_STATUS_HALF_DONE:
1059     /* unexpected for intersection */
1060     GNUNET_break (0);
1061     return;
1062   case GNUNET_SET_STATUS_FAILURE:
1063     /* unhandled status code */
1064     LOG (GNUNET_ERROR_TYPE_DEBUG,
1065          "Set intersection failed!\n");
1066     s->intersection_op = NULL;
1067     if (NULL != s->intersection_set)
1068     {
1069       GNUNET_SET_destroy (s->intersection_set);
1070       s->intersection_set = NULL;
1071     }
1072     s->status = GNUNET_SCALARPRODUCT_STATUS_FAILURE;
1073     prepare_client_end_notification (s);
1074     return;
1075   default:
1076     GNUNET_break (0);
1077     return;
1078   }
1079 }
1080
1081
1082 /**
1083  * We've paired up a client session with an incoming CADET request.
1084  * Initiate set intersection work.
1085  *
1086  * @param s client session to start intersection for
1087  */
1088 static void
1089 start_intersection (struct BobServiceSession *s)
1090 {
1091   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1092               "Got session with key %s and %u elements, starting intersection.\n",
1093               GNUNET_h2s (&s->session_id),
1094               (unsigned int) s->total);
1095
1096   s->intersection_op
1097     = GNUNET_SET_prepare (&s->cadet->peer,
1098                           &s->session_id,
1099                           NULL,
1100                           GNUNET_SET_RESULT_REMOVED,
1101                           &cb_intersection_element_removed,
1102                           s);
1103   if (GNUNET_OK !=
1104       GNUNET_SET_commit (s->intersection_op,
1105                          s->intersection_set))
1106   {
1107     GNUNET_break (0);
1108     s->status = GNUNET_SCALARPRODUCT_STATUS_FAILURE;
1109     prepare_client_end_notification (s);
1110     return;
1111   }
1112   GNUNET_SET_destroy (s->intersection_set);
1113   s->intersection_set = NULL;
1114 }
1115
1116
1117 /**
1118  * Handle a request from Alice to calculate a scalarproduct with us (Bob).
1119  *
1120  * @param cls closure (set from #GNUNET_CADET_connect)
1121  * @param channel connection to the other end
1122  * @param channel_ctx place to store the `struct CadetIncomingSession *`
1123  * @param message the actual message
1124  * @return #GNUNET_OK to keep the connection open,
1125  *         #GNUNET_SYSERR to close it (signal serious error)
1126  */
1127 static int
1128 handle_alices_computation_request (void *cls,
1129                                    struct GNUNET_CADET_Channel *channel,
1130                                    void **channel_ctx,
1131                                    const struct GNUNET_MessageHeader *message)
1132 {
1133   struct CadetIncomingSession *in = *channel_ctx;
1134   struct BobServiceSession *s;
1135   const struct ServiceRequestMessage *msg;
1136
1137   msg = (const struct ServiceRequestMessage *) message;
1138   if (GNUNET_YES == in->in_map)
1139   {
1140     GNUNET_break_op (0);
1141     return GNUNET_SYSERR;
1142   }
1143   if (NULL != find_matching_cadet_session (&msg->session_id))
1144   {
1145     /* not unique, got one like this already */
1146     GNUNET_break_op (0);
1147     return GNUNET_SYSERR;
1148   }
1149   in->session_id = msg->session_id;
1150   in->remote_pubkey = msg->public_key;
1151   GNUNET_assert (GNUNET_YES ==
1152                  GNUNET_CONTAINER_multihashmap_put (cadet_sessions,
1153                                                     &in->session_id,
1154                                                     in,
1155                                                     GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY));
1156   s = find_matching_client_session (&in->session_id);
1157   if (NULL == s)
1158   {
1159     /* no client waiting for this request, wait for client */
1160     return GNUNET_OK;
1161   }
1162   GNUNET_assert (NULL == s->cadet);
1163   /* pair them up */
1164   in->s = s;
1165   s->cadet = in;
1166   if (s->client_received_element_count == s->total)
1167     start_intersection (s);
1168   return GNUNET_OK;
1169 }
1170
1171
1172 /**
1173  * Function called for inbound channels on Bob's end.  Does some
1174  * preliminary initialization, more happens after we get Alice's first
1175  * message.
1176  *
1177  * @param cls closure
1178  * @param channel new handle to the channel
1179  * @param initiator peer that started the channel
1180  * @param port unused
1181  * @param options unused
1182  * @return session associated with the channel
1183  */
1184 static void *
1185 cb_channel_incoming (void *cls,
1186                      struct GNUNET_CADET_Channel *channel,
1187                      const struct GNUNET_PeerIdentity *initiator,
1188                      uint32_t port,
1189                      enum GNUNET_CADET_ChannelOption options)
1190 {
1191   struct CadetIncomingSession *in;
1192
1193   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1194               "New incoming channel from peer %s.\n",
1195               GNUNET_i2s (initiator));
1196   in = GNUNET_new (struct CadetIncomingSession);
1197   in->peer = *initiator;
1198   in->channel = channel;
1199   in->cadet_mq = GNUNET_CADET_mq_create (in->channel);
1200   return in;
1201 }
1202
1203
1204 /**
1205  * We're receiving additional set data. Add it to our
1206  * set and if we are done, initiate the transaction.
1207  *
1208  * @param cls closure
1209  * @param client identification of the client
1210  * @param message the actual message
1211  */
1212 static void
1213 GSS_handle_bob_client_message_multipart (void *cls,
1214                                          struct GNUNET_SERVER_Client *client,
1215                                          const struct GNUNET_MessageHeader *message)
1216 {
1217   const struct ComputationBobCryptodataMultipartMessage * msg;
1218   struct BobServiceSession *s;
1219   uint32_t contained_count;
1220   const struct GNUNET_SCALARPRODUCT_Element *elements;
1221   uint32_t i;
1222   uint16_t msize;
1223   struct GNUNET_SET_Element set_elem;
1224   struct GNUNET_SCALARPRODUCT_Element *elem;
1225
1226   s = GNUNET_SERVER_client_get_user_context (client,
1227                                              struct BobServiceSession);
1228   if (NULL == s)
1229   {
1230     /* session needs to already exist */
1231     GNUNET_break (0);
1232     GNUNET_SERVER_receive_done (client,
1233                                 GNUNET_SYSERR);
1234     return;
1235   }
1236   msize = ntohs (message->size);
1237   if (msize < sizeof (struct ComputationBobCryptodataMultipartMessage))
1238   {
1239     GNUNET_break (0);
1240     GNUNET_SERVER_receive_done (client,
1241                                 GNUNET_SYSERR);
1242     return;
1243   }
1244   msg = (const struct ComputationBobCryptodataMultipartMessage *) message;
1245   contained_count = ntohl (msg->element_count_contained);
1246
1247   if ( (msize != (sizeof (struct ComputationBobCryptodataMultipartMessage) +
1248                   contained_count * sizeof (struct GNUNET_SCALARPRODUCT_Element))) ||
1249        (0 == contained_count) ||
1250        (UINT16_MAX < contained_count) ||
1251        (s->total == s->client_received_element_count) ||
1252        (s->total < s->client_received_element_count + contained_count) )
1253   {
1254     GNUNET_break_op (0);
1255     GNUNET_SERVER_receive_done (client,
1256                                 GNUNET_SYSERR);
1257     return;
1258   }
1259   elements = (const struct GNUNET_SCALARPRODUCT_Element *) &msg[1];
1260   for (i = 0; i < contained_count; i++)
1261   {
1262     elem = GNUNET_new (struct GNUNET_SCALARPRODUCT_Element);
1263     memcpy (elem,
1264             &elements[i],
1265             sizeof (struct GNUNET_SCALARPRODUCT_Element));
1266     if (GNUNET_SYSERR ==
1267         GNUNET_CONTAINER_multihashmap_put (s->intersected_elements,
1268                                            &elem->key,
1269                                            elem,
1270                                            GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY))
1271     {
1272       GNUNET_break (0);
1273       GNUNET_free (elem);
1274       continue;
1275     }
1276     set_elem.data = &elem->key;
1277     set_elem.size = sizeof (elem->key);
1278     set_elem.element_type = 0;
1279     GNUNET_SET_add_element (s->intersection_set,
1280                             &set_elem,
1281                             NULL, NULL);
1282   }
1283   s->client_received_element_count += contained_count;
1284   GNUNET_SERVER_receive_done (client,
1285                               GNUNET_OK);
1286   if (s->total != s->client_received_element_count)
1287   {
1288     /* more to come */
1289     return;
1290   }
1291   if (NULL == s->cadet)
1292   {
1293     /* no Alice waiting for this request, wait for Alice */
1294     return;
1295   }
1296   start_intersection (s);
1297 }
1298
1299
1300 /**
1301  * Handler for Bob's a client request message.  Bob is in the response
1302  * role, keep the values + session and waiting for a matching session
1303  * or process a waiting request from Alice.
1304  *
1305  * @param cls closure
1306  * @param client identification of the client
1307  * @param message the actual message
1308  */
1309 static void
1310 GSS_handle_bob_client_message (void *cls,
1311                                struct GNUNET_SERVER_Client *client,
1312                                const struct GNUNET_MessageHeader *message)
1313 {
1314   const struct BobComputationMessage *msg;
1315   struct BobServiceSession *s;
1316   struct CadetIncomingSession *in;
1317   uint32_t contained_count;
1318   uint32_t total_count;
1319   const struct GNUNET_SCALARPRODUCT_Element *elements;
1320   uint32_t i;
1321   struct GNUNET_SET_Element set_elem;
1322   struct GNUNET_SCALARPRODUCT_Element *elem;
1323   uint16_t msize;
1324
1325   s = GNUNET_SERVER_client_get_user_context (client,
1326                                              struct BobServiceSession);
1327   if (NULL != s)
1328   {
1329     /* only one concurrent session per client connection allowed,
1330        simplifies logic a lot... */
1331     GNUNET_break (0);
1332     GNUNET_SERVER_receive_done (client,
1333                                 GNUNET_SYSERR);
1334     return;
1335   }
1336   msize = ntohs (message->size);
1337   if (msize < sizeof (struct BobComputationMessage))
1338   {
1339     GNUNET_break (0);
1340     GNUNET_SERVER_receive_done (client,
1341                                 GNUNET_SYSERR);
1342     return;
1343   }
1344   msg = (const struct BobComputationMessage *) message;
1345   total_count = ntohl (msg->element_count_total);
1346   contained_count = ntohl (msg->element_count_contained);
1347   if ( (0 == total_count) ||
1348        (0 == contained_count) ||
1349        (UINT16_MAX < contained_count) ||
1350        (msize != (sizeof (struct BobComputationMessage) +
1351                   contained_count * sizeof (struct GNUNET_SCALARPRODUCT_Element))) )
1352   {
1353     GNUNET_break_op (0);
1354     GNUNET_SERVER_receive_done (client,
1355                                 GNUNET_SYSERR);
1356     return;
1357   }
1358   if (NULL != find_matching_client_session (&msg->session_key))
1359   {
1360     GNUNET_break (0);
1361     GNUNET_SERVER_receive_done (client,
1362                                 GNUNET_SYSERR);
1363     return;
1364   }
1365
1366   s = GNUNET_new (struct BobServiceSession);
1367   s->status = GNUNET_SCALARPRODUCT_STATUS_ACTIVE;
1368   s->client = client;
1369   s->client_mq = GNUNET_MQ_queue_for_server_client (client);
1370   s->total = total_count;
1371   s->client_received_element_count = contained_count;
1372   s->session_id = msg->session_key;
1373   GNUNET_break (GNUNET_YES ==
1374                 GNUNET_CONTAINER_multihashmap_put (client_sessions,
1375                                                    &s->session_id,
1376                                                    s,
1377                                                    GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY));
1378   elements = (const struct GNUNET_SCALARPRODUCT_Element *) &msg[1];
1379   s->intersected_elements = GNUNET_CONTAINER_multihashmap_create (s->total,
1380                                                                   GNUNET_YES);
1381   s->intersection_set = GNUNET_SET_create (cfg,
1382                                            GNUNET_SET_OPERATION_INTERSECTION);
1383   for (i = 0; i < contained_count; i++)
1384   {
1385     if (0 == GNUNET_ntohll (elements[i].value))
1386       continue;
1387     elem = GNUNET_new (struct GNUNET_SCALARPRODUCT_Element);
1388     memcpy (elem,
1389             &elements[i],
1390             sizeof (struct GNUNET_SCALARPRODUCT_Element));
1391     if (GNUNET_SYSERR ==
1392         GNUNET_CONTAINER_multihashmap_put (s->intersected_elements,
1393                                            &elem->key,
1394                                            elem,
1395                                            GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY))
1396     {
1397       GNUNET_break (0);
1398       GNUNET_free (elem);
1399       continue;
1400     }
1401     set_elem.data = &elem->key;
1402     set_elem.size = sizeof (elem->key);
1403     set_elem.element_type = 0;
1404     GNUNET_SET_add_element (s->intersection_set,
1405                             &set_elem,
1406                             NULL, NULL);
1407     s->used_element_count++;
1408   }
1409   GNUNET_SERVER_client_set_user_context (client,
1410                                          s);
1411   GNUNET_SERVER_receive_done (client,
1412                               GNUNET_YES);
1413   if (s->total != s->client_received_element_count)
1414   {
1415     /* multipart msg */
1416     return;
1417   }
1418   in = find_matching_cadet_session (&s->session_id);
1419   if (NULL == in)
1420   {
1421     /* nothing yet, wait for Alice */
1422     return;
1423   }
1424   GNUNET_assert (NULL == in->s);
1425   /* pair them up */
1426   in->s = s;
1427   s->cadet = in;
1428   start_intersection (s);
1429 }
1430
1431
1432 /**
1433  * Task run during shutdown.
1434  *
1435  * @param cls unused
1436  * @param tc unused
1437  */
1438 static void
1439 shutdown_task (void *cls,
1440                const struct GNUNET_SCHEDULER_TaskContext *tc)
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               client);
1477   s = GNUNET_SERVER_client_get_user_context (client,
1478                                              struct BobServiceSession);
1479   if (NULL == s)
1480     return;
1481   s->client = NULL;
1482   destroy_service_session (s);
1483 }
1484
1485
1486 /**
1487  * Initialization of the program and message handlers
1488  *
1489  * @param cls closure
1490  * @param server the initialized server
1491  * @param c configuration to use
1492  */
1493 static void
1494 run (void *cls,
1495      struct GNUNET_SERVER_Handle *server,
1496      const struct GNUNET_CONFIGURATION_Handle *c)
1497 {
1498   static const struct GNUNET_SERVER_MessageHandler server_handlers[] = {
1499     { &GSS_handle_bob_client_message, NULL,
1500       GNUNET_MESSAGE_TYPE_SCALARPRODUCT_CLIENT_TO_BOB,
1501       0},
1502     { &GSS_handle_bob_client_message_multipart, NULL,
1503       GNUNET_MESSAGE_TYPE_SCALARPRODUCT_CLIENT_MUTLIPART_BOB,
1504       0},
1505     { NULL, NULL, 0, 0}
1506   };
1507   static const struct GNUNET_CADET_MessageHandler cadet_handlers[] = {
1508     { &handle_alices_computation_request,
1509       GNUNET_MESSAGE_TYPE_SCALARPRODUCT_SESSION_INITIALIZATION,
1510       sizeof (struct ServiceRequestMessage) },
1511     { &handle_alices_cryptodata_message,
1512       GNUNET_MESSAGE_TYPE_SCALARPRODUCT_ALICE_CRYPTODATA,
1513       0},
1514     { NULL, 0, 0}
1515   };
1516   static const uint32_t ports[] = {
1517     GNUNET_APPLICATION_TYPE_SCALARPRODUCT,
1518     0
1519   };
1520
1521   cfg = c;
1522   /*
1523     offset has to be sufficiently small to allow computation of:
1524     m1+m2 mod n == (S + a) + (S + b) mod n,
1525     if we have more complex operations, this factor needs to be lowered */
1526   my_offset = gcry_mpi_new (GNUNET_CRYPTO_PAILLIER_BITS / 3);
1527   gcry_mpi_set_bit (my_offset,
1528                     GNUNET_CRYPTO_PAILLIER_BITS / 3);
1529
1530   GNUNET_CRYPTO_paillier_create (&my_pubkey,
1531                                  &my_privkey);
1532   GNUNET_SERVER_add_handlers (server,
1533                               server_handlers);
1534   GNUNET_SERVER_disconnect_notify (server,
1535                                    &handle_client_disconnect,
1536                                    NULL);
1537   client_sessions = GNUNET_CONTAINER_multihashmap_create (128,
1538                                                           GNUNET_YES);
1539   cadet_sessions = GNUNET_CONTAINER_multihashmap_create (128,
1540                                                          GNUNET_YES);
1541   my_cadet = GNUNET_CADET_connect (cfg, NULL,
1542                                    &cb_channel_incoming,
1543                                    &cb_channel_destruction,
1544                                    cadet_handlers,
1545                                    ports);
1546   if (NULL == my_cadet)
1547   {
1548     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1549                 _("Connect to CADET failed\n"));
1550     GNUNET_SCHEDULER_shutdown ();
1551     return;
1552   }
1553   GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_FOREVER_REL,
1554                                 &shutdown_task,
1555                                 NULL);
1556 }
1557
1558
1559 /**
1560  * The main function for the scalarproduct service.
1561  *
1562  * @param argc number of arguments from the command line
1563  * @param argv command line arguments
1564  * @return 0 ok, 1 on error
1565  */
1566 int
1567 main (int argc,
1568       char *const *argv)
1569 {
1570   return (GNUNET_OK ==
1571           GNUNET_SERVICE_run (argc, argv,
1572                               "scalarproduct-bob",
1573                               GNUNET_SERVICE_OPTION_NONE,
1574                               &run, NULL)) ? 0 : 1;
1575 }
1576
1577 /* end of gnunet-service-scalarproduct_bob.c */