2 This file is part of GNUnet.
3 (C) 2013 Christian Grothoff (and other contributing authors)
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.
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.
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.
22 * @file scalarproduct/gnunet-service-scalarproduct.c
23 * @brief scalarproduct service implementation
24 * @author Christian M. Fuchs
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"
38 #define LOG(kind,...) GNUNET_log_from (kind, "scalarproduct", __VA_ARGS__)
40 ///////////////////////////////////////////////////////////////////////////////
41 // Service Structure Definitions
42 ///////////////////////////////////////////////////////////////////////////////
46 * role a peer in a session can assume
57 struct SortedValue * next;
58 struct SortedValue * prev;
59 struct GNUNET_SCALARPRODUCT_Element * elem;
65 * A scalarproduct session which tracks:
67 * a request form the client to our final response.
69 * a request from a service to us(service).
74 * the role this peer has
79 * session information is kept in a DLL
81 struct ServiceSession *next;
84 * session information is kept in a DLL
86 struct ServiceSession *prev;
89 * (hopefully) unique transaction ID
91 struct GNUNET_HashCode session_id;
94 * Alice or Bob's peerID
96 struct GNUNET_PeerIdentity peer;
99 * the client this request is related to
101 struct GNUNET_SERVER_Client * client;
104 * The message to send
106 struct GNUNET_MessageHeader * msg;
109 * how many elements we were supplied with from the client
114 * how many elements we used for intersection
116 uint32_t intersected_elements_count;
119 * all non-0-value'd elements transmitted to us
121 struct GNUNET_CONTAINER_MultiHashMap * intersected_elements;
124 * how many elements actually are used for the scalar product
126 uint32_t used_elements_count;
129 * already transferred elements (sent/received) for multipart messages, less or equal than used_element_count for
131 uint32_t transferred_element_count;
134 * Set of elements for which will conduction an intersection.
135 * the resulting elements are then used for computing the scalar product.
137 struct GNUNET_SET_Handle * intersection_set;
140 * Set of elements for which will conduction an intersection.
141 * the resulting elements are then used for computing the scalar product.
143 struct GNUNET_SET_OperationHandle * intersection_op;
146 * Handle to Alice's Intersection operation listening for Bob
148 struct GNUNET_SET_ListenHandle * intersection_listen;
151 * Public key of the remote service, only used by bob
153 struct GNUNET_CRYPTO_PaillierPublicKey remote_pubkey;
156 * DLL for sorting elements after intersection
158 struct SortedValue * a_head;
163 struct SortedValue * a_tail;
168 gcry_mpi_t * sorted_elements;
171 * E(ai)(Bob) after applying the mask
173 struct GNUNET_CRYPTO_PaillierCiphertext * e_a;
176 * Bob's permutation p of R
178 struct GNUNET_CRYPTO_PaillierCiphertext * r;
181 * Bob's permutation q of R
183 struct GNUNET_CRYPTO_PaillierCiphertext * r_prime;
188 struct GNUNET_CRYPTO_PaillierCiphertext * s;
193 struct GNUNET_CRYPTO_PaillierCiphertext * s_prime;
196 * Bobs matching response session from the client
198 struct ServiceSession * response;
201 * The computed scalar
206 * My transmit handle for the current message to a alice/bob
208 struct GNUNET_CADET_TransmitHandle * service_transmit_handle;
211 * My transmit handle for the current message to the client
213 struct GNUNET_SERVER_TransmitHandle * client_transmit_handle;
216 * channel-handle associated with our cadet handle
218 struct GNUNET_CADET_Channel * channel;
221 * Handle to a task that sends a msg to the our client
223 GNUNET_SCHEDULER_TaskIdentifier client_notification_task;
226 ///////////////////////////////////////////////////////////////////////////////
227 // Forward Delcarations
228 ///////////////////////////////////////////////////////////////////////////////
231 * Send a multi part chunk of a service request from alice to bob.
232 * This element only contains a part of the elements-vector (session->a[]),
233 * mask and public key set have to be contained within the first message
235 * This allows a ~32kbit key length while using 32000 elements or 62000 elements per request.
237 * @param cls the associated service session
240 prepare_alices_cyrptodata_message_multipart (void *cls);
243 * Send a multi part chunk of a service response from bob to alice.
244 * This element only contains the two permutations of R, R'.
246 * @param cls the associated service session
249 prepare_bobs_cryptodata_message_multipart (void *cls);
252 ///////////////////////////////////////////////////////////////////////////////
254 ///////////////////////////////////////////////////////////////////////////////
258 * Gnunet configuration handle
260 const struct GNUNET_CONFIGURATION_Handle * cfg;
263 * Handle to the core service (NULL until we've connected to it).
265 static struct GNUNET_CADET_Handle *my_cadet;
268 * The identity of this host.
270 static struct GNUNET_PeerIdentity me;
273 * Service's own public key
275 static struct GNUNET_CRYPTO_PaillierPublicKey my_pubkey;
278 * Service's own private key
280 static struct GNUNET_CRYPTO_PaillierPrivateKey my_privkey;
283 * Service's offset for values that could possibly be negative but are plaintext for encryption.
285 static gcry_mpi_t my_offset;
288 * Head of our double linked list for client-requests sent to us.
289 * for all of these elements we calculate a scalar product with a remote peer
290 * split between service->service and client->service for simplicity
292 static struct ServiceSession * from_client_head;
294 * Tail of our double linked list for client-requests sent to us.
295 * for all of these elements we calculate a scalar product with a remote peer
296 * split between service->service and client->service for simplicity
298 static struct ServiceSession * from_client_tail;
301 * Head of our double linked list for service-requests sent to us.
302 * for all of these elements we help the requesting service in calculating a scalar product
303 * split between service->service and client->service for simplicity
305 static struct ServiceSession * from_service_head;
308 * Tail of our double linked list for service-requests sent to us.
309 * for all of these elements we help the requesting service in calculating a scalar product
310 * split between service->service and client->service for simplicity
312 static struct ServiceSession * from_service_tail;
315 * Certain events (callbacks for server & cadet operations) must not be queued after shutdown.
317 static int do_shutdown;
319 ///////////////////////////////////////////////////////////////////////////////
321 ///////////////////////////////////////////////////////////////////////////////
325 * computes the square sum over a vector of a given length.
327 * @param vector the vector to encrypt
328 * @param length the length of the vector
329 * @return an MPI value containing the calculated sum, never NULL
332 compute_square_sum (gcry_mpi_t * vector, uint32_t length)
338 GNUNET_assert (sum = gcry_mpi_new (0));
339 GNUNET_assert (elem = gcry_mpi_new (0));
341 // calculare E(sum (ai ^ 2), publickey)
342 for (i = 0; i < length; i++) {
343 gcry_mpi_mul (elem, vector[i], vector[i]);
344 gcry_mpi_add (sum, sum, elem);
346 gcry_mpi_release (elem);
353 * Primitive callback for copying over a message, as they
354 * usually are too complex to be handled in the callback itself.
355 * clears a session-callback, if a session was handed over and the transmit handle was stored
357 * @param cls the session containing the message object
358 * @param size the size of the buffer we got
359 * @param buf the buffer to copy the message to
360 * @return 0 if we couldn't copy, else the size copied over
363 do_send_message (void *cls, size_t size, void *buf)
365 struct ServiceSession * s = cls;
370 if (ntohs (s->msg->size) != size) {
375 type = ntohs (s->msg->type);
376 memcpy (buf, s->msg, size);
377 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
378 "Sent a message of type %hu.\n",
380 GNUNET_free (s->msg);
385 case GNUNET_MESSAGE_TYPE_SCALARPRODUCT_RESULT:
386 s->client_transmit_handle = NULL;
389 case GNUNET_MESSAGE_TYPE_SCALARPRODUCT_ALICE_CRYPTODATA:
390 case GNUNET_MESSAGE_TYPE_SCALARPRODUCT_ALICE_CRYPTODATA_MULTIPART:
391 s->service_transmit_handle = NULL;
392 if (s->used_elements_count != s->transferred_element_count)
393 prepare_alices_cyrptodata_message_multipart (s);
396 case GNUNET_MESSAGE_TYPE_SCALARPRODUCT_BOB_CRYPTODATA:
397 case GNUNET_MESSAGE_TYPE_SCALARPRODUCT_BOB_CRYPTODATA_MULTIPART:
398 s->service_transmit_handle = NULL;
399 if (s->used_elements_count != s->transferred_element_count)
400 prepare_bobs_cryptodata_message_multipart (s);
412 * Finds a not terminated client/service session in the
413 * given DLL based on session key, element count and state.
415 * @param tail - the tail of the DLL
416 * @param key - the key we want to search for
417 * @param element_count - the total element count of the dataset (session->total)
418 * @param peerid - a pointer to the peer ID of the associated peer, NULL to ignore
419 * @return a pointer to a matching session, or NULL
421 static struct ServiceSession *
422 find_matching_session (struct ServiceSession * tail,
423 const struct GNUNET_HashCode * key,
424 uint32_t element_count,
425 const struct GNUNET_PeerIdentity * peerid)
427 struct ServiceSession * curr;
429 for (curr = tail; NULL != curr; curr = curr->prev) {
430 // if the key matches, and the element_count is same
431 if ((!memcmp (&curr->session_id, key, sizeof (struct GNUNET_HashCode)))
432 && (curr->total == element_count)) {
433 // if peerid is NULL OR same as the peer Id in the queued request
435 || (!memcmp (&curr->peer, peerid, sizeof (struct GNUNET_PeerIdentity))))
436 // matches and is not an already terminated session
446 * Safely frees ALL memory areas referenced by a session.
448 * @param session - the session to free elements from
451 free_session_variables (struct ServiceSession * session)
453 while (NULL != session->a_head) {
454 struct SortedValue * e = session->a_head;
455 GNUNET_free (e->elem);
456 gcry_mpi_release (e->val);
457 GNUNET_CONTAINER_DLL_remove (session->a_head, session->a_tail, e);
461 GNUNET_free (session->e_a);
464 if (session->sorted_elements) {
465 GNUNET_free (session->sorted_elements);
466 session->sorted_elements = NULL;
468 if (session->intersected_elements) {
469 GNUNET_CONTAINER_multihashmap_destroy (session->intersected_elements);
470 //elements are freed independently in session->a_head/tail
471 session->intersected_elements = NULL;
473 if (session->intersection_listen) {
474 GNUNET_SET_listen_cancel (session->intersection_listen);
475 session->intersection_listen = NULL;
477 if (session->intersection_op) {
478 GNUNET_SET_operation_cancel (session->intersection_op);
479 session->intersection_op = NULL;
481 if (session->intersection_set) {
482 GNUNET_SET_destroy (session->intersection_set);
483 session->intersection_set = NULL;
486 GNUNET_free (session->msg);
490 GNUNET_free (session->r);
493 if (session->r_prime) {
494 GNUNET_free (session->r_prime);
495 session->r_prime = NULL;
498 GNUNET_free (session->s);
501 if (session->s_prime) {
502 GNUNET_free (session->s_prime);
503 session->s_prime = NULL;
505 if (session->product) {
506 gcry_mpi_release (session->product);
507 session->product = NULL;
510 ///////////////////////////////////////////////////////////////////////////////
511 // Event and Message Handlers
512 ///////////////////////////////////////////////////////////////////////////////
516 * A client disconnected.
518 * Remove the associated session(s), release data structures
519 * and cancel pending outgoing transmissions to the client.
520 * if the session has not yet completed, we also cancel Alice's request to Bob.
522 * @param cls closure, NULL
523 * @param client identification of the client
526 handle_client_disconnect (void *cls,
527 struct GNUNET_SERVER_Client *client)
529 struct ServiceSession *session;
532 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
533 _ ("Client (%p) disconnected from us.\n"), client);
537 session = GNUNET_SERVER_client_get_user_context (client, struct ServiceSession);
540 GNUNET_CONTAINER_DLL_remove (from_client_head, from_client_tail, session);
542 if (!(session->role == BOB && 0/*//TODO: if session concluded*/)) {
543 //we MUST terminate any client message underway
544 if (session->service_transmit_handle && session->channel)
545 GNUNET_CADET_notify_transmit_ready_cancel (session->service_transmit_handle);
546 if (session->channel && 0/* //TODO: waiting for service response */)
547 GNUNET_CADET_channel_destroy (session->channel);
549 if (GNUNET_SCHEDULER_NO_TASK != session->client_notification_task) {
550 GNUNET_SCHEDULER_cancel (session->client_notification_task);
551 session->client_notification_task = GNUNET_SCHEDULER_NO_TASK;
553 if (NULL != session->client_transmit_handle) {
554 GNUNET_SERVER_notify_transmit_ready_cancel (session->client_transmit_handle);
555 session->client_transmit_handle = NULL;
557 free_session_variables (session);
558 GNUNET_free (session);
563 * Notify the client that the session has succeeded or failed completely.
564 * This message gets sent to
565 * * alice's client if bob disconnected or to
566 * * bob's client if the operation completed or alice disconnected
568 * @param cls the associated client session
569 * @param tc the task context handed to us by the scheduler, unused
572 prepare_client_end_notification (void * cls,
573 const struct GNUNET_SCHEDULER_TaskContext * tc)
575 struct ServiceSession * session = cls;
576 struct GNUNET_SCALARPRODUCT_client_response * msg;
578 session->client_notification_task = GNUNET_SCHEDULER_NO_TASK;
580 msg = GNUNET_new (struct GNUNET_SCALARPRODUCT_client_response);
581 msg->header.type = htons (GNUNET_MESSAGE_TYPE_SCALARPRODUCT_RESULT);
582 memcpy (&msg->key, &session->session_id, sizeof (struct GNUNET_HashCode));
583 memcpy (&msg->peer, &session->peer, sizeof ( struct GNUNET_PeerIdentity));
584 msg->header.size = htons (sizeof (struct GNUNET_SCALARPRODUCT_client_response));
585 // signal error if not signalized, positive result-range field but zero length.
586 msg->product_length = htonl (0);
587 msg->range = (session /* //TODO: if finalized */) ? 0 : -1;
589 session->msg = &msg->header;
591 //transmit this message to our client
592 session->client_transmit_handle =
593 GNUNET_SERVER_notify_transmit_ready (session->client,
594 sizeof (struct GNUNET_SCALARPRODUCT_client_response),
595 GNUNET_TIME_UNIT_FOREVER_REL,
599 // if we could not even queue our request, something is wrong
600 if (NULL == session->client_transmit_handle) {
601 GNUNET_log (GNUNET_ERROR_TYPE_WARNING, _ ("Could not send message to client (%p)!\n"), session->client);
602 // usually gets freed by do_send_message
607 GNUNET_log (GNUNET_ERROR_TYPE_INFO, _ ("Sending session-end notification to client (%p) for session %s\n"), &session->client, GNUNET_h2s (&session->session_id));
609 free_session_variables (session);
614 * Executed by Alice, fills in a service-request message and sends it to the given peer
616 * @param cls the session associated with this request
619 prepare_alices_cyrptodata_message (void *cls)
621 struct ServiceSession * session = cls;
622 struct GNUNET_SCALARPRODUCT_alices_cryptodata_message * msg;
623 struct GNUNET_CRYPTO_PaillierCiphertext * payload;
628 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, _ ("Successfully created new channel to peer (%s)!\n"), GNUNET_i2s (&session->peer));
630 msg_length = sizeof (struct GNUNET_SCALARPRODUCT_alices_cryptodata_message)
631 +session->used_elements_count * sizeof (struct GNUNET_CRYPTO_PaillierCiphertext);
633 if (GNUNET_SERVER_MAX_MESSAGE_SIZE > msg_length) {
634 session->transferred_element_count = session->used_elements_count;
637 //create a multipart msg, first we calculate a new msg size for the head msg
638 session->transferred_element_count = (GNUNET_SERVER_MAX_MESSAGE_SIZE - 1 - sizeof (struct GNUNET_SCALARPRODUCT_alices_cryptodata_message))
639 / sizeof (struct GNUNET_CRYPTO_PaillierCiphertext);
640 msg_length = sizeof (struct GNUNET_SCALARPRODUCT_alices_cryptodata_message)
641 +session->transferred_element_count * sizeof (struct GNUNET_CRYPTO_PaillierCiphertext);
644 msg = GNUNET_malloc (msg_length);
645 msg->header.size = htons (msg_length);
646 msg->header.type = htons (GNUNET_MESSAGE_TYPE_SCALARPRODUCT_ALICE_CRYPTODATA);
647 msg->contained_element_count = htonl (session->transferred_element_count);
649 // fill in the payload
650 payload = (struct GNUNET_CRYPTO_PaillierCiphertext *) &msg[1];
652 // now copy over the sorted element vector
653 a = gcry_mpi_new (0);
654 for (i = 0; i < session->transferred_element_count; i++) {
655 gcry_mpi_add (a, session->sorted_elements[i], my_offset);
656 GNUNET_CRYPTO_paillier_encrypt (&my_pubkey, a, 3, &payload[i]);
658 gcry_mpi_release (a);
660 session->msg = (struct GNUNET_MessageHeader *) msg;
661 GNUNET_log (GNUNET_ERROR_TYPE_INFO, _ ("Transmitting service request.\n"));
663 //transmit via cadet messaging
664 session->service_transmit_handle = GNUNET_CADET_notify_transmit_ready (session->channel, GNUNET_YES,
665 GNUNET_TIME_UNIT_FOREVER_REL,
669 if (NULL == session->service_transmit_handle) {
670 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, _ ("Could not send message to channel!\n"));
673 session->client_notification_task =
674 GNUNET_SCHEDULER_add_now (&prepare_client_end_notification,
682 * Send a multipart chunk of a service response from bob to alice.
683 * This element only contains the two permutations of R, R'.
685 * @param cls the associated service session
688 prepare_bobs_cryptodata_message_multipart (void *cls)
690 struct ServiceSession * session = cls;
691 struct GNUNET_CRYPTO_PaillierCiphertext * payload;
692 struct GNUNET_SCALARPRODUCT_multipart_message * msg;
698 msg_length = sizeof (struct GNUNET_SCALARPRODUCT_multipart_message);
699 todo_count = session->used_elements_count - session->transferred_element_count;
701 if (todo_count > MULTIPART_ELEMENT_CAPACITY / 2)
702 // send the currently possible maximum chunk, we always transfer both permutations
703 todo_count = MULTIPART_ELEMENT_CAPACITY / 2;
705 msg_length += todo_count * sizeof (struct GNUNET_CRYPTO_PaillierCiphertext) * 2;
706 msg = GNUNET_malloc (msg_length);
707 msg->header.type = htons (GNUNET_MESSAGE_TYPE_SCALARPRODUCT_ALICE_CRYPTODATA_MULTIPART);
708 msg->header.size = htons (msg_length);
709 msg->contained_element_count = htonl (todo_count);
711 payload = (struct GNUNET_CRYPTO_PaillierCiphertext *) &msg[1];
712 for (i = session->transferred_element_count, j = 0; i < session->transferred_element_count + todo_count; i++) {
713 //r[i][p] and r[i][q]
714 memcpy (&payload[j++], &session->r[i], sizeof (struct GNUNET_CRYPTO_PaillierCiphertext));
715 memcpy (&payload[j++], &session->r_prime[i], sizeof (struct GNUNET_CRYPTO_PaillierCiphertext));
717 session->transferred_element_count += todo_count;
718 session->msg = (struct GNUNET_MessageHeader *) msg;
719 session->service_transmit_handle =
720 GNUNET_CADET_notify_transmit_ready (session->channel,
722 GNUNET_TIME_UNIT_FOREVER_REL,
726 //disconnect our client
727 if (NULL == session->service_transmit_handle) {
728 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, _ ("Could not send service-response message via cadet!)\n"));
730 session->response->client_notification_task =
731 GNUNET_SCHEDULER_add_now (&prepare_client_end_notification,
735 if (session->transferred_element_count != session->used_elements_count) {
740 GNUNET_free (session->r_prime);
741 GNUNET_free (session->r);
742 session->r_prime = NULL;
750 * generates the response message to be sent to alice after computing
751 * the values (1), (2), S and S'
752 * (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)})$
753 * (2)[]: $E_A(a_{pi'(i)}) times E_A(- r_{pi'(i)}) &= E_A(a_{pi'(i)} - r_{pi'(i)})$
754 * S: $S := E_A(sum (r_i + b_i)^2)$
755 * S': $S' := E_A(sum r_i^2)$
757 * @param session the associated requesting session with alice
760 prepare_bobs_cryptodata_message (void *cls,
761 const struct GNUNET_SCHEDULER_TaskContext
764 struct ServiceSession * session = (struct ServiceSession *) cls;
765 struct GNUNET_SCALARPRODUCT_service_response * msg;
766 uint32_t msg_length = 0;
767 struct GNUNET_CRYPTO_PaillierCiphertext * payload;
770 msg_length = sizeof (struct GNUNET_SCALARPRODUCT_service_response)
771 + 2 * sizeof (struct GNUNET_CRYPTO_PaillierCiphertext); // s, stick
773 if (GNUNET_SERVER_MAX_MESSAGE_SIZE >
774 msg_length + 2 * session->used_elements_count * sizeof (struct GNUNET_CRYPTO_PaillierCiphertext)) { //r, r'
775 msg_length += 2 * session->used_elements_count * sizeof (struct GNUNET_CRYPTO_PaillierCiphertext);
776 session->transferred_element_count = session->used_elements_count;
779 session->transferred_element_count = (GNUNET_SERVER_MAX_MESSAGE_SIZE - 1 - msg_length) /
780 (sizeof (struct GNUNET_CRYPTO_PaillierCiphertext) * 2);
782 msg = GNUNET_malloc (msg_length);
783 msg->header.type = htons (GNUNET_MESSAGE_TYPE_SCALARPRODUCT_BOB_CRYPTODATA);
784 msg->header.size = htons (msg_length);
785 msg->total_element_count = htonl (session->total);
786 msg->used_element_count = htonl (session->used_elements_count);
787 msg->contained_element_count = htonl (session->transferred_element_count);
788 memcpy (&msg->key, &session->session_id, sizeof (struct GNUNET_HashCode));
790 payload = (struct GNUNET_CRYPTO_PaillierCiphertext *) &msg[1];
791 memcpy (&payload[0], session->s, sizeof (struct GNUNET_CRYPTO_PaillierCiphertext));
792 memcpy (&payload[1], session->s_prime, sizeof (struct GNUNET_CRYPTO_PaillierCiphertext));
793 GNUNET_free (session->s_prime);
794 session->s_prime = NULL;
795 GNUNET_free (session->s);
798 payload = &payload[2];
800 for (i = 0; i < session->transferred_element_count; i++) {
801 //k[i][p] and k[i][q]
802 memcpy (&payload[i * 2], &session->r[i], sizeof (struct GNUNET_CRYPTO_PaillierCiphertext));
803 memcpy (&payload[i * 2 + 1], &session->r_prime[i], sizeof (struct GNUNET_CRYPTO_PaillierCiphertext));
806 session->msg = (struct GNUNET_MessageHeader *) msg;
807 session->service_transmit_handle =
808 GNUNET_CADET_notify_transmit_ready (session->channel,
810 GNUNET_TIME_UNIT_FOREVER_REL,
814 //disconnect our client
815 if (NULL == session->service_transmit_handle) {
816 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, _ ("Could not send service-response message via cadet!)\n"));
818 session->response->client_notification_task =
819 GNUNET_SCHEDULER_add_now (&prepare_client_end_notification,
822 if (session->transferred_element_count != session->used_elements_count) {
827 GNUNET_free (session->r);
829 GNUNET_free (session->r_prime);
830 session->r_prime = NULL;
838 * (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)})$
839 * (2)[]: $E_A(a_{pi'(i)}) otimes E_A(- r_{pi'(i)}) &= E_A(a_{pi'(i)} - r_{pi'(i)})$
840 * S: $S := E_A(sum (r_i + b_i)^2)$
841 * S': $S' := E_A(sum r_i^2)$
843 * @param request the requesting session + bob's requesting peer
846 compute_service_response (struct ServiceSession * session)
852 gcry_mpi_t * rand = NULL;
855 struct GNUNET_CRYPTO_PaillierCiphertext * a;
856 struct GNUNET_CRYPTO_PaillierCiphertext * r;
857 struct GNUNET_CRYPTO_PaillierCiphertext * r_prime;
858 struct GNUNET_CRYPTO_PaillierCiphertext * s;
859 struct GNUNET_CRYPTO_PaillierCiphertext * s_prime;
861 count = session->used_elements_count;
863 b = session->sorted_elements;
864 q = GNUNET_CRYPTO_random_permute (GNUNET_CRYPTO_QUALITY_WEAK, count);
865 p = GNUNET_CRYPTO_random_permute (GNUNET_CRYPTO_QUALITY_WEAK, count);
867 for (i = 0; i < count; i++)
868 GNUNET_assert (NULL != (rand[i] = gcry_mpi_new (0)));
869 r = GNUNET_malloc (sizeof (struct GNUNET_CRYPTO_PaillierCiphertext) * count);
870 r_prime = GNUNET_malloc (sizeof (struct GNUNET_CRYPTO_PaillierCiphertext) * count);
871 s = GNUNET_malloc (sizeof (struct GNUNET_CRYPTO_PaillierCiphertext));
872 s_prime = GNUNET_malloc (sizeof (struct GNUNET_CRYPTO_PaillierCiphertext));
874 for (i = 0; i < count; i++) {
877 svalue = (int32_t) GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_WEAK, UINT32_MAX);
879 // long to gcry_mpi_t
881 gcry_mpi_sub_ui (rand[i],
885 rand[i] = gcry_mpi_set_ui (rand[i], svalue);
888 tmp = gcry_mpi_new (0);
889 // encrypt the element
890 // for the sake of readability I decided to have dedicated permutation
891 // vectors, which get rid of all the lookups in p/q.
892 // however, ap/aq are not absolutely necessary but are just abstraction
893 // Calculate Kp = E(S + a_pi) (+) E(S - r_pi - b_pi)
894 for (i = 0; i < count; i++) {
895 // E(S - r_pi - b_pi)
896 gcry_mpi_sub (tmp, my_offset, rand[p[i]]);
897 gcry_mpi_sub (tmp, tmp, b[p[i]]);
898 GNUNET_CRYPTO_paillier_encrypt (&session->remote_pubkey,
903 // E(S - r_pi - b_pi) * E(S + a_pi) == E(2*S + a - r - b)
904 GNUNET_CRYPTO_paillier_hom_add (&session->remote_pubkey,
910 // Calculate Kq = E(S + a_qi) (+) E(S - r_qi)
911 for (i = 0; i < count; i++) {
913 gcry_mpi_sub (tmp, my_offset, rand[q[i]]);
914 GNUNET_assert (2 == GNUNET_CRYPTO_paillier_encrypt (&session->remote_pubkey,
919 // E(S - r_qi) * E(S + a_qi) == E(2*S + a_qi - r_qi)
920 GNUNET_assert (1 == GNUNET_CRYPTO_paillier_hom_add (&session->remote_pubkey,
926 // Calculate S' = E(SUM( r_i^2 ))
927 tmp = compute_square_sum (rand, count);
928 GNUNET_CRYPTO_paillier_encrypt (&session->remote_pubkey,
933 // Calculate S = E(SUM( (r_i + b_i)^2 ))
934 for (i = 0; i < count; i++)
935 gcry_mpi_add (rand[i], rand[i], b[i]);
936 tmp = compute_square_sum (rand, count);
937 GNUNET_CRYPTO_paillier_encrypt (&session->remote_pubkey,
943 session->r_prime = r_prime;
945 session->s_prime = s_prime;
947 // release rand, b and a
948 for (i = 0; i < count; i++) {
949 gcry_mpi_release (rand[i]);
950 gcry_mpi_release (b[i]);
952 gcry_mpi_release (tmp);
953 GNUNET_free (session->e_a);
960 // copy the r[], r_prime[], S and Stick into a new message, prepare_service_response frees these
961 GNUNET_SCHEDULER_add_now (&prepare_bobs_cryptodata_message, session);
966 * Iterator over all hash map entries in session->intersected_elements.
969 * @param key current key code
970 * @param value value in the hash map
971 * @return #GNUNET_YES if we should continue to
976 cb_insert_element_sorted (void *cls,
977 const struct GNUNET_HashCode *key,
980 struct ServiceSession * session = (struct ServiceSession*) cls;
981 struct SortedValue * e = GNUNET_new (struct SortedValue);
982 struct SortedValue * o = session->a_head;
985 e->val = gcry_mpi_new (0);
986 if (0 > e->elem->value)
987 gcry_mpi_sub_ui (e->val, e->val, abs (e->elem->value));
989 gcry_mpi_add_ui (e->val, e->val, e->elem->value);
991 // insert as first element with the lowest key
992 if (NULL == session->a_head
993 || (0 <= GNUNET_CRYPTO_hash_cmp (&session->a_head->elem->key, &e->elem->key))) {
994 GNUNET_CONTAINER_DLL_insert (session->a_head, session->a_tail, e);
997 // insert as last element with the highest key
998 if (0 >= GNUNET_CRYPTO_hash_cmp (&session->a_tail->elem->key, &e->elem->key)) {
999 GNUNET_CONTAINER_DLL_insert_tail (session->a_head, session->a_tail, e);
1002 // insert before the first higher/equal element
1004 if (0 <= GNUNET_CRYPTO_hash_cmp (&o->elem->key, &e->elem->key)) {
1005 GNUNET_CONTAINER_DLL_insert_before (session->a_head, session->a_tail, o, e);
1018 * Callback for set operation results. Called for each element
1019 * in the result set.
1021 * @param cls closure
1022 * @param element a result element, only valid if status is #GNUNET_SET_STATUS_OK
1023 * @param status see `enum GNUNET_SET_Status`
1026 cb_intersection_element_removed (void *cls,
1027 const struct GNUNET_SET_Element *element,
1028 enum GNUNET_SET_Status status)
1030 struct ServiceSession * session = (struct ServiceSession*) cls;
1031 struct GNUNET_SCALARPRODUCT_Element * se;
1036 case GNUNET_SET_STATUS_OK:
1037 //this element has been removed from the set
1038 se = GNUNET_CONTAINER_multihashmap_get (session->intersected_elements,
1041 GNUNET_CONTAINER_multihashmap_remove (session->intersected_elements,
1044 session->used_elements_count--;
1047 case GNUNET_SET_STATUS_DONE:
1048 if (2 > session->used_elements_count) {
1049 // failed! do not leak information about our single remaining element!
1050 // continue after the loop
1054 GNUNET_CONTAINER_multihashmap_iterate (session->intersected_elements,
1055 &cb_insert_element_sorted,
1058 session->sorted_elements = GNUNET_malloc (session->used_elements_count * sizeof (gcry_mpi_t));
1059 for (i = 0; NULL != session->a_head; i++) {
1060 struct SortedValue* a = session->a_head;
1061 if (i > session->used_elements_count) {
1065 session->sorted_elements[i] = a->val;
1066 GNUNET_CONTAINER_DLL_remove (session->a_head, session->a_tail, a);
1067 GNUNET_free (a->elem);
1069 if (i != session->used_elements_count)
1072 if (ALICE == session->role) {
1073 prepare_alices_cyrptodata_message (session);
1077 if (session->used_elements_count == session->transferred_element_count)
1078 compute_service_response (session);
1086 //failed if we go here
1087 if (ALICE == session->role) {
1088 session->client_notification_task =
1089 GNUNET_SCHEDULER_add_now (&prepare_client_end_notification,
1093 //TODO: Fail service session, exit tunnel
1096 session->response->client_notification_task =
1097 GNUNET_SCHEDULER_add_now (&prepare_client_end_notification,
1105 * Called when another peer wants to do a set operation with the
1106 * local peer. If a listen error occurs, the @a request is NULL.
1108 * @param cls closure
1109 * @param other_peer the other peer
1110 * @param context_msg message with application specific information from
1112 * @param request request from the other peer (never NULL), use GNUNET_SET_accept()
1113 * to accept it, otherwise the request will be refused
1114 * Note that we can't just return value from the listen callback,
1115 * as it is also necessary to specify the set we want to do the
1116 * operation with, whith sometimes can be derived from the context
1117 * message. It's necessary to specify the timeout.
1120 cb_intersection_request_alice (void *cls,
1121 const struct GNUNET_PeerIdentity *other_peer,
1122 const struct GNUNET_MessageHeader *context_msg,
1123 struct GNUNET_SET_Request *request)
1125 struct ServiceSession * session = (struct ServiceSession *) cls;
1127 // check the peer-id, the app-id=session-id is compared by SET
1128 if (0 != memcmp (&session->peer, &other_peer, sizeof (struct GNUNET_PeerIdentity)))
1131 session->intersection_op = GNUNET_SET_accept (request,
1132 GNUNET_SET_RESULT_REMOVED,
1133 cb_intersection_element_removed,
1136 if (NULL == session->intersection_op) {
1137 session->response->client_notification_task =
1138 GNUNET_SCHEDULER_add_now (&prepare_client_end_notification,
1142 if (GNUNET_OK != GNUNET_SET_commit (session->intersection_op, session->intersection_set)) {
1143 session->response->client_notification_task =
1144 GNUNET_SCHEDULER_add_now (&prepare_client_end_notification,
1148 session->intersection_set = NULL;
1149 session->intersection_listen = NULL;
1154 * prepare the response we will send to alice or bobs' clients.
1155 * in Bobs case the product will be NULL.
1157 * @param cls the session associated with our client.
1158 * @param tc the task context handed to us by the scheduler, unused
1161 prepare_client_response (void *cls,
1162 const struct GNUNET_SCHEDULER_TaskContext *tc)
1164 struct ServiceSession * session = cls;
1165 struct GNUNET_SCALARPRODUCT_client_response * msg;
1166 unsigned char * product_exported = NULL;
1167 size_t product_length = 0;
1168 uint32_t msg_length = 0;
1173 session->client_notification_task = GNUNET_SCHEDULER_NO_TASK;
1175 if (session->product) {
1176 gcry_mpi_t value = gcry_mpi_new (0);
1178 sign = gcry_mpi_cmp_ui (session->product, 0);
1179 // libgcrypt can not handle a print of a negative number
1180 // if (a->sign) return gcry_error (GPG_ERR_INTERNAL); /* Can't handle it yet. */
1182 gcry_mpi_sub (value, value, session->product);
1184 else if (0 < sign) {
1186 gcry_mpi_add (value, value, session->product);
1191 gcry_mpi_release (session->product);
1192 session->product = NULL;
1194 // get representation as string
1196 && (0 != (rc = gcry_mpi_aprint (GCRYMPI_FMT_STD,
1200 LOG_GCRY (GNUNET_ERROR_TYPE_ERROR, "gcry_mpi_scan", rc);
1202 range = -1; // signal error with product-length = 0 and range = -1
1204 gcry_mpi_release (value);
1207 msg_length = sizeof (struct GNUNET_SCALARPRODUCT_client_response) +product_length;
1208 msg = GNUNET_malloc (msg_length);
1209 msg->key = session->session_id;
1210 msg->peer = session->peer;
1211 if (product_exported != NULL) {
1212 memcpy (&msg[1], product_exported, product_length);
1213 GNUNET_free (product_exported);
1215 msg->header.type = htons (GNUNET_MESSAGE_TYPE_SCALARPRODUCT_RESULT);
1216 msg->header.size = htons (msg_length);
1218 msg->product_length = htonl (product_length);
1220 session->msg = (struct GNUNET_MessageHeader *) msg;
1221 //transmit this message to our client
1222 session->client_transmit_handle =
1223 GNUNET_SERVER_notify_transmit_ready (session->client,
1225 GNUNET_TIME_UNIT_FOREVER_REL,
1228 if (NULL == session->client_transmit_handle) {
1229 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
1230 _ ("Could not send message to client (%p)!\n"),
1232 session->client = NULL;
1233 // callback was not called!
1235 session->msg = NULL;
1238 // gracefully sent message, just terminate session structure
1239 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
1240 _ ("Sent result to client (%p), this session (%s) has ended!\n"),
1242 GNUNET_h2s (&session->session_id));
1243 free_session_variables (session);
1248 * Executed by Alice, fills in a service-request message and sends it to the given peer
1250 * @param session the session associated with this request
1253 prepare_alices_computation_request (struct ServiceSession * session)
1255 struct GNUNET_SCALARPRODUCT_service_request * msg;
1257 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, _ ("Successfully created new channel to peer (%s)!\n"), GNUNET_i2s (&session->peer));
1259 msg = GNUNET_new (struct GNUNET_SCALARPRODUCT_service_request);
1260 msg->header.type = htons (GNUNET_MESSAGE_TYPE_SCALARPRODUCT_ALICE_CRYPTODATA);
1261 msg->total_element_count = htonl (session->used_elements_count);
1262 memcpy (&msg->session_id, &session->session_id, sizeof (struct GNUNET_HashCode));
1263 msg->header.size = htons (sizeof (struct GNUNET_SCALARPRODUCT_service_request));
1265 session->msg = (struct GNUNET_MessageHeader *) msg;
1266 GNUNET_log (GNUNET_ERROR_TYPE_INFO, _ ("Transmitting service request.\n"));
1268 //transmit via cadet messaging
1269 session->service_transmit_handle = GNUNET_CADET_notify_transmit_ready (session->channel, GNUNET_YES,
1270 GNUNET_TIME_UNIT_FOREVER_REL,
1271 sizeof (struct GNUNET_SCALARPRODUCT_service_request),
1274 if (!session->service_transmit_handle) {
1275 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, _ ("Could not send message to channel!\n"));
1277 session->msg = NULL;
1278 session->client_notification_task =
1279 GNUNET_SCHEDULER_add_now (&prepare_client_end_notification,
1287 * Send a multi part chunk of a service request from alice to bob.
1288 * This element only contains a part of the elements-vector (session->a[]),
1289 * mask and public key set have to be contained within the first message
1291 * This allows a ~32kbit key length while using 32000 elements or 62000 elements per request.
1293 * @param cls the associated service session
1296 prepare_alices_cyrptodata_message_multipart (void *cls)
1298 struct ServiceSession * session = cls;
1299 struct GNUNET_SCALARPRODUCT_multipart_message * msg;
1300 struct GNUNET_CRYPTO_PaillierCiphertext * payload;
1302 uint32_t msg_length;
1303 uint32_t todo_count;
1306 msg_length = sizeof (struct GNUNET_SCALARPRODUCT_multipart_message);
1307 todo_count = session->used_elements_count - session->transferred_element_count;
1309 if (todo_count > MULTIPART_ELEMENT_CAPACITY)
1310 // send the currently possible maximum chunk
1311 todo_count = MULTIPART_ELEMENT_CAPACITY;
1313 msg_length += todo_count * sizeof (struct GNUNET_CRYPTO_PaillierCiphertext);
1314 msg = GNUNET_malloc (msg_length);
1315 msg->header.type = htons (GNUNET_MESSAGE_TYPE_SCALARPRODUCT_ALICE_CRYPTODATA_MULTIPART);
1316 msg->header.size = htons (msg_length);
1317 msg->contained_element_count = htonl (todo_count);
1319 payload = (struct GNUNET_CRYPTO_PaillierCiphertext *) &msg[1];
1321 // now copy over the sorted element vector
1322 a = gcry_mpi_new (0);
1323 for (i = session->transferred_element_count; i < todo_count; i++) {
1324 gcry_mpi_add (a, session->sorted_elements[i], my_offset);
1325 GNUNET_CRYPTO_paillier_encrypt (&my_pubkey, a, 3, &payload[i - session->transferred_element_count]);
1327 gcry_mpi_release (a);
1328 session->transferred_element_count += todo_count;
1330 session->msg = (struct GNUNET_MessageHeader *) msg;
1331 GNUNET_log (GNUNET_ERROR_TYPE_INFO, _ ("Transmitting service request.\n"));
1333 //transmit via cadet messaging
1334 session->service_transmit_handle = GNUNET_CADET_notify_transmit_ready (session->channel, GNUNET_YES,
1335 GNUNET_TIME_UNIT_FOREVER_REL,
1339 if (!session->service_transmit_handle) {
1340 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, _ ("Could not send service-request multipart message to channel!\n"));
1342 session->msg = NULL;
1343 session->client_notification_task =
1344 GNUNET_SCHEDULER_add_now (&prepare_client_end_notification,
1352 * Our client has finished sending us its multipart message.
1354 * @param session the service session context
1357 client_request_complete_bob (struct ServiceSession * client_session)
1359 struct ServiceSession * session;
1361 //check if service queue contains a matching request
1362 session = find_matching_session (from_service_tail,
1363 &client_session->session_id,
1364 client_session->total, NULL);
1365 if (NULL != session) {
1366 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
1367 _ ("Got client-responder-session with key %s and a matching service-request-session set, processing.\n"),
1368 GNUNET_h2s (&client_session->session_id));
1370 session->response = client_session;
1371 session->intersected_elements = client_session->intersected_elements;
1372 client_session->intersected_elements = NULL;
1373 session->intersection_set = client_session->intersection_set;
1374 client_session->intersection_set = NULL;
1376 session->intersection_op = GNUNET_SET_prepare (&session->peer,
1377 &session->session_id,
1379 GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_WEAK, UINT16_MAX),
1380 GNUNET_SET_RESULT_REMOVED,
1381 cb_intersection_element_removed,
1384 GNUNET_SET_commit (session->intersection_op, session->intersection_set);
1387 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
1388 _ ("Got client-responder-session with key %s but NO matching service-request-session set, queuing element for later use.\n"),
1389 GNUNET_h2s (&client_session->session_id));
1390 // no matching session exists yet, store the response
1391 // for later processing by handle_service_request()
1397 * Our client has finished sending us its multipart message.
1399 * @param session the service session context
1402 client_request_complete_alice (struct ServiceSession * session)
1404 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
1405 _ ("Creating new channel for session with key %s.\n"),
1406 GNUNET_h2s (&session->session_id));
1407 session->channel = GNUNET_CADET_channel_create (my_cadet, session,
1409 GNUNET_APPLICATION_TYPE_SCALARPRODUCT,
1410 GNUNET_CADET_OPTION_RELIABLE);
1411 if (NULL == session->channel) {
1412 session->response->client_notification_task =
1413 GNUNET_SCHEDULER_add_now (&prepare_client_end_notification,
1417 session->intersection_listen = GNUNET_SET_listen (cfg,
1418 GNUNET_SET_OPERATION_INTERSECTION,
1419 &session->session_id,
1420 cb_intersection_request_alice,
1422 if (NULL == session->intersection_listen) {
1423 session->response->client_notification_task =
1424 GNUNET_SCHEDULER_add_now (&prepare_client_end_notification,
1428 prepare_alices_computation_request (session);
1433 handle_client_message_multipart (void *cls,
1434 struct GNUNET_SERVER_Client *client,
1435 const struct GNUNET_MessageHeader *message)
1437 const struct GNUNET_SCALARPRODUCT_computation_message_multipart * msg = (const struct GNUNET_SCALARPRODUCT_computation_message_multipart *) message;
1438 struct ServiceSession * session;
1439 uint32_t contained_count;
1440 struct GNUNET_SCALARPRODUCT_Element * elements;
1443 // only one concurrent session per client connection allowed, simplifies logics a lot...
1444 session = GNUNET_SERVER_client_get_user_context (client, struct ServiceSession);
1445 if (NULL == session) {
1446 GNUNET_SERVER_receive_done (client, GNUNET_OK);
1450 contained_count = ntohl (msg->element_count_contained);
1452 //sanity check: is the message as long as the message_count fields suggests?
1453 if ((ntohs (msg->header.size) != (sizeof (struct GNUNET_SCALARPRODUCT_computation_message_multipart) +contained_count * sizeof (struct GNUNET_SCALARPRODUCT_Element)))
1454 || (0 == contained_count) || (session->total < session->transferred_element_count + contained_count)) {
1455 GNUNET_break_op (0);
1456 GNUNET_SERVER_receive_done (client, GNUNET_OK);
1459 session->transferred_element_count += contained_count;
1461 elements = (struct GNUNET_SCALARPRODUCT_Element *) & msg[1];
1462 for (i = 0; i < contained_count; i++) {
1463 struct GNUNET_SET_Element set_elem;
1464 struct GNUNET_SCALARPRODUCT_Element * elem;
1466 if (0 == ntohl (elements[i].value))
1469 elem = GNUNET_new (struct GNUNET_SCALARPRODUCT_Element);
1470 memcpy (elem, &elements[i], sizeof (struct GNUNET_SCALARPRODUCT_Element));
1472 if (GNUNET_SYSERR == GNUNET_CONTAINER_multihashmap_put (session->intersected_elements,
1475 GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY)) {
1479 set_elem.data = &elements[i].key;
1480 set_elem.size = htons (sizeof (elements[i].key));
1481 set_elem.type = htons (0); /* do we REALLY need this? */
1482 GNUNET_SET_add_element (session->intersection_set, &set_elem, NULL, NULL);
1483 session->used_elements_count++;
1486 GNUNET_SERVER_receive_done (client, GNUNET_OK);
1488 if (session->total != session->transferred_element_count)
1492 if (ALICE == session->role)
1493 client_request_complete_alice (session);
1495 client_request_complete_bob (session);
1500 * Handler for a client request message.
1501 * Can either be type A or B
1502 * A: request-initiation to compute a scalar product with a peer
1503 * B: response role, keep the values + session and wait for a matching session or process a waiting request
1505 * @param cls closure
1506 * @param client identification of the client
1507 * @param message the actual message
1510 handle_client_message (void *cls,
1511 struct GNUNET_SERVER_Client *client,
1512 const struct GNUNET_MessageHeader *message)
1514 const struct GNUNET_SCALARPRODUCT_computation_message * msg = (const struct GNUNET_SCALARPRODUCT_computation_message *) message;
1515 struct ServiceSession * session;
1516 uint32_t contained_count;
1517 uint32_t total_count;
1519 struct GNUNET_SCALARPRODUCT_Element * elements;
1522 // only one concurrent session per client connection allowed, simplifies logics a lot...
1523 session = GNUNET_SERVER_client_get_user_context (client, struct ServiceSession);
1524 if (NULL != session) {
1525 GNUNET_SERVER_receive_done (client, GNUNET_OK);
1529 msg_type = ntohs (msg->header.type);
1530 total_count = ntohl (msg->element_count_total);
1531 contained_count = ntohl (msg->element_count_contained);
1533 if ((GNUNET_MESSAGE_TYPE_SCALARPRODUCT_CLIENT_TO_ALICE == msg_type)
1534 && (!memcmp (&msg->peer, &me, sizeof (struct GNUNET_PeerIdentity)))) {
1535 //session with ourself makes no sense!
1536 GNUNET_break_op (0);
1537 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
1541 //sanity check: is the message as long as the message_count fields suggests?
1542 if ((ntohs (msg->header.size) != (sizeof (struct GNUNET_SCALARPRODUCT_computation_message) +contained_count * sizeof (struct GNUNET_SCALARPRODUCT_Element)))
1543 || (0 == total_count)) {
1544 GNUNET_break_op (0);
1545 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
1549 // do we have a duplicate session here already?
1550 if (NULL != find_matching_session (from_client_tail,
1552 total_count, NULL)) {
1553 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
1554 _ ("Duplicate session information received, can not create new session with key `%s'\n"),
1555 GNUNET_h2s (&msg->session_key));
1556 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
1560 session = GNUNET_new (struct ServiceSession);
1561 session->client_notification_task = GNUNET_SCHEDULER_NO_TASK;
1562 session->client = client;
1563 session->total = total_count;
1564 session->transferred_element_count = contained_count;
1565 // get our transaction key
1566 memcpy (&session->session_id, &msg->session_key, sizeof (struct GNUNET_HashCode));
1568 elements = (struct GNUNET_SCALARPRODUCT_Element *) & msg[1];
1569 session->intersected_elements = GNUNET_CONTAINER_multihashmap_create (session->total, GNUNET_NO);
1570 session->intersection_set = GNUNET_SET_create (cfg, GNUNET_SET_OPERATION_INTERSECTION);
1571 for (i = 0; i < contained_count; i++) {
1572 struct GNUNET_SET_Element set_elem;
1573 struct GNUNET_SCALARPRODUCT_Element * elem;
1575 if (0 == ntohl (elements[i].value))
1578 elem = GNUNET_new (struct GNUNET_SCALARPRODUCT_Element);
1579 memcpy (elem, &elements[i], sizeof (struct GNUNET_SCALARPRODUCT_Element));
1581 if (GNUNET_SYSERR == GNUNET_CONTAINER_multihashmap_put (session->intersected_elements,
1584 GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY)) {
1588 set_elem.data = &elements[i].key;
1589 set_elem.size = htons (sizeof (elements[i].key));
1590 set_elem.type = htons (0); /* do we REALLY need this? */
1591 GNUNET_SET_add_element (session->intersection_set, &set_elem, NULL, NULL);
1592 session->used_elements_count++;
1595 if (GNUNET_MESSAGE_TYPE_SCALARPRODUCT_CLIENT_TO_ALICE == msg_type) {
1596 session->role = ALICE;
1597 memcpy (&session->peer, &msg->peer, sizeof (struct GNUNET_PeerIdentity));
1600 session->role = BOB;
1603 GNUNET_CONTAINER_DLL_insert (from_client_head, from_client_tail, session);
1604 GNUNET_SERVER_client_set_user_context (client, session);
1605 GNUNET_SERVER_receive_done (client, GNUNET_YES);
1607 if (session->total != session->transferred_element_count)
1611 if (ALICE == session->role)
1612 client_request_complete_alice (session);
1614 client_request_complete_bob (session);
1619 * Function called for inbound channels.
1621 * @param cls closure
1622 * @param channel new handle to the channel
1623 * @param initiator peer that started the channel
1624 * @param port unused
1625 * @param options unused
1627 * @return session associated with the channel
1630 cb_channel_incoming (void *cls,
1631 struct GNUNET_CADET_Channel *channel,
1632 const struct GNUNET_PeerIdentity *initiator,
1633 uint32_t port, enum GNUNET_CADET_ChannelOption options)
1635 struct ServiceSession * c = GNUNET_new (struct ServiceSession);
1637 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1638 _ ("New incoming channel from peer %s.\n"),
1639 GNUNET_i2s (initiator));
1641 c->peer = *initiator;
1642 c->channel = channel;
1649 * Function called whenever a channel is destroyed. Should clean up
1650 * any associated state.
1652 * It must NOT call GNUNET_CADET_channel_destroy on the channel.
1654 * @param cls closure (set from GNUNET_CADET_connect)
1655 * @param channel connection to the other end (henceforth invalid)
1656 * @param channel_ctx place where local state associated
1657 * with the channel is stored
1660 cb_channel_destruction (void *cls,
1661 const struct GNUNET_CADET_Channel *channel,
1664 struct ServiceSession * session = channel_ctx;
1665 struct ServiceSession * client_session;
1666 struct ServiceSession * curr;
1668 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1669 _ ("Peer disconnected, terminating session %s with peer (%s)\n"),
1670 GNUNET_h2s (&session->session_id),
1671 GNUNET_i2s (&session->peer));
1672 if (ALICE == session->role) {
1673 // as we have only one peer connected in each session, just remove the session
1675 if ((0/*//TODO: only for complete session*/) && (!do_shutdown)) {
1676 session->channel = NULL;
1677 // if this happened before we received the answer, we must terminate the session
1678 session->client_notification_task =
1679 GNUNET_SCHEDULER_add_now (&prepare_client_end_notification,
1683 else { //(BOB == session->role) service session
1684 // remove the session, unless it has already been dequeued, but somehow still active
1685 // this could bug without the IF in case the queue is empty and the service session was the only one know to the service
1686 // scenario: disconnect before alice can send her message to bob.
1687 for (curr = from_service_head; NULL != curr; curr = curr->next)
1688 if (curr == session) {
1689 GNUNET_CONTAINER_DLL_remove (from_service_head, from_service_tail, curr);
1692 // there is a client waiting for this service session, terminate it, too!
1693 // i assume the tupel of key and element count is unique. if it was not the rest of the code would not work either.
1694 client_session = find_matching_session (from_client_tail,
1695 &session->session_id,
1696 session->total, NULL);
1697 free_session_variables (session);
1698 GNUNET_free (session);
1700 // the client has to check if it was waiting for a result
1701 // or if it was a responder, no point in adding more statefulness
1702 if (client_session && (!do_shutdown)) {
1703 client_session->client_notification_task =
1704 GNUNET_SCHEDULER_add_now (&prepare_client_end_notification,
1712 * Compute our scalar product, done by Alice
1714 * @param session - the session associated with this computation
1715 * @return product as MPI, never NULL
1718 compute_scalar_product (struct ServiceSession * session)
1727 gcry_mpi_t r[session->used_elements_count];
1728 gcry_mpi_t r_prime[session->used_elements_count];
1733 count = session->used_elements_count;
1734 // due to the introduced static offset S, we now also have to remove this
1735 // from the E(a_pi)(+)E(-b_pi-r_pi) and E(a_qi)(+)E(-r_qi) twice each,
1736 // the result is E((S + a_pi) + (S -b_pi-r_pi)) and E(S + a_qi + S - r_qi)
1737 for (i = 0; i < count; i++) {
1738 GNUNET_CRYPTO_paillier_decrypt (&my_privkey, &my_pubkey,
1739 &session->r[i], r[i]);
1740 gcry_mpi_sub (r[i], r[i], my_offset);
1741 gcry_mpi_sub (r[i], r[i], my_offset);
1742 GNUNET_CRYPTO_paillier_decrypt (&my_privkey, &my_pubkey,
1743 &session->r_prime[i], r_prime[i]);
1744 gcry_mpi_sub (r_prime[i], r_prime[i], my_offset);
1745 gcry_mpi_sub (r_prime[i], r_prime[i], my_offset);
1748 // calculate t = sum(ai)
1749 t = compute_square_sum (session->sorted_elements, count);
1752 u = gcry_mpi_new (0);
1753 tmp = compute_square_sum (r, count);
1754 gcry_mpi_sub (u, u, tmp);
1755 gcry_mpi_release (tmp);
1758 u_prime = gcry_mpi_new (0);
1759 tmp = compute_square_sum (r_prime, count);
1760 gcry_mpi_sub (u_prime, u_prime, tmp);
1762 GNUNET_assert (p = gcry_mpi_new (0));
1763 GNUNET_assert (p_prime = gcry_mpi_new (0));
1764 GNUNET_assert (s = gcry_mpi_new (0));
1765 GNUNET_assert (s_prime = gcry_mpi_new (0));
1768 GNUNET_CRYPTO_paillier_decrypt (&my_privkey, &my_pubkey,
1770 GNUNET_CRYPTO_paillier_decrypt (&my_privkey, &my_pubkey,
1771 session->s_prime, s_prime);
1774 gcry_mpi_add (p, s, t);
1775 gcry_mpi_add (p, p, u);
1778 gcry_mpi_add (p_prime, s_prime, t);
1779 gcry_mpi_add (p_prime, p_prime, u_prime);
1781 gcry_mpi_release (t);
1782 gcry_mpi_release (u);
1783 gcry_mpi_release (u_prime);
1784 gcry_mpi_release (s);
1785 gcry_mpi_release (s_prime);
1788 gcry_mpi_sub (p, p, p_prime);
1789 gcry_mpi_release (p_prime);
1790 tmp = gcry_mpi_set_ui (tmp, 2);
1791 gcry_mpi_div (p, NULL, p, tmp, 0);
1793 gcry_mpi_release (tmp);
1794 for (i = 0; i < count; i++) {
1795 gcry_mpi_release (session->sorted_elements[i]);
1796 gcry_mpi_release (r[i]);
1797 gcry_mpi_release (r_prime[i]);
1799 GNUNET_free (session->a_head);
1800 session->a_head = NULL;
1801 GNUNET_free (session->s);
1803 GNUNET_free (session->s_prime);
1804 session->s_prime = NULL;
1805 GNUNET_free (session->r);
1807 GNUNET_free (session->r_prime);
1808 session->r_prime = NULL;
1815 * Handle a multipart-chunk of a request from another service to calculate a scalarproduct with us.
1817 * @param cls closure (set from #GNUNET_CADET_connect)
1818 * @param channel connection to the other end
1819 * @param channel_ctx place to store local state associated with the channel
1820 * @param message the actual message
1821 * @return #GNUNET_OK to keep the connection open,
1822 * #GNUNET_SYSERR to close it (signal serious error)
1825 handle_alices_cyrptodata_message_multipart (void *cls,
1826 struct GNUNET_CADET_Channel * channel,
1828 const struct GNUNET_MessageHeader * message)
1830 struct ServiceSession * session;
1831 const struct GNUNET_SCALARPRODUCT_multipart_message * msg = (const struct GNUNET_SCALARPRODUCT_multipart_message *) message;
1832 struct GNUNET_CRYPTO_PaillierCiphertext *payload;
1833 uint32_t contained_elements;
1834 uint32_t msg_length;
1836 // are we in the correct state?
1837 session = (struct ServiceSession *) * channel_ctx;
1839 if ((NULL == session->e_a) || //or we did not expect this message yet
1840 (session->used_elements_count == session->transferred_element_count)) { //we not expecting multipart messages
1843 // shorter than minimum?
1844 if (ntohs (msg->header.size) <= sizeof (struct GNUNET_SCALARPRODUCT_multipart_message)) {
1847 contained_elements = ntohl (msg->contained_element_count);
1848 msg_length = sizeof (struct GNUNET_SCALARPRODUCT_multipart_message)
1849 +contained_elements * sizeof (struct GNUNET_CRYPTO_PaillierCiphertext);
1851 if ((ntohs (msg->header.size) != msg_length)
1852 || (session->used_elements_count < contained_elements + session->transferred_element_count)
1853 || (0 == contained_elements)) {
1856 payload = (struct GNUNET_CRYPTO_PaillierCiphertext *) &msg[1];
1857 // Convert each vector element to MPI_value
1858 memcpy (&session->e_a[session->transferred_element_count], payload,
1859 sizeof (struct GNUNET_CRYPTO_PaillierCiphertext) * contained_elements);
1861 session->transferred_element_count += contained_elements;
1863 if (contained_elements == session->used_elements_count) {
1864 // single part finished
1865 if (NULL == session->intersection_op)
1866 // intersection has already finished, so we can proceed
1867 compute_service_response (session);
1872 // and notify our client-session that we could not complete the session
1873 GNUNET_CONTAINER_DLL_remove (from_service_head, from_service_tail, session);
1874 if (session->response)
1875 // we just found the responder session in this queue
1876 session->response->client_notification_task =
1877 GNUNET_SCHEDULER_add_now (&prepare_client_end_notification,
1879 free_session_variables (session);
1880 GNUNET_free (session);
1881 return GNUNET_SYSERR;
1886 * Handle a request from another service to calculate a scalarproduct with us.
1888 * @param cls closure (set from #GNUNET_CADET_connect)
1889 * @param channel connection to the other end
1890 * @param channel_ctx place to store local state associated with the channel
1891 * @param message the actual message
1892 * @return #GNUNET_OK to keep the connection open,
1893 * #GNUNET_SYSERR to close it (signal serious error)
1896 handle_alices_cyrptodata_message (void *cls,
1897 struct GNUNET_CADET_Channel * channel,
1899 const struct GNUNET_MessageHeader * message)
1901 struct ServiceSession * session;
1902 const struct GNUNET_SCALARPRODUCT_alices_cryptodata_message * msg = (const struct GNUNET_SCALARPRODUCT_alices_cryptodata_message *) message;
1903 struct GNUNET_CRYPTO_PaillierCiphertext *payload;
1904 uint32_t contained_elements = 0;
1905 uint32_t msg_length;
1907 session = (struct ServiceSession *) * channel_ctx;
1909 if ((BOB != session->role)
1910 //we are expecting multipart messages instead
1911 || (NULL != session->e_a)
1912 //or we did not expect this message yet
1913 || //intersection OP has not yet finished
1914 !((NULL != session->intersection_op)
1915 //intersection OP done
1916 || (session->response->sorted_elements)
1921 // shorter than minimum?
1922 if (ntohs (msg->header.size) <= sizeof (struct GNUNET_SCALARPRODUCT_multipart_message)) {
1926 contained_elements = ntohl (msg->contained_element_count);
1927 msg_length = sizeof (struct GNUNET_SCALARPRODUCT_alices_cryptodata_message)
1928 +contained_elements * sizeof (struct GNUNET_CRYPTO_PaillierCiphertext);
1930 //sanity check: is the message as long as the message_count fields suggests?
1931 if ((ntohs (msg->header.size) != msg_length) ||
1932 (session->used_elements_count < session->transferred_element_count + contained_elements) ||
1933 (0 == contained_elements)) {
1937 session->transferred_element_count = contained_elements;
1938 payload = (struct GNUNET_CRYPTO_PaillierCiphertext*) &msg[1];
1940 session->e_a = GNUNET_malloc (sizeof (struct GNUNET_CRYPTO_PaillierCiphertext) * session->used_elements_count);
1941 memcpy (&session->e_a[0], payload, contained_elements * sizeof (struct GNUNET_CRYPTO_PaillierCiphertext));
1942 if (contained_elements == session->used_elements_count) {
1943 // single part finished
1944 if (NULL == session->intersection_op)
1945 // intersection has already finished, so we can proceed
1946 compute_service_response (session);
1950 GNUNET_break_op (0);
1951 if ((NULL != session->next) || (NULL != session->prev) || (from_service_head == session))
1952 GNUNET_CONTAINER_DLL_remove (from_service_head, from_service_tail, session);
1953 // and notify our client-session that we could not complete the session
1954 if (session->response)
1955 // we just found the responder session in this queue
1956 session->response->client_notification_task =
1957 GNUNET_SCHEDULER_add_now (&prepare_client_end_notification,
1959 free_session_variables (session);
1960 return GNUNET_SYSERR;
1965 * Handle a request from another service to calculate a scalarproduct with us.
1967 * @param cls closure (set from #GNUNET_CADET_connect)
1968 * @param channel connection to the other end
1969 * @param channel_ctx place to store local state associated with the channel
1970 * @param message the actual message
1971 * @return #GNUNET_OK to keep the connection open,
1972 * #GNUNET_SYSERR to close it (signal serious error)
1975 handle_alices_computation_request (void *cls,
1976 struct GNUNET_CADET_Channel * channel,
1978 const struct GNUNET_MessageHeader * message)
1980 struct ServiceSession * session;
1981 struct ServiceSession * client_session;
1982 const struct GNUNET_SCALARPRODUCT_service_request * msg = (const struct GNUNET_SCALARPRODUCT_service_request *) message;
1983 uint32_t total_elements;
1985 session = (struct ServiceSession *) * channel_ctx;
1986 if (session->total != 0) {
1987 // must be a fresh session
1990 // Check if message was sent by me, which would be bad!
1991 if (!memcmp (&session->peer, &me, sizeof (struct GNUNET_PeerIdentity))) {
1992 GNUNET_free (session);
1994 return GNUNET_SYSERR;
1996 // shorter than expected?
1997 if (ntohs (msg->header.size) != sizeof (struct GNUNET_SCALARPRODUCT_service_request)) {
1998 GNUNET_free (session);
1999 GNUNET_break_op (0);
2000 return GNUNET_SYSERR;
2002 total_elements = ntohl (msg->total_element_count);
2004 //sanity check: is the message as long as the message_count fields suggests?
2005 if (1 > total_elements) {
2006 GNUNET_free (session);
2007 GNUNET_break_op (0);
2008 return GNUNET_SYSERR;
2010 if (find_matching_session (from_service_tail,
2014 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
2015 _ ("Got message with duplicate session key (`%s'), ignoring service request.\n"),
2016 (const char *) &(msg->session_id));
2017 GNUNET_free (session);
2018 return GNUNET_SYSERR;
2021 session->total = total_elements;
2022 session->channel = channel;
2025 memcpy (&session->session_id, &msg->session_id, sizeof (struct GNUNET_HashCode));
2028 memcpy (&session->remote_pubkey, &msg->public_key, sizeof (struct GNUNET_CRYPTO_PaillierPublicKey));
2030 //check if service queue contains a matching request
2031 client_session = find_matching_session (from_client_tail,
2032 &session->session_id,
2033 session->total, NULL);
2035 GNUNET_CONTAINER_DLL_insert (from_service_head, from_service_tail, session);
2037 if ((NULL != client_session)
2038 && (client_session->transferred_element_count == client_session->total)) {
2040 GNUNET_log (GNUNET_ERROR_TYPE_INFO, _ ("Got session with key %s and a matching element set, processing.\n"), GNUNET_h2s (&session->session_id));
2042 session->response = client_session;
2043 session->intersected_elements = client_session->intersected_elements;
2044 client_session->intersected_elements = NULL;
2045 session->intersection_set = client_session->intersection_set;
2046 client_session->intersection_set = NULL;
2048 session->intersection_op = GNUNET_SET_prepare (&session->peer,
2049 &session->session_id,
2051 GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_WEAK, UINT16_MAX),
2052 GNUNET_SET_RESULT_REMOVED,
2053 cb_intersection_element_removed,
2056 GNUNET_SET_commit (session->intersection_op, session->intersection_set);
2059 GNUNET_log (GNUNET_ERROR_TYPE_INFO, _ ("Got session with key %s without a matching element set, queueing.\n"), GNUNET_h2s (&session->session_id));
2064 GNUNET_break_op (0);
2065 if ((NULL != session->next) || (NULL != session->prev) || (from_service_head == session))
2066 GNUNET_CONTAINER_DLL_remove (from_service_head, from_service_tail, session);
2067 // and notify our client-session that we could not complete the session
2068 if (session->response)
2069 // we just found the responder session in this queue
2070 session->response->client_notification_task =
2071 GNUNET_SCHEDULER_add_now (&prepare_client_end_notification,
2073 free_session_variables (session);
2074 return GNUNET_SYSERR;
2079 * Handle a multipart chunk of a response we got from another service we wanted to calculate a scalarproduct with.
2081 * @param cls closure (set from #GNUNET_CADET_connect)
2082 * @param channel connection to the other end
2083 * @param channel_ctx place to store local state associated with the channel
2084 * @param message the actual message
2085 * @return #GNUNET_OK to keep the connection open,
2086 * #GNUNET_SYSERR to close it (signal serious error)
2089 handle_bobs_cryptodata_multipart (void *cls,
2090 struct GNUNET_CADET_Channel * channel,
2092 const struct GNUNET_MessageHeader * message)
2094 struct ServiceSession * session;
2095 const struct GNUNET_SCALARPRODUCT_multipart_message * msg = (const struct GNUNET_SCALARPRODUCT_multipart_message *) message;
2096 struct GNUNET_CRYPTO_PaillierCiphertext * payload;
2098 uint32_t contained = 0;
2100 size_t required_size;
2102 GNUNET_assert (NULL != message);
2103 // are we in the correct state?
2104 session = (struct ServiceSession *) * channel_ctx;
2105 if ((ALICE != session->role) || (NULL == session->sorted_elements)) {
2108 msg_size = ntohs (msg->header.size);
2109 required_size = sizeof (struct GNUNET_SCALARPRODUCT_multipart_message)
2110 + 2 * sizeof (struct GNUNET_CRYPTO_PaillierCiphertext);
2111 // shorter than minimum?
2112 if (required_size > msg_size) {
2115 contained = ntohl (msg->contained_element_count);
2116 required_size = sizeof (struct GNUNET_SCALARPRODUCT_multipart_message)
2117 + 2 * contained * sizeof (struct GNUNET_CRYPTO_PaillierCiphertext);
2118 //sanity check: is the message as long as the message_count fields suggests?
2119 if ((required_size != msg_size) || (session->used_elements_count < session->transferred_element_count + contained)) {
2122 payload = (struct GNUNET_CRYPTO_PaillierCiphertext *) &msg[1];
2123 // Convert each k[][perm] to its MPI_value
2124 for (i = 0; i < contained; i++) {
2125 memcpy (&session->r[session->transferred_element_count + i], &payload[2 * i], sizeof (struct GNUNET_CRYPTO_PaillierCiphertext));
2126 memcpy (&session->r_prime[session->transferred_element_count + i], &payload[2 * i], sizeof (struct GNUNET_CRYPTO_PaillierCiphertext));
2128 session->transferred_element_count += contained;
2129 if (session->transferred_element_count != session->used_elements_count)
2131 session->product = compute_scalar_product (session); //never NULL
2134 GNUNET_break_op (NULL != session->product); //NULL if we never tried to compute it...
2136 // send message with product to client
2137 if (ALICE == session->role) {
2138 session->channel = NULL;
2139 session->client_notification_task =
2140 GNUNET_SCHEDULER_add_now (&prepare_client_response,
2143 // the channel has done its job, terminate our connection and the channel
2144 // the peer will be notified that the channel was destroyed via channel_destruction_handler
2145 // just close the connection, as recommended by Christian
2146 return GNUNET_SYSERR;
2151 * Handle a response we got from another service we wanted to calculate a scalarproduct with.
2153 * @param cls closure (set from #GNUNET_CADET_connect)
2154 * @param channel connection to the other end
2155 * @param channel_ctx place to store local state associated with the channel
2156 * @param message the actual message
2157 * @return #GNUNET_OK to keep the connection open,
2158 * #GNUNET_SYSERR to close it (we are done)
2161 handle_bobs_cryptodata_message (void *cls,
2162 struct GNUNET_CADET_Channel * channel,
2164 const struct GNUNET_MessageHeader * message)
2166 struct ServiceSession * session;
2167 const struct GNUNET_SCALARPRODUCT_service_response * msg = (const struct GNUNET_SCALARPRODUCT_service_response *) message;
2168 struct GNUNET_CRYPTO_PaillierCiphertext * payload;
2170 uint32_t contained = 0;
2172 size_t required_size;
2174 GNUNET_assert (NULL != message);
2175 session = (struct ServiceSession *) * channel_ctx;
2176 // are we in the correct state?
2177 if (0 /*//TODO: correct state*/) {
2180 //we need at least a full message without elements attached
2181 msg_size = ntohs (msg->header.size);
2182 required_size = sizeof (struct GNUNET_SCALARPRODUCT_service_response) + 2 * sizeof (struct GNUNET_CRYPTO_PaillierCiphertext);
2184 if (required_size > msg_size) {
2187 contained = ntohl (msg->contained_element_count);
2188 required_size = sizeof (struct GNUNET_SCALARPRODUCT_service_response)
2189 + 2 * contained * sizeof (struct GNUNET_CRYPTO_PaillierCiphertext)
2190 + 2 * sizeof (struct GNUNET_CRYPTO_PaillierCiphertext);
2191 //sanity check: is the message as long as the message_count fields suggests?
2192 if ((msg_size != required_size) || (session->used_elements_count < contained)) {
2195 session->transferred_element_count = contained;
2197 payload = (struct GNUNET_CRYPTO_PaillierCiphertext *) &msg[1];
2199 session->s = GNUNET_malloc (sizeof (struct GNUNET_CRYPTO_PaillierCiphertext));
2200 session->s_prime = GNUNET_malloc (sizeof (struct GNUNET_CRYPTO_PaillierCiphertext));
2201 memcpy (session->s, &payload[0], sizeof (struct GNUNET_CRYPTO_PaillierCiphertext));
2202 memcpy (session->s_prime, &payload[1], sizeof (struct GNUNET_CRYPTO_PaillierCiphertext));
2204 session->r = GNUNET_malloc (sizeof (struct GNUNET_CRYPTO_PaillierCiphertext) * session->used_elements_count);
2205 session->r_prime = GNUNET_malloc (sizeof (struct GNUNET_CRYPTO_PaillierCiphertext) * session->used_elements_count);
2207 // Convert each k[][perm] to its MPI_value
2208 for (i = 0; i < contained; i++) {
2209 memcpy (&session->r[i], &payload[2 + 2 * i], sizeof (struct GNUNET_CRYPTO_PaillierCiphertext));
2210 memcpy (&session->r_prime[i], &payload[3 + 2 * i], sizeof (struct GNUNET_CRYPTO_PaillierCiphertext));
2212 if (session->transferred_element_count != session->used_elements_count)
2213 return GNUNET_OK; //wait for the other multipart chunks
2214 session->product = compute_scalar_product (session); //never NULL
2217 GNUNET_break_op (NULL != session->product);
2218 // send message with product to client
2219 if (ALICE == session->role) {
2220 session->channel = NULL;
2221 session->client_notification_task =
2222 GNUNET_SCHEDULER_add_now (&prepare_client_response,
2225 // the channel has done its job, terminate our connection and the channel
2226 // the peer will be notified that the channel was destroyed via channel_destruction_handler
2227 // just close the connection, as recommended by Christian
2228 return GNUNET_SYSERR;
2233 * Task run during shutdown.
2239 shutdown_task (void *cls,
2240 const struct GNUNET_SCHEDULER_TaskContext *tc)
2242 struct ServiceSession * session;
2243 GNUNET_log (GNUNET_ERROR_TYPE_INFO, _ ("Shutting down, initiating cleanup.\n"));
2245 do_shutdown = GNUNET_YES;
2247 // terminate all owned open channels.
2248 for (session = from_client_head; NULL != session; session = session->next) {
2249 if ((0/*//TODO: not finalized*/) && (NULL != session->channel)) {
2250 GNUNET_CADET_channel_destroy (session->channel);
2251 session->channel = NULL;
2253 if (GNUNET_SCHEDULER_NO_TASK != session->client_notification_task) {
2254 GNUNET_SCHEDULER_cancel (session->client_notification_task);
2255 session->client_notification_task = GNUNET_SCHEDULER_NO_TASK;
2257 if (NULL != session->client) {
2258 GNUNET_SERVER_client_disconnect (session->client);
2259 session->client = NULL;
2262 for (session = from_service_head; NULL != session; session = session->next)
2263 if (NULL != session->channel) {
2264 GNUNET_CADET_channel_destroy (session->channel);
2265 session->channel = NULL;
2269 GNUNET_CADET_disconnect (my_cadet);
2276 * Initialization of the program and message handlers
2278 * @param cls closure
2279 * @param server the initialized server
2280 * @param c configuration to use
2284 struct GNUNET_SERVER_Handle *server,
2285 const struct GNUNET_CONFIGURATION_Handle *c)
2287 static const struct GNUNET_SERVER_MessageHandler server_handlers[] = {
2288 {&handle_client_message, NULL, GNUNET_MESSAGE_TYPE_SCALARPRODUCT_CLIENT_TO_ALICE, 0},
2289 {&handle_client_message, NULL, GNUNET_MESSAGE_TYPE_SCALARPRODUCT_CLIENT_TO_BOB, 0},
2290 {&handle_client_message_multipart, NULL, GNUNET_MESSAGE_TYPE_SCALARPRODUCT_CLIENT_MUTLIPART, 0},
2293 static const struct GNUNET_CADET_MessageHandler cadet_handlers[] = {
2294 { &handle_alices_computation_request, GNUNET_MESSAGE_TYPE_SCALARPRODUCT_ALICE_CRYPTODATA, 0},
2295 { &handle_alices_cyrptodata_message, GNUNET_MESSAGE_TYPE_SCALARPRODUCT_ALICE_CRYPTODATA, 0},
2296 { &handle_alices_cyrptodata_message_multipart, GNUNET_MESSAGE_TYPE_SCALARPRODUCT_ALICE_CRYPTODATA_MULTIPART, 0},
2297 { &handle_bobs_cryptodata_message, GNUNET_MESSAGE_TYPE_SCALARPRODUCT_BOB_CRYPTODATA, 0},
2298 { &handle_bobs_cryptodata_multipart, GNUNET_MESSAGE_TYPE_SCALARPRODUCT_BOB_CRYPTODATA_MULTIPART, 0},
2301 static const uint32_t ports[] = {
2302 GNUNET_APPLICATION_TYPE_SCALARPRODUCT,
2305 //generate private/public key set
2306 GNUNET_CRYPTO_paillier_create (&my_pubkey, &my_privkey);
2308 // offset has to be sufficiently small to allow computation of:
2309 // m1+m2 mod n == (S + a) + (S + b) mod n,
2310 // if we have more complex operations, this factor needs to be lowered
2311 my_offset = gcry_mpi_new (GNUNET_CRYPTO_PAILLIER_BITS / 3);
2312 gcry_mpi_set_bit (my_offset, GNUNET_CRYPTO_PAILLIER_BITS / 3);
2314 // register server callbacks and disconnect handler
2315 GNUNET_SERVER_add_handlers (server, server_handlers);
2316 GNUNET_SERVER_disconnect_notify (server,
2317 &handle_client_disconnect,
2319 GNUNET_break (GNUNET_OK ==
2320 GNUNET_CRYPTO_get_peer_identity (c,
2322 my_cadet = GNUNET_CADET_connect (c, NULL,
2323 &cb_channel_incoming,
2324 &cb_channel_destruction,
2325 cadet_handlers, ports);
2327 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, _ ("Connect to CADET failed\n"));
2328 GNUNET_SCHEDULER_shutdown ();
2331 GNUNET_log (GNUNET_ERROR_TYPE_INFO, _ ("Mesh initialized\n"));
2332 GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_FOREVER_REL,
2339 * The main function for the scalarproduct service.
2341 * @param argc number of arguments from the command line
2342 * @param argv command line arguments
2343 * @return 0 ok, 1 on error
2346 main (int argc, char *const *argv)
2348 return (GNUNET_OK ==
2349 GNUNET_SERVICE_run (argc, argv,
2351 GNUNET_SERVICE_OPTION_NONE,
2352 &run, NULL)) ? 0 : 1;
2355 /* end of gnunet-service-scalarproduct.c */