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