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