diff options
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.c | 1150 |
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 | */ | ||
61 | struct 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 | */ | ||
81 | struct 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 | */ | ||
184 | static const struct GNUNET_CONFIGURATION_Handle *cfg; | ||
185 | |||
186 | /** | ||
187 | * Context for DLOG operations on a curve. | ||
188 | */ | ||
189 | static struct GNUNET_CRYPTO_EccDlogContext *edc; | ||
190 | |||
191 | /** | ||
192 | * Alice's private key ('a'). | ||
193 | */ | ||
194 | static struct GNUNET_CRYPTO_EccScalar my_privkey; | ||
195 | |||
196 | /** | ||
197 | * Inverse of Alice's private key ('a_inv'). | ||
198 | */ | ||
199 | static struct GNUNET_CRYPTO_EccScalar my_privkey_inv; | ||
200 | |||
201 | /** | ||
202 | * Handle to the CADET service. | ||
203 | */ | ||
204 | static 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 | */ | ||
215 | static int | ||
216 | free_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 | */ | ||
232 | static void | ||
233 | destroy_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 | */ | ||
290 | static void | ||
291 | prepare_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 | */ | ||
318 | static void | ||
319 | transmit_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 | */ | ||
396 | static void | ||
397 | cb_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 | */ | ||
423 | static void | ||
424 | handle_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 | */ | ||
490 | static int | ||
491 | copy_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 | */ | ||
513 | static int | ||
514 | element_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 | */ | ||
541 | static void | ||
542 | send_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 | ©_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 | */ | ||
645 | static void | ||
646 | cb_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 | */ | ||
721 | static void | ||
722 | cb_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 | */ | ||
767 | static void | ||
768 | client_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 | */ | ||
831 | static int | ||
832 | check_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 | */ | ||
863 | static void | ||
864 | handle_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 | */ | ||
920 | static int | ||
921 | check_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 | */ | ||
958 | static void | ||
959 | handle_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 | */ | ||
1028 | static void | ||
1029 | shutdown_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 | */ | ||
1057 | static void * | ||
1058 | client_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 | */ | ||
1081 | static void | ||
1082 | client_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 | */ | ||
1104 | static void | ||
1105 | run (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 | */ | ||
1131 | GNUNET_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 */ | ||