1462 lines
36 KiB
C
1462 lines
36 KiB
C
/*
|
|
Name: imdrover.c
|
|
Purpose: Keeper of the hordes of testing code.
|
|
Author: M. J. Fromberger
|
|
|
|
Copyright (C) 2002-2007 Michael J. Fromberger, All Rights Reserved.
|
|
|
|
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
of this software and associated documentation files (the "Software"), to deal
|
|
in the Software without restriction, including without limitation the rights
|
|
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
copies of the Software, and to permit persons to whom the Software is
|
|
furnished to do so, subject to the following conditions:
|
|
|
|
The above copyright notice and this permission notice shall be included in
|
|
all copies or substantial portions of the Software.
|
|
|
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
SOFTWARE.
|
|
*/
|
|
|
|
#include <assert.h>
|
|
#include <limits.h>
|
|
#include <stdlib.h>
|
|
#include <string.h>
|
|
|
|
#include "imath.h"
|
|
#include "imdrover.h"
|
|
#include "imrat.h"
|
|
#include "iprime.h"
|
|
|
|
/* Globals visible from outside this file */
|
|
mp_result imath_errno;
|
|
char* imath_errmsg;
|
|
|
|
/* Set imath_errno and return failure from a test. */
|
|
#define FAIL(E) return (imath_errno = (E), false)
|
|
|
|
/* Check that an expression X yields the expected mp_result value V. */
|
|
#define VCHECK(X, V) \
|
|
do { \
|
|
mp_result res_; \
|
|
if ((res_ = (X)) != (V)) { \
|
|
FAIL(res_); \
|
|
} \
|
|
} while (0)
|
|
#define CHECK(X) VCHECK(X, MP_OK)
|
|
#define ECHECK(X) VCHECK(X, expect)
|
|
#define ACHECK(X) \
|
|
do { \
|
|
if (!(X)) { \
|
|
FAIL(MP_BADARG); \
|
|
} \
|
|
} while (0)
|
|
|
|
#define OUTPUT_LIMIT 2048
|
|
#define NUM_REGS 16
|
|
#define OTHER_ERROR -1024
|
|
|
|
static char g_output[OUTPUT_LIMIT];
|
|
static mpz_t g_zreg[NUM_REGS];
|
|
static mpq_t g_qreg[NUM_REGS];
|
|
static unsigned char g_bin1[OUTPUT_LIMIT];
|
|
static unsigned char g_bin2[OUTPUT_LIMIT];
|
|
|
|
extern void trim_line(char* line); /* borrowed from imtest.c */
|
|
|
|
/* Read in a string with radix tags */
|
|
static mp_result read_int_value(mp_int z, char* str);
|
|
static mp_result read_rat_value(mp_rat q, char* str);
|
|
|
|
/* Read in a string with radix tags, as a long (not an mp_int) */
|
|
static bool read_long(long* z, char* str);
|
|
|
|
/* Parse the input and output values and fill in pointers to the
|
|
registers containing them. Returns true if all is well, false
|
|
in case of error. Caller allocates in/out to correct sizes. */
|
|
static bool parse_int_values(testspec_t* t, mp_int* in, mp_int* out,
|
|
mp_result* rval);
|
|
static bool parse_rat_values(testspec_t* t, mp_rat* in, mp_rat* out,
|
|
mp_result* rval);
|
|
|
|
/* Parse a result code name and return the corresponding result code */
|
|
static bool parse_result_code(char* str, mp_result* code);
|
|
|
|
/* Read in a dot-delimited binary sequence to the given buffer, and return the
|
|
number of bytes read. Returns < 0 in case of a syntax error. Records no
|
|
more than limit bytes. */
|
|
static int parse_binary(char* str, unsigned char* buf, int limit);
|
|
|
|
/* Clean up registers (called from atexit()) */
|
|
static void done_testing(void);
|
|
|
|
/*
|
|
* Utility subroutines for writing tests (explained above)
|
|
*/
|
|
|
|
static mp_result read_int_value(mp_int z, char* str) {
|
|
int radix = 10;
|
|
|
|
if (*str == '#') {
|
|
++str;
|
|
switch (*str) {
|
|
case 'x':
|
|
case 'X':
|
|
radix = 16;
|
|
break;
|
|
case 'd':
|
|
case 'D':
|
|
radix = 10;
|
|
break;
|
|
case 'o':
|
|
case 'O':
|
|
radix = 8;
|
|
break;
|
|
case 'b':
|
|
case 'B':
|
|
radix = 2;
|
|
break;
|
|
default:
|
|
return MP_RANGE;
|
|
}
|
|
++str;
|
|
}
|
|
|
|
return mp_int_read_string(z, radix, str);
|
|
}
|
|
|
|
static mp_result read_rat_value(mp_rat q, char* str) {
|
|
int radix = 10;
|
|
|
|
if (*str == '#') {
|
|
++str;
|
|
switch (*str) {
|
|
case 'x':
|
|
case 'X':
|
|
radix = 16;
|
|
break;
|
|
case 'd':
|
|
case 'D':
|
|
radix = 10;
|
|
break;
|
|
case 'o':
|
|
case 'O':
|
|
radix = 8;
|
|
break;
|
|
case 'b':
|
|
case 'B':
|
|
radix = 2;
|
|
break;
|
|
default:
|
|
return MP_RANGE;
|
|
}
|
|
++str;
|
|
}
|
|
|
|
if (*str == '@')
|
|
return mp_rat_read_decimal(q, radix, str + 1);
|
|
else
|
|
return mp_rat_read_string(q, radix, str);
|
|
}
|
|
|
|
static bool read_long(long* z, char* str) {
|
|
char* end;
|
|
int radix = 10;
|
|
|
|
if (*str == '#') {
|
|
++str;
|
|
switch (*str) {
|
|
case 'x':
|
|
case 'X':
|
|
radix = 16;
|
|
break;
|
|
case 'd':
|
|
case 'D':
|
|
radix = 10;
|
|
break;
|
|
case 'o':
|
|
case 'O':
|
|
radix = 8;
|
|
break;
|
|
case 'b':
|
|
case 'B':
|
|
radix = 2;
|
|
break;
|
|
default:
|
|
return false;
|
|
}
|
|
++str;
|
|
}
|
|
|
|
*z = strtol(str, &end, radix);
|
|
return (end != str && *end == '\0');
|
|
}
|
|
|
|
static bool parse_int_values(testspec_t* t, mp_int* in, mp_int* out,
|
|
mp_result* rval) {
|
|
int pos = 0;
|
|
char* str;
|
|
|
|
if (rval != NULL) *rval = MP_OK; /* default */
|
|
|
|
if (in != NULL) {
|
|
for (int i = 0; i < t->num_inputs; ++i) {
|
|
str = t->input[i];
|
|
|
|
trim_line(str);
|
|
|
|
if (*str == '=') {
|
|
int k = abs(atoi(str + 1)) - 1;
|
|
|
|
if (k < 0 || k >= i) {
|
|
fprintf(stderr, "Line %d: Invalid input back-reference [%s]\n",
|
|
t->line, str);
|
|
return false;
|
|
}
|
|
|
|
in[i] = in[k];
|
|
} else {
|
|
mp_int reg = g_zreg + pos++; /* grab next free register */
|
|
|
|
if (read_int_value(reg, str) != MP_OK) {
|
|
fprintf(stderr, "Line %d: Invalid input value [%s]\n", t->line, str);
|
|
return false;
|
|
}
|
|
|
|
in[i] = reg;
|
|
}
|
|
}
|
|
}
|
|
|
|
for (int i = 0; i < t->num_outputs; ++i) {
|
|
mp_int reg = g_zreg + pos++;
|
|
|
|
str = t->output[i];
|
|
|
|
trim_line(str);
|
|
|
|
if (strcmp(str, "?") == 0)
|
|
mp_int_zero(reg);
|
|
else if (*str == '$') {
|
|
mp_result code;
|
|
|
|
if (!parse_result_code(str, &code)) {
|
|
fprintf(stderr, "Line %d: Invalid result code [%s]\n", t->line, str);
|
|
return false;
|
|
} else if (rval == NULL) {
|
|
fprintf(stderr, "Line %d: Result code not permitted here [%s]\n",
|
|
t->line, str);
|
|
return false;
|
|
} else
|
|
*rval = code;
|
|
|
|
/* Provide a dummy value for the corresponding output */
|
|
mp_int_zero(reg);
|
|
} else if (out != NULL && read_int_value(reg, str) != MP_OK) {
|
|
fprintf(stderr, "Line %d: Invalid output value [%s]\n", t->line, str);
|
|
return false;
|
|
}
|
|
|
|
if (out != NULL) out[i] = reg;
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
static bool parse_rat_values(testspec_t* t, mp_rat* in, mp_rat* out,
|
|
mp_result* rval) {
|
|
int pos = 0;
|
|
char* str;
|
|
|
|
if (rval != NULL) *rval = MP_OK; /* default */
|
|
|
|
if (in != NULL) {
|
|
for (int i = 0; i < t->num_inputs; ++i) {
|
|
str = t->input[i];
|
|
|
|
trim_line(str);
|
|
|
|
if (*str == '=') {
|
|
int k = abs(atoi(str + 1)) - 1;
|
|
|
|
if (k < 0 || k >= i) {
|
|
fprintf(stderr, "Line %d: Invalid input back-reference [%s]\n",
|
|
t->line, str);
|
|
return false;
|
|
}
|
|
|
|
in[i] = in[k];
|
|
} else {
|
|
mp_rat reg = g_qreg + pos++; /* grab next free register */
|
|
|
|
if (read_rat_value(reg, str) != MP_OK) {
|
|
fprintf(stderr, "Line %d: Invalid input value [%s]\n", t->line, str);
|
|
return false;
|
|
}
|
|
|
|
in[i] = reg;
|
|
}
|
|
}
|
|
}
|
|
|
|
for (int i = 0; i < t->num_outputs; ++i) {
|
|
mp_rat reg = g_qreg + pos++;
|
|
|
|
str = t->output[i];
|
|
|
|
trim_line(str);
|
|
|
|
if (strcmp(str, "?") == 0)
|
|
mp_rat_zero(reg);
|
|
else if (*str == '$') {
|
|
mp_result code;
|
|
|
|
if (!parse_result_code(str, &code)) {
|
|
fprintf(stderr, "Line %d: Invalid result code [%s]\n", t->line, str);
|
|
return false;
|
|
} else if (rval == NULL) {
|
|
fprintf(stderr, "Line %d: Result code not permitted here [%s]\n",
|
|
t->line, str);
|
|
return false;
|
|
} else
|
|
*rval = code;
|
|
|
|
/* Provide a dummy value for the corresponding output */
|
|
mp_rat_zero(reg);
|
|
} else if (out != NULL && read_rat_value(reg, str) != MP_OK) {
|
|
fprintf(stderr, "Line %d: Invalid output value [%s]\n", t->line, str);
|
|
return false;
|
|
}
|
|
|
|
if (out != NULL) out[i] = reg;
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
static bool parse_result_code(char* str, mp_result* code) {
|
|
if (str[0] == '$') {
|
|
if (str[1] == '#') {
|
|
long v;
|
|
|
|
if (!read_long(&v, str + 2)) return false;
|
|
|
|
*code = (mp_result)v;
|
|
} else if (strcmp(str + 1, "MP_OK") == 0 ||
|
|
strcmp(str + 1, "MP_FALSE") == 0) {
|
|
*code = MP_OK;
|
|
} else if (strcmp(str + 1, "MP_TRUE") == 0) {
|
|
*code = MP_TRUE;
|
|
} else if (strcmp(str + 1, "MP_MEMORY") == 0) {
|
|
*code = MP_MEMORY;
|
|
} else if (strcmp(str + 1, "MP_RANGE") == 0) {
|
|
*code = MP_RANGE;
|
|
} else if (strcmp(str + 1, "MP_UNDEF") == 0) {
|
|
*code = MP_UNDEF;
|
|
} else if (strcmp(str + 1, "MP_TRUNC") == 0) {
|
|
*code = MP_TRUNC;
|
|
} else if (strcmp(str + 1, "MP_ROUND_UP") == 0) {
|
|
*code = MP_ROUND_UP;
|
|
} else if (strcmp(str + 1, "MP_ROUND_DOWN") == 0) {
|
|
*code = MP_ROUND_DOWN;
|
|
} else if (strcmp(str + 1, "MP_ROUND_HALF_UP") == 0) {
|
|
*code = MP_ROUND_HALF_UP;
|
|
} else if (strcmp(str + 1, "MP_ROUND_HALF_DOWN") == 0) {
|
|
*code = MP_ROUND_HALF_DOWN;
|
|
} else {
|
|
return false;
|
|
}
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
static int parse_binary(char* str, unsigned char* buf, int limit) {
|
|
int pos = 0;
|
|
char* tok;
|
|
|
|
trim_line(str);
|
|
|
|
for (tok = strtok(str, "."); tok != NULL && pos < limit;
|
|
tok = strtok(NULL, ".")) {
|
|
long v;
|
|
|
|
if (!read_long(&v, tok) || v > UCHAR_MAX || v < 0) return -1;
|
|
|
|
buf[pos++] = (unsigned char)v;
|
|
}
|
|
|
|
return pos;
|
|
}
|
|
|
|
static void done_testing(void) {
|
|
int i;
|
|
|
|
for (i = 0; i < NUM_REGS; ++i) {
|
|
mp_int_clear(g_zreg + i);
|
|
mp_rat_clear(g_qreg + i);
|
|
}
|
|
}
|
|
|
|
/*
|
|
* Global functions visible to callers outside this file.
|
|
*/
|
|
|
|
void init_testing(void) {
|
|
static int is_done = 0;
|
|
|
|
if (is_done) return;
|
|
|
|
for (int i = 0; i < NUM_REGS; ++i) {
|
|
assert(mp_int_init(g_zreg + i) == MP_OK);
|
|
assert(mp_rat_init(g_qreg + i) == MP_OK);
|
|
}
|
|
|
|
imath_errmsg = g_output;
|
|
|
|
assert(atexit(done_testing) == 0);
|
|
is_done = 1;
|
|
}
|
|
|
|
void reset_registers(void) {
|
|
for (int i = 0; i < NUM_REGS; ++i) {
|
|
mp_int_zero(g_zreg + i);
|
|
mp_rat_zero(g_qreg + i);
|
|
}
|
|
}
|
|
|
|
bool test_init(testspec_t* t, FILE* ofp) {
|
|
mp_int in[2], out[1];
|
|
mp_small v;
|
|
mp_usmall uv;
|
|
mp_result expect;
|
|
|
|
ACHECK(parse_int_values(t, in, out, &expect));
|
|
|
|
if (strcmp(t->code, "initu") == 0) {
|
|
CHECK(mp_int_to_uint(in[1], &uv));
|
|
ECHECK(mp_int_init_uvalue(in[0], uv));
|
|
} else { /* initv */
|
|
CHECK(mp_int_to_int(in[1], &v));
|
|
ECHECK(mp_int_init_value(in[0], v));
|
|
}
|
|
|
|
if (expect == MP_OK && mp_int_compare(in[0], out[0]) != 0) {
|
|
mp_int_to_string(in[0], 10, g_output, OUTPUT_LIMIT);
|
|
FAIL(OTHER_ERROR);
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
bool test_set(testspec_t* t, FILE* ofp) {
|
|
mp_int in[2], out[1];
|
|
mp_small v;
|
|
mp_usmall uv;
|
|
mp_result expect;
|
|
|
|
ACHECK(parse_int_values(t, in, out, &expect));
|
|
|
|
if (strcmp(t->code, "setu") == 0) {
|
|
CHECK(mp_int_to_uint(in[1], &uv));
|
|
ECHECK(mp_int_set_uvalue(in[0], uv));
|
|
} else { /* setv */
|
|
CHECK(mp_int_to_int(in[1], &v));
|
|
ECHECK(mp_int_set_value(in[0], v));
|
|
}
|
|
|
|
if (expect == MP_OK && mp_int_compare(in[0], out[0]) != 0) {
|
|
mp_int_to_string(in[0], 10, g_output, OUTPUT_LIMIT);
|
|
FAIL(OTHER_ERROR);
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
bool test_neg(testspec_t* t, FILE* ofp) {
|
|
mp_int in[2], out[1];
|
|
mp_result expect;
|
|
|
|
ACHECK(parse_int_values(t, in, out, &expect));
|
|
ECHECK(mp_int_neg(in[0], in[1]));
|
|
|
|
if (expect == MP_OK && mp_int_compare(in[1], out[0]) != 0) {
|
|
mp_int_to_string(in[1], 10, g_output, OUTPUT_LIMIT);
|
|
FAIL(OTHER_ERROR);
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
bool test_abs(testspec_t* t, FILE* ofp) {
|
|
mp_int in[2], out[1];
|
|
mp_result expect;
|
|
|
|
ACHECK(parse_int_values(t, in, out, &expect));
|
|
ECHECK(mp_int_abs(in[0], in[1]));
|
|
|
|
if (expect == MP_OK && mp_int_compare(in[1], out[0]) != 0) {
|
|
mp_int_to_string(in[1], 10, g_output, OUTPUT_LIMIT);
|
|
FAIL(OTHER_ERROR);
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
bool test_add(testspec_t* t, FILE* ofp) {
|
|
mp_int in[3], out[1];
|
|
mp_small v;
|
|
mp_result expect;
|
|
|
|
ACHECK(parse_int_values(t, in, out, &expect));
|
|
|
|
if (strcmp(t->code, "addv") == 0) {
|
|
CHECK(mp_int_to_int(in[1], &v));
|
|
ECHECK(mp_int_add_value(in[0], v, in[2]));
|
|
} else {
|
|
ECHECK(mp_int_add(in[0], in[1], in[2]));
|
|
}
|
|
|
|
if (expect == MP_OK && mp_int_compare(in[2], out[0]) != 0) {
|
|
mp_int_to_string(in[2], 10, g_output, OUTPUT_LIMIT);
|
|
FAIL(OTHER_ERROR);
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
bool test_sub(testspec_t* t, FILE* ofp) {
|
|
mp_int in[3], out[1];
|
|
mp_small v;
|
|
mp_result expect;
|
|
|
|
ACHECK(parse_int_values(t, in, out, &expect));
|
|
|
|
if (strcmp(t->code, "subv") == 0) {
|
|
CHECK(mp_int_to_int(in[1], &v));
|
|
ECHECK(mp_int_sub_value(in[0], v, in[2]));
|
|
} else {
|
|
ECHECK(mp_int_sub(in[0], in[1], in[2]));
|
|
}
|
|
|
|
if (expect == MP_OK && mp_int_compare(in[2], out[0]) != 0) {
|
|
mp_int_to_string(in[2], 10, g_output, OUTPUT_LIMIT);
|
|
FAIL(OTHER_ERROR);
|
|
}
|
|
return true;
|
|
}
|
|
|
|
bool test_mul(testspec_t* t, FILE* ofp) {
|
|
mp_int in[3], out[1];
|
|
mp_result expect;
|
|
|
|
ACHECK(parse_int_values(t, in, out, &expect));
|
|
ECHECK(mp_int_mul(in[0], in[1], in[2]));
|
|
|
|
if (expect == MP_OK && mp_int_compare(in[2], out[0]) != 0) {
|
|
mp_int_to_string(in[2], 10, g_output, OUTPUT_LIMIT);
|
|
FAIL(OTHER_ERROR);
|
|
}
|
|
return true;
|
|
}
|
|
|
|
bool test_mulp2(testspec_t* t, FILE* ofp) {
|
|
mp_int in[3], out[1];
|
|
mp_result expect;
|
|
mp_small p2;
|
|
|
|
ACHECK(parse_int_values(t, in, out, &expect));
|
|
CHECK(mp_int_to_int(in[1], &p2));
|
|
ECHECK(mp_int_mul_pow2(in[0], p2, in[2]));
|
|
|
|
if (expect == MP_OK && mp_int_compare(in[2], out[0]) != 0) {
|
|
mp_int_to_string(in[2], 10, g_output, OUTPUT_LIMIT);
|
|
FAIL(OTHER_ERROR);
|
|
}
|
|
return true;
|
|
}
|
|
|
|
bool test_mulv(testspec_t* t, FILE* ofp) {
|
|
mp_int in[3], out[1];
|
|
mp_result expect;
|
|
mp_small v;
|
|
|
|
ACHECK(parse_int_values(t, in, out, &expect));
|
|
CHECK(mp_int_to_int(in[1], &v));
|
|
ECHECK(mp_int_mul_value(in[0], v, in[2]));
|
|
|
|
if (expect == MP_OK && mp_int_compare(in[2], out[0]) != 0) {
|
|
mp_int_to_string(in[2], 10, g_output, OUTPUT_LIMIT);
|
|
FAIL(OTHER_ERROR);
|
|
}
|
|
return true;
|
|
}
|
|
|
|
bool test_sqr(testspec_t* t, FILE* ofp) {
|
|
mp_int in[2], out[1];
|
|
mp_result expect;
|
|
|
|
ACHECK(parse_int_values(t, in, out, &expect));
|
|
ECHECK(mp_int_sqr(in[0], in[1]));
|
|
|
|
if (expect == MP_OK && mp_int_compare(in[1], out[0]) != 0) {
|
|
mp_int_to_string(in[1], 10, g_output, OUTPUT_LIMIT);
|
|
FAIL(OTHER_ERROR);
|
|
}
|
|
return true;
|
|
}
|
|
|
|
bool test_div(testspec_t* t, FILE* ofp) {
|
|
mp_int in[4], out[2];
|
|
mp_result expect;
|
|
|
|
ACHECK(parse_int_values(t, in, out, &expect));
|
|
ECHECK(mp_int_div(in[0], in[1], in[2], in[3]));
|
|
|
|
if (expect == MP_OK && ((mp_int_compare(in[2], out[0]) != 0) ||
|
|
(mp_int_compare(in[3], out[1]) != 0))) {
|
|
int len;
|
|
char* str;
|
|
|
|
mp_int_to_string(in[2], 10, g_output, OUTPUT_LIMIT);
|
|
str = g_output + (len = strlen(g_output));
|
|
*str++ = ',';
|
|
mp_int_to_string(in[3], 10, str, OUTPUT_LIMIT - (len + 1));
|
|
FAIL(OTHER_ERROR);
|
|
}
|
|
return true;
|
|
}
|
|
|
|
bool test_divp2(testspec_t* t, FILE* ofp) {
|
|
mp_int in[4], out[2];
|
|
mp_result expect;
|
|
mp_small p2;
|
|
|
|
ACHECK(parse_int_values(t, in, out, &expect));
|
|
CHECK(mp_int_to_int(in[1], &p2));
|
|
ECHECK(mp_int_div_pow2(in[0], p2, in[2], in[3]));
|
|
|
|
if (expect == MP_OK && ((mp_int_compare(in[2], out[0]) != 0) ||
|
|
(mp_int_compare(in[3], out[1]) != 0))) {
|
|
int len;
|
|
char* str;
|
|
|
|
mp_int_to_string(in[2], 10, g_output, OUTPUT_LIMIT);
|
|
str = g_output + (len = strlen(g_output));
|
|
*str++ = ',';
|
|
mp_int_to_string(in[3], 10, str, OUTPUT_LIMIT - (len + 1));
|
|
FAIL(OTHER_ERROR);
|
|
}
|
|
return true;
|
|
}
|
|
|
|
bool test_divv(testspec_t* t, FILE* ofp) {
|
|
mp_int in[3], out[2];
|
|
mp_result expect;
|
|
mp_small v, rem, orem;
|
|
|
|
ACHECK(parse_int_values(t, in, out, &expect));
|
|
CHECK(mp_int_to_int(in[1], &v));
|
|
CHECK(mp_int_to_int(out[1], &orem));
|
|
ECHECK(mp_int_div_value(in[0], v, in[2], &rem));
|
|
|
|
if (expect == MP_OK &&
|
|
((mp_int_compare(in[2], out[0]) != 0) || (rem != orem))) {
|
|
char* str;
|
|
|
|
mp_int_to_string(in[2], 10, g_output, OUTPUT_LIMIT);
|
|
str = g_output + strlen(g_output);
|
|
*str++ = ',';
|
|
sprintf(str, "%ld", rem);
|
|
FAIL(OTHER_ERROR);
|
|
}
|
|
return true;
|
|
}
|
|
|
|
bool test_expt(testspec_t* t, FILE* ofp) {
|
|
mp_int in[3], out[1];
|
|
mp_result expect;
|
|
mp_small pow;
|
|
|
|
ACHECK(parse_int_values(t, in, out, &expect));
|
|
CHECK(mp_int_to_int(in[1], &pow));
|
|
ECHECK(mp_int_expt(in[0], pow, in[2]));
|
|
|
|
if (expect == MP_OK && mp_int_compare(in[2], out[0]) != 0) {
|
|
mp_int_to_string(in[2], 10, g_output, OUTPUT_LIMIT);
|
|
FAIL(OTHER_ERROR);
|
|
}
|
|
return true;
|
|
}
|
|
|
|
bool test_exptv(testspec_t* t, FILE* ofp) {
|
|
mp_int in[3], out[1];
|
|
mp_result expect;
|
|
mp_small a, b;
|
|
|
|
ACHECK(parse_int_values(t, in, out, &expect));
|
|
CHECK(mp_int_to_int(in[0], &a));
|
|
CHECK(mp_int_to_int(in[1], &b));
|
|
ECHECK(mp_int_expt_value(a, b, in[2]));
|
|
|
|
if (expect == MP_OK && mp_int_compare(in[2], out[0]) != 0) {
|
|
mp_int_to_string(in[2], 10, g_output, OUTPUT_LIMIT);
|
|
FAIL(OTHER_ERROR);
|
|
}
|
|
return true;
|
|
}
|
|
|
|
bool test_exptf(testspec_t* t, FILE* ofp) {
|
|
mp_int in[3], out[1];
|
|
mp_result expect;
|
|
|
|
ACHECK(parse_int_values(t, in, out, &expect));
|
|
ECHECK(mp_int_expt_full(in[0], in[1], in[2]));
|
|
|
|
if (expect == MP_OK && mp_int_compare(in[2], out[0]) != 0) {
|
|
mp_int_to_string(in[2], 10, g_output, OUTPUT_LIMIT);
|
|
FAIL(OTHER_ERROR);
|
|
}
|
|
return true;
|
|
}
|
|
|
|
bool test_mod(testspec_t* t, FILE* ofp) {
|
|
mp_int in[3], out[1];
|
|
mp_result expect;
|
|
|
|
ACHECK(parse_int_values(t, in, out, &expect));
|
|
ECHECK(mp_int_mod(in[0], in[1], in[2]));
|
|
|
|
if (expect == MP_OK && mp_int_compare(in[2], out[0]) != 0) {
|
|
mp_int_to_string(in[2], 10, g_output, OUTPUT_LIMIT);
|
|
FAIL(OTHER_ERROR);
|
|
}
|
|
return true;
|
|
}
|
|
|
|
bool test_gcd(testspec_t* t, FILE* ofp) {
|
|
mp_int in[3], out[1];
|
|
mp_result expect;
|
|
|
|
ACHECK(parse_int_values(t, in, out, &expect));
|
|
ECHECK(mp_int_gcd(in[0], in[1], in[2]));
|
|
|
|
if (expect == MP_OK && mp_int_compare(in[2], out[0]) != 0) {
|
|
mp_int_to_string(in[2], 10, g_output, OUTPUT_LIMIT);
|
|
FAIL(OTHER_ERROR);
|
|
}
|
|
return true;
|
|
}
|
|
|
|
bool test_egcd(testspec_t* t, FILE* ofp) {
|
|
mp_int in[5], out[3], t1 = g_zreg + 8, t2 = g_zreg + 9;
|
|
mp_result expect;
|
|
|
|
ACHECK(parse_int_values(t, in, out, &expect));
|
|
ECHECK(mp_int_egcd(in[0], in[1], in[2], in[3], in[4]));
|
|
|
|
/* If we got an error we expected, return success immediately */
|
|
if (expect != MP_OK) return true;
|
|
|
|
if ((mp_int_compare(in[2], out[0]) != 0) ||
|
|
(mp_int_compare(in[3], out[1]) != 0) ||
|
|
(mp_int_compare(in[4], out[2]) != 0)) {
|
|
int len, len2;
|
|
char* str;
|
|
|
|
/* Failure might occur because the tester computed x and y in a different
|
|
way than we did. Verify that the results are correct before reporting
|
|
an error. */
|
|
mp_int_mul(in[3], in[0], t1);
|
|
mp_int_mul(in[4], in[1], t2);
|
|
mp_int_add(t1, t2, t2);
|
|
if (mp_int_compare(t2, in[2]) == 0) return true;
|
|
|
|
mp_int_to_string(in[2], 10, g_output, OUTPUT_LIMIT);
|
|
str = g_output + (len = strlen(g_output));
|
|
*str++ = ',';
|
|
mp_int_to_string(in[3], 10, str, OUTPUT_LIMIT - (len + 1));
|
|
str = str + (len2 = strlen(str));
|
|
*str++ = ',';
|
|
mp_int_to_string(in[4], 10, str, OUTPUT_LIMIT - (len + len2 + 2));
|
|
FAIL(OTHER_ERROR);
|
|
}
|
|
return true;
|
|
}
|
|
|
|
bool test_lcm(testspec_t* t, FILE* ofp) {
|
|
mp_int in[3], out[1];
|
|
mp_result expect;
|
|
|
|
ACHECK(parse_int_values(t, in, out, &expect));
|
|
ECHECK(mp_int_lcm(in[0], in[1], in[2]));
|
|
|
|
if (expect == MP_OK && mp_int_compare(in[2], out[0]) != 0) {
|
|
mp_int_to_string(in[2], 10, g_output, OUTPUT_LIMIT);
|
|
FAIL(OTHER_ERROR);
|
|
}
|
|
return true;
|
|
}
|
|
|
|
bool test_sqrt(testspec_t* t, FILE* ofp) {
|
|
mp_int in[2], out[1];
|
|
mp_result expect;
|
|
|
|
ACHECK(parse_int_values(t, in, out, &expect));
|
|
ECHECK(mp_int_sqrt(in[0], in[1]));
|
|
|
|
if (expect == MP_OK && mp_int_compare(in[1], out[0]) != 0) {
|
|
mp_int_to_string(in[1], 10, g_output, OUTPUT_LIMIT);
|
|
FAIL(OTHER_ERROR);
|
|
}
|
|
return true;
|
|
}
|
|
|
|
bool test_root(testspec_t* t, FILE* ofp) {
|
|
mp_int in[3], out[1];
|
|
mp_small v;
|
|
mp_result expect;
|
|
|
|
ACHECK(parse_int_values(t, in, out, &expect));
|
|
CHECK(mp_int_to_int(in[1], &v));
|
|
ECHECK(mp_int_root(in[0], v, in[2]));
|
|
|
|
if (expect == MP_OK && mp_int_compare(in[2], out[0]) != 0) {
|
|
mp_int_to_string(in[2], 10, g_output, OUTPUT_LIMIT);
|
|
FAIL(OTHER_ERROR);
|
|
}
|
|
return true;
|
|
}
|
|
|
|
bool test_invmod(testspec_t* t, FILE* ofp) {
|
|
mp_int in[3], out[1];
|
|
mp_result expect;
|
|
|
|
ACHECK(parse_int_values(t, in, out, &expect));
|
|
ECHECK(mp_int_invmod(in[0], in[1], in[2]));
|
|
|
|
if (expect == MP_OK && mp_int_compare(in[2], out[0]) != 0) {
|
|
mp_int_to_string(in[2], 10, g_output, OUTPUT_LIMIT);
|
|
FAIL(OTHER_ERROR);
|
|
}
|
|
return true;
|
|
}
|
|
|
|
bool test_exptmod(testspec_t* t, FILE* ofp) {
|
|
mp_int in[4], out[1];
|
|
mp_result expect;
|
|
|
|
ACHECK(parse_int_values(t, in, out, &expect));
|
|
ECHECK(mp_int_exptmod(in[0], in[1], in[2], in[3]));
|
|
|
|
if (expect == MP_OK && mp_int_compare(in[3], out[0]) != 0) {
|
|
mp_int_to_string(in[3], 10, g_output, OUTPUT_LIMIT);
|
|
FAIL(OTHER_ERROR);
|
|
}
|
|
return true;
|
|
}
|
|
|
|
bool test_exptmod_ev(testspec_t* t, FILE* ofp) {
|
|
mp_int in[4], out[1];
|
|
mp_result expect;
|
|
mp_small v;
|
|
|
|
ACHECK(parse_int_values(t, in, out, &expect));
|
|
CHECK(mp_int_to_int(in[1], &v));
|
|
ECHECK(mp_int_exptmod_evalue(in[0], v, in[2], in[3]));
|
|
|
|
if (expect == MP_OK && mp_int_compare(in[3], out[0]) != 0) {
|
|
mp_int_to_string(in[3], 10, g_output, OUTPUT_LIMIT);
|
|
FAIL(OTHER_ERROR);
|
|
}
|
|
return true;
|
|
}
|
|
|
|
bool test_exptmod_bv(testspec_t* t, FILE* ofp) {
|
|
mp_int in[4], out[1];
|
|
mp_result expect;
|
|
mp_small v;
|
|
|
|
ACHECK(parse_int_values(t, in, out, &expect));
|
|
CHECK(mp_int_to_int(in[0], &v));
|
|
ECHECK(mp_int_exptmod_bvalue(v, in[1], in[2], in[3]));
|
|
|
|
if (expect == MP_OK && mp_int_compare(in[3], out[0]) != 0) {
|
|
mp_int_to_string(in[3], 10, g_output, OUTPUT_LIMIT);
|
|
FAIL(OTHER_ERROR);
|
|
}
|
|
return true;
|
|
}
|
|
|
|
bool test_comp(testspec_t* t, FILE* ofp) {
|
|
mp_int in[2];
|
|
mp_result res, expect;
|
|
|
|
ACHECK(parse_int_values(t, in, NULL, &expect));
|
|
|
|
if ((res = mp_int_compare(in[0], in[1])) != expect) {
|
|
sprintf(g_output, "Incorrect comparison result (want %d, got %d)", expect,
|
|
res);
|
|
FAIL(OTHER_ERROR);
|
|
}
|
|
return true;
|
|
}
|
|
|
|
bool test_ucomp(testspec_t* t, FILE* ofp) {
|
|
mp_int in[2];
|
|
mp_result res, expect;
|
|
|
|
ACHECK(parse_int_values(t, in, NULL, &expect));
|
|
|
|
if ((res = mp_int_compare_unsigned(in[0], in[1])) != expect) {
|
|
sprintf(g_output, "Incorrect comparison result (want %d, got %d)", expect,
|
|
res);
|
|
FAIL(OTHER_ERROR);
|
|
}
|
|
return true;
|
|
}
|
|
|
|
bool test_zcomp(testspec_t* t, FILE* ofp) {
|
|
mp_int in[1];
|
|
mp_result res, expect;
|
|
|
|
ACHECK(parse_int_values(t, in, NULL, &expect));
|
|
|
|
if ((res = mp_int_compare_zero(in[0])) != expect) {
|
|
sprintf(g_output, "Incorrect comparison result (want %d, got %d)", expect,
|
|
res);
|
|
FAIL(OTHER_ERROR);
|
|
}
|
|
return true;
|
|
}
|
|
|
|
bool test_vcomp(testspec_t* t, FILE* ofp) {
|
|
mp_int in[2];
|
|
mp_result res, expect;
|
|
mp_small v;
|
|
|
|
ACHECK(parse_int_values(t, in, NULL, &expect));
|
|
|
|
v = atoi(t->input[1]);
|
|
if ((res = mp_int_compare_value(in[0], v)) != expect) {
|
|
sprintf(g_output, "Incorrect comparison result (want %d, got %d)", expect,
|
|
res);
|
|
FAIL(OTHER_ERROR);
|
|
}
|
|
return true;
|
|
}
|
|
|
|
bool test_uvcomp(testspec_t* t, FILE* ofp) {
|
|
mp_int in[2];
|
|
mp_result res, expect;
|
|
mp_usmall v;
|
|
|
|
ACHECK(parse_int_values(t, in, NULL, &expect));
|
|
|
|
v = strtoul(t->input[1], NULL, 0);
|
|
if ((res = mp_int_compare_uvalue(in[0], v)) != expect) {
|
|
sprintf(g_output, "Incorrect comparison result (want %d, got %d)", expect,
|
|
res);
|
|
FAIL(OTHER_ERROR);
|
|
}
|
|
return true;
|
|
}
|
|
|
|
bool test_tostr(testspec_t* t, FILE* ofp) {
|
|
mp_int in[2];
|
|
mp_small radix;
|
|
mp_result len;
|
|
|
|
ACHECK(parse_int_values(t, in, NULL, NULL));
|
|
ACHECK(mp_int_to_int(in[1], &radix) == MP_OK);
|
|
|
|
if (radix < MP_MIN_RADIX || radix > MP_MAX_RADIX) FAIL(MP_RANGE);
|
|
|
|
trim_line(t->output[0]);
|
|
len = mp_int_string_len(in[0], radix);
|
|
|
|
CHECK(mp_int_to_string(in[0], radix, g_output, len));
|
|
|
|
if (strcmp(t->output[0], g_output) != 0) FAIL(OTHER_ERROR);
|
|
|
|
return true;
|
|
}
|
|
|
|
bool test_tobin(testspec_t* t, FILE* ofp) {
|
|
mp_int in[1];
|
|
int test_len, out_len;
|
|
|
|
ACHECK(parse_int_values(t, in, NULL, NULL));
|
|
|
|
trim_line(t->output[0]);
|
|
if ((out_len = parse_binary(t->output[0], g_bin1, sizeof(g_bin1))) < 0)
|
|
FAIL(MP_BADARG);
|
|
|
|
if ((test_len = mp_int_binary_len(in[0])) != out_len) {
|
|
sprintf(g_output, "Output lengths do not match (want %d, got %d)", test_len,
|
|
out_len);
|
|
FAIL(OTHER_ERROR);
|
|
}
|
|
|
|
CHECK(mp_int_to_binary(in[0], g_bin2, sizeof(g_bin2)));
|
|
|
|
if (memcmp(g_bin1, g_bin2, test_len) != 0) {
|
|
int pos = 0, i;
|
|
|
|
for (i = 0; i < test_len - 1; ++i)
|
|
pos += sprintf(g_output + pos, "%d.", g_bin2[i]);
|
|
|
|
sprintf(g_output + pos, "%d", g_bin2[i]);
|
|
FAIL(OTHER_ERROR);
|
|
}
|
|
return true;
|
|
}
|
|
|
|
bool test_to_int(testspec_t* t, FILE* ofp) {
|
|
mp_int in[1], out[1];
|
|
mp_small v;
|
|
mp_result expect;
|
|
|
|
ACHECK(parse_int_values(t, in, out, &expect));
|
|
ECHECK(mp_int_to_int(in[0], &v));
|
|
|
|
if (expect == MP_OK && mp_int_compare_value(out[0], v) != 0) {
|
|
sprintf(g_output, "Incorrect value (got %ld)", v);
|
|
FAIL(OTHER_ERROR);
|
|
}
|
|
return true;
|
|
}
|
|
|
|
bool test_to_uint(testspec_t* t, FILE* ofp) {
|
|
mp_int in[1], out[1];
|
|
mp_usmall v;
|
|
mp_result expect;
|
|
|
|
ACHECK(parse_int_values(t, in, out, &expect));
|
|
ECHECK(mp_int_to_uint(in[0], &v));
|
|
|
|
if (expect == MP_OK && mp_int_compare_uvalue(out[0], v) != 0) {
|
|
sprintf(g_output, "Incorrect value (got %lu)", v);
|
|
FAIL(OTHER_ERROR);
|
|
}
|
|
return true;
|
|
}
|
|
|
|
bool test_read_binary(testspec_t* t, FILE* ofp) {
|
|
mp_int out[1], in = g_zreg + 1;
|
|
int in_len;
|
|
mp_result expect;
|
|
|
|
ACHECK(parse_int_values(t, NULL, out, &expect));
|
|
|
|
trim_line(t->input[0]);
|
|
if ((in_len = parse_binary(t->input[0], g_bin1, sizeof(g_bin1))) < 0)
|
|
FAIL(MP_BADARG);
|
|
|
|
ECHECK(mp_int_read_binary(in, g_bin1, in_len));
|
|
|
|
if (expect == MP_OK && mp_int_compare(in, out[0]) != 0) {
|
|
mp_int_to_string(in, 10, g_output, OUTPUT_LIMIT);
|
|
FAIL(OTHER_ERROR);
|
|
}
|
|
return true;
|
|
}
|
|
|
|
bool test_to_uns(testspec_t* t, FILE* ofp) {
|
|
mp_int in[1];
|
|
int test_len, out_len;
|
|
|
|
ACHECK(parse_int_values(t, in, NULL, NULL));
|
|
|
|
trim_line(t->output[0]);
|
|
if ((out_len = parse_binary(t->output[0], g_bin1, sizeof(g_bin1))) < 0)
|
|
FAIL(MP_BADARG);
|
|
|
|
if ((test_len = mp_int_unsigned_len(in[0])) != out_len) {
|
|
sprintf(g_output, "Output lengths do not match (want %d, got %d)", test_len,
|
|
out_len);
|
|
FAIL(OTHER_ERROR);
|
|
}
|
|
|
|
CHECK(mp_int_to_unsigned(in[0], g_bin2, sizeof(g_bin2)));
|
|
|
|
if (memcmp(g_bin1, g_bin2, test_len) != 0) {
|
|
int pos = 0, i;
|
|
|
|
for (i = 0; i < test_len - 1; ++i)
|
|
pos += sprintf(g_output + pos, "%d.", g_bin2[i]);
|
|
|
|
sprintf(g_output + pos, "%d", g_bin2[i]);
|
|
FAIL(OTHER_ERROR);
|
|
}
|
|
return true;
|
|
}
|
|
|
|
bool test_read_uns(testspec_t* t, FILE* ofp) {
|
|
mp_int out[1], in = g_zreg + 1;
|
|
int in_len;
|
|
mp_result expect;
|
|
|
|
ACHECK(parse_int_values(t, NULL, out, &expect));
|
|
|
|
trim_line(t->input[0]);
|
|
if ((in_len = parse_binary(t->input[0], g_bin1, sizeof(g_bin1))) < 0)
|
|
FAIL(MP_BADARG);
|
|
|
|
ECHECK(mp_int_read_unsigned(in, g_bin1, in_len));
|
|
|
|
if (expect == MP_OK && mp_int_compare(in, out[0]) != 0) {
|
|
mp_int_to_string(in, 10, g_output, OUTPUT_LIMIT);
|
|
FAIL(OTHER_ERROR);
|
|
}
|
|
return true;
|
|
}
|
|
|
|
bool test_meta(testspec_t* t, FILE* ofp) {
|
|
mp_int *in = NULL, *out = NULL;
|
|
int i, j;
|
|
mp_result expect;
|
|
|
|
if (t->num_inputs > 0) {
|
|
in = calloc(t->num_inputs, sizeof(mp_int));
|
|
}
|
|
if (t->num_outputs > 0) {
|
|
out = calloc(t->num_outputs, sizeof(mp_int));
|
|
}
|
|
|
|
if (!parse_int_values(t, in, out, &expect)) {
|
|
if (in != NULL) free(in);
|
|
if (out != NULL) free(out);
|
|
FAIL(MP_BADARG);
|
|
}
|
|
|
|
fprintf(ofp, "Test '%s' defined at line %d\n", t->code, t->line);
|
|
fprintf(ofp, "Expected result: %d\n", expect);
|
|
fprintf(ofp, "Input values: %d\n", t->num_inputs);
|
|
for (i = 0; i < t->num_inputs; ++i) {
|
|
mp_int_to_string(in[i], 10, g_output, OUTPUT_LIMIT);
|
|
|
|
fprintf(ofp, " %2d.) %s", i + 1, g_output);
|
|
|
|
for (j = i - 1; j >= 0; --j)
|
|
if (in[j] == in[i]) {
|
|
fprintf(ofp, " (=> %d)", j + 1);
|
|
break;
|
|
}
|
|
|
|
fputc('\n', ofp);
|
|
}
|
|
fprintf(ofp, "Output values: %d\n", t->num_outputs);
|
|
for (i = 0; i < t->num_outputs; ++i) {
|
|
mp_int_to_string(out[i], 10, g_output, OUTPUT_LIMIT);
|
|
|
|
fprintf(ofp, " %2d.) %s\n", i + 1, g_output);
|
|
}
|
|
if (in != NULL) free(in);
|
|
if (out != NULL) free(out);
|
|
return true;
|
|
}
|
|
|
|
bool test_qneg(testspec_t* t, FILE* ofp) {
|
|
mp_rat in[2], out[1];
|
|
mp_result expect;
|
|
|
|
ACHECK(parse_rat_values(t, in, out, &expect));
|
|
ECHECK(mp_rat_neg(in[0], in[1]));
|
|
|
|
if (expect == MP_OK && mp_rat_compare(in[1], out[0]) != 0) {
|
|
mp_rat_to_string(in[1], 10, g_output, OUTPUT_LIMIT);
|
|
FAIL(OTHER_ERROR);
|
|
}
|
|
return true;
|
|
}
|
|
|
|
bool test_qrecip(testspec_t* t, FILE* ofp) {
|
|
mp_rat in[2], out[1];
|
|
mp_result expect;
|
|
|
|
ACHECK(parse_rat_values(t, in, out, &expect));
|
|
ECHECK(mp_rat_recip(in[0], in[1]));
|
|
|
|
if (expect == MP_OK && mp_rat_compare(in[1], out[0]) != 0) {
|
|
mp_rat_to_string(in[1], 10, g_output, OUTPUT_LIMIT);
|
|
FAIL(OTHER_ERROR);
|
|
}
|
|
return true;
|
|
}
|
|
|
|
bool test_qabs(testspec_t* t, FILE* ofp) {
|
|
mp_rat in[2], out[1];
|
|
mp_result expect;
|
|
|
|
ACHECK(parse_rat_values(t, in, out, &expect));
|
|
ECHECK(mp_rat_abs(in[0], in[1]));
|
|
|
|
if (expect == MP_OK && mp_rat_compare(in[1], out[0]) != 0) {
|
|
mp_rat_to_string(in[1], 10, g_output, OUTPUT_LIMIT);
|
|
FAIL(OTHER_ERROR);
|
|
}
|
|
return true;
|
|
}
|
|
|
|
bool test_qadd(testspec_t* t, FILE* ofp) {
|
|
mp_rat in[3], out[1];
|
|
mp_result expect;
|
|
|
|
ACHECK(parse_rat_values(t, in, out, &expect));
|
|
ECHECK(mp_rat_add(in[0], in[1], in[2]));
|
|
|
|
if (expect == MP_OK && mp_rat_compare(in[2], out[0]) != 0) {
|
|
mp_rat_to_string(in[2], 10, g_output, OUTPUT_LIMIT);
|
|
FAIL(OTHER_ERROR);
|
|
}
|
|
return true;
|
|
}
|
|
|
|
bool test_qsub(testspec_t* t, FILE* ofp) {
|
|
mp_rat in[3], out[1];
|
|
mp_result expect;
|
|
|
|
ACHECK(parse_rat_values(t, in, out, &expect));
|
|
ECHECK(mp_rat_sub(in[0], in[1], in[2]));
|
|
|
|
if (expect == MP_OK && mp_rat_compare(in[2], out[0]) != 0) {
|
|
mp_rat_to_string(in[2], 10, g_output, OUTPUT_LIMIT);
|
|
FAIL(OTHER_ERROR);
|
|
}
|
|
return true;
|
|
}
|
|
|
|
bool test_qmul(testspec_t* t, FILE* ofp) {
|
|
mp_rat in[3], out[1];
|
|
mp_result expect;
|
|
|
|
ACHECK(parse_rat_values(t, in, out, &expect));
|
|
ECHECK(mp_rat_mul(in[0], in[1], in[2]));
|
|
|
|
if (expect == MP_OK && mp_rat_compare(in[2], out[0]) != 0) {
|
|
mp_rat_to_string(in[2], 10, g_output, OUTPUT_LIMIT);
|
|
FAIL(OTHER_ERROR);
|
|
}
|
|
return true;
|
|
}
|
|
|
|
bool test_qdiv(testspec_t* t, FILE* ofp) {
|
|
mp_rat in[3], out[1];
|
|
mp_result expect;
|
|
|
|
ACHECK(parse_rat_values(t, in, out, &expect));
|
|
ECHECK(mp_rat_div(in[0], in[1], in[2]));
|
|
|
|
if (expect == MP_OK && mp_rat_compare(in[2], out[0]) != 0) {
|
|
mp_rat_to_string(in[2], 10, g_output, OUTPUT_LIMIT);
|
|
FAIL(OTHER_ERROR);
|
|
}
|
|
return true;
|
|
}
|
|
|
|
bool test_qaddz(testspec_t* t, FILE* ofp) {
|
|
mp_rat in[3], out[1];
|
|
mp_result expect;
|
|
|
|
ACHECK(parse_rat_values(t, in, out, &expect));
|
|
|
|
if (!mp_rat_is_integer(in[1])) {
|
|
fprintf(stderr,
|
|
"Line %d: Second argument must be an integer (test_qaddz)\n",
|
|
t->line);
|
|
FAIL(MP_BADARG);
|
|
}
|
|
|
|
ECHECK(mp_rat_add_int(in[0], MP_NUMER_P(in[1]), in[2]));
|
|
|
|
if (expect == MP_OK && mp_rat_compare(in[2], out[0]) != 0) {
|
|
mp_rat_to_string(in[2], 10, g_output, OUTPUT_LIMIT);
|
|
FAIL(OTHER_ERROR);
|
|
}
|
|
return true;
|
|
}
|
|
|
|
bool test_qsubz(testspec_t* t, FILE* ofp) {
|
|
mp_rat in[3], out[1];
|
|
mp_result expect;
|
|
|
|
ACHECK(parse_rat_values(t, in, out, &expect));
|
|
|
|
if (!mp_rat_is_integer(in[1])) {
|
|
fprintf(stderr,
|
|
"Line %d: Second argument must be an integer (test_qsubz)\n",
|
|
t->line);
|
|
FAIL(MP_BADARG);
|
|
}
|
|
|
|
ECHECK(mp_rat_sub_int(in[0], MP_NUMER_P(in[1]), in[2]));
|
|
|
|
if (expect == MP_OK && mp_rat_compare(in[2], out[0]) != 0) {
|
|
mp_rat_to_string(in[2], 10, g_output, OUTPUT_LIMIT);
|
|
FAIL(OTHER_ERROR);
|
|
}
|
|
return true;
|
|
}
|
|
|
|
bool test_qmulz(testspec_t* t, FILE* ofp) {
|
|
mp_rat in[3], out[1];
|
|
mp_result expect;
|
|
|
|
ACHECK(parse_rat_values(t, in, out, &expect));
|
|
|
|
if (!mp_rat_is_integer(in[1])) {
|
|
fprintf(stderr,
|
|
"Line %d: Second argument must be an integer (test_qmulz)\n",
|
|
t->line);
|
|
FAIL(MP_BADARG);
|
|
}
|
|
|
|
ECHECK(mp_rat_mul_int(in[0], MP_NUMER_P(in[1]), in[2]));
|
|
|
|
if (expect == MP_OK && mp_rat_compare(in[2], out[0]) != 0) {
|
|
mp_rat_to_string(in[2], 10, g_output, OUTPUT_LIMIT);
|
|
FAIL(OTHER_ERROR);
|
|
}
|
|
return true;
|
|
}
|
|
|
|
bool test_qdivz(testspec_t* t, FILE* ofp) {
|
|
mp_rat in[3], out[1];
|
|
mp_result expect;
|
|
|
|
ACHECK(parse_rat_values(t, in, out, &expect));
|
|
|
|
if (!mp_rat_is_integer(in[1])) {
|
|
fprintf(stderr,
|
|
"Line %d: Second argument must be an integer (test_qdivz)\n",
|
|
t->line);
|
|
FAIL(MP_BADARG);
|
|
}
|
|
|
|
ECHECK(mp_rat_div_int(in[0], MP_NUMER_P(in[1]), in[2]));
|
|
|
|
if (expect == MP_OK && mp_rat_compare(in[2], out[0]) != 0) {
|
|
mp_rat_to_string(in[2], 10, g_output, OUTPUT_LIMIT);
|
|
FAIL(OTHER_ERROR);
|
|
}
|
|
return true;
|
|
}
|
|
|
|
bool test_qexpt(testspec_t* t, FILE* ofp) {
|
|
mp_rat in[3], out[1];
|
|
mp_result expect;
|
|
mp_small power;
|
|
|
|
ACHECK(parse_rat_values(t, in, out, &expect));
|
|
|
|
if (!mp_rat_is_integer(in[1])) {
|
|
fprintf(stderr,
|
|
"Line %d: Second argument must be an integer (test_qexpt)\n",
|
|
t->line);
|
|
FAIL(MP_BADARG);
|
|
}
|
|
|
|
CHECK(mp_int_to_int(MP_NUMER_P(in[1]), &power));
|
|
ECHECK(mp_rat_expt(in[0], power, in[2]));
|
|
|
|
if (expect == MP_OK && mp_rat_compare(in[2], out[0]) != 0) {
|
|
mp_rat_to_string(in[2], 10, g_output, OUTPUT_LIMIT);
|
|
FAIL(OTHER_ERROR);
|
|
}
|
|
return true;
|
|
}
|
|
|
|
bool test_qtostr(testspec_t* t, FILE* ofp) {
|
|
mp_rat in[2];
|
|
long radix;
|
|
mp_result len;
|
|
|
|
ACHECK(parse_rat_values(t, in, NULL, NULL));
|
|
trim_line(t->input[1]);
|
|
ACHECK(read_long(&radix, t->input[1]));
|
|
|
|
if (radix < MP_MIN_RADIX || radix > MP_MAX_RADIX) {
|
|
fprintf(stderr, "Line %d: Radix %ld out of range\n", t->line, radix);
|
|
FAIL(MP_RANGE);
|
|
}
|
|
|
|
trim_line(t->output[0]);
|
|
len = mp_rat_string_len(in[0], radix);
|
|
|
|
CHECK(mp_rat_to_string(in[0], radix, g_output, len));
|
|
|
|
if (strcmp(t->output[0], g_output) != 0) FAIL(OTHER_ERROR);
|
|
|
|
return true;
|
|
}
|
|
|
|
bool test_qtodec(testspec_t* t, FILE* ofp) {
|
|
mp_rat in[4];
|
|
long radix, prec, m;
|
|
mp_round_mode rmode;
|
|
mp_result res, expect = MP_OK, len;
|
|
|
|
ACHECK(parse_rat_values(t, in, NULL, NULL));
|
|
|
|
if (t->output[0][0] == '$' && !parse_result_code(t->output[0], &expect)) {
|
|
fprintf(stderr, "Line %d: Invalid result code [%s]\n", t->line,
|
|
t->output[0]);
|
|
FAIL(OTHER_ERROR);
|
|
}
|
|
|
|
trim_line(t->input[1]);
|
|
trim_line(t->input[2]);
|
|
trim_line(t->input[3]);
|
|
ACHECK(read_long(&radix, t->input[1]));
|
|
ACHECK(read_long(&prec, t->input[2]));
|
|
ACHECK(read_long(&m, t->input[3]));
|
|
rmode = (mp_round_mode)m;
|
|
|
|
if (prec < 0) {
|
|
fprintf(stderr, "Line %d: Precision %ld out of range\n", t->line, prec);
|
|
FAIL(MP_RANGE);
|
|
}
|
|
|
|
trim_line(t->output[0]);
|
|
len = mp_rat_decimal_len(in[0], radix, prec);
|
|
ECHECK((res = mp_rat_to_decimal(in[0], radix, prec, rmode, g_output, len)));
|
|
|
|
if (res == MP_OK && strcmp(t->output[0], g_output) != 0) FAIL(OTHER_ERROR);
|
|
|
|
return true;
|
|
}
|
|
|
|
bool test_qrdec(testspec_t* t, FILE* ofp) {
|
|
mp_rat out[1] = {NULL}, reg = g_qreg + 1;
|
|
long radix;
|
|
mp_result expect;
|
|
|
|
ACHECK(parse_rat_values(t, NULL, out, &expect));
|
|
trim_line(t->input[1]);
|
|
ACHECK(read_long(&radix, t->input[1]));
|
|
|
|
ECHECK(mp_rat_read_decimal(reg, radix, t->input[0]));
|
|
if (expect == MP_OK && mp_rat_compare(reg, out[0]) != 0) {
|
|
mp_rat_to_string(reg, 10, g_output, OUTPUT_LIMIT);
|
|
FAIL(OTHER_ERROR);
|
|
}
|
|
return true;
|
|
}
|
|
|
|
bool test_is_prime(testspec_t* t, FILE* OFP) {
|
|
mp_int in[1] = {NULL};
|
|
mp_result expect;
|
|
|
|
ACHECK(parse_int_values(t, in, NULL, &expect));
|
|
ECHECK(mp_int_is_prime(in[0]));
|
|
return true;
|
|
}
|
|
|
|
/* Here there be dragons */
|