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