2 This file is part of GNUnet.
3 Copyright (C) 2013-2017 GNUnet e.V.
5 GNUnet is free software: you can redistribute it and/or modify it
6 under the terms of the GNU Affero General Public License as published
7 by the Free Software Foundation, either version 3 of the License,
8 or (at your 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 Affero General Public License for more details.
16 * @file scalarproduct/gnunet-service-scalarproduct-ecc_alice.c
17 * @brief scalarproduct service implementation
18 * @author Christian M. Fuchs
19 * @author Christian Grothoff
24 #include "gnunet_util_lib.h"
25 #include "gnunet_core_service.h"
26 #include "gnunet_cadet_service.h"
27 #include "gnunet_applications.h"
28 #include "gnunet_protocols.h"
29 #include "gnunet_scalarproduct_service.h"
30 #include "gnunet_set_service.h"
31 #include "scalarproduct.h"
32 #include "gnunet-service-scalarproduct-ecc.h"
34 #define LOG(kind,...) GNUNET_log_from (kind, "scalarproduct-alice", __VA_ARGS__)
37 * Maximum allowed result value for the scalarproduct computation.
38 * DLOG will fail if the result is bigger. At 1 million, the
39 * precomputation takes about 2s on a fast machine.
41 #define MAX_RESULT (1024 * 1024)
44 * How many values should DLOG store in memory (determines baseline
45 * RAM consumption, roughly 100 bytes times the value given here).
46 * Should be about SQRT (MAX_RESULT), larger values will make the
47 * online computation faster.
49 #define MAX_RAM (1024)
52 * An encrypted element key-value pair.
57 * Key used to identify matching pairs of values to multiply.
58 * Points into an existing data structure, to avoid copying
59 * and doubling memory use.
61 const struct GNUNET_HashCode *key;
64 * a_i value, not disclosed to Bob.
72 * A scalarproduct session which tracks
73 * a request form the client to our final response.
75 struct AliceServiceSession
79 * (hopefully) unique transaction ID
81 struct GNUNET_HashCode session_id;
84 * Alice or Bob's peerID
86 struct GNUNET_PeerIdentity peer;
89 * The client this request is related to.
91 struct GNUNET_SERVICE_Client *client;
94 * The message queue for the client.
96 struct GNUNET_MQ_Handle *client_mq;
99 * The message queue for CADET.
101 struct GNUNET_MQ_Handle *cadet_mq;
104 * all non-0-value'd elements transmitted to us.
105 * Values are of type `struct GNUNET_SCALARPRODUCT_Element *`
107 struct GNUNET_CONTAINER_MultiHashMap *intersected_elements;
110 * Set of elements for which will conduction an intersection.
111 * the resulting elements are then used for computing the scalar product.
113 struct GNUNET_SET_Handle *intersection_set;
116 * Set of elements for which will conduction an intersection.
117 * the resulting elements are then used for computing the scalar product.
119 struct GNUNET_SET_OperationHandle *intersection_op;
122 * Handle to Alice's Intersection operation listening for Bob
124 struct GNUNET_SET_ListenHandle *intersection_listen;
127 * channel-handle associated with our cadet handle
129 struct GNUNET_CADET_Channel *channel;
132 * a(Alice), sorted array by key of length @e used_element_count.
134 struct MpiElement *sorted_elements;
137 * The computed scalar
142 * How many elements we were supplied with from the client (total
143 * count before intersection).
148 * How many elements actually are used for the scalar product.
149 * Size of the arrays in @e r and @e r_prime. Sometimes also
150 * reset to 0 and used as a counter!
152 uint32_t used_element_count;
155 * Already transferred elements from client to us.
156 * Less or equal than @e total.
158 uint32_t client_received_element_count;
161 * State of this session. In
162 * #GNUNET_SCALARPRODUCT_STATUS_ACTIVE while operation is
163 * ongoing, afterwards in #GNUNET_SCALARPRODUCT_STATUS_SUCCESS or
164 * #GNUNET_SCALARPRODUCT_STATUS_FAILURE.
166 enum GNUNET_SCALARPRODUCT_ResponseStatus status;
169 * Flag to prevent recursive calls to #destroy_service_session() from
178 * GNUnet configuration handle
180 static const struct GNUNET_CONFIGURATION_Handle *cfg;
183 * Context for DLOG operations on a curve.
185 static struct GNUNET_CRYPTO_EccDlogContext *edc;
188 * Alice's private key ('a').
190 static gcry_mpi_t my_privkey;
193 * Inverse of Alice's private key ('a_inv').
195 static gcry_mpi_t my_privkey_inv;
198 * Handle to the CADET service.
200 static struct GNUNET_CADET_Handle *my_cadet;
204 * Iterator called to free elements.
206 * @param cls the `struct AliceServiceSession *` (unused)
207 * @param key the key (unused)
208 * @param value value to free
209 * @return #GNUNET_OK (continue to iterate)
212 free_element_cb (void *cls,
213 const struct GNUNET_HashCode *key,
216 struct GNUNET_SCALARPRODUCT_Element *e = value;
224 * Destroy session state, we are done with it.
226 * @param s the session to free elements from
229 destroy_service_session (struct AliceServiceSession *s)
233 if (GNUNET_YES == s->in_destroy)
235 s->in_destroy = GNUNET_YES;
236 if (NULL != s->client)
238 struct GNUNET_SERVICE_Client *c = s->client;
241 GNUNET_SERVICE_client_drop (c);
243 if (NULL != s->channel)
245 GNUNET_CADET_channel_destroy (s->channel);
248 if (NULL != s->intersected_elements)
250 GNUNET_CONTAINER_multihashmap_iterate (s->intersected_elements,
253 GNUNET_CONTAINER_multihashmap_destroy (s->intersected_elements);
254 s->intersected_elements = NULL;
256 if (NULL != s->intersection_listen)
258 GNUNET_SET_listen_cancel (s->intersection_listen);
259 s->intersection_listen = NULL;
261 if (NULL != s->intersection_op)
263 LOG (GNUNET_ERROR_TYPE_DEBUG,
264 "Set intersection, op still ongoing!\n");
265 GNUNET_SET_operation_cancel (s->intersection_op);
266 s->intersection_op = NULL;
268 if (NULL != s->intersection_set)
270 GNUNET_SET_destroy (s->intersection_set);
271 s->intersection_set = NULL;
273 if (NULL != s->sorted_elements)
275 for (i=0;i<s->used_element_count;i++)
276 gcry_mpi_release (s->sorted_elements[i].value);
277 GNUNET_free (s->sorted_elements);
278 s->sorted_elements = NULL;
280 if (NULL != s->product)
282 gcry_mpi_release (s->product);
290 * Notify the client that the session has failed. A message gets sent
291 * to Alice's client if we encountered any error.
293 * @param session the associated client session to fail or succeed
296 prepare_client_end_notification (struct AliceServiceSession *session)
298 struct ClientResponseMessage *msg;
299 struct GNUNET_MQ_Envelope *e;
301 if (NULL == session->client_mq)
302 return; /* no client left to be notified */
303 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
304 "Sending session-end notification with status %d to client for session %s\n",
306 GNUNET_h2s (&session->session_id));
307 e = GNUNET_MQ_msg (msg,
308 GNUNET_MESSAGE_TYPE_SCALARPRODUCT_RESULT);
309 msg->product_length = htonl (0);
310 msg->status = htonl (session->status);
311 GNUNET_MQ_send (session->client_mq,
317 * Prepare the final (positive) response we will send to Alice's
320 * @param s the session associated with our client.
323 transmit_client_response (struct AliceServiceSession *s)
325 struct ClientResponseMessage *msg;
326 struct GNUNET_MQ_Envelope *e;
327 unsigned char *product_exported = NULL;
328 size_t product_length = 0;
334 if (NULL == s->product)
337 prepare_client_end_notification (s);
340 value = gcry_mpi_new (0);
341 sign = gcry_mpi_cmp_ui (s->product, 0);
352 gcry_mpi_add (value, value, s->product);
356 /* result is exactly zero */
359 gcry_mpi_release (s->product);
363 (0 != (rc = gcry_mpi_aprint (GCRYMPI_FMT_STD,
368 LOG_GCRY (GNUNET_ERROR_TYPE_ERROR,
371 prepare_client_end_notification (s);
374 gcry_mpi_release (value);
375 e = GNUNET_MQ_msg_extra (msg,
377 GNUNET_MESSAGE_TYPE_SCALARPRODUCT_RESULT);
378 msg->status = htonl (GNUNET_SCALARPRODUCT_STATUS_SUCCESS);
379 msg->range = htonl (range);
380 msg->product_length = htonl (product_length);
381 if (NULL != product_exported)
383 GNUNET_memcpy (&msg[1],
386 GNUNET_free (product_exported);
388 GNUNET_MQ_send (s->client_mq,
390 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
391 "Sent result to client, session %s has ended!\n",
392 GNUNET_h2s (&s->session_id));
397 * Function called whenever a channel is destroyed. Should clean up
398 * any associated state.
400 * It must NOT call #GNUNET_CADET_channel_destroy() on the channel.
402 * @param cls the `struct AliceServiceSession`
403 * @param channel connection to the other end (henceforth invalid)
406 cb_channel_destruction (void *cls,
407 const struct GNUNET_CADET_Channel *channel)
409 struct AliceServiceSession *s = cls;
411 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
412 "Peer disconnected, terminating session %s with peer %s\n",
413 GNUNET_h2s (&s->session_id),
414 GNUNET_i2s (&s->peer));
416 if (GNUNET_SCALARPRODUCT_STATUS_ACTIVE == s->status)
418 /* We didn't get an answer yet, fail with error */
419 s->status = GNUNET_SCALARPRODUCT_STATUS_FAILURE;
420 prepare_client_end_notification (s);
426 * Compute our scalar product, done by Alice
428 * @param session the session associated with this computation
429 * @param prod_g_i_b_i value from Bob
430 * @param prod_h_i_b_i value from Bob
431 * @return product as MPI, never NULL
434 compute_scalar_product (struct AliceServiceSession *session,
435 gcry_mpi_point_t prod_g_i_b_i,
436 gcry_mpi_point_t prod_h_i_b_i)
438 gcry_mpi_point_t g_i_b_i_a_inv;
439 gcry_mpi_point_t g_ai_bi;
443 g_i_b_i_a_inv = GNUNET_CRYPTO_ecc_pmul_mpi (edc,
446 g_ai_bi = GNUNET_CRYPTO_ecc_add (edc,
449 gcry_mpi_point_release (g_i_b_i_a_inv);
450 ai_bi = GNUNET_CRYPTO_ecc_dlog (edc,
452 gcry_mpi_point_release (g_ai_bi);
453 if (INT_MAX == ai_bi)
456 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
457 "Scalar product result out of range\n");
460 ret = gcry_mpi_new (0);
463 gcry_mpi_set_ui (ret, ai_bi);
467 gcry_mpi_set_ui (ret, - ai_bi);
468 gcry_mpi_neg (ret, ret);
475 * Handle a response we got from another service we wanted to
476 * calculate a scalarproduct with.
478 * @param cls the `struct AliceServiceSession *`
479 * @param msg the actual message
482 handle_bobs_cryptodata_message (void *cls,
483 const struct EccBobCryptodataMessage *msg)
485 struct AliceServiceSession *s = cls;
486 gcry_mpi_point_t prod_g_i_b_i;
487 gcry_mpi_point_t prod_h_i_b_i;
490 contained = ntohl (msg->contained_element_count);
494 destroy_service_session (s);
497 if (NULL == s->sorted_elements)
499 /* we're not ready yet, how can Bob be? */
501 destroy_service_session (s);
504 if (s->total != s->client_received_element_count)
506 /* we're not ready yet, how can Bob be? */
508 destroy_service_session (s);
512 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
513 "Received %u crypto values from Bob\n",
514 (unsigned int) contained);
515 GNUNET_CADET_receive_done (s->channel);
516 prod_g_i_b_i = GNUNET_CRYPTO_ecc_bin_to_point (edc,
518 prod_h_i_b_i = GNUNET_CRYPTO_ecc_bin_to_point (edc,
520 s->product = compute_scalar_product (s,
523 gcry_mpi_point_release (prod_g_i_b_i);
524 gcry_mpi_point_release (prod_h_i_b_i);
525 transmit_client_response (s);
530 * Iterator to copy over messages from the hash map
531 * into an array for sorting.
533 * @param cls the `struct AliceServiceSession *`
534 * @param key the key (unused)
535 * @param value the `struct GNUNET_SCALARPRODUCT_Element *`
538 copy_element_cb (void *cls,
539 const struct GNUNET_HashCode *key,
542 struct AliceServiceSession *s = cls;
543 struct GNUNET_SCALARPRODUCT_Element *e = value;
547 mval = gcry_mpi_new (0);
548 val = (int64_t) GNUNET_ntohll (e->value);
550 gcry_mpi_sub_ui (mval, mval, -val);
552 gcry_mpi_add_ui (mval, mval, val);
553 s->sorted_elements [s->used_element_count].value = mval;
554 s->sorted_elements [s->used_element_count].key = &e->key;
555 s->used_element_count++;
561 * Compare two `struct MpiValue`s by key for sorting.
563 * @param a pointer to first `struct MpiValue *`
564 * @param b pointer to first `struct MpiValue *`
565 * @return -1 for a < b, 0 for a=b, 1 for a > b.
568 element_cmp (const void *a,
571 const struct MpiElement *ma = a;
572 const struct MpiElement *mb = b;
574 return GNUNET_CRYPTO_hash_cmp (ma->key,
580 * Maximum number of elements we can put into a single cryptodata
583 #define ELEMENT_CAPACITY ((GNUNET_CONSTANTS_MAX_CADET_MESSAGE_SIZE - 1 - sizeof (struct EccAliceCryptodataMessage)) / sizeof (struct GNUNET_CRYPTO_EccPoint))
587 * Send the cryptographic data from Alice to Bob.
588 * Does nothing if we already transferred all elements.
590 * @param s the associated service session
593 send_alices_cryptodata_message (struct AliceServiceSession *s)
595 struct EccAliceCryptodataMessage *msg;
596 struct GNUNET_MQ_Envelope *e;
597 struct GNUNET_CRYPTO_EccPoint *payload;
602 unsigned int todo_count;
605 = GNUNET_new_array (GNUNET_CONTAINER_multihashmap_size (s->intersected_elements),
607 s->used_element_count = 0;
608 GNUNET_CONTAINER_multihashmap_iterate (s->intersected_elements,
611 LOG (GNUNET_ERROR_TYPE_DEBUG,
612 "Finished intersection, %d items remain\n",
613 s->used_element_count);
614 qsort (s->sorted_elements,
615 s->used_element_count,
616 sizeof (struct MpiElement),
619 while (off < s->used_element_count)
621 todo_count = s->used_element_count - off;
622 if (todo_count > ELEMENT_CAPACITY)
623 todo_count = ELEMENT_CAPACITY;
624 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
625 "Sending %u/%u crypto values to Bob\n",
626 (unsigned int) todo_count,
627 (unsigned int) s->used_element_count);
629 e = GNUNET_MQ_msg_extra (msg,
630 todo_count * 2 * sizeof (struct GNUNET_CRYPTO_EccPoint),
631 GNUNET_MESSAGE_TYPE_SCALARPRODUCT_ECC_ALICE_CRYPTODATA);
632 msg->contained_element_count = htonl (todo_count);
633 payload = (struct GNUNET_CRYPTO_EccPoint *) &msg[1];
634 r_ia = gcry_mpi_new (0);
635 r_ia_ai = gcry_mpi_new (0);
636 for (i = off; i < off + todo_count; i++)
639 gcry_mpi_point_t g_i;
640 gcry_mpi_point_t h_i;
642 r_i = GNUNET_CRYPTO_ecc_random_mod_n (edc);
643 g_i = GNUNET_CRYPTO_ecc_dexp_mpi (edc,
649 gcry_mpi_release (r_i);
650 /* r_ia_ai = r_ia + a_i */
651 gcry_mpi_add (r_ia_ai,
653 s->sorted_elements[i].value);
654 h_i = GNUNET_CRYPTO_ecc_dexp_mpi (edc,
656 GNUNET_CRYPTO_ecc_point_to_bin (edc,
658 &payload[(i - off) * 2]);
659 GNUNET_CRYPTO_ecc_point_to_bin (edc,
661 &payload[(i - off) * 2 + 1]);
662 gcry_mpi_point_release (g_i);
663 gcry_mpi_point_release (h_i);
665 gcry_mpi_release (r_ia);
666 gcry_mpi_release (r_ia_ai);
668 GNUNET_MQ_send (s->cadet_mq,
675 * Callback for set operation results. Called for each element
676 * that should be removed from the result set, and then once
677 * to indicate that the set intersection operation is done.
679 * @param cls closure with the `struct AliceServiceSession`
680 * @param element a result element, only valid if status is #GNUNET_SET_STATUS_OK
681 * @param current_size current set size
682 * @param status what has happened with the set intersection?
685 cb_intersection_element_removed (void *cls,
686 const struct GNUNET_SET_Element *element,
687 uint64_t current_size,
688 enum GNUNET_SET_Status status)
690 struct AliceServiceSession *s = cls;
691 struct GNUNET_SCALARPRODUCT_Element *se;
695 case GNUNET_SET_STATUS_OK:
696 /* this element has been removed from the set */
697 se = GNUNET_CONTAINER_multihashmap_get (s->intersected_elements,
699 GNUNET_assert (NULL != se);
700 LOG (GNUNET_ERROR_TYPE_DEBUG,
701 "Intersection removed element with key %s and value %lld\n",
702 GNUNET_h2s (&se->key),
703 (long long) GNUNET_ntohll (se->value));
704 GNUNET_assert (GNUNET_YES ==
705 GNUNET_CONTAINER_multihashmap_remove (s->intersected_elements,
710 case GNUNET_SET_STATUS_DONE:
711 s->intersection_op = NULL;
712 if (NULL != s->intersection_set)
714 GNUNET_SET_destroy (s->intersection_set);
715 s->intersection_set = NULL;
717 send_alices_cryptodata_message (s);
719 case GNUNET_SET_STATUS_HALF_DONE:
720 /* unexpected for intersection */
723 case GNUNET_SET_STATUS_FAILURE:
724 /* unhandled status code */
725 LOG (GNUNET_ERROR_TYPE_DEBUG,
726 "Set intersection failed!\n");
727 if (NULL != s->intersection_listen)
729 GNUNET_SET_listen_cancel (s->intersection_listen);
730 s->intersection_listen = NULL;
732 s->intersection_op = NULL;
733 if (NULL != s->intersection_set)
735 GNUNET_SET_destroy (s->intersection_set);
736 s->intersection_set = NULL;
738 s->status = GNUNET_SCALARPRODUCT_STATUS_FAILURE;
739 prepare_client_end_notification (s);
749 * Called when another peer wants to do a set operation with the
750 * local peer. If a listen error occurs, the @a request is NULL.
752 * @param cls closure with the `struct AliceServiceSession *`
753 * @param other_peer the other peer
754 * @param context_msg message with application specific information from
756 * @param request request from the other peer (never NULL), use GNUNET_SET_accept()
757 * to accept it, otherwise the request will be refused
758 * Note that we can't just return value from the listen callback,
759 * as it is also necessary to specify the set we want to do the
760 * operation with, whith sometimes can be derived from the context
761 * message. It's necessary to specify the timeout.
764 cb_intersection_request_alice (void *cls,
765 const struct GNUNET_PeerIdentity *other_peer,
766 const struct GNUNET_MessageHeader *context_msg,
767 struct GNUNET_SET_Request *request)
769 struct AliceServiceSession *s = cls;
771 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
772 "Received intersection request from %s!\n",
773 GNUNET_i2s (other_peer));
774 if (0 != memcmp (other_peer,
776 sizeof (struct GNUNET_PeerIdentity)))
782 = GNUNET_SET_accept (request,
783 GNUNET_SET_RESULT_REMOVED,
784 (struct GNUNET_SET_Option[]) {{ 0 }},
785 &cb_intersection_element_removed,
787 if (NULL == s->intersection_op)
790 s->status = GNUNET_SCALARPRODUCT_STATUS_FAILURE;
791 prepare_client_end_notification (s);
795 GNUNET_SET_commit (s->intersection_op,
796 s->intersection_set))
799 s->status = GNUNET_SCALARPRODUCT_STATUS_FAILURE;
800 prepare_client_end_notification (s);
807 * Our client has finished sending us its multipart message.
809 * @param session the service session context
812 client_request_complete_alice (struct AliceServiceSession *s)
814 struct GNUNET_MQ_MessageHandler cadet_handlers[] = {
815 GNUNET_MQ_hd_fixed_size (bobs_cryptodata_message,
816 GNUNET_MESSAGE_TYPE_SCALARPRODUCT_ECC_BOB_CRYPTODATA,
817 struct EccBobCryptodataMessage,
819 GNUNET_MQ_handler_end ()
821 struct EccServiceRequestMessage *msg;
822 struct GNUNET_MQ_Envelope *e;
823 struct GNUNET_HashCode set_sid;
825 GNUNET_CRYPTO_hash (&s->session_id,
826 sizeof (struct GNUNET_HashCode),
828 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
829 "Creating new channel for session with key %s.\n",
830 GNUNET_h2s (&s->session_id));
832 = GNUNET_CADET_channel_create (my_cadet,
836 GNUNET_CADET_OPTION_RELIABLE,
838 &cb_channel_destruction,
840 if (NULL == s->channel)
842 s->status = GNUNET_SCALARPRODUCT_STATUS_FAILURE;
843 prepare_client_end_notification (s);
846 s->cadet_mq = GNUNET_CADET_get_mq (s->channel);
847 s->intersection_listen
848 = GNUNET_SET_listen (cfg,
849 GNUNET_SET_OPERATION_INTERSECTION,
851 &cb_intersection_request_alice,
853 if (NULL == s->intersection_listen)
855 s->status = GNUNET_SCALARPRODUCT_STATUS_FAILURE;
856 GNUNET_CADET_channel_destroy (s->channel);
858 prepare_client_end_notification (s);
862 e = GNUNET_MQ_msg (msg,
863 GNUNET_MESSAGE_TYPE_SCALARPRODUCT_ECC_SESSION_INITIALIZATION);
864 msg->session_id = s->session_id;
865 GNUNET_MQ_send (s->cadet_mq,
871 * We're receiving additional set data. Check if
872 * @a msg is well-formed.
874 * @param cls client identification of the client
875 * @param msg the actual message
876 * @return #GNUNET_OK if @a msg is well-formed
879 check_alice_client_message_multipart (void *cls,
880 const struct ComputationBobCryptodataMultipartMessage *msg)
882 struct AliceServiceSession *s = cls;
883 uint32_t contained_count;
886 msize = ntohs (msg->header.size);
887 contained_count = ntohl (msg->element_count_contained);
888 if ( (msize != (sizeof (struct ComputationBobCryptodataMultipartMessage) +
889 contained_count * sizeof (struct GNUNET_SCALARPRODUCT_Element))) ||
890 (0 == contained_count) ||
891 (s->total == s->client_received_element_count) ||
892 (s->total < s->client_received_element_count + contained_count) )
895 return GNUNET_SYSERR;
902 * We're receiving additional set data. Add it to our
903 * set and if we are done, initiate the transaction.
905 * @param cls client identification of the client
906 * @param msg the actual message
909 handle_alice_client_message_multipart (void *cls,
910 const struct ComputationBobCryptodataMultipartMessage *msg)
912 struct AliceServiceSession *s = cls;
913 uint32_t contained_count;
914 const struct GNUNET_SCALARPRODUCT_Element *elements;
915 struct GNUNET_SET_Element set_elem;
916 struct GNUNET_SCALARPRODUCT_Element *elem;
918 contained_count = ntohl (msg->element_count_contained);
919 s->client_received_element_count += contained_count;
920 elements = (const struct GNUNET_SCALARPRODUCT_Element *) &msg[1];
921 for (uint32_t i = 0; i < contained_count; i++)
923 elem = GNUNET_new (struct GNUNET_SCALARPRODUCT_Element);
926 sizeof (struct GNUNET_SCALARPRODUCT_Element));
928 GNUNET_CONTAINER_multihashmap_put (s->intersected_elements,
931 GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY))
937 set_elem.data = &elem->key;
938 set_elem.size = sizeof (elem->key);
939 set_elem.element_type = 0;
940 GNUNET_SET_add_element (s->intersection_set,
943 s->used_element_count++;
945 GNUNET_SERVICE_client_continue (s->client);
946 if (s->total != s->client_received_element_count)
949 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
950 "Received client multipart data, waiting for more!\n");
953 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
954 "Launching computation\n");
955 client_request_complete_alice (s);
960 * Handler for Alice's client request message.
961 * Check that @a msg is well-formed.
963 * @param cls identification of the client
964 * @param msg the actual message
965 * @return #GNUNET_OK if @a msg is well-formed
968 check_alice_client_message (void *cls,
969 const struct AliceComputationMessage *msg)
971 struct AliceServiceSession *s = cls;
973 uint32_t total_count;
974 uint32_t contained_count;
976 if (NULL != s->intersected_elements)
978 /* only one concurrent session per client connection allowed,
979 simplifies logic a lot... */
981 return GNUNET_SYSERR;
983 msize = ntohs (msg->header.size);
984 total_count = ntohl (msg->element_count_total);
985 contained_count = ntohl (msg->element_count_contained);
986 if ( (0 == total_count) ||
987 (0 == contained_count) ||
988 (msize != (sizeof (struct AliceComputationMessage) +
989 contained_count * sizeof (struct GNUNET_SCALARPRODUCT_Element))) )
992 return GNUNET_SYSERR;
999 * Handler for Alice's client request message.
1000 * We are doing request-initiation to compute a scalar product with a peer.
1002 * @param cls identification of the client
1003 * @param msg the actual message
1006 handle_alice_client_message (void *cls,
1007 const struct AliceComputationMessage *msg)
1009 struct AliceServiceSession *s = cls;
1010 uint32_t contained_count;
1011 uint32_t total_count;
1012 const struct GNUNET_SCALARPRODUCT_Element *elements;
1013 struct GNUNET_SET_Element set_elem;
1014 struct GNUNET_SCALARPRODUCT_Element *elem;
1016 total_count = ntohl (msg->element_count_total);
1017 contained_count = ntohl (msg->element_count_contained);
1018 s->peer = msg->peer;
1019 s->status = GNUNET_SCALARPRODUCT_STATUS_ACTIVE;
1020 s->total = total_count;
1021 s->client_received_element_count = contained_count;
1022 s->session_id = msg->session_key;
1023 elements = (const struct GNUNET_SCALARPRODUCT_Element *) &msg[1];
1024 s->intersected_elements = GNUNET_CONTAINER_multihashmap_create (s->total,
1026 s->intersection_set = GNUNET_SET_create (cfg,
1027 GNUNET_SET_OPERATION_INTERSECTION);
1028 for (uint32_t i = 0; i < contained_count; i++)
1030 if (0 == GNUNET_ntohll (elements[i].value))
1032 elem = GNUNET_new (struct GNUNET_SCALARPRODUCT_Element);
1033 GNUNET_memcpy (elem,
1035 sizeof (struct GNUNET_SCALARPRODUCT_Element));
1036 if (GNUNET_SYSERR ==
1037 GNUNET_CONTAINER_multihashmap_put (s->intersected_elements,
1040 GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY))
1042 /* element with same key encountered twice! */
1047 set_elem.data = &elem->key;
1048 set_elem.size = sizeof (elem->key);
1049 set_elem.element_type = 0;
1050 GNUNET_SET_add_element (s->intersection_set,
1053 s->used_element_count++;
1055 GNUNET_SERVICE_client_continue (s->client);
1056 if (s->total != s->client_received_element_count)
1058 /* wait for multipart msg */
1059 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1060 "Received partial client request, waiting for more!\n");
1063 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1064 "Launching computation\n");
1065 client_request_complete_alice (s);
1070 * Task run during shutdown.
1076 shutdown_task (void *cls)
1078 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1079 "Shutting down, initiating cleanup.\n");
1080 // FIXME: we have to cut our connections to CADET first!
1081 if (NULL != my_cadet)
1083 GNUNET_CADET_disconnect (my_cadet);
1088 GNUNET_CRYPTO_ecc_dlog_release (edc);
1095 * A client connected.
1097 * Setup the associated data structure.
1099 * @param cls closure, NULL
1100 * @param client identification of the client
1101 * @param mq message queue to communicate with @a client
1102 * @return our `struct AliceServiceSession`
1105 client_connect_cb (void *cls,
1106 struct GNUNET_SERVICE_Client *client,
1107 struct GNUNET_MQ_Handle *mq)
1109 struct AliceServiceSession *s;
1111 s = GNUNET_new (struct AliceServiceSession);
1119 * A client disconnected.
1121 * Remove the associated session(s), release data structures
1122 * and cancel pending outgoing transmissions to the client.
1124 * @param cls closure, NULL
1125 * @param client identification of the client
1126 * @param app_cls our `struct AliceServiceSession`
1129 client_disconnect_cb (void *cls,
1130 struct GNUNET_SERVICE_Client *client,
1133 struct AliceServiceSession *s = app_cls;
1135 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1136 "Client %p disconnected from us.\n",
1139 s->client_mq = NULL;
1140 destroy_service_session (s);
1145 * Initialization of the program and message handlers
1147 * @param cls closure
1148 * @param c configuration to use
1149 * @param service the initialized service
1153 const struct GNUNET_CONFIGURATION_Handle *c,
1154 struct GNUNET_SERVICE_Handle *service)
1157 edc = GNUNET_CRYPTO_ecc_dlog_prepare (MAX_RESULT,
1159 /* Select a random 'a' value for Alice */
1160 GNUNET_CRYPTO_ecc_rnd_mpi (edc,
1163 my_cadet = GNUNET_CADET_connect (cfg);
1164 if (NULL == my_cadet)
1166 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1167 _("Connect to CADET failed\n"));
1168 GNUNET_SCHEDULER_shutdown ();
1171 GNUNET_SCHEDULER_add_shutdown (&shutdown_task,
1178 * Define "main" method using service macro.
1181 ("scalarproduct-alice",
1182 GNUNET_SERVICE_OPTION_NONE,
1185 &client_disconnect_cb,
1187 GNUNET_MQ_hd_var_size (alice_client_message,
1188 GNUNET_MESSAGE_TYPE_SCALARPRODUCT_CLIENT_TO_ALICE,
1189 struct AliceComputationMessage,
1191 GNUNET_MQ_hd_var_size (alice_client_message_multipart,
1192 GNUNET_MESSAGE_TYPE_SCALARPRODUCT_CLIENT_MULTIPART_ALICE,
1193 struct ComputationBobCryptodataMultipartMessage,
1195 GNUNET_MQ_handler_end ());
1198 /* end of gnunet-service-scalarproduct-ecc_alice.c */