diff options
Diffstat (limited to 'src/contrib/service/scalarproduct/gnunet-service-scalarproduct_bob.c')
-rw-r--r-- | src/contrib/service/scalarproduct/gnunet-service-scalarproduct_bob.c | 1384 |
1 files changed, 1384 insertions, 0 deletions
diff --git a/src/contrib/service/scalarproduct/gnunet-service-scalarproduct_bob.c b/src/contrib/service/scalarproduct/gnunet-service-scalarproduct_bob.c new file mode 100644 index 000000000..65e732675 --- /dev/null +++ b/src/contrib/service/scalarproduct/gnunet-service-scalarproduct_bob.c | |||
@@ -0,0 +1,1384 @@ | |||
1 | /* | ||
2 | This file is part of GNUnet. | ||
3 | Copyright (C) 2013, 2014, 2016 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_bob.c | ||
22 | * @brief scalarproduct service implementation | ||
23 | * @author Christian M. Fuchs | ||
24 | * @author Christian Grothoff | ||
25 | */ | ||
26 | #include "platform.h" | ||
27 | #include <limits.h> | ||
28 | #include <gcrypt.h> | ||
29 | #include "gnunet_util_lib.h" | ||
30 | #include "gnunet_core_service.h" | ||
31 | #include "gnunet_cadet_service.h" | ||
32 | #include "gnunet_applications.h" | ||
33 | #include "gnunet_protocols.h" | ||
34 | #include "gnunet_scalarproduct_service.h" | ||
35 | #include "gnunet_seti_service.h" | ||
36 | #include "scalarproduct.h" | ||
37 | #include "gnunet-service-scalarproduct.h" | ||
38 | #include "gnunet_constants.h" | ||
39 | |||
40 | #define LOG(kind, ...) GNUNET_log_from (kind, "scalarproduct-bob", __VA_ARGS__) | ||
41 | |||
42 | |||
43 | /** | ||
44 | * An encrypted element key-value pair. | ||
45 | */ | ||
46 | struct MpiElement | ||
47 | { | ||
48 | /** | ||
49 | * Key used to identify matching pairs of values to multiply. | ||
50 | * Points into an existing data structure, to avoid copying | ||
51 | * and doubling memory use. | ||
52 | */ | ||
53 | const struct GNUNET_HashCode *key; | ||
54 | |||
55 | /** | ||
56 | * Value represented (a). | ||
57 | */ | ||
58 | gcry_mpi_t value; | ||
59 | }; | ||
60 | |||
61 | |||
62 | /** | ||
63 | * A scalarproduct session which tracks an offer for a | ||
64 | * multiplication service by a local client. | ||
65 | */ | ||
66 | struct BobServiceSession | ||
67 | { | ||
68 | /** | ||
69 | * (hopefully) unique transaction ID | ||
70 | */ | ||
71 | struct GNUNET_HashCode session_id; | ||
72 | |||
73 | /** | ||
74 | * The client this request is related to. | ||
75 | */ | ||
76 | struct GNUNET_SERVICE_Client *client; | ||
77 | |||
78 | /** | ||
79 | * Client message queue. | ||
80 | */ | ||
81 | struct GNUNET_MQ_Handle *client_mq; | ||
82 | |||
83 | /** | ||
84 | * All non-0-value'd elements transmitted to us. | ||
85 | */ | ||
86 | struct GNUNET_CONTAINER_MultiHashMap *intersected_elements; | ||
87 | |||
88 | /** | ||
89 | * Set of elements for which we will be conducting an intersection. | ||
90 | * The resulting elements are then used for computing the scalar product. | ||
91 | */ | ||
92 | struct GNUNET_SETI_Handle *intersection_set; | ||
93 | |||
94 | /** | ||
95 | * Set of elements for which will conduction an intersection. | ||
96 | * the resulting elements are then used for computing the scalar product. | ||
97 | */ | ||
98 | struct GNUNET_SETI_OperationHandle *intersection_op; | ||
99 | |||
100 | /** | ||
101 | * CADET port we are listening on. | ||
102 | */ | ||
103 | struct GNUNET_CADET_Port *port; | ||
104 | |||
105 | /** | ||
106 | * a(Alice) | ||
107 | */ | ||
108 | struct MpiElement *sorted_elements; | ||
109 | |||
110 | /** | ||
111 | * E(ai)(Bob) after applying the mask | ||
112 | */ | ||
113 | struct GNUNET_CRYPTO_PaillierCiphertext *e_a; | ||
114 | |||
115 | /** | ||
116 | * Bob's permutation p of R | ||
117 | */ | ||
118 | struct GNUNET_CRYPTO_PaillierCiphertext *r; | ||
119 | |||
120 | /** | ||
121 | * Bob's permutation q of R | ||
122 | */ | ||
123 | struct GNUNET_CRYPTO_PaillierCiphertext *r_prime; | ||
124 | |||
125 | /** | ||
126 | * Bob's "s" | ||
127 | */ | ||
128 | struct GNUNET_CRYPTO_PaillierCiphertext s; | ||
129 | |||
130 | /** | ||
131 | * Bob's "s'" | ||
132 | */ | ||
133 | struct GNUNET_CRYPTO_PaillierCiphertext s_prime; | ||
134 | |||
135 | /** | ||
136 | * Handle for our associated incoming CADET session, or NULL | ||
137 | * if we have not gotten one yet. | ||
138 | */ | ||
139 | struct CadetIncomingSession *cadet; | ||
140 | |||
141 | /** | ||
142 | * How many elements will be supplied in total from the client. | ||
143 | */ | ||
144 | uint32_t total; | ||
145 | |||
146 | /** | ||
147 | * Already transferred elements (received) for multipart | ||
148 | * messages from client. Always less than @e total. | ||
149 | */ | ||
150 | uint32_t client_received_element_count; | ||
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. Also sometimes | ||
155 | * used as an index into the arrays during construction. | ||
156 | */ | ||
157 | uint32_t used_element_count; | ||
158 | |||
159 | /** | ||
160 | * Counts the number of values received from Alice by us. | ||
161 | * Always less than @e used_element_count. | ||
162 | */ | ||
163 | uint32_t cadet_received_element_count; | ||
164 | |||
165 | /** | ||
166 | * Counts the number of values transmitted from us to Alice. | ||
167 | * Always less than @e used_element_count. | ||
168 | */ | ||
169 | uint32_t cadet_transmitted_element_count; | ||
170 | |||
171 | /** | ||
172 | * State of this session. In | ||
173 | * #GNUNET_SCALARPRODUCT_STATUS_ACTIVE while operation is | ||
174 | * ongoing, afterwards in #GNUNET_SCALARPRODUCT_STATUS_SUCCESS or | ||
175 | * #GNUNET_SCALARPRODUCT_STATUS_FAILURE. | ||
176 | */ | ||
177 | enum GNUNET_SCALARPRODUCT_ResponseStatus status; | ||
178 | |||
179 | /** | ||
180 | * Are we already in #destroy_service_session()? | ||
181 | */ | ||
182 | int in_destroy; | ||
183 | |||
184 | /** | ||
185 | * The CADET channel. | ||
186 | */ | ||
187 | struct GNUNET_CADET_Channel *channel; | ||
188 | |||
189 | /** | ||
190 | * Originator's peer identity. (Only for diagnostics.) | ||
191 | */ | ||
192 | struct GNUNET_PeerIdentity peer; | ||
193 | |||
194 | /** | ||
195 | * Public key of the remote service. | ||
196 | */ | ||
197 | struct GNUNET_CRYPTO_PaillierPublicKey remote_pubkey; | ||
198 | |||
199 | /** | ||
200 | * The message queue for this channel. | ||
201 | */ | ||
202 | struct GNUNET_MQ_Handle *cadet_mq; | ||
203 | }; | ||
204 | |||
205 | |||
206 | /** | ||
207 | * GNUnet configuration handle | ||
208 | */ | ||
209 | static const struct GNUNET_CONFIGURATION_Handle *cfg; | ||
210 | |||
211 | /** | ||
212 | * Service's own public key | ||
213 | */ | ||
214 | static struct GNUNET_CRYPTO_PaillierPublicKey my_pubkey; | ||
215 | |||
216 | /** | ||
217 | * Service's own private key | ||
218 | */ | ||
219 | static struct GNUNET_CRYPTO_PaillierPrivateKey my_privkey; | ||
220 | |||
221 | /** | ||
222 | * Service's offset for values that could possibly be negative but are plaintext for encryption. | ||
223 | */ | ||
224 | static gcry_mpi_t my_offset; | ||
225 | |||
226 | /** | ||
227 | * Handle to the CADET service. | ||
228 | */ | ||
229 | static struct GNUNET_CADET_Handle *my_cadet; | ||
230 | |||
231 | |||
232 | /** | ||
233 | * Callback used to free the elements in the map. | ||
234 | * | ||
235 | * @param cls NULL | ||
236 | * @param key key of the element | ||
237 | * @param value the value to free | ||
238 | */ | ||
239 | static int | ||
240 | free_element_cb (void *cls, | ||
241 | const struct GNUNET_HashCode *key, | ||
242 | void *value) | ||
243 | { | ||
244 | struct GNUNET_SCALARPRODUCT_Element *element = value; | ||
245 | |||
246 | GNUNET_free (element); | ||
247 | return GNUNET_OK; | ||
248 | } | ||
249 | |||
250 | |||
251 | /** | ||
252 | * Destroy session state, we are done with it. | ||
253 | * | ||
254 | * @param session the session to free elements from | ||
255 | */ | ||
256 | static void | ||
257 | destroy_service_session (struct BobServiceSession *s) | ||
258 | { | ||
259 | unsigned int i; | ||
260 | |||
261 | if (GNUNET_YES == s->in_destroy) | ||
262 | return; | ||
263 | s->in_destroy = GNUNET_YES; | ||
264 | if (NULL != s->client) | ||
265 | { | ||
266 | struct GNUNET_SERVICE_Client *c = s->client; | ||
267 | |||
268 | s->client = NULL; | ||
269 | GNUNET_SERVICE_client_drop (c); | ||
270 | } | ||
271 | if (NULL != s->intersected_elements) | ||
272 | { | ||
273 | GNUNET_CONTAINER_multihashmap_iterate (s->intersected_elements, | ||
274 | &free_element_cb, | ||
275 | NULL); | ||
276 | GNUNET_CONTAINER_multihashmap_destroy (s->intersected_elements); | ||
277 | s->intersected_elements = NULL; | ||
278 | } | ||
279 | if (NULL != s->intersection_op) | ||
280 | { | ||
281 | GNUNET_SETI_operation_cancel (s->intersection_op); | ||
282 | s->intersection_op = NULL; | ||
283 | } | ||
284 | if (NULL != s->intersection_set) | ||
285 | { | ||
286 | GNUNET_SETI_destroy (s->intersection_set); | ||
287 | s->intersection_set = NULL; | ||
288 | } | ||
289 | if (NULL != s->e_a) | ||
290 | { | ||
291 | GNUNET_free (s->e_a); | ||
292 | s->e_a = NULL; | ||
293 | } | ||
294 | if (NULL != s->sorted_elements) | ||
295 | { | ||
296 | for (i = 0; i < s->used_element_count; i++) | ||
297 | gcry_mpi_release (s->sorted_elements[i].value); | ||
298 | GNUNET_free (s->sorted_elements); | ||
299 | s->sorted_elements = NULL; | ||
300 | } | ||
301 | if (NULL != s->r) | ||
302 | { | ||
303 | GNUNET_free (s->r); | ||
304 | s->r = NULL; | ||
305 | } | ||
306 | if (NULL != s->r_prime) | ||
307 | { | ||
308 | GNUNET_free (s->r_prime); | ||
309 | s->r_prime = NULL; | ||
310 | } | ||
311 | if (NULL != s->port) | ||
312 | { | ||
313 | GNUNET_CADET_close_port (s->port); | ||
314 | s->port = NULL; | ||
315 | } | ||
316 | if (NULL != s->channel) | ||
317 | { | ||
318 | GNUNET_CADET_channel_destroy (s->channel); | ||
319 | s->channel = NULL; | ||
320 | } | ||
321 | GNUNET_free (s); | ||
322 | } | ||
323 | |||
324 | |||
325 | /** | ||
326 | * Notify the client that the session has succeeded or failed. This | ||
327 | * message gets sent to Bob's client if the operation completed or | ||
328 | * Alice disconnected. | ||
329 | * | ||
330 | * @param session the associated client session to fail or succeed | ||
331 | */ | ||
332 | static void | ||
333 | prepare_client_end_notification (struct BobServiceSession *session) | ||
334 | { | ||
335 | struct ClientResponseMessage *msg; | ||
336 | struct GNUNET_MQ_Envelope *e; | ||
337 | |||
338 | if (NULL == session->client_mq) | ||
339 | return; /* no client left to be notified */ | ||
340 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
341 | "Sending session-end notification with status %d to client for session %s\n", | ||
342 | session->status, | ||
343 | GNUNET_h2s (&session->session_id)); | ||
344 | e = GNUNET_MQ_msg (msg, | ||
345 | GNUNET_MESSAGE_TYPE_SCALARPRODUCT_RESULT); | ||
346 | msg->range = 0; | ||
347 | msg->product_length = htonl (0); | ||
348 | msg->status = htonl (session->status); | ||
349 | GNUNET_MQ_send (session->client_mq, | ||
350 | e); | ||
351 | } | ||
352 | |||
353 | |||
354 | /** | ||
355 | * Function called whenever a channel is destroyed. Should clean up | ||
356 | * any associated state. | ||
357 | * | ||
358 | * It must NOT call #GNUNET_CADET_channel_destroy() on the channel. | ||
359 | * | ||
360 | * @param cls the `struct BobServiceSession` | ||
361 | * @param channel connection to the other end (henceforth invalid) | ||
362 | */ | ||
363 | static void | ||
364 | cb_channel_destruction (void *cls, | ||
365 | const struct GNUNET_CADET_Channel *channel) | ||
366 | { | ||
367 | struct BobServiceSession *s = cls; | ||
368 | |||
369 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
370 | "Peer disconnected, terminating session %s with peer %s\n", | ||
371 | GNUNET_h2s (&s->session_id), | ||
372 | GNUNET_i2s (&s->peer)); | ||
373 | if (GNUNET_SCALARPRODUCT_STATUS_ACTIVE == s->status) | ||
374 | { | ||
375 | s->status = GNUNET_SCALARPRODUCT_STATUS_FAILURE; | ||
376 | prepare_client_end_notification (s); | ||
377 | } | ||
378 | s->channel = NULL; | ||
379 | destroy_service_session (s); | ||
380 | } | ||
381 | |||
382 | |||
383 | /** | ||
384 | * MQ finished giving our last message to CADET, now notify | ||
385 | * the client that we are finished. | ||
386 | */ | ||
387 | static void | ||
388 | bob_cadet_done_cb (void *cls) | ||
389 | { | ||
390 | struct BobServiceSession *session = cls; | ||
391 | |||
392 | session->status = GNUNET_SCALARPRODUCT_STATUS_SUCCESS; | ||
393 | prepare_client_end_notification (session); | ||
394 | } | ||
395 | |||
396 | |||
397 | /** | ||
398 | * Maximum count of elements we can put into a multipart message | ||
399 | */ | ||
400 | #define ELEMENT_CAPACITY ((GNUNET_CONSTANTS_MAX_CADET_MESSAGE_SIZE - 1 \ | ||
401 | - sizeof(struct BobCryptodataMultipartMessage)) \ | ||
402 | / sizeof(struct \ | ||
403 | GNUNET_CRYPTO_PaillierCiphertext)) | ||
404 | |||
405 | |||
406 | /** | ||
407 | * Send a multipart chunk of a service response from Bob to Alice. | ||
408 | * This element only contains the two permutations of R, R'. | ||
409 | * | ||
410 | * @param s the associated service session | ||
411 | */ | ||
412 | static void | ||
413 | transmit_bobs_cryptodata_message_multipart (struct BobServiceSession *s) | ||
414 | { | ||
415 | struct GNUNET_CRYPTO_PaillierCiphertext *payload; | ||
416 | struct BobCryptodataMultipartMessage *msg; | ||
417 | struct GNUNET_MQ_Envelope *e; | ||
418 | unsigned int i; | ||
419 | unsigned int j; | ||
420 | uint32_t todo_count; | ||
421 | |||
422 | while (s->cadet_transmitted_element_count != s->used_element_count) | ||
423 | { | ||
424 | todo_count = s->used_element_count - s->cadet_transmitted_element_count; | ||
425 | if (todo_count > ELEMENT_CAPACITY / 2) | ||
426 | todo_count = ELEMENT_CAPACITY / 2; | ||
427 | |||
428 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
429 | "Sending %u additional crypto values to Alice\n", | ||
430 | (unsigned int) todo_count); | ||
431 | e = GNUNET_MQ_msg_extra (msg, | ||
432 | todo_count * sizeof(struct | ||
433 | GNUNET_CRYPTO_PaillierCiphertext) | ||
434 | * 2, | ||
435 | GNUNET_MESSAGE_TYPE_SCALARPRODUCT_BOB_CRYPTODATA_MULTIPART); | ||
436 | msg->contained_element_count = htonl (todo_count); | ||
437 | payload = (struct GNUNET_CRYPTO_PaillierCiphertext *) &msg[1]; | ||
438 | for (i = s->cadet_transmitted_element_count, j = 0; i < | ||
439 | s->cadet_transmitted_element_count + todo_count; i++) | ||
440 | { | ||
441 | // r[i][p] and r[i][q] | ||
442 | GNUNET_memcpy (&payload[j++], | ||
443 | &s->r[i], | ||
444 | sizeof(struct GNUNET_CRYPTO_PaillierCiphertext)); | ||
445 | GNUNET_memcpy (&payload[j++], | ||
446 | &s->r_prime[i], | ||
447 | sizeof(struct GNUNET_CRYPTO_PaillierCiphertext)); | ||
448 | } | ||
449 | s->cadet_transmitted_element_count += todo_count; | ||
450 | if (s->cadet_transmitted_element_count == s->used_element_count) | ||
451 | GNUNET_MQ_notify_sent (e, | ||
452 | &bob_cadet_done_cb, | ||
453 | s); | ||
454 | GNUNET_MQ_send (s->cadet_mq, | ||
455 | e); | ||
456 | } | ||
457 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
458 | "All values queued for Alice, Bob is done\n"); | ||
459 | } | ||
460 | |||
461 | |||
462 | /** | ||
463 | * Bob generates the response message to be sent to Alice after | ||
464 | * computing the values (1), (2), S and S'. | ||
465 | * | ||
466 | * (1)[]: $E_A(a_{pi(i)}) times E_A(- r_{pi(i)} - b_{pi(i)}) &= E_A(a_{pi(i)} - r_{pi(i)} - b_{pi(i)})$ | ||
467 | * (2)[]: $E_A(a_{pi'(i)}) times E_A(- r_{pi'(i)}) &= E_A(a_{pi'(i)} - r_{pi'(i)})$ | ||
468 | * S: $S := E_A(sum (r_i + b_i)^2)$ | ||
469 | * S': $S' := E_A(sum r_i^2)$ | ||
470 | * | ||
471 | * @param s the associated requesting session with Alice | ||
472 | */ | ||
473 | static void | ||
474 | transmit_bobs_cryptodata_message (struct BobServiceSession *s) | ||
475 | { | ||
476 | struct BobCryptodataMessage *msg; | ||
477 | struct GNUNET_MQ_Envelope *e; | ||
478 | struct GNUNET_CRYPTO_PaillierCiphertext *payload; | ||
479 | unsigned int i; | ||
480 | |||
481 | s->cadet_transmitted_element_count | ||
482 | = ((GNUNET_CONSTANTS_MAX_CADET_MESSAGE_SIZE - 1 - sizeof(struct | ||
483 | BobCryptodataMessage)) | ||
484 | / sizeof(struct GNUNET_CRYPTO_PaillierCiphertext) / 2) - 1; | ||
485 | if (s->cadet_transmitted_element_count > s->used_element_count) | ||
486 | s->cadet_transmitted_element_count = s->used_element_count; | ||
487 | |||
488 | e = GNUNET_MQ_msg_extra (msg, | ||
489 | (2 + s->cadet_transmitted_element_count * 2) | ||
490 | * sizeof(struct GNUNET_CRYPTO_PaillierCiphertext), | ||
491 | GNUNET_MESSAGE_TYPE_SCALARPRODUCT_BOB_CRYPTODATA); | ||
492 | msg->contained_element_count = htonl (s->cadet_transmitted_element_count); | ||
493 | |||
494 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
495 | "Sending %u/%u crypto values to Alice\n", | ||
496 | (unsigned int) s->cadet_transmitted_element_count, | ||
497 | (unsigned int) s->used_element_count); | ||
498 | |||
499 | payload = (struct GNUNET_CRYPTO_PaillierCiphertext *) &msg[1]; | ||
500 | GNUNET_memcpy (&payload[0], | ||
501 | &s->s, | ||
502 | sizeof(struct GNUNET_CRYPTO_PaillierCiphertext)); | ||
503 | GNUNET_memcpy (&payload[1], | ||
504 | &s->s_prime, | ||
505 | sizeof(struct GNUNET_CRYPTO_PaillierCiphertext)); | ||
506 | |||
507 | payload = &payload[2]; | ||
508 | // convert k[][] | ||
509 | for (i = 0; i < s->cadet_transmitted_element_count; i++) | ||
510 | { | ||
511 | // k[i][p] and k[i][q] | ||
512 | GNUNET_memcpy (&payload[i * 2], | ||
513 | &s->r[i], | ||
514 | sizeof(struct GNUNET_CRYPTO_PaillierCiphertext)); | ||
515 | GNUNET_memcpy (&payload[i * 2 + 1], | ||
516 | &s->r_prime[i], | ||
517 | sizeof(struct GNUNET_CRYPTO_PaillierCiphertext)); | ||
518 | } | ||
519 | if (s->cadet_transmitted_element_count == s->used_element_count) | ||
520 | GNUNET_MQ_notify_sent (e, | ||
521 | &bob_cadet_done_cb, | ||
522 | s); | ||
523 | GNUNET_MQ_send (s->cadet_mq, | ||
524 | e); | ||
525 | transmit_bobs_cryptodata_message_multipart (s); | ||
526 | } | ||
527 | |||
528 | |||
529 | #undef ELEMENT_CAPACITY | ||
530 | |||
531 | |||
532 | /** | ||
533 | * Computes the square sum over a vector of a given length. | ||
534 | * | ||
535 | * @param vector the vector to compute over | ||
536 | * @param length the length of the vector | ||
537 | * @return an MPI value containing the calculated sum, never NULL | ||
538 | * TODO: code duplication with Alice! | ||
539 | */ | ||
540 | static gcry_mpi_t | ||
541 | compute_square_sum (const gcry_mpi_t *vector, | ||
542 | uint32_t length) | ||
543 | { | ||
544 | gcry_mpi_t elem; | ||
545 | gcry_mpi_t sum; | ||
546 | uint32_t i; | ||
547 | |||
548 | GNUNET_assert (NULL != (sum = gcry_mpi_new (0))); | ||
549 | GNUNET_assert (NULL != (elem = gcry_mpi_new (0))); | ||
550 | for (i = 0; i < length; i++) | ||
551 | { | ||
552 | gcry_mpi_mul (elem, vector[i], vector[i]); | ||
553 | gcry_mpi_add (sum, sum, elem); | ||
554 | } | ||
555 | gcry_mpi_release (elem); | ||
556 | return sum; | ||
557 | } | ||
558 | |||
559 | |||
560 | /** | ||
561 | * Compute the values | ||
562 | * (1)[]: $E_A(a_{pi(i)}) otimes E_A(- r_{pi(i)} - b_{pi(i)}) &= E_A(a_{pi(i)} - r_{pi(i)} - b_{pi(i)})$ | ||
563 | * (2)[]: $E_A(a_{pi'(i)}) otimes E_A(- r_{pi'(i)}) &= E_A(a_{pi'(i)} - r_{pi'(i)})$ | ||
564 | * S: $S := E_A(sum (r_i + b_i)^2)$ | ||
565 | * S': $S' := E_A(sum r_i^2)$ | ||
566 | * | ||
567 | * @param session the requesting session + bob's requesting peer | ||
568 | * @return #GNUNET_OK on success | ||
569 | */ | ||
570 | static int | ||
571 | compute_service_response (struct BobServiceSession *session) | ||
572 | { | ||
573 | uint32_t i; | ||
574 | unsigned int *p; | ||
575 | unsigned int *q; | ||
576 | uint32_t count; | ||
577 | gcry_mpi_t *rand; | ||
578 | gcry_mpi_t tmp; | ||
579 | const struct MpiElement *b; | ||
580 | struct GNUNET_CRYPTO_PaillierCiphertext *a; | ||
581 | struct GNUNET_CRYPTO_PaillierCiphertext *r; | ||
582 | struct GNUNET_CRYPTO_PaillierCiphertext *r_prime; | ||
583 | |||
584 | count = session->used_element_count; | ||
585 | a = session->e_a; | ||
586 | b = session->sorted_elements; | ||
587 | q = GNUNET_CRYPTO_random_permute (GNUNET_CRYPTO_QUALITY_WEAK, | ||
588 | count); | ||
589 | p = GNUNET_CRYPTO_random_permute (GNUNET_CRYPTO_QUALITY_WEAK, | ||
590 | count); | ||
591 | rand = GNUNET_malloc (sizeof(gcry_mpi_t) * count); | ||
592 | for (i = 0; i < count; i++) | ||
593 | GNUNET_assert (NULL != (rand[i] = gcry_mpi_new (0))); | ||
594 | r = GNUNET_malloc (sizeof(struct GNUNET_CRYPTO_PaillierCiphertext) * count); | ||
595 | r_prime = GNUNET_malloc (sizeof(struct GNUNET_CRYPTO_PaillierCiphertext) | ||
596 | * count); | ||
597 | |||
598 | for (i = 0; i < count; i++) | ||
599 | { | ||
600 | int32_t svalue; | ||
601 | |||
602 | svalue = (int32_t) GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_WEAK, | ||
603 | UINT32_MAX); | ||
604 | // long to gcry_mpi_t | ||
605 | if (svalue < 0) | ||
606 | gcry_mpi_sub_ui (rand[i], | ||
607 | rand[i], | ||
608 | -svalue); | ||
609 | else | ||
610 | rand[i] = gcry_mpi_set_ui (rand[i], svalue); | ||
611 | } | ||
612 | |||
613 | tmp = gcry_mpi_new (0); | ||
614 | // encrypt the element | ||
615 | // for the sake of readability I decided to have dedicated permutation | ||
616 | // vectors, which get rid of all the lookups in p/q. | ||
617 | // however, ap/aq are not absolutely necessary but are just abstraction | ||
618 | // Calculate Kp = E(S + a_pi) (+) E(S - r_pi - b_pi) | ||
619 | for (i = 0; i < count; i++) | ||
620 | { | ||
621 | // E(S - r_pi - b_pi) | ||
622 | gcry_mpi_sub (tmp, my_offset, rand[p[i]]); | ||
623 | gcry_mpi_sub (tmp, tmp, b[p[i]].value); | ||
624 | GNUNET_assert (2 == | ||
625 | GNUNET_CRYPTO_paillier_encrypt (&session->remote_pubkey, | ||
626 | tmp, | ||
627 | 2, | ||
628 | &r[i])); | ||
629 | |||
630 | // E(S - r_pi - b_pi) * E(S + a_pi) == E(2*S + a - r - b) | ||
631 | if (GNUNET_OK != | ||
632 | GNUNET_CRYPTO_paillier_hom_add (&session->remote_pubkey, | ||
633 | &r[i], | ||
634 | &a[p[i]], | ||
635 | &r[i])) | ||
636 | { | ||
637 | GNUNET_break_op (0); | ||
638 | goto error_cleanup; | ||
639 | } | ||
640 | } | ||
641 | |||
642 | // Calculate Kq = E(S + a_qi) (+) E(S - r_qi) | ||
643 | for (i = 0; i < count; i++) | ||
644 | { | ||
645 | // E(S - r_qi) | ||
646 | gcry_mpi_sub (tmp, my_offset, rand[q[i]]); | ||
647 | GNUNET_assert (2 == | ||
648 | GNUNET_CRYPTO_paillier_encrypt (&session->remote_pubkey, | ||
649 | tmp, | ||
650 | 2, | ||
651 | &r_prime[i])); | ||
652 | |||
653 | // E(S - r_qi) * E(S + a_qi) == E(2*S + a_qi - r_qi) | ||
654 | if (GNUNET_OK != | ||
655 | GNUNET_CRYPTO_paillier_hom_add (&session->remote_pubkey, | ||
656 | &r_prime[i], | ||
657 | &a[q[i]], | ||
658 | &r_prime[i])) | ||
659 | { | ||
660 | GNUNET_break_op (0); | ||
661 | goto error_cleanup; | ||
662 | } | ||
663 | } | ||
664 | gcry_mpi_release (tmp); | ||
665 | |||
666 | // Calculate S' = E(SUM( r_i^2 )) | ||
667 | tmp = compute_square_sum (rand, count); | ||
668 | GNUNET_assert (1 == | ||
669 | GNUNET_CRYPTO_paillier_encrypt (&session->remote_pubkey, | ||
670 | tmp, | ||
671 | 1, | ||
672 | &session->s_prime)); | ||
673 | gcry_mpi_release (tmp); | ||
674 | |||
675 | // Calculate S = E(SUM( (r_i + b_i)^2 )) | ||
676 | for (i = 0; i < count; i++) | ||
677 | gcry_mpi_add (rand[i], rand[i], b[i].value); | ||
678 | tmp = compute_square_sum (rand, count); | ||
679 | GNUNET_assert (1 == | ||
680 | GNUNET_CRYPTO_paillier_encrypt (&session->remote_pubkey, | ||
681 | tmp, | ||
682 | 1, | ||
683 | &session->s)); | ||
684 | gcry_mpi_release (tmp); | ||
685 | |||
686 | session->r = r; | ||
687 | session->r_prime = r_prime; | ||
688 | |||
689 | for (i = 0; i < count; i++) | ||
690 | gcry_mpi_release (rand[i]); | ||
691 | GNUNET_free (session->e_a); | ||
692 | session->e_a = NULL; | ||
693 | GNUNET_free (p); | ||
694 | GNUNET_free (q); | ||
695 | GNUNET_free (rand); | ||
696 | return GNUNET_OK; | ||
697 | |||
698 | error_cleanup: | ||
699 | GNUNET_free (r); | ||
700 | GNUNET_free (r_prime); | ||
701 | gcry_mpi_release (tmp); | ||
702 | GNUNET_free (p); | ||
703 | GNUNET_free (q); | ||
704 | for (i = 0; i < count; i++) | ||
705 | gcry_mpi_release (rand[i]); | ||
706 | GNUNET_free (rand); | ||
707 | return GNUNET_SYSERR; | ||
708 | } | ||
709 | |||
710 | |||
711 | /** | ||
712 | * Iterator to copy over messages from the hash map | ||
713 | * into an array for sorting. | ||
714 | * | ||
715 | * @param cls the `struct BobServiceSession *` | ||
716 | * @param key the key (unused) | ||
717 | * @param value the `struct GNUNET_SCALARPRODUCT_Element *` | ||
718 | * TODO: code duplication with Alice! | ||
719 | */ | ||
720 | static int | ||
721 | copy_element_cb (void *cls, | ||
722 | const struct GNUNET_HashCode *key, | ||
723 | void *value) | ||
724 | { | ||
725 | struct BobServiceSession *s = cls; | ||
726 | struct GNUNET_SCALARPRODUCT_Element *e = value; | ||
727 | gcry_mpi_t mval; | ||
728 | int64_t val; | ||
729 | |||
730 | mval = gcry_mpi_new (0); | ||
731 | val = (int64_t) GNUNET_ntohll (e->value); | ||
732 | if (0 > val) | ||
733 | gcry_mpi_sub_ui (mval, mval, -val); | ||
734 | else | ||
735 | gcry_mpi_add_ui (mval, mval, val); | ||
736 | s->sorted_elements [s->used_element_count].value = mval; | ||
737 | s->sorted_elements [s->used_element_count].key = &e->key; | ||
738 | s->used_element_count++; | ||
739 | return GNUNET_OK; | ||
740 | } | ||
741 | |||
742 | |||
743 | /** | ||
744 | * Compare two `struct MpiValue`s by key for sorting. | ||
745 | * | ||
746 | * @param a pointer to first `struct MpiValue *` | ||
747 | * @param b pointer to first `struct MpiValue *` | ||
748 | * @return -1 for a < b, 0 for a=b, 1 for a > b. | ||
749 | * TODO: code duplication with Alice! | ||
750 | */ | ||
751 | static int | ||
752 | element_cmp (const void *a, | ||
753 | const void *b) | ||
754 | { | ||
755 | const struct MpiElement *ma = a; | ||
756 | const struct MpiElement *mb = b; | ||
757 | |||
758 | return GNUNET_CRYPTO_hash_cmp (ma->key, | ||
759 | mb->key); | ||
760 | } | ||
761 | |||
762 | |||
763 | /** | ||
764 | * Intersection operation and receiving data via CADET from | ||
765 | * Alice are both done, compute and transmit our reply via | ||
766 | * CADET. | ||
767 | * | ||
768 | * @param s session to transmit reply for. | ||
769 | */ | ||
770 | static void | ||
771 | transmit_cryptographic_reply (struct BobServiceSession *s) | ||
772 | { | ||
773 | struct GNUNET_CADET_Channel *channel; | ||
774 | |||
775 | /* TODO: code duplication with Alice! */ | ||
776 | LOG (GNUNET_ERROR_TYPE_DEBUG, | ||
777 | "Received everything, building reply for Alice\n"); | ||
778 | s->sorted_elements | ||
779 | = GNUNET_malloc (GNUNET_CONTAINER_multihashmap_size ( | ||
780 | s->intersected_elements) | ||
781 | * sizeof(struct MpiElement)); | ||
782 | s->used_element_count = 0; | ||
783 | GNUNET_CONTAINER_multihashmap_iterate (s->intersected_elements, | ||
784 | ©_element_cb, | ||
785 | s); | ||
786 | qsort (s->sorted_elements, | ||
787 | s->used_element_count, | ||
788 | sizeof(struct MpiElement), | ||
789 | &element_cmp); | ||
790 | if (GNUNET_OK != | ||
791 | compute_service_response (s)) | ||
792 | { | ||
793 | channel = s->channel; | ||
794 | s->channel = NULL; | ||
795 | GNUNET_CADET_channel_destroy (channel); | ||
796 | return; | ||
797 | } | ||
798 | transmit_bobs_cryptodata_message (s); | ||
799 | } | ||
800 | |||
801 | |||
802 | /** | ||
803 | * Check a multipart-chunk of a request from another service to | ||
804 | * calculate a scalarproduct with us. | ||
805 | * | ||
806 | * @param cls the `struct BobServiceSession *` | ||
807 | * @param msg the actual message | ||
808 | * @return #GNUNET_OK to keep the connection open, | ||
809 | * #GNUNET_SYSERR to close it (signal serious error) | ||
810 | */ | ||
811 | static int | ||
812 | check_alices_cryptodata_message (void *cls, | ||
813 | const struct AliceCryptodataMessage *msg) | ||
814 | { | ||
815 | struct BobServiceSession *s = cls; | ||
816 | uint32_t contained_elements; | ||
817 | size_t msg_length; | ||
818 | uint16_t msize; | ||
819 | unsigned int max; | ||
820 | |||
821 | msize = ntohs (msg->header.size); | ||
822 | contained_elements = ntohl (msg->contained_element_count); | ||
823 | /* Our intersection may still be ongoing, but this is nevertheless | ||
824 | an upper bound on the required array size */ | ||
825 | max = GNUNET_CONTAINER_multihashmap_size (s->intersected_elements); | ||
826 | msg_length = sizeof(struct AliceCryptodataMessage) | ||
827 | + contained_elements * sizeof(struct | ||
828 | GNUNET_CRYPTO_PaillierCiphertext); | ||
829 | if ((msize != msg_length) || | ||
830 | (0 == contained_elements) || | ||
831 | (contained_elements > UINT16_MAX) || | ||
832 | (max < contained_elements + s->cadet_received_element_count)) | ||
833 | { | ||
834 | GNUNET_break_op (0); | ||
835 | return GNUNET_SYSERR; | ||
836 | } | ||
837 | return GNUNET_OK; | ||
838 | } | ||
839 | |||
840 | |||
841 | /** | ||
842 | * Handle a multipart-chunk of a request from another service to | ||
843 | * calculate a scalarproduct with us. | ||
844 | * | ||
845 | * @param cls the `struct BobServiceSession *` | ||
846 | * @param msg the actual message | ||
847 | */ | ||
848 | static void | ||
849 | handle_alices_cryptodata_message (void *cls, | ||
850 | const struct AliceCryptodataMessage *msg) | ||
851 | { | ||
852 | struct BobServiceSession *s = cls; | ||
853 | const struct GNUNET_CRYPTO_PaillierCiphertext *payload; | ||
854 | uint32_t contained_elements; | ||
855 | unsigned int max; | ||
856 | |||
857 | contained_elements = ntohl (msg->contained_element_count); | ||
858 | /* Our intersection may still be ongoing, but this is nevertheless | ||
859 | an upper bound on the required array size */ | ||
860 | max = GNUNET_CONTAINER_multihashmap_size (s->intersected_elements); | ||
861 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
862 | "Received %u crypto values from Alice\n", | ||
863 | (unsigned int) contained_elements); | ||
864 | |||
865 | payload = (const struct GNUNET_CRYPTO_PaillierCiphertext *) &msg[1]; | ||
866 | if (NULL == s->e_a) | ||
867 | s->e_a = GNUNET_new_array (max, | ||
868 | struct GNUNET_CRYPTO_PaillierCiphertext); | ||
869 | GNUNET_memcpy (&s->e_a[s->cadet_received_element_count], | ||
870 | payload, | ||
871 | sizeof(struct GNUNET_CRYPTO_PaillierCiphertext) | ||
872 | * contained_elements); | ||
873 | s->cadet_received_element_count += contained_elements; | ||
874 | |||
875 | if ((s->cadet_received_element_count == max) && | ||
876 | (NULL == s->intersection_op)) | ||
877 | { | ||
878 | /* intersection has finished also on our side, and | ||
879 | we got the full set, so we can proceed with the | ||
880 | CADET response(s) */ | ||
881 | transmit_cryptographic_reply (s); | ||
882 | } | ||
883 | GNUNET_CADET_receive_done (s->channel); | ||
884 | } | ||
885 | |||
886 | |||
887 | /** | ||
888 | * Callback for set operation results. Called for each element | ||
889 | * that needs to be removed from the result set. | ||
890 | * | ||
891 | * @param cls closure with the `struct BobServiceSession` | ||
892 | * @param element a result element, only valid if status is #GNUNET_SETI_STATUS_OK | ||
893 | * @param current_size current set size | ||
894 | * @param status what has happened with the set intersection? | ||
895 | */ | ||
896 | static void | ||
897 | cb_intersection_element_removed (void *cls, | ||
898 | const struct GNUNET_SETI_Element *element, | ||
899 | uint64_t current_size, | ||
900 | enum GNUNET_SETI_Status status) | ||
901 | { | ||
902 | struct BobServiceSession *s = cls; | ||
903 | struct GNUNET_SCALARPRODUCT_Element *se; | ||
904 | |||
905 | switch (status) | ||
906 | { | ||
907 | case GNUNET_SETI_STATUS_DEL_LOCAL: | ||
908 | /* this element has been removed from the set */ | ||
909 | se = GNUNET_CONTAINER_multihashmap_get (s->intersected_elements, | ||
910 | element->data); | ||
911 | GNUNET_assert (NULL != se); | ||
912 | LOG (GNUNET_ERROR_TYPE_DEBUG, | ||
913 | "Removed element with key %s and value %lld\n", | ||
914 | GNUNET_h2s (&se->key), | ||
915 | (long long) GNUNET_ntohll (se->value)); | ||
916 | GNUNET_assert (GNUNET_YES == | ||
917 | GNUNET_CONTAINER_multihashmap_remove ( | ||
918 | s->intersected_elements, | ||
919 | element->data, | ||
920 | se)); | ||
921 | GNUNET_free (se); | ||
922 | return; | ||
923 | case GNUNET_SETI_STATUS_DONE: | ||
924 | s->intersection_op = NULL; | ||
925 | GNUNET_break (NULL == s->intersection_set); | ||
926 | GNUNET_CADET_receive_done (s->channel); | ||
927 | LOG (GNUNET_ERROR_TYPE_DEBUG, | ||
928 | "Finished intersection, %d items remain\n", | ||
929 | GNUNET_CONTAINER_multihashmap_size (s->intersected_elements)); | ||
930 | if (s->client_received_element_count == | ||
931 | GNUNET_CONTAINER_multihashmap_size (s->intersected_elements)) | ||
932 | { | ||
933 | /* CADET transmission from Alice is also already done, | ||
934 | start with our own reply */ | ||
935 | transmit_cryptographic_reply (s); | ||
936 | } | ||
937 | return; | ||
938 | case GNUNET_SETI_STATUS_FAILURE: | ||
939 | /* unhandled status code */ | ||
940 | LOG (GNUNET_ERROR_TYPE_DEBUG, | ||
941 | "Set intersection failed!\n"); | ||
942 | s->intersection_op = NULL; | ||
943 | if (NULL != s->intersection_set) | ||
944 | { | ||
945 | GNUNET_SETI_destroy (s->intersection_set); | ||
946 | s->intersection_set = NULL; | ||
947 | } | ||
948 | s->status = GNUNET_SCALARPRODUCT_STATUS_FAILURE; | ||
949 | prepare_client_end_notification (s); | ||
950 | return; | ||
951 | default: | ||
952 | GNUNET_break (0); | ||
953 | return; | ||
954 | } | ||
955 | } | ||
956 | |||
957 | |||
958 | /** | ||
959 | * We've paired up a client session with an incoming CADET request. | ||
960 | * Initiate set intersection work. | ||
961 | * | ||
962 | * @param s client session to start intersection for | ||
963 | */ | ||
964 | static void | ||
965 | start_intersection (struct BobServiceSession *s) | ||
966 | { | ||
967 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
968 | "Got session with key %s and %u elements, starting intersection.\n", | ||
969 | GNUNET_h2s (&s->session_id), | ||
970 | (unsigned int) s->total); | ||
971 | |||
972 | s->intersection_op | ||
973 | = GNUNET_SETI_prepare (&s->peer, | ||
974 | &s->session_id, | ||
975 | NULL, | ||
976 | (struct GNUNET_SETI_Option[]) { { 0 } }, | ||
977 | &cb_intersection_element_removed, | ||
978 | s); | ||
979 | if (GNUNET_OK != | ||
980 | GNUNET_SETI_commit (s->intersection_op, | ||
981 | s->intersection_set)) | ||
982 | { | ||
983 | GNUNET_break (0); | ||
984 | s->status = GNUNET_SCALARPRODUCT_STATUS_FAILURE; | ||
985 | prepare_client_end_notification (s); | ||
986 | return; | ||
987 | } | ||
988 | GNUNET_SETI_destroy (s->intersection_set); | ||
989 | s->intersection_set = NULL; | ||
990 | } | ||
991 | |||
992 | |||
993 | /** | ||
994 | * Handle a request from Alice to calculate a scalarproduct with us (Bob). | ||
995 | * | ||
996 | * @param cls the `struct BobServiceSession *` | ||
997 | * @param msg the actual message | ||
998 | */ | ||
999 | static void | ||
1000 | handle_alices_computation_request (void *cls, | ||
1001 | const struct ServiceRequestMessage *msg) | ||
1002 | { | ||
1003 | struct BobServiceSession *s = cls; | ||
1004 | |||
1005 | s->session_id = msg->session_id; // ?? | ||
1006 | s->remote_pubkey = msg->public_key; | ||
1007 | if (s->client_received_element_count == s->total) | ||
1008 | start_intersection (s); | ||
1009 | } | ||
1010 | |||
1011 | |||
1012 | /** | ||
1013 | * Function called for inbound channels on Bob's end. Does some | ||
1014 | * preliminary initialization, more happens after we get Alice's first | ||
1015 | * message. | ||
1016 | * | ||
1017 | * @param cls closure with the `struct BobServiceSession` | ||
1018 | * @param channel new handle to the channel | ||
1019 | * @param initiator peer that started the channel | ||
1020 | * @return session associated with the channel | ||
1021 | */ | ||
1022 | static void * | ||
1023 | cb_channel_incoming (void *cls, | ||
1024 | struct GNUNET_CADET_Channel *channel, | ||
1025 | const struct GNUNET_PeerIdentity *initiator) | ||
1026 | { | ||
1027 | struct BobServiceSession *s = cls; | ||
1028 | |||
1029 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
1030 | "New incoming channel from peer %s.\n", | ||
1031 | GNUNET_i2s (initiator)); | ||
1032 | GNUNET_CADET_close_port (s->port); | ||
1033 | s->port = NULL; | ||
1034 | s->channel = channel; | ||
1035 | s->peer = *initiator; | ||
1036 | s->cadet_mq = GNUNET_CADET_get_mq (s->channel); | ||
1037 | return s; | ||
1038 | } | ||
1039 | |||
1040 | |||
1041 | /** | ||
1042 | * We're receiving additional set data. Check it is well-formed. | ||
1043 | * | ||
1044 | * @param cls identification of the client | ||
1045 | * @param msg the actual message | ||
1046 | * @return #GNUNET_OK if @a msg is well-formed | ||
1047 | */ | ||
1048 | static int | ||
1049 | check_bob_client_message_multipart (void *cls, | ||
1050 | const struct | ||
1051 | ComputationBobCryptodataMultipartMessage * | ||
1052 | msg) | ||
1053 | { | ||
1054 | struct BobServiceSession *s = cls; | ||
1055 | uint32_t contained_count; | ||
1056 | uint16_t msize; | ||
1057 | |||
1058 | msize = ntohs (msg->header.size); | ||
1059 | contained_count = ntohl (msg->element_count_contained); | ||
1060 | if ((msize != (sizeof(struct ComputationBobCryptodataMultipartMessage) | ||
1061 | + contained_count * sizeof(struct | ||
1062 | GNUNET_SCALARPRODUCT_Element))) || | ||
1063 | (0 == contained_count) || | ||
1064 | (UINT16_MAX < contained_count) || | ||
1065 | (s->total == s->client_received_element_count) || | ||
1066 | (s->total < s->client_received_element_count + contained_count)) | ||
1067 | { | ||
1068 | GNUNET_break (0); | ||
1069 | return GNUNET_SYSERR; | ||
1070 | } | ||
1071 | return GNUNET_OK; | ||
1072 | } | ||
1073 | |||
1074 | |||
1075 | /** | ||
1076 | * We're receiving additional set data. Add it to our | ||
1077 | * set and if we are done, initiate the transaction. | ||
1078 | * | ||
1079 | * @param cls identification of the client | ||
1080 | * @param msg the actual message | ||
1081 | */ | ||
1082 | static void | ||
1083 | handle_bob_client_message_multipart (void *cls, | ||
1084 | const struct | ||
1085 | ComputationBobCryptodataMultipartMessage * | ||
1086 | msg) | ||
1087 | { | ||
1088 | struct BobServiceSession *s = cls; | ||
1089 | uint32_t contained_count; | ||
1090 | const struct GNUNET_SCALARPRODUCT_Element *elements; | ||
1091 | struct GNUNET_SETI_Element set_elem; | ||
1092 | struct GNUNET_SCALARPRODUCT_Element *elem; | ||
1093 | |||
1094 | contained_count = ntohl (msg->element_count_contained); | ||
1095 | elements = (const struct GNUNET_SCALARPRODUCT_Element *) &msg[1]; | ||
1096 | for (uint32_t i = 0; i < contained_count; i++) | ||
1097 | { | ||
1098 | elem = GNUNET_new (struct GNUNET_SCALARPRODUCT_Element); | ||
1099 | GNUNET_memcpy (elem, | ||
1100 | &elements[i], | ||
1101 | sizeof(struct GNUNET_SCALARPRODUCT_Element)); | ||
1102 | if (GNUNET_SYSERR == | ||
1103 | GNUNET_CONTAINER_multihashmap_put (s->intersected_elements, | ||
1104 | &elem->key, | ||
1105 | elem, | ||
1106 | GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY)) | ||
1107 | { | ||
1108 | GNUNET_break (0); | ||
1109 | GNUNET_free (elem); | ||
1110 | continue; | ||
1111 | } | ||
1112 | set_elem.data = &elem->key; | ||
1113 | set_elem.size = sizeof(elem->key); | ||
1114 | set_elem.element_type = 0; | ||
1115 | GNUNET_SETI_add_element (s->intersection_set, | ||
1116 | &set_elem, | ||
1117 | NULL, NULL); | ||
1118 | } | ||
1119 | s->client_received_element_count += contained_count; | ||
1120 | GNUNET_SERVICE_client_continue (s->client); | ||
1121 | if (s->total != s->client_received_element_count) | ||
1122 | { | ||
1123 | /* more to come */ | ||
1124 | return; | ||
1125 | } | ||
1126 | if (NULL == s->channel) | ||
1127 | { | ||
1128 | /* no Alice waiting for this request, wait for Alice */ | ||
1129 | return; | ||
1130 | } | ||
1131 | start_intersection (s); | ||
1132 | } | ||
1133 | |||
1134 | |||
1135 | /** | ||
1136 | * Handler for Bob's a client request message. Check @a msg is | ||
1137 | * well-formed. | ||
1138 | * | ||
1139 | * @param cls identification of the client | ||
1140 | * @param msg the actual message | ||
1141 | * @return #GNUNET_OK if @a msg is well-formed | ||
1142 | */ | ||
1143 | static int | ||
1144 | check_bob_client_message (void *cls, | ||
1145 | const struct BobComputationMessage *msg) | ||
1146 | { | ||
1147 | struct BobServiceSession *s = cls; | ||
1148 | uint32_t contained_count; | ||
1149 | uint32_t total_count; | ||
1150 | uint16_t msize; | ||
1151 | |||
1152 | if (GNUNET_SCALARPRODUCT_STATUS_INIT != s->status) | ||
1153 | { | ||
1154 | GNUNET_break (0); | ||
1155 | return GNUNET_SYSERR; | ||
1156 | } | ||
1157 | msize = ntohs (msg->header.size); | ||
1158 | total_count = ntohl (msg->element_count_total); | ||
1159 | contained_count = ntohl (msg->element_count_contained); | ||
1160 | if ((0 == total_count) || | ||
1161 | (0 == contained_count) || | ||
1162 | (UINT16_MAX < contained_count) || | ||
1163 | (msize != (sizeof(struct BobComputationMessage) | ||
1164 | + contained_count * sizeof(struct | ||
1165 | GNUNET_SCALARPRODUCT_Element)))) | ||
1166 | { | ||
1167 | GNUNET_break_op (0); | ||
1168 | return GNUNET_SYSERR; | ||
1169 | } | ||
1170 | return GNUNET_OK; | ||
1171 | } | ||
1172 | |||
1173 | |||
1174 | /** | ||
1175 | * Handler for Bob's a client request message. Bob is in the response | ||
1176 | * role, keep the values + session and waiting for a matching session | ||
1177 | * or process a waiting request from Alice. | ||
1178 | * | ||
1179 | * @param cls identification of the client | ||
1180 | * @param msg the actual message | ||
1181 | */ | ||
1182 | static void | ||
1183 | handle_bob_client_message (void *cls, | ||
1184 | const struct BobComputationMessage *msg) | ||
1185 | { | ||
1186 | struct BobServiceSession *s = cls; | ||
1187 | struct GNUNET_MQ_MessageHandler cadet_handlers[] = { | ||
1188 | GNUNET_MQ_hd_fixed_size (alices_computation_request, | ||
1189 | GNUNET_MESSAGE_TYPE_SCALARPRODUCT_SESSION_INITIALIZATION, | ||
1190 | struct ServiceRequestMessage, | ||
1191 | NULL), | ||
1192 | GNUNET_MQ_hd_var_size (alices_cryptodata_message, | ||
1193 | GNUNET_MESSAGE_TYPE_SCALARPRODUCT_ALICE_CRYPTODATA, | ||
1194 | struct AliceCryptodataMessage, | ||
1195 | NULL), | ||
1196 | GNUNET_MQ_handler_end () | ||
1197 | }; | ||
1198 | uint32_t contained_count; | ||
1199 | uint32_t total_count; | ||
1200 | const struct GNUNET_SCALARPRODUCT_Element *elements; | ||
1201 | struct GNUNET_SETI_Element set_elem; | ||
1202 | struct GNUNET_SCALARPRODUCT_Element *elem; | ||
1203 | |||
1204 | total_count = ntohl (msg->element_count_total); | ||
1205 | contained_count = ntohl (msg->element_count_contained); | ||
1206 | |||
1207 | s->status = GNUNET_SCALARPRODUCT_STATUS_ACTIVE; | ||
1208 | s->total = total_count; | ||
1209 | s->client_received_element_count = contained_count; | ||
1210 | s->session_id = msg->session_key; | ||
1211 | elements = (const struct GNUNET_SCALARPRODUCT_Element *) &msg[1]; | ||
1212 | s->intersected_elements | ||
1213 | = GNUNET_CONTAINER_multihashmap_create (s->total, | ||
1214 | GNUNET_YES); | ||
1215 | s->intersection_set = GNUNET_SETI_create (cfg); | ||
1216 | for (uint32_t i = 0; i < contained_count; i++) | ||
1217 | { | ||
1218 | if (0 == GNUNET_ntohll (elements[i].value)) | ||
1219 | continue; | ||
1220 | elem = GNUNET_new (struct GNUNET_SCALARPRODUCT_Element); | ||
1221 | GNUNET_memcpy (elem, | ||
1222 | &elements[i], | ||
1223 | sizeof(struct GNUNET_SCALARPRODUCT_Element)); | ||
1224 | if (GNUNET_SYSERR == | ||
1225 | GNUNET_CONTAINER_multihashmap_put (s->intersected_elements, | ||
1226 | &elem->key, | ||
1227 | elem, | ||
1228 | GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY)) | ||
1229 | { | ||
1230 | GNUNET_break (0); | ||
1231 | GNUNET_free (elem); | ||
1232 | continue; | ||
1233 | } | ||
1234 | set_elem.data = &elem->key; | ||
1235 | set_elem.size = sizeof(elem->key); | ||
1236 | set_elem.element_type = 0; | ||
1237 | GNUNET_SETI_add_element (s->intersection_set, | ||
1238 | &set_elem, | ||
1239 | NULL, NULL); | ||
1240 | s->used_element_count++; | ||
1241 | } | ||
1242 | GNUNET_SERVICE_client_continue (s->client); | ||
1243 | /* We're ready, open the port */ | ||
1244 | s->port = GNUNET_CADET_open_port (my_cadet, | ||
1245 | &msg->session_key, | ||
1246 | &cb_channel_incoming, | ||
1247 | s, | ||
1248 | NULL, | ||
1249 | &cb_channel_destruction, | ||
1250 | cadet_handlers); | ||
1251 | if (NULL == s->port) | ||
1252 | { | ||
1253 | GNUNET_break (0); | ||
1254 | GNUNET_SERVICE_client_drop (s->client); | ||
1255 | return; | ||
1256 | } | ||
1257 | } | ||
1258 | |||
1259 | |||
1260 | /** | ||
1261 | * Task run during shutdown. | ||
1262 | * | ||
1263 | * @param cls unused | ||
1264 | */ | ||
1265 | static void | ||
1266 | shutdown_task (void *cls) | ||
1267 | { | ||
1268 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
1269 | "Shutting down, initiating cleanup.\n"); | ||
1270 | // FIXME: we have to cut our connections to CADET first! | ||
1271 | if (NULL != my_cadet) | ||
1272 | { | ||
1273 | GNUNET_CADET_disconnect (my_cadet); | ||
1274 | my_cadet = NULL; | ||
1275 | } | ||
1276 | } | ||
1277 | |||
1278 | |||
1279 | /** | ||
1280 | * A client connected. | ||
1281 | * | ||
1282 | * Setup the associated data structure. | ||
1283 | * | ||
1284 | * @param cls closure, NULL | ||
1285 | * @param client identification of the client | ||
1286 | * @param mq message queue to communicate with @a client | ||
1287 | * @return our `struct BobServiceSession` | ||
1288 | */ | ||
1289 | static void * | ||
1290 | client_connect_cb (void *cls, | ||
1291 | struct GNUNET_SERVICE_Client *client, | ||
1292 | struct GNUNET_MQ_Handle *mq) | ||
1293 | { | ||
1294 | struct BobServiceSession *s; | ||
1295 | |||
1296 | s = GNUNET_new (struct BobServiceSession); | ||
1297 | s->client = client; | ||
1298 | s->client_mq = mq; | ||
1299 | return s; | ||
1300 | } | ||
1301 | |||
1302 | |||
1303 | /** | ||
1304 | * A client disconnected. | ||
1305 | * | ||
1306 | * Remove the associated session(s), release data structures | ||
1307 | * and cancel pending outgoing transmissions to the client. | ||
1308 | * | ||
1309 | * @param cls closure, NULL | ||
1310 | * @param client identification of the client | ||
1311 | * @param app_cls our `struct BobServiceSession` | ||
1312 | */ | ||
1313 | static void | ||
1314 | client_disconnect_cb (void *cls, | ||
1315 | struct GNUNET_SERVICE_Client *client, | ||
1316 | void *app_cls) | ||
1317 | { | ||
1318 | struct BobServiceSession *s = app_cls; | ||
1319 | |||
1320 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
1321 | "Client disconnected from us.\n"); | ||
1322 | s->client = NULL; | ||
1323 | destroy_service_session (s); | ||
1324 | } | ||
1325 | |||
1326 | |||
1327 | /** | ||
1328 | * Initialization of the program and message handlers | ||
1329 | * | ||
1330 | * @param cls closure | ||
1331 | * @param c configuration to use | ||
1332 | * @param service the initialized service | ||
1333 | */ | ||
1334 | static void | ||
1335 | run (void *cls, | ||
1336 | const struct GNUNET_CONFIGURATION_Handle *c, | ||
1337 | struct GNUNET_SERVICE_Handle *service) | ||
1338 | { | ||
1339 | cfg = c; | ||
1340 | /* | ||
1341 | offset has to be sufficiently small to allow computation of: | ||
1342 | m1+m2 mod n == (S + a) + (S + b) mod n, | ||
1343 | if we have more complex operations, this factor needs to be lowered */ | ||
1344 | my_offset = gcry_mpi_new (GNUNET_CRYPTO_PAILLIER_BITS / 3); | ||
1345 | gcry_mpi_set_bit (my_offset, | ||
1346 | GNUNET_CRYPTO_PAILLIER_BITS / 3); | ||
1347 | |||
1348 | GNUNET_CRYPTO_paillier_create (&my_pubkey, | ||
1349 | &my_privkey); | ||
1350 | my_cadet = GNUNET_CADET_connect (cfg); | ||
1351 | GNUNET_SCHEDULER_add_shutdown (&shutdown_task, | ||
1352 | NULL); | ||
1353 | if (NULL == my_cadet) | ||
1354 | { | ||
1355 | GNUNET_log (GNUNET_ERROR_TYPE_ERROR, | ||
1356 | _ ("Connect to CADET failed\n")); | ||
1357 | GNUNET_SCHEDULER_shutdown (); | ||
1358 | return; | ||
1359 | } | ||
1360 | } | ||
1361 | |||
1362 | |||
1363 | /** | ||
1364 | * Define "main" method using service macro. | ||
1365 | */ | ||
1366 | GNUNET_SERVICE_MAIN | ||
1367 | ("scalarproduct-bob", | ||
1368 | GNUNET_SERVICE_OPTION_NONE, | ||
1369 | &run, | ||
1370 | &client_connect_cb, | ||
1371 | &client_disconnect_cb, | ||
1372 | NULL, | ||
1373 | GNUNET_MQ_hd_var_size (bob_client_message, | ||
1374 | GNUNET_MESSAGE_TYPE_SCALARPRODUCT_CLIENT_TO_BOB, | ||
1375 | struct BobComputationMessage, | ||
1376 | NULL), | ||
1377 | GNUNET_MQ_hd_var_size (bob_client_message_multipart, | ||
1378 | GNUNET_MESSAGE_TYPE_SCALARPRODUCT_CLIENT_MULTIPART_BOB, | ||
1379 | struct ComputationBobCryptodataMultipartMessage, | ||
1380 | NULL), | ||
1381 | GNUNET_MQ_handler_end ()); | ||
1382 | |||
1383 | |||
1384 | /* end of gnunet-service-scalarproduct_bob.c */ | ||