"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 }