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