"Fossies" - the Fresh Open Source Software Archive 
Member "tor-0.4.8.9/src/test/bench.c" (9 Nov 2023, 23184 Bytes) of package /linux/misc/tor-0.4.8.9.tar.gz:
As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) C and C++ source code syntax highlighting (style:
standard) with prefixed line numbers and
code folding option.
Alternatively you can here
view or
download the uninterpreted source code file.
See also the last
Fossies "Diffs" side-by-side code changes report for "bench.c":
0.4.7.14_vs_0.4.8.4.
1 /* Copyright (c) 2001-2004, Roger Dingledine.
2 * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
3 * Copyright (c) 2007-2021, The Tor Project, Inc. */
4 /* See LICENSE for licensing information */
5
6 /**
7 * \file bench.c
8 * \brief Benchmarks for lower level Tor modules.
9 **/
10
11 #include "orconfig.h"
12
13 #include "core/or/or.h"
14 #include "core/crypto/onion_tap.h"
15 #include "core/crypto/relay_crypto.h"
16
17 #include "lib/intmath/weakrng.h"
18
19 #ifdef ENABLE_OPENSSL
20 #include <openssl/opensslv.h>
21 #include <openssl/evp.h>
22 #include <openssl/ec.h>
23 #include <openssl/ecdh.h>
24 #include <openssl/obj_mac.h>
25 #endif /* defined(ENABLE_OPENSSL) */
26
27 #include "core/or/circuitlist.h"
28 #include "app/config/config.h"
29 #include "app/main/subsysmgr.h"
30 #include "lib/crypt_ops/crypto_curve25519.h"
31 #include "lib/crypt_ops/crypto_dh.h"
32 #include "core/crypto/onion_ntor.h"
33 #include "lib/crypt_ops/crypto_ed25519.h"
34 #include "lib/crypt_ops/crypto_rand.h"
35 #include "feature/dircommon/consdiff.h"
36 #include "lib/compress/compress.h"
37
38 #include "core/or/cell_st.h"
39 #include "core/or/or_circuit_st.h"
40
41 #include "lib/crypt_ops/digestset.h"
42 #include "lib/crypt_ops/crypto_init.h"
43
44 #include "feature/dirparse/microdesc_parse.h"
45 #include "feature/nodelist/microdesc.h"
46
47 #if defined(HAVE_CLOCK_GETTIME) && defined(CLOCK_PROCESS_CPUTIME_ID)
48 static uint64_t nanostart;
49 static inline uint64_t
50 timespec_to_nsec(const struct timespec *ts)
51 {
52 return ((uint64_t)ts->tv_sec)*1000000000 + ts->tv_nsec;
53 }
54
55 static void
56 reset_perftime(void)
57 {
58 struct timespec ts;
59 int r;
60 r = clock_gettime(CLOCK_PROCESS_CPUTIME_ID, &ts);
61 tor_assert(r == 0);
62 nanostart = timespec_to_nsec(&ts);
63 }
64
65 static uint64_t
66 perftime(void)
67 {
68 struct timespec ts;
69 int r;
70 r = clock_gettime(CLOCK_PROCESS_CPUTIME_ID, &ts);
71 tor_assert(r == 0);
72 return timespec_to_nsec(&ts) - nanostart;
73 }
74
75 #else /* !(defined(HAVE_CLOCK_GETTIME) && defined(CLOCK_PROCESS_CPUTIME_ID)) */
76 static struct timeval tv_start = { 0, 0 };
77 static void
78 reset_perftime(void)
79 {
80 tor_gettimeofday(&tv_start);
81 }
82 static uint64_t
83 perftime(void)
84 {
85 struct timeval now, out;
86 tor_gettimeofday(&now);
87 timersub(&now, &tv_start, &out);
88 return ((uint64_t)out.tv_sec)*1000000000 + out.tv_usec*1000;
89 }
90 #endif /* defined(HAVE_CLOCK_GETTIME) && defined(CLOCK_PROCESS_CPUTIME_ID) */
91
92 #define NANOCOUNT(start,end,iters) \
93 ( ((double)((end)-(start))) / (iters) )
94
95 #define MICROCOUNT(start,end,iters) \
96 ( NANOCOUNT((start), (end), (iters)) / 1000.0 )
97
98 /** Run AES performance benchmarks. */
99 static void
100 bench_aes(void)
101 {
102 int len, i;
103 char *b1, *b2;
104 crypto_cipher_t *c;
105 uint64_t start, end;
106 const int bytes_per_iter = (1<<24);
107 reset_perftime();
108 char key[CIPHER_KEY_LEN];
109 crypto_rand(key, sizeof(key));
110 c = crypto_cipher_new(key);
111
112 for (len = 1; len <= 8192; len *= 2) {
113 int iters = bytes_per_iter / len;
114 b1 = tor_malloc_zero(len);
115 b2 = tor_malloc_zero(len);
116 start = perftime();
117 for (i = 0; i < iters; ++i) {
118 crypto_cipher_encrypt(c, b1, b2, len);
119 }
120 end = perftime();
121 tor_free(b1);
122 tor_free(b2);
123 printf("%d bytes: %.2f nsec per byte\n", len,
124 NANOCOUNT(start, end, iters*len));
125 }
126 crypto_cipher_free(c);
127 }
128
129 static void
130 bench_onion_TAP(void)
131 {
132 const int iters = 1<<9;
133 int i;
134 crypto_pk_t *key, *key2;
135 uint64_t start, end;
136 char os[TAP_ONIONSKIN_CHALLENGE_LEN];
137 char or[TAP_ONIONSKIN_REPLY_LEN];
138 crypto_dh_t *dh_out = NULL;
139
140 key = crypto_pk_new();
141 key2 = crypto_pk_new();
142 if (crypto_pk_generate_key_with_bits(key, 1024) < 0)
143 goto done;
144 if (crypto_pk_generate_key_with_bits(key2, 1024) < 0)
145 goto done;
146
147 reset_perftime();
148 start = perftime();
149 for (i = 0; i < iters; ++i) {
150 onion_skin_TAP_create(key, &dh_out, os);
151 crypto_dh_free(dh_out);
152 }
153 end = perftime();
154 printf("Client-side, part 1: %f usec.\n", NANOCOUNT(start, end, iters)/1e3);
155
156 onion_skin_TAP_create(key, &dh_out, os);
157 start = perftime();
158 for (i = 0; i < iters; ++i) {
159 char key_out[CPATH_KEY_MATERIAL_LEN];
160 onion_skin_TAP_server_handshake(os, key, NULL, or,
161 key_out, sizeof(key_out));
162 }
163 end = perftime();
164 printf("Server-side, key guessed right: %f usec\n",
165 NANOCOUNT(start, end, iters)/1e3);
166
167 start = perftime();
168 for (i = 0; i < iters; ++i) {
169 char key_out[CPATH_KEY_MATERIAL_LEN];
170 onion_skin_TAP_server_handshake(os, key2, key, or,
171 key_out, sizeof(key_out));
172 }
173 end = perftime();
174 printf("Server-side, key guessed wrong: %f usec.\n",
175 NANOCOUNT(start, end, iters)/1e3);
176
177 start = perftime();
178 for (i = 0; i < iters; ++i) {
179 crypto_dh_t *dh;
180 char key_out[CPATH_KEY_MATERIAL_LEN];
181 int s;
182 dh = crypto_dh_dup(dh_out);
183 s = onion_skin_TAP_client_handshake(dh, or, key_out, sizeof(key_out),
184 NULL);
185 crypto_dh_free(dh);
186 tor_assert(s == 0);
187 }
188 end = perftime();
189 printf("Client-side, part 2: %f usec.\n",
190 NANOCOUNT(start, end, iters)/1e3);
191
192 done:
193 crypto_dh_free(dh_out);
194 crypto_pk_free(key);
195 crypto_pk_free(key2);
196 }
197
198 static void
199 bench_onion_ntor_impl(void)
200 {
201 const int iters = 1<<10;
202 int i;
203 curve25519_keypair_t keypair1, keypair2;
204 uint64_t start, end;
205 uint8_t os[NTOR_ONIONSKIN_LEN];
206 uint8_t or[NTOR_REPLY_LEN];
207 ntor_handshake_state_t *state = NULL;
208 uint8_t nodeid[DIGEST_LEN];
209 di_digest256_map_t *keymap = NULL;
210
211 curve25519_secret_key_generate(&keypair1.seckey, 0);
212 curve25519_public_key_generate(&keypair1.pubkey, &keypair1.seckey);
213 curve25519_secret_key_generate(&keypair2.seckey, 0);
214 curve25519_public_key_generate(&keypair2.pubkey, &keypair2.seckey);
215 dimap_add_entry(&keymap, keypair1.pubkey.public_key, &keypair1);
216 dimap_add_entry(&keymap, keypair2.pubkey.public_key, &keypair2);
217 crypto_rand((char *)nodeid, sizeof(nodeid));
218
219 reset_perftime();
220 start = perftime();
221 for (i = 0; i < iters; ++i) {
222 onion_skin_ntor_create(nodeid, &keypair1.pubkey, &state, os);
223 ntor_handshake_state_free(state);
224 state = NULL;
225 }
226 end = perftime();
227 printf("Client-side, part 1: %f usec.\n", NANOCOUNT(start, end, iters)/1e3);
228
229 state = NULL;
230 onion_skin_ntor_create(nodeid, &keypair1.pubkey, &state, os);
231 start = perftime();
232 for (i = 0; i < iters; ++i) {
233 uint8_t key_out[CPATH_KEY_MATERIAL_LEN];
234 onion_skin_ntor_server_handshake(os, keymap, NULL, nodeid, or,
235 key_out, sizeof(key_out));
236 }
237 end = perftime();
238 printf("Server-side: %f usec\n",
239 NANOCOUNT(start, end, iters)/1e3);
240
241 start = perftime();
242 for (i = 0; i < iters; ++i) {
243 uint8_t key_out[CPATH_KEY_MATERIAL_LEN];
244 int s;
245 s = onion_skin_ntor_client_handshake(state, or, key_out, sizeof(key_out),
246 NULL);
247 tor_assert(s == 0);
248 }
249 end = perftime();
250 printf("Client-side, part 2: %f usec.\n",
251 NANOCOUNT(start, end, iters)/1e3);
252
253 ntor_handshake_state_free(state);
254 dimap_free(keymap, NULL);
255 }
256
257 static void
258 bench_onion_ntor(void)
259 {
260 int ed;
261
262 for (ed = 0; ed <= 1; ++ed) {
263 printf("Ed25519-based basepoint multiply = %s.\n",
264 (ed == 0) ? "disabled" : "enabled");
265 curve25519_set_impl_params(ed);
266 bench_onion_ntor_impl();
267 }
268 }
269
270 static void
271 bench_ed25519_impl(void)
272 {
273 uint64_t start, end;
274 const int iters = 1<<12;
275 int i;
276 const uint8_t msg[] = "but leaving, could not tell what they had heard";
277 ed25519_signature_t sig;
278 ed25519_keypair_t kp;
279 curve25519_keypair_t curve_kp;
280 ed25519_public_key_t pubkey_tmp;
281
282 ed25519_secret_key_generate(&kp.seckey, 0);
283 start = perftime();
284 for (i = 0; i < iters; ++i) {
285 ed25519_public_key_generate(&kp.pubkey, &kp.seckey);
286 }
287 end = perftime();
288 printf("Generate public key: %.2f usec\n",
289 MICROCOUNT(start, end, iters));
290
291 start = perftime();
292 for (i = 0; i < iters; ++i) {
293 ed25519_sign(&sig, msg, sizeof(msg), &kp);
294 }
295 end = perftime();
296 printf("Sign a short message: %.2f usec\n",
297 MICROCOUNT(start, end, iters));
298
299 start = perftime();
300 for (i = 0; i < iters; ++i) {
301 ed25519_checksig(&sig, msg, sizeof(msg), &kp.pubkey);
302 }
303 end = perftime();
304 printf("Verify signature: %.2f usec\n",
305 MICROCOUNT(start, end, iters));
306
307 curve25519_keypair_generate(&curve_kp, 0);
308 start = perftime();
309 for (i = 0; i < iters; ++i) {
310 ed25519_public_key_from_curve25519_public_key(&pubkey_tmp,
311 &curve_kp.pubkey, 1);
312 }
313 end = perftime();
314 printf("Convert public point from curve25519: %.2f usec\n",
315 MICROCOUNT(start, end, iters));
316
317 curve25519_keypair_generate(&curve_kp, 0);
318 start = perftime();
319 for (i = 0; i < iters; ++i) {
320 ed25519_public_blind(&pubkey_tmp, &kp.pubkey, msg);
321 }
322 end = perftime();
323 printf("Blind a public key: %.2f usec\n",
324 MICROCOUNT(start, end, iters));
325 }
326
327 static void
328 bench_ed25519(void)
329 {
330 int donna;
331
332 for (donna = 0; donna <= 1; ++donna) {
333 printf("Ed25519-donna = %s.\n",
334 (donna == 0) ? "disabled" : "enabled");
335 ed25519_set_impl_params(donna);
336 bench_ed25519_impl();
337 }
338 }
339
340 static void
341 bench_rand_len(int len)
342 {
343 const int N = 100000;
344 int i;
345 char *buf = tor_malloc(len);
346 uint64_t start,end;
347
348 start = perftime();
349 for (i = 0; i < N; ++i) {
350 crypto_rand(buf, len);
351 }
352 end = perftime();
353 printf("crypto_rand(%d): %f nsec.\n", len, NANOCOUNT(start,end,N));
354
355 crypto_fast_rng_t *fr = crypto_fast_rng_new();
356 start = perftime();
357 for (i = 0; i < N; ++i) {
358 crypto_fast_rng_getbytes(fr,(uint8_t*)buf,len);
359 }
360 end = perftime();
361 printf("crypto_fast_rng_getbytes(%d): %f nsec.\n", len,
362 NANOCOUNT(start,end,N));
363 crypto_fast_rng_free(fr);
364
365 if (len <= 32) {
366 start = perftime();
367 for (i = 0; i < N; ++i) {
368 crypto_strongest_rand((uint8_t*)buf, len);
369 }
370 end = perftime();
371 printf("crypto_strongest_rand(%d): %f nsec.\n", len,
372 NANOCOUNT(start,end,N));
373 }
374
375 if (len == 4) {
376 tor_weak_rng_t weak;
377 tor_init_weak_random(&weak, 1337);
378
379 start = perftime();
380 uint32_t t=0;
381 for (i = 0; i < N; ++i) {
382 t += tor_weak_random(&weak);
383 (void) t;
384 }
385 end = perftime();
386 printf("weak_rand(4): %f nsec.\n", NANOCOUNT(start,end,N));
387 }
388
389 tor_free(buf);
390 }
391
392 static void
393 bench_rand(void)
394 {
395 bench_rand_len(4);
396 bench_rand_len(16);
397 bench_rand_len(128);
398 }
399
400 static void
401 bench_cell_aes(void)
402 {
403 uint64_t start, end;
404 const int len = 509;
405 const int iters = (1<<16);
406 const int max_misalign = 15;
407 char *b = tor_malloc(len+max_misalign);
408 crypto_cipher_t *c;
409 int i, misalign;
410 char key[CIPHER_KEY_LEN];
411 crypto_rand(key, sizeof(key));
412 c = crypto_cipher_new(key);
413
414 reset_perftime();
415 for (misalign = 0; misalign <= max_misalign; ++misalign) {
416 start = perftime();
417 for (i = 0; i < iters; ++i) {
418 crypto_cipher_crypt_inplace(c, b+misalign, len);
419 }
420 end = perftime();
421 printf("%d bytes, misaligned by %d: %.2f nsec per byte\n", len, misalign,
422 NANOCOUNT(start, end, iters*len));
423 }
424
425 crypto_cipher_free(c);
426 tor_free(b);
427 }
428
429 /** Run digestmap_t performance benchmarks. */
430 static void
431 bench_dmap(void)
432 {
433 smartlist_t *sl = smartlist_new();
434 smartlist_t *sl2 = smartlist_new();
435 uint64_t start, end, pt2, pt3, pt4;
436 int iters = 8192;
437 const int elts = 4000;
438 const int fpostests = 100000;
439 char d[20];
440 int i,n=0, fp = 0;
441 digestmap_t *dm = digestmap_new();
442 digestset_t *ds = digestset_new(elts);
443
444 for (i = 0; i < elts; ++i) {
445 crypto_rand(d, 20);
446 smartlist_add(sl, tor_memdup(d, 20));
447 }
448 for (i = 0; i < elts; ++i) {
449 crypto_rand(d, 20);
450 smartlist_add(sl2, tor_memdup(d, 20));
451 }
452 //printf("nbits=%d\n", ds->mask+1);
453
454 reset_perftime();
455
456 start = perftime();
457 for (i = 0; i < iters; ++i) {
458 SMARTLIST_FOREACH(sl, const char *, cp, digestmap_set(dm, cp, (void*)1));
459 }
460 pt2 = perftime();
461 printf("digestmap_set: %.2f ns per element\n",
462 NANOCOUNT(start, pt2, iters*elts));
463
464 for (i = 0; i < iters; ++i) {
465 SMARTLIST_FOREACH(sl, const char *, cp, digestmap_get(dm, cp));
466 SMARTLIST_FOREACH(sl2, const char *, cp, digestmap_get(dm, cp));
467 }
468 pt3 = perftime();
469 printf("digestmap_get: %.2f ns per element\n",
470 NANOCOUNT(pt2, pt3, iters*elts*2));
471
472 for (i = 0; i < iters; ++i) {
473 SMARTLIST_FOREACH(sl, const char *, cp, digestset_add(ds, cp));
474 }
475 pt4 = perftime();
476 printf("digestset_add: %.2f ns per element\n",
477 NANOCOUNT(pt3, pt4, iters*elts));
478
479 for (i = 0; i < iters; ++i) {
480 SMARTLIST_FOREACH(sl, const char *, cp,
481 n += digestset_probably_contains(ds, cp));
482 SMARTLIST_FOREACH(sl2, const char *, cp,
483 n += digestset_probably_contains(ds, cp));
484 }
485 end = perftime();
486 printf("digestset_probably_contains: %.2f ns per element.\n",
487 NANOCOUNT(pt4, end, iters*elts*2));
488 /* We need to use this, or else the whole loop gets optimized out. */
489 printf("Hits == %d\n", n);
490
491 for (i = 0; i < fpostests; ++i) {
492 crypto_rand(d, 20);
493 if (digestset_probably_contains(ds, d)) ++fp;
494 }
495 printf("False positive rate on digestset: %.2f%%\n",
496 (fp/(double)fpostests)*100);
497
498 digestmap_free(dm, NULL);
499 digestset_free(ds);
500 SMARTLIST_FOREACH(sl, char *, cp, tor_free(cp));
501 SMARTLIST_FOREACH(sl2, char *, cp, tor_free(cp));
502 smartlist_free(sl);
503 smartlist_free(sl2);
504 }
505
506 static void
507 bench_siphash(void)
508 {
509 char buf[128];
510 int lens[] = { 7, 8, 15, 16, 20, 32, 111, 128, -1 };
511 int i, j;
512 uint64_t start, end;
513 const int N = 300000;
514 crypto_rand(buf, sizeof(buf));
515
516 for (i = 0; lens[i] > 0; ++i) {
517 reset_perftime();
518 start = perftime();
519 for (j = 0; j < N; ++j) {
520 siphash24g(buf, lens[i]);
521 }
522 end = perftime();
523 printf("siphash24g(%d): %.2f ns per call\n",
524 lens[i], NANOCOUNT(start,end,N));
525 }
526 }
527
528 static void
529 bench_digest(void)
530 {
531 char buf[8192];
532 char out[DIGEST512_LEN];
533 const int lens[] = { 1, 16, 32, 64, 128, 512, 1024, 2048, -1 };
534 const int N = 300000;
535 uint64_t start, end;
536 crypto_rand(buf, sizeof(buf));
537
538 for (int alg = 0; alg < N_DIGEST_ALGORITHMS; alg++) {
539 for (int i = 0; lens[i] > 0; ++i) {
540 reset_perftime();
541 start = perftime();
542 int failures = 0;
543 for (int j = 0; j < N; ++j) {
544 switch (alg) {
545 case DIGEST_SHA1:
546 failures += crypto_digest(out, buf, lens[i]) < 0;
547 break;
548 case DIGEST_SHA256:
549 case DIGEST_SHA3_256:
550 failures += crypto_digest256(out, buf, lens[i], alg) < 0;
551 break;
552 case DIGEST_SHA512:
553 case DIGEST_SHA3_512:
554 failures += crypto_digest512(out, buf, lens[i], alg) < 0;
555 break;
556 default:
557 tor_assert(0);
558 }
559 }
560 end = perftime();
561 printf("%s(%d): %.2f ns per call\n",
562 crypto_digest_algorithm_get_name(alg),
563 lens[i], NANOCOUNT(start,end,N));
564 if (failures)
565 printf("ERROR: crypto_digest failed %d times.\n", failures);
566 }
567 }
568 }
569
570 static void
571 bench_cell_ops(void)
572 {
573 const int iters = 1<<16;
574 int i;
575
576 /* benchmarks for cell ops at relay. */
577 or_circuit_t *or_circ = tor_malloc_zero(sizeof(or_circuit_t));
578 cell_t *cell = tor_malloc(sizeof(cell_t));
579 int outbound;
580 uint64_t start, end;
581
582 crypto_rand((char*)cell->payload, sizeof(cell->payload));
583
584 /* Mock-up or_circuit_t */
585 or_circ->base_.magic = OR_CIRCUIT_MAGIC;
586 or_circ->base_.purpose = CIRCUIT_PURPOSE_OR;
587
588 /* Initialize crypto */
589 char key1[CIPHER_KEY_LEN], key2[CIPHER_KEY_LEN];
590 crypto_rand(key1, sizeof(key1));
591 crypto_rand(key2, sizeof(key2));
592 or_circ->crypto.f_crypto = crypto_cipher_new(key1);
593 or_circ->crypto.b_crypto = crypto_cipher_new(key2);
594 or_circ->crypto.f_digest = crypto_digest_new();
595 or_circ->crypto.b_digest = crypto_digest_new();
596
597 reset_perftime();
598
599 for (outbound = 0; outbound <= 1; ++outbound) {
600 cell_direction_t d = outbound ? CELL_DIRECTION_OUT : CELL_DIRECTION_IN;
601 start = perftime();
602 for (i = 0; i < iters; ++i) {
603 char recognized = 0;
604 crypt_path_t *layer_hint = NULL;
605 relay_decrypt_cell(TO_CIRCUIT(or_circ), cell, d,
606 &layer_hint, &recognized);
607 }
608 end = perftime();
609 printf("%sbound cells: %.2f ns per cell. (%.2f ns per byte of payload)\n",
610 outbound?"Out":" In",
611 NANOCOUNT(start,end,iters),
612 NANOCOUNT(start,end,iters*CELL_PAYLOAD_SIZE));
613 }
614
615 relay_crypto_clear(&or_circ->crypto);
616 tor_free(or_circ);
617 tor_free(cell);
618 }
619
620 static void
621 bench_dh(void)
622 {
623 const int iters = 1<<10;
624 int i;
625 uint64_t start, end;
626
627 reset_perftime();
628 start = perftime();
629 for (i = 0; i < iters; ++i) {
630 char dh_pubkey_a[DH1024_KEY_LEN], dh_pubkey_b[DH1024_KEY_LEN];
631 char secret_a[DH1024_KEY_LEN], secret_b[DH1024_KEY_LEN];
632 ssize_t slen_a, slen_b;
633 crypto_dh_t *dh_a = crypto_dh_new(DH_TYPE_TLS);
634 crypto_dh_t *dh_b = crypto_dh_new(DH_TYPE_TLS);
635 crypto_dh_generate_public(dh_a);
636 crypto_dh_generate_public(dh_b);
637 crypto_dh_get_public(dh_a, dh_pubkey_a, sizeof(dh_pubkey_a));
638 crypto_dh_get_public(dh_b, dh_pubkey_b, sizeof(dh_pubkey_b));
639 slen_a = crypto_dh_compute_secret(LOG_NOTICE,
640 dh_a, dh_pubkey_b, sizeof(dh_pubkey_b),
641 secret_a, sizeof(secret_a));
642 slen_b = crypto_dh_compute_secret(LOG_NOTICE,
643 dh_b, dh_pubkey_a, sizeof(dh_pubkey_a),
644 secret_b, sizeof(secret_b));
645 tor_assert(slen_a == slen_b);
646 tor_assert(fast_memeq(secret_a, secret_b, slen_a));
647 crypto_dh_free(dh_a);
648 crypto_dh_free(dh_b);
649 }
650 end = perftime();
651 printf("Complete DH handshakes (1024 bit, public and private ops):\n"
652 " %f millisec each.\n", NANOCOUNT(start, end, iters)/1e6);
653 }
654
655 #ifdef ENABLE_OPENSSL
656 static void
657 bench_ecdh_impl(int nid, const char *name)
658 {
659 const int iters = 1<<10;
660 int i;
661 uint64_t start, end;
662
663 reset_perftime();
664 start = perftime();
665 for (i = 0; i < iters; ++i) {
666 char secret_a[DH1024_KEY_LEN], secret_b[DH1024_KEY_LEN];
667 ssize_t slen_a, slen_b;
668 EC_KEY *dh_a = EC_KEY_new_by_curve_name(nid);
669 EC_KEY *dh_b = EC_KEY_new_by_curve_name(nid);
670 if (!dh_a || !dh_b) {
671 puts("Skipping. (No implementation?)");
672 return;
673 }
674
675 EC_KEY_generate_key(dh_a);
676 EC_KEY_generate_key(dh_b);
677 slen_a = ECDH_compute_key(secret_a, DH1024_KEY_LEN,
678 EC_KEY_get0_public_key(dh_b), dh_a,
679 NULL);
680 slen_b = ECDH_compute_key(secret_b, DH1024_KEY_LEN,
681 EC_KEY_get0_public_key(dh_a), dh_b,
682 NULL);
683
684 tor_assert(slen_a == slen_b);
685 tor_assert(fast_memeq(secret_a, secret_b, slen_a));
686 EC_KEY_free(dh_a);
687 EC_KEY_free(dh_b);
688 }
689 end = perftime();
690 printf("Complete ECDH %s handshakes (2 public and 2 private ops):\n"
691 " %f millisec each.\n", name, NANOCOUNT(start, end, iters)/1e6);
692 }
693
694 static void
695 bench_ecdh_p256(void)
696 {
697 bench_ecdh_impl(NID_X9_62_prime256v1, "P-256");
698 }
699
700 static void
701 bench_ecdh_p224(void)
702 {
703 bench_ecdh_impl(NID_secp224r1, "P-224");
704 }
705 #endif /* defined(ENABLE_OPENSSL) */
706
707 static void
708 bench_md_parse(void)
709 {
710 uint64_t start, end;
711 const int N = 100000;
712 // selected arbitrarily
713 const char md_text[] =
714 "@last-listed 2018-12-14 18:14:14\n"
715 "onion-key\n"
716 "-----BEGIN RSA PUBLIC KEY-----\n"
717 "MIGJAoGBAMHkZeXNDX/49JqM2BVLmh1Fnb5iMVnatvZZTLJyedqDLkbXZ1WKP5oh\n"
718 "7ec14dj/k3ntpwHD4s2o3Lb6nfagWbug4+F/rNJ7JuFru/PSyOvDyHGNAuegOXph\n"
719 "3gTGjdDpv/yPoiadGebbVe8E7n6hO+XxM2W/4dqheKimF0/s9B7HAgMBAAE=\n"
720 "-----END RSA PUBLIC KEY-----\n"
721 "ntor-onion-key QgF/EjqlNG1wRHLIop/nCekEH+ETGZSgYOhu26eiTF4=\n"
722 "family $00E9A86E7733240E60D8435A7BBD634A23894098 "
723 "$329BD7545DEEEBBDC8C4285F243916F248972102 "
724 "$69E06EBB2573A4F89330BDF8BC869794A3E10E4D "
725 "$DCA2A3FAE50B3729DAA15BC95FB21AF03389818B\n"
726 "p accept 53,80,443,5222-5223,25565\n"
727 "id ed25519 BzffzY99z6Q8KltcFlUTLWjNTBU7yKK+uQhyi1Ivb3A\n";
728
729 reset_perftime();
730 start = perftime();
731 for (int i = 0; i < N; ++i) {
732 smartlist_t *s = microdescs_parse_from_string(md_text, NULL, 1,
733 SAVED_IN_CACHE, NULL);
734 SMARTLIST_FOREACH(s, microdesc_t *, md, microdesc_free(md));
735 smartlist_free(s);
736 }
737
738 end = perftime();
739 printf("Microdesc parse: %f nsec\n", NANOCOUNT(start, end, N));
740 }
741
742 typedef void (*bench_fn)(void);
743
744 typedef struct benchmark_t {
745 const char *name;
746 bench_fn fn;
747 int enabled;
748 } benchmark_t;
749
750 #define ENT(s) { #s , bench_##s, 0 }
751
752 static struct benchmark_t benchmarks[] = {
753 ENT(dmap),
754 ENT(siphash),
755 ENT(digest),
756 ENT(aes),
757 ENT(onion_TAP),
758 ENT(onion_ntor),
759 ENT(ed25519),
760 ENT(rand),
761
762 ENT(cell_aes),
763 ENT(cell_ops),
764 ENT(dh),
765
766 #ifdef ENABLE_OPENSSL
767 ENT(ecdh_p256),
768 ENT(ecdh_p224),
769 #endif
770
771 ENT(md_parse),
772 {NULL,NULL,0}
773 };
774
775 static benchmark_t *
776 find_benchmark(const char *name)
777 {
778 benchmark_t *b;
779 for (b = benchmarks; b->name; ++b) {
780 if (!strcmp(name, b->name)) {
781 return b;
782 }
783 }
784 return NULL;
785 }
786
787 /** Main entry point for benchmark code: parse the command line, and run
788 * some benchmarks. */
789 int
790 main(int argc, const char **argv)
791 {
792 int i;
793 int list=0, n_enabled=0;
794 char *errmsg;
795 or_options_t *options;
796
797 subsystems_init_upto(SUBSYS_LEVEL_LIBS);
798 flush_log_messages_from_startup();
799
800 tor_compress_init();
801
802 if (argc == 4 && !strcmp(argv[1], "diff")) {
803 const int N = 200;
804 char *f1 = read_file_to_str(argv[2], RFTS_BIN, NULL);
805 char *f2 = read_file_to_str(argv[3], RFTS_BIN, NULL);
806 if (! f1 || ! f2) {
807 perror("X");
808 return 1;
809 }
810 size_t f1len = strlen(f1);
811 size_t f2len = strlen(f2);
812 for (i = 0; i < N; ++i) {
813 char *diff = consensus_diff_generate(f1, f1len, f2, f2len);
814 tor_free(diff);
815 }
816 char *diff = consensus_diff_generate(f1, f1len, f2, f2len);
817 printf("%s", diff);
818 tor_free(f1);
819 tor_free(f2);
820 tor_free(diff);
821 return 0;
822 }
823
824 for (i = 1; i < argc; ++i) {
825 if (!strcmp(argv[i], "--list")) {
826 list = 1;
827 } else {
828 benchmark_t *benchmark = find_benchmark(argv[i]);
829 ++n_enabled;
830 if (benchmark) {
831 benchmark->enabled = 1;
832 } else {
833 printf("No such benchmark as %s\n", argv[i]);
834 }
835 }
836 }
837
838 reset_perftime();
839
840 if (crypto_global_init(0, NULL, NULL) < 0) {
841 printf("Couldn't seed RNG; exiting.\n");
842 return 1;
843 }
844
845 init_protocol_warning_severity_level();
846 options = options_new();
847 options->command = CMD_RUN_UNITTESTS;
848 options->DataDirectory = tor_strdup("");
849 options->KeyDirectory = tor_strdup("");
850 options->CacheDirectory = tor_strdup("");
851 options_init(options);
852 if (set_options(options, &errmsg) < 0) {
853 printf("Failed to set initial options: %s\n", errmsg);
854 tor_free(errmsg);
855 return 1;
856 }
857
858 for (benchmark_t *b = benchmarks; b->name; ++b) {
859 if (b->enabled || n_enabled == 0) {
860 printf("===== %s =====\n", b->name);
861 if (!list)
862 b->fn();
863 }
864 }
865
866 return 0;
867 }