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