xref: /openbsd-src/regress/lib/libcrypto/bn/bn_word.c (revision 6822f9c8033774f6aab00bcb43e8718e7034e67d)
1 /* $OpenBSD: bn_word.c,v 1.2 2024/08/23 12:56:26 anton Exp $ */
2 /*
3  * Copyright (c) 2023 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 <err.h>
19 #include <string.h>
20 
21 #include <openssl/bn.h>
22 
23 struct bn_word_test {
24 	const char *in_hex;
25 	BN_ULONG in_word;
26 	BN_ULONG mod_word;
27 	BN_ULONG out_word;
28 	const char *out_hex;
29 	int out_is_negative;
30 };
31 
32 static int
33 check_bn_word_test(const char *op_name, const BIGNUM *bn,
34     const struct bn_word_test *bwt)
35 {
36 	char *out_hex = NULL;
37 	BN_ULONG out_word;
38 	int failed = 1;
39 
40 	if ((out_word = BN_get_word(bn)) != bwt->out_word) {
41 		fprintf(stderr, "FAIL %s: Got word %lx, want %lx\n",
42 		    op_name, (unsigned long)out_word,
43 		    (unsigned long)bwt->out_word);
44 		goto failure;
45 	}
46 
47 	if (BN_is_negative(bn) != bwt->out_is_negative) {
48 		fprintf(stderr, "FAIL %s: Got is negative %d, want %d\n",
49 		    op_name, BN_is_negative(bn), bwt->out_is_negative);
50 		goto failure;
51 	}
52 
53 	if ((out_hex = BN_bn2hex(bn)) == NULL)
54 		errx(1, "BN_bn2hex() failed");
55 
56 	if (strcmp(out_hex, bwt->out_hex) != 0) {
57 		fprintf(stderr, "FAIL %s: Got hex %s, want %s\n",
58 		    op_name, out_hex, bwt->out_hex);
59 		goto failure;
60 	}
61 
62 	if (BN_is_zero(bn) && BN_is_negative(bn) != 0) {
63 		fprintf(stderr, "FAIL %s: Got negative zero\n", op_name);
64 		goto failure;
65 	}
66 
67 	failed = 0;
68 
69  failure:
70 	free(out_hex);
71 
72 	return failed;
73 }
74 
75 static int
76 test_bn_word(int (*bn_word_op)(BIGNUM *, BN_ULONG), const char *op_name,
77     const struct bn_word_test *bwts, size_t num_tests)
78 {
79 	const struct bn_word_test *bwt;
80 	BIGNUM *bn;
81 	size_t i;
82 	int failed = 0;
83 
84 	if ((bn = BN_new()) == NULL)
85 		errx(1, "BN_new() failed");
86 
87 	for (i = 0; i < num_tests; i++) {
88 		bwt = &bwts[i];
89 
90 		if (!BN_hex2bn(&bn, bwt->in_hex)) {
91 			fprintf(stderr, "FAIL: BN_hex2bn(\"%s\") failed\n",
92 			    bwt->in_hex);
93 			failed = 1;
94 			continue;
95 		}
96 
97 		if (!bn_word_op(bn, bwt->in_word)) {
98 			fprintf(stderr, "FAIL: %s(%lx) failed\n", op_name,
99 			     (unsigned long)bwt->in_word);
100 			failed = 1;
101 			continue;
102 		}
103 
104 		failed |= check_bn_word_test(op_name, bn, bwt);
105 	}
106 
107 	BN_free(bn);
108 
109 	return failed;
110 }
111 
112 static const struct bn_word_test bn_add_word_tests[] = {
113 	{
114 		.in_hex = "1",
115 		.in_word = 0,
116 		.out_word = 1,
117 		.out_hex = "01",
118 	},
119 	{
120 		.in_hex = "0",
121 		.in_word = 1,
122 		.out_word = 1,
123 		.out_hex = "01",
124 	},
125 	{
126 		.in_hex = "1",
127 		.in_word = 1,
128 		.out_word = 2,
129 		.out_hex = "02",
130 	},
131 	{
132 		.in_hex = "-1",
133 		.in_word = 2,
134 		.out_word = 1,
135 		.out_hex = "01",
136 	},
137 	{
138 		.in_hex = "-1",
139 		.in_word = 1,
140 		.out_word = 0,
141 		.out_hex = "0",
142 	},
143 	{
144 		.in_hex = "-3",
145 		.in_word = 2,
146 		.out_word = 1,
147 		.out_hex = "-01",
148 		.out_is_negative = 1,
149 	},
150 	{
151 		.in_hex = "1",
152 		.in_word = 0xfffffffeUL,
153 		.out_word = 0xffffffffUL,
154 		.out_hex = "FFFFFFFF",
155 	},
156 	{
157 		.in_hex = "FFFFFFFFFFFFFFFF",
158 		.in_word = 1,
159 		.out_word = BN_MASK2,
160 		.out_hex = "010000000000000000",
161 	},
162 };
163 
164 #define N_BN_ADD_WORD_TESTS \
165     (sizeof(bn_add_word_tests) / sizeof(bn_add_word_tests[0]))
166 
167 static int
168 test_bn_add_word(void)
169 {
170 	return test_bn_word(BN_add_word, "BN_add_word", bn_add_word_tests,
171 	    N_BN_ADD_WORD_TESTS);
172 }
173 
174 static const struct bn_word_test bn_sub_word_tests[] = {
175 	{
176 		.in_hex = "1",
177 		.in_word = 0,
178 		.out_word = 1,
179 		.out_hex = "01",
180 	},
181 	{
182 		.in_hex = "0",
183 		.in_word = 1,
184 		.out_word = 1,
185 		.out_hex = "-01",
186 		.out_is_negative = 1,
187 	},
188 	{
189 		.in_hex = "1",
190 		.in_word = 1,
191 		.out_word = 0,
192 		.out_hex = "0",
193 	},
194 	{
195 		.in_hex = "2",
196 		.in_word = 1,
197 		.out_word = 1,
198 		.out_hex = "01",
199 	},
200 	{
201 		.in_hex = "-1",
202 		.in_word = 2,
203 		.out_word = 3,
204 		.out_hex = "-03",
205 		.out_is_negative = 1,
206 	},
207 	{
208 		.in_hex = "1",
209 		.in_word = 1,
210 		.out_word = 0,
211 		.out_hex = "0",
212 	},
213 	{
214 		.in_hex = "3",
215 		.in_word = 2,
216 		.out_word = 1,
217 		.out_hex = "01",
218 	},
219 	{
220 		.in_hex = "-3",
221 		.in_word = 2,
222 		.out_word = 5,
223 		.out_hex = "-05",
224 		.out_is_negative = 1,
225 	},
226 	{
227 		.in_hex = "-1",
228 		.in_word = 0xfffffffeUL,
229 		.out_word = 0xffffffffUL,
230 		.out_hex = "-FFFFFFFF",
231 		.out_is_negative = 1,
232 	},
233 	{
234 		.in_hex = "010000000000000000",
235 		.in_word = 1,
236 		.out_word = BN_MASK2,
237 		.out_hex = "FFFFFFFFFFFFFFFF",
238 	},
239 };
240 
241 #define N_BN_SUB_WORD_TESTS \
242     (sizeof(bn_sub_word_tests) / sizeof(bn_sub_word_tests[0]))
243 
244 static int
245 test_bn_sub_word(void)
246 {
247 	return test_bn_word(BN_sub_word, "BN_sub_word", bn_sub_word_tests,
248 	    N_BN_SUB_WORD_TESTS);
249 }
250 
251 static const struct bn_word_test bn_mul_word_tests[] = {
252 	{
253 		.in_hex = "1",
254 		.in_word = 0,
255 		.out_word = 0,
256 		.out_hex = "0",
257 	},
258 	{
259 		.in_hex = "0",
260 		.in_word = 1,
261 		.out_word = 0,
262 		.out_hex = "0",
263 	},
264 	{
265 		.in_hex = "1",
266 		.in_word = 1,
267 		.out_word = 1,
268 		.out_hex = "01",
269 	},
270 	{
271 		.in_hex = "-1",
272 		.in_word = 0,
273 		.out_word = 0,
274 		.out_hex = "0",
275 	},
276 	{
277 		.in_hex = "-1",
278 		.in_word = 1,
279 		.out_word = 1,
280 		.out_hex = "-01",
281 		.out_is_negative = 1,
282 	},
283 	{
284 		.in_hex = "-3",
285 		.in_word = 2,
286 		.out_word = 6,
287 		.out_hex = "-06",
288 		.out_is_negative = 1,
289 	},
290 	{
291 		.in_hex = "1",
292 		.in_word = 0xfffffffeUL,
293 		.out_word = 0xfffffffeUL,
294 		.out_hex = "FFFFFFFE",
295 	},
296 	{
297 		.in_hex = "010000000000000000",
298 		.in_word = 2,
299 		.out_word = BN_MASK2,
300 		.out_hex = "020000000000000000",
301 	},
302 };
303 
304 #define N_BN_MUL_WORD_TESTS \
305     (sizeof(bn_mul_word_tests) / sizeof(bn_mul_word_tests[0]))
306 
307 static int
308 test_bn_mul_word(void)
309 {
310 	return test_bn_word(BN_mul_word, "BN_mul_word", bn_mul_word_tests,
311 	    N_BN_MUL_WORD_TESTS);
312 }
313 
314 static const struct bn_word_test bn_div_word_tests[] = {
315 	{
316 		.in_hex = "1",
317 		.in_word = 0,
318 		.mod_word = BN_MASK2,
319 		.out_word = 1,
320 		.out_hex = "01",
321 	},
322 	{
323 		.in_hex = "0",
324 		.in_word = 1,
325 		.mod_word = 0,
326 		.out_word = 0,
327 		.out_hex = "0",
328 	},
329 	{
330 		.in_hex = "4",
331 		.in_word = 2,
332 		.mod_word = 0,
333 		.out_word = 2,
334 		.out_hex = "02",
335 	},
336 	{
337 		.in_hex = "7",
338 		.in_word = 3,
339 		.mod_word = 1,
340 		.out_word = 2,
341 		.out_hex = "02",
342 	},
343 	{
344 		.in_hex = "1",
345 		.in_word = 1,
346 		.mod_word = 0,
347 		.out_word = 1,
348 		.out_hex = "01",
349 	},
350 	{
351 		.in_hex = "-2",
352 		.in_word = 1,
353 		.mod_word = 0,
354 		.out_word = 2,
355 		.out_hex = "-02",
356 		.out_is_negative = 1,
357 	},
358 	{
359 		.in_hex = "-1",
360 		.in_word = 2,
361 		.mod_word = 1,
362 		.out_word = 0,
363 		.out_hex = "0",
364 	},
365 	{
366 		.in_hex = "-3",
367 		.in_word = 2,
368 		.mod_word = 1,
369 		.out_word = 1,
370 		.out_hex = "-01",
371 		.out_is_negative = 1,
372 	},
373 	{
374 		.in_hex = "1",
375 		.in_word = 0xffffffffUL,
376 		.mod_word = 1,
377 		.out_word = 0,
378 		.out_hex = "0",
379 	},
380 	{
381 		.in_hex = "FFFFFFFF",
382 		.in_word = 1,
383 		.mod_word = 0,
384 		.out_word = 0xffffffffUL,
385 		.out_hex = "FFFFFFFF",
386 	},
387 	{
388 		.in_hex = "FFFFFFFE",
389 		.in_word = 0xffffffffUL,
390 		.mod_word = 0xfffffffeUL,
391 		.out_word = 0,
392 		.out_hex = "0",
393 	},
394 	{
395 		.in_hex = "FFFFFFFFFFFFFFFF",
396 		.in_word = 1,
397 		.mod_word = 0,
398 		.out_word = BN_MASK2,
399 		.out_hex = "FFFFFFFFFFFFFFFF",
400 	},
401 	{
402 		.in_hex = "FFFFFFFF",
403 		.in_word = 0xff,
404 		.mod_word = 0,
405 		.out_word = 0x1010101UL,
406 		.out_hex = "01010101",
407 	},
408 	{
409 		.in_hex = "FFFFFFFF",
410 		.in_word = 0x10,
411 		.mod_word = 0xf,
412 		.out_word = 0xfffffffUL,
413 		.out_hex = "0FFFFFFF",
414 	},
415 };
416 
417 #define N_BN_DIV_WORD_TESTS \
418     (sizeof(bn_div_word_tests) / sizeof(bn_div_word_tests[0]))
419 
420 static int
421 test_bn_div_word(void)
422 {
423 	const char *op_name = "BN_div_word";
424 	const struct bn_word_test *bwt;
425 	BN_ULONG mod_word;
426 	BIGNUM *bn;
427 	size_t i;
428 	int failed = 0;
429 
430 	if ((bn = BN_new()) == NULL)
431 		errx(1, "BN_new() failed");
432 
433 	for (i = 0; i < N_BN_DIV_WORD_TESTS; i++) {
434 		bwt = &bn_div_word_tests[i];
435 
436 		if (!BN_hex2bn(&bn, bwt->in_hex)) {
437 			fprintf(stderr, "FAIL: BN_hex2bn(\"%s\") failed\n",
438 			    bwt->in_hex);
439 			failed = 1;
440 			continue;
441 		}
442 
443 		if ((mod_word = BN_div_word(bn, bwt->in_word)) != bwt->mod_word) {
444 			fprintf(stderr, "FAIL %s: Got mod word %lx, want %lx\n",
445 			    op_name, (unsigned long)mod_word,
446 			    (unsigned long)bwt->mod_word);
447 			failed = 1;
448 			continue;
449 		}
450 
451 		failed |= check_bn_word_test(op_name, bn, bwt);
452 	}
453 
454 	BN_free(bn);
455 
456 	return failed;
457 }
458 
459 static const struct bn_word_test bn_mod_word_tests[] = {
460 	{
461 		.in_hex = "1",
462 		.in_word = 0,
463 		.mod_word = BN_MASK2,
464 		.out_word = 1,
465 		.out_hex = "01",
466 	},
467 	{
468 		.in_hex = "0",
469 		.in_word = 1,
470 		.mod_word = 0,
471 		.out_word = 0,
472 		.out_hex = "0",
473 	},
474 	{
475 		.in_hex = "4",
476 		.in_word = 2,
477 		.mod_word = 0,
478 		.out_word = 4,
479 		.out_hex = "04",
480 	},
481 	{
482 		.in_hex = "7",
483 		.in_word = 3,
484 		.mod_word = 1,
485 		.out_word = 7,
486 		.out_hex = "07",
487 	},
488 	{
489 		.in_hex = "1",
490 		.in_word = 1,
491 		.mod_word = 0,
492 		.out_word = 1,
493 		.out_hex = "01",
494 	},
495 	{
496 		.in_hex = "-2",
497 		.in_word = 1,
498 		.mod_word = 0,
499 		.out_word = 2,
500 		.out_hex = "-02",
501 		.out_is_negative = 1,
502 	},
503 	{
504 		.in_hex = "-1",
505 		.in_word = 2,
506 		.mod_word = 1,
507 		.out_word = 1,
508 		.out_hex = "-01",
509 		.out_is_negative = 1,
510 	},
511 	{
512 		.in_hex = "-3",
513 		.in_word = 2,
514 		.mod_word = 1,
515 		.out_word = 3,
516 		.out_hex = "-03",
517 		.out_is_negative = 1,
518 	},
519 	{
520 		.in_hex = "1",
521 		.in_word = 0xffffffffUL,
522 		.mod_word = 1,
523 		.out_word = 1,
524 		.out_hex = "01",
525 	},
526 	{
527 		.in_hex = "FFFFFFFF",
528 		.in_word = 1,
529 		.mod_word = 0,
530 		.out_word = 0xffffffffUL,
531 		.out_hex = "FFFFFFFF",
532 	},
533 	{
534 		.in_hex = "FFFFFFFE",
535 		.in_word = 0xffffffffUL,
536 		.mod_word = 0xfffffffeUL,
537 		.out_word = 0xfffffffeUL,
538 		.out_hex = "FFFFFFFE",
539 	},
540 	{
541 		.in_hex = "FFFFFFFFFFFFFFFF",
542 		.in_word = 1,
543 		.mod_word = 0,
544 		.out_word = BN_MASK2,
545 		.out_hex = "FFFFFFFFFFFFFFFF",
546 	},
547 	{
548 		.in_hex = "FFFFFFFF",
549 		.in_word = 0xff,
550 		.mod_word = 0,
551 		.out_word = 0xffffffff,
552 		.out_hex = "FFFFFFFF",
553 	},
554 	{
555 		.in_hex = "FFFFFFFF",
556 		.in_word = 0x10,
557 		.mod_word = 0xf,
558 		.out_word = 0xffffffffUL,
559 		.out_hex = "FFFFFFFF",
560 	},
561 };
562 
563 #define N_BN_MOD_WORD_TESTS \
564     (sizeof(bn_mod_word_tests) / sizeof(bn_mod_word_tests[0]))
565 
566 static int
567 test_bn_mod_word(void)
568 {
569 	const char *op_name = "BN_mod_word";
570 	const struct bn_word_test *bwt;
571 	BN_ULONG mod_word;
572 	BIGNUM *bn;
573 	size_t i;
574 	int failed = 0;
575 
576 	if ((bn = BN_new()) == NULL)
577 		errx(1, "BN_new() failed");
578 
579 	for (i = 0; i < N_BN_MOD_WORD_TESTS; i++) {
580 		bwt = &bn_mod_word_tests[i];
581 
582 		if (!BN_hex2bn(&bn, bwt->in_hex)) {
583 			fprintf(stderr, "FAIL: BN_hex2bn(\"%s\") failed\n",
584 			    bwt->in_hex);
585 			failed = 1;
586 			continue;
587 		}
588 
589 		if ((mod_word = BN_mod_word(bn, bwt->in_word)) != bwt->mod_word) {
590 			fprintf(stderr, "FAIL %s: Got mod word %lx, want %lx\n",
591 			    op_name, (unsigned long)mod_word,
592 			    (unsigned long)bwt->mod_word);
593 			failed = 1;
594 			continue;
595 		}
596 
597 		failed |= check_bn_word_test(op_name, bn, bwt);
598 	}
599 
600 	BN_free(bn);
601 
602 	return failed;
603 }
604 
605 int
606 main(int argc, char **argv)
607 {
608 	int failed = 0;
609 
610 	failed |= test_bn_add_word();
611 	failed |= test_bn_sub_word();
612 	failed |= test_bn_mul_word();
613 	failed |= test_bn_div_word();
614 	failed |= test_bn_mod_word();
615 
616 	return failed;
617 }
618