2 This file is part of GNUnet.
3 (C) 2013, 2014 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
25 * @author Christian Grothoff
30 #include "gnunet_util_lib.h"
31 #include "gnunet_core_service.h"
32 #include "gnunet_cadet_service.h"
33 #include "gnunet_applications.h"
34 #include "gnunet_protocols.h"
35 #include "gnunet_scalarproduct_service.h"
36 #include "gnunet_set_service.h"
37 #include "scalarproduct.h"
39 #define LOG(kind,...) GNUNET_log_from (kind, "scalarproduct", __VA_ARGS__)
43 * Maximum count of elements we can put into a multipart message
45 #define MULTIPART_ELEMENT_CAPACITY ((GNUNET_SERVER_MAX_MESSAGE_SIZE - 1 - sizeof (struct MultipartMessage)) / sizeof (struct GNUNET_CRYPTO_PaillierCiphertext))
48 GNUNET_NETWORK_STRUCT_BEGIN
51 * Message type passed from requesting service Alice to responding
52 * service Bob to initiate a request and make Bob participate in our
55 struct ServiceRequestMessage
58 * GNUNET message header
60 struct GNUNET_MessageHeader header;
63 * the transaction/session key used to identify a session
65 struct GNUNET_HashCode session_id;
70 struct GNUNET_CRYPTO_PaillierPublicKey public_key;
78 struct AliceCryptodataMessage
81 * GNUNET message header
83 struct GNUNET_MessageHeader header;
86 * how many elements we appended to this message
88 uint32_t contained_element_count GNUNET_PACKED;
91 * struct GNUNET_CRYPTO_PaillierCiphertext[contained_element_count]
97 * Multipart Message type passed between to supply additional elements
100 struct MultipartMessage
103 * GNUNET message header
105 struct GNUNET_MessageHeader header;
108 * how many elements we supply within this message
110 uint32_t contained_element_count GNUNET_PACKED;
112 // struct GNUNET_CRYPTO_PaillierCiphertext[multipart_element_count]
117 * Message type passed from responding service Bob to responding service Alice
118 * to complete a request and allow Alice to compute the result
120 struct ServiceResponseMessage
123 * GNUNET message header
125 struct GNUNET_MessageHeader header;
128 * how many elements the session input had
130 uint32_t total_element_count GNUNET_PACKED;
133 * how many elements were included after the mask was applied
134 * including all multipart msgs.
136 uint32_t used_element_count GNUNET_PACKED;
139 * how many elements this individual message delivers
141 uint32_t contained_element_count GNUNET_PACKED;
144 * the transaction/session key used to identify a session
146 struct GNUNET_HashCode key;
149 * followed by s | s' | k[i][perm]
153 GNUNET_NETWORK_STRUCT_END
157 * role a peer in a session can assume
166 * DLL for sorting elements
171 * Sorted Values are kept in a DLL
173 struct SortedValue * next;
176 * Sorted Values are kept in a DLL
178 struct SortedValue * prev;
181 * The element's id+integer-value
183 struct GNUNET_SCALARPRODUCT_Element * elem;
186 * the element's value converted to MPI
193 * A scalarproduct session which tracks:
195 * a request form the client to our final response.
197 * a request from a service to us(service).
199 struct ServiceSession
202 * Is this session active (#GNUNET_YES), Concluded (#GNUNET_NO), or had an error (#GNUNET_SYSERR)
207 * the role this peer has
212 * session information is kept in a DLL
214 struct ServiceSession *next;
217 * session information is kept in a DLL
219 struct ServiceSession *prev;
222 * (hopefully) unique transaction ID
224 struct GNUNET_HashCode session_id;
227 * Alice or Bob's peerID
229 struct GNUNET_PeerIdentity peer;
232 * the client this request is related to
234 struct GNUNET_SERVER_Client *client;
237 * The message to send
239 struct GNUNET_MessageHeader *msg;
242 * how many elements we were supplied with from the client
247 * all non-0-value'd elements transmitted to us
249 struct GNUNET_CONTAINER_MultiHashMap *intersected_elements;
252 * how many elements actually are used for the scalar product
254 uint32_t used_element_count;
257 * already transferred elements (sent/received) for multipart messages, less or equal than @e used_element_count for
259 uint32_t transferred_element_count;
262 * Set of elements for which will conduction an intersection.
263 * the resulting elements are then used for computing the scalar product.
265 struct GNUNET_SET_Handle *intersection_set;
268 * Set of elements for which will conduction an intersection.
269 * the resulting elements are then used for computing the scalar product.
271 struct GNUNET_SET_OperationHandle *intersection_op;
274 * Handle to Alice's Intersection operation listening for Bob
276 struct GNUNET_SET_ListenHandle *intersection_listen;
279 * Public key of the remote service, only used by Bob
281 struct GNUNET_CRYPTO_PaillierPublicKey *remote_pubkey;
284 * DLL for sorting elements after intersection
286 struct SortedValue *a_head;
291 struct SortedValue *a_tail;
296 gcry_mpi_t *sorted_elements;
299 * E(ai)(Bob) after applying the mask
301 struct GNUNET_CRYPTO_PaillierCiphertext *e_a;
304 * Bob's permutation p of R
306 struct GNUNET_CRYPTO_PaillierCiphertext *r;
309 * Bob's permutation q of R
311 struct GNUNET_CRYPTO_PaillierCiphertext *r_prime;
316 struct GNUNET_CRYPTO_PaillierCiphertext *s;
321 struct GNUNET_CRYPTO_PaillierCiphertext *s_prime;
324 * Bob's matching response session from the client
326 struct ServiceSession *response;
329 * The computed scalar
334 * My transmit handle for the current message to a Alice/Bob
336 struct GNUNET_CADET_TransmitHandle *service_transmit_handle;
339 * My transmit handle for the current message to the client
341 struct GNUNET_SERVER_TransmitHandle *client_transmit_handle;
344 * channel-handle associated with our cadet handle
346 struct GNUNET_CADET_Channel *channel;
349 * Handle to a task that sends a msg to the our client
351 GNUNET_SCHEDULER_TaskIdentifier client_notification_task;
356 * Send a multi part chunk of a service request from alice to bob.
357 * This element only contains a part of the elements-vector (session->a[]),
358 * mask and public key set have to be contained within the first message
360 * This allows a ~32kbit key length while using 32000 elements or 62000 elements per request.
362 * @param cls the associated service session
365 prepare_alices_cyrptodata_message_multipart (void *cls);
369 * Send a multi part chunk of a service response from Bob to Alice.
370 * This element only contains the two permutations of R, R'.
372 * @param cls the associated service session
375 prepare_bobs_cryptodata_message_multipart (void *cls);
380 * GNUnet configuration handle
382 static const struct GNUNET_CONFIGURATION_Handle * cfg;
385 * Handle to the core service (NULL until we've connected to it).
387 static struct GNUNET_CADET_Handle *my_cadet;
390 * The identity of this host.
392 static struct GNUNET_PeerIdentity me;
395 * Service's own public key
397 static struct GNUNET_CRYPTO_PaillierPublicKey my_pubkey;
400 * Service's own private key
402 static struct GNUNET_CRYPTO_PaillierPrivateKey my_privkey;
405 * Service's offset for values that could possibly be negative but are plaintext for encryption.
407 static gcry_mpi_t my_offset;
410 * Head of our double linked list for client-requests sent to us.
411 * for all of these elements we calculate a scalar product with a remote peer
412 * split between service->service and client->service for simplicity
414 static struct ServiceSession *from_client_head;
417 * Tail of our double linked list for client-requests sent to us.
418 * for all of these elements we calculate a scalar product with a remote peer
419 * split between service->service and client->service for simplicity
421 static struct ServiceSession *from_client_tail;
424 * Head of our double linked list for service-requests sent to us.
425 * for all of these elements we help the requesting service in calculating a scalar product
426 * split between service->service and client->service for simplicity
428 static struct ServiceSession *from_service_head;
431 * Tail of our double linked list for service-requests sent to us.
432 * for all of these elements we help the requesting service in calculating a scalar product
433 * split between service->service and client->service for simplicity
435 static struct ServiceSession *from_service_tail;
438 * Certain events (callbacks for server & cadet operations) must not be queued after shutdown.
440 static int do_shutdown;
444 * computes the square sum over a vector of a given length.
446 * @param vector the vector to encrypt
447 * @param length the length of the vector
448 * @return an MPI value containing the calculated sum, never NULL
451 compute_square_sum (gcry_mpi_t *vector,
458 GNUNET_assert (sum = gcry_mpi_new (0));
459 GNUNET_assert (elem = gcry_mpi_new (0));
461 // calculare E(sum (ai ^ 2), publickey)
462 for (i = 0; i < length; i++) {
463 gcry_mpi_mul (elem, vector[i], vector[i]);
464 gcry_mpi_add (sum, sum, elem);
466 gcry_mpi_release (elem);
473 * Safely frees ALL memory areas referenced by a session.
475 * @param session - the session to free elements from
478 free_session_variables (struct ServiceSession *s)
480 while (NULL != s->a_head)
482 struct SortedValue * e = s->a_head;
484 GNUNET_free (e->elem);
485 gcry_mpi_release (e->val);
486 GNUNET_CONTAINER_DLL_remove (s->a_head, s->a_tail, e);
491 GNUNET_free (s->e_a);
494 if (s->remote_pubkey)
496 GNUNET_free(s->remote_pubkey);
497 s->remote_pubkey=NULL;
499 if (s->sorted_elements)
501 GNUNET_free (s->sorted_elements);
502 s->sorted_elements = NULL;
504 if (s->intersected_elements)
506 GNUNET_CONTAINER_multihashmap_destroy (s->intersected_elements);
507 //elements are freed independently in session->a_head/tail
508 s->intersected_elements = NULL;
510 if (s->intersection_listen)
512 GNUNET_SET_listen_cancel (s->intersection_listen);
513 s->intersection_listen = NULL;
515 if (s->intersection_op)
517 GNUNET_SET_operation_cancel (s->intersection_op);
518 s->intersection_op = NULL;
520 if (s->intersection_set)
522 GNUNET_SET_destroy (s->intersection_set);
523 s->intersection_set = NULL;
527 GNUNET_free (s->msg);
537 GNUNET_free (s->r_prime);
547 GNUNET_free (s->s_prime);
552 gcry_mpi_release (s->product);
559 * Primitive callback for copying over a message, as they
560 * usually are too complex to be handled in the callback itself.
561 * clears a session-callback, if a session was handed over and the transmit handle was stored
563 * @param cls the session containing the message object
564 * @param size the size of the buffer we got
565 * @param buf the buffer to copy the message to
566 * @return 0 if we couldn't copy, else the size copied over
569 cb_transfer_message (void *cls,
573 struct ServiceSession * s = cls;
577 if (ntohs (s->msg->size) != size)
583 type = ntohs (s->msg->type);
584 memcpy (buf, s->msg, size);
585 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
586 "Sent a message of type %hu.\n",
588 GNUNET_free (s->msg);
593 case GNUNET_MESSAGE_TYPE_SCALARPRODUCT_RESULT:
594 s->client_transmit_handle = NULL;
595 free_session_variables (s);
598 case GNUNET_MESSAGE_TYPE_SCALARPRODUCT_SESSION_INITIALIZATION:
599 s->service_transmit_handle = NULL;
602 case GNUNET_MESSAGE_TYPE_SCALARPRODUCT_ALICE_CRYPTODATA:
603 case GNUNET_MESSAGE_TYPE_SCALARPRODUCT_ALICE_CRYPTODATA_MULTIPART:
604 s->service_transmit_handle = NULL;
605 if (s->used_element_count != s->transferred_element_count)
606 prepare_alices_cyrptodata_message_multipart (s);
611 case GNUNET_MESSAGE_TYPE_SCALARPRODUCT_BOB_CRYPTODATA:
612 case GNUNET_MESSAGE_TYPE_SCALARPRODUCT_BOB_CRYPTODATA_MULTIPART:
613 s->service_transmit_handle = NULL;
614 if (s->used_element_count != s->transferred_element_count)
615 prepare_bobs_cryptodata_message_multipart (s);
627 * Finds a not terminated client/service session in the
628 * given DLL based on session key, element count and state.
630 * @param tail - the tail of the DLL
631 * @param key - the key we want to search for
632 * @param peerid - a pointer to the peer ID of the associated peer, NULL to ignore
633 * @return a pointer to a matching session, or NULL
635 static struct ServiceSession *
636 find_matching_session (struct ServiceSession * tail,
637 const struct GNUNET_HashCode * key,
638 const struct GNUNET_PeerIdentity * peerid)
640 struct ServiceSession * s;
642 for (s = tail; NULL != s; s = s->prev)
644 // if the key matches, and the element_count is same
645 if (0 == memcmp (&s->session_id, key, sizeof (struct GNUNET_HashCode)))
647 // if peerid is NULL OR same as the peer Id in the queued request
649 || (0 == memcmp (&s->peer, peerid, sizeof (struct GNUNET_PeerIdentity))))
650 // matches and is not an already terminated session
660 * A client disconnected.
662 * Remove the associated session(s), release data structures
663 * and cancel pending outgoing transmissions to the client.
664 * if the session has not yet completed, we also cancel Alice's request to Bob.
666 * @param cls closure, NULL
667 * @param client identification of the client
670 cb_client_disconnect (void *cls,
671 struct GNUNET_SERVER_Client *client)
673 struct ServiceSession *s;
677 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
678 _ ("Client %p disconnected from us.\n"), client);
679 s = GNUNET_SERVER_client_get_user_context (client, struct ServiceSession);
682 GNUNET_CONTAINER_DLL_remove (from_client_head,
685 if (NULL != s->service_transmit_handle)
687 GNUNET_CADET_notify_transmit_ready_cancel (s->service_transmit_handle);
688 s->service_transmit_handle = NULL;
690 if (NULL != s->channel)
692 GNUNET_CADET_channel_destroy (s->channel);
695 if (GNUNET_SCHEDULER_NO_TASK != s->client_notification_task)
697 GNUNET_SCHEDULER_cancel (s->client_notification_task);
698 s->client_notification_task = GNUNET_SCHEDULER_NO_TASK;
700 if (NULL != s->client_transmit_handle)
702 GNUNET_SERVER_notify_transmit_ready_cancel (s->client_transmit_handle);
703 s->client_transmit_handle = NULL;
705 free_session_variables (s);
711 * Notify the client that the session has succeeded or failed completely.
712 * This message gets sent to
713 * * alice's client if bob disconnected or to
714 * * bob's client if the operation completed or alice disconnected
716 * @param cls the associated client session
717 * @param tc the task context handed to us by the scheduler, unused
720 prepare_client_end_notification (void * cls,
721 const struct GNUNET_SCHEDULER_TaskContext * tc)
723 struct ServiceSession * s = cls;
724 struct ClientResponseMessage *msg;
726 s->client_notification_task = GNUNET_SCHEDULER_NO_TASK;
728 msg = GNUNET_new (struct ClientResponseMessage);
729 msg->header.size = htons (sizeof (struct ClientResponseMessage));
730 msg->header.type = htons (GNUNET_MESSAGE_TYPE_SCALARPRODUCT_RESULT);
731 // signal error if not signalized, positive result-range field but zero length.
732 msg->product_length = htonl (0);
733 msg->status = htonl(s->active);
734 s->msg = &msg->header;
736 //transmit this message to our client
737 s->client_transmit_handle
738 = GNUNET_SERVER_notify_transmit_ready (s->client,
739 sizeof (struct ClientResponseMessage),
740 GNUNET_TIME_UNIT_FOREVER_REL,
741 &cb_transfer_message,
744 // if we could not even queue our request, something is wrong
745 if (NULL == s->client_transmit_handle)
747 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
748 _("Could not send message to client (%p)!\n"),
750 GNUNET_SERVER_client_disconnect (s->client);
751 free_session_variables(s);
752 GNUNET_CONTAINER_DLL_remove (from_client_head,
758 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
759 _("Sending session-end notification to client (%p) for session %s\n"),
761 GNUNET_h2s (&s->session_id));
766 * Executed by Alice, fills in a service-request message and sends it to the given peer
768 * @param cls the session associated with this request
771 prepare_alices_cyrptodata_message (void *cls)
773 struct ServiceSession * s = cls;
774 struct AliceCryptodataMessage * msg;
775 struct GNUNET_CRYPTO_PaillierCiphertext * payload;
780 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
781 _ ("Successfully created new channel to peer (%s)!\n"),
782 GNUNET_i2s (&s->peer));
784 msg_length = sizeof (struct AliceCryptodataMessage)
785 +s->used_element_count * sizeof (struct GNUNET_CRYPTO_PaillierCiphertext);
787 if (GNUNET_SERVER_MAX_MESSAGE_SIZE > msg_length) {
788 s->transferred_element_count = s->used_element_count;
792 //create a multipart msg, first we calculate a new msg size for the head msg
793 s->transferred_element_count = (GNUNET_SERVER_MAX_MESSAGE_SIZE - 1 - sizeof (struct AliceCryptodataMessage))
794 / sizeof (struct GNUNET_CRYPTO_PaillierCiphertext);
795 msg_length = sizeof (struct AliceCryptodataMessage)
796 +s->transferred_element_count * sizeof (struct GNUNET_CRYPTO_PaillierCiphertext);
799 msg = GNUNET_malloc (msg_length);
800 msg->header.size = htons (msg_length);
801 msg->header.type = htons (GNUNET_MESSAGE_TYPE_SCALARPRODUCT_ALICE_CRYPTODATA);
802 msg->contained_element_count = htonl (s->transferred_element_count);
804 // fill in the payload
805 payload = (struct GNUNET_CRYPTO_PaillierCiphertext *) &msg[1];
807 // now copy over the sorted element vector
808 a = gcry_mpi_new (0);
809 for (i = 0; i < s->transferred_element_count; i++)
811 gcry_mpi_add (a, s->sorted_elements[i], my_offset);
812 GNUNET_CRYPTO_paillier_encrypt (&my_pubkey, a, 3, &payload[i]);
814 gcry_mpi_release (a);
816 s->msg = (struct GNUNET_MessageHeader *) msg;
817 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
818 _("Transmitting service request.\n"));
820 //transmit via cadet messaging
821 s->service_transmit_handle = GNUNET_CADET_notify_transmit_ready (s->channel,
823 GNUNET_TIME_UNIT_FOREVER_REL,
825 &cb_transfer_message,
827 if (NULL == s->service_transmit_handle)
829 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
830 _("Could not send message to channel!\n"));
833 s->active = GNUNET_SYSERR;
834 s->client_notification_task =
835 GNUNET_SCHEDULER_add_now (&prepare_client_end_notification,
843 * Send a multipart chunk of a service response from bob to alice.
844 * This element only contains the two permutations of R, R'.
846 * @param cls the associated service session
849 prepare_bobs_cryptodata_message_multipart (void *cls)
851 struct ServiceSession * s = cls;
852 struct GNUNET_CRYPTO_PaillierCiphertext * payload;
853 struct MultipartMessage * msg;
859 msg_length = sizeof (struct MultipartMessage);
860 todo_count = s->used_element_count - s->transferred_element_count;
862 if (todo_count > MULTIPART_ELEMENT_CAPACITY / 2)
863 // send the currently possible maximum chunk, we always transfer both permutations
864 todo_count = MULTIPART_ELEMENT_CAPACITY / 2;
866 msg_length += todo_count * sizeof (struct GNUNET_CRYPTO_PaillierCiphertext) * 2;
867 msg = GNUNET_malloc (msg_length);
868 msg->header.type = htons (GNUNET_MESSAGE_TYPE_SCALARPRODUCT_ALICE_CRYPTODATA_MULTIPART);
869 msg->header.size = htons (msg_length);
870 msg->contained_element_count = htonl (todo_count);
872 payload = (struct GNUNET_CRYPTO_PaillierCiphertext *) &msg[1];
873 for (i = s->transferred_element_count, j = 0; i < s->transferred_element_count + todo_count; i++)
875 //r[i][p] and r[i][q]
876 memcpy (&payload[j++], &s->r[i], sizeof (struct GNUNET_CRYPTO_PaillierCiphertext));
877 memcpy (&payload[j++], &s->r_prime[i], sizeof (struct GNUNET_CRYPTO_PaillierCiphertext));
879 s->transferred_element_count += todo_count;
880 s->msg = (struct GNUNET_MessageHeader *) msg;
881 s->service_transmit_handle =
882 GNUNET_CADET_notify_transmit_ready (s->channel,
884 GNUNET_TIME_UNIT_FOREVER_REL,
886 &cb_transfer_message,
888 if (NULL == s->service_transmit_handle)
890 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
891 _("Could not send service-response message via cadet!)\n"));
895 GNUNET_CADET_channel_destroy(s->channel);
896 s->response->active = GNUNET_SYSERR;
898 GNUNET_CONTAINER_DLL_remove (from_service_head, from_service_tail, s);
900 s->response->client_notification_task =
901 GNUNET_SCHEDULER_add_now (&prepare_client_end_notification,
903 free_session_variables(s);
907 if (s->transferred_element_count == s->used_element_count)
910 s->active = GNUNET_NO;
911 GNUNET_free (s->r_prime);
921 * generates the response message to be sent to alice after computing
922 * the values (1), (2), S and S'
923 * (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)})$
924 * (2)[]: $E_A(a_{pi'(i)}) times E_A(- r_{pi'(i)}) &= E_A(a_{pi'(i)} - r_{pi'(i)})$
925 * S: $S := E_A(sum (r_i + b_i)^2)$
926 * S': $S' := E_A(sum r_i^2)$
928 * @param session the associated requesting session with alice
931 prepare_bobs_cryptodata_message (void *cls,
932 const struct GNUNET_SCHEDULER_TaskContext
935 struct ServiceSession * s = cls;
936 struct ServiceResponseMessage * msg;
937 uint32_t msg_length = 0;
938 struct GNUNET_CRYPTO_PaillierCiphertext * payload;
941 msg_length = sizeof (struct ServiceResponseMessage)
942 + 2 * sizeof (struct GNUNET_CRYPTO_PaillierCiphertext); // s, stick
944 if (GNUNET_SERVER_MAX_MESSAGE_SIZE >
945 msg_length + 2 * s->used_element_count * sizeof (struct GNUNET_CRYPTO_PaillierCiphertext))
947 msg_length += 2 * s->used_element_count * sizeof (struct GNUNET_CRYPTO_PaillierCiphertext);
948 s->transferred_element_count = s->used_element_count;
951 s->transferred_element_count = (GNUNET_SERVER_MAX_MESSAGE_SIZE - 1 - msg_length) /
952 (sizeof (struct GNUNET_CRYPTO_PaillierCiphertext) * 2);
954 msg = GNUNET_malloc (msg_length);
955 msg->header.type = htons (GNUNET_MESSAGE_TYPE_SCALARPRODUCT_BOB_CRYPTODATA);
956 msg->header.size = htons (msg_length);
957 msg->total_element_count = htonl (s->total);
958 msg->used_element_count = htonl (s->used_element_count);
959 msg->contained_element_count = htonl (s->transferred_element_count);
960 memcpy (&msg->key, &s->session_id, sizeof (struct GNUNET_HashCode));
962 payload = (struct GNUNET_CRYPTO_PaillierCiphertext *) &msg[1];
963 memcpy (&payload[0], s->s, sizeof (struct GNUNET_CRYPTO_PaillierCiphertext));
964 memcpy (&payload[1], s->s_prime, sizeof (struct GNUNET_CRYPTO_PaillierCiphertext));
965 GNUNET_free (s->s_prime);
970 payload = &payload[2];
972 for (i = 0; i < s->transferred_element_count; i++)
974 //k[i][p] and k[i][q]
975 memcpy (&payload[i * 2], &s->r[i], sizeof (struct GNUNET_CRYPTO_PaillierCiphertext));
976 memcpy (&payload[i * 2 + 1], &s->r_prime[i], sizeof (struct GNUNET_CRYPTO_PaillierCiphertext));
979 s->msg = (struct GNUNET_MessageHeader *) msg;
980 s->service_transmit_handle =
981 GNUNET_CADET_notify_transmit_ready (s->channel,
983 GNUNET_TIME_UNIT_FOREVER_REL,
985 &cb_transfer_message,
987 if (NULL == s->service_transmit_handle)
989 //disconnect our client
990 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
991 _("Could not send service-response message via cadet!)\n"));
995 GNUNET_CONTAINER_DLL_remove (from_service_head, from_service_tail, s);
996 GNUNET_CADET_channel_destroy(s->channel);
997 s->response->active = GNUNET_SYSERR;
999 s->response->client_notification_task =
1000 GNUNET_SCHEDULER_add_now (&prepare_client_end_notification,
1002 free_session_variables(s);
1006 if (s->transferred_element_count != s->used_element_count)
1013 s->active = GNUNET_NO;
1016 GNUNET_free (s->r_prime);
1024 * compute the values
1025 * (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)})$
1026 * (2)[]: $E_A(a_{pi'(i)}) otimes E_A(- r_{pi'(i)}) &= E_A(a_{pi'(i)} - r_{pi'(i)})$
1027 * S: $S := E_A(sum (r_i + b_i)^2)$
1028 * S': $S' := E_A(sum r_i^2)$
1030 * @param request the requesting session + bob's requesting peer
1033 compute_service_response (struct ServiceSession *session)
1039 gcry_mpi_t * rand = NULL;
1042 struct GNUNET_CRYPTO_PaillierCiphertext * a;
1043 struct GNUNET_CRYPTO_PaillierCiphertext * r;
1044 struct GNUNET_CRYPTO_PaillierCiphertext * r_prime;
1045 struct GNUNET_CRYPTO_PaillierCiphertext * s;
1046 struct GNUNET_CRYPTO_PaillierCiphertext * s_prime;
1048 count = session->used_element_count;
1050 b = session->sorted_elements;
1051 q = GNUNET_CRYPTO_random_permute (GNUNET_CRYPTO_QUALITY_WEAK, count);
1052 p = GNUNET_CRYPTO_random_permute (GNUNET_CRYPTO_QUALITY_WEAK, count);
1054 for (i = 0; i < count; i++)
1055 GNUNET_assert (NULL != (rand[i] = gcry_mpi_new (0)));
1056 r = GNUNET_malloc (sizeof (struct GNUNET_CRYPTO_PaillierCiphertext) * count);
1057 r_prime = GNUNET_malloc (sizeof (struct GNUNET_CRYPTO_PaillierCiphertext) * count);
1058 s = GNUNET_malloc (sizeof (struct GNUNET_CRYPTO_PaillierCiphertext));
1059 s_prime = GNUNET_malloc (sizeof (struct GNUNET_CRYPTO_PaillierCiphertext));
1061 for (i = 0; i < count; i++)
1065 svalue = (int32_t) GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_WEAK, UINT32_MAX);
1067 // long to gcry_mpi_t
1069 gcry_mpi_sub_ui (rand[i],
1073 rand[i] = gcry_mpi_set_ui (rand[i], svalue);
1076 tmp = gcry_mpi_new (0);
1077 // encrypt the element
1078 // for the sake of readability I decided to have dedicated permutation
1079 // vectors, which get rid of all the lookups in p/q.
1080 // however, ap/aq are not absolutely necessary but are just abstraction
1081 // Calculate Kp = E(S + a_pi) (+) E(S - r_pi - b_pi)
1082 for (i = 0; i < count; i++) {
1083 // E(S - r_pi - b_pi)
1084 gcry_mpi_sub (tmp, my_offset, rand[p[i]]);
1085 gcry_mpi_sub (tmp, tmp, b[p[i]]);
1086 GNUNET_CRYPTO_paillier_encrypt (session->remote_pubkey,
1091 // E(S - r_pi - b_pi) * E(S + a_pi) == E(2*S + a - r - b)
1092 GNUNET_CRYPTO_paillier_hom_add (session->remote_pubkey,
1098 // Calculate Kq = E(S + a_qi) (+) E(S - r_qi)
1099 for (i = 0; i < count; i++) {
1101 gcry_mpi_sub (tmp, my_offset, rand[q[i]]);
1102 GNUNET_assert (2 == GNUNET_CRYPTO_paillier_encrypt (session->remote_pubkey,
1107 // E(S - r_qi) * E(S + a_qi) == E(2*S + a_qi - r_qi)
1108 GNUNET_assert (1 == GNUNET_CRYPTO_paillier_hom_add (session->remote_pubkey,
1114 // Calculate S' = E(SUM( r_i^2 ))
1115 tmp = compute_square_sum (rand, count);
1116 GNUNET_CRYPTO_paillier_encrypt (session->remote_pubkey,
1121 // Calculate S = E(SUM( (r_i + b_i)^2 ))
1122 for (i = 0; i < count; i++)
1123 gcry_mpi_add (rand[i], rand[i], b[i]);
1124 tmp = compute_square_sum (rand, count);
1125 GNUNET_CRYPTO_paillier_encrypt (session->remote_pubkey,
1131 session->r_prime = r_prime;
1133 session->s_prime = s_prime;
1135 // release rand, b and a
1136 for (i = 0; i < count; i++) {
1137 gcry_mpi_release (rand[i]);
1138 gcry_mpi_release (b[i]);
1140 gcry_mpi_release (tmp);
1141 GNUNET_free (session->e_a);
1142 session->e_a = NULL;
1148 // copy the r[], r_prime[], S and Stick into a new message, prepare_service_response frees these
1149 GNUNET_SCHEDULER_add_now (&prepare_bobs_cryptodata_message, s);
1154 * Iterator over all hash map entries in session->intersected_elements.
1156 * @param cls closure
1157 * @param key current key code
1158 * @param value value in the hash map
1159 * @return #GNUNET_YES if we should continue to
1161 * #GNUNET_NO if not.
1164 cb_insert_element_sorted (void *cls,
1165 const struct GNUNET_HashCode *key,
1168 struct ServiceSession * s = (struct ServiceSession*) cls;
1169 struct SortedValue * e = GNUNET_new (struct SortedValue);
1170 struct SortedValue * o = s->a_head;
1174 e->val = gcry_mpi_new (0);
1175 val = (int64_t) GNUNET_ntohll (e->elem->value);
1177 gcry_mpi_sub_ui (e->val, e->val, -val);
1179 gcry_mpi_add_ui (e->val, e->val, val);
1181 // insert as first element with the lowest key
1182 if (NULL == s->a_head
1183 || (0 <= GNUNET_CRYPTO_hash_cmp (&s->a_head->elem->key, &e->elem->key)))
1185 GNUNET_CONTAINER_DLL_insert (s->a_head, s->a_tail, e);
1188 else if (0 > GNUNET_CRYPTO_hash_cmp (&s->a_tail->elem->key, &e->elem->key))
1190 // insert as last element with the highest key
1191 GNUNET_CONTAINER_DLL_insert_tail (s->a_head, s->a_tail, e);
1194 // insert before the first higher/equal element
1197 if (0 <= GNUNET_CRYPTO_hash_cmp (&o->elem->key, &e->elem->key))
1199 GNUNET_CONTAINER_DLL_insert_before (s->a_head, s->a_tail, o, e);
1211 * Callback for set operation results. Called for each element
1212 * in the result set.
1214 * @param cls closure
1215 * @param element a result element, only valid if status is #GNUNET_SET_STATUS_OK
1216 * @param status see `enum GNUNET_SET_Status`
1219 cb_intersection_element_removed (void *cls,
1220 const struct GNUNET_SET_Element *element,
1221 enum GNUNET_SET_Status status)
1223 struct ServiceSession * s = cls;
1224 struct GNUNET_SCALARPRODUCT_Element * se;
1229 case GNUNET_SET_STATUS_OK:
1230 //this element has been removed from the set
1231 se = GNUNET_CONTAINER_multihashmap_get (s->intersected_elements,
1234 GNUNET_CONTAINER_multihashmap_remove (s->intersected_elements,
1237 LOG (GNUNET_ERROR_TYPE_DEBUG, "%s: removed element with key %s value %d\n", s->role == ALICE ? "ALICE" : "BOB", GNUNET_h2s(&se->key), se->value);
1240 case GNUNET_SET_STATUS_DONE:
1241 s->intersection_op = NULL;
1242 s->intersection_set = NULL;
1244 s->used_element_count = GNUNET_CONTAINER_multihashmap_iterate (s->intersected_elements,
1245 &cb_insert_element_sorted,
1247 LOG (GNUNET_ERROR_TYPE_DEBUG, "%s: Finished intersection, %d items remain\n", s->role == ALICE ? "ALICE" : "BOB", s->used_element_count);
1248 if (2 > s->used_element_count)
1250 // failed! do not leak information about our single remaining element!
1251 // continue after the loop
1255 s->sorted_elements = GNUNET_malloc (s->used_element_count * sizeof (gcry_mpi_t));
1256 for (i = 0; NULL != s->a_head; i++)
1258 struct SortedValue* a = s->a_head;
1259 GNUNET_assert (i < s->used_element_count);
1261 s->sorted_elements[i] = a->val;
1262 GNUNET_CONTAINER_DLL_remove (s->a_head, s->a_tail, a);
1263 GNUNET_free (a->elem);
1265 GNUNET_assert (i == s->used_element_count);
1267 if (ALICE == s->role) {
1268 prepare_alices_cyrptodata_message (s);
1271 else if (s->used_element_count == s->transferred_element_count)
1273 compute_service_response (s);
1278 LOG (GNUNET_ERROR_TYPE_DEBUG, "%s: OOOPS %d", s->role == ALICE ? "ALICE" : "BOB", status);
1279 if (NULL != s->intersection_listen)
1281 GNUNET_SET_listen_cancel (s->intersection_listen);
1282 s->intersection_listen = NULL;
1285 // the op failed and has already been invalidated by the set service
1289 s->intersection_op = NULL;
1290 s->intersection_set = NULL;
1292 //failed if we go here
1293 GNUNET_break_op (0);
1295 // and notify our client-session that we could not complete the session
1296 if (ALICE == s->role) {
1297 s->active = GNUNET_SYSERR;
1298 s->client_notification_task =
1299 GNUNET_SCHEDULER_add_now (&prepare_client_end_notification,
1304 GNUNET_CONTAINER_DLL_remove (from_service_head,
1307 free_session_variables (s);
1308 s->response->active = GNUNET_SYSERR;
1309 s->response->client_notification_task =
1310 GNUNET_SCHEDULER_add_now (&prepare_client_end_notification,
1318 * Called when another peer wants to do a set operation with the
1319 * local peer. If a listen error occurs, the @a request is NULL.
1321 * @param cls closure
1322 * @param other_peer the other peer
1323 * @param context_msg message with application specific information from
1325 * @param request request from the other peer (never NULL), use GNUNET_SET_accept()
1326 * to accept it, otherwise the request will be refused
1327 * Note that we can't just return value from the listen callback,
1328 * as it is also necessary to specify the set we want to do the
1329 * operation with, whith sometimes can be derived from the context
1330 * message. It's necessary to specify the timeout.
1333 cb_intersection_request_alice (void *cls,
1334 const struct GNUNET_PeerIdentity *other_peer,
1335 const struct GNUNET_MessageHeader *context_msg,
1336 struct GNUNET_SET_Request *request)
1338 struct ServiceSession * s = cls;
1340 s->intersection_op = GNUNET_SET_accept (request,
1341 GNUNET_SET_RESULT_REMOVED,
1342 cb_intersection_element_removed,
1344 if (NULL == s->intersection_op)
1346 s->active = GNUNET_SYSERR;
1347 s->client_notification_task =
1348 GNUNET_SCHEDULER_add_now (&prepare_client_end_notification,
1352 if (GNUNET_OK != GNUNET_SET_commit (s->intersection_op, s->intersection_set))
1354 s->active = GNUNET_SYSERR;
1355 s->client_notification_task =
1356 GNUNET_SCHEDULER_add_now (&prepare_client_end_notification,
1360 s->intersection_set = NULL;
1361 s->intersection_listen = NULL;
1366 * prepare the response we will send to alice or bobs' clients.
1367 * in Bobs case the product will be NULL.
1369 * @param cls the session associated with our client.
1370 * @param tc the task context handed to us by the scheduler, unused
1373 prepare_client_response (void *cls,
1374 const struct GNUNET_SCHEDULER_TaskContext *tc)
1376 struct ServiceSession * s = cls;
1377 struct ClientResponseMessage *msg;
1378 unsigned char * product_exported = NULL;
1379 size_t product_length = 0;
1380 uint32_t msg_length = 0;
1385 s->client_notification_task = GNUNET_SCHEDULER_NO_TASK;
1389 gcry_mpi_t value = gcry_mpi_new (0);
1391 sign = gcry_mpi_cmp_ui (s->product, 0);
1392 // libgcrypt can not handle a print of a negative number
1393 // if (a->sign) return gcry_error (GPG_ERR_INTERNAL); /* Can't handle it yet. */
1396 gcry_mpi_sub (value, value, s->product);
1401 gcry_mpi_add (value, value, s->product);
1406 gcry_mpi_release (s->product);
1409 // get representation as string
1411 && (0 != (rc = gcry_mpi_aprint (GCRYMPI_FMT_STD,
1416 LOG_GCRY (GNUNET_ERROR_TYPE_ERROR, "gcry_mpi_scan", rc);
1418 range = -1; // signal error with product-length = 0 and range = -1
1420 gcry_mpi_release (value);
1423 msg_length = sizeof (struct ClientResponseMessage) + product_length;
1424 msg = GNUNET_malloc (msg_length);
1425 if (product_exported != NULL)
1427 memcpy (&msg[1], product_exported, product_length);
1428 GNUNET_free (product_exported);
1430 msg->header.type = htons (GNUNET_MESSAGE_TYPE_SCALARPRODUCT_RESULT);
1431 msg->header.size = htons (msg_length);
1433 msg->product_length = htonl (product_length);
1434 s->msg = (struct GNUNET_MessageHeader *) msg;
1435 s->client_transmit_handle =
1436 GNUNET_SERVER_notify_transmit_ready (s->client,
1438 GNUNET_TIME_UNIT_FOREVER_REL,
1439 &cb_transfer_message,
1441 GNUNET_break (NULL != s->client_transmit_handle);
1442 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
1443 _ ("Sent result to client (%p), this session (%s) has ended!\n"),
1445 GNUNET_h2s (&s->session_id));
1450 * Executed by Alice, fills in a service-request message and sends it to the given peer
1452 * @param session the session associated with this request
1455 prepare_alices_computation_request (struct ServiceSession * s)
1457 struct ServiceRequestMessage * msg;
1459 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1460 _("Successfully created new channel to peer (%s)!\n"),
1461 GNUNET_i2s (&s->peer));
1463 msg = GNUNET_new (struct ServiceRequestMessage);
1464 msg->header.type = htons (GNUNET_MESSAGE_TYPE_SCALARPRODUCT_SESSION_INITIALIZATION);
1465 memcpy (&msg->session_id, &s->session_id, sizeof (struct GNUNET_HashCode));
1466 msg->header.size = htons (sizeof (struct ServiceRequestMessage));
1468 s->msg = (struct GNUNET_MessageHeader *) msg;
1469 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
1470 _("Transmitting service request.\n"));
1472 //transmit via cadet messaging
1473 s->service_transmit_handle
1474 = GNUNET_CADET_notify_transmit_ready (s->channel, GNUNET_YES,
1475 GNUNET_TIME_UNIT_FOREVER_REL,
1476 sizeof (struct ServiceRequestMessage),
1477 &cb_transfer_message,
1479 if (!s->service_transmit_handle)
1481 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1482 _("Could not send message to channel!\n"));
1485 s->active = GNUNET_SYSERR;
1486 s->client_notification_task =
1487 GNUNET_SCHEDULER_add_now (&prepare_client_end_notification,
1495 * Send a multi part chunk of a service request from alice to bob.
1496 * This element only contains a part of the elements-vector (session->a[]),
1497 * mask and public key set have to be contained within the first message
1499 * This allows a ~32kbit key length while using 32000 elements or 62000 elements per request.
1501 * @param cls the associated service session
1504 prepare_alices_cyrptodata_message_multipart (void *cls)
1506 struct ServiceSession * s = cls;
1507 struct MultipartMessage * msg;
1508 struct GNUNET_CRYPTO_PaillierCiphertext * payload;
1510 uint32_t msg_length;
1511 uint32_t todo_count;
1514 msg_length = sizeof (struct MultipartMessage);
1515 todo_count = s->used_element_count - s->transferred_element_count;
1517 if (todo_count > MULTIPART_ELEMENT_CAPACITY)
1518 // send the currently possible maximum chunk
1519 todo_count = MULTIPART_ELEMENT_CAPACITY;
1521 msg_length += todo_count * sizeof (struct GNUNET_CRYPTO_PaillierCiphertext);
1522 msg = GNUNET_malloc (msg_length);
1523 msg->header.type = htons (GNUNET_MESSAGE_TYPE_SCALARPRODUCT_ALICE_CRYPTODATA_MULTIPART);
1524 msg->header.size = htons (msg_length);
1525 msg->contained_element_count = htonl (todo_count);
1527 payload = (struct GNUNET_CRYPTO_PaillierCiphertext *) &msg[1];
1529 // now copy over the sorted element vector
1530 a = gcry_mpi_new (0);
1531 for (i = s->transferred_element_count; i < todo_count; i++)
1533 gcry_mpi_add (a, s->sorted_elements[i], my_offset);
1534 GNUNET_CRYPTO_paillier_encrypt (&my_pubkey, a, 3, &payload[i - s->transferred_element_count]);
1536 gcry_mpi_release (a);
1537 s->transferred_element_count += todo_count;
1539 s->msg = (struct GNUNET_MessageHeader *) msg;
1540 GNUNET_log (GNUNET_ERROR_TYPE_INFO, _ ("Transmitting service request.\n"));
1542 //transmit via cadet messaging
1543 s->service_transmit_handle = GNUNET_CADET_notify_transmit_ready (s->channel, GNUNET_YES,
1544 GNUNET_TIME_UNIT_FOREVER_REL,
1546 &cb_transfer_message,
1548 if (!s->service_transmit_handle)
1550 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1551 _("Could not send service-request multipart message to channel!\n"));
1554 s->active = GNUNET_SYSERR;
1555 s->client_notification_task =
1556 GNUNET_SCHEDULER_add_now (&prepare_client_end_notification,
1564 * Our client has finished sending us its multipart message.
1566 * @param session the service session context
1569 client_request_complete_bob (struct ServiceSession * client_session)
1571 struct ServiceSession * s;
1573 //check if service queue contains a matching request
1574 s = find_matching_session (from_service_tail,
1575 &client_session->session_id,
1579 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
1580 _ ("Got client-responder-session with key %s and a matching service-request-session set, processing.\n"),
1581 GNUNET_h2s (&client_session->session_id));
1583 s->response = client_session;
1584 s->intersected_elements = client_session->intersected_elements;
1585 client_session->intersected_elements = NULL;
1586 s->intersection_set = client_session->intersection_set;
1587 client_session->intersection_set = NULL;
1589 s->intersection_op = GNUNET_SET_prepare (&s->peer,
1592 GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_WEAK, UINT16_MAX),
1593 GNUNET_SET_RESULT_REMOVED,
1594 cb_intersection_element_removed,
1597 GNUNET_SET_commit (s->intersection_op, s->intersection_set);
1601 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
1602 _ ("Got client-responder-session with key %s but NO matching service-request-session set, queuing element for later use.\n"),
1603 GNUNET_h2s (&client_session->session_id));
1604 // no matching session exists yet, store the response
1605 // for later processing by handle_service_request()
1611 * Our client has finished sending us its multipart message.
1613 * @param session the service session context
1616 client_request_complete_alice (struct ServiceSession * s)
1618 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
1619 _ ("Creating new channel for session with key %s.\n"),
1620 GNUNET_h2s (&s->session_id));
1621 s->channel = GNUNET_CADET_channel_create (my_cadet, s,
1623 GNUNET_APPLICATION_TYPE_SCALARPRODUCT,
1624 GNUNET_CADET_OPTION_RELIABLE);
1625 if (NULL == s->channel)
1627 s->active = GNUNET_SYSERR;
1628 s->client_notification_task =
1629 GNUNET_SCHEDULER_add_now (&prepare_client_end_notification,
1633 s->intersection_listen = GNUNET_SET_listen (cfg,
1634 GNUNET_SET_OPERATION_INTERSECTION,
1636 cb_intersection_request_alice,
1638 if (NULL == s->intersection_listen)
1640 s->active = GNUNET_SYSERR;
1641 s->client_notification_task =
1642 GNUNET_SCHEDULER_add_now (&prepare_client_end_notification,
1646 prepare_alices_computation_request (s);
1651 handle_client_message_multipart (void *cls,
1652 struct GNUNET_SERVER_Client *client,
1653 const struct GNUNET_MessageHeader *message)
1655 const struct ComputationMultipartMessage * msg = (const struct ComputationMultipartMessage *) message;
1656 struct ServiceSession *s;
1657 uint32_t contained_count;
1658 struct GNUNET_SCALARPRODUCT_Element *elements;
1661 // only one concurrent session per client connection allowed, simplifies logics a lot...
1662 s = GNUNET_SERVER_client_get_user_context (client, struct ServiceSession);
1664 GNUNET_SERVER_receive_done (client, GNUNET_OK);
1668 contained_count = ntohl (msg->element_count_contained);
1670 //sanity check: is the message as long as the message_count fields suggests?
1671 if ((ntohs (msg->header.size) != (sizeof (struct ComputationMultipartMessage) +contained_count * sizeof (struct GNUNET_SCALARPRODUCT_Element)))
1672 || (0 == contained_count) || (s->total < s->transferred_element_count + contained_count))
1674 GNUNET_break_op (0);
1675 GNUNET_SERVER_receive_done (client, GNUNET_OK);
1678 s->transferred_element_count += contained_count;
1680 elements = (struct GNUNET_SCALARPRODUCT_Element *) & msg[1];
1681 for (i = 0; i < contained_count; i++)
1683 struct GNUNET_SET_Element set_elem;
1684 struct GNUNET_SCALARPRODUCT_Element * elem;
1686 if (0 == GNUNET_ntohll (elements[i].value))
1689 elem = GNUNET_new (struct GNUNET_SCALARPRODUCT_Element);
1690 memcpy (elem, &elements[i], sizeof (struct GNUNET_SCALARPRODUCT_Element));
1692 if (GNUNET_SYSERR == GNUNET_CONTAINER_multihashmap_put (s->intersected_elements,
1695 GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY))
1700 set_elem.data = &elem->key;
1701 set_elem.size = sizeof (elem->key);
1702 set_elem.type = 0; /* do we REALLY need this? */
1703 GNUNET_SET_add_element (s->intersection_set, &set_elem, NULL, NULL);
1704 s->used_element_count++;
1707 GNUNET_SERVER_receive_done (client, GNUNET_OK);
1709 if (s->total != s->transferred_element_count)
1713 if (ALICE == s->role)
1714 client_request_complete_alice (s);
1716 client_request_complete_bob (s);
1721 * Handler for a client request message.
1722 * Can either be type A or B
1723 * A: request-initiation to compute a scalar product with a peer
1724 * B: response role, keep the values + session and wait for a matching session or process a waiting request
1726 * @param cls closure
1727 * @param client identification of the client
1728 * @param message the actual message
1731 handle_client_message (void *cls,
1732 struct GNUNET_SERVER_Client *client,
1733 const struct GNUNET_MessageHeader *message)
1735 const struct ComputationMessage * msg = (const struct ComputationMessage *) message;
1736 struct ServiceSession * s;
1737 uint32_t contained_count;
1738 uint32_t total_count;
1740 struct GNUNET_SCALARPRODUCT_Element * elements;
1743 // only one concurrent session per client connection allowed, simplifies logics a lot...
1744 s = GNUNET_SERVER_client_get_user_context (client, struct ServiceSession);
1747 GNUNET_SERVER_receive_done (client, GNUNET_OK);
1751 msg_type = ntohs (msg->header.type);
1752 total_count = ntohl (msg->element_count_total);
1753 contained_count = ntohl (msg->element_count_contained);
1755 if ((GNUNET_MESSAGE_TYPE_SCALARPRODUCT_CLIENT_TO_ALICE == msg_type)
1756 && (!memcmp (&msg->peer, &me, sizeof (struct GNUNET_PeerIdentity)))) {
1757 //session with ourself makes no sense!
1758 GNUNET_break_op (0);
1759 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
1763 //sanity check: is the message as long as the message_count fields suggests?
1764 if ((ntohs (msg->header.size) !=
1765 (sizeof (struct ComputationMessage) + contained_count * sizeof (struct GNUNET_SCALARPRODUCT_Element)))
1766 || (0 == total_count))
1768 GNUNET_break_op (0);
1769 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
1773 // do we have a duplicate session here already?
1774 if (NULL != find_matching_session (from_client_tail,
1777 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
1778 _ ("Duplicate session information received, can not create new session with key `%s'\n"),
1779 GNUNET_h2s (&msg->session_key));
1780 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
1784 s = GNUNET_new (struct ServiceSession);
1785 s->active = GNUNET_YES;
1786 s->client_notification_task = GNUNET_SCHEDULER_NO_TASK;
1788 s->total = total_count;
1789 s->transferred_element_count = contained_count;
1790 // get our transaction key
1791 memcpy (&s->session_id, &msg->session_key, sizeof (struct GNUNET_HashCode));
1793 elements = (struct GNUNET_SCALARPRODUCT_Element *) & msg[1];
1794 s->intersected_elements = GNUNET_CONTAINER_multihashmap_create (s->total, GNUNET_NO);
1795 s->intersection_set = GNUNET_SET_create (cfg, GNUNET_SET_OPERATION_INTERSECTION);
1796 for (i = 0; i < contained_count; i++) {
1797 struct GNUNET_SET_Element set_elem;
1798 struct GNUNET_SCALARPRODUCT_Element * elem;
1800 if (0 == GNUNET_ntohll (elements[i].value))
1803 elem = GNUNET_new (struct GNUNET_SCALARPRODUCT_Element);
1804 memcpy (elem, &elements[i], sizeof (struct GNUNET_SCALARPRODUCT_Element));
1806 if (GNUNET_SYSERR == GNUNET_CONTAINER_multihashmap_put (s->intersected_elements,
1809 GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY)) {
1813 set_elem.data = &elem->key;
1814 set_elem.size = sizeof (elem->key);
1815 set_elem.type = 0; /* do we REALLY need this? */
1816 GNUNET_SET_add_element (s->intersection_set, &set_elem, NULL, NULL);
1817 s->used_element_count++;
1820 if (GNUNET_MESSAGE_TYPE_SCALARPRODUCT_CLIENT_TO_ALICE == msg_type) {
1822 memcpy (&s->peer, &msg->peer, sizeof (struct GNUNET_PeerIdentity));
1828 GNUNET_CONTAINER_DLL_insert (from_client_head, from_client_tail, s);
1829 GNUNET_SERVER_client_set_user_context (client, s);
1830 GNUNET_SERVER_receive_done (client, GNUNET_YES);
1832 if (s->total != s->transferred_element_count)
1836 if (ALICE == s->role)
1837 client_request_complete_alice (s);
1839 client_request_complete_bob (s);
1844 * Function called for inbound channels.
1846 * @param cls closure
1847 * @param channel new handle to the channel
1848 * @param initiator peer that started the channel
1849 * @param port unused
1850 * @param options unused
1851 * @return session associated with the channel
1854 cb_channel_incoming (void *cls,
1855 struct GNUNET_CADET_Channel *channel,
1856 const struct GNUNET_PeerIdentity *initiator,
1858 enum GNUNET_CADET_ChannelOption options)
1860 struct ServiceSession *s = GNUNET_new (struct ServiceSession);
1862 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1863 _ ("New incoming channel from peer %s.\n"),
1864 GNUNET_i2s (initiator));
1865 s->peer = *initiator;
1866 s->channel = channel;
1868 s->active = GNUNET_YES;
1874 * Function called whenever a channel is destroyed. Should clean up
1875 * any associated state.
1877 * It must NOT call GNUNET_CADET_channel_destroy on the channel.
1879 * @param cls closure (set from GNUNET_CADET_connect)
1880 * @param channel connection to the other end (henceforth invalid)
1881 * @param channel_ctx place where local state associated
1882 * with the channel is stored
1885 cb_channel_destruction (void *cls,
1886 const struct GNUNET_CADET_Channel *channel,
1889 struct ServiceSession * s = channel_ctx;
1890 struct ServiceSession * client_session;
1892 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1893 _ ("Peer disconnected, terminating session %s with peer (%s)\n"),
1894 GNUNET_h2s (&s->session_id),
1895 GNUNET_i2s (&s->peer));
1897 // as we have only one peer connected in each session, just remove the session
1900 if ((ALICE == s->role) && (GNUNET_YES == s->active) && (!do_shutdown))
1902 // if this happened before we received the answer, we must terminate the session
1903 s->role = GNUNET_SYSERR;
1904 s->client_notification_task =
1905 GNUNET_SCHEDULER_add_now (&prepare_client_end_notification,
1908 else if ((BOB == s->role) && (GNUNET_SYSERR != s->active))
1910 if ((s == from_service_head) || ((NULL != from_service_head) && ((NULL != s->next) || (NULL != s->a_tail))))
1911 GNUNET_CONTAINER_DLL_remove (from_service_head, from_service_tail, s);
1913 // there is a client waiting for this service session, terminate it, too!
1914 // i assume the tupel of key and element count is unique. if it was not the rest of the code would not work either.
1915 client_session = s->response;
1916 if ((NULL != s->response ) && (GNUNET_NO == s->active) && (GNUNET_YES == client_session->active))
1917 client_session->active = GNUNET_NO;
1918 free_session_variables (s);
1920 // the client has to check if it was waiting for a result
1921 // or if it was a responder, no point in adding more statefulness
1922 if ((NULL != s->response ) && (!do_shutdown))
1924 client_session->client_notification_task =
1925 GNUNET_SCHEDULER_add_now (&prepare_client_end_notification,
1934 * Compute our scalar product, done by Alice
1936 * @param session - the session associated with this computation
1937 * @return product as MPI, never NULL
1940 compute_scalar_product (struct ServiceSession *session)
1949 gcry_mpi_t r[session->used_element_count];
1950 gcry_mpi_t r_prime[session->used_element_count];
1955 count = session->used_element_count;
1956 // due to the introduced static offset S, we now also have to remove this
1957 // from the E(a_pi)(+)E(-b_pi-r_pi) and E(a_qi)(+)E(-r_qi) twice each,
1958 // the result is E((S + a_pi) + (S -b_pi-r_pi)) and E(S + a_qi + S - r_qi)
1959 for (i = 0; i < count; i++)
1961 GNUNET_CRYPTO_paillier_decrypt (&my_privkey, &my_pubkey,
1962 &session->r[i], r[i]);
1963 gcry_mpi_sub (r[i], r[i], my_offset);
1964 gcry_mpi_sub (r[i], r[i], my_offset);
1965 GNUNET_CRYPTO_paillier_decrypt (&my_privkey, &my_pubkey,
1966 &session->r_prime[i], r_prime[i]);
1967 gcry_mpi_sub (r_prime[i], r_prime[i], my_offset);
1968 gcry_mpi_sub (r_prime[i], r_prime[i], my_offset);
1971 // calculate t = sum(ai)
1972 t = compute_square_sum (session->sorted_elements, count);
1975 u = gcry_mpi_new (0);
1976 tmp = compute_square_sum (r, count);
1977 gcry_mpi_sub (u, u, tmp);
1978 gcry_mpi_release (tmp);
1981 u_prime = gcry_mpi_new (0);
1982 tmp = compute_square_sum (r_prime, count);
1983 gcry_mpi_sub (u_prime, u_prime, tmp);
1985 GNUNET_assert (p = gcry_mpi_new (0));
1986 GNUNET_assert (p_prime = gcry_mpi_new (0));
1987 GNUNET_assert (s = gcry_mpi_new (0));
1988 GNUNET_assert (s_prime = gcry_mpi_new (0));
1991 GNUNET_CRYPTO_paillier_decrypt (&my_privkey, &my_pubkey,
1993 GNUNET_CRYPTO_paillier_decrypt (&my_privkey, &my_pubkey,
1994 session->s_prime, s_prime);
1997 gcry_mpi_add (p, s, t);
1998 gcry_mpi_add (p, p, u);
2001 gcry_mpi_add (p_prime, s_prime, t);
2002 gcry_mpi_add (p_prime, p_prime, u_prime);
2004 gcry_mpi_release (t);
2005 gcry_mpi_release (u);
2006 gcry_mpi_release (u_prime);
2007 gcry_mpi_release (s);
2008 gcry_mpi_release (s_prime);
2011 gcry_mpi_sub (p, p, p_prime);
2012 gcry_mpi_release (p_prime);
2013 tmp = gcry_mpi_set_ui (tmp, 2);
2014 gcry_mpi_div (p, NULL, p, tmp, 0);
2016 gcry_mpi_release (tmp);
2017 for (i = 0; i < count; i++)
2019 gcry_mpi_release (session->sorted_elements[i]);
2020 gcry_mpi_release (r[i]);
2021 gcry_mpi_release (r_prime[i]);
2023 GNUNET_free (session->a_head);
2024 session->a_head = NULL;
2025 GNUNET_free (session->s);
2027 GNUNET_free (session->s_prime);
2028 session->s_prime = NULL;
2029 GNUNET_free (session->r);
2031 GNUNET_free (session->r_prime);
2032 session->r_prime = NULL;
2039 * Handle a multipart-chunk of a request from another service to calculate a scalarproduct with us.
2041 * @param cls closure (set from #GNUNET_CADET_connect)
2042 * @param channel connection to the other end
2043 * @param channel_ctx place to store local state associated with the channel
2044 * @param message the actual message
2045 * @return #GNUNET_OK to keep the connection open,
2046 * #GNUNET_SYSERR to close it (signal serious error)
2049 handle_alices_cyrptodata_message_multipart (void *cls,
2050 struct GNUNET_CADET_Channel * channel,
2052 const struct GNUNET_MessageHeader * message)
2054 struct ServiceSession * s;
2055 const struct MultipartMessage * msg = (const struct MultipartMessage *) message;
2056 struct GNUNET_CRYPTO_PaillierCiphertext *payload;
2057 uint32_t contained_elements;
2058 uint32_t msg_length;
2060 // are we in the correct state?
2061 s = (struct ServiceSession *) * channel_ctx;
2063 if ((NULL == s->e_a) || //or we did not expect this message yet
2064 (s->used_element_count == s->transferred_element_count))
2065 { //we are not expecting multipart messages
2068 // shorter than minimum?
2069 if (ntohs (msg->header.size) <= sizeof (struct MultipartMessage))
2073 contained_elements = ntohl (msg->contained_element_count);
2074 msg_length = sizeof (struct MultipartMessage)
2075 +contained_elements * sizeof (struct GNUNET_CRYPTO_PaillierCiphertext);
2077 if ((ntohs (msg->header.size) != msg_length)
2078 || (s->used_element_count < contained_elements + s->transferred_element_count)
2079 || (0 == contained_elements))
2083 payload = (struct GNUNET_CRYPTO_PaillierCiphertext *) &msg[1];
2084 // Convert each vector element to MPI_value
2085 memcpy (&s->e_a[s->transferred_element_count], payload,
2086 sizeof (struct GNUNET_CRYPTO_PaillierCiphertext) * contained_elements);
2088 s->transferred_element_count += contained_elements;
2090 if (contained_elements == s->used_element_count)
2092 // single part finished
2093 if (NULL == s->intersection_op)
2094 // intersection has already finished, so we can proceed
2095 compute_service_response (s);
2101 // and notify our client-session that we could not complete the session
2102 free_session_variables (s);
2103 if (NULL != s->client)
2106 s->active = GNUNET_SYSERR;
2107 s->client_notification_task =
2108 GNUNET_SCHEDULER_add_now (&prepare_client_end_notification,
2114 if (NULL != s->response){
2115 s->response->active = GNUNET_SYSERR;
2116 s->response->client_notification_task =
2117 GNUNET_SCHEDULER_add_now (&prepare_client_end_notification,
2120 if ((s == from_service_head) || ((NULL != from_service_head) && ((NULL != s->next) || (NULL != s->a_tail))))
2121 GNUNET_CONTAINER_DLL_remove (from_service_head, from_service_tail, s);
2124 return GNUNET_SYSERR;
2129 * Handle a request from another service to calculate a scalarproduct with us.
2131 * @param cls closure (set from #GNUNET_CADET_connect)
2132 * @param channel connection to the other end
2133 * @param channel_ctx place to store local state associated with the channel
2134 * @param message the actual message
2135 * @return #GNUNET_OK to keep the connection open,
2136 * #GNUNET_SYSERR to close it (signal serious error)
2139 handle_alices_cyrptodata_message (void *cls,
2140 struct GNUNET_CADET_Channel * channel,
2142 const struct GNUNET_MessageHeader * message)
2144 struct ServiceSession * s;
2145 const struct AliceCryptodataMessage * msg = (const struct AliceCryptodataMessage *) message;
2146 struct GNUNET_CRYPTO_PaillierCiphertext *payload;
2147 uint32_t contained_elements = 0;
2148 uint32_t msg_length;
2150 s = (struct ServiceSession *) * channel_ctx;
2152 if ((BOB != s->role)
2153 //we are expecting multipart messages instead
2155 //or we did not expect this message yet
2156 || //intersection OP has not yet finished
2157 !((NULL != s->intersection_op)
2158 //intersection OP done
2159 || (s->response->sorted_elements)
2165 // shorter than minimum?
2166 if (ntohs (msg->header.size) <= sizeof (struct MultipartMessage))
2171 contained_elements = ntohl (msg->contained_element_count);
2172 msg_length = sizeof (struct AliceCryptodataMessage)
2173 +contained_elements * sizeof (struct GNUNET_CRYPTO_PaillierCiphertext);
2175 //sanity check: is the message as long as the message_count fields suggests?
2176 if ((ntohs (msg->header.size) != msg_length) ||
2177 (s->used_element_count < s->transferred_element_count + contained_elements) ||
2178 (0 == contained_elements))
2183 s->transferred_element_count = contained_elements;
2184 payload = (struct GNUNET_CRYPTO_PaillierCiphertext*) &msg[1];
2186 s->e_a = GNUNET_malloc (sizeof (struct GNUNET_CRYPTO_PaillierCiphertext) * s->used_element_count);
2187 memcpy (&s->e_a[0], payload, contained_elements * sizeof (struct GNUNET_CRYPTO_PaillierCiphertext));
2188 if (contained_elements == s->used_element_count)
2190 // single part finished
2191 if (NULL == s->intersection_op)
2192 // intersection has already finished, so we can proceed
2193 compute_service_response (s);
2197 GNUNET_break_op (0);
2199 // and notify our client-session that we could not complete the session
2200 free_session_variables (s);
2201 if (NULL != s->client)
2204 s->active = GNUNET_SYSERR;
2205 s->client_notification_task =
2206 GNUNET_SCHEDULER_add_now (&prepare_client_end_notification,
2212 if (NULL != s->response)
2214 s->response->active = GNUNET_SYSERR;
2215 s->response->client_notification_task =
2216 GNUNET_SCHEDULER_add_now (&prepare_client_end_notification,
2219 if ((s == from_service_head) || ((NULL != from_service_head) && ((NULL != s->next) || (NULL != s->a_tail))))
2220 GNUNET_CONTAINER_DLL_remove (from_service_head, from_service_tail, s);
2223 return GNUNET_SYSERR;
2228 * Handle a request from another service to calculate a scalarproduct with us.
2230 * @param cls closure (set from #GNUNET_CADET_connect)
2231 * @param channel connection to the other end
2232 * @param channel_ctx place to store local state associated with the channel
2233 * @param message the actual message
2234 * @return #GNUNET_OK to keep the connection open,
2235 * #GNUNET_SYSERR to close it (signal serious error)
2238 handle_alices_computation_request (void *cls,
2239 struct GNUNET_CADET_Channel * channel,
2241 const struct GNUNET_MessageHeader * message)
2243 struct ServiceSession * s;
2244 struct ServiceSession * client_session;
2245 const struct ServiceRequestMessage * msg = (const struct ServiceRequestMessage *) message;
2247 s = (struct ServiceSession *) * channel_ctx;
2248 if ((BOB != s->role) || (s->total != 0))
2250 // must be a fresh session
2253 // Check if message was sent by me, which would be bad!
2254 if (!memcmp (&s->peer, &me, sizeof (struct GNUNET_PeerIdentity)))
2258 return GNUNET_SYSERR;
2260 // shorter than expected?
2261 if (ntohs (msg->header.size) != sizeof (struct ServiceRequestMessage))
2264 GNUNET_break_op (0);
2265 return GNUNET_SYSERR;
2267 if (find_matching_session (from_service_tail,
2270 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
2271 _ ("Got message with duplicate session key (`%s'), ignoring service request.\n"),
2272 (const char *) &(msg->session_id));
2274 return GNUNET_SYSERR;
2277 s->channel = channel;
2280 memcpy (&s->session_id, &msg->session_id, sizeof (struct GNUNET_HashCode));
2283 s->remote_pubkey = GNUNET_new (struct GNUNET_CRYPTO_PaillierPublicKey);
2284 memcpy (s->remote_pubkey, &msg->public_key, sizeof (struct GNUNET_CRYPTO_PaillierPublicKey));
2286 //check if service queue contains a matching request
2287 client_session = find_matching_session (from_client_tail,
2291 GNUNET_CONTAINER_DLL_insert (from_service_head, from_service_tail, s);
2293 if ((NULL != client_session)
2294 && (client_session->transferred_element_count == client_session->total))
2297 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
2298 _("Got session with key %s and a matching element set, processing.\n"),
2299 GNUNET_h2s (&s->session_id));
2301 s->response = client_session;
2302 s->intersected_elements = client_session->intersected_elements;
2303 client_session->intersected_elements = NULL;
2304 s->intersection_set = client_session->intersection_set;
2305 client_session->intersection_set = NULL;
2307 s->intersection_op = GNUNET_SET_prepare (&s->peer,
2310 GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_WEAK, UINT16_MAX),
2311 GNUNET_SET_RESULT_REMOVED,
2312 cb_intersection_element_removed,
2315 GNUNET_SET_commit (s->intersection_op, s->intersection_set);
2319 GNUNET_log (GNUNET_ERROR_TYPE_INFO, _ ("Got session with key %s without a matching element set, queueing.\n"), GNUNET_h2s (&s->session_id));
2324 GNUNET_break_op (0);
2326 // and notify our client-session that we could not complete the session
2327 free_session_variables (s);
2328 if (NULL != s->client)
2331 s->active = GNUNET_SYSERR;
2332 s->client_notification_task =
2333 GNUNET_SCHEDULER_add_now (&prepare_client_end_notification,
2339 if (NULL != s->response) {
2340 s->response->active = GNUNET_SYSERR;
2341 s->response->client_notification_task =
2342 GNUNET_SCHEDULER_add_now (&prepare_client_end_notification,
2345 if ((s == from_service_head) || ((NULL != from_service_head) && ((NULL != s->next) || (NULL != s->a_tail))))
2346 GNUNET_CONTAINER_DLL_remove (from_service_head, from_service_tail, s);
2349 return GNUNET_SYSERR;
2354 * Handle a multipart chunk of a response we got from another service we wanted to calculate a scalarproduct with.
2356 * @param cls closure (set from #GNUNET_CADET_connect)
2357 * @param channel connection to the other end
2358 * @param channel_ctx place to store local state associated with the channel
2359 * @param message the actual message
2360 * @return #GNUNET_OK to keep the connection open,
2361 * #GNUNET_SYSERR to close it (signal serious error)
2364 handle_bobs_cryptodata_multipart (void *cls,
2365 struct GNUNET_CADET_Channel * channel,
2367 const struct GNUNET_MessageHeader * message)
2369 struct ServiceSession * s;
2370 const struct MultipartMessage * msg = (const struct MultipartMessage *) message;
2371 struct GNUNET_CRYPTO_PaillierCiphertext * payload;
2373 uint32_t contained = 0;
2375 size_t required_size;
2377 GNUNET_assert (NULL != message);
2378 // are we in the correct state?
2379 s = (struct ServiceSession *) * channel_ctx;
2380 if ((ALICE != s->role) || (NULL == s->sorted_elements))
2384 msg_size = ntohs (msg->header.size);
2385 required_size = sizeof (struct MultipartMessage)
2386 + 2 * sizeof (struct GNUNET_CRYPTO_PaillierCiphertext);
2387 // shorter than minimum?
2388 if (required_size > msg_size)
2392 contained = ntohl (msg->contained_element_count);
2393 required_size = sizeof (struct MultipartMessage)
2394 + 2 * contained * sizeof (struct GNUNET_CRYPTO_PaillierCiphertext);
2395 //sanity check: is the message as long as the message_count fields suggests?
2396 if ((required_size != msg_size) || (s->used_element_count < s->transferred_element_count + contained))
2400 payload = (struct GNUNET_CRYPTO_PaillierCiphertext *) &msg[1];
2401 // Convert each k[][perm] to its MPI_value
2402 for (i = 0; i < contained; i++) {
2403 memcpy (&s->r[s->transferred_element_count + i], &payload[2 * i], sizeof (struct GNUNET_CRYPTO_PaillierCiphertext));
2404 memcpy (&s->r_prime[s->transferred_element_count + i], &payload[2 * i], sizeof (struct GNUNET_CRYPTO_PaillierCiphertext));
2406 s->transferred_element_count += contained;
2407 if (s->transferred_element_count != s->used_element_count)
2409 s->product = compute_scalar_product (s); //never NULL
2412 GNUNET_break_op (NULL != s->product);
2414 // send message with product to client
2415 if (NULL != s->client)
2418 if (NULL != s->product)
2419 s->active = GNUNET_NO;
2421 s->active = GNUNET_SYSERR;
2422 s->client_notification_task =
2423 GNUNET_SCHEDULER_add_now (&prepare_client_response,
2429 if (NULL != s->response){
2430 s->response->active = GNUNET_SYSERR;
2431 s->response->client_notification_task =
2432 GNUNET_SCHEDULER_add_now (&prepare_client_end_notification,
2435 if ((s == from_service_head) || ((NULL != from_service_head) && ((NULL != s->next) || (NULL != s->a_tail))))
2436 GNUNET_CONTAINER_DLL_remove (from_service_head, from_service_tail, s);
2437 free_session_variables (s);
2440 // the channel has done its job, terminate our connection and the channel
2441 // the peer will be notified that the channel was destroyed via channel_destruction_handler
2442 // just close the connection, as recommended by Christian
2443 return GNUNET_SYSERR;
2448 * Handle a response we got from another service we wanted to calculate a scalarproduct with.
2450 * @param cls closure (set from #GNUNET_CADET_connect)
2451 * @param channel connection to the other end
2452 * @param channel_ctx place to store local state associated with the channel
2453 * @param message the actual message
2454 * @return #GNUNET_OK to keep the connection open,
2455 * #GNUNET_SYSERR to close it (we are done)
2458 handle_bobs_cryptodata_message (void *cls,
2459 struct GNUNET_CADET_Channel *channel,
2461 const struct GNUNET_MessageHeader *message)
2463 struct ServiceSession * s;
2464 const struct ServiceResponseMessage *msg = (const struct ServiceResponseMessage *) message;
2465 struct GNUNET_CRYPTO_PaillierCiphertext * payload;
2467 uint32_t contained = 0;
2469 size_t required_size;
2471 GNUNET_assert (NULL != message);
2472 s = (struct ServiceSession *) * channel_ctx;
2473 // are we in the correct state?
2474 if (NULL == s->sorted_elements
2476 || s->used_element_count != s->transferred_element_count)
2480 //we need at least a full message without elements attached
2481 msg_size = ntohs (msg->header.size);
2482 required_size = sizeof (struct ServiceResponseMessage) + 2 * sizeof (struct GNUNET_CRYPTO_PaillierCiphertext);
2484 if (required_size > msg_size)
2488 contained = ntohl (msg->contained_element_count);
2489 required_size = sizeof (struct ServiceResponseMessage)
2490 + 2 * contained * sizeof (struct GNUNET_CRYPTO_PaillierCiphertext)
2491 + 2 * sizeof (struct GNUNET_CRYPTO_PaillierCiphertext);
2492 //sanity check: is the message as long as the message_count fields suggests?
2493 if ((msg_size != required_size) || (s->used_element_count < contained))
2497 s->transferred_element_count = contained;
2499 payload = (struct GNUNET_CRYPTO_PaillierCiphertext *) &msg[1];
2501 s->s = GNUNET_malloc (sizeof (struct GNUNET_CRYPTO_PaillierCiphertext));
2502 s->s_prime = GNUNET_malloc (sizeof (struct GNUNET_CRYPTO_PaillierCiphertext));
2503 memcpy (s->s, &payload[0], sizeof (struct GNUNET_CRYPTO_PaillierCiphertext));
2504 memcpy (s->s_prime, &payload[1], sizeof (struct GNUNET_CRYPTO_PaillierCiphertext));
2506 s->r = GNUNET_malloc (sizeof (struct GNUNET_CRYPTO_PaillierCiphertext) * s->used_element_count);
2507 s->r_prime = GNUNET_malloc (sizeof (struct GNUNET_CRYPTO_PaillierCiphertext) * s->used_element_count);
2509 payload = &payload[2];
2510 // Convert each k[][perm] to its MPI_value
2511 for (i = 0; i < contained; i++)
2513 memcpy (&s->r[i], &payload[2 * i], sizeof (struct GNUNET_CRYPTO_PaillierCiphertext));
2514 memcpy (&s->r_prime[i], &payload[2 * i + 1], sizeof (struct GNUNET_CRYPTO_PaillierCiphertext));
2516 if (s->transferred_element_count != s->used_element_count)
2517 return GNUNET_OK; //wait for the other multipart chunks
2518 s->product = compute_scalar_product (s); //never NULL
2521 GNUNET_break_op (NULL != s->product);
2523 // send message with product to client
2524 if (NULL != s->client)
2527 s->client_notification_task =
2528 GNUNET_SCHEDULER_add_now (&prepare_client_response,
2534 if (NULL != s->response)
2536 s->response->active = GNUNET_SYSERR;
2537 s->response->client_notification_task =
2538 GNUNET_SCHEDULER_add_now (&prepare_client_end_notification,
2541 if ((s == from_service_head) || ((NULL != from_service_head) && ((NULL != s->next) || (NULL != s->a_tail))))
2542 GNUNET_CONTAINER_DLL_remove (from_service_head, from_service_tail, s);
2543 free_session_variables (s);
2546 // the channel has done its job, terminate our connection and the channel
2547 // the peer will be notified that the channel was destroyed via channel_destruction_handler
2548 // just close the connection, as recommended by Christian
2549 return GNUNET_SYSERR;
2554 * Task run during shutdown.
2560 shutdown_task (void *cls,
2561 const struct GNUNET_SCHEDULER_TaskContext *tc)
2563 struct ServiceSession * s;
2565 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
2566 _("Shutting down, initiating cleanup.\n"));
2568 do_shutdown = GNUNET_YES;
2570 // terminate all owned open channels.
2571 for (s = from_client_head; NULL != s; s = s->next)
2573 if ((GNUNET_NO != s->active) && (NULL != s->channel))
2575 GNUNET_CADET_channel_destroy (s->channel);
2578 if (GNUNET_SCHEDULER_NO_TASK != s->client_notification_task)
2580 GNUNET_SCHEDULER_cancel (s->client_notification_task);
2581 s->client_notification_task = GNUNET_SCHEDULER_NO_TASK;
2583 if (NULL != s->client)
2585 GNUNET_SERVER_client_disconnect (s->client);
2589 for (s = from_service_head; NULL != s; s = s->next)
2590 if (NULL != s->channel)
2592 GNUNET_CADET_channel_destroy (s->channel);
2598 GNUNET_CADET_disconnect (my_cadet);
2605 * Initialization of the program and message handlers
2607 * @param cls closure
2608 * @param server the initialized server
2609 * @param c configuration to use
2613 struct GNUNET_SERVER_Handle *server,
2614 const struct GNUNET_CONFIGURATION_Handle *c)
2616 static const struct GNUNET_SERVER_MessageHandler server_handlers[] = {
2617 {&handle_client_message, NULL, GNUNET_MESSAGE_TYPE_SCALARPRODUCT_CLIENT_TO_ALICE, 0},
2618 {&handle_client_message, NULL, GNUNET_MESSAGE_TYPE_SCALARPRODUCT_CLIENT_TO_BOB, 0},
2619 {&handle_client_message_multipart, NULL, GNUNET_MESSAGE_TYPE_SCALARPRODUCT_CLIENT_MUTLIPART, 0},
2622 static const struct GNUNET_CADET_MessageHandler cadet_handlers[] = {
2623 { &handle_alices_computation_request, GNUNET_MESSAGE_TYPE_SCALARPRODUCT_SESSION_INITIALIZATION, 0},
2624 { &handle_alices_cyrptodata_message, GNUNET_MESSAGE_TYPE_SCALARPRODUCT_ALICE_CRYPTODATA, 0},
2625 { &handle_alices_cyrptodata_message_multipart, GNUNET_MESSAGE_TYPE_SCALARPRODUCT_ALICE_CRYPTODATA_MULTIPART, 0},
2626 { &handle_bobs_cryptodata_message, GNUNET_MESSAGE_TYPE_SCALARPRODUCT_BOB_CRYPTODATA, 0},
2627 { &handle_bobs_cryptodata_multipart, GNUNET_MESSAGE_TYPE_SCALARPRODUCT_BOB_CRYPTODATA_MULTIPART, 0},
2630 static const uint32_t ports[] = {
2631 GNUNET_APPLICATION_TYPE_SCALARPRODUCT,
2636 //generate private/public key set
2637 GNUNET_CRYPTO_paillier_create (&my_pubkey, &my_privkey);
2639 // offset has to be sufficiently small to allow computation of:
2640 // m1+m2 mod n == (S + a) + (S + b) mod n,
2641 // if we have more complex operations, this factor needs to be lowered
2642 my_offset = gcry_mpi_new (GNUNET_CRYPTO_PAILLIER_BITS / 3);
2643 gcry_mpi_set_bit (my_offset, GNUNET_CRYPTO_PAILLIER_BITS / 3);
2645 // register server callbacks and disconnect handler
2646 GNUNET_SERVER_add_handlers (server, server_handlers);
2647 GNUNET_SERVER_disconnect_notify (server,
2648 &cb_client_disconnect,
2650 GNUNET_break (GNUNET_OK ==
2651 GNUNET_CRYPTO_get_peer_identity (cfg,
2653 my_cadet = GNUNET_CADET_connect (cfg, NULL,
2654 &cb_channel_incoming,
2655 &cb_channel_destruction,
2656 cadet_handlers, ports);
2659 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
2660 _("Connect to CADET failed\n"));
2661 GNUNET_SCHEDULER_shutdown ();
2664 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
2665 _("CADET initialized\n"));
2666 GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_FOREVER_REL,
2673 * The main function for the scalarproduct service.
2675 * @param argc number of arguments from the command line
2676 * @param argv command line arguments
2677 * @return 0 ok, 1 on error
2680 main (int argc, char *const *argv)
2682 return (GNUNET_OK ==
2683 GNUNET_SERVICE_run (argc, argv,
2685 GNUNET_SERVICE_OPTION_NONE,
2686 &run, NULL)) ? 0 : 1;
2689 /* end of gnunet-service-scalarproduct.c */