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