- sessions now terminate correctly for both sides if invalid/unexpected msgs are...
[oweals/gnunet.git] / src / scalarproduct / gnunet-service-scalarproduct.c
1 /*
2      This file is part of GNUnet.
3      (C) 2013 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 /**
22  * @file scalarproduct/gnunet-service-scalarproduct.c
23  * @brief scalarproduct service implementation
24  * @author Christian M. Fuchs
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
38 #define LOG(kind,...) GNUNET_log_from (kind, "scalarproduct", __VA_ARGS__)
39
40 ///////////////////////////////////////////////////////////////////////////////
41 //                     Service Structure Definitions
42 ///////////////////////////////////////////////////////////////////////////////
43
44
45 /**
46  * role a peer in a session can assume
47  */
48 enum PeerRole
49 {
50   ALICE,
51   BOB
52 };
53
54 /**
55  * DLL for sorting elements
56  */
57 struct SortedValue
58 {
59   struct SortedValue * next;
60   struct SortedValue * prev;
61   struct GNUNET_SCALARPRODUCT_Element * elem;
62   gcry_mpi_t val;
63 };
64
65
66 /**
67  * A scalarproduct session which tracks:
68  *
69  * a request form the client to our final response.
70  * or
71  * a request from a service to us(service).
72  */
73 struct ServiceSession
74 {
75   /**
76    * the role this peer has
77    */
78   enum PeerRole role;
79
80   /**
81    * session information is kept in a DLL
82    */
83   struct ServiceSession *next;
84
85   /**
86    * session information is kept in a DLL
87    */
88   struct ServiceSession *prev;
89
90   /**
91    * (hopefully) unique transaction ID
92    */
93   struct GNUNET_HashCode session_id;
94
95   /**
96    * Alice or Bob's peerID
97    */
98   struct GNUNET_PeerIdentity peer;
99
100   /**
101    * the client this request is related to
102    */
103   struct GNUNET_SERVER_Client * client;
104
105   /**
106    * The message to send
107    */
108   struct GNUNET_MessageHeader * msg;
109
110   /**
111    * how many elements we were supplied with from the client
112    */
113   uint32_t total;
114
115   /**
116    * how many elements we used for intersection
117    */
118   uint32_t intersected_elements_count;
119
120   /**
121    * all non-0-value'd elements transmitted to us
122    */
123   struct GNUNET_CONTAINER_MultiHashMap * intersected_elements;
124
125   /**
126    * how many elements actually are used for the scalar product
127    */
128   uint32_t used_elements_count;
129
130   /**
131    * already transferred elements (sent/received) for multipart messages, less or equal than used_element_count for
132    */
133   uint32_t transferred_element_count;
134
135   /**
136    * Set of elements for which will conduction an intersection. 
137    * the resulting elements are then used for computing the scalar product.
138    */
139   struct GNUNET_SET_Handle * intersection_set;
140
141   /**
142    * Set of elements for which will conduction an intersection. 
143    * the resulting elements are then used for computing the scalar product.
144    */
145   struct GNUNET_SET_OperationHandle * intersection_op;
146
147   /**
148    * Handle to Alice's Intersection operation listening for Bob
149    */
150   struct GNUNET_SET_ListenHandle * intersection_listen;
151
152   /**
153    * Public key of the remote service, only used by bob
154    */
155   struct GNUNET_CRYPTO_PaillierPublicKey remote_pubkey;
156
157   /**
158    * DLL for sorting elements after intersection
159    */
160   struct SortedValue * a_head;
161
162   /**
163    * a(Alice)
164    */
165   struct SortedValue * a_tail;
166
167   /**
168    * a(Alice)
169    */
170   gcry_mpi_t * sorted_elements;
171
172   /**
173    * E(ai)(Bob) after applying the mask
174    */
175   struct GNUNET_CRYPTO_PaillierCiphertext * e_a;
176
177   /**
178    * Bob's permutation p of R
179    */
180   struct GNUNET_CRYPTO_PaillierCiphertext * r;
181
182   /**
183    * Bob's permutation q of R
184    */
185   struct GNUNET_CRYPTO_PaillierCiphertext * r_prime;
186
187   /**
188    * Bob's s
189    */
190   struct GNUNET_CRYPTO_PaillierCiphertext * s;
191
192   /**
193    * Bob's s'
194    */
195   struct GNUNET_CRYPTO_PaillierCiphertext * s_prime;
196
197   /**
198    * Bobs matching response session from the client
199    */
200   struct ServiceSession * response;
201
202   /**
203    * The computed scalar
204    */
205   gcry_mpi_t product;
206
207   /**
208    * My transmit handle for the current message to a alice/bob
209    */
210   struct GNUNET_CADET_TransmitHandle * service_transmit_handle;
211
212   /**
213    * My transmit handle for the current message to the client
214    */
215   struct GNUNET_SERVER_TransmitHandle * client_transmit_handle;
216
217   /**
218    * channel-handle associated with our cadet handle
219    */
220   struct GNUNET_CADET_Channel * channel;
221
222   /**
223    * Handle to a task that sends a msg to the our client
224    */
225   GNUNET_SCHEDULER_TaskIdentifier client_notification_task;
226 };
227
228 ///////////////////////////////////////////////////////////////////////////////
229 //                      Forward Delcarations
230 ///////////////////////////////////////////////////////////////////////////////
231
232 /**
233  * Send a multi part chunk of a service request from alice to bob.
234  * This element only contains a part of the elements-vector (session->a[]),
235  * mask and public key set have to be contained within the first message
236  *
237  * This allows a ~32kbit key length while using 32000 elements or 62000 elements per request.
238  *
239  * @param cls the associated service session
240  */
241 static void
242 prepare_alices_cyrptodata_message_multipart (void *cls);
243
244 /**
245  * Send a multi part chunk of a service response from bob to alice.
246  * This element only contains the two permutations of R, R'.
247  *
248  * @param cls the associated service session
249  */
250 static void
251 prepare_bobs_cryptodata_message_multipart (void *cls);
252
253
254 ///////////////////////////////////////////////////////////////////////////////
255 //                      Global Variables
256 ///////////////////////////////////////////////////////////////////////////////
257
258
259 /**
260  * Gnunet configuration handle
261  */
262 const struct GNUNET_CONFIGURATION_Handle * cfg;
263
264 /**
265  * Handle to the core service (NULL until we've connected to it).
266  */
267 static struct GNUNET_CADET_Handle *my_cadet;
268
269 /**
270  * The identity of this host.
271  */
272 static struct GNUNET_PeerIdentity me;
273
274 /**
275  * Service's own public key
276  */
277 static struct GNUNET_CRYPTO_PaillierPublicKey my_pubkey;
278
279 /**
280  * Service's own private key
281  */
282 static struct GNUNET_CRYPTO_PaillierPrivateKey my_privkey;
283
284 /**
285  * Service's offset for values that could possibly be negative but are plaintext for encryption.
286  */
287 static gcry_mpi_t my_offset;
288
289 /**
290  * Head of our double linked list for client-requests sent to us.
291  * for all of these elements we calculate a scalar product with a remote peer
292  * split between service->service and client->service for simplicity
293  */
294 static struct ServiceSession * from_client_head;
295 /**
296  * Tail of our double linked list for client-requests sent to us.
297  * for all of these elements we calculate a scalar product with a remote peer
298  * split between service->service and client->service for simplicity
299  */
300 static struct ServiceSession * from_client_tail;
301
302 /**
303  * Head of our double linked list for service-requests sent to us.
304  * for all of these elements we help the requesting service in calculating a scalar product
305  * split between service->service and client->service for simplicity
306  */
307 static struct ServiceSession * from_service_head;
308
309 /**
310  * Tail of our double linked list for service-requests sent to us.
311  * for all of these elements we help the requesting service in calculating a scalar product
312  * split between service->service and client->service for simplicity
313  */
314 static struct ServiceSession * from_service_tail;
315
316 /**
317  * Certain events (callbacks for server & cadet operations) must not be queued after shutdown.
318  */
319 static int do_shutdown;
320
321 ///////////////////////////////////////////////////////////////////////////////
322 //                      Helper Functions
323 ///////////////////////////////////////////////////////////////////////////////
324
325
326 /**
327  * computes the square sum over a vector of a given length.
328  *
329  * @param vector the vector to encrypt
330  * @param length the length of the vector
331  * @return an MPI value containing the calculated sum, never NULL
332  */
333 static gcry_mpi_t
334 compute_square_sum (gcry_mpi_t * vector, uint32_t length)
335 {
336   gcry_mpi_t elem;
337   gcry_mpi_t sum;
338   int32_t i;
339
340   GNUNET_assert (sum = gcry_mpi_new (0));
341   GNUNET_assert (elem = gcry_mpi_new (0));
342
343   // calculare E(sum (ai ^ 2), publickey)
344   for (i = 0; i < length; i++) {
345     gcry_mpi_mul (elem, vector[i], vector[i]);
346     gcry_mpi_add (sum, sum, elem);
347   }
348   gcry_mpi_release (elem);
349
350   return sum;
351 }
352
353
354 /**
355  * Primitive callback for copying over a message, as they
356  * usually are too complex to be handled in the callback itself.
357  * clears a session-callback, if a session was handed over and the transmit handle was stored
358  *
359  * @param cls the session containing the message object
360  * @param size the size of the buffer we got
361  * @param buf the buffer to copy the message to
362  * @return 0 if we couldn't copy, else the size copied over
363  */
364 static size_t
365 do_send_message (void *cls, size_t size, void *buf)
366 {
367   struct ServiceSession * s = cls;
368   uint16_t type;
369
370   GNUNET_assert (buf);
371
372   if (ntohs (s->msg->size) != size) {
373     GNUNET_break (0);
374     return 0;
375   }
376
377   type = ntohs (s->msg->type);
378   memcpy (buf, s->msg, size);
379   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
380               "Sent a message of type %hu.\n",
381               type);
382   GNUNET_free (s->msg);
383   s->msg = NULL;
384
385   switch (type)
386   {
387   case GNUNET_MESSAGE_TYPE_SCALARPRODUCT_RESULT:
388     s->client_transmit_handle = NULL;
389     break;
390
391   case GNUNET_MESSAGE_TYPE_SCALARPRODUCT_ALICE_CRYPTODATA:
392   case GNUNET_MESSAGE_TYPE_SCALARPRODUCT_ALICE_CRYPTODATA_MULTIPART:
393     s->service_transmit_handle = NULL;
394     if (s->used_elements_count != s->transferred_element_count)
395       prepare_alices_cyrptodata_message_multipart (s);
396     break;
397
398   case GNUNET_MESSAGE_TYPE_SCALARPRODUCT_BOB_CRYPTODATA:
399   case GNUNET_MESSAGE_TYPE_SCALARPRODUCT_BOB_CRYPTODATA_MULTIPART:
400     s->service_transmit_handle = NULL;
401     if (s->used_elements_count != s->transferred_element_count)
402       prepare_bobs_cryptodata_message_multipart (s);
403     break;
404
405   default:
406     GNUNET_assert (0);
407   }
408
409   return size;
410 }
411
412
413 /**
414  * Finds a not terminated client/service session in the
415  * given DLL based on session key, element count and state.
416  *
417  * @param tail - the tail of the DLL
418  * @param key - the key we want to search for
419  * @param element_count - the total element count of the dataset (session->total)
420  * @param peerid - a pointer to the peer ID of the associated peer, NULL to ignore
421  * @return a pointer to a matching session, or NULL
422  */
423 static struct ServiceSession *
424 find_matching_session (struct ServiceSession * tail,
425                        const struct GNUNET_HashCode * key,
426                        uint32_t element_count,
427                        const struct GNUNET_PeerIdentity * peerid)
428 {
429   struct ServiceSession * curr;
430
431   for (curr = tail; NULL != curr; curr = curr->prev) {
432     // if the key matches, and the element_count is same
433     if ((!memcmp (&curr->session_id, key, sizeof (struct GNUNET_HashCode)))
434         && (curr->total == element_count)) {
435       // if peerid is NULL OR same as the peer Id in the queued request
436       if ((NULL == peerid)
437           || (!memcmp (&curr->peer, peerid, sizeof (struct GNUNET_PeerIdentity))))
438         // matches and is not an already terminated session
439         return curr;
440     }
441   }
442
443   return NULL;
444 }
445
446
447 /**
448  * Safely frees ALL memory areas referenced by a session.
449  *
450  * @param session - the session to free elements from
451  */
452 static void
453 free_session_variables (struct ServiceSession * session)
454 {
455   while (NULL != session->a_head) {
456     struct SortedValue * e = session->a_head;
457     GNUNET_free (e->elem);
458     gcry_mpi_release (e->val);
459     GNUNET_CONTAINER_DLL_remove (session->a_head, session->a_tail, e);
460     GNUNET_free (e);
461   }
462   if (session->e_a) {
463     GNUNET_free (session->e_a);
464     session->e_a = NULL;
465   }
466   if (session->sorted_elements) {
467     GNUNET_free (session->sorted_elements);
468     session->sorted_elements = NULL;
469   }
470   if (session->intersected_elements) {
471     GNUNET_CONTAINER_multihashmap_destroy (session->intersected_elements);
472     //elements are freed independently in session->a_head/tail
473     session->intersected_elements = NULL;
474   }
475   if (session->intersection_listen) {
476     GNUNET_SET_listen_cancel (session->intersection_listen);
477     session->intersection_listen = NULL;
478   }
479   if (session->intersection_op) {
480     GNUNET_SET_operation_cancel (session->intersection_op);
481     session->intersection_op = NULL;
482   }
483   if (session->intersection_set) {
484     GNUNET_SET_destroy (session->intersection_set);
485     session->intersection_set = NULL;
486   }
487   if (session->channel){
488     GNUNET_CADET_channel_destroy(session->channel);
489     session->channel = NULL;
490   }
491   if (session->msg) {
492     GNUNET_free (session->msg);
493     session->msg = NULL;
494   }
495   if (session->r) {
496     GNUNET_free (session->r);
497     session->r = NULL;
498   }
499   if (session->r_prime) {
500     GNUNET_free (session->r_prime);
501     session->r_prime = NULL;
502   }
503   if (session->s) {
504     GNUNET_free (session->s);
505     session->s = NULL;
506   }
507   if (session->s_prime) {
508     GNUNET_free (session->s_prime);
509     session->s_prime = NULL;
510   }
511   if (session->product) {
512     gcry_mpi_release (session->product);
513     session->product = NULL;
514   }
515 }
516 ///////////////////////////////////////////////////////////////////////////////
517 //                      Event and Message Handlers
518 ///////////////////////////////////////////////////////////////////////////////
519
520
521 /**
522  * A client disconnected.
523  *
524  * Remove the associated session(s), release data structures
525  * and cancel pending outgoing transmissions to the client.
526  * if the session has not yet completed, we also cancel Alice's request to Bob.
527  *
528  * @param cls closure, NULL
529  * @param client identification of the client
530  */
531 static void
532 handle_client_disconnect (void *cls,
533                           struct GNUNET_SERVER_Client *client)
534 {
535   struct ServiceSession *session;
536
537   if (NULL != client)
538     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
539                 _ ("Client (%p) disconnected from us.\n"), client);
540   else
541     return;
542
543   session = GNUNET_SERVER_client_get_user_context (client, struct ServiceSession);
544   if (NULL == session)
545     return;
546   GNUNET_CONTAINER_DLL_remove (from_client_head, from_client_tail, session);
547
548   if (!(session->role == BOB && 0/*//TODO: if session concluded*/)) {
549     //we MUST terminate any client message underway
550     if (session->service_transmit_handle && session->channel)
551       GNUNET_CADET_notify_transmit_ready_cancel (session->service_transmit_handle);
552     if (session->channel && 0/* //TODO: waiting for service response */)
553       GNUNET_CADET_channel_destroy (session->channel);
554   }
555   if (GNUNET_SCHEDULER_NO_TASK != session->client_notification_task) {
556     GNUNET_SCHEDULER_cancel (session->client_notification_task);
557     session->client_notification_task = GNUNET_SCHEDULER_NO_TASK;
558   }
559   if (NULL != session->client_transmit_handle) {
560     GNUNET_SERVER_notify_transmit_ready_cancel (session->client_transmit_handle);
561     session->client_transmit_handle = NULL;
562   }
563   free_session_variables (session);
564   GNUNET_free (session);
565 }
566
567
568 /**
569  * Notify the client that the session has succeeded or failed completely.
570  * This message gets sent to
571  * * alice's client if bob disconnected or to
572  * * bob's client if the operation completed or alice disconnected
573  *
574  * @param cls the associated client session
575  * @param tc the task context handed to us by the scheduler, unused
576  */
577 static void
578 prepare_client_end_notification (void * cls,
579                                  const struct GNUNET_SCHEDULER_TaskContext * tc)
580 {
581   struct ServiceSession * session = cls;
582   struct GNUNET_SCALARPRODUCT_client_response * msg;
583
584   session->client_notification_task = GNUNET_SCHEDULER_NO_TASK;
585
586   msg = GNUNET_new (struct GNUNET_SCALARPRODUCT_client_response);
587   msg->header.type = htons (GNUNET_MESSAGE_TYPE_SCALARPRODUCT_RESULT);
588   memcpy (&msg->key, &session->session_id, sizeof (struct GNUNET_HashCode));
589   memcpy (&msg->peer, &session->peer, sizeof ( struct GNUNET_PeerIdentity));
590   msg->header.size = htons (sizeof (struct GNUNET_SCALARPRODUCT_client_response));
591   // signal error if not signalized, positive result-range field but zero length.
592   msg->product_length = htonl (0);
593   msg->range = (session /* //TODO: if finalized */) ? 0 : -1;
594
595   session->msg = &msg->header;
596
597   //transmit this message to our client
598   session->client_transmit_handle =
599           GNUNET_SERVER_notify_transmit_ready (session->client,
600                                                sizeof (struct GNUNET_SCALARPRODUCT_client_response),
601                                                GNUNET_TIME_UNIT_FOREVER_REL,
602                                                &do_send_message,
603                                                session);
604
605   // if we could not even queue our request, something is wrong
606   if (NULL == session->client_transmit_handle) {
607     GNUNET_log (GNUNET_ERROR_TYPE_WARNING, _ ("Could not send message to client (%p)!\n"), session->client);
608     // usually gets freed by do_send_message
609     session->msg = NULL;
610     GNUNET_free (msg);
611   }
612   else
613     GNUNET_log (GNUNET_ERROR_TYPE_INFO, _ ("Sending session-end notification to client (%p) for session %s\n"), &session->client, GNUNET_h2s (&session->session_id));
614
615   free_session_variables (session);
616 }
617
618
619 /**
620  * Executed by Alice, fills in a service-request message and sends it to the given peer
621  *
622  * @param cls the session associated with this request
623  */
624 static void
625 prepare_alices_cyrptodata_message (void *cls)
626 {
627   struct ServiceSession * session = cls;
628   struct GNUNET_SCALARPRODUCT_alices_cryptodata_message * msg;
629   struct GNUNET_CRYPTO_PaillierCiphertext * payload;
630   unsigned int i;
631   uint32_t msg_length;
632   gcry_mpi_t a;
633
634   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, _ ("Successfully created new channel to peer (%s)!\n"), GNUNET_i2s (&session->peer));
635
636   msg_length = sizeof (struct GNUNET_SCALARPRODUCT_alices_cryptodata_message)
637           +session->used_elements_count * sizeof (struct GNUNET_CRYPTO_PaillierCiphertext);
638
639   if (GNUNET_SERVER_MAX_MESSAGE_SIZE > msg_length) {
640     session->transferred_element_count = session->used_elements_count;
641   }
642   else {
643     //create a multipart msg, first we calculate a new msg size for the head msg
644     session->transferred_element_count = (GNUNET_SERVER_MAX_MESSAGE_SIZE - 1 - sizeof (struct GNUNET_SCALARPRODUCT_alices_cryptodata_message))
645             / sizeof (struct GNUNET_CRYPTO_PaillierCiphertext);
646     msg_length = sizeof (struct GNUNET_SCALARPRODUCT_alices_cryptodata_message)
647             +session->transferred_element_count * sizeof (struct GNUNET_CRYPTO_PaillierCiphertext);
648   }
649
650   msg = GNUNET_malloc (msg_length);
651   msg->header.size = htons (msg_length);
652   msg->header.type = htons (GNUNET_MESSAGE_TYPE_SCALARPRODUCT_ALICE_CRYPTODATA);
653   msg->contained_element_count = htonl (session->transferred_element_count);
654
655   // fill in the payload
656   payload = (struct GNUNET_CRYPTO_PaillierCiphertext *) &msg[1];
657
658   // now copy over the sorted element vector
659   a = gcry_mpi_new (0);
660   for (i = 0; i < session->transferred_element_count; i++) {
661     gcry_mpi_add (a, session->sorted_elements[i], my_offset);
662     GNUNET_CRYPTO_paillier_encrypt (&my_pubkey, a, 3, &payload[i]);
663   }
664   gcry_mpi_release (a);
665
666   session->msg = (struct GNUNET_MessageHeader *) msg;
667   GNUNET_log (GNUNET_ERROR_TYPE_INFO, _ ("Transmitting service request.\n"));
668
669   //transmit via cadet messaging
670   session->service_transmit_handle = GNUNET_CADET_notify_transmit_ready (session->channel, GNUNET_YES,
671                                                                         GNUNET_TIME_UNIT_FOREVER_REL,
672                                                                         msg_length,
673                                                                         &do_send_message,
674                                                                         session);
675   if (NULL == session->service_transmit_handle) {
676     GNUNET_log (GNUNET_ERROR_TYPE_ERROR, _ ("Could not send message to channel!\n"));
677     GNUNET_free (msg);
678     session->msg = NULL;
679     session->client_notification_task =
680             GNUNET_SCHEDULER_add_now (&prepare_client_end_notification,
681                                       session);
682     return;
683   }
684 }
685
686
687 /**
688  * Send a multipart chunk of a service response from bob to alice.
689  * This element only contains the two permutations of R, R'.
690  *
691  * @param cls the associated service session
692  */
693 static void
694 prepare_bobs_cryptodata_message_multipart (void *cls)
695 {
696   struct ServiceSession * session = cls;
697   struct GNUNET_CRYPTO_PaillierCiphertext * payload;
698   struct GNUNET_SCALARPRODUCT_multipart_message * msg;
699   unsigned int i;
700   unsigned int j;
701   uint32_t msg_length;
702   uint32_t todo_count;
703
704   msg_length = sizeof (struct GNUNET_SCALARPRODUCT_multipart_message);
705   todo_count = session->used_elements_count - session->transferred_element_count;
706
707   if (todo_count > MULTIPART_ELEMENT_CAPACITY / 2)
708     // send the currently possible maximum chunk, we always transfer both permutations
709     todo_count = MULTIPART_ELEMENT_CAPACITY / 2;
710
711   msg_length += todo_count * sizeof (struct GNUNET_CRYPTO_PaillierCiphertext) * 2;
712   msg = GNUNET_malloc (msg_length);
713   msg->header.type = htons (GNUNET_MESSAGE_TYPE_SCALARPRODUCT_ALICE_CRYPTODATA_MULTIPART);
714   msg->header.size = htons (msg_length);
715   msg->contained_element_count = htonl (todo_count);
716
717   payload = (struct GNUNET_CRYPTO_PaillierCiphertext *) &msg[1];
718   for (i = session->transferred_element_count, j = 0; i < session->transferred_element_count + todo_count; i++) {
719     //r[i][p] and r[i][q]
720     memcpy (&payload[j++], &session->r[i], sizeof (struct GNUNET_CRYPTO_PaillierCiphertext));
721     memcpy (&payload[j++], &session->r_prime[i], sizeof (struct GNUNET_CRYPTO_PaillierCiphertext));
722   }
723   session->transferred_element_count += todo_count;
724   session->msg = (struct GNUNET_MessageHeader *) msg;
725   session->service_transmit_handle =
726           GNUNET_CADET_notify_transmit_ready (session->channel,
727                                              GNUNET_YES,
728                                              GNUNET_TIME_UNIT_FOREVER_REL,
729                                              msg_length,
730                                              &do_send_message,
731                                              session);
732   //disconnect our client
733   if (NULL == session->service_transmit_handle) {
734     GNUNET_log (GNUNET_ERROR_TYPE_ERROR, _ ("Could not send service-response message via cadet!)\n"));
735
736     session->response->client_notification_task =
737             GNUNET_SCHEDULER_add_now (&prepare_client_end_notification,
738                                       session->response);
739     return;
740   }
741   if (session->transferred_element_count != session->used_elements_count) {
742     // more multiparts
743   }
744   else {
745     // final part
746     GNUNET_free (session->r_prime);
747     GNUNET_free (session->r);
748     session->r_prime = NULL;
749     session->r = NULL;
750   }
751 }
752
753
754 /**
755  * Bob executes:
756  * generates the response message to be sent to alice after computing
757  * the values (1), (2), S and S'
758  *  (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)})$
759  *  (2)[]: $E_A(a_{pi'(i)}) times E_A(- r_{pi'(i)}) &= E_A(a_{pi'(i)} - r_{pi'(i)})$
760  *      S: $S := E_A(sum (r_i + b_i)^2)$
761  *     S': $S' := E_A(sum r_i^2)$
762  *
763  * @param session  the associated requesting session with alice
764  */
765 static void
766 prepare_bobs_cryptodata_message (void *cls,
767                           const struct GNUNET_SCHEDULER_TaskContext
768                           * tc)
769 {
770   struct ServiceSession * session = (struct ServiceSession *) cls;
771   struct GNUNET_SCALARPRODUCT_service_response * msg;
772   uint32_t msg_length = 0;
773   struct GNUNET_CRYPTO_PaillierCiphertext * payload;
774   int i;
775
776   msg_length = sizeof (struct GNUNET_SCALARPRODUCT_service_response)
777           + 2 * sizeof (struct GNUNET_CRYPTO_PaillierCiphertext); // s, stick
778
779   if (GNUNET_SERVER_MAX_MESSAGE_SIZE >
780       msg_length + 2 * session->used_elements_count * sizeof (struct GNUNET_CRYPTO_PaillierCiphertext)) { //r, r'
781     msg_length += 2 * session->used_elements_count * sizeof (struct GNUNET_CRYPTO_PaillierCiphertext);
782     session->transferred_element_count = session->used_elements_count;
783   }
784   else
785     session->transferred_element_count = (GNUNET_SERVER_MAX_MESSAGE_SIZE - 1 - msg_length) /
786     (sizeof (struct GNUNET_CRYPTO_PaillierCiphertext) * 2);
787
788   msg = GNUNET_malloc (msg_length);
789   msg->header.type = htons (GNUNET_MESSAGE_TYPE_SCALARPRODUCT_BOB_CRYPTODATA);
790   msg->header.size = htons (msg_length);
791   msg->total_element_count = htonl (session->total);
792   msg->used_element_count = htonl (session->used_elements_count);
793   msg->contained_element_count = htonl (session->transferred_element_count);
794   memcpy (&msg->key, &session->session_id, sizeof (struct GNUNET_HashCode));
795
796   payload = (struct GNUNET_CRYPTO_PaillierCiphertext *) &msg[1];
797   memcpy (&payload[0], session->s, sizeof (struct GNUNET_CRYPTO_PaillierCiphertext));
798   memcpy (&payload[1], session->s_prime, sizeof (struct GNUNET_CRYPTO_PaillierCiphertext));
799   GNUNET_free (session->s_prime);
800   session->s_prime = NULL;
801   GNUNET_free (session->s);
802   session->s = NULL;
803
804   payload = &payload[2];
805   // convert k[][]
806   for (i = 0; i < session->transferred_element_count; i++) {
807     //k[i][p] and k[i][q]
808     memcpy (&payload[i * 2], &session->r[i], sizeof (struct GNUNET_CRYPTO_PaillierCiphertext));
809     memcpy (&payload[i * 2 + 1], &session->r_prime[i], sizeof (struct GNUNET_CRYPTO_PaillierCiphertext));
810   }
811
812   session->msg = (struct GNUNET_MessageHeader *) msg;
813   session->service_transmit_handle =
814           GNUNET_CADET_notify_transmit_ready (session->channel,
815                                              GNUNET_YES,
816                                              GNUNET_TIME_UNIT_FOREVER_REL,
817                                              msg_length,
818                                              &do_send_message,
819                                              session);
820   //disconnect our client
821   if (NULL == session->service_transmit_handle) {
822     GNUNET_log (GNUNET_ERROR_TYPE_ERROR, _ ("Could not send service-response message via cadet!)\n"));
823
824     session->response->client_notification_task =
825             GNUNET_SCHEDULER_add_now (&prepare_client_end_notification,
826                                       session->response);
827   }
828   if (session->transferred_element_count != session->used_elements_count) {
829     // multipart
830   }
831   else {
832     //singlepart
833     GNUNET_free (session->r);
834     session->r = NULL;
835     GNUNET_free (session->r_prime);
836     session->r_prime = NULL;
837   }
838 }
839
840
841 /**
842  * executed by bob:
843  * compute the values
844  *  (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)})$
845  *  (2)[]: $E_A(a_{pi'(i)}) otimes E_A(- r_{pi'(i)}) &= E_A(a_{pi'(i)} - r_{pi'(i)})$
846  *      S: $S := E_A(sum (r_i + b_i)^2)$
847  *     S': $S' := E_A(sum r_i^2)$
848  *
849  * @param request the requesting session + bob's requesting peer
850  */
851 static void
852 compute_service_response (struct ServiceSession * session)
853 {
854   int i;
855   unsigned int * p;
856   unsigned int * q;
857   uint32_t count;
858   gcry_mpi_t * rand = NULL;
859   gcry_mpi_t tmp;
860   gcry_mpi_t * b;
861   struct GNUNET_CRYPTO_PaillierCiphertext * a;
862   struct GNUNET_CRYPTO_PaillierCiphertext * r;
863   struct GNUNET_CRYPTO_PaillierCiphertext * r_prime;
864   struct GNUNET_CRYPTO_PaillierCiphertext * s;
865   struct GNUNET_CRYPTO_PaillierCiphertext * s_prime;
866
867   count = session->used_elements_count;
868   a = session->e_a;
869   b = session->sorted_elements;
870   q = GNUNET_CRYPTO_random_permute (GNUNET_CRYPTO_QUALITY_WEAK, count);
871   p = GNUNET_CRYPTO_random_permute (GNUNET_CRYPTO_QUALITY_WEAK, count);
872
873   for (i = 0; i < count; i++)
874     GNUNET_assert (NULL != (rand[i] = gcry_mpi_new (0)));
875   r = GNUNET_malloc (sizeof (struct GNUNET_CRYPTO_PaillierCiphertext) * count);
876   r_prime = GNUNET_malloc (sizeof (struct GNUNET_CRYPTO_PaillierCiphertext) * count);
877   s = GNUNET_malloc (sizeof (struct GNUNET_CRYPTO_PaillierCiphertext));
878   s_prime = GNUNET_malloc (sizeof (struct GNUNET_CRYPTO_PaillierCiphertext));
879
880   for (i = 0; i < count; i++) {
881     int32_t svalue;
882
883     svalue = (int32_t) GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_WEAK, UINT32_MAX);
884
885     // long to gcry_mpi_t
886     if (svalue < 0)
887       gcry_mpi_sub_ui (rand[i],
888                        rand[i],
889                        -svalue);
890     else
891       rand[i] = gcry_mpi_set_ui (rand[i], svalue);
892   }
893
894   tmp = gcry_mpi_new (0);
895   // encrypt the element
896   // for the sake of readability I decided to have dedicated permutation
897   // vectors, which get rid of all the lookups in p/q.
898   // however, ap/aq are not absolutely necessary but are just abstraction
899   // Calculate Kp = E(S + a_pi) (+) E(S - r_pi - b_pi)
900   for (i = 0; i < count; i++) {
901     // E(S - r_pi - b_pi)
902     gcry_mpi_sub (tmp, my_offset, rand[p[i]]);
903     gcry_mpi_sub (tmp, tmp, b[p[i]]);
904     GNUNET_CRYPTO_paillier_encrypt (&session->remote_pubkey,
905                                     tmp,
906                                     2,
907                                     &r[i]);
908
909     // E(S - r_pi - b_pi) * E(S + a_pi) ==  E(2*S + a - r - b)
910     GNUNET_CRYPTO_paillier_hom_add (&session->remote_pubkey,
911                                     &r[i],
912                                     &a[p[i]],
913                                     &r[i]);
914   }
915
916   // Calculate Kq = E(S + a_qi) (+) E(S - r_qi)
917   for (i = 0; i < count; i++) {
918     // E(S - r_qi)
919     gcry_mpi_sub (tmp, my_offset, rand[q[i]]);
920     GNUNET_assert (2 == GNUNET_CRYPTO_paillier_encrypt (&session->remote_pubkey,
921                                                         tmp,
922                                                         2,
923                                                         &r_prime[i]));
924
925     // E(S - r_qi) * E(S + a_qi) == E(2*S + a_qi - r_qi)
926     GNUNET_assert (1 == GNUNET_CRYPTO_paillier_hom_add (&session->remote_pubkey,
927                                                         &r_prime[i],
928                                                         &a[q[i]],
929                                                         &r_prime[i]));
930   }
931
932   // Calculate S' =  E(SUM( r_i^2 ))
933   tmp = compute_square_sum (rand, count);
934   GNUNET_CRYPTO_paillier_encrypt (&session->remote_pubkey,
935                                   tmp,
936                                   1,
937                                   s_prime);
938
939   // Calculate S = E(SUM( (r_i + b_i)^2 ))
940   for (i = 0; i < count; i++)
941     gcry_mpi_add (rand[i], rand[i], b[i]);
942   tmp = compute_square_sum (rand, count);
943   GNUNET_CRYPTO_paillier_encrypt (&session->remote_pubkey,
944                                   tmp,
945                                   1,
946                                   s);
947
948   session->r = r;
949   session->r_prime = r_prime;
950   session->s = s;
951   session->s_prime = s_prime;
952
953   // release rand, b and a
954   for (i = 0; i < count; i++) {
955     gcry_mpi_release (rand[i]);
956     gcry_mpi_release (b[i]);
957   }
958   gcry_mpi_release (tmp);
959   GNUNET_free (session->e_a);
960   session->e_a = NULL;
961   GNUNET_free (p);
962   GNUNET_free (q);
963   GNUNET_free (b);
964   GNUNET_free (rand);
965
966   // copy the r[], r_prime[], S and Stick into a new message, prepare_service_response frees these
967   GNUNET_SCHEDULER_add_now (&prepare_bobs_cryptodata_message, session);
968 }
969
970
971 /**
972  * Iterator over all hash map entries in session->intersected_elements.
973  *
974  * @param cls closure
975  * @param key current key code
976  * @param value value in the hash map
977  * @return #GNUNET_YES if we should continue to
978  *         iterate,
979  *         #GNUNET_NO if not.
980  */
981 int
982 cb_insert_element_sorted (void *cls,
983                           const struct GNUNET_HashCode *key,
984                           void *value)
985 {
986   struct ServiceSession * session = (struct ServiceSession*) cls;
987   struct SortedValue * e = GNUNET_new (struct SortedValue);
988   struct SortedValue * o = session->a_head;
989
990   e->elem = value;
991   e->val = gcry_mpi_new (0);
992   if (0 > e->elem->value)
993     gcry_mpi_sub_ui (e->val, e->val, abs (e->elem->value));
994   else
995     gcry_mpi_add_ui (e->val, e->val, e->elem->value);
996
997   // insert as first element with the lowest key
998   if (NULL == session->a_head
999       || (0 <= GNUNET_CRYPTO_hash_cmp (&session->a_head->elem->key, &e->elem->key))) {
1000     GNUNET_CONTAINER_DLL_insert (session->a_head, session->a_tail, e);
1001     return GNUNET_YES;
1002   }
1003   // insert as last element with the highest key
1004   if (0 >= GNUNET_CRYPTO_hash_cmp (&session->a_tail->elem->key, &e->elem->key)) {
1005     GNUNET_CONTAINER_DLL_insert_tail (session->a_head, session->a_tail, e);
1006     return GNUNET_YES;
1007   }
1008   // insert before the first higher/equal element
1009   do {
1010     if (0 <= GNUNET_CRYPTO_hash_cmp (&o->elem->key, &e->elem->key)) {
1011       GNUNET_CONTAINER_DLL_insert_before (session->a_head, session->a_tail, o, e);
1012       return GNUNET_YES;
1013     }
1014     o = o->next;
1015   }
1016   while (NULL != o);
1017   // broken DLL
1018   GNUNET_assert (0);
1019 }
1020
1021
1022 /**
1023  * Callback for set operation results. Called for each element
1024  * in the result set.
1025  *
1026  * @param cls closure
1027  * @param element a result element, only valid if status is #GNUNET_SET_STATUS_OK
1028  * @param status see `enum GNUNET_SET_Status`
1029  */
1030 static void
1031 cb_intersection_element_removed (void *cls,
1032                                  const struct GNUNET_SET_Element *element,
1033                                  enum GNUNET_SET_Status status)
1034 {
1035   struct ServiceSession * session = (struct ServiceSession*) cls;
1036   struct GNUNET_SCALARPRODUCT_Element * se;
1037   int i;
1038
1039   switch (status)
1040   {
1041   case GNUNET_SET_STATUS_OK:
1042     //this element has been removed from the set
1043     se = GNUNET_CONTAINER_multihashmap_get (session->intersected_elements,
1044                                             element->data);
1045
1046     GNUNET_CONTAINER_multihashmap_remove (session->intersected_elements,
1047                                           element->data,
1048                                           se);
1049     session->used_elements_count--;
1050     return;
1051
1052   case GNUNET_SET_STATUS_DONE:
1053     if (2 > session->used_elements_count) {
1054       // failed! do not leak information about our single remaining element!
1055       // continue after the loop
1056       break;
1057     }
1058
1059     GNUNET_CONTAINER_multihashmap_iterate (session->intersected_elements,
1060                                            &cb_insert_element_sorted,
1061                                            session);
1062
1063     session->sorted_elements = GNUNET_malloc (session->used_elements_count * sizeof (gcry_mpi_t));
1064     for (i = 0; NULL != session->a_head; i++) {
1065       struct SortedValue* a = session->a_head;
1066       GNUNET_assert (i < session->used_elements_count);
1067       
1068       session->sorted_elements[i] = a->val;
1069       GNUNET_CONTAINER_DLL_remove (session->a_head, session->a_tail, a);
1070       GNUNET_free (a->elem);
1071     }
1072     GNUNET_assert (i == session->used_elements_count);
1073
1074     if (ALICE == session->role) {
1075       prepare_alices_cyrptodata_message (session);
1076       return;
1077     }
1078     else if (session->used_elements_count == session->transferred_element_count) {
1079       compute_service_response (session);
1080       return;
1081     }
1082   default:
1083     break;
1084   }
1085
1086   //failed if we go here
1087   GNUNET_break (0);
1088
1089   // and notify our client-session that we could not complete the session
1090   if (ALICE == session->role) {
1091     session->client_notification_task =
1092             GNUNET_SCHEDULER_add_now (&prepare_client_end_notification,
1093                                       session);
1094   }
1095   else {
1096     GNUNET_CONTAINER_DLL_remove (from_service_head, from_service_tail, session);
1097     free_session_variables (session);
1098     session->response->client_notification_task =
1099             GNUNET_SCHEDULER_add_now (&prepare_client_end_notification,
1100                                       session->response);
1101     GNUNET_free(session);
1102   }
1103 }
1104
1105
1106 /**
1107  * Called when another peer wants to do a set operation with the
1108  * local peer. If a listen error occurs, the @a request is NULL.
1109  *
1110  * @param cls closure
1111  * @param other_peer the other peer
1112  * @param context_msg message with application specific information from
1113  *        the other peer
1114  * @param request request from the other peer (never NULL), use GNUNET_SET_accept()
1115  *        to accept it, otherwise the request will be refused
1116  *        Note that we can't just return value from the listen callback,
1117  *        as it is also necessary to specify the set we want to do the
1118  *        operation with, whith sometimes can be derived from the context
1119  *        message. It's necessary to specify the timeout.
1120  */
1121 static void
1122 cb_intersection_request_alice (void *cls,
1123                                const struct GNUNET_PeerIdentity *other_peer,
1124                                const struct GNUNET_MessageHeader *context_msg,
1125                                struct GNUNET_SET_Request *request)
1126 {
1127   struct ServiceSession * session = (struct ServiceSession *) cls;
1128
1129   // check the peer-id, the app-id=session-id is compared by SET
1130   if (0 != memcmp (&session->peer, &other_peer, sizeof (struct GNUNET_PeerIdentity)))
1131     return;
1132
1133   session->intersection_op = GNUNET_SET_accept (request,
1134                                                 GNUNET_SET_RESULT_REMOVED,
1135                                                 cb_intersection_element_removed,
1136                                                 session);
1137
1138   if (NULL == session->intersection_op) {
1139     session->response->client_notification_task =
1140             GNUNET_SCHEDULER_add_now (&prepare_client_end_notification,
1141                                       session);
1142     return;
1143   }
1144   if (GNUNET_OK != GNUNET_SET_commit (session->intersection_op, session->intersection_set)) {
1145     session->response->client_notification_task =
1146             GNUNET_SCHEDULER_add_now (&prepare_client_end_notification,
1147                                       session);
1148     return;
1149   }
1150   session->intersection_set = NULL;
1151   session->intersection_listen = NULL;
1152 }
1153
1154
1155 /**
1156  * prepare the response we will send to alice or bobs' clients.
1157  * in Bobs case the product will be NULL.
1158  *
1159  * @param cls the session associated with our client.
1160  * @param tc the task context handed to us by the scheduler, unused
1161  */
1162 static void
1163 prepare_client_response (void *cls,
1164                          const struct GNUNET_SCHEDULER_TaskContext *tc)
1165 {
1166   struct ServiceSession * session = cls;
1167   struct GNUNET_SCALARPRODUCT_client_response * msg;
1168   unsigned char * product_exported = NULL;
1169   size_t product_length = 0;
1170   uint32_t msg_length = 0;
1171   int8_t range = -1;
1172   gcry_error_t rc;
1173   int sign;
1174
1175   session->client_notification_task = GNUNET_SCHEDULER_NO_TASK;
1176
1177   if (session->product) {
1178     gcry_mpi_t value = gcry_mpi_new (0);
1179
1180     sign = gcry_mpi_cmp_ui (session->product, 0);
1181     // libgcrypt can not handle a print of a negative number
1182     // if (a->sign) return gcry_error (GPG_ERR_INTERNAL); /* Can't handle it yet. */
1183     if (0 > sign) {
1184       gcry_mpi_sub (value, value, session->product);
1185     }
1186     else if (0 < sign) {
1187       range = 1;
1188       gcry_mpi_add (value, value, session->product);
1189     }
1190     else
1191       range = 0;
1192
1193     gcry_mpi_release (session->product);
1194     session->product = NULL;
1195
1196     // get representation as string
1197     if (range
1198         && (0 != (rc = gcry_mpi_aprint (GCRYMPI_FMT_STD,
1199                                         &product_exported,
1200                                         &product_length,
1201                                         value)))) {
1202       LOG_GCRY (GNUNET_ERROR_TYPE_ERROR, "gcry_mpi_scan", rc);
1203       product_length = 0;
1204       range = -1; // signal error with product-length = 0 and range = -1
1205     }
1206     gcry_mpi_release (value);
1207   }
1208
1209   msg_length = sizeof (struct GNUNET_SCALARPRODUCT_client_response) +product_length;
1210   msg = GNUNET_malloc (msg_length);
1211   msg->key = session->session_id;
1212   msg->peer = session->peer;
1213   if (product_exported != NULL) {
1214     memcpy (&msg[1], product_exported, product_length);
1215     GNUNET_free (product_exported);
1216   }
1217   msg->header.type = htons (GNUNET_MESSAGE_TYPE_SCALARPRODUCT_RESULT);
1218   msg->header.size = htons (msg_length);
1219   msg->range = range;
1220   msg->product_length = htonl (product_length);
1221
1222   session->msg = (struct GNUNET_MessageHeader *) msg;
1223   //transmit this message to our client
1224   session->client_transmit_handle =
1225           GNUNET_SERVER_notify_transmit_ready (session->client,
1226                                                msg_length,
1227                                                GNUNET_TIME_UNIT_FOREVER_REL,
1228                                                &do_send_message,
1229                                                session);
1230   if (NULL == session->client_transmit_handle) {
1231     GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
1232                 _ ("Could not send message to client (%p)!\n"),
1233                 session->client);
1234     session->client = NULL;
1235     // callback was not called!
1236     GNUNET_free (msg);
1237     session->msg = NULL;
1238   }
1239   else
1240     // gracefully sent message, just terminate session structure
1241     GNUNET_log (GNUNET_ERROR_TYPE_INFO,
1242                 _ ("Sent result to client (%p), this session (%s) has ended!\n"),
1243                 session->client,
1244                 GNUNET_h2s (&session->session_id));
1245   free_session_variables (session);
1246 }
1247
1248
1249 /**
1250  * Executed by Alice, fills in a service-request message and sends it to the given peer
1251  *
1252  * @param session the session associated with this request
1253  */
1254 static void
1255 prepare_alices_computation_request (struct ServiceSession * session)
1256 {
1257   struct GNUNET_SCALARPRODUCT_service_request * msg;
1258
1259   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, _ ("Successfully created new channel to peer (%s)!\n"), GNUNET_i2s (&session->peer));
1260
1261   msg = GNUNET_new (struct GNUNET_SCALARPRODUCT_service_request);
1262   msg->header.type = htons (GNUNET_MESSAGE_TYPE_SCALARPRODUCT_ALICE_CRYPTODATA);
1263   msg->total_element_count = htonl (session->used_elements_count);
1264   memcpy (&msg->session_id, &session->session_id, sizeof (struct GNUNET_HashCode));
1265   msg->header.size = htons (sizeof (struct GNUNET_SCALARPRODUCT_service_request));
1266
1267   session->msg = (struct GNUNET_MessageHeader *) msg;
1268   GNUNET_log (GNUNET_ERROR_TYPE_INFO, _ ("Transmitting service request.\n"));
1269
1270   //transmit via cadet messaging
1271   session->service_transmit_handle = GNUNET_CADET_notify_transmit_ready (session->channel, GNUNET_YES,
1272                                                                         GNUNET_TIME_UNIT_FOREVER_REL,
1273                                                                         sizeof (struct GNUNET_SCALARPRODUCT_service_request),
1274                                                                         &do_send_message,
1275                                                                         session);
1276   if (!session->service_transmit_handle) {
1277     GNUNET_log (GNUNET_ERROR_TYPE_ERROR, _ ("Could not send message to channel!\n"));
1278     GNUNET_free (msg);
1279     session->msg = NULL;
1280     session->client_notification_task =
1281             GNUNET_SCHEDULER_add_now (&prepare_client_end_notification,
1282                                       session);
1283     return;
1284   }
1285 }
1286
1287
1288 /**
1289  * Send a multi part chunk of a service request from alice to bob.
1290  * This element only contains a part of the elements-vector (session->a[]),
1291  * mask and public key set have to be contained within the first message
1292  *
1293  * This allows a ~32kbit key length while using 32000 elements or 62000 elements per request.
1294  *
1295  * @param cls the associated service session
1296  */
1297 static void
1298 prepare_alices_cyrptodata_message_multipart (void *cls)
1299 {
1300   struct ServiceSession * session = cls;
1301   struct GNUNET_SCALARPRODUCT_multipart_message * msg;
1302   struct GNUNET_CRYPTO_PaillierCiphertext * payload;
1303   unsigned int i;
1304   uint32_t msg_length;
1305   uint32_t todo_count;
1306   gcry_mpi_t a;
1307
1308   msg_length = sizeof (struct GNUNET_SCALARPRODUCT_multipart_message);
1309   todo_count = session->used_elements_count - session->transferred_element_count;
1310
1311   if (todo_count > MULTIPART_ELEMENT_CAPACITY)
1312     // send the currently possible maximum chunk
1313     todo_count = MULTIPART_ELEMENT_CAPACITY;
1314
1315   msg_length += todo_count * sizeof (struct GNUNET_CRYPTO_PaillierCiphertext);
1316   msg = GNUNET_malloc (msg_length);
1317   msg->header.type = htons (GNUNET_MESSAGE_TYPE_SCALARPRODUCT_ALICE_CRYPTODATA_MULTIPART);
1318   msg->header.size = htons (msg_length);
1319   msg->contained_element_count = htonl (todo_count);
1320
1321   payload = (struct GNUNET_CRYPTO_PaillierCiphertext *) &msg[1];
1322
1323   // now copy over the sorted element vector
1324   a = gcry_mpi_new (0);
1325   for (i = session->transferred_element_count; i < todo_count; i++) {
1326     gcry_mpi_add (a, session->sorted_elements[i], my_offset);
1327     GNUNET_CRYPTO_paillier_encrypt (&my_pubkey, a, 3, &payload[i - session->transferred_element_count]);
1328   }
1329   gcry_mpi_release (a);
1330   session->transferred_element_count += todo_count;
1331
1332   session->msg = (struct GNUNET_MessageHeader *) msg;
1333   GNUNET_log (GNUNET_ERROR_TYPE_INFO, _ ("Transmitting service request.\n"));
1334
1335   //transmit via cadet messaging
1336   session->service_transmit_handle = GNUNET_CADET_notify_transmit_ready (session->channel, GNUNET_YES,
1337                                                                         GNUNET_TIME_UNIT_FOREVER_REL,
1338                                                                         msg_length,
1339                                                                         &do_send_message,
1340                                                                         session);
1341   if (!session->service_transmit_handle) {
1342     GNUNET_log (GNUNET_ERROR_TYPE_ERROR, _ ("Could not send service-request multipart message to channel!\n"));
1343     GNUNET_free (msg);
1344     session->msg = NULL;
1345     session->client_notification_task =
1346             GNUNET_SCHEDULER_add_now (&prepare_client_end_notification,
1347                                       session);
1348     return;
1349   }
1350 }
1351
1352
1353 /**
1354  * Our client has finished sending us its multipart message.
1355  * 
1356  * @param session the service session context
1357  */
1358 static void
1359 client_request_complete_bob (struct ServiceSession * client_session)
1360 {
1361   struct ServiceSession * session;
1362
1363   //check if service queue contains a matching request
1364   session = find_matching_session (from_service_tail,
1365                                    &client_session->session_id,
1366                                    client_session->total, NULL);
1367   if (NULL != session) {
1368     GNUNET_log (GNUNET_ERROR_TYPE_INFO,
1369                 _ ("Got client-responder-session with key %s and a matching service-request-session set, processing.\n"),
1370                 GNUNET_h2s (&client_session->session_id));
1371
1372     session->response = client_session;
1373     session->intersected_elements = client_session->intersected_elements;
1374     client_session->intersected_elements = NULL;
1375     session->intersection_set = client_session->intersection_set;
1376     client_session->intersection_set = NULL;
1377
1378     session->intersection_op = GNUNET_SET_prepare (&session->peer,
1379                                                    &session->session_id,
1380                                                    NULL,
1381                                                    GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_WEAK, UINT16_MAX),
1382                                                    GNUNET_SET_RESULT_REMOVED,
1383                                                    cb_intersection_element_removed,
1384                                                    session);
1385
1386     GNUNET_SET_commit (session->intersection_op, session->intersection_set);
1387   }
1388   else {
1389     GNUNET_log (GNUNET_ERROR_TYPE_INFO,
1390                 _ ("Got client-responder-session with key %s but NO matching service-request-session set, queuing element for later use.\n"),
1391                 GNUNET_h2s (&client_session->session_id));
1392     // no matching session exists yet, store the response
1393     // for later processing by handle_service_request()
1394   }
1395 }
1396
1397
1398 /**
1399  * Our client has finished sending us its multipart message.
1400  * 
1401  * @param session the service session context
1402  */
1403 static void
1404 client_request_complete_alice (struct ServiceSession * session)
1405 {
1406   GNUNET_log (GNUNET_ERROR_TYPE_INFO,
1407               _ ("Creating new channel for session with key %s.\n"),
1408               GNUNET_h2s (&session->session_id));
1409   session->channel = GNUNET_CADET_channel_create (my_cadet, session,
1410                                                  &session->peer,
1411                                                  GNUNET_APPLICATION_TYPE_SCALARPRODUCT,
1412                                                  GNUNET_CADET_OPTION_RELIABLE);
1413   if (NULL == session->channel) {
1414     session->response->client_notification_task =
1415             GNUNET_SCHEDULER_add_now (&prepare_client_end_notification,
1416                                       session);
1417     return;
1418   }
1419   session->intersection_listen = GNUNET_SET_listen (cfg,
1420                                                     GNUNET_SET_OPERATION_INTERSECTION,
1421                                                     &session->session_id,
1422                                                     cb_intersection_request_alice,
1423                                                     session);
1424   if (NULL == session->intersection_listen) {
1425     session->response->client_notification_task =
1426             GNUNET_SCHEDULER_add_now (&prepare_client_end_notification,
1427                                       session);
1428     return;
1429   }
1430   prepare_alices_computation_request (session);
1431 }
1432
1433
1434 static void
1435 handle_client_message_multipart (void *cls,
1436                                  struct GNUNET_SERVER_Client *client,
1437                                  const struct GNUNET_MessageHeader *message)
1438 {
1439   const struct GNUNET_SCALARPRODUCT_computation_message_multipart * msg = (const struct GNUNET_SCALARPRODUCT_computation_message_multipart *) message;
1440   struct ServiceSession * session;
1441   uint32_t contained_count;
1442   struct GNUNET_SCALARPRODUCT_Element * elements;
1443   uint32_t i;
1444
1445   // only one concurrent session per client connection allowed, simplifies logics a lot...
1446   session = GNUNET_SERVER_client_get_user_context (client, struct ServiceSession);
1447   if (NULL == session) {
1448     GNUNET_SERVER_receive_done (client, GNUNET_OK);
1449     return;
1450   }
1451
1452   contained_count = ntohl (msg->element_count_contained);
1453
1454   //sanity check: is the message as long as the message_count fields suggests?
1455   if ((ntohs (msg->header.size) != (sizeof (struct GNUNET_SCALARPRODUCT_computation_message_multipart) +contained_count * sizeof (struct GNUNET_SCALARPRODUCT_Element)))
1456       || (0 == contained_count) || (session->total < session->transferred_element_count + contained_count)) {
1457     GNUNET_break_op (0);
1458     GNUNET_SERVER_receive_done (client, GNUNET_OK);
1459     return;
1460   }
1461   session->transferred_element_count += contained_count;
1462
1463   elements = (struct GNUNET_SCALARPRODUCT_Element *) & msg[1];
1464   for (i = 0; i < contained_count; i++) {
1465     struct GNUNET_SET_Element set_elem;
1466     struct GNUNET_SCALARPRODUCT_Element * elem;
1467
1468     if (0 == ntohl (elements[i].value))
1469       continue;
1470
1471     elem = GNUNET_new (struct GNUNET_SCALARPRODUCT_Element);
1472     memcpy (elem, &elements[i], sizeof (struct GNUNET_SCALARPRODUCT_Element));
1473
1474     if (GNUNET_SYSERR == GNUNET_CONTAINER_multihashmap_put (session->intersected_elements,
1475                                                             &elem->key,
1476                                                             elem,
1477                                                             GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY)) {
1478       GNUNET_free (elem);
1479       continue;
1480     }
1481     set_elem.data = &elements[i].key;
1482     set_elem.size = htons (sizeof (elements[i].key));
1483     set_elem.type = htons (0); /* do we REALLY need this? */
1484     GNUNET_SET_add_element (session->intersection_set, &set_elem, NULL, NULL);
1485     session->used_elements_count++;
1486   }
1487
1488   GNUNET_SERVER_receive_done (client, GNUNET_OK);
1489
1490   if (session->total != session->transferred_element_count)
1491     // multipart msg
1492     return;
1493
1494   if (ALICE == session->role)
1495     client_request_complete_alice (session);
1496   else
1497     client_request_complete_bob (session);
1498 }
1499
1500
1501 /**
1502  * Handler for a client request message.
1503  * Can either be type A or B
1504  *   A: request-initiation to compute a scalar product with a peer
1505  *   B: response role, keep the values + session and wait for a matching session or process a waiting request
1506  *
1507  * @param cls closure
1508  * @param client identification of the client
1509  * @param message the actual message
1510  */
1511 static void
1512 handle_client_message (void *cls,
1513                        struct GNUNET_SERVER_Client *client,
1514                        const struct GNUNET_MessageHeader *message)
1515 {
1516   const struct GNUNET_SCALARPRODUCT_computation_message * msg = (const struct GNUNET_SCALARPRODUCT_computation_message *) message;
1517   struct ServiceSession * session;
1518   uint32_t contained_count;
1519   uint32_t total_count;
1520   uint32_t msg_type;
1521   struct GNUNET_SCALARPRODUCT_Element * elements;
1522   uint32_t i;
1523
1524   // only one concurrent session per client connection allowed, simplifies logics a lot...
1525   session = GNUNET_SERVER_client_get_user_context (client, struct ServiceSession);
1526   if (NULL != session) {
1527     GNUNET_SERVER_receive_done (client, GNUNET_OK);
1528     return;
1529   }
1530
1531   msg_type = ntohs (msg->header.type);
1532   total_count = ntohl (msg->element_count_total);
1533   contained_count = ntohl (msg->element_count_contained);
1534
1535   if ((GNUNET_MESSAGE_TYPE_SCALARPRODUCT_CLIENT_TO_ALICE == msg_type)
1536       && (!memcmp (&msg->peer, &me, sizeof (struct GNUNET_PeerIdentity)))) {
1537     //session with ourself makes no sense!
1538     GNUNET_break_op (0);
1539     GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
1540     return;
1541   }
1542
1543   //sanity check: is the message as long as the message_count fields suggests?
1544   if ((ntohs (msg->header.size) != (sizeof (struct GNUNET_SCALARPRODUCT_computation_message) +contained_count * sizeof (struct GNUNET_SCALARPRODUCT_Element)))
1545       || (0 == total_count)) {
1546     GNUNET_break_op (0);
1547     GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
1548     return;
1549   }
1550
1551   // do we have a duplicate session here already?
1552   if (NULL != find_matching_session (from_client_tail,
1553                                      &msg->session_key,
1554                                      total_count, NULL)) {
1555     GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
1556                 _ ("Duplicate session information received, can not create new session with key `%s'\n"),
1557                 GNUNET_h2s (&msg->session_key));
1558     GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
1559     return;
1560   }
1561
1562   session = GNUNET_new (struct ServiceSession);
1563   session->client_notification_task = GNUNET_SCHEDULER_NO_TASK;
1564   session->client = client;
1565   session->total = total_count;
1566   session->transferred_element_count = contained_count;
1567   // get our transaction key
1568   memcpy (&session->session_id, &msg->session_key, sizeof (struct GNUNET_HashCode));
1569
1570   elements = (struct GNUNET_SCALARPRODUCT_Element *) & msg[1];
1571   session->intersected_elements = GNUNET_CONTAINER_multihashmap_create (session->total, GNUNET_NO);
1572   session->intersection_set = GNUNET_SET_create (cfg, GNUNET_SET_OPERATION_INTERSECTION);
1573   for (i = 0; i < contained_count; i++) {
1574     struct GNUNET_SET_Element set_elem;
1575     struct GNUNET_SCALARPRODUCT_Element * elem;
1576
1577     if (0 == ntohl (elements[i].value))
1578       continue;
1579
1580     elem = GNUNET_new (struct GNUNET_SCALARPRODUCT_Element);
1581     memcpy (elem, &elements[i], sizeof (struct GNUNET_SCALARPRODUCT_Element));
1582
1583     if (GNUNET_SYSERR == GNUNET_CONTAINER_multihashmap_put (session->intersected_elements,
1584                                                             &elem->key,
1585                                                             elem,
1586                                                             GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY)) {
1587       GNUNET_free (elem);
1588       continue;
1589     }
1590     set_elem.data = &elements[i].key;
1591     set_elem.size = htons (sizeof (elements[i].key));
1592     set_elem.type = htons (0); /* do we REALLY need this? */
1593     GNUNET_SET_add_element (session->intersection_set, &set_elem, NULL, NULL);
1594     session->used_elements_count++;
1595   }
1596
1597   if (GNUNET_MESSAGE_TYPE_SCALARPRODUCT_CLIENT_TO_ALICE == msg_type) {
1598     session->role = ALICE;
1599     memcpy (&session->peer, &msg->peer, sizeof (struct GNUNET_PeerIdentity));
1600   }
1601   else {
1602     session->role = BOB;
1603   }
1604
1605   GNUNET_CONTAINER_DLL_insert (from_client_head, from_client_tail, session);
1606   GNUNET_SERVER_client_set_user_context (client, session);
1607   GNUNET_SERVER_receive_done (client, GNUNET_YES);
1608
1609   if (session->total != session->transferred_element_count)
1610     // multipart msg
1611     return;
1612
1613   if (ALICE == session->role)
1614     client_request_complete_alice (session);
1615   else
1616     client_request_complete_bob (session);
1617 }
1618
1619
1620 /**
1621  * Function called for inbound channels.
1622  *
1623  * @param cls closure
1624  * @param channel new handle to the channel
1625  * @param initiator peer that started the channel
1626  * @param port unused
1627  * @param options unused
1628  *
1629  * @return session associated with the channel
1630  */
1631 static void *
1632 cb_channel_incoming (void *cls,
1633                           struct GNUNET_CADET_Channel *channel,
1634                           const struct GNUNET_PeerIdentity *initiator,
1635                           uint32_t port, enum GNUNET_CADET_ChannelOption options)
1636 {
1637   struct ServiceSession * c = GNUNET_new (struct ServiceSession);
1638
1639   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1640               _ ("New incoming channel from peer %s.\n"),
1641               GNUNET_i2s (initiator));
1642
1643   c->peer = *initiator;
1644   c->channel = channel;
1645   c->role = BOB;
1646   return c;
1647 }
1648
1649
1650 /**
1651  * Function called whenever a channel is destroyed.  Should clean up
1652  * any associated state.
1653  *
1654  * It must NOT call GNUNET_CADET_channel_destroy on the channel.
1655  *
1656  * @param cls closure (set from GNUNET_CADET_connect)
1657  * @param channel connection to the other end (henceforth invalid)
1658  * @param channel_ctx place where local state associated
1659  *                   with the channel is stored
1660  */
1661 static void
1662 cb_channel_destruction (void *cls,
1663                              const struct GNUNET_CADET_Channel *channel,
1664                              void *channel_ctx)
1665 {
1666   struct ServiceSession * session = channel_ctx;
1667   struct ServiceSession * client_session;
1668   struct ServiceSession * curr;
1669
1670   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1671               _ ("Peer disconnected, terminating session %s with peer (%s)\n"),
1672               GNUNET_h2s (&session->session_id),
1673               GNUNET_i2s (&session->peer));
1674   if (ALICE == session->role) {
1675     // as we have only one peer connected in each session, just remove the session
1676
1677     if ((0/*//TODO: only for complete session*/) && (!do_shutdown)) {
1678       session->channel = NULL;
1679       // if this happened before we received the answer, we must terminate the session
1680       session->client_notification_task =
1681               GNUNET_SCHEDULER_add_now (&prepare_client_end_notification,
1682                                         session);
1683     }
1684   }
1685   else { //(BOB == session->role) service session
1686     // remove the session, unless it has already been dequeued, but somehow still active
1687     // this could bug without the IF in case the queue is empty and the service session was the only one know to the service
1688     // scenario: disconnect before alice can send her message to bob.
1689     for (curr = from_service_head; NULL != curr; curr = curr->next)
1690       if (curr == session) {
1691         GNUNET_CONTAINER_DLL_remove (from_service_head, from_service_tail, curr);
1692         break;
1693       }
1694     // there is a client waiting for this service session, terminate it, too!
1695     // i assume the tupel of key and element count is unique. if it was not the rest of the code would not work either.
1696     client_session = find_matching_session (from_client_tail,
1697                                             &session->session_id,
1698                                             session->total, NULL);
1699     free_session_variables (session);
1700     GNUNET_free (session);
1701
1702     // the client has to check if it was waiting for a result
1703     // or if it was a responder, no point in adding more statefulness
1704     if (client_session && (!do_shutdown)) {
1705       client_session->client_notification_task =
1706               GNUNET_SCHEDULER_add_now (&prepare_client_end_notification,
1707                                         client_session);
1708     }
1709   }
1710 }
1711
1712
1713 /**
1714  * Compute our scalar product, done by Alice
1715  *
1716  * @param session - the session associated with this computation
1717  * @return product as MPI, never NULL
1718  */
1719 static gcry_mpi_t
1720 compute_scalar_product (struct ServiceSession * session)
1721 {
1722   uint32_t count;
1723   gcry_mpi_t t;
1724   gcry_mpi_t u;
1725   gcry_mpi_t u_prime;
1726   gcry_mpi_t p;
1727   gcry_mpi_t p_prime;
1728   gcry_mpi_t tmp;
1729   gcry_mpi_t r[session->used_elements_count];
1730   gcry_mpi_t r_prime[session->used_elements_count];
1731   gcry_mpi_t s;
1732   gcry_mpi_t s_prime;
1733   unsigned int i;
1734
1735   count = session->used_elements_count;
1736   // due to the introduced static offset S, we now also have to remove this
1737   // from the E(a_pi)(+)E(-b_pi-r_pi) and E(a_qi)(+)E(-r_qi) twice each,
1738   // the result is E((S + a_pi) + (S -b_pi-r_pi)) and E(S + a_qi + S - r_qi)
1739   for (i = 0; i < count; i++) {
1740     GNUNET_CRYPTO_paillier_decrypt (&my_privkey, &my_pubkey,
1741                                     &session->r[i], r[i]);
1742     gcry_mpi_sub (r[i], r[i], my_offset);
1743     gcry_mpi_sub (r[i], r[i], my_offset);
1744     GNUNET_CRYPTO_paillier_decrypt (&my_privkey, &my_pubkey,
1745                                     &session->r_prime[i], r_prime[i]);
1746     gcry_mpi_sub (r_prime[i], r_prime[i], my_offset);
1747     gcry_mpi_sub (r_prime[i], r_prime[i], my_offset);
1748   }
1749
1750   // calculate t = sum(ai)
1751   t = compute_square_sum (session->sorted_elements, count);
1752
1753   // calculate U
1754   u = gcry_mpi_new (0);
1755   tmp = compute_square_sum (r, count);
1756   gcry_mpi_sub (u, u, tmp);
1757   gcry_mpi_release (tmp);
1758
1759   //calculate U'
1760   u_prime = gcry_mpi_new (0);
1761   tmp = compute_square_sum (r_prime, count);
1762   gcry_mpi_sub (u_prime, u_prime, tmp);
1763
1764   GNUNET_assert (p = gcry_mpi_new (0));
1765   GNUNET_assert (p_prime = gcry_mpi_new (0));
1766   GNUNET_assert (s = gcry_mpi_new (0));
1767   GNUNET_assert (s_prime = gcry_mpi_new (0));
1768
1769   // compute P
1770   GNUNET_CRYPTO_paillier_decrypt (&my_privkey, &my_pubkey,
1771                                   session->s, s);
1772   GNUNET_CRYPTO_paillier_decrypt (&my_privkey, &my_pubkey,
1773                                   session->s_prime, s_prime);
1774
1775   // compute P
1776   gcry_mpi_add (p, s, t);
1777   gcry_mpi_add (p, p, u);
1778
1779   // compute P'
1780   gcry_mpi_add (p_prime, s_prime, t);
1781   gcry_mpi_add (p_prime, p_prime, u_prime);
1782
1783   gcry_mpi_release (t);
1784   gcry_mpi_release (u);
1785   gcry_mpi_release (u_prime);
1786   gcry_mpi_release (s);
1787   gcry_mpi_release (s_prime);
1788
1789   // compute product
1790   gcry_mpi_sub (p, p, p_prime);
1791   gcry_mpi_release (p_prime);
1792   tmp = gcry_mpi_set_ui (tmp, 2);
1793   gcry_mpi_div (p, NULL, p, tmp, 0);
1794
1795   gcry_mpi_release (tmp);
1796   for (i = 0; i < count; i++) {
1797     gcry_mpi_release (session->sorted_elements[i]);
1798     gcry_mpi_release (r[i]);
1799     gcry_mpi_release (r_prime[i]);
1800   }
1801   GNUNET_free (session->a_head);
1802   session->a_head = NULL;
1803   GNUNET_free (session->s);
1804   session->s = NULL;
1805   GNUNET_free (session->s_prime);
1806   session->s_prime = NULL;
1807   GNUNET_free (session->r);
1808   session->r = NULL;
1809   GNUNET_free (session->r_prime);
1810   session->r_prime = NULL;
1811
1812   return p;
1813 }
1814
1815
1816 /**
1817  * Handle a multipart-chunk of a request from another service to calculate a scalarproduct with us.
1818  *
1819  * @param cls closure (set from #GNUNET_CADET_connect)
1820  * @param channel connection to the other end
1821  * @param channel_ctx place to store local state associated with the channel
1822  * @param message the actual message
1823  * @return #GNUNET_OK to keep the connection open,
1824  *         #GNUNET_SYSERR to close it (signal serious error)
1825  */
1826 static int
1827 handle_alices_cyrptodata_message_multipart (void *cls,
1828                                             struct GNUNET_CADET_Channel * channel,
1829                                             void **channel_ctx,
1830                                             const struct GNUNET_MessageHeader * message)
1831 {
1832   struct ServiceSession * session;
1833   const struct GNUNET_SCALARPRODUCT_multipart_message * msg = (const struct GNUNET_SCALARPRODUCT_multipart_message *) message;
1834   struct GNUNET_CRYPTO_PaillierCiphertext *payload;
1835   uint32_t contained_elements;
1836   uint32_t msg_length;
1837
1838   // are we in the correct state?
1839   session = (struct ServiceSession *) * channel_ctx;
1840   //we are not bob
1841   if ((NULL == session->e_a) || //or we did not expect this message yet 
1842       (session->used_elements_count == session->transferred_element_count)) { //we are not expecting multipart messages
1843     goto except;
1844   }
1845   // shorter than minimum?
1846   if (ntohs (msg->header.size) <= sizeof (struct GNUNET_SCALARPRODUCT_multipart_message)) {
1847     goto except;
1848   }
1849   contained_elements = ntohl (msg->contained_element_count);
1850   msg_length = sizeof (struct GNUNET_SCALARPRODUCT_multipart_message)
1851           +contained_elements * sizeof (struct GNUNET_CRYPTO_PaillierCiphertext);
1852   //sanity check
1853   if ((ntohs (msg->header.size) != msg_length)
1854       || (session->used_elements_count < contained_elements + session->transferred_element_count)
1855       || (0 == contained_elements)) {
1856     goto except;
1857   }
1858   payload = (struct GNUNET_CRYPTO_PaillierCiphertext *) &msg[1];
1859   // Convert each vector element to MPI_value
1860   memcpy (&session->e_a[session->transferred_element_count], payload,
1861           sizeof (struct GNUNET_CRYPTO_PaillierCiphertext) * contained_elements);
1862
1863   session->transferred_element_count += contained_elements;
1864
1865   if (contained_elements == session->used_elements_count) {
1866     // single part finished
1867     if (NULL == session->intersection_op)
1868       // intersection has already finished, so we can proceed
1869       compute_service_response (session);
1870   }
1871
1872   return GNUNET_OK;
1873 except:
1874   session->channel = NULL;
1875   // and notify our client-session that we could not complete the session
1876   free_session_variables (session);
1877   if (NULL != session->client){
1878     //Alice
1879     session->client_notification_task =
1880           GNUNET_SCHEDULER_add_now (&prepare_client_end_notification,
1881                                     session);
1882   }
1883   else {
1884     //Bob
1885     if (NULL != session->response)
1886     session->response->client_notification_task =
1887           GNUNET_SCHEDULER_add_now (&prepare_client_end_notification,
1888                                     session->response);
1889     GNUNET_CONTAINER_DLL_remove (from_service_head, from_service_tail, session);
1890     GNUNET_free(session);
1891   }
1892   return GNUNET_SYSERR;
1893 }
1894
1895
1896 /**
1897  * Handle a request from another service to calculate a scalarproduct with us.
1898  *
1899  * @param cls closure (set from #GNUNET_CADET_connect)
1900  * @param channel connection to the other end
1901  * @param channel_ctx place to store local state associated with the channel
1902  * @param message the actual message
1903  * @return #GNUNET_OK to keep the connection open,
1904  *         #GNUNET_SYSERR to close it (signal serious error)
1905  */
1906 static int
1907 handle_alices_cyrptodata_message (void *cls,
1908                                   struct GNUNET_CADET_Channel * channel,
1909                                   void **channel_ctx,
1910                                   const struct GNUNET_MessageHeader * message)
1911 {
1912   struct ServiceSession * session;
1913   const struct GNUNET_SCALARPRODUCT_alices_cryptodata_message * msg = (const struct GNUNET_SCALARPRODUCT_alices_cryptodata_message *) message;
1914   struct GNUNET_CRYPTO_PaillierCiphertext *payload;
1915   uint32_t contained_elements = 0;
1916   uint32_t msg_length;
1917
1918   session = (struct ServiceSession *) * channel_ctx;
1919   //we are not bob
1920   if ((BOB != session->role)
1921       //we are expecting multipart messages instead
1922       || (NULL != session->e_a)
1923       //or we did not expect this message yet
1924       || //intersection OP has not yet finished
1925       !((NULL != session->intersection_op)
1926         //intersection OP done
1927         || (session->response->sorted_elements)
1928         )) {
1929     goto invalid_msg;
1930   }
1931
1932   // shorter than minimum?
1933   if (ntohs (msg->header.size) <= sizeof (struct GNUNET_SCALARPRODUCT_multipart_message)) {
1934     goto invalid_msg;
1935   }
1936
1937   contained_elements = ntohl (msg->contained_element_count);
1938   msg_length = sizeof (struct GNUNET_SCALARPRODUCT_alices_cryptodata_message)
1939           +contained_elements * sizeof (struct GNUNET_CRYPTO_PaillierCiphertext);
1940
1941   //sanity check: is the message as long as the message_count fields suggests?
1942   if ((ntohs (msg->header.size) != msg_length) ||
1943       (session->used_elements_count < session->transferred_element_count + contained_elements) ||
1944       (0 == contained_elements)) {
1945     goto invalid_msg;
1946   }
1947
1948   session->transferred_element_count = contained_elements;
1949   payload = (struct GNUNET_CRYPTO_PaillierCiphertext*) &msg[1];
1950
1951   session->e_a = GNUNET_malloc (sizeof (struct GNUNET_CRYPTO_PaillierCiphertext) * session->used_elements_count);
1952   memcpy (&session->e_a[0], payload, contained_elements * sizeof (struct GNUNET_CRYPTO_PaillierCiphertext));
1953   if (contained_elements == session->used_elements_count) {
1954     // single part finished
1955     if (NULL == session->intersection_op)
1956       // intersection has already finished, so we can proceed
1957       compute_service_response (session);
1958   }
1959   return GNUNET_OK;
1960 invalid_msg:
1961   GNUNET_break_op (0);
1962   session->channel = NULL;
1963   // and notify our client-session that we could not complete the session
1964   free_session_variables (session);
1965   if (NULL != session->client){
1966     //Alice
1967     session->client_notification_task =
1968           GNUNET_SCHEDULER_add_now (&prepare_client_end_notification,
1969                                     session);
1970   }
1971   else {
1972     //Bob
1973     if (NULL != session->response)
1974     session->response->client_notification_task =
1975           GNUNET_SCHEDULER_add_now (&prepare_client_end_notification,
1976                                     session->response);
1977     GNUNET_CONTAINER_DLL_remove (from_service_head, from_service_tail, session);
1978     GNUNET_free(session);
1979   }
1980   return GNUNET_SYSERR;
1981 }
1982
1983
1984 /**
1985  * Handle a request from another service to calculate a scalarproduct with us.
1986  *
1987  * @param cls closure (set from #GNUNET_CADET_connect)
1988  * @param channel connection to the other end
1989  * @param channel_ctx place to store local state associated with the channel
1990  * @param message the actual message
1991  * @return #GNUNET_OK to keep the connection open,
1992  *         #GNUNET_SYSERR to close it (signal serious error)
1993  */
1994 static int
1995 handle_alices_computation_request (void *cls,
1996                         struct GNUNET_CADET_Channel * channel,
1997                         void **channel_ctx,
1998                         const struct GNUNET_MessageHeader * message)
1999 {
2000   struct ServiceSession * session;
2001   struct ServiceSession * client_session;
2002   const struct GNUNET_SCALARPRODUCT_service_request * msg = (const struct GNUNET_SCALARPRODUCT_service_request *) message;
2003   uint32_t total_elements;
2004
2005   session = (struct ServiceSession *) * channel_ctx;
2006   if (session->total != 0) {
2007     // must be a fresh session
2008     goto invalid_msg;
2009   }
2010   // Check if message was sent by me, which would be bad!
2011   if (!memcmp (&session->peer, &me, sizeof (struct GNUNET_PeerIdentity))) {
2012     GNUNET_free (session);
2013     GNUNET_break (0);
2014     return GNUNET_SYSERR;
2015   }
2016   // shorter than expected?
2017   if (ntohs (msg->header.size) != sizeof (struct GNUNET_SCALARPRODUCT_service_request)) {
2018     GNUNET_free (session);
2019     GNUNET_break_op (0);
2020     return GNUNET_SYSERR;
2021   }
2022   total_elements = ntohl (msg->total_element_count);
2023
2024   //sanity check: is the message as long as the message_count fields suggests?
2025   if (1 > total_elements) {
2026     GNUNET_free (session);
2027     GNUNET_break_op (0);
2028     return GNUNET_SYSERR;
2029   }
2030   if (find_matching_session (from_service_tail,
2031                              &msg->session_id,
2032                              total_elements,
2033                              NULL)) {
2034     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
2035                 _ ("Got message with duplicate session key (`%s'), ignoring service request.\n"),
2036                 (const char *) &(msg->session_id));
2037     GNUNET_free (session);
2038     return GNUNET_SYSERR;
2039   }
2040
2041   session->total = total_elements;
2042   session->channel = channel;
2043
2044   // session key
2045   memcpy (&session->session_id, &msg->session_id, sizeof (struct GNUNET_HashCode));
2046
2047   // public key
2048   memcpy (&session->remote_pubkey, &msg->public_key, sizeof (struct GNUNET_CRYPTO_PaillierPublicKey));
2049
2050   //check if service queue contains a matching request
2051   client_session = find_matching_session (from_client_tail,
2052                                           &session->session_id,
2053                                           session->total, NULL);
2054
2055   GNUNET_CONTAINER_DLL_insert (from_service_head, from_service_tail, session);
2056
2057   if ((NULL != client_session)
2058       && (client_session->transferred_element_count == client_session->total)) {
2059
2060     GNUNET_log (GNUNET_ERROR_TYPE_INFO, _ ("Got session with key %s and a matching element set, processing.\n"), GNUNET_h2s (&session->session_id));
2061
2062     session->response = client_session;
2063     session->intersected_elements = client_session->intersected_elements;
2064     client_session->intersected_elements = NULL;
2065     session->intersection_set = client_session->intersection_set;
2066     client_session->intersection_set = NULL;
2067
2068     session->intersection_op = GNUNET_SET_prepare (&session->peer,
2069                                                    &session->session_id,
2070                                                    NULL,
2071                                                    GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_WEAK, UINT16_MAX),
2072                                                    GNUNET_SET_RESULT_REMOVED,
2073                                                    cb_intersection_element_removed,
2074                                                    session);
2075
2076     GNUNET_SET_commit (session->intersection_op, session->intersection_set);
2077   }
2078   else {
2079     GNUNET_log (GNUNET_ERROR_TYPE_INFO, _ ("Got session with key %s without a matching element set, queueing.\n"), GNUNET_h2s (&session->session_id));
2080   }
2081
2082   return GNUNET_OK;
2083 invalid_msg:
2084   GNUNET_break_op (0);
2085   session->channel = NULL;
2086   // and notify our client-session that we could not complete the session
2087   free_session_variables (session);
2088   if (NULL != session->client){
2089     //Alice
2090     session->client_notification_task =
2091           GNUNET_SCHEDULER_add_now (&prepare_client_end_notification,
2092                                     session);
2093   }
2094   else {
2095     //Bob
2096     if (NULL != session->response)
2097     session->response->client_notification_task =
2098           GNUNET_SCHEDULER_add_now (&prepare_client_end_notification,
2099                                     session->response);
2100     GNUNET_CONTAINER_DLL_remove (from_service_head, from_service_tail, session);
2101     GNUNET_free(session);
2102   }
2103   return GNUNET_SYSERR;
2104 }
2105
2106
2107 /**
2108  * Handle a multipart chunk of a response we got from another service we wanted to calculate a scalarproduct with.
2109  *
2110  * @param cls closure (set from #GNUNET_CADET_connect)
2111  * @param channel connection to the other end
2112  * @param channel_ctx place to store local state associated with the channel
2113  * @param message the actual message
2114  * @return #GNUNET_OK to keep the connection open,
2115  *         #GNUNET_SYSERR to close it (signal serious error)
2116  */
2117 static int
2118 handle_bobs_cryptodata_multipart (void *cls,
2119                                    struct GNUNET_CADET_Channel * channel,
2120                                    void **channel_ctx,
2121                                    const struct GNUNET_MessageHeader * message)
2122 {
2123   struct ServiceSession * session;
2124   const struct GNUNET_SCALARPRODUCT_multipart_message * msg = (const struct GNUNET_SCALARPRODUCT_multipart_message *) message;
2125   struct GNUNET_CRYPTO_PaillierCiphertext * payload;
2126   size_t i;
2127   uint32_t contained = 0;
2128   size_t msg_size;
2129   size_t required_size;
2130
2131   GNUNET_assert (NULL != message);
2132   // are we in the correct state?
2133   session = (struct ServiceSession *) * channel_ctx;
2134   if ((ALICE != session->role) || (NULL == session->sorted_elements)) {
2135     goto invalid_msg;
2136   }
2137   msg_size = ntohs (msg->header.size);
2138   required_size = sizeof (struct GNUNET_SCALARPRODUCT_multipart_message)
2139           + 2 * sizeof (struct GNUNET_CRYPTO_PaillierCiphertext);
2140   // shorter than minimum?
2141   if (required_size > msg_size) {
2142     goto invalid_msg;
2143   }
2144   contained = ntohl (msg->contained_element_count);
2145   required_size = sizeof (struct GNUNET_SCALARPRODUCT_multipart_message)
2146           + 2 * contained * sizeof (struct GNUNET_CRYPTO_PaillierCiphertext);
2147   //sanity check: is the message as long as the message_count fields suggests?
2148   if ((required_size != msg_size) || (session->used_elements_count < session->transferred_element_count + contained)) {
2149     goto invalid_msg;
2150   }
2151   payload = (struct GNUNET_CRYPTO_PaillierCiphertext *) &msg[1];
2152   // Convert each k[][perm] to its MPI_value
2153   for (i = 0; i < contained; i++) {
2154     memcpy (&session->r[session->transferred_element_count + i], &payload[2 * i], sizeof (struct GNUNET_CRYPTO_PaillierCiphertext));
2155     memcpy (&session->r_prime[session->transferred_element_count + i], &payload[2 * i], sizeof (struct GNUNET_CRYPTO_PaillierCiphertext));
2156   }
2157   session->transferred_element_count += contained;
2158   if (session->transferred_element_count != session->used_elements_count)
2159     return GNUNET_OK;
2160   session->product = compute_scalar_product (session); //never NULL
2161
2162 invalid_msg:
2163   GNUNET_break_op (NULL != session->product);
2164   session->channel = NULL;
2165   // send message with product to client
2166   if (NULL != session->client){
2167     //Alice
2168     session->client_notification_task =
2169           GNUNET_SCHEDULER_add_now (&prepare_client_response,
2170                                     session);
2171   }
2172   else {
2173     //Bob
2174     if (NULL != session->response)
2175     session->response->client_notification_task =
2176           GNUNET_SCHEDULER_add_now (&prepare_client_end_notification,
2177                                     session->response);
2178     GNUNET_CONTAINER_DLL_remove (from_service_head, from_service_tail, session);
2179     free_session_variables (session);
2180     GNUNET_free(session);
2181   }
2182   // the channel has done its job, terminate our connection and the channel
2183   // the peer will be notified that the channel was destroyed via channel_destruction_handler
2184   // just close the connection, as recommended by Christian
2185   return GNUNET_SYSERR;
2186 }
2187
2188
2189 /**
2190  * Handle a response we got from another service we wanted to calculate a scalarproduct with.
2191  *
2192  * @param cls closure (set from #GNUNET_CADET_connect)
2193  * @param channel connection to the other end
2194  * @param channel_ctx place to store local state associated with the channel
2195  * @param message the actual message
2196  * @return #GNUNET_OK to keep the connection open,
2197  *         #GNUNET_SYSERR to close it (we are done)
2198  */
2199 static int
2200 handle_bobs_cryptodata_message (void *cls,
2201                          struct GNUNET_CADET_Channel * channel,
2202                          void **channel_ctx,
2203                          const struct GNUNET_MessageHeader * message)
2204 {
2205   struct ServiceSession * session;
2206   const struct GNUNET_SCALARPRODUCT_service_response * msg = (const struct GNUNET_SCALARPRODUCT_service_response *) message;
2207   struct GNUNET_CRYPTO_PaillierCiphertext * payload;
2208   size_t i;
2209   uint32_t contained = 0;
2210   size_t msg_size;
2211   size_t required_size;
2212
2213   GNUNET_assert (NULL != message);
2214   session = (struct ServiceSession *) * channel_ctx;
2215   // are we in the correct state?
2216   if (0 /*//TODO: correct state*/) {
2217     goto invalid_msg;
2218   }
2219   //we need at least a full message without elements attached
2220   msg_size = ntohs (msg->header.size);
2221   required_size = sizeof (struct GNUNET_SCALARPRODUCT_service_response) + 2 * sizeof (struct GNUNET_CRYPTO_PaillierCiphertext);
2222
2223   if (required_size > msg_size) {
2224     goto invalid_msg;
2225   }
2226   contained = ntohl (msg->contained_element_count);
2227   required_size = sizeof (struct GNUNET_SCALARPRODUCT_service_response)
2228           + 2 * contained * sizeof (struct GNUNET_CRYPTO_PaillierCiphertext)
2229           + 2 * sizeof (struct GNUNET_CRYPTO_PaillierCiphertext);
2230   //sanity check: is the message as long as the message_count fields suggests?
2231   if ((msg_size != required_size) || (session->used_elements_count < contained)) {
2232     goto invalid_msg;
2233   }
2234   session->transferred_element_count = contained;
2235   //convert s
2236   payload = (struct GNUNET_CRYPTO_PaillierCiphertext *) &msg[1];
2237
2238   session->s = GNUNET_malloc (sizeof (struct GNUNET_CRYPTO_PaillierCiphertext));
2239   session->s_prime = GNUNET_malloc (sizeof (struct GNUNET_CRYPTO_PaillierCiphertext));
2240   memcpy (session->s, &payload[0], sizeof (struct GNUNET_CRYPTO_PaillierCiphertext));
2241   memcpy (session->s_prime, &payload[1], sizeof (struct GNUNET_CRYPTO_PaillierCiphertext));
2242
2243   session->r = GNUNET_malloc (sizeof (struct GNUNET_CRYPTO_PaillierCiphertext) * session->used_elements_count);
2244   session->r_prime = GNUNET_malloc (sizeof (struct GNUNET_CRYPTO_PaillierCiphertext) * session->used_elements_count);
2245
2246   // Convert each k[][perm] to its MPI_value
2247   for (i = 0; i < contained; i++) {
2248     memcpy (&session->r[i], &payload[2 + 2 * i], sizeof (struct GNUNET_CRYPTO_PaillierCiphertext));
2249     memcpy (&session->r_prime[i], &payload[3 + 2 * i], sizeof (struct GNUNET_CRYPTO_PaillierCiphertext));
2250   }
2251   if (session->transferred_element_count != session->used_elements_count)
2252     return GNUNET_OK; //wait for the other multipart chunks
2253   session->product = compute_scalar_product (session); //never NULL
2254
2255 invalid_msg:
2256   GNUNET_break_op (NULL != session->product);
2257   session->channel = NULL;
2258   // send message with product to client
2259   if (NULL != session->client){
2260     //Alice
2261     session->client_notification_task =
2262           GNUNET_SCHEDULER_add_now (&prepare_client_response,
2263                                     session);
2264   }
2265   else {
2266     //Bob
2267     if (NULL != session->response)
2268     session->response->client_notification_task =
2269           GNUNET_SCHEDULER_add_now (&prepare_client_end_notification,
2270                                     session->response);
2271     GNUNET_CONTAINER_DLL_remove (from_service_head, from_service_tail, session);
2272     free_session_variables (session);
2273     GNUNET_free(session);
2274   }
2275   // the channel has done its job, terminate our connection and the channel
2276   // the peer will be notified that the channel was destroyed via channel_destruction_handler
2277   // just close the connection, as recommended by Christian
2278   return GNUNET_SYSERR;
2279 }
2280
2281
2282 /**
2283  * Task run during shutdown.
2284  *
2285  * @param cls unused
2286  * @param tc unused
2287  */
2288 static void
2289 shutdown_task (void *cls,
2290                const struct GNUNET_SCHEDULER_TaskContext *tc)
2291 {
2292   struct ServiceSession * session;
2293   GNUNET_log (GNUNET_ERROR_TYPE_INFO, _ ("Shutting down, initiating cleanup.\n"));
2294
2295   do_shutdown = GNUNET_YES;
2296
2297   // terminate all owned open channels.
2298   for (session = from_client_head; NULL != session; session = session->next) {
2299     if ((0/*//TODO: not finalized*/) && (NULL != session->channel)) {
2300       GNUNET_CADET_channel_destroy (session->channel);
2301       session->channel = NULL;
2302     }
2303     if (GNUNET_SCHEDULER_NO_TASK != session->client_notification_task) {
2304       GNUNET_SCHEDULER_cancel (session->client_notification_task);
2305       session->client_notification_task = GNUNET_SCHEDULER_NO_TASK;
2306     }
2307     if (NULL != session->client) {
2308       GNUNET_SERVER_client_disconnect (session->client);
2309       session->client = NULL;
2310     }
2311   }
2312   for (session = from_service_head; NULL != session; session = session->next)
2313     if (NULL != session->channel) {
2314       GNUNET_CADET_channel_destroy (session->channel);
2315       session->channel = NULL;
2316     }
2317
2318   if (my_cadet) {
2319     GNUNET_CADET_disconnect (my_cadet);
2320     my_cadet = NULL;
2321   }
2322 }
2323
2324
2325 /**
2326  * Initialization of the program and message handlers
2327  *
2328  * @param cls closure
2329  * @param server the initialized server
2330  * @param c configuration to use
2331  */
2332 static void
2333 run (void *cls,
2334      struct GNUNET_SERVER_Handle *server,
2335      const struct GNUNET_CONFIGURATION_Handle *c)
2336 {
2337   static const struct GNUNET_SERVER_MessageHandler server_handlers[] = {
2338     {&handle_client_message, NULL, GNUNET_MESSAGE_TYPE_SCALARPRODUCT_CLIENT_TO_ALICE, 0},
2339     {&handle_client_message, NULL, GNUNET_MESSAGE_TYPE_SCALARPRODUCT_CLIENT_TO_BOB, 0},
2340     {&handle_client_message_multipart, NULL, GNUNET_MESSAGE_TYPE_SCALARPRODUCT_CLIENT_MUTLIPART, 0},
2341     {NULL, NULL, 0, 0}
2342   };
2343   static const struct GNUNET_CADET_MessageHandler cadet_handlers[] = {
2344     { &handle_alices_computation_request, GNUNET_MESSAGE_TYPE_SCALARPRODUCT_ALICE_CRYPTODATA, 0},
2345     { &handle_alices_cyrptodata_message, GNUNET_MESSAGE_TYPE_SCALARPRODUCT_ALICE_CRYPTODATA, 0},
2346     { &handle_alices_cyrptodata_message_multipart, GNUNET_MESSAGE_TYPE_SCALARPRODUCT_ALICE_CRYPTODATA_MULTIPART, 0},
2347     { &handle_bobs_cryptodata_message, GNUNET_MESSAGE_TYPE_SCALARPRODUCT_BOB_CRYPTODATA, 0},
2348     { &handle_bobs_cryptodata_multipart, GNUNET_MESSAGE_TYPE_SCALARPRODUCT_BOB_CRYPTODATA_MULTIPART, 0},
2349     {NULL, 0, 0}
2350   };
2351   static const uint32_t ports[] = {
2352     GNUNET_APPLICATION_TYPE_SCALARPRODUCT,
2353     0
2354   };
2355   //generate private/public key set
2356   GNUNET_CRYPTO_paillier_create (&my_pubkey, &my_privkey);
2357
2358   // offset has to be sufficiently small to allow computation of:
2359   // m1+m2 mod n == (S + a) + (S + b) mod n,
2360   // if we have more complex operations, this factor needs to be lowered
2361   my_offset = gcry_mpi_new (GNUNET_CRYPTO_PAILLIER_BITS / 3);
2362   gcry_mpi_set_bit (my_offset, GNUNET_CRYPTO_PAILLIER_BITS / 3);
2363
2364   // register server callbacks and disconnect handler
2365   GNUNET_SERVER_add_handlers (server, server_handlers);
2366   GNUNET_SERVER_disconnect_notify (server,
2367                                    &handle_client_disconnect,
2368                                    NULL);
2369   GNUNET_break (GNUNET_OK ==
2370                 GNUNET_CRYPTO_get_peer_identity (c,
2371                                                  &me));
2372   my_cadet = GNUNET_CADET_connect (c, NULL,
2373                                  &cb_channel_incoming,
2374                                  &cb_channel_destruction,
2375                                  cadet_handlers, ports);
2376   if (!my_cadet) {
2377     GNUNET_log (GNUNET_ERROR_TYPE_ERROR, _ ("Connect to CADET failed\n"));
2378     GNUNET_SCHEDULER_shutdown ();
2379     return;
2380   }
2381   GNUNET_log (GNUNET_ERROR_TYPE_INFO, _ ("CADET initialized\n"));
2382   GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_FOREVER_REL,
2383                                 &shutdown_task,
2384                                 NULL);
2385 }
2386
2387
2388 /**
2389  * The main function for the scalarproduct service.
2390  *
2391  * @param argc number of arguments from the command line
2392  * @param argv command line arguments
2393  * @return 0 ok, 1 on error
2394  */
2395 int
2396 main (int argc, char *const *argv)
2397 {
2398   return (GNUNET_OK ==
2399           GNUNET_SERVICE_run (argc, argv,
2400                               "scalarproduct",
2401                               GNUNET_SERVICE_OPTION_NONE,
2402                               &run, NULL)) ? 0 : 1;
2403 }
2404
2405 /* end of gnunet-service-scalarproduct.c */