gnunet-scrypt.c 9.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328
  1. /*
  2. This file is part of GNUnet.
  3. Copyright (C) 2014 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 util/gnunet-scrypt.c
  18. * @brief tool to manipulate SCRYPT proofs of work.
  19. * @author Bart Polot
  20. */
  21. #include "platform.h"
  22. #include "gnunet_util_lib.h"
  23. #include <gcrypt.h>
  24. /**
  25. * Amount of work required (W-bit collisions) for NSE proofs, in collision-bits.
  26. */
  27. static unsigned long long nse_work_required;
  28. /**
  29. * Interval between proof find runs.
  30. */
  31. static struct GNUNET_TIME_Relative proof_find_delay;
  32. static struct GNUNET_CRYPTO_EddsaPublicKey pub;
  33. static uint64_t proof;
  34. static struct GNUNET_SCHEDULER_Task *proof_task;
  35. static const struct GNUNET_CONFIGURATION_Handle *cfg;
  36. static char *pkfn;
  37. static char *pwfn;
  38. /**
  39. * Write our current proof to disk.
  40. *
  41. * @param cls closure
  42. */
  43. static void
  44. shutdown_task (void *cls)
  45. {
  46. (void) cls;
  47. if (sizeof(proof) != GNUNET_DISK_fn_write (pwfn,
  48. &proof,
  49. sizeof(proof),
  50. GNUNET_DISK_PERM_USER_READ
  51. | GNUNET_DISK_PERM_USER_WRITE))
  52. GNUNET_log_strerror_file (GNUNET_ERROR_TYPE_WARNING, "write", pwfn);
  53. }
  54. /**
  55. * Count the leading zeroes in hash.
  56. *
  57. * @param hash to count leading zeros in
  58. * @return the number of leading zero bits.
  59. */
  60. static unsigned int
  61. count_leading_zeroes (const struct GNUNET_HashCode *hash)
  62. {
  63. unsigned int hash_count;
  64. hash_count = 0;
  65. while (0 == GNUNET_CRYPTO_hash_get_bit (hash, hash_count))
  66. hash_count++;
  67. return hash_count;
  68. }
  69. /**
  70. * Find our proof of work.
  71. *
  72. * @param cls closure (unused)
  73. * @param tc task context
  74. */
  75. static void
  76. find_proof (void *cls)
  77. {
  78. #define ROUND_SIZE 10
  79. uint64_t counter;
  80. char buf[sizeof(struct GNUNET_CRYPTO_EddsaPublicKey)
  81. + sizeof(uint64_t)] GNUNET_ALIGN;
  82. struct GNUNET_HashCode result;
  83. unsigned int i;
  84. struct GNUNET_TIME_Absolute timestamp;
  85. struct GNUNET_TIME_Relative elapsed;
  86. (void) cls;
  87. GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
  88. "Got Proof of Work %llu\n",
  89. (unsigned long long) proof);
  90. proof_task = NULL;
  91. GNUNET_memcpy (&buf[sizeof(uint64_t)],
  92. &pub,
  93. sizeof(struct GNUNET_CRYPTO_EddsaPublicKey));
  94. i = 0;
  95. counter = proof;
  96. timestamp = GNUNET_TIME_absolute_get ();
  97. while ((counter != UINT64_MAX) && (i < ROUND_SIZE))
  98. {
  99. GNUNET_memcpy (buf, &counter, sizeof(uint64_t));
  100. GNUNET_CRYPTO_pow_hash ("gnunet-nse-proof-of-work",
  101. buf,
  102. sizeof(buf),
  103. &result);
  104. if (nse_work_required <= count_leading_zeroes (&result))
  105. {
  106. proof = counter;
  107. fprintf (stdout,
  108. "Proof of work found: %llu!\n",
  109. (unsigned long long) proof);
  110. GNUNET_SCHEDULER_shutdown ();
  111. return;
  112. }
  113. counter++;
  114. i++;
  115. }
  116. elapsed = GNUNET_TIME_absolute_get_duration (timestamp);
  117. elapsed = GNUNET_TIME_relative_divide (elapsed, ROUND_SIZE);
  118. GNUNET_log (GNUNET_ERROR_TYPE_INFO,
  119. "Current: %llu [%s/proof]\n",
  120. (unsigned long long) counter,
  121. GNUNET_STRINGS_relative_time_to_string (elapsed, 0));
  122. if (proof / (100 * ROUND_SIZE) < counter / (100 * ROUND_SIZE))
  123. {
  124. GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
  125. "Testing proofs currently at %llu\n",
  126. (unsigned long long) counter);
  127. /* remember progress every 100 rounds */
  128. proof = counter;
  129. shutdown_task (NULL);
  130. }
  131. else
  132. {
  133. proof = counter;
  134. }
  135. proof_task =
  136. GNUNET_SCHEDULER_add_delayed_with_priority (proof_find_delay,
  137. GNUNET_SCHEDULER_PRIORITY_IDLE,
  138. &find_proof,
  139. NULL);
  140. }
  141. /**
  142. * Main function that will be run by the scheduler.
  143. *
  144. * @param cls closure
  145. * @param args remaining command-line arguments
  146. * @param cfgfile name of the configuration file used (for saving, can be NULL!)
  147. * @param cfg configuration
  148. */
  149. static void
  150. run (void *cls,
  151. char *const *args,
  152. const char *cfgfile,
  153. const struct GNUNET_CONFIGURATION_Handle *config)
  154. {
  155. struct GNUNET_CRYPTO_EddsaPrivateKey *pk;
  156. char *pids;
  157. (void) cls;
  158. (void) args;
  159. (void) cfgfile;
  160. cfg = config;
  161. /* load proof of work */
  162. if (NULL == pwfn)
  163. {
  164. if (GNUNET_OK != GNUNET_CONFIGURATION_get_value_filename (cfg,
  165. "NSE",
  166. "PROOFFILE",
  167. &pwfn))
  168. {
  169. GNUNET_log_config_missing (GNUNET_ERROR_TYPE_ERROR, "NSE", "PROOFFILE");
  170. GNUNET_SCHEDULER_shutdown ();
  171. return;
  172. }
  173. }
  174. GNUNET_log (GNUNET_ERROR_TYPE_INFO, "Proof of Work file: %s\n", pwfn);
  175. if ((GNUNET_YES != GNUNET_DISK_file_test (pwfn)) ||
  176. (sizeof(proof) != GNUNET_DISK_fn_read (pwfn, &proof, sizeof(proof))))
  177. proof = 0;
  178. /* load private key */
  179. if (NULL == pkfn)
  180. {
  181. if (GNUNET_OK != GNUNET_CONFIGURATION_get_value_filename (cfg,
  182. "PEER",
  183. "PRIVATE_KEY",
  184. &pkfn))
  185. {
  186. GNUNET_log_config_missing (GNUNET_ERROR_TYPE_ERROR,
  187. "PEER",
  188. "PRIVATE_KEY");
  189. return;
  190. }
  191. }
  192. GNUNET_log (GNUNET_ERROR_TYPE_INFO, "Private Key file: %s\n", pkfn);
  193. if (NULL == (pk = GNUNET_CRYPTO_eddsa_key_create_from_file (pkfn)))
  194. {
  195. fprintf (stderr, _ ("Loading hostkey from `%s' failed.\n"), pkfn);
  196. GNUNET_free (pkfn);
  197. return;
  198. }
  199. GNUNET_free (pkfn);
  200. GNUNET_CRYPTO_eddsa_key_get_public (pk, &pub);
  201. GNUNET_free (pk);
  202. pids = GNUNET_CRYPTO_eddsa_public_key_to_string (&pub);
  203. GNUNET_log (GNUNET_ERROR_TYPE_INFO, "Peer ID: %s\n", pids);
  204. GNUNET_free (pids);
  205. /* get target bit amount */
  206. if (0 == nse_work_required)
  207. {
  208. if (GNUNET_OK != GNUNET_CONFIGURATION_get_value_number (cfg,
  209. "NSE",
  210. "WORKBITS",
  211. &nse_work_required))
  212. {
  213. GNUNET_log_config_missing (GNUNET_ERROR_TYPE_ERROR, "NSE", "WORKBITS");
  214. GNUNET_SCHEDULER_shutdown ();
  215. return;
  216. }
  217. if (nse_work_required >= sizeof(struct GNUNET_HashCode) * 8)
  218. {
  219. GNUNET_log_config_invalid (GNUNET_ERROR_TYPE_ERROR,
  220. "NSE",
  221. "WORKBITS",
  222. _ ("Value is too large.\n"));
  223. GNUNET_SCHEDULER_shutdown ();
  224. return;
  225. }
  226. else if (0 == nse_work_required)
  227. {
  228. GNUNET_SCHEDULER_shutdown ();
  229. return;
  230. }
  231. }
  232. GNUNET_log (GNUNET_ERROR_TYPE_INFO, "Bits: %llu\n", nse_work_required);
  233. GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
  234. "Delay between tries: %s\n",
  235. GNUNET_STRINGS_relative_time_to_string (proof_find_delay, 1));
  236. proof_task =
  237. GNUNET_SCHEDULER_add_with_priority (GNUNET_SCHEDULER_PRIORITY_IDLE,
  238. &find_proof,
  239. NULL);
  240. GNUNET_SCHEDULER_add_shutdown (&shutdown_task, NULL);
  241. }
  242. /**
  243. * Program to manipulate ECC key files.
  244. *
  245. * @param argc number of arguments from the command line
  246. * @param argv command line arguments
  247. * @return 0 ok, 1 on error
  248. */
  249. int
  250. main (int argc, char *const *argv)
  251. {
  252. struct GNUNET_GETOPT_CommandLineOption options[] =
  253. { GNUNET_GETOPT_option_ulong (
  254. 'b',
  255. "bits",
  256. "BITS",
  257. gettext_noop ("number of bits to require for the proof of work"),
  258. &nse_work_required),
  259. GNUNET_GETOPT_option_filename (
  260. 'k',
  261. "keyfile",
  262. "FILE",
  263. gettext_noop ("file with private key, otherwise default is used"),
  264. &pkfn),
  265. GNUNET_GETOPT_option_filename (
  266. 'o',
  267. "outfile",
  268. "FILE",
  269. gettext_noop ("file with proof of work, otherwise default is used"),
  270. &pwfn),
  271. GNUNET_GETOPT_option_relative_time ('t',
  272. "timeout",
  273. "TIME",
  274. gettext_noop (
  275. "time to wait between calculations"),
  276. &proof_find_delay),
  277. GNUNET_GETOPT_OPTION_END };
  278. int ret;
  279. if (GNUNET_OK != GNUNET_STRINGS_get_utf8_args (argc, argv, &argc, &argv))
  280. return 2;
  281. ret =
  282. (GNUNET_OK ==
  283. GNUNET_PROGRAM_run (argc,
  284. argv,
  285. "gnunet-scrypt [OPTIONS] prooffile",
  286. gettext_noop ("Manipulate GNUnet proof of work files"),
  287. options,
  288. &run,
  289. NULL))
  290. ? 0
  291. : 1;
  292. GNUNET_free ((void *) argv);
  293. GNUNET_free_non_null (pwfn);
  294. return ret;
  295. }
  296. /* end of gnunet-scrypt.c */