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.
15 You should have received a copy of the GNU Affero General Public License
16 along with this program. If not, see <http://www.gnu.org/licenses/>.
19 * @file scalarproduct/gnunet-service-scalarproduct-ecc_alice.c
20 * @brief scalarproduct service implementation
21 * @author Christian M. Fuchs
22 * @author Christian Grothoff
27 #include "gnunet_util_lib.h"
28 #include "gnunet_core_service.h"
29 #include "gnunet_cadet_service.h"
30 #include "gnunet_applications.h"
31 #include "gnunet_protocols.h"
32 #include "gnunet_scalarproduct_service.h"
33 #include "gnunet_set_service.h"
34 #include "scalarproduct.h"
35 #include "gnunet-service-scalarproduct-ecc.h"
37 #define LOG(kind,...) GNUNET_log_from (kind, "scalarproduct-alice", __VA_ARGS__)
40 * Maximum allowed result value for the scalarproduct computation.
41 * DLOG will fail if the result is bigger. At 1 million, the
42 * precomputation takes about 2s on a fast machine.
44 #define MAX_RESULT (1024 * 1024)
47 * How many values should DLOG store in memory (determines baseline
48 * RAM consumption, roughly 100 bytes times the value given here).
49 * Should be about SQRT (MAX_RESULT), larger values will make the
50 * online computation faster.
52 #define MAX_RAM (1024)
55 * An encrypted element key-value pair.
60 * Key used to identify matching pairs of values to multiply.
61 * Points into an existing data structure, to avoid copying
62 * and doubling memory use.
64 const struct GNUNET_HashCode *key;
67 * a_i value, not disclosed to Bob.
75 * A scalarproduct session which tracks
76 * a request form the client to our final response.
78 struct AliceServiceSession
82 * (hopefully) unique transaction ID
84 struct GNUNET_HashCode session_id;
87 * Alice or Bob's peerID
89 struct GNUNET_PeerIdentity peer;
92 * The client this request is related to.
94 struct GNUNET_SERVICE_Client *client;
97 * The message queue for the client.
99 struct GNUNET_MQ_Handle *client_mq;
102 * The message queue for CADET.
104 struct GNUNET_MQ_Handle *cadet_mq;
107 * all non-0-value'd elements transmitted to us.
108 * Values are of type `struct GNUNET_SCALARPRODUCT_Element *`
110 struct GNUNET_CONTAINER_MultiHashMap *intersected_elements;
113 * Set of elements for which will conduction an intersection.
114 * the resulting elements are then used for computing the scalar product.
116 struct GNUNET_SET_Handle *intersection_set;
119 * Set of elements for which will conduction an intersection.
120 * the resulting elements are then used for computing the scalar product.
122 struct GNUNET_SET_OperationHandle *intersection_op;
125 * Handle to Alice's Intersection operation listening for Bob
127 struct GNUNET_SET_ListenHandle *intersection_listen;
130 * channel-handle associated with our cadet handle
132 struct GNUNET_CADET_Channel *channel;
135 * a(Alice), sorted array by key of length @e used_element_count.
137 struct MpiElement *sorted_elements;
140 * The computed scalar
145 * How many elements we were supplied with from the client (total
146 * count before intersection).
151 * How many elements actually are used for the scalar product.
152 * Size of the arrays in @e r and @e r_prime. Sometimes also
153 * reset to 0 and used as a counter!
155 uint32_t used_element_count;
158 * Already transferred elements from client to us.
159 * Less or equal than @e total.
161 uint32_t client_received_element_count;
164 * State of this session. In
165 * #GNUNET_SCALARPRODUCT_STATUS_ACTIVE while operation is
166 * ongoing, afterwards in #GNUNET_SCALARPRODUCT_STATUS_SUCCESS or
167 * #GNUNET_SCALARPRODUCT_STATUS_FAILURE.
169 enum GNUNET_SCALARPRODUCT_ResponseStatus status;
172 * Flag to prevent recursive calls to #destroy_service_session() from
181 * GNUnet configuration handle
183 static const struct GNUNET_CONFIGURATION_Handle *cfg;
186 * Context for DLOG operations on a curve.
188 static struct GNUNET_CRYPTO_EccDlogContext *edc;
191 * Alice's private key ('a').
193 static gcry_mpi_t my_privkey;
196 * Inverse of Alice's private key ('a_inv').
198 static gcry_mpi_t my_privkey_inv;
201 * Handle to the CADET service.
203 static struct GNUNET_CADET_Handle *my_cadet;
207 * Iterator called to free elements.
209 * @param cls the `struct AliceServiceSession *` (unused)
210 * @param key the key (unused)
211 * @param value value to free
212 * @return #GNUNET_OK (continue to iterate)
215 free_element_cb (void *cls,
216 const struct GNUNET_HashCode *key,
219 struct GNUNET_SCALARPRODUCT_Element *e = value;
227 * Destroy session state, we are done with it.
229 * @param s the session to free elements from
232 destroy_service_session (struct AliceServiceSession *s)
236 if (GNUNET_YES == s->in_destroy)
238 s->in_destroy = GNUNET_YES;
239 if (NULL != s->client)
241 struct GNUNET_SERVICE_Client *c = s->client;
244 GNUNET_SERVICE_client_drop (c);
246 if (NULL != s->channel)
248 GNUNET_CADET_channel_destroy (s->channel);
251 if (NULL != s->intersected_elements)
253 GNUNET_CONTAINER_multihashmap_iterate (s->intersected_elements,
256 GNUNET_CONTAINER_multihashmap_destroy (s->intersected_elements);
257 s->intersected_elements = NULL;
259 if (NULL != s->intersection_listen)
261 GNUNET_SET_listen_cancel (s->intersection_listen);
262 s->intersection_listen = NULL;
264 if (NULL != s->intersection_op)
266 LOG (GNUNET_ERROR_TYPE_DEBUG,
267 "Set intersection, op still ongoing!\n");
268 GNUNET_SET_operation_cancel (s->intersection_op);
269 s->intersection_op = NULL;
271 if (NULL != s->intersection_set)
273 GNUNET_SET_destroy (s->intersection_set);
274 s->intersection_set = NULL;
276 if (NULL != s->sorted_elements)
278 for (i=0;i<s->used_element_count;i++)
279 gcry_mpi_release (s->sorted_elements[i].value);
280 GNUNET_free (s->sorted_elements);
281 s->sorted_elements = NULL;
283 if (NULL != s->product)
285 gcry_mpi_release (s->product);
293 * Notify the client that the session has failed. A message gets sent
294 * to Alice's client if we encountered any error.
296 * @param session the associated client session to fail or succeed
299 prepare_client_end_notification (struct AliceServiceSession *session)
301 struct ClientResponseMessage *msg;
302 struct GNUNET_MQ_Envelope *e;
304 if (NULL == session->client_mq)
305 return; /* no client left to be notified */
306 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
307 "Sending session-end notification with status %d to client for session %s\n",
309 GNUNET_h2s (&session->session_id));
310 e = GNUNET_MQ_msg (msg,
311 GNUNET_MESSAGE_TYPE_SCALARPRODUCT_RESULT);
312 msg->product_length = htonl (0);
313 msg->status = htonl (session->status);
314 GNUNET_MQ_send (session->client_mq,
320 * Prepare the final (positive) response we will send to Alice's
323 * @param s the session associated with our client.
326 transmit_client_response (struct AliceServiceSession *s)
328 struct ClientResponseMessage *msg;
329 struct GNUNET_MQ_Envelope *e;
330 unsigned char *product_exported = NULL;
331 size_t product_length = 0;
337 if (NULL == s->product)
340 prepare_client_end_notification (s);
343 value = gcry_mpi_new (0);
344 sign = gcry_mpi_cmp_ui (s->product, 0);
355 gcry_mpi_add (value, value, s->product);
359 /* result is exactly zero */
362 gcry_mpi_release (s->product);
366 (0 != (rc = gcry_mpi_aprint (GCRYMPI_FMT_STD,
371 LOG_GCRY (GNUNET_ERROR_TYPE_ERROR,
374 prepare_client_end_notification (s);
377 gcry_mpi_release (value);
378 e = GNUNET_MQ_msg_extra (msg,
380 GNUNET_MESSAGE_TYPE_SCALARPRODUCT_RESULT);
381 msg->status = htonl (GNUNET_SCALARPRODUCT_STATUS_SUCCESS);
382 msg->range = htonl (range);
383 msg->product_length = htonl (product_length);
384 if (NULL != product_exported)
386 GNUNET_memcpy (&msg[1],
389 GNUNET_free (product_exported);
391 GNUNET_MQ_send (s->client_mq,
393 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
394 "Sent result to client, session %s has ended!\n",
395 GNUNET_h2s (&s->session_id));
400 * Function called whenever a channel is destroyed. Should clean up
401 * any associated state.
403 * It must NOT call #GNUNET_CADET_channel_destroy() on the channel.
405 * @param cls the `struct AliceServiceSession`
406 * @param channel connection to the other end (henceforth invalid)
409 cb_channel_destruction (void *cls,
410 const struct GNUNET_CADET_Channel *channel)
412 struct AliceServiceSession *s = cls;
414 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
415 "Peer disconnected, terminating session %s with peer %s\n",
416 GNUNET_h2s (&s->session_id),
417 GNUNET_i2s (&s->peer));
419 if (GNUNET_SCALARPRODUCT_STATUS_ACTIVE == s->status)
421 /* We didn't get an answer yet, fail with error */
422 s->status = GNUNET_SCALARPRODUCT_STATUS_FAILURE;
423 prepare_client_end_notification (s);
429 * Compute our scalar product, done by Alice
431 * @param session the session associated with this computation
432 * @param prod_g_i_b_i value from Bob
433 * @param prod_h_i_b_i value from Bob
434 * @return product as MPI, never NULL
437 compute_scalar_product (struct AliceServiceSession *session,
438 gcry_mpi_point_t prod_g_i_b_i,
439 gcry_mpi_point_t prod_h_i_b_i)
441 gcry_mpi_point_t g_i_b_i_a_inv;
442 gcry_mpi_point_t g_ai_bi;
446 g_i_b_i_a_inv = GNUNET_CRYPTO_ecc_pmul_mpi (edc,
449 g_ai_bi = GNUNET_CRYPTO_ecc_add (edc,
452 gcry_mpi_point_release (g_i_b_i_a_inv);
453 ai_bi = GNUNET_CRYPTO_ecc_dlog (edc,
455 gcry_mpi_point_release (g_ai_bi);
456 if (INT_MAX == ai_bi)
459 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
460 "Scalar product result out of range\n");
463 ret = gcry_mpi_new (0);
466 gcry_mpi_set_ui (ret, ai_bi);
470 gcry_mpi_set_ui (ret, - ai_bi);
471 gcry_mpi_neg (ret, ret);
478 * Handle a response we got from another service we wanted to
479 * calculate a scalarproduct with.
481 * @param cls the `struct AliceServiceSession *`
482 * @param msg the actual message
485 handle_bobs_cryptodata_message (void *cls,
486 const struct EccBobCryptodataMessage *msg)
488 struct AliceServiceSession *s = cls;
489 gcry_mpi_point_t prod_g_i_b_i;
490 gcry_mpi_point_t prod_h_i_b_i;
493 contained = ntohl (msg->contained_element_count);
497 destroy_service_session (s);
500 if (NULL == s->sorted_elements)
502 /* we're not ready yet, how can Bob be? */
504 destroy_service_session (s);
507 if (s->total != s->client_received_element_count)
509 /* we're not ready yet, how can Bob be? */
511 destroy_service_session (s);
515 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
516 "Received %u crypto values from Bob\n",
517 (unsigned int) contained);
518 GNUNET_CADET_receive_done (s->channel);
519 prod_g_i_b_i = GNUNET_CRYPTO_ecc_bin_to_point (edc,
521 prod_h_i_b_i = GNUNET_CRYPTO_ecc_bin_to_point (edc,
523 s->product = compute_scalar_product (s,
526 gcry_mpi_point_release (prod_g_i_b_i);
527 gcry_mpi_point_release (prod_h_i_b_i);
528 transmit_client_response (s);
533 * Iterator to copy over messages from the hash map
534 * into an array for sorting.
536 * @param cls the `struct AliceServiceSession *`
537 * @param key the key (unused)
538 * @param value the `struct GNUNET_SCALARPRODUCT_Element *`
541 copy_element_cb (void *cls,
542 const struct GNUNET_HashCode *key,
545 struct AliceServiceSession *s = cls;
546 struct GNUNET_SCALARPRODUCT_Element *e = value;
550 mval = gcry_mpi_new (0);
551 val = (int64_t) GNUNET_ntohll (e->value);
553 gcry_mpi_sub_ui (mval, mval, -val);
555 gcry_mpi_add_ui (mval, mval, val);
556 s->sorted_elements [s->used_element_count].value = mval;
557 s->sorted_elements [s->used_element_count].key = &e->key;
558 s->used_element_count++;
564 * Compare two `struct MpiValue`s by key for sorting.
566 * @param a pointer to first `struct MpiValue *`
567 * @param b pointer to first `struct MpiValue *`
568 * @return -1 for a < b, 0 for a=b, 1 for a > b.
571 element_cmp (const void *a,
574 const struct MpiElement *ma = a;
575 const struct MpiElement *mb = b;
577 return GNUNET_CRYPTO_hash_cmp (ma->key,
583 * Maximum number of elements we can put into a single cryptodata
586 #define ELEMENT_CAPACITY ((GNUNET_CONSTANTS_MAX_CADET_MESSAGE_SIZE - 1 - sizeof (struct EccAliceCryptodataMessage)) / sizeof (struct GNUNET_CRYPTO_EccPoint))
590 * Send the cryptographic data from Alice to Bob.
591 * Does nothing if we already transferred all elements.
593 * @param s the associated service session
596 send_alices_cryptodata_message (struct AliceServiceSession *s)
598 struct EccAliceCryptodataMessage *msg;
599 struct GNUNET_MQ_Envelope *e;
600 struct GNUNET_CRYPTO_EccPoint *payload;
605 unsigned int todo_count;
608 = GNUNET_new_array (GNUNET_CONTAINER_multihashmap_size (s->intersected_elements),
610 s->used_element_count = 0;
611 GNUNET_CONTAINER_multihashmap_iterate (s->intersected_elements,
614 LOG (GNUNET_ERROR_TYPE_DEBUG,
615 "Finished intersection, %d items remain\n",
616 s->used_element_count);
617 qsort (s->sorted_elements,
618 s->used_element_count,
619 sizeof (struct MpiElement),
622 while (off < s->used_element_count)
624 todo_count = s->used_element_count - off;
625 if (todo_count > ELEMENT_CAPACITY)
626 todo_count = ELEMENT_CAPACITY;
627 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
628 "Sending %u/%u crypto values to Bob\n",
629 (unsigned int) todo_count,
630 (unsigned int) s->used_element_count);
632 e = GNUNET_MQ_msg_extra (msg,
633 todo_count * 2 * sizeof (struct GNUNET_CRYPTO_EccPoint),
634 GNUNET_MESSAGE_TYPE_SCALARPRODUCT_ECC_ALICE_CRYPTODATA);
635 msg->contained_element_count = htonl (todo_count);
636 payload = (struct GNUNET_CRYPTO_EccPoint *) &msg[1];
637 r_ia = gcry_mpi_new (0);
638 r_ia_ai = gcry_mpi_new (0);
639 for (i = off; i < off + todo_count; i++)
642 gcry_mpi_point_t g_i;
643 gcry_mpi_point_t h_i;
645 r_i = GNUNET_CRYPTO_ecc_random_mod_n (edc);
646 g_i = GNUNET_CRYPTO_ecc_dexp_mpi (edc,
652 gcry_mpi_release (r_i);
653 /* r_ia_ai = r_ia + a_i */
654 gcry_mpi_add (r_ia_ai,
656 s->sorted_elements[i].value);
657 h_i = GNUNET_CRYPTO_ecc_dexp_mpi (edc,
659 GNUNET_CRYPTO_ecc_point_to_bin (edc,
661 &payload[(i - off) * 2]);
662 GNUNET_CRYPTO_ecc_point_to_bin (edc,
664 &payload[(i - off) * 2 + 1]);
665 gcry_mpi_point_release (g_i);
666 gcry_mpi_point_release (h_i);
668 gcry_mpi_release (r_ia);
669 gcry_mpi_release (r_ia_ai);
671 GNUNET_MQ_send (s->cadet_mq,
678 * Callback for set operation results. Called for each element
679 * that should be removed from the result set, and then once
680 * to indicate that the set intersection operation is done.
682 * @param cls closure with the `struct AliceServiceSession`
683 * @param element a result element, only valid if status is #GNUNET_SET_STATUS_OK
684 * @param current_size current set size
685 * @param status what has happened with the set intersection?
688 cb_intersection_element_removed (void *cls,
689 const struct GNUNET_SET_Element *element,
690 uint64_t current_size,
691 enum GNUNET_SET_Status status)
693 struct AliceServiceSession *s = cls;
694 struct GNUNET_SCALARPRODUCT_Element *se;
698 case GNUNET_SET_STATUS_OK:
699 /* this element has been removed from the set */
700 se = GNUNET_CONTAINER_multihashmap_get (s->intersected_elements,
702 GNUNET_assert (NULL != se);
703 LOG (GNUNET_ERROR_TYPE_DEBUG,
704 "Intersection removed element with key %s and value %lld\n",
705 GNUNET_h2s (&se->key),
706 (long long) GNUNET_ntohll (se->value));
707 GNUNET_assert (GNUNET_YES ==
708 GNUNET_CONTAINER_multihashmap_remove (s->intersected_elements,
713 case GNUNET_SET_STATUS_DONE:
714 s->intersection_op = NULL;
715 if (NULL != s->intersection_set)
717 GNUNET_SET_destroy (s->intersection_set);
718 s->intersection_set = NULL;
720 send_alices_cryptodata_message (s);
722 case GNUNET_SET_STATUS_HALF_DONE:
723 /* unexpected for intersection */
726 case GNUNET_SET_STATUS_FAILURE:
727 /* unhandled status code */
728 LOG (GNUNET_ERROR_TYPE_DEBUG,
729 "Set intersection failed!\n");
730 if (NULL != s->intersection_listen)
732 GNUNET_SET_listen_cancel (s->intersection_listen);
733 s->intersection_listen = NULL;
735 s->intersection_op = NULL;
736 if (NULL != s->intersection_set)
738 GNUNET_SET_destroy (s->intersection_set);
739 s->intersection_set = NULL;
741 s->status = GNUNET_SCALARPRODUCT_STATUS_FAILURE;
742 prepare_client_end_notification (s);
752 * Called when another peer wants to do a set operation with the
753 * local peer. If a listen error occurs, the @a request is NULL.
755 * @param cls closure with the `struct AliceServiceSession *`
756 * @param other_peer the other peer
757 * @param context_msg message with application specific information from
759 * @param request request from the other peer (never NULL), use GNUNET_SET_accept()
760 * to accept it, otherwise the request will be refused
761 * Note that we can't just return value from the listen callback,
762 * as it is also necessary to specify the set we want to do the
763 * operation with, whith sometimes can be derived from the context
764 * message. It's necessary to specify the timeout.
767 cb_intersection_request_alice (void *cls,
768 const struct GNUNET_PeerIdentity *other_peer,
769 const struct GNUNET_MessageHeader *context_msg,
770 struct GNUNET_SET_Request *request)
772 struct AliceServiceSession *s = cls;
774 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
775 "Received intersection request from %s!\n",
776 GNUNET_i2s (other_peer));
777 if (0 != memcmp (other_peer,
779 sizeof (struct GNUNET_PeerIdentity)))
785 = GNUNET_SET_accept (request,
786 GNUNET_SET_RESULT_REMOVED,
787 (struct GNUNET_SET_Option[]) {{ 0 }},
788 &cb_intersection_element_removed,
790 if (NULL == s->intersection_op)
793 s->status = GNUNET_SCALARPRODUCT_STATUS_FAILURE;
794 prepare_client_end_notification (s);
798 GNUNET_SET_commit (s->intersection_op,
799 s->intersection_set))
802 s->status = GNUNET_SCALARPRODUCT_STATUS_FAILURE;
803 prepare_client_end_notification (s);
810 * Our client has finished sending us its multipart message.
812 * @param session the service session context
815 client_request_complete_alice (struct AliceServiceSession *s)
817 struct GNUNET_MQ_MessageHandler cadet_handlers[] = {
818 GNUNET_MQ_hd_fixed_size (bobs_cryptodata_message,
819 GNUNET_MESSAGE_TYPE_SCALARPRODUCT_ECC_BOB_CRYPTODATA,
820 struct EccBobCryptodataMessage,
822 GNUNET_MQ_handler_end ()
824 struct EccServiceRequestMessage *msg;
825 struct GNUNET_MQ_Envelope *e;
826 struct GNUNET_HashCode set_sid;
828 GNUNET_CRYPTO_hash (&s->session_id,
829 sizeof (struct GNUNET_HashCode),
831 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
832 "Creating new channel for session with key %s.\n",
833 GNUNET_h2s (&s->session_id));
835 = GNUNET_CADET_channel_create (my_cadet,
839 GNUNET_CADET_OPTION_RELIABLE,
841 &cb_channel_destruction,
843 if (NULL == s->channel)
845 s->status = GNUNET_SCALARPRODUCT_STATUS_FAILURE;
846 prepare_client_end_notification (s);
849 s->cadet_mq = GNUNET_CADET_get_mq (s->channel);
850 s->intersection_listen
851 = GNUNET_SET_listen (cfg,
852 GNUNET_SET_OPERATION_INTERSECTION,
854 &cb_intersection_request_alice,
856 if (NULL == s->intersection_listen)
858 s->status = GNUNET_SCALARPRODUCT_STATUS_FAILURE;
859 GNUNET_CADET_channel_destroy (s->channel);
861 prepare_client_end_notification (s);
865 e = GNUNET_MQ_msg (msg,
866 GNUNET_MESSAGE_TYPE_SCALARPRODUCT_ECC_SESSION_INITIALIZATION);
867 msg->session_id = s->session_id;
868 GNUNET_MQ_send (s->cadet_mq,
874 * We're receiving additional set data. Check if
875 * @a msg is well-formed.
877 * @param cls client identification of the client
878 * @param msg the actual message
879 * @return #GNUNET_OK if @a msg is well-formed
882 check_alice_client_message_multipart (void *cls,
883 const struct ComputationBobCryptodataMultipartMessage *msg)
885 struct AliceServiceSession *s = cls;
886 uint32_t contained_count;
889 msize = ntohs (msg->header.size);
890 contained_count = ntohl (msg->element_count_contained);
891 if ( (msize != (sizeof (struct ComputationBobCryptodataMultipartMessage) +
892 contained_count * sizeof (struct GNUNET_SCALARPRODUCT_Element))) ||
893 (0 == contained_count) ||
894 (s->total == s->client_received_element_count) ||
895 (s->total < s->client_received_element_count + contained_count) )
898 return GNUNET_SYSERR;
905 * We're receiving additional set data. Add it to our
906 * set and if we are done, initiate the transaction.
908 * @param cls client identification of the client
909 * @param msg the actual message
912 handle_alice_client_message_multipart (void *cls,
913 const struct ComputationBobCryptodataMultipartMessage *msg)
915 struct AliceServiceSession *s = cls;
916 uint32_t contained_count;
917 const struct GNUNET_SCALARPRODUCT_Element *elements;
918 struct GNUNET_SET_Element set_elem;
919 struct GNUNET_SCALARPRODUCT_Element *elem;
921 contained_count = ntohl (msg->element_count_contained);
922 s->client_received_element_count += contained_count;
923 elements = (const struct GNUNET_SCALARPRODUCT_Element *) &msg[1];
924 for (uint32_t i = 0; i < contained_count; i++)
926 elem = GNUNET_new (struct GNUNET_SCALARPRODUCT_Element);
929 sizeof (struct GNUNET_SCALARPRODUCT_Element));
931 GNUNET_CONTAINER_multihashmap_put (s->intersected_elements,
934 GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY))
940 set_elem.data = &elem->key;
941 set_elem.size = sizeof (elem->key);
942 set_elem.element_type = 0;
943 GNUNET_SET_add_element (s->intersection_set,
946 s->used_element_count++;
948 GNUNET_SERVICE_client_continue (s->client);
949 if (s->total != s->client_received_element_count)
952 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
953 "Received client multipart data, waiting for more!\n");
956 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
957 "Launching computation\n");
958 client_request_complete_alice (s);
963 * Handler for Alice's client request message.
964 * Check that @a msg is well-formed.
966 * @param cls identification of the client
967 * @param msg the actual message
968 * @return #GNUNET_OK if @a msg is well-formed
971 check_alice_client_message (void *cls,
972 const struct AliceComputationMessage *msg)
974 struct AliceServiceSession *s = cls;
976 uint32_t total_count;
977 uint32_t contained_count;
979 if (NULL != s->intersected_elements)
981 /* only one concurrent session per client connection allowed,
982 simplifies logic a lot... */
984 return GNUNET_SYSERR;
986 msize = ntohs (msg->header.size);
987 total_count = ntohl (msg->element_count_total);
988 contained_count = ntohl (msg->element_count_contained);
989 if ( (0 == total_count) ||
990 (0 == contained_count) ||
991 (msize != (sizeof (struct AliceComputationMessage) +
992 contained_count * sizeof (struct GNUNET_SCALARPRODUCT_Element))) )
995 return GNUNET_SYSERR;
1002 * Handler for Alice's client request message.
1003 * We are doing request-initiation to compute a scalar product with a peer.
1005 * @param cls identification of the client
1006 * @param msg the actual message
1009 handle_alice_client_message (void *cls,
1010 const struct AliceComputationMessage *msg)
1012 struct AliceServiceSession *s = cls;
1013 uint32_t contained_count;
1014 uint32_t total_count;
1015 const struct GNUNET_SCALARPRODUCT_Element *elements;
1016 struct GNUNET_SET_Element set_elem;
1017 struct GNUNET_SCALARPRODUCT_Element *elem;
1019 total_count = ntohl (msg->element_count_total);
1020 contained_count = ntohl (msg->element_count_contained);
1021 s->peer = msg->peer;
1022 s->status = GNUNET_SCALARPRODUCT_STATUS_ACTIVE;
1023 s->total = total_count;
1024 s->client_received_element_count = contained_count;
1025 s->session_id = msg->session_key;
1026 elements = (const struct GNUNET_SCALARPRODUCT_Element *) &msg[1];
1027 s->intersected_elements = GNUNET_CONTAINER_multihashmap_create (s->total,
1029 s->intersection_set = GNUNET_SET_create (cfg,
1030 GNUNET_SET_OPERATION_INTERSECTION);
1031 for (uint32_t i = 0; i < contained_count; i++)
1033 if (0 == GNUNET_ntohll (elements[i].value))
1035 elem = GNUNET_new (struct GNUNET_SCALARPRODUCT_Element);
1036 GNUNET_memcpy (elem,
1038 sizeof (struct GNUNET_SCALARPRODUCT_Element));
1039 if (GNUNET_SYSERR ==
1040 GNUNET_CONTAINER_multihashmap_put (s->intersected_elements,
1043 GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY))
1045 /* element with same key encountered twice! */
1050 set_elem.data = &elem->key;
1051 set_elem.size = sizeof (elem->key);
1052 set_elem.element_type = 0;
1053 GNUNET_SET_add_element (s->intersection_set,
1056 s->used_element_count++;
1058 GNUNET_SERVICE_client_continue (s->client);
1059 if (s->total != s->client_received_element_count)
1061 /* wait for multipart msg */
1062 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1063 "Received partial client request, waiting for more!\n");
1066 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1067 "Launching computation\n");
1068 client_request_complete_alice (s);
1073 * Task run during shutdown.
1079 shutdown_task (void *cls)
1081 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1082 "Shutting down, initiating cleanup.\n");
1083 // FIXME: we have to cut our connections to CADET first!
1084 if (NULL != my_cadet)
1086 GNUNET_CADET_disconnect (my_cadet);
1091 GNUNET_CRYPTO_ecc_dlog_release (edc);
1098 * A client connected.
1100 * Setup the associated data structure.
1102 * @param cls closure, NULL
1103 * @param client identification of the client
1104 * @param mq message queue to communicate with @a client
1105 * @return our `struct AliceServiceSession`
1108 client_connect_cb (void *cls,
1109 struct GNUNET_SERVICE_Client *client,
1110 struct GNUNET_MQ_Handle *mq)
1112 struct AliceServiceSession *s;
1114 s = GNUNET_new (struct AliceServiceSession);
1122 * A client disconnected.
1124 * Remove the associated session(s), release data structures
1125 * and cancel pending outgoing transmissions to the client.
1127 * @param cls closure, NULL
1128 * @param client identification of the client
1129 * @param app_cls our `struct AliceServiceSession`
1132 client_disconnect_cb (void *cls,
1133 struct GNUNET_SERVICE_Client *client,
1136 struct AliceServiceSession *s = app_cls;
1138 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1139 "Client %p disconnected from us.\n",
1142 s->client_mq = NULL;
1143 destroy_service_session (s);
1148 * Initialization of the program and message handlers
1150 * @param cls closure
1151 * @param c configuration to use
1152 * @param service the initialized service
1156 const struct GNUNET_CONFIGURATION_Handle *c,
1157 struct GNUNET_SERVICE_Handle *service)
1160 edc = GNUNET_CRYPTO_ecc_dlog_prepare (MAX_RESULT,
1162 /* Select a random 'a' value for Alice */
1163 GNUNET_CRYPTO_ecc_rnd_mpi (edc,
1166 my_cadet = GNUNET_CADET_connect (cfg);
1167 if (NULL == my_cadet)
1169 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1170 _("Connect to CADET failed\n"));
1171 GNUNET_SCHEDULER_shutdown ();
1174 GNUNET_SCHEDULER_add_shutdown (&shutdown_task,
1181 * Define "main" method using service macro.
1184 ("scalarproduct-alice",
1185 GNUNET_SERVICE_OPTION_NONE,
1188 &client_disconnect_cb,
1190 GNUNET_MQ_hd_var_size (alice_client_message,
1191 GNUNET_MESSAGE_TYPE_SCALARPRODUCT_CLIENT_TO_ALICE,
1192 struct AliceComputationMessage,
1194 GNUNET_MQ_hd_var_size (alice_client_message_multipart,
1195 GNUNET_MESSAGE_TYPE_SCALARPRODUCT_CLIENT_MULTIPART_ALICE,
1196 struct ComputationBobCryptodataMultipartMessage,
1198 GNUNET_MQ_handler_end ());
1201 /* end of gnunet-service-scalarproduct-ecc_alice.c */