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