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