diff options
Diffstat (limited to 'src/scalarproduct')
18 files changed, 0 insertions, 6911 deletions
diff --git a/src/scalarproduct/.gitignore b/src/scalarproduct/.gitignore deleted file mode 100644 index 19909a3f9..000000000 --- a/src/scalarproduct/.gitignore +++ /dev/null | |||
@@ -1,6 +0,0 @@ | |||
1 | gnunet-service-scalarproduct-ecc-bob | ||
2 | gnunet-scalarproduct | ||
3 | gnunet-service-scalarproduct-alice | ||
4 | gnunet-service-scalarproduct-bob | ||
5 | gnunet-service-scalarproduct-ecc-alice | ||
6 | test_ecc_scalarproduct | ||
diff --git a/src/scalarproduct/Makefile.am b/src/scalarproduct/Makefile.am deleted file mode 100644 index cf05e8377..000000000 --- a/src/scalarproduct/Makefile.am +++ /dev/null | |||
@@ -1,116 +0,0 @@ | |||
1 | # This Makefile.am is in the public domain | ||
2 | AM_CPPFLAGS = -I$(top_srcdir)/src/include | ||
3 | |||
4 | pkgcfgdir= $(pkgdatadir)/config.d/ | ||
5 | |||
6 | libexecdir= $(pkglibdir)/libexec/ | ||
7 | |||
8 | pkgcfg_DATA = \ | ||
9 | scalarproduct.conf | ||
10 | |||
11 | if USE_COVERAGE | ||
12 | AM_CFLAGS = -fprofile-arcs -ftest-coverage | ||
13 | endif | ||
14 | |||
15 | bin_PROGRAMS = \ | ||
16 | gnunet-scalarproduct | ||
17 | |||
18 | libexec_PROGRAMS = \ | ||
19 | gnunet-service-scalarproduct-alice \ | ||
20 | gnunet-service-scalarproduct-bob \ | ||
21 | gnunet-service-scalarproduct-ecc-alice \ | ||
22 | gnunet-service-scalarproduct-ecc-bob | ||
23 | |||
24 | lib_LTLIBRARIES = \ | ||
25 | libgnunetscalarproduct.la | ||
26 | |||
27 | gnunet_scalarproduct_SOURCES = \ | ||
28 | gnunet-scalarproduct.c | ||
29 | gnunet_scalarproduct_LDADD = \ | ||
30 | $(top_builddir)/src/util/libgnunetutil.la \ | ||
31 | libgnunetscalarproduct.la \ | ||
32 | $(LIBGCRYPT_LIBS) \ | ||
33 | -lgcrypt \ | ||
34 | $(GN_LIBINTL) | ||
35 | |||
36 | gnunet_service_scalarproduct_alice_SOURCES = \ | ||
37 | gnunet-service-scalarproduct.h \ | ||
38 | gnunet-service-scalarproduct_alice.c | ||
39 | gnunet_service_scalarproduct_alice_LDADD = \ | ||
40 | $(top_builddir)/src/util/libgnunetutil.la \ | ||
41 | $(top_builddir)/src/cadet/libgnunetcadet.la \ | ||
42 | $(top_builddir)/src/seti/libgnunetseti.la \ | ||
43 | $(LIBGCRYPT_LIBS) \ | ||
44 | -lgcrypt \ | ||
45 | $(GN_LIBINTL) | ||
46 | |||
47 | gnunet_service_scalarproduct_bob_SOURCES = \ | ||
48 | gnunet-service-scalarproduct.h \ | ||
49 | gnunet-service-scalarproduct_bob.c | ||
50 | gnunet_service_scalarproduct_bob_LDADD = \ | ||
51 | $(top_builddir)/src/util/libgnunetutil.la \ | ||
52 | $(top_builddir)/src/cadet/libgnunetcadet.la \ | ||
53 | $(top_builddir)/src/seti/libgnunetseti.la \ | ||
54 | $(LIBGCRYPT_LIBS) \ | ||
55 | -lgcrypt \ | ||
56 | $(GN_LIBINTL) | ||
57 | |||
58 | gnunet_service_scalarproduct_ecc_alice_SOURCES = \ | ||
59 | gnunet-service-scalarproduct-ecc.h \ | ||
60 | gnunet-service-scalarproduct-ecc_alice.c | ||
61 | gnunet_service_scalarproduct_ecc_alice_LDADD = \ | ||
62 | $(top_builddir)/src/util/libgnunetutil.la \ | ||
63 | $(top_builddir)/src/cadet/libgnunetcadet.la \ | ||
64 | $(top_builddir)/src/seti/libgnunetseti.la \ | ||
65 | $(LIBGCRYPT_LIBS) \ | ||
66 | -lsodium \ | ||
67 | -lgcrypt \ | ||
68 | $(GN_LIBINTL) | ||
69 | |||
70 | gnunet_service_scalarproduct_ecc_bob_SOURCES = \ | ||
71 | gnunet-service-scalarproduct-ecc.h \ | ||
72 | gnunet-service-scalarproduct-ecc_bob.c | ||
73 | gnunet_service_scalarproduct_ecc_bob_LDADD = \ | ||
74 | $(top_builddir)/src/util/libgnunetutil.la \ | ||
75 | $(top_builddir)/src/cadet/libgnunetcadet.la \ | ||
76 | $(top_builddir)/src/seti/libgnunetseti.la \ | ||
77 | $(LIBGCRYPT_LIBS) \ | ||
78 | -lsodium \ | ||
79 | -lgcrypt \ | ||
80 | $(GN_LIBINTL) | ||
81 | |||
82 | libgnunetscalarproduct_la_SOURCES = \ | ||
83 | scalarproduct_api.c \ | ||
84 | scalarproduct.h | ||
85 | libgnunetscalarproduct_la_LIBADD = \ | ||
86 | $(top_builddir)/src/util/libgnunetutil.la \ | ||
87 | $(top_builddir)/src/statistics/libgnunetstatistics.la \ | ||
88 | $(LIBGCRYPT_LIBS) \ | ||
89 | -lgcrypt \ | ||
90 | $(LTLIBINTL) | ||
91 | libgnunetscalarproduct_la_LDFLAGS = \ | ||
92 | $(GN_LIB_LDFLAGS) | ||
93 | |||
94 | EXTRA_DIST = \ | ||
95 | test_scalarproduct.conf \ | ||
96 | $(check_SCRIPTS) | ||
97 | |||
98 | check_SCRIPTS = \ | ||
99 | test_scalarproduct.sh \ | ||
100 | test_scalarproduct_negative.sh \ | ||
101 | test_scalarproduct_negativezero.sh | ||
102 | |||
103 | check_PROGRAMS = \ | ||
104 | test_ecc_scalarproduct | ||
105 | |||
106 | if ENABLE_TEST_RUN | ||
107 | AM_TESTS_ENVIRONMENT=export GNUNET_PREFIX=$${GNUNET_PREFIX:-@libdir@};export PATH=$${GNUNET_PREFIX:-@prefix@}/bin:$$PATH;unset XDG_DATA_HOME;unset XDG_CONFIG_HOME; | ||
108 | TESTS = $(check_SCRIPTS) $(check_PROGRAMS) | ||
109 | endif | ||
110 | |||
111 | |||
112 | test_ecc_scalarproduct_SOURCES = \ | ||
113 | test_ecc_scalarproduct.c | ||
114 | test_ecc_scalarproduct_LDADD = \ | ||
115 | $(top_builddir)/src/util/libgnunetutil.la \ | ||
116 | -lsodium | ||
diff --git a/src/scalarproduct/gnunet-scalarproduct.c b/src/scalarproduct/gnunet-scalarproduct.c deleted file mode 100644 index 14495de05..000000000 --- a/src/scalarproduct/gnunet-scalarproduct.c +++ /dev/null | |||
@@ -1,402 +0,0 @@ | |||
1 | /* | ||
2 | This file is part of GNUnet. | ||
3 | Copyright (C) 2013, 2014 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 | /** | ||
22 | * @file scalarproduct/gnunet-scalarproduct.c | ||
23 | * @brief scalarproduct client | ||
24 | * @author Christian M. Fuchs | ||
25 | */ | ||
26 | #define GCRYPT_NO_DEPRECATED | ||
27 | #include <gcrypt.h> | ||
28 | #include <inttypes.h> | ||
29 | |||
30 | #include "platform.h" | ||
31 | #include "gnunet_util_lib.h" | ||
32 | #include "gnunet_scalarproduct_service.h" | ||
33 | #include "gnunet_protocols.h" | ||
34 | #include "scalarproduct.h" | ||
35 | |||
36 | #define LOG(kind, ...) GNUNET_log_from (kind, "gnunet-scalarproduct", \ | ||
37 | __VA_ARGS__) | ||
38 | |||
39 | |||
40 | /** | ||
41 | * the session key identifying this computation | ||
42 | */ | ||
43 | static struct GNUNET_HashCode session_key; | ||
44 | |||
45 | /** | ||
46 | * PeerID we want to compute a scalar product with | ||
47 | */ | ||
48 | static struct GNUNET_PeerIdentity peer_id; | ||
49 | |||
50 | /** | ||
51 | * Option -p: destination peer identity for checking message-ids with | ||
52 | */ | ||
53 | static char *input_peer_id; | ||
54 | |||
55 | /** | ||
56 | * Option -p: destination peer identity for checking message-ids with | ||
57 | */ | ||
58 | static char *input_session_key; | ||
59 | |||
60 | /** | ||
61 | * Option -e: vector to calculate a scalarproduct with | ||
62 | */ | ||
63 | static char *input_elements; | ||
64 | |||
65 | /** | ||
66 | * Global return value | ||
67 | */ | ||
68 | static int ret = -1; | ||
69 | |||
70 | /** | ||
71 | * our Scalarproduct Computation handle | ||
72 | */ | ||
73 | static struct GNUNET_SCALARPRODUCT_ComputationHandle *computation; | ||
74 | |||
75 | |||
76 | /** | ||
77 | * Callback called if we are initiating a new computation session | ||
78 | * | ||
79 | * @param cls unused | ||
80 | * @param status if our job was successfully processed | ||
81 | */ | ||
82 | static void | ||
83 | responder_callback (void *cls, | ||
84 | enum GNUNET_SCALARPRODUCT_ResponseStatus status) | ||
85 | { | ||
86 | switch (status) | ||
87 | { | ||
88 | case GNUNET_SCALARPRODUCT_STATUS_SUCCESS: | ||
89 | ret = 0; | ||
90 | LOG (GNUNET_ERROR_TYPE_INFO, | ||
91 | "Session %s concluded.\n", | ||
92 | GNUNET_h2s (&session_key)); | ||
93 | break; | ||
94 | |||
95 | case GNUNET_SCALARPRODUCT_STATUS_INVALID_RESPONSE: | ||
96 | LOG (GNUNET_ERROR_TYPE_ERROR, | ||
97 | "Session %s failed: invalid response\n", | ||
98 | GNUNET_h2s (&session_key)); | ||
99 | break; | ||
100 | |||
101 | case GNUNET_SCALARPRODUCT_STATUS_FAILURE: | ||
102 | LOG (GNUNET_ERROR_TYPE_ERROR, | ||
103 | "Session %s failed: service failure\n", | ||
104 | GNUNET_h2s (&session_key)); | ||
105 | break; | ||
106 | |||
107 | case GNUNET_SCALARPRODUCT_STATUS_DISCONNECTED: | ||
108 | LOG (GNUNET_ERROR_TYPE_ERROR, | ||
109 | "Session %s failed: service disconnect!\n", | ||
110 | GNUNET_h2s (&session_key)); | ||
111 | break; | ||
112 | |||
113 | default: | ||
114 | LOG (GNUNET_ERROR_TYPE_ERROR, | ||
115 | "Session %s failed: return code %d\n", | ||
116 | GNUNET_h2s (&session_key), | ||
117 | status); | ||
118 | } | ||
119 | computation = NULL; | ||
120 | GNUNET_SCHEDULER_shutdown (); | ||
121 | } | ||
122 | |||
123 | |||
124 | /** | ||
125 | * Callback called if we are initiating a new computation session | ||
126 | * | ||
127 | * @param cls unused | ||
128 | * @param status if our job was successfully processed | ||
129 | * @param result the result in gnu/gcry MPI format | ||
130 | */ | ||
131 | static void | ||
132 | requester_callback (void *cls, | ||
133 | enum GNUNET_SCALARPRODUCT_ResponseStatus status, | ||
134 | gcry_mpi_t result) | ||
135 | { | ||
136 | unsigned char *buf; | ||
137 | gcry_error_t rc; | ||
138 | |||
139 | switch (status) | ||
140 | { | ||
141 | case GNUNET_SCALARPRODUCT_STATUS_SUCCESS: | ||
142 | if (0 == (rc = gcry_mpi_aprint (GCRYMPI_FMT_HEX, &buf, NULL, result))) | ||
143 | { | ||
144 | ret = 0; | ||
145 | fprintf (stdout, | ||
146 | "%s\n", | ||
147 | buf); | ||
148 | fflush (stdout); | ||
149 | } | ||
150 | else | ||
151 | LOG_GCRY (GNUNET_ERROR_TYPE_ERROR, | ||
152 | "gcry_mpi_aprint", | ||
153 | rc); | ||
154 | break; | ||
155 | |||
156 | case GNUNET_SCALARPRODUCT_STATUS_INVALID_RESPONSE: | ||
157 | LOG (GNUNET_ERROR_TYPE_ERROR, | ||
158 | "Session %s with peer %s failed: invalid response received\n", | ||
159 | GNUNET_h2s (&session_key), | ||
160 | GNUNET_i2s (&peer_id)); | ||
161 | break; | ||
162 | |||
163 | case GNUNET_SCALARPRODUCT_STATUS_FAILURE: | ||
164 | LOG (GNUNET_ERROR_TYPE_ERROR, | ||
165 | "Session %s with peer %s failed: API failure\n", | ||
166 | GNUNET_h2s (&session_key), | ||
167 | GNUNET_i2s (&peer_id)); | ||
168 | break; | ||
169 | |||
170 | case GNUNET_SCALARPRODUCT_STATUS_DISCONNECTED: | ||
171 | LOG (GNUNET_ERROR_TYPE_ERROR, | ||
172 | "Session %s with peer %s was disconnected from service.\n", | ||
173 | GNUNET_h2s (&session_key), | ||
174 | GNUNET_i2s (&peer_id)); | ||
175 | break; | ||
176 | |||
177 | default: | ||
178 | LOG (GNUNET_ERROR_TYPE_ERROR, | ||
179 | "Session %s with peer %s failed: return code %d\n", | ||
180 | GNUNET_h2s (&session_key), | ||
181 | GNUNET_i2s (&peer_id), | ||
182 | status); | ||
183 | } | ||
184 | computation = NULL; | ||
185 | GNUNET_SCHEDULER_shutdown (); | ||
186 | } | ||
187 | |||
188 | |||
189 | /** | ||
190 | * Task run during shutdown. | ||
191 | * | ||
192 | * @param cls unused | ||
193 | * @param tc unused | ||
194 | */ | ||
195 | static void | ||
196 | shutdown_task (void *cls) | ||
197 | { | ||
198 | if (NULL != computation) | ||
199 | { | ||
200 | GNUNET_SCALARPRODUCT_cancel (computation); | ||
201 | ret = 1; /* aborted */ | ||
202 | } | ||
203 | } | ||
204 | |||
205 | |||
206 | /** | ||
207 | * Main function that will be run by the scheduler. | ||
208 | * | ||
209 | * @param cls closure | ||
210 | * @param args remaining command-line arguments | ||
211 | * @param cfgfile name of the configuration file used (for saving, can be NULL!) | ||
212 | * @param cfg configuration | ||
213 | */ | ||
214 | static void | ||
215 | run (void *cls, | ||
216 | char *const *args, | ||
217 | const char *cfgfile, | ||
218 | const struct GNUNET_CONFIGURATION_Handle *cfg) | ||
219 | { | ||
220 | char *begin = input_elements; | ||
221 | char *end; | ||
222 | unsigned int i; | ||
223 | struct GNUNET_SCALARPRODUCT_Element *elements; | ||
224 | uint32_t element_count = 0; | ||
225 | |||
226 | if (NULL == input_elements) | ||
227 | { | ||
228 | LOG (GNUNET_ERROR_TYPE_ERROR, | ||
229 | _ ("You must specify at least one message ID to check!\n")); | ||
230 | return; | ||
231 | } | ||
232 | if ((NULL == input_session_key) || | ||
233 | (0 == strlen (input_session_key))) | ||
234 | { | ||
235 | LOG (GNUNET_ERROR_TYPE_ERROR, | ||
236 | _ ( | ||
237 | "This program needs a session identifier for comparing vectors.\n")); | ||
238 | return; | ||
239 | } | ||
240 | GNUNET_CRYPTO_hash (input_session_key, | ||
241 | strlen (input_session_key), | ||
242 | &session_key); | ||
243 | if ((NULL != input_peer_id) && | ||
244 | (GNUNET_OK != | ||
245 | GNUNET_CRYPTO_eddsa_public_key_from_string (input_peer_id, | ||
246 | strlen (input_peer_id), | ||
247 | &peer_id.public_key))) | ||
248 | { | ||
249 | LOG (GNUNET_ERROR_TYPE_ERROR, | ||
250 | _ ("Tried to set initiator mode, as peer ID was given. " | ||
251 | "However, `%s' is not a valid peer identifier.\n"), | ||
252 | input_peer_id); | ||
253 | return; | ||
254 | } | ||
255 | if (('\'' == *begin) && | ||
256 | ('\'' == begin[strlen (begin) - 1])) | ||
257 | { | ||
258 | begin[strlen (begin) - 1] = '\0'; | ||
259 | if (strlen (begin) > 0) | ||
260 | begin++; | ||
261 | } | ||
262 | for (end = begin; 0 != *end; end++) | ||
263 | if (*end == ';') | ||
264 | element_count++; | ||
265 | if (0 == element_count) | ||
266 | { | ||
267 | LOG (GNUNET_ERROR_TYPE_ERROR, | ||
268 | _ ("Need elements to compute the scalarproduct, got none.\n")); | ||
269 | return; | ||
270 | } | ||
271 | |||
272 | elements = GNUNET_malloc (sizeof(struct GNUNET_SCALARPRODUCT_Element) | ||
273 | * element_count); | ||
274 | |||
275 | for (i = 0; i < element_count; i++) | ||
276 | { | ||
277 | struct GNUNET_SCALARPRODUCT_Element element; | ||
278 | char*separator = NULL; | ||
279 | |||
280 | /* get the length of the current key,value; tuple */ | ||
281 | for (end = begin; *end != ';'; end++) | ||
282 | if (*end == ',') | ||
283 | separator = end; | ||
284 | |||
285 | /* final element */ | ||
286 | if ((NULL == separator) || | ||
287 | (begin == separator) || | ||
288 | (separator == end - 1)) | ||
289 | { | ||
290 | LOG (GNUNET_ERROR_TYPE_ERROR, | ||
291 | _ ("Malformed input, could not parse `%s'\n"), | ||
292 | begin); | ||
293 | GNUNET_free (elements); | ||
294 | return; | ||
295 | } | ||
296 | *separator = 0; | ||
297 | /* read the element's key */ | ||
298 | GNUNET_CRYPTO_hash (begin, | ||
299 | strlen (begin), | ||
300 | &element.key); | ||
301 | |||
302 | /* read the element's value */ | ||
303 | if (1 != | ||
304 | sscanf (separator + 1, | ||
305 | "%" SCNd64 ";", | ||
306 | &element.value)) | ||
307 | { | ||
308 | LOG (GNUNET_ERROR_TYPE_ERROR, | ||
309 | _ ("Could not convert `%s' to int64_t.\n"), | ||
310 | begin); | ||
311 | GNUNET_free (elements); | ||
312 | return; | ||
313 | } | ||
314 | element.value = GNUNET_htonll (element.value); | ||
315 | elements[i] = element; | ||
316 | begin = end + 1; | ||
317 | } | ||
318 | |||
319 | if (((NULL != input_peer_id) && | ||
320 | (NULL == (computation | ||
321 | = GNUNET_SCALARPRODUCT_start_computation (cfg, | ||
322 | &session_key, | ||
323 | &peer_id, | ||
324 | elements, | ||
325 | element_count, | ||
326 | &requester_callback, | ||
327 | NULL)))) || | ||
328 | ((NULL == input_peer_id) && | ||
329 | (NULL == (computation | ||
330 | = GNUNET_SCALARPRODUCT_accept_computation (cfg, | ||
331 | &session_key, | ||
332 | elements, | ||
333 | element_count, | ||
334 | & | ||
335 | responder_callback, | ||
336 | NULL))))) | ||
337 | { | ||
338 | fprintf (stderr, | ||
339 | _ ("Failed to initiate computation, were all keys unique?\n")); | ||
340 | GNUNET_free (elements); | ||
341 | return; | ||
342 | } | ||
343 | GNUNET_free (elements); | ||
344 | GNUNET_SCHEDULER_add_shutdown (&shutdown_task, | ||
345 | NULL); | ||
346 | ret = 0; | ||
347 | } | ||
348 | |||
349 | |||
350 | /** | ||
351 | * The main function to the scalarproduct client. | ||
352 | * | ||
353 | * @param argc number of arguments from the command line | ||
354 | * @param argv command line arguments | ||
355 | * @return 0 ok, 1 on error | ||
356 | */ | ||
357 | int | ||
358 | main (int argc, char *const *argv) | ||
359 | { | ||
360 | struct GNUNET_GETOPT_CommandLineOption options[] = { | ||
361 | GNUNET_GETOPT_option_string ('e', | ||
362 | "elements", | ||
363 | "\"key1,val1;key2,val2;...,keyn,valn;\"", | ||
364 | gettext_noop ( | ||
365 | "A comma separated list of elements to compare as vector with our remote peer."), | ||
366 | &input_elements), | ||
367 | |||
368 | GNUNET_GETOPT_option_string ('e', | ||
369 | "elements", | ||
370 | "\"key1,val1;key2,val2;...,keyn,valn;\"", | ||
371 | gettext_noop ( | ||
372 | "A comma separated list of elements to compare as vector with our remote peer."), | ||
373 | &input_elements), | ||
374 | |||
375 | GNUNET_GETOPT_option_string ('p', | ||
376 | "peer", | ||
377 | "PEERID", | ||
378 | gettext_noop ( | ||
379 | "[Optional] peer to calculate our scalarproduct with. If this parameter is not given, the service will wait for a remote peer to compute the request."), | ||
380 | &input_peer_id), | ||
381 | |||
382 | GNUNET_GETOPT_option_string ('k', | ||
383 | "key", | ||
384 | "TRANSACTION_ID", | ||
385 | gettext_noop ( | ||
386 | "Transaction ID shared with peer."), | ||
387 | &input_session_key), | ||
388 | |||
389 | GNUNET_GETOPT_OPTION_END | ||
390 | }; | ||
391 | |||
392 | return (GNUNET_OK == | ||
393 | GNUNET_PROGRAM_run (argc, | ||
394 | argv, | ||
395 | "gnunet-scalarproduct", | ||
396 | gettext_noop ( | ||
397 | "Calculate the Vectorproduct with a GNUnet peer."), | ||
398 | options, &run, NULL)) ? ret : 1; | ||
399 | } | ||
400 | |||
401 | |||
402 | /* end of gnunet-scalarproduct.c */ | ||
diff --git a/src/scalarproduct/gnunet-service-scalarproduct-ecc.h b/src/scalarproduct/gnunet-service-scalarproduct-ecc.h deleted file mode 100644 index 5c7a8d8f1..000000000 --- a/src/scalarproduct/gnunet-service-scalarproduct-ecc.h +++ /dev/null | |||
@@ -1,118 +0,0 @@ | |||
1 | /* | ||
2 | This file is part of GNUnet. | ||
3 | Copyright (C) 2015 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.h | ||
22 | * @brief scalarproduct service P2P messages | ||
23 | * @author Christian M. Fuchs | ||
24 | * @author Christian Grothoff | ||
25 | */ | ||
26 | #ifndef GNUNET_SERVICE_SCALARPRODUCT_ECC_H | ||
27 | #define GNUNET_SERVICE_SCALARPRODUCT_ECC_H | ||
28 | |||
29 | |||
30 | GNUNET_NETWORK_STRUCT_BEGIN | ||
31 | |||
32 | /** | ||
33 | * Message type passed from requesting service Alice to responding | ||
34 | * service Bob to initiate a request and make Bob participate in our | ||
35 | * protocol. Afterwards, Bob is expected to perform the set | ||
36 | * intersection with Alice. Once that has succeeded, Alice will | ||
37 | * send a `struct AliceCryptodataMessage *`. Bob is not expected | ||
38 | * to respond via CADET in the meantime. | ||
39 | */ | ||
40 | struct EccServiceRequestMessage | ||
41 | { | ||
42 | /** | ||
43 | * Type is #GNUNET_MESSAGE_TYPE_SCALARPRODUCT_ECC_SESSION_INITIALIZATION | ||
44 | */ | ||
45 | struct GNUNET_MessageHeader header; | ||
46 | |||
47 | /** | ||
48 | * For alignment. Always zero. | ||
49 | */ | ||
50 | uint32_t reserved; | ||
51 | |||
52 | /** | ||
53 | * The transaction/session key used to identify a session | ||
54 | */ | ||
55 | struct GNUNET_HashCode session_id; | ||
56 | }; | ||
57 | |||
58 | |||
59 | /** | ||
60 | * Vector of ECC-encrypted values sent by Alice to Bob | ||
61 | * (after set intersection). Alice may send messages of this | ||
62 | * type repeatedly to transmit all values. | ||
63 | */ | ||
64 | struct EccAliceCryptodataMessage | ||
65 | { | ||
66 | /** | ||
67 | * Type is #GNUNET_MESSAGE_TYPE_SCALARPRODUCT_ECC_ALICE_CRYPTODATA | ||
68 | */ | ||
69 | struct GNUNET_MessageHeader header; | ||
70 | |||
71 | /** | ||
72 | * How many elements we appended to this message? In NBO. | ||
73 | */ | ||
74 | uint32_t contained_element_count GNUNET_PACKED; | ||
75 | |||
76 | /** | ||
77 | * struct GNUNET_CRYPTO_EccPoint[contained_element_count] | ||
78 | */ | ||
79 | }; | ||
80 | |||
81 | |||
82 | /** | ||
83 | * Message type passed from responding service Bob to responding | ||
84 | * service Alice to complete a request and allow Alice to compute the | ||
85 | * result. If Bob's reply does not fit into this one message, the | ||
86 | * conversation may be continued with `struct BobCryptodataMultipartMessage` | ||
87 | * messages afterwards. | ||
88 | */ | ||
89 | struct EccBobCryptodataMessage | ||
90 | { | ||
91 | /** | ||
92 | * GNUNET message header with type | ||
93 | * #GNUNET_MESSAGE_TYPE_SCALARPRODUCT_ECC_BOB_CRYPTODATA. | ||
94 | */ | ||
95 | struct GNUNET_MessageHeader header; | ||
96 | |||
97 | /** | ||
98 | * How many elements this individual message delivers (in NBO), | ||
99 | * always TWO. | ||
100 | */ | ||
101 | uint32_t contained_element_count GNUNET_PACKED; | ||
102 | |||
103 | /** | ||
104 | * The product of the g_i^{b_i} values. | ||
105 | */ | ||
106 | struct GNUNET_CRYPTO_EccPoint prod_g_i_b_i; | ||
107 | |||
108 | /** | ||
109 | * The product of the h_i^{b_i} values. | ||
110 | */ | ||
111 | struct GNUNET_CRYPTO_EccPoint prod_h_i_b_i; | ||
112 | }; | ||
113 | |||
114 | |||
115 | GNUNET_NETWORK_STRUCT_END | ||
116 | |||
117 | |||
118 | #endif | ||
diff --git a/src/scalarproduct/gnunet-service-scalarproduct-ecc_alice.c b/src/scalarproduct/gnunet-service-scalarproduct-ecc_alice.c deleted file mode 100644 index dc43b5a54..000000000 --- a/src/scalarproduct/gnunet-service-scalarproduct-ecc_alice.c +++ /dev/null | |||
@@ -1,1149 +0,0 @@ | |||
1 | /* | ||
2 | This file is part of GNUnet. | ||
3 | Copyright (C) 2013-2017, 2021 GNUnet e.V. | ||
4 | |||
5 | GNUnet is free software: you can redistribute it and/or modify it | ||
6 | under the terms of the GNU Affero General Public License as published | ||
7 | by the Free Software Foundation, either version 3 of the License, | ||
8 | or (at your option) any later version. | ||
9 | |||
10 | GNUnet is distributed in the hope that it will be useful, but | ||
11 | WITHOUT ANY WARRANTY; without even the implied warranty of | ||
12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
13 | Affero General Public License for more details. | ||
14 | |||
15 | You should have received a copy of the GNU Affero General Public License | ||
16 | along with this program. If not, see <http://www.gnu.org/licenses/>. | ||
17 | |||
18 | SPDX-License-Identifier: AGPL3.0-or-later | ||
19 | */ | ||
20 | /** | ||
21 | * @file scalarproduct/gnunet-service-scalarproduct-ecc_alice.c | ||
22 | * @brief scalarproduct service implementation | ||
23 | * @author Christian M. Fuchs | ||
24 | * @author Christian Grothoff | ||
25 | */ | ||
26 | #include "platform.h" | ||
27 | #include <limits.h> | ||
28 | #include <gcrypt.h> | ||
29 | #include "gnunet_util_lib.h" | ||
30 | #include "gnunet_core_service.h" | ||
31 | #include "gnunet_cadet_service.h" | ||
32 | #include "gnunet_applications.h" | ||
33 | #include "gnunet_protocols.h" | ||
34 | #include "gnunet_scalarproduct_service.h" | ||
35 | #include "gnunet_seti_service.h" | ||
36 | #include "scalarproduct.h" | ||
37 | #include "gnunet-service-scalarproduct-ecc.h" | ||
38 | |||
39 | #define LOG(kind, ...) \ | ||
40 | GNUNET_log_from (kind, "scalarproduct-alice", __VA_ARGS__) | ||
41 | |||
42 | /** | ||
43 | * Maximum allowed result value for the scalarproduct computation. | ||
44 | * DLOG will fail if the result is bigger. At 1 million, the | ||
45 | * precomputation takes about 2s on a fast machine. | ||
46 | */ | ||
47 | #define MAX_RESULT (1024 * 1024) | ||
48 | |||
49 | /** | ||
50 | * How many values should DLOG store in memory (determines baseline | ||
51 | * RAM consumption, roughly 100 bytes times the value given here). | ||
52 | * Should be about SQRT (MAX_RESULT), larger values will make the | ||
53 | * online computation faster. | ||
54 | */ | ||
55 | #define MAX_RAM (1024) | ||
56 | |||
57 | /** | ||
58 | * An encrypted element key-value pair. | ||
59 | */ | ||
60 | struct MpiElement | ||
61 | { | ||
62 | /** | ||
63 | * Key used to identify matching pairs of values to multiply. | ||
64 | * Points into an existing data structure, to avoid copying | ||
65 | * and doubling memory use. | ||
66 | */ | ||
67 | const struct GNUNET_HashCode *key; | ||
68 | |||
69 | /** | ||
70 | * a_i value, not disclosed to Bob. | ||
71 | */ | ||
72 | int64_t value; | ||
73 | }; | ||
74 | |||
75 | |||
76 | /** | ||
77 | * A scalarproduct session which tracks | ||
78 | * a request form the client to our final response. | ||
79 | */ | ||
80 | struct AliceServiceSession | ||
81 | { | ||
82 | /** | ||
83 | * (hopefully) unique transaction ID | ||
84 | */ | ||
85 | struct GNUNET_HashCode session_id; | ||
86 | |||
87 | /** | ||
88 | * Alice or Bob's peerID | ||
89 | */ | ||
90 | struct GNUNET_PeerIdentity peer; | ||
91 | |||
92 | /** | ||
93 | * The client this request is related to. | ||
94 | */ | ||
95 | struct GNUNET_SERVICE_Client *client; | ||
96 | |||
97 | /** | ||
98 | * The message queue for the client. | ||
99 | */ | ||
100 | struct GNUNET_MQ_Handle *client_mq; | ||
101 | |||
102 | /** | ||
103 | * The message queue for CADET. | ||
104 | */ | ||
105 | struct GNUNET_MQ_Handle *cadet_mq; | ||
106 | |||
107 | /** | ||
108 | * all non-0-value'd elements transmitted to us. | ||
109 | * Values are of type `struct GNUNET_SCALARPRODUCT_Element *` | ||
110 | */ | ||
111 | struct GNUNET_CONTAINER_MultiHashMap *intersected_elements; | ||
112 | |||
113 | /** | ||
114 | * Set of elements for which will conduction an intersection. | ||
115 | * the resulting elements are then used for computing the scalar product. | ||
116 | */ | ||
117 | struct GNUNET_SETI_Handle *intersection_set; | ||
118 | |||
119 | /** | ||
120 | * Set of elements for which will conduction an intersection. | ||
121 | * the resulting elements are then used for computing the scalar product. | ||
122 | */ | ||
123 | struct GNUNET_SETI_OperationHandle *intersection_op; | ||
124 | |||
125 | /** | ||
126 | * Handle to Alice's Intersection operation listening for Bob | ||
127 | */ | ||
128 | struct GNUNET_SETI_ListenHandle *intersection_listen; | ||
129 | |||
130 | /** | ||
131 | * channel-handle associated with our cadet handle | ||
132 | */ | ||
133 | struct GNUNET_CADET_Channel *channel; | ||
134 | |||
135 | /** | ||
136 | * a(Alice), sorted array by key of length @e used_element_count. | ||
137 | */ | ||
138 | struct MpiElement *sorted_elements; | ||
139 | |||
140 | /** | ||
141 | * The computed scalar product. INT_MAX if the computation failed. | ||
142 | */ | ||
143 | int product; | ||
144 | |||
145 | /** | ||
146 | * How many elements we were supplied with from the client (total | ||
147 | * count before intersection). | ||
148 | */ | ||
149 | uint32_t total; | ||
150 | |||
151 | /** | ||
152 | * How many elements actually are used for the scalar product. | ||
153 | * Size of the arrays in @e r and @e r_prime. Sometimes also | ||
154 | * reset to 0 and used as a counter! | ||
155 | */ | ||
156 | uint32_t used_element_count; | ||
157 | |||
158 | /** | ||
159 | * Already transferred elements from client to us. | ||
160 | * Less or equal than @e total. | ||
161 | */ | ||
162 | uint32_t client_received_element_count; | ||
163 | |||
164 | /** | ||
165 | * State of this session. In | ||
166 | * #GNUNET_SCALARPRODUCT_STATUS_ACTIVE while operation is | ||
167 | * ongoing, afterwards in #GNUNET_SCALARPRODUCT_STATUS_SUCCESS or | ||
168 | * #GNUNET_SCALARPRODUCT_STATUS_FAILURE. | ||
169 | */ | ||
170 | enum GNUNET_SCALARPRODUCT_ResponseStatus status; | ||
171 | |||
172 | /** | ||
173 | * Flag to prevent recursive calls to #destroy_service_session() from | ||
174 | * doing harm. | ||
175 | */ | ||
176 | int in_destroy; | ||
177 | }; | ||
178 | |||
179 | |||
180 | /** | ||
181 | * GNUnet configuration handle | ||
182 | */ | ||
183 | static const struct GNUNET_CONFIGURATION_Handle *cfg; | ||
184 | |||
185 | /** | ||
186 | * Context for DLOG operations on a curve. | ||
187 | */ | ||
188 | static struct GNUNET_CRYPTO_EccDlogContext *edc; | ||
189 | |||
190 | /** | ||
191 | * Alice's private key ('a'). | ||
192 | */ | ||
193 | static struct GNUNET_CRYPTO_EccScalar my_privkey; | ||
194 | |||
195 | /** | ||
196 | * Inverse of Alice's private key ('a_inv'). | ||
197 | */ | ||
198 | static struct GNUNET_CRYPTO_EccScalar my_privkey_inv; | ||
199 | |||
200 | /** | ||
201 | * Handle to the CADET service. | ||
202 | */ | ||
203 | static struct GNUNET_CADET_Handle *my_cadet; | ||
204 | |||
205 | |||
206 | /** | ||
207 | * Iterator called to free elements. | ||
208 | * | ||
209 | * @param cls the `struct AliceServiceSession *` (unused) | ||
210 | * @param key the key (unused) | ||
211 | * @param value value to free | ||
212 | * @return #GNUNET_OK (continue to iterate) | ||
213 | */ | ||
214 | static int | ||
215 | free_element_cb (void *cls, | ||
216 | const struct GNUNET_HashCode *key, | ||
217 | void *value) | ||
218 | { | ||
219 | struct GNUNET_SCALARPRODUCT_Element *e = value; | ||
220 | |||
221 | GNUNET_free (e); | ||
222 | return GNUNET_OK; | ||
223 | } | ||
224 | |||
225 | |||
226 | /** | ||
227 | * Destroy session state, we are done with it. | ||
228 | * | ||
229 | * @param s the session to free elements from | ||
230 | */ | ||
231 | static void | ||
232 | destroy_service_session (struct AliceServiceSession *s) | ||
233 | { | ||
234 | if (GNUNET_YES == s->in_destroy) | ||
235 | return; | ||
236 | s->in_destroy = GNUNET_YES; | ||
237 | if (NULL != s->client) | ||
238 | { | ||
239 | struct GNUNET_SERVICE_Client *c = s->client; | ||
240 | |||
241 | s->client = NULL; | ||
242 | GNUNET_SERVICE_client_drop (c); | ||
243 | } | ||
244 | if (NULL != s->channel) | ||
245 | { | ||
246 | GNUNET_CADET_channel_destroy (s->channel); | ||
247 | s->channel = NULL; | ||
248 | } | ||
249 | if (NULL != s->intersected_elements) | ||
250 | { | ||
251 | GNUNET_CONTAINER_multihashmap_iterate (s->intersected_elements, | ||
252 | &free_element_cb, | ||
253 | s); | ||
254 | GNUNET_CONTAINER_multihashmap_destroy (s->intersected_elements); | ||
255 | s->intersected_elements = NULL; | ||
256 | } | ||
257 | if (NULL != s->intersection_listen) | ||
258 | { | ||
259 | GNUNET_SETI_listen_cancel (s->intersection_listen); | ||
260 | s->intersection_listen = NULL; | ||
261 | } | ||
262 | if (NULL != s->intersection_op) | ||
263 | { | ||
264 | LOG (GNUNET_ERROR_TYPE_DEBUG, | ||
265 | "Set intersection, op still ongoing!\n"); | ||
266 | GNUNET_SETI_operation_cancel (s->intersection_op); | ||
267 | s->intersection_op = NULL; | ||
268 | } | ||
269 | if (NULL != s->intersection_set) | ||
270 | { | ||
271 | GNUNET_SETI_destroy (s->intersection_set); | ||
272 | s->intersection_set = NULL; | ||
273 | } | ||
274 | if (NULL != s->sorted_elements) | ||
275 | { | ||
276 | GNUNET_free (s->sorted_elements); | ||
277 | s->sorted_elements = NULL; | ||
278 | } | ||
279 | GNUNET_free (s); | ||
280 | } | ||
281 | |||
282 | |||
283 | /** | ||
284 | * Notify the client that the session has failed. A message gets sent | ||
285 | * to Alice's client if we encountered any error. | ||
286 | * | ||
287 | * @param session the associated client session to fail or succeed | ||
288 | */ | ||
289 | static void | ||
290 | prepare_client_end_notification (struct AliceServiceSession *session) | ||
291 | { | ||
292 | struct ClientResponseMessage *msg; | ||
293 | struct GNUNET_MQ_Envelope *e; | ||
294 | |||
295 | if (NULL == session->client_mq) | ||
296 | return; /* no client left to be notified */ | ||
297 | GNUNET_log ( | ||
298 | GNUNET_ERROR_TYPE_DEBUG, | ||
299 | "Sending session-end notification with status %d to client for session %s\n", | ||
300 | session->status, | ||
301 | GNUNET_h2s (&session->session_id)); | ||
302 | e = GNUNET_MQ_msg (msg, | ||
303 | GNUNET_MESSAGE_TYPE_SCALARPRODUCT_RESULT); | ||
304 | msg->product_length = htonl (0); | ||
305 | msg->status = htonl (session->status); | ||
306 | GNUNET_MQ_send (session->client_mq, | ||
307 | e); | ||
308 | } | ||
309 | |||
310 | |||
311 | /** | ||
312 | * Prepare the final (positive) response we will send to Alice's | ||
313 | * client. | ||
314 | * | ||
315 | * @param s the session associated with our client. | ||
316 | */ | ||
317 | static void | ||
318 | transmit_client_response (struct AliceServiceSession *s) | ||
319 | { | ||
320 | struct ClientResponseMessage *msg; | ||
321 | struct GNUNET_MQ_Envelope *e; | ||
322 | unsigned char *product_exported = NULL; | ||
323 | size_t product_length = 0; | ||
324 | int32_t range; | ||
325 | gcry_error_t rc; | ||
326 | gcry_mpi_t value; | ||
327 | |||
328 | if (INT_MAX == s->product) | ||
329 | { | ||
330 | GNUNET_break (0); | ||
331 | prepare_client_end_notification (s); | ||
332 | return; | ||
333 | } | ||
334 | value = gcry_mpi_new (32); | ||
335 | if (0 > s->product) | ||
336 | { | ||
337 | range = -1; | ||
338 | gcry_mpi_set_ui (value, | ||
339 | -s->product); | ||
340 | } | ||
341 | else if (0 < s->product) | ||
342 | { | ||
343 | range = 1; | ||
344 | gcry_mpi_set_ui (value, | ||
345 | s->product); | ||
346 | } | ||
347 | else | ||
348 | { | ||
349 | /* result is exactly zero */ | ||
350 | range = 0; | ||
351 | } | ||
352 | if ( (0 != range) && | ||
353 | (0 != (rc = gcry_mpi_aprint (GCRYMPI_FMT_STD, | ||
354 | &product_exported, | ||
355 | &product_length, | ||
356 | value)))) | ||
357 | { | ||
358 | LOG_GCRY (GNUNET_ERROR_TYPE_ERROR, | ||
359 | "gcry_mpi_scan", | ||
360 | rc); | ||
361 | prepare_client_end_notification (s); | ||
362 | return; | ||
363 | } | ||
364 | gcry_mpi_release (value); | ||
365 | e = GNUNET_MQ_msg_extra (msg, | ||
366 | product_length, | ||
367 | GNUNET_MESSAGE_TYPE_SCALARPRODUCT_RESULT); | ||
368 | msg->status = htonl (GNUNET_SCALARPRODUCT_STATUS_SUCCESS); | ||
369 | msg->range = htonl (range); | ||
370 | msg->product_length = htonl (product_length); | ||
371 | if (NULL != product_exported) | ||
372 | { | ||
373 | GNUNET_memcpy (&msg[1], | ||
374 | product_exported, | ||
375 | product_length); | ||
376 | GNUNET_free (product_exported); | ||
377 | } | ||
378 | GNUNET_MQ_send (s->client_mq, | ||
379 | e); | ||
380 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
381 | "Sent result to client, session %s has ended!\n", | ||
382 | GNUNET_h2s (&s->session_id)); | ||
383 | } | ||
384 | |||
385 | |||
386 | /** | ||
387 | * Function called whenever a channel is destroyed. Should clean up | ||
388 | * any associated state. | ||
389 | * | ||
390 | * It must NOT call #GNUNET_CADET_channel_destroy() on the channel. | ||
391 | * | ||
392 | * @param cls the `struct AliceServiceSession` | ||
393 | * @param channel connection to the other end (henceforth invalid) | ||
394 | */ | ||
395 | static void | ||
396 | cb_channel_destruction (void *cls, | ||
397 | const struct GNUNET_CADET_Channel *channel) | ||
398 | { | ||
399 | struct AliceServiceSession *s = cls; | ||
400 | |||
401 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
402 | "Peer disconnected, terminating session %s with peer %s\n", | ||
403 | GNUNET_h2s (&s->session_id), | ||
404 | GNUNET_i2s (&s->peer)); | ||
405 | s->channel = NULL; | ||
406 | if (GNUNET_SCALARPRODUCT_STATUS_ACTIVE == s->status) | ||
407 | { | ||
408 | /* We didn't get an answer yet, fail with error */ | ||
409 | s->status = GNUNET_SCALARPRODUCT_STATUS_FAILURE; | ||
410 | prepare_client_end_notification (s); | ||
411 | } | ||
412 | } | ||
413 | |||
414 | |||
415 | /** | ||
416 | * Handle a response we got from another service we wanted to | ||
417 | * calculate a scalarproduct with. | ||
418 | * | ||
419 | * @param cls the `struct AliceServiceSession *` | ||
420 | * @param msg the actual message | ||
421 | */ | ||
422 | static void | ||
423 | handle_bobs_cryptodata_message (void *cls, | ||
424 | const struct EccBobCryptodataMessage *msg) | ||
425 | { | ||
426 | struct AliceServiceSession *s = cls; | ||
427 | uint32_t contained; | ||
428 | |||
429 | contained = ntohl (msg->contained_element_count); | ||
430 | if (2 != contained) | ||
431 | { | ||
432 | GNUNET_break_op (0); | ||
433 | destroy_service_session (s); | ||
434 | return; | ||
435 | } | ||
436 | if (NULL == s->sorted_elements) | ||
437 | { | ||
438 | /* we're not ready yet, how can Bob be? */ | ||
439 | GNUNET_break_op (0); | ||
440 | destroy_service_session (s); | ||
441 | return; | ||
442 | } | ||
443 | if (s->total != s->client_received_element_count) | ||
444 | { | ||
445 | /* we're not ready yet, how can Bob be? */ | ||
446 | GNUNET_break_op (0); | ||
447 | destroy_service_session (s); | ||
448 | return; | ||
449 | } | ||
450 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
451 | "Received %u crypto values from Bob\n", | ||
452 | (unsigned int) contained); | ||
453 | GNUNET_CADET_receive_done (s->channel); | ||
454 | { | ||
455 | struct GNUNET_CRYPTO_EccPoint g_i_b_i_a_inv; | ||
456 | struct GNUNET_CRYPTO_EccPoint g_ai_bi; | ||
457 | |||
458 | GNUNET_assert ( | ||
459 | GNUNET_OK == | ||
460 | GNUNET_CRYPTO_ecc_pmul_mpi (&msg->prod_g_i_b_i, | ||
461 | &my_privkey_inv, | ||
462 | &g_i_b_i_a_inv)); | ||
463 | GNUNET_assert ( | ||
464 | GNUNET_OK == | ||
465 | GNUNET_CRYPTO_ecc_add (&g_i_b_i_a_inv, | ||
466 | &msg->prod_h_i_b_i, | ||
467 | &g_ai_bi)); | ||
468 | s->product = GNUNET_CRYPTO_ecc_dlog (edc, | ||
469 | &g_ai_bi); | ||
470 | if (INT_MAX == s->product) | ||
471 | { | ||
472 | /* result too big */ | ||
473 | GNUNET_log (GNUNET_ERROR_TYPE_ERROR, | ||
474 | "Scalar product result out of range\n"); | ||
475 | } | ||
476 | } | ||
477 | transmit_client_response (s); | ||
478 | } | ||
479 | |||
480 | |||
481 | /** | ||
482 | * Iterator to copy over messages from the hash map | ||
483 | * into an array for sorting. | ||
484 | * | ||
485 | * @param cls the `struct AliceServiceSession *` | ||
486 | * @param key the key (unused) | ||
487 | * @param value the `struct GNUNET_SCALARPRODUCT_Element *` | ||
488 | */ | ||
489 | static int | ||
490 | copy_element_cb (void *cls, | ||
491 | const struct GNUNET_HashCode *key, | ||
492 | void *value) | ||
493 | { | ||
494 | struct AliceServiceSession *s = cls; | ||
495 | struct GNUNET_SCALARPRODUCT_Element *e = value; | ||
496 | |||
497 | s->sorted_elements[s->used_element_count].value = (int64_t) GNUNET_ntohll ( | ||
498 | e->value); | ||
499 | s->sorted_elements[s->used_element_count].key = &e->key; | ||
500 | s->used_element_count++; | ||
501 | return GNUNET_OK; | ||
502 | } | ||
503 | |||
504 | |||
505 | /** | ||
506 | * Compare two `struct MpiValue`s by key for sorting. | ||
507 | * | ||
508 | * @param a pointer to first `struct MpiValue *` | ||
509 | * @param b pointer to first `struct MpiValue *` | ||
510 | * @return -1 for a < b, 0 for a=b, 1 for a > b. | ||
511 | */ | ||
512 | static int | ||
513 | element_cmp (const void *a, | ||
514 | const void *b) | ||
515 | { | ||
516 | const struct MpiElement *ma = a; | ||
517 | const struct MpiElement *mb = b; | ||
518 | |||
519 | return GNUNET_CRYPTO_hash_cmp (ma->key, | ||
520 | mb->key); | ||
521 | } | ||
522 | |||
523 | |||
524 | /** | ||
525 | * Maximum number of elements we can put into a single cryptodata | ||
526 | * message | ||
527 | */ | ||
528 | #define ELEMENT_CAPACITY \ | ||
529 | ((GNUNET_CONSTANTS_MAX_CADET_MESSAGE_SIZE - 1 \ | ||
530 | - sizeof(struct EccAliceCryptodataMessage)) \ | ||
531 | / sizeof(struct GNUNET_CRYPTO_EccPoint)) | ||
532 | |||
533 | |||
534 | /** | ||
535 | * Send the cryptographic data from Alice to Bob. | ||
536 | * Does nothing if we already transferred all elements. | ||
537 | * | ||
538 | * @param s the associated service session | ||
539 | */ | ||
540 | static void | ||
541 | send_alices_cryptodata_message (struct AliceServiceSession *s) | ||
542 | { | ||
543 | struct EccAliceCryptodataMessage *msg; | ||
544 | struct GNUNET_MQ_Envelope *e; | ||
545 | struct GNUNET_CRYPTO_EccPoint *payload; | ||
546 | struct GNUNET_CRYPTO_EccScalar r_ia; | ||
547 | struct GNUNET_CRYPTO_EccScalar r_ia_ai; | ||
548 | unsigned int off; | ||
549 | unsigned int todo_count; | ||
550 | |||
551 | s->sorted_elements = GNUNET_new_array (GNUNET_CONTAINER_multihashmap_size ( | ||
552 | s->intersected_elements), | ||
553 | struct MpiElement); | ||
554 | s->used_element_count = 0; | ||
555 | GNUNET_CONTAINER_multihashmap_iterate (s->intersected_elements, | ||
556 | ©_element_cb, | ||
557 | s); | ||
558 | LOG (GNUNET_ERROR_TYPE_DEBUG, | ||
559 | "Finished intersection, %d items remain\n", | ||
560 | s->used_element_count); | ||
561 | qsort (s->sorted_elements, | ||
562 | s->used_element_count, | ||
563 | sizeof(struct MpiElement), | ||
564 | &element_cmp); | ||
565 | off = 0; | ||
566 | while (off < s->used_element_count) | ||
567 | { | ||
568 | todo_count = s->used_element_count - off; | ||
569 | if (todo_count > ELEMENT_CAPACITY) | ||
570 | todo_count = ELEMENT_CAPACITY; | ||
571 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
572 | "Sending %u/%u crypto values to Bob\n", | ||
573 | (unsigned int) todo_count, | ||
574 | (unsigned int) s->used_element_count); | ||
575 | |||
576 | e = | ||
577 | GNUNET_MQ_msg_extra (msg, | ||
578 | todo_count * 2 | ||
579 | * sizeof(struct GNUNET_CRYPTO_EccPoint), | ||
580 | GNUNET_MESSAGE_TYPE_SCALARPRODUCT_ECC_ALICE_CRYPTODATA); | ||
581 | msg->contained_element_count = htonl (todo_count); | ||
582 | payload = (struct GNUNET_CRYPTO_EccPoint *) &msg[1]; | ||
583 | for (unsigned int i = off; i < off + todo_count; i++) | ||
584 | { | ||
585 | struct GNUNET_CRYPTO_EccScalar r_i; | ||
586 | struct GNUNET_CRYPTO_EccPoint g_i; | ||
587 | struct GNUNET_CRYPTO_EccPoint h_i; | ||
588 | |||
589 | /* r_i = random() mod n */ | ||
590 | GNUNET_CRYPTO_ecc_random_mod_n (&r_i); | ||
591 | /* g_i = g^{r_i} */ | ||
592 | GNUNET_assert (GNUNET_OK == | ||
593 | GNUNET_CRYPTO_ecc_dexp_mpi (&r_i, | ||
594 | &g_i)); | ||
595 | /* r_ia = r_i * a */ | ||
596 | crypto_core_ed25519_scalar_mul (r_ia.v, | ||
597 | r_i.v, | ||
598 | my_privkey.v); | ||
599 | /* r_ia_ai = r_ia + a_i */ | ||
600 | { | ||
601 | int64_t val = s->sorted_elements[i].value; | ||
602 | struct GNUNET_CRYPTO_EccScalar vali; | ||
603 | |||
604 | GNUNET_assert (INT64_MIN != val); | ||
605 | GNUNET_CRYPTO_ecc_scalar_from_int (val > 0 ? val : -val, | ||
606 | &vali); | ||
607 | if (val > 0) | ||
608 | crypto_core_ed25519_scalar_add (r_ia_ai.v, | ||
609 | r_ia.v, | ||
610 | vali.v); | ||
611 | else | ||
612 | crypto_core_ed25519_scalar_sub (r_ia_ai.v, | ||
613 | r_ia.v, | ||
614 | vali.v); | ||
615 | } | ||
616 | /* h_i = g^{r_ia_ai} */ | ||
617 | GNUNET_assert (GNUNET_OK == | ||
618 | GNUNET_CRYPTO_ecc_dexp_mpi (&r_ia_ai, | ||
619 | &h_i)); | ||
620 | memcpy (&payload[(i - off) * 2], | ||
621 | &g_i, | ||
622 | sizeof (g_i)); | ||
623 | memcpy (&payload[(i - off) * 2 + 1], | ||
624 | &h_i, | ||
625 | sizeof (h_i)); | ||
626 | } | ||
627 | off += todo_count; | ||
628 | GNUNET_MQ_send (s->cadet_mq, | ||
629 | e); | ||
630 | } | ||
631 | } | ||
632 | |||
633 | |||
634 | /** | ||
635 | * Callback for set operation results. Called for each element | ||
636 | * that should be removed from the result set, and then once | ||
637 | * to indicate that the set intersection operation is done. | ||
638 | * | ||
639 | * @param cls closure with the `struct AliceServiceSession` | ||
640 | * @param element a result element, only valid if status is #GNUNET_SETI_STATUS_OK | ||
641 | * @param current_size current set size | ||
642 | * @param status what has happened with the set intersection? | ||
643 | */ | ||
644 | static void | ||
645 | cb_intersection_element_removed (void *cls, | ||
646 | const struct GNUNET_SETI_Element *element, | ||
647 | uint64_t current_size, | ||
648 | enum GNUNET_SETI_Status status) | ||
649 | { | ||
650 | struct AliceServiceSession *s = cls; | ||
651 | struct GNUNET_SCALARPRODUCT_Element *se; | ||
652 | |||
653 | switch (status) | ||
654 | { | ||
655 | case GNUNET_SETI_STATUS_DEL_LOCAL: | ||
656 | /* this element has been removed from the set */ | ||
657 | se = GNUNET_CONTAINER_multihashmap_get (s->intersected_elements, | ||
658 | element->data); | ||
659 | GNUNET_assert (NULL != se); | ||
660 | LOG (GNUNET_ERROR_TYPE_DEBUG, | ||
661 | "Intersection removed element with key %s and value %lld\n", | ||
662 | GNUNET_h2s (&se->key), | ||
663 | (long long) GNUNET_ntohll (se->value)); | ||
664 | GNUNET_assert ( | ||
665 | GNUNET_YES == | ||
666 | GNUNET_CONTAINER_multihashmap_remove (s->intersected_elements, | ||
667 | element->data, | ||
668 | se)); | ||
669 | GNUNET_free (se); | ||
670 | return; | ||
671 | case GNUNET_SETI_STATUS_DONE: | ||
672 | s->intersection_op = NULL; | ||
673 | if (NULL != s->intersection_set) | ||
674 | { | ||
675 | GNUNET_SETI_destroy (s->intersection_set); | ||
676 | s->intersection_set = NULL; | ||
677 | } | ||
678 | send_alices_cryptodata_message (s); | ||
679 | return; | ||
680 | case GNUNET_SETI_STATUS_FAILURE: | ||
681 | /* unhandled status code */ | ||
682 | LOG (GNUNET_ERROR_TYPE_DEBUG, "Set intersection failed!\n"); | ||
683 | if (NULL != s->intersection_listen) | ||
684 | { | ||
685 | GNUNET_SETI_listen_cancel (s->intersection_listen); | ||
686 | s->intersection_listen = NULL; | ||
687 | } | ||
688 | s->intersection_op = NULL; | ||
689 | if (NULL != s->intersection_set) | ||
690 | { | ||
691 | GNUNET_SETI_destroy (s->intersection_set); | ||
692 | s->intersection_set = NULL; | ||
693 | } | ||
694 | s->status = GNUNET_SCALARPRODUCT_STATUS_FAILURE; | ||
695 | prepare_client_end_notification (s); | ||
696 | return; | ||
697 | |||
698 | default: | ||
699 | GNUNET_break (0); | ||
700 | return; | ||
701 | } | ||
702 | } | ||
703 | |||
704 | |||
705 | /** | ||
706 | * Called when another peer wants to do a set operation with the | ||
707 | * local peer. If a listen error occurs, the @a request is NULL. | ||
708 | * | ||
709 | * @param cls closure with the `struct AliceServiceSession *` | ||
710 | * @param other_peer the other peer | ||
711 | * @param context_msg message with application specific information from | ||
712 | * the other peer | ||
713 | * @param request request from the other peer (never NULL), use GNUNET_SETI_accept() | ||
714 | * to accept it, otherwise the request will be refused | ||
715 | * Note that we can't just return value from the listen callback, | ||
716 | * as it is also necessary to specify the set we want to do the | ||
717 | * operation with, which sometimes can be derived from the context | ||
718 | * message. It's necessary to specify the timeout. | ||
719 | */ | ||
720 | static void | ||
721 | cb_intersection_request_alice (void *cls, | ||
722 | const struct GNUNET_PeerIdentity *other_peer, | ||
723 | const struct GNUNET_MessageHeader *context_msg, | ||
724 | struct GNUNET_SETI_Request *request) | ||
725 | { | ||
726 | struct AliceServiceSession *s = cls; | ||
727 | |||
728 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
729 | "Received intersection request from %s!\n", | ||
730 | GNUNET_i2s (other_peer)); | ||
731 | if (0 != GNUNET_memcmp (other_peer, | ||
732 | &s->peer)) | ||
733 | { | ||
734 | GNUNET_break_op (0); | ||
735 | return; | ||
736 | } | ||
737 | s->intersection_op | ||
738 | = GNUNET_SETI_accept (request, | ||
739 | (struct GNUNET_SETI_Option[]){ { 0 } }, | ||
740 | &cb_intersection_element_removed, | ||
741 | s); | ||
742 | if (NULL == s->intersection_op) | ||
743 | { | ||
744 | GNUNET_break (0); | ||
745 | s->status = GNUNET_SCALARPRODUCT_STATUS_FAILURE; | ||
746 | prepare_client_end_notification (s); | ||
747 | return; | ||
748 | } | ||
749 | if (GNUNET_OK != | ||
750 | GNUNET_SETI_commit (s->intersection_op, | ||
751 | s->intersection_set)) | ||
752 | { | ||
753 | GNUNET_break (0); | ||
754 | s->status = GNUNET_SCALARPRODUCT_STATUS_FAILURE; | ||
755 | prepare_client_end_notification (s); | ||
756 | return; | ||
757 | } | ||
758 | } | ||
759 | |||
760 | |||
761 | /** | ||
762 | * Our client has finished sending us its multipart message. | ||
763 | * | ||
764 | * @param session the service session context | ||
765 | */ | ||
766 | static void | ||
767 | client_request_complete_alice (struct AliceServiceSession *s) | ||
768 | { | ||
769 | struct GNUNET_MQ_MessageHandler cadet_handlers[] = { | ||
770 | GNUNET_MQ_hd_fixed_size (bobs_cryptodata_message, | ||
771 | GNUNET_MESSAGE_TYPE_SCALARPRODUCT_ECC_BOB_CRYPTODATA, | ||
772 | struct EccBobCryptodataMessage, | ||
773 | s), | ||
774 | GNUNET_MQ_handler_end () | ||
775 | }; | ||
776 | struct EccServiceRequestMessage *msg; | ||
777 | struct GNUNET_MQ_Envelope *e; | ||
778 | struct GNUNET_HashCode set_sid; | ||
779 | |||
780 | GNUNET_CRYPTO_hash (&s->session_id, | ||
781 | sizeof(struct GNUNET_HashCode), | ||
782 | &set_sid); | ||
783 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
784 | "Creating new channel for session with key %s.\n", | ||
785 | GNUNET_h2s (&s->session_id)); | ||
786 | s->channel = GNUNET_CADET_channel_create (my_cadet, | ||
787 | s, | ||
788 | &s->peer, | ||
789 | &s->session_id, | ||
790 | NULL, | ||
791 | &cb_channel_destruction, | ||
792 | cadet_handlers); | ||
793 | if (NULL == s->channel) | ||
794 | { | ||
795 | s->status = GNUNET_SCALARPRODUCT_STATUS_FAILURE; | ||
796 | prepare_client_end_notification (s); | ||
797 | return; | ||
798 | } | ||
799 | s->cadet_mq = GNUNET_CADET_get_mq (s->channel); | ||
800 | s->intersection_listen = GNUNET_SETI_listen (cfg, | ||
801 | &set_sid, | ||
802 | &cb_intersection_request_alice, | ||
803 | s); | ||
804 | if (NULL == s->intersection_listen) | ||
805 | { | ||
806 | s->status = GNUNET_SCALARPRODUCT_STATUS_FAILURE; | ||
807 | GNUNET_CADET_channel_destroy (s->channel); | ||
808 | s->channel = NULL; | ||
809 | prepare_client_end_notification (s); | ||
810 | return; | ||
811 | } | ||
812 | |||
813 | e = | ||
814 | GNUNET_MQ_msg (msg, | ||
815 | GNUNET_MESSAGE_TYPE_SCALARPRODUCT_ECC_SESSION_INITIALIZATION); | ||
816 | GNUNET_MQ_env_set_options (e, GNUNET_MQ_PRIO_CRITICAL_CONTROL); | ||
817 | msg->session_id = s->session_id; | ||
818 | GNUNET_MQ_send (s->cadet_mq, e); | ||
819 | } | ||
820 | |||
821 | |||
822 | /** | ||
823 | * We're receiving additional set data. Check if | ||
824 | * @a msg is well-formed. | ||
825 | * | ||
826 | * @param cls client identification of the client | ||
827 | * @param msg the actual message | ||
828 | * @return #GNUNET_OK if @a msg is well-formed | ||
829 | */ | ||
830 | static int | ||
831 | check_alice_client_message_multipart ( | ||
832 | void *cls, | ||
833 | const struct ComputationBobCryptodataMultipartMessage *msg) | ||
834 | { | ||
835 | struct AliceServiceSession *s = cls; | ||
836 | uint32_t contained_count; | ||
837 | uint16_t msize; | ||
838 | |||
839 | msize = ntohs (msg->header.size); | ||
840 | contained_count = ntohl (msg->element_count_contained); | ||
841 | if ((msize != | ||
842 | (sizeof(struct ComputationBobCryptodataMultipartMessage) | ||
843 | + contained_count * sizeof(struct GNUNET_SCALARPRODUCT_Element))) || | ||
844 | (0 == contained_count) || | ||
845 | (s->total == s->client_received_element_count) || | ||
846 | (s->total < s->client_received_element_count + contained_count)) | ||
847 | { | ||
848 | GNUNET_break_op (0); | ||
849 | return GNUNET_SYSERR; | ||
850 | } | ||
851 | return GNUNET_OK; | ||
852 | } | ||
853 | |||
854 | |||
855 | /** | ||
856 | * We're receiving additional set data. Add it to our | ||
857 | * set and if we are done, initiate the transaction. | ||
858 | * | ||
859 | * @param cls client identification of the client | ||
860 | * @param msg the actual message | ||
861 | */ | ||
862 | static void | ||
863 | handle_alice_client_message_multipart ( | ||
864 | void *cls, | ||
865 | const struct ComputationBobCryptodataMultipartMessage *msg) | ||
866 | { | ||
867 | struct AliceServiceSession *s = cls; | ||
868 | uint32_t contained_count; | ||
869 | const struct GNUNET_SCALARPRODUCT_Element *elements; | ||
870 | struct GNUNET_SETI_Element set_elem; | ||
871 | struct GNUNET_SCALARPRODUCT_Element *elem; | ||
872 | |||
873 | contained_count = ntohl (msg->element_count_contained); | ||
874 | s->client_received_element_count += contained_count; | ||
875 | elements = (const struct GNUNET_SCALARPRODUCT_Element *) &msg[1]; | ||
876 | for (uint32_t i = 0; i < contained_count; i++) | ||
877 | { | ||
878 | elem = GNUNET_new (struct GNUNET_SCALARPRODUCT_Element); | ||
879 | GNUNET_memcpy (elem, | ||
880 | &elements[i], | ||
881 | sizeof(struct GNUNET_SCALARPRODUCT_Element)); | ||
882 | if (GNUNET_SYSERR == GNUNET_CONTAINER_multihashmap_put ( | ||
883 | s->intersected_elements, | ||
884 | &elem->key, | ||
885 | elem, | ||
886 | GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY)) | ||
887 | { | ||
888 | GNUNET_break (0); | ||
889 | GNUNET_free (elem); | ||
890 | continue; | ||
891 | } | ||
892 | set_elem.data = &elem->key; | ||
893 | set_elem.size = sizeof(elem->key); | ||
894 | set_elem.element_type = 0; | ||
895 | GNUNET_SETI_add_element (s->intersection_set, &set_elem, NULL, NULL); | ||
896 | s->used_element_count++; | ||
897 | } | ||
898 | GNUNET_SERVICE_client_continue (s->client); | ||
899 | if (s->total != s->client_received_element_count) | ||
900 | { | ||
901 | /* more to come */ | ||
902 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
903 | "Received client multipart data, waiting for more!\n"); | ||
904 | return; | ||
905 | } | ||
906 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Launching computation\n"); | ||
907 | client_request_complete_alice (s); | ||
908 | } | ||
909 | |||
910 | |||
911 | /** | ||
912 | * Handler for Alice's client request message. | ||
913 | * Check that @a msg is well-formed. | ||
914 | * | ||
915 | * @param cls identification of the client | ||
916 | * @param msg the actual message | ||
917 | * @return #GNUNET_OK if @a msg is well-formed | ||
918 | */ | ||
919 | static int | ||
920 | check_alice_client_message (void *cls, | ||
921 | const struct AliceComputationMessage *msg) | ||
922 | { | ||
923 | struct AliceServiceSession *s = cls; | ||
924 | uint16_t msize; | ||
925 | uint32_t total_count; | ||
926 | uint32_t contained_count; | ||
927 | |||
928 | if (NULL != s->intersected_elements) | ||
929 | { | ||
930 | /* only one concurrent session per client connection allowed, | ||
931 | simplifies logic a lot... */ | ||
932 | GNUNET_break (0); | ||
933 | return GNUNET_SYSERR; | ||
934 | } | ||
935 | msize = ntohs (msg->header.size); | ||
936 | total_count = ntohl (msg->element_count_total); | ||
937 | contained_count = ntohl (msg->element_count_contained); | ||
938 | if ((0 == total_count) || (0 == contained_count) || | ||
939 | (msize != | ||
940 | (sizeof(struct AliceComputationMessage) | ||
941 | + contained_count * sizeof(struct GNUNET_SCALARPRODUCT_Element)))) | ||
942 | { | ||
943 | GNUNET_break_op (0); | ||
944 | return GNUNET_SYSERR; | ||
945 | } | ||
946 | return GNUNET_OK; | ||
947 | } | ||
948 | |||
949 | |||
950 | /** | ||
951 | * Handler for Alice's client request message. | ||
952 | * We are doing request-initiation to compute a scalar product with a peer. | ||
953 | * | ||
954 | * @param cls identification of the client | ||
955 | * @param msg the actual message | ||
956 | */ | ||
957 | static void | ||
958 | handle_alice_client_message (void *cls, | ||
959 | const struct AliceComputationMessage *msg) | ||
960 | { | ||
961 | struct AliceServiceSession *s = cls; | ||
962 | uint32_t contained_count; | ||
963 | uint32_t total_count; | ||
964 | const struct GNUNET_SCALARPRODUCT_Element *elements; | ||
965 | struct GNUNET_SETI_Element set_elem; | ||
966 | struct GNUNET_SCALARPRODUCT_Element *elem; | ||
967 | |||
968 | total_count = ntohl (msg->element_count_total); | ||
969 | contained_count = ntohl (msg->element_count_contained); | ||
970 | s->peer = msg->peer; | ||
971 | s->status = GNUNET_SCALARPRODUCT_STATUS_ACTIVE; | ||
972 | s->total = total_count; | ||
973 | s->client_received_element_count = contained_count; | ||
974 | s->session_id = msg->session_key; | ||
975 | elements = (const struct GNUNET_SCALARPRODUCT_Element *) &msg[1]; | ||
976 | s->intersected_elements = | ||
977 | GNUNET_CONTAINER_multihashmap_create (s->total, | ||
978 | GNUNET_YES); | ||
979 | s->intersection_set = GNUNET_SETI_create (cfg); | ||
980 | for (uint32_t i = 0; i < contained_count; i++) | ||
981 | { | ||
982 | if (0 == GNUNET_ntohll (elements[i].value)) | ||
983 | continue; | ||
984 | elem = GNUNET_new (struct GNUNET_SCALARPRODUCT_Element); | ||
985 | *elem = elements[i]; | ||
986 | if (GNUNET_SYSERR == | ||
987 | GNUNET_CONTAINER_multihashmap_put ( | ||
988 | s->intersected_elements, | ||
989 | &elem->key, | ||
990 | elem, | ||
991 | GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY)) | ||
992 | { | ||
993 | /* element with same key encountered twice! */ | ||
994 | GNUNET_break (0); | ||
995 | GNUNET_free (elem); | ||
996 | continue; | ||
997 | } | ||
998 | set_elem.data = &elem->key; | ||
999 | set_elem.size = sizeof(elem->key); | ||
1000 | set_elem.element_type = 0; | ||
1001 | GNUNET_SETI_add_element (s->intersection_set, | ||
1002 | &set_elem, | ||
1003 | NULL, | ||
1004 | NULL); | ||
1005 | s->used_element_count++; | ||
1006 | } | ||
1007 | GNUNET_SERVICE_client_continue (s->client); | ||
1008 | if (s->total != s->client_received_element_count) | ||
1009 | { | ||
1010 | /* wait for multipart msg */ | ||
1011 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
1012 | "Received partial client request, waiting for more!\n"); | ||
1013 | return; | ||
1014 | } | ||
1015 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
1016 | "Launching computation\n"); | ||
1017 | client_request_complete_alice (s); | ||
1018 | } | ||
1019 | |||
1020 | |||
1021 | /** | ||
1022 | * Task run during shutdown. | ||
1023 | * | ||
1024 | * @param cls unused | ||
1025 | * @param tc unused | ||
1026 | */ | ||
1027 | static void | ||
1028 | shutdown_task (void *cls) | ||
1029 | { | ||
1030 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
1031 | "Shutting down, initiating cleanup.\n"); | ||
1032 | // FIXME: we have to cut our connections to CADET first! | ||
1033 | if (NULL != my_cadet) | ||
1034 | { | ||
1035 | GNUNET_CADET_disconnect (my_cadet); | ||
1036 | my_cadet = NULL; | ||
1037 | } | ||
1038 | if (NULL != edc) | ||
1039 | { | ||
1040 | GNUNET_CRYPTO_ecc_dlog_release (edc); | ||
1041 | edc = NULL; | ||
1042 | } | ||
1043 | } | ||
1044 | |||
1045 | |||
1046 | /** | ||
1047 | * A client connected. | ||
1048 | * | ||
1049 | * Setup the associated data structure. | ||
1050 | * | ||
1051 | * @param cls closure, NULL | ||
1052 | * @param client identification of the client | ||
1053 | * @param mq message queue to communicate with @a client | ||
1054 | * @return our `struct AliceServiceSession` | ||
1055 | */ | ||
1056 | static void * | ||
1057 | client_connect_cb (void *cls, | ||
1058 | struct GNUNET_SERVICE_Client *client, | ||
1059 | struct GNUNET_MQ_Handle *mq) | ||
1060 | { | ||
1061 | struct AliceServiceSession *s; | ||
1062 | |||
1063 | s = GNUNET_new (struct AliceServiceSession); | ||
1064 | s->client = client; | ||
1065 | s->client_mq = mq; | ||
1066 | return s; | ||
1067 | } | ||
1068 | |||
1069 | |||
1070 | /** | ||
1071 | * A client disconnected. | ||
1072 | * | ||
1073 | * Remove the associated session(s), release data structures | ||
1074 | * and cancel pending outgoing transmissions to the client. | ||
1075 | * | ||
1076 | * @param cls closure, NULL | ||
1077 | * @param client identification of the client | ||
1078 | * @param app_cls our `struct AliceServiceSession` | ||
1079 | */ | ||
1080 | static void | ||
1081 | client_disconnect_cb (void *cls, | ||
1082 | struct GNUNET_SERVICE_Client *client, | ||
1083 | void *app_cls) | ||
1084 | { | ||
1085 | struct AliceServiceSession *s = app_cls; | ||
1086 | |||
1087 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
1088 | "Client %p disconnected from us.\n", | ||
1089 | client); | ||
1090 | s->client = NULL; | ||
1091 | s->client_mq = NULL; | ||
1092 | destroy_service_session (s); | ||
1093 | } | ||
1094 | |||
1095 | |||
1096 | /** | ||
1097 | * Initialization of the program and message handlers | ||
1098 | * | ||
1099 | * @param cls closure | ||
1100 | * @param c configuration to use | ||
1101 | * @param service the initialized service | ||
1102 | */ | ||
1103 | static void | ||
1104 | run (void *cls, | ||
1105 | const struct GNUNET_CONFIGURATION_Handle *c, | ||
1106 | struct GNUNET_SERVICE_Handle *service) | ||
1107 | { | ||
1108 | cfg = c; | ||
1109 | edc = GNUNET_CRYPTO_ecc_dlog_prepare (MAX_RESULT, | ||
1110 | MAX_RAM); | ||
1111 | /* Select a random 'a' value for Alice */ | ||
1112 | GNUNET_CRYPTO_ecc_rnd_mpi (&my_privkey, | ||
1113 | &my_privkey_inv); | ||
1114 | my_cadet = GNUNET_CADET_connect (cfg); | ||
1115 | if (NULL == my_cadet) | ||
1116 | { | ||
1117 | GNUNET_log (GNUNET_ERROR_TYPE_ERROR, | ||
1118 | _ ("Connect to CADET failed\n")); | ||
1119 | GNUNET_SCHEDULER_shutdown (); | ||
1120 | return; | ||
1121 | } | ||
1122 | GNUNET_SCHEDULER_add_shutdown (&shutdown_task, | ||
1123 | NULL); | ||
1124 | } | ||
1125 | |||
1126 | |||
1127 | /** | ||
1128 | * Define "main" method using service macro. | ||
1129 | */ | ||
1130 | GNUNET_SERVICE_MAIN ( | ||
1131 | "scalarproduct-alice", | ||
1132 | GNUNET_SERVICE_OPTION_NONE, | ||
1133 | &run, | ||
1134 | &client_connect_cb, | ||
1135 | &client_disconnect_cb, | ||
1136 | NULL, | ||
1137 | GNUNET_MQ_hd_var_size (alice_client_message, | ||
1138 | GNUNET_MESSAGE_TYPE_SCALARPRODUCT_CLIENT_TO_ALICE, | ||
1139 | struct AliceComputationMessage, | ||
1140 | NULL), | ||
1141 | GNUNET_MQ_hd_var_size ( | ||
1142 | alice_client_message_multipart, | ||
1143 | GNUNET_MESSAGE_TYPE_SCALARPRODUCT_CLIENT_MULTIPART_ALICE, | ||
1144 | struct ComputationBobCryptodataMultipartMessage, | ||
1145 | NULL), | ||
1146 | GNUNET_MQ_handler_end ()); | ||
1147 | |||
1148 | |||
1149 | /* end of gnunet-service-scalarproduct-ecc_alice.c */ | ||
diff --git a/src/scalarproduct/gnunet-service-scalarproduct-ecc_bob.c b/src/scalarproduct/gnunet-service-scalarproduct-ecc_bob.c deleted file mode 100644 index 02a62c164..000000000 --- a/src/scalarproduct/gnunet-service-scalarproduct-ecc_bob.c +++ /dev/null | |||
@@ -1,1062 +0,0 @@ | |||
1 | /* | ||
2 | This file is part of GNUnet. | ||
3 | Copyright (C) 2013-2017, 2021 GNUnet e.V. | ||
4 | |||
5 | GNUnet is free software: you can redistribute it and/or modify it | ||
6 | under the terms of the GNU Affero General Public License as published | ||
7 | by the Free Software Foundation, either version 3 of the License, | ||
8 | or (at your option) any later version. | ||
9 | |||
10 | GNUnet is distributed in the hope that it will be useful, but | ||
11 | WITHOUT ANY WARRANTY; without even the implied warranty of | ||
12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
13 | Affero General Public License for more details. | ||
14 | |||
15 | You should have received a copy of the GNU Affero General Public License | ||
16 | along with this program. If not, see <http://www.gnu.org/licenses/>. | ||
17 | |||
18 | SPDX-License-Identifier: AGPL3.0-or-later | ||
19 | */ | ||
20 | /** | ||
21 | * @file scalarproduct/gnunet-service-scalarproduct-ecc_bob.c | ||
22 | * @brief scalarproduct service implementation | ||
23 | * @author Christian M. Fuchs | ||
24 | * @author Christian Grothoff | ||
25 | */ | ||
26 | #include "platform.h" | ||
27 | #include <limits.h> | ||
28 | #include <gcrypt.h> | ||
29 | #include "gnunet_util_lib.h" | ||
30 | #include "gnunet_core_service.h" | ||
31 | #include "gnunet_cadet_service.h" | ||
32 | #include "gnunet_applications.h" | ||
33 | #include "gnunet_protocols.h" | ||
34 | #include "gnunet_scalarproduct_service.h" | ||
35 | #include "gnunet_seti_service.h" | ||
36 | #include "scalarproduct.h" | ||
37 | #include "gnunet-service-scalarproduct-ecc.h" | ||
38 | |||
39 | #define LOG(kind, ...) GNUNET_log_from (kind, "scalarproduct-bob", __VA_ARGS__) | ||
40 | |||
41 | |||
42 | /** | ||
43 | * An encrypted element key-value pair. | ||
44 | */ | ||
45 | struct MpiElement | ||
46 | { | ||
47 | /** | ||
48 | * Key used to identify matching pairs of values to multiply. | ||
49 | * Points into an existing data structure, to avoid copying | ||
50 | * and doubling memory use. | ||
51 | */ | ||
52 | const struct GNUNET_HashCode *key; | ||
53 | |||
54 | /** | ||
55 | * Value represented (a). | ||
56 | */ | ||
57 | int64_t value; | ||
58 | }; | ||
59 | |||
60 | |||
61 | /** | ||
62 | * A scalarproduct session which tracks an offer for a | ||
63 | * multiplication service by a local client. | ||
64 | */ | ||
65 | struct BobServiceSession | ||
66 | { | ||
67 | /** | ||
68 | * The client this request is related to. | ||
69 | */ | ||
70 | struct GNUNET_SERVICE_Client *client; | ||
71 | |||
72 | /** | ||
73 | * Client message queue. | ||
74 | */ | ||
75 | struct GNUNET_MQ_Handle *client_mq; | ||
76 | |||
77 | /** | ||
78 | * All non-0-value'd elements transmitted to us. | ||
79 | */ | ||
80 | struct GNUNET_CONTAINER_MultiHashMap *intersected_elements; | ||
81 | |||
82 | /** | ||
83 | * Set of elements for which we will be conducting an intersection. | ||
84 | * The resulting elements are then used for computing the scalar product. | ||
85 | */ | ||
86 | struct GNUNET_SETI_Handle *intersection_set; | ||
87 | |||
88 | /** | ||
89 | * Set of elements for which will conduction an intersection. | ||
90 | * the resulting elements are then used for computing the scalar product. | ||
91 | */ | ||
92 | struct GNUNET_SETI_OperationHandle *intersection_op; | ||
93 | |||
94 | /** | ||
95 | * Our open port. | ||
96 | */ | ||
97 | struct GNUNET_CADET_Port *port; | ||
98 | |||
99 | /** | ||
100 | * b(Bob) | ||
101 | */ | ||
102 | struct MpiElement *sorted_elements; | ||
103 | |||
104 | /** | ||
105 | * Product of the g_i^{b_i} | ||
106 | */ | ||
107 | struct GNUNET_CRYPTO_EccPoint prod_g_i_b_i; | ||
108 | |||
109 | /** | ||
110 | * Product of the h_i^{b_i} | ||
111 | */ | ||
112 | struct GNUNET_CRYPTO_EccPoint prod_h_i_b_i; | ||
113 | |||
114 | /** | ||
115 | * How many elements will be supplied in total from the client. | ||
116 | */ | ||
117 | uint32_t total; | ||
118 | |||
119 | /** | ||
120 | * Already transferred elements (received) for multipart | ||
121 | * messages from client. Always less than @e total. | ||
122 | */ | ||
123 | uint32_t client_received_element_count; | ||
124 | |||
125 | /** | ||
126 | * How many elements actually are used for the scalar product. | ||
127 | * Size of the arrays in @e r and @e r_prime. Also sometimes | ||
128 | * used as an index into the arrays during construction. | ||
129 | */ | ||
130 | uint32_t used_element_count; | ||
131 | |||
132 | /** | ||
133 | * Counts the number of values received from Alice by us. | ||
134 | * Always less than @e used_element_count. | ||
135 | */ | ||
136 | uint32_t cadet_received_element_count; | ||
137 | |||
138 | /** | ||
139 | * State of this session. In | ||
140 | * #GNUNET_SCALARPRODUCT_STATUS_ACTIVE while operation is | ||
141 | * ongoing, afterwards in #GNUNET_SCALARPRODUCT_STATUS_SUCCESS or | ||
142 | * #GNUNET_SCALARPRODUCT_STATUS_FAILURE. | ||
143 | */ | ||
144 | enum GNUNET_SCALARPRODUCT_ResponseStatus status; | ||
145 | |||
146 | /** | ||
147 | * Are we already in #destroy_service_session()? | ||
148 | */ | ||
149 | int in_destroy; | ||
150 | |||
151 | /** | ||
152 | * The CADET channel. | ||
153 | */ | ||
154 | struct GNUNET_CADET_Channel *channel; | ||
155 | |||
156 | /** | ||
157 | * Originator's peer identity. (Only for diagnostics.) | ||
158 | */ | ||
159 | struct GNUNET_PeerIdentity peer; | ||
160 | |||
161 | /** | ||
162 | * (hopefully) unique transaction ID | ||
163 | */ | ||
164 | struct GNUNET_HashCode session_id; | ||
165 | |||
166 | /** | ||
167 | * The message queue for this channel. | ||
168 | */ | ||
169 | struct GNUNET_MQ_Handle *cadet_mq; | ||
170 | }; | ||
171 | |||
172 | |||
173 | /** | ||
174 | * GNUnet configuration handle | ||
175 | */ | ||
176 | static const struct GNUNET_CONFIGURATION_Handle *cfg; | ||
177 | |||
178 | /** | ||
179 | * Handle to the CADET service. | ||
180 | */ | ||
181 | static struct GNUNET_CADET_Handle *my_cadet; | ||
182 | |||
183 | /** | ||
184 | * Context for DLOG operations on a curve. | ||
185 | */ | ||
186 | static struct GNUNET_CRYPTO_EccDlogContext *edc; | ||
187 | |||
188 | |||
189 | /** | ||
190 | * Callback used to free the elements in the map. | ||
191 | * | ||
192 | * @param cls NULL | ||
193 | * @param key key of the element | ||
194 | * @param value the value to free | ||
195 | */ | ||
196 | static int | ||
197 | free_element_cb (void *cls, | ||
198 | const struct GNUNET_HashCode *key, | ||
199 | void *value) | ||
200 | { | ||
201 | struct GNUNET_SCALARPRODUCT_Element *element = value; | ||
202 | |||
203 | GNUNET_free (element); | ||
204 | return GNUNET_OK; | ||
205 | } | ||
206 | |||
207 | |||
208 | /** | ||
209 | * Destroy session state, we are done with it. | ||
210 | * | ||
211 | * @param session the session to free elements from | ||
212 | */ | ||
213 | static void | ||
214 | destroy_service_session (struct BobServiceSession *s) | ||
215 | { | ||
216 | if (GNUNET_YES == s->in_destroy) | ||
217 | return; | ||
218 | s->in_destroy = GNUNET_YES; | ||
219 | if (NULL != s->client) | ||
220 | { | ||
221 | struct GNUNET_SERVICE_Client *c = s->client; | ||
222 | |||
223 | s->client = NULL; | ||
224 | GNUNET_SERVICE_client_drop (c); | ||
225 | } | ||
226 | if (NULL != s->intersected_elements) | ||
227 | { | ||
228 | GNUNET_CONTAINER_multihashmap_iterate (s->intersected_elements, | ||
229 | &free_element_cb, | ||
230 | NULL); | ||
231 | GNUNET_CONTAINER_multihashmap_destroy (s->intersected_elements); | ||
232 | s->intersected_elements = NULL; | ||
233 | } | ||
234 | if (NULL != s->intersection_op) | ||
235 | { | ||
236 | GNUNET_SETI_operation_cancel (s->intersection_op); | ||
237 | s->intersection_op = NULL; | ||
238 | } | ||
239 | if (NULL != s->intersection_set) | ||
240 | { | ||
241 | GNUNET_SETI_destroy (s->intersection_set); | ||
242 | s->intersection_set = NULL; | ||
243 | } | ||
244 | if (NULL != s->sorted_elements) | ||
245 | { | ||
246 | GNUNET_free (s->sorted_elements); | ||
247 | s->sorted_elements = NULL; | ||
248 | } | ||
249 | if (NULL != s->port) | ||
250 | { | ||
251 | GNUNET_CADET_close_port (s->port); | ||
252 | s->port = NULL; | ||
253 | } | ||
254 | if (NULL != s->channel) | ||
255 | { | ||
256 | GNUNET_CADET_channel_destroy (s->channel); | ||
257 | s->channel = NULL; | ||
258 | } | ||
259 | GNUNET_free (s); | ||
260 | } | ||
261 | |||
262 | |||
263 | /** | ||
264 | * Notify the client that the session has succeeded or failed. This | ||
265 | * message gets sent to Bob's client if the operation completed or | ||
266 | * Alice disconnected. | ||
267 | * | ||
268 | * @param session the associated client session to fail or succeed | ||
269 | */ | ||
270 | static void | ||
271 | prepare_client_end_notification (struct BobServiceSession *session) | ||
272 | { | ||
273 | struct ClientResponseMessage *msg; | ||
274 | struct GNUNET_MQ_Envelope *e; | ||
275 | |||
276 | if (NULL == session->client_mq) | ||
277 | return; /* no client left to be notified */ | ||
278 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
279 | "Sending session-end notification with status %d to client for session %s\n", | ||
280 | session->status, | ||
281 | GNUNET_h2s (&session->session_id)); | ||
282 | e = GNUNET_MQ_msg (msg, | ||
283 | GNUNET_MESSAGE_TYPE_SCALARPRODUCT_RESULT); | ||
284 | msg->range = 0; | ||
285 | msg->product_length = htonl (0); | ||
286 | msg->status = htonl (session->status); | ||
287 | GNUNET_MQ_send (session->client_mq, | ||
288 | e); | ||
289 | } | ||
290 | |||
291 | |||
292 | /** | ||
293 | * Function called whenever a channel is destroyed. Should clean up | ||
294 | * any associated state. | ||
295 | * | ||
296 | * It must NOT call #GNUNET_CADET_channel_destroy() on the channel. | ||
297 | * | ||
298 | * @param cls the `struct BobServiceSession` | ||
299 | * @param channel connection to the other end (henceforth invalid) | ||
300 | * @param channel_ctx place where local state associated | ||
301 | * with the channel is stored | ||
302 | */ | ||
303 | static void | ||
304 | cb_channel_destruction (void *cls, | ||
305 | const struct GNUNET_CADET_Channel *channel) | ||
306 | { | ||
307 | struct BobServiceSession *s = cls; | ||
308 | |||
309 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
310 | "Peer disconnected, terminating session %s with peer %s\n", | ||
311 | GNUNET_h2s (&s->session_id), | ||
312 | GNUNET_i2s (&s->peer)); | ||
313 | s->channel = NULL; | ||
314 | if (GNUNET_SCALARPRODUCT_STATUS_ACTIVE == s->status) | ||
315 | { | ||
316 | s->status = GNUNET_SCALARPRODUCT_STATUS_FAILURE; | ||
317 | prepare_client_end_notification (s); | ||
318 | } | ||
319 | destroy_service_session (s); | ||
320 | } | ||
321 | |||
322 | |||
323 | /** | ||
324 | * MQ finished giving our last message to CADET, now notify | ||
325 | * the client that we are finished. | ||
326 | */ | ||
327 | static void | ||
328 | bob_cadet_done_cb (void *cls) | ||
329 | { | ||
330 | struct BobServiceSession *session = cls; | ||
331 | |||
332 | session->status = GNUNET_SCALARPRODUCT_STATUS_SUCCESS; | ||
333 | prepare_client_end_notification (session); | ||
334 | } | ||
335 | |||
336 | |||
337 | /** | ||
338 | * Bob generates the response message to be sent to Alice. | ||
339 | * | ||
340 | * @param s the associated requesting session with Alice | ||
341 | */ | ||
342 | static void | ||
343 | transmit_bobs_cryptodata_message (struct BobServiceSession *s) | ||
344 | { | ||
345 | struct EccBobCryptodataMessage *msg; | ||
346 | struct GNUNET_MQ_Envelope *e; | ||
347 | |||
348 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
349 | "Sending response to Alice\n"); | ||
350 | e = GNUNET_MQ_msg (msg, | ||
351 | GNUNET_MESSAGE_TYPE_SCALARPRODUCT_ECC_BOB_CRYPTODATA); | ||
352 | msg->contained_element_count = htonl (2); | ||
353 | msg->prod_g_i_b_i = s->prod_g_i_b_i; | ||
354 | msg->prod_h_i_b_i = s->prod_h_i_b_i; | ||
355 | GNUNET_MQ_notify_sent (e, | ||
356 | &bob_cadet_done_cb, | ||
357 | s); | ||
358 | GNUNET_MQ_send (s->cadet_mq, | ||
359 | e); | ||
360 | } | ||
361 | |||
362 | |||
363 | /** | ||
364 | * Iterator to copy over messages from the hash map | ||
365 | * into an array for sorting. | ||
366 | * | ||
367 | * @param cls the `struct AliceServiceSession *` | ||
368 | * @param key the key (unused) | ||
369 | * @param value the `struct GNUNET_SCALARPRODUCT_Element *` | ||
370 | */ | ||
371 | static int | ||
372 | copy_element_cb (void *cls, | ||
373 | const struct GNUNET_HashCode *key, | ||
374 | void *value) | ||
375 | { | ||
376 | struct BobServiceSession *s = cls; | ||
377 | struct GNUNET_SCALARPRODUCT_Element *e = value; | ||
378 | |||
379 | s->sorted_elements[s->used_element_count].value = (int64_t) GNUNET_ntohll ( | ||
380 | e->value); | ||
381 | s->sorted_elements[s->used_element_count].key = &e->key; | ||
382 | s->used_element_count++; | ||
383 | return GNUNET_OK; | ||
384 | } | ||
385 | |||
386 | |||
387 | /** | ||
388 | * Compare two `struct MpiValue`s by key for sorting. | ||
389 | * | ||
390 | * @param a pointer to first `struct MpiValue *` | ||
391 | * @param b pointer to first `struct MpiValue *` | ||
392 | * @return -1 for a < b, 0 for a=b, 1 for a > b. | ||
393 | * TODO: code duplication with Alice! | ||
394 | */ | ||
395 | static int | ||
396 | element_cmp (const void *a, | ||
397 | const void *b) | ||
398 | { | ||
399 | const struct MpiElement *ma = a; | ||
400 | const struct MpiElement *mb = b; | ||
401 | |||
402 | return GNUNET_CRYPTO_hash_cmp (ma->key, | ||
403 | mb->key); | ||
404 | } | ||
405 | |||
406 | |||
407 | /** | ||
408 | * Check a multipart-chunk of a request from another service to | ||
409 | * calculate a scalarproduct with us. | ||
410 | * | ||
411 | * @param cls closure (set from #GNUNET_CADET_connect) | ||
412 | * @param msg the actual message | ||
413 | * @return #GNUNET_OK to keep the connection open, | ||
414 | * #GNUNET_SYSERR to close it (signal serious error) | ||
415 | */ | ||
416 | static int | ||
417 | check_alices_cryptodata_message (void *cls, | ||
418 | const struct EccAliceCryptodataMessage *msg) | ||
419 | { | ||
420 | struct BobServiceSession *s = cls; | ||
421 | uint32_t contained_elements; | ||
422 | size_t msg_length; | ||
423 | uint16_t msize; | ||
424 | unsigned int max; | ||
425 | |||
426 | msize = ntohs (msg->header.size); | ||
427 | if (msize <= sizeof(struct EccAliceCryptodataMessage)) | ||
428 | { | ||
429 | GNUNET_break_op (0); | ||
430 | return GNUNET_SYSERR; | ||
431 | } | ||
432 | contained_elements = ntohl (msg->contained_element_count); | ||
433 | /* Our intersection may still be ongoing, but this is nevertheless | ||
434 | an upper bound on the required array size */ | ||
435 | max = GNUNET_CONTAINER_multihashmap_size (s->intersected_elements); | ||
436 | msg_length = sizeof(struct EccAliceCryptodataMessage) | ||
437 | + contained_elements * sizeof(struct GNUNET_CRYPTO_EccPoint) * 2; | ||
438 | if ((msize != msg_length) || | ||
439 | (0 == contained_elements) || | ||
440 | (contained_elements > UINT16_MAX) || | ||
441 | (max < contained_elements + s->cadet_received_element_count)) | ||
442 | { | ||
443 | GNUNET_break_op (0); | ||
444 | return GNUNET_SYSERR; | ||
445 | } | ||
446 | return GNUNET_OK; | ||
447 | } | ||
448 | |||
449 | |||
450 | /** | ||
451 | * Handle a multipart-chunk of a request from another service to | ||
452 | * calculate a scalarproduct with us. | ||
453 | * | ||
454 | * @param cls closure (set from #GNUNET_CADET_connect) | ||
455 | * @param msg the actual message | ||
456 | */ | ||
457 | static void | ||
458 | handle_alices_cryptodata_message (void *cls, | ||
459 | const struct EccAliceCryptodataMessage *msg) | ||
460 | { | ||
461 | struct BobServiceSession *s = cls; | ||
462 | const struct GNUNET_CRYPTO_EccPoint *payload; | ||
463 | uint32_t contained_elements; | ||
464 | unsigned int max; | ||
465 | const struct GNUNET_CRYPTO_EccPoint *g_i; | ||
466 | const struct GNUNET_CRYPTO_EccPoint *h_i; | ||
467 | struct GNUNET_CRYPTO_EccPoint g_i_b_i; | ||
468 | struct GNUNET_CRYPTO_EccPoint h_i_b_i; | ||
469 | |||
470 | contained_elements = ntohl (msg->contained_element_count); | ||
471 | max = GNUNET_CONTAINER_multihashmap_size (s->intersected_elements); | ||
472 | /* sort our vector for the computation */ | ||
473 | if (NULL == s->sorted_elements) | ||
474 | { | ||
475 | s->sorted_elements | ||
476 | = GNUNET_new_array (GNUNET_CONTAINER_multihashmap_size ( | ||
477 | s->intersected_elements), | ||
478 | struct MpiElement); | ||
479 | s->used_element_count = 0; | ||
480 | GNUNET_CONTAINER_multihashmap_iterate (s->intersected_elements, | ||
481 | ©_element_cb, | ||
482 | s); | ||
483 | qsort (s->sorted_elements, | ||
484 | s->used_element_count, | ||
485 | sizeof(struct MpiElement), | ||
486 | &element_cmp); | ||
487 | } | ||
488 | |||
489 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
490 | "Received %u crypto values from Alice\n", | ||
491 | (unsigned int) contained_elements); | ||
492 | payload = (const struct GNUNET_CRYPTO_EccPoint *) &msg[1]; | ||
493 | |||
494 | for (unsigned int i = 0; i < contained_elements; i++) | ||
495 | { | ||
496 | int64_t val = s->sorted_elements[i + s->cadet_received_element_count].value; | ||
497 | struct GNUNET_CRYPTO_EccScalar vali; | ||
498 | |||
499 | GNUNET_assert (INT64_MIN != val); | ||
500 | GNUNET_CRYPTO_ecc_scalar_from_int (val > 0 ? val : -val, | ||
501 | &vali); | ||
502 | if (val < 0) | ||
503 | crypto_core_ed25519_scalar_negate (vali.v, | ||
504 | vali.v); | ||
505 | g_i = &payload[i * 2]; | ||
506 | /* g_i_b_i = g_i^vali */ | ||
507 | GNUNET_assert (GNUNET_OK == | ||
508 | GNUNET_CRYPTO_ecc_pmul_mpi (g_i, | ||
509 | &vali, | ||
510 | &g_i_b_i)); | ||
511 | h_i = &payload[i * 2 + 1]; | ||
512 | /* h_i_b_i = h_i^vali */ | ||
513 | GNUNET_assert (GNUNET_OK == | ||
514 | GNUNET_CRYPTO_ecc_pmul_mpi (h_i, | ||
515 | &vali, | ||
516 | &h_i_b_i)); | ||
517 | if (0 == i + s->cadet_received_element_count) | ||
518 | { | ||
519 | /* first iteration, nothing to add */ | ||
520 | s->prod_g_i_b_i = g_i_b_i; | ||
521 | s->prod_h_i_b_i = h_i_b_i; | ||
522 | } | ||
523 | else | ||
524 | { | ||
525 | /* further iterations, cummulate resulting value */ | ||
526 | GNUNET_assert (GNUNET_OK == | ||
527 | GNUNET_CRYPTO_ecc_add (&s->prod_g_i_b_i, | ||
528 | &g_i_b_i, | ||
529 | &s->prod_g_i_b_i)); | ||
530 | GNUNET_assert (GNUNET_OK == | ||
531 | GNUNET_CRYPTO_ecc_add (&s->prod_h_i_b_i, | ||
532 | &h_i_b_i, | ||
533 | &s->prod_h_i_b_i)); | ||
534 | } | ||
535 | } | ||
536 | s->cadet_received_element_count += contained_elements; | ||
537 | if ((s->cadet_received_element_count == max) && | ||
538 | (NULL == s->intersection_op)) | ||
539 | { | ||
540 | /* intersection has finished also on our side, and | ||
541 | we got the full set, so we can proceed with the | ||
542 | CADET response(s) */ | ||
543 | transmit_bobs_cryptodata_message (s); | ||
544 | } | ||
545 | GNUNET_CADET_receive_done (s->channel); | ||
546 | } | ||
547 | |||
548 | |||
549 | /** | ||
550 | * Callback for set operation results. Called for each element | ||
551 | * that needs to be removed from the result set. | ||
552 | * | ||
553 | * @param cls closure with the `struct BobServiceSession` | ||
554 | * @param element a result element, only valid if status is #GNUNET_SETI_STATUS_OK | ||
555 | * @param current_size current set size | ||
556 | * @param status what has happened with the set intersection? | ||
557 | */ | ||
558 | static void | ||
559 | cb_intersection_element_removed (void *cls, | ||
560 | const struct GNUNET_SETI_Element *element, | ||
561 | uint64_t current_size, | ||
562 | enum GNUNET_SETI_Status status) | ||
563 | { | ||
564 | struct BobServiceSession *s = cls; | ||
565 | struct GNUNET_SCALARPRODUCT_Element *se; | ||
566 | |||
567 | switch (status) | ||
568 | { | ||
569 | case GNUNET_SETI_STATUS_DEL_LOCAL: | ||
570 | /* this element has been removed from the set */ | ||
571 | se = GNUNET_CONTAINER_multihashmap_get (s->intersected_elements, | ||
572 | element->data); | ||
573 | GNUNET_assert (NULL != se); | ||
574 | LOG (GNUNET_ERROR_TYPE_DEBUG, | ||
575 | "Removed element with key %s and value %lld\n", | ||
576 | GNUNET_h2s (&se->key), | ||
577 | (long long) GNUNET_ntohll (se->value)); | ||
578 | GNUNET_assert (GNUNET_YES == | ||
579 | GNUNET_CONTAINER_multihashmap_remove ( | ||
580 | s->intersected_elements, | ||
581 | element->data, | ||
582 | se)); | ||
583 | GNUNET_free (se); | ||
584 | return; | ||
585 | case GNUNET_SETI_STATUS_DONE: | ||
586 | s->intersection_op = NULL; | ||
587 | GNUNET_break (NULL == s->intersection_set); | ||
588 | GNUNET_CADET_receive_done (s->channel); | ||
589 | LOG (GNUNET_ERROR_TYPE_DEBUG, | ||
590 | "Finished intersection, %d items remain\n", | ||
591 | GNUNET_CONTAINER_multihashmap_size (s->intersected_elements)); | ||
592 | if (s->client_received_element_count == | ||
593 | GNUNET_CONTAINER_multihashmap_size (s->intersected_elements)) | ||
594 | { | ||
595 | /* CADET transmission from Alice is also already done, | ||
596 | start with our own reply */ | ||
597 | transmit_bobs_cryptodata_message (s); | ||
598 | } | ||
599 | return; | ||
600 | case GNUNET_SETI_STATUS_FAILURE: | ||
601 | /* unhandled status code */ | ||
602 | LOG (GNUNET_ERROR_TYPE_DEBUG, | ||
603 | "Set intersection failed!\n"); | ||
604 | s->intersection_op = NULL; | ||
605 | if (NULL != s->intersection_set) | ||
606 | { | ||
607 | GNUNET_SETI_destroy (s->intersection_set); | ||
608 | s->intersection_set = NULL; | ||
609 | } | ||
610 | s->status = GNUNET_SCALARPRODUCT_STATUS_FAILURE; | ||
611 | prepare_client_end_notification (s); | ||
612 | return; | ||
613 | |||
614 | default: | ||
615 | GNUNET_break (0); | ||
616 | return; | ||
617 | } | ||
618 | } | ||
619 | |||
620 | |||
621 | /** | ||
622 | * We've paired up a client session with an incoming CADET request. | ||
623 | * Initiate set intersection work. | ||
624 | * | ||
625 | * @param s client session to start intersection for | ||
626 | */ | ||
627 | static void | ||
628 | start_intersection (struct BobServiceSession *s) | ||
629 | { | ||
630 | struct GNUNET_HashCode set_sid; | ||
631 | |||
632 | GNUNET_CRYPTO_hash (&s->session_id, | ||
633 | sizeof(struct GNUNET_HashCode), | ||
634 | &set_sid); | ||
635 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
636 | "Got session with key %s and %u elements, starting intersection.\n", | ||
637 | GNUNET_h2s (&s->session_id), | ||
638 | (unsigned int) s->total); | ||
639 | |||
640 | s->intersection_op | ||
641 | = GNUNET_SETI_prepare (&s->peer, | ||
642 | &set_sid, | ||
643 | NULL, | ||
644 | (struct GNUNET_SETI_Option[]) { { 0 } }, | ||
645 | &cb_intersection_element_removed, | ||
646 | s); | ||
647 | if (GNUNET_OK != | ||
648 | GNUNET_SETI_commit (s->intersection_op, | ||
649 | s->intersection_set)) | ||
650 | { | ||
651 | GNUNET_break (0); | ||
652 | s->status = GNUNET_SCALARPRODUCT_STATUS_FAILURE; | ||
653 | prepare_client_end_notification (s); | ||
654 | return; | ||
655 | } | ||
656 | GNUNET_SETI_destroy (s->intersection_set); | ||
657 | s->intersection_set = NULL; | ||
658 | } | ||
659 | |||
660 | |||
661 | /** | ||
662 | * Handle a request from Alice to calculate a scalarproduct with us (Bob). | ||
663 | * | ||
664 | * @param cls closure (set from #GNUNET_CADET_connect) | ||
665 | * @param msg the actual message | ||
666 | */ | ||
667 | static void | ||
668 | handle_alices_computation_request (void *cls, | ||
669 | const struct EccServiceRequestMessage *msg) | ||
670 | { | ||
671 | struct BobServiceSession *s = cls; | ||
672 | |||
673 | s->session_id = msg->session_id; // ?? | ||
674 | if (s->client_received_element_count < s->total) | ||
675 | { | ||
676 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
677 | "Alice ready, still waiting for Bob client data!\n"); | ||
678 | return; | ||
679 | } | ||
680 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
681 | "Both ready, launching intersection!\n"); | ||
682 | start_intersection (s); | ||
683 | } | ||
684 | |||
685 | |||
686 | /** | ||
687 | * Function called for inbound channels on Bob's end. Does some | ||
688 | * preliminary initialization, more happens after we get Alice's first | ||
689 | * message. | ||
690 | * | ||
691 | * @param cls our `struct BobServiceSession` | ||
692 | * @param channel new handle to the channel | ||
693 | * @param initiator peer that started the channel | ||
694 | * @return session associated with the channel | ||
695 | */ | ||
696 | static void * | ||
697 | cb_channel_incoming (void *cls, | ||
698 | struct GNUNET_CADET_Channel *channel, | ||
699 | const struct GNUNET_PeerIdentity *initiator) | ||
700 | { | ||
701 | struct BobServiceSession *s = cls; | ||
702 | |||
703 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
704 | "New incoming channel from peer %s.\n", | ||
705 | GNUNET_i2s (initiator)); | ||
706 | GNUNET_CADET_close_port (s->port); | ||
707 | s->port = NULL; | ||
708 | s->peer = *initiator; | ||
709 | s->channel = channel; | ||
710 | s->cadet_mq = GNUNET_CADET_get_mq (s->channel); | ||
711 | return s; | ||
712 | } | ||
713 | |||
714 | |||
715 | /** | ||
716 | * We're receiving additional set data. Check it is well-formed. | ||
717 | * | ||
718 | * @param cls identification of the client | ||
719 | * @param msg the actual message | ||
720 | * @return #GNUNET_OK if @a msg is well-formed | ||
721 | */ | ||
722 | static int | ||
723 | check_bob_client_message_multipart ( | ||
724 | void *cls, | ||
725 | const struct ComputationBobCryptodataMultipartMessage *msg) | ||
726 | { | ||
727 | struct BobServiceSession *s = cls; | ||
728 | uint32_t contained_count; | ||
729 | uint16_t msize; | ||
730 | |||
731 | msize = ntohs (msg->header.size); | ||
732 | contained_count = ntohl (msg->element_count_contained); | ||
733 | if ((msize != (sizeof(struct ComputationBobCryptodataMultipartMessage) | ||
734 | + contained_count * sizeof(struct | ||
735 | GNUNET_SCALARPRODUCT_Element))) || | ||
736 | (0 == contained_count) || | ||
737 | (UINT16_MAX < contained_count) || | ||
738 | (s->total == s->client_received_element_count) || | ||
739 | (s->total < s->client_received_element_count + contained_count)) | ||
740 | { | ||
741 | GNUNET_break (0); | ||
742 | return GNUNET_SYSERR; | ||
743 | } | ||
744 | return GNUNET_OK; | ||
745 | } | ||
746 | |||
747 | |||
748 | /** | ||
749 | * We're receiving additional set data. Add it to our | ||
750 | * set and if we are done, initiate the transaction. | ||
751 | * | ||
752 | * @param cls identification of the client | ||
753 | * @param msg the actual message | ||
754 | */ | ||
755 | static void | ||
756 | handle_bob_client_message_multipart ( | ||
757 | void *cls, | ||
758 | const struct ComputationBobCryptodataMultipartMessage *msg) | ||
759 | { | ||
760 | struct BobServiceSession *s = cls; | ||
761 | uint32_t contained_count; | ||
762 | const struct GNUNET_SCALARPRODUCT_Element *elements; | ||
763 | struct GNUNET_SETI_Element set_elem; | ||
764 | struct GNUNET_SCALARPRODUCT_Element *elem; | ||
765 | |||
766 | contained_count = ntohl (msg->element_count_contained); | ||
767 | elements = (const struct GNUNET_SCALARPRODUCT_Element *) &msg[1]; | ||
768 | for (uint32_t i = 0; i < contained_count; i++) | ||
769 | { | ||
770 | elem = GNUNET_new (struct GNUNET_SCALARPRODUCT_Element); | ||
771 | GNUNET_memcpy (elem, | ||
772 | &elements[i], | ||
773 | sizeof(struct GNUNET_SCALARPRODUCT_Element)); | ||
774 | if (GNUNET_SYSERR == | ||
775 | GNUNET_CONTAINER_multihashmap_put (s->intersected_elements, | ||
776 | &elem->key, | ||
777 | elem, | ||
778 | GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY)) | ||
779 | { | ||
780 | GNUNET_break (0); | ||
781 | GNUNET_free (elem); | ||
782 | continue; | ||
783 | } | ||
784 | set_elem.data = &elem->key; | ||
785 | set_elem.size = sizeof(elem->key); | ||
786 | set_elem.element_type = 0; | ||
787 | GNUNET_SETI_add_element (s->intersection_set, | ||
788 | &set_elem, | ||
789 | NULL, NULL); | ||
790 | } | ||
791 | s->client_received_element_count += contained_count; | ||
792 | GNUNET_SERVICE_client_continue (s->client); | ||
793 | if (s->total != s->client_received_element_count) | ||
794 | { | ||
795 | /* more to come */ | ||
796 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
797 | "Request still partial, waiting for more client data!\n"); | ||
798 | return; | ||
799 | } | ||
800 | if (NULL == s->channel) | ||
801 | { | ||
802 | /* no Alice waiting for this request, wait for Alice */ | ||
803 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
804 | "Client ready, still waiting for Alice!\n"); | ||
805 | return; | ||
806 | } | ||
807 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
808 | "Both ready, launching intersection!\n"); | ||
809 | start_intersection (s); | ||
810 | } | ||
811 | |||
812 | |||
813 | /** | ||
814 | * Handler for Bob's a client request message. Check @a msg is | ||
815 | * well-formed. | ||
816 | * | ||
817 | * @param cls identification of the client | ||
818 | * @param msg the actual message | ||
819 | * @return #GNUNET_OK if @a msg is well-formed | ||
820 | */ | ||
821 | static int | ||
822 | check_bob_client_message (void *cls, | ||
823 | const struct BobComputationMessage *msg) | ||
824 | { | ||
825 | struct BobServiceSession *s = cls; | ||
826 | uint32_t contained_count; | ||
827 | uint32_t total_count; | ||
828 | uint16_t msize; | ||
829 | |||
830 | if (GNUNET_SCALARPRODUCT_STATUS_INIT != s->status) | ||
831 | { | ||
832 | GNUNET_break (0); | ||
833 | return GNUNET_SYSERR; | ||
834 | } | ||
835 | msize = ntohs (msg->header.size); | ||
836 | total_count = ntohl (msg->element_count_total); | ||
837 | contained_count = ntohl (msg->element_count_contained); | ||
838 | if ((0 == total_count) || | ||
839 | (0 == contained_count) || | ||
840 | (UINT16_MAX < contained_count) || | ||
841 | (msize != (sizeof(struct BobComputationMessage) | ||
842 | + contained_count * sizeof(struct | ||
843 | GNUNET_SCALARPRODUCT_Element)))) | ||
844 | { | ||
845 | GNUNET_break_op (0); | ||
846 | return GNUNET_SYSERR; | ||
847 | } | ||
848 | return GNUNET_OK; | ||
849 | } | ||
850 | |||
851 | |||
852 | /** | ||
853 | * Handler for Bob's a client request message. Bob is in the response | ||
854 | * role, keep the values + session and waiting for a matching session | ||
855 | * or process a waiting request from Alice. | ||
856 | * | ||
857 | * @param cls identification of the client | ||
858 | * @param msg the actual message | ||
859 | */ | ||
860 | static void | ||
861 | handle_bob_client_message (void *cls, | ||
862 | const struct BobComputationMessage *msg) | ||
863 | { | ||
864 | struct BobServiceSession *s = cls; | ||
865 | struct GNUNET_MQ_MessageHandler cadet_handlers[] = { | ||
866 | GNUNET_MQ_hd_fixed_size (alices_computation_request, | ||
867 | GNUNET_MESSAGE_TYPE_SCALARPRODUCT_ECC_SESSION_INITIALIZATION, | ||
868 | struct EccServiceRequestMessage, | ||
869 | s), | ||
870 | GNUNET_MQ_hd_var_size (alices_cryptodata_message, | ||
871 | GNUNET_MESSAGE_TYPE_SCALARPRODUCT_ECC_ALICE_CRYPTODATA, | ||
872 | struct EccAliceCryptodataMessage, | ||
873 | s), | ||
874 | GNUNET_MQ_handler_end () | ||
875 | }; | ||
876 | uint32_t contained_count; | ||
877 | uint32_t total_count; | ||
878 | const struct GNUNET_SCALARPRODUCT_Element *elements; | ||
879 | struct GNUNET_SETI_Element set_elem; | ||
880 | struct GNUNET_SCALARPRODUCT_Element *elem; | ||
881 | |||
882 | total_count = ntohl (msg->element_count_total); | ||
883 | contained_count = ntohl (msg->element_count_contained); | ||
884 | |||
885 | s->status = GNUNET_SCALARPRODUCT_STATUS_ACTIVE; | ||
886 | s->total = total_count; | ||
887 | s->client_received_element_count = contained_count; | ||
888 | s->session_id = msg->session_key; | ||
889 | elements = (const struct GNUNET_SCALARPRODUCT_Element *) &msg[1]; | ||
890 | s->intersected_elements | ||
891 | = GNUNET_CONTAINER_multihashmap_create (s->total, | ||
892 | GNUNET_YES); | ||
893 | s->intersection_set = GNUNET_SETI_create (cfg); | ||
894 | for (uint32_t i = 0; i < contained_count; i++) | ||
895 | { | ||
896 | if (0 == GNUNET_ntohll (elements[i].value)) | ||
897 | continue; | ||
898 | elem = GNUNET_new (struct GNUNET_SCALARPRODUCT_Element); | ||
899 | GNUNET_memcpy (elem, | ||
900 | &elements[i], | ||
901 | sizeof(struct GNUNET_SCALARPRODUCT_Element)); | ||
902 | if (GNUNET_SYSERR == | ||
903 | GNUNET_CONTAINER_multihashmap_put (s->intersected_elements, | ||
904 | &elem->key, | ||
905 | elem, | ||
906 | GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY)) | ||
907 | { | ||
908 | GNUNET_break (0); | ||
909 | GNUNET_free (elem); | ||
910 | continue; | ||
911 | } | ||
912 | set_elem.data = &elem->key; | ||
913 | set_elem.size = sizeof(elem->key); | ||
914 | set_elem.element_type = 0; | ||
915 | GNUNET_SETI_add_element (s->intersection_set, | ||
916 | &set_elem, | ||
917 | NULL, NULL); | ||
918 | s->used_element_count++; | ||
919 | } | ||
920 | GNUNET_SERVICE_client_continue (s->client); | ||
921 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
922 | "Received client request, opening port %s!\n", | ||
923 | GNUNET_h2s (&msg->session_key)); | ||
924 | s->port = GNUNET_CADET_open_port (my_cadet, | ||
925 | &msg->session_key, | ||
926 | &cb_channel_incoming, | ||
927 | s, | ||
928 | NULL, | ||
929 | &cb_channel_destruction, | ||
930 | cadet_handlers); | ||
931 | if (NULL == s->port) | ||
932 | { | ||
933 | GNUNET_break (0); | ||
934 | GNUNET_SERVICE_client_drop (s->client); | ||
935 | return; | ||
936 | } | ||
937 | } | ||
938 | |||
939 | |||
940 | /** | ||
941 | * Task run during shutdown. | ||
942 | * | ||
943 | * @param cls unused | ||
944 | */ | ||
945 | static void | ||
946 | shutdown_task (void *cls) | ||
947 | { | ||
948 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
949 | "Shutting down, initiating cleanup.\n"); | ||
950 | // FIXME: we have to cut our connections to CADET first! | ||
951 | if (NULL != my_cadet) | ||
952 | { | ||
953 | GNUNET_CADET_disconnect (my_cadet); | ||
954 | my_cadet = NULL; | ||
955 | } | ||
956 | if (NULL != edc) | ||
957 | { | ||
958 | GNUNET_CRYPTO_ecc_dlog_release (edc); | ||
959 | edc = NULL; | ||
960 | } | ||
961 | } | ||
962 | |||
963 | |||
964 | /** | ||
965 | * A client connected. | ||
966 | * | ||
967 | * Setup the associated data structure. | ||
968 | * | ||
969 | * @param cls closure, NULL | ||
970 | * @param client identification of the client | ||
971 | * @param mq message queue to communicate with @a client | ||
972 | * @return our `struct BobServiceSession` | ||
973 | */ | ||
974 | static void * | ||
975 | client_connect_cb (void *cls, | ||
976 | struct GNUNET_SERVICE_Client *client, | ||
977 | struct GNUNET_MQ_Handle *mq) | ||
978 | { | ||
979 | struct BobServiceSession *s; | ||
980 | |||
981 | s = GNUNET_new (struct BobServiceSession); | ||
982 | s->client = client; | ||
983 | s->client_mq = mq; | ||
984 | return s; | ||
985 | } | ||
986 | |||
987 | |||
988 | /** | ||
989 | * A client disconnected. | ||
990 | * | ||
991 | * Remove the associated session(s), release data structures | ||
992 | * and cancel pending outgoing transmissions to the client. | ||
993 | * | ||
994 | * @param cls closure, NULL | ||
995 | * @param client identification of the client | ||
996 | * @param app_cls our `struct BobServiceSession` | ||
997 | */ | ||
998 | static void | ||
999 | client_disconnect_cb (void *cls, | ||
1000 | struct GNUNET_SERVICE_Client *client, | ||
1001 | void *app_cls) | ||
1002 | { | ||
1003 | struct BobServiceSession *s = app_cls; | ||
1004 | |||
1005 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
1006 | "Client disconnected from us.\n"); | ||
1007 | s->client = NULL; | ||
1008 | destroy_service_session (s); | ||
1009 | } | ||
1010 | |||
1011 | |||
1012 | /** | ||
1013 | * Initialization of the program and message handlers | ||
1014 | * | ||
1015 | * @param cls closure | ||
1016 | * @param c configuration to use | ||
1017 | * @param service the initialized service | ||
1018 | */ | ||
1019 | static void | ||
1020 | run (void *cls, | ||
1021 | const struct GNUNET_CONFIGURATION_Handle *c, | ||
1022 | struct GNUNET_SERVICE_Handle *service) | ||
1023 | { | ||
1024 | cfg = c; | ||
1025 | /* We don't really do DLOG, so we can setup with very minimal resources */ | ||
1026 | edc = GNUNET_CRYPTO_ecc_dlog_prepare (4 /* max value */, | ||
1027 | 2 /* RAM */); | ||
1028 | my_cadet = GNUNET_CADET_connect (cfg); | ||
1029 | GNUNET_SCHEDULER_add_shutdown (&shutdown_task, | ||
1030 | NULL); | ||
1031 | if (NULL == my_cadet) | ||
1032 | { | ||
1033 | GNUNET_log (GNUNET_ERROR_TYPE_ERROR, | ||
1034 | _ ("Connect to CADET failed\n")); | ||
1035 | GNUNET_SCHEDULER_shutdown (); | ||
1036 | return; | ||
1037 | } | ||
1038 | } | ||
1039 | |||
1040 | |||
1041 | /** | ||
1042 | * Define "main" method using service macro. | ||
1043 | */ | ||
1044 | GNUNET_SERVICE_MAIN | ||
1045 | ("scalarproduct-bob", | ||
1046 | GNUNET_SERVICE_OPTION_NONE, | ||
1047 | &run, | ||
1048 | &client_connect_cb, | ||
1049 | &client_disconnect_cb, | ||
1050 | NULL, | ||
1051 | GNUNET_MQ_hd_var_size (bob_client_message, | ||
1052 | GNUNET_MESSAGE_TYPE_SCALARPRODUCT_CLIENT_TO_BOB, | ||
1053 | struct BobComputationMessage, | ||
1054 | NULL), | ||
1055 | GNUNET_MQ_hd_var_size (bob_client_message_multipart, | ||
1056 | GNUNET_MESSAGE_TYPE_SCALARPRODUCT_CLIENT_MULTIPART_BOB, | ||
1057 | struct ComputationBobCryptodataMultipartMessage, | ||
1058 | NULL), | ||
1059 | GNUNET_MQ_handler_end ()); | ||
1060 | |||
1061 | |||
1062 | /* end of gnunet-service-scalarproduct-ecc_bob.c */ | ||
diff --git a/src/scalarproduct/gnunet-service-scalarproduct.h b/src/scalarproduct/gnunet-service-scalarproduct.h deleted file mode 100644 index 4e79afa2f..000000000 --- a/src/scalarproduct/gnunet-service-scalarproduct.h +++ /dev/null | |||
@@ -1,142 +0,0 @@ | |||
1 | /* | ||
2 | This file is part of GNUnet. | ||
3 | Copyright (C) 2013, 2014 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.h | ||
22 | * @brief scalarproduct service P2P messages | ||
23 | * @author Christian M. Fuchs | ||
24 | * @author Christian Grothoff | ||
25 | */ | ||
26 | #ifndef GNUNET_SERVICE_SCALARPRODUCT_H | ||
27 | #define GNUNET_SERVICE_SCALARPRODUCT_H | ||
28 | |||
29 | |||
30 | GNUNET_NETWORK_STRUCT_BEGIN | ||
31 | |||
32 | /** | ||
33 | * Message type passed from requesting service Alice to responding | ||
34 | * service Bob to initiate a request and make Bob participate in our | ||
35 | * protocol. Afterwards, Bob is expected to perform the set | ||
36 | * intersection with Alice. Once that has succeeded, Alice will | ||
37 | * send a `struct AliceCryptodataMessage *`. Bob is not expected | ||
38 | * to respond via CADET in the meantime. | ||
39 | */ | ||
40 | struct ServiceRequestMessage | ||
41 | { | ||
42 | /** | ||
43 | * Type is #GNUNET_MESSAGE_TYPE_SCALARPRODUCT_SESSION_INITIALIZATION | ||
44 | */ | ||
45 | struct GNUNET_MessageHeader header; | ||
46 | |||
47 | /** | ||
48 | * For alignment. Always zero. | ||
49 | */ | ||
50 | uint32_t reserved; | ||
51 | |||
52 | /** | ||
53 | * The transaction/session key used to identify a session | ||
54 | */ | ||
55 | struct GNUNET_HashCode session_id; | ||
56 | |||
57 | /** | ||
58 | * Alice's public key | ||
59 | */ | ||
60 | struct GNUNET_CRYPTO_PaillierPublicKey public_key; | ||
61 | }; | ||
62 | |||
63 | |||
64 | /** | ||
65 | * Vector of Pallier-encrypted values sent by Alice to Bob | ||
66 | * (after set intersection). Alice may send messages of this | ||
67 | * type repeatedly to transmit all values. | ||
68 | */ | ||
69 | struct AliceCryptodataMessage | ||
70 | { | ||
71 | /** | ||
72 | * Type is #GNUNET_MESSAGE_TYPE_SCALARPRODUCT_ALICE_CRYPTODATA | ||
73 | */ | ||
74 | struct GNUNET_MessageHeader header; | ||
75 | |||
76 | /** | ||
77 | * How many elements we appended to this message? In NBO. | ||
78 | */ | ||
79 | uint32_t contained_element_count GNUNET_PACKED; | ||
80 | |||
81 | /** | ||
82 | * struct GNUNET_CRYPTO_PaillierCiphertext[contained_element_count] | ||
83 | */ | ||
84 | }; | ||
85 | |||
86 | |||
87 | /** | ||
88 | * Message type passed from responding service Bob to responding | ||
89 | * service Alice to complete a request and allow Alice to compute the | ||
90 | * result. If Bob's reply does not fit into this one message, the | ||
91 | * conversation may be continued with `struct BobCryptodataMultipartMessage` | ||
92 | * messages afterwards. | ||
93 | */ | ||
94 | struct BobCryptodataMessage | ||
95 | { | ||
96 | /** | ||
97 | * GNUNET message header with type | ||
98 | * #GNUNET_MESSAGE_TYPE_SCALARPRODUCT_BOB_CRYPTODATA. | ||
99 | */ | ||
100 | struct GNUNET_MessageHeader header; | ||
101 | |||
102 | /** | ||
103 | * How many elements this individual message delivers (in NBO). | ||
104 | */ | ||
105 | uint32_t contained_element_count GNUNET_PACKED; | ||
106 | |||
107 | /** | ||
108 | * followed by s | s' | k[i][perm] | ||
109 | */ | ||
110 | }; | ||
111 | |||
112 | |||
113 | /** | ||
114 | * Multipart Message type passed between to supply additional elements | ||
115 | * for the peer. Send from Bob to Alice with additional elements | ||
116 | * of k[i][perm] after his `struct BobCryptodataMessage *`. | ||
117 | * Once all k-values have been transmitted, Bob is finished and | ||
118 | * Alice can transmit the final result to the client. | ||
119 | */ | ||
120 | struct BobCryptodataMultipartMessage | ||
121 | { | ||
122 | /** | ||
123 | * GNUNET message header | ||
124 | */ | ||
125 | struct GNUNET_MessageHeader header; | ||
126 | |||
127 | /** | ||
128 | * How many elements we supply within this message? In NBO. | ||
129 | */ | ||
130 | uint32_t contained_element_count GNUNET_PACKED; | ||
131 | |||
132 | /** | ||
133 | * Followed by `struct | ||
134 | * GNUNET_CRYPTO_PaillierCiphertext[contained_element_count]` | ||
135 | */ | ||
136 | }; | ||
137 | |||
138 | |||
139 | GNUNET_NETWORK_STRUCT_END | ||
140 | |||
141 | |||
142 | #endif | ||
diff --git a/src/scalarproduct/gnunet-service-scalarproduct_alice.c b/src/scalarproduct/gnunet-service-scalarproduct_alice.c deleted file mode 100644 index 665d2ad7f..000000000 --- a/src/scalarproduct/gnunet-service-scalarproduct_alice.c +++ /dev/null | |||
@@ -1,1387 +0,0 @@ | |||
1 | /* | ||
2 | This file is part of GNUnet. | ||
3 | Copyright (C) 2013, 2014, 2017 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_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.h" | ||
38 | |||
39 | #define LOG(kind, ...) \ | ||
40 | GNUNET_log_from (kind, "scalarproduct-alice", __VA_ARGS__) | ||
41 | |||
42 | /** | ||
43 | * An encrypted element key-value pair. | ||
44 | */ | ||
45 | struct MpiElement | ||
46 | { | ||
47 | /** | ||
48 | * Key used to identify matching pairs of values to multiply. | ||
49 | * Points into an existing data structure, to avoid copying | ||
50 | * and doubling memory use. | ||
51 | */ | ||
52 | const struct GNUNET_HashCode *key; | ||
53 | |||
54 | /** | ||
55 | * Value represented (a). | ||
56 | */ | ||
57 | gcry_mpi_t value; | ||
58 | }; | ||
59 | |||
60 | |||
61 | /** | ||
62 | * A scalarproduct session which tracks | ||
63 | * a request form the client to our final response. | ||
64 | */ | ||
65 | struct AliceServiceSession | ||
66 | { | ||
67 | /** | ||
68 | * (hopefully) unique transaction ID | ||
69 | */ | ||
70 | struct GNUNET_HashCode session_id; | ||
71 | |||
72 | /** | ||
73 | * Alice or Bob's peerID | ||
74 | */ | ||
75 | struct GNUNET_PeerIdentity peer; | ||
76 | |||
77 | /** | ||
78 | * The client this request is related to. | ||
79 | */ | ||
80 | struct GNUNET_SERVICE_Client *client; | ||
81 | |||
82 | /** | ||
83 | * The message queue for the client. | ||
84 | */ | ||
85 | struct GNUNET_MQ_Handle *client_mq; | ||
86 | |||
87 | /** | ||
88 | * The message queue for CADET. | ||
89 | */ | ||
90 | struct GNUNET_MQ_Handle *cadet_mq; | ||
91 | |||
92 | /** | ||
93 | * all non-0-value'd elements transmitted to us. | ||
94 | * Values are of type `struct GNUNET_SCALARPRODUCT_Element *` | ||
95 | */ | ||
96 | struct GNUNET_CONTAINER_MultiHashMap *intersected_elements; | ||
97 | |||
98 | /** | ||
99 | * Set of elements for which will conduction an intersection. | ||
100 | * the resulting elements are then used for computing the scalar product. | ||
101 | */ | ||
102 | struct GNUNET_SETI_Handle *intersection_set; | ||
103 | |||
104 | /** | ||
105 | * Set of elements for which will conduction an intersection. | ||
106 | * the resulting elements are then used for computing the scalar product. | ||
107 | */ | ||
108 | struct GNUNET_SETI_OperationHandle *intersection_op; | ||
109 | |||
110 | /** | ||
111 | * Handle to Alice's Intersection operation listening for Bob | ||
112 | */ | ||
113 | struct GNUNET_SETI_ListenHandle *intersection_listen; | ||
114 | |||
115 | /** | ||
116 | * channel-handle associated with our cadet handle | ||
117 | */ | ||
118 | struct GNUNET_CADET_Channel *channel; | ||
119 | |||
120 | /** | ||
121 | * a(Alice), sorted array by key of length @e used_element_count. | ||
122 | */ | ||
123 | struct MpiElement *sorted_elements; | ||
124 | |||
125 | /** | ||
126 | * Bob's permutation p of R | ||
127 | */ | ||
128 | struct GNUNET_CRYPTO_PaillierCiphertext *r; | ||
129 | |||
130 | /** | ||
131 | * Bob's permutation q of R | ||
132 | */ | ||
133 | struct GNUNET_CRYPTO_PaillierCiphertext *r_prime; | ||
134 | |||
135 | /** | ||
136 | * Bob's "s" | ||
137 | */ | ||
138 | struct GNUNET_CRYPTO_PaillierCiphertext s; | ||
139 | |||
140 | /** | ||
141 | * Bob's "s'" | ||
142 | */ | ||
143 | struct GNUNET_CRYPTO_PaillierCiphertext s_prime; | ||
144 | |||
145 | /** | ||
146 | * The computed scalar | ||
147 | */ | ||
148 | gcry_mpi_t product; | ||
149 | |||
150 | /** | ||
151 | * How many elements we were supplied with from the client (total | ||
152 | * count before intersection). | ||
153 | */ | ||
154 | uint32_t total; | ||
155 | |||
156 | /** | ||
157 | * How many elements actually are used for the scalar product. | ||
158 | * Size of the arrays in @e r and @e r_prime. Sometimes also | ||
159 | * reset to 0 and used as a counter! | ||
160 | */ | ||
161 | uint32_t used_element_count; | ||
162 | |||
163 | /** | ||
164 | * Already transferred elements from client to us. | ||
165 | * Less or equal than @e total. | ||
166 | */ | ||
167 | uint32_t client_received_element_count; | ||
168 | |||
169 | /** | ||
170 | * Already transferred elements from Bob to us. | ||
171 | * Less or equal than @e total. | ||
172 | */ | ||
173 | uint32_t cadet_received_element_count; | ||
174 | |||
175 | /** | ||
176 | * State of this session. In | ||
177 | * #GNUNET_SCALARPRODUCT_STATUS_ACTIVE while operation is | ||
178 | * ongoing, afterwards in #GNUNET_SCALARPRODUCT_STATUS_SUCCESS or | ||
179 | * #GNUNET_SCALARPRODUCT_STATUS_FAILURE. | ||
180 | */ | ||
181 | enum GNUNET_SCALARPRODUCT_ResponseStatus status; | ||
182 | |||
183 | /** | ||
184 | * Flag to prevent recursive calls to #destroy_service_session() from | ||
185 | * doing harm. | ||
186 | */ | ||
187 | int in_destroy; | ||
188 | }; | ||
189 | |||
190 | |||
191 | /** | ||
192 | * GNUnet configuration handle | ||
193 | */ | ||
194 | static const struct GNUNET_CONFIGURATION_Handle *cfg; | ||
195 | |||
196 | /** | ||
197 | * Service's own public key | ||
198 | */ | ||
199 | static struct GNUNET_CRYPTO_PaillierPublicKey my_pubkey; | ||
200 | |||
201 | /** | ||
202 | * Service's own private key | ||
203 | */ | ||
204 | static struct GNUNET_CRYPTO_PaillierPrivateKey my_privkey; | ||
205 | |||
206 | /** | ||
207 | * Service's offset for values that could possibly be negative but are plaintext for encryption. | ||
208 | */ | ||
209 | static gcry_mpi_t my_offset; | ||
210 | |||
211 | /** | ||
212 | * Handle to the CADET service. | ||
213 | */ | ||
214 | static struct GNUNET_CADET_Handle *my_cadet; | ||
215 | |||
216 | |||
217 | /** | ||
218 | * Iterator called to free elements. | ||
219 | * | ||
220 | * @param cls the `struct AliceServiceSession *` (unused) | ||
221 | * @param key the key (unused) | ||
222 | * @param value value to free | ||
223 | * @return #GNUNET_OK (continue to iterate) | ||
224 | */ | ||
225 | static int | ||
226 | free_element_cb (void *cls, const struct GNUNET_HashCode *key, void *value) | ||
227 | { | ||
228 | struct GNUNET_SCALARPRODUCT_Element *e = value; | ||
229 | |||
230 | GNUNET_free (e); | ||
231 | return GNUNET_OK; | ||
232 | } | ||
233 | |||
234 | |||
235 | /** | ||
236 | * Destroy session state, we are done with it. | ||
237 | * | ||
238 | * @param s the session to free elements from | ||
239 | */ | ||
240 | static void | ||
241 | destroy_service_session (struct AliceServiceSession *s) | ||
242 | { | ||
243 | if (GNUNET_YES == s->in_destroy) | ||
244 | return; | ||
245 | s->in_destroy = GNUNET_YES; | ||
246 | if (NULL != s->client) | ||
247 | { | ||
248 | struct GNUNET_SERVICE_Client *c = s->client; | ||
249 | |||
250 | s->client = NULL; | ||
251 | GNUNET_SERVICE_client_drop (c); | ||
252 | } | ||
253 | if (NULL != s->channel) | ||
254 | { | ||
255 | GNUNET_CADET_channel_destroy (s->channel); | ||
256 | s->channel = NULL; | ||
257 | } | ||
258 | if (NULL != s->intersected_elements) | ||
259 | { | ||
260 | GNUNET_CONTAINER_multihashmap_iterate (s->intersected_elements, | ||
261 | &free_element_cb, | ||
262 | s); | ||
263 | GNUNET_CONTAINER_multihashmap_destroy (s->intersected_elements); | ||
264 | s->intersected_elements = NULL; | ||
265 | } | ||
266 | if (NULL != s->intersection_listen) | ||
267 | { | ||
268 | GNUNET_SETI_listen_cancel (s->intersection_listen); | ||
269 | s->intersection_listen = NULL; | ||
270 | } | ||
271 | if (NULL != s->intersection_op) | ||
272 | { | ||
273 | GNUNET_SETI_operation_cancel (s->intersection_op); | ||
274 | s->intersection_op = NULL; | ||
275 | } | ||
276 | if (NULL != s->intersection_set) | ||
277 | { | ||
278 | GNUNET_SETI_destroy (s->intersection_set); | ||
279 | s->intersection_set = NULL; | ||
280 | } | ||
281 | if (NULL != s->sorted_elements) | ||
282 | { | ||
283 | for (unsigned int i = 0; i < s->used_element_count; i++) | ||
284 | gcry_mpi_release (s->sorted_elements[i].value); | ||
285 | GNUNET_free (s->sorted_elements); | ||
286 | s->sorted_elements = NULL; | ||
287 | } | ||
288 | if (NULL != s->r) | ||
289 | { | ||
290 | GNUNET_free (s->r); | ||
291 | s->r = NULL; | ||
292 | } | ||
293 | if (NULL != s->r_prime) | ||
294 | { | ||
295 | GNUNET_free (s->r_prime); | ||
296 | s->r_prime = NULL; | ||
297 | } | ||
298 | if (NULL != s->product) | ||
299 | { | ||
300 | gcry_mpi_release (s->product); | ||
301 | s->product = NULL; | ||
302 | } | ||
303 | GNUNET_free (s); | ||
304 | } | ||
305 | |||
306 | |||
307 | /** | ||
308 | * Notify the client that the session has failed. A message gets sent | ||
309 | * to Alice's client if we encountered any error. | ||
310 | * | ||
311 | * @param session the associated client session to fail or succeed | ||
312 | */ | ||
313 | static void | ||
314 | prepare_client_end_notification (struct AliceServiceSession *session) | ||
315 | { | ||
316 | struct ClientResponseMessage *msg; | ||
317 | struct GNUNET_MQ_Envelope *e; | ||
318 | |||
319 | if (NULL == session->client_mq) | ||
320 | return; /* no client left to be notified */ | ||
321 | GNUNET_log ( | ||
322 | GNUNET_ERROR_TYPE_DEBUG, | ||
323 | "Sending session-end notification with status %d to client for session %s\n", | ||
324 | session->status, | ||
325 | GNUNET_h2s (&session->session_id)); | ||
326 | e = GNUNET_MQ_msg (msg, GNUNET_MESSAGE_TYPE_SCALARPRODUCT_RESULT); | ||
327 | msg->product_length = htonl (0); | ||
328 | msg->status = htonl (session->status); | ||
329 | GNUNET_MQ_send (session->client_mq, e); | ||
330 | } | ||
331 | |||
332 | |||
333 | /** | ||
334 | * Prepare the final (positive) response we will send to Alice's | ||
335 | * client. | ||
336 | * | ||
337 | * @param s the session associated with our client. | ||
338 | */ | ||
339 | static void | ||
340 | transmit_client_response (struct AliceServiceSession *s) | ||
341 | { | ||
342 | struct ClientResponseMessage *msg; | ||
343 | struct GNUNET_MQ_Envelope *e; | ||
344 | unsigned char *product_exported = NULL; | ||
345 | size_t product_length = 0; | ||
346 | int32_t range; | ||
347 | gcry_error_t rc; | ||
348 | int sign; | ||
349 | gcry_mpi_t value; | ||
350 | |||
351 | if (NULL == s->product) | ||
352 | { | ||
353 | GNUNET_break (0); | ||
354 | prepare_client_end_notification (s); | ||
355 | return; | ||
356 | } | ||
357 | value = gcry_mpi_new (0); | ||
358 | sign = gcry_mpi_cmp_ui (s->product, 0); | ||
359 | if (0 > sign) | ||
360 | { | ||
361 | range = -1; | ||
362 | gcry_mpi_sub (value, value, s->product); | ||
363 | } | ||
364 | else if (0 < sign) | ||
365 | { | ||
366 | range = 1; | ||
367 | gcry_mpi_add (value, value, s->product); | ||
368 | } | ||
369 | else | ||
370 | { | ||
371 | /* result is exactly zero */ | ||
372 | range = 0; | ||
373 | } | ||
374 | gcry_mpi_release (s->product); | ||
375 | s->product = NULL; | ||
376 | |||
377 | if ((0 != range) && (0 != (rc = gcry_mpi_aprint (GCRYMPI_FMT_STD, | ||
378 | &product_exported, | ||
379 | &product_length, | ||
380 | value)))) | ||
381 | { | ||
382 | LOG_GCRY (GNUNET_ERROR_TYPE_ERROR, "gcry_mpi_scan", rc); | ||
383 | prepare_client_end_notification (s); | ||
384 | return; | ||
385 | } | ||
386 | gcry_mpi_release (value); | ||
387 | e = GNUNET_MQ_msg_extra (msg, | ||
388 | product_length, | ||
389 | GNUNET_MESSAGE_TYPE_SCALARPRODUCT_RESULT); | ||
390 | msg->status = htonl (GNUNET_SCALARPRODUCT_STATUS_SUCCESS); | ||
391 | msg->range = htonl (range); | ||
392 | msg->product_length = htonl (product_length); | ||
393 | if (NULL != product_exported) | ||
394 | { | ||
395 | GNUNET_memcpy (&msg[1], product_exported, product_length); | ||
396 | GNUNET_free (product_exported); | ||
397 | } | ||
398 | GNUNET_MQ_send (s->client_mq, e); | ||
399 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
400 | "Sent result to client, session %s has ended!\n", | ||
401 | GNUNET_h2s (&s->session_id)); | ||
402 | } | ||
403 | |||
404 | |||
405 | /** | ||
406 | * Function called whenever a channel is destroyed. Should clean up | ||
407 | * any associated state. | ||
408 | * | ||
409 | * It must NOT call #GNUNET_CADET_channel_destroy() on the channel. | ||
410 | * | ||
411 | * @param cls our `struct AliceServiceSession` | ||
412 | * @param channel connection to the other end (henceforth invalid) | ||
413 | */ | ||
414 | static void | ||
415 | cb_channel_destruction (void *cls, const struct GNUNET_CADET_Channel *channel) | ||
416 | { | ||
417 | struct AliceServiceSession *s = cls; | ||
418 | |||
419 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
420 | "Peer disconnected, terminating session %s with peer %s\n", | ||
421 | GNUNET_h2s (&s->session_id), | ||
422 | GNUNET_i2s (&s->peer)); | ||
423 | if (GNUNET_SCALARPRODUCT_STATUS_ACTIVE == s->status) | ||
424 | { | ||
425 | /* We didn't get an answer yet, fail with error */ | ||
426 | s->status = GNUNET_SCALARPRODUCT_STATUS_FAILURE; | ||
427 | prepare_client_end_notification (s); | ||
428 | } | ||
429 | s->channel = NULL; | ||
430 | } | ||
431 | |||
432 | |||
433 | /** | ||
434 | * Computes the square sum over a vector of a given length. | ||
435 | * | ||
436 | * @param vector the vector to compute over | ||
437 | * @param length the length of the vector | ||
438 | * @return an MPI value containing the calculated sum, never NULL | ||
439 | */ | ||
440 | static gcry_mpi_t | ||
441 | compute_square_sum_mpi_elements (const struct MpiElement *vector, | ||
442 | uint32_t length) | ||
443 | { | ||
444 | gcry_mpi_t elem; | ||
445 | gcry_mpi_t sum; | ||
446 | uint32_t i; | ||
447 | |||
448 | GNUNET_assert (NULL != (sum = gcry_mpi_new (0))); | ||
449 | GNUNET_assert (NULL != (elem = gcry_mpi_new (0))); | ||
450 | for (i = 0; i < length; i++) | ||
451 | { | ||
452 | gcry_mpi_mul (elem, vector[i].value, vector[i].value); | ||
453 | gcry_mpi_add (sum, sum, elem); | ||
454 | } | ||
455 | gcry_mpi_release (elem); | ||
456 | return sum; | ||
457 | } | ||
458 | |||
459 | |||
460 | /** | ||
461 | * Computes the square sum over a vector of a given length. | ||
462 | * | ||
463 | * @param vector the vector to compute over | ||
464 | * @param length the length of the vector | ||
465 | * @return an MPI value containing the calculated sum, never NULL | ||
466 | */ | ||
467 | static gcry_mpi_t | ||
468 | compute_square_sum (const gcry_mpi_t *vector, uint32_t length) | ||
469 | { | ||
470 | gcry_mpi_t elem; | ||
471 | gcry_mpi_t sum; | ||
472 | uint32_t i; | ||
473 | |||
474 | GNUNET_assert (NULL != (sum = gcry_mpi_new (0))); | ||
475 | GNUNET_assert (NULL != (elem = gcry_mpi_new (0))); | ||
476 | for (i = 0; i < length; i++) | ||
477 | { | ||
478 | gcry_mpi_mul (elem, vector[i], vector[i]); | ||
479 | gcry_mpi_add (sum, sum, elem); | ||
480 | } | ||
481 | gcry_mpi_release (elem); | ||
482 | return sum; | ||
483 | } | ||
484 | |||
485 | |||
486 | /** | ||
487 | * Compute our scalar product, done by Alice | ||
488 | * | ||
489 | * @param session the session associated with this computation | ||
490 | * @return product as MPI, never NULL | ||
491 | */ | ||
492 | static gcry_mpi_t | ||
493 | compute_scalar_product (struct AliceServiceSession *session) | ||
494 | { | ||
495 | uint32_t count; | ||
496 | gcry_mpi_t t; | ||
497 | gcry_mpi_t u; | ||
498 | gcry_mpi_t u_prime; | ||
499 | gcry_mpi_t p; | ||
500 | gcry_mpi_t p_prime; | ||
501 | gcry_mpi_t tmp; | ||
502 | gcry_mpi_t r[session->used_element_count]; | ||
503 | gcry_mpi_t r_prime[session->used_element_count]; | ||
504 | gcry_mpi_t s; | ||
505 | gcry_mpi_t s_prime; | ||
506 | unsigned int i; | ||
507 | |||
508 | count = session->used_element_count; | ||
509 | // due to the introduced static offset S, we now also have to remove this | ||
510 | // from the E(a_pi)(+)E(-b_pi-r_pi) and E(a_qi)(+)E(-r_qi) twice each, | ||
511 | // the result is E((S + a_pi) + (S -b_pi-r_pi)) and E(S + a_qi + S - r_qi) | ||
512 | for (i = 0; i < count; i++) | ||
513 | { | ||
514 | r[i] = gcry_mpi_new (0); | ||
515 | GNUNET_CRYPTO_paillier_decrypt (&my_privkey, | ||
516 | &my_pubkey, | ||
517 | &session->r[i], | ||
518 | r[i]); | ||
519 | gcry_mpi_sub (r[i], r[i], my_offset); | ||
520 | gcry_mpi_sub (r[i], r[i], my_offset); | ||
521 | r_prime[i] = gcry_mpi_new (0); | ||
522 | GNUNET_CRYPTO_paillier_decrypt (&my_privkey, | ||
523 | &my_pubkey, | ||
524 | &session->r_prime[i], | ||
525 | r_prime[i]); | ||
526 | gcry_mpi_sub (r_prime[i], r_prime[i], my_offset); | ||
527 | gcry_mpi_sub (r_prime[i], r_prime[i], my_offset); | ||
528 | } | ||
529 | |||
530 | // calculate t = sum(ai) | ||
531 | t = compute_square_sum_mpi_elements (session->sorted_elements, count); | ||
532 | // calculate U | ||
533 | u = gcry_mpi_new (0); | ||
534 | tmp = compute_square_sum (r, count); | ||
535 | gcry_mpi_sub (u, u, tmp); | ||
536 | gcry_mpi_release (tmp); | ||
537 | |||
538 | // calculate U' | ||
539 | u_prime = gcry_mpi_new (0); | ||
540 | tmp = compute_square_sum (r_prime, count); | ||
541 | gcry_mpi_sub (u_prime, u_prime, tmp); | ||
542 | |||
543 | GNUNET_assert (p = gcry_mpi_new (0)); | ||
544 | GNUNET_assert (p_prime = gcry_mpi_new (0)); | ||
545 | GNUNET_assert (s = gcry_mpi_new (0)); | ||
546 | GNUNET_assert (s_prime = gcry_mpi_new (0)); | ||
547 | |||
548 | // compute P | ||
549 | GNUNET_CRYPTO_paillier_decrypt (&my_privkey, &my_pubkey, &session->s, s); | ||
550 | GNUNET_CRYPTO_paillier_decrypt (&my_privkey, | ||
551 | &my_pubkey, | ||
552 | &session->s_prime, | ||
553 | s_prime); | ||
554 | |||
555 | // compute P | ||
556 | gcry_mpi_add (p, s, t); | ||
557 | gcry_mpi_add (p, p, u); | ||
558 | |||
559 | // compute P' | ||
560 | gcry_mpi_add (p_prime, s_prime, t); | ||
561 | gcry_mpi_add (p_prime, p_prime, u_prime); | ||
562 | |||
563 | gcry_mpi_release (t); | ||
564 | gcry_mpi_release (u); | ||
565 | gcry_mpi_release (u_prime); | ||
566 | gcry_mpi_release (s); | ||
567 | gcry_mpi_release (s_prime); | ||
568 | |||
569 | // compute product | ||
570 | gcry_mpi_sub (p, p, p_prime); | ||
571 | gcry_mpi_release (p_prime); | ||
572 | tmp = gcry_mpi_set_ui (tmp, 2); | ||
573 | gcry_mpi_div (p, NULL, p, tmp, 0); | ||
574 | |||
575 | gcry_mpi_release (tmp); | ||
576 | for (i = 0; i < count; i++) | ||
577 | { | ||
578 | gcry_mpi_release (session->sorted_elements[i].value); | ||
579 | gcry_mpi_release (r[i]); | ||
580 | gcry_mpi_release (r_prime[i]); | ||
581 | } | ||
582 | GNUNET_free (session->sorted_elements); | ||
583 | session->sorted_elements = NULL; | ||
584 | GNUNET_free (session->r); | ||
585 | session->r = NULL; | ||
586 | GNUNET_free (session->r_prime); | ||
587 | session->r_prime = NULL; | ||
588 | |||
589 | return p; | ||
590 | } | ||
591 | |||
592 | |||
593 | /** | ||
594 | * Check a multipart chunk of a response we got from another service | ||
595 | * we wanted to calculate a scalarproduct with. | ||
596 | * | ||
597 | * @param cls the `struct AliceServiceSession` | ||
598 | * @param msg the actual message | ||
599 | * @return #GNUNET_OK to keep the connection open, | ||
600 | * #GNUNET_SYSERR to close it (signal serious error) | ||
601 | */ | ||
602 | static int | ||
603 | check_bobs_cryptodata_multipart ( | ||
604 | void *cls, | ||
605 | const struct BobCryptodataMultipartMessage *msg) | ||
606 | { | ||
607 | struct AliceServiceSession *s = cls; | ||
608 | uint32_t contained; | ||
609 | size_t msg_size; | ||
610 | size_t required_size; | ||
611 | |||
612 | msg_size = ntohs (msg->header.size); | ||
613 | contained = ntohl (msg->contained_element_count); | ||
614 | required_size = | ||
615 | sizeof(struct BobCryptodataMultipartMessage) | ||
616 | + 2 * contained * sizeof(struct GNUNET_CRYPTO_PaillierCiphertext); | ||
617 | if ((required_size != msg_size) || | ||
618 | (s->cadet_received_element_count + contained > s->used_element_count)) | ||
619 | { | ||
620 | GNUNET_break (0); | ||
621 | return GNUNET_SYSERR; | ||
622 | } | ||
623 | return GNUNET_OK; | ||
624 | } | ||
625 | |||
626 | |||
627 | /** | ||
628 | * Handle a multipart chunk of a response we got from another service | ||
629 | * we wanted to calculate a scalarproduct with. | ||
630 | * | ||
631 | * @param cls the `struct AliceServiceSession` | ||
632 | * @param msg the actual message | ||
633 | */ | ||
634 | static void | ||
635 | handle_bobs_cryptodata_multipart ( | ||
636 | void *cls, | ||
637 | const struct BobCryptodataMultipartMessage *msg) | ||
638 | { | ||
639 | struct AliceServiceSession *s = cls; | ||
640 | const struct GNUNET_CRYPTO_PaillierCiphertext *payload; | ||
641 | size_t i; | ||
642 | uint32_t contained; | ||
643 | |||
644 | contained = ntohl (msg->contained_element_count); | ||
645 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
646 | "Received %u additional crypto values from Bob\n", | ||
647 | (unsigned int) contained); | ||
648 | |||
649 | payload = (const struct GNUNET_CRYPTO_PaillierCiphertext *) &msg[1]; | ||
650 | /* Convert each k[][perm] to its MPI_value */ | ||
651 | for (i = 0; i < contained; i++) | ||
652 | { | ||
653 | GNUNET_memcpy (&s->r[s->cadet_received_element_count + i], | ||
654 | &payload[2 * i], | ||
655 | sizeof(struct GNUNET_CRYPTO_PaillierCiphertext)); | ||
656 | GNUNET_memcpy (&s->r_prime[s->cadet_received_element_count + i], | ||
657 | &payload[2 * i], | ||
658 | sizeof(struct GNUNET_CRYPTO_PaillierCiphertext)); | ||
659 | } | ||
660 | s->cadet_received_element_count += contained; | ||
661 | GNUNET_CADET_receive_done (s->channel); | ||
662 | if (s->cadet_received_element_count != s->used_element_count) | ||
663 | return; /* more to come */ | ||
664 | |||
665 | s->product = compute_scalar_product (s); | ||
666 | transmit_client_response (s); | ||
667 | } | ||
668 | |||
669 | |||
670 | /** | ||
671 | * Check a response we got from another service we wanted to | ||
672 | * calculate a scalarproduct with. | ||
673 | * | ||
674 | * @param cls our `struct AliceServiceSession` | ||
675 | * @param message the actual message | ||
676 | * @return #GNUNET_OK to keep the connection open, | ||
677 | * #GNUNET_SYSERR to close it (we are done) | ||
678 | */ | ||
679 | static int | ||
680 | check_bobs_cryptodata_message (void *cls, | ||
681 | const struct BobCryptodataMessage *msg) | ||
682 | { | ||
683 | struct AliceServiceSession *s = cls; | ||
684 | uint32_t contained; | ||
685 | uint16_t msg_size; | ||
686 | size_t required_size; | ||
687 | |||
688 | msg_size = ntohs (msg->header.size); | ||
689 | contained = ntohl (msg->contained_element_count); | ||
690 | required_size = | ||
691 | sizeof(struct BobCryptodataMessage) | ||
692 | + 2 * contained * sizeof(struct GNUNET_CRYPTO_PaillierCiphertext) | ||
693 | + 2 * sizeof(struct GNUNET_CRYPTO_PaillierCiphertext); | ||
694 | if ((msg_size != required_size) || (contained > UINT16_MAX) || | ||
695 | (s->used_element_count < contained)) | ||
696 | { | ||
697 | GNUNET_break_op (0); | ||
698 | return GNUNET_SYSERR; | ||
699 | } | ||
700 | if (NULL == s->sorted_elements) | ||
701 | { | ||
702 | /* we're not ready yet, how can Bob be? */ | ||
703 | GNUNET_break_op (0); | ||
704 | return GNUNET_SYSERR; | ||
705 | } | ||
706 | if (s->total != s->client_received_element_count) | ||
707 | { | ||
708 | /* we're not ready yet, how can Bob be? */ | ||
709 | GNUNET_break_op (0); | ||
710 | return GNUNET_SYSERR; | ||
711 | } | ||
712 | return GNUNET_OK; | ||
713 | } | ||
714 | |||
715 | |||
716 | /** | ||
717 | * Handle a response we got from another service we wanted to | ||
718 | * calculate a scalarproduct with. | ||
719 | * | ||
720 | * @param cls our `struct AliceServiceSession` | ||
721 | * @param msg the actual message | ||
722 | */ | ||
723 | static void | ||
724 | handle_bobs_cryptodata_message (void *cls, | ||
725 | const struct BobCryptodataMessage *msg) | ||
726 | { | ||
727 | struct AliceServiceSession *s = cls; | ||
728 | const struct GNUNET_CRYPTO_PaillierCiphertext *payload; | ||
729 | uint32_t i; | ||
730 | uint32_t contained; | ||
731 | |||
732 | contained = ntohl (msg->contained_element_count); | ||
733 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
734 | "Received %u crypto values from Bob\n", | ||
735 | (unsigned int) contained); | ||
736 | payload = (const struct GNUNET_CRYPTO_PaillierCiphertext *) &msg[1]; | ||
737 | GNUNET_memcpy (&s->s, | ||
738 | &payload[0], | ||
739 | sizeof(struct GNUNET_CRYPTO_PaillierCiphertext)); | ||
740 | GNUNET_memcpy (&s->s_prime, | ||
741 | &payload[1], | ||
742 | sizeof(struct GNUNET_CRYPTO_PaillierCiphertext)); | ||
743 | payload = &payload[2]; | ||
744 | |||
745 | s->r = GNUNET_new_array (s->used_element_count, | ||
746 | struct GNUNET_CRYPTO_PaillierCiphertext); | ||
747 | s->r_prime = GNUNET_new_array (s->used_element_count, | ||
748 | struct GNUNET_CRYPTO_PaillierCiphertext); | ||
749 | for (i = 0; i < contained; i++) | ||
750 | { | ||
751 | GNUNET_memcpy (&s->r[i], | ||
752 | &payload[2 * i], | ||
753 | sizeof(struct GNUNET_CRYPTO_PaillierCiphertext)); | ||
754 | GNUNET_memcpy (&s->r_prime[i], | ||
755 | &payload[2 * i + 1], | ||
756 | sizeof(struct GNUNET_CRYPTO_PaillierCiphertext)); | ||
757 | } | ||
758 | s->cadet_received_element_count = contained; | ||
759 | GNUNET_CADET_receive_done (s->channel); | ||
760 | |||
761 | if (s->cadet_received_element_count != s->used_element_count) | ||
762 | { | ||
763 | /* More to come */ | ||
764 | return; | ||
765 | } | ||
766 | s->product = compute_scalar_product (s); | ||
767 | transmit_client_response (s); | ||
768 | } | ||
769 | |||
770 | |||
771 | /** | ||
772 | * Iterator to copy over messages from the hash map | ||
773 | * into an array for sorting. | ||
774 | * | ||
775 | * @param cls the `struct AliceServiceSession *` | ||
776 | * @param key the key (unused) | ||
777 | * @param value the `struct GNUNET_SCALARPRODUCT_Element *` | ||
778 | */ | ||
779 | static int | ||
780 | copy_element_cb (void *cls, const struct GNUNET_HashCode *key, void *value) | ||
781 | { | ||
782 | struct AliceServiceSession *s = cls; | ||
783 | struct GNUNET_SCALARPRODUCT_Element *e = value; | ||
784 | gcry_mpi_t mval; | ||
785 | int64_t val; | ||
786 | |||
787 | mval = gcry_mpi_new (0); | ||
788 | val = (int64_t) GNUNET_ntohll (e->value); | ||
789 | if (0 > val) | ||
790 | gcry_mpi_sub_ui (mval, mval, -val); | ||
791 | else | ||
792 | gcry_mpi_add_ui (mval, mval, val); | ||
793 | s->sorted_elements[s->used_element_count].value = mval; | ||
794 | s->sorted_elements[s->used_element_count].key = &e->key; | ||
795 | s->used_element_count++; | ||
796 | return GNUNET_OK; | ||
797 | } | ||
798 | |||
799 | |||
800 | /** | ||
801 | * Compare two `struct MpiValue`s by key for sorting. | ||
802 | * | ||
803 | * @param a pointer to first `struct MpiValue *` | ||
804 | * @param b pointer to first `struct MpiValue *` | ||
805 | * @return -1 for a < b, 0 for a=b, 1 for a > b. | ||
806 | */ | ||
807 | static int | ||
808 | element_cmp (const void *a, const void *b) | ||
809 | { | ||
810 | const struct MpiElement *ma = a; | ||
811 | const struct MpiElement *mb = b; | ||
812 | |||
813 | return GNUNET_CRYPTO_hash_cmp (ma->key, mb->key); | ||
814 | } | ||
815 | |||
816 | |||
817 | /** | ||
818 | * Maximum number of elements we can put into a single cryptodata | ||
819 | * message | ||
820 | */ | ||
821 | #define ELEMENT_CAPACITY \ | ||
822 | ((GNUNET_CONSTANTS_MAX_CADET_MESSAGE_SIZE - 1 \ | ||
823 | - sizeof(struct AliceCryptodataMessage)) \ | ||
824 | / sizeof(struct GNUNET_CRYPTO_PaillierCiphertext)) | ||
825 | |||
826 | |||
827 | /** | ||
828 | * Send the cryptographic data from Alice to Bob. | ||
829 | * Does nothing if we already transferred all elements. | ||
830 | * | ||
831 | * @param s the associated service session | ||
832 | */ | ||
833 | static void | ||
834 | send_alices_cryptodata_message (struct AliceServiceSession *s) | ||
835 | { | ||
836 | struct AliceCryptodataMessage *msg; | ||
837 | struct GNUNET_MQ_Envelope *e; | ||
838 | struct GNUNET_CRYPTO_PaillierCiphertext *payload; | ||
839 | unsigned int i; | ||
840 | uint32_t todo_count; | ||
841 | gcry_mpi_t a; | ||
842 | uint32_t off; | ||
843 | |||
844 | s->sorted_elements = GNUNET_malloc ( | ||
845 | GNUNET_CONTAINER_multihashmap_size (s->intersected_elements) | ||
846 | * sizeof(struct MpiElement)); | ||
847 | s->used_element_count = 0; | ||
848 | GNUNET_CONTAINER_multihashmap_iterate (s->intersected_elements, | ||
849 | ©_element_cb, | ||
850 | s); | ||
851 | LOG (GNUNET_ERROR_TYPE_DEBUG, | ||
852 | "Finished intersection, %d items remain\n", | ||
853 | s->used_element_count); | ||
854 | qsort (s->sorted_elements, | ||
855 | s->used_element_count, | ||
856 | sizeof(struct MpiElement), | ||
857 | &element_cmp); | ||
858 | off = 0; | ||
859 | while (off < s->used_element_count) | ||
860 | { | ||
861 | todo_count = s->used_element_count - off; | ||
862 | if (todo_count > ELEMENT_CAPACITY) | ||
863 | todo_count = ELEMENT_CAPACITY; | ||
864 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
865 | "Sending %u/%u crypto values to Bob\n", | ||
866 | (unsigned int) todo_count, | ||
867 | (unsigned int) s->used_element_count); | ||
868 | |||
869 | e = | ||
870 | GNUNET_MQ_msg_extra (msg, | ||
871 | todo_count | ||
872 | * sizeof(struct GNUNET_CRYPTO_PaillierCiphertext), | ||
873 | GNUNET_MESSAGE_TYPE_SCALARPRODUCT_ALICE_CRYPTODATA); | ||
874 | msg->contained_element_count = htonl (todo_count); | ||
875 | payload = (struct GNUNET_CRYPTO_PaillierCiphertext *) &msg[1]; | ||
876 | a = gcry_mpi_new (0); | ||
877 | for (i = off; i < off + todo_count; i++) | ||
878 | { | ||
879 | gcry_mpi_add (a, s->sorted_elements[i].value, my_offset); | ||
880 | GNUNET_assert ( | ||
881 | 3 == | ||
882 | GNUNET_CRYPTO_paillier_encrypt (&my_pubkey, a, 3, &payload[i - off])); | ||
883 | } | ||
884 | gcry_mpi_release (a); | ||
885 | off += todo_count; | ||
886 | GNUNET_MQ_send (s->cadet_mq, e); | ||
887 | } | ||
888 | } | ||
889 | |||
890 | |||
891 | /** | ||
892 | * Callback for set operation results. Called for each element | ||
893 | * that should be removed from the result set, and then once | ||
894 | * to indicate that the set intersection operation is done. | ||
895 | * | ||
896 | * @param cls closure with the `struct AliceServiceSession` | ||
897 | * @param element a result element, only valid if status is #GNUNET_SETI_STATUS_OK | ||
898 | * @param current_size current set size | ||
899 | * @param status what has happened with the set intersection? | ||
900 | */ | ||
901 | static void | ||
902 | cb_intersection_element_removed (void *cls, | ||
903 | const struct GNUNET_SETI_Element *element, | ||
904 | uint64_t current_size, | ||
905 | enum GNUNET_SETI_Status status) | ||
906 | { | ||
907 | struct AliceServiceSession *s = cls; | ||
908 | struct GNUNET_SCALARPRODUCT_Element *se; | ||
909 | |||
910 | switch (status) | ||
911 | { | ||
912 | case GNUNET_SETI_STATUS_DEL_LOCAL: | ||
913 | /* this element has been removed from the set */ | ||
914 | se = GNUNET_CONTAINER_multihashmap_get (s->intersected_elements, | ||
915 | element->data); | ||
916 | GNUNET_assert (NULL != se); | ||
917 | LOG (GNUNET_ERROR_TYPE_DEBUG, | ||
918 | "Intersection removed element with key %s and value %lld\n", | ||
919 | GNUNET_h2s (&se->key), | ||
920 | (long long) GNUNET_ntohll (se->value)); | ||
921 | GNUNET_assert ( | ||
922 | GNUNET_YES == | ||
923 | GNUNET_CONTAINER_multihashmap_remove (s->intersected_elements, | ||
924 | element->data, | ||
925 | se)); | ||
926 | GNUNET_free (se); | ||
927 | return; | ||
928 | |||
929 | case GNUNET_SETI_STATUS_DONE: | ||
930 | s->intersection_op = NULL; | ||
931 | if (NULL != s->intersection_set) | ||
932 | { | ||
933 | GNUNET_SETI_destroy (s->intersection_set); | ||
934 | s->intersection_set = NULL; | ||
935 | } | ||
936 | send_alices_cryptodata_message (s); | ||
937 | return; | ||
938 | case GNUNET_SETI_STATUS_FAILURE: | ||
939 | /* unhandled status code */ | ||
940 | LOG (GNUNET_ERROR_TYPE_DEBUG, "Set intersection failed!\n"); | ||
941 | if (NULL != s->intersection_listen) | ||
942 | { | ||
943 | GNUNET_SETI_listen_cancel (s->intersection_listen); | ||
944 | s->intersection_listen = NULL; | ||
945 | } | ||
946 | s->intersection_op = NULL; | ||
947 | if (NULL != s->intersection_set) | ||
948 | { | ||
949 | GNUNET_SETI_destroy (s->intersection_set); | ||
950 | s->intersection_set = NULL; | ||
951 | } | ||
952 | s->status = GNUNET_SCALARPRODUCT_STATUS_FAILURE; | ||
953 | prepare_client_end_notification (s); | ||
954 | return; | ||
955 | |||
956 | default: | ||
957 | GNUNET_break (0); | ||
958 | return; | ||
959 | } | ||
960 | } | ||
961 | |||
962 | |||
963 | /** | ||
964 | * Called when another peer wants to do a set operation with the | ||
965 | * local peer. If a listen error occurs, the @a request is NULL. | ||
966 | * | ||
967 | * @param cls closure with the `struct AliceServiceSession *` | ||
968 | * @param other_peer the other peer | ||
969 | * @param context_msg message with application specific information from | ||
970 | * the other peer | ||
971 | * @param request request from the other peer (never NULL), use GNUNET_SETI_accept() | ||
972 | * to accept it, otherwise the request will be refused | ||
973 | * Note that we can't just return value from the listen callback, | ||
974 | * as it is also necessary to specify the set we want to do the | ||
975 | * operation with, which sometimes can be derived from the context | ||
976 | * message. It's necessary to specify the timeout. | ||
977 | */ | ||
978 | static void | ||
979 | cb_intersection_request_alice (void *cls, | ||
980 | const struct GNUNET_PeerIdentity *other_peer, | ||
981 | const struct GNUNET_MessageHeader *context_msg, | ||
982 | struct GNUNET_SETI_Request *request) | ||
983 | { | ||
984 | struct AliceServiceSession *s = cls; | ||
985 | |||
986 | if (0 != GNUNET_memcmp (other_peer, &s->peer)) | ||
987 | { | ||
988 | GNUNET_break_op (0); | ||
989 | return; | ||
990 | } | ||
991 | s->intersection_op = GNUNET_SETI_accept (request, | ||
992 | (struct | ||
993 | GNUNET_SETI_Option[]){ { 0 } }, | ||
994 | &cb_intersection_element_removed, | ||
995 | s); | ||
996 | if (NULL == s->intersection_op) | ||
997 | { | ||
998 | GNUNET_break (0); | ||
999 | s->status = GNUNET_SCALARPRODUCT_STATUS_FAILURE; | ||
1000 | prepare_client_end_notification (s); | ||
1001 | return; | ||
1002 | } | ||
1003 | if (GNUNET_OK != GNUNET_SETI_commit (s->intersection_op, s->intersection_set)) | ||
1004 | { | ||
1005 | GNUNET_break (0); | ||
1006 | s->status = GNUNET_SCALARPRODUCT_STATUS_FAILURE; | ||
1007 | prepare_client_end_notification (s); | ||
1008 | return; | ||
1009 | } | ||
1010 | } | ||
1011 | |||
1012 | |||
1013 | /** | ||
1014 | * Our client has finished sending us its multipart message. | ||
1015 | * | ||
1016 | * @param session the service session context | ||
1017 | */ | ||
1018 | static void | ||
1019 | client_request_complete_alice (struct AliceServiceSession *s) | ||
1020 | { | ||
1021 | struct GNUNET_MQ_MessageHandler cadet_handlers[] = | ||
1022 | { GNUNET_MQ_hd_var_size (bobs_cryptodata_message, | ||
1023 | GNUNET_MESSAGE_TYPE_SCALARPRODUCT_BOB_CRYPTODATA, | ||
1024 | struct BobCryptodataMessage, | ||
1025 | s), | ||
1026 | GNUNET_MQ_hd_var_size ( | ||
1027 | bobs_cryptodata_multipart, | ||
1028 | GNUNET_MESSAGE_TYPE_SCALARPRODUCT_BOB_CRYPTODATA_MULTIPART, | ||
1029 | struct BobCryptodataMultipartMessage, | ||
1030 | s), | ||
1031 | GNUNET_MQ_handler_end () }; | ||
1032 | struct ServiceRequestMessage *msg; | ||
1033 | struct GNUNET_MQ_Envelope *e; | ||
1034 | |||
1035 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
1036 | "Creating new channel for session with key %s.\n", | ||
1037 | GNUNET_h2s (&s->session_id)); | ||
1038 | s->channel = GNUNET_CADET_channel_create (my_cadet, | ||
1039 | s, | ||
1040 | &s->peer, | ||
1041 | &s->session_id, | ||
1042 | NULL, | ||
1043 | &cb_channel_destruction, | ||
1044 | cadet_handlers); | ||
1045 | if (NULL == s->channel) | ||
1046 | { | ||
1047 | s->status = GNUNET_SCALARPRODUCT_STATUS_FAILURE; | ||
1048 | prepare_client_end_notification (s); | ||
1049 | return; | ||
1050 | } | ||
1051 | s->cadet_mq = GNUNET_CADET_get_mq (s->channel); | ||
1052 | s->intersection_listen = GNUNET_SETI_listen (cfg, | ||
1053 | &s->session_id, | ||
1054 | &cb_intersection_request_alice, | ||
1055 | s); | ||
1056 | if (NULL == s->intersection_listen) | ||
1057 | { | ||
1058 | s->status = GNUNET_SCALARPRODUCT_STATUS_FAILURE; | ||
1059 | GNUNET_CADET_channel_destroy (s->channel); | ||
1060 | s->channel = NULL; | ||
1061 | prepare_client_end_notification (s); | ||
1062 | return; | ||
1063 | } | ||
1064 | |||
1065 | e = GNUNET_MQ_msg (msg, | ||
1066 | GNUNET_MESSAGE_TYPE_SCALARPRODUCT_SESSION_INITIALIZATION); | ||
1067 | msg->session_id = s->session_id; | ||
1068 | msg->public_key = my_pubkey; | ||
1069 | GNUNET_MQ_send (s->cadet_mq, e); | ||
1070 | } | ||
1071 | |||
1072 | |||
1073 | /** | ||
1074 | * We're receiving additional set data. Check if | ||
1075 | * @a msg is well-formed. | ||
1076 | * | ||
1077 | * @param cls client identification of the client | ||
1078 | * @param msg the actual message | ||
1079 | * @return #GNUNET_OK if @a msg is well-formed | ||
1080 | */ | ||
1081 | static int | ||
1082 | check_alice_client_message_multipart ( | ||
1083 | void *cls, | ||
1084 | const struct ComputationBobCryptodataMultipartMessage *msg) | ||
1085 | { | ||
1086 | struct AliceServiceSession *s = cls; | ||
1087 | uint32_t contained_count; | ||
1088 | uint16_t msize; | ||
1089 | |||
1090 | msize = ntohs (msg->header.size); | ||
1091 | contained_count = ntohl (msg->element_count_contained); | ||
1092 | if ((msize != | ||
1093 | (sizeof(struct ComputationBobCryptodataMultipartMessage) | ||
1094 | + contained_count * sizeof(struct GNUNET_SCALARPRODUCT_Element))) || | ||
1095 | (0 == contained_count) || | ||
1096 | (s->total == s->client_received_element_count) || | ||
1097 | (s->total < s->client_received_element_count + contained_count)) | ||
1098 | { | ||
1099 | GNUNET_break_op (0); | ||
1100 | return GNUNET_SYSERR; | ||
1101 | } | ||
1102 | return GNUNET_OK; | ||
1103 | } | ||
1104 | |||
1105 | |||
1106 | /** | ||
1107 | * We're receiving additional set data. Add it to our | ||
1108 | * set and if we are done, initiate the transaction. | ||
1109 | * | ||
1110 | * @param cls client identification of the client | ||
1111 | * @param msg the actual message | ||
1112 | */ | ||
1113 | static void | ||
1114 | handle_alice_client_message_multipart ( | ||
1115 | void *cls, | ||
1116 | const struct ComputationBobCryptodataMultipartMessage *msg) | ||
1117 | { | ||
1118 | struct AliceServiceSession *s = cls; | ||
1119 | uint32_t contained_count; | ||
1120 | const struct GNUNET_SCALARPRODUCT_Element *elements; | ||
1121 | struct GNUNET_SETI_Element set_elem; | ||
1122 | struct GNUNET_SCALARPRODUCT_Element *elem; | ||
1123 | |||
1124 | contained_count = ntohl (msg->element_count_contained); | ||
1125 | s->client_received_element_count += contained_count; | ||
1126 | elements = (const struct GNUNET_SCALARPRODUCT_Element *) &msg[1]; | ||
1127 | for (uint32_t i = 0; i < contained_count; i++) | ||
1128 | { | ||
1129 | elem = GNUNET_new (struct GNUNET_SCALARPRODUCT_Element); | ||
1130 | GNUNET_memcpy (elem, | ||
1131 | &elements[i], | ||
1132 | sizeof(struct GNUNET_SCALARPRODUCT_Element)); | ||
1133 | if (GNUNET_SYSERR == GNUNET_CONTAINER_multihashmap_put ( | ||
1134 | s->intersected_elements, | ||
1135 | &elem->key, | ||
1136 | elem, | ||
1137 | GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY)) | ||
1138 | { | ||
1139 | GNUNET_break (0); | ||
1140 | GNUNET_free (elem); | ||
1141 | continue; | ||
1142 | } | ||
1143 | set_elem.data = &elem->key; | ||
1144 | set_elem.size = sizeof(elem->key); | ||
1145 | set_elem.element_type = 0; | ||
1146 | GNUNET_SETI_add_element (s->intersection_set, &set_elem, NULL, NULL); | ||
1147 | s->used_element_count++; | ||
1148 | } | ||
1149 | GNUNET_SERVICE_client_continue (s->client); | ||
1150 | if (s->total != s->client_received_element_count) | ||
1151 | { | ||
1152 | /* more to come */ | ||
1153 | return; | ||
1154 | } | ||
1155 | client_request_complete_alice (s); | ||
1156 | } | ||
1157 | |||
1158 | |||
1159 | /** | ||
1160 | * Handler for Alice's client request message. | ||
1161 | * Check that @a msg is well-formed. | ||
1162 | * | ||
1163 | * @param cls identification of the client | ||
1164 | * @param msg the actual message | ||
1165 | * @return #GNUNET_OK if @a msg is well-formed | ||
1166 | */ | ||
1167 | static int | ||
1168 | check_alice_client_message (void *cls, | ||
1169 | const struct AliceComputationMessage *msg) | ||
1170 | { | ||
1171 | struct AliceServiceSession *s = cls; | ||
1172 | uint16_t msize; | ||
1173 | uint32_t total_count; | ||
1174 | uint32_t contained_count; | ||
1175 | |||
1176 | if (NULL != s->intersected_elements) | ||
1177 | { | ||
1178 | /* only one concurrent session per client connection allowed, | ||
1179 | simplifies logic a lot... */ | ||
1180 | GNUNET_break (0); | ||
1181 | return GNUNET_SYSERR; | ||
1182 | } | ||
1183 | msize = ntohs (msg->header.size); | ||
1184 | total_count = ntohl (msg->element_count_total); | ||
1185 | contained_count = ntohl (msg->element_count_contained); | ||
1186 | if ((0 == total_count) || (0 == contained_count) || | ||
1187 | (msize != | ||
1188 | (sizeof(struct AliceComputationMessage) | ||
1189 | + contained_count * sizeof(struct GNUNET_SCALARPRODUCT_Element)))) | ||
1190 | { | ||
1191 | GNUNET_break_op (0); | ||
1192 | return GNUNET_SYSERR; | ||
1193 | } | ||
1194 | return GNUNET_OK; | ||
1195 | } | ||
1196 | |||
1197 | |||
1198 | /** | ||
1199 | * Handler for Alice's client request message. | ||
1200 | * We are doing request-initiation to compute a scalar product with a peer. | ||
1201 | * | ||
1202 | * @param cls identification of the client | ||
1203 | * @param msg the actual message | ||
1204 | */ | ||
1205 | static void | ||
1206 | handle_alice_client_message (void *cls, | ||
1207 | const struct AliceComputationMessage *msg) | ||
1208 | { | ||
1209 | struct AliceServiceSession *s = cls; | ||
1210 | uint32_t contained_count; | ||
1211 | uint32_t total_count; | ||
1212 | const struct GNUNET_SCALARPRODUCT_Element *elements; | ||
1213 | struct GNUNET_SETI_Element set_elem; | ||
1214 | struct GNUNET_SCALARPRODUCT_Element *elem; | ||
1215 | |||
1216 | total_count = ntohl (msg->element_count_total); | ||
1217 | contained_count = ntohl (msg->element_count_contained); | ||
1218 | s->peer = msg->peer; | ||
1219 | s->status = GNUNET_SCALARPRODUCT_STATUS_ACTIVE; | ||
1220 | s->total = total_count; | ||
1221 | s->client_received_element_count = contained_count; | ||
1222 | s->session_id = msg->session_key; | ||
1223 | elements = (const struct GNUNET_SCALARPRODUCT_Element *) &msg[1]; | ||
1224 | s->intersected_elements = | ||
1225 | GNUNET_CONTAINER_multihashmap_create (s->total, GNUNET_YES); | ||
1226 | s->intersection_set = GNUNET_SETI_create (cfg); | ||
1227 | |||
1228 | for (uint32_t i = 0; i < contained_count; i++) | ||
1229 | { | ||
1230 | if (0 == GNUNET_ntohll (elements[i].value)) | ||
1231 | continue; | ||
1232 | elem = GNUNET_new (struct GNUNET_SCALARPRODUCT_Element); | ||
1233 | GNUNET_memcpy (elem, | ||
1234 | &elements[i], | ||
1235 | sizeof(struct GNUNET_SCALARPRODUCT_Element)); | ||
1236 | if (GNUNET_SYSERR == GNUNET_CONTAINER_multihashmap_put ( | ||
1237 | s->intersected_elements, | ||
1238 | &elem->key, | ||
1239 | elem, | ||
1240 | GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY)) | ||
1241 | { | ||
1242 | /* element with same key encountered twice! */ | ||
1243 | GNUNET_break (0); | ||
1244 | GNUNET_free (elem); | ||
1245 | continue; | ||
1246 | } | ||
1247 | set_elem.data = &elem->key; | ||
1248 | set_elem.size = sizeof(elem->key); | ||
1249 | set_elem.element_type = 0; | ||
1250 | GNUNET_SETI_add_element (s->intersection_set, | ||
1251 | &set_elem, | ||
1252 | NULL, | ||
1253 | NULL); | ||
1254 | s->used_element_count++; | ||
1255 | } | ||
1256 | GNUNET_SERVICE_client_continue (s->client); | ||
1257 | if (s->total != s->client_received_element_count) | ||
1258 | { | ||
1259 | /* wait for multipart msg */ | ||
1260 | return; | ||
1261 | } | ||
1262 | client_request_complete_alice (s); | ||
1263 | } | ||
1264 | |||
1265 | |||
1266 | /** | ||
1267 | * Task run during shutdown. | ||
1268 | * | ||
1269 | * @param cls unused | ||
1270 | */ | ||
1271 | static void | ||
1272 | shutdown_task (void *cls) | ||
1273 | { | ||
1274 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Shutting down, initiating cleanup.\n"); | ||
1275 | // FIXME: we have to cut our connections to CADET first! | ||
1276 | if (NULL != my_cadet) | ||
1277 | { | ||
1278 | GNUNET_CADET_disconnect (my_cadet); | ||
1279 | my_cadet = NULL; | ||
1280 | } | ||
1281 | } | ||
1282 | |||
1283 | |||
1284 | /** | ||
1285 | * A client connected. | ||
1286 | * | ||
1287 | * Setup the associated data structure. | ||
1288 | * | ||
1289 | * @param cls closure, NULL | ||
1290 | * @param client identification of the client | ||
1291 | * @param mq message queue to communicate with @a client | ||
1292 | * @return our `struct AliceServiceSession` | ||
1293 | */ | ||
1294 | static void * | ||
1295 | client_connect_cb (void *cls, | ||
1296 | struct GNUNET_SERVICE_Client *client, | ||
1297 | struct GNUNET_MQ_Handle *mq) | ||
1298 | { | ||
1299 | struct AliceServiceSession *s; | ||
1300 | |||
1301 | s = GNUNET_new (struct AliceServiceSession); | ||
1302 | s->client = client; | ||
1303 | s->client_mq = mq; | ||
1304 | return s; | ||
1305 | } | ||
1306 | |||
1307 | |||
1308 | /** | ||
1309 | * A client disconnected. | ||
1310 | * | ||
1311 | * Remove the associated session(s), release data structures | ||
1312 | * and cancel pending outgoing transmissions to the client. | ||
1313 | * | ||
1314 | * @param cls closure, NULL | ||
1315 | * @param client identification of the client | ||
1316 | * @param app_cls our `struct AliceServiceSession` | ||
1317 | */ | ||
1318 | static void | ||
1319 | client_disconnect_cb (void *cls, | ||
1320 | struct GNUNET_SERVICE_Client *client, | ||
1321 | void *app_cls) | ||
1322 | { | ||
1323 | struct AliceServiceSession *s = app_cls; | ||
1324 | |||
1325 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
1326 | "Client %p disconnected from us.\n", | ||
1327 | client); | ||
1328 | s->client = NULL; | ||
1329 | s->client_mq = NULL; | ||
1330 | destroy_service_session (s); | ||
1331 | } | ||
1332 | |||
1333 | |||
1334 | /** | ||
1335 | * Initialization of the program and message handlers | ||
1336 | * | ||
1337 | * @param cls closure | ||
1338 | * @param c configuration to use | ||
1339 | * @param service the initialized service | ||
1340 | */ | ||
1341 | static void | ||
1342 | run (void *cls, | ||
1343 | const struct GNUNET_CONFIGURATION_Handle *c, | ||
1344 | struct GNUNET_SERVICE_Handle *service) | ||
1345 | { | ||
1346 | cfg = c; | ||
1347 | /* | ||
1348 | offset has to be sufficiently small to allow computation of: | ||
1349 | m1+m2 mod n == (S + a) + (S + b) mod n, | ||
1350 | if we have more complex operations, this factor needs to be lowered */ | ||
1351 | my_offset = gcry_mpi_new (GNUNET_CRYPTO_PAILLIER_BITS / 3); | ||
1352 | gcry_mpi_set_bit (my_offset, GNUNET_CRYPTO_PAILLIER_BITS / 3); | ||
1353 | GNUNET_CRYPTO_paillier_create (&my_pubkey, &my_privkey); | ||
1354 | my_cadet = GNUNET_CADET_connect (cfg); | ||
1355 | GNUNET_SCHEDULER_add_shutdown (&shutdown_task, NULL); | ||
1356 | if (NULL == my_cadet) | ||
1357 | { | ||
1358 | GNUNET_log (GNUNET_ERROR_TYPE_ERROR, _ ("Connect to CADET failed\n")); | ||
1359 | GNUNET_SCHEDULER_shutdown (); | ||
1360 | return; | ||
1361 | } | ||
1362 | } | ||
1363 | |||
1364 | |||
1365 | /** | ||
1366 | * Define "main" method using service macro. | ||
1367 | */ | ||
1368 | GNUNET_SERVICE_MAIN ( | ||
1369 | "scalarproduct-alice", | ||
1370 | GNUNET_SERVICE_OPTION_NONE, | ||
1371 | &run, | ||
1372 | &client_connect_cb, | ||
1373 | &client_disconnect_cb, | ||
1374 | NULL, | ||
1375 | GNUNET_MQ_hd_var_size (alice_client_message, | ||
1376 | GNUNET_MESSAGE_TYPE_SCALARPRODUCT_CLIENT_TO_ALICE, | ||
1377 | struct AliceComputationMessage, | ||
1378 | NULL), | ||
1379 | GNUNET_MQ_hd_var_size ( | ||
1380 | alice_client_message_multipart, | ||
1381 | GNUNET_MESSAGE_TYPE_SCALARPRODUCT_CLIENT_MULTIPART_ALICE, | ||
1382 | struct ComputationBobCryptodataMultipartMessage, | ||
1383 | NULL), | ||
1384 | GNUNET_MQ_handler_end ()); | ||
1385 | |||
1386 | |||
1387 | /* end of gnunet-service-scalarproduct_alice.c */ | ||
diff --git a/src/scalarproduct/gnunet-service-scalarproduct_bob.c b/src/scalarproduct/gnunet-service-scalarproduct_bob.c deleted file mode 100644 index b0299779d..000000000 --- a/src/scalarproduct/gnunet-service-scalarproduct_bob.c +++ /dev/null | |||
@@ -1,1383 +0,0 @@ | |||
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 | |||
39 | #define LOG(kind, ...) GNUNET_log_from (kind, "scalarproduct-bob", __VA_ARGS__) | ||
40 | |||
41 | |||
42 | /** | ||
43 | * An encrypted element key-value pair. | ||
44 | */ | ||
45 | struct MpiElement | ||
46 | { | ||
47 | /** | ||
48 | * Key used to identify matching pairs of values to multiply. | ||
49 | * Points into an existing data structure, to avoid copying | ||
50 | * and doubling memory use. | ||
51 | */ | ||
52 | const struct GNUNET_HashCode *key; | ||
53 | |||
54 | /** | ||
55 | * Value represented (a). | ||
56 | */ | ||
57 | gcry_mpi_t value; | ||
58 | }; | ||
59 | |||
60 | |||
61 | /** | ||
62 | * A scalarproduct session which tracks an offer for a | ||
63 | * multiplication service by a local client. | ||
64 | */ | ||
65 | struct BobServiceSession | ||
66 | { | ||
67 | /** | ||
68 | * (hopefully) unique transaction ID | ||
69 | */ | ||
70 | struct GNUNET_HashCode session_id; | ||
71 | |||
72 | /** | ||
73 | * The client this request is related to. | ||
74 | */ | ||
75 | struct GNUNET_SERVICE_Client *client; | ||
76 | |||
77 | /** | ||
78 | * Client message queue. | ||
79 | */ | ||
80 | struct GNUNET_MQ_Handle *client_mq; | ||
81 | |||
82 | /** | ||
83 | * All non-0-value'd elements transmitted to us. | ||
84 | */ | ||
85 | struct GNUNET_CONTAINER_MultiHashMap *intersected_elements; | ||
86 | |||
87 | /** | ||
88 | * Set of elements for which we will be conducting an intersection. | ||
89 | * The resulting elements are then used for computing the scalar product. | ||
90 | */ | ||
91 | struct GNUNET_SETI_Handle *intersection_set; | ||
92 | |||
93 | /** | ||
94 | * Set of elements for which will conduction an intersection. | ||
95 | * the resulting elements are then used for computing the scalar product. | ||
96 | */ | ||
97 | struct GNUNET_SETI_OperationHandle *intersection_op; | ||
98 | |||
99 | /** | ||
100 | * CADET port we are listening on. | ||
101 | */ | ||
102 | struct GNUNET_CADET_Port *port; | ||
103 | |||
104 | /** | ||
105 | * a(Alice) | ||
106 | */ | ||
107 | struct MpiElement *sorted_elements; | ||
108 | |||
109 | /** | ||
110 | * E(ai)(Bob) after applying the mask | ||
111 | */ | ||
112 | struct GNUNET_CRYPTO_PaillierCiphertext *e_a; | ||
113 | |||
114 | /** | ||
115 | * Bob's permutation p of R | ||
116 | */ | ||
117 | struct GNUNET_CRYPTO_PaillierCiphertext *r; | ||
118 | |||
119 | /** | ||
120 | * Bob's permutation q of R | ||
121 | */ | ||
122 | struct GNUNET_CRYPTO_PaillierCiphertext *r_prime; | ||
123 | |||
124 | /** | ||
125 | * Bob's "s" | ||
126 | */ | ||
127 | struct GNUNET_CRYPTO_PaillierCiphertext s; | ||
128 | |||
129 | /** | ||
130 | * Bob's "s'" | ||
131 | */ | ||
132 | struct GNUNET_CRYPTO_PaillierCiphertext s_prime; | ||
133 | |||
134 | /** | ||
135 | * Handle for our associated incoming CADET session, or NULL | ||
136 | * if we have not gotten one yet. | ||
137 | */ | ||
138 | struct CadetIncomingSession *cadet; | ||
139 | |||
140 | /** | ||
141 | * How many elements will be supplied in total from the client. | ||
142 | */ | ||
143 | uint32_t total; | ||
144 | |||
145 | /** | ||
146 | * Already transferred elements (received) for multipart | ||
147 | * messages from client. Always less than @e total. | ||
148 | */ | ||
149 | uint32_t client_received_element_count; | ||
150 | |||
151 | /** | ||
152 | * How many elements actually are used for the scalar product. | ||
153 | * Size of the arrays in @e r and @e r_prime. Also sometimes | ||
154 | * used as an index into the arrays during construction. | ||
155 | */ | ||
156 | uint32_t used_element_count; | ||
157 | |||
158 | /** | ||
159 | * Counts the number of values received from Alice by us. | ||
160 | * Always less than @e used_element_count. | ||
161 | */ | ||
162 | uint32_t cadet_received_element_count; | ||
163 | |||
164 | /** | ||
165 | * Counts the number of values transmitted from us to Alice. | ||
166 | * Always less than @e used_element_count. | ||
167 | */ | ||
168 | uint32_t cadet_transmitted_element_count; | ||
169 | |||
170 | /** | ||
171 | * State of this session. In | ||
172 | * #GNUNET_SCALARPRODUCT_STATUS_ACTIVE while operation is | ||
173 | * ongoing, afterwards in #GNUNET_SCALARPRODUCT_STATUS_SUCCESS or | ||
174 | * #GNUNET_SCALARPRODUCT_STATUS_FAILURE. | ||
175 | */ | ||
176 | enum GNUNET_SCALARPRODUCT_ResponseStatus status; | ||
177 | |||
178 | /** | ||
179 | * Are we already in #destroy_service_session()? | ||
180 | */ | ||
181 | int in_destroy; | ||
182 | |||
183 | /** | ||
184 | * The CADET channel. | ||
185 | */ | ||
186 | struct GNUNET_CADET_Channel *channel; | ||
187 | |||
188 | /** | ||
189 | * Originator's peer identity. (Only for diagnostics.) | ||
190 | */ | ||
191 | struct GNUNET_PeerIdentity peer; | ||
192 | |||
193 | /** | ||
194 | * Public key of the remote service. | ||
195 | */ | ||
196 | struct GNUNET_CRYPTO_PaillierPublicKey remote_pubkey; | ||
197 | |||
198 | /** | ||
199 | * The message queue for this channel. | ||
200 | */ | ||
201 | struct GNUNET_MQ_Handle *cadet_mq; | ||
202 | }; | ||
203 | |||
204 | |||
205 | /** | ||
206 | * GNUnet configuration handle | ||
207 | */ | ||
208 | static const struct GNUNET_CONFIGURATION_Handle *cfg; | ||
209 | |||
210 | /** | ||
211 | * Service's own public key | ||
212 | */ | ||
213 | static struct GNUNET_CRYPTO_PaillierPublicKey my_pubkey; | ||
214 | |||
215 | /** | ||
216 | * Service's own private key | ||
217 | */ | ||
218 | static struct GNUNET_CRYPTO_PaillierPrivateKey my_privkey; | ||
219 | |||
220 | /** | ||
221 | * Service's offset for values that could possibly be negative but are plaintext for encryption. | ||
222 | */ | ||
223 | static gcry_mpi_t my_offset; | ||
224 | |||
225 | /** | ||
226 | * Handle to the CADET service. | ||
227 | */ | ||
228 | static struct GNUNET_CADET_Handle *my_cadet; | ||
229 | |||
230 | |||
231 | /** | ||
232 | * Callback used to free the elements in the map. | ||
233 | * | ||
234 | * @param cls NULL | ||
235 | * @param key key of the element | ||
236 | * @param value the value to free | ||
237 | */ | ||
238 | static int | ||
239 | free_element_cb (void *cls, | ||
240 | const struct GNUNET_HashCode *key, | ||
241 | void *value) | ||
242 | { | ||
243 | struct GNUNET_SCALARPRODUCT_Element *element = value; | ||
244 | |||
245 | GNUNET_free (element); | ||
246 | return GNUNET_OK; | ||
247 | } | ||
248 | |||
249 | |||
250 | /** | ||
251 | * Destroy session state, we are done with it. | ||
252 | * | ||
253 | * @param session the session to free elements from | ||
254 | */ | ||
255 | static void | ||
256 | destroy_service_session (struct BobServiceSession *s) | ||
257 | { | ||
258 | unsigned int i; | ||
259 | |||
260 | if (GNUNET_YES == s->in_destroy) | ||
261 | return; | ||
262 | s->in_destroy = GNUNET_YES; | ||
263 | if (NULL != s->client) | ||
264 | { | ||
265 | struct GNUNET_SERVICE_Client *c = s->client; | ||
266 | |||
267 | s->client = NULL; | ||
268 | GNUNET_SERVICE_client_drop (c); | ||
269 | } | ||
270 | if (NULL != s->intersected_elements) | ||
271 | { | ||
272 | GNUNET_CONTAINER_multihashmap_iterate (s->intersected_elements, | ||
273 | &free_element_cb, | ||
274 | NULL); | ||
275 | GNUNET_CONTAINER_multihashmap_destroy (s->intersected_elements); | ||
276 | s->intersected_elements = NULL; | ||
277 | } | ||
278 | if (NULL != s->intersection_op) | ||
279 | { | ||
280 | GNUNET_SETI_operation_cancel (s->intersection_op); | ||
281 | s->intersection_op = NULL; | ||
282 | } | ||
283 | if (NULL != s->intersection_set) | ||
284 | { | ||
285 | GNUNET_SETI_destroy (s->intersection_set); | ||
286 | s->intersection_set = NULL; | ||
287 | } | ||
288 | if (NULL != s->e_a) | ||
289 | { | ||
290 | GNUNET_free (s->e_a); | ||
291 | s->e_a = NULL; | ||
292 | } | ||
293 | if (NULL != s->sorted_elements) | ||
294 | { | ||
295 | for (i = 0; i < s->used_element_count; i++) | ||
296 | gcry_mpi_release (s->sorted_elements[i].value); | ||
297 | GNUNET_free (s->sorted_elements); | ||
298 | s->sorted_elements = NULL; | ||
299 | } | ||
300 | if (NULL != s->r) | ||
301 | { | ||
302 | GNUNET_free (s->r); | ||
303 | s->r = NULL; | ||
304 | } | ||
305 | if (NULL != s->r_prime) | ||
306 | { | ||
307 | GNUNET_free (s->r_prime); | ||
308 | s->r_prime = NULL; | ||
309 | } | ||
310 | if (NULL != s->port) | ||
311 | { | ||
312 | GNUNET_CADET_close_port (s->port); | ||
313 | s->port = NULL; | ||
314 | } | ||
315 | if (NULL != s->channel) | ||
316 | { | ||
317 | GNUNET_CADET_channel_destroy (s->channel); | ||
318 | s->channel = NULL; | ||
319 | } | ||
320 | GNUNET_free (s); | ||
321 | } | ||
322 | |||
323 | |||
324 | /** | ||
325 | * Notify the client that the session has succeeded or failed. This | ||
326 | * message gets sent to Bob's client if the operation completed or | ||
327 | * Alice disconnected. | ||
328 | * | ||
329 | * @param session the associated client session to fail or succeed | ||
330 | */ | ||
331 | static void | ||
332 | prepare_client_end_notification (struct BobServiceSession *session) | ||
333 | { | ||
334 | struct ClientResponseMessage *msg; | ||
335 | struct GNUNET_MQ_Envelope *e; | ||
336 | |||
337 | if (NULL == session->client_mq) | ||
338 | return; /* no client left to be notified */ | ||
339 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
340 | "Sending session-end notification with status %d to client for session %s\n", | ||
341 | session->status, | ||
342 | GNUNET_h2s (&session->session_id)); | ||
343 | e = GNUNET_MQ_msg (msg, | ||
344 | GNUNET_MESSAGE_TYPE_SCALARPRODUCT_RESULT); | ||
345 | msg->range = 0; | ||
346 | msg->product_length = htonl (0); | ||
347 | msg->status = htonl (session->status); | ||
348 | GNUNET_MQ_send (session->client_mq, | ||
349 | e); | ||
350 | } | ||
351 | |||
352 | |||
353 | /** | ||
354 | * Function called whenever a channel is destroyed. Should clean up | ||
355 | * any associated state. | ||
356 | * | ||
357 | * It must NOT call #GNUNET_CADET_channel_destroy() on the channel. | ||
358 | * | ||
359 | * @param cls the `struct BobServiceSession` | ||
360 | * @param channel connection to the other end (henceforth invalid) | ||
361 | */ | ||
362 | static void | ||
363 | cb_channel_destruction (void *cls, | ||
364 | const struct GNUNET_CADET_Channel *channel) | ||
365 | { | ||
366 | struct BobServiceSession *s = cls; | ||
367 | |||
368 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
369 | "Peer disconnected, terminating session %s with peer %s\n", | ||
370 | GNUNET_h2s (&s->session_id), | ||
371 | GNUNET_i2s (&s->peer)); | ||
372 | if (GNUNET_SCALARPRODUCT_STATUS_ACTIVE == s->status) | ||
373 | { | ||
374 | s->status = GNUNET_SCALARPRODUCT_STATUS_FAILURE; | ||
375 | prepare_client_end_notification (s); | ||
376 | } | ||
377 | s->channel = NULL; | ||
378 | destroy_service_session (s); | ||
379 | } | ||
380 | |||
381 | |||
382 | /** | ||
383 | * MQ finished giving our last message to CADET, now notify | ||
384 | * the client that we are finished. | ||
385 | */ | ||
386 | static void | ||
387 | bob_cadet_done_cb (void *cls) | ||
388 | { | ||
389 | struct BobServiceSession *session = cls; | ||
390 | |||
391 | session->status = GNUNET_SCALARPRODUCT_STATUS_SUCCESS; | ||
392 | prepare_client_end_notification (session); | ||
393 | } | ||
394 | |||
395 | |||
396 | /** | ||
397 | * Maximum count of elements we can put into a multipart message | ||
398 | */ | ||
399 | #define ELEMENT_CAPACITY ((GNUNET_CONSTANTS_MAX_CADET_MESSAGE_SIZE - 1 \ | ||
400 | - sizeof(struct BobCryptodataMultipartMessage)) \ | ||
401 | / sizeof(struct \ | ||
402 | GNUNET_CRYPTO_PaillierCiphertext)) | ||
403 | |||
404 | |||
405 | /** | ||
406 | * Send a multipart chunk of a service response from Bob to Alice. | ||
407 | * This element only contains the two permutations of R, R'. | ||
408 | * | ||
409 | * @param s the associated service session | ||
410 | */ | ||
411 | static void | ||
412 | transmit_bobs_cryptodata_message_multipart (struct BobServiceSession *s) | ||
413 | { | ||
414 | struct GNUNET_CRYPTO_PaillierCiphertext *payload; | ||
415 | struct BobCryptodataMultipartMessage *msg; | ||
416 | struct GNUNET_MQ_Envelope *e; | ||
417 | unsigned int i; | ||
418 | unsigned int j; | ||
419 | uint32_t todo_count; | ||
420 | |||
421 | while (s->cadet_transmitted_element_count != s->used_element_count) | ||
422 | { | ||
423 | todo_count = s->used_element_count - s->cadet_transmitted_element_count; | ||
424 | if (todo_count > ELEMENT_CAPACITY / 2) | ||
425 | todo_count = ELEMENT_CAPACITY / 2; | ||
426 | |||
427 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
428 | "Sending %u additional crypto values to Alice\n", | ||
429 | (unsigned int) todo_count); | ||
430 | e = GNUNET_MQ_msg_extra (msg, | ||
431 | todo_count * sizeof(struct | ||
432 | GNUNET_CRYPTO_PaillierCiphertext) | ||
433 | * 2, | ||
434 | GNUNET_MESSAGE_TYPE_SCALARPRODUCT_BOB_CRYPTODATA_MULTIPART); | ||
435 | msg->contained_element_count = htonl (todo_count); | ||
436 | payload = (struct GNUNET_CRYPTO_PaillierCiphertext *) &msg[1]; | ||
437 | for (i = s->cadet_transmitted_element_count, j = 0; i < | ||
438 | s->cadet_transmitted_element_count + todo_count; i++) | ||
439 | { | ||
440 | // r[i][p] and r[i][q] | ||
441 | GNUNET_memcpy (&payload[j++], | ||
442 | &s->r[i], | ||
443 | sizeof(struct GNUNET_CRYPTO_PaillierCiphertext)); | ||
444 | GNUNET_memcpy (&payload[j++], | ||
445 | &s->r_prime[i], | ||
446 | sizeof(struct GNUNET_CRYPTO_PaillierCiphertext)); | ||
447 | } | ||
448 | s->cadet_transmitted_element_count += todo_count; | ||
449 | if (s->cadet_transmitted_element_count == s->used_element_count) | ||
450 | GNUNET_MQ_notify_sent (e, | ||
451 | &bob_cadet_done_cb, | ||
452 | s); | ||
453 | GNUNET_MQ_send (s->cadet_mq, | ||
454 | e); | ||
455 | } | ||
456 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
457 | "All values queued for Alice, Bob is done\n"); | ||
458 | } | ||
459 | |||
460 | |||
461 | /** | ||
462 | * Bob generates the response message to be sent to Alice after | ||
463 | * computing the values (1), (2), S and S'. | ||
464 | * | ||
465 | * (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)})$ | ||
466 | * (2)[]: $E_A(a_{pi'(i)}) times E_A(- r_{pi'(i)}) &= E_A(a_{pi'(i)} - r_{pi'(i)})$ | ||
467 | * S: $S := E_A(sum (r_i + b_i)^2)$ | ||
468 | * S': $S' := E_A(sum r_i^2)$ | ||
469 | * | ||
470 | * @param s the associated requesting session with Alice | ||
471 | */ | ||
472 | static void | ||
473 | transmit_bobs_cryptodata_message (struct BobServiceSession *s) | ||
474 | { | ||
475 | struct BobCryptodataMessage *msg; | ||
476 | struct GNUNET_MQ_Envelope *e; | ||
477 | struct GNUNET_CRYPTO_PaillierCiphertext *payload; | ||
478 | unsigned int i; | ||
479 | |||
480 | s->cadet_transmitted_element_count | ||
481 | = ((GNUNET_CONSTANTS_MAX_CADET_MESSAGE_SIZE - 1 - sizeof(struct | ||
482 | BobCryptodataMessage)) | ||
483 | / sizeof(struct GNUNET_CRYPTO_PaillierCiphertext) / 2) - 1; | ||
484 | if (s->cadet_transmitted_element_count > s->used_element_count) | ||
485 | s->cadet_transmitted_element_count = s->used_element_count; | ||
486 | |||
487 | e = GNUNET_MQ_msg_extra (msg, | ||
488 | (2 + s->cadet_transmitted_element_count * 2) | ||
489 | * sizeof(struct GNUNET_CRYPTO_PaillierCiphertext), | ||
490 | GNUNET_MESSAGE_TYPE_SCALARPRODUCT_BOB_CRYPTODATA); | ||
491 | msg->contained_element_count = htonl (s->cadet_transmitted_element_count); | ||
492 | |||
493 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
494 | "Sending %u/%u crypto values to Alice\n", | ||
495 | (unsigned int) s->cadet_transmitted_element_count, | ||
496 | (unsigned int) s->used_element_count); | ||
497 | |||
498 | payload = (struct GNUNET_CRYPTO_PaillierCiphertext *) &msg[1]; | ||
499 | GNUNET_memcpy (&payload[0], | ||
500 | &s->s, | ||
501 | sizeof(struct GNUNET_CRYPTO_PaillierCiphertext)); | ||
502 | GNUNET_memcpy (&payload[1], | ||
503 | &s->s_prime, | ||
504 | sizeof(struct GNUNET_CRYPTO_PaillierCiphertext)); | ||
505 | |||
506 | payload = &payload[2]; | ||
507 | // convert k[][] | ||
508 | for (i = 0; i < s->cadet_transmitted_element_count; i++) | ||
509 | { | ||
510 | // k[i][p] and k[i][q] | ||
511 | GNUNET_memcpy (&payload[i * 2], | ||
512 | &s->r[i], | ||
513 | sizeof(struct GNUNET_CRYPTO_PaillierCiphertext)); | ||
514 | GNUNET_memcpy (&payload[i * 2 + 1], | ||
515 | &s->r_prime[i], | ||
516 | sizeof(struct GNUNET_CRYPTO_PaillierCiphertext)); | ||
517 | } | ||
518 | if (s->cadet_transmitted_element_count == s->used_element_count) | ||
519 | GNUNET_MQ_notify_sent (e, | ||
520 | &bob_cadet_done_cb, | ||
521 | s); | ||
522 | GNUNET_MQ_send (s->cadet_mq, | ||
523 | e); | ||
524 | transmit_bobs_cryptodata_message_multipart (s); | ||
525 | } | ||
526 | |||
527 | |||
528 | #undef ELEMENT_CAPACITY | ||
529 | |||
530 | |||
531 | /** | ||
532 | * Computes the square sum over a vector of a given length. | ||
533 | * | ||
534 | * @param vector the vector to compute over | ||
535 | * @param length the length of the vector | ||
536 | * @return an MPI value containing the calculated sum, never NULL | ||
537 | * TODO: code duplication with Alice! | ||
538 | */ | ||
539 | static gcry_mpi_t | ||
540 | compute_square_sum (const gcry_mpi_t *vector, | ||
541 | uint32_t length) | ||
542 | { | ||
543 | gcry_mpi_t elem; | ||
544 | gcry_mpi_t sum; | ||
545 | uint32_t i; | ||
546 | |||
547 | GNUNET_assert (NULL != (sum = gcry_mpi_new (0))); | ||
548 | GNUNET_assert (NULL != (elem = gcry_mpi_new (0))); | ||
549 | for (i = 0; i < length; i++) | ||
550 | { | ||
551 | gcry_mpi_mul (elem, vector[i], vector[i]); | ||
552 | gcry_mpi_add (sum, sum, elem); | ||
553 | } | ||
554 | gcry_mpi_release (elem); | ||
555 | return sum; | ||
556 | } | ||
557 | |||
558 | |||
559 | /** | ||
560 | * Compute the values | ||
561 | * (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)})$ | ||
562 | * (2)[]: $E_A(a_{pi'(i)}) otimes E_A(- r_{pi'(i)}) &= E_A(a_{pi'(i)} - r_{pi'(i)})$ | ||
563 | * S: $S := E_A(sum (r_i + b_i)^2)$ | ||
564 | * S': $S' := E_A(sum r_i^2)$ | ||
565 | * | ||
566 | * @param request the requesting session + bob's requesting peer | ||
567 | * @return #GNUNET_OK on success | ||
568 | */ | ||
569 | static int | ||
570 | compute_service_response (struct BobServiceSession *session) | ||
571 | { | ||
572 | uint32_t i; | ||
573 | unsigned int *p; | ||
574 | unsigned int *q; | ||
575 | uint32_t count; | ||
576 | gcry_mpi_t *rand; | ||
577 | gcry_mpi_t tmp; | ||
578 | const struct MpiElement *b; | ||
579 | struct GNUNET_CRYPTO_PaillierCiphertext *a; | ||
580 | struct GNUNET_CRYPTO_PaillierCiphertext *r; | ||
581 | struct GNUNET_CRYPTO_PaillierCiphertext *r_prime; | ||
582 | |||
583 | count = session->used_element_count; | ||
584 | a = session->e_a; | ||
585 | b = session->sorted_elements; | ||
586 | q = GNUNET_CRYPTO_random_permute (GNUNET_CRYPTO_QUALITY_WEAK, | ||
587 | count); | ||
588 | p = GNUNET_CRYPTO_random_permute (GNUNET_CRYPTO_QUALITY_WEAK, | ||
589 | count); | ||
590 | rand = GNUNET_malloc (sizeof(gcry_mpi_t) * count); | ||
591 | for (i = 0; i < count; i++) | ||
592 | GNUNET_assert (NULL != (rand[i] = gcry_mpi_new (0))); | ||
593 | r = GNUNET_malloc (sizeof(struct GNUNET_CRYPTO_PaillierCiphertext) * count); | ||
594 | r_prime = GNUNET_malloc (sizeof(struct GNUNET_CRYPTO_PaillierCiphertext) | ||
595 | * count); | ||
596 | |||
597 | for (i = 0; i < count; i++) | ||
598 | { | ||
599 | int32_t svalue; | ||
600 | |||
601 | svalue = (int32_t) GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_WEAK, | ||
602 | UINT32_MAX); | ||
603 | // long to gcry_mpi_t | ||
604 | if (svalue < 0) | ||
605 | gcry_mpi_sub_ui (rand[i], | ||
606 | rand[i], | ||
607 | -svalue); | ||
608 | else | ||
609 | rand[i] = gcry_mpi_set_ui (rand[i], svalue); | ||
610 | } | ||
611 | |||
612 | tmp = gcry_mpi_new (0); | ||
613 | // encrypt the element | ||
614 | // for the sake of readability I decided to have dedicated permutation | ||
615 | // vectors, which get rid of all the lookups in p/q. | ||
616 | // however, ap/aq are not absolutely necessary but are just abstraction | ||
617 | // Calculate Kp = E(S + a_pi) (+) E(S - r_pi - b_pi) | ||
618 | for (i = 0; i < count; i++) | ||
619 | { | ||
620 | // E(S - r_pi - b_pi) | ||
621 | gcry_mpi_sub (tmp, my_offset, rand[p[i]]); | ||
622 | gcry_mpi_sub (tmp, tmp, b[p[i]].value); | ||
623 | GNUNET_assert (2 == | ||
624 | GNUNET_CRYPTO_paillier_encrypt (&session->remote_pubkey, | ||
625 | tmp, | ||
626 | 2, | ||
627 | &r[i])); | ||
628 | |||
629 | // E(S - r_pi - b_pi) * E(S + a_pi) == E(2*S + a - r - b) | ||
630 | if (GNUNET_OK != | ||
631 | GNUNET_CRYPTO_paillier_hom_add (&session->remote_pubkey, | ||
632 | &r[i], | ||
633 | &a[p[i]], | ||
634 | &r[i])) | ||
635 | { | ||
636 | GNUNET_break_op (0); | ||
637 | goto error_cleanup; | ||
638 | } | ||
639 | } | ||
640 | |||
641 | // Calculate Kq = E(S + a_qi) (+) E(S - r_qi) | ||
642 | for (i = 0; i < count; i++) | ||
643 | { | ||
644 | // E(S - r_qi) | ||
645 | gcry_mpi_sub (tmp, my_offset, rand[q[i]]); | ||
646 | GNUNET_assert (2 == | ||
647 | GNUNET_CRYPTO_paillier_encrypt (&session->remote_pubkey, | ||
648 | tmp, | ||
649 | 2, | ||
650 | &r_prime[i])); | ||
651 | |||
652 | // E(S - r_qi) * E(S + a_qi) == E(2*S + a_qi - r_qi) | ||
653 | if (GNUNET_OK != | ||
654 | GNUNET_CRYPTO_paillier_hom_add (&session->remote_pubkey, | ||
655 | &r_prime[i], | ||
656 | &a[q[i]], | ||
657 | &r_prime[i])) | ||
658 | { | ||
659 | GNUNET_break_op (0); | ||
660 | goto error_cleanup; | ||
661 | } | ||
662 | } | ||
663 | gcry_mpi_release (tmp); | ||
664 | |||
665 | // Calculate S' = E(SUM( r_i^2 )) | ||
666 | tmp = compute_square_sum (rand, count); | ||
667 | GNUNET_assert (1 == | ||
668 | GNUNET_CRYPTO_paillier_encrypt (&session->remote_pubkey, | ||
669 | tmp, | ||
670 | 1, | ||
671 | &session->s_prime)); | ||
672 | gcry_mpi_release (tmp); | ||
673 | |||
674 | // Calculate S = E(SUM( (r_i + b_i)^2 )) | ||
675 | for (i = 0; i < count; i++) | ||
676 | gcry_mpi_add (rand[i], rand[i], b[i].value); | ||
677 | tmp = compute_square_sum (rand, count); | ||
678 | GNUNET_assert (1 == | ||
679 | GNUNET_CRYPTO_paillier_encrypt (&session->remote_pubkey, | ||
680 | tmp, | ||
681 | 1, | ||
682 | &session->s)); | ||
683 | gcry_mpi_release (tmp); | ||
684 | |||
685 | session->r = r; | ||
686 | session->r_prime = r_prime; | ||
687 | |||
688 | for (i = 0; i < count; i++) | ||
689 | gcry_mpi_release (rand[i]); | ||
690 | GNUNET_free (session->e_a); | ||
691 | session->e_a = NULL; | ||
692 | GNUNET_free (p); | ||
693 | GNUNET_free (q); | ||
694 | GNUNET_free (rand); | ||
695 | return GNUNET_OK; | ||
696 | |||
697 | error_cleanup: | ||
698 | GNUNET_free (r); | ||
699 | GNUNET_free (r_prime); | ||
700 | gcry_mpi_release (tmp); | ||
701 | GNUNET_free (p); | ||
702 | GNUNET_free (q); | ||
703 | for (i = 0; i < count; i++) | ||
704 | gcry_mpi_release (rand[i]); | ||
705 | GNUNET_free (rand); | ||
706 | return GNUNET_SYSERR; | ||
707 | } | ||
708 | |||
709 | |||
710 | /** | ||
711 | * Iterator to copy over messages from the hash map | ||
712 | * into an array for sorting. | ||
713 | * | ||
714 | * @param cls the `struct BobServiceSession *` | ||
715 | * @param key the key (unused) | ||
716 | * @param value the `struct GNUNET_SCALARPRODUCT_Element *` | ||
717 | * TODO: code duplication with Alice! | ||
718 | */ | ||
719 | static int | ||
720 | copy_element_cb (void *cls, | ||
721 | const struct GNUNET_HashCode *key, | ||
722 | void *value) | ||
723 | { | ||
724 | struct BobServiceSession *s = cls; | ||
725 | struct GNUNET_SCALARPRODUCT_Element *e = value; | ||
726 | gcry_mpi_t mval; | ||
727 | int64_t val; | ||
728 | |||
729 | mval = gcry_mpi_new (0); | ||
730 | val = (int64_t) GNUNET_ntohll (e->value); | ||
731 | if (0 > val) | ||
732 | gcry_mpi_sub_ui (mval, mval, -val); | ||
733 | else | ||
734 | gcry_mpi_add_ui (mval, mval, val); | ||
735 | s->sorted_elements [s->used_element_count].value = mval; | ||
736 | s->sorted_elements [s->used_element_count].key = &e->key; | ||
737 | s->used_element_count++; | ||
738 | return GNUNET_OK; | ||
739 | } | ||
740 | |||
741 | |||
742 | /** | ||
743 | * Compare two `struct MpiValue`s by key for sorting. | ||
744 | * | ||
745 | * @param a pointer to first `struct MpiValue *` | ||
746 | * @param b pointer to first `struct MpiValue *` | ||
747 | * @return -1 for a < b, 0 for a=b, 1 for a > b. | ||
748 | * TODO: code duplication with Alice! | ||
749 | */ | ||
750 | static int | ||
751 | element_cmp (const void *a, | ||
752 | const void *b) | ||
753 | { | ||
754 | const struct MpiElement *ma = a; | ||
755 | const struct MpiElement *mb = b; | ||
756 | |||
757 | return GNUNET_CRYPTO_hash_cmp (ma->key, | ||
758 | mb->key); | ||
759 | } | ||
760 | |||
761 | |||
762 | /** | ||
763 | * Intersection operation and receiving data via CADET from | ||
764 | * Alice are both done, compute and transmit our reply via | ||
765 | * CADET. | ||
766 | * | ||
767 | * @param s session to transmit reply for. | ||
768 | */ | ||
769 | static void | ||
770 | transmit_cryptographic_reply (struct BobServiceSession *s) | ||
771 | { | ||
772 | struct GNUNET_CADET_Channel *channel; | ||
773 | |||
774 | /* TODO: code duplication with Alice! */ | ||
775 | LOG (GNUNET_ERROR_TYPE_DEBUG, | ||
776 | "Received everything, building reply for Alice\n"); | ||
777 | s->sorted_elements | ||
778 | = GNUNET_malloc (GNUNET_CONTAINER_multihashmap_size ( | ||
779 | s->intersected_elements) | ||
780 | * sizeof(struct MpiElement)); | ||
781 | s->used_element_count = 0; | ||
782 | GNUNET_CONTAINER_multihashmap_iterate (s->intersected_elements, | ||
783 | ©_element_cb, | ||
784 | s); | ||
785 | qsort (s->sorted_elements, | ||
786 | s->used_element_count, | ||
787 | sizeof(struct MpiElement), | ||
788 | &element_cmp); | ||
789 | if (GNUNET_OK != | ||
790 | compute_service_response (s)) | ||
791 | { | ||
792 | channel = s->channel; | ||
793 | s->channel = NULL; | ||
794 | GNUNET_CADET_channel_destroy (channel); | ||
795 | return; | ||
796 | } | ||
797 | transmit_bobs_cryptodata_message (s); | ||
798 | } | ||
799 | |||
800 | |||
801 | /** | ||
802 | * Check a multipart-chunk of a request from another service to | ||
803 | * calculate a scalarproduct with us. | ||
804 | * | ||
805 | * @param cls the `struct BobServiceSession *` | ||
806 | * @param msg the actual message | ||
807 | * @return #GNUNET_OK to keep the connection open, | ||
808 | * #GNUNET_SYSERR to close it (signal serious error) | ||
809 | */ | ||
810 | static int | ||
811 | check_alices_cryptodata_message (void *cls, | ||
812 | const struct AliceCryptodataMessage *msg) | ||
813 | { | ||
814 | struct BobServiceSession *s = cls; | ||
815 | uint32_t contained_elements; | ||
816 | size_t msg_length; | ||
817 | uint16_t msize; | ||
818 | unsigned int max; | ||
819 | |||
820 | msize = ntohs (msg->header.size); | ||
821 | contained_elements = ntohl (msg->contained_element_count); | ||
822 | /* Our intersection may still be ongoing, but this is nevertheless | ||
823 | an upper bound on the required array size */ | ||
824 | max = GNUNET_CONTAINER_multihashmap_size (s->intersected_elements); | ||
825 | msg_length = sizeof(struct AliceCryptodataMessage) | ||
826 | + contained_elements * sizeof(struct | ||
827 | GNUNET_CRYPTO_PaillierCiphertext); | ||
828 | if ((msize != msg_length) || | ||
829 | (0 == contained_elements) || | ||
830 | (contained_elements > UINT16_MAX) || | ||
831 | (max < contained_elements + s->cadet_received_element_count)) | ||
832 | { | ||
833 | GNUNET_break_op (0); | ||
834 | return GNUNET_SYSERR; | ||
835 | } | ||
836 | return GNUNET_OK; | ||
837 | } | ||
838 | |||
839 | |||
840 | /** | ||
841 | * Handle a multipart-chunk of a request from another service to | ||
842 | * calculate a scalarproduct with us. | ||
843 | * | ||
844 | * @param cls the `struct BobServiceSession *` | ||
845 | * @param msg the actual message | ||
846 | */ | ||
847 | static void | ||
848 | handle_alices_cryptodata_message (void *cls, | ||
849 | const struct AliceCryptodataMessage *msg) | ||
850 | { | ||
851 | struct BobServiceSession *s = cls; | ||
852 | const struct GNUNET_CRYPTO_PaillierCiphertext *payload; | ||
853 | uint32_t contained_elements; | ||
854 | unsigned int max; | ||
855 | |||
856 | contained_elements = ntohl (msg->contained_element_count); | ||
857 | /* Our intersection may still be ongoing, but this is nevertheless | ||
858 | an upper bound on the required array size */ | ||
859 | max = GNUNET_CONTAINER_multihashmap_size (s->intersected_elements); | ||
860 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
861 | "Received %u crypto values from Alice\n", | ||
862 | (unsigned int) contained_elements); | ||
863 | |||
864 | payload = (const struct GNUNET_CRYPTO_PaillierCiphertext *) &msg[1]; | ||
865 | if (NULL == s->e_a) | ||
866 | s->e_a = GNUNET_new_array (max, | ||
867 | struct GNUNET_CRYPTO_PaillierCiphertext); | ||
868 | GNUNET_memcpy (&s->e_a[s->cadet_received_element_count], | ||
869 | payload, | ||
870 | sizeof(struct GNUNET_CRYPTO_PaillierCiphertext) | ||
871 | * contained_elements); | ||
872 | s->cadet_received_element_count += contained_elements; | ||
873 | |||
874 | if ((s->cadet_received_element_count == max) && | ||
875 | (NULL == s->intersection_op)) | ||
876 | { | ||
877 | /* intersection has finished also on our side, and | ||
878 | we got the full set, so we can proceed with the | ||
879 | CADET response(s) */ | ||
880 | transmit_cryptographic_reply (s); | ||
881 | } | ||
882 | GNUNET_CADET_receive_done (s->channel); | ||
883 | } | ||
884 | |||
885 | |||
886 | /** | ||
887 | * Callback for set operation results. Called for each element | ||
888 | * that needs to be removed from the result set. | ||
889 | * | ||
890 | * @param cls closure with the `struct BobServiceSession` | ||
891 | * @param element a result element, only valid if status is #GNUNET_SETI_STATUS_OK | ||
892 | * @param current_size current set size | ||
893 | * @param status what has happened with the set intersection? | ||
894 | */ | ||
895 | static void | ||
896 | cb_intersection_element_removed (void *cls, | ||
897 | const struct GNUNET_SETI_Element *element, | ||
898 | uint64_t current_size, | ||
899 | enum GNUNET_SETI_Status status) | ||
900 | { | ||
901 | struct BobServiceSession *s = cls; | ||
902 | struct GNUNET_SCALARPRODUCT_Element *se; | ||
903 | |||
904 | switch (status) | ||
905 | { | ||
906 | case GNUNET_SETI_STATUS_DEL_LOCAL: | ||
907 | /* this element has been removed from the set */ | ||
908 | se = GNUNET_CONTAINER_multihashmap_get (s->intersected_elements, | ||
909 | element->data); | ||
910 | GNUNET_assert (NULL != se); | ||
911 | LOG (GNUNET_ERROR_TYPE_DEBUG, | ||
912 | "Removed element with key %s and value %lld\n", | ||
913 | GNUNET_h2s (&se->key), | ||
914 | (long long) GNUNET_ntohll (se->value)); | ||
915 | GNUNET_assert (GNUNET_YES == | ||
916 | GNUNET_CONTAINER_multihashmap_remove ( | ||
917 | s->intersected_elements, | ||
918 | element->data, | ||
919 | se)); | ||
920 | GNUNET_free (se); | ||
921 | return; | ||
922 | case GNUNET_SETI_STATUS_DONE: | ||
923 | s->intersection_op = NULL; | ||
924 | GNUNET_break (NULL == s->intersection_set); | ||
925 | GNUNET_CADET_receive_done (s->channel); | ||
926 | LOG (GNUNET_ERROR_TYPE_DEBUG, | ||
927 | "Finished intersection, %d items remain\n", | ||
928 | GNUNET_CONTAINER_multihashmap_size (s->intersected_elements)); | ||
929 | if (s->client_received_element_count == | ||
930 | GNUNET_CONTAINER_multihashmap_size (s->intersected_elements)) | ||
931 | { | ||
932 | /* CADET transmission from Alice is also already done, | ||
933 | start with our own reply */ | ||
934 | transmit_cryptographic_reply (s); | ||
935 | } | ||
936 | return; | ||
937 | case GNUNET_SETI_STATUS_FAILURE: | ||
938 | /* unhandled status code */ | ||
939 | LOG (GNUNET_ERROR_TYPE_DEBUG, | ||
940 | "Set intersection failed!\n"); | ||
941 | s->intersection_op = NULL; | ||
942 | if (NULL != s->intersection_set) | ||
943 | { | ||
944 | GNUNET_SETI_destroy (s->intersection_set); | ||
945 | s->intersection_set = NULL; | ||
946 | } | ||
947 | s->status = GNUNET_SCALARPRODUCT_STATUS_FAILURE; | ||
948 | prepare_client_end_notification (s); | ||
949 | return; | ||
950 | default: | ||
951 | GNUNET_break (0); | ||
952 | return; | ||
953 | } | ||
954 | } | ||
955 | |||
956 | |||
957 | /** | ||
958 | * We've paired up a client session with an incoming CADET request. | ||
959 | * Initiate set intersection work. | ||
960 | * | ||
961 | * @param s client session to start intersection for | ||
962 | */ | ||
963 | static void | ||
964 | start_intersection (struct BobServiceSession *s) | ||
965 | { | ||
966 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
967 | "Got session with key %s and %u elements, starting intersection.\n", | ||
968 | GNUNET_h2s (&s->session_id), | ||
969 | (unsigned int) s->total); | ||
970 | |||
971 | s->intersection_op | ||
972 | = GNUNET_SETI_prepare (&s->peer, | ||
973 | &s->session_id, | ||
974 | NULL, | ||
975 | (struct GNUNET_SETI_Option[]) { { 0 } }, | ||
976 | &cb_intersection_element_removed, | ||
977 | s); | ||
978 | if (GNUNET_OK != | ||
979 | GNUNET_SETI_commit (s->intersection_op, | ||
980 | s->intersection_set)) | ||
981 | { | ||
982 | GNUNET_break (0); | ||
983 | s->status = GNUNET_SCALARPRODUCT_STATUS_FAILURE; | ||
984 | prepare_client_end_notification (s); | ||
985 | return; | ||
986 | } | ||
987 | GNUNET_SETI_destroy (s->intersection_set); | ||
988 | s->intersection_set = NULL; | ||
989 | } | ||
990 | |||
991 | |||
992 | /** | ||
993 | * Handle a request from Alice to calculate a scalarproduct with us (Bob). | ||
994 | * | ||
995 | * @param cls the `struct BobServiceSession *` | ||
996 | * @param msg the actual message | ||
997 | */ | ||
998 | static void | ||
999 | handle_alices_computation_request (void *cls, | ||
1000 | const struct ServiceRequestMessage *msg) | ||
1001 | { | ||
1002 | struct BobServiceSession *s = cls; | ||
1003 | |||
1004 | s->session_id = msg->session_id; // ?? | ||
1005 | s->remote_pubkey = msg->public_key; | ||
1006 | if (s->client_received_element_count == s->total) | ||
1007 | start_intersection (s); | ||
1008 | } | ||
1009 | |||
1010 | |||
1011 | /** | ||
1012 | * Function called for inbound channels on Bob's end. Does some | ||
1013 | * preliminary initialization, more happens after we get Alice's first | ||
1014 | * message. | ||
1015 | * | ||
1016 | * @param cls closure with the `struct BobServiceSession` | ||
1017 | * @param channel new handle to the channel | ||
1018 | * @param initiator peer that started the channel | ||
1019 | * @return session associated with the channel | ||
1020 | */ | ||
1021 | static void * | ||
1022 | cb_channel_incoming (void *cls, | ||
1023 | struct GNUNET_CADET_Channel *channel, | ||
1024 | const struct GNUNET_PeerIdentity *initiator) | ||
1025 | { | ||
1026 | struct BobServiceSession *s = cls; | ||
1027 | |||
1028 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
1029 | "New incoming channel from peer %s.\n", | ||
1030 | GNUNET_i2s (initiator)); | ||
1031 | GNUNET_CADET_close_port (s->port); | ||
1032 | s->port = NULL; | ||
1033 | s->channel = channel; | ||
1034 | s->peer = *initiator; | ||
1035 | s->cadet_mq = GNUNET_CADET_get_mq (s->channel); | ||
1036 | return s; | ||
1037 | } | ||
1038 | |||
1039 | |||
1040 | /** | ||
1041 | * We're receiving additional set data. Check it is well-formed. | ||
1042 | * | ||
1043 | * @param cls identification of the client | ||
1044 | * @param msg the actual message | ||
1045 | * @return #GNUNET_OK if @a msg is well-formed | ||
1046 | */ | ||
1047 | static int | ||
1048 | check_bob_client_message_multipart (void *cls, | ||
1049 | const struct | ||
1050 | ComputationBobCryptodataMultipartMessage * | ||
1051 | msg) | ||
1052 | { | ||
1053 | struct BobServiceSession *s = cls; | ||
1054 | uint32_t contained_count; | ||
1055 | uint16_t msize; | ||
1056 | |||
1057 | msize = ntohs (msg->header.size); | ||
1058 | contained_count = ntohl (msg->element_count_contained); | ||
1059 | if ((msize != (sizeof(struct ComputationBobCryptodataMultipartMessage) | ||
1060 | + contained_count * sizeof(struct | ||
1061 | GNUNET_SCALARPRODUCT_Element))) || | ||
1062 | (0 == contained_count) || | ||
1063 | (UINT16_MAX < contained_count) || | ||
1064 | (s->total == s->client_received_element_count) || | ||
1065 | (s->total < s->client_received_element_count + contained_count)) | ||
1066 | { | ||
1067 | GNUNET_break (0); | ||
1068 | return GNUNET_SYSERR; | ||
1069 | } | ||
1070 | return GNUNET_OK; | ||
1071 | } | ||
1072 | |||
1073 | |||
1074 | /** | ||
1075 | * We're receiving additional set data. Add it to our | ||
1076 | * set and if we are done, initiate the transaction. | ||
1077 | * | ||
1078 | * @param cls identification of the client | ||
1079 | * @param msg the actual message | ||
1080 | */ | ||
1081 | static void | ||
1082 | handle_bob_client_message_multipart (void *cls, | ||
1083 | const struct | ||
1084 | ComputationBobCryptodataMultipartMessage * | ||
1085 | msg) | ||
1086 | { | ||
1087 | struct BobServiceSession *s = cls; | ||
1088 | uint32_t contained_count; | ||
1089 | const struct GNUNET_SCALARPRODUCT_Element *elements; | ||
1090 | struct GNUNET_SETI_Element set_elem; | ||
1091 | struct GNUNET_SCALARPRODUCT_Element *elem; | ||
1092 | |||
1093 | contained_count = ntohl (msg->element_count_contained); | ||
1094 | elements = (const struct GNUNET_SCALARPRODUCT_Element *) &msg[1]; | ||
1095 | for (uint32_t i = 0; i < contained_count; i++) | ||
1096 | { | ||
1097 | elem = GNUNET_new (struct GNUNET_SCALARPRODUCT_Element); | ||
1098 | GNUNET_memcpy (elem, | ||
1099 | &elements[i], | ||
1100 | sizeof(struct GNUNET_SCALARPRODUCT_Element)); | ||
1101 | if (GNUNET_SYSERR == | ||
1102 | GNUNET_CONTAINER_multihashmap_put (s->intersected_elements, | ||
1103 | &elem->key, | ||
1104 | elem, | ||
1105 | GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY)) | ||
1106 | { | ||
1107 | GNUNET_break (0); | ||
1108 | GNUNET_free (elem); | ||
1109 | continue; | ||
1110 | } | ||
1111 | set_elem.data = &elem->key; | ||
1112 | set_elem.size = sizeof(elem->key); | ||
1113 | set_elem.element_type = 0; | ||
1114 | GNUNET_SETI_add_element (s->intersection_set, | ||
1115 | &set_elem, | ||
1116 | NULL, NULL); | ||
1117 | } | ||
1118 | s->client_received_element_count += contained_count; | ||
1119 | GNUNET_SERVICE_client_continue (s->client); | ||
1120 | if (s->total != s->client_received_element_count) | ||
1121 | { | ||
1122 | /* more to come */ | ||
1123 | return; | ||
1124 | } | ||
1125 | if (NULL == s->channel) | ||
1126 | { | ||
1127 | /* no Alice waiting for this request, wait for Alice */ | ||
1128 | return; | ||
1129 | } | ||
1130 | start_intersection (s); | ||
1131 | } | ||
1132 | |||
1133 | |||
1134 | /** | ||
1135 | * Handler for Bob's a client request message. Check @a msg is | ||
1136 | * well-formed. | ||
1137 | * | ||
1138 | * @param cls identification of the client | ||
1139 | * @param msg the actual message | ||
1140 | * @return #GNUNET_OK if @a msg is well-formed | ||
1141 | */ | ||
1142 | static int | ||
1143 | check_bob_client_message (void *cls, | ||
1144 | const struct BobComputationMessage *msg) | ||
1145 | { | ||
1146 | struct BobServiceSession *s = cls; | ||
1147 | uint32_t contained_count; | ||
1148 | uint32_t total_count; | ||
1149 | uint16_t msize; | ||
1150 | |||
1151 | if (GNUNET_SCALARPRODUCT_STATUS_INIT != s->status) | ||
1152 | { | ||
1153 | GNUNET_break (0); | ||
1154 | return GNUNET_SYSERR; | ||
1155 | } | ||
1156 | msize = ntohs (msg->header.size); | ||
1157 | total_count = ntohl (msg->element_count_total); | ||
1158 | contained_count = ntohl (msg->element_count_contained); | ||
1159 | if ((0 == total_count) || | ||
1160 | (0 == contained_count) || | ||
1161 | (UINT16_MAX < contained_count) || | ||
1162 | (msize != (sizeof(struct BobComputationMessage) | ||
1163 | + contained_count * sizeof(struct | ||
1164 | GNUNET_SCALARPRODUCT_Element)))) | ||
1165 | { | ||
1166 | GNUNET_break_op (0); | ||
1167 | return GNUNET_SYSERR; | ||
1168 | } | ||
1169 | return GNUNET_OK; | ||
1170 | } | ||
1171 | |||
1172 | |||
1173 | /** | ||
1174 | * Handler for Bob's a client request message. Bob is in the response | ||
1175 | * role, keep the values + session and waiting for a matching session | ||
1176 | * or process a waiting request from Alice. | ||
1177 | * | ||
1178 | * @param cls identification of the client | ||
1179 | * @param msg the actual message | ||
1180 | */ | ||
1181 | static void | ||
1182 | handle_bob_client_message (void *cls, | ||
1183 | const struct BobComputationMessage *msg) | ||
1184 | { | ||
1185 | struct BobServiceSession *s = cls; | ||
1186 | struct GNUNET_MQ_MessageHandler cadet_handlers[] = { | ||
1187 | GNUNET_MQ_hd_fixed_size (alices_computation_request, | ||
1188 | GNUNET_MESSAGE_TYPE_SCALARPRODUCT_SESSION_INITIALIZATION, | ||
1189 | struct ServiceRequestMessage, | ||
1190 | NULL), | ||
1191 | GNUNET_MQ_hd_var_size (alices_cryptodata_message, | ||
1192 | GNUNET_MESSAGE_TYPE_SCALARPRODUCT_ALICE_CRYPTODATA, | ||
1193 | struct AliceCryptodataMessage, | ||
1194 | NULL), | ||
1195 | GNUNET_MQ_handler_end () | ||
1196 | }; | ||
1197 | uint32_t contained_count; | ||
1198 | uint32_t total_count; | ||
1199 | const struct GNUNET_SCALARPRODUCT_Element *elements; | ||
1200 | struct GNUNET_SETI_Element set_elem; | ||
1201 | struct GNUNET_SCALARPRODUCT_Element *elem; | ||
1202 | |||
1203 | total_count = ntohl (msg->element_count_total); | ||
1204 | contained_count = ntohl (msg->element_count_contained); | ||
1205 | |||
1206 | s->status = GNUNET_SCALARPRODUCT_STATUS_ACTIVE; | ||
1207 | s->total = total_count; | ||
1208 | s->client_received_element_count = contained_count; | ||
1209 | s->session_id = msg->session_key; | ||
1210 | elements = (const struct GNUNET_SCALARPRODUCT_Element *) &msg[1]; | ||
1211 | s->intersected_elements | ||
1212 | = GNUNET_CONTAINER_multihashmap_create (s->total, | ||
1213 | GNUNET_YES); | ||
1214 | s->intersection_set = GNUNET_SETI_create (cfg); | ||
1215 | for (uint32_t i = 0; i < contained_count; i++) | ||
1216 | { | ||
1217 | if (0 == GNUNET_ntohll (elements[i].value)) | ||
1218 | continue; | ||
1219 | elem = GNUNET_new (struct GNUNET_SCALARPRODUCT_Element); | ||
1220 | GNUNET_memcpy (elem, | ||
1221 | &elements[i], | ||
1222 | sizeof(struct GNUNET_SCALARPRODUCT_Element)); | ||
1223 | if (GNUNET_SYSERR == | ||
1224 | GNUNET_CONTAINER_multihashmap_put (s->intersected_elements, | ||
1225 | &elem->key, | ||
1226 | elem, | ||
1227 | GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY)) | ||
1228 | { | ||
1229 | GNUNET_break (0); | ||
1230 | GNUNET_free (elem); | ||
1231 | continue; | ||
1232 | } | ||
1233 | set_elem.data = &elem->key; | ||
1234 | set_elem.size = sizeof(elem->key); | ||
1235 | set_elem.element_type = 0; | ||
1236 | GNUNET_SETI_add_element (s->intersection_set, | ||
1237 | &set_elem, | ||
1238 | NULL, NULL); | ||
1239 | s->used_element_count++; | ||
1240 | } | ||
1241 | GNUNET_SERVICE_client_continue (s->client); | ||
1242 | /* We're ready, open the port */ | ||
1243 | s->port = GNUNET_CADET_open_port (my_cadet, | ||
1244 | &msg->session_key, | ||
1245 | &cb_channel_incoming, | ||
1246 | s, | ||
1247 | NULL, | ||
1248 | &cb_channel_destruction, | ||
1249 | cadet_handlers); | ||
1250 | if (NULL == s->port) | ||
1251 | { | ||
1252 | GNUNET_break (0); | ||
1253 | GNUNET_SERVICE_client_drop (s->client); | ||
1254 | return; | ||
1255 | } | ||
1256 | } | ||
1257 | |||
1258 | |||
1259 | /** | ||
1260 | * Task run during shutdown. | ||
1261 | * | ||
1262 | * @param cls unused | ||
1263 | */ | ||
1264 | static void | ||
1265 | shutdown_task (void *cls) | ||
1266 | { | ||
1267 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
1268 | "Shutting down, initiating cleanup.\n"); | ||
1269 | // FIXME: we have to cut our connections to CADET first! | ||
1270 | if (NULL != my_cadet) | ||
1271 | { | ||
1272 | GNUNET_CADET_disconnect (my_cadet); | ||
1273 | my_cadet = NULL; | ||
1274 | } | ||
1275 | } | ||
1276 | |||
1277 | |||
1278 | /** | ||
1279 | * A client connected. | ||
1280 | * | ||
1281 | * Setup the associated data structure. | ||
1282 | * | ||
1283 | * @param cls closure, NULL | ||
1284 | * @param client identification of the client | ||
1285 | * @param mq message queue to communicate with @a client | ||
1286 | * @return our `struct BobServiceSession` | ||
1287 | */ | ||
1288 | static void * | ||
1289 | client_connect_cb (void *cls, | ||
1290 | struct GNUNET_SERVICE_Client *client, | ||
1291 | struct GNUNET_MQ_Handle *mq) | ||
1292 | { | ||
1293 | struct BobServiceSession *s; | ||
1294 | |||
1295 | s = GNUNET_new (struct BobServiceSession); | ||
1296 | s->client = client; | ||
1297 | s->client_mq = mq; | ||
1298 | return s; | ||
1299 | } | ||
1300 | |||
1301 | |||
1302 | /** | ||
1303 | * A client disconnected. | ||
1304 | * | ||
1305 | * Remove the associated session(s), release data structures | ||
1306 | * and cancel pending outgoing transmissions to the client. | ||
1307 | * | ||
1308 | * @param cls closure, NULL | ||
1309 | * @param client identification of the client | ||
1310 | * @param app_cls our `struct BobServiceSession` | ||
1311 | */ | ||
1312 | static void | ||
1313 | client_disconnect_cb (void *cls, | ||
1314 | struct GNUNET_SERVICE_Client *client, | ||
1315 | void *app_cls) | ||
1316 | { | ||
1317 | struct BobServiceSession *s = app_cls; | ||
1318 | |||
1319 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
1320 | "Client disconnected from us.\n"); | ||
1321 | s->client = NULL; | ||
1322 | destroy_service_session (s); | ||
1323 | } | ||
1324 | |||
1325 | |||
1326 | /** | ||
1327 | * Initialization of the program and message handlers | ||
1328 | * | ||
1329 | * @param cls closure | ||
1330 | * @param c configuration to use | ||
1331 | * @param service the initialized service | ||
1332 | */ | ||
1333 | static void | ||
1334 | run (void *cls, | ||
1335 | const struct GNUNET_CONFIGURATION_Handle *c, | ||
1336 | struct GNUNET_SERVICE_Handle *service) | ||
1337 | { | ||
1338 | cfg = c; | ||
1339 | /* | ||
1340 | offset has to be sufficiently small to allow computation of: | ||
1341 | m1+m2 mod n == (S + a) + (S + b) mod n, | ||
1342 | if we have more complex operations, this factor needs to be lowered */ | ||
1343 | my_offset = gcry_mpi_new (GNUNET_CRYPTO_PAILLIER_BITS / 3); | ||
1344 | gcry_mpi_set_bit (my_offset, | ||
1345 | GNUNET_CRYPTO_PAILLIER_BITS / 3); | ||
1346 | |||
1347 | GNUNET_CRYPTO_paillier_create (&my_pubkey, | ||
1348 | &my_privkey); | ||
1349 | my_cadet = GNUNET_CADET_connect (cfg); | ||
1350 | GNUNET_SCHEDULER_add_shutdown (&shutdown_task, | ||
1351 | NULL); | ||
1352 | if (NULL == my_cadet) | ||
1353 | { | ||
1354 | GNUNET_log (GNUNET_ERROR_TYPE_ERROR, | ||
1355 | _ ("Connect to CADET failed\n")); | ||
1356 | GNUNET_SCHEDULER_shutdown (); | ||
1357 | return; | ||
1358 | } | ||
1359 | } | ||
1360 | |||
1361 | |||
1362 | /** | ||
1363 | * Define "main" method using service macro. | ||
1364 | */ | ||
1365 | GNUNET_SERVICE_MAIN | ||
1366 | ("scalarproduct-bob", | ||
1367 | GNUNET_SERVICE_OPTION_NONE, | ||
1368 | &run, | ||
1369 | &client_connect_cb, | ||
1370 | &client_disconnect_cb, | ||
1371 | NULL, | ||
1372 | GNUNET_MQ_hd_var_size (bob_client_message, | ||
1373 | GNUNET_MESSAGE_TYPE_SCALARPRODUCT_CLIENT_TO_BOB, | ||
1374 | struct BobComputationMessage, | ||
1375 | NULL), | ||
1376 | GNUNET_MQ_hd_var_size (bob_client_message_multipart, | ||
1377 | GNUNET_MESSAGE_TYPE_SCALARPRODUCT_CLIENT_MULTIPART_BOB, | ||
1378 | struct ComputationBobCryptodataMultipartMessage, | ||
1379 | NULL), | ||
1380 | GNUNET_MQ_handler_end ()); | ||
1381 | |||
1382 | |||
1383 | /* end of gnunet-service-scalarproduct_bob.c */ | ||
diff --git a/src/scalarproduct/perf_scalarproduct.sh b/src/scalarproduct/perf_scalarproduct.sh deleted file mode 100755 index b15465c9a..000000000 --- a/src/scalarproduct/perf_scalarproduct.sh +++ /dev/null | |||
@@ -1,73 +0,0 @@ | |||
1 | #!/bin/bash | ||
2 | # Computes a simple scalar product, with configurable vector size. | ||
3 | # | ||
4 | # Some results (wall-clock for Alice+Bob, single-core, i7, libgcrypt): | ||
5 | # SIZE 2048-H(s) 2048-O(s) 1024-O(s) ECC-2^20-H(s) ECC-2^28-H(s) | ||
6 | # 25 10 14 3 2 29 | ||
7 | # 50 17 21 5 2 29 | ||
8 | # 100 32 39 7 2 29 | ||
9 | # 200 77 13 3 30 | ||
10 | # 400 149 23 OOR 31 | ||
11 | # 800 304 32 OOR 33 | ||
12 | |||
13 | # Bandwidth (including set intersection): | ||
14 | # RSA-1024 RSA-2048 ECC | ||
15 | # 800: 629 kb 1234 kb 65 kb | ||
16 | # | ||
17 | # LIBSODIUM, AMD Threadripper 1950: | ||
18 | # | ||
19 | # SIZE 2048-O(s) 1024-O(s) ECC-2^20-H(s) ECC-2^28-H(s) | ||
20 | # 25 4.3 0.7 0.129 4.233 | ||
21 | # 50 7.7 1.2 0.143 4.267 | ||
22 | # 100 10.3 2.4 0.163 4.282 | ||
23 | # 200 19.8 3.0 0.192 4.326 | ||
24 | # 400 35.9 6.0 0.253 4.358 | ||
25 | # 800 73.7 12.6 0.379 4.533 | ||
26 | |||
27 | # | ||
28 | # | ||
29 | # Configure benchmark size: | ||
30 | SIZE=800 | ||
31 | # | ||
32 | # Construct input vectors: | ||
33 | INPUTALICE="-k CCC -e '" | ||
34 | INPUTBOB="-k CCC -e '" | ||
35 | for X in `seq 1 $SIZE` | ||
36 | do | ||
37 | INPUTALICE="${INPUTALICE}A${X},$X;" | ||
38 | INPUTBOB="${INPUTBOB}A${X},$X;" | ||
39 | done | ||
40 | INPUTALICE="${INPUTALICE}BC,-20000;RO,1000;FL,100;LOL,24;'" | ||
41 | INPUTBOB="${INPUTBOB}AB,10;RO,3;FL,3;LOL,-1;'" | ||
42 | |||
43 | # necessary to make the testing prefix deterministic, so we can access the config files | ||
44 | PREFIX=/tmp/test-scalarproduct`date +%H%M%S` | ||
45 | |||
46 | # where can we find the peers config files? | ||
47 | CFGALICE="-c $PREFIX/0/config" | ||
48 | CFGBOB="-c $PREFIX/1/config" | ||
49 | |||
50 | # launch two peers in line topology non-interactively | ||
51 | # | ||
52 | # interactive mode would terminate the test immediately | ||
53 | # because the rest of the script is already in stdin, | ||
54 | # thus redirecting stdin does not suffice) | ||
55 | #GNUNET_FORCE_LOG=';;;;ERROR' | ||
56 | #GNUNET_FORCE_LOG='scalarproduct*;;;;DEBUG/cadet-api*;;;;DEBUG' | ||
57 | GNUNET_TESTING_PREFIX=$PREFIX ../testbed/gnunet-testbed-profiler -n -c test_scalarproduct.conf -p 2 & | ||
58 | PID=$! | ||
59 | # sleep 1 is too short on most systems, 2 works on most, 5 seems to be safe | ||
60 | echo "Waiting for peers to start..." | ||
61 | sleep 5 | ||
62 | # get Bob's peer ID, necessary for Alice | ||
63 | PEERIDBOB=`gnunet-peerinfo -qs $CFGBOB` | ||
64 | |||
65 | echo "Running problem of size $SIZE" | ||
66 | gnunet-scalarproduct $CFGBOB $INPUTBOB & | ||
67 | time RESULT=`gnunet-scalarproduct $CFGALICE $INPUTALICE -p $PEERIDBOB` | ||
68 | gnunet-statistics $CFGALICE -s core | grep "bytes encrypted" | ||
69 | gnunet-statistics $CFGBOB -s core | grep "bytes encrypted" | ||
70 | |||
71 | echo "Terminating testbed..." | ||
72 | # terminate the testbed | ||
73 | kill $PID | ||
diff --git a/src/scalarproduct/scalarproduct.conf.in b/src/scalarproduct/scalarproduct.conf.in deleted file mode 100644 index e2286b076..000000000 --- a/src/scalarproduct/scalarproduct.conf.in +++ /dev/null | |||
@@ -1,27 +0,0 @@ | |||
1 | [scalarproduct-alice] | ||
2 | START_ON_DEMAND = @START_ON_DEMAND@ | ||
3 | BINARY = gnunet-service-scalarproduct-ecc-alice | ||
4 | UNIXPATH = $GNUNET_RUNTIME_DIR/gnunet-service-scalarproduct-alice.sock | ||
5 | @UNIXONLY@ PORT = 2117 | ||
6 | #ACCEPT_FROM = 127.0.0.1; | ||
7 | #ACCEPT_FROM6 = ::1; | ||
8 | UNIX_MATCH_UID = NO | ||
9 | UNIX_MATCH_GID = YES | ||
10 | #OPTIONS = -L DEBUG | ||
11 | #PREFIX = valgrind | ||
12 | |||
13 | |||
14 | [scalarproduct-bob] | ||
15 | START_ON_DEMAND = @START_ON_DEMAND@ | ||
16 | HOSTNAME = localhost | ||
17 | BINARY = gnunet-service-scalarproduct-ecc-bob | ||
18 | UNIXPATH = $GNUNET_RUNTIME_DIR/gnunet-service-scalarproduct-bob.sock | ||
19 | @UNIXONLY@ PORT = 2118 | ||
20 | |||
21 | #ACCEPT_FROM = 127.0.0.1; | ||
22 | #ACCEPT_FROM6 = ::1; | ||
23 | UNIX_MATCH_UID = NO | ||
24 | UNIX_MATCH_GID = YES | ||
25 | #OPTIONS = -L DEBUG | ||
26 | |||
27 | #PREFIX = valgrind | ||
diff --git a/src/scalarproduct/scalarproduct.h b/src/scalarproduct/scalarproduct.h deleted file mode 100644 index f2311cda0..000000000 --- a/src/scalarproduct/scalarproduct.h +++ /dev/null | |||
@@ -1,177 +0,0 @@ | |||
1 | /* | ||
2 | This file is part of GNUnet. | ||
3 | Copyright (C) 2009, 2010, 2011, 2012, 2013 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.h | ||
22 | * @brief Scalar Product API Message Types | ||
23 | * @author Christian M. Fuchs | ||
24 | */ | ||
25 | #ifndef SCALARPRODUCT_H | ||
26 | #define SCALARPRODUCT_H | ||
27 | |||
28 | GNUNET_NETWORK_STRUCT_BEGIN | ||
29 | |||
30 | /** | ||
31 | * Log an error message at log-level 'level' that indicates | ||
32 | * a failure of the command 'cmd' with the message given | ||
33 | * by gcry_strerror(rc). | ||
34 | */ | ||
35 | #define LOG_GCRY(level, cmd, rc) do { LOG (level, _ ( \ | ||
36 | "`%s' failed at %s:%d with error: %s\n"), \ | ||
37 | cmd, __FILE__, __LINE__, \ | ||
38 | gcry_strerror (rc)); } while (0) | ||
39 | |||
40 | |||
41 | /** | ||
42 | * Message type passed from client to service | ||
43 | * to initiate a request or responder role | ||
44 | */ | ||
45 | struct AliceComputationMessage | ||
46 | { | ||
47 | /** | ||
48 | * GNUNET message header with type | ||
49 | * #GNUNET_MESSAGE_TYPE_SCALARPRODUCT_CLIENT_TO_ALICE | ||
50 | */ | ||
51 | struct GNUNET_MessageHeader header; | ||
52 | |||
53 | /** | ||
54 | * how many elements the vector in payload contains | ||
55 | */ | ||
56 | uint32_t element_count_total GNUNET_PACKED; | ||
57 | |||
58 | /** | ||
59 | * contained elements the vector in payload contains | ||
60 | */ | ||
61 | uint32_t element_count_contained GNUNET_PACKED; | ||
62 | |||
63 | /** | ||
64 | * Always zero. | ||
65 | */ | ||
66 | uint32_t reserved GNUNET_PACKED; | ||
67 | |||
68 | /** | ||
69 | * the transaction/session key used to identify a session | ||
70 | */ | ||
71 | struct GNUNET_HashCode session_key; | ||
72 | |||
73 | /** | ||
74 | * the identity of a remote peer we want to communicate with | ||
75 | */ | ||
76 | struct GNUNET_PeerIdentity peer; | ||
77 | |||
78 | /** | ||
79 | * followed by struct GNUNET_SCALARPRODUCT_Element[] | ||
80 | */ | ||
81 | }; | ||
82 | |||
83 | |||
84 | /** | ||
85 | * Message type passed from client to service | ||
86 | * to initiate a request or responder role | ||
87 | */ | ||
88 | struct BobComputationMessage | ||
89 | { | ||
90 | /** | ||
91 | * GNUNET message header with type | ||
92 | * #GNUNET_MESSAGE_TYPE_SCALARPRODUCT_CLIENT_TO_BOB | ||
93 | */ | ||
94 | struct GNUNET_MessageHeader header; | ||
95 | |||
96 | /** | ||
97 | * how many elements the vector in payload contains | ||
98 | */ | ||
99 | uint32_t element_count_total GNUNET_PACKED; | ||
100 | |||
101 | /** | ||
102 | * contained elements the vector in payload contains | ||
103 | */ | ||
104 | uint32_t element_count_contained GNUNET_PACKED; | ||
105 | |||
106 | /** | ||
107 | * Always zero. | ||
108 | */ | ||
109 | uint32_t reserved GNUNET_PACKED; | ||
110 | |||
111 | /** | ||
112 | * the transaction/session key used to identify a session | ||
113 | */ | ||
114 | struct GNUNET_HashCode session_key; | ||
115 | |||
116 | /** | ||
117 | * followed by struct GNUNET_SCALARPRODUCT_Element[] | ||
118 | */ | ||
119 | }; | ||
120 | |||
121 | |||
122 | /** | ||
123 | * multipart messages following `struct ComputationMessage` | ||
124 | */ | ||
125 | struct ComputationBobCryptodataMultipartMessage | ||
126 | { | ||
127 | /** | ||
128 | * GNUNET message header | ||
129 | */ | ||
130 | struct GNUNET_MessageHeader header; | ||
131 | |||
132 | /** | ||
133 | * contained elements the vector in payload contains | ||
134 | */ | ||
135 | uint32_t element_count_contained GNUNET_PACKED; | ||
136 | |||
137 | /** | ||
138 | * followed by struct GNUNET_SCALARPRODUCT_Element[] | ||
139 | */ | ||
140 | }; | ||
141 | |||
142 | |||
143 | /** | ||
144 | * Message type passed from service client | ||
145 | * to finalize a session as requester or responder | ||
146 | */ | ||
147 | struct ClientResponseMessage | ||
148 | { | ||
149 | /** | ||
150 | * GNUNET message header | ||
151 | */ | ||
152 | struct GNUNET_MessageHeader header; | ||
153 | |||
154 | /** | ||
155 | * 0 if no product attached | ||
156 | */ | ||
157 | uint32_t product_length GNUNET_PACKED; | ||
158 | |||
159 | /** | ||
160 | * Status information about the outcome of this session, | ||
161 | * An `enum GNUNET_SCALARPRODUCT_ResponseStatus` (in NBO). | ||
162 | */ | ||
163 | uint32_t status GNUNET_PACKED; | ||
164 | |||
165 | /** | ||
166 | * Workaround for libgcrypt: -1 if negative, 0 if zero, else 1 | ||
167 | */ | ||
168 | int32_t range GNUNET_PACKED; | ||
169 | |||
170 | /** | ||
171 | * followed by product of length product_length (or nothing) | ||
172 | */ | ||
173 | }; | ||
174 | |||
175 | GNUNET_NETWORK_STRUCT_END | ||
176 | |||
177 | #endif /* SCALARPRODUCT_H */ | ||
diff --git a/src/scalarproduct/scalarproduct_api.c b/src/scalarproduct/scalarproduct_api.c deleted file mode 100644 index 44d6bd812..000000000 --- a/src/scalarproduct/scalarproduct_api.c +++ /dev/null | |||
@@ -1,491 +0,0 @@ | |||
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/scalarproduct_api.c | ||
22 | * @brief API for the scalarproduct | ||
23 | * @author Christian Fuchs | ||
24 | * @author Gaurav Kukreja | ||
25 | * @author Christian Grothoff | ||
26 | */ | ||
27 | #include "platform.h" | ||
28 | #include "gnunet_util_lib.h" | ||
29 | #include "gnunet_statistics_service.h" | ||
30 | #include "gnunet_scalarproduct_service.h" | ||
31 | #include "gnunet_protocols.h" | ||
32 | #include "scalarproduct.h" | ||
33 | |||
34 | #define LOG(kind, ...) GNUNET_log_from (kind, "scalarproduct-api", __VA_ARGS__) | ||
35 | |||
36 | |||
37 | /** | ||
38 | * The abstraction function for our internal callback | ||
39 | * | ||
40 | * @param h computation handle | ||
41 | * @param msg response we got, NULL on errors | ||
42 | * @param status processing status code | ||
43 | */ | ||
44 | typedef void | ||
45 | (*GNUNET_SCALARPRODUCT_ResponseMessageHandler) ( | ||
46 | struct GNUNET_SCALARPRODUCT_ComputationHandle *h, | ||
47 | const struct ClientResponseMessage *msg, | ||
48 | enum GNUNET_SCALARPRODUCT_ResponseStatus status); | ||
49 | |||
50 | |||
51 | /** | ||
52 | * A handle returned for each computation | ||
53 | */ | ||
54 | struct GNUNET_SCALARPRODUCT_ComputationHandle | ||
55 | { | ||
56 | /** | ||
57 | * Our configuration. | ||
58 | */ | ||
59 | const struct GNUNET_CONFIGURATION_Handle *cfg; | ||
60 | |||
61 | /** | ||
62 | * Current connection to the scalarproduct service. | ||
63 | */ | ||
64 | struct GNUNET_MQ_Handle *mq; | ||
65 | |||
66 | /** | ||
67 | * Function to call after transmission of the request (Bob). | ||
68 | */ | ||
69 | GNUNET_SCALARPRODUCT_ContinuationWithStatus cont_status; | ||
70 | |||
71 | /** | ||
72 | * Function to call after transmission of the request (Alice). | ||
73 | */ | ||
74 | GNUNET_SCALARPRODUCT_DatumProcessor cont_datum; | ||
75 | |||
76 | /** | ||
77 | * Closure for @e cont_status or @e cont_datum. | ||
78 | */ | ||
79 | void *cont_cls; | ||
80 | |||
81 | /** | ||
82 | * API internal callback for results and failures to be forwarded to | ||
83 | * the client. | ||
84 | */ | ||
85 | GNUNET_SCALARPRODUCT_ResponseMessageHandler response_proc; | ||
86 | |||
87 | /** | ||
88 | * The shared session key identifying this computation | ||
89 | */ | ||
90 | struct GNUNET_HashCode key; | ||
91 | }; | ||
92 | |||
93 | |||
94 | /** | ||
95 | * Called when a response is received from the service. Perform basic | ||
96 | * check that the message is well-formed. | ||
97 | * | ||
98 | * @param cls Pointer to the Master Context | ||
99 | * @param message Pointer to the data received in response | ||
100 | * @return #GNUNET_OK if @a message is well-formed | ||
101 | */ | ||
102 | static int | ||
103 | check_response (void *cls, | ||
104 | const struct ClientResponseMessage *message) | ||
105 | { | ||
106 | if (ntohs (message->header.size) != | ||
107 | ntohl (message->product_length) + sizeof(struct ClientResponseMessage)) | ||
108 | { | ||
109 | GNUNET_break (0); | ||
110 | return GNUNET_SYSERR; | ||
111 | } | ||
112 | return GNUNET_OK; | ||
113 | } | ||
114 | |||
115 | |||
116 | /** | ||
117 | * Handles the STATUS received from the service for a response, does | ||
118 | * not contain a payload. Called when we participate as "Bob" via | ||
119 | * #GNUNET_SCALARPRODUCT_accept_computation(). | ||
120 | * | ||
121 | * @param h our Handle | ||
122 | * @param msg the response received | ||
123 | * @param status the condition the request was terminated with (eg: disconnect) | ||
124 | */ | ||
125 | static void | ||
126 | process_status_message (struct GNUNET_SCALARPRODUCT_ComputationHandle *h, | ||
127 | const struct ClientResponseMessage *msg, | ||
128 | enum GNUNET_SCALARPRODUCT_ResponseStatus status) | ||
129 | { | ||
130 | if (NULL != h->cont_status) | ||
131 | h->cont_status (h->cont_cls, | ||
132 | status); | ||
133 | GNUNET_SCALARPRODUCT_cancel (h); | ||
134 | } | ||
135 | |||
136 | |||
137 | /** | ||
138 | * Called when a response is received from the service. After basic | ||
139 | * check, the handler in `h->response_proc` is called. This functions | ||
140 | * handles the response to the client which used the API. | ||
141 | * | ||
142 | * @param cls Pointer to the Master Context | ||
143 | * @param msg Pointer to the data received in response | ||
144 | */ | ||
145 | static void | ||
146 | handle_response (void *cls, | ||
147 | const struct ClientResponseMessage *message) | ||
148 | { | ||
149 | struct GNUNET_SCALARPRODUCT_ComputationHandle *h = cls; | ||
150 | enum GNUNET_SCALARPRODUCT_ResponseStatus status; | ||
151 | |||
152 | status = (enum GNUNET_SCALARPRODUCT_ResponseStatus) ntohl (message->status); | ||
153 | h->response_proc (h, | ||
154 | message, | ||
155 | status); | ||
156 | } | ||
157 | |||
158 | |||
159 | /** | ||
160 | * Check if the keys for all given elements are unique. | ||
161 | * | ||
162 | * @param elements elements to check | ||
163 | * @param element_count size of the @a elements array | ||
164 | * @return #GNUNET_OK if all keys are unique | ||
165 | */ | ||
166 | static int | ||
167 | check_unique (const struct GNUNET_SCALARPRODUCT_Element *elements, | ||
168 | uint32_t element_count) | ||
169 | { | ||
170 | struct GNUNET_CONTAINER_MultiHashMap *map; | ||
171 | int ok; | ||
172 | |||
173 | ok = GNUNET_OK; | ||
174 | map = GNUNET_CONTAINER_multihashmap_create (2 * element_count, | ||
175 | GNUNET_YES); | ||
176 | for (uint32_t i = 0; i < element_count; i++) | ||
177 | if (GNUNET_OK != | ||
178 | GNUNET_CONTAINER_multihashmap_put (map, | ||
179 | &elements[i].key, | ||
180 | map, | ||
181 | GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY)) | ||
182 | { | ||
183 | GNUNET_log (GNUNET_ERROR_TYPE_ERROR, | ||
184 | _ ("Keys given to SCALARPRODUCT not unique!\n")); | ||
185 | ok = GNUNET_SYSERR; | ||
186 | } | ||
187 | GNUNET_CONTAINER_multihashmap_destroy (map); | ||
188 | return ok; | ||
189 | } | ||
190 | |||
191 | |||
192 | /** | ||
193 | * We encountered an error communicating with the set service while | ||
194 | * performing a set operation. Report to the application. | ||
195 | * | ||
196 | * @param cls the `struct GNUNET_SCALARPRODUCT_ComputationHandle` | ||
197 | * @param error error code | ||
198 | */ | ||
199 | static void | ||
200 | mq_error_handler (void *cls, | ||
201 | enum GNUNET_MQ_Error error) | ||
202 | { | ||
203 | struct GNUNET_SCALARPRODUCT_ComputationHandle *h = cls; | ||
204 | |||
205 | LOG (GNUNET_ERROR_TYPE_INFO, | ||
206 | "Disconnected from SCALARPRODUCT service.\n"); | ||
207 | h->response_proc (h, | ||
208 | NULL, | ||
209 | GNUNET_SCALARPRODUCT_STATUS_DISCONNECTED); | ||
210 | } | ||
211 | |||
212 | |||
213 | /** | ||
214 | * Used by Bob's client to cooperate with Alice, | ||
215 | * | ||
216 | * @param cfg the gnunet configuration handle | ||
217 | * @param key Session key unique to the requesting client | ||
218 | * @param elements Array of elements of the vector | ||
219 | * @param element_count Number of elements in the @a elements vector | ||
220 | * @param cont Callback function | ||
221 | * @param cont_cls Closure for @a cont | ||
222 | * @return a new handle for this computation | ||
223 | */ | ||
224 | struct GNUNET_SCALARPRODUCT_ComputationHandle * | ||
225 | GNUNET_SCALARPRODUCT_accept_computation ( | ||
226 | const struct GNUNET_CONFIGURATION_Handle *cfg, | ||
227 | const struct GNUNET_HashCode *session_key, | ||
228 | const struct GNUNET_SCALARPRODUCT_Element *elements, | ||
229 | uint32_t element_count, | ||
230 | GNUNET_SCALARPRODUCT_ContinuationWithStatus cont, | ||
231 | void *cont_cls) | ||
232 | { | ||
233 | struct GNUNET_SCALARPRODUCT_ComputationHandle *h | ||
234 | = GNUNET_new (struct GNUNET_SCALARPRODUCT_ComputationHandle); | ||
235 | struct GNUNET_MQ_MessageHandler handlers[] = { | ||
236 | GNUNET_MQ_hd_var_size (response, | ||
237 | GNUNET_MESSAGE_TYPE_SCALARPRODUCT_RESULT, | ||
238 | struct ClientResponseMessage, | ||
239 | h), | ||
240 | GNUNET_MQ_handler_end () | ||
241 | }; | ||
242 | struct GNUNET_MQ_Envelope *env; | ||
243 | struct BobComputationMessage *msg; | ||
244 | struct ComputationBobCryptodataMultipartMessage *mmsg; | ||
245 | uint32_t size; | ||
246 | uint16_t possible; | ||
247 | uint16_t todo; | ||
248 | uint32_t element_count_transfered; | ||
249 | |||
250 | |||
251 | if (GNUNET_SYSERR == check_unique (elements, | ||
252 | element_count)) | ||
253 | return NULL; | ||
254 | h->cont_status = cont; | ||
255 | h->cont_cls = cont_cls; | ||
256 | h->response_proc = &process_status_message; | ||
257 | h->cfg = cfg; | ||
258 | h->key = *session_key; | ||
259 | h->mq = GNUNET_CLIENT_connect (cfg, | ||
260 | "scalarproduct-bob", | ||
261 | handlers, | ||
262 | &mq_error_handler, | ||
263 | h); | ||
264 | if (NULL == h->mq) | ||
265 | { | ||
266 | /* scalarproduct configuration error */ | ||
267 | GNUNET_break (0); | ||
268 | GNUNET_free (h); | ||
269 | return NULL; | ||
270 | } | ||
271 | possible = (GNUNET_MAX_MESSAGE_SIZE - 1 - sizeof(struct | ||
272 | BobComputationMessage)) | ||
273 | / sizeof(struct GNUNET_SCALARPRODUCT_Element); | ||
274 | todo = GNUNET_MIN (possible, | ||
275 | element_count); | ||
276 | size = todo * sizeof(struct GNUNET_SCALARPRODUCT_Element); | ||
277 | env = GNUNET_MQ_msg_extra (msg, | ||
278 | size, | ||
279 | GNUNET_MESSAGE_TYPE_SCALARPRODUCT_CLIENT_TO_BOB); | ||
280 | msg->element_count_total = htonl (element_count); | ||
281 | msg->element_count_contained = htonl (todo); | ||
282 | msg->session_key = *session_key; | ||
283 | GNUNET_memcpy (&msg[1], | ||
284 | elements, | ||
285 | size); | ||
286 | element_count_transfered = todo; | ||
287 | GNUNET_MQ_send (h->mq, | ||
288 | env); | ||
289 | possible = (GNUNET_MAX_MESSAGE_SIZE - 1 - sizeof(*mmsg)) | ||
290 | / sizeof(struct GNUNET_SCALARPRODUCT_Element); | ||
291 | while (element_count_transfered < element_count) | ||
292 | { | ||
293 | todo = GNUNET_MIN (possible, | ||
294 | element_count - element_count_transfered); | ||
295 | size = todo * sizeof(struct GNUNET_SCALARPRODUCT_Element); | ||
296 | env = GNUNET_MQ_msg_extra (mmsg, | ||
297 | size, | ||
298 | GNUNET_MESSAGE_TYPE_SCALARPRODUCT_CLIENT_MULTIPART_BOB); | ||
299 | mmsg->element_count_contained = htonl (todo); | ||
300 | GNUNET_memcpy (&mmsg[1], | ||
301 | &elements[element_count_transfered], | ||
302 | size); | ||
303 | element_count_transfered += todo; | ||
304 | GNUNET_MQ_send (h->mq, | ||
305 | env); | ||
306 | } | ||
307 | return h; | ||
308 | } | ||
309 | |||
310 | |||
311 | /** | ||
312 | * Handles the RESULT received from the service for a request, should | ||
313 | * contain a result MPI value. Called when we participate as "Alice" via | ||
314 | * #GNUNET_SCALARPRODUCT_start_computation(). | ||
315 | * | ||
316 | * @param h our Handle | ||
317 | * @param msg Pointer to the response received | ||
318 | * @param status the condition the request was terminated with (eg: disconnect) | ||
319 | */ | ||
320 | static void | ||
321 | process_result_message (struct GNUNET_SCALARPRODUCT_ComputationHandle *h, | ||
322 | const struct ClientResponseMessage *msg, | ||
323 | enum GNUNET_SCALARPRODUCT_ResponseStatus status) | ||
324 | { | ||
325 | uint32_t product_len; | ||
326 | gcry_mpi_t result = NULL; | ||
327 | gcry_error_t rc; | ||
328 | gcry_mpi_t num; | ||
329 | size_t rsize; | ||
330 | |||
331 | if (GNUNET_SCALARPRODUCT_STATUS_SUCCESS == status) | ||
332 | { | ||
333 | result = gcry_mpi_new (0); | ||
334 | |||
335 | product_len = ntohl (msg->product_length); | ||
336 | if (0 < product_len) | ||
337 | { | ||
338 | rsize = 0; | ||
339 | if (0 != (rc = gcry_mpi_scan (&num, GCRYMPI_FMT_STD, | ||
340 | &msg[1], | ||
341 | product_len, | ||
342 | &rsize))) | ||
343 | { | ||
344 | LOG_GCRY (GNUNET_ERROR_TYPE_ERROR, | ||
345 | "gcry_mpi_scan", | ||
346 | rc); | ||
347 | gcry_mpi_release (result); | ||
348 | result = NULL; | ||
349 | status = GNUNET_SCALARPRODUCT_STATUS_INVALID_RESPONSE; | ||
350 | } | ||
351 | else | ||
352 | { | ||
353 | if (0 < (int32_t) ntohl (msg->range)) | ||
354 | gcry_mpi_add (result, result, num); | ||
355 | else | ||
356 | gcry_mpi_sub (result, result, num); | ||
357 | gcry_mpi_release (num); | ||
358 | } | ||
359 | } | ||
360 | } | ||
361 | if (NULL != h->cont_datum) | ||
362 | h->cont_datum (h->cont_cls, | ||
363 | status, | ||
364 | result); | ||
365 | if (NULL != result) | ||
366 | gcry_mpi_release (result); | ||
367 | GNUNET_SCALARPRODUCT_cancel (h); | ||
368 | } | ||
369 | |||
370 | |||
371 | /** | ||
372 | * Request by Alice's client for computing a scalar product | ||
373 | * | ||
374 | * @param cfg the gnunet configuration handle | ||
375 | * @param session_key Session key should be unique to the requesting client | ||
376 | * @param peer PeerID of the other peer | ||
377 | * @param elements Array of elements of the vector | ||
378 | * @param element_count Number of elements in the @a elements vector | ||
379 | * @param cont Callback function | ||
380 | * @param cont_cls Closure for @a cont | ||
381 | * @return a new handle for this computation | ||
382 | */ | ||
383 | struct GNUNET_SCALARPRODUCT_ComputationHandle * | ||
384 | GNUNET_SCALARPRODUCT_start_computation ( | ||
385 | const struct GNUNET_CONFIGURATION_Handle *cfg, | ||
386 | const struct GNUNET_HashCode *session_key, | ||
387 | const struct GNUNET_PeerIdentity *peer, | ||
388 | const struct GNUNET_SCALARPRODUCT_Element *elements, | ||
389 | uint32_t element_count, | ||
390 | GNUNET_SCALARPRODUCT_DatumProcessor cont, | ||
391 | void *cont_cls) | ||
392 | { | ||
393 | struct GNUNET_SCALARPRODUCT_ComputationHandle *h | ||
394 | = GNUNET_new (struct GNUNET_SCALARPRODUCT_ComputationHandle); | ||
395 | struct GNUNET_MQ_MessageHandler handlers[] = { | ||
396 | GNUNET_MQ_hd_var_size (response, | ||
397 | GNUNET_MESSAGE_TYPE_SCALARPRODUCT_RESULT, | ||
398 | struct ClientResponseMessage, | ||
399 | h), | ||
400 | GNUNET_MQ_handler_end () | ||
401 | }; | ||
402 | struct GNUNET_MQ_Envelope *env; | ||
403 | struct AliceComputationMessage *msg; | ||
404 | struct ComputationBobCryptodataMultipartMessage *mmsg; | ||
405 | uint32_t size; | ||
406 | uint16_t possible; | ||
407 | uint16_t todo; | ||
408 | uint32_t element_count_transfered; | ||
409 | |||
410 | if (GNUNET_SYSERR == check_unique (elements, | ||
411 | element_count)) | ||
412 | return NULL; | ||
413 | h->mq = GNUNET_CLIENT_connect (cfg, | ||
414 | "scalarproduct-alice", | ||
415 | handlers, | ||
416 | &mq_error_handler, | ||
417 | h); | ||
418 | if (NULL == h->mq) | ||
419 | { | ||
420 | /* misconfigured scalarproduct service */ | ||
421 | GNUNET_break (0); | ||
422 | GNUNET_free (h); | ||
423 | return NULL; | ||
424 | } | ||
425 | h->cont_datum = cont; | ||
426 | h->cont_cls = cont_cls; | ||
427 | h->response_proc = &process_result_message; | ||
428 | h->cfg = cfg; | ||
429 | h->key = *session_key; | ||
430 | |||
431 | possible = (GNUNET_MAX_MESSAGE_SIZE - 1 - sizeof(struct | ||
432 | AliceComputationMessage)) | ||
433 | / sizeof(struct GNUNET_SCALARPRODUCT_Element); | ||
434 | todo = GNUNET_MIN (possible, | ||
435 | element_count); | ||
436 | size = todo * sizeof(struct GNUNET_SCALARPRODUCT_Element); | ||
437 | env = GNUNET_MQ_msg_extra (msg, | ||
438 | size, | ||
439 | GNUNET_MESSAGE_TYPE_SCALARPRODUCT_CLIENT_TO_ALICE); | ||
440 | msg->element_count_total = htonl (element_count); | ||
441 | msg->element_count_contained = htonl (todo); | ||
442 | msg->reserved = htonl (0); | ||
443 | msg->peer = *peer; | ||
444 | msg->session_key = *session_key; | ||
445 | GNUNET_memcpy (&msg[1], | ||
446 | elements, | ||
447 | size); | ||
448 | GNUNET_MQ_send (h->mq, | ||
449 | env); | ||
450 | element_count_transfered = todo; | ||
451 | possible = (GNUNET_MAX_MESSAGE_SIZE - 1 - sizeof(*mmsg)) | ||
452 | / sizeof(struct GNUNET_SCALARPRODUCT_Element); | ||
453 | while (element_count_transfered < element_count) | ||
454 | { | ||
455 | todo = GNUNET_MIN (possible, | ||
456 | element_count - element_count_transfered); | ||
457 | size = todo * sizeof(struct GNUNET_SCALARPRODUCT_Element); | ||
458 | env = GNUNET_MQ_msg_extra (mmsg, | ||
459 | size, | ||
460 | GNUNET_MESSAGE_TYPE_SCALARPRODUCT_CLIENT_MULTIPART_ALICE); | ||
461 | mmsg->element_count_contained = htonl (todo); | ||
462 | GNUNET_memcpy (&mmsg[1], | ||
463 | &elements[element_count_transfered], | ||
464 | size); | ||
465 | element_count_transfered += todo; | ||
466 | GNUNET_MQ_send (h->mq, | ||
467 | env); | ||
468 | } | ||
469 | return h; | ||
470 | } | ||
471 | |||
472 | |||
473 | /** | ||
474 | * Cancel an ongoing computation or revoke our collaboration offer. | ||
475 | * Closes the connection to the service | ||
476 | * | ||
477 | * @param h computation handle to terminate | ||
478 | */ | ||
479 | void | ||
480 | GNUNET_SCALARPRODUCT_cancel (struct GNUNET_SCALARPRODUCT_ComputationHandle *h) | ||
481 | { | ||
482 | if (NULL != h->mq) | ||
483 | { | ||
484 | GNUNET_MQ_destroy (h->mq); | ||
485 | h->mq = NULL; | ||
486 | } | ||
487 | GNUNET_free (h); | ||
488 | } | ||
489 | |||
490 | |||
491 | /* end of scalarproduct_api.c */ | ||
diff --git a/src/scalarproduct/test_ecc_scalarproduct.c b/src/scalarproduct/test_ecc_scalarproduct.c deleted file mode 100644 index 85460cb05..000000000 --- a/src/scalarproduct/test_ecc_scalarproduct.c +++ /dev/null | |||
@@ -1,212 +0,0 @@ | |||
1 | /* | ||
2 | This file is part of GNUnet. | ||
3 | Copyright (C) 2015 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 | /** | ||
22 | * @file util/test_ecc_scalarproduct.c | ||
23 | * @brief testcase for math behind ECC SP calculation | ||
24 | * @author Christian Grothoff | ||
25 | */ | ||
26 | #include "platform.h" | ||
27 | #include "gnunet_util_lib.h" | ||
28 | #include <gcrypt.h> | ||
29 | |||
30 | /** | ||
31 | * Global context. | ||
32 | */ | ||
33 | static struct GNUNET_CRYPTO_EccDlogContext *edc; | ||
34 | |||
35 | |||
36 | /** | ||
37 | * Perform SP calculation. | ||
38 | * | ||
39 | * @param avec 0-terminated vector of Alice's values | ||
40 | * @param bvec 0-terminated vector of Bob's values | ||
41 | * @return avec * bvec | ||
42 | */ | ||
43 | static int | ||
44 | test_sp (const unsigned int *avec, | ||
45 | const unsigned int *bvec) | ||
46 | { | ||
47 | unsigned int len; | ||
48 | struct GNUNET_CRYPTO_EccScalar a; | ||
49 | struct GNUNET_CRYPTO_EccScalar a_neg; | ||
50 | struct GNUNET_CRYPTO_EccPoint *g; | ||
51 | struct GNUNET_CRYPTO_EccPoint *h; | ||
52 | struct GNUNET_CRYPTO_EccPoint pg; | ||
53 | struct GNUNET_CRYPTO_EccPoint ph; | ||
54 | |||
55 | /* determine length */ | ||
56 | for (len = 0; 0 != avec[len]; len++) | ||
57 | ; | ||
58 | if (0 == len) | ||
59 | return 0; | ||
60 | |||
61 | /* Alice */ | ||
62 | GNUNET_CRYPTO_ecc_rnd_mpi (&a, | ||
63 | &a_neg); | ||
64 | g = GNUNET_new_array (len, | ||
65 | struct GNUNET_CRYPTO_EccPoint); | ||
66 | h = GNUNET_new_array (len, | ||
67 | struct GNUNET_CRYPTO_EccPoint); | ||
68 | for (unsigned int i = 0; i < len; i++) | ||
69 | { | ||
70 | struct GNUNET_CRYPTO_EccScalar tmp; | ||
71 | struct GNUNET_CRYPTO_EccScalar ri; | ||
72 | struct GNUNET_CRYPTO_EccScalar ria; | ||
73 | |||
74 | GNUNET_CRYPTO_ecc_random_mod_n (&ri); | ||
75 | GNUNET_assert (GNUNET_OK == | ||
76 | GNUNET_CRYPTO_ecc_dexp_mpi (&ri, | ||
77 | &g[i])); | ||
78 | /* ria = ri * a mod L, where L is the order of the main subgroup */ | ||
79 | crypto_core_ed25519_scalar_mul (ria.v, | ||
80 | ri.v, | ||
81 | a.v); | ||
82 | /* tmp = ria + avec[i] */ | ||
83 | { | ||
84 | int64_t val = avec[i]; | ||
85 | struct GNUNET_CRYPTO_EccScalar vali; | ||
86 | |||
87 | GNUNET_assert (INT64_MIN != val); | ||
88 | GNUNET_CRYPTO_ecc_scalar_from_int (val > 0 ? val : -val, | ||
89 | &vali); | ||
90 | if (val > 0) | ||
91 | crypto_core_ed25519_scalar_add (tmp.v, | ||
92 | ria.v, | ||
93 | vali.v); | ||
94 | else | ||
95 | crypto_core_ed25519_scalar_sub (tmp.v, | ||
96 | ria.v, | ||
97 | vali.v); | ||
98 | } | ||
99 | /* h[i] = g^tmp = g^{ria + avec[i]} */ | ||
100 | GNUNET_assert (GNUNET_OK == | ||
101 | GNUNET_CRYPTO_ecc_dexp_mpi (&tmp, | ||
102 | &h[i])); | ||
103 | } | ||
104 | |||
105 | /* Bob */ | ||
106 | for (unsigned int i = 0; i < len; i++) | ||
107 | { | ||
108 | struct GNUNET_CRYPTO_EccPoint gm; | ||
109 | struct GNUNET_CRYPTO_EccPoint hm; | ||
110 | |||
111 | { | ||
112 | int64_t val = bvec[i]; | ||
113 | struct GNUNET_CRYPTO_EccScalar vali; | ||
114 | |||
115 | GNUNET_assert (INT64_MIN != val); | ||
116 | GNUNET_CRYPTO_ecc_scalar_from_int (val > 0 ? val : -val, | ||
117 | &vali); | ||
118 | if (val < 0) | ||
119 | crypto_core_ed25519_scalar_negate (vali.v, | ||
120 | vali.v); | ||
121 | /* gm = g[i]^vali */ | ||
122 | GNUNET_assert (GNUNET_OK == | ||
123 | GNUNET_CRYPTO_ecc_pmul_mpi (&g[i], | ||
124 | &vali, | ||
125 | &gm)); | ||
126 | /* hm = h[i]^vali */ | ||
127 | GNUNET_assert (GNUNET_OK == | ||
128 | GNUNET_CRYPTO_ecc_pmul_mpi (&h[i], | ||
129 | &vali, | ||
130 | &hm)); | ||
131 | } | ||
132 | if (0 != i) | ||
133 | { | ||
134 | /* pg += gm */ | ||
135 | GNUNET_assert (GNUNET_OK == | ||
136 | GNUNET_CRYPTO_ecc_add (&gm, | ||
137 | &pg, | ||
138 | &pg)); | ||
139 | /* ph += hm */ | ||
140 | GNUNET_assert (GNUNET_OK == | ||
141 | GNUNET_CRYPTO_ecc_add (&hm, | ||
142 | &ph, | ||
143 | &ph)); | ||
144 | } | ||
145 | else | ||
146 | { | ||
147 | pg = gm; | ||
148 | ph = hm; | ||
149 | } | ||
150 | } | ||
151 | GNUNET_free (g); | ||
152 | GNUNET_free (h); | ||
153 | |||
154 | /* Alice */ | ||
155 | { | ||
156 | struct GNUNET_CRYPTO_EccPoint pgi; | ||
157 | struct GNUNET_CRYPTO_EccPoint gsp; | ||
158 | |||
159 | /* pgi = pg^inv */ | ||
160 | GNUNET_assert (GNUNET_OK == | ||
161 | GNUNET_CRYPTO_ecc_pmul_mpi (&pg, | ||
162 | &a_neg, | ||
163 | &pgi)); | ||
164 | /* gsp = pgi + ph */ | ||
165 | GNUNET_assert (GNUNET_OK == | ||
166 | GNUNET_CRYPTO_ecc_add (&pgi, | ||
167 | &ph, | ||
168 | &gsp)); | ||
169 | return GNUNET_CRYPTO_ecc_dlog (edc, | ||
170 | &gsp); | ||
171 | } | ||
172 | } | ||
173 | |||
174 | |||
175 | /** | ||
176 | * Macro that checks that @a want is equal to @a have and | ||
177 | * if not returns with a failure code. | ||
178 | */ | ||
179 | #define CHECK(want,have) do { \ | ||
180 | if (want != have) { \ | ||
181 | GNUNET_break (0); \ | ||
182 | GNUNET_log (GNUNET_ERROR_TYPE_ERROR, \ | ||
183 | "Wanted %d, got %d\n", want, have); \ | ||
184 | GNUNET_CRYPTO_ecc_dlog_release (edc); \ | ||
185 | return 1; \ | ||
186 | } } while (0) | ||
187 | |||
188 | |||
189 | int | ||
190 | main (int argc, char *argv[]) | ||
191 | { | ||
192 | static unsigned int v11[] = { 1, 1, 0 }; | ||
193 | static unsigned int v22[] = { 2, 2, 0 }; | ||
194 | static unsigned int v35[] = { 3, 5, 0 }; | ||
195 | static unsigned int v24[] = { 2, 4, 0 }; | ||
196 | |||
197 | GNUNET_log_setup ("test-ecc-scalarproduct", | ||
198 | "WARNING", | ||
199 | NULL); | ||
200 | edc = GNUNET_CRYPTO_ecc_dlog_prepare (128, 128); | ||
201 | CHECK (2, test_sp (v11, v11)); | ||
202 | CHECK (4, test_sp (v22, v11)); | ||
203 | CHECK (8, test_sp (v35, v11)); | ||
204 | CHECK (26, test_sp (v35, v24)); | ||
205 | CHECK (26, test_sp (v24, v35)); | ||
206 | CHECK (16, test_sp (v22, v35)); | ||
207 | GNUNET_CRYPTO_ecc_dlog_release (edc); | ||
208 | return 0; | ||
209 | } | ||
210 | |||
211 | |||
212 | /* end of test_ecc_scalarproduct.c */ | ||
diff --git a/src/scalarproduct/test_scalarproduct.conf b/src/scalarproduct/test_scalarproduct.conf deleted file mode 100644 index c7e2b55f5..000000000 --- a/src/scalarproduct/test_scalarproduct.conf +++ /dev/null | |||
@@ -1,23 +0,0 @@ | |||
1 | @INLINE@ ../../contrib/conf/gnunet/no_forcestart.conf | ||
2 | |||
3 | [PATHS] | ||
4 | GNUNET_TEST_HOME = $GNUNET_TMP/test-scalarproduct/ | ||
5 | |||
6 | [testbed] | ||
7 | OVERLAY_TOPOLOGY = CLIQUE | ||
8 | |||
9 | [nse] | ||
10 | WORKBITS=0 | ||
11 | |||
12 | [scalarproduct-bob] | ||
13 | #PREFIX = valgrind --leak-check=yes | ||
14 | |||
15 | [scalarproduct-alice] | ||
16 | #PREFIX = valgrind --leak-check=yes | ||
17 | |||
18 | [ats] | ||
19 | WAN_QUOTA_IN = unlimited | ||
20 | WAN_QUOTA_OUT = unlimited | ||
21 | |||
22 | [peerinfo] | ||
23 | USE_INCLUDED_HELLOS = NO | ||
diff --git a/src/scalarproduct/test_scalarproduct.sh b/src/scalarproduct/test_scalarproduct.sh deleted file mode 100755 index ed91cd5c4..000000000 --- a/src/scalarproduct/test_scalarproduct.sh +++ /dev/null | |||
@@ -1,48 +0,0 @@ | |||
1 | #!/bin/bash | ||
2 | # compute a simple scalar product | ||
3 | # payload for this test: | ||
4 | INPUTALICE="-k CCC -e 'AB,10;RO,3;FL,3;LOL,-1;'" | ||
5 | INPUTBOB="-k CCC -e 'BC,-20000;RO,1000;FL,100;LOL,24;'" | ||
6 | EXPECTED="0CCC" | ||
7 | |||
8 | # necessary to make the testing prefix deterministic, so we can access the config files | ||
9 | PREFIX=/tmp/test-scalarproduct`date +%H%M%S` | ||
10 | |||
11 | # where can we find the peers config files? | ||
12 | CFGALICE="-c $PREFIX/0/config" | ||
13 | CFGBOB="-c $PREFIX/1/config" | ||
14 | |||
15 | # launch two peers in line topology non-interactively | ||
16 | # | ||
17 | # interactive mode would terminate the test immediately | ||
18 | # because the rest of the script is already in stdin, | ||
19 | # thus redirecting stdin does not suffice) | ||
20 | # GNUNET_FORCE_LOG='scalarproduct*;;;;DEBUG' | ||
21 | GNUNET_TESTING_PREFIX=$PREFIX ../testbed/gnunet-testbed-profiler -n -c test_scalarproduct.conf -p 2 & | ||
22 | PID=$! | ||
23 | # sleep 1 is too short on most systems, 2 works on most, 5 seems to be safe | ||
24 | echo "Waiting for peers to start..." | ||
25 | sleep 5 | ||
26 | echo "Running test..." | ||
27 | |||
28 | which timeout >/dev/null 2>&1 && DO_TIMEOUT="timeout 15" | ||
29 | |||
30 | # get bob's peer ID, necessary for alice | ||
31 | PEERIDBOB=`${DO_TIMEOUT} gnunet-peerinfo -qs $CFGBOB` | ||
32 | |||
33 | #GNUNET_LOG=';;;;DEBUG' | ||
34 | ${DO_TIMEOUT} gnunet-scalarproduct $CFGBOB $INPUTBOB & | ||
35 | #GNUNET_LOG=';;;;DEBUG' | ||
36 | RESULT=`${DO_TIMEOUT} gnunet-scalarproduct $CFGALICE $INPUTALICE -p $PEERIDBOB` | ||
37 | |||
38 | # terminate the testbed | ||
39 | kill $PID | ||
40 | |||
41 | if [ "$RESULT" = "$EXPECTED" ] | ||
42 | then | ||
43 | echo "OK" | ||
44 | exit 0 | ||
45 | else | ||
46 | echo "Result $RESULT, expected $EXPECTED - NOTOK" | ||
47 | exit 1 | ||
48 | fi | ||
diff --git a/src/scalarproduct/test_scalarproduct_negative.sh b/src/scalarproduct/test_scalarproduct_negative.sh deleted file mode 100755 index 459406836..000000000 --- a/src/scalarproduct/test_scalarproduct_negative.sh +++ /dev/null | |||
@@ -1,49 +0,0 @@ | |||
1 | #!/bin/bash | ||
2 | # compute a simple scalar product | ||
3 | # payload for this test: | ||
4 | INPUTALICE="-k CCC -e 'AB,10;RO,-3;FL,-3;LOL,1;'" | ||
5 | INPUTBOB="-k CCC -e 'BC,-20000;RO,1000;FL,100;LOL,24;'" | ||
6 | |||
7 | # necessary to make the testing prefix deterministic, so we can access the config files | ||
8 | unset XDG_DATA_HOME | ||
9 | unset XDG_CONFIG_HOME | ||
10 | |||
11 | PREFIX=/tmp/test-scalarproduct`date +%H%M%S` | ||
12 | |||
13 | # where can we find the peers config files? | ||
14 | CFGALICE="-c $PREFIX/0/config" | ||
15 | CFGBOB="-c $PREFIX/1/config" | ||
16 | |||
17 | which timeout >/dev/null 2>&1 && DO_TIMEOUT="timeout 15" | ||
18 | |||
19 | # launch two peers in line topology non-interactively | ||
20 | # | ||
21 | # interactive mode would terminate the test immediately | ||
22 | # because the rest of the script is already in stdin, | ||
23 | # thus redirecting stdin does not suffice) | ||
24 | #GNUNET_LOG='scalarproduct;;;;DEBUG' | ||
25 | GNUNET_TESTING_PREFIX=$PREFIX ../testbed/gnunet-testbed-profiler -n -c test_scalarproduct.conf -p 2 & | ||
26 | PID=$! | ||
27 | # sleep 1 is too short on most systems, 2 works on most, 5 seems to be safe | ||
28 | sleep 5 | ||
29 | |||
30 | # get bob's peer ID, necessary for alice | ||
31 | PEERIDBOB=`${DO_TIMEOUT} gnunet-peerinfo -qs $CFGBOB` | ||
32 | |||
33 | #GNUNET_LOG=';;;;DEBUG' | ||
34 | ${DO_TIMEOUT} gnunet-scalarproduct $CFGBOB $INPUTBOB & | ||
35 | #RESULT=`GNUNET_LOG=';;;;DEBUG' | ||
36 | RESULT=`${DO_TIMEOUT} gnunet-scalarproduct $CFGALICE $INPUTALICE -p $PEERIDBOB` | ||
37 | |||
38 | # terminate the testbed | ||
39 | kill $PID | ||
40 | |||
41 | EXPECTED="-0CCC" | ||
42 | if [ "$RESULT" = "$EXPECTED" ] | ||
43 | then | ||
44 | echo "OK" | ||
45 | exit 0 | ||
46 | else | ||
47 | echo "Result $RESULT, expected $EXPECTED NOTOK" | ||
48 | exit 1 | ||
49 | fi | ||
diff --git a/src/scalarproduct/test_scalarproduct_negativezero.sh b/src/scalarproduct/test_scalarproduct_negativezero.sh deleted file mode 100755 index 6f80b2ea2..000000000 --- a/src/scalarproduct/test_scalarproduct_negativezero.sh +++ /dev/null | |||
@@ -1,46 +0,0 @@ | |||
1 | #!/bin/bash | ||
2 | # compute a simple scalar product | ||
3 | # payload for this test: | ||
4 | INPUTALICE="-k CCC -e 'AB,10;RO,-1;FL,1;LOL,1;'" | ||
5 | INPUTBOB="-k CCC -e 'BC,20;RO,1;FL,1;LOL,0;'" | ||
6 | |||
7 | # necessary to make the testing prefix deterministic, so we can access the config files | ||
8 | PREFIX=/tmp/test-scalarproduct`date +%H%M%S` | ||
9 | |||
10 | # where can we find the peers config files? | ||
11 | CFGALICE="-c $PREFIX/0/config" | ||
12 | CFGBOB="-c $PREFIX/1/config" | ||
13 | |||
14 | # launch two peers in line topology non-interactively | ||
15 | # | ||
16 | # interactive mode would terminate the test immediately | ||
17 | # because the rest of the script is already in stdin, | ||
18 | # thus redirecting stdin does not suffice) | ||
19 | # GNUNET_LOG='scalarproduct;;;;DEBUG' | ||
20 | GNUNET_TESTING_PREFIX=$PREFIX ../testbed/gnunet-testbed-profiler -n -c test_scalarproduct.conf -p 2 & | ||
21 | PID=$! | ||
22 | # sleep 1 is too short on most systems, 2 works on most, 5 seems to be safe | ||
23 | sleep 5 | ||
24 | |||
25 | which timeout >/dev/null 2>&1 && DO_TIMEOUT="timeout 15" | ||
26 | |||
27 | # get bob's peer ID, necessary for alice | ||
28 | PEERIDBOB=`${DO_TIMEOUT} gnunet-peerinfo -qs $CFGBOB` | ||
29 | |||
30 | #GNUNET_LOG=';;;;DEBUG' | ||
31 | ${DO_TIMEOUT} gnunet-scalarproduct $CFGBOB $INPUTBOB & | ||
32 | #GNUNET_LOG=';;;;DEBUG' | ||
33 | RESULT=`${DO_TIMEOUT} gnunet-scalarproduct $CFGALICE $INPUTALICE -p $PEERIDBOB` | ||
34 | |||
35 | # terminate the testbed | ||
36 | kill $PID | ||
37 | |||
38 | EXPECTED="00" | ||
39 | if [ "$RESULT" = "$EXPECTED" ] | ||
40 | then | ||
41 | echo "OK" | ||
42 | exit 0 | ||
43 | else | ||
44 | echo "Result $RESULT NOTOK" | ||
45 | exit 1 | ||
46 | fi | ||