- merge; service API change
[oweals/gnunet.git] / src / scalarproduct / gnunet-service-scalarproduct_alice.c
1 /*
2      This file is part of GNUnet.
3      Copyright (C) 2013, 2014 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->cadet_mq)
252   {
253     GNUNET_MQ_destroy (s->cadet_mq);
254     s->cadet_mq = NULL;
255   }
256   if (NULL != s->client)
257   {
258     struct GNUNET_SERVICE_Client *c = s->client;
259     
260     s->client = NULL;
261     GNUNET_SERVICE_client_drop (c);
262   }
263   if (NULL != s->channel)
264   {
265     GNUNET_CADET_channel_destroy (s->channel);
266     s->channel = NULL;
267   }
268   if (NULL != s->intersected_elements)
269   {
270     GNUNET_CONTAINER_multihashmap_iterate (s->intersected_elements,
271                                            &free_element_cb,
272                                            s);
273     GNUNET_CONTAINER_multihashmap_destroy (s->intersected_elements);
274     s->intersected_elements = NULL;
275   }
276   if (NULL != s->intersection_listen)
277   {
278     GNUNET_SET_listen_cancel (s->intersection_listen);
279     s->intersection_listen = NULL;
280   }
281   if (NULL != s->intersection_op)
282   {
283     GNUNET_SET_operation_cancel (s->intersection_op);
284     s->intersection_op = NULL;
285   }
286   if (NULL != s->intersection_set)
287   {
288     GNUNET_SET_destroy (s->intersection_set);
289     s->intersection_set = NULL;
290   }
291   if (NULL != s->sorted_elements)
292   {
293     for (i=0;i<s->used_element_count;i++)
294       gcry_mpi_release (s->sorted_elements[i].value);
295     GNUNET_free (s->sorted_elements);
296     s->sorted_elements = NULL;
297   }
298   if (NULL != s->r)
299   {
300     GNUNET_free (s->r);
301     s->r = NULL;
302   }
303   if (NULL != s->r_prime)
304   {
305     GNUNET_free (s->r_prime);
306     s->r_prime = NULL;
307   }
308   if (NULL != s->product)
309   {
310     gcry_mpi_release (s->product);
311     s->product = NULL;
312   }
313   GNUNET_free (s);
314 }
315
316
317 /**
318  * Notify the client that the session has failed.  A message gets sent
319  * to Alice's client if we encountered any error.
320  *
321  * @param session the associated client session to fail or succeed
322  */
323 static void
324 prepare_client_end_notification (struct AliceServiceSession *session)
325 {
326   struct ClientResponseMessage *msg;
327   struct GNUNET_MQ_Envelope *e;
328
329   if (NULL == session->client_mq)
330     return; /* no client left to be notified */
331   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
332               "Sending session-end notification with status %d to client for session %s\n",
333               session->status,
334               GNUNET_h2s (&session->session_id));
335   e = GNUNET_MQ_msg (msg,
336                      GNUNET_MESSAGE_TYPE_SCALARPRODUCT_RESULT);
337   msg->product_length = htonl (0);
338   msg->status = htonl (session->status);
339   GNUNET_MQ_send (session->client_mq,
340                   e);
341 }
342
343
344 /**
345  * Prepare the final (positive) response we will send to Alice's
346  * client.
347  *
348  * @param s the session associated with our client.
349  */
350 static void
351 transmit_client_response (struct AliceServiceSession *s)
352 {
353   struct ClientResponseMessage *msg;
354   struct GNUNET_MQ_Envelope *e;
355   unsigned char *product_exported = NULL;
356   size_t product_length = 0;
357   int32_t range;
358   gcry_error_t rc;
359   int sign;
360   gcry_mpi_t value;
361
362   if (NULL == s->product)
363   {
364     GNUNET_break (0);
365     prepare_client_end_notification (s);
366     return;
367   }
368   value = gcry_mpi_new (0);
369   sign = gcry_mpi_cmp_ui (s->product, 0);
370   if (0 > sign)
371   {
372     range = -1;
373     gcry_mpi_sub (value,
374                   value,
375                   s->product);
376   }
377   else if (0 < sign)
378   {
379     range = 1;
380     gcry_mpi_add (value, value, s->product);
381   }
382   else
383   {
384     /* result is exactly zero */
385     range = 0;
386   }
387   gcry_mpi_release (s->product);
388   s->product = NULL;
389
390   if ( (0 != range) &&
391        (0 != (rc = gcry_mpi_aprint (GCRYMPI_FMT_STD,
392                                     &product_exported,
393                                     &product_length,
394                                     value))))
395   {
396     LOG_GCRY (GNUNET_ERROR_TYPE_ERROR,
397               "gcry_mpi_scan",
398               rc);
399     prepare_client_end_notification (s);
400     return;
401   }
402   gcry_mpi_release (value);
403   e = GNUNET_MQ_msg_extra (msg,
404                            product_length,
405                            GNUNET_MESSAGE_TYPE_SCALARPRODUCT_RESULT);
406   msg->status = htonl (GNUNET_SCALARPRODUCT_STATUS_SUCCESS);
407   msg->range = htonl (range);
408   msg->product_length = htonl (product_length);
409   if (NULL != product_exported)
410   {
411     GNUNET_memcpy (&msg[1],
412             product_exported,
413             product_length);
414     GNUNET_free (product_exported);
415   }
416   GNUNET_MQ_send (s->client_mq,
417                   e);
418   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
419               "Sent result to client, session %s has ended!\n",
420               GNUNET_h2s (&s->session_id));
421 }
422
423
424
425 /**
426  * Function called whenever a channel is destroyed.  Should clean up
427  * any associated state.
428  *
429  * It must NOT call #GNUNET_CADET_channel_destroy() on the channel.
430  *
431  * @param cls closure (set from #GNUNET_CADET_connect())
432  * @param channel connection to the other end (henceforth invalid)
433  * @param channel_ctx place where local state associated
434  *                   with the channel is stored
435  */
436 static void
437 cb_channel_destruction (void *cls,
438                         const struct GNUNET_CADET_Channel *channel,
439                         void *channel_ctx)
440 {
441   struct AliceServiceSession *s = channel_ctx;
442
443   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
444               "Peer disconnected, terminating session %s with peer %s\n",
445               GNUNET_h2s (&s->session_id),
446               GNUNET_i2s (&s->peer));
447   if (GNUNET_SCALARPRODUCT_STATUS_ACTIVE == s->status)
448   {
449     /* We didn't get an answer yet, fail with error */
450     s->status = GNUNET_SCALARPRODUCT_STATUS_FAILURE;
451     prepare_client_end_notification (s);
452   }
453   if (NULL != s->cadet_mq)
454   {
455     GNUNET_MQ_destroy (s->cadet_mq);
456     s->cadet_mq = NULL;
457   }
458   s->channel = NULL;
459 }
460
461
462 /**
463  * Computes the square sum over a vector of a given length.
464  *
465  * @param vector the vector to compute over
466  * @param length the length of the vector
467  * @return an MPI value containing the calculated sum, never NULL
468  */
469 static gcry_mpi_t
470 compute_square_sum_mpi_elements (const struct MpiElement *vector,
471                                  uint32_t length)
472 {
473   gcry_mpi_t elem;
474   gcry_mpi_t sum;
475   uint32_t i;
476
477   GNUNET_assert (NULL != (sum = gcry_mpi_new (0)));
478   GNUNET_assert (NULL != (elem = gcry_mpi_new (0)));
479   for (i = 0; i < length; i++)
480   {
481     gcry_mpi_mul (elem, vector[i].value, vector[i].value);
482     gcry_mpi_add (sum, sum, elem);
483   }
484   gcry_mpi_release (elem);
485   return sum;
486 }
487
488
489 /**
490  * Computes the square sum over a vector of a given length.
491  *
492  * @param vector the vector to compute over
493  * @param length the length of the vector
494  * @return an MPI value containing the calculated sum, never NULL
495  */
496 static gcry_mpi_t
497 compute_square_sum (const gcry_mpi_t *vector,
498                     uint32_t length)
499 {
500   gcry_mpi_t elem;
501   gcry_mpi_t sum;
502   uint32_t i;
503
504   GNUNET_assert (NULL != (sum = gcry_mpi_new (0)));
505   GNUNET_assert (NULL != (elem = gcry_mpi_new (0)));
506   for (i = 0; i < length; i++)
507   {
508     gcry_mpi_mul (elem, vector[i], vector[i]);
509     gcry_mpi_add (sum, sum, elem);
510   }
511   gcry_mpi_release (elem);
512   return sum;
513 }
514
515
516 /**
517  * Compute our scalar product, done by Alice
518  *
519  * @param session the session associated with this computation
520  * @return product as MPI, never NULL
521  */
522 static gcry_mpi_t
523 compute_scalar_product (struct AliceServiceSession *session)
524 {
525   uint32_t count;
526   gcry_mpi_t t;
527   gcry_mpi_t u;
528   gcry_mpi_t u_prime;
529   gcry_mpi_t p;
530   gcry_mpi_t p_prime;
531   gcry_mpi_t tmp;
532   gcry_mpi_t r[session->used_element_count];
533   gcry_mpi_t r_prime[session->used_element_count];
534   gcry_mpi_t s;
535   gcry_mpi_t s_prime;
536   unsigned int i;
537
538   count = session->used_element_count;
539   // due to the introduced static offset S, we now also have to remove this
540   // from the E(a_pi)(+)E(-b_pi-r_pi) and E(a_qi)(+)E(-r_qi) twice each,
541   // the result is E((S + a_pi) + (S -b_pi-r_pi)) and E(S + a_qi + S - r_qi)
542   for (i = 0; i < count; i++)
543   {
544     r[i] = gcry_mpi_new (0);
545     GNUNET_CRYPTO_paillier_decrypt (&my_privkey,
546                                     &my_pubkey,
547                                     &session->r[i],
548                                     r[i]);
549     gcry_mpi_sub (r[i],
550                   r[i],
551                   my_offset);
552     gcry_mpi_sub (r[i],
553                   r[i],
554                   my_offset);
555     r_prime[i] = gcry_mpi_new (0);
556     GNUNET_CRYPTO_paillier_decrypt (&my_privkey,
557                                     &my_pubkey,
558                                     &session->r_prime[i],
559                                     r_prime[i]);
560     gcry_mpi_sub (r_prime[i],
561                   r_prime[i],
562                   my_offset);
563     gcry_mpi_sub (r_prime[i],
564                   r_prime[i],
565                   my_offset);
566   }
567
568   // calculate t = sum(ai)
569   t = compute_square_sum_mpi_elements (session->sorted_elements,
570                                        count);
571   // calculate U
572   u = gcry_mpi_new (0);
573   tmp = compute_square_sum (r, count);
574   gcry_mpi_sub (u, u, tmp);
575   gcry_mpi_release (tmp);
576
577   //calculate U'
578   u_prime = gcry_mpi_new (0);
579   tmp = compute_square_sum (r_prime, count);
580   gcry_mpi_sub (u_prime, u_prime, tmp);
581
582   GNUNET_assert (p = gcry_mpi_new (0));
583   GNUNET_assert (p_prime = gcry_mpi_new (0));
584   GNUNET_assert (s = gcry_mpi_new (0));
585   GNUNET_assert (s_prime = gcry_mpi_new (0));
586
587   // compute P
588   GNUNET_CRYPTO_paillier_decrypt (&my_privkey,
589                                   &my_pubkey,
590                                   &session->s,
591                                   s);
592   GNUNET_CRYPTO_paillier_decrypt (&my_privkey,
593                                   &my_pubkey,
594                                   &session->s_prime,
595                                   s_prime);
596
597   // compute P
598   gcry_mpi_add (p, s, t);
599   gcry_mpi_add (p, p, u);
600
601   // compute P'
602   gcry_mpi_add (p_prime, s_prime, t);
603   gcry_mpi_add (p_prime, p_prime, u_prime);
604
605   gcry_mpi_release (t);
606   gcry_mpi_release (u);
607   gcry_mpi_release (u_prime);
608   gcry_mpi_release (s);
609   gcry_mpi_release (s_prime);
610
611   // compute product
612   gcry_mpi_sub (p, p, p_prime);
613   gcry_mpi_release (p_prime);
614   tmp = gcry_mpi_set_ui (tmp, 2);
615   gcry_mpi_div (p, NULL, p, tmp, 0);
616
617   gcry_mpi_release (tmp);
618   for (i = 0; i < count; i++)
619   {
620     gcry_mpi_release (session->sorted_elements[i].value);
621     gcry_mpi_release (r[i]);
622     gcry_mpi_release (r_prime[i]);
623   }
624   GNUNET_free (session->sorted_elements);
625   session->sorted_elements = NULL;
626   GNUNET_free (session->r);
627   session->r = NULL;
628   GNUNET_free (session->r_prime);
629   session->r_prime = NULL;
630
631   return p;
632 }
633
634
635 /**
636  * Handle a multipart chunk of a response we got from another service
637  * we wanted to calculate a scalarproduct with.
638  *
639  * @param cls closure (set from #GNUNET_CADET_connect)
640  * @param channel connection to the other end
641  * @param channel_ctx place to store local state associated with the @a channel
642  * @param message the actual message
643  * @return #GNUNET_OK to keep the connection open,
644  *         #GNUNET_SYSERR to close it (signal serious error)
645  */
646 static int
647 handle_bobs_cryptodata_multipart (void *cls,
648                                   struct GNUNET_CADET_Channel *channel,
649                                   void **channel_ctx,
650                                   const struct GNUNET_MessageHeader *message)
651 {
652   struct AliceServiceSession *s = *channel_ctx;
653   const struct BobCryptodataMultipartMessage *msg;
654   const struct GNUNET_CRYPTO_PaillierCiphertext *payload;
655   size_t i;
656   uint32_t contained;
657   size_t msg_size;
658   size_t required_size;
659
660   if (NULL == s)
661   {
662     GNUNET_break_op (0);
663     return GNUNET_SYSERR;
664   }
665   msg_size = ntohs (message->size);
666   if (sizeof (struct BobCryptodataMultipartMessage) > msg_size)
667   {
668     GNUNET_break_op (0);
669     return GNUNET_SYSERR;
670   }
671   msg = (const struct BobCryptodataMultipartMessage *) message;
672   contained = ntohl (msg->contained_element_count);
673   required_size = sizeof (struct BobCryptodataMultipartMessage)
674     + 2 * contained * sizeof (struct GNUNET_CRYPTO_PaillierCiphertext);
675   if ( (required_size != msg_size) ||
676        (s->cadet_received_element_count + contained > s->used_element_count) )
677   {
678     GNUNET_break (0);
679     return GNUNET_SYSERR;
680   }
681
682   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
683               "Received %u additional crypto values from Bob\n",
684               (unsigned int) contained);
685
686   payload = (const struct GNUNET_CRYPTO_PaillierCiphertext *) &msg[1];
687   /* Convert each k[][perm] to its MPI_value */
688   for (i = 0; i < contained; i++)
689   {
690     GNUNET_memcpy (&s->r[s->cadet_received_element_count + i],
691             &payload[2 * i],
692             sizeof (struct GNUNET_CRYPTO_PaillierCiphertext));
693     GNUNET_memcpy (&s->r_prime[s->cadet_received_element_count + i],
694             &payload[2 * i],
695             sizeof (struct GNUNET_CRYPTO_PaillierCiphertext));
696   }
697   s->cadet_received_element_count += contained;
698   GNUNET_CADET_receive_done (s->channel);
699   if (s->cadet_received_element_count != s->used_element_count)
700     return GNUNET_OK;
701
702   s->product = compute_scalar_product (s);
703   transmit_client_response (s);
704   return GNUNET_OK;
705 }
706
707
708 /**
709  * Handle a response we got from another service we wanted to
710  * calculate a scalarproduct with.
711  *
712  * @param cls closure (set from #GNUNET_CADET_connect)
713  * @param channel connection to the other end
714  * @param channel_ctx place to store local state associated with the channel
715  * @param message the actual message
716  * @return #GNUNET_OK to keep the connection open,
717  *         #GNUNET_SYSERR to close it (we are done)
718  */
719 static int
720 handle_bobs_cryptodata_message (void *cls,
721                                 struct GNUNET_CADET_Channel *channel,
722                                 void **channel_ctx,
723                                 const struct GNUNET_MessageHeader *message)
724 {
725   struct AliceServiceSession *s = *channel_ctx;
726   const struct BobCryptodataMessage *msg;
727   const struct GNUNET_CRYPTO_PaillierCiphertext *payload;
728   uint32_t i;
729   uint32_t contained;
730   uint16_t msg_size;
731   size_t required_size;
732
733   if (NULL == s)
734   {
735     GNUNET_break_op (0);
736     return GNUNET_SYSERR;
737   }
738   msg_size = ntohs (message->size);
739   if (sizeof (struct BobCryptodataMessage) > msg_size)
740   {
741     GNUNET_break_op (0);
742     return GNUNET_SYSERR;
743   }
744   msg = (const struct BobCryptodataMessage *) message;
745   contained = ntohl (msg->contained_element_count);
746   required_size = sizeof (struct BobCryptodataMessage)
747     + 2 * contained * sizeof (struct GNUNET_CRYPTO_PaillierCiphertext)
748     + 2 * sizeof (struct GNUNET_CRYPTO_PaillierCiphertext);
749   if ( (msg_size != required_size) ||
750        (contained > UINT16_MAX) ||
751        (s->used_element_count < contained) )
752   {
753     GNUNET_break_op (0);
754     return GNUNET_SYSERR;
755   }
756   if (NULL == s->sorted_elements)
757   {
758     /* we're not ready yet, how can Bob be? */
759     GNUNET_break_op (0);
760     return GNUNET_SYSERR;
761   }
762   if (s->total != s->client_received_element_count)
763   {
764     /* we're not ready yet, how can Bob be? */
765     GNUNET_break_op (0);
766     return GNUNET_SYSERR;
767   }
768   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
769               "Received %u crypto values from Bob\n",
770               (unsigned int) contained);
771
772   payload = (const struct GNUNET_CRYPTO_PaillierCiphertext *) &msg[1];
773   GNUNET_memcpy (&s->s,
774           &payload[0],
775           sizeof (struct GNUNET_CRYPTO_PaillierCiphertext));
776   GNUNET_memcpy (&s->s_prime,
777           &payload[1],
778           sizeof (struct GNUNET_CRYPTO_PaillierCiphertext));
779   payload = &payload[2];
780
781   s->r = GNUNET_malloc (sizeof (struct GNUNET_CRYPTO_PaillierCiphertext) * s->used_element_count);
782   s->r_prime = GNUNET_malloc (sizeof (struct GNUNET_CRYPTO_PaillierCiphertext) * s->used_element_count);
783   for (i = 0; i < contained; i++)
784   {
785     GNUNET_memcpy (&s->r[i],
786             &payload[2 * i],
787             sizeof (struct GNUNET_CRYPTO_PaillierCiphertext));
788     GNUNET_memcpy (&s->r_prime[i],
789             &payload[2 * i + 1],
790             sizeof (struct GNUNET_CRYPTO_PaillierCiphertext));
791   }
792   s->cadet_received_element_count = contained;
793   GNUNET_CADET_receive_done (s->channel);
794
795   if (s->cadet_received_element_count != s->used_element_count)
796   {
797     /* More to come */
798     return GNUNET_OK;
799   }
800
801   s->product = compute_scalar_product (s);
802   transmit_client_response (s);
803   return GNUNET_OK;
804 }
805
806
807 /**
808  * Iterator to copy over messages from the hash map
809  * into an array for sorting.
810  *
811  * @param cls the `struct AliceServiceSession *`
812  * @param key the key (unused)
813  * @param value the `struct GNUNET_SCALARPRODUCT_Element *`
814  */
815 static int
816 copy_element_cb (void *cls,
817                  const struct GNUNET_HashCode *key,
818                  void *value)
819 {
820   struct AliceServiceSession *s = cls;
821   struct GNUNET_SCALARPRODUCT_Element *e = value;
822   gcry_mpi_t mval;
823   int64_t val;
824
825   mval = gcry_mpi_new (0);
826   val = (int64_t) GNUNET_ntohll (e->value);
827   if (0 > val)
828     gcry_mpi_sub_ui (mval, mval, -val);
829   else
830     gcry_mpi_add_ui (mval, mval, val);
831   s->sorted_elements [s->used_element_count].value = mval;
832   s->sorted_elements [s->used_element_count].key = &e->key;
833   s->used_element_count++;
834   return GNUNET_OK;
835 }
836
837
838 /**
839  * Compare two `struct MpiValue`s by key for sorting.
840  *
841  * @param a pointer to first `struct MpiValue *`
842  * @param b pointer to first `struct MpiValue *`
843  * @return -1 for a < b, 0 for a=b, 1 for a > b.
844  */
845 static int
846 element_cmp (const void *a,
847              const void *b)
848 {
849   const struct MpiElement *ma = a;
850   const struct MpiElement *mb = b;
851
852   return GNUNET_CRYPTO_hash_cmp (ma->key,
853                                  mb->key);
854 }
855
856
857 /**
858  * Maximum number of elements we can put into a single cryptodata
859  * message
860  */
861 #define ELEMENT_CAPACITY ((GNUNET_CONSTANTS_MAX_CADET_MESSAGE_SIZE - 1 - sizeof (struct AliceCryptodataMessage)) / sizeof (struct GNUNET_CRYPTO_PaillierCiphertext))
862
863
864 /**
865  * Send the cryptographic data from Alice to Bob.
866  * Does nothing if we already transferred all elements.
867  *
868  * @param s the associated service session
869  */
870 static void
871 send_alices_cryptodata_message (struct AliceServiceSession *s)
872 {
873   struct AliceCryptodataMessage *msg;
874   struct GNUNET_MQ_Envelope *e;
875   struct GNUNET_CRYPTO_PaillierCiphertext *payload;
876   unsigned int i;
877   uint32_t todo_count;
878   gcry_mpi_t a;
879   uint32_t off;
880
881   s->sorted_elements
882     = GNUNET_malloc (GNUNET_CONTAINER_multihashmap_size (s->intersected_elements) *
883                      sizeof (struct MpiElement));
884   s->used_element_count = 0;
885   GNUNET_CONTAINER_multihashmap_iterate (s->intersected_elements,
886                                          &copy_element_cb,
887                                          s);
888   LOG (GNUNET_ERROR_TYPE_DEBUG,
889        "Finished intersection, %d items remain\n",
890        s->used_element_count);
891   qsort (s->sorted_elements,
892          s->used_element_count,
893          sizeof (struct MpiElement),
894          &element_cmp);
895   off = 0;
896   while (off < s->used_element_count)
897   {
898     todo_count = s->used_element_count - off;
899     if (todo_count > ELEMENT_CAPACITY)
900       todo_count = ELEMENT_CAPACITY;
901     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
902                 "Sending %u/%u crypto values to Bob\n",
903                 (unsigned int) todo_count,
904                 (unsigned int) s->used_element_count);
905
906     e = GNUNET_MQ_msg_extra (msg,
907                              todo_count * sizeof (struct GNUNET_CRYPTO_PaillierCiphertext),
908                              GNUNET_MESSAGE_TYPE_SCALARPRODUCT_ALICE_CRYPTODATA);
909     msg->contained_element_count = htonl (todo_count);
910     payload = (struct GNUNET_CRYPTO_PaillierCiphertext *) &msg[1];
911     a = gcry_mpi_new (0);
912     for (i = off; i < off + todo_count; i++)
913     {
914       gcry_mpi_add (a,
915                     s->sorted_elements[i].value,
916                     my_offset);
917       GNUNET_assert (3 ==
918                      GNUNET_CRYPTO_paillier_encrypt (&my_pubkey,
919                                                      a,
920                                                      3,
921                                                      &payload[i - off]));
922     }
923     gcry_mpi_release (a);
924     off += todo_count;
925     GNUNET_MQ_send (s->cadet_mq,
926                     e);
927   }
928 }
929
930
931 /**
932  * Callback for set operation results. Called for each element
933  * that should be removed from the result set, and then once
934  * to indicate that the set intersection operation is done.
935  *
936  * @param cls closure with the `struct AliceServiceSession`
937  * @param element a result element, only valid if status is #GNUNET_SET_STATUS_OK
938  * @param status what has happened with the set intersection?
939  */
940 static void
941 cb_intersection_element_removed (void *cls,
942                                  const struct GNUNET_SET_Element *element,
943                                  enum GNUNET_SET_Status status)
944 {
945   struct AliceServiceSession *s = cls;
946   struct GNUNET_SCALARPRODUCT_Element *se;
947
948   switch (status)
949   {
950   case GNUNET_SET_STATUS_OK:
951     /* this element has been removed from the set */
952     se = GNUNET_CONTAINER_multihashmap_get (s->intersected_elements,
953                                             element->data);
954     GNUNET_assert (NULL != se);
955     LOG (GNUNET_ERROR_TYPE_DEBUG,
956          "Intersection removed element with key %s and value %lld\n",
957          GNUNET_h2s (&se->key),
958          (long long) GNUNET_ntohll (se->value));
959     GNUNET_assert (GNUNET_YES ==
960                    GNUNET_CONTAINER_multihashmap_remove (s->intersected_elements,
961                                                          element->data,
962                                                          se));
963     GNUNET_free (se);
964     return;
965   case GNUNET_SET_STATUS_DONE:
966     s->intersection_op = NULL;
967     if (NULL != s->intersection_set)
968     {
969       GNUNET_SET_destroy (s->intersection_set);
970       s->intersection_set = NULL;
971     }
972     send_alices_cryptodata_message (s);
973     return;
974   case GNUNET_SET_STATUS_HALF_DONE:
975     /* unexpected for intersection */
976     GNUNET_break (0);
977     return;
978   case GNUNET_SET_STATUS_FAILURE:
979     /* unhandled status code */
980     LOG (GNUNET_ERROR_TYPE_DEBUG,
981          "Set intersection failed!\n");
982     if (NULL != s->intersection_listen)
983     {
984       GNUNET_SET_listen_cancel (s->intersection_listen);
985       s->intersection_listen = NULL;
986     }
987     s->intersection_op = NULL;
988     if (NULL != s->intersection_set)
989     {
990       GNUNET_SET_destroy (s->intersection_set);
991       s->intersection_set = NULL;
992     }
993     s->status = GNUNET_SCALARPRODUCT_STATUS_FAILURE;
994     prepare_client_end_notification (s);
995     return;
996   default:
997     GNUNET_break (0);
998     return;
999   }
1000 }
1001
1002
1003 /**
1004  * Called when another peer wants to do a set operation with the
1005  * local peer. If a listen error occurs, the @a request is NULL.
1006  *
1007  * @param cls closure with the `struct AliceServiceSession *`
1008  * @param other_peer the other peer
1009  * @param context_msg message with application specific information from
1010  *        the other peer
1011  * @param request request from the other peer (never NULL), use GNUNET_SET_accept()
1012  *        to accept it, otherwise the request will be refused
1013  *        Note that we can't just return value from the listen callback,
1014  *        as it is also necessary to specify the set we want to do the
1015  *        operation with, whith sometimes can be derived from the context
1016  *        message. It's necessary to specify the timeout.
1017  */
1018 static void
1019 cb_intersection_request_alice (void *cls,
1020                                const struct GNUNET_PeerIdentity *other_peer,
1021                                const struct GNUNET_MessageHeader *context_msg,
1022                                struct GNUNET_SET_Request *request)
1023 {
1024   struct AliceServiceSession *s = cls;
1025
1026   if (0 != memcmp (other_peer,
1027                    &s->peer,
1028                    sizeof (struct GNUNET_PeerIdentity)))
1029   {
1030     GNUNET_break_op (0);
1031     return;
1032   }
1033   s->intersection_op
1034     = GNUNET_SET_accept (request,
1035                          GNUNET_SET_RESULT_REMOVED,
1036                          &cb_intersection_element_removed,
1037                          s);
1038   if (NULL == s->intersection_op)
1039   {
1040     GNUNET_break (0);
1041     s->status = GNUNET_SCALARPRODUCT_STATUS_FAILURE;
1042     prepare_client_end_notification (s);
1043     return;
1044   }
1045   if (GNUNET_OK !=
1046       GNUNET_SET_commit (s->intersection_op,
1047                          s->intersection_set))
1048   {
1049     GNUNET_break (0);
1050     s->status = GNUNET_SCALARPRODUCT_STATUS_FAILURE;
1051     prepare_client_end_notification (s);
1052     return;
1053   }
1054   GNUNET_SET_destroy (s->intersection_set);
1055   s->intersection_set = NULL;
1056   GNUNET_SET_listen_cancel (s->intersection_listen);
1057   s->intersection_listen = NULL;
1058 }
1059
1060
1061 /**
1062  * Our client has finished sending us its multipart message.
1063  *
1064  * @param session the service session context
1065  */
1066 static void
1067 client_request_complete_alice (struct AliceServiceSession *s)
1068 {
1069   struct ServiceRequestMessage *msg;
1070   struct GNUNET_MQ_Envelope *e;
1071
1072   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1073               "Creating new channel for session with key %s.\n",
1074               GNUNET_h2s (&s->session_id));
1075   s->channel
1076     = GNUNET_CADET_channel_create (my_cadet,
1077                                    s,
1078                                    &s->peer,
1079                                    &s->session_id,
1080                                    GNUNET_CADET_OPTION_RELIABLE);
1081   if (NULL == s->channel)
1082   {
1083     s->status = GNUNET_SCALARPRODUCT_STATUS_FAILURE;
1084     prepare_client_end_notification (s);
1085     return;
1086   }
1087   s->cadet_mq = GNUNET_CADET_mq_create (s->channel);
1088   s->intersection_listen
1089     = GNUNET_SET_listen (cfg,
1090                          GNUNET_SET_OPERATION_INTERSECTION,
1091                          &s->session_id,
1092                          &cb_intersection_request_alice,
1093                          s);
1094   if (NULL == s->intersection_listen)
1095   {
1096     s->status = GNUNET_SCALARPRODUCT_STATUS_FAILURE;
1097     GNUNET_CADET_channel_destroy (s->channel);
1098     s->channel = NULL;
1099     prepare_client_end_notification (s);
1100     return;
1101   }
1102
1103   e = GNUNET_MQ_msg (msg,
1104                      GNUNET_MESSAGE_TYPE_SCALARPRODUCT_SESSION_INITIALIZATION);
1105   msg->session_id = s->session_id;
1106   msg->public_key = my_pubkey;
1107   GNUNET_MQ_send (s->cadet_mq,
1108                   e);
1109 }
1110
1111
1112 /**
1113  * We're receiving additional set data. Check if 
1114  * @a msg is well-formed.
1115  *
1116  * @param cls client identification of the client
1117  * @param msg the actual message
1118  * @return #GNUNET_OK if @a msg is well-formed
1119  */
1120 static int
1121 check_alice_client_message_multipart (void *cls,                                       
1122                                       const struct ComputationBobCryptodataMultipartMessage *msg)
1123 {
1124   struct AliceServiceSession *s = cls;
1125   uint32_t contained_count;
1126   uint16_t msize;
1127
1128   msize = ntohs (msg->header.size);
1129   contained_count = ntohl (msg->element_count_contained);
1130   if ( (msize != (sizeof (struct ComputationBobCryptodataMultipartMessage) +
1131                   contained_count * sizeof (struct GNUNET_SCALARPRODUCT_Element))) ||
1132        (0 == contained_count) ||
1133        (s->total == s->client_received_element_count) ||
1134        (s->total < s->client_received_element_count + contained_count) )
1135   {
1136     GNUNET_break_op (0);
1137     return GNUNET_SYSERR;
1138   }
1139   return GNUNET_OK;
1140 }
1141
1142
1143 /**
1144  * We're receiving additional set data. Add it to our
1145  * set and if we are done, initiate the transaction.
1146  *
1147  * @param cls client identification of the client
1148  * @param msg the actual message
1149  */
1150 static void
1151 handle_alice_client_message_multipart (void *cls,                                      
1152                                        const struct ComputationBobCryptodataMultipartMessage *msg)
1153 {
1154   struct AliceServiceSession *s = cls;
1155   uint32_t contained_count;
1156   const struct GNUNET_SCALARPRODUCT_Element *elements;
1157   struct GNUNET_SET_Element set_elem;
1158   struct GNUNET_SCALARPRODUCT_Element *elem;
1159
1160   contained_count = ntohl (msg->element_count_contained);
1161   s->client_received_element_count += contained_count;
1162   elements = (const struct GNUNET_SCALARPRODUCT_Element *) &msg[1];
1163   for (uint32_t i = 0; i < contained_count; i++)
1164   {
1165     elem = GNUNET_new (struct GNUNET_SCALARPRODUCT_Element);
1166     GNUNET_memcpy (elem,
1167                    &elements[i],
1168                    sizeof (struct GNUNET_SCALARPRODUCT_Element));
1169     if (GNUNET_SYSERR ==
1170         GNUNET_CONTAINER_multihashmap_put (s->intersected_elements,
1171                                            &elem->key,
1172                                            elem,
1173                                            GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY))
1174     {
1175       GNUNET_break (0);
1176       GNUNET_free (elem);
1177       continue;
1178     }
1179     set_elem.data = &elem->key;
1180     set_elem.size = sizeof (elem->key);
1181     set_elem.element_type = 0;
1182     GNUNET_SET_add_element (s->intersection_set,
1183                             &set_elem,
1184                             NULL, NULL);
1185     s->used_element_count++;
1186   }
1187   GNUNET_SERVICE_client_continue (s->client);
1188   if (s->total != s->client_received_element_count)
1189   {
1190     /* more to come */
1191     return;
1192   }
1193   client_request_complete_alice (s);
1194 }
1195
1196
1197 /**
1198  * Handler for Alice's client request message.
1199  * Check that @a msg is well-formed.
1200  *
1201  * @param cls identification of the client
1202  * @param msg the actual message
1203  * @return #GNUNET_OK if @a msg is well-formed
1204  */
1205 static int
1206 check_alice_client_message (void *cls,                       
1207                             const struct AliceComputationMessage *msg)
1208 {
1209   struct AliceServiceSession *s = cls;
1210   uint16_t msize;
1211   uint32_t total_count;
1212   uint32_t contained_count;
1213
1214   if (NULL != s->intersected_elements)
1215   {
1216     /* only one concurrent session per client connection allowed,
1217        simplifies logic a lot... */
1218     GNUNET_break (0);
1219     return GNUNET_SYSERR;
1220   }
1221   msize = ntohs (msg->header.size);
1222   total_count = ntohl (msg->element_count_total);
1223   contained_count = ntohl (msg->element_count_contained);
1224   if ( (0 == total_count) ||
1225        (0 == contained_count) ||
1226        (msize != (sizeof (struct AliceComputationMessage) +
1227                   contained_count * sizeof (struct GNUNET_SCALARPRODUCT_Element))) )
1228   {
1229     GNUNET_break_op (0);
1230     return GNUNET_SYSERR;
1231   }
1232   return GNUNET_OK;
1233 }
1234
1235   
1236 /**
1237  * Handler for Alice's client request message.
1238  * We are doing request-initiation to compute a scalar product with a peer.
1239  *
1240  * @param cls identification of the client
1241  * @param msg the actual message
1242  */
1243 static void
1244 handle_alice_client_message (void *cls,                      
1245                              const struct AliceComputationMessage *msg)
1246 {
1247   struct AliceServiceSession *s = cls;
1248   uint32_t contained_count;
1249   uint32_t total_count;
1250   const struct GNUNET_SCALARPRODUCT_Element *elements;
1251   struct GNUNET_SET_Element set_elem;
1252   struct GNUNET_SCALARPRODUCT_Element *elem;
1253
1254   total_count = ntohl (msg->element_count_total);
1255   contained_count = ntohl (msg->element_count_contained);
1256   s->peer = msg->peer;
1257   s->status = GNUNET_SCALARPRODUCT_STATUS_ACTIVE;
1258   s->total = total_count;
1259   s->client_received_element_count = contained_count;
1260   s->session_id = msg->session_key;
1261   elements = (const struct GNUNET_SCALARPRODUCT_Element *) &msg[1];
1262   s->intersected_elements = GNUNET_CONTAINER_multihashmap_create (s->total,
1263                                                                   GNUNET_YES);
1264   s->intersection_set = GNUNET_SET_create (cfg,
1265                                            GNUNET_SET_OPERATION_INTERSECTION);
1266
1267   for (uint32_t i = 0; i < contained_count; i++)
1268   {
1269     if (0 == GNUNET_ntohll (elements[i].value))
1270       continue;
1271     elem = GNUNET_new (struct GNUNET_SCALARPRODUCT_Element);
1272     GNUNET_memcpy (elem,
1273             &elements[i],
1274             sizeof (struct GNUNET_SCALARPRODUCT_Element));
1275     if (GNUNET_SYSERR ==
1276         GNUNET_CONTAINER_multihashmap_put (s->intersected_elements,
1277                                            &elem->key,
1278                                            elem,
1279                                            GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY))
1280     {
1281       /* element with same key encountered twice! */
1282       GNUNET_break (0);
1283       GNUNET_free (elem);
1284       continue;
1285     }
1286     set_elem.data = &elem->key;
1287     set_elem.size = sizeof (elem->key);
1288     set_elem.element_type = 0;
1289     GNUNET_SET_add_element (s->intersection_set,
1290                             &set_elem,
1291                             NULL, NULL);
1292     s->used_element_count++;
1293   }
1294   GNUNET_SERVICE_client_continue (s->client);
1295   if (s->total != s->client_received_element_count)
1296   {
1297     /* wait for multipart msg */
1298     return;
1299   }
1300   client_request_complete_alice (s);
1301 }
1302
1303
1304 /**
1305  * Task run during shutdown.
1306  *
1307  * @param cls unused
1308  */
1309 static void
1310 shutdown_task (void *cls)
1311 {
1312   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1313               "Shutting down, initiating cleanup.\n");
1314   // FIXME: we have to cut our connections to CADET first!
1315   if (NULL != my_cadet)
1316   {
1317     GNUNET_CADET_disconnect (my_cadet);
1318     my_cadet = NULL;
1319   }
1320 }
1321
1322
1323 /**
1324  * A client connected.
1325  *
1326  * Setup the associated data structure.
1327  *
1328  * @param cls closure, NULL
1329  * @param client identification of the client
1330  * @param mq message queue to communicate with @a client
1331  * @return our `struct AliceServiceSession`
1332  */
1333 static void *
1334 client_connect_cb (void *cls,
1335                    struct GNUNET_SERVICE_Client *client,
1336                    struct GNUNET_MQ_Handle *mq)
1337 {
1338   struct AliceServiceSession *s;
1339
1340   s = GNUNET_new (struct AliceServiceSession);
1341   s->client = client;
1342   s->client_mq = mq;
1343   return s;
1344 }
1345
1346
1347 /**
1348  * A client disconnected.
1349  *
1350  * Remove the associated session(s), release data structures
1351  * and cancel pending outgoing transmissions to the client.
1352  *
1353  * @param cls closure, NULL
1354  * @param client identification of the client
1355  * @param app_cls our `struct AliceServiceSession`
1356  */
1357 static void
1358 client_disconnect_cb (void *cls,
1359                       struct GNUNET_SERVICE_Client *client,
1360                       void *app_cls)
1361 {
1362   struct AliceServiceSession *s = app_cls;
1363
1364   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1365               "Client %p disconnected from us.\n",
1366               client);
1367   s->client = NULL;
1368   s->client_mq = NULL;
1369   destroy_service_session (s);
1370 }
1371
1372
1373 /**
1374  * Initialization of the program and message handlers
1375  *
1376  * @param cls closure
1377  * @param c configuration to use
1378  * @param service the initialized service
1379  */
1380 static void
1381 run (void *cls,
1382      const struct GNUNET_CONFIGURATION_Handle *c,
1383      struct GNUNET_SERVICE_Handle *service)
1384 {
1385   static const struct GNUNET_CADET_MessageHandler cadet_handlers[] = {
1386     { &handle_bobs_cryptodata_message,
1387       GNUNET_MESSAGE_TYPE_SCALARPRODUCT_BOB_CRYPTODATA,
1388       0},
1389     { &handle_bobs_cryptodata_multipart,
1390       GNUNET_MESSAGE_TYPE_SCALARPRODUCT_BOB_CRYPTODATA_MULTIPART,
1391       0},
1392     { NULL, 0, 0}
1393   };
1394
1395   cfg = c;
1396   /*
1397     offset has to be sufficiently small to allow computation of:
1398     m1+m2 mod n == (S + a) + (S + b) mod n,
1399     if we have more complex operations, this factor needs to be lowered */
1400   my_offset = gcry_mpi_new (GNUNET_CRYPTO_PAILLIER_BITS / 3);
1401   gcry_mpi_set_bit (my_offset,
1402                     GNUNET_CRYPTO_PAILLIER_BITS / 3);
1403
1404   GNUNET_CRYPTO_paillier_create (&my_pubkey,
1405                                  &my_privkey);
1406   my_cadet = GNUNET_CADET_connect (cfg,
1407                                    NULL,
1408                                    &cb_channel_destruction,
1409                                    cadet_handlers);
1410   GNUNET_SCHEDULER_add_shutdown (&shutdown_task,
1411                                  NULL);
1412   if (NULL == my_cadet)
1413   {
1414     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1415                 _("Connect to CADET failed\n"));
1416     GNUNET_SCHEDULER_shutdown ();
1417     return;
1418   }
1419 }
1420
1421
1422 /**
1423  * Define "main" method using service macro.
1424  */
1425 GNUNET_SERVICE_MAIN
1426 ("scalarproduct-alice",
1427  GNUNET_SERVICE_OPTION_NONE,
1428  &run,
1429  &client_connect_cb,
1430  &client_disconnect_cb,
1431  NULL,
1432  GNUNET_MQ_hd_var_size (alice_client_message,
1433                         GNUNET_MESSAGE_TYPE_SCALARPRODUCT_CLIENT_TO_ALICE,
1434                         struct AliceComputationMessage,
1435                         NULL),
1436  GNUNET_MQ_hd_var_size (alice_client_message_multipart,
1437                         GNUNET_MESSAGE_TYPE_SCALARPRODUCT_CLIENT_MULTIPART_ALICE,
1438                         struct ComputationBobCryptodataMultipartMessage,
1439                         NULL),
1440   GNUNET_MQ_handler_end ());
1441
1442
1443 /* end of gnunet-service-scalarproduct_alice.c */