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