2 This file is part of GNUnet.
3 Copyright (C) 2013, 2014 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_bob.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-bob", __VA_ARGS__)
43 * An encrypted element key-value pair.
48 * Key used to identify matching pairs of values to multiply.
49 * Points into an existing data structure, to avoid copying
50 * and doubling memory use.
52 const struct GNUNET_HashCode *key;
55 * Value represented (a).
62 * An incoming session from CADET.
64 struct CadetIncomingSession;
68 * A scalarproduct session which tracks an offer for a
69 * multiplication service by a local client.
71 struct BobServiceSession
75 * (hopefully) unique transaction ID
77 struct GNUNET_HashCode session_id;
80 * The client this request is related to.
82 struct GNUNET_SERVER_Client *client;
85 * Client message queue.
87 struct GNUNET_MQ_Handle *client_mq;
90 * All non-0-value'd elements transmitted to us.
92 struct GNUNET_CONTAINER_MultiHashMap *intersected_elements;
95 * Set of elements for which we will be conducting an intersection.
96 * The resulting elements are then used for computing the scalar product.
98 struct GNUNET_SET_Handle *intersection_set;
101 * Set of elements for which will conduction an intersection.
102 * the resulting elements are then used for computing the scalar product.
104 struct GNUNET_SET_OperationHandle *intersection_op;
109 struct MpiElement *sorted_elements;
112 * E(ai)(Bob) after applying the mask
114 struct GNUNET_CRYPTO_PaillierCiphertext *e_a;
117 * Bob's permutation p of R
119 struct GNUNET_CRYPTO_PaillierCiphertext *r;
122 * Bob's permutation q of R
124 struct GNUNET_CRYPTO_PaillierCiphertext *r_prime;
129 struct GNUNET_CRYPTO_PaillierCiphertext s;
134 struct GNUNET_CRYPTO_PaillierCiphertext s_prime;
137 * Handle for our associated incoming CADET session, or NULL
138 * if we have not gotten one yet.
140 struct CadetIncomingSession *cadet;
143 * How many elements will be supplied in total from the client.
148 * Already transferred elements (received) for multipart
149 * messages from client. Always less than @e total.
151 uint32_t client_received_element_count;
154 * How many elements actually are used for the scalar product.
155 * Size of the arrays in @e r and @e r_prime. Also sometimes
156 * used as an index into the arrays during construction.
158 uint32_t used_element_count;
161 * Counts the number of values received from Alice by us.
162 * Always less than @e used_element_count.
164 uint32_t cadet_received_element_count;
167 * Counts the number of values transmitted from us to Alice.
168 * Always less than @e used_element_count.
170 uint32_t cadet_transmitted_element_count;
173 * State of this session. In
174 * #GNUNET_SCALARPRODUCT_STATUS_ACTIVE while operation is
175 * ongoing, afterwards in #GNUNET_SCALARPRODUCT_STATUS_SUCCESS or
176 * #GNUNET_SCALARPRODUCT_STATUS_FAILURE.
178 enum GNUNET_SCALARPRODUCT_ResponseStatus status;
181 * Are we already in #destroy_service_session()?
189 * An incoming session from CADET.
191 struct CadetIncomingSession
195 * Associated client session, or NULL.
197 struct BobServiceSession *s;
202 struct GNUNET_CADET_Channel *channel;
205 * Originator's peer identity. (Only for diagnostics.)
207 struct GNUNET_PeerIdentity peer;
210 * (hopefully) unique transaction ID
212 struct GNUNET_HashCode session_id;
215 * Public key of the remote service.
217 struct GNUNET_CRYPTO_PaillierPublicKey remote_pubkey;
220 * The message queue for this channel.
222 struct GNUNET_MQ_Handle *cadet_mq;
225 * Has this CADET session been added to the map yet?
226 * #GNUNET_YES if so, in which case @e session_id is
232 * Are we already in #destroy_cadet_session()?
240 * GNUnet configuration handle
242 static const struct GNUNET_CONFIGURATION_Handle *cfg;
245 * Service's own public key
247 static struct GNUNET_CRYPTO_PaillierPublicKey my_pubkey;
250 * Service's own private key
252 static struct GNUNET_CRYPTO_PaillierPrivateKey my_privkey;
255 * Service's offset for values that could possibly be negative but are plaintext for encryption.
257 static gcry_mpi_t my_offset;
260 * Map of `struct BobServiceSession`, by session keys.
262 static struct GNUNET_CONTAINER_MultiHashMap *client_sessions;
265 * Map of `struct CadetIncomingSession`, by session keys.
267 static struct GNUNET_CONTAINER_MultiHashMap *cadet_sessions;
270 * Handle to the CADET service.
272 static struct GNUNET_CADET_Handle *my_cadet;
277 * Finds a not terminated client session in the respective map based on
280 * @param key the session key we want to search for
281 * @return the matching session, or NULL for none
283 static struct BobServiceSession *
284 find_matching_client_session (const struct GNUNET_HashCode *key)
286 return GNUNET_CONTAINER_multihashmap_get (client_sessions,
292 * Finds a CADET session in the respective map based on session key.
294 * @param key the session key we want to search for
295 * @return the matching session, or NULL for none
297 static struct CadetIncomingSession *
298 find_matching_cadet_session (const struct GNUNET_HashCode *key)
300 return GNUNET_CONTAINER_multihashmap_get (cadet_sessions,
306 * Callback used to free the elements in the map.
309 * @param key key of the element
310 * @param value the value to free
313 free_element_cb (void *cls,
314 const struct GNUNET_HashCode *key,
317 struct GNUNET_SCALARPRODUCT_Element *element = value;
319 GNUNET_free (element);
325 * Destroy session state, we are done with it.
327 * @param session the session to free elements from
330 destroy_cadet_session (struct CadetIncomingSession *s);
334 * Destroy session state, we are done with it.
336 * @param session the session to free elements from
339 destroy_service_session (struct BobServiceSession *s)
341 struct CadetIncomingSession *in;
344 if (GNUNET_YES == s->in_destroy)
346 s->in_destroy = GNUNET_YES;
347 if (NULL != (in = s->cadet))
350 destroy_cadet_session (in);
352 if (NULL != s->client_mq)
354 GNUNET_MQ_destroy (s->client_mq);
357 if (NULL != s->client)
359 GNUNET_SERVER_client_disconnect (s->client);
362 GNUNET_assert (GNUNET_YES ==
363 GNUNET_CONTAINER_multihashmap_remove (client_sessions,
366 if (NULL != s->intersected_elements)
368 GNUNET_CONTAINER_multihashmap_iterate (s->intersected_elements,
371 GNUNET_CONTAINER_multihashmap_destroy (s->intersected_elements);
372 s->intersected_elements = NULL;
374 if (NULL != s->intersection_op)
376 GNUNET_SET_operation_cancel (s->intersection_op);
377 s->intersection_op = NULL;
379 if (NULL != s->intersection_set)
381 GNUNET_SET_destroy (s->intersection_set);
382 s->intersection_set = NULL;
386 GNUNET_free (s->e_a);
389 if (NULL != s->sorted_elements)
391 for (i=0;i<s->used_element_count;i++)
392 gcry_mpi_release (s->sorted_elements[i].value);
393 GNUNET_free (s->sorted_elements);
394 s->sorted_elements = NULL;
401 if (NULL != s->r_prime)
403 GNUNET_free (s->r_prime);
411 * Destroy incoming CADET session state, we are done with it.
413 * @param in the session to free elements from
416 destroy_cadet_session (struct CadetIncomingSession *in)
418 struct BobServiceSession *s;
420 if (GNUNET_YES == in->in_destroy)
422 in->in_destroy = GNUNET_YES;
423 if (NULL != (s = in->s))
426 destroy_service_session (s);
428 if (GNUNET_YES == in->in_map)
430 GNUNET_assert (GNUNET_YES ==
431 GNUNET_CONTAINER_multihashmap_remove (cadet_sessions,
434 in->in_map = GNUNET_NO;
436 if (NULL != in->cadet_mq)
438 GNUNET_MQ_destroy (in->cadet_mq);
441 if (NULL != in->channel)
443 GNUNET_CADET_channel_destroy (in->channel);
451 * Notify the client that the session has succeeded or failed. This
452 * message gets sent to Bob's client if the operation completed or
453 * Alice disconnected.
455 * @param session the associated client session to fail or succeed
458 prepare_client_end_notification (struct BobServiceSession *session)
460 struct ClientResponseMessage *msg;
461 struct GNUNET_MQ_Envelope *e;
463 if (NULL == session->client_mq)
464 return; /* no client left to be notified */
465 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
466 "Sending session-end notification with status %d to client for session %s\n",
468 GNUNET_h2s (&session->session_id));
469 e = GNUNET_MQ_msg (msg,
470 GNUNET_MESSAGE_TYPE_SCALARPRODUCT_RESULT);
472 msg->product_length = htonl (0);
473 msg->status = htonl (session->status);
474 GNUNET_MQ_send (session->client_mq,
480 * Function called whenever a channel is destroyed. Should clean up
481 * any associated state.
483 * It must NOT call #GNUNET_CADET_channel_destroy() on the channel.
485 * @param cls closure (set from #GNUNET_CADET_connect())
486 * @param channel connection to the other end (henceforth invalid)
487 * @param channel_ctx place where local state associated
488 * with the channel is stored
491 cb_channel_destruction (void *cls,
492 const struct GNUNET_CADET_Channel *channel,
495 struct CadetIncomingSession *in = channel_ctx;
496 struct BobServiceSession *s;
498 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
499 "Peer disconnected, terminating session %s with peer %s\n",
500 GNUNET_h2s (&in->session_id),
501 GNUNET_i2s (&in->peer));
502 if (NULL != (s = in->s))
504 if (GNUNET_SCALARPRODUCT_STATUS_ACTIVE == s->status)
506 s->status = GNUNET_SCALARPRODUCT_STATUS_FAILURE;
507 prepare_client_end_notification (s);
510 if (NULL != in->cadet_mq)
512 GNUNET_MQ_destroy (in->cadet_mq);
516 destroy_cadet_session (in);
521 * MQ finished giving our last message to CADET, now notify
522 * the client that we are finished.
525 bob_cadet_done_cb (void *cls)
527 struct BobServiceSession *session = cls;
529 session->status = GNUNET_SCALARPRODUCT_STATUS_SUCCESS;
530 prepare_client_end_notification (session);
535 * Maximum count of elements we can put into a multipart message
537 #define ELEMENT_CAPACITY ((GNUNET_CONSTANTS_MAX_CADET_MESSAGE_SIZE - 1 - sizeof (struct BobCryptodataMultipartMessage)) / sizeof (struct GNUNET_CRYPTO_PaillierCiphertext))
541 * Send a multipart chunk of a service response from Bob to Alice.
542 * This element only contains the two permutations of R, R'.
544 * @param s the associated service session
547 transmit_bobs_cryptodata_message_multipart (struct BobServiceSession *s)
549 struct GNUNET_CRYPTO_PaillierCiphertext *payload;
550 struct BobCryptodataMultipartMessage *msg;
551 struct GNUNET_MQ_Envelope *e;
556 while (s->cadet_transmitted_element_count != s->used_element_count)
558 todo_count = s->used_element_count - s->cadet_transmitted_element_count;
559 if (todo_count > ELEMENT_CAPACITY / 2)
560 todo_count = ELEMENT_CAPACITY / 2;
562 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
563 "Sending %u additional crypto values to Alice\n",
564 (unsigned int) todo_count);
565 e = GNUNET_MQ_msg_extra (msg,
566 todo_count * sizeof (struct GNUNET_CRYPTO_PaillierCiphertext) * 2,
567 GNUNET_MESSAGE_TYPE_SCALARPRODUCT_BOB_CRYPTODATA_MULTIPART);
568 msg->contained_element_count = htonl (todo_count);
569 payload = (struct GNUNET_CRYPTO_PaillierCiphertext *) &msg[1];
570 for (i = s->cadet_transmitted_element_count, j = 0; i < s->cadet_transmitted_element_count + todo_count; i++)
572 //r[i][p] and r[i][q]
573 GNUNET_memcpy (&payload[j++],
575 sizeof (struct GNUNET_CRYPTO_PaillierCiphertext));
576 GNUNET_memcpy (&payload[j++],
578 sizeof (struct GNUNET_CRYPTO_PaillierCiphertext));
580 s->cadet_transmitted_element_count += todo_count;
581 if (s->cadet_transmitted_element_count == s->used_element_count)
582 GNUNET_MQ_notify_sent (e,
585 GNUNET_MQ_send (s->cadet->cadet_mq,
588 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
589 "All values queued for Alice, Bob is done\n");
594 * Bob generates the response message to be sent to Alice after
595 * computing the values (1), (2), S and S'.
597 * (1)[]: $E_A(a_{pi(i)}) times E_A(- r_{pi(i)} - b_{pi(i)}) &= E_A(a_{pi(i)} - r_{pi(i)} - b_{pi(i)})$
598 * (2)[]: $E_A(a_{pi'(i)}) times E_A(- r_{pi'(i)}) &= E_A(a_{pi'(i)} - r_{pi'(i)})$
599 * S: $S := E_A(sum (r_i + b_i)^2)$
600 * S': $S' := E_A(sum r_i^2)$
602 * @param s the associated requesting session with Alice
605 transmit_bobs_cryptodata_message (struct BobServiceSession *s)
607 struct BobCryptodataMessage *msg;
608 struct GNUNET_MQ_Envelope *e;
609 struct GNUNET_CRYPTO_PaillierCiphertext *payload;
612 s->cadet_transmitted_element_count
613 = ((GNUNET_CONSTANTS_MAX_CADET_MESSAGE_SIZE - 1 - sizeof (struct BobCryptodataMessage))
614 / sizeof (struct GNUNET_CRYPTO_PaillierCiphertext) / 2) - 1;
615 if (s->cadet_transmitted_element_count > s->used_element_count)
616 s->cadet_transmitted_element_count = s->used_element_count;
618 e = GNUNET_MQ_msg_extra (msg,
619 (2 + s->cadet_transmitted_element_count * 2)
620 * sizeof (struct GNUNET_CRYPTO_PaillierCiphertext),
621 GNUNET_MESSAGE_TYPE_SCALARPRODUCT_BOB_CRYPTODATA);
622 msg->contained_element_count = htonl (s->cadet_transmitted_element_count);
624 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
625 "Sending %u/%u crypto values to Alice\n",
626 (unsigned int) s->cadet_transmitted_element_count,
627 (unsigned int) s->used_element_count);
629 payload = (struct GNUNET_CRYPTO_PaillierCiphertext *) &msg[1];
630 GNUNET_memcpy (&payload[0],
632 sizeof (struct GNUNET_CRYPTO_PaillierCiphertext));
633 GNUNET_memcpy (&payload[1],
635 sizeof (struct GNUNET_CRYPTO_PaillierCiphertext));
637 payload = &payload[2];
639 for (i = 0; i < s->cadet_transmitted_element_count; i++)
641 //k[i][p] and k[i][q]
642 GNUNET_memcpy (&payload[i * 2],
644 sizeof (struct GNUNET_CRYPTO_PaillierCiphertext));
645 GNUNET_memcpy (&payload[i * 2 + 1],
647 sizeof (struct GNUNET_CRYPTO_PaillierCiphertext));
649 if (s->cadet_transmitted_element_count == s->used_element_count)
650 GNUNET_MQ_notify_sent (e,
653 GNUNET_MQ_send (s->cadet->cadet_mq,
655 transmit_bobs_cryptodata_message_multipart (s);
657 #undef ELEMENT_CAPACITY
661 * Computes the square sum over a vector of a given length.
663 * @param vector the vector to compute over
664 * @param length the length of the vector
665 * @return an MPI value containing the calculated sum, never NULL
666 * TODO: code duplication with Alice!
669 compute_square_sum (const gcry_mpi_t *vector,
676 GNUNET_assert (NULL != (sum = gcry_mpi_new (0)));
677 GNUNET_assert (NULL != (elem = gcry_mpi_new (0)));
678 for (i = 0; i < length; i++)
680 gcry_mpi_mul (elem, vector[i], vector[i]);
681 gcry_mpi_add (sum, sum, elem);
683 gcry_mpi_release (elem);
690 * (1)[]: $E_A(a_{pi(i)}) otimes E_A(- r_{pi(i)} - b_{pi(i)}) &= E_A(a_{pi(i)} - r_{pi(i)} - b_{pi(i)})$
691 * (2)[]: $E_A(a_{pi'(i)}) otimes E_A(- r_{pi'(i)}) &= E_A(a_{pi'(i)} - r_{pi'(i)})$
692 * S: $S := E_A(sum (r_i + b_i)^2)$
693 * S': $S' := E_A(sum r_i^2)$
695 * @param request the requesting session + bob's requesting peer
696 * @return #GNUNET_OK on success
699 compute_service_response (struct BobServiceSession *session)
707 const struct MpiElement *b;
708 struct GNUNET_CRYPTO_PaillierCiphertext *a;
709 struct GNUNET_CRYPTO_PaillierCiphertext *r;
710 struct GNUNET_CRYPTO_PaillierCiphertext *r_prime;
712 count = session->used_element_count;
714 b = session->sorted_elements;
715 q = GNUNET_CRYPTO_random_permute (GNUNET_CRYPTO_QUALITY_WEAK,
717 p = GNUNET_CRYPTO_random_permute (GNUNET_CRYPTO_QUALITY_WEAK,
719 rand = GNUNET_malloc (sizeof (gcry_mpi_t) * count);
720 for (i = 0; i < count; i++)
721 GNUNET_assert (NULL != (rand[i] = gcry_mpi_new (0)));
722 r = GNUNET_malloc (sizeof (struct GNUNET_CRYPTO_PaillierCiphertext) * count);
723 r_prime = GNUNET_malloc (sizeof (struct GNUNET_CRYPTO_PaillierCiphertext) * count);
725 for (i = 0; i < count; i++)
729 svalue = (int32_t) GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_WEAK,
731 // long to gcry_mpi_t
733 gcry_mpi_sub_ui (rand[i],
737 rand[i] = gcry_mpi_set_ui (rand[i], svalue);
740 tmp = gcry_mpi_new (0);
741 // encrypt the element
742 // for the sake of readability I decided to have dedicated permutation
743 // vectors, which get rid of all the lookups in p/q.
744 // however, ap/aq are not absolutely necessary but are just abstraction
745 // Calculate Kp = E(S + a_pi) (+) E(S - r_pi - b_pi)
746 for (i = 0; i < count; i++)
748 // E(S - r_pi - b_pi)
749 gcry_mpi_sub (tmp, my_offset, rand[p[i]]);
750 gcry_mpi_sub (tmp, tmp, b[p[i]].value);
752 GNUNET_CRYPTO_paillier_encrypt (&session->cadet->remote_pubkey,
757 // E(S - r_pi - b_pi) * E(S + a_pi) == E(2*S + a - r - b)
759 GNUNET_CRYPTO_paillier_hom_add (&session->cadet->remote_pubkey,
769 // Calculate Kq = E(S + a_qi) (+) E(S - r_qi)
770 for (i = 0; i < count; i++)
773 gcry_mpi_sub (tmp, my_offset, rand[q[i]]);
775 GNUNET_CRYPTO_paillier_encrypt (&session->cadet->remote_pubkey,
780 // E(S - r_qi) * E(S + a_qi) == E(2*S + a_qi - r_qi)
782 GNUNET_CRYPTO_paillier_hom_add (&session->cadet->remote_pubkey,
791 gcry_mpi_release (tmp);
793 // Calculate S' = E(SUM( r_i^2 ))
794 tmp = compute_square_sum (rand, count);
796 GNUNET_CRYPTO_paillier_encrypt (&session->cadet->remote_pubkey,
800 gcry_mpi_release (tmp);
802 // Calculate S = E(SUM( (r_i + b_i)^2 ))
803 for (i = 0; i < count; i++)
804 gcry_mpi_add (rand[i], rand[i], b[i].value);
805 tmp = compute_square_sum (rand, count);
807 GNUNET_CRYPTO_paillier_encrypt (&session->cadet->remote_pubkey,
811 gcry_mpi_release (tmp);
814 session->r_prime = r_prime;
816 for (i = 0; i < count; i++)
817 gcry_mpi_release (rand[i]);
818 GNUNET_free (session->e_a);
827 GNUNET_free (r_prime);
828 gcry_mpi_release (tmp);
831 for (i = 0; i < count; i++)
832 gcry_mpi_release (rand[i]);
834 return GNUNET_SYSERR;
839 * Iterator to copy over messages from the hash map
840 * into an array for sorting.
842 * @param cls the `struct BobServiceSession *`
843 * @param key the key (unused)
844 * @param value the `struct GNUNET_SCALARPRODUCT_Element *`
845 * TODO: code duplication with Alice!
848 copy_element_cb (void *cls,
849 const struct GNUNET_HashCode *key,
852 struct BobServiceSession *s = cls;
853 struct GNUNET_SCALARPRODUCT_Element *e = value;
857 mval = gcry_mpi_new (0);
858 val = (int64_t) GNUNET_ntohll (e->value);
860 gcry_mpi_sub_ui (mval, mval, -val);
862 gcry_mpi_add_ui (mval, mval, val);
863 s->sorted_elements [s->used_element_count].value = mval;
864 s->sorted_elements [s->used_element_count].key = &e->key;
865 s->used_element_count++;
871 * Compare two `struct MpiValue`s by key for sorting.
873 * @param a pointer to first `struct MpiValue *`
874 * @param b pointer to first `struct MpiValue *`
875 * @return -1 for a < b, 0 for a=b, 1 for a > b.
876 * TODO: code duplication with Alice!
879 element_cmp (const void *a,
882 const struct MpiElement *ma = a;
883 const struct MpiElement *mb = b;
885 return GNUNET_CRYPTO_hash_cmp (ma->key,
891 * Intersection operation and receiving data via CADET from
892 * Alice are both done, compute and transmit our reply via
895 * @param s session to transmit reply for.
898 transmit_cryptographic_reply (struct BobServiceSession *s)
900 struct GNUNET_CADET_Channel *channel;
902 /* TODO: code duplication with Alice! */
903 LOG (GNUNET_ERROR_TYPE_DEBUG,
904 "Received everything, building reply for Alice\n");
906 = GNUNET_malloc (GNUNET_CONTAINER_multihashmap_size (s->intersected_elements) *
907 sizeof (struct MpiElement));
908 s->used_element_count = 0;
909 GNUNET_CONTAINER_multihashmap_iterate (s->intersected_elements,
912 qsort (s->sorted_elements,
913 s->used_element_count,
914 sizeof (struct MpiElement),
917 compute_service_response (s))
919 channel = s->cadet->channel;
920 s->cadet->channel = NULL;
921 GNUNET_CADET_channel_destroy (channel);
924 transmit_bobs_cryptodata_message (s);
929 * Handle a multipart-chunk of a request from another service to
930 * calculate a scalarproduct with us.
932 * @param cls closure (set from #GNUNET_CADET_connect)
933 * @param channel connection to the other end
934 * @param channel_ctx place to store local state associated with the @a channel
935 * @param message the actual message
936 * @return #GNUNET_OK to keep the connection open,
937 * #GNUNET_SYSERR to close it (signal serious error)
940 handle_alices_cryptodata_message (void *cls,
941 struct GNUNET_CADET_Channel *channel,
943 const struct GNUNET_MessageHeader *message)
945 struct CadetIncomingSession *in = *channel_ctx;
946 struct BobServiceSession *s;
947 const struct AliceCryptodataMessage *msg;
948 const struct GNUNET_CRYPTO_PaillierCiphertext *payload;
949 uint32_t contained_elements;
957 return GNUNET_SYSERR;
963 return GNUNET_SYSERR;
965 msize = ntohs (message->size);
966 if (msize <= sizeof (struct AliceCryptodataMessage))
969 return GNUNET_SYSERR;
971 msg = (const struct AliceCryptodataMessage *) message;
972 contained_elements = ntohl (msg->contained_element_count);
973 /* Our intersection may still be ongoing, but this is nevertheless
974 an upper bound on the required array size */
975 max = GNUNET_CONTAINER_multihashmap_size (s->intersected_elements);
976 msg_length = sizeof (struct AliceCryptodataMessage)
977 + contained_elements * sizeof (struct GNUNET_CRYPTO_PaillierCiphertext);
978 if ( (msize != msg_length) ||
979 (0 == contained_elements) ||
980 (contained_elements > UINT16_MAX) ||
981 (max < contained_elements + s->cadet_received_element_count) )
984 return GNUNET_SYSERR;
986 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
987 "Received %u crypto values from Alice\n",
988 (unsigned int) contained_elements);
990 payload = (const struct GNUNET_CRYPTO_PaillierCiphertext *) &msg[1];
992 s->e_a = GNUNET_malloc (sizeof (struct GNUNET_CRYPTO_PaillierCiphertext) *
994 GNUNET_memcpy (&s->e_a[s->cadet_received_element_count],
996 sizeof (struct GNUNET_CRYPTO_PaillierCiphertext) * contained_elements);
997 s->cadet_received_element_count += contained_elements;
999 if ( (s->cadet_received_element_count == max) &&
1000 (NULL == s->intersection_op) )
1002 /* intersection has finished also on our side, and
1003 we got the full set, so we can proceed with the
1004 CADET response(s) */
1005 transmit_cryptographic_reply (s);
1007 GNUNET_CADET_receive_done (s->cadet->channel);
1013 * Callback for set operation results. Called for each element
1014 * that needs to be removed from the result set.
1016 * @param cls closure with the `struct BobServiceSession`
1017 * @param element a result element, only valid if status is #GNUNET_SET_STATUS_OK
1018 * @param status what has happened with the set intersection?
1021 cb_intersection_element_removed (void *cls,
1022 const struct GNUNET_SET_Element *element,
1023 enum GNUNET_SET_Status status)
1025 struct BobServiceSession *s = cls;
1026 struct GNUNET_SCALARPRODUCT_Element *se;
1030 case GNUNET_SET_STATUS_OK:
1031 /* this element has been removed from the set */
1032 se = GNUNET_CONTAINER_multihashmap_get (s->intersected_elements,
1034 GNUNET_assert (NULL != se);
1035 LOG (GNUNET_ERROR_TYPE_DEBUG,
1036 "Removed element with key %s and value %lld\n",
1037 GNUNET_h2s (&se->key),
1038 (long long) GNUNET_ntohll (se->value));
1039 GNUNET_assert (GNUNET_YES ==
1040 GNUNET_CONTAINER_multihashmap_remove (s->intersected_elements,
1045 case GNUNET_SET_STATUS_DONE:
1046 s->intersection_op = NULL;
1047 GNUNET_break (NULL == s->intersection_set);
1048 GNUNET_CADET_receive_done (s->cadet->channel);
1049 LOG (GNUNET_ERROR_TYPE_DEBUG,
1050 "Finished intersection, %d items remain\n",
1051 GNUNET_CONTAINER_multihashmap_size (s->intersected_elements));
1052 if (s->client_received_element_count ==
1053 GNUNET_CONTAINER_multihashmap_size (s->intersected_elements))
1055 /* CADET transmission from Alice is also already done,
1056 start with our own reply */
1057 transmit_cryptographic_reply (s);
1060 case GNUNET_SET_STATUS_HALF_DONE:
1061 /* unexpected for intersection */
1064 case GNUNET_SET_STATUS_FAILURE:
1065 /* unhandled status code */
1066 LOG (GNUNET_ERROR_TYPE_DEBUG,
1067 "Set intersection failed!\n");
1068 s->intersection_op = NULL;
1069 if (NULL != s->intersection_set)
1071 GNUNET_SET_destroy (s->intersection_set);
1072 s->intersection_set = NULL;
1074 s->status = GNUNET_SCALARPRODUCT_STATUS_FAILURE;
1075 prepare_client_end_notification (s);
1085 * We've paired up a client session with an incoming CADET request.
1086 * Initiate set intersection work.
1088 * @param s client session to start intersection for
1091 start_intersection (struct BobServiceSession *s)
1093 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1094 "Got session with key %s and %u elements, starting intersection.\n",
1095 GNUNET_h2s (&s->session_id),
1096 (unsigned int) s->total);
1099 = GNUNET_SET_prepare (&s->cadet->peer,
1102 GNUNET_SET_RESULT_REMOVED,
1103 &cb_intersection_element_removed,
1106 GNUNET_SET_commit (s->intersection_op,
1107 s->intersection_set))
1110 s->status = GNUNET_SCALARPRODUCT_STATUS_FAILURE;
1111 prepare_client_end_notification (s);
1114 GNUNET_SET_destroy (s->intersection_set);
1115 s->intersection_set = NULL;
1120 * Handle a request from Alice to calculate a scalarproduct with us (Bob).
1122 * @param cls closure (set from #GNUNET_CADET_connect)
1123 * @param channel connection to the other end
1124 * @param channel_ctx place to store the `struct CadetIncomingSession *`
1125 * @param message the actual message
1126 * @return #GNUNET_OK to keep the connection open,
1127 * #GNUNET_SYSERR to close it (signal serious error)
1130 handle_alices_computation_request (void *cls,
1131 struct GNUNET_CADET_Channel *channel,
1133 const struct GNUNET_MessageHeader *message)
1135 struct CadetIncomingSession *in = *channel_ctx;
1136 struct BobServiceSession *s;
1137 const struct ServiceRequestMessage *msg;
1139 msg = (const struct ServiceRequestMessage *) message;
1140 if (GNUNET_YES == in->in_map)
1142 GNUNET_break_op (0);
1143 return GNUNET_SYSERR;
1145 if (NULL != find_matching_cadet_session (&msg->session_id))
1147 /* not unique, got one like this already */
1148 GNUNET_break_op (0);
1149 return GNUNET_SYSERR;
1151 in->session_id = msg->session_id;
1152 in->remote_pubkey = msg->public_key;
1153 GNUNET_assert (GNUNET_YES ==
1154 GNUNET_CONTAINER_multihashmap_put (cadet_sessions,
1157 GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY));
1158 s = find_matching_client_session (&in->session_id);
1161 /* no client waiting for this request, wait for client */
1164 GNUNET_assert (NULL == s->cadet);
1168 if (s->client_received_element_count == s->total)
1169 start_intersection (s);
1175 * Function called for inbound channels on Bob's end. Does some
1176 * preliminary initialization, more happens after we get Alice's first
1179 * @param cls closure
1180 * @param channel new handle to the channel
1181 * @param initiator peer that started the channel
1182 * @param port unused
1183 * @param options unused
1184 * @return session associated with the channel
1187 cb_channel_incoming (void *cls,
1188 struct GNUNET_CADET_Channel *channel,
1189 const struct GNUNET_PeerIdentity *initiator,
1191 enum GNUNET_CADET_ChannelOption options)
1193 struct CadetIncomingSession *in;
1195 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1196 "New incoming channel from peer %s.\n",
1197 GNUNET_i2s (initiator));
1198 in = GNUNET_new (struct CadetIncomingSession);
1199 in->peer = *initiator;
1200 in->channel = channel;
1201 in->cadet_mq = GNUNET_CADET_mq_create (in->channel);
1207 * We're receiving additional set data. Add it to our
1208 * set and if we are done, initiate the transaction.
1210 * @param cls closure
1211 * @param client identification of the client
1212 * @param message the actual message
1215 GSS_handle_bob_client_message_multipart (void *cls,
1216 struct GNUNET_SERVER_Client *client,
1217 const struct GNUNET_MessageHeader *message)
1219 const struct ComputationBobCryptodataMultipartMessage * msg;
1220 struct BobServiceSession *s;
1221 uint32_t contained_count;
1222 const struct GNUNET_SCALARPRODUCT_Element *elements;
1225 struct GNUNET_SET_Element set_elem;
1226 struct GNUNET_SCALARPRODUCT_Element *elem;
1228 s = GNUNET_SERVER_client_get_user_context (client,
1229 struct BobServiceSession);
1232 /* session needs to already exist */
1234 GNUNET_SERVER_receive_done (client,
1238 msize = ntohs (message->size);
1239 if (msize < sizeof (struct ComputationBobCryptodataMultipartMessage))
1242 GNUNET_SERVER_receive_done (client,
1246 msg = (const struct ComputationBobCryptodataMultipartMessage *) message;
1247 contained_count = ntohl (msg->element_count_contained);
1249 if ( (msize != (sizeof (struct ComputationBobCryptodataMultipartMessage) +
1250 contained_count * sizeof (struct GNUNET_SCALARPRODUCT_Element))) ||
1251 (0 == contained_count) ||
1252 (UINT16_MAX < contained_count) ||
1253 (s->total == s->client_received_element_count) ||
1254 (s->total < s->client_received_element_count + contained_count) )
1256 GNUNET_break_op (0);
1257 GNUNET_SERVER_receive_done (client,
1261 elements = (const struct GNUNET_SCALARPRODUCT_Element *) &msg[1];
1262 for (i = 0; i < contained_count; i++)
1264 elem = GNUNET_new (struct GNUNET_SCALARPRODUCT_Element);
1265 GNUNET_memcpy (elem,
1267 sizeof (struct GNUNET_SCALARPRODUCT_Element));
1268 if (GNUNET_SYSERR ==
1269 GNUNET_CONTAINER_multihashmap_put (s->intersected_elements,
1272 GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY))
1278 set_elem.data = &elem->key;
1279 set_elem.size = sizeof (elem->key);
1280 set_elem.element_type = 0;
1281 GNUNET_SET_add_element (s->intersection_set,
1285 s->client_received_element_count += contained_count;
1286 GNUNET_SERVER_receive_done (client,
1288 if (s->total != s->client_received_element_count)
1293 if (NULL == s->cadet)
1295 /* no Alice waiting for this request, wait for Alice */
1298 start_intersection (s);
1303 * Handler for Bob's a client request message. Bob is in the response
1304 * role, keep the values + session and waiting for a matching session
1305 * or process a waiting request from Alice.
1307 * @param cls closure
1308 * @param client identification of the client
1309 * @param message the actual message
1312 GSS_handle_bob_client_message (void *cls,
1313 struct GNUNET_SERVER_Client *client,
1314 const struct GNUNET_MessageHeader *message)
1316 const struct BobComputationMessage *msg;
1317 struct BobServiceSession *s;
1318 struct CadetIncomingSession *in;
1319 uint32_t contained_count;
1320 uint32_t total_count;
1321 const struct GNUNET_SCALARPRODUCT_Element *elements;
1323 struct GNUNET_SET_Element set_elem;
1324 struct GNUNET_SCALARPRODUCT_Element *elem;
1327 s = GNUNET_SERVER_client_get_user_context (client,
1328 struct BobServiceSession);
1331 /* only one concurrent session per client connection allowed,
1332 simplifies logic a lot... */
1334 GNUNET_SERVER_receive_done (client,
1338 msize = ntohs (message->size);
1339 if (msize < sizeof (struct BobComputationMessage))
1342 GNUNET_SERVER_receive_done (client,
1346 msg = (const struct BobComputationMessage *) message;
1347 total_count = ntohl (msg->element_count_total);
1348 contained_count = ntohl (msg->element_count_contained);
1349 if ( (0 == total_count) ||
1350 (0 == contained_count) ||
1351 (UINT16_MAX < contained_count) ||
1352 (msize != (sizeof (struct BobComputationMessage) +
1353 contained_count * sizeof (struct GNUNET_SCALARPRODUCT_Element))) )
1355 GNUNET_break_op (0);
1356 GNUNET_SERVER_receive_done (client,
1360 if (NULL != find_matching_client_session (&msg->session_key))
1363 GNUNET_SERVER_receive_done (client,
1368 s = GNUNET_new (struct BobServiceSession);
1369 s->status = GNUNET_SCALARPRODUCT_STATUS_ACTIVE;
1371 s->client_mq = GNUNET_MQ_queue_for_server_client (client);
1372 s->total = total_count;
1373 s->client_received_element_count = contained_count;
1374 s->session_id = msg->session_key;
1375 GNUNET_break (GNUNET_YES ==
1376 GNUNET_CONTAINER_multihashmap_put (client_sessions,
1379 GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY));
1380 elements = (const struct GNUNET_SCALARPRODUCT_Element *) &msg[1];
1381 s->intersected_elements = GNUNET_CONTAINER_multihashmap_create (s->total,
1383 s->intersection_set = GNUNET_SET_create (cfg,
1384 GNUNET_SET_OPERATION_INTERSECTION);
1385 for (i = 0; i < contained_count; i++)
1387 if (0 == GNUNET_ntohll (elements[i].value))
1389 elem = GNUNET_new (struct GNUNET_SCALARPRODUCT_Element);
1390 GNUNET_memcpy (elem,
1392 sizeof (struct GNUNET_SCALARPRODUCT_Element));
1393 if (GNUNET_SYSERR ==
1394 GNUNET_CONTAINER_multihashmap_put (s->intersected_elements,
1397 GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY))
1403 set_elem.data = &elem->key;
1404 set_elem.size = sizeof (elem->key);
1405 set_elem.element_type = 0;
1406 GNUNET_SET_add_element (s->intersection_set,
1409 s->used_element_count++;
1411 GNUNET_SERVER_client_set_user_context (client,
1413 GNUNET_SERVER_receive_done (client,
1415 if (s->total != s->client_received_element_count)
1420 in = find_matching_cadet_session (&s->session_id);
1423 /* nothing yet, wait for Alice */
1426 GNUNET_assert (NULL == in->s);
1430 start_intersection (s);
1435 * Task run during shutdown.
1440 shutdown_task (void *cls)
1442 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1443 "Shutting down, initiating cleanup.\n");
1444 // FIXME: we have to cut our connections to CADET first!
1445 if (NULL != my_cadet)
1447 GNUNET_CADET_disconnect (my_cadet);
1450 GNUNET_CONTAINER_multihashmap_destroy (client_sessions);
1451 client_sessions = NULL;
1452 GNUNET_CONTAINER_multihashmap_destroy (cadet_sessions);
1453 cadet_sessions = NULL;
1458 * A client disconnected.
1460 * Remove the associated session(s), release data structures
1461 * and cancel pending outgoing transmissions to the client.
1463 * @param cls closure, NULL
1464 * @param client identification of the client
1467 handle_client_disconnect (void *cls,
1468 struct GNUNET_SERVER_Client *client)
1470 struct BobServiceSession *s;
1474 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1475 "Client disconnected from us.\n");
1476 s = GNUNET_SERVER_client_get_user_context (client,
1477 struct BobServiceSession);
1481 destroy_service_session (s);
1486 * Initialization of the program and message handlers
1488 * @param cls closure
1489 * @param server the initialized server
1490 * @param c configuration to use
1494 struct GNUNET_SERVER_Handle *server,
1495 const struct GNUNET_CONFIGURATION_Handle *c)
1497 static const struct GNUNET_SERVER_MessageHandler server_handlers[] = {
1498 { &GSS_handle_bob_client_message, NULL,
1499 GNUNET_MESSAGE_TYPE_SCALARPRODUCT_CLIENT_TO_BOB,
1501 { &GSS_handle_bob_client_message_multipart, NULL,
1502 GNUNET_MESSAGE_TYPE_SCALARPRODUCT_CLIENT_MUTLIPART_BOB,
1506 static const struct GNUNET_CADET_MessageHandler cadet_handlers[] = {
1507 { &handle_alices_computation_request,
1508 GNUNET_MESSAGE_TYPE_SCALARPRODUCT_SESSION_INITIALIZATION,
1509 sizeof (struct ServiceRequestMessage) },
1510 { &handle_alices_cryptodata_message,
1511 GNUNET_MESSAGE_TYPE_SCALARPRODUCT_ALICE_CRYPTODATA,
1515 static const uint32_t ports[] = {
1516 GNUNET_APPLICATION_TYPE_SCALARPRODUCT,
1522 offset has to be sufficiently small to allow computation of:
1523 m1+m2 mod n == (S + a) + (S + b) mod n,
1524 if we have more complex operations, this factor needs to be lowered */
1525 my_offset = gcry_mpi_new (GNUNET_CRYPTO_PAILLIER_BITS / 3);
1526 gcry_mpi_set_bit (my_offset,
1527 GNUNET_CRYPTO_PAILLIER_BITS / 3);
1529 GNUNET_CRYPTO_paillier_create (&my_pubkey,
1531 GNUNET_SERVER_add_handlers (server,
1533 GNUNET_SERVER_disconnect_notify (server,
1534 &handle_client_disconnect,
1536 client_sessions = GNUNET_CONTAINER_multihashmap_create (128,
1538 cadet_sessions = GNUNET_CONTAINER_multihashmap_create (128,
1540 my_cadet = GNUNET_CADET_connect (cfg, NULL,
1541 &cb_channel_incoming,
1542 &cb_channel_destruction,
1545 if (NULL == my_cadet)
1547 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1548 _("Connect to CADET failed\n"));
1549 GNUNET_SCHEDULER_shutdown ();
1552 GNUNET_SCHEDULER_add_shutdown (&shutdown_task,
1558 * The main function for the scalarproduct service.
1560 * @param argc number of arguments from the command line
1561 * @param argv command line arguments
1562 * @return 0 ok, 1 on error
1568 return (GNUNET_OK ==
1569 GNUNET_SERVICE_run (argc, argv,
1570 "scalarproduct-bob",
1571 GNUNET_SERVICE_OPTION_NONE,
1572 &run, NULL)) ? 0 : 1;
1575 /* end of gnunet-service-scalarproduct_bob.c */