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