2 This file is part of GNUnet.
3 Copyright (C) 2013, 2014, 2016 GNUnet e.V.
5 GNUnet is free software: you can redistribute it and/or modify it
6 under the terms of the GNU Affero General Public License as published
7 by the Free Software Foundation, either version 3 of the License,
8 or (at your option) any later version.
10 GNUnet is distributed in the hope that it will be useful, but
11 WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 Affero General Public License for more details.
15 You should have received a copy of the GNU Affero General Public License
16 along with this program. If not, see <http://www.gnu.org/licenses/>.
18 SPDX-License-Identifier: AGPL3.0-or-later
21 * @file scalarproduct/gnunet-service-scalarproduct_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 * A scalarproduct session which tracks an offer for a
63 * multiplication service by a local client.
65 struct BobServiceSession
68 * (hopefully) unique transaction ID
70 struct GNUNET_HashCode session_id;
73 * The client this request is related to.
75 struct GNUNET_SERVICE_Client *client;
78 * Client message queue.
80 struct GNUNET_MQ_Handle *client_mq;
83 * All non-0-value'd elements transmitted to us.
85 struct GNUNET_CONTAINER_MultiHashMap *intersected_elements;
88 * Set of elements for which we will be conducting an intersection.
89 * The resulting elements are then used for computing the scalar product.
91 struct GNUNET_SET_Handle *intersection_set;
94 * Set of elements for which will conduction an intersection.
95 * the resulting elements are then used for computing the scalar product.
97 struct GNUNET_SET_OperationHandle *intersection_op;
100 * CADET port we are listening on.
102 struct GNUNET_CADET_Port *port;
107 struct MpiElement *sorted_elements;
110 * E(ai)(Bob) after applying the mask
112 struct GNUNET_CRYPTO_PaillierCiphertext *e_a;
115 * Bob's permutation p of R
117 struct GNUNET_CRYPTO_PaillierCiphertext *r;
120 * Bob's permutation q of R
122 struct GNUNET_CRYPTO_PaillierCiphertext *r_prime;
127 struct GNUNET_CRYPTO_PaillierCiphertext s;
132 struct GNUNET_CRYPTO_PaillierCiphertext s_prime;
135 * Handle for our associated incoming CADET session, or NULL
136 * if we have not gotten one yet.
138 struct CadetIncomingSession *cadet;
141 * How many elements will be supplied in total from the client.
146 * Already transferred elements (received) for multipart
147 * messages from client. Always less than @e total.
149 uint32_t client_received_element_count;
152 * How many elements actually are used for the scalar product.
153 * Size of the arrays in @e r and @e r_prime. Also sometimes
154 * used as an index into the arrays during construction.
156 uint32_t used_element_count;
159 * Counts the number of values received from Alice by us.
160 * Always less than @e used_element_count.
162 uint32_t cadet_received_element_count;
165 * Counts the number of values transmitted from us to Alice.
166 * Always less than @e used_element_count.
168 uint32_t cadet_transmitted_element_count;
171 * State of this session. In
172 * #GNUNET_SCALARPRODUCT_STATUS_ACTIVE while operation is
173 * ongoing, afterwards in #GNUNET_SCALARPRODUCT_STATUS_SUCCESS or
174 * #GNUNET_SCALARPRODUCT_STATUS_FAILURE.
176 enum GNUNET_SCALARPRODUCT_ResponseStatus status;
179 * Are we already in #destroy_service_session()?
186 struct GNUNET_CADET_Channel *channel;
189 * Originator's peer identity. (Only for diagnostics.)
191 struct GNUNET_PeerIdentity peer;
194 * Public key of the remote service.
196 struct GNUNET_CRYPTO_PaillierPublicKey remote_pubkey;
199 * The message queue for this channel.
201 struct GNUNET_MQ_Handle *cadet_mq;
206 * GNUnet configuration handle
208 static const struct GNUNET_CONFIGURATION_Handle *cfg;
211 * Service's own public key
213 static struct GNUNET_CRYPTO_PaillierPublicKey my_pubkey;
216 * Service's own private key
218 static struct GNUNET_CRYPTO_PaillierPrivateKey my_privkey;
221 * Service's offset for values that could possibly be negative but are plaintext for encryption.
223 static gcry_mpi_t my_offset;
226 * Handle to the CADET service.
228 static struct GNUNET_CADET_Handle *my_cadet;
232 * Callback used to free the elements in the map.
235 * @param key key of the element
236 * @param value the value to free
239 free_element_cb (void *cls,
240 const struct GNUNET_HashCode *key,
243 struct GNUNET_SCALARPRODUCT_Element *element = value;
245 GNUNET_free (element);
251 * Destroy session state, we are done with it.
253 * @param session the session to free elements from
256 destroy_service_session (struct BobServiceSession *s)
260 if (GNUNET_YES == s->in_destroy)
262 s->in_destroy = GNUNET_YES;
263 if (NULL != s->client)
265 struct GNUNET_SERVICE_Client *c = s->client;
268 GNUNET_SERVICE_client_drop (c);
270 if (NULL != s->intersected_elements)
272 GNUNET_CONTAINER_multihashmap_iterate (s->intersected_elements,
275 GNUNET_CONTAINER_multihashmap_destroy (s->intersected_elements);
276 s->intersected_elements = NULL;
278 if (NULL != s->intersection_op)
280 GNUNET_SET_operation_cancel (s->intersection_op);
281 s->intersection_op = NULL;
283 if (NULL != s->intersection_set)
285 GNUNET_SET_destroy (s->intersection_set);
286 s->intersection_set = NULL;
290 GNUNET_free (s->e_a);
293 if (NULL != s->sorted_elements)
295 for (i = 0; i < s->used_element_count; i++)
296 gcry_mpi_release (s->sorted_elements[i].value);
297 GNUNET_free (s->sorted_elements);
298 s->sorted_elements = NULL;
305 if (NULL != s->r_prime)
307 GNUNET_free (s->r_prime);
312 GNUNET_CADET_close_port (s->port);
315 if (NULL != s->channel)
317 GNUNET_CADET_channel_destroy (s->channel);
325 * Notify the client that the session has succeeded or failed. This
326 * message gets sent to Bob's client if the operation completed or
327 * Alice disconnected.
329 * @param session the associated client session to fail or succeed
332 prepare_client_end_notification (struct BobServiceSession *session)
334 struct ClientResponseMessage *msg;
335 struct GNUNET_MQ_Envelope *e;
337 if (NULL == session->client_mq)
338 return; /* no client left to be notified */
339 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
340 "Sending session-end notification with status %d to client for session %s\n",
342 GNUNET_h2s (&session->session_id));
343 e = GNUNET_MQ_msg (msg,
344 GNUNET_MESSAGE_TYPE_SCALARPRODUCT_RESULT);
346 msg->product_length = htonl (0);
347 msg->status = htonl (session->status);
348 GNUNET_MQ_send (session->client_mq,
354 * Function called whenever a channel is destroyed. Should clean up
355 * any associated state.
357 * It must NOT call #GNUNET_CADET_channel_destroy() on the channel.
359 * @param cls the `struct BobServiceSession`
360 * @param channel connection to the other end (henceforth invalid)
363 cb_channel_destruction (void *cls,
364 const struct GNUNET_CADET_Channel *channel)
366 struct BobServiceSession *s = cls;
368 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
369 "Peer disconnected, terminating session %s with peer %s\n",
370 GNUNET_h2s (&s->session_id),
371 GNUNET_i2s (&s->peer));
372 if (GNUNET_SCALARPRODUCT_STATUS_ACTIVE == s->status)
374 s->status = GNUNET_SCALARPRODUCT_STATUS_FAILURE;
375 prepare_client_end_notification (s);
378 destroy_service_session (s);
383 * MQ finished giving our last message to CADET, now notify
384 * the client that we are finished.
387 bob_cadet_done_cb (void *cls)
389 struct BobServiceSession *session = cls;
391 session->status = GNUNET_SCALARPRODUCT_STATUS_SUCCESS;
392 prepare_client_end_notification (session);
397 * Maximum count of elements we can put into a multipart message
399 #define ELEMENT_CAPACITY ((GNUNET_CONSTANTS_MAX_CADET_MESSAGE_SIZE - 1 \
400 - sizeof(struct BobCryptodataMultipartMessage)) \
402 GNUNET_CRYPTO_PaillierCiphertext))
406 * Send a multipart chunk of a service response from Bob to Alice.
407 * This element only contains the two permutations of R, R'.
409 * @param s the associated service session
412 transmit_bobs_cryptodata_message_multipart (struct BobServiceSession *s)
414 struct GNUNET_CRYPTO_PaillierCiphertext *payload;
415 struct BobCryptodataMultipartMessage *msg;
416 struct GNUNET_MQ_Envelope *e;
421 while (s->cadet_transmitted_element_count != s->used_element_count)
423 todo_count = s->used_element_count - s->cadet_transmitted_element_count;
424 if (todo_count > ELEMENT_CAPACITY / 2)
425 todo_count = ELEMENT_CAPACITY / 2;
427 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
428 "Sending %u additional crypto values to Alice\n",
429 (unsigned int) todo_count);
430 e = GNUNET_MQ_msg_extra (msg,
431 todo_count * sizeof(struct
432 GNUNET_CRYPTO_PaillierCiphertext)
434 GNUNET_MESSAGE_TYPE_SCALARPRODUCT_BOB_CRYPTODATA_MULTIPART);
435 msg->contained_element_count = htonl (todo_count);
436 payload = (struct GNUNET_CRYPTO_PaillierCiphertext *) &msg[1];
437 for (i = s->cadet_transmitted_element_count, j = 0; i <
438 s->cadet_transmitted_element_count + todo_count; i++)
440 // r[i][p] and r[i][q]
441 GNUNET_memcpy (&payload[j++],
443 sizeof(struct GNUNET_CRYPTO_PaillierCiphertext));
444 GNUNET_memcpy (&payload[j++],
446 sizeof(struct GNUNET_CRYPTO_PaillierCiphertext));
448 s->cadet_transmitted_element_count += todo_count;
449 if (s->cadet_transmitted_element_count == s->used_element_count)
450 GNUNET_MQ_notify_sent (e,
453 GNUNET_MQ_send (s->cadet_mq,
456 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
457 "All values queued for Alice, Bob is done\n");
462 * Bob generates the response message to be sent to Alice after
463 * computing the values (1), (2), S and S'.
465 * (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)})$
466 * (2)[]: $E_A(a_{pi'(i)}) times E_A(- r_{pi'(i)}) &= E_A(a_{pi'(i)} - r_{pi'(i)})$
467 * S: $S := E_A(sum (r_i + b_i)^2)$
468 * S': $S' := E_A(sum r_i^2)$
470 * @param s the associated requesting session with Alice
473 transmit_bobs_cryptodata_message (struct BobServiceSession *s)
475 struct BobCryptodataMessage *msg;
476 struct GNUNET_MQ_Envelope *e;
477 struct GNUNET_CRYPTO_PaillierCiphertext *payload;
480 s->cadet_transmitted_element_count
481 = ((GNUNET_CONSTANTS_MAX_CADET_MESSAGE_SIZE - 1 - sizeof(struct
482 BobCryptodataMessage))
483 / sizeof(struct GNUNET_CRYPTO_PaillierCiphertext) / 2) - 1;
484 if (s->cadet_transmitted_element_count > s->used_element_count)
485 s->cadet_transmitted_element_count = s->used_element_count;
487 e = GNUNET_MQ_msg_extra (msg,
488 (2 + s->cadet_transmitted_element_count * 2)
489 * sizeof(struct GNUNET_CRYPTO_PaillierCiphertext),
490 GNUNET_MESSAGE_TYPE_SCALARPRODUCT_BOB_CRYPTODATA);
491 msg->contained_element_count = htonl (s->cadet_transmitted_element_count);
493 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
494 "Sending %u/%u crypto values to Alice\n",
495 (unsigned int) s->cadet_transmitted_element_count,
496 (unsigned int) s->used_element_count);
498 payload = (struct GNUNET_CRYPTO_PaillierCiphertext *) &msg[1];
499 GNUNET_memcpy (&payload[0],
501 sizeof(struct GNUNET_CRYPTO_PaillierCiphertext));
502 GNUNET_memcpy (&payload[1],
504 sizeof(struct GNUNET_CRYPTO_PaillierCiphertext));
506 payload = &payload[2];
508 for (i = 0; i < s->cadet_transmitted_element_count; i++)
510 // k[i][p] and k[i][q]
511 GNUNET_memcpy (&payload[i * 2],
513 sizeof(struct GNUNET_CRYPTO_PaillierCiphertext));
514 GNUNET_memcpy (&payload[i * 2 + 1],
516 sizeof(struct GNUNET_CRYPTO_PaillierCiphertext));
518 if (s->cadet_transmitted_element_count == s->used_element_count)
519 GNUNET_MQ_notify_sent (e,
522 GNUNET_MQ_send (s->cadet_mq,
524 transmit_bobs_cryptodata_message_multipart (s);
528 #undef ELEMENT_CAPACITY
532 * Computes the square sum over a vector of a given length.
534 * @param vector the vector to compute over
535 * @param length the length of the vector
536 * @return an MPI value containing the calculated sum, never NULL
537 * TODO: code duplication with Alice!
540 compute_square_sum (const gcry_mpi_t *vector,
547 GNUNET_assert (NULL != (sum = gcry_mpi_new (0)));
548 GNUNET_assert (NULL != (elem = gcry_mpi_new (0)));
549 for (i = 0; i < length; i++)
551 gcry_mpi_mul (elem, vector[i], vector[i]);
552 gcry_mpi_add (sum, sum, elem);
554 gcry_mpi_release (elem);
561 * (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)})$
562 * (2)[]: $E_A(a_{pi'(i)}) otimes E_A(- r_{pi'(i)}) &= E_A(a_{pi'(i)} - r_{pi'(i)})$
563 * S: $S := E_A(sum (r_i + b_i)^2)$
564 * S': $S' := E_A(sum r_i^2)$
566 * @param request the requesting session + bob's requesting peer
567 * @return #GNUNET_OK on success
570 compute_service_response (struct BobServiceSession *session)
578 const struct MpiElement *b;
579 struct GNUNET_CRYPTO_PaillierCiphertext *a;
580 struct GNUNET_CRYPTO_PaillierCiphertext *r;
581 struct GNUNET_CRYPTO_PaillierCiphertext *r_prime;
583 count = session->used_element_count;
585 b = session->sorted_elements;
586 q = GNUNET_CRYPTO_random_permute (GNUNET_CRYPTO_QUALITY_WEAK,
588 p = GNUNET_CRYPTO_random_permute (GNUNET_CRYPTO_QUALITY_WEAK,
590 rand = GNUNET_malloc (sizeof(gcry_mpi_t) * count);
591 for (i = 0; i < count; i++)
592 GNUNET_assert (NULL != (rand[i] = gcry_mpi_new (0)));
593 r = GNUNET_malloc (sizeof(struct GNUNET_CRYPTO_PaillierCiphertext) * count);
594 r_prime = GNUNET_malloc (sizeof(struct GNUNET_CRYPTO_PaillierCiphertext)
597 for (i = 0; i < count; i++)
601 svalue = (int32_t) GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_WEAK,
603 // long to gcry_mpi_t
605 gcry_mpi_sub_ui (rand[i],
609 rand[i] = gcry_mpi_set_ui (rand[i], svalue);
612 tmp = gcry_mpi_new (0);
613 // encrypt the element
614 // for the sake of readability I decided to have dedicated permutation
615 // vectors, which get rid of all the lookups in p/q.
616 // however, ap/aq are not absolutely necessary but are just abstraction
617 // Calculate Kp = E(S + a_pi) (+) E(S - r_pi - b_pi)
618 for (i = 0; i < count; i++)
620 // E(S - r_pi - b_pi)
621 gcry_mpi_sub (tmp, my_offset, rand[p[i]]);
622 gcry_mpi_sub (tmp, tmp, b[p[i]].value);
624 GNUNET_CRYPTO_paillier_encrypt (&session->remote_pubkey,
629 // E(S - r_pi - b_pi) * E(S + a_pi) == E(2*S + a - r - b)
631 GNUNET_CRYPTO_paillier_hom_add (&session->remote_pubkey,
641 // Calculate Kq = E(S + a_qi) (+) E(S - r_qi)
642 for (i = 0; i < count; i++)
645 gcry_mpi_sub (tmp, my_offset, rand[q[i]]);
647 GNUNET_CRYPTO_paillier_encrypt (&session->remote_pubkey,
652 // E(S - r_qi) * E(S + a_qi) == E(2*S + a_qi - r_qi)
654 GNUNET_CRYPTO_paillier_hom_add (&session->remote_pubkey,
663 gcry_mpi_release (tmp);
665 // Calculate S' = E(SUM( r_i^2 ))
666 tmp = compute_square_sum (rand, count);
668 GNUNET_CRYPTO_paillier_encrypt (&session->remote_pubkey,
672 gcry_mpi_release (tmp);
674 // Calculate S = E(SUM( (r_i + b_i)^2 ))
675 for (i = 0; i < count; i++)
676 gcry_mpi_add (rand[i], rand[i], b[i].value);
677 tmp = compute_square_sum (rand, count);
679 GNUNET_CRYPTO_paillier_encrypt (&session->remote_pubkey,
683 gcry_mpi_release (tmp);
686 session->r_prime = r_prime;
688 for (i = 0; i < count; i++)
689 gcry_mpi_release (rand[i]);
690 GNUNET_free (session->e_a);
699 GNUNET_free (r_prime);
700 gcry_mpi_release (tmp);
703 for (i = 0; i < count; i++)
704 gcry_mpi_release (rand[i]);
706 return GNUNET_SYSERR;
711 * Iterator to copy over messages from the hash map
712 * into an array for sorting.
714 * @param cls the `struct BobServiceSession *`
715 * @param key the key (unused)
716 * @param value the `struct GNUNET_SCALARPRODUCT_Element *`
717 * TODO: code duplication with Alice!
720 copy_element_cb (void *cls,
721 const struct GNUNET_HashCode *key,
724 struct BobServiceSession *s = cls;
725 struct GNUNET_SCALARPRODUCT_Element *e = value;
729 mval = gcry_mpi_new (0);
730 val = (int64_t) GNUNET_ntohll (e->value);
732 gcry_mpi_sub_ui (mval, mval, -val);
734 gcry_mpi_add_ui (mval, mval, val);
735 s->sorted_elements [s->used_element_count].value = mval;
736 s->sorted_elements [s->used_element_count].key = &e->key;
737 s->used_element_count++;
743 * Compare two `struct MpiValue`s by key for sorting.
745 * @param a pointer to first `struct MpiValue *`
746 * @param b pointer to first `struct MpiValue *`
747 * @return -1 for a < b, 0 for a=b, 1 for a > b.
748 * TODO: code duplication with Alice!
751 element_cmp (const void *a,
754 const struct MpiElement *ma = a;
755 const struct MpiElement *mb = b;
757 return GNUNET_CRYPTO_hash_cmp (ma->key,
763 * Intersection operation and receiving data via CADET from
764 * Alice are both done, compute and transmit our reply via
767 * @param s session to transmit reply for.
770 transmit_cryptographic_reply (struct BobServiceSession *s)
772 struct GNUNET_CADET_Channel *channel;
774 /* TODO: code duplication with Alice! */
775 LOG (GNUNET_ERROR_TYPE_DEBUG,
776 "Received everything, building reply for Alice\n");
778 = GNUNET_malloc (GNUNET_CONTAINER_multihashmap_size (
779 s->intersected_elements)
780 * sizeof(struct MpiElement));
781 s->used_element_count = 0;
782 GNUNET_CONTAINER_multihashmap_iterate (s->intersected_elements,
785 qsort (s->sorted_elements,
786 s->used_element_count,
787 sizeof(struct MpiElement),
790 compute_service_response (s))
792 channel = s->channel;
794 GNUNET_CADET_channel_destroy (channel);
797 transmit_bobs_cryptodata_message (s);
802 * Check a multipart-chunk of a request from another service to
803 * calculate a scalarproduct with us.
805 * @param cls the `struct BobServiceSession *`
806 * @param msg the actual message
807 * @return #GNUNET_OK to keep the connection open,
808 * #GNUNET_SYSERR to close it (signal serious error)
811 check_alices_cryptodata_message (void *cls,
812 const struct AliceCryptodataMessage *msg)
814 struct BobServiceSession *s = cls;
815 uint32_t contained_elements;
820 msize = ntohs (msg->header.size);
821 contained_elements = ntohl (msg->contained_element_count);
822 /* Our intersection may still be ongoing, but this is nevertheless
823 an upper bound on the required array size */
824 max = GNUNET_CONTAINER_multihashmap_size (s->intersected_elements);
825 msg_length = sizeof(struct AliceCryptodataMessage)
826 + contained_elements * sizeof(struct
827 GNUNET_CRYPTO_PaillierCiphertext);
828 if ((msize != msg_length) ||
829 (0 == contained_elements) ||
830 (contained_elements > UINT16_MAX) ||
831 (max < contained_elements + s->cadet_received_element_count))
834 return GNUNET_SYSERR;
841 * Handle a multipart-chunk of a request from another service to
842 * calculate a scalarproduct with us.
844 * @param cls the `struct BobServiceSession *`
845 * @param msg the actual message
848 handle_alices_cryptodata_message (void *cls,
849 const struct AliceCryptodataMessage *msg)
851 struct BobServiceSession *s = cls;
852 const struct GNUNET_CRYPTO_PaillierCiphertext *payload;
853 uint32_t contained_elements;
856 contained_elements = ntohl (msg->contained_element_count);
857 /* Our intersection may still be ongoing, but this is nevertheless
858 an upper bound on the required array size */
859 max = GNUNET_CONTAINER_multihashmap_size (s->intersected_elements);
860 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
861 "Received %u crypto values from Alice\n",
862 (unsigned int) contained_elements);
864 payload = (const struct GNUNET_CRYPTO_PaillierCiphertext *) &msg[1];
866 s->e_a = GNUNET_new_array (max,
867 struct GNUNET_CRYPTO_PaillierCiphertext);
868 GNUNET_memcpy (&s->e_a[s->cadet_received_element_count],
870 sizeof(struct GNUNET_CRYPTO_PaillierCiphertext)
871 * contained_elements);
872 s->cadet_received_element_count += contained_elements;
874 if ((s->cadet_received_element_count == max) &&
875 (NULL == s->intersection_op))
877 /* intersection has finished also on our side, and
878 we got the full set, so we can proceed with the
880 transmit_cryptographic_reply (s);
882 GNUNET_CADET_receive_done (s->channel);
887 * Callback for set operation results. Called for each element
888 * that needs to be removed from the result set.
890 * @param cls closure with the `struct BobServiceSession`
891 * @param element a result element, only valid if status is #GNUNET_SET_STATUS_OK
892 * @param current_size current set size
893 * @param status what has happened with the set intersection?
896 cb_intersection_element_removed (void *cls,
897 const struct GNUNET_SET_Element *element,
898 uint64_t current_size,
899 enum GNUNET_SET_Status status)
901 struct BobServiceSession *s = cls;
902 struct GNUNET_SCALARPRODUCT_Element *se;
906 case GNUNET_SET_STATUS_OK:
907 /* this element has been removed from the set */
908 se = GNUNET_CONTAINER_multihashmap_get (s->intersected_elements,
910 GNUNET_assert (NULL != se);
911 LOG (GNUNET_ERROR_TYPE_DEBUG,
912 "Removed element with key %s and value %lld\n",
913 GNUNET_h2s (&se->key),
914 (long long) GNUNET_ntohll (se->value));
915 GNUNET_assert (GNUNET_YES ==
916 GNUNET_CONTAINER_multihashmap_remove (
917 s->intersected_elements,
923 case GNUNET_SET_STATUS_DONE:
924 s->intersection_op = NULL;
925 GNUNET_break (NULL == s->intersection_set);
926 GNUNET_CADET_receive_done (s->channel);
927 LOG (GNUNET_ERROR_TYPE_DEBUG,
928 "Finished intersection, %d items remain\n",
929 GNUNET_CONTAINER_multihashmap_size (s->intersected_elements));
930 if (s->client_received_element_count ==
931 GNUNET_CONTAINER_multihashmap_size (s->intersected_elements))
933 /* CADET transmission from Alice is also already done,
934 start with our own reply */
935 transmit_cryptographic_reply (s);
939 case GNUNET_SET_STATUS_HALF_DONE:
940 /* unexpected for intersection */
944 case GNUNET_SET_STATUS_FAILURE:
945 /* unhandled status code */
946 LOG (GNUNET_ERROR_TYPE_DEBUG,
947 "Set intersection failed!\n");
948 s->intersection_op = NULL;
949 if (NULL != s->intersection_set)
951 GNUNET_SET_destroy (s->intersection_set);
952 s->intersection_set = NULL;
954 s->status = GNUNET_SCALARPRODUCT_STATUS_FAILURE;
955 prepare_client_end_notification (s);
966 * We've paired up a client session with an incoming CADET request.
967 * Initiate set intersection work.
969 * @param s client session to start intersection for
972 start_intersection (struct BobServiceSession *s)
974 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
975 "Got session with key %s and %u elements, starting intersection.\n",
976 GNUNET_h2s (&s->session_id),
977 (unsigned int) s->total);
980 = GNUNET_SET_prepare (&s->peer,
983 GNUNET_SET_RESULT_REMOVED,
984 (struct GNUNET_SET_Option[]) { { 0 } },
985 &cb_intersection_element_removed,
988 GNUNET_SET_commit (s->intersection_op,
989 s->intersection_set))
992 s->status = GNUNET_SCALARPRODUCT_STATUS_FAILURE;
993 prepare_client_end_notification (s);
996 GNUNET_SET_destroy (s->intersection_set);
997 s->intersection_set = NULL;
1002 * Handle a request from Alice to calculate a scalarproduct with us (Bob).
1004 * @param cls the `struct BobServiceSession *`
1005 * @param msg the actual message
1008 handle_alices_computation_request (void *cls,
1009 const struct ServiceRequestMessage *msg)
1011 struct BobServiceSession *s = cls;
1013 s->session_id = msg->session_id; // ??
1014 s->remote_pubkey = msg->public_key;
1015 if (s->client_received_element_count == s->total)
1016 start_intersection (s);
1021 * Function called for inbound channels on Bob's end. Does some
1022 * preliminary initialization, more happens after we get Alice's first
1025 * @param cls closure with the `struct BobServiceSession`
1026 * @param channel new handle to the channel
1027 * @param initiator peer that started the channel
1028 * @return session associated with the channel
1031 cb_channel_incoming (void *cls,
1032 struct GNUNET_CADET_Channel *channel,
1033 const struct GNUNET_PeerIdentity *initiator)
1035 struct BobServiceSession *s = cls;
1037 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1038 "New incoming channel from peer %s.\n",
1039 GNUNET_i2s (initiator));
1040 GNUNET_CADET_close_port (s->port);
1042 s->channel = channel;
1043 s->peer = *initiator;
1044 s->cadet_mq = GNUNET_CADET_get_mq (s->channel);
1050 * We're receiving additional set data. Check it is well-formed.
1052 * @param cls identification of the client
1053 * @param msg the actual message
1054 * @return #GNUNET_OK if @a msg is well-formed
1057 check_bob_client_message_multipart (void *cls,
1059 ComputationBobCryptodataMultipartMessage *
1062 struct BobServiceSession *s = cls;
1063 uint32_t contained_count;
1066 msize = ntohs (msg->header.size);
1067 contained_count = ntohl (msg->element_count_contained);
1068 if ((msize != (sizeof(struct ComputationBobCryptodataMultipartMessage)
1069 + contained_count * sizeof(struct
1070 GNUNET_SCALARPRODUCT_Element))) ||
1071 (0 == contained_count) ||
1072 (UINT16_MAX < contained_count) ||
1073 (s->total == s->client_received_element_count) ||
1074 (s->total < s->client_received_element_count + contained_count))
1077 return GNUNET_SYSERR;
1084 * We're receiving additional set data. Add it to our
1085 * set and if we are done, initiate the transaction.
1087 * @param cls identification of the client
1088 * @param msg the actual message
1091 handle_bob_client_message_multipart (void *cls,
1093 ComputationBobCryptodataMultipartMessage *
1096 struct BobServiceSession *s = cls;
1097 uint32_t contained_count;
1098 const struct GNUNET_SCALARPRODUCT_Element *elements;
1099 struct GNUNET_SET_Element set_elem;
1100 struct GNUNET_SCALARPRODUCT_Element *elem;
1102 contained_count = ntohl (msg->element_count_contained);
1103 elements = (const struct GNUNET_SCALARPRODUCT_Element *) &msg[1];
1104 for (uint32_t i = 0; i < contained_count; i++)
1106 elem = GNUNET_new (struct GNUNET_SCALARPRODUCT_Element);
1107 GNUNET_memcpy (elem,
1109 sizeof(struct GNUNET_SCALARPRODUCT_Element));
1110 if (GNUNET_SYSERR ==
1111 GNUNET_CONTAINER_multihashmap_put (s->intersected_elements,
1114 GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY))
1120 set_elem.data = &elem->key;
1121 set_elem.size = sizeof(elem->key);
1122 set_elem.element_type = 0;
1123 GNUNET_SET_add_element (s->intersection_set,
1127 s->client_received_element_count += contained_count;
1128 GNUNET_SERVICE_client_continue (s->client);
1129 if (s->total != s->client_received_element_count)
1134 if (NULL == s->channel)
1136 /* no Alice waiting for this request, wait for Alice */
1139 start_intersection (s);
1144 * Handler for Bob's a client request message. Check @a msg is
1147 * @param cls identification of the client
1148 * @param msg the actual message
1149 * @return #GNUNET_OK if @a msg is well-formed
1152 check_bob_client_message (void *cls,
1153 const struct BobComputationMessage *msg)
1155 struct BobServiceSession *s = cls;
1156 uint32_t contained_count;
1157 uint32_t total_count;
1160 if (GNUNET_SCALARPRODUCT_STATUS_INIT != s->status)
1163 return GNUNET_SYSERR;
1165 msize = ntohs (msg->header.size);
1166 total_count = ntohl (msg->element_count_total);
1167 contained_count = ntohl (msg->element_count_contained);
1168 if ((0 == total_count) ||
1169 (0 == contained_count) ||
1170 (UINT16_MAX < contained_count) ||
1171 (msize != (sizeof(struct BobComputationMessage)
1172 + contained_count * sizeof(struct
1173 GNUNET_SCALARPRODUCT_Element))))
1175 GNUNET_break_op (0);
1176 return GNUNET_SYSERR;
1183 * Handler for Bob's a client request message. Bob is in the response
1184 * role, keep the values + session and waiting for a matching session
1185 * or process a waiting request from Alice.
1187 * @param cls identification of the client
1188 * @param msg the actual message
1191 handle_bob_client_message (void *cls,
1192 const struct BobComputationMessage *msg)
1194 struct BobServiceSession *s = cls;
1195 struct GNUNET_MQ_MessageHandler cadet_handlers[] = {
1196 GNUNET_MQ_hd_fixed_size (alices_computation_request,
1197 GNUNET_MESSAGE_TYPE_SCALARPRODUCT_SESSION_INITIALIZATION,
1198 struct ServiceRequestMessage,
1200 GNUNET_MQ_hd_var_size (alices_cryptodata_message,
1201 GNUNET_MESSAGE_TYPE_SCALARPRODUCT_ALICE_CRYPTODATA,
1202 struct AliceCryptodataMessage,
1204 GNUNET_MQ_handler_end ()
1206 uint32_t contained_count;
1207 uint32_t total_count;
1208 const struct GNUNET_SCALARPRODUCT_Element *elements;
1209 struct GNUNET_SET_Element set_elem;
1210 struct GNUNET_SCALARPRODUCT_Element *elem;
1212 total_count = ntohl (msg->element_count_total);
1213 contained_count = ntohl (msg->element_count_contained);
1215 s->status = GNUNET_SCALARPRODUCT_STATUS_ACTIVE;
1216 s->total = total_count;
1217 s->client_received_element_count = contained_count;
1218 s->session_id = msg->session_key;
1219 elements = (const struct GNUNET_SCALARPRODUCT_Element *) &msg[1];
1220 s->intersected_elements
1221 = GNUNET_CONTAINER_multihashmap_create (s->total,
1224 = GNUNET_SET_create (cfg,
1225 GNUNET_SET_OPERATION_INTERSECTION);
1226 for (uint32_t i = 0; i < contained_count; i++)
1228 if (0 == GNUNET_ntohll (elements[i].value))
1230 elem = GNUNET_new (struct GNUNET_SCALARPRODUCT_Element);
1231 GNUNET_memcpy (elem,
1233 sizeof(struct GNUNET_SCALARPRODUCT_Element));
1234 if (GNUNET_SYSERR ==
1235 GNUNET_CONTAINER_multihashmap_put (s->intersected_elements,
1238 GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY))
1244 set_elem.data = &elem->key;
1245 set_elem.size = sizeof(elem->key);
1246 set_elem.element_type = 0;
1247 GNUNET_SET_add_element (s->intersection_set,
1250 s->used_element_count++;
1252 GNUNET_SERVICE_client_continue (s->client);
1253 /* We're ready, open the port */
1254 s->port = GNUNET_CADET_open_port (my_cadet,
1256 &cb_channel_incoming,
1259 &cb_channel_destruction,
1261 if (NULL == s->port)
1264 GNUNET_SERVICE_client_drop (s->client);
1271 * Task run during shutdown.
1276 shutdown_task (void *cls)
1278 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1279 "Shutting down, initiating cleanup.\n");
1280 // FIXME: we have to cut our connections to CADET first!
1281 if (NULL != my_cadet)
1283 GNUNET_CADET_disconnect (my_cadet);
1290 * A client connected.
1292 * Setup the associated data structure.
1294 * @param cls closure, NULL
1295 * @param client identification of the client
1296 * @param mq message queue to communicate with @a client
1297 * @return our `struct BobServiceSession`
1300 client_connect_cb (void *cls,
1301 struct GNUNET_SERVICE_Client *client,
1302 struct GNUNET_MQ_Handle *mq)
1304 struct BobServiceSession *s;
1306 s = GNUNET_new (struct BobServiceSession);
1314 * A client disconnected.
1316 * Remove the associated session(s), release data structures
1317 * and cancel pending outgoing transmissions to the client.
1319 * @param cls closure, NULL
1320 * @param client identification of the client
1321 * @param app_cls our `struct BobServiceSession`
1324 client_disconnect_cb (void *cls,
1325 struct GNUNET_SERVICE_Client *client,
1328 struct BobServiceSession *s = app_cls;
1330 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1331 "Client disconnected from us.\n");
1333 destroy_service_session (s);
1338 * Initialization of the program and message handlers
1340 * @param cls closure
1341 * @param c configuration to use
1342 * @param service the initialized service
1346 const struct GNUNET_CONFIGURATION_Handle *c,
1347 struct GNUNET_SERVICE_Handle *service)
1351 offset has to be sufficiently small to allow computation of:
1352 m1+m2 mod n == (S + a) + (S + b) mod n,
1353 if we have more complex operations, this factor needs to be lowered */
1354 my_offset = gcry_mpi_new (GNUNET_CRYPTO_PAILLIER_BITS / 3);
1355 gcry_mpi_set_bit (my_offset,
1356 GNUNET_CRYPTO_PAILLIER_BITS / 3);
1358 GNUNET_CRYPTO_paillier_create (&my_pubkey,
1360 my_cadet = GNUNET_CADET_connect (cfg);
1361 GNUNET_SCHEDULER_add_shutdown (&shutdown_task,
1363 if (NULL == my_cadet)
1365 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1366 _ ("Connect to CADET failed\n"));
1367 GNUNET_SCHEDULER_shutdown ();
1374 * Define "main" method using service macro.
1377 ("scalarproduct-bob",
1378 GNUNET_SERVICE_OPTION_NONE,
1381 &client_disconnect_cb,
1383 GNUNET_MQ_hd_var_size (bob_client_message,
1384 GNUNET_MESSAGE_TYPE_SCALARPRODUCT_CLIENT_TO_BOB,
1385 struct BobComputationMessage,
1387 GNUNET_MQ_hd_var_size (bob_client_message_multipart,
1388 GNUNET_MESSAGE_TYPE_SCALARPRODUCT_CLIENT_MULTIPART_BOB,
1389 struct ComputationBobCryptodataMultipartMessage,
1391 GNUNET_MQ_handler_end ());
1394 /* end of gnunet-service-scalarproduct_bob.c */