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, ...) \
40 GNUNET_log_from (kind, "scalarproduct-alice", __VA_ARGS__)
43 * Maximum allowed result value for the scalarproduct computation.
44 * DLOG will fail if the result is bigger. At 1 million, the
45 * precomputation takes about 2s on a fast machine.
47 #define MAX_RESULT (1024 * 1024)
50 * How many values should DLOG store in memory (determines baseline
51 * RAM consumption, roughly 100 bytes times the value given here).
52 * Should be about SQRT (MAX_RESULT), larger values will make the
53 * online computation faster.
55 #define MAX_RAM (1024)
58 * An encrypted element key-value pair.
63 * Key used to identify matching pairs of values to multiply.
64 * Points into an existing data structure, to avoid copying
65 * and doubling memory use.
67 const struct GNUNET_HashCode *key;
70 * 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
83 * (hopefully) unique transaction ID
85 struct GNUNET_HashCode session_id;
88 * Alice or Bob's peerID
90 struct GNUNET_PeerIdentity peer;
93 * The client this request is related to.
95 struct GNUNET_SERVICE_Client *client;
98 * The message queue for the client.
100 struct GNUNET_MQ_Handle *client_mq;
103 * The message queue for CADET.
105 struct GNUNET_MQ_Handle *cadet_mq;
108 * all non-0-value'd elements transmitted to us.
109 * Values are of type `struct GNUNET_SCALARPRODUCT_Element *`
111 struct GNUNET_CONTAINER_MultiHashMap *intersected_elements;
114 * Set of elements for which will conduction an intersection.
115 * the resulting elements are then used for computing the scalar product.
117 struct GNUNET_SET_Handle *intersection_set;
120 * Set of elements for which will conduction an intersection.
121 * the resulting elements are then used for computing the scalar product.
123 struct GNUNET_SET_OperationHandle *intersection_op;
126 * Handle to Alice's Intersection operation listening for Bob
128 struct GNUNET_SET_ListenHandle *intersection_listen;
131 * channel-handle associated with our cadet handle
133 struct GNUNET_CADET_Channel *channel;
136 * a(Alice), sorted array by key of length @e used_element_count.
138 struct MpiElement *sorted_elements;
141 * The computed scalar
146 * How many elements we were supplied with from the client (total
147 * count before intersection).
152 * How many elements actually are used for the scalar product.
153 * Size of the arrays in @e r and @e r_prime. Sometimes also
154 * reset to 0 and used as a counter!
156 uint32_t used_element_count;
159 * Already transferred elements from client to us.
160 * Less or equal than @e total.
162 uint32_t client_received_element_count;
165 * State of this session. In
166 * #GNUNET_SCALARPRODUCT_STATUS_ACTIVE while operation is
167 * ongoing, afterwards in #GNUNET_SCALARPRODUCT_STATUS_SUCCESS or
168 * #GNUNET_SCALARPRODUCT_STATUS_FAILURE.
170 enum GNUNET_SCALARPRODUCT_ResponseStatus status;
173 * 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, const struct GNUNET_HashCode *key, void *value)
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)
239 struct GNUNET_SERVICE_Client *c = s->client;
242 GNUNET_SERVICE_client_drop (c);
244 if (NULL != s->channel)
246 GNUNET_CADET_channel_destroy (s->channel);
249 if (NULL != s->intersected_elements)
251 GNUNET_CONTAINER_multihashmap_iterate (s->intersected_elements,
254 GNUNET_CONTAINER_multihashmap_destroy (s->intersected_elements);
255 s->intersected_elements = NULL;
257 if (NULL != s->intersection_listen)
259 GNUNET_SET_listen_cancel (s->intersection_listen);
260 s->intersection_listen = NULL;
262 if (NULL != s->intersection_op)
264 LOG (GNUNET_ERROR_TYPE_DEBUG, "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 */
304 GNUNET_ERROR_TYPE_DEBUG,
305 "Sending session-end notification with status %d to client for session %s\n",
307 GNUNET_h2s (&session->session_id));
308 e = GNUNET_MQ_msg (msg, GNUNET_MESSAGE_TYPE_SCALARPRODUCT_RESULT);
309 msg->product_length = htonl (0);
310 msg->status = htonl (session->status);
311 GNUNET_MQ_send (session->client_mq, e);
316 * Prepare the final (positive) response we will send to Alice's
319 * @param s the session associated with our client.
322 transmit_client_response (struct AliceServiceSession *s)
324 struct ClientResponseMessage *msg;
325 struct GNUNET_MQ_Envelope *e;
326 unsigned char *product_exported = NULL;
327 size_t product_length = 0;
333 if (NULL == s->product)
336 prepare_client_end_notification (s);
339 value = gcry_mpi_new (0);
340 sign = gcry_mpi_cmp_ui (s->product, 0);
344 gcry_mpi_sub (value, value, s->product);
349 gcry_mpi_add (value, value, s->product);
353 /* result is exactly zero */
356 gcry_mpi_release (s->product);
359 if ((0 != range) && (0 != (rc = gcry_mpi_aprint (GCRYMPI_FMT_STD,
364 LOG_GCRY (GNUNET_ERROR_TYPE_ERROR, "gcry_mpi_scan", rc);
365 prepare_client_end_notification (s);
368 gcry_mpi_release (value);
369 e = GNUNET_MQ_msg_extra (msg,
371 GNUNET_MESSAGE_TYPE_SCALARPRODUCT_RESULT);
372 msg->status = htonl (GNUNET_SCALARPRODUCT_STATUS_SUCCESS);
373 msg->range = htonl (range);
374 msg->product_length = htonl (product_length);
375 if (NULL != product_exported)
377 GNUNET_memcpy (&msg[1], product_exported, product_length);
378 GNUNET_free (product_exported);
380 GNUNET_MQ_send (s->client_mq, e);
381 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
382 "Sent result to client, session %s has ended!\n",
383 GNUNET_h2s (&s->session_id));
388 * Function called whenever a channel is destroyed. Should clean up
389 * any associated state.
391 * It must NOT call #GNUNET_CADET_channel_destroy() on the channel.
393 * @param cls the `struct AliceServiceSession`
394 * @param channel connection to the other end (henceforth invalid)
397 cb_channel_destruction (void *cls, const struct GNUNET_CADET_Channel *channel)
399 struct AliceServiceSession *s = cls;
401 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
402 "Peer disconnected, terminating session %s with peer %s\n",
403 GNUNET_h2s (&s->session_id),
404 GNUNET_i2s (&s->peer));
406 if (GNUNET_SCALARPRODUCT_STATUS_ACTIVE == s->status)
408 /* We didn't get an answer yet, fail with error */
409 s->status = GNUNET_SCALARPRODUCT_STATUS_FAILURE;
410 prepare_client_end_notification (s);
416 * Compute our scalar product, done by Alice
418 * @param session the session associated with this computation
419 * @param prod_g_i_b_i value from Bob
420 * @param prod_h_i_b_i value from Bob
421 * @return product as MPI, never NULL
424 compute_scalar_product (struct AliceServiceSession *session,
425 gcry_mpi_point_t prod_g_i_b_i,
426 gcry_mpi_point_t prod_h_i_b_i)
428 gcry_mpi_point_t g_i_b_i_a_inv;
429 gcry_mpi_point_t g_ai_bi;
434 GNUNET_CRYPTO_ecc_pmul_mpi (edc, prod_g_i_b_i, my_privkey_inv);
435 g_ai_bi = GNUNET_CRYPTO_ecc_add (edc, g_i_b_i_a_inv, prod_h_i_b_i);
436 gcry_mpi_point_release (g_i_b_i_a_inv);
437 ai_bi = GNUNET_CRYPTO_ecc_dlog (edc, g_ai_bi);
438 gcry_mpi_point_release (g_ai_bi);
439 if (INT_MAX == ai_bi)
442 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
443 "Scalar product result out of range\n");
446 ret = gcry_mpi_new (0);
449 gcry_mpi_set_ui (ret, ai_bi);
453 gcry_mpi_set_ui (ret, -ai_bi);
454 gcry_mpi_neg (ret, ret);
461 * Handle a response we got from another service we wanted to
462 * calculate a scalarproduct with.
464 * @param cls the `struct AliceServiceSession *`
465 * @param msg the actual message
468 handle_bobs_cryptodata_message (void *cls,
469 const struct EccBobCryptodataMessage *msg)
471 struct AliceServiceSession *s = cls;
472 gcry_mpi_point_t prod_g_i_b_i;
473 gcry_mpi_point_t prod_h_i_b_i;
476 contained = ntohl (msg->contained_element_count);
480 destroy_service_session (s);
483 if (NULL == s->sorted_elements)
485 /* we're not ready yet, how can Bob be? */
487 destroy_service_session (s);
490 if (s->total != s->client_received_element_count)
492 /* we're not ready yet, how can Bob be? */
494 destroy_service_session (s);
498 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
499 "Received %u crypto values from Bob\n",
500 (unsigned int) contained);
501 GNUNET_CADET_receive_done (s->channel);
502 prod_g_i_b_i = GNUNET_CRYPTO_ecc_bin_to_point (edc, &msg->prod_g_i_b_i);
503 prod_h_i_b_i = GNUNET_CRYPTO_ecc_bin_to_point (edc, &msg->prod_h_i_b_i);
504 s->product = compute_scalar_product (s, prod_g_i_b_i, prod_h_i_b_i);
505 gcry_mpi_point_release (prod_g_i_b_i);
506 gcry_mpi_point_release (prod_h_i_b_i);
507 transmit_client_response (s);
512 * Iterator to copy over messages from the hash map
513 * into an array for sorting.
515 * @param cls the `struct AliceServiceSession *`
516 * @param key the key (unused)
517 * @param value the `struct GNUNET_SCALARPRODUCT_Element *`
520 copy_element_cb (void *cls, const struct GNUNET_HashCode *key, void *value)
522 struct AliceServiceSession *s = cls;
523 struct GNUNET_SCALARPRODUCT_Element *e = value;
527 mval = gcry_mpi_new (0);
528 val = (int64_t) GNUNET_ntohll (e->value);
530 gcry_mpi_sub_ui (mval, mval, -val);
532 gcry_mpi_add_ui (mval, mval, val);
533 s->sorted_elements[s->used_element_count].value = mval;
534 s->sorted_elements[s->used_element_count].key = &e->key;
535 s->used_element_count++;
541 * Compare two `struct MpiValue`s by key for sorting.
543 * @param a pointer to first `struct MpiValue *`
544 * @param b pointer to first `struct MpiValue *`
545 * @return -1 for a < b, 0 for a=b, 1 for a > b.
548 element_cmp (const void *a, const void *b)
550 const struct MpiElement *ma = a;
551 const struct MpiElement *mb = b;
553 return GNUNET_CRYPTO_hash_cmp (ma->key, mb->key);
558 * Maximum number of elements we can put into a single cryptodata
561 #define ELEMENT_CAPACITY \
562 ((GNUNET_CONSTANTS_MAX_CADET_MESSAGE_SIZE - 1 \
563 - sizeof(struct EccAliceCryptodataMessage)) \
564 / sizeof(struct GNUNET_CRYPTO_EccPoint))
568 * Send the cryptographic data from Alice to Bob.
569 * Does nothing if we already transferred all elements.
571 * @param s the associated service session
574 send_alices_cryptodata_message (struct AliceServiceSession *s)
576 struct EccAliceCryptodataMessage *msg;
577 struct GNUNET_MQ_Envelope *e;
578 struct GNUNET_CRYPTO_EccPoint *payload;
583 unsigned int todo_count;
585 s->sorted_elements = GNUNET_new_array (GNUNET_CONTAINER_multihashmap_size (
586 s->intersected_elements),
588 s->used_element_count = 0;
589 GNUNET_CONTAINER_multihashmap_iterate (s->intersected_elements,
592 LOG (GNUNET_ERROR_TYPE_DEBUG,
593 "Finished intersection, %d items remain\n",
594 s->used_element_count);
595 qsort (s->sorted_elements,
596 s->used_element_count,
597 sizeof(struct MpiElement),
600 while (off < s->used_element_count)
602 todo_count = s->used_element_count - off;
603 if (todo_count > ELEMENT_CAPACITY)
604 todo_count = ELEMENT_CAPACITY;
605 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
606 "Sending %u/%u crypto values to Bob\n",
607 (unsigned int) todo_count,
608 (unsigned int) s->used_element_count);
611 GNUNET_MQ_msg_extra (msg,
613 * sizeof(struct GNUNET_CRYPTO_EccPoint),
614 GNUNET_MESSAGE_TYPE_SCALARPRODUCT_ECC_ALICE_CRYPTODATA);
615 msg->contained_element_count = htonl (todo_count);
616 payload = (struct GNUNET_CRYPTO_EccPoint *) &msg[1];
617 r_ia = gcry_mpi_new (0);
618 r_ia_ai = gcry_mpi_new (0);
619 for (i = off; i < off + todo_count; i++)
622 gcry_mpi_point_t g_i;
623 gcry_mpi_point_t h_i;
625 r_i = GNUNET_CRYPTO_ecc_random_mod_n (edc);
626 g_i = GNUNET_CRYPTO_ecc_dexp_mpi (edc, r_i);
628 gcry_mpi_mul (r_ia, r_i, my_privkey);
629 gcry_mpi_release (r_i);
630 /* r_ia_ai = r_ia + a_i */
631 gcry_mpi_add (r_ia_ai, r_ia, s->sorted_elements[i].value);
632 h_i = GNUNET_CRYPTO_ecc_dexp_mpi (edc, r_ia_ai);
633 GNUNET_CRYPTO_ecc_point_to_bin (edc, g_i, &payload[(i - off) * 2]);
634 GNUNET_CRYPTO_ecc_point_to_bin (edc, h_i, &payload[(i - off) * 2 + 1]);
635 gcry_mpi_point_release (g_i);
636 gcry_mpi_point_release (h_i);
638 gcry_mpi_release (r_ia);
639 gcry_mpi_release (r_ia_ai);
641 GNUNET_MQ_send (s->cadet_mq, e);
647 * Callback for set operation results. Called for each element
648 * that should be removed from the result set, and then once
649 * to indicate that the set intersection operation is done.
651 * @param cls closure with the `struct AliceServiceSession`
652 * @param element a result element, only valid if status is #GNUNET_SET_STATUS_OK
653 * @param current_size current set size
654 * @param status what has happened with the set intersection?
657 cb_intersection_element_removed (void *cls,
658 const struct GNUNET_SET_Element *element,
659 uint64_t current_size,
660 enum GNUNET_SET_Status status)
662 struct AliceServiceSession *s = cls;
663 struct GNUNET_SCALARPRODUCT_Element *se;
667 case GNUNET_SET_STATUS_OK:
668 /* this element has been removed from the set */
669 se = GNUNET_CONTAINER_multihashmap_get (s->intersected_elements,
671 GNUNET_assert (NULL != se);
672 LOG (GNUNET_ERROR_TYPE_DEBUG,
673 "Intersection removed element with key %s and value %lld\n",
674 GNUNET_h2s (&se->key),
675 (long long) GNUNET_ntohll (se->value));
678 GNUNET_CONTAINER_multihashmap_remove (s->intersected_elements,
684 case GNUNET_SET_STATUS_DONE:
685 s->intersection_op = NULL;
686 if (NULL != s->intersection_set)
688 GNUNET_SET_destroy (s->intersection_set);
689 s->intersection_set = NULL;
691 send_alices_cryptodata_message (s);
694 case GNUNET_SET_STATUS_HALF_DONE:
695 /* unexpected for intersection */
699 case GNUNET_SET_STATUS_FAILURE:
700 /* unhandled status code */
701 LOG (GNUNET_ERROR_TYPE_DEBUG, "Set intersection failed!\n");
702 if (NULL != s->intersection_listen)
704 GNUNET_SET_listen_cancel (s->intersection_listen);
705 s->intersection_listen = NULL;
707 s->intersection_op = NULL;
708 if (NULL != s->intersection_set)
710 GNUNET_SET_destroy (s->intersection_set);
711 s->intersection_set = NULL;
713 s->status = GNUNET_SCALARPRODUCT_STATUS_FAILURE;
714 prepare_client_end_notification (s);
725 * Called when another peer wants to do a set operation with the
726 * local peer. If a listen error occurs, the @a request is NULL.
728 * @param cls closure with the `struct AliceServiceSession *`
729 * @param other_peer the other peer
730 * @param context_msg message with application specific information from
732 * @param request request from the other peer (never NULL), use GNUNET_SET_accept()
733 * to accept it, otherwise the request will be refused
734 * Note that we can't just return value from the listen callback,
735 * as it is also necessary to specify the set we want to do the
736 * operation with, whith sometimes can be derived from the context
737 * message. It's necessary to specify the timeout.
740 cb_intersection_request_alice (void *cls,
741 const struct GNUNET_PeerIdentity *other_peer,
742 const struct GNUNET_MessageHeader *context_msg,
743 struct GNUNET_SET_Request *request)
745 struct AliceServiceSession *s = cls;
747 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
748 "Received intersection request from %s!\n",
749 GNUNET_i2s (other_peer));
750 if (0 != GNUNET_memcmp (other_peer, &s->peer))
755 s->intersection_op = GNUNET_SET_accept (request,
756 GNUNET_SET_RESULT_REMOVED,
757 (struct GNUNET_SET_Option[]){ { 0 } },
758 &cb_intersection_element_removed,
760 if (NULL == s->intersection_op)
763 s->status = GNUNET_SCALARPRODUCT_STATUS_FAILURE;
764 prepare_client_end_notification (s);
767 if (GNUNET_OK != GNUNET_SET_commit (s->intersection_op, s->intersection_set))
770 s->status = GNUNET_SCALARPRODUCT_STATUS_FAILURE;
771 prepare_client_end_notification (s);
778 * Our client has finished sending us its multipart message.
780 * @param session the service session context
783 client_request_complete_alice (struct AliceServiceSession *s)
785 struct GNUNET_MQ_MessageHandler cadet_handlers[] =
786 { GNUNET_MQ_hd_fixed_size (bobs_cryptodata_message,
787 GNUNET_MESSAGE_TYPE_SCALARPRODUCT_ECC_BOB_CRYPTODATA,
788 struct EccBobCryptodataMessage,
790 GNUNET_MQ_handler_end () };
791 struct EccServiceRequestMessage *msg;
792 struct GNUNET_MQ_Envelope *e;
793 struct GNUNET_HashCode set_sid;
795 GNUNET_CRYPTO_hash (&s->session_id,
796 sizeof(struct GNUNET_HashCode),
798 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
799 "Creating new channel for session with key %s.\n",
800 GNUNET_h2s (&s->session_id));
801 s->channel = GNUNET_CADET_channel_create (my_cadet,
806 &cb_channel_destruction,
808 if (NULL == s->channel)
810 s->status = GNUNET_SCALARPRODUCT_STATUS_FAILURE;
811 prepare_client_end_notification (s);
814 s->cadet_mq = GNUNET_CADET_get_mq (s->channel);
815 s->intersection_listen = GNUNET_SET_listen (cfg,
816 GNUNET_SET_OPERATION_INTERSECTION,
818 &cb_intersection_request_alice,
820 if (NULL == s->intersection_listen)
822 s->status = GNUNET_SCALARPRODUCT_STATUS_FAILURE;
823 GNUNET_CADET_channel_destroy (s->channel);
825 prepare_client_end_notification (s);
831 GNUNET_MESSAGE_TYPE_SCALARPRODUCT_ECC_SESSION_INITIALIZATION);
832 GNUNET_MQ_env_set_options (e, GNUNET_MQ_PRIO_CRITICAL_CONTROL);
833 msg->session_id = s->session_id;
834 GNUNET_MQ_send (s->cadet_mq, e);
839 * We're receiving additional set data. Check if
840 * @a msg is well-formed.
842 * @param cls client identification of the client
843 * @param msg the actual message
844 * @return #GNUNET_OK if @a msg is well-formed
847 check_alice_client_message_multipart (
849 const struct ComputationBobCryptodataMultipartMessage *msg)
851 struct AliceServiceSession *s = cls;
852 uint32_t contained_count;
855 msize = ntohs (msg->header.size);
856 contained_count = ntohl (msg->element_count_contained);
858 (sizeof(struct ComputationBobCryptodataMultipartMessage)
859 + contained_count * sizeof(struct GNUNET_SCALARPRODUCT_Element))) ||
860 (0 == contained_count) ||
861 (s->total == s->client_received_element_count) ||
862 (s->total < s->client_received_element_count + contained_count))
865 return GNUNET_SYSERR;
872 * We're receiving additional set data. Add it to our
873 * set and if we are done, initiate the transaction.
875 * @param cls client identification of the client
876 * @param msg the actual message
879 handle_alice_client_message_multipart (
881 const struct ComputationBobCryptodataMultipartMessage *msg)
883 struct AliceServiceSession *s = cls;
884 uint32_t contained_count;
885 const struct GNUNET_SCALARPRODUCT_Element *elements;
886 struct GNUNET_SET_Element set_elem;
887 struct GNUNET_SCALARPRODUCT_Element *elem;
889 contained_count = ntohl (msg->element_count_contained);
890 s->client_received_element_count += contained_count;
891 elements = (const struct GNUNET_SCALARPRODUCT_Element *) &msg[1];
892 for (uint32_t i = 0; i < contained_count; i++)
894 elem = GNUNET_new (struct GNUNET_SCALARPRODUCT_Element);
897 sizeof(struct GNUNET_SCALARPRODUCT_Element));
898 if (GNUNET_SYSERR == GNUNET_CONTAINER_multihashmap_put (
899 s->intersected_elements,
902 GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY))
908 set_elem.data = &elem->key;
909 set_elem.size = sizeof(elem->key);
910 set_elem.element_type = 0;
911 GNUNET_SET_add_element (s->intersection_set, &set_elem, NULL, NULL);
912 s->used_element_count++;
914 GNUNET_SERVICE_client_continue (s->client);
915 if (s->total != s->client_received_element_count)
918 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
919 "Received client multipart data, waiting for more!\n");
922 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Launching computation\n");
923 client_request_complete_alice (s);
928 * Handler for Alice's client request message.
929 * Check that @a msg is well-formed.
931 * @param cls identification of the client
932 * @param msg the actual message
933 * @return #GNUNET_OK if @a msg is well-formed
936 check_alice_client_message (void *cls,
937 const struct AliceComputationMessage *msg)
939 struct AliceServiceSession *s = cls;
941 uint32_t total_count;
942 uint32_t contained_count;
944 if (NULL != s->intersected_elements)
946 /* only one concurrent session per client connection allowed,
947 simplifies logic a lot... */
949 return GNUNET_SYSERR;
951 msize = ntohs (msg->header.size);
952 total_count = ntohl (msg->element_count_total);
953 contained_count = ntohl (msg->element_count_contained);
954 if ((0 == total_count) || (0 == contained_count) ||
956 (sizeof(struct AliceComputationMessage)
957 + contained_count * sizeof(struct GNUNET_SCALARPRODUCT_Element))))
960 return GNUNET_SYSERR;
967 * Handler for Alice's client request message.
968 * We are doing request-initiation to compute a scalar product with a peer.
970 * @param cls identification of the client
971 * @param msg the actual message
974 handle_alice_client_message (void *cls,
975 const struct AliceComputationMessage *msg)
977 struct AliceServiceSession *s = cls;
978 uint32_t contained_count;
979 uint32_t total_count;
980 const struct GNUNET_SCALARPRODUCT_Element *elements;
981 struct GNUNET_SET_Element set_elem;
982 struct GNUNET_SCALARPRODUCT_Element *elem;
984 total_count = ntohl (msg->element_count_total);
985 contained_count = ntohl (msg->element_count_contained);
987 s->status = GNUNET_SCALARPRODUCT_STATUS_ACTIVE;
988 s->total = total_count;
989 s->client_received_element_count = contained_count;
990 s->session_id = msg->session_key;
991 elements = (const struct GNUNET_SCALARPRODUCT_Element *) &msg[1];
992 s->intersected_elements =
993 GNUNET_CONTAINER_multihashmap_create (s->total, GNUNET_YES);
994 s->intersection_set =
995 GNUNET_SET_create (cfg, GNUNET_SET_OPERATION_INTERSECTION);
996 for (uint32_t i = 0; i < contained_count; i++)
998 if (0 == GNUNET_ntohll (elements[i].value))
1000 elem = GNUNET_new (struct GNUNET_SCALARPRODUCT_Element);
1001 GNUNET_memcpy (elem,
1003 sizeof(struct GNUNET_SCALARPRODUCT_Element));
1004 if (GNUNET_SYSERR == GNUNET_CONTAINER_multihashmap_put (
1005 s->intersected_elements,
1008 GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY))
1010 /* element with same key encountered twice! */
1015 set_elem.data = &elem->key;
1016 set_elem.size = sizeof(elem->key);
1017 set_elem.element_type = 0;
1018 GNUNET_SET_add_element (s->intersection_set, &set_elem, NULL, NULL);
1019 s->used_element_count++;
1021 GNUNET_SERVICE_client_continue (s->client);
1022 if (s->total != s->client_received_element_count)
1024 /* wait for multipart msg */
1025 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1026 "Received partial client request, waiting for more!\n");
1029 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Launching computation\n");
1030 client_request_complete_alice (s);
1035 * Task run during shutdown.
1041 shutdown_task (void *cls)
1043 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Shutting down, initiating cleanup.\n");
1044 // FIXME: we have to cut our connections to CADET first!
1045 if (NULL != my_cadet)
1047 GNUNET_CADET_disconnect (my_cadet);
1052 GNUNET_CRYPTO_ecc_dlog_release (edc);
1059 * A client connected.
1061 * Setup the associated data structure.
1063 * @param cls closure, NULL
1064 * @param client identification of the client
1065 * @param mq message queue to communicate with @a client
1066 * @return our `struct AliceServiceSession`
1069 client_connect_cb (void *cls,
1070 struct GNUNET_SERVICE_Client *client,
1071 struct GNUNET_MQ_Handle *mq)
1073 struct AliceServiceSession *s;
1075 s = GNUNET_new (struct AliceServiceSession);
1083 * A client disconnected.
1085 * Remove the associated session(s), release data structures
1086 * and cancel pending outgoing transmissions to the client.
1088 * @param cls closure, NULL
1089 * @param client identification of the client
1090 * @param app_cls our `struct AliceServiceSession`
1093 client_disconnect_cb (void *cls,
1094 struct GNUNET_SERVICE_Client *client,
1097 struct AliceServiceSession *s = app_cls;
1099 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1100 "Client %p disconnected from us.\n",
1103 s->client_mq = NULL;
1104 destroy_service_session (s);
1109 * Initialization of the program and message handlers
1111 * @param cls closure
1112 * @param c configuration to use
1113 * @param service the initialized service
1117 const struct GNUNET_CONFIGURATION_Handle *c,
1118 struct GNUNET_SERVICE_Handle *service)
1121 edc = GNUNET_CRYPTO_ecc_dlog_prepare (MAX_RESULT, MAX_RAM);
1122 /* Select a random 'a' value for Alice */
1123 GNUNET_CRYPTO_ecc_rnd_mpi (edc, &my_privkey, &my_privkey_inv);
1124 my_cadet = GNUNET_CADET_connect (cfg);
1125 if (NULL == my_cadet)
1127 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, _ ("Connect to CADET failed\n"));
1128 GNUNET_SCHEDULER_shutdown ();
1131 GNUNET_SCHEDULER_add_shutdown (&shutdown_task, NULL);
1136 * Define "main" method using service macro.
1138 GNUNET_SERVICE_MAIN (
1139 "scalarproduct-alice",
1140 GNUNET_SERVICE_OPTION_NONE,
1143 &client_disconnect_cb,
1145 GNUNET_MQ_hd_var_size (alice_client_message,
1146 GNUNET_MESSAGE_TYPE_SCALARPRODUCT_CLIENT_TO_ALICE,
1147 struct AliceComputationMessage,
1149 GNUNET_MQ_hd_var_size (
1150 alice_client_message_multipart,
1151 GNUNET_MESSAGE_TYPE_SCALARPRODUCT_CLIENT_MULTIPART_ALICE,
1152 struct ComputationBobCryptodataMultipartMessage,
1154 GNUNET_MQ_handler_end ());
1157 /* end of gnunet-service-scalarproduct-ecc_alice.c */