xref: /openbsd-src/regress/lib/libcrypto/bn/bn_mul_div.c (revision d1ac4eb253fca7bc79cbde208e085881b3264048)
1*d1ac4eb2Sjsing /*	$OpenBSD: bn_mul_div.c,v 1.7 2023/06/21 07:18:10 jsing Exp $ */
22900a9c1Sjsing /*
32900a9c1Sjsing  * Copyright (c) 2023 Joel Sing <jsing@openbsd.org>
42900a9c1Sjsing  *
52900a9c1Sjsing  * Permission to use, copy, modify, and distribute this software for any
62900a9c1Sjsing  * purpose with or without fee is hereby granted, provided that the above
72900a9c1Sjsing  * copyright notice and this permission notice appear in all copies.
82900a9c1Sjsing  *
92900a9c1Sjsing  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
102900a9c1Sjsing  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
112900a9c1Sjsing  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
122900a9c1Sjsing  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
132900a9c1Sjsing  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
142900a9c1Sjsing  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
152900a9c1Sjsing  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
162900a9c1Sjsing  */
172900a9c1Sjsing 
188d9f23acSjsing #include <sys/resource.h>
192900a9c1Sjsing #include <sys/time.h>
202900a9c1Sjsing 
212900a9c1Sjsing #include <err.h>
222900a9c1Sjsing #include <signal.h>
232900a9c1Sjsing #include <stdio.h>
242900a9c1Sjsing #include <string.h>
252900a9c1Sjsing #include <time.h>
262900a9c1Sjsing #include <unistd.h>
272900a9c1Sjsing 
282900a9c1Sjsing #include <openssl/bn.h>
292900a9c1Sjsing 
302900a9c1Sjsing static int
benchmark_bn_div_setup(BIGNUM * a,size_t a_bits,BIGNUM * b,size_t b_bits,BIGNUM * r,BIGNUM * q)3172c289bdSjsing benchmark_bn_div_setup(BIGNUM *a, size_t a_bits, BIGNUM *b, size_t b_bits,
3272c289bdSjsing     BIGNUM *r, BIGNUM *q)
3372c289bdSjsing {
3472c289bdSjsing 	if (!BN_rand(a, a_bits, BN_RAND_TOP_ONE, BN_RAND_BOTTOM_ANY))
3572c289bdSjsing 		return 0;
3672c289bdSjsing 	if (!BN_rand(b, b_bits - 1, BN_RAND_TOP_ONE, BN_RAND_BOTTOM_ANY))
3772c289bdSjsing 		return 0;
3872c289bdSjsing 	if (!BN_set_bit(r, a_bits))
3972c289bdSjsing 		return 0;
4072c289bdSjsing 	if (!BN_set_bit(q, b_bits))
4172c289bdSjsing 		return 0;
4272c289bdSjsing 
4372c289bdSjsing 	return 1;
4472c289bdSjsing }
4572c289bdSjsing 
4672c289bdSjsing static void
benchmark_bn_div_run_once(BIGNUM * r,BIGNUM * q,BIGNUM * a,BIGNUM * b,BN_CTX * bn_ctx)4772c289bdSjsing benchmark_bn_div_run_once(BIGNUM *r, BIGNUM *q, BIGNUM *a, BIGNUM *b, BN_CTX *bn_ctx)
4872c289bdSjsing {
4972c289bdSjsing 	if (!BN_div(r, q, a, b, bn_ctx))
5072c289bdSjsing 		errx(1, "BN_div");
5172c289bdSjsing }
5272c289bdSjsing 
5372c289bdSjsing static int
benchmark_bn_mul_setup(BIGNUM * a,size_t a_bits,BIGNUM * b,size_t b_bits,BIGNUM * r,BIGNUM * q)542900a9c1Sjsing benchmark_bn_mul_setup(BIGNUM *a, size_t a_bits, BIGNUM *b, size_t b_bits,
5572c289bdSjsing     BIGNUM *r, BIGNUM *q)
562900a9c1Sjsing {
57a3f05336Sjsing 	if (!BN_rand(a, a_bits, BN_RAND_TOP_ONE, BN_RAND_BOTTOM_ANY))
582900a9c1Sjsing 		return 0;
59a3f05336Sjsing 	if (!BN_rand(b, b_bits, BN_RAND_TOP_ONE, BN_RAND_BOTTOM_ANY))
602900a9c1Sjsing 		return 0;
612900a9c1Sjsing 	if (!BN_set_bit(r, (a_bits + b_bits) - 1))
622900a9c1Sjsing 		return 0;
632900a9c1Sjsing 
642900a9c1Sjsing 	return 1;
652900a9c1Sjsing }
662900a9c1Sjsing 
672900a9c1Sjsing static void
benchmark_bn_mul_run_once(BIGNUM * r,BIGNUM * q,BIGNUM * a,BIGNUM * b,BN_CTX * bn_ctx)6872c289bdSjsing benchmark_bn_mul_run_once(BIGNUM *r, BIGNUM *q, BIGNUM *a, BIGNUM *b, BN_CTX *bn_ctx)
692900a9c1Sjsing {
702900a9c1Sjsing 	if (!BN_mul(r, a, b, bn_ctx))
712900a9c1Sjsing 		errx(1, "BN_mul");
722900a9c1Sjsing }
732900a9c1Sjsing 
742900a9c1Sjsing static int
benchmark_bn_sqr_setup(BIGNUM * a,size_t a_bits,BIGNUM * b,size_t b_bits,BIGNUM * r,BIGNUM * q)752900a9c1Sjsing benchmark_bn_sqr_setup(BIGNUM *a, size_t a_bits, BIGNUM *b, size_t b_bits,
7672c289bdSjsing     BIGNUM *r, BIGNUM *q)
772900a9c1Sjsing {
78a3f05336Sjsing 	if (!BN_rand(a, a_bits, BN_RAND_TOP_ONE, BN_RAND_BOTTOM_ANY))
792900a9c1Sjsing 		return 0;
802900a9c1Sjsing 	if (!BN_set_bit(r, (a_bits + a_bits) - 1))
812900a9c1Sjsing 		return 0;
822900a9c1Sjsing 
832900a9c1Sjsing 	return 1;
842900a9c1Sjsing }
852900a9c1Sjsing 
862900a9c1Sjsing static void
benchmark_bn_sqr_run_once(BIGNUM * r,BIGNUM * q,BIGNUM * a,BIGNUM * b,BN_CTX * bn_ctx)8772c289bdSjsing benchmark_bn_sqr_run_once(BIGNUM *r, BIGNUM *q, BIGNUM *a, BIGNUM *b, BN_CTX *bn_ctx)
882900a9c1Sjsing {
892900a9c1Sjsing 	if (!BN_sqr(r, a, bn_ctx))
902900a9c1Sjsing 		errx(1, "BN_sqr");
912900a9c1Sjsing }
922900a9c1Sjsing 
932900a9c1Sjsing struct benchmark {
942900a9c1Sjsing 	const char *desc;
9572c289bdSjsing 	int (*setup)(BIGNUM *, size_t, BIGNUM *, size_t, BIGNUM *, BIGNUM *);
9672c289bdSjsing 	void (*run_once)(BIGNUM *, BIGNUM *, BIGNUM *, BIGNUM *, BN_CTX *);
972900a9c1Sjsing 	size_t a_bits;
982900a9c1Sjsing 	size_t b_bits;
992900a9c1Sjsing };
1002900a9c1Sjsing 
1012900a9c1Sjsing struct benchmark benchmarks[] = {
1022900a9c1Sjsing 	{
10372c289bdSjsing 		.desc = "BN_div (64 bit / 64 bit)",
10472c289bdSjsing 		.setup = benchmark_bn_div_setup,
10572c289bdSjsing 		.run_once = benchmark_bn_div_run_once,
10672c289bdSjsing 		.a_bits = 64,
10772c289bdSjsing 		.b_bits = 64,
10872c289bdSjsing 	},
10972c289bdSjsing 	{
11072c289bdSjsing 		.desc = "BN_div (128 bit / 128 bit)",
11172c289bdSjsing 		.setup = benchmark_bn_div_setup,
11272c289bdSjsing 		.run_once = benchmark_bn_div_run_once,
11372c289bdSjsing 		.a_bits = 128,
11472c289bdSjsing 		.b_bits = 128,
11572c289bdSjsing 	},
11672c289bdSjsing 	{
11772c289bdSjsing 		.desc = "BN_div (196 bit / 196 bit)",
11872c289bdSjsing 		.setup = benchmark_bn_div_setup,
11972c289bdSjsing 		.run_once = benchmark_bn_div_run_once,
12072c289bdSjsing 		.a_bits = 196,
12172c289bdSjsing 		.b_bits = 196,
12272c289bdSjsing 	},
12372c289bdSjsing 	{
12472c289bdSjsing 		.desc = "BN_div (256 bit / 256 bit)",
12572c289bdSjsing 		.setup = benchmark_bn_div_setup,
12672c289bdSjsing 		.run_once = benchmark_bn_div_run_once,
12772c289bdSjsing 		.a_bits = 256,
12872c289bdSjsing 		.b_bits = 256,
12972c289bdSjsing 	},
13072c289bdSjsing 	{
13172c289bdSjsing 		.desc = "BN_div (320 bit / 320 bit)",
13272c289bdSjsing 		.setup = benchmark_bn_div_setup,
13372c289bdSjsing 		.run_once = benchmark_bn_div_run_once,
13472c289bdSjsing 		.a_bits = 320,
13572c289bdSjsing 		.b_bits = 320,
13672c289bdSjsing 	},
13772c289bdSjsing 	{
13872c289bdSjsing 		.desc = "BN_div (384 bit / 384 bit)",
13972c289bdSjsing 		.setup = benchmark_bn_div_setup,
14072c289bdSjsing 		.run_once = benchmark_bn_div_run_once,
14172c289bdSjsing 		.a_bits = 384,
14272c289bdSjsing 		.b_bits = 384,
14372c289bdSjsing 	},
14472c289bdSjsing 	{
14572c289bdSjsing 		.desc = "BN_div (384 bit / 128 bit)",
14672c289bdSjsing 		.setup = benchmark_bn_div_setup,
14772c289bdSjsing 		.run_once = benchmark_bn_div_run_once,
14872c289bdSjsing 		.a_bits = 384,
14972c289bdSjsing 		.b_bits = 128,
15072c289bdSjsing 	},
15172c289bdSjsing 	{
15272c289bdSjsing 		.desc = "BN_div (448 bit / 256 bit)",
15372c289bdSjsing 		.setup = benchmark_bn_div_setup,
15472c289bdSjsing 		.run_once = benchmark_bn_div_run_once,
15572c289bdSjsing 		.a_bits = 448,
15672c289bdSjsing 		.b_bits = 256,
15772c289bdSjsing 	},
15872c289bdSjsing 	{
15972c289bdSjsing 		.desc = "BN_div (512 bit / 512 bit)",
16072c289bdSjsing 		.setup = benchmark_bn_div_setup,
16172c289bdSjsing 		.run_once = benchmark_bn_div_run_once,
16272c289bdSjsing 		.a_bits = 512,
16372c289bdSjsing 		.b_bits = 512,
16472c289bdSjsing 	},
16572c289bdSjsing 	{
16672c289bdSjsing 		.desc = "BN_div (768 bit / 256 bit)",
16772c289bdSjsing 		.setup = benchmark_bn_div_setup,
16872c289bdSjsing 		.run_once = benchmark_bn_div_run_once,
16972c289bdSjsing 		.a_bits = 768,
17072c289bdSjsing 		.b_bits = 256,
17172c289bdSjsing 	},
17272c289bdSjsing 	{
17372c289bdSjsing 		.desc = "BN_div (1024 bit / 128 bit)",
17472c289bdSjsing 		.setup = benchmark_bn_div_setup,
17572c289bdSjsing 		.run_once = benchmark_bn_div_run_once,
17672c289bdSjsing 		.a_bits = 1024,
17772c289bdSjsing 		.b_bits = 128,
17872c289bdSjsing 	},
17972c289bdSjsing 	{
18072c289bdSjsing 		.desc = "BN_div (2048 bit / 512 bit)",
18172c289bdSjsing 		.setup = benchmark_bn_div_setup,
18272c289bdSjsing 		.run_once = benchmark_bn_div_run_once,
18372c289bdSjsing 		.a_bits = 2048,
18472c289bdSjsing 		.b_bits = 128,
18572c289bdSjsing 	},
18672c289bdSjsing 	{
18772c289bdSjsing 		.desc = "BN_div (3072 bit / 1024 bit)",
18872c289bdSjsing 		.setup = benchmark_bn_div_setup,
18972c289bdSjsing 		.run_once = benchmark_bn_div_run_once,
19072c289bdSjsing 		.a_bits = 2048,
19172c289bdSjsing 		.b_bits = 1024,
19272c289bdSjsing 	},
19372c289bdSjsing 	{
19472c289bdSjsing 		.desc = "BN_div (4288 bit / 2176 bit)",
19572c289bdSjsing 		.setup = benchmark_bn_div_setup,
19672c289bdSjsing 		.run_once = benchmark_bn_div_run_once,
19772c289bdSjsing 		.a_bits = 2048,
19872c289bdSjsing 		.b_bits = 1024,
19972c289bdSjsing 	},
20072c289bdSjsing 	{
20172c289bdSjsing 		.desc = "BN_div (6144 bit / 2048 bit)",
20272c289bdSjsing 		.setup = benchmark_bn_div_setup,
20372c289bdSjsing 		.run_once = benchmark_bn_div_run_once,
20472c289bdSjsing 		.a_bits = 2048,
20572c289bdSjsing 		.b_bits = 1024,
20672c289bdSjsing 	},
20772c289bdSjsing 	{
20872c289bdSjsing 		.desc = "BN_div (16384 bit / 8192 bit)",
20972c289bdSjsing 		.setup = benchmark_bn_div_setup,
21072c289bdSjsing 		.run_once = benchmark_bn_div_run_once,
21172c289bdSjsing 		.a_bits = 16384,
21272c289bdSjsing 		.b_bits = 8192,
21372c289bdSjsing 	},
21472c289bdSjsing 	{
2152900a9c1Sjsing 		.desc = "BN_mul (128 bit x 128 bit)",
2162900a9c1Sjsing 		.setup = benchmark_bn_mul_setup,
2172900a9c1Sjsing 		.run_once = benchmark_bn_mul_run_once,
2182900a9c1Sjsing 		.a_bits = 128,
2192900a9c1Sjsing 		.b_bits = 128,
2202900a9c1Sjsing 	},
2212900a9c1Sjsing 	{
2222900a9c1Sjsing 		.desc = "BN_mul (128 bit x 256 bit)",
2232900a9c1Sjsing 		.setup = benchmark_bn_mul_setup,
2242900a9c1Sjsing 		.run_once = benchmark_bn_mul_run_once,
2252900a9c1Sjsing 		.a_bits = 128,
2262900a9c1Sjsing 		.b_bits = 256,
2272900a9c1Sjsing 	},
2282900a9c1Sjsing 	{
2292900a9c1Sjsing 		.desc = "BN_mul (256 bit x 256 bit)",
2302900a9c1Sjsing 		.setup = benchmark_bn_mul_setup,
2312900a9c1Sjsing 		.run_once = benchmark_bn_mul_run_once,
2322900a9c1Sjsing 		.a_bits = 256,
2332900a9c1Sjsing 		.b_bits = 256,
2342900a9c1Sjsing 	},
2352900a9c1Sjsing 	{
2362900a9c1Sjsing 		.desc = "BN_mul (512 bit x 512 bit)",
2372900a9c1Sjsing 		.setup = benchmark_bn_mul_setup,
2382900a9c1Sjsing 		.run_once = benchmark_bn_mul_run_once,
2392900a9c1Sjsing 		.a_bits = 512,
2402900a9c1Sjsing 		.b_bits = 512,
2412900a9c1Sjsing 	},
2422900a9c1Sjsing 	{
2432900a9c1Sjsing 		.desc = "BN_mul (1024 bit x 1024 bit)",
2442900a9c1Sjsing 		.setup = benchmark_bn_mul_setup,
2452900a9c1Sjsing 		.run_once = benchmark_bn_mul_run_once,
2462900a9c1Sjsing 		.a_bits = 1024,
2472900a9c1Sjsing 		.b_bits = 1024,
2482900a9c1Sjsing 	},
2492900a9c1Sjsing 	{
2502900a9c1Sjsing 		.desc = "BN_mul (1024 bit x 2048 bit)",
2512900a9c1Sjsing 		.setup = benchmark_bn_mul_setup,
2522900a9c1Sjsing 		.run_once = benchmark_bn_mul_run_once,
2532900a9c1Sjsing 		.a_bits = 1024,
2542900a9c1Sjsing 		.b_bits = 2048,
2552900a9c1Sjsing 	},
2562900a9c1Sjsing 	{
2572900a9c1Sjsing 		.desc = "BN_mul (2048 bit x 2048 bit)",
2582900a9c1Sjsing 		.setup = benchmark_bn_mul_setup,
2592900a9c1Sjsing 		.run_once = benchmark_bn_mul_run_once,
2602900a9c1Sjsing 		.a_bits = 2048,
2612900a9c1Sjsing 		.b_bits = 2048,
2622900a9c1Sjsing 	},
2632900a9c1Sjsing 	{
2642900a9c1Sjsing 		.desc = "BN_mul (4096 bit x 4096 bit)",
2652900a9c1Sjsing 		.setup = benchmark_bn_mul_setup,
2662900a9c1Sjsing 		.run_once = benchmark_bn_mul_run_once,
2672900a9c1Sjsing 		.a_bits = 4096,
2682900a9c1Sjsing 		.b_bits = 4096,
2692900a9c1Sjsing 	},
2702900a9c1Sjsing 	{
2712900a9c1Sjsing 		.desc = "BN_mul (4096 bit x 8192 bit)",
2722900a9c1Sjsing 		.setup = benchmark_bn_mul_setup,
2732900a9c1Sjsing 		.run_once = benchmark_bn_mul_run_once,
2742900a9c1Sjsing 		.a_bits = 4096,
2752900a9c1Sjsing 		.b_bits = 8192,
2762900a9c1Sjsing 	},
2772900a9c1Sjsing 	{
2782900a9c1Sjsing 		.desc = "BN_mul (8192 bit x 8192 bit)",
2792900a9c1Sjsing 		.setup = benchmark_bn_mul_setup,
2802900a9c1Sjsing 		.run_once = benchmark_bn_mul_run_once,
2812900a9c1Sjsing 		.a_bits = 8192,
2822900a9c1Sjsing 		.b_bits = 8192,
2832900a9c1Sjsing 	},
2842900a9c1Sjsing 	{
2852900a9c1Sjsing 		.desc = "BN_sqr (128 bit)",
2862900a9c1Sjsing 		.setup = benchmark_bn_sqr_setup,
2872900a9c1Sjsing 		.run_once = benchmark_bn_sqr_run_once,
2882900a9c1Sjsing 		.a_bits = 128,
2892900a9c1Sjsing 	},
2902900a9c1Sjsing 	{
2912900a9c1Sjsing 		.desc = "BN_sqr (256 bit)",
2922900a9c1Sjsing 		.setup = benchmark_bn_sqr_setup,
2932900a9c1Sjsing 		.run_once = benchmark_bn_sqr_run_once,
2942900a9c1Sjsing 		.a_bits = 256,
2952900a9c1Sjsing 	},
2962900a9c1Sjsing 	{
2972900a9c1Sjsing 		.desc = "BN_sqr (512 bit)",
2982900a9c1Sjsing 		.setup = benchmark_bn_sqr_setup,
2992900a9c1Sjsing 		.run_once = benchmark_bn_sqr_run_once,
3002900a9c1Sjsing 		.a_bits = 512,
3012900a9c1Sjsing 	},
3022900a9c1Sjsing 	{
3032900a9c1Sjsing 		.desc = "BN_sqr (1024 bit)",
3042900a9c1Sjsing 		.setup = benchmark_bn_sqr_setup,
3052900a9c1Sjsing 		.run_once = benchmark_bn_sqr_run_once,
3062900a9c1Sjsing 		.a_bits = 1024,
3072900a9c1Sjsing 	},
3082900a9c1Sjsing 	{
3092900a9c1Sjsing 		.desc = "BN_sqr (2048 bit)",
3102900a9c1Sjsing 		.setup = benchmark_bn_sqr_setup,
3112900a9c1Sjsing 		.run_once = benchmark_bn_sqr_run_once,
3122900a9c1Sjsing 		.a_bits = 2048,
3132900a9c1Sjsing 	},
3142900a9c1Sjsing 	{
3152900a9c1Sjsing 		.desc = "BN_sqr (4096 bit)",
3162900a9c1Sjsing 		.setup = benchmark_bn_sqr_setup,
3172900a9c1Sjsing 		.run_once = benchmark_bn_sqr_run_once,
3182900a9c1Sjsing 		.a_bits = 4096,
3192900a9c1Sjsing 	},
3202900a9c1Sjsing 	{
3212900a9c1Sjsing 		.desc = "BN_sqr (8192 bit)",
3222900a9c1Sjsing 		.setup = benchmark_bn_sqr_setup,
3232900a9c1Sjsing 		.run_once = benchmark_bn_sqr_run_once,
3242900a9c1Sjsing 		.a_bits = 8192,
3252900a9c1Sjsing 	},
3262900a9c1Sjsing };
3272900a9c1Sjsing 
3282900a9c1Sjsing #define N_BENCHMARKS (sizeof(benchmarks) / sizeof(benchmarks[0]))
3292900a9c1Sjsing 
3302900a9c1Sjsing static volatile sig_atomic_t benchmark_stop;
3312900a9c1Sjsing 
3322900a9c1Sjsing static void
benchmark_sig_alarm(int sig)3332900a9c1Sjsing benchmark_sig_alarm(int sig)
3342900a9c1Sjsing {
3352900a9c1Sjsing 	benchmark_stop = 1;
3362900a9c1Sjsing }
3372900a9c1Sjsing 
3382900a9c1Sjsing static void
benchmark_run(const struct benchmark * bm,int seconds)3392900a9c1Sjsing benchmark_run(const struct benchmark *bm, int seconds)
3402900a9c1Sjsing {
3412900a9c1Sjsing 	struct timespec start, end, duration;
3428d9f23acSjsing 	struct rusage rusage;
34372c289bdSjsing 	BIGNUM *a, *b, *r, *q;
3442900a9c1Sjsing 	BN_CTX *bn_ctx;
3452900a9c1Sjsing 	int i;
3462900a9c1Sjsing 
3472900a9c1Sjsing 	signal(SIGALRM, benchmark_sig_alarm);
3482900a9c1Sjsing 
3492900a9c1Sjsing 	if ((bn_ctx = BN_CTX_new()) == NULL)
3502900a9c1Sjsing 		errx(1, "BN_CTX_new");
3512900a9c1Sjsing 
3522900a9c1Sjsing 	BN_CTX_start(bn_ctx);
3532900a9c1Sjsing 
3542900a9c1Sjsing 	if ((a = BN_CTX_get(bn_ctx)) == NULL)
3552900a9c1Sjsing 		errx(1, "BN_CTX_get");
3562900a9c1Sjsing 	if ((b = BN_CTX_get(bn_ctx)) == NULL)
3572900a9c1Sjsing 		errx(1, "BN_CTX_get");
3582900a9c1Sjsing 	if ((r = BN_CTX_get(bn_ctx)) == NULL)
3592900a9c1Sjsing 		errx(1, "BN_CTX_get");
36072c289bdSjsing 	if ((q = BN_CTX_get(bn_ctx)) == NULL)
36172c289bdSjsing 		errx(1, "BN_CTX_get");
3622900a9c1Sjsing 
363964a7cf0Sjsing 	BN_set_flags(a, BN_FLG_CONSTTIME);
364964a7cf0Sjsing 	BN_set_flags(b, BN_FLG_CONSTTIME);
365964a7cf0Sjsing 
36672c289bdSjsing 	if (!bm->setup(a, bm->a_bits, b, bm->b_bits, r, q))
3672900a9c1Sjsing 		errx(1, "benchmark setup failed");
3682900a9c1Sjsing 
3692900a9c1Sjsing 	benchmark_stop = 0;
3702900a9c1Sjsing 	i = 0;
3712900a9c1Sjsing 	alarm(seconds);
3722900a9c1Sjsing 
3738d9f23acSjsing 	if (getrusage(RUSAGE_SELF, &rusage) == -1)
3748d9f23acSjsing 		err(1, "getrusage failed");
3758d9f23acSjsing 	TIMEVAL_TO_TIMESPEC(&rusage.ru_utime, &start);
3762900a9c1Sjsing 
3772900a9c1Sjsing 	fprintf(stderr, "Benchmarking %s for %ds: ", bm->desc, seconds);
3782900a9c1Sjsing 	while (!benchmark_stop) {
37972c289bdSjsing 		bm->run_once(r, q, a, b, bn_ctx);
3802900a9c1Sjsing 		i++;
3812900a9c1Sjsing 	}
3828d9f23acSjsing 	if (getrusage(RUSAGE_SELF, &rusage) == -1)
3838d9f23acSjsing 		err(1, "getrusage failed");
3848d9f23acSjsing 	TIMEVAL_TO_TIMESPEC(&rusage.ru_utime, &end);
3858d9f23acSjsing 
3862900a9c1Sjsing 	timespecsub(&end, &start, &duration);
3878d9f23acSjsing 	fprintf(stderr, "%d iterations in %f seconds - %llu op/s\n", i,
3888d9f23acSjsing 	    duration.tv_sec + duration.tv_nsec / 1000000000.0,
389b2cabbc1Sjsing 	    (uint64_t)i * 1000000000 /
3908d9f23acSjsing 	    (duration.tv_sec * 1000000000 + duration.tv_nsec));
3912900a9c1Sjsing 
3922900a9c1Sjsing 	BN_CTX_end(bn_ctx);
3932900a9c1Sjsing 	BN_CTX_free(bn_ctx);
3942900a9c1Sjsing }
3952900a9c1Sjsing 
3962900a9c1Sjsing static void
benchmark_bn_mul_sqr(void)3972900a9c1Sjsing benchmark_bn_mul_sqr(void)
3982900a9c1Sjsing {
3992900a9c1Sjsing 	const struct benchmark *bm;
4002900a9c1Sjsing 	size_t i;
4012900a9c1Sjsing 
4022900a9c1Sjsing 	for (i = 0; i < N_BENCHMARKS; i++) {
4032900a9c1Sjsing 		bm = &benchmarks[i];
4042900a9c1Sjsing 		benchmark_run(bm, 5);
4052900a9c1Sjsing 	}
4062900a9c1Sjsing }
4072900a9c1Sjsing 
408*d1ac4eb2Sjsing static int
test_bn_sqr(void)409*d1ac4eb2Sjsing test_bn_sqr(void)
410*d1ac4eb2Sjsing {
411*d1ac4eb2Sjsing 	BN_CTX *bn_ctx = NULL;
412*d1ac4eb2Sjsing 	BIGNUM *a, *r;
413*d1ac4eb2Sjsing 	int failed = 1;
414*d1ac4eb2Sjsing 
415*d1ac4eb2Sjsing 	if ((bn_ctx = BN_CTX_new()) == NULL)
416*d1ac4eb2Sjsing 		errx(1, "BN_CTX_new");
417*d1ac4eb2Sjsing 
418*d1ac4eb2Sjsing 	BN_CTX_start(bn_ctx);
419*d1ac4eb2Sjsing 
420*d1ac4eb2Sjsing 	if ((a = BN_CTX_get(bn_ctx)) == NULL)
421*d1ac4eb2Sjsing 		errx(1, "BN_new");
422*d1ac4eb2Sjsing 	if ((r = BN_CTX_get(bn_ctx)) == NULL)
423*d1ac4eb2Sjsing 		errx(1, "BN_new");
424*d1ac4eb2Sjsing 
425*d1ac4eb2Sjsing 	/* Square of a new BN. */
426*d1ac4eb2Sjsing 	if (!BN_sqr(r, a, bn_ctx)) {
427*d1ac4eb2Sjsing 		fprintf(stderr, "FAIL: BN_sqr() on new BN failed\n");
428*d1ac4eb2Sjsing 		goto failure;
429*d1ac4eb2Sjsing 	}
430*d1ac4eb2Sjsing 	if (!BN_is_zero(r)) {
431*d1ac4eb2Sjsing 		fprintf(stderr, "FAIL: BN_sqr() on new BN is not zero\n");
432*d1ac4eb2Sjsing 		goto failure;
433*d1ac4eb2Sjsing 	}
434*d1ac4eb2Sjsing 
435*d1ac4eb2Sjsing 	/* Square of BN that is explicitly set to zero. */
436*d1ac4eb2Sjsing 	if (!BN_set_word(a, 0)) {
437*d1ac4eb2Sjsing 		fprintf(stderr, "FAIL: BN_set_word(0) failed\n");
438*d1ac4eb2Sjsing 		goto failure;
439*d1ac4eb2Sjsing 	}
440*d1ac4eb2Sjsing 	if (!BN_sqr(r, a, bn_ctx)) {
441*d1ac4eb2Sjsing 		fprintf(stderr, "FAIL: BN_sqr(0) failed\n");
442*d1ac4eb2Sjsing 		goto failure;
443*d1ac4eb2Sjsing 	}
444*d1ac4eb2Sjsing 	if (!BN_is_zero(r)) {
445*d1ac4eb2Sjsing 		fprintf(stderr, "FAIL: BN_sqr(0) != 0\n");
446*d1ac4eb2Sjsing 		goto failure;
447*d1ac4eb2Sjsing 	}
448*d1ac4eb2Sjsing 
449*d1ac4eb2Sjsing 	/* Square of BN with value one. */
450*d1ac4eb2Sjsing 	if (!BN_set_word(a, 1)) {
451*d1ac4eb2Sjsing 		fprintf(stderr, "FAIL: BN_set_word(1) failed\n");
452*d1ac4eb2Sjsing 		goto failure;
453*d1ac4eb2Sjsing 	}
454*d1ac4eb2Sjsing 	if (!BN_sqr(r, a, bn_ctx)) {
455*d1ac4eb2Sjsing 		fprintf(stderr, "FAIL: BN_sqr(1) failed\n");
456*d1ac4eb2Sjsing 		goto failure;
457*d1ac4eb2Sjsing 	}
458*d1ac4eb2Sjsing 	if (BN_get_word(r) != 1) {
459*d1ac4eb2Sjsing 		fprintf(stderr, "FAIL: BN_sqr(1) != 1\n");
460*d1ac4eb2Sjsing 		goto failure;
461*d1ac4eb2Sjsing 	}
462*d1ac4eb2Sjsing 
463*d1ac4eb2Sjsing 	/* Square of BN with value two. */
464*d1ac4eb2Sjsing 	if (!BN_set_word(a, 2)) {
465*d1ac4eb2Sjsing 		fprintf(stderr, "FAIL: BN_set_word(2) failed\n");
466*d1ac4eb2Sjsing 		goto failure;
467*d1ac4eb2Sjsing 	}
468*d1ac4eb2Sjsing 	if (!BN_sqr(r, a, bn_ctx)) {
469*d1ac4eb2Sjsing 		fprintf(stderr, "FAIL: BN_sqr(2) failed\n");
470*d1ac4eb2Sjsing 		goto failure;
471*d1ac4eb2Sjsing 	}
472*d1ac4eb2Sjsing 	if (BN_get_word(r) != 4) {
473*d1ac4eb2Sjsing 		fprintf(stderr, "FAIL: BN_sqr(2) != 4\n");
474*d1ac4eb2Sjsing 		goto failure;
475*d1ac4eb2Sjsing 	}
476*d1ac4eb2Sjsing 
477*d1ac4eb2Sjsing 	failed = 0;
478*d1ac4eb2Sjsing 
479*d1ac4eb2Sjsing  failure:
480*d1ac4eb2Sjsing 	BN_CTX_end(bn_ctx);
481*d1ac4eb2Sjsing 	BN_CTX_free(bn_ctx);
482*d1ac4eb2Sjsing 
483*d1ac4eb2Sjsing 	return failed;
484*d1ac4eb2Sjsing }
485*d1ac4eb2Sjsing 
4862900a9c1Sjsing int
main(int argc,char ** argv)4872900a9c1Sjsing main(int argc, char **argv)
4882900a9c1Sjsing {
4892900a9c1Sjsing 	int benchmark = 0, failed = 0;
4902900a9c1Sjsing 
4912900a9c1Sjsing 	if (argc == 2 && strcmp(argv[1], "--benchmark") == 0)
4922900a9c1Sjsing 		benchmark = 1;
4932900a9c1Sjsing 
494*d1ac4eb2Sjsing 	failed |= test_bn_sqr();
495*d1ac4eb2Sjsing 
4962900a9c1Sjsing 	if (benchmark && !failed)
4972900a9c1Sjsing 		benchmark_bn_mul_sqr();
4982900a9c1Sjsing 
4992900a9c1Sjsing 	return failed;
5002900a9c1Sjsing }
501