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
59 struct SortedValue * next;
60 struct SortedValue * prev;
61 struct GNUNET_SCALARPRODUCT_Element * elem;
67 * A scalarproduct session which tracks:
69 * a request form the client to our final response.
71 * a request from a service to us(service).
76 * the role this peer has
81 * session information is kept in a DLL
83 struct ServiceSession *next;
86 * session information is kept in a DLL
88 struct ServiceSession *prev;
91 * (hopefully) unique transaction ID
93 struct GNUNET_HashCode session_id;
96 * Alice or Bob's peerID
98 struct GNUNET_PeerIdentity peer;
101 * the client this request is related to
103 struct GNUNET_SERVER_Client * client;
106 * The message to send
108 struct GNUNET_MessageHeader * msg;
111 * how many elements we were supplied with from the client
116 * how many elements we used for intersection
118 uint32_t intersected_elements_count;
121 * all non-0-value'd elements transmitted to us
123 struct GNUNET_CONTAINER_MultiHashMap * intersected_elements;
126 * how many elements actually are used for the scalar product
128 uint32_t used_elements_count;
131 * already transferred elements (sent/received) for multipart messages, less or equal than used_element_count for
133 uint32_t transferred_element_count;
136 * Set of elements for which will conduction an intersection.
137 * the resulting elements are then used for computing the scalar product.
139 struct GNUNET_SET_Handle * intersection_set;
142 * Set of elements for which will conduction an intersection.
143 * the resulting elements are then used for computing the scalar product.
145 struct GNUNET_SET_OperationHandle * intersection_op;
148 * Handle to Alice's Intersection operation listening for Bob
150 struct GNUNET_SET_ListenHandle * intersection_listen;
153 * Public key of the remote service, only used by bob
155 struct GNUNET_CRYPTO_PaillierPublicKey remote_pubkey;
158 * DLL for sorting elements after intersection
160 struct SortedValue * a_head;
165 struct SortedValue * a_tail;
170 gcry_mpi_t * sorted_elements;
173 * E(ai)(Bob) after applying the mask
175 struct GNUNET_CRYPTO_PaillierCiphertext * e_a;
178 * Bob's permutation p of R
180 struct GNUNET_CRYPTO_PaillierCiphertext * r;
183 * Bob's permutation q of R
185 struct GNUNET_CRYPTO_PaillierCiphertext * r_prime;
190 struct GNUNET_CRYPTO_PaillierCiphertext * s;
195 struct GNUNET_CRYPTO_PaillierCiphertext * s_prime;
198 * Bobs matching response session from the client
200 struct ServiceSession * response;
203 * The computed scalar
208 * My transmit handle for the current message to a alice/bob
210 struct GNUNET_CADET_TransmitHandle * service_transmit_handle;
213 * My transmit handle for the current message to the client
215 struct GNUNET_SERVER_TransmitHandle * client_transmit_handle;
218 * channel-handle associated with our cadet handle
220 struct GNUNET_CADET_Channel * channel;
223 * Handle to a task that sends a msg to the our client
225 GNUNET_SCHEDULER_TaskIdentifier client_notification_task;
228 ///////////////////////////////////////////////////////////////////////////////
229 // Forward Delcarations
230 ///////////////////////////////////////////////////////////////////////////////
233 * Send a multi part chunk of a service request from alice to bob.
234 * This element only contains a part of the elements-vector (session->a[]),
235 * mask and public key set have to be contained within the first message
237 * This allows a ~32kbit key length while using 32000 elements or 62000 elements per request.
239 * @param cls the associated service session
242 prepare_alices_cyrptodata_message_multipart (void *cls);
245 * Send a multi part chunk of a service response from bob to alice.
246 * This element only contains the two permutations of R, R'.
248 * @param cls the associated service session
251 prepare_bobs_cryptodata_message_multipart (void *cls);
254 ///////////////////////////////////////////////////////////////////////////////
256 ///////////////////////////////////////////////////////////////////////////////
260 * Gnunet configuration handle
262 const struct GNUNET_CONFIGURATION_Handle * cfg;
265 * Handle to the core service (NULL until we've connected to it).
267 static struct GNUNET_CADET_Handle *my_cadet;
270 * The identity of this host.
272 static struct GNUNET_PeerIdentity me;
275 * Service's own public key
277 static struct GNUNET_CRYPTO_PaillierPublicKey my_pubkey;
280 * Service's own private key
282 static struct GNUNET_CRYPTO_PaillierPrivateKey my_privkey;
285 * Service's offset for values that could possibly be negative but are plaintext for encryption.
287 static gcry_mpi_t my_offset;
290 * Head of our double linked list for client-requests sent to us.
291 * for all of these elements we calculate a scalar product with a remote peer
292 * split between service->service and client->service for simplicity
294 static struct ServiceSession * from_client_head;
296 * Tail of our double linked list for client-requests sent to us.
297 * for all of these elements we calculate a scalar product with a remote peer
298 * split between service->service and client->service for simplicity
300 static struct ServiceSession * from_client_tail;
303 * Head of our double linked list for service-requests sent to us.
304 * for all of these elements we help the requesting service in calculating a scalar product
305 * split between service->service and client->service for simplicity
307 static struct ServiceSession * from_service_head;
310 * Tail of our double linked list for service-requests sent to us.
311 * for all of these elements we help the requesting service in calculating a scalar product
312 * split between service->service and client->service for simplicity
314 static struct ServiceSession * from_service_tail;
317 * Certain events (callbacks for server & cadet operations) must not be queued after shutdown.
319 static int do_shutdown;
321 ///////////////////////////////////////////////////////////////////////////////
323 ///////////////////////////////////////////////////////////////////////////////
327 * computes the square sum over a vector of a given length.
329 * @param vector the vector to encrypt
330 * @param length the length of the vector
331 * @return an MPI value containing the calculated sum, never NULL
334 compute_square_sum (gcry_mpi_t * vector, uint32_t length)
340 GNUNET_assert (sum = gcry_mpi_new (0));
341 GNUNET_assert (elem = gcry_mpi_new (0));
343 // calculare E(sum (ai ^ 2), publickey)
344 for (i = 0; i < length; i++) {
345 gcry_mpi_mul (elem, vector[i], vector[i]);
346 gcry_mpi_add (sum, sum, elem);
348 gcry_mpi_release (elem);
355 * Primitive callback for copying over a message, as they
356 * usually are too complex to be handled in the callback itself.
357 * clears a session-callback, if a session was handed over and the transmit handle was stored
359 * @param cls the session containing the message object
360 * @param size the size of the buffer we got
361 * @param buf the buffer to copy the message to
362 * @return 0 if we couldn't copy, else the size copied over
365 do_send_message (void *cls, size_t size, void *buf)
367 struct ServiceSession * s = cls;
372 if (ntohs (s->msg->size) != size) {
377 type = ntohs (s->msg->type);
378 memcpy (buf, s->msg, size);
379 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
380 "Sent a message of type %hu.\n",
382 GNUNET_free (s->msg);
387 case GNUNET_MESSAGE_TYPE_SCALARPRODUCT_RESULT:
388 s->client_transmit_handle = NULL;
391 case GNUNET_MESSAGE_TYPE_SCALARPRODUCT_ALICE_CRYPTODATA:
392 case GNUNET_MESSAGE_TYPE_SCALARPRODUCT_ALICE_CRYPTODATA_MULTIPART:
393 s->service_transmit_handle = NULL;
394 if (s->used_elements_count != s->transferred_element_count)
395 prepare_alices_cyrptodata_message_multipart (s);
398 case GNUNET_MESSAGE_TYPE_SCALARPRODUCT_BOB_CRYPTODATA:
399 case GNUNET_MESSAGE_TYPE_SCALARPRODUCT_BOB_CRYPTODATA_MULTIPART:
400 s->service_transmit_handle = NULL;
401 if (s->used_elements_count != s->transferred_element_count)
402 prepare_bobs_cryptodata_message_multipart (s);
414 * Finds a not terminated client/service session in the
415 * given DLL based on session key, element count and state.
417 * @param tail - the tail of the DLL
418 * @param key - the key we want to search for
419 * @param element_count - the total element count of the dataset (session->total)
420 * @param peerid - a pointer to the peer ID of the associated peer, NULL to ignore
421 * @return a pointer to a matching session, or NULL
423 static struct ServiceSession *
424 find_matching_session (struct ServiceSession * tail,
425 const struct GNUNET_HashCode * key,
426 uint32_t element_count,
427 const struct GNUNET_PeerIdentity * peerid)
429 struct ServiceSession * curr;
431 for (curr = tail; NULL != curr; curr = curr->prev) {
432 // if the key matches, and the element_count is same
433 if ((!memcmp (&curr->session_id, key, sizeof (struct GNUNET_HashCode)))
434 && (curr->total == element_count)) {
435 // if peerid is NULL OR same as the peer Id in the queued request
437 || (!memcmp (&curr->peer, peerid, sizeof (struct GNUNET_PeerIdentity))))
438 // matches and is not an already terminated session
448 * Safely frees ALL memory areas referenced by a session.
450 * @param session - the session to free elements from
453 free_session_variables (struct ServiceSession * session)
455 while (NULL != session->a_head) {
456 struct SortedValue * e = session->a_head;
457 GNUNET_free (e->elem);
458 gcry_mpi_release (e->val);
459 GNUNET_CONTAINER_DLL_remove (session->a_head, session->a_tail, e);
463 GNUNET_free (session->e_a);
466 if (session->sorted_elements) {
467 GNUNET_free (session->sorted_elements);
468 session->sorted_elements = NULL;
470 if (session->intersected_elements) {
471 GNUNET_CONTAINER_multihashmap_destroy (session->intersected_elements);
472 //elements are freed independently in session->a_head/tail
473 session->intersected_elements = NULL;
475 if (session->intersection_listen) {
476 GNUNET_SET_listen_cancel (session->intersection_listen);
477 session->intersection_listen = NULL;
479 if (session->intersection_op) {
480 GNUNET_SET_operation_cancel (session->intersection_op);
481 session->intersection_op = NULL;
483 if (session->intersection_set) {
484 GNUNET_SET_destroy (session->intersection_set);
485 session->intersection_set = NULL;
487 if (session->channel){
488 GNUNET_CADET_channel_destroy(session->channel);
489 session->channel = NULL;
492 GNUNET_free (session->msg);
496 GNUNET_free (session->r);
499 if (session->r_prime) {
500 GNUNET_free (session->r_prime);
501 session->r_prime = NULL;
504 GNUNET_free (session->s);
507 if (session->s_prime) {
508 GNUNET_free (session->s_prime);
509 session->s_prime = NULL;
511 if (session->product) {
512 gcry_mpi_release (session->product);
513 session->product = NULL;
516 ///////////////////////////////////////////////////////////////////////////////
517 // Event and Message Handlers
518 ///////////////////////////////////////////////////////////////////////////////
522 * A client disconnected.
524 * Remove the associated session(s), release data structures
525 * and cancel pending outgoing transmissions to the client.
526 * if the session has not yet completed, we also cancel Alice's request to Bob.
528 * @param cls closure, NULL
529 * @param client identification of the client
532 handle_client_disconnect (void *cls,
533 struct GNUNET_SERVER_Client *client)
535 struct ServiceSession *session;
538 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
539 _ ("Client (%p) disconnected from us.\n"), client);
543 session = GNUNET_SERVER_client_get_user_context (client, struct ServiceSession);
546 GNUNET_CONTAINER_DLL_remove (from_client_head, from_client_tail, session);
548 if (!(session->role == BOB && 0/*//TODO: if session concluded*/)) {
549 //we MUST terminate any client message underway
550 if (session->service_transmit_handle && session->channel)
551 GNUNET_CADET_notify_transmit_ready_cancel (session->service_transmit_handle);
552 if (session->channel && 0/* //TODO: waiting for service response */)
553 GNUNET_CADET_channel_destroy (session->channel);
555 if (GNUNET_SCHEDULER_NO_TASK != session->client_notification_task) {
556 GNUNET_SCHEDULER_cancel (session->client_notification_task);
557 session->client_notification_task = GNUNET_SCHEDULER_NO_TASK;
559 if (NULL != session->client_transmit_handle) {
560 GNUNET_SERVER_notify_transmit_ready_cancel (session->client_transmit_handle);
561 session->client_transmit_handle = NULL;
563 free_session_variables (session);
564 GNUNET_free (session);
569 * Notify the client that the session has succeeded or failed completely.
570 * This message gets sent to
571 * * alice's client if bob disconnected or to
572 * * bob's client if the operation completed or alice disconnected
574 * @param cls the associated client session
575 * @param tc the task context handed to us by the scheduler, unused
578 prepare_client_end_notification (void * cls,
579 const struct GNUNET_SCHEDULER_TaskContext * tc)
581 struct ServiceSession * session = cls;
582 struct GNUNET_SCALARPRODUCT_client_response * msg;
584 session->client_notification_task = GNUNET_SCHEDULER_NO_TASK;
586 msg = GNUNET_new (struct GNUNET_SCALARPRODUCT_client_response);
587 msg->header.type = htons (GNUNET_MESSAGE_TYPE_SCALARPRODUCT_RESULT);
588 memcpy (&msg->key, &session->session_id, sizeof (struct GNUNET_HashCode));
589 memcpy (&msg->peer, &session->peer, sizeof ( struct GNUNET_PeerIdentity));
590 msg->header.size = htons (sizeof (struct GNUNET_SCALARPRODUCT_client_response));
591 // signal error if not signalized, positive result-range field but zero length.
592 msg->product_length = htonl (0);
593 msg->range = (session /* //TODO: if finalized */) ? 0 : -1;
595 session->msg = &msg->header;
597 //transmit this message to our client
598 session->client_transmit_handle =
599 GNUNET_SERVER_notify_transmit_ready (session->client,
600 sizeof (struct GNUNET_SCALARPRODUCT_client_response),
601 GNUNET_TIME_UNIT_FOREVER_REL,
605 // if we could not even queue our request, something is wrong
606 if (NULL == session->client_transmit_handle) {
607 GNUNET_log (GNUNET_ERROR_TYPE_WARNING, _ ("Could not send message to client (%p)!\n"), session->client);
608 // usually gets freed by do_send_message
613 GNUNET_log (GNUNET_ERROR_TYPE_INFO, _ ("Sending session-end notification to client (%p) for session %s\n"), &session->client, GNUNET_h2s (&session->session_id));
615 free_session_variables (session);
620 * Executed by Alice, fills in a service-request message and sends it to the given peer
622 * @param cls the session associated with this request
625 prepare_alices_cyrptodata_message (void *cls)
627 struct ServiceSession * session = cls;
628 struct GNUNET_SCALARPRODUCT_alices_cryptodata_message * msg;
629 struct GNUNET_CRYPTO_PaillierCiphertext * payload;
634 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, _ ("Successfully created new channel to peer (%s)!\n"), GNUNET_i2s (&session->peer));
636 msg_length = sizeof (struct GNUNET_SCALARPRODUCT_alices_cryptodata_message)
637 +session->used_elements_count * sizeof (struct GNUNET_CRYPTO_PaillierCiphertext);
639 if (GNUNET_SERVER_MAX_MESSAGE_SIZE > msg_length) {
640 session->transferred_element_count = session->used_elements_count;
643 //create a multipart msg, first we calculate a new msg size for the head msg
644 session->transferred_element_count = (GNUNET_SERVER_MAX_MESSAGE_SIZE - 1 - sizeof (struct GNUNET_SCALARPRODUCT_alices_cryptodata_message))
645 / sizeof (struct GNUNET_CRYPTO_PaillierCiphertext);
646 msg_length = sizeof (struct GNUNET_SCALARPRODUCT_alices_cryptodata_message)
647 +session->transferred_element_count * sizeof (struct GNUNET_CRYPTO_PaillierCiphertext);
650 msg = GNUNET_malloc (msg_length);
651 msg->header.size = htons (msg_length);
652 msg->header.type = htons (GNUNET_MESSAGE_TYPE_SCALARPRODUCT_ALICE_CRYPTODATA);
653 msg->contained_element_count = htonl (session->transferred_element_count);
655 // fill in the payload
656 payload = (struct GNUNET_CRYPTO_PaillierCiphertext *) &msg[1];
658 // now copy over the sorted element vector
659 a = gcry_mpi_new (0);
660 for (i = 0; i < session->transferred_element_count; i++) {
661 gcry_mpi_add (a, session->sorted_elements[i], my_offset);
662 GNUNET_CRYPTO_paillier_encrypt (&my_pubkey, a, 3, &payload[i]);
664 gcry_mpi_release (a);
666 session->msg = (struct GNUNET_MessageHeader *) msg;
667 GNUNET_log (GNUNET_ERROR_TYPE_INFO, _ ("Transmitting service request.\n"));
669 //transmit via cadet messaging
670 session->service_transmit_handle = GNUNET_CADET_notify_transmit_ready (session->channel, GNUNET_YES,
671 GNUNET_TIME_UNIT_FOREVER_REL,
675 if (NULL == session->service_transmit_handle) {
676 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, _ ("Could not send message to channel!\n"));
679 session->client_notification_task =
680 GNUNET_SCHEDULER_add_now (&prepare_client_end_notification,
688 * Send a multipart chunk of a service response from bob to alice.
689 * This element only contains the two permutations of R, R'.
691 * @param cls the associated service session
694 prepare_bobs_cryptodata_message_multipart (void *cls)
696 struct ServiceSession * session = cls;
697 struct GNUNET_CRYPTO_PaillierCiphertext * payload;
698 struct GNUNET_SCALARPRODUCT_multipart_message * msg;
704 msg_length = sizeof (struct GNUNET_SCALARPRODUCT_multipart_message);
705 todo_count = session->used_elements_count - session->transferred_element_count;
707 if (todo_count > MULTIPART_ELEMENT_CAPACITY / 2)
708 // send the currently possible maximum chunk, we always transfer both permutations
709 todo_count = MULTIPART_ELEMENT_CAPACITY / 2;
711 msg_length += todo_count * sizeof (struct GNUNET_CRYPTO_PaillierCiphertext) * 2;
712 msg = GNUNET_malloc (msg_length);
713 msg->header.type = htons (GNUNET_MESSAGE_TYPE_SCALARPRODUCT_ALICE_CRYPTODATA_MULTIPART);
714 msg->header.size = htons (msg_length);
715 msg->contained_element_count = htonl (todo_count);
717 payload = (struct GNUNET_CRYPTO_PaillierCiphertext *) &msg[1];
718 for (i = session->transferred_element_count, j = 0; i < session->transferred_element_count + todo_count; i++) {
719 //r[i][p] and r[i][q]
720 memcpy (&payload[j++], &session->r[i], sizeof (struct GNUNET_CRYPTO_PaillierCiphertext));
721 memcpy (&payload[j++], &session->r_prime[i], sizeof (struct GNUNET_CRYPTO_PaillierCiphertext));
723 session->transferred_element_count += todo_count;
724 session->msg = (struct GNUNET_MessageHeader *) msg;
725 session->service_transmit_handle =
726 GNUNET_CADET_notify_transmit_ready (session->channel,
728 GNUNET_TIME_UNIT_FOREVER_REL,
732 //disconnect our client
733 if (NULL == session->service_transmit_handle) {
734 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, _ ("Could not send service-response message via cadet!)\n"));
736 session->response->client_notification_task =
737 GNUNET_SCHEDULER_add_now (&prepare_client_end_notification,
741 if (session->transferred_element_count != session->used_elements_count) {
746 GNUNET_free (session->r_prime);
747 GNUNET_free (session->r);
748 session->r_prime = NULL;
756 * generates the response message to be sent to alice after computing
757 * the values (1), (2), S and S'
758 * (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)})$
759 * (2)[]: $E_A(a_{pi'(i)}) times E_A(- r_{pi'(i)}) &= E_A(a_{pi'(i)} - r_{pi'(i)})$
760 * S: $S := E_A(sum (r_i + b_i)^2)$
761 * S': $S' := E_A(sum r_i^2)$
763 * @param session the associated requesting session with alice
766 prepare_bobs_cryptodata_message (void *cls,
767 const struct GNUNET_SCHEDULER_TaskContext
770 struct ServiceSession * session = (struct ServiceSession *) cls;
771 struct GNUNET_SCALARPRODUCT_service_response * msg;
772 uint32_t msg_length = 0;
773 struct GNUNET_CRYPTO_PaillierCiphertext * payload;
776 msg_length = sizeof (struct GNUNET_SCALARPRODUCT_service_response)
777 + 2 * sizeof (struct GNUNET_CRYPTO_PaillierCiphertext); // s, stick
779 if (GNUNET_SERVER_MAX_MESSAGE_SIZE >
780 msg_length + 2 * session->used_elements_count * sizeof (struct GNUNET_CRYPTO_PaillierCiphertext)) { //r, r'
781 msg_length += 2 * session->used_elements_count * sizeof (struct GNUNET_CRYPTO_PaillierCiphertext);
782 session->transferred_element_count = session->used_elements_count;
785 session->transferred_element_count = (GNUNET_SERVER_MAX_MESSAGE_SIZE - 1 - msg_length) /
786 (sizeof (struct GNUNET_CRYPTO_PaillierCiphertext) * 2);
788 msg = GNUNET_malloc (msg_length);
789 msg->header.type = htons (GNUNET_MESSAGE_TYPE_SCALARPRODUCT_BOB_CRYPTODATA);
790 msg->header.size = htons (msg_length);
791 msg->total_element_count = htonl (session->total);
792 msg->used_element_count = htonl (session->used_elements_count);
793 msg->contained_element_count = htonl (session->transferred_element_count);
794 memcpy (&msg->key, &session->session_id, sizeof (struct GNUNET_HashCode));
796 payload = (struct GNUNET_CRYPTO_PaillierCiphertext *) &msg[1];
797 memcpy (&payload[0], session->s, sizeof (struct GNUNET_CRYPTO_PaillierCiphertext));
798 memcpy (&payload[1], session->s_prime, sizeof (struct GNUNET_CRYPTO_PaillierCiphertext));
799 GNUNET_free (session->s_prime);
800 session->s_prime = NULL;
801 GNUNET_free (session->s);
804 payload = &payload[2];
806 for (i = 0; i < session->transferred_element_count; i++) {
807 //k[i][p] and k[i][q]
808 memcpy (&payload[i * 2], &session->r[i], sizeof (struct GNUNET_CRYPTO_PaillierCiphertext));
809 memcpy (&payload[i * 2 + 1], &session->r_prime[i], sizeof (struct GNUNET_CRYPTO_PaillierCiphertext));
812 session->msg = (struct GNUNET_MessageHeader *) msg;
813 session->service_transmit_handle =
814 GNUNET_CADET_notify_transmit_ready (session->channel,
816 GNUNET_TIME_UNIT_FOREVER_REL,
820 //disconnect our client
821 if (NULL == session->service_transmit_handle) {
822 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, _ ("Could not send service-response message via cadet!)\n"));
824 session->response->client_notification_task =
825 GNUNET_SCHEDULER_add_now (&prepare_client_end_notification,
828 if (session->transferred_element_count != session->used_elements_count) {
833 GNUNET_free (session->r);
835 GNUNET_free (session->r_prime);
836 session->r_prime = NULL;
844 * (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)})$
845 * (2)[]: $E_A(a_{pi'(i)}) otimes E_A(- r_{pi'(i)}) &= E_A(a_{pi'(i)} - r_{pi'(i)})$
846 * S: $S := E_A(sum (r_i + b_i)^2)$
847 * S': $S' := E_A(sum r_i^2)$
849 * @param request the requesting session + bob's requesting peer
852 compute_service_response (struct ServiceSession * session)
858 gcry_mpi_t * rand = NULL;
861 struct GNUNET_CRYPTO_PaillierCiphertext * a;
862 struct GNUNET_CRYPTO_PaillierCiphertext * r;
863 struct GNUNET_CRYPTO_PaillierCiphertext * r_prime;
864 struct GNUNET_CRYPTO_PaillierCiphertext * s;
865 struct GNUNET_CRYPTO_PaillierCiphertext * s_prime;
867 count = session->used_elements_count;
869 b = session->sorted_elements;
870 q = GNUNET_CRYPTO_random_permute (GNUNET_CRYPTO_QUALITY_WEAK, count);
871 p = GNUNET_CRYPTO_random_permute (GNUNET_CRYPTO_QUALITY_WEAK, count);
873 for (i = 0; i < count; i++)
874 GNUNET_assert (NULL != (rand[i] = gcry_mpi_new (0)));
875 r = GNUNET_malloc (sizeof (struct GNUNET_CRYPTO_PaillierCiphertext) * count);
876 r_prime = GNUNET_malloc (sizeof (struct GNUNET_CRYPTO_PaillierCiphertext) * count);
877 s = GNUNET_malloc (sizeof (struct GNUNET_CRYPTO_PaillierCiphertext));
878 s_prime = GNUNET_malloc (sizeof (struct GNUNET_CRYPTO_PaillierCiphertext));
880 for (i = 0; i < count; i++) {
883 svalue = (int32_t) GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_WEAK, UINT32_MAX);
885 // long to gcry_mpi_t
887 gcry_mpi_sub_ui (rand[i],
891 rand[i] = gcry_mpi_set_ui (rand[i], svalue);
894 tmp = gcry_mpi_new (0);
895 // encrypt the element
896 // for the sake of readability I decided to have dedicated permutation
897 // vectors, which get rid of all the lookups in p/q.
898 // however, ap/aq are not absolutely necessary but are just abstraction
899 // Calculate Kp = E(S + a_pi) (+) E(S - r_pi - b_pi)
900 for (i = 0; i < count; i++) {
901 // E(S - r_pi - b_pi)
902 gcry_mpi_sub (tmp, my_offset, rand[p[i]]);
903 gcry_mpi_sub (tmp, tmp, b[p[i]]);
904 GNUNET_CRYPTO_paillier_encrypt (&session->remote_pubkey,
909 // E(S - r_pi - b_pi) * E(S + a_pi) == E(2*S + a - r - b)
910 GNUNET_CRYPTO_paillier_hom_add (&session->remote_pubkey,
916 // Calculate Kq = E(S + a_qi) (+) E(S - r_qi)
917 for (i = 0; i < count; i++) {
919 gcry_mpi_sub (tmp, my_offset, rand[q[i]]);
920 GNUNET_assert (2 == GNUNET_CRYPTO_paillier_encrypt (&session->remote_pubkey,
925 // E(S - r_qi) * E(S + a_qi) == E(2*S + a_qi - r_qi)
926 GNUNET_assert (1 == GNUNET_CRYPTO_paillier_hom_add (&session->remote_pubkey,
932 // Calculate S' = E(SUM( r_i^2 ))
933 tmp = compute_square_sum (rand, count);
934 GNUNET_CRYPTO_paillier_encrypt (&session->remote_pubkey,
939 // Calculate S = E(SUM( (r_i + b_i)^2 ))
940 for (i = 0; i < count; i++)
941 gcry_mpi_add (rand[i], rand[i], b[i]);
942 tmp = compute_square_sum (rand, count);
943 GNUNET_CRYPTO_paillier_encrypt (&session->remote_pubkey,
949 session->r_prime = r_prime;
951 session->s_prime = s_prime;
953 // release rand, b and a
954 for (i = 0; i < count; i++) {
955 gcry_mpi_release (rand[i]);
956 gcry_mpi_release (b[i]);
958 gcry_mpi_release (tmp);
959 GNUNET_free (session->e_a);
966 // copy the r[], r_prime[], S and Stick into a new message, prepare_service_response frees these
967 GNUNET_SCHEDULER_add_now (&prepare_bobs_cryptodata_message, session);
972 * Iterator over all hash map entries in session->intersected_elements.
975 * @param key current key code
976 * @param value value in the hash map
977 * @return #GNUNET_YES if we should continue to
982 cb_insert_element_sorted (void *cls,
983 const struct GNUNET_HashCode *key,
986 struct ServiceSession * session = (struct ServiceSession*) cls;
987 struct SortedValue * e = GNUNET_new (struct SortedValue);
988 struct SortedValue * o = session->a_head;
991 e->val = gcry_mpi_new (0);
992 if (0 > e->elem->value)
993 gcry_mpi_sub_ui (e->val, e->val, abs (e->elem->value));
995 gcry_mpi_add_ui (e->val, e->val, e->elem->value);
997 // insert as first element with the lowest key
998 if (NULL == session->a_head
999 || (0 <= GNUNET_CRYPTO_hash_cmp (&session->a_head->elem->key, &e->elem->key))) {
1000 GNUNET_CONTAINER_DLL_insert (session->a_head, session->a_tail, e);
1003 // insert as last element with the highest key
1004 if (0 >= GNUNET_CRYPTO_hash_cmp (&session->a_tail->elem->key, &e->elem->key)) {
1005 GNUNET_CONTAINER_DLL_insert_tail (session->a_head, session->a_tail, e);
1008 // insert before the first higher/equal element
1010 if (0 <= GNUNET_CRYPTO_hash_cmp (&o->elem->key, &e->elem->key)) {
1011 GNUNET_CONTAINER_DLL_insert_before (session->a_head, session->a_tail, o, e);
1023 * Callback for set operation results. Called for each element
1024 * in the result set.
1026 * @param cls closure
1027 * @param element a result element, only valid if status is #GNUNET_SET_STATUS_OK
1028 * @param status see `enum GNUNET_SET_Status`
1031 cb_intersection_element_removed (void *cls,
1032 const struct GNUNET_SET_Element *element,
1033 enum GNUNET_SET_Status status)
1035 struct ServiceSession * session = (struct ServiceSession*) cls;
1036 struct GNUNET_SCALARPRODUCT_Element * se;
1041 case GNUNET_SET_STATUS_OK:
1042 //this element has been removed from the set
1043 se = GNUNET_CONTAINER_multihashmap_get (session->intersected_elements,
1046 GNUNET_CONTAINER_multihashmap_remove (session->intersected_elements,
1049 session->used_elements_count--;
1052 case GNUNET_SET_STATUS_DONE:
1053 if (2 > session->used_elements_count) {
1054 // failed! do not leak information about our single remaining element!
1055 // continue after the loop
1059 GNUNET_CONTAINER_multihashmap_iterate (session->intersected_elements,
1060 &cb_insert_element_sorted,
1063 session->sorted_elements = GNUNET_malloc (session->used_elements_count * sizeof (gcry_mpi_t));
1064 for (i = 0; NULL != session->a_head; i++) {
1065 struct SortedValue* a = session->a_head;
1066 GNUNET_assert (i < session->used_elements_count);
1068 session->sorted_elements[i] = a->val;
1069 GNUNET_CONTAINER_DLL_remove (session->a_head, session->a_tail, a);
1070 GNUNET_free (a->elem);
1072 GNUNET_assert (i == session->used_elements_count);
1074 if (ALICE == session->role) {
1075 prepare_alices_cyrptodata_message (session);
1078 else if (session->used_elements_count == session->transferred_element_count) {
1079 compute_service_response (session);
1086 //failed if we go here
1089 // and notify our client-session that we could not complete the session
1090 if (ALICE == session->role) {
1091 session->client_notification_task =
1092 GNUNET_SCHEDULER_add_now (&prepare_client_end_notification,
1096 GNUNET_CONTAINER_DLL_remove (from_service_head, from_service_tail, session);
1097 free_session_variables (session);
1098 session->response->client_notification_task =
1099 GNUNET_SCHEDULER_add_now (&prepare_client_end_notification,
1101 GNUNET_free(session);
1107 * Called when another peer wants to do a set operation with the
1108 * local peer. If a listen error occurs, the @a request is NULL.
1110 * @param cls closure
1111 * @param other_peer the other peer
1112 * @param context_msg message with application specific information from
1114 * @param request request from the other peer (never NULL), use GNUNET_SET_accept()
1115 * to accept it, otherwise the request will be refused
1116 * Note that we can't just return value from the listen callback,
1117 * as it is also necessary to specify the set we want to do the
1118 * operation with, whith sometimes can be derived from the context
1119 * message. It's necessary to specify the timeout.
1122 cb_intersection_request_alice (void *cls,
1123 const struct GNUNET_PeerIdentity *other_peer,
1124 const struct GNUNET_MessageHeader *context_msg,
1125 struct GNUNET_SET_Request *request)
1127 struct ServiceSession * session = (struct ServiceSession *) cls;
1129 // check the peer-id, the app-id=session-id is compared by SET
1130 if (0 != memcmp (&session->peer, &other_peer, sizeof (struct GNUNET_PeerIdentity)))
1133 session->intersection_op = GNUNET_SET_accept (request,
1134 GNUNET_SET_RESULT_REMOVED,
1135 cb_intersection_element_removed,
1138 if (NULL == session->intersection_op) {
1139 session->response->client_notification_task =
1140 GNUNET_SCHEDULER_add_now (&prepare_client_end_notification,
1144 if (GNUNET_OK != GNUNET_SET_commit (session->intersection_op, session->intersection_set)) {
1145 session->response->client_notification_task =
1146 GNUNET_SCHEDULER_add_now (&prepare_client_end_notification,
1150 session->intersection_set = NULL;
1151 session->intersection_listen = NULL;
1156 * prepare the response we will send to alice or bobs' clients.
1157 * in Bobs case the product will be NULL.
1159 * @param cls the session associated with our client.
1160 * @param tc the task context handed to us by the scheduler, unused
1163 prepare_client_response (void *cls,
1164 const struct GNUNET_SCHEDULER_TaskContext *tc)
1166 struct ServiceSession * session = cls;
1167 struct GNUNET_SCALARPRODUCT_client_response * msg;
1168 unsigned char * product_exported = NULL;
1169 size_t product_length = 0;
1170 uint32_t msg_length = 0;
1175 session->client_notification_task = GNUNET_SCHEDULER_NO_TASK;
1177 if (session->product) {
1178 gcry_mpi_t value = gcry_mpi_new (0);
1180 sign = gcry_mpi_cmp_ui (session->product, 0);
1181 // libgcrypt can not handle a print of a negative number
1182 // if (a->sign) return gcry_error (GPG_ERR_INTERNAL); /* Can't handle it yet. */
1184 gcry_mpi_sub (value, value, session->product);
1186 else if (0 < sign) {
1188 gcry_mpi_add (value, value, session->product);
1193 gcry_mpi_release (session->product);
1194 session->product = NULL;
1196 // get representation as string
1198 && (0 != (rc = gcry_mpi_aprint (GCRYMPI_FMT_STD,
1202 LOG_GCRY (GNUNET_ERROR_TYPE_ERROR, "gcry_mpi_scan", rc);
1204 range = -1; // signal error with product-length = 0 and range = -1
1206 gcry_mpi_release (value);
1209 msg_length = sizeof (struct GNUNET_SCALARPRODUCT_client_response) +product_length;
1210 msg = GNUNET_malloc (msg_length);
1211 msg->key = session->session_id;
1212 msg->peer = session->peer;
1213 if (product_exported != NULL) {
1214 memcpy (&msg[1], product_exported, product_length);
1215 GNUNET_free (product_exported);
1217 msg->header.type = htons (GNUNET_MESSAGE_TYPE_SCALARPRODUCT_RESULT);
1218 msg->header.size = htons (msg_length);
1220 msg->product_length = htonl (product_length);
1222 session->msg = (struct GNUNET_MessageHeader *) msg;
1223 //transmit this message to our client
1224 session->client_transmit_handle =
1225 GNUNET_SERVER_notify_transmit_ready (session->client,
1227 GNUNET_TIME_UNIT_FOREVER_REL,
1230 if (NULL == session->client_transmit_handle) {
1231 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
1232 _ ("Could not send message to client (%p)!\n"),
1234 session->client = NULL;
1235 // callback was not called!
1237 session->msg = NULL;
1240 // gracefully sent message, just terminate session structure
1241 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
1242 _ ("Sent result to client (%p), this session (%s) has ended!\n"),
1244 GNUNET_h2s (&session->session_id));
1245 free_session_variables (session);
1250 * Executed by Alice, fills in a service-request message and sends it to the given peer
1252 * @param session the session associated with this request
1255 prepare_alices_computation_request (struct ServiceSession * session)
1257 struct GNUNET_SCALARPRODUCT_service_request * msg;
1259 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, _ ("Successfully created new channel to peer (%s)!\n"), GNUNET_i2s (&session->peer));
1261 msg = GNUNET_new (struct GNUNET_SCALARPRODUCT_service_request);
1262 msg->header.type = htons (GNUNET_MESSAGE_TYPE_SCALARPRODUCT_ALICE_CRYPTODATA);
1263 msg->total_element_count = htonl (session->used_elements_count);
1264 memcpy (&msg->session_id, &session->session_id, sizeof (struct GNUNET_HashCode));
1265 msg->header.size = htons (sizeof (struct GNUNET_SCALARPRODUCT_service_request));
1267 session->msg = (struct GNUNET_MessageHeader *) msg;
1268 GNUNET_log (GNUNET_ERROR_TYPE_INFO, _ ("Transmitting service request.\n"));
1270 //transmit via cadet messaging
1271 session->service_transmit_handle = GNUNET_CADET_notify_transmit_ready (session->channel, GNUNET_YES,
1272 GNUNET_TIME_UNIT_FOREVER_REL,
1273 sizeof (struct GNUNET_SCALARPRODUCT_service_request),
1276 if (!session->service_transmit_handle) {
1277 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, _ ("Could not send message to channel!\n"));
1279 session->msg = NULL;
1280 session->client_notification_task =
1281 GNUNET_SCHEDULER_add_now (&prepare_client_end_notification,
1289 * Send a multi part chunk of a service request from alice to bob.
1290 * This element only contains a part of the elements-vector (session->a[]),
1291 * mask and public key set have to be contained within the first message
1293 * This allows a ~32kbit key length while using 32000 elements or 62000 elements per request.
1295 * @param cls the associated service session
1298 prepare_alices_cyrptodata_message_multipart (void *cls)
1300 struct ServiceSession * session = cls;
1301 struct GNUNET_SCALARPRODUCT_multipart_message * msg;
1302 struct GNUNET_CRYPTO_PaillierCiphertext * payload;
1304 uint32_t msg_length;
1305 uint32_t todo_count;
1308 msg_length = sizeof (struct GNUNET_SCALARPRODUCT_multipart_message);
1309 todo_count = session->used_elements_count - session->transferred_element_count;
1311 if (todo_count > MULTIPART_ELEMENT_CAPACITY)
1312 // send the currently possible maximum chunk
1313 todo_count = MULTIPART_ELEMENT_CAPACITY;
1315 msg_length += todo_count * sizeof (struct GNUNET_CRYPTO_PaillierCiphertext);
1316 msg = GNUNET_malloc (msg_length);
1317 msg->header.type = htons (GNUNET_MESSAGE_TYPE_SCALARPRODUCT_ALICE_CRYPTODATA_MULTIPART);
1318 msg->header.size = htons (msg_length);
1319 msg->contained_element_count = htonl (todo_count);
1321 payload = (struct GNUNET_CRYPTO_PaillierCiphertext *) &msg[1];
1323 // now copy over the sorted element vector
1324 a = gcry_mpi_new (0);
1325 for (i = session->transferred_element_count; i < todo_count; i++) {
1326 gcry_mpi_add (a, session->sorted_elements[i], my_offset);
1327 GNUNET_CRYPTO_paillier_encrypt (&my_pubkey, a, 3, &payload[i - session->transferred_element_count]);
1329 gcry_mpi_release (a);
1330 session->transferred_element_count += todo_count;
1332 session->msg = (struct GNUNET_MessageHeader *) msg;
1333 GNUNET_log (GNUNET_ERROR_TYPE_INFO, _ ("Transmitting service request.\n"));
1335 //transmit via cadet messaging
1336 session->service_transmit_handle = GNUNET_CADET_notify_transmit_ready (session->channel, GNUNET_YES,
1337 GNUNET_TIME_UNIT_FOREVER_REL,
1341 if (!session->service_transmit_handle) {
1342 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, _ ("Could not send service-request multipart message to channel!\n"));
1344 session->msg = NULL;
1345 session->client_notification_task =
1346 GNUNET_SCHEDULER_add_now (&prepare_client_end_notification,
1354 * Our client has finished sending us its multipart message.
1356 * @param session the service session context
1359 client_request_complete_bob (struct ServiceSession * client_session)
1361 struct ServiceSession * session;
1363 //check if service queue contains a matching request
1364 session = find_matching_session (from_service_tail,
1365 &client_session->session_id,
1366 client_session->total, NULL);
1367 if (NULL != session) {
1368 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
1369 _ ("Got client-responder-session with key %s and a matching service-request-session set, processing.\n"),
1370 GNUNET_h2s (&client_session->session_id));
1372 session->response = client_session;
1373 session->intersected_elements = client_session->intersected_elements;
1374 client_session->intersected_elements = NULL;
1375 session->intersection_set = client_session->intersection_set;
1376 client_session->intersection_set = NULL;
1378 session->intersection_op = GNUNET_SET_prepare (&session->peer,
1379 &session->session_id,
1381 GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_WEAK, UINT16_MAX),
1382 GNUNET_SET_RESULT_REMOVED,
1383 cb_intersection_element_removed,
1386 GNUNET_SET_commit (session->intersection_op, session->intersection_set);
1389 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
1390 _ ("Got client-responder-session with key %s but NO matching service-request-session set, queuing element for later use.\n"),
1391 GNUNET_h2s (&client_session->session_id));
1392 // no matching session exists yet, store the response
1393 // for later processing by handle_service_request()
1399 * Our client has finished sending us its multipart message.
1401 * @param session the service session context
1404 client_request_complete_alice (struct ServiceSession * session)
1406 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
1407 _ ("Creating new channel for session with key %s.\n"),
1408 GNUNET_h2s (&session->session_id));
1409 session->channel = GNUNET_CADET_channel_create (my_cadet, session,
1411 GNUNET_APPLICATION_TYPE_SCALARPRODUCT,
1412 GNUNET_CADET_OPTION_RELIABLE);
1413 if (NULL == session->channel) {
1414 session->response->client_notification_task =
1415 GNUNET_SCHEDULER_add_now (&prepare_client_end_notification,
1419 session->intersection_listen = GNUNET_SET_listen (cfg,
1420 GNUNET_SET_OPERATION_INTERSECTION,
1421 &session->session_id,
1422 cb_intersection_request_alice,
1424 if (NULL == session->intersection_listen) {
1425 session->response->client_notification_task =
1426 GNUNET_SCHEDULER_add_now (&prepare_client_end_notification,
1430 prepare_alices_computation_request (session);
1435 handle_client_message_multipart (void *cls,
1436 struct GNUNET_SERVER_Client *client,
1437 const struct GNUNET_MessageHeader *message)
1439 const struct GNUNET_SCALARPRODUCT_computation_message_multipart * msg = (const struct GNUNET_SCALARPRODUCT_computation_message_multipart *) message;
1440 struct ServiceSession * session;
1441 uint32_t contained_count;
1442 struct GNUNET_SCALARPRODUCT_Element * elements;
1445 // only one concurrent session per client connection allowed, simplifies logics a lot...
1446 session = GNUNET_SERVER_client_get_user_context (client, struct ServiceSession);
1447 if (NULL == session) {
1448 GNUNET_SERVER_receive_done (client, GNUNET_OK);
1452 contained_count = ntohl (msg->element_count_contained);
1454 //sanity check: is the message as long as the message_count fields suggests?
1455 if ((ntohs (msg->header.size) != (sizeof (struct GNUNET_SCALARPRODUCT_computation_message_multipart) +contained_count * sizeof (struct GNUNET_SCALARPRODUCT_Element)))
1456 || (0 == contained_count) || (session->total < session->transferred_element_count + contained_count)) {
1457 GNUNET_break_op (0);
1458 GNUNET_SERVER_receive_done (client, GNUNET_OK);
1461 session->transferred_element_count += contained_count;
1463 elements = (struct GNUNET_SCALARPRODUCT_Element *) & msg[1];
1464 for (i = 0; i < contained_count; i++) {
1465 struct GNUNET_SET_Element set_elem;
1466 struct GNUNET_SCALARPRODUCT_Element * elem;
1468 if (0 == ntohl (elements[i].value))
1471 elem = GNUNET_new (struct GNUNET_SCALARPRODUCT_Element);
1472 memcpy (elem, &elements[i], sizeof (struct GNUNET_SCALARPRODUCT_Element));
1474 if (GNUNET_SYSERR == GNUNET_CONTAINER_multihashmap_put (session->intersected_elements,
1477 GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY)) {
1481 set_elem.data = &elements[i].key;
1482 set_elem.size = htons (sizeof (elements[i].key));
1483 set_elem.type = htons (0); /* do we REALLY need this? */
1484 GNUNET_SET_add_element (session->intersection_set, &set_elem, NULL, NULL);
1485 session->used_elements_count++;
1488 GNUNET_SERVER_receive_done (client, GNUNET_OK);
1490 if (session->total != session->transferred_element_count)
1494 if (ALICE == session->role)
1495 client_request_complete_alice (session);
1497 client_request_complete_bob (session);
1502 * Handler for a client request message.
1503 * Can either be type A or B
1504 * A: request-initiation to compute a scalar product with a peer
1505 * B: response role, keep the values + session and wait for a matching session or process a waiting request
1507 * @param cls closure
1508 * @param client identification of the client
1509 * @param message the actual message
1512 handle_client_message (void *cls,
1513 struct GNUNET_SERVER_Client *client,
1514 const struct GNUNET_MessageHeader *message)
1516 const struct GNUNET_SCALARPRODUCT_computation_message * msg = (const struct GNUNET_SCALARPRODUCT_computation_message *) message;
1517 struct ServiceSession * session;
1518 uint32_t contained_count;
1519 uint32_t total_count;
1521 struct GNUNET_SCALARPRODUCT_Element * elements;
1524 // only one concurrent session per client connection allowed, simplifies logics a lot...
1525 session = GNUNET_SERVER_client_get_user_context (client, struct ServiceSession);
1526 if (NULL != session) {
1527 GNUNET_SERVER_receive_done (client, GNUNET_OK);
1531 msg_type = ntohs (msg->header.type);
1532 total_count = ntohl (msg->element_count_total);
1533 contained_count = ntohl (msg->element_count_contained);
1535 if ((GNUNET_MESSAGE_TYPE_SCALARPRODUCT_CLIENT_TO_ALICE == msg_type)
1536 && (!memcmp (&msg->peer, &me, sizeof (struct GNUNET_PeerIdentity)))) {
1537 //session with ourself makes no sense!
1538 GNUNET_break_op (0);
1539 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
1543 //sanity check: is the message as long as the message_count fields suggests?
1544 if ((ntohs (msg->header.size) != (sizeof (struct GNUNET_SCALARPRODUCT_computation_message) +contained_count * sizeof (struct GNUNET_SCALARPRODUCT_Element)))
1545 || (0 == total_count)) {
1546 GNUNET_break_op (0);
1547 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
1551 // do we have a duplicate session here already?
1552 if (NULL != find_matching_session (from_client_tail,
1554 total_count, NULL)) {
1555 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
1556 _ ("Duplicate session information received, can not create new session with key `%s'\n"),
1557 GNUNET_h2s (&msg->session_key));
1558 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
1562 session = GNUNET_new (struct ServiceSession);
1563 session->client_notification_task = GNUNET_SCHEDULER_NO_TASK;
1564 session->client = client;
1565 session->total = total_count;
1566 session->transferred_element_count = contained_count;
1567 // get our transaction key
1568 memcpy (&session->session_id, &msg->session_key, sizeof (struct GNUNET_HashCode));
1570 elements = (struct GNUNET_SCALARPRODUCT_Element *) & msg[1];
1571 session->intersected_elements = GNUNET_CONTAINER_multihashmap_create (session->total, GNUNET_NO);
1572 session->intersection_set = GNUNET_SET_create (cfg, GNUNET_SET_OPERATION_INTERSECTION);
1573 for (i = 0; i < contained_count; i++) {
1574 struct GNUNET_SET_Element set_elem;
1575 struct GNUNET_SCALARPRODUCT_Element * elem;
1577 if (0 == ntohl (elements[i].value))
1580 elem = GNUNET_new (struct GNUNET_SCALARPRODUCT_Element);
1581 memcpy (elem, &elements[i], sizeof (struct GNUNET_SCALARPRODUCT_Element));
1583 if (GNUNET_SYSERR == GNUNET_CONTAINER_multihashmap_put (session->intersected_elements,
1586 GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY)) {
1590 set_elem.data = &elements[i].key;
1591 set_elem.size = htons (sizeof (elements[i].key));
1592 set_elem.type = htons (0); /* do we REALLY need this? */
1593 GNUNET_SET_add_element (session->intersection_set, &set_elem, NULL, NULL);
1594 session->used_elements_count++;
1597 if (GNUNET_MESSAGE_TYPE_SCALARPRODUCT_CLIENT_TO_ALICE == msg_type) {
1598 session->role = ALICE;
1599 memcpy (&session->peer, &msg->peer, sizeof (struct GNUNET_PeerIdentity));
1602 session->role = BOB;
1605 GNUNET_CONTAINER_DLL_insert (from_client_head, from_client_tail, session);
1606 GNUNET_SERVER_client_set_user_context (client, session);
1607 GNUNET_SERVER_receive_done (client, GNUNET_YES);
1609 if (session->total != session->transferred_element_count)
1613 if (ALICE == session->role)
1614 client_request_complete_alice (session);
1616 client_request_complete_bob (session);
1621 * Function called for inbound channels.
1623 * @param cls closure
1624 * @param channel new handle to the channel
1625 * @param initiator peer that started the channel
1626 * @param port unused
1627 * @param options unused
1629 * @return session associated with the channel
1632 cb_channel_incoming (void *cls,
1633 struct GNUNET_CADET_Channel *channel,
1634 const struct GNUNET_PeerIdentity *initiator,
1635 uint32_t port, enum GNUNET_CADET_ChannelOption options)
1637 struct ServiceSession * c = GNUNET_new (struct ServiceSession);
1639 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1640 _ ("New incoming channel from peer %s.\n"),
1641 GNUNET_i2s (initiator));
1643 c->peer = *initiator;
1644 c->channel = channel;
1651 * Function called whenever a channel is destroyed. Should clean up
1652 * any associated state.
1654 * It must NOT call GNUNET_CADET_channel_destroy on the channel.
1656 * @param cls closure (set from GNUNET_CADET_connect)
1657 * @param channel connection to the other end (henceforth invalid)
1658 * @param channel_ctx place where local state associated
1659 * with the channel is stored
1662 cb_channel_destruction (void *cls,
1663 const struct GNUNET_CADET_Channel *channel,
1666 struct ServiceSession * session = channel_ctx;
1667 struct ServiceSession * client_session;
1668 struct ServiceSession * curr;
1670 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1671 _ ("Peer disconnected, terminating session %s with peer (%s)\n"),
1672 GNUNET_h2s (&session->session_id),
1673 GNUNET_i2s (&session->peer));
1674 if (ALICE == session->role) {
1675 // as we have only one peer connected in each session, just remove the session
1677 if ((0/*//TODO: only for complete session*/) && (!do_shutdown)) {
1678 session->channel = NULL;
1679 // if this happened before we received the answer, we must terminate the session
1680 session->client_notification_task =
1681 GNUNET_SCHEDULER_add_now (&prepare_client_end_notification,
1685 else { //(BOB == session->role) service session
1686 // remove the session, unless it has already been dequeued, but somehow still active
1687 // this could bug without the IF in case the queue is empty and the service session was the only one know to the service
1688 // scenario: disconnect before alice can send her message to bob.
1689 for (curr = from_service_head; NULL != curr; curr = curr->next)
1690 if (curr == session) {
1691 GNUNET_CONTAINER_DLL_remove (from_service_head, from_service_tail, curr);
1694 // there is a client waiting for this service session, terminate it, too!
1695 // i assume the tupel of key and element count is unique. if it was not the rest of the code would not work either.
1696 client_session = find_matching_session (from_client_tail,
1697 &session->session_id,
1698 session->total, NULL);
1699 free_session_variables (session);
1700 GNUNET_free (session);
1702 // the client has to check if it was waiting for a result
1703 // or if it was a responder, no point in adding more statefulness
1704 if (client_session && (!do_shutdown)) {
1705 client_session->client_notification_task =
1706 GNUNET_SCHEDULER_add_now (&prepare_client_end_notification,
1714 * Compute our scalar product, done by Alice
1716 * @param session - the session associated with this computation
1717 * @return product as MPI, never NULL
1720 compute_scalar_product (struct ServiceSession * session)
1729 gcry_mpi_t r[session->used_elements_count];
1730 gcry_mpi_t r_prime[session->used_elements_count];
1735 count = session->used_elements_count;
1736 // due to the introduced static offset S, we now also have to remove this
1737 // from the E(a_pi)(+)E(-b_pi-r_pi) and E(a_qi)(+)E(-r_qi) twice each,
1738 // the result is E((S + a_pi) + (S -b_pi-r_pi)) and E(S + a_qi + S - r_qi)
1739 for (i = 0; i < count; i++) {
1740 GNUNET_CRYPTO_paillier_decrypt (&my_privkey, &my_pubkey,
1741 &session->r[i], r[i]);
1742 gcry_mpi_sub (r[i], r[i], my_offset);
1743 gcry_mpi_sub (r[i], r[i], my_offset);
1744 GNUNET_CRYPTO_paillier_decrypt (&my_privkey, &my_pubkey,
1745 &session->r_prime[i], r_prime[i]);
1746 gcry_mpi_sub (r_prime[i], r_prime[i], my_offset);
1747 gcry_mpi_sub (r_prime[i], r_prime[i], my_offset);
1750 // calculate t = sum(ai)
1751 t = compute_square_sum (session->sorted_elements, count);
1754 u = gcry_mpi_new (0);
1755 tmp = compute_square_sum (r, count);
1756 gcry_mpi_sub (u, u, tmp);
1757 gcry_mpi_release (tmp);
1760 u_prime = gcry_mpi_new (0);
1761 tmp = compute_square_sum (r_prime, count);
1762 gcry_mpi_sub (u_prime, u_prime, tmp);
1764 GNUNET_assert (p = gcry_mpi_new (0));
1765 GNUNET_assert (p_prime = gcry_mpi_new (0));
1766 GNUNET_assert (s = gcry_mpi_new (0));
1767 GNUNET_assert (s_prime = gcry_mpi_new (0));
1770 GNUNET_CRYPTO_paillier_decrypt (&my_privkey, &my_pubkey,
1772 GNUNET_CRYPTO_paillier_decrypt (&my_privkey, &my_pubkey,
1773 session->s_prime, s_prime);
1776 gcry_mpi_add (p, s, t);
1777 gcry_mpi_add (p, p, u);
1780 gcry_mpi_add (p_prime, s_prime, t);
1781 gcry_mpi_add (p_prime, p_prime, u_prime);
1783 gcry_mpi_release (t);
1784 gcry_mpi_release (u);
1785 gcry_mpi_release (u_prime);
1786 gcry_mpi_release (s);
1787 gcry_mpi_release (s_prime);
1790 gcry_mpi_sub (p, p, p_prime);
1791 gcry_mpi_release (p_prime);
1792 tmp = gcry_mpi_set_ui (tmp, 2);
1793 gcry_mpi_div (p, NULL, p, tmp, 0);
1795 gcry_mpi_release (tmp);
1796 for (i = 0; i < count; i++) {
1797 gcry_mpi_release (session->sorted_elements[i]);
1798 gcry_mpi_release (r[i]);
1799 gcry_mpi_release (r_prime[i]);
1801 GNUNET_free (session->a_head);
1802 session->a_head = NULL;
1803 GNUNET_free (session->s);
1805 GNUNET_free (session->s_prime);
1806 session->s_prime = NULL;
1807 GNUNET_free (session->r);
1809 GNUNET_free (session->r_prime);
1810 session->r_prime = NULL;
1817 * Handle a multipart-chunk of a request from another service to calculate a scalarproduct with us.
1819 * @param cls closure (set from #GNUNET_CADET_connect)
1820 * @param channel connection to the other end
1821 * @param channel_ctx place to store local state associated with the channel
1822 * @param message the actual message
1823 * @return #GNUNET_OK to keep the connection open,
1824 * #GNUNET_SYSERR to close it (signal serious error)
1827 handle_alices_cyrptodata_message_multipart (void *cls,
1828 struct GNUNET_CADET_Channel * channel,
1830 const struct GNUNET_MessageHeader * message)
1832 struct ServiceSession * session;
1833 const struct GNUNET_SCALARPRODUCT_multipart_message * msg = (const struct GNUNET_SCALARPRODUCT_multipart_message *) message;
1834 struct GNUNET_CRYPTO_PaillierCiphertext *payload;
1835 uint32_t contained_elements;
1836 uint32_t msg_length;
1838 // are we in the correct state?
1839 session = (struct ServiceSession *) * channel_ctx;
1841 if ((NULL == session->e_a) || //or we did not expect this message yet
1842 (session->used_elements_count == session->transferred_element_count)) { //we are not expecting multipart messages
1845 // shorter than minimum?
1846 if (ntohs (msg->header.size) <= sizeof (struct GNUNET_SCALARPRODUCT_multipart_message)) {
1849 contained_elements = ntohl (msg->contained_element_count);
1850 msg_length = sizeof (struct GNUNET_SCALARPRODUCT_multipart_message)
1851 +contained_elements * sizeof (struct GNUNET_CRYPTO_PaillierCiphertext);
1853 if ((ntohs (msg->header.size) != msg_length)
1854 || (session->used_elements_count < contained_elements + session->transferred_element_count)
1855 || (0 == contained_elements)) {
1858 payload = (struct GNUNET_CRYPTO_PaillierCiphertext *) &msg[1];
1859 // Convert each vector element to MPI_value
1860 memcpy (&session->e_a[session->transferred_element_count], payload,
1861 sizeof (struct GNUNET_CRYPTO_PaillierCiphertext) * contained_elements);
1863 session->transferred_element_count += contained_elements;
1865 if (contained_elements == session->used_elements_count) {
1866 // single part finished
1867 if (NULL == session->intersection_op)
1868 // intersection has already finished, so we can proceed
1869 compute_service_response (session);
1874 session->channel = NULL;
1875 // and notify our client-session that we could not complete the session
1876 free_session_variables (session);
1877 if (NULL != session->client){
1879 session->client_notification_task =
1880 GNUNET_SCHEDULER_add_now (&prepare_client_end_notification,
1885 if (NULL != session->response)
1886 session->response->client_notification_task =
1887 GNUNET_SCHEDULER_add_now (&prepare_client_end_notification,
1889 GNUNET_CONTAINER_DLL_remove (from_service_head, from_service_tail, session);
1890 GNUNET_free(session);
1892 return GNUNET_SYSERR;
1897 * Handle a request from another service to calculate a scalarproduct with us.
1899 * @param cls closure (set from #GNUNET_CADET_connect)
1900 * @param channel connection to the other end
1901 * @param channel_ctx place to store local state associated with the channel
1902 * @param message the actual message
1903 * @return #GNUNET_OK to keep the connection open,
1904 * #GNUNET_SYSERR to close it (signal serious error)
1907 handle_alices_cyrptodata_message (void *cls,
1908 struct GNUNET_CADET_Channel * channel,
1910 const struct GNUNET_MessageHeader * message)
1912 struct ServiceSession * session;
1913 const struct GNUNET_SCALARPRODUCT_alices_cryptodata_message * msg = (const struct GNUNET_SCALARPRODUCT_alices_cryptodata_message *) message;
1914 struct GNUNET_CRYPTO_PaillierCiphertext *payload;
1915 uint32_t contained_elements = 0;
1916 uint32_t msg_length;
1918 session = (struct ServiceSession *) * channel_ctx;
1920 if ((BOB != session->role)
1921 //we are expecting multipart messages instead
1922 || (NULL != session->e_a)
1923 //or we did not expect this message yet
1924 || //intersection OP has not yet finished
1925 !((NULL != session->intersection_op)
1926 //intersection OP done
1927 || (session->response->sorted_elements)
1932 // shorter than minimum?
1933 if (ntohs (msg->header.size) <= sizeof (struct GNUNET_SCALARPRODUCT_multipart_message)) {
1937 contained_elements = ntohl (msg->contained_element_count);
1938 msg_length = sizeof (struct GNUNET_SCALARPRODUCT_alices_cryptodata_message)
1939 +contained_elements * sizeof (struct GNUNET_CRYPTO_PaillierCiphertext);
1941 //sanity check: is the message as long as the message_count fields suggests?
1942 if ((ntohs (msg->header.size) != msg_length) ||
1943 (session->used_elements_count < session->transferred_element_count + contained_elements) ||
1944 (0 == contained_elements)) {
1948 session->transferred_element_count = contained_elements;
1949 payload = (struct GNUNET_CRYPTO_PaillierCiphertext*) &msg[1];
1951 session->e_a = GNUNET_malloc (sizeof (struct GNUNET_CRYPTO_PaillierCiphertext) * session->used_elements_count);
1952 memcpy (&session->e_a[0], payload, contained_elements * sizeof (struct GNUNET_CRYPTO_PaillierCiphertext));
1953 if (contained_elements == session->used_elements_count) {
1954 // single part finished
1955 if (NULL == session->intersection_op)
1956 // intersection has already finished, so we can proceed
1957 compute_service_response (session);
1961 GNUNET_break_op (0);
1962 session->channel = NULL;
1963 // and notify our client-session that we could not complete the session
1964 free_session_variables (session);
1965 if (NULL != session->client){
1967 session->client_notification_task =
1968 GNUNET_SCHEDULER_add_now (&prepare_client_end_notification,
1973 if (NULL != session->response)
1974 session->response->client_notification_task =
1975 GNUNET_SCHEDULER_add_now (&prepare_client_end_notification,
1977 GNUNET_CONTAINER_DLL_remove (from_service_head, from_service_tail, session);
1978 GNUNET_free(session);
1980 return GNUNET_SYSERR;
1985 * Handle a request from another service to calculate a scalarproduct with us.
1987 * @param cls closure (set from #GNUNET_CADET_connect)
1988 * @param channel connection to the other end
1989 * @param channel_ctx place to store local state associated with the channel
1990 * @param message the actual message
1991 * @return #GNUNET_OK to keep the connection open,
1992 * #GNUNET_SYSERR to close it (signal serious error)
1995 handle_alices_computation_request (void *cls,
1996 struct GNUNET_CADET_Channel * channel,
1998 const struct GNUNET_MessageHeader * message)
2000 struct ServiceSession * session;
2001 struct ServiceSession * client_session;
2002 const struct GNUNET_SCALARPRODUCT_service_request * msg = (const struct GNUNET_SCALARPRODUCT_service_request *) message;
2003 uint32_t total_elements;
2005 session = (struct ServiceSession *) * channel_ctx;
2006 if (session->total != 0) {
2007 // must be a fresh session
2010 // Check if message was sent by me, which would be bad!
2011 if (!memcmp (&session->peer, &me, sizeof (struct GNUNET_PeerIdentity))) {
2012 GNUNET_free (session);
2014 return GNUNET_SYSERR;
2016 // shorter than expected?
2017 if (ntohs (msg->header.size) != sizeof (struct GNUNET_SCALARPRODUCT_service_request)) {
2018 GNUNET_free (session);
2019 GNUNET_break_op (0);
2020 return GNUNET_SYSERR;
2022 total_elements = ntohl (msg->total_element_count);
2024 //sanity check: is the message as long as the message_count fields suggests?
2025 if (1 > total_elements) {
2026 GNUNET_free (session);
2027 GNUNET_break_op (0);
2028 return GNUNET_SYSERR;
2030 if (find_matching_session (from_service_tail,
2034 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
2035 _ ("Got message with duplicate session key (`%s'), ignoring service request.\n"),
2036 (const char *) &(msg->session_id));
2037 GNUNET_free (session);
2038 return GNUNET_SYSERR;
2041 session->total = total_elements;
2042 session->channel = channel;
2045 memcpy (&session->session_id, &msg->session_id, sizeof (struct GNUNET_HashCode));
2048 memcpy (&session->remote_pubkey, &msg->public_key, sizeof (struct GNUNET_CRYPTO_PaillierPublicKey));
2050 //check if service queue contains a matching request
2051 client_session = find_matching_session (from_client_tail,
2052 &session->session_id,
2053 session->total, NULL);
2055 GNUNET_CONTAINER_DLL_insert (from_service_head, from_service_tail, session);
2057 if ((NULL != client_session)
2058 && (client_session->transferred_element_count == client_session->total)) {
2060 GNUNET_log (GNUNET_ERROR_TYPE_INFO, _ ("Got session with key %s and a matching element set, processing.\n"), GNUNET_h2s (&session->session_id));
2062 session->response = client_session;
2063 session->intersected_elements = client_session->intersected_elements;
2064 client_session->intersected_elements = NULL;
2065 session->intersection_set = client_session->intersection_set;
2066 client_session->intersection_set = NULL;
2068 session->intersection_op = GNUNET_SET_prepare (&session->peer,
2069 &session->session_id,
2071 GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_WEAK, UINT16_MAX),
2072 GNUNET_SET_RESULT_REMOVED,
2073 cb_intersection_element_removed,
2076 GNUNET_SET_commit (session->intersection_op, session->intersection_set);
2079 GNUNET_log (GNUNET_ERROR_TYPE_INFO, _ ("Got session with key %s without a matching element set, queueing.\n"), GNUNET_h2s (&session->session_id));
2084 GNUNET_break_op (0);
2085 session->channel = NULL;
2086 // and notify our client-session that we could not complete the session
2087 free_session_variables (session);
2088 if (NULL != session->client){
2090 session->client_notification_task =
2091 GNUNET_SCHEDULER_add_now (&prepare_client_end_notification,
2096 if (NULL != session->response)
2097 session->response->client_notification_task =
2098 GNUNET_SCHEDULER_add_now (&prepare_client_end_notification,
2100 GNUNET_CONTAINER_DLL_remove (from_service_head, from_service_tail, session);
2101 GNUNET_free(session);
2103 return GNUNET_SYSERR;
2108 * Handle a multipart chunk of a response we got from another service we wanted to calculate a scalarproduct with.
2110 * @param cls closure (set from #GNUNET_CADET_connect)
2111 * @param channel connection to the other end
2112 * @param channel_ctx place to store local state associated with the channel
2113 * @param message the actual message
2114 * @return #GNUNET_OK to keep the connection open,
2115 * #GNUNET_SYSERR to close it (signal serious error)
2118 handle_bobs_cryptodata_multipart (void *cls,
2119 struct GNUNET_CADET_Channel * channel,
2121 const struct GNUNET_MessageHeader * message)
2123 struct ServiceSession * session;
2124 const struct GNUNET_SCALARPRODUCT_multipart_message * msg = (const struct GNUNET_SCALARPRODUCT_multipart_message *) message;
2125 struct GNUNET_CRYPTO_PaillierCiphertext * payload;
2127 uint32_t contained = 0;
2129 size_t required_size;
2131 GNUNET_assert (NULL != message);
2132 // are we in the correct state?
2133 session = (struct ServiceSession *) * channel_ctx;
2134 if ((ALICE != session->role) || (NULL == session->sorted_elements)) {
2137 msg_size = ntohs (msg->header.size);
2138 required_size = sizeof (struct GNUNET_SCALARPRODUCT_multipart_message)
2139 + 2 * sizeof (struct GNUNET_CRYPTO_PaillierCiphertext);
2140 // shorter than minimum?
2141 if (required_size > msg_size) {
2144 contained = ntohl (msg->contained_element_count);
2145 required_size = sizeof (struct GNUNET_SCALARPRODUCT_multipart_message)
2146 + 2 * contained * sizeof (struct GNUNET_CRYPTO_PaillierCiphertext);
2147 //sanity check: is the message as long as the message_count fields suggests?
2148 if ((required_size != msg_size) || (session->used_elements_count < session->transferred_element_count + contained)) {
2151 payload = (struct GNUNET_CRYPTO_PaillierCiphertext *) &msg[1];
2152 // Convert each k[][perm] to its MPI_value
2153 for (i = 0; i < contained; i++) {
2154 memcpy (&session->r[session->transferred_element_count + i], &payload[2 * i], sizeof (struct GNUNET_CRYPTO_PaillierCiphertext));
2155 memcpy (&session->r_prime[session->transferred_element_count + i], &payload[2 * i], sizeof (struct GNUNET_CRYPTO_PaillierCiphertext));
2157 session->transferred_element_count += contained;
2158 if (session->transferred_element_count != session->used_elements_count)
2160 session->product = compute_scalar_product (session); //never NULL
2163 GNUNET_break_op (NULL != session->product);
2164 session->channel = NULL;
2165 // send message with product to client
2166 if (NULL != session->client){
2168 session->client_notification_task =
2169 GNUNET_SCHEDULER_add_now (&prepare_client_response,
2174 if (NULL != session->response)
2175 session->response->client_notification_task =
2176 GNUNET_SCHEDULER_add_now (&prepare_client_end_notification,
2178 GNUNET_CONTAINER_DLL_remove (from_service_head, from_service_tail, session);
2179 free_session_variables (session);
2180 GNUNET_free(session);
2182 // the channel has done its job, terminate our connection and the channel
2183 // the peer will be notified that the channel was destroyed via channel_destruction_handler
2184 // just close the connection, as recommended by Christian
2185 return GNUNET_SYSERR;
2190 * Handle a response we got from another service we wanted to calculate a scalarproduct with.
2192 * @param cls closure (set from #GNUNET_CADET_connect)
2193 * @param channel connection to the other end
2194 * @param channel_ctx place to store local state associated with the channel
2195 * @param message the actual message
2196 * @return #GNUNET_OK to keep the connection open,
2197 * #GNUNET_SYSERR to close it (we are done)
2200 handle_bobs_cryptodata_message (void *cls,
2201 struct GNUNET_CADET_Channel * channel,
2203 const struct GNUNET_MessageHeader * message)
2205 struct ServiceSession * session;
2206 const struct GNUNET_SCALARPRODUCT_service_response * msg = (const struct GNUNET_SCALARPRODUCT_service_response *) message;
2207 struct GNUNET_CRYPTO_PaillierCiphertext * payload;
2209 uint32_t contained = 0;
2211 size_t required_size;
2213 GNUNET_assert (NULL != message);
2214 session = (struct ServiceSession *) * channel_ctx;
2215 // are we in the correct state?
2216 if (0 /*//TODO: correct state*/) {
2219 //we need at least a full message without elements attached
2220 msg_size = ntohs (msg->header.size);
2221 required_size = sizeof (struct GNUNET_SCALARPRODUCT_service_response) + 2 * sizeof (struct GNUNET_CRYPTO_PaillierCiphertext);
2223 if (required_size > msg_size) {
2226 contained = ntohl (msg->contained_element_count);
2227 required_size = sizeof (struct GNUNET_SCALARPRODUCT_service_response)
2228 + 2 * contained * sizeof (struct GNUNET_CRYPTO_PaillierCiphertext)
2229 + 2 * sizeof (struct GNUNET_CRYPTO_PaillierCiphertext);
2230 //sanity check: is the message as long as the message_count fields suggests?
2231 if ((msg_size != required_size) || (session->used_elements_count < contained)) {
2234 session->transferred_element_count = contained;
2236 payload = (struct GNUNET_CRYPTO_PaillierCiphertext *) &msg[1];
2238 session->s = GNUNET_malloc (sizeof (struct GNUNET_CRYPTO_PaillierCiphertext));
2239 session->s_prime = GNUNET_malloc (sizeof (struct GNUNET_CRYPTO_PaillierCiphertext));
2240 memcpy (session->s, &payload[0], sizeof (struct GNUNET_CRYPTO_PaillierCiphertext));
2241 memcpy (session->s_prime, &payload[1], sizeof (struct GNUNET_CRYPTO_PaillierCiphertext));
2243 session->r = GNUNET_malloc (sizeof (struct GNUNET_CRYPTO_PaillierCiphertext) * session->used_elements_count);
2244 session->r_prime = GNUNET_malloc (sizeof (struct GNUNET_CRYPTO_PaillierCiphertext) * session->used_elements_count);
2246 // Convert each k[][perm] to its MPI_value
2247 for (i = 0; i < contained; i++) {
2248 memcpy (&session->r[i], &payload[2 + 2 * i], sizeof (struct GNUNET_CRYPTO_PaillierCiphertext));
2249 memcpy (&session->r_prime[i], &payload[3 + 2 * i], sizeof (struct GNUNET_CRYPTO_PaillierCiphertext));
2251 if (session->transferred_element_count != session->used_elements_count)
2252 return GNUNET_OK; //wait for the other multipart chunks
2253 session->product = compute_scalar_product (session); //never NULL
2256 GNUNET_break_op (NULL != session->product);
2257 session->channel = NULL;
2258 // send message with product to client
2259 if (NULL != session->client){
2261 session->client_notification_task =
2262 GNUNET_SCHEDULER_add_now (&prepare_client_response,
2267 if (NULL != session->response)
2268 session->response->client_notification_task =
2269 GNUNET_SCHEDULER_add_now (&prepare_client_end_notification,
2271 GNUNET_CONTAINER_DLL_remove (from_service_head, from_service_tail, session);
2272 free_session_variables (session);
2273 GNUNET_free(session);
2275 // the channel has done its job, terminate our connection and the channel
2276 // the peer will be notified that the channel was destroyed via channel_destruction_handler
2277 // just close the connection, as recommended by Christian
2278 return GNUNET_SYSERR;
2283 * Task run during shutdown.
2289 shutdown_task (void *cls,
2290 const struct GNUNET_SCHEDULER_TaskContext *tc)
2292 struct ServiceSession * session;
2293 GNUNET_log (GNUNET_ERROR_TYPE_INFO, _ ("Shutting down, initiating cleanup.\n"));
2295 do_shutdown = GNUNET_YES;
2297 // terminate all owned open channels.
2298 for (session = from_client_head; NULL != session; session = session->next) {
2299 if ((0/*//TODO: not finalized*/) && (NULL != session->channel)) {
2300 GNUNET_CADET_channel_destroy (session->channel);
2301 session->channel = NULL;
2303 if (GNUNET_SCHEDULER_NO_TASK != session->client_notification_task) {
2304 GNUNET_SCHEDULER_cancel (session->client_notification_task);
2305 session->client_notification_task = GNUNET_SCHEDULER_NO_TASK;
2307 if (NULL != session->client) {
2308 GNUNET_SERVER_client_disconnect (session->client);
2309 session->client = NULL;
2312 for (session = from_service_head; NULL != session; session = session->next)
2313 if (NULL != session->channel) {
2314 GNUNET_CADET_channel_destroy (session->channel);
2315 session->channel = NULL;
2319 GNUNET_CADET_disconnect (my_cadet);
2326 * Initialization of the program and message handlers
2328 * @param cls closure
2329 * @param server the initialized server
2330 * @param c configuration to use
2334 struct GNUNET_SERVER_Handle *server,
2335 const struct GNUNET_CONFIGURATION_Handle *c)
2337 static const struct GNUNET_SERVER_MessageHandler server_handlers[] = {
2338 {&handle_client_message, NULL, GNUNET_MESSAGE_TYPE_SCALARPRODUCT_CLIENT_TO_ALICE, 0},
2339 {&handle_client_message, NULL, GNUNET_MESSAGE_TYPE_SCALARPRODUCT_CLIENT_TO_BOB, 0},
2340 {&handle_client_message_multipart, NULL, GNUNET_MESSAGE_TYPE_SCALARPRODUCT_CLIENT_MUTLIPART, 0},
2343 static const struct GNUNET_CADET_MessageHandler cadet_handlers[] = {
2344 { &handle_alices_computation_request, GNUNET_MESSAGE_TYPE_SCALARPRODUCT_ALICE_CRYPTODATA, 0},
2345 { &handle_alices_cyrptodata_message, GNUNET_MESSAGE_TYPE_SCALARPRODUCT_ALICE_CRYPTODATA, 0},
2346 { &handle_alices_cyrptodata_message_multipart, GNUNET_MESSAGE_TYPE_SCALARPRODUCT_ALICE_CRYPTODATA_MULTIPART, 0},
2347 { &handle_bobs_cryptodata_message, GNUNET_MESSAGE_TYPE_SCALARPRODUCT_BOB_CRYPTODATA, 0},
2348 { &handle_bobs_cryptodata_multipart, GNUNET_MESSAGE_TYPE_SCALARPRODUCT_BOB_CRYPTODATA_MULTIPART, 0},
2351 static const uint32_t ports[] = {
2352 GNUNET_APPLICATION_TYPE_SCALARPRODUCT,
2355 //generate private/public key set
2356 GNUNET_CRYPTO_paillier_create (&my_pubkey, &my_privkey);
2358 // offset has to be sufficiently small to allow computation of:
2359 // m1+m2 mod n == (S + a) + (S + b) mod n,
2360 // if we have more complex operations, this factor needs to be lowered
2361 my_offset = gcry_mpi_new (GNUNET_CRYPTO_PAILLIER_BITS / 3);
2362 gcry_mpi_set_bit (my_offset, GNUNET_CRYPTO_PAILLIER_BITS / 3);
2364 // register server callbacks and disconnect handler
2365 GNUNET_SERVER_add_handlers (server, server_handlers);
2366 GNUNET_SERVER_disconnect_notify (server,
2367 &handle_client_disconnect,
2369 GNUNET_break (GNUNET_OK ==
2370 GNUNET_CRYPTO_get_peer_identity (c,
2372 my_cadet = GNUNET_CADET_connect (c, NULL,
2373 &cb_channel_incoming,
2374 &cb_channel_destruction,
2375 cadet_handlers, ports);
2377 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, _ ("Connect to CADET failed\n"));
2378 GNUNET_SCHEDULER_shutdown ();
2381 GNUNET_log (GNUNET_ERROR_TYPE_INFO, _ ("CADET initialized\n"));
2382 GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_FOREVER_REL,
2389 * The main function for the scalarproduct service.
2391 * @param argc number of arguments from the command line
2392 * @param argv command line arguments
2393 * @return 0 ok, 1 on error
2396 main (int argc, char *const *argv)
2398 return (GNUNET_OK ==
2399 GNUNET_SERVICE_run (argc, argv,
2401 GNUNET_SERVICE_OPTION_NONE,
2402 &run, NULL)) ? 0 : 1;
2405 /* end of gnunet-service-scalarproduct.c */