diff --git a/demo/mtest_opponent.c b/demo/mtest_opponent.c index edbecc0c1..25d9b5b90 100644 --- a/demo/mtest_opponent.c +++ b/demo/mtest_opponent.c @@ -6,16 +6,56 @@ #define LTM_MTEST_RAND_SEED 23 #endif -static void draw(const mp_int *a) +#define DRAW(a) do{ ndraw(&(a), #a); }while(0) + +/* + Get tokens. It is just a very(!) simple fgets(3) that does not keep line endings. + + Implementation follows along "man 3 fgets", some of which is quoted. + */ +static int s_mp_get_token(char *s, int size, FILE *stream) { - ndraw(a, ""); -} + char *s_bar = s; + int c; + bool eol_hit = false; -#define FGETS(str, size, stream) \ - { \ - char *ret = fgets(str, size, stream); \ - if (!ret) { fprintf(stderr, "\n%d: fgets failed\n", __LINE__); goto LBL_ERR; } \ + /* "fgets [...] reads in at most one less than size characters from stream" */ + while (--size) { + /* "Reading stops after an EOF or a newline." We stop only for EOF here */ + if ((c = fgetc(stream)) == EOF) { + /* "Returns [...] NULL on error or when end of file occurs while no characters have been read" */ + if ((s_bar == s) || (ferror(stream) != 0)) { + return -1; + } + break; + } + /* Ignore line-breaks but keep reading to get them out of the stream-buffer */ + if ((c == '\n') || (c == '\r')) { + eol_hit = true; + continue; + } + /* Stop reading after linebreak */ + if (eol_hit) { + /* We already read the character after the linebreak, put it back */ + ungetc(c, stream); + break; + } + *s_bar++ = c; } + if (size == 0) return -2; + /* "A terminating null byte ('\0') is stored after the last character in the buffer" */ + *s_bar = '\0'; + return 0; +} + +#define TMP_(r,l) r ## _ ## l +#define TMP(r,l) TMP_(r,l) + +#define GET_TOKEN(str, stream) \ + do { \ + int TMP(ret,__LINE__) = s_mp_get_token((str), sizeof(str), (stream)); \ + if (TMP(ret,__LINE__) < 0) { fprintf(stderr, "\n%d: s_mp_get_token failed with error %d\n", __LINE__, TMP(ret,__LINE__)); goto LBL_ERR; } \ + } while(0) static int mtest_opponent(void) { @@ -76,34 +116,33 @@ static int mtest_opponent(void) printf("%4lu/%4lu/%4lu/%4lu/%4lu/%4lu/%4lu/%4lu/%4lu/%4lu/%4lu/%4lu/%4lu/%4lu/%4lu ", add_n, sub_n, mul_n, div_n, sqr_n, mul2d_n, div2d_n, gcd_n, lcm_n, expt_n, inv_n, div2_n, mul2_n, add_d_n, sub_d_n); - FGETS(cmd, 4095, stdin); - cmd[strlen(cmd) - 1u] = '\0'; + GET_TOKEN(cmd, stdin); printf("%-6s ]\r", cmd); fflush(stdout); if (strcmp(cmd, "mul2d") == 0) { ++mul2d_n; - FGETS(buf, 4095, stdin); + GET_TOKEN(buf, stdin); DO(mp_read_radix(&a, buf, 64)); - FGETS(buf, 4095, stdin); + GET_TOKEN(buf, stdin); sscanf(buf, "%u", &rr); - FGETS(buf, 4095, stdin); + GET_TOKEN(buf, stdin); DO(mp_read_radix(&b, buf, 64)); DO(mp_mul_2d(&a, (int)rr, &a)); a.sign = b.sign; if (mp_cmp(&a, &b) != MP_EQ) { printf("mul2d failed, rr == %u\n", rr); - draw(&a); - draw(&b); + DRAW(a); + DRAW(b); goto LBL_ERR; } } else if (strcmp(cmd, "div2d") == 0) { ++div2d_n; - FGETS(buf, 4095, stdin); + GET_TOKEN(buf, stdin); DO(mp_read_radix(&a, buf, 64)); - FGETS(buf, 4095, stdin); + GET_TOKEN(buf, stdin); sscanf(buf, "%u", &rr); - FGETS(buf, 4095, stdin); + GET_TOKEN(buf, stdin); DO(mp_read_radix(&b, buf, 64)); DO(mp_div_2d(&a, (int)rr, &a, &e)); @@ -113,26 +152,26 @@ static int mtest_opponent(void) } if (mp_cmp(&a, &b) != MP_EQ) { printf("div2d failed, rr == %u\n", rr); - draw(&a); - draw(&b); + DRAW(a); + DRAW(b); goto LBL_ERR; } } else if (strcmp(cmd, "add") == 0) { ++add_n; - FGETS(buf, 4095, stdin); + GET_TOKEN(buf, stdin); DO(mp_read_radix(&a, buf, 64)); - FGETS(buf, 4095, stdin); + GET_TOKEN(buf, stdin); DO(mp_read_radix(&b, buf, 64)); - FGETS(buf, 4095, stdin); + GET_TOKEN(buf, stdin); DO(mp_read_radix(&c, buf, 64)); DO(mp_copy(&a, &d)); DO(mp_add(&d, &b, &d)); if (mp_cmp(&c, &d) != MP_EQ) { printf("add %lu failure!\n", add_n); - draw(&a); - draw(&b); - draw(&c); - draw(&d); + DRAW(a); + DRAW(b); + DRAW(c); + DRAW(d); goto LBL_ERR; } @@ -144,8 +183,8 @@ static int mtest_opponent(void) DO(mp_from_sbin(&d, (uint8_t *) cmd, (size_t)rr)); if (mp_cmp(&c, &d) != MP_EQ) { printf("mp_signed_bin failure!\n"); - draw(&c); - draw(&d); + DRAW(c); + DRAW(d); goto LBL_ERR; } @@ -155,226 +194,226 @@ static int mtest_opponent(void) DO(mp_from_ubin(&d, (uint8_t *) cmd, (size_t)rr)); if (mp_cmp_mag(&c, &d) != MP_EQ) { printf("mp_unsigned_bin failure!\n"); - draw(&c); - draw(&d); + DRAW(c); + DRAW(d); goto LBL_ERR; } } else if (strcmp(cmd, "sub") == 0) { ++sub_n; - FGETS(buf, 4095, stdin); + GET_TOKEN(buf, stdin); DO(mp_read_radix(&a, buf, 64)); - FGETS(buf, 4095, stdin); + GET_TOKEN(buf, stdin); DO(mp_read_radix(&b, buf, 64)); - FGETS(buf, 4095, stdin); + GET_TOKEN(buf, stdin); DO(mp_read_radix(&c, buf, 64)); DO(mp_copy(&a, &d)); DO(mp_sub(&d, &b, &d)); if (mp_cmp(&c, &d) != MP_EQ) { printf("sub %lu failure!\n", sub_n); - draw(&a); - draw(&b); - draw(&c); - draw(&d); + DRAW(a); + DRAW(b); + DRAW(c); + DRAW(d); goto LBL_ERR; } } else if (strcmp(cmd, "mul") == 0) { ++mul_n; - FGETS(buf, 4095, stdin); + GET_TOKEN(buf, stdin); DO(mp_read_radix(&a, buf, 64)); - FGETS(buf, 4095, stdin); + GET_TOKEN(buf, stdin); DO(mp_read_radix(&b, buf, 64)); - FGETS(buf, 4095, stdin); + GET_TOKEN(buf, stdin); DO(mp_read_radix(&c, buf, 64)); DO(mp_copy(&a, &d)); DO(mp_mul(&d, &b, &d)); if (mp_cmp(&c, &d) != MP_EQ) { printf("mul %lu failure!\n", mul_n); - draw(&a); - draw(&b); - draw(&c); - draw(&d); + DRAW(a); + DRAW(b); + DRAW(c); + DRAW(d); goto LBL_ERR; } } else if (strcmp(cmd, "div") == 0) { ++div_n; - FGETS(buf, 4095, stdin); + GET_TOKEN(buf, stdin); DO(mp_read_radix(&a, buf, 64)); - FGETS(buf, 4095, stdin); + GET_TOKEN(buf, stdin); DO(mp_read_radix(&b, buf, 64)); - FGETS(buf, 4095, stdin); + GET_TOKEN(buf, stdin); DO(mp_read_radix(&c, buf, 64)); - FGETS(buf, 4095, stdin); + GET_TOKEN(buf, stdin); DO(mp_read_radix(&d, buf, 64)); DO(mp_div(&a, &b, &e, &f)); if ((mp_cmp(&c, &e) != MP_EQ) || (mp_cmp(&d, &f) != MP_EQ)) { printf("div %lu %d, %d, failure!\n", div_n, mp_cmp(&c, &e), mp_cmp(&d, &f)); - draw(&a); - draw(&b); - draw(&c); - draw(&d); - draw(&e); - draw(&f); + DRAW(a); + DRAW(b); + DRAW(c); + DRAW(d); + DRAW(e); + DRAW(f); goto LBL_ERR; } } else if (strcmp(cmd, "sqr") == 0) { ++sqr_n; - FGETS(buf, 4095, stdin); + GET_TOKEN(buf, stdin); DO(mp_read_radix(&a, buf, 64)); - FGETS(buf, 4095, stdin); + GET_TOKEN(buf, stdin); DO(mp_read_radix(&b, buf, 64)); DO(mp_copy(&a, &c)); DO(mp_sqr(&c, &c)); if (mp_cmp(&b, &c) != MP_EQ) { printf("sqr %lu failure!\n", sqr_n); - draw(&a); - draw(&b); - draw(&c); + DRAW(a); + DRAW(b); + DRAW(c); goto LBL_ERR; } } else if (strcmp(cmd, "gcd") == 0) { ++gcd_n; - FGETS(buf, 4095, stdin); + GET_TOKEN(buf, stdin); DO(mp_read_radix(&a, buf, 64)); - FGETS(buf, 4095, stdin); + GET_TOKEN(buf, stdin); DO(mp_read_radix(&b, buf, 64)); - FGETS(buf, 4095, stdin); + GET_TOKEN(buf, stdin); DO(mp_read_radix(&c, buf, 64)); DO(mp_copy(&a, &d)); DO(mp_gcd(&d, &b, &d)); d.sign = c.sign; if (mp_cmp(&c, &d) != MP_EQ) { printf("gcd %lu failure!\n", gcd_n); - draw(&a); - draw(&b); - draw(&c); - draw(&d); + DRAW(a); + DRAW(b); + DRAW(c); + DRAW(d); goto LBL_ERR; } } else if (strcmp(cmd, "lcm") == 0) { ++lcm_n; - FGETS(buf, 4095, stdin); + GET_TOKEN(buf, stdin); DO(mp_read_radix(&a, buf, 64)); - FGETS(buf, 4095, stdin); + GET_TOKEN(buf, stdin); DO(mp_read_radix(&b, buf, 64)); - FGETS(buf, 4095, stdin); + GET_TOKEN(buf, stdin); DO(mp_read_radix(&c, buf, 64)); DO(mp_copy(&a, &d)); DO(mp_lcm(&d, &b, &d)); d.sign = c.sign; if (mp_cmp(&c, &d) != MP_EQ) { printf("lcm %lu failure!\n", lcm_n); - draw(&a); - draw(&b); - draw(&c); - draw(&d); + DRAW(a); + DRAW(b); + DRAW(c); + DRAW(d); goto LBL_ERR; } } else if (strcmp(cmd, "expt") == 0) { ++expt_n; - FGETS(buf, 4095, stdin); + GET_TOKEN(buf, stdin); DO(mp_read_radix(&a, buf, 64)); - FGETS(buf, 4095, stdin); + GET_TOKEN(buf, stdin); DO(mp_read_radix(&b, buf, 64)); - FGETS(buf, 4095, stdin); + GET_TOKEN(buf, stdin); DO(mp_read_radix(&c, buf, 64)); - FGETS(buf, 4095, stdin); + GET_TOKEN(buf, stdin); DO(mp_read_radix(&d, buf, 64)); DO(mp_copy(&a, &e)); DO(mp_exptmod(&e, &b, &c, &e)); if (mp_cmp(&d, &e) != MP_EQ) { printf("expt %lu failure!\n", expt_n); - draw(&a); - draw(&b); - draw(&c); - draw(&d); - draw(&e); + DRAW(a); + DRAW(b); + DRAW(c); + DRAW(d); + DRAW(e); goto LBL_ERR; } } else if (strcmp(cmd, "invmod") == 0) { ++inv_n; - FGETS(buf, 4095, stdin); + GET_TOKEN(buf, stdin); DO(mp_read_radix(&a, buf, 64)); - FGETS(buf, 4095, stdin); + GET_TOKEN(buf, stdin); DO(mp_read_radix(&b, buf, 64)); - FGETS(buf, 4095, stdin); + GET_TOKEN(buf, stdin); DO(mp_read_radix(&c, buf, 64)); DO(mp_invmod(&a, &b, &d)); DO(mp_mulmod(&d, &a, &b, &e)); if (mp_cmp_d(&e, 1u) != MP_EQ) { printf("inv [wrong value from MPI?!] failure\n"); - draw(&a); - draw(&b); - draw(&c); - draw(&d); - draw(&e); + DRAW(a); + DRAW(b); + DRAW(c); + DRAW(d); + DRAW(e); DO(mp_gcd(&a, &b, &e)); - draw(&e); + DRAW(e); goto LBL_ERR; } } else if (strcmp(cmd, "div2") == 0) { ++div2_n; - FGETS(buf, 4095, stdin); + GET_TOKEN(buf, stdin); DO(mp_read_radix(&a, buf, 64)); - FGETS(buf, 4095, stdin); + GET_TOKEN(buf, stdin); DO(mp_read_radix(&b, buf, 64)); DO(mp_div_2(&a, &c)); if (mp_cmp(&c, &b) != MP_EQ) { printf("div_2 %lu failure\n", div2_n); - draw(&a); - draw(&b); - draw(&c); + DRAW(a); + DRAW(b); + DRAW(c); goto LBL_ERR; } } else if (strcmp(cmd, "mul2") == 0) { ++mul2_n; - FGETS(buf, 4095, stdin); + GET_TOKEN(buf, stdin); DO(mp_read_radix(&a, buf, 64)); - FGETS(buf, 4095, stdin); + GET_TOKEN(buf, stdin); DO(mp_read_radix(&b, buf, 64)); DO(mp_mul_2(&a, &c)); if (mp_cmp(&c, &b) != MP_EQ) { printf("mul_2 %lu failure\n", mul2_n); - draw(&a); - draw(&b); - draw(&c); + DRAW(a); + DRAW(b); + DRAW(c); goto LBL_ERR; } } else if (strcmp(cmd, "add_d") == 0) { ++add_d_n; - FGETS(buf, 4095, stdin); + GET_TOKEN(buf, stdin); DO(mp_read_radix(&a, buf, 64)); - FGETS(buf, 4095, stdin); + GET_TOKEN(buf, stdin); sscanf(buf, "%d", &ix); - FGETS(buf, 4095, stdin); + GET_TOKEN(buf, stdin); DO(mp_read_radix(&b, buf, 64)); DO(mp_add_d(&a, (mp_digit)ix, &c)); if (mp_cmp(&b, &c) != MP_EQ) { printf("add_d %lu failure\n", add_d_n); - draw(&a); - draw(&b); - draw(&c); + DRAW(a); + DRAW(b); + DRAW(c); printf("d == %d\n", ix); goto LBL_ERR; } } else if (strcmp(cmd, "sub_d") == 0) { ++sub_d_n; - FGETS(buf, 4095, stdin); + GET_TOKEN(buf, stdin); DO(mp_read_radix(&a, buf, 64)); - FGETS(buf, 4095, stdin); + GET_TOKEN(buf, stdin); sscanf(buf, "%d", &ix); - FGETS(buf, 4095, stdin); + GET_TOKEN(buf, stdin); DO(mp_read_radix(&b, buf, 64)); DO(mp_sub_d(&a, (mp_digit)ix, &c)); if (mp_cmp(&b, &c) != MP_EQ) { printf("sub_d %lu failure\n", sub_d_n); - draw(&a); - draw(&b); - draw(&c); + DRAW(a); + DRAW(b); + DRAW(c); printf("d == %d\n", ix); goto LBL_ERR; } diff --git a/doc/bn.tex b/doc/bn.tex index 6f1cb8cd4..1dfb34d55 100644 --- a/doc/bn.tex +++ b/doc/bn.tex @@ -2409,9 +2409,25 @@ \subsection{From ASCII} mp_err mp_read_radix (mp_int *a, const char *str, int radix); \end{alltt} This will read a \texttt{NUL} terminated string in base \texttt{radix} from \texttt{str} into $a$. -It will stop reading when it reads a character it does not recognize (which happens to include the -\texttt{NUL} char\dots imagine that\dots). A single leading $-$ (ASCII \texttt{0x20}) sign can be -used to denote a negative number. The input encoding is currently restricted to ASCII only. +Valid values of \texttt{radix} are in the range $[2, 64]$. +%It will stop reading when it reads a character it does not recognize (which happens to include the +%\texttt{NUL} char\dots imagine that\dots). + +It returns \texttt{MP\_VAL} for any character {\em not} in the range allowed for the given base. +The list of characters is the same as for base-64 and also in the same order. +\begin{alltt} +0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz+/ +\end{alltt} + +A single leading $-$ (ASCII \texttt{0x20}) sign can be used to denote a negative number. The +plus sign $+$ (ASCII \texttt{0x2b}) is already in use (bases 63 and 64) and cannot be used +to denote positivity, no matter how good the mood of the number is. + +For all bases smaller than 37 the list is case-insensitive, e.g.:~the two hexadecimal numbers +$123abc_{16} = 1194684_{10}$ and $123ABC_{16} = 1194684_{10}$ are equivalent but the two base +64 numbers $123abc_{64} = 1108232550_{10}$ and $123ABC_{64} = 1108124364_{10}$ are not. + +The input encoding is currently restricted to ASCII only. If \texttt{MP\_NO\_FILE} is not defined a function to read from a file is also available. \index{mp\_fread}