add attestation API
[oweals/gnunet.git] / src / scalarproduct / gnunet-service-scalarproduct-ecc_bob.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      You should have received a copy of the GNU Affero General Public License
16      along with this program.  If not, see <http://www.gnu.org/licenses/>.
17
18      SPDX-License-Identifier: AGPL3.0-or-later
19  */
20 /**
21  * @file scalarproduct/gnunet-service-scalarproduct-ecc_bob.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-bob", __VA_ARGS__)
40
41
42 /**
43  * An encrypted element key-value pair.
44  */
45 struct MpiElement
46 {
47   /**
48    * Key used to identify matching pairs of values to multiply.
49    * Points into an existing data structure, to avoid copying
50    * and doubling memory use.
51    */
52   const struct GNUNET_HashCode *key;
53
54   /**
55    * Value represented (a).
56    */
57   gcry_mpi_t value;
58 };
59
60
61 /**
62  * A scalarproduct session which tracks an offer for a
63  * multiplication service by a local client.
64  */
65 struct BobServiceSession
66 {
67   /**
68    * The client this request is related to.
69    */
70   struct GNUNET_SERVICE_Client *client;
71
72   /**
73    * Client message queue.
74    */
75   struct GNUNET_MQ_Handle *client_mq;
76
77   /**
78    * All non-0-value'd elements transmitted to us.
79    */
80   struct GNUNET_CONTAINER_MultiHashMap *intersected_elements;
81
82   /**
83    * Set of elements for which we will be conducting an intersection.
84    * The resulting elements are then used for computing the scalar product.
85    */
86   struct GNUNET_SET_Handle *intersection_set;
87
88   /**
89    * Set of elements for which will conduction an intersection.
90    * the resulting elements are then used for computing the scalar product.
91    */
92   struct GNUNET_SET_OperationHandle *intersection_op;
93
94   /**
95    * Our open port.
96    */
97   struct GNUNET_CADET_Port *port;
98
99   /**
100    * b(Bob)
101    */
102   struct MpiElement *sorted_elements;
103
104   /**
105    * Product of the g_i^{b_i}
106    */
107   gcry_mpi_point_t prod_g_i_b_i;
108
109   /**
110    * Product of the h_i^{b_i}
111    */
112   gcry_mpi_point_t prod_h_i_b_i;
113
114   /**
115    * How many elements will be supplied in total from the client.
116    */
117   uint32_t total;
118
119   /**
120    * Already transferred elements (received) for multipart
121    * messages from client. Always less than @e total.
122    */
123   uint32_t client_received_element_count;
124
125   /**
126    * How many elements actually are used for the scalar product.
127    * Size of the arrays in @e r and @e r_prime.  Also sometimes
128    * used as an index into the arrays during construction.
129    */
130   uint32_t used_element_count;
131
132   /**
133    * Counts the number of values received from Alice by us.
134    * Always less than @e used_element_count.
135    */
136   uint32_t cadet_received_element_count;
137
138   /**
139    * State of this session.   In
140    * #GNUNET_SCALARPRODUCT_STATUS_ACTIVE while operation is
141    * ongoing, afterwards in #GNUNET_SCALARPRODUCT_STATUS_SUCCESS or
142    * #GNUNET_SCALARPRODUCT_STATUS_FAILURE.
143    */
144   enum GNUNET_SCALARPRODUCT_ResponseStatus status;
145
146   /**
147    * Are we already in #destroy_service_session()?
148    */
149   int in_destroy;
150
151   /**
152    * The CADET channel.
153    */
154   struct GNUNET_CADET_Channel *channel;
155
156   /**
157    * Originator's peer identity. (Only for diagnostics.)
158    */
159   struct GNUNET_PeerIdentity peer;
160
161   /**
162    * (hopefully) unique transaction ID
163    */
164   struct GNUNET_HashCode session_id;
165
166   /**
167    * The message queue for this channel.
168    */
169   struct GNUNET_MQ_Handle *cadet_mq;
170 };
171
172
173 /**
174  * GNUnet configuration handle
175  */
176 static const struct GNUNET_CONFIGURATION_Handle *cfg;
177
178 /**
179  * Handle to the CADET service.
180  */
181 static struct GNUNET_CADET_Handle *my_cadet;
182
183 /**
184  * Context for DLOG operations on a curve.
185  */
186 static struct GNUNET_CRYPTO_EccDlogContext *edc;
187
188
189 /**
190  * Callback used to free the elements in the map.
191  *
192  * @param cls NULL
193  * @param key key of the element
194  * @param value the value to free
195  */
196 static int
197 free_element_cb (void *cls,
198                  const struct GNUNET_HashCode *key,
199                  void *value)
200 {
201   struct GNUNET_SCALARPRODUCT_Element *element = value;
202
203   GNUNET_free (element);
204   return GNUNET_OK;
205 }
206
207
208 /**
209  * Destroy session state, we are done with it.
210  *
211  * @param session the session to free elements from
212  */
213 static void
214 destroy_service_session (struct BobServiceSession *s)
215 {
216   unsigned int i;
217
218   if (GNUNET_YES == s->in_destroy)
219     return;
220   s->in_destroy = GNUNET_YES;
221   if (NULL != s->client)
222   {
223     struct GNUNET_SERVICE_Client *c = s->client;
224
225     s->client = NULL;
226     GNUNET_SERVICE_client_drop (c);
227   }
228   if (NULL != s->intersected_elements)
229   {
230     GNUNET_CONTAINER_multihashmap_iterate (s->intersected_elements,
231                                            &free_element_cb,
232                                            NULL);
233     GNUNET_CONTAINER_multihashmap_destroy (s->intersected_elements);
234     s->intersected_elements = NULL;
235   }
236   if (NULL != s->intersection_op)
237   {
238     GNUNET_SET_operation_cancel (s->intersection_op);
239     s->intersection_op = NULL;
240   }
241   if (NULL != s->intersection_set)
242   {
243     GNUNET_SET_destroy (s->intersection_set);
244     s->intersection_set = NULL;
245   }
246   if (NULL != s->sorted_elements)
247   {
248     for (i = 0; i < s->used_element_count; i++)
249       gcry_mpi_release (s->sorted_elements[i].value);
250     GNUNET_free (s->sorted_elements);
251     s->sorted_elements = NULL;
252   }
253   if (NULL != s->prod_g_i_b_i)
254   {
255     gcry_mpi_point_release (s->prod_g_i_b_i);
256     s->prod_g_i_b_i = NULL;
257   }
258   if (NULL != s->prod_h_i_b_i)
259   {
260     gcry_mpi_point_release (s->prod_h_i_b_i);
261     s->prod_h_i_b_i = NULL;
262   }
263   if (NULL != s->port)
264   {
265     GNUNET_CADET_close_port (s->port);
266     s->port = NULL;
267   }
268   if (NULL != s->channel)
269   {
270     GNUNET_CADET_channel_destroy (s->channel);
271     s->channel = NULL;
272   }
273   GNUNET_free (s);
274 }
275
276
277 /**
278  * Notify the client that the session has succeeded or failed.  This
279  * message gets sent to Bob's client if the operation completed or
280  * Alice disconnected.
281  *
282  * @param session the associated client session to fail or succeed
283  */
284 static void
285 prepare_client_end_notification (struct BobServiceSession *session)
286 {
287   struct ClientResponseMessage *msg;
288   struct GNUNET_MQ_Envelope *e;
289
290   if (NULL == session->client_mq)
291     return; /* no client left to be notified */
292   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
293               "Sending session-end notification with status %d to client for session %s\n",
294               session->status,
295               GNUNET_h2s (&session->session_id));
296   e = GNUNET_MQ_msg (msg,
297                      GNUNET_MESSAGE_TYPE_SCALARPRODUCT_RESULT);
298   msg->range = 0;
299   msg->product_length = htonl (0);
300   msg->status = htonl (session->status);
301   GNUNET_MQ_send (session->client_mq,
302                   e);
303 }
304
305
306 /**
307  * Function called whenever a channel is destroyed.  Should clean up
308  * any associated state.
309  *
310  * It must NOT call #GNUNET_CADET_channel_destroy() on the channel.
311  *
312  * @param cls the `struct BobServiceSession`
313  * @param channel connection to the other end (henceforth invalid)
314  * @param channel_ctx place where local state associated
315  *                   with the channel is stored
316  */
317 static void
318 cb_channel_destruction (void *cls,
319                         const struct GNUNET_CADET_Channel *channel)
320 {
321   struct BobServiceSession *s = cls;
322
323   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
324               "Peer disconnected, terminating session %s with peer %s\n",
325               GNUNET_h2s (&s->session_id),
326               GNUNET_i2s (&s->peer));
327   s->channel = NULL;
328   if (GNUNET_SCALARPRODUCT_STATUS_ACTIVE == s->status)
329   {
330     s->status = GNUNET_SCALARPRODUCT_STATUS_FAILURE;
331     prepare_client_end_notification (s);
332   }
333   destroy_service_session (s);
334 }
335
336
337 /**
338  * MQ finished giving our last message to CADET, now notify
339  * the client that we are finished.
340  */
341 static void
342 bob_cadet_done_cb (void *cls)
343 {
344   struct BobServiceSession *session = cls;
345
346   session->status = GNUNET_SCALARPRODUCT_STATUS_SUCCESS;
347   prepare_client_end_notification (session);
348 }
349
350
351 /**
352  * Bob generates the response message to be sent to Alice.
353  *
354  * @param s the associated requesting session with Alice
355  */
356 static void
357 transmit_bobs_cryptodata_message (struct BobServiceSession *s)
358 {
359   struct EccBobCryptodataMessage *msg;
360   struct GNUNET_MQ_Envelope *e;
361
362   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
363               "Sending response to Alice\n");
364   e = GNUNET_MQ_msg (msg,
365                      GNUNET_MESSAGE_TYPE_SCALARPRODUCT_ECC_BOB_CRYPTODATA);
366   msg->contained_element_count = htonl (2);
367   if (NULL != s->prod_g_i_b_i)
368     GNUNET_CRYPTO_ecc_point_to_bin (edc,
369                                     s->prod_g_i_b_i,
370                                     &msg->prod_g_i_b_i);
371   if (NULL != s->prod_h_i_b_i)
372     GNUNET_CRYPTO_ecc_point_to_bin (edc,
373                                     s->prod_h_i_b_i,
374                                     &msg->prod_h_i_b_i);
375   GNUNET_MQ_notify_sent (e,
376                          &bob_cadet_done_cb,
377                          s);
378   GNUNET_MQ_send (s->cadet_mq,
379                   e);
380 }
381
382
383 /**
384  * Iterator to copy over messages from the hash map
385  * into an array for sorting.
386  *
387  * @param cls the `struct BobServiceSession *`
388  * @param key the key (unused)
389  * @param value the `struct GNUNET_SCALARPRODUCT_Element *`
390  * TODO: code duplication with Alice!
391  */
392 static int
393 copy_element_cb (void *cls,
394                  const struct GNUNET_HashCode *key,
395                  void *value)
396 {
397   struct BobServiceSession *s = cls;
398   struct GNUNET_SCALARPRODUCT_Element *e = value;
399   gcry_mpi_t mval;
400   int64_t val;
401
402   mval = gcry_mpi_new (0);
403   val = (int64_t) GNUNET_ntohll (e->value);
404   if (0 > val)
405     gcry_mpi_sub_ui (mval, mval, -val);
406   else
407     gcry_mpi_add_ui (mval, mval, val);
408   s->sorted_elements [s->used_element_count].value = mval;
409   s->sorted_elements [s->used_element_count].key = &e->key;
410   s->used_element_count++;
411   return GNUNET_OK;
412 }
413
414
415 /**
416  * Compare two `struct MpiValue`s by key for sorting.
417  *
418  * @param a pointer to first `struct MpiValue *`
419  * @param b pointer to first `struct MpiValue *`
420  * @return -1 for a < b, 0 for a=b, 1 for a > b.
421  * TODO: code duplication with Alice!
422  */
423 static int
424 element_cmp (const void *a,
425              const void *b)
426 {
427   const struct MpiElement *ma = a;
428   const struct MpiElement *mb = b;
429
430   return GNUNET_CRYPTO_hash_cmp (ma->key,
431                                  mb->key);
432 }
433
434
435 /**
436  * Check a multipart-chunk of a request from another service to
437  * calculate a scalarproduct with us.
438  *
439  * @param cls closure (set from #GNUNET_CADET_connect)
440  * @param msg the actual message
441  * @return #GNUNET_OK to keep the connection open,
442  *         #GNUNET_SYSERR to close it (signal serious error)
443  */
444 static int
445 check_alices_cryptodata_message (void *cls,
446                                  const struct EccAliceCryptodataMessage *msg)
447 {
448   struct BobServiceSession *s = cls;
449   uint32_t contained_elements;
450   size_t msg_length;
451   uint16_t msize;
452   unsigned int max;
453
454   msize = ntohs (msg->header.size);
455   if (msize <= sizeof(struct EccAliceCryptodataMessage))
456   {
457     GNUNET_break_op (0);
458     return GNUNET_SYSERR;
459   }
460   contained_elements = ntohl (msg->contained_element_count);
461   /* Our intersection may still be ongoing, but this is nevertheless
462      an upper bound on the required array size */
463   max = GNUNET_CONTAINER_multihashmap_size (s->intersected_elements);
464   msg_length = sizeof(struct EccAliceCryptodataMessage)
465                + contained_elements * sizeof(struct GNUNET_CRYPTO_EccPoint) * 2;
466   if ((msize != msg_length) ||
467       (0 == contained_elements) ||
468       (contained_elements > UINT16_MAX) ||
469       (max < contained_elements + s->cadet_received_element_count))
470   {
471     GNUNET_break_op (0);
472     return GNUNET_SYSERR;
473   }
474   return GNUNET_OK;
475 }
476
477
478 /**
479  * Handle a multipart-chunk of a request from another service to
480  * calculate a scalarproduct with us.
481  *
482  * @param cls closure (set from #GNUNET_CADET_connect)
483  * @param msg the actual message
484  */
485 static void
486 handle_alices_cryptodata_message (void *cls,
487                                   const struct EccAliceCryptodataMessage *msg)
488 {
489   struct BobServiceSession *s = cls;
490   const struct GNUNET_CRYPTO_EccPoint *payload;
491   uint32_t contained_elements;
492   unsigned int max;
493   unsigned int i;
494   const struct MpiElement *b_i;
495   gcry_mpi_point_t tmp;
496   gcry_mpi_point_t g_i;
497   gcry_mpi_point_t h_i;
498   gcry_mpi_point_t g_i_b_i;
499   gcry_mpi_point_t h_i_b_i;
500
501   contained_elements = ntohl (msg->contained_element_count);
502   max = GNUNET_CONTAINER_multihashmap_size (s->intersected_elements);
503   /* sort our vector for the computation */
504   if (NULL == s->sorted_elements)
505   {
506     s->sorted_elements
507       = GNUNET_new_array (GNUNET_CONTAINER_multihashmap_size (
508                             s->intersected_elements),
509                           struct MpiElement);
510     s->used_element_count = 0;
511     GNUNET_CONTAINER_multihashmap_iterate (s->intersected_elements,
512                                            &copy_element_cb,
513                                            s);
514     qsort (s->sorted_elements,
515            s->used_element_count,
516            sizeof(struct MpiElement),
517            &element_cmp);
518   }
519
520   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
521               "Received %u crypto values from Alice\n",
522               (unsigned int) contained_elements);
523   payload = (const struct GNUNET_CRYPTO_EccPoint *) &msg[1];
524
525   for (i = 0; i < contained_elements; i++)
526   {
527     b_i = &s->sorted_elements[i + s->cadet_received_element_count];
528     g_i = GNUNET_CRYPTO_ecc_bin_to_point (edc,
529                                           &payload[i * 2]);
530     g_i_b_i = GNUNET_CRYPTO_ecc_pmul_mpi (edc,
531                                           g_i,
532                                           b_i->value);
533     gcry_mpi_point_release (g_i);
534     h_i = GNUNET_CRYPTO_ecc_bin_to_point (edc,
535                                           &payload[i * 2 + 1]);
536     h_i_b_i = GNUNET_CRYPTO_ecc_pmul_mpi (edc,
537                                           h_i,
538                                           b_i->value);
539     gcry_mpi_point_release (h_i);
540     if (0 == i + s->cadet_received_element_count)
541     {
542       /* first iteration, nothing to add */
543       s->prod_g_i_b_i = g_i_b_i;
544       s->prod_h_i_b_i = h_i_b_i;
545     }
546     else
547     {
548       /* further iterations, cummulate resulting value */
549       tmp = GNUNET_CRYPTO_ecc_add (edc,
550                                    s->prod_g_i_b_i,
551                                    g_i_b_i);
552       gcry_mpi_point_release (s->prod_g_i_b_i);
553       gcry_mpi_point_release (g_i_b_i);
554       s->prod_g_i_b_i = tmp;
555       tmp = GNUNET_CRYPTO_ecc_add (edc,
556                                    s->prod_h_i_b_i,
557                                    h_i_b_i);
558       gcry_mpi_point_release (s->prod_h_i_b_i);
559       gcry_mpi_point_release (h_i_b_i);
560       s->prod_h_i_b_i = tmp;
561     }
562   }
563   s->cadet_received_element_count += contained_elements;
564   if ((s->cadet_received_element_count == max) &&
565       (NULL == s->intersection_op))
566   {
567     /* intersection has finished also on our side, and
568        we got the full set, so we can proceed with the
569        CADET response(s) */
570     transmit_bobs_cryptodata_message (s);
571   }
572   GNUNET_CADET_receive_done (s->channel);
573 }
574
575
576 /**
577  * Callback for set operation results. Called for each element
578  * that needs to be removed from the result set.
579  *
580  * @param cls closure with the `struct BobServiceSession`
581  * @param element a result element, only valid if status is #GNUNET_SET_STATUS_OK
582  * @param current_size current set size
583  * @param status what has happened with the set intersection?
584  */
585 static void
586 cb_intersection_element_removed (void *cls,
587                                  const struct GNUNET_SET_Element *element,
588                                  uint64_t current_size,
589                                  enum GNUNET_SET_Status status)
590 {
591   struct BobServiceSession *s = cls;
592   struct GNUNET_SCALARPRODUCT_Element *se;
593
594   switch (status)
595   {
596   case GNUNET_SET_STATUS_OK:
597     /* this element has been removed from the set */
598     se = GNUNET_CONTAINER_multihashmap_get (s->intersected_elements,
599                                             element->data);
600     GNUNET_assert (NULL != se);
601     LOG (GNUNET_ERROR_TYPE_DEBUG,
602          "Removed element with key %s and value %lld\n",
603          GNUNET_h2s (&se->key),
604          (long long) GNUNET_ntohll (se->value));
605     GNUNET_assert (GNUNET_YES ==
606                    GNUNET_CONTAINER_multihashmap_remove (
607                      s->intersected_elements,
608                      element->data,
609                      se));
610     GNUNET_free (se);
611     return;
612
613   case GNUNET_SET_STATUS_DONE:
614     s->intersection_op = NULL;
615     GNUNET_break (NULL == s->intersection_set);
616     GNUNET_CADET_receive_done (s->channel);
617     LOG (GNUNET_ERROR_TYPE_DEBUG,
618          "Finished intersection, %d items remain\n",
619          GNUNET_CONTAINER_multihashmap_size (s->intersected_elements));
620     if (s->client_received_element_count ==
621         GNUNET_CONTAINER_multihashmap_size (s->intersected_elements))
622     {
623       /* CADET transmission from Alice is also already done,
624          start with our own reply */
625       transmit_bobs_cryptodata_message (s);
626     }
627     return;
628
629   case GNUNET_SET_STATUS_HALF_DONE:
630     /* unexpected for intersection */
631     GNUNET_break (0);
632     return;
633
634   case GNUNET_SET_STATUS_FAILURE:
635     /* unhandled status code */
636     LOG (GNUNET_ERROR_TYPE_DEBUG,
637          "Set intersection failed!\n");
638     s->intersection_op = NULL;
639     if (NULL != s->intersection_set)
640     {
641       GNUNET_SET_destroy (s->intersection_set);
642       s->intersection_set = NULL;
643     }
644     s->status = GNUNET_SCALARPRODUCT_STATUS_FAILURE;
645     prepare_client_end_notification (s);
646     return;
647
648   default:
649     GNUNET_break (0);
650     return;
651   }
652 }
653
654
655 /**
656  * We've paired up a client session with an incoming CADET request.
657  * Initiate set intersection work.
658  *
659  * @param s client session to start intersection for
660  */
661 static void
662 start_intersection (struct BobServiceSession *s)
663 {
664   struct GNUNET_HashCode set_sid;
665
666   GNUNET_CRYPTO_hash (&s->session_id,
667                       sizeof(struct GNUNET_HashCode),
668                       &set_sid);
669   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
670               "Got session with key %s and %u elements, starting intersection.\n",
671               GNUNET_h2s (&s->session_id),
672               (unsigned int) s->total);
673
674   s->intersection_op
675     = GNUNET_SET_prepare (&s->peer,
676                           &set_sid,
677                           NULL,
678                           GNUNET_SET_RESULT_REMOVED,
679                           (struct GNUNET_SET_Option[]) { { 0 } },
680                           &cb_intersection_element_removed,
681                           s);
682   if (GNUNET_OK !=
683       GNUNET_SET_commit (s->intersection_op,
684                          s->intersection_set))
685   {
686     GNUNET_break (0);
687     s->status = GNUNET_SCALARPRODUCT_STATUS_FAILURE;
688     prepare_client_end_notification (s);
689     return;
690   }
691   GNUNET_SET_destroy (s->intersection_set);
692   s->intersection_set = NULL;
693 }
694
695
696 /**
697  * Handle a request from Alice to calculate a scalarproduct with us (Bob).
698  *
699  * @param cls closure (set from #GNUNET_CADET_connect)
700  * @param msg the actual message
701  */
702 static void
703 handle_alices_computation_request (void *cls,
704                                    const struct EccServiceRequestMessage *msg)
705 {
706   struct BobServiceSession *s = cls;
707
708   s->session_id = msg->session_id; // ??
709   if (s->client_received_element_count < s->total)
710   {
711     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
712                 "Alice ready, still waiting for Bob client data!\n");
713     return;
714   }
715   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
716               "Both ready, launching intersection!\n");
717   start_intersection (s);
718 }
719
720
721 /**
722  * Function called for inbound channels on Bob's end.  Does some
723  * preliminary initialization, more happens after we get Alice's first
724  * message.
725  *
726  * @param cls our `struct BobServiceSession`
727  * @param channel new handle to the channel
728  * @param initiator peer that started the channel
729  * @return session associated with the channel
730  */
731 static void *
732 cb_channel_incoming (void *cls,
733                      struct GNUNET_CADET_Channel *channel,
734                      const struct GNUNET_PeerIdentity *initiator)
735 {
736   struct BobServiceSession *s = cls;
737
738   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
739               "New incoming channel from peer %s.\n",
740               GNUNET_i2s (initiator));
741   GNUNET_CADET_close_port (s->port);
742   s->port = NULL;
743   s->peer = *initiator;
744   s->channel = channel;
745   s->cadet_mq = GNUNET_CADET_get_mq (s->channel);
746   return s;
747 }
748
749
750 /**
751  * We're receiving additional set data. Check it is well-formed.
752  *
753  * @param cls identification of the client
754  * @param msg the actual message
755  * @return #GNUNET_OK if @a msg is well-formed
756  */
757 static int
758 check_bob_client_message_multipart (void *cls,
759                                     const struct
760                                     ComputationBobCryptodataMultipartMessage *
761                                     msg)
762 {
763   struct BobServiceSession *s = cls;
764   uint32_t contained_count;
765   uint16_t msize;
766
767   msize = ntohs (msg->header.size);
768   contained_count = ntohl (msg->element_count_contained);
769   if ((msize != (sizeof(struct ComputationBobCryptodataMultipartMessage)
770                  + contained_count * sizeof(struct
771                                             GNUNET_SCALARPRODUCT_Element))) ||
772       (0 == contained_count) ||
773       (UINT16_MAX < contained_count) ||
774       (s->total == s->client_received_element_count) ||
775       (s->total < s->client_received_element_count + contained_count))
776   {
777     GNUNET_break (0);
778     return GNUNET_SYSERR;
779   }
780   return GNUNET_OK;
781 }
782
783
784 /**
785  * We're receiving additional set data. Add it to our
786  * set and if we are done, initiate the transaction.
787  *
788  * @param cls identification of the client
789  * @param msg the actual message
790  */
791 static void
792 handle_bob_client_message_multipart (void *cls,
793                                      const struct
794                                      ComputationBobCryptodataMultipartMessage *
795                                      msg)
796 {
797   struct BobServiceSession *s = cls;
798   uint32_t contained_count;
799   const struct GNUNET_SCALARPRODUCT_Element *elements;
800   struct GNUNET_SET_Element set_elem;
801   struct GNUNET_SCALARPRODUCT_Element *elem;
802
803   contained_count = ntohl (msg->element_count_contained);
804   elements = (const struct GNUNET_SCALARPRODUCT_Element *) &msg[1];
805   for (uint32_t i = 0; i < contained_count; i++)
806   {
807     elem = GNUNET_new (struct GNUNET_SCALARPRODUCT_Element);
808     GNUNET_memcpy (elem,
809                    &elements[i],
810                    sizeof(struct GNUNET_SCALARPRODUCT_Element));
811     if (GNUNET_SYSERR ==
812         GNUNET_CONTAINER_multihashmap_put (s->intersected_elements,
813                                            &elem->key,
814                                            elem,
815                                            GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY))
816     {
817       GNUNET_break (0);
818       GNUNET_free (elem);
819       continue;
820     }
821     set_elem.data = &elem->key;
822     set_elem.size = sizeof(elem->key);
823     set_elem.element_type = 0;
824     GNUNET_SET_add_element (s->intersection_set,
825                             &set_elem,
826                             NULL, NULL);
827   }
828   s->client_received_element_count += contained_count;
829   GNUNET_SERVICE_client_continue (s->client);
830   if (s->total != s->client_received_element_count)
831   {
832     /* more to come */
833     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
834                 "Request still partial, waiting for more client data!\n");
835     return;
836   }
837   if (NULL == s->channel)
838   {
839     /* no Alice waiting for this request, wait for Alice */
840     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
841                 "Client ready, still waiting for Alice!\n");
842     return;
843   }
844   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
845               "Both ready, launching intersection!\n");
846   start_intersection (s);
847 }
848
849
850 /**
851  * Handler for Bob's a client request message.  Check @a msg is
852  * well-formed.
853  *
854  * @param cls identification of the client
855  * @param msg the actual message
856  * @return #GNUNET_OK if @a msg is well-formed
857  */
858 static int
859 check_bob_client_message (void *cls,
860                           const struct BobComputationMessage *msg)
861 {
862   struct BobServiceSession *s = cls;
863   uint32_t contained_count;
864   uint32_t total_count;
865   uint16_t msize;
866
867   if (GNUNET_SCALARPRODUCT_STATUS_INIT != s->status)
868   {
869     GNUNET_break (0);
870     return GNUNET_SYSERR;
871   }
872   msize = ntohs (msg->header.size);
873   total_count = ntohl (msg->element_count_total);
874   contained_count = ntohl (msg->element_count_contained);
875   if ((0 == total_count) ||
876       (0 == contained_count) ||
877       (UINT16_MAX < contained_count) ||
878       (msize != (sizeof(struct BobComputationMessage)
879                  + contained_count * sizeof(struct
880                                             GNUNET_SCALARPRODUCT_Element))))
881   {
882     GNUNET_break_op (0);
883     return GNUNET_SYSERR;
884   }
885   return GNUNET_OK;
886 }
887
888
889 /**
890  * Handler for Bob's a client request message.  Bob is in the response
891  * role, keep the values + session and waiting for a matching session
892  * or process a waiting request from Alice.
893  *
894  * @param cls identification of the client
895  * @param msg the actual message
896  */
897 static void
898 handle_bob_client_message (void *cls,
899                            const struct BobComputationMessage *msg)
900 {
901   struct BobServiceSession *s = cls;
902   struct GNUNET_MQ_MessageHandler cadet_handlers[] = {
903     GNUNET_MQ_hd_fixed_size (alices_computation_request,
904                              GNUNET_MESSAGE_TYPE_SCALARPRODUCT_ECC_SESSION_INITIALIZATION,
905                              struct EccServiceRequestMessage,
906                              s),
907     GNUNET_MQ_hd_var_size (alices_cryptodata_message,
908                            GNUNET_MESSAGE_TYPE_SCALARPRODUCT_ECC_ALICE_CRYPTODATA,
909                            struct EccAliceCryptodataMessage,
910                            s),
911     GNUNET_MQ_handler_end ()
912   };
913   uint32_t contained_count;
914   uint32_t total_count;
915   const struct GNUNET_SCALARPRODUCT_Element *elements;
916   struct GNUNET_SET_Element set_elem;
917   struct GNUNET_SCALARPRODUCT_Element *elem;
918
919   total_count = ntohl (msg->element_count_total);
920   contained_count = ntohl (msg->element_count_contained);
921
922   s->status = GNUNET_SCALARPRODUCT_STATUS_ACTIVE;
923   s->total = total_count;
924   s->client_received_element_count = contained_count;
925   s->session_id = msg->session_key;
926   elements = (const struct GNUNET_SCALARPRODUCT_Element *) &msg[1];
927   s->intersected_elements
928     = GNUNET_CONTAINER_multihashmap_create (s->total,
929                                             GNUNET_YES);
930   s->intersection_set
931     = GNUNET_SET_create (cfg,
932                          GNUNET_SET_OPERATION_INTERSECTION);
933   for (uint32_t i = 0; i < contained_count; i++)
934   {
935     if (0 == GNUNET_ntohll (elements[i].value))
936       continue;
937     elem = GNUNET_new (struct GNUNET_SCALARPRODUCT_Element);
938     GNUNET_memcpy (elem,
939                    &elements[i],
940                    sizeof(struct GNUNET_SCALARPRODUCT_Element));
941     if (GNUNET_SYSERR ==
942         GNUNET_CONTAINER_multihashmap_put (s->intersected_elements,
943                                            &elem->key,
944                                            elem,
945                                            GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY))
946     {
947       GNUNET_break (0);
948       GNUNET_free (elem);
949       continue;
950     }
951     set_elem.data = &elem->key;
952     set_elem.size = sizeof(elem->key);
953     set_elem.element_type = 0;
954     GNUNET_SET_add_element (s->intersection_set,
955                             &set_elem,
956                             NULL, NULL);
957     s->used_element_count++;
958   }
959   GNUNET_SERVICE_client_continue (s->client);
960   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
961               "Received client request, opening port %s!\n",
962               GNUNET_h2s (&msg->session_key));
963   s->port = GNUNET_CADET_open_port (my_cadet,
964                                     &msg->session_key,
965                                     &cb_channel_incoming,
966                                     s,
967                                     NULL,
968                                     &cb_channel_destruction,
969                                     cadet_handlers);
970   if (NULL == s->port)
971   {
972     GNUNET_break (0);
973     GNUNET_SERVICE_client_drop (s->client);
974     return;
975   }
976 }
977
978
979 /**
980  * Task run during shutdown.
981  *
982  * @param cls unused
983  */
984 static void
985 shutdown_task (void *cls)
986 {
987   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
988               "Shutting down, initiating cleanup.\n");
989   // FIXME: we have to cut our connections to CADET first!
990   if (NULL != my_cadet)
991   {
992     GNUNET_CADET_disconnect (my_cadet);
993     my_cadet = NULL;
994   }
995   if (NULL != edc)
996   {
997     GNUNET_CRYPTO_ecc_dlog_release (edc);
998     edc = NULL;
999   }
1000 }
1001
1002
1003 /**
1004  * A client connected.
1005  *
1006  * Setup the associated data structure.
1007  *
1008  * @param cls closure, NULL
1009  * @param client identification of the client
1010  * @param mq message queue to communicate with @a client
1011  * @return our `struct BobServiceSession`
1012  */
1013 static void *
1014 client_connect_cb (void *cls,
1015                    struct GNUNET_SERVICE_Client *client,
1016                    struct GNUNET_MQ_Handle *mq)
1017 {
1018   struct BobServiceSession *s;
1019
1020   s = GNUNET_new (struct BobServiceSession);
1021   s->client = client;
1022   s->client_mq = mq;
1023   return s;
1024 }
1025
1026
1027 /**
1028  * A client disconnected.
1029  *
1030  * Remove the associated session(s), release data structures
1031  * and cancel pending outgoing transmissions to the client.
1032  *
1033  * @param cls closure, NULL
1034  * @param client identification of the client
1035  * @param app_cls our `struct BobServiceSession`
1036  */
1037 static void
1038 client_disconnect_cb (void *cls,
1039                       struct GNUNET_SERVICE_Client *client,
1040                       void *app_cls)
1041 {
1042   struct BobServiceSession *s = app_cls;
1043
1044   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1045               "Client disconnected from us.\n");
1046   s->client = NULL;
1047   destroy_service_session (s);
1048 }
1049
1050
1051 /**
1052  * Initialization of the program and message handlers
1053  *
1054  * @param cls closure
1055  * @param c configuration to use
1056  * @param service the initialized service
1057  */
1058 static void
1059 run (void *cls,
1060      const struct GNUNET_CONFIGURATION_Handle *c,
1061      struct GNUNET_SERVICE_Handle *service)
1062 {
1063   cfg = c;
1064   /* We don't really do DLOG, so we can setup with very minimal resources */
1065   edc = GNUNET_CRYPTO_ecc_dlog_prepare (4 /* max value */,
1066                                         2 /* RAM */);
1067   my_cadet = GNUNET_CADET_connect (cfg);
1068   GNUNET_SCHEDULER_add_shutdown (&shutdown_task,
1069                                  NULL);
1070   if (NULL == my_cadet)
1071   {
1072     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1073                 _ ("Connect to CADET failed\n"));
1074     GNUNET_SCHEDULER_shutdown ();
1075     return;
1076   }
1077 }
1078
1079
1080 /**
1081  * Define "main" method using service macro.
1082  */
1083 GNUNET_SERVICE_MAIN
1084   ("scalarproduct-bob",
1085   GNUNET_SERVICE_OPTION_NONE,
1086   &run,
1087   &client_connect_cb,
1088   &client_disconnect_cb,
1089   NULL,
1090   GNUNET_MQ_hd_var_size (bob_client_message,
1091                          GNUNET_MESSAGE_TYPE_SCALARPRODUCT_CLIENT_TO_BOB,
1092                          struct BobComputationMessage,
1093                          NULL),
1094   GNUNET_MQ_hd_var_size (bob_client_message_multipart,
1095                          GNUNET_MESSAGE_TYPE_SCALARPRODUCT_CLIENT_MULTIPART_BOB,
1096                          struct ComputationBobCryptodataMultipartMessage,
1097                          NULL),
1098   GNUNET_MQ_handler_end ());
1099
1100
1101 /* end of gnunet-service-scalarproduct-ecc_bob.c */