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