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