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
test_bn_cmp(void)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
test_bn_cmp_null(void)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
test_bn_cmp_word(void)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
main(int argc,char ** argv)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