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