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