include set size in result callback, needed by consensus
[oweals/gnunet.git] / src / scalarproduct / gnunet-service-scalarproduct_alice.c
1 /*
2      This file is part of GNUnet.
3      Copyright (C) 2013, 2014, 2017 GNUnet e.V.
4
5      GNUnet is free software; you can redistribute it and/or modify
6      it under the terms of the GNU General Public License as published
7      by the Free Software Foundation; either version 3, or (at your
8      option) any later version.
9
10      GNUnet is distributed in the hope that it will be useful, but
11      WITHOUT ANY WARRANTY; without even the implied warranty of
12      MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13      General Public License for more details.
14
15      You should have received a copy of the GNU General Public License
16      along with GNUnet; see the file COPYING.  If not, write to the
17      Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
18      Boston, MA 02110-1301, USA.
19  */
20 /**
21  * @file scalarproduct/gnunet-service-scalarproduct_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.h"
38
39 #define LOG(kind,...) GNUNET_log_from (kind, "scalarproduct-alice", __VA_ARGS__)
40
41 /**
42  * An encrypted element key-value pair.
43  */
44 struct MpiElement
45 {
46   /**
47    * Key used to identify matching pairs of values to multiply.
48    * Points into an existing data structure, to avoid copying
49    * and doubling memory use.
50    */
51   const struct GNUNET_HashCode *key;
52
53   /**
54    * Value represented (a).
55    */
56   gcry_mpi_t value;
57 };
58
59
60 /**
61  * A scalarproduct session which tracks
62  * a request form the client to our final response.
63  */
64 struct AliceServiceSession
65 {
66
67   /**
68    * (hopefully) unique transaction ID
69    */
70   struct GNUNET_HashCode session_id;
71
72   /**
73    * Alice or Bob's peerID
74    */
75   struct GNUNET_PeerIdentity peer;
76
77   /**
78    * The client this request is related to.
79    */
80   struct GNUNET_SERVICE_Client *client;
81
82   /**
83    * The message queue for the client.
84    */
85   struct GNUNET_MQ_Handle *client_mq;
86
87   /**
88    * The message queue for CADET.
89    */
90   struct GNUNET_MQ_Handle *cadet_mq;
91
92   /**
93    * all non-0-value'd elements transmitted to us.
94    * Values are of type `struct GNUNET_SCALARPRODUCT_Element *`
95    */
96   struct GNUNET_CONTAINER_MultiHashMap *intersected_elements;
97
98   /**
99    * Set of elements for which will conduction an intersection.
100    * the resulting elements are then used for computing the scalar product.
101    */
102   struct GNUNET_SET_Handle *intersection_set;
103
104   /**
105    * Set of elements for which will conduction an intersection.
106    * the resulting elements are then used for computing the scalar product.
107    */
108   struct GNUNET_SET_OperationHandle *intersection_op;
109
110   /**
111    * Handle to Alice's Intersection operation listening for Bob
112    */
113   struct GNUNET_SET_ListenHandle *intersection_listen;
114
115   /**
116    * channel-handle associated with our cadet handle
117    */
118   struct GNUNET_CADET_Channel *channel;
119
120   /**
121    * a(Alice), sorted array by key of length @e used_element_count.
122    */
123   struct MpiElement *sorted_elements;
124
125   /**
126    * Bob's permutation p of R
127    */
128   struct GNUNET_CRYPTO_PaillierCiphertext *r;
129
130   /**
131    * Bob's permutation q of R
132    */
133   struct GNUNET_CRYPTO_PaillierCiphertext *r_prime;
134
135   /**
136    * Bob's "s"
137    */
138   struct GNUNET_CRYPTO_PaillierCiphertext s;
139
140   /**
141    * Bob's "s'"
142    */
143   struct GNUNET_CRYPTO_PaillierCiphertext s_prime;
144
145   /**
146    * The computed scalar
147    */
148   gcry_mpi_t product;
149
150   /**
151    * How many elements we were supplied with from the client (total
152    * count before intersection).
153    */
154   uint32_t total;
155
156   /**
157    * How many elements actually are used for the scalar product.
158    * Size of the arrays in @e r and @e r_prime.  Sometimes also
159    * reset to 0 and used as a counter!
160    */
161   uint32_t used_element_count;
162
163   /**
164    * Already transferred elements from client to us.
165    * Less or equal than @e total.
166    */
167   uint32_t client_received_element_count;
168
169   /**
170    * Already transferred elements from Bob to us.
171    * Less or equal than @e total.
172    */
173   uint32_t cadet_received_element_count;
174
175   /**
176    * State of this session.   In
177    * #GNUNET_SCALARPRODUCT_STATUS_ACTIVE while operation is
178    * ongoing, afterwards in #GNUNET_SCALARPRODUCT_STATUS_SUCCESS or
179    * #GNUNET_SCALARPRODUCT_STATUS_FAILURE.
180    */
181   enum GNUNET_SCALARPRODUCT_ResponseStatus status;
182
183   /**
184    * Flag to prevent recursive calls to #destroy_service_session() from
185    * doing harm.
186    */
187   int in_destroy;
188
189 };
190
191
192 /**
193  * GNUnet configuration handle
194  */
195 static const struct GNUNET_CONFIGURATION_Handle *cfg;
196
197 /**
198  * Service's own public key
199  */
200 static struct GNUNET_CRYPTO_PaillierPublicKey my_pubkey;
201
202 /**
203  * Service's own private key
204  */
205 static struct GNUNET_CRYPTO_PaillierPrivateKey my_privkey;
206
207 /**
208  * Service's offset for values that could possibly be negative but are plaintext for encryption.
209  */
210 static gcry_mpi_t my_offset;
211
212 /**
213  * Handle to the CADET service.
214  */
215 static struct GNUNET_CADET_Handle *my_cadet;
216
217
218 /**
219  * Iterator called to free elements.
220  *
221  * @param cls the `struct AliceServiceSession *` (unused)
222  * @param key the key (unused)
223  * @param value value to free
224  * @return #GNUNET_OK (continue to iterate)
225  */
226 static int
227 free_element_cb (void *cls,
228                  const struct GNUNET_HashCode *key,
229                  void *value)
230 {
231   struct GNUNET_SCALARPRODUCT_Element *e = value;
232
233   GNUNET_free (e);
234   return GNUNET_OK;
235 }
236
237
238 /**
239  * Destroy session state, we are done with it.
240  *
241  * @param s the session to free elements from
242  */
243 static void
244 destroy_service_session (struct AliceServiceSession *s)
245 {
246   unsigned int i;
247
248   if (GNUNET_YES == s->in_destroy)
249     return;
250   s->in_destroy = GNUNET_YES;
251   if (NULL != s->client)
252   {
253     struct GNUNET_SERVICE_Client *c = s->client;
254
255     s->client = NULL;
256     GNUNET_SERVICE_client_drop (c);
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->r)
294   {
295     GNUNET_free (s->r);
296     s->r = NULL;
297   }
298   if (NULL != s->r_prime)
299   {
300     GNUNET_free (s->r_prime);
301     s->r_prime = NULL;
302   }
303   if (NULL != s->product)
304   {
305     gcry_mpi_release (s->product);
306     s->product = NULL;
307   }
308   GNUNET_free (s);
309 }
310
311
312 /**
313  * Notify the client that the session has failed.  A message gets sent
314  * to Alice's client if we encountered any error.
315  *
316  * @param session the associated client session to fail or succeed
317  */
318 static void
319 prepare_client_end_notification (struct AliceServiceSession *session)
320 {
321   struct ClientResponseMessage *msg;
322   struct GNUNET_MQ_Envelope *e;
323
324   if (NULL == session->client_mq)
325     return; /* no client left to be notified */
326   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
327               "Sending session-end notification with status %d to client for session %s\n",
328               session->status,
329               GNUNET_h2s (&session->session_id));
330   e = GNUNET_MQ_msg (msg,
331                      GNUNET_MESSAGE_TYPE_SCALARPRODUCT_RESULT);
332   msg->product_length = htonl (0);
333   msg->status = htonl (session->status);
334   GNUNET_MQ_send (session->client_mq,
335                   e);
336 }
337
338
339 /**
340  * Prepare the final (positive) response we will send to Alice's
341  * client.
342  *
343  * @param s the session associated with our client.
344  */
345 static void
346 transmit_client_response (struct AliceServiceSession *s)
347 {
348   struct ClientResponseMessage *msg;
349   struct GNUNET_MQ_Envelope *e;
350   unsigned char *product_exported = NULL;
351   size_t product_length = 0;
352   int32_t range;
353   gcry_error_t rc;
354   int sign;
355   gcry_mpi_t value;
356
357   if (NULL == s->product)
358   {
359     GNUNET_break (0);
360     prepare_client_end_notification (s);
361     return;
362   }
363   value = gcry_mpi_new (0);
364   sign = gcry_mpi_cmp_ui (s->product, 0);
365   if (0 > sign)
366   {
367     range = -1;
368     gcry_mpi_sub (value,
369                   value,
370                   s->product);
371   }
372   else if (0 < sign)
373   {
374     range = 1;
375     gcry_mpi_add (value, value, s->product);
376   }
377   else
378   {
379     /* result is exactly zero */
380     range = 0;
381   }
382   gcry_mpi_release (s->product);
383   s->product = NULL;
384
385   if ( (0 != range) &&
386        (0 != (rc = gcry_mpi_aprint (GCRYMPI_FMT_STD,
387                                     &product_exported,
388                                     &product_length,
389                                     value))))
390   {
391     LOG_GCRY (GNUNET_ERROR_TYPE_ERROR,
392               "gcry_mpi_scan",
393               rc);
394     prepare_client_end_notification (s);
395     return;
396   }
397   gcry_mpi_release (value);
398   e = GNUNET_MQ_msg_extra (msg,
399                            product_length,
400                            GNUNET_MESSAGE_TYPE_SCALARPRODUCT_RESULT);
401   msg->status = htonl (GNUNET_SCALARPRODUCT_STATUS_SUCCESS);
402   msg->range = htonl (range);
403   msg->product_length = htonl (product_length);
404   if (NULL != product_exported)
405   {
406     GNUNET_memcpy (&msg[1],
407             product_exported,
408             product_length);
409     GNUNET_free (product_exported);
410   }
411   GNUNET_MQ_send (s->client_mq,
412                   e);
413   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
414               "Sent result to client, session %s has ended!\n",
415               GNUNET_h2s (&s->session_id));
416 }
417
418
419
420 /**
421  * Function called whenever a channel is destroyed.  Should clean up
422  * any associated state.
423  *
424  * It must NOT call #GNUNET_CADET_channel_destroy() on the channel.
425  *
426  * @param cls our `struct AliceServiceSession`
427  * @param channel connection to the other end (henceforth invalid)
428  */
429 static void
430 cb_channel_destruction (void *cls,
431                         const struct GNUNET_CADET_Channel *channel)
432 {
433   struct AliceServiceSession *s = cls;
434
435   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
436               "Peer disconnected, terminating session %s with peer %s\n",
437               GNUNET_h2s (&s->session_id),
438               GNUNET_i2s (&s->peer));
439   if (GNUNET_SCALARPRODUCT_STATUS_ACTIVE == s->status)
440   {
441     /* We didn't get an answer yet, fail with error */
442     s->status = GNUNET_SCALARPRODUCT_STATUS_FAILURE;
443     prepare_client_end_notification (s);
444   }
445   s->channel = NULL;
446 }
447
448
449 /**
450  * Computes the square sum over a vector of a given length.
451  *
452  * @param vector the vector to compute over
453  * @param length the length of the vector
454  * @return an MPI value containing the calculated sum, never NULL
455  */
456 static gcry_mpi_t
457 compute_square_sum_mpi_elements (const struct MpiElement *vector,
458                                  uint32_t length)
459 {
460   gcry_mpi_t elem;
461   gcry_mpi_t sum;
462   uint32_t i;
463
464   GNUNET_assert (NULL != (sum = gcry_mpi_new (0)));
465   GNUNET_assert (NULL != (elem = gcry_mpi_new (0)));
466   for (i = 0; i < length; i++)
467   {
468     gcry_mpi_mul (elem, vector[i].value, vector[i].value);
469     gcry_mpi_add (sum, sum, elem);
470   }
471   gcry_mpi_release (elem);
472   return sum;
473 }
474
475
476 /**
477  * Computes the square sum over a vector of a given length.
478  *
479  * @param vector the vector to compute over
480  * @param length the length of the vector
481  * @return an MPI value containing the calculated sum, never NULL
482  */
483 static gcry_mpi_t
484 compute_square_sum (const gcry_mpi_t *vector,
485                     uint32_t length)
486 {
487   gcry_mpi_t elem;
488   gcry_mpi_t sum;
489   uint32_t i;
490
491   GNUNET_assert (NULL != (sum = gcry_mpi_new (0)));
492   GNUNET_assert (NULL != (elem = gcry_mpi_new (0)));
493   for (i = 0; i < length; i++)
494   {
495     gcry_mpi_mul (elem, vector[i], vector[i]);
496     gcry_mpi_add (sum, sum, elem);
497   }
498   gcry_mpi_release (elem);
499   return sum;
500 }
501
502
503 /**
504  * Compute our scalar product, done by Alice
505  *
506  * @param session the session associated with this computation
507  * @return product as MPI, never NULL
508  */
509 static gcry_mpi_t
510 compute_scalar_product (struct AliceServiceSession *session)
511 {
512   uint32_t count;
513   gcry_mpi_t t;
514   gcry_mpi_t u;
515   gcry_mpi_t u_prime;
516   gcry_mpi_t p;
517   gcry_mpi_t p_prime;
518   gcry_mpi_t tmp;
519   gcry_mpi_t r[session->used_element_count];
520   gcry_mpi_t r_prime[session->used_element_count];
521   gcry_mpi_t s;
522   gcry_mpi_t s_prime;
523   unsigned int i;
524
525   count = session->used_element_count;
526   // due to the introduced static offset S, we now also have to remove this
527   // from the E(a_pi)(+)E(-b_pi-r_pi) and E(a_qi)(+)E(-r_qi) twice each,
528   // the result is E((S + a_pi) + (S -b_pi-r_pi)) and E(S + a_qi + S - r_qi)
529   for (i = 0; i < count; i++)
530   {
531     r[i] = gcry_mpi_new (0);
532     GNUNET_CRYPTO_paillier_decrypt (&my_privkey,
533                                     &my_pubkey,
534                                     &session->r[i],
535                                     r[i]);
536     gcry_mpi_sub (r[i],
537                   r[i],
538                   my_offset);
539     gcry_mpi_sub (r[i],
540                   r[i],
541                   my_offset);
542     r_prime[i] = gcry_mpi_new (0);
543     GNUNET_CRYPTO_paillier_decrypt (&my_privkey,
544                                     &my_pubkey,
545                                     &session->r_prime[i],
546                                     r_prime[i]);
547     gcry_mpi_sub (r_prime[i],
548                   r_prime[i],
549                   my_offset);
550     gcry_mpi_sub (r_prime[i],
551                   r_prime[i],
552                   my_offset);
553   }
554
555   // calculate t = sum(ai)
556   t = compute_square_sum_mpi_elements (session->sorted_elements,
557                                        count);
558   // calculate U
559   u = gcry_mpi_new (0);
560   tmp = compute_square_sum (r, count);
561   gcry_mpi_sub (u, u, tmp);
562   gcry_mpi_release (tmp);
563
564   //calculate U'
565   u_prime = gcry_mpi_new (0);
566   tmp = compute_square_sum (r_prime, count);
567   gcry_mpi_sub (u_prime, u_prime, tmp);
568
569   GNUNET_assert (p = gcry_mpi_new (0));
570   GNUNET_assert (p_prime = gcry_mpi_new (0));
571   GNUNET_assert (s = gcry_mpi_new (0));
572   GNUNET_assert (s_prime = gcry_mpi_new (0));
573
574   // compute P
575   GNUNET_CRYPTO_paillier_decrypt (&my_privkey,
576                                   &my_pubkey,
577                                   &session->s,
578                                   s);
579   GNUNET_CRYPTO_paillier_decrypt (&my_privkey,
580                                   &my_pubkey,
581                                   &session->s_prime,
582                                   s_prime);
583
584   // compute P
585   gcry_mpi_add (p, s, t);
586   gcry_mpi_add (p, p, u);
587
588   // compute P'
589   gcry_mpi_add (p_prime, s_prime, t);
590   gcry_mpi_add (p_prime, p_prime, u_prime);
591
592   gcry_mpi_release (t);
593   gcry_mpi_release (u);
594   gcry_mpi_release (u_prime);
595   gcry_mpi_release (s);
596   gcry_mpi_release (s_prime);
597
598   // compute product
599   gcry_mpi_sub (p, p, p_prime);
600   gcry_mpi_release (p_prime);
601   tmp = gcry_mpi_set_ui (tmp, 2);
602   gcry_mpi_div (p, NULL, p, tmp, 0);
603
604   gcry_mpi_release (tmp);
605   for (i = 0; i < count; i++)
606   {
607     gcry_mpi_release (session->sorted_elements[i].value);
608     gcry_mpi_release (r[i]);
609     gcry_mpi_release (r_prime[i]);
610   }
611   GNUNET_free (session->sorted_elements);
612   session->sorted_elements = NULL;
613   GNUNET_free (session->r);
614   session->r = NULL;
615   GNUNET_free (session->r_prime);
616   session->r_prime = NULL;
617
618   return p;
619 }
620
621
622 /**
623  * Check a multipart chunk of a response we got from another service
624  * we wanted to calculate a scalarproduct with.
625  *
626  * @param cls the `struct AliceServiceSession`
627  * @param msg the actual message
628  * @return #GNUNET_OK to keep the connection open,
629  *         #GNUNET_SYSERR to close it (signal serious error)
630  */
631 static int
632 check_bobs_cryptodata_multipart (void *cls,
633                                  const struct BobCryptodataMultipartMessage *msg)
634 {
635   struct AliceServiceSession *s = cls;
636   uint32_t contained;
637   size_t msg_size;
638   size_t required_size;
639
640   msg_size = ntohs (msg->header.size);
641   contained = ntohl (msg->contained_element_count);
642   required_size = sizeof (struct BobCryptodataMultipartMessage)
643     + 2 * contained * sizeof (struct GNUNET_CRYPTO_PaillierCiphertext);
644   if ( (required_size != msg_size) ||
645        (s->cadet_received_element_count + contained > s->used_element_count) )
646   {
647     GNUNET_break (0);
648     return GNUNET_SYSERR;
649   }
650   return GNUNET_OK;
651 }
652
653 /**
654  * Handle a multipart chunk of a response we got from another service
655  * we wanted to calculate a scalarproduct with.
656  *
657  * @param cls the `struct AliceServiceSession`
658  * @param msg the actual message
659  */
660 static void
661 handle_bobs_cryptodata_multipart (void *cls,
662                                   const struct BobCryptodataMultipartMessage *msg)
663 {
664   struct AliceServiceSession *s = cls;
665   const struct GNUNET_CRYPTO_PaillierCiphertext *payload;
666   size_t i;
667   uint32_t contained;
668
669   contained = ntohl (msg->contained_element_count);
670   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
671               "Received %u additional crypto values from Bob\n",
672               (unsigned int) contained);
673
674   payload = (const struct GNUNET_CRYPTO_PaillierCiphertext *) &msg[1];
675   /* Convert each k[][perm] to its MPI_value */
676   for (i = 0; i < contained; i++)
677   {
678     GNUNET_memcpy (&s->r[s->cadet_received_element_count + i],
679                    &payload[2 * i],
680                    sizeof (struct GNUNET_CRYPTO_PaillierCiphertext));
681     GNUNET_memcpy (&s->r_prime[s->cadet_received_element_count + i],
682                    &payload[2 * i],
683                    sizeof (struct GNUNET_CRYPTO_PaillierCiphertext));
684   }
685   s->cadet_received_element_count += contained;
686   GNUNET_CADET_receive_done (s->channel);
687   if (s->cadet_received_element_count != s->used_element_count)
688     return; /* more to come */
689
690   s->product = compute_scalar_product (s);
691   transmit_client_response (s);
692 }
693
694
695 /**
696  * Check a response we got from another service we wanted to
697  * calculate a scalarproduct with.
698  *
699  * @param cls our `struct AliceServiceSession`
700  * @param message the actual message
701  * @return #GNUNET_OK to keep the connection open,
702  *         #GNUNET_SYSERR to close it (we are done)
703  */
704 static int
705 check_bobs_cryptodata_message (void *cls,
706                                const struct BobCryptodataMessage *msg)
707 {
708   struct AliceServiceSession *s = cls;
709   uint32_t contained;
710   uint16_t msg_size;
711   size_t required_size;
712
713   msg_size = ntohs (msg->header.size);
714   contained = ntohl (msg->contained_element_count);
715   required_size = sizeof (struct BobCryptodataMessage)
716     + 2 * contained * sizeof (struct GNUNET_CRYPTO_PaillierCiphertext)
717     + 2 * sizeof (struct GNUNET_CRYPTO_PaillierCiphertext);
718   if ( (msg_size != required_size) ||
719        (contained > UINT16_MAX) ||
720        (s->used_element_count < contained) )
721   {
722     GNUNET_break_op (0);
723     return GNUNET_SYSERR;
724   }
725   if (NULL == s->sorted_elements)
726   {
727     /* we're not ready yet, how can Bob be? */
728     GNUNET_break_op (0);
729     return GNUNET_SYSERR;
730   }
731   if (s->total != s->client_received_element_count)
732   {
733     /* we're not ready yet, how can Bob be? */
734     GNUNET_break_op (0);
735     return GNUNET_SYSERR;
736   }
737   return GNUNET_OK;
738 }
739
740
741 /**
742  * Handle a response we got from another service we wanted to
743  * calculate a scalarproduct with.
744  *
745  * @param cls our `struct AliceServiceSession`
746  * @param msg the actual message
747  */
748 static void
749 handle_bobs_cryptodata_message (void *cls,
750                                 const struct BobCryptodataMessage *msg)
751 {
752   struct AliceServiceSession *s = cls;
753   const struct GNUNET_CRYPTO_PaillierCiphertext *payload;
754   uint32_t i;
755   uint32_t contained;
756
757   contained = ntohl (msg->contained_element_count);
758   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
759               "Received %u crypto values from Bob\n",
760               (unsigned int) contained);
761   payload = (const struct GNUNET_CRYPTO_PaillierCiphertext *) &msg[1];
762   GNUNET_memcpy (&s->s,
763                  &payload[0],
764                  sizeof (struct GNUNET_CRYPTO_PaillierCiphertext));
765   GNUNET_memcpy (&s->s_prime,
766                  &payload[1],
767                  sizeof (struct GNUNET_CRYPTO_PaillierCiphertext));
768   payload = &payload[2];
769
770   s->r = GNUNET_new_array (s->used_element_count,
771                            struct GNUNET_CRYPTO_PaillierCiphertext);
772   s->r_prime = GNUNET_new_array (s->used_element_count,
773                                  struct GNUNET_CRYPTO_PaillierCiphertext);
774   for (i = 0; i < contained; i++)
775   {
776     GNUNET_memcpy (&s->r[i],
777                    &payload[2 * i],
778                    sizeof (struct GNUNET_CRYPTO_PaillierCiphertext));
779     GNUNET_memcpy (&s->r_prime[i],
780                    &payload[2 * i + 1],
781                    sizeof (struct GNUNET_CRYPTO_PaillierCiphertext));
782   }
783   s->cadet_received_element_count = contained;
784   GNUNET_CADET_receive_done (s->channel);
785
786   if (s->cadet_received_element_count != s->used_element_count)
787   {
788     /* More to come */
789     return;
790   }
791   s->product = compute_scalar_product (s);
792   transmit_client_response (s);
793 }
794
795
796 /**
797  * Iterator to copy over messages from the hash map
798  * into an array for sorting.
799  *
800  * @param cls the `struct AliceServiceSession *`
801  * @param key the key (unused)
802  * @param value the `struct GNUNET_SCALARPRODUCT_Element *`
803  */
804 static int
805 copy_element_cb (void *cls,
806                  const struct GNUNET_HashCode *key,
807                  void *value)
808 {
809   struct AliceServiceSession *s = cls;
810   struct GNUNET_SCALARPRODUCT_Element *e = value;
811   gcry_mpi_t mval;
812   int64_t val;
813
814   mval = gcry_mpi_new (0);
815   val = (int64_t) GNUNET_ntohll (e->value);
816   if (0 > val)
817     gcry_mpi_sub_ui (mval, mval, -val);
818   else
819     gcry_mpi_add_ui (mval, mval, val);
820   s->sorted_elements [s->used_element_count].value = mval;
821   s->sorted_elements [s->used_element_count].key = &e->key;
822   s->used_element_count++;
823   return GNUNET_OK;
824 }
825
826
827 /**
828  * Compare two `struct MpiValue`s by key for sorting.
829  *
830  * @param a pointer to first `struct MpiValue *`
831  * @param b pointer to first `struct MpiValue *`
832  * @return -1 for a < b, 0 for a=b, 1 for a > b.
833  */
834 static int
835 element_cmp (const void *a,
836              const void *b)
837 {
838   const struct MpiElement *ma = a;
839   const struct MpiElement *mb = b;
840
841   return GNUNET_CRYPTO_hash_cmp (ma->key,
842                                  mb->key);
843 }
844
845
846 /**
847  * Maximum number of elements we can put into a single cryptodata
848  * message
849  */
850 #define ELEMENT_CAPACITY ((GNUNET_CONSTANTS_MAX_CADET_MESSAGE_SIZE - 1 - sizeof (struct AliceCryptodataMessage)) / sizeof (struct GNUNET_CRYPTO_PaillierCiphertext))
851
852
853 /**
854  * Send the cryptographic data from Alice to Bob.
855  * Does nothing if we already transferred all elements.
856  *
857  * @param s the associated service session
858  */
859 static void
860 send_alices_cryptodata_message (struct AliceServiceSession *s)
861 {
862   struct AliceCryptodataMessage *msg;
863   struct GNUNET_MQ_Envelope *e;
864   struct GNUNET_CRYPTO_PaillierCiphertext *payload;
865   unsigned int i;
866   uint32_t todo_count;
867   gcry_mpi_t a;
868   uint32_t off;
869
870   s->sorted_elements
871     = GNUNET_malloc (GNUNET_CONTAINER_multihashmap_size (s->intersected_elements) *
872                      sizeof (struct MpiElement));
873   s->used_element_count = 0;
874   GNUNET_CONTAINER_multihashmap_iterate (s->intersected_elements,
875                                          &copy_element_cb,
876                                          s);
877   LOG (GNUNET_ERROR_TYPE_DEBUG,
878        "Finished intersection, %d items remain\n",
879        s->used_element_count);
880   qsort (s->sorted_elements,
881          s->used_element_count,
882          sizeof (struct MpiElement),
883          &element_cmp);
884   off = 0;
885   while (off < s->used_element_count)
886   {
887     todo_count = s->used_element_count - off;
888     if (todo_count > ELEMENT_CAPACITY)
889       todo_count = ELEMENT_CAPACITY;
890     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
891                 "Sending %u/%u crypto values to Bob\n",
892                 (unsigned int) todo_count,
893                 (unsigned int) s->used_element_count);
894
895     e = GNUNET_MQ_msg_extra (msg,
896                              todo_count * sizeof (struct GNUNET_CRYPTO_PaillierCiphertext),
897                              GNUNET_MESSAGE_TYPE_SCALARPRODUCT_ALICE_CRYPTODATA);
898     msg->contained_element_count = htonl (todo_count);
899     payload = (struct GNUNET_CRYPTO_PaillierCiphertext *) &msg[1];
900     a = gcry_mpi_new (0);
901     for (i = off; i < off + todo_count; i++)
902     {
903       gcry_mpi_add (a,
904                     s->sorted_elements[i].value,
905                     my_offset);
906       GNUNET_assert (3 ==
907                      GNUNET_CRYPTO_paillier_encrypt (&my_pubkey,
908                                                      a,
909                                                      3,
910                                                      &payload[i - off]));
911     }
912     gcry_mpi_release (a);
913     off += todo_count;
914     GNUNET_MQ_send (s->cadet_mq,
915                     e);
916   }
917 }
918
919
920 /**
921  * Callback for set operation results. Called for each element
922  * that should be removed from the result set, and then once
923  * to indicate that the set intersection operation is done.
924  *
925  * @param cls closure with the `struct AliceServiceSession`
926  * @param element a result element, only valid if status is #GNUNET_SET_STATUS_OK
927  * @param current_size current set size
928  * @param status what has happened with the set intersection?
929  */
930 static void
931 cb_intersection_element_removed (void *cls,
932                                  const struct GNUNET_SET_Element *element,
933                                  uint64_t current_size,
934                                  enum GNUNET_SET_Status status)
935 {
936   struct AliceServiceSession *s = cls;
937   struct GNUNET_SCALARPRODUCT_Element *se;
938
939   switch (status)
940   {
941   case GNUNET_SET_STATUS_OK:
942     /* this element has been removed from the set */
943     se = GNUNET_CONTAINER_multihashmap_get (s->intersected_elements,
944                                             element->data);
945     GNUNET_assert (NULL != se);
946     LOG (GNUNET_ERROR_TYPE_DEBUG,
947          "Intersection removed element with key %s and value %lld\n",
948          GNUNET_h2s (&se->key),
949          (long long) GNUNET_ntohll (se->value));
950     GNUNET_assert (GNUNET_YES ==
951                    GNUNET_CONTAINER_multihashmap_remove (s->intersected_elements,
952                                                          element->data,
953                                                          se));
954     GNUNET_free (se);
955     return;
956   case GNUNET_SET_STATUS_DONE:
957     s->intersection_op = NULL;
958     if (NULL != s->intersection_set)
959     {
960       GNUNET_SET_destroy (s->intersection_set);
961       s->intersection_set = NULL;
962     }
963     send_alices_cryptodata_message (s);
964     return;
965   case GNUNET_SET_STATUS_HALF_DONE:
966     /* unexpected for intersection */
967     GNUNET_break (0);
968     return;
969   case GNUNET_SET_STATUS_FAILURE:
970     /* unhandled status code */
971     LOG (GNUNET_ERROR_TYPE_DEBUG,
972          "Set intersection failed!\n");
973     if (NULL != s->intersection_listen)
974     {
975       GNUNET_SET_listen_cancel (s->intersection_listen);
976       s->intersection_listen = NULL;
977     }
978     s->intersection_op = NULL;
979     if (NULL != s->intersection_set)
980     {
981       GNUNET_SET_destroy (s->intersection_set);
982       s->intersection_set = NULL;
983     }
984     s->status = GNUNET_SCALARPRODUCT_STATUS_FAILURE;
985     prepare_client_end_notification (s);
986     return;
987   default:
988     GNUNET_break (0);
989     return;
990   }
991 }
992
993
994 /**
995  * Called when another peer wants to do a set operation with the
996  * local peer. If a listen error occurs, the @a request is NULL.
997  *
998  * @param cls closure with the `struct AliceServiceSession *`
999  * @param other_peer the other peer
1000  * @param context_msg message with application specific information from
1001  *        the other peer
1002  * @param request request from the other peer (never NULL), use GNUNET_SET_accept()
1003  *        to accept it, otherwise the request will be refused
1004  *        Note that we can't just return value from the listen callback,
1005  *        as it is also necessary to specify the set we want to do the
1006  *        operation with, whith sometimes can be derived from the context
1007  *        message. It's necessary to specify the timeout.
1008  */
1009 static void
1010 cb_intersection_request_alice (void *cls,
1011                                const struct GNUNET_PeerIdentity *other_peer,
1012                                const struct GNUNET_MessageHeader *context_msg,
1013                                struct GNUNET_SET_Request *request)
1014 {
1015   struct AliceServiceSession *s = cls;
1016
1017   if (0 != memcmp (other_peer,
1018                    &s->peer,
1019                    sizeof (struct GNUNET_PeerIdentity)))
1020   {
1021     GNUNET_break_op (0);
1022     return;
1023   }
1024   s->intersection_op
1025     = GNUNET_SET_accept (request,
1026                          GNUNET_SET_RESULT_REMOVED,
1027                          (struct GNUNET_SET_Option[]) {{ 0 }},
1028                          &cb_intersection_element_removed,
1029                          s);
1030   if (NULL == s->intersection_op)
1031   {
1032     GNUNET_break (0);
1033     s->status = GNUNET_SCALARPRODUCT_STATUS_FAILURE;
1034     prepare_client_end_notification (s);
1035     return;
1036   }
1037   if (GNUNET_OK !=
1038       GNUNET_SET_commit (s->intersection_op,
1039                          s->intersection_set))
1040   {
1041     GNUNET_break (0);
1042     s->status = GNUNET_SCALARPRODUCT_STATUS_FAILURE;
1043     prepare_client_end_notification (s);
1044     return;
1045   }
1046   GNUNET_SET_destroy (s->intersection_set);
1047   s->intersection_set = NULL;
1048   GNUNET_SET_listen_cancel (s->intersection_listen);
1049   s->intersection_listen = NULL;
1050 }
1051
1052
1053 /**
1054  * Our client has finished sending us its multipart message.
1055  *
1056  * @param session the service session context
1057  */
1058 static void
1059 client_request_complete_alice (struct AliceServiceSession *s)
1060 {
1061   struct GNUNET_MQ_MessageHandler cadet_handlers[] = {
1062     GNUNET_MQ_hd_var_size (bobs_cryptodata_message,
1063                            GNUNET_MESSAGE_TYPE_SCALARPRODUCT_BOB_CRYPTODATA,
1064                            struct BobCryptodataMessage,
1065                            s),
1066     GNUNET_MQ_hd_var_size (bobs_cryptodata_multipart,
1067                            GNUNET_MESSAGE_TYPE_SCALARPRODUCT_BOB_CRYPTODATA_MULTIPART,
1068                            struct BobCryptodataMultipartMessage,
1069                            s),
1070     GNUNET_MQ_handler_end ()
1071   };
1072   struct ServiceRequestMessage *msg;
1073   struct GNUNET_MQ_Envelope *e;
1074
1075   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1076               "Creating new channel for session with key %s.\n",
1077               GNUNET_h2s (&s->session_id));
1078   s->channel
1079     = GNUNET_CADET_channel_creatE (my_cadet,
1080                                    s,
1081                                    &s->peer,
1082                                    &s->session_id,
1083                                    GNUNET_CADET_OPTION_RELIABLE,
1084                                    NULL,
1085                                    &cb_channel_destruction,
1086                                    cadet_handlers);
1087   if (NULL == s->channel)
1088   {
1089     s->status = GNUNET_SCALARPRODUCT_STATUS_FAILURE;
1090     prepare_client_end_notification (s);
1091     return;
1092   }
1093   s->cadet_mq = GNUNET_CADET_get_mq (s->channel);
1094   s->intersection_listen
1095     = GNUNET_SET_listen (cfg,
1096                          GNUNET_SET_OPERATION_INTERSECTION,
1097                          &s->session_id,
1098                          &cb_intersection_request_alice,
1099                          s);
1100   if (NULL == s->intersection_listen)
1101   {
1102     s->status = GNUNET_SCALARPRODUCT_STATUS_FAILURE;
1103     GNUNET_CADET_channel_destroy (s->channel);
1104     s->channel = NULL;
1105     prepare_client_end_notification (s);
1106     return;
1107   }
1108
1109   e = GNUNET_MQ_msg (msg,
1110                      GNUNET_MESSAGE_TYPE_SCALARPRODUCT_SESSION_INITIALIZATION);
1111   msg->session_id = s->session_id;
1112   msg->public_key = my_pubkey;
1113   GNUNET_MQ_send (s->cadet_mq,
1114                   e);
1115 }
1116
1117
1118 /**
1119  * We're receiving additional set data. Check if
1120  * @a msg is well-formed.
1121  *
1122  * @param cls client identification of the client
1123  * @param msg the actual message
1124  * @return #GNUNET_OK if @a msg is well-formed
1125  */
1126 static int
1127 check_alice_client_message_multipart (void *cls,
1128                                       const struct ComputationBobCryptodataMultipartMessage *msg)
1129 {
1130   struct AliceServiceSession *s = cls;
1131   uint32_t contained_count;
1132   uint16_t msize;
1133
1134   msize = ntohs (msg->header.size);
1135   contained_count = ntohl (msg->element_count_contained);
1136   if ( (msize != (sizeof (struct ComputationBobCryptodataMultipartMessage) +
1137                   contained_count * sizeof (struct GNUNET_SCALARPRODUCT_Element))) ||
1138        (0 == contained_count) ||
1139        (s->total == s->client_received_element_count) ||
1140        (s->total < s->client_received_element_count + contained_count) )
1141   {
1142     GNUNET_break_op (0);
1143     return GNUNET_SYSERR;
1144   }
1145   return GNUNET_OK;
1146 }
1147
1148
1149 /**
1150  * We're receiving additional set data. Add it to our
1151  * set and if we are done, initiate the transaction.
1152  *
1153  * @param cls client identification of the client
1154  * @param msg the actual message
1155  */
1156 static void
1157 handle_alice_client_message_multipart (void *cls,
1158                                        const struct ComputationBobCryptodataMultipartMessage *msg)
1159 {
1160   struct AliceServiceSession *s = cls;
1161   uint32_t contained_count;
1162   const struct GNUNET_SCALARPRODUCT_Element *elements;
1163   struct GNUNET_SET_Element set_elem;
1164   struct GNUNET_SCALARPRODUCT_Element *elem;
1165
1166   contained_count = ntohl (msg->element_count_contained);
1167   s->client_received_element_count += contained_count;
1168   elements = (const struct GNUNET_SCALARPRODUCT_Element *) &msg[1];
1169   for (uint32_t i = 0; i < contained_count; i++)
1170   {
1171     elem = GNUNET_new (struct GNUNET_SCALARPRODUCT_Element);
1172     GNUNET_memcpy (elem,
1173                    &elements[i],
1174                    sizeof (struct GNUNET_SCALARPRODUCT_Element));
1175     if (GNUNET_SYSERR ==
1176         GNUNET_CONTAINER_multihashmap_put (s->intersected_elements,
1177                                            &elem->key,
1178                                            elem,
1179                                            GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY))
1180     {
1181       GNUNET_break (0);
1182       GNUNET_free (elem);
1183       continue;
1184     }
1185     set_elem.data = &elem->key;
1186     set_elem.size = sizeof (elem->key);
1187     set_elem.element_type = 0;
1188     GNUNET_SET_add_element (s->intersection_set,
1189                             &set_elem,
1190                             NULL, NULL);
1191     s->used_element_count++;
1192   }
1193   GNUNET_SERVICE_client_continue (s->client);
1194   if (s->total != s->client_received_element_count)
1195   {
1196     /* more to come */
1197     return;
1198   }
1199   client_request_complete_alice (s);
1200 }
1201
1202
1203 /**
1204  * Handler for Alice's client request message.
1205  * Check that @a msg is well-formed.
1206  *
1207  * @param cls identification of the client
1208  * @param msg the actual message
1209  * @return #GNUNET_OK if @a msg is well-formed
1210  */
1211 static int
1212 check_alice_client_message (void *cls,
1213                             const struct AliceComputationMessage *msg)
1214 {
1215   struct AliceServiceSession *s = cls;
1216   uint16_t msize;
1217   uint32_t total_count;
1218   uint32_t contained_count;
1219
1220   if (NULL != s->intersected_elements)
1221   {
1222     /* only one concurrent session per client connection allowed,
1223        simplifies logic a lot... */
1224     GNUNET_break (0);
1225     return GNUNET_SYSERR;
1226   }
1227   msize = ntohs (msg->header.size);
1228   total_count = ntohl (msg->element_count_total);
1229   contained_count = ntohl (msg->element_count_contained);
1230   if ( (0 == total_count) ||
1231        (0 == contained_count) ||
1232        (msize != (sizeof (struct AliceComputationMessage) +
1233                   contained_count * sizeof (struct GNUNET_SCALARPRODUCT_Element))) )
1234   {
1235     GNUNET_break_op (0);
1236     return GNUNET_SYSERR;
1237   }
1238   return GNUNET_OK;
1239 }
1240
1241
1242 /**
1243  * Handler for Alice's client request message.
1244  * We are doing request-initiation to compute a scalar product with a peer.
1245  *
1246  * @param cls identification of the client
1247  * @param msg the actual message
1248  */
1249 static void
1250 handle_alice_client_message (void *cls,
1251                              const struct AliceComputationMessage *msg)
1252 {
1253   struct AliceServiceSession *s = cls;
1254   uint32_t contained_count;
1255   uint32_t total_count;
1256   const struct GNUNET_SCALARPRODUCT_Element *elements;
1257   struct GNUNET_SET_Element set_elem;
1258   struct GNUNET_SCALARPRODUCT_Element *elem;
1259
1260   total_count = ntohl (msg->element_count_total);
1261   contained_count = ntohl (msg->element_count_contained);
1262   s->peer = msg->peer;
1263   s->status = GNUNET_SCALARPRODUCT_STATUS_ACTIVE;
1264   s->total = total_count;
1265   s->client_received_element_count = contained_count;
1266   s->session_id = msg->session_key;
1267   elements = (const struct GNUNET_SCALARPRODUCT_Element *) &msg[1];
1268   s->intersected_elements = GNUNET_CONTAINER_multihashmap_create (s->total,
1269                                                                   GNUNET_YES);
1270   s->intersection_set = GNUNET_SET_create (cfg,
1271                                            GNUNET_SET_OPERATION_INTERSECTION);
1272
1273   for (uint32_t i = 0; i < contained_count; i++)
1274   {
1275     if (0 == GNUNET_ntohll (elements[i].value))
1276       continue;
1277     elem = GNUNET_new (struct GNUNET_SCALARPRODUCT_Element);
1278     GNUNET_memcpy (elem,
1279             &elements[i],
1280             sizeof (struct GNUNET_SCALARPRODUCT_Element));
1281     if (GNUNET_SYSERR ==
1282         GNUNET_CONTAINER_multihashmap_put (s->intersected_elements,
1283                                            &elem->key,
1284                                            elem,
1285                                            GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY))
1286     {
1287       /* element with same key encountered twice! */
1288       GNUNET_break (0);
1289       GNUNET_free (elem);
1290       continue;
1291     }
1292     set_elem.data = &elem->key;
1293     set_elem.size = sizeof (elem->key);
1294     set_elem.element_type = 0;
1295     GNUNET_SET_add_element (s->intersection_set,
1296                             &set_elem,
1297                             NULL, NULL);
1298     s->used_element_count++;
1299   }
1300   GNUNET_SERVICE_client_continue (s->client);
1301   if (s->total != s->client_received_element_count)
1302   {
1303     /* wait for multipart msg */
1304     return;
1305   }
1306   client_request_complete_alice (s);
1307 }
1308
1309
1310 /**
1311  * Task run during shutdown.
1312  *
1313  * @param cls unused
1314  */
1315 static void
1316 shutdown_task (void *cls)
1317 {
1318   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1319               "Shutting down, initiating cleanup.\n");
1320   // FIXME: we have to cut our connections to CADET first!
1321   if (NULL != my_cadet)
1322   {
1323     GNUNET_CADET_disconnect (my_cadet);
1324     my_cadet = NULL;
1325   }
1326 }
1327
1328
1329 /**
1330  * A client connected.
1331  *
1332  * Setup the associated data structure.
1333  *
1334  * @param cls closure, NULL
1335  * @param client identification of the client
1336  * @param mq message queue to communicate with @a client
1337  * @return our `struct AliceServiceSession`
1338  */
1339 static void *
1340 client_connect_cb (void *cls,
1341                    struct GNUNET_SERVICE_Client *client,
1342                    struct GNUNET_MQ_Handle *mq)
1343 {
1344   struct AliceServiceSession *s;
1345
1346   s = GNUNET_new (struct AliceServiceSession);
1347   s->client = client;
1348   s->client_mq = mq;
1349   return s;
1350 }
1351
1352
1353 /**
1354  * A client disconnected.
1355  *
1356  * Remove the associated session(s), release data structures
1357  * and cancel pending outgoing transmissions to the client.
1358  *
1359  * @param cls closure, NULL
1360  * @param client identification of the client
1361  * @param app_cls our `struct AliceServiceSession`
1362  */
1363 static void
1364 client_disconnect_cb (void *cls,
1365                       struct GNUNET_SERVICE_Client *client,
1366                       void *app_cls)
1367 {
1368   struct AliceServiceSession *s = app_cls;
1369
1370   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1371               "Client %p disconnected from us.\n",
1372               client);
1373   s->client = NULL;
1374   s->client_mq = NULL;
1375   destroy_service_session (s);
1376 }
1377
1378
1379 /**
1380  * Initialization of the program and message handlers
1381  *
1382  * @param cls closure
1383  * @param c configuration to use
1384  * @param service the initialized service
1385  */
1386 static void
1387 run (void *cls,
1388      const struct GNUNET_CONFIGURATION_Handle *c,
1389      struct GNUNET_SERVICE_Handle *service)
1390 {
1391   cfg = c;
1392   /*
1393     offset has to be sufficiently small to allow computation of:
1394     m1+m2 mod n == (S + a) + (S + b) mod n,
1395     if we have more complex operations, this factor needs to be lowered */
1396   my_offset = gcry_mpi_new (GNUNET_CRYPTO_PAILLIER_BITS / 3);
1397   gcry_mpi_set_bit (my_offset,
1398                     GNUNET_CRYPTO_PAILLIER_BITS / 3);
1399   GNUNET_CRYPTO_paillier_create (&my_pubkey,
1400                                  &my_privkey);
1401   my_cadet = GNUNET_CADET_connecT (cfg);
1402   GNUNET_SCHEDULER_add_shutdown (&shutdown_task,
1403                                  NULL);
1404   if (NULL == my_cadet)
1405   {
1406     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1407                 _("Connect to CADET failed\n"));
1408     GNUNET_SCHEDULER_shutdown ();
1409     return;
1410   }
1411 }
1412
1413
1414 /**
1415  * Define "main" method using service macro.
1416  */
1417 GNUNET_SERVICE_MAIN
1418 ("scalarproduct-alice",
1419  GNUNET_SERVICE_OPTION_NONE,
1420  &run,
1421  &client_connect_cb,
1422  &client_disconnect_cb,
1423  NULL,
1424  GNUNET_MQ_hd_var_size (alice_client_message,
1425                         GNUNET_MESSAGE_TYPE_SCALARPRODUCT_CLIENT_TO_ALICE,
1426                         struct AliceComputationMessage,
1427                         NULL),
1428  GNUNET_MQ_hd_var_size (alice_client_message_multipart,
1429                         GNUNET_MESSAGE_TYPE_SCALARPRODUCT_CLIENT_MULTIPART_ALICE,
1430                         struct ComputationBobCryptodataMultipartMessage,
1431                         NULL),
1432  GNUNET_MQ_handler_end ());
1433
1434
1435 /* end of gnunet-service-scalarproduct_alice.c */