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