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