gnunet-service-scalarproduct-ecc_alice.c 33 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149
  1. /*
  2. This file is part of GNUnet.
  3. Copyright (C) 2013-2017, 2021 GNUnet e.V.
  4. GNUnet is free software: you can redistribute it and/or modify it
  5. under the terms of the GNU Affero General Public License as published
  6. by the Free Software Foundation, either version 3 of the License,
  7. or (at your option) any later version.
  8. GNUnet is distributed in the hope that it will be useful, but
  9. WITHOUT ANY WARRANTY; without even the implied warranty of
  10. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
  11. Affero General Public License for more details.
  12. You should have received a copy of the GNU Affero General Public License
  13. along with this program. If not, see <http://www.gnu.org/licenses/>.
  14. SPDX-License-Identifier: AGPL3.0-or-later
  15. */
  16. /**
  17. * @file scalarproduct/gnunet-service-scalarproduct-ecc_alice.c
  18. * @brief scalarproduct service implementation
  19. * @author Christian M. Fuchs
  20. * @author Christian Grothoff
  21. */
  22. #include "platform.h"
  23. #include <limits.h>
  24. #include <gcrypt.h>
  25. #include "gnunet_util_lib.h"
  26. #include "gnunet_core_service.h"
  27. #include "gnunet_cadet_service.h"
  28. #include "gnunet_applications.h"
  29. #include "gnunet_protocols.h"
  30. #include "gnunet_scalarproduct_service.h"
  31. #include "gnunet_seti_service.h"
  32. #include "scalarproduct.h"
  33. #include "gnunet-service-scalarproduct-ecc.h"
  34. #define LOG(kind, ...) \
  35. GNUNET_log_from (kind, "scalarproduct-alice", __VA_ARGS__)
  36. /**
  37. * Maximum allowed result value for the scalarproduct computation.
  38. * DLOG will fail if the result is bigger. At 1 million, the
  39. * precomputation takes about 2s on a fast machine.
  40. */
  41. #define MAX_RESULT (1024 * 1024)
  42. /**
  43. * How many values should DLOG store in memory (determines baseline
  44. * RAM consumption, roughly 100 bytes times the value given here).
  45. * Should be about SQRT (MAX_RESULT), larger values will make the
  46. * online computation faster.
  47. */
  48. #define MAX_RAM (1024)
  49. /**
  50. * An encrypted element key-value pair.
  51. */
  52. struct MpiElement
  53. {
  54. /**
  55. * Key used to identify matching pairs of values to multiply.
  56. * Points into an existing data structure, to avoid copying
  57. * and doubling memory use.
  58. */
  59. const struct GNUNET_HashCode *key;
  60. /**
  61. * a_i value, not disclosed to Bob.
  62. */
  63. int64_t value;
  64. };
  65. /**
  66. * A scalarproduct session which tracks
  67. * a request form the client to our final response.
  68. */
  69. struct AliceServiceSession
  70. {
  71. /**
  72. * (hopefully) unique transaction ID
  73. */
  74. struct GNUNET_HashCode session_id;
  75. /**
  76. * Alice or Bob's peerID
  77. */
  78. struct GNUNET_PeerIdentity peer;
  79. /**
  80. * The client this request is related to.
  81. */
  82. struct GNUNET_SERVICE_Client *client;
  83. /**
  84. * The message queue for the client.
  85. */
  86. struct GNUNET_MQ_Handle *client_mq;
  87. /**
  88. * The message queue for CADET.
  89. */
  90. struct GNUNET_MQ_Handle *cadet_mq;
  91. /**
  92. * all non-0-value'd elements transmitted to us.
  93. * Values are of type `struct GNUNET_SCALARPRODUCT_Element *`
  94. */
  95. struct GNUNET_CONTAINER_MultiHashMap *intersected_elements;
  96. /**
  97. * Set of elements for which will conduction an intersection.
  98. * the resulting elements are then used for computing the scalar product.
  99. */
  100. struct GNUNET_SETI_Handle *intersection_set;
  101. /**
  102. * Set of elements for which will conduction an intersection.
  103. * the resulting elements are then used for computing the scalar product.
  104. */
  105. struct GNUNET_SETI_OperationHandle *intersection_op;
  106. /**
  107. * Handle to Alice's Intersection operation listening for Bob
  108. */
  109. struct GNUNET_SETI_ListenHandle *intersection_listen;
  110. /**
  111. * channel-handle associated with our cadet handle
  112. */
  113. struct GNUNET_CADET_Channel *channel;
  114. /**
  115. * a(Alice), sorted array by key of length @e used_element_count.
  116. */
  117. struct MpiElement *sorted_elements;
  118. /**
  119. * The computed scalar product. INT_MAX if the computation failed.
  120. */
  121. int product;
  122. /**
  123. * How many elements we were supplied with from the client (total
  124. * count before intersection).
  125. */
  126. uint32_t total;
  127. /**
  128. * How many elements actually are used for the scalar product.
  129. * Size of the arrays in @e r and @e r_prime. Sometimes also
  130. * reset to 0 and used as a counter!
  131. */
  132. uint32_t used_element_count;
  133. /**
  134. * Already transferred elements from client to us.
  135. * Less or equal than @e total.
  136. */
  137. uint32_t client_received_element_count;
  138. /**
  139. * State of this session. In
  140. * #GNUNET_SCALARPRODUCT_STATUS_ACTIVE while operation is
  141. * ongoing, afterwards in #GNUNET_SCALARPRODUCT_STATUS_SUCCESS or
  142. * #GNUNET_SCALARPRODUCT_STATUS_FAILURE.
  143. */
  144. enum GNUNET_SCALARPRODUCT_ResponseStatus status;
  145. /**
  146. * Flag to prevent recursive calls to #destroy_service_session() from
  147. * doing harm.
  148. */
  149. int in_destroy;
  150. };
  151. /**
  152. * GNUnet configuration handle
  153. */
  154. static const struct GNUNET_CONFIGURATION_Handle *cfg;
  155. /**
  156. * Context for DLOG operations on a curve.
  157. */
  158. static struct GNUNET_CRYPTO_EccDlogContext *edc;
  159. /**
  160. * Alice's private key ('a').
  161. */
  162. static struct GNUNET_CRYPTO_EccScalar my_privkey;
  163. /**
  164. * Inverse of Alice's private key ('a_inv').
  165. */
  166. static struct GNUNET_CRYPTO_EccScalar my_privkey_inv;
  167. /**
  168. * Handle to the CADET service.
  169. */
  170. static struct GNUNET_CADET_Handle *my_cadet;
  171. /**
  172. * Iterator called to free elements.
  173. *
  174. * @param cls the `struct AliceServiceSession *` (unused)
  175. * @param key the key (unused)
  176. * @param value value to free
  177. * @return #GNUNET_OK (continue to iterate)
  178. */
  179. static int
  180. free_element_cb (void *cls,
  181. const struct GNUNET_HashCode *key,
  182. void *value)
  183. {
  184. struct GNUNET_SCALARPRODUCT_Element *e = value;
  185. GNUNET_free (e);
  186. return GNUNET_OK;
  187. }
  188. /**
  189. * Destroy session state, we are done with it.
  190. *
  191. * @param s the session to free elements from
  192. */
  193. static void
  194. destroy_service_session (struct AliceServiceSession *s)
  195. {
  196. if (GNUNET_YES == s->in_destroy)
  197. return;
  198. s->in_destroy = GNUNET_YES;
  199. if (NULL != s->client)
  200. {
  201. struct GNUNET_SERVICE_Client *c = s->client;
  202. s->client = NULL;
  203. GNUNET_SERVICE_client_drop (c);
  204. }
  205. if (NULL != s->channel)
  206. {
  207. GNUNET_CADET_channel_destroy (s->channel);
  208. s->channel = NULL;
  209. }
  210. if (NULL != s->intersected_elements)
  211. {
  212. GNUNET_CONTAINER_multihashmap_iterate (s->intersected_elements,
  213. &free_element_cb,
  214. s);
  215. GNUNET_CONTAINER_multihashmap_destroy (s->intersected_elements);
  216. s->intersected_elements = NULL;
  217. }
  218. if (NULL != s->intersection_listen)
  219. {
  220. GNUNET_SETI_listen_cancel (s->intersection_listen);
  221. s->intersection_listen = NULL;
  222. }
  223. if (NULL != s->intersection_op)
  224. {
  225. LOG (GNUNET_ERROR_TYPE_DEBUG,
  226. "Set intersection, op still ongoing!\n");
  227. GNUNET_SETI_operation_cancel (s->intersection_op);
  228. s->intersection_op = NULL;
  229. }
  230. if (NULL != s->intersection_set)
  231. {
  232. GNUNET_SETI_destroy (s->intersection_set);
  233. s->intersection_set = NULL;
  234. }
  235. if (NULL != s->sorted_elements)
  236. {
  237. GNUNET_free (s->sorted_elements);
  238. s->sorted_elements = NULL;
  239. }
  240. GNUNET_free (s);
  241. }
  242. /**
  243. * Notify the client that the session has failed. A message gets sent
  244. * to Alice's client if we encountered any error.
  245. *
  246. * @param session the associated client session to fail or succeed
  247. */
  248. static void
  249. prepare_client_end_notification (struct AliceServiceSession *session)
  250. {
  251. struct ClientResponseMessage *msg;
  252. struct GNUNET_MQ_Envelope *e;
  253. if (NULL == session->client_mq)
  254. return; /* no client left to be notified */
  255. GNUNET_log (
  256. GNUNET_ERROR_TYPE_DEBUG,
  257. "Sending session-end notification with status %d to client for session %s\n",
  258. session->status,
  259. GNUNET_h2s (&session->session_id));
  260. e = GNUNET_MQ_msg (msg,
  261. GNUNET_MESSAGE_TYPE_SCALARPRODUCT_RESULT);
  262. msg->product_length = htonl (0);
  263. msg->status = htonl (session->status);
  264. GNUNET_MQ_send (session->client_mq,
  265. e);
  266. }
  267. /**
  268. * Prepare the final (positive) response we will send to Alice's
  269. * client.
  270. *
  271. * @param s the session associated with our client.
  272. */
  273. static void
  274. transmit_client_response (struct AliceServiceSession *s)
  275. {
  276. struct ClientResponseMessage *msg;
  277. struct GNUNET_MQ_Envelope *e;
  278. unsigned char *product_exported = NULL;
  279. size_t product_length = 0;
  280. int32_t range;
  281. gcry_error_t rc;
  282. gcry_mpi_t value;
  283. if (INT_MAX == s->product)
  284. {
  285. GNUNET_break (0);
  286. prepare_client_end_notification (s);
  287. return;
  288. }
  289. value = gcry_mpi_new (32);
  290. if (0 > s->product)
  291. {
  292. range = -1;
  293. gcry_mpi_set_ui (value,
  294. -s->product);
  295. }
  296. else if (0 < s->product)
  297. {
  298. range = 1;
  299. gcry_mpi_set_ui (value,
  300. s->product);
  301. }
  302. else
  303. {
  304. /* result is exactly zero */
  305. range = 0;
  306. }
  307. if ( (0 != range) &&
  308. (0 != (rc = gcry_mpi_aprint (GCRYMPI_FMT_STD,
  309. &product_exported,
  310. &product_length,
  311. value))))
  312. {
  313. LOG_GCRY (GNUNET_ERROR_TYPE_ERROR,
  314. "gcry_mpi_scan",
  315. rc);
  316. prepare_client_end_notification (s);
  317. return;
  318. }
  319. gcry_mpi_release (value);
  320. e = GNUNET_MQ_msg_extra (msg,
  321. product_length,
  322. GNUNET_MESSAGE_TYPE_SCALARPRODUCT_RESULT);
  323. msg->status = htonl (GNUNET_SCALARPRODUCT_STATUS_SUCCESS);
  324. msg->range = htonl (range);
  325. msg->product_length = htonl (product_length);
  326. if (NULL != product_exported)
  327. {
  328. GNUNET_memcpy (&msg[1],
  329. product_exported,
  330. product_length);
  331. GNUNET_free (product_exported);
  332. }
  333. GNUNET_MQ_send (s->client_mq,
  334. e);
  335. GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
  336. "Sent result to client, session %s has ended!\n",
  337. GNUNET_h2s (&s->session_id));
  338. }
  339. /**
  340. * Function called whenever a channel is destroyed. Should clean up
  341. * any associated state.
  342. *
  343. * It must NOT call #GNUNET_CADET_channel_destroy() on the channel.
  344. *
  345. * @param cls the `struct AliceServiceSession`
  346. * @param channel connection to the other end (henceforth invalid)
  347. */
  348. static void
  349. cb_channel_destruction (void *cls,
  350. const struct GNUNET_CADET_Channel *channel)
  351. {
  352. struct AliceServiceSession *s = cls;
  353. GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
  354. "Peer disconnected, terminating session %s with peer %s\n",
  355. GNUNET_h2s (&s->session_id),
  356. GNUNET_i2s (&s->peer));
  357. s->channel = NULL;
  358. if (GNUNET_SCALARPRODUCT_STATUS_ACTIVE == s->status)
  359. {
  360. /* We didn't get an answer yet, fail with error */
  361. s->status = GNUNET_SCALARPRODUCT_STATUS_FAILURE;
  362. prepare_client_end_notification (s);
  363. }
  364. }
  365. /**
  366. * Handle a response we got from another service we wanted to
  367. * calculate a scalarproduct with.
  368. *
  369. * @param cls the `struct AliceServiceSession *`
  370. * @param msg the actual message
  371. */
  372. static void
  373. handle_bobs_cryptodata_message (void *cls,
  374. const struct EccBobCryptodataMessage *msg)
  375. {
  376. struct AliceServiceSession *s = cls;
  377. uint32_t contained;
  378. contained = ntohl (msg->contained_element_count);
  379. if (2 != contained)
  380. {
  381. GNUNET_break_op (0);
  382. destroy_service_session (s);
  383. return;
  384. }
  385. if (NULL == s->sorted_elements)
  386. {
  387. /* we're not ready yet, how can Bob be? */
  388. GNUNET_break_op (0);
  389. destroy_service_session (s);
  390. return;
  391. }
  392. if (s->total != s->client_received_element_count)
  393. {
  394. /* we're not ready yet, how can Bob be? */
  395. GNUNET_break_op (0);
  396. destroy_service_session (s);
  397. return;
  398. }
  399. GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
  400. "Received %u crypto values from Bob\n",
  401. (unsigned int) contained);
  402. GNUNET_CADET_receive_done (s->channel);
  403. {
  404. struct GNUNET_CRYPTO_EccPoint g_i_b_i_a_inv;
  405. struct GNUNET_CRYPTO_EccPoint g_ai_bi;
  406. GNUNET_assert (
  407. GNUNET_OK ==
  408. GNUNET_CRYPTO_ecc_pmul_mpi (&msg->prod_g_i_b_i,
  409. &my_privkey_inv,
  410. &g_i_b_i_a_inv));
  411. GNUNET_assert (
  412. GNUNET_OK ==
  413. GNUNET_CRYPTO_ecc_add (&g_i_b_i_a_inv,
  414. &msg->prod_h_i_b_i,
  415. &g_ai_bi));
  416. s->product = GNUNET_CRYPTO_ecc_dlog (edc,
  417. &g_ai_bi);
  418. if (INT_MAX == s->product)
  419. {
  420. /* result too big */
  421. GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
  422. "Scalar product result out of range\n");
  423. }
  424. }
  425. transmit_client_response (s);
  426. }
  427. /**
  428. * Iterator to copy over messages from the hash map
  429. * into an array for sorting.
  430. *
  431. * @param cls the `struct AliceServiceSession *`
  432. * @param key the key (unused)
  433. * @param value the `struct GNUNET_SCALARPRODUCT_Element *`
  434. */
  435. static int
  436. copy_element_cb (void *cls,
  437. const struct GNUNET_HashCode *key,
  438. void *value)
  439. {
  440. struct AliceServiceSession *s = cls;
  441. struct GNUNET_SCALARPRODUCT_Element *e = value;
  442. s->sorted_elements[s->used_element_count].value = (int64_t) GNUNET_ntohll (
  443. e->value);
  444. s->sorted_elements[s->used_element_count].key = &e->key;
  445. s->used_element_count++;
  446. return GNUNET_OK;
  447. }
  448. /**
  449. * Compare two `struct MpiValue`s by key for sorting.
  450. *
  451. * @param a pointer to first `struct MpiValue *`
  452. * @param b pointer to first `struct MpiValue *`
  453. * @return -1 for a < b, 0 for a=b, 1 for a > b.
  454. */
  455. static int
  456. element_cmp (const void *a,
  457. const void *b)
  458. {
  459. const struct MpiElement *ma = a;
  460. const struct MpiElement *mb = b;
  461. return GNUNET_CRYPTO_hash_cmp (ma->key,
  462. mb->key);
  463. }
  464. /**
  465. * Maximum number of elements we can put into a single cryptodata
  466. * message
  467. */
  468. #define ELEMENT_CAPACITY \
  469. ((GNUNET_CONSTANTS_MAX_CADET_MESSAGE_SIZE - 1 \
  470. - sizeof(struct EccAliceCryptodataMessage)) \
  471. / sizeof(struct GNUNET_CRYPTO_EccPoint))
  472. /**
  473. * Send the cryptographic data from Alice to Bob.
  474. * Does nothing if we already transferred all elements.
  475. *
  476. * @param s the associated service session
  477. */
  478. static void
  479. send_alices_cryptodata_message (struct AliceServiceSession *s)
  480. {
  481. struct EccAliceCryptodataMessage *msg;
  482. struct GNUNET_MQ_Envelope *e;
  483. struct GNUNET_CRYPTO_EccPoint *payload;
  484. struct GNUNET_CRYPTO_EccScalar r_ia;
  485. struct GNUNET_CRYPTO_EccScalar r_ia_ai;
  486. unsigned int off;
  487. unsigned int todo_count;
  488. s->sorted_elements = GNUNET_new_array (GNUNET_CONTAINER_multihashmap_size (
  489. s->intersected_elements),
  490. struct MpiElement);
  491. s->used_element_count = 0;
  492. GNUNET_CONTAINER_multihashmap_iterate (s->intersected_elements,
  493. &copy_element_cb,
  494. s);
  495. LOG (GNUNET_ERROR_TYPE_DEBUG,
  496. "Finished intersection, %d items remain\n",
  497. s->used_element_count);
  498. qsort (s->sorted_elements,
  499. s->used_element_count,
  500. sizeof(struct MpiElement),
  501. &element_cmp);
  502. off = 0;
  503. while (off < s->used_element_count)
  504. {
  505. todo_count = s->used_element_count - off;
  506. if (todo_count > ELEMENT_CAPACITY)
  507. todo_count = ELEMENT_CAPACITY;
  508. GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
  509. "Sending %u/%u crypto values to Bob\n",
  510. (unsigned int) todo_count,
  511. (unsigned int) s->used_element_count);
  512. e =
  513. GNUNET_MQ_msg_extra (msg,
  514. todo_count * 2
  515. * sizeof(struct GNUNET_CRYPTO_EccPoint),
  516. GNUNET_MESSAGE_TYPE_SCALARPRODUCT_ECC_ALICE_CRYPTODATA);
  517. msg->contained_element_count = htonl (todo_count);
  518. payload = (struct GNUNET_CRYPTO_EccPoint *) &msg[1];
  519. for (unsigned int i = off; i < off + todo_count; i++)
  520. {
  521. struct GNUNET_CRYPTO_EccScalar r_i;
  522. struct GNUNET_CRYPTO_EccPoint g_i;
  523. struct GNUNET_CRYPTO_EccPoint h_i;
  524. /* r_i = random() mod n */
  525. GNUNET_CRYPTO_ecc_random_mod_n (&r_i);
  526. /* g_i = g^{r_i} */
  527. GNUNET_assert (GNUNET_OK ==
  528. GNUNET_CRYPTO_ecc_dexp_mpi (&r_i,
  529. &g_i));
  530. /* r_ia = r_i * a */
  531. crypto_core_ed25519_scalar_mul (r_ia.v,
  532. r_i.v,
  533. my_privkey.v);
  534. /* r_ia_ai = r_ia + a_i */
  535. {
  536. int64_t val = s->sorted_elements[i].value;
  537. struct GNUNET_CRYPTO_EccScalar vali;
  538. GNUNET_assert (INT64_MIN != val);
  539. GNUNET_CRYPTO_ecc_scalar_from_int (val > 0 ? val : -val,
  540. &vali);
  541. if (val > 0)
  542. crypto_core_ed25519_scalar_add (r_ia_ai.v,
  543. r_ia.v,
  544. vali.v);
  545. else
  546. crypto_core_ed25519_scalar_sub (r_ia_ai.v,
  547. r_ia.v,
  548. vali.v);
  549. }
  550. /* h_i = g^{r_ia_ai} */
  551. GNUNET_assert (GNUNET_OK ==
  552. GNUNET_CRYPTO_ecc_dexp_mpi (&r_ia_ai,
  553. &h_i));
  554. memcpy (&payload[(i - off) * 2],
  555. &g_i,
  556. sizeof (g_i));
  557. memcpy (&payload[(i - off) * 2 + 1],
  558. &h_i,
  559. sizeof (h_i));
  560. }
  561. off += todo_count;
  562. GNUNET_MQ_send (s->cadet_mq,
  563. e);
  564. }
  565. }
  566. /**
  567. * Callback for set operation results. Called for each element
  568. * that should be removed from the result set, and then once
  569. * to indicate that the set intersection operation is done.
  570. *
  571. * @param cls closure with the `struct AliceServiceSession`
  572. * @param element a result element, only valid if status is #GNUNET_SETI_STATUS_OK
  573. * @param current_size current set size
  574. * @param status what has happened with the set intersection?
  575. */
  576. static void
  577. cb_intersection_element_removed (void *cls,
  578. const struct GNUNET_SETI_Element *element,
  579. uint64_t current_size,
  580. enum GNUNET_SETI_Status status)
  581. {
  582. struct AliceServiceSession *s = cls;
  583. struct GNUNET_SCALARPRODUCT_Element *se;
  584. switch (status)
  585. {
  586. case GNUNET_SETI_STATUS_DEL_LOCAL:
  587. /* this element has been removed from the set */
  588. se = GNUNET_CONTAINER_multihashmap_get (s->intersected_elements,
  589. element->data);
  590. GNUNET_assert (NULL != se);
  591. LOG (GNUNET_ERROR_TYPE_DEBUG,
  592. "Intersection removed element with key %s and value %lld\n",
  593. GNUNET_h2s (&se->key),
  594. (long long) GNUNET_ntohll (se->value));
  595. GNUNET_assert (
  596. GNUNET_YES ==
  597. GNUNET_CONTAINER_multihashmap_remove (s->intersected_elements,
  598. element->data,
  599. se));
  600. GNUNET_free (se);
  601. return;
  602. case GNUNET_SETI_STATUS_DONE:
  603. s->intersection_op = NULL;
  604. if (NULL != s->intersection_set)
  605. {
  606. GNUNET_SETI_destroy (s->intersection_set);
  607. s->intersection_set = NULL;
  608. }
  609. send_alices_cryptodata_message (s);
  610. return;
  611. case GNUNET_SETI_STATUS_FAILURE:
  612. /* unhandled status code */
  613. LOG (GNUNET_ERROR_TYPE_DEBUG, "Set intersection failed!\n");
  614. if (NULL != s->intersection_listen)
  615. {
  616. GNUNET_SETI_listen_cancel (s->intersection_listen);
  617. s->intersection_listen = NULL;
  618. }
  619. s->intersection_op = NULL;
  620. if (NULL != s->intersection_set)
  621. {
  622. GNUNET_SETI_destroy (s->intersection_set);
  623. s->intersection_set = NULL;
  624. }
  625. s->status = GNUNET_SCALARPRODUCT_STATUS_FAILURE;
  626. prepare_client_end_notification (s);
  627. return;
  628. default:
  629. GNUNET_break (0);
  630. return;
  631. }
  632. }
  633. /**
  634. * Called when another peer wants to do a set operation with the
  635. * local peer. If a listen error occurs, the @a request is NULL.
  636. *
  637. * @param cls closure with the `struct AliceServiceSession *`
  638. * @param other_peer the other peer
  639. * @param context_msg message with application specific information from
  640. * the other peer
  641. * @param request request from the other peer (never NULL), use GNUNET_SETI_accept()
  642. * to accept it, otherwise the request will be refused
  643. * Note that we can't just return value from the listen callback,
  644. * as it is also necessary to specify the set we want to do the
  645. * operation with, whith sometimes can be derived from the context
  646. * message. It's necessary to specify the timeout.
  647. */
  648. static void
  649. cb_intersection_request_alice (void *cls,
  650. const struct GNUNET_PeerIdentity *other_peer,
  651. const struct GNUNET_MessageHeader *context_msg,
  652. struct GNUNET_SETI_Request *request)
  653. {
  654. struct AliceServiceSession *s = cls;
  655. GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
  656. "Received intersection request from %s!\n",
  657. GNUNET_i2s (other_peer));
  658. if (0 != GNUNET_memcmp (other_peer,
  659. &s->peer))
  660. {
  661. GNUNET_break_op (0);
  662. return;
  663. }
  664. s->intersection_op
  665. = GNUNET_SETI_accept (request,
  666. (struct GNUNET_SETI_Option[]){ { 0 } },
  667. &cb_intersection_element_removed,
  668. s);
  669. if (NULL == s->intersection_op)
  670. {
  671. GNUNET_break (0);
  672. s->status = GNUNET_SCALARPRODUCT_STATUS_FAILURE;
  673. prepare_client_end_notification (s);
  674. return;
  675. }
  676. if (GNUNET_OK !=
  677. GNUNET_SETI_commit (s->intersection_op,
  678. s->intersection_set))
  679. {
  680. GNUNET_break (0);
  681. s->status = GNUNET_SCALARPRODUCT_STATUS_FAILURE;
  682. prepare_client_end_notification (s);
  683. return;
  684. }
  685. }
  686. /**
  687. * Our client has finished sending us its multipart message.
  688. *
  689. * @param session the service session context
  690. */
  691. static void
  692. client_request_complete_alice (struct AliceServiceSession *s)
  693. {
  694. struct GNUNET_MQ_MessageHandler cadet_handlers[] = {
  695. GNUNET_MQ_hd_fixed_size (bobs_cryptodata_message,
  696. GNUNET_MESSAGE_TYPE_SCALARPRODUCT_ECC_BOB_CRYPTODATA,
  697. struct EccBobCryptodataMessage,
  698. s),
  699. GNUNET_MQ_handler_end ()
  700. };
  701. struct EccServiceRequestMessage *msg;
  702. struct GNUNET_MQ_Envelope *e;
  703. struct GNUNET_HashCode set_sid;
  704. GNUNET_CRYPTO_hash (&s->session_id,
  705. sizeof(struct GNUNET_HashCode),
  706. &set_sid);
  707. GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
  708. "Creating new channel for session with key %s.\n",
  709. GNUNET_h2s (&s->session_id));
  710. s->channel = GNUNET_CADET_channel_create (my_cadet,
  711. s,
  712. &s->peer,
  713. &s->session_id,
  714. NULL,
  715. &cb_channel_destruction,
  716. cadet_handlers);
  717. if (NULL == s->channel)
  718. {
  719. s->status = GNUNET_SCALARPRODUCT_STATUS_FAILURE;
  720. prepare_client_end_notification (s);
  721. return;
  722. }
  723. s->cadet_mq = GNUNET_CADET_get_mq (s->channel);
  724. s->intersection_listen = GNUNET_SETI_listen (cfg,
  725. &set_sid,
  726. &cb_intersection_request_alice,
  727. s);
  728. if (NULL == s->intersection_listen)
  729. {
  730. s->status = GNUNET_SCALARPRODUCT_STATUS_FAILURE;
  731. GNUNET_CADET_channel_destroy (s->channel);
  732. s->channel = NULL;
  733. prepare_client_end_notification (s);
  734. return;
  735. }
  736. e =
  737. GNUNET_MQ_msg (msg,
  738. GNUNET_MESSAGE_TYPE_SCALARPRODUCT_ECC_SESSION_INITIALIZATION);
  739. GNUNET_MQ_env_set_options (e, GNUNET_MQ_PRIO_CRITICAL_CONTROL);
  740. msg->session_id = s->session_id;
  741. GNUNET_MQ_send (s->cadet_mq, e);
  742. }
  743. /**
  744. * We're receiving additional set data. Check if
  745. * @a msg is well-formed.
  746. *
  747. * @param cls client identification of the client
  748. * @param msg the actual message
  749. * @return #GNUNET_OK if @a msg is well-formed
  750. */
  751. static int
  752. check_alice_client_message_multipart (
  753. void *cls,
  754. const struct ComputationBobCryptodataMultipartMessage *msg)
  755. {
  756. struct AliceServiceSession *s = cls;
  757. uint32_t contained_count;
  758. uint16_t msize;
  759. msize = ntohs (msg->header.size);
  760. contained_count = ntohl (msg->element_count_contained);
  761. if ((msize !=
  762. (sizeof(struct ComputationBobCryptodataMultipartMessage)
  763. + contained_count * sizeof(struct GNUNET_SCALARPRODUCT_Element))) ||
  764. (0 == contained_count) ||
  765. (s->total == s->client_received_element_count) ||
  766. (s->total < s->client_received_element_count + contained_count))
  767. {
  768. GNUNET_break_op (0);
  769. return GNUNET_SYSERR;
  770. }
  771. return GNUNET_OK;
  772. }
  773. /**
  774. * We're receiving additional set data. Add it to our
  775. * set and if we are done, initiate the transaction.
  776. *
  777. * @param cls client identification of the client
  778. * @param msg the actual message
  779. */
  780. static void
  781. handle_alice_client_message_multipart (
  782. void *cls,
  783. const struct ComputationBobCryptodataMultipartMessage *msg)
  784. {
  785. struct AliceServiceSession *s = cls;
  786. uint32_t contained_count;
  787. const struct GNUNET_SCALARPRODUCT_Element *elements;
  788. struct GNUNET_SETI_Element set_elem;
  789. struct GNUNET_SCALARPRODUCT_Element *elem;
  790. contained_count = ntohl (msg->element_count_contained);
  791. s->client_received_element_count += contained_count;
  792. elements = (const struct GNUNET_SCALARPRODUCT_Element *) &msg[1];
  793. for (uint32_t i = 0; i < contained_count; i++)
  794. {
  795. elem = GNUNET_new (struct GNUNET_SCALARPRODUCT_Element);
  796. GNUNET_memcpy (elem,
  797. &elements[i],
  798. sizeof(struct GNUNET_SCALARPRODUCT_Element));
  799. if (GNUNET_SYSERR == GNUNET_CONTAINER_multihashmap_put (
  800. s->intersected_elements,
  801. &elem->key,
  802. elem,
  803. GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY))
  804. {
  805. GNUNET_break (0);
  806. GNUNET_free (elem);
  807. continue;
  808. }
  809. set_elem.data = &elem->key;
  810. set_elem.size = sizeof(elem->key);
  811. set_elem.element_type = 0;
  812. GNUNET_SETI_add_element (s->intersection_set, &set_elem, NULL, NULL);
  813. s->used_element_count++;
  814. }
  815. GNUNET_SERVICE_client_continue (s->client);
  816. if (s->total != s->client_received_element_count)
  817. {
  818. /* more to come */
  819. GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
  820. "Received client multipart data, waiting for more!\n");
  821. return;
  822. }
  823. GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Launching computation\n");
  824. client_request_complete_alice (s);
  825. }
  826. /**
  827. * Handler for Alice's client request message.
  828. * Check that @a msg is well-formed.
  829. *
  830. * @param cls identification of the client
  831. * @param msg the actual message
  832. * @return #GNUNET_OK if @a msg is well-formed
  833. */
  834. static int
  835. check_alice_client_message (void *cls,
  836. const struct AliceComputationMessage *msg)
  837. {
  838. struct AliceServiceSession *s = cls;
  839. uint16_t msize;
  840. uint32_t total_count;
  841. uint32_t contained_count;
  842. if (NULL != s->intersected_elements)
  843. {
  844. /* only one concurrent session per client connection allowed,
  845. simplifies logic a lot... */
  846. GNUNET_break (0);
  847. return GNUNET_SYSERR;
  848. }
  849. msize = ntohs (msg->header.size);
  850. total_count = ntohl (msg->element_count_total);
  851. contained_count = ntohl (msg->element_count_contained);
  852. if ((0 == total_count) || (0 == contained_count) ||
  853. (msize !=
  854. (sizeof(struct AliceComputationMessage)
  855. + contained_count * sizeof(struct GNUNET_SCALARPRODUCT_Element))))
  856. {
  857. GNUNET_break_op (0);
  858. return GNUNET_SYSERR;
  859. }
  860. return GNUNET_OK;
  861. }
  862. /**
  863. * Handler for Alice's client request message.
  864. * We are doing request-initiation to compute a scalar product with a peer.
  865. *
  866. * @param cls identification of the client
  867. * @param msg the actual message
  868. */
  869. static void
  870. handle_alice_client_message (void *cls,
  871. const struct AliceComputationMessage *msg)
  872. {
  873. struct AliceServiceSession *s = cls;
  874. uint32_t contained_count;
  875. uint32_t total_count;
  876. const struct GNUNET_SCALARPRODUCT_Element *elements;
  877. struct GNUNET_SETI_Element set_elem;
  878. struct GNUNET_SCALARPRODUCT_Element *elem;
  879. total_count = ntohl (msg->element_count_total);
  880. contained_count = ntohl (msg->element_count_contained);
  881. s->peer = msg->peer;
  882. s->status = GNUNET_SCALARPRODUCT_STATUS_ACTIVE;
  883. s->total = total_count;
  884. s->client_received_element_count = contained_count;
  885. s->session_id = msg->session_key;
  886. elements = (const struct GNUNET_SCALARPRODUCT_Element *) &msg[1];
  887. s->intersected_elements =
  888. GNUNET_CONTAINER_multihashmap_create (s->total,
  889. GNUNET_YES);
  890. s->intersection_set = GNUNET_SETI_create (cfg);
  891. for (uint32_t i = 0; i < contained_count; i++)
  892. {
  893. if (0 == GNUNET_ntohll (elements[i].value))
  894. continue;
  895. elem = GNUNET_new (struct GNUNET_SCALARPRODUCT_Element);
  896. *elem = elements[i];
  897. if (GNUNET_SYSERR ==
  898. GNUNET_CONTAINER_multihashmap_put (
  899. s->intersected_elements,
  900. &elem->key,
  901. elem,
  902. GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY))
  903. {
  904. /* element with same key encountered twice! */
  905. GNUNET_break (0);
  906. GNUNET_free (elem);
  907. continue;
  908. }
  909. set_elem.data = &elem->key;
  910. set_elem.size = sizeof(elem->key);
  911. set_elem.element_type = 0;
  912. GNUNET_SETI_add_element (s->intersection_set,
  913. &set_elem,
  914. NULL,
  915. NULL);
  916. s->used_element_count++;
  917. }
  918. GNUNET_SERVICE_client_continue (s->client);
  919. if (s->total != s->client_received_element_count)
  920. {
  921. /* wait for multipart msg */
  922. GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
  923. "Received partial client request, waiting for more!\n");
  924. return;
  925. }
  926. GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
  927. "Launching computation\n");
  928. client_request_complete_alice (s);
  929. }
  930. /**
  931. * Task run during shutdown.
  932. *
  933. * @param cls unused
  934. * @param tc unused
  935. */
  936. static void
  937. shutdown_task (void *cls)
  938. {
  939. GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
  940. "Shutting down, initiating cleanup.\n");
  941. // FIXME: we have to cut our connections to CADET first!
  942. if (NULL != my_cadet)
  943. {
  944. GNUNET_CADET_disconnect (my_cadet);
  945. my_cadet = NULL;
  946. }
  947. if (NULL != edc)
  948. {
  949. GNUNET_CRYPTO_ecc_dlog_release (edc);
  950. edc = NULL;
  951. }
  952. }
  953. /**
  954. * A client connected.
  955. *
  956. * Setup the associated data structure.
  957. *
  958. * @param cls closure, NULL
  959. * @param client identification of the client
  960. * @param mq message queue to communicate with @a client
  961. * @return our `struct AliceServiceSession`
  962. */
  963. static void *
  964. client_connect_cb (void *cls,
  965. struct GNUNET_SERVICE_Client *client,
  966. struct GNUNET_MQ_Handle *mq)
  967. {
  968. struct AliceServiceSession *s;
  969. s = GNUNET_new (struct AliceServiceSession);
  970. s->client = client;
  971. s->client_mq = mq;
  972. return s;
  973. }
  974. /**
  975. * A client disconnected.
  976. *
  977. * Remove the associated session(s), release data structures
  978. * and cancel pending outgoing transmissions to the client.
  979. *
  980. * @param cls closure, NULL
  981. * @param client identification of the client
  982. * @param app_cls our `struct AliceServiceSession`
  983. */
  984. static void
  985. client_disconnect_cb (void *cls,
  986. struct GNUNET_SERVICE_Client *client,
  987. void *app_cls)
  988. {
  989. struct AliceServiceSession *s = app_cls;
  990. GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
  991. "Client %p disconnected from us.\n",
  992. client);
  993. s->client = NULL;
  994. s->client_mq = NULL;
  995. destroy_service_session (s);
  996. }
  997. /**
  998. * Initialization of the program and message handlers
  999. *
  1000. * @param cls closure
  1001. * @param c configuration to use
  1002. * @param service the initialized service
  1003. */
  1004. static void
  1005. run (void *cls,
  1006. const struct GNUNET_CONFIGURATION_Handle *c,
  1007. struct GNUNET_SERVICE_Handle *service)
  1008. {
  1009. cfg = c;
  1010. edc = GNUNET_CRYPTO_ecc_dlog_prepare (MAX_RESULT,
  1011. MAX_RAM);
  1012. /* Select a random 'a' value for Alice */
  1013. GNUNET_CRYPTO_ecc_rnd_mpi (&my_privkey,
  1014. &my_privkey_inv);
  1015. my_cadet = GNUNET_CADET_connect (cfg);
  1016. if (NULL == my_cadet)
  1017. {
  1018. GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
  1019. _ ("Connect to CADET failed\n"));
  1020. GNUNET_SCHEDULER_shutdown ();
  1021. return;
  1022. }
  1023. GNUNET_SCHEDULER_add_shutdown (&shutdown_task,
  1024. NULL);
  1025. }
  1026. /**
  1027. * Define "main" method using service macro.
  1028. */
  1029. GNUNET_SERVICE_MAIN (
  1030. "scalarproduct-alice",
  1031. GNUNET_SERVICE_OPTION_NONE,
  1032. &run,
  1033. &client_connect_cb,
  1034. &client_disconnect_cb,
  1035. NULL,
  1036. GNUNET_MQ_hd_var_size (alice_client_message,
  1037. GNUNET_MESSAGE_TYPE_SCALARPRODUCT_CLIENT_TO_ALICE,
  1038. struct AliceComputationMessage,
  1039. NULL),
  1040. GNUNET_MQ_hd_var_size (
  1041. alice_client_message_multipart,
  1042. GNUNET_MESSAGE_TYPE_SCALARPRODUCT_CLIENT_MULTIPART_ALICE,
  1043. struct ComputationBobCryptodataMultipartMessage,
  1044. NULL),
  1045. GNUNET_MQ_handler_end ());
  1046. /* end of gnunet-service-scalarproduct-ecc_alice.c */