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