-simplify
[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   gcry_mpi_set_ui (ret, ai_bi);
473   return ret;
474 }
475
476
477 /**
478  * Handle a response we got from another service we wanted to
479  * calculate a scalarproduct with.
480  *
481  * @param cls closure (set from #GNUNET_CADET_connect)
482  * @param channel connection to the other end
483  * @param channel_ctx place to store local state associated with the channel
484  * @param message the actual message
485  * @return #GNUNET_OK to keep the connection open,
486  *         #GNUNET_SYSERR to close it (we are done)
487  */
488 static int
489 handle_bobs_cryptodata_message (void *cls,
490                                 struct GNUNET_CADET_Channel *channel,
491                                 void **channel_ctx,
492                                 const struct GNUNET_MessageHeader *message)
493 {
494   struct AliceServiceSession *s = *channel_ctx;
495   const struct EccBobCryptodataMessage *msg;
496   uint32_t contained;
497   uint16_t msg_size;
498   gcry_mpi_point_t prod_g_i_b_i;
499   gcry_mpi_point_t prod_h_i_b_i;
500
501   if (NULL == s)
502   {
503     GNUNET_break_op (0);
504     return GNUNET_SYSERR;
505   }
506   msg_size = ntohs (message->size);
507   if (sizeof (struct EccBobCryptodataMessage) > msg_size)
508   {
509     GNUNET_break_op (0);
510     return GNUNET_SYSERR;
511   }
512   msg = (const struct EccBobCryptodataMessage *) message;
513   contained = ntohl (msg->contained_element_count);
514   if (2 != contained)
515   {
516     GNUNET_break_op (0);
517     return GNUNET_SYSERR;
518   }
519   if (NULL == s->sorted_elements)
520   {
521     /* we're not ready yet, how can Bob be? */
522     GNUNET_break_op (0);
523     return GNUNET_SYSERR;
524   }
525   if (s->total != s->client_received_element_count)
526   {
527     /* we're not ready yet, how can Bob be? */
528     GNUNET_break_op (0);
529     return GNUNET_SYSERR;
530   }
531   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
532               "Received %u crypto values from Bob\n",
533               (unsigned int) contained);
534   GNUNET_CADET_receive_done (s->channel);
535   prod_g_i_b_i = GNUNET_CRYPTO_ecc_bin_to_point (edc,
536                                                  &msg->prod_g_i_b_i);
537   prod_h_i_b_i = GNUNET_CRYPTO_ecc_bin_to_point (edc,
538                                                  &msg->prod_h_i_b_i);
539   s->product = compute_scalar_product (s,
540                                        prod_g_i_b_i,
541                                        prod_h_i_b_i);
542   gcry_mpi_point_release (prod_g_i_b_i);
543   gcry_mpi_point_release (prod_h_i_b_i);
544   transmit_client_response (s);
545   return GNUNET_OK;
546 }
547
548
549 /**
550  * Iterator to copy over messages from the hash map
551  * into an array for sorting.
552  *
553  * @param cls the `struct AliceServiceSession *`
554  * @param key the key (unused)
555  * @param value the `struct GNUNET_SCALARPRODUCT_Element *`
556  */
557 static int
558 copy_element_cb (void *cls,
559                  const struct GNUNET_HashCode *key,
560                  void *value)
561 {
562   struct AliceServiceSession *s = cls;
563   struct GNUNET_SCALARPRODUCT_Element *e = value;
564   gcry_mpi_t mval;
565   int64_t val;
566
567   mval = gcry_mpi_new (0);
568   val = (int64_t) GNUNET_ntohll (e->value);
569   if (0 > val)
570     gcry_mpi_sub_ui (mval, mval, -val);
571   else
572     gcry_mpi_add_ui (mval, mval, val);
573   s->sorted_elements [s->used_element_count].value = mval;
574   s->sorted_elements [s->used_element_count].key = &e->key;
575   s->used_element_count++;
576   return GNUNET_OK;
577 }
578
579
580 /**
581  * Compare two `struct MpiValue`s by key for sorting.
582  *
583  * @param a pointer to first `struct MpiValue *`
584  * @param b pointer to first `struct MpiValue *`
585  * @return -1 for a < b, 0 for a=b, 1 for a > b.
586  */
587 static int
588 element_cmp (const void *a,
589              const void *b)
590 {
591   const struct MpiElement *ma = a;
592   const struct MpiElement *mb = b;
593
594   return GNUNET_CRYPTO_hash_cmp (ma->key,
595                                  mb->key);
596 }
597
598
599 /**
600  * Maximum number of elements we can put into a single cryptodata
601  * message
602  */
603 #define ELEMENT_CAPACITY ((GNUNET_CONSTANTS_MAX_CADET_MESSAGE_SIZE - 1 - sizeof (struct EccAliceCryptodataMessage)) / sizeof (struct GNUNET_CRYPTO_EccPoint))
604
605
606 /**
607  * Send the cryptographic data from Alice to Bob.
608  * Does nothing if we already transferred all elements.
609  *
610  * @param s the associated service session
611  */
612 static void
613 send_alices_cryptodata_message (struct AliceServiceSession *s)
614 {
615   struct EccAliceCryptodataMessage *msg;
616   struct GNUNET_MQ_Envelope *e;
617   struct GNUNET_CRYPTO_EccPoint *payload;
618   gcry_mpi_t r_ia;
619   gcry_mpi_t r_ia_ai;
620   unsigned int i;
621   unsigned int off;
622   unsigned int todo_count;
623
624   s->sorted_elements
625     = GNUNET_malloc (GNUNET_CONTAINER_multihashmap_size (s->intersected_elements) *
626                      sizeof (struct MpiElement));
627   s->used_element_count = 0;
628   GNUNET_CONTAINER_multihashmap_iterate (s->intersected_elements,
629                                          &copy_element_cb,
630                                          s);
631   LOG (GNUNET_ERROR_TYPE_DEBUG,
632        "Finished intersection, %d items remain\n",
633        s->used_element_count);
634   qsort (s->sorted_elements,
635          s->used_element_count,
636          sizeof (struct MpiElement),
637          &element_cmp);
638   off = 0;
639   while (off < s->used_element_count)
640   {
641     todo_count = s->used_element_count - off;
642     if (todo_count > ELEMENT_CAPACITY)
643       todo_count = ELEMENT_CAPACITY;
644     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
645                 "Sending %u/%u crypto values to Bob\n",
646                 (unsigned int) todo_count,
647                 (unsigned int) s->used_element_count);
648
649     e = GNUNET_MQ_msg_extra (msg,
650                              todo_count * 2 * sizeof (struct GNUNET_CRYPTO_EccPoint),
651                              GNUNET_MESSAGE_TYPE_SCALARPRODUCT_ECC_ALICE_CRYPTODATA);
652     msg->contained_element_count = htonl (todo_count);
653     payload = (struct GNUNET_CRYPTO_EccPoint *) &msg[1];
654     r_ia = gcry_mpi_new (0);
655     r_ia_ai = gcry_mpi_new (0);
656     for (i = off; i < off + todo_count; i++)
657     {
658       gcry_mpi_t r_i;
659       gcry_mpi_point_t g_i;
660       gcry_mpi_point_t h_i;
661
662       r_i = GNUNET_CRYPTO_ecc_random_mod_n (edc);
663       g_i = GNUNET_CRYPTO_ecc_dexp_mpi (edc,
664                                         r_i);
665       /* r_ia = r_i * a */
666       gcry_mpi_mul (r_i,
667                     my_privkey,
668                     r_ia);
669       gcry_mpi_release (r_i);
670       /* r_ia_ai = r_ia + a_i */
671       gcry_mpi_add (r_ia_ai,
672                     s->sorted_elements[i].value,
673                     r_ia);
674       h_i = GNUNET_CRYPTO_ecc_dexp_mpi (edc,
675                                         r_ia_ai);
676       GNUNET_CRYPTO_ecc_point_to_bin (edc,
677                                       g_i,
678                                       &payload[(i - off) * 2]);
679       GNUNET_CRYPTO_ecc_point_to_bin (edc,
680                                       h_i,
681                                       &payload[(i - off) * 2 + 1]);
682       gcry_mpi_point_release (g_i);
683       gcry_mpi_point_release (h_i);
684     }
685     gcry_mpi_release (r_ia);
686     gcry_mpi_release (r_ia_ai);
687     off += todo_count;
688     GNUNET_MQ_send (s->cadet_mq,
689                     e);
690   }
691 }
692
693
694 /**
695  * Callback for set operation results. Called for each element
696  * that should be removed from the result set, and then once
697  * to indicate that the set intersection operation is done.
698  *
699  * @param cls closure with the `struct AliceServiceSession`
700  * @param element a result element, only valid if status is #GNUNET_SET_STATUS_OK
701  * @param status what has happened with the set intersection?
702  */
703 static void
704 cb_intersection_element_removed (void *cls,
705                                  const struct GNUNET_SET_Element *element,
706                                  enum GNUNET_SET_Status status)
707 {
708   struct AliceServiceSession *s = cls;
709   struct GNUNET_SCALARPRODUCT_Element *se;
710
711   switch (status)
712   {
713   case GNUNET_SET_STATUS_OK:
714     /* this element has been removed from the set */
715     se = GNUNET_CONTAINER_multihashmap_get (s->intersected_elements,
716                                             element->data);
717     GNUNET_assert (NULL != se);
718     LOG (GNUNET_ERROR_TYPE_DEBUG,
719          "Intersection removed element with key %s and value %lld\n",
720          GNUNET_h2s (&se->key),
721          (long long) GNUNET_ntohll (se->value));
722     GNUNET_assert (GNUNET_YES ==
723                    GNUNET_CONTAINER_multihashmap_remove (s->intersected_elements,
724                                                          element->data,
725                                                          se));
726     GNUNET_free (se);
727     return;
728   case GNUNET_SET_STATUS_DONE:
729     s->intersection_op = NULL;
730     if (NULL != s->intersection_set)
731     {
732       GNUNET_SET_destroy (s->intersection_set);
733       s->intersection_set = NULL;
734     }
735     send_alices_cryptodata_message (s);
736     return;
737   case GNUNET_SET_STATUS_HALF_DONE:
738     /* unexpected for intersection */
739     GNUNET_break (0);
740     return;
741   case GNUNET_SET_STATUS_FAILURE:
742     /* unhandled status code */
743     LOG (GNUNET_ERROR_TYPE_DEBUG,
744          "Set intersection failed!\n");
745     if (NULL != s->intersection_listen)
746     {
747       GNUNET_SET_listen_cancel (s->intersection_listen);
748       s->intersection_listen = NULL;
749     }
750     s->intersection_op = NULL;
751     if (NULL != s->intersection_set)
752     {
753       GNUNET_SET_destroy (s->intersection_set);
754       s->intersection_set = NULL;
755     }
756     s->status = GNUNET_SCALARPRODUCT_STATUS_FAILURE;
757     prepare_client_end_notification (s);
758     return;
759   default:
760     GNUNET_break (0);
761     return;
762   }
763 }
764
765
766 /**
767  * Called when another peer wants to do a set operation with the
768  * local peer. If a listen error occurs, the @a request is NULL.
769  *
770  * @param cls closure with the `struct AliceServiceSession *`
771  * @param other_peer the other peer
772  * @param context_msg message with application specific information from
773  *        the other peer
774  * @param request request from the other peer (never NULL), use GNUNET_SET_accept()
775  *        to accept it, otherwise the request will be refused
776  *        Note that we can't just return value from the listen callback,
777  *        as it is also necessary to specify the set we want to do the
778  *        operation with, whith sometimes can be derived from the context
779  *        message. It's necessary to specify the timeout.
780  */
781 static void
782 cb_intersection_request_alice (void *cls,
783                                const struct GNUNET_PeerIdentity *other_peer,
784                                const struct GNUNET_MessageHeader *context_msg,
785                                struct GNUNET_SET_Request *request)
786 {
787   struct AliceServiceSession *s = cls;
788
789   if (0 != memcmp (other_peer,
790                    &s->peer,
791                    sizeof (struct GNUNET_PeerIdentity)))
792   {
793     GNUNET_break_op (0);
794     return;
795   }
796   s->intersection_op
797     = GNUNET_SET_accept (request,
798                          GNUNET_SET_RESULT_REMOVED,
799                          &cb_intersection_element_removed,
800                          s);
801   if (NULL == s->intersection_op)
802   {
803     GNUNET_break (0);
804     s->status = GNUNET_SCALARPRODUCT_STATUS_FAILURE;
805     prepare_client_end_notification (s);
806     return;
807   }
808   if (GNUNET_OK !=
809       GNUNET_SET_commit (s->intersection_op,
810                          s->intersection_set))
811   {
812     GNUNET_break (0);
813     s->status = GNUNET_SCALARPRODUCT_STATUS_FAILURE;
814     prepare_client_end_notification (s);
815     return;
816   }
817   GNUNET_SET_destroy (s->intersection_set);
818   s->intersection_set = NULL;
819   GNUNET_SET_listen_cancel (s->intersection_listen);
820   s->intersection_listen = NULL;
821 }
822
823
824 /**
825  * Our client has finished sending us its multipart message.
826  *
827  * @param session the service session context
828  */
829 static void
830 client_request_complete_alice (struct AliceServiceSession *s)
831 {
832   struct EccServiceRequestMessage *msg;
833   struct GNUNET_MQ_Envelope *e;
834
835   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
836               "Creating new channel for session with key %s.\n",
837               GNUNET_h2s (&s->session_id));
838   s->channel
839     = GNUNET_CADET_channel_create (my_cadet,
840                                    s,
841                                    &s->peer,
842                                    GNUNET_APPLICATION_TYPE_SCALARPRODUCT_ECC,
843                                    GNUNET_CADET_OPTION_RELIABLE);
844   if (NULL == s->channel)
845   {
846     s->status = GNUNET_SCALARPRODUCT_STATUS_FAILURE;
847     prepare_client_end_notification (s);
848     return;
849   }
850   s->cadet_mq = GNUNET_CADET_mq_create (s->channel);
851   s->intersection_listen
852     = GNUNET_SET_listen (cfg,
853                          GNUNET_SET_OPERATION_INTERSECTION,
854                          &s->session_id,
855                          &cb_intersection_request_alice,
856                          s);
857   if (NULL == s->intersection_listen)
858   {
859     s->status = GNUNET_SCALARPRODUCT_STATUS_FAILURE;
860     GNUNET_CADET_channel_destroy (s->channel);
861     s->channel = NULL;
862     prepare_client_end_notification (s);
863     return;
864   }
865
866   e = GNUNET_MQ_msg (msg,
867                      GNUNET_MESSAGE_TYPE_SCALARPRODUCT_ECC_SESSION_INITIALIZATION);
868   msg->session_id = s->session_id;
869   GNUNET_MQ_send (s->cadet_mq,
870                   e);
871 }
872
873
874 /**
875  * We're receiving additional set data. Add it to our
876  * set and if we are done, initiate the transaction.
877  *
878  * @param cls closure
879  * @param client identification of the client
880  * @param message the actual message
881  */
882 static void
883 GSS_handle_alice_client_message_multipart (void *cls,
884                                            struct GNUNET_SERVER_Client *client,
885                                            const struct GNUNET_MessageHeader *message)
886 {
887   const struct ComputationBobCryptodataMultipartMessage * msg;
888   struct AliceServiceSession *s;
889   uint32_t contained_count;
890   const struct GNUNET_SCALARPRODUCT_Element *elements;
891   uint32_t i;
892   uint16_t msize;
893   struct GNUNET_SET_Element set_elem;
894   struct GNUNET_SCALARPRODUCT_Element *elem;
895
896   s = GNUNET_SERVER_client_get_user_context (client,
897                                              struct AliceServiceSession);
898   if (NULL == s)
899   {
900     /* session needs to already exist */
901     GNUNET_break (0);
902     GNUNET_SERVER_receive_done (client,
903                                 GNUNET_SYSERR);
904     return;
905   }
906   msize = ntohs (message->size);
907   if (msize < sizeof (struct ComputationBobCryptodataMultipartMessage))
908   {
909     GNUNET_break (0);
910     GNUNET_SERVER_receive_done (client,
911                                 GNUNET_SYSERR);
912     return;
913   }
914   msg = (const struct ComputationBobCryptodataMultipartMessage *) message;
915   contained_count = ntohl (msg->element_count_contained);
916
917   if ( (msize != (sizeof (struct ComputationBobCryptodataMultipartMessage) +
918                   contained_count * sizeof (struct GNUNET_SCALARPRODUCT_Element))) ||
919        (0 == contained_count) ||
920        (s->total == s->client_received_element_count) ||
921        (s->total < s->client_received_element_count + contained_count) )
922   {
923     GNUNET_break_op (0);
924     GNUNET_SERVER_receive_done (client,
925                                 GNUNET_SYSERR);
926     return;
927   }
928   s->client_received_element_count += contained_count;
929   elements = (const struct GNUNET_SCALARPRODUCT_Element *) &msg[1];
930   for (i = 0; i < contained_count; i++)
931   {
932     elem = GNUNET_new (struct GNUNET_SCALARPRODUCT_Element);
933     memcpy (elem,
934             &elements[i],
935             sizeof (struct GNUNET_SCALARPRODUCT_Element));
936     if (GNUNET_SYSERR ==
937         GNUNET_CONTAINER_multihashmap_put (s->intersected_elements,
938                                            &elem->key,
939                                            elem,
940                                            GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY))
941     {
942       GNUNET_break (0);
943       GNUNET_free (elem);
944       continue;
945     }
946     set_elem.data = &elem->key;
947     set_elem.size = sizeof (elem->key);
948     set_elem.element_type = 0;
949     GNUNET_SET_add_element (s->intersection_set,
950                             &set_elem,
951                             NULL, NULL);
952     s->used_element_count++;
953   }
954   GNUNET_SERVER_receive_done (client,
955                               GNUNET_OK);
956   if (s->total != s->client_received_element_count)
957   {
958     /* more to come */
959     return;
960   }
961   client_request_complete_alice (s);
962 }
963
964
965 /**
966  * Handler for Alice's client request message.
967  * We are doing request-initiation to compute a scalar product with a peer.
968  *
969  * @param cls closure
970  * @param client identification of the client
971  * @param message the actual message
972  */
973 static void
974 GSS_handle_alice_client_message (void *cls,
975                                  struct GNUNET_SERVER_Client *client,
976                                  const struct GNUNET_MessageHeader *message)
977 {
978   const struct AliceComputationMessage *msg;
979   struct AliceServiceSession *s;
980   uint32_t contained_count;
981   uint32_t total_count;
982   const struct GNUNET_SCALARPRODUCT_Element *elements;
983   uint32_t i;
984   uint16_t msize;
985   struct GNUNET_SET_Element set_elem;
986   struct GNUNET_SCALARPRODUCT_Element *elem;
987
988   s = GNUNET_SERVER_client_get_user_context (client,
989                                              struct AliceServiceSession);
990   if (NULL != s)
991   {
992     /* only one concurrent session per client connection allowed,
993        simplifies logic a lot... */
994     GNUNET_break (0);
995     GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
996     return;
997   }
998   msize = ntohs (message->size);
999   if (msize < sizeof (struct AliceComputationMessage))
1000   {
1001     GNUNET_break (0);
1002     GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
1003     return;
1004   }
1005   msg = (const struct AliceComputationMessage *) message;
1006   total_count = ntohl (msg->element_count_total);
1007   contained_count = ntohl (msg->element_count_contained);
1008   if ( (0 == total_count) ||
1009        (0 == contained_count) ||
1010        (msize != (sizeof (struct AliceComputationMessage) +
1011                   contained_count * sizeof (struct GNUNET_SCALARPRODUCT_Element))) )
1012   {
1013     GNUNET_break_op (0);
1014     GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
1015     return;
1016   }
1017
1018   s = GNUNET_new (struct AliceServiceSession);
1019   s->peer = msg->peer;
1020   s->status = GNUNET_SCALARPRODUCT_STATUS_ACTIVE;
1021   s->client = client;
1022   s->client_mq = GNUNET_MQ_queue_for_server_client (client);
1023   s->total = total_count;
1024   s->client_received_element_count = contained_count;
1025   s->session_id = msg->session_key;
1026   elements = (const struct GNUNET_SCALARPRODUCT_Element *) &msg[1];
1027   s->intersected_elements = GNUNET_CONTAINER_multihashmap_create (s->total,
1028                                                                   GNUNET_YES);
1029   s->intersection_set = GNUNET_SET_create (cfg,
1030                                            GNUNET_SET_OPERATION_INTERSECTION);
1031   for (i = 0; i < contained_count; i++)
1032   {
1033     if (0 == GNUNET_ntohll (elements[i].value))
1034       continue;
1035     elem = GNUNET_new (struct GNUNET_SCALARPRODUCT_Element);
1036     memcpy (elem,
1037             &elements[i],
1038             sizeof (struct GNUNET_SCALARPRODUCT_Element));
1039     if (GNUNET_SYSERR ==
1040         GNUNET_CONTAINER_multihashmap_put (s->intersected_elements,
1041                                            &elem->key,
1042                                            elem,
1043                                            GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY))
1044     {
1045       /* element with same key encountered twice! */
1046       GNUNET_break (0);
1047       GNUNET_free (elem);
1048       continue;
1049     }
1050     set_elem.data = &elem->key;
1051     set_elem.size = sizeof (elem->key);
1052     set_elem.element_type = 0;
1053     GNUNET_SET_add_element (s->intersection_set,
1054                             &set_elem,
1055                             NULL, NULL);
1056     s->used_element_count++;
1057   }
1058   GNUNET_SERVER_client_set_user_context (client,
1059                                          s);
1060   GNUNET_SERVER_receive_done (client,
1061                               GNUNET_OK);
1062   if (s->total != s->client_received_element_count)
1063   {
1064     /* wait for multipart msg */
1065     return;
1066   }
1067   client_request_complete_alice (s);
1068 }
1069
1070
1071 /**
1072  * Task run during shutdown.
1073  *
1074  * @param cls unused
1075  * @param tc unused
1076  */
1077 static void
1078 shutdown_task (void *cls,
1079                const struct GNUNET_SCHEDULER_TaskContext *tc)
1080 {
1081   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1082               "Shutting down, initiating cleanup.\n");
1083   // FIXME: we have to cut our connections to CADET first!
1084   if (NULL != my_cadet)
1085   {
1086     GNUNET_CADET_disconnect (my_cadet);
1087     my_cadet = NULL;
1088   }
1089   if (NULL != edc)
1090   {
1091     GNUNET_CRYPTO_ecc_dlog_release (edc);
1092     edc = NULL;
1093   }
1094 }
1095
1096
1097 /**
1098  * A client disconnected.
1099  *
1100  * Remove the associated session(s), release data structures
1101  * and cancel pending outgoing transmissions to the client.
1102  *
1103  * @param cls closure, NULL
1104  * @param client identification of the client
1105  */
1106 static void
1107 handle_client_disconnect (void *cls,
1108                           struct GNUNET_SERVER_Client *client)
1109 {
1110   struct AliceServiceSession *s;
1111
1112   if (NULL == client)
1113     return;
1114   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1115               "Client %p disconnected from us.\n",
1116               client);
1117   s = GNUNET_SERVER_client_get_user_context (client,
1118                                              struct AliceServiceSession);
1119   if (NULL == s)
1120     return;
1121   s->client = NULL;
1122   GNUNET_SERVER_client_set_user_context (client,
1123                                          NULL);
1124   destroy_service_session (s);
1125 }
1126
1127
1128 /**
1129  * Initialization of the program and message handlers
1130  *
1131  * @param cls closure
1132  * @param server the initialized server
1133  * @param c configuration to use
1134  */
1135 static void
1136 run (void *cls,
1137      struct GNUNET_SERVER_Handle *server,
1138      const struct GNUNET_CONFIGURATION_Handle *c)
1139 {
1140   static const struct GNUNET_CADET_MessageHandler cadet_handlers[] = {
1141     { &handle_bobs_cryptodata_message,
1142       GNUNET_MESSAGE_TYPE_SCALARPRODUCT_ECC_BOB_CRYPTODATA,
1143       0},
1144     { NULL, 0, 0}
1145   };
1146   static const struct GNUNET_SERVER_MessageHandler server_handlers[] = {
1147     { &GSS_handle_alice_client_message, NULL,
1148       GNUNET_MESSAGE_TYPE_SCALARPRODUCT_CLIENT_TO_ALICE,
1149       0},
1150     { &GSS_handle_alice_client_message_multipart, NULL,
1151       GNUNET_MESSAGE_TYPE_SCALARPRODUCT_CLIENT_MUTLIPART_ALICE,
1152       0},
1153     { NULL, NULL, 0, 0}
1154   };
1155
1156   cfg = c;
1157   edc = GNUNET_CRYPTO_ecc_dlog_prepare (MAX_RESULT /* max value */,
1158                                         1024 /* RAM */);
1159   /* Select a random 'a' value for Alice */
1160   GNUNET_CRYPTO_ecc_rnd_mpi (edc,
1161                              &my_privkey,
1162                              &my_privkey_inv);
1163   GNUNET_SERVER_add_handlers (server,
1164                               server_handlers);
1165   GNUNET_SERVER_disconnect_notify (server,
1166                                    &handle_client_disconnect,
1167                                    NULL);
1168   my_cadet = GNUNET_CADET_connect (cfg, NULL,
1169                                    NULL /* no incoming supported */,
1170                                    &cb_channel_destruction,
1171                                    cadet_handlers,
1172                                    NULL);
1173   if (NULL == my_cadet)
1174   {
1175     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1176                 _("Connect to CADET failed\n"));
1177     GNUNET_SCHEDULER_shutdown ();
1178     return;
1179   }
1180   GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_FOREVER_REL,
1181                                 &shutdown_task,
1182                                 NULL);
1183
1184 }
1185
1186
1187 /**
1188  * The main function for the scalarproduct service.
1189  *
1190  * @param argc number of arguments from the command line
1191  * @param argv command line arguments
1192  * @return 0 ok, 1 on error
1193  */
1194 int
1195 main (int argc,
1196       char *const *argv)
1197 {
1198   return (GNUNET_OK ==
1199           GNUNET_SERVICE_run (argc, argv,
1200                               "scalarproduct-alice",
1201                               GNUNET_SERVICE_OPTION_NONE,
1202                               &run, NULL)) ? 0 : 1;
1203 }
1204
1205 /* end of gnunet-service-scalarproduct-ecc_alice.c */