xref: /openbsd/regress/lib/libcrypto/bn/bn_shift.c (revision b0c07ee0)
1*b0c07ee0Sjsing /*	$OpenBSD: bn_shift.c,v 1.9 2023/03/11 14:02:26 jsing Exp $ */
20b39bee8Sjsing /*
30b39bee8Sjsing  * Copyright (c) 2022 Joel Sing <jsing@openbsd.org>
40b39bee8Sjsing  *
50b39bee8Sjsing  * Permission to use, copy, modify, and distribute this software for any
60b39bee8Sjsing  * purpose with or without fee is hereby granted, provided that the above
70b39bee8Sjsing  * copyright notice and this permission notice appear in all copies.
80b39bee8Sjsing  *
90b39bee8Sjsing  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
100b39bee8Sjsing  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
110b39bee8Sjsing  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
120b39bee8Sjsing  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
130b39bee8Sjsing  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
140b39bee8Sjsing  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
150b39bee8Sjsing  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
160b39bee8Sjsing  */
170b39bee8Sjsing 
180b39bee8Sjsing #include <sys/time.h>
190b39bee8Sjsing 
200b39bee8Sjsing #include <err.h>
210b39bee8Sjsing #include <signal.h>
220b39bee8Sjsing #include <stdio.h>
230b39bee8Sjsing #include <string.h>
240b39bee8Sjsing #include <time.h>
250b39bee8Sjsing #include <unistd.h>
260b39bee8Sjsing 
270b39bee8Sjsing #include <openssl/bn.h>
280b39bee8Sjsing 
290b39bee8Sjsing static const char *bn_shift_want_hex = \
300b39bee8Sjsing     "02AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" \
310b39bee8Sjsing     "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA8";
320b39bee8Sjsing 
330b39bee8Sjsing static int
check_shift_result(BIGNUM * bn1)340b39bee8Sjsing check_shift_result(BIGNUM *bn1)
350b39bee8Sjsing {
360b39bee8Sjsing 	BIGNUM *bn2 = NULL;
370b39bee8Sjsing 	char *s = NULL;
380b39bee8Sjsing 	int ret = 0;
390b39bee8Sjsing 
400b39bee8Sjsing 	if (!BN_hex2bn(&bn2, bn_shift_want_hex)) {
410b39bee8Sjsing 		fprintf(stderr, "FAIL: BN_hex2bn() failed\n");
420b39bee8Sjsing 		goto failure;
430b39bee8Sjsing 	}
440b39bee8Sjsing 	if (BN_cmp(bn1, bn2) != 0) {
450b39bee8Sjsing 		fprintf(stderr, "FAIL: shifted result differs\n");
460b39bee8Sjsing 		if ((s = BN_bn2hex(bn1)) == NULL) {
470b39bee8Sjsing 			fprintf(stderr, "FAIL: BN_bn2hex()\n");
480b39bee8Sjsing 			goto failure;
490b39bee8Sjsing 		}
500b39bee8Sjsing 		fprintf(stderr, "Got:  %s\n", s);
510b39bee8Sjsing 		free(s);
520b39bee8Sjsing 		if ((s = BN_bn2hex(bn2)) == NULL) {
530b39bee8Sjsing 			fprintf(stderr, "FAIL: BN_bn2hex()\n");
540b39bee8Sjsing 			goto failure;
550b39bee8Sjsing 		}
560b39bee8Sjsing 		fprintf(stderr, "Want: %s\n", s);
570b39bee8Sjsing 	}
580b39bee8Sjsing 
590b39bee8Sjsing 	ret = 1;
600b39bee8Sjsing 
610b39bee8Sjsing  failure:
620b39bee8Sjsing 	BN_free(bn2);
630b39bee8Sjsing 	free(s);
640b39bee8Sjsing 
650b39bee8Sjsing 	return ret;
660b39bee8Sjsing }
670b39bee8Sjsing 
680b39bee8Sjsing static int
test_bn_shift1(void)690b39bee8Sjsing test_bn_shift1(void)
700b39bee8Sjsing {
710b39bee8Sjsing 	BIGNUM *bn1 = NULL, *bn2 = NULL;
720b39bee8Sjsing 	int i;
730b39bee8Sjsing 	int failed = 1;
740b39bee8Sjsing 
750b39bee8Sjsing 	if ((bn1 = BN_new()) == NULL) {
760b39bee8Sjsing 		fprintf(stderr, "FAIL: failed to create BN\n");
770b39bee8Sjsing 		goto failure;
780b39bee8Sjsing 	}
790b39bee8Sjsing 	if ((bn2 = BN_new()) == NULL) {
800b39bee8Sjsing 		fprintf(stderr, "FAIL: failed to create BN\n");
810b39bee8Sjsing 		goto failure;
820b39bee8Sjsing 	}
830b39bee8Sjsing 
840b39bee8Sjsing 	for (i = 1; i <= 256; i++) {
850b39bee8Sjsing 		if (!BN_set_bit(bn1, 1)) {
860b39bee8Sjsing 			fprintf(stderr, "FAIL: failed to set bit\n");
870b39bee8Sjsing 			goto failure;
880b39bee8Sjsing 		}
890b39bee8Sjsing 		if (!BN_lshift1(bn1, bn1)) {
900b39bee8Sjsing 			fprintf(stderr, "FAIL: failed to BN_lshift1()\n");
910b39bee8Sjsing 			goto failure;
920b39bee8Sjsing 		}
930b39bee8Sjsing 		if (!BN_lshift1(bn1, bn1)) {
940b39bee8Sjsing 			fprintf(stderr, "FAIL: failed to BN_lshift1()\n");
950b39bee8Sjsing 			goto failure;
960b39bee8Sjsing 		}
970b39bee8Sjsing 		if (!BN_rshift1(bn1, bn1)) {
980b39bee8Sjsing 			fprintf(stderr, "FAIL: failed to BN_rshift1()\n");
990b39bee8Sjsing 			goto failure;
1000b39bee8Sjsing 		}
1010b39bee8Sjsing 		if (!BN_lshift1(bn1, bn1)) {
1020b39bee8Sjsing 			fprintf(stderr, "FAIL: failed to BN_lshift1()\n");
1030b39bee8Sjsing 			goto failure;
1040b39bee8Sjsing 		}
1050b39bee8Sjsing 	}
1060b39bee8Sjsing 
1070b39bee8Sjsing 	if (!check_shift_result(bn1))
1080b39bee8Sjsing 		goto failure;
1090b39bee8Sjsing 
1100b39bee8Sjsing 	/*
1110b39bee8Sjsing 	 * Shift result into a different BN.
1120b39bee8Sjsing 	 */
1130b39bee8Sjsing 	if (!BN_lshift1(bn1, bn1)) {
1140b39bee8Sjsing 		fprintf(stderr, "FAIL: failed to BN_lshift1()\n");
1150b39bee8Sjsing 		goto failure;
1160b39bee8Sjsing 	}
1170b39bee8Sjsing 	if (!BN_rshift1(bn2, bn1)) {
1180b39bee8Sjsing 		fprintf(stderr, "FAIL: failed to BN_rshift1()\n");
1190b39bee8Sjsing 		goto failure;
1200b39bee8Sjsing 	}
1210b39bee8Sjsing 
1220b39bee8Sjsing 	if (!check_shift_result(bn2))
1230b39bee8Sjsing 		goto failure;
1240b39bee8Sjsing 
1250b39bee8Sjsing 	if (!BN_rshift1(bn2, bn2)) {
1260b39bee8Sjsing 		fprintf(stderr, "FAIL: failed to BN_rshift1()\n");
1270b39bee8Sjsing 		goto failure;
1280b39bee8Sjsing 	}
1290b39bee8Sjsing 	if (!BN_lshift1(bn1, bn2)) {
1300b39bee8Sjsing 		fprintf(stderr, "FAIL: failed to BN_lshift1()\n");
1310b39bee8Sjsing 		goto failure;
1320b39bee8Sjsing 	}
1330b39bee8Sjsing 
1340b39bee8Sjsing 	if (!check_shift_result(bn1))
1350b39bee8Sjsing 		goto failure;
1360b39bee8Sjsing 
1370b39bee8Sjsing 	failed = 0;
1380b39bee8Sjsing 
1390b39bee8Sjsing  failure:
1400b39bee8Sjsing 	BN_free(bn1);
1410b39bee8Sjsing 	BN_free(bn2);
1420b39bee8Sjsing 
1430b39bee8Sjsing 	return failed;
1440b39bee8Sjsing }
1450b39bee8Sjsing 
1460b39bee8Sjsing static int
test_bn_shift(void)1470b39bee8Sjsing test_bn_shift(void)
1480b39bee8Sjsing {
1490b39bee8Sjsing 	BIGNUM *bn1 = NULL, *bn2 = NULL;
1500b39bee8Sjsing 	int i;
1510b39bee8Sjsing 	int failed = 1;
1520b39bee8Sjsing 
1530b39bee8Sjsing 	if ((bn1 = BN_new()) == NULL) {
1540b39bee8Sjsing 		fprintf(stderr, "FAIL: failed to create BN 1\n");
1550b39bee8Sjsing 		goto failure;
1560b39bee8Sjsing 	}
1570b39bee8Sjsing 	if ((bn2 = BN_new()) == NULL) {
1580b39bee8Sjsing 		fprintf(stderr, "FAIL: failed to create BN 2\n");
1590b39bee8Sjsing 		goto failure;
1600b39bee8Sjsing 	}
1610b39bee8Sjsing 
1620b39bee8Sjsing 	for (i = 1; i <= 256; i++) {
1630b39bee8Sjsing 		if (!BN_set_bit(bn1, 1)) {
1640b39bee8Sjsing 			fprintf(stderr, "FAIL: failed to set bit\n");
1650b39bee8Sjsing 			goto failure;
1660b39bee8Sjsing 		}
1670b39bee8Sjsing 		if (!BN_lshift(bn1, bn1, i + 1)) {
1680b39bee8Sjsing 			fprintf(stderr, "FAIL: failed to BN_lshift()\n");
1690b39bee8Sjsing 			goto failure;
1700b39bee8Sjsing 		}
1710b39bee8Sjsing 		if (!BN_rshift(bn1, bn1, i - 1)) {
1720b39bee8Sjsing 			fprintf(stderr, "FAIL: failed to BN_rshift()\n");
1730b39bee8Sjsing 			goto failure;
1740b39bee8Sjsing 		}
1750b39bee8Sjsing 	}
1760b39bee8Sjsing 
1770b39bee8Sjsing 	if (!check_shift_result(bn1))
1780b39bee8Sjsing 		goto failure;
1790b39bee8Sjsing 
1800b39bee8Sjsing 	for (i = 0; i <= 256; i++) {
1810b39bee8Sjsing 		if (!BN_lshift(bn1, bn1, i)) {
1820b39bee8Sjsing 			fprintf(stderr, "FAIL: failed to BN_lshift()\n");
1830b39bee8Sjsing 			goto failure;
1840b39bee8Sjsing 		}
1850b39bee8Sjsing 		if (i > 1) {
1860b39bee8Sjsing 			if (!BN_set_bit(bn1, 1)) {
1870b39bee8Sjsing 				fprintf(stderr, "FAIL: failed to set bit\n");
1880b39bee8Sjsing 				goto failure;
1890b39bee8Sjsing 			}
1900b39bee8Sjsing 		}
1910b39bee8Sjsing 	}
1920b39bee8Sjsing 
1930b39bee8Sjsing 	if (BN_num_bytes(bn1) != 4177) {
1940b39bee8Sjsing 		fprintf(stderr, "FAIL: BN has %d bytes, want 4177\n",
1950b39bee8Sjsing 		    BN_num_bytes(bn1));
1960b39bee8Sjsing 		goto failure;
1970b39bee8Sjsing 	}
1980b39bee8Sjsing 
1990b39bee8Sjsing 	for (i = 0; i <= 256; i++) {
2000b39bee8Sjsing 		if (!BN_rshift(bn1, bn1, i)) {
2010b39bee8Sjsing 			fprintf(stderr, "FAIL: failed to BN_rshift()\n");
2020b39bee8Sjsing 			goto failure;
2030b39bee8Sjsing 		}
2040b39bee8Sjsing 	}
2050b39bee8Sjsing 
2060b39bee8Sjsing 	if (!check_shift_result(bn1))
2070b39bee8Sjsing 		goto failure;
2080b39bee8Sjsing 
2090b39bee8Sjsing 	/*
2100b39bee8Sjsing 	 * Shift result into a different BN.
2110b39bee8Sjsing 	 */
2120b39bee8Sjsing 	if (!BN_lshift(bn1, bn1, BN_BITS2 + 1)) {
2130b39bee8Sjsing 		fprintf(stderr, "FAIL: failed to BN_lshift()\n");
2140b39bee8Sjsing 		goto failure;
2150b39bee8Sjsing 	}
2160b39bee8Sjsing 	if (!BN_rshift(bn2, bn1, BN_BITS2 + 1)) {
2170b39bee8Sjsing 		fprintf(stderr, "FAIL: failed to BN_rshift()\n");
2180b39bee8Sjsing 		goto failure;
2190b39bee8Sjsing 	}
2200b39bee8Sjsing 
2210b39bee8Sjsing 	if (!check_shift_result(bn2))
2220b39bee8Sjsing 		goto failure;
2230b39bee8Sjsing 
2240b39bee8Sjsing 	if (!BN_rshift(bn2, bn2, 3)) {
2250b39bee8Sjsing 		fprintf(stderr, "FAIL: failed to BN_rshift()\n");
2260b39bee8Sjsing 		goto failure;
2270b39bee8Sjsing 	}
2280b39bee8Sjsing 	if (!BN_lshift(bn1, bn2, 3)) {
2290b39bee8Sjsing 		fprintf(stderr, "FAIL: failed to BN_lshift()\n");
2300b39bee8Sjsing 		goto failure;
2310b39bee8Sjsing 	}
2320b39bee8Sjsing 
2330b39bee8Sjsing 	if (!check_shift_result(bn1))
2340b39bee8Sjsing 		goto failure;
2350b39bee8Sjsing 
2360c6046f5Sjsing 	/*
2370c6046f5Sjsing 	 * Shift of zero (equivalent to a copy).
2380c6046f5Sjsing 	 */
2390c6046f5Sjsing 	BN_zero(bn2);
2400c6046f5Sjsing 	if (!BN_lshift(bn2, bn1, 0)) {
2410c6046f5Sjsing 		fprintf(stderr, "FAIL: failed to BN_lshift()\n");
2420c6046f5Sjsing 		goto failure;
2430c6046f5Sjsing 	}
2440c6046f5Sjsing 
2450c6046f5Sjsing 	if (!check_shift_result(bn2))
2460c6046f5Sjsing 		goto failure;
2470c6046f5Sjsing 
2480c6046f5Sjsing 	if (!BN_lshift(bn2, bn2, 0)) {
2490c6046f5Sjsing 		fprintf(stderr, "FAIL: failed to BN_lshift()\n");
2500c6046f5Sjsing 		goto failure;
2510c6046f5Sjsing 	}
2520c6046f5Sjsing 
2530c6046f5Sjsing 	if (!check_shift_result(bn2))
2540c6046f5Sjsing 		goto failure;
2550c6046f5Sjsing 
2560c6046f5Sjsing 	BN_zero(bn2);
2570c6046f5Sjsing 	if (!BN_rshift(bn2, bn1, 0)) {
2580c6046f5Sjsing 		fprintf(stderr, "FAIL: failed to BN_rshift()\n");
2590c6046f5Sjsing 		goto failure;
2600c6046f5Sjsing 	}
2610c6046f5Sjsing 
2620c6046f5Sjsing 	if (!check_shift_result(bn2))
2630c6046f5Sjsing 		goto failure;
2640c6046f5Sjsing 
2650c6046f5Sjsing 	if (!BN_rshift(bn2, bn2, 0)) {
2660c6046f5Sjsing 		fprintf(stderr, "FAIL: failed to BN_rshift()\n");
2670c6046f5Sjsing 		goto failure;
2680c6046f5Sjsing 	}
2690c6046f5Sjsing 
2700c6046f5Sjsing 	if (!check_shift_result(bn2))
2710c6046f5Sjsing 		goto failure;
2720c6046f5Sjsing 
2730b39bee8Sjsing 	failed = 0;
2740b39bee8Sjsing 
2750b39bee8Sjsing  failure:
2760b39bee8Sjsing 	BN_free(bn1);
2770b39bee8Sjsing 	BN_free(bn2);
2780b39bee8Sjsing 
2790b39bee8Sjsing 	return failed;
2800b39bee8Sjsing }
2810b39bee8Sjsing 
2820b39bee8Sjsing static int
test_bn_rshift_to_zero(void)2830b39bee8Sjsing test_bn_rshift_to_zero(void)
2840b39bee8Sjsing {
2850b39bee8Sjsing 	BIGNUM *bn1 = NULL, *bn2 = NULL;
2860b39bee8Sjsing 	int failed = 1;
2870b39bee8Sjsing 
2880b39bee8Sjsing 	if (!BN_hex2bn(&bn1, "ffff")) {
2890b39bee8Sjsing 		fprintf(stderr, "FAIL: BN_hex2bn() failed\n");
2900b39bee8Sjsing 		goto failure;
2910b39bee8Sjsing 	}
2920b39bee8Sjsing 	if (!BN_lshift(bn1, bn1, BN_BITS2)) {
2930b39bee8Sjsing 		fprintf(stderr, "FAIL: BN_lshift() failed\n");
2940b39bee8Sjsing 		goto failure;
2950b39bee8Sjsing 	}
2960b39bee8Sjsing 
2970b39bee8Sjsing 	if ((bn2 = BN_new()) == NULL) {
2980b39bee8Sjsing 		fprintf(stderr, "FAIL: BN_new() failed\n");
2990b39bee8Sjsing 		goto failure;
3000b39bee8Sjsing 	}
3010b39bee8Sjsing 
3020b39bee8Sjsing 	/* Shift all words. */
3030b39bee8Sjsing 	if (!BN_rshift(bn2, bn1, BN_BITS2 * 2)) {
3040b39bee8Sjsing 		fprintf(stderr, "FAIL: BN_rshift() failed\n");
3050b39bee8Sjsing 		goto failure;
3060b39bee8Sjsing 	}
3070b39bee8Sjsing 	if (BN_is_zero(bn1)) {
3080b39bee8Sjsing 		fprintf(stderr, "FAIL: BN is zero\n");
3090b39bee8Sjsing 		goto failure;
3100b39bee8Sjsing 	}
3110b39bee8Sjsing 	if (!BN_is_zero(bn2)) {
3120b39bee8Sjsing 		fprintf(stderr, "FAIL: BN is not zero\n");
3130b39bee8Sjsing 		goto failure;
3140b39bee8Sjsing 	}
3150b39bee8Sjsing 
3160b39bee8Sjsing 	/* Shift to zero, with partial shift for top most word. */
3170b39bee8Sjsing 	if (!BN_rshift(bn2, bn1, BN_BITS2 + 16)) {
3180b39bee8Sjsing 		fprintf(stderr, "FAIL: BN_rshift() failed\n");
3190b39bee8Sjsing 		goto failure;
3200b39bee8Sjsing 	}
3210b39bee8Sjsing 	if (BN_is_zero(bn1)) {
3220b39bee8Sjsing 		fprintf(stderr, "FAIL: BN is zero\n");
3230b39bee8Sjsing 		goto failure;
3240b39bee8Sjsing 	}
3250b39bee8Sjsing 	if (!BN_is_zero(bn2)) {
3260b39bee8Sjsing 		fprintf(stderr, "FAIL: BN is not zero\n");
3270b39bee8Sjsing 		goto failure;
3280b39bee8Sjsing 	}
3290b39bee8Sjsing 
3300b39bee8Sjsing 	/* Shift to zero of negative value. */
3310b39bee8Sjsing 	if (!BN_one(bn1)) {
3320b39bee8Sjsing 		fprintf(stderr, "FAIL: BN_one() failed\n");
3330b39bee8Sjsing 		goto failure;
3340b39bee8Sjsing 	}
3350b39bee8Sjsing 	BN_set_negative(bn1, 1);
3360b39bee8Sjsing 	if (!BN_rshift(bn1, bn1, 1)) {
3370b39bee8Sjsing 		fprintf(stderr, "FAIL: BN_rshift() failed\n");
3380b39bee8Sjsing 		goto failure;
3390b39bee8Sjsing 	}
3400b39bee8Sjsing 	if (!BN_is_zero(bn1)) {
3410b39bee8Sjsing 		fprintf(stderr, "FAIL: BN is not zero\n");
3420b39bee8Sjsing 		goto failure;
3430b39bee8Sjsing 	}
3443fa2f542Sjsing 	if (BN_is_negative(bn1)) {
3453fa2f542Sjsing 		fprintf(stderr, "FAIL: BN is negative zero\n");
3463fa2f542Sjsing 		goto failure;
3473fa2f542Sjsing 	}
3480b39bee8Sjsing 
3490b39bee8Sjsing 	failed = 0;
3500b39bee8Sjsing 
3510b39bee8Sjsing  failure:
3520b39bee8Sjsing 	BN_free(bn1);
3530b39bee8Sjsing 	BN_free(bn2);
3540b39bee8Sjsing 
3550b39bee8Sjsing 	return failed;
3560b39bee8Sjsing }
3570b39bee8Sjsing 
3580b39bee8Sjsing static void
benchmark_bn_lshift1(BIGNUM * bn)3590b39bee8Sjsing benchmark_bn_lshift1(BIGNUM *bn)
3600b39bee8Sjsing {
3610b39bee8Sjsing 	int i;
3620b39bee8Sjsing 
36362cf9064Sjsing 	if (!BN_set_bit(bn, 8192))
36462cf9064Sjsing 		errx(1, "BN_set_bit");
36562cf9064Sjsing 
3660b39bee8Sjsing 	if (!BN_one(bn))
3670b39bee8Sjsing 		errx(1, "BN_one");
3680b39bee8Sjsing 
3690b39bee8Sjsing 	for (i = 0; i < 8192; i++) {
3700b39bee8Sjsing 		if (!BN_lshift1(bn, bn))
3710b39bee8Sjsing 			errx(1, "BN_lshift1");
3720b39bee8Sjsing 	}
3730b39bee8Sjsing }
3740b39bee8Sjsing 
3750b39bee8Sjsing static void
benchmark_bn_lshift(BIGNUM * bn,int n)3760b39bee8Sjsing benchmark_bn_lshift(BIGNUM *bn, int n)
3770b39bee8Sjsing {
3780b39bee8Sjsing 	int i;
3790b39bee8Sjsing 
38062cf9064Sjsing 	if (!BN_set_bit(bn, 8192 * n))
38162cf9064Sjsing 		errx(1, "BN_set_bit");
38262cf9064Sjsing 
3830b39bee8Sjsing 	if (!BN_one(bn))
3840b39bee8Sjsing 		errx(1, "BN_one");
3850b39bee8Sjsing 
3860b39bee8Sjsing 	for (i = 0; i < 8192; i++) {
3870b39bee8Sjsing 		if (!BN_lshift(bn, bn, n))
3880b39bee8Sjsing 			errx(1, "BN_lshift");
3890b39bee8Sjsing 	}
3900b39bee8Sjsing }
3910b39bee8Sjsing 
3920b39bee8Sjsing static void
benchmark_bn_lshift_1(BIGNUM * bn)3930b39bee8Sjsing benchmark_bn_lshift_1(BIGNUM *bn)
3940b39bee8Sjsing {
3950b39bee8Sjsing 	benchmark_bn_lshift(bn, 1);
3960b39bee8Sjsing }
3970b39bee8Sjsing 
3980b39bee8Sjsing static void
benchmark_bn_lshift_16(BIGNUM * bn)399756fa007Sjsing benchmark_bn_lshift_16(BIGNUM *bn)
400756fa007Sjsing {
401756fa007Sjsing 	benchmark_bn_lshift(bn, 16);
402756fa007Sjsing }
403756fa007Sjsing 
404756fa007Sjsing static void
benchmark_bn_lshift_32(BIGNUM * bn)4050b39bee8Sjsing benchmark_bn_lshift_32(BIGNUM *bn)
4060b39bee8Sjsing {
4070b39bee8Sjsing 	benchmark_bn_lshift(bn, 32);
4080b39bee8Sjsing }
4090b39bee8Sjsing 
4100b39bee8Sjsing static void
benchmark_bn_lshift_64(BIGNUM * bn)4110b39bee8Sjsing benchmark_bn_lshift_64(BIGNUM *bn)
4120b39bee8Sjsing {
4130b39bee8Sjsing 	benchmark_bn_lshift(bn, 64);
4140b39bee8Sjsing }
4150b39bee8Sjsing 
4160b39bee8Sjsing static void
benchmark_bn_lshift_65(BIGNUM * bn)417756fa007Sjsing benchmark_bn_lshift_65(BIGNUM *bn)
418756fa007Sjsing {
419756fa007Sjsing 	benchmark_bn_lshift(bn, 65);
420756fa007Sjsing }
421756fa007Sjsing 
422756fa007Sjsing static void
benchmark_bn_lshift_80(BIGNUM * bn)423756fa007Sjsing benchmark_bn_lshift_80(BIGNUM *bn)
424756fa007Sjsing {
425756fa007Sjsing 	benchmark_bn_lshift(bn, 80);
426756fa007Sjsing }
427756fa007Sjsing 
428756fa007Sjsing static void
benchmark_bn_lshift_127(BIGNUM * bn)4290b39bee8Sjsing benchmark_bn_lshift_127(BIGNUM *bn)
4300b39bee8Sjsing {
4310b39bee8Sjsing 	benchmark_bn_lshift(bn, 127);
4320b39bee8Sjsing }
4330b39bee8Sjsing 
4340b39bee8Sjsing static void
benchmark_bn_rshift1(BIGNUM * bn)4350b39bee8Sjsing benchmark_bn_rshift1(BIGNUM *bn)
4360b39bee8Sjsing {
4370b39bee8Sjsing 	int i;
4380b39bee8Sjsing 
43962cf9064Sjsing 	if (!BN_one(bn))
44062cf9064Sjsing 		errx(1, "BN_one");
44162cf9064Sjsing 
4420b39bee8Sjsing 	if (!BN_set_bit(bn, 8192))
4430b39bee8Sjsing 		errx(1, "BN_set_bit");
4440b39bee8Sjsing 
4450b39bee8Sjsing 	for (i = 0; i < 8192; i++) {
4460b39bee8Sjsing 		if (!BN_rshift1(bn, bn))
4470b39bee8Sjsing 			errx(1, "BN_rshift1");
4480b39bee8Sjsing 	}
4490b39bee8Sjsing }
4500b39bee8Sjsing 
4510b39bee8Sjsing static void
benchmark_bn_rshift(BIGNUM * bn,int n)4520b39bee8Sjsing benchmark_bn_rshift(BIGNUM *bn, int n)
4530b39bee8Sjsing {
4540b39bee8Sjsing 	int i;
4550b39bee8Sjsing 
45662cf9064Sjsing 	if (!BN_one(bn))
45762cf9064Sjsing 		errx(1, "BN_one");
45862cf9064Sjsing 
4590b39bee8Sjsing 	if (!BN_set_bit(bn, 8192 * n))
4600b39bee8Sjsing 		errx(1, "BN_set_bit");
4610b39bee8Sjsing 
4620b39bee8Sjsing 	for (i = 0; i < 8192; i++) {
4630b39bee8Sjsing 		if (!BN_rshift(bn, bn, n))
4640b39bee8Sjsing 			errx(1, "BN_rshift");
4650b39bee8Sjsing 	}
4660b39bee8Sjsing }
4670b39bee8Sjsing 
4680b39bee8Sjsing static void
benchmark_bn_rshift_1(BIGNUM * bn)4690b39bee8Sjsing benchmark_bn_rshift_1(BIGNUM *bn)
4700b39bee8Sjsing {
4710b39bee8Sjsing 	benchmark_bn_rshift(bn, 1);
4720b39bee8Sjsing }
4730b39bee8Sjsing 
4740b39bee8Sjsing static void
benchmark_bn_rshift_16(BIGNUM * bn)475e204e7afSjsing benchmark_bn_rshift_16(BIGNUM *bn)
476e204e7afSjsing {
477e204e7afSjsing 	benchmark_bn_rshift(bn, 16);
478e204e7afSjsing }
479e204e7afSjsing 
480e204e7afSjsing static void
benchmark_bn_rshift_32(BIGNUM * bn)4810b39bee8Sjsing benchmark_bn_rshift_32(BIGNUM *bn)
4820b39bee8Sjsing {
4830b39bee8Sjsing 	benchmark_bn_rshift(bn, 32);
4840b39bee8Sjsing }
4850b39bee8Sjsing 
4860b39bee8Sjsing static void
benchmark_bn_rshift_64(BIGNUM * bn)4870b39bee8Sjsing benchmark_bn_rshift_64(BIGNUM *bn)
4880b39bee8Sjsing {
4890b39bee8Sjsing 	benchmark_bn_rshift(bn, 64);
4900b39bee8Sjsing }
4910b39bee8Sjsing 
4920b39bee8Sjsing static void
benchmark_bn_rshift_65(BIGNUM * bn)493756fa007Sjsing benchmark_bn_rshift_65(BIGNUM *bn)
494756fa007Sjsing {
495756fa007Sjsing 	benchmark_bn_rshift(bn, 65);
496756fa007Sjsing }
497756fa007Sjsing 
498756fa007Sjsing static void
benchmark_bn_rshift_80(BIGNUM * bn)499756fa007Sjsing benchmark_bn_rshift_80(BIGNUM *bn)
500756fa007Sjsing {
501756fa007Sjsing 	benchmark_bn_rshift(bn, 80);
502756fa007Sjsing }
503756fa007Sjsing 
504756fa007Sjsing static void
benchmark_bn_rshift_127(BIGNUM * bn)5050b39bee8Sjsing benchmark_bn_rshift_127(BIGNUM *bn)
5060b39bee8Sjsing {
5070b39bee8Sjsing 	benchmark_bn_rshift(bn, 127);
5080b39bee8Sjsing }
5090b39bee8Sjsing 
5100b39bee8Sjsing struct benchmark {
5110b39bee8Sjsing 	const char *desc;
5120b39bee8Sjsing 	void (*func)(BIGNUM *);
5130b39bee8Sjsing };
5140b39bee8Sjsing 
515*b0c07ee0Sjsing static const struct benchmark benchmarks[] = {
5160b39bee8Sjsing 	{
5170b39bee8Sjsing 		.desc = "BN_lshift1()",
5180b39bee8Sjsing 		.func = benchmark_bn_lshift1,
5190b39bee8Sjsing 	},
5200b39bee8Sjsing 	{
5210b39bee8Sjsing 		.desc = "BN_lshift(_, _, 1)",
5220b39bee8Sjsing 		.func = benchmark_bn_lshift_1,
5230b39bee8Sjsing 	},
5240b39bee8Sjsing 	{
525756fa007Sjsing 		.desc = "BN_lshift(_, _, 16)",
526756fa007Sjsing 		.func = benchmark_bn_lshift_16,
527756fa007Sjsing 	},
528756fa007Sjsing 	{
5290b39bee8Sjsing 		.desc = "BN_lshift(_, _, 32)",
5300b39bee8Sjsing 		.func = benchmark_bn_lshift_32,
5310b39bee8Sjsing 	},
5320b39bee8Sjsing 	{
5330b39bee8Sjsing 		.desc = "BN_lshift(_, _, 64)",
5340b39bee8Sjsing 		.func = benchmark_bn_lshift_64,
5350b39bee8Sjsing 	},
5360b39bee8Sjsing 	{
537756fa007Sjsing 		.desc = "BN_lshift(_, _, 65)",
538756fa007Sjsing 		.func = benchmark_bn_lshift_65,
539756fa007Sjsing 	},
540756fa007Sjsing 	{
541756fa007Sjsing 		.desc = "BN_lshift(_, _, 80)",
542756fa007Sjsing 		.func = benchmark_bn_lshift_80,
543756fa007Sjsing 	},
544756fa007Sjsing 	{
5450b39bee8Sjsing 		.desc = "BN_lshift(_, _, 127)",
5460b39bee8Sjsing 		.func = benchmark_bn_lshift_127,
5470b39bee8Sjsing 	},
5480b39bee8Sjsing 	{
5490b39bee8Sjsing 		.desc = "BN_rshift1()",
5500b39bee8Sjsing 		.func = benchmark_bn_rshift1,
5510b39bee8Sjsing 	},
5520b39bee8Sjsing 	{
5530b39bee8Sjsing 		.desc = "BN_rshift(_, _, 1)",
5540b39bee8Sjsing 		.func = benchmark_bn_rshift_1,
5550b39bee8Sjsing 	},
5560b39bee8Sjsing 	{
557756fa007Sjsing 		.desc = "BN_rshift(_, _, 16)",
558e204e7afSjsing 		.func = benchmark_bn_rshift_16,
559756fa007Sjsing 	},
560756fa007Sjsing 	{
561e204e7afSjsing 		.desc = "BN_rshift(_, _, 32)",
5620b39bee8Sjsing 		.func = benchmark_bn_rshift_32,
5630b39bee8Sjsing 	},
5640b39bee8Sjsing 	{
5650b39bee8Sjsing 		.desc = "BN_rshift(_, _, 64)",
5660b39bee8Sjsing 		.func = benchmark_bn_rshift_64,
5670b39bee8Sjsing 	},
5680b39bee8Sjsing 	{
569756fa007Sjsing 		.desc = "BN_rshift(_, _, 65)",
570756fa007Sjsing 		.func = benchmark_bn_rshift_65,
571756fa007Sjsing 	},
572756fa007Sjsing 	{
573756fa007Sjsing 		.desc = "BN_rshift(_, _, 80)",
574756fa007Sjsing 		.func = benchmark_bn_rshift_80,
575756fa007Sjsing 	},
576756fa007Sjsing 	{
5770b39bee8Sjsing 		.desc = "BN_rshift(_, _, 127)",
5780b39bee8Sjsing 		.func = benchmark_bn_rshift_127,
5790b39bee8Sjsing 	},
5800b39bee8Sjsing };
5810b39bee8Sjsing 
5820b39bee8Sjsing #define N_BENCHMARKS (sizeof(benchmarks) / sizeof(benchmarks[0]))
5830b39bee8Sjsing 
58455d8058fStb static volatile sig_atomic_t benchmark_stop;
5850b39bee8Sjsing 
5860b39bee8Sjsing static void
benchmark_sig_alarm(int sig)5870b39bee8Sjsing benchmark_sig_alarm(int sig)
5880b39bee8Sjsing {
5890b39bee8Sjsing 	benchmark_stop = 1;
5900b39bee8Sjsing }
5910b39bee8Sjsing 
5920b39bee8Sjsing static void
benchmark_run(const struct benchmark * bm,int seconds)5930b39bee8Sjsing benchmark_run(const struct benchmark *bm, int seconds)
5940b39bee8Sjsing {
5950b39bee8Sjsing 	struct timespec start, end, duration;
5960b39bee8Sjsing 	BIGNUM *bn;
5970b39bee8Sjsing 	int i;
5980b39bee8Sjsing 
5990b39bee8Sjsing 	signal(SIGALRM, benchmark_sig_alarm);
6000b39bee8Sjsing 
6010b39bee8Sjsing 	if ((bn = BN_new()) == NULL)
6020b39bee8Sjsing 		errx(1, "BN_new");
6030b39bee8Sjsing 
6040b39bee8Sjsing 	benchmark_stop = 0;
6050b39bee8Sjsing 	i = 0;
6060b39bee8Sjsing 	alarm(seconds);
6070b39bee8Sjsing 
6080b39bee8Sjsing 	clock_gettime(CLOCK_MONOTONIC, &start);
6090b39bee8Sjsing 
6100b39bee8Sjsing 	fprintf(stderr, "Benchmarking %s for %ds: ", bm->desc, seconds);
6110b39bee8Sjsing 	while (!benchmark_stop) {
6120b39bee8Sjsing 		bm->func(bn);
6130b39bee8Sjsing 		i++;
6140b39bee8Sjsing 	}
6150b39bee8Sjsing 	clock_gettime(CLOCK_MONOTONIC, &end);
6160b39bee8Sjsing 	timespecsub(&end, &start, &duration);
6170b39bee8Sjsing 	fprintf(stderr, "%d iterations in %f seconds\n", i,
6180b39bee8Sjsing 	    duration.tv_sec + duration.tv_nsec / 1000000000.0);
6190b39bee8Sjsing 
6200b39bee8Sjsing 	BN_free(bn);
6210b39bee8Sjsing }
6220b39bee8Sjsing 
6230b39bee8Sjsing static void
benchmark_bn_shift(void)6240b39bee8Sjsing benchmark_bn_shift(void)
6250b39bee8Sjsing {
6260b39bee8Sjsing 	const struct benchmark *bm;
6270b39bee8Sjsing 	size_t i;
6280b39bee8Sjsing 
6290b39bee8Sjsing 	for (i = 0; i < N_BENCHMARKS; i++) {
6300b39bee8Sjsing 		bm = &benchmarks[i];
6310b39bee8Sjsing 		benchmark_run(bm, 5);
6320b39bee8Sjsing 	}
6330b39bee8Sjsing }
6340b39bee8Sjsing 
6350b39bee8Sjsing int
main(int argc,char ** argv)6360b39bee8Sjsing main(int argc, char **argv)
6370b39bee8Sjsing {
6380b39bee8Sjsing 	int benchmark = 0, failed = 0;
6390b39bee8Sjsing 
6400b39bee8Sjsing 	if (argc == 2 && strcmp(argv[1], "--benchmark") == 0)
6410b39bee8Sjsing 		benchmark = 1;
6420b39bee8Sjsing 
6430b39bee8Sjsing 	failed |= test_bn_shift1();
6440b39bee8Sjsing 	failed |= test_bn_shift();
6450b39bee8Sjsing 	failed |= test_bn_rshift_to_zero();
6460b39bee8Sjsing 
6470b39bee8Sjsing 	if (benchmark && !failed)
6480b39bee8Sjsing 		benchmark_bn_shift();
6490b39bee8Sjsing 
6500b39bee8Sjsing 	return failed;
6510b39bee8Sjsing }
652