aboutsummaryrefslogtreecommitdiff
path: root/src/scalarproduct/gnunet-service-scalarproduct-ecc_alice.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/scalarproduct/gnunet-service-scalarproduct-ecc_alice.c')
-rw-r--r--src/scalarproduct/gnunet-service-scalarproduct-ecc_alice.c1149
1 files changed, 0 insertions, 1149 deletions
diff --git a/src/scalarproduct/gnunet-service-scalarproduct-ecc_alice.c b/src/scalarproduct/gnunet-service-scalarproduct-ecc_alice.c
deleted file mode 100644
index dc43b5a54..000000000
--- a/src/scalarproduct/gnunet-service-scalarproduct-ecc_alice.c
+++ /dev/null
@@ -1,1149 +0,0 @@
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_alice.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, ...) \
40 GNUNET_log_from (kind, "scalarproduct-alice", __VA_ARGS__)
41
42/**
43 * Maximum allowed result value for the scalarproduct computation.
44 * DLOG will fail if the result is bigger. At 1 million, the
45 * precomputation takes about 2s on a fast machine.
46 */
47#define MAX_RESULT (1024 * 1024)
48
49/**
50 * How many values should DLOG store in memory (determines baseline
51 * RAM consumption, roughly 100 bytes times the value given here).
52 * Should be about SQRT (MAX_RESULT), larger values will make the
53 * online computation faster.
54 */
55#define MAX_RAM (1024)
56
57/**
58 * An encrypted element key-value pair.
59 */
60struct MpiElement
61{
62 /**
63 * Key used to identify matching pairs of values to multiply.
64 * Points into an existing data structure, to avoid copying
65 * and doubling memory use.
66 */
67 const struct GNUNET_HashCode *key;
68
69 /**
70 * a_i value, not disclosed to Bob.
71 */
72 int64_t value;
73};
74
75
76/**
77 * A scalarproduct session which tracks
78 * a request form the client to our final response.
79 */
80struct AliceServiceSession
81{
82 /**
83 * (hopefully) unique transaction ID
84 */
85 struct GNUNET_HashCode session_id;
86
87 /**
88 * Alice or Bob's peerID
89 */
90 struct GNUNET_PeerIdentity peer;
91
92 /**
93 * The client this request is related to.
94 */
95 struct GNUNET_SERVICE_Client *client;
96
97 /**
98 * The message queue for the client.
99 */
100 struct GNUNET_MQ_Handle *client_mq;
101
102 /**
103 * The message queue for CADET.
104 */
105 struct GNUNET_MQ_Handle *cadet_mq;
106
107 /**
108 * all non-0-value'd elements transmitted to us.
109 * Values are of type `struct GNUNET_SCALARPRODUCT_Element *`
110 */
111 struct GNUNET_CONTAINER_MultiHashMap *intersected_elements;
112
113 /**
114 * Set of elements for which will conduction an intersection.
115 * the resulting elements are then used for computing the scalar product.
116 */
117 struct GNUNET_SETI_Handle *intersection_set;
118
119 /**
120 * Set of elements for which will conduction an intersection.
121 * the resulting elements are then used for computing the scalar product.
122 */
123 struct GNUNET_SETI_OperationHandle *intersection_op;
124
125 /**
126 * Handle to Alice's Intersection operation listening for Bob
127 */
128 struct GNUNET_SETI_ListenHandle *intersection_listen;
129
130 /**
131 * channel-handle associated with our cadet handle
132 */
133 struct GNUNET_CADET_Channel *channel;
134
135 /**
136 * a(Alice), sorted array by key of length @e used_element_count.
137 */
138 struct MpiElement *sorted_elements;
139
140 /**
141 * The computed scalar product. INT_MAX if the computation failed.
142 */
143 int product;
144
145 /**
146 * How many elements we were supplied with from the client (total
147 * count before intersection).
148 */
149 uint32_t total;
150
151 /**
152 * How many elements actually are used for the scalar product.
153 * Size of the arrays in @e r and @e r_prime. Sometimes also
154 * reset to 0 and used as a counter!
155 */
156 uint32_t used_element_count;
157
158 /**
159 * Already transferred elements from client to us.
160 * Less or equal than @e total.
161 */
162 uint32_t client_received_element_count;
163
164 /**
165 * State of this session. In
166 * #GNUNET_SCALARPRODUCT_STATUS_ACTIVE while operation is
167 * ongoing, afterwards in #GNUNET_SCALARPRODUCT_STATUS_SUCCESS or
168 * #GNUNET_SCALARPRODUCT_STATUS_FAILURE.
169 */
170 enum GNUNET_SCALARPRODUCT_ResponseStatus status;
171
172 /**
173 * Flag to prevent recursive calls to #destroy_service_session() from
174 * doing harm.
175 */
176 int in_destroy;
177};
178
179
180/**
181 * GNUnet configuration handle
182 */
183static const struct GNUNET_CONFIGURATION_Handle *cfg;
184
185/**
186 * Context for DLOG operations on a curve.
187 */
188static struct GNUNET_CRYPTO_EccDlogContext *edc;
189
190/**
191 * Alice's private key ('a').
192 */
193static struct GNUNET_CRYPTO_EccScalar my_privkey;
194
195/**
196 * Inverse of Alice's private key ('a_inv').
197 */
198static struct GNUNET_CRYPTO_EccScalar my_privkey_inv;
199
200/**
201 * Handle to the CADET service.
202 */
203static struct GNUNET_CADET_Handle *my_cadet;
204
205
206/**
207 * Iterator called to free elements.
208 *
209 * @param cls the `struct AliceServiceSession *` (unused)
210 * @param key the key (unused)
211 * @param value value to free
212 * @return #GNUNET_OK (continue to iterate)
213 */
214static int
215free_element_cb (void *cls,
216 const struct GNUNET_HashCode *key,
217 void *value)
218{
219 struct GNUNET_SCALARPRODUCT_Element *e = value;
220
221 GNUNET_free (e);
222 return GNUNET_OK;
223}
224
225
226/**
227 * Destroy session state, we are done with it.
228 *
229 * @param s the session to free elements from
230 */
231static void
232destroy_service_session (struct AliceServiceSession *s)
233{
234 if (GNUNET_YES == s->in_destroy)
235 return;
236 s->in_destroy = GNUNET_YES;
237 if (NULL != s->client)
238 {
239 struct GNUNET_SERVICE_Client *c = s->client;
240
241 s->client = NULL;
242 GNUNET_SERVICE_client_drop (c);
243 }
244 if (NULL != s->channel)
245 {
246 GNUNET_CADET_channel_destroy (s->channel);
247 s->channel = NULL;
248 }
249 if (NULL != s->intersected_elements)
250 {
251 GNUNET_CONTAINER_multihashmap_iterate (s->intersected_elements,
252 &free_element_cb,
253 s);
254 GNUNET_CONTAINER_multihashmap_destroy (s->intersected_elements);
255 s->intersected_elements = NULL;
256 }
257 if (NULL != s->intersection_listen)
258 {
259 GNUNET_SETI_listen_cancel (s->intersection_listen);
260 s->intersection_listen = NULL;
261 }
262 if (NULL != s->intersection_op)
263 {
264 LOG (GNUNET_ERROR_TYPE_DEBUG,
265 "Set intersection, op still ongoing!\n");
266 GNUNET_SETI_operation_cancel (s->intersection_op);
267 s->intersection_op = NULL;
268 }
269 if (NULL != s->intersection_set)
270 {
271 GNUNET_SETI_destroy (s->intersection_set);
272 s->intersection_set = NULL;
273 }
274 if (NULL != s->sorted_elements)
275 {
276 GNUNET_free (s->sorted_elements);
277 s->sorted_elements = NULL;
278 }
279 GNUNET_free (s);
280}
281
282
283/**
284 * Notify the client that the session has failed. A message gets sent
285 * to Alice's client if we encountered any error.
286 *
287 * @param session the associated client session to fail or succeed
288 */
289static void
290prepare_client_end_notification (struct AliceServiceSession *session)
291{
292 struct ClientResponseMessage *msg;
293 struct GNUNET_MQ_Envelope *e;
294
295 if (NULL == session->client_mq)
296 return; /* no client left to be notified */
297 GNUNET_log (
298 GNUNET_ERROR_TYPE_DEBUG,
299 "Sending session-end notification with status %d to client for session %s\n",
300 session->status,
301 GNUNET_h2s (&session->session_id));
302 e = GNUNET_MQ_msg (msg,
303 GNUNET_MESSAGE_TYPE_SCALARPRODUCT_RESULT);
304 msg->product_length = htonl (0);
305 msg->status = htonl (session->status);
306 GNUNET_MQ_send (session->client_mq,
307 e);
308}
309
310
311/**
312 * Prepare the final (positive) response we will send to Alice's
313 * client.
314 *
315 * @param s the session associated with our client.
316 */
317static void
318transmit_client_response (struct AliceServiceSession *s)
319{
320 struct ClientResponseMessage *msg;
321 struct GNUNET_MQ_Envelope *e;
322 unsigned char *product_exported = NULL;
323 size_t product_length = 0;
324 int32_t range;
325 gcry_error_t rc;
326 gcry_mpi_t value;
327
328 if (INT_MAX == s->product)
329 {
330 GNUNET_break (0);
331 prepare_client_end_notification (s);
332 return;
333 }
334 value = gcry_mpi_new (32);
335 if (0 > s->product)
336 {
337 range = -1;
338 gcry_mpi_set_ui (value,
339 -s->product);
340 }
341 else if (0 < s->product)
342 {
343 range = 1;
344 gcry_mpi_set_ui (value,
345 s->product);
346 }
347 else
348 {
349 /* result is exactly zero */
350 range = 0;
351 }
352 if ( (0 != range) &&
353 (0 != (rc = gcry_mpi_aprint (GCRYMPI_FMT_STD,
354 &product_exported,
355 &product_length,
356 value))))
357 {
358 LOG_GCRY (GNUNET_ERROR_TYPE_ERROR,
359 "gcry_mpi_scan",
360 rc);
361 prepare_client_end_notification (s);
362 return;
363 }
364 gcry_mpi_release (value);
365 e = GNUNET_MQ_msg_extra (msg,
366 product_length,
367 GNUNET_MESSAGE_TYPE_SCALARPRODUCT_RESULT);
368 msg->status = htonl (GNUNET_SCALARPRODUCT_STATUS_SUCCESS);
369 msg->range = htonl (range);
370 msg->product_length = htonl (product_length);
371 if (NULL != product_exported)
372 {
373 GNUNET_memcpy (&msg[1],
374 product_exported,
375 product_length);
376 GNUNET_free (product_exported);
377 }
378 GNUNET_MQ_send (s->client_mq,
379 e);
380 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
381 "Sent result to client, session %s has ended!\n",
382 GNUNET_h2s (&s->session_id));
383}
384
385
386/**
387 * Function called whenever a channel is destroyed. Should clean up
388 * any associated state.
389 *
390 * It must NOT call #GNUNET_CADET_channel_destroy() on the channel.
391 *
392 * @param cls the `struct AliceServiceSession`
393 * @param channel connection to the other end (henceforth invalid)
394 */
395static void
396cb_channel_destruction (void *cls,
397 const struct GNUNET_CADET_Channel *channel)
398{
399 struct AliceServiceSession *s = cls;
400
401 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
402 "Peer disconnected, terminating session %s with peer %s\n",
403 GNUNET_h2s (&s->session_id),
404 GNUNET_i2s (&s->peer));
405 s->channel = NULL;
406 if (GNUNET_SCALARPRODUCT_STATUS_ACTIVE == s->status)
407 {
408 /* We didn't get an answer yet, fail with error */
409 s->status = GNUNET_SCALARPRODUCT_STATUS_FAILURE;
410 prepare_client_end_notification (s);
411 }
412}
413
414
415/**
416 * Handle a response we got from another service we wanted to
417 * calculate a scalarproduct with.
418 *
419 * @param cls the `struct AliceServiceSession *`
420 * @param msg the actual message
421 */
422static void
423handle_bobs_cryptodata_message (void *cls,
424 const struct EccBobCryptodataMessage *msg)
425{
426 struct AliceServiceSession *s = cls;
427 uint32_t contained;
428
429 contained = ntohl (msg->contained_element_count);
430 if (2 != contained)
431 {
432 GNUNET_break_op (0);
433 destroy_service_session (s);
434 return;
435 }
436 if (NULL == s->sorted_elements)
437 {
438 /* we're not ready yet, how can Bob be? */
439 GNUNET_break_op (0);
440 destroy_service_session (s);
441 return;
442 }
443 if (s->total != s->client_received_element_count)
444 {
445 /* we're not ready yet, how can Bob be? */
446 GNUNET_break_op (0);
447 destroy_service_session (s);
448 return;
449 }
450 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
451 "Received %u crypto values from Bob\n",
452 (unsigned int) contained);
453 GNUNET_CADET_receive_done (s->channel);
454 {
455 struct GNUNET_CRYPTO_EccPoint g_i_b_i_a_inv;
456 struct GNUNET_CRYPTO_EccPoint g_ai_bi;
457
458 GNUNET_assert (
459 GNUNET_OK ==
460 GNUNET_CRYPTO_ecc_pmul_mpi (&msg->prod_g_i_b_i,
461 &my_privkey_inv,
462 &g_i_b_i_a_inv));
463 GNUNET_assert (
464 GNUNET_OK ==
465 GNUNET_CRYPTO_ecc_add (&g_i_b_i_a_inv,
466 &msg->prod_h_i_b_i,
467 &g_ai_bi));
468 s->product = GNUNET_CRYPTO_ecc_dlog (edc,
469 &g_ai_bi);
470 if (INT_MAX == s->product)
471 {
472 /* result too big */
473 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
474 "Scalar product result out of range\n");
475 }
476 }
477 transmit_client_response (s);
478}
479
480
481/**
482 * Iterator to copy over messages from the hash map
483 * into an array for sorting.
484 *
485 * @param cls the `struct AliceServiceSession *`
486 * @param key the key (unused)
487 * @param value the `struct GNUNET_SCALARPRODUCT_Element *`
488 */
489static int
490copy_element_cb (void *cls,
491 const struct GNUNET_HashCode *key,
492 void *value)
493{
494 struct AliceServiceSession *s = cls;
495 struct GNUNET_SCALARPRODUCT_Element *e = value;
496
497 s->sorted_elements[s->used_element_count].value = (int64_t) GNUNET_ntohll (
498 e->value);
499 s->sorted_elements[s->used_element_count].key = &e->key;
500 s->used_element_count++;
501 return GNUNET_OK;
502}
503
504
505/**
506 * Compare two `struct MpiValue`s by key for sorting.
507 *
508 * @param a pointer to first `struct MpiValue *`
509 * @param b pointer to first `struct MpiValue *`
510 * @return -1 for a < b, 0 for a=b, 1 for a > b.
511 */
512static int
513element_cmp (const void *a,
514 const void *b)
515{
516 const struct MpiElement *ma = a;
517 const struct MpiElement *mb = b;
518
519 return GNUNET_CRYPTO_hash_cmp (ma->key,
520 mb->key);
521}
522
523
524/**
525 * Maximum number of elements we can put into a single cryptodata
526 * message
527 */
528#define ELEMENT_CAPACITY \
529 ((GNUNET_CONSTANTS_MAX_CADET_MESSAGE_SIZE - 1 \
530 - sizeof(struct EccAliceCryptodataMessage)) \
531 / sizeof(struct GNUNET_CRYPTO_EccPoint))
532
533
534/**
535 * Send the cryptographic data from Alice to Bob.
536 * Does nothing if we already transferred all elements.
537 *
538 * @param s the associated service session
539 */
540static void
541send_alices_cryptodata_message (struct AliceServiceSession *s)
542{
543 struct EccAliceCryptodataMessage *msg;
544 struct GNUNET_MQ_Envelope *e;
545 struct GNUNET_CRYPTO_EccPoint *payload;
546 struct GNUNET_CRYPTO_EccScalar r_ia;
547 struct GNUNET_CRYPTO_EccScalar r_ia_ai;
548 unsigned int off;
549 unsigned int todo_count;
550
551 s->sorted_elements = GNUNET_new_array (GNUNET_CONTAINER_multihashmap_size (
552 s->intersected_elements),
553 struct MpiElement);
554 s->used_element_count = 0;
555 GNUNET_CONTAINER_multihashmap_iterate (s->intersected_elements,
556 &copy_element_cb,
557 s);
558 LOG (GNUNET_ERROR_TYPE_DEBUG,
559 "Finished intersection, %d items remain\n",
560 s->used_element_count);
561 qsort (s->sorted_elements,
562 s->used_element_count,
563 sizeof(struct MpiElement),
564 &element_cmp);
565 off = 0;
566 while (off < s->used_element_count)
567 {
568 todo_count = s->used_element_count - off;
569 if (todo_count > ELEMENT_CAPACITY)
570 todo_count = ELEMENT_CAPACITY;
571 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
572 "Sending %u/%u crypto values to Bob\n",
573 (unsigned int) todo_count,
574 (unsigned int) s->used_element_count);
575
576 e =
577 GNUNET_MQ_msg_extra (msg,
578 todo_count * 2
579 * sizeof(struct GNUNET_CRYPTO_EccPoint),
580 GNUNET_MESSAGE_TYPE_SCALARPRODUCT_ECC_ALICE_CRYPTODATA);
581 msg->contained_element_count = htonl (todo_count);
582 payload = (struct GNUNET_CRYPTO_EccPoint *) &msg[1];
583 for (unsigned int i = off; i < off + todo_count; i++)
584 {
585 struct GNUNET_CRYPTO_EccScalar r_i;
586 struct GNUNET_CRYPTO_EccPoint g_i;
587 struct GNUNET_CRYPTO_EccPoint h_i;
588
589 /* r_i = random() mod n */
590 GNUNET_CRYPTO_ecc_random_mod_n (&r_i);
591 /* g_i = g^{r_i} */
592 GNUNET_assert (GNUNET_OK ==
593 GNUNET_CRYPTO_ecc_dexp_mpi (&r_i,
594 &g_i));
595 /* r_ia = r_i * a */
596 crypto_core_ed25519_scalar_mul (r_ia.v,
597 r_i.v,
598 my_privkey.v);
599 /* r_ia_ai = r_ia + a_i */
600 {
601 int64_t val = s->sorted_elements[i].value;
602 struct GNUNET_CRYPTO_EccScalar vali;
603
604 GNUNET_assert (INT64_MIN != val);
605 GNUNET_CRYPTO_ecc_scalar_from_int (val > 0 ? val : -val,
606 &vali);
607 if (val > 0)
608 crypto_core_ed25519_scalar_add (r_ia_ai.v,
609 r_ia.v,
610 vali.v);
611 else
612 crypto_core_ed25519_scalar_sub (r_ia_ai.v,
613 r_ia.v,
614 vali.v);
615 }
616 /* h_i = g^{r_ia_ai} */
617 GNUNET_assert (GNUNET_OK ==
618 GNUNET_CRYPTO_ecc_dexp_mpi (&r_ia_ai,
619 &h_i));
620 memcpy (&payload[(i - off) * 2],
621 &g_i,
622 sizeof (g_i));
623 memcpy (&payload[(i - off) * 2 + 1],
624 &h_i,
625 sizeof (h_i));
626 }
627 off += todo_count;
628 GNUNET_MQ_send (s->cadet_mq,
629 e);
630 }
631}
632
633
634/**
635 * Callback for set operation results. Called for each element
636 * that should be removed from the result set, and then once
637 * to indicate that the set intersection operation is done.
638 *
639 * @param cls closure with the `struct AliceServiceSession`
640 * @param element a result element, only valid if status is #GNUNET_SETI_STATUS_OK
641 * @param current_size current set size
642 * @param status what has happened with the set intersection?
643 */
644static void
645cb_intersection_element_removed (void *cls,
646 const struct GNUNET_SETI_Element *element,
647 uint64_t current_size,
648 enum GNUNET_SETI_Status status)
649{
650 struct AliceServiceSession *s = cls;
651 struct GNUNET_SCALARPRODUCT_Element *se;
652
653 switch (status)
654 {
655 case GNUNET_SETI_STATUS_DEL_LOCAL:
656 /* this element has been removed from the set */
657 se = GNUNET_CONTAINER_multihashmap_get (s->intersected_elements,
658 element->data);
659 GNUNET_assert (NULL != se);
660 LOG (GNUNET_ERROR_TYPE_DEBUG,
661 "Intersection removed element with key %s and value %lld\n",
662 GNUNET_h2s (&se->key),
663 (long long) GNUNET_ntohll (se->value));
664 GNUNET_assert (
665 GNUNET_YES ==
666 GNUNET_CONTAINER_multihashmap_remove (s->intersected_elements,
667 element->data,
668 se));
669 GNUNET_free (se);
670 return;
671 case GNUNET_SETI_STATUS_DONE:
672 s->intersection_op = NULL;
673 if (NULL != s->intersection_set)
674 {
675 GNUNET_SETI_destroy (s->intersection_set);
676 s->intersection_set = NULL;
677 }
678 send_alices_cryptodata_message (s);
679 return;
680 case GNUNET_SETI_STATUS_FAILURE:
681 /* unhandled status code */
682 LOG (GNUNET_ERROR_TYPE_DEBUG, "Set intersection failed!\n");
683 if (NULL != s->intersection_listen)
684 {
685 GNUNET_SETI_listen_cancel (s->intersection_listen);
686 s->intersection_listen = NULL;
687 }
688 s->intersection_op = NULL;
689 if (NULL != s->intersection_set)
690 {
691 GNUNET_SETI_destroy (s->intersection_set);
692 s->intersection_set = NULL;
693 }
694 s->status = GNUNET_SCALARPRODUCT_STATUS_FAILURE;
695 prepare_client_end_notification (s);
696 return;
697
698 default:
699 GNUNET_break (0);
700 return;
701 }
702}
703
704
705/**
706 * Called when another peer wants to do a set operation with the
707 * local peer. If a listen error occurs, the @a request is NULL.
708 *
709 * @param cls closure with the `struct AliceServiceSession *`
710 * @param other_peer the other peer
711 * @param context_msg message with application specific information from
712 * the other peer
713 * @param request request from the other peer (never NULL), use GNUNET_SETI_accept()
714 * to accept it, otherwise the request will be refused
715 * Note that we can't just return value from the listen callback,
716 * as it is also necessary to specify the set we want to do the
717 * operation with, which sometimes can be derived from the context
718 * message. It's necessary to specify the timeout.
719 */
720static void
721cb_intersection_request_alice (void *cls,
722 const struct GNUNET_PeerIdentity *other_peer,
723 const struct GNUNET_MessageHeader *context_msg,
724 struct GNUNET_SETI_Request *request)
725{
726 struct AliceServiceSession *s = cls;
727
728 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
729 "Received intersection request from %s!\n",
730 GNUNET_i2s (other_peer));
731 if (0 != GNUNET_memcmp (other_peer,
732 &s->peer))
733 {
734 GNUNET_break_op (0);
735 return;
736 }
737 s->intersection_op
738 = GNUNET_SETI_accept (request,
739 (struct GNUNET_SETI_Option[]){ { 0 } },
740 &cb_intersection_element_removed,
741 s);
742 if (NULL == s->intersection_op)
743 {
744 GNUNET_break (0);
745 s->status = GNUNET_SCALARPRODUCT_STATUS_FAILURE;
746 prepare_client_end_notification (s);
747 return;
748 }
749 if (GNUNET_OK !=
750 GNUNET_SETI_commit (s->intersection_op,
751 s->intersection_set))
752 {
753 GNUNET_break (0);
754 s->status = GNUNET_SCALARPRODUCT_STATUS_FAILURE;
755 prepare_client_end_notification (s);
756 return;
757 }
758}
759
760
761/**
762 * Our client has finished sending us its multipart message.
763 *
764 * @param session the service session context
765 */
766static void
767client_request_complete_alice (struct AliceServiceSession *s)
768{
769 struct GNUNET_MQ_MessageHandler cadet_handlers[] = {
770 GNUNET_MQ_hd_fixed_size (bobs_cryptodata_message,
771 GNUNET_MESSAGE_TYPE_SCALARPRODUCT_ECC_BOB_CRYPTODATA,
772 struct EccBobCryptodataMessage,
773 s),
774 GNUNET_MQ_handler_end ()
775 };
776 struct EccServiceRequestMessage *msg;
777 struct GNUNET_MQ_Envelope *e;
778 struct GNUNET_HashCode set_sid;
779
780 GNUNET_CRYPTO_hash (&s->session_id,
781 sizeof(struct GNUNET_HashCode),
782 &set_sid);
783 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
784 "Creating new channel for session with key %s.\n",
785 GNUNET_h2s (&s->session_id));
786 s->channel = GNUNET_CADET_channel_create (my_cadet,
787 s,
788 &s->peer,
789 &s->session_id,
790 NULL,
791 &cb_channel_destruction,
792 cadet_handlers);
793 if (NULL == s->channel)
794 {
795 s->status = GNUNET_SCALARPRODUCT_STATUS_FAILURE;
796 prepare_client_end_notification (s);
797 return;
798 }
799 s->cadet_mq = GNUNET_CADET_get_mq (s->channel);
800 s->intersection_listen = GNUNET_SETI_listen (cfg,
801 &set_sid,
802 &cb_intersection_request_alice,
803 s);
804 if (NULL == s->intersection_listen)
805 {
806 s->status = GNUNET_SCALARPRODUCT_STATUS_FAILURE;
807 GNUNET_CADET_channel_destroy (s->channel);
808 s->channel = NULL;
809 prepare_client_end_notification (s);
810 return;
811 }
812
813 e =
814 GNUNET_MQ_msg (msg,
815 GNUNET_MESSAGE_TYPE_SCALARPRODUCT_ECC_SESSION_INITIALIZATION);
816 GNUNET_MQ_env_set_options (e, GNUNET_MQ_PRIO_CRITICAL_CONTROL);
817 msg->session_id = s->session_id;
818 GNUNET_MQ_send (s->cadet_mq, e);
819}
820
821
822/**
823 * We're receiving additional set data. Check if
824 * @a msg is well-formed.
825 *
826 * @param cls client identification of the client
827 * @param msg the actual message
828 * @return #GNUNET_OK if @a msg is well-formed
829 */
830static int
831check_alice_client_message_multipart (
832 void *cls,
833 const struct ComputationBobCryptodataMultipartMessage *msg)
834{
835 struct AliceServiceSession *s = cls;
836 uint32_t contained_count;
837 uint16_t msize;
838
839 msize = ntohs (msg->header.size);
840 contained_count = ntohl (msg->element_count_contained);
841 if ((msize !=
842 (sizeof(struct ComputationBobCryptodataMultipartMessage)
843 + contained_count * sizeof(struct GNUNET_SCALARPRODUCT_Element))) ||
844 (0 == contained_count) ||
845 (s->total == s->client_received_element_count) ||
846 (s->total < s->client_received_element_count + contained_count))
847 {
848 GNUNET_break_op (0);
849 return GNUNET_SYSERR;
850 }
851 return GNUNET_OK;
852}
853
854
855/**
856 * We're receiving additional set data. Add it to our
857 * set and if we are done, initiate the transaction.
858 *
859 * @param cls client identification of the client
860 * @param msg the actual message
861 */
862static void
863handle_alice_client_message_multipart (
864 void *cls,
865 const struct ComputationBobCryptodataMultipartMessage *msg)
866{
867 struct AliceServiceSession *s = cls;
868 uint32_t contained_count;
869 const struct GNUNET_SCALARPRODUCT_Element *elements;
870 struct GNUNET_SETI_Element set_elem;
871 struct GNUNET_SCALARPRODUCT_Element *elem;
872
873 contained_count = ntohl (msg->element_count_contained);
874 s->client_received_element_count += contained_count;
875 elements = (const struct GNUNET_SCALARPRODUCT_Element *) &msg[1];
876 for (uint32_t i = 0; i < contained_count; i++)
877 {
878 elem = GNUNET_new (struct GNUNET_SCALARPRODUCT_Element);
879 GNUNET_memcpy (elem,
880 &elements[i],
881 sizeof(struct GNUNET_SCALARPRODUCT_Element));
882 if (GNUNET_SYSERR == GNUNET_CONTAINER_multihashmap_put (
883 s->intersected_elements,
884 &elem->key,
885 elem,
886 GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY))
887 {
888 GNUNET_break (0);
889 GNUNET_free (elem);
890 continue;
891 }
892 set_elem.data = &elem->key;
893 set_elem.size = sizeof(elem->key);
894 set_elem.element_type = 0;
895 GNUNET_SETI_add_element (s->intersection_set, &set_elem, NULL, NULL);
896 s->used_element_count++;
897 }
898 GNUNET_SERVICE_client_continue (s->client);
899 if (s->total != s->client_received_element_count)
900 {
901 /* more to come */
902 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
903 "Received client multipart data, waiting for more!\n");
904 return;
905 }
906 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Launching computation\n");
907 client_request_complete_alice (s);
908}
909
910
911/**
912 * Handler for Alice's client request message.
913 * Check that @a msg is well-formed.
914 *
915 * @param cls identification of the client
916 * @param msg the actual message
917 * @return #GNUNET_OK if @a msg is well-formed
918 */
919static int
920check_alice_client_message (void *cls,
921 const struct AliceComputationMessage *msg)
922{
923 struct AliceServiceSession *s = cls;
924 uint16_t msize;
925 uint32_t total_count;
926 uint32_t contained_count;
927
928 if (NULL != s->intersected_elements)
929 {
930 /* only one concurrent session per client connection allowed,
931 simplifies logic a lot... */
932 GNUNET_break (0);
933 return GNUNET_SYSERR;
934 }
935 msize = ntohs (msg->header.size);
936 total_count = ntohl (msg->element_count_total);
937 contained_count = ntohl (msg->element_count_contained);
938 if ((0 == total_count) || (0 == contained_count) ||
939 (msize !=
940 (sizeof(struct AliceComputationMessage)
941 + contained_count * sizeof(struct GNUNET_SCALARPRODUCT_Element))))
942 {
943 GNUNET_break_op (0);
944 return GNUNET_SYSERR;
945 }
946 return GNUNET_OK;
947}
948
949
950/**
951 * Handler for Alice's client request message.
952 * We are doing request-initiation to compute a scalar product with a peer.
953 *
954 * @param cls identification of the client
955 * @param msg the actual message
956 */
957static void
958handle_alice_client_message (void *cls,
959 const struct AliceComputationMessage *msg)
960{
961 struct AliceServiceSession *s = cls;
962 uint32_t contained_count;
963 uint32_t total_count;
964 const struct GNUNET_SCALARPRODUCT_Element *elements;
965 struct GNUNET_SETI_Element set_elem;
966 struct GNUNET_SCALARPRODUCT_Element *elem;
967
968 total_count = ntohl (msg->element_count_total);
969 contained_count = ntohl (msg->element_count_contained);
970 s->peer = msg->peer;
971 s->status = GNUNET_SCALARPRODUCT_STATUS_ACTIVE;
972 s->total = total_count;
973 s->client_received_element_count = contained_count;
974 s->session_id = msg->session_key;
975 elements = (const struct GNUNET_SCALARPRODUCT_Element *) &msg[1];
976 s->intersected_elements =
977 GNUNET_CONTAINER_multihashmap_create (s->total,
978 GNUNET_YES);
979 s->intersection_set = GNUNET_SETI_create (cfg);
980 for (uint32_t i = 0; i < contained_count; i++)
981 {
982 if (0 == GNUNET_ntohll (elements[i].value))
983 continue;
984 elem = GNUNET_new (struct GNUNET_SCALARPRODUCT_Element);
985 *elem = elements[i];
986 if (GNUNET_SYSERR ==
987 GNUNET_CONTAINER_multihashmap_put (
988 s->intersected_elements,
989 &elem->key,
990 elem,
991 GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY))
992 {
993 /* element with same key encountered twice! */
994 GNUNET_break (0);
995 GNUNET_free (elem);
996 continue;
997 }
998 set_elem.data = &elem->key;
999 set_elem.size = sizeof(elem->key);
1000 set_elem.element_type = 0;
1001 GNUNET_SETI_add_element (s->intersection_set,
1002 &set_elem,
1003 NULL,
1004 NULL);
1005 s->used_element_count++;
1006 }
1007 GNUNET_SERVICE_client_continue (s->client);
1008 if (s->total != s->client_received_element_count)
1009 {
1010 /* wait for multipart msg */
1011 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1012 "Received partial client request, waiting for more!\n");
1013 return;
1014 }
1015 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1016 "Launching computation\n");
1017 client_request_complete_alice (s);
1018}
1019
1020
1021/**
1022 * Task run during shutdown.
1023 *
1024 * @param cls unused
1025 * @param tc unused
1026 */
1027static void
1028shutdown_task (void *cls)
1029{
1030 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1031 "Shutting down, initiating cleanup.\n");
1032 // FIXME: we have to cut our connections to CADET first!
1033 if (NULL != my_cadet)
1034 {
1035 GNUNET_CADET_disconnect (my_cadet);
1036 my_cadet = NULL;
1037 }
1038 if (NULL != edc)
1039 {
1040 GNUNET_CRYPTO_ecc_dlog_release (edc);
1041 edc = NULL;
1042 }
1043}
1044
1045
1046/**
1047 * A client connected.
1048 *
1049 * Setup the associated data structure.
1050 *
1051 * @param cls closure, NULL
1052 * @param client identification of the client
1053 * @param mq message queue to communicate with @a client
1054 * @return our `struct AliceServiceSession`
1055 */
1056static void *
1057client_connect_cb (void *cls,
1058 struct GNUNET_SERVICE_Client *client,
1059 struct GNUNET_MQ_Handle *mq)
1060{
1061 struct AliceServiceSession *s;
1062
1063 s = GNUNET_new (struct AliceServiceSession);
1064 s->client = client;
1065 s->client_mq = mq;
1066 return s;
1067}
1068
1069
1070/**
1071 * A client disconnected.
1072 *
1073 * Remove the associated session(s), release data structures
1074 * and cancel pending outgoing transmissions to the client.
1075 *
1076 * @param cls closure, NULL
1077 * @param client identification of the client
1078 * @param app_cls our `struct AliceServiceSession`
1079 */
1080static void
1081client_disconnect_cb (void *cls,
1082 struct GNUNET_SERVICE_Client *client,
1083 void *app_cls)
1084{
1085 struct AliceServiceSession *s = app_cls;
1086
1087 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1088 "Client %p disconnected from us.\n",
1089 client);
1090 s->client = NULL;
1091 s->client_mq = NULL;
1092 destroy_service_session (s);
1093}
1094
1095
1096/**
1097 * Initialization of the program and message handlers
1098 *
1099 * @param cls closure
1100 * @param c configuration to use
1101 * @param service the initialized service
1102 */
1103static void
1104run (void *cls,
1105 const struct GNUNET_CONFIGURATION_Handle *c,
1106 struct GNUNET_SERVICE_Handle *service)
1107{
1108 cfg = c;
1109 edc = GNUNET_CRYPTO_ecc_dlog_prepare (MAX_RESULT,
1110 MAX_RAM);
1111 /* Select a random 'a' value for Alice */
1112 GNUNET_CRYPTO_ecc_rnd_mpi (&my_privkey,
1113 &my_privkey_inv);
1114 my_cadet = GNUNET_CADET_connect (cfg);
1115 if (NULL == my_cadet)
1116 {
1117 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1118 _ ("Connect to CADET failed\n"));
1119 GNUNET_SCHEDULER_shutdown ();
1120 return;
1121 }
1122 GNUNET_SCHEDULER_add_shutdown (&shutdown_task,
1123 NULL);
1124}
1125
1126
1127/**
1128 * Define "main" method using service macro.
1129 */
1130GNUNET_SERVICE_MAIN (
1131 "scalarproduct-alice",
1132 GNUNET_SERVICE_OPTION_NONE,
1133 &run,
1134 &client_connect_cb,
1135 &client_disconnect_cb,
1136 NULL,
1137 GNUNET_MQ_hd_var_size (alice_client_message,
1138 GNUNET_MESSAGE_TYPE_SCALARPRODUCT_CLIENT_TO_ALICE,
1139 struct AliceComputationMessage,
1140 NULL),
1141 GNUNET_MQ_hd_var_size (
1142 alice_client_message_multipart,
1143 GNUNET_MESSAGE_TYPE_SCALARPRODUCT_CLIENT_MULTIPART_ALICE,
1144 struct ComputationBobCryptodataMultipartMessage,
1145 NULL),
1146 GNUNET_MQ_handler_end ());
1147
1148
1149/* end of gnunet-service-scalarproduct-ecc_alice.c */