1*0a6a1f1dSLionel Sambuc /* $NetBSD: mpi.c,v 1.1.1.3 2014/04/24 12:45:39 pettai Exp $ */
2ebfedea0SLionel Sambuc
3ebfedea0SLionel Sambuc /*
4ebfedea0SLionel Sambuc mpi.c
5ebfedea0SLionel Sambuc
6ebfedea0SLionel Sambuc by Michael J. Fromberger <sting@linguist.dartmouth.edu>
7ebfedea0SLionel Sambuc Copyright (C) 1998 Michael J. Fromberger, All Rights Reserved
8ebfedea0SLionel Sambuc
9ebfedea0SLionel Sambuc Arbitrary precision integer arithmetic library
10ebfedea0SLionel Sambuc
11ebfedea0SLionel Sambuc Id: mpi.c,v 1.2 2005/05/05 14:38:47 tom Exp
12ebfedea0SLionel Sambuc */
13ebfedea0SLionel Sambuc
14ebfedea0SLionel Sambuc #include "mpi.h"
15ebfedea0SLionel Sambuc #include <stdlib.h>
16ebfedea0SLionel Sambuc #include <string.h>
17ebfedea0SLionel Sambuc #include <ctype.h>
18ebfedea0SLionel Sambuc
19ebfedea0SLionel Sambuc #if MP_DEBUG
20ebfedea0SLionel Sambuc #include <stdio.h>
21ebfedea0SLionel Sambuc
22ebfedea0SLionel Sambuc #define DIAG(T,V) {fprintf(stderr,T);mp_print(V,stderr);fputc('\n',stderr);}
23ebfedea0SLionel Sambuc #else
24ebfedea0SLionel Sambuc #define DIAG(T,V)
25ebfedea0SLionel Sambuc #endif
26ebfedea0SLionel Sambuc
27ebfedea0SLionel Sambuc /*
28ebfedea0SLionel Sambuc If MP_LOGTAB is not defined, use the math library to compute the
29ebfedea0SLionel Sambuc logarithms on the fly. Otherwise, use the static table below.
30ebfedea0SLionel Sambuc Pick which works best for your system.
31ebfedea0SLionel Sambuc */
32ebfedea0SLionel Sambuc #if MP_LOGTAB
33ebfedea0SLionel Sambuc
34ebfedea0SLionel Sambuc /* {{{ s_logv_2[] - log table for 2 in various bases */
35ebfedea0SLionel Sambuc
36ebfedea0SLionel Sambuc /*
37ebfedea0SLionel Sambuc A table of the logs of 2 for various bases (the 0 and 1 entries of
38ebfedea0SLionel Sambuc this table are meaningless and should not be referenced).
39ebfedea0SLionel Sambuc
40ebfedea0SLionel Sambuc This table is used to compute output lengths for the mp_toradix()
41ebfedea0SLionel Sambuc function. Since a number n in radix r takes up about log_r(n)
42ebfedea0SLionel Sambuc digits, we estimate the output size by taking the least integer
43ebfedea0SLionel Sambuc greater than log_r(n), where:
44ebfedea0SLionel Sambuc
45ebfedea0SLionel Sambuc log_r(n) = log_2(n) * log_r(2)
46ebfedea0SLionel Sambuc
47ebfedea0SLionel Sambuc This table, therefore, is a table of log_r(2) for 2 <= r <= 36,
48ebfedea0SLionel Sambuc which are the output bases supported.
49ebfedea0SLionel Sambuc */
50ebfedea0SLionel Sambuc
51ebfedea0SLionel Sambuc #include "logtab.h"
52ebfedea0SLionel Sambuc
53ebfedea0SLionel Sambuc /* }}} */
54ebfedea0SLionel Sambuc #define LOG_V_2(R) s_logv_2[(R)]
55ebfedea0SLionel Sambuc
56ebfedea0SLionel Sambuc #else
57ebfedea0SLionel Sambuc
58ebfedea0SLionel Sambuc #include <math.h>
59ebfedea0SLionel Sambuc #define LOG_V_2(R) (log(2.0)/log(R))
60ebfedea0SLionel Sambuc
61ebfedea0SLionel Sambuc #endif
62ebfedea0SLionel Sambuc
63ebfedea0SLionel Sambuc /* Default precision for newly created mp_int's */
64ebfedea0SLionel Sambuc static unsigned int s_mp_defprec = MP_DEFPREC;
65ebfedea0SLionel Sambuc
66ebfedea0SLionel Sambuc /* {{{ Digit arithmetic macros */
67ebfedea0SLionel Sambuc
68ebfedea0SLionel Sambuc /*
69ebfedea0SLionel Sambuc When adding and multiplying digits, the results can be larger than
70ebfedea0SLionel Sambuc can be contained in an mp_digit. Thus, an mp_word is used. These
71ebfedea0SLionel Sambuc macros mask off the upper and lower digits of the mp_word (the
72ebfedea0SLionel Sambuc mp_word may be more than 2 mp_digits wide, but we only concern
73ebfedea0SLionel Sambuc ourselves with the low-order 2 mp_digits)
74ebfedea0SLionel Sambuc
75ebfedea0SLionel Sambuc If your mp_word DOES have more than 2 mp_digits, you need to
76ebfedea0SLionel Sambuc uncomment the first line, and comment out the second.
77ebfedea0SLionel Sambuc */
78ebfedea0SLionel Sambuc
79ebfedea0SLionel Sambuc /* #define CARRYOUT(W) (((W)>>DIGIT_BIT)&MP_DIGIT_MAX) */
80ebfedea0SLionel Sambuc #define CARRYOUT(W) ((W)>>DIGIT_BIT)
81ebfedea0SLionel Sambuc #define ACCUM(W) ((W)&MP_DIGIT_MAX)
82ebfedea0SLionel Sambuc
83ebfedea0SLionel Sambuc /* }}} */
84ebfedea0SLionel Sambuc
85ebfedea0SLionel Sambuc /* {{{ Comparison constants */
86ebfedea0SLionel Sambuc
87ebfedea0SLionel Sambuc #define MP_LT -1
88ebfedea0SLionel Sambuc #define MP_EQ 0
89ebfedea0SLionel Sambuc #define MP_GT 1
90ebfedea0SLionel Sambuc
91ebfedea0SLionel Sambuc /* }}} */
92ebfedea0SLionel Sambuc
93ebfedea0SLionel Sambuc /* {{{ Constant strings */
94ebfedea0SLionel Sambuc
95ebfedea0SLionel Sambuc /* Constant strings returned by mp_strerror() */
96ebfedea0SLionel Sambuc static const char *mp_err_string[] = {
97ebfedea0SLionel Sambuc "unknown result code", /* say what? */
98ebfedea0SLionel Sambuc "boolean true", /* MP_OKAY, MP_YES */
99ebfedea0SLionel Sambuc "boolean false", /* MP_NO */
100ebfedea0SLionel Sambuc "out of memory", /* MP_MEM */
101ebfedea0SLionel Sambuc "argument out of range", /* MP_RANGE */
102ebfedea0SLionel Sambuc "invalid input parameter", /* MP_BADARG */
103ebfedea0SLionel Sambuc "result is undefined" /* MP_UNDEF */
104ebfedea0SLionel Sambuc };
105ebfedea0SLionel Sambuc
106ebfedea0SLionel Sambuc /* Value to digit maps for radix conversion */
107ebfedea0SLionel Sambuc
108ebfedea0SLionel Sambuc /* s_dmap_1 - standard digits and letters */
109ebfedea0SLionel Sambuc static const char *s_dmap_1 =
110ebfedea0SLionel Sambuc "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz+/";
111ebfedea0SLionel Sambuc
112ebfedea0SLionel Sambuc #if 0
113ebfedea0SLionel Sambuc /* s_dmap_2 - base64 ordering for digits */
114ebfedea0SLionel Sambuc static const char *s_dmap_2 =
115ebfedea0SLionel Sambuc "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
116ebfedea0SLionel Sambuc #endif
117ebfedea0SLionel Sambuc
118ebfedea0SLionel Sambuc /* }}} */
119ebfedea0SLionel Sambuc
120ebfedea0SLionel Sambuc /* {{{ Static function declarations */
121ebfedea0SLionel Sambuc
122ebfedea0SLionel Sambuc /*
123ebfedea0SLionel Sambuc If MP_MACRO is false, these will be defined as actual functions;
124ebfedea0SLionel Sambuc otherwise, suitable macro definitions will be used. This works
125ebfedea0SLionel Sambuc around the fact that ANSI C89 doesn't support an 'inline' keyword
126ebfedea0SLionel Sambuc (although I hear C9x will ... about bloody time). At present, the
127ebfedea0SLionel Sambuc macro definitions are identical to the function bodies, but they'll
128ebfedea0SLionel Sambuc expand in place, instead of generating a function call.
129ebfedea0SLionel Sambuc
130ebfedea0SLionel Sambuc I chose these particular functions to be made into macros because
131ebfedea0SLionel Sambuc some profiling showed they are called a lot on a typical workload,
132ebfedea0SLionel Sambuc and yet they are primarily housekeeping.
133ebfedea0SLionel Sambuc */
134ebfedea0SLionel Sambuc #if MP_MACRO == 0
135ebfedea0SLionel Sambuc void s_mp_setz(mp_digit *dp, mp_size count); /* zero digits */
136ebfedea0SLionel Sambuc void s_mp_copy(mp_digit *sp, mp_digit *dp, mp_size count); /* copy */
137ebfedea0SLionel Sambuc void *s_mp_alloc(size_t nb, size_t ni); /* general allocator */
138ebfedea0SLionel Sambuc void s_mp_free(void *ptr); /* general free function */
139ebfedea0SLionel Sambuc #else
140ebfedea0SLionel Sambuc
141ebfedea0SLionel Sambuc /* Even if these are defined as macros, we need to respect the settings
142ebfedea0SLionel Sambuc of the MP_MEMSET and MP_MEMCPY configuration options...
143ebfedea0SLionel Sambuc */
144ebfedea0SLionel Sambuc #if MP_MEMSET == 0
145ebfedea0SLionel Sambuc #define s_mp_setz(dp, count) \
146ebfedea0SLionel Sambuc {int ix;for(ix=0;ix<(count);ix++)(dp)[ix]=0;}
147ebfedea0SLionel Sambuc #else
148ebfedea0SLionel Sambuc #define s_mp_setz(dp, count) memset(dp, 0, (count) * sizeof(mp_digit))
149ebfedea0SLionel Sambuc #endif /* MP_MEMSET */
150ebfedea0SLionel Sambuc
151ebfedea0SLionel Sambuc #if MP_MEMCPY == 0
152ebfedea0SLionel Sambuc #define s_mp_copy(sp, dp, count) \
153ebfedea0SLionel Sambuc {int ix;for(ix=0;ix<(count);ix++)(dp)[ix]=(sp)[ix];}
154ebfedea0SLionel Sambuc #else
155ebfedea0SLionel Sambuc #define s_mp_copy(sp, dp, count) memcpy(dp, sp, (count) * sizeof(mp_digit))
156ebfedea0SLionel Sambuc #endif /* MP_MEMCPY */
157ebfedea0SLionel Sambuc
158ebfedea0SLionel Sambuc #define s_mp_alloc(nb, ni) calloc(nb, ni)
159ebfedea0SLionel Sambuc #define s_mp_free(ptr) {if(ptr) free(ptr);}
160ebfedea0SLionel Sambuc #endif /* MP_MACRO */
161ebfedea0SLionel Sambuc
162ebfedea0SLionel Sambuc mp_err s_mp_grow(mp_int *mp, mp_size min); /* increase allocated size */
163ebfedea0SLionel Sambuc mp_err s_mp_pad(mp_int *mp, mp_size min); /* left pad with zeroes */
164ebfedea0SLionel Sambuc
165ebfedea0SLionel Sambuc void s_mp_clamp(mp_int *mp); /* clip leading zeroes */
166ebfedea0SLionel Sambuc
167ebfedea0SLionel Sambuc void s_mp_exch(mp_int *a, mp_int *b); /* swap a and b in place */
168ebfedea0SLionel Sambuc
169ebfedea0SLionel Sambuc mp_err s_mp_lshd(mp_int *mp, mp_size p); /* left-shift by p digits */
170ebfedea0SLionel Sambuc void s_mp_rshd(mp_int *mp, mp_size p); /* right-shift by p digits */
171ebfedea0SLionel Sambuc void s_mp_div_2d(mp_int *mp, mp_digit d); /* divide by 2^d in place */
172ebfedea0SLionel Sambuc void s_mp_mod_2d(mp_int *mp, mp_digit d); /* modulo 2^d in place */
173ebfedea0SLionel Sambuc mp_err s_mp_mul_2d(mp_int *mp, mp_digit d); /* multiply by 2^d in place*/
174ebfedea0SLionel Sambuc void s_mp_div_2(mp_int *mp); /* divide by 2 in place */
175ebfedea0SLionel Sambuc mp_err s_mp_mul_2(mp_int *mp); /* multiply by 2 in place */
176ebfedea0SLionel Sambuc mp_digit s_mp_norm(mp_int *a, mp_int *b); /* normalize for division */
177ebfedea0SLionel Sambuc mp_err s_mp_add_d(mp_int *mp, mp_digit d); /* unsigned digit addition */
178ebfedea0SLionel Sambuc mp_err s_mp_sub_d(mp_int *mp, mp_digit d); /* unsigned digit subtract */
179ebfedea0SLionel Sambuc mp_err s_mp_mul_d(mp_int *mp, mp_digit d); /* unsigned digit multiply */
180ebfedea0SLionel Sambuc mp_err s_mp_div_d(mp_int *mp, mp_digit d, mp_digit *r);
181ebfedea0SLionel Sambuc /* unsigned digit divide */
182ebfedea0SLionel Sambuc mp_err s_mp_reduce(mp_int *x, mp_int *m, mp_int *mu);
183ebfedea0SLionel Sambuc /* Barrett reduction */
184ebfedea0SLionel Sambuc mp_err s_mp_add(mp_int *a, mp_int *b); /* magnitude addition */
185ebfedea0SLionel Sambuc mp_err s_mp_sub(mp_int *a, mp_int *b); /* magnitude subtract */
186ebfedea0SLionel Sambuc mp_err s_mp_mul(mp_int *a, mp_int *b); /* magnitude multiply */
187ebfedea0SLionel Sambuc #if 0
188ebfedea0SLionel Sambuc void s_mp_kmul(mp_digit *a, mp_digit *b, mp_digit *out, mp_size len);
189ebfedea0SLionel Sambuc /* multiply buffers in place */
190ebfedea0SLionel Sambuc #endif
191ebfedea0SLionel Sambuc #if MP_SQUARE
192ebfedea0SLionel Sambuc mp_err s_mp_sqr(mp_int *a); /* magnitude square */
193ebfedea0SLionel Sambuc #else
194ebfedea0SLionel Sambuc #define s_mp_sqr(a) s_mp_mul(a, a)
195ebfedea0SLionel Sambuc #endif
196ebfedea0SLionel Sambuc mp_err s_mp_div(mp_int *a, mp_int *b); /* magnitude divide */
197ebfedea0SLionel Sambuc mp_err s_mp_2expt(mp_int *a, mp_digit k); /* a = 2^k */
198ebfedea0SLionel Sambuc int s_mp_cmp(mp_int *a, mp_int *b); /* magnitude comparison */
199ebfedea0SLionel Sambuc int s_mp_cmp_d(mp_int *a, mp_digit d); /* magnitude digit compare */
200ebfedea0SLionel Sambuc int s_mp_ispow2(mp_int *v); /* is v a power of 2? */
201ebfedea0SLionel Sambuc int s_mp_ispow2d(mp_digit d); /* is d a power of 2? */
202ebfedea0SLionel Sambuc
203ebfedea0SLionel Sambuc int s_mp_tovalue(char ch, int r); /* convert ch to value */
204ebfedea0SLionel Sambuc char s_mp_todigit(int val, int r, int low); /* convert val to digit */
205ebfedea0SLionel Sambuc int s_mp_outlen(int bits, int r); /* output length in bytes */
206ebfedea0SLionel Sambuc
207ebfedea0SLionel Sambuc /* }}} */
208ebfedea0SLionel Sambuc
209ebfedea0SLionel Sambuc /* {{{ Default precision manipulation */
210ebfedea0SLionel Sambuc
mp_get_prec(void)211ebfedea0SLionel Sambuc unsigned int mp_get_prec(void)
212ebfedea0SLionel Sambuc {
213ebfedea0SLionel Sambuc return s_mp_defprec;
214ebfedea0SLionel Sambuc
215ebfedea0SLionel Sambuc } /* end mp_get_prec() */
216ebfedea0SLionel Sambuc
mp_set_prec(unsigned int prec)217ebfedea0SLionel Sambuc void mp_set_prec(unsigned int prec)
218ebfedea0SLionel Sambuc {
219ebfedea0SLionel Sambuc if(prec == 0)
220ebfedea0SLionel Sambuc s_mp_defprec = MP_DEFPREC;
221ebfedea0SLionel Sambuc else
222ebfedea0SLionel Sambuc s_mp_defprec = prec;
223ebfedea0SLionel Sambuc
224ebfedea0SLionel Sambuc } /* end mp_set_prec() */
225ebfedea0SLionel Sambuc
226ebfedea0SLionel Sambuc /* }}} */
227ebfedea0SLionel Sambuc
228ebfedea0SLionel Sambuc /*------------------------------------------------------------------------*/
229ebfedea0SLionel Sambuc /* {{{ mp_init(mp) */
230ebfedea0SLionel Sambuc
231ebfedea0SLionel Sambuc /*
232ebfedea0SLionel Sambuc mp_init(mp)
233ebfedea0SLionel Sambuc
234ebfedea0SLionel Sambuc Initialize a new zero-valued mp_int. Returns MP_OKAY if successful,
235ebfedea0SLionel Sambuc MP_MEM if memory could not be allocated for the structure.
236ebfedea0SLionel Sambuc */
237ebfedea0SLionel Sambuc
mp_init(mp_int * mp)238ebfedea0SLionel Sambuc mp_err mp_init(mp_int *mp)
239ebfedea0SLionel Sambuc {
240ebfedea0SLionel Sambuc return mp_init_size(mp, s_mp_defprec);
241ebfedea0SLionel Sambuc
242ebfedea0SLionel Sambuc } /* end mp_init() */
243ebfedea0SLionel Sambuc
244ebfedea0SLionel Sambuc /* }}} */
245ebfedea0SLionel Sambuc
246ebfedea0SLionel Sambuc /* {{{ mp_init_array(mp[], count) */
247ebfedea0SLionel Sambuc
mp_init_array(mp_int mp[],int count)248ebfedea0SLionel Sambuc mp_err mp_init_array(mp_int mp[], int count)
249ebfedea0SLionel Sambuc {
250ebfedea0SLionel Sambuc mp_err res;
251ebfedea0SLionel Sambuc int pos;
252ebfedea0SLionel Sambuc
253ebfedea0SLionel Sambuc ARGCHK(mp !=NULL && count > 0, MP_BADARG);
254ebfedea0SLionel Sambuc
255ebfedea0SLionel Sambuc for(pos = 0; pos < count; ++pos) {
256ebfedea0SLionel Sambuc if((res = mp_init(&mp[pos])) != MP_OKAY)
257ebfedea0SLionel Sambuc goto CLEANUP;
258ebfedea0SLionel Sambuc }
259ebfedea0SLionel Sambuc
260ebfedea0SLionel Sambuc return MP_OKAY;
261ebfedea0SLionel Sambuc
262ebfedea0SLionel Sambuc CLEANUP:
263ebfedea0SLionel Sambuc while(--pos >= 0)
264ebfedea0SLionel Sambuc mp_clear(&mp[pos]);
265ebfedea0SLionel Sambuc
266ebfedea0SLionel Sambuc return res;
267ebfedea0SLionel Sambuc
268ebfedea0SLionel Sambuc } /* end mp_init_array() */
269ebfedea0SLionel Sambuc
270ebfedea0SLionel Sambuc /* }}} */
271ebfedea0SLionel Sambuc
272ebfedea0SLionel Sambuc /* {{{ mp_init_size(mp, prec) */
273ebfedea0SLionel Sambuc
274ebfedea0SLionel Sambuc /*
275ebfedea0SLionel Sambuc mp_init_size(mp, prec)
276ebfedea0SLionel Sambuc
277ebfedea0SLionel Sambuc Initialize a new zero-valued mp_int with at least the given
278ebfedea0SLionel Sambuc precision; returns MP_OKAY if successful, or MP_MEM if memory could
279ebfedea0SLionel Sambuc not be allocated for the structure.
280ebfedea0SLionel Sambuc */
281ebfedea0SLionel Sambuc
mp_init_size(mp_int * mp,mp_size prec)282ebfedea0SLionel Sambuc mp_err mp_init_size(mp_int *mp, mp_size prec)
283ebfedea0SLionel Sambuc {
284ebfedea0SLionel Sambuc ARGCHK(mp != NULL && prec > 0, MP_BADARG);
285ebfedea0SLionel Sambuc
286ebfedea0SLionel Sambuc if((DIGITS(mp) = s_mp_alloc(prec, sizeof(mp_digit))) == NULL)
287ebfedea0SLionel Sambuc return MP_MEM;
288ebfedea0SLionel Sambuc
289ebfedea0SLionel Sambuc SIGN(mp) = MP_ZPOS;
290ebfedea0SLionel Sambuc USED(mp) = 1;
291ebfedea0SLionel Sambuc ALLOC(mp) = prec;
292ebfedea0SLionel Sambuc
293ebfedea0SLionel Sambuc return MP_OKAY;
294ebfedea0SLionel Sambuc
295ebfedea0SLionel Sambuc } /* end mp_init_size() */
296ebfedea0SLionel Sambuc
297ebfedea0SLionel Sambuc /* }}} */
298ebfedea0SLionel Sambuc
299ebfedea0SLionel Sambuc /* {{{ mp_init_copy(mp, from) */
300ebfedea0SLionel Sambuc
301ebfedea0SLionel Sambuc /*
302ebfedea0SLionel Sambuc mp_init_copy(mp, from)
303ebfedea0SLionel Sambuc
304ebfedea0SLionel Sambuc Initialize mp as an exact copy of from. Returns MP_OKAY if
305ebfedea0SLionel Sambuc successful, MP_MEM if memory could not be allocated for the new
306ebfedea0SLionel Sambuc structure.
307ebfedea0SLionel Sambuc */
308ebfedea0SLionel Sambuc
mp_init_copy(mp_int * mp,mp_int * from)309ebfedea0SLionel Sambuc mp_err mp_init_copy(mp_int *mp, mp_int *from)
310ebfedea0SLionel Sambuc {
311ebfedea0SLionel Sambuc ARGCHK(mp != NULL && from != NULL, MP_BADARG);
312ebfedea0SLionel Sambuc
313ebfedea0SLionel Sambuc if(mp == from)
314ebfedea0SLionel Sambuc return MP_OKAY;
315ebfedea0SLionel Sambuc
316ebfedea0SLionel Sambuc if((DIGITS(mp) = s_mp_alloc(USED(from), sizeof(mp_digit))) == NULL)
317ebfedea0SLionel Sambuc return MP_MEM;
318ebfedea0SLionel Sambuc
319ebfedea0SLionel Sambuc s_mp_copy(DIGITS(from), DIGITS(mp), USED(from));
320ebfedea0SLionel Sambuc USED(mp) = USED(from);
321ebfedea0SLionel Sambuc ALLOC(mp) = USED(from);
322ebfedea0SLionel Sambuc SIGN(mp) = SIGN(from);
323ebfedea0SLionel Sambuc
324ebfedea0SLionel Sambuc return MP_OKAY;
325ebfedea0SLionel Sambuc
326ebfedea0SLionel Sambuc } /* end mp_init_copy() */
327ebfedea0SLionel Sambuc
328ebfedea0SLionel Sambuc /* }}} */
329ebfedea0SLionel Sambuc
330ebfedea0SLionel Sambuc /* {{{ mp_copy(from, to) */
331ebfedea0SLionel Sambuc
332ebfedea0SLionel Sambuc /*
333ebfedea0SLionel Sambuc mp_copy(from, to)
334ebfedea0SLionel Sambuc
335ebfedea0SLionel Sambuc Copies the mp_int 'from' to the mp_int 'to'. It is presumed that
336ebfedea0SLionel Sambuc 'to' has already been initialized (if not, use mp_init_copy()
337ebfedea0SLionel Sambuc instead). If 'from' and 'to' are identical, nothing happens.
338ebfedea0SLionel Sambuc */
339ebfedea0SLionel Sambuc
mp_copy(mp_int * from,mp_int * to)340ebfedea0SLionel Sambuc mp_err mp_copy(mp_int *from, mp_int *to)
341ebfedea0SLionel Sambuc {
342ebfedea0SLionel Sambuc ARGCHK(from != NULL && to != NULL, MP_BADARG);
343ebfedea0SLionel Sambuc
344ebfedea0SLionel Sambuc if(from == to)
345ebfedea0SLionel Sambuc return MP_OKAY;
346ebfedea0SLionel Sambuc
347ebfedea0SLionel Sambuc { /* copy */
348ebfedea0SLionel Sambuc mp_digit *tmp;
349ebfedea0SLionel Sambuc
350ebfedea0SLionel Sambuc /*
351ebfedea0SLionel Sambuc If the allocated buffer in 'to' already has enough space to hold
352ebfedea0SLionel Sambuc all the used digits of 'from', we'll re-use it to avoid hitting
353ebfedea0SLionel Sambuc the memory allocater more than necessary; otherwise, we'd have
354ebfedea0SLionel Sambuc to grow anyway, so we just allocate a hunk and make the copy as
355ebfedea0SLionel Sambuc usual
356ebfedea0SLionel Sambuc */
357ebfedea0SLionel Sambuc if(ALLOC(to) >= USED(from)) {
358ebfedea0SLionel Sambuc s_mp_setz(DIGITS(to) + USED(from), ALLOC(to) - USED(from));
359ebfedea0SLionel Sambuc s_mp_copy(DIGITS(from), DIGITS(to), USED(from));
360ebfedea0SLionel Sambuc
361ebfedea0SLionel Sambuc } else {
362ebfedea0SLionel Sambuc if((tmp = s_mp_alloc(USED(from), sizeof(mp_digit))) == NULL)
363ebfedea0SLionel Sambuc return MP_MEM;
364ebfedea0SLionel Sambuc
365ebfedea0SLionel Sambuc s_mp_copy(DIGITS(from), tmp, USED(from));
366ebfedea0SLionel Sambuc
367ebfedea0SLionel Sambuc if(DIGITS(to) != NULL) {
368ebfedea0SLionel Sambuc #if MP_CRYPTO
369ebfedea0SLionel Sambuc s_mp_setz(DIGITS(to), ALLOC(to));
370ebfedea0SLionel Sambuc #endif
371ebfedea0SLionel Sambuc s_mp_free(DIGITS(to));
372ebfedea0SLionel Sambuc }
373ebfedea0SLionel Sambuc
374ebfedea0SLionel Sambuc DIGITS(to) = tmp;
375ebfedea0SLionel Sambuc ALLOC(to) = USED(from);
376ebfedea0SLionel Sambuc }
377ebfedea0SLionel Sambuc
378ebfedea0SLionel Sambuc /* Copy the precision and sign from the original */
379ebfedea0SLionel Sambuc USED(to) = USED(from);
380ebfedea0SLionel Sambuc SIGN(to) = SIGN(from);
381ebfedea0SLionel Sambuc } /* end copy */
382ebfedea0SLionel Sambuc
383ebfedea0SLionel Sambuc return MP_OKAY;
384ebfedea0SLionel Sambuc
385ebfedea0SLionel Sambuc } /* end mp_copy() */
386ebfedea0SLionel Sambuc
387ebfedea0SLionel Sambuc /* }}} */
388ebfedea0SLionel Sambuc
389ebfedea0SLionel Sambuc /* {{{ mp_exch(mp1, mp2) */
390ebfedea0SLionel Sambuc
391ebfedea0SLionel Sambuc /*
392ebfedea0SLionel Sambuc mp_exch(mp1, mp2)
393ebfedea0SLionel Sambuc
394ebfedea0SLionel Sambuc Exchange mp1 and mp2 without allocating any intermediate memory
395ebfedea0SLionel Sambuc (well, unless you count the stack space needed for this call and the
396ebfedea0SLionel Sambuc locals it creates...). This cannot fail.
397ebfedea0SLionel Sambuc */
398ebfedea0SLionel Sambuc
mp_exch(mp_int * mp1,mp_int * mp2)399ebfedea0SLionel Sambuc void mp_exch(mp_int *mp1, mp_int *mp2)
400ebfedea0SLionel Sambuc {
401ebfedea0SLionel Sambuc #if MP_ARGCHK == 2
402ebfedea0SLionel Sambuc assert(mp1 != NULL && mp2 != NULL);
403ebfedea0SLionel Sambuc #else
404ebfedea0SLionel Sambuc if(mp1 == NULL || mp2 == NULL)
405ebfedea0SLionel Sambuc return;
406ebfedea0SLionel Sambuc #endif
407ebfedea0SLionel Sambuc
408ebfedea0SLionel Sambuc s_mp_exch(mp1, mp2);
409ebfedea0SLionel Sambuc
410ebfedea0SLionel Sambuc } /* end mp_exch() */
411ebfedea0SLionel Sambuc
412ebfedea0SLionel Sambuc /* }}} */
413ebfedea0SLionel Sambuc
414ebfedea0SLionel Sambuc /* {{{ mp_clear(mp) */
415ebfedea0SLionel Sambuc
416ebfedea0SLionel Sambuc /*
417ebfedea0SLionel Sambuc mp_clear(mp)
418ebfedea0SLionel Sambuc
419ebfedea0SLionel Sambuc Release the storage used by an mp_int, and void its fields so that
420ebfedea0SLionel Sambuc if someone calls mp_clear() again for the same int later, we won't
421ebfedea0SLionel Sambuc get tollchocked.
422ebfedea0SLionel Sambuc */
423ebfedea0SLionel Sambuc
mp_clear(mp_int * mp)424ebfedea0SLionel Sambuc void mp_clear(mp_int *mp)
425ebfedea0SLionel Sambuc {
426ebfedea0SLionel Sambuc if(mp == NULL)
427ebfedea0SLionel Sambuc return;
428ebfedea0SLionel Sambuc
429ebfedea0SLionel Sambuc if(DIGITS(mp) != NULL) {
430ebfedea0SLionel Sambuc #if MP_CRYPTO
431ebfedea0SLionel Sambuc s_mp_setz(DIGITS(mp), ALLOC(mp));
432ebfedea0SLionel Sambuc #endif
433ebfedea0SLionel Sambuc s_mp_free(DIGITS(mp));
434ebfedea0SLionel Sambuc DIGITS(mp) = NULL;
435ebfedea0SLionel Sambuc }
436ebfedea0SLionel Sambuc
437ebfedea0SLionel Sambuc USED(mp) = 0;
438ebfedea0SLionel Sambuc ALLOC(mp) = 0;
439ebfedea0SLionel Sambuc
440ebfedea0SLionel Sambuc } /* end mp_clear() */
441ebfedea0SLionel Sambuc
442ebfedea0SLionel Sambuc /* }}} */
443ebfedea0SLionel Sambuc
444ebfedea0SLionel Sambuc /* {{{ mp_clear_array(mp[], count) */
445ebfedea0SLionel Sambuc
mp_clear_array(mp_int mp[],int count)446ebfedea0SLionel Sambuc void mp_clear_array(mp_int mp[], int count)
447ebfedea0SLionel Sambuc {
448ebfedea0SLionel Sambuc ARGCHK(mp != NULL && count > 0, MP_BADARG);
449ebfedea0SLionel Sambuc
450ebfedea0SLionel Sambuc while(--count >= 0)
451ebfedea0SLionel Sambuc mp_clear(&mp[count]);
452ebfedea0SLionel Sambuc
453ebfedea0SLionel Sambuc } /* end mp_clear_array() */
454ebfedea0SLionel Sambuc
455ebfedea0SLionel Sambuc /* }}} */
456ebfedea0SLionel Sambuc
457ebfedea0SLionel Sambuc /* {{{ mp_zero(mp) */
458ebfedea0SLionel Sambuc
459ebfedea0SLionel Sambuc /*
460ebfedea0SLionel Sambuc mp_zero(mp)
461ebfedea0SLionel Sambuc
462ebfedea0SLionel Sambuc Set mp to zero. Does not change the allocated size of the structure,
463ebfedea0SLionel Sambuc and therefore cannot fail (except on a bad argument, which we ignore)
464ebfedea0SLionel Sambuc */
mp_zero(mp_int * mp)465ebfedea0SLionel Sambuc void mp_zero(mp_int *mp)
466ebfedea0SLionel Sambuc {
467ebfedea0SLionel Sambuc if(mp == NULL)
468ebfedea0SLionel Sambuc return;
469ebfedea0SLionel Sambuc
470ebfedea0SLionel Sambuc s_mp_setz(DIGITS(mp), ALLOC(mp));
471ebfedea0SLionel Sambuc USED(mp) = 1;
472ebfedea0SLionel Sambuc SIGN(mp) = MP_ZPOS;
473ebfedea0SLionel Sambuc
474ebfedea0SLionel Sambuc } /* end mp_zero() */
475ebfedea0SLionel Sambuc
476ebfedea0SLionel Sambuc /* }}} */
477ebfedea0SLionel Sambuc
478ebfedea0SLionel Sambuc /* {{{ mp_set(mp, d) */
479ebfedea0SLionel Sambuc
mp_set(mp_int * mp,mp_digit d)480ebfedea0SLionel Sambuc void mp_set(mp_int *mp, mp_digit d)
481ebfedea0SLionel Sambuc {
482ebfedea0SLionel Sambuc if(mp == NULL)
483ebfedea0SLionel Sambuc return;
484ebfedea0SLionel Sambuc
485ebfedea0SLionel Sambuc mp_zero(mp);
486ebfedea0SLionel Sambuc DIGIT(mp, 0) = d;
487ebfedea0SLionel Sambuc
488ebfedea0SLionel Sambuc } /* end mp_set() */
489ebfedea0SLionel Sambuc
490ebfedea0SLionel Sambuc /* }}} */
491ebfedea0SLionel Sambuc
492ebfedea0SLionel Sambuc /* {{{ mp_set_int(mp, z) */
493ebfedea0SLionel Sambuc
mp_set_int(mp_int * mp,long z)494ebfedea0SLionel Sambuc mp_err mp_set_int(mp_int *mp, long z)
495ebfedea0SLionel Sambuc {
496ebfedea0SLionel Sambuc int ix;
497ebfedea0SLionel Sambuc unsigned long v = abs(z);
498ebfedea0SLionel Sambuc mp_err res;
499ebfedea0SLionel Sambuc
500ebfedea0SLionel Sambuc ARGCHK(mp != NULL, MP_BADARG);
501ebfedea0SLionel Sambuc
502ebfedea0SLionel Sambuc mp_zero(mp);
503ebfedea0SLionel Sambuc if(z == 0)
504ebfedea0SLionel Sambuc return MP_OKAY; /* shortcut for zero */
505ebfedea0SLionel Sambuc
506ebfedea0SLionel Sambuc for(ix = sizeof(long) - 1; ix >= 0; ix--) {
507ebfedea0SLionel Sambuc
508ebfedea0SLionel Sambuc if((res = s_mp_mul_2d(mp, CHAR_BIT)) != MP_OKAY)
509ebfedea0SLionel Sambuc return res;
510ebfedea0SLionel Sambuc
511ebfedea0SLionel Sambuc res = s_mp_add_d(mp,
512ebfedea0SLionel Sambuc (mp_digit)((v >> (ix * CHAR_BIT)) & UCHAR_MAX));
513ebfedea0SLionel Sambuc if(res != MP_OKAY)
514ebfedea0SLionel Sambuc return res;
515ebfedea0SLionel Sambuc
516ebfedea0SLionel Sambuc }
517ebfedea0SLionel Sambuc
518ebfedea0SLionel Sambuc if(z < 0)
519ebfedea0SLionel Sambuc SIGN(mp) = MP_NEG;
520ebfedea0SLionel Sambuc
521ebfedea0SLionel Sambuc return MP_OKAY;
522ebfedea0SLionel Sambuc
523ebfedea0SLionel Sambuc } /* end mp_set_int() */
524ebfedea0SLionel Sambuc
525ebfedea0SLionel Sambuc /* }}} */
526ebfedea0SLionel Sambuc
527ebfedea0SLionel Sambuc /*------------------------------------------------------------------------*/
528ebfedea0SLionel Sambuc /* {{{ Digit arithmetic */
529ebfedea0SLionel Sambuc
530ebfedea0SLionel Sambuc /* {{{ mp_add_d(a, d, b) */
531ebfedea0SLionel Sambuc
532ebfedea0SLionel Sambuc /*
533ebfedea0SLionel Sambuc mp_add_d(a, d, b)
534ebfedea0SLionel Sambuc
535ebfedea0SLionel Sambuc Compute the sum b = a + d, for a single digit d. Respects the sign of
536ebfedea0SLionel Sambuc its primary addend (single digits are unsigned anyway).
537ebfedea0SLionel Sambuc */
538ebfedea0SLionel Sambuc
mp_add_d(mp_int * a,mp_digit d,mp_int * b)539ebfedea0SLionel Sambuc mp_err mp_add_d(mp_int *a, mp_digit d, mp_int *b)
540ebfedea0SLionel Sambuc {
541ebfedea0SLionel Sambuc mp_err res = MP_OKAY;
542ebfedea0SLionel Sambuc
543ebfedea0SLionel Sambuc ARGCHK(a != NULL && b != NULL, MP_BADARG);
544ebfedea0SLionel Sambuc
545ebfedea0SLionel Sambuc if((res = mp_copy(a, b)) != MP_OKAY)
546ebfedea0SLionel Sambuc return res;
547ebfedea0SLionel Sambuc
548ebfedea0SLionel Sambuc if(SIGN(b) == MP_ZPOS) {
549ebfedea0SLionel Sambuc res = s_mp_add_d(b, d);
550ebfedea0SLionel Sambuc } else if(s_mp_cmp_d(b, d) >= 0) {
551ebfedea0SLionel Sambuc res = s_mp_sub_d(b, d);
552ebfedea0SLionel Sambuc } else {
553ebfedea0SLionel Sambuc SIGN(b) = MP_ZPOS;
554ebfedea0SLionel Sambuc
555ebfedea0SLionel Sambuc DIGIT(b, 0) = d - DIGIT(b, 0);
556ebfedea0SLionel Sambuc }
557ebfedea0SLionel Sambuc
558ebfedea0SLionel Sambuc return res;
559ebfedea0SLionel Sambuc
560ebfedea0SLionel Sambuc } /* end mp_add_d() */
561ebfedea0SLionel Sambuc
562ebfedea0SLionel Sambuc /* }}} */
563ebfedea0SLionel Sambuc
564ebfedea0SLionel Sambuc /* {{{ mp_sub_d(a, d, b) */
565ebfedea0SLionel Sambuc
566ebfedea0SLionel Sambuc /*
567ebfedea0SLionel Sambuc mp_sub_d(a, d, b)
568ebfedea0SLionel Sambuc
569ebfedea0SLionel Sambuc Compute the difference b = a - d, for a single digit d. Respects the
570ebfedea0SLionel Sambuc sign of its subtrahend (single digits are unsigned anyway).
571ebfedea0SLionel Sambuc */
572ebfedea0SLionel Sambuc
mp_sub_d(mp_int * a,mp_digit d,mp_int * b)573ebfedea0SLionel Sambuc mp_err mp_sub_d(mp_int *a, mp_digit d, mp_int *b)
574ebfedea0SLionel Sambuc {
575ebfedea0SLionel Sambuc mp_err res;
576ebfedea0SLionel Sambuc
577ebfedea0SLionel Sambuc ARGCHK(a != NULL && b != NULL, MP_BADARG);
578ebfedea0SLionel Sambuc
579ebfedea0SLionel Sambuc if((res = mp_copy(a, b)) != MP_OKAY)
580ebfedea0SLionel Sambuc return res;
581ebfedea0SLionel Sambuc
582ebfedea0SLionel Sambuc if(SIGN(b) == MP_NEG) {
583ebfedea0SLionel Sambuc if((res = s_mp_add_d(b, d)) != MP_OKAY)
584ebfedea0SLionel Sambuc return res;
585ebfedea0SLionel Sambuc
586ebfedea0SLionel Sambuc } else if(s_mp_cmp_d(b, d) >= 0) {
587ebfedea0SLionel Sambuc if((res = s_mp_sub_d(b, d)) != MP_OKAY)
588ebfedea0SLionel Sambuc return res;
589ebfedea0SLionel Sambuc
590ebfedea0SLionel Sambuc } else {
591ebfedea0SLionel Sambuc mp_neg(b, b);
592ebfedea0SLionel Sambuc
593ebfedea0SLionel Sambuc DIGIT(b, 0) = d - DIGIT(b, 0);
594ebfedea0SLionel Sambuc SIGN(b) = MP_NEG;
595ebfedea0SLionel Sambuc }
596ebfedea0SLionel Sambuc
597ebfedea0SLionel Sambuc if(s_mp_cmp_d(b, 0) == 0)
598ebfedea0SLionel Sambuc SIGN(b) = MP_ZPOS;
599ebfedea0SLionel Sambuc
600ebfedea0SLionel Sambuc return MP_OKAY;
601ebfedea0SLionel Sambuc
602ebfedea0SLionel Sambuc } /* end mp_sub_d() */
603ebfedea0SLionel Sambuc
604ebfedea0SLionel Sambuc /* }}} */
605ebfedea0SLionel Sambuc
606ebfedea0SLionel Sambuc /* {{{ mp_mul_d(a, d, b) */
607ebfedea0SLionel Sambuc
608ebfedea0SLionel Sambuc /*
609ebfedea0SLionel Sambuc mp_mul_d(a, d, b)
610ebfedea0SLionel Sambuc
611ebfedea0SLionel Sambuc Compute the product b = a * d, for a single digit d. Respects the sign
612ebfedea0SLionel Sambuc of its multiplicand (single digits are unsigned anyway)
613ebfedea0SLionel Sambuc */
614ebfedea0SLionel Sambuc
mp_mul_d(mp_int * a,mp_digit d,mp_int * b)615ebfedea0SLionel Sambuc mp_err mp_mul_d(mp_int *a, mp_digit d, mp_int *b)
616ebfedea0SLionel Sambuc {
617ebfedea0SLionel Sambuc mp_err res;
618ebfedea0SLionel Sambuc
619ebfedea0SLionel Sambuc ARGCHK(a != NULL && b != NULL, MP_BADARG);
620ebfedea0SLionel Sambuc
621ebfedea0SLionel Sambuc if(d == 0) {
622ebfedea0SLionel Sambuc mp_zero(b);
623ebfedea0SLionel Sambuc return MP_OKAY;
624ebfedea0SLionel Sambuc }
625ebfedea0SLionel Sambuc
626ebfedea0SLionel Sambuc if((res = mp_copy(a, b)) != MP_OKAY)
627ebfedea0SLionel Sambuc return res;
628ebfedea0SLionel Sambuc
629ebfedea0SLionel Sambuc res = s_mp_mul_d(b, d);
630ebfedea0SLionel Sambuc
631ebfedea0SLionel Sambuc return res;
632ebfedea0SLionel Sambuc
633ebfedea0SLionel Sambuc } /* end mp_mul_d() */
634ebfedea0SLionel Sambuc
635ebfedea0SLionel Sambuc /* }}} */
636ebfedea0SLionel Sambuc
637ebfedea0SLionel Sambuc /* {{{ mp_mul_2(a, c) */
638ebfedea0SLionel Sambuc
mp_mul_2(mp_int * a,mp_int * c)639ebfedea0SLionel Sambuc mp_err mp_mul_2(mp_int *a, mp_int *c)
640ebfedea0SLionel Sambuc {
641ebfedea0SLionel Sambuc mp_err res;
642ebfedea0SLionel Sambuc
643ebfedea0SLionel Sambuc ARGCHK(a != NULL && c != NULL, MP_BADARG);
644ebfedea0SLionel Sambuc
645ebfedea0SLionel Sambuc if((res = mp_copy(a, c)) != MP_OKAY)
646ebfedea0SLionel Sambuc return res;
647ebfedea0SLionel Sambuc
648ebfedea0SLionel Sambuc return s_mp_mul_2(c);
649ebfedea0SLionel Sambuc
650ebfedea0SLionel Sambuc } /* end mp_mul_2() */
651ebfedea0SLionel Sambuc
652ebfedea0SLionel Sambuc /* }}} */
653ebfedea0SLionel Sambuc
654ebfedea0SLionel Sambuc /* {{{ mp_div_d(a, d, q, r) */
655ebfedea0SLionel Sambuc
656ebfedea0SLionel Sambuc /*
657ebfedea0SLionel Sambuc mp_div_d(a, d, q, r)
658ebfedea0SLionel Sambuc
659ebfedea0SLionel Sambuc Compute the quotient q = a / d and remainder r = a mod d, for a
660ebfedea0SLionel Sambuc single digit d. Respects the sign of its divisor (single digits are
661ebfedea0SLionel Sambuc unsigned anyway).
662ebfedea0SLionel Sambuc */
663ebfedea0SLionel Sambuc
mp_div_d(mp_int * a,mp_digit d,mp_int * q,mp_digit * r)664ebfedea0SLionel Sambuc mp_err mp_div_d(mp_int *a, mp_digit d, mp_int *q, mp_digit *r)
665ebfedea0SLionel Sambuc {
666ebfedea0SLionel Sambuc mp_err res;
667ebfedea0SLionel Sambuc mp_digit rem;
668ebfedea0SLionel Sambuc int pow;
669ebfedea0SLionel Sambuc
670ebfedea0SLionel Sambuc ARGCHK(a != NULL, MP_BADARG);
671ebfedea0SLionel Sambuc
672ebfedea0SLionel Sambuc if(d == 0)
673ebfedea0SLionel Sambuc return MP_RANGE;
674ebfedea0SLionel Sambuc
675ebfedea0SLionel Sambuc /* Shortcut for powers of two ... */
676ebfedea0SLionel Sambuc if((pow = s_mp_ispow2d(d)) >= 0) {
677ebfedea0SLionel Sambuc mp_digit mask;
678ebfedea0SLionel Sambuc
679ebfedea0SLionel Sambuc mask = (1 << pow) - 1;
680ebfedea0SLionel Sambuc rem = DIGIT(a, 0) & mask;
681ebfedea0SLionel Sambuc
682ebfedea0SLionel Sambuc if(q) {
683ebfedea0SLionel Sambuc mp_copy(a, q);
684ebfedea0SLionel Sambuc s_mp_div_2d(q, pow);
685ebfedea0SLionel Sambuc }
686ebfedea0SLionel Sambuc
687ebfedea0SLionel Sambuc if(r)
688ebfedea0SLionel Sambuc *r = rem;
689ebfedea0SLionel Sambuc
690ebfedea0SLionel Sambuc return MP_OKAY;
691ebfedea0SLionel Sambuc }
692ebfedea0SLionel Sambuc
693ebfedea0SLionel Sambuc /*
694ebfedea0SLionel Sambuc If the quotient is actually going to be returned, we'll try to
695ebfedea0SLionel Sambuc avoid hitting the memory allocator by copying the dividend into it
696ebfedea0SLionel Sambuc and doing the division there. This can't be any _worse_ than
697ebfedea0SLionel Sambuc always copying, and will sometimes be better (since it won't make
698ebfedea0SLionel Sambuc another copy)
699ebfedea0SLionel Sambuc
700ebfedea0SLionel Sambuc If it's not going to be returned, we need to allocate a temporary
701ebfedea0SLionel Sambuc to hold the quotient, which will just be discarded.
702ebfedea0SLionel Sambuc */
703ebfedea0SLionel Sambuc if(q) {
704ebfedea0SLionel Sambuc if((res = mp_copy(a, q)) != MP_OKAY)
705ebfedea0SLionel Sambuc return res;
706ebfedea0SLionel Sambuc
707ebfedea0SLionel Sambuc res = s_mp_div_d(q, d, &rem);
708ebfedea0SLionel Sambuc if(s_mp_cmp_d(q, 0) == MP_EQ)
709ebfedea0SLionel Sambuc SIGN(q) = MP_ZPOS;
710ebfedea0SLionel Sambuc
711ebfedea0SLionel Sambuc } else {
712ebfedea0SLionel Sambuc mp_int qp;
713ebfedea0SLionel Sambuc
714ebfedea0SLionel Sambuc if((res = mp_init_copy(&qp, a)) != MP_OKAY)
715ebfedea0SLionel Sambuc return res;
716ebfedea0SLionel Sambuc
717ebfedea0SLionel Sambuc res = s_mp_div_d(&qp, d, &rem);
718ebfedea0SLionel Sambuc if(s_mp_cmp_d(&qp, 0) == 0)
719ebfedea0SLionel Sambuc SIGN(&qp) = MP_ZPOS;
720ebfedea0SLionel Sambuc
721ebfedea0SLionel Sambuc mp_clear(&qp);
722ebfedea0SLionel Sambuc }
723ebfedea0SLionel Sambuc
724ebfedea0SLionel Sambuc if(r)
725ebfedea0SLionel Sambuc *r = rem;
726ebfedea0SLionel Sambuc
727ebfedea0SLionel Sambuc return res;
728ebfedea0SLionel Sambuc
729ebfedea0SLionel Sambuc } /* end mp_div_d() */
730ebfedea0SLionel Sambuc
731ebfedea0SLionel Sambuc /* }}} */
732ebfedea0SLionel Sambuc
733ebfedea0SLionel Sambuc /* {{{ mp_div_2(a, c) */
734ebfedea0SLionel Sambuc
735ebfedea0SLionel Sambuc /*
736ebfedea0SLionel Sambuc mp_div_2(a, c)
737ebfedea0SLionel Sambuc
738ebfedea0SLionel Sambuc Compute c = a / 2, disregarding the remainder.
739ebfedea0SLionel Sambuc */
740ebfedea0SLionel Sambuc
mp_div_2(mp_int * a,mp_int * c)741ebfedea0SLionel Sambuc mp_err mp_div_2(mp_int *a, mp_int *c)
742ebfedea0SLionel Sambuc {
743ebfedea0SLionel Sambuc mp_err res;
744ebfedea0SLionel Sambuc
745ebfedea0SLionel Sambuc ARGCHK(a != NULL && c != NULL, MP_BADARG);
746ebfedea0SLionel Sambuc
747ebfedea0SLionel Sambuc if((res = mp_copy(a, c)) != MP_OKAY)
748ebfedea0SLionel Sambuc return res;
749ebfedea0SLionel Sambuc
750ebfedea0SLionel Sambuc s_mp_div_2(c);
751ebfedea0SLionel Sambuc
752ebfedea0SLionel Sambuc return MP_OKAY;
753ebfedea0SLionel Sambuc
754ebfedea0SLionel Sambuc } /* end mp_div_2() */
755ebfedea0SLionel Sambuc
756ebfedea0SLionel Sambuc /* }}} */
757ebfedea0SLionel Sambuc
758ebfedea0SLionel Sambuc /* {{{ mp_expt_d(a, d, b) */
759ebfedea0SLionel Sambuc
mp_expt_d(mp_int * a,mp_digit d,mp_int * c)760ebfedea0SLionel Sambuc mp_err mp_expt_d(mp_int *a, mp_digit d, mp_int *c)
761ebfedea0SLionel Sambuc {
762ebfedea0SLionel Sambuc mp_int s, x;
763ebfedea0SLionel Sambuc mp_err res;
764ebfedea0SLionel Sambuc
765ebfedea0SLionel Sambuc ARGCHK(a != NULL && c != NULL, MP_BADARG);
766ebfedea0SLionel Sambuc
767ebfedea0SLionel Sambuc if((res = mp_init(&s)) != MP_OKAY)
768ebfedea0SLionel Sambuc return res;
769ebfedea0SLionel Sambuc if((res = mp_init_copy(&x, a)) != MP_OKAY)
770ebfedea0SLionel Sambuc goto X;
771ebfedea0SLionel Sambuc
772ebfedea0SLionel Sambuc DIGIT(&s, 0) = 1;
773ebfedea0SLionel Sambuc
774ebfedea0SLionel Sambuc while(d != 0) {
775ebfedea0SLionel Sambuc if(d & 1) {
776ebfedea0SLionel Sambuc if((res = s_mp_mul(&s, &x)) != MP_OKAY)
777ebfedea0SLionel Sambuc goto CLEANUP;
778ebfedea0SLionel Sambuc }
779ebfedea0SLionel Sambuc
780ebfedea0SLionel Sambuc d >>= 1;
781ebfedea0SLionel Sambuc
782ebfedea0SLionel Sambuc if((res = s_mp_sqr(&x)) != MP_OKAY)
783ebfedea0SLionel Sambuc goto CLEANUP;
784ebfedea0SLionel Sambuc }
785ebfedea0SLionel Sambuc
786ebfedea0SLionel Sambuc s_mp_exch(&s, c);
787ebfedea0SLionel Sambuc
788ebfedea0SLionel Sambuc CLEANUP:
789ebfedea0SLionel Sambuc mp_clear(&x);
790ebfedea0SLionel Sambuc X:
791ebfedea0SLionel Sambuc mp_clear(&s);
792ebfedea0SLionel Sambuc
793ebfedea0SLionel Sambuc return res;
794ebfedea0SLionel Sambuc
795ebfedea0SLionel Sambuc } /* end mp_expt_d() */
796ebfedea0SLionel Sambuc
797ebfedea0SLionel Sambuc /* }}} */
798ebfedea0SLionel Sambuc
799ebfedea0SLionel Sambuc /* }}} */
800ebfedea0SLionel Sambuc
801ebfedea0SLionel Sambuc /*------------------------------------------------------------------------*/
802ebfedea0SLionel Sambuc /* {{{ Full arithmetic */
803ebfedea0SLionel Sambuc
804ebfedea0SLionel Sambuc /* {{{ mp_abs(a, b) */
805ebfedea0SLionel Sambuc
806ebfedea0SLionel Sambuc /*
807ebfedea0SLionel Sambuc mp_abs(a, b)
808ebfedea0SLionel Sambuc
809ebfedea0SLionel Sambuc Compute b = |a|. 'a' and 'b' may be identical.
810ebfedea0SLionel Sambuc */
811ebfedea0SLionel Sambuc
mp_abs(mp_int * a,mp_int * b)812ebfedea0SLionel Sambuc mp_err mp_abs(mp_int *a, mp_int *b)
813ebfedea0SLionel Sambuc {
814ebfedea0SLionel Sambuc mp_err res;
815ebfedea0SLionel Sambuc
816ebfedea0SLionel Sambuc ARGCHK(a != NULL && b != NULL, MP_BADARG);
817ebfedea0SLionel Sambuc
818ebfedea0SLionel Sambuc if((res = mp_copy(a, b)) != MP_OKAY)
819ebfedea0SLionel Sambuc return res;
820ebfedea0SLionel Sambuc
821ebfedea0SLionel Sambuc SIGN(b) = MP_ZPOS;
822ebfedea0SLionel Sambuc
823ebfedea0SLionel Sambuc return MP_OKAY;
824ebfedea0SLionel Sambuc
825ebfedea0SLionel Sambuc } /* end mp_abs() */
826ebfedea0SLionel Sambuc
827ebfedea0SLionel Sambuc /* }}} */
828ebfedea0SLionel Sambuc
829ebfedea0SLionel Sambuc /* {{{ mp_neg(a, b) */
830ebfedea0SLionel Sambuc
831ebfedea0SLionel Sambuc /*
832ebfedea0SLionel Sambuc mp_neg(a, b)
833ebfedea0SLionel Sambuc
834ebfedea0SLionel Sambuc Compute b = -a. 'a' and 'b' may be identical.
835ebfedea0SLionel Sambuc */
836ebfedea0SLionel Sambuc
mp_neg(mp_int * a,mp_int * b)837ebfedea0SLionel Sambuc mp_err mp_neg(mp_int *a, mp_int *b)
838ebfedea0SLionel Sambuc {
839ebfedea0SLionel Sambuc mp_err res;
840ebfedea0SLionel Sambuc
841ebfedea0SLionel Sambuc ARGCHK(a != NULL && b != NULL, MP_BADARG);
842ebfedea0SLionel Sambuc
843ebfedea0SLionel Sambuc if((res = mp_copy(a, b)) != MP_OKAY)
844ebfedea0SLionel Sambuc return res;
845ebfedea0SLionel Sambuc
846ebfedea0SLionel Sambuc if(s_mp_cmp_d(b, 0) == MP_EQ)
847ebfedea0SLionel Sambuc SIGN(b) = MP_ZPOS;
848ebfedea0SLionel Sambuc else
849ebfedea0SLionel Sambuc SIGN(b) = (SIGN(b) == MP_NEG) ? MP_ZPOS : MP_NEG;
850ebfedea0SLionel Sambuc
851ebfedea0SLionel Sambuc return MP_OKAY;
852ebfedea0SLionel Sambuc
853ebfedea0SLionel Sambuc } /* end mp_neg() */
854ebfedea0SLionel Sambuc
855ebfedea0SLionel Sambuc /* }}} */
856ebfedea0SLionel Sambuc
857ebfedea0SLionel Sambuc /* {{{ mp_add(a, b, c) */
858ebfedea0SLionel Sambuc
859ebfedea0SLionel Sambuc /*
860ebfedea0SLionel Sambuc mp_add(a, b, c)
861ebfedea0SLionel Sambuc
862ebfedea0SLionel Sambuc Compute c = a + b. All parameters may be identical.
863ebfedea0SLionel Sambuc */
864ebfedea0SLionel Sambuc
mp_add(mp_int * a,mp_int * b,mp_int * c)865ebfedea0SLionel Sambuc mp_err mp_add(mp_int *a, mp_int *b, mp_int *c)
866ebfedea0SLionel Sambuc {
867ebfedea0SLionel Sambuc mp_err res;
868ebfedea0SLionel Sambuc int cmp;
869ebfedea0SLionel Sambuc
870ebfedea0SLionel Sambuc ARGCHK(a != NULL && b != NULL && c != NULL, MP_BADARG);
871ebfedea0SLionel Sambuc
872ebfedea0SLionel Sambuc if(SIGN(a) == SIGN(b)) { /* same sign: add values, keep sign */
873ebfedea0SLionel Sambuc
874ebfedea0SLionel Sambuc /* Commutativity of addition lets us do this in either order,
875ebfedea0SLionel Sambuc so we avoid having to use a temporary even if the result
876ebfedea0SLionel Sambuc is supposed to replace the output
877ebfedea0SLionel Sambuc */
878ebfedea0SLionel Sambuc if(c == b) {
879ebfedea0SLionel Sambuc if((res = s_mp_add(c, a)) != MP_OKAY)
880ebfedea0SLionel Sambuc return res;
881ebfedea0SLionel Sambuc } else {
882ebfedea0SLionel Sambuc if(c != a && (res = mp_copy(a, c)) != MP_OKAY)
883ebfedea0SLionel Sambuc return res;
884ebfedea0SLionel Sambuc
885ebfedea0SLionel Sambuc if((res = s_mp_add(c, b)) != MP_OKAY)
886ebfedea0SLionel Sambuc return res;
887ebfedea0SLionel Sambuc }
888ebfedea0SLionel Sambuc
889ebfedea0SLionel Sambuc } else if((cmp = s_mp_cmp(a, b)) > 0) { /* different sign: a > b */
890ebfedea0SLionel Sambuc
891ebfedea0SLionel Sambuc /* If the output is going to be clobbered, we will use a temporary
892ebfedea0SLionel Sambuc variable; otherwise, we'll do it without touching the memory
893ebfedea0SLionel Sambuc allocator at all, if possible
894ebfedea0SLionel Sambuc */
895ebfedea0SLionel Sambuc if(c == b) {
896ebfedea0SLionel Sambuc mp_int tmp;
897ebfedea0SLionel Sambuc
898ebfedea0SLionel Sambuc if((res = mp_init_copy(&tmp, a)) != MP_OKAY)
899ebfedea0SLionel Sambuc return res;
900ebfedea0SLionel Sambuc if((res = s_mp_sub(&tmp, b)) != MP_OKAY) {
901ebfedea0SLionel Sambuc mp_clear(&tmp);
902ebfedea0SLionel Sambuc return res;
903ebfedea0SLionel Sambuc }
904ebfedea0SLionel Sambuc
905ebfedea0SLionel Sambuc s_mp_exch(&tmp, c);
906ebfedea0SLionel Sambuc mp_clear(&tmp);
907ebfedea0SLionel Sambuc
908ebfedea0SLionel Sambuc } else {
909ebfedea0SLionel Sambuc
910ebfedea0SLionel Sambuc if(c != a && (res = mp_copy(a, c)) != MP_OKAY)
911ebfedea0SLionel Sambuc return res;
912ebfedea0SLionel Sambuc if((res = s_mp_sub(c, b)) != MP_OKAY)
913ebfedea0SLionel Sambuc return res;
914ebfedea0SLionel Sambuc
915ebfedea0SLionel Sambuc }
916ebfedea0SLionel Sambuc
917ebfedea0SLionel Sambuc } else if(cmp == 0) { /* different sign, a == b */
918ebfedea0SLionel Sambuc
919ebfedea0SLionel Sambuc mp_zero(c);
920ebfedea0SLionel Sambuc return MP_OKAY;
921ebfedea0SLionel Sambuc
922ebfedea0SLionel Sambuc } else { /* different sign: a < b */
923ebfedea0SLionel Sambuc
924ebfedea0SLionel Sambuc /* See above... */
925ebfedea0SLionel Sambuc if(c == a) {
926ebfedea0SLionel Sambuc mp_int tmp;
927ebfedea0SLionel Sambuc
928ebfedea0SLionel Sambuc if((res = mp_init_copy(&tmp, b)) != MP_OKAY)
929ebfedea0SLionel Sambuc return res;
930ebfedea0SLionel Sambuc if((res = s_mp_sub(&tmp, a)) != MP_OKAY) {
931ebfedea0SLionel Sambuc mp_clear(&tmp);
932ebfedea0SLionel Sambuc return res;
933ebfedea0SLionel Sambuc }
934ebfedea0SLionel Sambuc
935ebfedea0SLionel Sambuc s_mp_exch(&tmp, c);
936ebfedea0SLionel Sambuc mp_clear(&tmp);
937ebfedea0SLionel Sambuc
938ebfedea0SLionel Sambuc } else {
939ebfedea0SLionel Sambuc
940ebfedea0SLionel Sambuc if(c != b && (res = mp_copy(b, c)) != MP_OKAY)
941ebfedea0SLionel Sambuc return res;
942ebfedea0SLionel Sambuc if((res = s_mp_sub(c, a)) != MP_OKAY)
943ebfedea0SLionel Sambuc return res;
944ebfedea0SLionel Sambuc
945ebfedea0SLionel Sambuc }
946ebfedea0SLionel Sambuc }
947ebfedea0SLionel Sambuc
948ebfedea0SLionel Sambuc if(USED(c) == 1 && DIGIT(c, 0) == 0)
949ebfedea0SLionel Sambuc SIGN(c) = MP_ZPOS;
950ebfedea0SLionel Sambuc
951ebfedea0SLionel Sambuc return MP_OKAY;
952ebfedea0SLionel Sambuc
953ebfedea0SLionel Sambuc } /* end mp_add() */
954ebfedea0SLionel Sambuc
955ebfedea0SLionel Sambuc /* }}} */
956ebfedea0SLionel Sambuc
957ebfedea0SLionel Sambuc /* {{{ mp_sub(a, b, c) */
958ebfedea0SLionel Sambuc
959ebfedea0SLionel Sambuc /*
960ebfedea0SLionel Sambuc mp_sub(a, b, c)
961ebfedea0SLionel Sambuc
962ebfedea0SLionel Sambuc Compute c = a - b. All parameters may be identical.
963ebfedea0SLionel Sambuc */
964ebfedea0SLionel Sambuc
mp_sub(mp_int * a,mp_int * b,mp_int * c)965ebfedea0SLionel Sambuc mp_err mp_sub(mp_int *a, mp_int *b, mp_int *c)
966ebfedea0SLionel Sambuc {
967ebfedea0SLionel Sambuc mp_err res;
968ebfedea0SLionel Sambuc int cmp;
969ebfedea0SLionel Sambuc
970ebfedea0SLionel Sambuc ARGCHK(a != NULL && b != NULL && c != NULL, MP_BADARG);
971ebfedea0SLionel Sambuc
972ebfedea0SLionel Sambuc if(SIGN(a) != SIGN(b)) {
973ebfedea0SLionel Sambuc if(c == a) {
974ebfedea0SLionel Sambuc if((res = s_mp_add(c, b)) != MP_OKAY)
975ebfedea0SLionel Sambuc return res;
976ebfedea0SLionel Sambuc } else {
977ebfedea0SLionel Sambuc if(c != b && ((res = mp_copy(b, c)) != MP_OKAY))
978ebfedea0SLionel Sambuc return res;
979ebfedea0SLionel Sambuc if((res = s_mp_add(c, a)) != MP_OKAY)
980ebfedea0SLionel Sambuc return res;
981ebfedea0SLionel Sambuc SIGN(c) = SIGN(a);
982ebfedea0SLionel Sambuc }
983ebfedea0SLionel Sambuc
984ebfedea0SLionel Sambuc } else if((cmp = s_mp_cmp(a, b)) > 0) { /* Same sign, a > b */
985ebfedea0SLionel Sambuc if(c == b) {
986ebfedea0SLionel Sambuc mp_int tmp;
987ebfedea0SLionel Sambuc
988ebfedea0SLionel Sambuc if((res = mp_init_copy(&tmp, a)) != MP_OKAY)
989ebfedea0SLionel Sambuc return res;
990ebfedea0SLionel Sambuc if((res = s_mp_sub(&tmp, b)) != MP_OKAY) {
991ebfedea0SLionel Sambuc mp_clear(&tmp);
992ebfedea0SLionel Sambuc return res;
993ebfedea0SLionel Sambuc }
994ebfedea0SLionel Sambuc s_mp_exch(&tmp, c);
995ebfedea0SLionel Sambuc mp_clear(&tmp);
996ebfedea0SLionel Sambuc
997ebfedea0SLionel Sambuc } else {
998ebfedea0SLionel Sambuc if(c != a && ((res = mp_copy(a, c)) != MP_OKAY))
999ebfedea0SLionel Sambuc return res;
1000ebfedea0SLionel Sambuc
1001ebfedea0SLionel Sambuc if((res = s_mp_sub(c, b)) != MP_OKAY)
1002ebfedea0SLionel Sambuc return res;
1003ebfedea0SLionel Sambuc }
1004ebfedea0SLionel Sambuc
1005ebfedea0SLionel Sambuc } else if(cmp == 0) { /* Same sign, equal magnitude */
1006ebfedea0SLionel Sambuc mp_zero(c);
1007ebfedea0SLionel Sambuc return MP_OKAY;
1008ebfedea0SLionel Sambuc
1009ebfedea0SLionel Sambuc } else { /* Same sign, b > a */
1010ebfedea0SLionel Sambuc if(c == a) {
1011ebfedea0SLionel Sambuc mp_int tmp;
1012ebfedea0SLionel Sambuc
1013ebfedea0SLionel Sambuc if((res = mp_init_copy(&tmp, b)) != MP_OKAY)
1014ebfedea0SLionel Sambuc return res;
1015ebfedea0SLionel Sambuc
1016ebfedea0SLionel Sambuc if((res = s_mp_sub(&tmp, a)) != MP_OKAY) {
1017ebfedea0SLionel Sambuc mp_clear(&tmp);
1018ebfedea0SLionel Sambuc return res;
1019ebfedea0SLionel Sambuc }
1020ebfedea0SLionel Sambuc s_mp_exch(&tmp, c);
1021ebfedea0SLionel Sambuc mp_clear(&tmp);
1022ebfedea0SLionel Sambuc
1023ebfedea0SLionel Sambuc } else {
1024ebfedea0SLionel Sambuc if(c != b && ((res = mp_copy(b, c)) != MP_OKAY))
1025ebfedea0SLionel Sambuc return res;
1026ebfedea0SLionel Sambuc
1027ebfedea0SLionel Sambuc if((res = s_mp_sub(c, a)) != MP_OKAY)
1028ebfedea0SLionel Sambuc return res;
1029ebfedea0SLionel Sambuc }
1030ebfedea0SLionel Sambuc
1031ebfedea0SLionel Sambuc SIGN(c) = !SIGN(b);
1032ebfedea0SLionel Sambuc }
1033ebfedea0SLionel Sambuc
1034ebfedea0SLionel Sambuc if(USED(c) == 1 && DIGIT(c, 0) == 0)
1035ebfedea0SLionel Sambuc SIGN(c) = MP_ZPOS;
1036ebfedea0SLionel Sambuc
1037ebfedea0SLionel Sambuc return MP_OKAY;
1038ebfedea0SLionel Sambuc
1039ebfedea0SLionel Sambuc } /* end mp_sub() */
1040ebfedea0SLionel Sambuc
1041ebfedea0SLionel Sambuc /* }}} */
1042ebfedea0SLionel Sambuc
1043ebfedea0SLionel Sambuc /* {{{ mp_mul(a, b, c) */
1044ebfedea0SLionel Sambuc
1045ebfedea0SLionel Sambuc /*
1046ebfedea0SLionel Sambuc mp_mul(a, b, c)
1047ebfedea0SLionel Sambuc
1048ebfedea0SLionel Sambuc Compute c = a * b. All parameters may be identical.
1049ebfedea0SLionel Sambuc */
1050ebfedea0SLionel Sambuc
mp_mul(mp_int * a,mp_int * b,mp_int * c)1051ebfedea0SLionel Sambuc mp_err mp_mul(mp_int *a, mp_int *b, mp_int *c)
1052ebfedea0SLionel Sambuc {
1053ebfedea0SLionel Sambuc mp_err res;
1054ebfedea0SLionel Sambuc mp_sign sgn;
1055ebfedea0SLionel Sambuc
1056ebfedea0SLionel Sambuc ARGCHK(a != NULL && b != NULL && c != NULL, MP_BADARG);
1057ebfedea0SLionel Sambuc
1058ebfedea0SLionel Sambuc sgn = (SIGN(a) == SIGN(b)) ? MP_ZPOS : MP_NEG;
1059ebfedea0SLionel Sambuc
1060ebfedea0SLionel Sambuc if(c == b) {
1061ebfedea0SLionel Sambuc if((res = s_mp_mul(c, a)) != MP_OKAY)
1062ebfedea0SLionel Sambuc return res;
1063ebfedea0SLionel Sambuc
1064ebfedea0SLionel Sambuc } else {
1065ebfedea0SLionel Sambuc if((res = mp_copy(a, c)) != MP_OKAY)
1066ebfedea0SLionel Sambuc return res;
1067ebfedea0SLionel Sambuc
1068ebfedea0SLionel Sambuc if((res = s_mp_mul(c, b)) != MP_OKAY)
1069ebfedea0SLionel Sambuc return res;
1070ebfedea0SLionel Sambuc }
1071ebfedea0SLionel Sambuc
1072ebfedea0SLionel Sambuc if(sgn == MP_ZPOS || s_mp_cmp_d(c, 0) == MP_EQ)
1073ebfedea0SLionel Sambuc SIGN(c) = MP_ZPOS;
1074ebfedea0SLionel Sambuc else
1075ebfedea0SLionel Sambuc SIGN(c) = sgn;
1076ebfedea0SLionel Sambuc
1077ebfedea0SLionel Sambuc return MP_OKAY;
1078ebfedea0SLionel Sambuc
1079ebfedea0SLionel Sambuc } /* end mp_mul() */
1080ebfedea0SLionel Sambuc
1081ebfedea0SLionel Sambuc /* }}} */
1082ebfedea0SLionel Sambuc
1083ebfedea0SLionel Sambuc /* {{{ mp_mul_2d(a, d, c) */
1084ebfedea0SLionel Sambuc
1085ebfedea0SLionel Sambuc /*
1086ebfedea0SLionel Sambuc mp_mul_2d(a, d, c)
1087ebfedea0SLionel Sambuc
1088ebfedea0SLionel Sambuc Compute c = a * 2^d. a may be the same as c.
1089ebfedea0SLionel Sambuc */
1090ebfedea0SLionel Sambuc
mp_mul_2d(mp_int * a,mp_digit d,mp_int * c)1091ebfedea0SLionel Sambuc mp_err mp_mul_2d(mp_int *a, mp_digit d, mp_int *c)
1092ebfedea0SLionel Sambuc {
1093ebfedea0SLionel Sambuc mp_err res;
1094ebfedea0SLionel Sambuc
1095ebfedea0SLionel Sambuc ARGCHK(a != NULL && c != NULL, MP_BADARG);
1096ebfedea0SLionel Sambuc
1097ebfedea0SLionel Sambuc if((res = mp_copy(a, c)) != MP_OKAY)
1098ebfedea0SLionel Sambuc return res;
1099ebfedea0SLionel Sambuc
1100ebfedea0SLionel Sambuc if(d == 0)
1101ebfedea0SLionel Sambuc return MP_OKAY;
1102ebfedea0SLionel Sambuc
1103ebfedea0SLionel Sambuc return s_mp_mul_2d(c, d);
1104ebfedea0SLionel Sambuc
1105ebfedea0SLionel Sambuc } /* end mp_mul() */
1106ebfedea0SLionel Sambuc
1107ebfedea0SLionel Sambuc /* }}} */
1108ebfedea0SLionel Sambuc
1109ebfedea0SLionel Sambuc /* {{{ mp_sqr(a, b) */
1110ebfedea0SLionel Sambuc
1111ebfedea0SLionel Sambuc #if MP_SQUARE
mp_sqr(mp_int * a,mp_int * b)1112ebfedea0SLionel Sambuc mp_err mp_sqr(mp_int *a, mp_int *b)
1113ebfedea0SLionel Sambuc {
1114ebfedea0SLionel Sambuc mp_err res;
1115ebfedea0SLionel Sambuc
1116ebfedea0SLionel Sambuc ARGCHK(a != NULL && b != NULL, MP_BADARG);
1117ebfedea0SLionel Sambuc
1118ebfedea0SLionel Sambuc if((res = mp_copy(a, b)) != MP_OKAY)
1119ebfedea0SLionel Sambuc return res;
1120ebfedea0SLionel Sambuc
1121ebfedea0SLionel Sambuc if((res = s_mp_sqr(b)) != MP_OKAY)
1122ebfedea0SLionel Sambuc return res;
1123ebfedea0SLionel Sambuc
1124ebfedea0SLionel Sambuc SIGN(b) = MP_ZPOS;
1125ebfedea0SLionel Sambuc
1126ebfedea0SLionel Sambuc return MP_OKAY;
1127ebfedea0SLionel Sambuc
1128ebfedea0SLionel Sambuc } /* end mp_sqr() */
1129ebfedea0SLionel Sambuc #endif
1130ebfedea0SLionel Sambuc
1131ebfedea0SLionel Sambuc /* }}} */
1132ebfedea0SLionel Sambuc
1133ebfedea0SLionel Sambuc /* {{{ mp_div(a, b, q, r) */
1134ebfedea0SLionel Sambuc
1135ebfedea0SLionel Sambuc /*
1136ebfedea0SLionel Sambuc mp_div(a, b, q, r)
1137ebfedea0SLionel Sambuc
1138ebfedea0SLionel Sambuc Compute q = a / b and r = a mod b. Input parameters may be re-used
1139ebfedea0SLionel Sambuc as output parameters. If q or r is NULL, that portion of the
1140ebfedea0SLionel Sambuc computation will be discarded (although it will still be computed)
1141ebfedea0SLionel Sambuc
1142ebfedea0SLionel Sambuc Pay no attention to the hacker behind the curtain.
1143ebfedea0SLionel Sambuc */
1144ebfedea0SLionel Sambuc
mp_div(mp_int * a,mp_int * b,mp_int * q,mp_int * r)1145ebfedea0SLionel Sambuc mp_err mp_div(mp_int *a, mp_int *b, mp_int *q, mp_int *r)
1146ebfedea0SLionel Sambuc {
1147ebfedea0SLionel Sambuc mp_err res;
1148ebfedea0SLionel Sambuc mp_int qtmp, rtmp;
1149ebfedea0SLionel Sambuc int cmp;
1150ebfedea0SLionel Sambuc
1151ebfedea0SLionel Sambuc ARGCHK(a != NULL && b != NULL, MP_BADARG);
1152ebfedea0SLionel Sambuc
1153ebfedea0SLionel Sambuc if(mp_cmp_z(b) == MP_EQ)
1154ebfedea0SLionel Sambuc return MP_RANGE;
1155ebfedea0SLionel Sambuc
1156ebfedea0SLionel Sambuc /* If a <= b, we can compute the solution without division, and
1157ebfedea0SLionel Sambuc avoid any memory allocation
1158ebfedea0SLionel Sambuc */
1159ebfedea0SLionel Sambuc if((cmp = s_mp_cmp(a, b)) < 0) {
1160ebfedea0SLionel Sambuc if(r) {
1161ebfedea0SLionel Sambuc if((res = mp_copy(a, r)) != MP_OKAY)
1162ebfedea0SLionel Sambuc return res;
1163ebfedea0SLionel Sambuc }
1164ebfedea0SLionel Sambuc
1165ebfedea0SLionel Sambuc if(q)
1166ebfedea0SLionel Sambuc mp_zero(q);
1167ebfedea0SLionel Sambuc
1168ebfedea0SLionel Sambuc return MP_OKAY;
1169ebfedea0SLionel Sambuc
1170ebfedea0SLionel Sambuc } else if(cmp == 0) {
1171ebfedea0SLionel Sambuc
1172ebfedea0SLionel Sambuc /* Set quotient to 1, with appropriate sign */
1173ebfedea0SLionel Sambuc if(q) {
1174ebfedea0SLionel Sambuc int qneg = (SIGN(a) != SIGN(b));
1175ebfedea0SLionel Sambuc
1176ebfedea0SLionel Sambuc mp_set(q, 1);
1177ebfedea0SLionel Sambuc if(qneg)
1178ebfedea0SLionel Sambuc SIGN(q) = MP_NEG;
1179ebfedea0SLionel Sambuc }
1180ebfedea0SLionel Sambuc
1181ebfedea0SLionel Sambuc if(r)
1182ebfedea0SLionel Sambuc mp_zero(r);
1183ebfedea0SLionel Sambuc
1184ebfedea0SLionel Sambuc return MP_OKAY;
1185ebfedea0SLionel Sambuc }
1186ebfedea0SLionel Sambuc
1187ebfedea0SLionel Sambuc /* If we get here, it means we actually have to do some division */
1188ebfedea0SLionel Sambuc
1189ebfedea0SLionel Sambuc /* Set up some temporaries... */
1190ebfedea0SLionel Sambuc if((res = mp_init_copy(&qtmp, a)) != MP_OKAY)
1191ebfedea0SLionel Sambuc return res;
1192ebfedea0SLionel Sambuc if((res = mp_init_copy(&rtmp, b)) != MP_OKAY)
1193ebfedea0SLionel Sambuc goto CLEANUP;
1194ebfedea0SLionel Sambuc
1195ebfedea0SLionel Sambuc if((res = s_mp_div(&qtmp, &rtmp)) != MP_OKAY)
1196ebfedea0SLionel Sambuc goto CLEANUP;
1197ebfedea0SLionel Sambuc
1198ebfedea0SLionel Sambuc /* Compute the signs for the output */
1199ebfedea0SLionel Sambuc SIGN(&rtmp) = SIGN(a); /* Sr = Sa */
1200ebfedea0SLionel Sambuc if(SIGN(a) == SIGN(b))
1201ebfedea0SLionel Sambuc SIGN(&qtmp) = MP_ZPOS; /* Sq = MP_ZPOS if Sa = Sb */
1202ebfedea0SLionel Sambuc else
1203ebfedea0SLionel Sambuc SIGN(&qtmp) = MP_NEG; /* Sq = MP_NEG if Sa != Sb */
1204ebfedea0SLionel Sambuc
1205ebfedea0SLionel Sambuc if(s_mp_cmp_d(&qtmp, 0) == MP_EQ)
1206ebfedea0SLionel Sambuc SIGN(&qtmp) = MP_ZPOS;
1207ebfedea0SLionel Sambuc if(s_mp_cmp_d(&rtmp, 0) == MP_EQ)
1208ebfedea0SLionel Sambuc SIGN(&rtmp) = MP_ZPOS;
1209ebfedea0SLionel Sambuc
1210ebfedea0SLionel Sambuc /* Copy output, if it is needed */
1211ebfedea0SLionel Sambuc if(q)
1212ebfedea0SLionel Sambuc s_mp_exch(&qtmp, q);
1213ebfedea0SLionel Sambuc
1214ebfedea0SLionel Sambuc if(r)
1215ebfedea0SLionel Sambuc s_mp_exch(&rtmp, r);
1216ebfedea0SLionel Sambuc
1217ebfedea0SLionel Sambuc CLEANUP:
1218ebfedea0SLionel Sambuc mp_clear(&rtmp);
1219ebfedea0SLionel Sambuc mp_clear(&qtmp);
1220ebfedea0SLionel Sambuc
1221ebfedea0SLionel Sambuc return res;
1222ebfedea0SLionel Sambuc
1223ebfedea0SLionel Sambuc } /* end mp_div() */
1224ebfedea0SLionel Sambuc
1225ebfedea0SLionel Sambuc /* }}} */
1226ebfedea0SLionel Sambuc
1227ebfedea0SLionel Sambuc /* {{{ mp_div_2d(a, d, q, r) */
1228ebfedea0SLionel Sambuc
mp_div_2d(mp_int * a,mp_digit d,mp_int * q,mp_int * r)1229ebfedea0SLionel Sambuc mp_err mp_div_2d(mp_int *a, mp_digit d, mp_int *q, mp_int *r)
1230ebfedea0SLionel Sambuc {
1231ebfedea0SLionel Sambuc mp_err res;
1232ebfedea0SLionel Sambuc
1233ebfedea0SLionel Sambuc ARGCHK(a != NULL, MP_BADARG);
1234ebfedea0SLionel Sambuc
1235ebfedea0SLionel Sambuc if(q) {
1236ebfedea0SLionel Sambuc if((res = mp_copy(a, q)) != MP_OKAY)
1237ebfedea0SLionel Sambuc return res;
1238ebfedea0SLionel Sambuc
1239ebfedea0SLionel Sambuc s_mp_div_2d(q, d);
1240ebfedea0SLionel Sambuc }
1241ebfedea0SLionel Sambuc
1242ebfedea0SLionel Sambuc if(r) {
1243ebfedea0SLionel Sambuc if((res = mp_copy(a, r)) != MP_OKAY)
1244ebfedea0SLionel Sambuc return res;
1245ebfedea0SLionel Sambuc
1246ebfedea0SLionel Sambuc s_mp_mod_2d(r, d);
1247ebfedea0SLionel Sambuc }
1248ebfedea0SLionel Sambuc
1249ebfedea0SLionel Sambuc return MP_OKAY;
1250ebfedea0SLionel Sambuc
1251ebfedea0SLionel Sambuc } /* end mp_div_2d() */
1252ebfedea0SLionel Sambuc
1253ebfedea0SLionel Sambuc /* }}} */
1254ebfedea0SLionel Sambuc
1255ebfedea0SLionel Sambuc /* {{{ mp_expt(a, b, c) */
1256ebfedea0SLionel Sambuc
1257ebfedea0SLionel Sambuc /*
1258ebfedea0SLionel Sambuc mp_expt(a, b, c)
1259ebfedea0SLionel Sambuc
1260ebfedea0SLionel Sambuc Compute c = a ** b, that is, raise a to the b power. Uses a
1261ebfedea0SLionel Sambuc standard iterative square-and-multiply technique.
1262ebfedea0SLionel Sambuc */
1263ebfedea0SLionel Sambuc
mp_expt(mp_int * a,mp_int * b,mp_int * c)1264ebfedea0SLionel Sambuc mp_err mp_expt(mp_int *a, mp_int *b, mp_int *c)
1265ebfedea0SLionel Sambuc {
1266ebfedea0SLionel Sambuc mp_int s, x;
1267ebfedea0SLionel Sambuc mp_err res;
1268ebfedea0SLionel Sambuc mp_digit d;
1269ebfedea0SLionel Sambuc int dig, bit;
1270ebfedea0SLionel Sambuc
1271ebfedea0SLionel Sambuc ARGCHK(a != NULL && b != NULL && c != NULL, MP_BADARG);
1272ebfedea0SLionel Sambuc
1273ebfedea0SLionel Sambuc if(mp_cmp_z(b) < 0)
1274ebfedea0SLionel Sambuc return MP_RANGE;
1275ebfedea0SLionel Sambuc
1276ebfedea0SLionel Sambuc if((res = mp_init(&s)) != MP_OKAY)
1277ebfedea0SLionel Sambuc return res;
1278ebfedea0SLionel Sambuc
1279ebfedea0SLionel Sambuc mp_set(&s, 1);
1280ebfedea0SLionel Sambuc
1281ebfedea0SLionel Sambuc if((res = mp_init_copy(&x, a)) != MP_OKAY)
1282ebfedea0SLionel Sambuc goto X;
1283ebfedea0SLionel Sambuc
1284ebfedea0SLionel Sambuc /* Loop over low-order digits in ascending order */
1285ebfedea0SLionel Sambuc for(dig = 0; dig < (USED(b) - 1); dig++) {
1286ebfedea0SLionel Sambuc d = DIGIT(b, dig);
1287ebfedea0SLionel Sambuc
1288ebfedea0SLionel Sambuc /* Loop over bits of each non-maximal digit */
1289ebfedea0SLionel Sambuc for(bit = 0; bit < DIGIT_BIT; bit++) {
1290ebfedea0SLionel Sambuc if(d & 1) {
1291ebfedea0SLionel Sambuc if((res = s_mp_mul(&s, &x)) != MP_OKAY)
1292ebfedea0SLionel Sambuc goto CLEANUP;
1293ebfedea0SLionel Sambuc }
1294ebfedea0SLionel Sambuc
1295ebfedea0SLionel Sambuc d >>= 1;
1296ebfedea0SLionel Sambuc
1297ebfedea0SLionel Sambuc if((res = s_mp_sqr(&x)) != MP_OKAY)
1298ebfedea0SLionel Sambuc goto CLEANUP;
1299ebfedea0SLionel Sambuc }
1300ebfedea0SLionel Sambuc }
1301ebfedea0SLionel Sambuc
1302ebfedea0SLionel Sambuc /* Consider now the last digit... */
1303ebfedea0SLionel Sambuc d = DIGIT(b, dig);
1304ebfedea0SLionel Sambuc
1305ebfedea0SLionel Sambuc while(d) {
1306ebfedea0SLionel Sambuc if(d & 1) {
1307ebfedea0SLionel Sambuc if((res = s_mp_mul(&s, &x)) != MP_OKAY)
1308ebfedea0SLionel Sambuc goto CLEANUP;
1309ebfedea0SLionel Sambuc }
1310ebfedea0SLionel Sambuc
1311ebfedea0SLionel Sambuc d >>= 1;
1312ebfedea0SLionel Sambuc
1313ebfedea0SLionel Sambuc if((res = s_mp_sqr(&x)) != MP_OKAY)
1314ebfedea0SLionel Sambuc goto CLEANUP;
1315ebfedea0SLionel Sambuc }
1316ebfedea0SLionel Sambuc
1317ebfedea0SLionel Sambuc if(mp_iseven(b))
1318ebfedea0SLionel Sambuc SIGN(&s) = SIGN(a);
1319ebfedea0SLionel Sambuc
1320ebfedea0SLionel Sambuc res = mp_copy(&s, c);
1321ebfedea0SLionel Sambuc
1322ebfedea0SLionel Sambuc CLEANUP:
1323ebfedea0SLionel Sambuc mp_clear(&x);
1324ebfedea0SLionel Sambuc X:
1325ebfedea0SLionel Sambuc mp_clear(&s);
1326ebfedea0SLionel Sambuc
1327ebfedea0SLionel Sambuc return res;
1328ebfedea0SLionel Sambuc
1329ebfedea0SLionel Sambuc } /* end mp_expt() */
1330ebfedea0SLionel Sambuc
1331ebfedea0SLionel Sambuc /* }}} */
1332ebfedea0SLionel Sambuc
1333ebfedea0SLionel Sambuc /* {{{ mp_2expt(a, k) */
1334ebfedea0SLionel Sambuc
1335ebfedea0SLionel Sambuc /* Compute a = 2^k */
1336ebfedea0SLionel Sambuc
mp_2expt(mp_int * a,mp_digit k)1337ebfedea0SLionel Sambuc mp_err mp_2expt(mp_int *a, mp_digit k)
1338ebfedea0SLionel Sambuc {
1339ebfedea0SLionel Sambuc ARGCHK(a != NULL, MP_BADARG);
1340ebfedea0SLionel Sambuc
1341ebfedea0SLionel Sambuc return s_mp_2expt(a, k);
1342ebfedea0SLionel Sambuc
1343ebfedea0SLionel Sambuc } /* end mp_2expt() */
1344ebfedea0SLionel Sambuc
1345ebfedea0SLionel Sambuc /* }}} */
1346ebfedea0SLionel Sambuc
1347ebfedea0SLionel Sambuc /* {{{ mp_mod(a, m, c) */
1348ebfedea0SLionel Sambuc
1349ebfedea0SLionel Sambuc /*
1350ebfedea0SLionel Sambuc mp_mod(a, m, c)
1351ebfedea0SLionel Sambuc
1352ebfedea0SLionel Sambuc Compute c = a (mod m). Result will always be 0 <= c < m.
1353ebfedea0SLionel Sambuc */
1354ebfedea0SLionel Sambuc
mp_mod(mp_int * a,mp_int * m,mp_int * c)1355ebfedea0SLionel Sambuc mp_err mp_mod(mp_int *a, mp_int *m, mp_int *c)
1356ebfedea0SLionel Sambuc {
1357ebfedea0SLionel Sambuc mp_err res;
1358ebfedea0SLionel Sambuc int mag;
1359ebfedea0SLionel Sambuc
1360ebfedea0SLionel Sambuc ARGCHK(a != NULL && m != NULL && c != NULL, MP_BADARG);
1361ebfedea0SLionel Sambuc
1362ebfedea0SLionel Sambuc if(SIGN(m) == MP_NEG)
1363ebfedea0SLionel Sambuc return MP_RANGE;
1364ebfedea0SLionel Sambuc
1365ebfedea0SLionel Sambuc /*
1366ebfedea0SLionel Sambuc If |a| > m, we need to divide to get the remainder and take the
1367ebfedea0SLionel Sambuc absolute value.
1368ebfedea0SLionel Sambuc
1369ebfedea0SLionel Sambuc If |a| < m, we don't need to do any division, just copy and adjust
1370ebfedea0SLionel Sambuc the sign (if a is negative).
1371ebfedea0SLionel Sambuc
1372ebfedea0SLionel Sambuc If |a| == m, we can simply set the result to zero.
1373ebfedea0SLionel Sambuc
1374ebfedea0SLionel Sambuc This order is intended to minimize the average path length of the
1375ebfedea0SLionel Sambuc comparison chain on common workloads -- the most frequent cases are
1376ebfedea0SLionel Sambuc that |a| != m, so we do those first.
1377ebfedea0SLionel Sambuc */
1378ebfedea0SLionel Sambuc if((mag = s_mp_cmp(a, m)) > 0) {
1379ebfedea0SLionel Sambuc if((res = mp_div(a, m, NULL, c)) != MP_OKAY)
1380ebfedea0SLionel Sambuc return res;
1381ebfedea0SLionel Sambuc
1382ebfedea0SLionel Sambuc if(SIGN(c) == MP_NEG) {
1383ebfedea0SLionel Sambuc if((res = mp_add(c, m, c)) != MP_OKAY)
1384ebfedea0SLionel Sambuc return res;
1385ebfedea0SLionel Sambuc }
1386ebfedea0SLionel Sambuc
1387ebfedea0SLionel Sambuc } else if(mag < 0) {
1388ebfedea0SLionel Sambuc if((res = mp_copy(a, c)) != MP_OKAY)
1389ebfedea0SLionel Sambuc return res;
1390ebfedea0SLionel Sambuc
1391ebfedea0SLionel Sambuc if(mp_cmp_z(a) < 0) {
1392ebfedea0SLionel Sambuc if((res = mp_add(c, m, c)) != MP_OKAY)
1393ebfedea0SLionel Sambuc return res;
1394ebfedea0SLionel Sambuc
1395ebfedea0SLionel Sambuc }
1396ebfedea0SLionel Sambuc
1397ebfedea0SLionel Sambuc } else {
1398ebfedea0SLionel Sambuc mp_zero(c);
1399ebfedea0SLionel Sambuc
1400ebfedea0SLionel Sambuc }
1401ebfedea0SLionel Sambuc
1402ebfedea0SLionel Sambuc return MP_OKAY;
1403ebfedea0SLionel Sambuc
1404ebfedea0SLionel Sambuc } /* end mp_mod() */
1405ebfedea0SLionel Sambuc
1406ebfedea0SLionel Sambuc /* }}} */
1407ebfedea0SLionel Sambuc
1408ebfedea0SLionel Sambuc /* {{{ mp_mod_d(a, d, c) */
1409ebfedea0SLionel Sambuc
1410ebfedea0SLionel Sambuc /*
1411ebfedea0SLionel Sambuc mp_mod_d(a, d, c)
1412ebfedea0SLionel Sambuc
1413ebfedea0SLionel Sambuc Compute c = a (mod d). Result will always be 0 <= c < d
1414ebfedea0SLionel Sambuc */
mp_mod_d(mp_int * a,mp_digit d,mp_digit * c)1415ebfedea0SLionel Sambuc mp_err mp_mod_d(mp_int *a, mp_digit d, mp_digit *c)
1416ebfedea0SLionel Sambuc {
1417ebfedea0SLionel Sambuc mp_err res;
1418ebfedea0SLionel Sambuc mp_digit rem;
1419ebfedea0SLionel Sambuc
1420ebfedea0SLionel Sambuc ARGCHK(a != NULL && c != NULL, MP_BADARG);
1421ebfedea0SLionel Sambuc
1422ebfedea0SLionel Sambuc if(s_mp_cmp_d(a, d) > 0) {
1423ebfedea0SLionel Sambuc if((res = mp_div_d(a, d, NULL, &rem)) != MP_OKAY)
1424ebfedea0SLionel Sambuc return res;
1425ebfedea0SLionel Sambuc
1426ebfedea0SLionel Sambuc } else {
1427ebfedea0SLionel Sambuc if(SIGN(a) == MP_NEG)
1428ebfedea0SLionel Sambuc rem = d - DIGIT(a, 0);
1429ebfedea0SLionel Sambuc else
1430ebfedea0SLionel Sambuc rem = DIGIT(a, 0);
1431ebfedea0SLionel Sambuc }
1432ebfedea0SLionel Sambuc
1433ebfedea0SLionel Sambuc if(c)
1434ebfedea0SLionel Sambuc *c = rem;
1435ebfedea0SLionel Sambuc
1436ebfedea0SLionel Sambuc return MP_OKAY;
1437ebfedea0SLionel Sambuc
1438ebfedea0SLionel Sambuc } /* end mp_mod_d() */
1439ebfedea0SLionel Sambuc
1440ebfedea0SLionel Sambuc /* }}} */
1441ebfedea0SLionel Sambuc
1442ebfedea0SLionel Sambuc /* {{{ mp_sqrt(a, b) */
1443ebfedea0SLionel Sambuc
1444ebfedea0SLionel Sambuc /*
1445ebfedea0SLionel Sambuc mp_sqrt(a, b)
1446ebfedea0SLionel Sambuc
1447ebfedea0SLionel Sambuc Compute the integer square root of a, and store the result in b.
1448ebfedea0SLionel Sambuc Uses an integer-arithmetic version of Newton's iterative linear
1449ebfedea0SLionel Sambuc approximation technique to determine this value; the result has the
1450ebfedea0SLionel Sambuc following two properties:
1451ebfedea0SLionel Sambuc
1452ebfedea0SLionel Sambuc b^2 <= a
1453ebfedea0SLionel Sambuc (b+1)^2 >= a
1454ebfedea0SLionel Sambuc
1455ebfedea0SLionel Sambuc It is a range error to pass a negative value.
1456ebfedea0SLionel Sambuc */
mp_sqrt(mp_int * a,mp_int * b)1457ebfedea0SLionel Sambuc mp_err mp_sqrt(mp_int *a, mp_int *b)
1458ebfedea0SLionel Sambuc {
1459ebfedea0SLionel Sambuc mp_int x, t;
1460ebfedea0SLionel Sambuc mp_err res;
1461ebfedea0SLionel Sambuc
1462ebfedea0SLionel Sambuc ARGCHK(a != NULL && b != NULL, MP_BADARG);
1463ebfedea0SLionel Sambuc
1464ebfedea0SLionel Sambuc /* Cannot take square root of a negative value */
1465ebfedea0SLionel Sambuc if(SIGN(a) == MP_NEG)
1466ebfedea0SLionel Sambuc return MP_RANGE;
1467ebfedea0SLionel Sambuc
1468ebfedea0SLionel Sambuc /* Special cases for zero and one, trivial */
1469ebfedea0SLionel Sambuc if(mp_cmp_d(a, 0) == MP_EQ || mp_cmp_d(a, 1) == MP_EQ)
1470ebfedea0SLionel Sambuc return mp_copy(a, b);
1471ebfedea0SLionel Sambuc
1472ebfedea0SLionel Sambuc /* Initialize the temporaries we'll use below */
1473ebfedea0SLionel Sambuc if((res = mp_init_size(&t, USED(a))) != MP_OKAY)
1474ebfedea0SLionel Sambuc return res;
1475ebfedea0SLionel Sambuc
1476ebfedea0SLionel Sambuc /* Compute an initial guess for the iteration as a itself */
1477ebfedea0SLionel Sambuc if((res = mp_init_copy(&x, a)) != MP_OKAY)
1478ebfedea0SLionel Sambuc goto X;
1479ebfedea0SLionel Sambuc
1480ebfedea0SLionel Sambuc s_mp_rshd(&x, (USED(&x)/2)+1);
1481ebfedea0SLionel Sambuc mp_add_d(&x, 1, &x);
1482ebfedea0SLionel Sambuc
1483ebfedea0SLionel Sambuc for(;;) {
1484ebfedea0SLionel Sambuc /* t = (x * x) - a */
1485ebfedea0SLionel Sambuc mp_copy(&x, &t); /* can't fail, t is big enough for original x */
1486ebfedea0SLionel Sambuc if((res = mp_sqr(&t, &t)) != MP_OKAY ||
1487ebfedea0SLionel Sambuc (res = mp_sub(&t, a, &t)) != MP_OKAY)
1488ebfedea0SLionel Sambuc goto CLEANUP;
1489ebfedea0SLionel Sambuc
1490ebfedea0SLionel Sambuc /* t = t / 2x */
1491ebfedea0SLionel Sambuc s_mp_mul_2(&x);
1492ebfedea0SLionel Sambuc if((res = mp_div(&t, &x, &t, NULL)) != MP_OKAY)
1493ebfedea0SLionel Sambuc goto CLEANUP;
1494ebfedea0SLionel Sambuc s_mp_div_2(&x);
1495ebfedea0SLionel Sambuc
1496ebfedea0SLionel Sambuc /* Terminate the loop, if the quotient is zero */
1497ebfedea0SLionel Sambuc if(mp_cmp_z(&t) == MP_EQ)
1498ebfedea0SLionel Sambuc break;
1499ebfedea0SLionel Sambuc
1500ebfedea0SLionel Sambuc /* x = x - t */
1501ebfedea0SLionel Sambuc if((res = mp_sub(&x, &t, &x)) != MP_OKAY)
1502ebfedea0SLionel Sambuc goto CLEANUP;
1503ebfedea0SLionel Sambuc
1504ebfedea0SLionel Sambuc }
1505ebfedea0SLionel Sambuc
1506ebfedea0SLionel Sambuc /* Copy result to output parameter */
1507ebfedea0SLionel Sambuc mp_sub_d(&x, 1, &x);
1508ebfedea0SLionel Sambuc s_mp_exch(&x, b);
1509ebfedea0SLionel Sambuc
1510ebfedea0SLionel Sambuc CLEANUP:
1511ebfedea0SLionel Sambuc mp_clear(&x);
1512ebfedea0SLionel Sambuc X:
1513ebfedea0SLionel Sambuc mp_clear(&t);
1514ebfedea0SLionel Sambuc
1515ebfedea0SLionel Sambuc return res;
1516ebfedea0SLionel Sambuc
1517ebfedea0SLionel Sambuc } /* end mp_sqrt() */
1518ebfedea0SLionel Sambuc
1519ebfedea0SLionel Sambuc /* }}} */
1520ebfedea0SLionel Sambuc
1521ebfedea0SLionel Sambuc /* }}} */
1522ebfedea0SLionel Sambuc
1523ebfedea0SLionel Sambuc /*------------------------------------------------------------------------*/
1524ebfedea0SLionel Sambuc /* {{{ Modular arithmetic */
1525ebfedea0SLionel Sambuc
1526ebfedea0SLionel Sambuc #if MP_MODARITH
1527ebfedea0SLionel Sambuc /* {{{ mp_addmod(a, b, m, c) */
1528ebfedea0SLionel Sambuc
1529ebfedea0SLionel Sambuc /*
1530ebfedea0SLionel Sambuc mp_addmod(a, b, m, c)
1531ebfedea0SLionel Sambuc
1532ebfedea0SLionel Sambuc Compute c = (a + b) mod m
1533ebfedea0SLionel Sambuc */
1534ebfedea0SLionel Sambuc
mp_addmod(mp_int * a,mp_int * b,mp_int * m,mp_int * c)1535ebfedea0SLionel Sambuc mp_err mp_addmod(mp_int *a, mp_int *b, mp_int *m, mp_int *c)
1536ebfedea0SLionel Sambuc {
1537ebfedea0SLionel Sambuc mp_err res;
1538ebfedea0SLionel Sambuc
1539ebfedea0SLionel Sambuc ARGCHK(a != NULL && b != NULL && m != NULL && c != NULL, MP_BADARG);
1540ebfedea0SLionel Sambuc
1541ebfedea0SLionel Sambuc if((res = mp_add(a, b, c)) != MP_OKAY)
1542ebfedea0SLionel Sambuc return res;
1543ebfedea0SLionel Sambuc if((res = mp_mod(c, m, c)) != MP_OKAY)
1544ebfedea0SLionel Sambuc return res;
1545ebfedea0SLionel Sambuc
1546ebfedea0SLionel Sambuc return MP_OKAY;
1547ebfedea0SLionel Sambuc
1548ebfedea0SLionel Sambuc }
1549ebfedea0SLionel Sambuc
1550ebfedea0SLionel Sambuc /* }}} */
1551ebfedea0SLionel Sambuc
1552ebfedea0SLionel Sambuc /* {{{ mp_submod(a, b, m, c) */
1553ebfedea0SLionel Sambuc
1554ebfedea0SLionel Sambuc /*
1555ebfedea0SLionel Sambuc mp_submod(a, b, m, c)
1556ebfedea0SLionel Sambuc
1557ebfedea0SLionel Sambuc Compute c = (a - b) mod m
1558ebfedea0SLionel Sambuc */
1559ebfedea0SLionel Sambuc
mp_submod(mp_int * a,mp_int * b,mp_int * m,mp_int * c)1560ebfedea0SLionel Sambuc mp_err mp_submod(mp_int *a, mp_int *b, mp_int *m, mp_int *c)
1561ebfedea0SLionel Sambuc {
1562ebfedea0SLionel Sambuc mp_err res;
1563ebfedea0SLionel Sambuc
1564ebfedea0SLionel Sambuc ARGCHK(a != NULL && b != NULL && m != NULL && c != NULL, MP_BADARG);
1565ebfedea0SLionel Sambuc
1566ebfedea0SLionel Sambuc if((res = mp_sub(a, b, c)) != MP_OKAY)
1567ebfedea0SLionel Sambuc return res;
1568ebfedea0SLionel Sambuc if((res = mp_mod(c, m, c)) != MP_OKAY)
1569ebfedea0SLionel Sambuc return res;
1570ebfedea0SLionel Sambuc
1571ebfedea0SLionel Sambuc return MP_OKAY;
1572ebfedea0SLionel Sambuc
1573ebfedea0SLionel Sambuc }
1574ebfedea0SLionel Sambuc
1575ebfedea0SLionel Sambuc /* }}} */
1576ebfedea0SLionel Sambuc
1577ebfedea0SLionel Sambuc /* {{{ mp_mulmod(a, b, m, c) */
1578ebfedea0SLionel Sambuc
1579ebfedea0SLionel Sambuc /*
1580ebfedea0SLionel Sambuc mp_mulmod(a, b, m, c)
1581ebfedea0SLionel Sambuc
1582ebfedea0SLionel Sambuc Compute c = (a * b) mod m
1583ebfedea0SLionel Sambuc */
1584ebfedea0SLionel Sambuc
mp_mulmod(mp_int * a,mp_int * b,mp_int * m,mp_int * c)1585ebfedea0SLionel Sambuc mp_err mp_mulmod(mp_int *a, mp_int *b, mp_int *m, mp_int *c)
1586ebfedea0SLionel Sambuc {
1587ebfedea0SLionel Sambuc mp_err res;
1588ebfedea0SLionel Sambuc
1589ebfedea0SLionel Sambuc ARGCHK(a != NULL && b != NULL && m != NULL && c != NULL, MP_BADARG);
1590ebfedea0SLionel Sambuc
1591ebfedea0SLionel Sambuc if((res = mp_mul(a, b, c)) != MP_OKAY)
1592ebfedea0SLionel Sambuc return res;
1593ebfedea0SLionel Sambuc if((res = mp_mod(c, m, c)) != MP_OKAY)
1594ebfedea0SLionel Sambuc return res;
1595ebfedea0SLionel Sambuc
1596ebfedea0SLionel Sambuc return MP_OKAY;
1597ebfedea0SLionel Sambuc
1598ebfedea0SLionel Sambuc }
1599ebfedea0SLionel Sambuc
1600ebfedea0SLionel Sambuc /* }}} */
1601ebfedea0SLionel Sambuc
1602ebfedea0SLionel Sambuc /* {{{ mp_sqrmod(a, m, c) */
1603ebfedea0SLionel Sambuc
1604ebfedea0SLionel Sambuc #if MP_SQUARE
mp_sqrmod(mp_int * a,mp_int * m,mp_int * c)1605ebfedea0SLionel Sambuc mp_err mp_sqrmod(mp_int *a, mp_int *m, mp_int *c)
1606ebfedea0SLionel Sambuc {
1607ebfedea0SLionel Sambuc mp_err res;
1608ebfedea0SLionel Sambuc
1609ebfedea0SLionel Sambuc ARGCHK(a != NULL && m != NULL && c != NULL, MP_BADARG);
1610ebfedea0SLionel Sambuc
1611ebfedea0SLionel Sambuc if((res = mp_sqr(a, c)) != MP_OKAY)
1612ebfedea0SLionel Sambuc return res;
1613ebfedea0SLionel Sambuc if((res = mp_mod(c, m, c)) != MP_OKAY)
1614ebfedea0SLionel Sambuc return res;
1615ebfedea0SLionel Sambuc
1616ebfedea0SLionel Sambuc return MP_OKAY;
1617ebfedea0SLionel Sambuc
1618ebfedea0SLionel Sambuc } /* end mp_sqrmod() */
1619ebfedea0SLionel Sambuc #endif
1620ebfedea0SLionel Sambuc
1621ebfedea0SLionel Sambuc /* }}} */
1622ebfedea0SLionel Sambuc
1623ebfedea0SLionel Sambuc /* {{{ mp_exptmod(a, b, m, c) */
1624ebfedea0SLionel Sambuc
1625ebfedea0SLionel Sambuc /*
1626ebfedea0SLionel Sambuc mp_exptmod(a, b, m, c)
1627ebfedea0SLionel Sambuc
1628ebfedea0SLionel Sambuc Compute c = (a ** b) mod m. Uses a standard square-and-multiply
1629ebfedea0SLionel Sambuc method with modular reductions at each step. (This is basically the
1630ebfedea0SLionel Sambuc same code as mp_expt(), except for the addition of the reductions)
1631ebfedea0SLionel Sambuc
1632ebfedea0SLionel Sambuc The modular reductions are done using Barrett's algorithm (see
1633ebfedea0SLionel Sambuc s_mp_reduce() below for details)
1634ebfedea0SLionel Sambuc */
1635ebfedea0SLionel Sambuc
mp_exptmod(mp_int * a,mp_int * b,mp_int * m,mp_int * c)1636ebfedea0SLionel Sambuc mp_err mp_exptmod(mp_int *a, mp_int *b, mp_int *m, mp_int *c)
1637ebfedea0SLionel Sambuc {
1638ebfedea0SLionel Sambuc mp_int s, x, mu;
1639ebfedea0SLionel Sambuc mp_err res;
1640ebfedea0SLionel Sambuc mp_digit d, *db = DIGITS(b);
1641ebfedea0SLionel Sambuc mp_size ub = USED(b);
1642ebfedea0SLionel Sambuc int dig, bit;
1643ebfedea0SLionel Sambuc
1644ebfedea0SLionel Sambuc ARGCHK(a != NULL && b != NULL && c != NULL, MP_BADARG);
1645ebfedea0SLionel Sambuc
1646ebfedea0SLionel Sambuc if(mp_cmp_z(b) < 0 || mp_cmp_z(m) <= 0)
1647ebfedea0SLionel Sambuc return MP_RANGE;
1648ebfedea0SLionel Sambuc
1649ebfedea0SLionel Sambuc if((res = mp_init(&s)) != MP_OKAY)
1650ebfedea0SLionel Sambuc return res;
1651ebfedea0SLionel Sambuc if((res = mp_init_copy(&x, a)) != MP_OKAY)
1652ebfedea0SLionel Sambuc goto X;
1653ebfedea0SLionel Sambuc if((res = mp_mod(&x, m, &x)) != MP_OKAY ||
1654ebfedea0SLionel Sambuc (res = mp_init(&mu)) != MP_OKAY)
1655ebfedea0SLionel Sambuc goto MU;
1656ebfedea0SLionel Sambuc
1657ebfedea0SLionel Sambuc mp_set(&s, 1);
1658ebfedea0SLionel Sambuc
1659ebfedea0SLionel Sambuc /* mu = b^2k / m */
1660ebfedea0SLionel Sambuc s_mp_add_d(&mu, 1);
1661ebfedea0SLionel Sambuc s_mp_lshd(&mu, 2 * USED(m));
1662ebfedea0SLionel Sambuc if((res = mp_div(&mu, m, &mu, NULL)) != MP_OKAY)
1663ebfedea0SLionel Sambuc goto CLEANUP;
1664ebfedea0SLionel Sambuc
1665ebfedea0SLionel Sambuc /* Loop over digits of b in ascending order, except highest order */
1666ebfedea0SLionel Sambuc for(dig = 0; dig < (ub - 1); dig++) {
1667ebfedea0SLionel Sambuc d = *db++;
1668ebfedea0SLionel Sambuc
1669ebfedea0SLionel Sambuc /* Loop over the bits of the lower-order digits */
1670ebfedea0SLionel Sambuc for(bit = 0; bit < DIGIT_BIT; bit++) {
1671ebfedea0SLionel Sambuc if(d & 1) {
1672ebfedea0SLionel Sambuc if((res = s_mp_mul(&s, &x)) != MP_OKAY)
1673ebfedea0SLionel Sambuc goto CLEANUP;
1674ebfedea0SLionel Sambuc if((res = s_mp_reduce(&s, m, &mu)) != MP_OKAY)
1675ebfedea0SLionel Sambuc goto CLEANUP;
1676ebfedea0SLionel Sambuc }
1677ebfedea0SLionel Sambuc
1678ebfedea0SLionel Sambuc d >>= 1;
1679ebfedea0SLionel Sambuc
1680ebfedea0SLionel Sambuc if((res = s_mp_sqr(&x)) != MP_OKAY)
1681ebfedea0SLionel Sambuc goto CLEANUP;
1682ebfedea0SLionel Sambuc if((res = s_mp_reduce(&x, m, &mu)) != MP_OKAY)
1683ebfedea0SLionel Sambuc goto CLEANUP;
1684ebfedea0SLionel Sambuc }
1685ebfedea0SLionel Sambuc }
1686ebfedea0SLionel Sambuc
1687ebfedea0SLionel Sambuc /* Now do the last digit... */
1688ebfedea0SLionel Sambuc d = *db;
1689ebfedea0SLionel Sambuc
1690ebfedea0SLionel Sambuc while(d) {
1691ebfedea0SLionel Sambuc if(d & 1) {
1692ebfedea0SLionel Sambuc if((res = s_mp_mul(&s, &x)) != MP_OKAY)
1693ebfedea0SLionel Sambuc goto CLEANUP;
1694ebfedea0SLionel Sambuc if((res = s_mp_reduce(&s, m, &mu)) != MP_OKAY)
1695ebfedea0SLionel Sambuc goto CLEANUP;
1696ebfedea0SLionel Sambuc }
1697ebfedea0SLionel Sambuc
1698ebfedea0SLionel Sambuc d >>= 1;
1699ebfedea0SLionel Sambuc
1700ebfedea0SLionel Sambuc if((res = s_mp_sqr(&x)) != MP_OKAY)
1701ebfedea0SLionel Sambuc goto CLEANUP;
1702ebfedea0SLionel Sambuc if((res = s_mp_reduce(&x, m, &mu)) != MP_OKAY)
1703ebfedea0SLionel Sambuc goto CLEANUP;
1704ebfedea0SLionel Sambuc }
1705ebfedea0SLionel Sambuc
1706ebfedea0SLionel Sambuc s_mp_exch(&s, c);
1707ebfedea0SLionel Sambuc
1708ebfedea0SLionel Sambuc CLEANUP:
1709ebfedea0SLionel Sambuc mp_clear(&mu);
1710ebfedea0SLionel Sambuc MU:
1711ebfedea0SLionel Sambuc mp_clear(&x);
1712ebfedea0SLionel Sambuc X:
1713ebfedea0SLionel Sambuc mp_clear(&s);
1714ebfedea0SLionel Sambuc
1715ebfedea0SLionel Sambuc return res;
1716ebfedea0SLionel Sambuc
1717ebfedea0SLionel Sambuc } /* end mp_exptmod() */
1718ebfedea0SLionel Sambuc
1719ebfedea0SLionel Sambuc /* }}} */
1720ebfedea0SLionel Sambuc
1721ebfedea0SLionel Sambuc /* {{{ mp_exptmod_d(a, d, m, c) */
1722ebfedea0SLionel Sambuc
mp_exptmod_d(mp_int * a,mp_digit d,mp_int * m,mp_int * c)1723ebfedea0SLionel Sambuc mp_err mp_exptmod_d(mp_int *a, mp_digit d, mp_int *m, mp_int *c)
1724ebfedea0SLionel Sambuc {
1725ebfedea0SLionel Sambuc mp_int s, x;
1726ebfedea0SLionel Sambuc mp_err res;
1727ebfedea0SLionel Sambuc
1728ebfedea0SLionel Sambuc ARGCHK(a != NULL && c != NULL, MP_BADARG);
1729ebfedea0SLionel Sambuc
1730ebfedea0SLionel Sambuc if((res = mp_init(&s)) != MP_OKAY)
1731ebfedea0SLionel Sambuc return res;
1732ebfedea0SLionel Sambuc if((res = mp_init_copy(&x, a)) != MP_OKAY)
1733ebfedea0SLionel Sambuc goto X;
1734ebfedea0SLionel Sambuc
1735ebfedea0SLionel Sambuc mp_set(&s, 1);
1736ebfedea0SLionel Sambuc
1737ebfedea0SLionel Sambuc while(d != 0) {
1738ebfedea0SLionel Sambuc if(d & 1) {
1739ebfedea0SLionel Sambuc if((res = s_mp_mul(&s, &x)) != MP_OKAY ||
1740ebfedea0SLionel Sambuc (res = mp_mod(&s, m, &s)) != MP_OKAY)
1741ebfedea0SLionel Sambuc goto CLEANUP;
1742ebfedea0SLionel Sambuc }
1743ebfedea0SLionel Sambuc
1744ebfedea0SLionel Sambuc d /= 2;
1745ebfedea0SLionel Sambuc
1746ebfedea0SLionel Sambuc if((res = s_mp_sqr(&x)) != MP_OKAY ||
1747ebfedea0SLionel Sambuc (res = mp_mod(&x, m, &x)) != MP_OKAY)
1748ebfedea0SLionel Sambuc goto CLEANUP;
1749ebfedea0SLionel Sambuc }
1750ebfedea0SLionel Sambuc
1751ebfedea0SLionel Sambuc s_mp_exch(&s, c);
1752ebfedea0SLionel Sambuc
1753ebfedea0SLionel Sambuc CLEANUP:
1754ebfedea0SLionel Sambuc mp_clear(&x);
1755ebfedea0SLionel Sambuc X:
1756ebfedea0SLionel Sambuc mp_clear(&s);
1757ebfedea0SLionel Sambuc
1758ebfedea0SLionel Sambuc return res;
1759ebfedea0SLionel Sambuc
1760ebfedea0SLionel Sambuc } /* end mp_exptmod_d() */
1761ebfedea0SLionel Sambuc
1762ebfedea0SLionel Sambuc /* }}} */
1763ebfedea0SLionel Sambuc #endif /* if MP_MODARITH */
1764ebfedea0SLionel Sambuc
1765ebfedea0SLionel Sambuc /* }}} */
1766ebfedea0SLionel Sambuc
1767ebfedea0SLionel Sambuc /*------------------------------------------------------------------------*/
1768ebfedea0SLionel Sambuc /* {{{ Comparison functions */
1769ebfedea0SLionel Sambuc
1770ebfedea0SLionel Sambuc /* {{{ mp_cmp_z(a) */
1771ebfedea0SLionel Sambuc
1772ebfedea0SLionel Sambuc /*
1773ebfedea0SLionel Sambuc mp_cmp_z(a)
1774ebfedea0SLionel Sambuc
1775ebfedea0SLionel Sambuc Compare a <=> 0. Returns <0 if a<0, 0 if a=0, >0 if a>0.
1776ebfedea0SLionel Sambuc */
1777ebfedea0SLionel Sambuc
mp_cmp_z(mp_int * a)1778ebfedea0SLionel Sambuc int mp_cmp_z(mp_int *a)
1779ebfedea0SLionel Sambuc {
1780ebfedea0SLionel Sambuc if(SIGN(a) == MP_NEG)
1781ebfedea0SLionel Sambuc return MP_LT;
1782ebfedea0SLionel Sambuc else if(USED(a) == 1 && DIGIT(a, 0) == 0)
1783ebfedea0SLionel Sambuc return MP_EQ;
1784ebfedea0SLionel Sambuc else
1785ebfedea0SLionel Sambuc return MP_GT;
1786ebfedea0SLionel Sambuc
1787ebfedea0SLionel Sambuc } /* end mp_cmp_z() */
1788ebfedea0SLionel Sambuc
1789ebfedea0SLionel Sambuc /* }}} */
1790ebfedea0SLionel Sambuc
1791ebfedea0SLionel Sambuc /* {{{ mp_cmp_d(a, d) */
1792ebfedea0SLionel Sambuc
1793ebfedea0SLionel Sambuc /*
1794ebfedea0SLionel Sambuc mp_cmp_d(a, d)
1795ebfedea0SLionel Sambuc
1796ebfedea0SLionel Sambuc Compare a <=> d. Returns <0 if a<d, 0 if a=d, >0 if a>d
1797ebfedea0SLionel Sambuc */
1798ebfedea0SLionel Sambuc
mp_cmp_d(mp_int * a,mp_digit d)1799ebfedea0SLionel Sambuc int mp_cmp_d(mp_int *a, mp_digit d)
1800ebfedea0SLionel Sambuc {
1801ebfedea0SLionel Sambuc ARGCHK(a != NULL, MP_EQ);
1802ebfedea0SLionel Sambuc
1803ebfedea0SLionel Sambuc if(SIGN(a) == MP_NEG)
1804ebfedea0SLionel Sambuc return MP_LT;
1805ebfedea0SLionel Sambuc
1806ebfedea0SLionel Sambuc return s_mp_cmp_d(a, d);
1807ebfedea0SLionel Sambuc
1808ebfedea0SLionel Sambuc } /* end mp_cmp_d() */
1809ebfedea0SLionel Sambuc
1810ebfedea0SLionel Sambuc /* }}} */
1811ebfedea0SLionel Sambuc
1812ebfedea0SLionel Sambuc /* {{{ mp_cmp(a, b) */
1813ebfedea0SLionel Sambuc
mp_cmp(mp_int * a,mp_int * b)1814ebfedea0SLionel Sambuc int mp_cmp(mp_int *a, mp_int *b)
1815ebfedea0SLionel Sambuc {
1816ebfedea0SLionel Sambuc ARGCHK(a != NULL && b != NULL, MP_EQ);
1817ebfedea0SLionel Sambuc
1818ebfedea0SLionel Sambuc if(SIGN(a) == SIGN(b)) {
1819ebfedea0SLionel Sambuc int mag;
1820ebfedea0SLionel Sambuc
1821ebfedea0SLionel Sambuc if((mag = s_mp_cmp(a, b)) == MP_EQ)
1822ebfedea0SLionel Sambuc return MP_EQ;
1823ebfedea0SLionel Sambuc
1824ebfedea0SLionel Sambuc if(SIGN(a) == MP_ZPOS)
1825ebfedea0SLionel Sambuc return mag;
1826ebfedea0SLionel Sambuc else
1827ebfedea0SLionel Sambuc return -mag;
1828ebfedea0SLionel Sambuc
1829ebfedea0SLionel Sambuc } else if(SIGN(a) == MP_ZPOS) {
1830ebfedea0SLionel Sambuc return MP_GT;
1831ebfedea0SLionel Sambuc } else {
1832ebfedea0SLionel Sambuc return MP_LT;
1833ebfedea0SLionel Sambuc }
1834ebfedea0SLionel Sambuc
1835ebfedea0SLionel Sambuc } /* end mp_cmp() */
1836ebfedea0SLionel Sambuc
1837ebfedea0SLionel Sambuc /* }}} */
1838ebfedea0SLionel Sambuc
1839ebfedea0SLionel Sambuc /* {{{ mp_cmp_mag(a, b) */
1840ebfedea0SLionel Sambuc
1841ebfedea0SLionel Sambuc /*
1842ebfedea0SLionel Sambuc mp_cmp_mag(a, b)
1843ebfedea0SLionel Sambuc
1844ebfedea0SLionel Sambuc Compares |a| <=> |b|, and returns an appropriate comparison result
1845ebfedea0SLionel Sambuc */
1846ebfedea0SLionel Sambuc
mp_cmp_mag(mp_int * a,mp_int * b)1847ebfedea0SLionel Sambuc int mp_cmp_mag(mp_int *a, mp_int *b)
1848ebfedea0SLionel Sambuc {
1849ebfedea0SLionel Sambuc ARGCHK(a != NULL && b != NULL, MP_EQ);
1850ebfedea0SLionel Sambuc
1851ebfedea0SLionel Sambuc return s_mp_cmp(a, b);
1852ebfedea0SLionel Sambuc
1853ebfedea0SLionel Sambuc } /* end mp_cmp_mag() */
1854ebfedea0SLionel Sambuc
1855ebfedea0SLionel Sambuc /* }}} */
1856ebfedea0SLionel Sambuc
1857ebfedea0SLionel Sambuc /* {{{ mp_cmp_int(a, z) */
1858ebfedea0SLionel Sambuc
1859ebfedea0SLionel Sambuc /*
1860ebfedea0SLionel Sambuc This just converts z to an mp_int, and uses the existing comparison
1861ebfedea0SLionel Sambuc routines. This is sort of inefficient, but it's not clear to me how
1862ebfedea0SLionel Sambuc frequently this wil get used anyway. For small positive constants,
1863ebfedea0SLionel Sambuc you can always use mp_cmp_d(), and for zero, there is mp_cmp_z().
1864ebfedea0SLionel Sambuc */
mp_cmp_int(mp_int * a,long z)1865ebfedea0SLionel Sambuc int mp_cmp_int(mp_int *a, long z)
1866ebfedea0SLionel Sambuc {
1867ebfedea0SLionel Sambuc mp_int tmp;
1868ebfedea0SLionel Sambuc int out;
1869ebfedea0SLionel Sambuc
1870ebfedea0SLionel Sambuc ARGCHK(a != NULL, MP_EQ);
1871ebfedea0SLionel Sambuc
1872ebfedea0SLionel Sambuc mp_init(&tmp); mp_set_int(&tmp, z);
1873ebfedea0SLionel Sambuc out = mp_cmp(a, &tmp);
1874ebfedea0SLionel Sambuc mp_clear(&tmp);
1875ebfedea0SLionel Sambuc
1876ebfedea0SLionel Sambuc return out;
1877ebfedea0SLionel Sambuc
1878ebfedea0SLionel Sambuc } /* end mp_cmp_int() */
1879ebfedea0SLionel Sambuc
1880ebfedea0SLionel Sambuc /* }}} */
1881ebfedea0SLionel Sambuc
1882ebfedea0SLionel Sambuc /* {{{ mp_isodd(a) */
1883ebfedea0SLionel Sambuc
1884ebfedea0SLionel Sambuc /*
1885ebfedea0SLionel Sambuc mp_isodd(a)
1886ebfedea0SLionel Sambuc
1887ebfedea0SLionel Sambuc Returns a true (non-zero) value if a is odd, false (zero) otherwise.
1888ebfedea0SLionel Sambuc */
mp_isodd(mp_int * a)1889ebfedea0SLionel Sambuc int mp_isodd(mp_int *a)
1890ebfedea0SLionel Sambuc {
1891ebfedea0SLionel Sambuc ARGCHK(a != NULL, 0);
1892ebfedea0SLionel Sambuc
1893ebfedea0SLionel Sambuc return (DIGIT(a, 0) & 1);
1894ebfedea0SLionel Sambuc
1895ebfedea0SLionel Sambuc } /* end mp_isodd() */
1896ebfedea0SLionel Sambuc
1897ebfedea0SLionel Sambuc /* }}} */
1898ebfedea0SLionel Sambuc
1899ebfedea0SLionel Sambuc /* {{{ mp_iseven(a) */
1900ebfedea0SLionel Sambuc
mp_iseven(mp_int * a)1901ebfedea0SLionel Sambuc int mp_iseven(mp_int *a)
1902ebfedea0SLionel Sambuc {
1903ebfedea0SLionel Sambuc return !mp_isodd(a);
1904ebfedea0SLionel Sambuc
1905ebfedea0SLionel Sambuc } /* end mp_iseven() */
1906ebfedea0SLionel Sambuc
1907ebfedea0SLionel Sambuc /* }}} */
1908ebfedea0SLionel Sambuc
1909ebfedea0SLionel Sambuc /* }}} */
1910ebfedea0SLionel Sambuc
1911ebfedea0SLionel Sambuc /*------------------------------------------------------------------------*/
1912ebfedea0SLionel Sambuc /* {{{ Number theoretic functions */
1913ebfedea0SLionel Sambuc
1914ebfedea0SLionel Sambuc #if MP_NUMTH
1915ebfedea0SLionel Sambuc /* {{{ mp_gcd(a, b, c) */
1916ebfedea0SLionel Sambuc
1917ebfedea0SLionel Sambuc /*
1918ebfedea0SLionel Sambuc Like the old mp_gcd() function, except computes the GCD using the
1919ebfedea0SLionel Sambuc binary algorithm due to Josef Stein in 1961 (via Knuth).
1920ebfedea0SLionel Sambuc */
mp_gcd(mp_int * a,mp_int * b,mp_int * c)1921ebfedea0SLionel Sambuc mp_err mp_gcd(mp_int *a, mp_int *b, mp_int *c)
1922ebfedea0SLionel Sambuc {
1923ebfedea0SLionel Sambuc mp_err res;
1924ebfedea0SLionel Sambuc mp_int u, v, t;
1925ebfedea0SLionel Sambuc mp_size k = 0;
1926ebfedea0SLionel Sambuc
1927ebfedea0SLionel Sambuc ARGCHK(a != NULL && b != NULL && c != NULL, MP_BADARG);
1928ebfedea0SLionel Sambuc
1929ebfedea0SLionel Sambuc if(mp_cmp_z(a) == MP_EQ && mp_cmp_z(b) == MP_EQ)
1930ebfedea0SLionel Sambuc return MP_RANGE;
1931ebfedea0SLionel Sambuc if(mp_cmp_z(a) == MP_EQ) {
1932ebfedea0SLionel Sambuc return mp_copy(b, c);
1933ebfedea0SLionel Sambuc } else if(mp_cmp_z(b) == MP_EQ) {
1934ebfedea0SLionel Sambuc return mp_copy(a, c);
1935ebfedea0SLionel Sambuc }
1936ebfedea0SLionel Sambuc
1937ebfedea0SLionel Sambuc if((res = mp_init(&t)) != MP_OKAY)
1938ebfedea0SLionel Sambuc return res;
1939ebfedea0SLionel Sambuc if((res = mp_init_copy(&u, a)) != MP_OKAY)
1940ebfedea0SLionel Sambuc goto U;
1941ebfedea0SLionel Sambuc if((res = mp_init_copy(&v, b)) != MP_OKAY)
1942ebfedea0SLionel Sambuc goto V;
1943ebfedea0SLionel Sambuc
1944ebfedea0SLionel Sambuc SIGN(&u) = MP_ZPOS;
1945ebfedea0SLionel Sambuc SIGN(&v) = MP_ZPOS;
1946ebfedea0SLionel Sambuc
1947ebfedea0SLionel Sambuc /* Divide out common factors of 2 until at least 1 of a, b is even */
1948ebfedea0SLionel Sambuc while(mp_iseven(&u) && mp_iseven(&v)) {
1949ebfedea0SLionel Sambuc s_mp_div_2(&u);
1950ebfedea0SLionel Sambuc s_mp_div_2(&v);
1951ebfedea0SLionel Sambuc ++k;
1952ebfedea0SLionel Sambuc }
1953ebfedea0SLionel Sambuc
1954ebfedea0SLionel Sambuc /* Initialize t */
1955ebfedea0SLionel Sambuc if(mp_isodd(&u)) {
1956ebfedea0SLionel Sambuc if((res = mp_copy(&v, &t)) != MP_OKAY)
1957ebfedea0SLionel Sambuc goto CLEANUP;
1958ebfedea0SLionel Sambuc
1959ebfedea0SLionel Sambuc /* t = -v */
1960ebfedea0SLionel Sambuc if(SIGN(&v) == MP_ZPOS)
1961ebfedea0SLionel Sambuc SIGN(&t) = MP_NEG;
1962ebfedea0SLionel Sambuc else
1963ebfedea0SLionel Sambuc SIGN(&t) = MP_ZPOS;
1964ebfedea0SLionel Sambuc
1965ebfedea0SLionel Sambuc } else {
1966ebfedea0SLionel Sambuc if((res = mp_copy(&u, &t)) != MP_OKAY)
1967ebfedea0SLionel Sambuc goto CLEANUP;
1968ebfedea0SLionel Sambuc
1969ebfedea0SLionel Sambuc }
1970ebfedea0SLionel Sambuc
1971ebfedea0SLionel Sambuc for(;;) {
1972ebfedea0SLionel Sambuc while(mp_iseven(&t)) {
1973ebfedea0SLionel Sambuc s_mp_div_2(&t);
1974ebfedea0SLionel Sambuc }
1975ebfedea0SLionel Sambuc
1976ebfedea0SLionel Sambuc if(mp_cmp_z(&t) == MP_GT) {
1977ebfedea0SLionel Sambuc if((res = mp_copy(&t, &u)) != MP_OKAY)
1978ebfedea0SLionel Sambuc goto CLEANUP;
1979ebfedea0SLionel Sambuc
1980ebfedea0SLionel Sambuc } else {
1981ebfedea0SLionel Sambuc if((res = mp_copy(&t, &v)) != MP_OKAY)
1982ebfedea0SLionel Sambuc goto CLEANUP;
1983ebfedea0SLionel Sambuc
1984ebfedea0SLionel Sambuc /* v = -t */
1985ebfedea0SLionel Sambuc if(SIGN(&t) == MP_ZPOS)
1986ebfedea0SLionel Sambuc SIGN(&v) = MP_NEG;
1987ebfedea0SLionel Sambuc else
1988ebfedea0SLionel Sambuc SIGN(&v) = MP_ZPOS;
1989ebfedea0SLionel Sambuc }
1990ebfedea0SLionel Sambuc
1991ebfedea0SLionel Sambuc if((res = mp_sub(&u, &v, &t)) != MP_OKAY)
1992ebfedea0SLionel Sambuc goto CLEANUP;
1993ebfedea0SLionel Sambuc
1994ebfedea0SLionel Sambuc if(s_mp_cmp_d(&t, 0) == MP_EQ)
1995ebfedea0SLionel Sambuc break;
1996ebfedea0SLionel Sambuc }
1997ebfedea0SLionel Sambuc
1998ebfedea0SLionel Sambuc s_mp_2expt(&v, k); /* v = 2^k */
1999ebfedea0SLionel Sambuc res = mp_mul(&u, &v, c); /* c = u * v */
2000ebfedea0SLionel Sambuc
2001ebfedea0SLionel Sambuc CLEANUP:
2002ebfedea0SLionel Sambuc mp_clear(&v);
2003ebfedea0SLionel Sambuc V:
2004ebfedea0SLionel Sambuc mp_clear(&u);
2005ebfedea0SLionel Sambuc U:
2006ebfedea0SLionel Sambuc mp_clear(&t);
2007ebfedea0SLionel Sambuc
2008ebfedea0SLionel Sambuc return res;
2009ebfedea0SLionel Sambuc
2010ebfedea0SLionel Sambuc } /* end mp_bgcd() */
2011ebfedea0SLionel Sambuc
2012ebfedea0SLionel Sambuc /* }}} */
2013ebfedea0SLionel Sambuc
2014ebfedea0SLionel Sambuc /* {{{ mp_lcm(a, b, c) */
2015ebfedea0SLionel Sambuc
2016ebfedea0SLionel Sambuc /* We compute the least common multiple using the rule:
2017ebfedea0SLionel Sambuc
2018ebfedea0SLionel Sambuc ab = [a, b](a, b)
2019ebfedea0SLionel Sambuc
2020ebfedea0SLionel Sambuc ... by computing the product, and dividing out the gcd.
2021ebfedea0SLionel Sambuc */
2022ebfedea0SLionel Sambuc
mp_lcm(mp_int * a,mp_int * b,mp_int * c)2023ebfedea0SLionel Sambuc mp_err mp_lcm(mp_int *a, mp_int *b, mp_int *c)
2024ebfedea0SLionel Sambuc {
2025ebfedea0SLionel Sambuc mp_int gcd, prod;
2026ebfedea0SLionel Sambuc mp_err res;
2027ebfedea0SLionel Sambuc
2028ebfedea0SLionel Sambuc ARGCHK(a != NULL && b != NULL && c != NULL, MP_BADARG);
2029ebfedea0SLionel Sambuc
2030ebfedea0SLionel Sambuc /* Set up temporaries */
2031ebfedea0SLionel Sambuc if((res = mp_init(&gcd)) != MP_OKAY)
2032ebfedea0SLionel Sambuc return res;
2033ebfedea0SLionel Sambuc if((res = mp_init(&prod)) != MP_OKAY)
2034ebfedea0SLionel Sambuc goto GCD;
2035ebfedea0SLionel Sambuc
2036ebfedea0SLionel Sambuc if((res = mp_mul(a, b, &prod)) != MP_OKAY)
2037ebfedea0SLionel Sambuc goto CLEANUP;
2038ebfedea0SLionel Sambuc if((res = mp_gcd(a, b, &gcd)) != MP_OKAY)
2039ebfedea0SLionel Sambuc goto CLEANUP;
2040ebfedea0SLionel Sambuc
2041ebfedea0SLionel Sambuc res = mp_div(&prod, &gcd, c, NULL);
2042ebfedea0SLionel Sambuc
2043ebfedea0SLionel Sambuc CLEANUP:
2044ebfedea0SLionel Sambuc mp_clear(&prod);
2045ebfedea0SLionel Sambuc GCD:
2046ebfedea0SLionel Sambuc mp_clear(&gcd);
2047ebfedea0SLionel Sambuc
2048ebfedea0SLionel Sambuc return res;
2049ebfedea0SLionel Sambuc
2050ebfedea0SLionel Sambuc } /* end mp_lcm() */
2051ebfedea0SLionel Sambuc
2052ebfedea0SLionel Sambuc /* }}} */
2053ebfedea0SLionel Sambuc
2054ebfedea0SLionel Sambuc /* {{{ mp_xgcd(a, b, g, x, y) */
2055ebfedea0SLionel Sambuc
2056ebfedea0SLionel Sambuc /*
2057ebfedea0SLionel Sambuc mp_xgcd(a, b, g, x, y)
2058ebfedea0SLionel Sambuc
2059ebfedea0SLionel Sambuc Compute g = (a, b) and values x and y satisfying Bezout's identity
2060ebfedea0SLionel Sambuc (that is, ax + by = g). This uses the extended binary GCD algorithm
2061ebfedea0SLionel Sambuc based on the Stein algorithm used for mp_gcd()
2062ebfedea0SLionel Sambuc */
2063ebfedea0SLionel Sambuc
mp_xgcd(mp_int * a,mp_int * b,mp_int * g,mp_int * x,mp_int * y)2064ebfedea0SLionel Sambuc mp_err mp_xgcd(mp_int *a, mp_int *b, mp_int *g, mp_int *x, mp_int *y)
2065ebfedea0SLionel Sambuc {
2066ebfedea0SLionel Sambuc mp_int gx, xc, yc, u, v, A, B, C, D;
2067ebfedea0SLionel Sambuc mp_int *clean[9];
2068ebfedea0SLionel Sambuc mp_err res;
2069ebfedea0SLionel Sambuc int last = -1;
2070ebfedea0SLionel Sambuc
2071ebfedea0SLionel Sambuc if(mp_cmp_z(b) == 0)
2072ebfedea0SLionel Sambuc return MP_RANGE;
2073ebfedea0SLionel Sambuc
2074ebfedea0SLionel Sambuc /* Initialize all these variables we need */
2075ebfedea0SLionel Sambuc if((res = mp_init(&u)) != MP_OKAY) goto CLEANUP;
2076ebfedea0SLionel Sambuc clean[++last] = &u;
2077ebfedea0SLionel Sambuc if((res = mp_init(&v)) != MP_OKAY) goto CLEANUP;
2078ebfedea0SLionel Sambuc clean[++last] = &v;
2079ebfedea0SLionel Sambuc if((res = mp_init(&gx)) != MP_OKAY) goto CLEANUP;
2080ebfedea0SLionel Sambuc clean[++last] = &gx;
2081ebfedea0SLionel Sambuc if((res = mp_init(&A)) != MP_OKAY) goto CLEANUP;
2082ebfedea0SLionel Sambuc clean[++last] = &A;
2083ebfedea0SLionel Sambuc if((res = mp_init(&B)) != MP_OKAY) goto CLEANUP;
2084ebfedea0SLionel Sambuc clean[++last] = &B;
2085ebfedea0SLionel Sambuc if((res = mp_init(&C)) != MP_OKAY) goto CLEANUP;
2086ebfedea0SLionel Sambuc clean[++last] = &C;
2087ebfedea0SLionel Sambuc if((res = mp_init(&D)) != MP_OKAY) goto CLEANUP;
2088ebfedea0SLionel Sambuc clean[++last] = &D;
2089ebfedea0SLionel Sambuc if((res = mp_init_copy(&xc, a)) != MP_OKAY) goto CLEANUP;
2090ebfedea0SLionel Sambuc clean[++last] = &xc;
2091ebfedea0SLionel Sambuc mp_abs(&xc, &xc);
2092ebfedea0SLionel Sambuc if((res = mp_init_copy(&yc, b)) != MP_OKAY) goto CLEANUP;
2093ebfedea0SLionel Sambuc clean[++last] = &yc;
2094ebfedea0SLionel Sambuc mp_abs(&yc, &yc);
2095ebfedea0SLionel Sambuc
2096ebfedea0SLionel Sambuc mp_set(&gx, 1);
2097ebfedea0SLionel Sambuc
2098ebfedea0SLionel Sambuc /* Divide by two until at least one of them is even */
2099ebfedea0SLionel Sambuc while(mp_iseven(&xc) && mp_iseven(&yc)) {
2100ebfedea0SLionel Sambuc s_mp_div_2(&xc);
2101ebfedea0SLionel Sambuc s_mp_div_2(&yc);
2102ebfedea0SLionel Sambuc if((res = s_mp_mul_2(&gx)) != MP_OKAY)
2103ebfedea0SLionel Sambuc goto CLEANUP;
2104ebfedea0SLionel Sambuc }
2105ebfedea0SLionel Sambuc
2106ebfedea0SLionel Sambuc mp_copy(&xc, &u);
2107ebfedea0SLionel Sambuc mp_copy(&yc, &v);
2108ebfedea0SLionel Sambuc mp_set(&A, 1); mp_set(&D, 1);
2109ebfedea0SLionel Sambuc
2110ebfedea0SLionel Sambuc /* Loop through binary GCD algorithm */
2111ebfedea0SLionel Sambuc for(;;) {
2112ebfedea0SLionel Sambuc while(mp_iseven(&u)) {
2113ebfedea0SLionel Sambuc s_mp_div_2(&u);
2114ebfedea0SLionel Sambuc
2115ebfedea0SLionel Sambuc if(mp_iseven(&A) && mp_iseven(&B)) {
2116ebfedea0SLionel Sambuc s_mp_div_2(&A); s_mp_div_2(&B);
2117ebfedea0SLionel Sambuc } else {
2118ebfedea0SLionel Sambuc if((res = mp_add(&A, &yc, &A)) != MP_OKAY) goto CLEANUP;
2119ebfedea0SLionel Sambuc s_mp_div_2(&A);
2120ebfedea0SLionel Sambuc if((res = mp_sub(&B, &xc, &B)) != MP_OKAY) goto CLEANUP;
2121ebfedea0SLionel Sambuc s_mp_div_2(&B);
2122ebfedea0SLionel Sambuc }
2123ebfedea0SLionel Sambuc }
2124ebfedea0SLionel Sambuc
2125ebfedea0SLionel Sambuc while(mp_iseven(&v)) {
2126ebfedea0SLionel Sambuc s_mp_div_2(&v);
2127ebfedea0SLionel Sambuc
2128ebfedea0SLionel Sambuc if(mp_iseven(&C) && mp_iseven(&D)) {
2129ebfedea0SLionel Sambuc s_mp_div_2(&C); s_mp_div_2(&D);
2130ebfedea0SLionel Sambuc } else {
2131ebfedea0SLionel Sambuc if((res = mp_add(&C, &yc, &C)) != MP_OKAY) goto CLEANUP;
2132ebfedea0SLionel Sambuc s_mp_div_2(&C);
2133ebfedea0SLionel Sambuc if((res = mp_sub(&D, &xc, &D)) != MP_OKAY) goto CLEANUP;
2134ebfedea0SLionel Sambuc s_mp_div_2(&D);
2135ebfedea0SLionel Sambuc }
2136ebfedea0SLionel Sambuc }
2137ebfedea0SLionel Sambuc
2138ebfedea0SLionel Sambuc if(mp_cmp(&u, &v) >= 0) {
2139ebfedea0SLionel Sambuc if((res = mp_sub(&u, &v, &u)) != MP_OKAY) goto CLEANUP;
2140ebfedea0SLionel Sambuc if((res = mp_sub(&A, &C, &A)) != MP_OKAY) goto CLEANUP;
2141ebfedea0SLionel Sambuc if((res = mp_sub(&B, &D, &B)) != MP_OKAY) goto CLEANUP;
2142ebfedea0SLionel Sambuc
2143ebfedea0SLionel Sambuc } else {
2144ebfedea0SLionel Sambuc if((res = mp_sub(&v, &u, &v)) != MP_OKAY) goto CLEANUP;
2145ebfedea0SLionel Sambuc if((res = mp_sub(&C, &A, &C)) != MP_OKAY) goto CLEANUP;
2146ebfedea0SLionel Sambuc if((res = mp_sub(&D, &B, &D)) != MP_OKAY) goto CLEANUP;
2147ebfedea0SLionel Sambuc
2148ebfedea0SLionel Sambuc }
2149ebfedea0SLionel Sambuc
2150ebfedea0SLionel Sambuc /* If we're done, copy results to output */
2151ebfedea0SLionel Sambuc if(mp_cmp_z(&u) == 0) {
2152ebfedea0SLionel Sambuc if(x)
2153ebfedea0SLionel Sambuc if((res = mp_copy(&C, x)) != MP_OKAY) goto CLEANUP;
2154ebfedea0SLionel Sambuc
2155ebfedea0SLionel Sambuc if(y)
2156ebfedea0SLionel Sambuc if((res = mp_copy(&D, y)) != MP_OKAY) goto CLEANUP;
2157ebfedea0SLionel Sambuc
2158ebfedea0SLionel Sambuc if(g)
2159ebfedea0SLionel Sambuc if((res = mp_mul(&gx, &v, g)) != MP_OKAY) goto CLEANUP;
2160ebfedea0SLionel Sambuc
2161ebfedea0SLionel Sambuc break;
2162ebfedea0SLionel Sambuc }
2163ebfedea0SLionel Sambuc }
2164ebfedea0SLionel Sambuc
2165ebfedea0SLionel Sambuc CLEANUP:
2166ebfedea0SLionel Sambuc while(last >= 0)
2167ebfedea0SLionel Sambuc mp_clear(clean[last--]);
2168ebfedea0SLionel Sambuc
2169ebfedea0SLionel Sambuc return res;
2170ebfedea0SLionel Sambuc
2171ebfedea0SLionel Sambuc } /* end mp_xgcd() */
2172ebfedea0SLionel Sambuc
2173ebfedea0SLionel Sambuc /* }}} */
2174ebfedea0SLionel Sambuc
2175ebfedea0SLionel Sambuc /* {{{ mp_invmod(a, m, c) */
2176ebfedea0SLionel Sambuc
2177ebfedea0SLionel Sambuc /*
2178ebfedea0SLionel Sambuc mp_invmod(a, m, c)
2179ebfedea0SLionel Sambuc
2180ebfedea0SLionel Sambuc Compute c = a^-1 (mod m), if there is an inverse for a (mod m).
2181ebfedea0SLionel Sambuc This is equivalent to the question of whether (a, m) = 1. If not,
2182ebfedea0SLionel Sambuc MP_UNDEF is returned, and there is no inverse.
2183ebfedea0SLionel Sambuc */
2184ebfedea0SLionel Sambuc
mp_invmod(mp_int * a,mp_int * m,mp_int * c)2185ebfedea0SLionel Sambuc mp_err mp_invmod(mp_int *a, mp_int *m, mp_int *c)
2186ebfedea0SLionel Sambuc {
2187ebfedea0SLionel Sambuc mp_int g, x;
2188ebfedea0SLionel Sambuc mp_err res;
2189ebfedea0SLionel Sambuc
2190ebfedea0SLionel Sambuc ARGCHK(a && m && c, MP_BADARG);
2191ebfedea0SLionel Sambuc
2192ebfedea0SLionel Sambuc if(mp_cmp_z(a) == 0 || mp_cmp_z(m) == 0)
2193ebfedea0SLionel Sambuc return MP_RANGE;
2194ebfedea0SLionel Sambuc
2195ebfedea0SLionel Sambuc if((res = mp_init(&g)) != MP_OKAY)
2196ebfedea0SLionel Sambuc return res;
2197ebfedea0SLionel Sambuc if((res = mp_init(&x)) != MP_OKAY)
2198ebfedea0SLionel Sambuc goto X;
2199ebfedea0SLionel Sambuc
2200ebfedea0SLionel Sambuc if((res = mp_xgcd(a, m, &g, &x, NULL)) != MP_OKAY)
2201ebfedea0SLionel Sambuc goto CLEANUP;
2202ebfedea0SLionel Sambuc
2203ebfedea0SLionel Sambuc if(mp_cmp_d(&g, 1) != MP_EQ) {
2204ebfedea0SLionel Sambuc res = MP_UNDEF;
2205ebfedea0SLionel Sambuc goto CLEANUP;
2206ebfedea0SLionel Sambuc }
2207ebfedea0SLionel Sambuc
2208ebfedea0SLionel Sambuc res = mp_mod(&x, m, c);
2209ebfedea0SLionel Sambuc SIGN(c) = SIGN(a);
2210ebfedea0SLionel Sambuc
2211ebfedea0SLionel Sambuc CLEANUP:
2212ebfedea0SLionel Sambuc mp_clear(&x);
2213ebfedea0SLionel Sambuc X:
2214ebfedea0SLionel Sambuc mp_clear(&g);
2215ebfedea0SLionel Sambuc
2216ebfedea0SLionel Sambuc return res;
2217ebfedea0SLionel Sambuc
2218ebfedea0SLionel Sambuc } /* end mp_invmod() */
2219ebfedea0SLionel Sambuc
2220ebfedea0SLionel Sambuc /* }}} */
2221ebfedea0SLionel Sambuc #endif /* if MP_NUMTH */
2222ebfedea0SLionel Sambuc
2223ebfedea0SLionel Sambuc /* }}} */
2224ebfedea0SLionel Sambuc
2225ebfedea0SLionel Sambuc /*------------------------------------------------------------------------*/
2226ebfedea0SLionel Sambuc /* {{{ mp_print(mp, ofp) */
2227ebfedea0SLionel Sambuc
2228ebfedea0SLionel Sambuc #if MP_IOFUNC
2229ebfedea0SLionel Sambuc /*
2230ebfedea0SLionel Sambuc mp_print(mp, ofp)
2231ebfedea0SLionel Sambuc
2232ebfedea0SLionel Sambuc Print a textual representation of the given mp_int on the output
2233ebfedea0SLionel Sambuc stream 'ofp'. Output is generated using the internal radix.
2234ebfedea0SLionel Sambuc */
2235ebfedea0SLionel Sambuc
mp_print(mp_int * mp,FILE * ofp)2236ebfedea0SLionel Sambuc void mp_print(mp_int *mp, FILE *ofp)
2237ebfedea0SLionel Sambuc {
2238ebfedea0SLionel Sambuc int ix;
2239ebfedea0SLionel Sambuc
2240ebfedea0SLionel Sambuc if(mp == NULL || ofp == NULL)
2241ebfedea0SLionel Sambuc return;
2242ebfedea0SLionel Sambuc
2243ebfedea0SLionel Sambuc fputc((SIGN(mp) == MP_NEG) ? '-' : '+', ofp);
2244ebfedea0SLionel Sambuc
2245ebfedea0SLionel Sambuc for(ix = USED(mp) - 1; ix >= 0; ix--) {
2246ebfedea0SLionel Sambuc fprintf(ofp, DIGIT_FMT, DIGIT(mp, ix));
2247ebfedea0SLionel Sambuc }
2248ebfedea0SLionel Sambuc
2249ebfedea0SLionel Sambuc } /* end mp_print() */
2250ebfedea0SLionel Sambuc
2251ebfedea0SLionel Sambuc #endif /* if MP_IOFUNC */
2252ebfedea0SLionel Sambuc
2253ebfedea0SLionel Sambuc /* }}} */
2254ebfedea0SLionel Sambuc
2255ebfedea0SLionel Sambuc /*------------------------------------------------------------------------*/
2256ebfedea0SLionel Sambuc /* {{{ More I/O Functions */
2257ebfedea0SLionel Sambuc
2258ebfedea0SLionel Sambuc /* {{{ mp_read_signed_bin(mp, str, len) */
2259ebfedea0SLionel Sambuc
2260ebfedea0SLionel Sambuc /*
2261ebfedea0SLionel Sambuc mp_read_signed_bin(mp, str, len)
2262ebfedea0SLionel Sambuc
2263ebfedea0SLionel Sambuc Read in a raw value (base 256) into the given mp_int
2264ebfedea0SLionel Sambuc */
2265ebfedea0SLionel Sambuc
mp_read_signed_bin(mp_int * mp,unsigned char * str,int len)2266ebfedea0SLionel Sambuc mp_err mp_read_signed_bin(mp_int *mp, unsigned char *str, int len)
2267ebfedea0SLionel Sambuc {
2268ebfedea0SLionel Sambuc mp_err res;
2269ebfedea0SLionel Sambuc
2270ebfedea0SLionel Sambuc ARGCHK(mp != NULL && str != NULL && len > 0, MP_BADARG);
2271ebfedea0SLionel Sambuc
2272ebfedea0SLionel Sambuc if((res = mp_read_unsigned_bin(mp, str + 1, len - 1)) == MP_OKAY) {
2273ebfedea0SLionel Sambuc /* Get sign from first byte */
2274ebfedea0SLionel Sambuc if(str[0])
2275ebfedea0SLionel Sambuc SIGN(mp) = MP_NEG;
2276ebfedea0SLionel Sambuc else
2277ebfedea0SLionel Sambuc SIGN(mp) = MP_ZPOS;
2278ebfedea0SLionel Sambuc }
2279ebfedea0SLionel Sambuc
2280ebfedea0SLionel Sambuc return res;
2281ebfedea0SLionel Sambuc
2282ebfedea0SLionel Sambuc } /* end mp_read_signed_bin() */
2283ebfedea0SLionel Sambuc
2284ebfedea0SLionel Sambuc /* }}} */
2285ebfedea0SLionel Sambuc
2286ebfedea0SLionel Sambuc /* {{{ mp_signed_bin_size(mp) */
2287ebfedea0SLionel Sambuc
mp_signed_bin_size(mp_int * mp)2288ebfedea0SLionel Sambuc int mp_signed_bin_size(mp_int *mp)
2289ebfedea0SLionel Sambuc {
2290ebfedea0SLionel Sambuc ARGCHK(mp != NULL, 0);
2291ebfedea0SLionel Sambuc
2292ebfedea0SLionel Sambuc return mp_unsigned_bin_size(mp) + 1;
2293ebfedea0SLionel Sambuc
2294ebfedea0SLionel Sambuc } /* end mp_signed_bin_size() */
2295ebfedea0SLionel Sambuc
2296ebfedea0SLionel Sambuc /* }}} */
2297ebfedea0SLionel Sambuc
2298ebfedea0SLionel Sambuc /* {{{ mp_to_signed_bin(mp, str) */
2299ebfedea0SLionel Sambuc
mp_to_signed_bin(mp_int * mp,unsigned char * str)2300ebfedea0SLionel Sambuc mp_err mp_to_signed_bin(mp_int *mp, unsigned char *str)
2301ebfedea0SLionel Sambuc {
2302ebfedea0SLionel Sambuc ARGCHK(mp != NULL && str != NULL, MP_BADARG);
2303ebfedea0SLionel Sambuc
2304ebfedea0SLionel Sambuc /* Caller responsible for allocating enough memory (use mp_raw_size(mp)) */
2305ebfedea0SLionel Sambuc str[0] = (char)SIGN(mp);
2306ebfedea0SLionel Sambuc
2307ebfedea0SLionel Sambuc return mp_to_unsigned_bin(mp, str + 1);
2308ebfedea0SLionel Sambuc
2309ebfedea0SLionel Sambuc } /* end mp_to_signed_bin() */
2310ebfedea0SLionel Sambuc
2311ebfedea0SLionel Sambuc /* }}} */
2312ebfedea0SLionel Sambuc
2313ebfedea0SLionel Sambuc /* {{{ mp_read_unsigned_bin(mp, str, len) */
2314ebfedea0SLionel Sambuc
2315ebfedea0SLionel Sambuc /*
2316ebfedea0SLionel Sambuc mp_read_unsigned_bin(mp, str, len)
2317ebfedea0SLionel Sambuc
2318ebfedea0SLionel Sambuc Read in an unsigned value (base 256) into the given mp_int
2319ebfedea0SLionel Sambuc */
2320ebfedea0SLionel Sambuc
mp_read_unsigned_bin(mp_int * mp,unsigned char * str,int len)2321ebfedea0SLionel Sambuc mp_err mp_read_unsigned_bin(mp_int *mp, unsigned char *str, int len)
2322ebfedea0SLionel Sambuc {
2323ebfedea0SLionel Sambuc int ix;
2324ebfedea0SLionel Sambuc mp_err res;
2325ebfedea0SLionel Sambuc
2326ebfedea0SLionel Sambuc ARGCHK(mp != NULL && str != NULL && len > 0, MP_BADARG);
2327ebfedea0SLionel Sambuc
2328ebfedea0SLionel Sambuc mp_zero(mp);
2329ebfedea0SLionel Sambuc
2330ebfedea0SLionel Sambuc for(ix = 0; ix < len; ix++) {
2331ebfedea0SLionel Sambuc if((res = s_mp_mul_2d(mp, CHAR_BIT)) != MP_OKAY)
2332ebfedea0SLionel Sambuc return res;
2333ebfedea0SLionel Sambuc
2334ebfedea0SLionel Sambuc if((res = mp_add_d(mp, str[ix], mp)) != MP_OKAY)
2335ebfedea0SLionel Sambuc return res;
2336ebfedea0SLionel Sambuc }
2337ebfedea0SLionel Sambuc
2338ebfedea0SLionel Sambuc return MP_OKAY;
2339ebfedea0SLionel Sambuc
2340ebfedea0SLionel Sambuc } /* end mp_read_unsigned_bin() */
2341ebfedea0SLionel Sambuc
2342ebfedea0SLionel Sambuc /* }}} */
2343ebfedea0SLionel Sambuc
2344ebfedea0SLionel Sambuc /* {{{ mp_unsigned_bin_size(mp) */
2345ebfedea0SLionel Sambuc
mp_unsigned_bin_size(mp_int * mp)2346ebfedea0SLionel Sambuc int mp_unsigned_bin_size(mp_int *mp)
2347ebfedea0SLionel Sambuc {
2348ebfedea0SLionel Sambuc mp_digit topdig;
2349ebfedea0SLionel Sambuc int count;
2350ebfedea0SLionel Sambuc
2351ebfedea0SLionel Sambuc ARGCHK(mp != NULL, 0);
2352ebfedea0SLionel Sambuc
2353ebfedea0SLionel Sambuc /* Special case for the value zero */
2354ebfedea0SLionel Sambuc if(USED(mp) == 1 && DIGIT(mp, 0) == 0)
2355ebfedea0SLionel Sambuc return 1;
2356ebfedea0SLionel Sambuc
2357ebfedea0SLionel Sambuc count = (USED(mp) - 1) * sizeof(mp_digit);
2358ebfedea0SLionel Sambuc topdig = DIGIT(mp, USED(mp) - 1);
2359ebfedea0SLionel Sambuc
2360ebfedea0SLionel Sambuc while(topdig != 0) {
2361ebfedea0SLionel Sambuc ++count;
2362ebfedea0SLionel Sambuc topdig >>= CHAR_BIT;
2363ebfedea0SLionel Sambuc }
2364ebfedea0SLionel Sambuc
2365ebfedea0SLionel Sambuc return count;
2366ebfedea0SLionel Sambuc
2367ebfedea0SLionel Sambuc } /* end mp_unsigned_bin_size() */
2368ebfedea0SLionel Sambuc
2369ebfedea0SLionel Sambuc /* }}} */
2370ebfedea0SLionel Sambuc
2371ebfedea0SLionel Sambuc /* {{{ mp_to_unsigned_bin(mp, str) */
2372ebfedea0SLionel Sambuc
mp_to_unsigned_bin(mp_int * mp,unsigned char * str)2373ebfedea0SLionel Sambuc mp_err mp_to_unsigned_bin(mp_int *mp, unsigned char *str)
2374ebfedea0SLionel Sambuc {
2375ebfedea0SLionel Sambuc mp_digit *dp, *end, d;
2376ebfedea0SLionel Sambuc unsigned char *spos;
2377ebfedea0SLionel Sambuc
2378ebfedea0SLionel Sambuc ARGCHK(mp != NULL && str != NULL, MP_BADARG);
2379ebfedea0SLionel Sambuc
2380ebfedea0SLionel Sambuc dp = DIGITS(mp);
2381ebfedea0SLionel Sambuc end = dp + USED(mp) - 1;
2382ebfedea0SLionel Sambuc spos = str;
2383ebfedea0SLionel Sambuc
2384ebfedea0SLionel Sambuc /* Special case for zero, quick test */
2385ebfedea0SLionel Sambuc if(dp == end && *dp == 0) {
2386ebfedea0SLionel Sambuc *str = '\0';
2387ebfedea0SLionel Sambuc return MP_OKAY;
2388ebfedea0SLionel Sambuc }
2389ebfedea0SLionel Sambuc
2390ebfedea0SLionel Sambuc /* Generate digits in reverse order */
2391ebfedea0SLionel Sambuc while(dp < end) {
2392ebfedea0SLionel Sambuc int ix;
2393ebfedea0SLionel Sambuc
2394ebfedea0SLionel Sambuc d = *dp;
2395ebfedea0SLionel Sambuc for(ix = 0; ix < sizeof(mp_digit); ++ix) {
2396ebfedea0SLionel Sambuc *spos = d & UCHAR_MAX;
2397ebfedea0SLionel Sambuc d >>= CHAR_BIT;
2398ebfedea0SLionel Sambuc ++spos;
2399ebfedea0SLionel Sambuc }
2400ebfedea0SLionel Sambuc
2401ebfedea0SLionel Sambuc ++dp;
2402ebfedea0SLionel Sambuc }
2403ebfedea0SLionel Sambuc
2404ebfedea0SLionel Sambuc /* Now handle last digit specially, high order zeroes are not written */
2405ebfedea0SLionel Sambuc d = *end;
2406ebfedea0SLionel Sambuc while(d != 0) {
2407ebfedea0SLionel Sambuc *spos = d & UCHAR_MAX;
2408ebfedea0SLionel Sambuc d >>= CHAR_BIT;
2409ebfedea0SLionel Sambuc ++spos;
2410ebfedea0SLionel Sambuc }
2411ebfedea0SLionel Sambuc
2412ebfedea0SLionel Sambuc /* Reverse everything to get digits in the correct order */
2413ebfedea0SLionel Sambuc while(--spos > str) {
2414ebfedea0SLionel Sambuc unsigned char t = *str;
2415ebfedea0SLionel Sambuc *str = *spos;
2416ebfedea0SLionel Sambuc *spos = t;
2417ebfedea0SLionel Sambuc
2418ebfedea0SLionel Sambuc ++str;
2419ebfedea0SLionel Sambuc }
2420ebfedea0SLionel Sambuc
2421ebfedea0SLionel Sambuc return MP_OKAY;
2422ebfedea0SLionel Sambuc
2423ebfedea0SLionel Sambuc } /* end mp_to_unsigned_bin() */
2424ebfedea0SLionel Sambuc
2425ebfedea0SLionel Sambuc /* }}} */
2426ebfedea0SLionel Sambuc
2427ebfedea0SLionel Sambuc /* {{{ mp_count_bits(mp) */
2428ebfedea0SLionel Sambuc
mp_count_bits(mp_int * mp)2429ebfedea0SLionel Sambuc int mp_count_bits(mp_int *mp)
2430ebfedea0SLionel Sambuc {
2431ebfedea0SLionel Sambuc int len;
2432ebfedea0SLionel Sambuc mp_digit d;
2433ebfedea0SLionel Sambuc
2434ebfedea0SLionel Sambuc ARGCHK(mp != NULL, MP_BADARG);
2435ebfedea0SLionel Sambuc
2436ebfedea0SLionel Sambuc len = DIGIT_BIT * (USED(mp) - 1);
2437ebfedea0SLionel Sambuc d = DIGIT(mp, USED(mp) - 1);
2438ebfedea0SLionel Sambuc
2439ebfedea0SLionel Sambuc while(d != 0) {
2440ebfedea0SLionel Sambuc ++len;
2441ebfedea0SLionel Sambuc d >>= 1;
2442ebfedea0SLionel Sambuc }
2443ebfedea0SLionel Sambuc
2444ebfedea0SLionel Sambuc return len;
2445ebfedea0SLionel Sambuc
2446ebfedea0SLionel Sambuc } /* end mp_count_bits() */
2447ebfedea0SLionel Sambuc
2448ebfedea0SLionel Sambuc /* }}} */
2449ebfedea0SLionel Sambuc
2450ebfedea0SLionel Sambuc /* {{{ mp_read_radix(mp, str, radix) */
2451ebfedea0SLionel Sambuc
2452ebfedea0SLionel Sambuc /*
2453ebfedea0SLionel Sambuc mp_read_radix(mp, str, radix)
2454ebfedea0SLionel Sambuc
2455ebfedea0SLionel Sambuc Read an integer from the given string, and set mp to the resulting
2456ebfedea0SLionel Sambuc value. The input is presumed to be in base 10. Leading non-digit
2457ebfedea0SLionel Sambuc characters are ignored, and the function reads until a non-digit
2458ebfedea0SLionel Sambuc character or the end of the string.
2459ebfedea0SLionel Sambuc */
2460ebfedea0SLionel Sambuc
mp_read_radix(mp_int * mp,unsigned char * str,int radix)2461ebfedea0SLionel Sambuc mp_err mp_read_radix(mp_int *mp, unsigned char *str, int radix)
2462ebfedea0SLionel Sambuc {
2463ebfedea0SLionel Sambuc int ix = 0, val = 0;
2464ebfedea0SLionel Sambuc mp_err res;
2465ebfedea0SLionel Sambuc mp_sign sig = MP_ZPOS;
2466ebfedea0SLionel Sambuc
2467ebfedea0SLionel Sambuc ARGCHK(mp != NULL && str != NULL && radix >= 2 && radix <= MAX_RADIX,
2468ebfedea0SLionel Sambuc MP_BADARG);
2469ebfedea0SLionel Sambuc
2470ebfedea0SLionel Sambuc mp_zero(mp);
2471ebfedea0SLionel Sambuc
2472ebfedea0SLionel Sambuc /* Skip leading non-digit characters until a digit or '-' or '+' */
2473ebfedea0SLionel Sambuc while(str[ix] &&
2474ebfedea0SLionel Sambuc (s_mp_tovalue(str[ix], radix) < 0) &&
2475ebfedea0SLionel Sambuc str[ix] != '-' &&
2476ebfedea0SLionel Sambuc str[ix] != '+') {
2477ebfedea0SLionel Sambuc ++ix;
2478ebfedea0SLionel Sambuc }
2479ebfedea0SLionel Sambuc
2480ebfedea0SLionel Sambuc if(str[ix] == '-') {
2481ebfedea0SLionel Sambuc sig = MP_NEG;
2482ebfedea0SLionel Sambuc ++ix;
2483ebfedea0SLionel Sambuc } else if(str[ix] == '+') {
2484ebfedea0SLionel Sambuc sig = MP_ZPOS; /* this is the default anyway... */
2485ebfedea0SLionel Sambuc ++ix;
2486ebfedea0SLionel Sambuc }
2487ebfedea0SLionel Sambuc
2488ebfedea0SLionel Sambuc while((val = s_mp_tovalue(str[ix], radix)) >= 0) {
2489ebfedea0SLionel Sambuc if((res = s_mp_mul_d(mp, radix)) != MP_OKAY)
2490ebfedea0SLionel Sambuc return res;
2491ebfedea0SLionel Sambuc if((res = s_mp_add_d(mp, val)) != MP_OKAY)
2492ebfedea0SLionel Sambuc return res;
2493ebfedea0SLionel Sambuc ++ix;
2494ebfedea0SLionel Sambuc }
2495ebfedea0SLionel Sambuc
2496ebfedea0SLionel Sambuc if(s_mp_cmp_d(mp, 0) == MP_EQ)
2497ebfedea0SLionel Sambuc SIGN(mp) = MP_ZPOS;
2498ebfedea0SLionel Sambuc else
2499ebfedea0SLionel Sambuc SIGN(mp) = sig;
2500ebfedea0SLionel Sambuc
2501ebfedea0SLionel Sambuc return MP_OKAY;
2502ebfedea0SLionel Sambuc
2503ebfedea0SLionel Sambuc } /* end mp_read_radix() */
2504ebfedea0SLionel Sambuc
2505ebfedea0SLionel Sambuc /* }}} */
2506ebfedea0SLionel Sambuc
2507ebfedea0SLionel Sambuc /* {{{ mp_radix_size(mp, radix) */
2508ebfedea0SLionel Sambuc
mp_radix_size(mp_int * mp,int radix)2509ebfedea0SLionel Sambuc int mp_radix_size(mp_int *mp, int radix)
2510ebfedea0SLionel Sambuc {
2511ebfedea0SLionel Sambuc int len;
2512ebfedea0SLionel Sambuc ARGCHK(mp != NULL, 0);
2513ebfedea0SLionel Sambuc
2514ebfedea0SLionel Sambuc len = s_mp_outlen(mp_count_bits(mp), radix) + 1; /* for NUL terminator */
2515ebfedea0SLionel Sambuc
2516ebfedea0SLionel Sambuc if(mp_cmp_z(mp) < 0)
2517ebfedea0SLionel Sambuc ++len; /* for sign */
2518ebfedea0SLionel Sambuc
2519ebfedea0SLionel Sambuc return len;
2520ebfedea0SLionel Sambuc
2521ebfedea0SLionel Sambuc } /* end mp_radix_size() */
2522ebfedea0SLionel Sambuc
2523ebfedea0SLionel Sambuc /* }}} */
2524ebfedea0SLionel Sambuc
2525ebfedea0SLionel Sambuc /* {{{ mp_value_radix_size(num, qty, radix) */
2526ebfedea0SLionel Sambuc
2527ebfedea0SLionel Sambuc /* num = number of digits
2528ebfedea0SLionel Sambuc qty = number of bits per digit
2529ebfedea0SLionel Sambuc radix = target base
2530ebfedea0SLionel Sambuc
2531ebfedea0SLionel Sambuc Return the number of digits in the specified radix that would be
2532ebfedea0SLionel Sambuc needed to express 'num' digits of 'qty' bits each.
2533ebfedea0SLionel Sambuc */
mp_value_radix_size(int num,int qty,int radix)2534ebfedea0SLionel Sambuc int mp_value_radix_size(int num, int qty, int radix)
2535ebfedea0SLionel Sambuc {
2536ebfedea0SLionel Sambuc ARGCHK(num >= 0 && qty > 0 && radix >= 2 && radix <= MAX_RADIX, 0);
2537ebfedea0SLionel Sambuc
2538ebfedea0SLionel Sambuc return s_mp_outlen(num * qty, radix);
2539ebfedea0SLionel Sambuc
2540ebfedea0SLionel Sambuc } /* end mp_value_radix_size() */
2541ebfedea0SLionel Sambuc
2542ebfedea0SLionel Sambuc /* }}} */
2543ebfedea0SLionel Sambuc
2544ebfedea0SLionel Sambuc /* {{{ mp_toradix(mp, str, radix) */
2545ebfedea0SLionel Sambuc
mp_toradix(mp_int * mp,unsigned char * str,int radix)2546ebfedea0SLionel Sambuc mp_err mp_toradix(mp_int *mp, unsigned char *str, int radix)
2547ebfedea0SLionel Sambuc {
2548ebfedea0SLionel Sambuc int ix, pos = 0;
2549ebfedea0SLionel Sambuc
2550ebfedea0SLionel Sambuc ARGCHK(mp != NULL && str != NULL, MP_BADARG);
2551ebfedea0SLionel Sambuc ARGCHK(radix > 1 && radix <= MAX_RADIX, MP_RANGE);
2552ebfedea0SLionel Sambuc
2553ebfedea0SLionel Sambuc if(mp_cmp_z(mp) == MP_EQ) {
2554ebfedea0SLionel Sambuc str[0] = '0';
2555ebfedea0SLionel Sambuc str[1] = '\0';
2556ebfedea0SLionel Sambuc } else {
2557ebfedea0SLionel Sambuc mp_err res;
2558ebfedea0SLionel Sambuc mp_int tmp;
2559ebfedea0SLionel Sambuc mp_sign sgn;
2560ebfedea0SLionel Sambuc mp_digit rem, rdx = (mp_digit)radix;
2561ebfedea0SLionel Sambuc char ch;
2562ebfedea0SLionel Sambuc
2563ebfedea0SLionel Sambuc if((res = mp_init_copy(&tmp, mp)) != MP_OKAY)
2564ebfedea0SLionel Sambuc return res;
2565ebfedea0SLionel Sambuc
2566ebfedea0SLionel Sambuc /* Save sign for later, and take absolute value */
2567ebfedea0SLionel Sambuc sgn = SIGN(&tmp); SIGN(&tmp) = MP_ZPOS;
2568ebfedea0SLionel Sambuc
2569ebfedea0SLionel Sambuc /* Generate output digits in reverse order */
2570ebfedea0SLionel Sambuc while(mp_cmp_z(&tmp) != 0) {
2571ebfedea0SLionel Sambuc if((res = s_mp_div_d(&tmp, rdx, &rem)) != MP_OKAY) {
2572ebfedea0SLionel Sambuc mp_clear(&tmp);
2573ebfedea0SLionel Sambuc return res;
2574ebfedea0SLionel Sambuc }
2575ebfedea0SLionel Sambuc
2576ebfedea0SLionel Sambuc /* Generate digits, use capital letters */
2577ebfedea0SLionel Sambuc ch = s_mp_todigit(rem, radix, 0);
2578ebfedea0SLionel Sambuc
2579ebfedea0SLionel Sambuc str[pos++] = ch;
2580ebfedea0SLionel Sambuc }
2581ebfedea0SLionel Sambuc
2582ebfedea0SLionel Sambuc /* Add - sign if original value was negative */
2583ebfedea0SLionel Sambuc if(sgn == MP_NEG)
2584ebfedea0SLionel Sambuc str[pos++] = '-';
2585ebfedea0SLionel Sambuc
2586ebfedea0SLionel Sambuc /* Add trailing NUL to end the string */
2587ebfedea0SLionel Sambuc str[pos--] = '\0';
2588ebfedea0SLionel Sambuc
2589ebfedea0SLionel Sambuc /* Reverse the digits and sign indicator */
2590ebfedea0SLionel Sambuc ix = 0;
2591ebfedea0SLionel Sambuc while(ix < pos) {
2592ebfedea0SLionel Sambuc char tmp = str[ix];
2593ebfedea0SLionel Sambuc
2594ebfedea0SLionel Sambuc str[ix] = str[pos];
2595ebfedea0SLionel Sambuc str[pos] = tmp;
2596ebfedea0SLionel Sambuc ++ix;
2597ebfedea0SLionel Sambuc --pos;
2598ebfedea0SLionel Sambuc }
2599ebfedea0SLionel Sambuc
2600ebfedea0SLionel Sambuc mp_clear(&tmp);
2601ebfedea0SLionel Sambuc }
2602ebfedea0SLionel Sambuc
2603ebfedea0SLionel Sambuc return MP_OKAY;
2604ebfedea0SLionel Sambuc
2605ebfedea0SLionel Sambuc } /* end mp_toradix() */
2606ebfedea0SLionel Sambuc
2607ebfedea0SLionel Sambuc /* }}} */
2608ebfedea0SLionel Sambuc
2609ebfedea0SLionel Sambuc /* {{{ mp_char2value(ch, r) */
2610ebfedea0SLionel Sambuc
mp_char2value(char ch,int r)2611ebfedea0SLionel Sambuc int mp_char2value(char ch, int r)
2612ebfedea0SLionel Sambuc {
2613ebfedea0SLionel Sambuc return s_mp_tovalue(ch, r);
2614ebfedea0SLionel Sambuc
2615ebfedea0SLionel Sambuc } /* end mp_tovalue() */
2616ebfedea0SLionel Sambuc
2617ebfedea0SLionel Sambuc /* }}} */
2618ebfedea0SLionel Sambuc
2619ebfedea0SLionel Sambuc /* }}} */
2620ebfedea0SLionel Sambuc
2621ebfedea0SLionel Sambuc /* {{{ mp_strerror(ec) */
2622ebfedea0SLionel Sambuc
2623ebfedea0SLionel Sambuc /*
2624ebfedea0SLionel Sambuc mp_strerror(ec)
2625ebfedea0SLionel Sambuc
2626ebfedea0SLionel Sambuc Return a string describing the meaning of error code 'ec'. The
2627ebfedea0SLionel Sambuc string returned is allocated in static memory, so the caller should
2628ebfedea0SLionel Sambuc not attempt to modify or free the memory associated with this
2629ebfedea0SLionel Sambuc string.
2630ebfedea0SLionel Sambuc */
mp_strerror(mp_err ec)2631ebfedea0SLionel Sambuc const char *mp_strerror(mp_err ec)
2632ebfedea0SLionel Sambuc {
2633ebfedea0SLionel Sambuc int aec = (ec < 0) ? -ec : ec;
2634ebfedea0SLionel Sambuc
2635ebfedea0SLionel Sambuc /* Code values are negative, so the senses of these comparisons
2636ebfedea0SLionel Sambuc are accurate */
2637ebfedea0SLionel Sambuc if(ec < MP_LAST_CODE || ec > MP_OKAY) {
2638ebfedea0SLionel Sambuc return mp_err_string[0]; /* unknown error code */
2639ebfedea0SLionel Sambuc } else {
2640ebfedea0SLionel Sambuc return mp_err_string[aec + 1];
2641ebfedea0SLionel Sambuc }
2642ebfedea0SLionel Sambuc
2643ebfedea0SLionel Sambuc } /* end mp_strerror() */
2644ebfedea0SLionel Sambuc
2645ebfedea0SLionel Sambuc /* }}} */
2646ebfedea0SLionel Sambuc
2647ebfedea0SLionel Sambuc /*========================================================================*/
2648ebfedea0SLionel Sambuc /*------------------------------------------------------------------------*/
2649ebfedea0SLionel Sambuc /* Static function definitions (internal use only) */
2650ebfedea0SLionel Sambuc
2651ebfedea0SLionel Sambuc /* {{{ Memory management */
2652ebfedea0SLionel Sambuc
2653ebfedea0SLionel Sambuc /* {{{ s_mp_grow(mp, min) */
2654ebfedea0SLionel Sambuc
2655ebfedea0SLionel Sambuc /* Make sure there are at least 'min' digits allocated to mp */
s_mp_grow(mp_int * mp,mp_size min)2656ebfedea0SLionel Sambuc mp_err s_mp_grow(mp_int *mp, mp_size min)
2657ebfedea0SLionel Sambuc {
2658ebfedea0SLionel Sambuc if(min > ALLOC(mp)) {
2659ebfedea0SLionel Sambuc mp_digit *tmp;
2660ebfedea0SLionel Sambuc
2661ebfedea0SLionel Sambuc /* Set min to next nearest default precision block size */
2662ebfedea0SLionel Sambuc min = ((min + (s_mp_defprec - 1)) / s_mp_defprec) * s_mp_defprec;
2663ebfedea0SLionel Sambuc
2664ebfedea0SLionel Sambuc if((tmp = s_mp_alloc(min, sizeof(mp_digit))) == NULL)
2665ebfedea0SLionel Sambuc return MP_MEM;
2666ebfedea0SLionel Sambuc
2667ebfedea0SLionel Sambuc s_mp_copy(DIGITS(mp), tmp, USED(mp));
2668ebfedea0SLionel Sambuc
2669ebfedea0SLionel Sambuc #if MP_CRYPTO
2670ebfedea0SLionel Sambuc s_mp_setz(DIGITS(mp), ALLOC(mp));
2671ebfedea0SLionel Sambuc #endif
2672ebfedea0SLionel Sambuc s_mp_free(DIGITS(mp));
2673ebfedea0SLionel Sambuc DIGITS(mp) = tmp;
2674ebfedea0SLionel Sambuc ALLOC(mp) = min;
2675ebfedea0SLionel Sambuc }
2676ebfedea0SLionel Sambuc
2677ebfedea0SLionel Sambuc return MP_OKAY;
2678ebfedea0SLionel Sambuc
2679ebfedea0SLionel Sambuc } /* end s_mp_grow() */
2680ebfedea0SLionel Sambuc
2681ebfedea0SLionel Sambuc /* }}} */
2682ebfedea0SLionel Sambuc
2683ebfedea0SLionel Sambuc /* {{{ s_mp_pad(mp, min) */
2684ebfedea0SLionel Sambuc
2685ebfedea0SLionel Sambuc /* Make sure the used size of mp is at least 'min', growing if needed */
s_mp_pad(mp_int * mp,mp_size min)2686ebfedea0SLionel Sambuc mp_err s_mp_pad(mp_int *mp, mp_size min)
2687ebfedea0SLionel Sambuc {
2688ebfedea0SLionel Sambuc if(min > USED(mp)) {
2689ebfedea0SLionel Sambuc mp_err res;
2690ebfedea0SLionel Sambuc
2691ebfedea0SLionel Sambuc /* Make sure there is room to increase precision */
2692ebfedea0SLionel Sambuc if(min > ALLOC(mp) && (res = s_mp_grow(mp, min)) != MP_OKAY)
2693ebfedea0SLionel Sambuc return res;
2694ebfedea0SLionel Sambuc
2695ebfedea0SLionel Sambuc /* Increase precision; should already be 0-filled */
2696ebfedea0SLionel Sambuc USED(mp) = min;
2697ebfedea0SLionel Sambuc }
2698ebfedea0SLionel Sambuc
2699ebfedea0SLionel Sambuc return MP_OKAY;
2700ebfedea0SLionel Sambuc
2701ebfedea0SLionel Sambuc } /* end s_mp_pad() */
2702ebfedea0SLionel Sambuc
2703ebfedea0SLionel Sambuc /* }}} */
2704ebfedea0SLionel Sambuc
2705ebfedea0SLionel Sambuc /* {{{ s_mp_setz(dp, count) */
2706ebfedea0SLionel Sambuc
2707ebfedea0SLionel Sambuc #if MP_MACRO == 0
2708ebfedea0SLionel Sambuc /* Set 'count' digits pointed to by dp to be zeroes */
s_mp_setz(mp_digit * dp,mp_size count)2709ebfedea0SLionel Sambuc void s_mp_setz(mp_digit *dp, mp_size count)
2710ebfedea0SLionel Sambuc {
2711ebfedea0SLionel Sambuc #if MP_MEMSET == 0
2712ebfedea0SLionel Sambuc int ix;
2713ebfedea0SLionel Sambuc
2714ebfedea0SLionel Sambuc for(ix = 0; ix < count; ix++)
2715ebfedea0SLionel Sambuc dp[ix] = 0;
2716ebfedea0SLionel Sambuc #else
2717ebfedea0SLionel Sambuc memset(dp, 0, count * sizeof(mp_digit));
2718ebfedea0SLionel Sambuc #endif
2719ebfedea0SLionel Sambuc
2720ebfedea0SLionel Sambuc } /* end s_mp_setz() */
2721ebfedea0SLionel Sambuc #endif
2722ebfedea0SLionel Sambuc
2723ebfedea0SLionel Sambuc /* }}} */
2724ebfedea0SLionel Sambuc
2725ebfedea0SLionel Sambuc /* {{{ s_mp_copy(sp, dp, count) */
2726ebfedea0SLionel Sambuc
2727ebfedea0SLionel Sambuc #if MP_MACRO == 0
2728ebfedea0SLionel Sambuc /* Copy 'count' digits from sp to dp */
s_mp_copy(mp_digit * sp,mp_digit * dp,mp_size count)2729ebfedea0SLionel Sambuc void s_mp_copy(mp_digit *sp, mp_digit *dp, mp_size count)
2730ebfedea0SLionel Sambuc {
2731ebfedea0SLionel Sambuc #if MP_MEMCPY == 0
2732ebfedea0SLionel Sambuc int ix;
2733ebfedea0SLionel Sambuc
2734ebfedea0SLionel Sambuc for(ix = 0; ix < count; ix++)
2735ebfedea0SLionel Sambuc dp[ix] = sp[ix];
2736ebfedea0SLionel Sambuc #else
2737ebfedea0SLionel Sambuc memcpy(dp, sp, count * sizeof(mp_digit));
2738ebfedea0SLionel Sambuc #endif
2739ebfedea0SLionel Sambuc
2740ebfedea0SLionel Sambuc } /* end s_mp_copy() */
2741ebfedea0SLionel Sambuc #endif
2742ebfedea0SLionel Sambuc
2743ebfedea0SLionel Sambuc /* }}} */
2744ebfedea0SLionel Sambuc
2745ebfedea0SLionel Sambuc /* {{{ s_mp_alloc(nb, ni) */
2746ebfedea0SLionel Sambuc
2747ebfedea0SLionel Sambuc #if MP_MACRO == 0
2748ebfedea0SLionel Sambuc /* Allocate ni records of nb bytes each, and return a pointer to that */
s_mp_alloc(size_t nb,size_t ni)2749ebfedea0SLionel Sambuc void *s_mp_alloc(size_t nb, size_t ni)
2750ebfedea0SLionel Sambuc {
2751ebfedea0SLionel Sambuc return calloc(nb, ni);
2752ebfedea0SLionel Sambuc
2753ebfedea0SLionel Sambuc } /* end s_mp_alloc() */
2754ebfedea0SLionel Sambuc #endif
2755ebfedea0SLionel Sambuc
2756ebfedea0SLionel Sambuc /* }}} */
2757ebfedea0SLionel Sambuc
2758ebfedea0SLionel Sambuc /* {{{ s_mp_free(ptr) */
2759ebfedea0SLionel Sambuc
2760ebfedea0SLionel Sambuc #if MP_MACRO == 0
2761ebfedea0SLionel Sambuc /* Free the memory pointed to by ptr */
s_mp_free(void * ptr)2762ebfedea0SLionel Sambuc void s_mp_free(void *ptr)
2763ebfedea0SLionel Sambuc {
2764ebfedea0SLionel Sambuc if(ptr)
2765ebfedea0SLionel Sambuc free(ptr);
2766ebfedea0SLionel Sambuc
2767ebfedea0SLionel Sambuc } /* end s_mp_free() */
2768ebfedea0SLionel Sambuc #endif
2769ebfedea0SLionel Sambuc
2770ebfedea0SLionel Sambuc /* }}} */
2771ebfedea0SLionel Sambuc
2772ebfedea0SLionel Sambuc /* {{{ s_mp_clamp(mp) */
2773ebfedea0SLionel Sambuc
2774ebfedea0SLionel Sambuc /* Remove leading zeroes from the given value */
s_mp_clamp(mp_int * mp)2775ebfedea0SLionel Sambuc void s_mp_clamp(mp_int *mp)
2776ebfedea0SLionel Sambuc {
2777ebfedea0SLionel Sambuc mp_size du = USED(mp);
2778ebfedea0SLionel Sambuc mp_digit *zp = DIGITS(mp) + du - 1;
2779ebfedea0SLionel Sambuc
2780ebfedea0SLionel Sambuc while(du > 1 && !*zp--)
2781ebfedea0SLionel Sambuc --du;
2782ebfedea0SLionel Sambuc
2783ebfedea0SLionel Sambuc USED(mp) = du;
2784ebfedea0SLionel Sambuc
2785ebfedea0SLionel Sambuc } /* end s_mp_clamp() */
2786ebfedea0SLionel Sambuc
2787ebfedea0SLionel Sambuc
2788ebfedea0SLionel Sambuc /* }}} */
2789ebfedea0SLionel Sambuc
2790ebfedea0SLionel Sambuc /* {{{ s_mp_exch(a, b) */
2791ebfedea0SLionel Sambuc
2792ebfedea0SLionel Sambuc /* Exchange the data for a and b; (b, a) = (a, b) */
s_mp_exch(mp_int * a,mp_int * b)2793ebfedea0SLionel Sambuc void s_mp_exch(mp_int *a, mp_int *b)
2794ebfedea0SLionel Sambuc {
2795ebfedea0SLionel Sambuc mp_int tmp;
2796ebfedea0SLionel Sambuc
2797ebfedea0SLionel Sambuc tmp = *a;
2798ebfedea0SLionel Sambuc *a = *b;
2799ebfedea0SLionel Sambuc *b = tmp;
2800ebfedea0SLionel Sambuc
2801ebfedea0SLionel Sambuc } /* end s_mp_exch() */
2802ebfedea0SLionel Sambuc
2803ebfedea0SLionel Sambuc /* }}} */
2804ebfedea0SLionel Sambuc
2805ebfedea0SLionel Sambuc /* }}} */
2806ebfedea0SLionel Sambuc
2807ebfedea0SLionel Sambuc /* {{{ Arithmetic helpers */
2808ebfedea0SLionel Sambuc
2809ebfedea0SLionel Sambuc /* {{{ s_mp_lshd(mp, p) */
2810ebfedea0SLionel Sambuc
2811ebfedea0SLionel Sambuc /*
2812ebfedea0SLionel Sambuc Shift mp leftward by p digits, growing if needed, and zero-filling
2813ebfedea0SLionel Sambuc the in-shifted digits at the right end. This is a convenient
2814ebfedea0SLionel Sambuc alternative to multiplication by powers of the radix
2815ebfedea0SLionel Sambuc */
2816ebfedea0SLionel Sambuc
s_mp_lshd(mp_int * mp,mp_size p)2817ebfedea0SLionel Sambuc mp_err s_mp_lshd(mp_int *mp, mp_size p)
2818ebfedea0SLionel Sambuc {
2819ebfedea0SLionel Sambuc mp_err res;
2820ebfedea0SLionel Sambuc mp_size pos;
2821ebfedea0SLionel Sambuc mp_digit *dp;
2822ebfedea0SLionel Sambuc int ix;
2823ebfedea0SLionel Sambuc
2824ebfedea0SLionel Sambuc if(p == 0)
2825ebfedea0SLionel Sambuc return MP_OKAY;
2826ebfedea0SLionel Sambuc
2827ebfedea0SLionel Sambuc if((res = s_mp_pad(mp, USED(mp) + p)) != MP_OKAY)
2828ebfedea0SLionel Sambuc return res;
2829ebfedea0SLionel Sambuc
2830ebfedea0SLionel Sambuc pos = USED(mp) - 1;
2831ebfedea0SLionel Sambuc dp = DIGITS(mp);
2832ebfedea0SLionel Sambuc
2833ebfedea0SLionel Sambuc /* Shift all the significant figures over as needed */
2834ebfedea0SLionel Sambuc for(ix = pos - p; ix >= 0; ix--)
2835ebfedea0SLionel Sambuc dp[ix + p] = dp[ix];
2836ebfedea0SLionel Sambuc
2837ebfedea0SLionel Sambuc /* Fill the bottom digits with zeroes */
2838ebfedea0SLionel Sambuc for(ix = 0; ix < p; ix++)
2839ebfedea0SLionel Sambuc dp[ix] = 0;
2840ebfedea0SLionel Sambuc
2841ebfedea0SLionel Sambuc return MP_OKAY;
2842ebfedea0SLionel Sambuc
2843ebfedea0SLionel Sambuc } /* end s_mp_lshd() */
2844ebfedea0SLionel Sambuc
2845ebfedea0SLionel Sambuc /* }}} */
2846ebfedea0SLionel Sambuc
2847ebfedea0SLionel Sambuc /* {{{ s_mp_rshd(mp, p) */
2848ebfedea0SLionel Sambuc
2849ebfedea0SLionel Sambuc /*
2850ebfedea0SLionel Sambuc Shift mp rightward by p digits. Maintains the invariant that
2851ebfedea0SLionel Sambuc digits above the precision are all zero. Digits shifted off the
2852ebfedea0SLionel Sambuc end are lost. Cannot fail.
2853ebfedea0SLionel Sambuc */
2854ebfedea0SLionel Sambuc
s_mp_rshd(mp_int * mp,mp_size p)2855ebfedea0SLionel Sambuc void s_mp_rshd(mp_int *mp, mp_size p)
2856ebfedea0SLionel Sambuc {
2857ebfedea0SLionel Sambuc mp_size ix;
2858ebfedea0SLionel Sambuc mp_digit *dp;
2859ebfedea0SLionel Sambuc
2860ebfedea0SLionel Sambuc if(p == 0)
2861ebfedea0SLionel Sambuc return;
2862ebfedea0SLionel Sambuc
2863ebfedea0SLionel Sambuc /* Shortcut when all digits are to be shifted off */
2864ebfedea0SLionel Sambuc if(p >= USED(mp)) {
2865ebfedea0SLionel Sambuc s_mp_setz(DIGITS(mp), ALLOC(mp));
2866ebfedea0SLionel Sambuc USED(mp) = 1;
2867ebfedea0SLionel Sambuc SIGN(mp) = MP_ZPOS;
2868ebfedea0SLionel Sambuc return;
2869ebfedea0SLionel Sambuc }
2870ebfedea0SLionel Sambuc
2871ebfedea0SLionel Sambuc /* Shift all the significant figures over as needed */
2872ebfedea0SLionel Sambuc dp = DIGITS(mp);
2873ebfedea0SLionel Sambuc for(ix = p; ix < USED(mp); ix++)
2874ebfedea0SLionel Sambuc dp[ix - p] = dp[ix];
2875ebfedea0SLionel Sambuc
2876ebfedea0SLionel Sambuc /* Fill the top digits with zeroes */
2877ebfedea0SLionel Sambuc ix -= p;
2878ebfedea0SLionel Sambuc while(ix < USED(mp))
2879ebfedea0SLionel Sambuc dp[ix++] = 0;
2880ebfedea0SLionel Sambuc
2881ebfedea0SLionel Sambuc /* Strip off any leading zeroes */
2882ebfedea0SLionel Sambuc s_mp_clamp(mp);
2883ebfedea0SLionel Sambuc
2884ebfedea0SLionel Sambuc } /* end s_mp_rshd() */
2885ebfedea0SLionel Sambuc
2886ebfedea0SLionel Sambuc /* }}} */
2887ebfedea0SLionel Sambuc
2888ebfedea0SLionel Sambuc /* {{{ s_mp_div_2(mp) */
2889ebfedea0SLionel Sambuc
2890ebfedea0SLionel Sambuc /* Divide by two -- take advantage of radix properties to do it fast */
s_mp_div_2(mp_int * mp)2891ebfedea0SLionel Sambuc void s_mp_div_2(mp_int *mp)
2892ebfedea0SLionel Sambuc {
2893ebfedea0SLionel Sambuc s_mp_div_2d(mp, 1);
2894ebfedea0SLionel Sambuc
2895ebfedea0SLionel Sambuc } /* end s_mp_div_2() */
2896ebfedea0SLionel Sambuc
2897ebfedea0SLionel Sambuc /* }}} */
2898ebfedea0SLionel Sambuc
2899ebfedea0SLionel Sambuc /* {{{ s_mp_mul_2(mp) */
2900ebfedea0SLionel Sambuc
s_mp_mul_2(mp_int * mp)2901ebfedea0SLionel Sambuc mp_err s_mp_mul_2(mp_int *mp)
2902ebfedea0SLionel Sambuc {
2903ebfedea0SLionel Sambuc int ix;
2904ebfedea0SLionel Sambuc mp_digit kin = 0, kout, *dp = DIGITS(mp);
2905ebfedea0SLionel Sambuc mp_err res;
2906ebfedea0SLionel Sambuc
2907ebfedea0SLionel Sambuc /* Shift digits leftward by 1 bit */
2908ebfedea0SLionel Sambuc for(ix = 0; ix < USED(mp); ix++) {
2909ebfedea0SLionel Sambuc kout = (dp[ix] >> (DIGIT_BIT - 1)) & 1;
2910ebfedea0SLionel Sambuc dp[ix] = (dp[ix] << 1) | kin;
2911ebfedea0SLionel Sambuc
2912ebfedea0SLionel Sambuc kin = kout;
2913ebfedea0SLionel Sambuc }
2914ebfedea0SLionel Sambuc
2915ebfedea0SLionel Sambuc /* Deal with rollover from last digit */
2916ebfedea0SLionel Sambuc if(kin) {
2917ebfedea0SLionel Sambuc if(ix >= ALLOC(mp)) {
2918ebfedea0SLionel Sambuc if((res = s_mp_grow(mp, ALLOC(mp) + 1)) != MP_OKAY)
2919ebfedea0SLionel Sambuc return res;
2920ebfedea0SLionel Sambuc dp = DIGITS(mp);
2921ebfedea0SLionel Sambuc }
2922ebfedea0SLionel Sambuc
2923ebfedea0SLionel Sambuc dp[ix] = kin;
2924ebfedea0SLionel Sambuc USED(mp) += 1;
2925ebfedea0SLionel Sambuc }
2926ebfedea0SLionel Sambuc
2927ebfedea0SLionel Sambuc return MP_OKAY;
2928ebfedea0SLionel Sambuc
2929ebfedea0SLionel Sambuc } /* end s_mp_mul_2() */
2930ebfedea0SLionel Sambuc
2931ebfedea0SLionel Sambuc /* }}} */
2932ebfedea0SLionel Sambuc
2933ebfedea0SLionel Sambuc /* {{{ s_mp_mod_2d(mp, d) */
2934ebfedea0SLionel Sambuc
2935ebfedea0SLionel Sambuc /*
2936ebfedea0SLionel Sambuc Remainder the integer by 2^d, where d is a number of bits. This
2937ebfedea0SLionel Sambuc amounts to a bitwise AND of the value, and does not require the full
2938ebfedea0SLionel Sambuc division code
2939ebfedea0SLionel Sambuc */
s_mp_mod_2d(mp_int * mp,mp_digit d)2940ebfedea0SLionel Sambuc void s_mp_mod_2d(mp_int *mp, mp_digit d)
2941ebfedea0SLionel Sambuc {
2942ebfedea0SLionel Sambuc unsigned int ndig = (d / DIGIT_BIT), nbit = (d % DIGIT_BIT);
2943ebfedea0SLionel Sambuc unsigned int ix;
2944ebfedea0SLionel Sambuc mp_digit dmask, *dp = DIGITS(mp);
2945ebfedea0SLionel Sambuc
2946ebfedea0SLionel Sambuc if(ndig >= USED(mp))
2947ebfedea0SLionel Sambuc return;
2948ebfedea0SLionel Sambuc
2949ebfedea0SLionel Sambuc /* Flush all the bits above 2^d in its digit */
2950ebfedea0SLionel Sambuc dmask = (1 << nbit) - 1;
2951ebfedea0SLionel Sambuc dp[ndig] &= dmask;
2952ebfedea0SLionel Sambuc
2953ebfedea0SLionel Sambuc /* Flush all digits above the one with 2^d in it */
2954ebfedea0SLionel Sambuc for(ix = ndig + 1; ix < USED(mp); ix++)
2955ebfedea0SLionel Sambuc dp[ix] = 0;
2956ebfedea0SLionel Sambuc
2957ebfedea0SLionel Sambuc s_mp_clamp(mp);
2958ebfedea0SLionel Sambuc
2959ebfedea0SLionel Sambuc } /* end s_mp_mod_2d() */
2960ebfedea0SLionel Sambuc
2961ebfedea0SLionel Sambuc /* }}} */
2962ebfedea0SLionel Sambuc
2963ebfedea0SLionel Sambuc /* {{{ s_mp_mul_2d(mp, d) */
2964ebfedea0SLionel Sambuc
2965ebfedea0SLionel Sambuc /*
2966ebfedea0SLionel Sambuc Multiply by the integer 2^d, where d is a number of bits. This
2967ebfedea0SLionel Sambuc amounts to a bitwise shift of the value, and does not require the
2968ebfedea0SLionel Sambuc full multiplication code.
2969ebfedea0SLionel Sambuc */
s_mp_mul_2d(mp_int * mp,mp_digit d)2970ebfedea0SLionel Sambuc mp_err s_mp_mul_2d(mp_int *mp, mp_digit d)
2971ebfedea0SLionel Sambuc {
2972ebfedea0SLionel Sambuc mp_err res;
2973ebfedea0SLionel Sambuc mp_digit save, next, mask, *dp;
2974ebfedea0SLionel Sambuc mp_size used;
2975ebfedea0SLionel Sambuc int ix;
2976ebfedea0SLionel Sambuc
2977ebfedea0SLionel Sambuc if((res = s_mp_lshd(mp, d / DIGIT_BIT)) != MP_OKAY)
2978ebfedea0SLionel Sambuc return res;
2979ebfedea0SLionel Sambuc
2980ebfedea0SLionel Sambuc dp = DIGITS(mp); used = USED(mp);
2981ebfedea0SLionel Sambuc d %= DIGIT_BIT;
2982ebfedea0SLionel Sambuc
2983ebfedea0SLionel Sambuc mask = (1 << d) - 1;
2984ebfedea0SLionel Sambuc
2985ebfedea0SLionel Sambuc /* If the shift requires another digit, make sure we've got one to
2986ebfedea0SLionel Sambuc work with */
2987ebfedea0SLionel Sambuc if((dp[used - 1] >> (DIGIT_BIT - d)) & mask) {
2988ebfedea0SLionel Sambuc if((res = s_mp_grow(mp, used + 1)) != MP_OKAY)
2989ebfedea0SLionel Sambuc return res;
2990ebfedea0SLionel Sambuc dp = DIGITS(mp);
2991ebfedea0SLionel Sambuc }
2992ebfedea0SLionel Sambuc
2993ebfedea0SLionel Sambuc /* Do the shifting... */
2994ebfedea0SLionel Sambuc save = 0;
2995ebfedea0SLionel Sambuc for(ix = 0; ix < used; ix++) {
2996ebfedea0SLionel Sambuc next = (dp[ix] >> (DIGIT_BIT - d)) & mask;
2997ebfedea0SLionel Sambuc dp[ix] = (dp[ix] << d) | save;
2998ebfedea0SLionel Sambuc save = next;
2999ebfedea0SLionel Sambuc }
3000ebfedea0SLionel Sambuc
3001ebfedea0SLionel Sambuc /* If, at this point, we have a nonzero carryout into the next
3002ebfedea0SLionel Sambuc digit, we'll increase the size by one digit, and store it...
3003ebfedea0SLionel Sambuc */
3004ebfedea0SLionel Sambuc if(save) {
3005ebfedea0SLionel Sambuc dp[used] = save;
3006ebfedea0SLionel Sambuc USED(mp) += 1;
3007ebfedea0SLionel Sambuc }
3008ebfedea0SLionel Sambuc
3009ebfedea0SLionel Sambuc s_mp_clamp(mp);
3010ebfedea0SLionel Sambuc return MP_OKAY;
3011ebfedea0SLionel Sambuc
3012ebfedea0SLionel Sambuc } /* end s_mp_mul_2d() */
3013ebfedea0SLionel Sambuc
3014ebfedea0SLionel Sambuc /* }}} */
3015ebfedea0SLionel Sambuc
3016ebfedea0SLionel Sambuc /* {{{ s_mp_div_2d(mp, d) */
3017ebfedea0SLionel Sambuc
3018ebfedea0SLionel Sambuc /*
3019ebfedea0SLionel Sambuc Divide the integer by 2^d, where d is a number of bits. This
3020ebfedea0SLionel Sambuc amounts to a bitwise shift of the value, and does not require the
3021ebfedea0SLionel Sambuc full division code (used in Barrett reduction, see below)
3022ebfedea0SLionel Sambuc */
s_mp_div_2d(mp_int * mp,mp_digit d)3023ebfedea0SLionel Sambuc void s_mp_div_2d(mp_int *mp, mp_digit d)
3024ebfedea0SLionel Sambuc {
3025ebfedea0SLionel Sambuc int ix;
3026ebfedea0SLionel Sambuc mp_digit save, next, mask, *dp = DIGITS(mp);
3027ebfedea0SLionel Sambuc
3028ebfedea0SLionel Sambuc s_mp_rshd(mp, d / DIGIT_BIT);
3029ebfedea0SLionel Sambuc d %= DIGIT_BIT;
3030ebfedea0SLionel Sambuc
3031ebfedea0SLionel Sambuc mask = (1 << d) - 1;
3032ebfedea0SLionel Sambuc
3033ebfedea0SLionel Sambuc save = 0;
3034ebfedea0SLionel Sambuc for(ix = USED(mp) - 1; ix >= 0; ix--) {
3035ebfedea0SLionel Sambuc next = dp[ix] & mask;
3036ebfedea0SLionel Sambuc dp[ix] = (dp[ix] >> d) | (save << (DIGIT_BIT - d));
3037ebfedea0SLionel Sambuc save = next;
3038ebfedea0SLionel Sambuc }
3039ebfedea0SLionel Sambuc
3040ebfedea0SLionel Sambuc s_mp_clamp(mp);
3041ebfedea0SLionel Sambuc
3042ebfedea0SLionel Sambuc } /* end s_mp_div_2d() */
3043ebfedea0SLionel Sambuc
3044ebfedea0SLionel Sambuc /* }}} */
3045ebfedea0SLionel Sambuc
3046ebfedea0SLionel Sambuc /* {{{ s_mp_norm(a, b) */
3047ebfedea0SLionel Sambuc
3048ebfedea0SLionel Sambuc /*
3049ebfedea0SLionel Sambuc s_mp_norm(a, b)
3050ebfedea0SLionel Sambuc
3051ebfedea0SLionel Sambuc Normalize a and b for division, where b is the divisor. In order
3052ebfedea0SLionel Sambuc that we might make good guesses for quotient digits, we want the
3053ebfedea0SLionel Sambuc leading digit of b to be at least half the radix, which we
3054ebfedea0SLionel Sambuc accomplish by multiplying a and b by a constant. This constant is
3055ebfedea0SLionel Sambuc returned (so that it can be divided back out of the remainder at the
3056ebfedea0SLionel Sambuc end of the division process).
3057ebfedea0SLionel Sambuc
3058ebfedea0SLionel Sambuc We multiply by the smallest power of 2 that gives us a leading digit
3059ebfedea0SLionel Sambuc at least half the radix. By choosing a power of 2, we simplify the
3060ebfedea0SLionel Sambuc multiplication and division steps to simple shifts.
3061ebfedea0SLionel Sambuc */
s_mp_norm(mp_int * a,mp_int * b)3062ebfedea0SLionel Sambuc mp_digit s_mp_norm(mp_int *a, mp_int *b)
3063ebfedea0SLionel Sambuc {
3064ebfedea0SLionel Sambuc mp_digit t, d = 0;
3065ebfedea0SLionel Sambuc
3066ebfedea0SLionel Sambuc t = DIGIT(b, USED(b) - 1);
3067ebfedea0SLionel Sambuc while(t < (RADIX / 2)) {
3068ebfedea0SLionel Sambuc t <<= 1;
3069ebfedea0SLionel Sambuc ++d;
3070ebfedea0SLionel Sambuc }
3071ebfedea0SLionel Sambuc
3072ebfedea0SLionel Sambuc if(d != 0) {
3073ebfedea0SLionel Sambuc s_mp_mul_2d(a, d);
3074ebfedea0SLionel Sambuc s_mp_mul_2d(b, d);
3075ebfedea0SLionel Sambuc }
3076ebfedea0SLionel Sambuc
3077ebfedea0SLionel Sambuc return d;
3078ebfedea0SLionel Sambuc
3079ebfedea0SLionel Sambuc } /* end s_mp_norm() */
3080ebfedea0SLionel Sambuc
3081ebfedea0SLionel Sambuc /* }}} */
3082ebfedea0SLionel Sambuc
3083ebfedea0SLionel Sambuc /* }}} */
3084ebfedea0SLionel Sambuc
3085ebfedea0SLionel Sambuc /* {{{ Primitive digit arithmetic */
3086ebfedea0SLionel Sambuc
3087ebfedea0SLionel Sambuc /* {{{ s_mp_add_d(mp, d) */
3088ebfedea0SLionel Sambuc
3089ebfedea0SLionel Sambuc /* Add d to |mp| in place */
s_mp_add_d(mp_int * mp,mp_digit d)3090ebfedea0SLionel Sambuc mp_err s_mp_add_d(mp_int *mp, mp_digit d) /* unsigned digit addition */
3091ebfedea0SLionel Sambuc {
3092ebfedea0SLionel Sambuc mp_word w, k = 0;
3093ebfedea0SLionel Sambuc mp_size ix = 1, used = USED(mp);
3094ebfedea0SLionel Sambuc mp_digit *dp = DIGITS(mp);
3095ebfedea0SLionel Sambuc
3096ebfedea0SLionel Sambuc w = dp[0] + d;
3097ebfedea0SLionel Sambuc dp[0] = ACCUM(w);
3098ebfedea0SLionel Sambuc k = CARRYOUT(w);
3099ebfedea0SLionel Sambuc
3100ebfedea0SLionel Sambuc while(ix < used && k) {
3101ebfedea0SLionel Sambuc w = dp[ix] + k;
3102ebfedea0SLionel Sambuc dp[ix] = ACCUM(w);
3103ebfedea0SLionel Sambuc k = CARRYOUT(w);
3104ebfedea0SLionel Sambuc ++ix;
3105ebfedea0SLionel Sambuc }
3106ebfedea0SLionel Sambuc
3107ebfedea0SLionel Sambuc if(k != 0) {
3108ebfedea0SLionel Sambuc mp_err res;
3109ebfedea0SLionel Sambuc
3110ebfedea0SLionel Sambuc if((res = s_mp_pad(mp, USED(mp) + 1)) != MP_OKAY)
3111ebfedea0SLionel Sambuc return res;
3112ebfedea0SLionel Sambuc
3113ebfedea0SLionel Sambuc DIGIT(mp, ix) = k;
3114ebfedea0SLionel Sambuc }
3115ebfedea0SLionel Sambuc
3116ebfedea0SLionel Sambuc return MP_OKAY;
3117ebfedea0SLionel Sambuc
3118ebfedea0SLionel Sambuc } /* end s_mp_add_d() */
3119ebfedea0SLionel Sambuc
3120ebfedea0SLionel Sambuc /* }}} */
3121ebfedea0SLionel Sambuc
3122ebfedea0SLionel Sambuc /* {{{ s_mp_sub_d(mp, d) */
3123ebfedea0SLionel Sambuc
3124ebfedea0SLionel Sambuc /* Subtract d from |mp| in place, assumes |mp| > d */
s_mp_sub_d(mp_int * mp,mp_digit d)3125ebfedea0SLionel Sambuc mp_err s_mp_sub_d(mp_int *mp, mp_digit d) /* unsigned digit subtract */
3126ebfedea0SLionel Sambuc {
3127ebfedea0SLionel Sambuc mp_word w, b = 0;
3128ebfedea0SLionel Sambuc mp_size ix = 1, used = USED(mp);
3129ebfedea0SLionel Sambuc mp_digit *dp = DIGITS(mp);
3130ebfedea0SLionel Sambuc
3131ebfedea0SLionel Sambuc /* Compute initial subtraction */
3132ebfedea0SLionel Sambuc w = (RADIX + dp[0]) - d;
3133ebfedea0SLionel Sambuc b = CARRYOUT(w) ? 0 : 1;
3134ebfedea0SLionel Sambuc dp[0] = ACCUM(w);
3135ebfedea0SLionel Sambuc
3136ebfedea0SLionel Sambuc /* Propagate borrows leftward */
3137ebfedea0SLionel Sambuc while(b && ix < used) {
3138ebfedea0SLionel Sambuc w = (RADIX + dp[ix]) - b;
3139ebfedea0SLionel Sambuc b = CARRYOUT(w) ? 0 : 1;
3140ebfedea0SLionel Sambuc dp[ix] = ACCUM(w);
3141ebfedea0SLionel Sambuc ++ix;
3142ebfedea0SLionel Sambuc }
3143ebfedea0SLionel Sambuc
3144ebfedea0SLionel Sambuc /* Remove leading zeroes */
3145ebfedea0SLionel Sambuc s_mp_clamp(mp);
3146ebfedea0SLionel Sambuc
3147ebfedea0SLionel Sambuc /* If we have a borrow out, it's a violation of the input invariant */
3148ebfedea0SLionel Sambuc if(b)
3149ebfedea0SLionel Sambuc return MP_RANGE;
3150ebfedea0SLionel Sambuc else
3151ebfedea0SLionel Sambuc return MP_OKAY;
3152ebfedea0SLionel Sambuc
3153ebfedea0SLionel Sambuc } /* end s_mp_sub_d() */
3154ebfedea0SLionel Sambuc
3155ebfedea0SLionel Sambuc /* }}} */
3156ebfedea0SLionel Sambuc
3157ebfedea0SLionel Sambuc /* {{{ s_mp_mul_d(a, d) */
3158ebfedea0SLionel Sambuc
3159ebfedea0SLionel Sambuc /* Compute a = a * d, single digit multiplication */
s_mp_mul_d(mp_int * a,mp_digit d)3160ebfedea0SLionel Sambuc mp_err s_mp_mul_d(mp_int *a, mp_digit d)
3161ebfedea0SLionel Sambuc {
3162ebfedea0SLionel Sambuc mp_word w, k = 0;
3163ebfedea0SLionel Sambuc mp_size ix, max;
3164ebfedea0SLionel Sambuc mp_err res;
3165ebfedea0SLionel Sambuc mp_digit *dp = DIGITS(a);
3166ebfedea0SLionel Sambuc
3167ebfedea0SLionel Sambuc /*
3168ebfedea0SLionel Sambuc Single-digit multiplication will increase the precision of the
3169ebfedea0SLionel Sambuc output by at most one digit. However, we can detect when this
3170ebfedea0SLionel Sambuc will happen -- if the high-order digit of a, times d, gives a
3171ebfedea0SLionel Sambuc two-digit result, then the precision of the result will increase;
3172ebfedea0SLionel Sambuc otherwise it won't. We use this fact to avoid calling s_mp_pad()
3173ebfedea0SLionel Sambuc unless absolutely necessary.
3174ebfedea0SLionel Sambuc */
3175ebfedea0SLionel Sambuc max = USED(a);
3176ebfedea0SLionel Sambuc w = dp[max - 1] * d;
3177ebfedea0SLionel Sambuc if(CARRYOUT(w) != 0) {
3178ebfedea0SLionel Sambuc if((res = s_mp_pad(a, max + 1)) != MP_OKAY)
3179ebfedea0SLionel Sambuc return res;
3180ebfedea0SLionel Sambuc dp = DIGITS(a);
3181ebfedea0SLionel Sambuc }
3182ebfedea0SLionel Sambuc
3183ebfedea0SLionel Sambuc for(ix = 0; ix < max; ix++) {
3184ebfedea0SLionel Sambuc w = (dp[ix] * d) + k;
3185ebfedea0SLionel Sambuc dp[ix] = ACCUM(w);
3186ebfedea0SLionel Sambuc k = CARRYOUT(w);
3187ebfedea0SLionel Sambuc }
3188ebfedea0SLionel Sambuc
3189ebfedea0SLionel Sambuc /* If there is a precision increase, take care of it here; the above
3190ebfedea0SLionel Sambuc test guarantees we have enough storage to do this safely.
3191ebfedea0SLionel Sambuc */
3192ebfedea0SLionel Sambuc if(k) {
3193ebfedea0SLionel Sambuc dp[max] = k;
3194ebfedea0SLionel Sambuc USED(a) = max + 1;
3195ebfedea0SLionel Sambuc }
3196ebfedea0SLionel Sambuc
3197ebfedea0SLionel Sambuc s_mp_clamp(a);
3198ebfedea0SLionel Sambuc
3199ebfedea0SLionel Sambuc return MP_OKAY;
3200ebfedea0SLionel Sambuc
3201ebfedea0SLionel Sambuc } /* end s_mp_mul_d() */
3202ebfedea0SLionel Sambuc
3203ebfedea0SLionel Sambuc /* }}} */
3204ebfedea0SLionel Sambuc
3205ebfedea0SLionel Sambuc /* {{{ s_mp_div_d(mp, d, r) */
3206ebfedea0SLionel Sambuc
3207ebfedea0SLionel Sambuc /*
3208ebfedea0SLionel Sambuc s_mp_div_d(mp, d, r)
3209ebfedea0SLionel Sambuc
3210ebfedea0SLionel Sambuc Compute the quotient mp = mp / d and remainder r = mp mod d, for a
3211ebfedea0SLionel Sambuc single digit d. If r is null, the remainder will be discarded.
3212ebfedea0SLionel Sambuc */
3213ebfedea0SLionel Sambuc
s_mp_div_d(mp_int * mp,mp_digit d,mp_digit * r)3214ebfedea0SLionel Sambuc mp_err s_mp_div_d(mp_int *mp, mp_digit d, mp_digit *r)
3215ebfedea0SLionel Sambuc {
3216ebfedea0SLionel Sambuc mp_word w = 0, t;
3217ebfedea0SLionel Sambuc mp_int quot;
3218ebfedea0SLionel Sambuc mp_err res;
3219ebfedea0SLionel Sambuc mp_digit *dp = DIGITS(mp), *qp;
3220ebfedea0SLionel Sambuc int ix;
3221ebfedea0SLionel Sambuc
3222ebfedea0SLionel Sambuc if(d == 0)
3223ebfedea0SLionel Sambuc return MP_RANGE;
3224ebfedea0SLionel Sambuc
3225ebfedea0SLionel Sambuc /* Make room for the quotient */
3226ebfedea0SLionel Sambuc if((res = mp_init_size(", USED(mp))) != MP_OKAY)
3227ebfedea0SLionel Sambuc return res;
3228ebfedea0SLionel Sambuc
3229ebfedea0SLionel Sambuc USED(") = USED(mp); /* so clamping will work below */
3230ebfedea0SLionel Sambuc qp = DIGITS(");
3231ebfedea0SLionel Sambuc
3232ebfedea0SLionel Sambuc /* Divide without subtraction */
3233ebfedea0SLionel Sambuc for(ix = USED(mp) - 1; ix >= 0; ix--) {
3234ebfedea0SLionel Sambuc w = (w << DIGIT_BIT) | dp[ix];
3235ebfedea0SLionel Sambuc
3236ebfedea0SLionel Sambuc if(w >= d) {
3237ebfedea0SLionel Sambuc t = w / d;
3238ebfedea0SLionel Sambuc w = w % d;
3239ebfedea0SLionel Sambuc } else {
3240ebfedea0SLionel Sambuc t = 0;
3241ebfedea0SLionel Sambuc }
3242ebfedea0SLionel Sambuc
3243ebfedea0SLionel Sambuc qp[ix] = t;
3244ebfedea0SLionel Sambuc }
3245ebfedea0SLionel Sambuc
3246ebfedea0SLionel Sambuc /* Deliver the remainder, if desired */
3247ebfedea0SLionel Sambuc if(r)
3248ebfedea0SLionel Sambuc *r = w;
3249ebfedea0SLionel Sambuc
3250ebfedea0SLionel Sambuc s_mp_clamp(");
3251ebfedea0SLionel Sambuc mp_exch(", mp);
3252ebfedea0SLionel Sambuc mp_clear(");
3253ebfedea0SLionel Sambuc
3254ebfedea0SLionel Sambuc return MP_OKAY;
3255ebfedea0SLionel Sambuc
3256ebfedea0SLionel Sambuc } /* end s_mp_div_d() */
3257ebfedea0SLionel Sambuc
3258ebfedea0SLionel Sambuc /* }}} */
3259ebfedea0SLionel Sambuc
3260ebfedea0SLionel Sambuc /* }}} */
3261ebfedea0SLionel Sambuc
3262ebfedea0SLionel Sambuc /* {{{ Primitive full arithmetic */
3263ebfedea0SLionel Sambuc
3264ebfedea0SLionel Sambuc /* {{{ s_mp_add(a, b) */
3265ebfedea0SLionel Sambuc
3266ebfedea0SLionel Sambuc /* Compute a = |a| + |b| */
s_mp_add(mp_int * a,mp_int * b)3267ebfedea0SLionel Sambuc mp_err s_mp_add(mp_int *a, mp_int *b) /* magnitude addition */
3268ebfedea0SLionel Sambuc {
3269ebfedea0SLionel Sambuc mp_word w = 0;
3270ebfedea0SLionel Sambuc mp_digit *pa, *pb;
3271ebfedea0SLionel Sambuc mp_size ix, used = USED(b);
3272ebfedea0SLionel Sambuc mp_err res;
3273ebfedea0SLionel Sambuc
3274ebfedea0SLionel Sambuc /* Make sure a has enough precision for the output value */
3275ebfedea0SLionel Sambuc if((used > USED(a)) && (res = s_mp_pad(a, used)) != MP_OKAY)
3276ebfedea0SLionel Sambuc return res;
3277ebfedea0SLionel Sambuc
3278ebfedea0SLionel Sambuc /*
3279ebfedea0SLionel Sambuc Add up all digits up to the precision of b. If b had initially
3280ebfedea0SLionel Sambuc the same precision as a, or greater, we took care of it by the
3281ebfedea0SLionel Sambuc padding step above, so there is no problem. If b had initially
3282ebfedea0SLionel Sambuc less precision, we'll have to make sure the carry out is duly
3283ebfedea0SLionel Sambuc propagated upward among the higher-order digits of the sum.
3284ebfedea0SLionel Sambuc */
3285ebfedea0SLionel Sambuc pa = DIGITS(a);
3286ebfedea0SLionel Sambuc pb = DIGITS(b);
3287ebfedea0SLionel Sambuc for(ix = 0; ix < used; ++ix) {
3288ebfedea0SLionel Sambuc w += *pa + *pb++;
3289ebfedea0SLionel Sambuc *pa++ = ACCUM(w);
3290ebfedea0SLionel Sambuc w = CARRYOUT(w);
3291ebfedea0SLionel Sambuc }
3292ebfedea0SLionel Sambuc
3293ebfedea0SLionel Sambuc /* If we run out of 'b' digits before we're actually done, make
3294ebfedea0SLionel Sambuc sure the carries get propagated upward...
3295ebfedea0SLionel Sambuc */
3296ebfedea0SLionel Sambuc used = USED(a);
3297ebfedea0SLionel Sambuc while(w && ix < used) {
3298ebfedea0SLionel Sambuc w += *pa;
3299ebfedea0SLionel Sambuc *pa++ = ACCUM(w);
3300ebfedea0SLionel Sambuc w = CARRYOUT(w);
3301ebfedea0SLionel Sambuc ++ix;
3302ebfedea0SLionel Sambuc }
3303ebfedea0SLionel Sambuc
3304ebfedea0SLionel Sambuc /* If there's an overall carry out, increase precision and include
3305ebfedea0SLionel Sambuc it. We could have done this initially, but why touch the memory
3306ebfedea0SLionel Sambuc allocator unless we're sure we have to?
3307ebfedea0SLionel Sambuc */
3308ebfedea0SLionel Sambuc if(w) {
3309ebfedea0SLionel Sambuc if((res = s_mp_pad(a, used + 1)) != MP_OKAY)
3310ebfedea0SLionel Sambuc return res;
3311ebfedea0SLionel Sambuc
3312ebfedea0SLionel Sambuc DIGIT(a, ix) = w; /* pa may not be valid after s_mp_pad() call */
3313ebfedea0SLionel Sambuc }
3314ebfedea0SLionel Sambuc
3315ebfedea0SLionel Sambuc return MP_OKAY;
3316ebfedea0SLionel Sambuc
3317ebfedea0SLionel Sambuc } /* end s_mp_add() */
3318ebfedea0SLionel Sambuc
3319ebfedea0SLionel Sambuc /* }}} */
3320ebfedea0SLionel Sambuc
3321ebfedea0SLionel Sambuc /* {{{ s_mp_sub(a, b) */
3322ebfedea0SLionel Sambuc
3323ebfedea0SLionel Sambuc /* Compute a = |a| - |b|, assumes |a| >= |b| */
s_mp_sub(mp_int * a,mp_int * b)3324ebfedea0SLionel Sambuc mp_err s_mp_sub(mp_int *a, mp_int *b) /* magnitude subtract */
3325ebfedea0SLionel Sambuc {
3326ebfedea0SLionel Sambuc mp_word w = 0;
3327ebfedea0SLionel Sambuc mp_digit *pa, *pb;
3328ebfedea0SLionel Sambuc mp_size ix, used = USED(b);
3329ebfedea0SLionel Sambuc
3330ebfedea0SLionel Sambuc /*
3331ebfedea0SLionel Sambuc Subtract and propagate borrow. Up to the precision of b, this
3332ebfedea0SLionel Sambuc accounts for the digits of b; after that, we just make sure the
3333ebfedea0SLionel Sambuc carries get to the right place. This saves having to pad b out to
3334ebfedea0SLionel Sambuc the precision of a just to make the loops work right...
3335ebfedea0SLionel Sambuc */
3336ebfedea0SLionel Sambuc pa = DIGITS(a);
3337ebfedea0SLionel Sambuc pb = DIGITS(b);
3338ebfedea0SLionel Sambuc
3339ebfedea0SLionel Sambuc for(ix = 0; ix < used; ++ix) {
3340ebfedea0SLionel Sambuc w = (RADIX + *pa) - w - *pb++;
3341ebfedea0SLionel Sambuc *pa++ = ACCUM(w);
3342ebfedea0SLionel Sambuc w = CARRYOUT(w) ? 0 : 1;
3343ebfedea0SLionel Sambuc }
3344ebfedea0SLionel Sambuc
3345ebfedea0SLionel Sambuc used = USED(a);
3346ebfedea0SLionel Sambuc while(ix < used) {
3347ebfedea0SLionel Sambuc w = RADIX + *pa - w;
3348ebfedea0SLionel Sambuc *pa++ = ACCUM(w);
3349ebfedea0SLionel Sambuc w = CARRYOUT(w) ? 0 : 1;
3350ebfedea0SLionel Sambuc ++ix;
3351ebfedea0SLionel Sambuc }
3352ebfedea0SLionel Sambuc
3353ebfedea0SLionel Sambuc /* Clobber any leading zeroes we created */
3354ebfedea0SLionel Sambuc s_mp_clamp(a);
3355ebfedea0SLionel Sambuc
3356ebfedea0SLionel Sambuc /*
3357ebfedea0SLionel Sambuc If there was a borrow out, then |b| > |a| in violation
3358ebfedea0SLionel Sambuc of our input invariant. We've already done the work,
3359ebfedea0SLionel Sambuc but we'll at least complain about it...
3360ebfedea0SLionel Sambuc */
3361ebfedea0SLionel Sambuc if(w)
3362ebfedea0SLionel Sambuc return MP_RANGE;
3363ebfedea0SLionel Sambuc else
3364ebfedea0SLionel Sambuc return MP_OKAY;
3365ebfedea0SLionel Sambuc
3366ebfedea0SLionel Sambuc } /* end s_mp_sub() */
3367ebfedea0SLionel Sambuc
3368ebfedea0SLionel Sambuc /* }}} */
3369ebfedea0SLionel Sambuc
s_mp_reduce(mp_int * x,mp_int * m,mp_int * mu)3370ebfedea0SLionel Sambuc mp_err s_mp_reduce(mp_int *x, mp_int *m, mp_int *mu)
3371ebfedea0SLionel Sambuc {
3372ebfedea0SLionel Sambuc mp_int q;
3373ebfedea0SLionel Sambuc mp_err res;
3374ebfedea0SLionel Sambuc mp_size um = USED(m);
3375ebfedea0SLionel Sambuc
3376ebfedea0SLionel Sambuc if((res = mp_init_copy(&q, x)) != MP_OKAY)
3377ebfedea0SLionel Sambuc return res;
3378ebfedea0SLionel Sambuc
3379ebfedea0SLionel Sambuc s_mp_rshd(&q, um - 1); /* q1 = x / b^(k-1) */
3380ebfedea0SLionel Sambuc s_mp_mul(&q, mu); /* q2 = q1 * mu */
3381ebfedea0SLionel Sambuc s_mp_rshd(&q, um + 1); /* q3 = q2 / b^(k+1) */
3382ebfedea0SLionel Sambuc
3383ebfedea0SLionel Sambuc /* x = x mod b^(k+1), quick (no division) */
3384ebfedea0SLionel Sambuc s_mp_mod_2d(x, (mp_digit)(DIGIT_BIT * (um + 1)));
3385ebfedea0SLionel Sambuc
3386ebfedea0SLionel Sambuc /* q = q * m mod b^(k+1), quick (no division), uses the short multiplier */
3387ebfedea0SLionel Sambuc #ifndef SHRT_MUL
3388ebfedea0SLionel Sambuc s_mp_mul(&q, m);
3389ebfedea0SLionel Sambuc s_mp_mod_2d(&q, (mp_digit)(DIGIT_BIT * (um + 1)));
3390ebfedea0SLionel Sambuc #else
3391ebfedea0SLionel Sambuc s_mp_mul_dig(&q, m, um + 1);
3392ebfedea0SLionel Sambuc #endif
3393ebfedea0SLionel Sambuc
3394ebfedea0SLionel Sambuc /* x = x - q */
3395ebfedea0SLionel Sambuc if((res = mp_sub(x, &q, x)) != MP_OKAY)
3396ebfedea0SLionel Sambuc goto CLEANUP;
3397ebfedea0SLionel Sambuc
3398ebfedea0SLionel Sambuc /* If x < 0, add b^(k+1) to it */
3399ebfedea0SLionel Sambuc if(mp_cmp_z(x) < 0) {
3400ebfedea0SLionel Sambuc mp_set(&q, 1);
3401ebfedea0SLionel Sambuc if((res = s_mp_lshd(&q, um + 1)) != MP_OKAY)
3402ebfedea0SLionel Sambuc goto CLEANUP;
3403ebfedea0SLionel Sambuc if((res = mp_add(x, &q, x)) != MP_OKAY)
3404ebfedea0SLionel Sambuc goto CLEANUP;
3405ebfedea0SLionel Sambuc }
3406ebfedea0SLionel Sambuc
3407ebfedea0SLionel Sambuc /* Back off if it's too big */
3408ebfedea0SLionel Sambuc while(mp_cmp(x, m) >= 0) {
3409ebfedea0SLionel Sambuc if((res = s_mp_sub(x, m)) != MP_OKAY)
3410ebfedea0SLionel Sambuc break;
3411ebfedea0SLionel Sambuc }
3412ebfedea0SLionel Sambuc
3413ebfedea0SLionel Sambuc CLEANUP:
3414ebfedea0SLionel Sambuc mp_clear(&q);
3415ebfedea0SLionel Sambuc
3416ebfedea0SLionel Sambuc return res;
3417ebfedea0SLionel Sambuc
3418ebfedea0SLionel Sambuc } /* end s_mp_reduce() */
3419ebfedea0SLionel Sambuc
3420ebfedea0SLionel Sambuc
3421ebfedea0SLionel Sambuc
3422ebfedea0SLionel Sambuc /* {{{ s_mp_mul(a, b) */
3423ebfedea0SLionel Sambuc
3424ebfedea0SLionel Sambuc /* Compute a = |a| * |b| */
s_mp_mul(mp_int * a,mp_int * b)3425ebfedea0SLionel Sambuc mp_err s_mp_mul(mp_int *a, mp_int *b)
3426ebfedea0SLionel Sambuc {
3427ebfedea0SLionel Sambuc mp_word w, k = 0;
3428ebfedea0SLionel Sambuc mp_int tmp;
3429ebfedea0SLionel Sambuc mp_err res;
3430ebfedea0SLionel Sambuc mp_size ix, jx, ua = USED(a), ub = USED(b);
3431ebfedea0SLionel Sambuc mp_digit *pa, *pb, *pt, *pbt;
3432ebfedea0SLionel Sambuc
3433ebfedea0SLionel Sambuc if((res = mp_init_size(&tmp, ua + ub)) != MP_OKAY)
3434ebfedea0SLionel Sambuc return res;
3435ebfedea0SLionel Sambuc
3436ebfedea0SLionel Sambuc /* This has the effect of left-padding with zeroes... */
3437ebfedea0SLionel Sambuc USED(&tmp) = ua + ub;
3438ebfedea0SLionel Sambuc
3439ebfedea0SLionel Sambuc /* We're going to need the base value each iteration */
3440ebfedea0SLionel Sambuc pbt = DIGITS(&tmp);
3441ebfedea0SLionel Sambuc
3442ebfedea0SLionel Sambuc /* Outer loop: Digits of b */
3443ebfedea0SLionel Sambuc
3444ebfedea0SLionel Sambuc pb = DIGITS(b);
3445ebfedea0SLionel Sambuc for(ix = 0; ix < ub; ++ix, ++pb) {
3446ebfedea0SLionel Sambuc if(*pb == 0)
3447ebfedea0SLionel Sambuc continue;
3448ebfedea0SLionel Sambuc
3449ebfedea0SLionel Sambuc /* Inner product: Digits of a */
3450ebfedea0SLionel Sambuc pa = DIGITS(a);
3451ebfedea0SLionel Sambuc for(jx = 0; jx < ua; ++jx, ++pa) {
3452ebfedea0SLionel Sambuc pt = pbt + ix + jx;
3453ebfedea0SLionel Sambuc w = *pb * *pa + k + *pt;
3454ebfedea0SLionel Sambuc *pt = ACCUM(w);
3455ebfedea0SLionel Sambuc k = CARRYOUT(w);
3456ebfedea0SLionel Sambuc }
3457ebfedea0SLionel Sambuc
3458ebfedea0SLionel Sambuc pbt[ix + jx] = k;
3459ebfedea0SLionel Sambuc k = 0;
3460ebfedea0SLionel Sambuc }
3461ebfedea0SLionel Sambuc
3462ebfedea0SLionel Sambuc s_mp_clamp(&tmp);
3463ebfedea0SLionel Sambuc s_mp_exch(&tmp, a);
3464ebfedea0SLionel Sambuc
3465ebfedea0SLionel Sambuc mp_clear(&tmp);
3466ebfedea0SLionel Sambuc
3467ebfedea0SLionel Sambuc return MP_OKAY;
3468ebfedea0SLionel Sambuc
3469ebfedea0SLionel Sambuc } /* end s_mp_mul() */
3470ebfedea0SLionel Sambuc
3471ebfedea0SLionel Sambuc /* }}} */
3472ebfedea0SLionel Sambuc
3473ebfedea0SLionel Sambuc /* {{{ s_mp_kmul(a, b, out, len) */
3474ebfedea0SLionel Sambuc
3475ebfedea0SLionel Sambuc #if 0
3476ebfedea0SLionel Sambuc void s_mp_kmul(mp_digit *a, mp_digit *b, mp_digit *out, mp_size len)
3477ebfedea0SLionel Sambuc {
3478ebfedea0SLionel Sambuc mp_word w, k = 0;
3479ebfedea0SLionel Sambuc mp_size ix, jx;
3480ebfedea0SLionel Sambuc mp_digit *pa, *pt;
3481ebfedea0SLionel Sambuc
3482ebfedea0SLionel Sambuc for(ix = 0; ix < len; ++ix, ++b) {
3483ebfedea0SLionel Sambuc if(*b == 0)
3484ebfedea0SLionel Sambuc continue;
3485ebfedea0SLionel Sambuc
3486ebfedea0SLionel Sambuc pa = a;
3487ebfedea0SLionel Sambuc for(jx = 0; jx < len; ++jx, ++pa) {
3488ebfedea0SLionel Sambuc pt = out + ix + jx;
3489ebfedea0SLionel Sambuc w = *b * *pa + k + *pt;
3490ebfedea0SLionel Sambuc *pt = ACCUM(w);
3491ebfedea0SLionel Sambuc k = CARRYOUT(w);
3492ebfedea0SLionel Sambuc }
3493ebfedea0SLionel Sambuc
3494ebfedea0SLionel Sambuc out[ix + jx] = k;
3495ebfedea0SLionel Sambuc k = 0;
3496ebfedea0SLionel Sambuc }
3497ebfedea0SLionel Sambuc
3498ebfedea0SLionel Sambuc } /* end s_mp_kmul() */
3499ebfedea0SLionel Sambuc #endif
3500ebfedea0SLionel Sambuc
3501ebfedea0SLionel Sambuc /* }}} */
3502ebfedea0SLionel Sambuc
3503ebfedea0SLionel Sambuc /* {{{ s_mp_sqr(a) */
3504ebfedea0SLionel Sambuc
3505ebfedea0SLionel Sambuc /*
3506ebfedea0SLionel Sambuc Computes the square of a, in place. This can be done more
3507ebfedea0SLionel Sambuc efficiently than a general multiplication, because many of the
3508ebfedea0SLionel Sambuc computation steps are redundant when squaring. The inner product
3509ebfedea0SLionel Sambuc step is a bit more complicated, but we save a fair number of
3510ebfedea0SLionel Sambuc iterations of the multiplication loop.
3511ebfedea0SLionel Sambuc */
3512ebfedea0SLionel Sambuc #if MP_SQUARE
s_mp_sqr(mp_int * a)3513ebfedea0SLionel Sambuc mp_err s_mp_sqr(mp_int *a)
3514ebfedea0SLionel Sambuc {
3515ebfedea0SLionel Sambuc mp_word w, k = 0;
3516ebfedea0SLionel Sambuc mp_int tmp;
3517ebfedea0SLionel Sambuc mp_err res;
3518ebfedea0SLionel Sambuc mp_size ix, jx, kx, used = USED(a);
3519ebfedea0SLionel Sambuc mp_digit *pa1, *pa2, *pt, *pbt;
3520ebfedea0SLionel Sambuc
3521ebfedea0SLionel Sambuc if((res = mp_init_size(&tmp, 2 * used)) != MP_OKAY)
3522ebfedea0SLionel Sambuc return res;
3523ebfedea0SLionel Sambuc
3524ebfedea0SLionel Sambuc /* Left-pad with zeroes */
3525ebfedea0SLionel Sambuc USED(&tmp) = 2 * used;
3526ebfedea0SLionel Sambuc
3527ebfedea0SLionel Sambuc /* We need the base value each time through the loop */
3528ebfedea0SLionel Sambuc pbt = DIGITS(&tmp);
3529ebfedea0SLionel Sambuc
3530ebfedea0SLionel Sambuc pa1 = DIGITS(a);
3531ebfedea0SLionel Sambuc for(ix = 0; ix < used; ++ix, ++pa1) {
3532ebfedea0SLionel Sambuc if(*pa1 == 0)
3533ebfedea0SLionel Sambuc continue;
3534ebfedea0SLionel Sambuc
3535ebfedea0SLionel Sambuc w = DIGIT(&tmp, ix + ix) + (*pa1 * *pa1);
3536ebfedea0SLionel Sambuc
3537ebfedea0SLionel Sambuc pbt[ix + ix] = ACCUM(w);
3538ebfedea0SLionel Sambuc k = CARRYOUT(w);
3539ebfedea0SLionel Sambuc
3540ebfedea0SLionel Sambuc /*
3541ebfedea0SLionel Sambuc The inner product is computed as:
3542ebfedea0SLionel Sambuc
3543ebfedea0SLionel Sambuc (C, S) = t[i,j] + 2 a[i] a[j] + C
3544ebfedea0SLionel Sambuc
3545ebfedea0SLionel Sambuc This can overflow what can be represented in an mp_word, and
3546ebfedea0SLionel Sambuc since C arithmetic does not provide any way to check for
3547ebfedea0SLionel Sambuc overflow, we have to check explicitly for overflow conditions
3548ebfedea0SLionel Sambuc before they happen.
3549ebfedea0SLionel Sambuc */
3550ebfedea0SLionel Sambuc for(jx = ix + 1, pa2 = DIGITS(a) + jx; jx < used; ++jx, ++pa2) {
3551ebfedea0SLionel Sambuc mp_word u = 0, v;
3552ebfedea0SLionel Sambuc
3553ebfedea0SLionel Sambuc /* Store this in a temporary to avoid indirections later */
3554ebfedea0SLionel Sambuc pt = pbt + ix + jx;
3555ebfedea0SLionel Sambuc
3556ebfedea0SLionel Sambuc /* Compute the multiplicative step */
3557ebfedea0SLionel Sambuc w = *pa1 * *pa2;
3558ebfedea0SLionel Sambuc
3559ebfedea0SLionel Sambuc /* If w is more than half MP_WORD_MAX, the doubling will
3560ebfedea0SLionel Sambuc overflow, and we need to record a carry out into the next
3561ebfedea0SLionel Sambuc word */
3562ebfedea0SLionel Sambuc u = (w >> (MP_WORD_BIT - 1)) & 1;
3563ebfedea0SLionel Sambuc
3564ebfedea0SLionel Sambuc /* Double what we've got, overflow will be ignored as defined
3565ebfedea0SLionel Sambuc for C arithmetic (we've already noted if it is to occur)
3566ebfedea0SLionel Sambuc */
3567ebfedea0SLionel Sambuc w *= 2;
3568ebfedea0SLionel Sambuc
3569ebfedea0SLionel Sambuc /* Compute the additive step */
3570ebfedea0SLionel Sambuc v = *pt + k;
3571ebfedea0SLionel Sambuc
3572ebfedea0SLionel Sambuc /* If we do not already have an overflow carry, check to see
3573ebfedea0SLionel Sambuc if the addition will cause one, and set the carry out if so
3574ebfedea0SLionel Sambuc */
3575ebfedea0SLionel Sambuc u |= ((MP_WORD_MAX - v) < w);
3576ebfedea0SLionel Sambuc
3577ebfedea0SLionel Sambuc /* Add in the rest, again ignoring overflow */
3578ebfedea0SLionel Sambuc w += v;
3579ebfedea0SLionel Sambuc
3580ebfedea0SLionel Sambuc /* Set the i,j digit of the output */
3581ebfedea0SLionel Sambuc *pt = ACCUM(w);
3582ebfedea0SLionel Sambuc
3583ebfedea0SLionel Sambuc /* Save carry information for the next iteration of the loop.
3584ebfedea0SLionel Sambuc This is why k must be an mp_word, instead of an mp_digit */
3585ebfedea0SLionel Sambuc k = CARRYOUT(w) | (u << DIGIT_BIT);
3586ebfedea0SLionel Sambuc
3587ebfedea0SLionel Sambuc } /* for(jx ...) */
3588ebfedea0SLionel Sambuc
3589ebfedea0SLionel Sambuc /* Set the last digit in the cycle and reset the carry */
3590ebfedea0SLionel Sambuc k = DIGIT(&tmp, ix + jx) + k;
3591ebfedea0SLionel Sambuc pbt[ix + jx] = ACCUM(k);
3592ebfedea0SLionel Sambuc k = CARRYOUT(k);
3593ebfedea0SLionel Sambuc
3594ebfedea0SLionel Sambuc /* If we are carrying out, propagate the carry to the next digit
3595ebfedea0SLionel Sambuc in the output. This may cascade, so we have to be somewhat
3596ebfedea0SLionel Sambuc circumspect -- but we will have enough precision in the output
3597ebfedea0SLionel Sambuc that we won't overflow
3598ebfedea0SLionel Sambuc */
3599ebfedea0SLionel Sambuc kx = 1;
3600ebfedea0SLionel Sambuc while(k) {
3601ebfedea0SLionel Sambuc k = pbt[ix + jx + kx] + 1;
3602ebfedea0SLionel Sambuc pbt[ix + jx + kx] = ACCUM(k);
3603ebfedea0SLionel Sambuc k = CARRYOUT(k);
3604ebfedea0SLionel Sambuc ++kx;
3605ebfedea0SLionel Sambuc }
3606ebfedea0SLionel Sambuc } /* for(ix ...) */
3607ebfedea0SLionel Sambuc
3608ebfedea0SLionel Sambuc s_mp_clamp(&tmp);
3609ebfedea0SLionel Sambuc s_mp_exch(&tmp, a);
3610ebfedea0SLionel Sambuc
3611ebfedea0SLionel Sambuc mp_clear(&tmp);
3612ebfedea0SLionel Sambuc
3613ebfedea0SLionel Sambuc return MP_OKAY;
3614ebfedea0SLionel Sambuc
3615ebfedea0SLionel Sambuc } /* end s_mp_sqr() */
3616ebfedea0SLionel Sambuc #endif
3617ebfedea0SLionel Sambuc
3618ebfedea0SLionel Sambuc /* }}} */
3619ebfedea0SLionel Sambuc
3620ebfedea0SLionel Sambuc /* {{{ s_mp_div(a, b) */
3621ebfedea0SLionel Sambuc
3622ebfedea0SLionel Sambuc /*
3623ebfedea0SLionel Sambuc s_mp_div(a, b)
3624ebfedea0SLionel Sambuc
3625ebfedea0SLionel Sambuc Compute a = a / b and b = a mod b. Assumes b > a.
3626ebfedea0SLionel Sambuc */
3627ebfedea0SLionel Sambuc
s_mp_div(mp_int * a,mp_int * b)3628ebfedea0SLionel Sambuc mp_err s_mp_div(mp_int *a, mp_int *b)
3629ebfedea0SLionel Sambuc {
3630ebfedea0SLionel Sambuc mp_int quot, rem, t;
3631ebfedea0SLionel Sambuc mp_word q;
3632ebfedea0SLionel Sambuc mp_err res;
3633ebfedea0SLionel Sambuc mp_digit d;
3634ebfedea0SLionel Sambuc int ix;
3635ebfedea0SLionel Sambuc
3636ebfedea0SLionel Sambuc if(mp_cmp_z(b) == 0)
3637ebfedea0SLionel Sambuc return MP_RANGE;
3638ebfedea0SLionel Sambuc
3639ebfedea0SLionel Sambuc /* Shortcut if b is power of two */
3640ebfedea0SLionel Sambuc if((ix = s_mp_ispow2(b)) >= 0) {
3641ebfedea0SLionel Sambuc mp_copy(a, b); /* need this for remainder */
3642ebfedea0SLionel Sambuc s_mp_div_2d(a, (mp_digit)ix);
3643ebfedea0SLionel Sambuc s_mp_mod_2d(b, (mp_digit)ix);
3644ebfedea0SLionel Sambuc
3645ebfedea0SLionel Sambuc return MP_OKAY;
3646ebfedea0SLionel Sambuc }
3647ebfedea0SLionel Sambuc
3648ebfedea0SLionel Sambuc /* Allocate space to store the quotient */
3649ebfedea0SLionel Sambuc if((res = mp_init_size(", USED(a))) != MP_OKAY)
3650ebfedea0SLionel Sambuc return res;
3651ebfedea0SLionel Sambuc
3652ebfedea0SLionel Sambuc /* A working temporary for division */
3653ebfedea0SLionel Sambuc if((res = mp_init_size(&t, USED(a))) != MP_OKAY)
3654ebfedea0SLionel Sambuc goto T;
3655ebfedea0SLionel Sambuc
3656ebfedea0SLionel Sambuc /* Allocate space for the remainder */
3657ebfedea0SLionel Sambuc if((res = mp_init_size(&rem, USED(a))) != MP_OKAY)
3658ebfedea0SLionel Sambuc goto REM;
3659ebfedea0SLionel Sambuc
3660ebfedea0SLionel Sambuc /* Normalize to optimize guessing */
3661ebfedea0SLionel Sambuc d = s_mp_norm(a, b);
3662ebfedea0SLionel Sambuc
3663ebfedea0SLionel Sambuc /* Perform the division itself...woo! */
3664ebfedea0SLionel Sambuc ix = USED(a) - 1;
3665ebfedea0SLionel Sambuc
3666ebfedea0SLionel Sambuc while(ix >= 0) {
3667ebfedea0SLionel Sambuc /* Find a partial substring of a which is at least b */
3668ebfedea0SLionel Sambuc while(s_mp_cmp(&rem, b) < 0 && ix >= 0) {
3669ebfedea0SLionel Sambuc if((res = s_mp_lshd(&rem, 1)) != MP_OKAY)
3670ebfedea0SLionel Sambuc goto CLEANUP;
3671ebfedea0SLionel Sambuc
3672ebfedea0SLionel Sambuc if((res = s_mp_lshd(", 1)) != MP_OKAY)
3673ebfedea0SLionel Sambuc goto CLEANUP;
3674ebfedea0SLionel Sambuc
3675ebfedea0SLionel Sambuc DIGIT(&rem, 0) = DIGIT(a, ix);
3676ebfedea0SLionel Sambuc s_mp_clamp(&rem);
3677ebfedea0SLionel Sambuc --ix;
3678ebfedea0SLionel Sambuc }
3679ebfedea0SLionel Sambuc
3680ebfedea0SLionel Sambuc /* If we didn't find one, we're finished dividing */
3681ebfedea0SLionel Sambuc if(s_mp_cmp(&rem, b) < 0)
3682ebfedea0SLionel Sambuc break;
3683ebfedea0SLionel Sambuc
3684ebfedea0SLionel Sambuc /* Compute a guess for the next quotient digit */
3685ebfedea0SLionel Sambuc q = DIGIT(&rem, USED(&rem) - 1);
3686ebfedea0SLionel Sambuc if(q <= DIGIT(b, USED(b) - 1) && USED(&rem) > 1)
3687ebfedea0SLionel Sambuc q = (q << DIGIT_BIT) | DIGIT(&rem, USED(&rem) - 2);
3688ebfedea0SLionel Sambuc
3689ebfedea0SLionel Sambuc q /= DIGIT(b, USED(b) - 1);
3690ebfedea0SLionel Sambuc
3691ebfedea0SLionel Sambuc /* The guess can be as much as RADIX + 1 */
3692ebfedea0SLionel Sambuc if(q >= RADIX)
3693ebfedea0SLionel Sambuc q = RADIX - 1;
3694ebfedea0SLionel Sambuc
3695ebfedea0SLionel Sambuc /* See what that multiplies out to */
3696ebfedea0SLionel Sambuc mp_copy(b, &t);
3697ebfedea0SLionel Sambuc if((res = s_mp_mul_d(&t, q)) != MP_OKAY)
3698ebfedea0SLionel Sambuc goto CLEANUP;
3699ebfedea0SLionel Sambuc
3700ebfedea0SLionel Sambuc /*
3701ebfedea0SLionel Sambuc If it's too big, back it off. We should not have to do this
3702ebfedea0SLionel Sambuc more than once, or, in rare cases, twice. Knuth describes a
3703ebfedea0SLionel Sambuc method by which this could be reduced to a maximum of once, but
3704ebfedea0SLionel Sambuc I didn't implement that here.
3705ebfedea0SLionel Sambuc */
3706ebfedea0SLionel Sambuc while(s_mp_cmp(&t, &rem) > 0) {
3707ebfedea0SLionel Sambuc --q;
3708ebfedea0SLionel Sambuc s_mp_sub(&t, b);
3709ebfedea0SLionel Sambuc }
3710ebfedea0SLionel Sambuc
3711ebfedea0SLionel Sambuc /* At this point, q should be the right next digit */
3712ebfedea0SLionel Sambuc if((res = s_mp_sub(&rem, &t)) != MP_OKAY)
3713ebfedea0SLionel Sambuc goto CLEANUP;
3714ebfedea0SLionel Sambuc
3715ebfedea0SLionel Sambuc /*
3716ebfedea0SLionel Sambuc Include the digit in the quotient. We allocated enough memory
3717ebfedea0SLionel Sambuc for any quotient we could ever possibly get, so we should not
3718ebfedea0SLionel Sambuc have to check for failures here
3719ebfedea0SLionel Sambuc */
3720ebfedea0SLionel Sambuc DIGIT(", 0) = q;
3721ebfedea0SLionel Sambuc }
3722ebfedea0SLionel Sambuc
3723ebfedea0SLionel Sambuc /* Denormalize remainder */
3724ebfedea0SLionel Sambuc if(d != 0)
3725ebfedea0SLionel Sambuc s_mp_div_2d(&rem, d);
3726ebfedea0SLionel Sambuc
3727ebfedea0SLionel Sambuc s_mp_clamp(");
3728ebfedea0SLionel Sambuc s_mp_clamp(&rem);
3729ebfedea0SLionel Sambuc
3730ebfedea0SLionel Sambuc /* Copy quotient back to output */
3731ebfedea0SLionel Sambuc s_mp_exch(", a);
3732ebfedea0SLionel Sambuc
3733ebfedea0SLionel Sambuc /* Copy remainder back to output */
3734ebfedea0SLionel Sambuc s_mp_exch(&rem, b);
3735ebfedea0SLionel Sambuc
3736ebfedea0SLionel Sambuc CLEANUP:
3737ebfedea0SLionel Sambuc mp_clear(&rem);
3738ebfedea0SLionel Sambuc REM:
3739ebfedea0SLionel Sambuc mp_clear(&t);
3740ebfedea0SLionel Sambuc T:
3741ebfedea0SLionel Sambuc mp_clear(");
3742ebfedea0SLionel Sambuc
3743ebfedea0SLionel Sambuc return res;
3744ebfedea0SLionel Sambuc
3745ebfedea0SLionel Sambuc } /* end s_mp_div() */
3746ebfedea0SLionel Sambuc
3747ebfedea0SLionel Sambuc /* }}} */
3748ebfedea0SLionel Sambuc
3749ebfedea0SLionel Sambuc /* {{{ s_mp_2expt(a, k) */
3750ebfedea0SLionel Sambuc
s_mp_2expt(mp_int * a,mp_digit k)3751ebfedea0SLionel Sambuc mp_err s_mp_2expt(mp_int *a, mp_digit k)
3752ebfedea0SLionel Sambuc {
3753ebfedea0SLionel Sambuc mp_err res;
3754ebfedea0SLionel Sambuc mp_size dig, bit;
3755ebfedea0SLionel Sambuc
3756ebfedea0SLionel Sambuc dig = k / DIGIT_BIT;
3757ebfedea0SLionel Sambuc bit = k % DIGIT_BIT;
3758ebfedea0SLionel Sambuc
3759ebfedea0SLionel Sambuc mp_zero(a);
3760ebfedea0SLionel Sambuc if((res = s_mp_pad(a, dig + 1)) != MP_OKAY)
3761ebfedea0SLionel Sambuc return res;
3762ebfedea0SLionel Sambuc
3763ebfedea0SLionel Sambuc DIGIT(a, dig) |= (1 << bit);
3764ebfedea0SLionel Sambuc
3765ebfedea0SLionel Sambuc return MP_OKAY;
3766ebfedea0SLionel Sambuc
3767ebfedea0SLionel Sambuc } /* end s_mp_2expt() */
3768ebfedea0SLionel Sambuc
3769ebfedea0SLionel Sambuc /* }}} */
3770ebfedea0SLionel Sambuc
3771ebfedea0SLionel Sambuc
3772ebfedea0SLionel Sambuc /* }}} */
3773ebfedea0SLionel Sambuc
3774ebfedea0SLionel Sambuc /* }}} */
3775ebfedea0SLionel Sambuc
3776ebfedea0SLionel Sambuc /* {{{ Primitive comparisons */
3777ebfedea0SLionel Sambuc
3778ebfedea0SLionel Sambuc /* {{{ s_mp_cmp(a, b) */
3779ebfedea0SLionel Sambuc
3780ebfedea0SLionel Sambuc /* Compare |a| <=> |b|, return 0 if equal, <0 if a<b, >0 if a>b */
s_mp_cmp(mp_int * a,mp_int * b)3781ebfedea0SLionel Sambuc int s_mp_cmp(mp_int *a, mp_int *b)
3782ebfedea0SLionel Sambuc {
3783ebfedea0SLionel Sambuc mp_size ua = USED(a), ub = USED(b);
3784ebfedea0SLionel Sambuc
3785ebfedea0SLionel Sambuc if(ua > ub)
3786ebfedea0SLionel Sambuc return MP_GT;
3787ebfedea0SLionel Sambuc else if(ua < ub)
3788ebfedea0SLionel Sambuc return MP_LT;
3789ebfedea0SLionel Sambuc else {
3790ebfedea0SLionel Sambuc int ix = ua - 1;
3791ebfedea0SLionel Sambuc mp_digit *ap = DIGITS(a) + ix, *bp = DIGITS(b) + ix;
3792ebfedea0SLionel Sambuc
3793ebfedea0SLionel Sambuc while(ix >= 0) {
3794ebfedea0SLionel Sambuc if(*ap > *bp)
3795ebfedea0SLionel Sambuc return MP_GT;
3796ebfedea0SLionel Sambuc else if(*ap < *bp)
3797ebfedea0SLionel Sambuc return MP_LT;
3798ebfedea0SLionel Sambuc
3799ebfedea0SLionel Sambuc --ap; --bp; --ix;
3800ebfedea0SLionel Sambuc }
3801ebfedea0SLionel Sambuc
3802ebfedea0SLionel Sambuc return MP_EQ;
3803ebfedea0SLionel Sambuc }
3804ebfedea0SLionel Sambuc
3805ebfedea0SLionel Sambuc } /* end s_mp_cmp() */
3806ebfedea0SLionel Sambuc
3807ebfedea0SLionel Sambuc /* }}} */
3808ebfedea0SLionel Sambuc
3809ebfedea0SLionel Sambuc /* {{{ s_mp_cmp_d(a, d) */
3810ebfedea0SLionel Sambuc
3811ebfedea0SLionel Sambuc /* Compare |a| <=> d, return 0 if equal, <0 if a<d, >0 if a>d */
s_mp_cmp_d(mp_int * a,mp_digit d)3812ebfedea0SLionel Sambuc int s_mp_cmp_d(mp_int *a, mp_digit d)
3813ebfedea0SLionel Sambuc {
3814ebfedea0SLionel Sambuc mp_size ua = USED(a);
3815ebfedea0SLionel Sambuc mp_digit *ap = DIGITS(a);
3816ebfedea0SLionel Sambuc
3817ebfedea0SLionel Sambuc if(ua > 1)
3818ebfedea0SLionel Sambuc return MP_GT;
3819ebfedea0SLionel Sambuc
3820ebfedea0SLionel Sambuc if(*ap < d)
3821ebfedea0SLionel Sambuc return MP_LT;
3822ebfedea0SLionel Sambuc else if(*ap > d)
3823ebfedea0SLionel Sambuc return MP_GT;
3824ebfedea0SLionel Sambuc else
3825ebfedea0SLionel Sambuc return MP_EQ;
3826ebfedea0SLionel Sambuc
3827ebfedea0SLionel Sambuc } /* end s_mp_cmp_d() */
3828ebfedea0SLionel Sambuc
3829ebfedea0SLionel Sambuc /* }}} */
3830ebfedea0SLionel Sambuc
3831ebfedea0SLionel Sambuc /* {{{ s_mp_ispow2(v) */
3832ebfedea0SLionel Sambuc
3833ebfedea0SLionel Sambuc /*
3834ebfedea0SLionel Sambuc Returns -1 if the value is not a power of two; otherwise, it returns
3835ebfedea0SLionel Sambuc k such that v = 2^k, i.e. lg(v).
3836ebfedea0SLionel Sambuc */
s_mp_ispow2(mp_int * v)3837ebfedea0SLionel Sambuc int s_mp_ispow2(mp_int *v)
3838ebfedea0SLionel Sambuc {
3839ebfedea0SLionel Sambuc mp_digit d, *dp;
3840ebfedea0SLionel Sambuc mp_size uv = USED(v);
3841ebfedea0SLionel Sambuc int extra = 0, ix;
3842ebfedea0SLionel Sambuc
3843ebfedea0SLionel Sambuc d = DIGIT(v, uv - 1); /* most significant digit of v */
3844ebfedea0SLionel Sambuc
3845ebfedea0SLionel Sambuc while(d && ((d & 1) == 0)) {
3846ebfedea0SLionel Sambuc d >>= 1;
3847ebfedea0SLionel Sambuc ++extra;
3848ebfedea0SLionel Sambuc }
3849ebfedea0SLionel Sambuc
3850ebfedea0SLionel Sambuc if(d == 1) {
3851ebfedea0SLionel Sambuc ix = uv - 2;
3852ebfedea0SLionel Sambuc dp = DIGITS(v) + ix;
3853ebfedea0SLionel Sambuc
3854ebfedea0SLionel Sambuc while(ix >= 0) {
3855ebfedea0SLionel Sambuc if(*dp)
3856ebfedea0SLionel Sambuc return -1; /* not a power of two */
3857ebfedea0SLionel Sambuc
3858ebfedea0SLionel Sambuc --dp; --ix;
3859ebfedea0SLionel Sambuc }
3860ebfedea0SLionel Sambuc
3861ebfedea0SLionel Sambuc return ((uv - 1) * DIGIT_BIT) + extra;
3862ebfedea0SLionel Sambuc }
3863ebfedea0SLionel Sambuc
3864ebfedea0SLionel Sambuc return -1;
3865ebfedea0SLionel Sambuc
3866ebfedea0SLionel Sambuc } /* end s_mp_ispow2() */
3867ebfedea0SLionel Sambuc
3868ebfedea0SLionel Sambuc /* }}} */
3869ebfedea0SLionel Sambuc
3870ebfedea0SLionel Sambuc /* {{{ s_mp_ispow2d(d) */
3871ebfedea0SLionel Sambuc
s_mp_ispow2d(mp_digit d)3872ebfedea0SLionel Sambuc int s_mp_ispow2d(mp_digit d)
3873ebfedea0SLionel Sambuc {
3874ebfedea0SLionel Sambuc int pow = 0;
3875ebfedea0SLionel Sambuc
3876ebfedea0SLionel Sambuc while((d & 1) == 0) {
3877ebfedea0SLionel Sambuc ++pow; d >>= 1;
3878ebfedea0SLionel Sambuc }
3879ebfedea0SLionel Sambuc
3880ebfedea0SLionel Sambuc if(d == 1)
3881ebfedea0SLionel Sambuc return pow;
3882ebfedea0SLionel Sambuc
3883ebfedea0SLionel Sambuc return -1;
3884ebfedea0SLionel Sambuc
3885ebfedea0SLionel Sambuc } /* end s_mp_ispow2d() */
3886ebfedea0SLionel Sambuc
3887ebfedea0SLionel Sambuc /* }}} */
3888ebfedea0SLionel Sambuc
3889ebfedea0SLionel Sambuc /* }}} */
3890ebfedea0SLionel Sambuc
3891ebfedea0SLionel Sambuc /* {{{ Primitive I/O helpers */
3892ebfedea0SLionel Sambuc
3893ebfedea0SLionel Sambuc /* {{{ s_mp_tovalue(ch, r) */
3894ebfedea0SLionel Sambuc
3895ebfedea0SLionel Sambuc /*
3896ebfedea0SLionel Sambuc Convert the given character to its digit value, in the given radix.
3897ebfedea0SLionel Sambuc If the given character is not understood in the given radix, -1 is
3898ebfedea0SLionel Sambuc returned. Otherwise the digit's numeric value is returned.
3899ebfedea0SLionel Sambuc
3900ebfedea0SLionel Sambuc The results will be odd if you use a radix < 2 or > 62, you are
3901ebfedea0SLionel Sambuc expected to know what you're up to.
3902ebfedea0SLionel Sambuc */
s_mp_tovalue(char ch,int r)3903ebfedea0SLionel Sambuc int s_mp_tovalue(char ch, int r)
3904ebfedea0SLionel Sambuc {
3905ebfedea0SLionel Sambuc int val, xch;
3906ebfedea0SLionel Sambuc
3907ebfedea0SLionel Sambuc if(r > 36)
3908ebfedea0SLionel Sambuc xch = ch;
3909ebfedea0SLionel Sambuc else
3910ebfedea0SLionel Sambuc xch = toupper(ch);
3911ebfedea0SLionel Sambuc
3912ebfedea0SLionel Sambuc if(isdigit(xch))
3913ebfedea0SLionel Sambuc val = xch - '0';
3914ebfedea0SLionel Sambuc else if(isupper(xch))
3915ebfedea0SLionel Sambuc val = xch - 'A' + 10;
3916ebfedea0SLionel Sambuc else if(islower(xch))
3917ebfedea0SLionel Sambuc val = xch - 'a' + 36;
3918ebfedea0SLionel Sambuc else if(xch == '+')
3919ebfedea0SLionel Sambuc val = 62;
3920ebfedea0SLionel Sambuc else if(xch == '/')
3921ebfedea0SLionel Sambuc val = 63;
3922ebfedea0SLionel Sambuc else
3923ebfedea0SLionel Sambuc return -1;
3924ebfedea0SLionel Sambuc
3925ebfedea0SLionel Sambuc if(val < 0 || val >= r)
3926ebfedea0SLionel Sambuc return -1;
3927ebfedea0SLionel Sambuc
3928ebfedea0SLionel Sambuc return val;
3929ebfedea0SLionel Sambuc
3930ebfedea0SLionel Sambuc } /* end s_mp_tovalue() */
3931ebfedea0SLionel Sambuc
3932ebfedea0SLionel Sambuc /* }}} */
3933ebfedea0SLionel Sambuc
3934ebfedea0SLionel Sambuc /* {{{ s_mp_todigit(val, r, low) */
3935ebfedea0SLionel Sambuc
3936ebfedea0SLionel Sambuc /*
3937ebfedea0SLionel Sambuc Convert val to a radix-r digit, if possible. If val is out of range
3938ebfedea0SLionel Sambuc for r, returns zero. Otherwise, returns an ASCII character denoting
3939ebfedea0SLionel Sambuc the value in the given radix.
3940ebfedea0SLionel Sambuc
3941ebfedea0SLionel Sambuc The results may be odd if you use a radix < 2 or > 64, you are
3942ebfedea0SLionel Sambuc expected to know what you're doing.
3943ebfedea0SLionel Sambuc */
3944ebfedea0SLionel Sambuc
s_mp_todigit(int val,int r,int low)3945ebfedea0SLionel Sambuc char s_mp_todigit(int val, int r, int low)
3946ebfedea0SLionel Sambuc {
3947ebfedea0SLionel Sambuc char ch;
3948ebfedea0SLionel Sambuc
3949ebfedea0SLionel Sambuc if(val < 0 || val >= r)
3950ebfedea0SLionel Sambuc return 0;
3951ebfedea0SLionel Sambuc
3952ebfedea0SLionel Sambuc ch = s_dmap_1[val];
3953ebfedea0SLionel Sambuc
3954ebfedea0SLionel Sambuc if(r <= 36 && low)
3955ebfedea0SLionel Sambuc ch = tolower(ch);
3956ebfedea0SLionel Sambuc
3957ebfedea0SLionel Sambuc return ch;
3958ebfedea0SLionel Sambuc
3959ebfedea0SLionel Sambuc } /* end s_mp_todigit() */
3960ebfedea0SLionel Sambuc
3961ebfedea0SLionel Sambuc /* }}} */
3962ebfedea0SLionel Sambuc
3963ebfedea0SLionel Sambuc /* {{{ s_mp_outlen(bits, radix) */
3964ebfedea0SLionel Sambuc
3965ebfedea0SLionel Sambuc /*
3966ebfedea0SLionel Sambuc Return an estimate for how long a string is needed to hold a radix
3967ebfedea0SLionel Sambuc r representation of a number with 'bits' significant bits.
3968ebfedea0SLionel Sambuc
3969ebfedea0SLionel Sambuc Does not include space for a sign or a NUL terminator.
3970ebfedea0SLionel Sambuc */
s_mp_outlen(int bits,int r)3971ebfedea0SLionel Sambuc int s_mp_outlen(int bits, int r)
3972ebfedea0SLionel Sambuc {
3973ebfedea0SLionel Sambuc return (int)((double)bits * LOG_V_2(r));
3974ebfedea0SLionel Sambuc
3975ebfedea0SLionel Sambuc } /* end s_mp_outlen() */
3976ebfedea0SLionel Sambuc
3977ebfedea0SLionel Sambuc /* }}} */
3978ebfedea0SLionel Sambuc
3979ebfedea0SLionel Sambuc /* }}} */
3980ebfedea0SLionel Sambuc
3981ebfedea0SLionel Sambuc /*------------------------------------------------------------------------*/
3982ebfedea0SLionel Sambuc /* HERE THERE BE DRAGONS */
3983ebfedea0SLionel Sambuc /* crc==4242132123, version==2, Sat Feb 02 06:43:52 2002 */
3984ebfedea0SLionel Sambuc
3985ebfedea0SLionel Sambuc /* Source: /cvs/libtom/libtommath/mtest/mpi.c,v */
3986ebfedea0SLionel Sambuc /* Revision: 1.2 */
3987ebfedea0SLionel Sambuc /* Date: 2005/05/05 14:38:47 */
3988