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