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