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
55 * DLL for sorting elements
60 * Sorted Values are kept in a DLL
62 struct SortedValue * next;
65 * Sorted Values are kept in a DLL
67 struct SortedValue * prev;
70 * The element's id+integer-value
72 struct GNUNET_SCALARPRODUCT_Element * elem;
75 * the element's value converted to MPI
82 * A scalarproduct session which tracks:
84 * a request form the client to our final response.
86 * a request from a service to us(service).
91 * the role this peer has
96 * session information is kept in a DLL
98 struct ServiceSession *next;
101 * session information is kept in a DLL
103 struct ServiceSession *prev;
106 * (hopefully) unique transaction ID
108 struct GNUNET_HashCode session_id;
111 * Alice or Bob's peerID
113 struct GNUNET_PeerIdentity peer;
116 * the client this request is related to
118 struct GNUNET_SERVER_Client * client;
121 * The message to send
123 struct GNUNET_MessageHeader * msg;
126 * how many elements we were supplied with from the client
131 * how many elements we used for intersection
133 uint32_t intersected_elements_count;
136 * all non-0-value'd elements transmitted to us
138 struct GNUNET_CONTAINER_MultiHashMap * intersected_elements;
141 * how many elements actually are used for the scalar product
143 uint32_t used_elements_count;
146 * already transferred elements (sent/received) for multipart messages, less or equal than used_element_count for
148 uint32_t transferred_element_count;
151 * Set of elements for which will conduction an intersection.
152 * the resulting elements are then used for computing the scalar product.
154 struct GNUNET_SET_Handle * intersection_set;
157 * Set of elements for which will conduction an intersection.
158 * the resulting elements are then used for computing the scalar product.
160 struct GNUNET_SET_OperationHandle * intersection_op;
163 * Handle to Alice's Intersection operation listening for Bob
165 struct GNUNET_SET_ListenHandle * intersection_listen;
168 * Public key of the remote service, only used by bob
170 struct GNUNET_CRYPTO_PaillierPublicKey * remote_pubkey;
173 * DLL for sorting elements after intersection
175 struct SortedValue * a_head;
180 struct SortedValue * a_tail;
185 gcry_mpi_t * sorted_elements;
188 * E(ai)(Bob) after applying the mask
190 struct GNUNET_CRYPTO_PaillierCiphertext * e_a;
193 * Bob's permutation p of R
195 struct GNUNET_CRYPTO_PaillierCiphertext * r;
198 * Bob's permutation q of R
200 struct GNUNET_CRYPTO_PaillierCiphertext * r_prime;
205 struct GNUNET_CRYPTO_PaillierCiphertext * s;
210 struct GNUNET_CRYPTO_PaillierCiphertext * s_prime;
213 * Bobs matching response session from the client
215 struct ServiceSession * response;
218 * The computed scalar
223 * My transmit handle for the current message to a alice/bob
225 struct GNUNET_CADET_TransmitHandle * service_transmit_handle;
228 * My transmit handle for the current message to the client
230 struct GNUNET_SERVER_TransmitHandle * client_transmit_handle;
233 * channel-handle associated with our cadet handle
235 struct GNUNET_CADET_Channel * channel;
238 * Handle to a task that sends a msg to the our client
240 GNUNET_SCHEDULER_TaskIdentifier client_notification_task;
243 ///////////////////////////////////////////////////////////////////////////////
244 // Forward Delcarations
245 ///////////////////////////////////////////////////////////////////////////////
248 * Send a multi part chunk of a service request from alice to bob.
249 * This element only contains a part of the elements-vector (session->a[]),
250 * mask and public key set have to be contained within the first message
252 * This allows a ~32kbit key length while using 32000 elements or 62000 elements per request.
254 * @param cls the associated service session
257 prepare_alices_cyrptodata_message_multipart (void *cls);
260 * Send a multi part chunk of a service response from bob to alice.
261 * This element only contains the two permutations of R, R'.
263 * @param cls the associated service session
266 prepare_bobs_cryptodata_message_multipart (void *cls);
269 ///////////////////////////////////////////////////////////////////////////////
271 ///////////////////////////////////////////////////////////////////////////////
275 * Gnunet configuration handle
277 const struct GNUNET_CONFIGURATION_Handle * cfg;
280 * Handle to the core service (NULL until we've connected to it).
282 static struct GNUNET_CADET_Handle *my_cadet;
285 * The identity of this host.
287 static struct GNUNET_PeerIdentity me;
290 * Service's own public key
292 static struct GNUNET_CRYPTO_PaillierPublicKey my_pubkey;
295 * Service's own private key
297 static struct GNUNET_CRYPTO_PaillierPrivateKey my_privkey;
300 * Service's offset for values that could possibly be negative but are plaintext for encryption.
302 static gcry_mpi_t my_offset;
305 * Head of our double linked list for client-requests sent to us.
306 * for all of these elements we calculate a scalar product with a remote peer
307 * split between service->service and client->service for simplicity
309 static struct ServiceSession * from_client_head;
311 * Tail of our double linked list for client-requests sent to us.
312 * for all of these elements we calculate a scalar product with a remote peer
313 * split between service->service and client->service for simplicity
315 static struct ServiceSession * from_client_tail;
318 * Head of our double linked list for service-requests sent to us.
319 * for all of these elements we help the requesting service in calculating a scalar product
320 * split between service->service and client->service for simplicity
322 static struct ServiceSession * from_service_head;
325 * Tail of our double linked list for service-requests sent to us.
326 * for all of these elements we help the requesting service in calculating a scalar product
327 * split between service->service and client->service for simplicity
329 static struct ServiceSession * from_service_tail;
332 * Certain events (callbacks for server & cadet operations) must not be queued after shutdown.
334 static int do_shutdown;
336 ///////////////////////////////////////////////////////////////////////////////
338 ///////////////////////////////////////////////////////////////////////////////
342 * computes the square sum over a vector of a given length.
344 * @param vector the vector to encrypt
345 * @param length the length of the vector
346 * @return an MPI value containing the calculated sum, never NULL
349 compute_square_sum (gcry_mpi_t * vector, uint32_t length)
355 GNUNET_assert (sum = gcry_mpi_new (0));
356 GNUNET_assert (elem = gcry_mpi_new (0));
358 // calculare E(sum (ai ^ 2), publickey)
359 for (i = 0; i < length; i++) {
360 gcry_mpi_mul (elem, vector[i], vector[i]);
361 gcry_mpi_add (sum, sum, elem);
363 gcry_mpi_release (elem);
370 * Primitive callback for copying over a message, as they
371 * usually are too complex to be handled in the callback itself.
372 * clears a session-callback, if a session was handed over and the transmit handle was stored
374 * @param cls the session containing the message object
375 * @param size the size of the buffer we got
376 * @param buf the buffer to copy the message to
377 * @return 0 if we couldn't copy, else the size copied over
380 do_send_message (void *cls, size_t size, void *buf)
382 struct ServiceSession * s = cls;
387 if (ntohs (s->msg->size) != size) {
392 type = ntohs (s->msg->type);
393 memcpy (buf, s->msg, size);
394 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
395 "Sent a message of type %hu.\n",
397 GNUNET_free (s->msg);
402 case GNUNET_MESSAGE_TYPE_SCALARPRODUCT_RESULT:
403 s->client_transmit_handle = NULL;
406 case GNUNET_MESSAGE_TYPE_SCALARPRODUCT_ALICE_CRYPTODATA:
407 case GNUNET_MESSAGE_TYPE_SCALARPRODUCT_ALICE_CRYPTODATA_MULTIPART:
408 s->service_transmit_handle = NULL;
409 if (s->used_elements_count != s->transferred_element_count)
410 prepare_alices_cyrptodata_message_multipart (s);
413 case GNUNET_MESSAGE_TYPE_SCALARPRODUCT_BOB_CRYPTODATA:
414 case GNUNET_MESSAGE_TYPE_SCALARPRODUCT_BOB_CRYPTODATA_MULTIPART:
415 s->service_transmit_handle = NULL;
416 if (s->used_elements_count != s->transferred_element_count)
417 prepare_bobs_cryptodata_message_multipart (s);
429 * Finds a not terminated client/service session in the
430 * given DLL based on session key, element count and state.
432 * @param tail - the tail of the DLL
433 * @param key - the key we want to search for
434 * @param element_count - the total element count of the dataset (session->total)
435 * @param peerid - a pointer to the peer ID of the associated peer, NULL to ignore
436 * @return a pointer to a matching session, or NULL
438 static struct ServiceSession *
439 find_matching_session (struct ServiceSession * tail,
440 const struct GNUNET_HashCode * key,
441 uint32_t element_count,
442 const struct GNUNET_PeerIdentity * peerid)
444 struct ServiceSession * curr;
446 for (curr = tail; NULL != curr; curr = curr->prev) {
447 // if the key matches, and the element_count is same
448 if ((!memcmp (&curr->session_id, key, sizeof (struct GNUNET_HashCode)))
449 && (curr->total == element_count)) {
450 // if peerid is NULL OR same as the peer Id in the queued request
452 || (!memcmp (&curr->peer, peerid, sizeof (struct GNUNET_PeerIdentity))))
453 // matches and is not an already terminated session
463 * Safely frees ALL memory areas referenced by a session.
465 * @param session - the session to free elements from
468 free_session_variables (struct ServiceSession * session)
470 while (NULL != session->a_head) {
471 struct SortedValue * e = session->a_head;
472 GNUNET_free (e->elem);
473 gcry_mpi_release (e->val);
474 GNUNET_CONTAINER_DLL_remove (session->a_head, session->a_tail, e);
478 GNUNET_free (session->e_a);
481 if (session->remote_pubkey){
482 GNUNET_free(session->remote_pubkey);
483 session->remote_pubkey=NULL;
485 if (session->sorted_elements) {
486 GNUNET_free (session->sorted_elements);
487 session->sorted_elements = NULL;
489 if (session->intersected_elements) {
490 GNUNET_CONTAINER_multihashmap_destroy (session->intersected_elements);
491 //elements are freed independently in session->a_head/tail
492 session->intersected_elements = NULL;
494 if (session->intersection_listen) {
495 GNUNET_SET_listen_cancel (session->intersection_listen);
496 session->intersection_listen = NULL;
498 if (session->intersection_op) {
499 GNUNET_SET_operation_cancel (session->intersection_op);
500 session->intersection_op = NULL;
502 if (session->intersection_set) {
503 GNUNET_SET_destroy (session->intersection_set);
504 session->intersection_set = NULL;
506 if (session->channel){
507 GNUNET_CADET_channel_destroy(session->channel);
508 session->channel = NULL;
511 GNUNET_free (session->msg);
515 GNUNET_free (session->r);
518 if (session->r_prime) {
519 GNUNET_free (session->r_prime);
520 session->r_prime = NULL;
523 GNUNET_free (session->s);
526 if (session->s_prime) {
527 GNUNET_free (session->s_prime);
528 session->s_prime = NULL;
530 if (session->product) {
531 gcry_mpi_release (session->product);
532 session->product = NULL;
535 ///////////////////////////////////////////////////////////////////////////////
536 // Event and Message Handlers
537 ///////////////////////////////////////////////////////////////////////////////
541 * A client disconnected.
543 * Remove the associated session(s), release data structures
544 * and cancel pending outgoing transmissions to the client.
545 * if the session has not yet completed, we also cancel Alice's request to Bob.
547 * @param cls closure, NULL
548 * @param client identification of the client
551 handle_client_disconnect (void *cls,
552 struct GNUNET_SERVER_Client *client)
554 struct ServiceSession *session;
557 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
558 _ ("Client (%p) disconnected from us.\n"), client);
562 session = GNUNET_SERVER_client_get_user_context (client, struct ServiceSession);
565 GNUNET_CONTAINER_DLL_remove (from_client_head, from_client_tail, session);
567 if (!(session->role == BOB && 0/*//TODO: if session concluded*/)) {
568 //we MUST terminate any client message underway
569 if (session->service_transmit_handle && session->channel)
570 GNUNET_CADET_notify_transmit_ready_cancel (session->service_transmit_handle);
571 if (session->channel && 0/* //TODO: waiting for service response */)
572 GNUNET_CADET_channel_destroy (session->channel);
574 if (GNUNET_SCHEDULER_NO_TASK != session->client_notification_task) {
575 GNUNET_SCHEDULER_cancel (session->client_notification_task);
576 session->client_notification_task = GNUNET_SCHEDULER_NO_TASK;
578 if (NULL != session->client_transmit_handle) {
579 GNUNET_SERVER_notify_transmit_ready_cancel (session->client_transmit_handle);
580 session->client_transmit_handle = NULL;
582 free_session_variables (session);
583 GNUNET_free (session);
588 * Notify the client that the session has succeeded or failed completely.
589 * This message gets sent to
590 * * alice's client if bob disconnected or to
591 * * bob's client if the operation completed or alice disconnected
593 * @param cls the associated client session
594 * @param tc the task context handed to us by the scheduler, unused
597 prepare_client_end_notification (void * cls,
598 const struct GNUNET_SCHEDULER_TaskContext * tc)
600 struct ServiceSession * session = cls;
601 struct GNUNET_SCALARPRODUCT_client_response * msg;
603 session->client_notification_task = GNUNET_SCHEDULER_NO_TASK;
605 msg = GNUNET_new (struct GNUNET_SCALARPRODUCT_client_response);
606 msg->header.type = htons (GNUNET_MESSAGE_TYPE_SCALARPRODUCT_RESULT);
607 memcpy (&msg->key, &session->session_id, sizeof (struct GNUNET_HashCode));
608 memcpy (&msg->peer, &session->peer, sizeof ( struct GNUNET_PeerIdentity));
609 msg->header.size = htons (sizeof (struct GNUNET_SCALARPRODUCT_client_response));
610 // signal error if not signalized, positive result-range field but zero length.
611 msg->product_length = htonl (0);
612 msg->range = (session /* //TODO: if finalized */) ? 0 : -1;
614 session->msg = &msg->header;
616 //transmit this message to our client
617 session->client_transmit_handle =
618 GNUNET_SERVER_notify_transmit_ready (session->client,
619 sizeof (struct GNUNET_SCALARPRODUCT_client_response),
620 GNUNET_TIME_UNIT_FOREVER_REL,
624 // if we could not even queue our request, something is wrong
625 if (NULL == session->client_transmit_handle) {
626 GNUNET_log (GNUNET_ERROR_TYPE_WARNING, _ ("Could not send message to client (%p)!\n"), session->client);
627 // usually gets freed by do_send_message
632 GNUNET_log (GNUNET_ERROR_TYPE_INFO, _ ("Sending session-end notification to client (%p) for session %s\n"), &session->client, GNUNET_h2s (&session->session_id));
634 free_session_variables (session);
639 * Executed by Alice, fills in a service-request message and sends it to the given peer
641 * @param cls the session associated with this request
644 prepare_alices_cyrptodata_message (void *cls)
646 struct ServiceSession * session = cls;
647 struct GNUNET_SCALARPRODUCT_alices_cryptodata_message * msg;
648 struct GNUNET_CRYPTO_PaillierCiphertext * payload;
653 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, _ ("Successfully created new channel to peer (%s)!\n"), GNUNET_i2s (&session->peer));
655 msg_length = sizeof (struct GNUNET_SCALARPRODUCT_alices_cryptodata_message)
656 +session->used_elements_count * sizeof (struct GNUNET_CRYPTO_PaillierCiphertext);
658 if (GNUNET_SERVER_MAX_MESSAGE_SIZE > msg_length) {
659 session->transferred_element_count = session->used_elements_count;
662 //create a multipart msg, first we calculate a new msg size for the head msg
663 session->transferred_element_count = (GNUNET_SERVER_MAX_MESSAGE_SIZE - 1 - sizeof (struct GNUNET_SCALARPRODUCT_alices_cryptodata_message))
664 / sizeof (struct GNUNET_CRYPTO_PaillierCiphertext);
665 msg_length = sizeof (struct GNUNET_SCALARPRODUCT_alices_cryptodata_message)
666 +session->transferred_element_count * sizeof (struct GNUNET_CRYPTO_PaillierCiphertext);
669 msg = GNUNET_malloc (msg_length);
670 msg->header.size = htons (msg_length);
671 msg->header.type = htons (GNUNET_MESSAGE_TYPE_SCALARPRODUCT_ALICE_CRYPTODATA);
672 msg->contained_element_count = htonl (session->transferred_element_count);
674 // fill in the payload
675 payload = (struct GNUNET_CRYPTO_PaillierCiphertext *) &msg[1];
677 // now copy over the sorted element vector
678 a = gcry_mpi_new (0);
679 for (i = 0; i < session->transferred_element_count; i++) {
680 gcry_mpi_add (a, session->sorted_elements[i], my_offset);
681 GNUNET_CRYPTO_paillier_encrypt (&my_pubkey, a, 3, &payload[i]);
683 gcry_mpi_release (a);
685 session->msg = (struct GNUNET_MessageHeader *) msg;
686 GNUNET_log (GNUNET_ERROR_TYPE_INFO, _ ("Transmitting service request.\n"));
688 //transmit via cadet messaging
689 session->service_transmit_handle = GNUNET_CADET_notify_transmit_ready (session->channel, GNUNET_YES,
690 GNUNET_TIME_UNIT_FOREVER_REL,
694 if (NULL == session->service_transmit_handle) {
695 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, _ ("Could not send message to channel!\n"));
698 session->client_notification_task =
699 GNUNET_SCHEDULER_add_now (&prepare_client_end_notification,
707 * Send a multipart chunk of a service response from bob to alice.
708 * This element only contains the two permutations of R, R'.
710 * @param cls the associated service session
713 prepare_bobs_cryptodata_message_multipart (void *cls)
715 struct ServiceSession * session = cls;
716 struct GNUNET_CRYPTO_PaillierCiphertext * payload;
717 struct GNUNET_SCALARPRODUCT_multipart_message * msg;
723 msg_length = sizeof (struct GNUNET_SCALARPRODUCT_multipart_message);
724 todo_count = session->used_elements_count - session->transferred_element_count;
726 if (todo_count > MULTIPART_ELEMENT_CAPACITY / 2)
727 // send the currently possible maximum chunk, we always transfer both permutations
728 todo_count = MULTIPART_ELEMENT_CAPACITY / 2;
730 msg_length += todo_count * sizeof (struct GNUNET_CRYPTO_PaillierCiphertext) * 2;
731 msg = GNUNET_malloc (msg_length);
732 msg->header.type = htons (GNUNET_MESSAGE_TYPE_SCALARPRODUCT_ALICE_CRYPTODATA_MULTIPART);
733 msg->header.size = htons (msg_length);
734 msg->contained_element_count = htonl (todo_count);
736 payload = (struct GNUNET_CRYPTO_PaillierCiphertext *) &msg[1];
737 for (i = session->transferred_element_count, j = 0; i < session->transferred_element_count + todo_count; i++) {
738 //r[i][p] and r[i][q]
739 memcpy (&payload[j++], &session->r[i], sizeof (struct GNUNET_CRYPTO_PaillierCiphertext));
740 memcpy (&payload[j++], &session->r_prime[i], sizeof (struct GNUNET_CRYPTO_PaillierCiphertext));
742 session->transferred_element_count += todo_count;
743 session->msg = (struct GNUNET_MessageHeader *) msg;
744 session->service_transmit_handle =
745 GNUNET_CADET_notify_transmit_ready (session->channel,
747 GNUNET_TIME_UNIT_FOREVER_REL,
751 //disconnect our client
752 if (NULL == session->service_transmit_handle) {
753 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, _ ("Could not send service-response message via cadet!)\n"));
757 GNUNET_CONTAINER_DLL_remove (from_service_head, from_service_tail, session);
759 session->response->client_notification_task =
760 GNUNET_SCHEDULER_add_now (&prepare_client_end_notification,
762 free_session_variables(session);
763 GNUNET_free(session);
766 if (session->transferred_element_count != session->used_elements_count) {
771 GNUNET_free (session->r_prime);
772 GNUNET_free (session->r);
773 session->r_prime = NULL;
781 * generates the response message to be sent to alice after computing
782 * the values (1), (2), S and S'
783 * (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)})$
784 * (2)[]: $E_A(a_{pi'(i)}) times E_A(- r_{pi'(i)}) &= E_A(a_{pi'(i)} - r_{pi'(i)})$
785 * S: $S := E_A(sum (r_i + b_i)^2)$
786 * S': $S' := E_A(sum r_i^2)$
788 * @param session the associated requesting session with alice
791 prepare_bobs_cryptodata_message (void *cls,
792 const struct GNUNET_SCHEDULER_TaskContext
795 struct ServiceSession * session = (struct ServiceSession *) cls;
796 struct GNUNET_SCALARPRODUCT_service_response * msg;
797 uint32_t msg_length = 0;
798 struct GNUNET_CRYPTO_PaillierCiphertext * payload;
801 msg_length = sizeof (struct GNUNET_SCALARPRODUCT_service_response)
802 + 2 * sizeof (struct GNUNET_CRYPTO_PaillierCiphertext); // s, stick
804 if (GNUNET_SERVER_MAX_MESSAGE_SIZE >
805 msg_length + 2 * session->used_elements_count * sizeof (struct GNUNET_CRYPTO_PaillierCiphertext)) { //r, r'
806 msg_length += 2 * session->used_elements_count * sizeof (struct GNUNET_CRYPTO_PaillierCiphertext);
807 session->transferred_element_count = session->used_elements_count;
810 session->transferred_element_count = (GNUNET_SERVER_MAX_MESSAGE_SIZE - 1 - msg_length) /
811 (sizeof (struct GNUNET_CRYPTO_PaillierCiphertext) * 2);
813 msg = GNUNET_malloc (msg_length);
814 msg->header.type = htons (GNUNET_MESSAGE_TYPE_SCALARPRODUCT_BOB_CRYPTODATA);
815 msg->header.size = htons (msg_length);
816 msg->total_element_count = htonl (session->total);
817 msg->used_element_count = htonl (session->used_elements_count);
818 msg->contained_element_count = htonl (session->transferred_element_count);
819 memcpy (&msg->key, &session->session_id, sizeof (struct GNUNET_HashCode));
821 payload = (struct GNUNET_CRYPTO_PaillierCiphertext *) &msg[1];
822 memcpy (&payload[0], session->s, sizeof (struct GNUNET_CRYPTO_PaillierCiphertext));
823 memcpy (&payload[1], session->s_prime, sizeof (struct GNUNET_CRYPTO_PaillierCiphertext));
824 GNUNET_free (session->s_prime);
825 session->s_prime = NULL;
826 GNUNET_free (session->s);
829 payload = &payload[2];
831 for (i = 0; i < session->transferred_element_count; i++) {
832 //k[i][p] and k[i][q]
833 memcpy (&payload[i * 2], &session->r[i], sizeof (struct GNUNET_CRYPTO_PaillierCiphertext));
834 memcpy (&payload[i * 2 + 1], &session->r_prime[i], sizeof (struct GNUNET_CRYPTO_PaillierCiphertext));
837 session->msg = (struct GNUNET_MessageHeader *) msg;
838 session->service_transmit_handle =
839 GNUNET_CADET_notify_transmit_ready (session->channel,
841 GNUNET_TIME_UNIT_FOREVER_REL,
845 //disconnect our client
846 if (NULL == session->service_transmit_handle) {
847 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, _ ("Could not send service-response message via cadet!)\n"));
851 GNUNET_CONTAINER_DLL_remove (from_service_head, from_service_tail, session);
853 session->response->client_notification_task =
854 GNUNET_SCHEDULER_add_now (&prepare_client_end_notification,
856 free_session_variables(session);
857 GNUNET_free(session);
860 if (session->transferred_element_count != session->used_elements_count) {
865 GNUNET_free (session->r);
867 GNUNET_free (session->r_prime);
868 session->r_prime = NULL;
876 * (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)})$
877 * (2)[]: $E_A(a_{pi'(i)}) otimes E_A(- r_{pi'(i)}) &= E_A(a_{pi'(i)} - r_{pi'(i)})$
878 * S: $S := E_A(sum (r_i + b_i)^2)$
879 * S': $S' := E_A(sum r_i^2)$
881 * @param request the requesting session + bob's requesting peer
884 compute_service_response (struct ServiceSession * session)
890 gcry_mpi_t * rand = NULL;
893 struct GNUNET_CRYPTO_PaillierCiphertext * a;
894 struct GNUNET_CRYPTO_PaillierCiphertext * r;
895 struct GNUNET_CRYPTO_PaillierCiphertext * r_prime;
896 struct GNUNET_CRYPTO_PaillierCiphertext * s;
897 struct GNUNET_CRYPTO_PaillierCiphertext * s_prime;
899 count = session->used_elements_count;
901 b = session->sorted_elements;
902 q = GNUNET_CRYPTO_random_permute (GNUNET_CRYPTO_QUALITY_WEAK, count);
903 p = GNUNET_CRYPTO_random_permute (GNUNET_CRYPTO_QUALITY_WEAK, count);
905 for (i = 0; i < count; i++)
906 GNUNET_assert (NULL != (rand[i] = gcry_mpi_new (0)));
907 r = GNUNET_malloc (sizeof (struct GNUNET_CRYPTO_PaillierCiphertext) * count);
908 r_prime = GNUNET_malloc (sizeof (struct GNUNET_CRYPTO_PaillierCiphertext) * count);
909 s = GNUNET_malloc (sizeof (struct GNUNET_CRYPTO_PaillierCiphertext));
910 s_prime = GNUNET_malloc (sizeof (struct GNUNET_CRYPTO_PaillierCiphertext));
912 for (i = 0; i < count; i++) {
915 svalue = (int32_t) GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_WEAK, UINT32_MAX);
917 // long to gcry_mpi_t
919 gcry_mpi_sub_ui (rand[i],
923 rand[i] = gcry_mpi_set_ui (rand[i], svalue);
926 tmp = gcry_mpi_new (0);
927 // encrypt the element
928 // for the sake of readability I decided to have dedicated permutation
929 // vectors, which get rid of all the lookups in p/q.
930 // however, ap/aq are not absolutely necessary but are just abstraction
931 // Calculate Kp = E(S + a_pi) (+) E(S - r_pi - b_pi)
932 for (i = 0; i < count; i++) {
933 // E(S - r_pi - b_pi)
934 gcry_mpi_sub (tmp, my_offset, rand[p[i]]);
935 gcry_mpi_sub (tmp, tmp, b[p[i]]);
936 GNUNET_CRYPTO_paillier_encrypt (session->remote_pubkey,
941 // E(S - r_pi - b_pi) * E(S + a_pi) == E(2*S + a - r - b)
942 GNUNET_CRYPTO_paillier_hom_add (session->remote_pubkey,
948 // Calculate Kq = E(S + a_qi) (+) E(S - r_qi)
949 for (i = 0; i < count; i++) {
951 gcry_mpi_sub (tmp, my_offset, rand[q[i]]);
952 GNUNET_assert (2 == GNUNET_CRYPTO_paillier_encrypt (session->remote_pubkey,
957 // E(S - r_qi) * E(S + a_qi) == E(2*S + a_qi - r_qi)
958 GNUNET_assert (1 == GNUNET_CRYPTO_paillier_hom_add (session->remote_pubkey,
964 // Calculate S' = E(SUM( r_i^2 ))
965 tmp = compute_square_sum (rand, count);
966 GNUNET_CRYPTO_paillier_encrypt (session->remote_pubkey,
971 // Calculate S = E(SUM( (r_i + b_i)^2 ))
972 for (i = 0; i < count; i++)
973 gcry_mpi_add (rand[i], rand[i], b[i]);
974 tmp = compute_square_sum (rand, count);
975 GNUNET_CRYPTO_paillier_encrypt (session->remote_pubkey,
981 session->r_prime = r_prime;
983 session->s_prime = s_prime;
985 // release rand, b and a
986 for (i = 0; i < count; i++) {
987 gcry_mpi_release (rand[i]);
988 gcry_mpi_release (b[i]);
990 gcry_mpi_release (tmp);
991 GNUNET_free (session->e_a);
998 // copy the r[], r_prime[], S and Stick into a new message, prepare_service_response frees these
999 GNUNET_SCHEDULER_add_now (&prepare_bobs_cryptodata_message, session);
1004 * Iterator over all hash map entries in session->intersected_elements.
1006 * @param cls closure
1007 * @param key current key code
1008 * @param value value in the hash map
1009 * @return #GNUNET_YES if we should continue to
1011 * #GNUNET_NO if not.
1014 cb_insert_element_sorted (void *cls,
1015 const struct GNUNET_HashCode *key,
1018 struct ServiceSession * session = (struct ServiceSession*) cls;
1019 struct SortedValue * e = GNUNET_new (struct SortedValue);
1020 struct SortedValue * o = session->a_head;
1023 e->val = gcry_mpi_new (0);
1024 if (0 > e->elem->value)
1025 gcry_mpi_sub_ui (e->val, e->val, abs (e->elem->value));
1027 gcry_mpi_add_ui (e->val, e->val, e->elem->value);
1029 // insert as first element with the lowest key
1030 if (NULL == session->a_head
1031 || (0 <= GNUNET_CRYPTO_hash_cmp (&session->a_head->elem->key, &e->elem->key))) {
1032 GNUNET_CONTAINER_DLL_insert (session->a_head, session->a_tail, e);
1035 // insert as last element with the highest key
1036 if (0 >= GNUNET_CRYPTO_hash_cmp (&session->a_tail->elem->key, &e->elem->key)) {
1037 GNUNET_CONTAINER_DLL_insert_tail (session->a_head, session->a_tail, e);
1040 // insert before the first higher/equal element
1042 if (0 <= GNUNET_CRYPTO_hash_cmp (&o->elem->key, &e->elem->key)) {
1043 GNUNET_CONTAINER_DLL_insert_before (session->a_head, session->a_tail, o, e);
1055 * Callback for set operation results. Called for each element
1056 * in the result set.
1058 * @param cls closure
1059 * @param element a result element, only valid if status is #GNUNET_SET_STATUS_OK
1060 * @param status see `enum GNUNET_SET_Status`
1063 cb_intersection_element_removed (void *cls,
1064 const struct GNUNET_SET_Element *element,
1065 enum GNUNET_SET_Status status)
1067 struct ServiceSession * session = (struct ServiceSession*) cls;
1068 struct GNUNET_SCALARPRODUCT_Element * se;
1073 case GNUNET_SET_STATUS_OK:
1074 //this element has been removed from the set
1075 se = GNUNET_CONTAINER_multihashmap_get (session->intersected_elements,
1078 GNUNET_CONTAINER_multihashmap_remove (session->intersected_elements,
1081 session->used_elements_count--;
1084 case GNUNET_SET_STATUS_DONE:
1085 if (2 > session->used_elements_count) {
1086 // failed! do not leak information about our single remaining element!
1087 // continue after the loop
1091 GNUNET_CONTAINER_multihashmap_iterate (session->intersected_elements,
1092 &cb_insert_element_sorted,
1095 session->sorted_elements = GNUNET_malloc (session->used_elements_count * sizeof (gcry_mpi_t));
1096 for (i = 0; NULL != session->a_head; i++) {
1097 struct SortedValue* a = session->a_head;
1098 GNUNET_assert (i < session->used_elements_count);
1100 session->sorted_elements[i] = a->val;
1101 GNUNET_CONTAINER_DLL_remove (session->a_head, session->a_tail, a);
1102 GNUNET_free (a->elem);
1104 GNUNET_assert (i == session->used_elements_count);
1106 if (ALICE == session->role) {
1107 prepare_alices_cyrptodata_message (session);
1110 else if (session->used_elements_count == session->transferred_element_count) {
1111 compute_service_response (session);
1118 //failed if we go here
1121 // and notify our client-session that we could not complete the session
1122 if (ALICE == session->role) {
1123 session->client_notification_task =
1124 GNUNET_SCHEDULER_add_now (&prepare_client_end_notification,
1128 GNUNET_CONTAINER_DLL_remove (from_service_head, from_service_tail, session);
1129 free_session_variables (session);
1130 session->response->client_notification_task =
1131 GNUNET_SCHEDULER_add_now (&prepare_client_end_notification,
1133 GNUNET_free(session);
1139 * Called when another peer wants to do a set operation with the
1140 * local peer. If a listen error occurs, the @a request is NULL.
1142 * @param cls closure
1143 * @param other_peer the other peer
1144 * @param context_msg message with application specific information from
1146 * @param request request from the other peer (never NULL), use GNUNET_SET_accept()
1147 * to accept it, otherwise the request will be refused
1148 * Note that we can't just return value from the listen callback,
1149 * as it is also necessary to specify the set we want to do the
1150 * operation with, whith sometimes can be derived from the context
1151 * message. It's necessary to specify the timeout.
1154 cb_intersection_request_alice (void *cls,
1155 const struct GNUNET_PeerIdentity *other_peer,
1156 const struct GNUNET_MessageHeader *context_msg,
1157 struct GNUNET_SET_Request *request)
1159 struct ServiceSession * session = (struct ServiceSession *) cls;
1161 // check the peer-id, the app-id=session-id is compared by SET
1162 if (0 != memcmp (&session->peer, &other_peer, sizeof (struct GNUNET_PeerIdentity)))
1165 session->intersection_op = GNUNET_SET_accept (request,
1166 GNUNET_SET_RESULT_REMOVED,
1167 cb_intersection_element_removed,
1170 if (NULL == session->intersection_op) {
1171 session->response->client_notification_task =
1172 GNUNET_SCHEDULER_add_now (&prepare_client_end_notification,
1176 if (GNUNET_OK != GNUNET_SET_commit (session->intersection_op, session->intersection_set)) {
1177 session->response->client_notification_task =
1178 GNUNET_SCHEDULER_add_now (&prepare_client_end_notification,
1182 session->intersection_set = NULL;
1183 session->intersection_listen = NULL;
1188 * prepare the response we will send to alice or bobs' clients.
1189 * in Bobs case the product will be NULL.
1191 * @param cls the session associated with our client.
1192 * @param tc the task context handed to us by the scheduler, unused
1195 prepare_client_response (void *cls,
1196 const struct GNUNET_SCHEDULER_TaskContext *tc)
1198 struct ServiceSession * session = cls;
1199 struct GNUNET_SCALARPRODUCT_client_response * msg;
1200 unsigned char * product_exported = NULL;
1201 size_t product_length = 0;
1202 uint32_t msg_length = 0;
1207 session->client_notification_task = GNUNET_SCHEDULER_NO_TASK;
1209 if (session->product) {
1210 gcry_mpi_t value = gcry_mpi_new (0);
1212 sign = gcry_mpi_cmp_ui (session->product, 0);
1213 // libgcrypt can not handle a print of a negative number
1214 // if (a->sign) return gcry_error (GPG_ERR_INTERNAL); /* Can't handle it yet. */
1216 gcry_mpi_sub (value, value, session->product);
1218 else if (0 < sign) {
1220 gcry_mpi_add (value, value, session->product);
1225 gcry_mpi_release (session->product);
1226 session->product = NULL;
1228 // get representation as string
1230 && (0 != (rc = gcry_mpi_aprint (GCRYMPI_FMT_STD,
1234 LOG_GCRY (GNUNET_ERROR_TYPE_ERROR, "gcry_mpi_scan", rc);
1236 range = -1; // signal error with product-length = 0 and range = -1
1238 gcry_mpi_release (value);
1241 msg_length = sizeof (struct GNUNET_SCALARPRODUCT_client_response) +product_length;
1242 msg = GNUNET_malloc (msg_length);
1243 msg->key = session->session_id;
1244 msg->peer = session->peer;
1245 if (product_exported != NULL) {
1246 memcpy (&msg[1], product_exported, product_length);
1247 GNUNET_free (product_exported);
1249 msg->header.type = htons (GNUNET_MESSAGE_TYPE_SCALARPRODUCT_RESULT);
1250 msg->header.size = htons (msg_length);
1252 msg->product_length = htonl (product_length);
1254 session->msg = (struct GNUNET_MessageHeader *) msg;
1255 //transmit this message to our client
1256 session->client_transmit_handle =
1257 GNUNET_SERVER_notify_transmit_ready (session->client,
1259 GNUNET_TIME_UNIT_FOREVER_REL,
1262 if (NULL == session->client_transmit_handle) {
1263 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
1264 _ ("Could not send message to client (%p)!\n"),
1266 session->client = NULL;
1267 // callback was not called!
1269 session->msg = NULL;
1272 // gracefully sent message, just terminate session structure
1273 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
1274 _ ("Sent result to client (%p), this session (%s) has ended!\n"),
1276 GNUNET_h2s (&session->session_id));
1277 free_session_variables (session);
1282 * Executed by Alice, fills in a service-request message and sends it to the given peer
1284 * @param session the session associated with this request
1287 prepare_alices_computation_request (struct ServiceSession * session)
1289 struct GNUNET_SCALARPRODUCT_service_request * msg;
1291 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, _ ("Successfully created new channel to peer (%s)!\n"), GNUNET_i2s (&session->peer));
1293 msg = GNUNET_new (struct GNUNET_SCALARPRODUCT_service_request);
1294 msg->header.type = htons (GNUNET_MESSAGE_TYPE_SCALARPRODUCT_ALICE_CRYPTODATA);
1295 msg->total_element_count = htonl (session->used_elements_count);
1296 memcpy (&msg->session_id, &session->session_id, sizeof (struct GNUNET_HashCode));
1297 msg->header.size = htons (sizeof (struct GNUNET_SCALARPRODUCT_service_request));
1299 session->msg = (struct GNUNET_MessageHeader *) msg;
1300 GNUNET_log (GNUNET_ERROR_TYPE_INFO, _ ("Transmitting service request.\n"));
1302 //transmit via cadet messaging
1303 session->service_transmit_handle = GNUNET_CADET_notify_transmit_ready (session->channel, GNUNET_YES,
1304 GNUNET_TIME_UNIT_FOREVER_REL,
1305 sizeof (struct GNUNET_SCALARPRODUCT_service_request),
1308 if (!session->service_transmit_handle) {
1309 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, _ ("Could not send message to channel!\n"));
1311 session->msg = NULL;
1312 session->client_notification_task =
1313 GNUNET_SCHEDULER_add_now (&prepare_client_end_notification,
1321 * Send a multi part chunk of a service request from alice to bob.
1322 * This element only contains a part of the elements-vector (session->a[]),
1323 * mask and public key set have to be contained within the first message
1325 * This allows a ~32kbit key length while using 32000 elements or 62000 elements per request.
1327 * @param cls the associated service session
1330 prepare_alices_cyrptodata_message_multipart (void *cls)
1332 struct ServiceSession * session = cls;
1333 struct GNUNET_SCALARPRODUCT_multipart_message * msg;
1334 struct GNUNET_CRYPTO_PaillierCiphertext * payload;
1336 uint32_t msg_length;
1337 uint32_t todo_count;
1340 msg_length = sizeof (struct GNUNET_SCALARPRODUCT_multipart_message);
1341 todo_count = session->used_elements_count - session->transferred_element_count;
1343 if (todo_count > MULTIPART_ELEMENT_CAPACITY)
1344 // send the currently possible maximum chunk
1345 todo_count = MULTIPART_ELEMENT_CAPACITY;
1347 msg_length += todo_count * sizeof (struct GNUNET_CRYPTO_PaillierCiphertext);
1348 msg = GNUNET_malloc (msg_length);
1349 msg->header.type = htons (GNUNET_MESSAGE_TYPE_SCALARPRODUCT_ALICE_CRYPTODATA_MULTIPART);
1350 msg->header.size = htons (msg_length);
1351 msg->contained_element_count = htonl (todo_count);
1353 payload = (struct GNUNET_CRYPTO_PaillierCiphertext *) &msg[1];
1355 // now copy over the sorted element vector
1356 a = gcry_mpi_new (0);
1357 for (i = session->transferred_element_count; i < todo_count; i++) {
1358 gcry_mpi_add (a, session->sorted_elements[i], my_offset);
1359 GNUNET_CRYPTO_paillier_encrypt (&my_pubkey, a, 3, &payload[i - session->transferred_element_count]);
1361 gcry_mpi_release (a);
1362 session->transferred_element_count += todo_count;
1364 session->msg = (struct GNUNET_MessageHeader *) msg;
1365 GNUNET_log (GNUNET_ERROR_TYPE_INFO, _ ("Transmitting service request.\n"));
1367 //transmit via cadet messaging
1368 session->service_transmit_handle = GNUNET_CADET_notify_transmit_ready (session->channel, GNUNET_YES,
1369 GNUNET_TIME_UNIT_FOREVER_REL,
1373 if (!session->service_transmit_handle) {
1374 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, _ ("Could not send service-request multipart message to channel!\n"));
1376 session->msg = NULL;
1377 session->client_notification_task =
1378 GNUNET_SCHEDULER_add_now (&prepare_client_end_notification,
1386 * Our client has finished sending us its multipart message.
1388 * @param session the service session context
1391 client_request_complete_bob (struct ServiceSession * client_session)
1393 struct ServiceSession * session;
1395 //check if service queue contains a matching request
1396 session = find_matching_session (from_service_tail,
1397 &client_session->session_id,
1398 client_session->total, NULL);
1399 if (NULL != session) {
1400 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
1401 _ ("Got client-responder-session with key %s and a matching service-request-session set, processing.\n"),
1402 GNUNET_h2s (&client_session->session_id));
1404 session->response = client_session;
1405 session->intersected_elements = client_session->intersected_elements;
1406 client_session->intersected_elements = NULL;
1407 session->intersection_set = client_session->intersection_set;
1408 client_session->intersection_set = NULL;
1410 session->intersection_op = GNUNET_SET_prepare (&session->peer,
1411 &session->session_id,
1413 GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_WEAK, UINT16_MAX),
1414 GNUNET_SET_RESULT_REMOVED,
1415 cb_intersection_element_removed,
1418 GNUNET_SET_commit (session->intersection_op, session->intersection_set);
1421 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
1422 _ ("Got client-responder-session with key %s but NO matching service-request-session set, queuing element for later use.\n"),
1423 GNUNET_h2s (&client_session->session_id));
1424 // no matching session exists yet, store the response
1425 // for later processing by handle_service_request()
1431 * Our client has finished sending us its multipart message.
1433 * @param session the service session context
1436 client_request_complete_alice (struct ServiceSession * session)
1438 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
1439 _ ("Creating new channel for session with key %s.\n"),
1440 GNUNET_h2s (&session->session_id));
1441 session->channel = GNUNET_CADET_channel_create (my_cadet, session,
1443 GNUNET_APPLICATION_TYPE_SCALARPRODUCT,
1444 GNUNET_CADET_OPTION_RELIABLE);
1445 if (NULL == session->channel) {
1446 session->response->client_notification_task =
1447 GNUNET_SCHEDULER_add_now (&prepare_client_end_notification,
1451 session->intersection_listen = GNUNET_SET_listen (cfg,
1452 GNUNET_SET_OPERATION_INTERSECTION,
1453 &session->session_id,
1454 cb_intersection_request_alice,
1456 if (NULL == session->intersection_listen) {
1457 session->response->client_notification_task =
1458 GNUNET_SCHEDULER_add_now (&prepare_client_end_notification,
1462 prepare_alices_computation_request (session);
1467 handle_client_message_multipart (void *cls,
1468 struct GNUNET_SERVER_Client *client,
1469 const struct GNUNET_MessageHeader *message)
1471 const struct GNUNET_SCALARPRODUCT_computation_message_multipart * msg = (const struct GNUNET_SCALARPRODUCT_computation_message_multipart *) message;
1472 struct ServiceSession * session;
1473 uint32_t contained_count;
1474 struct GNUNET_SCALARPRODUCT_Element * elements;
1477 // only one concurrent session per client connection allowed, simplifies logics a lot...
1478 session = GNUNET_SERVER_client_get_user_context (client, struct ServiceSession);
1479 if (NULL == session) {
1480 GNUNET_SERVER_receive_done (client, GNUNET_OK);
1484 contained_count = ntohl (msg->element_count_contained);
1486 //sanity check: is the message as long as the message_count fields suggests?
1487 if ((ntohs (msg->header.size) != (sizeof (struct GNUNET_SCALARPRODUCT_computation_message_multipart) +contained_count * sizeof (struct GNUNET_SCALARPRODUCT_Element)))
1488 || (0 == contained_count) || (session->total < session->transferred_element_count + contained_count)) {
1489 GNUNET_break_op (0);
1490 GNUNET_SERVER_receive_done (client, GNUNET_OK);
1493 session->transferred_element_count += contained_count;
1495 elements = (struct GNUNET_SCALARPRODUCT_Element *) & msg[1];
1496 for (i = 0; i < contained_count; i++) {
1497 struct GNUNET_SET_Element set_elem;
1498 struct GNUNET_SCALARPRODUCT_Element * elem;
1500 if (0 == ntohl (elements[i].value))
1503 elem = GNUNET_new (struct GNUNET_SCALARPRODUCT_Element);
1504 memcpy (elem, &elements[i], sizeof (struct GNUNET_SCALARPRODUCT_Element));
1506 if (GNUNET_SYSERR == GNUNET_CONTAINER_multihashmap_put (session->intersected_elements,
1509 GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY)) {
1513 set_elem.data = &elements[i].key;
1514 set_elem.size = htons (sizeof (elements[i].key));
1515 set_elem.type = htons (0); /* do we REALLY need this? */
1516 GNUNET_SET_add_element (session->intersection_set, &set_elem, NULL, NULL);
1517 session->used_elements_count++;
1520 GNUNET_SERVER_receive_done (client, GNUNET_OK);
1522 if (session->total != session->transferred_element_count)
1526 if (ALICE == session->role)
1527 client_request_complete_alice (session);
1529 client_request_complete_bob (session);
1534 * Handler for a client request message.
1535 * Can either be type A or B
1536 * A: request-initiation to compute a scalar product with a peer
1537 * B: response role, keep the values + session and wait for a matching session or process a waiting request
1539 * @param cls closure
1540 * @param client identification of the client
1541 * @param message the actual message
1544 handle_client_message (void *cls,
1545 struct GNUNET_SERVER_Client *client,
1546 const struct GNUNET_MessageHeader *message)
1548 const struct GNUNET_SCALARPRODUCT_computation_message * msg = (const struct GNUNET_SCALARPRODUCT_computation_message *) message;
1549 struct ServiceSession * session;
1550 uint32_t contained_count;
1551 uint32_t total_count;
1553 struct GNUNET_SCALARPRODUCT_Element * elements;
1556 // only one concurrent session per client connection allowed, simplifies logics a lot...
1557 session = GNUNET_SERVER_client_get_user_context (client, struct ServiceSession);
1558 if (NULL != session) {
1559 GNUNET_SERVER_receive_done (client, GNUNET_OK);
1563 msg_type = ntohs (msg->header.type);
1564 total_count = ntohl (msg->element_count_total);
1565 contained_count = ntohl (msg->element_count_contained);
1567 if ((GNUNET_MESSAGE_TYPE_SCALARPRODUCT_CLIENT_TO_ALICE == msg_type)
1568 && (!memcmp (&msg->peer, &me, sizeof (struct GNUNET_PeerIdentity)))) {
1569 //session with ourself makes no sense!
1570 GNUNET_break_op (0);
1571 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
1575 //sanity check: is the message as long as the message_count fields suggests?
1576 if ((ntohs (msg->header.size) != (sizeof (struct GNUNET_SCALARPRODUCT_computation_message) +contained_count * sizeof (struct GNUNET_SCALARPRODUCT_Element)))
1577 || (0 == total_count)) {
1578 GNUNET_break_op (0);
1579 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
1583 // do we have a duplicate session here already?
1584 if (NULL != find_matching_session (from_client_tail,
1586 total_count, NULL)) {
1587 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
1588 _ ("Duplicate session information received, can not create new session with key `%s'\n"),
1589 GNUNET_h2s (&msg->session_key));
1590 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
1594 session = GNUNET_new (struct ServiceSession);
1595 session->client_notification_task = GNUNET_SCHEDULER_NO_TASK;
1596 session->client = client;
1597 session->total = total_count;
1598 session->transferred_element_count = contained_count;
1599 // get our transaction key
1600 memcpy (&session->session_id, &msg->session_key, sizeof (struct GNUNET_HashCode));
1602 elements = (struct GNUNET_SCALARPRODUCT_Element *) & msg[1];
1603 session->intersected_elements = GNUNET_CONTAINER_multihashmap_create (session->total, GNUNET_NO);
1604 session->intersection_set = GNUNET_SET_create (cfg, GNUNET_SET_OPERATION_INTERSECTION);
1605 for (i = 0; i < contained_count; i++) {
1606 struct GNUNET_SET_Element set_elem;
1607 struct GNUNET_SCALARPRODUCT_Element * elem;
1609 if (0 == ntohl (elements[i].value))
1612 elem = GNUNET_new (struct GNUNET_SCALARPRODUCT_Element);
1613 memcpy (elem, &elements[i], sizeof (struct GNUNET_SCALARPRODUCT_Element));
1615 if (GNUNET_SYSERR == GNUNET_CONTAINER_multihashmap_put (session->intersected_elements,
1618 GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY)) {
1622 set_elem.data = &elements[i].key;
1623 set_elem.size = htons (sizeof (elements[i].key));
1624 set_elem.type = htons (0); /* do we REALLY need this? */
1625 GNUNET_SET_add_element (session->intersection_set, &set_elem, NULL, NULL);
1626 session->used_elements_count++;
1629 if (GNUNET_MESSAGE_TYPE_SCALARPRODUCT_CLIENT_TO_ALICE == msg_type) {
1630 session->role = ALICE;
1631 memcpy (&session->peer, &msg->peer, sizeof (struct GNUNET_PeerIdentity));
1634 session->role = BOB;
1637 GNUNET_CONTAINER_DLL_insert (from_client_head, from_client_tail, session);
1638 GNUNET_SERVER_client_set_user_context (client, session);
1639 GNUNET_SERVER_receive_done (client, GNUNET_YES);
1641 if (session->total != session->transferred_element_count)
1645 if (ALICE == session->role)
1646 client_request_complete_alice (session);
1648 client_request_complete_bob (session);
1653 * Function called for inbound channels.
1655 * @param cls closure
1656 * @param channel new handle to the channel
1657 * @param initiator peer that started the channel
1658 * @param port unused
1659 * @param options unused
1661 * @return session associated with the channel
1664 cb_channel_incoming (void *cls,
1665 struct GNUNET_CADET_Channel *channel,
1666 const struct GNUNET_PeerIdentity *initiator,
1667 uint32_t port, enum GNUNET_CADET_ChannelOption options)
1669 struct ServiceSession * c = GNUNET_new (struct ServiceSession);
1671 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1672 _ ("New incoming channel from peer %s.\n"),
1673 GNUNET_i2s (initiator));
1675 c->peer = *initiator;
1676 c->channel = channel;
1683 * Function called whenever a channel is destroyed. Should clean up
1684 * any associated state.
1686 * It must NOT call GNUNET_CADET_channel_destroy on the channel.
1688 * @param cls closure (set from GNUNET_CADET_connect)
1689 * @param channel connection to the other end (henceforth invalid)
1690 * @param channel_ctx place where local state associated
1691 * with the channel is stored
1694 cb_channel_destruction (void *cls,
1695 const struct GNUNET_CADET_Channel *channel,
1698 struct ServiceSession * session = channel_ctx;
1699 struct ServiceSession * client_session;
1700 struct ServiceSession * curr;
1702 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1703 _ ("Peer disconnected, terminating session %s with peer (%s)\n"),
1704 GNUNET_h2s (&session->session_id),
1705 GNUNET_i2s (&session->peer));
1706 if (ALICE == session->role) {
1707 // as we have only one peer connected in each session, just remove the session
1709 if ((0/*//TODO: only for complete session*/) && (!do_shutdown)) {
1710 session->channel = NULL;
1711 // if this happened before we received the answer, we must terminate the session
1712 session->client_notification_task =
1713 GNUNET_SCHEDULER_add_now (&prepare_client_end_notification,
1717 else { //(BOB == session->role) service session
1718 // remove the session, unless it has already been dequeued, but somehow still active
1719 // this could bug without the IF in case the queue is empty and the service session was the only one know to the service
1720 // scenario: disconnect before alice can send her message to bob.
1721 for (curr = from_service_head; NULL != curr; curr = curr->next)
1722 if (curr == session) {
1723 GNUNET_CONTAINER_DLL_remove (from_service_head, from_service_tail, curr);
1726 // there is a client waiting for this service session, terminate it, too!
1727 // i assume the tupel of key and element count is unique. if it was not the rest of the code would not work either.
1728 client_session = find_matching_session (from_client_tail,
1729 &session->session_id,
1730 session->total, NULL);
1731 free_session_variables (session);
1732 GNUNET_free (session);
1734 // the client has to check if it was waiting for a result
1735 // or if it was a responder, no point in adding more statefulness
1736 if (client_session && (!do_shutdown)) {
1737 client_session->client_notification_task =
1738 GNUNET_SCHEDULER_add_now (&prepare_client_end_notification,
1746 * Compute our scalar product, done by Alice
1748 * @param session - the session associated with this computation
1749 * @return product as MPI, never NULL
1752 compute_scalar_product (struct ServiceSession * session)
1761 gcry_mpi_t r[session->used_elements_count];
1762 gcry_mpi_t r_prime[session->used_elements_count];
1767 count = session->used_elements_count;
1768 // due to the introduced static offset S, we now also have to remove this
1769 // from the E(a_pi)(+)E(-b_pi-r_pi) and E(a_qi)(+)E(-r_qi) twice each,
1770 // the result is E((S + a_pi) + (S -b_pi-r_pi)) and E(S + a_qi + S - r_qi)
1771 for (i = 0; i < count; i++) {
1772 GNUNET_CRYPTO_paillier_decrypt (&my_privkey, &my_pubkey,
1773 &session->r[i], r[i]);
1774 gcry_mpi_sub (r[i], r[i], my_offset);
1775 gcry_mpi_sub (r[i], r[i], my_offset);
1776 GNUNET_CRYPTO_paillier_decrypt (&my_privkey, &my_pubkey,
1777 &session->r_prime[i], r_prime[i]);
1778 gcry_mpi_sub (r_prime[i], r_prime[i], my_offset);
1779 gcry_mpi_sub (r_prime[i], r_prime[i], my_offset);
1782 // calculate t = sum(ai)
1783 t = compute_square_sum (session->sorted_elements, count);
1786 u = gcry_mpi_new (0);
1787 tmp = compute_square_sum (r, count);
1788 gcry_mpi_sub (u, u, tmp);
1789 gcry_mpi_release (tmp);
1792 u_prime = gcry_mpi_new (0);
1793 tmp = compute_square_sum (r_prime, count);
1794 gcry_mpi_sub (u_prime, u_prime, tmp);
1796 GNUNET_assert (p = gcry_mpi_new (0));
1797 GNUNET_assert (p_prime = gcry_mpi_new (0));
1798 GNUNET_assert (s = gcry_mpi_new (0));
1799 GNUNET_assert (s_prime = gcry_mpi_new (0));
1802 GNUNET_CRYPTO_paillier_decrypt (&my_privkey, &my_pubkey,
1804 GNUNET_CRYPTO_paillier_decrypt (&my_privkey, &my_pubkey,
1805 session->s_prime, s_prime);
1808 gcry_mpi_add (p, s, t);
1809 gcry_mpi_add (p, p, u);
1812 gcry_mpi_add (p_prime, s_prime, t);
1813 gcry_mpi_add (p_prime, p_prime, u_prime);
1815 gcry_mpi_release (t);
1816 gcry_mpi_release (u);
1817 gcry_mpi_release (u_prime);
1818 gcry_mpi_release (s);
1819 gcry_mpi_release (s_prime);
1822 gcry_mpi_sub (p, p, p_prime);
1823 gcry_mpi_release (p_prime);
1824 tmp = gcry_mpi_set_ui (tmp, 2);
1825 gcry_mpi_div (p, NULL, p, tmp, 0);
1827 gcry_mpi_release (tmp);
1828 for (i = 0; i < count; i++) {
1829 gcry_mpi_release (session->sorted_elements[i]);
1830 gcry_mpi_release (r[i]);
1831 gcry_mpi_release (r_prime[i]);
1833 GNUNET_free (session->a_head);
1834 session->a_head = NULL;
1835 GNUNET_free (session->s);
1837 GNUNET_free (session->s_prime);
1838 session->s_prime = NULL;
1839 GNUNET_free (session->r);
1841 GNUNET_free (session->r_prime);
1842 session->r_prime = NULL;
1849 * Handle a multipart-chunk of a request from another service to calculate a scalarproduct with us.
1851 * @param cls closure (set from #GNUNET_CADET_connect)
1852 * @param channel connection to the other end
1853 * @param channel_ctx place to store local state associated with the channel
1854 * @param message the actual message
1855 * @return #GNUNET_OK to keep the connection open,
1856 * #GNUNET_SYSERR to close it (signal serious error)
1859 handle_alices_cyrptodata_message_multipart (void *cls,
1860 struct GNUNET_CADET_Channel * channel,
1862 const struct GNUNET_MessageHeader * message)
1864 struct ServiceSession * session;
1865 const struct GNUNET_SCALARPRODUCT_multipart_message * msg = (const struct GNUNET_SCALARPRODUCT_multipart_message *) message;
1866 struct GNUNET_CRYPTO_PaillierCiphertext *payload;
1867 uint32_t contained_elements;
1868 uint32_t msg_length;
1870 // are we in the correct state?
1871 session = (struct ServiceSession *) * channel_ctx;
1873 if ((NULL == session->e_a) || //or we did not expect this message yet
1874 (session->used_elements_count == session->transferred_element_count)) { //we are not expecting multipart messages
1877 // shorter than minimum?
1878 if (ntohs (msg->header.size) <= sizeof (struct GNUNET_SCALARPRODUCT_multipart_message)) {
1881 contained_elements = ntohl (msg->contained_element_count);
1882 msg_length = sizeof (struct GNUNET_SCALARPRODUCT_multipart_message)
1883 +contained_elements * sizeof (struct GNUNET_CRYPTO_PaillierCiphertext);
1885 if ((ntohs (msg->header.size) != msg_length)
1886 || (session->used_elements_count < contained_elements + session->transferred_element_count)
1887 || (0 == contained_elements)) {
1890 payload = (struct GNUNET_CRYPTO_PaillierCiphertext *) &msg[1];
1891 // Convert each vector element to MPI_value
1892 memcpy (&session->e_a[session->transferred_element_count], payload,
1893 sizeof (struct GNUNET_CRYPTO_PaillierCiphertext) * contained_elements);
1895 session->transferred_element_count += contained_elements;
1897 if (contained_elements == session->used_elements_count) {
1898 // single part finished
1899 if (NULL == session->intersection_op)
1900 // intersection has already finished, so we can proceed
1901 compute_service_response (session);
1906 session->channel = NULL;
1907 // and notify our client-session that we could not complete the session
1908 free_session_variables (session);
1909 if (NULL != session->client){
1911 session->client_notification_task =
1912 GNUNET_SCHEDULER_add_now (&prepare_client_end_notification,
1917 if (NULL != session->response)
1918 session->response->client_notification_task =
1919 GNUNET_SCHEDULER_add_now (&prepare_client_end_notification,
1921 GNUNET_CONTAINER_DLL_remove (from_service_head, from_service_tail, session);
1922 GNUNET_free(session);
1924 return GNUNET_SYSERR;
1929 * Handle a request from another service to calculate a scalarproduct with us.
1931 * @param cls closure (set from #GNUNET_CADET_connect)
1932 * @param channel connection to the other end
1933 * @param channel_ctx place to store local state associated with the channel
1934 * @param message the actual message
1935 * @return #GNUNET_OK to keep the connection open,
1936 * #GNUNET_SYSERR to close it (signal serious error)
1939 handle_alices_cyrptodata_message (void *cls,
1940 struct GNUNET_CADET_Channel * channel,
1942 const struct GNUNET_MessageHeader * message)
1944 struct ServiceSession * session;
1945 const struct GNUNET_SCALARPRODUCT_alices_cryptodata_message * msg = (const struct GNUNET_SCALARPRODUCT_alices_cryptodata_message *) message;
1946 struct GNUNET_CRYPTO_PaillierCiphertext *payload;
1947 uint32_t contained_elements = 0;
1948 uint32_t msg_length;
1950 session = (struct ServiceSession *) * channel_ctx;
1952 if ((BOB != session->role)
1953 //we are expecting multipart messages instead
1954 || (NULL != session->e_a)
1955 //or we did not expect this message yet
1956 || //intersection OP has not yet finished
1957 !((NULL != session->intersection_op)
1958 //intersection OP done
1959 || (session->response->sorted_elements)
1964 // shorter than minimum?
1965 if (ntohs (msg->header.size) <= sizeof (struct GNUNET_SCALARPRODUCT_multipart_message)) {
1969 contained_elements = ntohl (msg->contained_element_count);
1970 msg_length = sizeof (struct GNUNET_SCALARPRODUCT_alices_cryptodata_message)
1971 +contained_elements * sizeof (struct GNUNET_CRYPTO_PaillierCiphertext);
1973 //sanity check: is the message as long as the message_count fields suggests?
1974 if ((ntohs (msg->header.size) != msg_length) ||
1975 (session->used_elements_count < session->transferred_element_count + contained_elements) ||
1976 (0 == contained_elements)) {
1980 session->transferred_element_count = contained_elements;
1981 payload = (struct GNUNET_CRYPTO_PaillierCiphertext*) &msg[1];
1983 session->e_a = GNUNET_malloc (sizeof (struct GNUNET_CRYPTO_PaillierCiphertext) * session->used_elements_count);
1984 memcpy (&session->e_a[0], payload, contained_elements * sizeof (struct GNUNET_CRYPTO_PaillierCiphertext));
1985 if (contained_elements == session->used_elements_count) {
1986 // single part finished
1987 if (NULL == session->intersection_op)
1988 // intersection has already finished, so we can proceed
1989 compute_service_response (session);
1993 GNUNET_break_op (0);
1994 session->channel = NULL;
1995 // and notify our client-session that we could not complete the session
1996 free_session_variables (session);
1997 if (NULL != session->client){
1999 session->client_notification_task =
2000 GNUNET_SCHEDULER_add_now (&prepare_client_end_notification,
2005 if (NULL != session->response)
2006 session->response->client_notification_task =
2007 GNUNET_SCHEDULER_add_now (&prepare_client_end_notification,
2009 GNUNET_CONTAINER_DLL_remove (from_service_head, from_service_tail, session);
2010 GNUNET_free(session);
2012 return GNUNET_SYSERR;
2017 * Handle a request from another service to calculate a scalarproduct with us.
2019 * @param cls closure (set from #GNUNET_CADET_connect)
2020 * @param channel connection to the other end
2021 * @param channel_ctx place to store local state associated with the channel
2022 * @param message the actual message
2023 * @return #GNUNET_OK to keep the connection open,
2024 * #GNUNET_SYSERR to close it (signal serious error)
2027 handle_alices_computation_request (void *cls,
2028 struct GNUNET_CADET_Channel * channel,
2030 const struct GNUNET_MessageHeader * message)
2032 struct ServiceSession * session;
2033 struct ServiceSession * client_session;
2034 const struct GNUNET_SCALARPRODUCT_service_request * msg = (const struct GNUNET_SCALARPRODUCT_service_request *) message;
2035 uint32_t total_elements;
2037 session = (struct ServiceSession *) * channel_ctx;
2038 if (session->total != 0) {
2039 // must be a fresh session
2042 // Check if message was sent by me, which would be bad!
2043 if (!memcmp (&session->peer, &me, sizeof (struct GNUNET_PeerIdentity))) {
2044 GNUNET_free (session);
2046 return GNUNET_SYSERR;
2048 // shorter than expected?
2049 if (ntohs (msg->header.size) != sizeof (struct GNUNET_SCALARPRODUCT_service_request)) {
2050 GNUNET_free (session);
2051 GNUNET_break_op (0);
2052 return GNUNET_SYSERR;
2054 total_elements = ntohl (msg->total_element_count);
2056 //sanity check: is the message as long as the message_count fields suggests?
2057 if (1 > total_elements) {
2058 GNUNET_free (session);
2059 GNUNET_break_op (0);
2060 return GNUNET_SYSERR;
2062 if (find_matching_session (from_service_tail,
2066 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
2067 _ ("Got message with duplicate session key (`%s'), ignoring service request.\n"),
2068 (const char *) &(msg->session_id));
2069 GNUNET_free (session);
2070 return GNUNET_SYSERR;
2073 session->total = total_elements;
2074 session->channel = channel;
2077 memcpy (&session->session_id, &msg->session_id, sizeof (struct GNUNET_HashCode));
2080 session->remote_pubkey = GNUNET_new (struct GNUNET_CRYPTO_PaillierPublicKey);
2081 memcpy (session->remote_pubkey, &msg->public_key, sizeof (struct GNUNET_CRYPTO_PaillierPublicKey));
2083 //check if service queue contains a matching request
2084 client_session = find_matching_session (from_client_tail,
2085 &session->session_id,
2086 session->total, NULL);
2088 GNUNET_CONTAINER_DLL_insert (from_service_head, from_service_tail, session);
2090 if ((NULL != client_session)
2091 && (client_session->transferred_element_count == client_session->total)) {
2093 GNUNET_log (GNUNET_ERROR_TYPE_INFO, _ ("Got session with key %s and a matching element set, processing.\n"), GNUNET_h2s (&session->session_id));
2095 session->response = client_session;
2096 session->intersected_elements = client_session->intersected_elements;
2097 client_session->intersected_elements = NULL;
2098 session->intersection_set = client_session->intersection_set;
2099 client_session->intersection_set = NULL;
2101 session->intersection_op = GNUNET_SET_prepare (&session->peer,
2102 &session->session_id,
2104 GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_WEAK, UINT16_MAX),
2105 GNUNET_SET_RESULT_REMOVED,
2106 cb_intersection_element_removed,
2109 GNUNET_SET_commit (session->intersection_op, session->intersection_set);
2112 GNUNET_log (GNUNET_ERROR_TYPE_INFO, _ ("Got session with key %s without a matching element set, queueing.\n"), GNUNET_h2s (&session->session_id));
2117 GNUNET_break_op (0);
2118 session->channel = NULL;
2119 // and notify our client-session that we could not complete the session
2120 free_session_variables (session);
2121 if (NULL != session->client){
2123 session->client_notification_task =
2124 GNUNET_SCHEDULER_add_now (&prepare_client_end_notification,
2129 if (NULL != session->response)
2130 session->response->client_notification_task =
2131 GNUNET_SCHEDULER_add_now (&prepare_client_end_notification,
2133 GNUNET_CONTAINER_DLL_remove (from_service_head, from_service_tail, session);
2134 GNUNET_free(session);
2136 return GNUNET_SYSERR;
2141 * Handle a multipart chunk of a response we got from another service we wanted to calculate a scalarproduct with.
2143 * @param cls closure (set from #GNUNET_CADET_connect)
2144 * @param channel connection to the other end
2145 * @param channel_ctx place to store local state associated with the channel
2146 * @param message the actual message
2147 * @return #GNUNET_OK to keep the connection open,
2148 * #GNUNET_SYSERR to close it (signal serious error)
2151 handle_bobs_cryptodata_multipart (void *cls,
2152 struct GNUNET_CADET_Channel * channel,
2154 const struct GNUNET_MessageHeader * message)
2156 struct ServiceSession * session;
2157 const struct GNUNET_SCALARPRODUCT_multipart_message * msg = (const struct GNUNET_SCALARPRODUCT_multipart_message *) message;
2158 struct GNUNET_CRYPTO_PaillierCiphertext * payload;
2160 uint32_t contained = 0;
2162 size_t required_size;
2164 GNUNET_assert (NULL != message);
2165 // are we in the correct state?
2166 session = (struct ServiceSession *) * channel_ctx;
2167 if ((ALICE != session->role) || (NULL == session->sorted_elements)) {
2170 msg_size = ntohs (msg->header.size);
2171 required_size = sizeof (struct GNUNET_SCALARPRODUCT_multipart_message)
2172 + 2 * sizeof (struct GNUNET_CRYPTO_PaillierCiphertext);
2173 // shorter than minimum?
2174 if (required_size > msg_size) {
2177 contained = ntohl (msg->contained_element_count);
2178 required_size = sizeof (struct GNUNET_SCALARPRODUCT_multipart_message)
2179 + 2 * contained * sizeof (struct GNUNET_CRYPTO_PaillierCiphertext);
2180 //sanity check: is the message as long as the message_count fields suggests?
2181 if ((required_size != msg_size) || (session->used_elements_count < session->transferred_element_count + contained)) {
2184 payload = (struct GNUNET_CRYPTO_PaillierCiphertext *) &msg[1];
2185 // Convert each k[][perm] to its MPI_value
2186 for (i = 0; i < contained; i++) {
2187 memcpy (&session->r[session->transferred_element_count + i], &payload[2 * i], sizeof (struct GNUNET_CRYPTO_PaillierCiphertext));
2188 memcpy (&session->r_prime[session->transferred_element_count + i], &payload[2 * i], sizeof (struct GNUNET_CRYPTO_PaillierCiphertext));
2190 session->transferred_element_count += contained;
2191 if (session->transferred_element_count != session->used_elements_count)
2193 session->product = compute_scalar_product (session); //never NULL
2196 GNUNET_break_op (NULL != session->product);
2197 session->channel = NULL;
2198 // send message with product to client
2199 if (NULL != session->client){
2201 session->client_notification_task =
2202 GNUNET_SCHEDULER_add_now (&prepare_client_response,
2207 if (NULL != session->response)
2208 session->response->client_notification_task =
2209 GNUNET_SCHEDULER_add_now (&prepare_client_end_notification,
2211 GNUNET_CONTAINER_DLL_remove (from_service_head, from_service_tail, session);
2212 free_session_variables (session);
2213 GNUNET_free(session);
2215 // the channel has done its job, terminate our connection and the channel
2216 // the peer will be notified that the channel was destroyed via channel_destruction_handler
2217 // just close the connection, as recommended by Christian
2218 return GNUNET_SYSERR;
2223 * Handle a response we got from another service we wanted to calculate a scalarproduct with.
2225 * @param cls closure (set from #GNUNET_CADET_connect)
2226 * @param channel connection to the other end
2227 * @param channel_ctx place to store local state associated with the channel
2228 * @param message the actual message
2229 * @return #GNUNET_OK to keep the connection open,
2230 * #GNUNET_SYSERR to close it (we are done)
2233 handle_bobs_cryptodata_message (void *cls,
2234 struct GNUNET_CADET_Channel * channel,
2236 const struct GNUNET_MessageHeader * message)
2238 struct ServiceSession * session;
2239 const struct GNUNET_SCALARPRODUCT_service_response * msg = (const struct GNUNET_SCALARPRODUCT_service_response *) message;
2240 struct GNUNET_CRYPTO_PaillierCiphertext * payload;
2242 uint32_t contained = 0;
2244 size_t required_size;
2246 GNUNET_assert (NULL != message);
2247 session = (struct ServiceSession *) * channel_ctx;
2248 // are we in the correct state?
2249 if (0 /*//TODO: correct state*/) {
2252 //we need at least a full message without elements attached
2253 msg_size = ntohs (msg->header.size);
2254 required_size = sizeof (struct GNUNET_SCALARPRODUCT_service_response) + 2 * sizeof (struct GNUNET_CRYPTO_PaillierCiphertext);
2256 if (required_size > msg_size) {
2259 contained = ntohl (msg->contained_element_count);
2260 required_size = sizeof (struct GNUNET_SCALARPRODUCT_service_response)
2261 + 2 * contained * sizeof (struct GNUNET_CRYPTO_PaillierCiphertext)
2262 + 2 * sizeof (struct GNUNET_CRYPTO_PaillierCiphertext);
2263 //sanity check: is the message as long as the message_count fields suggests?
2264 if ((msg_size != required_size) || (session->used_elements_count < contained)) {
2267 session->transferred_element_count = contained;
2269 payload = (struct GNUNET_CRYPTO_PaillierCiphertext *) &msg[1];
2271 session->s = GNUNET_malloc (sizeof (struct GNUNET_CRYPTO_PaillierCiphertext));
2272 session->s_prime = GNUNET_malloc (sizeof (struct GNUNET_CRYPTO_PaillierCiphertext));
2273 memcpy (session->s, &payload[0], sizeof (struct GNUNET_CRYPTO_PaillierCiphertext));
2274 memcpy (session->s_prime, &payload[1], sizeof (struct GNUNET_CRYPTO_PaillierCiphertext));
2276 session->r = GNUNET_malloc (sizeof (struct GNUNET_CRYPTO_PaillierCiphertext) * session->used_elements_count);
2277 session->r_prime = GNUNET_malloc (sizeof (struct GNUNET_CRYPTO_PaillierCiphertext) * session->used_elements_count);
2279 // Convert each k[][perm] to its MPI_value
2280 for (i = 0; i < contained; i++) {
2281 memcpy (&session->r[i], &payload[2 + 2 * i], sizeof (struct GNUNET_CRYPTO_PaillierCiphertext));
2282 memcpy (&session->r_prime[i], &payload[3 + 2 * i], sizeof (struct GNUNET_CRYPTO_PaillierCiphertext));
2284 if (session->transferred_element_count != session->used_elements_count)
2285 return GNUNET_OK; //wait for the other multipart chunks
2286 session->product = compute_scalar_product (session); //never NULL
2289 GNUNET_break_op (NULL != session->product);
2290 session->channel = NULL;
2291 // send message with product to client
2292 if (NULL != session->client){
2294 session->client_notification_task =
2295 GNUNET_SCHEDULER_add_now (&prepare_client_response,
2300 if (NULL != session->response)
2301 session->response->client_notification_task =
2302 GNUNET_SCHEDULER_add_now (&prepare_client_end_notification,
2304 GNUNET_CONTAINER_DLL_remove (from_service_head, from_service_tail, session);
2305 free_session_variables (session);
2306 GNUNET_free(session);
2308 // the channel has done its job, terminate our connection and the channel
2309 // the peer will be notified that the channel was destroyed via channel_destruction_handler
2310 // just close the connection, as recommended by Christian
2311 return GNUNET_SYSERR;
2316 * Task run during shutdown.
2322 shutdown_task (void *cls,
2323 const struct GNUNET_SCHEDULER_TaskContext *tc)
2325 struct ServiceSession * session;
2326 GNUNET_log (GNUNET_ERROR_TYPE_INFO, _ ("Shutting down, initiating cleanup.\n"));
2328 do_shutdown = GNUNET_YES;
2330 // terminate all owned open channels.
2331 for (session = from_client_head; NULL != session; session = session->next) {
2332 if ((0/*//TODO: not finalized*/) && (NULL != session->channel)) {
2333 GNUNET_CADET_channel_destroy (session->channel);
2334 session->channel = NULL;
2336 if (GNUNET_SCHEDULER_NO_TASK != session->client_notification_task) {
2337 GNUNET_SCHEDULER_cancel (session->client_notification_task);
2338 session->client_notification_task = GNUNET_SCHEDULER_NO_TASK;
2340 if (NULL != session->client) {
2341 GNUNET_SERVER_client_disconnect (session->client);
2342 session->client = NULL;
2345 for (session = from_service_head; NULL != session; session = session->next)
2346 if (NULL != session->channel) {
2347 GNUNET_CADET_channel_destroy (session->channel);
2348 session->channel = NULL;
2352 GNUNET_CADET_disconnect (my_cadet);
2359 * Initialization of the program and message handlers
2361 * @param cls closure
2362 * @param server the initialized server
2363 * @param c configuration to use
2367 struct GNUNET_SERVER_Handle *server,
2368 const struct GNUNET_CONFIGURATION_Handle *c)
2370 static const struct GNUNET_SERVER_MessageHandler server_handlers[] = {
2371 {&handle_client_message, NULL, GNUNET_MESSAGE_TYPE_SCALARPRODUCT_CLIENT_TO_ALICE, 0},
2372 {&handle_client_message, NULL, GNUNET_MESSAGE_TYPE_SCALARPRODUCT_CLIENT_TO_BOB, 0},
2373 {&handle_client_message_multipart, NULL, GNUNET_MESSAGE_TYPE_SCALARPRODUCT_CLIENT_MUTLIPART, 0},
2376 static const struct GNUNET_CADET_MessageHandler cadet_handlers[] = {
2377 { &handle_alices_computation_request, GNUNET_MESSAGE_TYPE_SCALARPRODUCT_ALICE_CRYPTODATA, 0},
2378 { &handle_alices_cyrptodata_message, GNUNET_MESSAGE_TYPE_SCALARPRODUCT_ALICE_CRYPTODATA, 0},
2379 { &handle_alices_cyrptodata_message_multipart, GNUNET_MESSAGE_TYPE_SCALARPRODUCT_ALICE_CRYPTODATA_MULTIPART, 0},
2380 { &handle_bobs_cryptodata_message, GNUNET_MESSAGE_TYPE_SCALARPRODUCT_BOB_CRYPTODATA, 0},
2381 { &handle_bobs_cryptodata_multipart, GNUNET_MESSAGE_TYPE_SCALARPRODUCT_BOB_CRYPTODATA_MULTIPART, 0},
2384 static const uint32_t ports[] = {
2385 GNUNET_APPLICATION_TYPE_SCALARPRODUCT,
2388 //generate private/public key set
2389 GNUNET_CRYPTO_paillier_create (&my_pubkey, &my_privkey);
2391 // offset has to be sufficiently small to allow computation of:
2392 // m1+m2 mod n == (S + a) + (S + b) mod n,
2393 // if we have more complex operations, this factor needs to be lowered
2394 my_offset = gcry_mpi_new (GNUNET_CRYPTO_PAILLIER_BITS / 3);
2395 gcry_mpi_set_bit (my_offset, GNUNET_CRYPTO_PAILLIER_BITS / 3);
2397 // register server callbacks and disconnect handler
2398 GNUNET_SERVER_add_handlers (server, server_handlers);
2399 GNUNET_SERVER_disconnect_notify (server,
2400 &handle_client_disconnect,
2402 GNUNET_break (GNUNET_OK ==
2403 GNUNET_CRYPTO_get_peer_identity (c,
2405 my_cadet = GNUNET_CADET_connect (c, NULL,
2406 &cb_channel_incoming,
2407 &cb_channel_destruction,
2408 cadet_handlers, ports);
2410 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, _ ("Connect to CADET failed\n"));
2411 GNUNET_SCHEDULER_shutdown ();
2414 GNUNET_log (GNUNET_ERROR_TYPE_INFO, _ ("CADET initialized\n"));
2415 GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_FOREVER_REL,
2422 * The main function for the scalarproduct service.
2424 * @param argc number of arguments from the command line
2425 * @param argv command line arguments
2426 * @return 0 ok, 1 on error
2429 main (int argc, char *const *argv)
2431 return (GNUNET_OK ==
2432 GNUNET_SERVICE_run (argc, argv,
2434 GNUNET_SERVICE_OPTION_NONE,
2435 &run, NULL)) ? 0 : 1;
2438 /* end of gnunet-service-scalarproduct.c */