2 This file is part of GNUnet.
3 Copyright (C) 2013-2015 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., 51 Franklin Street, Fifth Floor,
18 Boston, MA 02110-1301, USA.
21 * @file scalarproduct/gnunet-service-scalarproduct-ecc_alice.c
22 * @brief scalarproduct service implementation
23 * @author Christian M. Fuchs
24 * @author Christian Grothoff
29 #include "gnunet_util_lib.h"
30 #include "gnunet_core_service.h"
31 #include "gnunet_cadet_service.h"
32 #include "gnunet_applications.h"
33 #include "gnunet_protocols.h"
34 #include "gnunet_scalarproduct_service.h"
35 #include "gnunet_set_service.h"
36 #include "scalarproduct.h"
37 #include "gnunet-service-scalarproduct-ecc.h"
39 #define LOG(kind,...) GNUNET_log_from (kind, "scalarproduct-alice", __VA_ARGS__)
42 * Maximum allowed result value for the scalarproduct computation.
43 * DLOG will fail if the result is bigger. At 1 million, the
44 * precomputation takes about 2s on a fast machine.
46 #define MAX_RESULT (1024 * 1024)
49 * How many values should DLOG store in memory (determines baseline
50 * RAM consumption, roughly 100 bytes times the value given here).
51 * Should be about SQRT (MAX_RESULT), larger values will make the
52 * online computation faster.
54 #define MAX_RAM (1024)
57 * An encrypted element key-value pair.
62 * Key used to identify matching pairs of values to multiply.
63 * Points into an existing data structure, to avoid copying
64 * and doubling memory use.
66 const struct GNUNET_HashCode *key;
69 * a_i value, not disclosed to Bob.
77 * A scalarproduct session which tracks
78 * a request form the client to our final response.
80 struct AliceServiceSession
84 * (hopefully) unique transaction ID
86 struct GNUNET_HashCode session_id;
89 * Alice or Bob's peerID
91 struct GNUNET_PeerIdentity peer;
94 * The client this request is related to.
96 struct GNUNET_SERVER_Client *client;
99 * The message queue for the client.
101 struct GNUNET_MQ_Handle *client_mq;
104 * The message queue for CADET.
106 struct GNUNET_MQ_Handle *cadet_mq;
109 * all non-0-value'd elements transmitted to us.
110 * Values are of type `struct GNUNET_SCALARPRODUCT_Element *`
112 struct GNUNET_CONTAINER_MultiHashMap *intersected_elements;
115 * Set of elements for which will conduction an intersection.
116 * the resulting elements are then used for computing the scalar product.
118 struct GNUNET_SET_Handle *intersection_set;
121 * Set of elements for which will conduction an intersection.
122 * the resulting elements are then used for computing the scalar product.
124 struct GNUNET_SET_OperationHandle *intersection_op;
127 * Handle to Alice's Intersection operation listening for Bob
129 struct GNUNET_SET_ListenHandle *intersection_listen;
132 * channel-handle associated with our cadet handle
134 struct GNUNET_CADET_Channel *channel;
137 * a(Alice), sorted array by key of length @e used_element_count.
139 struct MpiElement *sorted_elements;
142 * The computed scalar
147 * How many elements we were supplied with from the client (total
148 * count before intersection).
153 * How many elements actually are used for the scalar product.
154 * Size of the arrays in @e r and @e r_prime. Sometimes also
155 * reset to 0 and used as a counter!
157 uint32_t used_element_count;
160 * Already transferred elements from client to us.
161 * Less or equal than @e total.
163 uint32_t client_received_element_count;
166 * State of this session. In
167 * #GNUNET_SCALARPRODUCT_STATUS_ACTIVE while operation is
168 * ongoing, afterwards in #GNUNET_SCALARPRODUCT_STATUS_SUCCESS or
169 * #GNUNET_SCALARPRODUCT_STATUS_FAILURE.
171 enum GNUNET_SCALARPRODUCT_ResponseStatus status;
174 * Flag to prevent recursive calls to #destroy_service_session() from
183 * GNUnet configuration handle
185 static const struct GNUNET_CONFIGURATION_Handle *cfg;
188 * Context for DLOG operations on a curve.
190 static struct GNUNET_CRYPTO_EccDlogContext *edc;
193 * Alice's private key ('a').
195 static gcry_mpi_t my_privkey;
198 * Inverse of Alice's private key ('a_inv').
200 static gcry_mpi_t my_privkey_inv;
203 * Handle to the CADET service.
205 static struct GNUNET_CADET_Handle *my_cadet;
209 * Iterator called to free elements.
211 * @param cls the `struct AliceServiceSession *` (unused)
212 * @param key the key (unused)
213 * @param value value to free
214 * @return #GNUNET_OK (continue to iterate)
217 free_element_cb (void *cls,
218 const struct GNUNET_HashCode *key,
221 struct GNUNET_SCALARPRODUCT_Element *e = value;
229 * Destroy session state, we are done with it.
231 * @param s the session to free elements from
234 destroy_service_session (struct AliceServiceSession *s)
238 if (GNUNET_YES == s->in_destroy)
240 s->in_destroy = GNUNET_YES;
241 if (NULL != s->client_mq)
243 GNUNET_MQ_destroy (s->client_mq);
246 if (NULL != s->cadet_mq)
248 GNUNET_MQ_destroy (s->cadet_mq);
251 if (NULL != s->client)
253 GNUNET_SERVER_client_set_user_context (s->client,
255 GNUNET_SERVER_client_disconnect (s->client);
258 if (NULL != s->channel)
260 GNUNET_CADET_channel_destroy (s->channel);
263 if (NULL != s->intersected_elements)
265 GNUNET_CONTAINER_multihashmap_iterate (s->intersected_elements,
268 GNUNET_CONTAINER_multihashmap_destroy (s->intersected_elements);
269 s->intersected_elements = NULL;
271 if (NULL != s->intersection_listen)
273 GNUNET_SET_listen_cancel (s->intersection_listen);
274 s->intersection_listen = NULL;
276 if (NULL != s->intersection_op)
278 GNUNET_SET_operation_cancel (s->intersection_op);
279 s->intersection_op = NULL;
281 if (NULL != s->intersection_set)
283 GNUNET_SET_destroy (s->intersection_set);
284 s->intersection_set = NULL;
286 if (NULL != s->sorted_elements)
288 for (i=0;i<s->used_element_count;i++)
289 gcry_mpi_release (s->sorted_elements[i].value);
290 GNUNET_free (s->sorted_elements);
291 s->sorted_elements = NULL;
293 if (NULL != s->product)
295 gcry_mpi_release (s->product);
303 * Notify the client that the session has failed. A message gets sent
304 * to Alice's client if we encountered any error.
306 * @param session the associated client session to fail or succeed
309 prepare_client_end_notification (struct AliceServiceSession *session)
311 struct ClientResponseMessage *msg;
312 struct GNUNET_MQ_Envelope *e;
314 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
315 "Sending session-end notification with status %d to client for session %s\n",
317 GNUNET_h2s (&session->session_id));
318 e = GNUNET_MQ_msg (msg,
319 GNUNET_MESSAGE_TYPE_SCALARPRODUCT_RESULT);
320 msg->product_length = htonl (0);
321 msg->status = htonl (session->status);
322 GNUNET_MQ_send (session->client_mq,
328 * Prepare the final (positive) response we will send to Alice's
331 * @param s the session associated with our client.
334 transmit_client_response (struct AliceServiceSession *s)
336 struct ClientResponseMessage *msg;
337 struct GNUNET_MQ_Envelope *e;
338 unsigned char *product_exported = NULL;
339 size_t product_length = 0;
345 if (NULL == s->product)
348 prepare_client_end_notification (s);
351 value = gcry_mpi_new (0);
352 sign = gcry_mpi_cmp_ui (s->product, 0);
363 gcry_mpi_add (value, value, s->product);
367 /* result is exactly zero */
370 gcry_mpi_release (s->product);
374 (0 != (rc = gcry_mpi_aprint (GCRYMPI_FMT_STD,
379 LOG_GCRY (GNUNET_ERROR_TYPE_ERROR,
382 prepare_client_end_notification (s);
385 gcry_mpi_release (value);
386 e = GNUNET_MQ_msg_extra (msg,
388 GNUNET_MESSAGE_TYPE_SCALARPRODUCT_RESULT);
389 msg->status = htonl (GNUNET_SCALARPRODUCT_STATUS_SUCCESS);
390 msg->range = htonl (range);
391 msg->product_length = htonl (product_length);
392 if (NULL != product_exported)
397 GNUNET_free (product_exported);
399 GNUNET_MQ_send (s->client_mq,
401 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
402 "Sent result to client, session %s has ended!\n",
403 GNUNET_h2s (&s->session_id));
409 * Function called whenever a channel is destroyed. Should clean up
410 * any associated state.
412 * It must NOT call #GNUNET_CADET_channel_destroy() on the channel.
414 * @param cls closure (set from #GNUNET_CADET_connect())
415 * @param channel connection to the other end (henceforth invalid)
416 * @param channel_ctx place where local state associated
417 * with the channel is stored
420 cb_channel_destruction (void *cls,
421 const struct GNUNET_CADET_Channel *channel,
424 struct AliceServiceSession *s = channel_ctx;
426 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
427 "Peer disconnected, terminating session %s with peer %s\n",
428 GNUNET_h2s (&s->session_id),
429 GNUNET_i2s (&s->peer));
430 if (NULL != s->cadet_mq)
432 GNUNET_MQ_destroy (s->cadet_mq);
436 if (GNUNET_SCALARPRODUCT_STATUS_ACTIVE == s->status)
438 /* We didn't get an answer yet, fail with error */
439 s->status = GNUNET_SCALARPRODUCT_STATUS_FAILURE;
440 prepare_client_end_notification (s);
446 * Compute our scalar product, done by Alice
448 * @param session the session associated with this computation
449 * @param prod_g_i_b_i value from Bob
450 * @param prod_h_i_b_i value from Bob
451 * @return product as MPI, never NULL
454 compute_scalar_product (struct AliceServiceSession *session,
455 gcry_mpi_point_t prod_g_i_b_i,
456 gcry_mpi_point_t prod_h_i_b_i)
458 gcry_mpi_point_t g_i_b_i_a_inv;
459 gcry_mpi_point_t g_ai_bi;
463 g_i_b_i_a_inv = GNUNET_CRYPTO_ecc_pmul_mpi (edc,
466 g_ai_bi = GNUNET_CRYPTO_ecc_add (edc,
469 gcry_mpi_point_release (g_i_b_i_a_inv);
470 ai_bi = GNUNET_CRYPTO_ecc_dlog (edc,
472 gcry_mpi_point_release (g_ai_bi);
473 if (MAX_RESULT == ai_bi)
476 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
477 "Scalar product result out of range\n");
480 ret = gcry_mpi_new (0);
483 gcry_mpi_set_ui (ret, ai_bi);
487 gcry_mpi_set_ui (ret, - ai_bi);
488 gcry_mpi_neg (ret, ret);
495 * Handle a response we got from another service we wanted to
496 * calculate a scalarproduct with.
498 * @param cls closure (set from #GNUNET_CADET_connect)
499 * @param channel connection to the other end
500 * @param channel_ctx place to store local state associated with the channel
501 * @param message the actual message
502 * @return #GNUNET_OK to keep the connection open,
503 * #GNUNET_SYSERR to close it (we are done)
506 handle_bobs_cryptodata_message (void *cls,
507 struct GNUNET_CADET_Channel *channel,
509 const struct GNUNET_MessageHeader *message)
511 struct AliceServiceSession *s = *channel_ctx;
512 const struct EccBobCryptodataMessage *msg;
515 gcry_mpi_point_t prod_g_i_b_i;
516 gcry_mpi_point_t prod_h_i_b_i;
521 return GNUNET_SYSERR;
523 msg_size = ntohs (message->size);
524 if (sizeof (struct EccBobCryptodataMessage) > msg_size)
527 return GNUNET_SYSERR;
529 msg = (const struct EccBobCryptodataMessage *) message;
530 contained = ntohl (msg->contained_element_count);
534 return GNUNET_SYSERR;
536 if (NULL == s->sorted_elements)
538 /* we're not ready yet, how can Bob be? */
540 return GNUNET_SYSERR;
542 if (s->total != s->client_received_element_count)
544 /* we're not ready yet, how can Bob be? */
546 return GNUNET_SYSERR;
548 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
549 "Received %u crypto values from Bob\n",
550 (unsigned int) contained);
551 GNUNET_CADET_receive_done (s->channel);
552 prod_g_i_b_i = GNUNET_CRYPTO_ecc_bin_to_point (edc,
554 prod_h_i_b_i = GNUNET_CRYPTO_ecc_bin_to_point (edc,
556 s->product = compute_scalar_product (s,
559 gcry_mpi_point_release (prod_g_i_b_i);
560 gcry_mpi_point_release (prod_h_i_b_i);
561 transmit_client_response (s);
567 * Iterator to copy over messages from the hash map
568 * into an array for sorting.
570 * @param cls the `struct AliceServiceSession *`
571 * @param key the key (unused)
572 * @param value the `struct GNUNET_SCALARPRODUCT_Element *`
575 copy_element_cb (void *cls,
576 const struct GNUNET_HashCode *key,
579 struct AliceServiceSession *s = cls;
580 struct GNUNET_SCALARPRODUCT_Element *e = value;
584 mval = gcry_mpi_new (0);
585 val = (int64_t) GNUNET_ntohll (e->value);
587 gcry_mpi_sub_ui (mval, mval, -val);
589 gcry_mpi_add_ui (mval, mval, val);
590 s->sorted_elements [s->used_element_count].value = mval;
591 s->sorted_elements [s->used_element_count].key = &e->key;
592 s->used_element_count++;
598 * Compare two `struct MpiValue`s by key for sorting.
600 * @param a pointer to first `struct MpiValue *`
601 * @param b pointer to first `struct MpiValue *`
602 * @return -1 for a < b, 0 for a=b, 1 for a > b.
605 element_cmp (const void *a,
608 const struct MpiElement *ma = a;
609 const struct MpiElement *mb = b;
611 return GNUNET_CRYPTO_hash_cmp (ma->key,
617 * Maximum number of elements we can put into a single cryptodata
620 #define ELEMENT_CAPACITY ((GNUNET_CONSTANTS_MAX_CADET_MESSAGE_SIZE - 1 - sizeof (struct EccAliceCryptodataMessage)) / sizeof (struct GNUNET_CRYPTO_EccPoint))
624 * Send the cryptographic data from Alice to Bob.
625 * Does nothing if we already transferred all elements.
627 * @param s the associated service session
630 send_alices_cryptodata_message (struct AliceServiceSession *s)
632 struct EccAliceCryptodataMessage *msg;
633 struct GNUNET_MQ_Envelope *e;
634 struct GNUNET_CRYPTO_EccPoint *payload;
639 unsigned int todo_count;
642 = GNUNET_malloc (GNUNET_CONTAINER_multihashmap_size (s->intersected_elements) *
643 sizeof (struct MpiElement));
644 s->used_element_count = 0;
645 GNUNET_CONTAINER_multihashmap_iterate (s->intersected_elements,
648 LOG (GNUNET_ERROR_TYPE_DEBUG,
649 "Finished intersection, %d items remain\n",
650 s->used_element_count);
651 qsort (s->sorted_elements,
652 s->used_element_count,
653 sizeof (struct MpiElement),
656 while (off < s->used_element_count)
658 todo_count = s->used_element_count - off;
659 if (todo_count > ELEMENT_CAPACITY)
660 todo_count = ELEMENT_CAPACITY;
661 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
662 "Sending %u/%u crypto values to Bob\n",
663 (unsigned int) todo_count,
664 (unsigned int) s->used_element_count);
666 e = GNUNET_MQ_msg_extra (msg,
667 todo_count * 2 * sizeof (struct GNUNET_CRYPTO_EccPoint),
668 GNUNET_MESSAGE_TYPE_SCALARPRODUCT_ECC_ALICE_CRYPTODATA);
669 msg->contained_element_count = htonl (todo_count);
670 payload = (struct GNUNET_CRYPTO_EccPoint *) &msg[1];
671 r_ia = gcry_mpi_new (0);
672 r_ia_ai = gcry_mpi_new (0);
673 for (i = off; i < off + todo_count; i++)
676 gcry_mpi_point_t g_i;
677 gcry_mpi_point_t h_i;
679 r_i = GNUNET_CRYPTO_ecc_random_mod_n (edc);
680 g_i = GNUNET_CRYPTO_ecc_dexp_mpi (edc,
686 gcry_mpi_release (r_i);
687 /* r_ia_ai = r_ia + a_i */
688 gcry_mpi_add (r_ia_ai,
690 s->sorted_elements[i].value);
691 h_i = GNUNET_CRYPTO_ecc_dexp_mpi (edc,
693 GNUNET_CRYPTO_ecc_point_to_bin (edc,
695 &payload[(i - off) * 2]);
696 GNUNET_CRYPTO_ecc_point_to_bin (edc,
698 &payload[(i - off) * 2 + 1]);
699 gcry_mpi_point_release (g_i);
700 gcry_mpi_point_release (h_i);
702 gcry_mpi_release (r_ia);
703 gcry_mpi_release (r_ia_ai);
705 GNUNET_MQ_send (s->cadet_mq,
712 * Callback for set operation results. Called for each element
713 * that should be removed from the result set, and then once
714 * to indicate that the set intersection operation is done.
716 * @param cls closure with the `struct AliceServiceSession`
717 * @param element a result element, only valid if status is #GNUNET_SET_STATUS_OK
718 * @param status what has happened with the set intersection?
721 cb_intersection_element_removed (void *cls,
722 const struct GNUNET_SET_Element *element,
723 enum GNUNET_SET_Status status)
725 struct AliceServiceSession *s = cls;
726 struct GNUNET_SCALARPRODUCT_Element *se;
730 case GNUNET_SET_STATUS_OK:
731 /* this element has been removed from the set */
732 se = GNUNET_CONTAINER_multihashmap_get (s->intersected_elements,
734 GNUNET_assert (NULL != se);
735 LOG (GNUNET_ERROR_TYPE_DEBUG,
736 "Intersection removed element with key %s and value %lld\n",
737 GNUNET_h2s (&se->key),
738 (long long) GNUNET_ntohll (se->value));
739 GNUNET_assert (GNUNET_YES ==
740 GNUNET_CONTAINER_multihashmap_remove (s->intersected_elements,
745 case GNUNET_SET_STATUS_DONE:
746 s->intersection_op = NULL;
747 if (NULL != s->intersection_set)
749 GNUNET_SET_destroy (s->intersection_set);
750 s->intersection_set = NULL;
752 send_alices_cryptodata_message (s);
754 case GNUNET_SET_STATUS_HALF_DONE:
755 /* unexpected for intersection */
758 case GNUNET_SET_STATUS_FAILURE:
759 /* unhandled status code */
760 LOG (GNUNET_ERROR_TYPE_DEBUG,
761 "Set intersection failed!\n");
762 if (NULL != s->intersection_listen)
764 GNUNET_SET_listen_cancel (s->intersection_listen);
765 s->intersection_listen = NULL;
767 s->intersection_op = NULL;
768 if (NULL != s->intersection_set)
770 GNUNET_SET_destroy (s->intersection_set);
771 s->intersection_set = NULL;
773 s->status = GNUNET_SCALARPRODUCT_STATUS_FAILURE;
774 prepare_client_end_notification (s);
784 * Called when another peer wants to do a set operation with the
785 * local peer. If a listen error occurs, the @a request is NULL.
787 * @param cls closure with the `struct AliceServiceSession *`
788 * @param other_peer the other peer
789 * @param context_msg message with application specific information from
791 * @param request request from the other peer (never NULL), use GNUNET_SET_accept()
792 * to accept it, otherwise the request will be refused
793 * Note that we can't just return value from the listen callback,
794 * as it is also necessary to specify the set we want to do the
795 * operation with, whith sometimes can be derived from the context
796 * message. It's necessary to specify the timeout.
799 cb_intersection_request_alice (void *cls,
800 const struct GNUNET_PeerIdentity *other_peer,
801 const struct GNUNET_MessageHeader *context_msg,
802 struct GNUNET_SET_Request *request)
804 struct AliceServiceSession *s = cls;
806 if (0 != memcmp (other_peer,
808 sizeof (struct GNUNET_PeerIdentity)))
814 = GNUNET_SET_accept (request,
815 GNUNET_SET_RESULT_REMOVED,
816 &cb_intersection_element_removed,
818 if (NULL == s->intersection_op)
821 s->status = GNUNET_SCALARPRODUCT_STATUS_FAILURE;
822 prepare_client_end_notification (s);
826 GNUNET_SET_commit (s->intersection_op,
827 s->intersection_set))
830 s->status = GNUNET_SCALARPRODUCT_STATUS_FAILURE;
831 prepare_client_end_notification (s);
834 GNUNET_SET_destroy (s->intersection_set);
835 s->intersection_set = NULL;
836 GNUNET_SET_listen_cancel (s->intersection_listen);
837 s->intersection_listen = NULL;
842 * Our client has finished sending us its multipart message.
844 * @param session the service session context
847 client_request_complete_alice (struct AliceServiceSession *s)
849 struct EccServiceRequestMessage *msg;
850 struct GNUNET_MQ_Envelope *e;
852 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
853 "Creating new channel for session with key %s.\n",
854 GNUNET_h2s (&s->session_id));
856 = GNUNET_CADET_channel_create (my_cadet,
859 GNUNET_APPLICATION_TYPE_SCALARPRODUCT_ECC,
860 GNUNET_CADET_OPTION_RELIABLE);
861 if (NULL == s->channel)
863 s->status = GNUNET_SCALARPRODUCT_STATUS_FAILURE;
864 prepare_client_end_notification (s);
867 s->cadet_mq = GNUNET_CADET_mq_create (s->channel);
868 s->intersection_listen
869 = GNUNET_SET_listen (cfg,
870 GNUNET_SET_OPERATION_INTERSECTION,
872 &cb_intersection_request_alice,
874 if (NULL == s->intersection_listen)
876 s->status = GNUNET_SCALARPRODUCT_STATUS_FAILURE;
877 GNUNET_CADET_channel_destroy (s->channel);
879 prepare_client_end_notification (s);
883 e = GNUNET_MQ_msg (msg,
884 GNUNET_MESSAGE_TYPE_SCALARPRODUCT_ECC_SESSION_INITIALIZATION);
885 msg->session_id = s->session_id;
886 GNUNET_MQ_send (s->cadet_mq,
892 * We're receiving additional set data. Add it to our
893 * set and if we are done, initiate the transaction.
896 * @param client identification of the client
897 * @param message the actual message
900 GSS_handle_alice_client_message_multipart (void *cls,
901 struct GNUNET_SERVER_Client *client,
902 const struct GNUNET_MessageHeader *message)
904 const struct ComputationBobCryptodataMultipartMessage * msg;
905 struct AliceServiceSession *s;
906 uint32_t contained_count;
907 const struct GNUNET_SCALARPRODUCT_Element *elements;
910 struct GNUNET_SET_Element set_elem;
911 struct GNUNET_SCALARPRODUCT_Element *elem;
913 s = GNUNET_SERVER_client_get_user_context (client,
914 struct AliceServiceSession);
917 /* session needs to already exist */
919 GNUNET_SERVER_receive_done (client,
923 msize = ntohs (message->size);
924 if (msize < sizeof (struct ComputationBobCryptodataMultipartMessage))
927 GNUNET_SERVER_receive_done (client,
931 msg = (const struct ComputationBobCryptodataMultipartMessage *) message;
932 contained_count = ntohl (msg->element_count_contained);
934 if ( (msize != (sizeof (struct ComputationBobCryptodataMultipartMessage) +
935 contained_count * sizeof (struct GNUNET_SCALARPRODUCT_Element))) ||
936 (0 == contained_count) ||
937 (s->total == s->client_received_element_count) ||
938 (s->total < s->client_received_element_count + contained_count) )
941 GNUNET_SERVER_receive_done (client,
945 s->client_received_element_count += contained_count;
946 elements = (const struct GNUNET_SCALARPRODUCT_Element *) &msg[1];
947 for (i = 0; i < contained_count; i++)
949 elem = GNUNET_new (struct GNUNET_SCALARPRODUCT_Element);
952 sizeof (struct GNUNET_SCALARPRODUCT_Element));
954 GNUNET_CONTAINER_multihashmap_put (s->intersected_elements,
957 GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY))
963 set_elem.data = &elem->key;
964 set_elem.size = sizeof (elem->key);
965 set_elem.element_type = 0;
966 GNUNET_SET_add_element (s->intersection_set,
969 s->used_element_count++;
971 GNUNET_SERVER_receive_done (client,
973 if (s->total != s->client_received_element_count)
978 client_request_complete_alice (s);
983 * Handler for Alice's client request message.
984 * We are doing request-initiation to compute a scalar product with a peer.
987 * @param client identification of the client
988 * @param message the actual message
991 GSS_handle_alice_client_message (void *cls,
992 struct GNUNET_SERVER_Client *client,
993 const struct GNUNET_MessageHeader *message)
995 const struct AliceComputationMessage *msg;
996 struct AliceServiceSession *s;
997 uint32_t contained_count;
998 uint32_t total_count;
999 const struct GNUNET_SCALARPRODUCT_Element *elements;
1002 struct GNUNET_SET_Element set_elem;
1003 struct GNUNET_SCALARPRODUCT_Element *elem;
1005 s = GNUNET_SERVER_client_get_user_context (client,
1006 struct AliceServiceSession);
1009 /* only one concurrent session per client connection allowed,
1010 simplifies logic a lot... */
1012 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
1015 msize = ntohs (message->size);
1016 if (msize < sizeof (struct AliceComputationMessage))
1019 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
1022 msg = (const struct AliceComputationMessage *) message;
1023 total_count = ntohl (msg->element_count_total);
1024 contained_count = ntohl (msg->element_count_contained);
1025 if ( (0 == total_count) ||
1026 (0 == contained_count) ||
1027 (msize != (sizeof (struct AliceComputationMessage) +
1028 contained_count * sizeof (struct GNUNET_SCALARPRODUCT_Element))) )
1030 GNUNET_break_op (0);
1031 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
1035 s = GNUNET_new (struct AliceServiceSession);
1036 s->peer = msg->peer;
1037 s->status = GNUNET_SCALARPRODUCT_STATUS_ACTIVE;
1039 s->client_mq = GNUNET_MQ_queue_for_server_client (client);
1040 s->total = total_count;
1041 s->client_received_element_count = contained_count;
1042 s->session_id = msg->session_key;
1043 elements = (const struct GNUNET_SCALARPRODUCT_Element *) &msg[1];
1044 s->intersected_elements = GNUNET_CONTAINER_multihashmap_create (s->total,
1046 s->intersection_set = GNUNET_SET_create (cfg,
1047 GNUNET_SET_OPERATION_INTERSECTION);
1048 for (i = 0; i < contained_count; i++)
1050 if (0 == GNUNET_ntohll (elements[i].value))
1052 elem = GNUNET_new (struct GNUNET_SCALARPRODUCT_Element);
1055 sizeof (struct GNUNET_SCALARPRODUCT_Element));
1056 if (GNUNET_SYSERR ==
1057 GNUNET_CONTAINER_multihashmap_put (s->intersected_elements,
1060 GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY))
1062 /* element with same key encountered twice! */
1067 set_elem.data = &elem->key;
1068 set_elem.size = sizeof (elem->key);
1069 set_elem.element_type = 0;
1070 GNUNET_SET_add_element (s->intersection_set,
1073 s->used_element_count++;
1075 GNUNET_SERVER_client_set_user_context (client,
1077 GNUNET_SERVER_receive_done (client,
1079 if (s->total != s->client_received_element_count)
1081 /* wait for multipart msg */
1084 client_request_complete_alice (s);
1089 * Task run during shutdown.
1095 shutdown_task (void *cls,
1096 const struct GNUNET_SCHEDULER_TaskContext *tc)
1098 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1099 "Shutting down, initiating cleanup.\n");
1100 // FIXME: we have to cut our connections to CADET first!
1101 if (NULL != my_cadet)
1103 GNUNET_CADET_disconnect (my_cadet);
1108 GNUNET_CRYPTO_ecc_dlog_release (edc);
1115 * A client disconnected.
1117 * Remove the associated session(s), release data structures
1118 * and cancel pending outgoing transmissions to the client.
1120 * @param cls closure, NULL
1121 * @param client identification of the client
1124 handle_client_disconnect (void *cls,
1125 struct GNUNET_SERVER_Client *client)
1127 struct AliceServiceSession *s;
1131 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1132 "Client %p disconnected from us.\n",
1134 s = GNUNET_SERVER_client_get_user_context (client,
1135 struct AliceServiceSession);
1139 GNUNET_SERVER_client_set_user_context (client,
1141 destroy_service_session (s);
1146 * Initialization of the program and message handlers
1148 * @param cls closure
1149 * @param server the initialized server
1150 * @param c configuration to use
1154 struct GNUNET_SERVER_Handle *server,
1155 const struct GNUNET_CONFIGURATION_Handle *c)
1157 static const struct GNUNET_CADET_MessageHandler cadet_handlers[] = {
1158 { &handle_bobs_cryptodata_message,
1159 GNUNET_MESSAGE_TYPE_SCALARPRODUCT_ECC_BOB_CRYPTODATA,
1163 static const struct GNUNET_SERVER_MessageHandler server_handlers[] = {
1164 { &GSS_handle_alice_client_message, NULL,
1165 GNUNET_MESSAGE_TYPE_SCALARPRODUCT_CLIENT_TO_ALICE,
1167 { &GSS_handle_alice_client_message_multipart, NULL,
1168 GNUNET_MESSAGE_TYPE_SCALARPRODUCT_CLIENT_MUTLIPART_ALICE,
1174 edc = GNUNET_CRYPTO_ecc_dlog_prepare (MAX_RESULT,
1176 /* Select a random 'a' value for Alice */
1177 GNUNET_CRYPTO_ecc_rnd_mpi (edc,
1180 GNUNET_SERVER_add_handlers (server,
1182 GNUNET_SERVER_disconnect_notify (server,
1183 &handle_client_disconnect,
1185 my_cadet = GNUNET_CADET_connect (cfg, NULL,
1186 NULL /* no incoming supported */,
1187 &cb_channel_destruction,
1190 if (NULL == my_cadet)
1192 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1193 _("Connect to CADET failed\n"));
1194 GNUNET_SCHEDULER_shutdown ();
1197 GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_FOREVER_REL,
1205 * The main function for the scalarproduct service.
1207 * @param argc number of arguments from the command line
1208 * @param argv command line arguments
1209 * @return 0 ok, 1 on error
1215 return (GNUNET_OK ==
1216 GNUNET_SERVICE_run (argc, argv,
1217 "scalarproduct-alice",
1218 GNUNET_SERVICE_OPTION_NONE,
1219 &run, NULL)) ? 0 : 1;
1222 /* end of gnunet-service-scalarproduct-ecc_alice.c */