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