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