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