1 | /* |
2 | Name: imdrover.c |
3 | Purpose: Keeper of the hordes of testing code. |
4 | Author: M. J. Fromberger |
5 | |
6 | Copyright (C) 2002-2007 Michael J. Fromberger, All Rights Reserved. |
7 | |
8 | Permission is hereby granted, free of charge, to any person obtaining a copy |
9 | of this software and associated documentation files (the "Software"), to deal |
10 | in the Software without restriction, including without limitation the rights |
11 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell |
12 | copies of the Software, and to permit persons to whom the Software is |
13 | furnished to do so, subject to the following conditions: |
14 | |
15 | The above copyright notice and this permission notice shall be included in |
16 | all copies or substantial portions of the Software. |
17 | |
18 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR |
19 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, |
20 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE |
21 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER |
22 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, |
23 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE |
24 | SOFTWARE. |
25 | */ |
26 | |
27 | #include <assert.h> |
28 | #include <limits.h> |
29 | #include <stdlib.h> |
30 | #include <string.h> |
31 | |
32 | #include "imath.h" |
33 | #include "imdrover.h" |
34 | #include "imrat.h" |
35 | #include "iprime.h" |
36 | |
37 | /* Globals visible from outside this file */ |
38 | mp_result imath_errno; |
39 | char* imath_errmsg; |
40 | |
41 | /* Set imath_errno and return failure from a test. */ |
42 | #define FAIL(E) return (imath_errno = (E), false) |
43 | |
44 | /* Check that an expression X yields the expected mp_result value V. */ |
45 | #define VCHECK(X, V) \ |
46 | do { \ |
47 | mp_result res_; \ |
48 | if ((res_ = (X)) != (V)) { \ |
49 | FAIL(res_); \ |
50 | } \ |
51 | } while (0) |
52 | #define CHECK(X) VCHECK(X, MP_OK) |
53 | #define ECHECK(X) VCHECK(X, expect) |
54 | #define ACHECK(X) \ |
55 | do { \ |
56 | if (!(X)) { \ |
57 | FAIL(MP_BADARG); \ |
58 | } \ |
59 | } while (0) |
60 | |
61 | #define OUTPUT_LIMIT 2048 |
62 | #define NUM_REGS 16 |
63 | #define OTHER_ERROR -1024 |
64 | |
65 | static char g_output[OUTPUT_LIMIT]; |
66 | static mpz_t g_zreg[NUM_REGS]; |
67 | static mpq_t g_qreg[NUM_REGS]; |
68 | static unsigned char g_bin1[OUTPUT_LIMIT]; |
69 | static unsigned char g_bin2[OUTPUT_LIMIT]; |
70 | |
71 | extern void trim_line(char* line); /* borrowed from imtest.c */ |
72 | |
73 | /* Read in a string with radix tags */ |
74 | static mp_result read_int_value(mp_int z, char* str); |
75 | static mp_result read_rat_value(mp_rat q, char* str); |
76 | |
77 | /* Read in a string with radix tags, as a long (not an mp_int) */ |
78 | static bool read_long(long* z, char* str); |
79 | |
80 | /* Parse the input and output values and fill in pointers to the |
81 | registers containing them. Returns true if all is well, false |
82 | in case of error. Caller allocates in/out to correct sizes. */ |
83 | static bool parse_int_values(testspec_t* t, mp_int* in, mp_int* out, |
84 | mp_result* rval); |
85 | static bool parse_rat_values(testspec_t* t, mp_rat* in, mp_rat* out, |
86 | mp_result* rval); |
87 | |
88 | /* Parse a result code name and return the corresponding result code */ |
89 | static bool parse_result_code(char* str, mp_result* code); |
90 | |
91 | /* Read in a dot-delimited binary sequence to the given buffer, and return the |
92 | number of bytes read. Returns < 0 in case of a syntax error. Records no |
93 | more than limit bytes. */ |
94 | static int parse_binary(char* str, unsigned char* buf, int limit); |
95 | |
96 | /* Clean up registers (called from atexit()) */ |
97 | static void done_testing(void); |
98 | |
99 | /* |
100 | * Utility subroutines for writing tests (explained above) |
101 | */ |
102 | |
103 | static mp_result read_int_value(mp_int z, char* str) { |
104 | int radix = 10; |
105 | |
106 | if (*str == '#') { |
107 | ++str; |
108 | switch (*str) { |
109 | case 'x': |
110 | case 'X': |
111 | radix = 16; |
112 | break; |
113 | case 'd': |
114 | case 'D': |
115 | radix = 10; |
116 | break; |
117 | case 'o': |
118 | case 'O': |
119 | radix = 8; |
120 | break; |
121 | case 'b': |
122 | case 'B': |
123 | radix = 2; |
124 | break; |
125 | default: |
126 | return MP_RANGE; |
127 | } |
128 | ++str; |
129 | } |
130 | |
131 | return mp_int_read_string(z, radix, str); |
132 | } |
133 | |
134 | static mp_result read_rat_value(mp_rat q, char* str) { |
135 | int radix = 10; |
136 | |
137 | if (*str == '#') { |
138 | ++str; |
139 | switch (*str) { |
140 | case 'x': |
141 | case 'X': |
142 | radix = 16; |
143 | break; |
144 | case 'd': |
145 | case 'D': |
146 | radix = 10; |
147 | break; |
148 | case 'o': |
149 | case 'O': |
150 | radix = 8; |
151 | break; |
152 | case 'b': |
153 | case 'B': |
154 | radix = 2; |
155 | break; |
156 | default: |
157 | return MP_RANGE; |
158 | } |
159 | ++str; |
160 | } |
161 | |
162 | if (*str == '@') |
163 | return mp_rat_read_decimal(r: q, radix, str: str + 1); |
164 | else |
165 | return mp_rat_read_string(r: q, radix, str); |
166 | } |
167 | |
168 | static bool read_long(long* z, char* str) { |
169 | char* end; |
170 | int radix = 10; |
171 | |
172 | if (*str == '#') { |
173 | ++str; |
174 | switch (*str) { |
175 | case 'x': |
176 | case 'X': |
177 | radix = 16; |
178 | break; |
179 | case 'd': |
180 | case 'D': |
181 | radix = 10; |
182 | break; |
183 | case 'o': |
184 | case 'O': |
185 | radix = 8; |
186 | break; |
187 | case 'b': |
188 | case 'B': |
189 | radix = 2; |
190 | break; |
191 | default: |
192 | return false; |
193 | } |
194 | ++str; |
195 | } |
196 | |
197 | *z = strtol(nptr: str, endptr: &end, base: radix); |
198 | return (end != str && *end == '\0'); |
199 | } |
200 | |
201 | static bool parse_int_values(testspec_t* t, mp_int* in, mp_int* out, |
202 | mp_result* rval) { |
203 | int pos = 0; |
204 | char* str; |
205 | |
206 | if (rval != NULL) *rval = MP_OK; /* default */ |
207 | |
208 | if (in != NULL) { |
209 | for (int i = 0; i < t->num_inputs; ++i) { |
210 | str = t->input[i]; |
211 | |
212 | trim_line(line: str); |
213 | |
214 | if (*str == '=') { |
215 | int k = abs(x: atoi(nptr: str + 1)) - 1; |
216 | |
217 | if (k < 0 || k >= i) { |
218 | fprintf(stderr, format: "Line %d: Invalid input back-reference [%s]\n" , |
219 | t->line, str); |
220 | return false; |
221 | } |
222 | |
223 | in[i] = in[k]; |
224 | } else { |
225 | mp_int reg = g_zreg + pos++; /* grab next free register */ |
226 | |
227 | if (read_int_value(z: reg, str) != MP_OK) { |
228 | fprintf(stderr, format: "Line %d: Invalid input value [%s]\n" , t->line, str); |
229 | return false; |
230 | } |
231 | |
232 | in[i] = reg; |
233 | } |
234 | } |
235 | } |
236 | |
237 | for (int i = 0; i < t->num_outputs; ++i) { |
238 | mp_int reg = g_zreg + pos++; |
239 | |
240 | str = t->output[i]; |
241 | |
242 | trim_line(line: str); |
243 | |
244 | if (strcmp(s1: str, s2: "?" ) == 0) |
245 | mp_int_zero(z: reg); |
246 | else if (*str == '$') { |
247 | mp_result code; |
248 | |
249 | if (!parse_result_code(str, code: &code)) { |
250 | fprintf(stderr, format: "Line %d: Invalid result code [%s]\n" , t->line, str); |
251 | return false; |
252 | } else if (rval == NULL) { |
253 | fprintf(stderr, format: "Line %d: Result code not permitted here [%s]\n" , |
254 | t->line, str); |
255 | return false; |
256 | } else |
257 | *rval = code; |
258 | |
259 | /* Provide a dummy value for the corresponding output */ |
260 | mp_int_zero(z: reg); |
261 | } else if (out != NULL && read_int_value(z: reg, str) != MP_OK) { |
262 | fprintf(stderr, format: "Line %d: Invalid output value [%s]\n" , t->line, str); |
263 | return false; |
264 | } |
265 | |
266 | if (out != NULL) out[i] = reg; |
267 | } |
268 | |
269 | return true; |
270 | } |
271 | |
272 | static bool parse_rat_values(testspec_t* t, mp_rat* in, mp_rat* out, |
273 | mp_result* rval) { |
274 | int pos = 0; |
275 | char* str; |
276 | |
277 | if (rval != NULL) *rval = MP_OK; /* default */ |
278 | |
279 | if (in != NULL) { |
280 | for (int i = 0; i < t->num_inputs; ++i) { |
281 | str = t->input[i]; |
282 | |
283 | trim_line(line: str); |
284 | |
285 | if (*str == '=') { |
286 | int k = abs(x: atoi(nptr: str + 1)) - 1; |
287 | |
288 | if (k < 0 || k >= i) { |
289 | fprintf(stderr, format: "Line %d: Invalid input back-reference [%s]\n" , |
290 | t->line, str); |
291 | return false; |
292 | } |
293 | |
294 | in[i] = in[k]; |
295 | } else { |
296 | mp_rat reg = g_qreg + pos++; /* grab next free register */ |
297 | |
298 | if (read_rat_value(q: reg, str) != MP_OK) { |
299 | fprintf(stderr, format: "Line %d: Invalid input value [%s]\n" , t->line, str); |
300 | return false; |
301 | } |
302 | |
303 | in[i] = reg; |
304 | } |
305 | } |
306 | } |
307 | |
308 | for (int i = 0; i < t->num_outputs; ++i) { |
309 | mp_rat reg = g_qreg + pos++; |
310 | |
311 | str = t->output[i]; |
312 | |
313 | trim_line(line: str); |
314 | |
315 | if (strcmp(s1: str, s2: "?" ) == 0) |
316 | mp_rat_zero(r: reg); |
317 | else if (*str == '$') { |
318 | mp_result code; |
319 | |
320 | if (!parse_result_code(str, code: &code)) { |
321 | fprintf(stderr, format: "Line %d: Invalid result code [%s]\n" , t->line, str); |
322 | return false; |
323 | } else if (rval == NULL) { |
324 | fprintf(stderr, format: "Line %d: Result code not permitted here [%s]\n" , |
325 | t->line, str); |
326 | return false; |
327 | } else |
328 | *rval = code; |
329 | |
330 | /* Provide a dummy value for the corresponding output */ |
331 | mp_rat_zero(r: reg); |
332 | } else if (out != NULL && read_rat_value(q: reg, str) != MP_OK) { |
333 | fprintf(stderr, format: "Line %d: Invalid output value [%s]\n" , t->line, str); |
334 | return false; |
335 | } |
336 | |
337 | if (out != NULL) out[i] = reg; |
338 | } |
339 | |
340 | return true; |
341 | } |
342 | |
343 | static bool parse_result_code(char* str, mp_result* code) { |
344 | if (str[0] == '$') { |
345 | if (str[1] == '#') { |
346 | long v; |
347 | |
348 | if (!read_long(z: &v, str: str + 2)) return false; |
349 | |
350 | *code = (mp_result)v; |
351 | } else if (strcmp(s1: str + 1, s2: "MP_OK" ) == 0 || |
352 | strcmp(s1: str + 1, s2: "MP_FALSE" ) == 0) { |
353 | *code = MP_OK; |
354 | } else if (strcmp(s1: str + 1, s2: "MP_TRUE" ) == 0) { |
355 | *code = MP_TRUE; |
356 | } else if (strcmp(s1: str + 1, s2: "MP_MEMORY" ) == 0) { |
357 | *code = MP_MEMORY; |
358 | } else if (strcmp(s1: str + 1, s2: "MP_RANGE" ) == 0) { |
359 | *code = MP_RANGE; |
360 | } else if (strcmp(s1: str + 1, s2: "MP_UNDEF" ) == 0) { |
361 | *code = MP_UNDEF; |
362 | } else if (strcmp(s1: str + 1, s2: "MP_TRUNC" ) == 0) { |
363 | *code = MP_TRUNC; |
364 | } else if (strcmp(s1: str + 1, s2: "MP_ROUND_UP" ) == 0) { |
365 | *code = MP_ROUND_UP; |
366 | } else if (strcmp(s1: str + 1, s2: "MP_ROUND_DOWN" ) == 0) { |
367 | *code = MP_ROUND_DOWN; |
368 | } else if (strcmp(s1: str + 1, s2: "MP_ROUND_HALF_UP" ) == 0) { |
369 | *code = MP_ROUND_HALF_UP; |
370 | } else if (strcmp(s1: str + 1, s2: "MP_ROUND_HALF_DOWN" ) == 0) { |
371 | *code = MP_ROUND_HALF_DOWN; |
372 | } else { |
373 | return false; |
374 | } |
375 | } |
376 | |
377 | return true; |
378 | } |
379 | |
380 | static int parse_binary(char* str, unsigned char* buf, int limit) { |
381 | int pos = 0; |
382 | char* tok; |
383 | |
384 | trim_line(line: str); |
385 | |
386 | for (tok = strtok(s: str, delim: "." ); tok != NULL && pos < limit; |
387 | tok = strtok(NULL, delim: "." )) { |
388 | long v; |
389 | |
390 | if (!read_long(z: &v, str: tok) || v > UCHAR_MAX || v < 0) return -1; |
391 | |
392 | buf[pos++] = (unsigned char)v; |
393 | } |
394 | |
395 | return pos; |
396 | } |
397 | |
398 | static void done_testing(void) { |
399 | int i; |
400 | |
401 | for (i = 0; i < NUM_REGS; ++i) { |
402 | mp_int_clear(z: g_zreg + i); |
403 | mp_rat_clear(r: g_qreg + i); |
404 | } |
405 | } |
406 | |
407 | /* |
408 | * Global functions visible to callers outside this file. |
409 | */ |
410 | |
411 | void init_testing(void) { |
412 | static int is_done = 0; |
413 | |
414 | if (is_done) return; |
415 | |
416 | for (int i = 0; i < NUM_REGS; ++i) { |
417 | assert(mp_int_init(g_zreg + i) == MP_OK); |
418 | assert(mp_rat_init(g_qreg + i) == MP_OK); |
419 | } |
420 | |
421 | imath_errmsg = g_output; |
422 | |
423 | assert(atexit(done_testing) == 0); |
424 | is_done = 1; |
425 | } |
426 | |
427 | void reset_registers(void) { |
428 | for (int i = 0; i < NUM_REGS; ++i) { |
429 | mp_int_zero(z: g_zreg + i); |
430 | mp_rat_zero(r: g_qreg + i); |
431 | } |
432 | } |
433 | |
434 | bool test_init(testspec_t* t, FILE* ofp) { |
435 | mp_int in[2], out[1]; |
436 | mp_small v; |
437 | mp_usmall uv; |
438 | mp_result expect; |
439 | |
440 | ACHECK(parse_int_values(t, in, out, &expect)); |
441 | |
442 | if (strcmp(s1: t->code, s2: "initu" ) == 0) { |
443 | CHECK(mp_int_to_uint(in[1], &uv)); |
444 | ECHECK(mp_int_init_uvalue(in[0], uv)); |
445 | } else { /* initv */ |
446 | CHECK(mp_int_to_int(in[1], &v)); |
447 | ECHECK(mp_int_init_value(in[0], v)); |
448 | } |
449 | |
450 | if (expect == MP_OK && mp_int_compare(a: in[0], b: out[0]) != 0) { |
451 | mp_int_to_string(z: in[0], radix: 10, str: g_output, OUTPUT_LIMIT); |
452 | FAIL(OTHER_ERROR); |
453 | } |
454 | |
455 | return true; |
456 | } |
457 | |
458 | bool test_set(testspec_t* t, FILE* ofp) { |
459 | mp_int in[2], out[1]; |
460 | mp_small v; |
461 | mp_usmall uv; |
462 | mp_result expect; |
463 | |
464 | ACHECK(parse_int_values(t, in, out, &expect)); |
465 | |
466 | if (strcmp(s1: t->code, s2: "setu" ) == 0) { |
467 | CHECK(mp_int_to_uint(in[1], &uv)); |
468 | ECHECK(mp_int_set_uvalue(in[0], uv)); |
469 | } else { /* setv */ |
470 | CHECK(mp_int_to_int(in[1], &v)); |
471 | ECHECK(mp_int_set_value(in[0], v)); |
472 | } |
473 | |
474 | if (expect == MP_OK && mp_int_compare(a: in[0], b: out[0]) != 0) { |
475 | mp_int_to_string(z: in[0], radix: 10, str: g_output, OUTPUT_LIMIT); |
476 | FAIL(OTHER_ERROR); |
477 | } |
478 | |
479 | return true; |
480 | } |
481 | |
482 | bool test_neg(testspec_t* t, FILE* ofp) { |
483 | mp_int in[2], out[1]; |
484 | mp_result expect; |
485 | |
486 | ACHECK(parse_int_values(t, in, out, &expect)); |
487 | ECHECK(mp_int_neg(in[0], in[1])); |
488 | |
489 | if (expect == MP_OK && mp_int_compare(a: in[1], b: out[0]) != 0) { |
490 | mp_int_to_string(z: in[1], radix: 10, str: g_output, OUTPUT_LIMIT); |
491 | FAIL(OTHER_ERROR); |
492 | } |
493 | |
494 | return true; |
495 | } |
496 | |
497 | bool test_abs(testspec_t* t, FILE* ofp) { |
498 | mp_int in[2], out[1]; |
499 | mp_result expect; |
500 | |
501 | ACHECK(parse_int_values(t, in, out, &expect)); |
502 | ECHECK(mp_int_abs(in[0], in[1])); |
503 | |
504 | if (expect == MP_OK && mp_int_compare(a: in[1], b: out[0]) != 0) { |
505 | mp_int_to_string(z: in[1], radix: 10, str: g_output, OUTPUT_LIMIT); |
506 | FAIL(OTHER_ERROR); |
507 | } |
508 | |
509 | return true; |
510 | } |
511 | |
512 | bool test_add(testspec_t* t, FILE* ofp) { |
513 | mp_int in[3], out[1]; |
514 | mp_small v; |
515 | mp_result expect; |
516 | |
517 | ACHECK(parse_int_values(t, in, out, &expect)); |
518 | |
519 | if (strcmp(s1: t->code, s2: "addv" ) == 0) { |
520 | CHECK(mp_int_to_int(in[1], &v)); |
521 | ECHECK(mp_int_add_value(in[0], v, in[2])); |
522 | } else { |
523 | ECHECK(mp_int_add(in[0], in[1], in[2])); |
524 | } |
525 | |
526 | if (expect == MP_OK && mp_int_compare(a: in[2], b: out[0]) != 0) { |
527 | mp_int_to_string(z: in[2], radix: 10, str: g_output, OUTPUT_LIMIT); |
528 | FAIL(OTHER_ERROR); |
529 | } |
530 | |
531 | return true; |
532 | } |
533 | |
534 | bool test_sub(testspec_t* t, FILE* ofp) { |
535 | mp_int in[3], out[1]; |
536 | mp_small v; |
537 | mp_result expect; |
538 | |
539 | ACHECK(parse_int_values(t, in, out, &expect)); |
540 | |
541 | if (strcmp(s1: t->code, s2: "subv" ) == 0) { |
542 | CHECK(mp_int_to_int(in[1], &v)); |
543 | ECHECK(mp_int_sub_value(in[0], v, in[2])); |
544 | } else { |
545 | ECHECK(mp_int_sub(in[0], in[1], in[2])); |
546 | } |
547 | |
548 | if (expect == MP_OK && mp_int_compare(a: in[2], b: out[0]) != 0) { |
549 | mp_int_to_string(z: in[2], radix: 10, str: g_output, OUTPUT_LIMIT); |
550 | FAIL(OTHER_ERROR); |
551 | } |
552 | return true; |
553 | } |
554 | |
555 | bool test_mul(testspec_t* t, FILE* ofp) { |
556 | mp_int in[3], out[1]; |
557 | mp_result expect; |
558 | |
559 | ACHECK(parse_int_values(t, in, out, &expect)); |
560 | ECHECK(mp_int_mul(in[0], in[1], in[2])); |
561 | |
562 | if (expect == MP_OK && mp_int_compare(a: in[2], b: out[0]) != 0) { |
563 | mp_int_to_string(z: in[2], radix: 10, str: g_output, OUTPUT_LIMIT); |
564 | FAIL(OTHER_ERROR); |
565 | } |
566 | return true; |
567 | } |
568 | |
569 | bool test_mulp2(testspec_t* t, FILE* ofp) { |
570 | mp_int in[3], out[1]; |
571 | mp_result expect; |
572 | mp_small p2; |
573 | |
574 | ACHECK(parse_int_values(t, in, out, &expect)); |
575 | CHECK(mp_int_to_int(in[1], &p2)); |
576 | ECHECK(mp_int_mul_pow2(in[0], p2, in[2])); |
577 | |
578 | if (expect == MP_OK && mp_int_compare(a: in[2], b: out[0]) != 0) { |
579 | mp_int_to_string(z: in[2], radix: 10, str: g_output, OUTPUT_LIMIT); |
580 | FAIL(OTHER_ERROR); |
581 | } |
582 | return true; |
583 | } |
584 | |
585 | bool test_mulv(testspec_t* t, FILE* ofp) { |
586 | mp_int in[3], out[1]; |
587 | mp_result expect; |
588 | mp_small v; |
589 | |
590 | ACHECK(parse_int_values(t, in, out, &expect)); |
591 | CHECK(mp_int_to_int(in[1], &v)); |
592 | ECHECK(mp_int_mul_value(in[0], v, in[2])); |
593 | |
594 | if (expect == MP_OK && mp_int_compare(a: in[2], b: out[0]) != 0) { |
595 | mp_int_to_string(z: in[2], radix: 10, str: g_output, OUTPUT_LIMIT); |
596 | FAIL(OTHER_ERROR); |
597 | } |
598 | return true; |
599 | } |
600 | |
601 | bool test_sqr(testspec_t* t, FILE* ofp) { |
602 | mp_int in[2], out[1]; |
603 | mp_result expect; |
604 | |
605 | ACHECK(parse_int_values(t, in, out, &expect)); |
606 | ECHECK(mp_int_sqr(in[0], in[1])); |
607 | |
608 | if (expect == MP_OK && mp_int_compare(a: in[1], b: out[0]) != 0) { |
609 | mp_int_to_string(z: in[1], radix: 10, str: g_output, OUTPUT_LIMIT); |
610 | FAIL(OTHER_ERROR); |
611 | } |
612 | return true; |
613 | } |
614 | |
615 | bool test_div(testspec_t* t, FILE* ofp) { |
616 | mp_int in[4], out[2]; |
617 | mp_result expect; |
618 | |
619 | ACHECK(parse_int_values(t, in, out, &expect)); |
620 | ECHECK(mp_int_div(in[0], in[1], in[2], in[3])); |
621 | |
622 | if (expect == MP_OK && ((mp_int_compare(a: in[2], b: out[0]) != 0) || |
623 | (mp_int_compare(a: in[3], b: out[1]) != 0))) { |
624 | int len; |
625 | char* str; |
626 | |
627 | mp_int_to_string(z: in[2], radix: 10, str: g_output, OUTPUT_LIMIT); |
628 | str = g_output + (len = strlen(s: g_output)); |
629 | *str++ = ','; |
630 | mp_int_to_string(z: in[3], radix: 10, str, OUTPUT_LIMIT - (len + 1)); |
631 | FAIL(OTHER_ERROR); |
632 | } |
633 | return true; |
634 | } |
635 | |
636 | bool test_divp2(testspec_t* t, FILE* ofp) { |
637 | mp_int in[4], out[2]; |
638 | mp_result expect; |
639 | mp_small p2; |
640 | |
641 | ACHECK(parse_int_values(t, in, out, &expect)); |
642 | CHECK(mp_int_to_int(in[1], &p2)); |
643 | ECHECK(mp_int_div_pow2(in[0], p2, in[2], in[3])); |
644 | |
645 | if (expect == MP_OK && ((mp_int_compare(a: in[2], b: out[0]) != 0) || |
646 | (mp_int_compare(a: in[3], b: out[1]) != 0))) { |
647 | int len; |
648 | char* str; |
649 | |
650 | mp_int_to_string(z: in[2], radix: 10, str: g_output, OUTPUT_LIMIT); |
651 | str = g_output + (len = strlen(s: g_output)); |
652 | *str++ = ','; |
653 | mp_int_to_string(z: in[3], radix: 10, str, OUTPUT_LIMIT - (len + 1)); |
654 | FAIL(OTHER_ERROR); |
655 | } |
656 | return true; |
657 | } |
658 | |
659 | bool test_divv(testspec_t* t, FILE* ofp) { |
660 | mp_int in[3], out[2]; |
661 | mp_result expect; |
662 | mp_small v, rem, orem; |
663 | |
664 | ACHECK(parse_int_values(t, in, out, &expect)); |
665 | CHECK(mp_int_to_int(in[1], &v)); |
666 | CHECK(mp_int_to_int(out[1], &orem)); |
667 | ECHECK(mp_int_div_value(in[0], v, in[2], &rem)); |
668 | |
669 | if (expect == MP_OK && |
670 | ((mp_int_compare(a: in[2], b: out[0]) != 0) || (rem != orem))) { |
671 | char* str; |
672 | |
673 | mp_int_to_string(z: in[2], radix: 10, str: g_output, OUTPUT_LIMIT); |
674 | str = g_output + strlen(s: g_output); |
675 | *str++ = ','; |
676 | sprintf(s: str, format: "%ld" , rem); |
677 | FAIL(OTHER_ERROR); |
678 | } |
679 | return true; |
680 | } |
681 | |
682 | bool test_expt(testspec_t* t, FILE* ofp) { |
683 | mp_int in[3], out[1]; |
684 | mp_result expect; |
685 | mp_small pow; |
686 | |
687 | ACHECK(parse_int_values(t, in, out, &expect)); |
688 | CHECK(mp_int_to_int(in[1], &pow)); |
689 | ECHECK(mp_int_expt(in[0], pow, in[2])); |
690 | |
691 | if (expect == MP_OK && mp_int_compare(a: in[2], b: out[0]) != 0) { |
692 | mp_int_to_string(z: in[2], radix: 10, str: g_output, OUTPUT_LIMIT); |
693 | FAIL(OTHER_ERROR); |
694 | } |
695 | return true; |
696 | } |
697 | |
698 | bool test_exptv(testspec_t* t, FILE* ofp) { |
699 | mp_int in[3], out[1]; |
700 | mp_result expect; |
701 | mp_small a, b; |
702 | |
703 | ACHECK(parse_int_values(t, in, out, &expect)); |
704 | CHECK(mp_int_to_int(in[0], &a)); |
705 | CHECK(mp_int_to_int(in[1], &b)); |
706 | ECHECK(mp_int_expt_value(a, b, in[2])); |
707 | |
708 | if (expect == MP_OK && mp_int_compare(a: in[2], b: out[0]) != 0) { |
709 | mp_int_to_string(z: in[2], radix: 10, str: g_output, OUTPUT_LIMIT); |
710 | FAIL(OTHER_ERROR); |
711 | } |
712 | return true; |
713 | } |
714 | |
715 | bool test_exptf(testspec_t* t, FILE* ofp) { |
716 | mp_int in[3], out[1]; |
717 | mp_result expect; |
718 | |
719 | ACHECK(parse_int_values(t, in, out, &expect)); |
720 | ECHECK(mp_int_expt_full(in[0], in[1], in[2])); |
721 | |
722 | if (expect == MP_OK && mp_int_compare(a: in[2], b: out[0]) != 0) { |
723 | mp_int_to_string(z: in[2], radix: 10, str: g_output, OUTPUT_LIMIT); |
724 | FAIL(OTHER_ERROR); |
725 | } |
726 | return true; |
727 | } |
728 | |
729 | bool test_mod(testspec_t* t, FILE* ofp) { |
730 | mp_int in[3], out[1]; |
731 | mp_result expect; |
732 | |
733 | ACHECK(parse_int_values(t, in, out, &expect)); |
734 | ECHECK(mp_int_mod(in[0], in[1], in[2])); |
735 | |
736 | if (expect == MP_OK && mp_int_compare(a: in[2], b: out[0]) != 0) { |
737 | mp_int_to_string(z: in[2], radix: 10, str: g_output, OUTPUT_LIMIT); |
738 | FAIL(OTHER_ERROR); |
739 | } |
740 | return true; |
741 | } |
742 | |
743 | bool test_gcd(testspec_t* t, FILE* ofp) { |
744 | mp_int in[3], out[1]; |
745 | mp_result expect; |
746 | |
747 | ACHECK(parse_int_values(t, in, out, &expect)); |
748 | ECHECK(mp_int_gcd(in[0], in[1], in[2])); |
749 | |
750 | if (expect == MP_OK && mp_int_compare(a: in[2], b: out[0]) != 0) { |
751 | mp_int_to_string(z: in[2], radix: 10, str: g_output, OUTPUT_LIMIT); |
752 | FAIL(OTHER_ERROR); |
753 | } |
754 | return true; |
755 | } |
756 | |
757 | bool test_egcd(testspec_t* t, FILE* ofp) { |
758 | mp_int in[5], out[3], t1 = g_zreg + 8, t2 = g_zreg + 9; |
759 | mp_result expect; |
760 | |
761 | ACHECK(parse_int_values(t, in, out, &expect)); |
762 | ECHECK(mp_int_egcd(in[0], in[1], in[2], in[3], in[4])); |
763 | |
764 | /* If we got an error we expected, return success immediately */ |
765 | if (expect != MP_OK) return true; |
766 | |
767 | if ((mp_int_compare(a: in[2], b: out[0]) != 0) || |
768 | (mp_int_compare(a: in[3], b: out[1]) != 0) || |
769 | (mp_int_compare(a: in[4], b: out[2]) != 0)) { |
770 | int len, len2; |
771 | char* str; |
772 | |
773 | /* Failure might occur because the tester computed x and y in a different |
774 | way than we did. Verify that the results are correct before reporting |
775 | an error. */ |
776 | mp_int_mul(a: in[3], b: in[0], c: t1); |
777 | mp_int_mul(a: in[4], b: in[1], c: t2); |
778 | mp_int_add(a: t1, b: t2, c: t2); |
779 | if (mp_int_compare(a: t2, b: in[2]) == 0) return true; |
780 | |
781 | mp_int_to_string(z: in[2], radix: 10, str: g_output, OUTPUT_LIMIT); |
782 | str = g_output + (len = strlen(s: g_output)); |
783 | *str++ = ','; |
784 | mp_int_to_string(z: in[3], radix: 10, str, OUTPUT_LIMIT - (len + 1)); |
785 | str = str + (len2 = strlen(s: str)); |
786 | *str++ = ','; |
787 | mp_int_to_string(z: in[4], radix: 10, str, OUTPUT_LIMIT - (len + len2 + 2)); |
788 | FAIL(OTHER_ERROR); |
789 | } |
790 | return true; |
791 | } |
792 | |
793 | bool test_lcm(testspec_t* t, FILE* ofp) { |
794 | mp_int in[3], out[1]; |
795 | mp_result expect; |
796 | |
797 | ACHECK(parse_int_values(t, in, out, &expect)); |
798 | ECHECK(mp_int_lcm(in[0], in[1], in[2])); |
799 | |
800 | if (expect == MP_OK && mp_int_compare(a: in[2], b: out[0]) != 0) { |
801 | mp_int_to_string(z: in[2], radix: 10, str: g_output, OUTPUT_LIMIT); |
802 | FAIL(OTHER_ERROR); |
803 | } |
804 | return true; |
805 | } |
806 | |
807 | bool test_sqrt(testspec_t* t, FILE* ofp) { |
808 | mp_int in[2], out[1]; |
809 | mp_result expect; |
810 | |
811 | ACHECK(parse_int_values(t, in, out, &expect)); |
812 | ECHECK(mp_int_sqrt(in[0], in[1])); |
813 | |
814 | if (expect == MP_OK && mp_int_compare(a: in[1], b: out[0]) != 0) { |
815 | mp_int_to_string(z: in[1], radix: 10, str: g_output, OUTPUT_LIMIT); |
816 | FAIL(OTHER_ERROR); |
817 | } |
818 | return true; |
819 | } |
820 | |
821 | bool test_root(testspec_t* t, FILE* ofp) { |
822 | mp_int in[3], out[1]; |
823 | mp_small v; |
824 | mp_result expect; |
825 | |
826 | ACHECK(parse_int_values(t, in, out, &expect)); |
827 | CHECK(mp_int_to_int(in[1], &v)); |
828 | ECHECK(mp_int_root(in[0], v, in[2])); |
829 | |
830 | if (expect == MP_OK && mp_int_compare(a: in[2], b: out[0]) != 0) { |
831 | mp_int_to_string(z: in[2], radix: 10, str: g_output, OUTPUT_LIMIT); |
832 | FAIL(OTHER_ERROR); |
833 | } |
834 | return true; |
835 | } |
836 | |
837 | bool test_invmod(testspec_t* t, FILE* ofp) { |
838 | mp_int in[3], out[1]; |
839 | mp_result expect; |
840 | |
841 | ACHECK(parse_int_values(t, in, out, &expect)); |
842 | ECHECK(mp_int_invmod(in[0], in[1], in[2])); |
843 | |
844 | if (expect == MP_OK && mp_int_compare(a: in[2], b: out[0]) != 0) { |
845 | mp_int_to_string(z: in[2], radix: 10, str: g_output, OUTPUT_LIMIT); |
846 | FAIL(OTHER_ERROR); |
847 | } |
848 | return true; |
849 | } |
850 | |
851 | bool test_exptmod(testspec_t* t, FILE* ofp) { |
852 | mp_int in[4], out[1]; |
853 | mp_result expect; |
854 | |
855 | ACHECK(parse_int_values(t, in, out, &expect)); |
856 | ECHECK(mp_int_exptmod(in[0], in[1], in[2], in[3])); |
857 | |
858 | if (expect == MP_OK && mp_int_compare(a: in[3], b: out[0]) != 0) { |
859 | mp_int_to_string(z: in[3], radix: 10, str: g_output, OUTPUT_LIMIT); |
860 | FAIL(OTHER_ERROR); |
861 | } |
862 | return true; |
863 | } |
864 | |
865 | bool test_exptmod_ev(testspec_t* t, FILE* ofp) { |
866 | mp_int in[4], out[1]; |
867 | mp_result expect; |
868 | mp_small v; |
869 | |
870 | ACHECK(parse_int_values(t, in, out, &expect)); |
871 | CHECK(mp_int_to_int(in[1], &v)); |
872 | ECHECK(mp_int_exptmod_evalue(in[0], v, in[2], in[3])); |
873 | |
874 | if (expect == MP_OK && mp_int_compare(a: in[3], b: out[0]) != 0) { |
875 | mp_int_to_string(z: in[3], radix: 10, str: g_output, OUTPUT_LIMIT); |
876 | FAIL(OTHER_ERROR); |
877 | } |
878 | return true; |
879 | } |
880 | |
881 | bool test_exptmod_bv(testspec_t* t, FILE* ofp) { |
882 | mp_int in[4], out[1]; |
883 | mp_result expect; |
884 | mp_small v; |
885 | |
886 | ACHECK(parse_int_values(t, in, out, &expect)); |
887 | CHECK(mp_int_to_int(in[0], &v)); |
888 | ECHECK(mp_int_exptmod_bvalue(v, in[1], in[2], in[3])); |
889 | |
890 | if (expect == MP_OK && mp_int_compare(a: in[3], b: out[0]) != 0) { |
891 | mp_int_to_string(z: in[3], radix: 10, str: g_output, OUTPUT_LIMIT); |
892 | FAIL(OTHER_ERROR); |
893 | } |
894 | return true; |
895 | } |
896 | |
897 | bool test_comp(testspec_t* t, FILE* ofp) { |
898 | mp_int in[2]; |
899 | mp_result res, expect; |
900 | |
901 | ACHECK(parse_int_values(t, in, NULL, &expect)); |
902 | |
903 | if ((res = mp_int_compare(a: in[0], b: in[1])) != expect) { |
904 | sprintf(s: g_output, format: "Incorrect comparison result (want %d, got %d)" , expect, |
905 | res); |
906 | FAIL(OTHER_ERROR); |
907 | } |
908 | return true; |
909 | } |
910 | |
911 | bool test_ucomp(testspec_t* t, FILE* ofp) { |
912 | mp_int in[2]; |
913 | mp_result res, expect; |
914 | |
915 | ACHECK(parse_int_values(t, in, NULL, &expect)); |
916 | |
917 | if ((res = mp_int_compare_unsigned(a: in[0], b: in[1])) != expect) { |
918 | sprintf(s: g_output, format: "Incorrect comparison result (want %d, got %d)" , expect, |
919 | res); |
920 | FAIL(OTHER_ERROR); |
921 | } |
922 | return true; |
923 | } |
924 | |
925 | bool test_zcomp(testspec_t* t, FILE* ofp) { |
926 | mp_int in[1]; |
927 | mp_result res, expect; |
928 | |
929 | ACHECK(parse_int_values(t, in, NULL, &expect)); |
930 | |
931 | if ((res = mp_int_compare_zero(z: in[0])) != expect) { |
932 | sprintf(s: g_output, format: "Incorrect comparison result (want %d, got %d)" , expect, |
933 | res); |
934 | FAIL(OTHER_ERROR); |
935 | } |
936 | return true; |
937 | } |
938 | |
939 | bool test_vcomp(testspec_t* t, FILE* ofp) { |
940 | mp_int in[2]; |
941 | mp_result res, expect; |
942 | mp_small v; |
943 | |
944 | ACHECK(parse_int_values(t, in, NULL, &expect)); |
945 | |
946 | v = atoi(nptr: t->input[1]); |
947 | if ((res = mp_int_compare_value(z: in[0], v)) != expect) { |
948 | sprintf(s: g_output, format: "Incorrect comparison result (want %d, got %d)" , expect, |
949 | res); |
950 | FAIL(OTHER_ERROR); |
951 | } |
952 | return true; |
953 | } |
954 | |
955 | bool test_uvcomp(testspec_t* t, FILE* ofp) { |
956 | mp_int in[2]; |
957 | mp_result res, expect; |
958 | mp_usmall v; |
959 | |
960 | ACHECK(parse_int_values(t, in, NULL, &expect)); |
961 | |
962 | v = strtoul(nptr: t->input[1], NULL, base: 0); |
963 | if ((res = mp_int_compare_uvalue(z: in[0], uv: v)) != expect) { |
964 | sprintf(s: g_output, format: "Incorrect comparison result (want %d, got %d)" , expect, |
965 | res); |
966 | FAIL(OTHER_ERROR); |
967 | } |
968 | return true; |
969 | } |
970 | |
971 | bool test_tostr(testspec_t* t, FILE* ofp) { |
972 | mp_int in[2]; |
973 | mp_small radix; |
974 | mp_result len; |
975 | |
976 | ACHECK(parse_int_values(t, in, NULL, NULL)); |
977 | ACHECK(mp_int_to_int(in[1], &radix) == MP_OK); |
978 | |
979 | if (radix < MP_MIN_RADIX || radix > MP_MAX_RADIX) FAIL(MP_RANGE); |
980 | |
981 | trim_line(line: t->output[0]); |
982 | len = mp_int_string_len(z: in[0], radix); |
983 | |
984 | CHECK(mp_int_to_string(in[0], radix, g_output, len)); |
985 | |
986 | if (strcmp(s1: t->output[0], s2: g_output) != 0) FAIL(OTHER_ERROR); |
987 | |
988 | return true; |
989 | } |
990 | |
991 | bool test_tobin(testspec_t* t, FILE* ofp) { |
992 | mp_int in[1]; |
993 | int test_len, out_len; |
994 | |
995 | ACHECK(parse_int_values(t, in, NULL, NULL)); |
996 | |
997 | trim_line(line: t->output[0]); |
998 | if ((out_len = parse_binary(str: t->output[0], buf: g_bin1, limit: sizeof(g_bin1))) < 0) |
999 | FAIL(MP_BADARG); |
1000 | |
1001 | if ((test_len = mp_int_binary_len(z: in[0])) != out_len) { |
1002 | sprintf(s: g_output, format: "Output lengths do not match (want %d, got %d)" , test_len, |
1003 | out_len); |
1004 | FAIL(OTHER_ERROR); |
1005 | } |
1006 | |
1007 | CHECK(mp_int_to_binary(in[0], g_bin2, sizeof(g_bin2))); |
1008 | |
1009 | if (memcmp(s1: g_bin1, s2: g_bin2, n: test_len) != 0) { |
1010 | int pos = 0, i; |
1011 | |
1012 | for (i = 0; i < test_len - 1; ++i) |
1013 | pos += sprintf(s: g_output + pos, format: "%d." , g_bin2[i]); |
1014 | |
1015 | sprintf(s: g_output + pos, format: "%d" , g_bin2[i]); |
1016 | FAIL(OTHER_ERROR); |
1017 | } |
1018 | return true; |
1019 | } |
1020 | |
1021 | bool test_to_int(testspec_t* t, FILE* ofp) { |
1022 | mp_int in[1], out[1]; |
1023 | mp_small v; |
1024 | mp_result expect; |
1025 | |
1026 | ACHECK(parse_int_values(t, in, out, &expect)); |
1027 | ECHECK(mp_int_to_int(in[0], &v)); |
1028 | |
1029 | if (expect == MP_OK && mp_int_compare_value(z: out[0], v) != 0) { |
1030 | sprintf(s: g_output, format: "Incorrect value (got %ld)" , v); |
1031 | FAIL(OTHER_ERROR); |
1032 | } |
1033 | return true; |
1034 | } |
1035 | |
1036 | bool test_to_uint(testspec_t* t, FILE* ofp) { |
1037 | mp_int in[1], out[1]; |
1038 | mp_usmall v; |
1039 | mp_result expect; |
1040 | |
1041 | ACHECK(parse_int_values(t, in, out, &expect)); |
1042 | ECHECK(mp_int_to_uint(in[0], &v)); |
1043 | |
1044 | if (expect == MP_OK && mp_int_compare_uvalue(z: out[0], uv: v) != 0) { |
1045 | sprintf(s: g_output, format: "Incorrect value (got %lu)" , v); |
1046 | FAIL(OTHER_ERROR); |
1047 | } |
1048 | return true; |
1049 | } |
1050 | |
1051 | bool test_read_binary(testspec_t* t, FILE* ofp) { |
1052 | mp_int out[1], in = g_zreg + 1; |
1053 | int in_len; |
1054 | mp_result expect; |
1055 | |
1056 | ACHECK(parse_int_values(t, NULL, out, &expect)); |
1057 | |
1058 | trim_line(line: t->input[0]); |
1059 | if ((in_len = parse_binary(str: t->input[0], buf: g_bin1, limit: sizeof(g_bin1))) < 0) |
1060 | FAIL(MP_BADARG); |
1061 | |
1062 | ECHECK(mp_int_read_binary(in, g_bin1, in_len)); |
1063 | |
1064 | if (expect == MP_OK && mp_int_compare(a: in, b: out[0]) != 0) { |
1065 | mp_int_to_string(z: in, radix: 10, str: g_output, OUTPUT_LIMIT); |
1066 | FAIL(OTHER_ERROR); |
1067 | } |
1068 | return true; |
1069 | } |
1070 | |
1071 | bool test_to_uns(testspec_t* t, FILE* ofp) { |
1072 | mp_int in[1]; |
1073 | int test_len, out_len; |
1074 | |
1075 | ACHECK(parse_int_values(t, in, NULL, NULL)); |
1076 | |
1077 | trim_line(line: t->output[0]); |
1078 | if ((out_len = parse_binary(str: t->output[0], buf: g_bin1, limit: sizeof(g_bin1))) < 0) |
1079 | FAIL(MP_BADARG); |
1080 | |
1081 | if ((test_len = mp_int_unsigned_len(z: in[0])) != out_len) { |
1082 | sprintf(s: g_output, format: "Output lengths do not match (want %d, got %d)" , test_len, |
1083 | out_len); |
1084 | FAIL(OTHER_ERROR); |
1085 | } |
1086 | |
1087 | CHECK(mp_int_to_unsigned(in[0], g_bin2, sizeof(g_bin2))); |
1088 | |
1089 | if (memcmp(s1: g_bin1, s2: g_bin2, n: test_len) != 0) { |
1090 | int pos = 0, i; |
1091 | |
1092 | for (i = 0; i < test_len - 1; ++i) |
1093 | pos += sprintf(s: g_output + pos, format: "%d." , g_bin2[i]); |
1094 | |
1095 | sprintf(s: g_output + pos, format: "%d" , g_bin2[i]); |
1096 | FAIL(OTHER_ERROR); |
1097 | } |
1098 | return true; |
1099 | } |
1100 | |
1101 | bool test_read_uns(testspec_t* t, FILE* ofp) { |
1102 | mp_int out[1], in = g_zreg + 1; |
1103 | int in_len; |
1104 | mp_result expect; |
1105 | |
1106 | ACHECK(parse_int_values(t, NULL, out, &expect)); |
1107 | |
1108 | trim_line(line: t->input[0]); |
1109 | if ((in_len = parse_binary(str: t->input[0], buf: g_bin1, limit: sizeof(g_bin1))) < 0) |
1110 | FAIL(MP_BADARG); |
1111 | |
1112 | ECHECK(mp_int_read_unsigned(in, g_bin1, in_len)); |
1113 | |
1114 | if (expect == MP_OK && mp_int_compare(a: in, b: out[0]) != 0) { |
1115 | mp_int_to_string(z: in, radix: 10, str: g_output, OUTPUT_LIMIT); |
1116 | FAIL(OTHER_ERROR); |
1117 | } |
1118 | return true; |
1119 | } |
1120 | |
1121 | bool test_meta(testspec_t* t, FILE* ofp) { |
1122 | mp_int *in = NULL, *out = NULL; |
1123 | int i, j; |
1124 | mp_result expect; |
1125 | |
1126 | if (t->num_inputs > 0) { |
1127 | in = calloc(nmemb: t->num_inputs, size: sizeof(mp_int)); |
1128 | } |
1129 | if (t->num_outputs > 0) { |
1130 | out = calloc(nmemb: t->num_outputs, size: sizeof(mp_int)); |
1131 | } |
1132 | |
1133 | if (!parse_int_values(t, in, out, rval: &expect)) { |
1134 | if (in != NULL) free(ptr: in); |
1135 | if (out != NULL) free(ptr: out); |
1136 | FAIL(MP_BADARG); |
1137 | } |
1138 | |
1139 | fprintf(stream: ofp, format: "Test '%s' defined at line %d\n" , t->code, t->line); |
1140 | fprintf(stream: ofp, format: "Expected result: %d\n" , expect); |
1141 | fprintf(stream: ofp, format: "Input values: %d\n" , t->num_inputs); |
1142 | for (i = 0; i < t->num_inputs; ++i) { |
1143 | mp_int_to_string(z: in[i], radix: 10, str: g_output, OUTPUT_LIMIT); |
1144 | |
1145 | fprintf(stream: ofp, format: " %2d.) %s" , i + 1, g_output); |
1146 | |
1147 | for (j = i - 1; j >= 0; --j) |
1148 | if (in[j] == in[i]) { |
1149 | fprintf(stream: ofp, format: " (=> %d)" , j + 1); |
1150 | break; |
1151 | } |
1152 | |
1153 | fputc(c: '\n', stream: ofp); |
1154 | } |
1155 | fprintf(stream: ofp, format: "Output values: %d\n" , t->num_outputs); |
1156 | for (i = 0; i < t->num_outputs; ++i) { |
1157 | mp_int_to_string(z: out[i], radix: 10, str: g_output, OUTPUT_LIMIT); |
1158 | |
1159 | fprintf(stream: ofp, format: " %2d.) %s\n" , i + 1, g_output); |
1160 | } |
1161 | if (in != NULL) free(ptr: in); |
1162 | if (out != NULL) free(ptr: out); |
1163 | return true; |
1164 | } |
1165 | |
1166 | bool test_qneg(testspec_t* t, FILE* ofp) { |
1167 | mp_rat in[2], out[1]; |
1168 | mp_result expect; |
1169 | |
1170 | ACHECK(parse_rat_values(t, in, out, &expect)); |
1171 | ECHECK(mp_rat_neg(in[0], in[1])); |
1172 | |
1173 | if (expect == MP_OK && mp_rat_compare(a: in[1], b: out[0]) != 0) { |
1174 | mp_rat_to_string(r: in[1], radix: 10, str: g_output, OUTPUT_LIMIT); |
1175 | FAIL(OTHER_ERROR); |
1176 | } |
1177 | return true; |
1178 | } |
1179 | |
1180 | bool test_qrecip(testspec_t* t, FILE* ofp) { |
1181 | mp_rat in[2], out[1]; |
1182 | mp_result expect; |
1183 | |
1184 | ACHECK(parse_rat_values(t, in, out, &expect)); |
1185 | ECHECK(mp_rat_recip(in[0], in[1])); |
1186 | |
1187 | if (expect == MP_OK && mp_rat_compare(a: in[1], b: out[0]) != 0) { |
1188 | mp_rat_to_string(r: in[1], radix: 10, str: g_output, OUTPUT_LIMIT); |
1189 | FAIL(OTHER_ERROR); |
1190 | } |
1191 | return true; |
1192 | } |
1193 | |
1194 | bool test_qabs(testspec_t* t, FILE* ofp) { |
1195 | mp_rat in[2], out[1]; |
1196 | mp_result expect; |
1197 | |
1198 | ACHECK(parse_rat_values(t, in, out, &expect)); |
1199 | ECHECK(mp_rat_abs(in[0], in[1])); |
1200 | |
1201 | if (expect == MP_OK && mp_rat_compare(a: in[1], b: out[0]) != 0) { |
1202 | mp_rat_to_string(r: in[1], radix: 10, str: g_output, OUTPUT_LIMIT); |
1203 | FAIL(OTHER_ERROR); |
1204 | } |
1205 | return true; |
1206 | } |
1207 | |
1208 | bool test_qadd(testspec_t* t, FILE* ofp) { |
1209 | mp_rat in[3], out[1]; |
1210 | mp_result expect; |
1211 | |
1212 | ACHECK(parse_rat_values(t, in, out, &expect)); |
1213 | ECHECK(mp_rat_add(in[0], in[1], in[2])); |
1214 | |
1215 | if (expect == MP_OK && mp_rat_compare(a: in[2], b: out[0]) != 0) { |
1216 | mp_rat_to_string(r: in[2], radix: 10, str: g_output, OUTPUT_LIMIT); |
1217 | FAIL(OTHER_ERROR); |
1218 | } |
1219 | return true; |
1220 | } |
1221 | |
1222 | bool test_qsub(testspec_t* t, FILE* ofp) { |
1223 | mp_rat in[3], out[1]; |
1224 | mp_result expect; |
1225 | |
1226 | ACHECK(parse_rat_values(t, in, out, &expect)); |
1227 | ECHECK(mp_rat_sub(in[0], in[1], in[2])); |
1228 | |
1229 | if (expect == MP_OK && mp_rat_compare(a: in[2], b: out[0]) != 0) { |
1230 | mp_rat_to_string(r: in[2], radix: 10, str: g_output, OUTPUT_LIMIT); |
1231 | FAIL(OTHER_ERROR); |
1232 | } |
1233 | return true; |
1234 | } |
1235 | |
1236 | bool test_qmul(testspec_t* t, FILE* ofp) { |
1237 | mp_rat in[3], out[1]; |
1238 | mp_result expect; |
1239 | |
1240 | ACHECK(parse_rat_values(t, in, out, &expect)); |
1241 | ECHECK(mp_rat_mul(in[0], in[1], in[2])); |
1242 | |
1243 | if (expect == MP_OK && mp_rat_compare(a: in[2], b: out[0]) != 0) { |
1244 | mp_rat_to_string(r: in[2], radix: 10, str: g_output, OUTPUT_LIMIT); |
1245 | FAIL(OTHER_ERROR); |
1246 | } |
1247 | return true; |
1248 | } |
1249 | |
1250 | bool test_qdiv(testspec_t* t, FILE* ofp) { |
1251 | mp_rat in[3], out[1]; |
1252 | mp_result expect; |
1253 | |
1254 | ACHECK(parse_rat_values(t, in, out, &expect)); |
1255 | ECHECK(mp_rat_div(in[0], in[1], in[2])); |
1256 | |
1257 | if (expect == MP_OK && mp_rat_compare(a: in[2], b: out[0]) != 0) { |
1258 | mp_rat_to_string(r: in[2], radix: 10, str: g_output, OUTPUT_LIMIT); |
1259 | FAIL(OTHER_ERROR); |
1260 | } |
1261 | return true; |
1262 | } |
1263 | |
1264 | bool test_qaddz(testspec_t* t, FILE* ofp) { |
1265 | mp_rat in[3], out[1]; |
1266 | mp_result expect; |
1267 | |
1268 | ACHECK(parse_rat_values(t, in, out, &expect)); |
1269 | |
1270 | if (!mp_rat_is_integer(r: in[1])) { |
1271 | fprintf(stderr, |
1272 | format: "Line %d: Second argument must be an integer (test_qaddz)\n" , |
1273 | t->line); |
1274 | FAIL(MP_BADARG); |
1275 | } |
1276 | |
1277 | ECHECK(mp_rat_add_int(in[0], MP_NUMER_P(in[1]), in[2])); |
1278 | |
1279 | if (expect == MP_OK && mp_rat_compare(a: in[2], b: out[0]) != 0) { |
1280 | mp_rat_to_string(r: in[2], radix: 10, str: g_output, OUTPUT_LIMIT); |
1281 | FAIL(OTHER_ERROR); |
1282 | } |
1283 | return true; |
1284 | } |
1285 | |
1286 | bool test_qsubz(testspec_t* t, FILE* ofp) { |
1287 | mp_rat in[3], out[1]; |
1288 | mp_result expect; |
1289 | |
1290 | ACHECK(parse_rat_values(t, in, out, &expect)); |
1291 | |
1292 | if (!mp_rat_is_integer(r: in[1])) { |
1293 | fprintf(stderr, |
1294 | format: "Line %d: Second argument must be an integer (test_qsubz)\n" , |
1295 | t->line); |
1296 | FAIL(MP_BADARG); |
1297 | } |
1298 | |
1299 | ECHECK(mp_rat_sub_int(in[0], MP_NUMER_P(in[1]), in[2])); |
1300 | |
1301 | if (expect == MP_OK && mp_rat_compare(a: in[2], b: out[0]) != 0) { |
1302 | mp_rat_to_string(r: in[2], radix: 10, str: g_output, OUTPUT_LIMIT); |
1303 | FAIL(OTHER_ERROR); |
1304 | } |
1305 | return true; |
1306 | } |
1307 | |
1308 | bool test_qmulz(testspec_t* t, FILE* ofp) { |
1309 | mp_rat in[3], out[1]; |
1310 | mp_result expect; |
1311 | |
1312 | ACHECK(parse_rat_values(t, in, out, &expect)); |
1313 | |
1314 | if (!mp_rat_is_integer(r: in[1])) { |
1315 | fprintf(stderr, |
1316 | format: "Line %d: Second argument must be an integer (test_qmulz)\n" , |
1317 | t->line); |
1318 | FAIL(MP_BADARG); |
1319 | } |
1320 | |
1321 | ECHECK(mp_rat_mul_int(in[0], MP_NUMER_P(in[1]), in[2])); |
1322 | |
1323 | if (expect == MP_OK && mp_rat_compare(a: in[2], b: out[0]) != 0) { |
1324 | mp_rat_to_string(r: in[2], radix: 10, str: g_output, OUTPUT_LIMIT); |
1325 | FAIL(OTHER_ERROR); |
1326 | } |
1327 | return true; |
1328 | } |
1329 | |
1330 | bool test_qdivz(testspec_t* t, FILE* ofp) { |
1331 | mp_rat in[3], out[1]; |
1332 | mp_result expect; |
1333 | |
1334 | ACHECK(parse_rat_values(t, in, out, &expect)); |
1335 | |
1336 | if (!mp_rat_is_integer(r: in[1])) { |
1337 | fprintf(stderr, |
1338 | format: "Line %d: Second argument must be an integer (test_qdivz)\n" , |
1339 | t->line); |
1340 | FAIL(MP_BADARG); |
1341 | } |
1342 | |
1343 | ECHECK(mp_rat_div_int(in[0], MP_NUMER_P(in[1]), in[2])); |
1344 | |
1345 | if (expect == MP_OK && mp_rat_compare(a: in[2], b: out[0]) != 0) { |
1346 | mp_rat_to_string(r: in[2], radix: 10, str: g_output, OUTPUT_LIMIT); |
1347 | FAIL(OTHER_ERROR); |
1348 | } |
1349 | return true; |
1350 | } |
1351 | |
1352 | bool test_qexpt(testspec_t* t, FILE* ofp) { |
1353 | mp_rat in[3], out[1]; |
1354 | mp_result expect; |
1355 | mp_small power; |
1356 | |
1357 | ACHECK(parse_rat_values(t, in, out, &expect)); |
1358 | |
1359 | if (!mp_rat_is_integer(r: in[1])) { |
1360 | fprintf(stderr, |
1361 | format: "Line %d: Second argument must be an integer (test_qexpt)\n" , |
1362 | t->line); |
1363 | FAIL(MP_BADARG); |
1364 | } |
1365 | |
1366 | CHECK(mp_int_to_int(MP_NUMER_P(in[1]), &power)); |
1367 | ECHECK(mp_rat_expt(in[0], power, in[2])); |
1368 | |
1369 | if (expect == MP_OK && mp_rat_compare(a: in[2], b: out[0]) != 0) { |
1370 | mp_rat_to_string(r: in[2], radix: 10, str: g_output, OUTPUT_LIMIT); |
1371 | FAIL(OTHER_ERROR); |
1372 | } |
1373 | return true; |
1374 | } |
1375 | |
1376 | bool test_qtostr(testspec_t* t, FILE* ofp) { |
1377 | mp_rat in[2]; |
1378 | long radix; |
1379 | mp_result len; |
1380 | |
1381 | ACHECK(parse_rat_values(t, in, NULL, NULL)); |
1382 | trim_line(line: t->input[1]); |
1383 | ACHECK(read_long(&radix, t->input[1])); |
1384 | |
1385 | if (radix < MP_MIN_RADIX || radix > MP_MAX_RADIX) { |
1386 | fprintf(stderr, format: "Line %d: Radix %ld out of range\n" , t->line, radix); |
1387 | FAIL(MP_RANGE); |
1388 | } |
1389 | |
1390 | trim_line(line: t->output[0]); |
1391 | len = mp_rat_string_len(r: in[0], radix); |
1392 | |
1393 | CHECK(mp_rat_to_string(in[0], radix, g_output, len)); |
1394 | |
1395 | if (strcmp(s1: t->output[0], s2: g_output) != 0) FAIL(OTHER_ERROR); |
1396 | |
1397 | return true; |
1398 | } |
1399 | |
1400 | bool test_qtodec(testspec_t* t, FILE* ofp) { |
1401 | mp_rat in[4]; |
1402 | long radix, prec, m; |
1403 | mp_round_mode rmode; |
1404 | mp_result res, expect = MP_OK, len; |
1405 | |
1406 | ACHECK(parse_rat_values(t, in, NULL, NULL)); |
1407 | |
1408 | if (t->output[0][0] == '$' && !parse_result_code(str: t->output[0], code: &expect)) { |
1409 | fprintf(stderr, format: "Line %d: Invalid result code [%s]\n" , t->line, |
1410 | t->output[0]); |
1411 | FAIL(OTHER_ERROR); |
1412 | } |
1413 | |
1414 | trim_line(line: t->input[1]); |
1415 | trim_line(line: t->input[2]); |
1416 | trim_line(line: t->input[3]); |
1417 | ACHECK(read_long(&radix, t->input[1])); |
1418 | ACHECK(read_long(&prec, t->input[2])); |
1419 | ACHECK(read_long(&m, t->input[3])); |
1420 | rmode = (mp_round_mode)m; |
1421 | |
1422 | if (prec < 0) { |
1423 | fprintf(stderr, format: "Line %d: Precision %ld out of range\n" , t->line, prec); |
1424 | FAIL(MP_RANGE); |
1425 | } |
1426 | |
1427 | trim_line(line: t->output[0]); |
1428 | len = mp_rat_decimal_len(r: in[0], radix, prec); |
1429 | ECHECK((res = mp_rat_to_decimal(in[0], radix, prec, rmode, g_output, len))); |
1430 | |
1431 | if (res == MP_OK && strcmp(s1: t->output[0], s2: g_output) != 0) FAIL(OTHER_ERROR); |
1432 | |
1433 | return true; |
1434 | } |
1435 | |
1436 | bool test_qrdec(testspec_t* t, FILE* ofp) { |
1437 | mp_rat out[1] = {NULL}, reg = g_qreg + 1; |
1438 | long radix; |
1439 | mp_result expect; |
1440 | |
1441 | ACHECK(parse_rat_values(t, NULL, out, &expect)); |
1442 | trim_line(line: t->input[1]); |
1443 | ACHECK(read_long(&radix, t->input[1])); |
1444 | |
1445 | ECHECK(mp_rat_read_decimal(reg, radix, t->input[0])); |
1446 | if (expect == MP_OK && mp_rat_compare(a: reg, b: out[0]) != 0) { |
1447 | mp_rat_to_string(r: reg, radix: 10, str: g_output, OUTPUT_LIMIT); |
1448 | FAIL(OTHER_ERROR); |
1449 | } |
1450 | return true; |
1451 | } |
1452 | |
1453 | bool test_is_prime(testspec_t* t, FILE* OFP) { |
1454 | mp_int in[1] = {NULL}; |
1455 | mp_result expect; |
1456 | |
1457 | ACHECK(parse_int_values(t, in, NULL, &expect)); |
1458 | ECHECK(mp_int_is_prime(in[0])); |
1459 | return true; |
1460 | } |
1461 | |
1462 | /* Here there be dragons */ |
1463 | |