xref: /openbsd-src/regress/lib/libcrypto/bn/bn_bits.c (revision c199f4b2ed818cc4e8ea37ab132b87789ae29a21)
1*c199f4b2Sjsing /*	$OpenBSD: bn_bits.c,v 1.2 2024/04/15 14:36:16 jsing Exp $ */
283d1dbd8Sjsing /*
383d1dbd8Sjsing  * Copyright (c) 2024 Joel Sing <jsing@openbsd.org>
483d1dbd8Sjsing  *
583d1dbd8Sjsing  * Permission to use, copy, modify, and distribute this software for any
683d1dbd8Sjsing  * purpose with or without fee is hereby granted, provided that the above
783d1dbd8Sjsing  * copyright notice and this permission notice appear in all copies.
883d1dbd8Sjsing  *
983d1dbd8Sjsing  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
1083d1dbd8Sjsing  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
1183d1dbd8Sjsing  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
1283d1dbd8Sjsing  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
1383d1dbd8Sjsing  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
1483d1dbd8Sjsing  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
1583d1dbd8Sjsing  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
1683d1dbd8Sjsing  */
1783d1dbd8Sjsing 
1883d1dbd8Sjsing #include <stdio.h>
1983d1dbd8Sjsing #include <string.h>
2083d1dbd8Sjsing 
2183d1dbd8Sjsing #include <openssl/bn.h>
2283d1dbd8Sjsing 
2383d1dbd8Sjsing static int
test_bn_set_bit(void)2483d1dbd8Sjsing test_bn_set_bit(void)
2583d1dbd8Sjsing {
2683d1dbd8Sjsing 	BIGNUM *bn = NULL;
2783d1dbd8Sjsing 	char *out_str = NULL;
2883d1dbd8Sjsing 	size_t i;
2983d1dbd8Sjsing 	int failed = 1;
3083d1dbd8Sjsing 
3183d1dbd8Sjsing 	if ((bn = BN_new()) == NULL)
3283d1dbd8Sjsing 		goto failure;
3383d1dbd8Sjsing 
3483d1dbd8Sjsing 	for (i = 0; i < 128; i++) {
3583d1dbd8Sjsing 		if (i % 2 == 0) {
3683d1dbd8Sjsing 			if (!BN_set_bit(bn, i)) {
3783d1dbd8Sjsing 				fprintf(stderr, "FAIL: failed to set bit\n");
3883d1dbd8Sjsing 				goto failure;
3983d1dbd8Sjsing 			}
4083d1dbd8Sjsing 		}
4183d1dbd8Sjsing 		if (BN_is_bit_set(bn, i) != (i % 2 == 0)) {
4283d1dbd8Sjsing 			fprintf(stderr, "FAIL: BN_is_bit_set() = %d, want %d\n",
4383d1dbd8Sjsing 			    BN_is_bit_set(bn, i), (i % 2 == 0));
4483d1dbd8Sjsing 			goto failure;
4583d1dbd8Sjsing 		}
4683d1dbd8Sjsing 	}
4783d1dbd8Sjsing 
4883d1dbd8Sjsing 	if ((out_str = BN_bn2hex(bn)) == NULL)
4983d1dbd8Sjsing 		goto failure;
5083d1dbd8Sjsing 	if (strcmp(out_str, "55555555555555555555555555555555") != 0) {
5183d1dbd8Sjsing 		fprintf(stderr, "FAIL: got 0x%s, want 0x%s\n", out_str,
5283d1dbd8Sjsing 		    "55555555555555555555555555555555");
5383d1dbd8Sjsing 		goto failure;
5483d1dbd8Sjsing 	}
5583d1dbd8Sjsing 
5683d1dbd8Sjsing 	failed = 0;
5783d1dbd8Sjsing 
5883d1dbd8Sjsing  failure:
5983d1dbd8Sjsing 	BN_free(bn);
6083d1dbd8Sjsing 	free(out_str);
6183d1dbd8Sjsing 
6283d1dbd8Sjsing 	return failed;
6383d1dbd8Sjsing }
6483d1dbd8Sjsing 
6583d1dbd8Sjsing static int
test_bn_clear_bit(void)6683d1dbd8Sjsing test_bn_clear_bit(void)
6783d1dbd8Sjsing {
6883d1dbd8Sjsing 	BIGNUM *bn = NULL;
6983d1dbd8Sjsing 	char *out_str = NULL;
7083d1dbd8Sjsing 	size_t i;
7183d1dbd8Sjsing 	int failed = 1;
7283d1dbd8Sjsing 
7383d1dbd8Sjsing 	if ((bn = BN_new()) == NULL)
7483d1dbd8Sjsing 		goto failure;
7583d1dbd8Sjsing 
7683d1dbd8Sjsing 	for (i = 0; i < 128; i++) {
7783d1dbd8Sjsing 		if (!BN_set_bit(bn, i)) {
7883d1dbd8Sjsing 			fprintf(stderr, "FAIL: failed to set bit\n");
7983d1dbd8Sjsing 			goto failure;
8083d1dbd8Sjsing 		}
8183d1dbd8Sjsing 		if (i % 2 == 0) {
8283d1dbd8Sjsing 			if (!BN_clear_bit(bn, i)) {
8383d1dbd8Sjsing 				fprintf(stderr, "FAIL: failed to clear bit\n");
8483d1dbd8Sjsing 				goto failure;
8583d1dbd8Sjsing 			}
8683d1dbd8Sjsing 		}
8783d1dbd8Sjsing 		if (BN_is_bit_set(bn, i) != (i % 2 == 1)) {
8883d1dbd8Sjsing 			fprintf(stderr, "FAIL: BN_is_bit_set() = %d, want %d\n",
8983d1dbd8Sjsing 			    BN_is_bit_set(bn, i), (i % 2 == 1));
9083d1dbd8Sjsing 			goto failure;
9183d1dbd8Sjsing 		}
9283d1dbd8Sjsing 	}
9383d1dbd8Sjsing 
9483d1dbd8Sjsing 	if ((out_str = BN_bn2hex(bn)) == NULL)
9583d1dbd8Sjsing 		goto failure;
9683d1dbd8Sjsing 	if (strcmp(out_str, "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA") != 0) {
9783d1dbd8Sjsing 		fprintf(stderr, "FAIL: got 0x%s, want 0x%s\n", out_str,
9883d1dbd8Sjsing 		    "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA");
9983d1dbd8Sjsing 		goto failure;
10083d1dbd8Sjsing 	}
10183d1dbd8Sjsing 
10283d1dbd8Sjsing 	/* Ensure that clearing results in non-negative zero. */
10383d1dbd8Sjsing 	if (!BN_one(bn))
10483d1dbd8Sjsing 		goto failure;
10583d1dbd8Sjsing 	BN_set_negative(bn, 1);
10683d1dbd8Sjsing 	if (!BN_clear_bit(bn, 0)) {
10783d1dbd8Sjsing 		fprintf(stderr, "FAIL: failed to clear bit\n");
10883d1dbd8Sjsing 		goto failure;
10983d1dbd8Sjsing 	}
11083d1dbd8Sjsing 	if (!BN_is_zero(bn)) {
11183d1dbd8Sjsing 		fprintf(stderr, "FAIL: clear bit did not result in zero\n");
11283d1dbd8Sjsing 		goto failure;
11383d1dbd8Sjsing 	}
11483d1dbd8Sjsing 	if (BN_is_negative(bn)) {
11583d1dbd8Sjsing 		fprintf(stderr, "FAIL: clear bit resulted in -0\n");
11683d1dbd8Sjsing 		goto failure;
11783d1dbd8Sjsing 	}
11883d1dbd8Sjsing 
11983d1dbd8Sjsing 	failed = 0;
12083d1dbd8Sjsing 
12183d1dbd8Sjsing  failure:
12283d1dbd8Sjsing 	BN_free(bn);
12383d1dbd8Sjsing 	free(out_str);
12483d1dbd8Sjsing 
12583d1dbd8Sjsing 	return failed;
12683d1dbd8Sjsing }
12783d1dbd8Sjsing 
12883d1dbd8Sjsing static int
test_bn_mask_bits(void)12983d1dbd8Sjsing test_bn_mask_bits(void)
13083d1dbd8Sjsing {
13183d1dbd8Sjsing 	BIGNUM *bn = NULL;
13283d1dbd8Sjsing 	char *out_str = NULL;
13383d1dbd8Sjsing 	size_t i;
13483d1dbd8Sjsing 	int failed = 1;
13583d1dbd8Sjsing 
13683d1dbd8Sjsing 	if ((bn = BN_new()) == NULL)
13783d1dbd8Sjsing 		goto failure;
13883d1dbd8Sjsing 
13983d1dbd8Sjsing 	if (BN_mask_bits(bn, 0)) {
14083d1dbd8Sjsing 		fprintf(stderr, "FAIL: mask bits should have failed\n");
14183d1dbd8Sjsing 		goto failure;
14283d1dbd8Sjsing 	}
14383d1dbd8Sjsing 
14483d1dbd8Sjsing 	for (i = 0; i < 128; i++) {
14583d1dbd8Sjsing 		if (!BN_set_bit(bn, i)) {
14683d1dbd8Sjsing 			fprintf(stderr, "FAIL: failed to set bit\n");
14783d1dbd8Sjsing 			goto failure;
14883d1dbd8Sjsing 		}
14983d1dbd8Sjsing 	}
15083d1dbd8Sjsing 
15183d1dbd8Sjsing 	if ((out_str = BN_bn2hex(bn)) == NULL)
15283d1dbd8Sjsing 		goto failure;
15383d1dbd8Sjsing 	if (strcmp(out_str, "FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF") != 0) {
15483d1dbd8Sjsing 		fprintf(stderr, "FAIL: got 0x%s, want 0x%s\n", out_str,
15583d1dbd8Sjsing 		    "FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF");
15683d1dbd8Sjsing 		goto failure;
15783d1dbd8Sjsing 	}
15883d1dbd8Sjsing 
15983d1dbd8Sjsing 	if (!BN_mask_bits(bn, 127)) {
16083d1dbd8Sjsing 		fprintf(stderr, "FAIL: failed to mask bits\n");
16183d1dbd8Sjsing 		goto failure;
16283d1dbd8Sjsing 	}
16383d1dbd8Sjsing 
16483d1dbd8Sjsing 	free(out_str);
16583d1dbd8Sjsing 	if ((out_str = BN_bn2hex(bn)) == NULL)
16683d1dbd8Sjsing 		goto failure;
16783d1dbd8Sjsing 	if (strcmp(out_str, "7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF") != 0) {
16883d1dbd8Sjsing 		fprintf(stderr, "FAIL: got 0x%s, want 0x%s\n", out_str,
16983d1dbd8Sjsing 		    "7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF");
17083d1dbd8Sjsing 		goto failure;
17183d1dbd8Sjsing 	}
17283d1dbd8Sjsing 
17383d1dbd8Sjsing 	if (!BN_mask_bits(bn, 65)) {
17483d1dbd8Sjsing 		fprintf(stderr, "FAIL: failed to mask bits\n");
17583d1dbd8Sjsing 		goto failure;
17683d1dbd8Sjsing 	}
17783d1dbd8Sjsing 
17883d1dbd8Sjsing 	free(out_str);
17983d1dbd8Sjsing 	if ((out_str = BN_bn2hex(bn)) == NULL)
18083d1dbd8Sjsing 		goto failure;
18183d1dbd8Sjsing 	if (strcmp(out_str, "01FFFFFFFFFFFFFFFF") != 0) {
18283d1dbd8Sjsing 		fprintf(stderr, "FAIL: got 0x%s, want 0x%s\n", out_str,
18383d1dbd8Sjsing 		    "01FFFFFFFFFFFFFFFF");
18483d1dbd8Sjsing 		goto failure;
18583d1dbd8Sjsing 	}
18683d1dbd8Sjsing 
18783d1dbd8Sjsing 	/* Ensure that masking results in non-negative zero. */
18883d1dbd8Sjsing 	if (!BN_one(bn))
18983d1dbd8Sjsing 		goto failure;
19083d1dbd8Sjsing 	BN_set_negative(bn, 1);
19183d1dbd8Sjsing 	if (!BN_mask_bits(bn, 0)) {
19283d1dbd8Sjsing 		fprintf(stderr, "FAIL: failed to mask bits\n");
19383d1dbd8Sjsing 		goto failure;
19483d1dbd8Sjsing 	}
19583d1dbd8Sjsing 	if (!BN_is_zero(bn)) {
19683d1dbd8Sjsing 		fprintf(stderr, "FAIL: mask bits did not result in zero\n");
19783d1dbd8Sjsing 		goto failure;
19883d1dbd8Sjsing 	}
19983d1dbd8Sjsing 	if (BN_is_negative(bn)) {
20083d1dbd8Sjsing 		fprintf(stderr, "FAIL: mask bits resulted in -0\n");
20183d1dbd8Sjsing 		goto failure;
20283d1dbd8Sjsing 	}
20383d1dbd8Sjsing 
20483d1dbd8Sjsing 	failed = 0;
20583d1dbd8Sjsing 
20683d1dbd8Sjsing  failure:
20783d1dbd8Sjsing 	BN_free(bn);
20883d1dbd8Sjsing 	free(out_str);
20983d1dbd8Sjsing 
21083d1dbd8Sjsing 	return failed;
21183d1dbd8Sjsing }
21283d1dbd8Sjsing 
21383d1dbd8Sjsing int
main(int argc,char ** argv)21483d1dbd8Sjsing main(int argc, char **argv)
21583d1dbd8Sjsing {
21683d1dbd8Sjsing 	int failed = 0;
21783d1dbd8Sjsing 
21883d1dbd8Sjsing 	failed |= test_bn_set_bit();
21983d1dbd8Sjsing 	failed |= test_bn_clear_bit();
22083d1dbd8Sjsing 	failed |= test_bn_mask_bits();
22183d1dbd8Sjsing 
22283d1dbd8Sjsing 	return failed;
22383d1dbd8Sjsing }
224