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