xref: /openbsd/regress/lib/libcrypto/bn/bn_cmp.c (revision 3bef86f7)
1 /*	$OpenBSD: bn_cmp.c,v 1.2 2023/06/21 07:16:08 jsing Exp $ */
2 /*
3  * Copyright (c) 2022 Joel Sing <jsing@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 <stdio.h>
19 
20 #include <openssl/bn.h>
21 
22 struct bn_cmp_test {
23 	const char *a;
24 	const char *b;
25 	int cmp;
26 	int ucmp;
27 };
28 
29 struct bn_cmp_test bn_cmp_tests[] = {
30 	{
31 		.a = "0",
32 		.b = "0",
33 		.cmp = 0,
34 		.ucmp = 0,
35 	},
36 	{
37 		.a = "-1",
38 		.b = "0",
39 		.cmp = -1,
40 		.ucmp = 1,
41 	},
42 	{
43 		.a = "1ffffffffffffffff",
44 		.b = "1ffffffffffffffff",
45 		.cmp = 0,
46 		.ucmp = 0,
47 	},
48 	{
49 		.a = "1fffffffffffffffe",
50 		.b = "1ffffffffffffffff",
51 		.cmp = -1,
52 		.ucmp = -1,
53 	},
54 	{
55 		.a = "1ffffffffffffffff",
56 		.b = "1fffffffffffffffe",
57 		.cmp = 1,
58 		.ucmp = 1,
59 	},
60 	{
61 		.a = "0",
62 		.b = "1ffffffffffffffff",
63 		.cmp = -1,
64 		.ucmp = -1,
65 	},
66 	{
67 		.a = "1ffffffffffffffff",
68 		.b = "0",
69 		.cmp = 1,
70 		.ucmp = 1,
71 	},
72 	{
73 		.a = "-1ffffffffffffffff",
74 		.b = "0",
75 		.cmp = -1,
76 		.ucmp = 1,
77 	},
78 	{
79 		.a = "1ffffffffffffffff",
80 		.b = "00000000000000001ffffffffffffffff",
81 		.cmp = 0,
82 		.ucmp = 0,
83 	},
84 	{
85 		.a = "-1ffffffffffffffff",
86 		.b = "-00000000000000001ffffffffffffffff",
87 		.cmp = 0,
88 		.ucmp = 0,
89 	},
90 	{
91 		.a = "1ffffffffffffffff",
92 		.b = "-00000000000000001ffffffffffffffff",
93 		.cmp = 1,
94 		.ucmp = 0,
95 	},
96 	{
97 		.a = "-1ffffffffffffffff",
98 		.b = "00000000000000001ffffffffffffffff",
99 		.cmp = -1,
100 		.ucmp = 0,
101 	},
102 };
103 
104 #define N_BN_CMP_TESTS \
105     (sizeof(bn_cmp_tests) / sizeof(*bn_cmp_tests))
106 
107 static int
108 test_bn_cmp(void)
109 {
110 	struct bn_cmp_test *bct;
111 	BIGNUM *a = NULL, *b = NULL;
112 	size_t i;
113 	int ret;
114 	int failed = 1;
115 
116 	if ((a = BN_new()) == NULL) {
117 		fprintf(stderr, "FAIL: failed to create BN\n");
118 		goto failure;
119 	}
120 	if ((b = BN_new()) == NULL) {
121 		fprintf(stderr, "FAIL: failed to create BN\n");
122 		goto failure;
123 	}
124 
125 	for (i = 0; i < N_BN_CMP_TESTS; i++) {
126 		bct = &bn_cmp_tests[i];
127 
128 		if (!BN_hex2bn(&a, bct->a)) {
129 			fprintf(stderr, "FAIL: failed to set a from hex\n");
130 			goto failure;
131 		}
132 		if (!BN_hex2bn(&b, bct->b)) {
133 			fprintf(stderr, "FAIL: failed to set b from hex\n");
134 			goto failure;
135 		}
136 
137 		if ((ret = BN_cmp(a, b)) != bct->cmp) {
138 			fprintf(stderr, "FAIL: BN_cmp(%s, %s) = %d, want %d\n",
139 			    bct->a, bct->b, ret, bct->cmp);
140 			goto failure;
141 		}
142 		if ((ret = BN_ucmp(a, b)) != bct->ucmp) {
143 			fprintf(stderr, "FAIL: BN_ucmp(%s, %s) = %d, want %d\n",
144 			    bct->a, bct->b, ret, bct->ucmp);
145 			goto failure;
146 		}
147 	}
148 
149 	failed = 0;
150 
151  failure:
152 	BN_free(a);
153 	BN_free(b);
154 
155 	return failed;
156 }
157 
158 static int
159 test_bn_cmp_null(void)
160 {
161 	BIGNUM *a = NULL;
162 	int ret;
163 	int failed = 1;
164 
165 	if ((a = BN_new()) == NULL) {
166 		fprintf(stderr, "FAIL: failed to create BN\n");
167 		goto failure;
168 	}
169 
170 	/*
171 	 * Comparison to NULL.
172 	 */
173 	if ((ret = BN_cmp(NULL, NULL)) != 0) {
174 		fprintf(stderr, "FAIL: BN_cmp(NULL, NULL) == %d, want 0\n", ret);
175 		goto failure;
176 	}
177 
178 	if ((ret = BN_cmp(a, NULL)) != -1) {
179 		fprintf(stderr, "FAIL: BN_cmp(0, NULL) == %d, want -1\n", ret);
180 		goto failure;
181 	}
182 	if ((ret = BN_cmp(NULL, a)) != 1) {
183 		fprintf(stderr, "FAIL: BN_cmp(NULL, 0) == %d, want 1\n", ret);
184 		goto failure;
185 	}
186 
187 	if (!BN_set_word(a, 1)) {
188 		fprintf(stderr, "FAIL: failed to set BN to 1\n");
189 		goto failure;
190 	}
191 	if ((ret = BN_cmp(a, NULL)) != -1) {
192 		fprintf(stderr, "FAIL: BN_cmp(1, NULL) == %d, want -1\n", ret);
193 		goto failure;
194 	}
195 	if ((ret = BN_cmp(NULL, a)) != 1) {
196 		fprintf(stderr, "FAIL: BN_cmp(NULL, 1) == %d, want 1\n", ret);
197 		goto failure;
198 	}
199 
200 	BN_set_negative(a, 1);
201 	if ((ret = BN_cmp(a, NULL)) != -1) {
202 		fprintf(stderr, "FAIL: BN_cmp(-1, NULL) == %d, want -1\n", ret);
203 		goto failure;
204 	}
205 	if ((ret = BN_cmp(NULL, a)) != 1) {
206 		fprintf(stderr, "FAIL: BN_cmp(NULL, -1) == %d, want 1\n", ret);
207 		goto failure;
208 	}
209 
210 	failed = 0;
211 
212  failure:
213 	BN_free(a);
214 
215 	return failed;
216 }
217 
218 struct bn_cmp_word_test {
219 	int a;
220 	int b;
221 	int cmp;
222 	int ucmp;
223 };
224 
225 struct bn_cmp_word_test bn_cmp_word_tests[] = {
226 	{
227 		.a = -1,
228 		.b = -1,
229 		.cmp = 0,
230 		.ucmp = 0,
231 	},
232 	{
233 		.a = 0,
234 		.b = 0,
235 		.cmp = 0,
236 		.ucmp = 0,
237 	},
238 	{
239 		.a = 1,
240 		.b = 1,
241 		.cmp = 0,
242 		.ucmp = 0,
243 	},
244 	{
245 		.a = 0,
246 		.b = 1,
247 		.cmp = -1,
248 		.ucmp = -1,
249 	},
250 	{
251 		.a = 1,
252 		.b = 0,
253 		.cmp = 1,
254 		.ucmp = 1,
255 	},
256 	{
257 		.a = -1,
258 		.b = 0,
259 		.cmp = -1,
260 		.ucmp = 1,
261 	},
262 	{
263 		.a = 0,
264 		.b = -1,
265 		.cmp = 1,
266 		.ucmp = -1,
267 	},
268 	{
269 		.a = -1,
270 		.b = 1,
271 		.cmp = -1,
272 		.ucmp = 0,
273 	},
274 	{
275 		.a = 1,
276 		.b = -1,
277 		.cmp = 1,
278 		.ucmp = 0,
279 	},
280 };
281 
282 #define N_BN_CMP_WORD_TESTS \
283     (sizeof(bn_cmp_word_tests) / sizeof(*bn_cmp_word_tests))
284 
285 static int
286 test_bn_cmp_word(void)
287 {
288 	struct bn_cmp_word_test *bcwt;
289 	BIGNUM *a = NULL, *b = NULL;
290 	BN_ULONG v;
291 	size_t i;
292 	int ret;
293 	int failed = 1;
294 
295 	if ((a = BN_new()) == NULL) {
296 		fprintf(stderr, "FAIL: failed to create BN\n");
297 		goto failure;
298 	}
299 	if ((b = BN_new()) == NULL) {
300 		fprintf(stderr, "FAIL: failed to create BN\n");
301 		goto failure;
302 	}
303 
304 	for (i = 0; i < N_BN_CMP_WORD_TESTS; i++) {
305 		bcwt = &bn_cmp_word_tests[i];
306 
307 		if (bcwt->a >= 0) {
308 			v = bcwt->a;
309 		} else {
310 			v = 0 - bcwt->a;
311 		}
312 		if (!BN_set_word(a, v)) {
313 			fprintf(stderr, "FAIL: failed to set a\n");
314 			goto failure;
315 		}
316 		BN_set_negative(a, (bcwt->a < 0));
317 
318 		if (bcwt->b >= 0) {
319 			v = bcwt->b;
320 		} else {
321 			v = 0 - bcwt->b;
322 		}
323 		if (!BN_set_word(b, v)) {
324 			fprintf(stderr, "FAIL: failed to set b\n");
325 			goto failure;
326 		}
327 		BN_set_negative(b, (bcwt->b < 0));
328 
329 		if ((ret = BN_cmp(a, b)) != bcwt->cmp) {
330 			fprintf(stderr, "FAIL: BN_cmp(%d, %d) = %d, want %d\n",
331 			    bcwt->a, bcwt->b, ret, bcwt->cmp);
332 			goto failure;
333 		}
334 		if ((ret = BN_ucmp(a, b)) != bcwt->ucmp) {
335 			fprintf(stderr, "FAIL: BN_ucmp(%d, %d) = %d, want %d\n",
336 			    bcwt->a, bcwt->b, ret, bcwt->ucmp);
337 			goto failure;
338 		}
339 	}
340 
341 	failed = 0;
342 
343  failure:
344 	BN_free(a);
345 	BN_free(b);
346 
347 	return failed;
348 }
349 
350 int
351 main(int argc, char **argv)
352 {
353 	int failed = 0;
354 
355 	failed |= test_bn_cmp();
356 	failed |= test_bn_cmp_null();
357 	failed |= test_bn_cmp_word();
358 
359 	return failed;
360 }
361