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