80fe35758ea7496fd12a654b74496a91ed02a39c
[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 //                      Global Variables
48 ///////////////////////////////////////////////////////////////////////////////
49
50
51 /**
52  * Handle to the core service (NULL until we've connected to it).
53  */
54 static struct GNUNET_MESH_Handle *my_mesh;
55
56 /**
57  * The identity of this host.
58  */
59 static struct GNUNET_PeerIdentity me;
60
61 /**
62  * Service's own public key represented as string
63  */
64 static unsigned char * my_pubkey_external;
65
66 /**
67  * Service's own public key represented as string
68  */
69 static uint16_t my_pubkey_external_length = 0;
70
71 /**
72  * Service's own n
73  */
74 static gcry_mpi_t my_n;
75
76 /**
77  * Service's own n^2 (kept for performance)
78  */
79 static gcry_mpi_t my_nsquare;
80
81 /**
82  * Service's own public exponent
83  */
84 static gcry_mpi_t my_g;
85
86 /**
87  * Service's own private multiplier
88  */
89 static gcry_mpi_t my_mu;
90
91 /**
92  * Service's own private exponent
93  */
94 static gcry_mpi_t my_lambda;
95
96 /**
97  * Service's offset for values that could possibly be negative but are plaintext for encryption.
98  */
99 static gcry_mpi_t my_offset;
100
101 /**
102  * Head of our double linked list for client-requests sent to us. 
103  * for all of these elements we calculate a scalar product with a remote peer
104  * split between service->service and client->service for simplicity
105  */
106 static struct ServiceSession * from_client_head;
107 /**
108  * Tail of our double linked list for client-requests sent to us. 
109  * for all of these elements we calculate a scalar product with a remote peer
110  * split between service->service and client->service for simplicity
111  */
112 static struct ServiceSession * from_client_tail;
113
114 /**
115  * Head of our double linked list for service-requests sent to us. 
116  * for all of these elements we help the requesting service in calculating a scalar product
117  * split between service->service and client->service for simplicity
118  */
119 static struct ServiceSession * from_service_head;
120
121 /**
122  * Tail of our double linked list for service-requests sent to us. 
123  * for all of these elements we help the requesting service in calculating a scalar product
124  * split between service->service and client->service for simplicity
125  */
126 static struct ServiceSession * from_service_tail;
127
128 /**
129  * Certain events (callbacks for server & mesh operations) must not be queued after shutdown.
130  */
131 static int do_shutdown;
132
133 ///////////////////////////////////////////////////////////////////////////////
134 //                      Helper Functions
135 ///////////////////////////////////////////////////////////////////////////////
136
137 /**
138  * Generates an Paillier private/public keyset and extracts the values using libgrcypt only
139  */
140 static void
141 generate_keyset ()
142 {
143   gcry_sexp_t gen_parms;
144   gcry_sexp_t key;
145   gcry_sexp_t tmp_sexp;
146   gcry_mpi_t p;
147   gcry_mpi_t q;
148   gcry_mpi_t tmp1;
149   gcry_mpi_t tmp2;
150   gcry_mpi_t gcd;
151
152   size_t erroff = 0;
153
154   // we can still use the RSA keygen for generating p,q,n, but using e is pointless.
155   GNUNET_assert (0 == gcry_sexp_build (&gen_parms, &erroff,
156                                        "(genkey(rsa(nbits %d)(rsa-use-e 3:257)))",
157                                        KEYBITS));
158
159   GNUNET_assert (0 == gcry_pk_genkey (&key, gen_parms));
160   gcry_sexp_release (gen_parms);
161
162   // get n and d of our publickey as MPI  
163   tmp_sexp = gcry_sexp_find_token (key, "n", 0);
164   GNUNET_assert (tmp_sexp);
165   my_n = gcry_sexp_nth_mpi (tmp_sexp, 1, GCRYMPI_FMT_USG);
166   gcry_sexp_release (tmp_sexp);
167   tmp_sexp = gcry_sexp_find_token (key, "p", 0);
168   GNUNET_assert (tmp_sexp);
169   p = gcry_sexp_nth_mpi (tmp_sexp, 1, GCRYMPI_FMT_USG);
170   gcry_sexp_release (tmp_sexp);
171   tmp_sexp = gcry_sexp_find_token (key, "q", 0);
172   GNUNET_assert (tmp_sexp);
173   q = gcry_sexp_nth_mpi (tmp_sexp, 1, GCRYMPI_FMT_USG);
174   gcry_sexp_release (key);
175
176   tmp1 = gcry_mpi_new (0);
177   tmp2 = gcry_mpi_new (0);
178   gcd = gcry_mpi_new (0);
179   my_g = gcry_mpi_new (0);
180   my_mu = gcry_mpi_new (0);
181   my_nsquare = gcry_mpi_new (0);
182   my_lambda = gcry_mpi_new (0);
183
184   // calculate lambda
185   // lambda = \frac{(p-1)*(q-1)}{gcd(p-1,q-1)}
186   gcry_mpi_sub_ui (tmp1, p, 1);
187   gcry_mpi_sub_ui (tmp2, q, 1);
188   gcry_mpi_gcd (gcd, tmp1, tmp2);
189   gcry_mpi_set (my_lambda, tmp1);
190   gcry_mpi_mul (my_lambda, my_lambda, tmp2);
191   gcry_mpi_div (my_lambda, NULL, my_lambda, gcd, 0);
192
193   // generate a g
194   gcry_mpi_mul (my_nsquare, my_n, my_n);
195   do
196     {
197       // find a matching g
198       do
199         {
200           gcry_mpi_randomize (my_g, KEYBITS * 2, GCRY_WEAK_RANDOM);
201           // g must be smaller than n^2
202           if (0 >= gcry_mpi_cmp (my_g, my_nsquare))
203             continue;
204
205           // g must have gcd == 1 with n^2
206           gcry_mpi_gcd (gcd, my_g, my_nsquare);
207         }
208       while (gcry_mpi_cmp_ui (gcd, 1));
209
210       // is this a valid g?
211       // if so, gcd(((g^lambda mod n^2)-1 )/n, n) = 1
212       gcry_mpi_powm (tmp1, my_g, my_lambda, my_nsquare);
213       gcry_mpi_sub_ui (tmp1, tmp1, 1);
214       gcry_mpi_div (tmp1, NULL, tmp1, my_n, 0);
215       gcry_mpi_gcd (gcd, tmp1, my_n);
216     }
217   while (gcry_mpi_cmp_ui (gcd, 1));
218
219   // calculate our mu based on g and n.
220   // mu = (((g^lambda mod n^2)-1 )/n)^-1 mod n
221   gcry_mpi_invm (my_mu, tmp1, my_n);
222
223   GNUNET_assert (0 == gcry_sexp_build (&key, &erroff,
224                                        "(public-key (paillier (n %M)(g %M)))",
225                                        my_n, my_g));
226
227   // get the length of this sexpression
228   my_pubkey_external_length = gcry_sexp_sprint (key,
229                                                 GCRYSEXP_FMT_CANON,
230                                                 NULL,
231                                                 UINT16_MAX);
232
233   GNUNET_assert (my_pubkey_external_length > 0);
234   my_pubkey_external = GNUNET_malloc (my_pubkey_external_length);
235
236   // convert the sexpression to canonical format
237   gcry_sexp_sprint (key,
238                     GCRYSEXP_FMT_CANON,
239                     my_pubkey_external,
240                     my_pubkey_external_length);
241
242   gcry_sexp_release (key);
243   
244   // offset has to be sufficiently small to allow computation of:
245   // m1+m2 mod n == (S + a) + (S + b) mod n, 
246   // if we have more complex operations, this factor needs to be lowered
247   my_offset = gcry_mpi_new(KEYBITS/3);
248   gcry_mpi_set_bit(my_offset, KEYBITS/3);
249
250   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, _ ("Generated key set with key length %d bits.\n"), KEYBITS);
251 }
252
253
254 /**
255  * If target != size, move target bytes to the
256  * end of the size-sized buffer and zero out the
257  * first target-size bytes.
258  *
259  * @param buf original buffer
260  * @param size number of bytes in the buffer
261  * @param target target size of the buffer
262  */
263 static void
264 adjust (unsigned char *buf, size_t size, size_t target)
265 {
266   if (size < target)
267     {
268       memmove (&buf[target - size], buf, size);
269       memset (buf, 0, target - size);
270     }
271 }
272
273
274 /**
275  * encrypts an element using the paillier crypto system
276  * 
277  * @param c ciphertext (output)
278  * @param m plaintext
279  * @param g the public base
280  * @param n the module from which which r is chosen (Z*_n)
281  * @param n_square the module for encryption, for performance reasons.
282  */
283 static void
284 encrypt_element (gcry_mpi_t c, gcry_mpi_t m, gcry_mpi_t g, gcry_mpi_t n, gcry_mpi_t n_square)
285 {
286   gcry_mpi_t tmp;
287
288   GNUNET_assert (tmp = gcry_mpi_new (0));
289
290   while (0 >= gcry_mpi_cmp_ui (tmp, 1))
291     {
292       gcry_mpi_randomize (tmp, KEYBITS / 3, GCRY_WEAK_RANDOM);
293       // r must be 1 < r < n
294     }
295
296   gcry_mpi_powm (c, g, m, n_square);
297   gcry_mpi_powm (tmp, tmp, n, n_square);
298   gcry_mpi_mulm (c, tmp, c, n_square);
299
300   gcry_mpi_release (tmp);
301 }
302
303 /**
304  * decrypts an element using the paillier crypto system
305  * 
306  * @param m plaintext (output)
307  * @param c the ciphertext
308  * @param mu the modifier to correct encryption
309  * @param lambda the private exponent
310  * @param n the outer module for decryption
311  * @param n_square the inner module for decryption
312  */
313 static void
314 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)
315 {
316   gcry_mpi_powm (m, c, lambda, n_square);
317   gcry_mpi_sub_ui (m, m, 1);
318   gcry_mpi_div (m, NULL, m, n, 0);
319   gcry_mpi_mulm (m, m, mu, n);
320 }
321
322
323 /**
324  * computes the square sum over a vector of a given length.
325  * 
326  * @param vector the vector to encrypt
327  * @param length the length of the vector
328  * @return an MPI value containing the calculated sum, never NULL
329  */
330 static gcry_mpi_t
331 compute_square_sum (gcry_mpi_t * vector, uint16_t length)
332 {
333   gcry_mpi_t elem;
334   gcry_mpi_t sum;
335   int32_t i;
336
337   GNUNET_assert (sum = gcry_mpi_new (0));
338   GNUNET_assert (elem = gcry_mpi_new (0));
339
340   // calculare E(sum (ai ^ 2), publickey)
341   for (i = 0; i < length; i++)
342     {
343       gcry_mpi_mul (elem, vector[i], vector[i]);
344       gcry_mpi_add (sum, sum, elem);
345     }
346   gcry_mpi_release (elem);
347
348   return sum;
349 }
350
351
352 /**
353  * Primitive callback for copying over a message, as they
354  * usually are too complex to be handled in the callback itself.
355  * clears a session-callback, if a session was handed over and the transmit handle was stored
356  * 
357  * @param cls the message object
358  * @param size the size of the buffer we got
359  * @param buf the buffer to copy the message to
360  * @return 0 if we couldn't copy, else the size copied over
361  */
362 static size_t
363 do_send_message (void *cls, size_t size, void *buf)
364 {
365   struct MessageObject * info = cls;
366   struct GNUNET_MessageHeader * msg;
367   size_t written = 0;
368
369   GNUNET_assert (info);
370   msg = info->msg;
371   GNUNET_assert (msg);
372   GNUNET_assert (buf);
373
374   if (ntohs (msg->size) == size)
375     {
376       memcpy (buf, msg, size);
377       written = size;
378     }
379
380   // reset the transmit handle, if necessary
381   if (info->transmit_handle)
382     *info->transmit_handle = NULL;
383
384   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, 
385               "Sent a message of type %hu.\n", 
386               ntohs (msg->type));
387   GNUNET_free(msg);
388   GNUNET_free(info);
389   return written;
390 }
391
392
393 /**
394  * initializes a new vector with fresh MPI values (=0) of a given length
395  * 
396  * @param length of the vector to create
397  * @return the initialized vector, never NULL
398  */
399 static gcry_mpi_t *
400 initialize_mpi_vector (uint16_t length)
401 {
402   uint32_t i;
403   gcry_mpi_t * output = GNUNET_malloc (sizeof (gcry_mpi_t) * length);
404
405   for (i = 0; i < length; i++)
406     GNUNET_assert (NULL != (output[i] = gcry_mpi_new (0)));
407   return output;
408 }
409
410
411 /**
412  * permutes an MPI vector according to the given permutation vector
413  * 
414  * @param vector the vector to permuted
415  * @param perm the permutation to use
416  * @param length the length of the vectors
417  * @return the permuted vector (same as input), never NULL
418  */
419 static gcry_mpi_t *
420 permute_vector (gcry_mpi_t * vector,
421                 unsigned int * perm,
422                 uint32_t length)
423 {
424   gcry_mpi_t tmp[length];
425   uint32_t i;
426
427   GNUNET_assert (length > 0);
428
429   // backup old layout
430   memcpy (tmp, vector, length * sizeof (gcry_mpi_t));
431
432   // permute vector according to given 
433   for (i = 0; i < length; i++)
434     vector[i] = tmp[perm[i]];
435
436   return vector;
437 }
438
439
440 /**
441  * Populate a vector with random integer values and convert them to 
442  * 
443  * @param length the length of the vector we must generate
444  * @return an array of MPI values with random values
445  */
446 static gcry_mpi_t *
447 generate_random_vector (uint16_t length)
448 {
449   gcry_mpi_t * random_vector;
450   int32_t value;
451   uint32_t i;
452
453   random_vector = initialize_mpi_vector (length);
454   for (i = 0; i < length; i++)
455     {
456       value = (int32_t) GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_WEAK, UINT32_MAX);
457
458       // long to gcry_mpi_t
459       if (value < 0)
460         gcry_mpi_sub_ui (random_vector[i],
461                          random_vector[i],
462                          -value);
463       else
464         random_vector[i] = gcry_mpi_set_ui (random_vector[i], value);
465     }
466
467   return random_vector;
468 }
469
470
471 /**
472  * Finds a not terminated client/service session in the 
473  * given DLL based on session key, element count and state.
474  * 
475  * @param tail - the tail of the DLL
476  * @param my - the session to compare it to
477  * @return a pointer to a matching session, 
478  *         else NULL
479  */
480 static struct ServiceSession *
481 find_matching_session (struct ServiceSession * tail,
482                        const struct GNUNET_HashCode * key,
483                        uint16_t element_count,
484                        enum SessionState * state,
485                        const struct GNUNET_PeerIdentity * peerid)
486 {
487   struct ServiceSession * curr;
488
489   for (curr = tail; NULL != curr; curr = curr->prev)
490     {
491       // if the key matches, and the element_count is same
492       if ((!memcmp (&curr->key, key, sizeof (struct GNUNET_HashCode)))
493           && (curr->element_count == element_count))
494         {
495           // if incoming state is NULL OR is same as state of the queued request
496           if ((NULL == state) || (curr->state == *state))
497             {
498               // if peerid is NULL OR same as the peer Id in the queued request
499               if ((NULL == peerid)
500                   || (!memcmp (&curr->peer, peerid, sizeof (struct GNUNET_PeerIdentity))))
501                 // matches and is not an already terminated session
502                 return curr;
503             }
504         }
505     }
506
507   return NULL;
508 }
509
510
511 static void
512 destroy_tunnel (void *cls,
513                 const struct GNUNET_SCHEDULER_TaskContext *tc)
514 {
515   struct ServiceSession * session = cls;
516
517   if (session->tunnel)
518     {
519       GNUNET_MESH_tunnel_destroy (session->tunnel);
520       session->tunnel = NULL;
521     }
522   session->service_transmit_handle = NULL;
523   // we need to set this to NULL so there is no problem with double-cancel later on.
524 }
525
526
527 static void
528 free_session (struct ServiceSession * session)
529 {
530   unsigned int i;
531
532   if (FINALIZED != session->state)
533     {
534       if (session->a)
535         {
536           for (i = 0; i < session->used_element_count; i++)
537             gcry_mpi_release (session->a[i]);
538
539           GNUNET_free (session->a);
540         }
541       if (session->product)
542         gcry_mpi_release (session->product);
543
544       if (session->remote_pubkey)
545         gcry_sexp_release (session->remote_pubkey);
546
547       GNUNET_free_non_null (session->vector);
548     }
549
550   GNUNET_free (session);
551 }
552 ///////////////////////////////////////////////////////////////////////////////
553 //                      Event and Message Handlers
554 ///////////////////////////////////////////////////////////////////////////////
555
556
557 /**
558  * A client disconnected. 
559  * 
560  * Remove the associated session(s), release datastructures 
561  * and cancel pending outgoing transmissions to the client.
562  * if the session has not yet completed, we also cancel Alice's request to Bob.
563  *
564  * @param cls closure, NULL
565  * @param client identification of the client
566  */
567 static void
568 handle_client_disconnect (void *cls,
569                           struct GNUNET_SERVER_Client
570                           * client)
571 {
572   struct ServiceSession * elem;
573   struct ServiceSession * next;
574
575   // start from the tail, old stuff will be there...
576   for (elem = from_client_head; NULL != elem; elem = next)
577     {
578       next = elem->next;
579       if (elem->client != client)
580         continue;
581
582       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, _ ("Client (%p) disconnected from us.\n"), client);
583       GNUNET_CONTAINER_DLL_remove (from_client_head, from_client_tail, elem);
584
585       if (!(elem->role == BOB && elem->state == FINALIZED))
586         {
587           //we MUST terminate any client message underway
588           if (elem->service_transmit_handle && elem->tunnel)
589             GNUNET_MESH_notify_transmit_ready_cancel (elem->service_transmit_handle);
590           if (elem->tunnel && elem->state == WAITING_FOR_RESPONSE_FROM_SERVICE)
591             destroy_tunnel (elem, NULL);
592         }
593       free_session (elem);
594     }
595 }
596
597
598 /**
599  * Notify the client that the session has succeeded or failed completely.
600  * This message gets sent to 
601  * * alice's client if bob disconnected or to
602  * * bob's client if the operation completed or alice disconnected
603  * 
604  * @param client_session the associated client session
605  * @return GNUNET_NO, if we could not notify the client
606  *         GNUNET_YES if we notified it.
607  */
608 static void
609 prepare_client_end_notification (void * cls,
610                                  const struct GNUNET_SCHEDULER_TaskContext * tc)
611 {
612   struct ServiceSession * session = cls;
613   struct GNUNET_SCALARPRODUCT_client_response * msg;
614   struct MessageObject * msg_obj;
615
616   msg = GNUNET_new (struct GNUNET_SCALARPRODUCT_client_response);
617   msg->header.type = htons (GNUNET_MESSAGE_TYPE_SCALARPRODUCT_SERVICE_TO_CLIENT);
618   memcpy (&msg->key, &session->key, sizeof (struct GNUNET_HashCode));
619   memcpy (&msg->peer, &session->peer, sizeof ( struct GNUNET_PeerIdentity));
620   msg->header.size = htons (sizeof (struct GNUNET_SCALARPRODUCT_client_response));
621   // 0 size and the first char in the product is 0, which should never be zero if encoding is used.
622   msg->product_length = htonl (0);
623
624   msg_obj = GNUNET_new (struct MessageObject);
625   msg_obj->msg = &msg->header;
626   msg_obj->transmit_handle = NULL; // do not reset the transmit handle, please
627
628   //transmit this message to our client
629   session->client_transmit_handle =
630           GNUNET_SERVER_notify_transmit_ready (session->client,
631                                                sizeof (struct GNUNET_SCALARPRODUCT_client_response),
632                                                GNUNET_TIME_UNIT_FOREVER_REL,
633                                                &do_send_message,
634                                                msg_obj);
635
636
637   // if we could not even queue our request, something is wrong
638   if ( ! session->client_transmit_handle)
639     {
640
641       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);
642       // usually gets freed by do_send_message
643       GNUNET_free (msg_obj);
644       GNUNET_free (msg);
645     }
646   else
647     GNUNET_log (GNUNET_ERROR_TYPE_INFO, _ ("Sending session-end notification to client (%p) for session %s\n"), &session->client, GNUNET_h2s (&session->key));
648   
649   free_session(session);
650 }
651
652
653 /**
654  * Bob executes:
655  * generates the response message to be sent to alice after computing 
656  * the values (1), (2), S and S'
657  *  (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)})$
658  *  (2)[]: $E_A(a_{pi'(i)}) times E_A(- r_{pi'(i)}) &= E_A(a_{pi'(i)} - r_{pi'(i)})$
659  *      S: $S := E_A(sum (r_i + b_i)^2)$
660  *     S': $S' := E_A(sum r_i^2)$
661  * 
662  * @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)})$
663  * @param r_prime    (2)[]: $E_A(a_{pi'(i)}) times E_A(- r_{pi'(i)}) &= E_A(a_{pi'(i)} - r_{pi'(i)})$
664  * @param s         S: $S := E_A(sum (r_i + b_i)^2)$
665  * @param s_prime    S': $S' := E_A(sum r_i^2)$
666  * @param request  the associated requesting session with alice
667  * @param response the associated responder session with bob's client
668  * @return GNUNET_SYSERR if the function was called with NULL parameters or if there was an error
669  *         GNUNET_NO if we could not send our message
670  *         GNUNET_OK if the operation succeeded
671  */
672 static int
673 prepare_service_response (gcry_mpi_t * r,
674                           gcry_mpi_t * r_prime,
675                           gcry_mpi_t s,
676                           gcry_mpi_t s_prime,
677                           struct ServiceSession * request,
678                           struct ServiceSession * response)
679 {
680   struct GNUNET_SCALARPRODUCT_service_response * msg;
681   uint16_t msg_length = 0;
682   unsigned char * current = NULL;
683   unsigned char * element_exported = NULL;
684   size_t element_length = 0;
685   int i;
686
687   msg_length = sizeof (struct GNUNET_SCALARPRODUCT_service_response)
688           + 2 * request->used_element_count * PAILLIER_ELEMENT_LENGTH // kp, kq
689           + 2 * PAILLIER_ELEMENT_LENGTH; // s, stick
690
691   msg = GNUNET_malloc (msg_length);
692
693   msg->header.type = htons (GNUNET_MESSAGE_TYPE_SCALARPRODUCT_BOB_TO_ALICE);
694   msg->header.size = htons (msg_length);
695   msg->element_count = htons (request->element_count);
696   msg->used_element_count = htons (request->used_element_count);
697   memcpy (&msg->key, &request->key, sizeof (struct GNUNET_HashCode));
698   current = (unsigned char *) &msg[1];
699
700   // 4 times the same logics with slight variations.
701   // doesn't really justify having 2 functions for that
702   // so i put it into blocks to enhance readability 
703   // convert s
704   {
705     element_exported = GNUNET_malloc (PAILLIER_ELEMENT_LENGTH);
706     GNUNET_assert (0 == gcry_mpi_print (GCRYMPI_FMT_USG,
707                                         element_exported, PAILLIER_ELEMENT_LENGTH,
708                                         &element_length,
709                                         s));
710     adjust (element_exported, element_length, PAILLIER_ELEMENT_LENGTH);
711     memcpy (current, element_exported, PAILLIER_ELEMENT_LENGTH);
712     GNUNET_free (element_exported);
713     current += PAILLIER_ELEMENT_LENGTH;
714   }
715
716   // convert stick
717   {
718     element_exported = GNUNET_malloc (PAILLIER_ELEMENT_LENGTH);
719     GNUNET_assert (0 == gcry_mpi_print (GCRYMPI_FMT_USG,
720                                         element_exported, PAILLIER_ELEMENT_LENGTH,
721                                         &element_length,
722                                         s_prime));
723     adjust (element_exported, element_length, PAILLIER_ELEMENT_LENGTH);
724     memcpy (current, element_exported, PAILLIER_ELEMENT_LENGTH);
725     GNUNET_free (element_exported);
726     current += PAILLIER_ELEMENT_LENGTH;
727   }
728
729   // convert kp[]
730   for (i = 0; i < request->used_element_count; i++)
731     {
732       element_exported = GNUNET_malloc (PAILLIER_ELEMENT_LENGTH);
733       GNUNET_assert (0 == gcry_mpi_print (GCRYMPI_FMT_USG,
734                                           element_exported, PAILLIER_ELEMENT_LENGTH,
735                                           &element_length,
736                                           r[i]));
737       adjust (element_exported, element_length, PAILLIER_ELEMENT_LENGTH);
738       memcpy (current, element_exported, PAILLIER_ELEMENT_LENGTH);
739       GNUNET_free (element_exported);
740       current += PAILLIER_ELEMENT_LENGTH;
741     }
742
743
744   // convert kq[]
745   for (i = 0; i < request->used_element_count; i++)
746     {
747       element_exported = GNUNET_malloc (PAILLIER_ELEMENT_LENGTH);
748       GNUNET_assert (0 == gcry_mpi_print (GCRYMPI_FMT_USG,
749                                           element_exported, PAILLIER_ELEMENT_LENGTH,
750                                           &element_length,
751                                           r_prime[i]));
752       adjust (element_exported, element_length, PAILLIER_ELEMENT_LENGTH);
753       memcpy (current, element_exported, PAILLIER_ELEMENT_LENGTH);
754       GNUNET_free (element_exported);
755       current += PAILLIER_ELEMENT_LENGTH;
756     }
757
758   if (GNUNET_SERVER_MAX_MESSAGE_SIZE >= msg_length)
759     {
760       struct MessageObject * msg_obj;
761
762       msg_obj = GNUNET_new (struct MessageObject);
763       msg_obj->msg = (struct GNUNET_MessageHeader *) msg;
764       msg_obj->transmit_handle = (void *) &request->service_transmit_handle; //and reset the transmit handle
765       request->service_transmit_handle =
766               GNUNET_MESH_notify_transmit_ready (request->tunnel,
767                                                  GNUNET_YES,
768                                                  GNUNET_TIME_UNIT_FOREVER_REL,
769                                                  &request->peer, //must be specified, we are a slave/participant/non-owner
770                                                  msg_length,
771                                                  &do_send_message,
772                                                  msg_obj);
773       // we don't care if it could be send or not. either way, the session is over for us.
774       request->state = FINALIZED;
775       response->state = FINALIZED;
776     }
777   else
778     {
779       // TODO FEATURE: fallback to fragmentation, in case the message is too long
780       GNUNET_log (GNUNET_ERROR_TYPE_WARNING, _ ("Message too large, fragmentation is currently not supported!)\n"));
781     }
782
783   //disconnect our client
784   if ( ! request->service_transmit_handle)
785     {
786       GNUNET_log (GNUNET_ERROR_TYPE_ERROR, _ ("Could not send service-response message via mesh!)\n"));
787       GNUNET_CONTAINER_DLL_remove (from_client_head, from_client_tail, response);
788       GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_SECONDS,
789                                     &prepare_client_end_notification,
790                                     response);
791       return GNUNET_NO;
792     }
793   return GNUNET_OK;
794 }
795
796
797 /**
798  * executed by bob: 
799  * compute the values 
800  *  (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)})$
801  *  (2)[]: $E_A(a_{\pi'(i)}) \otimes E_A(- r_{\pi'(i)}) &= E_A(a_{\pi'(i)} - r_{\pi'(i)})$
802  *      S: $S := E_A(\sum (r_i + b_i)^2)$
803  *     S': $S' := E_A(\sum r_i^2)$
804  * 
805  * @param request the requesting session + bob's requesting peer
806  * @param response the responding session + bob's client handle
807  * @return GNUNET_SYSERR if the computation failed
808  *         GNUNET_OK if everything went well.
809  */
810 static int
811 compute_service_response (struct ServiceSession * request,
812                           struct ServiceSession * response)
813 {
814   int i;
815   int j;
816   int ret = GNUNET_SYSERR;
817   unsigned int * p;
818   unsigned int * q;
819   uint16_t count;
820   gcry_mpi_t * rand = NULL;
821   gcry_mpi_t * r = NULL;
822   gcry_mpi_t * r_prime = NULL;
823   gcry_mpi_t * b;
824   gcry_mpi_t * a_pi;
825   gcry_mpi_t * a_pi_prime;
826   gcry_mpi_t * b_pi;
827   gcry_mpi_t * rand_pi;
828   gcry_mpi_t * rand_pi_prime;
829   gcry_mpi_t s = NULL;
830   gcry_mpi_t s_prime = NULL;
831   gcry_mpi_t remote_n = NULL;
832   gcry_mpi_t remote_nsquare;
833   gcry_mpi_t remote_g = NULL;
834   gcry_sexp_t tmp_exp;
835   uint32_t value;
836
837   count = request->used_element_count;
838
839   b = GNUNET_malloc (sizeof (gcry_mpi_t) * count);
840   a_pi = GNUNET_malloc (sizeof (gcry_mpi_t) * count);
841   b_pi = GNUNET_malloc (sizeof (gcry_mpi_t) * count);
842   a_pi_prime = GNUNET_malloc (sizeof (gcry_mpi_t) * count);
843   rand_pi = GNUNET_malloc (sizeof (gcry_mpi_t) * count);
844   rand_pi_prime = GNUNET_malloc (sizeof (gcry_mpi_t) * count);
845
846   // convert responder session to from long to mpi
847   for (i = 0, j = 0; i < response->element_count && j < count; i++)
848     {
849       if (request->mask[i / 8] & (1 << (i % 8)))
850         {
851           value = response->vector[i] >= 0 ? response->vector[i] : -response->vector[i];
852           // long to gcry_mpi_t
853           if (0 > response->vector[i])
854             {
855               b[j] = gcry_mpi_new (0);
856               gcry_mpi_sub_ui (b[j], b[j], value);
857             }
858           else
859             {
860               b[j] = gcry_mpi_set_ui (NULL, value);
861             }
862           j++;
863         }
864     }
865   GNUNET_free (response->vector);
866   response->vector = NULL;
867
868   tmp_exp = gcry_sexp_find_token (request->remote_pubkey, "n", 0);
869   if ( ! tmp_exp)
870     {
871       GNUNET_break_op (0);
872       gcry_sexp_release (request->remote_pubkey);
873       request->remote_pubkey = NULL;
874       goto except;
875     }
876   remote_n = gcry_sexp_nth_mpi (tmp_exp, 1, GCRYMPI_FMT_USG);
877   if ( ! remote_n)
878     {
879       GNUNET_break (0);
880       gcry_sexp_release (tmp_exp);
881       goto except;
882     }
883   remote_nsquare = gcry_mpi_new (KEYBITS + 1);
884   gcry_mpi_mul (remote_nsquare, remote_n, remote_n);
885   gcry_sexp_release (tmp_exp);
886   tmp_exp = gcry_sexp_find_token (request->remote_pubkey, "g", 0);
887   gcry_sexp_release (request->remote_pubkey);
888   request->remote_pubkey = NULL;
889   if ( ! tmp_exp)
890     {
891       GNUNET_break_op (0);
892       gcry_mpi_release (remote_n);
893       goto except;
894     }
895   remote_g = gcry_sexp_nth_mpi (tmp_exp, 1, GCRYMPI_FMT_USG);
896   if ( ! remote_g)
897     {
898       GNUNET_break (0);
899       gcry_mpi_release (remote_n);
900       gcry_sexp_release (tmp_exp);
901       goto except;
902     }
903   gcry_sexp_release (tmp_exp);
904
905   // generate r, p and q
906   rand = generate_random_vector (count);
907   p = GNUNET_CRYPTO_random_permute (GNUNET_CRYPTO_QUALITY_WEAK, count);
908   q = GNUNET_CRYPTO_random_permute (GNUNET_CRYPTO_QUALITY_WEAK, count);
909   //initialize the result vectors
910   r = initialize_mpi_vector (count);
911   r_prime = initialize_mpi_vector (count);
912
913   // copy the REFERNCES of a, b and r into aq and bq. we will not change 
914   // those values, thus we can work with the references
915   memcpy (a_pi, request->a, sizeof (gcry_mpi_t) * count);
916   memcpy (a_pi_prime, request->a, sizeof (gcry_mpi_t) * count);
917   memcpy (b_pi, b, sizeof (gcry_mpi_t) * count);
918   memcpy (rand_pi, rand, sizeof (gcry_mpi_t) * count);
919   memcpy (rand_pi_prime, rand, sizeof (gcry_mpi_t) * count);
920
921   // generate p and q permutations for a, b and r
922   GNUNET_assert (permute_vector (a_pi, p, count));
923   GNUNET_assert (permute_vector (b_pi, p, count));
924   GNUNET_assert (permute_vector (rand_pi, p, count));
925   GNUNET_assert (permute_vector (a_pi_prime, q, count));
926   GNUNET_assert (permute_vector (rand_pi_prime, q, count));
927
928   // encrypt the element
929   // for the sake of readability I decided to have dedicated permutation
930   // vectors, which get rid of all the lookups in p/q. 
931   // however, ap/aq are not absolutely necessary but are just abstraction
932   // Calculate Kp = E(S + a_pi) (+) E(S - r_pi - b_pi)
933   for (i = 0; i < count; i++)
934     {
935       // E(S - r_pi - b_pi)
936       gcry_mpi_sub (r[i], my_offset, rand_pi[i]);
937       gcry_mpi_sub (r[i], r[i], b_pi[i]);
938       encrypt_element (r[i], r[i], remote_g, remote_n, remote_nsquare);
939
940       // E(S - r_pi - b_pi) * E(S + a_pi) ==  E(2*S + a - r - b)
941       gcry_mpi_mulm (r[i], r[i], a_pi[i], remote_nsquare);
942     }
943   GNUNET_free (a_pi);
944   GNUNET_free (b_pi);
945   GNUNET_free (rand_pi);
946
947   // Calculate Kq = E(S + a_qi) (+) E(S - r_qi)
948   for (i = 0; i < count; i++)
949     {
950       // E(S - r_qi)
951       gcry_mpi_sub (r_prime[i], my_offset, rand_pi_prime[i]);
952       encrypt_element (r_prime[i], r_prime[i], remote_g, remote_n, remote_nsquare);
953
954       // E(S - r_qi) * E(S + a_qi) == E(2*S + a_qi - r_qi)
955       gcry_mpi_mulm (r_prime[i], r_prime[i], a_pi_prime[i], remote_nsquare);
956     }
957   GNUNET_free (a_pi_prime);
958   GNUNET_free (rand_pi_prime);
959
960   // Calculate S' =  E(SUM( r_i^2 ))
961   s_prime = compute_square_sum (rand, count);
962   encrypt_element (s_prime, s_prime, remote_g, remote_n, remote_nsquare);
963
964   // Calculate S = E(SUM( (r_i + b_i)^2 ))
965   for (i = 0; i < count; i++)
966     {
967       gcry_mpi_add (rand[i], rand[i], b[i]);
968     }
969   s = compute_square_sum (rand, count);
970   encrypt_element (s, s, remote_g, remote_n, remote_nsquare);
971   gcry_mpi_release (remote_n);
972   gcry_mpi_release (remote_g);
973   gcry_mpi_release (remote_nsquare);
974
975   // release r and tmp
976   for (i = 0; i < count; i++)
977     // rp, rq, aq, ap, bp, bq are released along with a, r, b respectively, (a and b are handled at except:)
978     gcry_mpi_release (rand[i]);
979
980   // copy the Kp[], Kq[], S and Stick into a new message
981   if (GNUNET_YES != prepare_service_response (r, r_prime, s, s_prime, request, response))
982     GNUNET_log (GNUNET_ERROR_TYPE_INFO, _("Failed to communicate with `%s', scalar product calculation aborted.\n"),
983                 GNUNET_i2s (&request->peer));
984   else
985     ret = GNUNET_OK;
986
987   for (i = 0; i < count; i++)
988     {
989       gcry_mpi_release (r_prime[i]);
990       gcry_mpi_release (r[i]);
991     }
992
993   gcry_mpi_release (s);
994   gcry_mpi_release (s_prime);
995
996 except:
997   for (i = 0; i < count; i++)
998     {
999       gcry_mpi_release (b[i]);
1000       gcry_mpi_release (request->a[i]);
1001     }
1002
1003   GNUNET_free (b);
1004   GNUNET_free (request->a);
1005   request->a = NULL;
1006
1007   return ret;
1008 }
1009
1010
1011 /**
1012  * Executed by Alice, fills in a service-request message and sends it to the given peer
1013  * 
1014  * @param session the session associated with this request, then also holds the CORE-handle
1015  * @return #GNUNET_SYSERR if we could not send the message
1016  *         #GNUNET_NO if the message was too large
1017  *         #GNUNET_OK if we sent it
1018  */
1019 static void
1020 prepare_service_request (void *cls,
1021                          const struct GNUNET_PeerIdentity * peer,
1022                          const struct GNUNET_ATS_Information * atsi)
1023 {
1024   struct ServiceSession * session = cls;
1025   unsigned char * current;
1026   struct GNUNET_SCALARPRODUCT_service_request * msg;
1027   struct MessageObject * msg_obj;
1028   unsigned int i;
1029   unsigned int j;
1030   uint16_t msg_length;
1031   size_t element_length = 0; //gets initialized by gcry_mpi_print, but the compiler doesn't know that
1032   gcry_mpi_t a;
1033   uint32_t value;
1034
1035   GNUNET_assert (NULL != cls);
1036   GNUNET_assert (NULL != peer);
1037   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, _ ("Successfully created new tunnel to peer (%s)!\n"), GNUNET_i2s (peer));
1038
1039   msg_length = sizeof (struct GNUNET_SCALARPRODUCT_service_request)
1040           + session->used_element_count * PAILLIER_ELEMENT_LENGTH
1041           + session->mask_length
1042           + my_pubkey_external_length;
1043
1044   if (GNUNET_SERVER_MAX_MESSAGE_SIZE < sizeof (struct GNUNET_SCALARPRODUCT_service_request)
1045       + session->used_element_count * PAILLIER_ELEMENT_LENGTH
1046       + session->mask_length
1047       + my_pubkey_external_length)
1048     {
1049       // TODO FEATURE: fallback to fragmentation, in case the message is too long
1050       GNUNET_log (GNUNET_ERROR_TYPE_WARNING, _ ("Message too large, fragmentation is currently not supported!\n"));
1051       GNUNET_CONTAINER_DLL_remove (from_client_head, from_client_tail, session);
1052       GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_SECONDS,
1053                                     &prepare_client_end_notification,
1054                                     session);
1055       return;
1056     }
1057   msg = GNUNET_malloc (msg_length);
1058
1059   msg->header.type = htons (GNUNET_MESSAGE_TYPE_SCALARPRODUCT_ALICE_TO_BOB);
1060   memcpy (&msg->key, &session->key, sizeof (struct GNUNET_HashCode));
1061   msg->mask_length = htons (session->mask_length);
1062   msg->pk_length = htons (my_pubkey_external_length);
1063   msg->used_element_count = htons (session->used_element_count);
1064   msg->element_count = htons (session->element_count);
1065   msg->header.size = htons (msg_length);
1066
1067   // fill in the payload
1068   current = (unsigned char *) &msg[1];
1069   // copy over the mask
1070   memcpy (current, session->mask, session->mask_length);
1071   // copy over our public key
1072   current += session->mask_length;
1073   memcpy (current, my_pubkey_external, my_pubkey_external_length);
1074   current += my_pubkey_external_length;
1075   
1076   // now copy over the element vector
1077   session->a = GNUNET_malloc (sizeof (gcry_mpi_t) * session->used_element_count);
1078   a = gcry_mpi_new (KEYBITS * 2);
1079   // encrypt our vector and generate string representations
1080   for (i = 0, j = 0; i < session->element_count; i++)
1081     {
1082       // if this is a used element...
1083       if (session->mask[i / 8] & 1 << (i % 8))
1084         {
1085           unsigned char * element_exported = GNUNET_malloc (PAILLIER_ELEMENT_LENGTH);
1086           value = session->vector[i] >= 0 ? session->vector[i] : -session->vector[i];
1087
1088           a = gcry_mpi_set_ui (a, 0);
1089           // long to gcry_mpi_t
1090           if (session->vector[i] < 0)
1091             gcry_mpi_sub_ui (a, a, value);
1092           else
1093             gcry_mpi_add_ui (a, a, value);
1094
1095           session->a[j++] = gcry_mpi_set (NULL, a);
1096           gcry_mpi_add (a, a, my_offset);
1097           encrypt_element (a, a, my_g, my_n, my_nsquare);
1098
1099           // get representation as string
1100           // we always supply some value, so gcry_mpi_print fails only if it can't reserve memory
1101           GNUNET_assert ( ! gcry_mpi_print (GCRYMPI_FMT_USG,
1102                                               element_exported, PAILLIER_ELEMENT_LENGTH,
1103                                               &element_length,
1104                                               a));
1105
1106           // move buffer content to the end of the buffer so it can easily be read by libgcrypt. also this now has fixed size
1107           adjust (element_exported, element_length, PAILLIER_ELEMENT_LENGTH);
1108
1109           // copy over to the message
1110           memcpy (current, element_exported, PAILLIER_ELEMENT_LENGTH);
1111           current += PAILLIER_ELEMENT_LENGTH;
1112         }
1113     }
1114   gcry_mpi_release (a);
1115
1116   msg_obj = GNUNET_new (struct MessageObject);
1117   msg_obj->msg = (struct GNUNET_MessageHeader *) msg;
1118   msg_obj->transmit_handle = (void *) &session->service_transmit_handle; //and reset the transmit handle
1119   GNUNET_log (GNUNET_ERROR_TYPE_INFO, _("Transmitting service request.\n"));
1120
1121   //transmit via mesh messaging
1122   session->state = WAITING_FOR_RESPONSE_FROM_SERVICE;
1123   session->service_transmit_handle = GNUNET_MESH_notify_transmit_ready (session->tunnel, GNUNET_YES,
1124                                                                         GNUNET_TIME_UNIT_FOREVER_REL,
1125                                                                         peer, //multicast to all targets, maybe useful in the future
1126                                                                         msg_length,
1127                                                                         &do_send_message,
1128                                                                         msg_obj);
1129   if ( ! session->service_transmit_handle)
1130     {
1131       GNUNET_log (GNUNET_ERROR_TYPE_ERROR, _("Could not send mutlicast message to tunnel!\n"));
1132       GNUNET_free (msg_obj);
1133       GNUNET_free (msg);
1134       GNUNET_CONTAINER_DLL_remove (from_client_head, from_client_tail, session);
1135       GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_SECONDS,
1136                                     &prepare_client_end_notification,
1137                                     session);
1138     }
1139 }
1140
1141
1142 /**
1143  * Method called whenever a peer has disconnected from the tunnel.
1144  * Implementations of this callback must NOT call
1145  * #GNUNET_MESH_tunnel_destroy immediately, but instead schedule those
1146  * to run in some other task later.  However, calling 
1147  * #GNUNET_MESH_notify_transmit_ready_cancel is allowed.
1148  *
1149  * @param cls closure
1150  * @param peer peer identity the tunnel stopped working with
1151  */
1152 static void
1153 tunnel_peer_disconnect_handler (void *cls, const struct GNUNET_PeerIdentity * peer)
1154 {
1155   // as we have only one peer connected in each session, just remove the session and say good bye
1156   struct ServiceSession * session = cls;
1157   struct ServiceSession * curr;
1158
1159   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, 
1160               "Peer (%s) disconnected from our tunnel!\n",
1161               GNUNET_i2s (peer));
1162
1163   if ((session->role == ALICE) && (FINALIZED != session->state) && ( ! do_shutdown))
1164     {
1165       for (curr = from_client_head; NULL != curr; curr = curr->next)
1166         if (curr == session)
1167           {
1168             GNUNET_CONTAINER_DLL_remove (from_client_head, from_client_tail, session);
1169             break;
1170           }
1171       // FIXME: dangling tasks, code duplication, use-after-free, fun...
1172       GNUNET_SCHEDULER_add_now (&destroy_tunnel,
1173                                 session);
1174       // if this happened before we received the answer, we must terminate the session
1175       GNUNET_SCHEDULER_add_now (&prepare_client_end_notification,
1176                                 session);
1177     }
1178 }
1179
1180
1181 /**
1182  * Handler for a client request message. 
1183  * Can either be type A or B
1184  *   A: request-initiation to compute a scalar product with a peer
1185  *   B: response role, keep the values + session and wait for a matching session or process a waiting request   
1186  *
1187  * @param cls closure
1188  * @param client identification of the client
1189  * @param message the actual message
1190  */
1191 static void
1192 handle_client_request (void *cls,
1193                        struct GNUNET_SERVER_Client *client,
1194                        const struct GNUNET_MessageHeader *message)
1195 {
1196   const struct GNUNET_SCALARPRODUCT_client_request * msg = (const struct GNUNET_SCALARPRODUCT_client_request *) message;
1197   struct ServiceSession * session;
1198   uint16_t element_count;
1199   uint16_t mask_length;
1200   uint16_t msg_type;
1201   int32_t * vector;
1202   uint32_t i;
1203
1204   GNUNET_assert (message);
1205
1206   //we need at least a peer and one message id to compare
1207   if (sizeof (struct GNUNET_SCALARPRODUCT_client_request) > ntohs (msg->header.size))
1208     {
1209       GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
1210                   _ ("Too short message received from client!\n"));
1211       GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
1212       return;
1213     }
1214
1215   msg_type = ntohs (msg->header.type);
1216   element_count = ntohs (msg->element_count);
1217   mask_length = ntohs (msg->mask_length);
1218
1219   //sanity check: is the message as long as the message_count fields suggests?
1220   if (( ntohs (msg->header.size) != (sizeof (struct GNUNET_SCALARPRODUCT_client_request) + element_count * sizeof (int32_t) + mask_length))
1221       || (0 == element_count))
1222     {
1223       GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
1224                   _ ("Invalid message received from client, session information incorrect!\n"));
1225       GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
1226       return;
1227     }
1228
1229   // do we have a duplicate session here already?
1230   if (NULL != find_matching_session (from_client_tail,
1231                                      &msg->key,
1232                                      element_count,
1233                                      NULL, NULL))
1234     {
1235       GNUNET_log (GNUNET_ERROR_TYPE_WARNING, _ ("Duplicate session information received, cannot create new session with key `%s'\n"), GNUNET_h2s (&msg->key));
1236       GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
1237       return;
1238     }
1239
1240   session = GNUNET_new (struct ServiceSession);
1241   session->client = client;
1242   session->element_count = element_count;
1243   session->mask_length = mask_length;
1244   // get our transaction key
1245   memcpy (&session->key, &msg->key, sizeof (struct GNUNET_HashCode));
1246   //allocate memory for vector and encrypted vector
1247   session->vector = GNUNET_malloc (sizeof (int32_t) * element_count);
1248   vector = (int32_t *) & msg[1];
1249
1250   if (GNUNET_MESSAGE_TYPE_SCALARPRODUCT_CLIENT_TO_ALICE == msg_type)
1251     {
1252       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, _ ("Got client-request-session with key %s, preparing tunnel to remote service.\n"), GNUNET_h2s (&session->key));
1253
1254       session->role = ALICE;
1255       // fill in the mask
1256       session->mask = GNUNET_malloc (mask_length);
1257       memcpy (session->mask, &vector[element_count], mask_length);
1258
1259       // copy over the elements
1260       session->used_element_count = 0;
1261       for (i = 0; i < element_count; i++)
1262         {
1263           session->vector[i] = ntohl (vector[i]);
1264           if (session->vector[i] == 0)
1265             session->mask[i / 8] &= ~(1 << (i % 8));
1266           if (session->mask[i / 8] & (1 << (i % 8)))
1267             session->used_element_count++;
1268         }
1269
1270       if ( ! session->used_element_count)
1271         {
1272           GNUNET_break_op (0);
1273           GNUNET_free (session->vector);
1274           GNUNET_free (session->a);
1275           GNUNET_free (session);
1276           GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
1277           return;
1278         }
1279       //session with ourself makes no sense!
1280       if ( ! memcmp (&msg->peer, &me, sizeof (struct GNUNET_PeerIdentity)))
1281         {
1282           GNUNET_break (0);
1283           GNUNET_free (session->vector);
1284           GNUNET_free (session->a);
1285           GNUNET_free (session);
1286           GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
1287           return;
1288         }
1289       // get our peer ID
1290       memcpy (&session->peer, &msg->peer, sizeof (struct GNUNET_PeerIdentity));
1291       GNUNET_log (GNUNET_ERROR_TYPE_INFO, _ ("Creating new tunnel to for session with key %s.\n"), GNUNET_h2s (&session->key));
1292       GNUNET_CONTAINER_DLL_insert (from_client_head, from_client_tail, session);
1293       session->tunnel = GNUNET_MESH_tunnel_create (my_mesh, session,
1294                                                    prepare_service_request,
1295                                                    tunnel_peer_disconnect_handler,
1296                                                    session);
1297       if ( ! session->tunnel)
1298         {
1299           GNUNET_break (0);
1300           GNUNET_free (session->vector);
1301           GNUNET_free (session->a);
1302           GNUNET_free (session);
1303           GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
1304           return;
1305         }
1306       GNUNET_MESH_peer_request_connect_add (session->tunnel, &session->peer);
1307       GNUNET_SERVER_receive_done (client, GNUNET_YES);
1308       session->state = WAITING_FOR_BOBS_CONNECT;
1309     }
1310   else
1311     {
1312       struct ServiceSession * requesting_session;
1313       enum SessionState needed_state = REQUEST_FROM_SERVICE_RECEIVED;
1314
1315       session->role = BOB;
1316       session->mask = NULL;
1317       // copy over the elements
1318       session->used_element_count = element_count;
1319       for (i = 0; i < element_count; i++)
1320         session->vector[i] = ntohl (vector[i]);
1321       session->state = MESSAGE_FROM_RESPONDING_CLIENT_RECEIVED;
1322       
1323       GNUNET_CONTAINER_DLL_insert (from_client_head, from_client_tail, session);
1324       GNUNET_SERVER_receive_done (client, GNUNET_YES);
1325       //check if service queue contains a matching request 
1326       requesting_session = find_matching_session (from_service_tail,
1327                                                   &session->key,
1328                                                   session->element_count,
1329                                                   &needed_state, NULL);
1330       if (NULL != requesting_session)
1331         {
1332           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));
1333           if (GNUNET_OK != compute_service_response (requesting_session, session))
1334             {
1335               GNUNET_CONTAINER_DLL_remove (from_client_head, from_client_tail, session);
1336               GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_SECONDS,
1337                                             &prepare_client_end_notification,
1338                                             session);
1339             }
1340         }
1341       else
1342         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));
1343         // no matching session exists yet, store the response
1344         // for later processing by handle_service_request()
1345     }
1346 }
1347
1348
1349 /**
1350  * Function called for inbound tunnels. 
1351  *
1352  * @param cls closure
1353  * @param tunnel new handle to the tunnel
1354  * @param initiator peer that started the tunnel
1355  * @param atsi performance information for the tunnel
1356  * @return initial tunnel context for the tunnel
1357  *         (can be NULL -- that's not an error)
1358  */
1359 static void *
1360 tunnel_incoming_handler (void *cls, struct GNUNET_MESH_Tunnel *tunnel,
1361                          const struct GNUNET_PeerIdentity *initiator,
1362                          const struct GNUNET_ATS_Information *atsi)
1363 {
1364
1365   struct ServiceSession * c = GNUNET_new (struct ServiceSession);
1366
1367   memcpy (&c->peer, initiator, sizeof (struct GNUNET_PeerIdentity));
1368   c->tunnel = tunnel;
1369   c->role = BOB;
1370   return c;
1371 }
1372
1373
1374 /**
1375  * Function called whenever an inbound tunnel is destroyed.  Should clean up
1376  * any associated state.
1377  *
1378  * @param cls closure (set from #GNUNET_MESH_connect)
1379  * @param tunnel connection to the other end (henceforth invalid)
1380  * @param tunnel_ctx place where local state associated
1381  *                   with the tunnel is stored (our 'struct TunnelState')
1382  */
1383 static void
1384 tunnel_destruction_handler (void *cls,
1385                             const struct GNUNET_MESH_Tunnel *tunnel,
1386                             void *tunnel_ctx)
1387 {
1388   struct ServiceSession * service_session = tunnel_ctx;
1389   struct ServiceSession * client_session;
1390   struct ServiceSession * curr;
1391
1392   GNUNET_assert (service_session);
1393   if (!memcmp (&service_session->peer, &me, sizeof (struct GNUNET_PeerIdentity)))
1394     return;
1395   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, _ ("Tunnel destroyed, terminating session with peer (%s)\n"), GNUNET_i2s (&service_session->peer));
1396   // remove the session, unless it has already been dequeued, but somehow still active
1397   // this could bug without the IF in case the queue is empty and the service session was the only one know to the service
1398   for (curr = from_service_head; NULL != curr; curr = curr->next)
1399         if (curr == service_session)
1400           {
1401             GNUNET_CONTAINER_DLL_remove (from_service_head, from_service_tail, curr);
1402             break;
1403           }
1404   // there is a client waiting for this service session, terminate it, too!
1405   // i assume the tupel of key and element count is unique. if it was not the rest of the code would not work either.
1406   client_session = find_matching_session (from_client_tail,
1407                                           &service_session->key,
1408                                           service_session->element_count,
1409                                           NULL, NULL);
1410   free_session (service_session);
1411
1412   // the client has to check if it was waiting for a result 
1413   // or if it was a responder, no point in adding more statefulness
1414   if (client_session && ( ! do_shutdown))
1415     {
1416       // remove the session, we just found it in the queue, so it must be there
1417       GNUNET_CONTAINER_DLL_remove (from_client_head, from_client_tail, client_session);
1418       GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_SECONDS,
1419                                     &prepare_client_end_notification,
1420                                     client_session);
1421     }
1422 }
1423
1424
1425 /**
1426  * Compute our scalar product, done by Alice
1427  * 
1428  * @param session - the session associated with this computation
1429  * @param kp - (1) from the protocol definition: 
1430  *             $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)})$
1431  * @param kq - (2) from the protocol definition: 
1432  *             $E_A(a_{\pi'(i)}) \otimes E_A(- r_{\pi'(i)}) &= E_A(a_{\pi'(i)} - r_{\pi'(i)})$
1433  * @param s - S from the protocol definition: 
1434  *            $S := E_A(\sum (r_i + b_i)^2)$
1435  * @param stick - S' from the protocol definition: 
1436  *                $S' := E_A(\sum r_i^2)$
1437  * @return product as MPI, never NULL
1438  */
1439 static gcry_mpi_t
1440 compute_scalar_product (struct ServiceSession * session,
1441                         gcry_mpi_t * r, gcry_mpi_t * r_prime, gcry_mpi_t s, gcry_mpi_t s_prime)
1442 {
1443   uint16_t count;
1444   gcry_mpi_t t;
1445   gcry_mpi_t u;
1446   gcry_mpi_t utick;
1447   gcry_mpi_t p;
1448   gcry_mpi_t ptick;
1449   gcry_mpi_t tmp;
1450   unsigned int i;
1451
1452   count = session->used_element_count;
1453   tmp = gcry_mpi_new (KEYBITS);
1454   // due to the introduced static offset S, we now also have to remove this
1455   // from the E(a_pi)(+)E(-b_pi-r_pi) and E(a_qi)(+)E(-r_qi) twice each,
1456   // the result is E((S + a_pi) + (S -b_pi-r_pi)) and E(S + a_qi + S - r_qi)
1457   for (i = 0; i < count; i++)
1458     {
1459       decrypt_element (r[i], r[i], my_mu, my_lambda, my_n, my_nsquare);
1460       gcry_mpi_sub(r[i],r[i],my_offset);
1461       gcry_mpi_sub(r[i],r[i],my_offset);
1462       decrypt_element (r_prime[i], r_prime[i], my_mu, my_lambda, my_n, my_nsquare);
1463       gcry_mpi_sub(r_prime[i],r_prime[i],my_offset);
1464       gcry_mpi_sub(r_prime[i],r_prime[i],my_offset);
1465     }
1466
1467   // calculate t = sum(ai)
1468   t = compute_square_sum (session->a, count);
1469
1470   // calculate U
1471   u = gcry_mpi_new (0);
1472   tmp = compute_square_sum (r, count);
1473   gcry_mpi_sub (u, u, tmp);
1474   gcry_mpi_release (tmp);
1475
1476   //calculate U'
1477   utick = gcry_mpi_new (0);
1478   tmp = compute_square_sum (r_prime, count);
1479   gcry_mpi_sub (utick, utick, tmp);
1480
1481   GNUNET_assert (p = gcry_mpi_new (0));
1482   GNUNET_assert (ptick = gcry_mpi_new (0));
1483
1484   // compute P
1485   decrypt_element (s, s, my_mu, my_lambda, my_n, my_nsquare);
1486   decrypt_element (s_prime, s_prime, my_mu, my_lambda, my_n, my_nsquare);
1487   
1488   // compute P
1489   gcry_mpi_add (p, s, t);
1490   gcry_mpi_add (p, p, u);
1491
1492   // compute P'
1493   gcry_mpi_add (ptick, s_prime, t);
1494   gcry_mpi_add (ptick, ptick, utick);
1495
1496   gcry_mpi_release (t);
1497   gcry_mpi_release (u);
1498   gcry_mpi_release (utick);
1499
1500   // compute product
1501   gcry_mpi_sub (p, p, ptick);
1502   gcry_mpi_release (ptick);
1503   tmp = gcry_mpi_set_ui (tmp, 2);
1504   gcry_mpi_div (p, NULL, p, tmp, 0);
1505
1506   gcry_mpi_release (tmp);
1507   for (i = 0; i < count; i++)
1508     gcry_mpi_release (session->a[i]);
1509   GNUNET_free (session->a);
1510   session->a = NULL;
1511   
1512   return p;
1513 }
1514
1515
1516 /**
1517  * prepare the response we will send to alice or bobs' clients.
1518  * in Bobs case the product will be NULL. 
1519  * 
1520  * @param session  the session associated with our client.
1521  */
1522 static void
1523 prepare_client_response (void *cls,
1524                          const struct GNUNET_SCHEDULER_TaskContext *tc)
1525 {
1526   struct ServiceSession * session = cls;
1527   struct GNUNET_SCALARPRODUCT_client_response * msg;
1528   unsigned char * product_exported = NULL;
1529   size_t product_length = 0;
1530   uint16_t msg_length = 0;
1531   struct MessageObject * msg_obj;
1532   int8_t range = 0;
1533   int sign;
1534
1535   if (session->product)
1536     {
1537       gcry_mpi_t value = gcry_mpi_new(0);
1538       
1539       sign = gcry_mpi_cmp_ui(session->product, 0);
1540       // libgcrypt can not handle a print of a negative number
1541       if (0 > sign){
1542           range = -1;
1543           gcry_mpi_sub(value, value, session->product);
1544       }
1545       else if(0 < sign){
1546           range = 1;
1547           gcry_mpi_add(value, value, session->product);
1548       }
1549       
1550       // get representation as string
1551       // unfortunately libgcrypt is too stupid to implement print-support in
1552       // signed GCRYMPI_FMT_STD format, and simply asserts in that case.
1553       // here is the associated sourcecode:
1554       // if (a->sign) return gcry_error (GPG_ERR_INTERNAL); /* Can't handle it yet. */
1555       if (range)
1556           GNUNET_assert ( ! gcry_mpi_aprint (GCRYMPI_FMT_USG, // FIXME: just log (& survive!)
1557                                              &product_exported,
1558                                              &product_length,
1559                                              session->product));
1560       
1561       gcry_mpi_release (session->product);
1562       session->product = NULL;
1563     }
1564
1565   msg_length = sizeof (struct GNUNET_SCALARPRODUCT_client_response) + product_length;
1566   msg = GNUNET_malloc (msg_length);
1567   memcpy (&msg[1], product_exported, product_length);
1568   GNUNET_free_non_null (product_exported);
1569   msg->header.type = htons (GNUNET_MESSAGE_TYPE_SCALARPRODUCT_SERVICE_TO_CLIENT);
1570   msg->header.size = htons (msg_length);
1571   msg->range = range;
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 =  // FIXME: use after free possibility during shutdown
1582           GNUNET_SERVER_notify_transmit_ready (session->client,
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)
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 s_prime = NULL;
1821   size_t read;
1822   size_t i;
1823   uint16_t used_element_count;
1824   size_t msg_size;
1825   gcry_mpi_t * r = NULL;
1826   gcry_mpi_t * r_prime = 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 (&s_prime, 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   r = 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 (&r[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   r_prime = 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 (&r_prime[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, r, r_prime, s, s_prime);
1909   
1910 invalid_msg:
1911   if (s)
1912     gcry_mpi_release (s);
1913   if (s_prime)
1914     gcry_mpi_release (s_prime);
1915   for (i = 0; r && i < count; i++)
1916     if (r[i]) gcry_mpi_release (r[i]);
1917   for (i = 0; r_prime && i < count; i++)
1918     if (r_prime[i]) gcry_mpi_release (r_prime[i]);
1919   GNUNET_free_non_null (r);
1920   GNUNET_free_non_null (r_prime);
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 Paillier-Keyset.\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 */