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