aboutsummaryrefslogtreecommitdiff
path: root/src/contrib/service/scalarproduct/gnunet-service-scalarproduct-ecc_bob.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/contrib/service/scalarproduct/gnunet-service-scalarproduct-ecc_bob.c')
-rw-r--r--src/contrib/service/scalarproduct/gnunet-service-scalarproduct-ecc_bob.c1060
1 files changed, 1060 insertions, 0 deletions
diff --git a/src/contrib/service/scalarproduct/gnunet-service-scalarproduct-ecc_bob.c b/src/contrib/service/scalarproduct/gnunet-service-scalarproduct-ecc_bob.c
new file mode 100644
index 000000000..1945f1937
--- /dev/null
+++ b/src/contrib/service/scalarproduct/gnunet-service-scalarproduct-ecc_bob.c
@@ -0,0 +1,1060 @@
1/*
2 This file is part of GNUnet.
3 Copyright (C) 2013-2017, 2021 GNUnet e.V.
4
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.
9
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.
14
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/>.
17
18 SPDX-License-Identifier: AGPL3.0-or-later
19 */
20/**
21 * @file scalarproduct/gnunet-service-scalarproduct-ecc_bob.c
22 * @brief scalarproduct service implementation
23 * @author Christian M. Fuchs
24 * @author Christian Grothoff
25 */
26#include "platform.h"
27#include <limits.h>
28#include <gcrypt.h>
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_seti_service.h"
36#include "scalarproduct.h"
37#include "gnunet-service-scalarproduct-ecc.h"
38
39#define LOG(kind, ...) GNUNET_log_from (kind, "scalarproduct-bob", __VA_ARGS__)
40
41
42/**
43 * An encrypted element key-value pair.
44 */
45struct MpiElement
46{
47 /**
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.
51 */
52 const struct GNUNET_HashCode *key;
53
54 /**
55 * Value represented (a).
56 */
57 int64_t value;
58};
59
60
61/**
62 * A scalarproduct session which tracks an offer for a
63 * multiplication service by a local client.
64 */
65struct BobServiceSession
66{
67 /**
68 * The client this request is related to.
69 */
70 struct GNUNET_SERVICE_Client *client;
71
72 /**
73 * Client message queue.
74 */
75 struct GNUNET_MQ_Handle *client_mq;
76
77 /**
78 * All non-0-value'd elements transmitted to us.
79 */
80 struct GNUNET_CONTAINER_MultiHashMap *intersected_elements;
81
82 /**
83 * Set of elements for which we will be conducting an intersection.
84 * The resulting elements are then used for computing the scalar product.
85 */
86 struct GNUNET_SETI_Handle *intersection_set;
87
88 /**
89 * Set of elements for which will conduction an intersection.
90 * the resulting elements are then used for computing the scalar product.
91 */
92 struct GNUNET_SETI_OperationHandle *intersection_op;
93
94 /**
95 * Our open port.
96 */
97 struct GNUNET_CADET_Port *port;
98
99 /**
100 * b(Bob)
101 */
102 struct MpiElement *sorted_elements;
103
104 /**
105 * Product of the g_i^{b_i}
106 */
107 struct GNUNET_CRYPTO_EccPoint prod_g_i_b_i;
108
109 /**
110 * Product of the h_i^{b_i}
111 */
112 struct GNUNET_CRYPTO_EccPoint prod_h_i_b_i;
113
114 /**
115 * How many elements will be supplied in total from the client.
116 */
117 uint32_t total;
118
119 /**
120 * Already transferred elements (received) for multipart
121 * messages from client. Always less than @e total.
122 */
123 uint32_t client_received_element_count;
124
125 /**
126 * How many elements actually are used for the scalar product.
127 * Size of the arrays in @e r and @e r_prime. Also sometimes
128 * used as an index into the arrays during construction.
129 */
130 uint32_t used_element_count;
131
132 /**
133 * Counts the number of values received from Alice by us.
134 * Always less than @e used_element_count.
135 */
136 uint32_t cadet_received_element_count;
137
138 /**
139 * State of this session. In
140 * #GNUNET_SCALARPRODUCT_STATUS_ACTIVE while operation is
141 * ongoing, afterwards in #GNUNET_SCALARPRODUCT_STATUS_SUCCESS or
142 * #GNUNET_SCALARPRODUCT_STATUS_FAILURE.
143 */
144 enum GNUNET_SCALARPRODUCT_ResponseStatus status;
145
146 /**
147 * Are we already in #destroy_service_session()?
148 */
149 int in_destroy;
150
151 /**
152 * The CADET channel.
153 */
154 struct GNUNET_CADET_Channel *channel;
155
156 /**
157 * Originator's peer identity. (Only for diagnostics.)
158 */
159 struct GNUNET_PeerIdentity peer;
160
161 /**
162 * (hopefully) unique transaction ID
163 */
164 struct GNUNET_HashCode session_id;
165
166 /**
167 * The message queue for this channel.
168 */
169 struct GNUNET_MQ_Handle *cadet_mq;
170};
171
172
173/**
174 * GNUnet configuration handle
175 */
176static const struct GNUNET_CONFIGURATION_Handle *cfg;
177
178/**
179 * Handle to the CADET service.
180 */
181static struct GNUNET_CADET_Handle *my_cadet;
182
183/**
184 * Context for DLOG operations on a curve.
185 */
186static struct GNUNET_CRYPTO_EccDlogContext *edc;
187
188
189/**
190 * Callback used to free the elements in the map.
191 *
192 * @param cls NULL
193 * @param key key of the element
194 * @param value the value to free
195 */
196static int
197free_element_cb (void *cls,
198 const struct GNUNET_HashCode *key,
199 void *value)
200{
201 struct GNUNET_SCALARPRODUCT_Element *element = value;
202
203 GNUNET_free (element);
204 return GNUNET_OK;
205}
206
207
208/**
209 * Destroy session state, we are done with it.
210 *
211 * @param s the session to free elements from
212 */
213static void
214destroy_service_session (struct BobServiceSession *s)
215{
216 if (GNUNET_YES == s->in_destroy)
217 return;
218 s->in_destroy = GNUNET_YES;
219 if (NULL != s->client)
220 {
221 struct GNUNET_SERVICE_Client *c = s->client;
222
223 s->client = NULL;
224 GNUNET_SERVICE_client_drop (c);
225 }
226 if (NULL != s->intersected_elements)
227 {
228 GNUNET_CONTAINER_multihashmap_iterate (s->intersected_elements,
229 &free_element_cb,
230 NULL);
231 GNUNET_CONTAINER_multihashmap_destroy (s->intersected_elements);
232 s->intersected_elements = NULL;
233 }
234 if (NULL != s->intersection_op)
235 {
236 GNUNET_SETI_operation_cancel (s->intersection_op);
237 s->intersection_op = NULL;
238 }
239 if (NULL != s->intersection_set)
240 {
241 GNUNET_SETI_destroy (s->intersection_set);
242 s->intersection_set = NULL;
243 }
244 if (NULL != s->sorted_elements)
245 {
246 GNUNET_free (s->sorted_elements);
247 s->sorted_elements = NULL;
248 }
249 if (NULL != s->port)
250 {
251 GNUNET_CADET_close_port (s->port);
252 s->port = NULL;
253 }
254 if (NULL != s->channel)
255 {
256 GNUNET_CADET_channel_destroy (s->channel);
257 s->channel = NULL;
258 }
259 GNUNET_free (s);
260}
261
262
263/**
264 * Notify the client that the session has succeeded or failed. This
265 * message gets sent to Bob's client if the operation completed or
266 * Alice disconnected.
267 *
268 * @param session the associated client session to fail or succeed
269 */
270static void
271prepare_client_end_notification (struct BobServiceSession *session)
272{
273 struct ClientResponseMessage *msg;
274 struct GNUNET_MQ_Envelope *e;
275
276 if (NULL == session->client_mq)
277 return; /* no client left to be notified */
278 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
279 "Sending session-end notification with status %d to client for session %s\n",
280 session->status,
281 GNUNET_h2s (&session->session_id));
282 e = GNUNET_MQ_msg (msg,
283 GNUNET_MESSAGE_TYPE_SCALARPRODUCT_RESULT);
284 msg->range = 0;
285 msg->product_length = htonl (0);
286 msg->status = htonl (session->status);
287 GNUNET_MQ_send (session->client_mq,
288 e);
289}
290
291
292/**
293 * Function called whenever a channel is destroyed. Should clean up
294 * any associated state.
295 *
296 * It must NOT call #GNUNET_CADET_channel_destroy() on the channel.
297 *
298 * @param cls the `struct BobServiceSession`
299 * @param channel connection to the other end (henceforth invalid)
300 */
301static void
302cb_channel_destruction (void *cls,
303 const struct GNUNET_CADET_Channel *channel)
304{
305 struct BobServiceSession *s = cls;
306
307 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
308 "Peer disconnected, terminating session %s with peer %s\n",
309 GNUNET_h2s (&s->session_id),
310 GNUNET_i2s (&s->peer));
311 s->channel = NULL;
312 if (GNUNET_SCALARPRODUCT_STATUS_ACTIVE == s->status)
313 {
314 s->status = GNUNET_SCALARPRODUCT_STATUS_FAILURE;
315 prepare_client_end_notification (s);
316 }
317 destroy_service_session (s);
318}
319
320
321/**
322 * MQ finished giving our last message to CADET, now notify
323 * the client that we are finished.
324 */
325static void
326bob_cadet_done_cb (void *cls)
327{
328 struct BobServiceSession *session = cls;
329
330 session->status = GNUNET_SCALARPRODUCT_STATUS_SUCCESS;
331 prepare_client_end_notification (session);
332}
333
334
335/**
336 * Bob generates the response message to be sent to Alice.
337 *
338 * @param s the associated requesting session with Alice
339 */
340static void
341transmit_bobs_cryptodata_message (struct BobServiceSession *s)
342{
343 struct EccBobCryptodataMessage *msg;
344 struct GNUNET_MQ_Envelope *e;
345
346 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
347 "Sending response to Alice\n");
348 e = GNUNET_MQ_msg (msg,
349 GNUNET_MESSAGE_TYPE_SCALARPRODUCT_ECC_BOB_CRYPTODATA);
350 msg->contained_element_count = htonl (2);
351 msg->prod_g_i_b_i = s->prod_g_i_b_i;
352 msg->prod_h_i_b_i = s->prod_h_i_b_i;
353 GNUNET_MQ_notify_sent (e,
354 &bob_cadet_done_cb,
355 s);
356 GNUNET_MQ_send (s->cadet_mq,
357 e);
358}
359
360
361/**
362 * Iterator to copy over messages from the hash map
363 * into an array for sorting.
364 *
365 * @param cls the `struct AliceServiceSession *`
366 * @param key the key (unused)
367 * @param value the `struct GNUNET_SCALARPRODUCT_Element *`
368 */
369static int
370copy_element_cb (void *cls,
371 const struct GNUNET_HashCode *key,
372 void *value)
373{
374 struct BobServiceSession *s = cls;
375 struct GNUNET_SCALARPRODUCT_Element *e = value;
376
377 s->sorted_elements[s->used_element_count].value = (int64_t) GNUNET_ntohll (
378 e->value);
379 s->sorted_elements[s->used_element_count].key = &e->key;
380 s->used_element_count++;
381 return GNUNET_OK;
382}
383
384
385/**
386 * Compare two `struct MpiValue`s by key for sorting.
387 *
388 * @param a pointer to first `struct MpiValue *`
389 * @param b pointer to first `struct MpiValue *`
390 * @return -1 for a < b, 0 for a=b, 1 for a > b.
391 * TODO: code duplication with Alice!
392 */
393static int
394element_cmp (const void *a,
395 const void *b)
396{
397 const struct MpiElement *ma = a;
398 const struct MpiElement *mb = b;
399
400 return GNUNET_CRYPTO_hash_cmp (ma->key,
401 mb->key);
402}
403
404
405/**
406 * Check a multipart-chunk of a request from another service to
407 * calculate a scalarproduct with us.
408 *
409 * @param cls closure (set from #GNUNET_CADET_connect)
410 * @param msg the actual message
411 * @return #GNUNET_OK to keep the connection open,
412 * #GNUNET_SYSERR to close it (signal serious error)
413 */
414static int
415check_alices_cryptodata_message (void *cls,
416 const struct EccAliceCryptodataMessage *msg)
417{
418 struct BobServiceSession *s = cls;
419 uint32_t contained_elements;
420 size_t msg_length;
421 uint16_t msize;
422 unsigned int max;
423
424 msize = ntohs (msg->header.size);
425 if (msize <= sizeof(struct EccAliceCryptodataMessage))
426 {
427 GNUNET_break_op (0);
428 return GNUNET_SYSERR;
429 }
430 contained_elements = ntohl (msg->contained_element_count);
431 /* Our intersection may still be ongoing, but this is nevertheless
432 an upper bound on the required array size */
433 max = GNUNET_CONTAINER_multihashmap_size (s->intersected_elements);
434 msg_length = sizeof(struct EccAliceCryptodataMessage)
435 + contained_elements * sizeof(struct GNUNET_CRYPTO_EccPoint) * 2;
436 if ((msize != msg_length) ||
437 (0 == contained_elements) ||
438 (contained_elements > UINT16_MAX) ||
439 (max < contained_elements + s->cadet_received_element_count))
440 {
441 GNUNET_break_op (0);
442 return GNUNET_SYSERR;
443 }
444 return GNUNET_OK;
445}
446
447
448/**
449 * Handle a multipart-chunk of a request from another service to
450 * calculate a scalarproduct with us.
451 *
452 * @param cls closure (set from #GNUNET_CADET_connect)
453 * @param msg the actual message
454 */
455static void
456handle_alices_cryptodata_message (void *cls,
457 const struct EccAliceCryptodataMessage *msg)
458{
459 struct BobServiceSession *s = cls;
460 const struct GNUNET_CRYPTO_EccPoint *payload;
461 uint32_t contained_elements;
462 unsigned int max;
463 const struct GNUNET_CRYPTO_EccPoint *g_i;
464 const struct GNUNET_CRYPTO_EccPoint *h_i;
465 struct GNUNET_CRYPTO_EccPoint g_i_b_i;
466 struct GNUNET_CRYPTO_EccPoint h_i_b_i;
467
468 contained_elements = ntohl (msg->contained_element_count);
469 max = GNUNET_CONTAINER_multihashmap_size (s->intersected_elements);
470 /* sort our vector for the computation */
471 if (NULL == s->sorted_elements)
472 {
473 s->sorted_elements
474 = GNUNET_new_array (GNUNET_CONTAINER_multihashmap_size (
475 s->intersected_elements),
476 struct MpiElement);
477 s->used_element_count = 0;
478 GNUNET_CONTAINER_multihashmap_iterate (s->intersected_elements,
479 &copy_element_cb,
480 s);
481 qsort (s->sorted_elements,
482 s->used_element_count,
483 sizeof(struct MpiElement),
484 &element_cmp);
485 }
486
487 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
488 "Received %u crypto values from Alice\n",
489 (unsigned int) contained_elements);
490 payload = (const struct GNUNET_CRYPTO_EccPoint *) &msg[1];
491
492 for (unsigned int i = 0; i < contained_elements; i++)
493 {
494 int64_t val = s->sorted_elements[i + s->cadet_received_element_count].value;
495 struct GNUNET_CRYPTO_EccScalar vali;
496
497 GNUNET_assert (INT64_MIN != val);
498 GNUNET_CRYPTO_ecc_scalar_from_int (val > 0 ? val : -val,
499 &vali);
500 if (val < 0)
501 crypto_core_ed25519_scalar_negate (vali.v,
502 vali.v);
503 g_i = &payload[i * 2];
504 /* g_i_b_i = g_i^vali */
505 GNUNET_assert (GNUNET_OK ==
506 GNUNET_CRYPTO_ecc_pmul_mpi (g_i,
507 &vali,
508 &g_i_b_i));
509 h_i = &payload[i * 2 + 1];
510 /* h_i_b_i = h_i^vali */
511 GNUNET_assert (GNUNET_OK ==
512 GNUNET_CRYPTO_ecc_pmul_mpi (h_i,
513 &vali,
514 &h_i_b_i));
515 if (0 == i + s->cadet_received_element_count)
516 {
517 /* first iteration, nothing to add */
518 s->prod_g_i_b_i = g_i_b_i;
519 s->prod_h_i_b_i = h_i_b_i;
520 }
521 else
522 {
523 /* further iterations, cummulate resulting value */
524 GNUNET_assert (GNUNET_OK ==
525 GNUNET_CRYPTO_ecc_add (&s->prod_g_i_b_i,
526 &g_i_b_i,
527 &s->prod_g_i_b_i));
528 GNUNET_assert (GNUNET_OK ==
529 GNUNET_CRYPTO_ecc_add (&s->prod_h_i_b_i,
530 &h_i_b_i,
531 &s->prod_h_i_b_i));
532 }
533 }
534 s->cadet_received_element_count += contained_elements;
535 if ((s->cadet_received_element_count == max) &&
536 (NULL == s->intersection_op))
537 {
538 /* intersection has finished also on our side, and
539 we got the full set, so we can proceed with the
540 CADET response(s) */
541 transmit_bobs_cryptodata_message (s);
542 }
543 GNUNET_CADET_receive_done (s->channel);
544}
545
546
547/**
548 * Callback for set operation results. Called for each element
549 * that needs to be removed from the result set.
550 *
551 * @param cls closure with the `struct BobServiceSession`
552 * @param element a result element, only valid if status is #GNUNET_SETI_STATUS_OK
553 * @param current_size current set size
554 * @param status what has happened with the set intersection?
555 */
556static void
557cb_intersection_element_removed (void *cls,
558 const struct GNUNET_SETI_Element *element,
559 uint64_t current_size,
560 enum GNUNET_SETI_Status status)
561{
562 struct BobServiceSession *s = cls;
563 struct GNUNET_SCALARPRODUCT_Element *se;
564
565 switch (status)
566 {
567 case GNUNET_SETI_STATUS_DEL_LOCAL:
568 /* this element has been removed from the set */
569 se = GNUNET_CONTAINER_multihashmap_get (s->intersected_elements,
570 element->data);
571 GNUNET_assert (NULL != se);
572 LOG (GNUNET_ERROR_TYPE_DEBUG,
573 "Removed element with key %s and value %lld\n",
574 GNUNET_h2s (&se->key),
575 (long long) GNUNET_ntohll (se->value));
576 GNUNET_assert (GNUNET_YES ==
577 GNUNET_CONTAINER_multihashmap_remove (
578 s->intersected_elements,
579 element->data,
580 se));
581 GNUNET_free (se);
582 return;
583 case GNUNET_SETI_STATUS_DONE:
584 s->intersection_op = NULL;
585 GNUNET_break (NULL == s->intersection_set);
586 GNUNET_CADET_receive_done (s->channel);
587 LOG (GNUNET_ERROR_TYPE_DEBUG,
588 "Finished intersection, %d items remain\n",
589 GNUNET_CONTAINER_multihashmap_size (s->intersected_elements));
590 if (s->client_received_element_count ==
591 GNUNET_CONTAINER_multihashmap_size (s->intersected_elements))
592 {
593 /* CADET transmission from Alice is also already done,
594 start with our own reply */
595 transmit_bobs_cryptodata_message (s);
596 }
597 return;
598 case GNUNET_SETI_STATUS_FAILURE:
599 /* unhandled status code */
600 LOG (GNUNET_ERROR_TYPE_DEBUG,
601 "Set intersection failed!\n");
602 s->intersection_op = NULL;
603 if (NULL != s->intersection_set)
604 {
605 GNUNET_SETI_destroy (s->intersection_set);
606 s->intersection_set = NULL;
607 }
608 s->status = GNUNET_SCALARPRODUCT_STATUS_FAILURE;
609 prepare_client_end_notification (s);
610 return;
611
612 default:
613 GNUNET_break (0);
614 return;
615 }
616}
617
618
619/**
620 * We've paired up a client session with an incoming CADET request.
621 * Initiate set intersection work.
622 *
623 * @param s client session to start intersection for
624 */
625static void
626start_intersection (struct BobServiceSession *s)
627{
628 struct GNUNET_HashCode set_sid;
629
630 GNUNET_CRYPTO_hash (&s->session_id,
631 sizeof(struct GNUNET_HashCode),
632 &set_sid);
633 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
634 "Got session with key %s and %u elements, starting intersection.\n",
635 GNUNET_h2s (&s->session_id),
636 (unsigned int) s->total);
637
638 s->intersection_op
639 = GNUNET_SETI_prepare (&s->peer,
640 &set_sid,
641 NULL,
642 (struct GNUNET_SETI_Option[]) { { 0 } },
643 &cb_intersection_element_removed,
644 s);
645 if (GNUNET_OK !=
646 GNUNET_SETI_commit (s->intersection_op,
647 s->intersection_set))
648 {
649 GNUNET_break (0);
650 s->status = GNUNET_SCALARPRODUCT_STATUS_FAILURE;
651 prepare_client_end_notification (s);
652 return;
653 }
654 GNUNET_SETI_destroy (s->intersection_set);
655 s->intersection_set = NULL;
656}
657
658
659/**
660 * Handle a request from Alice to calculate a scalarproduct with us (Bob).
661 *
662 * @param cls closure (set from #GNUNET_CADET_connect)
663 * @param msg the actual message
664 */
665static void
666handle_alices_computation_request (void *cls,
667 const struct EccServiceRequestMessage *msg)
668{
669 struct BobServiceSession *s = cls;
670
671 s->session_id = msg->session_id; // ??
672 if (s->client_received_element_count < s->total)
673 {
674 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
675 "Alice ready, still waiting for Bob client data!\n");
676 return;
677 }
678 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
679 "Both ready, launching intersection!\n");
680 start_intersection (s);
681}
682
683
684/**
685 * Function called for inbound channels on Bob's end. Does some
686 * preliminary initialization, more happens after we get Alice's first
687 * message.
688 *
689 * @param cls our `struct BobServiceSession`
690 * @param channel new handle to the channel
691 * @param initiator peer that started the channel
692 * @return session associated with the channel
693 */
694static void *
695cb_channel_incoming (void *cls,
696 struct GNUNET_CADET_Channel *channel,
697 const struct GNUNET_PeerIdentity *initiator)
698{
699 struct BobServiceSession *s = cls;
700
701 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
702 "New incoming channel from peer %s.\n",
703 GNUNET_i2s (initiator));
704 GNUNET_CADET_close_port (s->port);
705 s->port = NULL;
706 s->peer = *initiator;
707 s->channel = channel;
708 s->cadet_mq = GNUNET_CADET_get_mq (s->channel);
709 return s;
710}
711
712
713/**
714 * We're receiving additional set data. Check it is well-formed.
715 *
716 * @param cls identification of the client
717 * @param msg the actual message
718 * @return #GNUNET_OK if @a msg is well-formed
719 */
720static int
721check_bob_client_message_multipart (
722 void *cls,
723 const struct ComputationBobCryptodataMultipartMessage *msg)
724{
725 struct BobServiceSession *s = cls;
726 uint32_t contained_count;
727 uint16_t msize;
728
729 msize = ntohs (msg->header.size);
730 contained_count = ntohl (msg->element_count_contained);
731 if ((msize != (sizeof(struct ComputationBobCryptodataMultipartMessage)
732 + contained_count * sizeof(struct
733 GNUNET_SCALARPRODUCT_Element))) ||
734 (0 == contained_count) ||
735 (UINT16_MAX < contained_count) ||
736 (s->total == s->client_received_element_count) ||
737 (s->total < s->client_received_element_count + contained_count))
738 {
739 GNUNET_break (0);
740 return GNUNET_SYSERR;
741 }
742 return GNUNET_OK;
743}
744
745
746/**
747 * We're receiving additional set data. Add it to our
748 * set and if we are done, initiate the transaction.
749 *
750 * @param cls identification of the client
751 * @param msg the actual message
752 */
753static void
754handle_bob_client_message_multipart (
755 void *cls,
756 const struct ComputationBobCryptodataMultipartMessage *msg)
757{
758 struct BobServiceSession *s = cls;
759 uint32_t contained_count;
760 const struct GNUNET_SCALARPRODUCT_Element *elements;
761 struct GNUNET_SETI_Element set_elem;
762 struct GNUNET_SCALARPRODUCT_Element *elem;
763
764 contained_count = ntohl (msg->element_count_contained);
765 elements = (const struct GNUNET_SCALARPRODUCT_Element *) &msg[1];
766 for (uint32_t i = 0; i < contained_count; i++)
767 {
768 elem = GNUNET_new (struct GNUNET_SCALARPRODUCT_Element);
769 GNUNET_memcpy (elem,
770 &elements[i],
771 sizeof(struct GNUNET_SCALARPRODUCT_Element));
772 if (GNUNET_SYSERR ==
773 GNUNET_CONTAINER_multihashmap_put (s->intersected_elements,
774 &elem->key,
775 elem,
776 GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY))
777 {
778 GNUNET_break (0);
779 GNUNET_free (elem);
780 continue;
781 }
782 set_elem.data = &elem->key;
783 set_elem.size = sizeof(elem->key);
784 set_elem.element_type = 0;
785 GNUNET_SETI_add_element (s->intersection_set,
786 &set_elem,
787 NULL, NULL);
788 }
789 s->client_received_element_count += contained_count;
790 GNUNET_SERVICE_client_continue (s->client);
791 if (s->total != s->client_received_element_count)
792 {
793 /* more to come */
794 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
795 "Request still partial, waiting for more client data!\n");
796 return;
797 }
798 if (NULL == s->channel)
799 {
800 /* no Alice waiting for this request, wait for Alice */
801 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
802 "Client ready, still waiting for Alice!\n");
803 return;
804 }
805 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
806 "Both ready, launching intersection!\n");
807 start_intersection (s);
808}
809
810
811/**
812 * Handler for Bob's a client request message. Check @a msg is
813 * well-formed.
814 *
815 * @param cls identification of the client
816 * @param msg the actual message
817 * @return #GNUNET_OK if @a msg is well-formed
818 */
819static int
820check_bob_client_message (void *cls,
821 const struct BobComputationMessage *msg)
822{
823 struct BobServiceSession *s = cls;
824 uint32_t contained_count;
825 uint32_t total_count;
826 uint16_t msize;
827
828 if (GNUNET_SCALARPRODUCT_STATUS_INIT != s->status)
829 {
830 GNUNET_break (0);
831 return GNUNET_SYSERR;
832 }
833 msize = ntohs (msg->header.size);
834 total_count = ntohl (msg->element_count_total);
835 contained_count = ntohl (msg->element_count_contained);
836 if ((0 == total_count) ||
837 (0 == contained_count) ||
838 (UINT16_MAX < contained_count) ||
839 (msize != (sizeof(struct BobComputationMessage)
840 + contained_count * sizeof(struct
841 GNUNET_SCALARPRODUCT_Element))))
842 {
843 GNUNET_break_op (0);
844 return GNUNET_SYSERR;
845 }
846 return GNUNET_OK;
847}
848
849
850/**
851 * Handler for Bob's a client request message. Bob is in the response
852 * role, keep the values + session and waiting for a matching session
853 * or process a waiting request from Alice.
854 *
855 * @param cls identification of the client
856 * @param msg the actual message
857 */
858static void
859handle_bob_client_message (void *cls,
860 const struct BobComputationMessage *msg)
861{
862 struct BobServiceSession *s = cls;
863 struct GNUNET_MQ_MessageHandler cadet_handlers[] = {
864 GNUNET_MQ_hd_fixed_size (alices_computation_request,
865 GNUNET_MESSAGE_TYPE_SCALARPRODUCT_ECC_SESSION_INITIALIZATION,
866 struct EccServiceRequestMessage,
867 s),
868 GNUNET_MQ_hd_var_size (alices_cryptodata_message,
869 GNUNET_MESSAGE_TYPE_SCALARPRODUCT_ECC_ALICE_CRYPTODATA,
870 struct EccAliceCryptodataMessage,
871 s),
872 GNUNET_MQ_handler_end ()
873 };
874 uint32_t contained_count;
875 uint32_t total_count;
876 const struct GNUNET_SCALARPRODUCT_Element *elements;
877 struct GNUNET_SETI_Element set_elem;
878 struct GNUNET_SCALARPRODUCT_Element *elem;
879
880 total_count = ntohl (msg->element_count_total);
881 contained_count = ntohl (msg->element_count_contained);
882
883 s->status = GNUNET_SCALARPRODUCT_STATUS_ACTIVE;
884 s->total = total_count;
885 s->client_received_element_count = contained_count;
886 s->session_id = msg->session_key;
887 elements = (const struct GNUNET_SCALARPRODUCT_Element *) &msg[1];
888 s->intersected_elements
889 = GNUNET_CONTAINER_multihashmap_create (s->total,
890 GNUNET_YES);
891 s->intersection_set = GNUNET_SETI_create (cfg);
892 for (uint32_t i = 0; i < contained_count; i++)
893 {
894 if (0 == GNUNET_ntohll (elements[i].value))
895 continue;
896 elem = GNUNET_new (struct GNUNET_SCALARPRODUCT_Element);
897 GNUNET_memcpy (elem,
898 &elements[i],
899 sizeof(struct GNUNET_SCALARPRODUCT_Element));
900 if (GNUNET_SYSERR ==
901 GNUNET_CONTAINER_multihashmap_put (s->intersected_elements,
902 &elem->key,
903 elem,
904 GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY))
905 {
906 GNUNET_break (0);
907 GNUNET_free (elem);
908 continue;
909 }
910 set_elem.data = &elem->key;
911 set_elem.size = sizeof(elem->key);
912 set_elem.element_type = 0;
913 GNUNET_SETI_add_element (s->intersection_set,
914 &set_elem,
915 NULL, NULL);
916 s->used_element_count++;
917 }
918 GNUNET_SERVICE_client_continue (s->client);
919 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
920 "Received client request, opening port %s!\n",
921 GNUNET_h2s (&msg->session_key));
922 s->port = GNUNET_CADET_open_port (my_cadet,
923 &msg->session_key,
924 &cb_channel_incoming,
925 s,
926 NULL,
927 &cb_channel_destruction,
928 cadet_handlers);
929 if (NULL == s->port)
930 {
931 GNUNET_break (0);
932 GNUNET_SERVICE_client_drop (s->client);
933 return;
934 }
935}
936
937
938/**
939 * Task run during shutdown.
940 *
941 * @param cls unused
942 */
943static void
944shutdown_task (void *cls)
945{
946 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
947 "Shutting down, initiating cleanup.\n");
948 // FIXME: we have to cut our connections to CADET first!
949 if (NULL != my_cadet)
950 {
951 GNUNET_CADET_disconnect (my_cadet);
952 my_cadet = NULL;
953 }
954 if (NULL != edc)
955 {
956 GNUNET_CRYPTO_ecc_dlog_release (edc);
957 edc = NULL;
958 }
959}
960
961
962/**
963 * A client connected.
964 *
965 * Setup the associated data structure.
966 *
967 * @param cls closure, NULL
968 * @param client identification of the client
969 * @param mq message queue to communicate with @a client
970 * @return our `struct BobServiceSession`
971 */
972static void *
973client_connect_cb (void *cls,
974 struct GNUNET_SERVICE_Client *client,
975 struct GNUNET_MQ_Handle *mq)
976{
977 struct BobServiceSession *s;
978
979 s = GNUNET_new (struct BobServiceSession);
980 s->client = client;
981 s->client_mq = mq;
982 return s;
983}
984
985
986/**
987 * A client disconnected.
988 *
989 * Remove the associated session(s), release data structures
990 * and cancel pending outgoing transmissions to the client.
991 *
992 * @param cls closure, NULL
993 * @param client identification of the client
994 * @param app_cls our `struct BobServiceSession`
995 */
996static void
997client_disconnect_cb (void *cls,
998 struct GNUNET_SERVICE_Client *client,
999 void *app_cls)
1000{
1001 struct BobServiceSession *s = app_cls;
1002
1003 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1004 "Client disconnected from us.\n");
1005 s->client = NULL;
1006 destroy_service_session (s);
1007}
1008
1009
1010/**
1011 * Initialization of the program and message handlers
1012 *
1013 * @param cls closure
1014 * @param c configuration to use
1015 * @param service the initialized service
1016 */
1017static void
1018run (void *cls,
1019 const struct GNUNET_CONFIGURATION_Handle *c,
1020 struct GNUNET_SERVICE_Handle *service)
1021{
1022 cfg = c;
1023 /* We don't really do DLOG, so we can setup with very minimal resources */
1024 edc = GNUNET_CRYPTO_ecc_dlog_prepare (4 /* max value */,
1025 2 /* RAM */);
1026 my_cadet = GNUNET_CADET_connect (cfg);
1027 GNUNET_SCHEDULER_add_shutdown (&shutdown_task,
1028 NULL);
1029 if (NULL == my_cadet)
1030 {
1031 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1032 _ ("Connect to CADET failed\n"));
1033 GNUNET_SCHEDULER_shutdown ();
1034 return;
1035 }
1036}
1037
1038
1039/**
1040 * Define "main" method using service macro.
1041 */
1042GNUNET_SERVICE_MAIN
1043 ("scalarproduct-bob",
1044 GNUNET_SERVICE_OPTION_NONE,
1045 &run,
1046 &client_connect_cb,
1047 &client_disconnect_cb,
1048 NULL,
1049 GNUNET_MQ_hd_var_size (bob_client_message,
1050 GNUNET_MESSAGE_TYPE_SCALARPRODUCT_CLIENT_TO_BOB,
1051 struct BobComputationMessage,
1052 NULL),
1053 GNUNET_MQ_hd_var_size (bob_client_message_multipart,
1054 GNUNET_MESSAGE_TYPE_SCALARPRODUCT_CLIENT_MULTIPART_BOB,
1055 struct ComputationBobCryptodataMultipartMessage,
1056 NULL),
1057 GNUNET_MQ_handler_end ());
1058
1059
1060/* end of gnunet-service-scalarproduct-ecc_bob.c */