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