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 // insert as last element with the highest key
1189 if (0 >= GNUNET_CRYPTO_hash_cmp (&s->a_tail->elem->key, &e->elem->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 s->used_element_count--;
1240 case GNUNET_SET_STATUS_DONE:
1241 s->intersection_op = NULL;
1242 s->intersection_set = NULL;
1244 if (2 > s->used_element_count)
1246 // failed! do not leak information about our single remaining element!
1247 // continue after the loop
1251 GNUNET_CONTAINER_multihashmap_iterate (s->intersected_elements,
1252 &cb_insert_element_sorted,
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 if (NULL != s->intersection_listen)
1280 GNUNET_SET_listen_cancel (s->intersection_listen);
1281 s->intersection_listen = NULL;
1284 // the op failed and has already been invalidated by the set service
1285 s->intersection_op = NULL;
1286 s->intersection_set = NULL;
1290 //failed if we go here
1291 GNUNET_break_op (0);
1294 // and notify our client-session that we could not complete the session
1295 if (ALICE == s->role) {
1296 s->active = GNUNET_SYSERR;
1297 s->client_notification_task =
1298 GNUNET_SCHEDULER_add_now (&prepare_client_end_notification,
1303 GNUNET_CONTAINER_DLL_remove (from_service_head,
1306 free_session_variables (s);
1307 s->response->active = GNUNET_SYSERR;
1308 s->response->client_notification_task =
1309 GNUNET_SCHEDULER_add_now (&prepare_client_end_notification,
1317 * Called when another peer wants to do a set operation with the
1318 * local peer. If a listen error occurs, the @a request is NULL.
1320 * @param cls closure
1321 * @param other_peer the other peer
1322 * @param context_msg message with application specific information from
1324 * @param request request from the other peer (never NULL), use GNUNET_SET_accept()
1325 * to accept it, otherwise the request will be refused
1326 * Note that we can't just return value from the listen callback,
1327 * as it is also necessary to specify the set we want to do the
1328 * operation with, whith sometimes can be derived from the context
1329 * message. It's necessary to specify the timeout.
1332 cb_intersection_request_alice (void *cls,
1333 const struct GNUNET_PeerIdentity *other_peer,
1334 const struct GNUNET_MessageHeader *context_msg,
1335 struct GNUNET_SET_Request *request)
1337 struct ServiceSession * s = cls;
1339 s->intersection_op = GNUNET_SET_accept (request,
1340 GNUNET_SET_RESULT_REMOVED,
1341 cb_intersection_element_removed,
1343 if (NULL == s->intersection_op)
1345 s->active = GNUNET_SYSERR;
1346 s->client_notification_task =
1347 GNUNET_SCHEDULER_add_now (&prepare_client_end_notification,
1351 if (GNUNET_OK != GNUNET_SET_commit (s->intersection_op, s->intersection_set))
1353 s->active = GNUNET_SYSERR;
1354 s->client_notification_task =
1355 GNUNET_SCHEDULER_add_now (&prepare_client_end_notification,
1359 s->intersection_set = NULL;
1360 s->intersection_listen = NULL;
1365 * prepare the response we will send to alice or bobs' clients.
1366 * in Bobs case the product will be NULL.
1368 * @param cls the session associated with our client.
1369 * @param tc the task context handed to us by the scheduler, unused
1372 prepare_client_response (void *cls,
1373 const struct GNUNET_SCHEDULER_TaskContext *tc)
1375 struct ServiceSession * s = cls;
1376 struct ClientResponseMessage *msg;
1377 unsigned char * product_exported = NULL;
1378 size_t product_length = 0;
1379 uint32_t msg_length = 0;
1384 s->client_notification_task = GNUNET_SCHEDULER_NO_TASK;
1388 gcry_mpi_t value = gcry_mpi_new (0);
1390 sign = gcry_mpi_cmp_ui (s->product, 0);
1391 // libgcrypt can not handle a print of a negative number
1392 // if (a->sign) return gcry_error (GPG_ERR_INTERNAL); /* Can't handle it yet. */
1395 gcry_mpi_sub (value, value, s->product);
1400 gcry_mpi_add (value, value, s->product);
1405 gcry_mpi_release (s->product);
1408 // get representation as string
1410 && (0 != (rc = gcry_mpi_aprint (GCRYMPI_FMT_STD,
1415 LOG_GCRY (GNUNET_ERROR_TYPE_ERROR, "gcry_mpi_scan", rc);
1417 range = -1; // signal error with product-length = 0 and range = -1
1419 gcry_mpi_release (value);
1422 msg_length = sizeof (struct ClientResponseMessage) + product_length;
1423 msg = GNUNET_malloc (msg_length);
1424 if (product_exported != NULL)
1426 memcpy (&msg[1], product_exported, product_length);
1427 GNUNET_free (product_exported);
1429 msg->header.type = htons (GNUNET_MESSAGE_TYPE_SCALARPRODUCT_RESULT);
1430 msg->header.size = htons (msg_length);
1432 msg->product_length = htonl (product_length);
1433 s->msg = (struct GNUNET_MessageHeader *) msg;
1434 s->client_transmit_handle =
1435 GNUNET_SERVER_notify_transmit_ready (s->client,
1437 GNUNET_TIME_UNIT_FOREVER_REL,
1438 &cb_transfer_message,
1440 GNUNET_break (NULL != s->client_transmit_handle);
1441 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
1442 _ ("Sent result to client (%p), this session (%s) has ended!\n"),
1444 GNUNET_h2s (&s->session_id));
1449 * Executed by Alice, fills in a service-request message and sends it to the given peer
1451 * @param session the session associated with this request
1454 prepare_alices_computation_request (struct ServiceSession * s)
1456 struct ServiceRequestMessage * msg;
1458 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1459 _("Successfully created new channel to peer (%s)!\n"),
1460 GNUNET_i2s (&s->peer));
1462 msg = GNUNET_new (struct ServiceRequestMessage);
1463 msg->header.type = htons (GNUNET_MESSAGE_TYPE_SCALARPRODUCT_SESSION_INITIALIZATION);
1464 memcpy (&msg->session_id, &s->session_id, sizeof (struct GNUNET_HashCode));
1465 msg->header.size = htons (sizeof (struct ServiceRequestMessage));
1467 s->msg = (struct GNUNET_MessageHeader *) msg;
1468 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
1469 _("Transmitting service request.\n"));
1471 //transmit via cadet messaging
1472 s->service_transmit_handle
1473 = GNUNET_CADET_notify_transmit_ready (s->channel, GNUNET_YES,
1474 GNUNET_TIME_UNIT_FOREVER_REL,
1475 sizeof (struct ServiceRequestMessage),
1476 &cb_transfer_message,
1478 if (!s->service_transmit_handle)
1480 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1481 _("Could not send message to channel!\n"));
1484 s->active = GNUNET_SYSERR;
1485 s->client_notification_task =
1486 GNUNET_SCHEDULER_add_now (&prepare_client_end_notification,
1494 * Send a multi part chunk of a service request from alice to bob.
1495 * This element only contains a part of the elements-vector (session->a[]),
1496 * mask and public key set have to be contained within the first message
1498 * This allows a ~32kbit key length while using 32000 elements or 62000 elements per request.
1500 * @param cls the associated service session
1503 prepare_alices_cyrptodata_message_multipart (void *cls)
1505 struct ServiceSession * s = cls;
1506 struct MultipartMessage * msg;
1507 struct GNUNET_CRYPTO_PaillierCiphertext * payload;
1509 uint32_t msg_length;
1510 uint32_t todo_count;
1513 msg_length = sizeof (struct MultipartMessage);
1514 todo_count = s->used_element_count - s->transferred_element_count;
1516 if (todo_count > MULTIPART_ELEMENT_CAPACITY)
1517 // send the currently possible maximum chunk
1518 todo_count = MULTIPART_ELEMENT_CAPACITY;
1520 msg_length += todo_count * sizeof (struct GNUNET_CRYPTO_PaillierCiphertext);
1521 msg = GNUNET_malloc (msg_length);
1522 msg->header.type = htons (GNUNET_MESSAGE_TYPE_SCALARPRODUCT_ALICE_CRYPTODATA_MULTIPART);
1523 msg->header.size = htons (msg_length);
1524 msg->contained_element_count = htonl (todo_count);
1526 payload = (struct GNUNET_CRYPTO_PaillierCiphertext *) &msg[1];
1528 // now copy over the sorted element vector
1529 a = gcry_mpi_new (0);
1530 for (i = s->transferred_element_count; i < todo_count; i++)
1532 gcry_mpi_add (a, s->sorted_elements[i], my_offset);
1533 GNUNET_CRYPTO_paillier_encrypt (&my_pubkey, a, 3, &payload[i - s->transferred_element_count]);
1535 gcry_mpi_release (a);
1536 s->transferred_element_count += todo_count;
1538 s->msg = (struct GNUNET_MessageHeader *) msg;
1539 GNUNET_log (GNUNET_ERROR_TYPE_INFO, _ ("Transmitting service request.\n"));
1541 //transmit via cadet messaging
1542 s->service_transmit_handle = GNUNET_CADET_notify_transmit_ready (s->channel, GNUNET_YES,
1543 GNUNET_TIME_UNIT_FOREVER_REL,
1545 &cb_transfer_message,
1547 if (!s->service_transmit_handle)
1549 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1550 _("Could not send service-request multipart message to channel!\n"));
1553 s->active = GNUNET_SYSERR;
1554 s->client_notification_task =
1555 GNUNET_SCHEDULER_add_now (&prepare_client_end_notification,
1563 * Our client has finished sending us its multipart message.
1565 * @param session the service session context
1568 client_request_complete_bob (struct ServiceSession * client_session)
1570 struct ServiceSession * s;
1572 //check if service queue contains a matching request
1573 s = find_matching_session (from_service_tail,
1574 &client_session->session_id,
1578 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
1579 _ ("Got client-responder-session with key %s and a matching service-request-session set, processing.\n"),
1580 GNUNET_h2s (&client_session->session_id));
1582 s->response = client_session;
1583 s->intersected_elements = client_session->intersected_elements;
1584 client_session->intersected_elements = NULL;
1585 s->intersection_set = client_session->intersection_set;
1586 client_session->intersection_set = NULL;
1588 s->intersection_op = GNUNET_SET_prepare (&s->peer,
1591 GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_WEAK, UINT16_MAX),
1592 GNUNET_SET_RESULT_REMOVED,
1593 cb_intersection_element_removed,
1596 GNUNET_SET_commit (s->intersection_op, s->intersection_set);
1600 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
1601 _ ("Got client-responder-session with key %s but NO matching service-request-session set, queuing element for later use.\n"),
1602 GNUNET_h2s (&client_session->session_id));
1603 // no matching session exists yet, store the response
1604 // for later processing by handle_service_request()
1610 * Our client has finished sending us its multipart message.
1612 * @param session the service session context
1615 client_request_complete_alice (struct ServiceSession * s)
1617 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
1618 _ ("Creating new channel for session with key %s.\n"),
1619 GNUNET_h2s (&s->session_id));
1620 s->channel = GNUNET_CADET_channel_create (my_cadet, s,
1622 GNUNET_APPLICATION_TYPE_SCALARPRODUCT,
1623 GNUNET_CADET_OPTION_RELIABLE);
1624 if (NULL == s->channel)
1626 s->active = GNUNET_SYSERR;
1627 s->client_notification_task =
1628 GNUNET_SCHEDULER_add_now (&prepare_client_end_notification,
1632 s->intersection_listen = GNUNET_SET_listen (cfg,
1633 GNUNET_SET_OPERATION_INTERSECTION,
1635 cb_intersection_request_alice,
1637 if (NULL == s->intersection_listen)
1639 s->active = GNUNET_SYSERR;
1640 s->client_notification_task =
1641 GNUNET_SCHEDULER_add_now (&prepare_client_end_notification,
1645 prepare_alices_computation_request (s);
1650 handle_client_message_multipart (void *cls,
1651 struct GNUNET_SERVER_Client *client,
1652 const struct GNUNET_MessageHeader *message)
1654 const struct ComputationMultipartMessage * msg = (const struct ComputationMultipartMessage *) message;
1655 struct ServiceSession *s;
1656 uint32_t contained_count;
1657 struct GNUNET_SCALARPRODUCT_Element *elements;
1660 // only one concurrent session per client connection allowed, simplifies logics a lot...
1661 s = GNUNET_SERVER_client_get_user_context (client, struct ServiceSession);
1663 GNUNET_SERVER_receive_done (client, GNUNET_OK);
1667 contained_count = ntohl (msg->element_count_contained);
1669 //sanity check: is the message as long as the message_count fields suggests?
1670 if ((ntohs (msg->header.size) != (sizeof (struct ComputationMultipartMessage) +contained_count * sizeof (struct GNUNET_SCALARPRODUCT_Element)))
1671 || (0 == contained_count) || (s->total < s->transferred_element_count + contained_count))
1673 GNUNET_break_op (0);
1674 GNUNET_SERVER_receive_done (client, GNUNET_OK);
1677 s->transferred_element_count += contained_count;
1679 elements = (struct GNUNET_SCALARPRODUCT_Element *) & msg[1];
1680 for (i = 0; i < contained_count; i++)
1682 struct GNUNET_SET_Element set_elem;
1683 struct GNUNET_SCALARPRODUCT_Element * elem;
1685 if (0 == GNUNET_ntohll (elements[i].value))
1688 elem = GNUNET_new (struct GNUNET_SCALARPRODUCT_Element);
1689 memcpy (elem, &elements[i], sizeof (struct GNUNET_SCALARPRODUCT_Element));
1691 if (GNUNET_SYSERR == GNUNET_CONTAINER_multihashmap_put (s->intersected_elements,
1694 GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY))
1699 set_elem.data = &elem->key;
1700 set_elem.size = sizeof (elem->key);
1701 set_elem.type = 0; /* do we REALLY need this? */
1702 GNUNET_SET_add_element (s->intersection_set, &set_elem, NULL, NULL);
1703 s->used_element_count++;
1706 GNUNET_SERVER_receive_done (client, GNUNET_OK);
1708 if (s->total != s->transferred_element_count)
1712 if (ALICE == s->role)
1713 client_request_complete_alice (s);
1715 client_request_complete_bob (s);
1720 * Handler for a client request message.
1721 * Can either be type A or B
1722 * A: request-initiation to compute a scalar product with a peer
1723 * B: response role, keep the values + session and wait for a matching session or process a waiting request
1725 * @param cls closure
1726 * @param client identification of the client
1727 * @param message the actual message
1730 handle_client_message (void *cls,
1731 struct GNUNET_SERVER_Client *client,
1732 const struct GNUNET_MessageHeader *message)
1734 const struct ComputationMessage * msg = (const struct ComputationMessage *) message;
1735 struct ServiceSession * s;
1736 uint32_t contained_count;
1737 uint32_t total_count;
1739 struct GNUNET_SCALARPRODUCT_Element * elements;
1742 // only one concurrent session per client connection allowed, simplifies logics a lot...
1743 s = GNUNET_SERVER_client_get_user_context (client, struct ServiceSession);
1746 GNUNET_SERVER_receive_done (client, GNUNET_OK);
1750 msg_type = ntohs (msg->header.type);
1751 total_count = ntohl (msg->element_count_total);
1752 contained_count = ntohl (msg->element_count_contained);
1754 if ((GNUNET_MESSAGE_TYPE_SCALARPRODUCT_CLIENT_TO_ALICE == msg_type)
1755 && (!memcmp (&msg->peer, &me, sizeof (struct GNUNET_PeerIdentity)))) {
1756 //session with ourself makes no sense!
1757 GNUNET_break_op (0);
1758 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
1762 //sanity check: is the message as long as the message_count fields suggests?
1763 if ((ntohs (msg->header.size) !=
1764 (sizeof (struct ComputationMessage) + contained_count * sizeof (struct GNUNET_SCALARPRODUCT_Element)))
1765 || (0 == total_count))
1767 GNUNET_break_op (0);
1768 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
1772 // do we have a duplicate session here already?
1773 if (NULL != find_matching_session (from_client_tail,
1776 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
1777 _ ("Duplicate session information received, can not create new session with key `%s'\n"),
1778 GNUNET_h2s (&msg->session_key));
1779 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
1783 s = GNUNET_new (struct ServiceSession);
1784 s->active = GNUNET_YES;
1785 s->client_notification_task = GNUNET_SCHEDULER_NO_TASK;
1787 s->total = total_count;
1788 s->transferred_element_count = contained_count;
1789 // get our transaction key
1790 memcpy (&s->session_id, &msg->session_key, sizeof (struct GNUNET_HashCode));
1792 elements = (struct GNUNET_SCALARPRODUCT_Element *) & msg[1];
1793 s->intersected_elements = GNUNET_CONTAINER_multihashmap_create (s->total, GNUNET_NO);
1794 s->intersection_set = GNUNET_SET_create (cfg, GNUNET_SET_OPERATION_INTERSECTION);
1795 for (i = 0; i < contained_count; i++) {
1796 struct GNUNET_SET_Element set_elem;
1797 struct GNUNET_SCALARPRODUCT_Element * elem;
1799 if (0 == GNUNET_ntohll (elements[i].value))
1802 elem = GNUNET_new (struct GNUNET_SCALARPRODUCT_Element);
1803 memcpy (elem, &elements[i], sizeof (struct GNUNET_SCALARPRODUCT_Element));
1805 if (GNUNET_SYSERR == GNUNET_CONTAINER_multihashmap_put (s->intersected_elements,
1808 GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY)) {
1812 set_elem.data = &elem->key;
1813 set_elem.size = sizeof (elem->key);
1814 set_elem.type = 0; /* do we REALLY need this? */
1815 GNUNET_SET_add_element (s->intersection_set, &set_elem, NULL, NULL);
1816 s->used_element_count++;
1819 if (GNUNET_MESSAGE_TYPE_SCALARPRODUCT_CLIENT_TO_ALICE == msg_type) {
1821 memcpy (&s->peer, &msg->peer, sizeof (struct GNUNET_PeerIdentity));
1827 GNUNET_CONTAINER_DLL_insert (from_client_head, from_client_tail, s);
1828 GNUNET_SERVER_client_set_user_context (client, s);
1829 GNUNET_SERVER_receive_done (client, GNUNET_YES);
1831 if (s->total != s->transferred_element_count)
1835 if (ALICE == s->role)
1836 client_request_complete_alice (s);
1838 client_request_complete_bob (s);
1843 * Function called for inbound channels.
1845 * @param cls closure
1846 * @param channel new handle to the channel
1847 * @param initiator peer that started the channel
1848 * @param port unused
1849 * @param options unused
1850 * @return session associated with the channel
1853 cb_channel_incoming (void *cls,
1854 struct GNUNET_CADET_Channel *channel,
1855 const struct GNUNET_PeerIdentity *initiator,
1857 enum GNUNET_CADET_ChannelOption options)
1859 struct ServiceSession *s = GNUNET_new (struct ServiceSession);
1861 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1862 _ ("New incoming channel from peer %s.\n"),
1863 GNUNET_i2s (initiator));
1864 s->peer = *initiator;
1865 s->channel = channel;
1867 s->active = GNUNET_YES;
1873 * Function called whenever a channel is destroyed. Should clean up
1874 * any associated state.
1876 * It must NOT call GNUNET_CADET_channel_destroy on the channel.
1878 * @param cls closure (set from GNUNET_CADET_connect)
1879 * @param channel connection to the other end (henceforth invalid)
1880 * @param channel_ctx place where local state associated
1881 * with the channel is stored
1884 cb_channel_destruction (void *cls,
1885 const struct GNUNET_CADET_Channel *channel,
1888 struct ServiceSession * s = channel_ctx;
1889 struct ServiceSession * client_session;
1891 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1892 _ ("Peer disconnected, terminating session %s with peer (%s)\n"),
1893 GNUNET_h2s (&s->session_id),
1894 GNUNET_i2s (&s->peer));
1896 // as we have only one peer connected in each session, just remove the session
1899 if ((ALICE == s->role) && (GNUNET_YES == s->active) && (!do_shutdown))
1901 // if this happened before we received the answer, we must terminate the session
1902 s->role = GNUNET_SYSERR;
1903 s->client_notification_task =
1904 GNUNET_SCHEDULER_add_now (&prepare_client_end_notification,
1907 else if ((BOB == s->role) && (GNUNET_SYSERR != s->active))
1909 if ((s == from_service_head) || ((NULL != from_service_head) && ((NULL != s->next) || (NULL != s->a_tail))))
1910 GNUNET_CONTAINER_DLL_remove (from_service_head, from_service_tail, s);
1912 // there is a client waiting for this service session, terminate it, too!
1913 // i assume the tupel of key and element count is unique. if it was not the rest of the code would not work either.
1914 client_session = s->response;
1915 if ((NULL != s->response ) && (GNUNET_NO == s->active) && (GNUNET_YES == client_session->active))
1916 client_session->active = GNUNET_NO;
1917 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,
1933 * Compute our scalar product, done by Alice
1935 * @param session - the session associated with this computation
1936 * @return product as MPI, never NULL
1939 compute_scalar_product (struct ServiceSession *session)
1948 gcry_mpi_t r[session->used_element_count];
1949 gcry_mpi_t r_prime[session->used_element_count];
1954 count = session->used_element_count;
1955 // due to the introduced static offset S, we now also have to remove this
1956 // from the E(a_pi)(+)E(-b_pi-r_pi) and E(a_qi)(+)E(-r_qi) twice each,
1957 // the result is E((S + a_pi) + (S -b_pi-r_pi)) and E(S + a_qi + S - r_qi)
1958 for (i = 0; i < count; i++)
1960 GNUNET_CRYPTO_paillier_decrypt (&my_privkey, &my_pubkey,
1961 &session->r[i], r[i]);
1962 gcry_mpi_sub (r[i], r[i], my_offset);
1963 gcry_mpi_sub (r[i], r[i], my_offset);
1964 GNUNET_CRYPTO_paillier_decrypt (&my_privkey, &my_pubkey,
1965 &session->r_prime[i], r_prime[i]);
1966 gcry_mpi_sub (r_prime[i], r_prime[i], my_offset);
1967 gcry_mpi_sub (r_prime[i], r_prime[i], my_offset);
1970 // calculate t = sum(ai)
1971 t = compute_square_sum (session->sorted_elements, count);
1974 u = gcry_mpi_new (0);
1975 tmp = compute_square_sum (r, count);
1976 gcry_mpi_sub (u, u, tmp);
1977 gcry_mpi_release (tmp);
1980 u_prime = gcry_mpi_new (0);
1981 tmp = compute_square_sum (r_prime, count);
1982 gcry_mpi_sub (u_prime, u_prime, tmp);
1984 GNUNET_assert (p = gcry_mpi_new (0));
1985 GNUNET_assert (p_prime = gcry_mpi_new (0));
1986 GNUNET_assert (s = gcry_mpi_new (0));
1987 GNUNET_assert (s_prime = gcry_mpi_new (0));
1990 GNUNET_CRYPTO_paillier_decrypt (&my_privkey, &my_pubkey,
1992 GNUNET_CRYPTO_paillier_decrypt (&my_privkey, &my_pubkey,
1993 session->s_prime, s_prime);
1996 gcry_mpi_add (p, s, t);
1997 gcry_mpi_add (p, p, u);
2000 gcry_mpi_add (p_prime, s_prime, t);
2001 gcry_mpi_add (p_prime, p_prime, u_prime);
2003 gcry_mpi_release (t);
2004 gcry_mpi_release (u);
2005 gcry_mpi_release (u_prime);
2006 gcry_mpi_release (s);
2007 gcry_mpi_release (s_prime);
2010 gcry_mpi_sub (p, p, p_prime);
2011 gcry_mpi_release (p_prime);
2012 tmp = gcry_mpi_set_ui (tmp, 2);
2013 gcry_mpi_div (p, NULL, p, tmp, 0);
2015 gcry_mpi_release (tmp);
2016 for (i = 0; i < count; i++)
2018 gcry_mpi_release (session->sorted_elements[i]);
2019 gcry_mpi_release (r[i]);
2020 gcry_mpi_release (r_prime[i]);
2022 GNUNET_free (session->a_head);
2023 session->a_head = NULL;
2024 GNUNET_free (session->s);
2026 GNUNET_free (session->s_prime);
2027 session->s_prime = NULL;
2028 GNUNET_free (session->r);
2030 GNUNET_free (session->r_prime);
2031 session->r_prime = NULL;
2038 * Handle a multipart-chunk of a request from another service to calculate a scalarproduct with us.
2040 * @param cls closure (set from #GNUNET_CADET_connect)
2041 * @param channel connection to the other end
2042 * @param channel_ctx place to store local state associated with the channel
2043 * @param message the actual message
2044 * @return #GNUNET_OK to keep the connection open,
2045 * #GNUNET_SYSERR to close it (signal serious error)
2048 handle_alices_cyrptodata_message_multipart (void *cls,
2049 struct GNUNET_CADET_Channel * channel,
2051 const struct GNUNET_MessageHeader * message)
2053 struct ServiceSession * s;
2054 const struct MultipartMessage * msg = (const struct MultipartMessage *) message;
2055 struct GNUNET_CRYPTO_PaillierCiphertext *payload;
2056 uint32_t contained_elements;
2057 uint32_t msg_length;
2059 // are we in the correct state?
2060 s = (struct ServiceSession *) * channel_ctx;
2062 if ((NULL == s->e_a) || //or we did not expect this message yet
2063 (s->used_element_count == s->transferred_element_count))
2064 { //we are not expecting multipart messages
2067 // shorter than minimum?
2068 if (ntohs (msg->header.size) <= sizeof (struct MultipartMessage))
2072 contained_elements = ntohl (msg->contained_element_count);
2073 msg_length = sizeof (struct MultipartMessage)
2074 +contained_elements * sizeof (struct GNUNET_CRYPTO_PaillierCiphertext);
2076 if ((ntohs (msg->header.size) != msg_length)
2077 || (s->used_element_count < contained_elements + s->transferred_element_count)
2078 || (0 == contained_elements))
2082 payload = (struct GNUNET_CRYPTO_PaillierCiphertext *) &msg[1];
2083 // Convert each vector element to MPI_value
2084 memcpy (&s->e_a[s->transferred_element_count], payload,
2085 sizeof (struct GNUNET_CRYPTO_PaillierCiphertext) * contained_elements);
2087 s->transferred_element_count += contained_elements;
2089 if (contained_elements == s->used_element_count)
2091 // single part finished
2092 if (NULL == s->intersection_op)
2093 // intersection has already finished, so we can proceed
2094 compute_service_response (s);
2100 // and notify our client-session that we could not complete the session
2101 free_session_variables (s);
2102 if (NULL != s->client)
2105 s->active = GNUNET_SYSERR;
2106 s->client_notification_task =
2107 GNUNET_SCHEDULER_add_now (&prepare_client_end_notification,
2113 if (NULL != s->response){
2114 s->response->active = GNUNET_SYSERR;
2115 s->response->client_notification_task =
2116 GNUNET_SCHEDULER_add_now (&prepare_client_end_notification,
2119 if ((s == from_service_head) || ((NULL != from_service_head) && ((NULL != s->next) || (NULL != s->a_tail))))
2120 GNUNET_CONTAINER_DLL_remove (from_service_head, from_service_tail, s);
2123 return GNUNET_SYSERR;
2128 * Handle a request from another service to calculate a scalarproduct with us.
2130 * @param cls closure (set from #GNUNET_CADET_connect)
2131 * @param channel connection to the other end
2132 * @param channel_ctx place to store local state associated with the channel
2133 * @param message the actual message
2134 * @return #GNUNET_OK to keep the connection open,
2135 * #GNUNET_SYSERR to close it (signal serious error)
2138 handle_alices_cyrptodata_message (void *cls,
2139 struct GNUNET_CADET_Channel * channel,
2141 const struct GNUNET_MessageHeader * message)
2143 struct ServiceSession * s;
2144 const struct AliceCryptodataMessage * msg = (const struct AliceCryptodataMessage *) message;
2145 struct GNUNET_CRYPTO_PaillierCiphertext *payload;
2146 uint32_t contained_elements = 0;
2147 uint32_t msg_length;
2149 s = (struct ServiceSession *) * channel_ctx;
2151 if ((BOB != s->role)
2152 //we are expecting multipart messages instead
2154 //or we did not expect this message yet
2155 || //intersection OP has not yet finished
2156 !((NULL != s->intersection_op)
2157 //intersection OP done
2158 || (s->response->sorted_elements)
2164 // shorter than minimum?
2165 if (ntohs (msg->header.size) <= sizeof (struct MultipartMessage))
2170 contained_elements = ntohl (msg->contained_element_count);
2171 msg_length = sizeof (struct AliceCryptodataMessage)
2172 +contained_elements * sizeof (struct GNUNET_CRYPTO_PaillierCiphertext);
2174 //sanity check: is the message as long as the message_count fields suggests?
2175 if ((ntohs (msg->header.size) != msg_length) ||
2176 (s->used_element_count < s->transferred_element_count + contained_elements) ||
2177 (0 == contained_elements))
2182 s->transferred_element_count = contained_elements;
2183 payload = (struct GNUNET_CRYPTO_PaillierCiphertext*) &msg[1];
2185 s->e_a = GNUNET_malloc (sizeof (struct GNUNET_CRYPTO_PaillierCiphertext) * s->used_element_count);
2186 memcpy (&s->e_a[0], payload, contained_elements * sizeof (struct GNUNET_CRYPTO_PaillierCiphertext));
2187 if (contained_elements == s->used_element_count)
2189 // single part finished
2190 if (NULL == s->intersection_op)
2191 // intersection has already finished, so we can proceed
2192 compute_service_response (s);
2196 GNUNET_break_op (0);
2198 // and notify our client-session that we could not complete the session
2199 free_session_variables (s);
2200 if (NULL != s->client)
2203 s->active = GNUNET_SYSERR;
2204 s->client_notification_task =
2205 GNUNET_SCHEDULER_add_now (&prepare_client_end_notification,
2211 if (NULL != s->response)
2213 s->response->active = GNUNET_SYSERR;
2214 s->response->client_notification_task =
2215 GNUNET_SCHEDULER_add_now (&prepare_client_end_notification,
2218 if ((s == from_service_head) || ((NULL != from_service_head) && ((NULL != s->next) || (NULL != s->a_tail))))
2219 GNUNET_CONTAINER_DLL_remove (from_service_head, from_service_tail, s);
2222 return GNUNET_SYSERR;
2227 * Handle a request from another service to calculate a scalarproduct with us.
2229 * @param cls closure (set from #GNUNET_CADET_connect)
2230 * @param channel connection to the other end
2231 * @param channel_ctx place to store local state associated with the channel
2232 * @param message the actual message
2233 * @return #GNUNET_OK to keep the connection open,
2234 * #GNUNET_SYSERR to close it (signal serious error)
2237 handle_alices_computation_request (void *cls,
2238 struct GNUNET_CADET_Channel * channel,
2240 const struct GNUNET_MessageHeader * message)
2242 struct ServiceSession * s;
2243 struct ServiceSession * client_session;
2244 const struct ServiceRequestMessage * msg = (const struct ServiceRequestMessage *) message;
2246 s = (struct ServiceSession *) * channel_ctx;
2247 if ((BOB != s->role) || (s->total != 0))
2249 // must be a fresh session
2252 // Check if message was sent by me, which would be bad!
2253 if (!memcmp (&s->peer, &me, sizeof (struct GNUNET_PeerIdentity)))
2257 return GNUNET_SYSERR;
2259 // shorter than expected?
2260 if (ntohs (msg->header.size) != sizeof (struct ServiceRequestMessage))
2263 GNUNET_break_op (0);
2264 return GNUNET_SYSERR;
2266 if (find_matching_session (from_service_tail,
2269 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
2270 _ ("Got message with duplicate session key (`%s'), ignoring service request.\n"),
2271 (const char *) &(msg->session_id));
2273 return GNUNET_SYSERR;
2276 s->channel = channel;
2279 memcpy (&s->session_id, &msg->session_id, sizeof (struct GNUNET_HashCode));
2282 s->remote_pubkey = GNUNET_new (struct GNUNET_CRYPTO_PaillierPublicKey);
2283 memcpy (s->remote_pubkey, &msg->public_key, sizeof (struct GNUNET_CRYPTO_PaillierPublicKey));
2285 //check if service queue contains a matching request
2286 client_session = find_matching_session (from_client_tail,
2290 GNUNET_CONTAINER_DLL_insert (from_service_head, from_service_tail, s);
2292 if ((NULL != client_session)
2293 && (client_session->transferred_element_count == client_session->total))
2296 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
2297 _("Got session with key %s and a matching element set, processing.\n"),
2298 GNUNET_h2s (&s->session_id));
2300 s->response = client_session;
2301 s->intersected_elements = client_session->intersected_elements;
2302 client_session->intersected_elements = NULL;
2303 s->intersection_set = client_session->intersection_set;
2304 client_session->intersection_set = NULL;
2306 s->intersection_op = GNUNET_SET_prepare (&s->peer,
2309 GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_WEAK, UINT16_MAX),
2310 GNUNET_SET_RESULT_REMOVED,
2311 cb_intersection_element_removed,
2314 GNUNET_SET_commit (s->intersection_op, s->intersection_set);
2318 GNUNET_log (GNUNET_ERROR_TYPE_INFO, _ ("Got session with key %s without a matching element set, queueing.\n"), GNUNET_h2s (&s->session_id));
2323 GNUNET_break_op (0);
2325 // and notify our client-session that we could not complete the session
2326 free_session_variables (s);
2327 if (NULL != s->client)
2330 s->active = GNUNET_SYSERR;
2331 s->client_notification_task =
2332 GNUNET_SCHEDULER_add_now (&prepare_client_end_notification,
2338 if (NULL != s->response) {
2339 s->response->active = GNUNET_SYSERR;
2340 s->response->client_notification_task =
2341 GNUNET_SCHEDULER_add_now (&prepare_client_end_notification,
2344 if ((s == from_service_head) || ((NULL != from_service_head) && ((NULL != s->next) || (NULL != s->a_tail))))
2345 GNUNET_CONTAINER_DLL_remove (from_service_head, from_service_tail, s);
2348 return GNUNET_SYSERR;
2353 * Handle a multipart chunk of a response we got from another service we wanted to calculate a scalarproduct with.
2355 * @param cls closure (set from #GNUNET_CADET_connect)
2356 * @param channel connection to the other end
2357 * @param channel_ctx place to store local state associated with the channel
2358 * @param message the actual message
2359 * @return #GNUNET_OK to keep the connection open,
2360 * #GNUNET_SYSERR to close it (signal serious error)
2363 handle_bobs_cryptodata_multipart (void *cls,
2364 struct GNUNET_CADET_Channel * channel,
2366 const struct GNUNET_MessageHeader * message)
2368 struct ServiceSession * s;
2369 const struct MultipartMessage * msg = (const struct MultipartMessage *) message;
2370 struct GNUNET_CRYPTO_PaillierCiphertext * payload;
2372 uint32_t contained = 0;
2374 size_t required_size;
2376 GNUNET_assert (NULL != message);
2377 // are we in the correct state?
2378 s = (struct ServiceSession *) * channel_ctx;
2379 if ((ALICE != s->role) || (NULL == s->sorted_elements))
2383 msg_size = ntohs (msg->header.size);
2384 required_size = sizeof (struct MultipartMessage)
2385 + 2 * sizeof (struct GNUNET_CRYPTO_PaillierCiphertext);
2386 // shorter than minimum?
2387 if (required_size > msg_size)
2391 contained = ntohl (msg->contained_element_count);
2392 required_size = sizeof (struct MultipartMessage)
2393 + 2 * contained * sizeof (struct GNUNET_CRYPTO_PaillierCiphertext);
2394 //sanity check: is the message as long as the message_count fields suggests?
2395 if ((required_size != msg_size) || (s->used_element_count < s->transferred_element_count + contained))
2399 payload = (struct GNUNET_CRYPTO_PaillierCiphertext *) &msg[1];
2400 // Convert each k[][perm] to its MPI_value
2401 for (i = 0; i < contained; i++) {
2402 memcpy (&s->r[s->transferred_element_count + i], &payload[2 * i], sizeof (struct GNUNET_CRYPTO_PaillierCiphertext));
2403 memcpy (&s->r_prime[s->transferred_element_count + i], &payload[2 * i], sizeof (struct GNUNET_CRYPTO_PaillierCiphertext));
2405 s->transferred_element_count += contained;
2406 if (s->transferred_element_count != s->used_element_count)
2408 s->product = compute_scalar_product (s); //never NULL
2411 GNUNET_break_op (NULL != s->product);
2413 // send message with product to client
2414 if (NULL != s->client)
2417 if (NULL != s->product)
2418 s->active = GNUNET_NO;
2420 s->active = GNUNET_SYSERR;
2421 s->client_notification_task =
2422 GNUNET_SCHEDULER_add_now (&prepare_client_response,
2428 if (NULL != s->response){
2429 s->response->active = GNUNET_SYSERR;
2430 s->response->client_notification_task =
2431 GNUNET_SCHEDULER_add_now (&prepare_client_end_notification,
2434 if ((s == from_service_head) || ((NULL != from_service_head) && ((NULL != s->next) || (NULL != s->a_tail))))
2435 GNUNET_CONTAINER_DLL_remove (from_service_head, from_service_tail, s);
2436 free_session_variables (s);
2439 // the channel has done its job, terminate our connection and the channel
2440 // the peer will be notified that the channel was destroyed via channel_destruction_handler
2441 // just close the connection, as recommended by Christian
2442 return GNUNET_SYSERR;
2447 * Handle a response we got from another service we wanted to calculate a scalarproduct with.
2449 * @param cls closure (set from #GNUNET_CADET_connect)
2450 * @param channel connection to the other end
2451 * @param channel_ctx place to store local state associated with the channel
2452 * @param message the actual message
2453 * @return #GNUNET_OK to keep the connection open,
2454 * #GNUNET_SYSERR to close it (we are done)
2457 handle_bobs_cryptodata_message (void *cls,
2458 struct GNUNET_CADET_Channel *channel,
2460 const struct GNUNET_MessageHeader *message)
2462 struct ServiceSession * s;
2463 const struct ServiceResponseMessage *msg = (const struct ServiceResponseMessage *) message;
2464 struct GNUNET_CRYPTO_PaillierCiphertext * payload;
2466 uint32_t contained = 0;
2468 size_t required_size;
2470 GNUNET_assert (NULL != message);
2471 s = (struct ServiceSession *) * channel_ctx;
2472 // are we in the correct state?
2473 if (NULL == s->sorted_elements
2475 || s->used_element_count != s->transferred_element_count)
2479 //we need at least a full message without elements attached
2480 msg_size = ntohs (msg->header.size);
2481 required_size = sizeof (struct ServiceResponseMessage) + 2 * sizeof (struct GNUNET_CRYPTO_PaillierCiphertext);
2483 if (required_size > msg_size)
2487 contained = ntohl (msg->contained_element_count);
2488 required_size = sizeof (struct ServiceResponseMessage)
2489 + 2 * contained * sizeof (struct GNUNET_CRYPTO_PaillierCiphertext)
2490 + 2 * sizeof (struct GNUNET_CRYPTO_PaillierCiphertext);
2491 //sanity check: is the message as long as the message_count fields suggests?
2492 if ((msg_size != required_size) || (s->used_element_count < contained))
2496 s->transferred_element_count = contained;
2498 payload = (struct GNUNET_CRYPTO_PaillierCiphertext *) &msg[1];
2500 s->s = GNUNET_malloc (sizeof (struct GNUNET_CRYPTO_PaillierCiphertext));
2501 s->s_prime = GNUNET_malloc (sizeof (struct GNUNET_CRYPTO_PaillierCiphertext));
2502 memcpy (s->s, &payload[0], sizeof (struct GNUNET_CRYPTO_PaillierCiphertext));
2503 memcpy (s->s_prime, &payload[1], sizeof (struct GNUNET_CRYPTO_PaillierCiphertext));
2505 s->r = GNUNET_malloc (sizeof (struct GNUNET_CRYPTO_PaillierCiphertext) * s->used_element_count);
2506 s->r_prime = GNUNET_malloc (sizeof (struct GNUNET_CRYPTO_PaillierCiphertext) * s->used_element_count);
2508 payload = &payload[2];
2509 // Convert each k[][perm] to its MPI_value
2510 for (i = 0; i < contained; i++)
2512 memcpy (&s->r[i], &payload[2 * i], sizeof (struct GNUNET_CRYPTO_PaillierCiphertext));
2513 memcpy (&s->r_prime[i], &payload[2 * i + 1], sizeof (struct GNUNET_CRYPTO_PaillierCiphertext));
2515 if (s->transferred_element_count != s->used_element_count)
2516 return GNUNET_OK; //wait for the other multipart chunks
2517 s->product = compute_scalar_product (s); //never NULL
2520 GNUNET_break_op (NULL != s->product);
2522 // send message with product to client
2523 if (NULL != s->client)
2526 s->client_notification_task =
2527 GNUNET_SCHEDULER_add_now (&prepare_client_response,
2533 if (NULL != s->response)
2535 s->response->active = GNUNET_SYSERR;
2536 s->response->client_notification_task =
2537 GNUNET_SCHEDULER_add_now (&prepare_client_end_notification,
2540 if ((s == from_service_head) || ((NULL != from_service_head) && ((NULL != s->next) || (NULL != s->a_tail))))
2541 GNUNET_CONTAINER_DLL_remove (from_service_head, from_service_tail, s);
2542 free_session_variables (s);
2545 // the channel has done its job, terminate our connection and the channel
2546 // the peer will be notified that the channel was destroyed via channel_destruction_handler
2547 // just close the connection, as recommended by Christian
2548 return GNUNET_SYSERR;
2553 * Task run during shutdown.
2559 shutdown_task (void *cls,
2560 const struct GNUNET_SCHEDULER_TaskContext *tc)
2562 struct ServiceSession * s;
2564 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
2565 _("Shutting down, initiating cleanup.\n"));
2567 do_shutdown = GNUNET_YES;
2569 // terminate all owned open channels.
2570 for (s = from_client_head; NULL != s; s = s->next)
2572 if ((GNUNET_NO != s->active) && (NULL != s->channel))
2574 GNUNET_CADET_channel_destroy (s->channel);
2577 if (GNUNET_SCHEDULER_NO_TASK != s->client_notification_task)
2579 GNUNET_SCHEDULER_cancel (s->client_notification_task);
2580 s->client_notification_task = GNUNET_SCHEDULER_NO_TASK;
2582 if (NULL != s->client)
2584 GNUNET_SERVER_client_disconnect (s->client);
2588 for (s = from_service_head; NULL != s; s = s->next)
2589 if (NULL != s->channel)
2591 GNUNET_CADET_channel_destroy (s->channel);
2597 GNUNET_CADET_disconnect (my_cadet);
2604 * Initialization of the program and message handlers
2606 * @param cls closure
2607 * @param server the initialized server
2608 * @param c configuration to use
2612 struct GNUNET_SERVER_Handle *server,
2613 const struct GNUNET_CONFIGURATION_Handle *c)
2615 static const struct GNUNET_SERVER_MessageHandler server_handlers[] = {
2616 {&handle_client_message, NULL, GNUNET_MESSAGE_TYPE_SCALARPRODUCT_CLIENT_TO_ALICE, 0},
2617 {&handle_client_message, NULL, GNUNET_MESSAGE_TYPE_SCALARPRODUCT_CLIENT_TO_BOB, 0},
2618 {&handle_client_message_multipart, NULL, GNUNET_MESSAGE_TYPE_SCALARPRODUCT_CLIENT_MUTLIPART, 0},
2621 static const struct GNUNET_CADET_MessageHandler cadet_handlers[] = {
2622 { &handle_alices_computation_request, GNUNET_MESSAGE_TYPE_SCALARPRODUCT_SESSION_INITIALIZATION, 0},
2623 { &handle_alices_cyrptodata_message, GNUNET_MESSAGE_TYPE_SCALARPRODUCT_ALICE_CRYPTODATA, 0},
2624 { &handle_alices_cyrptodata_message_multipart, GNUNET_MESSAGE_TYPE_SCALARPRODUCT_ALICE_CRYPTODATA_MULTIPART, 0},
2625 { &handle_bobs_cryptodata_message, GNUNET_MESSAGE_TYPE_SCALARPRODUCT_BOB_CRYPTODATA, 0},
2626 { &handle_bobs_cryptodata_multipart, GNUNET_MESSAGE_TYPE_SCALARPRODUCT_BOB_CRYPTODATA_MULTIPART, 0},
2629 static const uint32_t ports[] = {
2630 GNUNET_APPLICATION_TYPE_SCALARPRODUCT,
2635 //generate private/public key set
2636 GNUNET_CRYPTO_paillier_create (&my_pubkey, &my_privkey);
2638 // offset has to be sufficiently small to allow computation of:
2639 // m1+m2 mod n == (S + a) + (S + b) mod n,
2640 // if we have more complex operations, this factor needs to be lowered
2641 my_offset = gcry_mpi_new (GNUNET_CRYPTO_PAILLIER_BITS / 3);
2642 gcry_mpi_set_bit (my_offset, GNUNET_CRYPTO_PAILLIER_BITS / 3);
2644 // register server callbacks and disconnect handler
2645 GNUNET_SERVER_add_handlers (server, server_handlers);
2646 GNUNET_SERVER_disconnect_notify (server,
2647 &cb_client_disconnect,
2649 GNUNET_break (GNUNET_OK ==
2650 GNUNET_CRYPTO_get_peer_identity (cfg,
2652 my_cadet = GNUNET_CADET_connect (cfg, NULL,
2653 &cb_channel_incoming,
2654 &cb_channel_destruction,
2655 cadet_handlers, ports);
2658 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
2659 _("Connect to CADET failed\n"));
2660 GNUNET_SCHEDULER_shutdown ();
2663 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
2664 _("CADET initialized\n"));
2665 GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_FOREVER_REL,
2672 * The main function for the scalarproduct service.
2674 * @param argc number of arguments from the command line
2675 * @param argv command line arguments
2676 * @return 0 ok, 1 on error
2679 main (int argc, char *const *argv)
2681 return (GNUNET_OK ==
2682 GNUNET_SERVICE_run (argc, argv,
2684 GNUNET_SERVICE_OPTION_NONE,
2685 &run, NULL)) ? 0 : 1;
2688 /* end of gnunet-service-scalarproduct.c */