2 This file is part of GNUnet.
3 Copyright (C) 2013, 2014, 2017 GNUnet e.V.
5 GNUnet is free software; you can redistribute it and/or modify
6 it under the terms of the GNU General Public License as published
7 by the Free Software Foundation; either version 3, or (at your
8 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 General Public License for more details.
15 You should have received a copy of the GNU General Public License
16 along with GNUnet; see the file COPYING. If not, write to the
17 Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
18 Boston, MA 02110-1301, USA.
21 * @file scalarproduct/gnunet-service-scalarproduct_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.h"
39 #define LOG(kind,...) GNUNET_log_from (kind, "scalarproduct-alice", __VA_ARGS__)
42 * An encrypted element key-value pair.
47 * Key used to identify matching pairs of values to multiply.
48 * Points into an existing data structure, to avoid copying
49 * and doubling memory use.
51 const struct GNUNET_HashCode *key;
54 * Value represented (a).
61 * A scalarproduct session which tracks
62 * a request form the client to our final response.
64 struct AliceServiceSession
68 * (hopefully) unique transaction ID
70 struct GNUNET_HashCode session_id;
73 * Alice or Bob's peerID
75 struct GNUNET_PeerIdentity peer;
78 * The client this request is related to.
80 struct GNUNET_SERVICE_Client *client;
83 * The message queue for the client.
85 struct GNUNET_MQ_Handle *client_mq;
88 * The message queue for CADET.
90 struct GNUNET_MQ_Handle *cadet_mq;
93 * all non-0-value'd elements transmitted to us.
94 * Values are of type `struct GNUNET_SCALARPRODUCT_Element *`
96 struct GNUNET_CONTAINER_MultiHashMap *intersected_elements;
99 * Set of elements for which will conduction an intersection.
100 * the resulting elements are then used for computing the scalar product.
102 struct GNUNET_SET_Handle *intersection_set;
105 * Set of elements for which will conduction an intersection.
106 * the resulting elements are then used for computing the scalar product.
108 struct GNUNET_SET_OperationHandle *intersection_op;
111 * Handle to Alice's Intersection operation listening for Bob
113 struct GNUNET_SET_ListenHandle *intersection_listen;
116 * channel-handle associated with our cadet handle
118 struct GNUNET_CADET_Channel *channel;
121 * a(Alice), sorted array by key of length @e used_element_count.
123 struct MpiElement *sorted_elements;
126 * Bob's permutation p of R
128 struct GNUNET_CRYPTO_PaillierCiphertext *r;
131 * Bob's permutation q of R
133 struct GNUNET_CRYPTO_PaillierCiphertext *r_prime;
138 struct GNUNET_CRYPTO_PaillierCiphertext s;
143 struct GNUNET_CRYPTO_PaillierCiphertext s_prime;
146 * The computed scalar
151 * How many elements we were supplied with from the client (total
152 * count before intersection).
157 * How many elements actually are used for the scalar product.
158 * Size of the arrays in @e r and @e r_prime. Sometimes also
159 * reset to 0 and used as a counter!
161 uint32_t used_element_count;
164 * Already transferred elements from client to us.
165 * Less or equal than @e total.
167 uint32_t client_received_element_count;
170 * Already transferred elements from Bob to us.
171 * Less or equal than @e total.
173 uint32_t cadet_received_element_count;
176 * State of this session. In
177 * #GNUNET_SCALARPRODUCT_STATUS_ACTIVE while operation is
178 * ongoing, afterwards in #GNUNET_SCALARPRODUCT_STATUS_SUCCESS or
179 * #GNUNET_SCALARPRODUCT_STATUS_FAILURE.
181 enum GNUNET_SCALARPRODUCT_ResponseStatus status;
184 * Flag to prevent recursive calls to #destroy_service_session() from
193 * GNUnet configuration handle
195 static const struct GNUNET_CONFIGURATION_Handle *cfg;
198 * Service's own public key
200 static struct GNUNET_CRYPTO_PaillierPublicKey my_pubkey;
203 * Service's own private key
205 static struct GNUNET_CRYPTO_PaillierPrivateKey my_privkey;
208 * Service's offset for values that could possibly be negative but are plaintext for encryption.
210 static gcry_mpi_t my_offset;
213 * Handle to the CADET service.
215 static struct GNUNET_CADET_Handle *my_cadet;
219 * Iterator called to free elements.
221 * @param cls the `struct AliceServiceSession *` (unused)
222 * @param key the key (unused)
223 * @param value value to free
224 * @return #GNUNET_OK (continue to iterate)
227 free_element_cb (void *cls,
228 const struct GNUNET_HashCode *key,
231 struct GNUNET_SCALARPRODUCT_Element *e = value;
239 * Destroy session state, we are done with it.
241 * @param s the session to free elements from
244 destroy_service_session (struct AliceServiceSession *s)
248 if (GNUNET_YES == s->in_destroy)
250 s->in_destroy = GNUNET_YES;
251 if (NULL != s->client)
253 struct GNUNET_SERVICE_Client *c = s->client;
256 GNUNET_SERVICE_client_drop (c);
258 if (NULL != s->channel)
260 GNUNET_CADET_channel_destroy (s->channel);
263 if (NULL != s->intersected_elements)
265 GNUNET_CONTAINER_multihashmap_iterate (s->intersected_elements,
268 GNUNET_CONTAINER_multihashmap_destroy (s->intersected_elements);
269 s->intersected_elements = NULL;
271 if (NULL != s->intersection_listen)
273 GNUNET_SET_listen_cancel (s->intersection_listen);
274 s->intersection_listen = NULL;
276 if (NULL != s->intersection_op)
278 GNUNET_SET_operation_cancel (s->intersection_op);
279 s->intersection_op = NULL;
281 if (NULL != s->intersection_set)
283 GNUNET_SET_destroy (s->intersection_set);
284 s->intersection_set = NULL;
286 if (NULL != s->sorted_elements)
288 for (i=0;i<s->used_element_count;i++)
289 gcry_mpi_release (s->sorted_elements[i].value);
290 GNUNET_free (s->sorted_elements);
291 s->sorted_elements = NULL;
298 if (NULL != s->r_prime)
300 GNUNET_free (s->r_prime);
303 if (NULL != s->product)
305 gcry_mpi_release (s->product);
313 * Notify the client that the session has failed. A message gets sent
314 * to Alice's client if we encountered any error.
316 * @param session the associated client session to fail or succeed
319 prepare_client_end_notification (struct AliceServiceSession *session)
321 struct ClientResponseMessage *msg;
322 struct GNUNET_MQ_Envelope *e;
324 if (NULL == session->client_mq)
325 return; /* no client left to be notified */
326 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
327 "Sending session-end notification with status %d to client for session %s\n",
329 GNUNET_h2s (&session->session_id));
330 e = GNUNET_MQ_msg (msg,
331 GNUNET_MESSAGE_TYPE_SCALARPRODUCT_RESULT);
332 msg->product_length = htonl (0);
333 msg->status = htonl (session->status);
334 GNUNET_MQ_send (session->client_mq,
340 * Prepare the final (positive) response we will send to Alice's
343 * @param s the session associated with our client.
346 transmit_client_response (struct AliceServiceSession *s)
348 struct ClientResponseMessage *msg;
349 struct GNUNET_MQ_Envelope *e;
350 unsigned char *product_exported = NULL;
351 size_t product_length = 0;
357 if (NULL == s->product)
360 prepare_client_end_notification (s);
363 value = gcry_mpi_new (0);
364 sign = gcry_mpi_cmp_ui (s->product, 0);
375 gcry_mpi_add (value, value, s->product);
379 /* result is exactly zero */
382 gcry_mpi_release (s->product);
386 (0 != (rc = gcry_mpi_aprint (GCRYMPI_FMT_STD,
391 LOG_GCRY (GNUNET_ERROR_TYPE_ERROR,
394 prepare_client_end_notification (s);
397 gcry_mpi_release (value);
398 e = GNUNET_MQ_msg_extra (msg,
400 GNUNET_MESSAGE_TYPE_SCALARPRODUCT_RESULT);
401 msg->status = htonl (GNUNET_SCALARPRODUCT_STATUS_SUCCESS);
402 msg->range = htonl (range);
403 msg->product_length = htonl (product_length);
404 if (NULL != product_exported)
406 GNUNET_memcpy (&msg[1],
409 GNUNET_free (product_exported);
411 GNUNET_MQ_send (s->client_mq,
413 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
414 "Sent result to client, session %s has ended!\n",
415 GNUNET_h2s (&s->session_id));
421 * Function called whenever a channel is destroyed. Should clean up
422 * any associated state.
424 * It must NOT call #GNUNET_CADET_channel_destroy() on the channel.
426 * @param cls our `struct AliceServiceSession`
427 * @param channel connection to the other end (henceforth invalid)
430 cb_channel_destruction (void *cls,
431 const struct GNUNET_CADET_Channel *channel)
433 struct AliceServiceSession *s = cls;
435 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
436 "Peer disconnected, terminating session %s with peer %s\n",
437 GNUNET_h2s (&s->session_id),
438 GNUNET_i2s (&s->peer));
439 if (GNUNET_SCALARPRODUCT_STATUS_ACTIVE == s->status)
441 /* We didn't get an answer yet, fail with error */
442 s->status = GNUNET_SCALARPRODUCT_STATUS_FAILURE;
443 prepare_client_end_notification (s);
450 * Computes the square sum over a vector of a given length.
452 * @param vector the vector to compute over
453 * @param length the length of the vector
454 * @return an MPI value containing the calculated sum, never NULL
457 compute_square_sum_mpi_elements (const struct MpiElement *vector,
464 GNUNET_assert (NULL != (sum = gcry_mpi_new (0)));
465 GNUNET_assert (NULL != (elem = gcry_mpi_new (0)));
466 for (i = 0; i < length; i++)
468 gcry_mpi_mul (elem, vector[i].value, vector[i].value);
469 gcry_mpi_add (sum, sum, elem);
471 gcry_mpi_release (elem);
477 * Computes the square sum over a vector of a given length.
479 * @param vector the vector to compute over
480 * @param length the length of the vector
481 * @return an MPI value containing the calculated sum, never NULL
484 compute_square_sum (const gcry_mpi_t *vector,
491 GNUNET_assert (NULL != (sum = gcry_mpi_new (0)));
492 GNUNET_assert (NULL != (elem = gcry_mpi_new (0)));
493 for (i = 0; i < length; i++)
495 gcry_mpi_mul (elem, vector[i], vector[i]);
496 gcry_mpi_add (sum, sum, elem);
498 gcry_mpi_release (elem);
504 * Compute our scalar product, done by Alice
506 * @param session the session associated with this computation
507 * @return product as MPI, never NULL
510 compute_scalar_product (struct AliceServiceSession *session)
519 gcry_mpi_t r[session->used_element_count];
520 gcry_mpi_t r_prime[session->used_element_count];
525 count = session->used_element_count;
526 // due to the introduced static offset S, we now also have to remove this
527 // from the E(a_pi)(+)E(-b_pi-r_pi) and E(a_qi)(+)E(-r_qi) twice each,
528 // the result is E((S + a_pi) + (S -b_pi-r_pi)) and E(S + a_qi + S - r_qi)
529 for (i = 0; i < count; i++)
531 r[i] = gcry_mpi_new (0);
532 GNUNET_CRYPTO_paillier_decrypt (&my_privkey,
542 r_prime[i] = gcry_mpi_new (0);
543 GNUNET_CRYPTO_paillier_decrypt (&my_privkey,
545 &session->r_prime[i],
547 gcry_mpi_sub (r_prime[i],
550 gcry_mpi_sub (r_prime[i],
555 // calculate t = sum(ai)
556 t = compute_square_sum_mpi_elements (session->sorted_elements,
559 u = gcry_mpi_new (0);
560 tmp = compute_square_sum (r, count);
561 gcry_mpi_sub (u, u, tmp);
562 gcry_mpi_release (tmp);
565 u_prime = gcry_mpi_new (0);
566 tmp = compute_square_sum (r_prime, count);
567 gcry_mpi_sub (u_prime, u_prime, tmp);
569 GNUNET_assert (p = gcry_mpi_new (0));
570 GNUNET_assert (p_prime = gcry_mpi_new (0));
571 GNUNET_assert (s = gcry_mpi_new (0));
572 GNUNET_assert (s_prime = gcry_mpi_new (0));
575 GNUNET_CRYPTO_paillier_decrypt (&my_privkey,
579 GNUNET_CRYPTO_paillier_decrypt (&my_privkey,
585 gcry_mpi_add (p, s, t);
586 gcry_mpi_add (p, p, u);
589 gcry_mpi_add (p_prime, s_prime, t);
590 gcry_mpi_add (p_prime, p_prime, u_prime);
592 gcry_mpi_release (t);
593 gcry_mpi_release (u);
594 gcry_mpi_release (u_prime);
595 gcry_mpi_release (s);
596 gcry_mpi_release (s_prime);
599 gcry_mpi_sub (p, p, p_prime);
600 gcry_mpi_release (p_prime);
601 tmp = gcry_mpi_set_ui (tmp, 2);
602 gcry_mpi_div (p, NULL, p, tmp, 0);
604 gcry_mpi_release (tmp);
605 for (i = 0; i < count; i++)
607 gcry_mpi_release (session->sorted_elements[i].value);
608 gcry_mpi_release (r[i]);
609 gcry_mpi_release (r_prime[i]);
611 GNUNET_free (session->sorted_elements);
612 session->sorted_elements = NULL;
613 GNUNET_free (session->r);
615 GNUNET_free (session->r_prime);
616 session->r_prime = NULL;
623 * Check a multipart chunk of a response we got from another service
624 * we wanted to calculate a scalarproduct with.
626 * @param cls the `struct AliceServiceSession`
627 * @param msg the actual message
628 * @return #GNUNET_OK to keep the connection open,
629 * #GNUNET_SYSERR to close it (signal serious error)
632 check_bobs_cryptodata_multipart (void *cls,
633 const struct BobCryptodataMultipartMessage *msg)
635 struct AliceServiceSession *s = cls;
638 size_t required_size;
640 msg_size = ntohs (msg->header.size);
641 contained = ntohl (msg->contained_element_count);
642 required_size = sizeof (struct BobCryptodataMultipartMessage)
643 + 2 * contained * sizeof (struct GNUNET_CRYPTO_PaillierCiphertext);
644 if ( (required_size != msg_size) ||
645 (s->cadet_received_element_count + contained > s->used_element_count) )
648 return GNUNET_SYSERR;
654 * Handle a multipart chunk of a response we got from another service
655 * we wanted to calculate a scalarproduct with.
657 * @param cls the `struct AliceServiceSession`
658 * @param msg the actual message
661 handle_bobs_cryptodata_multipart (void *cls,
662 const struct BobCryptodataMultipartMessage *msg)
664 struct AliceServiceSession *s = cls;
665 const struct GNUNET_CRYPTO_PaillierCiphertext *payload;
669 contained = ntohl (msg->contained_element_count);
670 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
671 "Received %u additional crypto values from Bob\n",
672 (unsigned int) contained);
674 payload = (const struct GNUNET_CRYPTO_PaillierCiphertext *) &msg[1];
675 /* Convert each k[][perm] to its MPI_value */
676 for (i = 0; i < contained; i++)
678 GNUNET_memcpy (&s->r[s->cadet_received_element_count + i],
680 sizeof (struct GNUNET_CRYPTO_PaillierCiphertext));
681 GNUNET_memcpy (&s->r_prime[s->cadet_received_element_count + i],
683 sizeof (struct GNUNET_CRYPTO_PaillierCiphertext));
685 s->cadet_received_element_count += contained;
686 GNUNET_CADET_receive_done (s->channel);
687 if (s->cadet_received_element_count != s->used_element_count)
688 return; /* more to come */
690 s->product = compute_scalar_product (s);
691 transmit_client_response (s);
696 * Check a response we got from another service we wanted to
697 * calculate a scalarproduct with.
699 * @param cls our `struct AliceServiceSession`
700 * @param message the actual message
701 * @return #GNUNET_OK to keep the connection open,
702 * #GNUNET_SYSERR to close it (we are done)
705 check_bobs_cryptodata_message (void *cls,
706 const struct BobCryptodataMessage *msg)
708 struct AliceServiceSession *s = cls;
711 size_t required_size;
713 msg_size = ntohs (msg->header.size);
714 contained = ntohl (msg->contained_element_count);
715 required_size = sizeof (struct BobCryptodataMessage)
716 + 2 * contained * sizeof (struct GNUNET_CRYPTO_PaillierCiphertext)
717 + 2 * sizeof (struct GNUNET_CRYPTO_PaillierCiphertext);
718 if ( (msg_size != required_size) ||
719 (contained > UINT16_MAX) ||
720 (s->used_element_count < contained) )
723 return GNUNET_SYSERR;
725 if (NULL == s->sorted_elements)
727 /* we're not ready yet, how can Bob be? */
729 return GNUNET_SYSERR;
731 if (s->total != s->client_received_element_count)
733 /* we're not ready yet, how can Bob be? */
735 return GNUNET_SYSERR;
742 * Handle a response we got from another service we wanted to
743 * calculate a scalarproduct with.
745 * @param cls our `struct AliceServiceSession`
746 * @param msg the actual message
749 handle_bobs_cryptodata_message (void *cls,
750 const struct BobCryptodataMessage *msg)
752 struct AliceServiceSession *s = cls;
753 const struct GNUNET_CRYPTO_PaillierCiphertext *payload;
757 contained = ntohl (msg->contained_element_count);
758 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
759 "Received %u crypto values from Bob\n",
760 (unsigned int) contained);
761 payload = (const struct GNUNET_CRYPTO_PaillierCiphertext *) &msg[1];
762 GNUNET_memcpy (&s->s,
764 sizeof (struct GNUNET_CRYPTO_PaillierCiphertext));
765 GNUNET_memcpy (&s->s_prime,
767 sizeof (struct GNUNET_CRYPTO_PaillierCiphertext));
768 payload = &payload[2];
770 s->r = GNUNET_new_array (s->used_element_count,
771 struct GNUNET_CRYPTO_PaillierCiphertext);
772 s->r_prime = GNUNET_new_array (s->used_element_count,
773 struct GNUNET_CRYPTO_PaillierCiphertext);
774 for (i = 0; i < contained; i++)
776 GNUNET_memcpy (&s->r[i],
778 sizeof (struct GNUNET_CRYPTO_PaillierCiphertext));
779 GNUNET_memcpy (&s->r_prime[i],
781 sizeof (struct GNUNET_CRYPTO_PaillierCiphertext));
783 s->cadet_received_element_count = contained;
784 GNUNET_CADET_receive_done (s->channel);
786 if (s->cadet_received_element_count != s->used_element_count)
791 s->product = compute_scalar_product (s);
792 transmit_client_response (s);
797 * Iterator to copy over messages from the hash map
798 * into an array for sorting.
800 * @param cls the `struct AliceServiceSession *`
801 * @param key the key (unused)
802 * @param value the `struct GNUNET_SCALARPRODUCT_Element *`
805 copy_element_cb (void *cls,
806 const struct GNUNET_HashCode *key,
809 struct AliceServiceSession *s = cls;
810 struct GNUNET_SCALARPRODUCT_Element *e = value;
814 mval = gcry_mpi_new (0);
815 val = (int64_t) GNUNET_ntohll (e->value);
817 gcry_mpi_sub_ui (mval, mval, -val);
819 gcry_mpi_add_ui (mval, mval, val);
820 s->sorted_elements [s->used_element_count].value = mval;
821 s->sorted_elements [s->used_element_count].key = &e->key;
822 s->used_element_count++;
828 * Compare two `struct MpiValue`s by key for sorting.
830 * @param a pointer to first `struct MpiValue *`
831 * @param b pointer to first `struct MpiValue *`
832 * @return -1 for a < b, 0 for a=b, 1 for a > b.
835 element_cmp (const void *a,
838 const struct MpiElement *ma = a;
839 const struct MpiElement *mb = b;
841 return GNUNET_CRYPTO_hash_cmp (ma->key,
847 * Maximum number of elements we can put into a single cryptodata
850 #define ELEMENT_CAPACITY ((GNUNET_CONSTANTS_MAX_CADET_MESSAGE_SIZE - 1 - sizeof (struct AliceCryptodataMessage)) / sizeof (struct GNUNET_CRYPTO_PaillierCiphertext))
854 * Send the cryptographic data from Alice to Bob.
855 * Does nothing if we already transferred all elements.
857 * @param s the associated service session
860 send_alices_cryptodata_message (struct AliceServiceSession *s)
862 struct AliceCryptodataMessage *msg;
863 struct GNUNET_MQ_Envelope *e;
864 struct GNUNET_CRYPTO_PaillierCiphertext *payload;
871 = GNUNET_malloc (GNUNET_CONTAINER_multihashmap_size (s->intersected_elements) *
872 sizeof (struct MpiElement));
873 s->used_element_count = 0;
874 GNUNET_CONTAINER_multihashmap_iterate (s->intersected_elements,
877 LOG (GNUNET_ERROR_TYPE_DEBUG,
878 "Finished intersection, %d items remain\n",
879 s->used_element_count);
880 qsort (s->sorted_elements,
881 s->used_element_count,
882 sizeof (struct MpiElement),
885 while (off < s->used_element_count)
887 todo_count = s->used_element_count - off;
888 if (todo_count > ELEMENT_CAPACITY)
889 todo_count = ELEMENT_CAPACITY;
890 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
891 "Sending %u/%u crypto values to Bob\n",
892 (unsigned int) todo_count,
893 (unsigned int) s->used_element_count);
895 e = GNUNET_MQ_msg_extra (msg,
896 todo_count * sizeof (struct GNUNET_CRYPTO_PaillierCiphertext),
897 GNUNET_MESSAGE_TYPE_SCALARPRODUCT_ALICE_CRYPTODATA);
898 msg->contained_element_count = htonl (todo_count);
899 payload = (struct GNUNET_CRYPTO_PaillierCiphertext *) &msg[1];
900 a = gcry_mpi_new (0);
901 for (i = off; i < off + todo_count; i++)
904 s->sorted_elements[i].value,
907 GNUNET_CRYPTO_paillier_encrypt (&my_pubkey,
912 gcry_mpi_release (a);
914 GNUNET_MQ_send (s->cadet_mq,
921 * Callback for set operation results. Called for each element
922 * that should be removed from the result set, and then once
923 * to indicate that the set intersection operation is done.
925 * @param cls closure with the `struct AliceServiceSession`
926 * @param element a result element, only valid if status is #GNUNET_SET_STATUS_OK
927 * @param status what has happened with the set intersection?
930 cb_intersection_element_removed (void *cls,
931 const struct GNUNET_SET_Element *element,
932 enum GNUNET_SET_Status status)
934 struct AliceServiceSession *s = cls;
935 struct GNUNET_SCALARPRODUCT_Element *se;
939 case GNUNET_SET_STATUS_OK:
940 /* this element has been removed from the set */
941 se = GNUNET_CONTAINER_multihashmap_get (s->intersected_elements,
943 GNUNET_assert (NULL != se);
944 LOG (GNUNET_ERROR_TYPE_DEBUG,
945 "Intersection removed element with key %s and value %lld\n",
946 GNUNET_h2s (&se->key),
947 (long long) GNUNET_ntohll (se->value));
948 GNUNET_assert (GNUNET_YES ==
949 GNUNET_CONTAINER_multihashmap_remove (s->intersected_elements,
954 case GNUNET_SET_STATUS_DONE:
955 s->intersection_op = NULL;
956 if (NULL != s->intersection_set)
958 GNUNET_SET_destroy (s->intersection_set);
959 s->intersection_set = NULL;
961 send_alices_cryptodata_message (s);
963 case GNUNET_SET_STATUS_HALF_DONE:
964 /* unexpected for intersection */
967 case GNUNET_SET_STATUS_FAILURE:
968 /* unhandled status code */
969 LOG (GNUNET_ERROR_TYPE_DEBUG,
970 "Set intersection failed!\n");
971 if (NULL != s->intersection_listen)
973 GNUNET_SET_listen_cancel (s->intersection_listen);
974 s->intersection_listen = NULL;
976 s->intersection_op = NULL;
977 if (NULL != s->intersection_set)
979 GNUNET_SET_destroy (s->intersection_set);
980 s->intersection_set = NULL;
982 s->status = GNUNET_SCALARPRODUCT_STATUS_FAILURE;
983 prepare_client_end_notification (s);
993 * Called when another peer wants to do a set operation with the
994 * local peer. If a listen error occurs, the @a request is NULL.
996 * @param cls closure with the `struct AliceServiceSession *`
997 * @param other_peer the other peer
998 * @param context_msg message with application specific information from
1000 * @param request request from the other peer (never NULL), use GNUNET_SET_accept()
1001 * to accept it, otherwise the request will be refused
1002 * Note that we can't just return value from the listen callback,
1003 * as it is also necessary to specify the set we want to do the
1004 * operation with, whith sometimes can be derived from the context
1005 * message. It's necessary to specify the timeout.
1008 cb_intersection_request_alice (void *cls,
1009 const struct GNUNET_PeerIdentity *other_peer,
1010 const struct GNUNET_MessageHeader *context_msg,
1011 struct GNUNET_SET_Request *request)
1013 struct AliceServiceSession *s = cls;
1015 if (0 != memcmp (other_peer,
1017 sizeof (struct GNUNET_PeerIdentity)))
1019 GNUNET_break_op (0);
1023 = GNUNET_SET_accept (request,
1024 GNUNET_SET_RESULT_REMOVED,
1025 (struct GNUNET_SET_Option[]) { 0 },
1026 &cb_intersection_element_removed,
1028 if (NULL == s->intersection_op)
1031 s->status = GNUNET_SCALARPRODUCT_STATUS_FAILURE;
1032 prepare_client_end_notification (s);
1036 GNUNET_SET_commit (s->intersection_op,
1037 s->intersection_set))
1040 s->status = GNUNET_SCALARPRODUCT_STATUS_FAILURE;
1041 prepare_client_end_notification (s);
1044 GNUNET_SET_destroy (s->intersection_set);
1045 s->intersection_set = NULL;
1046 GNUNET_SET_listen_cancel (s->intersection_listen);
1047 s->intersection_listen = NULL;
1052 * Our client has finished sending us its multipart message.
1054 * @param session the service session context
1057 client_request_complete_alice (struct AliceServiceSession *s)
1059 struct GNUNET_MQ_MessageHandler cadet_handlers[] = {
1060 GNUNET_MQ_hd_var_size (bobs_cryptodata_message,
1061 GNUNET_MESSAGE_TYPE_SCALARPRODUCT_BOB_CRYPTODATA,
1062 struct BobCryptodataMessage,
1064 GNUNET_MQ_hd_var_size (bobs_cryptodata_multipart,
1065 GNUNET_MESSAGE_TYPE_SCALARPRODUCT_BOB_CRYPTODATA_MULTIPART,
1066 struct BobCryptodataMultipartMessage,
1068 GNUNET_MQ_handler_end ()
1070 struct ServiceRequestMessage *msg;
1071 struct GNUNET_MQ_Envelope *e;
1073 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1074 "Creating new channel for session with key %s.\n",
1075 GNUNET_h2s (&s->session_id));
1077 = GNUNET_CADET_channel_creatE (my_cadet,
1081 GNUNET_CADET_OPTION_RELIABLE,
1083 &cb_channel_destruction,
1085 if (NULL == s->channel)
1087 s->status = GNUNET_SCALARPRODUCT_STATUS_FAILURE;
1088 prepare_client_end_notification (s);
1091 s->cadet_mq = GNUNET_CADET_get_mq (s->channel);
1092 s->intersection_listen
1093 = GNUNET_SET_listen (cfg,
1094 GNUNET_SET_OPERATION_INTERSECTION,
1096 &cb_intersection_request_alice,
1098 if (NULL == s->intersection_listen)
1100 s->status = GNUNET_SCALARPRODUCT_STATUS_FAILURE;
1101 GNUNET_CADET_channel_destroy (s->channel);
1103 prepare_client_end_notification (s);
1107 e = GNUNET_MQ_msg (msg,
1108 GNUNET_MESSAGE_TYPE_SCALARPRODUCT_SESSION_INITIALIZATION);
1109 msg->session_id = s->session_id;
1110 msg->public_key = my_pubkey;
1111 GNUNET_MQ_send (s->cadet_mq,
1117 * We're receiving additional set data. Check if
1118 * @a msg is well-formed.
1120 * @param cls client identification of the client
1121 * @param msg the actual message
1122 * @return #GNUNET_OK if @a msg is well-formed
1125 check_alice_client_message_multipart (void *cls,
1126 const struct ComputationBobCryptodataMultipartMessage *msg)
1128 struct AliceServiceSession *s = cls;
1129 uint32_t contained_count;
1132 msize = ntohs (msg->header.size);
1133 contained_count = ntohl (msg->element_count_contained);
1134 if ( (msize != (sizeof (struct ComputationBobCryptodataMultipartMessage) +
1135 contained_count * sizeof (struct GNUNET_SCALARPRODUCT_Element))) ||
1136 (0 == contained_count) ||
1137 (s->total == s->client_received_element_count) ||
1138 (s->total < s->client_received_element_count + contained_count) )
1140 GNUNET_break_op (0);
1141 return GNUNET_SYSERR;
1148 * We're receiving additional set data. Add it to our
1149 * set and if we are done, initiate the transaction.
1151 * @param cls client identification of the client
1152 * @param msg the actual message
1155 handle_alice_client_message_multipart (void *cls,
1156 const struct ComputationBobCryptodataMultipartMessage *msg)
1158 struct AliceServiceSession *s = cls;
1159 uint32_t contained_count;
1160 const struct GNUNET_SCALARPRODUCT_Element *elements;
1161 struct GNUNET_SET_Element set_elem;
1162 struct GNUNET_SCALARPRODUCT_Element *elem;
1164 contained_count = ntohl (msg->element_count_contained);
1165 s->client_received_element_count += contained_count;
1166 elements = (const struct GNUNET_SCALARPRODUCT_Element *) &msg[1];
1167 for (uint32_t i = 0; i < contained_count; i++)
1169 elem = GNUNET_new (struct GNUNET_SCALARPRODUCT_Element);
1170 GNUNET_memcpy (elem,
1172 sizeof (struct GNUNET_SCALARPRODUCT_Element));
1173 if (GNUNET_SYSERR ==
1174 GNUNET_CONTAINER_multihashmap_put (s->intersected_elements,
1177 GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY))
1183 set_elem.data = &elem->key;
1184 set_elem.size = sizeof (elem->key);
1185 set_elem.element_type = 0;
1186 GNUNET_SET_add_element (s->intersection_set,
1189 s->used_element_count++;
1191 GNUNET_SERVICE_client_continue (s->client);
1192 if (s->total != s->client_received_element_count)
1197 client_request_complete_alice (s);
1202 * Handler for Alice's client request message.
1203 * Check that @a msg is well-formed.
1205 * @param cls identification of the client
1206 * @param msg the actual message
1207 * @return #GNUNET_OK if @a msg is well-formed
1210 check_alice_client_message (void *cls,
1211 const struct AliceComputationMessage *msg)
1213 struct AliceServiceSession *s = cls;
1215 uint32_t total_count;
1216 uint32_t contained_count;
1218 if (NULL != s->intersected_elements)
1220 /* only one concurrent session per client connection allowed,
1221 simplifies logic a lot... */
1223 return GNUNET_SYSERR;
1225 msize = ntohs (msg->header.size);
1226 total_count = ntohl (msg->element_count_total);
1227 contained_count = ntohl (msg->element_count_contained);
1228 if ( (0 == total_count) ||
1229 (0 == contained_count) ||
1230 (msize != (sizeof (struct AliceComputationMessage) +
1231 contained_count * sizeof (struct GNUNET_SCALARPRODUCT_Element))) )
1233 GNUNET_break_op (0);
1234 return GNUNET_SYSERR;
1241 * Handler for Alice's client request message.
1242 * We are doing request-initiation to compute a scalar product with a peer.
1244 * @param cls identification of the client
1245 * @param msg the actual message
1248 handle_alice_client_message (void *cls,
1249 const struct AliceComputationMessage *msg)
1251 struct AliceServiceSession *s = cls;
1252 uint32_t contained_count;
1253 uint32_t total_count;
1254 const struct GNUNET_SCALARPRODUCT_Element *elements;
1255 struct GNUNET_SET_Element set_elem;
1256 struct GNUNET_SCALARPRODUCT_Element *elem;
1258 total_count = ntohl (msg->element_count_total);
1259 contained_count = ntohl (msg->element_count_contained);
1260 s->peer = msg->peer;
1261 s->status = GNUNET_SCALARPRODUCT_STATUS_ACTIVE;
1262 s->total = total_count;
1263 s->client_received_element_count = contained_count;
1264 s->session_id = msg->session_key;
1265 elements = (const struct GNUNET_SCALARPRODUCT_Element *) &msg[1];
1266 s->intersected_elements = GNUNET_CONTAINER_multihashmap_create (s->total,
1268 s->intersection_set = GNUNET_SET_create (cfg,
1269 GNUNET_SET_OPERATION_INTERSECTION);
1271 for (uint32_t i = 0; i < contained_count; i++)
1273 if (0 == GNUNET_ntohll (elements[i].value))
1275 elem = GNUNET_new (struct GNUNET_SCALARPRODUCT_Element);
1276 GNUNET_memcpy (elem,
1278 sizeof (struct GNUNET_SCALARPRODUCT_Element));
1279 if (GNUNET_SYSERR ==
1280 GNUNET_CONTAINER_multihashmap_put (s->intersected_elements,
1283 GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY))
1285 /* element with same key encountered twice! */
1290 set_elem.data = &elem->key;
1291 set_elem.size = sizeof (elem->key);
1292 set_elem.element_type = 0;
1293 GNUNET_SET_add_element (s->intersection_set,
1296 s->used_element_count++;
1298 GNUNET_SERVICE_client_continue (s->client);
1299 if (s->total != s->client_received_element_count)
1301 /* wait for multipart msg */
1304 client_request_complete_alice (s);
1309 * Task run during shutdown.
1314 shutdown_task (void *cls)
1316 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1317 "Shutting down, initiating cleanup.\n");
1318 // FIXME: we have to cut our connections to CADET first!
1319 if (NULL != my_cadet)
1321 GNUNET_CADET_disconnect (my_cadet);
1328 * A client connected.
1330 * Setup the associated data structure.
1332 * @param cls closure, NULL
1333 * @param client identification of the client
1334 * @param mq message queue to communicate with @a client
1335 * @return our `struct AliceServiceSession`
1338 client_connect_cb (void *cls,
1339 struct GNUNET_SERVICE_Client *client,
1340 struct GNUNET_MQ_Handle *mq)
1342 struct AliceServiceSession *s;
1344 s = GNUNET_new (struct AliceServiceSession);
1352 * A client disconnected.
1354 * Remove the associated session(s), release data structures
1355 * and cancel pending outgoing transmissions to the client.
1357 * @param cls closure, NULL
1358 * @param client identification of the client
1359 * @param app_cls our `struct AliceServiceSession`
1362 client_disconnect_cb (void *cls,
1363 struct GNUNET_SERVICE_Client *client,
1366 struct AliceServiceSession *s = app_cls;
1368 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1369 "Client %p disconnected from us.\n",
1372 s->client_mq = NULL;
1373 destroy_service_session (s);
1378 * Initialization of the program and message handlers
1380 * @param cls closure
1381 * @param c configuration to use
1382 * @param service the initialized service
1386 const struct GNUNET_CONFIGURATION_Handle *c,
1387 struct GNUNET_SERVICE_Handle *service)
1391 offset has to be sufficiently small to allow computation of:
1392 m1+m2 mod n == (S + a) + (S + b) mod n,
1393 if we have more complex operations, this factor needs to be lowered */
1394 my_offset = gcry_mpi_new (GNUNET_CRYPTO_PAILLIER_BITS / 3);
1395 gcry_mpi_set_bit (my_offset,
1396 GNUNET_CRYPTO_PAILLIER_BITS / 3);
1397 GNUNET_CRYPTO_paillier_create (&my_pubkey,
1399 my_cadet = GNUNET_CADET_connecT (cfg);
1400 GNUNET_SCHEDULER_add_shutdown (&shutdown_task,
1402 if (NULL == my_cadet)
1404 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1405 _("Connect to CADET failed\n"));
1406 GNUNET_SCHEDULER_shutdown ();
1413 * Define "main" method using service macro.
1416 ("scalarproduct-alice",
1417 GNUNET_SERVICE_OPTION_NONE,
1420 &client_disconnect_cb,
1422 GNUNET_MQ_hd_var_size (alice_client_message,
1423 GNUNET_MESSAGE_TYPE_SCALARPRODUCT_CLIENT_TO_ALICE,
1424 struct AliceComputationMessage,
1426 GNUNET_MQ_hd_var_size (alice_client_message_multipart,
1427 GNUNET_MESSAGE_TYPE_SCALARPRODUCT_CLIENT_MULTIPART_ALICE,
1428 struct ComputationBobCryptodataMultipartMessage,
1430 GNUNET_MQ_handler_end ());
1433 /* end of gnunet-service-scalarproduct_alice.c */