- fix coverity
[oweals/gnunet.git] / src / scalarproduct / gnunet-service-scalarproduct_alice.c
1 /*
2      This file is part of GNUnet.
3      Copyright (C) 2013, 2014 GNUnet e.V.
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., 51 Franklin Street, Fifth Floor,
18      Boston, MA 02110-1301, USA.
19  */
20 /**
21  * @file scalarproduct/gnunet-service-scalarproduct_alice.c
22  * @brief scalarproduct service implementation
23  * @author Christian M. Fuchs
24  * @author Christian Grothoff
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 #include "gnunet-service-scalarproduct.h"
38
39 #define LOG(kind,...) GNUNET_log_from (kind, "scalarproduct-alice", __VA_ARGS__)
40
41 /**
42  * An encrypted element key-value pair.
43  */
44 struct MpiElement
45 {
46   /**
47    * Key used to identify matching pairs of values to multiply.
48    * Points into an existing data structure, to avoid copying
49    * and doubling memory use.
50    */
51   const struct GNUNET_HashCode *key;
52
53   /**
54    * Value represented (a).
55    */
56   gcry_mpi_t value;
57 };
58
59
60 /**
61  * A scalarproduct session which tracks
62  * a request form the client to our final response.
63  */
64 struct AliceServiceSession
65 {
66
67   /**
68    * (hopefully) unique transaction ID
69    */
70   struct GNUNET_HashCode session_id;
71
72   /**
73    * Alice or Bob's peerID
74    */
75   struct GNUNET_PeerIdentity peer;
76
77   /**
78    * The client this request is related to.
79    */
80   struct GNUNET_SERVER_Client *client;
81
82   /**
83    * The message queue for the client.
84    */
85   struct GNUNET_MQ_Handle *client_mq;
86
87   /**
88    * The message queue for CADET.
89    */
90   struct GNUNET_MQ_Handle *cadet_mq;
91
92   /**
93    * all non-0-value'd elements transmitted to us.
94    * Values are of type `struct GNUNET_SCALARPRODUCT_Element *`
95    */
96   struct GNUNET_CONTAINER_MultiHashMap *intersected_elements;
97
98   /**
99    * Set of elements for which will conduction an intersection.
100    * the resulting elements are then used for computing the scalar product.
101    */
102   struct GNUNET_SET_Handle *intersection_set;
103
104   /**
105    * Set of elements for which will conduction an intersection.
106    * the resulting elements are then used for computing the scalar product.
107    */
108   struct GNUNET_SET_OperationHandle *intersection_op;
109
110   /**
111    * Handle to Alice's Intersection operation listening for Bob
112    */
113   struct GNUNET_SET_ListenHandle *intersection_listen;
114
115   /**
116    * channel-handle associated with our cadet handle
117    */
118   struct GNUNET_CADET_Channel *channel;
119
120   /**
121    * a(Alice), sorted array by key of length @e used_element_count.
122    */
123   struct MpiElement *sorted_elements;
124
125   /**
126    * Bob's permutation p of R
127    */
128   struct GNUNET_CRYPTO_PaillierCiphertext *r;
129
130   /**
131    * Bob's permutation q of R
132    */
133   struct GNUNET_CRYPTO_PaillierCiphertext *r_prime;
134
135   /**
136    * Bob's "s"
137    */
138   struct GNUNET_CRYPTO_PaillierCiphertext s;
139
140   /**
141    * Bob's "s'"
142    */
143   struct GNUNET_CRYPTO_PaillierCiphertext s_prime;
144
145   /**
146    * The computed scalar
147    */
148   gcry_mpi_t product;
149
150   /**
151    * How many elements we were supplied with from the client (total
152    * count before intersection).
153    */
154   uint32_t total;
155
156   /**
157    * How many elements actually are used for the scalar product.
158    * Size of the arrays in @e r and @e r_prime.  Sometimes also
159    * reset to 0 and used as a counter!
160    */
161   uint32_t used_element_count;
162
163   /**
164    * Already transferred elements from client to us.
165    * Less or equal than @e total.
166    */
167   uint32_t client_received_element_count;
168
169   /**
170    * Already transferred elements from Bob to us.
171    * Less or equal than @e total.
172    */
173   uint32_t cadet_received_element_count;
174
175   /**
176    * State of this session.   In
177    * #GNUNET_SCALARPRODUCT_STATUS_ACTIVE while operation is
178    * ongoing, afterwards in #GNUNET_SCALARPRODUCT_STATUS_SUCCESS or
179    * #GNUNET_SCALARPRODUCT_STATUS_FAILURE.
180    */
181   enum GNUNET_SCALARPRODUCT_ResponseStatus status;
182
183   /**
184    * Flag to prevent recursive calls to #destroy_service_session() from
185    * doing harm.
186    */
187   int in_destroy;
188
189 };
190
191
192 /**
193  * GNUnet configuration handle
194  */
195 static const struct GNUNET_CONFIGURATION_Handle *cfg;
196
197 /**
198  * Service's own public key
199  */
200 static struct GNUNET_CRYPTO_PaillierPublicKey my_pubkey;
201
202 /**
203  * Service's own private key
204  */
205 static struct GNUNET_CRYPTO_PaillierPrivateKey my_privkey;
206
207 /**
208  * Service's offset for values that could possibly be negative but are plaintext for encryption.
209  */
210 static gcry_mpi_t my_offset;
211
212 /**
213  * Handle to the CADET service.
214  */
215 static struct GNUNET_CADET_Handle *my_cadet;
216
217
218 /**
219  * Iterator called to free elements.
220  *
221  * @param cls the `struct AliceServiceSession *` (unused)
222  * @param key the key (unused)
223  * @param value value to free
224  * @return #GNUNET_OK (continue to iterate)
225  */
226 static int
227 free_element_cb (void *cls,
228                  const struct GNUNET_HashCode *key,
229                  void *value)
230 {
231   struct GNUNET_SCALARPRODUCT_Element *e = value;
232
233   GNUNET_free (e);
234   return GNUNET_OK;
235 }
236
237
238 /**
239  * Destroy session state, we are done with it.
240  *
241  * @param s the session to free elements from
242  */
243 static void
244 destroy_service_session (struct AliceServiceSession *s)
245 {
246   unsigned int i;
247
248   if (GNUNET_YES == s->in_destroy)
249     return;
250   s->in_destroy = GNUNET_YES;
251   if (NULL != s->client_mq)
252   {
253     GNUNET_MQ_destroy (s->client_mq);
254     s->client_mq = NULL;
255   }
256   if (NULL != s->cadet_mq)
257   {
258     GNUNET_MQ_destroy (s->cadet_mq);
259     s->cadet_mq = NULL;
260   }
261   if (NULL != s->client)
262   {
263     GNUNET_SERVER_client_set_user_context (s->client,
264                                            NULL);
265     GNUNET_SERVER_client_disconnect (s->client);
266     s->client = NULL;
267   }
268   if (NULL != s->channel)
269   {
270     GNUNET_CADET_channel_destroy (s->channel);
271     s->channel = NULL;
272   }
273   if (NULL != s->intersected_elements)
274   {
275     GNUNET_CONTAINER_multihashmap_iterate (s->intersected_elements,
276                                            &free_element_cb,
277                                            s);
278     GNUNET_CONTAINER_multihashmap_destroy (s->intersected_elements);
279     s->intersected_elements = NULL;
280   }
281   if (NULL != s->intersection_listen)
282   {
283     GNUNET_SET_listen_cancel (s->intersection_listen);
284     s->intersection_listen = NULL;
285   }
286   if (NULL != s->intersection_op)
287   {
288     GNUNET_SET_operation_cancel (s->intersection_op);
289     s->intersection_op = NULL;
290   }
291   if (NULL != s->intersection_set)
292   {
293     GNUNET_SET_destroy (s->intersection_set);
294     s->intersection_set = NULL;
295   }
296   if (NULL != s->sorted_elements)
297   {
298     for (i=0;i<s->used_element_count;i++)
299       gcry_mpi_release (s->sorted_elements[i].value);
300     GNUNET_free (s->sorted_elements);
301     s->sorted_elements = NULL;
302   }
303   if (NULL != s->r)
304   {
305     GNUNET_free (s->r);
306     s->r = NULL;
307   }
308   if (NULL != s->r_prime)
309   {
310     GNUNET_free (s->r_prime);
311     s->r_prime = NULL;
312   }
313   if (NULL != s->product)
314   {
315     gcry_mpi_release (s->product);
316     s->product = NULL;
317   }
318   GNUNET_free (s);
319 }
320
321
322 /**
323  * Notify the client that the session has failed.  A message gets sent
324  * to Alice's client if we encountered any error.
325  *
326  * @param session the associated client session to fail or succeed
327  */
328 static void
329 prepare_client_end_notification (struct AliceServiceSession *session)
330 {
331   struct ClientResponseMessage *msg;
332   struct GNUNET_MQ_Envelope *e;
333
334   if (NULL == session->client_mq)
335     return; /* no client left to be notified */
336   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
337               "Sending session-end notification with status %d to client for session %s\n",
338               session->status,
339               GNUNET_h2s (&session->session_id));
340   e = GNUNET_MQ_msg (msg,
341                      GNUNET_MESSAGE_TYPE_SCALARPRODUCT_RESULT);
342   msg->product_length = htonl (0);
343   msg->status = htonl (session->status);
344   GNUNET_MQ_send (session->client_mq,
345                   e);
346 }
347
348
349 /**
350  * Prepare the final (positive) response we will send to Alice's
351  * client.
352  *
353  * @param s the session associated with our client.
354  */
355 static void
356 transmit_client_response (struct AliceServiceSession *s)
357 {
358   struct ClientResponseMessage *msg;
359   struct GNUNET_MQ_Envelope *e;
360   unsigned char *product_exported = NULL;
361   size_t product_length = 0;
362   int32_t range;
363   gcry_error_t rc;
364   int sign;
365   gcry_mpi_t value;
366
367   if (NULL == s->product)
368   {
369     GNUNET_break (0);
370     prepare_client_end_notification (s);
371     return;
372   }
373   value = gcry_mpi_new (0);
374   sign = gcry_mpi_cmp_ui (s->product, 0);
375   if (0 > sign)
376   {
377     range = -1;
378     gcry_mpi_sub (value,
379                   value,
380                   s->product);
381   }
382   else if (0 < sign)
383   {
384     range = 1;
385     gcry_mpi_add (value, value, s->product);
386   }
387   else
388   {
389     /* result is exactly zero */
390     range = 0;
391   }
392   gcry_mpi_release (s->product);
393   s->product = NULL;
394
395   if ( (0 != range) &&
396        (0 != (rc = gcry_mpi_aprint (GCRYMPI_FMT_STD,
397                                     &product_exported,
398                                     &product_length,
399                                     value))))
400   {
401     LOG_GCRY (GNUNET_ERROR_TYPE_ERROR,
402               "gcry_mpi_scan",
403               rc);
404     prepare_client_end_notification (s);
405     return;
406   }
407   gcry_mpi_release (value);
408   e = GNUNET_MQ_msg_extra (msg,
409                            product_length,
410                            GNUNET_MESSAGE_TYPE_SCALARPRODUCT_RESULT);
411   msg->status = htonl (GNUNET_SCALARPRODUCT_STATUS_SUCCESS);
412   msg->range = htonl (range);
413   msg->product_length = htonl (product_length);
414   if (NULL != product_exported)
415   {
416     memcpy (&msg[1],
417             product_exported,
418             product_length);
419     GNUNET_free (product_exported);
420   }
421   GNUNET_MQ_send (s->client_mq,
422                   e);
423   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
424               "Sent result to client, session %s has ended!\n",
425               GNUNET_h2s (&s->session_id));
426 }
427
428
429
430 /**
431  * Function called whenever a channel is destroyed.  Should clean up
432  * any associated state.
433  *
434  * It must NOT call #GNUNET_CADET_channel_destroy() on the channel.
435  *
436  * @param cls closure (set from #GNUNET_CADET_connect())
437  * @param channel connection to the other end (henceforth invalid)
438  * @param channel_ctx place where local state associated
439  *                   with the channel is stored
440  */
441 static void
442 cb_channel_destruction (void *cls,
443                         const struct GNUNET_CADET_Channel *channel,
444                         void *channel_ctx)
445 {
446   struct AliceServiceSession *s = channel_ctx;
447
448   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
449               "Peer disconnected, terminating session %s with peer %s\n",
450               GNUNET_h2s (&s->session_id),
451               GNUNET_i2s (&s->peer));
452   if (GNUNET_SCALARPRODUCT_STATUS_ACTIVE == s->status)
453   {
454     /* We didn't get an answer yet, fail with error */
455     s->status = GNUNET_SCALARPRODUCT_STATUS_FAILURE;
456     prepare_client_end_notification (s);
457   }
458   if (NULL != s->cadet_mq)
459   {
460     GNUNET_MQ_destroy (s->cadet_mq);
461     s->cadet_mq = NULL;
462   }
463   s->channel = NULL;
464 }
465
466
467 /**
468  * Computes the square sum over a vector of a given length.
469  *
470  * @param vector the vector to compute over
471  * @param length the length of the vector
472  * @return an MPI value containing the calculated sum, never NULL
473  */
474 static gcry_mpi_t
475 compute_square_sum_mpi_elements (const struct MpiElement *vector,
476                                  uint32_t length)
477 {
478   gcry_mpi_t elem;
479   gcry_mpi_t sum;
480   uint32_t i;
481
482   GNUNET_assert (NULL != (sum = gcry_mpi_new (0)));
483   GNUNET_assert (NULL != (elem = gcry_mpi_new (0)));
484   for (i = 0; i < length; i++)
485   {
486     gcry_mpi_mul (elem, vector[i].value, vector[i].value);
487     gcry_mpi_add (sum, sum, elem);
488   }
489   gcry_mpi_release (elem);
490   return sum;
491 }
492
493
494 /**
495  * Computes the square sum over a vector of a given length.
496  *
497  * @param vector the vector to compute over
498  * @param length the length of the vector
499  * @return an MPI value containing the calculated sum, never NULL
500  */
501 static gcry_mpi_t
502 compute_square_sum (const gcry_mpi_t *vector,
503                     uint32_t length)
504 {
505   gcry_mpi_t elem;
506   gcry_mpi_t sum;
507   uint32_t i;
508
509   GNUNET_assert (NULL != (sum = gcry_mpi_new (0)));
510   GNUNET_assert (NULL != (elem = gcry_mpi_new (0)));
511   for (i = 0; i < length; i++)
512   {
513     gcry_mpi_mul (elem, vector[i], vector[i]);
514     gcry_mpi_add (sum, sum, elem);
515   }
516   gcry_mpi_release (elem);
517   return sum;
518 }
519
520
521 /**
522  * Compute our scalar product, done by Alice
523  *
524  * @param session the session associated with this computation
525  * @return product as MPI, never NULL
526  */
527 static gcry_mpi_t
528 compute_scalar_product (struct AliceServiceSession *session)
529 {
530   uint32_t count;
531   gcry_mpi_t t;
532   gcry_mpi_t u;
533   gcry_mpi_t u_prime;
534   gcry_mpi_t p;
535   gcry_mpi_t p_prime;
536   gcry_mpi_t tmp;
537   gcry_mpi_t r[session->used_element_count];
538   gcry_mpi_t r_prime[session->used_element_count];
539   gcry_mpi_t s;
540   gcry_mpi_t s_prime;
541   unsigned int i;
542
543   count = session->used_element_count;
544   // due to the introduced static offset S, we now also have to remove this
545   // from the E(a_pi)(+)E(-b_pi-r_pi) and E(a_qi)(+)E(-r_qi) twice each,
546   // the result is E((S + a_pi) + (S -b_pi-r_pi)) and E(S + a_qi + S - r_qi)
547   for (i = 0; i < count; i++)
548   {
549     r[i] = gcry_mpi_new (0);
550     GNUNET_CRYPTO_paillier_decrypt (&my_privkey,
551                                     &my_pubkey,
552                                     &session->r[i],
553                                     r[i]);
554     gcry_mpi_sub (r[i],
555                   r[i],
556                   my_offset);
557     gcry_mpi_sub (r[i],
558                   r[i],
559                   my_offset);
560     r_prime[i] = gcry_mpi_new (0);
561     GNUNET_CRYPTO_paillier_decrypt (&my_privkey,
562                                     &my_pubkey,
563                                     &session->r_prime[i],
564                                     r_prime[i]);
565     gcry_mpi_sub (r_prime[i],
566                   r_prime[i],
567                   my_offset);
568     gcry_mpi_sub (r_prime[i],
569                   r_prime[i],
570                   my_offset);
571   }
572
573   // calculate t = sum(ai)
574   t = compute_square_sum_mpi_elements (session->sorted_elements,
575                                        count);
576   // calculate U
577   u = gcry_mpi_new (0);
578   tmp = compute_square_sum (r, count);
579   gcry_mpi_sub (u, u, tmp);
580   gcry_mpi_release (tmp);
581
582   //calculate U'
583   u_prime = gcry_mpi_new (0);
584   tmp = compute_square_sum (r_prime, count);
585   gcry_mpi_sub (u_prime, u_prime, tmp);
586
587   GNUNET_assert (p = gcry_mpi_new (0));
588   GNUNET_assert (p_prime = gcry_mpi_new (0));
589   GNUNET_assert (s = gcry_mpi_new (0));
590   GNUNET_assert (s_prime = gcry_mpi_new (0));
591
592   // compute P
593   GNUNET_CRYPTO_paillier_decrypt (&my_privkey,
594                                   &my_pubkey,
595                                   &session->s,
596                                   s);
597   GNUNET_CRYPTO_paillier_decrypt (&my_privkey,
598                                   &my_pubkey,
599                                   &session->s_prime,
600                                   s_prime);
601
602   // compute P
603   gcry_mpi_add (p, s, t);
604   gcry_mpi_add (p, p, u);
605
606   // compute P'
607   gcry_mpi_add (p_prime, s_prime, t);
608   gcry_mpi_add (p_prime, p_prime, u_prime);
609
610   gcry_mpi_release (t);
611   gcry_mpi_release (u);
612   gcry_mpi_release (u_prime);
613   gcry_mpi_release (s);
614   gcry_mpi_release (s_prime);
615
616   // compute product
617   gcry_mpi_sub (p, p, p_prime);
618   gcry_mpi_release (p_prime);
619   tmp = gcry_mpi_set_ui (tmp, 2);
620   gcry_mpi_div (p, NULL, p, tmp, 0);
621
622   gcry_mpi_release (tmp);
623   for (i = 0; i < count; i++)
624   {
625     gcry_mpi_release (session->sorted_elements[i].value);
626     gcry_mpi_release (r[i]);
627     gcry_mpi_release (r_prime[i]);
628   }
629   GNUNET_free (session->sorted_elements);
630   session->sorted_elements = NULL;
631   GNUNET_free (session->r);
632   session->r = NULL;
633   GNUNET_free (session->r_prime);
634   session->r_prime = NULL;
635
636   return p;
637 }
638
639
640 /**
641  * Handle a multipart chunk of a response we got from another service
642  * we wanted to calculate a scalarproduct with.
643  *
644  * @param cls closure (set from #GNUNET_CADET_connect)
645  * @param channel connection to the other end
646  * @param channel_ctx place to store local state associated with the @a channel
647  * @param message the actual message
648  * @return #GNUNET_OK to keep the connection open,
649  *         #GNUNET_SYSERR to close it (signal serious error)
650  */
651 static int
652 handle_bobs_cryptodata_multipart (void *cls,
653                                   struct GNUNET_CADET_Channel *channel,
654                                   void **channel_ctx,
655                                   const struct GNUNET_MessageHeader *message)
656 {
657   struct AliceServiceSession *s = *channel_ctx;
658   const struct BobCryptodataMultipartMessage *msg;
659   const struct GNUNET_CRYPTO_PaillierCiphertext *payload;
660   size_t i;
661   uint32_t contained;
662   size_t msg_size;
663   size_t required_size;
664
665   if (NULL == s)
666   {
667     GNUNET_break_op (0);
668     return GNUNET_SYSERR;
669   }
670   msg_size = ntohs (message->size);
671   if (sizeof (struct BobCryptodataMultipartMessage) > msg_size)
672   {
673     GNUNET_break_op (0);
674     return GNUNET_SYSERR;
675   }
676   msg = (const struct BobCryptodataMultipartMessage *) message;
677   contained = ntohl (msg->contained_element_count);
678   required_size = sizeof (struct BobCryptodataMultipartMessage)
679     + 2 * contained * sizeof (struct GNUNET_CRYPTO_PaillierCiphertext);
680   if ( (required_size != msg_size) ||
681        (s->cadet_received_element_count + contained > s->used_element_count) )
682   {
683     GNUNET_break (0);
684     return GNUNET_SYSERR;
685   }
686
687   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
688               "Received %u additional crypto values from Bob\n",
689               (unsigned int) contained);
690
691   payload = (const struct GNUNET_CRYPTO_PaillierCiphertext *) &msg[1];
692   /* Convert each k[][perm] to its MPI_value */
693   for (i = 0; i < contained; i++)
694   {
695     memcpy (&s->r[s->cadet_received_element_count + i],
696             &payload[2 * i],
697             sizeof (struct GNUNET_CRYPTO_PaillierCiphertext));
698     memcpy (&s->r_prime[s->cadet_received_element_count + i],
699             &payload[2 * i],
700             sizeof (struct GNUNET_CRYPTO_PaillierCiphertext));
701   }
702   s->cadet_received_element_count += contained;
703   GNUNET_CADET_receive_done (s->channel);
704   if (s->cadet_received_element_count != s->used_element_count)
705     return GNUNET_OK;
706
707   s->product = compute_scalar_product (s);
708   transmit_client_response (s);
709   return GNUNET_OK;
710 }
711
712
713 /**
714  * Handle a response we got from another service we wanted to
715  * calculate a scalarproduct with.
716  *
717  * @param cls closure (set from #GNUNET_CADET_connect)
718  * @param channel connection to the other end
719  * @param channel_ctx place to store local state associated with the channel
720  * @param message the actual message
721  * @return #GNUNET_OK to keep the connection open,
722  *         #GNUNET_SYSERR to close it (we are done)
723  */
724 static int
725 handle_bobs_cryptodata_message (void *cls,
726                                 struct GNUNET_CADET_Channel *channel,
727                                 void **channel_ctx,
728                                 const struct GNUNET_MessageHeader *message)
729 {
730   struct AliceServiceSession *s = *channel_ctx;
731   const struct BobCryptodataMessage *msg;
732   const struct GNUNET_CRYPTO_PaillierCiphertext *payload;
733   uint32_t i;
734   uint32_t contained;
735   uint16_t msg_size;
736   size_t required_size;
737
738   if (NULL == s)
739   {
740     GNUNET_break_op (0);
741     return GNUNET_SYSERR;
742   }
743   msg_size = ntohs (message->size);
744   if (sizeof (struct BobCryptodataMessage) > msg_size)
745   {
746     GNUNET_break_op (0);
747     return GNUNET_SYSERR;
748   }
749   msg = (const struct BobCryptodataMessage *) message;
750   contained = ntohl (msg->contained_element_count);
751   required_size = sizeof (struct BobCryptodataMessage)
752     + 2 * contained * sizeof (struct GNUNET_CRYPTO_PaillierCiphertext)
753     + 2 * sizeof (struct GNUNET_CRYPTO_PaillierCiphertext);
754   if ( (msg_size != required_size) ||
755        (contained > UINT16_MAX) ||
756        (s->used_element_count < contained) )
757   {
758     GNUNET_break_op (0);
759     return GNUNET_SYSERR;
760   }
761   if (NULL == s->sorted_elements)
762   {
763     /* we're not ready yet, how can Bob be? */
764     GNUNET_break_op (0);
765     return GNUNET_SYSERR;
766   }
767   if (s->total != s->client_received_element_count)
768   {
769     /* we're not ready yet, how can Bob be? */
770     GNUNET_break_op (0);
771     return GNUNET_SYSERR;
772   }
773   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
774               "Received %u crypto values from Bob\n",
775               (unsigned int) contained);
776
777   payload = (const struct GNUNET_CRYPTO_PaillierCiphertext *) &msg[1];
778   memcpy (&s->s,
779           &payload[0],
780           sizeof (struct GNUNET_CRYPTO_PaillierCiphertext));
781   memcpy (&s->s_prime,
782           &payload[1],
783           sizeof (struct GNUNET_CRYPTO_PaillierCiphertext));
784   payload = &payload[2];
785
786   s->r = GNUNET_malloc (sizeof (struct GNUNET_CRYPTO_PaillierCiphertext) * s->used_element_count);
787   s->r_prime = GNUNET_malloc (sizeof (struct GNUNET_CRYPTO_PaillierCiphertext) * s->used_element_count);
788   for (i = 0; i < contained; i++)
789   {
790     memcpy (&s->r[i],
791             &payload[2 * i],
792             sizeof (struct GNUNET_CRYPTO_PaillierCiphertext));
793     memcpy (&s->r_prime[i],
794             &payload[2 * i + 1],
795             sizeof (struct GNUNET_CRYPTO_PaillierCiphertext));
796   }
797   s->cadet_received_element_count = contained;
798   GNUNET_CADET_receive_done (s->channel);
799
800   if (s->cadet_received_element_count != s->used_element_count)
801   {
802     /* More to come */
803     return GNUNET_OK;
804   }
805
806   s->product = compute_scalar_product (s);
807   transmit_client_response (s);
808   return GNUNET_OK;
809 }
810
811
812 /**
813  * Iterator to copy over messages from the hash map
814  * into an array for sorting.
815  *
816  * @param cls the `struct AliceServiceSession *`
817  * @param key the key (unused)
818  * @param value the `struct GNUNET_SCALARPRODUCT_Element *`
819  */
820 static int
821 copy_element_cb (void *cls,
822                  const struct GNUNET_HashCode *key,
823                  void *value)
824 {
825   struct AliceServiceSession *s = cls;
826   struct GNUNET_SCALARPRODUCT_Element *e = value;
827   gcry_mpi_t mval;
828   int64_t val;
829
830   mval = gcry_mpi_new (0);
831   val = (int64_t) GNUNET_ntohll (e->value);
832   if (0 > val)
833     gcry_mpi_sub_ui (mval, mval, -val);
834   else
835     gcry_mpi_add_ui (mval, mval, val);
836   s->sorted_elements [s->used_element_count].value = mval;
837   s->sorted_elements [s->used_element_count].key = &e->key;
838   s->used_element_count++;
839   return GNUNET_OK;
840 }
841
842
843 /**
844  * Compare two `struct MpiValue`s by key for sorting.
845  *
846  * @param a pointer to first `struct MpiValue *`
847  * @param b pointer to first `struct MpiValue *`
848  * @return -1 for a < b, 0 for a=b, 1 for a > b.
849  */
850 static int
851 element_cmp (const void *a,
852              const void *b)
853 {
854   const struct MpiElement *ma = a;
855   const struct MpiElement *mb = b;
856
857   return GNUNET_CRYPTO_hash_cmp (ma->key,
858                                  mb->key);
859 }
860
861
862 /**
863  * Maximum number of elements we can put into a single cryptodata
864  * message
865  */
866 #define ELEMENT_CAPACITY ((GNUNET_CONSTANTS_MAX_CADET_MESSAGE_SIZE - 1 - sizeof (struct AliceCryptodataMessage)) / sizeof (struct GNUNET_CRYPTO_PaillierCiphertext))
867
868
869 /**
870  * Send the cryptographic data from Alice to Bob.
871  * Does nothing if we already transferred all elements.
872  *
873  * @param s the associated service session
874  */
875 static void
876 send_alices_cryptodata_message (struct AliceServiceSession *s)
877 {
878   struct AliceCryptodataMessage *msg;
879   struct GNUNET_MQ_Envelope *e;
880   struct GNUNET_CRYPTO_PaillierCiphertext *payload;
881   unsigned int i;
882   uint32_t todo_count;
883   gcry_mpi_t a;
884   uint32_t off;
885
886   s->sorted_elements
887     = GNUNET_malloc (GNUNET_CONTAINER_multihashmap_size (s->intersected_elements) *
888                      sizeof (struct MpiElement));
889   s->used_element_count = 0;
890   GNUNET_CONTAINER_multihashmap_iterate (s->intersected_elements,
891                                          &copy_element_cb,
892                                          s);
893   LOG (GNUNET_ERROR_TYPE_DEBUG,
894        "Finished intersection, %d items remain\n",
895        s->used_element_count);
896   qsort (s->sorted_elements,
897          s->used_element_count,
898          sizeof (struct MpiElement),
899          &element_cmp);
900   off = 0;
901   while (off < s->used_element_count)
902   {
903     todo_count = s->used_element_count - off;
904     if (todo_count > ELEMENT_CAPACITY)
905       todo_count = ELEMENT_CAPACITY;
906     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
907                 "Sending %u/%u crypto values to Bob\n",
908                 (unsigned int) todo_count,
909                 (unsigned int) s->used_element_count);
910
911     e = GNUNET_MQ_msg_extra (msg,
912                              todo_count * sizeof (struct GNUNET_CRYPTO_PaillierCiphertext),
913                              GNUNET_MESSAGE_TYPE_SCALARPRODUCT_ALICE_CRYPTODATA);
914     msg->contained_element_count = htonl (todo_count);
915     payload = (struct GNUNET_CRYPTO_PaillierCiphertext *) &msg[1];
916     a = gcry_mpi_new (0);
917     for (i = off; i < off + todo_count; i++)
918     {
919       gcry_mpi_add (a,
920                     s->sorted_elements[i].value,
921                     my_offset);
922       GNUNET_assert (3 ==
923                      GNUNET_CRYPTO_paillier_encrypt (&my_pubkey,
924                                                      a,
925                                                      3,
926                                                      &payload[i - off]));
927     }
928     gcry_mpi_release (a);
929     off += todo_count;
930     GNUNET_MQ_send (s->cadet_mq,
931                     e);
932   }
933 }
934
935
936 /**
937  * Callback for set operation results. Called for each element
938  * that should be removed from the result set, and then once
939  * to indicate that the set intersection operation is done.
940  *
941  * @param cls closure with the `struct AliceServiceSession`
942  * @param element a result element, only valid if status is #GNUNET_SET_STATUS_OK
943  * @param status what has happened with the set intersection?
944  */
945 static void
946 cb_intersection_element_removed (void *cls,
947                                  const struct GNUNET_SET_Element *element,
948                                  enum GNUNET_SET_Status status)
949 {
950   struct AliceServiceSession *s = cls;
951   struct GNUNET_SCALARPRODUCT_Element *se;
952
953   switch (status)
954   {
955   case GNUNET_SET_STATUS_OK:
956     /* this element has been removed from the set */
957     se = GNUNET_CONTAINER_multihashmap_get (s->intersected_elements,
958                                             element->data);
959     GNUNET_assert (NULL != se);
960     LOG (GNUNET_ERROR_TYPE_DEBUG,
961          "Intersection removed element with key %s and value %lld\n",
962          GNUNET_h2s (&se->key),
963          (long long) GNUNET_ntohll (se->value));
964     GNUNET_assert (GNUNET_YES ==
965                    GNUNET_CONTAINER_multihashmap_remove (s->intersected_elements,
966                                                          element->data,
967                                                          se));
968     GNUNET_free (se);
969     return;
970   case GNUNET_SET_STATUS_DONE:
971     s->intersection_op = NULL;
972     if (NULL != s->intersection_set)
973     {
974       GNUNET_SET_destroy (s->intersection_set);
975       s->intersection_set = NULL;
976     }
977     send_alices_cryptodata_message (s);
978     return;
979   case GNUNET_SET_STATUS_HALF_DONE:
980     /* unexpected for intersection */
981     GNUNET_break (0);
982     return;
983   case GNUNET_SET_STATUS_FAILURE:
984     /* unhandled status code */
985     LOG (GNUNET_ERROR_TYPE_DEBUG,
986          "Set intersection failed!\n");
987     if (NULL != s->intersection_listen)
988     {
989       GNUNET_SET_listen_cancel (s->intersection_listen);
990       s->intersection_listen = NULL;
991     }
992     s->intersection_op = NULL;
993     if (NULL != s->intersection_set)
994     {
995       GNUNET_SET_destroy (s->intersection_set);
996       s->intersection_set = NULL;
997     }
998     s->status = GNUNET_SCALARPRODUCT_STATUS_FAILURE;
999     prepare_client_end_notification (s);
1000     return;
1001   default:
1002     GNUNET_break (0);
1003     return;
1004   }
1005 }
1006
1007
1008 /**
1009  * Called when another peer wants to do a set operation with the
1010  * local peer. If a listen error occurs, the @a request is NULL.
1011  *
1012  * @param cls closure with the `struct AliceServiceSession *`
1013  * @param other_peer the other peer
1014  * @param context_msg message with application specific information from
1015  *        the other peer
1016  * @param request request from the other peer (never NULL), use GNUNET_SET_accept()
1017  *        to accept it, otherwise the request will be refused
1018  *        Note that we can't just return value from the listen callback,
1019  *        as it is also necessary to specify the set we want to do the
1020  *        operation with, whith sometimes can be derived from the context
1021  *        message. It's necessary to specify the timeout.
1022  */
1023 static void
1024 cb_intersection_request_alice (void *cls,
1025                                const struct GNUNET_PeerIdentity *other_peer,
1026                                const struct GNUNET_MessageHeader *context_msg,
1027                                struct GNUNET_SET_Request *request)
1028 {
1029   struct AliceServiceSession *s = cls;
1030
1031   if (0 != memcmp (other_peer,
1032                    &s->peer,
1033                    sizeof (struct GNUNET_PeerIdentity)))
1034   {
1035     GNUNET_break_op (0);
1036     return;
1037   }
1038   s->intersection_op
1039     = GNUNET_SET_accept (request,
1040                          GNUNET_SET_RESULT_REMOVED,
1041                          &cb_intersection_element_removed,
1042                          s);
1043   if (NULL == s->intersection_op)
1044   {
1045     GNUNET_break (0);
1046     s->status = GNUNET_SCALARPRODUCT_STATUS_FAILURE;
1047     prepare_client_end_notification (s);
1048     return;
1049   }
1050   if (GNUNET_OK !=
1051       GNUNET_SET_commit (s->intersection_op,
1052                          s->intersection_set))
1053   {
1054     GNUNET_break (0);
1055     s->status = GNUNET_SCALARPRODUCT_STATUS_FAILURE;
1056     prepare_client_end_notification (s);
1057     return;
1058   }
1059   GNUNET_SET_destroy (s->intersection_set);
1060   s->intersection_set = NULL;
1061   GNUNET_SET_listen_cancel (s->intersection_listen);
1062   s->intersection_listen = NULL;
1063 }
1064
1065
1066 /**
1067  * Our client has finished sending us its multipart message.
1068  *
1069  * @param session the service session context
1070  */
1071 static void
1072 client_request_complete_alice (struct AliceServiceSession *s)
1073 {
1074   struct ServiceRequestMessage *msg;
1075   struct GNUNET_MQ_Envelope *e;
1076
1077   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1078               "Creating new channel for session with key %s.\n",
1079               GNUNET_h2s (&s->session_id));
1080   s->channel
1081     = GNUNET_CADET_channel_create (my_cadet,
1082                                    s,
1083                                    &s->peer,
1084                                    GNUNET_APPLICATION_TYPE_SCALARPRODUCT,
1085                                    GNUNET_CADET_OPTION_RELIABLE);
1086   if (NULL == s->channel)
1087   {
1088     s->status = GNUNET_SCALARPRODUCT_STATUS_FAILURE;
1089     prepare_client_end_notification (s);
1090     return;
1091   }
1092   s->cadet_mq = GNUNET_CADET_mq_create (s->channel);
1093   s->intersection_listen
1094     = GNUNET_SET_listen (cfg,
1095                          GNUNET_SET_OPERATION_INTERSECTION,
1096                          &s->session_id,
1097                          &cb_intersection_request_alice,
1098                          s);
1099   if (NULL == s->intersection_listen)
1100   {
1101     s->status = GNUNET_SCALARPRODUCT_STATUS_FAILURE;
1102     GNUNET_CADET_channel_destroy (s->channel);
1103     s->channel = NULL;
1104     prepare_client_end_notification (s);
1105     return;
1106   }
1107
1108   e = GNUNET_MQ_msg (msg,
1109                      GNUNET_MESSAGE_TYPE_SCALARPRODUCT_SESSION_INITIALIZATION);
1110   msg->session_id = s->session_id;
1111   msg->public_key = my_pubkey;
1112   GNUNET_MQ_send (s->cadet_mq,
1113                   e);
1114 }
1115
1116
1117 /**
1118  * We're receiving additional set data. Add it to our
1119  * set and if we are done, initiate the transaction.
1120  *
1121  * @param cls closure
1122  * @param client identification of the client
1123  * @param message the actual message
1124  */
1125 static void
1126 GSS_handle_alice_client_message_multipart (void *cls,
1127                                            struct GNUNET_SERVER_Client *client,
1128                                            const struct GNUNET_MessageHeader *message)
1129 {
1130   const struct ComputationBobCryptodataMultipartMessage * msg;
1131   struct AliceServiceSession *s;
1132   uint32_t contained_count;
1133   const struct GNUNET_SCALARPRODUCT_Element *elements;
1134   uint32_t i;
1135   uint16_t msize;
1136   struct GNUNET_SET_Element set_elem;
1137   struct GNUNET_SCALARPRODUCT_Element *elem;
1138
1139   s = GNUNET_SERVER_client_get_user_context (client,
1140                                              struct AliceServiceSession);
1141   if (NULL == s)
1142   {
1143     /* session needs to already exist */
1144     GNUNET_break (0);
1145     GNUNET_SERVER_receive_done (client,
1146                                 GNUNET_SYSERR);
1147     return;
1148   }
1149   msize = ntohs (message->size);
1150   if (msize < sizeof (struct ComputationBobCryptodataMultipartMessage))
1151   {
1152     GNUNET_break (0);
1153     GNUNET_SERVER_receive_done (client,
1154                                 GNUNET_SYSERR);
1155     return;
1156   }
1157   msg = (const struct ComputationBobCryptodataMultipartMessage *) message;
1158   contained_count = ntohl (msg->element_count_contained);
1159
1160   if ( (msize != (sizeof (struct ComputationBobCryptodataMultipartMessage) +
1161                   contained_count * sizeof (struct GNUNET_SCALARPRODUCT_Element))) ||
1162        (0 == contained_count) ||
1163        (s->total == s->client_received_element_count) ||
1164        (s->total < s->client_received_element_count + contained_count) )
1165   {
1166     GNUNET_break_op (0);
1167     GNUNET_SERVER_receive_done (client,
1168                                 GNUNET_SYSERR);
1169     return;
1170   }
1171   s->client_received_element_count += contained_count;
1172   elements = (const struct GNUNET_SCALARPRODUCT_Element *) &msg[1];
1173   for (i = 0; i < contained_count; i++)
1174   {
1175     elem = GNUNET_new (struct GNUNET_SCALARPRODUCT_Element);
1176     memcpy (elem,
1177             &elements[i],
1178             sizeof (struct GNUNET_SCALARPRODUCT_Element));
1179     if (GNUNET_SYSERR ==
1180         GNUNET_CONTAINER_multihashmap_put (s->intersected_elements,
1181                                            &elem->key,
1182                                            elem,
1183                                            GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY))
1184     {
1185       GNUNET_break (0);
1186       GNUNET_free (elem);
1187       continue;
1188     }
1189     set_elem.data = &elem->key;
1190     set_elem.size = sizeof (elem->key);
1191     set_elem.element_type = 0;
1192     GNUNET_SET_add_element (s->intersection_set,
1193                             &set_elem,
1194                             NULL, NULL);
1195     s->used_element_count++;
1196   }
1197   GNUNET_SERVER_receive_done (client,
1198                               GNUNET_OK);
1199   if (s->total != s->client_received_element_count)
1200   {
1201     /* more to come */
1202     return;
1203   }
1204   client_request_complete_alice (s);
1205 }
1206
1207
1208 /**
1209  * Handler for Alice's client request message.
1210  * We are doing request-initiation to compute a scalar product with a peer.
1211  *
1212  * @param cls closure
1213  * @param client identification of the client
1214  * @param message the actual message
1215  */
1216 static void
1217 GSS_handle_alice_client_message (void *cls,
1218                                  struct GNUNET_SERVER_Client *client,
1219                                  const struct GNUNET_MessageHeader *message)
1220 {
1221   const struct AliceComputationMessage *msg;
1222   struct AliceServiceSession *s;
1223   uint32_t contained_count;
1224   uint32_t total_count;
1225   const struct GNUNET_SCALARPRODUCT_Element *elements;
1226   uint32_t i;
1227   uint16_t msize;
1228   struct GNUNET_SET_Element set_elem;
1229   struct GNUNET_SCALARPRODUCT_Element *elem;
1230
1231   s = GNUNET_SERVER_client_get_user_context (client,
1232                                              struct AliceServiceSession);
1233   if (NULL != s)
1234   {
1235     /* only one concurrent session per client connection allowed,
1236        simplifies logic a lot... */
1237     GNUNET_break (0);
1238     GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
1239     return;
1240   }
1241   msize = ntohs (message->size);
1242   if (msize < sizeof (struct AliceComputationMessage))
1243   {
1244     GNUNET_break (0);
1245     GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
1246     return;
1247   }
1248   msg = (const struct AliceComputationMessage *) message;
1249   total_count = ntohl (msg->element_count_total);
1250   contained_count = ntohl (msg->element_count_contained);
1251   if ( (0 == total_count) ||
1252        (0 == contained_count) ||
1253        (msize != (sizeof (struct AliceComputationMessage) +
1254                   contained_count * sizeof (struct GNUNET_SCALARPRODUCT_Element))) )
1255   {
1256     GNUNET_break_op (0);
1257     GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
1258     return;
1259   }
1260
1261   s = GNUNET_new (struct AliceServiceSession);
1262   s->peer = msg->peer;
1263   s->status = GNUNET_SCALARPRODUCT_STATUS_ACTIVE;
1264   s->client = client;
1265   s->client_mq = GNUNET_MQ_queue_for_server_client (client);
1266   s->total = total_count;
1267   s->client_received_element_count = contained_count;
1268   s->session_id = msg->session_key;
1269   elements = (const struct GNUNET_SCALARPRODUCT_Element *) &msg[1];
1270   s->intersected_elements = GNUNET_CONTAINER_multihashmap_create (s->total,
1271                                                                   GNUNET_YES);
1272   s->intersection_set = GNUNET_SET_create (cfg,
1273                                            GNUNET_SET_OPERATION_INTERSECTION);
1274   for (i = 0; i < contained_count; i++)
1275   {
1276     if (0 == GNUNET_ntohll (elements[i].value))
1277       continue;
1278     elem = GNUNET_new (struct GNUNET_SCALARPRODUCT_Element);
1279     memcpy (elem,
1280             &elements[i],
1281             sizeof (struct GNUNET_SCALARPRODUCT_Element));
1282     if (GNUNET_SYSERR ==
1283         GNUNET_CONTAINER_multihashmap_put (s->intersected_elements,
1284                                            &elem->key,
1285                                            elem,
1286                                            GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY))
1287     {
1288       /* element with same key encountered twice! */
1289       GNUNET_break (0);
1290       GNUNET_free (elem);
1291       continue;
1292     }
1293     set_elem.data = &elem->key;
1294     set_elem.size = sizeof (elem->key);
1295     set_elem.element_type = 0;
1296     GNUNET_SET_add_element (s->intersection_set,
1297                             &set_elem,
1298                             NULL, NULL);
1299     s->used_element_count++;
1300   }
1301   GNUNET_SERVER_client_set_user_context (client,
1302                                          s);
1303   GNUNET_SERVER_receive_done (client,
1304                               GNUNET_OK);
1305   if (s->total != s->client_received_element_count)
1306   {
1307     /* wait for multipart msg */
1308     return;
1309   }
1310   client_request_complete_alice (s);
1311 }
1312
1313
1314 /**
1315  * Task run during shutdown.
1316  *
1317  * @param cls unused
1318  */
1319 static void
1320 shutdown_task (void *cls)
1321 {
1322   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1323               "Shutting down, initiating cleanup.\n");
1324   // FIXME: we have to cut our connections to CADET first!
1325   if (NULL != my_cadet)
1326   {
1327     GNUNET_CADET_disconnect (my_cadet);
1328     my_cadet = NULL;
1329   }
1330 }
1331
1332
1333 /**
1334  * A client disconnected.
1335  *
1336  * Remove the associated session(s), release data structures
1337  * and cancel pending outgoing transmissions to the client.
1338  *
1339  * @param cls closure, NULL
1340  * @param client identification of the client
1341  */
1342 static void
1343 handle_client_disconnect (void *cls,
1344                           struct GNUNET_SERVER_Client *client)
1345 {
1346   struct AliceServiceSession *s;
1347
1348   if (NULL == client)
1349     return;
1350   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1351               "Client %p disconnected from us.\n",
1352               client);
1353   s = GNUNET_SERVER_client_get_user_context (client,
1354                                              struct AliceServiceSession);
1355   if (NULL == s)
1356     return;
1357   s->client = NULL;
1358   GNUNET_SERVER_client_set_user_context (client,
1359                                          NULL);
1360   destroy_service_session (s);
1361 }
1362
1363
1364 /**
1365  * Initialization of the program and message handlers
1366  *
1367  * @param cls closure
1368  * @param server the initialized server
1369  * @param c configuration to use
1370  */
1371 static void
1372 run (void *cls,
1373      struct GNUNET_SERVER_Handle *server,
1374      const struct GNUNET_CONFIGURATION_Handle *c)
1375 {
1376   static const struct GNUNET_CADET_MessageHandler cadet_handlers[] = {
1377     { &handle_bobs_cryptodata_message,
1378       GNUNET_MESSAGE_TYPE_SCALARPRODUCT_BOB_CRYPTODATA,
1379       0},
1380     { &handle_bobs_cryptodata_multipart,
1381       GNUNET_MESSAGE_TYPE_SCALARPRODUCT_BOB_CRYPTODATA_MULTIPART,
1382       0},
1383     { NULL, 0, 0}
1384   };
1385   static const struct GNUNET_SERVER_MessageHandler server_handlers[] = {
1386     { &GSS_handle_alice_client_message, NULL,
1387       GNUNET_MESSAGE_TYPE_SCALARPRODUCT_CLIENT_TO_ALICE,
1388       0},
1389     { &GSS_handle_alice_client_message_multipart, NULL,
1390       GNUNET_MESSAGE_TYPE_SCALARPRODUCT_CLIENT_MUTLIPART_ALICE,
1391       0},
1392     { NULL, NULL, 0, 0}
1393   };
1394
1395   cfg = c;
1396   /*
1397     offset has to be sufficiently small to allow computation of:
1398     m1+m2 mod n == (S + a) + (S + b) mod n,
1399     if we have more complex operations, this factor needs to be lowered */
1400   my_offset = gcry_mpi_new (GNUNET_CRYPTO_PAILLIER_BITS / 3);
1401   gcry_mpi_set_bit (my_offset,
1402                     GNUNET_CRYPTO_PAILLIER_BITS / 3);
1403
1404   GNUNET_CRYPTO_paillier_create (&my_pubkey,
1405                                  &my_privkey);
1406   GNUNET_SERVER_add_handlers (server,
1407                               server_handlers);
1408   GNUNET_SERVER_disconnect_notify (server,
1409                                    &handle_client_disconnect,
1410                                    NULL);
1411   my_cadet = GNUNET_CADET_connect (cfg, NULL,
1412                                    NULL /* no incoming supported */,
1413                                    &cb_channel_destruction,
1414                                    cadet_handlers,
1415                                    NULL);
1416   if (NULL == my_cadet)
1417   {
1418     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1419                 _("Connect to CADET failed\n"));
1420     GNUNET_SCHEDULER_shutdown ();
1421     return;
1422   }
1423   GNUNET_SCHEDULER_add_shutdown (&shutdown_task,
1424                                  NULL);
1425
1426 }
1427
1428
1429 /**
1430  * The main function for the scalarproduct service.
1431  *
1432  * @param argc number of arguments from the command line
1433  * @param argv command line arguments
1434  * @return 0 ok, 1 on error
1435  */
1436 int
1437 main (int argc,
1438       char *const *argv)
1439 {
1440   return (GNUNET_OK ==
1441           GNUNET_SERVICE_run (argc, argv,
1442                               "scalarproduct-alice",
1443                               GNUNET_SERVICE_OPTION_NONE,
1444                               &run, NULL)) ? 0 : 1;
1445 }
1446
1447 /* end of gnunet-service-scalarproduct_alice.c */