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