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