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