/ src / secp256k1 / src / bench.c
bench.c
  1  /***********************************************************************
  2   * Copyright (c) 2014 Pieter Wuille                                    *
  3   * Distributed under the MIT software license, see the accompanying    *
  4   * file COPYING or https://www.opensource.org/licenses/mit-license.php.*
  5   ***********************************************************************/
  6  
  7  #include <stdio.h>
  8  #include <stdlib.h>
  9  #include <string.h>
 10  
 11  #include "../include/secp256k1.h"
 12  #include "util.h"
 13  #include "bench.h"
 14  
 15  static void help(const char *executable_path, int default_iters) {
 16      printf("Benchmarks the following algorithms:\n");
 17      printf("    - ECDSA signing/verification\n");
 18  
 19  #ifdef ENABLE_MODULE_RECOVERY
 20      printf("    - Public key recovery (optional module)\n");
 21  #endif
 22  
 23  #ifdef ENABLE_MODULE_ECDH
 24      printf("    - ECDH key exchange (optional module)\n");
 25  #endif
 26  
 27  #ifdef ENABLE_MODULE_SCHNORRSIG
 28      printf("    - Schnorr signatures (optional module)\n");
 29  #endif
 30  
 31  #ifdef ENABLE_MODULE_ELLSWIFT
 32      printf("    - ElligatorSwift (optional module)\n");
 33  #endif
 34  
 35      printf("\n");
 36      printf("The default number of iterations for each benchmark is %d. This can be\n", default_iters);
 37      printf("customized using the SECP256K1_BENCH_ITERS environment variable.\n");
 38      printf("\n");
 39      printf("Usage: %s [args]\n", executable_path);
 40      printf("By default, all benchmarks will be run.\n");
 41      printf("args:\n");
 42      printf("    help              : display this help and exit\n");
 43      printf("    ecdsa             : all ECDSA algorithms--sign, verify, recovery (if enabled)\n");
 44      printf("    ecdsa_sign        : ECDSA siging algorithm\n");
 45      printf("    ecdsa_verify      : ECDSA verification algorithm\n");
 46      printf("    ec                : all EC public key algorithms (keygen)\n");
 47      printf("    ec_keygen         : EC public key generation\n");
 48  
 49  #ifdef ENABLE_MODULE_RECOVERY
 50      printf("    ecdsa_recover     : ECDSA public key recovery algorithm\n");
 51  #endif
 52  
 53  #ifdef ENABLE_MODULE_ECDH
 54      printf("    ecdh              : ECDH key exchange algorithm\n");
 55  #endif
 56  
 57  #ifdef ENABLE_MODULE_SCHNORRSIG
 58      printf("    schnorrsig        : all Schnorr signature algorithms (sign, verify)\n");
 59      printf("    schnorrsig_sign   : Schnorr sigining algorithm\n");
 60      printf("    schnorrsig_verify : Schnorr verification algorithm\n");
 61  #endif
 62  
 63  #ifdef ENABLE_MODULE_ELLSWIFT
 64      printf("    ellswift          : all ElligatorSwift benchmarks (encode, decode, keygen, ecdh)\n");
 65      printf("    ellswift_encode   : ElligatorSwift encoding\n");
 66      printf("    ellswift_decode   : ElligatorSwift decoding\n");
 67      printf("    ellswift_keygen   : ElligatorSwift key generation\n");
 68      printf("    ellswift_ecdh     : ECDH on ElligatorSwift keys\n");
 69  #endif
 70  
 71      printf("\n");
 72  }
 73  
 74  typedef struct {
 75      secp256k1_context *ctx;
 76      unsigned char msg[32];
 77      unsigned char key[32];
 78      unsigned char sig[72];
 79      size_t siglen;
 80      unsigned char pubkey[33];
 81      size_t pubkeylen;
 82  } bench_data;
 83  
 84  static void bench_verify(void* arg, int iters) {
 85      int i;
 86      bench_data* data = (bench_data*)arg;
 87  
 88      for (i = 0; i < iters; i++) {
 89          secp256k1_pubkey pubkey;
 90          secp256k1_ecdsa_signature sig;
 91          data->sig[data->siglen - 1] ^= (i & 0xFF);
 92          data->sig[data->siglen - 2] ^= ((i >> 8) & 0xFF);
 93          data->sig[data->siglen - 3] ^= ((i >> 16) & 0xFF);
 94          CHECK(secp256k1_ec_pubkey_parse(data->ctx, &pubkey, data->pubkey, data->pubkeylen) == 1);
 95          CHECK(secp256k1_ecdsa_signature_parse_der(data->ctx, &sig, data->sig, data->siglen) == 1);
 96          CHECK(secp256k1_ecdsa_verify(data->ctx, &sig, data->msg, &pubkey) == (i == 0));
 97          data->sig[data->siglen - 1] ^= (i & 0xFF);
 98          data->sig[data->siglen - 2] ^= ((i >> 8) & 0xFF);
 99          data->sig[data->siglen - 3] ^= ((i >> 16) & 0xFF);
100      }
101  }
102  
103  static void bench_sign_setup(void* arg) {
104      int i;
105      bench_data *data = (bench_data*)arg;
106  
107      for (i = 0; i < 32; i++) {
108          data->msg[i] = i + 1;
109      }
110      for (i = 0; i < 32; i++) {
111          data->key[i] = i + 65;
112      }
113  }
114  
115  static void bench_sign_run(void* arg, int iters) {
116      int i;
117      bench_data *data = (bench_data*)arg;
118  
119      unsigned char sig[74];
120      for (i = 0; i < iters; i++) {
121          size_t siglen = 74;
122          int j;
123          secp256k1_ecdsa_signature signature;
124          CHECK(secp256k1_ecdsa_sign(data->ctx, &signature, data->msg, data->key, NULL, NULL));
125          CHECK(secp256k1_ecdsa_signature_serialize_der(data->ctx, sig, &siglen, &signature));
126          for (j = 0; j < 32; j++) {
127              data->msg[j] = sig[j];
128              data->key[j] = sig[j + 32];
129          }
130      }
131  }
132  
133  static void bench_keygen_setup(void* arg) {
134      int i;
135      bench_data *data = (bench_data*)arg;
136  
137      for (i = 0; i < 32; i++) {
138          data->key[i] = i + 65;
139      }
140  }
141  
142  static void bench_keygen_run(void *arg, int iters) {
143      int i;
144      bench_data *data = (bench_data*)arg;
145  
146      for (i = 0; i < iters; i++) {
147          unsigned char pub33[33];
148          size_t len = 33;
149          secp256k1_pubkey pubkey;
150          CHECK(secp256k1_ec_pubkey_create(data->ctx, &pubkey, data->key));
151          CHECK(secp256k1_ec_pubkey_serialize(data->ctx, pub33, &len, &pubkey, SECP256K1_EC_COMPRESSED));
152          memcpy(data->key, pub33 + 1, 32);
153      }
154  }
155  
156  
157  #ifdef ENABLE_MODULE_ECDH
158  # include "modules/ecdh/bench_impl.h"
159  #endif
160  
161  #ifdef ENABLE_MODULE_RECOVERY
162  # include "modules/recovery/bench_impl.h"
163  #endif
164  
165  #ifdef ENABLE_MODULE_SCHNORRSIG
166  # include "modules/schnorrsig/bench_impl.h"
167  #endif
168  
169  #ifdef ENABLE_MODULE_ELLSWIFT
170  # include "modules/ellswift/bench_impl.h"
171  #endif
172  
173  int main(int argc, char** argv) {
174      int i;
175      secp256k1_pubkey pubkey;
176      secp256k1_ecdsa_signature sig;
177      bench_data data;
178  
179      int d = argc == 1;
180  
181      /* Check for invalid user arguments */
182      char* valid_args[] = {"ecdsa", "verify", "ecdsa_verify", "sign", "ecdsa_sign", "ecdh", "recover",
183                           "ecdsa_recover", "schnorrsig", "schnorrsig_verify", "schnorrsig_sign", "ec",
184                           "keygen", "ec_keygen", "ellswift", "encode", "ellswift_encode", "decode",
185                           "ellswift_decode", "ellswift_keygen", "ellswift_ecdh"};
186      int invalid_args = have_invalid_args(argc, argv, valid_args, ARRAY_SIZE(valid_args));
187  
188      int default_iters = 20000;
189      int iters = get_iters(default_iters);
190      if (iters == 0) {
191          help(argv[0], default_iters);
192          return EXIT_FAILURE;
193      }
194  
195      if (argc > 1) {
196          if (have_flag(argc, argv, "-h")
197             || have_flag(argc, argv, "--help")
198             || have_flag(argc, argv, "help")) {
199              help(argv[0], default_iters);
200              return EXIT_SUCCESS;
201          } else if (invalid_args) {
202              fprintf(stderr, "./bench: unrecognized argument.\n\n");
203              help(argv[0], default_iters);
204              return EXIT_FAILURE;
205          }
206      }
207  
208  /* Check if the user tries to benchmark optional module without building it */
209  #ifndef ENABLE_MODULE_ECDH
210      if (have_flag(argc, argv, "ecdh")) {
211          fprintf(stderr, "./bench: ECDH module not enabled.\n");
212          fprintf(stderr, "See README.md for configuration instructions.\n\n");
213          return EXIT_FAILURE;
214      }
215  #endif
216  
217  #ifndef ENABLE_MODULE_RECOVERY
218      if (have_flag(argc, argv, "recover") || have_flag(argc, argv, "ecdsa_recover")) {
219          fprintf(stderr, "./bench: Public key recovery module not enabled.\n");
220          fprintf(stderr, "See README.md for configuration instructions.\n\n");
221          return EXIT_FAILURE;
222      }
223  #endif
224  
225  #ifndef ENABLE_MODULE_SCHNORRSIG
226      if (have_flag(argc, argv, "schnorrsig") || have_flag(argc, argv, "schnorrsig_sign") || have_flag(argc, argv, "schnorrsig_verify")) {
227          fprintf(stderr, "./bench: Schnorr signatures module not enabled.\n");
228          fprintf(stderr, "See README.md for configuration instructions.\n\n");
229          return EXIT_FAILURE;
230      }
231  #endif
232  
233  #ifndef ENABLE_MODULE_ELLSWIFT
234      if (have_flag(argc, argv, "ellswift") || have_flag(argc, argv, "ellswift_encode") || have_flag(argc, argv, "ellswift_decode") ||
235          have_flag(argc, argv, "encode") || have_flag(argc, argv, "decode") || have_flag(argc, argv, "ellswift_keygen") ||
236          have_flag(argc, argv, "ellswift_ecdh")) {
237          fprintf(stderr, "./bench: ElligatorSwift module not enabled.\n");
238          fprintf(stderr, "See README.md for configuration instructions.\n\n");
239          return EXIT_FAILURE;
240      }
241  #endif
242  
243      /* ECDSA benchmark */
244      data.ctx = secp256k1_context_create(SECP256K1_CONTEXT_NONE);
245  
246      for (i = 0; i < 32; i++) {
247          data.msg[i] = 1 + i;
248      }
249      for (i = 0; i < 32; i++) {
250          data.key[i] = 33 + i;
251      }
252      data.siglen = 72;
253      CHECK(secp256k1_ecdsa_sign(data.ctx, &sig, data.msg, data.key, NULL, NULL));
254      CHECK(secp256k1_ecdsa_signature_serialize_der(data.ctx, data.sig, &data.siglen, &sig));
255      CHECK(secp256k1_ec_pubkey_create(data.ctx, &pubkey, data.key));
256      data.pubkeylen = 33;
257      CHECK(secp256k1_ec_pubkey_serialize(data.ctx, data.pubkey, &data.pubkeylen, &pubkey, SECP256K1_EC_COMPRESSED) == 1);
258  
259      print_output_table_header_row();
260      if (d || have_flag(argc, argv, "ecdsa") || have_flag(argc, argv, "verify") || have_flag(argc, argv, "ecdsa_verify")) run_benchmark("ecdsa_verify", bench_verify, NULL, NULL, &data, 10, iters);
261  
262      if (d || have_flag(argc, argv, "ecdsa") || have_flag(argc, argv, "sign") || have_flag(argc, argv, "ecdsa_sign")) run_benchmark("ecdsa_sign", bench_sign_run, bench_sign_setup, NULL, &data, 10, iters);
263      if (d || have_flag(argc, argv, "ec") || have_flag(argc, argv, "keygen") || have_flag(argc, argv, "ec_keygen")) run_benchmark("ec_keygen", bench_keygen_run, bench_keygen_setup, NULL, &data, 10, iters);
264  
265      secp256k1_context_destroy(data.ctx);
266  
267  #ifdef ENABLE_MODULE_ECDH
268      /* ECDH benchmarks */
269      run_ecdh_bench(iters, argc, argv);
270  #endif
271  
272  #ifdef ENABLE_MODULE_RECOVERY
273      /* ECDSA recovery benchmarks */
274      run_recovery_bench(iters, argc, argv);
275  #endif
276  
277  #ifdef ENABLE_MODULE_SCHNORRSIG
278      /* Schnorr signature benchmarks */
279      run_schnorrsig_bench(iters, argc, argv);
280  #endif
281  
282  #ifdef ENABLE_MODULE_ELLSWIFT
283      /* ElligatorSwift benchmarks */
284      run_ellswift_bench(iters, argc, argv);
285  #endif
286  
287      return EXIT_SUCCESS;
288  }