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