-dead
[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   if (ntohs (message->size) != sizeof (struct ServiceRequestMessage))
1138   {
1139     GNUNET_break_op (0);
1140     return GNUNET_SYSERR;
1141   }
1142   msg = (const struct ServiceRequestMessage *) message;
1143   if (GNUNET_YES == in->in_map)
1144   {
1145     GNUNET_break_op (0);
1146     return GNUNET_SYSERR;
1147   }
1148   if (NULL != find_matching_cadet_session (&msg->session_id))
1149   {
1150     /* not unique, got one like this already */
1151     GNUNET_break_op (0);
1152     return GNUNET_SYSERR;
1153   }
1154   in->session_id = msg->session_id;
1155   in->remote_pubkey = msg->public_key;
1156   GNUNET_assert (GNUNET_YES ==
1157                  GNUNET_CONTAINER_multihashmap_put (cadet_sessions,
1158                                                     &in->session_id,
1159                                                     in,
1160                                                     GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY));
1161   s = find_matching_client_session (&in->session_id);
1162   if (NULL == s)
1163   {
1164     /* no client waiting for this request, wait for client */
1165     return GNUNET_OK;
1166   }
1167   GNUNET_assert (NULL == s->cadet);
1168   /* pair them up */
1169   in->s = s;
1170   s->cadet = in;
1171   if (s->client_received_element_count == s->total)
1172     start_intersection (s);
1173   return GNUNET_OK;
1174 }
1175
1176
1177 /**
1178  * Function called for inbound channels on Bob's end.  Does some
1179  * preliminary initialization, more happens after we get Alice's first
1180  * message.
1181  *
1182  * @param cls closure
1183  * @param channel new handle to the channel
1184  * @param initiator peer that started the channel
1185  * @param port unused
1186  * @param options unused
1187  * @return session associated with the channel
1188  */
1189 static void *
1190 cb_channel_incoming (void *cls,
1191                      struct GNUNET_CADET_Channel *channel,
1192                      const struct GNUNET_PeerIdentity *initiator,
1193                      uint32_t port,
1194                      enum GNUNET_CADET_ChannelOption options)
1195 {
1196   struct CadetIncomingSession *in;
1197
1198   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1199               "New incoming channel from peer %s.\n",
1200               GNUNET_i2s (initiator));
1201   in = GNUNET_new (struct CadetIncomingSession);
1202   in->peer = *initiator;
1203   in->channel = channel;
1204   in->cadet_mq = GNUNET_CADET_mq_create (in->channel);
1205   return in;
1206 }
1207
1208
1209 /**
1210  * We're receiving additional set data. Add it to our
1211  * set and if we are done, initiate the transaction.
1212  *
1213  * @param cls closure
1214  * @param client identification of the client
1215  * @param message the actual message
1216  */
1217 static void
1218 GSS_handle_bob_client_message_multipart (void *cls,
1219                                          struct GNUNET_SERVER_Client *client,
1220                                          const struct GNUNET_MessageHeader *message)
1221 {
1222   const struct ComputationBobCryptodataMultipartMessage * msg;
1223   struct BobServiceSession *s;
1224   uint32_t contained_count;
1225   const struct GNUNET_SCALARPRODUCT_Element *elements;
1226   uint32_t i;
1227   uint16_t msize;
1228   struct GNUNET_SET_Element set_elem;
1229   struct GNUNET_SCALARPRODUCT_Element *elem;
1230
1231   s = GNUNET_SERVER_client_get_user_context (client,
1232                                              struct BobServiceSession);
1233   if (NULL == s)
1234   {
1235     /* session needs to already exist */
1236     GNUNET_break (0);
1237     GNUNET_SERVER_receive_done (client,
1238                                 GNUNET_SYSERR);
1239     return;
1240   }
1241   msize = ntohs (message->size);
1242   if (msize < sizeof (struct ComputationBobCryptodataMultipartMessage))
1243   {
1244     GNUNET_break (0);
1245     GNUNET_SERVER_receive_done (client,
1246                                 GNUNET_SYSERR);
1247     return;
1248   }
1249   msg = (const struct ComputationBobCryptodataMultipartMessage *) message;
1250   contained_count = ntohl (msg->element_count_contained);
1251
1252   if ( (msize != (sizeof (struct ComputationBobCryptodataMultipartMessage) +
1253                   contained_count * sizeof (struct GNUNET_SCALARPRODUCT_Element))) ||
1254        (0 == contained_count) ||
1255        (UINT16_MAX < contained_count) ||
1256        (s->total == s->client_received_element_count) ||
1257        (s->total < s->client_received_element_count + contained_count) )
1258   {
1259     GNUNET_break_op (0);
1260     GNUNET_SERVER_receive_done (client,
1261                                 GNUNET_SYSERR);
1262     return;
1263   }
1264   elements = (const struct GNUNET_SCALARPRODUCT_Element *) &msg[1];
1265   for (i = 0; i < contained_count; i++)
1266   {
1267     elem = GNUNET_new (struct GNUNET_SCALARPRODUCT_Element);
1268     memcpy (elem,
1269             &elements[i],
1270             sizeof (struct GNUNET_SCALARPRODUCT_Element));
1271     if (GNUNET_SYSERR ==
1272         GNUNET_CONTAINER_multihashmap_put (s->intersected_elements,
1273                                            &elem->key,
1274                                            elem,
1275                                            GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY))
1276     {
1277       GNUNET_break (0);
1278       GNUNET_free (elem);
1279       continue;
1280     }
1281     set_elem.data = &elem->key;
1282     set_elem.size = sizeof (elem->key);
1283     set_elem.element_type = 0;
1284     GNUNET_SET_add_element (s->intersection_set,
1285                             &set_elem,
1286                             NULL, NULL);
1287   }
1288   s->client_received_element_count += contained_count;
1289   GNUNET_SERVER_receive_done (client,
1290                               GNUNET_OK);
1291   if (s->total != s->client_received_element_count)
1292   {
1293     /* more to come */
1294     return;
1295   }
1296   if (NULL == s->cadet)
1297   {
1298     /* no Alice waiting for this request, wait for Alice */
1299     return;
1300   }
1301   start_intersection (s);
1302 }
1303
1304
1305 /**
1306  * Handler for Bob's a client request message.  Bob is in the response
1307  * role, keep the values + session and waiting for a matching session
1308  * or process a waiting request from Alice.
1309  *
1310  * @param cls closure
1311  * @param client identification of the client
1312  * @param message the actual message
1313  */
1314 static void
1315 GSS_handle_bob_client_message (void *cls,
1316                                struct GNUNET_SERVER_Client *client,
1317                                const struct GNUNET_MessageHeader *message)
1318 {
1319   const struct BobComputationMessage *msg;
1320   struct BobServiceSession *s;
1321   struct CadetIncomingSession *in;
1322   uint32_t contained_count;
1323   uint32_t total_count;
1324   const struct GNUNET_SCALARPRODUCT_Element *elements;
1325   uint32_t i;
1326   struct GNUNET_SET_Element set_elem;
1327   struct GNUNET_SCALARPRODUCT_Element *elem;
1328   uint16_t msize;
1329
1330   s = GNUNET_SERVER_client_get_user_context (client,
1331                                              struct BobServiceSession);
1332   if (NULL != s)
1333   {
1334     /* only one concurrent session per client connection allowed,
1335        simplifies logic a lot... */
1336     GNUNET_break (0);
1337     GNUNET_SERVER_receive_done (client,
1338                                 GNUNET_SYSERR);
1339     return;
1340   }
1341   msize = ntohs (message->size);
1342   if (msize < sizeof (struct BobComputationMessage))
1343   {
1344     GNUNET_break (0);
1345     GNUNET_SERVER_receive_done (client,
1346                                 GNUNET_SYSERR);
1347     return;
1348   }
1349   msg = (const struct BobComputationMessage *) message;
1350   total_count = ntohl (msg->element_count_total);
1351   contained_count = ntohl (msg->element_count_contained);
1352   if ( (0 == total_count) ||
1353        (0 == contained_count) ||
1354        (UINT16_MAX < contained_count) ||
1355        (msize != (sizeof (struct BobComputationMessage) +
1356                   contained_count * sizeof (struct GNUNET_SCALARPRODUCT_Element))) )
1357   {
1358     GNUNET_break_op (0);
1359     GNUNET_SERVER_receive_done (client,
1360                                 GNUNET_SYSERR);
1361     return;
1362   }
1363   if (NULL != find_matching_client_session (&msg->session_key))
1364   {
1365     GNUNET_break (0);
1366     GNUNET_SERVER_receive_done (client,
1367                                 GNUNET_SYSERR);
1368     return;
1369   }
1370
1371   s = GNUNET_new (struct BobServiceSession);
1372   s->status = GNUNET_SCALARPRODUCT_STATUS_ACTIVE;
1373   s->client = client;
1374   s->client_mq = GNUNET_MQ_queue_for_server_client (client);
1375   s->total = total_count;
1376   s->client_received_element_count = contained_count;
1377   s->session_id = msg->session_key;
1378   GNUNET_break (GNUNET_YES ==
1379                 GNUNET_CONTAINER_multihashmap_put (client_sessions,
1380                                                    &s->session_id,
1381                                                    s,
1382                                                    GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY));
1383   elements = (const struct GNUNET_SCALARPRODUCT_Element *) &msg[1];
1384   s->intersected_elements = GNUNET_CONTAINER_multihashmap_create (s->total,
1385                                                                   GNUNET_YES);
1386   s->intersection_set = GNUNET_SET_create (cfg,
1387                                            GNUNET_SET_OPERATION_INTERSECTION);
1388   for (i = 0; i < contained_count; i++)
1389   {
1390     if (0 == GNUNET_ntohll (elements[i].value))
1391       continue;
1392     elem = GNUNET_new (struct GNUNET_SCALARPRODUCT_Element);
1393     memcpy (elem,
1394             &elements[i],
1395             sizeof (struct GNUNET_SCALARPRODUCT_Element));
1396     if (GNUNET_SYSERR ==
1397         GNUNET_CONTAINER_multihashmap_put (s->intersected_elements,
1398                                            &elem->key,
1399                                            elem,
1400                                            GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY))
1401     {
1402       GNUNET_break (0);
1403       GNUNET_free (elem);
1404       continue;
1405     }
1406     set_elem.data = &elem->key;
1407     set_elem.size = sizeof (elem->key);
1408     set_elem.element_type = 0;
1409     GNUNET_SET_add_element (s->intersection_set,
1410                             &set_elem,
1411                             NULL, NULL);
1412     s->used_element_count++;
1413   }
1414   GNUNET_SERVER_client_set_user_context (client,
1415                                          s);
1416   GNUNET_SERVER_receive_done (client,
1417                               GNUNET_YES);
1418   if (s->total != s->client_received_element_count)
1419   {
1420     /* multipart msg */
1421     return;
1422   }
1423   in = find_matching_cadet_session (&s->session_id);
1424   if (NULL == in)
1425   {
1426     /* nothing yet, wait for Alice */
1427     return;
1428   }
1429   GNUNET_assert (NULL == in->s);
1430   /* pair them up */
1431   in->s = s;
1432   s->cadet = in;
1433   start_intersection (s);
1434 }
1435
1436
1437 /**
1438  * Task run during shutdown.
1439  *
1440  * @param cls unused
1441  * @param tc unused
1442  */
1443 static void
1444 shutdown_task (void *cls,
1445                const struct GNUNET_SCHEDULER_TaskContext *tc)
1446 {
1447   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1448               "Shutting down, initiating cleanup.\n");
1449   // FIXME: we have to cut our connections to CADET first!
1450   if (NULL != my_cadet)
1451   {
1452     GNUNET_CADET_disconnect (my_cadet);
1453     my_cadet = NULL;
1454   }
1455   GNUNET_CONTAINER_multihashmap_destroy (client_sessions);
1456   client_sessions = NULL;
1457   GNUNET_CONTAINER_multihashmap_destroy (cadet_sessions);
1458   cadet_sessions = NULL;
1459 }
1460
1461
1462 /**
1463  * A client disconnected.
1464  *
1465  * Remove the associated session(s), release data structures
1466  * and cancel pending outgoing transmissions to the client.
1467  *
1468  * @param cls closure, NULL
1469  * @param client identification of the client
1470  */
1471 static void
1472 handle_client_disconnect (void *cls,
1473                           struct GNUNET_SERVER_Client *client)
1474 {
1475   struct BobServiceSession *s;
1476
1477   if (NULL == client)
1478     return;
1479   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1480               "Client disconnected from us.\n",
1481               client);
1482   s = GNUNET_SERVER_client_get_user_context (client,
1483                                              struct BobServiceSession);
1484   if (NULL == s)
1485     return;
1486   s->client = NULL;
1487   destroy_service_session (s);
1488 }
1489
1490
1491 /**
1492  * Initialization of the program and message handlers
1493  *
1494  * @param cls closure
1495  * @param server the initialized server
1496  * @param c configuration to use
1497  */
1498 static void
1499 run (void *cls,
1500      struct GNUNET_SERVER_Handle *server,
1501      const struct GNUNET_CONFIGURATION_Handle *c)
1502 {
1503   static const struct GNUNET_SERVER_MessageHandler server_handlers[] = {
1504     { &GSS_handle_bob_client_message, NULL,
1505       GNUNET_MESSAGE_TYPE_SCALARPRODUCT_CLIENT_TO_BOB,
1506       0},
1507     { &GSS_handle_bob_client_message_multipart, NULL,
1508       GNUNET_MESSAGE_TYPE_SCALARPRODUCT_CLIENT_MUTLIPART_BOB,
1509       0},
1510     { NULL, NULL, 0, 0}
1511   };
1512   static const struct GNUNET_CADET_MessageHandler cadet_handlers[] = {
1513     { &handle_alices_computation_request,
1514       GNUNET_MESSAGE_TYPE_SCALARPRODUCT_SESSION_INITIALIZATION,
1515       sizeof (struct ServiceRequestMessage) },
1516     { &handle_alices_cryptodata_message,
1517       GNUNET_MESSAGE_TYPE_SCALARPRODUCT_ALICE_CRYPTODATA,
1518       0},
1519     { NULL, 0, 0}
1520   };
1521   static const uint32_t ports[] = {
1522     GNUNET_APPLICATION_TYPE_SCALARPRODUCT,
1523     0
1524   };
1525
1526   cfg = c;
1527   /*
1528     offset has to be sufficiently small to allow computation of:
1529     m1+m2 mod n == (S + a) + (S + b) mod n,
1530     if we have more complex operations, this factor needs to be lowered */
1531   my_offset = gcry_mpi_new (GNUNET_CRYPTO_PAILLIER_BITS / 3);
1532   gcry_mpi_set_bit (my_offset,
1533                     GNUNET_CRYPTO_PAILLIER_BITS / 3);
1534
1535   GNUNET_CRYPTO_paillier_create (&my_pubkey,
1536                                  &my_privkey);
1537   GNUNET_SERVER_add_handlers (server,
1538                               server_handlers);
1539   GNUNET_SERVER_disconnect_notify (server,
1540                                    &handle_client_disconnect,
1541                                    NULL);
1542   client_sessions = GNUNET_CONTAINER_multihashmap_create (128,
1543                                                           GNUNET_YES);
1544   cadet_sessions = GNUNET_CONTAINER_multihashmap_create (128,
1545                                                          GNUNET_YES);
1546   my_cadet = GNUNET_CADET_connect (cfg, NULL,
1547                                    &cb_channel_incoming,
1548                                    &cb_channel_destruction,
1549                                    cadet_handlers,
1550                                    ports);
1551   if (NULL == my_cadet)
1552   {
1553     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1554                 _("Connect to CADET failed\n"));
1555     GNUNET_SCHEDULER_shutdown ();
1556     return;
1557   }
1558   GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_FOREVER_REL,
1559                                 &shutdown_task,
1560                                 NULL);
1561 }
1562
1563
1564 /**
1565  * The main function for the scalarproduct service.
1566  *
1567  * @param argc number of arguments from the command line
1568  * @param argv command line arguments
1569  * @return 0 ok, 1 on error
1570  */
1571 int
1572 main (int argc,
1573       char *const *argv)
1574 {
1575   return (GNUNET_OK ==
1576           GNUNET_SERVICE_run (argc, argv,
1577                               "scalarproduct-bob",
1578                               GNUNET_SERVICE_OPTION_NONE,
1579                               &run, NULL)) ? 0 : 1;
1580 }
1581
1582 /* end of gnunet-service-scalarproduct_bob.c */