diff options
author | Christian Grothoff <christian@grothoff.org> | 2014-12-06 22:41:30 +0000 |
---|---|---|
committer | Christian Grothoff <christian@grothoff.org> | 2014-12-06 22:41:30 +0000 |
commit | 9d487bb2fe029b369f362bdbe4697005061a4e5e (patch) | |
tree | 5c2eb6849a5dd7a813a07e29a7f2be60af9b9792 | |
parent | 6cd1fc3aa29926ce0326d07ba684e1b65a1a0db7 (diff) | |
download | gnunet-9d487bb2fe029b369f362bdbe4697005061a4e5e.tar.gz gnunet-9d487bb2fe029b369f362bdbe4697005061a4e5e.zip |
massive rework of scalarproduct service, splitting into Alice and Bob
-rw-r--r-- | src/include/gnunet_mq_lib.h | 8 | ||||
-rw-r--r-- | src/include/gnunet_protocols.h | 22 | ||||
-rw-r--r-- | src/scalarproduct/Makefile.am | 21 | ||||
-rw-r--r-- | src/scalarproduct/gnunet-service-scalarproduct.c | 2819 | ||||
-rw-r--r-- | src/scalarproduct/gnunet-service-scalarproduct.h | 165 | ||||
-rw-r--r-- | src/scalarproduct/gnunet-service-scalarproduct_alice.c | 1396 | ||||
-rw-r--r-- | src/scalarproduct/gnunet-service-scalarproduct_bob.c | 1490 | ||||
-rw-r--r-- | src/scalarproduct/scalarproduct.conf.in | 14 | ||||
-rw-r--r-- | src/scalarproduct/scalarproduct.h | 56 | ||||
-rw-r--r-- | src/scalarproduct/scalarproduct_api.c | 31 | ||||
-rw-r--r-- | src/scalarproduct/test_scalarproduct.conf | 2 |
11 files changed, 3155 insertions, 2869 deletions
diff --git a/src/include/gnunet_mq_lib.h b/src/include/gnunet_mq_lib.h index 8da51d198..ca09e7196 100644 --- a/src/include/gnunet_mq_lib.h +++ b/src/include/gnunet_mq_lib.h | |||
@@ -231,7 +231,8 @@ typedef void | |||
231 | * @param error error code | 231 | * @param error error code |
232 | */ | 232 | */ |
233 | typedef void | 233 | typedef void |
234 | (*GNUNET_MQ_ErrorHandler) (void *cls, enum GNUNET_MQ_Error error); | 234 | (*GNUNET_MQ_ErrorHandler) (void *cls, |
235 | enum GNUNET_MQ_Error error); | ||
235 | 236 | ||
236 | 237 | ||
237 | /** | 238 | /** |
@@ -270,7 +271,9 @@ struct GNUNET_MQ_MessageHandler | |||
270 | * @return the allocated MQ message | 271 | * @return the allocated MQ message |
271 | */ | 272 | */ |
272 | struct GNUNET_MQ_Envelope * | 273 | struct GNUNET_MQ_Envelope * |
273 | GNUNET_MQ_msg_ (struct GNUNET_MessageHeader **mhp, uint16_t size, uint16_t type); | 274 | GNUNET_MQ_msg_ (struct GNUNET_MessageHeader **mhp, |
275 | uint16_t size, | ||
276 | uint16_t type); | ||
274 | 277 | ||
275 | 278 | ||
276 | /** | 279 | /** |
@@ -388,7 +391,6 @@ GNUNET_MQ_queue_for_callbacks (GNUNET_MQ_SendImpl send, | |||
388 | void *cls); | 391 | void *cls); |
389 | 392 | ||
390 | 393 | ||
391 | |||
392 | /** | 394 | /** |
393 | * Replace the handlers of a message queue with new handlers. Takes | 395 | * Replace the handlers of a message queue with new handlers. Takes |
394 | * effect immediately, even for messages that already have been | 396 | * effect immediately, even for messages that already have been |
diff --git a/src/include/gnunet_protocols.h b/src/include/gnunet_protocols.h index 747a252ff..f9e8df77f 100644 --- a/src/include/gnunet_protocols.h +++ b/src/include/gnunet_protocols.h | |||
@@ -2050,39 +2050,39 @@ extern "C" | |||
2050 | #define GNUNET_MESSAGE_TYPE_SCALARPRODUCT_CLIENT_TO_BOB 641 | 2050 | #define GNUNET_MESSAGE_TYPE_SCALARPRODUCT_CLIENT_TO_BOB 641 |
2051 | 2051 | ||
2052 | /** | 2052 | /** |
2053 | * Client -> Alice/Bob multipart | 2053 | * Client -> Alice multipart |
2054 | */ | 2054 | */ |
2055 | #define GNUNET_MESSAGE_TYPE_SCALARPRODUCT_CLIENT_MUTLIPART 642 | 2055 | #define GNUNET_MESSAGE_TYPE_SCALARPRODUCT_CLIENT_MUTLIPART_ALICE 642 |
2056 | 2056 | ||
2057 | /** | 2057 | /** |
2058 | * Alice -> Bob session initialization | 2058 | * Client -> Bob multipart |
2059 | */ | 2059 | */ |
2060 | #define GNUNET_MESSAGE_TYPE_SCALARPRODUCT_SESSION_INITIALIZATION 643 | 2060 | #define GNUNET_MESSAGE_TYPE_SCALARPRODUCT_CLIENT_MUTLIPART_BOB 643 |
2061 | 2061 | ||
2062 | /** | 2062 | /** |
2063 | * Alice -> Bob SP crypto-data (after intersection) | 2063 | * Alice -> Bob session initialization |
2064 | */ | 2064 | */ |
2065 | #define GNUNET_MESSAGE_TYPE_SCALARPRODUCT_ALICE_CRYPTODATA 644 | 2065 | #define GNUNET_MESSAGE_TYPE_SCALARPRODUCT_SESSION_INITIALIZATION 644 |
2066 | 2066 | ||
2067 | /** | 2067 | /** |
2068 | * Alice -> Bob SP crypto-data multipart | 2068 | * Alice -> Bob SP crypto-data (after intersection) |
2069 | */ | 2069 | */ |
2070 | #define GNUNET_MESSAGE_TYPE_SCALARPRODUCT_ALICE_CRYPTODATA_MULTIPART 645 | 2070 | #define GNUNET_MESSAGE_TYPE_SCALARPRODUCT_ALICE_CRYPTODATA 645 |
2071 | 2071 | ||
2072 | /** | 2072 | /** |
2073 | * Bob -> Alice SP crypto-data | 2073 | * Bob -> Alice SP crypto-data |
2074 | */ | 2074 | */ |
2075 | #define GNUNET_MESSAGE_TYPE_SCALARPRODUCT_BOB_CRYPTODATA 646 | 2075 | #define GNUNET_MESSAGE_TYPE_SCALARPRODUCT_BOB_CRYPTODATA 647 |
2076 | 2076 | ||
2077 | /** | 2077 | /** |
2078 | * Bob -> Alice SP crypto-data multipart | 2078 | * Bob -> Alice SP crypto-data multipart |
2079 | */ | 2079 | */ |
2080 | #define GNUNET_MESSAGE_TYPE_SCALARPRODUCT_BOB_CRYPTODATA_MULTIPART 647 | 2080 | #define GNUNET_MESSAGE_TYPE_SCALARPRODUCT_BOB_CRYPTODATA_MULTIPART 648 |
2081 | 2081 | ||
2082 | /** | 2082 | /** |
2083 | * Alice/Bob -> Client Result | 2083 | * Alice/Bob -> Client Result |
2084 | */ | 2084 | */ |
2085 | #define GNUNET_MESSAGE_TYPE_SCALARPRODUCT_RESULT 648 | 2085 | #define GNUNET_MESSAGE_TYPE_SCALARPRODUCT_RESULT 649 |
2086 | 2086 | ||
2087 | 2087 | ||
2088 | 2088 | ||
diff --git a/src/scalarproduct/Makefile.am b/src/scalarproduct/Makefile.am index 0d3597126..ecebdbfc5 100644 --- a/src/scalarproduct/Makefile.am +++ b/src/scalarproduct/Makefile.am | |||
@@ -19,7 +19,8 @@ bin_PROGRAMS = \ | |||
19 | gnunet-scalarproduct | 19 | gnunet-scalarproduct |
20 | 20 | ||
21 | libexec_PROGRAMS = \ | 21 | libexec_PROGRAMS = \ |
22 | gnunet-service-scalarproduct | 22 | gnunet-service-scalarproduct-alice \ |
23 | gnunet-service-scalarproduct-bob | ||
23 | 24 | ||
24 | lib_LTLIBRARIES = \ | 25 | lib_LTLIBRARIES = \ |
25 | libgnunetscalarproduct.la | 26 | libgnunetscalarproduct.la |
@@ -33,9 +34,21 @@ gnunet_scalarproduct_LDADD = \ | |||
33 | -lgcrypt \ | 34 | -lgcrypt \ |
34 | $(GN_LIBINTL) | 35 | $(GN_LIBINTL) |
35 | 36 | ||
36 | gnunet_service_scalarproduct_SOURCES = \ | 37 | gnunet_service_scalarproduct_alice_SOURCES = \ |
37 | gnunet-service-scalarproduct.c | 38 | gnunet-service-scalarproduct.h \ |
38 | gnunet_service_scalarproduct_LDADD = \ | 39 | gnunet-service-scalarproduct_alice.c |
40 | gnunet_service_scalarproduct_alice_LDADD = \ | ||
41 | $(top_builddir)/src/util/libgnunetutil.la \ | ||
42 | $(top_builddir)/src/cadet/libgnunetcadet.la \ | ||
43 | $(top_builddir)/src/set/libgnunetset.la \ | ||
44 | $(LIBGCRYPT_LIBS) \ | ||
45 | -lgcrypt \ | ||
46 | $(GN_LIBINTL) | ||
47 | |||
48 | gnunet_service_scalarproduct_bob_SOURCES = \ | ||
49 | gnunet-service-scalarproduct.h \ | ||
50 | gnunet-service-scalarproduct_bob.c gnunet-service-scalarproduct_bob.h | ||
51 | gnunet_service_scalarproduct_bob_LDADD = \ | ||
39 | $(top_builddir)/src/util/libgnunetutil.la \ | 52 | $(top_builddir)/src/util/libgnunetutil.la \ |
40 | $(top_builddir)/src/cadet/libgnunetcadet.la \ | 53 | $(top_builddir)/src/cadet/libgnunetcadet.la \ |
41 | $(top_builddir)/src/set/libgnunetset.la \ | 54 | $(top_builddir)/src/set/libgnunetset.la \ |
diff --git a/src/scalarproduct/gnunet-service-scalarproduct.c b/src/scalarproduct/gnunet-service-scalarproduct.c deleted file mode 100644 index 18f243e5d..000000000 --- a/src/scalarproduct/gnunet-service-scalarproduct.c +++ /dev/null | |||
@@ -1,2819 +0,0 @@ | |||
1 | /* | ||
2 | This file is part of GNUnet. | ||
3 | (C) 2013, 2014 Christian Grothoff (and other contributing authors) | ||
4 | |||
5 | GNUnet is free software; you can redistribute it and/or modify | ||
6 | it under the terms of the GNU General Public License as published | ||
7 | by the Free Software Foundation; either version 3, or (at your | ||
8 | 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 | General Public License for more details. | ||
14 | |||
15 | You should have received a copy of the GNU General Public License | ||
16 | along with GNUnet; see the file COPYING. If not, write to the | ||
17 | Free Software Foundation, Inc., 59 Temple Place - Suite 330, | ||
18 | Boston, MA 02111-1307, USA. | ||
19 | */ | ||
20 | |||
21 | /** | ||
22 | * @file scalarproduct/gnunet-service-scalarproduct.c | ||
23 | * @brief scalarproduct service implementation | ||
24 | * @author Christian M. Fuchs | ||
25 | * @author Christian Grothoff | ||
26 | */ | ||
27 | #include "platform.h" | ||
28 | #include <limits.h> | ||
29 | #include <gcrypt.h> | ||
30 | #include "gnunet_util_lib.h" | ||
31 | #include "gnunet_core_service.h" | ||
32 | #include "gnunet_cadet_service.h" | ||
33 | #include "gnunet_applications.h" | ||
34 | #include "gnunet_protocols.h" | ||
35 | #include "gnunet_scalarproduct_service.h" | ||
36 | #include "gnunet_set_service.h" | ||
37 | #include "scalarproduct.h" | ||
38 | |||
39 | #define LOG(kind,...) GNUNET_log_from (kind, "scalarproduct", __VA_ARGS__) | ||
40 | |||
41 | |||
42 | /** | ||
43 | * Maximum count of elements we can put into a multipart message | ||
44 | */ | ||
45 | #define MULTIPART_ELEMENT_CAPACITY ((GNUNET_SERVER_MAX_MESSAGE_SIZE - 1 - sizeof (struct MultipartMessage)) / sizeof (struct GNUNET_CRYPTO_PaillierCiphertext)) | ||
46 | |||
47 | |||
48 | GNUNET_NETWORK_STRUCT_BEGIN | ||
49 | |||
50 | /** | ||
51 | * Message type passed from requesting service Alice to responding | ||
52 | * service Bob to initiate a request and make Bob participate in our | ||
53 | * protocol | ||
54 | */ | ||
55 | struct ServiceRequestMessage | ||
56 | { | ||
57 | /** | ||
58 | * Type is #GNUNET_MESSAGE_TYPE_SCALARPRODUCT_SESSION_INITIALIZATION | ||
59 | */ | ||
60 | struct GNUNET_MessageHeader header; | ||
61 | |||
62 | /** | ||
63 | * For alignment. Always zero. | ||
64 | */ | ||
65 | uint32_t reserved; | ||
66 | |||
67 | /** | ||
68 | * The transaction/session key used to identify a session | ||
69 | */ | ||
70 | struct GNUNET_HashCode session_id; | ||
71 | |||
72 | /** | ||
73 | * Alice's public key | ||
74 | */ | ||
75 | struct GNUNET_CRYPTO_PaillierPublicKey public_key; | ||
76 | |||
77 | }; | ||
78 | |||
79 | |||
80 | /** | ||
81 | * Vector of Pallier-encrypted values sent by Alice to Bob | ||
82 | * (after set intersection). | ||
83 | */ | ||
84 | struct AliceCryptodataMessage | ||
85 | { | ||
86 | /** | ||
87 | * Type is #GNUNET_MESSAGE_TYPE_SCALARPRODUCT_ALICE_CRYPTODATA | ||
88 | */ | ||
89 | struct GNUNET_MessageHeader header; | ||
90 | |||
91 | /** | ||
92 | * How many elements we appended to this message? In NBO. | ||
93 | */ | ||
94 | uint32_t contained_element_count GNUNET_PACKED; | ||
95 | |||
96 | /** | ||
97 | * struct GNUNET_CRYPTO_PaillierCiphertext[contained_element_count] | ||
98 | */ | ||
99 | }; | ||
100 | |||
101 | |||
102 | /** | ||
103 | * Multipart Message type passed between to supply additional elements | ||
104 | * for the peer. | ||
105 | */ | ||
106 | struct MultipartMessage | ||
107 | { | ||
108 | /** | ||
109 | * GNUNET message header | ||
110 | */ | ||
111 | struct GNUNET_MessageHeader header; | ||
112 | |||
113 | /** | ||
114 | * How many elements we supply within this message? In NBO. | ||
115 | */ | ||
116 | uint32_t contained_element_count GNUNET_PACKED; | ||
117 | |||
118 | /** | ||
119 | * struct GNUNET_CRYPTO_PaillierCiphertext[multipart_element_count] | ||
120 | */ | ||
121 | }; | ||
122 | |||
123 | |||
124 | /** | ||
125 | * Message type passed from responding service Bob to responding service Alice | ||
126 | * to complete a request and allow Alice to compute the result. | ||
127 | */ | ||
128 | struct ServiceResponseMessage | ||
129 | { | ||
130 | /** | ||
131 | * GNUNET message header | ||
132 | */ | ||
133 | struct GNUNET_MessageHeader header; | ||
134 | |||
135 | /** | ||
136 | * How many elements the session input had (in NBO). | ||
137 | */ | ||
138 | uint32_t total_element_count GNUNET_PACKED; | ||
139 | |||
140 | /** | ||
141 | * How many elements were included after the mask was applied | ||
142 | * including all multipart msgs (in NBO). | ||
143 | */ | ||
144 | uint32_t used_element_count GNUNET_PACKED; | ||
145 | |||
146 | /** | ||
147 | * How many elements this individual message delivers (in NBO). | ||
148 | */ | ||
149 | uint32_t contained_element_count GNUNET_PACKED; | ||
150 | |||
151 | /** | ||
152 | * The transaction/session key used to identify a session. | ||
153 | * FIXME: needed? CADET should already identify sessions! | ||
154 | */ | ||
155 | struct GNUNET_HashCode key; | ||
156 | |||
157 | /** | ||
158 | * followed by s | s' | k[i][perm] | ||
159 | */ | ||
160 | }; | ||
161 | |||
162 | GNUNET_NETWORK_STRUCT_END | ||
163 | |||
164 | |||
165 | /** | ||
166 | * Role a peer in a session can assume. | ||
167 | */ | ||
168 | enum PeerRole | ||
169 | { | ||
170 | /** | ||
171 | * Alice is the peer that learns the result of the scalar product | ||
172 | * calculation. | ||
173 | */ | ||
174 | ALICE, | ||
175 | |||
176 | /** | ||
177 | * Bob merely provides his vector to compute the scalar product, but | ||
178 | * does not learn anything about Alice's vector (except which elements | ||
179 | * Alice's vector may contain, as the compute an intersection). | ||
180 | */ | ||
181 | BOB | ||
182 | }; | ||
183 | |||
184 | |||
185 | /** | ||
186 | * DLL for sorting elements. | ||
187 | */ | ||
188 | struct SortedValue | ||
189 | { | ||
190 | /** | ||
191 | * Sorted Values are kept in a DLL | ||
192 | */ | ||
193 | struct SortedValue *next; | ||
194 | |||
195 | /** | ||
196 | * Sorted Values are kept in a DLL | ||
197 | */ | ||
198 | struct SortedValue *prev; | ||
199 | |||
200 | /** | ||
201 | * The element's id+integer-value | ||
202 | */ | ||
203 | struct GNUNET_SCALARPRODUCT_Element *elem; | ||
204 | |||
205 | /** | ||
206 | * The element's value converted to MPI | ||
207 | */ | ||
208 | gcry_mpi_t val; | ||
209 | }; | ||
210 | |||
211 | |||
212 | /** | ||
213 | * A scalarproduct session which tracks: | ||
214 | * | ||
215 | * a request form the client to our final response. | ||
216 | * or | ||
217 | * a request from a service to us (service). | ||
218 | */ | ||
219 | struct ServiceSession | ||
220 | { | ||
221 | |||
222 | /** | ||
223 | * Session information is kept in a DLL | ||
224 | */ | ||
225 | struct ServiceSession *next; | ||
226 | |||
227 | /** | ||
228 | * Session information is kept in a DLL | ||
229 | */ | ||
230 | struct ServiceSession *prev; | ||
231 | |||
232 | /** | ||
233 | * (hopefully) unique transaction ID | ||
234 | */ | ||
235 | struct GNUNET_HashCode session_id; | ||
236 | |||
237 | /** | ||
238 | * Alice or Bob's peerID | ||
239 | */ | ||
240 | struct GNUNET_PeerIdentity peer; | ||
241 | |||
242 | /** | ||
243 | * The client this request is related to. | ||
244 | */ | ||
245 | struct GNUNET_SERVER_Client *client; | ||
246 | |||
247 | /** | ||
248 | * The message to send | ||
249 | */ | ||
250 | struct GNUNET_MessageHeader *msg; | ||
251 | |||
252 | /** | ||
253 | * all non-0-value'd elements transmitted to us | ||
254 | */ | ||
255 | struct GNUNET_CONTAINER_MultiHashMap *intersected_elements; | ||
256 | |||
257 | /** | ||
258 | * Set of elements for which will conduction an intersection. | ||
259 | * the resulting elements are then used for computing the scalar product. | ||
260 | */ | ||
261 | struct GNUNET_SET_Handle *intersection_set; | ||
262 | |||
263 | /** | ||
264 | * Set of elements for which will conduction an intersection. | ||
265 | * the resulting elements are then used for computing the scalar product. | ||
266 | */ | ||
267 | struct GNUNET_SET_OperationHandle *intersection_op; | ||
268 | |||
269 | /** | ||
270 | * Handle to Alice's Intersection operation listening for Bob | ||
271 | */ | ||
272 | struct GNUNET_SET_ListenHandle *intersection_listen; | ||
273 | |||
274 | /** | ||
275 | * DLL for sorting elements after intersection | ||
276 | */ | ||
277 | struct SortedValue *a_head; | ||
278 | |||
279 | /** | ||
280 | * a(Alice) | ||
281 | */ | ||
282 | struct SortedValue *a_tail; | ||
283 | |||
284 | /** | ||
285 | * a(Alice) | ||
286 | */ | ||
287 | gcry_mpi_t *sorted_elements; | ||
288 | |||
289 | /** | ||
290 | * E(ai)(Bob) after applying the mask | ||
291 | */ | ||
292 | struct GNUNET_CRYPTO_PaillierCiphertext *e_a; | ||
293 | |||
294 | /** | ||
295 | * Bob's permutation p of R | ||
296 | */ | ||
297 | struct GNUNET_CRYPTO_PaillierCiphertext *r; | ||
298 | |||
299 | /** | ||
300 | * Bob's permutation q of R | ||
301 | */ | ||
302 | struct GNUNET_CRYPTO_PaillierCiphertext *r_prime; | ||
303 | |||
304 | /** | ||
305 | * Bob's "s" | ||
306 | */ | ||
307 | struct GNUNET_CRYPTO_PaillierCiphertext s; | ||
308 | |||
309 | /** | ||
310 | * Bob's "s'" | ||
311 | */ | ||
312 | struct GNUNET_CRYPTO_PaillierCiphertext s_prime; | ||
313 | |||
314 | /** | ||
315 | * Bob's matching response session from the client | ||
316 | */ | ||
317 | struct ServiceSession *response; | ||
318 | |||
319 | /** | ||
320 | * My transmit handle for the current message to a Alice/Bob | ||
321 | */ | ||
322 | struct GNUNET_CADET_TransmitHandle *service_transmit_handle; | ||
323 | |||
324 | /** | ||
325 | * My transmit handle for the current message to the client | ||
326 | */ | ||
327 | struct GNUNET_SERVER_TransmitHandle *client_transmit_handle; | ||
328 | |||
329 | /** | ||
330 | * channel-handle associated with our cadet handle | ||
331 | */ | ||
332 | struct GNUNET_CADET_Channel *channel; | ||
333 | |||
334 | /** | ||
335 | * Public key of the remote service, only used by Bob | ||
336 | */ | ||
337 | struct GNUNET_CRYPTO_PaillierPublicKey remote_pubkey; | ||
338 | |||
339 | /** | ||
340 | * Handle to a task that sends a msg to the our client | ||
341 | */ | ||
342 | GNUNET_SCHEDULER_TaskIdentifier client_notification_task; | ||
343 | |||
344 | /** | ||
345 | * The computed scalar | ||
346 | */ | ||
347 | gcry_mpi_t product; | ||
348 | |||
349 | /** | ||
350 | * how many elements we were supplied with from the client | ||
351 | */ | ||
352 | uint32_t total; | ||
353 | |||
354 | /** | ||
355 | * how many elements actually are used for the scalar product. | ||
356 | * Size of the arrays in @e r and @e r_prime. | ||
357 | */ | ||
358 | uint32_t used_element_count; | ||
359 | |||
360 | /** | ||
361 | * already transferred elements (sent/received) for multipart messages, less or equal than @e used_element_count for | ||
362 | */ | ||
363 | uint32_t transferred_element_count; | ||
364 | |||
365 | /** | ||
366 | * Is this session active (#GNUNET_YES), Concluded (#GNUNET_NO), or had an error (#GNUNET_SYSERR) | ||
367 | */ | ||
368 | int32_t active; | ||
369 | |||
370 | /** | ||
371 | * the role this peer has | ||
372 | */ | ||
373 | enum PeerRole role; | ||
374 | |||
375 | }; | ||
376 | |||
377 | |||
378 | /** | ||
379 | * GNUnet configuration handle | ||
380 | */ | ||
381 | static const struct GNUNET_CONFIGURATION_Handle * cfg; | ||
382 | |||
383 | /** | ||
384 | * Handle to the core service (NULL until we've connected to it). | ||
385 | */ | ||
386 | static struct GNUNET_CADET_Handle *my_cadet; | ||
387 | |||
388 | /** | ||
389 | * The identity of this host. | ||
390 | */ | ||
391 | static struct GNUNET_PeerIdentity me; | ||
392 | |||
393 | /** | ||
394 | * Service's own public key | ||
395 | */ | ||
396 | static struct GNUNET_CRYPTO_PaillierPublicKey my_pubkey; | ||
397 | |||
398 | /** | ||
399 | * Service's own private key | ||
400 | */ | ||
401 | static struct GNUNET_CRYPTO_PaillierPrivateKey my_privkey; | ||
402 | |||
403 | /** | ||
404 | * Service's offset for values that could possibly be negative but are plaintext for encryption. | ||
405 | */ | ||
406 | static gcry_mpi_t my_offset; | ||
407 | |||
408 | /** | ||
409 | * Head of our double linked list for client-requests sent to us. | ||
410 | * for all of these elements we calculate a scalar product with a remote peer | ||
411 | * split between service->service and client->service for simplicity | ||
412 | */ | ||
413 | static struct ServiceSession *from_client_head; | ||
414 | |||
415 | /** | ||
416 | * Tail of our double linked list for client-requests sent to us. | ||
417 | * for all of these elements we calculate a scalar product with a remote peer | ||
418 | * split between service->service and client->service for simplicity | ||
419 | */ | ||
420 | static struct ServiceSession *from_client_tail; | ||
421 | |||
422 | /** | ||
423 | * Head of our double linked list for service-requests sent to us. | ||
424 | * for all of these elements we help the requesting service in calculating a scalar product | ||
425 | * split between service->service and client->service for simplicity | ||
426 | */ | ||
427 | static struct ServiceSession *from_service_head; | ||
428 | |||
429 | /** | ||
430 | * Tail of our double linked list for service-requests sent to us. | ||
431 | * for all of these elements we help the requesting service in calculating a scalar product | ||
432 | * split between service->service and client->service for simplicity | ||
433 | */ | ||
434 | static struct ServiceSession *from_service_tail; | ||
435 | |||
436 | /** | ||
437 | * Certain events (callbacks for server & cadet operations) must not be queued after shutdown. | ||
438 | */ | ||
439 | static int do_shutdown; | ||
440 | |||
441 | |||
442 | /** | ||
443 | * Send a multi part chunk of a service request from alice to bob. | ||
444 | * This element only contains a part of the elements-vector (session->a[]), | ||
445 | * mask and public key set have to be contained within the first message | ||
446 | * | ||
447 | * This allows a ~32kbit key length while using 32000 elements or 62000 elements per request. | ||
448 | * | ||
449 | * @param cls the associated service session | ||
450 | */ | ||
451 | static void | ||
452 | prepare_alices_cyrptodata_message_multipart (void *cls); | ||
453 | |||
454 | |||
455 | /** | ||
456 | * Send a multi part chunk of a service response from Bob to Alice. | ||
457 | * This element only contains the two permutations of R, R'. | ||
458 | * | ||
459 | * @param cls the associated service session | ||
460 | */ | ||
461 | static void | ||
462 | prepare_bobs_cryptodata_message_multipart (void *cls); | ||
463 | |||
464 | |||
465 | /** | ||
466 | * Computes the square sum over a vector of a given length. | ||
467 | * | ||
468 | * @param vector the vector to encrypt | ||
469 | * @param length the length of the vector | ||
470 | * @return an MPI value containing the calculated sum, never NULL | ||
471 | */ | ||
472 | static gcry_mpi_t | ||
473 | compute_square_sum (gcry_mpi_t *vector, | ||
474 | uint32_t length) | ||
475 | { | ||
476 | gcry_mpi_t elem; | ||
477 | gcry_mpi_t sum; | ||
478 | uint32_t i; | ||
479 | |||
480 | GNUNET_assert (NULL != (sum = gcry_mpi_new (0))); | ||
481 | GNUNET_assert (NULL != (elem = gcry_mpi_new (0))); | ||
482 | for (i = 0; i < length; i++) | ||
483 | { | ||
484 | gcry_mpi_mul (elem, vector[i], vector[i]); | ||
485 | gcry_mpi_add (sum, sum, elem); | ||
486 | } | ||
487 | gcry_mpi_release (elem); | ||
488 | return sum; | ||
489 | } | ||
490 | |||
491 | |||
492 | /** | ||
493 | * Safely frees ALL memory areas referenced by a session. | ||
494 | * | ||
495 | * @param session - the session to free elements from | ||
496 | */ | ||
497 | static void | ||
498 | free_session_variables (struct ServiceSession *s) | ||
499 | { | ||
500 | struct SortedValue *e; | ||
501 | |||
502 | while (NULL != (e = s->a_head)) | ||
503 | { | ||
504 | GNUNET_free (e->elem); | ||
505 | gcry_mpi_release (e->val); | ||
506 | GNUNET_CONTAINER_DLL_remove (s->a_head, | ||
507 | s->a_tail, | ||
508 | e); | ||
509 | GNUNET_free (e); | ||
510 | } | ||
511 | if (NULL != s->intersected_elements) | ||
512 | { | ||
513 | GNUNET_CONTAINER_multihashmap_destroy (s->intersected_elements); | ||
514 | /* elements are freed independently in above loop over a_head */ | ||
515 | s->intersected_elements = NULL; | ||
516 | } | ||
517 | if (NULL != s->intersection_listen) | ||
518 | { | ||
519 | GNUNET_SET_listen_cancel (s->intersection_listen); | ||
520 | s->intersection_listen = NULL; | ||
521 | } | ||
522 | if (NULL != s->intersection_op) | ||
523 | { | ||
524 | GNUNET_SET_operation_cancel (s->intersection_op); | ||
525 | s->intersection_op = NULL; | ||
526 | } | ||
527 | if (NULL != s->intersection_set) | ||
528 | { | ||
529 | GNUNET_SET_destroy (s->intersection_set); | ||
530 | s->intersection_set = NULL; | ||
531 | } | ||
532 | if (NULL != s->e_a) | ||
533 | { | ||
534 | GNUNET_free (s->e_a); | ||
535 | s->e_a = NULL; | ||
536 | } | ||
537 | if (NULL != s->sorted_elements) | ||
538 | { | ||
539 | GNUNET_free (s->sorted_elements); | ||
540 | s->sorted_elements = NULL; | ||
541 | } | ||
542 | if (NULL != s->msg) | ||
543 | { | ||
544 | GNUNET_free (s->msg); | ||
545 | s->msg = NULL; | ||
546 | } | ||
547 | if (NULL != s->r) | ||
548 | { | ||
549 | GNUNET_free (s->r); | ||
550 | s->r = NULL; | ||
551 | } | ||
552 | if (NULL != s->r_prime) | ||
553 | { | ||
554 | GNUNET_free (s->r_prime); | ||
555 | s->r_prime = NULL; | ||
556 | } | ||
557 | if (NULL != s->product) | ||
558 | { | ||
559 | gcry_mpi_release (s->product); | ||
560 | s->product = NULL; | ||
561 | } | ||
562 | } | ||
563 | |||
564 | |||
565 | /** | ||
566 | * Primitive callback for copying over a message, as they usually are | ||
567 | * too complex to be handled in the callback itself. Clears a | ||
568 | * session-callback, if a session was handed over and the transmit | ||
569 | * handle was stored. | ||
570 | * | ||
571 | * @param cls the session containing the message object | ||
572 | * @param size the size of the @a buf we got | ||
573 | * @param buf the buffer to copy the message to | ||
574 | * @return 0 if we couldn't copy, else the size copied over | ||
575 | */ | ||
576 | static size_t | ||
577 | cb_transfer_message (void *cls, | ||
578 | size_t size, | ||
579 | void *buf) | ||
580 | { | ||
581 | struct ServiceSession *s = cls; | ||
582 | uint16_t type; | ||
583 | |||
584 | s->client_transmit_handle = NULL; | ||
585 | GNUNET_assert (buf); | ||
586 | if (ntohs (s->msg->size) > size) | ||
587 | { | ||
588 | GNUNET_break (0); | ||
589 | return 0; | ||
590 | } | ||
591 | size = ntohs (s->msg->size); | ||
592 | type = ntohs (s->msg->type); | ||
593 | memcpy (buf, | ||
594 | s->msg, | ||
595 | size); | ||
596 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
597 | "Sending a message of type %u.\n", | ||
598 | (unsigned int) type); | ||
599 | GNUNET_free (s->msg); | ||
600 | s->msg = NULL; | ||
601 | |||
602 | switch (type) | ||
603 | { | ||
604 | case GNUNET_MESSAGE_TYPE_SCALARPRODUCT_RESULT: | ||
605 | free_session_variables (s); | ||
606 | // FIXME: that does not fully clean up 's' | ||
607 | break; | ||
608 | case GNUNET_MESSAGE_TYPE_SCALARPRODUCT_SESSION_INITIALIZATION: | ||
609 | break; | ||
610 | case GNUNET_MESSAGE_TYPE_SCALARPRODUCT_ALICE_CRYPTODATA: | ||
611 | case GNUNET_MESSAGE_TYPE_SCALARPRODUCT_ALICE_CRYPTODATA_MULTIPART: | ||
612 | if (s->used_element_count != s->transferred_element_count) | ||
613 | prepare_alices_cyrptodata_message_multipart (s); | ||
614 | else | ||
615 | s->channel = NULL; | ||
616 | break; | ||
617 | case GNUNET_MESSAGE_TYPE_SCALARPRODUCT_BOB_CRYPTODATA: | ||
618 | case GNUNET_MESSAGE_TYPE_SCALARPRODUCT_BOB_CRYPTODATA_MULTIPART: | ||
619 | if (s->used_element_count != s->transferred_element_count) | ||
620 | prepare_bobs_cryptodata_message_multipart (s); | ||
621 | else | ||
622 | s->channel = NULL; | ||
623 | break; | ||
624 | default: | ||
625 | GNUNET_assert (0); | ||
626 | } | ||
627 | return size; | ||
628 | } | ||
629 | |||
630 | |||
631 | /** | ||
632 | * Finds a not terminated client/service session in the | ||
633 | * given DLL based on session key, element count and state. | ||
634 | * | ||
635 | * FIXME: Use hashmap based on key instead of linear search. | ||
636 | * | ||
637 | * @param tail - the tail of the DLL | ||
638 | * @param key - the key we want to search for | ||
639 | * @param peerid - a pointer to the peer ID of the associated peer, NULL to ignore | ||
640 | * @return a pointer to a matching session, or NULL | ||
641 | */ | ||
642 | static struct ServiceSession * | ||
643 | find_matching_session (struct ServiceSession *tail, | ||
644 | const struct GNUNET_HashCode *key, | ||
645 | const struct GNUNET_PeerIdentity *peerid) | ||
646 | { | ||
647 | struct ServiceSession * s; | ||
648 | |||
649 | for (s = tail; NULL != s; s = s->prev) | ||
650 | { | ||
651 | // if the key matches, and the element_count is same | ||
652 | if (0 == memcmp (&s->session_id, key, sizeof (struct GNUNET_HashCode))) | ||
653 | { | ||
654 | // if peerid is NULL OR same as the peer Id in the queued request | ||
655 | if ((NULL == peerid) | ||
656 | || (0 == memcmp (&s->peer, peerid, sizeof (struct GNUNET_PeerIdentity)))) | ||
657 | // matches and is not an already terminated session | ||
658 | return s; | ||
659 | } | ||
660 | } | ||
661 | |||
662 | return NULL; | ||
663 | } | ||
664 | |||
665 | |||
666 | /** | ||
667 | * A client disconnected. | ||
668 | * | ||
669 | * Remove the associated session(s), release data structures | ||
670 | * and cancel pending outgoing transmissions to the client. | ||
671 | * if the session has not yet completed, we also cancel Alice's request to Bob. | ||
672 | * | ||
673 | * @param cls closure, NULL | ||
674 | * @param client identification of the client | ||
675 | */ | ||
676 | static void | ||
677 | cb_client_disconnect (void *cls, | ||
678 | struct GNUNET_SERVER_Client *client) | ||
679 | { | ||
680 | struct ServiceSession *s; | ||
681 | |||
682 | if (NULL == client) | ||
683 | return; | ||
684 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
685 | "Client %p disconnected from us.\n", | ||
686 | client); | ||
687 | s = GNUNET_SERVER_client_get_user_context (client, | ||
688 | struct ServiceSession); | ||
689 | if (NULL == s) | ||
690 | return; | ||
691 | GNUNET_CONTAINER_DLL_remove (from_client_head, | ||
692 | from_client_tail, | ||
693 | s); | ||
694 | if (NULL != s->service_transmit_handle) | ||
695 | { | ||
696 | GNUNET_CADET_notify_transmit_ready_cancel (s->service_transmit_handle); | ||
697 | s->service_transmit_handle = NULL; | ||
698 | } | ||
699 | if (NULL != s->channel) | ||
700 | { | ||
701 | GNUNET_CADET_channel_destroy (s->channel); | ||
702 | s->channel = NULL; | ||
703 | } | ||
704 | if (GNUNET_SCHEDULER_NO_TASK != s->client_notification_task) | ||
705 | { | ||
706 | GNUNET_SCHEDULER_cancel (s->client_notification_task); | ||
707 | s->client_notification_task = GNUNET_SCHEDULER_NO_TASK; | ||
708 | } | ||
709 | if (NULL != s->client_transmit_handle) | ||
710 | { | ||
711 | GNUNET_SERVER_notify_transmit_ready_cancel (s->client_transmit_handle); | ||
712 | s->client_transmit_handle = NULL; | ||
713 | } | ||
714 | free_session_variables (s); | ||
715 | GNUNET_free (s); | ||
716 | } | ||
717 | |||
718 | |||
719 | /** | ||
720 | * Notify the client that the session has succeeded or failed completely. | ||
721 | * This message gets sent to | ||
722 | * - Alice's client if Bob disconnected or to | ||
723 | * - Bob's client if the operation completed or Alice disconnected | ||
724 | * | ||
725 | * @param cls the associated client session | ||
726 | * @param tc the task context handed to us by the scheduler, unused | ||
727 | */ | ||
728 | static void | ||
729 | prepare_client_end_notification (void *cls, | ||
730 | const struct GNUNET_SCHEDULER_TaskContext *tc) | ||
731 | { | ||
732 | struct ServiceSession *session = cls; | ||
733 | struct ClientResponseMessage *msg; | ||
734 | |||
735 | session->client_notification_task = GNUNET_SCHEDULER_NO_TASK; | ||
736 | |||
737 | msg = GNUNET_new (struct ClientResponseMessage); | ||
738 | msg->header.size = htons (sizeof (struct ClientResponseMessage)); | ||
739 | msg->header.type = htons (GNUNET_MESSAGE_TYPE_SCALARPRODUCT_RESULT); | ||
740 | // signal error if not signalized, positive result-range field but zero length. | ||
741 | msg->product_length = htonl (0); | ||
742 | msg->status = htonl (session->active); | ||
743 | session->msg = &msg->header; | ||
744 | |||
745 | //transmit this message to our client | ||
746 | session->client_transmit_handle | ||
747 | = GNUNET_SERVER_notify_transmit_ready (session->client, | ||
748 | sizeof (struct ClientResponseMessage), | ||
749 | GNUNET_TIME_UNIT_FOREVER_REL, | ||
750 | &cb_transfer_message, | ||
751 | session); | ||
752 | |||
753 | // if we could not even queue our request, something is wrong | ||
754 | if (NULL == session->client_transmit_handle) | ||
755 | { | ||
756 | GNUNET_log (GNUNET_ERROR_TYPE_WARNING, | ||
757 | _("Could not send message to client (%p)!\n"), | ||
758 | session->client); | ||
759 | GNUNET_SERVER_client_disconnect (session->client); | ||
760 | free_session_variables (session); | ||
761 | GNUNET_CONTAINER_DLL_remove (from_client_head, | ||
762 | from_client_tail, | ||
763 | session); | ||
764 | GNUNET_free (session); | ||
765 | return; | ||
766 | } | ||
767 | GNUNET_log (GNUNET_ERROR_TYPE_INFO, | ||
768 | _("Sending session-end notification to client (%p) for session %s\n"), | ||
769 | session->client, | ||
770 | GNUNET_h2s (&session->session_id)); | ||
771 | } | ||
772 | |||
773 | |||
774 | /** | ||
775 | * Executed by Alice, fills in a service-request message and sends it | ||
776 | * to the given peer. | ||
777 | * | ||
778 | * @param cls the session associated with this request | ||
779 | */ | ||
780 | static void | ||
781 | prepare_alices_cyrptodata_message (void *cls) | ||
782 | { | ||
783 | struct ServiceSession *session = cls; | ||
784 | struct AliceCryptodataMessage * msg; | ||
785 | struct GNUNET_CRYPTO_PaillierCiphertext * payload; | ||
786 | unsigned int i; | ||
787 | uint32_t msg_length; | ||
788 | gcry_mpi_t a; | ||
789 | |||
790 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
791 | "Successfully created new channel to peer (%s)!\n", | ||
792 | GNUNET_i2s (&session->peer)); | ||
793 | |||
794 | msg_length = sizeof (struct AliceCryptodataMessage) | ||
795 | + session->used_element_count * sizeof (struct GNUNET_CRYPTO_PaillierCiphertext); | ||
796 | |||
797 | if (GNUNET_SERVER_MAX_MESSAGE_SIZE > msg_length) | ||
798 | { | ||
799 | session->transferred_element_count = session->used_element_count; | ||
800 | } | ||
801 | else | ||
802 | { | ||
803 | //create a multipart msg, first we calculate a new msg size for the head msg | ||
804 | session->transferred_element_count = (GNUNET_SERVER_MAX_MESSAGE_SIZE - 1 - sizeof (struct AliceCryptodataMessage)) | ||
805 | / sizeof (struct GNUNET_CRYPTO_PaillierCiphertext); | ||
806 | msg_length = sizeof (struct AliceCryptodataMessage) | ||
807 | + session->transferred_element_count * sizeof (struct GNUNET_CRYPTO_PaillierCiphertext); | ||
808 | } | ||
809 | |||
810 | msg = GNUNET_malloc (msg_length); | ||
811 | msg->header.size = htons (msg_length); | ||
812 | msg->header.type = htons (GNUNET_MESSAGE_TYPE_SCALARPRODUCT_ALICE_CRYPTODATA); | ||
813 | msg->contained_element_count = htonl (session->transferred_element_count); | ||
814 | |||
815 | // fill in the payload | ||
816 | payload = (struct GNUNET_CRYPTO_PaillierCiphertext *) &msg[1]; | ||
817 | |||
818 | // now copy over the sorted element vector | ||
819 | a = gcry_mpi_new (0); | ||
820 | for (i = 0; i < session->transferred_element_count; i++) | ||
821 | { | ||
822 | gcry_mpi_add (a, session->sorted_elements[i], my_offset); | ||
823 | GNUNET_CRYPTO_paillier_encrypt (&my_pubkey, a, 3, &payload[i]); | ||
824 | } | ||
825 | gcry_mpi_release (a); | ||
826 | |||
827 | session->msg = (struct GNUNET_MessageHeader *) msg; | ||
828 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
829 | "Transmitting service request.\n"); | ||
830 | |||
831 | //transmit via cadet messaging | ||
832 | session->service_transmit_handle | ||
833 | = GNUNET_CADET_notify_transmit_ready (session->channel, | ||
834 | GNUNET_YES, | ||
835 | GNUNET_TIME_UNIT_FOREVER_REL, | ||
836 | msg_length, | ||
837 | &cb_transfer_message, | ||
838 | session); | ||
839 | if (NULL == session->service_transmit_handle) | ||
840 | { | ||
841 | GNUNET_log (GNUNET_ERROR_TYPE_ERROR, | ||
842 | _("Could not send message to channel!\n")); | ||
843 | GNUNET_free (msg); | ||
844 | session->msg = NULL; | ||
845 | session->active = GNUNET_SYSERR; | ||
846 | session->client_notification_task | ||
847 | = GNUNET_SCHEDULER_add_now (&prepare_client_end_notification, | ||
848 | session); | ||
849 | return; | ||
850 | } | ||
851 | } | ||
852 | |||
853 | |||
854 | /** | ||
855 | * Send a multipart chunk of a service response from bob to alice. | ||
856 | * This element only contains the two permutations of R, R'. | ||
857 | * | ||
858 | * @param cls the associated service session | ||
859 | */ | ||
860 | static void | ||
861 | prepare_bobs_cryptodata_message_multipart (void *cls) | ||
862 | { | ||
863 | struct ServiceSession *session = cls; | ||
864 | struct GNUNET_CRYPTO_PaillierCiphertext * payload; | ||
865 | struct MultipartMessage * msg; | ||
866 | unsigned int i; | ||
867 | unsigned int j; | ||
868 | uint32_t msg_length; | ||
869 | uint32_t todo_count; | ||
870 | |||
871 | msg_length = sizeof (struct MultipartMessage); | ||
872 | todo_count = session->used_element_count - session->transferred_element_count; | ||
873 | |||
874 | if (todo_count > MULTIPART_ELEMENT_CAPACITY / 2) | ||
875 | // send the currently possible maximum chunk, we always transfer both permutations | ||
876 | todo_count = MULTIPART_ELEMENT_CAPACITY / 2; | ||
877 | |||
878 | msg_length += todo_count * sizeof (struct GNUNET_CRYPTO_PaillierCiphertext) * 2; | ||
879 | msg = GNUNET_malloc (msg_length); | ||
880 | msg->header.type = htons (GNUNET_MESSAGE_TYPE_SCALARPRODUCT_ALICE_CRYPTODATA_MULTIPART); | ||
881 | msg->header.size = htons (msg_length); | ||
882 | msg->contained_element_count = htonl (todo_count); | ||
883 | |||
884 | payload = (struct GNUNET_CRYPTO_PaillierCiphertext *) &msg[1]; | ||
885 | for (i = session->transferred_element_count, j = 0; i < session->transferred_element_count + todo_count; i++) | ||
886 | { | ||
887 | //r[i][p] and r[i][q] | ||
888 | memcpy (&payload[j++], | ||
889 | &session->r[i], | ||
890 | sizeof (struct GNUNET_CRYPTO_PaillierCiphertext)); | ||
891 | memcpy (&payload[j++], | ||
892 | &session->r_prime[i], | ||
893 | sizeof (struct GNUNET_CRYPTO_PaillierCiphertext)); | ||
894 | } | ||
895 | session->transferred_element_count += todo_count; | ||
896 | session->msg = (struct GNUNET_MessageHeader *) msg; | ||
897 | session->service_transmit_handle | ||
898 | = GNUNET_CADET_notify_transmit_ready (session->channel, | ||
899 | GNUNET_YES, | ||
900 | GNUNET_TIME_UNIT_FOREVER_REL, | ||
901 | msg_length, | ||
902 | &cb_transfer_message, | ||
903 | session); | ||
904 | if (NULL == session->service_transmit_handle) | ||
905 | { | ||
906 | GNUNET_log (GNUNET_ERROR_TYPE_ERROR, | ||
907 | _("Could not send service-response message via CADET!)\n")); | ||
908 | |||
909 | GNUNET_free (msg); | ||
910 | session->msg = NULL; | ||
911 | GNUNET_CADET_channel_destroy (session->channel); | ||
912 | session->response->active = GNUNET_SYSERR; | ||
913 | |||
914 | GNUNET_CONTAINER_DLL_remove (from_service_head, | ||
915 | from_service_tail, | ||
916 | session); | ||
917 | session->response->client_notification_task | ||
918 | = GNUNET_SCHEDULER_add_now (&prepare_client_end_notification, | ||
919 | session->response); | ||
920 | free_session_variables (session); | ||
921 | GNUNET_free (session); | ||
922 | return; | ||
923 | } | ||
924 | if (session->transferred_element_count == session->used_element_count) | ||
925 | { | ||
926 | // final part | ||
927 | session->active = GNUNET_NO; | ||
928 | GNUNET_free (session->r_prime); | ||
929 | GNUNET_free (session->r); | ||
930 | session->r_prime = NULL; | ||
931 | session->r = NULL; | ||
932 | } | ||
933 | } | ||
934 | |||
935 | |||
936 | /** | ||
937 | * Bob executes: | ||
938 | * generates the response message to be sent to alice after computing | ||
939 | * the values (1), (2), S and S' | ||
940 | * (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)})$ | ||
941 | * (2)[]: $E_A(a_{pi'(i)}) times E_A(- r_{pi'(i)}) &= E_A(a_{pi'(i)} - r_{pi'(i)})$ | ||
942 | * S: $S := E_A(sum (r_i + b_i)^2)$ | ||
943 | * S': $S' := E_A(sum r_i^2)$ | ||
944 | * | ||
945 | * @param session the associated requesting session with alice | ||
946 | */ | ||
947 | static void | ||
948 | prepare_bobs_cryptodata_message (void *cls, | ||
949 | const struct GNUNET_SCHEDULER_TaskContext *tc) | ||
950 | { | ||
951 | struct ServiceSession * s = cls; | ||
952 | struct ServiceResponseMessage *msg; | ||
953 | uint32_t msg_length = 0; | ||
954 | struct GNUNET_CRYPTO_PaillierCiphertext *payload; | ||
955 | unsigned int i; | ||
956 | |||
957 | msg_length = sizeof (struct ServiceResponseMessage) | ||
958 | + 2 * sizeof (struct GNUNET_CRYPTO_PaillierCiphertext); // s, stick | ||
959 | |||
960 | if (GNUNET_SERVER_MAX_MESSAGE_SIZE > | ||
961 | msg_length + 2 * s->used_element_count * sizeof (struct GNUNET_CRYPTO_PaillierCiphertext)) | ||
962 | { //r, r' | ||
963 | msg_length += 2 * s->used_element_count * sizeof (struct GNUNET_CRYPTO_PaillierCiphertext); | ||
964 | s->transferred_element_count = s->used_element_count; | ||
965 | } | ||
966 | else | ||
967 | s->transferred_element_count = (GNUNET_SERVER_MAX_MESSAGE_SIZE - 1 - msg_length) / | ||
968 | (sizeof (struct GNUNET_CRYPTO_PaillierCiphertext) * 2); | ||
969 | |||
970 | msg = GNUNET_malloc (msg_length); | ||
971 | msg->header.type = htons (GNUNET_MESSAGE_TYPE_SCALARPRODUCT_BOB_CRYPTODATA); | ||
972 | msg->header.size = htons (msg_length); | ||
973 | msg->total_element_count = htonl (s->total); | ||
974 | msg->used_element_count = htonl (s->used_element_count); | ||
975 | msg->contained_element_count = htonl (s->transferred_element_count); | ||
976 | msg->key = s->session_id; | ||
977 | |||
978 | payload = (struct GNUNET_CRYPTO_PaillierCiphertext *) &msg[1]; | ||
979 | memcpy (&payload[0], | ||
980 | &s->s, | ||
981 | sizeof (struct GNUNET_CRYPTO_PaillierCiphertext)); | ||
982 | memcpy (&payload[1], | ||
983 | &s->s_prime, | ||
984 | sizeof (struct GNUNET_CRYPTO_PaillierCiphertext)); | ||
985 | |||
986 | payload = &payload[2]; | ||
987 | // convert k[][] | ||
988 | for (i = 0; i < s->transferred_element_count; i++) | ||
989 | { | ||
990 | //k[i][p] and k[i][q] | ||
991 | memcpy (&payload[i * 2], | ||
992 | &s->r[i], | ||
993 | sizeof (struct GNUNET_CRYPTO_PaillierCiphertext)); | ||
994 | memcpy (&payload[i * 2 + 1], | ||
995 | &s->r_prime[i], | ||
996 | sizeof (struct GNUNET_CRYPTO_PaillierCiphertext)); | ||
997 | } | ||
998 | |||
999 | s->msg = (struct GNUNET_MessageHeader *) msg; | ||
1000 | s->service_transmit_handle | ||
1001 | = GNUNET_CADET_notify_transmit_ready (s->channel, | ||
1002 | GNUNET_YES, | ||
1003 | GNUNET_TIME_UNIT_FOREVER_REL, | ||
1004 | msg_length, | ||
1005 | &cb_transfer_message, | ||
1006 | s); | ||
1007 | if (NULL == s->service_transmit_handle) | ||
1008 | { | ||
1009 | //disconnect our client | ||
1010 | GNUNET_log (GNUNET_ERROR_TYPE_ERROR, | ||
1011 | _("Could not send service-response message via cadet!)\n")); | ||
1012 | |||
1013 | GNUNET_free (msg); | ||
1014 | s->msg = NULL; | ||
1015 | GNUNET_CONTAINER_DLL_remove (from_service_head, | ||
1016 | from_service_tail, | ||
1017 | s); | ||
1018 | GNUNET_CADET_channel_destroy(s->channel); | ||
1019 | s->response->active = GNUNET_SYSERR; | ||
1020 | |||
1021 | s->response->client_notification_task = | ||
1022 | GNUNET_SCHEDULER_add_now (&prepare_client_end_notification, | ||
1023 | s->response); | ||
1024 | free_session_variables (s); | ||
1025 | GNUNET_free(s); | ||
1026 | return; | ||
1027 | } | ||
1028 | if (s->transferred_element_count != s->used_element_count) | ||
1029 | { | ||
1030 | // multipart | ||
1031 | } | ||
1032 | else | ||
1033 | { | ||
1034 | //singlepart | ||
1035 | s->active = GNUNET_NO; | ||
1036 | GNUNET_free (s->r); | ||
1037 | s->r = NULL; | ||
1038 | GNUNET_free (s->r_prime); | ||
1039 | s->r_prime = NULL; | ||
1040 | } | ||
1041 | } | ||
1042 | |||
1043 | |||
1044 | /** | ||
1045 | * executed by bob: | ||
1046 | * compute the values | ||
1047 | * (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)})$ | ||
1048 | * (2)[]: $E_A(a_{pi'(i)}) otimes E_A(- r_{pi'(i)}) &= E_A(a_{pi'(i)} - r_{pi'(i)})$ | ||
1049 | * S: $S := E_A(sum (r_i + b_i)^2)$ | ||
1050 | * S': $S' := E_A(sum r_i^2)$ | ||
1051 | * | ||
1052 | * @param request the requesting session + bob's requesting peer | ||
1053 | */ | ||
1054 | static void | ||
1055 | compute_service_response (struct ServiceSession *session) | ||
1056 | { | ||
1057 | int i; | ||
1058 | unsigned int *p; | ||
1059 | unsigned int *q; | ||
1060 | uint32_t count; | ||
1061 | gcry_mpi_t *rand; | ||
1062 | gcry_mpi_t tmp; | ||
1063 | gcry_mpi_t *b; | ||
1064 | struct GNUNET_CRYPTO_PaillierCiphertext *a; | ||
1065 | struct GNUNET_CRYPTO_PaillierCiphertext *r; | ||
1066 | struct GNUNET_CRYPTO_PaillierCiphertext *r_prime; | ||
1067 | |||
1068 | count = session->used_element_count; | ||
1069 | a = session->e_a; | ||
1070 | b = session->sorted_elements; | ||
1071 | q = GNUNET_CRYPTO_random_permute (GNUNET_CRYPTO_QUALITY_WEAK, | ||
1072 | count); | ||
1073 | p = GNUNET_CRYPTO_random_permute (GNUNET_CRYPTO_QUALITY_WEAK, | ||
1074 | count); | ||
1075 | rand = GNUNET_malloc (sizeof (gcry_mpi_t) * count); | ||
1076 | for (i = 0; i < count; i++) | ||
1077 | GNUNET_assert (NULL != (rand[i] = gcry_mpi_new (0))); | ||
1078 | r = GNUNET_malloc (sizeof (struct GNUNET_CRYPTO_PaillierCiphertext) * count); | ||
1079 | r_prime = GNUNET_malloc (sizeof (struct GNUNET_CRYPTO_PaillierCiphertext) * count); | ||
1080 | |||
1081 | for (i = 0; i < count; i++) | ||
1082 | { | ||
1083 | int32_t svalue; | ||
1084 | |||
1085 | svalue = (int32_t) GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_WEAK, | ||
1086 | UINT32_MAX); | ||
1087 | // long to gcry_mpi_t | ||
1088 | if (svalue < 0) | ||
1089 | gcry_mpi_sub_ui (rand[i], | ||
1090 | rand[i], | ||
1091 | - svalue); | ||
1092 | else | ||
1093 | rand[i] = gcry_mpi_set_ui (rand[i], svalue); | ||
1094 | } | ||
1095 | |||
1096 | tmp = gcry_mpi_new (0); | ||
1097 | // encrypt the element | ||
1098 | // for the sake of readability I decided to have dedicated permutation | ||
1099 | // vectors, which get rid of all the lookups in p/q. | ||
1100 | // however, ap/aq are not absolutely necessary but are just abstraction | ||
1101 | // Calculate Kp = E(S + a_pi) (+) E(S - r_pi - b_pi) | ||
1102 | for (i = 0; i < count; i++) | ||
1103 | { | ||
1104 | // E(S - r_pi - b_pi) | ||
1105 | gcry_mpi_sub (tmp, my_offset, rand[p[i]]); | ||
1106 | gcry_mpi_sub (tmp, tmp, b[p[i]]); | ||
1107 | GNUNET_CRYPTO_paillier_encrypt (&session->remote_pubkey, | ||
1108 | tmp, | ||
1109 | 2, | ||
1110 | &r[i]); | ||
1111 | |||
1112 | // E(S - r_pi - b_pi) * E(S + a_pi) == E(2*S + a - r - b) | ||
1113 | GNUNET_CRYPTO_paillier_hom_add (&session->remote_pubkey, | ||
1114 | &r[i], | ||
1115 | &a[p[i]], | ||
1116 | &r[i]); | ||
1117 | } | ||
1118 | |||
1119 | // Calculate Kq = E(S + a_qi) (+) E(S - r_qi) | ||
1120 | for (i = 0; i < count; i++) | ||
1121 | { | ||
1122 | // E(S - r_qi) | ||
1123 | gcry_mpi_sub (tmp, my_offset, rand[q[i]]); | ||
1124 | GNUNET_assert (2 == GNUNET_CRYPTO_paillier_encrypt (&session->remote_pubkey, | ||
1125 | tmp, | ||
1126 | 2, | ||
1127 | &r_prime[i])); | ||
1128 | |||
1129 | // E(S - r_qi) * E(S + a_qi) == E(2*S + a_qi - r_qi) | ||
1130 | GNUNET_assert (1 == GNUNET_CRYPTO_paillier_hom_add (&session->remote_pubkey, | ||
1131 | &r_prime[i], | ||
1132 | &a[q[i]], | ||
1133 | &r_prime[i])); | ||
1134 | } | ||
1135 | |||
1136 | // Calculate S' = E(SUM( r_i^2 )) | ||
1137 | tmp = compute_square_sum (rand, count); | ||
1138 | GNUNET_CRYPTO_paillier_encrypt (&session->remote_pubkey, | ||
1139 | tmp, | ||
1140 | 1, | ||
1141 | &session->s_prime); | ||
1142 | |||
1143 | // Calculate S = E(SUM( (r_i + b_i)^2 )) | ||
1144 | for (i = 0; i < count; i++) | ||
1145 | gcry_mpi_add (rand[i], rand[i], b[i]); | ||
1146 | tmp = compute_square_sum (rand, count); | ||
1147 | GNUNET_CRYPTO_paillier_encrypt (&session->remote_pubkey, | ||
1148 | tmp, | ||
1149 | 1, | ||
1150 | &session->s); | ||
1151 | |||
1152 | session->r = r; | ||
1153 | session->r_prime = r_prime; | ||
1154 | |||
1155 | // release rand, b and a | ||
1156 | for (i = 0; i < count; i++) | ||
1157 | { | ||
1158 | gcry_mpi_release (rand[i]); | ||
1159 | gcry_mpi_release (b[i]); | ||
1160 | } | ||
1161 | gcry_mpi_release (tmp); | ||
1162 | GNUNET_free (session->e_a); | ||
1163 | session->e_a = NULL; | ||
1164 | GNUNET_free (p); | ||
1165 | GNUNET_free (q); | ||
1166 | GNUNET_free (b); | ||
1167 | GNUNET_free (rand); | ||
1168 | |||
1169 | // copy the r[], r_prime[], S and Stick into a new message, prepare_service_response frees these | ||
1170 | GNUNET_SCHEDULER_add_now (&prepare_bobs_cryptodata_message, | ||
1171 | session); | ||
1172 | } | ||
1173 | |||
1174 | |||
1175 | /** | ||
1176 | * Iterator over all hash map entries in session->intersected_elements. | ||
1177 | * | ||
1178 | * @param cls closure | ||
1179 | * @param key current key code | ||
1180 | * @param value value in the hash map | ||
1181 | * @return #GNUNET_YES if we should continue to | ||
1182 | * iterate, | ||
1183 | * #GNUNET_NO if not. | ||
1184 | */ | ||
1185 | static int | ||
1186 | cb_insert_element_sorted (void *cls, | ||
1187 | const struct GNUNET_HashCode *key, | ||
1188 | void *value) | ||
1189 | { | ||
1190 | struct ServiceSession * s = cls; | ||
1191 | struct SortedValue * e = GNUNET_new (struct SortedValue); | ||
1192 | struct SortedValue * o = s->a_head; | ||
1193 | int64_t val; | ||
1194 | |||
1195 | e->elem = value; | ||
1196 | e->val = gcry_mpi_new (0); | ||
1197 | val = (int64_t) GNUNET_ntohll (e->elem->value); | ||
1198 | if (0 > val) | ||
1199 | gcry_mpi_sub_ui (e->val, e->val, -val); | ||
1200 | else | ||
1201 | gcry_mpi_add_ui (e->val, e->val, val); | ||
1202 | |||
1203 | // insert as first element with the lowest key | ||
1204 | if (NULL == s->a_head | ||
1205 | || (0 <= GNUNET_CRYPTO_hash_cmp (&s->a_head->elem->key, | ||
1206 | &e->elem->key))) | ||
1207 | { | ||
1208 | GNUNET_CONTAINER_DLL_insert (s->a_head, | ||
1209 | s->a_tail, | ||
1210 | e); | ||
1211 | return GNUNET_YES; | ||
1212 | } | ||
1213 | else if (0 > GNUNET_CRYPTO_hash_cmp (&s->a_tail->elem->key, | ||
1214 | &e->elem->key)) | ||
1215 | { | ||
1216 | // insert as last element with the highest key | ||
1217 | GNUNET_CONTAINER_DLL_insert_tail (s->a_head, | ||
1218 | s->a_tail, | ||
1219 | e); | ||
1220 | return GNUNET_YES; | ||
1221 | } | ||
1222 | // insert before the first higher/equal element | ||
1223 | do | ||
1224 | { | ||
1225 | if (0 <= GNUNET_CRYPTO_hash_cmp (&o->elem->key, | ||
1226 | &e->elem->key)) | ||
1227 | { | ||
1228 | GNUNET_CONTAINER_DLL_insert_before (s->a_head, | ||
1229 | s->a_tail, | ||
1230 | o, | ||
1231 | e); | ||
1232 | return GNUNET_YES; | ||
1233 | } | ||
1234 | o = o->next; | ||
1235 | } | ||
1236 | while (NULL != o); | ||
1237 | // broken DLL | ||
1238 | GNUNET_assert (0); | ||
1239 | } | ||
1240 | |||
1241 | |||
1242 | /** | ||
1243 | * Callback for set operation results. Called for each element | ||
1244 | * in the result set. | ||
1245 | * | ||
1246 | * @param cls closure | ||
1247 | * @param element a result element, only valid if status is #GNUNET_SET_STATUS_OK | ||
1248 | * @param status see `enum GNUNET_SET_Status` | ||
1249 | */ | ||
1250 | static void | ||
1251 | cb_intersection_element_removed (void *cls, | ||
1252 | const struct GNUNET_SET_Element *element, | ||
1253 | enum GNUNET_SET_Status status) | ||
1254 | { | ||
1255 | struct ServiceSession * s = cls; | ||
1256 | struct GNUNET_SCALARPRODUCT_Element * se; | ||
1257 | int i; | ||
1258 | |||
1259 | switch (status) | ||
1260 | { | ||
1261 | case GNUNET_SET_STATUS_OK: | ||
1262 | //this element has been removed from the set | ||
1263 | se = GNUNET_CONTAINER_multihashmap_get (s->intersected_elements, | ||
1264 | element->data); | ||
1265 | |||
1266 | GNUNET_CONTAINER_multihashmap_remove (s->intersected_elements, | ||
1267 | element->data, | ||
1268 | se); | ||
1269 | LOG (GNUNET_ERROR_TYPE_DEBUG, | ||
1270 | "%s: removed element with key %s value %d\n", | ||
1271 | s->role == ALICE ? "ALICE" : "BOB", | ||
1272 | GNUNET_h2s(&se->key), | ||
1273 | se->value); | ||
1274 | return; | ||
1275 | |||
1276 | case GNUNET_SET_STATUS_DONE: | ||
1277 | s->intersection_op = NULL; | ||
1278 | s->intersection_set = NULL; | ||
1279 | |||
1280 | s->used_element_count | ||
1281 | = GNUNET_CONTAINER_multihashmap_iterate (s->intersected_elements, | ||
1282 | &cb_insert_element_sorted, | ||
1283 | s); | ||
1284 | LOG (GNUNET_ERROR_TYPE_DEBUG, | ||
1285 | "%s: Finished intersection, %d items remain\n", | ||
1286 | s->role == ALICE ? "ALICE" : "BOB", | ||
1287 | s->used_element_count); | ||
1288 | if (2 > s->used_element_count) | ||
1289 | { | ||
1290 | // failed! do not leak information about our single remaining element! | ||
1291 | // continue after the loop | ||
1292 | break; | ||
1293 | } | ||
1294 | |||
1295 | s->sorted_elements = GNUNET_malloc (s->used_element_count * sizeof (gcry_mpi_t)); | ||
1296 | for (i = 0; NULL != s->a_head; i++) | ||
1297 | { | ||
1298 | struct SortedValue* a = s->a_head; | ||
1299 | GNUNET_assert (i < s->used_element_count); | ||
1300 | |||
1301 | s->sorted_elements[i] = a->val; | ||
1302 | GNUNET_CONTAINER_DLL_remove (s->a_head, s->a_tail, a); | ||
1303 | GNUNET_free (a->elem); | ||
1304 | } | ||
1305 | GNUNET_assert (i == s->used_element_count); | ||
1306 | |||
1307 | if (ALICE == s->role) { | ||
1308 | prepare_alices_cyrptodata_message (s); | ||
1309 | return; | ||
1310 | } | ||
1311 | else if (s->used_element_count == s->transferred_element_count) | ||
1312 | { | ||
1313 | compute_service_response (s); | ||
1314 | return; | ||
1315 | } | ||
1316 | break; | ||
1317 | default: | ||
1318 | LOG (GNUNET_ERROR_TYPE_DEBUG, "%s: OOOPS %d", s->role == ALICE ? "ALICE" : "BOB", status); | ||
1319 | if (NULL != s->intersection_listen) | ||
1320 | { | ||
1321 | GNUNET_SET_listen_cancel (s->intersection_listen); | ||
1322 | s->intersection_listen = NULL; | ||
1323 | } | ||
1324 | |||
1325 | // the op failed and has already been invalidated by the set service | ||
1326 | break; | ||
1327 | } | ||
1328 | |||
1329 | s->intersection_op = NULL; | ||
1330 | s->intersection_set = NULL; | ||
1331 | |||
1332 | //failed if we go here | ||
1333 | GNUNET_break_op (0); | ||
1334 | |||
1335 | // and notify our client-session that we could not complete the session | ||
1336 | if (ALICE == s->role) { | ||
1337 | s->active = GNUNET_SYSERR; | ||
1338 | s->client_notification_task = | ||
1339 | GNUNET_SCHEDULER_add_now (&prepare_client_end_notification, | ||
1340 | s); | ||
1341 | } | ||
1342 | else | ||
1343 | { | ||
1344 | GNUNET_CONTAINER_DLL_remove (from_service_head, | ||
1345 | from_service_tail, | ||
1346 | s); | ||
1347 | free_session_variables (s); | ||
1348 | s->response->active = GNUNET_SYSERR; | ||
1349 | s->response->client_notification_task = | ||
1350 | GNUNET_SCHEDULER_add_now (&prepare_client_end_notification, | ||
1351 | s->response); | ||
1352 | GNUNET_free(s); | ||
1353 | } | ||
1354 | } | ||
1355 | |||
1356 | |||
1357 | /** | ||
1358 | * Called when another peer wants to do a set operation with the | ||
1359 | * local peer. If a listen error occurs, the @a request is NULL. | ||
1360 | * | ||
1361 | * @param cls closure | ||
1362 | * @param other_peer the other peer | ||
1363 | * @param context_msg message with application specific information from | ||
1364 | * the other peer | ||
1365 | * @param request request from the other peer (never NULL), use GNUNET_SET_accept() | ||
1366 | * to accept it, otherwise the request will be refused | ||
1367 | * Note that we can't just return value from the listen callback, | ||
1368 | * as it is also necessary to specify the set we want to do the | ||
1369 | * operation with, whith sometimes can be derived from the context | ||
1370 | * message. It's necessary to specify the timeout. | ||
1371 | */ | ||
1372 | static void | ||
1373 | cb_intersection_request_alice (void *cls, | ||
1374 | const struct GNUNET_PeerIdentity *other_peer, | ||
1375 | const struct GNUNET_MessageHeader *context_msg, | ||
1376 | struct GNUNET_SET_Request *request) | ||
1377 | { | ||
1378 | struct ServiceSession * s = cls; | ||
1379 | |||
1380 | s->intersection_op = GNUNET_SET_accept (request, | ||
1381 | GNUNET_SET_RESULT_REMOVED, | ||
1382 | cb_intersection_element_removed, | ||
1383 | s); | ||
1384 | if (NULL == s->intersection_op) | ||
1385 | { | ||
1386 | s->active = GNUNET_SYSERR; | ||
1387 | s->client_notification_task = | ||
1388 | GNUNET_SCHEDULER_add_now (&prepare_client_end_notification, | ||
1389 | s); | ||
1390 | return; | ||
1391 | } | ||
1392 | if (GNUNET_OK != GNUNET_SET_commit (s->intersection_op, s->intersection_set)) | ||
1393 | { | ||
1394 | s->active = GNUNET_SYSERR; | ||
1395 | s->client_notification_task = | ||
1396 | GNUNET_SCHEDULER_add_now (&prepare_client_end_notification, | ||
1397 | s); | ||
1398 | return; | ||
1399 | } | ||
1400 | s->intersection_set = NULL; | ||
1401 | s->intersection_listen = NULL; | ||
1402 | } | ||
1403 | |||
1404 | |||
1405 | /** | ||
1406 | * prepare the response we will send to alice or bobs' clients. | ||
1407 | * in Bobs case the product will be NULL. | ||
1408 | * | ||
1409 | * @param cls the session associated with our client. | ||
1410 | * @param tc the task context handed to us by the scheduler, unused | ||
1411 | */ | ||
1412 | static void | ||
1413 | prepare_client_response (void *cls, | ||
1414 | const struct GNUNET_SCHEDULER_TaskContext *tc) | ||
1415 | { | ||
1416 | struct ServiceSession * s = cls; | ||
1417 | struct ClientResponseMessage *msg; | ||
1418 | unsigned char * product_exported = NULL; | ||
1419 | size_t product_length = 0; | ||
1420 | uint32_t msg_length = 0; | ||
1421 | int8_t range = -1; | ||
1422 | gcry_error_t rc; | ||
1423 | int sign; | ||
1424 | |||
1425 | s->client_notification_task = GNUNET_SCHEDULER_NO_TASK; | ||
1426 | |||
1427 | if (s->product) | ||
1428 | { | ||
1429 | gcry_mpi_t value = gcry_mpi_new (0); | ||
1430 | |||
1431 | sign = gcry_mpi_cmp_ui (s->product, 0); | ||
1432 | // libgcrypt can not handle a print of a negative number | ||
1433 | // if (a->sign) return gcry_error (GPG_ERR_INTERNAL); /* Can't handle it yet. */ | ||
1434 | if (0 > sign) | ||
1435 | { | ||
1436 | gcry_mpi_sub (value, value, s->product); | ||
1437 | } | ||
1438 | else if (0 < sign) | ||
1439 | { | ||
1440 | range = 1; | ||
1441 | gcry_mpi_add (value, value, s->product); | ||
1442 | } | ||
1443 | else | ||
1444 | range = 0; | ||
1445 | |||
1446 | gcry_mpi_release (s->product); | ||
1447 | s->product = NULL; | ||
1448 | |||
1449 | // get representation as string | ||
1450 | if (range | ||
1451 | && (0 != (rc = gcry_mpi_aprint (GCRYMPI_FMT_STD, | ||
1452 | &product_exported, | ||
1453 | &product_length, | ||
1454 | value)))) | ||
1455 | { | ||
1456 | LOG_GCRY (GNUNET_ERROR_TYPE_ERROR, | ||
1457 | "gcry_mpi_scan", | ||
1458 | rc); | ||
1459 | product_length = 0; | ||
1460 | range = -1; // signal error with product-length = 0 and range = -1 | ||
1461 | } | ||
1462 | gcry_mpi_release (value); | ||
1463 | } | ||
1464 | |||
1465 | msg_length = sizeof (struct ClientResponseMessage) + product_length; | ||
1466 | msg = GNUNET_malloc (msg_length); | ||
1467 | if (NULL != product_exported) | ||
1468 | { | ||
1469 | memcpy (&msg[1], | ||
1470 | product_exported, | ||
1471 | product_length); | ||
1472 | GNUNET_free (product_exported); | ||
1473 | } | ||
1474 | msg->header.type = htons (GNUNET_MESSAGE_TYPE_SCALARPRODUCT_RESULT); | ||
1475 | msg->header.size = htons (msg_length); | ||
1476 | msg->range = range; | ||
1477 | msg->product_length = htonl (product_length); | ||
1478 | s->msg = (struct GNUNET_MessageHeader *) msg; | ||
1479 | s->client_transmit_handle = | ||
1480 | GNUNET_SERVER_notify_transmit_ready (s->client, | ||
1481 | msg_length, | ||
1482 | GNUNET_TIME_UNIT_FOREVER_REL, | ||
1483 | &cb_transfer_message, | ||
1484 | s); | ||
1485 | GNUNET_break (NULL != s->client_transmit_handle); | ||
1486 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
1487 | "Sent result to client (%p), this session (%s) has ended!\n", | ||
1488 | s->client, | ||
1489 | GNUNET_h2s (&s->session_id)); | ||
1490 | } | ||
1491 | |||
1492 | |||
1493 | /** | ||
1494 | * Executed by Alice, fills in a service-request message and sends it to the given peer | ||
1495 | * | ||
1496 | * @param session the session associated with this request | ||
1497 | */ | ||
1498 | static void | ||
1499 | prepare_alices_computation_request (struct ServiceSession * s) | ||
1500 | { | ||
1501 | struct ServiceRequestMessage * msg; | ||
1502 | |||
1503 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
1504 | _("Successfully created new channel to peer (%s)!\n"), | ||
1505 | GNUNET_i2s (&s->peer)); | ||
1506 | |||
1507 | msg = GNUNET_new (struct ServiceRequestMessage); | ||
1508 | msg->header.type = htons (GNUNET_MESSAGE_TYPE_SCALARPRODUCT_SESSION_INITIALIZATION); | ||
1509 | memcpy (&msg->session_id, &s->session_id, sizeof (struct GNUNET_HashCode)); | ||
1510 | msg->header.size = htons (sizeof (struct ServiceRequestMessage)); | ||
1511 | |||
1512 | s->msg = (struct GNUNET_MessageHeader *) msg; | ||
1513 | GNUNET_log (GNUNET_ERROR_TYPE_INFO, | ||
1514 | _("Transmitting service request.\n")); | ||
1515 | |||
1516 | //transmit via cadet messaging | ||
1517 | s->service_transmit_handle | ||
1518 | = GNUNET_CADET_notify_transmit_ready (s->channel, GNUNET_YES, | ||
1519 | GNUNET_TIME_UNIT_FOREVER_REL, | ||
1520 | sizeof (struct ServiceRequestMessage), | ||
1521 | &cb_transfer_message, | ||
1522 | s); | ||
1523 | if (! s->service_transmit_handle) | ||
1524 | { | ||
1525 | GNUNET_log (GNUNET_ERROR_TYPE_ERROR, | ||
1526 | _("Could not send message to channel!\n")); | ||
1527 | GNUNET_free (msg); | ||
1528 | s->msg = NULL; | ||
1529 | s->active = GNUNET_SYSERR; | ||
1530 | s->client_notification_task = | ||
1531 | GNUNET_SCHEDULER_add_now (&prepare_client_end_notification, | ||
1532 | s); | ||
1533 | return; | ||
1534 | } | ||
1535 | } | ||
1536 | |||
1537 | |||
1538 | /** | ||
1539 | * Send a multi part chunk of a service request from alice to bob. | ||
1540 | * This element only contains a part of the elements-vector (session->a[]), | ||
1541 | * mask and public key set have to be contained within the first message | ||
1542 | * | ||
1543 | * This allows a ~32kbit key length while using 32000 elements or 62000 elements per request. | ||
1544 | * | ||
1545 | * @param cls the associated service session | ||
1546 | */ | ||
1547 | static void | ||
1548 | prepare_alices_cyrptodata_message_multipart (void *cls) | ||
1549 | { | ||
1550 | struct ServiceSession * s = cls; | ||
1551 | struct MultipartMessage * msg; | ||
1552 | struct GNUNET_CRYPTO_PaillierCiphertext * payload; | ||
1553 | unsigned int i; | ||
1554 | uint32_t msg_length; | ||
1555 | uint32_t todo_count; | ||
1556 | gcry_mpi_t a; | ||
1557 | |||
1558 | msg_length = sizeof (struct MultipartMessage); | ||
1559 | todo_count = s->used_element_count - s->transferred_element_count; | ||
1560 | |||
1561 | if (todo_count > MULTIPART_ELEMENT_CAPACITY) | ||
1562 | // send the currently possible maximum chunk | ||
1563 | todo_count = MULTIPART_ELEMENT_CAPACITY; | ||
1564 | |||
1565 | msg_length += todo_count * sizeof (struct GNUNET_CRYPTO_PaillierCiphertext); | ||
1566 | msg = GNUNET_malloc (msg_length); | ||
1567 | msg->header.type = htons (GNUNET_MESSAGE_TYPE_SCALARPRODUCT_ALICE_CRYPTODATA_MULTIPART); | ||
1568 | msg->header.size = htons (msg_length); | ||
1569 | msg->contained_element_count = htonl (todo_count); | ||
1570 | |||
1571 | payload = (struct GNUNET_CRYPTO_PaillierCiphertext *) &msg[1]; | ||
1572 | |||
1573 | // now copy over the sorted element vector | ||
1574 | a = gcry_mpi_new (0); | ||
1575 | for (i = s->transferred_element_count; i < todo_count; i++) | ||
1576 | { | ||
1577 | gcry_mpi_add (a, s->sorted_elements[i], my_offset); | ||
1578 | GNUNET_CRYPTO_paillier_encrypt (&my_pubkey, a, 3, &payload[i - s->transferred_element_count]); | ||
1579 | } | ||
1580 | gcry_mpi_release (a); | ||
1581 | s->transferred_element_count += todo_count; | ||
1582 | |||
1583 | s->msg = (struct GNUNET_MessageHeader *) msg; | ||
1584 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
1585 | "Transmitting service request.\n"); | ||
1586 | |||
1587 | //transmit via cadet messaging | ||
1588 | s->service_transmit_handle | ||
1589 | = GNUNET_CADET_notify_transmit_ready (s->channel, | ||
1590 | GNUNET_YES, | ||
1591 | GNUNET_TIME_UNIT_FOREVER_REL, | ||
1592 | msg_length, | ||
1593 | &cb_transfer_message, | ||
1594 | s); | ||
1595 | if (!s->service_transmit_handle) | ||
1596 | { | ||
1597 | GNUNET_log (GNUNET_ERROR_TYPE_ERROR, | ||
1598 | _("Could not send service-request multipart message to channel!\n")); | ||
1599 | GNUNET_free (msg); | ||
1600 | s->msg = NULL; | ||
1601 | s->active = GNUNET_SYSERR; | ||
1602 | s->client_notification_task | ||
1603 | = GNUNET_SCHEDULER_add_now (&prepare_client_end_notification, | ||
1604 | s); | ||
1605 | return; | ||
1606 | } | ||
1607 | } | ||
1608 | |||
1609 | |||
1610 | /** | ||
1611 | * Our client has finished sending us its multipart message. | ||
1612 | * | ||
1613 | * @param session the service session context | ||
1614 | */ | ||
1615 | static void | ||
1616 | client_request_complete_bob (struct ServiceSession * client_session) | ||
1617 | { | ||
1618 | struct ServiceSession * s; | ||
1619 | |||
1620 | //check if service queue contains a matching request | ||
1621 | s = find_matching_session (from_service_tail, | ||
1622 | &client_session->session_id, | ||
1623 | NULL); | ||
1624 | if (NULL != s) | ||
1625 | { | ||
1626 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
1627 | "Got client-responder-session with key %s and a matching service-request-session set, processing.\n", | ||
1628 | GNUNET_h2s (&client_session->session_id)); | ||
1629 | |||
1630 | s->response = client_session; | ||
1631 | s->intersected_elements = client_session->intersected_elements; | ||
1632 | client_session->intersected_elements = NULL; | ||
1633 | s->intersection_set = client_session->intersection_set; | ||
1634 | client_session->intersection_set = NULL; | ||
1635 | |||
1636 | s->intersection_op = GNUNET_SET_prepare (&s->peer, | ||
1637 | &s->session_id, | ||
1638 | NULL, | ||
1639 | GNUNET_SET_RESULT_REMOVED, | ||
1640 | cb_intersection_element_removed, | ||
1641 | s); | ||
1642 | |||
1643 | GNUNET_SET_commit (s->intersection_op, s->intersection_set); | ||
1644 | } | ||
1645 | else | ||
1646 | { | ||
1647 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
1648 | "Got client-responder-session with key %s but NO matching service-request-session set, queuing element for later use.\n", | ||
1649 | GNUNET_h2s (&client_session->session_id)); | ||
1650 | // no matching session exists yet, store the response | ||
1651 | // for later processing by handle_service_request() | ||
1652 | } | ||
1653 | } | ||
1654 | |||
1655 | |||
1656 | /** | ||
1657 | * Our client has finished sending us its multipart message. | ||
1658 | * | ||
1659 | * @param session the service session context | ||
1660 | */ | ||
1661 | static void | ||
1662 | client_request_complete_alice (struct ServiceSession * s) | ||
1663 | { | ||
1664 | GNUNET_log (GNUNET_ERROR_TYPE_INFO, | ||
1665 | _ ("Creating new channel for session with key %s.\n"), | ||
1666 | GNUNET_h2s (&s->session_id)); | ||
1667 | s->channel = GNUNET_CADET_channel_create (my_cadet, s, | ||
1668 | &s->peer, | ||
1669 | GNUNET_APPLICATION_TYPE_SCALARPRODUCT, | ||
1670 | GNUNET_CADET_OPTION_RELIABLE); | ||
1671 | if (NULL == s->channel) | ||
1672 | { | ||
1673 | s->active = GNUNET_SYSERR; | ||
1674 | s->client_notification_task = | ||
1675 | GNUNET_SCHEDULER_add_now (&prepare_client_end_notification, | ||
1676 | s); | ||
1677 | return; | ||
1678 | } | ||
1679 | s->intersection_listen = GNUNET_SET_listen (cfg, | ||
1680 | GNUNET_SET_OPERATION_INTERSECTION, | ||
1681 | &s->session_id, | ||
1682 | cb_intersection_request_alice, | ||
1683 | s); | ||
1684 | if (NULL == s->intersection_listen) | ||
1685 | { | ||
1686 | s->active = GNUNET_SYSERR; | ||
1687 | s->client_notification_task = | ||
1688 | GNUNET_SCHEDULER_add_now (&prepare_client_end_notification, | ||
1689 | s); | ||
1690 | return; | ||
1691 | } | ||
1692 | prepare_alices_computation_request (s); | ||
1693 | } | ||
1694 | |||
1695 | |||
1696 | static void | ||
1697 | handle_client_message_multipart (void *cls, | ||
1698 | struct GNUNET_SERVER_Client *client, | ||
1699 | const struct GNUNET_MessageHeader *message) | ||
1700 | { | ||
1701 | const struct ComputationMultipartMessage * msg; | ||
1702 | struct ServiceSession *s; | ||
1703 | uint32_t contained_count; | ||
1704 | struct GNUNET_SCALARPRODUCT_Element *elements; | ||
1705 | uint32_t i; | ||
1706 | |||
1707 | msg = (const struct ComputationMultipartMessage *) message; | ||
1708 | // only one concurrent session per client connection allowed, simplifies logics a lot... | ||
1709 | s = GNUNET_SERVER_client_get_user_context (client, struct ServiceSession); | ||
1710 | if (NULL == s) | ||
1711 | { | ||
1712 | GNUNET_SERVER_receive_done (client, GNUNET_OK); | ||
1713 | return; | ||
1714 | } | ||
1715 | |||
1716 | contained_count = ntohl (msg->element_count_contained); | ||
1717 | |||
1718 | //sanity check: is the message as long as the message_count fields suggests? | ||
1719 | if ( (ntohs (msg->header.size) != (sizeof (struct ComputationMultipartMessage) + contained_count * sizeof (struct GNUNET_SCALARPRODUCT_Element))) || | ||
1720 | (0 == contained_count) || | ||
1721 | (s->total < s->transferred_element_count + contained_count)) | ||
1722 | { | ||
1723 | GNUNET_break_op (0); | ||
1724 | GNUNET_SERVER_receive_done (client, GNUNET_OK); | ||
1725 | return; | ||
1726 | } | ||
1727 | s->transferred_element_count += contained_count; | ||
1728 | |||
1729 | elements = (struct GNUNET_SCALARPRODUCT_Element *) & msg[1]; | ||
1730 | for (i = 0; i < contained_count; i++) | ||
1731 | { | ||
1732 | struct GNUNET_SET_Element set_elem; | ||
1733 | struct GNUNET_SCALARPRODUCT_Element * elem; | ||
1734 | |||
1735 | if (0 == GNUNET_ntohll (elements[i].value)) | ||
1736 | continue; | ||
1737 | |||
1738 | elem = GNUNET_new (struct GNUNET_SCALARPRODUCT_Element); | ||
1739 | memcpy (elem, &elements[i], sizeof (struct GNUNET_SCALARPRODUCT_Element)); | ||
1740 | |||
1741 | if (GNUNET_SYSERR == GNUNET_CONTAINER_multihashmap_put (s->intersected_elements, | ||
1742 | &elem->key, | ||
1743 | elem, | ||
1744 | GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY)) | ||
1745 | { | ||
1746 | GNUNET_free (elem); | ||
1747 | continue; | ||
1748 | } | ||
1749 | set_elem.data = &elem->key; | ||
1750 | set_elem.size = sizeof (elem->key); | ||
1751 | set_elem.element_type = 0; /* do we REALLY need this? */ | ||
1752 | GNUNET_SET_add_element (s->intersection_set, &set_elem, NULL, NULL); | ||
1753 | s->used_element_count++; | ||
1754 | } | ||
1755 | |||
1756 | GNUNET_SERVER_receive_done (client, GNUNET_OK); | ||
1757 | |||
1758 | if (s->total != s->transferred_element_count) | ||
1759 | // multipart msg | ||
1760 | return; | ||
1761 | |||
1762 | if (ALICE == s->role) | ||
1763 | client_request_complete_alice (s); | ||
1764 | else | ||
1765 | client_request_complete_bob (s); | ||
1766 | } | ||
1767 | |||
1768 | |||
1769 | /** | ||
1770 | * Handler for a client request message. | ||
1771 | * Can either be type A or B | ||
1772 | * A: request-initiation to compute a scalar product with a peer | ||
1773 | * B: response role, keep the values + session and wait for a matching session or process a waiting request | ||
1774 | * | ||
1775 | * @param cls closure | ||
1776 | * @param client identification of the client | ||
1777 | * @param message the actual message | ||
1778 | */ | ||
1779 | static void | ||
1780 | handle_client_message (void *cls, | ||
1781 | struct GNUNET_SERVER_Client *client, | ||
1782 | const struct GNUNET_MessageHeader *message) | ||
1783 | { | ||
1784 | const struct ComputationMessage * msg = (const struct ComputationMessage *) message; | ||
1785 | struct ServiceSession * s; | ||
1786 | uint32_t contained_count; | ||
1787 | uint32_t total_count; | ||
1788 | uint32_t msg_type; | ||
1789 | struct GNUNET_SCALARPRODUCT_Element * elements; | ||
1790 | uint32_t i; | ||
1791 | |||
1792 | // only one concurrent session per client connection allowed, simplifies logics a lot... | ||
1793 | s = GNUNET_SERVER_client_get_user_context (client, struct ServiceSession); | ||
1794 | if (NULL != s) | ||
1795 | { | ||
1796 | GNUNET_SERVER_receive_done (client, GNUNET_OK); | ||
1797 | return; | ||
1798 | } | ||
1799 | |||
1800 | msg_type = ntohs (msg->header.type); | ||
1801 | total_count = ntohl (msg->element_count_total); | ||
1802 | contained_count = ntohl (msg->element_count_contained); | ||
1803 | |||
1804 | if ((GNUNET_MESSAGE_TYPE_SCALARPRODUCT_CLIENT_TO_ALICE == msg_type) | ||
1805 | && (!memcmp (&msg->peer, &me, sizeof (struct GNUNET_PeerIdentity)))) | ||
1806 | { | ||
1807 | //session with ourself makes no sense! | ||
1808 | GNUNET_break_op (0); | ||
1809 | GNUNET_SERVER_receive_done (client, GNUNET_SYSERR); | ||
1810 | return; | ||
1811 | } | ||
1812 | |||
1813 | //sanity check: is the message as long as the message_count fields suggests? | ||
1814 | if ((ntohs (msg->header.size) != | ||
1815 | (sizeof (struct ComputationMessage) + contained_count * sizeof (struct GNUNET_SCALARPRODUCT_Element))) | ||
1816 | || (0 == total_count)) | ||
1817 | { | ||
1818 | GNUNET_break_op (0); | ||
1819 | GNUNET_SERVER_receive_done (client, GNUNET_SYSERR); | ||
1820 | return; | ||
1821 | } | ||
1822 | |||
1823 | // do we have a duplicate session here already? | ||
1824 | if (NULL != find_matching_session (from_client_tail, | ||
1825 | &msg->session_key, | ||
1826 | NULL)) | ||
1827 | { | ||
1828 | GNUNET_log (GNUNET_ERROR_TYPE_WARNING, | ||
1829 | _ ("Duplicate session information received, can not create new session with key `%s'\n"), | ||
1830 | GNUNET_h2s (&msg->session_key)); | ||
1831 | GNUNET_SERVER_receive_done (client, GNUNET_SYSERR); | ||
1832 | return; | ||
1833 | } | ||
1834 | |||
1835 | s = GNUNET_new (struct ServiceSession); | ||
1836 | s->active = GNUNET_YES; | ||
1837 | s->client_notification_task = GNUNET_SCHEDULER_NO_TASK; | ||
1838 | s->client = client; | ||
1839 | s->total = total_count; | ||
1840 | s->transferred_element_count = contained_count; | ||
1841 | // get our transaction key | ||
1842 | memcpy (&s->session_id, &msg->session_key, sizeof (struct GNUNET_HashCode)); | ||
1843 | |||
1844 | elements = (struct GNUNET_SCALARPRODUCT_Element *) & msg[1]; | ||
1845 | s->intersected_elements = GNUNET_CONTAINER_multihashmap_create (s->total, GNUNET_NO); | ||
1846 | s->intersection_set = GNUNET_SET_create (cfg, GNUNET_SET_OPERATION_INTERSECTION); | ||
1847 | for (i = 0; i < contained_count; i++) | ||
1848 | { | ||
1849 | struct GNUNET_SET_Element set_elem; | ||
1850 | struct GNUNET_SCALARPRODUCT_Element * elem; | ||
1851 | |||
1852 | if (0 == GNUNET_ntohll (elements[i].value)) | ||
1853 | continue; | ||
1854 | |||
1855 | elem = GNUNET_new (struct GNUNET_SCALARPRODUCT_Element); | ||
1856 | memcpy (elem, &elements[i], sizeof (struct GNUNET_SCALARPRODUCT_Element)); | ||
1857 | |||
1858 | if (GNUNET_SYSERR == | ||
1859 | GNUNET_CONTAINER_multihashmap_put (s->intersected_elements, | ||
1860 | &elem->key, | ||
1861 | elem, | ||
1862 | GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY)) | ||
1863 | { | ||
1864 | GNUNET_free (elem); | ||
1865 | continue; | ||
1866 | } | ||
1867 | set_elem.data = &elem->key; | ||
1868 | set_elem.size = sizeof (elem->key); | ||
1869 | set_elem.element_type = 0; | ||
1870 | GNUNET_SET_add_element (s->intersection_set, &set_elem, NULL, NULL); | ||
1871 | s->used_element_count++; | ||
1872 | } | ||
1873 | |||
1874 | if (GNUNET_MESSAGE_TYPE_SCALARPRODUCT_CLIENT_TO_ALICE == msg_type) | ||
1875 | { | ||
1876 | s->role = ALICE; | ||
1877 | memcpy (&s->peer, | ||
1878 | &msg->peer, | ||
1879 | sizeof (struct GNUNET_PeerIdentity)); | ||
1880 | } | ||
1881 | else | ||
1882 | { | ||
1883 | s->role = BOB; | ||
1884 | } | ||
1885 | |||
1886 | GNUNET_CONTAINER_DLL_insert (from_client_head, | ||
1887 | from_client_tail, | ||
1888 | s); | ||
1889 | GNUNET_SERVER_client_set_user_context (client, s); | ||
1890 | GNUNET_SERVER_receive_done (client, GNUNET_YES); | ||
1891 | |||
1892 | if (s->total != s->transferred_element_count) | ||
1893 | // multipart msg | ||
1894 | return; | ||
1895 | |||
1896 | if (ALICE == s->role) | ||
1897 | client_request_complete_alice (s); | ||
1898 | else | ||
1899 | client_request_complete_bob (s); | ||
1900 | } | ||
1901 | |||
1902 | |||
1903 | /** | ||
1904 | * Function called for inbound channels. | ||
1905 | * | ||
1906 | * @param cls closure | ||
1907 | * @param channel new handle to the channel | ||
1908 | * @param initiator peer that started the channel | ||
1909 | * @param port unused | ||
1910 | * @param options unused | ||
1911 | * @return session associated with the channel | ||
1912 | */ | ||
1913 | static void * | ||
1914 | cb_channel_incoming (void *cls, | ||
1915 | struct GNUNET_CADET_Channel *channel, | ||
1916 | const struct GNUNET_PeerIdentity *initiator, | ||
1917 | uint32_t port, | ||
1918 | enum GNUNET_CADET_ChannelOption options) | ||
1919 | { | ||
1920 | struct ServiceSession *s; | ||
1921 | |||
1922 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
1923 | _ ("New incoming channel from peer %s.\n"), | ||
1924 | GNUNET_i2s (initiator)); | ||
1925 | s = GNUNET_new (struct ServiceSession); | ||
1926 | s->peer = *initiator; | ||
1927 | s->channel = channel; | ||
1928 | s->role = BOB; | ||
1929 | s->active = GNUNET_YES; | ||
1930 | return s; | ||
1931 | } | ||
1932 | |||
1933 | |||
1934 | /** | ||
1935 | * Function called whenever a channel is destroyed. Should clean up | ||
1936 | * any associated state. | ||
1937 | * | ||
1938 | * It must NOT call #GNUNET_CADET_channel_destroy() on the channel. | ||
1939 | * | ||
1940 | * @param cls closure (set from #GNUNET_CADET_connect()) | ||
1941 | * @param channel connection to the other end (henceforth invalid) | ||
1942 | * @param channel_ctx place where local state associated | ||
1943 | * with the channel is stored | ||
1944 | */ | ||
1945 | static void | ||
1946 | cb_channel_destruction (void *cls, | ||
1947 | const struct GNUNET_CADET_Channel *channel, | ||
1948 | void *channel_ctx) | ||
1949 | { | ||
1950 | struct ServiceSession * s = channel_ctx; | ||
1951 | struct ServiceSession * client_session; | ||
1952 | |||
1953 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
1954 | "Peer disconnected, terminating session %s with peer (%s)\n", | ||
1955 | GNUNET_h2s (&s->session_id), | ||
1956 | GNUNET_i2s (&s->peer)); | ||
1957 | |||
1958 | // as we have only one peer connected in each session, just remove the session | ||
1959 | s->channel = NULL; | ||
1960 | |||
1961 | if ( (ALICE == s->role) && | ||
1962 | (GNUNET_YES == s->active) && | ||
1963 | (! do_shutdown) ) | ||
1964 | { | ||
1965 | // if this happened before we received the answer, we must terminate the session | ||
1966 | s->role = GNUNET_SYSERR; | ||
1967 | s->client_notification_task = | ||
1968 | GNUNET_SCHEDULER_add_now (&prepare_client_end_notification, | ||
1969 | s); | ||
1970 | } | ||
1971 | else if ((BOB == s->role) && (GNUNET_SYSERR != s->active)) | ||
1972 | { | ||
1973 | if ( (s == from_service_head) || | ||
1974 | ( (NULL != from_service_head) && | ||
1975 | ( (NULL != s->next) || | ||
1976 | (NULL != s->a_tail)) ) ) | ||
1977 | GNUNET_CONTAINER_DLL_remove (from_service_head, | ||
1978 | from_service_tail, | ||
1979 | s); | ||
1980 | |||
1981 | // there is a client waiting for this service session, terminate it, too! | ||
1982 | // i assume the tupel of key and element count is unique. if it was not the rest of the code would not work either. | ||
1983 | client_session = s->response; | ||
1984 | if ( (NULL != s->response ) && | ||
1985 | (GNUNET_NO == s->active) && | ||
1986 | (GNUNET_YES == client_session->active) ) | ||
1987 | client_session->active = GNUNET_NO; | ||
1988 | free_session_variables (s); | ||
1989 | |||
1990 | // the client has to check if it was waiting for a result | ||
1991 | // or if it was a responder, no point in adding more statefulness | ||
1992 | if ((NULL != s->response ) && (! do_shutdown)) | ||
1993 | { | ||
1994 | client_session->client_notification_task | ||
1995 | = GNUNET_SCHEDULER_add_now (&prepare_client_end_notification, | ||
1996 | client_session); | ||
1997 | } | ||
1998 | GNUNET_free (s); | ||
1999 | } | ||
2000 | } | ||
2001 | |||
2002 | |||
2003 | /** | ||
2004 | * Compute our scalar product, done by Alice | ||
2005 | * | ||
2006 | * @param session - the session associated with this computation | ||
2007 | * @return product as MPI, never NULL | ||
2008 | */ | ||
2009 | static gcry_mpi_t | ||
2010 | compute_scalar_product (struct ServiceSession *session) | ||
2011 | { | ||
2012 | uint32_t count; | ||
2013 | gcry_mpi_t t; | ||
2014 | gcry_mpi_t u; | ||
2015 | gcry_mpi_t u_prime; | ||
2016 | gcry_mpi_t p; | ||
2017 | gcry_mpi_t p_prime; | ||
2018 | gcry_mpi_t tmp; | ||
2019 | gcry_mpi_t r[session->used_element_count]; | ||
2020 | gcry_mpi_t r_prime[session->used_element_count]; | ||
2021 | gcry_mpi_t s; | ||
2022 | gcry_mpi_t s_prime; | ||
2023 | unsigned int i; | ||
2024 | |||
2025 | count = session->used_element_count; | ||
2026 | // due to the introduced static offset S, we now also have to remove this | ||
2027 | // from the E(a_pi)(+)E(-b_pi-r_pi) and E(a_qi)(+)E(-r_qi) twice each, | ||
2028 | // the result is E((S + a_pi) + (S -b_pi-r_pi)) and E(S + a_qi + S - r_qi) | ||
2029 | for (i = 0; i < count; i++) | ||
2030 | { | ||
2031 | r[i] = gcry_mpi_new (0); | ||
2032 | GNUNET_CRYPTO_paillier_decrypt (&my_privkey, | ||
2033 | &my_pubkey, | ||
2034 | &session->r[i], | ||
2035 | r[i]); | ||
2036 | gcry_mpi_sub (r[i], r[i], my_offset); | ||
2037 | gcry_mpi_sub (r[i], r[i], my_offset); | ||
2038 | r_prime[i] = gcry_mpi_new (0); | ||
2039 | GNUNET_CRYPTO_paillier_decrypt (&my_privkey, | ||
2040 | &my_pubkey, | ||
2041 | &session->r_prime[i], | ||
2042 | r_prime[i]); | ||
2043 | gcry_mpi_sub (r_prime[i], r_prime[i], my_offset); | ||
2044 | gcry_mpi_sub (r_prime[i], r_prime[i], my_offset); | ||
2045 | } | ||
2046 | |||
2047 | // calculate t = sum(ai) | ||
2048 | t = compute_square_sum (session->sorted_elements, count); | ||
2049 | |||
2050 | // calculate U | ||
2051 | u = gcry_mpi_new (0); | ||
2052 | tmp = compute_square_sum (r, count); | ||
2053 | gcry_mpi_sub (u, u, tmp); | ||
2054 | gcry_mpi_release (tmp); | ||
2055 | |||
2056 | //calculate U' | ||
2057 | u_prime = gcry_mpi_new (0); | ||
2058 | tmp = compute_square_sum (r_prime, count); | ||
2059 | gcry_mpi_sub (u_prime, u_prime, tmp); | ||
2060 | |||
2061 | GNUNET_assert (p = gcry_mpi_new (0)); | ||
2062 | GNUNET_assert (p_prime = gcry_mpi_new (0)); | ||
2063 | GNUNET_assert (s = gcry_mpi_new (0)); | ||
2064 | GNUNET_assert (s_prime = gcry_mpi_new (0)); | ||
2065 | |||
2066 | // compute P | ||
2067 | GNUNET_CRYPTO_paillier_decrypt (&my_privkey, | ||
2068 | &my_pubkey, | ||
2069 | &session->s, | ||
2070 | s); | ||
2071 | GNUNET_CRYPTO_paillier_decrypt (&my_privkey, | ||
2072 | &my_pubkey, | ||
2073 | &session->s_prime, | ||
2074 | s_prime); | ||
2075 | |||
2076 | // compute P | ||
2077 | gcry_mpi_add (p, s, t); | ||
2078 | gcry_mpi_add (p, p, u); | ||
2079 | |||
2080 | // compute P' | ||
2081 | gcry_mpi_add (p_prime, s_prime, t); | ||
2082 | gcry_mpi_add (p_prime, p_prime, u_prime); | ||
2083 | |||
2084 | gcry_mpi_release (t); | ||
2085 | gcry_mpi_release (u); | ||
2086 | gcry_mpi_release (u_prime); | ||
2087 | gcry_mpi_release (s); | ||
2088 | gcry_mpi_release (s_prime); | ||
2089 | |||
2090 | // compute product | ||
2091 | gcry_mpi_sub (p, p, p_prime); | ||
2092 | gcry_mpi_release (p_prime); | ||
2093 | tmp = gcry_mpi_set_ui (tmp, 2); | ||
2094 | gcry_mpi_div (p, NULL, p, tmp, 0); | ||
2095 | |||
2096 | gcry_mpi_release (tmp); | ||
2097 | for (i = 0; i < count; i++) | ||
2098 | { | ||
2099 | gcry_mpi_release (session->sorted_elements[i]); | ||
2100 | gcry_mpi_release (r[i]); | ||
2101 | gcry_mpi_release (r_prime[i]); | ||
2102 | } | ||
2103 | GNUNET_free (session->a_head); | ||
2104 | session->a_head = NULL; | ||
2105 | GNUNET_free (session->r); | ||
2106 | session->r = NULL; | ||
2107 | GNUNET_free (session->r_prime); | ||
2108 | session->r_prime = NULL; | ||
2109 | |||
2110 | return p; | ||
2111 | } | ||
2112 | |||
2113 | |||
2114 | /** | ||
2115 | * Handle a multipart-chunk of a request from another service to calculate a scalarproduct with us. | ||
2116 | * | ||
2117 | * @param cls closure (set from #GNUNET_CADET_connect) | ||
2118 | * @param channel connection to the other end | ||
2119 | * @param channel_ctx place to store local state associated with the @a channel | ||
2120 | * @param message the actual message | ||
2121 | * @return #GNUNET_OK to keep the connection open, | ||
2122 | * #GNUNET_SYSERR to close it (signal serious error) | ||
2123 | */ | ||
2124 | static int | ||
2125 | handle_alices_cyrptodata_message_multipart (void *cls, | ||
2126 | struct GNUNET_CADET_Channel *channel, | ||
2127 | void **channel_ctx, | ||
2128 | const struct GNUNET_MessageHeader *message) | ||
2129 | { | ||
2130 | struct ServiceSession * s; | ||
2131 | const struct MultipartMessage * msg = (const struct MultipartMessage *) message; | ||
2132 | struct GNUNET_CRYPTO_PaillierCiphertext *payload; | ||
2133 | uint32_t contained_elements; | ||
2134 | uint32_t msg_length; | ||
2135 | |||
2136 | // are we in the correct state? | ||
2137 | s = (struct ServiceSession *) * channel_ctx; | ||
2138 | //we are not bob | ||
2139 | if ((NULL == s->e_a) || //or we did not expect this message yet | ||
2140 | (s->used_element_count == s->transferred_element_count)) | ||
2141 | { //we are not expecting multipart messages | ||
2142 | goto except; | ||
2143 | } | ||
2144 | // shorter than minimum? | ||
2145 | if (ntohs (msg->header.size) <= sizeof (struct MultipartMessage)) | ||
2146 | { | ||
2147 | goto except; | ||
2148 | } | ||
2149 | contained_elements = ntohl (msg->contained_element_count); | ||
2150 | msg_length = sizeof (struct MultipartMessage) | ||
2151 | +contained_elements * sizeof (struct GNUNET_CRYPTO_PaillierCiphertext); | ||
2152 | //sanity check | ||
2153 | if ((ntohs (msg->header.size) != msg_length) | ||
2154 | || (s->used_element_count < contained_elements + s->transferred_element_count) | ||
2155 | || (0 == contained_elements)) | ||
2156 | { | ||
2157 | goto except; | ||
2158 | } | ||
2159 | payload = (struct GNUNET_CRYPTO_PaillierCiphertext *) &msg[1]; | ||
2160 | // Convert each vector element to MPI_value | ||
2161 | memcpy (&s->e_a[s->transferred_element_count], payload, | ||
2162 | sizeof (struct GNUNET_CRYPTO_PaillierCiphertext) * contained_elements); | ||
2163 | |||
2164 | s->transferred_element_count += contained_elements; | ||
2165 | |||
2166 | if (contained_elements == s->used_element_count) | ||
2167 | { | ||
2168 | // single part finished | ||
2169 | if (NULL == s->intersection_op) | ||
2170 | // intersection has already finished, so we can proceed | ||
2171 | compute_service_response (s); | ||
2172 | } | ||
2173 | |||
2174 | return GNUNET_OK; | ||
2175 | except: | ||
2176 | s->channel = NULL; | ||
2177 | // and notify our client-session that we could not complete the session | ||
2178 | free_session_variables (s); | ||
2179 | if (NULL != s->client) | ||
2180 | { | ||
2181 | //Alice | ||
2182 | s->active = GNUNET_SYSERR; | ||
2183 | s->client_notification_task = | ||
2184 | GNUNET_SCHEDULER_add_now (&prepare_client_end_notification, | ||
2185 | s); | ||
2186 | } | ||
2187 | else | ||
2188 | { | ||
2189 | //Bob | ||
2190 | if (NULL != s->response){ | ||
2191 | s->response->active = GNUNET_SYSERR; | ||
2192 | s->response->client_notification_task = | ||
2193 | GNUNET_SCHEDULER_add_now (&prepare_client_end_notification, | ||
2194 | s->response); | ||
2195 | } | ||
2196 | if ( (s == from_service_head) || | ||
2197 | ( (NULL != from_service_head) && | ||
2198 | ( (NULL != s->next) || | ||
2199 | (NULL != s->a_tail)) ) ) | ||
2200 | GNUNET_CONTAINER_DLL_remove (from_service_head, | ||
2201 | from_service_tail, | ||
2202 | s); | ||
2203 | GNUNET_free (s); | ||
2204 | } | ||
2205 | return GNUNET_SYSERR; | ||
2206 | } | ||
2207 | |||
2208 | |||
2209 | /** | ||
2210 | * Handle a request from another service to calculate a scalarproduct with us. | ||
2211 | * | ||
2212 | * @param cls closure (set from #GNUNET_CADET_connect) | ||
2213 | * @param channel connection to the other end | ||
2214 | * @param channel_ctx place to store local state associated with the channel | ||
2215 | * @param message the actual message | ||
2216 | * @return #GNUNET_OK to keep the connection open, | ||
2217 | * #GNUNET_SYSERR to close it (signal serious error) | ||
2218 | */ | ||
2219 | static int | ||
2220 | handle_alices_cyrptodata_message (void *cls, | ||
2221 | struct GNUNET_CADET_Channel *channel, | ||
2222 | void **channel_ctx, | ||
2223 | const struct GNUNET_MessageHeader *message) | ||
2224 | { | ||
2225 | struct ServiceSession * s; | ||
2226 | const struct AliceCryptodataMessage *msg; | ||
2227 | struct GNUNET_CRYPTO_PaillierCiphertext *payload; | ||
2228 | uint32_t contained_elements = 0; | ||
2229 | uint32_t msg_length; | ||
2230 | |||
2231 | s = (struct ServiceSession *) * channel_ctx; | ||
2232 | //we are not bob | ||
2233 | if ((BOB != s->role) | ||
2234 | //we are expecting multipart messages instead | ||
2235 | || (NULL != s->e_a) | ||
2236 | //or we did not expect this message yet | ||
2237 | || //intersection OP has not yet finished | ||
2238 | !((NULL != s->intersection_op) | ||
2239 | //intersection OP done | ||
2240 | || (s->response->sorted_elements) | ||
2241 | )) | ||
2242 | { | ||
2243 | goto invalid_msg; | ||
2244 | } | ||
2245 | |||
2246 | if (ntohs (message->size) < sizeof (struct AliceCryptodataMessage)) | ||
2247 | { | ||
2248 | GNUNET_break_op (0); | ||
2249 | goto invalid_msg; | ||
2250 | } | ||
2251 | msg = (const struct AliceCryptodataMessage *) message; | ||
2252 | |||
2253 | contained_elements = ntohl (msg->contained_element_count); | ||
2254 | msg_length = sizeof (struct AliceCryptodataMessage) | ||
2255 | +contained_elements * sizeof (struct GNUNET_CRYPTO_PaillierCiphertext); | ||
2256 | |||
2257 | //sanity check: is the message as long as the message_count fields suggests? | ||
2258 | if ((ntohs (msg->header.size) != msg_length) || | ||
2259 | (s->used_element_count < s->transferred_element_count + contained_elements) || | ||
2260 | (0 == contained_elements)) | ||
2261 | { | ||
2262 | goto invalid_msg; | ||
2263 | } | ||
2264 | |||
2265 | s->transferred_element_count = contained_elements; | ||
2266 | payload = (struct GNUNET_CRYPTO_PaillierCiphertext*) &msg[1]; | ||
2267 | |||
2268 | s->e_a = GNUNET_malloc (sizeof (struct GNUNET_CRYPTO_PaillierCiphertext) * s->used_element_count); | ||
2269 | memcpy (&s->e_a[0], | ||
2270 | payload, | ||
2271 | contained_elements * sizeof (struct GNUNET_CRYPTO_PaillierCiphertext)); | ||
2272 | if (contained_elements == s->used_element_count) | ||
2273 | { | ||
2274 | // single part finished | ||
2275 | if (NULL == s->intersection_op) | ||
2276 | // intersection has already finished, so we can proceed | ||
2277 | compute_service_response (s); | ||
2278 | } | ||
2279 | return GNUNET_OK; | ||
2280 | |||
2281 | invalid_msg: | ||
2282 | GNUNET_break_op (0); | ||
2283 | s->channel = NULL; | ||
2284 | // and notify our client-session that we could not complete the session | ||
2285 | free_session_variables (s); | ||
2286 | if (NULL != s->client) | ||
2287 | { | ||
2288 | //Alice | ||
2289 | s->active = GNUNET_SYSERR; | ||
2290 | s->client_notification_task = | ||
2291 | GNUNET_SCHEDULER_add_now (&prepare_client_end_notification, | ||
2292 | s); | ||
2293 | } | ||
2294 | else | ||
2295 | { | ||
2296 | //Bob | ||
2297 | if (NULL != s->response) | ||
2298 | { | ||
2299 | s->response->active = GNUNET_SYSERR; | ||
2300 | s->response->client_notification_task = | ||
2301 | GNUNET_SCHEDULER_add_now (&prepare_client_end_notification, | ||
2302 | s->response); | ||
2303 | } | ||
2304 | if ( (s == from_service_head) || | ||
2305 | ( (NULL != from_service_head) && | ||
2306 | ( (NULL != s->next) || | ||
2307 | (NULL != s->a_tail)) ) ) | ||
2308 | GNUNET_CONTAINER_DLL_remove (from_service_head, | ||
2309 | from_service_tail, | ||
2310 | s); | ||
2311 | GNUNET_free(s); | ||
2312 | } | ||
2313 | return GNUNET_SYSERR; | ||
2314 | } | ||
2315 | |||
2316 | |||
2317 | /** | ||
2318 | * Handle a request from another service to calculate a scalarproduct with us. | ||
2319 | * | ||
2320 | * @param cls closure (set from #GNUNET_CADET_connect) | ||
2321 | * @param channel connection to the other end | ||
2322 | * @param channel_ctx place to store local state associated with the channel | ||
2323 | * @param message the actual message | ||
2324 | * @return #GNUNET_OK to keep the connection open, | ||
2325 | * #GNUNET_SYSERR to close it (signal serious error) | ||
2326 | */ | ||
2327 | static int | ||
2328 | handle_alices_computation_request (void *cls, | ||
2329 | struct GNUNET_CADET_Channel *channel, | ||
2330 | void **channel_ctx, | ||
2331 | const struct GNUNET_MessageHeader *message) | ||
2332 | { | ||
2333 | struct ServiceSession * s; | ||
2334 | struct ServiceSession * client_session; | ||
2335 | const struct ServiceRequestMessage *msg; | ||
2336 | |||
2337 | msg = (const struct ServiceRequestMessage *) message; | ||
2338 | s = (struct ServiceSession *) * channel_ctx; | ||
2339 | if ((BOB != s->role) || (0 != s->total)) | ||
2340 | { | ||
2341 | // must be a fresh session | ||
2342 | goto invalid_msg; | ||
2343 | } | ||
2344 | // Check if message was sent by me, which would be bad! | ||
2345 | if (0 != memcmp (&s->peer, | ||
2346 | &me, | ||
2347 | sizeof (struct GNUNET_PeerIdentity))) | ||
2348 | { | ||
2349 | GNUNET_free (s); | ||
2350 | GNUNET_break (0); | ||
2351 | return GNUNET_SYSERR; | ||
2352 | } | ||
2353 | if (find_matching_session (from_service_tail, | ||
2354 | &msg->session_id, | ||
2355 | NULL)) | ||
2356 | { | ||
2357 | GNUNET_log (GNUNET_ERROR_TYPE_ERROR, | ||
2358 | _("Got message with duplicate session key (`%s'), ignoring service request.\n"), | ||
2359 | (const char *) &(msg->session_id)); | ||
2360 | GNUNET_free (s); | ||
2361 | return GNUNET_SYSERR; | ||
2362 | } | ||
2363 | |||
2364 | s->channel = channel; | ||
2365 | s->session_id = msg->session_id; | ||
2366 | s->remote_pubkey = msg->public_key; | ||
2367 | |||
2368 | //check if service queue contains a matching request | ||
2369 | client_session = find_matching_session (from_client_tail, | ||
2370 | &s->session_id, | ||
2371 | NULL); | ||
2372 | |||
2373 | GNUNET_CONTAINER_DLL_insert (from_service_head, | ||
2374 | from_service_tail, | ||
2375 | s); | ||
2376 | |||
2377 | if ( (NULL != client_session) && | ||
2378 | (client_session->transferred_element_count == client_session->total) ) | ||
2379 | { | ||
2380 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
2381 | "Got session with key %s and a matching element set, processing.\n", | ||
2382 | GNUNET_h2s (&s->session_id)); | ||
2383 | |||
2384 | s->response = client_session; | ||
2385 | s->intersected_elements = client_session->intersected_elements; | ||
2386 | client_session->intersected_elements = NULL; | ||
2387 | s->intersection_set = client_session->intersection_set; | ||
2388 | client_session->intersection_set = NULL; | ||
2389 | |||
2390 | s->intersection_op | ||
2391 | = GNUNET_SET_prepare (&s->peer, | ||
2392 | &s->session_id, | ||
2393 | NULL, | ||
2394 | GNUNET_SET_RESULT_REMOVED, | ||
2395 | &cb_intersection_element_removed, | ||
2396 | s); | ||
2397 | GNUNET_SET_commit (s->intersection_op, | ||
2398 | s->intersection_set); | ||
2399 | } | ||
2400 | else | ||
2401 | { | ||
2402 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
2403 | "Got session with key %s without a matching element set, queueing.\n", | ||
2404 | GNUNET_h2s (&s->session_id)); | ||
2405 | } | ||
2406 | |||
2407 | return GNUNET_OK; | ||
2408 | invalid_msg: | ||
2409 | GNUNET_break_op (0); | ||
2410 | s->channel = NULL; | ||
2411 | // and notify our client-session that we could not complete the session | ||
2412 | free_session_variables (s); | ||
2413 | if (NULL != s->client) | ||
2414 | { | ||
2415 | //Alice | ||
2416 | s->active = GNUNET_SYSERR; | ||
2417 | s->client_notification_task = | ||
2418 | GNUNET_SCHEDULER_add_now (&prepare_client_end_notification, | ||
2419 | s); | ||
2420 | } | ||
2421 | else | ||
2422 | { | ||
2423 | //Bob | ||
2424 | if (NULL != s->response) { | ||
2425 | s->response->active = GNUNET_SYSERR; | ||
2426 | s->response->client_notification_task = | ||
2427 | GNUNET_SCHEDULER_add_now (&prepare_client_end_notification, | ||
2428 | s->response); | ||
2429 | } | ||
2430 | if ( (s == from_service_head) || | ||
2431 | ( (NULL != from_service_head) && | ||
2432 | ( (NULL != s->next) || | ||
2433 | (NULL != s->a_tail)) ) ) | ||
2434 | GNUNET_CONTAINER_DLL_remove (from_service_head, | ||
2435 | from_service_tail, | ||
2436 | s); | ||
2437 | GNUNET_free(s); | ||
2438 | } | ||
2439 | return GNUNET_SYSERR; | ||
2440 | } | ||
2441 | |||
2442 | |||
2443 | /** | ||
2444 | * Handle a multipart chunk of a response we got from another service we wanted to calculate a scalarproduct with. | ||
2445 | * | ||
2446 | * @param cls closure (set from #GNUNET_CADET_connect) | ||
2447 | * @param channel connection to the other end | ||
2448 | * @param channel_ctx place to store local state associated with the @a channel | ||
2449 | * @param message the actual message | ||
2450 | * @return #GNUNET_OK to keep the connection open, | ||
2451 | * #GNUNET_SYSERR to close it (signal serious error) | ||
2452 | */ | ||
2453 | static int | ||
2454 | handle_bobs_cryptodata_multipart (void *cls, | ||
2455 | struct GNUNET_CADET_Channel *channel, | ||
2456 | void **channel_ctx, | ||
2457 | const struct GNUNET_MessageHeader *message) | ||
2458 | { | ||
2459 | struct ServiceSession * s; | ||
2460 | const struct MultipartMessage *msg; | ||
2461 | struct GNUNET_CRYPTO_PaillierCiphertext * payload; | ||
2462 | size_t i; | ||
2463 | uint32_t contained = 0; | ||
2464 | size_t msg_size; | ||
2465 | size_t required_size; | ||
2466 | |||
2467 | GNUNET_assert (NULL != message); | ||
2468 | // are we in the correct state? | ||
2469 | s = (struct ServiceSession *) * channel_ctx; | ||
2470 | if ((ALICE != s->role) || (NULL == s->sorted_elements)) | ||
2471 | { | ||
2472 | goto invalid_msg; | ||
2473 | } | ||
2474 | msg_size = ntohs (message->size); | ||
2475 | if (sizeof (struct MultipartMessage) > msg_size) | ||
2476 | { | ||
2477 | GNUNET_break_op (0); | ||
2478 | goto invalid_msg; | ||
2479 | } | ||
2480 | msg = (const struct MultipartMessage *) message; | ||
2481 | contained = ntohl (msg->contained_element_count); | ||
2482 | required_size = sizeof (struct MultipartMessage) | ||
2483 | + 2 * contained * sizeof (struct GNUNET_CRYPTO_PaillierCiphertext); | ||
2484 | //sanity check: is the message as long as the message_count fields suggests? | ||
2485 | if ( (required_size != msg_size) || | ||
2486 | (s->used_element_count < s->transferred_element_count + contained) ) | ||
2487 | { | ||
2488 | goto invalid_msg; | ||
2489 | } | ||
2490 | payload = (struct GNUNET_CRYPTO_PaillierCiphertext *) &msg[1]; | ||
2491 | // Convert each k[][perm] to its MPI_value | ||
2492 | for (i = 0; i < contained; i++) | ||
2493 | { | ||
2494 | memcpy (&s->r[s->transferred_element_count + i], | ||
2495 | &payload[2 * i], | ||
2496 | sizeof (struct GNUNET_CRYPTO_PaillierCiphertext)); | ||
2497 | memcpy (&s->r_prime[s->transferred_element_count + i], | ||
2498 | &payload[2 * i], | ||
2499 | sizeof (struct GNUNET_CRYPTO_PaillierCiphertext)); | ||
2500 | } | ||
2501 | s->transferred_element_count += contained; | ||
2502 | if (s->transferred_element_count != s->used_element_count) | ||
2503 | return GNUNET_OK; | ||
2504 | s->product = compute_scalar_product (s); //never NULL | ||
2505 | |||
2506 | invalid_msg: | ||
2507 | GNUNET_break_op (NULL != s->product); | ||
2508 | s->channel = NULL; | ||
2509 | // send message with product to client | ||
2510 | if (NULL != s->client) | ||
2511 | { | ||
2512 | //Alice | ||
2513 | if (NULL != s->product) | ||
2514 | s->active = GNUNET_NO; | ||
2515 | else | ||
2516 | s->active = GNUNET_SYSERR; | ||
2517 | s->client_notification_task = | ||
2518 | GNUNET_SCHEDULER_add_now (&prepare_client_response, | ||
2519 | s); | ||
2520 | } | ||
2521 | else | ||
2522 | { | ||
2523 | //Bob | ||
2524 | if (NULL != s->response){ | ||
2525 | s->response->active = GNUNET_SYSERR; | ||
2526 | s->response->client_notification_task = | ||
2527 | GNUNET_SCHEDULER_add_now (&prepare_client_end_notification, | ||
2528 | s->response); | ||
2529 | } | ||
2530 | if ( (s == from_service_head) || | ||
2531 | ( (NULL != from_service_head) && | ||
2532 | ( (NULL != s->next) || | ||
2533 | (NULL != s->a_tail)) ) ) | ||
2534 | GNUNET_CONTAINER_DLL_remove (from_service_head, | ||
2535 | from_service_tail, | ||
2536 | s); | ||
2537 | free_session_variables (s); | ||
2538 | GNUNET_free(s); | ||
2539 | } | ||
2540 | // the channel has done its job, terminate our connection and the channel | ||
2541 | // the peer will be notified that the channel was destroyed via channel_destruction_handler | ||
2542 | // just close the connection, as recommended by Christian | ||
2543 | return GNUNET_SYSERR; | ||
2544 | } | ||
2545 | |||
2546 | |||
2547 | /** | ||
2548 | * Handle a response we got from another service we wanted to calculate a scalarproduct with. | ||
2549 | * | ||
2550 | * @param cls closure (set from #GNUNET_CADET_connect) | ||
2551 | * @param channel connection to the other end | ||
2552 | * @param channel_ctx place to store local state associated with the channel | ||
2553 | * @param message the actual message | ||
2554 | * @return #GNUNET_OK to keep the connection open, | ||
2555 | * #GNUNET_SYSERR to close it (we are done) | ||
2556 | */ | ||
2557 | static int | ||
2558 | handle_bobs_cryptodata_message (void *cls, | ||
2559 | struct GNUNET_CADET_Channel *channel, | ||
2560 | void **channel_ctx, | ||
2561 | const struct GNUNET_MessageHeader *message) | ||
2562 | { | ||
2563 | struct ServiceSession *s; | ||
2564 | const struct ServiceResponseMessage *msg; | ||
2565 | struct GNUNET_CRYPTO_PaillierCiphertext * payload; | ||
2566 | size_t i; | ||
2567 | uint32_t contained = 0; | ||
2568 | size_t msg_size; | ||
2569 | size_t required_size; | ||
2570 | |||
2571 | GNUNET_assert (NULL != message); | ||
2572 | s = (struct ServiceSession *) * channel_ctx; | ||
2573 | // are we in the correct state? | ||
2574 | if (NULL == s->sorted_elements | ||
2575 | || NULL != s->msg | ||
2576 | || s->used_element_count != s->transferred_element_count) | ||
2577 | { | ||
2578 | goto invalid_msg; | ||
2579 | } | ||
2580 | //we need at least a full message without elements attached | ||
2581 | msg_size = ntohs (message->size); | ||
2582 | if (sizeof (struct ServiceResponseMessage) > msg_size) | ||
2583 | { | ||
2584 | GNUNET_break_op (0); | ||
2585 | goto invalid_msg; | ||
2586 | } | ||
2587 | msg = (const struct ServiceResponseMessage *) message; | ||
2588 | contained = ntohl (msg->contained_element_count); | ||
2589 | required_size = sizeof (struct ServiceResponseMessage) | ||
2590 | + 2 * contained * sizeof (struct GNUNET_CRYPTO_PaillierCiphertext) | ||
2591 | + 2 * sizeof (struct GNUNET_CRYPTO_PaillierCiphertext); | ||
2592 | //sanity check: is the message as long as the message_count fields suggests? | ||
2593 | if ((msg_size != required_size) || (s->used_element_count < contained)) | ||
2594 | { | ||
2595 | goto invalid_msg; | ||
2596 | } | ||
2597 | s->transferred_element_count = contained; | ||
2598 | //convert s | ||
2599 | payload = (struct GNUNET_CRYPTO_PaillierCiphertext *) &msg[1]; | ||
2600 | memcpy (&s->s, | ||
2601 | &payload[0], | ||
2602 | sizeof (struct GNUNET_CRYPTO_PaillierCiphertext)); | ||
2603 | memcpy (&s->s_prime, | ||
2604 | &payload[1], | ||
2605 | sizeof (struct GNUNET_CRYPTO_PaillierCiphertext)); | ||
2606 | |||
2607 | s->r = GNUNET_malloc (sizeof (struct GNUNET_CRYPTO_PaillierCiphertext) * s->used_element_count); | ||
2608 | s->r_prime = GNUNET_malloc (sizeof (struct GNUNET_CRYPTO_PaillierCiphertext) * s->used_element_count); | ||
2609 | |||
2610 | payload = &payload[2]; | ||
2611 | // Convert each k[][perm] to its MPI_value | ||
2612 | for (i = 0; i < contained; i++) | ||
2613 | { | ||
2614 | memcpy (&s->r[i], | ||
2615 | &payload[2 * i], | ||
2616 | sizeof (struct GNUNET_CRYPTO_PaillierCiphertext)); | ||
2617 | memcpy (&s->r_prime[i], | ||
2618 | &payload[2 * i + 1], | ||
2619 | sizeof (struct GNUNET_CRYPTO_PaillierCiphertext)); | ||
2620 | } | ||
2621 | if (s->transferred_element_count != s->used_element_count) | ||
2622 | return GNUNET_OK; //wait for the other multipart chunks | ||
2623 | s->product = compute_scalar_product (s); //never NULL | ||
2624 | |||
2625 | invalid_msg: | ||
2626 | GNUNET_break_op (NULL != s->product); | ||
2627 | s->channel = NULL; | ||
2628 | // send message with product to client | ||
2629 | if (NULL != s->client) | ||
2630 | { | ||
2631 | //Alice | ||
2632 | s->client_notification_task = | ||
2633 | GNUNET_SCHEDULER_add_now (&prepare_client_response, | ||
2634 | s); | ||
2635 | } | ||
2636 | else | ||
2637 | { | ||
2638 | //Bob | ||
2639 | if (NULL != s->response) | ||
2640 | { | ||
2641 | s->response->active = GNUNET_SYSERR; | ||
2642 | s->response->client_notification_task | ||
2643 | = GNUNET_SCHEDULER_add_now (&prepare_client_end_notification, | ||
2644 | s->response); | ||
2645 | } | ||
2646 | if ( (s == from_service_head) || | ||
2647 | ( (NULL != from_service_head) && | ||
2648 | ( (NULL != s->next) || | ||
2649 | (NULL != s->a_tail)) ) ) | ||
2650 | GNUNET_CONTAINER_DLL_remove (from_service_head, | ||
2651 | from_service_tail, | ||
2652 | s); | ||
2653 | free_session_variables (s); | ||
2654 | GNUNET_free(s); | ||
2655 | } | ||
2656 | // the channel has done its job, terminate our connection and the channel | ||
2657 | // the peer will be notified that the channel was destroyed via channel_destruction_handler | ||
2658 | // just close the connection, as recommended by Christian | ||
2659 | return GNUNET_SYSERR; | ||
2660 | } | ||
2661 | |||
2662 | |||
2663 | /** | ||
2664 | * Task run during shutdown. | ||
2665 | * | ||
2666 | * @param cls unused | ||
2667 | * @param tc unused | ||
2668 | */ | ||
2669 | static void | ||
2670 | shutdown_task (void *cls, | ||
2671 | const struct GNUNET_SCHEDULER_TaskContext *tc) | ||
2672 | { | ||
2673 | struct ServiceSession * s; | ||
2674 | |||
2675 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
2676 | "Shutting down, initiating cleanup.\n"); | ||
2677 | |||
2678 | do_shutdown = GNUNET_YES; | ||
2679 | |||
2680 | // terminate all owned open channels. | ||
2681 | // FIXME: this should be unnecessary, as we should | ||
2682 | // get client disconnect events that create the same effect. | ||
2683 | for (s = from_client_head; NULL != s; s = s->next) | ||
2684 | { | ||
2685 | if ((GNUNET_NO != s->active) && (NULL != s->channel)) | ||
2686 | { | ||
2687 | GNUNET_CADET_channel_destroy (s->channel); | ||
2688 | s->channel = NULL; | ||
2689 | } | ||
2690 | if (GNUNET_SCHEDULER_NO_TASK != s->client_notification_task) | ||
2691 | { | ||
2692 | GNUNET_SCHEDULER_cancel (s->client_notification_task); | ||
2693 | s->client_notification_task = GNUNET_SCHEDULER_NO_TASK; | ||
2694 | } | ||
2695 | if (NULL != s->client) | ||
2696 | { | ||
2697 | GNUNET_SERVER_client_disconnect (s->client); | ||
2698 | s->client = NULL; | ||
2699 | } | ||
2700 | } | ||
2701 | for (s = from_service_head; NULL != s; s = s->next) | ||
2702 | if (NULL != s->channel) | ||
2703 | { | ||
2704 | GNUNET_CADET_channel_destroy (s->channel); | ||
2705 | s->channel = NULL; | ||
2706 | } | ||
2707 | |||
2708 | if (my_cadet) | ||
2709 | { | ||
2710 | GNUNET_CADET_disconnect (my_cadet); | ||
2711 | my_cadet = NULL; | ||
2712 | } | ||
2713 | } | ||
2714 | |||
2715 | |||
2716 | /** | ||
2717 | * Initialization of the program and message handlers | ||
2718 | * | ||
2719 | * @param cls closure | ||
2720 | * @param server the initialized server | ||
2721 | * @param c configuration to use | ||
2722 | */ | ||
2723 | static void | ||
2724 | run (void *cls, | ||
2725 | struct GNUNET_SERVER_Handle *server, | ||
2726 | const struct GNUNET_CONFIGURATION_Handle *c) | ||
2727 | { | ||
2728 | static const struct GNUNET_SERVER_MessageHandler server_handlers[] = { | ||
2729 | { &handle_client_message, NULL, | ||
2730 | GNUNET_MESSAGE_TYPE_SCALARPRODUCT_CLIENT_TO_ALICE, | ||
2731 | 0}, | ||
2732 | { &handle_client_message, NULL, | ||
2733 | GNUNET_MESSAGE_TYPE_SCALARPRODUCT_CLIENT_TO_BOB, | ||
2734 | 0}, | ||
2735 | { &handle_client_message_multipart, NULL, | ||
2736 | GNUNET_MESSAGE_TYPE_SCALARPRODUCT_CLIENT_MUTLIPART, | ||
2737 | 0}, | ||
2738 | { NULL, NULL, 0, 0} | ||
2739 | }; | ||
2740 | static const struct GNUNET_CADET_MessageHandler cadet_handlers[] = { | ||
2741 | { &handle_alices_computation_request, | ||
2742 | GNUNET_MESSAGE_TYPE_SCALARPRODUCT_SESSION_INITIALIZATION, | ||
2743 | sizeof (struct ServiceRequestMessage) }, | ||
2744 | { &handle_alices_cyrptodata_message, | ||
2745 | GNUNET_MESSAGE_TYPE_SCALARPRODUCT_ALICE_CRYPTODATA, | ||
2746 | 0}, | ||
2747 | { &handle_alices_cyrptodata_message_multipart, | ||
2748 | GNUNET_MESSAGE_TYPE_SCALARPRODUCT_ALICE_CRYPTODATA_MULTIPART, | ||
2749 | 0}, | ||
2750 | { &handle_bobs_cryptodata_message, | ||
2751 | GNUNET_MESSAGE_TYPE_SCALARPRODUCT_BOB_CRYPTODATA, | ||
2752 | 0}, | ||
2753 | { &handle_bobs_cryptodata_multipart, | ||
2754 | GNUNET_MESSAGE_TYPE_SCALARPRODUCT_BOB_CRYPTODATA_MULTIPART, | ||
2755 | 0}, | ||
2756 | { NULL, 0, 0} | ||
2757 | }; | ||
2758 | static const uint32_t ports[] = { | ||
2759 | GNUNET_APPLICATION_TYPE_SCALARPRODUCT, | ||
2760 | 0 | ||
2761 | }; | ||
2762 | cfg = c; | ||
2763 | |||
2764 | //generate private/public key set | ||
2765 | GNUNET_CRYPTO_paillier_create (&my_pubkey, | ||
2766 | &my_privkey); | ||
2767 | |||
2768 | // offset has to be sufficiently small to allow computation of: | ||
2769 | // m1+m2 mod n == (S + a) + (S + b) mod n, | ||
2770 | // if we have more complex operations, this factor needs to be lowered | ||
2771 | my_offset = gcry_mpi_new (GNUNET_CRYPTO_PAILLIER_BITS / 3); | ||
2772 | gcry_mpi_set_bit (my_offset, GNUNET_CRYPTO_PAILLIER_BITS / 3); | ||
2773 | |||
2774 | // register server callbacks and disconnect handler | ||
2775 | GNUNET_SERVER_add_handlers (server, server_handlers); | ||
2776 | GNUNET_SERVER_disconnect_notify (server, | ||
2777 | &cb_client_disconnect, | ||
2778 | NULL); | ||
2779 | GNUNET_break (GNUNET_OK == | ||
2780 | GNUNET_CRYPTO_get_peer_identity (cfg, | ||
2781 | &me)); | ||
2782 | my_cadet = GNUNET_CADET_connect (cfg, NULL, | ||
2783 | &cb_channel_incoming, | ||
2784 | &cb_channel_destruction, | ||
2785 | cadet_handlers, | ||
2786 | ports); | ||
2787 | if (!my_cadet) | ||
2788 | { | ||
2789 | GNUNET_log (GNUNET_ERROR_TYPE_ERROR, | ||
2790 | _("Connect to CADET failed\n")); | ||
2791 | GNUNET_SCHEDULER_shutdown (); | ||
2792 | return; | ||
2793 | } | ||
2794 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
2795 | "Connection to CADET initialized\n"); | ||
2796 | GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_FOREVER_REL, | ||
2797 | &shutdown_task, | ||
2798 | NULL); | ||
2799 | } | ||
2800 | |||
2801 | |||
2802 | /** | ||
2803 | * The main function for the scalarproduct service. | ||
2804 | * | ||
2805 | * @param argc number of arguments from the command line | ||
2806 | * @param argv command line arguments | ||
2807 | * @return 0 ok, 1 on error | ||
2808 | */ | ||
2809 | int | ||
2810 | main (int argc, char *const *argv) | ||
2811 | { | ||
2812 | return (GNUNET_OK == | ||
2813 | GNUNET_SERVICE_run (argc, argv, | ||
2814 | "scalarproduct", | ||
2815 | GNUNET_SERVICE_OPTION_NONE, | ||
2816 | &run, NULL)) ? 0 : 1; | ||
2817 | } | ||
2818 | |||
2819 | /* end of gnunet-service-scalarproduct.c */ | ||
diff --git a/src/scalarproduct/gnunet-service-scalarproduct.h b/src/scalarproduct/gnunet-service-scalarproduct.h new file mode 100644 index 000000000..9a5008628 --- /dev/null +++ b/src/scalarproduct/gnunet-service-scalarproduct.h | |||
@@ -0,0 +1,165 @@ | |||
1 | /* | ||
2 | This file is part of GNUnet. | ||
3 | (C) 2013, 2014 Christian Grothoff (and other contributing authors) | ||
4 | |||
5 | GNUnet is free software; you can redistribute it and/or modify | ||
6 | it under the terms of the GNU General Public License as published | ||
7 | by the Free Software Foundation; either version 3, or (at your | ||
8 | 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 | General Public License for more details. | ||
14 | |||
15 | You should have received a copy of the GNU General Public License | ||
16 | along with GNUnet; see the file COPYING. If not, write to the | ||
17 | Free Software Foundation, Inc., 59 Temple Place - Suite 330, | ||
18 | Boston, MA 02111-1307, USA. | ||
19 | */ | ||
20 | /** | ||
21 | * @file scalarproduct/gnunet-service-scalarproduct.h | ||
22 | * @brief scalarproduct service P2P messages | ||
23 | * @author Christian M. Fuchs | ||
24 | * @author Christian Grothoff | ||
25 | */ | ||
26 | #ifndef GNUNET_SERVICE_SCALARPRODUCT_H | ||
27 | #define GNUNET_SERVICE_SCALARPRODUCT_H | ||
28 | |||
29 | /** | ||
30 | * Maximum count of elements we can put into a multipart message | ||
31 | */ | ||
32 | #define MULTIPART_ELEMENT_CAPACITY ((GNUNET_SERVER_MAX_MESSAGE_SIZE - 1 - sizeof (struct MultipartMessage)) / sizeof (struct GNUNET_CRYPTO_PaillierCiphertext)) | ||
33 | |||
34 | |||
35 | GNUNET_NETWORK_STRUCT_BEGIN | ||
36 | |||
37 | /** | ||
38 | * Message type passed from requesting service Alice to responding | ||
39 | * service Bob to initiate a request and make Bob participate in our | ||
40 | * protocol. Afterwards, Bob is expected to perform the set | ||
41 | * intersection with Alice. Once that has succeeded, Alice will | ||
42 | * send a `struct AliceCryptodataMessage *`. Bob is not expected | ||
43 | * to respond via CADET in the meantime. | ||
44 | */ | ||
45 | struct ServiceRequestMessage | ||
46 | { | ||
47 | /** | ||
48 | * Type is #GNUNET_MESSAGE_TYPE_SCALARPRODUCT_SESSION_INITIALIZATION | ||
49 | */ | ||
50 | struct GNUNET_MessageHeader header; | ||
51 | |||
52 | /** | ||
53 | * For alignment. Always zero. | ||
54 | */ | ||
55 | uint32_t reserved; | ||
56 | |||
57 | /** | ||
58 | * The transaction/session key used to identify a session | ||
59 | */ | ||
60 | struct GNUNET_HashCode session_id; | ||
61 | |||
62 | /** | ||
63 | * Alice's public key | ||
64 | */ | ||
65 | struct GNUNET_CRYPTO_PaillierPublicKey public_key; | ||
66 | |||
67 | }; | ||
68 | |||
69 | |||
70 | /** | ||
71 | * Vector of Pallier-encrypted values sent by Alice to Bob | ||
72 | * (after set intersection). Alice may send messages of this | ||
73 | * type repeatedly to transmit all values. | ||
74 | */ | ||
75 | struct AliceCryptodataMessage | ||
76 | { | ||
77 | /** | ||
78 | * Type is #GNUNET_MESSAGE_TYPE_SCALARPRODUCT_ALICE_CRYPTODATA | ||
79 | */ | ||
80 | struct GNUNET_MessageHeader header; | ||
81 | |||
82 | /** | ||
83 | * How many elements we appended to this message? In NBO. | ||
84 | */ | ||
85 | uint32_t contained_element_count GNUNET_PACKED; | ||
86 | |||
87 | /** | ||
88 | * struct GNUNET_CRYPTO_PaillierCiphertext[contained_element_count] | ||
89 | */ | ||
90 | }; | ||
91 | |||
92 | |||
93 | /** | ||
94 | * Message type passed from responding service Bob to responding | ||
95 | * service Alice to complete a request and allow Alice to compute the | ||
96 | * result. If Bob's reply does not fit into this one message, the | ||
97 | * conversation may be continued with `struct MultipartMessage` | ||
98 | * messages afterwards. | ||
99 | */ | ||
100 | struct ServiceResponseMessage | ||
101 | { | ||
102 | /** | ||
103 | * GNUNET message header with type | ||
104 | * #GNUNET_MESSAGE_TYPE_SCALARPRODUCT_BOB_CRYPTODATA. | ||
105 | */ | ||
106 | struct GNUNET_MessageHeader header; | ||
107 | |||
108 | /** | ||
109 | * How many elements the session input had (in NBO). | ||
110 | */ | ||
111 | uint32_t total_element_count GNUNET_PACKED; | ||
112 | |||
113 | /** | ||
114 | * How many elements were included after the mask was applied | ||
115 | * including all multipart msgs (in NBO). | ||
116 | */ | ||
117 | uint32_t used_element_count GNUNET_PACKED; | ||
118 | |||
119 | /** | ||
120 | * How many elements this individual message delivers (in NBO). | ||
121 | */ | ||
122 | uint32_t contained_element_count GNUNET_PACKED; | ||
123 | |||
124 | /** | ||
125 | * The transaction/session key used to identify a session. | ||
126 | * FIXME: needed? CADET should already identify sessions! | ||
127 | */ | ||
128 | struct GNUNET_HashCode key; | ||
129 | |||
130 | /** | ||
131 | * followed by s | s' | k[i][perm] | ||
132 | */ | ||
133 | }; | ||
134 | |||
135 | |||
136 | /** | ||
137 | * Multipart Message type passed between to supply additional elements | ||
138 | * for the peer. Send from Bob to Alice with additional elements | ||
139 | * of k[i][perm] after his `struct ServiceResponseMessage *`. | ||
140 | * Once all k-values have been transmitted, Bob is finished and | ||
141 | * Alice can transmit the final result to the client. | ||
142 | */ | ||
143 | struct MultipartMessage | ||
144 | { | ||
145 | /** | ||
146 | * GNUNET message header | ||
147 | */ | ||
148 | struct GNUNET_MessageHeader header; | ||
149 | |||
150 | /** | ||
151 | * How many elements we supply within this message? In NBO. | ||
152 | */ | ||
153 | uint32_t contained_element_count GNUNET_PACKED; | ||
154 | |||
155 | /** | ||
156 | * struct GNUNET_CRYPTO_PaillierCiphertext[multipart_element_count] | ||
157 | */ | ||
158 | }; | ||
159 | |||
160 | |||
161 | |||
162 | GNUNET_NETWORK_STRUCT_END | ||
163 | |||
164 | |||
165 | #endif | ||
diff --git a/src/scalarproduct/gnunet-service-scalarproduct_alice.c b/src/scalarproduct/gnunet-service-scalarproduct_alice.c new file mode 100644 index 000000000..888f9d1f0 --- /dev/null +++ b/src/scalarproduct/gnunet-service-scalarproduct_alice.c | |||
@@ -0,0 +1,1396 @@ | |||
1 | /* | ||
2 | This file is part of GNUnet. | ||
3 | (C) 2013, 2014 Christian Grothoff (and other contributing authors) | ||
4 | |||
5 | GNUnet is free software; you can redistribute it and/or modify | ||
6 | it under the terms of the GNU General Public License as published | ||
7 | by the Free Software Foundation; either version 3, or (at your | ||
8 | 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 | General Public License for more details. | ||
14 | |||
15 | You should have received a copy of the GNU General Public License | ||
16 | along with GNUnet; see the file COPYING. If not, write to the | ||
17 | Free Software Foundation, Inc., 59 Temple Place - Suite 330, | ||
18 | Boston, MA 02111-1307, USA. | ||
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_set_service.h" | ||
36 | #include "scalarproduct.h" | ||
37 | #include "gnunet-service-scalarproduct.h" | ||
38 | |||
39 | #define LOG(kind,...) GNUNET_log_from (kind, "scalarproduct-alice", __VA_ARGS__) | ||
40 | |||
41 | /** | ||
42 | * An encrypted element key-value pair. | ||
43 | */ | ||
44 | struct MpiElement | ||
45 | { | ||
46 | /** | ||
47 | * Key used to identify matching pairs of values to multiply. | ||
48 | * Points into an existing data structure, to avoid copying | ||
49 | * and doubling memory use. | ||
50 | */ | ||
51 | const struct GNUNET_HashCode *key; | ||
52 | |||
53 | /** | ||
54 | * Value represented (a). | ||
55 | */ | ||
56 | gcry_mpi_t value; | ||
57 | }; | ||
58 | |||
59 | |||
60 | /** | ||
61 | * A scalarproduct session which tracks | ||
62 | * a request form the client to our final response. | ||
63 | */ | ||
64 | struct AliceServiceSession | ||
65 | { | ||
66 | |||
67 | /** | ||
68 | * (hopefully) unique transaction ID | ||
69 | */ | ||
70 | struct GNUNET_HashCode session_id; | ||
71 | |||
72 | /** | ||
73 | * Alice or Bob's peerID | ||
74 | */ | ||
75 | struct GNUNET_PeerIdentity peer; | ||
76 | |||
77 | /** | ||
78 | * The client this request is related to. | ||
79 | */ | ||
80 | struct GNUNET_SERVER_Client *client; | ||
81 | |||
82 | /** | ||
83 | * The message queue for the client. | ||
84 | */ | ||
85 | struct GNUNET_MQ_Handle *client_mq; | ||
86 | |||
87 | /** | ||
88 | * The message queue for CADET. | ||
89 | */ | ||
90 | struct GNUNET_MQ_Handle *cadet_mq; | ||
91 | |||
92 | /** | ||
93 | * all non-0-value'd elements transmitted to us. | ||
94 | * Values are of type `struct GNUNET_SCALARPRODUCT_Element *` | ||
95 | */ | ||
96 | struct GNUNET_CONTAINER_MultiHashMap *intersected_elements; | ||
97 | |||
98 | /** | ||
99 | * Set of elements for which will conduction an intersection. | ||
100 | * the resulting elements are then used for computing the scalar product. | ||
101 | */ | ||
102 | struct GNUNET_SET_Handle *intersection_set; | ||
103 | |||
104 | /** | ||
105 | * Set of elements for which will conduction an intersection. | ||
106 | * the resulting elements are then used for computing the scalar product. | ||
107 | */ | ||
108 | struct GNUNET_SET_OperationHandle *intersection_op; | ||
109 | |||
110 | /** | ||
111 | * Handle to Alice's Intersection operation listening for Bob | ||
112 | */ | ||
113 | struct GNUNET_SET_ListenHandle *intersection_listen; | ||
114 | |||
115 | /** | ||
116 | * channel-handle associated with our cadet handle | ||
117 | */ | ||
118 | struct GNUNET_CADET_Channel *channel; | ||
119 | |||
120 | /** | ||
121 | * a(Alice), sorted array by key of length @e used_element_count. | ||
122 | */ | ||
123 | struct MpiElement *sorted_elements; | ||
124 | |||
125 | /** | ||
126 | * Bob's permutation p of R | ||
127 | */ | ||
128 | struct GNUNET_CRYPTO_PaillierCiphertext *r; | ||
129 | |||
130 | /** | ||
131 | * Bob's permutation q of R | ||
132 | */ | ||
133 | struct GNUNET_CRYPTO_PaillierCiphertext *r_prime; | ||
134 | |||
135 | /** | ||
136 | * Bob's "s" | ||
137 | */ | ||
138 | struct GNUNET_CRYPTO_PaillierCiphertext s; | ||
139 | |||
140 | /** | ||
141 | * Bob's "s'" | ||
142 | */ | ||
143 | struct GNUNET_CRYPTO_PaillierCiphertext s_prime; | ||
144 | |||
145 | /** | ||
146 | * The computed scalar | ||
147 | */ | ||
148 | gcry_mpi_t product; | ||
149 | |||
150 | /** | ||
151 | * how many elements we were supplied with from the client | ||
152 | */ | ||
153 | uint32_t total; | ||
154 | |||
155 | /** | ||
156 | * how many elements actually are used for the scalar product. | ||
157 | * Size of the arrays in @e r and @e r_prime. | ||
158 | */ | ||
159 | uint32_t used_element_count; | ||
160 | |||
161 | /** | ||
162 | * already transferred elements (sent/received) for multipart messages, less or equal than @e used_element_count for | ||
163 | */ | ||
164 | uint32_t transferred_element_count; | ||
165 | |||
166 | /** | ||
167 | * Is this session active (#GNUNET_YES), Concluded (#GNUNET_NO), or | ||
168 | * had an error (#GNUNET_SYSERR). | ||
169 | * FIXME: replace with proper enum for status codes! | ||
170 | */ | ||
171 | int32_t active; | ||
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 | /** | ||
183 | * GNUnet configuration handle | ||
184 | */ | ||
185 | static const struct GNUNET_CONFIGURATION_Handle *cfg; | ||
186 | |||
187 | /** | ||
188 | * Service's own public key | ||
189 | */ | ||
190 | static struct GNUNET_CRYPTO_PaillierPublicKey my_pubkey; | ||
191 | |||
192 | /** | ||
193 | * Service's own private key | ||
194 | */ | ||
195 | static struct GNUNET_CRYPTO_PaillierPrivateKey my_privkey; | ||
196 | |||
197 | /** | ||
198 | * Service's offset for values that could possibly be negative but are plaintext for encryption. | ||
199 | */ | ||
200 | static gcry_mpi_t my_offset; | ||
201 | |||
202 | /** | ||
203 | * Handle to the CADET service. | ||
204 | */ | ||
205 | static struct GNUNET_CADET_Handle *my_cadet; | ||
206 | |||
207 | |||
208 | /** | ||
209 | * Iterator called to free elements. | ||
210 | * | ||
211 | * @param cls the `struct AliceServiceSession *` (unused) | ||
212 | * @param key the key (unused) | ||
213 | * @param value value to free | ||
214 | * @return #GNUNET_OK (continue to iterate) | ||
215 | */ | ||
216 | static int | ||
217 | free_element (void *cls, | ||
218 | const struct GNUNET_HashCode *key, | ||
219 | void *value) | ||
220 | { | ||
221 | struct GNUNET_SCALARPRODUCT_Element *e = value; | ||
222 | |||
223 | GNUNET_free (e); | ||
224 | return GNUNET_OK; | ||
225 | } | ||
226 | |||
227 | |||
228 | /** | ||
229 | * Destroy session state, we are done with it. | ||
230 | * | ||
231 | * @param s the session to free elements from | ||
232 | */ | ||
233 | static void | ||
234 | destroy_service_session (struct AliceServiceSession *s) | ||
235 | { | ||
236 | unsigned int i; | ||
237 | |||
238 | if (GNUNET_YES == s->in_destroy) | ||
239 | return; | ||
240 | s->in_destroy = GNUNET_YES; | ||
241 | if (NULL != s->client_mq) | ||
242 | { | ||
243 | GNUNET_MQ_destroy (s->client_mq); | ||
244 | s->client_mq = NULL; | ||
245 | } | ||
246 | if (NULL != s->cadet_mq) | ||
247 | { | ||
248 | GNUNET_MQ_destroy (s->cadet_mq); | ||
249 | s->cadet_mq = NULL; | ||
250 | } | ||
251 | if (NULL != s->client) | ||
252 | { | ||
253 | GNUNET_SERVER_client_set_user_context (s->client, | ||
254 | NULL); | ||
255 | GNUNET_SERVER_client_disconnect (s->client); | ||
256 | s->client = NULL; | ||
257 | } | ||
258 | if (NULL != s->channel) | ||
259 | { | ||
260 | GNUNET_CADET_channel_destroy (s->channel); | ||
261 | s->channel = NULL; | ||
262 | } | ||
263 | if (NULL != s->intersected_elements) | ||
264 | { | ||
265 | GNUNET_CONTAINER_multihashmap_iterate (s->intersected_elements, | ||
266 | &free_element, | ||
267 | s); | ||
268 | GNUNET_CONTAINER_multihashmap_destroy (s->intersected_elements); | ||
269 | s->intersected_elements = NULL; | ||
270 | } | ||
271 | if (NULL != s->intersection_listen) | ||
272 | { | ||
273 | GNUNET_SET_listen_cancel (s->intersection_listen); | ||
274 | s->intersection_listen = NULL; | ||
275 | } | ||
276 | if (NULL != s->intersection_op) | ||
277 | { | ||
278 | GNUNET_SET_operation_cancel (s->intersection_op); | ||
279 | s->intersection_op = NULL; | ||
280 | } | ||
281 | if (NULL != s->intersection_set) | ||
282 | { | ||
283 | GNUNET_SET_destroy (s->intersection_set); | ||
284 | s->intersection_set = NULL; | ||
285 | } | ||
286 | if (NULL != s->sorted_elements) | ||
287 | { | ||
288 | for (i=0;i<s->used_element_count;i++) | ||
289 | gcry_mpi_release (s->sorted_elements[i].value); | ||
290 | GNUNET_free (s->sorted_elements); | ||
291 | s->sorted_elements = NULL; | ||
292 | } | ||
293 | if (NULL != s->r) | ||
294 | { | ||
295 | GNUNET_free (s->r); | ||
296 | s->r = NULL; | ||
297 | } | ||
298 | if (NULL != s->r_prime) | ||
299 | { | ||
300 | GNUNET_free (s->r_prime); | ||
301 | s->r_prime = NULL; | ||
302 | } | ||
303 | if (NULL != s->product) | ||
304 | { | ||
305 | gcry_mpi_release (s->product); | ||
306 | s->product = NULL; | ||
307 | } | ||
308 | GNUNET_free (s); | ||
309 | } | ||
310 | |||
311 | |||
312 | /** | ||
313 | * Notify the client that the session has failed. A message gets sent | ||
314 | * to Alice's client if we encountered any error. | ||
315 | * | ||
316 | * @param session the associated client session to fail or succeed | ||
317 | */ | ||
318 | static void | ||
319 | prepare_client_end_notification (struct AliceServiceSession *session) | ||
320 | { | ||
321 | struct ClientResponseMessage *msg; | ||
322 | struct GNUNET_MQ_Envelope *e; | ||
323 | |||
324 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
325 | "Sending session-end notification with status %d to client for session %s\n", | ||
326 | session->active, | ||
327 | GNUNET_h2s (&session->session_id)); | ||
328 | e = GNUNET_MQ_msg (msg, | ||
329 | GNUNET_MESSAGE_TYPE_SCALARPRODUCT_RESULT); | ||
330 | msg->product_length = htonl (0); | ||
331 | msg->status = htonl (session->active); | ||
332 | GNUNET_MQ_send (session->client_mq, | ||
333 | e); | ||
334 | } | ||
335 | |||
336 | |||
337 | /** | ||
338 | * Prepare the final (positive) response we will send to Alice's | ||
339 | * client. | ||
340 | * | ||
341 | * @param s the session associated with our client. | ||
342 | */ | ||
343 | static void | ||
344 | transmit_client_response (struct AliceServiceSession *s) | ||
345 | { | ||
346 | struct ClientResponseMessage *msg; | ||
347 | struct GNUNET_MQ_Envelope *e; | ||
348 | unsigned char *product_exported = NULL; | ||
349 | size_t product_length = 0; | ||
350 | int32_t range; | ||
351 | gcry_error_t rc; | ||
352 | int sign; | ||
353 | gcry_mpi_t value; | ||
354 | |||
355 | if (NULL == s->product) | ||
356 | { | ||
357 | GNUNET_break (0); | ||
358 | prepare_client_end_notification (s); | ||
359 | return; | ||
360 | } | ||
361 | value = gcry_mpi_new (0); | ||
362 | sign = gcry_mpi_cmp_ui (s->product, 0); | ||
363 | if (0 > sign) | ||
364 | { | ||
365 | range = -1; | ||
366 | gcry_mpi_sub (value, | ||
367 | value, | ||
368 | s->product); | ||
369 | } | ||
370 | else if (0 < sign) | ||
371 | { | ||
372 | range = 1; | ||
373 | gcry_mpi_add (value, value, s->product); | ||
374 | } | ||
375 | else | ||
376 | { | ||
377 | /* result is exactly zero */ | ||
378 | range = 0; | ||
379 | } | ||
380 | gcry_mpi_release (s->product); | ||
381 | s->product = NULL; | ||
382 | |||
383 | if ( (0 != range) && | ||
384 | (0 != (rc = gcry_mpi_aprint (GCRYMPI_FMT_STD, | ||
385 | &product_exported, | ||
386 | &product_length, | ||
387 | value)))) | ||
388 | { | ||
389 | LOG_GCRY (GNUNET_ERROR_TYPE_ERROR, | ||
390 | "gcry_mpi_scan", | ||
391 | rc); | ||
392 | prepare_client_end_notification (s); | ||
393 | return; | ||
394 | } | ||
395 | gcry_mpi_release (value); | ||
396 | e = GNUNET_MQ_msg_extra (msg, | ||
397 | product_length, | ||
398 | GNUNET_MESSAGE_TYPE_SCALARPRODUCT_RESULT); | ||
399 | msg->range = htonl (range); | ||
400 | msg->product_length = htonl (product_length); | ||
401 | if (NULL != product_exported) | ||
402 | { | ||
403 | memcpy (&msg[1], | ||
404 | product_exported, | ||
405 | product_length); | ||
406 | GNUNET_free (product_exported); | ||
407 | } | ||
408 | GNUNET_MQ_send (s->client_mq, | ||
409 | e); | ||
410 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
411 | "Sent result to client, session %s has ended!\n", | ||
412 | GNUNET_h2s (&s->session_id)); | ||
413 | } | ||
414 | |||
415 | |||
416 | |||
417 | /** | ||
418 | * Function called whenever a channel is destroyed. Should clean up | ||
419 | * any associated state. | ||
420 | * | ||
421 | * It must NOT call #GNUNET_CADET_channel_destroy() on the channel. | ||
422 | * | ||
423 | * @param cls closure (set from #GNUNET_CADET_connect()) | ||
424 | * @param channel connection to the other end (henceforth invalid) | ||
425 | * @param channel_ctx place where local state associated | ||
426 | * with the channel is stored | ||
427 | */ | ||
428 | static void | ||
429 | cb_channel_destruction (void *cls, | ||
430 | const struct GNUNET_CADET_Channel *channel, | ||
431 | void *channel_ctx) | ||
432 | { | ||
433 | struct AliceServiceSession *s = channel_ctx; | ||
434 | |||
435 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
436 | "Peer disconnected, terminating session %s with peer %s\n", | ||
437 | GNUNET_h2s (&s->session_id), | ||
438 | GNUNET_i2s (&s->peer)); | ||
439 | s->channel = NULL; | ||
440 | if (GNUNET_YES == s->active) | ||
441 | { | ||
442 | /* We didn't get an answer yet, fail with error */ | ||
443 | s->active = GNUNET_SYSERR; | ||
444 | prepare_client_end_notification (s); | ||
445 | } | ||
446 | } | ||
447 | |||
448 | |||
449 | /** | ||
450 | * Computes the square sum over a vector of a given length. | ||
451 | * | ||
452 | * @param vector the vector to compute over | ||
453 | * @param length the length of the vector | ||
454 | * @return an MPI value containing the calculated sum, never NULL | ||
455 | */ | ||
456 | static gcry_mpi_t | ||
457 | compute_square_sum_mpi_elements (const struct MpiElement *vector, | ||
458 | uint32_t length) | ||
459 | { | ||
460 | gcry_mpi_t elem; | ||
461 | gcry_mpi_t sum; | ||
462 | uint32_t i; | ||
463 | |||
464 | GNUNET_assert (NULL != (sum = gcry_mpi_new (0))); | ||
465 | GNUNET_assert (NULL != (elem = gcry_mpi_new (0))); | ||
466 | for (i = 0; i < length; i++) | ||
467 | { | ||
468 | gcry_mpi_mul (elem, vector[i].value, vector[i].value); | ||
469 | gcry_mpi_add (sum, sum, elem); | ||
470 | } | ||
471 | gcry_mpi_release (elem); | ||
472 | return sum; | ||
473 | } | ||
474 | |||
475 | |||
476 | /** | ||
477 | * Computes the square sum over a vector of a given length. | ||
478 | * | ||
479 | * @param vector the vector to compute over | ||
480 | * @param length the length of the vector | ||
481 | * @return an MPI value containing the calculated sum, never NULL | ||
482 | */ | ||
483 | static gcry_mpi_t | ||
484 | compute_square_sum (const gcry_mpi_t *vector, | ||
485 | uint32_t length) | ||
486 | { | ||
487 | gcry_mpi_t elem; | ||
488 | gcry_mpi_t sum; | ||
489 | uint32_t i; | ||
490 | |||
491 | GNUNET_assert (NULL != (sum = gcry_mpi_new (0))); | ||
492 | GNUNET_assert (NULL != (elem = gcry_mpi_new (0))); | ||
493 | for (i = 0; i < length; i++) | ||
494 | { | ||
495 | gcry_mpi_mul (elem, vector[i], vector[i]); | ||
496 | gcry_mpi_add (sum, sum, elem); | ||
497 | } | ||
498 | gcry_mpi_release (elem); | ||
499 | return sum; | ||
500 | } | ||
501 | |||
502 | |||
503 | /** | ||
504 | * Compute our scalar product, done by Alice | ||
505 | * | ||
506 | * @param session the session associated with this computation | ||
507 | * @return product as MPI, never NULL | ||
508 | */ | ||
509 | static gcry_mpi_t | ||
510 | compute_scalar_product (struct AliceServiceSession *session) | ||
511 | { | ||
512 | uint32_t count; | ||
513 | gcry_mpi_t t; | ||
514 | gcry_mpi_t u; | ||
515 | gcry_mpi_t u_prime; | ||
516 | gcry_mpi_t p; | ||
517 | gcry_mpi_t p_prime; | ||
518 | gcry_mpi_t tmp; | ||
519 | gcry_mpi_t r[session->used_element_count]; | ||
520 | gcry_mpi_t r_prime[session->used_element_count]; | ||
521 | gcry_mpi_t s; | ||
522 | gcry_mpi_t s_prime; | ||
523 | unsigned int i; | ||
524 | |||
525 | count = session->used_element_count; | ||
526 | // due to the introduced static offset S, we now also have to remove this | ||
527 | // from the E(a_pi)(+)E(-b_pi-r_pi) and E(a_qi)(+)E(-r_qi) twice each, | ||
528 | // the result is E((S + a_pi) + (S -b_pi-r_pi)) and E(S + a_qi + S - r_qi) | ||
529 | for (i = 0; i < count; i++) | ||
530 | { | ||
531 | r[i] = gcry_mpi_new (0); | ||
532 | GNUNET_CRYPTO_paillier_decrypt (&my_privkey, | ||
533 | &my_pubkey, | ||
534 | &session->r[i], | ||
535 | r[i]); | ||
536 | gcry_mpi_sub (r[i], | ||
537 | r[i], | ||
538 | my_offset); | ||
539 | gcry_mpi_sub (r[i], | ||
540 | r[i], | ||
541 | my_offset); | ||
542 | r_prime[i] = gcry_mpi_new (0); | ||
543 | GNUNET_CRYPTO_paillier_decrypt (&my_privkey, | ||
544 | &my_pubkey, | ||
545 | &session->r_prime[i], | ||
546 | r_prime[i]); | ||
547 | gcry_mpi_sub (r_prime[i], | ||
548 | r_prime[i], | ||
549 | my_offset); | ||
550 | gcry_mpi_sub (r_prime[i], | ||
551 | r_prime[i], | ||
552 | my_offset); | ||
553 | } | ||
554 | |||
555 | // calculate t = sum(ai) | ||
556 | t = compute_square_sum_mpi_elements (session->sorted_elements, | ||
557 | count); | ||
558 | // calculate U | ||
559 | u = gcry_mpi_new (0); | ||
560 | tmp = compute_square_sum (r, count); | ||
561 | gcry_mpi_sub (u, u, tmp); | ||
562 | gcry_mpi_release (tmp); | ||
563 | |||
564 | //calculate U' | ||
565 | u_prime = gcry_mpi_new (0); | ||
566 | tmp = compute_square_sum (r_prime, count); | ||
567 | gcry_mpi_sub (u_prime, u_prime, tmp); | ||
568 | |||
569 | GNUNET_assert (p = gcry_mpi_new (0)); | ||
570 | GNUNET_assert (p_prime = gcry_mpi_new (0)); | ||
571 | GNUNET_assert (s = gcry_mpi_new (0)); | ||
572 | GNUNET_assert (s_prime = gcry_mpi_new (0)); | ||
573 | |||
574 | // compute P | ||
575 | GNUNET_CRYPTO_paillier_decrypt (&my_privkey, | ||
576 | &my_pubkey, | ||
577 | &session->s, | ||
578 | s); | ||
579 | GNUNET_CRYPTO_paillier_decrypt (&my_privkey, | ||
580 | &my_pubkey, | ||
581 | &session->s_prime, | ||
582 | s_prime); | ||
583 | |||
584 | // compute P | ||
585 | gcry_mpi_add (p, s, t); | ||
586 | gcry_mpi_add (p, p, u); | ||
587 | |||
588 | // compute P' | ||
589 | gcry_mpi_add (p_prime, s_prime, t); | ||
590 | gcry_mpi_add (p_prime, p_prime, u_prime); | ||
591 | |||
592 | gcry_mpi_release (t); | ||
593 | gcry_mpi_release (u); | ||
594 | gcry_mpi_release (u_prime); | ||
595 | gcry_mpi_release (s); | ||
596 | gcry_mpi_release (s_prime); | ||
597 | |||
598 | // compute product | ||
599 | gcry_mpi_sub (p, p, p_prime); | ||
600 | gcry_mpi_release (p_prime); | ||
601 | tmp = gcry_mpi_set_ui (tmp, 2); | ||
602 | gcry_mpi_div (p, NULL, p, tmp, 0); | ||
603 | |||
604 | gcry_mpi_release (tmp); | ||
605 | for (i = 0; i < count; i++) | ||
606 | { | ||
607 | gcry_mpi_release (session->sorted_elements[i].value); | ||
608 | gcry_mpi_release (r[i]); | ||
609 | gcry_mpi_release (r_prime[i]); | ||
610 | } | ||
611 | GNUNET_free (session->sorted_elements); | ||
612 | session->sorted_elements = NULL; | ||
613 | GNUNET_free (session->r); | ||
614 | session->r = NULL; | ||
615 | GNUNET_free (session->r_prime); | ||
616 | session->r_prime = NULL; | ||
617 | |||
618 | return p; | ||
619 | } | ||
620 | |||
621 | |||
622 | /** | ||
623 | * Handle a multipart chunk of a response we got from another service | ||
624 | * we wanted to calculate a scalarproduct with. | ||
625 | * | ||
626 | * @param cls closure (set from #GNUNET_CADET_connect) | ||
627 | * @param channel connection to the other end | ||
628 | * @param channel_ctx place to store local state associated with the @a channel | ||
629 | * @param message the actual message | ||
630 | * @return #GNUNET_OK to keep the connection open, | ||
631 | * #GNUNET_SYSERR to close it (signal serious error) | ||
632 | */ | ||
633 | static int | ||
634 | handle_bobs_cryptodata_multipart (void *cls, | ||
635 | struct GNUNET_CADET_Channel *channel, | ||
636 | void **channel_ctx, | ||
637 | const struct GNUNET_MessageHeader *message) | ||
638 | { | ||
639 | struct AliceServiceSession *s = *channel_ctx; | ||
640 | const struct MultipartMessage *msg; | ||
641 | const struct GNUNET_CRYPTO_PaillierCiphertext *payload; | ||
642 | size_t i; | ||
643 | uint32_t contained; | ||
644 | size_t msg_size; | ||
645 | size_t required_size; | ||
646 | |||
647 | if (NULL == s) | ||
648 | { | ||
649 | GNUNET_break_op (0); | ||
650 | return GNUNET_SYSERR; | ||
651 | } | ||
652 | msg_size = ntohs (message->size); | ||
653 | if (sizeof (struct MultipartMessage) > msg_size) | ||
654 | { | ||
655 | GNUNET_break_op (0); | ||
656 | return GNUNET_SYSERR; | ||
657 | } | ||
658 | msg = (const struct MultipartMessage *) message; | ||
659 | contained = ntohl (msg->contained_element_count); | ||
660 | required_size = sizeof (struct MultipartMessage) | ||
661 | + 2 * contained * sizeof (struct GNUNET_CRYPTO_PaillierCiphertext); | ||
662 | if ( (required_size != msg_size) || | ||
663 | (s->transferred_element_count + contained > s->used_element_count) ) | ||
664 | { | ||
665 | GNUNET_break (0); | ||
666 | return GNUNET_SYSERR; | ||
667 | } | ||
668 | payload = (const struct GNUNET_CRYPTO_PaillierCiphertext *) &msg[1]; | ||
669 | /* Convert each k[][perm] to its MPI_value */ | ||
670 | for (i = 0; i < contained; i++) | ||
671 | { | ||
672 | memcpy (&s->r[s->transferred_element_count + i], | ||
673 | &payload[2 * i], | ||
674 | sizeof (struct GNUNET_CRYPTO_PaillierCiphertext)); | ||
675 | memcpy (&s->r_prime[s->transferred_element_count + i], | ||
676 | &payload[2 * i], | ||
677 | sizeof (struct GNUNET_CRYPTO_PaillierCiphertext)); | ||
678 | } | ||
679 | s->transferred_element_count += contained; | ||
680 | if (s->transferred_element_count != s->used_element_count) | ||
681 | return GNUNET_OK; | ||
682 | |||
683 | s->product = compute_scalar_product (s); | ||
684 | transmit_client_response (s); | ||
685 | return GNUNET_OK; | ||
686 | } | ||
687 | |||
688 | |||
689 | /** | ||
690 | * Handle a response we got from another service we wanted to | ||
691 | * calculate a scalarproduct with. | ||
692 | * | ||
693 | * @param cls closure (set from #GNUNET_CADET_connect) | ||
694 | * @param channel connection to the other end | ||
695 | * @param channel_ctx place to store local state associated with the channel | ||
696 | * @param message the actual message | ||
697 | * @return #GNUNET_OK to keep the connection open, | ||
698 | * #GNUNET_SYSERR to close it (we are done) | ||
699 | */ | ||
700 | static int | ||
701 | handle_bobs_cryptodata_message (void *cls, | ||
702 | struct GNUNET_CADET_Channel *channel, | ||
703 | void **channel_ctx, | ||
704 | const struct GNUNET_MessageHeader *message) | ||
705 | { | ||
706 | struct AliceServiceSession *s = *channel_ctx; | ||
707 | const struct ServiceResponseMessage *msg; | ||
708 | const struct GNUNET_CRYPTO_PaillierCiphertext *payload; | ||
709 | uint32_t i; | ||
710 | uint32_t contained; | ||
711 | uint16_t msg_size; | ||
712 | size_t required_size; | ||
713 | |||
714 | if (NULL == s) | ||
715 | { | ||
716 | GNUNET_break_op (0); | ||
717 | return GNUNET_SYSERR; | ||
718 | } | ||
719 | msg_size = ntohs (message->size); | ||
720 | if (sizeof (struct ServiceResponseMessage) > msg_size) | ||
721 | { | ||
722 | GNUNET_break_op (0); | ||
723 | return GNUNET_SYSERR; | ||
724 | } | ||
725 | msg = (const struct ServiceResponseMessage *) message; | ||
726 | contained = ntohl (msg->contained_element_count); | ||
727 | required_size = sizeof (struct ServiceResponseMessage) | ||
728 | + 2 * contained * sizeof (struct GNUNET_CRYPTO_PaillierCiphertext) | ||
729 | + 2 * sizeof (struct GNUNET_CRYPTO_PaillierCiphertext); | ||
730 | if ( (msg_size != required_size) || | ||
731 | (contained > UINT16_MAX) || | ||
732 | (s->used_element_count < contained) ) | ||
733 | { | ||
734 | GNUNET_break_op (0); | ||
735 | return GNUNET_SYSERR; | ||
736 | } | ||
737 | if ( (NULL == s->sorted_elements) || | ||
738 | (s->used_element_count != s->transferred_element_count) ) | ||
739 | { | ||
740 | /* we're not ready yet, how can Bob be? */ | ||
741 | GNUNET_break_op (0); | ||
742 | return GNUNET_SYSERR; | ||
743 | } | ||
744 | payload = (const struct GNUNET_CRYPTO_PaillierCiphertext *) &msg[1]; | ||
745 | memcpy (&s->s, | ||
746 | &payload[0], | ||
747 | sizeof (struct GNUNET_CRYPTO_PaillierCiphertext)); | ||
748 | memcpy (&s->s_prime, | ||
749 | &payload[1], | ||
750 | sizeof (struct GNUNET_CRYPTO_PaillierCiphertext)); | ||
751 | payload = &payload[2]; | ||
752 | |||
753 | s->r = GNUNET_malloc (sizeof (struct GNUNET_CRYPTO_PaillierCiphertext) * s->used_element_count); | ||
754 | s->r_prime = GNUNET_malloc (sizeof (struct GNUNET_CRYPTO_PaillierCiphertext) * s->used_element_count); | ||
755 | for (i = 0; i < contained; i++) | ||
756 | { | ||
757 | memcpy (&s->r[i], | ||
758 | &payload[2 * i], | ||
759 | sizeof (struct GNUNET_CRYPTO_PaillierCiphertext)); | ||
760 | memcpy (&s->r_prime[i], | ||
761 | &payload[2 * i + 1], | ||
762 | sizeof (struct GNUNET_CRYPTO_PaillierCiphertext)); | ||
763 | } | ||
764 | s->transferred_element_count = contained; | ||
765 | |||
766 | if (s->transferred_element_count != s->used_element_count) | ||
767 | { | ||
768 | /* More to come */ | ||
769 | return GNUNET_OK; | ||
770 | } | ||
771 | |||
772 | s->product = compute_scalar_product (s); | ||
773 | transmit_client_response (s); | ||
774 | return GNUNET_OK; | ||
775 | } | ||
776 | |||
777 | |||
778 | /** | ||
779 | * Iterator to copy over messages from the hash map | ||
780 | * into an array for sorting. | ||
781 | * | ||
782 | * @param cls the `struct AliceServiceSession *` | ||
783 | * @param key the key (unused) | ||
784 | * @param value the `struct GNUNET_SCALARPRODUCT_Element *` | ||
785 | */ | ||
786 | static int | ||
787 | copy_element_cb (void *cls, | ||
788 | const struct GNUNET_HashCode *key, | ||
789 | void *value) | ||
790 | { | ||
791 | struct AliceServiceSession *s = cls; | ||
792 | struct GNUNET_SCALARPRODUCT_Element *e = value; | ||
793 | gcry_mpi_t mval; | ||
794 | int64_t val; | ||
795 | |||
796 | mval = gcry_mpi_new (0); | ||
797 | val = (int64_t) GNUNET_ntohll (e->value); | ||
798 | if (0 > val) | ||
799 | gcry_mpi_sub_ui (mval, mval, -val); | ||
800 | else | ||
801 | gcry_mpi_add_ui (mval, mval, val); | ||
802 | s->sorted_elements [s->used_element_count].value = mval; | ||
803 | s->sorted_elements [s->used_element_count].key = &e->key; | ||
804 | s->used_element_count++; | ||
805 | return GNUNET_OK; | ||
806 | } | ||
807 | |||
808 | |||
809 | /** | ||
810 | * Compare two `struct MpiValue`s by key for sorting. | ||
811 | * | ||
812 | * @param a pointer to first `struct MpiValue *` | ||
813 | * @param b pointer to first `struct MpiValue *` | ||
814 | * @return -1 for a < b, 0 for a=b, 1 for a > b. | ||
815 | */ | ||
816 | static int | ||
817 | element_cmp (const void *a, | ||
818 | const void *b) | ||
819 | { | ||
820 | const struct MpiElement *ma = *(const struct MpiElement **) a; | ||
821 | const struct MpiElement *mb = *(const struct MpiElement **) b; | ||
822 | |||
823 | return GNUNET_CRYPTO_hash_cmp (ma->key, | ||
824 | mb->key); | ||
825 | } | ||
826 | |||
827 | |||
828 | /** | ||
829 | * Maximum number of elements we can put into a single cryptodata | ||
830 | * message | ||
831 | */ | ||
832 | #define ELEMENT_CAPACITY ((GNUNET_SERVER_MAX_MESSAGE_SIZE - 1 - sizeof (struct AliceCryptodataMessage)) / sizeof (struct GNUNET_CRYPTO_PaillierCiphertext)) | ||
833 | |||
834 | |||
835 | /** | ||
836 | * Send the cryptographic data from Alice to Bob. | ||
837 | * Does nothing if we already transferred all elements. | ||
838 | * | ||
839 | * @param s the associated service session | ||
840 | */ | ||
841 | static void | ||
842 | send_alices_cryptodata_message (struct AliceServiceSession *s) | ||
843 | { | ||
844 | struct AliceCryptodataMessage *msg; | ||
845 | struct GNUNET_MQ_Envelope *e; | ||
846 | struct GNUNET_CRYPTO_PaillierCiphertext *payload; | ||
847 | unsigned int i; | ||
848 | uint32_t todo_count; | ||
849 | gcry_mpi_t a; | ||
850 | |||
851 | s->sorted_elements | ||
852 | = GNUNET_malloc (GNUNET_CONTAINER_multihashmap_size (s->intersected_elements) * | ||
853 | sizeof (struct MpiElement)); | ||
854 | s->used_element_count = 0; | ||
855 | GNUNET_CONTAINER_multihashmap_iterate (s->intersected_elements, | ||
856 | ©_element_cb, | ||
857 | s); | ||
858 | LOG (GNUNET_ERROR_TYPE_DEBUG, | ||
859 | "Finished intersection, %d items remain\n", | ||
860 | s->used_element_count); | ||
861 | qsort (s->intersected_elements, | ||
862 | s->used_element_count, | ||
863 | sizeof (struct MpiElement), | ||
864 | &element_cmp); | ||
865 | |||
866 | while (s->transferred_element_count < s->used_element_count) | ||
867 | { | ||
868 | todo_count = s->used_element_count - s->transferred_element_count; | ||
869 | if (todo_count > ELEMENT_CAPACITY) | ||
870 | todo_count = ELEMENT_CAPACITY; | ||
871 | |||
872 | e = GNUNET_MQ_msg_extra (msg, | ||
873 | todo_count * 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 = s->transferred_element_count; i < todo_count; i++) | ||
879 | { | ||
880 | gcry_mpi_add (a, | ||
881 | s->sorted_elements[i].value, | ||
882 | my_offset); | ||
883 | GNUNET_CRYPTO_paillier_encrypt (&my_pubkey, | ||
884 | a, | ||
885 | 3, | ||
886 | &payload[i - s->transferred_element_count]); | ||
887 | } | ||
888 | gcry_mpi_release (a); | ||
889 | s->transferred_element_count += todo_count; | ||
890 | GNUNET_MQ_send (s->cadet_mq, | ||
891 | e); | ||
892 | } | ||
893 | } | ||
894 | |||
895 | |||
896 | /** | ||
897 | * Callback for set operation results. Called for each element | ||
898 | * that should be removed from the result set, and then once | ||
899 | * to indicate that the set intersection operation is done. | ||
900 | * | ||
901 | * @param cls closure with the `struct AliceServiceSession` | ||
902 | * @param element a result element, only valid if status is #GNUNET_SET_STATUS_OK | ||
903 | * @param status what has happened with the set intersection? | ||
904 | */ | ||
905 | static void | ||
906 | cb_intersection_element_removed (void *cls, | ||
907 | const struct GNUNET_SET_Element *element, | ||
908 | enum GNUNET_SET_Status status) | ||
909 | { | ||
910 | struct AliceServiceSession *s = cls; | ||
911 | struct GNUNET_SCALARPRODUCT_Element *se; | ||
912 | |||
913 | switch (status) | ||
914 | { | ||
915 | case GNUNET_SET_STATUS_OK: | ||
916 | /* this element has been removed from the set */ | ||
917 | se = GNUNET_CONTAINER_multihashmap_get (s->intersected_elements, | ||
918 | element->data); | ||
919 | LOG (GNUNET_ERROR_TYPE_DEBUG, | ||
920 | "Intersection removed element with key %s and value %lld\n", | ||
921 | GNUNET_h2s (&se->key), | ||
922 | (long long) GNUNET_ntohll (se->value)); | ||
923 | GNUNET_assert (GNUNET_YES == | ||
924 | GNUNET_CONTAINER_multihashmap_remove (s->intersected_elements, | ||
925 | element->data, | ||
926 | se)); | ||
927 | GNUNET_free (se); | ||
928 | return; | ||
929 | case GNUNET_SET_STATUS_DONE: | ||
930 | s->intersection_op = NULL; | ||
931 | s->intersection_set = NULL; | ||
932 | send_alices_cryptodata_message (s); | ||
933 | return; | ||
934 | case GNUNET_SET_STATUS_HALF_DONE: | ||
935 | /* unexpected for intersection */ | ||
936 | GNUNET_break (0); | ||
937 | return; | ||
938 | case GNUNET_SET_STATUS_FAILURE: | ||
939 | /* unhandled status code */ | ||
940 | LOG (GNUNET_ERROR_TYPE_DEBUG, | ||
941 | "Set intersection failed!\n"); | ||
942 | if (NULL != s->intersection_listen) | ||
943 | { | ||
944 | GNUNET_SET_listen_cancel (s->intersection_listen); | ||
945 | s->intersection_listen = NULL; | ||
946 | } | ||
947 | s->intersection_op = NULL; | ||
948 | s->intersection_set = NULL; | ||
949 | s->active = GNUNET_SYSERR; | ||
950 | prepare_client_end_notification (s); | ||
951 | return; | ||
952 | default: | ||
953 | GNUNET_break (0); | ||
954 | return; | ||
955 | } | ||
956 | } | ||
957 | |||
958 | |||
959 | /** | ||
960 | * Called when another peer wants to do a set operation with the | ||
961 | * local peer. If a listen error occurs, the @a request is NULL. | ||
962 | * | ||
963 | * @param cls closure with the `struct AliceServiceSession *` | ||
964 | * @param other_peer the other peer | ||
965 | * @param context_msg message with application specific information from | ||
966 | * the other peer | ||
967 | * @param request request from the other peer (never NULL), use GNUNET_SET_accept() | ||
968 | * to accept it, otherwise the request will be refused | ||
969 | * Note that we can't just return value from the listen callback, | ||
970 | * as it is also necessary to specify the set we want to do the | ||
971 | * operation with, whith sometimes can be derived from the context | ||
972 | * message. It's necessary to specify the timeout. | ||
973 | */ | ||
974 | static void | ||
975 | cb_intersection_request_alice (void *cls, | ||
976 | const struct GNUNET_PeerIdentity *other_peer, | ||
977 | const struct GNUNET_MessageHeader *context_msg, | ||
978 | struct GNUNET_SET_Request *request) | ||
979 | { | ||
980 | struct AliceServiceSession *s = cls; | ||
981 | |||
982 | if (0 != memcmp (other_peer, | ||
983 | &s->peer, | ||
984 | sizeof (struct GNUNET_PeerIdentity))) | ||
985 | { | ||
986 | GNUNET_break_op (0); | ||
987 | return; | ||
988 | } | ||
989 | s->intersection_op | ||
990 | = GNUNET_SET_accept (request, | ||
991 | GNUNET_SET_RESULT_REMOVED, | ||
992 | &cb_intersection_element_removed, | ||
993 | s); | ||
994 | if (NULL == s->intersection_op) | ||
995 | { | ||
996 | GNUNET_break (0); | ||
997 | s->active = GNUNET_SYSERR; | ||
998 | prepare_client_end_notification (s); | ||
999 | return; | ||
1000 | } | ||
1001 | if (GNUNET_OK != | ||
1002 | GNUNET_SET_commit (s->intersection_op, | ||
1003 | s->intersection_set)) | ||
1004 | { | ||
1005 | s->active = GNUNET_SYSERR; | ||
1006 | prepare_client_end_notification (s); | ||
1007 | return; | ||
1008 | } | ||
1009 | s->intersection_set = NULL; | ||
1010 | s->intersection_listen = NULL; | ||
1011 | } | ||
1012 | |||
1013 | |||
1014 | /** | ||
1015 | * Our client has finished sending us its multipart message. | ||
1016 | * | ||
1017 | * @param session the service session context | ||
1018 | */ | ||
1019 | static void | ||
1020 | client_request_complete_alice (struct AliceServiceSession *s) | ||
1021 | { | ||
1022 | struct ServiceRequestMessage *msg; | ||
1023 | struct GNUNET_MQ_Envelope *e; | ||
1024 | |||
1025 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
1026 | "Creating new channel for session with key %s.\n", | ||
1027 | GNUNET_h2s (&s->session_id)); | ||
1028 | s->channel | ||
1029 | = GNUNET_CADET_channel_create (my_cadet, | ||
1030 | s, | ||
1031 | &s->peer, | ||
1032 | GNUNET_APPLICATION_TYPE_SCALARPRODUCT, | ||
1033 | GNUNET_CADET_OPTION_RELIABLE); | ||
1034 | if (NULL == s->channel) | ||
1035 | { | ||
1036 | s->active = GNUNET_SYSERR; | ||
1037 | prepare_client_end_notification (s); | ||
1038 | return; | ||
1039 | } | ||
1040 | s->cadet_mq = GNUNET_CADET_mq_create (s->channel); | ||
1041 | s->intersection_listen | ||
1042 | = GNUNET_SET_listen (cfg, | ||
1043 | GNUNET_SET_OPERATION_INTERSECTION, | ||
1044 | &s->session_id, | ||
1045 | &cb_intersection_request_alice, | ||
1046 | s); | ||
1047 | if (NULL == s->intersection_listen) | ||
1048 | { | ||
1049 | s->active = GNUNET_SYSERR; | ||
1050 | GNUNET_CADET_channel_destroy (s->channel); | ||
1051 | s->channel = NULL; | ||
1052 | prepare_client_end_notification (s); | ||
1053 | return; | ||
1054 | } | ||
1055 | |||
1056 | e = GNUNET_MQ_msg (msg, | ||
1057 | GNUNET_MESSAGE_TYPE_SCALARPRODUCT_SESSION_INITIALIZATION); | ||
1058 | msg->session_id = s->session_id; | ||
1059 | GNUNET_MQ_send (s->cadet_mq, | ||
1060 | e); | ||
1061 | } | ||
1062 | |||
1063 | |||
1064 | /** | ||
1065 | * We're receiving additional set data. Add it to our | ||
1066 | * set and if we are done, initiate the transaction. | ||
1067 | * | ||
1068 | * @param cls closure | ||
1069 | * @param client identification of the client | ||
1070 | * @param message the actual message | ||
1071 | */ | ||
1072 | static void | ||
1073 | GSS_handle_alice_client_message_multipart (void *cls, | ||
1074 | struct GNUNET_SERVER_Client *client, | ||
1075 | const struct GNUNET_MessageHeader *message) | ||
1076 | { | ||
1077 | const struct ComputationMultipartMessage * msg; | ||
1078 | struct AliceServiceSession *s; | ||
1079 | uint32_t contained_count; | ||
1080 | const struct GNUNET_SCALARPRODUCT_Element *elements; | ||
1081 | uint32_t i; | ||
1082 | uint16_t msize; | ||
1083 | struct GNUNET_SET_Element set_elem; | ||
1084 | struct GNUNET_SCALARPRODUCT_Element *elem; | ||
1085 | |||
1086 | s = GNUNET_SERVER_client_get_user_context (client, | ||
1087 | struct AliceServiceSession); | ||
1088 | if (NULL == s) | ||
1089 | { | ||
1090 | /* session needs to already exist */ | ||
1091 | GNUNET_break (0); | ||
1092 | GNUNET_SERVER_receive_done (client, | ||
1093 | GNUNET_SYSERR); | ||
1094 | return; | ||
1095 | } | ||
1096 | msize = ntohs (message->size); | ||
1097 | if (msize < sizeof (struct ComputationMultipartMessage)) | ||
1098 | { | ||
1099 | GNUNET_break (0); | ||
1100 | GNUNET_SERVER_receive_done (client, | ||
1101 | GNUNET_SYSERR); | ||
1102 | return; | ||
1103 | } | ||
1104 | msg = (const struct ComputationMultipartMessage *) message; | ||
1105 | contained_count = ntohl (msg->element_count_contained); | ||
1106 | |||
1107 | if ( (msize != (sizeof (struct ComputationMultipartMessage) + | ||
1108 | contained_count * sizeof (struct GNUNET_SCALARPRODUCT_Element))) || | ||
1109 | (0 == contained_count) || | ||
1110 | (s->total == s->transferred_element_count) || | ||
1111 | (s->total < s->transferred_element_count + contained_count) ) | ||
1112 | { | ||
1113 | GNUNET_break_op (0); | ||
1114 | GNUNET_SERVER_receive_done (client, | ||
1115 | GNUNET_SYSERR); | ||
1116 | return; | ||
1117 | } | ||
1118 | s->transferred_element_count += contained_count; | ||
1119 | elements = (const struct GNUNET_SCALARPRODUCT_Element *) &msg[1]; | ||
1120 | for (i = 0; i < contained_count; i++) | ||
1121 | { | ||
1122 | if (0 == GNUNET_ntohll (elements[i].value)) | ||
1123 | continue; | ||
1124 | elem = GNUNET_new (struct GNUNET_SCALARPRODUCT_Element); | ||
1125 | memcpy (elem, | ||
1126 | &elements[i], | ||
1127 | sizeof (struct GNUNET_SCALARPRODUCT_Element)); | ||
1128 | if (GNUNET_SYSERR == | ||
1129 | GNUNET_CONTAINER_multihashmap_put (s->intersected_elements, | ||
1130 | &elem->key, | ||
1131 | elem, | ||
1132 | GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY)) | ||
1133 | { | ||
1134 | GNUNET_break (0); | ||
1135 | GNUNET_free (elem); | ||
1136 | continue; | ||
1137 | } | ||
1138 | set_elem.data = &elem->key; | ||
1139 | set_elem.size = sizeof (elem->key); | ||
1140 | set_elem.element_type = 0; | ||
1141 | GNUNET_SET_add_element (s->intersection_set, | ||
1142 | &set_elem, | ||
1143 | NULL, NULL); | ||
1144 | s->used_element_count++; | ||
1145 | } | ||
1146 | GNUNET_SERVER_receive_done (client, | ||
1147 | GNUNET_OK); | ||
1148 | if (s->total != s->transferred_element_count) | ||
1149 | { | ||
1150 | /* more to come */ | ||
1151 | return; | ||
1152 | } | ||
1153 | client_request_complete_alice (s); | ||
1154 | } | ||
1155 | |||
1156 | |||
1157 | /** | ||
1158 | * Handler for Alice's client request message. | ||
1159 | * We are doing request-initiation to compute a scalar product with a peer. | ||
1160 | * | ||
1161 | * @param cls closure | ||
1162 | * @param client identification of the client | ||
1163 | * @param message the actual message | ||
1164 | */ | ||
1165 | static void | ||
1166 | GSS_handle_alice_client_message (void *cls, | ||
1167 | struct GNUNET_SERVER_Client *client, | ||
1168 | const struct GNUNET_MessageHeader *message) | ||
1169 | { | ||
1170 | const struct AliceComputationMessage *msg; | ||
1171 | struct AliceServiceSession *s; | ||
1172 | uint32_t contained_count; | ||
1173 | uint32_t total_count; | ||
1174 | const struct GNUNET_SCALARPRODUCT_Element *elements; | ||
1175 | uint32_t i; | ||
1176 | uint16_t msize; | ||
1177 | struct GNUNET_SET_Element set_elem; | ||
1178 | struct GNUNET_SCALARPRODUCT_Element *elem; | ||
1179 | |||
1180 | s = GNUNET_SERVER_client_get_user_context (client, | ||
1181 | struct AliceServiceSession); | ||
1182 | if (NULL != s) | ||
1183 | { | ||
1184 | /* only one concurrent session per client connection allowed, | ||
1185 | simplifies logic a lot... */ | ||
1186 | GNUNET_break (0); | ||
1187 | GNUNET_SERVER_receive_done (client, GNUNET_SYSERR); | ||
1188 | return; | ||
1189 | } | ||
1190 | msize = ntohs (message->size); | ||
1191 | if (msize < sizeof (struct AliceComputationMessage)) | ||
1192 | { | ||
1193 | GNUNET_break (0); | ||
1194 | GNUNET_SERVER_receive_done (client, GNUNET_SYSERR); | ||
1195 | return; | ||
1196 | } | ||
1197 | msg = (const struct AliceComputationMessage *) message; | ||
1198 | total_count = ntohl (msg->element_count_total); | ||
1199 | contained_count = ntohl (msg->element_count_contained); | ||
1200 | if ( (0 == total_count) || | ||
1201 | (0 == contained_count) || | ||
1202 | (msize != (sizeof (struct AliceComputationMessage) + | ||
1203 | contained_count * sizeof (struct GNUNET_SCALARPRODUCT_Element))) ) | ||
1204 | { | ||
1205 | GNUNET_break_op (0); | ||
1206 | GNUNET_SERVER_receive_done (client, GNUNET_SYSERR); | ||
1207 | return; | ||
1208 | } | ||
1209 | |||
1210 | s = GNUNET_new (struct AliceServiceSession); | ||
1211 | s->peer = msg->peer; | ||
1212 | s->active = GNUNET_YES; | ||
1213 | s->client = client; | ||
1214 | s->client_mq = GNUNET_MQ_queue_for_server_client (client); | ||
1215 | s->total = total_count; | ||
1216 | s->transferred_element_count = contained_count; | ||
1217 | s->session_id = msg->session_key; | ||
1218 | elements = (const struct GNUNET_SCALARPRODUCT_Element *) &msg[1]; | ||
1219 | s->intersected_elements = GNUNET_CONTAINER_multihashmap_create (s->total, | ||
1220 | GNUNET_YES); | ||
1221 | s->intersection_set = GNUNET_SET_create (cfg, | ||
1222 | GNUNET_SET_OPERATION_INTERSECTION); | ||
1223 | for (i = 0; i < contained_count; i++) | ||
1224 | { | ||
1225 | if (0 == GNUNET_ntohll (elements[i].value)) | ||
1226 | continue; | ||
1227 | elem = GNUNET_new (struct GNUNET_SCALARPRODUCT_Element); | ||
1228 | memcpy (elem, | ||
1229 | &elements[i], | ||
1230 | sizeof (struct GNUNET_SCALARPRODUCT_Element)); | ||
1231 | if (GNUNET_SYSERR == | ||
1232 | GNUNET_CONTAINER_multihashmap_put (s->intersected_elements, | ||
1233 | &elem->key, | ||
1234 | elem, | ||
1235 | GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY)) | ||
1236 | { | ||
1237 | /* element with same key encountered twice! */ | ||
1238 | GNUNET_break (0); | ||
1239 | GNUNET_free (elem); | ||
1240 | continue; | ||
1241 | } | ||
1242 | set_elem.data = &elem->key; | ||
1243 | set_elem.size = sizeof (elem->key); | ||
1244 | set_elem.element_type = 0; | ||
1245 | GNUNET_SET_add_element (s->intersection_set, | ||
1246 | &set_elem, | ||
1247 | NULL, NULL); | ||
1248 | s->used_element_count++; | ||
1249 | } | ||
1250 | GNUNET_SERVER_client_set_user_context (client, | ||
1251 | s); | ||
1252 | GNUNET_SERVER_receive_done (client, | ||
1253 | GNUNET_OK); | ||
1254 | if (s->total != s->transferred_element_count) | ||
1255 | { | ||
1256 | /* wait for multipart msg */ | ||
1257 | return; | ||
1258 | } | ||
1259 | client_request_complete_alice (s); | ||
1260 | } | ||
1261 | |||
1262 | |||
1263 | /** | ||
1264 | * Task run during shutdown. | ||
1265 | * | ||
1266 | * @param cls unused | ||
1267 | * @param tc unused | ||
1268 | */ | ||
1269 | static void | ||
1270 | shutdown_task (void *cls, | ||
1271 | const struct GNUNET_SCHEDULER_TaskContext *tc) | ||
1272 | { | ||
1273 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
1274 | "Shutting down, initiating cleanup.\n"); | ||
1275 | if (NULL != my_cadet) | ||
1276 | { | ||
1277 | GNUNET_CADET_disconnect (my_cadet); | ||
1278 | my_cadet = NULL; | ||
1279 | } | ||
1280 | } | ||
1281 | |||
1282 | |||
1283 | /** | ||
1284 | * A client disconnected. | ||
1285 | * | ||
1286 | * Remove the associated session(s), release data structures | ||
1287 | * and cancel pending outgoing transmissions to the client. | ||
1288 | * | ||
1289 | * @param cls closure, NULL | ||
1290 | * @param client identification of the client | ||
1291 | */ | ||
1292 | static void | ||
1293 | handle_client_disconnect (void *cls, | ||
1294 | struct GNUNET_SERVER_Client *client) | ||
1295 | { | ||
1296 | struct AliceServiceSession *s; | ||
1297 | |||
1298 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
1299 | "Client %p disconnected from us.\n", | ||
1300 | client); | ||
1301 | s = GNUNET_SERVER_client_get_user_context (client, | ||
1302 | struct AliceServiceSession); | ||
1303 | if (NULL == s) | ||
1304 | return; | ||
1305 | s->client = NULL; | ||
1306 | GNUNET_SERVER_client_set_user_context (client, | ||
1307 | NULL); | ||
1308 | destroy_service_session (s); | ||
1309 | } | ||
1310 | |||
1311 | |||
1312 | /** | ||
1313 | * Initialization of the program and message handlers | ||
1314 | * | ||
1315 | * @param cls closure | ||
1316 | * @param server the initialized server | ||
1317 | * @param c configuration to use | ||
1318 | */ | ||
1319 | static void | ||
1320 | run (void *cls, | ||
1321 | struct GNUNET_SERVER_Handle *server, | ||
1322 | const struct GNUNET_CONFIGURATION_Handle *c) | ||
1323 | { | ||
1324 | static const struct GNUNET_CADET_MessageHandler cadet_handlers[] = { | ||
1325 | { &handle_bobs_cryptodata_message, | ||
1326 | GNUNET_MESSAGE_TYPE_SCALARPRODUCT_BOB_CRYPTODATA, | ||
1327 | 0}, | ||
1328 | { &handle_bobs_cryptodata_multipart, | ||
1329 | GNUNET_MESSAGE_TYPE_SCALARPRODUCT_BOB_CRYPTODATA_MULTIPART, | ||
1330 | 0}, | ||
1331 | { NULL, 0, 0} | ||
1332 | }; | ||
1333 | static const struct GNUNET_SERVER_MessageHandler server_handlers[] = { | ||
1334 | { &GSS_handle_alice_client_message, NULL, | ||
1335 | GNUNET_MESSAGE_TYPE_SCALARPRODUCT_CLIENT_TO_ALICE, | ||
1336 | 0}, | ||
1337 | { &GSS_handle_alice_client_message_multipart, NULL, | ||
1338 | GNUNET_MESSAGE_TYPE_SCALARPRODUCT_CLIENT_MUTLIPART_ALICE, | ||
1339 | 0}, | ||
1340 | { NULL, NULL, 0, 0} | ||
1341 | }; | ||
1342 | |||
1343 | cfg = c; | ||
1344 | /* | ||
1345 | offset has to be sufficiently small to allow computation of: | ||
1346 | m1+m2 mod n == (S + a) + (S + b) mod n, | ||
1347 | if we have more complex operations, this factor needs to be lowered */ | ||
1348 | my_offset = gcry_mpi_new (GNUNET_CRYPTO_PAILLIER_BITS / 3); | ||
1349 | gcry_mpi_set_bit (my_offset, | ||
1350 | GNUNET_CRYPTO_PAILLIER_BITS / 3); | ||
1351 | |||
1352 | GNUNET_CRYPTO_paillier_create (&my_pubkey, | ||
1353 | &my_privkey); | ||
1354 | GNUNET_SERVER_add_handlers (server, | ||
1355 | server_handlers); | ||
1356 | GNUNET_SERVER_disconnect_notify (server, | ||
1357 | &handle_client_disconnect, | ||
1358 | NULL); | ||
1359 | my_cadet = GNUNET_CADET_connect (cfg, NULL, | ||
1360 | NULL /* no incoming supported */, | ||
1361 | &cb_channel_destruction, | ||
1362 | cadet_handlers, | ||
1363 | NULL); | ||
1364 | if (NULL == my_cadet) | ||
1365 | { | ||
1366 | GNUNET_log (GNUNET_ERROR_TYPE_ERROR, | ||
1367 | _("Connect to CADET failed\n")); | ||
1368 | GNUNET_SCHEDULER_shutdown (); | ||
1369 | return; | ||
1370 | } | ||
1371 | GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_FOREVER_REL, | ||
1372 | &shutdown_task, | ||
1373 | NULL); | ||
1374 | |||
1375 | } | ||
1376 | |||
1377 | |||
1378 | /** | ||
1379 | * The main function for the scalarproduct service. | ||
1380 | * | ||
1381 | * @param argc number of arguments from the command line | ||
1382 | * @param argv command line arguments | ||
1383 | * @return 0 ok, 1 on error | ||
1384 | */ | ||
1385 | int | ||
1386 | main (int argc, | ||
1387 | char *const *argv) | ||
1388 | { | ||
1389 | return (GNUNET_OK == | ||
1390 | GNUNET_SERVICE_run (argc, argv, | ||
1391 | "scalarproduct-alice", | ||
1392 | GNUNET_SERVICE_OPTION_NONE, | ||
1393 | &run, NULL)) ? 0 : 1; | ||
1394 | } | ||
1395 | |||
1396 | /* end of gnunet-service-scalarproduct_alice.c */ | ||
diff --git a/src/scalarproduct/gnunet-service-scalarproduct_bob.c b/src/scalarproduct/gnunet-service-scalarproduct_bob.c new file mode 100644 index 000000000..ee74b515a --- /dev/null +++ b/src/scalarproduct/gnunet-service-scalarproduct_bob.c | |||
@@ -0,0 +1,1490 @@ | |||
1 | /* | ||
2 | This file is part of GNUnet. | ||
3 | (C) 2013, 2014 Christian Grothoff (and other contributing authors) | ||
4 | |||
5 | GNUnet is free software; you can redistribute it and/or modify | ||
6 | it under the terms of the GNU General Public License as published | ||
7 | by the Free Software Foundation; either version 3, or (at your | ||
8 | 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 | General Public License for more details. | ||
14 | |||
15 | You should have received a copy of the GNU General Public License | ||
16 | along with GNUnet; see the file COPYING. If not, write to the | ||
17 | Free Software Foundation, Inc., 59 Temple Place - Suite 330, | ||
18 | Boston, MA 02111-1307, USA. | ||
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_set_service.h" | ||
36 | #include "scalarproduct.h" | ||
37 | #include "gnunet-service-scalarproduct.h" | ||
38 | |||
39 | #define LOG(kind,...) GNUNET_log_from (kind, "scalarproduct-bob", __VA_ARGS__) | ||
40 | |||
41 | |||
42 | /** | ||
43 | * An encrypted element key-value pair. | ||
44 | */ | ||
45 | struct MpiElement | ||
46 | { | ||
47 | /** | ||
48 | * Key used to identify matching pairs of values to multiply. | ||
49 | * Points into an existing data structure, to avoid copying | ||
50 | * and doubling memory use. | ||
51 | */ | ||
52 | const struct GNUNET_HashCode *key; | ||
53 | |||
54 | /** | ||
55 | * Value represented (a). | ||
56 | */ | ||
57 | gcry_mpi_t value; | ||
58 | }; | ||
59 | |||
60 | |||
61 | /** | ||
62 | * An incoming session from CADET. | ||
63 | */ | ||
64 | struct CadetIncomingSession; | ||
65 | |||
66 | |||
67 | /** | ||
68 | * A scalarproduct session which tracks an offer for a | ||
69 | * multiplication service by a local client. | ||
70 | */ | ||
71 | struct BobServiceSession | ||
72 | { | ||
73 | |||
74 | /** | ||
75 | * (hopefully) unique transaction ID | ||
76 | */ | ||
77 | struct GNUNET_HashCode session_id; | ||
78 | |||
79 | /** | ||
80 | * The client this request is related to. | ||
81 | */ | ||
82 | struct GNUNET_SERVER_Client *client; | ||
83 | |||
84 | /** | ||
85 | * Client message queue. | ||
86 | */ | ||
87 | struct GNUNET_MQ_Handle *client_mq; | ||
88 | |||
89 | /** | ||
90 | * All non-0-value'd elements transmitted to us. | ||
91 | */ | ||
92 | struct GNUNET_CONTAINER_MultiHashMap *intersected_elements; | ||
93 | |||
94 | /** | ||
95 | * Set of elements for which we will be conducting an intersection. | ||
96 | * The resulting elements are then used for computing the scalar product. | ||
97 | */ | ||
98 | struct GNUNET_SET_Handle *intersection_set; | ||
99 | |||
100 | /** | ||
101 | * Set of elements for which will conduction an intersection. | ||
102 | * the resulting elements are then used for computing the scalar product. | ||
103 | */ | ||
104 | struct GNUNET_SET_OperationHandle *intersection_op; | ||
105 | |||
106 | /** | ||
107 | * a(Alice) | ||
108 | */ | ||
109 | struct MpiElement *sorted_elements; | ||
110 | |||
111 | /** | ||
112 | * E(ai)(Bob) after applying the mask | ||
113 | */ | ||
114 | struct GNUNET_CRYPTO_PaillierCiphertext *e_a; | ||
115 | |||
116 | /** | ||
117 | * Bob's permutation p of R | ||
118 | */ | ||
119 | struct GNUNET_CRYPTO_PaillierCiphertext *r; | ||
120 | |||
121 | /** | ||
122 | * Bob's permutation q of R | ||
123 | */ | ||
124 | struct GNUNET_CRYPTO_PaillierCiphertext *r_prime; | ||
125 | |||
126 | /** | ||
127 | * Bob's "s" | ||
128 | */ | ||
129 | struct GNUNET_CRYPTO_PaillierCiphertext s; | ||
130 | |||
131 | /** | ||
132 | * Bob's "s'" | ||
133 | */ | ||
134 | struct GNUNET_CRYPTO_PaillierCiphertext s_prime; | ||
135 | |||
136 | /** | ||
137 | * Handle for our associated incoming CADET session, or NULL | ||
138 | * if we have not gotten one yet. | ||
139 | */ | ||
140 | struct CadetIncomingSession *cadet; | ||
141 | |||
142 | /** | ||
143 | * The computed scalar | ||
144 | */ | ||
145 | gcry_mpi_t product; | ||
146 | |||
147 | /** | ||
148 | * How many elements we were supplied with from the client | ||
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. | ||
155 | */ | ||
156 | uint32_t used_element_count; | ||
157 | |||
158 | /** | ||
159 | * already transferred elements (sent/received) for multipart messages, less or equal than @e used_element_count for | ||
160 | */ | ||
161 | uint32_t transferred_element_count; | ||
162 | |||
163 | /** | ||
164 | * Is this session active (#GNUNET_YES), Concluded (#GNUNET_NO), or had an error (#GNUNET_SYSERR) | ||
165 | */ | ||
166 | int32_t active; | ||
167 | |||
168 | /** | ||
169 | * Are we already in #destroy_service_session()? | ||
170 | */ | ||
171 | int in_destroy; | ||
172 | |||
173 | }; | ||
174 | |||
175 | |||
176 | /** | ||
177 | * An incoming session from CADET. | ||
178 | */ | ||
179 | struct CadetIncomingSession | ||
180 | { | ||
181 | |||
182 | /** | ||
183 | * Associated client session, or NULL. | ||
184 | */ | ||
185 | struct BobServiceSession *s; | ||
186 | |||
187 | /** | ||
188 | * The CADET channel. | ||
189 | */ | ||
190 | struct GNUNET_CADET_Channel *channel; | ||
191 | |||
192 | /** | ||
193 | * Originator's peer identity. (Only for diagnostics.) | ||
194 | */ | ||
195 | struct GNUNET_PeerIdentity peer; | ||
196 | |||
197 | /** | ||
198 | * (hopefully) unique transaction ID | ||
199 | */ | ||
200 | struct GNUNET_HashCode session_id; | ||
201 | |||
202 | /** | ||
203 | * Public key of the remote service. | ||
204 | */ | ||
205 | struct GNUNET_CRYPTO_PaillierPublicKey remote_pubkey; | ||
206 | |||
207 | /** | ||
208 | * The message queue for this channel. | ||
209 | */ | ||
210 | struct GNUNET_MQ_Handle *cadet_mq; | ||
211 | |||
212 | /** | ||
213 | * Has this CADET session been added to the map yet? | ||
214 | * #GNUNET_YES if so, in which case @e session_id is | ||
215 | * the key. | ||
216 | */ | ||
217 | int in_map; | ||
218 | |||
219 | /** | ||
220 | * Are we already in #destroy_cadet_session()? | ||
221 | */ | ||
222 | int in_destroy; | ||
223 | |||
224 | }; | ||
225 | |||
226 | |||
227 | /** | ||
228 | * GNUnet configuration handle | ||
229 | */ | ||
230 | static const struct GNUNET_CONFIGURATION_Handle *cfg; | ||
231 | |||
232 | /** | ||
233 | * Service's own public key | ||
234 | */ | ||
235 | static struct GNUNET_CRYPTO_PaillierPublicKey my_pubkey; | ||
236 | |||
237 | /** | ||
238 | * Service's own private key | ||
239 | */ | ||
240 | static struct GNUNET_CRYPTO_PaillierPrivateKey my_privkey; | ||
241 | |||
242 | /** | ||
243 | * Service's offset for values that could possibly be negative but are plaintext for encryption. | ||
244 | */ | ||
245 | static gcry_mpi_t my_offset; | ||
246 | |||
247 | /** | ||
248 | * Map of `struct BobServiceSession`, by session keys. | ||
249 | */ | ||
250 | static struct GNUNET_CONTAINER_MultiHashMap *client_sessions; | ||
251 | |||
252 | /** | ||
253 | * Map of `struct CadetIncomingSession`, by session keys. | ||
254 | */ | ||
255 | static struct GNUNET_CONTAINER_MultiHashMap *cadet_sessions; | ||
256 | |||
257 | /** | ||
258 | * Handle to the CADET service. | ||
259 | */ | ||
260 | static struct GNUNET_CADET_Handle *my_cadet; | ||
261 | |||
262 | /** | ||
263 | * Certain events (callbacks for server & cadet operations) must not | ||
264 | * be queued after shutdown. | ||
265 | */ | ||
266 | static int do_shutdown; | ||
267 | |||
268 | |||
269 | |||
270 | /** | ||
271 | * Finds a not terminated client session in the respective map based on | ||
272 | * session key. | ||
273 | * | ||
274 | * @param key the session key we want to search for | ||
275 | * @return the matching session, or NULL for none | ||
276 | */ | ||
277 | static struct BobServiceSession * | ||
278 | find_matching_client_session (const struct GNUNET_HashCode *key) | ||
279 | { | ||
280 | return GNUNET_CONTAINER_multihashmap_get (client_sessions, | ||
281 | key); | ||
282 | } | ||
283 | |||
284 | |||
285 | /** | ||
286 | * Finds a CADET session in the respective map based on session key. | ||
287 | * | ||
288 | * @param key the session key we want to search for | ||
289 | * @return the matching session, or NULL for none | ||
290 | */ | ||
291 | static struct CadetIncomingSession * | ||
292 | find_matching_cadet_session (const struct GNUNET_HashCode *key) | ||
293 | { | ||
294 | return GNUNET_CONTAINER_multihashmap_get (cadet_sessions, | ||
295 | key); | ||
296 | } | ||
297 | |||
298 | |||
299 | /** | ||
300 | * Destroy session state, we are done with it. | ||
301 | * | ||
302 | * @param session the session to free elements from | ||
303 | */ | ||
304 | static void | ||
305 | destroy_cadet_session (struct CadetIncomingSession *s); | ||
306 | |||
307 | |||
308 | /** | ||
309 | * Destroy session state, we are done with it. | ||
310 | * | ||
311 | * @param session the session to free elements from | ||
312 | */ | ||
313 | static void | ||
314 | destroy_service_session (struct BobServiceSession *s) | ||
315 | { | ||
316 | struct CadetIncomingSession *in; | ||
317 | unsigned int i; | ||
318 | |||
319 | if (GNUNET_YES == s->in_destroy) | ||
320 | return; | ||
321 | s->in_destroy = GNUNET_YES; | ||
322 | if (NULL != (in = s->cadet)) | ||
323 | { | ||
324 | s->cadet = NULL; | ||
325 | destroy_cadet_session (in); | ||
326 | } | ||
327 | if (NULL != s->client_mq) | ||
328 | { | ||
329 | GNUNET_MQ_destroy (s->client_mq); | ||
330 | s->client_mq = NULL; | ||
331 | } | ||
332 | if (NULL != s->client) | ||
333 | { | ||
334 | GNUNET_SERVER_client_disconnect (s->client); | ||
335 | s->client = NULL; | ||
336 | } | ||
337 | GNUNET_assert (GNUNET_YES == | ||
338 | GNUNET_CONTAINER_multihashmap_remove (client_sessions, | ||
339 | &s->session_id, | ||
340 | s)); | ||
341 | if (NULL != s->intersected_elements) | ||
342 | { | ||
343 | /* FIXME: free elements */ | ||
344 | GNUNET_CONTAINER_multihashmap_destroy (s->intersected_elements); | ||
345 | s->intersected_elements = NULL; | ||
346 | } | ||
347 | if (NULL != s->intersection_op) | ||
348 | { | ||
349 | GNUNET_SET_operation_cancel (s->intersection_op); | ||
350 | s->intersection_op = NULL; | ||
351 | } | ||
352 | if (NULL != s->intersection_set) | ||
353 | { | ||
354 | GNUNET_SET_destroy (s->intersection_set); | ||
355 | s->intersection_set = NULL; | ||
356 | } | ||
357 | if (NULL != s->e_a) | ||
358 | { | ||
359 | GNUNET_free (s->e_a); | ||
360 | s->e_a = NULL; | ||
361 | } | ||
362 | if (NULL != s->sorted_elements) | ||
363 | { | ||
364 | for (i=0;i<s->used_element_count;i++) | ||
365 | gcry_mpi_release (s->sorted_elements[i].value); | ||
366 | GNUNET_free (s->sorted_elements); | ||
367 | s->sorted_elements = NULL; | ||
368 | } | ||
369 | if (NULL != s->r) | ||
370 | { | ||
371 | GNUNET_free (s->r); | ||
372 | s->r = NULL; | ||
373 | } | ||
374 | if (NULL != s->r_prime) | ||
375 | { | ||
376 | GNUNET_free (s->r_prime); | ||
377 | s->r_prime = NULL; | ||
378 | } | ||
379 | if (NULL != s->product) | ||
380 | { | ||
381 | gcry_mpi_release (s->product); | ||
382 | s->product = NULL; | ||
383 | } | ||
384 | GNUNET_free (s); | ||
385 | } | ||
386 | |||
387 | |||
388 | /** | ||
389 | * Destroy incoming CADET session state, we are done with it. | ||
390 | * | ||
391 | * @param in the session to free elements from | ||
392 | */ | ||
393 | static void | ||
394 | destroy_cadet_session (struct CadetIncomingSession *in) | ||
395 | { | ||
396 | struct BobServiceSession *s; | ||
397 | |||
398 | if (GNUNET_YES == in->in_destroy) | ||
399 | return; | ||
400 | in->in_destroy = GNUNET_YES; | ||
401 | if (NULL != (s = in->s)) | ||
402 | { | ||
403 | in->s = NULL; | ||
404 | destroy_service_session (s); | ||
405 | } | ||
406 | if (GNUNET_YES == in->in_map) | ||
407 | { | ||
408 | GNUNET_assert (GNUNET_YES == | ||
409 | GNUNET_CONTAINER_multihashmap_remove (cadet_sessions, | ||
410 | &in->session_id, | ||
411 | in)); | ||
412 | in->in_map = GNUNET_NO; | ||
413 | } | ||
414 | if (NULL != in->cadet_mq) | ||
415 | { | ||
416 | GNUNET_MQ_destroy (in->cadet_mq); | ||
417 | in->cadet_mq = NULL; | ||
418 | } | ||
419 | if (NULL != in->channel) | ||
420 | { | ||
421 | GNUNET_CADET_channel_destroy (in->channel); | ||
422 | in->channel = NULL; | ||
423 | } | ||
424 | GNUNET_free (in); | ||
425 | } | ||
426 | |||
427 | |||
428 | /** | ||
429 | * Notify the client that the session has succeeded or failed. This | ||
430 | * message gets sent to Bob's client if the operation completed or | ||
431 | * Alice disconnected. | ||
432 | * | ||
433 | * @param session the associated client session to fail or succeed | ||
434 | */ | ||
435 | static void | ||
436 | prepare_client_end_notification (struct BobServiceSession *session) | ||
437 | { | ||
438 | struct ClientResponseMessage *msg; | ||
439 | struct GNUNET_MQ_Envelope *e; | ||
440 | |||
441 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
442 | "Sending session-end notification with status %d to client for session %s\n", | ||
443 | session->active, | ||
444 | GNUNET_h2s (&session->session_id)); | ||
445 | e = GNUNET_MQ_msg (msg, | ||
446 | GNUNET_MESSAGE_TYPE_SCALARPRODUCT_RESULT); | ||
447 | msg->range = 0; | ||
448 | msg->product_length = htonl (0); | ||
449 | msg->status = htonl (session->active); | ||
450 | GNUNET_MQ_send (session->client_mq, | ||
451 | e); | ||
452 | } | ||
453 | |||
454 | |||
455 | /** | ||
456 | * Function called whenever a channel is destroyed. Should clean up | ||
457 | * any associated state. | ||
458 | * | ||
459 | * It must NOT call #GNUNET_CADET_channel_destroy() on the channel. | ||
460 | * | ||
461 | * @param cls closure (set from #GNUNET_CADET_connect()) | ||
462 | * @param channel connection to the other end (henceforth invalid) | ||
463 | * @param channel_ctx place where local state associated | ||
464 | * with the channel is stored | ||
465 | */ | ||
466 | static void | ||
467 | cb_channel_destruction (void *cls, | ||
468 | const struct GNUNET_CADET_Channel *channel, | ||
469 | void *channel_ctx) | ||
470 | { | ||
471 | struct CadetIncomingSession *in = channel_ctx; | ||
472 | struct BobServiceSession *s; | ||
473 | |||
474 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
475 | "Peer disconnected, terminating session %s with peer %s\n", | ||
476 | GNUNET_h2s (&in->session_id), | ||
477 | GNUNET_i2s (&in->peer)); | ||
478 | in->channel = NULL; | ||
479 | if (NULL != (s = in->s)) | ||
480 | { | ||
481 | if (GNUNET_YES == s->active) | ||
482 | { | ||
483 | s->active = GNUNET_SYSERR; | ||
484 | prepare_client_end_notification (s); | ||
485 | } | ||
486 | } | ||
487 | destroy_cadet_session (in); | ||
488 | } | ||
489 | |||
490 | |||
491 | /** | ||
492 | * MQ finished giving our last message to CADET, now notify | ||
493 | * the client that we are finished. | ||
494 | */ | ||
495 | static void | ||
496 | bob_cadet_done_cb (void *cls) | ||
497 | { | ||
498 | struct BobServiceSession *session = cls; | ||
499 | |||
500 | session->active = GNUNET_NO; /* that means, done */ | ||
501 | prepare_client_end_notification (session); | ||
502 | } | ||
503 | |||
504 | |||
505 | /** | ||
506 | * Maximum count of elements we can put into a multipart message | ||
507 | */ | ||
508 | #define ELEMENT_CAPACITY ((GNUNET_SERVER_MAX_MESSAGE_SIZE - 1 - sizeof (struct MultipartMessage)) / sizeof (struct GNUNET_CRYPTO_PaillierCiphertext)) | ||
509 | |||
510 | |||
511 | /** | ||
512 | * Send a multipart chunk of a service response from Bob to Alice. | ||
513 | * This element only contains the two permutations of R, R'. | ||
514 | * | ||
515 | * @param s the associated service session | ||
516 | */ | ||
517 | static void | ||
518 | transmit_bobs_cryptodata_message_multipart (struct BobServiceSession *s) | ||
519 | { | ||
520 | struct GNUNET_CRYPTO_PaillierCiphertext *payload; | ||
521 | struct MultipartMessage *msg; | ||
522 | struct GNUNET_MQ_Envelope *e; | ||
523 | unsigned int i; | ||
524 | unsigned int j; | ||
525 | uint32_t todo_count; | ||
526 | |||
527 | while (s->transferred_element_count != s->used_element_count) | ||
528 | { | ||
529 | todo_count = s->used_element_count - s->transferred_element_count; | ||
530 | if (todo_count > ELEMENT_CAPACITY / 2) | ||
531 | todo_count = ELEMENT_CAPACITY / 2; | ||
532 | |||
533 | e = GNUNET_MQ_msg_extra (msg, | ||
534 | todo_count * sizeof (struct GNUNET_CRYPTO_PaillierCiphertext) * 2, | ||
535 | GNUNET_MESSAGE_TYPE_SCALARPRODUCT_BOB_CRYPTODATA_MULTIPART); | ||
536 | msg->contained_element_count = htonl (todo_count); | ||
537 | payload = (struct GNUNET_CRYPTO_PaillierCiphertext *) &msg[1]; | ||
538 | for (i = s->transferred_element_count, j = 0; i < s->transferred_element_count + todo_count; i++) | ||
539 | { | ||
540 | //r[i][p] and r[i][q] | ||
541 | memcpy (&payload[j++], | ||
542 | &s->r[i], | ||
543 | sizeof (struct GNUNET_CRYPTO_PaillierCiphertext)); | ||
544 | memcpy (&payload[j++], | ||
545 | &s->r_prime[i], | ||
546 | sizeof (struct GNUNET_CRYPTO_PaillierCiphertext)); | ||
547 | } | ||
548 | s->transferred_element_count += todo_count; | ||
549 | if (s->transferred_element_count == s->used_element_count) | ||
550 | GNUNET_MQ_notify_sent (e, | ||
551 | &bob_cadet_done_cb, | ||
552 | s); | ||
553 | GNUNET_MQ_send (s->cadet->cadet_mq, | ||
554 | e); | ||
555 | } | ||
556 | } | ||
557 | |||
558 | |||
559 | /** | ||
560 | * Bob generates the response message to be sent to Alice after | ||
561 | * computing the values (1), (2), S and S'. | ||
562 | * | ||
563 | * (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)})$ | ||
564 | * (2)[]: $E_A(a_{pi'(i)}) times E_A(- r_{pi'(i)}) &= E_A(a_{pi'(i)} - r_{pi'(i)})$ | ||
565 | * S: $S := E_A(sum (r_i + b_i)^2)$ | ||
566 | * S': $S' := E_A(sum r_i^2)$ | ||
567 | * | ||
568 | * @param s the associated requesting session with Alice | ||
569 | */ | ||
570 | static void | ||
571 | transmit_bobs_cryptodata_message (struct BobServiceSession *s) | ||
572 | { | ||
573 | struct ServiceResponseMessage *msg; | ||
574 | struct GNUNET_MQ_Envelope *e; | ||
575 | struct GNUNET_CRYPTO_PaillierCiphertext *payload; | ||
576 | unsigned int i; | ||
577 | |||
578 | s->transferred_element_count = (GNUNET_SERVER_MAX_MESSAGE_SIZE - 1 - sizeof (struct ServiceResponseMessage)) / | ||
579 | (sizeof (struct GNUNET_CRYPTO_PaillierCiphertext) * 2) - 2; | ||
580 | if (s->transferred_element_count > s->used_element_count) | ||
581 | s->transferred_element_count = s->used_element_count; | ||
582 | |||
583 | e = GNUNET_MQ_msg_extra (msg, | ||
584 | (2 + s->transferred_element_count * 2) | ||
585 | * sizeof (struct GNUNET_CRYPTO_PaillierCiphertext), | ||
586 | GNUNET_MESSAGE_TYPE_SCALARPRODUCT_BOB_CRYPTODATA); | ||
587 | msg->total_element_count = htonl (s->total); | ||
588 | msg->used_element_count = htonl (s->used_element_count); | ||
589 | msg->contained_element_count = htonl (s->transferred_element_count); | ||
590 | msg->key = s->session_id; | ||
591 | |||
592 | payload = (struct GNUNET_CRYPTO_PaillierCiphertext *) &msg[1]; | ||
593 | memcpy (&payload[0], | ||
594 | &s->s, | ||
595 | sizeof (struct GNUNET_CRYPTO_PaillierCiphertext)); | ||
596 | memcpy (&payload[1], | ||
597 | &s->s_prime, | ||
598 | sizeof (struct GNUNET_CRYPTO_PaillierCiphertext)); | ||
599 | |||
600 | payload = &payload[2]; | ||
601 | // convert k[][] | ||
602 | for (i = 0; i < s->transferred_element_count; i++) | ||
603 | { | ||
604 | //k[i][p] and k[i][q] | ||
605 | memcpy (&payload[i * 2], | ||
606 | &s->r[i], | ||
607 | sizeof (struct GNUNET_CRYPTO_PaillierCiphertext)); | ||
608 | memcpy (&payload[i * 2 + 1], | ||
609 | &s->r_prime[i], | ||
610 | sizeof (struct GNUNET_CRYPTO_PaillierCiphertext)); | ||
611 | } | ||
612 | if (s->transferred_element_count == s->used_element_count) | ||
613 | GNUNET_MQ_notify_sent (e, | ||
614 | &bob_cadet_done_cb, | ||
615 | s); | ||
616 | GNUNET_MQ_send (s->cadet->cadet_mq, | ||
617 | e); | ||
618 | transmit_bobs_cryptodata_message_multipart (s); | ||
619 | } | ||
620 | |||
621 | |||
622 | /** | ||
623 | * Computes the square sum over a vector of a given length. | ||
624 | * | ||
625 | * @param vector the vector to compute over | ||
626 | * @param length the length of the vector | ||
627 | * @return an MPI value containing the calculated sum, never NULL | ||
628 | */ | ||
629 | static gcry_mpi_t | ||
630 | compute_square_sum (const gcry_mpi_t *vector, | ||
631 | uint32_t length) | ||
632 | { | ||
633 | gcry_mpi_t elem; | ||
634 | gcry_mpi_t sum; | ||
635 | uint32_t i; | ||
636 | |||
637 | GNUNET_assert (NULL != (sum = gcry_mpi_new (0))); | ||
638 | GNUNET_assert (NULL != (elem = gcry_mpi_new (0))); | ||
639 | for (i = 0; i < length; i++) | ||
640 | { | ||
641 | gcry_mpi_mul (elem, vector[i], vector[i]); | ||
642 | gcry_mpi_add (sum, sum, elem); | ||
643 | } | ||
644 | gcry_mpi_release (elem); | ||
645 | return sum; | ||
646 | } | ||
647 | |||
648 | |||
649 | /** | ||
650 | * Compute the values | ||
651 | * (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)})$ | ||
652 | * (2)[]: $E_A(a_{pi'(i)}) otimes E_A(- r_{pi'(i)}) &= E_A(a_{pi'(i)} - r_{pi'(i)})$ | ||
653 | * S: $S := E_A(sum (r_i + b_i)^2)$ | ||
654 | * S': $S' := E_A(sum r_i^2)$ | ||
655 | * | ||
656 | * @param request the requesting session + bob's requesting peer | ||
657 | */ | ||
658 | static void | ||
659 | compute_service_response (struct BobServiceSession *session) | ||
660 | { | ||
661 | uint32_t i; | ||
662 | unsigned int *p; | ||
663 | unsigned int *q; | ||
664 | uint32_t count; | ||
665 | gcry_mpi_t *rand; | ||
666 | gcry_mpi_t tmp; | ||
667 | const struct MpiElement *b; | ||
668 | struct GNUNET_CRYPTO_PaillierCiphertext *a; | ||
669 | struct GNUNET_CRYPTO_PaillierCiphertext *r; | ||
670 | struct GNUNET_CRYPTO_PaillierCiphertext *r_prime; | ||
671 | |||
672 | count = session->used_element_count; | ||
673 | a = session->e_a; | ||
674 | b = session->sorted_elements; | ||
675 | q = GNUNET_CRYPTO_random_permute (GNUNET_CRYPTO_QUALITY_WEAK, | ||
676 | count); | ||
677 | p = GNUNET_CRYPTO_random_permute (GNUNET_CRYPTO_QUALITY_WEAK, | ||
678 | count); | ||
679 | rand = GNUNET_malloc (sizeof (gcry_mpi_t) * count); | ||
680 | for (i = 0; i < count; i++) | ||
681 | GNUNET_assert (NULL != (rand[i] = gcry_mpi_new (0))); | ||
682 | r = GNUNET_malloc (sizeof (struct GNUNET_CRYPTO_PaillierCiphertext) * count); | ||
683 | r_prime = GNUNET_malloc (sizeof (struct GNUNET_CRYPTO_PaillierCiphertext) * count); | ||
684 | |||
685 | for (i = 0; i < count; i++) | ||
686 | { | ||
687 | int32_t svalue; | ||
688 | |||
689 | svalue = (int32_t) GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_WEAK, | ||
690 | UINT32_MAX); | ||
691 | // long to gcry_mpi_t | ||
692 | if (svalue < 0) | ||
693 | gcry_mpi_sub_ui (rand[i], | ||
694 | rand[i], | ||
695 | - svalue); | ||
696 | else | ||
697 | rand[i] = gcry_mpi_set_ui (rand[i], svalue); | ||
698 | } | ||
699 | |||
700 | tmp = gcry_mpi_new (0); | ||
701 | // encrypt the element | ||
702 | // for the sake of readability I decided to have dedicated permutation | ||
703 | // vectors, which get rid of all the lookups in p/q. | ||
704 | // however, ap/aq are not absolutely necessary but are just abstraction | ||
705 | // Calculate Kp = E(S + a_pi) (+) E(S - r_pi - b_pi) | ||
706 | for (i = 0; i < count; i++) | ||
707 | { | ||
708 | // E(S - r_pi - b_pi) | ||
709 | gcry_mpi_sub (tmp, my_offset, rand[p[i]]); | ||
710 | gcry_mpi_sub (tmp, tmp, b[p[i]].value); | ||
711 | GNUNET_CRYPTO_paillier_encrypt (&session->cadet->remote_pubkey, | ||
712 | tmp, | ||
713 | 2, | ||
714 | &r[i]); | ||
715 | |||
716 | // E(S - r_pi - b_pi) * E(S + a_pi) == E(2*S + a - r - b) | ||
717 | GNUNET_CRYPTO_paillier_hom_add (&session->cadet->remote_pubkey, | ||
718 | &r[i], | ||
719 | &a[p[i]], | ||
720 | &r[i]); | ||
721 | } | ||
722 | |||
723 | // Calculate Kq = E(S + a_qi) (+) E(S - r_qi) | ||
724 | for (i = 0; i < count; i++) | ||
725 | { | ||
726 | // E(S - r_qi) | ||
727 | gcry_mpi_sub (tmp, my_offset, rand[q[i]]); | ||
728 | GNUNET_assert (2 == GNUNET_CRYPTO_paillier_encrypt (&session->cadet->remote_pubkey, | ||
729 | tmp, | ||
730 | 2, | ||
731 | &r_prime[i])); | ||
732 | |||
733 | // E(S - r_qi) * E(S + a_qi) == E(2*S + a_qi - r_qi) | ||
734 | GNUNET_assert (1 == GNUNET_CRYPTO_paillier_hom_add (&session->cadet->remote_pubkey, | ||
735 | &r_prime[i], | ||
736 | &a[q[i]], | ||
737 | &r_prime[i])); | ||
738 | } | ||
739 | |||
740 | // Calculate S' = E(SUM( r_i^2 )) | ||
741 | tmp = compute_square_sum (rand, count); | ||
742 | GNUNET_CRYPTO_paillier_encrypt (&session->cadet->remote_pubkey, | ||
743 | tmp, | ||
744 | 1, | ||
745 | &session->s_prime); | ||
746 | |||
747 | // Calculate S = E(SUM( (r_i + b_i)^2 )) | ||
748 | for (i = 0; i < count; i++) | ||
749 | gcry_mpi_add (rand[i], rand[i], b[i].value); | ||
750 | tmp = compute_square_sum (rand, count); | ||
751 | GNUNET_CRYPTO_paillier_encrypt (&session->cadet->remote_pubkey, | ||
752 | tmp, | ||
753 | 1, | ||
754 | &session->s); | ||
755 | |||
756 | session->r = r; | ||
757 | session->r_prime = r_prime; | ||
758 | |||
759 | // release rand, b and a | ||
760 | for (i = 0; i < count; i++) | ||
761 | gcry_mpi_release (rand[i]); | ||
762 | gcry_mpi_release (tmp); | ||
763 | GNUNET_free (session->e_a); | ||
764 | session->e_a = NULL; | ||
765 | GNUNET_free (p); | ||
766 | GNUNET_free (q); | ||
767 | GNUNET_free (rand); | ||
768 | |||
769 | // copy the r[], r_prime[], S and Stick into a new message, prepare_service_response frees these | ||
770 | } | ||
771 | |||
772 | |||
773 | |||
774 | |||
775 | |||
776 | /** | ||
777 | * Iterator to copy over messages from the hash map | ||
778 | * into an array for sorting. | ||
779 | * | ||
780 | * @param cls the `struct AliceServiceSession *` | ||
781 | * @param key the key (unused) | ||
782 | * @param value the `struct GNUNET_SCALARPRODUCT_Element *` | ||
783 | */ | ||
784 | static int | ||
785 | copy_element_cb (void *cls, | ||
786 | const struct GNUNET_HashCode *key, | ||
787 | void *value) | ||
788 | { | ||
789 | struct BobServiceSession *s = cls; | ||
790 | struct GNUNET_SCALARPRODUCT_Element *e = value; | ||
791 | gcry_mpi_t mval; | ||
792 | int64_t val; | ||
793 | |||
794 | mval = gcry_mpi_new (0); | ||
795 | val = (int64_t) GNUNET_ntohll (e->value); | ||
796 | if (0 > val) | ||
797 | gcry_mpi_sub_ui (mval, mval, -val); | ||
798 | else | ||
799 | gcry_mpi_add_ui (mval, mval, val); | ||
800 | s->sorted_elements [s->used_element_count].value = mval; | ||
801 | s->sorted_elements [s->used_element_count].key = &e->key; | ||
802 | s->used_element_count++; | ||
803 | return GNUNET_OK; | ||
804 | } | ||
805 | |||
806 | |||
807 | /** | ||
808 | * Compare two `struct MpiValue`s by key for sorting. | ||
809 | * | ||
810 | * @param a pointer to first `struct MpiValue *` | ||
811 | * @param b pointer to first `struct MpiValue *` | ||
812 | * @return -1 for a < b, 0 for a=b, 1 for a > b. | ||
813 | */ | ||
814 | static int | ||
815 | element_cmp (const void *a, | ||
816 | const void *b) | ||
817 | { | ||
818 | const struct MpiElement *ma = *(const struct MpiElement **) a; | ||
819 | const struct MpiElement *mb = *(const struct MpiElement **) b; | ||
820 | |||
821 | return GNUNET_CRYPTO_hash_cmp (ma->key, | ||
822 | mb->key); | ||
823 | } | ||
824 | |||
825 | |||
826 | /** | ||
827 | * Intersection operation and receiving data via CADET from | ||
828 | * Alice are both done, compute and transmit our reply via | ||
829 | * CADET. | ||
830 | * | ||
831 | * @param s session to transmit reply for. | ||
832 | */ | ||
833 | static void | ||
834 | transmit_cryptographic_reply (struct BobServiceSession *s) | ||
835 | { | ||
836 | s->sorted_elements | ||
837 | = GNUNET_malloc (GNUNET_CONTAINER_multihashmap_size (s->intersected_elements) * | ||
838 | sizeof (struct MpiElement)); | ||
839 | s->used_element_count = 0; | ||
840 | GNUNET_CONTAINER_multihashmap_iterate (s->intersected_elements, | ||
841 | ©_element_cb, | ||
842 | s); | ||
843 | LOG (GNUNET_ERROR_TYPE_DEBUG, | ||
844 | "Finished intersection, %d items remain\n", | ||
845 | s->used_element_count); | ||
846 | qsort (s->intersected_elements, | ||
847 | s->used_element_count, | ||
848 | sizeof (struct MpiElement), | ||
849 | &element_cmp); | ||
850 | compute_service_response (s); | ||
851 | transmit_bobs_cryptodata_message (s); | ||
852 | } | ||
853 | |||
854 | |||
855 | /** | ||
856 | * Handle a multipart-chunk of a request from another service to | ||
857 | * calculate a scalarproduct with us. | ||
858 | * | ||
859 | * @param cls closure (set from #GNUNET_CADET_connect) | ||
860 | * @param channel connection to the other end | ||
861 | * @param channel_ctx place to store local state associated with the @a channel | ||
862 | * @param message the actual message | ||
863 | * @return #GNUNET_OK to keep the connection open, | ||
864 | * #GNUNET_SYSERR to close it (signal serious error) | ||
865 | */ | ||
866 | static int | ||
867 | handle_alices_cryptodata_message (void *cls, | ||
868 | struct GNUNET_CADET_Channel *channel, | ||
869 | void **channel_ctx, | ||
870 | const struct GNUNET_MessageHeader *message) | ||
871 | { | ||
872 | struct CadetIncomingSession *in = *channel_ctx; | ||
873 | struct BobServiceSession *s; | ||
874 | const struct AliceCryptodataMessage *msg; | ||
875 | const struct GNUNET_CRYPTO_PaillierCiphertext *payload; | ||
876 | uint32_t contained_elements; | ||
877 | size_t msg_length; | ||
878 | uint16_t msize; | ||
879 | unsigned int max; | ||
880 | |||
881 | if (NULL == in) | ||
882 | { | ||
883 | GNUNET_break_op (0); | ||
884 | return GNUNET_SYSERR; | ||
885 | } | ||
886 | s = in->s; | ||
887 | if (NULL == s) | ||
888 | { | ||
889 | GNUNET_break_op (0); | ||
890 | return GNUNET_SYSERR; | ||
891 | } | ||
892 | msize = ntohs (message->size); | ||
893 | if (msize <= sizeof (struct AliceCryptodataMessage)) | ||
894 | { | ||
895 | GNUNET_break_op (0); | ||
896 | return GNUNET_SYSERR; | ||
897 | } | ||
898 | msg = (const struct AliceCryptodataMessage *) message; | ||
899 | contained_elements = ntohl (msg->contained_element_count); | ||
900 | /* Our intersection may still be ongoing, but this is nevertheless | ||
901 | an upper bound on the required array size */ | ||
902 | max = GNUNET_CONTAINER_multihashmap_size (s->intersected_elements); | ||
903 | msg_length = sizeof (struct AliceCryptodataMessage) | ||
904 | + contained_elements * sizeof (struct GNUNET_CRYPTO_PaillierCiphertext); | ||
905 | if ( (msize != msg_length) || | ||
906 | (0 == contained_elements) || | ||
907 | (contained_elements > UINT16_MAX) || | ||
908 | (max < contained_elements + s->transferred_element_count) ) | ||
909 | { | ||
910 | GNUNET_break_op (0); | ||
911 | return GNUNET_SYSERR; | ||
912 | } | ||
913 | |||
914 | payload = (const struct GNUNET_CRYPTO_PaillierCiphertext *) &msg[1]; | ||
915 | if (NULL == s->e_a) | ||
916 | s->e_a = GNUNET_malloc (sizeof (struct GNUNET_CRYPTO_PaillierCiphertext) * | ||
917 | max); | ||
918 | memcpy (&s->e_a[s->transferred_element_count], | ||
919 | payload, | ||
920 | sizeof (struct GNUNET_CRYPTO_PaillierCiphertext) * contained_elements); | ||
921 | s->transferred_element_count += contained_elements; | ||
922 | |||
923 | if ( (s->transferred_element_count == max) && | ||
924 | (NULL == s->intersection_op) ) | ||
925 | { | ||
926 | /* intersection has finished also on our side, and | ||
927 | we got the full set, so we can proceed with the | ||
928 | CADET response(s) */ | ||
929 | transmit_cryptographic_reply (s); | ||
930 | } | ||
931 | return GNUNET_OK; | ||
932 | } | ||
933 | |||
934 | |||
935 | /** | ||
936 | * Callback for set operation results. Called for each element | ||
937 | * that needs to be removed from the result set. | ||
938 | * | ||
939 | * @param cls closure with the `struct BobServiceSession` | ||
940 | * @param element a result element, only valid if status is #GNUNET_SET_STATUS_OK | ||
941 | * @param status what has happened with the set intersection? | ||
942 | */ | ||
943 | static void | ||
944 | cb_intersection_element_removed (void *cls, | ||
945 | const struct GNUNET_SET_Element *element, | ||
946 | enum GNUNET_SET_Status status) | ||
947 | { | ||
948 | struct BobServiceSession *s = cls; | ||
949 | struct GNUNET_SCALARPRODUCT_Element *se; | ||
950 | |||
951 | switch (status) | ||
952 | { | ||
953 | case GNUNET_SET_STATUS_OK: | ||
954 | /* this element has been removed from the set */ | ||
955 | se = GNUNET_CONTAINER_multihashmap_get (s->intersected_elements, | ||
956 | element->data); | ||
957 | LOG (GNUNET_ERROR_TYPE_DEBUG, | ||
958 | "Removed element with key %s and value %lld\n", | ||
959 | GNUNET_h2s (&se->key), | ||
960 | (long long) GNUNET_ntohll (se->value)); | ||
961 | GNUNET_assert (GNUNET_YES == | ||
962 | GNUNET_CONTAINER_multihashmap_remove (s->intersected_elements, | ||
963 | element->data, | ||
964 | se)); | ||
965 | GNUNET_free (se); | ||
966 | return; | ||
967 | case GNUNET_SET_STATUS_DONE: | ||
968 | s->intersection_op = NULL; | ||
969 | s->intersection_set = NULL; | ||
970 | if (s->transferred_element_count == | ||
971 | GNUNET_CONTAINER_multihashmap_size (s->intersected_elements)) | ||
972 | { | ||
973 | /* CADET transmission from Alice is also already done, | ||
974 | start with our own reply */ | ||
975 | transmit_cryptographic_reply (s); | ||
976 | } | ||
977 | return; | ||
978 | case GNUNET_SET_STATUS_HALF_DONE: | ||
979 | /* unexpected for intersection */ | ||
980 | GNUNET_break (0); | ||
981 | return; | ||
982 | case GNUNET_SET_STATUS_FAILURE: | ||
983 | /* unhandled status code */ | ||
984 | LOG (GNUNET_ERROR_TYPE_DEBUG, | ||
985 | "Set intersection failed!\n"); | ||
986 | s->intersection_op = NULL; | ||
987 | s->intersection_set = NULL; | ||
988 | s->active = GNUNET_SYSERR; | ||
989 | prepare_client_end_notification (s); | ||
990 | return; | ||
991 | default: | ||
992 | GNUNET_break (0); | ||
993 | return; | ||
994 | } | ||
995 | } | ||
996 | |||
997 | |||
998 | /** | ||
999 | * We've paired up a client session with an incoming CADET request. | ||
1000 | * Initiate set intersection work. | ||
1001 | * | ||
1002 | * @param s client session to start intersection for | ||
1003 | */ | ||
1004 | static void | ||
1005 | start_intersection (struct BobServiceSession *s) | ||
1006 | { | ||
1007 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
1008 | "Got session with key %s and a matching element set, processing.\n", | ||
1009 | GNUNET_h2s (&s->session_id)); | ||
1010 | |||
1011 | s->intersection_op | ||
1012 | = GNUNET_SET_prepare (&s->cadet->peer, | ||
1013 | &s->session_id, | ||
1014 | NULL, | ||
1015 | GNUNET_SET_RESULT_REMOVED, | ||
1016 | &cb_intersection_element_removed, | ||
1017 | s); | ||
1018 | GNUNET_SET_commit (s->intersection_op, | ||
1019 | s->intersection_set); | ||
1020 | } | ||
1021 | |||
1022 | |||
1023 | /** | ||
1024 | * Handle a request from Alice to calculate a scalarproduct with us (Bob). | ||
1025 | * | ||
1026 | * @param cls closure (set from #GNUNET_CADET_connect) | ||
1027 | * @param channel connection to the other end | ||
1028 | * @param channel_ctx place to store the `struct CadetIncomingSession *` | ||
1029 | * @param message the actual message | ||
1030 | * @return #GNUNET_OK to keep the connection open, | ||
1031 | * #GNUNET_SYSERR to close it (signal serious error) | ||
1032 | */ | ||
1033 | static int | ||
1034 | handle_alices_computation_request (void *cls, | ||
1035 | struct GNUNET_CADET_Channel *channel, | ||
1036 | void **channel_ctx, | ||
1037 | const struct GNUNET_MessageHeader *message) | ||
1038 | { | ||
1039 | struct CadetIncomingSession *in = *channel_ctx; | ||
1040 | struct BobServiceSession *s; | ||
1041 | const struct ServiceRequestMessage *msg; | ||
1042 | |||
1043 | if (ntohs (message->size) != sizeof (struct ServiceRequestMessage)) | ||
1044 | { | ||
1045 | GNUNET_break_op (0); | ||
1046 | return GNUNET_SYSERR; | ||
1047 | } | ||
1048 | msg = (const struct ServiceRequestMessage *) message; | ||
1049 | if (GNUNET_YES == in->in_map) | ||
1050 | { | ||
1051 | GNUNET_break_op (0); | ||
1052 | return GNUNET_SYSERR; | ||
1053 | } | ||
1054 | if (NULL != find_matching_cadet_session (&msg->session_id)) | ||
1055 | { | ||
1056 | /* not unique, got one like this already */ | ||
1057 | GNUNET_break_op (0); | ||
1058 | return GNUNET_SYSERR; | ||
1059 | } | ||
1060 | in->session_id = msg->session_id; | ||
1061 | in->remote_pubkey = msg->public_key; | ||
1062 | GNUNET_assert (GNUNET_YES == | ||
1063 | GNUNET_CONTAINER_multihashmap_put (cadet_sessions, | ||
1064 | &in->session_id, | ||
1065 | in, | ||
1066 | GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY)); | ||
1067 | s = find_matching_client_session (&in->session_id); | ||
1068 | if (NULL == s) | ||
1069 | { | ||
1070 | /* no client waiting for this request, wait for client */ | ||
1071 | return GNUNET_OK; | ||
1072 | } | ||
1073 | GNUNET_assert (NULL == s->cadet); | ||
1074 | /* pair them up */ | ||
1075 | in->s = s; | ||
1076 | s->cadet = in; | ||
1077 | if (s->transferred_element_count == s->total) | ||
1078 | start_intersection (s); | ||
1079 | return GNUNET_OK; | ||
1080 | } | ||
1081 | |||
1082 | |||
1083 | /** | ||
1084 | * Function called for inbound channels on Bob's end. Does some | ||
1085 | * preliminary initialization, more happens after we get Alice's first | ||
1086 | * message. | ||
1087 | * | ||
1088 | * @param cls closure | ||
1089 | * @param channel new handle to the channel | ||
1090 | * @param initiator peer that started the channel | ||
1091 | * @param port unused | ||
1092 | * @param options unused | ||
1093 | * @return session associated with the channel | ||
1094 | */ | ||
1095 | static void * | ||
1096 | cb_channel_incoming (void *cls, | ||
1097 | struct GNUNET_CADET_Channel *channel, | ||
1098 | const struct GNUNET_PeerIdentity *initiator, | ||
1099 | uint32_t port, | ||
1100 | enum GNUNET_CADET_ChannelOption options) | ||
1101 | { | ||
1102 | struct CadetIncomingSession *in; | ||
1103 | |||
1104 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
1105 | "New incoming channel from peer %s.\n", | ||
1106 | GNUNET_i2s (initiator)); | ||
1107 | in = GNUNET_new (struct CadetIncomingSession); | ||
1108 | in->peer = *initiator; | ||
1109 | in->channel = channel; | ||
1110 | return in; | ||
1111 | } | ||
1112 | |||
1113 | |||
1114 | /** | ||
1115 | * We're receiving additional set data. Add it to our | ||
1116 | * set and if we are done, initiate the transaction. | ||
1117 | * | ||
1118 | * @param cls closure | ||
1119 | * @param client identification of the client | ||
1120 | * @param message the actual message | ||
1121 | */ | ||
1122 | static void | ||
1123 | GSS_handle_bob_client_message_multipart (void *cls, | ||
1124 | struct GNUNET_SERVER_Client *client, | ||
1125 | const struct GNUNET_MessageHeader *message) | ||
1126 | { | ||
1127 | const struct ComputationMultipartMessage * msg; | ||
1128 | struct BobServiceSession *s; | ||
1129 | uint32_t contained_count; | ||
1130 | const struct GNUNET_SCALARPRODUCT_Element *elements; | ||
1131 | uint32_t i; | ||
1132 | uint16_t msize; | ||
1133 | struct GNUNET_SET_Element set_elem; | ||
1134 | struct GNUNET_SCALARPRODUCT_Element *elem; | ||
1135 | |||
1136 | s = GNUNET_SERVER_client_get_user_context (client, | ||
1137 | struct BobServiceSession); | ||
1138 | if (NULL == s) | ||
1139 | { | ||
1140 | /* session needs to already exist */ | ||
1141 | GNUNET_break (0); | ||
1142 | GNUNET_SERVER_receive_done (client, | ||
1143 | GNUNET_SYSERR); | ||
1144 | return; | ||
1145 | } | ||
1146 | msize = ntohs (message->size); | ||
1147 | if (msize < sizeof (struct ComputationMultipartMessage)) | ||
1148 | { | ||
1149 | GNUNET_break (0); | ||
1150 | GNUNET_SERVER_receive_done (client, | ||
1151 | GNUNET_SYSERR); | ||
1152 | return; | ||
1153 | } | ||
1154 | msg = (const struct ComputationMultipartMessage *) message; | ||
1155 | contained_count = ntohl (msg->element_count_contained); | ||
1156 | |||
1157 | if ( (msize != (sizeof (struct ComputationMultipartMessage) + | ||
1158 | contained_count * sizeof (struct GNUNET_SCALARPRODUCT_Element))) || | ||
1159 | (0 == contained_count) || | ||
1160 | (UINT16_MAX < contained_count) || | ||
1161 | (s->total == s->transferred_element_count) || | ||
1162 | (s->total < s->transferred_element_count + contained_count) ) | ||
1163 | { | ||
1164 | GNUNET_break_op (0); | ||
1165 | GNUNET_SERVER_receive_done (client, | ||
1166 | GNUNET_SYSERR); | ||
1167 | return; | ||
1168 | } | ||
1169 | elements = (const struct GNUNET_SCALARPRODUCT_Element *) &msg[1]; | ||
1170 | for (i = 0; i < contained_count; i++) | ||
1171 | { | ||
1172 | if (0 == GNUNET_ntohll (elements[i].value)) | ||
1173 | continue; | ||
1174 | elem = GNUNET_new (struct GNUNET_SCALARPRODUCT_Element); | ||
1175 | memcpy (elem, | ||
1176 | &elements[i], | ||
1177 | sizeof (struct GNUNET_SCALARPRODUCT_Element)); | ||
1178 | if (GNUNET_SYSERR == | ||
1179 | GNUNET_CONTAINER_multihashmap_put (s->intersected_elements, | ||
1180 | &elem->key, | ||
1181 | elem, | ||
1182 | GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY)) | ||
1183 | { | ||
1184 | GNUNET_break (0); | ||
1185 | GNUNET_free (elem); | ||
1186 | continue; | ||
1187 | } | ||
1188 | set_elem.data = &elem->key; | ||
1189 | set_elem.size = sizeof (elem->key); | ||
1190 | set_elem.element_type = 0; | ||
1191 | GNUNET_SET_add_element (s->intersection_set, | ||
1192 | &set_elem, | ||
1193 | NULL, NULL); | ||
1194 | } | ||
1195 | s->transferred_element_count += contained_count; | ||
1196 | GNUNET_SERVER_receive_done (client, | ||
1197 | GNUNET_OK); | ||
1198 | if (s->total != s->transferred_element_count) | ||
1199 | { | ||
1200 | /* more to come */ | ||
1201 | return; | ||
1202 | } | ||
1203 | if (NULL == s->cadet) | ||
1204 | { | ||
1205 | /* no Alice waiting for this request, wait for Alice */ | ||
1206 | return; | ||
1207 | } | ||
1208 | start_intersection (s); | ||
1209 | } | ||
1210 | |||
1211 | |||
1212 | /** | ||
1213 | * Handler for Bob's a client request message. Bob is in the response | ||
1214 | * role, keep the values + session and waiting for a matching session | ||
1215 | * or process a waiting request from Alice. | ||
1216 | * | ||
1217 | * @param cls closure | ||
1218 | * @param client identification of the client | ||
1219 | * @param message the actual message | ||
1220 | */ | ||
1221 | static void | ||
1222 | GSS_handle_bob_client_message (void *cls, | ||
1223 | struct GNUNET_SERVER_Client *client, | ||
1224 | const struct GNUNET_MessageHeader *message) | ||
1225 | { | ||
1226 | const struct BobComputationMessage *msg; | ||
1227 | struct BobServiceSession *s; | ||
1228 | struct CadetIncomingSession *in; | ||
1229 | uint32_t contained_count; | ||
1230 | uint32_t total_count; | ||
1231 | const struct GNUNET_SCALARPRODUCT_Element *elements; | ||
1232 | uint32_t i; | ||
1233 | struct GNUNET_SET_Element set_elem; | ||
1234 | struct GNUNET_SCALARPRODUCT_Element *elem; | ||
1235 | uint16_t msize; | ||
1236 | |||
1237 | s = GNUNET_SERVER_client_get_user_context (client, | ||
1238 | struct BobServiceSession); | ||
1239 | if (NULL != s) | ||
1240 | { | ||
1241 | /* only one concurrent session per client connection allowed, | ||
1242 | simplifies logic a lot... */ | ||
1243 | GNUNET_break (0); | ||
1244 | GNUNET_SERVER_receive_done (client, | ||
1245 | GNUNET_SYSERR); | ||
1246 | return; | ||
1247 | } | ||
1248 | msize = ntohs (message->size); | ||
1249 | if (msize < sizeof (struct BobComputationMessage)) | ||
1250 | { | ||
1251 | GNUNET_break (0); | ||
1252 | GNUNET_SERVER_receive_done (client, | ||
1253 | GNUNET_SYSERR); | ||
1254 | return; | ||
1255 | } | ||
1256 | msg = (const struct BobComputationMessage *) message; | ||
1257 | total_count = ntohl (msg->element_count_total); | ||
1258 | contained_count = ntohl (msg->element_count_contained); | ||
1259 | if ( (0 == total_count) || | ||
1260 | (0 == contained_count) || | ||
1261 | (UINT16_MAX < contained_count) || | ||
1262 | (msize != (sizeof (struct BobComputationMessage) + | ||
1263 | contained_count * sizeof (struct GNUNET_SCALARPRODUCT_Element))) ) | ||
1264 | { | ||
1265 | GNUNET_break_op (0); | ||
1266 | GNUNET_SERVER_receive_done (client, | ||
1267 | GNUNET_SYSERR); | ||
1268 | return; | ||
1269 | } | ||
1270 | if (NULL != find_matching_client_session (&msg->session_key)) | ||
1271 | { | ||
1272 | GNUNET_break (0); | ||
1273 | GNUNET_SERVER_receive_done (client, | ||
1274 | GNUNET_SYSERR); | ||
1275 | return; | ||
1276 | } | ||
1277 | |||
1278 | s = GNUNET_new (struct BobServiceSession); | ||
1279 | s->active = GNUNET_YES; | ||
1280 | s->client = client; | ||
1281 | s->client_mq = GNUNET_MQ_queue_for_server_client (client); | ||
1282 | s->total = total_count; | ||
1283 | s->transferred_element_count = contained_count; | ||
1284 | s->session_id = msg->session_key; | ||
1285 | GNUNET_break (GNUNET_YES == | ||
1286 | GNUNET_CONTAINER_multihashmap_put (client_sessions, | ||
1287 | &s->session_id, | ||
1288 | s, | ||
1289 | GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY)); | ||
1290 | elements = (const struct GNUNET_SCALARPRODUCT_Element *) &msg[1]; | ||
1291 | s->intersected_elements = GNUNET_CONTAINER_multihashmap_create (s->total, | ||
1292 | GNUNET_YES); | ||
1293 | s->intersection_set = GNUNET_SET_create (cfg, | ||
1294 | GNUNET_SET_OPERATION_INTERSECTION); | ||
1295 | for (i = 0; i < contained_count; i++) | ||
1296 | { | ||
1297 | if (0 == GNUNET_ntohll (elements[i].value)) | ||
1298 | continue; | ||
1299 | elem = GNUNET_new (struct GNUNET_SCALARPRODUCT_Element); | ||
1300 | memcpy (elem, | ||
1301 | &elements[i], | ||
1302 | sizeof (struct GNUNET_SCALARPRODUCT_Element)); | ||
1303 | if (GNUNET_SYSERR == | ||
1304 | GNUNET_CONTAINER_multihashmap_put (s->intersected_elements, | ||
1305 | &elem->key, | ||
1306 | elem, | ||
1307 | GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY)) | ||
1308 | { | ||
1309 | GNUNET_break (0); | ||
1310 | GNUNET_free (elem); | ||
1311 | continue; | ||
1312 | } | ||
1313 | set_elem.data = &elem->key; | ||
1314 | set_elem.size = sizeof (elem->key); | ||
1315 | set_elem.element_type = 0; | ||
1316 | GNUNET_SET_add_element (s->intersection_set, | ||
1317 | &set_elem, | ||
1318 | NULL, NULL); | ||
1319 | s->used_element_count++; | ||
1320 | } | ||
1321 | GNUNET_SERVER_client_set_user_context (client, | ||
1322 | s); | ||
1323 | GNUNET_SERVER_receive_done (client, | ||
1324 | GNUNET_YES); | ||
1325 | if (s->total != s->transferred_element_count) | ||
1326 | { | ||
1327 | /* multipart msg */ | ||
1328 | return; | ||
1329 | } | ||
1330 | in = find_matching_cadet_session (&s->session_id); | ||
1331 | if (NULL == in) | ||
1332 | { | ||
1333 | /* nothing yet, wait for Alice */ | ||
1334 | return; | ||
1335 | } | ||
1336 | GNUNET_assert (NULL == in->s); | ||
1337 | /* pair them up */ | ||
1338 | in->s = s; | ||
1339 | s->cadet = in; | ||
1340 | start_intersection (s); | ||
1341 | } | ||
1342 | |||
1343 | |||
1344 | /** | ||
1345 | * Task run during shutdown. | ||
1346 | * | ||
1347 | * @param cls unused | ||
1348 | * @param tc unused | ||
1349 | */ | ||
1350 | static void | ||
1351 | shutdown_task (void *cls, | ||
1352 | const struct GNUNET_SCHEDULER_TaskContext *tc) | ||
1353 | { | ||
1354 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
1355 | "Shutting down, initiating cleanup.\n"); | ||
1356 | do_shutdown = GNUNET_YES; | ||
1357 | // FIXME: is there a need to shutdown active sessions? | ||
1358 | if (NULL != my_cadet) | ||
1359 | { | ||
1360 | GNUNET_CADET_disconnect (my_cadet); | ||
1361 | my_cadet = NULL; | ||
1362 | } | ||
1363 | GNUNET_CONTAINER_multihashmap_destroy (client_sessions); | ||
1364 | client_sessions = NULL; | ||
1365 | GNUNET_CONTAINER_multihashmap_destroy (cadet_sessions); | ||
1366 | cadet_sessions = NULL; | ||
1367 | } | ||
1368 | |||
1369 | |||
1370 | /** | ||
1371 | * A client disconnected. | ||
1372 | * | ||
1373 | * Remove the associated session(s), release data structures | ||
1374 | * and cancel pending outgoing transmissions to the client. | ||
1375 | * | ||
1376 | * @param cls closure, NULL | ||
1377 | * @param client identification of the client | ||
1378 | */ | ||
1379 | static void | ||
1380 | handle_client_disconnect (void *cls, | ||
1381 | struct GNUNET_SERVER_Client *client) | ||
1382 | { | ||
1383 | struct BobServiceSession *s; | ||
1384 | |||
1385 | if (NULL == client) | ||
1386 | return; | ||
1387 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
1388 | "Client disconnected from us.\n", | ||
1389 | client); | ||
1390 | s = GNUNET_SERVER_client_get_user_context (client, | ||
1391 | struct BobServiceSession); | ||
1392 | if (NULL == s) | ||
1393 | return; | ||
1394 | s->client = NULL; | ||
1395 | destroy_service_session (s); | ||
1396 | } | ||
1397 | |||
1398 | |||
1399 | /** | ||
1400 | * Initialization of the program and message handlers | ||
1401 | * | ||
1402 | * @param cls closure | ||
1403 | * @param server the initialized server | ||
1404 | * @param c configuration to use | ||
1405 | */ | ||
1406 | static void | ||
1407 | run (void *cls, | ||
1408 | struct GNUNET_SERVER_Handle *server, | ||
1409 | const struct GNUNET_CONFIGURATION_Handle *c) | ||
1410 | { | ||
1411 | static const struct GNUNET_SERVER_MessageHandler server_handlers[] = { | ||
1412 | { &GSS_handle_bob_client_message, NULL, | ||
1413 | GNUNET_MESSAGE_TYPE_SCALARPRODUCT_CLIENT_TO_BOB, | ||
1414 | 0}, | ||
1415 | { &GSS_handle_bob_client_message_multipart, NULL, | ||
1416 | GNUNET_MESSAGE_TYPE_SCALARPRODUCT_CLIENT_MUTLIPART_BOB, | ||
1417 | 0}, | ||
1418 | { NULL, NULL, 0, 0} | ||
1419 | }; | ||
1420 | static const struct GNUNET_CADET_MessageHandler cadet_handlers[] = { | ||
1421 | { &handle_alices_computation_request, | ||
1422 | GNUNET_MESSAGE_TYPE_SCALARPRODUCT_SESSION_INITIALIZATION, | ||
1423 | sizeof (struct ServiceRequestMessage) }, | ||
1424 | { &handle_alices_cryptodata_message, | ||
1425 | GNUNET_MESSAGE_TYPE_SCALARPRODUCT_ALICE_CRYPTODATA, | ||
1426 | 0}, | ||
1427 | { NULL, 0, 0} | ||
1428 | }; | ||
1429 | static const uint32_t ports[] = { | ||
1430 | GNUNET_APPLICATION_TYPE_SCALARPRODUCT, | ||
1431 | 0 | ||
1432 | }; | ||
1433 | |||
1434 | cfg = c; | ||
1435 | /* | ||
1436 | offset has to be sufficiently small to allow computation of: | ||
1437 | m1+m2 mod n == (S + a) + (S + b) mod n, | ||
1438 | if we have more complex operations, this factor needs to be lowered */ | ||
1439 | my_offset = gcry_mpi_new (GNUNET_CRYPTO_PAILLIER_BITS / 3); | ||
1440 | gcry_mpi_set_bit (my_offset, | ||
1441 | GNUNET_CRYPTO_PAILLIER_BITS / 3); | ||
1442 | |||
1443 | GNUNET_CRYPTO_paillier_create (&my_pubkey, | ||
1444 | &my_privkey); | ||
1445 | GNUNET_SERVER_add_handlers (server, | ||
1446 | server_handlers); | ||
1447 | GNUNET_SERVER_disconnect_notify (server, | ||
1448 | &handle_client_disconnect, | ||
1449 | NULL); | ||
1450 | client_sessions = GNUNET_CONTAINER_multihashmap_create (128, | ||
1451 | GNUNET_YES); | ||
1452 | cadet_sessions = GNUNET_CONTAINER_multihashmap_create (128, | ||
1453 | GNUNET_YES); | ||
1454 | my_cadet = GNUNET_CADET_connect (cfg, NULL, | ||
1455 | &cb_channel_incoming, | ||
1456 | &cb_channel_destruction, | ||
1457 | cadet_handlers, | ||
1458 | ports); | ||
1459 | if (NULL == my_cadet) | ||
1460 | { | ||
1461 | GNUNET_log (GNUNET_ERROR_TYPE_ERROR, | ||
1462 | _("Connect to CADET failed\n")); | ||
1463 | GNUNET_SCHEDULER_shutdown (); | ||
1464 | return; | ||
1465 | } | ||
1466 | GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_FOREVER_REL, | ||
1467 | &shutdown_task, | ||
1468 | NULL); | ||
1469 | } | ||
1470 | |||
1471 | |||
1472 | /** | ||
1473 | * The main function for the scalarproduct service. | ||
1474 | * | ||
1475 | * @param argc number of arguments from the command line | ||
1476 | * @param argv command line arguments | ||
1477 | * @return 0 ok, 1 on error | ||
1478 | */ | ||
1479 | int | ||
1480 | main (int argc, | ||
1481 | char *const *argv) | ||
1482 | { | ||
1483 | return (GNUNET_OK == | ||
1484 | GNUNET_SERVICE_run (argc, argv, | ||
1485 | "scalarproduct-bob", | ||
1486 | GNUNET_SERVICE_OPTION_NONE, | ||
1487 | &run, NULL)) ? 0 : 1; | ||
1488 | } | ||
1489 | |||
1490 | /* end of gnunet-service-scalarproduct_bob.c */ | ||
diff --git a/src/scalarproduct/scalarproduct.conf.in b/src/scalarproduct/scalarproduct.conf.in index 5aea5cd7b..a383e37cc 100644 --- a/src/scalarproduct/scalarproduct.conf.in +++ b/src/scalarproduct/scalarproduct.conf.in | |||
@@ -1,6 +1,10 @@ | |||
1 | [scalarproduct] | 1 | [scalarproduct-alice] |
2 | BINARY = gnunet-service-scalarproduct | 2 | BINARY = gnunet-service-scalarproduct-alice |
3 | UNIXPATH = $GNUNET_RUNTIME_DIR/gnunet-service-scalarproduct.sock | 3 | UNIXPATH = $GNUNET_RUNTIME_DIR/gnunet-service-scalarproduct-alice.sock |
4 | # PORT = 2106 | 4 | @UNIXONLY@ PORT = 2117 |
5 | @UNIXONLY@ PORT = 2087 | 5 | |
6 | [scalarproduct-bob] | ||
7 | BINARY = gnunet-service-scalarproduct-bob | ||
8 | UNIXPATH = $GNUNET_RUNTIME_DIR/gnunet-service-scalarproduct-bob.sock | ||
9 | @UNIXONLY@ PORT = 2118 | ||
6 | 10 | ||
diff --git a/src/scalarproduct/scalarproduct.h b/src/scalarproduct/scalarproduct.h index 4bafb18fb..bcd2d6821 100644 --- a/src/scalarproduct/scalarproduct.h +++ b/src/scalarproduct/scalarproduct.h | |||
@@ -17,23 +17,14 @@ | |||
17 | Free Software Foundation, Inc., 59 Temple Place - Suite 330, | 17 | Free Software Foundation, Inc., 59 Temple Place - Suite 330, |
18 | Boston, MA 02111-1307, USA. | 18 | Boston, MA 02111-1307, USA. |
19 | */ | 19 | */ |
20 | |||
21 | /** | 20 | /** |
22 | * @file scalarproduct.h | 21 | * @file scalarproduct.h |
23 | * @brief Scalar Product Message Types | 22 | * @brief Scalar Product Message Types |
24 | * @author Christian M. Fuchs | 23 | * @author Christian M. Fuchs |
25 | * | ||
26 | * Created on September 2, 2013, 3:43 PM | ||
27 | */ | 24 | */ |
28 | |||
29 | #ifndef SCALARPRODUCT_H | 25 | #ifndef SCALARPRODUCT_H |
30 | #define SCALARPRODUCT_H | 26 | #define SCALARPRODUCT_H |
31 | 27 | ||
32 | #ifdef __cplusplus | ||
33 | extern "C" | ||
34 | { | ||
35 | #endif | ||
36 | |||
37 | GNUNET_NETWORK_STRUCT_BEGIN | 28 | GNUNET_NETWORK_STRUCT_BEGIN |
38 | 29 | ||
39 | /** | 30 | /** |
@@ -48,10 +39,11 @@ GNUNET_NETWORK_STRUCT_BEGIN | |||
48 | * Message type passed from client to service | 39 | * Message type passed from client to service |
49 | * to initiate a request or responder role | 40 | * to initiate a request or responder role |
50 | */ | 41 | */ |
51 | struct ComputationMessage | 42 | struct AliceComputationMessage |
52 | { | 43 | { |
53 | /** | 44 | /** |
54 | * GNUNET message header | 45 | * GNUNET message header with type |
46 | * #GNUNET_MESSAGE_TYPE_SCALARPRODUCT_CLIENT_TO_ALICE | ||
55 | */ | 47 | */ |
56 | struct GNUNET_MessageHeader header; | 48 | struct GNUNET_MessageHeader header; |
57 | 49 | ||
@@ -87,6 +79,44 @@ struct ComputationMessage | |||
87 | 79 | ||
88 | 80 | ||
89 | /** | 81 | /** |
82 | * Message type passed from client to service | ||
83 | * to initiate a request or responder role | ||
84 | */ | ||
85 | struct BobComputationMessage | ||
86 | { | ||
87 | /** | ||
88 | * GNUNET message header with type | ||
89 | * #GNUNET_MESSAGE_TYPE_SCALARPRODUCT_CLIENT_TO_BOB | ||
90 | */ | ||
91 | struct GNUNET_MessageHeader header; | ||
92 | |||
93 | /** | ||
94 | * how many elements the vector in payload contains | ||
95 | */ | ||
96 | uint32_t element_count_total GNUNET_PACKED; | ||
97 | |||
98 | /** | ||
99 | * contained elements the vector in payload contains | ||
100 | */ | ||
101 | uint32_t element_count_contained GNUNET_PACKED; | ||
102 | |||
103 | /** | ||
104 | * Always zero. | ||
105 | */ | ||
106 | uint32_t reserved GNUNET_PACKED; | ||
107 | |||
108 | /** | ||
109 | * the transaction/session key used to identify a session | ||
110 | */ | ||
111 | struct GNUNET_HashCode session_key; | ||
112 | |||
113 | /** | ||
114 | * followed by struct GNUNET_SCALARPRODUCT_Element[] | ||
115 | */ | ||
116 | }; | ||
117 | |||
118 | |||
119 | /** | ||
90 | * multipart messages following `struct ComputationMessage` | 120 | * multipart messages following `struct ComputationMessage` |
91 | */ | 121 | */ |
92 | struct ComputationMultipartMessage | 122 | struct ComputationMultipartMessage |
@@ -140,9 +170,5 @@ struct ClientResponseMessage | |||
140 | 170 | ||
141 | GNUNET_NETWORK_STRUCT_END | 171 | GNUNET_NETWORK_STRUCT_END |
142 | 172 | ||
143 | #ifdef __cplusplus | ||
144 | } | ||
145 | #endif | ||
146 | |||
147 | #endif /* SCALARPRODUCT_H */ | 173 | #endif /* SCALARPRODUCT_H */ |
148 | 174 | ||
diff --git a/src/scalarproduct/scalarproduct_api.c b/src/scalarproduct/scalarproduct_api.c index 5cb827838..8a4a0af98 100644 --- a/src/scalarproduct/scalarproduct_api.c +++ b/src/scalarproduct/scalarproduct_api.c | |||
@@ -23,6 +23,8 @@ | |||
23 | * @author Christian Fuchs | 23 | * @author Christian Fuchs |
24 | * @author Gaurav Kukreja | 24 | * @author Gaurav Kukreja |
25 | * @author Christian Grothoff | 25 | * @author Christian Grothoff |
26 | * | ||
27 | * TODO: use MQ | ||
26 | */ | 28 | */ |
27 | #include "platform.h" | 29 | #include "platform.h" |
28 | #include "gnunet_util_lib.h" | 30 | #include "gnunet_util_lib.h" |
@@ -113,6 +115,11 @@ struct GNUNET_SCALARPRODUCT_ComputationHandle | |||
113 | */ | 115 | */ |
114 | uint32_t element_count_transfered; | 116 | uint32_t element_count_transfered; |
115 | 117 | ||
118 | /** | ||
119 | * Type to use for the multipart messages. | ||
120 | */ | ||
121 | uint16_t mp_type; | ||
122 | |||
116 | }; | 123 | }; |
117 | 124 | ||
118 | 125 | ||
@@ -307,7 +314,7 @@ do_send_message (void *cls, | |||
307 | msg = GNUNET_malloc (nsize); | 314 | msg = GNUNET_malloc (nsize); |
308 | h->msg = &msg->header; | 315 | h->msg = &msg->header; |
309 | msg->header.size = htons (nsize); | 316 | msg->header.size = htons (nsize); |
310 | msg->header.type = htons (GNUNET_MESSAGE_TYPE_SCALARPRODUCT_CLIENT_MUTLIPART); | 317 | msg->header.type = htons (h->mp_type); |
311 | msg->element_count_contained = htonl (todo); | 318 | msg->element_count_contained = htonl (todo); |
312 | memcpy (&msg[1], | 319 | memcpy (&msg[1], |
313 | &h->elements[h->element_count_transfered], | 320 | &h->elements[h->element_count_transfered], |
@@ -342,7 +349,7 @@ GNUNET_SCALARPRODUCT_accept_computation (const struct GNUNET_CONFIGURATION_Handl | |||
342 | void *cont_cls) | 349 | void *cont_cls) |
343 | { | 350 | { |
344 | struct GNUNET_SCALARPRODUCT_ComputationHandle *h; | 351 | struct GNUNET_SCALARPRODUCT_ComputationHandle *h; |
345 | struct ComputationMessage *msg; | 352 | struct BobComputationMessage *msg; |
346 | uint32_t size; | 353 | uint32_t size; |
347 | uint16_t possible; | 354 | uint16_t possible; |
348 | 355 | ||
@@ -352,8 +359,9 @@ GNUNET_SCALARPRODUCT_accept_computation (const struct GNUNET_CONFIGURATION_Handl | |||
352 | h->response_proc = &process_status_message; | 359 | h->response_proc = &process_status_message; |
353 | h->cfg = cfg; | 360 | h->cfg = cfg; |
354 | h->key = *session_key; | 361 | h->key = *session_key; |
355 | h->client = GNUNET_CLIENT_connect ("scalarproduct", cfg); | 362 | h->client = GNUNET_CLIENT_connect ("scalarproduct-bob", cfg); |
356 | h->element_count_total = element_count; | 363 | h->element_count_total = element_count; |
364 | h->mp_type = GNUNET_MESSAGE_TYPE_SCALARPRODUCT_CLIENT_MUTLIPART_BOB; | ||
357 | if (NULL == h->client) | 365 | if (NULL == h->client) |
358 | { | 366 | { |
359 | /* scalarproduct configuration error */ | 367 | /* scalarproduct configuration error */ |
@@ -361,7 +369,7 @@ GNUNET_SCALARPRODUCT_accept_computation (const struct GNUNET_CONFIGURATION_Handl | |||
361 | GNUNET_free (h); | 369 | GNUNET_free (h); |
362 | return NULL; | 370 | return NULL; |
363 | } | 371 | } |
364 | size = sizeof (struct ComputationMessage) | 372 | size = sizeof (struct BobComputationMessage) |
365 | + element_count * sizeof (struct GNUNET_SCALARPRODUCT_Element); | 373 | + element_count * sizeof (struct GNUNET_SCALARPRODUCT_Element); |
366 | if (GNUNET_SERVER_MAX_MESSAGE_SIZE > size) | 374 | if (GNUNET_SERVER_MAX_MESSAGE_SIZE > size) |
367 | { | 375 | { |
@@ -371,10 +379,10 @@ GNUNET_SCALARPRODUCT_accept_computation (const struct GNUNET_CONFIGURATION_Handl | |||
371 | else | 379 | else |
372 | { | 380 | { |
373 | /* create a multipart msg, first we calculate a new msg size for the head msg */ | 381 | /* create a multipart msg, first we calculate a new msg size for the head msg */ |
374 | possible = (GNUNET_SERVER_MAX_MESSAGE_SIZE - 1 - sizeof (struct ComputationMessage)) | 382 | possible = (GNUNET_SERVER_MAX_MESSAGE_SIZE - 1 - sizeof (struct BobComputationMessage)) |
375 | / sizeof (struct GNUNET_SCALARPRODUCT_Element); | 383 | / sizeof (struct GNUNET_SCALARPRODUCT_Element); |
376 | h->element_count_transfered = possible; | 384 | h->element_count_transfered = possible; |
377 | size = sizeof (struct ComputationMessage) | 385 | size = sizeof (struct BobComputationMessage) |
378 | + possible * sizeof (struct GNUNET_SCALARPRODUCT_Element); | 386 | + possible * sizeof (struct GNUNET_SCALARPRODUCT_Element); |
379 | h->elements = GNUNET_malloc (sizeof(struct GNUNET_SCALARPRODUCT_Element) * element_count); | 387 | h->elements = GNUNET_malloc (sizeof(struct GNUNET_SCALARPRODUCT_Element) * element_count); |
380 | memcpy (h->elements, | 388 | memcpy (h->elements, |
@@ -423,12 +431,12 @@ GNUNET_SCALARPRODUCT_start_computation (const struct GNUNET_CONFIGURATION_Handle | |||
423 | void *cont_cls) | 431 | void *cont_cls) |
424 | { | 432 | { |
425 | struct GNUNET_SCALARPRODUCT_ComputationHandle *h; | 433 | struct GNUNET_SCALARPRODUCT_ComputationHandle *h; |
426 | struct ComputationMessage *msg; | 434 | struct AliceComputationMessage *msg; |
427 | uint32_t size; | 435 | uint32_t size; |
428 | uint32_t possible; | 436 | uint32_t possible; |
429 | 437 | ||
430 | h = GNUNET_new (struct GNUNET_SCALARPRODUCT_ComputationHandle); | 438 | h = GNUNET_new (struct GNUNET_SCALARPRODUCT_ComputationHandle); |
431 | h->client = GNUNET_CLIENT_connect ("scalarproduct", cfg); | 439 | h->client = GNUNET_CLIENT_connect ("scalarproduct-alice", cfg); |
432 | if (NULL == h->client) | 440 | if (NULL == h->client) |
433 | { | 441 | { |
434 | /* missconfigured scalarproduct service */ | 442 | /* missconfigured scalarproduct service */ |
@@ -442,7 +450,8 @@ GNUNET_SCALARPRODUCT_start_computation (const struct GNUNET_CONFIGURATION_Handle | |||
442 | h->response_proc = &process_result_message; | 450 | h->response_proc = &process_result_message; |
443 | h->cfg = cfg; | 451 | h->cfg = cfg; |
444 | h->key = *session_key; | 452 | h->key = *session_key; |
445 | size = sizeof (struct ComputationMessage) | 453 | h->mp_type = GNUNET_MESSAGE_TYPE_SCALARPRODUCT_CLIENT_MUTLIPART_ALICE; |
454 | size = sizeof (struct AliceComputationMessage) | ||
446 | + element_count * sizeof (struct GNUNET_SCALARPRODUCT_Element); | 455 | + element_count * sizeof (struct GNUNET_SCALARPRODUCT_Element); |
447 | if (GNUNET_SERVER_MAX_MESSAGE_SIZE > size) | 456 | if (GNUNET_SERVER_MAX_MESSAGE_SIZE > size) |
448 | { | 457 | { |
@@ -452,10 +461,10 @@ GNUNET_SCALARPRODUCT_start_computation (const struct GNUNET_CONFIGURATION_Handle | |||
452 | else | 461 | else |
453 | { | 462 | { |
454 | /* create a multipart msg, first we calculate a new msg size for the head msg */ | 463 | /* create a multipart msg, first we calculate a new msg size for the head msg */ |
455 | possible = (GNUNET_SERVER_MAX_MESSAGE_SIZE - 1 - sizeof (struct ComputationMessage)) | 464 | possible = (GNUNET_SERVER_MAX_MESSAGE_SIZE - 1 - sizeof (struct AliceComputationMessage)) |
456 | / sizeof (struct GNUNET_SCALARPRODUCT_Element); | 465 | / sizeof (struct GNUNET_SCALARPRODUCT_Element); |
457 | h->element_count_transfered = possible; | 466 | h->element_count_transfered = possible; |
458 | size = sizeof (struct ComputationMessage) | 467 | size = sizeof (struct AliceComputationMessage) |
459 | + possible * sizeof (struct GNUNET_SCALARPRODUCT_Element); | 468 | + possible * sizeof (struct GNUNET_SCALARPRODUCT_Element); |
460 | h->elements = GNUNET_malloc (sizeof(struct GNUNET_SCALARPRODUCT_Element) * element_count); | 469 | h->elements = GNUNET_malloc (sizeof(struct GNUNET_SCALARPRODUCT_Element) * element_count); |
461 | memcpy (h->elements, | 470 | memcpy (h->elements, |
diff --git a/src/scalarproduct/test_scalarproduct.conf b/src/scalarproduct/test_scalarproduct.conf index fb9a34da6..b61197dac 100644 --- a/src/scalarproduct/test_scalarproduct.conf +++ b/src/scalarproduct/test_scalarproduct.conf | |||
@@ -1,5 +1,5 @@ | |||
1 | [arm] | 1 | [arm] |
2 | DEFAULTSERVICES = core cadet statistics scalarproduct set | 2 | DEFAULTSERVICES = core cadet statistics set |
3 | PORT = 12366 | 3 | PORT = 12366 |
4 | 4 | ||
5 | [PATHS] | 5 | [PATHS] |