1/*	$OpenBSD: bn_primes.c,v 1.3 2023/04/25 15:30:03 tb Exp $ */
2/*
3 * Copyright (c) 2022 Theo Buehler <tb@openbsd.org>
4 *
5 * Permission to use, copy, modify, and distribute this software for any
6 * purpose with or without fee is hereby granted, provided that the above
7 * copyright notice and this permission notice appear in all copies.
8 *
9 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
10 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
11 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
12 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
13 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
14 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
15 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
16 */
17
18#include <stdint.h>
19#include <stdio.h>
20#include <stdlib.h>
21
22#include <openssl/bn.h>
23
24#include "bn_prime.h"
25
26static int
27test_bn_is_prime_fasttest(int do_trial_division)
28{
29	BIGNUM *n = NULL;
30	char *descr = NULL;
31	uint16_t i, j, max;
32	int is_prime, ret;
33	int failed = 1;
34
35	if (asprintf(&descr, "with%s trial divisions",
36	    do_trial_division ? "" : "out") == -1) {
37		descr = NULL;
38		fprintf(stderr, "asprintf failed\n");
39		goto err;
40	}
41
42	if ((n = BN_new()) == NULL) {
43		fprintf(stderr, "BN_new failed\n");
44		goto err;
45	}
46
47	max = primes[NUMPRIMES - 1] + 1;
48
49	failed = 0;
50	for (i = 1, j = 0; i < max && j < NUMPRIMES; i++) {
51		if (!BN_set_word(n, i)) {
52			fprintf(stderr, "BN_set_word(%d) failed", i);
53			failed = 1;
54			goto err;
55		}
56
57		is_prime = i == primes[j];
58		if (is_prime)
59			j++;
60
61		ret = BN_is_prime_fasttest_ex(n, BN_prime_checks, NULL,
62		    do_trial_division, NULL);
63		if (ret != is_prime) {
64			fprintf(stderr,
65			    "BN_is_prime_fasttest_ex(%d) %s: want %d, got %d\n",
66			    i, descr, is_prime, ret);
67			failed = 1;
68		}
69	}
70
71	if (i < max || j < NUMPRIMES) {
72		fprintf(stderr, "%s: %d < %d or %d < %d\n", descr, i, max, j,
73		    NUMPRIMES);
74		failed = 1;
75	}
76
77 err:
78	BN_free(n);
79	free(descr);
80	return failed;
81}
82
83#define BN_PRIME_FN_INIT(a) { .fn = a, .name = #a }
84
85static const struct test_dynamic_api {
86	BIGNUM *(*fn)(BIGNUM *);
87	const char *name;
88} dynamic_api_data[] = {
89	BN_PRIME_FN_INIT(BN_get_rfc2409_prime_1024),
90	BN_PRIME_FN_INIT(BN_get_rfc2409_prime_768),
91	BN_PRIME_FN_INIT(BN_get_rfc3526_prime_1536),
92	BN_PRIME_FN_INIT(BN_get_rfc3526_prime_2048),
93	BN_PRIME_FN_INIT(BN_get_rfc3526_prime_3072),
94	BN_PRIME_FN_INIT(BN_get_rfc3526_prime_4096),
95	BN_PRIME_FN_INIT(BN_get_rfc3526_prime_6144),
96	BN_PRIME_FN_INIT(BN_get_rfc3526_prime_8192),
97};
98
99#define N_DYNAMIC_TESTS (sizeof(dynamic_api_data) / sizeof(dynamic_api_data[0]))
100
101static int
102test_prime_dynamic_api(const struct test_dynamic_api *tc)
103{
104	BIGNUM *prime;
105	int ret;
106	int failed = 1;
107
108	if ((prime = tc->fn(NULL)) == NULL) {
109		fprintf(stderr, "%s failed\n", tc->name);
110		goto err;
111	}
112
113	if ((ret = BN_is_prime_fasttest_ex(prime, 1, NULL, 1, NULL)) != 1) {
114		fprintf(stderr, "%s: %s want 1, got %d\n", tc->name,
115		    "BN_is_prime_fasttest_ex", ret);
116		goto err;
117	}
118
119	failed = 0;
120
121 err:
122	BN_free(prime);
123	return failed;
124}
125
126static int
127test_prime_constants(void)
128{
129	size_t i;
130	int failed = 0;
131
132	for (i = 0; i < N_DYNAMIC_TESTS; i++)
133		failed |= test_prime_dynamic_api(&dynamic_api_data[i]);
134
135	return failed;
136}
137
138int
139main(void)
140{
141	int failed = 0;
142
143	failed |= test_bn_is_prime_fasttest(0);
144	failed |= test_bn_is_prime_fasttest(1);
145	failed |= test_prime_constants();
146
147	return failed;
148}
149