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.
45 #define MAX_RESULT (1024 * 1024)
48 * An encrypted element key-value pair.
53 * Key used to identify matching pairs of values to multiply.
54 * Points into an existing data structure, to avoid copying
55 * and doubling memory use.
57 const struct GNUNET_HashCode *key;
60 * a_i value, not disclosed to Bob.
65 * r_i value, chosen at random, not disclosed to Bob.
73 * A scalarproduct session which tracks
74 * a request form the client to our final response.
76 struct AliceServiceSession
80 * (hopefully) unique transaction ID
82 struct GNUNET_HashCode session_id;
85 * Alice or Bob's peerID
87 struct GNUNET_PeerIdentity peer;
90 * The client this request is related to.
92 struct GNUNET_SERVER_Client *client;
95 * The message queue for the client.
97 struct GNUNET_MQ_Handle *client_mq;
100 * The message queue for CADET.
102 struct GNUNET_MQ_Handle *cadet_mq;
105 * all non-0-value'd elements transmitted to us.
106 * Values are of type `struct GNUNET_SCALARPRODUCT_Element *`
108 struct GNUNET_CONTAINER_MultiHashMap *intersected_elements;
111 * Set of elements for which will conduction an intersection.
112 * the resulting elements are then used for computing the scalar product.
114 struct GNUNET_SET_Handle *intersection_set;
117 * Set of elements for which will conduction an intersection.
118 * the resulting elements are then used for computing the scalar product.
120 struct GNUNET_SET_OperationHandle *intersection_op;
123 * Handle to Alice's Intersection operation listening for Bob
125 struct GNUNET_SET_ListenHandle *intersection_listen;
128 * channel-handle associated with our cadet handle
130 struct GNUNET_CADET_Channel *channel;
133 * a(Alice), sorted array by key of length @e used_element_count.
135 struct MpiElement *sorted_elements;
138 * The computed scalar
143 * How many elements we were supplied with from the client (total
144 * count before intersection).
149 * How many elements actually are used for the scalar product.
150 * Size of the arrays in @e r and @e r_prime. Sometimes also
151 * reset to 0 and used as a counter!
153 uint32_t used_element_count;
156 * Already transferred elements from client to us.
157 * Less or equal than @e total.
159 uint32_t client_received_element_count;
162 * State of this session. In
163 * #GNUNET_SCALARPRODUCT_STATUS_ACTIVE while operation is
164 * ongoing, afterwards in #GNUNET_SCALARPRODUCT_STATUS_SUCCESS or
165 * #GNUNET_SCALARPRODUCT_STATUS_FAILURE.
167 enum GNUNET_SCALARPRODUCT_ResponseStatus status;
170 * Flag to prevent recursive calls to #destroy_service_session() from
179 * GNUnet configuration handle
181 static const struct GNUNET_CONFIGURATION_Handle *cfg;
184 * Context for DLOG operations on a curve.
186 static struct GNUNET_CRYPTO_EccDlogContext *edc;
189 * Alice's private key ('a').
191 static gcry_mpi_t my_privkey;
194 * Inverse of Alice's private key ('a_inv').
196 static gcry_mpi_t my_privkey_inv;
199 * Handle to the CADET service.
201 static struct GNUNET_CADET_Handle *my_cadet;
205 * Iterator called to free elements.
207 * @param cls the `struct AliceServiceSession *` (unused)
208 * @param key the key (unused)
209 * @param value value to free
210 * @return #GNUNET_OK (continue to iterate)
213 free_element_cb (void *cls,
214 const struct GNUNET_HashCode *key,
217 struct GNUNET_SCALARPRODUCT_Element *e = value;
225 * Destroy session state, we are done with it.
227 * @param s the session to free elements from
230 destroy_service_session (struct AliceServiceSession *s)
234 if (GNUNET_YES == s->in_destroy)
236 s->in_destroy = GNUNET_YES;
237 if (NULL != s->client_mq)
239 GNUNET_MQ_destroy (s->client_mq);
242 if (NULL != s->cadet_mq)
244 GNUNET_MQ_destroy (s->cadet_mq);
247 if (NULL != s->client)
249 GNUNET_SERVER_client_set_user_context (s->client,
251 GNUNET_SERVER_client_disconnect (s->client);
254 if (NULL != s->channel)
256 GNUNET_CADET_channel_destroy (s->channel);
259 if (NULL != s->intersected_elements)
261 GNUNET_CONTAINER_multihashmap_iterate (s->intersected_elements,
264 GNUNET_CONTAINER_multihashmap_destroy (s->intersected_elements);
265 s->intersected_elements = NULL;
267 if (NULL != s->intersection_listen)
269 GNUNET_SET_listen_cancel (s->intersection_listen);
270 s->intersection_listen = NULL;
272 if (NULL != s->intersection_op)
274 GNUNET_SET_operation_cancel (s->intersection_op);
275 s->intersection_op = NULL;
277 if (NULL != s->intersection_set)
279 GNUNET_SET_destroy (s->intersection_set);
280 s->intersection_set = NULL;
282 if (NULL != s->sorted_elements)
284 for (i=0;i<s->used_element_count;i++)
285 gcry_mpi_release (s->sorted_elements[i].value);
286 GNUNET_free (s->sorted_elements);
287 s->sorted_elements = NULL;
289 if (NULL != s->product)
291 gcry_mpi_release (s->product);
299 * Notify the client that the session has failed. A message gets sent
300 * to Alice's client if we encountered any error.
302 * @param session the associated client session to fail or succeed
305 prepare_client_end_notification (struct AliceServiceSession *session)
307 struct ClientResponseMessage *msg;
308 struct GNUNET_MQ_Envelope *e;
310 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
311 "Sending session-end notification with status %d to client for session %s\n",
313 GNUNET_h2s (&session->session_id));
314 e = GNUNET_MQ_msg (msg,
315 GNUNET_MESSAGE_TYPE_SCALARPRODUCT_RESULT);
316 msg->product_length = htonl (0);
317 msg->status = htonl (session->status);
318 GNUNET_MQ_send (session->client_mq,
324 * Prepare the final (positive) response we will send to Alice's
327 * @param s the session associated with our client.
330 transmit_client_response (struct AliceServiceSession *s)
332 struct ClientResponseMessage *msg;
333 struct GNUNET_MQ_Envelope *e;
334 unsigned char *product_exported = NULL;
335 size_t product_length = 0;
341 if (NULL == s->product)
344 prepare_client_end_notification (s);
347 value = gcry_mpi_new (0);
348 sign = gcry_mpi_cmp_ui (s->product, 0);
359 gcry_mpi_add (value, value, s->product);
363 /* result is exactly zero */
366 gcry_mpi_release (s->product);
370 (0 != (rc = gcry_mpi_aprint (GCRYMPI_FMT_STD,
375 LOG_GCRY (GNUNET_ERROR_TYPE_ERROR,
378 prepare_client_end_notification (s);
381 gcry_mpi_release (value);
382 e = GNUNET_MQ_msg_extra (msg,
384 GNUNET_MESSAGE_TYPE_SCALARPRODUCT_RESULT);
385 msg->status = htonl (GNUNET_SCALARPRODUCT_STATUS_SUCCESS);
386 msg->range = htonl (range);
387 msg->product_length = htonl (product_length);
388 if (NULL != product_exported)
393 GNUNET_free (product_exported);
395 GNUNET_MQ_send (s->client_mq,
397 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
398 "Sent result to client, session %s has ended!\n",
399 GNUNET_h2s (&s->session_id));
405 * Function called whenever a channel is destroyed. Should clean up
406 * any associated state.
408 * It must NOT call #GNUNET_CADET_channel_destroy() on the channel.
410 * @param cls closure (set from #GNUNET_CADET_connect())
411 * @param channel connection to the other end (henceforth invalid)
412 * @param channel_ctx place where local state associated
413 * with the channel is stored
416 cb_channel_destruction (void *cls,
417 const struct GNUNET_CADET_Channel *channel,
420 struct AliceServiceSession *s = channel_ctx;
422 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
423 "Peer disconnected, terminating session %s with peer %s\n",
424 GNUNET_h2s (&s->session_id),
425 GNUNET_i2s (&s->peer));
426 if (NULL != s->cadet_mq)
428 GNUNET_MQ_destroy (s->cadet_mq);
432 if (GNUNET_SCALARPRODUCT_STATUS_ACTIVE == s->status)
434 /* We didn't get an answer yet, fail with error */
435 s->status = GNUNET_SCALARPRODUCT_STATUS_FAILURE;
436 prepare_client_end_notification (s);
442 * Compute our scalar product, done by Alice
444 * @param session the session associated with this computation
445 * @param prod_g_i_b_i value from Bob
446 * @param prod_h_i_b_i value from Bob
447 * @return product as MPI, never NULL
450 compute_scalar_product (struct AliceServiceSession *session,
451 gcry_mpi_point_t prod_g_i_b_i,
452 gcry_mpi_point_t prod_h_i_b_i)
454 gcry_mpi_point_t g_i_b_i_a_inv;
455 gcry_mpi_point_t g_ai_bi;
459 g_i_b_i_a_inv = GNUNET_CRYPTO_ecc_pmul_mpi (edc,
462 g_ai_bi = GNUNET_CRYPTO_ecc_add (edc,
465 gcry_mpi_point_release (g_i_b_i_a_inv);
466 ai_bi = GNUNET_CRYPTO_ecc_dlog (edc,
468 gcry_mpi_point_release (g_ai_bi);
469 if (MAX_RESULT == ai_bi)
472 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
473 "Scalar product result out of range\n");
476 ret = gcry_mpi_new (0);
477 gcry_mpi_set_ui (ret, ai_bi);
483 * Handle a response we got from another service we wanted to
484 * calculate a scalarproduct with.
486 * @param cls closure (set from #GNUNET_CADET_connect)
487 * @param channel connection to the other end
488 * @param channel_ctx place to store local state associated with the channel
489 * @param message the actual message
490 * @return #GNUNET_OK to keep the connection open,
491 * #GNUNET_SYSERR to close it (we are done)
494 handle_bobs_cryptodata_message (void *cls,
495 struct GNUNET_CADET_Channel *channel,
497 const struct GNUNET_MessageHeader *message)
499 struct AliceServiceSession *s = *channel_ctx;
500 const struct EccBobCryptodataMessage *msg;
503 gcry_mpi_point_t prod_g_i_b_i;
504 gcry_mpi_point_t prod_h_i_b_i;
509 return GNUNET_SYSERR;
511 msg_size = ntohs (message->size);
512 if (sizeof (struct EccBobCryptodataMessage) > msg_size)
515 return GNUNET_SYSERR;
517 msg = (const struct EccBobCryptodataMessage *) message;
518 contained = ntohl (msg->contained_element_count);
522 return GNUNET_SYSERR;
524 if (NULL == s->sorted_elements)
526 /* we're not ready yet, how can Bob be? */
528 return GNUNET_SYSERR;
530 if (s->total != s->client_received_element_count)
532 /* we're not ready yet, how can Bob be? */
534 return GNUNET_SYSERR;
536 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
537 "Received %u crypto values from Bob\n",
538 (unsigned int) contained);
539 GNUNET_CADET_receive_done (s->channel);
540 prod_g_i_b_i = GNUNET_CRYPTO_ecc_bin_to_point (edc,
542 prod_h_i_b_i = GNUNET_CRYPTO_ecc_bin_to_point (edc,
544 s->product = compute_scalar_product (s,
547 gcry_mpi_point_release (prod_g_i_b_i);
548 gcry_mpi_point_release (prod_h_i_b_i);
549 transmit_client_response (s);
555 * Iterator to copy over messages from the hash map
556 * into an array for sorting.
558 * @param cls the `struct AliceServiceSession *`
559 * @param key the key (unused)
560 * @param value the `struct GNUNET_SCALARPRODUCT_Element *`
563 copy_element_cb (void *cls,
564 const struct GNUNET_HashCode *key,
567 struct AliceServiceSession *s = cls;
568 struct GNUNET_SCALARPRODUCT_Element *e = value;
572 mval = gcry_mpi_new (0);
573 val = (int64_t) GNUNET_ntohll (e->value);
575 gcry_mpi_sub_ui (mval, mval, -val);
577 gcry_mpi_add_ui (mval, mval, val);
578 s->sorted_elements [s->used_element_count].value = mval;
579 s->sorted_elements [s->used_element_count].r_i
580 = GNUNET_CRYPTO_ecc_random_mod_n (edc);
581 s->sorted_elements [s->used_element_count].key = &e->key;
582 s->used_element_count++;
588 * Compare two `struct MpiValue`s by key for sorting.
590 * @param a pointer to first `struct MpiValue *`
591 * @param b pointer to first `struct MpiValue *`
592 * @return -1 for a < b, 0 for a=b, 1 for a > b.
595 element_cmp (const void *a,
598 const struct MpiElement *ma = a;
599 const struct MpiElement *mb = b;
601 return GNUNET_CRYPTO_hash_cmp (ma->key,
607 * Maximum number of elements we can put into a single cryptodata
610 #define ELEMENT_CAPACITY ((GNUNET_CONSTANTS_MAX_CADET_MESSAGE_SIZE - 1 - sizeof (struct EccAliceCryptodataMessage)) / sizeof (struct GNUNET_CRYPTO_EccPoint))
614 * Send the cryptographic data from Alice to Bob.
615 * Does nothing if we already transferred all elements.
617 * @param s the associated service session
620 send_alices_cryptodata_message (struct AliceServiceSession *s)
622 struct EccAliceCryptodataMessage *msg;
623 struct GNUNET_MQ_Envelope *e;
624 struct GNUNET_CRYPTO_EccPoint *payload;
625 gcry_mpi_point_t g_i;
626 gcry_mpi_point_t h_i;
631 unsigned int todo_count;
634 = GNUNET_malloc (GNUNET_CONTAINER_multihashmap_size (s->intersected_elements) *
635 sizeof (struct MpiElement));
636 s->used_element_count = 0;
637 GNUNET_CONTAINER_multihashmap_iterate (s->intersected_elements,
640 LOG (GNUNET_ERROR_TYPE_DEBUG,
641 "Finished intersection, %d items remain\n",
642 s->used_element_count);
643 qsort (s->sorted_elements,
644 s->used_element_count,
645 sizeof (struct MpiElement),
648 while (off < s->used_element_count)
650 todo_count = s->used_element_count - off;
651 if (todo_count > ELEMENT_CAPACITY)
652 todo_count = ELEMENT_CAPACITY;
653 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
654 "Sending %u/%u crypto values to Bob\n",
655 (unsigned int) todo_count,
656 (unsigned int) s->used_element_count);
658 e = GNUNET_MQ_msg_extra (msg,
659 todo_count * 2 * sizeof (struct GNUNET_CRYPTO_EccPoint),
660 GNUNET_MESSAGE_TYPE_SCALARPRODUCT_ECC_ALICE_CRYPTODATA);
661 msg->contained_element_count = htonl (todo_count);
662 payload = (struct GNUNET_CRYPTO_EccPoint *) &msg[1];
663 r_ia = gcry_mpi_new (0);
664 r_ia_ai = gcry_mpi_new (0);
665 for (i = off; i < off + todo_count; i++)
667 g_i = GNUNET_CRYPTO_ecc_dexp_mpi (edc,
668 s->sorted_elements [i].r_i);
670 gcry_mpi_mul (s->sorted_elements[i].r_i,
673 /* r_ia_ai = r_ia + a_i */
674 gcry_mpi_add (r_ia_ai,
675 s->sorted_elements[i].value,
677 h_i = GNUNET_CRYPTO_ecc_dexp_mpi (edc,
679 GNUNET_CRYPTO_ecc_point_to_bin (edc,
681 &payload[(i - off) * 2]);
682 GNUNET_CRYPTO_ecc_point_to_bin (edc,
684 &payload[(i - off) * 2 + 1]);
685 gcry_mpi_point_release (g_i);
686 gcry_mpi_point_release (h_i);
688 gcry_mpi_release (r_ia);
689 gcry_mpi_release (r_ia_ai);
691 GNUNET_MQ_send (s->cadet_mq,
698 * Callback for set operation results. Called for each element
699 * that should be removed from the result set, and then once
700 * to indicate that the set intersection operation is done.
702 * @param cls closure with the `struct AliceServiceSession`
703 * @param element a result element, only valid if status is #GNUNET_SET_STATUS_OK
704 * @param status what has happened with the set intersection?
707 cb_intersection_element_removed (void *cls,
708 const struct GNUNET_SET_Element *element,
709 enum GNUNET_SET_Status status)
711 struct AliceServiceSession *s = cls;
712 struct GNUNET_SCALARPRODUCT_Element *se;
716 case GNUNET_SET_STATUS_OK:
717 /* this element has been removed from the set */
718 se = GNUNET_CONTAINER_multihashmap_get (s->intersected_elements,
720 GNUNET_assert (NULL != se);
721 LOG (GNUNET_ERROR_TYPE_DEBUG,
722 "Intersection removed element with key %s and value %lld\n",
723 GNUNET_h2s (&se->key),
724 (long long) GNUNET_ntohll (se->value));
725 GNUNET_assert (GNUNET_YES ==
726 GNUNET_CONTAINER_multihashmap_remove (s->intersected_elements,
731 case GNUNET_SET_STATUS_DONE:
732 s->intersection_op = NULL;
733 if (NULL != s->intersection_set)
735 GNUNET_SET_destroy (s->intersection_set);
736 s->intersection_set = NULL;
738 send_alices_cryptodata_message (s);
740 case GNUNET_SET_STATUS_HALF_DONE:
741 /* unexpected for intersection */
744 case GNUNET_SET_STATUS_FAILURE:
745 /* unhandled status code */
746 LOG (GNUNET_ERROR_TYPE_DEBUG,
747 "Set intersection failed!\n");
748 if (NULL != s->intersection_listen)
750 GNUNET_SET_listen_cancel (s->intersection_listen);
751 s->intersection_listen = NULL;
753 s->intersection_op = NULL;
754 if (NULL != s->intersection_set)
756 GNUNET_SET_destroy (s->intersection_set);
757 s->intersection_set = NULL;
759 s->status = GNUNET_SCALARPRODUCT_STATUS_FAILURE;
760 prepare_client_end_notification (s);
770 * Called when another peer wants to do a set operation with the
771 * local peer. If a listen error occurs, the @a request is NULL.
773 * @param cls closure with the `struct AliceServiceSession *`
774 * @param other_peer the other peer
775 * @param context_msg message with application specific information from
777 * @param request request from the other peer (never NULL), use GNUNET_SET_accept()
778 * to accept it, otherwise the request will be refused
779 * Note that we can't just return value from the listen callback,
780 * as it is also necessary to specify the set we want to do the
781 * operation with, whith sometimes can be derived from the context
782 * message. It's necessary to specify the timeout.
785 cb_intersection_request_alice (void *cls,
786 const struct GNUNET_PeerIdentity *other_peer,
787 const struct GNUNET_MessageHeader *context_msg,
788 struct GNUNET_SET_Request *request)
790 struct AliceServiceSession *s = cls;
792 if (0 != memcmp (other_peer,
794 sizeof (struct GNUNET_PeerIdentity)))
800 = GNUNET_SET_accept (request,
801 GNUNET_SET_RESULT_REMOVED,
802 &cb_intersection_element_removed,
804 if (NULL == s->intersection_op)
807 s->status = GNUNET_SCALARPRODUCT_STATUS_FAILURE;
808 prepare_client_end_notification (s);
812 GNUNET_SET_commit (s->intersection_op,
813 s->intersection_set))
816 s->status = GNUNET_SCALARPRODUCT_STATUS_FAILURE;
817 prepare_client_end_notification (s);
820 GNUNET_SET_destroy (s->intersection_set);
821 s->intersection_set = NULL;
822 GNUNET_SET_listen_cancel (s->intersection_listen);
823 s->intersection_listen = NULL;
828 * Our client has finished sending us its multipart message.
830 * @param session the service session context
833 client_request_complete_alice (struct AliceServiceSession *s)
835 struct EccServiceRequestMessage *msg;
836 struct GNUNET_MQ_Envelope *e;
838 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
839 "Creating new channel for session with key %s.\n",
840 GNUNET_h2s (&s->session_id));
842 = GNUNET_CADET_channel_create (my_cadet,
845 GNUNET_APPLICATION_TYPE_SCALARPRODUCT_ECC,
846 GNUNET_CADET_OPTION_RELIABLE);
847 if (NULL == s->channel)
849 s->status = GNUNET_SCALARPRODUCT_STATUS_FAILURE;
850 prepare_client_end_notification (s);
853 s->cadet_mq = GNUNET_CADET_mq_create (s->channel);
854 s->intersection_listen
855 = GNUNET_SET_listen (cfg,
856 GNUNET_SET_OPERATION_INTERSECTION,
858 &cb_intersection_request_alice,
860 if (NULL == s->intersection_listen)
862 s->status = GNUNET_SCALARPRODUCT_STATUS_FAILURE;
863 GNUNET_CADET_channel_destroy (s->channel);
865 prepare_client_end_notification (s);
869 e = GNUNET_MQ_msg (msg,
870 GNUNET_MESSAGE_TYPE_SCALARPRODUCT_ECC_SESSION_INITIALIZATION);
871 msg->session_id = s->session_id;
872 GNUNET_MQ_send (s->cadet_mq,
878 * We're receiving additional set data. Add it to our
879 * set and if we are done, initiate the transaction.
882 * @param client identification of the client
883 * @param message the actual message
886 GSS_handle_alice_client_message_multipart (void *cls,
887 struct GNUNET_SERVER_Client *client,
888 const struct GNUNET_MessageHeader *message)
890 const struct ComputationBobCryptodataMultipartMessage * msg;
891 struct AliceServiceSession *s;
892 uint32_t contained_count;
893 const struct GNUNET_SCALARPRODUCT_Element *elements;
896 struct GNUNET_SET_Element set_elem;
897 struct GNUNET_SCALARPRODUCT_Element *elem;
899 s = GNUNET_SERVER_client_get_user_context (client,
900 struct AliceServiceSession);
903 /* session needs to already exist */
905 GNUNET_SERVER_receive_done (client,
909 msize = ntohs (message->size);
910 if (msize < sizeof (struct ComputationBobCryptodataMultipartMessage))
913 GNUNET_SERVER_receive_done (client,
917 msg = (const struct ComputationBobCryptodataMultipartMessage *) message;
918 contained_count = ntohl (msg->element_count_contained);
920 if ( (msize != (sizeof (struct ComputationBobCryptodataMultipartMessage) +
921 contained_count * sizeof (struct GNUNET_SCALARPRODUCT_Element))) ||
922 (0 == contained_count) ||
923 (s->total == s->client_received_element_count) ||
924 (s->total < s->client_received_element_count + contained_count) )
927 GNUNET_SERVER_receive_done (client,
931 s->client_received_element_count += contained_count;
932 elements = (const struct GNUNET_SCALARPRODUCT_Element *) &msg[1];
933 for (i = 0; i < contained_count; i++)
935 elem = GNUNET_new (struct GNUNET_SCALARPRODUCT_Element);
938 sizeof (struct GNUNET_SCALARPRODUCT_Element));
940 GNUNET_CONTAINER_multihashmap_put (s->intersected_elements,
943 GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY))
949 set_elem.data = &elem->key;
950 set_elem.size = sizeof (elem->key);
951 set_elem.element_type = 0;
952 GNUNET_SET_add_element (s->intersection_set,
955 s->used_element_count++;
957 GNUNET_SERVER_receive_done (client,
959 if (s->total != s->client_received_element_count)
964 client_request_complete_alice (s);
969 * Handler for Alice's client request message.
970 * We are doing request-initiation to compute a scalar product with a peer.
973 * @param client identification of the client
974 * @param message the actual message
977 GSS_handle_alice_client_message (void *cls,
978 struct GNUNET_SERVER_Client *client,
979 const struct GNUNET_MessageHeader *message)
981 const struct AliceComputationMessage *msg;
982 struct AliceServiceSession *s;
983 uint32_t contained_count;
984 uint32_t total_count;
985 const struct GNUNET_SCALARPRODUCT_Element *elements;
988 struct GNUNET_SET_Element set_elem;
989 struct GNUNET_SCALARPRODUCT_Element *elem;
991 s = GNUNET_SERVER_client_get_user_context (client,
992 struct AliceServiceSession);
995 /* only one concurrent session per client connection allowed,
996 simplifies logic a lot... */
998 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
1001 msize = ntohs (message->size);
1002 if (msize < sizeof (struct AliceComputationMessage))
1005 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
1008 msg = (const struct AliceComputationMessage *) message;
1009 total_count = ntohl (msg->element_count_total);
1010 contained_count = ntohl (msg->element_count_contained);
1011 if ( (0 == total_count) ||
1012 (0 == contained_count) ||
1013 (msize != (sizeof (struct AliceComputationMessage) +
1014 contained_count * sizeof (struct GNUNET_SCALARPRODUCT_Element))) )
1016 GNUNET_break_op (0);
1017 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
1021 s = GNUNET_new (struct AliceServiceSession);
1022 s->peer = msg->peer;
1023 s->status = GNUNET_SCALARPRODUCT_STATUS_ACTIVE;
1025 s->client_mq = GNUNET_MQ_queue_for_server_client (client);
1026 s->total = total_count;
1027 s->client_received_element_count = contained_count;
1028 s->session_id = msg->session_key;
1029 elements = (const struct GNUNET_SCALARPRODUCT_Element *) &msg[1];
1030 s->intersected_elements = GNUNET_CONTAINER_multihashmap_create (s->total,
1032 s->intersection_set = GNUNET_SET_create (cfg,
1033 GNUNET_SET_OPERATION_INTERSECTION);
1034 for (i = 0; i < contained_count; i++)
1036 if (0 == GNUNET_ntohll (elements[i].value))
1038 elem = GNUNET_new (struct GNUNET_SCALARPRODUCT_Element);
1041 sizeof (struct GNUNET_SCALARPRODUCT_Element));
1042 if (GNUNET_SYSERR ==
1043 GNUNET_CONTAINER_multihashmap_put (s->intersected_elements,
1046 GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY))
1048 /* element with same key encountered twice! */
1053 set_elem.data = &elem->key;
1054 set_elem.size = sizeof (elem->key);
1055 set_elem.element_type = 0;
1056 GNUNET_SET_add_element (s->intersection_set,
1059 s->used_element_count++;
1061 GNUNET_SERVER_client_set_user_context (client,
1063 GNUNET_SERVER_receive_done (client,
1065 if (s->total != s->client_received_element_count)
1067 /* wait for multipart msg */
1070 client_request_complete_alice (s);
1075 * Task run during shutdown.
1081 shutdown_task (void *cls,
1082 const struct GNUNET_SCHEDULER_TaskContext *tc)
1084 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1085 "Shutting down, initiating cleanup.\n");
1086 // FIXME: we have to cut our connections to CADET first!
1087 if (NULL != my_cadet)
1089 GNUNET_CADET_disconnect (my_cadet);
1094 GNUNET_CRYPTO_ecc_dlog_release (edc);
1101 * A client disconnected.
1103 * Remove the associated session(s), release data structures
1104 * and cancel pending outgoing transmissions to the client.
1106 * @param cls closure, NULL
1107 * @param client identification of the client
1110 handle_client_disconnect (void *cls,
1111 struct GNUNET_SERVER_Client *client)
1113 struct AliceServiceSession *s;
1117 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1118 "Client %p disconnected from us.\n",
1120 s = GNUNET_SERVER_client_get_user_context (client,
1121 struct AliceServiceSession);
1125 GNUNET_SERVER_client_set_user_context (client,
1127 destroy_service_session (s);
1132 * Initialization of the program and message handlers
1134 * @param cls closure
1135 * @param server the initialized server
1136 * @param c configuration to use
1140 struct GNUNET_SERVER_Handle *server,
1141 const struct GNUNET_CONFIGURATION_Handle *c)
1143 static const struct GNUNET_CADET_MessageHandler cadet_handlers[] = {
1144 { &handle_bobs_cryptodata_message,
1145 GNUNET_MESSAGE_TYPE_SCALARPRODUCT_ECC_BOB_CRYPTODATA,
1149 static const struct GNUNET_SERVER_MessageHandler server_handlers[] = {
1150 { &GSS_handle_alice_client_message, NULL,
1151 GNUNET_MESSAGE_TYPE_SCALARPRODUCT_CLIENT_TO_ALICE,
1153 { &GSS_handle_alice_client_message_multipart, NULL,
1154 GNUNET_MESSAGE_TYPE_SCALARPRODUCT_CLIENT_MUTLIPART_ALICE,
1160 edc = GNUNET_CRYPTO_ecc_dlog_prepare (MAX_RESULT /* max value */,
1162 /* Select a random 'a' value for Alice */
1163 GNUNET_CRYPTO_ecc_rnd_mpi (edc,
1166 GNUNET_SERVER_add_handlers (server,
1168 GNUNET_SERVER_disconnect_notify (server,
1169 &handle_client_disconnect,
1171 my_cadet = GNUNET_CADET_connect (cfg, NULL,
1172 NULL /* no incoming supported */,
1173 &cb_channel_destruction,
1176 if (NULL == my_cadet)
1178 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1179 _("Connect to CADET failed\n"));
1180 GNUNET_SCHEDULER_shutdown ();
1183 GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_FOREVER_REL,
1191 * The main function for the scalarproduct service.
1193 * @param argc number of arguments from the command line
1194 * @param argv command line arguments
1195 * @return 0 ok, 1 on error
1201 return (GNUNET_OK ==
1202 GNUNET_SERVICE_run (argc, argv,
1203 "scalarproduct-alice",
1204 GNUNET_SERVICE_OPTION_NONE,
1205 &run, NULL)) ? 0 : 1;
1208 /* end of gnunet-service-scalarproduct-ecc_alice.c */