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/>.
18 SPDX-License-Identifier: AGPL3.0-or-later
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_SERVICE_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)
243 struct GNUNET_SERVICE_Client *c = s->client;
246 GNUNET_SERVICE_client_drop (c);
248 if (NULL != s->channel)
250 GNUNET_CADET_channel_destroy (s->channel);
253 if (NULL != s->intersected_elements)
255 GNUNET_CONTAINER_multihashmap_iterate (s->intersected_elements,
258 GNUNET_CONTAINER_multihashmap_destroy (s->intersected_elements);
259 s->intersected_elements = NULL;
261 if (NULL != s->intersection_listen)
263 GNUNET_SET_listen_cancel (s->intersection_listen);
264 s->intersection_listen = NULL;
266 if (NULL != s->intersection_op)
268 LOG (GNUNET_ERROR_TYPE_DEBUG,
269 "Set intersection, op still ongoing!\n");
270 GNUNET_SET_operation_cancel (s->intersection_op);
271 s->intersection_op = NULL;
273 if (NULL != s->intersection_set)
275 GNUNET_SET_destroy (s->intersection_set);
276 s->intersection_set = NULL;
278 if (NULL != s->sorted_elements)
280 for (i=0;i<s->used_element_count;i++)
281 gcry_mpi_release (s->sorted_elements[i].value);
282 GNUNET_free (s->sorted_elements);
283 s->sorted_elements = NULL;
285 if (NULL != s->product)
287 gcry_mpi_release (s->product);
295 * Notify the client that the session has failed. A message gets sent
296 * to Alice's client if we encountered any error.
298 * @param session the associated client session to fail or succeed
301 prepare_client_end_notification (struct AliceServiceSession *session)
303 struct ClientResponseMessage *msg;
304 struct GNUNET_MQ_Envelope *e;
306 if (NULL == session->client_mq)
307 return; /* no client left to be notified */
308 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
309 "Sending session-end notification with status %d to client for session %s\n",
311 GNUNET_h2s (&session->session_id));
312 e = GNUNET_MQ_msg (msg,
313 GNUNET_MESSAGE_TYPE_SCALARPRODUCT_RESULT);
314 msg->product_length = htonl (0);
315 msg->status = htonl (session->status);
316 GNUNET_MQ_send (session->client_mq,
322 * Prepare the final (positive) response we will send to Alice's
325 * @param s the session associated with our client.
328 transmit_client_response (struct AliceServiceSession *s)
330 struct ClientResponseMessage *msg;
331 struct GNUNET_MQ_Envelope *e;
332 unsigned char *product_exported = NULL;
333 size_t product_length = 0;
339 if (NULL == s->product)
342 prepare_client_end_notification (s);
345 value = gcry_mpi_new (0);
346 sign = gcry_mpi_cmp_ui (s->product, 0);
357 gcry_mpi_add (value, value, s->product);
361 /* result is exactly zero */
364 gcry_mpi_release (s->product);
368 (0 != (rc = gcry_mpi_aprint (GCRYMPI_FMT_STD,
373 LOG_GCRY (GNUNET_ERROR_TYPE_ERROR,
376 prepare_client_end_notification (s);
379 gcry_mpi_release (value);
380 e = GNUNET_MQ_msg_extra (msg,
382 GNUNET_MESSAGE_TYPE_SCALARPRODUCT_RESULT);
383 msg->status = htonl (GNUNET_SCALARPRODUCT_STATUS_SUCCESS);
384 msg->range = htonl (range);
385 msg->product_length = htonl (product_length);
386 if (NULL != product_exported)
388 GNUNET_memcpy (&msg[1],
391 GNUNET_free (product_exported);
393 GNUNET_MQ_send (s->client_mq,
395 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
396 "Sent result to client, session %s has ended!\n",
397 GNUNET_h2s (&s->session_id));
402 * Function called whenever a channel is destroyed. Should clean up
403 * any associated state.
405 * It must NOT call #GNUNET_CADET_channel_destroy() on the channel.
407 * @param cls the `struct AliceServiceSession`
408 * @param channel connection to the other end (henceforth invalid)
411 cb_channel_destruction (void *cls,
412 const struct GNUNET_CADET_Channel *channel)
414 struct AliceServiceSession *s = cls;
416 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
417 "Peer disconnected, terminating session %s with peer %s\n",
418 GNUNET_h2s (&s->session_id),
419 GNUNET_i2s (&s->peer));
421 if (GNUNET_SCALARPRODUCT_STATUS_ACTIVE == s->status)
423 /* We didn't get an answer yet, fail with error */
424 s->status = GNUNET_SCALARPRODUCT_STATUS_FAILURE;
425 prepare_client_end_notification (s);
431 * Compute our scalar product, done by Alice
433 * @param session the session associated with this computation
434 * @param prod_g_i_b_i value from Bob
435 * @param prod_h_i_b_i value from Bob
436 * @return product as MPI, never NULL
439 compute_scalar_product (struct AliceServiceSession *session,
440 gcry_mpi_point_t prod_g_i_b_i,
441 gcry_mpi_point_t prod_h_i_b_i)
443 gcry_mpi_point_t g_i_b_i_a_inv;
444 gcry_mpi_point_t g_ai_bi;
448 g_i_b_i_a_inv = GNUNET_CRYPTO_ecc_pmul_mpi (edc,
451 g_ai_bi = GNUNET_CRYPTO_ecc_add (edc,
454 gcry_mpi_point_release (g_i_b_i_a_inv);
455 ai_bi = GNUNET_CRYPTO_ecc_dlog (edc,
457 gcry_mpi_point_release (g_ai_bi);
458 if (INT_MAX == ai_bi)
461 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
462 "Scalar product result out of range\n");
465 ret = gcry_mpi_new (0);
468 gcry_mpi_set_ui (ret, ai_bi);
472 gcry_mpi_set_ui (ret, - ai_bi);
473 gcry_mpi_neg (ret, ret);
480 * Handle a response we got from another service we wanted to
481 * calculate a scalarproduct with.
483 * @param cls the `struct AliceServiceSession *`
484 * @param msg the actual message
487 handle_bobs_cryptodata_message (void *cls,
488 const struct EccBobCryptodataMessage *msg)
490 struct AliceServiceSession *s = cls;
491 gcry_mpi_point_t prod_g_i_b_i;
492 gcry_mpi_point_t prod_h_i_b_i;
495 contained = ntohl (msg->contained_element_count);
499 destroy_service_session (s);
502 if (NULL == s->sorted_elements)
504 /* we're not ready yet, how can Bob be? */
506 destroy_service_session (s);
509 if (s->total != s->client_received_element_count)
511 /* we're not ready yet, how can Bob be? */
513 destroy_service_session (s);
517 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
518 "Received %u crypto values from Bob\n",
519 (unsigned int) contained);
520 GNUNET_CADET_receive_done (s->channel);
521 prod_g_i_b_i = GNUNET_CRYPTO_ecc_bin_to_point (edc,
523 prod_h_i_b_i = GNUNET_CRYPTO_ecc_bin_to_point (edc,
525 s->product = compute_scalar_product (s,
528 gcry_mpi_point_release (prod_g_i_b_i);
529 gcry_mpi_point_release (prod_h_i_b_i);
530 transmit_client_response (s);
535 * Iterator to copy over messages from the hash map
536 * into an array for sorting.
538 * @param cls the `struct AliceServiceSession *`
539 * @param key the key (unused)
540 * @param value the `struct GNUNET_SCALARPRODUCT_Element *`
543 copy_element_cb (void *cls,
544 const struct GNUNET_HashCode *key,
547 struct AliceServiceSession *s = cls;
548 struct GNUNET_SCALARPRODUCT_Element *e = value;
552 mval = gcry_mpi_new (0);
553 val = (int64_t) GNUNET_ntohll (e->value);
555 gcry_mpi_sub_ui (mval, mval, -val);
557 gcry_mpi_add_ui (mval, mval, val);
558 s->sorted_elements [s->used_element_count].value = mval;
559 s->sorted_elements [s->used_element_count].key = &e->key;
560 s->used_element_count++;
566 * Compare two `struct MpiValue`s by key for sorting.
568 * @param a pointer to first `struct MpiValue *`
569 * @param b pointer to first `struct MpiValue *`
570 * @return -1 for a < b, 0 for a=b, 1 for a > b.
573 element_cmp (const void *a,
576 const struct MpiElement *ma = a;
577 const struct MpiElement *mb = b;
579 return GNUNET_CRYPTO_hash_cmp (ma->key,
585 * Maximum number of elements we can put into a single cryptodata
588 #define ELEMENT_CAPACITY ((GNUNET_CONSTANTS_MAX_CADET_MESSAGE_SIZE - 1 - sizeof (struct EccAliceCryptodataMessage)) / sizeof (struct GNUNET_CRYPTO_EccPoint))
592 * Send the cryptographic data from Alice to Bob.
593 * Does nothing if we already transferred all elements.
595 * @param s the associated service session
598 send_alices_cryptodata_message (struct AliceServiceSession *s)
600 struct EccAliceCryptodataMessage *msg;
601 struct GNUNET_MQ_Envelope *e;
602 struct GNUNET_CRYPTO_EccPoint *payload;
607 unsigned int todo_count;
610 = GNUNET_new_array (GNUNET_CONTAINER_multihashmap_size (s->intersected_elements),
612 s->used_element_count = 0;
613 GNUNET_CONTAINER_multihashmap_iterate (s->intersected_elements,
616 LOG (GNUNET_ERROR_TYPE_DEBUG,
617 "Finished intersection, %d items remain\n",
618 s->used_element_count);
619 qsort (s->sorted_elements,
620 s->used_element_count,
621 sizeof (struct MpiElement),
624 while (off < s->used_element_count)
626 todo_count = s->used_element_count - off;
627 if (todo_count > ELEMENT_CAPACITY)
628 todo_count = ELEMENT_CAPACITY;
629 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
630 "Sending %u/%u crypto values to Bob\n",
631 (unsigned int) todo_count,
632 (unsigned int) s->used_element_count);
634 e = GNUNET_MQ_msg_extra (msg,
635 todo_count * 2 * sizeof (struct GNUNET_CRYPTO_EccPoint),
636 GNUNET_MESSAGE_TYPE_SCALARPRODUCT_ECC_ALICE_CRYPTODATA);
637 GNUNET_MQ_env_set_options(e,
638 GNUNET_MQ_PREF_RELIABLE);
639 msg->contained_element_count = htonl (todo_count);
640 payload = (struct GNUNET_CRYPTO_EccPoint *) &msg[1];
641 r_ia = gcry_mpi_new (0);
642 r_ia_ai = gcry_mpi_new (0);
643 for (i = off; i < off + todo_count; i++)
646 gcry_mpi_point_t g_i;
647 gcry_mpi_point_t h_i;
649 r_i = GNUNET_CRYPTO_ecc_random_mod_n (edc);
650 g_i = GNUNET_CRYPTO_ecc_dexp_mpi (edc,
656 gcry_mpi_release (r_i);
657 /* r_ia_ai = r_ia + a_i */
658 gcry_mpi_add (r_ia_ai,
660 s->sorted_elements[i].value);
661 h_i = GNUNET_CRYPTO_ecc_dexp_mpi (edc,
663 GNUNET_CRYPTO_ecc_point_to_bin (edc,
665 &payload[(i - off) * 2]);
666 GNUNET_CRYPTO_ecc_point_to_bin (edc,
668 &payload[(i - off) * 2 + 1]);
669 gcry_mpi_point_release (g_i);
670 gcry_mpi_point_release (h_i);
672 gcry_mpi_release (r_ia);
673 gcry_mpi_release (r_ia_ai);
675 GNUNET_MQ_send (s->cadet_mq,
682 * Callback for set operation results. Called for each element
683 * that should be removed from the result set, and then once
684 * to indicate that the set intersection operation is done.
686 * @param cls closure with the `struct AliceServiceSession`
687 * @param element a result element, only valid if status is #GNUNET_SET_STATUS_OK
688 * @param current_size current set size
689 * @param status what has happened with the set intersection?
692 cb_intersection_element_removed (void *cls,
693 const struct GNUNET_SET_Element *element,
694 uint64_t current_size,
695 enum GNUNET_SET_Status status)
697 struct AliceServiceSession *s = cls;
698 struct GNUNET_SCALARPRODUCT_Element *se;
702 case GNUNET_SET_STATUS_OK:
703 /* this element has been removed from the set */
704 se = GNUNET_CONTAINER_multihashmap_get (s->intersected_elements,
706 GNUNET_assert (NULL != se);
707 LOG (GNUNET_ERROR_TYPE_DEBUG,
708 "Intersection removed element with key %s and value %lld\n",
709 GNUNET_h2s (&se->key),
710 (long long) GNUNET_ntohll (se->value));
711 GNUNET_assert (GNUNET_YES ==
712 GNUNET_CONTAINER_multihashmap_remove (s->intersected_elements,
717 case GNUNET_SET_STATUS_DONE:
718 s->intersection_op = NULL;
719 if (NULL != s->intersection_set)
721 GNUNET_SET_destroy (s->intersection_set);
722 s->intersection_set = NULL;
724 send_alices_cryptodata_message (s);
726 case GNUNET_SET_STATUS_HALF_DONE:
727 /* unexpected for intersection */
730 case GNUNET_SET_STATUS_FAILURE:
731 /* unhandled status code */
732 LOG (GNUNET_ERROR_TYPE_DEBUG,
733 "Set intersection failed!\n");
734 if (NULL != s->intersection_listen)
736 GNUNET_SET_listen_cancel (s->intersection_listen);
737 s->intersection_listen = NULL;
739 s->intersection_op = NULL;
740 if (NULL != s->intersection_set)
742 GNUNET_SET_destroy (s->intersection_set);
743 s->intersection_set = NULL;
745 s->status = GNUNET_SCALARPRODUCT_STATUS_FAILURE;
746 prepare_client_end_notification (s);
756 * Called when another peer wants to do a set operation with the
757 * local peer. If a listen error occurs, the @a request is NULL.
759 * @param cls closure with the `struct AliceServiceSession *`
760 * @param other_peer the other peer
761 * @param context_msg message with application specific information from
763 * @param request request from the other peer (never NULL), use GNUNET_SET_accept()
764 * to accept it, otherwise the request will be refused
765 * Note that we can't just return value from the listen callback,
766 * as it is also necessary to specify the set we want to do the
767 * operation with, whith sometimes can be derived from the context
768 * message. It's necessary to specify the timeout.
771 cb_intersection_request_alice (void *cls,
772 const struct GNUNET_PeerIdentity *other_peer,
773 const struct GNUNET_MessageHeader *context_msg,
774 struct GNUNET_SET_Request *request)
776 struct AliceServiceSession *s = cls;
778 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
779 "Received intersection request from %s!\n",
780 GNUNET_i2s (other_peer));
781 if (0 != GNUNET_memcmp (other_peer,
788 = GNUNET_SET_accept (request,
789 GNUNET_SET_RESULT_REMOVED,
790 (struct GNUNET_SET_Option[]) {{ 0 }},
791 &cb_intersection_element_removed,
793 if (NULL == s->intersection_op)
796 s->status = GNUNET_SCALARPRODUCT_STATUS_FAILURE;
797 prepare_client_end_notification (s);
801 GNUNET_SET_commit (s->intersection_op,
802 s->intersection_set))
805 s->status = GNUNET_SCALARPRODUCT_STATUS_FAILURE;
806 prepare_client_end_notification (s);
813 * Our client has finished sending us its multipart message.
815 * @param session the service session context
818 client_request_complete_alice (struct AliceServiceSession *s)
820 struct GNUNET_MQ_MessageHandler cadet_handlers[] = {
821 GNUNET_MQ_hd_fixed_size (bobs_cryptodata_message,
822 GNUNET_MESSAGE_TYPE_SCALARPRODUCT_ECC_BOB_CRYPTODATA,
823 struct EccBobCryptodataMessage,
825 GNUNET_MQ_handler_end ()
827 struct EccServiceRequestMessage *msg;
828 struct GNUNET_MQ_Envelope *e;
829 struct GNUNET_HashCode set_sid;
831 GNUNET_CRYPTO_hash (&s->session_id,
832 sizeof (struct GNUNET_HashCode),
834 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
835 "Creating new channel for session with key %s.\n",
836 GNUNET_h2s (&s->session_id));
838 = GNUNET_CADET_channel_create (my_cadet,
843 &cb_channel_destruction,
845 if (NULL == s->channel)
847 s->status = GNUNET_SCALARPRODUCT_STATUS_FAILURE;
848 prepare_client_end_notification (s);
851 s->cadet_mq = GNUNET_CADET_get_mq (s->channel);
852 s->intersection_listen
853 = GNUNET_SET_listen (cfg,
854 GNUNET_SET_OPERATION_INTERSECTION,
856 &cb_intersection_request_alice,
858 if (NULL == s->intersection_listen)
860 s->status = GNUNET_SCALARPRODUCT_STATUS_FAILURE;
861 GNUNET_CADET_channel_destroy (s->channel);
863 prepare_client_end_notification (s);
867 e = GNUNET_MQ_msg (msg,
868 GNUNET_MESSAGE_TYPE_SCALARPRODUCT_ECC_SESSION_INITIALIZATION);
869 GNUNET_MQ_env_set_options(e,
870 GNUNET_MQ_PREF_RELIABLE);
871 msg->session_id = s->session_id;
872 GNUNET_MQ_send (s->cadet_mq,
878 * We're receiving additional set data. Check if
879 * @a msg is well-formed.
881 * @param cls client identification of the client
882 * @param msg the actual message
883 * @return #GNUNET_OK if @a msg is well-formed
886 check_alice_client_message_multipart (void *cls,
887 const struct ComputationBobCryptodataMultipartMessage *msg)
889 struct AliceServiceSession *s = cls;
890 uint32_t contained_count;
893 msize = ntohs (msg->header.size);
894 contained_count = ntohl (msg->element_count_contained);
895 if ( (msize != (sizeof (struct ComputationBobCryptodataMultipartMessage) +
896 contained_count * sizeof (struct GNUNET_SCALARPRODUCT_Element))) ||
897 (0 == contained_count) ||
898 (s->total == s->client_received_element_count) ||
899 (s->total < s->client_received_element_count + contained_count) )
902 return GNUNET_SYSERR;
909 * We're receiving additional set data. Add it to our
910 * set and if we are done, initiate the transaction.
912 * @param cls client identification of the client
913 * @param msg the actual message
916 handle_alice_client_message_multipart (void *cls,
917 const struct ComputationBobCryptodataMultipartMessage *msg)
919 struct AliceServiceSession *s = cls;
920 uint32_t contained_count;
921 const struct GNUNET_SCALARPRODUCT_Element *elements;
922 struct GNUNET_SET_Element set_elem;
923 struct GNUNET_SCALARPRODUCT_Element *elem;
925 contained_count = ntohl (msg->element_count_contained);
926 s->client_received_element_count += contained_count;
927 elements = (const struct GNUNET_SCALARPRODUCT_Element *) &msg[1];
928 for (uint32_t i = 0; i < contained_count; i++)
930 elem = GNUNET_new (struct GNUNET_SCALARPRODUCT_Element);
933 sizeof (struct GNUNET_SCALARPRODUCT_Element));
935 GNUNET_CONTAINER_multihashmap_put (s->intersected_elements,
938 GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY))
944 set_elem.data = &elem->key;
945 set_elem.size = sizeof (elem->key);
946 set_elem.element_type = 0;
947 GNUNET_SET_add_element (s->intersection_set,
950 s->used_element_count++;
952 GNUNET_SERVICE_client_continue (s->client);
953 if (s->total != s->client_received_element_count)
956 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
957 "Received client multipart data, waiting for more!\n");
960 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
961 "Launching computation\n");
962 client_request_complete_alice (s);
967 * Handler for Alice's client request message.
968 * Check that @a msg is well-formed.
970 * @param cls identification of the client
971 * @param msg the actual message
972 * @return #GNUNET_OK if @a msg is well-formed
975 check_alice_client_message (void *cls,
976 const struct AliceComputationMessage *msg)
978 struct AliceServiceSession *s = cls;
980 uint32_t total_count;
981 uint32_t contained_count;
983 if (NULL != s->intersected_elements)
985 /* only one concurrent session per client connection allowed,
986 simplifies logic a lot... */
988 return GNUNET_SYSERR;
990 msize = ntohs (msg->header.size);
991 total_count = ntohl (msg->element_count_total);
992 contained_count = ntohl (msg->element_count_contained);
993 if ( (0 == total_count) ||
994 (0 == contained_count) ||
995 (msize != (sizeof (struct AliceComputationMessage) +
996 contained_count * sizeof (struct GNUNET_SCALARPRODUCT_Element))) )
999 return GNUNET_SYSERR;
1006 * Handler for Alice's client request message.
1007 * We are doing request-initiation to compute a scalar product with a peer.
1009 * @param cls identification of the client
1010 * @param msg the actual message
1013 handle_alice_client_message (void *cls,
1014 const struct AliceComputationMessage *msg)
1016 struct AliceServiceSession *s = cls;
1017 uint32_t contained_count;
1018 uint32_t total_count;
1019 const struct GNUNET_SCALARPRODUCT_Element *elements;
1020 struct GNUNET_SET_Element set_elem;
1021 struct GNUNET_SCALARPRODUCT_Element *elem;
1023 total_count = ntohl (msg->element_count_total);
1024 contained_count = ntohl (msg->element_count_contained);
1025 s->peer = msg->peer;
1026 s->status = GNUNET_SCALARPRODUCT_STATUS_ACTIVE;
1027 s->total = total_count;
1028 s->client_received_element_count = contained_count;
1029 s->session_id = msg->session_key;
1030 elements = (const struct GNUNET_SCALARPRODUCT_Element *) &msg[1];
1031 s->intersected_elements = GNUNET_CONTAINER_multihashmap_create (s->total,
1033 s->intersection_set = GNUNET_SET_create (cfg,
1034 GNUNET_SET_OPERATION_INTERSECTION);
1035 for (uint32_t i = 0; i < contained_count; i++)
1037 if (0 == GNUNET_ntohll (elements[i].value))
1039 elem = GNUNET_new (struct GNUNET_SCALARPRODUCT_Element);
1040 GNUNET_memcpy (elem,
1042 sizeof (struct GNUNET_SCALARPRODUCT_Element));
1043 if (GNUNET_SYSERR ==
1044 GNUNET_CONTAINER_multihashmap_put (s->intersected_elements,
1047 GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY))
1049 /* element with same key encountered twice! */
1054 set_elem.data = &elem->key;
1055 set_elem.size = sizeof (elem->key);
1056 set_elem.element_type = 0;
1057 GNUNET_SET_add_element (s->intersection_set,
1060 s->used_element_count++;
1062 GNUNET_SERVICE_client_continue (s->client);
1063 if (s->total != s->client_received_element_count)
1065 /* wait for multipart msg */
1066 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1067 "Received partial client request, waiting for more!\n");
1070 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1071 "Launching computation\n");
1072 client_request_complete_alice (s);
1077 * Task run during shutdown.
1083 shutdown_task (void *cls)
1085 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1086 "Shutting down, initiating cleanup.\n");
1087 // FIXME: we have to cut our connections to CADET first!
1088 if (NULL != my_cadet)
1090 GNUNET_CADET_disconnect (my_cadet);
1095 GNUNET_CRYPTO_ecc_dlog_release (edc);
1102 * A client connected.
1104 * Setup the associated data structure.
1106 * @param cls closure, NULL
1107 * @param client identification of the client
1108 * @param mq message queue to communicate with @a client
1109 * @return our `struct AliceServiceSession`
1112 client_connect_cb (void *cls,
1113 struct GNUNET_SERVICE_Client *client,
1114 struct GNUNET_MQ_Handle *mq)
1116 struct AliceServiceSession *s;
1118 s = GNUNET_new (struct AliceServiceSession);
1126 * A client disconnected.
1128 * Remove the associated session(s), release data structures
1129 * and cancel pending outgoing transmissions to the client.
1131 * @param cls closure, NULL
1132 * @param client identification of the client
1133 * @param app_cls our `struct AliceServiceSession`
1136 client_disconnect_cb (void *cls,
1137 struct GNUNET_SERVICE_Client *client,
1140 struct AliceServiceSession *s = app_cls;
1142 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1143 "Client %p disconnected from us.\n",
1146 s->client_mq = NULL;
1147 destroy_service_session (s);
1152 * Initialization of the program and message handlers
1154 * @param cls closure
1155 * @param c configuration to use
1156 * @param service the initialized service
1160 const struct GNUNET_CONFIGURATION_Handle *c,
1161 struct GNUNET_SERVICE_Handle *service)
1164 edc = GNUNET_CRYPTO_ecc_dlog_prepare (MAX_RESULT,
1166 /* Select a random 'a' value for Alice */
1167 GNUNET_CRYPTO_ecc_rnd_mpi (edc,
1170 my_cadet = GNUNET_CADET_connect (cfg);
1171 if (NULL == my_cadet)
1173 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1174 _("Connect to CADET failed\n"));
1175 GNUNET_SCHEDULER_shutdown ();
1178 GNUNET_SCHEDULER_add_shutdown (&shutdown_task,
1185 * Define "main" method using service macro.
1188 ("scalarproduct-alice",
1189 GNUNET_SERVICE_OPTION_NONE,
1192 &client_disconnect_cb,
1194 GNUNET_MQ_hd_var_size (alice_client_message,
1195 GNUNET_MESSAGE_TYPE_SCALARPRODUCT_CLIENT_TO_ALICE,
1196 struct AliceComputationMessage,
1198 GNUNET_MQ_hd_var_size (alice_client_message_multipart,
1199 GNUNET_MESSAGE_TYPE_SCALARPRODUCT_CLIENT_MULTIPART_ALICE,
1200 struct ComputationBobCryptodataMultipartMessage,
1202 GNUNET_MQ_handler_end ());
1205 /* end of gnunet-service-scalarproduct-ecc_alice.c */