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 }