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.
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.
76 * A scalarproduct session which tracks
77 * a request form the client to our final response.
79 struct AliceServiceSession {
81 * (hopefully) unique transaction ID
83 struct GNUNET_HashCode session_id;
86 * Alice or Bob's peerID
88 struct GNUNET_PeerIdentity peer;
91 * The client this request is related to.
93 struct GNUNET_SERVICE_Client *client;
96 * The message queue for the client.
98 struct GNUNET_MQ_Handle *client_mq;
101 * The message queue for CADET.
103 struct GNUNET_MQ_Handle *cadet_mq;
106 * all non-0-value'd elements transmitted to us.
107 * Values are of type `struct GNUNET_SCALARPRODUCT_Element *`
109 struct GNUNET_CONTAINER_MultiHashMap *intersected_elements;
112 * Set of elements for which will conduction an intersection.
113 * the resulting elements are then used for computing the scalar product.
115 struct GNUNET_SET_Handle *intersection_set;
118 * Set of elements for which will conduction an intersection.
119 * the resulting elements are then used for computing the scalar product.
121 struct GNUNET_SET_OperationHandle *intersection_op;
124 * Handle to Alice's Intersection operation listening for Bob
126 struct GNUNET_SET_ListenHandle *intersection_listen;
129 * channel-handle associated with our cadet handle
131 struct GNUNET_CADET_Channel *channel;
134 * a(Alice), sorted array by key of length @e used_element_count.
136 struct MpiElement *sorted_elements;
139 * The computed scalar
144 * How many elements we were supplied with from the client (total
145 * count before intersection).
150 * How many elements actually are used for the scalar product.
151 * Size of the arrays in @e r and @e r_prime. Sometimes also
152 * reset to 0 and used as a counter!
154 uint32_t used_element_count;
157 * Already transferred elements from client to us.
158 * Less or equal than @e total.
160 uint32_t client_received_element_count;
163 * State of this session. In
164 * #GNUNET_SCALARPRODUCT_STATUS_ACTIVE while operation is
165 * ongoing, afterwards in #GNUNET_SCALARPRODUCT_STATUS_SUCCESS or
166 * #GNUNET_SCALARPRODUCT_STATUS_FAILURE.
168 enum GNUNET_SCALARPRODUCT_ResponseStatus status;
171 * Flag to prevent recursive calls to #destroy_service_session() from
179 * GNUnet configuration handle
181 static const struct GNUNET_CONFIGURATION_Handle *cfg;
184 * Context for DLOG operations on a curve.
186 static struct GNUNET_CRYPTO_EccDlogContext *edc;
189 * Alice's private key ('a').
191 static gcry_mpi_t my_privkey;
194 * Inverse of Alice's private key ('a_inv').
196 static gcry_mpi_t my_privkey_inv;
199 * Handle to the CADET service.
201 static struct GNUNET_CADET_Handle *my_cadet;
205 * Iterator called to free elements.
207 * @param cls the `struct AliceServiceSession *` (unused)
208 * @param key the key (unused)
209 * @param value value to free
210 * @return #GNUNET_OK (continue to iterate)
213 free_element_cb(void *cls, const struct GNUNET_HashCode *key, void *value)
215 struct GNUNET_SCALARPRODUCT_Element *e = value;
223 * Destroy session state, we are done with it.
225 * @param s the session to free elements from
228 destroy_service_session(struct AliceServiceSession *s)
232 if (GNUNET_YES == s->in_destroy)
234 s->in_destroy = GNUNET_YES;
235 if (NULL != s->client)
237 struct GNUNET_SERVICE_Client *c = s->client;
240 GNUNET_SERVICE_client_drop(c);
242 if (NULL != s->channel)
244 GNUNET_CADET_channel_destroy(s->channel);
247 if (NULL != s->intersected_elements)
249 GNUNET_CONTAINER_multihashmap_iterate(s->intersected_elements,
252 GNUNET_CONTAINER_multihashmap_destroy(s->intersected_elements);
253 s->intersected_elements = NULL;
255 if (NULL != s->intersection_listen)
257 GNUNET_SET_listen_cancel(s->intersection_listen);
258 s->intersection_listen = NULL;
260 if (NULL != s->intersection_op)
262 LOG(GNUNET_ERROR_TYPE_DEBUG, "Set intersection, op still ongoing!\n");
263 GNUNET_SET_operation_cancel(s->intersection_op);
264 s->intersection_op = NULL;
266 if (NULL != s->intersection_set)
268 GNUNET_SET_destroy(s->intersection_set);
269 s->intersection_set = NULL;
271 if (NULL != s->sorted_elements)
273 for (i = 0; i < s->used_element_count; i++)
274 gcry_mpi_release(s->sorted_elements[i].value);
275 GNUNET_free(s->sorted_elements);
276 s->sorted_elements = NULL;
278 if (NULL != s->product)
280 gcry_mpi_release(s->product);
288 * Notify the client that the session has failed. A message gets sent
289 * to Alice's client if we encountered any error.
291 * @param session the associated client session to fail or succeed
294 prepare_client_end_notification(struct AliceServiceSession *session)
296 struct ClientResponseMessage *msg;
297 struct GNUNET_MQ_Envelope *e;
299 if (NULL == session->client_mq)
300 return; /* no client left to be notified */
302 GNUNET_ERROR_TYPE_DEBUG,
303 "Sending session-end notification with status %d to client for session %s\n",
305 GNUNET_h2s(&session->session_id));
306 e = GNUNET_MQ_msg(msg, GNUNET_MESSAGE_TYPE_SCALARPRODUCT_RESULT);
307 msg->product_length = htonl(0);
308 msg->status = htonl(session->status);
309 GNUNET_MQ_send(session->client_mq, e);
314 * Prepare the final (positive) response we will send to Alice's
317 * @param s the session associated with our client.
320 transmit_client_response(struct AliceServiceSession *s)
322 struct ClientResponseMessage *msg;
323 struct GNUNET_MQ_Envelope *e;
324 unsigned char *product_exported = NULL;
325 size_t product_length = 0;
331 if (NULL == s->product)
334 prepare_client_end_notification(s);
337 value = gcry_mpi_new(0);
338 sign = gcry_mpi_cmp_ui(s->product, 0);
342 gcry_mpi_sub(value, value, s->product);
347 gcry_mpi_add(value, value, s->product);
351 /* result is exactly zero */
354 gcry_mpi_release(s->product);
357 if ((0 != range) && (0 != (rc = gcry_mpi_aprint(GCRYMPI_FMT_STD,
362 LOG_GCRY(GNUNET_ERROR_TYPE_ERROR, "gcry_mpi_scan", rc);
363 prepare_client_end_notification(s);
366 gcry_mpi_release(value);
367 e = GNUNET_MQ_msg_extra(msg,
369 GNUNET_MESSAGE_TYPE_SCALARPRODUCT_RESULT);
370 msg->status = htonl(GNUNET_SCALARPRODUCT_STATUS_SUCCESS);
371 msg->range = htonl(range);
372 msg->product_length = htonl(product_length);
373 if (NULL != product_exported)
375 GNUNET_memcpy(&msg[1], product_exported, product_length);
376 GNUNET_free(product_exported);
378 GNUNET_MQ_send(s->client_mq, e);
379 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
380 "Sent result to client, session %s has ended!\n",
381 GNUNET_h2s(&s->session_id));
386 * Function called whenever a channel is destroyed. Should clean up
387 * any associated state.
389 * It must NOT call #GNUNET_CADET_channel_destroy() on the channel.
391 * @param cls the `struct AliceServiceSession`
392 * @param channel connection to the other end (henceforth invalid)
395 cb_channel_destruction(void *cls, const struct GNUNET_CADET_Channel *channel)
397 struct AliceServiceSession *s = cls;
399 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
400 "Peer disconnected, terminating session %s with peer %s\n",
401 GNUNET_h2s(&s->session_id),
402 GNUNET_i2s(&s->peer));
404 if (GNUNET_SCALARPRODUCT_STATUS_ACTIVE == s->status)
406 /* We didn't get an answer yet, fail with error */
407 s->status = GNUNET_SCALARPRODUCT_STATUS_FAILURE;
408 prepare_client_end_notification(s);
414 * Compute our scalar product, done by Alice
416 * @param session the session associated with this computation
417 * @param prod_g_i_b_i value from Bob
418 * @param prod_h_i_b_i value from Bob
419 * @return product as MPI, never NULL
422 compute_scalar_product(struct AliceServiceSession *session,
423 gcry_mpi_point_t prod_g_i_b_i,
424 gcry_mpi_point_t prod_h_i_b_i)
426 gcry_mpi_point_t g_i_b_i_a_inv;
427 gcry_mpi_point_t g_ai_bi;
432 GNUNET_CRYPTO_ecc_pmul_mpi(edc, prod_g_i_b_i, my_privkey_inv);
433 g_ai_bi = GNUNET_CRYPTO_ecc_add(edc, g_i_b_i_a_inv, prod_h_i_b_i);
434 gcry_mpi_point_release(g_i_b_i_a_inv);
435 ai_bi = GNUNET_CRYPTO_ecc_dlog(edc, g_ai_bi);
436 gcry_mpi_point_release(g_ai_bi);
437 if (INT_MAX == ai_bi)
440 GNUNET_log(GNUNET_ERROR_TYPE_ERROR,
441 "Scalar product result out of range\n");
444 ret = gcry_mpi_new(0);
447 gcry_mpi_set_ui(ret, ai_bi);
451 gcry_mpi_set_ui(ret, -ai_bi);
452 gcry_mpi_neg(ret, ret);
459 * Handle a response we got from another service we wanted to
460 * calculate a scalarproduct with.
462 * @param cls the `struct AliceServiceSession *`
463 * @param msg the actual message
466 handle_bobs_cryptodata_message(void *cls,
467 const struct EccBobCryptodataMessage *msg)
469 struct AliceServiceSession *s = cls;
470 gcry_mpi_point_t prod_g_i_b_i;
471 gcry_mpi_point_t prod_h_i_b_i;
474 contained = ntohl(msg->contained_element_count);
478 destroy_service_session(s);
481 if (NULL == s->sorted_elements)
483 /* we're not ready yet, how can Bob be? */
485 destroy_service_session(s);
488 if (s->total != s->client_received_element_count)
490 /* we're not ready yet, how can Bob be? */
492 destroy_service_session(s);
496 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
497 "Received %u crypto values from Bob\n",
498 (unsigned int)contained);
499 GNUNET_CADET_receive_done(s->channel);
500 prod_g_i_b_i = GNUNET_CRYPTO_ecc_bin_to_point(edc, &msg->prod_g_i_b_i);
501 prod_h_i_b_i = GNUNET_CRYPTO_ecc_bin_to_point(edc, &msg->prod_h_i_b_i);
502 s->product = compute_scalar_product(s, prod_g_i_b_i, prod_h_i_b_i);
503 gcry_mpi_point_release(prod_g_i_b_i);
504 gcry_mpi_point_release(prod_h_i_b_i);
505 transmit_client_response(s);
510 * Iterator to copy over messages from the hash map
511 * into an array for sorting.
513 * @param cls the `struct AliceServiceSession *`
514 * @param key the key (unused)
515 * @param value the `struct GNUNET_SCALARPRODUCT_Element *`
518 copy_element_cb(void *cls, const struct GNUNET_HashCode *key, void *value)
520 struct AliceServiceSession *s = cls;
521 struct GNUNET_SCALARPRODUCT_Element *e = value;
525 mval = gcry_mpi_new(0);
526 val = (int64_t)GNUNET_ntohll(e->value);
528 gcry_mpi_sub_ui(mval, mval, -val);
530 gcry_mpi_add_ui(mval, mval, val);
531 s->sorted_elements[s->used_element_count].value = mval;
532 s->sorted_elements[s->used_element_count].key = &e->key;
533 s->used_element_count++;
539 * Compare two `struct MpiValue`s by key for sorting.
541 * @param a pointer to first `struct MpiValue *`
542 * @param b pointer to first `struct MpiValue *`
543 * @return -1 for a < b, 0 for a=b, 1 for a > b.
546 element_cmp(const void *a, const void *b)
548 const struct MpiElement *ma = a;
549 const struct MpiElement *mb = b;
551 return GNUNET_CRYPTO_hash_cmp(ma->key, mb->key);
556 * Maximum number of elements we can put into a single cryptodata
559 #define ELEMENT_CAPACITY \
560 ((GNUNET_CONSTANTS_MAX_CADET_MESSAGE_SIZE - 1 - \
561 sizeof(struct EccAliceCryptodataMessage)) / \
562 sizeof(struct GNUNET_CRYPTO_EccPoint))
566 * Send the cryptographic data from Alice to Bob.
567 * Does nothing if we already transferred all elements.
569 * @param s the associated service session
572 send_alices_cryptodata_message(struct AliceServiceSession *s)
574 struct EccAliceCryptodataMessage *msg;
575 struct GNUNET_MQ_Envelope *e;
576 struct GNUNET_CRYPTO_EccPoint *payload;
581 unsigned int todo_count;
583 s->sorted_elements = GNUNET_new_array(GNUNET_CONTAINER_multihashmap_size(
584 s->intersected_elements),
586 s->used_element_count = 0;
587 GNUNET_CONTAINER_multihashmap_iterate(s->intersected_elements,
590 LOG(GNUNET_ERROR_TYPE_DEBUG,
591 "Finished intersection, %d items remain\n",
592 s->used_element_count);
593 qsort(s->sorted_elements,
594 s->used_element_count,
595 sizeof(struct MpiElement),
598 while (off < s->used_element_count)
600 todo_count = s->used_element_count - off;
601 if (todo_count > ELEMENT_CAPACITY)
602 todo_count = ELEMENT_CAPACITY;
603 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
604 "Sending %u/%u crypto values to Bob\n",
605 (unsigned int)todo_count,
606 (unsigned int)s->used_element_count);
609 GNUNET_MQ_msg_extra(msg,
611 sizeof(struct GNUNET_CRYPTO_EccPoint),
612 GNUNET_MESSAGE_TYPE_SCALARPRODUCT_ECC_ALICE_CRYPTODATA);
613 msg->contained_element_count = htonl(todo_count);
614 payload = (struct GNUNET_CRYPTO_EccPoint *)&msg[1];
615 r_ia = gcry_mpi_new(0);
616 r_ia_ai = gcry_mpi_new(0);
617 for (i = off; i < off + todo_count; i++)
620 gcry_mpi_point_t g_i;
621 gcry_mpi_point_t h_i;
623 r_i = GNUNET_CRYPTO_ecc_random_mod_n(edc);
624 g_i = GNUNET_CRYPTO_ecc_dexp_mpi(edc, r_i);
626 gcry_mpi_mul(r_ia, r_i, my_privkey);
627 gcry_mpi_release(r_i);
628 /* r_ia_ai = r_ia + a_i */
629 gcry_mpi_add(r_ia_ai, r_ia, s->sorted_elements[i].value);
630 h_i = GNUNET_CRYPTO_ecc_dexp_mpi(edc, r_ia_ai);
631 GNUNET_CRYPTO_ecc_point_to_bin(edc, g_i, &payload[(i - off) * 2]);
632 GNUNET_CRYPTO_ecc_point_to_bin(edc, h_i, &payload[(i - off) * 2 + 1]);
633 gcry_mpi_point_release(g_i);
634 gcry_mpi_point_release(h_i);
636 gcry_mpi_release(r_ia);
637 gcry_mpi_release(r_ia_ai);
639 GNUNET_MQ_send(s->cadet_mq, e);
645 * Callback for set operation results. Called for each element
646 * that should be removed from the result set, and then once
647 * to indicate that the set intersection operation is done.
649 * @param cls closure with the `struct AliceServiceSession`
650 * @param element a result element, only valid if status is #GNUNET_SET_STATUS_OK
651 * @param current_size current set size
652 * @param status what has happened with the set intersection?
655 cb_intersection_element_removed(void *cls,
656 const struct GNUNET_SET_Element *element,
657 uint64_t current_size,
658 enum GNUNET_SET_Status status)
660 struct AliceServiceSession *s = cls;
661 struct GNUNET_SCALARPRODUCT_Element *se;
665 case GNUNET_SET_STATUS_OK:
666 /* this element has been removed from the set */
667 se = GNUNET_CONTAINER_multihashmap_get(s->intersected_elements,
669 GNUNET_assert(NULL != se);
670 LOG(GNUNET_ERROR_TYPE_DEBUG,
671 "Intersection removed element with key %s and value %lld\n",
672 GNUNET_h2s(&se->key),
673 (long long)GNUNET_ntohll(se->value));
676 GNUNET_CONTAINER_multihashmap_remove(s->intersected_elements,
682 case GNUNET_SET_STATUS_DONE:
683 s->intersection_op = NULL;
684 if (NULL != s->intersection_set)
686 GNUNET_SET_destroy(s->intersection_set);
687 s->intersection_set = NULL;
689 send_alices_cryptodata_message(s);
692 case GNUNET_SET_STATUS_HALF_DONE:
693 /* unexpected for intersection */
697 case GNUNET_SET_STATUS_FAILURE:
698 /* unhandled status code */
699 LOG(GNUNET_ERROR_TYPE_DEBUG, "Set intersection failed!\n");
700 if (NULL != s->intersection_listen)
702 GNUNET_SET_listen_cancel(s->intersection_listen);
703 s->intersection_listen = NULL;
705 s->intersection_op = NULL;
706 if (NULL != s->intersection_set)
708 GNUNET_SET_destroy(s->intersection_set);
709 s->intersection_set = NULL;
711 s->status = GNUNET_SCALARPRODUCT_STATUS_FAILURE;
712 prepare_client_end_notification(s);
723 * Called when another peer wants to do a set operation with the
724 * local peer. If a listen error occurs, the @a request is NULL.
726 * @param cls closure with the `struct AliceServiceSession *`
727 * @param other_peer the other peer
728 * @param context_msg message with application specific information from
730 * @param request request from the other peer (never NULL), use GNUNET_SET_accept()
731 * to accept it, otherwise the request will be refused
732 * Note that we can't just return value from the listen callback,
733 * as it is also necessary to specify the set we want to do the
734 * operation with, whith sometimes can be derived from the context
735 * message. It's necessary to specify the timeout.
738 cb_intersection_request_alice(void *cls,
739 const struct GNUNET_PeerIdentity *other_peer,
740 const struct GNUNET_MessageHeader *context_msg,
741 struct GNUNET_SET_Request *request)
743 struct AliceServiceSession *s = cls;
745 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
746 "Received intersection request from %s!\n",
747 GNUNET_i2s(other_peer));
748 if (0 != GNUNET_memcmp(other_peer, &s->peer))
753 s->intersection_op = GNUNET_SET_accept(request,
754 GNUNET_SET_RESULT_REMOVED,
755 (struct GNUNET_SET_Option[]){ { 0 } },
756 &cb_intersection_element_removed,
758 if (NULL == s->intersection_op)
761 s->status = GNUNET_SCALARPRODUCT_STATUS_FAILURE;
762 prepare_client_end_notification(s);
765 if (GNUNET_OK != GNUNET_SET_commit(s->intersection_op, s->intersection_set))
768 s->status = GNUNET_SCALARPRODUCT_STATUS_FAILURE;
769 prepare_client_end_notification(s);
776 * Our client has finished sending us its multipart message.
778 * @param session the service session context
781 client_request_complete_alice(struct AliceServiceSession *s)
783 struct GNUNET_MQ_MessageHandler cadet_handlers[] =
784 { GNUNET_MQ_hd_fixed_size(bobs_cryptodata_message,
785 GNUNET_MESSAGE_TYPE_SCALARPRODUCT_ECC_BOB_CRYPTODATA,
786 struct EccBobCryptodataMessage,
788 GNUNET_MQ_handler_end() };
789 struct EccServiceRequestMessage *msg;
790 struct GNUNET_MQ_Envelope *e;
791 struct GNUNET_HashCode set_sid;
793 GNUNET_CRYPTO_hash(&s->session_id,
794 sizeof(struct GNUNET_HashCode),
796 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
797 "Creating new channel for session with key %s.\n",
798 GNUNET_h2s(&s->session_id));
799 s->channel = GNUNET_CADET_channel_create(my_cadet,
804 &cb_channel_destruction,
806 if (NULL == s->channel)
808 s->status = GNUNET_SCALARPRODUCT_STATUS_FAILURE;
809 prepare_client_end_notification(s);
812 s->cadet_mq = GNUNET_CADET_get_mq(s->channel);
813 s->intersection_listen = GNUNET_SET_listen(cfg,
814 GNUNET_SET_OPERATION_INTERSECTION,
816 &cb_intersection_request_alice,
818 if (NULL == s->intersection_listen)
820 s->status = GNUNET_SCALARPRODUCT_STATUS_FAILURE;
821 GNUNET_CADET_channel_destroy(s->channel);
823 prepare_client_end_notification(s);
829 GNUNET_MESSAGE_TYPE_SCALARPRODUCT_ECC_SESSION_INITIALIZATION);
830 GNUNET_MQ_env_set_options(e, GNUNET_MQ_PRIO_CRITICAL_CONTROL);
831 msg->session_id = s->session_id;
832 GNUNET_MQ_send(s->cadet_mq, e);
837 * We're receiving additional set data. Check if
838 * @a msg is well-formed.
840 * @param cls client identification of the client
841 * @param msg the actual message
842 * @return #GNUNET_OK if @a msg is well-formed
845 check_alice_client_message_multipart(
847 const struct ComputationBobCryptodataMultipartMessage *msg)
849 struct AliceServiceSession *s = cls;
850 uint32_t contained_count;
853 msize = ntohs(msg->header.size);
854 contained_count = ntohl(msg->element_count_contained);
856 (sizeof(struct ComputationBobCryptodataMultipartMessage) +
857 contained_count * sizeof(struct GNUNET_SCALARPRODUCT_Element))) ||
858 (0 == contained_count) ||
859 (s->total == s->client_received_element_count) ||
860 (s->total < s->client_received_element_count + contained_count))
863 return GNUNET_SYSERR;
870 * We're receiving additional set data. Add it to our
871 * set and if we are done, initiate the transaction.
873 * @param cls client identification of the client
874 * @param msg the actual message
877 handle_alice_client_message_multipart(
879 const struct ComputationBobCryptodataMultipartMessage *msg)
881 struct AliceServiceSession *s = cls;
882 uint32_t contained_count;
883 const struct GNUNET_SCALARPRODUCT_Element *elements;
884 struct GNUNET_SET_Element set_elem;
885 struct GNUNET_SCALARPRODUCT_Element *elem;
887 contained_count = ntohl(msg->element_count_contained);
888 s->client_received_element_count += contained_count;
889 elements = (const struct GNUNET_SCALARPRODUCT_Element *)&msg[1];
890 for (uint32_t i = 0; i < contained_count; i++)
892 elem = GNUNET_new(struct GNUNET_SCALARPRODUCT_Element);
895 sizeof(struct GNUNET_SCALARPRODUCT_Element));
896 if (GNUNET_SYSERR == GNUNET_CONTAINER_multihashmap_put(
897 s->intersected_elements,
900 GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY))
906 set_elem.data = &elem->key;
907 set_elem.size = sizeof(elem->key);
908 set_elem.element_type = 0;
909 GNUNET_SET_add_element(s->intersection_set, &set_elem, NULL, NULL);
910 s->used_element_count++;
912 GNUNET_SERVICE_client_continue(s->client);
913 if (s->total != s->client_received_element_count)
916 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
917 "Received client multipart data, waiting for more!\n");
920 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, "Launching computation\n");
921 client_request_complete_alice(s);
926 * Handler for Alice's client request message.
927 * Check that @a msg is well-formed.
929 * @param cls identification of the client
930 * @param msg the actual message
931 * @return #GNUNET_OK if @a msg is well-formed
934 check_alice_client_message(void *cls,
935 const struct AliceComputationMessage *msg)
937 struct AliceServiceSession *s = cls;
939 uint32_t total_count;
940 uint32_t contained_count;
942 if (NULL != s->intersected_elements)
944 /* only one concurrent session per client connection allowed,
945 simplifies logic a lot... */
947 return GNUNET_SYSERR;
949 msize = ntohs(msg->header.size);
950 total_count = ntohl(msg->element_count_total);
951 contained_count = ntohl(msg->element_count_contained);
952 if ((0 == total_count) || (0 == contained_count) ||
954 (sizeof(struct AliceComputationMessage) +
955 contained_count * sizeof(struct GNUNET_SCALARPRODUCT_Element))))
958 return GNUNET_SYSERR;
965 * Handler for Alice's client request message.
966 * We are doing request-initiation to compute a scalar product with a peer.
968 * @param cls identification of the client
969 * @param msg the actual message
972 handle_alice_client_message(void *cls,
973 const struct AliceComputationMessage *msg)
975 struct AliceServiceSession *s = cls;
976 uint32_t contained_count;
977 uint32_t total_count;
978 const struct GNUNET_SCALARPRODUCT_Element *elements;
979 struct GNUNET_SET_Element set_elem;
980 struct GNUNET_SCALARPRODUCT_Element *elem;
982 total_count = ntohl(msg->element_count_total);
983 contained_count = ntohl(msg->element_count_contained);
985 s->status = GNUNET_SCALARPRODUCT_STATUS_ACTIVE;
986 s->total = total_count;
987 s->client_received_element_count = contained_count;
988 s->session_id = msg->session_key;
989 elements = (const struct GNUNET_SCALARPRODUCT_Element *)&msg[1];
990 s->intersected_elements =
991 GNUNET_CONTAINER_multihashmap_create(s->total, GNUNET_YES);
992 s->intersection_set =
993 GNUNET_SET_create(cfg, GNUNET_SET_OPERATION_INTERSECTION);
994 for (uint32_t i = 0; i < contained_count; i++)
996 if (0 == GNUNET_ntohll(elements[i].value))
998 elem = GNUNET_new(struct GNUNET_SCALARPRODUCT_Element);
1001 sizeof(struct GNUNET_SCALARPRODUCT_Element));
1002 if (GNUNET_SYSERR == GNUNET_CONTAINER_multihashmap_put(
1003 s->intersected_elements,
1006 GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY))
1008 /* element with same key encountered twice! */
1013 set_elem.data = &elem->key;
1014 set_elem.size = sizeof(elem->key);
1015 set_elem.element_type = 0;
1016 GNUNET_SET_add_element(s->intersection_set, &set_elem, NULL, NULL);
1017 s->used_element_count++;
1019 GNUNET_SERVICE_client_continue(s->client);
1020 if (s->total != s->client_received_element_count)
1022 /* wait for multipart msg */
1023 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
1024 "Received partial client request, waiting for more!\n");
1027 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, "Launching computation\n");
1028 client_request_complete_alice(s);
1033 * Task run during shutdown.
1039 shutdown_task(void *cls)
1041 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, "Shutting down, initiating cleanup.\n");
1042 // FIXME: we have to cut our connections to CADET first!
1043 if (NULL != my_cadet)
1045 GNUNET_CADET_disconnect(my_cadet);
1050 GNUNET_CRYPTO_ecc_dlog_release(edc);
1057 * A client connected.
1059 * Setup the associated data structure.
1061 * @param cls closure, NULL
1062 * @param client identification of the client
1063 * @param mq message queue to communicate with @a client
1064 * @return our `struct AliceServiceSession`
1067 client_connect_cb(void *cls,
1068 struct GNUNET_SERVICE_Client *client,
1069 struct GNUNET_MQ_Handle *mq)
1071 struct AliceServiceSession *s;
1073 s = GNUNET_new(struct AliceServiceSession);
1081 * A client disconnected.
1083 * Remove the associated session(s), release data structures
1084 * and cancel pending outgoing transmissions to the client.
1086 * @param cls closure, NULL
1087 * @param client identification of the client
1088 * @param app_cls our `struct AliceServiceSession`
1091 client_disconnect_cb(void *cls,
1092 struct GNUNET_SERVICE_Client *client,
1095 struct AliceServiceSession *s = app_cls;
1097 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
1098 "Client %p disconnected from us.\n",
1101 s->client_mq = NULL;
1102 destroy_service_session(s);
1107 * Initialization of the program and message handlers
1109 * @param cls closure
1110 * @param c configuration to use
1111 * @param service the initialized service
1115 const struct GNUNET_CONFIGURATION_Handle *c,
1116 struct GNUNET_SERVICE_Handle *service)
1119 edc = GNUNET_CRYPTO_ecc_dlog_prepare(MAX_RESULT, MAX_RAM);
1120 /* Select a random 'a' value for Alice */
1121 GNUNET_CRYPTO_ecc_rnd_mpi(edc, &my_privkey, &my_privkey_inv);
1122 my_cadet = GNUNET_CADET_connect(cfg);
1123 if (NULL == my_cadet)
1125 GNUNET_log(GNUNET_ERROR_TYPE_ERROR, _("Connect to CADET failed\n"));
1126 GNUNET_SCHEDULER_shutdown();
1129 GNUNET_SCHEDULER_add_shutdown(&shutdown_task, NULL);
1134 * Define "main" method using service macro.
1136 GNUNET_SERVICE_MAIN(
1137 "scalarproduct-alice",
1138 GNUNET_SERVICE_OPTION_NONE,
1141 &client_disconnect_cb,
1143 GNUNET_MQ_hd_var_size(alice_client_message,
1144 GNUNET_MESSAGE_TYPE_SCALARPRODUCT_CLIENT_TO_ALICE,
1145 struct AliceComputationMessage,
1147 GNUNET_MQ_hd_var_size(
1148 alice_client_message_multipart,
1149 GNUNET_MESSAGE_TYPE_SCALARPRODUCT_CLIENT_MULTIPART_ALICE,
1150 struct ComputationBobCryptodataMultipartMessage,
1152 GNUNET_MQ_handler_end());
1155 /* end of gnunet-service-scalarproduct-ecc_alice.c */