1*13066SDina.Nimeh@Sun.COM /* BEGIN CSTYLED */
25697Smcpowers /*
35697Smcpowers * mpi.c
45697Smcpowers *
55697Smcpowers * Arbitrary precision integer arithmetic library
65697Smcpowers *
75697Smcpowers * ***** BEGIN LICENSE BLOCK *****
85697Smcpowers * Version: MPL 1.1/GPL 2.0/LGPL 2.1
95697Smcpowers *
105697Smcpowers * The contents of this file are subject to the Mozilla Public License Version
115697Smcpowers * 1.1 (the "License"); you may not use this file except in compliance with
125697Smcpowers * the License. You may obtain a copy of the License at
135697Smcpowers * http://www.mozilla.org/MPL/
145697Smcpowers *
155697Smcpowers * Software distributed under the License is distributed on an "AS IS" basis,
165697Smcpowers * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
175697Smcpowers * for the specific language governing rights and limitations under the
185697Smcpowers * License.
195697Smcpowers *
205697Smcpowers * The Original Code is the MPI Arbitrary Precision Integer Arithmetic library.
215697Smcpowers *
225697Smcpowers * The Initial Developer of the Original Code is
235697Smcpowers * Michael J. Fromberger.
245697Smcpowers * Portions created by the Initial Developer are Copyright (C) 1998
255697Smcpowers * the Initial Developer. All Rights Reserved.
265697Smcpowers *
275697Smcpowers * Contributor(s):
285697Smcpowers * Netscape Communications Corporation
295697Smcpowers * Douglas Stebila <douglas@stebila.ca> of Sun Laboratories.
305697Smcpowers *
315697Smcpowers * Alternatively, the contents of this file may be used under the terms of
325697Smcpowers * either the GNU General Public License Version 2 or later (the "GPL"), or
335697Smcpowers * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
345697Smcpowers * in which case the provisions of the GPL or the LGPL are applicable instead
355697Smcpowers * of those above. If you wish to allow use of your version of this file only
365697Smcpowers * under the terms of either the GPL or the LGPL, and not to allow others to
375697Smcpowers * use your version of this file under the terms of the MPL, indicate your
385697Smcpowers * decision by deleting the provisions above and replace them with the notice
395697Smcpowers * and other provisions required by the GPL or the LGPL. If you do not delete
405697Smcpowers * the provisions above, a recipient may use your version of this file under
415697Smcpowers * the terms of any one of the MPL, the GPL or the LGPL.
425697Smcpowers *
435697Smcpowers * ***** END LICENSE BLOCK ***** */
445697Smcpowers /*
45*13066SDina.Nimeh@Sun.COM * Copyright (c) 2007, 2010, Oracle and/or its affiliates. All rights reserved.
465697Smcpowers *
475697Smcpowers * Sun elects to use this software under the MPL license.
485697Smcpowers */
495697Smcpowers
505697Smcpowers /* $Id: mpi.c,v 1.45 2006/09/29 20:12:21 alexei.volkov.bugs%sun.com Exp $ */
515697Smcpowers
525697Smcpowers #include "mpi-priv.h"
535697Smcpowers #if defined(OSF1)
545697Smcpowers #include <c_asm.h>
555697Smcpowers #endif
565697Smcpowers
575697Smcpowers #if MP_LOGTAB
585697Smcpowers /*
595697Smcpowers A table of the logs of 2 for various bases (the 0 and 1 entries of
605697Smcpowers this table are meaningless and should not be referenced).
615697Smcpowers
625697Smcpowers This table is used to compute output lengths for the mp_toradix()
635697Smcpowers function. Since a number n in radix r takes up about log_r(n)
645697Smcpowers digits, we estimate the output size by taking the least integer
655697Smcpowers greater than log_r(n), where:
665697Smcpowers
675697Smcpowers log_r(n) = log_2(n) * log_r(2)
685697Smcpowers
695697Smcpowers This table, therefore, is a table of log_r(2) for 2 <= r <= 36,
705697Smcpowers which are the output bases supported.
715697Smcpowers */
725697Smcpowers #include "logtab.h"
735697Smcpowers #endif
745697Smcpowers
755697Smcpowers /* {{{ Constant strings */
765697Smcpowers
775697Smcpowers /* Constant strings returned by mp_strerror() */
785697Smcpowers static const char *mp_err_string[] = {
795697Smcpowers "unknown result code", /* say what? */
805697Smcpowers "boolean true", /* MP_OKAY, MP_YES */
815697Smcpowers "boolean false", /* MP_NO */
825697Smcpowers "out of memory", /* MP_MEM */
835697Smcpowers "argument out of range", /* MP_RANGE */
845697Smcpowers "invalid input parameter", /* MP_BADARG */
855697Smcpowers "result is undefined" /* MP_UNDEF */
865697Smcpowers };
875697Smcpowers
885697Smcpowers /* Value to digit maps for radix conversion */
895697Smcpowers
905697Smcpowers /* s_dmap_1 - standard digits and letters */
915697Smcpowers static const char *s_dmap_1 =
925697Smcpowers "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz+/";
935697Smcpowers
945697Smcpowers /* }}} */
955697Smcpowers
965697Smcpowers unsigned long mp_allocs;
975697Smcpowers unsigned long mp_frees;
985697Smcpowers unsigned long mp_copies;
995697Smcpowers
1005697Smcpowers /* {{{ Default precision manipulation */
1015697Smcpowers
1025697Smcpowers /* Default precision for newly created mp_int's */
1035697Smcpowers static mp_size s_mp_defprec = MP_DEFPREC;
1045697Smcpowers
mp_get_prec(void)1055697Smcpowers mp_size mp_get_prec(void)
1065697Smcpowers {
1075697Smcpowers return s_mp_defprec;
1085697Smcpowers
1095697Smcpowers } /* end mp_get_prec() */
1105697Smcpowers
mp_set_prec(mp_size prec)1115697Smcpowers void mp_set_prec(mp_size prec)
1125697Smcpowers {
1135697Smcpowers if(prec == 0)
1145697Smcpowers s_mp_defprec = MP_DEFPREC;
1155697Smcpowers else
1165697Smcpowers s_mp_defprec = prec;
1175697Smcpowers
1185697Smcpowers } /* end mp_set_prec() */
1195697Smcpowers
1205697Smcpowers /* }}} */
1215697Smcpowers
1225697Smcpowers /*------------------------------------------------------------------------*/
1235697Smcpowers /* {{{ mp_init(mp, kmflag) */
1245697Smcpowers
1255697Smcpowers /*
1265697Smcpowers mp_init(mp, kmflag)
1275697Smcpowers
1285697Smcpowers Initialize a new zero-valued mp_int. Returns MP_OKAY if successful,
1295697Smcpowers MP_MEM if memory could not be allocated for the structure.
1305697Smcpowers */
1315697Smcpowers
mp_init(mp_int * mp,int kmflag)1325697Smcpowers mp_err mp_init(mp_int *mp, int kmflag)
1335697Smcpowers {
1345697Smcpowers return mp_init_size(mp, s_mp_defprec, kmflag);
1355697Smcpowers
1365697Smcpowers } /* end mp_init() */
1375697Smcpowers
1385697Smcpowers /* }}} */
1395697Smcpowers
1405697Smcpowers /* {{{ mp_init_size(mp, prec, kmflag) */
1415697Smcpowers
1425697Smcpowers /*
1435697Smcpowers mp_init_size(mp, prec, kmflag)
1445697Smcpowers
1455697Smcpowers Initialize a new zero-valued mp_int with at least the given
1465697Smcpowers precision; returns MP_OKAY if successful, or MP_MEM if memory could
1475697Smcpowers not be allocated for the structure.
1485697Smcpowers */
1495697Smcpowers
mp_init_size(mp_int * mp,mp_size prec,int kmflag)1505697Smcpowers mp_err mp_init_size(mp_int *mp, mp_size prec, int kmflag)
1515697Smcpowers {
1525697Smcpowers ARGCHK(mp != NULL && prec > 0, MP_BADARG);
1535697Smcpowers
1545697Smcpowers prec = MP_ROUNDUP(prec, s_mp_defprec);
1555697Smcpowers if((DIGITS(mp) = s_mp_alloc(prec, sizeof(mp_digit), kmflag)) == NULL)
1565697Smcpowers return MP_MEM;
1575697Smcpowers
1585697Smcpowers SIGN(mp) = ZPOS;
1595697Smcpowers USED(mp) = 1;
1605697Smcpowers ALLOC(mp) = prec;
161*13066SDina.Nimeh@Sun.COM FLAG(mp) = kmflag;
1625697Smcpowers
1635697Smcpowers return MP_OKAY;
1645697Smcpowers
1655697Smcpowers } /* end mp_init_size() */
1665697Smcpowers
1675697Smcpowers /* }}} */
1685697Smcpowers
1695697Smcpowers /* {{{ mp_init_copy(mp, from) */
1705697Smcpowers
1715697Smcpowers /*
1725697Smcpowers mp_init_copy(mp, from)
1735697Smcpowers
1745697Smcpowers Initialize mp as an exact copy of from. Returns MP_OKAY if
1755697Smcpowers successful, MP_MEM if memory could not be allocated for the new
1765697Smcpowers structure.
1775697Smcpowers */
1785697Smcpowers
mp_init_copy(mp_int * mp,const mp_int * from)1795697Smcpowers mp_err mp_init_copy(mp_int *mp, const mp_int *from)
1805697Smcpowers {
1815697Smcpowers ARGCHK(mp != NULL && from != NULL, MP_BADARG);
1825697Smcpowers
1835697Smcpowers if(mp == from)
1845697Smcpowers return MP_OKAY;
1855697Smcpowers
1865697Smcpowers if((DIGITS(mp) = s_mp_alloc(ALLOC(from), sizeof(mp_digit), FLAG(from))) == NULL)
1875697Smcpowers return MP_MEM;
1885697Smcpowers
1895697Smcpowers s_mp_copy(DIGITS(from), DIGITS(mp), USED(from));
1905697Smcpowers USED(mp) = USED(from);
1915697Smcpowers ALLOC(mp) = ALLOC(from);
1925697Smcpowers SIGN(mp) = SIGN(from);
1935697Smcpowers FLAG(mp) = FLAG(from);
1945697Smcpowers
1955697Smcpowers return MP_OKAY;
1965697Smcpowers
1975697Smcpowers } /* end mp_init_copy() */
1985697Smcpowers
1995697Smcpowers /* }}} */
2005697Smcpowers
2015697Smcpowers /* {{{ mp_copy(from, to) */
2025697Smcpowers
2035697Smcpowers /*
2045697Smcpowers mp_copy(from, to)
2055697Smcpowers
2065697Smcpowers Copies the mp_int 'from' to the mp_int 'to'. It is presumed that
2075697Smcpowers 'to' has already been initialized (if not, use mp_init_copy()
2085697Smcpowers instead). If 'from' and 'to' are identical, nothing happens.
2095697Smcpowers */
2105697Smcpowers
mp_copy(const mp_int * from,mp_int * to)2115697Smcpowers mp_err mp_copy(const mp_int *from, mp_int *to)
2125697Smcpowers {
2135697Smcpowers ARGCHK(from != NULL && to != NULL, MP_BADARG);
2145697Smcpowers
2155697Smcpowers if(from == to)
2165697Smcpowers return MP_OKAY;
2175697Smcpowers
2185697Smcpowers ++mp_copies;
2195697Smcpowers { /* copy */
2205697Smcpowers mp_digit *tmp;
2215697Smcpowers
2225697Smcpowers /*
2235697Smcpowers If the allocated buffer in 'to' already has enough space to hold
2245697Smcpowers all the used digits of 'from', we'll re-use it to avoid hitting
2255697Smcpowers the memory allocater more than necessary; otherwise, we'd have
2265697Smcpowers to grow anyway, so we just allocate a hunk and make the copy as
2275697Smcpowers usual
2285697Smcpowers */
2295697Smcpowers if(ALLOC(to) >= USED(from)) {
2305697Smcpowers s_mp_setz(DIGITS(to) + USED(from), ALLOC(to) - USED(from));
2315697Smcpowers s_mp_copy(DIGITS(from), DIGITS(to), USED(from));
2325697Smcpowers
2335697Smcpowers } else {
2345697Smcpowers if((tmp = s_mp_alloc(ALLOC(from), sizeof(mp_digit), FLAG(from))) == NULL)
2355697Smcpowers return MP_MEM;
2365697Smcpowers
2375697Smcpowers s_mp_copy(DIGITS(from), tmp, USED(from));
2385697Smcpowers
2395697Smcpowers if(DIGITS(to) != NULL) {
2405697Smcpowers #if MP_CRYPTO
2415697Smcpowers s_mp_setz(DIGITS(to), ALLOC(to));
2425697Smcpowers #endif
2435697Smcpowers s_mp_free(DIGITS(to), ALLOC(to));
2445697Smcpowers }
2455697Smcpowers
2465697Smcpowers DIGITS(to) = tmp;
2475697Smcpowers ALLOC(to) = ALLOC(from);
2485697Smcpowers }
2495697Smcpowers
2505697Smcpowers /* Copy the precision and sign from the original */
2515697Smcpowers USED(to) = USED(from);
2525697Smcpowers SIGN(to) = SIGN(from);
253*13066SDina.Nimeh@Sun.COM FLAG(to) = FLAG(from);
2545697Smcpowers } /* end copy */
2555697Smcpowers
2565697Smcpowers return MP_OKAY;
2575697Smcpowers
2585697Smcpowers } /* end mp_copy() */
2595697Smcpowers
2605697Smcpowers /* }}} */
2615697Smcpowers
2625697Smcpowers /* {{{ mp_exch(mp1, mp2) */
2635697Smcpowers
2645697Smcpowers /*
2655697Smcpowers mp_exch(mp1, mp2)
2665697Smcpowers
2675697Smcpowers Exchange mp1 and mp2 without allocating any intermediate memory
2685697Smcpowers (well, unless you count the stack space needed for this call and the
2695697Smcpowers locals it creates...). This cannot fail.
2705697Smcpowers */
2715697Smcpowers
mp_exch(mp_int * mp1,mp_int * mp2)2725697Smcpowers void mp_exch(mp_int *mp1, mp_int *mp2)
2735697Smcpowers {
2745697Smcpowers #if MP_ARGCHK == 2
2755697Smcpowers assert(mp1 != NULL && mp2 != NULL);
2765697Smcpowers #else
2775697Smcpowers if(mp1 == NULL || mp2 == NULL)
2785697Smcpowers return;
2795697Smcpowers #endif
2805697Smcpowers
2815697Smcpowers s_mp_exch(mp1, mp2);
2825697Smcpowers
2835697Smcpowers } /* end mp_exch() */
2845697Smcpowers
2855697Smcpowers /* }}} */
2865697Smcpowers
2875697Smcpowers /* {{{ mp_clear(mp) */
2885697Smcpowers
2895697Smcpowers /*
2905697Smcpowers mp_clear(mp)
2915697Smcpowers
2925697Smcpowers Release the storage used by an mp_int, and void its fields so that
2935697Smcpowers if someone calls mp_clear() again for the same int later, we won't
2945697Smcpowers get tollchocked.
2955697Smcpowers */
2965697Smcpowers
mp_clear(mp_int * mp)2975697Smcpowers void mp_clear(mp_int *mp)
2985697Smcpowers {
2995697Smcpowers if(mp == NULL)
3005697Smcpowers return;
3015697Smcpowers
3025697Smcpowers if(DIGITS(mp) != NULL) {
3035697Smcpowers #if MP_CRYPTO
3045697Smcpowers s_mp_setz(DIGITS(mp), ALLOC(mp));
3055697Smcpowers #endif
3065697Smcpowers s_mp_free(DIGITS(mp), ALLOC(mp));
3075697Smcpowers DIGITS(mp) = NULL;
3085697Smcpowers }
3095697Smcpowers
3105697Smcpowers USED(mp) = 0;
3115697Smcpowers ALLOC(mp) = 0;
3125697Smcpowers
3135697Smcpowers } /* end mp_clear() */
3145697Smcpowers
3155697Smcpowers /* }}} */
3165697Smcpowers
3175697Smcpowers /* {{{ mp_zero(mp) */
3185697Smcpowers
3195697Smcpowers /*
3205697Smcpowers mp_zero(mp)
3215697Smcpowers
3225697Smcpowers Set mp to zero. Does not change the allocated size of the structure,
3235697Smcpowers and therefore cannot fail (except on a bad argument, which we ignore)
3245697Smcpowers */
mp_zero(mp_int * mp)3255697Smcpowers void mp_zero(mp_int *mp)
3265697Smcpowers {
3275697Smcpowers if(mp == NULL)
3285697Smcpowers return;
3295697Smcpowers
3305697Smcpowers s_mp_setz(DIGITS(mp), ALLOC(mp));
3315697Smcpowers USED(mp) = 1;
3325697Smcpowers SIGN(mp) = ZPOS;
3335697Smcpowers
3345697Smcpowers } /* end mp_zero() */
3355697Smcpowers
3365697Smcpowers /* }}} */
3375697Smcpowers
3385697Smcpowers /* {{{ mp_set(mp, d) */
3395697Smcpowers
mp_set(mp_int * mp,mp_digit d)3405697Smcpowers void mp_set(mp_int *mp, mp_digit d)
3415697Smcpowers {
3425697Smcpowers if(mp == NULL)
3435697Smcpowers return;
3445697Smcpowers
3455697Smcpowers mp_zero(mp);
3465697Smcpowers DIGIT(mp, 0) = d;
3475697Smcpowers
3485697Smcpowers } /* end mp_set() */
3495697Smcpowers
3505697Smcpowers /* }}} */
3515697Smcpowers
3525697Smcpowers /* {{{ mp_set_int(mp, z) */
3535697Smcpowers
mp_set_int(mp_int * mp,long z)3545697Smcpowers mp_err mp_set_int(mp_int *mp, long z)
3555697Smcpowers {
3565697Smcpowers int ix;
3575697Smcpowers unsigned long v = labs(z);
3585697Smcpowers mp_err res;
3595697Smcpowers
3605697Smcpowers ARGCHK(mp != NULL, MP_BADARG);
3615697Smcpowers
3625697Smcpowers mp_zero(mp);
3635697Smcpowers if(z == 0)
3645697Smcpowers return MP_OKAY; /* shortcut for zero */
3655697Smcpowers
3665697Smcpowers if (sizeof v <= sizeof(mp_digit)) {
3675697Smcpowers DIGIT(mp,0) = v;
3685697Smcpowers } else {
3695697Smcpowers for (ix = sizeof(long) - 1; ix >= 0; ix--) {
3705697Smcpowers if ((res = s_mp_mul_d(mp, (UCHAR_MAX + 1))) != MP_OKAY)
3715697Smcpowers return res;
3725697Smcpowers
3735697Smcpowers res = s_mp_add_d(mp, (mp_digit)((v >> (ix * CHAR_BIT)) & UCHAR_MAX));
3745697Smcpowers if (res != MP_OKAY)
3755697Smcpowers return res;
3765697Smcpowers }
3775697Smcpowers }
3785697Smcpowers if(z < 0)
3795697Smcpowers SIGN(mp) = NEG;
3805697Smcpowers
3815697Smcpowers return MP_OKAY;
3825697Smcpowers
3835697Smcpowers } /* end mp_set_int() */
3845697Smcpowers
3855697Smcpowers /* }}} */
3865697Smcpowers
3875697Smcpowers /* {{{ mp_set_ulong(mp, z) */
3885697Smcpowers
mp_set_ulong(mp_int * mp,unsigned long z)3895697Smcpowers mp_err mp_set_ulong(mp_int *mp, unsigned long z)
3905697Smcpowers {
3915697Smcpowers int ix;
3925697Smcpowers mp_err res;
3935697Smcpowers
3945697Smcpowers ARGCHK(mp != NULL, MP_BADARG);
3955697Smcpowers
3965697Smcpowers mp_zero(mp);
3975697Smcpowers if(z == 0)
3985697Smcpowers return MP_OKAY; /* shortcut for zero */
3995697Smcpowers
4005697Smcpowers if (sizeof z <= sizeof(mp_digit)) {
4015697Smcpowers DIGIT(mp,0) = z;
4025697Smcpowers } else {
4035697Smcpowers for (ix = sizeof(long) - 1; ix >= 0; ix--) {
4045697Smcpowers if ((res = s_mp_mul_d(mp, (UCHAR_MAX + 1))) != MP_OKAY)
4055697Smcpowers return res;
4065697Smcpowers
4075697Smcpowers res = s_mp_add_d(mp, (mp_digit)((z >> (ix * CHAR_BIT)) & UCHAR_MAX));
4085697Smcpowers if (res != MP_OKAY)
4095697Smcpowers return res;
4105697Smcpowers }
4115697Smcpowers }
4125697Smcpowers return MP_OKAY;
4135697Smcpowers } /* end mp_set_ulong() */
4145697Smcpowers
4155697Smcpowers /* }}} */
4165697Smcpowers
4175697Smcpowers /*------------------------------------------------------------------------*/
4185697Smcpowers /* {{{ Digit arithmetic */
4195697Smcpowers
4205697Smcpowers /* {{{ mp_add_d(a, d, b) */
4215697Smcpowers
4225697Smcpowers /*
4235697Smcpowers mp_add_d(a, d, b)
4245697Smcpowers
4255697Smcpowers Compute the sum b = a + d, for a single digit d. Respects the sign of
4265697Smcpowers its primary addend (single digits are unsigned anyway).
4275697Smcpowers */
4285697Smcpowers
mp_add_d(const mp_int * a,mp_digit d,mp_int * b)4295697Smcpowers mp_err mp_add_d(const mp_int *a, mp_digit d, mp_int *b)
4305697Smcpowers {
4315697Smcpowers mp_int tmp;
4325697Smcpowers mp_err res;
4335697Smcpowers
4345697Smcpowers ARGCHK(a != NULL && b != NULL, MP_BADARG);
4355697Smcpowers
4365697Smcpowers if((res = mp_init_copy(&tmp, a)) != MP_OKAY)
4375697Smcpowers return res;
4385697Smcpowers
4395697Smcpowers if(SIGN(&tmp) == ZPOS) {
4405697Smcpowers if((res = s_mp_add_d(&tmp, d)) != MP_OKAY)
4415697Smcpowers goto CLEANUP;
4425697Smcpowers } else if(s_mp_cmp_d(&tmp, d) >= 0) {
4435697Smcpowers if((res = s_mp_sub_d(&tmp, d)) != MP_OKAY)
4445697Smcpowers goto CLEANUP;
4455697Smcpowers } else {
4465697Smcpowers mp_neg(&tmp, &tmp);
4475697Smcpowers
4485697Smcpowers DIGIT(&tmp, 0) = d - DIGIT(&tmp, 0);
4495697Smcpowers }
4505697Smcpowers
4515697Smcpowers if(s_mp_cmp_d(&tmp, 0) == 0)
4525697Smcpowers SIGN(&tmp) = ZPOS;
4535697Smcpowers
4545697Smcpowers s_mp_exch(&tmp, b);
4555697Smcpowers
4565697Smcpowers CLEANUP:
4575697Smcpowers mp_clear(&tmp);
4585697Smcpowers return res;
4595697Smcpowers
4605697Smcpowers } /* end mp_add_d() */
4615697Smcpowers
4625697Smcpowers /* }}} */
4635697Smcpowers
4645697Smcpowers /* {{{ mp_sub_d(a, d, b) */
4655697Smcpowers
4665697Smcpowers /*
4675697Smcpowers mp_sub_d(a, d, b)
4685697Smcpowers
4695697Smcpowers Compute the difference b = a - d, for a single digit d. Respects the
4705697Smcpowers sign of its subtrahend (single digits are unsigned anyway).
4715697Smcpowers */
4725697Smcpowers
mp_sub_d(const mp_int * a,mp_digit d,mp_int * b)4735697Smcpowers mp_err mp_sub_d(const mp_int *a, mp_digit d, mp_int *b)
4745697Smcpowers {
4755697Smcpowers mp_int tmp;
4765697Smcpowers mp_err res;
4775697Smcpowers
4785697Smcpowers ARGCHK(a != NULL && b != NULL, MP_BADARG);
4795697Smcpowers
4805697Smcpowers if((res = mp_init_copy(&tmp, a)) != MP_OKAY)
4815697Smcpowers return res;
4825697Smcpowers
4835697Smcpowers if(SIGN(&tmp) == NEG) {
4845697Smcpowers if((res = s_mp_add_d(&tmp, d)) != MP_OKAY)
4855697Smcpowers goto CLEANUP;
4865697Smcpowers } else if(s_mp_cmp_d(&tmp, d) >= 0) {
4875697Smcpowers if((res = s_mp_sub_d(&tmp, d)) != MP_OKAY)
4885697Smcpowers goto CLEANUP;
4895697Smcpowers } else {
4905697Smcpowers mp_neg(&tmp, &tmp);
4915697Smcpowers
4925697Smcpowers DIGIT(&tmp, 0) = d - DIGIT(&tmp, 0);
4935697Smcpowers SIGN(&tmp) = NEG;
4945697Smcpowers }
4955697Smcpowers
4965697Smcpowers if(s_mp_cmp_d(&tmp, 0) == 0)
4975697Smcpowers SIGN(&tmp) = ZPOS;
4985697Smcpowers
4995697Smcpowers s_mp_exch(&tmp, b);
5005697Smcpowers
5015697Smcpowers CLEANUP:
5025697Smcpowers mp_clear(&tmp);
5035697Smcpowers return res;
5045697Smcpowers
5055697Smcpowers } /* end mp_sub_d() */
5065697Smcpowers
5075697Smcpowers /* }}} */
5085697Smcpowers
5095697Smcpowers /* {{{ mp_mul_d(a, d, b) */
5105697Smcpowers
5115697Smcpowers /*
5125697Smcpowers mp_mul_d(a, d, b)
5135697Smcpowers
5145697Smcpowers Compute the product b = a * d, for a single digit d. Respects the sign
5155697Smcpowers of its multiplicand (single digits are unsigned anyway)
5165697Smcpowers */
5175697Smcpowers
mp_mul_d(const mp_int * a,mp_digit d,mp_int * b)5185697Smcpowers mp_err mp_mul_d(const mp_int *a, mp_digit d, mp_int *b)
5195697Smcpowers {
5205697Smcpowers mp_err res;
5215697Smcpowers
5225697Smcpowers ARGCHK(a != NULL && b != NULL, MP_BADARG);
5235697Smcpowers
5245697Smcpowers if(d == 0) {
5255697Smcpowers mp_zero(b);
5265697Smcpowers return MP_OKAY;
5275697Smcpowers }
5285697Smcpowers
5295697Smcpowers if((res = mp_copy(a, b)) != MP_OKAY)
5305697Smcpowers return res;
5315697Smcpowers
5325697Smcpowers res = s_mp_mul_d(b, d);
5335697Smcpowers
5345697Smcpowers return res;
5355697Smcpowers
5365697Smcpowers } /* end mp_mul_d() */
5375697Smcpowers
5385697Smcpowers /* }}} */
5395697Smcpowers
5405697Smcpowers /* {{{ mp_mul_2(a, c) */
5415697Smcpowers
mp_mul_2(const mp_int * a,mp_int * c)5425697Smcpowers mp_err mp_mul_2(const mp_int *a, mp_int *c)
5435697Smcpowers {
5445697Smcpowers mp_err res;
5455697Smcpowers
5465697Smcpowers ARGCHK(a != NULL && c != NULL, MP_BADARG);
5475697Smcpowers
5485697Smcpowers if((res = mp_copy(a, c)) != MP_OKAY)
5495697Smcpowers return res;
5505697Smcpowers
5515697Smcpowers return s_mp_mul_2(c);
5525697Smcpowers
5535697Smcpowers } /* end mp_mul_2() */
5545697Smcpowers
5555697Smcpowers /* }}} */
5565697Smcpowers
5575697Smcpowers /* {{{ mp_div_d(a, d, q, r) */
5585697Smcpowers
5595697Smcpowers /*
5605697Smcpowers mp_div_d(a, d, q, r)
5615697Smcpowers
5625697Smcpowers Compute the quotient q = a / d and remainder r = a mod d, for a
5635697Smcpowers single digit d. Respects the sign of its divisor (single digits are
5645697Smcpowers unsigned anyway).
5655697Smcpowers */
5665697Smcpowers
mp_div_d(const mp_int * a,mp_digit d,mp_int * q,mp_digit * r)5675697Smcpowers mp_err mp_div_d(const mp_int *a, mp_digit d, mp_int *q, mp_digit *r)
5685697Smcpowers {
5695697Smcpowers mp_err res;
5705697Smcpowers mp_int qp;
5715697Smcpowers mp_digit rem;
5725697Smcpowers int pow;
5735697Smcpowers
5745697Smcpowers ARGCHK(a != NULL, MP_BADARG);
5755697Smcpowers
5765697Smcpowers if(d == 0)
5775697Smcpowers return MP_RANGE;
5785697Smcpowers
5795697Smcpowers /* Shortcut for powers of two ... */
5805697Smcpowers if((pow = s_mp_ispow2d(d)) >= 0) {
5815697Smcpowers mp_digit mask;
5825697Smcpowers
5835697Smcpowers mask = ((mp_digit)1 << pow) - 1;
5845697Smcpowers rem = DIGIT(a, 0) & mask;
5855697Smcpowers
5865697Smcpowers if(q) {
5875697Smcpowers mp_copy(a, q);
5885697Smcpowers s_mp_div_2d(q, pow);
5895697Smcpowers }
5905697Smcpowers
5915697Smcpowers if(r)
5925697Smcpowers *r = rem;
5935697Smcpowers
5945697Smcpowers return MP_OKAY;
5955697Smcpowers }
5965697Smcpowers
5975697Smcpowers if((res = mp_init_copy(&qp, a)) != MP_OKAY)
5985697Smcpowers return res;
5995697Smcpowers
6005697Smcpowers res = s_mp_div_d(&qp, d, &rem);
6015697Smcpowers
6025697Smcpowers if(s_mp_cmp_d(&qp, 0) == 0)
6035697Smcpowers SIGN(q) = ZPOS;
6045697Smcpowers
6055697Smcpowers if(r)
6065697Smcpowers *r = rem;
6075697Smcpowers
6085697Smcpowers if(q)
6095697Smcpowers s_mp_exch(&qp, q);
6105697Smcpowers
6115697Smcpowers mp_clear(&qp);
6125697Smcpowers return res;
6135697Smcpowers
6145697Smcpowers } /* end mp_div_d() */
6155697Smcpowers
6165697Smcpowers /* }}} */
6175697Smcpowers
6185697Smcpowers /* {{{ mp_div_2(a, c) */
6195697Smcpowers
6205697Smcpowers /*
6215697Smcpowers mp_div_2(a, c)
6225697Smcpowers
6235697Smcpowers Compute c = a / 2, disregarding the remainder.
6245697Smcpowers */
6255697Smcpowers
mp_div_2(const mp_int * a,mp_int * c)6265697Smcpowers mp_err mp_div_2(const mp_int *a, mp_int *c)
6275697Smcpowers {
6285697Smcpowers mp_err res;
6295697Smcpowers
6305697Smcpowers ARGCHK(a != NULL && c != NULL, MP_BADARG);
6315697Smcpowers
6325697Smcpowers if((res = mp_copy(a, c)) != MP_OKAY)
6335697Smcpowers return res;
6345697Smcpowers
6355697Smcpowers s_mp_div_2(c);
6365697Smcpowers
6375697Smcpowers return MP_OKAY;
6385697Smcpowers
6395697Smcpowers } /* end mp_div_2() */
6405697Smcpowers
6415697Smcpowers /* }}} */
6425697Smcpowers
6435697Smcpowers /* {{{ mp_expt_d(a, d, b) */
6445697Smcpowers
mp_expt_d(const mp_int * a,mp_digit d,mp_int * c)6455697Smcpowers mp_err mp_expt_d(const mp_int *a, mp_digit d, mp_int *c)
6465697Smcpowers {
6475697Smcpowers mp_int s, x;
6485697Smcpowers mp_err res;
6495697Smcpowers
6505697Smcpowers ARGCHK(a != NULL && c != NULL, MP_BADARG);
6515697Smcpowers
6525697Smcpowers if((res = mp_init(&s, FLAG(a))) != MP_OKAY)
6535697Smcpowers return res;
6545697Smcpowers if((res = mp_init_copy(&x, a)) != MP_OKAY)
6555697Smcpowers goto X;
6565697Smcpowers
6575697Smcpowers DIGIT(&s, 0) = 1;
6585697Smcpowers
6595697Smcpowers while(d != 0) {
6605697Smcpowers if(d & 1) {
6615697Smcpowers if((res = s_mp_mul(&s, &x)) != MP_OKAY)
6625697Smcpowers goto CLEANUP;
6635697Smcpowers }
6645697Smcpowers
6655697Smcpowers d /= 2;
6665697Smcpowers
6675697Smcpowers if((res = s_mp_sqr(&x)) != MP_OKAY)
6685697Smcpowers goto CLEANUP;
6695697Smcpowers }
6705697Smcpowers
6715697Smcpowers s_mp_exch(&s, c);
6725697Smcpowers
6735697Smcpowers CLEANUP:
6745697Smcpowers mp_clear(&x);
6755697Smcpowers X:
6765697Smcpowers mp_clear(&s);
6775697Smcpowers
6785697Smcpowers return res;
6795697Smcpowers
6805697Smcpowers } /* end mp_expt_d() */
6815697Smcpowers
6825697Smcpowers /* }}} */
6835697Smcpowers
6845697Smcpowers /* }}} */
6855697Smcpowers
6865697Smcpowers /*------------------------------------------------------------------------*/
6875697Smcpowers /* {{{ Full arithmetic */
6885697Smcpowers
6895697Smcpowers /* {{{ mp_abs(a, b) */
6905697Smcpowers
6915697Smcpowers /*
6925697Smcpowers mp_abs(a, b)
6935697Smcpowers
6945697Smcpowers Compute b = |a|. 'a' and 'b' may be identical.
6955697Smcpowers */
6965697Smcpowers
mp_abs(const mp_int * a,mp_int * b)6975697Smcpowers mp_err mp_abs(const mp_int *a, mp_int *b)
6985697Smcpowers {
6995697Smcpowers mp_err res;
7005697Smcpowers
7015697Smcpowers ARGCHK(a != NULL && b != NULL, MP_BADARG);
7025697Smcpowers
7035697Smcpowers if((res = mp_copy(a, b)) != MP_OKAY)
7045697Smcpowers return res;
7055697Smcpowers
7065697Smcpowers SIGN(b) = ZPOS;
7075697Smcpowers
7085697Smcpowers return MP_OKAY;
7095697Smcpowers
7105697Smcpowers } /* end mp_abs() */
7115697Smcpowers
7125697Smcpowers /* }}} */
7135697Smcpowers
7145697Smcpowers /* {{{ mp_neg(a, b) */
7155697Smcpowers
7165697Smcpowers /*
7175697Smcpowers mp_neg(a, b)
7185697Smcpowers
7195697Smcpowers Compute b = -a. 'a' and 'b' may be identical.
7205697Smcpowers */
7215697Smcpowers
mp_neg(const mp_int * a,mp_int * b)7225697Smcpowers mp_err mp_neg(const mp_int *a, mp_int *b)
7235697Smcpowers {
7245697Smcpowers mp_err res;
7255697Smcpowers
7265697Smcpowers ARGCHK(a != NULL && b != NULL, MP_BADARG);
7275697Smcpowers
7285697Smcpowers if((res = mp_copy(a, b)) != MP_OKAY)
7295697Smcpowers return res;
7305697Smcpowers
7315697Smcpowers if(s_mp_cmp_d(b, 0) == MP_EQ)
7325697Smcpowers SIGN(b) = ZPOS;
7335697Smcpowers else
7345697Smcpowers SIGN(b) = (SIGN(b) == NEG) ? ZPOS : NEG;
7355697Smcpowers
7365697Smcpowers return MP_OKAY;
7375697Smcpowers
7385697Smcpowers } /* end mp_neg() */
7395697Smcpowers
7405697Smcpowers /* }}} */
7415697Smcpowers
7425697Smcpowers /* {{{ mp_add(a, b, c) */
7435697Smcpowers
7445697Smcpowers /*
7455697Smcpowers mp_add(a, b, c)
7465697Smcpowers
7475697Smcpowers Compute c = a + b. All parameters may be identical.
7485697Smcpowers */
7495697Smcpowers
mp_add(const mp_int * a,const mp_int * b,mp_int * c)7505697Smcpowers mp_err mp_add(const mp_int *a, const mp_int *b, mp_int *c)
7515697Smcpowers {
7525697Smcpowers mp_err res;
7535697Smcpowers
7545697Smcpowers ARGCHK(a != NULL && b != NULL && c != NULL, MP_BADARG);
7555697Smcpowers
7565697Smcpowers if(SIGN(a) == SIGN(b)) { /* same sign: add values, keep sign */
7575697Smcpowers MP_CHECKOK( s_mp_add_3arg(a, b, c) );
7585697Smcpowers } else if(s_mp_cmp(a, b) >= 0) { /* different sign: |a| >= |b| */
7595697Smcpowers MP_CHECKOK( s_mp_sub_3arg(a, b, c) );
7605697Smcpowers } else { /* different sign: |a| < |b| */
7615697Smcpowers MP_CHECKOK( s_mp_sub_3arg(b, a, c) );
7625697Smcpowers }
7635697Smcpowers
7645697Smcpowers if (s_mp_cmp_d(c, 0) == MP_EQ)
7655697Smcpowers SIGN(c) = ZPOS;
7665697Smcpowers
7675697Smcpowers CLEANUP:
7685697Smcpowers return res;
7695697Smcpowers
7705697Smcpowers } /* end mp_add() */
7715697Smcpowers
7725697Smcpowers /* }}} */
7735697Smcpowers
7745697Smcpowers /* {{{ mp_sub(a, b, c) */
7755697Smcpowers
7765697Smcpowers /*
7775697Smcpowers mp_sub(a, b, c)
7785697Smcpowers
7795697Smcpowers Compute c = a - b. All parameters may be identical.
7805697Smcpowers */
7815697Smcpowers
mp_sub(const mp_int * a,const mp_int * b,mp_int * c)7825697Smcpowers mp_err mp_sub(const mp_int *a, const mp_int *b, mp_int *c)
7835697Smcpowers {
7845697Smcpowers mp_err res;
7855697Smcpowers int magDiff;
7865697Smcpowers
7875697Smcpowers ARGCHK(a != NULL && b != NULL && c != NULL, MP_BADARG);
7885697Smcpowers
7895697Smcpowers if (a == b) {
7905697Smcpowers mp_zero(c);
7915697Smcpowers return MP_OKAY;
7925697Smcpowers }
7935697Smcpowers
7945697Smcpowers if (MP_SIGN(a) != MP_SIGN(b)) {
7955697Smcpowers MP_CHECKOK( s_mp_add_3arg(a, b, c) );
7965697Smcpowers } else if (!(magDiff = s_mp_cmp(a, b))) {
7975697Smcpowers mp_zero(c);
7985697Smcpowers res = MP_OKAY;
7995697Smcpowers } else if (magDiff > 0) {
8005697Smcpowers MP_CHECKOK( s_mp_sub_3arg(a, b, c) );
8015697Smcpowers } else {
8025697Smcpowers MP_CHECKOK( s_mp_sub_3arg(b, a, c) );
8035697Smcpowers MP_SIGN(c) = !MP_SIGN(a);
8045697Smcpowers }
8055697Smcpowers
8065697Smcpowers if (s_mp_cmp_d(c, 0) == MP_EQ)
8075697Smcpowers MP_SIGN(c) = MP_ZPOS;
8085697Smcpowers
8095697Smcpowers CLEANUP:
8105697Smcpowers return res;
8115697Smcpowers
8125697Smcpowers } /* end mp_sub() */
8135697Smcpowers
8145697Smcpowers /* }}} */
8155697Smcpowers
8165697Smcpowers /* {{{ mp_mul(a, b, c) */
8175697Smcpowers
8185697Smcpowers /*
8195697Smcpowers mp_mul(a, b, c)
8205697Smcpowers
8215697Smcpowers Compute c = a * b. All parameters may be identical.
8225697Smcpowers */
mp_mul(const mp_int * a,const mp_int * b,mp_int * c)8235697Smcpowers mp_err mp_mul(const mp_int *a, const mp_int *b, mp_int * c)
8245697Smcpowers {
8255697Smcpowers mp_digit *pb;
8265697Smcpowers mp_int tmp;
8275697Smcpowers mp_err res;
8285697Smcpowers mp_size ib;
8295697Smcpowers mp_size useda, usedb;
8305697Smcpowers
8315697Smcpowers ARGCHK(a != NULL && b != NULL && c != NULL, MP_BADARG);
8325697Smcpowers
8335697Smcpowers if (a == c) {
8345697Smcpowers if ((res = mp_init_copy(&tmp, a)) != MP_OKAY)
8355697Smcpowers return res;
8365697Smcpowers if (a == b)
8375697Smcpowers b = &tmp;
8385697Smcpowers a = &tmp;
8395697Smcpowers } else if (b == c) {
8405697Smcpowers if ((res = mp_init_copy(&tmp, b)) != MP_OKAY)
8415697Smcpowers return res;
8425697Smcpowers b = &tmp;
8435697Smcpowers } else {
8445697Smcpowers MP_DIGITS(&tmp) = 0;
8455697Smcpowers }
8465697Smcpowers
8475697Smcpowers if (MP_USED(a) < MP_USED(b)) {
8485697Smcpowers const mp_int *xch = b; /* switch a and b, to do fewer outer loops */
8495697Smcpowers b = a;
8505697Smcpowers a = xch;
8515697Smcpowers }
8525697Smcpowers
8535697Smcpowers MP_USED(c) = 1; MP_DIGIT(c, 0) = 0;
8545697Smcpowers if((res = s_mp_pad(c, USED(a) + USED(b))) != MP_OKAY)
8555697Smcpowers goto CLEANUP;
8565697Smcpowers
8575697Smcpowers #ifdef NSS_USE_COMBA
8585697Smcpowers if ((MP_USED(a) == MP_USED(b)) && IS_POWER_OF_2(MP_USED(b))) {
8595697Smcpowers if (MP_USED(a) == 4) {
8605697Smcpowers s_mp_mul_comba_4(a, b, c);
8615697Smcpowers goto CLEANUP;
8625697Smcpowers }
8635697Smcpowers if (MP_USED(a) == 8) {
8645697Smcpowers s_mp_mul_comba_8(a, b, c);
8655697Smcpowers goto CLEANUP;
8665697Smcpowers }
8675697Smcpowers if (MP_USED(a) == 16) {
8685697Smcpowers s_mp_mul_comba_16(a, b, c);
8695697Smcpowers goto CLEANUP;
8705697Smcpowers }
8715697Smcpowers if (MP_USED(a) == 32) {
8725697Smcpowers s_mp_mul_comba_32(a, b, c);
8735697Smcpowers goto CLEANUP;
8745697Smcpowers }
8755697Smcpowers }
8765697Smcpowers #endif
8775697Smcpowers
8785697Smcpowers pb = MP_DIGITS(b);
8795697Smcpowers s_mpv_mul_d(MP_DIGITS(a), MP_USED(a), *pb++, MP_DIGITS(c));
8805697Smcpowers
8815697Smcpowers /* Outer loop: Digits of b */
8825697Smcpowers useda = MP_USED(a);
8835697Smcpowers usedb = MP_USED(b);
8845697Smcpowers for (ib = 1; ib < usedb; ib++) {
8855697Smcpowers mp_digit b_i = *pb++;
8865697Smcpowers
8875697Smcpowers /* Inner product: Digits of a */
8885697Smcpowers if (b_i)
8895697Smcpowers s_mpv_mul_d_add(MP_DIGITS(a), useda, b_i, MP_DIGITS(c) + ib);
8905697Smcpowers else
8915697Smcpowers MP_DIGIT(c, ib + useda) = b_i;
8925697Smcpowers }
8935697Smcpowers
8945697Smcpowers s_mp_clamp(c);
8955697Smcpowers
8965697Smcpowers if(SIGN(a) == SIGN(b) || s_mp_cmp_d(c, 0) == MP_EQ)
8975697Smcpowers SIGN(c) = ZPOS;
8985697Smcpowers else
8995697Smcpowers SIGN(c) = NEG;
9005697Smcpowers
9015697Smcpowers CLEANUP:
9025697Smcpowers mp_clear(&tmp);
9035697Smcpowers return res;
9045697Smcpowers } /* end mp_mul() */
9055697Smcpowers
9065697Smcpowers /* }}} */
9075697Smcpowers
9085697Smcpowers /* {{{ mp_sqr(a, sqr) */
9095697Smcpowers
9105697Smcpowers #if MP_SQUARE
9115697Smcpowers /*
9125697Smcpowers Computes the square of a. This can be done more
9135697Smcpowers efficiently than a general multiplication, because many of the
9145697Smcpowers computation steps are redundant when squaring. The inner product
9155697Smcpowers step is a bit more complicated, but we save a fair number of
9165697Smcpowers iterations of the multiplication loop.
9175697Smcpowers */
9185697Smcpowers
9195697Smcpowers /* sqr = a^2; Caller provides both a and tmp; */
mp_sqr(const mp_int * a,mp_int * sqr)9205697Smcpowers mp_err mp_sqr(const mp_int *a, mp_int *sqr)
9215697Smcpowers {
9225697Smcpowers mp_digit *pa;
9235697Smcpowers mp_digit d;
9245697Smcpowers mp_err res;
9255697Smcpowers mp_size ix;
9265697Smcpowers mp_int tmp;
9275697Smcpowers int count;
9285697Smcpowers
9295697Smcpowers ARGCHK(a != NULL && sqr != NULL, MP_BADARG);
9305697Smcpowers
9315697Smcpowers if (a == sqr) {
9325697Smcpowers if((res = mp_init_copy(&tmp, a)) != MP_OKAY)
9335697Smcpowers return res;
9345697Smcpowers a = &tmp;
9355697Smcpowers } else {
9365697Smcpowers DIGITS(&tmp) = 0;
9375697Smcpowers res = MP_OKAY;
9385697Smcpowers }
9395697Smcpowers
9405697Smcpowers ix = 2 * MP_USED(a);
9415697Smcpowers if (ix > MP_ALLOC(sqr)) {
9425697Smcpowers MP_USED(sqr) = 1;
9435697Smcpowers MP_CHECKOK( s_mp_grow(sqr, ix) );
9445697Smcpowers }
9455697Smcpowers MP_USED(sqr) = ix;
9465697Smcpowers MP_DIGIT(sqr, 0) = 0;
9475697Smcpowers
9485697Smcpowers #ifdef NSS_USE_COMBA
9495697Smcpowers if (IS_POWER_OF_2(MP_USED(a))) {
9505697Smcpowers if (MP_USED(a) == 4) {
9515697Smcpowers s_mp_sqr_comba_4(a, sqr);
9525697Smcpowers goto CLEANUP;
9535697Smcpowers }
9545697Smcpowers if (MP_USED(a) == 8) {
9555697Smcpowers s_mp_sqr_comba_8(a, sqr);
9565697Smcpowers goto CLEANUP;
9575697Smcpowers }
9585697Smcpowers if (MP_USED(a) == 16) {
9595697Smcpowers s_mp_sqr_comba_16(a, sqr);
9605697Smcpowers goto CLEANUP;
9615697Smcpowers }
9625697Smcpowers if (MP_USED(a) == 32) {
9635697Smcpowers s_mp_sqr_comba_32(a, sqr);
9645697Smcpowers goto CLEANUP;
9655697Smcpowers }
9665697Smcpowers }
9675697Smcpowers #endif
9685697Smcpowers
9695697Smcpowers pa = MP_DIGITS(a);
9705697Smcpowers count = MP_USED(a) - 1;
9715697Smcpowers if (count > 0) {
9725697Smcpowers d = *pa++;
9735697Smcpowers s_mpv_mul_d(pa, count, d, MP_DIGITS(sqr) + 1);
9745697Smcpowers for (ix = 3; --count > 0; ix += 2) {
9755697Smcpowers d = *pa++;
9765697Smcpowers s_mpv_mul_d_add(pa, count, d, MP_DIGITS(sqr) + ix);
9775697Smcpowers } /* for(ix ...) */
9785697Smcpowers MP_DIGIT(sqr, MP_USED(sqr)-1) = 0; /* above loop stopped short of this. */
9795697Smcpowers
9805697Smcpowers /* now sqr *= 2 */
9815697Smcpowers s_mp_mul_2(sqr);
9825697Smcpowers } else {
9835697Smcpowers MP_DIGIT(sqr, 1) = 0;
9845697Smcpowers }
9855697Smcpowers
9865697Smcpowers /* now add the squares of the digits of a to sqr. */
9875697Smcpowers s_mpv_sqr_add_prop(MP_DIGITS(a), MP_USED(a), MP_DIGITS(sqr));
9885697Smcpowers
9895697Smcpowers SIGN(sqr) = ZPOS;
9905697Smcpowers s_mp_clamp(sqr);
9915697Smcpowers
9925697Smcpowers CLEANUP:
9935697Smcpowers mp_clear(&tmp);
9945697Smcpowers return res;
9955697Smcpowers
9965697Smcpowers } /* end mp_sqr() */
9975697Smcpowers #endif
9985697Smcpowers
9995697Smcpowers /* }}} */
10005697Smcpowers
10015697Smcpowers /* {{{ mp_div(a, b, q, r) */
10025697Smcpowers
10035697Smcpowers /*
10045697Smcpowers mp_div(a, b, q, r)
10055697Smcpowers
10065697Smcpowers Compute q = a / b and r = a mod b. Input parameters may be re-used
10075697Smcpowers as output parameters. If q or r is NULL, that portion of the
10085697Smcpowers computation will be discarded (although it will still be computed)
10095697Smcpowers */
mp_div(const mp_int * a,const mp_int * b,mp_int * q,mp_int * r)10105697Smcpowers mp_err mp_div(const mp_int *a, const mp_int *b, mp_int *q, mp_int *r)
10115697Smcpowers {
10125697Smcpowers mp_err res;
10135697Smcpowers mp_int *pQ, *pR;
10145697Smcpowers mp_int qtmp, rtmp, btmp;
10155697Smcpowers int cmp;
10165697Smcpowers mp_sign signA;
10175697Smcpowers mp_sign signB;
10185697Smcpowers
10195697Smcpowers ARGCHK(a != NULL && b != NULL, MP_BADARG);
10205697Smcpowers
10215697Smcpowers signA = MP_SIGN(a);
10225697Smcpowers signB = MP_SIGN(b);
10235697Smcpowers
10245697Smcpowers if(mp_cmp_z(b) == MP_EQ)
10255697Smcpowers return MP_RANGE;
10265697Smcpowers
10275697Smcpowers DIGITS(&qtmp) = 0;
10285697Smcpowers DIGITS(&rtmp) = 0;
10295697Smcpowers DIGITS(&btmp) = 0;
10305697Smcpowers
10315697Smcpowers /* Set up some temporaries... */
10325697Smcpowers if (!r || r == a || r == b) {
10335697Smcpowers MP_CHECKOK( mp_init_copy(&rtmp, a) );
10345697Smcpowers pR = &rtmp;
10355697Smcpowers } else {
10365697Smcpowers MP_CHECKOK( mp_copy(a, r) );
10375697Smcpowers pR = r;
10385697Smcpowers }
10395697Smcpowers
10405697Smcpowers if (!q || q == a || q == b) {
10415697Smcpowers MP_CHECKOK( mp_init_size(&qtmp, MP_USED(a), FLAG(a)) );
10425697Smcpowers pQ = &qtmp;
10435697Smcpowers } else {
10445697Smcpowers MP_CHECKOK( s_mp_pad(q, MP_USED(a)) );
10455697Smcpowers pQ = q;
10465697Smcpowers mp_zero(pQ);
10475697Smcpowers }
10485697Smcpowers
10495697Smcpowers /*
10505697Smcpowers If |a| <= |b|, we can compute the solution without division;
10515697Smcpowers otherwise, we actually do the work required.
10525697Smcpowers */
10535697Smcpowers if ((cmp = s_mp_cmp(a, b)) <= 0) {
10545697Smcpowers if (cmp) {
10555697Smcpowers /* r was set to a above. */
10565697Smcpowers mp_zero(pQ);
10575697Smcpowers } else {
10585697Smcpowers mp_set(pQ, 1);
10595697Smcpowers mp_zero(pR);
10605697Smcpowers }
10615697Smcpowers } else {
10625697Smcpowers MP_CHECKOK( mp_init_copy(&btmp, b) );
10635697Smcpowers MP_CHECKOK( s_mp_div(pR, &btmp, pQ) );
10645697Smcpowers }
10655697Smcpowers
10665697Smcpowers /* Compute the signs for the output */
10675697Smcpowers MP_SIGN(pR) = signA; /* Sr = Sa */
10685697Smcpowers /* Sq = ZPOS if Sa == Sb */ /* Sq = NEG if Sa != Sb */
10695697Smcpowers MP_SIGN(pQ) = (signA == signB) ? ZPOS : NEG;
10705697Smcpowers
10715697Smcpowers if(s_mp_cmp_d(pQ, 0) == MP_EQ)
10725697Smcpowers SIGN(pQ) = ZPOS;
10735697Smcpowers if(s_mp_cmp_d(pR, 0) == MP_EQ)
10745697Smcpowers SIGN(pR) = ZPOS;
10755697Smcpowers
10765697Smcpowers /* Copy output, if it is needed */
10775697Smcpowers if(q && q != pQ)
10785697Smcpowers s_mp_exch(pQ, q);
10795697Smcpowers
10805697Smcpowers if(r && r != pR)
10815697Smcpowers s_mp_exch(pR, r);
10825697Smcpowers
10835697Smcpowers CLEANUP:
10845697Smcpowers mp_clear(&btmp);
10855697Smcpowers mp_clear(&rtmp);
10865697Smcpowers mp_clear(&qtmp);
10875697Smcpowers
10885697Smcpowers return res;
10895697Smcpowers
10905697Smcpowers } /* end mp_div() */
10915697Smcpowers
10925697Smcpowers /* }}} */
10935697Smcpowers
10945697Smcpowers /* {{{ mp_div_2d(a, d, q, r) */
10955697Smcpowers
mp_div_2d(const mp_int * a,mp_digit d,mp_int * q,mp_int * r)10965697Smcpowers mp_err mp_div_2d(const mp_int *a, mp_digit d, mp_int *q, mp_int *r)
10975697Smcpowers {
10985697Smcpowers mp_err res;
10995697Smcpowers
11005697Smcpowers ARGCHK(a != NULL, MP_BADARG);
11015697Smcpowers
11025697Smcpowers if(q) {
11035697Smcpowers if((res = mp_copy(a, q)) != MP_OKAY)
11045697Smcpowers return res;
11055697Smcpowers }
11065697Smcpowers if(r) {
11075697Smcpowers if((res = mp_copy(a, r)) != MP_OKAY)
11085697Smcpowers return res;
11095697Smcpowers }
11105697Smcpowers if(q) {
11115697Smcpowers s_mp_div_2d(q, d);
11125697Smcpowers }
11135697Smcpowers if(r) {
11145697Smcpowers s_mp_mod_2d(r, d);
11155697Smcpowers }
11165697Smcpowers
11175697Smcpowers return MP_OKAY;
11185697Smcpowers
11195697Smcpowers } /* end mp_div_2d() */
11205697Smcpowers
11215697Smcpowers /* }}} */
11225697Smcpowers
11235697Smcpowers /* {{{ mp_expt(a, b, c) */
11245697Smcpowers
11255697Smcpowers /*
11265697Smcpowers mp_expt(a, b, c)
11275697Smcpowers
11285697Smcpowers Compute c = a ** b, that is, raise a to the b power. Uses a
11295697Smcpowers standard iterative square-and-multiply technique.
11305697Smcpowers */
11315697Smcpowers
mp_expt(mp_int * a,mp_int * b,mp_int * c)11325697Smcpowers mp_err mp_expt(mp_int *a, mp_int *b, mp_int *c)
11335697Smcpowers {
11345697Smcpowers mp_int s, x;
11355697Smcpowers mp_err res;
11365697Smcpowers mp_digit d;
11375697Smcpowers int dig, bit;
11385697Smcpowers
11395697Smcpowers ARGCHK(a != NULL && b != NULL && c != NULL, MP_BADARG);
11405697Smcpowers
11415697Smcpowers if(mp_cmp_z(b) < 0)
11425697Smcpowers return MP_RANGE;
11435697Smcpowers
11445697Smcpowers if((res = mp_init(&s, FLAG(a))) != MP_OKAY)
11455697Smcpowers return res;
11465697Smcpowers
11475697Smcpowers mp_set(&s, 1);
11485697Smcpowers
11495697Smcpowers if((res = mp_init_copy(&x, a)) != MP_OKAY)
11505697Smcpowers goto X;
11515697Smcpowers
11525697Smcpowers /* Loop over low-order digits in ascending order */
11535697Smcpowers for(dig = 0; dig < (USED(b) - 1); dig++) {
11545697Smcpowers d = DIGIT(b, dig);
11555697Smcpowers
11565697Smcpowers /* Loop over bits of each non-maximal digit */
11575697Smcpowers for(bit = 0; bit < DIGIT_BIT; bit++) {
11585697Smcpowers if(d & 1) {
11595697Smcpowers if((res = s_mp_mul(&s, &x)) != MP_OKAY)
11605697Smcpowers goto CLEANUP;
11615697Smcpowers }
11625697Smcpowers
11635697Smcpowers d >>= 1;
11645697Smcpowers
11655697Smcpowers if((res = s_mp_sqr(&x)) != MP_OKAY)
11665697Smcpowers goto CLEANUP;
11675697Smcpowers }
11685697Smcpowers }
11695697Smcpowers
11705697Smcpowers /* Consider now the last digit... */
11715697Smcpowers d = DIGIT(b, dig);
11725697Smcpowers
11735697Smcpowers while(d) {
11745697Smcpowers if(d & 1) {
11755697Smcpowers if((res = s_mp_mul(&s, &x)) != MP_OKAY)
11765697Smcpowers goto CLEANUP;
11775697Smcpowers }
11785697Smcpowers
11795697Smcpowers d >>= 1;
11805697Smcpowers
11815697Smcpowers if((res = s_mp_sqr(&x)) != MP_OKAY)
11825697Smcpowers goto CLEANUP;
11835697Smcpowers }
11845697Smcpowers
11855697Smcpowers if(mp_iseven(b))
11865697Smcpowers SIGN(&s) = SIGN(a);
11875697Smcpowers
11885697Smcpowers res = mp_copy(&s, c);
11895697Smcpowers
11905697Smcpowers CLEANUP:
11915697Smcpowers mp_clear(&x);
11925697Smcpowers X:
11935697Smcpowers mp_clear(&s);
11945697Smcpowers
11955697Smcpowers return res;
11965697Smcpowers
11975697Smcpowers } /* end mp_expt() */
11985697Smcpowers
11995697Smcpowers /* }}} */
12005697Smcpowers
12015697Smcpowers /* {{{ mp_2expt(a, k) */
12025697Smcpowers
12035697Smcpowers /* Compute a = 2^k */
12045697Smcpowers
mp_2expt(mp_int * a,mp_digit k)12055697Smcpowers mp_err mp_2expt(mp_int *a, mp_digit k)
12065697Smcpowers {
12075697Smcpowers ARGCHK(a != NULL, MP_BADARG);
12085697Smcpowers
12095697Smcpowers return s_mp_2expt(a, k);
12105697Smcpowers
12115697Smcpowers } /* end mp_2expt() */
12125697Smcpowers
12135697Smcpowers /* }}} */
12145697Smcpowers
12155697Smcpowers /* {{{ mp_mod(a, m, c) */
12165697Smcpowers
12175697Smcpowers /*
12185697Smcpowers mp_mod(a, m, c)
12195697Smcpowers
12205697Smcpowers Compute c = a (mod m). Result will always be 0 <= c < m.
12215697Smcpowers */
12225697Smcpowers
mp_mod(const mp_int * a,const mp_int * m,mp_int * c)12235697Smcpowers mp_err mp_mod(const mp_int *a, const mp_int *m, mp_int *c)
12245697Smcpowers {
12255697Smcpowers mp_err res;
12265697Smcpowers int mag;
12275697Smcpowers
12285697Smcpowers ARGCHK(a != NULL && m != NULL && c != NULL, MP_BADARG);
12295697Smcpowers
12305697Smcpowers if(SIGN(m) == NEG)
12315697Smcpowers return MP_RANGE;
12325697Smcpowers
12335697Smcpowers /*
12345697Smcpowers If |a| > m, we need to divide to get the remainder and take the
12355697Smcpowers absolute value.
12365697Smcpowers
12375697Smcpowers If |a| < m, we don't need to do any division, just copy and adjust
12385697Smcpowers the sign (if a is negative).
12395697Smcpowers
12405697Smcpowers If |a| == m, we can simply set the result to zero.
12415697Smcpowers
12425697Smcpowers This order is intended to minimize the average path length of the
12435697Smcpowers comparison chain on common workloads -- the most frequent cases are
12445697Smcpowers that |a| != m, so we do those first.
12455697Smcpowers */
12465697Smcpowers if((mag = s_mp_cmp(a, m)) > 0) {
12475697Smcpowers if((res = mp_div(a, m, NULL, c)) != MP_OKAY)
12485697Smcpowers return res;
12495697Smcpowers
12505697Smcpowers if(SIGN(c) == NEG) {
12515697Smcpowers if((res = mp_add(c, m, c)) != MP_OKAY)
12525697Smcpowers return res;
12535697Smcpowers }
12545697Smcpowers
12555697Smcpowers } else if(mag < 0) {
12565697Smcpowers if((res = mp_copy(a, c)) != MP_OKAY)
12575697Smcpowers return res;
12585697Smcpowers
12595697Smcpowers if(mp_cmp_z(a) < 0) {
12605697Smcpowers if((res = mp_add(c, m, c)) != MP_OKAY)
12615697Smcpowers return res;
12625697Smcpowers
12635697Smcpowers }
12645697Smcpowers
12655697Smcpowers } else {
12665697Smcpowers mp_zero(c);
12675697Smcpowers
12685697Smcpowers }
12695697Smcpowers
12705697Smcpowers return MP_OKAY;
12715697Smcpowers
12725697Smcpowers } /* end mp_mod() */
12735697Smcpowers
12745697Smcpowers /* }}} */
12755697Smcpowers
12765697Smcpowers /* {{{ mp_mod_d(a, d, c) */
12775697Smcpowers
12785697Smcpowers /*
12795697Smcpowers mp_mod_d(a, d, c)
12805697Smcpowers
12815697Smcpowers Compute c = a (mod d). Result will always be 0 <= c < d
12825697Smcpowers */
mp_mod_d(const mp_int * a,mp_digit d,mp_digit * c)12835697Smcpowers mp_err mp_mod_d(const mp_int *a, mp_digit d, mp_digit *c)
12845697Smcpowers {
12855697Smcpowers mp_err res;
12865697Smcpowers mp_digit rem;
12875697Smcpowers
12885697Smcpowers ARGCHK(a != NULL && c != NULL, MP_BADARG);
12895697Smcpowers
12905697Smcpowers if(s_mp_cmp_d(a, d) > 0) {
12915697Smcpowers if((res = mp_div_d(a, d, NULL, &rem)) != MP_OKAY)
12925697Smcpowers return res;
12935697Smcpowers
12945697Smcpowers } else {
12955697Smcpowers if(SIGN(a) == NEG)
12965697Smcpowers rem = d - DIGIT(a, 0);
12975697Smcpowers else
12985697Smcpowers rem = DIGIT(a, 0);
12995697Smcpowers }
13005697Smcpowers
13015697Smcpowers if(c)
13025697Smcpowers *c = rem;
13035697Smcpowers
13045697Smcpowers return MP_OKAY;
13055697Smcpowers
13065697Smcpowers } /* end mp_mod_d() */
13075697Smcpowers
13085697Smcpowers /* }}} */
13095697Smcpowers
13105697Smcpowers /* {{{ mp_sqrt(a, b) */
13115697Smcpowers
13125697Smcpowers /*
13135697Smcpowers mp_sqrt(a, b)
13145697Smcpowers
13155697Smcpowers Compute the integer square root of a, and store the result in b.
13165697Smcpowers Uses an integer-arithmetic version of Newton's iterative linear
13175697Smcpowers approximation technique to determine this value; the result has the
13185697Smcpowers following two properties:
13195697Smcpowers
13205697Smcpowers b^2 <= a
13215697Smcpowers (b+1)^2 >= a
13225697Smcpowers
13235697Smcpowers It is a range error to pass a negative value.
13245697Smcpowers */
mp_sqrt(const mp_int * a,mp_int * b)13255697Smcpowers mp_err mp_sqrt(const mp_int *a, mp_int *b)
13265697Smcpowers {
13275697Smcpowers mp_int x, t;
13285697Smcpowers mp_err res;
13295697Smcpowers mp_size used;
13305697Smcpowers
13315697Smcpowers ARGCHK(a != NULL && b != NULL, MP_BADARG);
13325697Smcpowers
13335697Smcpowers /* Cannot take square root of a negative value */
13345697Smcpowers if(SIGN(a) == NEG)
13355697Smcpowers return MP_RANGE;
13365697Smcpowers
13375697Smcpowers /* Special cases for zero and one, trivial */
13385697Smcpowers if(mp_cmp_d(a, 1) <= 0)
13395697Smcpowers return mp_copy(a, b);
13405697Smcpowers
13415697Smcpowers /* Initialize the temporaries we'll use below */
13425697Smcpowers if((res = mp_init_size(&t, USED(a), FLAG(a))) != MP_OKAY)
13435697Smcpowers return res;
13445697Smcpowers
13455697Smcpowers /* Compute an initial guess for the iteration as a itself */
13465697Smcpowers if((res = mp_init_copy(&x, a)) != MP_OKAY)
13475697Smcpowers goto X;
13485697Smcpowers
13495697Smcpowers used = MP_USED(&x);
13505697Smcpowers if (used > 1) {
13515697Smcpowers s_mp_rshd(&x, used / 2);
13525697Smcpowers }
13535697Smcpowers
13545697Smcpowers for(;;) {
13555697Smcpowers /* t = (x * x) - a */
13565697Smcpowers mp_copy(&x, &t); /* can't fail, t is big enough for original x */
13575697Smcpowers if((res = mp_sqr(&t, &t)) != MP_OKAY ||
13585697Smcpowers (res = mp_sub(&t, a, &t)) != MP_OKAY)
13595697Smcpowers goto CLEANUP;
13605697Smcpowers
13615697Smcpowers /* t = t / 2x */
13625697Smcpowers s_mp_mul_2(&x);
13635697Smcpowers if((res = mp_div(&t, &x, &t, NULL)) != MP_OKAY)
13645697Smcpowers goto CLEANUP;
13655697Smcpowers s_mp_div_2(&x);
13665697Smcpowers
13675697Smcpowers /* Terminate the loop, if the quotient is zero */
13685697Smcpowers if(mp_cmp_z(&t) == MP_EQ)
13695697Smcpowers break;
13705697Smcpowers
13715697Smcpowers /* x = x - t */
13725697Smcpowers if((res = mp_sub(&x, &t, &x)) != MP_OKAY)
13735697Smcpowers goto CLEANUP;
13745697Smcpowers
13755697Smcpowers }
13765697Smcpowers
13775697Smcpowers /* Copy result to output parameter */
13785697Smcpowers mp_sub_d(&x, 1, &x);
13795697Smcpowers s_mp_exch(&x, b);
13805697Smcpowers
13815697Smcpowers CLEANUP:
13825697Smcpowers mp_clear(&x);
13835697Smcpowers X:
13845697Smcpowers mp_clear(&t);
13855697Smcpowers
13865697Smcpowers return res;
13875697Smcpowers
13885697Smcpowers } /* end mp_sqrt() */
13895697Smcpowers
13905697Smcpowers /* }}} */
13915697Smcpowers
13925697Smcpowers /* }}} */
13935697Smcpowers
13945697Smcpowers /*------------------------------------------------------------------------*/
13955697Smcpowers /* {{{ Modular arithmetic */
13965697Smcpowers
13975697Smcpowers #if MP_MODARITH
13985697Smcpowers /* {{{ mp_addmod(a, b, m, c) */
13995697Smcpowers
14005697Smcpowers /*
14015697Smcpowers mp_addmod(a, b, m, c)
14025697Smcpowers
14035697Smcpowers Compute c = (a + b) mod m
14045697Smcpowers */
14055697Smcpowers
mp_addmod(const mp_int * a,const mp_int * b,const mp_int * m,mp_int * c)14065697Smcpowers mp_err mp_addmod(const mp_int *a, const mp_int *b, const mp_int *m, mp_int *c)
14075697Smcpowers {
14085697Smcpowers mp_err res;
14095697Smcpowers
14105697Smcpowers ARGCHK(a != NULL && b != NULL && m != NULL && c != NULL, MP_BADARG);
14115697Smcpowers
14125697Smcpowers if((res = mp_add(a, b, c)) != MP_OKAY)
14135697Smcpowers return res;
14145697Smcpowers if((res = mp_mod(c, m, c)) != MP_OKAY)
14155697Smcpowers return res;
14165697Smcpowers
14175697Smcpowers return MP_OKAY;
14185697Smcpowers
14195697Smcpowers }
14205697Smcpowers
14215697Smcpowers /* }}} */
14225697Smcpowers
14235697Smcpowers /* {{{ mp_submod(a, b, m, c) */
14245697Smcpowers
14255697Smcpowers /*
14265697Smcpowers mp_submod(a, b, m, c)
14275697Smcpowers
14285697Smcpowers Compute c = (a - b) mod m
14295697Smcpowers */
14305697Smcpowers
mp_submod(const mp_int * a,const mp_int * b,const mp_int * m,mp_int * c)14315697Smcpowers mp_err mp_submod(const mp_int *a, const mp_int *b, const mp_int *m, mp_int *c)
14325697Smcpowers {
14335697Smcpowers mp_err res;
14345697Smcpowers
14355697Smcpowers ARGCHK(a != NULL && b != NULL && m != NULL && c != NULL, MP_BADARG);
14365697Smcpowers
14375697Smcpowers if((res = mp_sub(a, b, c)) != MP_OKAY)
14385697Smcpowers return res;
14395697Smcpowers if((res = mp_mod(c, m, c)) != MP_OKAY)
14405697Smcpowers return res;
14415697Smcpowers
14425697Smcpowers return MP_OKAY;
14435697Smcpowers
14445697Smcpowers }
14455697Smcpowers
14465697Smcpowers /* }}} */
14475697Smcpowers
14485697Smcpowers /* {{{ mp_mulmod(a, b, m, c) */
14495697Smcpowers
14505697Smcpowers /*
14515697Smcpowers mp_mulmod(a, b, m, c)
14525697Smcpowers
14535697Smcpowers Compute c = (a * b) mod m
14545697Smcpowers */
14555697Smcpowers
mp_mulmod(const mp_int * a,const mp_int * b,const mp_int * m,mp_int * c)14565697Smcpowers mp_err mp_mulmod(const mp_int *a, const mp_int *b, const mp_int *m, mp_int *c)
14575697Smcpowers {
14585697Smcpowers mp_err res;
14595697Smcpowers
14605697Smcpowers ARGCHK(a != NULL && b != NULL && m != NULL && c != NULL, MP_BADARG);
14615697Smcpowers
14625697Smcpowers if((res = mp_mul(a, b, c)) != MP_OKAY)
14635697Smcpowers return res;
14645697Smcpowers if((res = mp_mod(c, m, c)) != MP_OKAY)
14655697Smcpowers return res;
14665697Smcpowers
14675697Smcpowers return MP_OKAY;
14685697Smcpowers
14695697Smcpowers }
14705697Smcpowers
14715697Smcpowers /* }}} */
14725697Smcpowers
14735697Smcpowers /* {{{ mp_sqrmod(a, m, c) */
14745697Smcpowers
14755697Smcpowers #if MP_SQUARE
mp_sqrmod(const mp_int * a,const mp_int * m,mp_int * c)14765697Smcpowers mp_err mp_sqrmod(const mp_int *a, const mp_int *m, mp_int *c)
14775697Smcpowers {
14785697Smcpowers mp_err res;
14795697Smcpowers
14805697Smcpowers ARGCHK(a != NULL && m != NULL && c != NULL, MP_BADARG);
14815697Smcpowers
14825697Smcpowers if((res = mp_sqr(a, c)) != MP_OKAY)
14835697Smcpowers return res;
14845697Smcpowers if((res = mp_mod(c, m, c)) != MP_OKAY)
14855697Smcpowers return res;
14865697Smcpowers
14875697Smcpowers return MP_OKAY;
14885697Smcpowers
14895697Smcpowers } /* end mp_sqrmod() */
14905697Smcpowers #endif
14915697Smcpowers
14925697Smcpowers /* }}} */
14935697Smcpowers
14945697Smcpowers /* {{{ s_mp_exptmod(a, b, m, c) */
14955697Smcpowers
14965697Smcpowers /*
14975697Smcpowers s_mp_exptmod(a, b, m, c)
14985697Smcpowers
14995697Smcpowers Compute c = (a ** b) mod m. Uses a standard square-and-multiply
15005697Smcpowers method with modular reductions at each step. (This is basically the
15015697Smcpowers same code as mp_expt(), except for the addition of the reductions)
15025697Smcpowers
15035697Smcpowers The modular reductions are done using Barrett's algorithm (see
15045697Smcpowers s_mp_reduce() below for details)
15055697Smcpowers */
15065697Smcpowers
s_mp_exptmod(const mp_int * a,const mp_int * b,const mp_int * m,mp_int * c)15075697Smcpowers mp_err s_mp_exptmod(const mp_int *a, const mp_int *b, const mp_int *m, mp_int *c)
15085697Smcpowers {
15095697Smcpowers mp_int s, x, mu;
15105697Smcpowers mp_err res;
15115697Smcpowers mp_digit d;
15125697Smcpowers int dig, bit;
15135697Smcpowers
15145697Smcpowers ARGCHK(a != NULL && b != NULL && c != NULL, MP_BADARG);
15155697Smcpowers
15165697Smcpowers if(mp_cmp_z(b) < 0 || mp_cmp_z(m) <= 0)
15175697Smcpowers return MP_RANGE;
15185697Smcpowers
15195697Smcpowers if((res = mp_init(&s, FLAG(a))) != MP_OKAY)
15205697Smcpowers return res;
15215697Smcpowers if((res = mp_init_copy(&x, a)) != MP_OKAY ||
15225697Smcpowers (res = mp_mod(&x, m, &x)) != MP_OKAY)
15235697Smcpowers goto X;
15245697Smcpowers if((res = mp_init(&mu, FLAG(a))) != MP_OKAY)
15255697Smcpowers goto MU;
15265697Smcpowers
15275697Smcpowers mp_set(&s, 1);
15285697Smcpowers
15295697Smcpowers /* mu = b^2k / m */
15305697Smcpowers s_mp_add_d(&mu, 1);
15315697Smcpowers s_mp_lshd(&mu, 2 * USED(m));
15325697Smcpowers if((res = mp_div(&mu, m, &mu, NULL)) != MP_OKAY)
15335697Smcpowers goto CLEANUP;
15345697Smcpowers
15355697Smcpowers /* Loop over digits of b in ascending order, except highest order */
15365697Smcpowers for(dig = 0; dig < (USED(b) - 1); dig++) {
15375697Smcpowers d = DIGIT(b, dig);
15385697Smcpowers
15395697Smcpowers /* Loop over the bits of the lower-order digits */
15405697Smcpowers for(bit = 0; bit < DIGIT_BIT; bit++) {
15415697Smcpowers if(d & 1) {
15425697Smcpowers if((res = s_mp_mul(&s, &x)) != MP_OKAY)
15435697Smcpowers goto CLEANUP;
15445697Smcpowers if((res = s_mp_reduce(&s, m, &mu)) != MP_OKAY)
15455697Smcpowers goto CLEANUP;
15465697Smcpowers }
15475697Smcpowers
15485697Smcpowers d >>= 1;
15495697Smcpowers
15505697Smcpowers if((res = s_mp_sqr(&x)) != MP_OKAY)
15515697Smcpowers goto CLEANUP;
15525697Smcpowers if((res = s_mp_reduce(&x, m, &mu)) != MP_OKAY)
15535697Smcpowers goto CLEANUP;
15545697Smcpowers }
15555697Smcpowers }
15565697Smcpowers
15575697Smcpowers /* Now do the last digit... */
15585697Smcpowers d = DIGIT(b, dig);
15595697Smcpowers
15605697Smcpowers while(d) {
15615697Smcpowers if(d & 1) {
15625697Smcpowers if((res = s_mp_mul(&s, &x)) != MP_OKAY)
15635697Smcpowers goto CLEANUP;
15645697Smcpowers if((res = s_mp_reduce(&s, m, &mu)) != MP_OKAY)
15655697Smcpowers goto CLEANUP;
15665697Smcpowers }
15675697Smcpowers
15685697Smcpowers d >>= 1;
15695697Smcpowers
15705697Smcpowers if((res = s_mp_sqr(&x)) != MP_OKAY)
15715697Smcpowers goto CLEANUP;
15725697Smcpowers if((res = s_mp_reduce(&x, m, &mu)) != MP_OKAY)
15735697Smcpowers goto CLEANUP;
15745697Smcpowers }
15755697Smcpowers
15765697Smcpowers s_mp_exch(&s, c);
15775697Smcpowers
15785697Smcpowers CLEANUP:
15795697Smcpowers mp_clear(&mu);
15805697Smcpowers MU:
15815697Smcpowers mp_clear(&x);
15825697Smcpowers X:
15835697Smcpowers mp_clear(&s);
15845697Smcpowers
15855697Smcpowers return res;
15865697Smcpowers
15875697Smcpowers } /* end s_mp_exptmod() */
15885697Smcpowers
15895697Smcpowers /* }}} */
15905697Smcpowers
15915697Smcpowers /* {{{ mp_exptmod_d(a, d, m, c) */
15925697Smcpowers
mp_exptmod_d(const mp_int * a,mp_digit d,const mp_int * m,mp_int * c)15935697Smcpowers mp_err mp_exptmod_d(const mp_int *a, mp_digit d, const mp_int *m, mp_int *c)
15945697Smcpowers {
15955697Smcpowers mp_int s, x;
15965697Smcpowers mp_err res;
15975697Smcpowers
15985697Smcpowers ARGCHK(a != NULL && c != NULL, MP_BADARG);
15995697Smcpowers
16005697Smcpowers if((res = mp_init(&s, FLAG(a))) != MP_OKAY)
16015697Smcpowers return res;
16025697Smcpowers if((res = mp_init_copy(&x, a)) != MP_OKAY)
16035697Smcpowers goto X;
16045697Smcpowers
16055697Smcpowers mp_set(&s, 1);
16065697Smcpowers
16075697Smcpowers while(d != 0) {
16085697Smcpowers if(d & 1) {
16095697Smcpowers if((res = s_mp_mul(&s, &x)) != MP_OKAY ||
16105697Smcpowers (res = mp_mod(&s, m, &s)) != MP_OKAY)
16115697Smcpowers goto CLEANUP;
16125697Smcpowers }
16135697Smcpowers
16145697Smcpowers d /= 2;
16155697Smcpowers
16165697Smcpowers if((res = s_mp_sqr(&x)) != MP_OKAY ||
16175697Smcpowers (res = mp_mod(&x, m, &x)) != MP_OKAY)
16185697Smcpowers goto CLEANUP;
16195697Smcpowers }
16205697Smcpowers
16215697Smcpowers s_mp_exch(&s, c);
16225697Smcpowers
16235697Smcpowers CLEANUP:
16245697Smcpowers mp_clear(&x);
16255697Smcpowers X:
16265697Smcpowers mp_clear(&s);
16275697Smcpowers
16285697Smcpowers return res;
16295697Smcpowers
16305697Smcpowers } /* end mp_exptmod_d() */
16315697Smcpowers
16325697Smcpowers /* }}} */
16335697Smcpowers #endif /* if MP_MODARITH */
16345697Smcpowers
16355697Smcpowers /* }}} */
16365697Smcpowers
16375697Smcpowers /*------------------------------------------------------------------------*/
16385697Smcpowers /* {{{ Comparison functions */
16395697Smcpowers
16405697Smcpowers /* {{{ mp_cmp_z(a) */
16415697Smcpowers
16425697Smcpowers /*
16435697Smcpowers mp_cmp_z(a)
16445697Smcpowers
16455697Smcpowers Compare a <=> 0. Returns <0 if a<0, 0 if a=0, >0 if a>0.
16465697Smcpowers */
16475697Smcpowers
mp_cmp_z(const mp_int * a)16485697Smcpowers int mp_cmp_z(const mp_int *a)
16495697Smcpowers {
16505697Smcpowers if(SIGN(a) == NEG)
16515697Smcpowers return MP_LT;
16525697Smcpowers else if(USED(a) == 1 && DIGIT(a, 0) == 0)
16535697Smcpowers return MP_EQ;
16545697Smcpowers else
16555697Smcpowers return MP_GT;
16565697Smcpowers
16575697Smcpowers } /* end mp_cmp_z() */
16585697Smcpowers
16595697Smcpowers /* }}} */
16605697Smcpowers
16615697Smcpowers /* {{{ mp_cmp_d(a, d) */
16625697Smcpowers
16635697Smcpowers /*
16645697Smcpowers mp_cmp_d(a, d)
16655697Smcpowers
16665697Smcpowers Compare a <=> d. Returns <0 if a<d, 0 if a=d, >0 if a>d
16675697Smcpowers */
16685697Smcpowers
mp_cmp_d(const mp_int * a,mp_digit d)16695697Smcpowers int mp_cmp_d(const mp_int *a, mp_digit d)
16705697Smcpowers {
16715697Smcpowers ARGCHK(a != NULL, MP_EQ);
16725697Smcpowers
16735697Smcpowers if(SIGN(a) == NEG)
16745697Smcpowers return MP_LT;
16755697Smcpowers
16765697Smcpowers return s_mp_cmp_d(a, d);
16775697Smcpowers
16785697Smcpowers } /* end mp_cmp_d() */
16795697Smcpowers
16805697Smcpowers /* }}} */
16815697Smcpowers
16825697Smcpowers /* {{{ mp_cmp(a, b) */
16835697Smcpowers
mp_cmp(const mp_int * a,const mp_int * b)16845697Smcpowers int mp_cmp(const mp_int *a, const mp_int *b)
16855697Smcpowers {
16865697Smcpowers ARGCHK(a != NULL && b != NULL, MP_EQ);
16875697Smcpowers
16885697Smcpowers if(SIGN(a) == SIGN(b)) {
16895697Smcpowers int mag;
16905697Smcpowers
16915697Smcpowers if((mag = s_mp_cmp(a, b)) == MP_EQ)
16925697Smcpowers return MP_EQ;
16935697Smcpowers
16945697Smcpowers if(SIGN(a) == ZPOS)
16955697Smcpowers return mag;
16965697Smcpowers else
16975697Smcpowers return -mag;
16985697Smcpowers
16995697Smcpowers } else if(SIGN(a) == ZPOS) {
17005697Smcpowers return MP_GT;
17015697Smcpowers } else {
17025697Smcpowers return MP_LT;
17035697Smcpowers }
17045697Smcpowers
17055697Smcpowers } /* end mp_cmp() */
17065697Smcpowers
17075697Smcpowers /* }}} */
17085697Smcpowers
17095697Smcpowers /* {{{ mp_cmp_mag(a, b) */
17105697Smcpowers
17115697Smcpowers /*
17125697Smcpowers mp_cmp_mag(a, b)
17135697Smcpowers
17145697Smcpowers Compares |a| <=> |b|, and returns an appropriate comparison result
17155697Smcpowers */
17165697Smcpowers
mp_cmp_mag(mp_int * a,mp_int * b)17175697Smcpowers int mp_cmp_mag(mp_int *a, mp_int *b)
17185697Smcpowers {
17195697Smcpowers ARGCHK(a != NULL && b != NULL, MP_EQ);
17205697Smcpowers
17215697Smcpowers return s_mp_cmp(a, b);
17225697Smcpowers
17235697Smcpowers } /* end mp_cmp_mag() */
17245697Smcpowers
17255697Smcpowers /* }}} */
17265697Smcpowers
17275697Smcpowers /* {{{ mp_cmp_int(a, z, kmflag) */
17285697Smcpowers
17295697Smcpowers /*
17305697Smcpowers This just converts z to an mp_int, and uses the existing comparison
17315697Smcpowers routines. This is sort of inefficient, but it's not clear to me how
17325697Smcpowers frequently this wil get used anyway. For small positive constants,
17335697Smcpowers you can always use mp_cmp_d(), and for zero, there is mp_cmp_z().
17345697Smcpowers */
mp_cmp_int(const mp_int * a,long z,int kmflag)17355697Smcpowers int mp_cmp_int(const mp_int *a, long z, int kmflag)
17365697Smcpowers {
17375697Smcpowers mp_int tmp;
17385697Smcpowers int out;
17395697Smcpowers
17405697Smcpowers ARGCHK(a != NULL, MP_EQ);
17415697Smcpowers
17425697Smcpowers mp_init(&tmp, kmflag); mp_set_int(&tmp, z);
17435697Smcpowers out = mp_cmp(a, &tmp);
17445697Smcpowers mp_clear(&tmp);
17455697Smcpowers
17465697Smcpowers return out;
17475697Smcpowers
17485697Smcpowers } /* end mp_cmp_int() */
17495697Smcpowers
17505697Smcpowers /* }}} */
17515697Smcpowers
17525697Smcpowers /* {{{ mp_isodd(a) */
17535697Smcpowers
17545697Smcpowers /*
17555697Smcpowers mp_isodd(a)
17565697Smcpowers
17575697Smcpowers Returns a true (non-zero) value if a is odd, false (zero) otherwise.
17585697Smcpowers */
mp_isodd(const mp_int * a)17595697Smcpowers int mp_isodd(const mp_int *a)
17605697Smcpowers {
17615697Smcpowers ARGCHK(a != NULL, 0);
17625697Smcpowers
17635697Smcpowers return (int)(DIGIT(a, 0) & 1);
17645697Smcpowers
17655697Smcpowers } /* end mp_isodd() */
17665697Smcpowers
17675697Smcpowers /* }}} */
17685697Smcpowers
17695697Smcpowers /* {{{ mp_iseven(a) */
17705697Smcpowers
mp_iseven(const mp_int * a)17715697Smcpowers int mp_iseven(const mp_int *a)
17725697Smcpowers {
17735697Smcpowers return !mp_isodd(a);
17745697Smcpowers
17755697Smcpowers } /* end mp_iseven() */
17765697Smcpowers
17775697Smcpowers /* }}} */
17785697Smcpowers
17795697Smcpowers /* }}} */
17805697Smcpowers
17815697Smcpowers /*------------------------------------------------------------------------*/
17825697Smcpowers /* {{{ Number theoretic functions */
17835697Smcpowers
17845697Smcpowers #if MP_NUMTH
17855697Smcpowers /* {{{ mp_gcd(a, b, c) */
17865697Smcpowers
17875697Smcpowers /*
17885697Smcpowers Like the old mp_gcd() function, except computes the GCD using the
17895697Smcpowers binary algorithm due to Josef Stein in 1961 (via Knuth).
17905697Smcpowers */
mp_gcd(mp_int * a,mp_int * b,mp_int * c)17915697Smcpowers mp_err mp_gcd(mp_int *a, mp_int *b, mp_int *c)
17925697Smcpowers {
17935697Smcpowers mp_err res;
17945697Smcpowers mp_int u, v, t;
17955697Smcpowers mp_size k = 0;
17965697Smcpowers
17975697Smcpowers ARGCHK(a != NULL && b != NULL && c != NULL, MP_BADARG);
17985697Smcpowers
17995697Smcpowers if(mp_cmp_z(a) == MP_EQ && mp_cmp_z(b) == MP_EQ)
18005697Smcpowers return MP_RANGE;
18015697Smcpowers if(mp_cmp_z(a) == MP_EQ) {
18025697Smcpowers return mp_copy(b, c);
18035697Smcpowers } else if(mp_cmp_z(b) == MP_EQ) {
18045697Smcpowers return mp_copy(a, c);
18055697Smcpowers }
18065697Smcpowers
18075697Smcpowers if((res = mp_init(&t, FLAG(a))) != MP_OKAY)
18085697Smcpowers return res;
18095697Smcpowers if((res = mp_init_copy(&u, a)) != MP_OKAY)
18105697Smcpowers goto U;
18115697Smcpowers if((res = mp_init_copy(&v, b)) != MP_OKAY)
18125697Smcpowers goto V;
18135697Smcpowers
18145697Smcpowers SIGN(&u) = ZPOS;
18155697Smcpowers SIGN(&v) = ZPOS;
18165697Smcpowers
18175697Smcpowers /* Divide out common factors of 2 until at least 1 of a, b is even */
18185697Smcpowers while(mp_iseven(&u) && mp_iseven(&v)) {
18195697Smcpowers s_mp_div_2(&u);
18205697Smcpowers s_mp_div_2(&v);
18215697Smcpowers ++k;
18225697Smcpowers }
18235697Smcpowers
18245697Smcpowers /* Initialize t */
18255697Smcpowers if(mp_isodd(&u)) {
18265697Smcpowers if((res = mp_copy(&v, &t)) != MP_OKAY)
18275697Smcpowers goto CLEANUP;
18285697Smcpowers
18295697Smcpowers /* t = -v */
18305697Smcpowers if(SIGN(&v) == ZPOS)
18315697Smcpowers SIGN(&t) = NEG;
18325697Smcpowers else
18335697Smcpowers SIGN(&t) = ZPOS;
18345697Smcpowers
18355697Smcpowers } else {
18365697Smcpowers if((res = mp_copy(&u, &t)) != MP_OKAY)
18375697Smcpowers goto CLEANUP;
18385697Smcpowers
18395697Smcpowers }
18405697Smcpowers
18415697Smcpowers for(;;) {
18425697Smcpowers while(mp_iseven(&t)) {
18435697Smcpowers s_mp_div_2(&t);
18445697Smcpowers }
18455697Smcpowers
18465697Smcpowers if(mp_cmp_z(&t) == MP_GT) {
18475697Smcpowers if((res = mp_copy(&t, &u)) != MP_OKAY)
18485697Smcpowers goto CLEANUP;
18495697Smcpowers
18505697Smcpowers } else {
18515697Smcpowers if((res = mp_copy(&t, &v)) != MP_OKAY)
18525697Smcpowers goto CLEANUP;
18535697Smcpowers
18545697Smcpowers /* v = -t */
18555697Smcpowers if(SIGN(&t) == ZPOS)
18565697Smcpowers SIGN(&v) = NEG;
18575697Smcpowers else
18585697Smcpowers SIGN(&v) = ZPOS;
18595697Smcpowers }
18605697Smcpowers
18615697Smcpowers if((res = mp_sub(&u, &v, &t)) != MP_OKAY)
18625697Smcpowers goto CLEANUP;
18635697Smcpowers
18645697Smcpowers if(s_mp_cmp_d(&t, 0) == MP_EQ)
18655697Smcpowers break;
18665697Smcpowers }
18675697Smcpowers
18685697Smcpowers s_mp_2expt(&v, k); /* v = 2^k */
18695697Smcpowers res = mp_mul(&u, &v, c); /* c = u * v */
18705697Smcpowers
18715697Smcpowers CLEANUP:
18725697Smcpowers mp_clear(&v);
18735697Smcpowers V:
18745697Smcpowers mp_clear(&u);
18755697Smcpowers U:
18765697Smcpowers mp_clear(&t);
18775697Smcpowers
18785697Smcpowers return res;
18795697Smcpowers
18805697Smcpowers } /* end mp_gcd() */
18815697Smcpowers
18825697Smcpowers /* }}} */
18835697Smcpowers
18845697Smcpowers /* {{{ mp_lcm(a, b, c) */
18855697Smcpowers
18865697Smcpowers /* We compute the least common multiple using the rule:
18875697Smcpowers
18885697Smcpowers ab = [a, b](a, b)
18895697Smcpowers
18905697Smcpowers ... by computing the product, and dividing out the gcd.
18915697Smcpowers */
18925697Smcpowers
mp_lcm(mp_int * a,mp_int * b,mp_int * c)18935697Smcpowers mp_err mp_lcm(mp_int *a, mp_int *b, mp_int *c)
18945697Smcpowers {
18955697Smcpowers mp_int gcd, prod;
18965697Smcpowers mp_err res;
18975697Smcpowers
18985697Smcpowers ARGCHK(a != NULL && b != NULL && c != NULL, MP_BADARG);
18995697Smcpowers
19005697Smcpowers /* Set up temporaries */
19015697Smcpowers if((res = mp_init(&gcd, FLAG(a))) != MP_OKAY)
19025697Smcpowers return res;
19035697Smcpowers if((res = mp_init(&prod, FLAG(a))) != MP_OKAY)
19045697Smcpowers goto GCD;
19055697Smcpowers
19065697Smcpowers if((res = mp_mul(a, b, &prod)) != MP_OKAY)
19075697Smcpowers goto CLEANUP;
19085697Smcpowers if((res = mp_gcd(a, b, &gcd)) != MP_OKAY)
19095697Smcpowers goto CLEANUP;
19105697Smcpowers
19115697Smcpowers res = mp_div(&prod, &gcd, c, NULL);
19125697Smcpowers
19135697Smcpowers CLEANUP:
19145697Smcpowers mp_clear(&prod);
19155697Smcpowers GCD:
19165697Smcpowers mp_clear(&gcd);
19175697Smcpowers
19185697Smcpowers return res;
19195697Smcpowers
19205697Smcpowers } /* end mp_lcm() */
19215697Smcpowers
19225697Smcpowers /* }}} */
19235697Smcpowers
19245697Smcpowers /* {{{ mp_xgcd(a, b, g, x, y) */
19255697Smcpowers
19265697Smcpowers /*
19275697Smcpowers mp_xgcd(a, b, g, x, y)
19285697Smcpowers
19295697Smcpowers Compute g = (a, b) and values x and y satisfying Bezout's identity
19305697Smcpowers (that is, ax + by = g). This uses the binary extended GCD algorithm
19315697Smcpowers based on the Stein algorithm used for mp_gcd()
19325697Smcpowers See algorithm 14.61 in Handbook of Applied Cryptogrpahy.
19335697Smcpowers */
19345697Smcpowers
mp_xgcd(const mp_int * a,const mp_int * b,mp_int * g,mp_int * x,mp_int * y)19355697Smcpowers mp_err mp_xgcd(const mp_int *a, const mp_int *b, mp_int *g, mp_int *x, mp_int *y)
19365697Smcpowers {
19375697Smcpowers mp_int gx, xc, yc, u, v, A, B, C, D;
19385697Smcpowers mp_int *clean[9];
19395697Smcpowers mp_err res;
19405697Smcpowers int last = -1;
19415697Smcpowers
19425697Smcpowers if(mp_cmp_z(b) == 0)
19435697Smcpowers return MP_RANGE;
19445697Smcpowers
19455697Smcpowers /* Initialize all these variables we need */
19465697Smcpowers MP_CHECKOK( mp_init(&u, FLAG(a)) );
19475697Smcpowers clean[++last] = &u;
19485697Smcpowers MP_CHECKOK( mp_init(&v, FLAG(a)) );
19495697Smcpowers clean[++last] = &v;
19505697Smcpowers MP_CHECKOK( mp_init(&gx, FLAG(a)) );
19515697Smcpowers clean[++last] = &gx;
19525697Smcpowers MP_CHECKOK( mp_init(&A, FLAG(a)) );
19535697Smcpowers clean[++last] = &A;
19545697Smcpowers MP_CHECKOK( mp_init(&B, FLAG(a)) );
19555697Smcpowers clean[++last] = &B;
19565697Smcpowers MP_CHECKOK( mp_init(&C, FLAG(a)) );
19575697Smcpowers clean[++last] = &C;
19585697Smcpowers MP_CHECKOK( mp_init(&D, FLAG(a)) );
19595697Smcpowers clean[++last] = &D;
19605697Smcpowers MP_CHECKOK( mp_init_copy(&xc, a) );
19615697Smcpowers clean[++last] = &xc;
19625697Smcpowers mp_abs(&xc, &xc);
19635697Smcpowers MP_CHECKOK( mp_init_copy(&yc, b) );
19645697Smcpowers clean[++last] = &yc;
19655697Smcpowers mp_abs(&yc, &yc);
19665697Smcpowers
19675697Smcpowers mp_set(&gx, 1);
19685697Smcpowers
19695697Smcpowers /* Divide by two until at least one of them is odd */
19705697Smcpowers while(mp_iseven(&xc) && mp_iseven(&yc)) {
19715697Smcpowers mp_size nx = mp_trailing_zeros(&xc);
19725697Smcpowers mp_size ny = mp_trailing_zeros(&yc);
19735697Smcpowers mp_size n = MP_MIN(nx, ny);
19745697Smcpowers s_mp_div_2d(&xc,n);
19755697Smcpowers s_mp_div_2d(&yc,n);
19765697Smcpowers MP_CHECKOK( s_mp_mul_2d(&gx,n) );
19775697Smcpowers }
19785697Smcpowers
19795697Smcpowers mp_copy(&xc, &u);
19805697Smcpowers mp_copy(&yc, &v);
19815697Smcpowers mp_set(&A, 1); mp_set(&D, 1);
19825697Smcpowers
19835697Smcpowers /* Loop through binary GCD algorithm */
19845697Smcpowers do {
19855697Smcpowers while(mp_iseven(&u)) {
19865697Smcpowers s_mp_div_2(&u);
19875697Smcpowers
19885697Smcpowers if(mp_iseven(&A) && mp_iseven(&B)) {
19895697Smcpowers s_mp_div_2(&A); s_mp_div_2(&B);
19905697Smcpowers } else {
19915697Smcpowers MP_CHECKOK( mp_add(&A, &yc, &A) );
19925697Smcpowers s_mp_div_2(&A);
19935697Smcpowers MP_CHECKOK( mp_sub(&B, &xc, &B) );
19945697Smcpowers s_mp_div_2(&B);
19955697Smcpowers }
19965697Smcpowers }
19975697Smcpowers
19985697Smcpowers while(mp_iseven(&v)) {
19995697Smcpowers s_mp_div_2(&v);
20005697Smcpowers
20015697Smcpowers if(mp_iseven(&C) && mp_iseven(&D)) {
20025697Smcpowers s_mp_div_2(&C); s_mp_div_2(&D);
20035697Smcpowers } else {
20045697Smcpowers MP_CHECKOK( mp_add(&C, &yc, &C) );
20055697Smcpowers s_mp_div_2(&C);
20065697Smcpowers MP_CHECKOK( mp_sub(&D, &xc, &D) );
20075697Smcpowers s_mp_div_2(&D);
20085697Smcpowers }
20095697Smcpowers }
20105697Smcpowers
20115697Smcpowers if(mp_cmp(&u, &v) >= 0) {
20125697Smcpowers MP_CHECKOK( mp_sub(&u, &v, &u) );
20135697Smcpowers MP_CHECKOK( mp_sub(&A, &C, &A) );
20145697Smcpowers MP_CHECKOK( mp_sub(&B, &D, &B) );
20155697Smcpowers } else {
20165697Smcpowers MP_CHECKOK( mp_sub(&v, &u, &v) );
20175697Smcpowers MP_CHECKOK( mp_sub(&C, &A, &C) );
20185697Smcpowers MP_CHECKOK( mp_sub(&D, &B, &D) );
20195697Smcpowers }
20205697Smcpowers } while (mp_cmp_z(&u) != 0);
20215697Smcpowers
20225697Smcpowers /* copy results to output */
20235697Smcpowers if(x)
20245697Smcpowers MP_CHECKOK( mp_copy(&C, x) );
20255697Smcpowers
20265697Smcpowers if(y)
20275697Smcpowers MP_CHECKOK( mp_copy(&D, y) );
20285697Smcpowers
20295697Smcpowers if(g)
20305697Smcpowers MP_CHECKOK( mp_mul(&gx, &v, g) );
20315697Smcpowers
20325697Smcpowers CLEANUP:
20335697Smcpowers while(last >= 0)
20345697Smcpowers mp_clear(clean[last--]);
20355697Smcpowers
20365697Smcpowers return res;
20375697Smcpowers
20385697Smcpowers } /* end mp_xgcd() */
20395697Smcpowers
20405697Smcpowers /* }}} */
20415697Smcpowers
mp_trailing_zeros(const mp_int * mp)20425697Smcpowers mp_size mp_trailing_zeros(const mp_int *mp)
20435697Smcpowers {
20445697Smcpowers mp_digit d;
20455697Smcpowers mp_size n = 0;
20465697Smcpowers int ix;
20475697Smcpowers
20485697Smcpowers if (!mp || !MP_DIGITS(mp) || !mp_cmp_z(mp))
20495697Smcpowers return n;
20505697Smcpowers
20515697Smcpowers for (ix = 0; !(d = MP_DIGIT(mp,ix)) && (ix < MP_USED(mp)); ++ix)
20525697Smcpowers n += MP_DIGIT_BIT;
20535697Smcpowers if (!d)
20545697Smcpowers return 0; /* shouldn't happen, but ... */
20555697Smcpowers #if !defined(MP_USE_UINT_DIGIT)
20565697Smcpowers if (!(d & 0xffffffffU)) {
20575697Smcpowers d >>= 32;
20585697Smcpowers n += 32;
20595697Smcpowers }
20605697Smcpowers #endif
20615697Smcpowers if (!(d & 0xffffU)) {
20625697Smcpowers d >>= 16;
20635697Smcpowers n += 16;
20645697Smcpowers }
20655697Smcpowers if (!(d & 0xffU)) {
20665697Smcpowers d >>= 8;
20675697Smcpowers n += 8;
20685697Smcpowers }
20695697Smcpowers if (!(d & 0xfU)) {
20705697Smcpowers d >>= 4;
20715697Smcpowers n += 4;
20725697Smcpowers }
20735697Smcpowers if (!(d & 0x3U)) {
20745697Smcpowers d >>= 2;
20755697Smcpowers n += 2;
20765697Smcpowers }
20775697Smcpowers if (!(d & 0x1U)) {
20785697Smcpowers d >>= 1;
20795697Smcpowers n += 1;
20805697Smcpowers }
20815697Smcpowers #if MP_ARGCHK == 2
20825697Smcpowers assert(0 != (d & 1));
20835697Smcpowers #endif
20845697Smcpowers return n;
20855697Smcpowers }
20865697Smcpowers
20875697Smcpowers /* Given a and prime p, computes c and k such that a*c == 2**k (mod p).
20885697Smcpowers ** Returns k (positive) or error (negative).
20895697Smcpowers ** This technique from the paper "Fast Modular Reciprocals" (unpublished)
20905697Smcpowers ** by Richard Schroeppel (a.k.a. Captain Nemo).
20915697Smcpowers */
s_mp_almost_inverse(const mp_int * a,const mp_int * p,mp_int * c)20925697Smcpowers mp_err s_mp_almost_inverse(const mp_int *a, const mp_int *p, mp_int *c)
20935697Smcpowers {
20945697Smcpowers mp_err res;
20955697Smcpowers mp_err k = 0;
20965697Smcpowers mp_int d, f, g;
20975697Smcpowers
20985697Smcpowers ARGCHK(a && p && c, MP_BADARG);
20995697Smcpowers
21005697Smcpowers MP_DIGITS(&d) = 0;
21015697Smcpowers MP_DIGITS(&f) = 0;
21025697Smcpowers MP_DIGITS(&g) = 0;
21035697Smcpowers MP_CHECKOK( mp_init(&d, FLAG(a)) );
21045697Smcpowers MP_CHECKOK( mp_init_copy(&f, a) ); /* f = a */
21055697Smcpowers MP_CHECKOK( mp_init_copy(&g, p) ); /* g = p */
21065697Smcpowers
21075697Smcpowers mp_set(c, 1);
21085697Smcpowers mp_zero(&d);
21095697Smcpowers
21105697Smcpowers if (mp_cmp_z(&f) == 0) {
21115697Smcpowers res = MP_UNDEF;
21125697Smcpowers } else
21135697Smcpowers for (;;) {
21145697Smcpowers int diff_sign;
21155697Smcpowers while (mp_iseven(&f)) {
21165697Smcpowers mp_size n = mp_trailing_zeros(&f);
21175697Smcpowers if (!n) {
21185697Smcpowers res = MP_UNDEF;
21195697Smcpowers goto CLEANUP;
21205697Smcpowers }
21215697Smcpowers s_mp_div_2d(&f, n);
21225697Smcpowers MP_CHECKOK( s_mp_mul_2d(&d, n) );
21235697Smcpowers k += n;
21245697Smcpowers }
21255697Smcpowers if (mp_cmp_d(&f, 1) == MP_EQ) { /* f == 1 */
21265697Smcpowers res = k;
21275697Smcpowers break;
21285697Smcpowers }
21295697Smcpowers diff_sign = mp_cmp(&f, &g);
21305697Smcpowers if (diff_sign < 0) { /* f < g */
21315697Smcpowers s_mp_exch(&f, &g);
21325697Smcpowers s_mp_exch(c, &d);
21335697Smcpowers } else if (diff_sign == 0) { /* f == g */
21345697Smcpowers res = MP_UNDEF; /* a and p are not relatively prime */
21355697Smcpowers break;
21365697Smcpowers }
21375697Smcpowers if ((MP_DIGIT(&f,0) % 4) == (MP_DIGIT(&g,0) % 4)) {
21385697Smcpowers MP_CHECKOK( mp_sub(&f, &g, &f) ); /* f = f - g */
21395697Smcpowers MP_CHECKOK( mp_sub(c, &d, c) ); /* c = c - d */
21405697Smcpowers } else {
21415697Smcpowers MP_CHECKOK( mp_add(&f, &g, &f) ); /* f = f + g */
21425697Smcpowers MP_CHECKOK( mp_add(c, &d, c) ); /* c = c + d */
21435697Smcpowers }
21445697Smcpowers }
21455697Smcpowers if (res >= 0) {
21465697Smcpowers while (MP_SIGN(c) != MP_ZPOS) {
21475697Smcpowers MP_CHECKOK( mp_add(c, p, c) );
21485697Smcpowers }
21495697Smcpowers res = k;
21505697Smcpowers }
21515697Smcpowers
21525697Smcpowers CLEANUP:
21535697Smcpowers mp_clear(&d);
21545697Smcpowers mp_clear(&f);
21555697Smcpowers mp_clear(&g);
21565697Smcpowers return res;
21575697Smcpowers }
21585697Smcpowers
21595697Smcpowers /* Compute T = (P ** -1) mod MP_RADIX. Also works for 16-bit mp_digits.
21605697Smcpowers ** This technique from the paper "Fast Modular Reciprocals" (unpublished)
21615697Smcpowers ** by Richard Schroeppel (a.k.a. Captain Nemo).
21625697Smcpowers */
s_mp_invmod_radix(mp_digit P)21635697Smcpowers mp_digit s_mp_invmod_radix(mp_digit P)
21645697Smcpowers {
21655697Smcpowers mp_digit T = P;
21665697Smcpowers T *= 2 - (P * T);
21675697Smcpowers T *= 2 - (P * T);
21685697Smcpowers T *= 2 - (P * T);
21695697Smcpowers T *= 2 - (P * T);
21705697Smcpowers #if !defined(MP_USE_UINT_DIGIT)
21715697Smcpowers T *= 2 - (P * T);
21725697Smcpowers T *= 2 - (P * T);
21735697Smcpowers #endif
21745697Smcpowers return T;
21755697Smcpowers }
21765697Smcpowers
21775697Smcpowers /* Given c, k, and prime p, where a*c == 2**k (mod p),
21785697Smcpowers ** Compute x = (a ** -1) mod p. This is similar to Montgomery reduction.
21795697Smcpowers ** This technique from the paper "Fast Modular Reciprocals" (unpublished)
21805697Smcpowers ** by Richard Schroeppel (a.k.a. Captain Nemo).
21815697Smcpowers */
s_mp_fixup_reciprocal(const mp_int * c,const mp_int * p,int k,mp_int * x)21825697Smcpowers mp_err s_mp_fixup_reciprocal(const mp_int *c, const mp_int *p, int k, mp_int *x)
21835697Smcpowers {
21845697Smcpowers int k_orig = k;
21855697Smcpowers mp_digit r;
21865697Smcpowers mp_size ix;
21875697Smcpowers mp_err res;
21885697Smcpowers
21895697Smcpowers if (mp_cmp_z(c) < 0) { /* c < 0 */
21905697Smcpowers MP_CHECKOK( mp_add(c, p, x) ); /* x = c + p */
21915697Smcpowers } else {
21925697Smcpowers MP_CHECKOK( mp_copy(c, x) ); /* x = c */
21935697Smcpowers }
21945697Smcpowers
21955697Smcpowers /* make sure x is large enough */
21965697Smcpowers ix = MP_HOWMANY(k, MP_DIGIT_BIT) + MP_USED(p) + 1;
21975697Smcpowers ix = MP_MAX(ix, MP_USED(x));
21985697Smcpowers MP_CHECKOK( s_mp_pad(x, ix) );
21995697Smcpowers
22005697Smcpowers r = 0 - s_mp_invmod_radix(MP_DIGIT(p,0));
22015697Smcpowers
22025697Smcpowers for (ix = 0; k > 0; ix++) {
22035697Smcpowers int j = MP_MIN(k, MP_DIGIT_BIT);
22045697Smcpowers mp_digit v = r * MP_DIGIT(x, ix);
22055697Smcpowers if (j < MP_DIGIT_BIT) {
22065697Smcpowers v &= ((mp_digit)1 << j) - 1; /* v = v mod (2 ** j) */
22075697Smcpowers }
22085697Smcpowers s_mp_mul_d_add_offset(p, v, x, ix); /* x += p * v * (RADIX ** ix) */
22095697Smcpowers k -= j;
22105697Smcpowers }
22115697Smcpowers s_mp_clamp(x);
22125697Smcpowers s_mp_div_2d(x, k_orig);
22135697Smcpowers res = MP_OKAY;
22145697Smcpowers
22155697Smcpowers CLEANUP:
22165697Smcpowers return res;
22175697Smcpowers }
22185697Smcpowers
22195697Smcpowers /* compute mod inverse using Schroeppel's method, only if m is odd */
s_mp_invmod_odd_m(const mp_int * a,const mp_int * m,mp_int * c)22205697Smcpowers mp_err s_mp_invmod_odd_m(const mp_int *a, const mp_int *m, mp_int *c)
22215697Smcpowers {
22225697Smcpowers int k;
22235697Smcpowers mp_err res;
22245697Smcpowers mp_int x;
22255697Smcpowers
22265697Smcpowers ARGCHK(a && m && c, MP_BADARG);
22275697Smcpowers
22285697Smcpowers if(mp_cmp_z(a) == 0 || mp_cmp_z(m) == 0)
22295697Smcpowers return MP_RANGE;
22305697Smcpowers if (mp_iseven(m))
22315697Smcpowers return MP_UNDEF;
22325697Smcpowers
22335697Smcpowers MP_DIGITS(&x) = 0;
22345697Smcpowers
22355697Smcpowers if (a == c) {
22365697Smcpowers if ((res = mp_init_copy(&x, a)) != MP_OKAY)
22375697Smcpowers return res;
22385697Smcpowers if (a == m)
22395697Smcpowers m = &x;
22405697Smcpowers a = &x;
22415697Smcpowers } else if (m == c) {
22425697Smcpowers if ((res = mp_init_copy(&x, m)) != MP_OKAY)
22435697Smcpowers return res;
22445697Smcpowers m = &x;
22455697Smcpowers } else {
22465697Smcpowers MP_DIGITS(&x) = 0;
22475697Smcpowers }
22485697Smcpowers
22495697Smcpowers MP_CHECKOK( s_mp_almost_inverse(a, m, c) );
22505697Smcpowers k = res;
22515697Smcpowers MP_CHECKOK( s_mp_fixup_reciprocal(c, m, k, c) );
22525697Smcpowers CLEANUP:
22535697Smcpowers mp_clear(&x);
22545697Smcpowers return res;
22555697Smcpowers }
22565697Smcpowers
22575697Smcpowers /* Known good algorithm for computing modular inverse. But slow. */
mp_invmod_xgcd(const mp_int * a,const mp_int * m,mp_int * c)22585697Smcpowers mp_err mp_invmod_xgcd(const mp_int *a, const mp_int *m, mp_int *c)
22595697Smcpowers {
22605697Smcpowers mp_int g, x;
22615697Smcpowers mp_err res;
22625697Smcpowers
22635697Smcpowers ARGCHK(a && m && c, MP_BADARG);
22645697Smcpowers
22655697Smcpowers if(mp_cmp_z(a) == 0 || mp_cmp_z(m) == 0)
22665697Smcpowers return MP_RANGE;
22675697Smcpowers
22685697Smcpowers MP_DIGITS(&g) = 0;
22695697Smcpowers MP_DIGITS(&x) = 0;
22705697Smcpowers MP_CHECKOK( mp_init(&x, FLAG(a)) );
22715697Smcpowers MP_CHECKOK( mp_init(&g, FLAG(a)) );
22725697Smcpowers
22735697Smcpowers MP_CHECKOK( mp_xgcd(a, m, &g, &x, NULL) );
22745697Smcpowers
22755697Smcpowers if (mp_cmp_d(&g, 1) != MP_EQ) {
22765697Smcpowers res = MP_UNDEF;
22775697Smcpowers goto CLEANUP;
22785697Smcpowers }
22795697Smcpowers
22805697Smcpowers res = mp_mod(&x, m, c);
22815697Smcpowers SIGN(c) = SIGN(a);
22825697Smcpowers
22835697Smcpowers CLEANUP:
22845697Smcpowers mp_clear(&x);
22855697Smcpowers mp_clear(&g);
22865697Smcpowers
22875697Smcpowers return res;
22885697Smcpowers }
22895697Smcpowers
22905697Smcpowers /* modular inverse where modulus is 2**k. */
22915697Smcpowers /* c = a**-1 mod 2**k */
s_mp_invmod_2d(const mp_int * a,mp_size k,mp_int * c)22925697Smcpowers mp_err s_mp_invmod_2d(const mp_int *a, mp_size k, mp_int *c)
22935697Smcpowers {
22945697Smcpowers mp_err res;
22955697Smcpowers mp_size ix = k + 4;
22965697Smcpowers mp_int t0, t1, val, tmp, two2k;
22975697Smcpowers
22985697Smcpowers static const mp_digit d2 = 2;
22995697Smcpowers static const mp_int two = { 0, MP_ZPOS, 1, 1, (mp_digit *)&d2 };
23005697Smcpowers
23015697Smcpowers if (mp_iseven(a))
23025697Smcpowers return MP_UNDEF;
23035697Smcpowers if (k <= MP_DIGIT_BIT) {
23045697Smcpowers mp_digit i = s_mp_invmod_radix(MP_DIGIT(a,0));
23055697Smcpowers if (k < MP_DIGIT_BIT)
23065697Smcpowers i &= ((mp_digit)1 << k) - (mp_digit)1;
23075697Smcpowers mp_set(c, i);
23085697Smcpowers return MP_OKAY;
23095697Smcpowers }
23105697Smcpowers MP_DIGITS(&t0) = 0;
23115697Smcpowers MP_DIGITS(&t1) = 0;
23125697Smcpowers MP_DIGITS(&val) = 0;
23135697Smcpowers MP_DIGITS(&tmp) = 0;
23145697Smcpowers MP_DIGITS(&two2k) = 0;
23155697Smcpowers MP_CHECKOK( mp_init_copy(&val, a) );
23165697Smcpowers s_mp_mod_2d(&val, k);
23175697Smcpowers MP_CHECKOK( mp_init_copy(&t0, &val) );
23185697Smcpowers MP_CHECKOK( mp_init_copy(&t1, &t0) );
23195697Smcpowers MP_CHECKOK( mp_init(&tmp, FLAG(a)) );
23205697Smcpowers MP_CHECKOK( mp_init(&two2k, FLAG(a)) );
23215697Smcpowers MP_CHECKOK( s_mp_2expt(&two2k, k) );
23225697Smcpowers do {
23235697Smcpowers MP_CHECKOK( mp_mul(&val, &t1, &tmp) );
23245697Smcpowers MP_CHECKOK( mp_sub(&two, &tmp, &tmp) );
23255697Smcpowers MP_CHECKOK( mp_mul(&t1, &tmp, &t1) );
23265697Smcpowers s_mp_mod_2d(&t1, k);
23275697Smcpowers while (MP_SIGN(&t1) != MP_ZPOS) {
23285697Smcpowers MP_CHECKOK( mp_add(&t1, &two2k, &t1) );
23295697Smcpowers }
23305697Smcpowers if (mp_cmp(&t1, &t0) == MP_EQ)
23315697Smcpowers break;
23325697Smcpowers MP_CHECKOK( mp_copy(&t1, &t0) );
23335697Smcpowers } while (--ix > 0);
23345697Smcpowers if (!ix) {
23355697Smcpowers res = MP_UNDEF;
23365697Smcpowers } else {
23375697Smcpowers mp_exch(c, &t1);
23385697Smcpowers }
23395697Smcpowers
23405697Smcpowers CLEANUP:
23415697Smcpowers mp_clear(&t0);
23425697Smcpowers mp_clear(&t1);
23435697Smcpowers mp_clear(&val);
23445697Smcpowers mp_clear(&tmp);
23455697Smcpowers mp_clear(&two2k);
23465697Smcpowers return res;
23475697Smcpowers }
23485697Smcpowers
s_mp_invmod_even_m(const mp_int * a,const mp_int * m,mp_int * c)23495697Smcpowers mp_err s_mp_invmod_even_m(const mp_int *a, const mp_int *m, mp_int *c)
23505697Smcpowers {
23515697Smcpowers mp_err res;
23525697Smcpowers mp_size k;
23535697Smcpowers mp_int oddFactor, evenFactor; /* factors of the modulus */
23545697Smcpowers mp_int oddPart, evenPart; /* parts to combine via CRT. */
23555697Smcpowers mp_int C2, tmp1, tmp2;
23565697Smcpowers
23575697Smcpowers /*static const mp_digit d1 = 1; */
23585697Smcpowers /*static const mp_int one = { MP_ZPOS, 1, 1, (mp_digit *)&d1 }; */
23595697Smcpowers
23605697Smcpowers if ((res = s_mp_ispow2(m)) >= 0) {
23615697Smcpowers k = res;
23625697Smcpowers return s_mp_invmod_2d(a, k, c);
23635697Smcpowers }
23645697Smcpowers MP_DIGITS(&oddFactor) = 0;
23655697Smcpowers MP_DIGITS(&evenFactor) = 0;
23665697Smcpowers MP_DIGITS(&oddPart) = 0;
23675697Smcpowers MP_DIGITS(&evenPart) = 0;
23685697Smcpowers MP_DIGITS(&C2) = 0;
23695697Smcpowers MP_DIGITS(&tmp1) = 0;
23705697Smcpowers MP_DIGITS(&tmp2) = 0;
23715697Smcpowers
23725697Smcpowers MP_CHECKOK( mp_init_copy(&oddFactor, m) ); /* oddFactor = m */
23735697Smcpowers MP_CHECKOK( mp_init(&evenFactor, FLAG(m)) );
23745697Smcpowers MP_CHECKOK( mp_init(&oddPart, FLAG(m)) );
23755697Smcpowers MP_CHECKOK( mp_init(&evenPart, FLAG(m)) );
23765697Smcpowers MP_CHECKOK( mp_init(&C2, FLAG(m)) );
23775697Smcpowers MP_CHECKOK( mp_init(&tmp1, FLAG(m)) );
23785697Smcpowers MP_CHECKOK( mp_init(&tmp2, FLAG(m)) );
23795697Smcpowers
23805697Smcpowers k = mp_trailing_zeros(m);
23815697Smcpowers s_mp_div_2d(&oddFactor, k);
23825697Smcpowers MP_CHECKOK( s_mp_2expt(&evenFactor, k) );
23835697Smcpowers
23845697Smcpowers /* compute a**-1 mod oddFactor. */
23855697Smcpowers MP_CHECKOK( s_mp_invmod_odd_m(a, &oddFactor, &oddPart) );
23865697Smcpowers /* compute a**-1 mod evenFactor, where evenFactor == 2**k. */
23875697Smcpowers MP_CHECKOK( s_mp_invmod_2d( a, k, &evenPart) );
23885697Smcpowers
23895697Smcpowers /* Use Chinese Remainer theorem to compute a**-1 mod m. */
23905697Smcpowers /* let m1 = oddFactor, v1 = oddPart,
23915697Smcpowers * let m2 = evenFactor, v2 = evenPart.
23925697Smcpowers */
23935697Smcpowers
23945697Smcpowers /* Compute C2 = m1**-1 mod m2. */
23955697Smcpowers MP_CHECKOK( s_mp_invmod_2d(&oddFactor, k, &C2) );
23965697Smcpowers
23975697Smcpowers /* compute u = (v2 - v1)*C2 mod m2 */
23985697Smcpowers MP_CHECKOK( mp_sub(&evenPart, &oddPart, &tmp1) );
23995697Smcpowers MP_CHECKOK( mp_mul(&tmp1, &C2, &tmp2) );
24005697Smcpowers s_mp_mod_2d(&tmp2, k);
24015697Smcpowers while (MP_SIGN(&tmp2) != MP_ZPOS) {
24025697Smcpowers MP_CHECKOK( mp_add(&tmp2, &evenFactor, &tmp2) );
24035697Smcpowers }
24045697Smcpowers
24055697Smcpowers /* compute answer = v1 + u*m1 */
24065697Smcpowers MP_CHECKOK( mp_mul(&tmp2, &oddFactor, c) );
24075697Smcpowers MP_CHECKOK( mp_add(&oddPart, c, c) );
24085697Smcpowers /* not sure this is necessary, but it's low cost if not. */
24095697Smcpowers MP_CHECKOK( mp_mod(c, m, c) );
24105697Smcpowers
24115697Smcpowers CLEANUP:
24125697Smcpowers mp_clear(&oddFactor);
24135697Smcpowers mp_clear(&evenFactor);
24145697Smcpowers mp_clear(&oddPart);
24155697Smcpowers mp_clear(&evenPart);
24165697Smcpowers mp_clear(&C2);
24175697Smcpowers mp_clear(&tmp1);
24185697Smcpowers mp_clear(&tmp2);
24195697Smcpowers return res;
24205697Smcpowers }
24215697Smcpowers
24225697Smcpowers
24235697Smcpowers /* {{{ mp_invmod(a, m, c) */
24245697Smcpowers
24255697Smcpowers /*
24265697Smcpowers mp_invmod(a, m, c)
24275697Smcpowers
24285697Smcpowers Compute c = a^-1 (mod m), if there is an inverse for a (mod m).
24295697Smcpowers This is equivalent to the question of whether (a, m) = 1. If not,
24305697Smcpowers MP_UNDEF is returned, and there is no inverse.
24315697Smcpowers */
24325697Smcpowers
mp_invmod(const mp_int * a,const mp_int * m,mp_int * c)24335697Smcpowers mp_err mp_invmod(const mp_int *a, const mp_int *m, mp_int *c)
24345697Smcpowers {
24355697Smcpowers
24365697Smcpowers ARGCHK(a && m && c, MP_BADARG);
24375697Smcpowers
24385697Smcpowers if(mp_cmp_z(a) == 0 || mp_cmp_z(m) == 0)
24395697Smcpowers return MP_RANGE;
24405697Smcpowers
24415697Smcpowers if (mp_isodd(m)) {
24425697Smcpowers return s_mp_invmod_odd_m(a, m, c);
24435697Smcpowers }
24445697Smcpowers if (mp_iseven(a))
24455697Smcpowers return MP_UNDEF; /* not invertable */
24465697Smcpowers
24475697Smcpowers return s_mp_invmod_even_m(a, m, c);
24485697Smcpowers
24495697Smcpowers } /* end mp_invmod() */
24505697Smcpowers
24515697Smcpowers /* }}} */
24525697Smcpowers #endif /* if MP_NUMTH */
24535697Smcpowers
24545697Smcpowers /* }}} */
24555697Smcpowers
24565697Smcpowers /*------------------------------------------------------------------------*/
24575697Smcpowers /* {{{ mp_print(mp, ofp) */
24585697Smcpowers
24595697Smcpowers #if MP_IOFUNC
24605697Smcpowers /*
24615697Smcpowers mp_print(mp, ofp)
24625697Smcpowers
24635697Smcpowers Print a textual representation of the given mp_int on the output
24645697Smcpowers stream 'ofp'. Output is generated using the internal radix.
24655697Smcpowers */
24665697Smcpowers
mp_print(mp_int * mp,FILE * ofp)24675697Smcpowers void mp_print(mp_int *mp, FILE *ofp)
24685697Smcpowers {
24695697Smcpowers int ix;
24705697Smcpowers
24715697Smcpowers if(mp == NULL || ofp == NULL)
24725697Smcpowers return;
24735697Smcpowers
24745697Smcpowers fputc((SIGN(mp) == NEG) ? '-' : '+', ofp);
24755697Smcpowers
24765697Smcpowers for(ix = USED(mp) - 1; ix >= 0; ix--) {
24775697Smcpowers fprintf(ofp, DIGIT_FMT, DIGIT(mp, ix));
24785697Smcpowers }
24795697Smcpowers
24805697Smcpowers } /* end mp_print() */
24815697Smcpowers
24825697Smcpowers #endif /* if MP_IOFUNC */
24835697Smcpowers
24845697Smcpowers /* }}} */
24855697Smcpowers
24865697Smcpowers /*------------------------------------------------------------------------*/
24875697Smcpowers /* {{{ More I/O Functions */
24885697Smcpowers
24895697Smcpowers /* {{{ mp_read_raw(mp, str, len) */
24905697Smcpowers
24915697Smcpowers /*
24925697Smcpowers mp_read_raw(mp, str, len)
24935697Smcpowers
24945697Smcpowers Read in a raw value (base 256) into the given mp_int
24955697Smcpowers */
24965697Smcpowers
mp_read_raw(mp_int * mp,char * str,int len)24975697Smcpowers mp_err mp_read_raw(mp_int *mp, char *str, int len)
24985697Smcpowers {
24995697Smcpowers int ix;
25005697Smcpowers mp_err res;
25015697Smcpowers unsigned char *ustr = (unsigned char *)str;
25025697Smcpowers
25035697Smcpowers ARGCHK(mp != NULL && str != NULL && len > 0, MP_BADARG);
25045697Smcpowers
25055697Smcpowers mp_zero(mp);
25065697Smcpowers
25075697Smcpowers /* Get sign from first byte */
25085697Smcpowers if(ustr[0])
25095697Smcpowers SIGN(mp) = NEG;
25105697Smcpowers else
25115697Smcpowers SIGN(mp) = ZPOS;
25125697Smcpowers
25135697Smcpowers /* Read the rest of the digits */
25145697Smcpowers for(ix = 1; ix < len; ix++) {
25155697Smcpowers if((res = mp_mul_d(mp, 256, mp)) != MP_OKAY)
25165697Smcpowers return res;
25175697Smcpowers if((res = mp_add_d(mp, ustr[ix], mp)) != MP_OKAY)
25185697Smcpowers return res;
25195697Smcpowers }
25205697Smcpowers
25215697Smcpowers return MP_OKAY;
25225697Smcpowers
25235697Smcpowers } /* end mp_read_raw() */
25245697Smcpowers
25255697Smcpowers /* }}} */
25265697Smcpowers
25275697Smcpowers /* {{{ mp_raw_size(mp) */
25285697Smcpowers
mp_raw_size(mp_int * mp)25295697Smcpowers int mp_raw_size(mp_int *mp)
25305697Smcpowers {
25315697Smcpowers ARGCHK(mp != NULL, 0);
25325697Smcpowers
25335697Smcpowers return (USED(mp) * sizeof(mp_digit)) + 1;
25345697Smcpowers
25355697Smcpowers } /* end mp_raw_size() */
25365697Smcpowers
25375697Smcpowers /* }}} */
25385697Smcpowers
25395697Smcpowers /* {{{ mp_toraw(mp, str) */
25405697Smcpowers
mp_toraw(mp_int * mp,char * str)25415697Smcpowers mp_err mp_toraw(mp_int *mp, char *str)
25425697Smcpowers {
25435697Smcpowers int ix, jx, pos = 1;
25445697Smcpowers
25455697Smcpowers ARGCHK(mp != NULL && str != NULL, MP_BADARG);
25465697Smcpowers
25475697Smcpowers str[0] = (char)SIGN(mp);
25485697Smcpowers
25495697Smcpowers /* Iterate over each digit... */
25505697Smcpowers for(ix = USED(mp) - 1; ix >= 0; ix--) {
25515697Smcpowers mp_digit d = DIGIT(mp, ix);
25525697Smcpowers
25535697Smcpowers /* Unpack digit bytes, high order first */
25545697Smcpowers for(jx = sizeof(mp_digit) - 1; jx >= 0; jx--) {
25555697Smcpowers str[pos++] = (char)(d >> (jx * CHAR_BIT));
25565697Smcpowers }
25575697Smcpowers }
25585697Smcpowers
25595697Smcpowers return MP_OKAY;
25605697Smcpowers
25615697Smcpowers } /* end mp_toraw() */
25625697Smcpowers
25635697Smcpowers /* }}} */
25645697Smcpowers
25655697Smcpowers /* {{{ mp_read_radix(mp, str, radix) */
25665697Smcpowers
25675697Smcpowers /*
25685697Smcpowers mp_read_radix(mp, str, radix)
25695697Smcpowers
25705697Smcpowers Read an integer from the given string, and set mp to the resulting
25715697Smcpowers value. The input is presumed to be in base 10. Leading non-digit
25725697Smcpowers characters are ignored, and the function reads until a non-digit
25735697Smcpowers character or the end of the string.
25745697Smcpowers */
25755697Smcpowers
mp_read_radix(mp_int * mp,const char * str,int radix)25765697Smcpowers mp_err mp_read_radix(mp_int *mp, const char *str, int radix)
25775697Smcpowers {
25785697Smcpowers int ix = 0, val = 0;
25795697Smcpowers mp_err res;
25805697Smcpowers mp_sign sig = ZPOS;
25815697Smcpowers
25825697Smcpowers ARGCHK(mp != NULL && str != NULL && radix >= 2 && radix <= MAX_RADIX,
25835697Smcpowers MP_BADARG);
25845697Smcpowers
25855697Smcpowers mp_zero(mp);
25865697Smcpowers
25875697Smcpowers /* Skip leading non-digit characters until a digit or '-' or '+' */
25885697Smcpowers while(str[ix] &&
25895697Smcpowers (s_mp_tovalue(str[ix], radix) < 0) &&
25905697Smcpowers str[ix] != '-' &&
25915697Smcpowers str[ix] != '+') {
25925697Smcpowers ++ix;
25935697Smcpowers }
25945697Smcpowers
25955697Smcpowers if(str[ix] == '-') {
25965697Smcpowers sig = NEG;
25975697Smcpowers ++ix;
25985697Smcpowers } else if(str[ix] == '+') {
25995697Smcpowers sig = ZPOS; /* this is the default anyway... */
26005697Smcpowers ++ix;
26015697Smcpowers }
26025697Smcpowers
26035697Smcpowers while((val = s_mp_tovalue(str[ix], radix)) >= 0) {
26045697Smcpowers if((res = s_mp_mul_d(mp, radix)) != MP_OKAY)
26055697Smcpowers return res;
26065697Smcpowers if((res = s_mp_add_d(mp, val)) != MP_OKAY)
26075697Smcpowers return res;
26085697Smcpowers ++ix;
26095697Smcpowers }
26105697Smcpowers
26115697Smcpowers if(s_mp_cmp_d(mp, 0) == MP_EQ)
26125697Smcpowers SIGN(mp) = ZPOS;
26135697Smcpowers else
26145697Smcpowers SIGN(mp) = sig;
26155697Smcpowers
26165697Smcpowers return MP_OKAY;
26175697Smcpowers
26185697Smcpowers } /* end mp_read_radix() */
26195697Smcpowers
mp_read_variable_radix(mp_int * a,const char * str,int default_radix)26205697Smcpowers mp_err mp_read_variable_radix(mp_int *a, const char * str, int default_radix)
26215697Smcpowers {
26225697Smcpowers int radix = default_radix;
26235697Smcpowers int cx;
26245697Smcpowers mp_sign sig = ZPOS;
26255697Smcpowers mp_err res;
26265697Smcpowers
26275697Smcpowers /* Skip leading non-digit characters until a digit or '-' or '+' */
26285697Smcpowers while ((cx = *str) != 0 &&
26295697Smcpowers (s_mp_tovalue(cx, radix) < 0) &&
26305697Smcpowers cx != '-' &&
26315697Smcpowers cx != '+') {
26325697Smcpowers ++str;
26335697Smcpowers }
26345697Smcpowers
26355697Smcpowers if (cx == '-') {
26365697Smcpowers sig = NEG;
26375697Smcpowers ++str;
26385697Smcpowers } else if (cx == '+') {
26395697Smcpowers sig = ZPOS; /* this is the default anyway... */
26405697Smcpowers ++str;
26415697Smcpowers }
26425697Smcpowers
26435697Smcpowers if (str[0] == '0') {
26445697Smcpowers if ((str[1] | 0x20) == 'x') {
26455697Smcpowers radix = 16;
26465697Smcpowers str += 2;
26475697Smcpowers } else {
26485697Smcpowers radix = 8;
26495697Smcpowers str++;
26505697Smcpowers }
26515697Smcpowers }
26525697Smcpowers res = mp_read_radix(a, str, radix);
26535697Smcpowers if (res == MP_OKAY) {
26545697Smcpowers MP_SIGN(a) = (s_mp_cmp_d(a, 0) == MP_EQ) ? ZPOS : sig;
26555697Smcpowers }
26565697Smcpowers return res;
26575697Smcpowers }
26585697Smcpowers
26595697Smcpowers /* }}} */
26605697Smcpowers
26615697Smcpowers /* {{{ mp_radix_size(mp, radix) */
26625697Smcpowers
mp_radix_size(mp_int * mp,int radix)26635697Smcpowers int mp_radix_size(mp_int *mp, int radix)
26645697Smcpowers {
26655697Smcpowers int bits;
26665697Smcpowers
26675697Smcpowers if(!mp || radix < 2 || radix > MAX_RADIX)
26685697Smcpowers return 0;
26695697Smcpowers
26705697Smcpowers bits = USED(mp) * DIGIT_BIT - 1;
26715697Smcpowers
26725697Smcpowers return s_mp_outlen(bits, radix);
26735697Smcpowers
26745697Smcpowers } /* end mp_radix_size() */
26755697Smcpowers
26765697Smcpowers /* }}} */
26775697Smcpowers
26785697Smcpowers /* {{{ mp_toradix(mp, str, radix) */
26795697Smcpowers
mp_toradix(mp_int * mp,char * str,int radix)26805697Smcpowers mp_err mp_toradix(mp_int *mp, char *str, int radix)
26815697Smcpowers {
26825697Smcpowers int ix, pos = 0;
26835697Smcpowers
26845697Smcpowers ARGCHK(mp != NULL && str != NULL, MP_BADARG);
26855697Smcpowers ARGCHK(radix > 1 && radix <= MAX_RADIX, MP_RANGE);
26865697Smcpowers
26875697Smcpowers if(mp_cmp_z(mp) == MP_EQ) {
26885697Smcpowers str[0] = '0';
26895697Smcpowers str[1] = '\0';
26905697Smcpowers } else {
26915697Smcpowers mp_err res;
26925697Smcpowers mp_int tmp;
26935697Smcpowers mp_sign sgn;
26945697Smcpowers mp_digit rem, rdx = (mp_digit)radix;
26955697Smcpowers char ch;
26965697Smcpowers
26975697Smcpowers if((res = mp_init_copy(&tmp, mp)) != MP_OKAY)
26985697Smcpowers return res;
26995697Smcpowers
27005697Smcpowers /* Save sign for later, and take absolute value */
27015697Smcpowers sgn = SIGN(&tmp); SIGN(&tmp) = ZPOS;
27025697Smcpowers
27035697Smcpowers /* Generate output digits in reverse order */
27045697Smcpowers while(mp_cmp_z(&tmp) != 0) {
27055697Smcpowers if((res = mp_div_d(&tmp, rdx, &tmp, &rem)) != MP_OKAY) {
27065697Smcpowers mp_clear(&tmp);
27075697Smcpowers return res;
27085697Smcpowers }
27095697Smcpowers
27105697Smcpowers /* Generate digits, use capital letters */
27115697Smcpowers ch = s_mp_todigit(rem, radix, 0);
27125697Smcpowers
27135697Smcpowers str[pos++] = ch;
27145697Smcpowers }
27155697Smcpowers
27165697Smcpowers /* Add - sign if original value was negative */
27175697Smcpowers if(sgn == NEG)
27185697Smcpowers str[pos++] = '-';
27195697Smcpowers
27205697Smcpowers /* Add trailing NUL to end the string */
27215697Smcpowers str[pos--] = '\0';
27225697Smcpowers
27235697Smcpowers /* Reverse the digits and sign indicator */
27245697Smcpowers ix = 0;
27255697Smcpowers while(ix < pos) {
27265697Smcpowers char tmp = str[ix];
27275697Smcpowers
27285697Smcpowers str[ix] = str[pos];
27295697Smcpowers str[pos] = tmp;
27305697Smcpowers ++ix;
27315697Smcpowers --pos;
27325697Smcpowers }
27335697Smcpowers
27345697Smcpowers mp_clear(&tmp);
27355697Smcpowers }
27365697Smcpowers
27375697Smcpowers return MP_OKAY;
27385697Smcpowers
27395697Smcpowers } /* end mp_toradix() */
27405697Smcpowers
27415697Smcpowers /* }}} */
27425697Smcpowers
27435697Smcpowers /* {{{ mp_tovalue(ch, r) */
27445697Smcpowers
mp_tovalue(char ch,int r)27455697Smcpowers int mp_tovalue(char ch, int r)
27465697Smcpowers {
27475697Smcpowers return s_mp_tovalue(ch, r);
27485697Smcpowers
27495697Smcpowers } /* end mp_tovalue() */
27505697Smcpowers
27515697Smcpowers /* }}} */
27525697Smcpowers
27535697Smcpowers /* }}} */
27545697Smcpowers
27555697Smcpowers /* {{{ mp_strerror(ec) */
27565697Smcpowers
27575697Smcpowers /*
27585697Smcpowers mp_strerror(ec)
27595697Smcpowers
27605697Smcpowers Return a string describing the meaning of error code 'ec'. The
27615697Smcpowers string returned is allocated in static memory, so the caller should
27625697Smcpowers not attempt to modify or free the memory associated with this
27635697Smcpowers string.
27645697Smcpowers */
mp_strerror(mp_err ec)27655697Smcpowers const char *mp_strerror(mp_err ec)
27665697Smcpowers {
27675697Smcpowers int aec = (ec < 0) ? -ec : ec;
27685697Smcpowers
27695697Smcpowers /* Code values are negative, so the senses of these comparisons
27705697Smcpowers are accurate */
27715697Smcpowers if(ec < MP_LAST_CODE || ec > MP_OKAY) {
27725697Smcpowers return mp_err_string[0]; /* unknown error code */
27735697Smcpowers } else {
27745697Smcpowers return mp_err_string[aec + 1];
27755697Smcpowers }
27765697Smcpowers
27775697Smcpowers } /* end mp_strerror() */
27785697Smcpowers
27795697Smcpowers /* }}} */
27805697Smcpowers
27815697Smcpowers /*========================================================================*/
27825697Smcpowers /*------------------------------------------------------------------------*/
27835697Smcpowers /* Static function definitions (internal use only) */
27845697Smcpowers
27855697Smcpowers /* {{{ Memory management */
27865697Smcpowers
27875697Smcpowers /* {{{ s_mp_grow(mp, min) */
27885697Smcpowers
27895697Smcpowers /* Make sure there are at least 'min' digits allocated to mp */
s_mp_grow(mp_int * mp,mp_size min)27905697Smcpowers mp_err s_mp_grow(mp_int *mp, mp_size min)
27915697Smcpowers {
27925697Smcpowers if(min > ALLOC(mp)) {
27935697Smcpowers mp_digit *tmp;
27945697Smcpowers
27955697Smcpowers /* Set min to next nearest default precision block size */
27965697Smcpowers min = MP_ROUNDUP(min, s_mp_defprec);
27975697Smcpowers
27985697Smcpowers if((tmp = s_mp_alloc(min, sizeof(mp_digit), FLAG(mp))) == NULL)
27995697Smcpowers return MP_MEM;
28005697Smcpowers
28015697Smcpowers s_mp_copy(DIGITS(mp), tmp, USED(mp));
28025697Smcpowers
28035697Smcpowers #if MP_CRYPTO
28045697Smcpowers s_mp_setz(DIGITS(mp), ALLOC(mp));
28055697Smcpowers #endif
28065697Smcpowers s_mp_free(DIGITS(mp), ALLOC(mp));
28075697Smcpowers DIGITS(mp) = tmp;
28085697Smcpowers ALLOC(mp) = min;
28095697Smcpowers }
28105697Smcpowers
28115697Smcpowers return MP_OKAY;
28125697Smcpowers
28135697Smcpowers } /* end s_mp_grow() */
28145697Smcpowers
28155697Smcpowers /* }}} */
28165697Smcpowers
28175697Smcpowers /* {{{ s_mp_pad(mp, min) */
28185697Smcpowers
28195697Smcpowers /* Make sure the used size of mp is at least 'min', growing if needed */
s_mp_pad(mp_int * mp,mp_size min)28205697Smcpowers mp_err s_mp_pad(mp_int *mp, mp_size min)
28215697Smcpowers {
28225697Smcpowers if(min > USED(mp)) {
28235697Smcpowers mp_err res;
28245697Smcpowers
28255697Smcpowers /* Make sure there is room to increase precision */
28265697Smcpowers if (min > ALLOC(mp)) {
28275697Smcpowers if ((res = s_mp_grow(mp, min)) != MP_OKAY)
28285697Smcpowers return res;
28295697Smcpowers } else {
28305697Smcpowers s_mp_setz(DIGITS(mp) + USED(mp), min - USED(mp));
28315697Smcpowers }
28325697Smcpowers
28335697Smcpowers /* Increase precision; should already be 0-filled */
28345697Smcpowers USED(mp) = min;
28355697Smcpowers }
28365697Smcpowers
28375697Smcpowers return MP_OKAY;
28385697Smcpowers
28395697Smcpowers } /* end s_mp_pad() */
28405697Smcpowers
28415697Smcpowers /* }}} */
28425697Smcpowers
28435697Smcpowers /* {{{ s_mp_setz(dp, count) */
28445697Smcpowers
28455697Smcpowers #if MP_MACRO == 0
28465697Smcpowers /* Set 'count' digits pointed to by dp to be zeroes */
s_mp_setz(mp_digit * dp,mp_size count)28475697Smcpowers void s_mp_setz(mp_digit *dp, mp_size count)
28485697Smcpowers {
28495697Smcpowers #if MP_MEMSET == 0
28505697Smcpowers int ix;
28515697Smcpowers
28525697Smcpowers for(ix = 0; ix < count; ix++)
28535697Smcpowers dp[ix] = 0;
28545697Smcpowers #else
28555697Smcpowers memset(dp, 0, count * sizeof(mp_digit));
28565697Smcpowers #endif
28575697Smcpowers
28585697Smcpowers } /* end s_mp_setz() */
28595697Smcpowers #endif
28605697Smcpowers
28615697Smcpowers /* }}} */
28625697Smcpowers
28635697Smcpowers /* {{{ s_mp_copy(sp, dp, count) */
28645697Smcpowers
28655697Smcpowers #if MP_MACRO == 0
28665697Smcpowers /* Copy 'count' digits from sp to dp */
s_mp_copy(const mp_digit * sp,mp_digit * dp,mp_size count)28675697Smcpowers void s_mp_copy(const mp_digit *sp, mp_digit *dp, mp_size count)
28685697Smcpowers {
28695697Smcpowers #if MP_MEMCPY == 0
28705697Smcpowers int ix;
28715697Smcpowers
28725697Smcpowers for(ix = 0; ix < count; ix++)
28735697Smcpowers dp[ix] = sp[ix];
28745697Smcpowers #else
28755697Smcpowers memcpy(dp, sp, count * sizeof(mp_digit));
28765697Smcpowers #endif
28775697Smcpowers
28785697Smcpowers } /* end s_mp_copy() */
28795697Smcpowers #endif
28805697Smcpowers
28815697Smcpowers /* }}} */
28825697Smcpowers
28835697Smcpowers /* {{{ s_mp_alloc(nb, ni, kmflag) */
28845697Smcpowers
28855697Smcpowers #if MP_MACRO == 0
28865697Smcpowers /* Allocate ni records of nb bytes each, and return a pointer to that */
s_mp_alloc(size_t nb,size_t ni,int kmflag)28875697Smcpowers void *s_mp_alloc(size_t nb, size_t ni, int kmflag)
28885697Smcpowers {
28895697Smcpowers ++mp_allocs;
28905697Smcpowers #ifdef _KERNEL
2891*13066SDina.Nimeh@Sun.COM return kmem_zalloc(nb * ni, kmflag);
28925697Smcpowers #else
28935697Smcpowers return calloc(nb, ni);
28945697Smcpowers #endif
28955697Smcpowers
28965697Smcpowers } /* end s_mp_alloc() */
28975697Smcpowers #endif
28985697Smcpowers
28995697Smcpowers /* }}} */
29005697Smcpowers
29015697Smcpowers /* {{{ s_mp_free(ptr) */
29025697Smcpowers
29035697Smcpowers #if MP_MACRO == 0
29045697Smcpowers /* Free the memory pointed to by ptr */
s_mp_free(void * ptr,mp_size alloc)29055697Smcpowers void s_mp_free(void *ptr, mp_size alloc)
29065697Smcpowers {
29075697Smcpowers if(ptr) {
29085697Smcpowers ++mp_frees;
29095697Smcpowers #ifdef _KERNEL
29105697Smcpowers kmem_free(ptr, alloc * sizeof (mp_digit));
29115697Smcpowers #else
29125697Smcpowers free(ptr);
29135697Smcpowers #endif
29145697Smcpowers }
29155697Smcpowers } /* end s_mp_free() */
29165697Smcpowers #endif
29175697Smcpowers
29185697Smcpowers /* }}} */
29195697Smcpowers
29205697Smcpowers /* {{{ s_mp_clamp(mp) */
29215697Smcpowers
29225697Smcpowers #if MP_MACRO == 0
29235697Smcpowers /* Remove leading zeroes from the given value */
s_mp_clamp(mp_int * mp)29245697Smcpowers void s_mp_clamp(mp_int *mp)
29255697Smcpowers {
29265697Smcpowers mp_size used = MP_USED(mp);
29275697Smcpowers while (used > 1 && DIGIT(mp, used - 1) == 0)
29285697Smcpowers --used;
29295697Smcpowers MP_USED(mp) = used;
29305697Smcpowers } /* end s_mp_clamp() */
29315697Smcpowers #endif
29325697Smcpowers
29335697Smcpowers /* }}} */
29345697Smcpowers
29355697Smcpowers /* {{{ s_mp_exch(a, b) */
29365697Smcpowers
29375697Smcpowers /* Exchange the data for a and b; (b, a) = (a, b) */
s_mp_exch(mp_int * a,mp_int * b)29385697Smcpowers void s_mp_exch(mp_int *a, mp_int *b)
29395697Smcpowers {
29405697Smcpowers mp_int tmp;
29415697Smcpowers
29425697Smcpowers tmp = *a;
29435697Smcpowers *a = *b;
29445697Smcpowers *b = tmp;
29455697Smcpowers
29465697Smcpowers } /* end s_mp_exch() */
29475697Smcpowers
29485697Smcpowers /* }}} */
29495697Smcpowers
29505697Smcpowers /* }}} */
29515697Smcpowers
29525697Smcpowers /* {{{ Arithmetic helpers */
29535697Smcpowers
29545697Smcpowers /* {{{ s_mp_lshd(mp, p) */
29555697Smcpowers
29565697Smcpowers /*
29575697Smcpowers Shift mp leftward by p digits, growing if needed, and zero-filling
29585697Smcpowers the in-shifted digits at the right end. This is a convenient
29595697Smcpowers alternative to multiplication by powers of the radix
29605697Smcpowers The value of USED(mp) must already have been set to the value for
29615697Smcpowers the shifted result.
29625697Smcpowers */
29635697Smcpowers
s_mp_lshd(mp_int * mp,mp_size p)29645697Smcpowers mp_err s_mp_lshd(mp_int *mp, mp_size p)
29655697Smcpowers {
29665697Smcpowers mp_err res;
29675697Smcpowers mp_size pos;
29685697Smcpowers int ix;
29695697Smcpowers
29705697Smcpowers if(p == 0)
29715697Smcpowers return MP_OKAY;
29725697Smcpowers
29735697Smcpowers if (MP_USED(mp) == 1 && MP_DIGIT(mp, 0) == 0)
29745697Smcpowers return MP_OKAY;
29755697Smcpowers
29765697Smcpowers if((res = s_mp_pad(mp, USED(mp) + p)) != MP_OKAY)
29775697Smcpowers return res;
29785697Smcpowers
29795697Smcpowers pos = USED(mp) - 1;
29805697Smcpowers
29815697Smcpowers /* Shift all the significant figures over as needed */
29825697Smcpowers for(ix = pos - p; ix >= 0; ix--)
29835697Smcpowers DIGIT(mp, ix + p) = DIGIT(mp, ix);
29845697Smcpowers
29855697Smcpowers /* Fill the bottom digits with zeroes */
29865697Smcpowers for(ix = 0; ix < p; ix++)
29875697Smcpowers DIGIT(mp, ix) = 0;
29885697Smcpowers
29895697Smcpowers return MP_OKAY;
29905697Smcpowers
29915697Smcpowers } /* end s_mp_lshd() */
29925697Smcpowers
29935697Smcpowers /* }}} */
29945697Smcpowers
29955697Smcpowers /* {{{ s_mp_mul_2d(mp, d) */
29965697Smcpowers
29975697Smcpowers /*
29985697Smcpowers Multiply the integer by 2^d, where d is a number of bits. This
29995697Smcpowers amounts to a bitwise shift of the value.
30005697Smcpowers */
s_mp_mul_2d(mp_int * mp,mp_digit d)30015697Smcpowers mp_err s_mp_mul_2d(mp_int *mp, mp_digit d)
30025697Smcpowers {
30035697Smcpowers mp_err res;
30045697Smcpowers mp_digit dshift, bshift;
30055697Smcpowers mp_digit mask;
30065697Smcpowers
30075697Smcpowers ARGCHK(mp != NULL, MP_BADARG);
30085697Smcpowers
30095697Smcpowers dshift = d / MP_DIGIT_BIT;
30105697Smcpowers bshift = d % MP_DIGIT_BIT;
30115697Smcpowers /* bits to be shifted out of the top word */
30125697Smcpowers mask = ((mp_digit)~0 << (MP_DIGIT_BIT - bshift));
30135697Smcpowers mask &= MP_DIGIT(mp, MP_USED(mp) - 1);
30145697Smcpowers
30155697Smcpowers if (MP_OKAY != (res = s_mp_pad(mp, MP_USED(mp) + dshift + (mask != 0) )))
30165697Smcpowers return res;
30175697Smcpowers
30185697Smcpowers if (dshift && MP_OKAY != (res = s_mp_lshd(mp, dshift)))
30195697Smcpowers return res;
30205697Smcpowers
30215697Smcpowers if (bshift) {
30225697Smcpowers mp_digit *pa = MP_DIGITS(mp);
30235697Smcpowers mp_digit *alim = pa + MP_USED(mp);
30245697Smcpowers mp_digit prev = 0;
30255697Smcpowers
30265697Smcpowers for (pa += dshift; pa < alim; ) {
30275697Smcpowers mp_digit x = *pa;
30285697Smcpowers *pa++ = (x << bshift) | prev;
30295697Smcpowers prev = x >> (DIGIT_BIT - bshift);
30305697Smcpowers }
30315697Smcpowers }
30325697Smcpowers
30335697Smcpowers s_mp_clamp(mp);
30345697Smcpowers return MP_OKAY;
30355697Smcpowers } /* end s_mp_mul_2d() */
30365697Smcpowers
30375697Smcpowers /* {{{ s_mp_rshd(mp, p) */
30385697Smcpowers
30395697Smcpowers /*
30405697Smcpowers Shift mp rightward by p digits. Maintains the invariant that
30415697Smcpowers digits above the precision are all zero. Digits shifted off the
30425697Smcpowers end are lost. Cannot fail.
30435697Smcpowers */
30445697Smcpowers
s_mp_rshd(mp_int * mp,mp_size p)30455697Smcpowers void s_mp_rshd(mp_int *mp, mp_size p)
30465697Smcpowers {
30475697Smcpowers mp_size ix;
30485697Smcpowers mp_digit *src, *dst;
30495697Smcpowers
30505697Smcpowers if(p == 0)
30515697Smcpowers return;
30525697Smcpowers
30535697Smcpowers /* Shortcut when all digits are to be shifted off */
30545697Smcpowers if(p >= USED(mp)) {
30555697Smcpowers s_mp_setz(DIGITS(mp), ALLOC(mp));
30565697Smcpowers USED(mp) = 1;
30575697Smcpowers SIGN(mp) = ZPOS;
30585697Smcpowers return;
30595697Smcpowers }
30605697Smcpowers
30615697Smcpowers /* Shift all the significant figures over as needed */
30625697Smcpowers dst = MP_DIGITS(mp);
30635697Smcpowers src = dst + p;
30645697Smcpowers for (ix = USED(mp) - p; ix > 0; ix--)
30655697Smcpowers *dst++ = *src++;
30665697Smcpowers
30675697Smcpowers MP_USED(mp) -= p;
30685697Smcpowers /* Fill the top digits with zeroes */
30695697Smcpowers while (p-- > 0)
30705697Smcpowers *dst++ = 0;
30715697Smcpowers
30725697Smcpowers #if 0
30735697Smcpowers /* Strip off any leading zeroes */
30745697Smcpowers s_mp_clamp(mp);
30755697Smcpowers #endif
30765697Smcpowers
30775697Smcpowers } /* end s_mp_rshd() */
30785697Smcpowers
30795697Smcpowers /* }}} */
30805697Smcpowers
30815697Smcpowers /* {{{ s_mp_div_2(mp) */
30825697Smcpowers
30835697Smcpowers /* Divide by two -- take advantage of radix properties to do it fast */
s_mp_div_2(mp_int * mp)30845697Smcpowers void s_mp_div_2(mp_int *mp)
30855697Smcpowers {
30865697Smcpowers s_mp_div_2d(mp, 1);
30875697Smcpowers
30885697Smcpowers } /* end s_mp_div_2() */
30895697Smcpowers
30905697Smcpowers /* }}} */
30915697Smcpowers
30925697Smcpowers /* {{{ s_mp_mul_2(mp) */
30935697Smcpowers
s_mp_mul_2(mp_int * mp)30945697Smcpowers mp_err s_mp_mul_2(mp_int *mp)
30955697Smcpowers {
30965697Smcpowers mp_digit *pd;
30975697Smcpowers int ix, used;
30985697Smcpowers mp_digit kin = 0;
30995697Smcpowers
31005697Smcpowers /* Shift digits leftward by 1 bit */
31015697Smcpowers used = MP_USED(mp);
31025697Smcpowers pd = MP_DIGITS(mp);
31035697Smcpowers for (ix = 0; ix < used; ix++) {
31045697Smcpowers mp_digit d = *pd;
31055697Smcpowers *pd++ = (d << 1) | kin;
31065697Smcpowers kin = (d >> (DIGIT_BIT - 1));
31075697Smcpowers }
31085697Smcpowers
31095697Smcpowers /* Deal with rollover from last digit */
31105697Smcpowers if (kin) {
31115697Smcpowers if (ix >= ALLOC(mp)) {
31125697Smcpowers mp_err res;
31135697Smcpowers if((res = s_mp_grow(mp, ALLOC(mp) + 1)) != MP_OKAY)
31145697Smcpowers return res;
31155697Smcpowers }
31165697Smcpowers
31175697Smcpowers DIGIT(mp, ix) = kin;
31185697Smcpowers USED(mp) += 1;
31195697Smcpowers }
31205697Smcpowers
31215697Smcpowers return MP_OKAY;
31225697Smcpowers
31235697Smcpowers } /* end s_mp_mul_2() */
31245697Smcpowers
31255697Smcpowers /* }}} */
31265697Smcpowers
31275697Smcpowers /* {{{ s_mp_mod_2d(mp, d) */
31285697Smcpowers
31295697Smcpowers /*
31305697Smcpowers Remainder the integer by 2^d, where d is a number of bits. This
31315697Smcpowers amounts to a bitwise AND of the value, and does not require the full
31325697Smcpowers division code
31335697Smcpowers */
s_mp_mod_2d(mp_int * mp,mp_digit d)31345697Smcpowers void s_mp_mod_2d(mp_int *mp, mp_digit d)
31355697Smcpowers {
31365697Smcpowers mp_size ndig = (d / DIGIT_BIT), nbit = (d % DIGIT_BIT);
31375697Smcpowers mp_size ix;
31385697Smcpowers mp_digit dmask;
31395697Smcpowers
31405697Smcpowers if(ndig >= USED(mp))
31415697Smcpowers return;
31425697Smcpowers
31435697Smcpowers /* Flush all the bits above 2^d in its digit */
31445697Smcpowers dmask = ((mp_digit)1 << nbit) - 1;
31455697Smcpowers DIGIT(mp, ndig) &= dmask;
31465697Smcpowers
31475697Smcpowers /* Flush all digits above the one with 2^d in it */
31485697Smcpowers for(ix = ndig + 1; ix < USED(mp); ix++)
31495697Smcpowers DIGIT(mp, ix) = 0;
31505697Smcpowers
31515697Smcpowers s_mp_clamp(mp);
31525697Smcpowers
31535697Smcpowers } /* end s_mp_mod_2d() */
31545697Smcpowers
31555697Smcpowers /* }}} */
31565697Smcpowers
31575697Smcpowers /* {{{ s_mp_div_2d(mp, d) */
31585697Smcpowers
31595697Smcpowers /*
31605697Smcpowers Divide the integer by 2^d, where d is a number of bits. This
31615697Smcpowers amounts to a bitwise shift of the value, and does not require the
31625697Smcpowers full division code (used in Barrett reduction, see below)
31635697Smcpowers */
s_mp_div_2d(mp_int * mp,mp_digit d)31645697Smcpowers void s_mp_div_2d(mp_int *mp, mp_digit d)
31655697Smcpowers {
31665697Smcpowers int ix;
31675697Smcpowers mp_digit save, next, mask;
31685697Smcpowers
31695697Smcpowers s_mp_rshd(mp, d / DIGIT_BIT);
31705697Smcpowers d %= DIGIT_BIT;
31715697Smcpowers if (d) {
31725697Smcpowers mask = ((mp_digit)1 << d) - 1;
31735697Smcpowers save = 0;
31745697Smcpowers for(ix = USED(mp) - 1; ix >= 0; ix--) {
31755697Smcpowers next = DIGIT(mp, ix) & mask;
31765697Smcpowers DIGIT(mp, ix) = (DIGIT(mp, ix) >> d) | (save << (DIGIT_BIT - d));
31775697Smcpowers save = next;
31785697Smcpowers }
31795697Smcpowers }
31805697Smcpowers s_mp_clamp(mp);
31815697Smcpowers
31825697Smcpowers } /* end s_mp_div_2d() */
31835697Smcpowers
31845697Smcpowers /* }}} */
31855697Smcpowers
31865697Smcpowers /* {{{ s_mp_norm(a, b, *d) */
31875697Smcpowers
31885697Smcpowers /*
31895697Smcpowers s_mp_norm(a, b, *d)
31905697Smcpowers
31915697Smcpowers Normalize a and b for division, where b is the divisor. In order
31925697Smcpowers that we might make good guesses for quotient digits, we want the
31935697Smcpowers leading digit of b to be at least half the radix, which we
31945697Smcpowers accomplish by multiplying a and b by a power of 2. The exponent
31955697Smcpowers (shift count) is placed in *pd, so that the remainder can be shifted
31965697Smcpowers back at the end of the division process.
31975697Smcpowers */
31985697Smcpowers
s_mp_norm(mp_int * a,mp_int * b,mp_digit * pd)31995697Smcpowers mp_err s_mp_norm(mp_int *a, mp_int *b, mp_digit *pd)
32005697Smcpowers {
32015697Smcpowers mp_digit d;
32025697Smcpowers mp_digit mask;
32035697Smcpowers mp_digit b_msd;
32045697Smcpowers mp_err res = MP_OKAY;
32055697Smcpowers
32065697Smcpowers d = 0;
32075697Smcpowers mask = DIGIT_MAX & ~(DIGIT_MAX >> 1); /* mask is msb of digit */
32085697Smcpowers b_msd = DIGIT(b, USED(b) - 1);
32095697Smcpowers while (!(b_msd & mask)) {
32105697Smcpowers b_msd <<= 1;
32115697Smcpowers ++d;
32125697Smcpowers }
32135697Smcpowers
32145697Smcpowers if (d) {
32155697Smcpowers MP_CHECKOK( s_mp_mul_2d(a, d) );
32165697Smcpowers MP_CHECKOK( s_mp_mul_2d(b, d) );
32175697Smcpowers }
32185697Smcpowers
32195697Smcpowers *pd = d;
32205697Smcpowers CLEANUP:
32215697Smcpowers return res;
32225697Smcpowers
32235697Smcpowers } /* end s_mp_norm() */
32245697Smcpowers
32255697Smcpowers /* }}} */
32265697Smcpowers
32275697Smcpowers /* }}} */
32285697Smcpowers
32295697Smcpowers /* {{{ Primitive digit arithmetic */
32305697Smcpowers
32315697Smcpowers /* {{{ s_mp_add_d(mp, d) */
32325697Smcpowers
32335697Smcpowers /* Add d to |mp| in place */
s_mp_add_d(mp_int * mp,mp_digit d)32345697Smcpowers mp_err s_mp_add_d(mp_int *mp, mp_digit d) /* unsigned digit addition */
32355697Smcpowers {
32365697Smcpowers #if !defined(MP_NO_MP_WORD) && !defined(MP_NO_ADD_WORD)
32375697Smcpowers mp_word w, k = 0;
32385697Smcpowers mp_size ix = 1;
32395697Smcpowers
32405697Smcpowers w = (mp_word)DIGIT(mp, 0) + d;
32415697Smcpowers DIGIT(mp, 0) = ACCUM(w);
32425697Smcpowers k = CARRYOUT(w);
32435697Smcpowers
32445697Smcpowers while(ix < USED(mp) && k) {
32455697Smcpowers w = (mp_word)DIGIT(mp, ix) + k;
32465697Smcpowers DIGIT(mp, ix) = ACCUM(w);
32475697Smcpowers k = CARRYOUT(w);
32485697Smcpowers ++ix;
32495697Smcpowers }
32505697Smcpowers
32515697Smcpowers if(k != 0) {
32525697Smcpowers mp_err res;
32535697Smcpowers
32545697Smcpowers if((res = s_mp_pad(mp, USED(mp) + 1)) != MP_OKAY)
32555697Smcpowers return res;
32565697Smcpowers
32575697Smcpowers DIGIT(mp, ix) = (mp_digit)k;
32585697Smcpowers }
32595697Smcpowers
32605697Smcpowers return MP_OKAY;
32615697Smcpowers #else
32625697Smcpowers mp_digit * pmp = MP_DIGITS(mp);
32635697Smcpowers mp_digit sum, mp_i, carry = 0;
32645697Smcpowers mp_err res = MP_OKAY;
32655697Smcpowers int used = (int)MP_USED(mp);
32665697Smcpowers
32675697Smcpowers mp_i = *pmp;
32685697Smcpowers *pmp++ = sum = d + mp_i;
32695697Smcpowers carry = (sum < d);
32705697Smcpowers while (carry && --used > 0) {
32715697Smcpowers mp_i = *pmp;
32725697Smcpowers *pmp++ = sum = carry + mp_i;
32735697Smcpowers carry = !sum;
32745697Smcpowers }
32755697Smcpowers if (carry && !used) {
32765697Smcpowers /* mp is growing */
32775697Smcpowers used = MP_USED(mp);
32785697Smcpowers MP_CHECKOK( s_mp_pad(mp, used + 1) );
32795697Smcpowers MP_DIGIT(mp, used) = carry;
32805697Smcpowers }
32815697Smcpowers CLEANUP:
32825697Smcpowers return res;
32835697Smcpowers #endif
32845697Smcpowers } /* end s_mp_add_d() */
32855697Smcpowers
32865697Smcpowers /* }}} */
32875697Smcpowers
32885697Smcpowers /* {{{ s_mp_sub_d(mp, d) */
32895697Smcpowers
32905697Smcpowers /* Subtract d from |mp| in place, assumes |mp| > d */
s_mp_sub_d(mp_int * mp,mp_digit d)32915697Smcpowers mp_err s_mp_sub_d(mp_int *mp, mp_digit d) /* unsigned digit subtract */
32925697Smcpowers {
32935697Smcpowers #if !defined(MP_NO_MP_WORD) && !defined(MP_NO_SUB_WORD)
32945697Smcpowers mp_word w, b = 0;
32955697Smcpowers mp_size ix = 1;
32965697Smcpowers
32975697Smcpowers /* Compute initial subtraction */
32985697Smcpowers w = (RADIX + (mp_word)DIGIT(mp, 0)) - d;
32995697Smcpowers b = CARRYOUT(w) ? 0 : 1;
33005697Smcpowers DIGIT(mp, 0) = ACCUM(w);
33015697Smcpowers
33025697Smcpowers /* Propagate borrows leftward */
33035697Smcpowers while(b && ix < USED(mp)) {
33045697Smcpowers w = (RADIX + (mp_word)DIGIT(mp, ix)) - b;
33055697Smcpowers b = CARRYOUT(w) ? 0 : 1;
33065697Smcpowers DIGIT(mp, ix) = ACCUM(w);
33075697Smcpowers ++ix;
33085697Smcpowers }
33095697Smcpowers
33105697Smcpowers /* Remove leading zeroes */
33115697Smcpowers s_mp_clamp(mp);
33125697Smcpowers
33135697Smcpowers /* If we have a borrow out, it's a violation of the input invariant */
33145697Smcpowers if(b)
33155697Smcpowers return MP_RANGE;
33165697Smcpowers else
33175697Smcpowers return MP_OKAY;
33185697Smcpowers #else
33195697Smcpowers mp_digit *pmp = MP_DIGITS(mp);
33205697Smcpowers mp_digit mp_i, diff, borrow;
33215697Smcpowers mp_size used = MP_USED(mp);
33225697Smcpowers
33235697Smcpowers mp_i = *pmp;
33245697Smcpowers *pmp++ = diff = mp_i - d;
33255697Smcpowers borrow = (diff > mp_i);
33265697Smcpowers while (borrow && --used) {
33275697Smcpowers mp_i = *pmp;
33285697Smcpowers *pmp++ = diff = mp_i - borrow;
33295697Smcpowers borrow = (diff > mp_i);
33305697Smcpowers }
33315697Smcpowers s_mp_clamp(mp);
33325697Smcpowers return (borrow && !used) ? MP_RANGE : MP_OKAY;
33335697Smcpowers #endif
33345697Smcpowers } /* end s_mp_sub_d() */
33355697Smcpowers
33365697Smcpowers /* }}} */
33375697Smcpowers
33385697Smcpowers /* {{{ s_mp_mul_d(a, d) */
33395697Smcpowers
33405697Smcpowers /* Compute a = a * d, single digit multiplication */
s_mp_mul_d(mp_int * a,mp_digit d)33415697Smcpowers mp_err s_mp_mul_d(mp_int *a, mp_digit d)
33425697Smcpowers {
33435697Smcpowers mp_err res;
33445697Smcpowers mp_size used;
33455697Smcpowers int pow;
33465697Smcpowers
33475697Smcpowers if (!d) {
33485697Smcpowers mp_zero(a);
33495697Smcpowers return MP_OKAY;
33505697Smcpowers }
33515697Smcpowers if (d == 1)
33525697Smcpowers return MP_OKAY;
33535697Smcpowers if (0 <= (pow = s_mp_ispow2d(d))) {
33545697Smcpowers return s_mp_mul_2d(a, (mp_digit)pow);
33555697Smcpowers }
33565697Smcpowers
33575697Smcpowers used = MP_USED(a);
33585697Smcpowers MP_CHECKOK( s_mp_pad(a, used + 1) );
33595697Smcpowers
33605697Smcpowers s_mpv_mul_d(MP_DIGITS(a), used, d, MP_DIGITS(a));
33615697Smcpowers
33625697Smcpowers s_mp_clamp(a);
33635697Smcpowers
33645697Smcpowers CLEANUP:
33655697Smcpowers return res;
33665697Smcpowers
33675697Smcpowers } /* end s_mp_mul_d() */
33685697Smcpowers
33695697Smcpowers /* }}} */
33705697Smcpowers
33715697Smcpowers /* {{{ s_mp_div_d(mp, d, r) */
33725697Smcpowers
33735697Smcpowers /*
33745697Smcpowers s_mp_div_d(mp, d, r)
33755697Smcpowers
33765697Smcpowers Compute the quotient mp = mp / d and remainder r = mp mod d, for a
33775697Smcpowers single digit d. If r is null, the remainder will be discarded.
33785697Smcpowers */
33795697Smcpowers
s_mp_div_d(mp_int * mp,mp_digit d,mp_digit * r)33805697Smcpowers mp_err s_mp_div_d(mp_int *mp, mp_digit d, mp_digit *r)
33815697Smcpowers {
33825697Smcpowers #if !defined(MP_NO_MP_WORD) && !defined(MP_NO_DIV_WORD)
33835697Smcpowers mp_word w = 0, q;
33845697Smcpowers #else
33855697Smcpowers mp_digit w, q;
33865697Smcpowers #endif
33875697Smcpowers int ix;
33885697Smcpowers mp_err res;
33895697Smcpowers mp_int quot;
33905697Smcpowers mp_int rem;
33915697Smcpowers
33925697Smcpowers if(d == 0)
33935697Smcpowers return MP_RANGE;
33945697Smcpowers if (d == 1) {
33955697Smcpowers if (r)
33965697Smcpowers *r = 0;
33975697Smcpowers return MP_OKAY;
33985697Smcpowers }
33995697Smcpowers /* could check for power of 2 here, but mp_div_d does that. */
34005697Smcpowers if (MP_USED(mp) == 1) {
34015697Smcpowers mp_digit n = MP_DIGIT(mp,0);
34025697Smcpowers mp_digit rem;
34035697Smcpowers
34045697Smcpowers q = n / d;
34055697Smcpowers rem = n % d;
34065697Smcpowers MP_DIGIT(mp,0) = q;
34075697Smcpowers if (r)
34085697Smcpowers *r = rem;
34095697Smcpowers return MP_OKAY;
34105697Smcpowers }
34115697Smcpowers
34125697Smcpowers MP_DIGITS(&rem) = 0;
34135697Smcpowers MP_DIGITS(") = 0;
34145697Smcpowers /* Make room for the quotient */
34155697Smcpowers MP_CHECKOK( mp_init_size(", USED(mp), FLAG(mp)) );
34165697Smcpowers
34175697Smcpowers #if !defined(MP_NO_MP_WORD) && !defined(MP_NO_DIV_WORD)
34185697Smcpowers for(ix = USED(mp) - 1; ix >= 0; ix--) {
34195697Smcpowers w = (w << DIGIT_BIT) | DIGIT(mp, ix);
34205697Smcpowers
34215697Smcpowers if(w >= d) {
34225697Smcpowers q = w / d;
34235697Smcpowers w = w % d;
34245697Smcpowers } else {
34255697Smcpowers q = 0;
34265697Smcpowers }
34275697Smcpowers
34285697Smcpowers s_mp_lshd(", 1);
34295697Smcpowers DIGIT(", 0) = (mp_digit)q;
34305697Smcpowers }
34315697Smcpowers #else
34325697Smcpowers {
34335697Smcpowers mp_digit p;
34345697Smcpowers #if !defined(MP_ASSEMBLY_DIV_2DX1D)
34355697Smcpowers mp_digit norm;
34365697Smcpowers #endif
34375697Smcpowers
34385697Smcpowers MP_CHECKOK( mp_init_copy(&rem, mp) );
34395697Smcpowers
34405697Smcpowers #if !defined(MP_ASSEMBLY_DIV_2DX1D)
34415697Smcpowers MP_DIGIT(", 0) = d;
34425697Smcpowers MP_CHECKOK( s_mp_norm(&rem, ", &norm) );
34435697Smcpowers if (norm)
34445697Smcpowers d <<= norm;
34455697Smcpowers MP_DIGIT(", 0) = 0;
34465697Smcpowers #endif
34475697Smcpowers
34485697Smcpowers p = 0;
34495697Smcpowers for (ix = USED(&rem) - 1; ix >= 0; ix--) {
34505697Smcpowers w = DIGIT(&rem, ix);
34515697Smcpowers
34525697Smcpowers if (p) {
34535697Smcpowers MP_CHECKOK( s_mpv_div_2dx1d(p, w, d, &q, &w) );
34545697Smcpowers } else if (w >= d) {
34555697Smcpowers q = w / d;
34565697Smcpowers w = w % d;
34575697Smcpowers } else {
34585697Smcpowers q = 0;
34595697Smcpowers }
34605697Smcpowers
34615697Smcpowers MP_CHECKOK( s_mp_lshd(", 1) );
34625697Smcpowers DIGIT(", 0) = q;
34635697Smcpowers p = w;
34645697Smcpowers }
34655697Smcpowers #if !defined(MP_ASSEMBLY_DIV_2DX1D)
34665697Smcpowers if (norm)
34675697Smcpowers w >>= norm;
34685697Smcpowers #endif
34695697Smcpowers }
34705697Smcpowers #endif
34715697Smcpowers
34725697Smcpowers /* Deliver the remainder, if desired */
34735697Smcpowers if(r)
34745697Smcpowers *r = (mp_digit)w;
34755697Smcpowers
34765697Smcpowers s_mp_clamp(");
34775697Smcpowers mp_exch(", mp);
34785697Smcpowers CLEANUP:
34795697Smcpowers mp_clear(");
34805697Smcpowers mp_clear(&rem);
34815697Smcpowers
34825697Smcpowers return res;
34835697Smcpowers } /* end s_mp_div_d() */
34845697Smcpowers
34855697Smcpowers /* }}} */
34865697Smcpowers
34875697Smcpowers
34885697Smcpowers /* }}} */
34895697Smcpowers
34905697Smcpowers /* {{{ Primitive full arithmetic */
34915697Smcpowers
34925697Smcpowers /* {{{ s_mp_add(a, b) */
34935697Smcpowers
34945697Smcpowers /* Compute a = |a| + |b| */
s_mp_add(mp_int * a,const mp_int * b)34955697Smcpowers mp_err s_mp_add(mp_int *a, const mp_int *b) /* magnitude addition */
34965697Smcpowers {
34975697Smcpowers #if !defined(MP_NO_MP_WORD) && !defined(MP_NO_ADD_WORD)
34985697Smcpowers mp_word w = 0;
34995697Smcpowers #else
35005697Smcpowers mp_digit d, sum, carry = 0;
35015697Smcpowers #endif
35025697Smcpowers mp_digit *pa, *pb;
35035697Smcpowers mp_size ix;
35045697Smcpowers mp_size used;
35055697Smcpowers mp_err res;
35065697Smcpowers
35075697Smcpowers /* Make sure a has enough precision for the output value */
35085697Smcpowers if((USED(b) > USED(a)) && (res = s_mp_pad(a, USED(b))) != MP_OKAY)
35095697Smcpowers return res;
35105697Smcpowers
35115697Smcpowers /*
35125697Smcpowers Add up all digits up to the precision of b. If b had initially
35135697Smcpowers the same precision as a, or greater, we took care of it by the
35145697Smcpowers padding step above, so there is no problem. If b had initially
35155697Smcpowers less precision, we'll have to make sure the carry out is duly
35165697Smcpowers propagated upward among the higher-order digits of the sum.
35175697Smcpowers */
35185697Smcpowers pa = MP_DIGITS(a);
35195697Smcpowers pb = MP_DIGITS(b);
35205697Smcpowers used = MP_USED(b);
35215697Smcpowers for(ix = 0; ix < used; ix++) {
35225697Smcpowers #if !defined(MP_NO_MP_WORD) && !defined(MP_NO_ADD_WORD)
35235697Smcpowers w = w + *pa + *pb++;
35245697Smcpowers *pa++ = ACCUM(w);
35255697Smcpowers w = CARRYOUT(w);
35265697Smcpowers #else
35275697Smcpowers d = *pa;
35285697Smcpowers sum = d + *pb++;
35295697Smcpowers d = (sum < d); /* detect overflow */
35305697Smcpowers *pa++ = sum += carry;
35315697Smcpowers carry = d + (sum < carry); /* detect overflow */
35325697Smcpowers #endif
35335697Smcpowers }
35345697Smcpowers
35355697Smcpowers /* If we run out of 'b' digits before we're actually done, make
35365697Smcpowers sure the carries get propagated upward...
35375697Smcpowers */
35385697Smcpowers used = MP_USED(a);
35395697Smcpowers #if !defined(MP_NO_MP_WORD) && !defined(MP_NO_ADD_WORD)
35405697Smcpowers while (w && ix < used) {
35415697Smcpowers w = w + *pa;
35425697Smcpowers *pa++ = ACCUM(w);
35435697Smcpowers w = CARRYOUT(w);
35445697Smcpowers ++ix;
35455697Smcpowers }
35465697Smcpowers #else
35475697Smcpowers while (carry && ix < used) {
35485697Smcpowers sum = carry + *pa;
35495697Smcpowers *pa++ = sum;
35505697Smcpowers carry = !sum;
35515697Smcpowers ++ix;
35525697Smcpowers }
35535697Smcpowers #endif
35545697Smcpowers
35555697Smcpowers /* If there's an overall carry out, increase precision and include
35565697Smcpowers it. We could have done this initially, but why touch the memory
35575697Smcpowers allocator unless we're sure we have to?
35585697Smcpowers */
35595697Smcpowers #if !defined(MP_NO_MP_WORD) && !defined(MP_NO_ADD_WORD)
35605697Smcpowers if (w) {
35615697Smcpowers if((res = s_mp_pad(a, used + 1)) != MP_OKAY)
35625697Smcpowers return res;
35635697Smcpowers
35645697Smcpowers DIGIT(a, ix) = (mp_digit)w;
35655697Smcpowers }
35665697Smcpowers #else
35675697Smcpowers if (carry) {
35685697Smcpowers if((res = s_mp_pad(a, used + 1)) != MP_OKAY)
35695697Smcpowers return res;
35705697Smcpowers
35715697Smcpowers DIGIT(a, used) = carry;
35725697Smcpowers }
35735697Smcpowers #endif
35745697Smcpowers
35755697Smcpowers return MP_OKAY;
35765697Smcpowers } /* end s_mp_add() */
35775697Smcpowers
35785697Smcpowers /* }}} */
35795697Smcpowers
35805697Smcpowers /* Compute c = |a| + |b| */ /* magnitude addition */
s_mp_add_3arg(const mp_int * a,const mp_int * b,mp_int * c)35815697Smcpowers mp_err s_mp_add_3arg(const mp_int *a, const mp_int *b, mp_int *c)
35825697Smcpowers {
35835697Smcpowers mp_digit *pa, *pb, *pc;
35845697Smcpowers #if !defined(MP_NO_MP_WORD) && !defined(MP_NO_ADD_WORD)
35855697Smcpowers mp_word w = 0;
35865697Smcpowers #else
35875697Smcpowers mp_digit sum, carry = 0, d;
35885697Smcpowers #endif
35895697Smcpowers mp_size ix;
35905697Smcpowers mp_size used;
35915697Smcpowers mp_err res;
35925697Smcpowers
35935697Smcpowers MP_SIGN(c) = MP_SIGN(a);
35945697Smcpowers if (MP_USED(a) < MP_USED(b)) {
35955697Smcpowers const mp_int *xch = a;
35965697Smcpowers a = b;
35975697Smcpowers b = xch;
35985697Smcpowers }
35995697Smcpowers
36005697Smcpowers /* Make sure a has enough precision for the output value */
36015697Smcpowers if (MP_OKAY != (res = s_mp_pad(c, MP_USED(a))))
36025697Smcpowers return res;
36035697Smcpowers
36045697Smcpowers /*
36055697Smcpowers Add up all digits up to the precision of b. If b had initially
36065697Smcpowers the same precision as a, or greater, we took care of it by the
36075697Smcpowers exchange step above, so there is no problem. If b had initially
36085697Smcpowers less precision, we'll have to make sure the carry out is duly
36095697Smcpowers propagated upward among the higher-order digits of the sum.
36105697Smcpowers */
36115697Smcpowers pa = MP_DIGITS(a);
36125697Smcpowers pb = MP_DIGITS(b);
36135697Smcpowers pc = MP_DIGITS(c);
36145697Smcpowers used = MP_USED(b);
36155697Smcpowers for (ix = 0; ix < used; ix++) {
36165697Smcpowers #if !defined(MP_NO_MP_WORD) && !defined(MP_NO_ADD_WORD)
36175697Smcpowers w = w + *pa++ + *pb++;
36185697Smcpowers *pc++ = ACCUM(w);
36195697Smcpowers w = CARRYOUT(w);
36205697Smcpowers #else
36215697Smcpowers d = *pa++;
36225697Smcpowers sum = d + *pb++;
36235697Smcpowers d = (sum < d); /* detect overflow */
36245697Smcpowers *pc++ = sum += carry;
36255697Smcpowers carry = d + (sum < carry); /* detect overflow */
36265697Smcpowers #endif
36275697Smcpowers }
36285697Smcpowers
36295697Smcpowers /* If we run out of 'b' digits before we're actually done, make
36305697Smcpowers sure the carries get propagated upward...
36315697Smcpowers */
36325697Smcpowers for (used = MP_USED(a); ix < used; ++ix) {
36335697Smcpowers #if !defined(MP_NO_MP_WORD) && !defined(MP_NO_ADD_WORD)
36345697Smcpowers w = w + *pa++;
36355697Smcpowers *pc++ = ACCUM(w);
36365697Smcpowers w = CARRYOUT(w);
36375697Smcpowers #else
36385697Smcpowers *pc++ = sum = carry + *pa++;
36395697Smcpowers carry = (sum < carry);
36405697Smcpowers #endif
36415697Smcpowers }
36425697Smcpowers
36435697Smcpowers /* If there's an overall carry out, increase precision and include
36445697Smcpowers it. We could have done this initially, but why touch the memory
36455697Smcpowers allocator unless we're sure we have to?
36465697Smcpowers */
36475697Smcpowers #if !defined(MP_NO_MP_WORD) && !defined(MP_NO_ADD_WORD)
36485697Smcpowers if (w) {
36495697Smcpowers if((res = s_mp_pad(c, used + 1)) != MP_OKAY)
36505697Smcpowers return res;
36515697Smcpowers
36525697Smcpowers DIGIT(c, used) = (mp_digit)w;
36535697Smcpowers ++used;
36545697Smcpowers }
36555697Smcpowers #else
36565697Smcpowers if (carry) {
36575697Smcpowers if((res = s_mp_pad(c, used + 1)) != MP_OKAY)
36585697Smcpowers return res;
36595697Smcpowers
36605697Smcpowers DIGIT(c, used) = carry;
36615697Smcpowers ++used;
36625697Smcpowers }
36635697Smcpowers #endif
36645697Smcpowers MP_USED(c) = used;
36655697Smcpowers return MP_OKAY;
36665697Smcpowers }
36675697Smcpowers /* {{{ s_mp_add_offset(a, b, offset) */
36685697Smcpowers
36695697Smcpowers /* Compute a = |a| + ( |b| * (RADIX ** offset) ) */
s_mp_add_offset(mp_int * a,mp_int * b,mp_size offset)36705697Smcpowers mp_err s_mp_add_offset(mp_int *a, mp_int *b, mp_size offset)
36715697Smcpowers {
36725697Smcpowers #if !defined(MP_NO_MP_WORD) && !defined(MP_NO_ADD_WORD)
36735697Smcpowers mp_word w, k = 0;
36745697Smcpowers #else
36755697Smcpowers mp_digit d, sum, carry = 0;
36765697Smcpowers #endif
36775697Smcpowers mp_size ib;
36785697Smcpowers mp_size ia;
36795697Smcpowers mp_size lim;
36805697Smcpowers mp_err res;
36815697Smcpowers
36825697Smcpowers /* Make sure a has enough precision for the output value */
36835697Smcpowers lim = MP_USED(b) + offset;
36845697Smcpowers if((lim > USED(a)) && (res = s_mp_pad(a, lim)) != MP_OKAY)
36855697Smcpowers return res;
36865697Smcpowers
36875697Smcpowers /*
36885697Smcpowers Add up all digits up to the precision of b. If b had initially
36895697Smcpowers the same precision as a, or greater, we took care of it by the
36905697Smcpowers padding step above, so there is no problem. If b had initially
36915697Smcpowers less precision, we'll have to make sure the carry out is duly
36925697Smcpowers propagated upward among the higher-order digits of the sum.
36935697Smcpowers */
36945697Smcpowers lim = USED(b);
36955697Smcpowers for(ib = 0, ia = offset; ib < lim; ib++, ia++) {
36965697Smcpowers #if !defined(MP_NO_MP_WORD) && !defined(MP_NO_ADD_WORD)
36975697Smcpowers w = (mp_word)DIGIT(a, ia) + DIGIT(b, ib) + k;
36985697Smcpowers DIGIT(a, ia) = ACCUM(w);
36995697Smcpowers k = CARRYOUT(w);
37005697Smcpowers #else
37015697Smcpowers d = MP_DIGIT(a, ia);
37025697Smcpowers sum = d + MP_DIGIT(b, ib);
37035697Smcpowers d = (sum < d);
37045697Smcpowers MP_DIGIT(a,ia) = sum += carry;
37055697Smcpowers carry = d + (sum < carry);
37065697Smcpowers #endif
37075697Smcpowers }
37085697Smcpowers
37095697Smcpowers /* If we run out of 'b' digits before we're actually done, make
37105697Smcpowers sure the carries get propagated upward...
37115697Smcpowers */
37125697Smcpowers #if !defined(MP_NO_MP_WORD) && !defined(MP_NO_ADD_WORD)
37135697Smcpowers for (lim = MP_USED(a); k && (ia < lim); ++ia) {
37145697Smcpowers w = (mp_word)DIGIT(a, ia) + k;
37155697Smcpowers DIGIT(a, ia) = ACCUM(w);
37165697Smcpowers k = CARRYOUT(w);
37175697Smcpowers }
37185697Smcpowers #else
37195697Smcpowers for (lim = MP_USED(a); carry && (ia < lim); ++ia) {
37205697Smcpowers d = MP_DIGIT(a, ia);
37215697Smcpowers MP_DIGIT(a,ia) = sum = d + carry;
37225697Smcpowers carry = (sum < d);
37235697Smcpowers }
37245697Smcpowers #endif
37255697Smcpowers
37265697Smcpowers /* If there's an overall carry out, increase precision and include
37275697Smcpowers it. We could have done this initially, but why touch the memory
37285697Smcpowers allocator unless we're sure we have to?
37295697Smcpowers */
37305697Smcpowers #if !defined(MP_NO_MP_WORD) && !defined(MP_NO_ADD_WORD)
37315697Smcpowers if(k) {
37325697Smcpowers if((res = s_mp_pad(a, USED(a) + 1)) != MP_OKAY)
37335697Smcpowers return res;
37345697Smcpowers
37355697Smcpowers DIGIT(a, ia) = (mp_digit)k;
37365697Smcpowers }
37375697Smcpowers #else
37385697Smcpowers if (carry) {
37395697Smcpowers if((res = s_mp_pad(a, lim + 1)) != MP_OKAY)
37405697Smcpowers return res;
37415697Smcpowers
37425697Smcpowers DIGIT(a, lim) = carry;
37435697Smcpowers }
37445697Smcpowers #endif
37455697Smcpowers s_mp_clamp(a);
37465697Smcpowers
37475697Smcpowers return MP_OKAY;
37485697Smcpowers
37495697Smcpowers } /* end s_mp_add_offset() */
37505697Smcpowers
37515697Smcpowers /* }}} */
37525697Smcpowers
37535697Smcpowers /* {{{ s_mp_sub(a, b) */
37545697Smcpowers
37555697Smcpowers /* Compute a = |a| - |b|, assumes |a| >= |b| */
s_mp_sub(mp_int * a,const mp_int * b)37565697Smcpowers mp_err s_mp_sub(mp_int *a, const mp_int *b) /* magnitude subtract */
37575697Smcpowers {
37585697Smcpowers mp_digit *pa, *pb, *limit;
37595697Smcpowers #if !defined(MP_NO_MP_WORD) && !defined(MP_NO_SUB_WORD)
37605697Smcpowers mp_sword w = 0;
37615697Smcpowers #else
37625697Smcpowers mp_digit d, diff, borrow = 0;
37635697Smcpowers #endif
37645697Smcpowers
37655697Smcpowers /*
37665697Smcpowers Subtract and propagate borrow. Up to the precision of b, this
37675697Smcpowers accounts for the digits of b; after that, we just make sure the
37685697Smcpowers carries get to the right place. This saves having to pad b out to
37695697Smcpowers the precision of a just to make the loops work right...
37705697Smcpowers */
37715697Smcpowers pa = MP_DIGITS(a);
37725697Smcpowers pb = MP_DIGITS(b);
37735697Smcpowers limit = pb + MP_USED(b);
37745697Smcpowers while (pb < limit) {
37755697Smcpowers #if !defined(MP_NO_MP_WORD) && !defined(MP_NO_SUB_WORD)
37765697Smcpowers w = w + *pa - *pb++;
37775697Smcpowers *pa++ = ACCUM(w);
37785697Smcpowers w >>= MP_DIGIT_BIT;
37795697Smcpowers #else
37805697Smcpowers d = *pa;
37815697Smcpowers diff = d - *pb++;
37825697Smcpowers d = (diff > d); /* detect borrow */
37835697Smcpowers if (borrow && --diff == MP_DIGIT_MAX)
37845697Smcpowers ++d;
37855697Smcpowers *pa++ = diff;
37865697Smcpowers borrow = d;
37875697Smcpowers #endif
37885697Smcpowers }
37895697Smcpowers limit = MP_DIGITS(a) + MP_USED(a);
37905697Smcpowers #if !defined(MP_NO_MP_WORD) && !defined(MP_NO_SUB_WORD)
37915697Smcpowers while (w && pa < limit) {
37925697Smcpowers w = w + *pa;
37935697Smcpowers *pa++ = ACCUM(w);
37945697Smcpowers w >>= MP_DIGIT_BIT;
37955697Smcpowers }
37965697Smcpowers #else
37975697Smcpowers while (borrow && pa < limit) {
37985697Smcpowers d = *pa;
37995697Smcpowers *pa++ = diff = d - borrow;
38005697Smcpowers borrow = (diff > d);
38015697Smcpowers }
38025697Smcpowers #endif
38035697Smcpowers
38045697Smcpowers /* Clobber any leading zeroes we created */
38055697Smcpowers s_mp_clamp(a);
38065697Smcpowers
38075697Smcpowers /*
38085697Smcpowers If there was a borrow out, then |b| > |a| in violation
38095697Smcpowers of our input invariant. We've already done the work,
38105697Smcpowers but we'll at least complain about it...
38115697Smcpowers */
38125697Smcpowers #if !defined(MP_NO_MP_WORD) && !defined(MP_NO_SUB_WORD)
38135697Smcpowers return w ? MP_RANGE : MP_OKAY;
38145697Smcpowers #else
38155697Smcpowers return borrow ? MP_RANGE : MP_OKAY;
38165697Smcpowers #endif
38175697Smcpowers } /* end s_mp_sub() */
38185697Smcpowers
38195697Smcpowers /* }}} */
38205697Smcpowers
38215697Smcpowers /* Compute c = |a| - |b|, assumes |a| >= |b| */ /* magnitude subtract */
s_mp_sub_3arg(const mp_int * a,const mp_int * b,mp_int * c)38225697Smcpowers mp_err s_mp_sub_3arg(const mp_int *a, const mp_int *b, mp_int *c)
38235697Smcpowers {
38245697Smcpowers mp_digit *pa, *pb, *pc;
38255697Smcpowers #if !defined(MP_NO_MP_WORD) && !defined(MP_NO_SUB_WORD)
38265697Smcpowers mp_sword w = 0;
38275697Smcpowers #else
38285697Smcpowers mp_digit d, diff, borrow = 0;
38295697Smcpowers #endif
38305697Smcpowers int ix, limit;
38315697Smcpowers mp_err res;
38325697Smcpowers
38335697Smcpowers MP_SIGN(c) = MP_SIGN(a);
38345697Smcpowers
38355697Smcpowers /* Make sure a has enough precision for the output value */
38365697Smcpowers if (MP_OKAY != (res = s_mp_pad(c, MP_USED(a))))
38375697Smcpowers return res;
38385697Smcpowers
38395697Smcpowers /*
38405697Smcpowers Subtract and propagate borrow. Up to the precision of b, this
38415697Smcpowers accounts for the digits of b; after that, we just make sure the
38425697Smcpowers carries get to the right place. This saves having to pad b out to
38435697Smcpowers the precision of a just to make the loops work right...
38445697Smcpowers */
38455697Smcpowers pa = MP_DIGITS(a);
38465697Smcpowers pb = MP_DIGITS(b);
38475697Smcpowers pc = MP_DIGITS(c);
38485697Smcpowers limit = MP_USED(b);
38495697Smcpowers for (ix = 0; ix < limit; ++ix) {
38505697Smcpowers #if !defined(MP_NO_MP_WORD) && !defined(MP_NO_SUB_WORD)
38515697Smcpowers w = w + *pa++ - *pb++;
38525697Smcpowers *pc++ = ACCUM(w);
38535697Smcpowers w >>= MP_DIGIT_BIT;
38545697Smcpowers #else
38555697Smcpowers d = *pa++;
38565697Smcpowers diff = d - *pb++;
38575697Smcpowers d = (diff > d);
38585697Smcpowers if (borrow && --diff == MP_DIGIT_MAX)
38595697Smcpowers ++d;
38605697Smcpowers *pc++ = diff;
38615697Smcpowers borrow = d;
38625697Smcpowers #endif
38635697Smcpowers }
38645697Smcpowers for (limit = MP_USED(a); ix < limit; ++ix) {
38655697Smcpowers #if !defined(MP_NO_MP_WORD) && !defined(MP_NO_SUB_WORD)
38665697Smcpowers w = w + *pa++;
38675697Smcpowers *pc++ = ACCUM(w);
38685697Smcpowers w >>= MP_DIGIT_BIT;
38695697Smcpowers #else
38705697Smcpowers d = *pa++;
38715697Smcpowers *pc++ = diff = d - borrow;
38725697Smcpowers borrow = (diff > d);
38735697Smcpowers #endif
38745697Smcpowers }
38755697Smcpowers
38765697Smcpowers /* Clobber any leading zeroes we created */
38775697Smcpowers MP_USED(c) = ix;
38785697Smcpowers s_mp_clamp(c);
38795697Smcpowers
38805697Smcpowers /*
38815697Smcpowers If there was a borrow out, then |b| > |a| in violation
38825697Smcpowers of our input invariant. We've already done the work,
38835697Smcpowers but we'll at least complain about it...
38845697Smcpowers */
38855697Smcpowers #if !defined(MP_NO_MP_WORD) && !defined(MP_NO_SUB_WORD)
38865697Smcpowers return w ? MP_RANGE : MP_OKAY;
38875697Smcpowers #else
38885697Smcpowers return borrow ? MP_RANGE : MP_OKAY;
38895697Smcpowers #endif
38905697Smcpowers }
38915697Smcpowers /* {{{ s_mp_mul(a, b) */
38925697Smcpowers
38935697Smcpowers /* Compute a = |a| * |b| */
s_mp_mul(mp_int * a,const mp_int * b)38945697Smcpowers mp_err s_mp_mul(mp_int *a, const mp_int *b)
38955697Smcpowers {
38965697Smcpowers return mp_mul(a, b, a);
38975697Smcpowers } /* end s_mp_mul() */
38985697Smcpowers
38995697Smcpowers /* }}} */
39005697Smcpowers
39015697Smcpowers #if defined(MP_USE_UINT_DIGIT) && defined(MP_USE_LONG_LONG_MULTIPLY)
39025697Smcpowers /* This trick works on Sparc V8 CPUs with the Workshop compilers. */
39035697Smcpowers #define MP_MUL_DxD(a, b, Phi, Plo) \
39045697Smcpowers { unsigned long long product = (unsigned long long)a * b; \
39055697Smcpowers Plo = (mp_digit)product; \
39065697Smcpowers Phi = (mp_digit)(product >> MP_DIGIT_BIT); }
39075697Smcpowers #elif defined(OSF1)
39085697Smcpowers #define MP_MUL_DxD(a, b, Phi, Plo) \
39095697Smcpowers { Plo = asm ("mulq %a0, %a1, %v0", a, b);\
39105697Smcpowers Phi = asm ("umulh %a0, %a1, %v0", a, b); }
39115697Smcpowers #else
39125697Smcpowers #define MP_MUL_DxD(a, b, Phi, Plo) \
39135697Smcpowers { mp_digit a0b1, a1b0; \
39145697Smcpowers Plo = (a & MP_HALF_DIGIT_MAX) * (b & MP_HALF_DIGIT_MAX); \
39155697Smcpowers Phi = (a >> MP_HALF_DIGIT_BIT) * (b >> MP_HALF_DIGIT_BIT); \
39165697Smcpowers a0b1 = (a & MP_HALF_DIGIT_MAX) * (b >> MP_HALF_DIGIT_BIT); \
39175697Smcpowers a1b0 = (a >> MP_HALF_DIGIT_BIT) * (b & MP_HALF_DIGIT_MAX); \
39185697Smcpowers a1b0 += a0b1; \
39195697Smcpowers Phi += a1b0 >> MP_HALF_DIGIT_BIT; \
39205697Smcpowers if (a1b0 < a0b1) \
39215697Smcpowers Phi += MP_HALF_RADIX; \
39225697Smcpowers a1b0 <<= MP_HALF_DIGIT_BIT; \
39235697Smcpowers Plo += a1b0; \
39245697Smcpowers if (Plo < a1b0) \
39255697Smcpowers ++Phi; \
39265697Smcpowers }
39275697Smcpowers #endif
39285697Smcpowers
39295697Smcpowers #if !defined(MP_ASSEMBLY_MULTIPLY)
39305697Smcpowers /* c = a * b */
s_mpv_mul_d(const mp_digit * a,mp_size a_len,mp_digit b,mp_digit * c)39315697Smcpowers void s_mpv_mul_d(const mp_digit *a, mp_size a_len, mp_digit b, mp_digit *c)
39325697Smcpowers {
39335697Smcpowers #if !defined(MP_NO_MP_WORD) && !defined(MP_NO_MUL_WORD)
39345697Smcpowers mp_digit d = 0;
39355697Smcpowers
39365697Smcpowers /* Inner product: Digits of a */
39375697Smcpowers while (a_len--) {
39385697Smcpowers mp_word w = ((mp_word)b * *a++) + d;
39395697Smcpowers *c++ = ACCUM(w);
39405697Smcpowers d = CARRYOUT(w);
39415697Smcpowers }
39425697Smcpowers *c = d;
39435697Smcpowers #else
39445697Smcpowers mp_digit carry = 0;
39455697Smcpowers while (a_len--) {
39465697Smcpowers mp_digit a_i = *a++;
39475697Smcpowers mp_digit a0b0, a1b1;
39485697Smcpowers
39495697Smcpowers MP_MUL_DxD(a_i, b, a1b1, a0b0);
39505697Smcpowers
39515697Smcpowers a0b0 += carry;
39525697Smcpowers if (a0b0 < carry)
39535697Smcpowers ++a1b1;
39545697Smcpowers *c++ = a0b0;
39555697Smcpowers carry = a1b1;
39565697Smcpowers }
39575697Smcpowers *c = carry;
39585697Smcpowers #endif
39595697Smcpowers }
39605697Smcpowers
39615697Smcpowers /* c += a * b */
s_mpv_mul_d_add(const mp_digit * a,mp_size a_len,mp_digit b,mp_digit * c)39625697Smcpowers void s_mpv_mul_d_add(const mp_digit *a, mp_size a_len, mp_digit b,
39635697Smcpowers mp_digit *c)
39645697Smcpowers {
39655697Smcpowers #if !defined(MP_NO_MP_WORD) && !defined(MP_NO_MUL_WORD)
39665697Smcpowers mp_digit d = 0;
39675697Smcpowers
39685697Smcpowers /* Inner product: Digits of a */
39695697Smcpowers while (a_len--) {
39705697Smcpowers mp_word w = ((mp_word)b * *a++) + *c + d;
39715697Smcpowers *c++ = ACCUM(w);
39725697Smcpowers d = CARRYOUT(w);
39735697Smcpowers }
39745697Smcpowers *c = d;
39755697Smcpowers #else
39765697Smcpowers mp_digit carry = 0;
39775697Smcpowers while (a_len--) {
39785697Smcpowers mp_digit a_i = *a++;
39795697Smcpowers mp_digit a0b0, a1b1;
39805697Smcpowers
39815697Smcpowers MP_MUL_DxD(a_i, b, a1b1, a0b0);
39825697Smcpowers
39835697Smcpowers a0b0 += carry;
39845697Smcpowers if (a0b0 < carry)
39855697Smcpowers ++a1b1;
39865697Smcpowers a0b0 += a_i = *c;
39875697Smcpowers if (a0b0 < a_i)
39885697Smcpowers ++a1b1;
39895697Smcpowers *c++ = a0b0;
39905697Smcpowers carry = a1b1;
39915697Smcpowers }
39925697Smcpowers *c = carry;
39935697Smcpowers #endif
39945697Smcpowers }
39955697Smcpowers
39965697Smcpowers /* Presently, this is only used by the Montgomery arithmetic code. */
39975697Smcpowers /* c += a * b */
s_mpv_mul_d_add_prop(const mp_digit * a,mp_size a_len,mp_digit b,mp_digit * c)39985697Smcpowers void s_mpv_mul_d_add_prop(const mp_digit *a, mp_size a_len, mp_digit b, mp_digit *c)
39995697Smcpowers {
40005697Smcpowers #if !defined(MP_NO_MP_WORD) && !defined(MP_NO_MUL_WORD)
40015697Smcpowers mp_digit d = 0;
40025697Smcpowers
40035697Smcpowers /* Inner product: Digits of a */
40045697Smcpowers while (a_len--) {
40055697Smcpowers mp_word w = ((mp_word)b * *a++) + *c + d;
40065697Smcpowers *c++ = ACCUM(w);
40075697Smcpowers d = CARRYOUT(w);
40085697Smcpowers }
40095697Smcpowers
40105697Smcpowers while (d) {
40115697Smcpowers mp_word w = (mp_word)*c + d;
40125697Smcpowers *c++ = ACCUM(w);
40135697Smcpowers d = CARRYOUT(w);
40145697Smcpowers }
40155697Smcpowers #else
40165697Smcpowers mp_digit carry = 0;
40175697Smcpowers while (a_len--) {
40185697Smcpowers mp_digit a_i = *a++;
40195697Smcpowers mp_digit a0b0, a1b1;
40205697Smcpowers
40215697Smcpowers MP_MUL_DxD(a_i, b, a1b1, a0b0);
40225697Smcpowers
40235697Smcpowers a0b0 += carry;
40245697Smcpowers if (a0b0 < carry)
40255697Smcpowers ++a1b1;
40265697Smcpowers
40275697Smcpowers a0b0 += a_i = *c;
40285697Smcpowers if (a0b0 < a_i)
40295697Smcpowers ++a1b1;
40305697Smcpowers
40315697Smcpowers *c++ = a0b0;
40325697Smcpowers carry = a1b1;
40335697Smcpowers }
40345697Smcpowers while (carry) {
40355697Smcpowers mp_digit c_i = *c;
40365697Smcpowers carry += c_i;
40375697Smcpowers *c++ = carry;
40385697Smcpowers carry = carry < c_i;
40395697Smcpowers }
40405697Smcpowers #endif
40415697Smcpowers }
40425697Smcpowers #endif
40435697Smcpowers
40445697Smcpowers #if defined(MP_USE_UINT_DIGIT) && defined(MP_USE_LONG_LONG_MULTIPLY)
40455697Smcpowers /* This trick works on Sparc V8 CPUs with the Workshop compilers. */
40465697Smcpowers #define MP_SQR_D(a, Phi, Plo) \
40475697Smcpowers { unsigned long long square = (unsigned long long)a * a; \
40485697Smcpowers Plo = (mp_digit)square; \
40495697Smcpowers Phi = (mp_digit)(square >> MP_DIGIT_BIT); }
40505697Smcpowers #elif defined(OSF1)
40515697Smcpowers #define MP_SQR_D(a, Phi, Plo) \
40525697Smcpowers { Plo = asm ("mulq %a0, %a0, %v0", a);\
40535697Smcpowers Phi = asm ("umulh %a0, %a0, %v0", a); }
40545697Smcpowers #else
40555697Smcpowers #define MP_SQR_D(a, Phi, Plo) \
40565697Smcpowers { mp_digit Pmid; \
40575697Smcpowers Plo = (a & MP_HALF_DIGIT_MAX) * (a & MP_HALF_DIGIT_MAX); \
40585697Smcpowers Phi = (a >> MP_HALF_DIGIT_BIT) * (a >> MP_HALF_DIGIT_BIT); \
40595697Smcpowers Pmid = (a & MP_HALF_DIGIT_MAX) * (a >> MP_HALF_DIGIT_BIT); \
40605697Smcpowers Phi += Pmid >> (MP_HALF_DIGIT_BIT - 1); \
40615697Smcpowers Pmid <<= (MP_HALF_DIGIT_BIT + 1); \
40625697Smcpowers Plo += Pmid; \
40635697Smcpowers if (Plo < Pmid) \
40645697Smcpowers ++Phi; \
40655697Smcpowers }
40665697Smcpowers #endif
40675697Smcpowers
40685697Smcpowers #if !defined(MP_ASSEMBLY_SQUARE)
40695697Smcpowers /* Add the squares of the digits of a to the digits of b. */
s_mpv_sqr_add_prop(const mp_digit * pa,mp_size a_len,mp_digit * ps)40705697Smcpowers void s_mpv_sqr_add_prop(const mp_digit *pa, mp_size a_len, mp_digit *ps)
40715697Smcpowers {
40725697Smcpowers #if !defined(MP_NO_MP_WORD) && !defined(MP_NO_MUL_WORD)
40735697Smcpowers mp_word w;
40745697Smcpowers mp_digit d;
40755697Smcpowers mp_size ix;
40765697Smcpowers
40775697Smcpowers w = 0;
40785697Smcpowers #define ADD_SQUARE(n) \
40795697Smcpowers d = pa[n]; \
40805697Smcpowers w += (d * (mp_word)d) + ps[2*n]; \
40815697Smcpowers ps[2*n] = ACCUM(w); \
40825697Smcpowers w = (w >> DIGIT_BIT) + ps[2*n+1]; \
40835697Smcpowers ps[2*n+1] = ACCUM(w); \
40845697Smcpowers w = (w >> DIGIT_BIT)
40855697Smcpowers
40865697Smcpowers for (ix = a_len; ix >= 4; ix -= 4) {
40875697Smcpowers ADD_SQUARE(0);
40885697Smcpowers ADD_SQUARE(1);
40895697Smcpowers ADD_SQUARE(2);
40905697Smcpowers ADD_SQUARE(3);
40915697Smcpowers pa += 4;
40925697Smcpowers ps += 8;
40935697Smcpowers }
40945697Smcpowers if (ix) {
40955697Smcpowers ps += 2*ix;
40965697Smcpowers pa += ix;
40975697Smcpowers switch (ix) {
40985697Smcpowers case 3: ADD_SQUARE(-3); /* FALLTHRU */
40995697Smcpowers case 2: ADD_SQUARE(-2); /* FALLTHRU */
41005697Smcpowers case 1: ADD_SQUARE(-1); /* FALLTHRU */
41015697Smcpowers case 0: break;
41025697Smcpowers }
41035697Smcpowers }
41045697Smcpowers while (w) {
41055697Smcpowers w += *ps;
41065697Smcpowers *ps++ = ACCUM(w);
41075697Smcpowers w = (w >> DIGIT_BIT);
41085697Smcpowers }
41095697Smcpowers #else
41105697Smcpowers mp_digit carry = 0;
41115697Smcpowers while (a_len--) {
41125697Smcpowers mp_digit a_i = *pa++;
41135697Smcpowers mp_digit a0a0, a1a1;
41145697Smcpowers
41155697Smcpowers MP_SQR_D(a_i, a1a1, a0a0);
41165697Smcpowers
41175697Smcpowers /* here a1a1 and a0a0 constitute a_i ** 2 */
41185697Smcpowers a0a0 += carry;
41195697Smcpowers if (a0a0 < carry)
41205697Smcpowers ++a1a1;
41215697Smcpowers
41225697Smcpowers /* now add to ps */
41235697Smcpowers a0a0 += a_i = *ps;
41245697Smcpowers if (a0a0 < a_i)
41255697Smcpowers ++a1a1;
41265697Smcpowers *ps++ = a0a0;
41275697Smcpowers a1a1 += a_i = *ps;
41285697Smcpowers carry = (a1a1 < a_i);
41295697Smcpowers *ps++ = a1a1;
41305697Smcpowers }
41315697Smcpowers while (carry) {
41325697Smcpowers mp_digit s_i = *ps;
41335697Smcpowers carry += s_i;
41345697Smcpowers *ps++ = carry;
41355697Smcpowers carry = carry < s_i;
41365697Smcpowers }
41375697Smcpowers #endif
41385697Smcpowers }
41395697Smcpowers #endif
41405697Smcpowers
41415697Smcpowers #if (defined(MP_NO_MP_WORD) || defined(MP_NO_DIV_WORD)) \
41425697Smcpowers && !defined(MP_ASSEMBLY_DIV_2DX1D)
41435697Smcpowers /*
41445697Smcpowers ** Divide 64-bit (Nhi,Nlo) by 32-bit divisor, which must be normalized
41455697Smcpowers ** so its high bit is 1. This code is from NSPR.
41465697Smcpowers */
s_mpv_div_2dx1d(mp_digit Nhi,mp_digit Nlo,mp_digit divisor,mp_digit * qp,mp_digit * rp)41475697Smcpowers mp_err s_mpv_div_2dx1d(mp_digit Nhi, mp_digit Nlo, mp_digit divisor,
41485697Smcpowers mp_digit *qp, mp_digit *rp)
41495697Smcpowers {
41505697Smcpowers mp_digit d1, d0, q1, q0;
41515697Smcpowers mp_digit r1, r0, m;
41525697Smcpowers
41535697Smcpowers d1 = divisor >> MP_HALF_DIGIT_BIT;
41545697Smcpowers d0 = divisor & MP_HALF_DIGIT_MAX;
41555697Smcpowers r1 = Nhi % d1;
41565697Smcpowers q1 = Nhi / d1;
41575697Smcpowers m = q1 * d0;
41585697Smcpowers r1 = (r1 << MP_HALF_DIGIT_BIT) | (Nlo >> MP_HALF_DIGIT_BIT);
41595697Smcpowers if (r1 < m) {
41605697Smcpowers q1--, r1 += divisor;
41615697Smcpowers if (r1 >= divisor && r1 < m) {
41625697Smcpowers q1--, r1 += divisor;
41635697Smcpowers }
41645697Smcpowers }
41655697Smcpowers r1 -= m;
41665697Smcpowers r0 = r1 % d1;
41675697Smcpowers q0 = r1 / d1;
41685697Smcpowers m = q0 * d0;
41695697Smcpowers r0 = (r0 << MP_HALF_DIGIT_BIT) | (Nlo & MP_HALF_DIGIT_MAX);
41705697Smcpowers if (r0 < m) {
41715697Smcpowers q0--, r0 += divisor;
41725697Smcpowers if (r0 >= divisor && r0 < m) {
41735697Smcpowers q0--, r0 += divisor;
41745697Smcpowers }
41755697Smcpowers }
41765697Smcpowers if (qp)
41775697Smcpowers *qp = (q1 << MP_HALF_DIGIT_BIT) | q0;
41785697Smcpowers if (rp)
41795697Smcpowers *rp = r0 - m;
41805697Smcpowers return MP_OKAY;
41815697Smcpowers }
41825697Smcpowers #endif
41835697Smcpowers
41845697Smcpowers #if MP_SQUARE
41855697Smcpowers /* {{{ s_mp_sqr(a) */
41865697Smcpowers
s_mp_sqr(mp_int * a)41875697Smcpowers mp_err s_mp_sqr(mp_int *a)
41885697Smcpowers {
41895697Smcpowers mp_err res;
41905697Smcpowers mp_int tmp;
41915697Smcpowers
41925697Smcpowers if((res = mp_init_size(&tmp, 2 * USED(a), FLAG(a))) != MP_OKAY)
41935697Smcpowers return res;
41945697Smcpowers res = mp_sqr(a, &tmp);
41955697Smcpowers if (res == MP_OKAY) {
41965697Smcpowers s_mp_exch(&tmp, a);
41975697Smcpowers }
41985697Smcpowers mp_clear(&tmp);
41995697Smcpowers return res;
42005697Smcpowers }
42015697Smcpowers
42025697Smcpowers /* }}} */
42035697Smcpowers #endif
42045697Smcpowers
42055697Smcpowers /* {{{ s_mp_div(a, b) */
42065697Smcpowers
42075697Smcpowers /*
42085697Smcpowers s_mp_div(a, b)
42095697Smcpowers
42105697Smcpowers Compute a = a / b and b = a mod b. Assumes b > a.
42115697Smcpowers */
42125697Smcpowers
s_mp_div(mp_int * rem,mp_int * div,mp_int * quot)42135697Smcpowers mp_err s_mp_div(mp_int *rem, /* i: dividend, o: remainder */
42145697Smcpowers mp_int *div, /* i: divisor */
42155697Smcpowers mp_int *quot) /* i: 0; o: quotient */
42165697Smcpowers {
42175697Smcpowers mp_int part, t;
42185697Smcpowers #if !defined(MP_NO_MP_WORD) && !defined(MP_NO_DIV_WORD)
42195697Smcpowers mp_word q_msd;
42205697Smcpowers #else
42215697Smcpowers mp_digit q_msd;
42225697Smcpowers #endif
42235697Smcpowers mp_err res;
42245697Smcpowers mp_digit d;
42255697Smcpowers mp_digit div_msd;
42265697Smcpowers int ix;
42275697Smcpowers
42285697Smcpowers if(mp_cmp_z(div) == 0)
42295697Smcpowers return MP_RANGE;
42305697Smcpowers
42315697Smcpowers /* Shortcut if divisor is power of two */
42325697Smcpowers if((ix = s_mp_ispow2(div)) >= 0) {
42335697Smcpowers MP_CHECKOK( mp_copy(rem, quot) );
42345697Smcpowers s_mp_div_2d(quot, (mp_digit)ix);
42355697Smcpowers s_mp_mod_2d(rem, (mp_digit)ix);
42365697Smcpowers
42375697Smcpowers return MP_OKAY;
42385697Smcpowers }
42395697Smcpowers
42405697Smcpowers DIGITS(&t) = 0;
42415697Smcpowers MP_SIGN(rem) = ZPOS;
42425697Smcpowers MP_SIGN(div) = ZPOS;
42435697Smcpowers
42445697Smcpowers /* A working temporary for division */
42455697Smcpowers MP_CHECKOK( mp_init_size(&t, MP_ALLOC(rem), FLAG(rem)));
42465697Smcpowers
42475697Smcpowers /* Normalize to optimize guessing */
42485697Smcpowers MP_CHECKOK( s_mp_norm(rem, div, &d) );
42495697Smcpowers
42505697Smcpowers part = *rem;
42515697Smcpowers
42525697Smcpowers /* Perform the division itself...woo! */
42535697Smcpowers MP_USED(quot) = MP_ALLOC(quot);
42545697Smcpowers
42555697Smcpowers /* Find a partial substring of rem which is at least div */
42565697Smcpowers /* If we didn't find one, we're finished dividing */
42575697Smcpowers while (MP_USED(rem) > MP_USED(div) || s_mp_cmp(rem, div) >= 0) {
42585697Smcpowers int i;
42595697Smcpowers int unusedRem;
42605697Smcpowers
42615697Smcpowers unusedRem = MP_USED(rem) - MP_USED(div);
42625697Smcpowers MP_DIGITS(&part) = MP_DIGITS(rem) + unusedRem;
42635697Smcpowers MP_ALLOC(&part) = MP_ALLOC(rem) - unusedRem;
42645697Smcpowers MP_USED(&part) = MP_USED(div);
42655697Smcpowers if (s_mp_cmp(&part, div) < 0) {
42665697Smcpowers -- unusedRem;
42675697Smcpowers #if MP_ARGCHK == 2
42685697Smcpowers assert(unusedRem >= 0);
42695697Smcpowers #endif
42705697Smcpowers -- MP_DIGITS(&part);
42715697Smcpowers ++ MP_USED(&part);
42725697Smcpowers ++ MP_ALLOC(&part);
42735697Smcpowers }
42745697Smcpowers
42755697Smcpowers /* Compute a guess for the next quotient digit */
42765697Smcpowers q_msd = MP_DIGIT(&part, MP_USED(&part) - 1);
42775697Smcpowers div_msd = MP_DIGIT(div, MP_USED(div) - 1);
42785697Smcpowers if (q_msd >= div_msd) {
42795697Smcpowers q_msd = 1;
42805697Smcpowers } else if (MP_USED(&part) > 1) {
42815697Smcpowers #if !defined(MP_NO_MP_WORD) && !defined(MP_NO_DIV_WORD)
42825697Smcpowers q_msd = (q_msd << MP_DIGIT_BIT) | MP_DIGIT(&part, MP_USED(&part) - 2);
42835697Smcpowers q_msd /= div_msd;
42845697Smcpowers if (q_msd == RADIX)
42855697Smcpowers --q_msd;
42865697Smcpowers #else
42875697Smcpowers mp_digit r;
42885697Smcpowers MP_CHECKOK( s_mpv_div_2dx1d(q_msd, MP_DIGIT(&part, MP_USED(&part) - 2),
42895697Smcpowers div_msd, &q_msd, &r) );
42905697Smcpowers #endif
42915697Smcpowers } else {
42925697Smcpowers q_msd = 0;
42935697Smcpowers }
42945697Smcpowers #if MP_ARGCHK == 2
42955697Smcpowers assert(q_msd > 0); /* This case should never occur any more. */
42965697Smcpowers #endif
42975697Smcpowers if (q_msd <= 0)
42985697Smcpowers break;
42995697Smcpowers
43005697Smcpowers /* See what that multiplies out to */
43015697Smcpowers mp_copy(div, &t);
43025697Smcpowers MP_CHECKOK( s_mp_mul_d(&t, (mp_digit)q_msd) );
43035697Smcpowers
43045697Smcpowers /*
43055697Smcpowers If it's too big, back it off. We should not have to do this
43065697Smcpowers more than once, or, in rare cases, twice. Knuth describes a
43075697Smcpowers method by which this could be reduced to a maximum of once, but
43085697Smcpowers I didn't implement that here.
43095697Smcpowers * When using s_mpv_div_2dx1d, we may have to do this 3 times.
43105697Smcpowers */
43115697Smcpowers for (i = 4; s_mp_cmp(&t, &part) > 0 && i > 0; --i) {
43125697Smcpowers --q_msd;
43135697Smcpowers s_mp_sub(&t, div); /* t -= div */
43145697Smcpowers }
43155697Smcpowers if (i < 0) {
43165697Smcpowers res = MP_RANGE;
43175697Smcpowers goto CLEANUP;
43185697Smcpowers }
43195697Smcpowers
43205697Smcpowers /* At this point, q_msd should be the right next digit */
43215697Smcpowers MP_CHECKOK( s_mp_sub(&part, &t) ); /* part -= t */
43225697Smcpowers s_mp_clamp(rem);
43235697Smcpowers
43245697Smcpowers /*
43255697Smcpowers Include the digit in the quotient. We allocated enough memory
43265697Smcpowers for any quotient we could ever possibly get, so we should not
43275697Smcpowers have to check for failures here
43285697Smcpowers */
43295697Smcpowers MP_DIGIT(quot, unusedRem) = (mp_digit)q_msd;
43305697Smcpowers }
43315697Smcpowers
43325697Smcpowers /* Denormalize remainder */
43335697Smcpowers if (d) {
43345697Smcpowers s_mp_div_2d(rem, d);
43355697Smcpowers }
43365697Smcpowers
43375697Smcpowers s_mp_clamp(quot);
43385697Smcpowers
43395697Smcpowers CLEANUP:
43405697Smcpowers mp_clear(&t);
43415697Smcpowers
43425697Smcpowers return res;
43435697Smcpowers
43445697Smcpowers } /* end s_mp_div() */
43455697Smcpowers
43465697Smcpowers
43475697Smcpowers /* }}} */
43485697Smcpowers
43495697Smcpowers /* {{{ s_mp_2expt(a, k) */
43505697Smcpowers
s_mp_2expt(mp_int * a,mp_digit k)43515697Smcpowers mp_err s_mp_2expt(mp_int *a, mp_digit k)
43525697Smcpowers {
43535697Smcpowers mp_err res;
43545697Smcpowers mp_size dig, bit;
43555697Smcpowers
43565697Smcpowers dig = k / DIGIT_BIT;
43575697Smcpowers bit = k % DIGIT_BIT;
43585697Smcpowers
43595697Smcpowers mp_zero(a);
43605697Smcpowers if((res = s_mp_pad(a, dig + 1)) != MP_OKAY)
43615697Smcpowers return res;
43625697Smcpowers
43635697Smcpowers DIGIT(a, dig) |= ((mp_digit)1 << bit);
43645697Smcpowers
43655697Smcpowers return MP_OKAY;
43665697Smcpowers
43675697Smcpowers } /* end s_mp_2expt() */
43685697Smcpowers
43695697Smcpowers /* }}} */
43705697Smcpowers
43715697Smcpowers /* {{{ s_mp_reduce(x, m, mu) */
43725697Smcpowers
43735697Smcpowers /*
43745697Smcpowers Compute Barrett reduction, x (mod m), given a precomputed value for
43755697Smcpowers mu = b^2k / m, where b = RADIX and k = #digits(m). This should be
43765697Smcpowers faster than straight division, when many reductions by the same
43775697Smcpowers value of m are required (such as in modular exponentiation). This
43785697Smcpowers can nearly halve the time required to do modular exponentiation,
43795697Smcpowers as compared to using the full integer divide to reduce.
43805697Smcpowers
43815697Smcpowers This algorithm was derived from the _Handbook of Applied
43825697Smcpowers Cryptography_ by Menezes, Oorschot and VanStone, Ch. 14,
43835697Smcpowers pp. 603-604.
43845697Smcpowers */
43855697Smcpowers
s_mp_reduce(mp_int * x,const mp_int * m,const mp_int * mu)43865697Smcpowers mp_err s_mp_reduce(mp_int *x, const mp_int *m, const mp_int *mu)
43875697Smcpowers {
43885697Smcpowers mp_int q;
43895697Smcpowers mp_err res;
43905697Smcpowers
43915697Smcpowers if((res = mp_init_copy(&q, x)) != MP_OKAY)
43925697Smcpowers return res;
43935697Smcpowers
43945697Smcpowers s_mp_rshd(&q, USED(m) - 1); /* q1 = x / b^(k-1) */
43955697Smcpowers s_mp_mul(&q, mu); /* q2 = q1 * mu */
43965697Smcpowers s_mp_rshd(&q, USED(m) + 1); /* q3 = q2 / b^(k+1) */
43975697Smcpowers
43985697Smcpowers /* x = x mod b^(k+1), quick (no division) */
43995697Smcpowers s_mp_mod_2d(x, DIGIT_BIT * (USED(m) + 1));
44005697Smcpowers
44015697Smcpowers /* q = q * m mod b^(k+1), quick (no division) */
44025697Smcpowers s_mp_mul(&q, m);
44035697Smcpowers s_mp_mod_2d(&q, DIGIT_BIT * (USED(m) + 1));
44045697Smcpowers
44055697Smcpowers /* x = x - q */
44065697Smcpowers if((res = mp_sub(x, &q, x)) != MP_OKAY)
44075697Smcpowers goto CLEANUP;
44085697Smcpowers
44095697Smcpowers /* If x < 0, add b^(k+1) to it */
44105697Smcpowers if(mp_cmp_z(x) < 0) {
44115697Smcpowers mp_set(&q, 1);
44125697Smcpowers if((res = s_mp_lshd(&q, USED(m) + 1)) != MP_OKAY)
44135697Smcpowers goto CLEANUP;
44145697Smcpowers if((res = mp_add(x, &q, x)) != MP_OKAY)
44155697Smcpowers goto CLEANUP;
44165697Smcpowers }
44175697Smcpowers
44185697Smcpowers /* Back off if it's too big */
44195697Smcpowers while(mp_cmp(x, m) >= 0) {
44205697Smcpowers if((res = s_mp_sub(x, m)) != MP_OKAY)
44215697Smcpowers break;
44225697Smcpowers }
44235697Smcpowers
44245697Smcpowers CLEANUP:
44255697Smcpowers mp_clear(&q);
44265697Smcpowers
44275697Smcpowers return res;
44285697Smcpowers
44295697Smcpowers } /* end s_mp_reduce() */
44305697Smcpowers
44315697Smcpowers /* }}} */
44325697Smcpowers
44335697Smcpowers /* }}} */
44345697Smcpowers
44355697Smcpowers /* {{{ Primitive comparisons */
44365697Smcpowers
44375697Smcpowers /* {{{ s_mp_cmp(a, b) */
44385697Smcpowers
44395697Smcpowers /* Compare |a| <=> |b|, return 0 if equal, <0 if a<b, >0 if a>b */
s_mp_cmp(const mp_int * a,const mp_int * b)44405697Smcpowers int s_mp_cmp(const mp_int *a, const mp_int *b)
44415697Smcpowers {
44425697Smcpowers mp_size used_a = MP_USED(a);
44435697Smcpowers {
44445697Smcpowers mp_size used_b = MP_USED(b);
44455697Smcpowers
44465697Smcpowers if (used_a > used_b)
44475697Smcpowers goto IS_GT;
44485697Smcpowers if (used_a < used_b)
44495697Smcpowers goto IS_LT;
44505697Smcpowers }
44515697Smcpowers {
44525697Smcpowers mp_digit *pa, *pb;
44535697Smcpowers mp_digit da = 0, db = 0;
44545697Smcpowers
44555697Smcpowers #define CMP_AB(n) if ((da = pa[n]) != (db = pb[n])) goto done
44565697Smcpowers
44575697Smcpowers pa = MP_DIGITS(a) + used_a;
44585697Smcpowers pb = MP_DIGITS(b) + used_a;
44595697Smcpowers while (used_a >= 4) {
44605697Smcpowers pa -= 4;
44615697Smcpowers pb -= 4;
44625697Smcpowers used_a -= 4;
44635697Smcpowers CMP_AB(3);
44645697Smcpowers CMP_AB(2);
44655697Smcpowers CMP_AB(1);
44665697Smcpowers CMP_AB(0);
44675697Smcpowers }
44685697Smcpowers while (used_a-- > 0 && ((da = *--pa) == (db = *--pb)))
44695697Smcpowers /* do nothing */;
44705697Smcpowers done:
44715697Smcpowers if (da > db)
44725697Smcpowers goto IS_GT;
44735697Smcpowers if (da < db)
44745697Smcpowers goto IS_LT;
44755697Smcpowers }
44765697Smcpowers return MP_EQ;
44775697Smcpowers IS_LT:
44785697Smcpowers return MP_LT;
44795697Smcpowers IS_GT:
44805697Smcpowers return MP_GT;
44815697Smcpowers } /* end s_mp_cmp() */
44825697Smcpowers
44835697Smcpowers /* }}} */
44845697Smcpowers
44855697Smcpowers /* {{{ s_mp_cmp_d(a, d) */
44865697Smcpowers
44875697Smcpowers /* Compare |a| <=> d, return 0 if equal, <0 if a<d, >0 if a>d */
s_mp_cmp_d(const mp_int * a,mp_digit d)44885697Smcpowers int s_mp_cmp_d(const mp_int *a, mp_digit d)
44895697Smcpowers {
44905697Smcpowers if(USED(a) > 1)
44915697Smcpowers return MP_GT;
44925697Smcpowers
44935697Smcpowers if(DIGIT(a, 0) < d)
44945697Smcpowers return MP_LT;
44955697Smcpowers else if(DIGIT(a, 0) > d)
44965697Smcpowers return MP_GT;
44975697Smcpowers else
44985697Smcpowers return MP_EQ;
44995697Smcpowers
45005697Smcpowers } /* end s_mp_cmp_d() */
45015697Smcpowers
45025697Smcpowers /* }}} */
45035697Smcpowers
45045697Smcpowers /* {{{ s_mp_ispow2(v) */
45055697Smcpowers
45065697Smcpowers /*
45075697Smcpowers Returns -1 if the value is not a power of two; otherwise, it returns
45085697Smcpowers k such that v = 2^k, i.e. lg(v).
45095697Smcpowers */
s_mp_ispow2(const mp_int * v)45105697Smcpowers int s_mp_ispow2(const mp_int *v)
45115697Smcpowers {
45125697Smcpowers mp_digit d;
45135697Smcpowers int extra = 0, ix;
45145697Smcpowers
45155697Smcpowers ix = MP_USED(v) - 1;
45165697Smcpowers d = MP_DIGIT(v, ix); /* most significant digit of v */
45175697Smcpowers
45185697Smcpowers extra = s_mp_ispow2d(d);
45195697Smcpowers if (extra < 0 || ix == 0)
45205697Smcpowers return extra;
45215697Smcpowers
45225697Smcpowers while (--ix >= 0) {
45235697Smcpowers if (DIGIT(v, ix) != 0)
45245697Smcpowers return -1; /* not a power of two */
45255697Smcpowers extra += MP_DIGIT_BIT;
45265697Smcpowers }
45275697Smcpowers
45285697Smcpowers return extra;
45295697Smcpowers
45305697Smcpowers } /* end s_mp_ispow2() */
45315697Smcpowers
45325697Smcpowers /* }}} */
45335697Smcpowers
45345697Smcpowers /* {{{ s_mp_ispow2d(d) */
45355697Smcpowers
s_mp_ispow2d(mp_digit d)45365697Smcpowers int s_mp_ispow2d(mp_digit d)
45375697Smcpowers {
45385697Smcpowers if ((d != 0) && ((d & (d-1)) == 0)) { /* d is a power of 2 */
45395697Smcpowers int pow = 0;
45405697Smcpowers #if defined (MP_USE_UINT_DIGIT)
45415697Smcpowers if (d & 0xffff0000U)
45425697Smcpowers pow += 16;
45435697Smcpowers if (d & 0xff00ff00U)
45445697Smcpowers pow += 8;
45455697Smcpowers if (d & 0xf0f0f0f0U)
45465697Smcpowers pow += 4;
45475697Smcpowers if (d & 0xccccccccU)
45485697Smcpowers pow += 2;
45495697Smcpowers if (d & 0xaaaaaaaaU)
45505697Smcpowers pow += 1;
45515697Smcpowers #elif defined(MP_USE_LONG_LONG_DIGIT)
45525697Smcpowers if (d & 0xffffffff00000000ULL)
45535697Smcpowers pow += 32;
45545697Smcpowers if (d & 0xffff0000ffff0000ULL)
45555697Smcpowers pow += 16;
45565697Smcpowers if (d & 0xff00ff00ff00ff00ULL)
45575697Smcpowers pow += 8;
45585697Smcpowers if (d & 0xf0f0f0f0f0f0f0f0ULL)
45595697Smcpowers pow += 4;
45605697Smcpowers if (d & 0xccccccccccccccccULL)
45615697Smcpowers pow += 2;
45625697Smcpowers if (d & 0xaaaaaaaaaaaaaaaaULL)
45635697Smcpowers pow += 1;
45645697Smcpowers #elif defined(MP_USE_LONG_DIGIT)
45655697Smcpowers if (d & 0xffffffff00000000UL)
45665697Smcpowers pow += 32;
45675697Smcpowers if (d & 0xffff0000ffff0000UL)
45685697Smcpowers pow += 16;
45695697Smcpowers if (d & 0xff00ff00ff00ff00UL)
45705697Smcpowers pow += 8;
45715697Smcpowers if (d & 0xf0f0f0f0f0f0f0f0UL)
45725697Smcpowers pow += 4;
45735697Smcpowers if (d & 0xccccccccccccccccUL)
45745697Smcpowers pow += 2;
45755697Smcpowers if (d & 0xaaaaaaaaaaaaaaaaUL)
45765697Smcpowers pow += 1;
45775697Smcpowers #else
45785697Smcpowers #error "unknown type for mp_digit"
45795697Smcpowers #endif
45805697Smcpowers return pow;
45815697Smcpowers }
45825697Smcpowers return -1;
45835697Smcpowers
45845697Smcpowers } /* end s_mp_ispow2d() */
45855697Smcpowers
45865697Smcpowers /* }}} */
45875697Smcpowers
45885697Smcpowers /* }}} */
45895697Smcpowers
45905697Smcpowers /* {{{ Primitive I/O helpers */
45915697Smcpowers
45925697Smcpowers /* {{{ s_mp_tovalue(ch, r) */
45935697Smcpowers
45945697Smcpowers /*
45955697Smcpowers Convert the given character to its digit value, in the given radix.
45965697Smcpowers If the given character is not understood in the given radix, -1 is
45975697Smcpowers returned. Otherwise the digit's numeric value is returned.
45985697Smcpowers
45995697Smcpowers The results will be odd if you use a radix < 2 or > 62, you are
46005697Smcpowers expected to know what you're up to.
46015697Smcpowers */
s_mp_tovalue(char ch,int r)46025697Smcpowers int s_mp_tovalue(char ch, int r)
46035697Smcpowers {
46045697Smcpowers int val, xch;
46055697Smcpowers
46065697Smcpowers if(r > 36)
46075697Smcpowers xch = ch;
46085697Smcpowers else
46095697Smcpowers xch = toupper(ch);
46105697Smcpowers
46115697Smcpowers if(isdigit(xch))
46125697Smcpowers val = xch - '0';
46135697Smcpowers else if(isupper(xch))
46145697Smcpowers val = xch - 'A' + 10;
46155697Smcpowers else if(islower(xch))
46165697Smcpowers val = xch - 'a' + 36;
46175697Smcpowers else if(xch == '+')
46185697Smcpowers val = 62;
46195697Smcpowers else if(xch == '/')
46205697Smcpowers val = 63;
46215697Smcpowers else
46225697Smcpowers return -1;
46235697Smcpowers
46245697Smcpowers if(val < 0 || val >= r)
46255697Smcpowers return -1;
46265697Smcpowers
46275697Smcpowers return val;
46285697Smcpowers
46295697Smcpowers } /* end s_mp_tovalue() */
46305697Smcpowers
46315697Smcpowers /* }}} */
46325697Smcpowers
46335697Smcpowers /* {{{ s_mp_todigit(val, r, low) */
46345697Smcpowers
46355697Smcpowers /*
46365697Smcpowers Convert val to a radix-r digit, if possible. If val is out of range
46375697Smcpowers for r, returns zero. Otherwise, returns an ASCII character denoting
46385697Smcpowers the value in the given radix.
46395697Smcpowers
46405697Smcpowers The results may be odd if you use a radix < 2 or > 64, you are
46415697Smcpowers expected to know what you're doing.
46425697Smcpowers */
46435697Smcpowers
s_mp_todigit(mp_digit val,int r,int low)46445697Smcpowers char s_mp_todigit(mp_digit val, int r, int low)
46455697Smcpowers {
46465697Smcpowers char ch;
46475697Smcpowers
46485697Smcpowers if(val >= r)
46495697Smcpowers return 0;
46505697Smcpowers
46515697Smcpowers ch = s_dmap_1[val];
46525697Smcpowers
46535697Smcpowers if(r <= 36 && low)
46545697Smcpowers ch = tolower(ch);
46555697Smcpowers
46565697Smcpowers return ch;
46575697Smcpowers
46585697Smcpowers } /* end s_mp_todigit() */
46595697Smcpowers
46605697Smcpowers /* }}} */
46615697Smcpowers
46625697Smcpowers /* {{{ s_mp_outlen(bits, radix) */
46635697Smcpowers
46645697Smcpowers /*
46655697Smcpowers Return an estimate for how long a string is needed to hold a radix
46665697Smcpowers r representation of a number with 'bits' significant bits, plus an
46675697Smcpowers extra for a zero terminator (assuming C style strings here)
46685697Smcpowers */
s_mp_outlen(int bits,int r)46695697Smcpowers int s_mp_outlen(int bits, int r)
46705697Smcpowers {
46715697Smcpowers return (int)((double)bits * LOG_V_2(r) + 1.5) + 1;
46725697Smcpowers
46735697Smcpowers } /* end s_mp_outlen() */
46745697Smcpowers
46755697Smcpowers /* }}} */
46765697Smcpowers
46775697Smcpowers /* }}} */
46785697Smcpowers
46795697Smcpowers /* {{{ mp_read_unsigned_octets(mp, str, len) */
46805697Smcpowers /* mp_read_unsigned_octets(mp, str, len)
46815697Smcpowers Read in a raw value (base 256) into the given mp_int
46825697Smcpowers No sign bit, number is positive. Leading zeros ignored.
46835697Smcpowers */
46845697Smcpowers
46855697Smcpowers mp_err
mp_read_unsigned_octets(mp_int * mp,const unsigned char * str,mp_size len)46865697Smcpowers mp_read_unsigned_octets(mp_int *mp, const unsigned char *str, mp_size len)
46875697Smcpowers {
46885697Smcpowers int count;
46895697Smcpowers mp_err res;
46905697Smcpowers mp_digit d;
46915697Smcpowers
46925697Smcpowers ARGCHK(mp != NULL && str != NULL && len > 0, MP_BADARG);
46935697Smcpowers
46945697Smcpowers mp_zero(mp);
46955697Smcpowers
46965697Smcpowers count = len % sizeof(mp_digit);
46975697Smcpowers if (count) {
46985697Smcpowers for (d = 0; count-- > 0; --len) {
46995697Smcpowers d = (d << 8) | *str++;
47005697Smcpowers }
47015697Smcpowers MP_DIGIT(mp, 0) = d;
47025697Smcpowers }
47035697Smcpowers
47045697Smcpowers /* Read the rest of the digits */
47055697Smcpowers for(; len > 0; len -= sizeof(mp_digit)) {
47065697Smcpowers for (d = 0, count = sizeof(mp_digit); count > 0; --count) {
47075697Smcpowers d = (d << 8) | *str++;
47085697Smcpowers }
47095697Smcpowers if (MP_EQ == mp_cmp_z(mp)) {
47105697Smcpowers if (!d)
47115697Smcpowers continue;
47125697Smcpowers } else {
47135697Smcpowers if((res = s_mp_lshd(mp, 1)) != MP_OKAY)
47145697Smcpowers return res;
47155697Smcpowers }
47165697Smcpowers MP_DIGIT(mp, 0) = d;
47175697Smcpowers }
47185697Smcpowers return MP_OKAY;
47195697Smcpowers } /* end mp_read_unsigned_octets() */
47205697Smcpowers /* }}} */
47215697Smcpowers
47225697Smcpowers /* {{{ mp_unsigned_octet_size(mp) */
47235697Smcpowers int
mp_unsigned_octet_size(const mp_int * mp)47245697Smcpowers mp_unsigned_octet_size(const mp_int *mp)
47255697Smcpowers {
47265697Smcpowers int bytes;
47275697Smcpowers int ix;
47285697Smcpowers mp_digit d = 0;
47295697Smcpowers
47305697Smcpowers ARGCHK(mp != NULL, MP_BADARG);
47315697Smcpowers ARGCHK(MP_ZPOS == SIGN(mp), MP_BADARG);
47325697Smcpowers
47335697Smcpowers bytes = (USED(mp) * sizeof(mp_digit));
47345697Smcpowers
47355697Smcpowers /* subtract leading zeros. */
47365697Smcpowers /* Iterate over each digit... */
47375697Smcpowers for(ix = USED(mp) - 1; ix >= 0; ix--) {
47385697Smcpowers d = DIGIT(mp, ix);
47395697Smcpowers if (d)
47405697Smcpowers break;
47415697Smcpowers bytes -= sizeof(d);
47425697Smcpowers }
47435697Smcpowers if (!bytes)
47445697Smcpowers return 1;
47455697Smcpowers
47465697Smcpowers /* Have MSD, check digit bytes, high order first */
47475697Smcpowers for(ix = sizeof(mp_digit) - 1; ix >= 0; ix--) {
47485697Smcpowers unsigned char x = (unsigned char)(d >> (ix * CHAR_BIT));
47495697Smcpowers if (x)
47505697Smcpowers break;
47515697Smcpowers --bytes;
47525697Smcpowers }
47535697Smcpowers return bytes;
47545697Smcpowers } /* end mp_unsigned_octet_size() */
47555697Smcpowers /* }}} */
47565697Smcpowers
47575697Smcpowers /* {{{ mp_to_unsigned_octets(mp, str) */
47585697Smcpowers /* output a buffer of big endian octets no longer than specified. */
47595697Smcpowers mp_err
mp_to_unsigned_octets(const mp_int * mp,unsigned char * str,mp_size maxlen)47605697Smcpowers mp_to_unsigned_octets(const mp_int *mp, unsigned char *str, mp_size maxlen)
47615697Smcpowers {
47625697Smcpowers int ix, pos = 0;
47635697Smcpowers int bytes;
47645697Smcpowers
47655697Smcpowers ARGCHK(mp != NULL && str != NULL && !SIGN(mp), MP_BADARG);
47665697Smcpowers
47675697Smcpowers bytes = mp_unsigned_octet_size(mp);
47685697Smcpowers ARGCHK(bytes <= maxlen, MP_BADARG);
47695697Smcpowers
47705697Smcpowers /* Iterate over each digit... */
47715697Smcpowers for(ix = USED(mp) - 1; ix >= 0; ix--) {
47725697Smcpowers mp_digit d = DIGIT(mp, ix);
47735697Smcpowers int jx;
47745697Smcpowers
47755697Smcpowers /* Unpack digit bytes, high order first */
47765697Smcpowers for(jx = sizeof(mp_digit) - 1; jx >= 0; jx--) {
47775697Smcpowers unsigned char x = (unsigned char)(d >> (jx * CHAR_BIT));
47785697Smcpowers if (!pos && !x) /* suppress leading zeros */
47795697Smcpowers continue;
47805697Smcpowers str[pos++] = x;
47815697Smcpowers }
47825697Smcpowers }
47835697Smcpowers if (!pos)
47845697Smcpowers str[pos++] = 0;
47855697Smcpowers return pos;
47865697Smcpowers } /* end mp_to_unsigned_octets() */
47875697Smcpowers /* }}} */
47885697Smcpowers
47895697Smcpowers /* {{{ mp_to_signed_octets(mp, str) */
47905697Smcpowers /* output a buffer of big endian octets no longer than specified. */
47915697Smcpowers mp_err
mp_to_signed_octets(const mp_int * mp,unsigned char * str,mp_size maxlen)47925697Smcpowers mp_to_signed_octets(const mp_int *mp, unsigned char *str, mp_size maxlen)
47935697Smcpowers {
47945697Smcpowers int ix, pos = 0;
47955697Smcpowers int bytes;
47965697Smcpowers
47975697Smcpowers ARGCHK(mp != NULL && str != NULL && !SIGN(mp), MP_BADARG);
47985697Smcpowers
47995697Smcpowers bytes = mp_unsigned_octet_size(mp);
48005697Smcpowers ARGCHK(bytes <= maxlen, MP_BADARG);
48015697Smcpowers
48025697Smcpowers /* Iterate over each digit... */
48035697Smcpowers for(ix = USED(mp) - 1; ix >= 0; ix--) {
48045697Smcpowers mp_digit d = DIGIT(mp, ix);
48055697Smcpowers int jx;
48065697Smcpowers
48075697Smcpowers /* Unpack digit bytes, high order first */
48085697Smcpowers for(jx = sizeof(mp_digit) - 1; jx >= 0; jx--) {
48095697Smcpowers unsigned char x = (unsigned char)(d >> (jx * CHAR_BIT));
48105697Smcpowers if (!pos) {
48115697Smcpowers if (!x) /* suppress leading zeros */
48125697Smcpowers continue;
48135697Smcpowers if (x & 0x80) { /* add one leading zero to make output positive. */
48145697Smcpowers ARGCHK(bytes + 1 <= maxlen, MP_BADARG);
48155697Smcpowers if (bytes + 1 > maxlen)
48165697Smcpowers return MP_BADARG;
48175697Smcpowers str[pos++] = 0;
48185697Smcpowers }
48195697Smcpowers }
48205697Smcpowers str[pos++] = x;
48215697Smcpowers }
48225697Smcpowers }
48235697Smcpowers if (!pos)
48245697Smcpowers str[pos++] = 0;
48255697Smcpowers return pos;
48265697Smcpowers } /* end mp_to_signed_octets() */
48275697Smcpowers /* }}} */
48285697Smcpowers
48295697Smcpowers /* {{{ mp_to_fixlen_octets(mp, str) */
48305697Smcpowers /* output a buffer of big endian octets exactly as long as requested. */
48315697Smcpowers mp_err
mp_to_fixlen_octets(const mp_int * mp,unsigned char * str,mp_size length)48325697Smcpowers mp_to_fixlen_octets(const mp_int *mp, unsigned char *str, mp_size length)
48335697Smcpowers {
48345697Smcpowers int ix, pos = 0;
48355697Smcpowers int bytes;
48365697Smcpowers
48375697Smcpowers ARGCHK(mp != NULL && str != NULL && !SIGN(mp), MP_BADARG);
48385697Smcpowers
48395697Smcpowers bytes = mp_unsigned_octet_size(mp);
48405697Smcpowers ARGCHK(bytes <= length, MP_BADARG);
48415697Smcpowers
48425697Smcpowers /* place any needed leading zeros */
48435697Smcpowers for (;length > bytes; --length) {
48445697Smcpowers *str++ = 0;
48455697Smcpowers }
48465697Smcpowers
48475697Smcpowers /* Iterate over each digit... */
48485697Smcpowers for(ix = USED(mp) - 1; ix >= 0; ix--) {
48495697Smcpowers mp_digit d = DIGIT(mp, ix);
48505697Smcpowers int jx;
48515697Smcpowers
48525697Smcpowers /* Unpack digit bytes, high order first */
48535697Smcpowers for(jx = sizeof(mp_digit) - 1; jx >= 0; jx--) {
48545697Smcpowers unsigned char x = (unsigned char)(d >> (jx * CHAR_BIT));
48555697Smcpowers if (!pos && !x) /* suppress leading zeros */
48565697Smcpowers continue;
48575697Smcpowers str[pos++] = x;
48585697Smcpowers }
48595697Smcpowers }
48605697Smcpowers if (!pos)
48615697Smcpowers str[pos++] = 0;
48625697Smcpowers return MP_OKAY;
48635697Smcpowers } /* end mp_to_fixlen_octets() */
48645697Smcpowers /* }}} */
48655697Smcpowers
48665697Smcpowers
48675697Smcpowers /*------------------------------------------------------------------------*/
48685697Smcpowers /* HERE THERE BE DRAGONS */
4869*13066SDina.Nimeh@Sun.COM /* END CSTYLED */
4870