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