1656c5bc7SDima Dorfman /* 2656c5bc7SDima Dorfman * Copyright (c) 2001 Dima Dorfman. 3656c5bc7SDima Dorfman * All rights reserved. 4656c5bc7SDima Dorfman * 5656c5bc7SDima Dorfman * Redistribution and use in source and binary forms, with or without 6656c5bc7SDima Dorfman * modification, are permitted provided that the following conditions 7656c5bc7SDima Dorfman * are met: 8656c5bc7SDima Dorfman * 1. Redistributions of source code must retain the above copyright 9656c5bc7SDima Dorfman * notice, this list of conditions and the following disclaimer. 10656c5bc7SDima Dorfman * 2. Redistributions in binary form must reproduce the above copyright 11656c5bc7SDima Dorfman * notice, this list of conditions and the following disclaimer in the 12656c5bc7SDima Dorfman * documentation and/or other materials provided with the distribution. 13656c5bc7SDima Dorfman * 14656c5bc7SDima Dorfman * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 15656c5bc7SDima Dorfman * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 16656c5bc7SDima Dorfman * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 17656c5bc7SDima Dorfman * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 18656c5bc7SDima Dorfman * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 19656c5bc7SDima Dorfman * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 20656c5bc7SDima Dorfman * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 21656c5bc7SDima Dorfman * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 22656c5bc7SDima Dorfman * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 23656c5bc7SDima Dorfman * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 24656c5bc7SDima Dorfman * SUCH DAMAGE. 25656c5bc7SDima Dorfman */ 26656c5bc7SDima Dorfman 27656c5bc7SDima Dorfman /* 28656c5bc7SDima Dorfman * This is the traditional Berkeley MP library implemented in terms of 29656c5bc7SDima Dorfman * the OpenSSL BIGNUM library. It was written to replace libgmp, and 30656c5bc7SDima Dorfman * is meant to be as compatible with the latter as feasible. 31656c5bc7SDima Dorfman * 32656c5bc7SDima Dorfman * There seems to be a lack of documentation for the Berkeley MP 33656c5bc7SDima Dorfman * interface. All I could find was libgmp documentation (which didn't 34656c5bc7SDima Dorfman * talk about the semantics of the functions) and an old SunOS 4.1 35656c5bc7SDima Dorfman * manual page from 1989. The latter wasn't very detailed, either, 36656c5bc7SDima Dorfman * but at least described what the function's arguments were. In 37656c5bc7SDima Dorfman * general the interface seems to be archaic, somewhat poorly 38656c5bc7SDima Dorfman * designed, and poorly, if at all, documented. It is considered 39656c5bc7SDima Dorfman * harmful. 40656c5bc7SDima Dorfman * 41656c5bc7SDima Dorfman * Miscellaneous notes on this implementation: 42656c5bc7SDima Dorfman * 43656c5bc7SDima Dorfman * - The SunOS manual page mentioned above indicates that if an error 44656c5bc7SDima Dorfman * occurs, the library should "produce messages and core images." 45656c5bc7SDima Dorfman * Given that most of the functions don't have return values (and 46656c5bc7SDima Dorfman * thus no sane way of alerting the caller to an error), this seems 47656c5bc7SDima Dorfman * reasonable. The MPERR and MPERRX macros call warn and warnx, 48656c5bc7SDima Dorfman * respectively, then abort(). 49656c5bc7SDima Dorfman * 50656c5bc7SDima Dorfman * - All the functions which take an argument to be "filled in" 51656c5bc7SDima Dorfman * assume that the argument has been initialized by one of the *tom() 52656c5bc7SDima Dorfman * routines before being passed to it. I never saw this documented 53656c5bc7SDima Dorfman * anywhere, but this seems to be consistent with the way this 54656c5bc7SDima Dorfman * library is used. 55656c5bc7SDima Dorfman * 56656c5bc7SDima Dorfman * - msqrt() is the only routine which had to be implemented which 57656c5bc7SDima Dorfman * doesn't have a close counterpart in the OpenSSL BIGNUM library. 58656c5bc7SDima Dorfman * It was implemented by hand using Newton's recursive formula. 59656c5bc7SDima Dorfman * Doing it this way, although more error-prone, has the positive 60656c5bc7SDima Dorfman * sideaffect of testing a lot of other functions; if msqrt() 61656c5bc7SDima Dorfman * produces the correct results, most of the other routines will as 62656c5bc7SDima Dorfman * well. 63656c5bc7SDima Dorfman * 64656c5bc7SDima Dorfman * - Internal-use-only routines (i.e., those defined here statically 65656c5bc7SDima Dorfman * and not in mp.h) have an underscore prepended to their name (this 66656c5bc7SDima Dorfman * is more for aesthetical reasons than technical). All such 67656c5bc7SDima Dorfman * routines take an extra argument, 'msg', that denotes what they 68656c5bc7SDima Dorfman * should call themselves in an error message. This is so a user 69656c5bc7SDima Dorfman * doesn't get an error message from a function they didn't call. 70656c5bc7SDima Dorfman */ 71656c5bc7SDima Dorfman 72971e7077SMatthew Dillon #include <sys/cdefs.h> 73971e7077SMatthew Dillon __FBSDID("$FreeBSD$"); 74656c5bc7SDima Dorfman 75656c5bc7SDima Dorfman #include <ctype.h> 76656c5bc7SDima Dorfman #include <err.h> 77656c5bc7SDima Dorfman #include <errno.h> 78656c5bc7SDima Dorfman #include <stdio.h> 79656c5bc7SDima Dorfman #include <stdlib.h> 80656c5bc7SDima Dorfman #include <string.h> 81656c5bc7SDima Dorfman 82656c5bc7SDima Dorfman #include <openssl/crypto.h> 83656c5bc7SDima Dorfman #include <openssl/err.h> 84656c5bc7SDima Dorfman 85656c5bc7SDima Dorfman #include "mp.h" 86656c5bc7SDima Dorfman 87656c5bc7SDima Dorfman #define MPERR(s) do { warn s; abort(); } while (0) 88656c5bc7SDima Dorfman #define MPERRX(s) do { warnx s; abort(); } while (0) 89656c5bc7SDima Dorfman #define BN_ERRCHECK(msg, expr) do { \ 90656c5bc7SDima Dorfman if (!(expr)) _bnerr(msg); \ 91656c5bc7SDima Dorfman } while (0) 92656c5bc7SDima Dorfman 93656c5bc7SDima Dorfman static void _bnerr(const char *); 94656c5bc7SDima Dorfman static MINT *_dtom(const char *, const char *); 95656c5bc7SDima Dorfman static MINT *_itom(const char *, short); 96656c5bc7SDima Dorfman static void _madd(const char *, const MINT *, const MINT *, MINT *); 97656c5bc7SDima Dorfman static int _mcmpa(const char *, const MINT *, const MINT *); 9878078a56SSimon L. B. Nielsen static void _mdiv(const char *, const MINT *, const MINT *, MINT *, MINT *, 9978078a56SSimon L. B. Nielsen BN_CTX *); 100656c5bc7SDima Dorfman static void _mfree(const char *, MINT *); 101656c5bc7SDima Dorfman static void _moveb(const char *, const BIGNUM *, MINT *); 102656c5bc7SDima Dorfman static void _movem(const char *, const MINT *, MINT *); 103656c5bc7SDima Dorfman static void _msub(const char *, const MINT *, const MINT *, MINT *); 104656c5bc7SDima Dorfman static char *_mtod(const char *, const MINT *); 105656c5bc7SDima Dorfman static char *_mtox(const char *, const MINT *); 10678078a56SSimon L. B. Nielsen static void _mult(const char *, const MINT *, const MINT *, MINT *, BN_CTX *); 10778078a56SSimon L. B. Nielsen static void _sdiv(const char *, const MINT *, short, MINT *, short *, BN_CTX *); 108656c5bc7SDima Dorfman static MINT *_xtom(const char *, const char *); 109656c5bc7SDima Dorfman 110656c5bc7SDima Dorfman /* 111656c5bc7SDima Dorfman * Report an error from one of the BN_* functions using MPERRX. 112656c5bc7SDima Dorfman */ 113656c5bc7SDima Dorfman static void 114656c5bc7SDima Dorfman _bnerr(const char *msg) 115656c5bc7SDima Dorfman { 116656c5bc7SDima Dorfman 117656c5bc7SDima Dorfman ERR_load_crypto_strings(); 118656c5bc7SDima Dorfman MPERRX(("%s: %s", msg, ERR_reason_error_string(ERR_get_error()))); 119656c5bc7SDima Dorfman } 120656c5bc7SDima Dorfman 121656c5bc7SDima Dorfman /* 122656c5bc7SDima Dorfman * Convert a decimal string to an MINT. 123656c5bc7SDima Dorfman */ 124656c5bc7SDima Dorfman static MINT * 125656c5bc7SDima Dorfman _dtom(const char *msg, const char *s) 126656c5bc7SDima Dorfman { 127656c5bc7SDima Dorfman MINT *mp; 128656c5bc7SDima Dorfman 129656c5bc7SDima Dorfman mp = malloc(sizeof(*mp)); 130656c5bc7SDima Dorfman if (mp == NULL) 131656c5bc7SDima Dorfman MPERR(("%s", msg)); 132656c5bc7SDima Dorfman mp->bn = BN_new(); 133656c5bc7SDima Dorfman if (mp->bn == NULL) 134656c5bc7SDima Dorfman _bnerr(msg); 135656c5bc7SDima Dorfman BN_ERRCHECK(msg, BN_dec2bn(&mp->bn, s)); 136656c5bc7SDima Dorfman return (mp); 137656c5bc7SDima Dorfman } 138656c5bc7SDima Dorfman 139656c5bc7SDima Dorfman /* 140656c5bc7SDima Dorfman * Compute the greatest common divisor of mp1 and mp2; result goes in rmp. 141656c5bc7SDima Dorfman */ 142656c5bc7SDima Dorfman void 143b3aaa0ccSEd Schouten mp_gcd(const MINT *mp1, const MINT *mp2, MINT *rmp) 144656c5bc7SDima Dorfman { 145656c5bc7SDima Dorfman BIGNUM b; 14676f29359SSimon L. B. Nielsen BN_CTX *c; 147656c5bc7SDima Dorfman 14876f29359SSimon L. B. Nielsen c = BN_CTX_new(); 14976f29359SSimon L. B. Nielsen if (c == NULL) 15076f29359SSimon L. B. Nielsen _bnerr("gcd"); 151656c5bc7SDima Dorfman BN_init(&b); 15276f29359SSimon L. B. Nielsen BN_ERRCHECK("gcd", BN_gcd(&b, mp1->bn, mp2->bn, c)); 153656c5bc7SDima Dorfman _moveb("gcd", &b, rmp); 154656c5bc7SDima Dorfman BN_free(&b); 15576f29359SSimon L. B. Nielsen BN_CTX_free(c); 156656c5bc7SDima Dorfman } 157656c5bc7SDima Dorfman 158656c5bc7SDima Dorfman /* 159656c5bc7SDima Dorfman * Make an MINT out of a short integer. Return value must be mfree()'d. 160656c5bc7SDima Dorfman */ 161656c5bc7SDima Dorfman static MINT * 162656c5bc7SDima Dorfman _itom(const char *msg, short n) 163656c5bc7SDima Dorfman { 164656c5bc7SDima Dorfman MINT *mp; 165656c5bc7SDima Dorfman char *s; 166656c5bc7SDima Dorfman 167656c5bc7SDima Dorfman asprintf(&s, "%x", n); 168656c5bc7SDima Dorfman if (s == NULL) 169656c5bc7SDima Dorfman MPERR(("%s", msg)); 170656c5bc7SDima Dorfman mp = _xtom(msg, s); 171656c5bc7SDima Dorfman free(s); 172656c5bc7SDima Dorfman return (mp); 173656c5bc7SDima Dorfman } 174656c5bc7SDima Dorfman 175656c5bc7SDima Dorfman MINT * 176b3aaa0ccSEd Schouten mp_itom(short n) 177656c5bc7SDima Dorfman { 178656c5bc7SDima Dorfman 179656c5bc7SDima Dorfman return (_itom("itom", n)); 180656c5bc7SDima Dorfman } 181656c5bc7SDima Dorfman 182656c5bc7SDima Dorfman /* 183656c5bc7SDima Dorfman * Compute rmp=mp1+mp2. 184656c5bc7SDima Dorfman */ 185656c5bc7SDima Dorfman static void 186656c5bc7SDima Dorfman _madd(const char *msg, const MINT *mp1, const MINT *mp2, MINT *rmp) 187656c5bc7SDima Dorfman { 188656c5bc7SDima Dorfman BIGNUM b; 189656c5bc7SDima Dorfman 190656c5bc7SDima Dorfman BN_init(&b); 191656c5bc7SDima Dorfman BN_ERRCHECK(msg, BN_add(&b, mp1->bn, mp2->bn)); 192656c5bc7SDima Dorfman _moveb(msg, &b, rmp); 193656c5bc7SDima Dorfman BN_free(&b); 194656c5bc7SDima Dorfman } 195656c5bc7SDima Dorfman 196656c5bc7SDima Dorfman void 197b3aaa0ccSEd Schouten mp_madd(const MINT *mp1, const MINT *mp2, MINT *rmp) 198656c5bc7SDima Dorfman { 199656c5bc7SDima Dorfman 200656c5bc7SDima Dorfman _madd("madd", mp1, mp2, rmp); 201656c5bc7SDima Dorfman } 202656c5bc7SDima Dorfman 203656c5bc7SDima Dorfman /* 204656c5bc7SDima Dorfman * Return -1, 0, or 1 if mp1<mp2, mp1==mp2, or mp1>mp2, respectivley. 205656c5bc7SDima Dorfman */ 206656c5bc7SDima Dorfman int 207b3aaa0ccSEd Schouten mp_mcmp(const MINT *mp1, const MINT *mp2) 208656c5bc7SDima Dorfman { 209656c5bc7SDima Dorfman 210656c5bc7SDima Dorfman return (BN_cmp(mp1->bn, mp2->bn)); 211656c5bc7SDima Dorfman } 212656c5bc7SDima Dorfman 213656c5bc7SDima Dorfman /* 214656c5bc7SDima Dorfman * Same as mcmp but compares absolute values. 215656c5bc7SDima Dorfman */ 216656c5bc7SDima Dorfman static int 217656c5bc7SDima Dorfman _mcmpa(const char *msg __unused, const MINT *mp1, const MINT *mp2) 218656c5bc7SDima Dorfman { 219656c5bc7SDima Dorfman 220656c5bc7SDima Dorfman return (BN_ucmp(mp1->bn, mp2->bn)); 221656c5bc7SDima Dorfman } 222656c5bc7SDima Dorfman 223656c5bc7SDima Dorfman /* 224656c5bc7SDima Dorfman * Compute qmp=nmp/dmp and rmp=nmp%dmp. 225656c5bc7SDima Dorfman */ 226656c5bc7SDima Dorfman static void 22778078a56SSimon L. B. Nielsen _mdiv(const char *msg, const MINT *nmp, const MINT *dmp, MINT *qmp, MINT *rmp, 22878078a56SSimon L. B. Nielsen BN_CTX *c) 229656c5bc7SDima Dorfman { 230656c5bc7SDima Dorfman BIGNUM q, r; 231656c5bc7SDima Dorfman 232656c5bc7SDima Dorfman BN_init(&r); 233656c5bc7SDima Dorfman BN_init(&q); 23476f29359SSimon L. B. Nielsen BN_ERRCHECK(msg, BN_div(&q, &r, nmp->bn, dmp->bn, c)); 235656c5bc7SDima Dorfman _moveb(msg, &q, qmp); 236656c5bc7SDima Dorfman _moveb(msg, &r, rmp); 237656c5bc7SDima Dorfman BN_free(&q); 238656c5bc7SDima Dorfman BN_free(&r); 239656c5bc7SDima Dorfman } 240656c5bc7SDima Dorfman 241656c5bc7SDima Dorfman void 242b3aaa0ccSEd Schouten mp_mdiv(const MINT *nmp, const MINT *dmp, MINT *qmp, MINT *rmp) 243656c5bc7SDima Dorfman { 24478078a56SSimon L. B. Nielsen BN_CTX *c; 245656c5bc7SDima Dorfman 24678078a56SSimon L. B. Nielsen c = BN_CTX_new(); 24778078a56SSimon L. B. Nielsen if (c == NULL) 24878078a56SSimon L. B. Nielsen _bnerr("mdiv"); 24978078a56SSimon L. B. Nielsen _mdiv("mdiv", nmp, dmp, qmp, rmp, c); 25078078a56SSimon L. B. Nielsen BN_CTX_free(c); 251656c5bc7SDima Dorfman } 252656c5bc7SDima Dorfman 253656c5bc7SDima Dorfman /* 254656c5bc7SDima Dorfman * Free memory associated with an MINT. 255656c5bc7SDima Dorfman */ 256656c5bc7SDima Dorfman static void 257656c5bc7SDima Dorfman _mfree(const char *msg __unused, MINT *mp) 258656c5bc7SDima Dorfman { 259656c5bc7SDima Dorfman 260656c5bc7SDima Dorfman BN_clear(mp->bn); 261656c5bc7SDima Dorfman BN_free(mp->bn); 262656c5bc7SDima Dorfman free(mp); 263656c5bc7SDima Dorfman } 264656c5bc7SDima Dorfman 265656c5bc7SDima Dorfman void 266b3aaa0ccSEd Schouten mp_mfree(MINT *mp) 267656c5bc7SDima Dorfman { 268656c5bc7SDima Dorfman 269656c5bc7SDima Dorfman _mfree("mfree", mp); 270656c5bc7SDima Dorfman } 271656c5bc7SDima Dorfman 272656c5bc7SDima Dorfman /* 273656c5bc7SDima Dorfman * Read an integer from standard input and stick the result in mp. 274656c5bc7SDima Dorfman * The input is treated to be in base 10. This must be the silliest 275656c5bc7SDima Dorfman * API in existence; why can't the program read in a string and call 276656c5bc7SDima Dorfman * xtom()? (Or if base 10 is desires, perhaps dtom() could be 277656c5bc7SDima Dorfman * exported.) 278656c5bc7SDima Dorfman */ 279656c5bc7SDima Dorfman void 280b3aaa0ccSEd Schouten mp_min(MINT *mp) 281656c5bc7SDima Dorfman { 282656c5bc7SDima Dorfman MINT *rmp; 283656c5bc7SDima Dorfman char *line, *nline; 284656c5bc7SDima Dorfman size_t linelen; 285656c5bc7SDima Dorfman 286656c5bc7SDima Dorfman line = fgetln(stdin, &linelen); 287656c5bc7SDima Dorfman if (line == NULL) 288656c5bc7SDima Dorfman MPERR(("min")); 289*d0725e22SConrad Meyer nline = malloc(linelen + 1); 290656c5bc7SDima Dorfman if (nline == NULL) 291656c5bc7SDima Dorfman MPERR(("min")); 292*d0725e22SConrad Meyer memcpy(nline, line, linelen); 293656c5bc7SDima Dorfman nline[linelen] = '\0'; 294656c5bc7SDima Dorfman rmp = _dtom("min", nline); 295656c5bc7SDima Dorfman _movem("min", rmp, mp); 296656c5bc7SDima Dorfman _mfree("min", rmp); 297656c5bc7SDima Dorfman free(nline); 298656c5bc7SDima Dorfman } 299656c5bc7SDima Dorfman 300656c5bc7SDima Dorfman /* 301656c5bc7SDima Dorfman * Print the value of mp to standard output in base 10. See blurb 302656c5bc7SDima Dorfman * above min() for why this is so useless. 303656c5bc7SDima Dorfman */ 304656c5bc7SDima Dorfman void 305b3aaa0ccSEd Schouten mp_mout(const MINT *mp) 306656c5bc7SDima Dorfman { 307656c5bc7SDima Dorfman char *s; 308656c5bc7SDima Dorfman 309656c5bc7SDima Dorfman s = _mtod("mout", mp); 310656c5bc7SDima Dorfman printf("%s", s); 311656c5bc7SDima Dorfman free(s); 312656c5bc7SDima Dorfman } 313656c5bc7SDima Dorfman 314656c5bc7SDima Dorfman /* 315656c5bc7SDima Dorfman * Set the value of tmp to the value of smp (i.e., tmp=smp). 316656c5bc7SDima Dorfman */ 317656c5bc7SDima Dorfman void 318b3aaa0ccSEd Schouten mp_move(const MINT *smp, MINT *tmp) 319656c5bc7SDima Dorfman { 320656c5bc7SDima Dorfman 321656c5bc7SDima Dorfman _movem("move", smp, tmp); 322656c5bc7SDima Dorfman } 323656c5bc7SDima Dorfman 324656c5bc7SDima Dorfman 325656c5bc7SDima Dorfman /* 326656c5bc7SDima Dorfman * Internal routine to set the value of tmp to that of sbp. 327656c5bc7SDima Dorfman */ 328656c5bc7SDima Dorfman static void 329656c5bc7SDima Dorfman _moveb(const char *msg, const BIGNUM *sbp, MINT *tmp) 330656c5bc7SDima Dorfman { 331656c5bc7SDima Dorfman 332656c5bc7SDima Dorfman BN_ERRCHECK(msg, BN_copy(tmp->bn, sbp)); 333656c5bc7SDima Dorfman } 334656c5bc7SDima Dorfman 335656c5bc7SDima Dorfman /* 336656c5bc7SDima Dorfman * Internal routine to set the value of tmp to that of smp. 337656c5bc7SDima Dorfman */ 338656c5bc7SDima Dorfman static void 339656c5bc7SDima Dorfman _movem(const char *msg, const MINT *smp, MINT *tmp) 340656c5bc7SDima Dorfman { 341656c5bc7SDima Dorfman 342656c5bc7SDima Dorfman BN_ERRCHECK(msg, BN_copy(tmp->bn, smp->bn)); 343656c5bc7SDima Dorfman } 344656c5bc7SDima Dorfman 345656c5bc7SDima Dorfman /* 346656c5bc7SDima Dorfman * Compute the square root of nmp and put the result in xmp. The 347656c5bc7SDima Dorfman * remainder goes in rmp. Should satisfy: rmp=nmp-(xmp*xmp). 348656c5bc7SDima Dorfman * 349656c5bc7SDima Dorfman * Note that the OpenSSL BIGNUM library does not have a square root 350656c5bc7SDima Dorfman * function, so this had to be implemented by hand using Newton's 351656c5bc7SDima Dorfman * recursive formula: 352656c5bc7SDima Dorfman * 353656c5bc7SDima Dorfman * x = (x + (n / x)) / 2 354656c5bc7SDima Dorfman * 355656c5bc7SDima Dorfman * where x is the square root of the positive number n. In the 356656c5bc7SDima Dorfman * beginning, x should be a reasonable guess, but the value 1, 357656c5bc7SDima Dorfman * although suboptimal, works, too; this is that is used below. 358656c5bc7SDima Dorfman */ 359656c5bc7SDima Dorfman void 360b3aaa0ccSEd Schouten mp_msqrt(const MINT *nmp, MINT *xmp, MINT *rmp) 361656c5bc7SDima Dorfman { 36278078a56SSimon L. B. Nielsen BN_CTX *c; 363656c5bc7SDima Dorfman MINT *tolerance; 364656c5bc7SDima Dorfman MINT *ox, *x; 365656c5bc7SDima Dorfman MINT *z1, *z2, *z3; 366656c5bc7SDima Dorfman short i; 367656c5bc7SDima Dorfman 36878078a56SSimon L. B. Nielsen c = BN_CTX_new(); 36978078a56SSimon L. B. Nielsen if (c == NULL) 37078078a56SSimon L. B. Nielsen _bnerr("msqrt"); 371656c5bc7SDima Dorfman tolerance = _itom("msqrt", 1); 372656c5bc7SDima Dorfman x = _itom("msqrt", 1); 373656c5bc7SDima Dorfman ox = _itom("msqrt", 0); 374656c5bc7SDima Dorfman z1 = _itom("msqrt", 0); 375656c5bc7SDima Dorfman z2 = _itom("msqrt", 0); 376656c5bc7SDima Dorfman z3 = _itom("msqrt", 0); 377656c5bc7SDima Dorfman do { 378656c5bc7SDima Dorfman _movem("msqrt", x, ox); 37978078a56SSimon L. B. Nielsen _mdiv("msqrt", nmp, x, z1, z2, c); 380656c5bc7SDima Dorfman _madd("msqrt", x, z1, z2); 38178078a56SSimon L. B. Nielsen _sdiv("msqrt", z2, 2, x, &i, c); 382656c5bc7SDima Dorfman _msub("msqrt", ox, x, z3); 383656c5bc7SDima Dorfman } while (_mcmpa("msqrt", z3, tolerance) == 1); 384656c5bc7SDima Dorfman _movem("msqrt", x, xmp); 38578078a56SSimon L. B. Nielsen _mult("msqrt", x, x, z1, c); 386656c5bc7SDima Dorfman _msub("msqrt", nmp, z1, z2); 387656c5bc7SDima Dorfman _movem("msqrt", z2, rmp); 388656c5bc7SDima Dorfman _mfree("msqrt", tolerance); 389656c5bc7SDima Dorfman _mfree("msqrt", ox); 390656c5bc7SDima Dorfman _mfree("msqrt", x); 391656c5bc7SDima Dorfman _mfree("msqrt", z1); 392656c5bc7SDima Dorfman _mfree("msqrt", z2); 393656c5bc7SDima Dorfman _mfree("msqrt", z3); 39478078a56SSimon L. B. Nielsen BN_CTX_free(c); 395656c5bc7SDima Dorfman } 396656c5bc7SDima Dorfman 397656c5bc7SDima Dorfman /* 398656c5bc7SDima Dorfman * Compute rmp=mp1-mp2. 399656c5bc7SDima Dorfman */ 400656c5bc7SDima Dorfman static void 401656c5bc7SDima Dorfman _msub(const char *msg, const MINT *mp1, const MINT *mp2, MINT *rmp) 402656c5bc7SDima Dorfman { 403656c5bc7SDima Dorfman BIGNUM b; 404656c5bc7SDima Dorfman 405656c5bc7SDima Dorfman BN_init(&b); 406656c5bc7SDima Dorfman BN_ERRCHECK(msg, BN_sub(&b, mp1->bn, mp2->bn)); 407656c5bc7SDima Dorfman _moveb(msg, &b, rmp); 408656c5bc7SDima Dorfman BN_free(&b); 409656c5bc7SDima Dorfman } 410656c5bc7SDima Dorfman 411656c5bc7SDima Dorfman void 412b3aaa0ccSEd Schouten mp_msub(const MINT *mp1, const MINT *mp2, MINT *rmp) 413656c5bc7SDima Dorfman { 414656c5bc7SDima Dorfman 415656c5bc7SDima Dorfman _msub("msub", mp1, mp2, rmp); 416656c5bc7SDima Dorfman } 417656c5bc7SDima Dorfman 418656c5bc7SDima Dorfman /* 419656c5bc7SDima Dorfman * Return a decimal representation of mp. Return value must be 420656c5bc7SDima Dorfman * free()'d. 421656c5bc7SDima Dorfman */ 422656c5bc7SDima Dorfman static char * 423656c5bc7SDima Dorfman _mtod(const char *msg, const MINT *mp) 424656c5bc7SDima Dorfman { 425656c5bc7SDima Dorfman char *s, *s2; 426656c5bc7SDima Dorfman 427656c5bc7SDima Dorfman s = BN_bn2dec(mp->bn); 428656c5bc7SDima Dorfman if (s == NULL) 429656c5bc7SDima Dorfman _bnerr(msg); 430656c5bc7SDima Dorfman asprintf(&s2, "%s", s); 431656c5bc7SDima Dorfman if (s2 == NULL) 432656c5bc7SDima Dorfman MPERR(("%s", msg)); 433656c5bc7SDima Dorfman OPENSSL_free(s); 434656c5bc7SDima Dorfman return (s2); 435656c5bc7SDima Dorfman } 436656c5bc7SDima Dorfman 437656c5bc7SDima Dorfman /* 438656c5bc7SDima Dorfman * Return a hexadecimal representation of mp. Return value must be 439656c5bc7SDima Dorfman * free()'d. 440656c5bc7SDima Dorfman */ 441656c5bc7SDima Dorfman static char * 442656c5bc7SDima Dorfman _mtox(const char *msg, const MINT *mp) 443656c5bc7SDima Dorfman { 444656c5bc7SDima Dorfman char *p, *s, *s2; 445656c5bc7SDima Dorfman int len; 446656c5bc7SDima Dorfman 447656c5bc7SDima Dorfman s = BN_bn2hex(mp->bn); 448656c5bc7SDima Dorfman if (s == NULL) 449656c5bc7SDima Dorfman _bnerr(msg); 450656c5bc7SDima Dorfman asprintf(&s2, "%s", s); 451656c5bc7SDima Dorfman if (s2 == NULL) 452656c5bc7SDima Dorfman MPERR(("%s", msg)); 453656c5bc7SDima Dorfman OPENSSL_free(s); 454656c5bc7SDima Dorfman 455656c5bc7SDima Dorfman /* 456656c5bc7SDima Dorfman * This is a kludge for libgmp compatibility. The latter's 457656c5bc7SDima Dorfman * implementation of this function returns lower-case letters, 458656c5bc7SDima Dorfman * but BN_bn2hex returns upper-case. Some programs (e.g., 459656c5bc7SDima Dorfman * newkey(1)) are sensitive to this. Although it's probably 460656c5bc7SDima Dorfman * their fault, it's nice to be compatible. 461656c5bc7SDima Dorfman */ 462656c5bc7SDima Dorfman len = strlen(s2); 463656c5bc7SDima Dorfman for (p = s2; p < s2 + len; p++) 464656c5bc7SDima Dorfman *p = tolower(*p); 465656c5bc7SDima Dorfman 466656c5bc7SDima Dorfman return (s2); 467656c5bc7SDima Dorfman } 468656c5bc7SDima Dorfman 469656c5bc7SDima Dorfman char * 470b3aaa0ccSEd Schouten mp_mtox(const MINT *mp) 471656c5bc7SDima Dorfman { 472656c5bc7SDima Dorfman 473656c5bc7SDima Dorfman return (_mtox("mtox", mp)); 474656c5bc7SDima Dorfman } 475656c5bc7SDima Dorfman 476656c5bc7SDima Dorfman /* 477656c5bc7SDima Dorfman * Compute rmp=mp1*mp2. 478656c5bc7SDima Dorfman */ 479656c5bc7SDima Dorfman static void 48078078a56SSimon L. B. Nielsen _mult(const char *msg, const MINT *mp1, const MINT *mp2, MINT *rmp, BN_CTX *c) 481656c5bc7SDima Dorfman { 482656c5bc7SDima Dorfman BIGNUM b; 483656c5bc7SDima Dorfman 484656c5bc7SDima Dorfman BN_init(&b); 48576f29359SSimon L. B. Nielsen BN_ERRCHECK(msg, BN_mul(&b, mp1->bn, mp2->bn, c)); 486656c5bc7SDima Dorfman _moveb(msg, &b, rmp); 487656c5bc7SDima Dorfman BN_free(&b); 488656c5bc7SDima Dorfman } 489656c5bc7SDima Dorfman 490656c5bc7SDima Dorfman void 491b3aaa0ccSEd Schouten mp_mult(const MINT *mp1, const MINT *mp2, MINT *rmp) 492656c5bc7SDima Dorfman { 49378078a56SSimon L. B. Nielsen BN_CTX *c; 494656c5bc7SDima Dorfman 49578078a56SSimon L. B. Nielsen c = BN_CTX_new(); 49678078a56SSimon L. B. Nielsen if (c == NULL) 49778078a56SSimon L. B. Nielsen _bnerr("mult"); 49878078a56SSimon L. B. Nielsen _mult("mult", mp1, mp2, rmp, c); 49978078a56SSimon L. B. Nielsen BN_CTX_free(c); 500656c5bc7SDima Dorfman } 501656c5bc7SDima Dorfman 502656c5bc7SDima Dorfman /* 503656c5bc7SDima Dorfman * Compute rmp=(bmp^emp)mod mmp. (Note that here and above rpow() '^' 504656c5bc7SDima Dorfman * means 'raise to power', not 'bitwise XOR'.) 505656c5bc7SDima Dorfman */ 506656c5bc7SDima Dorfman void 507b3aaa0ccSEd Schouten mp_pow(const MINT *bmp, const MINT *emp, const MINT *mmp, MINT *rmp) 508656c5bc7SDima Dorfman { 509656c5bc7SDima Dorfman BIGNUM b; 51076f29359SSimon L. B. Nielsen BN_CTX *c; 511656c5bc7SDima Dorfman 51276f29359SSimon L. B. Nielsen c = BN_CTX_new(); 51376f29359SSimon L. B. Nielsen if (c == NULL) 51476f29359SSimon L. B. Nielsen _bnerr("pow"); 515656c5bc7SDima Dorfman BN_init(&b); 51676f29359SSimon L. B. Nielsen BN_ERRCHECK("pow", BN_mod_exp(&b, bmp->bn, emp->bn, mmp->bn, c)); 517656c5bc7SDima Dorfman _moveb("pow", &b, rmp); 518656c5bc7SDima Dorfman BN_free(&b); 51976f29359SSimon L. B. Nielsen BN_CTX_free(c); 520656c5bc7SDima Dorfman } 521656c5bc7SDima Dorfman 522656c5bc7SDima Dorfman /* 523656c5bc7SDima Dorfman * Compute rmp=bmp^e. (See note above pow().) 524656c5bc7SDima Dorfman */ 525656c5bc7SDima Dorfman void 526b3aaa0ccSEd Schouten mp_rpow(const MINT *bmp, short e, MINT *rmp) 527656c5bc7SDima Dorfman { 528656c5bc7SDima Dorfman MINT *emp; 529656c5bc7SDima Dorfman BIGNUM b; 53076f29359SSimon L. B. Nielsen BN_CTX *c; 531656c5bc7SDima Dorfman 53276f29359SSimon L. B. Nielsen c = BN_CTX_new(); 53376f29359SSimon L. B. Nielsen if (c == NULL) 53476f29359SSimon L. B. Nielsen _bnerr("rpow"); 535656c5bc7SDima Dorfman BN_init(&b); 536656c5bc7SDima Dorfman emp = _itom("rpow", e); 53776f29359SSimon L. B. Nielsen BN_ERRCHECK("rpow", BN_exp(&b, bmp->bn, emp->bn, c)); 538656c5bc7SDima Dorfman _moveb("rpow", &b, rmp); 539656c5bc7SDima Dorfman _mfree("rpow", emp); 540656c5bc7SDima Dorfman BN_free(&b); 54176f29359SSimon L. B. Nielsen BN_CTX_free(c); 542656c5bc7SDima Dorfman } 543656c5bc7SDima Dorfman 544656c5bc7SDima Dorfman /* 545656c5bc7SDima Dorfman * Compute qmp=nmp/d and ro=nmp%d. 546656c5bc7SDima Dorfman */ 547656c5bc7SDima Dorfman static void 54878078a56SSimon L. B. Nielsen _sdiv(const char *msg, const MINT *nmp, short d, MINT *qmp, short *ro, 54978078a56SSimon L. B. Nielsen BN_CTX *c) 550656c5bc7SDima Dorfman { 551656c5bc7SDima Dorfman MINT *dmp, *rmp; 552656c5bc7SDima Dorfman BIGNUM q, r; 553656c5bc7SDima Dorfman char *s; 554656c5bc7SDima Dorfman 555656c5bc7SDima Dorfman BN_init(&q); 556656c5bc7SDima Dorfman BN_init(&r); 557656c5bc7SDima Dorfman dmp = _itom(msg, d); 558656c5bc7SDima Dorfman rmp = _itom(msg, 0); 55976f29359SSimon L. B. Nielsen BN_ERRCHECK(msg, BN_div(&q, &r, nmp->bn, dmp->bn, c)); 560656c5bc7SDima Dorfman _moveb(msg, &q, qmp); 561656c5bc7SDima Dorfman _moveb(msg, &r, rmp); 562656c5bc7SDima Dorfman s = _mtox(msg, rmp); 563656c5bc7SDima Dorfman errno = 0; 564656c5bc7SDima Dorfman *ro = strtol(s, NULL, 16); 565656c5bc7SDima Dorfman if (errno != 0) 566656c5bc7SDima Dorfman MPERR(("%s underflow or overflow", msg)); 567656c5bc7SDima Dorfman free(s); 568656c5bc7SDima Dorfman _mfree(msg, dmp); 569656c5bc7SDima Dorfman _mfree(msg, rmp); 570656c5bc7SDima Dorfman BN_free(&r); 571656c5bc7SDima Dorfman BN_free(&q); 572656c5bc7SDima Dorfman } 573656c5bc7SDima Dorfman 574656c5bc7SDima Dorfman void 575b3aaa0ccSEd Schouten mp_sdiv(const MINT *nmp, short d, MINT *qmp, short *ro) 576656c5bc7SDima Dorfman { 57778078a56SSimon L. B. Nielsen BN_CTX *c; 578656c5bc7SDima Dorfman 57978078a56SSimon L. B. Nielsen c = BN_CTX_new(); 58078078a56SSimon L. B. Nielsen if (c == NULL) 58178078a56SSimon L. B. Nielsen _bnerr("sdiv"); 58278078a56SSimon L. B. Nielsen _sdiv("sdiv", nmp, d, qmp, ro, c); 58378078a56SSimon L. B. Nielsen BN_CTX_free(c); 584656c5bc7SDima Dorfman } 585656c5bc7SDima Dorfman 586656c5bc7SDima Dorfman /* 587656c5bc7SDima Dorfman * Convert a hexadecimal string to an MINT. 588656c5bc7SDima Dorfman */ 589656c5bc7SDima Dorfman static MINT * 590656c5bc7SDima Dorfman _xtom(const char *msg, const char *s) 591656c5bc7SDima Dorfman { 592656c5bc7SDima Dorfman MINT *mp; 593656c5bc7SDima Dorfman 594656c5bc7SDima Dorfman mp = malloc(sizeof(*mp)); 595656c5bc7SDima Dorfman if (mp == NULL) 596656c5bc7SDima Dorfman MPERR(("%s", msg)); 597656c5bc7SDima Dorfman mp->bn = BN_new(); 598656c5bc7SDima Dorfman if (mp->bn == NULL) 599656c5bc7SDima Dorfman _bnerr(msg); 600656c5bc7SDima Dorfman BN_ERRCHECK(msg, BN_hex2bn(&mp->bn, s)); 601656c5bc7SDima Dorfman return (mp); 602656c5bc7SDima Dorfman } 603656c5bc7SDima Dorfman 604656c5bc7SDima Dorfman MINT * 605b3aaa0ccSEd Schouten mp_xtom(const char *s) 606656c5bc7SDima Dorfman { 607656c5bc7SDima Dorfman 608656c5bc7SDima Dorfman return (_xtom("xtom", s)); 609656c5bc7SDima Dorfman } 610