aboutsummaryrefslogtreecommitdiff
path: root/src/scalarproduct
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
parent6cd1fc3aa29926ce0326d07ba684e1b65a1a0db7 (diff)
downloadgnunet-9d487bb2fe029b369f362bdbe4697005061a4e5e.tar.gz
gnunet-9d487bb2fe029b369f362bdbe4697005061a4e5e.zip
massive rework of scalarproduct service, splitting into Alice and Bob
Diffstat (limited to 'src/scalarproduct')
-rw-r--r--src/scalarproduct/Makefile.am21
-rw-r--r--src/scalarproduct/gnunet-service-scalarproduct.c2819
-rw-r--r--src/scalarproduct/gnunet-service-scalarproduct.h165
-rw-r--r--src/scalarproduct/gnunet-service-scalarproduct_alice.c1396
-rw-r--r--src/scalarproduct/gnunet-service-scalarproduct_bob.c1490
-rw-r--r--src/scalarproduct/scalarproduct.conf.in14
-rw-r--r--src/scalarproduct/scalarproduct.h56
-rw-r--r--src/scalarproduct/scalarproduct_api.c31
-rw-r--r--src/scalarproduct/test_scalarproduct.conf2
9 files changed, 3139 insertions, 2855 deletions
diff --git a/src/scalarproduct/Makefile.am b/src/scalarproduct/Makefile.am
index 0d3597126..ecebdbfc5 100644
--- a/src/scalarproduct/Makefile.am
+++ b/src/scalarproduct/Makefile.am
@@ -19,7 +19,8 @@ bin_PROGRAMS = \
19 gnunet-scalarproduct 19 gnunet-scalarproduct
20 20
21libexec_PROGRAMS = \ 21libexec_PROGRAMS = \
22 gnunet-service-scalarproduct 22 gnunet-service-scalarproduct-alice \
23 gnunet-service-scalarproduct-bob
23 24
24lib_LTLIBRARIES = \ 25lib_LTLIBRARIES = \
25 libgnunetscalarproduct.la 26 libgnunetscalarproduct.la
@@ -33,9 +34,21 @@ gnunet_scalarproduct_LDADD = \
33 -lgcrypt \ 34 -lgcrypt \
34 $(GN_LIBINTL) 35 $(GN_LIBINTL)
35 36
36gnunet_service_scalarproduct_SOURCES = \ 37gnunet_service_scalarproduct_alice_SOURCES = \
37 gnunet-service-scalarproduct.c 38 gnunet-service-scalarproduct.h \
38gnunet_service_scalarproduct_LDADD = \ 39 gnunet-service-scalarproduct_alice.c
40gnunet_service_scalarproduct_alice_LDADD = \
41 $(top_builddir)/src/util/libgnunetutil.la \
42 $(top_builddir)/src/cadet/libgnunetcadet.la \
43 $(top_builddir)/src/set/libgnunetset.la \
44 $(LIBGCRYPT_LIBS) \
45 -lgcrypt \
46 $(GN_LIBINTL)
47
48gnunet_service_scalarproduct_bob_SOURCES = \
49 gnunet-service-scalarproduct.h \
50 gnunet-service-scalarproduct_bob.c gnunet-service-scalarproduct_bob.h
51gnunet_service_scalarproduct_bob_LDADD = \
39 $(top_builddir)/src/util/libgnunetutil.la \ 52 $(top_builddir)/src/util/libgnunetutil.la \
40 $(top_builddir)/src/cadet/libgnunetcadet.la \ 53 $(top_builddir)/src/cadet/libgnunetcadet.la \
41 $(top_builddir)/src/set/libgnunetset.la \ 54 $(top_builddir)/src/set/libgnunetset.la \
diff --git a/src/scalarproduct/gnunet-service-scalarproduct.c b/src/scalarproduct/gnunet-service-scalarproduct.c
deleted file mode 100644
index 18f243e5d..000000000
--- a/src/scalarproduct/gnunet-service-scalarproduct.c
+++ /dev/null
@@ -1,2819 +0,0 @@
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/**
22 * @file scalarproduct/gnunet-service-scalarproduct.c
23 * @brief scalarproduct service implementation
24 * @author Christian M. Fuchs
25 * @author Christian Grothoff
26 */
27#include "platform.h"
28#include <limits.h>
29#include <gcrypt.h>
30#include "gnunet_util_lib.h"
31#include "gnunet_core_service.h"
32#include "gnunet_cadet_service.h"
33#include "gnunet_applications.h"
34#include "gnunet_protocols.h"
35#include "gnunet_scalarproduct_service.h"
36#include "gnunet_set_service.h"
37#include "scalarproduct.h"
38
39#define LOG(kind,...) GNUNET_log_from (kind, "scalarproduct", __VA_ARGS__)
40
41
42/**
43 * Maximum count of elements we can put into a multipart message
44 */
45#define MULTIPART_ELEMENT_CAPACITY ((GNUNET_SERVER_MAX_MESSAGE_SIZE - 1 - sizeof (struct MultipartMessage)) / sizeof (struct GNUNET_CRYPTO_PaillierCiphertext))
46
47
48GNUNET_NETWORK_STRUCT_BEGIN
49
50/**
51 * Message type passed from requesting service Alice to responding
52 * service Bob to initiate a request and make Bob participate in our
53 * protocol
54 */
55struct ServiceRequestMessage
56{
57 /**
58 * Type is #GNUNET_MESSAGE_TYPE_SCALARPRODUCT_SESSION_INITIALIZATION
59 */
60 struct GNUNET_MessageHeader header;
61
62 /**
63 * For alignment. Always zero.
64 */
65 uint32_t reserved;
66
67 /**
68 * The transaction/session key used to identify a session
69 */
70 struct GNUNET_HashCode session_id;
71
72 /**
73 * Alice's public key
74 */
75 struct GNUNET_CRYPTO_PaillierPublicKey public_key;
76
77};
78
79
80/**
81 * Vector of Pallier-encrypted values sent by Alice to Bob
82 * (after set intersection).
83 */
84struct AliceCryptodataMessage
85{
86 /**
87 * Type is #GNUNET_MESSAGE_TYPE_SCALARPRODUCT_ALICE_CRYPTODATA
88 */
89 struct GNUNET_MessageHeader header;
90
91 /**
92 * How many elements we appended to this message? In NBO.
93 */
94 uint32_t contained_element_count GNUNET_PACKED;
95
96 /**
97 * struct GNUNET_CRYPTO_PaillierCiphertext[contained_element_count]
98 */
99};
100
101
102/**
103 * Multipart Message type passed between to supply additional elements
104 * for the peer.
105 */
106struct MultipartMessage
107{
108 /**
109 * GNUNET message header
110 */
111 struct GNUNET_MessageHeader header;
112
113 /**
114 * How many elements we supply within this message? In NBO.
115 */
116 uint32_t contained_element_count GNUNET_PACKED;
117
118 /**
119 * struct GNUNET_CRYPTO_PaillierCiphertext[multipart_element_count]
120 */
121};
122
123
124/**
125 * Message type passed from responding service Bob to responding service Alice
126 * to complete a request and allow Alice to compute the result.
127 */
128struct ServiceResponseMessage
129{
130 /**
131 * GNUNET message header
132 */
133 struct GNUNET_MessageHeader header;
134
135 /**
136 * How many elements the session input had (in NBO).
137 */
138 uint32_t total_element_count GNUNET_PACKED;
139
140 /**
141 * How many elements were included after the mask was applied
142 * including all multipart msgs (in NBO).
143 */
144 uint32_t used_element_count GNUNET_PACKED;
145
146 /**
147 * How many elements this individual message delivers (in NBO).
148 */
149 uint32_t contained_element_count GNUNET_PACKED;
150
151 /**
152 * The transaction/session key used to identify a session.
153 * FIXME: needed? CADET should already identify sessions!
154 */
155 struct GNUNET_HashCode key;
156
157 /**
158 * followed by s | s' | k[i][perm]
159 */
160};
161
162GNUNET_NETWORK_STRUCT_END
163
164
165/**
166 * Role a peer in a session can assume.
167 */
168enum PeerRole
169{
170 /**
171 * Alice is the peer that learns the result of the scalar product
172 * calculation.
173 */
174 ALICE,
175
176 /**
177 * Bob merely provides his vector to compute the scalar product, but
178 * does not learn anything about Alice's vector (except which elements
179 * Alice's vector may contain, as the compute an intersection).
180 */
181 BOB
182};
183
184
185/**
186 * DLL for sorting elements.
187 */
188struct SortedValue
189{
190 /**
191 * Sorted Values are kept in a DLL
192 */
193 struct SortedValue *next;
194
195 /**
196 * Sorted Values are kept in a DLL
197 */
198 struct SortedValue *prev;
199
200 /**
201 * The element's id+integer-value
202 */
203 struct GNUNET_SCALARPRODUCT_Element *elem;
204
205 /**
206 * The element's value converted to MPI
207 */
208 gcry_mpi_t val;
209};
210
211
212/**
213 * A scalarproduct session which tracks:
214 *
215 * a request form the client to our final response.
216 * or
217 * a request from a service to us (service).
218 */
219struct ServiceSession
220{
221
222 /**
223 * Session information is kept in a DLL
224 */
225 struct ServiceSession *next;
226
227 /**
228 * Session information is kept in a DLL
229 */
230 struct ServiceSession *prev;
231
232 /**
233 * (hopefully) unique transaction ID
234 */
235 struct GNUNET_HashCode session_id;
236
237 /**
238 * Alice or Bob's peerID
239 */
240 struct GNUNET_PeerIdentity peer;
241
242 /**
243 * The client this request is related to.
244 */
245 struct GNUNET_SERVER_Client *client;
246
247 /**
248 * The message to send
249 */
250 struct GNUNET_MessageHeader *msg;
251
252 /**
253 * all non-0-value'd elements transmitted to us
254 */
255 struct GNUNET_CONTAINER_MultiHashMap *intersected_elements;
256
257 /**
258 * Set of elements for which will conduction an intersection.
259 * the resulting elements are then used for computing the scalar product.
260 */
261 struct GNUNET_SET_Handle *intersection_set;
262
263 /**
264 * Set of elements for which will conduction an intersection.
265 * the resulting elements are then used for computing the scalar product.
266 */
267 struct GNUNET_SET_OperationHandle *intersection_op;
268
269 /**
270 * Handle to Alice's Intersection operation listening for Bob
271 */
272 struct GNUNET_SET_ListenHandle *intersection_listen;
273
274 /**
275 * DLL for sorting elements after intersection
276 */
277 struct SortedValue *a_head;
278
279 /**
280 * a(Alice)
281 */
282 struct SortedValue *a_tail;
283
284 /**
285 * a(Alice)
286 */
287 gcry_mpi_t *sorted_elements;
288
289 /**
290 * E(ai)(Bob) after applying the mask
291 */
292 struct GNUNET_CRYPTO_PaillierCiphertext *e_a;
293
294 /**
295 * Bob's permutation p of R
296 */
297 struct GNUNET_CRYPTO_PaillierCiphertext *r;
298
299 /**
300 * Bob's permutation q of R
301 */
302 struct GNUNET_CRYPTO_PaillierCiphertext *r_prime;
303
304 /**
305 * Bob's "s"
306 */
307 struct GNUNET_CRYPTO_PaillierCiphertext s;
308
309 /**
310 * Bob's "s'"
311 */
312 struct GNUNET_CRYPTO_PaillierCiphertext s_prime;
313
314 /**
315 * Bob's matching response session from the client
316 */
317 struct ServiceSession *response;
318
319 /**
320 * My transmit handle for the current message to a Alice/Bob
321 */
322 struct GNUNET_CADET_TransmitHandle *service_transmit_handle;
323
324 /**
325 * My transmit handle for the current message to the client
326 */
327 struct GNUNET_SERVER_TransmitHandle *client_transmit_handle;
328
329 /**
330 * channel-handle associated with our cadet handle
331 */
332 struct GNUNET_CADET_Channel *channel;
333
334 /**
335 * Public key of the remote service, only used by Bob
336 */
337 struct GNUNET_CRYPTO_PaillierPublicKey remote_pubkey;
338
339 /**
340 * Handle to a task that sends a msg to the our client
341 */
342 GNUNET_SCHEDULER_TaskIdentifier client_notification_task;
343
344 /**
345 * The computed scalar
346 */
347 gcry_mpi_t product;
348
349 /**
350 * how many elements we were supplied with from the client
351 */
352 uint32_t total;
353
354 /**
355 * how many elements actually are used for the scalar product.
356 * Size of the arrays in @e r and @e r_prime.
357 */
358 uint32_t used_element_count;
359
360 /**
361 * already transferred elements (sent/received) for multipart messages, less or equal than @e used_element_count for
362 */
363 uint32_t transferred_element_count;
364
365 /**
366 * Is this session active (#GNUNET_YES), Concluded (#GNUNET_NO), or had an error (#GNUNET_SYSERR)
367 */
368 int32_t active;
369
370 /**
371 * the role this peer has
372 */
373 enum PeerRole role;
374
375};
376
377
378/**
379 * GNUnet configuration handle
380 */
381static const struct GNUNET_CONFIGURATION_Handle * cfg;
382
383/**
384 * Handle to the core service (NULL until we've connected to it).
385 */
386static struct GNUNET_CADET_Handle *my_cadet;
387
388/**
389 * The identity of this host.
390 */
391static struct GNUNET_PeerIdentity me;
392
393/**
394 * Service's own public key
395 */
396static struct GNUNET_CRYPTO_PaillierPublicKey my_pubkey;
397
398/**
399 * Service's own private key
400 */
401static struct GNUNET_CRYPTO_PaillierPrivateKey my_privkey;
402
403/**
404 * Service's offset for values that could possibly be negative but are plaintext for encryption.
405 */
406static gcry_mpi_t my_offset;
407
408/**
409 * Head of our double linked list for client-requests sent to us.
410 * for all of these elements we calculate a scalar product with a remote peer
411 * split between service->service and client->service for simplicity
412 */
413static struct ServiceSession *from_client_head;
414
415/**
416 * Tail of our double linked list for client-requests sent to us.
417 * for all of these elements we calculate a scalar product with a remote peer
418 * split between service->service and client->service for simplicity
419 */
420static struct ServiceSession *from_client_tail;
421
422/**
423 * Head of our double linked list for service-requests sent to us.
424 * for all of these elements we help the requesting service in calculating a scalar product
425 * split between service->service and client->service for simplicity
426 */
427static struct ServiceSession *from_service_head;
428
429/**
430 * Tail of our double linked list for service-requests sent to us.
431 * for all of these elements we help the requesting service in calculating a scalar product
432 * split between service->service and client->service for simplicity
433 */
434static struct ServiceSession *from_service_tail;
435
436/**
437 * Certain events (callbacks for server & cadet operations) must not be queued after shutdown.
438 */
439static int do_shutdown;
440
441
442/**
443 * Send a multi part chunk of a service request from alice to bob.
444 * This element only contains a part of the elements-vector (session->a[]),
445 * mask and public key set have to be contained within the first message
446 *
447 * This allows a ~32kbit key length while using 32000 elements or 62000 elements per request.
448 *
449 * @param cls the associated service session
450 */
451static void
452prepare_alices_cyrptodata_message_multipart (void *cls);
453
454
455/**
456 * Send a multi part chunk of a service response from Bob to Alice.
457 * This element only contains the two permutations of R, R'.
458 *
459 * @param cls the associated service session
460 */
461static void
462prepare_bobs_cryptodata_message_multipart (void *cls);
463
464
465/**
466 * Computes the square sum over a vector of a given length.
467 *
468 * @param vector the vector to encrypt
469 * @param length the length of the vector
470 * @return an MPI value containing the calculated sum, never NULL
471 */
472static gcry_mpi_t
473compute_square_sum (gcry_mpi_t *vector,
474 uint32_t length)
475{
476 gcry_mpi_t elem;
477 gcry_mpi_t sum;
478 uint32_t i;
479
480 GNUNET_assert (NULL != (sum = gcry_mpi_new (0)));
481 GNUNET_assert (NULL != (elem = gcry_mpi_new (0)));
482 for (i = 0; i < length; i++)
483 {
484 gcry_mpi_mul (elem, vector[i], vector[i]);
485 gcry_mpi_add (sum, sum, elem);
486 }
487 gcry_mpi_release (elem);
488 return sum;
489}
490
491
492/**
493 * Safely frees ALL memory areas referenced by a session.
494 *
495 * @param session - the session to free elements from
496 */
497static void
498free_session_variables (struct ServiceSession *s)
499{
500 struct SortedValue *e;
501
502 while (NULL != (e = s->a_head))
503 {
504 GNUNET_free (e->elem);
505 gcry_mpi_release (e->val);
506 GNUNET_CONTAINER_DLL_remove (s->a_head,
507 s->a_tail,
508 e);
509 GNUNET_free (e);
510 }
511 if (NULL != s->intersected_elements)
512 {
513 GNUNET_CONTAINER_multihashmap_destroy (s->intersected_elements);
514 /* elements are freed independently in above loop over a_head */
515 s->intersected_elements = NULL;
516 }
517 if (NULL != s->intersection_listen)
518 {
519 GNUNET_SET_listen_cancel (s->intersection_listen);
520 s->intersection_listen = NULL;
521 }
522 if (NULL != s->intersection_op)
523 {
524 GNUNET_SET_operation_cancel (s->intersection_op);
525 s->intersection_op = NULL;
526 }
527 if (NULL != s->intersection_set)
528 {
529 GNUNET_SET_destroy (s->intersection_set);
530 s->intersection_set = NULL;
531 }
532 if (NULL != s->e_a)
533 {
534 GNUNET_free (s->e_a);
535 s->e_a = NULL;
536 }
537 if (NULL != s->sorted_elements)
538 {
539 GNUNET_free (s->sorted_elements);
540 s->sorted_elements = NULL;
541 }
542 if (NULL != s->msg)
543 {
544 GNUNET_free (s->msg);
545 s->msg = NULL;
546 }
547 if (NULL != s->r)
548 {
549 GNUNET_free (s->r);
550 s->r = NULL;
551 }
552 if (NULL != s->r_prime)
553 {
554 GNUNET_free (s->r_prime);
555 s->r_prime = NULL;
556 }
557 if (NULL != s->product)
558 {
559 gcry_mpi_release (s->product);
560 s->product = NULL;
561 }
562}
563
564
565/**
566 * Primitive callback for copying over a message, as they usually are
567 * too complex to be handled in the callback itself. Clears a
568 * session-callback, if a session was handed over and the transmit
569 * handle was stored.
570 *
571 * @param cls the session containing the message object
572 * @param size the size of the @a buf we got
573 * @param buf the buffer to copy the message to
574 * @return 0 if we couldn't copy, else the size copied over
575 */
576static size_t
577cb_transfer_message (void *cls,
578 size_t size,
579 void *buf)
580{
581 struct ServiceSession *s = cls;
582 uint16_t type;
583
584 s->client_transmit_handle = NULL;
585 GNUNET_assert (buf);
586 if (ntohs (s->msg->size) > size)
587 {
588 GNUNET_break (0);
589 return 0;
590 }
591 size = ntohs (s->msg->size);
592 type = ntohs (s->msg->type);
593 memcpy (buf,
594 s->msg,
595 size);
596 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
597 "Sending a message of type %u.\n",
598 (unsigned int) type);
599 GNUNET_free (s->msg);
600 s->msg = NULL;
601
602 switch (type)
603 {
604 case GNUNET_MESSAGE_TYPE_SCALARPRODUCT_RESULT:
605 free_session_variables (s);
606 // FIXME: that does not fully clean up 's'
607 break;
608 case GNUNET_MESSAGE_TYPE_SCALARPRODUCT_SESSION_INITIALIZATION:
609 break;
610 case GNUNET_MESSAGE_TYPE_SCALARPRODUCT_ALICE_CRYPTODATA:
611 case GNUNET_MESSAGE_TYPE_SCALARPRODUCT_ALICE_CRYPTODATA_MULTIPART:
612 if (s->used_element_count != s->transferred_element_count)
613 prepare_alices_cyrptodata_message_multipart (s);
614 else
615 s->channel = NULL;
616 break;
617 case GNUNET_MESSAGE_TYPE_SCALARPRODUCT_BOB_CRYPTODATA:
618 case GNUNET_MESSAGE_TYPE_SCALARPRODUCT_BOB_CRYPTODATA_MULTIPART:
619 if (s->used_element_count != s->transferred_element_count)
620 prepare_bobs_cryptodata_message_multipart (s);
621 else
622 s->channel = NULL;
623 break;
624 default:
625 GNUNET_assert (0);
626 }
627 return size;
628}
629
630
631/**
632 * Finds a not terminated client/service session in the
633 * given DLL based on session key, element count and state.
634 *
635 * FIXME: Use hashmap based on key instead of linear search.
636 *
637 * @param tail - the tail of the DLL
638 * @param key - the key we want to search for
639 * @param peerid - a pointer to the peer ID of the associated peer, NULL to ignore
640 * @return a pointer to a matching session, or NULL
641 */
642static struct ServiceSession *
643find_matching_session (struct ServiceSession *tail,
644 const struct GNUNET_HashCode *key,
645 const struct GNUNET_PeerIdentity *peerid)
646{
647 struct ServiceSession * s;
648
649 for (s = tail; NULL != s; s = s->prev)
650 {
651 // if the key matches, and the element_count is same
652 if (0 == memcmp (&s->session_id, key, sizeof (struct GNUNET_HashCode)))
653 {
654 // if peerid is NULL OR same as the peer Id in the queued request
655 if ((NULL == peerid)
656 || (0 == memcmp (&s->peer, peerid, sizeof (struct GNUNET_PeerIdentity))))
657 // matches and is not an already terminated session
658 return s;
659 }
660 }
661
662 return NULL;
663}
664
665
666/**
667 * A client disconnected.
668 *
669 * Remove the associated session(s), release data structures
670 * and cancel pending outgoing transmissions to the client.
671 * if the session has not yet completed, we also cancel Alice's request to Bob.
672 *
673 * @param cls closure, NULL
674 * @param client identification of the client
675 */
676static void
677cb_client_disconnect (void *cls,
678 struct GNUNET_SERVER_Client *client)
679{
680 struct ServiceSession *s;
681
682 if (NULL == client)
683 return;
684 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
685 "Client %p disconnected from us.\n",
686 client);
687 s = GNUNET_SERVER_client_get_user_context (client,
688 struct ServiceSession);
689 if (NULL == s)
690 return;
691 GNUNET_CONTAINER_DLL_remove (from_client_head,
692 from_client_tail,
693 s);
694 if (NULL != s->service_transmit_handle)
695 {
696 GNUNET_CADET_notify_transmit_ready_cancel (s->service_transmit_handle);
697 s->service_transmit_handle = NULL;
698 }
699 if (NULL != s->channel)
700 {
701 GNUNET_CADET_channel_destroy (s->channel);
702 s->channel = NULL;
703 }
704 if (GNUNET_SCHEDULER_NO_TASK != s->client_notification_task)
705 {
706 GNUNET_SCHEDULER_cancel (s->client_notification_task);
707 s->client_notification_task = GNUNET_SCHEDULER_NO_TASK;
708 }
709 if (NULL != s->client_transmit_handle)
710 {
711 GNUNET_SERVER_notify_transmit_ready_cancel (s->client_transmit_handle);
712 s->client_transmit_handle = NULL;
713 }
714 free_session_variables (s);
715 GNUNET_free (s);
716}
717
718
719/**
720 * Notify the client that the session has succeeded or failed completely.
721 * This message gets sent to
722 * - Alice's client if Bob disconnected or to
723 * - Bob's client if the operation completed or Alice disconnected
724 *
725 * @param cls the associated client session
726 * @param tc the task context handed to us by the scheduler, unused
727 */
728static void
729prepare_client_end_notification (void *cls,
730 const struct GNUNET_SCHEDULER_TaskContext *tc)
731{
732 struct ServiceSession *session = cls;
733 struct ClientResponseMessage *msg;
734
735 session->client_notification_task = GNUNET_SCHEDULER_NO_TASK;
736
737 msg = GNUNET_new (struct ClientResponseMessage);
738 msg->header.size = htons (sizeof (struct ClientResponseMessage));
739 msg->header.type = htons (GNUNET_MESSAGE_TYPE_SCALARPRODUCT_RESULT);
740 // signal error if not signalized, positive result-range field but zero length.
741 msg->product_length = htonl (0);
742 msg->status = htonl (session->active);
743 session->msg = &msg->header;
744
745 //transmit this message to our client
746 session->client_transmit_handle
747 = GNUNET_SERVER_notify_transmit_ready (session->client,
748 sizeof (struct ClientResponseMessage),
749 GNUNET_TIME_UNIT_FOREVER_REL,
750 &cb_transfer_message,
751 session);
752
753 // if we could not even queue our request, something is wrong
754 if (NULL == session->client_transmit_handle)
755 {
756 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
757 _("Could not send message to client (%p)!\n"),
758 session->client);
759 GNUNET_SERVER_client_disconnect (session->client);
760 free_session_variables (session);
761 GNUNET_CONTAINER_DLL_remove (from_client_head,
762 from_client_tail,
763 session);
764 GNUNET_free (session);
765 return;
766 }
767 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
768 _("Sending session-end notification to client (%p) for session %s\n"),
769 session->client,
770 GNUNET_h2s (&session->session_id));
771}
772
773
774/**
775 * Executed by Alice, fills in a service-request message and sends it
776 * to the given peer.
777 *
778 * @param cls the session associated with this request
779 */
780static void
781prepare_alices_cyrptodata_message (void *cls)
782{
783 struct ServiceSession *session = cls;
784 struct AliceCryptodataMessage * msg;
785 struct GNUNET_CRYPTO_PaillierCiphertext * payload;
786 unsigned int i;
787 uint32_t msg_length;
788 gcry_mpi_t a;
789
790 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
791 "Successfully created new channel to peer (%s)!\n",
792 GNUNET_i2s (&session->peer));
793
794 msg_length = sizeof (struct AliceCryptodataMessage)
795 + session->used_element_count * sizeof (struct GNUNET_CRYPTO_PaillierCiphertext);
796
797 if (GNUNET_SERVER_MAX_MESSAGE_SIZE > msg_length)
798 {
799 session->transferred_element_count = session->used_element_count;
800 }
801 else
802 {
803 //create a multipart msg, first we calculate a new msg size for the head msg
804 session->transferred_element_count = (GNUNET_SERVER_MAX_MESSAGE_SIZE - 1 - sizeof (struct AliceCryptodataMessage))
805 / sizeof (struct GNUNET_CRYPTO_PaillierCiphertext);
806 msg_length = sizeof (struct AliceCryptodataMessage)
807 + session->transferred_element_count * sizeof (struct GNUNET_CRYPTO_PaillierCiphertext);
808 }
809
810 msg = GNUNET_malloc (msg_length);
811 msg->header.size = htons (msg_length);
812 msg->header.type = htons (GNUNET_MESSAGE_TYPE_SCALARPRODUCT_ALICE_CRYPTODATA);
813 msg->contained_element_count = htonl (session->transferred_element_count);
814
815 // fill in the payload
816 payload = (struct GNUNET_CRYPTO_PaillierCiphertext *) &msg[1];
817
818 // now copy over the sorted element vector
819 a = gcry_mpi_new (0);
820 for (i = 0; i < session->transferred_element_count; i++)
821 {
822 gcry_mpi_add (a, session->sorted_elements[i], my_offset);
823 GNUNET_CRYPTO_paillier_encrypt (&my_pubkey, a, 3, &payload[i]);
824 }
825 gcry_mpi_release (a);
826
827 session->msg = (struct GNUNET_MessageHeader *) msg;
828 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
829 "Transmitting service request.\n");
830
831 //transmit via cadet messaging
832 session->service_transmit_handle
833 = GNUNET_CADET_notify_transmit_ready (session->channel,
834 GNUNET_YES,
835 GNUNET_TIME_UNIT_FOREVER_REL,
836 msg_length,
837 &cb_transfer_message,
838 session);
839 if (NULL == session->service_transmit_handle)
840 {
841 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
842 _("Could not send message to channel!\n"));
843 GNUNET_free (msg);
844 session->msg = NULL;
845 session->active = GNUNET_SYSERR;
846 session->client_notification_task
847 = GNUNET_SCHEDULER_add_now (&prepare_client_end_notification,
848 session);
849 return;
850 }
851}
852
853
854/**
855 * Send a multipart chunk of a service response from bob to alice.
856 * This element only contains the two permutations of R, R'.
857 *
858 * @param cls the associated service session
859 */
860static void
861prepare_bobs_cryptodata_message_multipart (void *cls)
862{
863 struct ServiceSession *session = cls;
864 struct GNUNET_CRYPTO_PaillierCiphertext * payload;
865 struct MultipartMessage * msg;
866 unsigned int i;
867 unsigned int j;
868 uint32_t msg_length;
869 uint32_t todo_count;
870
871 msg_length = sizeof (struct MultipartMessage);
872 todo_count = session->used_element_count - session->transferred_element_count;
873
874 if (todo_count > MULTIPART_ELEMENT_CAPACITY / 2)
875 // send the currently possible maximum chunk, we always transfer both permutations
876 todo_count = MULTIPART_ELEMENT_CAPACITY / 2;
877
878 msg_length += todo_count * sizeof (struct GNUNET_CRYPTO_PaillierCiphertext) * 2;
879 msg = GNUNET_malloc (msg_length);
880 msg->header.type = htons (GNUNET_MESSAGE_TYPE_SCALARPRODUCT_ALICE_CRYPTODATA_MULTIPART);
881 msg->header.size = htons (msg_length);
882 msg->contained_element_count = htonl (todo_count);
883
884 payload = (struct GNUNET_CRYPTO_PaillierCiphertext *) &msg[1];
885 for (i = session->transferred_element_count, j = 0; i < session->transferred_element_count + todo_count; i++)
886 {
887 //r[i][p] and r[i][q]
888 memcpy (&payload[j++],
889 &session->r[i],
890 sizeof (struct GNUNET_CRYPTO_PaillierCiphertext));
891 memcpy (&payload[j++],
892 &session->r_prime[i],
893 sizeof (struct GNUNET_CRYPTO_PaillierCiphertext));
894 }
895 session->transferred_element_count += todo_count;
896 session->msg = (struct GNUNET_MessageHeader *) msg;
897 session->service_transmit_handle
898 = GNUNET_CADET_notify_transmit_ready (session->channel,
899 GNUNET_YES,
900 GNUNET_TIME_UNIT_FOREVER_REL,
901 msg_length,
902 &cb_transfer_message,
903 session);
904 if (NULL == session->service_transmit_handle)
905 {
906 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
907 _("Could not send service-response message via CADET!)\n"));
908
909 GNUNET_free (msg);
910 session->msg = NULL;
911 GNUNET_CADET_channel_destroy (session->channel);
912 session->response->active = GNUNET_SYSERR;
913
914 GNUNET_CONTAINER_DLL_remove (from_service_head,
915 from_service_tail,
916 session);
917 session->response->client_notification_task
918 = GNUNET_SCHEDULER_add_now (&prepare_client_end_notification,
919 session->response);
920 free_session_variables (session);
921 GNUNET_free (session);
922 return;
923 }
924 if (session->transferred_element_count == session->used_element_count)
925 {
926 // final part
927 session->active = GNUNET_NO;
928 GNUNET_free (session->r_prime);
929 GNUNET_free (session->r);
930 session->r_prime = NULL;
931 session->r = NULL;
932 }
933}
934
935
936/**
937 * Bob executes:
938 * generates the response message to be sent to alice after computing
939 * the values (1), (2), S and S'
940 * (1)[]: $E_A(a_{pi(i)}) times E_A(- r_{pi(i)} - b_{pi(i)}) &= E_A(a_{pi(i)} - r_{pi(i)} - b_{pi(i)})$
941 * (2)[]: $E_A(a_{pi'(i)}) times E_A(- r_{pi'(i)}) &= E_A(a_{pi'(i)} - r_{pi'(i)})$
942 * S: $S := E_A(sum (r_i + b_i)^2)$
943 * S': $S' := E_A(sum r_i^2)$
944 *
945 * @param session the associated requesting session with alice
946 */
947static void
948prepare_bobs_cryptodata_message (void *cls,
949 const struct GNUNET_SCHEDULER_TaskContext *tc)
950{
951 struct ServiceSession * s = cls;
952 struct ServiceResponseMessage *msg;
953 uint32_t msg_length = 0;
954 struct GNUNET_CRYPTO_PaillierCiphertext *payload;
955 unsigned int i;
956
957 msg_length = sizeof (struct ServiceResponseMessage)
958 + 2 * sizeof (struct GNUNET_CRYPTO_PaillierCiphertext); // s, stick
959
960 if (GNUNET_SERVER_MAX_MESSAGE_SIZE >
961 msg_length + 2 * s->used_element_count * sizeof (struct GNUNET_CRYPTO_PaillierCiphertext))
962 { //r, r'
963 msg_length += 2 * s->used_element_count * sizeof (struct GNUNET_CRYPTO_PaillierCiphertext);
964 s->transferred_element_count = s->used_element_count;
965 }
966 else
967 s->transferred_element_count = (GNUNET_SERVER_MAX_MESSAGE_SIZE - 1 - msg_length) /
968 (sizeof (struct GNUNET_CRYPTO_PaillierCiphertext) * 2);
969
970 msg = GNUNET_malloc (msg_length);
971 msg->header.type = htons (GNUNET_MESSAGE_TYPE_SCALARPRODUCT_BOB_CRYPTODATA);
972 msg->header.size = htons (msg_length);
973 msg->total_element_count = htonl (s->total);
974 msg->used_element_count = htonl (s->used_element_count);
975 msg->contained_element_count = htonl (s->transferred_element_count);
976 msg->key = s->session_id;
977
978 payload = (struct GNUNET_CRYPTO_PaillierCiphertext *) &msg[1];
979 memcpy (&payload[0],
980 &s->s,
981 sizeof (struct GNUNET_CRYPTO_PaillierCiphertext));
982 memcpy (&payload[1],
983 &s->s_prime,
984 sizeof (struct GNUNET_CRYPTO_PaillierCiphertext));
985
986 payload = &payload[2];
987 // convert k[][]
988 for (i = 0; i < s->transferred_element_count; i++)
989 {
990 //k[i][p] and k[i][q]
991 memcpy (&payload[i * 2],
992 &s->r[i],
993 sizeof (struct GNUNET_CRYPTO_PaillierCiphertext));
994 memcpy (&payload[i * 2 + 1],
995 &s->r_prime[i],
996 sizeof (struct GNUNET_CRYPTO_PaillierCiphertext));
997 }
998
999 s->msg = (struct GNUNET_MessageHeader *) msg;
1000 s->service_transmit_handle
1001 = GNUNET_CADET_notify_transmit_ready (s->channel,
1002 GNUNET_YES,
1003 GNUNET_TIME_UNIT_FOREVER_REL,
1004 msg_length,
1005 &cb_transfer_message,
1006 s);
1007 if (NULL == s->service_transmit_handle)
1008 {
1009 //disconnect our client
1010 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1011 _("Could not send service-response message via cadet!)\n"));
1012
1013 GNUNET_free (msg);
1014 s->msg = NULL;
1015 GNUNET_CONTAINER_DLL_remove (from_service_head,
1016 from_service_tail,
1017 s);
1018 GNUNET_CADET_channel_destroy(s->channel);
1019 s->response->active = GNUNET_SYSERR;
1020
1021 s->response->client_notification_task =
1022 GNUNET_SCHEDULER_add_now (&prepare_client_end_notification,
1023 s->response);
1024 free_session_variables (s);
1025 GNUNET_free(s);
1026 return;
1027 }
1028 if (s->transferred_element_count != s->used_element_count)
1029 {
1030 // multipart
1031 }
1032 else
1033 {
1034 //singlepart
1035 s->active = GNUNET_NO;
1036 GNUNET_free (s->r);
1037 s->r = NULL;
1038 GNUNET_free (s->r_prime);
1039 s->r_prime = NULL;
1040 }
1041}
1042
1043
1044/**
1045 * executed by bob:
1046 * compute the values
1047 * (1)[]: $E_A(a_{pi(i)}) otimes E_A(- r_{pi(i)} - b_{pi(i)}) &= E_A(a_{pi(i)} - r_{pi(i)} - b_{pi(i)})$
1048 * (2)[]: $E_A(a_{pi'(i)}) otimes E_A(- r_{pi'(i)}) &= E_A(a_{pi'(i)} - r_{pi'(i)})$
1049 * S: $S := E_A(sum (r_i + b_i)^2)$
1050 * S': $S' := E_A(sum r_i^2)$
1051 *
1052 * @param request the requesting session + bob's requesting peer
1053 */
1054static void
1055compute_service_response (struct ServiceSession *session)
1056{
1057 int i;
1058 unsigned int *p;
1059 unsigned int *q;
1060 uint32_t count;
1061 gcry_mpi_t *rand;
1062 gcry_mpi_t tmp;
1063 gcry_mpi_t *b;
1064 struct GNUNET_CRYPTO_PaillierCiphertext *a;
1065 struct GNUNET_CRYPTO_PaillierCiphertext *r;
1066 struct GNUNET_CRYPTO_PaillierCiphertext *r_prime;
1067
1068 count = session->used_element_count;
1069 a = session->e_a;
1070 b = session->sorted_elements;
1071 q = GNUNET_CRYPTO_random_permute (GNUNET_CRYPTO_QUALITY_WEAK,
1072 count);
1073 p = GNUNET_CRYPTO_random_permute (GNUNET_CRYPTO_QUALITY_WEAK,
1074 count);
1075 rand = GNUNET_malloc (sizeof (gcry_mpi_t) * count);
1076 for (i = 0; i < count; i++)
1077 GNUNET_assert (NULL != (rand[i] = gcry_mpi_new (0)));
1078 r = GNUNET_malloc (sizeof (struct GNUNET_CRYPTO_PaillierCiphertext) * count);
1079 r_prime = GNUNET_malloc (sizeof (struct GNUNET_CRYPTO_PaillierCiphertext) * count);
1080
1081 for (i = 0; i < count; i++)
1082 {
1083 int32_t svalue;
1084
1085 svalue = (int32_t) GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_WEAK,
1086 UINT32_MAX);
1087 // long to gcry_mpi_t
1088 if (svalue < 0)
1089 gcry_mpi_sub_ui (rand[i],
1090 rand[i],
1091 - svalue);
1092 else
1093 rand[i] = gcry_mpi_set_ui (rand[i], svalue);
1094 }
1095
1096 tmp = gcry_mpi_new (0);
1097 // encrypt the element
1098 // for the sake of readability I decided to have dedicated permutation
1099 // vectors, which get rid of all the lookups in p/q.
1100 // however, ap/aq are not absolutely necessary but are just abstraction
1101 // Calculate Kp = E(S + a_pi) (+) E(S - r_pi - b_pi)
1102 for (i = 0; i < count; i++)
1103 {
1104 // E(S - r_pi - b_pi)
1105 gcry_mpi_sub (tmp, my_offset, rand[p[i]]);
1106 gcry_mpi_sub (tmp, tmp, b[p[i]]);
1107 GNUNET_CRYPTO_paillier_encrypt (&session->remote_pubkey,
1108 tmp,
1109 2,
1110 &r[i]);
1111
1112 // E(S - r_pi - b_pi) * E(S + a_pi) == E(2*S + a - r - b)
1113 GNUNET_CRYPTO_paillier_hom_add (&session->remote_pubkey,
1114 &r[i],
1115 &a[p[i]],
1116 &r[i]);
1117 }
1118
1119 // Calculate Kq = E(S + a_qi) (+) E(S - r_qi)
1120 for (i = 0; i < count; i++)
1121 {
1122 // E(S - r_qi)
1123 gcry_mpi_sub (tmp, my_offset, rand[q[i]]);
1124 GNUNET_assert (2 == GNUNET_CRYPTO_paillier_encrypt (&session->remote_pubkey,
1125 tmp,
1126 2,
1127 &r_prime[i]));
1128
1129 // E(S - r_qi) * E(S + a_qi) == E(2*S + a_qi - r_qi)
1130 GNUNET_assert (1 == GNUNET_CRYPTO_paillier_hom_add (&session->remote_pubkey,
1131 &r_prime[i],
1132 &a[q[i]],
1133 &r_prime[i]));
1134 }
1135
1136 // Calculate S' = E(SUM( r_i^2 ))
1137 tmp = compute_square_sum (rand, count);
1138 GNUNET_CRYPTO_paillier_encrypt (&session->remote_pubkey,
1139 tmp,
1140 1,
1141 &session->s_prime);
1142
1143 // Calculate S = E(SUM( (r_i + b_i)^2 ))
1144 for (i = 0; i < count; i++)
1145 gcry_mpi_add (rand[i], rand[i], b[i]);
1146 tmp = compute_square_sum (rand, count);
1147 GNUNET_CRYPTO_paillier_encrypt (&session->remote_pubkey,
1148 tmp,
1149 1,
1150 &session->s);
1151
1152 session->r = r;
1153 session->r_prime = r_prime;
1154
1155 // release rand, b and a
1156 for (i = 0; i < count; i++)
1157 {
1158 gcry_mpi_release (rand[i]);
1159 gcry_mpi_release (b[i]);
1160 }
1161 gcry_mpi_release (tmp);
1162 GNUNET_free (session->e_a);
1163 session->e_a = NULL;
1164 GNUNET_free (p);
1165 GNUNET_free (q);
1166 GNUNET_free (b);
1167 GNUNET_free (rand);
1168
1169 // copy the r[], r_prime[], S and Stick into a new message, prepare_service_response frees these
1170 GNUNET_SCHEDULER_add_now (&prepare_bobs_cryptodata_message,
1171 session);
1172}
1173
1174
1175/**
1176 * Iterator over all hash map entries in session->intersected_elements.
1177 *
1178 * @param cls closure
1179 * @param key current key code
1180 * @param value value in the hash map
1181 * @return #GNUNET_YES if we should continue to
1182 * iterate,
1183 * #GNUNET_NO if not.
1184 */
1185static int
1186cb_insert_element_sorted (void *cls,
1187 const struct GNUNET_HashCode *key,
1188 void *value)
1189{
1190 struct ServiceSession * s = cls;
1191 struct SortedValue * e = GNUNET_new (struct SortedValue);
1192 struct SortedValue * o = s->a_head;
1193 int64_t val;
1194
1195 e->elem = value;
1196 e->val = gcry_mpi_new (0);
1197 val = (int64_t) GNUNET_ntohll (e->elem->value);
1198 if (0 > val)
1199 gcry_mpi_sub_ui (e->val, e->val, -val);
1200 else
1201 gcry_mpi_add_ui (e->val, e->val, val);
1202
1203 // insert as first element with the lowest key
1204 if (NULL == s->a_head
1205 || (0 <= GNUNET_CRYPTO_hash_cmp (&s->a_head->elem->key,
1206 &e->elem->key)))
1207 {
1208 GNUNET_CONTAINER_DLL_insert (s->a_head,
1209 s->a_tail,
1210 e);
1211 return GNUNET_YES;
1212 }
1213 else if (0 > GNUNET_CRYPTO_hash_cmp (&s->a_tail->elem->key,
1214 &e->elem->key))
1215 {
1216 // insert as last element with the highest key
1217 GNUNET_CONTAINER_DLL_insert_tail (s->a_head,
1218 s->a_tail,
1219 e);
1220 return GNUNET_YES;
1221 }
1222 // insert before the first higher/equal element
1223 do
1224 {
1225 if (0 <= GNUNET_CRYPTO_hash_cmp (&o->elem->key,
1226 &e->elem->key))
1227 {
1228 GNUNET_CONTAINER_DLL_insert_before (s->a_head,
1229 s->a_tail,
1230 o,
1231 e);
1232 return GNUNET_YES;
1233 }
1234 o = o->next;
1235 }
1236 while (NULL != o);
1237 // broken DLL
1238 GNUNET_assert (0);
1239}
1240
1241
1242/**
1243 * Callback for set operation results. Called for each element
1244 * in the result set.
1245 *
1246 * @param cls closure
1247 * @param element a result element, only valid if status is #GNUNET_SET_STATUS_OK
1248 * @param status see `enum GNUNET_SET_Status`
1249 */
1250static void
1251cb_intersection_element_removed (void *cls,
1252 const struct GNUNET_SET_Element *element,
1253 enum GNUNET_SET_Status status)
1254{
1255 struct ServiceSession * s = cls;
1256 struct GNUNET_SCALARPRODUCT_Element * se;
1257 int i;
1258
1259 switch (status)
1260 {
1261 case GNUNET_SET_STATUS_OK:
1262 //this element has been removed from the set
1263 se = GNUNET_CONTAINER_multihashmap_get (s->intersected_elements,
1264 element->data);
1265
1266 GNUNET_CONTAINER_multihashmap_remove (s->intersected_elements,
1267 element->data,
1268 se);
1269 LOG (GNUNET_ERROR_TYPE_DEBUG,
1270 "%s: removed element with key %s value %d\n",
1271 s->role == ALICE ? "ALICE" : "BOB",
1272 GNUNET_h2s(&se->key),
1273 se->value);
1274 return;
1275
1276 case GNUNET_SET_STATUS_DONE:
1277 s->intersection_op = NULL;
1278 s->intersection_set = NULL;
1279
1280 s->used_element_count
1281 = GNUNET_CONTAINER_multihashmap_iterate (s->intersected_elements,
1282 &cb_insert_element_sorted,
1283 s);
1284 LOG (GNUNET_ERROR_TYPE_DEBUG,
1285 "%s: Finished intersection, %d items remain\n",
1286 s->role == ALICE ? "ALICE" : "BOB",
1287 s->used_element_count);
1288 if (2 > s->used_element_count)
1289 {
1290 // failed! do not leak information about our single remaining element!
1291 // continue after the loop
1292 break;
1293 }
1294
1295 s->sorted_elements = GNUNET_malloc (s->used_element_count * sizeof (gcry_mpi_t));
1296 for (i = 0; NULL != s->a_head; i++)
1297 {
1298 struct SortedValue* a = s->a_head;
1299 GNUNET_assert (i < s->used_element_count);
1300
1301 s->sorted_elements[i] = a->val;
1302 GNUNET_CONTAINER_DLL_remove (s->a_head, s->a_tail, a);
1303 GNUNET_free (a->elem);
1304 }
1305 GNUNET_assert (i == s->used_element_count);
1306
1307 if (ALICE == s->role) {
1308 prepare_alices_cyrptodata_message (s);
1309 return;
1310 }
1311 else if (s->used_element_count == s->transferred_element_count)
1312 {
1313 compute_service_response (s);
1314 return;
1315 }
1316 break;
1317 default:
1318 LOG (GNUNET_ERROR_TYPE_DEBUG, "%s: OOOPS %d", s->role == ALICE ? "ALICE" : "BOB", status);
1319 if (NULL != s->intersection_listen)
1320 {
1321 GNUNET_SET_listen_cancel (s->intersection_listen);
1322 s->intersection_listen = NULL;
1323 }
1324
1325 // the op failed and has already been invalidated by the set service
1326 break;
1327 }
1328
1329 s->intersection_op = NULL;
1330 s->intersection_set = NULL;
1331
1332 //failed if we go here
1333 GNUNET_break_op (0);
1334
1335 // and notify our client-session that we could not complete the session
1336 if (ALICE == s->role) {
1337 s->active = GNUNET_SYSERR;
1338 s->client_notification_task =
1339 GNUNET_SCHEDULER_add_now (&prepare_client_end_notification,
1340 s);
1341 }
1342 else
1343 {
1344 GNUNET_CONTAINER_DLL_remove (from_service_head,
1345 from_service_tail,
1346 s);
1347 free_session_variables (s);
1348 s->response->active = GNUNET_SYSERR;
1349 s->response->client_notification_task =
1350 GNUNET_SCHEDULER_add_now (&prepare_client_end_notification,
1351 s->response);
1352 GNUNET_free(s);
1353 }
1354}
1355
1356
1357/**
1358 * Called when another peer wants to do a set operation with the
1359 * local peer. If a listen error occurs, the @a request is NULL.
1360 *
1361 * @param cls closure
1362 * @param other_peer the other peer
1363 * @param context_msg message with application specific information from
1364 * the other peer
1365 * @param request request from the other peer (never NULL), use GNUNET_SET_accept()
1366 * to accept it, otherwise the request will be refused
1367 * Note that we can't just return value from the listen callback,
1368 * as it is also necessary to specify the set we want to do the
1369 * operation with, whith sometimes can be derived from the context
1370 * message. It's necessary to specify the timeout.
1371 */
1372static void
1373cb_intersection_request_alice (void *cls,
1374 const struct GNUNET_PeerIdentity *other_peer,
1375 const struct GNUNET_MessageHeader *context_msg,
1376 struct GNUNET_SET_Request *request)
1377{
1378 struct ServiceSession * s = cls;
1379
1380 s->intersection_op = GNUNET_SET_accept (request,
1381 GNUNET_SET_RESULT_REMOVED,
1382 cb_intersection_element_removed,
1383 s);
1384 if (NULL == s->intersection_op)
1385 {
1386 s->active = GNUNET_SYSERR;
1387 s->client_notification_task =
1388 GNUNET_SCHEDULER_add_now (&prepare_client_end_notification,
1389 s);
1390 return;
1391 }
1392 if (GNUNET_OK != GNUNET_SET_commit (s->intersection_op, s->intersection_set))
1393 {
1394 s->active = GNUNET_SYSERR;
1395 s->client_notification_task =
1396 GNUNET_SCHEDULER_add_now (&prepare_client_end_notification,
1397 s);
1398 return;
1399 }
1400 s->intersection_set = NULL;
1401 s->intersection_listen = NULL;
1402}
1403
1404
1405/**
1406 * prepare the response we will send to alice or bobs' clients.
1407 * in Bobs case the product will be NULL.
1408 *
1409 * @param cls the session associated with our client.
1410 * @param tc the task context handed to us by the scheduler, unused
1411 */
1412static void
1413prepare_client_response (void *cls,
1414 const struct GNUNET_SCHEDULER_TaskContext *tc)
1415{
1416 struct ServiceSession * s = cls;
1417 struct ClientResponseMessage *msg;
1418 unsigned char * product_exported = NULL;
1419 size_t product_length = 0;
1420 uint32_t msg_length = 0;
1421 int8_t range = -1;
1422 gcry_error_t rc;
1423 int sign;
1424
1425 s->client_notification_task = GNUNET_SCHEDULER_NO_TASK;
1426
1427 if (s->product)
1428 {
1429 gcry_mpi_t value = gcry_mpi_new (0);
1430
1431 sign = gcry_mpi_cmp_ui (s->product, 0);
1432 // libgcrypt can not handle a print of a negative number
1433 // if (a->sign) return gcry_error (GPG_ERR_INTERNAL); /* Can't handle it yet. */
1434 if (0 > sign)
1435 {
1436 gcry_mpi_sub (value, value, s->product);
1437 }
1438 else if (0 < sign)
1439 {
1440 range = 1;
1441 gcry_mpi_add (value, value, s->product);
1442 }
1443 else
1444 range = 0;
1445
1446 gcry_mpi_release (s->product);
1447 s->product = NULL;
1448
1449 // get representation as string
1450 if (range
1451 && (0 != (rc = gcry_mpi_aprint (GCRYMPI_FMT_STD,
1452 &product_exported,
1453 &product_length,
1454 value))))
1455 {
1456 LOG_GCRY (GNUNET_ERROR_TYPE_ERROR,
1457 "gcry_mpi_scan",
1458 rc);
1459 product_length = 0;
1460 range = -1; // signal error with product-length = 0 and range = -1
1461 }
1462 gcry_mpi_release (value);
1463 }
1464
1465 msg_length = sizeof (struct ClientResponseMessage) + product_length;
1466 msg = GNUNET_malloc (msg_length);
1467 if (NULL != product_exported)
1468 {
1469 memcpy (&msg[1],
1470 product_exported,
1471 product_length);
1472 GNUNET_free (product_exported);
1473 }
1474 msg->header.type = htons (GNUNET_MESSAGE_TYPE_SCALARPRODUCT_RESULT);
1475 msg->header.size = htons (msg_length);
1476 msg->range = range;
1477 msg->product_length = htonl (product_length);
1478 s->msg = (struct GNUNET_MessageHeader *) msg;
1479 s->client_transmit_handle =
1480 GNUNET_SERVER_notify_transmit_ready (s->client,
1481 msg_length,
1482 GNUNET_TIME_UNIT_FOREVER_REL,
1483 &cb_transfer_message,
1484 s);
1485 GNUNET_break (NULL != s->client_transmit_handle);
1486 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1487 "Sent result to client (%p), this session (%s) has ended!\n",
1488 s->client,
1489 GNUNET_h2s (&s->session_id));
1490}
1491
1492
1493/**
1494 * Executed by Alice, fills in a service-request message and sends it to the given peer
1495 *
1496 * @param session the session associated with this request
1497 */
1498static void
1499prepare_alices_computation_request (struct ServiceSession * s)
1500{
1501 struct ServiceRequestMessage * msg;
1502
1503 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1504 _("Successfully created new channel to peer (%s)!\n"),
1505 GNUNET_i2s (&s->peer));
1506
1507 msg = GNUNET_new (struct ServiceRequestMessage);
1508 msg->header.type = htons (GNUNET_MESSAGE_TYPE_SCALARPRODUCT_SESSION_INITIALIZATION);
1509 memcpy (&msg->session_id, &s->session_id, sizeof (struct GNUNET_HashCode));
1510 msg->header.size = htons (sizeof (struct ServiceRequestMessage));
1511
1512 s->msg = (struct GNUNET_MessageHeader *) msg;
1513 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
1514 _("Transmitting service request.\n"));
1515
1516 //transmit via cadet messaging
1517 s->service_transmit_handle
1518 = GNUNET_CADET_notify_transmit_ready (s->channel, GNUNET_YES,
1519 GNUNET_TIME_UNIT_FOREVER_REL,
1520 sizeof (struct ServiceRequestMessage),
1521 &cb_transfer_message,
1522 s);
1523 if (! s->service_transmit_handle)
1524 {
1525 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1526 _("Could not send message to channel!\n"));
1527 GNUNET_free (msg);
1528 s->msg = NULL;
1529 s->active = GNUNET_SYSERR;
1530 s->client_notification_task =
1531 GNUNET_SCHEDULER_add_now (&prepare_client_end_notification,
1532 s);
1533 return;
1534 }
1535}
1536
1537
1538/**
1539 * Send a multi part chunk of a service request from alice to bob.
1540 * This element only contains a part of the elements-vector (session->a[]),
1541 * mask and public key set have to be contained within the first message
1542 *
1543 * This allows a ~32kbit key length while using 32000 elements or 62000 elements per request.
1544 *
1545 * @param cls the associated service session
1546 */
1547static void
1548prepare_alices_cyrptodata_message_multipart (void *cls)
1549{
1550 struct ServiceSession * s = cls;
1551 struct MultipartMessage * msg;
1552 struct GNUNET_CRYPTO_PaillierCiphertext * payload;
1553 unsigned int i;
1554 uint32_t msg_length;
1555 uint32_t todo_count;
1556 gcry_mpi_t a;
1557
1558 msg_length = sizeof (struct MultipartMessage);
1559 todo_count = s->used_element_count - s->transferred_element_count;
1560
1561 if (todo_count > MULTIPART_ELEMENT_CAPACITY)
1562 // send the currently possible maximum chunk
1563 todo_count = MULTIPART_ELEMENT_CAPACITY;
1564
1565 msg_length += todo_count * sizeof (struct GNUNET_CRYPTO_PaillierCiphertext);
1566 msg = GNUNET_malloc (msg_length);
1567 msg->header.type = htons (GNUNET_MESSAGE_TYPE_SCALARPRODUCT_ALICE_CRYPTODATA_MULTIPART);
1568 msg->header.size = htons (msg_length);
1569 msg->contained_element_count = htonl (todo_count);
1570
1571 payload = (struct GNUNET_CRYPTO_PaillierCiphertext *) &msg[1];
1572
1573 // now copy over the sorted element vector
1574 a = gcry_mpi_new (0);
1575 for (i = s->transferred_element_count; i < todo_count; i++)
1576 {
1577 gcry_mpi_add (a, s->sorted_elements[i], my_offset);
1578 GNUNET_CRYPTO_paillier_encrypt (&my_pubkey, a, 3, &payload[i - s->transferred_element_count]);
1579 }
1580 gcry_mpi_release (a);
1581 s->transferred_element_count += todo_count;
1582
1583 s->msg = (struct GNUNET_MessageHeader *) msg;
1584 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1585 "Transmitting service request.\n");
1586
1587 //transmit via cadet messaging
1588 s->service_transmit_handle
1589 = GNUNET_CADET_notify_transmit_ready (s->channel,
1590 GNUNET_YES,
1591 GNUNET_TIME_UNIT_FOREVER_REL,
1592 msg_length,
1593 &cb_transfer_message,
1594 s);
1595 if (!s->service_transmit_handle)
1596 {
1597 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1598 _("Could not send service-request multipart message to channel!\n"));
1599 GNUNET_free (msg);
1600 s->msg = NULL;
1601 s->active = GNUNET_SYSERR;
1602 s->client_notification_task
1603 = GNUNET_SCHEDULER_add_now (&prepare_client_end_notification,
1604 s);
1605 return;
1606 }
1607}
1608
1609
1610/**
1611 * Our client has finished sending us its multipart message.
1612 *
1613 * @param session the service session context
1614 */
1615static void
1616client_request_complete_bob (struct ServiceSession * client_session)
1617{
1618 struct ServiceSession * s;
1619
1620 //check if service queue contains a matching request
1621 s = find_matching_session (from_service_tail,
1622 &client_session->session_id,
1623 NULL);
1624 if (NULL != s)
1625 {
1626 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1627 "Got client-responder-session with key %s and a matching service-request-session set, processing.\n",
1628 GNUNET_h2s (&client_session->session_id));
1629
1630 s->response = client_session;
1631 s->intersected_elements = client_session->intersected_elements;
1632 client_session->intersected_elements = NULL;
1633 s->intersection_set = client_session->intersection_set;
1634 client_session->intersection_set = NULL;
1635
1636 s->intersection_op = GNUNET_SET_prepare (&s->peer,
1637 &s->session_id,
1638 NULL,
1639 GNUNET_SET_RESULT_REMOVED,
1640 cb_intersection_element_removed,
1641 s);
1642
1643 GNUNET_SET_commit (s->intersection_op, s->intersection_set);
1644 }
1645 else
1646 {
1647 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1648 "Got client-responder-session with key %s but NO matching service-request-session set, queuing element for later use.\n",
1649 GNUNET_h2s (&client_session->session_id));
1650 // no matching session exists yet, store the response
1651 // for later processing by handle_service_request()
1652 }
1653}
1654
1655
1656/**
1657 * Our client has finished sending us its multipart message.
1658 *
1659 * @param session the service session context
1660 */
1661static void
1662client_request_complete_alice (struct ServiceSession * s)
1663{
1664 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
1665 _ ("Creating new channel for session with key %s.\n"),
1666 GNUNET_h2s (&s->session_id));
1667 s->channel = GNUNET_CADET_channel_create (my_cadet, s,
1668 &s->peer,
1669 GNUNET_APPLICATION_TYPE_SCALARPRODUCT,
1670 GNUNET_CADET_OPTION_RELIABLE);
1671 if (NULL == s->channel)
1672 {
1673 s->active = GNUNET_SYSERR;
1674 s->client_notification_task =
1675 GNUNET_SCHEDULER_add_now (&prepare_client_end_notification,
1676 s);
1677 return;
1678 }
1679 s->intersection_listen = GNUNET_SET_listen (cfg,
1680 GNUNET_SET_OPERATION_INTERSECTION,
1681 &s->session_id,
1682 cb_intersection_request_alice,
1683 s);
1684 if (NULL == s->intersection_listen)
1685 {
1686 s->active = GNUNET_SYSERR;
1687 s->client_notification_task =
1688 GNUNET_SCHEDULER_add_now (&prepare_client_end_notification,
1689 s);
1690 return;
1691 }
1692 prepare_alices_computation_request (s);
1693}
1694
1695
1696static void
1697handle_client_message_multipart (void *cls,
1698 struct GNUNET_SERVER_Client *client,
1699 const struct GNUNET_MessageHeader *message)
1700{
1701 const struct ComputationMultipartMessage * msg;
1702 struct ServiceSession *s;
1703 uint32_t contained_count;
1704 struct GNUNET_SCALARPRODUCT_Element *elements;
1705 uint32_t i;
1706
1707 msg = (const struct ComputationMultipartMessage *) message;
1708 // only one concurrent session per client connection allowed, simplifies logics a lot...
1709 s = GNUNET_SERVER_client_get_user_context (client, struct ServiceSession);
1710 if (NULL == s)
1711 {
1712 GNUNET_SERVER_receive_done (client, GNUNET_OK);
1713 return;
1714 }
1715
1716 contained_count = ntohl (msg->element_count_contained);
1717
1718 //sanity check: is the message as long as the message_count fields suggests?
1719 if ( (ntohs (msg->header.size) != (sizeof (struct ComputationMultipartMessage) + contained_count * sizeof (struct GNUNET_SCALARPRODUCT_Element))) ||
1720 (0 == contained_count) ||
1721 (s->total < s->transferred_element_count + contained_count))
1722 {
1723 GNUNET_break_op (0);
1724 GNUNET_SERVER_receive_done (client, GNUNET_OK);
1725 return;
1726 }
1727 s->transferred_element_count += contained_count;
1728
1729 elements = (struct GNUNET_SCALARPRODUCT_Element *) & msg[1];
1730 for (i = 0; i < contained_count; i++)
1731 {
1732 struct GNUNET_SET_Element set_elem;
1733 struct GNUNET_SCALARPRODUCT_Element * elem;
1734
1735 if (0 == GNUNET_ntohll (elements[i].value))
1736 continue;
1737
1738 elem = GNUNET_new (struct GNUNET_SCALARPRODUCT_Element);
1739 memcpy (elem, &elements[i], sizeof (struct GNUNET_SCALARPRODUCT_Element));
1740
1741 if (GNUNET_SYSERR == GNUNET_CONTAINER_multihashmap_put (s->intersected_elements,
1742 &elem->key,
1743 elem,
1744 GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY))
1745 {
1746 GNUNET_free (elem);
1747 continue;
1748 }
1749 set_elem.data = &elem->key;
1750 set_elem.size = sizeof (elem->key);
1751 set_elem.element_type = 0; /* do we REALLY need this? */
1752 GNUNET_SET_add_element (s->intersection_set, &set_elem, NULL, NULL);
1753 s->used_element_count++;
1754 }
1755
1756 GNUNET_SERVER_receive_done (client, GNUNET_OK);
1757
1758 if (s->total != s->transferred_element_count)
1759 // multipart msg
1760 return;
1761
1762 if (ALICE == s->role)
1763 client_request_complete_alice (s);
1764 else
1765 client_request_complete_bob (s);
1766}
1767
1768
1769/**
1770 * Handler for a client request message.
1771 * Can either be type A or B
1772 * A: request-initiation to compute a scalar product with a peer
1773 * B: response role, keep the values + session and wait for a matching session or process a waiting request
1774 *
1775 * @param cls closure
1776 * @param client identification of the client
1777 * @param message the actual message
1778 */
1779static void
1780handle_client_message (void *cls,
1781 struct GNUNET_SERVER_Client *client,
1782 const struct GNUNET_MessageHeader *message)
1783{
1784 const struct ComputationMessage * msg = (const struct ComputationMessage *) message;
1785 struct ServiceSession * s;
1786 uint32_t contained_count;
1787 uint32_t total_count;
1788 uint32_t msg_type;
1789 struct GNUNET_SCALARPRODUCT_Element * elements;
1790 uint32_t i;
1791
1792 // only one concurrent session per client connection allowed, simplifies logics a lot...
1793 s = GNUNET_SERVER_client_get_user_context (client, struct ServiceSession);
1794 if (NULL != s)
1795 {
1796 GNUNET_SERVER_receive_done (client, GNUNET_OK);
1797 return;
1798 }
1799
1800 msg_type = ntohs (msg->header.type);
1801 total_count = ntohl (msg->element_count_total);
1802 contained_count = ntohl (msg->element_count_contained);
1803
1804 if ((GNUNET_MESSAGE_TYPE_SCALARPRODUCT_CLIENT_TO_ALICE == msg_type)
1805 && (!memcmp (&msg->peer, &me, sizeof (struct GNUNET_PeerIdentity))))
1806 {
1807 //session with ourself makes no sense!
1808 GNUNET_break_op (0);
1809 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
1810 return;
1811 }
1812
1813 //sanity check: is the message as long as the message_count fields suggests?
1814 if ((ntohs (msg->header.size) !=
1815 (sizeof (struct ComputationMessage) + contained_count * sizeof (struct GNUNET_SCALARPRODUCT_Element)))
1816 || (0 == total_count))
1817 {
1818 GNUNET_break_op (0);
1819 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
1820 return;
1821 }
1822
1823 // do we have a duplicate session here already?
1824 if (NULL != find_matching_session (from_client_tail,
1825 &msg->session_key,
1826 NULL))
1827 {
1828 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
1829 _ ("Duplicate session information received, can not create new session with key `%s'\n"),
1830 GNUNET_h2s (&msg->session_key));
1831 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
1832 return;
1833 }
1834
1835 s = GNUNET_new (struct ServiceSession);
1836 s->active = GNUNET_YES;
1837 s->client_notification_task = GNUNET_SCHEDULER_NO_TASK;
1838 s->client = client;
1839 s->total = total_count;
1840 s->transferred_element_count = contained_count;
1841 // get our transaction key
1842 memcpy (&s->session_id, &msg->session_key, sizeof (struct GNUNET_HashCode));
1843
1844 elements = (struct GNUNET_SCALARPRODUCT_Element *) & msg[1];
1845 s->intersected_elements = GNUNET_CONTAINER_multihashmap_create (s->total, GNUNET_NO);
1846 s->intersection_set = GNUNET_SET_create (cfg, GNUNET_SET_OPERATION_INTERSECTION);
1847 for (i = 0; i < contained_count; i++)
1848 {
1849 struct GNUNET_SET_Element set_elem;
1850 struct GNUNET_SCALARPRODUCT_Element * elem;
1851
1852 if (0 == GNUNET_ntohll (elements[i].value))
1853 continue;
1854
1855 elem = GNUNET_new (struct GNUNET_SCALARPRODUCT_Element);
1856 memcpy (elem, &elements[i], sizeof (struct GNUNET_SCALARPRODUCT_Element));
1857
1858 if (GNUNET_SYSERR ==
1859 GNUNET_CONTAINER_multihashmap_put (s->intersected_elements,
1860 &elem->key,
1861 elem,
1862 GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY))
1863 {
1864 GNUNET_free (elem);
1865 continue;
1866 }
1867 set_elem.data = &elem->key;
1868 set_elem.size = sizeof (elem->key);
1869 set_elem.element_type = 0;
1870 GNUNET_SET_add_element (s->intersection_set, &set_elem, NULL, NULL);
1871 s->used_element_count++;
1872 }
1873
1874 if (GNUNET_MESSAGE_TYPE_SCALARPRODUCT_CLIENT_TO_ALICE == msg_type)
1875 {
1876 s->role = ALICE;
1877 memcpy (&s->peer,
1878 &msg->peer,
1879 sizeof (struct GNUNET_PeerIdentity));
1880 }
1881 else
1882 {
1883 s->role = BOB;
1884 }
1885
1886 GNUNET_CONTAINER_DLL_insert (from_client_head,
1887 from_client_tail,
1888 s);
1889 GNUNET_SERVER_client_set_user_context (client, s);
1890 GNUNET_SERVER_receive_done (client, GNUNET_YES);
1891
1892 if (s->total != s->transferred_element_count)
1893 // multipart msg
1894 return;
1895
1896 if (ALICE == s->role)
1897 client_request_complete_alice (s);
1898 else
1899 client_request_complete_bob (s);
1900}
1901
1902
1903/**
1904 * Function called for inbound channels.
1905 *
1906 * @param cls closure
1907 * @param channel new handle to the channel
1908 * @param initiator peer that started the channel
1909 * @param port unused
1910 * @param options unused
1911 * @return session associated with the channel
1912 */
1913static void *
1914cb_channel_incoming (void *cls,
1915 struct GNUNET_CADET_Channel *channel,
1916 const struct GNUNET_PeerIdentity *initiator,
1917 uint32_t port,
1918 enum GNUNET_CADET_ChannelOption options)
1919{
1920 struct ServiceSession *s;
1921
1922 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1923 _ ("New incoming channel from peer %s.\n"),
1924 GNUNET_i2s (initiator));
1925 s = GNUNET_new (struct ServiceSession);
1926 s->peer = *initiator;
1927 s->channel = channel;
1928 s->role = BOB;
1929 s->active = GNUNET_YES;
1930 return s;
1931}
1932
1933
1934/**
1935 * Function called whenever a channel is destroyed. Should clean up
1936 * any associated state.
1937 *
1938 * It must NOT call #GNUNET_CADET_channel_destroy() on the channel.
1939 *
1940 * @param cls closure (set from #GNUNET_CADET_connect())
1941 * @param channel connection to the other end (henceforth invalid)
1942 * @param channel_ctx place where local state associated
1943 * with the channel is stored
1944 */
1945static void
1946cb_channel_destruction (void *cls,
1947 const struct GNUNET_CADET_Channel *channel,
1948 void *channel_ctx)
1949{
1950 struct ServiceSession * s = channel_ctx;
1951 struct ServiceSession * client_session;
1952
1953 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1954 "Peer disconnected, terminating session %s with peer (%s)\n",
1955 GNUNET_h2s (&s->session_id),
1956 GNUNET_i2s (&s->peer));
1957
1958 // as we have only one peer connected in each session, just remove the session
1959 s->channel = NULL;
1960
1961 if ( (ALICE == s->role) &&
1962 (GNUNET_YES == s->active) &&
1963 (! do_shutdown) )
1964 {
1965 // if this happened before we received the answer, we must terminate the session
1966 s->role = GNUNET_SYSERR;
1967 s->client_notification_task =
1968 GNUNET_SCHEDULER_add_now (&prepare_client_end_notification,
1969 s);
1970 }
1971 else if ((BOB == s->role) && (GNUNET_SYSERR != s->active))
1972 {
1973 if ( (s == from_service_head) ||
1974 ( (NULL != from_service_head) &&
1975 ( (NULL != s->next) ||
1976 (NULL != s->a_tail)) ) )
1977 GNUNET_CONTAINER_DLL_remove (from_service_head,
1978 from_service_tail,
1979 s);
1980
1981 // there is a client waiting for this service session, terminate it, too!
1982 // i assume the tupel of key and element count is unique. if it was not the rest of the code would not work either.
1983 client_session = s->response;
1984 if ( (NULL != s->response ) &&
1985 (GNUNET_NO == s->active) &&
1986 (GNUNET_YES == client_session->active) )
1987 client_session->active = GNUNET_NO;
1988 free_session_variables (s);
1989
1990 // the client has to check if it was waiting for a result
1991 // or if it was a responder, no point in adding more statefulness
1992 if ((NULL != s->response ) && (! do_shutdown))
1993 {
1994 client_session->client_notification_task
1995 = GNUNET_SCHEDULER_add_now (&prepare_client_end_notification,
1996 client_session);
1997 }
1998 GNUNET_free (s);
1999 }
2000}
2001
2002
2003/**
2004 * Compute our scalar product, done by Alice
2005 *
2006 * @param session - the session associated with this computation
2007 * @return product as MPI, never NULL
2008 */
2009static gcry_mpi_t
2010compute_scalar_product (struct ServiceSession *session)
2011{
2012 uint32_t count;
2013 gcry_mpi_t t;
2014 gcry_mpi_t u;
2015 gcry_mpi_t u_prime;
2016 gcry_mpi_t p;
2017 gcry_mpi_t p_prime;
2018 gcry_mpi_t tmp;
2019 gcry_mpi_t r[session->used_element_count];
2020 gcry_mpi_t r_prime[session->used_element_count];
2021 gcry_mpi_t s;
2022 gcry_mpi_t s_prime;
2023 unsigned int i;
2024
2025 count = session->used_element_count;
2026 // due to the introduced static offset S, we now also have to remove this
2027 // from the E(a_pi)(+)E(-b_pi-r_pi) and E(a_qi)(+)E(-r_qi) twice each,
2028 // the result is E((S + a_pi) + (S -b_pi-r_pi)) and E(S + a_qi + S - r_qi)
2029 for (i = 0; i < count; i++)
2030 {
2031 r[i] = gcry_mpi_new (0);
2032 GNUNET_CRYPTO_paillier_decrypt (&my_privkey,
2033 &my_pubkey,
2034 &session->r[i],
2035 r[i]);
2036 gcry_mpi_sub (r[i], r[i], my_offset);
2037 gcry_mpi_sub (r[i], r[i], my_offset);
2038 r_prime[i] = gcry_mpi_new (0);
2039 GNUNET_CRYPTO_paillier_decrypt (&my_privkey,
2040 &my_pubkey,
2041 &session->r_prime[i],
2042 r_prime[i]);
2043 gcry_mpi_sub (r_prime[i], r_prime[i], my_offset);
2044 gcry_mpi_sub (r_prime[i], r_prime[i], my_offset);
2045 }
2046
2047 // calculate t = sum(ai)
2048 t = compute_square_sum (session->sorted_elements, count);
2049
2050 // calculate U
2051 u = gcry_mpi_new (0);
2052 tmp = compute_square_sum (r, count);
2053 gcry_mpi_sub (u, u, tmp);
2054 gcry_mpi_release (tmp);
2055
2056 //calculate U'
2057 u_prime = gcry_mpi_new (0);
2058 tmp = compute_square_sum (r_prime, count);
2059 gcry_mpi_sub (u_prime, u_prime, tmp);
2060
2061 GNUNET_assert (p = gcry_mpi_new (0));
2062 GNUNET_assert (p_prime = gcry_mpi_new (0));
2063 GNUNET_assert (s = gcry_mpi_new (0));
2064 GNUNET_assert (s_prime = gcry_mpi_new (0));
2065
2066 // compute P
2067 GNUNET_CRYPTO_paillier_decrypt (&my_privkey,
2068 &my_pubkey,
2069 &session->s,
2070 s);
2071 GNUNET_CRYPTO_paillier_decrypt (&my_privkey,
2072 &my_pubkey,
2073 &session->s_prime,
2074 s_prime);
2075
2076 // compute P
2077 gcry_mpi_add (p, s, t);
2078 gcry_mpi_add (p, p, u);
2079
2080 // compute P'
2081 gcry_mpi_add (p_prime, s_prime, t);
2082 gcry_mpi_add (p_prime, p_prime, u_prime);
2083
2084 gcry_mpi_release (t);
2085 gcry_mpi_release (u);
2086 gcry_mpi_release (u_prime);
2087 gcry_mpi_release (s);
2088 gcry_mpi_release (s_prime);
2089
2090 // compute product
2091 gcry_mpi_sub (p, p, p_prime);
2092 gcry_mpi_release (p_prime);
2093 tmp = gcry_mpi_set_ui (tmp, 2);
2094 gcry_mpi_div (p, NULL, p, tmp, 0);
2095
2096 gcry_mpi_release (tmp);
2097 for (i = 0; i < count; i++)
2098 {
2099 gcry_mpi_release (session->sorted_elements[i]);
2100 gcry_mpi_release (r[i]);
2101 gcry_mpi_release (r_prime[i]);
2102 }
2103 GNUNET_free (session->a_head);
2104 session->a_head = NULL;
2105 GNUNET_free (session->r);
2106 session->r = NULL;
2107 GNUNET_free (session->r_prime);
2108 session->r_prime = NULL;
2109
2110 return p;
2111}
2112
2113
2114/**
2115 * Handle a multipart-chunk of a request from another service to calculate a scalarproduct with us.
2116 *
2117 * @param cls closure (set from #GNUNET_CADET_connect)
2118 * @param channel connection to the other end
2119 * @param channel_ctx place to store local state associated with the @a channel
2120 * @param message the actual message
2121 * @return #GNUNET_OK to keep the connection open,
2122 * #GNUNET_SYSERR to close it (signal serious error)
2123 */
2124static int
2125handle_alices_cyrptodata_message_multipart (void *cls,
2126 struct GNUNET_CADET_Channel *channel,
2127 void **channel_ctx,
2128 const struct GNUNET_MessageHeader *message)
2129{
2130 struct ServiceSession * s;
2131 const struct MultipartMessage * msg = (const struct MultipartMessage *) message;
2132 struct GNUNET_CRYPTO_PaillierCiphertext *payload;
2133 uint32_t contained_elements;
2134 uint32_t msg_length;
2135
2136 // are we in the correct state?
2137 s = (struct ServiceSession *) * channel_ctx;
2138 //we are not bob
2139 if ((NULL == s->e_a) || //or we did not expect this message yet
2140 (s->used_element_count == s->transferred_element_count))
2141 { //we are not expecting multipart messages
2142 goto except;
2143 }
2144 // shorter than minimum?
2145 if (ntohs (msg->header.size) <= sizeof (struct MultipartMessage))
2146 {
2147 goto except;
2148 }
2149 contained_elements = ntohl (msg->contained_element_count);
2150 msg_length = sizeof (struct MultipartMessage)
2151 +contained_elements * sizeof (struct GNUNET_CRYPTO_PaillierCiphertext);
2152 //sanity check
2153 if ((ntohs (msg->header.size) != msg_length)
2154 || (s->used_element_count < contained_elements + s->transferred_element_count)
2155 || (0 == contained_elements))
2156 {
2157 goto except;
2158 }
2159 payload = (struct GNUNET_CRYPTO_PaillierCiphertext *) &msg[1];
2160 // Convert each vector element to MPI_value
2161 memcpy (&s->e_a[s->transferred_element_count], payload,
2162 sizeof (struct GNUNET_CRYPTO_PaillierCiphertext) * contained_elements);
2163
2164 s->transferred_element_count += contained_elements;
2165
2166 if (contained_elements == s->used_element_count)
2167 {
2168 // single part finished
2169 if (NULL == s->intersection_op)
2170 // intersection has already finished, so we can proceed
2171 compute_service_response (s);
2172 }
2173
2174 return GNUNET_OK;
2175except:
2176 s->channel = NULL;
2177 // and notify our client-session that we could not complete the session
2178 free_session_variables (s);
2179 if (NULL != s->client)
2180 {
2181 //Alice
2182 s->active = GNUNET_SYSERR;
2183 s->client_notification_task =
2184 GNUNET_SCHEDULER_add_now (&prepare_client_end_notification,
2185 s);
2186 }
2187 else
2188 {
2189 //Bob
2190 if (NULL != s->response){
2191 s->response->active = GNUNET_SYSERR;
2192 s->response->client_notification_task =
2193 GNUNET_SCHEDULER_add_now (&prepare_client_end_notification,
2194 s->response);
2195 }
2196 if ( (s == from_service_head) ||
2197 ( (NULL != from_service_head) &&
2198 ( (NULL != s->next) ||
2199 (NULL != s->a_tail)) ) )
2200 GNUNET_CONTAINER_DLL_remove (from_service_head,
2201 from_service_tail,
2202 s);
2203 GNUNET_free (s);
2204 }
2205 return GNUNET_SYSERR;
2206}
2207
2208
2209/**
2210 * Handle a request from another service to calculate a scalarproduct with us.
2211 *
2212 * @param cls closure (set from #GNUNET_CADET_connect)
2213 * @param channel connection to the other end
2214 * @param channel_ctx place to store local state associated with the channel
2215 * @param message the actual message
2216 * @return #GNUNET_OK to keep the connection open,
2217 * #GNUNET_SYSERR to close it (signal serious error)
2218 */
2219static int
2220handle_alices_cyrptodata_message (void *cls,
2221 struct GNUNET_CADET_Channel *channel,
2222 void **channel_ctx,
2223 const struct GNUNET_MessageHeader *message)
2224{
2225 struct ServiceSession * s;
2226 const struct AliceCryptodataMessage *msg;
2227 struct GNUNET_CRYPTO_PaillierCiphertext *payload;
2228 uint32_t contained_elements = 0;
2229 uint32_t msg_length;
2230
2231 s = (struct ServiceSession *) * channel_ctx;
2232 //we are not bob
2233 if ((BOB != s->role)
2234 //we are expecting multipart messages instead
2235 || (NULL != s->e_a)
2236 //or we did not expect this message yet
2237 || //intersection OP has not yet finished
2238 !((NULL != s->intersection_op)
2239 //intersection OP done
2240 || (s->response->sorted_elements)
2241 ))
2242 {
2243 goto invalid_msg;
2244 }
2245
2246 if (ntohs (message->size) < sizeof (struct AliceCryptodataMessage))
2247 {
2248 GNUNET_break_op (0);
2249 goto invalid_msg;
2250 }
2251 msg = (const struct AliceCryptodataMessage *) message;
2252
2253 contained_elements = ntohl (msg->contained_element_count);
2254 msg_length = sizeof (struct AliceCryptodataMessage)
2255 +contained_elements * sizeof (struct GNUNET_CRYPTO_PaillierCiphertext);
2256
2257 //sanity check: is the message as long as the message_count fields suggests?
2258 if ((ntohs (msg->header.size) != msg_length) ||
2259 (s->used_element_count < s->transferred_element_count + contained_elements) ||
2260 (0 == contained_elements))
2261 {
2262 goto invalid_msg;
2263 }
2264
2265 s->transferred_element_count = contained_elements;
2266 payload = (struct GNUNET_CRYPTO_PaillierCiphertext*) &msg[1];
2267
2268 s->e_a = GNUNET_malloc (sizeof (struct GNUNET_CRYPTO_PaillierCiphertext) * s->used_element_count);
2269 memcpy (&s->e_a[0],
2270 payload,
2271 contained_elements * sizeof (struct GNUNET_CRYPTO_PaillierCiphertext));
2272 if (contained_elements == s->used_element_count)
2273 {
2274 // single part finished
2275 if (NULL == s->intersection_op)
2276 // intersection has already finished, so we can proceed
2277 compute_service_response (s);
2278 }
2279 return GNUNET_OK;
2280
2281invalid_msg:
2282 GNUNET_break_op (0);
2283 s->channel = NULL;
2284 // and notify our client-session that we could not complete the session
2285 free_session_variables (s);
2286 if (NULL != s->client)
2287 {
2288 //Alice
2289 s->active = GNUNET_SYSERR;
2290 s->client_notification_task =
2291 GNUNET_SCHEDULER_add_now (&prepare_client_end_notification,
2292 s);
2293 }
2294 else
2295 {
2296 //Bob
2297 if (NULL != s->response)
2298 {
2299 s->response->active = GNUNET_SYSERR;
2300 s->response->client_notification_task =
2301 GNUNET_SCHEDULER_add_now (&prepare_client_end_notification,
2302 s->response);
2303 }
2304 if ( (s == from_service_head) ||
2305 ( (NULL != from_service_head) &&
2306 ( (NULL != s->next) ||
2307 (NULL != s->a_tail)) ) )
2308 GNUNET_CONTAINER_DLL_remove (from_service_head,
2309 from_service_tail,
2310 s);
2311 GNUNET_free(s);
2312 }
2313 return GNUNET_SYSERR;
2314}
2315
2316
2317/**
2318 * Handle a request from another service to calculate a scalarproduct with us.
2319 *
2320 * @param cls closure (set from #GNUNET_CADET_connect)
2321 * @param channel connection to the other end
2322 * @param channel_ctx place to store local state associated with the channel
2323 * @param message the actual message
2324 * @return #GNUNET_OK to keep the connection open,
2325 * #GNUNET_SYSERR to close it (signal serious error)
2326 */
2327static int
2328handle_alices_computation_request (void *cls,
2329 struct GNUNET_CADET_Channel *channel,
2330 void **channel_ctx,
2331 const struct GNUNET_MessageHeader *message)
2332{
2333 struct ServiceSession * s;
2334 struct ServiceSession * client_session;
2335 const struct ServiceRequestMessage *msg;
2336
2337 msg = (const struct ServiceRequestMessage *) message;
2338 s = (struct ServiceSession *) * channel_ctx;
2339 if ((BOB != s->role) || (0 != s->total))
2340 {
2341 // must be a fresh session
2342 goto invalid_msg;
2343 }
2344 // Check if message was sent by me, which would be bad!
2345 if (0 != memcmp (&s->peer,
2346 &me,
2347 sizeof (struct GNUNET_PeerIdentity)))
2348 {
2349 GNUNET_free (s);
2350 GNUNET_break (0);
2351 return GNUNET_SYSERR;
2352 }
2353 if (find_matching_session (from_service_tail,
2354 &msg->session_id,
2355 NULL))
2356 {
2357 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
2358 _("Got message with duplicate session key (`%s'), ignoring service request.\n"),
2359 (const char *) &(msg->session_id));
2360 GNUNET_free (s);
2361 return GNUNET_SYSERR;
2362 }
2363
2364 s->channel = channel;
2365 s->session_id = msg->session_id;
2366 s->remote_pubkey = msg->public_key;
2367
2368 //check if service queue contains a matching request
2369 client_session = find_matching_session (from_client_tail,
2370 &s->session_id,
2371 NULL);
2372
2373 GNUNET_CONTAINER_DLL_insert (from_service_head,
2374 from_service_tail,
2375 s);
2376
2377 if ( (NULL != client_session) &&
2378 (client_session->transferred_element_count == client_session->total) )
2379 {
2380 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2381 "Got session with key %s and a matching element set, processing.\n",
2382 GNUNET_h2s (&s->session_id));
2383
2384 s->response = client_session;
2385 s->intersected_elements = client_session->intersected_elements;
2386 client_session->intersected_elements = NULL;
2387 s->intersection_set = client_session->intersection_set;
2388 client_session->intersection_set = NULL;
2389
2390 s->intersection_op
2391 = GNUNET_SET_prepare (&s->peer,
2392 &s->session_id,
2393 NULL,
2394 GNUNET_SET_RESULT_REMOVED,
2395 &cb_intersection_element_removed,
2396 s);
2397 GNUNET_SET_commit (s->intersection_op,
2398 s->intersection_set);
2399 }
2400 else
2401 {
2402 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2403 "Got session with key %s without a matching element set, queueing.\n",
2404 GNUNET_h2s (&s->session_id));
2405 }
2406
2407 return GNUNET_OK;
2408invalid_msg:
2409 GNUNET_break_op (0);
2410 s->channel = NULL;
2411 // and notify our client-session that we could not complete the session
2412 free_session_variables (s);
2413 if (NULL != s->client)
2414 {
2415 //Alice
2416 s->active = GNUNET_SYSERR;
2417 s->client_notification_task =
2418 GNUNET_SCHEDULER_add_now (&prepare_client_end_notification,
2419 s);
2420 }
2421 else
2422 {
2423 //Bob
2424 if (NULL != s->response) {
2425 s->response->active = GNUNET_SYSERR;
2426 s->response->client_notification_task =
2427 GNUNET_SCHEDULER_add_now (&prepare_client_end_notification,
2428 s->response);
2429 }
2430 if ( (s == from_service_head) ||
2431 ( (NULL != from_service_head) &&
2432 ( (NULL != s->next) ||
2433 (NULL != s->a_tail)) ) )
2434 GNUNET_CONTAINER_DLL_remove (from_service_head,
2435 from_service_tail,
2436 s);
2437 GNUNET_free(s);
2438 }
2439 return GNUNET_SYSERR;
2440}
2441
2442
2443/**
2444 * Handle a multipart chunk of a response we got from another service we wanted to calculate a scalarproduct with.
2445 *
2446 * @param cls closure (set from #GNUNET_CADET_connect)
2447 * @param channel connection to the other end
2448 * @param channel_ctx place to store local state associated with the @a channel
2449 * @param message the actual message
2450 * @return #GNUNET_OK to keep the connection open,
2451 * #GNUNET_SYSERR to close it (signal serious error)
2452 */
2453static int
2454handle_bobs_cryptodata_multipart (void *cls,
2455 struct GNUNET_CADET_Channel *channel,
2456 void **channel_ctx,
2457 const struct GNUNET_MessageHeader *message)
2458{
2459 struct ServiceSession * s;
2460 const struct MultipartMessage *msg;
2461 struct GNUNET_CRYPTO_PaillierCiphertext * payload;
2462 size_t i;
2463 uint32_t contained = 0;
2464 size_t msg_size;
2465 size_t required_size;
2466
2467 GNUNET_assert (NULL != message);
2468 // are we in the correct state?
2469 s = (struct ServiceSession *) * channel_ctx;
2470 if ((ALICE != s->role) || (NULL == s->sorted_elements))
2471 {
2472 goto invalid_msg;
2473 }
2474 msg_size = ntohs (message->size);
2475 if (sizeof (struct MultipartMessage) > msg_size)
2476 {
2477 GNUNET_break_op (0);
2478 goto invalid_msg;
2479 }
2480 msg = (const struct MultipartMessage *) message;
2481 contained = ntohl (msg->contained_element_count);
2482 required_size = sizeof (struct MultipartMessage)
2483 + 2 * contained * sizeof (struct GNUNET_CRYPTO_PaillierCiphertext);
2484 //sanity check: is the message as long as the message_count fields suggests?
2485 if ( (required_size != msg_size) ||
2486 (s->used_element_count < s->transferred_element_count + contained) )
2487 {
2488 goto invalid_msg;
2489 }
2490 payload = (struct GNUNET_CRYPTO_PaillierCiphertext *) &msg[1];
2491 // Convert each k[][perm] to its MPI_value
2492 for (i = 0; i < contained; i++)
2493 {
2494 memcpy (&s->r[s->transferred_element_count + i],
2495 &payload[2 * i],
2496 sizeof (struct GNUNET_CRYPTO_PaillierCiphertext));
2497 memcpy (&s->r_prime[s->transferred_element_count + i],
2498 &payload[2 * i],
2499 sizeof (struct GNUNET_CRYPTO_PaillierCiphertext));
2500 }
2501 s->transferred_element_count += contained;
2502 if (s->transferred_element_count != s->used_element_count)
2503 return GNUNET_OK;
2504 s->product = compute_scalar_product (s); //never NULL
2505
2506invalid_msg:
2507 GNUNET_break_op (NULL != s->product);
2508 s->channel = NULL;
2509 // send message with product to client
2510 if (NULL != s->client)
2511 {
2512 //Alice
2513 if (NULL != s->product)
2514 s->active = GNUNET_NO;
2515 else
2516 s->active = GNUNET_SYSERR;
2517 s->client_notification_task =
2518 GNUNET_SCHEDULER_add_now (&prepare_client_response,
2519 s);
2520 }
2521 else
2522 {
2523 //Bob
2524 if (NULL != s->response){
2525 s->response->active = GNUNET_SYSERR;
2526 s->response->client_notification_task =
2527 GNUNET_SCHEDULER_add_now (&prepare_client_end_notification,
2528 s->response);
2529 }
2530 if ( (s == from_service_head) ||
2531 ( (NULL != from_service_head) &&
2532 ( (NULL != s->next) ||
2533 (NULL != s->a_tail)) ) )
2534 GNUNET_CONTAINER_DLL_remove (from_service_head,
2535 from_service_tail,
2536 s);
2537 free_session_variables (s);
2538 GNUNET_free(s);
2539 }
2540 // the channel has done its job, terminate our connection and the channel
2541 // the peer will be notified that the channel was destroyed via channel_destruction_handler
2542 // just close the connection, as recommended by Christian
2543 return GNUNET_SYSERR;
2544}
2545
2546
2547/**
2548 * Handle a response we got from another service we wanted to calculate a scalarproduct with.
2549 *
2550 * @param cls closure (set from #GNUNET_CADET_connect)
2551 * @param channel connection to the other end
2552 * @param channel_ctx place to store local state associated with the channel
2553 * @param message the actual message
2554 * @return #GNUNET_OK to keep the connection open,
2555 * #GNUNET_SYSERR to close it (we are done)
2556 */
2557static int
2558handle_bobs_cryptodata_message (void *cls,
2559 struct GNUNET_CADET_Channel *channel,
2560 void **channel_ctx,
2561 const struct GNUNET_MessageHeader *message)
2562{
2563 struct ServiceSession *s;
2564 const struct ServiceResponseMessage *msg;
2565 struct GNUNET_CRYPTO_PaillierCiphertext * payload;
2566 size_t i;
2567 uint32_t contained = 0;
2568 size_t msg_size;
2569 size_t required_size;
2570
2571 GNUNET_assert (NULL != message);
2572 s = (struct ServiceSession *) * channel_ctx;
2573 // are we in the correct state?
2574 if (NULL == s->sorted_elements
2575 || NULL != s->msg
2576 || s->used_element_count != s->transferred_element_count)
2577 {
2578 goto invalid_msg;
2579 }
2580 //we need at least a full message without elements attached
2581 msg_size = ntohs (message->size);
2582 if (sizeof (struct ServiceResponseMessage) > msg_size)
2583 {
2584 GNUNET_break_op (0);
2585 goto invalid_msg;
2586 }
2587 msg = (const struct ServiceResponseMessage *) message;
2588 contained = ntohl (msg->contained_element_count);
2589 required_size = sizeof (struct ServiceResponseMessage)
2590 + 2 * contained * sizeof (struct GNUNET_CRYPTO_PaillierCiphertext)
2591 + 2 * sizeof (struct GNUNET_CRYPTO_PaillierCiphertext);
2592 //sanity check: is the message as long as the message_count fields suggests?
2593 if ((msg_size != required_size) || (s->used_element_count < contained))
2594 {
2595 goto invalid_msg;
2596 }
2597 s->transferred_element_count = contained;
2598 //convert s
2599 payload = (struct GNUNET_CRYPTO_PaillierCiphertext *) &msg[1];
2600 memcpy (&s->s,
2601 &payload[0],
2602 sizeof (struct GNUNET_CRYPTO_PaillierCiphertext));
2603 memcpy (&s->s_prime,
2604 &payload[1],
2605 sizeof (struct GNUNET_CRYPTO_PaillierCiphertext));
2606
2607 s->r = GNUNET_malloc (sizeof (struct GNUNET_CRYPTO_PaillierCiphertext) * s->used_element_count);
2608 s->r_prime = GNUNET_malloc (sizeof (struct GNUNET_CRYPTO_PaillierCiphertext) * s->used_element_count);
2609
2610 payload = &payload[2];
2611 // Convert each k[][perm] to its MPI_value
2612 for (i = 0; i < contained; i++)
2613 {
2614 memcpy (&s->r[i],
2615 &payload[2 * i],
2616 sizeof (struct GNUNET_CRYPTO_PaillierCiphertext));
2617 memcpy (&s->r_prime[i],
2618 &payload[2 * i + 1],
2619 sizeof (struct GNUNET_CRYPTO_PaillierCiphertext));
2620 }
2621 if (s->transferred_element_count != s->used_element_count)
2622 return GNUNET_OK; //wait for the other multipart chunks
2623 s->product = compute_scalar_product (s); //never NULL
2624
2625invalid_msg:
2626 GNUNET_break_op (NULL != s->product);
2627 s->channel = NULL;
2628 // send message with product to client
2629 if (NULL != s->client)
2630 {
2631 //Alice
2632 s->client_notification_task =
2633 GNUNET_SCHEDULER_add_now (&prepare_client_response,
2634 s);
2635 }
2636 else
2637 {
2638 //Bob
2639 if (NULL != s->response)
2640 {
2641 s->response->active = GNUNET_SYSERR;
2642 s->response->client_notification_task
2643 = GNUNET_SCHEDULER_add_now (&prepare_client_end_notification,
2644 s->response);
2645 }
2646 if ( (s == from_service_head) ||
2647 ( (NULL != from_service_head) &&
2648 ( (NULL != s->next) ||
2649 (NULL != s->a_tail)) ) )
2650 GNUNET_CONTAINER_DLL_remove (from_service_head,
2651 from_service_tail,
2652 s);
2653 free_session_variables (s);
2654 GNUNET_free(s);
2655 }
2656 // the channel has done its job, terminate our connection and the channel
2657 // the peer will be notified that the channel was destroyed via channel_destruction_handler
2658 // just close the connection, as recommended by Christian
2659 return GNUNET_SYSERR;
2660}
2661
2662
2663/**
2664 * Task run during shutdown.
2665 *
2666 * @param cls unused
2667 * @param tc unused
2668 */
2669static void
2670shutdown_task (void *cls,
2671 const struct GNUNET_SCHEDULER_TaskContext *tc)
2672{
2673 struct ServiceSession * s;
2674
2675 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2676 "Shutting down, initiating cleanup.\n");
2677
2678 do_shutdown = GNUNET_YES;
2679
2680 // terminate all owned open channels.
2681 // FIXME: this should be unnecessary, as we should
2682 // get client disconnect events that create the same effect.
2683 for (s = from_client_head; NULL != s; s = s->next)
2684 {
2685 if ((GNUNET_NO != s->active) && (NULL != s->channel))
2686 {
2687 GNUNET_CADET_channel_destroy (s->channel);
2688 s->channel = NULL;
2689 }
2690 if (GNUNET_SCHEDULER_NO_TASK != s->client_notification_task)
2691 {
2692 GNUNET_SCHEDULER_cancel (s->client_notification_task);
2693 s->client_notification_task = GNUNET_SCHEDULER_NO_TASK;
2694 }
2695 if (NULL != s->client)
2696 {
2697 GNUNET_SERVER_client_disconnect (s->client);
2698 s->client = NULL;
2699 }
2700 }
2701 for (s = from_service_head; NULL != s; s = s->next)
2702 if (NULL != s->channel)
2703 {
2704 GNUNET_CADET_channel_destroy (s->channel);
2705 s->channel = NULL;
2706 }
2707
2708 if (my_cadet)
2709 {
2710 GNUNET_CADET_disconnect (my_cadet);
2711 my_cadet = NULL;
2712 }
2713}
2714
2715
2716/**
2717 * Initialization of the program and message handlers
2718 *
2719 * @param cls closure
2720 * @param server the initialized server
2721 * @param c configuration to use
2722 */
2723static void
2724run (void *cls,
2725 struct GNUNET_SERVER_Handle *server,
2726 const struct GNUNET_CONFIGURATION_Handle *c)
2727{
2728 static const struct GNUNET_SERVER_MessageHandler server_handlers[] = {
2729 { &handle_client_message, NULL,
2730 GNUNET_MESSAGE_TYPE_SCALARPRODUCT_CLIENT_TO_ALICE,
2731 0},
2732 { &handle_client_message, NULL,
2733 GNUNET_MESSAGE_TYPE_SCALARPRODUCT_CLIENT_TO_BOB,
2734 0},
2735 { &handle_client_message_multipart, NULL,
2736 GNUNET_MESSAGE_TYPE_SCALARPRODUCT_CLIENT_MUTLIPART,
2737 0},
2738 { NULL, NULL, 0, 0}
2739 };
2740 static const struct GNUNET_CADET_MessageHandler cadet_handlers[] = {
2741 { &handle_alices_computation_request,
2742 GNUNET_MESSAGE_TYPE_SCALARPRODUCT_SESSION_INITIALIZATION,
2743 sizeof (struct ServiceRequestMessage) },
2744 { &handle_alices_cyrptodata_message,
2745 GNUNET_MESSAGE_TYPE_SCALARPRODUCT_ALICE_CRYPTODATA,
2746 0},
2747 { &handle_alices_cyrptodata_message_multipart,
2748 GNUNET_MESSAGE_TYPE_SCALARPRODUCT_ALICE_CRYPTODATA_MULTIPART,
2749 0},
2750 { &handle_bobs_cryptodata_message,
2751 GNUNET_MESSAGE_TYPE_SCALARPRODUCT_BOB_CRYPTODATA,
2752 0},
2753 { &handle_bobs_cryptodata_multipart,
2754 GNUNET_MESSAGE_TYPE_SCALARPRODUCT_BOB_CRYPTODATA_MULTIPART,
2755 0},
2756 { NULL, 0, 0}
2757 };
2758 static const uint32_t ports[] = {
2759 GNUNET_APPLICATION_TYPE_SCALARPRODUCT,
2760 0
2761 };
2762 cfg = c;
2763
2764 //generate private/public key set
2765 GNUNET_CRYPTO_paillier_create (&my_pubkey,
2766 &my_privkey);
2767
2768 // offset has to be sufficiently small to allow computation of:
2769 // m1+m2 mod n == (S + a) + (S + b) mod n,
2770 // if we have more complex operations, this factor needs to be lowered
2771 my_offset = gcry_mpi_new (GNUNET_CRYPTO_PAILLIER_BITS / 3);
2772 gcry_mpi_set_bit (my_offset, GNUNET_CRYPTO_PAILLIER_BITS / 3);
2773
2774 // register server callbacks and disconnect handler
2775 GNUNET_SERVER_add_handlers (server, server_handlers);
2776 GNUNET_SERVER_disconnect_notify (server,
2777 &cb_client_disconnect,
2778 NULL);
2779 GNUNET_break (GNUNET_OK ==
2780 GNUNET_CRYPTO_get_peer_identity (cfg,
2781 &me));
2782 my_cadet = GNUNET_CADET_connect (cfg, NULL,
2783 &cb_channel_incoming,
2784 &cb_channel_destruction,
2785 cadet_handlers,
2786 ports);
2787 if (!my_cadet)
2788 {
2789 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
2790 _("Connect to CADET failed\n"));
2791 GNUNET_SCHEDULER_shutdown ();
2792 return;
2793 }
2794 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2795 "Connection to CADET initialized\n");
2796 GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_FOREVER_REL,
2797 &shutdown_task,
2798 NULL);
2799}
2800
2801
2802/**
2803 * The main function for the scalarproduct service.
2804 *
2805 * @param argc number of arguments from the command line
2806 * @param argv command line arguments
2807 * @return 0 ok, 1 on error
2808 */
2809int
2810main (int argc, char *const *argv)
2811{
2812 return (GNUNET_OK ==
2813 GNUNET_SERVICE_run (argc, argv,
2814 "scalarproduct",
2815 GNUNET_SERVICE_OPTION_NONE,
2816 &run, NULL)) ? 0 : 1;
2817}
2818
2819/* end of gnunet-service-scalarproduct.c */
diff --git a/src/scalarproduct/gnunet-service-scalarproduct.h b/src/scalarproduct/gnunet-service-scalarproduct.h
new file mode 100644
index 000000000..9a5008628
--- /dev/null
+++ b/src/scalarproduct/gnunet-service-scalarproduct.h
@@ -0,0 +1,165 @@
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.h
22 * @brief scalarproduct service P2P messages
23 * @author Christian M. Fuchs
24 * @author Christian Grothoff
25 */
26#ifndef GNUNET_SERVICE_SCALARPRODUCT_H
27#define GNUNET_SERVICE_SCALARPRODUCT_H
28
29/**
30 * Maximum count of elements we can put into a multipart message
31 */
32#define MULTIPART_ELEMENT_CAPACITY ((GNUNET_SERVER_MAX_MESSAGE_SIZE - 1 - sizeof (struct MultipartMessage)) / sizeof (struct GNUNET_CRYPTO_PaillierCiphertext))
33
34
35GNUNET_NETWORK_STRUCT_BEGIN
36
37/**
38 * Message type passed from requesting service Alice to responding
39 * service Bob to initiate a request and make Bob participate in our
40 * protocol. Afterwards, Bob is expected to perform the set
41 * intersection with Alice. Once that has succeeded, Alice will
42 * send a `struct AliceCryptodataMessage *`. Bob is not expected
43 * to respond via CADET in the meantime.
44 */
45struct ServiceRequestMessage
46{
47 /**
48 * Type is #GNUNET_MESSAGE_TYPE_SCALARPRODUCT_SESSION_INITIALIZATION
49 */
50 struct GNUNET_MessageHeader header;
51
52 /**
53 * For alignment. Always zero.
54 */
55 uint32_t reserved;
56
57 /**
58 * The transaction/session key used to identify a session
59 */
60 struct GNUNET_HashCode session_id;
61
62 /**
63 * Alice's public key
64 */
65 struct GNUNET_CRYPTO_PaillierPublicKey public_key;
66
67};
68
69
70/**
71 * Vector of Pallier-encrypted values sent by Alice to Bob
72 * (after set intersection). Alice may send messages of this
73 * type repeatedly to transmit all values.
74 */
75struct AliceCryptodataMessage
76{
77 /**
78 * Type is #GNUNET_MESSAGE_TYPE_SCALARPRODUCT_ALICE_CRYPTODATA
79 */
80 struct GNUNET_MessageHeader header;
81
82 /**
83 * How many elements we appended to this message? In NBO.
84 */
85 uint32_t contained_element_count GNUNET_PACKED;
86
87 /**
88 * struct GNUNET_CRYPTO_PaillierCiphertext[contained_element_count]
89 */
90};
91
92
93/**
94 * Message type passed from responding service Bob to responding
95 * service Alice to complete a request and allow Alice to compute the
96 * result. If Bob's reply does not fit into this one message, the
97 * conversation may be continued with `struct MultipartMessage`
98 * messages afterwards.
99 */
100struct ServiceResponseMessage
101{
102 /**
103 * GNUNET message header with type
104 * #GNUNET_MESSAGE_TYPE_SCALARPRODUCT_BOB_CRYPTODATA.
105 */
106 struct GNUNET_MessageHeader header;
107
108 /**
109 * How many elements the session input had (in NBO).
110 */
111 uint32_t total_element_count GNUNET_PACKED;
112
113 /**
114 * How many elements were included after the mask was applied
115 * including all multipart msgs (in NBO).
116 */
117 uint32_t used_element_count GNUNET_PACKED;
118
119 /**
120 * How many elements this individual message delivers (in NBO).
121 */
122 uint32_t contained_element_count GNUNET_PACKED;
123
124 /**
125 * The transaction/session key used to identify a session.
126 * FIXME: needed? CADET should already identify sessions!
127 */
128 struct GNUNET_HashCode key;
129
130 /**
131 * followed by s | s' | k[i][perm]
132 */
133};
134
135
136/**
137 * Multipart Message type passed between to supply additional elements
138 * for the peer. Send from Bob to Alice with additional elements
139 * of k[i][perm] after his `struct ServiceResponseMessage *`.
140 * Once all k-values have been transmitted, Bob is finished and
141 * Alice can transmit the final result to the client.
142 */
143struct MultipartMessage
144{
145 /**
146 * GNUNET message header
147 */
148 struct GNUNET_MessageHeader header;
149
150 /**
151 * How many elements we supply within this message? In NBO.
152 */
153 uint32_t contained_element_count GNUNET_PACKED;
154
155 /**
156 * struct GNUNET_CRYPTO_PaillierCiphertext[multipart_element_count]
157 */
158};
159
160
161
162GNUNET_NETWORK_STRUCT_END
163
164
165#endif
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 */
diff --git a/src/scalarproduct/gnunet-service-scalarproduct_bob.c b/src/scalarproduct/gnunet-service-scalarproduct_bob.c
new file mode 100644
index 000000000..ee74b515a
--- /dev/null
+++ b/src/scalarproduct/gnunet-service-scalarproduct_bob.c
@@ -0,0 +1,1490 @@
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_bob.c
22 * @brief scalarproduct service implementation
23 * @author Christian M. Fuchs
24 * @author Christian Grothoff
25 */
26#include "platform.h"
27#include <limits.h>
28#include <gcrypt.h>
29#include "gnunet_util_lib.h"
30#include "gnunet_core_service.h"
31#include "gnunet_cadet_service.h"
32#include "gnunet_applications.h"
33#include "gnunet_protocols.h"
34#include "gnunet_scalarproduct_service.h"
35#include "gnunet_set_service.h"
36#include "scalarproduct.h"
37#include "gnunet-service-scalarproduct.h"
38
39#define LOG(kind,...) GNUNET_log_from (kind, "scalarproduct-bob", __VA_ARGS__)
40
41
42/**
43 * An encrypted element key-value pair.
44 */
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 * An incoming session from CADET.
63 */
64struct CadetIncomingSession;
65
66
67/**
68 * A scalarproduct session which tracks an offer for a
69 * multiplication service by a local client.
70 */
71struct BobServiceSession
72{
73
74 /**
75 * (hopefully) unique transaction ID
76 */
77 struct GNUNET_HashCode session_id;
78
79 /**
80 * The client this request is related to.
81 */
82 struct GNUNET_SERVER_Client *client;
83
84 /**
85 * Client message queue.
86 */
87 struct GNUNET_MQ_Handle *client_mq;
88
89 /**
90 * All non-0-value'd elements transmitted to us.
91 */
92 struct GNUNET_CONTAINER_MultiHashMap *intersected_elements;
93
94 /**
95 * Set of elements for which we will be conducting an intersection.
96 * The resulting elements are then used for computing the scalar product.
97 */
98 struct GNUNET_SET_Handle *intersection_set;
99
100 /**
101 * Set of elements for which will conduction an intersection.
102 * the resulting elements are then used for computing the scalar product.
103 */
104 struct GNUNET_SET_OperationHandle *intersection_op;
105
106 /**
107 * a(Alice)
108 */
109 struct MpiElement *sorted_elements;
110
111 /**
112 * E(ai)(Bob) after applying the mask
113 */
114 struct GNUNET_CRYPTO_PaillierCiphertext *e_a;
115
116 /**
117 * Bob's permutation p of R
118 */
119 struct GNUNET_CRYPTO_PaillierCiphertext *r;
120
121 /**
122 * Bob's permutation q of R
123 */
124 struct GNUNET_CRYPTO_PaillierCiphertext *r_prime;
125
126 /**
127 * Bob's "s"
128 */
129 struct GNUNET_CRYPTO_PaillierCiphertext s;
130
131 /**
132 * Bob's "s'"
133 */
134 struct GNUNET_CRYPTO_PaillierCiphertext s_prime;
135
136 /**
137 * Handle for our associated incoming CADET session, or NULL
138 * if we have not gotten one yet.
139 */
140 struct CadetIncomingSession *cadet;
141
142 /**
143 * The computed scalar
144 */
145 gcry_mpi_t product;
146
147 /**
148 * How many elements we were supplied with from the client
149 */
150 uint32_t total;
151
152 /**
153 * how many elements actually are used for the scalar product.
154 * Size of the arrays in @e r and @e r_prime.
155 */
156 uint32_t used_element_count;
157
158 /**
159 * already transferred elements (sent/received) for multipart messages, less or equal than @e used_element_count for
160 */
161 uint32_t transferred_element_count;
162
163 /**
164 * Is this session active (#GNUNET_YES), Concluded (#GNUNET_NO), or had an error (#GNUNET_SYSERR)
165 */
166 int32_t active;
167
168 /**
169 * Are we already in #destroy_service_session()?
170 */
171 int in_destroy;
172
173};
174
175
176/**
177 * An incoming session from CADET.
178 */
179struct CadetIncomingSession
180{
181
182 /**
183 * Associated client session, or NULL.
184 */
185 struct BobServiceSession *s;
186
187 /**
188 * The CADET channel.
189 */
190 struct GNUNET_CADET_Channel *channel;
191
192 /**
193 * Originator's peer identity. (Only for diagnostics.)
194 */
195 struct GNUNET_PeerIdentity peer;
196
197 /**
198 * (hopefully) unique transaction ID
199 */
200 struct GNUNET_HashCode session_id;
201
202 /**
203 * Public key of the remote service.
204 */
205 struct GNUNET_CRYPTO_PaillierPublicKey remote_pubkey;
206
207 /**
208 * The message queue for this channel.
209 */
210 struct GNUNET_MQ_Handle *cadet_mq;
211
212 /**
213 * Has this CADET session been added to the map yet?
214 * #GNUNET_YES if so, in which case @e session_id is
215 * the key.
216 */
217 int in_map;
218
219 /**
220 * Are we already in #destroy_cadet_session()?
221 */
222 int in_destroy;
223
224};
225
226
227/**
228 * GNUnet configuration handle
229 */
230static const struct GNUNET_CONFIGURATION_Handle *cfg;
231
232/**
233 * Service's own public key
234 */
235static struct GNUNET_CRYPTO_PaillierPublicKey my_pubkey;
236
237/**
238 * Service's own private key
239 */
240static struct GNUNET_CRYPTO_PaillierPrivateKey my_privkey;
241
242/**
243 * Service's offset for values that could possibly be negative but are plaintext for encryption.
244 */
245static gcry_mpi_t my_offset;
246
247/**
248 * Map of `struct BobServiceSession`, by session keys.
249 */
250static struct GNUNET_CONTAINER_MultiHashMap *client_sessions;
251
252/**
253 * Map of `struct CadetIncomingSession`, by session keys.
254 */
255static struct GNUNET_CONTAINER_MultiHashMap *cadet_sessions;
256
257/**
258 * Handle to the CADET service.
259 */
260static struct GNUNET_CADET_Handle *my_cadet;
261
262/**
263 * Certain events (callbacks for server & cadet operations) must not
264 * be queued after shutdown.
265 */
266static int do_shutdown;
267
268
269
270/**
271 * Finds a not terminated client session in the respective map based on
272 * session key.
273 *
274 * @param key the session key we want to search for
275 * @return the matching session, or NULL for none
276 */
277static struct BobServiceSession *
278find_matching_client_session (const struct GNUNET_HashCode *key)
279{
280 return GNUNET_CONTAINER_multihashmap_get (client_sessions,
281 key);
282}
283
284
285/**
286 * Finds a CADET session in the respective map based on session key.
287 *
288 * @param key the session key we want to search for
289 * @return the matching session, or NULL for none
290 */
291static struct CadetIncomingSession *
292find_matching_cadet_session (const struct GNUNET_HashCode *key)
293{
294 return GNUNET_CONTAINER_multihashmap_get (cadet_sessions,
295 key);
296}
297
298
299/**
300 * Destroy session state, we are done with it.
301 *
302 * @param session the session to free elements from
303 */
304static void
305destroy_cadet_session (struct CadetIncomingSession *s);
306
307
308/**
309 * Destroy session state, we are done with it.
310 *
311 * @param session the session to free elements from
312 */
313static void
314destroy_service_session (struct BobServiceSession *s)
315{
316 struct CadetIncomingSession *in;
317 unsigned int i;
318
319 if (GNUNET_YES == s->in_destroy)
320 return;
321 s->in_destroy = GNUNET_YES;
322 if (NULL != (in = s->cadet))
323 {
324 s->cadet = NULL;
325 destroy_cadet_session (in);
326 }
327 if (NULL != s->client_mq)
328 {
329 GNUNET_MQ_destroy (s->client_mq);
330 s->client_mq = NULL;
331 }
332 if (NULL != s->client)
333 {
334 GNUNET_SERVER_client_disconnect (s->client);
335 s->client = NULL;
336 }
337 GNUNET_assert (GNUNET_YES ==
338 GNUNET_CONTAINER_multihashmap_remove (client_sessions,
339 &s->session_id,
340 s));
341 if (NULL != s->intersected_elements)
342 {
343 /* FIXME: free elements */
344 GNUNET_CONTAINER_multihashmap_destroy (s->intersected_elements);
345 s->intersected_elements = NULL;
346 }
347 if (NULL != s->intersection_op)
348 {
349 GNUNET_SET_operation_cancel (s->intersection_op);
350 s->intersection_op = NULL;
351 }
352 if (NULL != s->intersection_set)
353 {
354 GNUNET_SET_destroy (s->intersection_set);
355 s->intersection_set = NULL;
356 }
357 if (NULL != s->e_a)
358 {
359 GNUNET_free (s->e_a);
360 s->e_a = NULL;
361 }
362 if (NULL != s->sorted_elements)
363 {
364 for (i=0;i<s->used_element_count;i++)
365 gcry_mpi_release (s->sorted_elements[i].value);
366 GNUNET_free (s->sorted_elements);
367 s->sorted_elements = NULL;
368 }
369 if (NULL != s->r)
370 {
371 GNUNET_free (s->r);
372 s->r = NULL;
373 }
374 if (NULL != s->r_prime)
375 {
376 GNUNET_free (s->r_prime);
377 s->r_prime = NULL;
378 }
379 if (NULL != s->product)
380 {
381 gcry_mpi_release (s->product);
382 s->product = NULL;
383 }
384 GNUNET_free (s);
385}
386
387
388/**
389 * Destroy incoming CADET session state, we are done with it.
390 *
391 * @param in the session to free elements from
392 */
393static void
394destroy_cadet_session (struct CadetIncomingSession *in)
395{
396 struct BobServiceSession *s;
397
398 if (GNUNET_YES == in->in_destroy)
399 return;
400 in->in_destroy = GNUNET_YES;
401 if (NULL != (s = in->s))
402 {
403 in->s = NULL;
404 destroy_service_session (s);
405 }
406 if (GNUNET_YES == in->in_map)
407 {
408 GNUNET_assert (GNUNET_YES ==
409 GNUNET_CONTAINER_multihashmap_remove (cadet_sessions,
410 &in->session_id,
411 in));
412 in->in_map = GNUNET_NO;
413 }
414 if (NULL != in->cadet_mq)
415 {
416 GNUNET_MQ_destroy (in->cadet_mq);
417 in->cadet_mq = NULL;
418 }
419 if (NULL != in->channel)
420 {
421 GNUNET_CADET_channel_destroy (in->channel);
422 in->channel = NULL;
423 }
424 GNUNET_free (in);
425}
426
427
428/**
429 * Notify the client that the session has succeeded or failed. This
430 * message gets sent to Bob's client if the operation completed or
431 * Alice disconnected.
432 *
433 * @param session the associated client session to fail or succeed
434 */
435static void
436prepare_client_end_notification (struct BobServiceSession *session)
437{
438 struct ClientResponseMessage *msg;
439 struct GNUNET_MQ_Envelope *e;
440
441 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
442 "Sending session-end notification with status %d to client for session %s\n",
443 session->active,
444 GNUNET_h2s (&session->session_id));
445 e = GNUNET_MQ_msg (msg,
446 GNUNET_MESSAGE_TYPE_SCALARPRODUCT_RESULT);
447 msg->range = 0;
448 msg->product_length = htonl (0);
449 msg->status = htonl (session->active);
450 GNUNET_MQ_send (session->client_mq,
451 e);
452}
453
454
455/**
456 * Function called whenever a channel is destroyed. Should clean up
457 * any associated state.
458 *
459 * It must NOT call #GNUNET_CADET_channel_destroy() on the channel.
460 *
461 * @param cls closure (set from #GNUNET_CADET_connect())
462 * @param channel connection to the other end (henceforth invalid)
463 * @param channel_ctx place where local state associated
464 * with the channel is stored
465 */
466static void
467cb_channel_destruction (void *cls,
468 const struct GNUNET_CADET_Channel *channel,
469 void *channel_ctx)
470{
471 struct CadetIncomingSession *in = channel_ctx;
472 struct BobServiceSession *s;
473
474 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
475 "Peer disconnected, terminating session %s with peer %s\n",
476 GNUNET_h2s (&in->session_id),
477 GNUNET_i2s (&in->peer));
478 in->channel = NULL;
479 if (NULL != (s = in->s))
480 {
481 if (GNUNET_YES == s->active)
482 {
483 s->active = GNUNET_SYSERR;
484 prepare_client_end_notification (s);
485 }
486 }
487 destroy_cadet_session (in);
488}
489
490
491/**
492 * MQ finished giving our last message to CADET, now notify
493 * the client that we are finished.
494 */
495static void
496bob_cadet_done_cb (void *cls)
497{
498 struct BobServiceSession *session = cls;
499
500 session->active = GNUNET_NO; /* that means, done */
501 prepare_client_end_notification (session);
502}
503
504
505/**
506 * Maximum count of elements we can put into a multipart message
507 */
508#define ELEMENT_CAPACITY ((GNUNET_SERVER_MAX_MESSAGE_SIZE - 1 - sizeof (struct MultipartMessage)) / sizeof (struct GNUNET_CRYPTO_PaillierCiphertext))
509
510
511/**
512 * Send a multipart chunk of a service response from Bob to Alice.
513 * This element only contains the two permutations of R, R'.
514 *
515 * @param s the associated service session
516 */
517static void
518transmit_bobs_cryptodata_message_multipart (struct BobServiceSession *s)
519{
520 struct GNUNET_CRYPTO_PaillierCiphertext *payload;
521 struct MultipartMessage *msg;
522 struct GNUNET_MQ_Envelope *e;
523 unsigned int i;
524 unsigned int j;
525 uint32_t todo_count;
526
527 while (s->transferred_element_count != s->used_element_count)
528 {
529 todo_count = s->used_element_count - s->transferred_element_count;
530 if (todo_count > ELEMENT_CAPACITY / 2)
531 todo_count = ELEMENT_CAPACITY / 2;
532
533 e = GNUNET_MQ_msg_extra (msg,
534 todo_count * sizeof (struct GNUNET_CRYPTO_PaillierCiphertext) * 2,
535 GNUNET_MESSAGE_TYPE_SCALARPRODUCT_BOB_CRYPTODATA_MULTIPART);
536 msg->contained_element_count = htonl (todo_count);
537 payload = (struct GNUNET_CRYPTO_PaillierCiphertext *) &msg[1];
538 for (i = s->transferred_element_count, j = 0; i < s->transferred_element_count + todo_count; i++)
539 {
540 //r[i][p] and r[i][q]
541 memcpy (&payload[j++],
542 &s->r[i],
543 sizeof (struct GNUNET_CRYPTO_PaillierCiphertext));
544 memcpy (&payload[j++],
545 &s->r_prime[i],
546 sizeof (struct GNUNET_CRYPTO_PaillierCiphertext));
547 }
548 s->transferred_element_count += todo_count;
549 if (s->transferred_element_count == s->used_element_count)
550 GNUNET_MQ_notify_sent (e,
551 &bob_cadet_done_cb,
552 s);
553 GNUNET_MQ_send (s->cadet->cadet_mq,
554 e);
555 }
556}
557
558
559/**
560 * Bob generates the response message to be sent to Alice after
561 * computing the values (1), (2), S and S'.
562 *
563 * (1)[]: $E_A(a_{pi(i)}) times E_A(- r_{pi(i)} - b_{pi(i)}) &= E_A(a_{pi(i)} - r_{pi(i)} - b_{pi(i)})$
564 * (2)[]: $E_A(a_{pi'(i)}) times E_A(- r_{pi'(i)}) &= E_A(a_{pi'(i)} - r_{pi'(i)})$
565 * S: $S := E_A(sum (r_i + b_i)^2)$
566 * S': $S' := E_A(sum r_i^2)$
567 *
568 * @param s the associated requesting session with Alice
569 */
570static void
571transmit_bobs_cryptodata_message (struct BobServiceSession *s)
572{
573 struct ServiceResponseMessage *msg;
574 struct GNUNET_MQ_Envelope *e;
575 struct GNUNET_CRYPTO_PaillierCiphertext *payload;
576 unsigned int i;
577
578 s->transferred_element_count = (GNUNET_SERVER_MAX_MESSAGE_SIZE - 1 - sizeof (struct ServiceResponseMessage)) /
579 (sizeof (struct GNUNET_CRYPTO_PaillierCiphertext) * 2) - 2;
580 if (s->transferred_element_count > s->used_element_count)
581 s->transferred_element_count = s->used_element_count;
582
583 e = GNUNET_MQ_msg_extra (msg,
584 (2 + s->transferred_element_count * 2)
585 * sizeof (struct GNUNET_CRYPTO_PaillierCiphertext),
586 GNUNET_MESSAGE_TYPE_SCALARPRODUCT_BOB_CRYPTODATA);
587 msg->total_element_count = htonl (s->total);
588 msg->used_element_count = htonl (s->used_element_count);
589 msg->contained_element_count = htonl (s->transferred_element_count);
590 msg->key = s->session_id;
591
592 payload = (struct GNUNET_CRYPTO_PaillierCiphertext *) &msg[1];
593 memcpy (&payload[0],
594 &s->s,
595 sizeof (struct GNUNET_CRYPTO_PaillierCiphertext));
596 memcpy (&payload[1],
597 &s->s_prime,
598 sizeof (struct GNUNET_CRYPTO_PaillierCiphertext));
599
600 payload = &payload[2];
601 // convert k[][]
602 for (i = 0; i < s->transferred_element_count; i++)
603 {
604 //k[i][p] and k[i][q]
605 memcpy (&payload[i * 2],
606 &s->r[i],
607 sizeof (struct GNUNET_CRYPTO_PaillierCiphertext));
608 memcpy (&payload[i * 2 + 1],
609 &s->r_prime[i],
610 sizeof (struct GNUNET_CRYPTO_PaillierCiphertext));
611 }
612 if (s->transferred_element_count == s->used_element_count)
613 GNUNET_MQ_notify_sent (e,
614 &bob_cadet_done_cb,
615 s);
616 GNUNET_MQ_send (s->cadet->cadet_mq,
617 e);
618 transmit_bobs_cryptodata_message_multipart (s);
619}
620
621
622/**
623 * Computes the square sum over a vector of a given length.
624 *
625 * @param vector the vector to compute over
626 * @param length the length of the vector
627 * @return an MPI value containing the calculated sum, never NULL
628 */
629static gcry_mpi_t
630compute_square_sum (const gcry_mpi_t *vector,
631 uint32_t length)
632{
633 gcry_mpi_t elem;
634 gcry_mpi_t sum;
635 uint32_t i;
636
637 GNUNET_assert (NULL != (sum = gcry_mpi_new (0)));
638 GNUNET_assert (NULL != (elem = gcry_mpi_new (0)));
639 for (i = 0; i < length; i++)
640 {
641 gcry_mpi_mul (elem, vector[i], vector[i]);
642 gcry_mpi_add (sum, sum, elem);
643 }
644 gcry_mpi_release (elem);
645 return sum;
646}
647
648
649/**
650 * Compute the values
651 * (1)[]: $E_A(a_{pi(i)}) otimes E_A(- r_{pi(i)} - b_{pi(i)}) &= E_A(a_{pi(i)} - r_{pi(i)} - b_{pi(i)})$
652 * (2)[]: $E_A(a_{pi'(i)}) otimes E_A(- r_{pi'(i)}) &= E_A(a_{pi'(i)} - r_{pi'(i)})$
653 * S: $S := E_A(sum (r_i + b_i)^2)$
654 * S': $S' := E_A(sum r_i^2)$
655 *
656 * @param request the requesting session + bob's requesting peer
657 */
658static void
659compute_service_response (struct BobServiceSession *session)
660{
661 uint32_t i;
662 unsigned int *p;
663 unsigned int *q;
664 uint32_t count;
665 gcry_mpi_t *rand;
666 gcry_mpi_t tmp;
667 const struct MpiElement *b;
668 struct GNUNET_CRYPTO_PaillierCiphertext *a;
669 struct GNUNET_CRYPTO_PaillierCiphertext *r;
670 struct GNUNET_CRYPTO_PaillierCiphertext *r_prime;
671
672 count = session->used_element_count;
673 a = session->e_a;
674 b = session->sorted_elements;
675 q = GNUNET_CRYPTO_random_permute (GNUNET_CRYPTO_QUALITY_WEAK,
676 count);
677 p = GNUNET_CRYPTO_random_permute (GNUNET_CRYPTO_QUALITY_WEAK,
678 count);
679 rand = GNUNET_malloc (sizeof (gcry_mpi_t) * count);
680 for (i = 0; i < count; i++)
681 GNUNET_assert (NULL != (rand[i] = gcry_mpi_new (0)));
682 r = GNUNET_malloc (sizeof (struct GNUNET_CRYPTO_PaillierCiphertext) * count);
683 r_prime = GNUNET_malloc (sizeof (struct GNUNET_CRYPTO_PaillierCiphertext) * count);
684
685 for (i = 0; i < count; i++)
686 {
687 int32_t svalue;
688
689 svalue = (int32_t) GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_WEAK,
690 UINT32_MAX);
691 // long to gcry_mpi_t
692 if (svalue < 0)
693 gcry_mpi_sub_ui (rand[i],
694 rand[i],
695 - svalue);
696 else
697 rand[i] = gcry_mpi_set_ui (rand[i], svalue);
698 }
699
700 tmp = gcry_mpi_new (0);
701 // encrypt the element
702 // for the sake of readability I decided to have dedicated permutation
703 // vectors, which get rid of all the lookups in p/q.
704 // however, ap/aq are not absolutely necessary but are just abstraction
705 // Calculate Kp = E(S + a_pi) (+) E(S - r_pi - b_pi)
706 for (i = 0; i < count; i++)
707 {
708 // E(S - r_pi - b_pi)
709 gcry_mpi_sub (tmp, my_offset, rand[p[i]]);
710 gcry_mpi_sub (tmp, tmp, b[p[i]].value);
711 GNUNET_CRYPTO_paillier_encrypt (&session->cadet->remote_pubkey,
712 tmp,
713 2,
714 &r[i]);
715
716 // E(S - r_pi - b_pi) * E(S + a_pi) == E(2*S + a - r - b)
717 GNUNET_CRYPTO_paillier_hom_add (&session->cadet->remote_pubkey,
718 &r[i],
719 &a[p[i]],
720 &r[i]);
721 }
722
723 // Calculate Kq = E(S + a_qi) (+) E(S - r_qi)
724 for (i = 0; i < count; i++)
725 {
726 // E(S - r_qi)
727 gcry_mpi_sub (tmp, my_offset, rand[q[i]]);
728 GNUNET_assert (2 == GNUNET_CRYPTO_paillier_encrypt (&session->cadet->remote_pubkey,
729 tmp,
730 2,
731 &r_prime[i]));
732
733 // E(S - r_qi) * E(S + a_qi) == E(2*S + a_qi - r_qi)
734 GNUNET_assert (1 == GNUNET_CRYPTO_paillier_hom_add (&session->cadet->remote_pubkey,
735 &r_prime[i],
736 &a[q[i]],
737 &r_prime[i]));
738 }
739
740 // Calculate S' = E(SUM( r_i^2 ))
741 tmp = compute_square_sum (rand, count);
742 GNUNET_CRYPTO_paillier_encrypt (&session->cadet->remote_pubkey,
743 tmp,
744 1,
745 &session->s_prime);
746
747 // Calculate S = E(SUM( (r_i + b_i)^2 ))
748 for (i = 0; i < count; i++)
749 gcry_mpi_add (rand[i], rand[i], b[i].value);
750 tmp = compute_square_sum (rand, count);
751 GNUNET_CRYPTO_paillier_encrypt (&session->cadet->remote_pubkey,
752 tmp,
753 1,
754 &session->s);
755
756 session->r = r;
757 session->r_prime = r_prime;
758
759 // release rand, b and a
760 for (i = 0; i < count; i++)
761 gcry_mpi_release (rand[i]);
762 gcry_mpi_release (tmp);
763 GNUNET_free (session->e_a);
764 session->e_a = NULL;
765 GNUNET_free (p);
766 GNUNET_free (q);
767 GNUNET_free (rand);
768
769 // copy the r[], r_prime[], S and Stick into a new message, prepare_service_response frees these
770}
771
772
773
774
775
776/**
777 * Iterator to copy over messages from the hash map
778 * into an array for sorting.
779 *
780 * @param cls the `struct AliceServiceSession *`
781 * @param key the key (unused)
782 * @param value the `struct GNUNET_SCALARPRODUCT_Element *`
783 */
784static int
785copy_element_cb (void *cls,
786 const struct GNUNET_HashCode *key,
787 void *value)
788{
789 struct BobServiceSession *s = cls;
790 struct GNUNET_SCALARPRODUCT_Element *e = value;
791 gcry_mpi_t mval;
792 int64_t val;
793
794 mval = gcry_mpi_new (0);
795 val = (int64_t) GNUNET_ntohll (e->value);
796 if (0 > val)
797 gcry_mpi_sub_ui (mval, mval, -val);
798 else
799 gcry_mpi_add_ui (mval, mval, val);
800 s->sorted_elements [s->used_element_count].value = mval;
801 s->sorted_elements [s->used_element_count].key = &e->key;
802 s->used_element_count++;
803 return GNUNET_OK;
804}
805
806
807/**
808 * Compare two `struct MpiValue`s by key for sorting.
809 *
810 * @param a pointer to first `struct MpiValue *`
811 * @param b pointer to first `struct MpiValue *`
812 * @return -1 for a < b, 0 for a=b, 1 for a > b.
813 */
814static int
815element_cmp (const void *a,
816 const void *b)
817{
818 const struct MpiElement *ma = *(const struct MpiElement **) a;
819 const struct MpiElement *mb = *(const struct MpiElement **) b;
820
821 return GNUNET_CRYPTO_hash_cmp (ma->key,
822 mb->key);
823}
824
825
826/**
827 * Intersection operation and receiving data via CADET from
828 * Alice are both done, compute and transmit our reply via
829 * CADET.
830 *
831 * @param s session to transmit reply for.
832 */
833static void
834transmit_cryptographic_reply (struct BobServiceSession *s)
835{
836 s->sorted_elements
837 = GNUNET_malloc (GNUNET_CONTAINER_multihashmap_size (s->intersected_elements) *
838 sizeof (struct MpiElement));
839 s->used_element_count = 0;
840 GNUNET_CONTAINER_multihashmap_iterate (s->intersected_elements,
841 &copy_element_cb,
842 s);
843 LOG (GNUNET_ERROR_TYPE_DEBUG,
844 "Finished intersection, %d items remain\n",
845 s->used_element_count);
846 qsort (s->intersected_elements,
847 s->used_element_count,
848 sizeof (struct MpiElement),
849 &element_cmp);
850 compute_service_response (s);
851 transmit_bobs_cryptodata_message (s);
852}
853
854
855/**
856 * Handle a multipart-chunk of a request from another service to
857 * calculate a scalarproduct with us.
858 *
859 * @param cls closure (set from #GNUNET_CADET_connect)
860 * @param channel connection to the other end
861 * @param channel_ctx place to store local state associated with the @a channel
862 * @param message the actual message
863 * @return #GNUNET_OK to keep the connection open,
864 * #GNUNET_SYSERR to close it (signal serious error)
865 */
866static int
867handle_alices_cryptodata_message (void *cls,
868 struct GNUNET_CADET_Channel *channel,
869 void **channel_ctx,
870 const struct GNUNET_MessageHeader *message)
871{
872 struct CadetIncomingSession *in = *channel_ctx;
873 struct BobServiceSession *s;
874 const struct AliceCryptodataMessage *msg;
875 const struct GNUNET_CRYPTO_PaillierCiphertext *payload;
876 uint32_t contained_elements;
877 size_t msg_length;
878 uint16_t msize;
879 unsigned int max;
880
881 if (NULL == in)
882 {
883 GNUNET_break_op (0);
884 return GNUNET_SYSERR;
885 }
886 s = in->s;
887 if (NULL == s)
888 {
889 GNUNET_break_op (0);
890 return GNUNET_SYSERR;
891 }
892 msize = ntohs (message->size);
893 if (msize <= sizeof (struct AliceCryptodataMessage))
894 {
895 GNUNET_break_op (0);
896 return GNUNET_SYSERR;
897 }
898 msg = (const struct AliceCryptodataMessage *) message;
899 contained_elements = ntohl (msg->contained_element_count);
900 /* Our intersection may still be ongoing, but this is nevertheless
901 an upper bound on the required array size */
902 max = GNUNET_CONTAINER_multihashmap_size (s->intersected_elements);
903 msg_length = sizeof (struct AliceCryptodataMessage)
904 + contained_elements * sizeof (struct GNUNET_CRYPTO_PaillierCiphertext);
905 if ( (msize != msg_length) ||
906 (0 == contained_elements) ||
907 (contained_elements > UINT16_MAX) ||
908 (max < contained_elements + s->transferred_element_count) )
909 {
910 GNUNET_break_op (0);
911 return GNUNET_SYSERR;
912 }
913
914 payload = (const struct GNUNET_CRYPTO_PaillierCiphertext *) &msg[1];
915 if (NULL == s->e_a)
916 s->e_a = GNUNET_malloc (sizeof (struct GNUNET_CRYPTO_PaillierCiphertext) *
917 max);
918 memcpy (&s->e_a[s->transferred_element_count],
919 payload,
920 sizeof (struct GNUNET_CRYPTO_PaillierCiphertext) * contained_elements);
921 s->transferred_element_count += contained_elements;
922
923 if ( (s->transferred_element_count == max) &&
924 (NULL == s->intersection_op) )
925 {
926 /* intersection has finished also on our side, and
927 we got the full set, so we can proceed with the
928 CADET response(s) */
929 transmit_cryptographic_reply (s);
930 }
931 return GNUNET_OK;
932}
933
934
935/**
936 * Callback for set operation results. Called for each element
937 * that needs to be removed from the result set.
938 *
939 * @param cls closure with the `struct BobServiceSession`
940 * @param element a result element, only valid if status is #GNUNET_SET_STATUS_OK
941 * @param status what has happened with the set intersection?
942 */
943static void
944cb_intersection_element_removed (void *cls,
945 const struct GNUNET_SET_Element *element,
946 enum GNUNET_SET_Status status)
947{
948 struct BobServiceSession *s = cls;
949 struct GNUNET_SCALARPRODUCT_Element *se;
950
951 switch (status)
952 {
953 case GNUNET_SET_STATUS_OK:
954 /* this element has been removed from the set */
955 se = GNUNET_CONTAINER_multihashmap_get (s->intersected_elements,
956 element->data);
957 LOG (GNUNET_ERROR_TYPE_DEBUG,
958 "Removed element with key %s and value %lld\n",
959 GNUNET_h2s (&se->key),
960 (long long) GNUNET_ntohll (se->value));
961 GNUNET_assert (GNUNET_YES ==
962 GNUNET_CONTAINER_multihashmap_remove (s->intersected_elements,
963 element->data,
964 se));
965 GNUNET_free (se);
966 return;
967 case GNUNET_SET_STATUS_DONE:
968 s->intersection_op = NULL;
969 s->intersection_set = NULL;
970 if (s->transferred_element_count ==
971 GNUNET_CONTAINER_multihashmap_size (s->intersected_elements))
972 {
973 /* CADET transmission from Alice is also already done,
974 start with our own reply */
975 transmit_cryptographic_reply (s);
976 }
977 return;
978 case GNUNET_SET_STATUS_HALF_DONE:
979 /* unexpected for intersection */
980 GNUNET_break (0);
981 return;
982 case GNUNET_SET_STATUS_FAILURE:
983 /* unhandled status code */
984 LOG (GNUNET_ERROR_TYPE_DEBUG,
985 "Set intersection failed!\n");
986 s->intersection_op = NULL;
987 s->intersection_set = NULL;
988 s->active = GNUNET_SYSERR;
989 prepare_client_end_notification (s);
990 return;
991 default:
992 GNUNET_break (0);
993 return;
994 }
995}
996
997
998/**
999 * We've paired up a client session with an incoming CADET request.
1000 * Initiate set intersection work.
1001 *
1002 * @param s client session to start intersection for
1003 */
1004static void
1005start_intersection (struct BobServiceSession *s)
1006{
1007 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1008 "Got session with key %s and a matching element set, processing.\n",
1009 GNUNET_h2s (&s->session_id));
1010
1011 s->intersection_op
1012 = GNUNET_SET_prepare (&s->cadet->peer,
1013 &s->session_id,
1014 NULL,
1015 GNUNET_SET_RESULT_REMOVED,
1016 &cb_intersection_element_removed,
1017 s);
1018 GNUNET_SET_commit (s->intersection_op,
1019 s->intersection_set);
1020}
1021
1022
1023/**
1024 * Handle a request from Alice to calculate a scalarproduct with us (Bob).
1025 *
1026 * @param cls closure (set from #GNUNET_CADET_connect)
1027 * @param channel connection to the other end
1028 * @param channel_ctx place to store the `struct CadetIncomingSession *`
1029 * @param message the actual message
1030 * @return #GNUNET_OK to keep the connection open,
1031 * #GNUNET_SYSERR to close it (signal serious error)
1032 */
1033static int
1034handle_alices_computation_request (void *cls,
1035 struct GNUNET_CADET_Channel *channel,
1036 void **channel_ctx,
1037 const struct GNUNET_MessageHeader *message)
1038{
1039 struct CadetIncomingSession *in = *channel_ctx;
1040 struct BobServiceSession *s;
1041 const struct ServiceRequestMessage *msg;
1042
1043 if (ntohs (message->size) != sizeof (struct ServiceRequestMessage))
1044 {
1045 GNUNET_break_op (0);
1046 return GNUNET_SYSERR;
1047 }
1048 msg = (const struct ServiceRequestMessage *) message;
1049 if (GNUNET_YES == in->in_map)
1050 {
1051 GNUNET_break_op (0);
1052 return GNUNET_SYSERR;
1053 }
1054 if (NULL != find_matching_cadet_session (&msg->session_id))
1055 {
1056 /* not unique, got one like this already */
1057 GNUNET_break_op (0);
1058 return GNUNET_SYSERR;
1059 }
1060 in->session_id = msg->session_id;
1061 in->remote_pubkey = msg->public_key;
1062 GNUNET_assert (GNUNET_YES ==
1063 GNUNET_CONTAINER_multihashmap_put (cadet_sessions,
1064 &in->session_id,
1065 in,
1066 GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY));
1067 s = find_matching_client_session (&in->session_id);
1068 if (NULL == s)
1069 {
1070 /* no client waiting for this request, wait for client */
1071 return GNUNET_OK;
1072 }
1073 GNUNET_assert (NULL == s->cadet);
1074 /* pair them up */
1075 in->s = s;
1076 s->cadet = in;
1077 if (s->transferred_element_count == s->total)
1078 start_intersection (s);
1079 return GNUNET_OK;
1080}
1081
1082
1083/**
1084 * Function called for inbound channels on Bob's end. Does some
1085 * preliminary initialization, more happens after we get Alice's first
1086 * message.
1087 *
1088 * @param cls closure
1089 * @param channel new handle to the channel
1090 * @param initiator peer that started the channel
1091 * @param port unused
1092 * @param options unused
1093 * @return session associated with the channel
1094 */
1095static void *
1096cb_channel_incoming (void *cls,
1097 struct GNUNET_CADET_Channel *channel,
1098 const struct GNUNET_PeerIdentity *initiator,
1099 uint32_t port,
1100 enum GNUNET_CADET_ChannelOption options)
1101{
1102 struct CadetIncomingSession *in;
1103
1104 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1105 "New incoming channel from peer %s.\n",
1106 GNUNET_i2s (initiator));
1107 in = GNUNET_new (struct CadetIncomingSession);
1108 in->peer = *initiator;
1109 in->channel = channel;
1110 return in;
1111}
1112
1113
1114/**
1115 * We're receiving additional set data. Add it to our
1116 * set and if we are done, initiate the transaction.
1117 *
1118 * @param cls closure
1119 * @param client identification of the client
1120 * @param message the actual message
1121 */
1122static void
1123GSS_handle_bob_client_message_multipart (void *cls,
1124 struct GNUNET_SERVER_Client *client,
1125 const struct GNUNET_MessageHeader *message)
1126{
1127 const struct ComputationMultipartMessage * msg;
1128 struct BobServiceSession *s;
1129 uint32_t contained_count;
1130 const struct GNUNET_SCALARPRODUCT_Element *elements;
1131 uint32_t i;
1132 uint16_t msize;
1133 struct GNUNET_SET_Element set_elem;
1134 struct GNUNET_SCALARPRODUCT_Element *elem;
1135
1136 s = GNUNET_SERVER_client_get_user_context (client,
1137 struct BobServiceSession);
1138 if (NULL == s)
1139 {
1140 /* session needs to already exist */
1141 GNUNET_break (0);
1142 GNUNET_SERVER_receive_done (client,
1143 GNUNET_SYSERR);
1144 return;
1145 }
1146 msize = ntohs (message->size);
1147 if (msize < sizeof (struct ComputationMultipartMessage))
1148 {
1149 GNUNET_break (0);
1150 GNUNET_SERVER_receive_done (client,
1151 GNUNET_SYSERR);
1152 return;
1153 }
1154 msg = (const struct ComputationMultipartMessage *) message;
1155 contained_count = ntohl (msg->element_count_contained);
1156
1157 if ( (msize != (sizeof (struct ComputationMultipartMessage) +
1158 contained_count * sizeof (struct GNUNET_SCALARPRODUCT_Element))) ||
1159 (0 == contained_count) ||
1160 (UINT16_MAX < contained_count) ||
1161 (s->total == s->transferred_element_count) ||
1162 (s->total < s->transferred_element_count + contained_count) )
1163 {
1164 GNUNET_break_op (0);
1165 GNUNET_SERVER_receive_done (client,
1166 GNUNET_SYSERR);
1167 return;
1168 }
1169 elements = (const struct GNUNET_SCALARPRODUCT_Element *) &msg[1];
1170 for (i = 0; i < contained_count; i++)
1171 {
1172 if (0 == GNUNET_ntohll (elements[i].value))
1173 continue;
1174 elem = GNUNET_new (struct GNUNET_SCALARPRODUCT_Element);
1175 memcpy (elem,
1176 &elements[i],
1177 sizeof (struct GNUNET_SCALARPRODUCT_Element));
1178 if (GNUNET_SYSERR ==
1179 GNUNET_CONTAINER_multihashmap_put (s->intersected_elements,
1180 &elem->key,
1181 elem,
1182 GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY))
1183 {
1184 GNUNET_break (0);
1185 GNUNET_free (elem);
1186 continue;
1187 }
1188 set_elem.data = &elem->key;
1189 set_elem.size = sizeof (elem->key);
1190 set_elem.element_type = 0;
1191 GNUNET_SET_add_element (s->intersection_set,
1192 &set_elem,
1193 NULL, NULL);
1194 }
1195 s->transferred_element_count += contained_count;
1196 GNUNET_SERVER_receive_done (client,
1197 GNUNET_OK);
1198 if (s->total != s->transferred_element_count)
1199 {
1200 /* more to come */
1201 return;
1202 }
1203 if (NULL == s->cadet)
1204 {
1205 /* no Alice waiting for this request, wait for Alice */
1206 return;
1207 }
1208 start_intersection (s);
1209}
1210
1211
1212/**
1213 * Handler for Bob's a client request message. Bob is in the response
1214 * role, keep the values + session and waiting for a matching session
1215 * or process a waiting request from Alice.
1216 *
1217 * @param cls closure
1218 * @param client identification of the client
1219 * @param message the actual message
1220 */
1221static void
1222GSS_handle_bob_client_message (void *cls,
1223 struct GNUNET_SERVER_Client *client,
1224 const struct GNUNET_MessageHeader *message)
1225{
1226 const struct BobComputationMessage *msg;
1227 struct BobServiceSession *s;
1228 struct CadetIncomingSession *in;
1229 uint32_t contained_count;
1230 uint32_t total_count;
1231 const struct GNUNET_SCALARPRODUCT_Element *elements;
1232 uint32_t i;
1233 struct GNUNET_SET_Element set_elem;
1234 struct GNUNET_SCALARPRODUCT_Element *elem;
1235 uint16_t msize;
1236
1237 s = GNUNET_SERVER_client_get_user_context (client,
1238 struct BobServiceSession);
1239 if (NULL != s)
1240 {
1241 /* only one concurrent session per client connection allowed,
1242 simplifies logic a lot... */
1243 GNUNET_break (0);
1244 GNUNET_SERVER_receive_done (client,
1245 GNUNET_SYSERR);
1246 return;
1247 }
1248 msize = ntohs (message->size);
1249 if (msize < sizeof (struct BobComputationMessage))
1250 {
1251 GNUNET_break (0);
1252 GNUNET_SERVER_receive_done (client,
1253 GNUNET_SYSERR);
1254 return;
1255 }
1256 msg = (const struct BobComputationMessage *) message;
1257 total_count = ntohl (msg->element_count_total);
1258 contained_count = ntohl (msg->element_count_contained);
1259 if ( (0 == total_count) ||
1260 (0 == contained_count) ||
1261 (UINT16_MAX < contained_count) ||
1262 (msize != (sizeof (struct BobComputationMessage) +
1263 contained_count * sizeof (struct GNUNET_SCALARPRODUCT_Element))) )
1264 {
1265 GNUNET_break_op (0);
1266 GNUNET_SERVER_receive_done (client,
1267 GNUNET_SYSERR);
1268 return;
1269 }
1270 if (NULL != find_matching_client_session (&msg->session_key))
1271 {
1272 GNUNET_break (0);
1273 GNUNET_SERVER_receive_done (client,
1274 GNUNET_SYSERR);
1275 return;
1276 }
1277
1278 s = GNUNET_new (struct BobServiceSession);
1279 s->active = GNUNET_YES;
1280 s->client = client;
1281 s->client_mq = GNUNET_MQ_queue_for_server_client (client);
1282 s->total = total_count;
1283 s->transferred_element_count = contained_count;
1284 s->session_id = msg->session_key;
1285 GNUNET_break (GNUNET_YES ==
1286 GNUNET_CONTAINER_multihashmap_put (client_sessions,
1287 &s->session_id,
1288 s,
1289 GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY));
1290 elements = (const struct GNUNET_SCALARPRODUCT_Element *) &msg[1];
1291 s->intersected_elements = GNUNET_CONTAINER_multihashmap_create (s->total,
1292 GNUNET_YES);
1293 s->intersection_set = GNUNET_SET_create (cfg,
1294 GNUNET_SET_OPERATION_INTERSECTION);
1295 for (i = 0; i < contained_count; i++)
1296 {
1297 if (0 == GNUNET_ntohll (elements[i].value))
1298 continue;
1299 elem = GNUNET_new (struct GNUNET_SCALARPRODUCT_Element);
1300 memcpy (elem,
1301 &elements[i],
1302 sizeof (struct GNUNET_SCALARPRODUCT_Element));
1303 if (GNUNET_SYSERR ==
1304 GNUNET_CONTAINER_multihashmap_put (s->intersected_elements,
1305 &elem->key,
1306 elem,
1307 GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY))
1308 {
1309 GNUNET_break (0);
1310 GNUNET_free (elem);
1311 continue;
1312 }
1313 set_elem.data = &elem->key;
1314 set_elem.size = sizeof (elem->key);
1315 set_elem.element_type = 0;
1316 GNUNET_SET_add_element (s->intersection_set,
1317 &set_elem,
1318 NULL, NULL);
1319 s->used_element_count++;
1320 }
1321 GNUNET_SERVER_client_set_user_context (client,
1322 s);
1323 GNUNET_SERVER_receive_done (client,
1324 GNUNET_YES);
1325 if (s->total != s->transferred_element_count)
1326 {
1327 /* multipart msg */
1328 return;
1329 }
1330 in = find_matching_cadet_session (&s->session_id);
1331 if (NULL == in)
1332 {
1333 /* nothing yet, wait for Alice */
1334 return;
1335 }
1336 GNUNET_assert (NULL == in->s);
1337 /* pair them up */
1338 in->s = s;
1339 s->cadet = in;
1340 start_intersection (s);
1341}
1342
1343
1344/**
1345 * Task run during shutdown.
1346 *
1347 * @param cls unused
1348 * @param tc unused
1349 */
1350static void
1351shutdown_task (void *cls,
1352 const struct GNUNET_SCHEDULER_TaskContext *tc)
1353{
1354 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1355 "Shutting down, initiating cleanup.\n");
1356 do_shutdown = GNUNET_YES;
1357 // FIXME: is there a need to shutdown active sessions?
1358 if (NULL != my_cadet)
1359 {
1360 GNUNET_CADET_disconnect (my_cadet);
1361 my_cadet = NULL;
1362 }
1363 GNUNET_CONTAINER_multihashmap_destroy (client_sessions);
1364 client_sessions = NULL;
1365 GNUNET_CONTAINER_multihashmap_destroy (cadet_sessions);
1366 cadet_sessions = NULL;
1367}
1368
1369
1370/**
1371 * A client disconnected.
1372 *
1373 * Remove the associated session(s), release data structures
1374 * and cancel pending outgoing transmissions to the client.
1375 *
1376 * @param cls closure, NULL
1377 * @param client identification of the client
1378 */
1379static void
1380handle_client_disconnect (void *cls,
1381 struct GNUNET_SERVER_Client *client)
1382{
1383 struct BobServiceSession *s;
1384
1385 if (NULL == client)
1386 return;
1387 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1388 "Client disconnected from us.\n",
1389 client);
1390 s = GNUNET_SERVER_client_get_user_context (client,
1391 struct BobServiceSession);
1392 if (NULL == s)
1393 return;
1394 s->client = NULL;
1395 destroy_service_session (s);
1396}
1397
1398
1399/**
1400 * Initialization of the program and message handlers
1401 *
1402 * @param cls closure
1403 * @param server the initialized server
1404 * @param c configuration to use
1405 */
1406static void
1407run (void *cls,
1408 struct GNUNET_SERVER_Handle *server,
1409 const struct GNUNET_CONFIGURATION_Handle *c)
1410{
1411 static const struct GNUNET_SERVER_MessageHandler server_handlers[] = {
1412 { &GSS_handle_bob_client_message, NULL,
1413 GNUNET_MESSAGE_TYPE_SCALARPRODUCT_CLIENT_TO_BOB,
1414 0},
1415 { &GSS_handle_bob_client_message_multipart, NULL,
1416 GNUNET_MESSAGE_TYPE_SCALARPRODUCT_CLIENT_MUTLIPART_BOB,
1417 0},
1418 { NULL, NULL, 0, 0}
1419 };
1420 static const struct GNUNET_CADET_MessageHandler cadet_handlers[] = {
1421 { &handle_alices_computation_request,
1422 GNUNET_MESSAGE_TYPE_SCALARPRODUCT_SESSION_INITIALIZATION,
1423 sizeof (struct ServiceRequestMessage) },
1424 { &handle_alices_cryptodata_message,
1425 GNUNET_MESSAGE_TYPE_SCALARPRODUCT_ALICE_CRYPTODATA,
1426 0},
1427 { NULL, 0, 0}
1428 };
1429 static const uint32_t ports[] = {
1430 GNUNET_APPLICATION_TYPE_SCALARPRODUCT,
1431 0
1432 };
1433
1434 cfg = c;
1435 /*
1436 offset has to be sufficiently small to allow computation of:
1437 m1+m2 mod n == (S + a) + (S + b) mod n,
1438 if we have more complex operations, this factor needs to be lowered */
1439 my_offset = gcry_mpi_new (GNUNET_CRYPTO_PAILLIER_BITS / 3);
1440 gcry_mpi_set_bit (my_offset,
1441 GNUNET_CRYPTO_PAILLIER_BITS / 3);
1442
1443 GNUNET_CRYPTO_paillier_create (&my_pubkey,
1444 &my_privkey);
1445 GNUNET_SERVER_add_handlers (server,
1446 server_handlers);
1447 GNUNET_SERVER_disconnect_notify (server,
1448 &handle_client_disconnect,
1449 NULL);
1450 client_sessions = GNUNET_CONTAINER_multihashmap_create (128,
1451 GNUNET_YES);
1452 cadet_sessions = GNUNET_CONTAINER_multihashmap_create (128,
1453 GNUNET_YES);
1454 my_cadet = GNUNET_CADET_connect (cfg, NULL,
1455 &cb_channel_incoming,
1456 &cb_channel_destruction,
1457 cadet_handlers,
1458 ports);
1459 if (NULL == my_cadet)
1460 {
1461 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1462 _("Connect to CADET failed\n"));
1463 GNUNET_SCHEDULER_shutdown ();
1464 return;
1465 }
1466 GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_FOREVER_REL,
1467 &shutdown_task,
1468 NULL);
1469}
1470
1471
1472/**
1473 * The main function for the scalarproduct service.
1474 *
1475 * @param argc number of arguments from the command line
1476 * @param argv command line arguments
1477 * @return 0 ok, 1 on error
1478 */
1479int
1480main (int argc,
1481 char *const *argv)
1482{
1483 return (GNUNET_OK ==
1484 GNUNET_SERVICE_run (argc, argv,
1485 "scalarproduct-bob",
1486 GNUNET_SERVICE_OPTION_NONE,
1487 &run, NULL)) ? 0 : 1;
1488}
1489
1490/* end of gnunet-service-scalarproduct_bob.c */
diff --git a/src/scalarproduct/scalarproduct.conf.in b/src/scalarproduct/scalarproduct.conf.in
index 5aea5cd7b..a383e37cc 100644
--- a/src/scalarproduct/scalarproduct.conf.in
+++ b/src/scalarproduct/scalarproduct.conf.in
@@ -1,6 +1,10 @@
1[scalarproduct] 1[scalarproduct-alice]
2BINARY = gnunet-service-scalarproduct 2BINARY = gnunet-service-scalarproduct-alice
3UNIXPATH = $GNUNET_RUNTIME_DIR/gnunet-service-scalarproduct.sock 3UNIXPATH = $GNUNET_RUNTIME_DIR/gnunet-service-scalarproduct-alice.sock
4# PORT = 2106 4@UNIXONLY@ PORT = 2117
5@UNIXONLY@ PORT = 2087 5
6[scalarproduct-bob]
7BINARY = gnunet-service-scalarproduct-bob
8UNIXPATH = $GNUNET_RUNTIME_DIR/gnunet-service-scalarproduct-bob.sock
9@UNIXONLY@ PORT = 2118
6 10
diff --git a/src/scalarproduct/scalarproduct.h b/src/scalarproduct/scalarproduct.h
index 4bafb18fb..bcd2d6821 100644
--- a/src/scalarproduct/scalarproduct.h
+++ b/src/scalarproduct/scalarproduct.h
@@ -17,23 +17,14 @@
17 Free Software Foundation, Inc., 59 Temple Place - Suite 330, 17 Free Software Foundation, Inc., 59 Temple Place - Suite 330,
18 Boston, MA 02111-1307, USA. 18 Boston, MA 02111-1307, USA.
19*/ 19*/
20
21/** 20/**
22 * @file scalarproduct.h 21 * @file scalarproduct.h
23 * @brief Scalar Product Message Types 22 * @brief Scalar Product Message Types
24 * @author Christian M. Fuchs 23 * @author Christian M. Fuchs
25 *
26 * Created on September 2, 2013, 3:43 PM
27 */ 24 */
28
29#ifndef SCALARPRODUCT_H 25#ifndef SCALARPRODUCT_H
30#define SCALARPRODUCT_H 26#define SCALARPRODUCT_H
31 27
32#ifdef __cplusplus
33extern "C"
34{
35#endif
36
37GNUNET_NETWORK_STRUCT_BEGIN 28GNUNET_NETWORK_STRUCT_BEGIN
38 29
39/** 30/**
@@ -48,10 +39,11 @@ GNUNET_NETWORK_STRUCT_BEGIN
48 * Message type passed from client to service 39 * Message type passed from client to service
49 * to initiate a request or responder role 40 * to initiate a request or responder role
50 */ 41 */
51struct ComputationMessage 42struct AliceComputationMessage
52{ 43{
53 /** 44 /**
54 * GNUNET message header 45 * GNUNET message header with type
46 * #GNUNET_MESSAGE_TYPE_SCALARPRODUCT_CLIENT_TO_ALICE
55 */ 47 */
56 struct GNUNET_MessageHeader header; 48 struct GNUNET_MessageHeader header;
57 49
@@ -87,6 +79,44 @@ struct ComputationMessage
87 79
88 80
89/** 81/**
82 * Message type passed from client to service
83 * to initiate a request or responder role
84 */
85struct BobComputationMessage
86{
87 /**
88 * GNUNET message header with type
89 * #GNUNET_MESSAGE_TYPE_SCALARPRODUCT_CLIENT_TO_BOB
90 */
91 struct GNUNET_MessageHeader header;
92
93 /**
94 * how many elements the vector in payload contains
95 */
96 uint32_t element_count_total GNUNET_PACKED;
97
98 /**
99 * contained elements the vector in payload contains
100 */
101 uint32_t element_count_contained GNUNET_PACKED;
102
103 /**
104 * Always zero.
105 */
106 uint32_t reserved GNUNET_PACKED;
107
108 /**
109 * the transaction/session key used to identify a session
110 */
111 struct GNUNET_HashCode session_key;
112
113 /**
114 * followed by struct GNUNET_SCALARPRODUCT_Element[]
115 */
116};
117
118
119/**
90 * multipart messages following `struct ComputationMessage` 120 * multipart messages following `struct ComputationMessage`
91 */ 121 */
92struct ComputationMultipartMessage 122struct ComputationMultipartMessage
@@ -140,9 +170,5 @@ struct ClientResponseMessage
140 170
141GNUNET_NETWORK_STRUCT_END 171GNUNET_NETWORK_STRUCT_END
142 172
143#ifdef __cplusplus
144}
145#endif
146
147#endif /* SCALARPRODUCT_H */ 173#endif /* SCALARPRODUCT_H */
148 174
diff --git a/src/scalarproduct/scalarproduct_api.c b/src/scalarproduct/scalarproduct_api.c
index 5cb827838..8a4a0af98 100644
--- a/src/scalarproduct/scalarproduct_api.c
+++ b/src/scalarproduct/scalarproduct_api.c
@@ -23,6 +23,8 @@
23 * @author Christian Fuchs 23 * @author Christian Fuchs
24 * @author Gaurav Kukreja 24 * @author Gaurav Kukreja
25 * @author Christian Grothoff 25 * @author Christian Grothoff
26 *
27 * TODO: use MQ
26 */ 28 */
27#include "platform.h" 29#include "platform.h"
28#include "gnunet_util_lib.h" 30#include "gnunet_util_lib.h"
@@ -113,6 +115,11 @@ struct GNUNET_SCALARPRODUCT_ComputationHandle
113 */ 115 */
114 uint32_t element_count_transfered; 116 uint32_t element_count_transfered;
115 117
118 /**
119 * Type to use for the multipart messages.
120 */
121 uint16_t mp_type;
122
116}; 123};
117 124
118 125
@@ -307,7 +314,7 @@ do_send_message (void *cls,
307 msg = GNUNET_malloc (nsize); 314 msg = GNUNET_malloc (nsize);
308 h->msg = &msg->header; 315 h->msg = &msg->header;
309 msg->header.size = htons (nsize); 316 msg->header.size = htons (nsize);
310 msg->header.type = htons (GNUNET_MESSAGE_TYPE_SCALARPRODUCT_CLIENT_MUTLIPART); 317 msg->header.type = htons (h->mp_type);
311 msg->element_count_contained = htonl (todo); 318 msg->element_count_contained = htonl (todo);
312 memcpy (&msg[1], 319 memcpy (&msg[1],
313 &h->elements[h->element_count_transfered], 320 &h->elements[h->element_count_transfered],
@@ -342,7 +349,7 @@ GNUNET_SCALARPRODUCT_accept_computation (const struct GNUNET_CONFIGURATION_Handl
342 void *cont_cls) 349 void *cont_cls)
343{ 350{
344 struct GNUNET_SCALARPRODUCT_ComputationHandle *h; 351 struct GNUNET_SCALARPRODUCT_ComputationHandle *h;
345 struct ComputationMessage *msg; 352 struct BobComputationMessage *msg;
346 uint32_t size; 353 uint32_t size;
347 uint16_t possible; 354 uint16_t possible;
348 355
@@ -352,8 +359,9 @@ GNUNET_SCALARPRODUCT_accept_computation (const struct GNUNET_CONFIGURATION_Handl
352 h->response_proc = &process_status_message; 359 h->response_proc = &process_status_message;
353 h->cfg = cfg; 360 h->cfg = cfg;
354 h->key = *session_key; 361 h->key = *session_key;
355 h->client = GNUNET_CLIENT_connect ("scalarproduct", cfg); 362 h->client = GNUNET_CLIENT_connect ("scalarproduct-bob", cfg);
356 h->element_count_total = element_count; 363 h->element_count_total = element_count;
364 h->mp_type = GNUNET_MESSAGE_TYPE_SCALARPRODUCT_CLIENT_MUTLIPART_BOB;
357 if (NULL == h->client) 365 if (NULL == h->client)
358 { 366 {
359 /* scalarproduct configuration error */ 367 /* scalarproduct configuration error */
@@ -361,7 +369,7 @@ GNUNET_SCALARPRODUCT_accept_computation (const struct GNUNET_CONFIGURATION_Handl
361 GNUNET_free (h); 369 GNUNET_free (h);
362 return NULL; 370 return NULL;
363 } 371 }
364 size = sizeof (struct ComputationMessage) 372 size = sizeof (struct BobComputationMessage)
365 + element_count * sizeof (struct GNUNET_SCALARPRODUCT_Element); 373 + element_count * sizeof (struct GNUNET_SCALARPRODUCT_Element);
366 if (GNUNET_SERVER_MAX_MESSAGE_SIZE > size) 374 if (GNUNET_SERVER_MAX_MESSAGE_SIZE > size)
367 { 375 {
@@ -371,10 +379,10 @@ GNUNET_SCALARPRODUCT_accept_computation (const struct GNUNET_CONFIGURATION_Handl
371 else 379 else
372 { 380 {
373 /* create a multipart msg, first we calculate a new msg size for the head msg */ 381 /* create a multipart msg, first we calculate a new msg size for the head msg */
374 possible = (GNUNET_SERVER_MAX_MESSAGE_SIZE - 1 - sizeof (struct ComputationMessage)) 382 possible = (GNUNET_SERVER_MAX_MESSAGE_SIZE - 1 - sizeof (struct BobComputationMessage))
375 / sizeof (struct GNUNET_SCALARPRODUCT_Element); 383 / sizeof (struct GNUNET_SCALARPRODUCT_Element);
376 h->element_count_transfered = possible; 384 h->element_count_transfered = possible;
377 size = sizeof (struct ComputationMessage) 385 size = sizeof (struct BobComputationMessage)
378 + possible * sizeof (struct GNUNET_SCALARPRODUCT_Element); 386 + possible * sizeof (struct GNUNET_SCALARPRODUCT_Element);
379 h->elements = GNUNET_malloc (sizeof(struct GNUNET_SCALARPRODUCT_Element) * element_count); 387 h->elements = GNUNET_malloc (sizeof(struct GNUNET_SCALARPRODUCT_Element) * element_count);
380 memcpy (h->elements, 388 memcpy (h->elements,
@@ -423,12 +431,12 @@ GNUNET_SCALARPRODUCT_start_computation (const struct GNUNET_CONFIGURATION_Handle
423 void *cont_cls) 431 void *cont_cls)
424{ 432{
425 struct GNUNET_SCALARPRODUCT_ComputationHandle *h; 433 struct GNUNET_SCALARPRODUCT_ComputationHandle *h;
426 struct ComputationMessage *msg; 434 struct AliceComputationMessage *msg;
427 uint32_t size; 435 uint32_t size;
428 uint32_t possible; 436 uint32_t possible;
429 437
430 h = GNUNET_new (struct GNUNET_SCALARPRODUCT_ComputationHandle); 438 h = GNUNET_new (struct GNUNET_SCALARPRODUCT_ComputationHandle);
431 h->client = GNUNET_CLIENT_connect ("scalarproduct", cfg); 439 h->client = GNUNET_CLIENT_connect ("scalarproduct-alice", cfg);
432 if (NULL == h->client) 440 if (NULL == h->client)
433 { 441 {
434 /* missconfigured scalarproduct service */ 442 /* missconfigured scalarproduct service */
@@ -442,7 +450,8 @@ GNUNET_SCALARPRODUCT_start_computation (const struct GNUNET_CONFIGURATION_Handle
442 h->response_proc = &process_result_message; 450 h->response_proc = &process_result_message;
443 h->cfg = cfg; 451 h->cfg = cfg;
444 h->key = *session_key; 452 h->key = *session_key;
445 size = sizeof (struct ComputationMessage) 453 h->mp_type = GNUNET_MESSAGE_TYPE_SCALARPRODUCT_CLIENT_MUTLIPART_ALICE;
454 size = sizeof (struct AliceComputationMessage)
446 + element_count * sizeof (struct GNUNET_SCALARPRODUCT_Element); 455 + element_count * sizeof (struct GNUNET_SCALARPRODUCT_Element);
447 if (GNUNET_SERVER_MAX_MESSAGE_SIZE > size) 456 if (GNUNET_SERVER_MAX_MESSAGE_SIZE > size)
448 { 457 {
@@ -452,10 +461,10 @@ GNUNET_SCALARPRODUCT_start_computation (const struct GNUNET_CONFIGURATION_Handle
452 else 461 else
453 { 462 {
454 /* create a multipart msg, first we calculate a new msg size for the head msg */ 463 /* create a multipart msg, first we calculate a new msg size for the head msg */
455 possible = (GNUNET_SERVER_MAX_MESSAGE_SIZE - 1 - sizeof (struct ComputationMessage)) 464 possible = (GNUNET_SERVER_MAX_MESSAGE_SIZE - 1 - sizeof (struct AliceComputationMessage))
456 / sizeof (struct GNUNET_SCALARPRODUCT_Element); 465 / sizeof (struct GNUNET_SCALARPRODUCT_Element);
457 h->element_count_transfered = possible; 466 h->element_count_transfered = possible;
458 size = sizeof (struct ComputationMessage) 467 size = sizeof (struct AliceComputationMessage)
459 + possible * sizeof (struct GNUNET_SCALARPRODUCT_Element); 468 + possible * sizeof (struct GNUNET_SCALARPRODUCT_Element);
460 h->elements = GNUNET_malloc (sizeof(struct GNUNET_SCALARPRODUCT_Element) * element_count); 469 h->elements = GNUNET_malloc (sizeof(struct GNUNET_SCALARPRODUCT_Element) * element_count);
461 memcpy (h->elements, 470 memcpy (h->elements,
diff --git a/src/scalarproduct/test_scalarproduct.conf b/src/scalarproduct/test_scalarproduct.conf
index fb9a34da6..b61197dac 100644
--- a/src/scalarproduct/test_scalarproduct.conf
+++ b/src/scalarproduct/test_scalarproduct.conf
@@ -1,5 +1,5 @@
1[arm] 1[arm]
2DEFAULTSERVICES = core cadet statistics scalarproduct set 2DEFAULTSERVICES = core cadet statistics set
3PORT = 12366 3PORT = 12366
4 4
5[PATHS] 5[PATHS]