2 This file is part of GNUnet.
3 (C) 2013, 2014 Christian Grothoff (and other contributing authors)
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., 59 Temple Place - Suite 330,
18 Boston, MA 02111-1307, 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 * The computed scalar
148 * How many elements we were supplied with from the client
153 * how many elements actually are used for the scalar product.
154 * Size of the arrays in @e r and @e r_prime.
156 uint32_t used_element_count;
159 * already transferred elements (sent/received) for multipart messages, less or equal than @e used_element_count for
161 uint32_t transferred_element_count;
164 * Is this session active (#GNUNET_YES), Concluded (#GNUNET_NO), or had an error (#GNUNET_SYSERR)
169 * Are we already in #destroy_service_session()?
177 * An incoming session from CADET.
179 struct CadetIncomingSession
183 * Associated client session, or NULL.
185 struct BobServiceSession *s;
190 struct GNUNET_CADET_Channel *channel;
193 * Originator's peer identity. (Only for diagnostics.)
195 struct GNUNET_PeerIdentity peer;
198 * (hopefully) unique transaction ID
200 struct GNUNET_HashCode session_id;
203 * Public key of the remote service.
205 struct GNUNET_CRYPTO_PaillierPublicKey remote_pubkey;
208 * The message queue for this channel.
210 struct GNUNET_MQ_Handle *cadet_mq;
213 * Has this CADET session been added to the map yet?
214 * #GNUNET_YES if so, in which case @e session_id is
220 * Are we already in #destroy_cadet_session()?
228 * GNUnet configuration handle
230 static const struct GNUNET_CONFIGURATION_Handle *cfg;
233 * Service's own public key
235 static struct GNUNET_CRYPTO_PaillierPublicKey my_pubkey;
238 * Service's own private key
240 static struct GNUNET_CRYPTO_PaillierPrivateKey my_privkey;
243 * Service's offset for values that could possibly be negative but are plaintext for encryption.
245 static gcry_mpi_t my_offset;
248 * Map of `struct BobServiceSession`, by session keys.
250 static struct GNUNET_CONTAINER_MultiHashMap *client_sessions;
253 * Map of `struct CadetIncomingSession`, by session keys.
255 static struct GNUNET_CONTAINER_MultiHashMap *cadet_sessions;
258 * Handle to the CADET service.
260 static struct GNUNET_CADET_Handle *my_cadet;
263 * Certain events (callbacks for server & cadet operations) must not
264 * be queued after shutdown.
266 static int do_shutdown;
271 * Finds a not terminated client session in the respective map based on
274 * @param key the session key we want to search for
275 * @return the matching session, or NULL for none
277 static struct BobServiceSession *
278 find_matching_client_session (const struct GNUNET_HashCode *key)
280 return GNUNET_CONTAINER_multihashmap_get (client_sessions,
286 * Finds a CADET session in the respective map based on session key.
288 * @param key the session key we want to search for
289 * @return the matching session, or NULL for none
291 static struct CadetIncomingSession *
292 find_matching_cadet_session (const struct GNUNET_HashCode *key)
294 return GNUNET_CONTAINER_multihashmap_get (cadet_sessions,
300 * Destroy session state, we are done with it.
302 * @param session the session to free elements from
305 destroy_cadet_session (struct CadetIncomingSession *s);
309 * Destroy session state, we are done with it.
311 * @param session the session to free elements from
314 destroy_service_session (struct BobServiceSession *s)
316 struct CadetIncomingSession *in;
319 if (GNUNET_YES == s->in_destroy)
321 s->in_destroy = GNUNET_YES;
322 if (NULL != (in = s->cadet))
325 destroy_cadet_session (in);
327 if (NULL != s->client_mq)
329 GNUNET_MQ_destroy (s->client_mq);
332 if (NULL != s->client)
334 GNUNET_SERVER_client_disconnect (s->client);
337 GNUNET_assert (GNUNET_YES ==
338 GNUNET_CONTAINER_multihashmap_remove (client_sessions,
341 if (NULL != s->intersected_elements)
343 /* FIXME: free elements */
344 GNUNET_CONTAINER_multihashmap_destroy (s->intersected_elements);
345 s->intersected_elements = NULL;
347 if (NULL != s->intersection_op)
349 GNUNET_SET_operation_cancel (s->intersection_op);
350 s->intersection_op = NULL;
352 if (NULL != s->intersection_set)
354 GNUNET_SET_destroy (s->intersection_set);
355 s->intersection_set = NULL;
359 GNUNET_free (s->e_a);
362 if (NULL != s->sorted_elements)
364 for (i=0;i<s->used_element_count;i++)
365 gcry_mpi_release (s->sorted_elements[i].value);
366 GNUNET_free (s->sorted_elements);
367 s->sorted_elements = NULL;
374 if (NULL != s->r_prime)
376 GNUNET_free (s->r_prime);
379 if (NULL != s->product)
381 gcry_mpi_release (s->product);
389 * Destroy incoming CADET session state, we are done with it.
391 * @param in the session to free elements from
394 destroy_cadet_session (struct CadetIncomingSession *in)
396 struct BobServiceSession *s;
398 if (GNUNET_YES == in->in_destroy)
400 in->in_destroy = GNUNET_YES;
401 if (NULL != (s = in->s))
404 destroy_service_session (s);
406 if (GNUNET_YES == in->in_map)
408 GNUNET_assert (GNUNET_YES ==
409 GNUNET_CONTAINER_multihashmap_remove (cadet_sessions,
412 in->in_map = GNUNET_NO;
414 if (NULL != in->cadet_mq)
416 GNUNET_MQ_destroy (in->cadet_mq);
419 if (NULL != in->channel)
421 GNUNET_CADET_channel_destroy (in->channel);
429 * Notify the client that the session has succeeded or failed. This
430 * message gets sent to Bob's client if the operation completed or
431 * Alice disconnected.
433 * @param session the associated client session to fail or succeed
436 prepare_client_end_notification (struct BobServiceSession *session)
438 struct ClientResponseMessage *msg;
439 struct GNUNET_MQ_Envelope *e;
441 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
442 "Sending session-end notification with status %d to client for session %s\n",
444 GNUNET_h2s (&session->session_id));
445 e = GNUNET_MQ_msg (msg,
446 GNUNET_MESSAGE_TYPE_SCALARPRODUCT_RESULT);
448 msg->product_length = htonl (0);
449 msg->status = htonl (session->active);
450 GNUNET_MQ_send (session->client_mq,
456 * Function called whenever a channel is destroyed. Should clean up
457 * any associated state.
459 * It must NOT call #GNUNET_CADET_channel_destroy() on the channel.
461 * @param cls closure (set from #GNUNET_CADET_connect())
462 * @param channel connection to the other end (henceforth invalid)
463 * @param channel_ctx place where local state associated
464 * with the channel is stored
467 cb_channel_destruction (void *cls,
468 const struct GNUNET_CADET_Channel *channel,
471 struct CadetIncomingSession *in = channel_ctx;
472 struct BobServiceSession *s;
474 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
475 "Peer disconnected, terminating session %s with peer %s\n",
476 GNUNET_h2s (&in->session_id),
477 GNUNET_i2s (&in->peer));
479 if (NULL != (s = in->s))
481 if (GNUNET_YES == s->active)
483 s->active = GNUNET_SYSERR;
484 prepare_client_end_notification (s);
487 destroy_cadet_session (in);
492 * MQ finished giving our last message to CADET, now notify
493 * the client that we are finished.
496 bob_cadet_done_cb (void *cls)
498 struct BobServiceSession *session = cls;
500 session->active = GNUNET_NO; /* that means, done */
501 prepare_client_end_notification (session);
506 * Maximum count of elements we can put into a multipart message
508 #define ELEMENT_CAPACITY ((GNUNET_SERVER_MAX_MESSAGE_SIZE - 1 - sizeof (struct MultipartMessage)) / sizeof (struct GNUNET_CRYPTO_PaillierCiphertext))
512 * Send a multipart chunk of a service response from Bob to Alice.
513 * This element only contains the two permutations of R, R'.
515 * @param s the associated service session
518 transmit_bobs_cryptodata_message_multipart (struct BobServiceSession *s)
520 struct GNUNET_CRYPTO_PaillierCiphertext *payload;
521 struct MultipartMessage *msg;
522 struct GNUNET_MQ_Envelope *e;
527 while (s->transferred_element_count != s->used_element_count)
529 todo_count = s->used_element_count - s->transferred_element_count;
530 if (todo_count > ELEMENT_CAPACITY / 2)
531 todo_count = ELEMENT_CAPACITY / 2;
533 e = GNUNET_MQ_msg_extra (msg,
534 todo_count * sizeof (struct GNUNET_CRYPTO_PaillierCiphertext) * 2,
535 GNUNET_MESSAGE_TYPE_SCALARPRODUCT_BOB_CRYPTODATA_MULTIPART);
536 msg->contained_element_count = htonl (todo_count);
537 payload = (struct GNUNET_CRYPTO_PaillierCiphertext *) &msg[1];
538 for (i = s->transferred_element_count, j = 0; i < s->transferred_element_count + todo_count; i++)
540 //r[i][p] and r[i][q]
541 memcpy (&payload[j++],
543 sizeof (struct GNUNET_CRYPTO_PaillierCiphertext));
544 memcpy (&payload[j++],
546 sizeof (struct GNUNET_CRYPTO_PaillierCiphertext));
548 s->transferred_element_count += todo_count;
549 if (s->transferred_element_count == s->used_element_count)
550 GNUNET_MQ_notify_sent (e,
553 GNUNET_MQ_send (s->cadet->cadet_mq,
560 * Bob generates the response message to be sent to Alice after
561 * computing the values (1), (2), S and S'.
563 * (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)})$
564 * (2)[]: $E_A(a_{pi'(i)}) times E_A(- r_{pi'(i)}) &= E_A(a_{pi'(i)} - r_{pi'(i)})$
565 * S: $S := E_A(sum (r_i + b_i)^2)$
566 * S': $S' := E_A(sum r_i^2)$
568 * @param s the associated requesting session with Alice
571 transmit_bobs_cryptodata_message (struct BobServiceSession *s)
573 struct ServiceResponseMessage *msg;
574 struct GNUNET_MQ_Envelope *e;
575 struct GNUNET_CRYPTO_PaillierCiphertext *payload;
578 s->transferred_element_count = (GNUNET_SERVER_MAX_MESSAGE_SIZE - 1 - sizeof (struct ServiceResponseMessage)) /
579 (sizeof (struct GNUNET_CRYPTO_PaillierCiphertext) * 2) - 2;
580 if (s->transferred_element_count > s->used_element_count)
581 s->transferred_element_count = s->used_element_count;
583 e = GNUNET_MQ_msg_extra (msg,
584 (2 + s->transferred_element_count * 2)
585 * sizeof (struct GNUNET_CRYPTO_PaillierCiphertext),
586 GNUNET_MESSAGE_TYPE_SCALARPRODUCT_BOB_CRYPTODATA);
587 msg->total_element_count = htonl (s->total);
588 msg->used_element_count = htonl (s->used_element_count);
589 msg->contained_element_count = htonl (s->transferred_element_count);
590 msg->key = s->session_id;
592 payload = (struct GNUNET_CRYPTO_PaillierCiphertext *) &msg[1];
595 sizeof (struct GNUNET_CRYPTO_PaillierCiphertext));
598 sizeof (struct GNUNET_CRYPTO_PaillierCiphertext));
600 payload = &payload[2];
602 for (i = 0; i < s->transferred_element_count; i++)
604 //k[i][p] and k[i][q]
605 memcpy (&payload[i * 2],
607 sizeof (struct GNUNET_CRYPTO_PaillierCiphertext));
608 memcpy (&payload[i * 2 + 1],
610 sizeof (struct GNUNET_CRYPTO_PaillierCiphertext));
612 if (s->transferred_element_count == s->used_element_count)
613 GNUNET_MQ_notify_sent (e,
616 GNUNET_MQ_send (s->cadet->cadet_mq,
618 transmit_bobs_cryptodata_message_multipart (s);
623 * Computes the square sum over a vector of a given length.
625 * @param vector the vector to compute over
626 * @param length the length of the vector
627 * @return an MPI value containing the calculated sum, never NULL
630 compute_square_sum (const gcry_mpi_t *vector,
637 GNUNET_assert (NULL != (sum = gcry_mpi_new (0)));
638 GNUNET_assert (NULL != (elem = gcry_mpi_new (0)));
639 for (i = 0; i < length; i++)
641 gcry_mpi_mul (elem, vector[i], vector[i]);
642 gcry_mpi_add (sum, sum, elem);
644 gcry_mpi_release (elem);
651 * (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)})$
652 * (2)[]: $E_A(a_{pi'(i)}) otimes E_A(- r_{pi'(i)}) &= E_A(a_{pi'(i)} - r_{pi'(i)})$
653 * S: $S := E_A(sum (r_i + b_i)^2)$
654 * S': $S' := E_A(sum r_i^2)$
656 * @param request the requesting session + bob's requesting peer
659 compute_service_response (struct BobServiceSession *session)
667 const struct MpiElement *b;
668 struct GNUNET_CRYPTO_PaillierCiphertext *a;
669 struct GNUNET_CRYPTO_PaillierCiphertext *r;
670 struct GNUNET_CRYPTO_PaillierCiphertext *r_prime;
672 count = session->used_element_count;
674 b = session->sorted_elements;
675 q = GNUNET_CRYPTO_random_permute (GNUNET_CRYPTO_QUALITY_WEAK,
677 p = GNUNET_CRYPTO_random_permute (GNUNET_CRYPTO_QUALITY_WEAK,
679 rand = GNUNET_malloc (sizeof (gcry_mpi_t) * count);
680 for (i = 0; i < count; i++)
681 GNUNET_assert (NULL != (rand[i] = gcry_mpi_new (0)));
682 r = GNUNET_malloc (sizeof (struct GNUNET_CRYPTO_PaillierCiphertext) * count);
683 r_prime = GNUNET_malloc (sizeof (struct GNUNET_CRYPTO_PaillierCiphertext) * count);
685 for (i = 0; i < count; i++)
689 svalue = (int32_t) GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_WEAK,
691 // long to gcry_mpi_t
693 gcry_mpi_sub_ui (rand[i],
697 rand[i] = gcry_mpi_set_ui (rand[i], svalue);
700 tmp = gcry_mpi_new (0);
701 // encrypt the element
702 // for the sake of readability I decided to have dedicated permutation
703 // vectors, which get rid of all the lookups in p/q.
704 // however, ap/aq are not absolutely necessary but are just abstraction
705 // Calculate Kp = E(S + a_pi) (+) E(S - r_pi - b_pi)
706 for (i = 0; i < count; i++)
708 // E(S - r_pi - b_pi)
709 gcry_mpi_sub (tmp, my_offset, rand[p[i]]);
710 gcry_mpi_sub (tmp, tmp, b[p[i]].value);
711 GNUNET_CRYPTO_paillier_encrypt (&session->cadet->remote_pubkey,
716 // E(S - r_pi - b_pi) * E(S + a_pi) == E(2*S + a - r - b)
717 GNUNET_CRYPTO_paillier_hom_add (&session->cadet->remote_pubkey,
723 // Calculate Kq = E(S + a_qi) (+) E(S - r_qi)
724 for (i = 0; i < count; i++)
727 gcry_mpi_sub (tmp, my_offset, rand[q[i]]);
728 GNUNET_assert (2 == GNUNET_CRYPTO_paillier_encrypt (&session->cadet->remote_pubkey,
733 // E(S - r_qi) * E(S + a_qi) == E(2*S + a_qi - r_qi)
734 GNUNET_assert (1 == GNUNET_CRYPTO_paillier_hom_add (&session->cadet->remote_pubkey,
740 // Calculate S' = E(SUM( r_i^2 ))
741 tmp = compute_square_sum (rand, count);
742 GNUNET_CRYPTO_paillier_encrypt (&session->cadet->remote_pubkey,
747 // Calculate S = E(SUM( (r_i + b_i)^2 ))
748 for (i = 0; i < count; i++)
749 gcry_mpi_add (rand[i], rand[i], b[i].value);
750 tmp = compute_square_sum (rand, count);
751 GNUNET_CRYPTO_paillier_encrypt (&session->cadet->remote_pubkey,
757 session->r_prime = r_prime;
759 // release rand, b and a
760 for (i = 0; i < count; i++)
761 gcry_mpi_release (rand[i]);
762 gcry_mpi_release (tmp);
763 GNUNET_free (session->e_a);
769 // copy the r[], r_prime[], S and Stick into a new message, prepare_service_response frees these
777 * Iterator to copy over messages from the hash map
778 * into an array for sorting.
780 * @param cls the `struct AliceServiceSession *`
781 * @param key the key (unused)
782 * @param value the `struct GNUNET_SCALARPRODUCT_Element *`
785 copy_element_cb (void *cls,
786 const struct GNUNET_HashCode *key,
789 struct BobServiceSession *s = cls;
790 struct GNUNET_SCALARPRODUCT_Element *e = value;
794 mval = gcry_mpi_new (0);
795 val = (int64_t) GNUNET_ntohll (e->value);
797 gcry_mpi_sub_ui (mval, mval, -val);
799 gcry_mpi_add_ui (mval, mval, val);
800 s->sorted_elements [s->used_element_count].value = mval;
801 s->sorted_elements [s->used_element_count].key = &e->key;
802 s->used_element_count++;
808 * Compare two `struct MpiValue`s by key for sorting.
810 * @param a pointer to first `struct MpiValue *`
811 * @param b pointer to first `struct MpiValue *`
812 * @return -1 for a < b, 0 for a=b, 1 for a > b.
815 element_cmp (const void *a,
818 const struct MpiElement *ma = *(const struct MpiElement **) a;
819 const struct MpiElement *mb = *(const struct MpiElement **) b;
821 return GNUNET_CRYPTO_hash_cmp (ma->key,
827 * Intersection operation and receiving data via CADET from
828 * Alice are both done, compute and transmit our reply via
831 * @param s session to transmit reply for.
834 transmit_cryptographic_reply (struct BobServiceSession *s)
837 = GNUNET_malloc (GNUNET_CONTAINER_multihashmap_size (s->intersected_elements) *
838 sizeof (struct MpiElement));
839 s->used_element_count = 0;
840 GNUNET_CONTAINER_multihashmap_iterate (s->intersected_elements,
843 LOG (GNUNET_ERROR_TYPE_DEBUG,
844 "Finished intersection, %d items remain\n",
845 s->used_element_count);
846 qsort (s->intersected_elements,
847 s->used_element_count,
848 sizeof (struct MpiElement),
850 compute_service_response (s);
851 transmit_bobs_cryptodata_message (s);
856 * Handle a multipart-chunk of a request from another service to
857 * calculate a scalarproduct with us.
859 * @param cls closure (set from #GNUNET_CADET_connect)
860 * @param channel connection to the other end
861 * @param channel_ctx place to store local state associated with the @a channel
862 * @param message the actual message
863 * @return #GNUNET_OK to keep the connection open,
864 * #GNUNET_SYSERR to close it (signal serious error)
867 handle_alices_cryptodata_message (void *cls,
868 struct GNUNET_CADET_Channel *channel,
870 const struct GNUNET_MessageHeader *message)
872 struct CadetIncomingSession *in = *channel_ctx;
873 struct BobServiceSession *s;
874 const struct AliceCryptodataMessage *msg;
875 const struct GNUNET_CRYPTO_PaillierCiphertext *payload;
876 uint32_t contained_elements;
884 return GNUNET_SYSERR;
890 return GNUNET_SYSERR;
892 msize = ntohs (message->size);
893 if (msize <= sizeof (struct AliceCryptodataMessage))
896 return GNUNET_SYSERR;
898 msg = (const struct AliceCryptodataMessage *) message;
899 contained_elements = ntohl (msg->contained_element_count);
900 /* Our intersection may still be ongoing, but this is nevertheless
901 an upper bound on the required array size */
902 max = GNUNET_CONTAINER_multihashmap_size (s->intersected_elements);
903 msg_length = sizeof (struct AliceCryptodataMessage)
904 + contained_elements * sizeof (struct GNUNET_CRYPTO_PaillierCiphertext);
905 if ( (msize != msg_length) ||
906 (0 == contained_elements) ||
907 (contained_elements > UINT16_MAX) ||
908 (max < contained_elements + s->transferred_element_count) )
911 return GNUNET_SYSERR;
914 payload = (const struct GNUNET_CRYPTO_PaillierCiphertext *) &msg[1];
916 s->e_a = GNUNET_malloc (sizeof (struct GNUNET_CRYPTO_PaillierCiphertext) *
918 memcpy (&s->e_a[s->transferred_element_count],
920 sizeof (struct GNUNET_CRYPTO_PaillierCiphertext) * contained_elements);
921 s->transferred_element_count += contained_elements;
923 if ( (s->transferred_element_count == max) &&
924 (NULL == s->intersection_op) )
926 /* intersection has finished also on our side, and
927 we got the full set, so we can proceed with the
929 transmit_cryptographic_reply (s);
936 * Callback for set operation results. Called for each element
937 * that needs to be removed from the result set.
939 * @param cls closure with the `struct BobServiceSession`
940 * @param element a result element, only valid if status is #GNUNET_SET_STATUS_OK
941 * @param status what has happened with the set intersection?
944 cb_intersection_element_removed (void *cls,
945 const struct GNUNET_SET_Element *element,
946 enum GNUNET_SET_Status status)
948 struct BobServiceSession *s = cls;
949 struct GNUNET_SCALARPRODUCT_Element *se;
953 case GNUNET_SET_STATUS_OK:
954 /* this element has been removed from the set */
955 se = GNUNET_CONTAINER_multihashmap_get (s->intersected_elements,
957 LOG (GNUNET_ERROR_TYPE_DEBUG,
958 "Removed element with key %s and value %lld\n",
959 GNUNET_h2s (&se->key),
960 (long long) GNUNET_ntohll (se->value));
961 GNUNET_assert (GNUNET_YES ==
962 GNUNET_CONTAINER_multihashmap_remove (s->intersected_elements,
967 case GNUNET_SET_STATUS_DONE:
968 s->intersection_op = NULL;
969 s->intersection_set = NULL;
970 if (s->transferred_element_count ==
971 GNUNET_CONTAINER_multihashmap_size (s->intersected_elements))
973 /* CADET transmission from Alice is also already done,
974 start with our own reply */
975 transmit_cryptographic_reply (s);
978 case GNUNET_SET_STATUS_HALF_DONE:
979 /* unexpected for intersection */
982 case GNUNET_SET_STATUS_FAILURE:
983 /* unhandled status code */
984 LOG (GNUNET_ERROR_TYPE_DEBUG,
985 "Set intersection failed!\n");
986 s->intersection_op = NULL;
987 s->intersection_set = NULL;
988 s->active = GNUNET_SYSERR;
989 prepare_client_end_notification (s);
999 * We've paired up a client session with an incoming CADET request.
1000 * Initiate set intersection work.
1002 * @param s client session to start intersection for
1005 start_intersection (struct BobServiceSession *s)
1007 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1008 "Got session with key %s and a matching element set, processing.\n",
1009 GNUNET_h2s (&s->session_id));
1012 = GNUNET_SET_prepare (&s->cadet->peer,
1015 GNUNET_SET_RESULT_REMOVED,
1016 &cb_intersection_element_removed,
1018 GNUNET_SET_commit (s->intersection_op,
1019 s->intersection_set);
1024 * Handle a request from Alice to calculate a scalarproduct with us (Bob).
1026 * @param cls closure (set from #GNUNET_CADET_connect)
1027 * @param channel connection to the other end
1028 * @param channel_ctx place to store the `struct CadetIncomingSession *`
1029 * @param message the actual message
1030 * @return #GNUNET_OK to keep the connection open,
1031 * #GNUNET_SYSERR to close it (signal serious error)
1034 handle_alices_computation_request (void *cls,
1035 struct GNUNET_CADET_Channel *channel,
1037 const struct GNUNET_MessageHeader *message)
1039 struct CadetIncomingSession *in = *channel_ctx;
1040 struct BobServiceSession *s;
1041 const struct ServiceRequestMessage *msg;
1043 if (ntohs (message->size) != sizeof (struct ServiceRequestMessage))
1045 GNUNET_break_op (0);
1046 return GNUNET_SYSERR;
1048 msg = (const struct ServiceRequestMessage *) message;
1049 if (GNUNET_YES == in->in_map)
1051 GNUNET_break_op (0);
1052 return GNUNET_SYSERR;
1054 if (NULL != find_matching_cadet_session (&msg->session_id))
1056 /* not unique, got one like this already */
1057 GNUNET_break_op (0);
1058 return GNUNET_SYSERR;
1060 in->session_id = msg->session_id;
1061 in->remote_pubkey = msg->public_key;
1062 GNUNET_assert (GNUNET_YES ==
1063 GNUNET_CONTAINER_multihashmap_put (cadet_sessions,
1066 GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY));
1067 s = find_matching_client_session (&in->session_id);
1070 /* no client waiting for this request, wait for client */
1073 GNUNET_assert (NULL == s->cadet);
1077 if (s->transferred_element_count == s->total)
1078 start_intersection (s);
1084 * Function called for inbound channels on Bob's end. Does some
1085 * preliminary initialization, more happens after we get Alice's first
1088 * @param cls closure
1089 * @param channel new handle to the channel
1090 * @param initiator peer that started the channel
1091 * @param port unused
1092 * @param options unused
1093 * @return session associated with the channel
1096 cb_channel_incoming (void *cls,
1097 struct GNUNET_CADET_Channel *channel,
1098 const struct GNUNET_PeerIdentity *initiator,
1100 enum GNUNET_CADET_ChannelOption options)
1102 struct CadetIncomingSession *in;
1104 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1105 "New incoming channel from peer %s.\n",
1106 GNUNET_i2s (initiator));
1107 in = GNUNET_new (struct CadetIncomingSession);
1108 in->peer = *initiator;
1109 in->channel = channel;
1115 * We're receiving additional set data. Add it to our
1116 * set and if we are done, initiate the transaction.
1118 * @param cls closure
1119 * @param client identification of the client
1120 * @param message the actual message
1123 GSS_handle_bob_client_message_multipart (void *cls,
1124 struct GNUNET_SERVER_Client *client,
1125 const struct GNUNET_MessageHeader *message)
1127 const struct ComputationMultipartMessage * msg;
1128 struct BobServiceSession *s;
1129 uint32_t contained_count;
1130 const struct GNUNET_SCALARPRODUCT_Element *elements;
1133 struct GNUNET_SET_Element set_elem;
1134 struct GNUNET_SCALARPRODUCT_Element *elem;
1136 s = GNUNET_SERVER_client_get_user_context (client,
1137 struct BobServiceSession);
1140 /* session needs to already exist */
1142 GNUNET_SERVER_receive_done (client,
1146 msize = ntohs (message->size);
1147 if (msize < sizeof (struct ComputationMultipartMessage))
1150 GNUNET_SERVER_receive_done (client,
1154 msg = (const struct ComputationMultipartMessage *) message;
1155 contained_count = ntohl (msg->element_count_contained);
1157 if ( (msize != (sizeof (struct ComputationMultipartMessage) +
1158 contained_count * sizeof (struct GNUNET_SCALARPRODUCT_Element))) ||
1159 (0 == contained_count) ||
1160 (UINT16_MAX < contained_count) ||
1161 (s->total == s->transferred_element_count) ||
1162 (s->total < s->transferred_element_count + contained_count) )
1164 GNUNET_break_op (0);
1165 GNUNET_SERVER_receive_done (client,
1169 elements = (const struct GNUNET_SCALARPRODUCT_Element *) &msg[1];
1170 for (i = 0; i < contained_count; i++)
1172 if (0 == GNUNET_ntohll (elements[i].value))
1174 elem = GNUNET_new (struct GNUNET_SCALARPRODUCT_Element);
1177 sizeof (struct GNUNET_SCALARPRODUCT_Element));
1178 if (GNUNET_SYSERR ==
1179 GNUNET_CONTAINER_multihashmap_put (s->intersected_elements,
1182 GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY))
1188 set_elem.data = &elem->key;
1189 set_elem.size = sizeof (elem->key);
1190 set_elem.element_type = 0;
1191 GNUNET_SET_add_element (s->intersection_set,
1195 s->transferred_element_count += contained_count;
1196 GNUNET_SERVER_receive_done (client,
1198 if (s->total != s->transferred_element_count)
1203 if (NULL == s->cadet)
1205 /* no Alice waiting for this request, wait for Alice */
1208 start_intersection (s);
1213 * Handler for Bob's a client request message. Bob is in the response
1214 * role, keep the values + session and waiting for a matching session
1215 * or process a waiting request from Alice.
1217 * @param cls closure
1218 * @param client identification of the client
1219 * @param message the actual message
1222 GSS_handle_bob_client_message (void *cls,
1223 struct GNUNET_SERVER_Client *client,
1224 const struct GNUNET_MessageHeader *message)
1226 const struct BobComputationMessage *msg;
1227 struct BobServiceSession *s;
1228 struct CadetIncomingSession *in;
1229 uint32_t contained_count;
1230 uint32_t total_count;
1231 const struct GNUNET_SCALARPRODUCT_Element *elements;
1233 struct GNUNET_SET_Element set_elem;
1234 struct GNUNET_SCALARPRODUCT_Element *elem;
1237 s = GNUNET_SERVER_client_get_user_context (client,
1238 struct BobServiceSession);
1241 /* only one concurrent session per client connection allowed,
1242 simplifies logic a lot... */
1244 GNUNET_SERVER_receive_done (client,
1248 msize = ntohs (message->size);
1249 if (msize < sizeof (struct BobComputationMessage))
1252 GNUNET_SERVER_receive_done (client,
1256 msg = (const struct BobComputationMessage *) message;
1257 total_count = ntohl (msg->element_count_total);
1258 contained_count = ntohl (msg->element_count_contained);
1259 if ( (0 == total_count) ||
1260 (0 == contained_count) ||
1261 (UINT16_MAX < contained_count) ||
1262 (msize != (sizeof (struct BobComputationMessage) +
1263 contained_count * sizeof (struct GNUNET_SCALARPRODUCT_Element))) )
1265 GNUNET_break_op (0);
1266 GNUNET_SERVER_receive_done (client,
1270 if (NULL != find_matching_client_session (&msg->session_key))
1273 GNUNET_SERVER_receive_done (client,
1278 s = GNUNET_new (struct BobServiceSession);
1279 s->active = GNUNET_YES;
1281 s->client_mq = GNUNET_MQ_queue_for_server_client (client);
1282 s->total = total_count;
1283 s->transferred_element_count = contained_count;
1284 s->session_id = msg->session_key;
1285 GNUNET_break (GNUNET_YES ==
1286 GNUNET_CONTAINER_multihashmap_put (client_sessions,
1289 GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY));
1290 elements = (const struct GNUNET_SCALARPRODUCT_Element *) &msg[1];
1291 s->intersected_elements = GNUNET_CONTAINER_multihashmap_create (s->total,
1293 s->intersection_set = GNUNET_SET_create (cfg,
1294 GNUNET_SET_OPERATION_INTERSECTION);
1295 for (i = 0; i < contained_count; i++)
1297 if (0 == GNUNET_ntohll (elements[i].value))
1299 elem = GNUNET_new (struct GNUNET_SCALARPRODUCT_Element);
1302 sizeof (struct GNUNET_SCALARPRODUCT_Element));
1303 if (GNUNET_SYSERR ==
1304 GNUNET_CONTAINER_multihashmap_put (s->intersected_elements,
1307 GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY))
1313 set_elem.data = &elem->key;
1314 set_elem.size = sizeof (elem->key);
1315 set_elem.element_type = 0;
1316 GNUNET_SET_add_element (s->intersection_set,
1319 s->used_element_count++;
1321 GNUNET_SERVER_client_set_user_context (client,
1323 GNUNET_SERVER_receive_done (client,
1325 if (s->total != s->transferred_element_count)
1330 in = find_matching_cadet_session (&s->session_id);
1333 /* nothing yet, wait for Alice */
1336 GNUNET_assert (NULL == in->s);
1340 start_intersection (s);
1345 * Task run during shutdown.
1351 shutdown_task (void *cls,
1352 const struct GNUNET_SCHEDULER_TaskContext *tc)
1354 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1355 "Shutting down, initiating cleanup.\n");
1356 do_shutdown = GNUNET_YES;
1357 // FIXME: is there a need to shutdown active sessions?
1358 if (NULL != my_cadet)
1360 GNUNET_CADET_disconnect (my_cadet);
1363 GNUNET_CONTAINER_multihashmap_destroy (client_sessions);
1364 client_sessions = NULL;
1365 GNUNET_CONTAINER_multihashmap_destroy (cadet_sessions);
1366 cadet_sessions = NULL;
1371 * A client disconnected.
1373 * Remove the associated session(s), release data structures
1374 * and cancel pending outgoing transmissions to the client.
1376 * @param cls closure, NULL
1377 * @param client identification of the client
1380 handle_client_disconnect (void *cls,
1381 struct GNUNET_SERVER_Client *client)
1383 struct BobServiceSession *s;
1387 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1388 "Client disconnected from us.\n",
1390 s = GNUNET_SERVER_client_get_user_context (client,
1391 struct BobServiceSession);
1395 destroy_service_session (s);
1400 * Initialization of the program and message handlers
1402 * @param cls closure
1403 * @param server the initialized server
1404 * @param c configuration to use
1408 struct GNUNET_SERVER_Handle *server,
1409 const struct GNUNET_CONFIGURATION_Handle *c)
1411 static const struct GNUNET_SERVER_MessageHandler server_handlers[] = {
1412 { &GSS_handle_bob_client_message, NULL,
1413 GNUNET_MESSAGE_TYPE_SCALARPRODUCT_CLIENT_TO_BOB,
1415 { &GSS_handle_bob_client_message_multipart, NULL,
1416 GNUNET_MESSAGE_TYPE_SCALARPRODUCT_CLIENT_MUTLIPART_BOB,
1420 static const struct GNUNET_CADET_MessageHandler cadet_handlers[] = {
1421 { &handle_alices_computation_request,
1422 GNUNET_MESSAGE_TYPE_SCALARPRODUCT_SESSION_INITIALIZATION,
1423 sizeof (struct ServiceRequestMessage) },
1424 { &handle_alices_cryptodata_message,
1425 GNUNET_MESSAGE_TYPE_SCALARPRODUCT_ALICE_CRYPTODATA,
1429 static const uint32_t ports[] = {
1430 GNUNET_APPLICATION_TYPE_SCALARPRODUCT,
1436 offset has to be sufficiently small to allow computation of:
1437 m1+m2 mod n == (S + a) + (S + b) mod n,
1438 if we have more complex operations, this factor needs to be lowered */
1439 my_offset = gcry_mpi_new (GNUNET_CRYPTO_PAILLIER_BITS / 3);
1440 gcry_mpi_set_bit (my_offset,
1441 GNUNET_CRYPTO_PAILLIER_BITS / 3);
1443 GNUNET_CRYPTO_paillier_create (&my_pubkey,
1445 GNUNET_SERVER_add_handlers (server,
1447 GNUNET_SERVER_disconnect_notify (server,
1448 &handle_client_disconnect,
1450 client_sessions = GNUNET_CONTAINER_multihashmap_create (128,
1452 cadet_sessions = GNUNET_CONTAINER_multihashmap_create (128,
1454 my_cadet = GNUNET_CADET_connect (cfg, NULL,
1455 &cb_channel_incoming,
1456 &cb_channel_destruction,
1459 if (NULL == my_cadet)
1461 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1462 _("Connect to CADET failed\n"));
1463 GNUNET_SCHEDULER_shutdown ();
1466 GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_FOREVER_REL,
1473 * The main function for the scalarproduct service.
1475 * @param argc number of arguments from the command line
1476 * @param argv command line arguments
1477 * @return 0 ok, 1 on error
1483 return (GNUNET_OK ==
1484 GNUNET_SERVICE_run (argc, argv,
1485 "scalarproduct-bob",
1486 GNUNET_SERVICE_OPTION_NONE,
1487 &run, NULL)) ? 0 : 1;
1490 /* end of gnunet-service-scalarproduct_bob.c */