Merge branch 'master' of 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-2017 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->client)
242   {
243     struct GNUNET_SERVICE_Client *c = s->client;
244
245     s->client = NULL;
246     GNUNET_SERVICE_client_drop (c);
247   }
248   if (NULL != s->channel)
249   {
250     GNUNET_CADET_channel_destroy (s->channel);
251     s->channel = NULL;
252   }
253   if (NULL != s->intersected_elements)
254   {
255     GNUNET_CONTAINER_multihashmap_iterate (s->intersected_elements,
256                                            &free_element_cb,
257                                            s);
258     GNUNET_CONTAINER_multihashmap_destroy (s->intersected_elements);
259     s->intersected_elements = NULL;
260   }
261   if (NULL != s->intersection_listen)
262   {
263     LOG (GNUNET_ERROR_TYPE_DEBUG,
264          "Set intersection, listen still up!\n");
265     GNUNET_SET_listen_cancel (s->intersection_listen);
266     s->intersection_listen = NULL;
267   }
268   if (NULL != s->intersection_op)
269   {
270     LOG (GNUNET_ERROR_TYPE_DEBUG,
271          "Set intersection, op still ongoing!\n");
272     GNUNET_SET_operation_cancel (s->intersection_op);
273     s->intersection_op = NULL;
274   }
275   if (NULL != s->intersection_set)
276   {
277     LOG (GNUNET_ERROR_TYPE_DEBUG,
278          "Set intersection, set still there!\n");
279     GNUNET_SET_destroy (s->intersection_set);
280     s->intersection_set = NULL;
281   }
282   if (NULL != s->sorted_elements)
283   {
284     for (i=0;i<s->used_element_count;i++)
285       gcry_mpi_release (s->sorted_elements[i].value);
286     GNUNET_free (s->sorted_elements);
287     s->sorted_elements = NULL;
288   }
289   if (NULL != s->product)
290   {
291     gcry_mpi_release (s->product);
292     s->product = NULL;
293   }
294   GNUNET_free (s);
295 }
296
297
298 /**
299  * Notify the client that the session has failed.  A message gets sent
300  * to Alice's client if we encountered any error.
301  *
302  * @param session the associated client session to fail or succeed
303  */
304 static void
305 prepare_client_end_notification (struct AliceServiceSession *session)
306 {
307   struct ClientResponseMessage *msg;
308   struct GNUNET_MQ_Envelope *e;
309
310   if (NULL == session->client_mq)
311     return; /* no client left to be notified */
312   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
313               "Sending session-end notification with status %d to client for session %s\n",
314               session->status,
315               GNUNET_h2s (&session->session_id));
316   e = GNUNET_MQ_msg (msg,
317                      GNUNET_MESSAGE_TYPE_SCALARPRODUCT_RESULT);
318   msg->product_length = htonl (0);
319   msg->status = htonl (session->status);
320   GNUNET_MQ_send (session->client_mq,
321                   e);
322 }
323
324
325 /**
326  * Prepare the final (positive) response we will send to Alice's
327  * client.
328  *
329  * @param s the session associated with our client.
330  */
331 static void
332 transmit_client_response (struct AliceServiceSession *s)
333 {
334   struct ClientResponseMessage *msg;
335   struct GNUNET_MQ_Envelope *e;
336   unsigned char *product_exported = NULL;
337   size_t product_length = 0;
338   int32_t range;
339   gcry_error_t rc;
340   int sign;
341   gcry_mpi_t value;
342
343   if (NULL == s->product)
344   {
345     GNUNET_break (0);
346     prepare_client_end_notification (s);
347     return;
348   }
349   value = gcry_mpi_new (0);
350   sign = gcry_mpi_cmp_ui (s->product, 0);
351   if (0 > sign)
352   {
353     range = -1;
354     gcry_mpi_sub (value,
355                   value,
356                   s->product);
357   }
358   else if (0 < sign)
359   {
360     range = 1;
361     gcry_mpi_add (value, value, s->product);
362   }
363   else
364   {
365     /* result is exactly zero */
366     range = 0;
367   }
368   gcry_mpi_release (s->product);
369   s->product = NULL;
370
371   if ( (0 != range) &&
372        (0 != (rc = gcry_mpi_aprint (GCRYMPI_FMT_STD,
373                                     &product_exported,
374                                     &product_length,
375                                     value))))
376   {
377     LOG_GCRY (GNUNET_ERROR_TYPE_ERROR,
378               "gcry_mpi_scan",
379               rc);
380     prepare_client_end_notification (s);
381     return;
382   }
383   gcry_mpi_release (value);
384   e = GNUNET_MQ_msg_extra (msg,
385                            product_length,
386                            GNUNET_MESSAGE_TYPE_SCALARPRODUCT_RESULT);
387   msg->status = htonl (GNUNET_SCALARPRODUCT_STATUS_SUCCESS);
388   msg->range = htonl (range);
389   msg->product_length = htonl (product_length);
390   if (NULL != product_exported)
391   {
392     GNUNET_memcpy (&msg[1],
393             product_exported,
394             product_length);
395     GNUNET_free (product_exported);
396   }
397   GNUNET_MQ_send (s->client_mq,
398                   e);
399   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
400               "Sent result to client, session %s has ended!\n",
401               GNUNET_h2s (&s->session_id));
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 the `struct AliceServiceSession`
412  * @param channel connection to the other end (henceforth invalid)
413  */
414 static void
415 cb_channel_destruction (void *cls,
416                         const struct GNUNET_CADET_Channel *channel)
417 {
418   struct AliceServiceSession *s = cls;
419
420   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
421               "Peer disconnected, terminating session %s with peer %s\n",
422               GNUNET_h2s (&s->session_id),
423               GNUNET_i2s (&s->peer));
424   s->channel = NULL;
425   if (GNUNET_SCALARPRODUCT_STATUS_ACTIVE == s->status)
426   {
427     /* We didn't get an answer yet, fail with error */
428     s->status = GNUNET_SCALARPRODUCT_STATUS_FAILURE;
429     prepare_client_end_notification (s);
430   }
431 }
432
433
434 /**
435  * Compute our scalar product, done by Alice
436  *
437  * @param session the session associated with this computation
438  * @param prod_g_i_b_i value from Bob
439  * @param prod_h_i_b_i value from Bob
440  * @return product as MPI, never NULL
441  */
442 static gcry_mpi_t
443 compute_scalar_product (struct AliceServiceSession *session,
444                         gcry_mpi_point_t prod_g_i_b_i,
445                         gcry_mpi_point_t prod_h_i_b_i)
446 {
447   gcry_mpi_point_t g_i_b_i_a_inv;
448   gcry_mpi_point_t g_ai_bi;
449   int ai_bi;
450   gcry_mpi_t ret;
451
452   g_i_b_i_a_inv = GNUNET_CRYPTO_ecc_pmul_mpi (edc,
453                                               prod_g_i_b_i,
454                                               my_privkey_inv);
455   g_ai_bi = GNUNET_CRYPTO_ecc_add (edc,
456                                    g_i_b_i_a_inv,
457                                    prod_h_i_b_i);
458   gcry_mpi_point_release (g_i_b_i_a_inv);
459   ai_bi = GNUNET_CRYPTO_ecc_dlog (edc,
460                                   g_ai_bi);
461   gcry_mpi_point_release (g_ai_bi);
462   if (INT_MAX == ai_bi)
463   {
464     /* result too big */
465     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
466                 "Scalar product result out of range\n");
467     return NULL;
468   }
469   ret = gcry_mpi_new (0);
470   if (ai_bi > 0)
471   {
472     gcry_mpi_set_ui (ret, ai_bi);
473   }
474   else
475   {
476     gcry_mpi_set_ui (ret, - ai_bi);
477     gcry_mpi_neg (ret, ret);
478   }
479   return ret;
480 }
481
482
483 /**
484  * Handle a response we got from another service we wanted to
485  * calculate a scalarproduct with.
486  *
487  * @param cls the `struct AliceServiceSession *`
488  * @param msg the actual message
489  */
490 static void
491 handle_bobs_cryptodata_message (void *cls,
492                                 const struct EccBobCryptodataMessage *msg)
493 {
494   struct AliceServiceSession *s = cls;
495   gcry_mpi_point_t prod_g_i_b_i;
496   gcry_mpi_point_t prod_h_i_b_i;
497   uint32_t contained;
498
499   contained = ntohl (msg->contained_element_count);
500   if (2 != contained)
501   {
502     GNUNET_break_op (0);
503     destroy_service_session (s);
504     return;
505   }
506   if (NULL == s->sorted_elements)
507   {
508     /* we're not ready yet, how can Bob be? */
509     GNUNET_break_op (0);
510     destroy_service_session (s);
511     return;
512   }
513   if (s->total != s->client_received_element_count)
514   {
515     /* we're not ready yet, how can Bob be? */
516     GNUNET_break_op (0);
517     destroy_service_session (s);
518     return;
519   }
520
521   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
522               "Received %u crypto values from Bob\n",
523               (unsigned int) contained);
524   GNUNET_CADET_receive_done (s->channel);
525   prod_g_i_b_i = GNUNET_CRYPTO_ecc_bin_to_point (edc,
526                                                  &msg->prod_g_i_b_i);
527   prod_h_i_b_i = GNUNET_CRYPTO_ecc_bin_to_point (edc,
528                                                  &msg->prod_h_i_b_i);
529   s->product = compute_scalar_product (s,
530                                        prod_g_i_b_i,
531                                        prod_h_i_b_i);
532   gcry_mpi_point_release (prod_g_i_b_i);
533   gcry_mpi_point_release (prod_h_i_b_i);
534   transmit_client_response (s);
535 }
536
537
538 /**
539  * Iterator to copy over messages from the hash map
540  * into an array for sorting.
541  *
542  * @param cls the `struct AliceServiceSession *`
543  * @param key the key (unused)
544  * @param value the `struct GNUNET_SCALARPRODUCT_Element *`
545  */
546 static int
547 copy_element_cb (void *cls,
548                  const struct GNUNET_HashCode *key,
549                  void *value)
550 {
551   struct AliceServiceSession *s = cls;
552   struct GNUNET_SCALARPRODUCT_Element *e = value;
553   gcry_mpi_t mval;
554   int64_t val;
555
556   mval = gcry_mpi_new (0);
557   val = (int64_t) GNUNET_ntohll (e->value);
558   if (0 > val)
559     gcry_mpi_sub_ui (mval, mval, -val);
560   else
561     gcry_mpi_add_ui (mval, mval, val);
562   s->sorted_elements [s->used_element_count].value = mval;
563   s->sorted_elements [s->used_element_count].key = &e->key;
564   s->used_element_count++;
565   return GNUNET_OK;
566 }
567
568
569 /**
570  * Compare two `struct MpiValue`s by key for sorting.
571  *
572  * @param a pointer to first `struct MpiValue *`
573  * @param b pointer to first `struct MpiValue *`
574  * @return -1 for a < b, 0 for a=b, 1 for a > b.
575  */
576 static int
577 element_cmp (const void *a,
578              const void *b)
579 {
580   const struct MpiElement *ma = a;
581   const struct MpiElement *mb = b;
582
583   return GNUNET_CRYPTO_hash_cmp (ma->key,
584                                  mb->key);
585 }
586
587
588 /**
589  * Maximum number of elements we can put into a single cryptodata
590  * message
591  */
592 #define ELEMENT_CAPACITY ((GNUNET_CONSTANTS_MAX_CADET_MESSAGE_SIZE - 1 - sizeof (struct EccAliceCryptodataMessage)) / sizeof (struct GNUNET_CRYPTO_EccPoint))
593
594
595 /**
596  * Send the cryptographic data from Alice to Bob.
597  * Does nothing if we already transferred all elements.
598  *
599  * @param s the associated service session
600  */
601 static void
602 send_alices_cryptodata_message (struct AliceServiceSession *s)
603 {
604   struct EccAliceCryptodataMessage *msg;
605   struct GNUNET_MQ_Envelope *e;
606   struct GNUNET_CRYPTO_EccPoint *payload;
607   gcry_mpi_t r_ia;
608   gcry_mpi_t r_ia_ai;
609   unsigned int i;
610   unsigned int off;
611   unsigned int todo_count;
612
613   s->sorted_elements
614     = GNUNET_new_array (GNUNET_CONTAINER_multihashmap_size (s->intersected_elements),
615                         struct MpiElement);
616   s->used_element_count = 0;
617   GNUNET_CONTAINER_multihashmap_iterate (s->intersected_elements,
618                                          &copy_element_cb,
619                                          s);
620   LOG (GNUNET_ERROR_TYPE_DEBUG,
621        "Finished intersection, %d items remain\n",
622        s->used_element_count);
623   qsort (s->sorted_elements,
624          s->used_element_count,
625          sizeof (struct MpiElement),
626          &element_cmp);
627   off = 0;
628   while (off < s->used_element_count)
629   {
630     todo_count = s->used_element_count - off;
631     if (todo_count > ELEMENT_CAPACITY)
632       todo_count = ELEMENT_CAPACITY;
633     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
634                 "Sending %u/%u crypto values to Bob\n",
635                 (unsigned int) todo_count,
636                 (unsigned int) s->used_element_count);
637
638     e = GNUNET_MQ_msg_extra (msg,
639                              todo_count * 2 * sizeof (struct GNUNET_CRYPTO_EccPoint),
640                              GNUNET_MESSAGE_TYPE_SCALARPRODUCT_ECC_ALICE_CRYPTODATA);
641     msg->contained_element_count = htonl (todo_count);
642     payload = (struct GNUNET_CRYPTO_EccPoint *) &msg[1];
643     r_ia = gcry_mpi_new (0);
644     r_ia_ai = gcry_mpi_new (0);
645     for (i = off; i < off + todo_count; i++)
646     {
647       gcry_mpi_t r_i;
648       gcry_mpi_point_t g_i;
649       gcry_mpi_point_t h_i;
650
651       r_i = GNUNET_CRYPTO_ecc_random_mod_n (edc);
652       g_i = GNUNET_CRYPTO_ecc_dexp_mpi (edc,
653                                         r_i);
654       /* r_ia = r_i * a */
655       gcry_mpi_mul (r_ia,
656                     r_i,
657                     my_privkey);
658       gcry_mpi_release (r_i);
659       /* r_ia_ai = r_ia + a_i */
660       gcry_mpi_add (r_ia_ai,
661                     r_ia,
662                     s->sorted_elements[i].value);
663       h_i = GNUNET_CRYPTO_ecc_dexp_mpi (edc,
664                                         r_ia_ai);
665       GNUNET_CRYPTO_ecc_point_to_bin (edc,
666                                       g_i,
667                                       &payload[(i - off) * 2]);
668       GNUNET_CRYPTO_ecc_point_to_bin (edc,
669                                       h_i,
670                                       &payload[(i - off) * 2 + 1]);
671       gcry_mpi_point_release (g_i);
672       gcry_mpi_point_release (h_i);
673     }
674     gcry_mpi_release (r_ia);
675     gcry_mpi_release (r_ia_ai);
676     off += todo_count;
677     GNUNET_MQ_send (s->cadet_mq,
678                     e);
679   }
680 }
681
682
683 /**
684  * Callback for set operation results. Called for each element
685  * that should be removed from the result set, and then once
686  * to indicate that the set intersection operation is done.
687  *
688  * @param cls closure with the `struct AliceServiceSession`
689  * @param element a result element, only valid if status is #GNUNET_SET_STATUS_OK
690  * @param current_size current set size
691  * @param status what has happened with the set intersection?
692  */
693 static void
694 cb_intersection_element_removed (void *cls,
695                                  const struct GNUNET_SET_Element *element,
696                                  uint64_t current_size,
697                                  enum GNUNET_SET_Status status)
698 {
699   struct AliceServiceSession *s = cls;
700   struct GNUNET_SCALARPRODUCT_Element *se;
701
702   switch (status)
703   {
704   case GNUNET_SET_STATUS_OK:
705     /* this element has been removed from the set */
706     se = GNUNET_CONTAINER_multihashmap_get (s->intersected_elements,
707                                             element->data);
708     GNUNET_assert (NULL != se);
709     LOG (GNUNET_ERROR_TYPE_DEBUG,
710          "Intersection removed element with key %s and value %lld\n",
711          GNUNET_h2s (&se->key),
712          (long long) GNUNET_ntohll (se->value));
713     GNUNET_assert (GNUNET_YES ==
714                    GNUNET_CONTAINER_multihashmap_remove (s->intersected_elements,
715                                                          element->data,
716                                                          se));
717     GNUNET_free (se);
718     return;
719   case GNUNET_SET_STATUS_DONE:
720     s->intersection_op = NULL;
721     if (NULL != s->intersection_set)
722     {
723       GNUNET_SET_destroy (s->intersection_set);
724       s->intersection_set = NULL;
725     }
726     send_alices_cryptodata_message (s);
727     return;
728   case GNUNET_SET_STATUS_HALF_DONE:
729     /* unexpected for intersection */
730     GNUNET_break (0);
731     return;
732   case GNUNET_SET_STATUS_FAILURE:
733     /* unhandled status code */
734     LOG (GNUNET_ERROR_TYPE_DEBUG,
735          "Set intersection failed!\n");
736     if (NULL != s->intersection_listen)
737     {
738       GNUNET_SET_listen_cancel (s->intersection_listen);
739       s->intersection_listen = NULL;
740     }
741     s->intersection_op = NULL;
742     if (NULL != s->intersection_set)
743     {
744       GNUNET_SET_destroy (s->intersection_set);
745       s->intersection_set = NULL;
746     }
747     s->status = GNUNET_SCALARPRODUCT_STATUS_FAILURE;
748     prepare_client_end_notification (s);
749     return;
750   default:
751     GNUNET_break (0);
752     return;
753   }
754 }
755
756
757 /**
758  * Called when another peer wants to do a set operation with the
759  * local peer. If a listen error occurs, the @a request is NULL.
760  *
761  * @param cls closure with the `struct AliceServiceSession *`
762  * @param other_peer the other peer
763  * @param context_msg message with application specific information from
764  *        the other peer
765  * @param request request from the other peer (never NULL), use GNUNET_SET_accept()
766  *        to accept it, otherwise the request will be refused
767  *        Note that we can't just return value from the listen callback,
768  *        as it is also necessary to specify the set we want to do the
769  *        operation with, whith sometimes can be derived from the context
770  *        message. It's necessary to specify the timeout.
771  */
772 static void
773 cb_intersection_request_alice (void *cls,
774                                const struct GNUNET_PeerIdentity *other_peer,
775                                const struct GNUNET_MessageHeader *context_msg,
776                                struct GNUNET_SET_Request *request)
777 {
778   struct AliceServiceSession *s = cls;
779
780   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
781               "Received intersection request from %s!\n",
782               GNUNET_i2s (other_peer));
783   if (0 != memcmp (other_peer,
784                    &s->peer,
785                    sizeof (struct GNUNET_PeerIdentity)))
786   {
787     GNUNET_break_op (0);
788     return;
789   }
790   s->intersection_op
791     = GNUNET_SET_accept (request,
792                          GNUNET_SET_RESULT_REMOVED,
793                          (struct GNUNET_SET_Option[]) {{ 0 }},
794                          &cb_intersection_element_removed,
795                          s);
796   if (NULL == s->intersection_op)
797   {
798     GNUNET_break (0);
799     s->status = GNUNET_SCALARPRODUCT_STATUS_FAILURE;
800     prepare_client_end_notification (s);
801     return;
802   }
803   if (GNUNET_OK !=
804       GNUNET_SET_commit (s->intersection_op,
805                          s->intersection_set))
806   {
807     GNUNET_break (0);
808     s->status = GNUNET_SCALARPRODUCT_STATUS_FAILURE;
809     prepare_client_end_notification (s);
810     return;
811   }
812   GNUNET_SET_destroy (s->intersection_set);
813   s->intersection_set = NULL;
814   GNUNET_SET_listen_cancel (s->intersection_listen);
815   s->intersection_listen = NULL;
816 }
817
818
819 /**
820  * Our client has finished sending us its multipart message.
821  *
822  * @param session the service session context
823  */
824 static void
825 client_request_complete_alice (struct AliceServiceSession *s)
826 {
827   struct GNUNET_MQ_MessageHandler cadet_handlers[] = {
828     GNUNET_MQ_hd_fixed_size (bobs_cryptodata_message,
829                              GNUNET_MESSAGE_TYPE_SCALARPRODUCT_ECC_BOB_CRYPTODATA,
830                              struct EccBobCryptodataMessage,
831                              s),
832     GNUNET_MQ_handler_end ()
833   };
834   struct EccServiceRequestMessage *msg;
835   struct GNUNET_MQ_Envelope *e;
836   struct GNUNET_HashCode set_sid;
837
838   GNUNET_CRYPTO_hash (&s->session_id,
839                       sizeof (struct GNUNET_HashCode),
840                       &set_sid);
841   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
842               "Creating new channel for session with key %s.\n",
843               GNUNET_h2s (&s->session_id));
844   s->channel
845     = GNUNET_CADET_channel_creatE (my_cadet,
846                                    s,
847                                    &s->peer,
848                                    &s->session_id,
849                                    GNUNET_CADET_OPTION_RELIABLE,
850                                    NULL,
851                                    &cb_channel_destruction,
852                                    cadet_handlers);
853   if (NULL == s->channel)
854   {
855     s->status = GNUNET_SCALARPRODUCT_STATUS_FAILURE;
856     prepare_client_end_notification (s);
857     return;
858   }
859   s->cadet_mq = GNUNET_CADET_get_mq (s->channel);
860   s->intersection_listen
861     = GNUNET_SET_listen (cfg,
862                          GNUNET_SET_OPERATION_INTERSECTION,
863                          &set_sid,
864                          &cb_intersection_request_alice,
865                          s);
866   if (NULL == s->intersection_listen)
867   {
868     s->status = GNUNET_SCALARPRODUCT_STATUS_FAILURE;
869     GNUNET_CADET_channel_destroy (s->channel);
870     s->channel = NULL;
871     prepare_client_end_notification (s);
872     return;
873   }
874
875   e = GNUNET_MQ_msg (msg,
876                      GNUNET_MESSAGE_TYPE_SCALARPRODUCT_ECC_SESSION_INITIALIZATION);
877   msg->session_id = s->session_id;
878   GNUNET_MQ_send (s->cadet_mq,
879                   e);
880 }
881
882
883 /**
884  * We're receiving additional set data. Check if
885  * @a msg is well-formed.
886  *
887  * @param cls client identification of the client
888  * @param msg the actual message
889  * @return #GNUNET_OK if @a msg is well-formed
890  */
891 static int
892 check_alice_client_message_multipart (void *cls,
893                                       const struct ComputationBobCryptodataMultipartMessage *msg)
894 {
895   struct AliceServiceSession *s = cls;
896   uint32_t contained_count;
897   uint16_t msize;
898
899   msize = ntohs (msg->header.size);
900   contained_count = ntohl (msg->element_count_contained);
901   if ( (msize != (sizeof (struct ComputationBobCryptodataMultipartMessage) +
902                   contained_count * sizeof (struct GNUNET_SCALARPRODUCT_Element))) ||
903        (0 == contained_count) ||
904        (s->total == s->client_received_element_count) ||
905        (s->total < s->client_received_element_count + contained_count) )
906   {
907     GNUNET_break_op (0);
908     return GNUNET_SYSERR;
909   }
910   return GNUNET_OK;
911 }
912
913
914 /**
915  * We're receiving additional set data. Add it to our
916  * set and if we are done, initiate the transaction.
917  *
918  * @param cls client identification of the client
919  * @param msg the actual message
920  */
921 static void
922 handle_alice_client_message_multipart (void *cls,
923                                        const struct ComputationBobCryptodataMultipartMessage *msg)
924 {
925   struct AliceServiceSession *s = cls;
926   uint32_t contained_count;
927   const struct GNUNET_SCALARPRODUCT_Element *elements;
928   struct GNUNET_SET_Element set_elem;
929   struct GNUNET_SCALARPRODUCT_Element *elem;
930
931   contained_count = ntohl (msg->element_count_contained);
932   s->client_received_element_count += contained_count;
933   elements = (const struct GNUNET_SCALARPRODUCT_Element *) &msg[1];
934   for (uint32_t i = 0; i < contained_count; i++)
935   {
936     elem = GNUNET_new (struct GNUNET_SCALARPRODUCT_Element);
937     GNUNET_memcpy (elem,
938                    &elements[i],
939                    sizeof (struct GNUNET_SCALARPRODUCT_Element));
940     if (GNUNET_SYSERR ==
941         GNUNET_CONTAINER_multihashmap_put (s->intersected_elements,
942                                            &elem->key,
943                                            elem,
944                                            GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY))
945     {
946       GNUNET_break (0);
947       GNUNET_free (elem);
948       continue;
949     }
950     set_elem.data = &elem->key;
951     set_elem.size = sizeof (elem->key);
952     set_elem.element_type = 0;
953     GNUNET_SET_add_element (s->intersection_set,
954                             &set_elem,
955                             NULL, NULL);
956     s->used_element_count++;
957   }
958   GNUNET_SERVICE_client_continue (s->client);
959   if (s->total != s->client_received_element_count)
960   {
961     /* more to come */
962     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
963                 "Received client multipart data, waiting for more!\n");
964     return;
965   }
966   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
967               "Launching computation\n");
968   client_request_complete_alice (s);
969 }
970
971
972 /**
973  * Handler for Alice's client request message.
974  * Check that @a msg is well-formed.
975  *
976  * @param cls identification of the client
977  * @param msg the actual message
978  * @return #GNUNET_OK if @a msg is well-formed
979  */
980 static int
981 check_alice_client_message (void *cls,
982                             const struct AliceComputationMessage *msg)
983 {
984   struct AliceServiceSession *s = cls;
985   uint16_t msize;
986   uint32_t total_count;
987   uint32_t contained_count;
988
989   if (NULL != s->intersected_elements)
990   {
991     /* only one concurrent session per client connection allowed,
992        simplifies logic a lot... */
993     GNUNET_break (0);
994     return GNUNET_SYSERR;
995   }
996   msize = ntohs (msg->header.size);
997   total_count = ntohl (msg->element_count_total);
998   contained_count = ntohl (msg->element_count_contained);
999   if ( (0 == total_count) ||
1000        (0 == contained_count) ||
1001        (msize != (sizeof (struct AliceComputationMessage) +
1002                   contained_count * sizeof (struct GNUNET_SCALARPRODUCT_Element))) )
1003   {
1004     GNUNET_break_op (0);
1005     return GNUNET_SYSERR;
1006   }
1007   return GNUNET_OK;
1008 }
1009
1010
1011 /**
1012  * Handler for Alice's client request message.
1013  * We are doing request-initiation to compute a scalar product with a peer.
1014  *
1015  * @param cls identification of the client
1016  * @param msg the actual message
1017  */
1018 static void
1019 handle_alice_client_message (void *cls,
1020                              const struct AliceComputationMessage *msg)
1021 {
1022   struct AliceServiceSession *s = cls;
1023   uint32_t contained_count;
1024   uint32_t total_count;
1025   const struct GNUNET_SCALARPRODUCT_Element *elements;
1026   struct GNUNET_SET_Element set_elem;
1027   struct GNUNET_SCALARPRODUCT_Element *elem;
1028
1029   total_count = ntohl (msg->element_count_total);
1030   contained_count = ntohl (msg->element_count_contained);
1031   s->peer = msg->peer;
1032   s->status = GNUNET_SCALARPRODUCT_STATUS_ACTIVE;
1033   s->total = total_count;
1034   s->client_received_element_count = contained_count;
1035   s->session_id = msg->session_key;
1036   elements = (const struct GNUNET_SCALARPRODUCT_Element *) &msg[1];
1037   s->intersected_elements = GNUNET_CONTAINER_multihashmap_create (s->total,
1038                                                                   GNUNET_YES);
1039   s->intersection_set = GNUNET_SET_create (cfg,
1040                                            GNUNET_SET_OPERATION_INTERSECTION);
1041   for (uint32_t i = 0; i < contained_count; i++)
1042   {
1043     if (0 == GNUNET_ntohll (elements[i].value))
1044       continue;
1045     elem = GNUNET_new (struct GNUNET_SCALARPRODUCT_Element);
1046     GNUNET_memcpy (elem,
1047                    &elements[i],
1048                    sizeof (struct GNUNET_SCALARPRODUCT_Element));
1049     if (GNUNET_SYSERR ==
1050         GNUNET_CONTAINER_multihashmap_put (s->intersected_elements,
1051                                            &elem->key,
1052                                            elem,
1053                                            GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY))
1054     {
1055       /* element with same key encountered twice! */
1056       GNUNET_break (0);
1057       GNUNET_free (elem);
1058       continue;
1059     }
1060     set_elem.data = &elem->key;
1061     set_elem.size = sizeof (elem->key);
1062     set_elem.element_type = 0;
1063     GNUNET_SET_add_element (s->intersection_set,
1064                             &set_elem,
1065                             NULL, NULL);
1066     s->used_element_count++;
1067   }
1068   GNUNET_SERVICE_client_continue (s->client);
1069   if (s->total != s->client_received_element_count)
1070   {
1071     /* wait for multipart msg */
1072     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1073                 "Received partial client request, waiting for more!\n");
1074     return;
1075   }
1076   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1077               "Launching computation\n");
1078   client_request_complete_alice (s);
1079 }
1080
1081
1082 /**
1083  * Task run during shutdown.
1084  *
1085  * @param cls unused
1086  * @param tc unused
1087  */
1088 static void
1089 shutdown_task (void *cls)
1090 {
1091   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1092               "Shutting down, initiating cleanup.\n");
1093   // FIXME: we have to cut our connections to CADET first!
1094   if (NULL != my_cadet)
1095   {
1096     GNUNET_CADET_disconnect (my_cadet);
1097     my_cadet = NULL;
1098   }
1099   if (NULL != edc)
1100   {
1101     GNUNET_CRYPTO_ecc_dlog_release (edc);
1102     edc = NULL;
1103   }
1104 }
1105
1106
1107 /**
1108  * A client connected.
1109  *
1110  * Setup the associated data structure.
1111  *
1112  * @param cls closure, NULL
1113  * @param client identification of the client
1114  * @param mq message queue to communicate with @a client
1115  * @return our `struct AliceServiceSession`
1116  */
1117 static void *
1118 client_connect_cb (void *cls,
1119                    struct GNUNET_SERVICE_Client *client,
1120                    struct GNUNET_MQ_Handle *mq)
1121 {
1122   struct AliceServiceSession *s;
1123
1124   s = GNUNET_new (struct AliceServiceSession);
1125   s->client = client;
1126   s->client_mq = mq;
1127   return s;
1128 }
1129
1130
1131 /**
1132  * A client disconnected.
1133  *
1134  * Remove the associated session(s), release data structures
1135  * and cancel pending outgoing transmissions to the client.
1136  *
1137  * @param cls closure, NULL
1138  * @param client identification of the client
1139  * @param app_cls our `struct AliceServiceSession`
1140  */
1141 static void
1142 client_disconnect_cb (void *cls,
1143                       struct GNUNET_SERVICE_Client *client,
1144                       void *app_cls)
1145 {
1146   struct AliceServiceSession *s = app_cls;
1147
1148   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1149               "Client %p disconnected from us.\n",
1150               client);
1151   s->client = NULL;
1152   s->client_mq = NULL;
1153   destroy_service_session (s);
1154 }
1155
1156
1157 /**
1158  * Initialization of the program and message handlers
1159  *
1160  * @param cls closure
1161  * @param c configuration to use
1162  * @param service the initialized service
1163  */
1164 static void
1165 run (void *cls,
1166      const struct GNUNET_CONFIGURATION_Handle *c,
1167      struct GNUNET_SERVICE_Handle *service)
1168 {
1169   cfg = c;
1170   edc = GNUNET_CRYPTO_ecc_dlog_prepare (MAX_RESULT,
1171                                         MAX_RAM);
1172   /* Select a random 'a' value for Alice */
1173   GNUNET_CRYPTO_ecc_rnd_mpi (edc,
1174                              &my_privkey,
1175                              &my_privkey_inv);
1176   my_cadet = GNUNET_CADET_connecT (cfg);
1177   if (NULL == my_cadet)
1178   {
1179     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1180                 _("Connect to CADET failed\n"));
1181     GNUNET_SCHEDULER_shutdown ();
1182     return;
1183   }
1184   GNUNET_SCHEDULER_add_shutdown (&shutdown_task,
1185                                  NULL);
1186
1187 }
1188
1189
1190 /**
1191  * Define "main" method using service macro.
1192  */
1193 GNUNET_SERVICE_MAIN
1194 ("scalarproduct-alice",
1195  GNUNET_SERVICE_OPTION_NONE,
1196  &run,
1197  &client_connect_cb,
1198  &client_disconnect_cb,
1199  NULL,
1200  GNUNET_MQ_hd_var_size (alice_client_message,
1201                         GNUNET_MESSAGE_TYPE_SCALARPRODUCT_CLIENT_TO_ALICE,
1202                         struct AliceComputationMessage,
1203                         NULL),
1204  GNUNET_MQ_hd_var_size (alice_client_message_multipart,
1205                         GNUNET_MESSAGE_TYPE_SCALARPRODUCT_CLIENT_MULTIPART_ALICE,
1206                         struct ComputationBobCryptodataMultipartMessage,
1207                         NULL),
1208  GNUNET_MQ_handler_end ());
1209
1210
1211 /* end of gnunet-service-scalarproduct-ecc_alice.c */