xref: /freebsd/lib/libmp/mpasbn.c (revision d0725e2250a7bb232faf10d9668cbbc56cd2485c)
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