15e53a4f9SPedro F. Giffuni /*-
2*4d846d26SWarner Losh * SPDX-License-Identifier: BSD-2-Clause
35e53a4f9SPedro F. Giffuni *
4656c5bc7SDima Dorfman * Copyright (c) 2001 Dima Dorfman.
5656c5bc7SDima Dorfman * All rights reserved.
6656c5bc7SDima Dorfman *
7656c5bc7SDima Dorfman * Redistribution and use in source and binary forms, with or without
8656c5bc7SDima Dorfman * modification, are permitted provided that the following conditions
9656c5bc7SDima Dorfman * are met:
10656c5bc7SDima Dorfman * 1. Redistributions of source code must retain the above copyright
11656c5bc7SDima Dorfman * notice, this list of conditions and the following disclaimer.
12656c5bc7SDima Dorfman * 2. Redistributions in binary form must reproduce the above copyright
13656c5bc7SDima Dorfman * notice, this list of conditions and the following disclaimer in the
14656c5bc7SDima Dorfman * documentation and/or other materials provided with the distribution.
15656c5bc7SDima Dorfman *
16656c5bc7SDima Dorfman * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
17656c5bc7SDima Dorfman * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18656c5bc7SDima Dorfman * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19656c5bc7SDima Dorfman * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
20656c5bc7SDima Dorfman * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
21656c5bc7SDima Dorfman * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
22656c5bc7SDima Dorfman * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
23656c5bc7SDima Dorfman * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
24656c5bc7SDima Dorfman * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
25656c5bc7SDima Dorfman * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
26656c5bc7SDima Dorfman * SUCH DAMAGE.
27656c5bc7SDima Dorfman */
28656c5bc7SDima Dorfman
29656c5bc7SDima Dorfman /*
30656c5bc7SDima Dorfman * This is the traditional Berkeley MP library implemented in terms of
31656c5bc7SDima Dorfman * the OpenSSL BIGNUM library. It was written to replace libgmp, and
32656c5bc7SDima Dorfman * is meant to be as compatible with the latter as feasible.
33656c5bc7SDima Dorfman *
34656c5bc7SDima Dorfman * There seems to be a lack of documentation for the Berkeley MP
35656c5bc7SDima Dorfman * interface. All I could find was libgmp documentation (which didn't
36656c5bc7SDima Dorfman * talk about the semantics of the functions) and an old SunOS 4.1
37656c5bc7SDima Dorfman * manual page from 1989. The latter wasn't very detailed, either,
38656c5bc7SDima Dorfman * but at least described what the function's arguments were. In
39656c5bc7SDima Dorfman * general the interface seems to be archaic, somewhat poorly
40656c5bc7SDima Dorfman * designed, and poorly, if at all, documented. It is considered
41656c5bc7SDima Dorfman * harmful.
42656c5bc7SDima Dorfman *
43656c5bc7SDima Dorfman * Miscellaneous notes on this implementation:
44656c5bc7SDima Dorfman *
45656c5bc7SDima Dorfman * - The SunOS manual page mentioned above indicates that if an error
46656c5bc7SDima Dorfman * occurs, the library should "produce messages and core images."
47656c5bc7SDima Dorfman * Given that most of the functions don't have return values (and
48656c5bc7SDima Dorfman * thus no sane way of alerting the caller to an error), this seems
49656c5bc7SDima Dorfman * reasonable. The MPERR and MPERRX macros call warn and warnx,
50656c5bc7SDima Dorfman * respectively, then abort().
51656c5bc7SDima Dorfman *
52656c5bc7SDima Dorfman * - All the functions which take an argument to be "filled in"
53656c5bc7SDima Dorfman * assume that the argument has been initialized by one of the *tom()
54656c5bc7SDima Dorfman * routines before being passed to it. I never saw this documented
55656c5bc7SDima Dorfman * anywhere, but this seems to be consistent with the way this
56656c5bc7SDima Dorfman * library is used.
57656c5bc7SDima Dorfman *
58656c5bc7SDima Dorfman * - msqrt() is the only routine which had to be implemented which
59656c5bc7SDima Dorfman * doesn't have a close counterpart in the OpenSSL BIGNUM library.
60656c5bc7SDima Dorfman * It was implemented by hand using Newton's recursive formula.
61656c5bc7SDima Dorfman * Doing it this way, although more error-prone, has the positive
62656c5bc7SDima Dorfman * sideaffect of testing a lot of other functions; if msqrt()
63656c5bc7SDima Dorfman * produces the correct results, most of the other routines will as
64656c5bc7SDima Dorfman * well.
65656c5bc7SDima Dorfman *
66656c5bc7SDima Dorfman * - Internal-use-only routines (i.e., those defined here statically
67656c5bc7SDima Dorfman * and not in mp.h) have an underscore prepended to their name (this
68656c5bc7SDima Dorfman * is more for aesthetical reasons than technical). All such
69656c5bc7SDima Dorfman * routines take an extra argument, 'msg', that denotes what they
70656c5bc7SDima Dorfman * should call themselves in an error message. This is so a user
71656c5bc7SDima Dorfman * doesn't get an error message from a function they didn't call.
72656c5bc7SDima Dorfman */
73656c5bc7SDima Dorfman
74971e7077SMatthew Dillon #include <sys/cdefs.h>
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
_bnerr(const char * msg)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 *
_dtom(const char * msg,const char * s)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
mp_gcd(const MINT * mp1,const MINT * mp2,MINT * rmp)143b3aaa0ccSEd Schouten mp_gcd(const MINT *mp1, const MINT *mp2, MINT *rmp)
144656c5bc7SDima Dorfman {
14507f5430dSJung-uk Kim BIGNUM *b;
14676f29359SSimon L. B. Nielsen BN_CTX *c;
147656c5bc7SDima Dorfman
14807f5430dSJung-uk Kim b = NULL;
14976f29359SSimon L. B. Nielsen c = BN_CTX_new();
15007f5430dSJung-uk Kim if (c != NULL)
15107f5430dSJung-uk Kim b = BN_new();
15207f5430dSJung-uk Kim if (c == NULL || b == NULL)
15376f29359SSimon L. B. Nielsen _bnerr("gcd");
15407f5430dSJung-uk Kim BN_ERRCHECK("gcd", BN_gcd(b, mp1->bn, mp2->bn, c));
15507f5430dSJung-uk Kim _moveb("gcd", b, rmp);
15607f5430dSJung-uk Kim BN_free(b);
15776f29359SSimon L. B. Nielsen BN_CTX_free(c);
158656c5bc7SDima Dorfman }
159656c5bc7SDima Dorfman
160656c5bc7SDima Dorfman /*
161656c5bc7SDima Dorfman * Make an MINT out of a short integer. Return value must be mfree()'d.
162656c5bc7SDima Dorfman */
163656c5bc7SDima Dorfman static MINT *
_itom(const char * msg,short n)164656c5bc7SDima Dorfman _itom(const char *msg, short n)
165656c5bc7SDima Dorfman {
166656c5bc7SDima Dorfman MINT *mp;
167656c5bc7SDima Dorfman char *s;
168656c5bc7SDima Dorfman
169656c5bc7SDima Dorfman asprintf(&s, "%x", n);
170656c5bc7SDima Dorfman if (s == NULL)
171656c5bc7SDima Dorfman MPERR(("%s", msg));
172656c5bc7SDima Dorfman mp = _xtom(msg, s);
173656c5bc7SDima Dorfman free(s);
174656c5bc7SDima Dorfman return (mp);
175656c5bc7SDima Dorfman }
176656c5bc7SDima Dorfman
177656c5bc7SDima Dorfman MINT *
mp_itom(short n)178b3aaa0ccSEd Schouten mp_itom(short n)
179656c5bc7SDima Dorfman {
180656c5bc7SDima Dorfman
181656c5bc7SDima Dorfman return (_itom("itom", n));
182656c5bc7SDima Dorfman }
183656c5bc7SDima Dorfman
184656c5bc7SDima Dorfman /*
185656c5bc7SDima Dorfman * Compute rmp=mp1+mp2.
186656c5bc7SDima Dorfman */
187656c5bc7SDima Dorfman static void
_madd(const char * msg,const MINT * mp1,const MINT * mp2,MINT * rmp)188656c5bc7SDima Dorfman _madd(const char *msg, const MINT *mp1, const MINT *mp2, MINT *rmp)
189656c5bc7SDima Dorfman {
19007f5430dSJung-uk Kim BIGNUM *b;
191656c5bc7SDima Dorfman
19207f5430dSJung-uk Kim b = BN_new();
19307f5430dSJung-uk Kim if (b == NULL)
19407f5430dSJung-uk Kim _bnerr(msg);
19507f5430dSJung-uk Kim BN_ERRCHECK(msg, BN_add(b, mp1->bn, mp2->bn));
19607f5430dSJung-uk Kim _moveb(msg, b, rmp);
19707f5430dSJung-uk Kim BN_free(b);
198656c5bc7SDima Dorfman }
199656c5bc7SDima Dorfman
200656c5bc7SDima Dorfman void
mp_madd(const MINT * mp1,const MINT * mp2,MINT * rmp)201b3aaa0ccSEd Schouten mp_madd(const MINT *mp1, const MINT *mp2, MINT *rmp)
202656c5bc7SDima Dorfman {
203656c5bc7SDima Dorfman
204656c5bc7SDima Dorfman _madd("madd", mp1, mp2, rmp);
205656c5bc7SDima Dorfman }
206656c5bc7SDima Dorfman
207656c5bc7SDima Dorfman /*
208656c5bc7SDima Dorfman * Return -1, 0, or 1 if mp1<mp2, mp1==mp2, or mp1>mp2, respectivley.
209656c5bc7SDima Dorfman */
210656c5bc7SDima Dorfman int
mp_mcmp(const MINT * mp1,const MINT * mp2)211b3aaa0ccSEd Schouten mp_mcmp(const MINT *mp1, const MINT *mp2)
212656c5bc7SDima Dorfman {
213656c5bc7SDima Dorfman
214656c5bc7SDima Dorfman return (BN_cmp(mp1->bn, mp2->bn));
215656c5bc7SDima Dorfman }
216656c5bc7SDima Dorfman
217656c5bc7SDima Dorfman /*
218656c5bc7SDima Dorfman * Same as mcmp but compares absolute values.
219656c5bc7SDima Dorfman */
220656c5bc7SDima Dorfman static int
_mcmpa(const char * msg __unused,const MINT * mp1,const MINT * mp2)221656c5bc7SDima Dorfman _mcmpa(const char *msg __unused, const MINT *mp1, const MINT *mp2)
222656c5bc7SDima Dorfman {
223656c5bc7SDima Dorfman
224656c5bc7SDima Dorfman return (BN_ucmp(mp1->bn, mp2->bn));
225656c5bc7SDima Dorfman }
226656c5bc7SDima Dorfman
227656c5bc7SDima Dorfman /*
228656c5bc7SDima Dorfman * Compute qmp=nmp/dmp and rmp=nmp%dmp.
229656c5bc7SDima Dorfman */
230656c5bc7SDima Dorfman static void
_mdiv(const char * msg,const MINT * nmp,const MINT * dmp,MINT * qmp,MINT * rmp,BN_CTX * c)23178078a56SSimon L. B. Nielsen _mdiv(const char *msg, const MINT *nmp, const MINT *dmp, MINT *qmp, MINT *rmp,
23278078a56SSimon L. B. Nielsen BN_CTX *c)
233656c5bc7SDima Dorfman {
23407f5430dSJung-uk Kim BIGNUM *q, *r;
235656c5bc7SDima Dorfman
23607f5430dSJung-uk Kim q = NULL;
23707f5430dSJung-uk Kim r = BN_new();
23807f5430dSJung-uk Kim if (r != NULL)
23907f5430dSJung-uk Kim q = BN_new();
24007f5430dSJung-uk Kim if (r == NULL || q == NULL)
24107f5430dSJung-uk Kim _bnerr(msg);
24207f5430dSJung-uk Kim BN_ERRCHECK(msg, BN_div(q, r, nmp->bn, dmp->bn, c));
24307f5430dSJung-uk Kim _moveb(msg, q, qmp);
24407f5430dSJung-uk Kim _moveb(msg, r, rmp);
24507f5430dSJung-uk Kim BN_free(q);
24607f5430dSJung-uk Kim BN_free(r);
247656c5bc7SDima Dorfman }
248656c5bc7SDima Dorfman
249656c5bc7SDima Dorfman void
mp_mdiv(const MINT * nmp,const MINT * dmp,MINT * qmp,MINT * rmp)250b3aaa0ccSEd Schouten mp_mdiv(const MINT *nmp, const MINT *dmp, MINT *qmp, MINT *rmp)
251656c5bc7SDima Dorfman {
25278078a56SSimon L. B. Nielsen BN_CTX *c;
253656c5bc7SDima Dorfman
25478078a56SSimon L. B. Nielsen c = BN_CTX_new();
25578078a56SSimon L. B. Nielsen if (c == NULL)
25678078a56SSimon L. B. Nielsen _bnerr("mdiv");
25778078a56SSimon L. B. Nielsen _mdiv("mdiv", nmp, dmp, qmp, rmp, c);
25878078a56SSimon L. B. Nielsen BN_CTX_free(c);
259656c5bc7SDima Dorfman }
260656c5bc7SDima Dorfman
261656c5bc7SDima Dorfman /*
262656c5bc7SDima Dorfman * Free memory associated with an MINT.
263656c5bc7SDima Dorfman */
264656c5bc7SDima Dorfman static void
_mfree(const char * msg __unused,MINT * mp)265656c5bc7SDima Dorfman _mfree(const char *msg __unused, MINT *mp)
266656c5bc7SDima Dorfman {
267656c5bc7SDima Dorfman
268656c5bc7SDima Dorfman BN_clear(mp->bn);
269656c5bc7SDima Dorfman BN_free(mp->bn);
270656c5bc7SDima Dorfman free(mp);
271656c5bc7SDima Dorfman }
272656c5bc7SDima Dorfman
273656c5bc7SDima Dorfman void
mp_mfree(MINT * mp)274b3aaa0ccSEd Schouten mp_mfree(MINT *mp)
275656c5bc7SDima Dorfman {
276656c5bc7SDima Dorfman
277656c5bc7SDima Dorfman _mfree("mfree", mp);
278656c5bc7SDima Dorfman }
279656c5bc7SDima Dorfman
280656c5bc7SDima Dorfman /*
281656c5bc7SDima Dorfman * Read an integer from standard input and stick the result in mp.
282656c5bc7SDima Dorfman * The input is treated to be in base 10. This must be the silliest
283656c5bc7SDima Dorfman * API in existence; why can't the program read in a string and call
284656c5bc7SDima Dorfman * xtom()? (Or if base 10 is desires, perhaps dtom() could be
285656c5bc7SDima Dorfman * exported.)
286656c5bc7SDima Dorfman */
287656c5bc7SDima Dorfman void
mp_min(MINT * mp)288b3aaa0ccSEd Schouten mp_min(MINT *mp)
289656c5bc7SDima Dorfman {
290656c5bc7SDima Dorfman MINT *rmp;
291656c5bc7SDima Dorfman char *line, *nline;
292656c5bc7SDima Dorfman size_t linelen;
293656c5bc7SDima Dorfman
294656c5bc7SDima Dorfman line = fgetln(stdin, &linelen);
295656c5bc7SDima Dorfman if (line == NULL)
296656c5bc7SDima Dorfman MPERR(("min"));
297d0725e22SConrad Meyer nline = malloc(linelen + 1);
298656c5bc7SDima Dorfman if (nline == NULL)
299656c5bc7SDima Dorfman MPERR(("min"));
300d0725e22SConrad Meyer memcpy(nline, line, linelen);
301656c5bc7SDima Dorfman nline[linelen] = '\0';
302656c5bc7SDima Dorfman rmp = _dtom("min", nline);
303656c5bc7SDima Dorfman _movem("min", rmp, mp);
304656c5bc7SDima Dorfman _mfree("min", rmp);
305656c5bc7SDima Dorfman free(nline);
306656c5bc7SDima Dorfman }
307656c5bc7SDima Dorfman
308656c5bc7SDima Dorfman /*
309656c5bc7SDima Dorfman * Print the value of mp to standard output in base 10. See blurb
310656c5bc7SDima Dorfman * above min() for why this is so useless.
311656c5bc7SDima Dorfman */
312656c5bc7SDima Dorfman void
mp_mout(const MINT * mp)313b3aaa0ccSEd Schouten mp_mout(const MINT *mp)
314656c5bc7SDima Dorfman {
315656c5bc7SDima Dorfman char *s;
316656c5bc7SDima Dorfman
317656c5bc7SDima Dorfman s = _mtod("mout", mp);
318656c5bc7SDima Dorfman printf("%s", s);
319656c5bc7SDima Dorfman free(s);
320656c5bc7SDima Dorfman }
321656c5bc7SDima Dorfman
322656c5bc7SDima Dorfman /*
323656c5bc7SDima Dorfman * Set the value of tmp to the value of smp (i.e., tmp=smp).
324656c5bc7SDima Dorfman */
325656c5bc7SDima Dorfman void
mp_move(const MINT * smp,MINT * tmp)326b3aaa0ccSEd Schouten mp_move(const MINT *smp, MINT *tmp)
327656c5bc7SDima Dorfman {
328656c5bc7SDima Dorfman
329656c5bc7SDima Dorfman _movem("move", smp, tmp);
330656c5bc7SDima Dorfman }
331656c5bc7SDima Dorfman
332656c5bc7SDima Dorfman
333656c5bc7SDima Dorfman /*
334656c5bc7SDima Dorfman * Internal routine to set the value of tmp to that of sbp.
335656c5bc7SDima Dorfman */
336656c5bc7SDima Dorfman static void
_moveb(const char * msg,const BIGNUM * sbp,MINT * tmp)337656c5bc7SDima Dorfman _moveb(const char *msg, const BIGNUM *sbp, MINT *tmp)
338656c5bc7SDima Dorfman {
339656c5bc7SDima Dorfman
340656c5bc7SDima Dorfman BN_ERRCHECK(msg, BN_copy(tmp->bn, sbp));
341656c5bc7SDima Dorfman }
342656c5bc7SDima Dorfman
343656c5bc7SDima Dorfman /*
344656c5bc7SDima Dorfman * Internal routine to set the value of tmp to that of smp.
345656c5bc7SDima Dorfman */
346656c5bc7SDima Dorfman static void
_movem(const char * msg,const MINT * smp,MINT * tmp)347656c5bc7SDima Dorfman _movem(const char *msg, const MINT *smp, MINT *tmp)
348656c5bc7SDima Dorfman {
349656c5bc7SDima Dorfman
350656c5bc7SDima Dorfman BN_ERRCHECK(msg, BN_copy(tmp->bn, smp->bn));
351656c5bc7SDima Dorfman }
352656c5bc7SDima Dorfman
353656c5bc7SDima Dorfman /*
354656c5bc7SDima Dorfman * Compute the square root of nmp and put the result in xmp. The
355656c5bc7SDima Dorfman * remainder goes in rmp. Should satisfy: rmp=nmp-(xmp*xmp).
356656c5bc7SDima Dorfman *
357656c5bc7SDima Dorfman * Note that the OpenSSL BIGNUM library does not have a square root
358656c5bc7SDima Dorfman * function, so this had to be implemented by hand using Newton's
359656c5bc7SDima Dorfman * recursive formula:
360656c5bc7SDima Dorfman *
361656c5bc7SDima Dorfman * x = (x + (n / x)) / 2
362656c5bc7SDima Dorfman *
363656c5bc7SDima Dorfman * where x is the square root of the positive number n. In the
364656c5bc7SDima Dorfman * beginning, x should be a reasonable guess, but the value 1,
365656c5bc7SDima Dorfman * although suboptimal, works, too; this is that is used below.
366656c5bc7SDima Dorfman */
367656c5bc7SDima Dorfman void
mp_msqrt(const MINT * nmp,MINT * xmp,MINT * rmp)368b3aaa0ccSEd Schouten mp_msqrt(const MINT *nmp, MINT *xmp, MINT *rmp)
369656c5bc7SDima Dorfman {
37078078a56SSimon L. B. Nielsen BN_CTX *c;
371656c5bc7SDima Dorfman MINT *tolerance;
372656c5bc7SDima Dorfman MINT *ox, *x;
373656c5bc7SDima Dorfman MINT *z1, *z2, *z3;
374656c5bc7SDima Dorfman short i;
375656c5bc7SDima Dorfman
37678078a56SSimon L. B. Nielsen c = BN_CTX_new();
37778078a56SSimon L. B. Nielsen if (c == NULL)
37878078a56SSimon L. B. Nielsen _bnerr("msqrt");
379656c5bc7SDima Dorfman tolerance = _itom("msqrt", 1);
380656c5bc7SDima Dorfman x = _itom("msqrt", 1);
381656c5bc7SDima Dorfman ox = _itom("msqrt", 0);
382656c5bc7SDima Dorfman z1 = _itom("msqrt", 0);
383656c5bc7SDima Dorfman z2 = _itom("msqrt", 0);
384656c5bc7SDima Dorfman z3 = _itom("msqrt", 0);
385656c5bc7SDima Dorfman do {
386656c5bc7SDima Dorfman _movem("msqrt", x, ox);
38778078a56SSimon L. B. Nielsen _mdiv("msqrt", nmp, x, z1, z2, c);
388656c5bc7SDima Dorfman _madd("msqrt", x, z1, z2);
38978078a56SSimon L. B. Nielsen _sdiv("msqrt", z2, 2, x, &i, c);
390656c5bc7SDima Dorfman _msub("msqrt", ox, x, z3);
391656c5bc7SDima Dorfman } while (_mcmpa("msqrt", z3, tolerance) == 1);
392656c5bc7SDima Dorfman _movem("msqrt", x, xmp);
39378078a56SSimon L. B. Nielsen _mult("msqrt", x, x, z1, c);
394656c5bc7SDima Dorfman _msub("msqrt", nmp, z1, z2);
395656c5bc7SDima Dorfman _movem("msqrt", z2, rmp);
396656c5bc7SDima Dorfman _mfree("msqrt", tolerance);
397656c5bc7SDima Dorfman _mfree("msqrt", ox);
398656c5bc7SDima Dorfman _mfree("msqrt", x);
399656c5bc7SDima Dorfman _mfree("msqrt", z1);
400656c5bc7SDima Dorfman _mfree("msqrt", z2);
401656c5bc7SDima Dorfman _mfree("msqrt", z3);
40278078a56SSimon L. B. Nielsen BN_CTX_free(c);
403656c5bc7SDima Dorfman }
404656c5bc7SDima Dorfman
405656c5bc7SDima Dorfman /*
406656c5bc7SDima Dorfman * Compute rmp=mp1-mp2.
407656c5bc7SDima Dorfman */
408656c5bc7SDima Dorfman static void
_msub(const char * msg,const MINT * mp1,const MINT * mp2,MINT * rmp)409656c5bc7SDima Dorfman _msub(const char *msg, const MINT *mp1, const MINT *mp2, MINT *rmp)
410656c5bc7SDima Dorfman {
41107f5430dSJung-uk Kim BIGNUM *b;
412656c5bc7SDima Dorfman
41307f5430dSJung-uk Kim b = BN_new();
41407f5430dSJung-uk Kim if (b == NULL)
41507f5430dSJung-uk Kim _bnerr(msg);
41607f5430dSJung-uk Kim BN_ERRCHECK(msg, BN_sub(b, mp1->bn, mp2->bn));
41707f5430dSJung-uk Kim _moveb(msg, b, rmp);
41807f5430dSJung-uk Kim BN_free(b);
419656c5bc7SDima Dorfman }
420656c5bc7SDima Dorfman
421656c5bc7SDima Dorfman void
mp_msub(const MINT * mp1,const MINT * mp2,MINT * rmp)422b3aaa0ccSEd Schouten mp_msub(const MINT *mp1, const MINT *mp2, MINT *rmp)
423656c5bc7SDima Dorfman {
424656c5bc7SDima Dorfman
425656c5bc7SDima Dorfman _msub("msub", mp1, mp2, rmp);
426656c5bc7SDima Dorfman }
427656c5bc7SDima Dorfman
428656c5bc7SDima Dorfman /*
429656c5bc7SDima Dorfman * Return a decimal representation of mp. Return value must be
430656c5bc7SDima Dorfman * free()'d.
431656c5bc7SDima Dorfman */
432656c5bc7SDima Dorfman static char *
_mtod(const char * msg,const MINT * mp)433656c5bc7SDima Dorfman _mtod(const char *msg, const MINT *mp)
434656c5bc7SDima Dorfman {
435656c5bc7SDima Dorfman char *s, *s2;
436656c5bc7SDima Dorfman
437656c5bc7SDima Dorfman s = BN_bn2dec(mp->bn);
438656c5bc7SDima Dorfman if (s == NULL)
439656c5bc7SDima Dorfman _bnerr(msg);
440656c5bc7SDima Dorfman asprintf(&s2, "%s", s);
441656c5bc7SDima Dorfman if (s2 == NULL)
442656c5bc7SDima Dorfman MPERR(("%s", msg));
443656c5bc7SDima Dorfman OPENSSL_free(s);
444656c5bc7SDima Dorfman return (s2);
445656c5bc7SDima Dorfman }
446656c5bc7SDima Dorfman
447656c5bc7SDima Dorfman /*
448656c5bc7SDima Dorfman * Return a hexadecimal representation of mp. Return value must be
449656c5bc7SDima Dorfman * free()'d.
450656c5bc7SDima Dorfman */
451656c5bc7SDima Dorfman static char *
_mtox(const char * msg,const MINT * mp)452656c5bc7SDima Dorfman _mtox(const char *msg, const MINT *mp)
453656c5bc7SDima Dorfman {
454656c5bc7SDima Dorfman char *p, *s, *s2;
455656c5bc7SDima Dorfman int len;
456656c5bc7SDima Dorfman
457656c5bc7SDima Dorfman s = BN_bn2hex(mp->bn);
458656c5bc7SDima Dorfman if (s == NULL)
459656c5bc7SDima Dorfman _bnerr(msg);
460656c5bc7SDima Dorfman asprintf(&s2, "%s", s);
461656c5bc7SDima Dorfman if (s2 == NULL)
462656c5bc7SDima Dorfman MPERR(("%s", msg));
463656c5bc7SDima Dorfman OPENSSL_free(s);
464656c5bc7SDima Dorfman
465656c5bc7SDima Dorfman /*
466656c5bc7SDima Dorfman * This is a kludge for libgmp compatibility. The latter's
467656c5bc7SDima Dorfman * implementation of this function returns lower-case letters,
468656c5bc7SDima Dorfman * but BN_bn2hex returns upper-case. Some programs (e.g.,
469656c5bc7SDima Dorfman * newkey(1)) are sensitive to this. Although it's probably
470656c5bc7SDima Dorfman * their fault, it's nice to be compatible.
471656c5bc7SDima Dorfman */
472656c5bc7SDima Dorfman len = strlen(s2);
473656c5bc7SDima Dorfman for (p = s2; p < s2 + len; p++)
474656c5bc7SDima Dorfman *p = tolower(*p);
475656c5bc7SDima Dorfman
476656c5bc7SDima Dorfman return (s2);
477656c5bc7SDima Dorfman }
478656c5bc7SDima Dorfman
479656c5bc7SDima Dorfman char *
mp_mtox(const MINT * mp)480b3aaa0ccSEd Schouten mp_mtox(const MINT *mp)
481656c5bc7SDima Dorfman {
482656c5bc7SDima Dorfman
483656c5bc7SDima Dorfman return (_mtox("mtox", mp));
484656c5bc7SDima Dorfman }
485656c5bc7SDima Dorfman
486656c5bc7SDima Dorfman /*
487656c5bc7SDima Dorfman * Compute rmp=mp1*mp2.
488656c5bc7SDima Dorfman */
489656c5bc7SDima Dorfman static void
_mult(const char * msg,const MINT * mp1,const MINT * mp2,MINT * rmp,BN_CTX * c)49078078a56SSimon L. B. Nielsen _mult(const char *msg, const MINT *mp1, const MINT *mp2, MINT *rmp, BN_CTX *c)
491656c5bc7SDima Dorfman {
49207f5430dSJung-uk Kim BIGNUM *b;
493656c5bc7SDima Dorfman
49407f5430dSJung-uk Kim b = BN_new();
49507f5430dSJung-uk Kim if (b == NULL)
49607f5430dSJung-uk Kim _bnerr(msg);
49707f5430dSJung-uk Kim BN_ERRCHECK(msg, BN_mul(b, mp1->bn, mp2->bn, c));
49807f5430dSJung-uk Kim _moveb(msg, b, rmp);
49907f5430dSJung-uk Kim BN_free(b);
500656c5bc7SDima Dorfman }
501656c5bc7SDima Dorfman
502656c5bc7SDima Dorfman void
mp_mult(const MINT * mp1,const MINT * mp2,MINT * rmp)503b3aaa0ccSEd Schouten mp_mult(const MINT *mp1, const MINT *mp2, MINT *rmp)
504656c5bc7SDima Dorfman {
50578078a56SSimon L. B. Nielsen BN_CTX *c;
506656c5bc7SDima Dorfman
50778078a56SSimon L. B. Nielsen c = BN_CTX_new();
50878078a56SSimon L. B. Nielsen if (c == NULL)
50978078a56SSimon L. B. Nielsen _bnerr("mult");
51078078a56SSimon L. B. Nielsen _mult("mult", mp1, mp2, rmp, c);
51178078a56SSimon L. B. Nielsen BN_CTX_free(c);
512656c5bc7SDima Dorfman }
513656c5bc7SDima Dorfman
514656c5bc7SDima Dorfman /*
515656c5bc7SDima Dorfman * Compute rmp=(bmp^emp)mod mmp. (Note that here and above rpow() '^'
516656c5bc7SDima Dorfman * means 'raise to power', not 'bitwise XOR'.)
517656c5bc7SDima Dorfman */
518656c5bc7SDima Dorfman void
mp_pow(const MINT * bmp,const MINT * emp,const MINT * mmp,MINT * rmp)519b3aaa0ccSEd Schouten mp_pow(const MINT *bmp, const MINT *emp, const MINT *mmp, MINT *rmp)
520656c5bc7SDima Dorfman {
52107f5430dSJung-uk Kim BIGNUM *b;
52276f29359SSimon L. B. Nielsen BN_CTX *c;
523656c5bc7SDima Dorfman
52407f5430dSJung-uk Kim b = NULL;
52576f29359SSimon L. B. Nielsen c = BN_CTX_new();
52607f5430dSJung-uk Kim if (c != NULL)
52707f5430dSJung-uk Kim b = BN_new();
52807f5430dSJung-uk Kim if (c == NULL || b == NULL)
52976f29359SSimon L. B. Nielsen _bnerr("pow");
53007f5430dSJung-uk Kim BN_ERRCHECK("pow", BN_mod_exp(b, bmp->bn, emp->bn, mmp->bn, c));
53107f5430dSJung-uk Kim _moveb("pow", b, rmp);
53207f5430dSJung-uk Kim BN_free(b);
53376f29359SSimon L. B. Nielsen BN_CTX_free(c);
534656c5bc7SDima Dorfman }
535656c5bc7SDima Dorfman
536656c5bc7SDima Dorfman /*
537656c5bc7SDima Dorfman * Compute rmp=bmp^e. (See note above pow().)
538656c5bc7SDima Dorfman */
539656c5bc7SDima Dorfman void
mp_rpow(const MINT * bmp,short e,MINT * rmp)540b3aaa0ccSEd Schouten mp_rpow(const MINT *bmp, short e, MINT *rmp)
541656c5bc7SDima Dorfman {
542656c5bc7SDima Dorfman MINT *emp;
54307f5430dSJung-uk Kim BIGNUM *b;
54476f29359SSimon L. B. Nielsen BN_CTX *c;
545656c5bc7SDima Dorfman
54607f5430dSJung-uk Kim b = NULL;
54776f29359SSimon L. B. Nielsen c = BN_CTX_new();
54807f5430dSJung-uk Kim if (c != NULL)
54907f5430dSJung-uk Kim b = BN_new();
55007f5430dSJung-uk Kim if (c == NULL || b == NULL)
55176f29359SSimon L. B. Nielsen _bnerr("rpow");
552656c5bc7SDima Dorfman emp = _itom("rpow", e);
55307f5430dSJung-uk Kim BN_ERRCHECK("rpow", BN_exp(b, bmp->bn, emp->bn, c));
55407f5430dSJung-uk Kim _moveb("rpow", b, rmp);
555656c5bc7SDima Dorfman _mfree("rpow", emp);
55607f5430dSJung-uk Kim BN_free(b);
55776f29359SSimon L. B. Nielsen BN_CTX_free(c);
558656c5bc7SDima Dorfman }
559656c5bc7SDima Dorfman
560656c5bc7SDima Dorfman /*
561656c5bc7SDima Dorfman * Compute qmp=nmp/d and ro=nmp%d.
562656c5bc7SDima Dorfman */
563656c5bc7SDima Dorfman static void
_sdiv(const char * msg,const MINT * nmp,short d,MINT * qmp,short * ro,BN_CTX * c)56478078a56SSimon L. B. Nielsen _sdiv(const char *msg, const MINT *nmp, short d, MINT *qmp, short *ro,
56578078a56SSimon L. B. Nielsen BN_CTX *c)
566656c5bc7SDima Dorfman {
567656c5bc7SDima Dorfman MINT *dmp, *rmp;
56807f5430dSJung-uk Kim BIGNUM *q, *r;
569656c5bc7SDima Dorfman char *s;
570656c5bc7SDima Dorfman
57107f5430dSJung-uk Kim r = NULL;
57207f5430dSJung-uk Kim q = BN_new();
57307f5430dSJung-uk Kim if (q != NULL)
57407f5430dSJung-uk Kim r = BN_new();
57507f5430dSJung-uk Kim if (q == NULL || r == NULL)
57607f5430dSJung-uk Kim _bnerr(msg);
577656c5bc7SDima Dorfman dmp = _itom(msg, d);
578656c5bc7SDima Dorfman rmp = _itom(msg, 0);
57907f5430dSJung-uk Kim BN_ERRCHECK(msg, BN_div(q, r, nmp->bn, dmp->bn, c));
58007f5430dSJung-uk Kim _moveb(msg, q, qmp);
58107f5430dSJung-uk Kim _moveb(msg, r, rmp);
582656c5bc7SDima Dorfman s = _mtox(msg, rmp);
583656c5bc7SDima Dorfman errno = 0;
584656c5bc7SDima Dorfman *ro = strtol(s, NULL, 16);
585656c5bc7SDima Dorfman if (errno != 0)
586656c5bc7SDima Dorfman MPERR(("%s underflow or overflow", msg));
587656c5bc7SDima Dorfman free(s);
588656c5bc7SDima Dorfman _mfree(msg, dmp);
589656c5bc7SDima Dorfman _mfree(msg, rmp);
59007f5430dSJung-uk Kim BN_free(r);
59107f5430dSJung-uk Kim BN_free(q);
592656c5bc7SDima Dorfman }
593656c5bc7SDima Dorfman
594656c5bc7SDima Dorfman void
mp_sdiv(const MINT * nmp,short d,MINT * qmp,short * ro)595b3aaa0ccSEd Schouten mp_sdiv(const MINT *nmp, short d, MINT *qmp, short *ro)
596656c5bc7SDima Dorfman {
59778078a56SSimon L. B. Nielsen BN_CTX *c;
598656c5bc7SDima Dorfman
59978078a56SSimon L. B. Nielsen c = BN_CTX_new();
60078078a56SSimon L. B. Nielsen if (c == NULL)
60178078a56SSimon L. B. Nielsen _bnerr("sdiv");
60278078a56SSimon L. B. Nielsen _sdiv("sdiv", nmp, d, qmp, ro, c);
60378078a56SSimon L. B. Nielsen BN_CTX_free(c);
604656c5bc7SDima Dorfman }
605656c5bc7SDima Dorfman
606656c5bc7SDima Dorfman /*
607656c5bc7SDima Dorfman * Convert a hexadecimal string to an MINT.
608656c5bc7SDima Dorfman */
609656c5bc7SDima Dorfman static MINT *
_xtom(const char * msg,const char * s)610656c5bc7SDima Dorfman _xtom(const char *msg, const char *s)
611656c5bc7SDima Dorfman {
612656c5bc7SDima Dorfman MINT *mp;
613656c5bc7SDima Dorfman
614656c5bc7SDima Dorfman mp = malloc(sizeof(*mp));
615656c5bc7SDima Dorfman if (mp == NULL)
616656c5bc7SDima Dorfman MPERR(("%s", msg));
617656c5bc7SDima Dorfman mp->bn = BN_new();
618656c5bc7SDima Dorfman if (mp->bn == NULL)
619656c5bc7SDima Dorfman _bnerr(msg);
620656c5bc7SDima Dorfman BN_ERRCHECK(msg, BN_hex2bn(&mp->bn, s));
621656c5bc7SDima Dorfman return (mp);
622656c5bc7SDima Dorfman }
623656c5bc7SDima Dorfman
624656c5bc7SDima Dorfman MINT *
mp_xtom(const char * s)625b3aaa0ccSEd Schouten mp_xtom(const char *s)
626656c5bc7SDima Dorfman {
627656c5bc7SDima Dorfman
628656c5bc7SDima Dorfman return (_xtom("xtom", s));
629656c5bc7SDima Dorfman }
630