1463 lines · c
1/*2 Name: imdrover.c3 Purpose: Keeper of the hordes of testing code.4 Author: M. J. Fromberger5 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 copy9 of this software and associated documentation files (the "Software"), to deal10 in the Software without restriction, including without limitation the rights11 to use, copy, modify, merge, publish, distribute, sublicense, and/or sell12 copies of the Software, and to permit persons to whom the Software is13 furnished to do so, subject to the following conditions:14 15 The above copyright notice and this permission notice shall be included in16 all copies or substantial portions of the Software.17 18 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR19 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,20 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE21 AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER22 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 THE24 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 */38mp_result imath_errno;39char* 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 204862#define NUM_REGS 1663#define OTHER_ERROR -102464 65static char g_output[OUTPUT_LIMIT];66static mpz_t g_zreg[NUM_REGS];67static mpq_t g_qreg[NUM_REGS];68static unsigned char g_bin1[OUTPUT_LIMIT];69static unsigned char g_bin2[OUTPUT_LIMIT];70 71extern void trim_line(char* line); /* borrowed from imtest.c */72 73/* Read in a string with radix tags */74static mp_result read_int_value(mp_int z, char* str);75static 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) */78static bool read_long(long* z, char* str);79 80/* Parse the input and output values and fill in pointers to the81 registers containing them. Returns true if all is well, false82 in case of error. Caller allocates in/out to correct sizes. */83static bool parse_int_values(testspec_t* t, mp_int* in, mp_int* out,84 mp_result* rval);85static 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 */89static bool parse_result_code(char* str, mp_result* code);90 91/* Read in a dot-delimited binary sequence to the given buffer, and return the92 number of bytes read. Returns < 0 in case of a syntax error. Records no93 more than limit bytes. */94static int parse_binary(char* str, unsigned char* buf, int limit);95 96/* Clean up registers (called from atexit()) */97static void done_testing(void);98 99/*100 * Utility subroutines for writing tests (explained above)101 */102 103static 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 134static 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(q, radix, str + 1);164 else165 return mp_rat_read_string(q, radix, str);166}167 168static 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(str, &end, radix);198 return (end != str && *end == '\0');199}200 201static 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(str);213 214 if (*str == '=') {215 int k = abs(atoi(str + 1)) - 1;216 217 if (k < 0 || k >= i) {218 fprintf(stderr, "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(reg, str) != MP_OK) {228 fprintf(stderr, "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(str);243 244 if (strcmp(str, "?") == 0)245 mp_int_zero(reg);246 else if (*str == '$') {247 mp_result code;248 249 if (!parse_result_code(str, &code)) {250 fprintf(stderr, "Line %d: Invalid result code [%s]\n", t->line, str);251 return false;252 } else if (rval == NULL) {253 fprintf(stderr, "Line %d: Result code not permitted here [%s]\n",254 t->line, str);255 return false;256 } else257 *rval = code;258 259 /* Provide a dummy value for the corresponding output */260 mp_int_zero(reg);261 } else if (out != NULL && read_int_value(reg, str) != MP_OK) {262 fprintf(stderr, "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 272static 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(str);284 285 if (*str == '=') {286 int k = abs(atoi(str + 1)) - 1;287 288 if (k < 0 || k >= i) {289 fprintf(stderr, "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(reg, str) != MP_OK) {299 fprintf(stderr, "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(str);314 315 if (strcmp(str, "?") == 0)316 mp_rat_zero(reg);317 else if (*str == '$') {318 mp_result code;319 320 if (!parse_result_code(str, &code)) {321 fprintf(stderr, "Line %d: Invalid result code [%s]\n", t->line, str);322 return false;323 } else if (rval == NULL) {324 fprintf(stderr, "Line %d: Result code not permitted here [%s]\n",325 t->line, str);326 return false;327 } else328 *rval = code;329 330 /* Provide a dummy value for the corresponding output */331 mp_rat_zero(reg);332 } else if (out != NULL && read_rat_value(reg, str) != MP_OK) {333 fprintf(stderr, "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 343static 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(&v, str + 2)) return false;349 350 *code = (mp_result)v;351 } else if (strcmp(str + 1, "MP_OK") == 0 ||352 strcmp(str + 1, "MP_FALSE") == 0) {353 *code = MP_OK;354 } else if (strcmp(str + 1, "MP_TRUE") == 0) {355 *code = MP_TRUE;356 } else if (strcmp(str + 1, "MP_MEMORY") == 0) {357 *code = MP_MEMORY;358 } else if (strcmp(str + 1, "MP_RANGE") == 0) {359 *code = MP_RANGE;360 } else if (strcmp(str + 1, "MP_UNDEF") == 0) {361 *code = MP_UNDEF;362 } else if (strcmp(str + 1, "MP_TRUNC") == 0) {363 *code = MP_TRUNC;364 } else if (strcmp(str + 1, "MP_ROUND_UP") == 0) {365 *code = MP_ROUND_UP;366 } else if (strcmp(str + 1, "MP_ROUND_DOWN") == 0) {367 *code = MP_ROUND_DOWN;368 } else if (strcmp(str + 1, "MP_ROUND_HALF_UP") == 0) {369 *code = MP_ROUND_HALF_UP;370 } else if (strcmp(str + 1, "MP_ROUND_HALF_DOWN") == 0) {371 *code = MP_ROUND_HALF_DOWN;372 } else {373 return false;374 }375 }376 377 return true;378}379 380static int parse_binary(char* str, unsigned char* buf, int limit) {381 int pos = 0;382 char* tok;383 384 trim_line(str);385 386 for (tok = strtok(str, "."); tok != NULL && pos < limit;387 tok = strtok(NULL, ".")) {388 long v;389 390 if (!read_long(&v, tok) || v > UCHAR_MAX || v < 0) return -1;391 392 buf[pos++] = (unsigned char)v;393 }394 395 return pos;396}397 398static void done_testing(void) {399 int i;400 401 for (i = 0; i < NUM_REGS; ++i) {402 mp_int_clear(g_zreg + i);403 mp_rat_clear(g_qreg + i);404 }405}406 407/*408 * Global functions visible to callers outside this file.409 */410 411void 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 427void reset_registers(void) {428 for (int i = 0; i < NUM_REGS; ++i) {429 mp_int_zero(g_zreg + i);430 mp_rat_zero(g_qreg + i);431 }432}433 434bool 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(t->code, "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(in[0], out[0]) != 0) {451 mp_int_to_string(in[0], 10, g_output, OUTPUT_LIMIT);452 FAIL(OTHER_ERROR);453 }454 455 return true;456}457 458bool 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(t->code, "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(in[0], out[0]) != 0) {475 mp_int_to_string(in[0], 10, g_output, OUTPUT_LIMIT);476 FAIL(OTHER_ERROR);477 }478 479 return true;480}481 482bool 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(in[1], out[0]) != 0) {490 mp_int_to_string(in[1], 10, g_output, OUTPUT_LIMIT);491 FAIL(OTHER_ERROR);492 }493 494 return true;495}496 497bool 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(in[1], out[0]) != 0) {505 mp_int_to_string(in[1], 10, g_output, OUTPUT_LIMIT);506 FAIL(OTHER_ERROR);507 }508 509 return true;510}511 512bool 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(t->code, "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(in[2], out[0]) != 0) {527 mp_int_to_string(in[2], 10, g_output, OUTPUT_LIMIT);528 FAIL(OTHER_ERROR);529 }530 531 return true;532}533 534bool 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(t->code, "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(in[2], out[0]) != 0) {549 mp_int_to_string(in[2], 10, g_output, OUTPUT_LIMIT);550 FAIL(OTHER_ERROR);551 }552 return true;553}554 555bool 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(in[2], out[0]) != 0) {563 mp_int_to_string(in[2], 10, g_output, OUTPUT_LIMIT);564 FAIL(OTHER_ERROR);565 }566 return true;567}568 569bool 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(in[2], out[0]) != 0) {579 mp_int_to_string(in[2], 10, g_output, OUTPUT_LIMIT);580 FAIL(OTHER_ERROR);581 }582 return true;583}584 585bool 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(in[2], out[0]) != 0) {595 mp_int_to_string(in[2], 10, g_output, OUTPUT_LIMIT);596 FAIL(OTHER_ERROR);597 }598 return true;599}600 601bool 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(in[1], out[0]) != 0) {609 mp_int_to_string(in[1], 10, g_output, OUTPUT_LIMIT);610 FAIL(OTHER_ERROR);611 }612 return true;613}614 615bool 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(in[2], out[0]) != 0) ||623 (mp_int_compare(in[3], out[1]) != 0))) {624 int len;625 char* str;626 627 mp_int_to_string(in[2], 10, g_output, OUTPUT_LIMIT);628 str = g_output + (len = strlen(g_output));629 *str++ = ',';630 mp_int_to_string(in[3], 10, str, OUTPUT_LIMIT - (len + 1));631 FAIL(OTHER_ERROR);632 }633 return true;634}635 636bool 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(in[2], out[0]) != 0) ||646 (mp_int_compare(in[3], out[1]) != 0))) {647 int len;648 char* str;649 650 mp_int_to_string(in[2], 10, g_output, OUTPUT_LIMIT);651 str = g_output + (len = strlen(g_output));652 *str++ = ',';653 mp_int_to_string(in[3], 10, str, OUTPUT_LIMIT - (len + 1));654 FAIL(OTHER_ERROR);655 }656 return true;657}658 659bool 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(in[2], out[0]) != 0) || (rem != orem))) {671 char* str;672 673 mp_int_to_string(in[2], 10, g_output, OUTPUT_LIMIT);674 str = g_output + strlen(g_output);675 *str++ = ',';676 sprintf(str, "%ld", rem);677 FAIL(OTHER_ERROR);678 }679 return true;680}681 682bool 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(in[2], out[0]) != 0) {692 mp_int_to_string(in[2], 10, g_output, OUTPUT_LIMIT);693 FAIL(OTHER_ERROR);694 }695 return true;696}697 698bool 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(in[2], out[0]) != 0) {709 mp_int_to_string(in[2], 10, g_output, OUTPUT_LIMIT);710 FAIL(OTHER_ERROR);711 }712 return true;713}714 715bool 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(in[2], out[0]) != 0) {723 mp_int_to_string(in[2], 10, g_output, OUTPUT_LIMIT);724 FAIL(OTHER_ERROR);725 }726 return true;727}728 729bool 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(in[2], out[0]) != 0) {737 mp_int_to_string(in[2], 10, g_output, OUTPUT_LIMIT);738 FAIL(OTHER_ERROR);739 }740 return true;741}742 743bool 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(in[2], out[0]) != 0) {751 mp_int_to_string(in[2], 10, g_output, OUTPUT_LIMIT);752 FAIL(OTHER_ERROR);753 }754 return true;755}756 757bool 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(in[2], out[0]) != 0) ||768 (mp_int_compare(in[3], out[1]) != 0) ||769 (mp_int_compare(in[4], out[2]) != 0)) {770 int len, len2;771 char* str;772 773 /* Failure might occur because the tester computed x and y in a different774 way than we did. Verify that the results are correct before reporting775 an error. */776 mp_int_mul(in[3], in[0], t1);777 mp_int_mul(in[4], in[1], t2);778 mp_int_add(t1, t2, t2);779 if (mp_int_compare(t2, in[2]) == 0) return true;780 781 mp_int_to_string(in[2], 10, g_output, OUTPUT_LIMIT);782 str = g_output + (len = strlen(g_output));783 *str++ = ',';784 mp_int_to_string(in[3], 10, str, OUTPUT_LIMIT - (len + 1));785 str = str + (len2 = strlen(str));786 *str++ = ',';787 mp_int_to_string(in[4], 10, str, OUTPUT_LIMIT - (len + len2 + 2));788 FAIL(OTHER_ERROR);789 }790 return true;791}792 793bool 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(in[2], out[0]) != 0) {801 mp_int_to_string(in[2], 10, g_output, OUTPUT_LIMIT);802 FAIL(OTHER_ERROR);803 }804 return true;805}806 807bool 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(in[1], out[0]) != 0) {815 mp_int_to_string(in[1], 10, g_output, OUTPUT_LIMIT);816 FAIL(OTHER_ERROR);817 }818 return true;819}820 821bool 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(in[2], out[0]) != 0) {831 mp_int_to_string(in[2], 10, g_output, OUTPUT_LIMIT);832 FAIL(OTHER_ERROR);833 }834 return true;835}836 837bool 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(in[2], out[0]) != 0) {845 mp_int_to_string(in[2], 10, g_output, OUTPUT_LIMIT);846 FAIL(OTHER_ERROR);847 }848 return true;849}850 851bool 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(in[3], out[0]) != 0) {859 mp_int_to_string(in[3], 10, g_output, OUTPUT_LIMIT);860 FAIL(OTHER_ERROR);861 }862 return true;863}864 865bool 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(in[3], out[0]) != 0) {875 mp_int_to_string(in[3], 10, g_output, OUTPUT_LIMIT);876 FAIL(OTHER_ERROR);877 }878 return true;879}880 881bool 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(in[3], out[0]) != 0) {891 mp_int_to_string(in[3], 10, g_output, OUTPUT_LIMIT);892 FAIL(OTHER_ERROR);893 }894 return true;895}896 897bool 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(in[0], in[1])) != expect) {904 sprintf(g_output, "Incorrect comparison result (want %d, got %d)", expect,905 res);906 FAIL(OTHER_ERROR);907 }908 return true;909}910 911bool 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(in[0], in[1])) != expect) {918 sprintf(g_output, "Incorrect comparison result (want %d, got %d)", expect,919 res);920 FAIL(OTHER_ERROR);921 }922 return true;923}924 925bool 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(in[0])) != expect) {932 sprintf(g_output, "Incorrect comparison result (want %d, got %d)", expect,933 res);934 FAIL(OTHER_ERROR);935 }936 return true;937}938 939bool 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(t->input[1]);947 if ((res = mp_int_compare_value(in[0], v)) != expect) {948 sprintf(g_output, "Incorrect comparison result (want %d, got %d)", expect,949 res);950 FAIL(OTHER_ERROR);951 }952 return true;953}954 955bool 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(t->input[1], NULL, 0);963 if ((res = mp_int_compare_uvalue(in[0], v)) != expect) {964 sprintf(g_output, "Incorrect comparison result (want %d, got %d)", expect,965 res);966 FAIL(OTHER_ERROR);967 }968 return true;969}970 971bool 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(t->output[0]);982 len = mp_int_string_len(in[0], radix);983 984 CHECK(mp_int_to_string(in[0], radix, g_output, len));985 986 if (strcmp(t->output[0], g_output) != 0) FAIL(OTHER_ERROR);987 988 return true;989}990 991bool 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(t->output[0]);998 if ((out_len = parse_binary(t->output[0], g_bin1, sizeof(g_bin1))) < 0)999 FAIL(MP_BADARG);1000 1001 if ((test_len = mp_int_binary_len(in[0])) != out_len) {1002 sprintf(g_output, "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(g_bin1, g_bin2, test_len) != 0) {1010 int pos = 0, i;1011 1012 for (i = 0; i < test_len - 1; ++i)1013 pos += sprintf(g_output + pos, "%d.", g_bin2[i]);1014 1015 sprintf(g_output + pos, "%d", g_bin2[i]);1016 FAIL(OTHER_ERROR);1017 }1018 return true;1019}1020 1021bool 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(out[0], v) != 0) {1030 sprintf(g_output, "Incorrect value (got %ld)", v);1031 FAIL(OTHER_ERROR);1032 }1033 return true;1034}1035 1036bool 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(out[0], v) != 0) {1045 sprintf(g_output, "Incorrect value (got %lu)", v);1046 FAIL(OTHER_ERROR);1047 }1048 return true;1049}1050 1051bool 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(t->input[0]);1059 if ((in_len = parse_binary(t->input[0], g_bin1, 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(in, out[0]) != 0) {1065 mp_int_to_string(in, 10, g_output, OUTPUT_LIMIT);1066 FAIL(OTHER_ERROR);1067 }1068 return true;1069}1070 1071bool 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(t->output[0]);1078 if ((out_len = parse_binary(t->output[0], g_bin1, sizeof(g_bin1))) < 0)1079 FAIL(MP_BADARG);1080 1081 if ((test_len = mp_int_unsigned_len(in[0])) != out_len) {1082 sprintf(g_output, "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(g_bin1, g_bin2, test_len) != 0) {1090 int pos = 0, i;1091 1092 for (i = 0; i < test_len - 1; ++i)1093 pos += sprintf(g_output + pos, "%d.", g_bin2[i]);1094 1095 sprintf(g_output + pos, "%d", g_bin2[i]);1096 FAIL(OTHER_ERROR);1097 }1098 return true;1099}1100 1101bool 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(t->input[0]);1109 if ((in_len = parse_binary(t->input[0], g_bin1, 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(in, out[0]) != 0) {1115 mp_int_to_string(in, 10, g_output, OUTPUT_LIMIT);1116 FAIL(OTHER_ERROR);1117 }1118 return true;1119}1120 1121bool 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(t->num_inputs, sizeof(mp_int));1128 }1129 if (t->num_outputs > 0) {1130 out = calloc(t->num_outputs, sizeof(mp_int));1131 }1132 1133 if (!parse_int_values(t, in, out, &expect)) {1134 if (in != NULL) free(in);1135 if (out != NULL) free(out);1136 FAIL(MP_BADARG);1137 }1138 1139 fprintf(ofp, "Test '%s' defined at line %d\n", t->code, t->line);1140 fprintf(ofp, "Expected result: %d\n", expect);1141 fprintf(ofp, "Input values: %d\n", t->num_inputs);1142 for (i = 0; i < t->num_inputs; ++i) {1143 mp_int_to_string(in[i], 10, g_output, OUTPUT_LIMIT);1144 1145 fprintf(ofp, " %2d.) %s", i + 1, g_output);1146 1147 for (j = i - 1; j >= 0; --j)1148 if (in[j] == in[i]) {1149 fprintf(ofp, " (=> %d)", j + 1);1150 break;1151 }1152 1153 fputc('\n', ofp);1154 }1155 fprintf(ofp, "Output values: %d\n", t->num_outputs);1156 for (i = 0; i < t->num_outputs; ++i) {1157 mp_int_to_string(out[i], 10, g_output, OUTPUT_LIMIT);1158 1159 fprintf(ofp, " %2d.) %s\n", i + 1, g_output);1160 }1161 if (in != NULL) free(in);1162 if (out != NULL) free(out);1163 return true;1164}1165 1166bool 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(in[1], out[0]) != 0) {1174 mp_rat_to_string(in[1], 10, g_output, OUTPUT_LIMIT);1175 FAIL(OTHER_ERROR);1176 }1177 return true;1178}1179 1180bool 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(in[1], out[0]) != 0) {1188 mp_rat_to_string(in[1], 10, g_output, OUTPUT_LIMIT);1189 FAIL(OTHER_ERROR);1190 }1191 return true;1192}1193 1194bool 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(in[1], out[0]) != 0) {1202 mp_rat_to_string(in[1], 10, g_output, OUTPUT_LIMIT);1203 FAIL(OTHER_ERROR);1204 }1205 return true;1206}1207 1208bool 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(in[2], out[0]) != 0) {1216 mp_rat_to_string(in[2], 10, g_output, OUTPUT_LIMIT);1217 FAIL(OTHER_ERROR);1218 }1219 return true;1220}1221 1222bool 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(in[2], out[0]) != 0) {1230 mp_rat_to_string(in[2], 10, g_output, OUTPUT_LIMIT);1231 FAIL(OTHER_ERROR);1232 }1233 return true;1234}1235 1236bool 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(in[2], out[0]) != 0) {1244 mp_rat_to_string(in[2], 10, g_output, OUTPUT_LIMIT);1245 FAIL(OTHER_ERROR);1246 }1247 return true;1248}1249 1250bool 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(in[2], out[0]) != 0) {1258 mp_rat_to_string(in[2], 10, g_output, OUTPUT_LIMIT);1259 FAIL(OTHER_ERROR);1260 }1261 return true;1262}1263 1264bool 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(in[1])) {1271 fprintf(stderr,1272 "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(in[2], out[0]) != 0) {1280 mp_rat_to_string(in[2], 10, g_output, OUTPUT_LIMIT);1281 FAIL(OTHER_ERROR);1282 }1283 return true;1284}1285 1286bool 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(in[1])) {1293 fprintf(stderr,1294 "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(in[2], out[0]) != 0) {1302 mp_rat_to_string(in[2], 10, g_output, OUTPUT_LIMIT);1303 FAIL(OTHER_ERROR);1304 }1305 return true;1306}1307 1308bool 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(in[1])) {1315 fprintf(stderr,1316 "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(in[2], out[0]) != 0) {1324 mp_rat_to_string(in[2], 10, g_output, OUTPUT_LIMIT);1325 FAIL(OTHER_ERROR);1326 }1327 return true;1328}1329 1330bool 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(in[1])) {1337 fprintf(stderr,1338 "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(in[2], out[0]) != 0) {1346 mp_rat_to_string(in[2], 10, g_output, OUTPUT_LIMIT);1347 FAIL(OTHER_ERROR);1348 }1349 return true;1350}1351 1352bool 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(in[1])) {1360 fprintf(stderr,1361 "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(in[2], out[0]) != 0) {1370 mp_rat_to_string(in[2], 10, g_output, OUTPUT_LIMIT);1371 FAIL(OTHER_ERROR);1372 }1373 return true;1374}1375 1376bool 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(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, "Line %d: Radix %ld out of range\n", t->line, radix);1387 FAIL(MP_RANGE);1388 }1389 1390 trim_line(t->output[0]);1391 len = mp_rat_string_len(in[0], radix);1392 1393 CHECK(mp_rat_to_string(in[0], radix, g_output, len));1394 1395 if (strcmp(t->output[0], g_output) != 0) FAIL(OTHER_ERROR);1396 1397 return true;1398}1399 1400bool 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(t->output[0], &expect)) {1409 fprintf(stderr, "Line %d: Invalid result code [%s]\n", t->line,1410 t->output[0]);1411 FAIL(OTHER_ERROR);1412 }1413 1414 trim_line(t->input[1]);1415 trim_line(t->input[2]);1416 trim_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, "Line %d: Precision %ld out of range\n", t->line, prec);1424 FAIL(MP_RANGE);1425 }1426 1427 trim_line(t->output[0]);1428 len = mp_rat_decimal_len(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(t->output[0], g_output) != 0) FAIL(OTHER_ERROR);1432 1433 return true;1434}1435 1436bool 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(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(reg, out[0]) != 0) {1447 mp_rat_to_string(reg, 10, g_output, OUTPUT_LIMIT);1448 FAIL(OTHER_ERROR);1449 }1450 return true;1451}1452 1453bool 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