1*f2ba9e96SDina K Nimeh /* BEGIN CSTYLED */ 2f9fbec18Smcpowers /* 3f9fbec18Smcpowers * mpi.c 4f9fbec18Smcpowers * 5f9fbec18Smcpowers * Arbitrary precision integer arithmetic library 6f9fbec18Smcpowers * 7f9fbec18Smcpowers * ***** BEGIN LICENSE BLOCK ***** 8f9fbec18Smcpowers * Version: MPL 1.1/GPL 2.0/LGPL 2.1 9f9fbec18Smcpowers * 10f9fbec18Smcpowers * The contents of this file are subject to the Mozilla Public License Version 11f9fbec18Smcpowers * 1.1 (the "License"); you may not use this file except in compliance with 12f9fbec18Smcpowers * the License. You may obtain a copy of the License at 13f9fbec18Smcpowers * http://www.mozilla.org/MPL/ 14f9fbec18Smcpowers * 15f9fbec18Smcpowers * Software distributed under the License is distributed on an "AS IS" basis, 16f9fbec18Smcpowers * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License 17f9fbec18Smcpowers * for the specific language governing rights and limitations under the 18f9fbec18Smcpowers * License. 19f9fbec18Smcpowers * 20f9fbec18Smcpowers * The Original Code is the MPI Arbitrary Precision Integer Arithmetic library. 21f9fbec18Smcpowers * 22f9fbec18Smcpowers * The Initial Developer of the Original Code is 23f9fbec18Smcpowers * Michael J. Fromberger. 24f9fbec18Smcpowers * Portions created by the Initial Developer are Copyright (C) 1998 25f9fbec18Smcpowers * the Initial Developer. All Rights Reserved. 26f9fbec18Smcpowers * 27f9fbec18Smcpowers * Contributor(s): 28f9fbec18Smcpowers * Netscape Communications Corporation 29f9fbec18Smcpowers * Douglas Stebila <douglas@stebila.ca> of Sun Laboratories. 30f9fbec18Smcpowers * 31f9fbec18Smcpowers * Alternatively, the contents of this file may be used under the terms of 32f9fbec18Smcpowers * either the GNU General Public License Version 2 or later (the "GPL"), or 33f9fbec18Smcpowers * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), 34f9fbec18Smcpowers * in which case the provisions of the GPL or the LGPL are applicable instead 35f9fbec18Smcpowers * of those above. If you wish to allow use of your version of this file only 36f9fbec18Smcpowers * under the terms of either the GPL or the LGPL, and not to allow others to 37f9fbec18Smcpowers * use your version of this file under the terms of the MPL, indicate your 38f9fbec18Smcpowers * decision by deleting the provisions above and replace them with the notice 39f9fbec18Smcpowers * and other provisions required by the GPL or the LGPL. If you do not delete 40f9fbec18Smcpowers * the provisions above, a recipient may use your version of this file under 41f9fbec18Smcpowers * the terms of any one of the MPL, the GPL or the LGPL. 42f9fbec18Smcpowers * 43f9fbec18Smcpowers * ***** END LICENSE BLOCK ***** */ 44f9fbec18Smcpowers /* 45*f2ba9e96SDina K Nimeh * Copyright (c) 2007, 2010, Oracle and/or its affiliates. All rights reserved. 46f9fbec18Smcpowers * 47f9fbec18Smcpowers * Sun elects to use this software under the MPL license. 48f9fbec18Smcpowers */ 49f9fbec18Smcpowers 50f9fbec18Smcpowers /* $Id: mpi.c,v 1.45 2006/09/29 20:12:21 alexei.volkov.bugs%sun.com Exp $ */ 51f9fbec18Smcpowers 52f9fbec18Smcpowers #include "mpi-priv.h" 53f9fbec18Smcpowers #if defined(OSF1) 54f9fbec18Smcpowers #include <c_asm.h> 55f9fbec18Smcpowers #endif 56f9fbec18Smcpowers 57f9fbec18Smcpowers #if MP_LOGTAB 58f9fbec18Smcpowers /* 59f9fbec18Smcpowers A table of the logs of 2 for various bases (the 0 and 1 entries of 60f9fbec18Smcpowers this table are meaningless and should not be referenced). 61f9fbec18Smcpowers 62f9fbec18Smcpowers This table is used to compute output lengths for the mp_toradix() 63f9fbec18Smcpowers function. Since a number n in radix r takes up about log_r(n) 64f9fbec18Smcpowers digits, we estimate the output size by taking the least integer 65f9fbec18Smcpowers greater than log_r(n), where: 66f9fbec18Smcpowers 67f9fbec18Smcpowers log_r(n) = log_2(n) * log_r(2) 68f9fbec18Smcpowers 69f9fbec18Smcpowers This table, therefore, is a table of log_r(2) for 2 <= r <= 36, 70f9fbec18Smcpowers which are the output bases supported. 71f9fbec18Smcpowers */ 72f9fbec18Smcpowers #include "logtab.h" 73f9fbec18Smcpowers #endif 74f9fbec18Smcpowers 75f9fbec18Smcpowers /* {{{ Constant strings */ 76f9fbec18Smcpowers 77f9fbec18Smcpowers /* Constant strings returned by mp_strerror() */ 78f9fbec18Smcpowers static const char *mp_err_string[] = { 79f9fbec18Smcpowers "unknown result code", /* say what? */ 80f9fbec18Smcpowers "boolean true", /* MP_OKAY, MP_YES */ 81f9fbec18Smcpowers "boolean false", /* MP_NO */ 82f9fbec18Smcpowers "out of memory", /* MP_MEM */ 83f9fbec18Smcpowers "argument out of range", /* MP_RANGE */ 84f9fbec18Smcpowers "invalid input parameter", /* MP_BADARG */ 85f9fbec18Smcpowers "result is undefined" /* MP_UNDEF */ 86f9fbec18Smcpowers }; 87f9fbec18Smcpowers 88f9fbec18Smcpowers /* Value to digit maps for radix conversion */ 89f9fbec18Smcpowers 90f9fbec18Smcpowers /* s_dmap_1 - standard digits and letters */ 91f9fbec18Smcpowers static const char *s_dmap_1 = 92f9fbec18Smcpowers "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz+/"; 93f9fbec18Smcpowers 94f9fbec18Smcpowers /* }}} */ 95f9fbec18Smcpowers 96f9fbec18Smcpowers unsigned long mp_allocs; 97f9fbec18Smcpowers unsigned long mp_frees; 98f9fbec18Smcpowers unsigned long mp_copies; 99f9fbec18Smcpowers 100f9fbec18Smcpowers /* {{{ Default precision manipulation */ 101f9fbec18Smcpowers 102f9fbec18Smcpowers /* Default precision for newly created mp_int's */ 103f9fbec18Smcpowers static mp_size s_mp_defprec = MP_DEFPREC; 104f9fbec18Smcpowers 105f9fbec18Smcpowers mp_size mp_get_prec(void) 106f9fbec18Smcpowers { 107f9fbec18Smcpowers return s_mp_defprec; 108f9fbec18Smcpowers 109f9fbec18Smcpowers } /* end mp_get_prec() */ 110f9fbec18Smcpowers 111f9fbec18Smcpowers void mp_set_prec(mp_size prec) 112f9fbec18Smcpowers { 113f9fbec18Smcpowers if(prec == 0) 114f9fbec18Smcpowers s_mp_defprec = MP_DEFPREC; 115f9fbec18Smcpowers else 116f9fbec18Smcpowers s_mp_defprec = prec; 117f9fbec18Smcpowers 118f9fbec18Smcpowers } /* end mp_set_prec() */ 119f9fbec18Smcpowers 120f9fbec18Smcpowers /* }}} */ 121f9fbec18Smcpowers 122f9fbec18Smcpowers /*------------------------------------------------------------------------*/ 123f9fbec18Smcpowers /* {{{ mp_init(mp, kmflag) */ 124f9fbec18Smcpowers 125f9fbec18Smcpowers /* 126f9fbec18Smcpowers mp_init(mp, kmflag) 127f9fbec18Smcpowers 128f9fbec18Smcpowers Initialize a new zero-valued mp_int. Returns MP_OKAY if successful, 129f9fbec18Smcpowers MP_MEM if memory could not be allocated for the structure. 130f9fbec18Smcpowers */ 131f9fbec18Smcpowers 132f9fbec18Smcpowers mp_err mp_init(mp_int *mp, int kmflag) 133f9fbec18Smcpowers { 134f9fbec18Smcpowers return mp_init_size(mp, s_mp_defprec, kmflag); 135f9fbec18Smcpowers 136f9fbec18Smcpowers } /* end mp_init() */ 137f9fbec18Smcpowers 138f9fbec18Smcpowers /* }}} */ 139f9fbec18Smcpowers 140f9fbec18Smcpowers /* {{{ mp_init_size(mp, prec, kmflag) */ 141f9fbec18Smcpowers 142f9fbec18Smcpowers /* 143f9fbec18Smcpowers mp_init_size(mp, prec, kmflag) 144f9fbec18Smcpowers 145f9fbec18Smcpowers Initialize a new zero-valued mp_int with at least the given 146f9fbec18Smcpowers precision; returns MP_OKAY if successful, or MP_MEM if memory could 147f9fbec18Smcpowers not be allocated for the structure. 148f9fbec18Smcpowers */ 149f9fbec18Smcpowers 150f9fbec18Smcpowers mp_err mp_init_size(mp_int *mp, mp_size prec, int kmflag) 151f9fbec18Smcpowers { 152f9fbec18Smcpowers ARGCHK(mp != NULL && prec > 0, MP_BADARG); 153f9fbec18Smcpowers 154f9fbec18Smcpowers prec = MP_ROUNDUP(prec, s_mp_defprec); 155f9fbec18Smcpowers if((DIGITS(mp) = s_mp_alloc(prec, sizeof(mp_digit), kmflag)) == NULL) 156f9fbec18Smcpowers return MP_MEM; 157f9fbec18Smcpowers 158f9fbec18Smcpowers SIGN(mp) = ZPOS; 159f9fbec18Smcpowers USED(mp) = 1; 160f9fbec18Smcpowers ALLOC(mp) = prec; 161*f2ba9e96SDina K Nimeh FLAG(mp) = kmflag; 162f9fbec18Smcpowers 163f9fbec18Smcpowers return MP_OKAY; 164f9fbec18Smcpowers 165f9fbec18Smcpowers } /* end mp_init_size() */ 166f9fbec18Smcpowers 167f9fbec18Smcpowers /* }}} */ 168f9fbec18Smcpowers 169f9fbec18Smcpowers /* {{{ mp_init_copy(mp, from) */ 170f9fbec18Smcpowers 171f9fbec18Smcpowers /* 172f9fbec18Smcpowers mp_init_copy(mp, from) 173f9fbec18Smcpowers 174f9fbec18Smcpowers Initialize mp as an exact copy of from. Returns MP_OKAY if 175f9fbec18Smcpowers successful, MP_MEM if memory could not be allocated for the new 176f9fbec18Smcpowers structure. 177f9fbec18Smcpowers */ 178f9fbec18Smcpowers 179f9fbec18Smcpowers mp_err mp_init_copy(mp_int *mp, const mp_int *from) 180f9fbec18Smcpowers { 181f9fbec18Smcpowers ARGCHK(mp != NULL && from != NULL, MP_BADARG); 182f9fbec18Smcpowers 183f9fbec18Smcpowers if(mp == from) 184f9fbec18Smcpowers return MP_OKAY; 185f9fbec18Smcpowers 186f9fbec18Smcpowers if((DIGITS(mp) = s_mp_alloc(ALLOC(from), sizeof(mp_digit), FLAG(from))) == NULL) 187f9fbec18Smcpowers return MP_MEM; 188f9fbec18Smcpowers 189f9fbec18Smcpowers s_mp_copy(DIGITS(from), DIGITS(mp), USED(from)); 190f9fbec18Smcpowers USED(mp) = USED(from); 191f9fbec18Smcpowers ALLOC(mp) = ALLOC(from); 192f9fbec18Smcpowers SIGN(mp) = SIGN(from); 193f9fbec18Smcpowers FLAG(mp) = FLAG(from); 194f9fbec18Smcpowers 195f9fbec18Smcpowers return MP_OKAY; 196f9fbec18Smcpowers 197f9fbec18Smcpowers } /* end mp_init_copy() */ 198f9fbec18Smcpowers 199f9fbec18Smcpowers /* }}} */ 200f9fbec18Smcpowers 201f9fbec18Smcpowers /* {{{ mp_copy(from, to) */ 202f9fbec18Smcpowers 203f9fbec18Smcpowers /* 204f9fbec18Smcpowers mp_copy(from, to) 205f9fbec18Smcpowers 206f9fbec18Smcpowers Copies the mp_int 'from' to the mp_int 'to'. It is presumed that 207f9fbec18Smcpowers 'to' has already been initialized (if not, use mp_init_copy() 208f9fbec18Smcpowers instead). If 'from' and 'to' are identical, nothing happens. 209f9fbec18Smcpowers */ 210f9fbec18Smcpowers 211f9fbec18Smcpowers mp_err mp_copy(const mp_int *from, mp_int *to) 212f9fbec18Smcpowers { 213f9fbec18Smcpowers ARGCHK(from != NULL && to != NULL, MP_BADARG); 214f9fbec18Smcpowers 215f9fbec18Smcpowers if(from == to) 216f9fbec18Smcpowers return MP_OKAY; 217f9fbec18Smcpowers 218f9fbec18Smcpowers ++mp_copies; 219f9fbec18Smcpowers { /* copy */ 220f9fbec18Smcpowers mp_digit *tmp; 221f9fbec18Smcpowers 222f9fbec18Smcpowers /* 223f9fbec18Smcpowers If the allocated buffer in 'to' already has enough space to hold 224f9fbec18Smcpowers all the used digits of 'from', we'll re-use it to avoid hitting 225f9fbec18Smcpowers the memory allocater more than necessary; otherwise, we'd have 226f9fbec18Smcpowers to grow anyway, so we just allocate a hunk and make the copy as 227f9fbec18Smcpowers usual 228f9fbec18Smcpowers */ 229f9fbec18Smcpowers if(ALLOC(to) >= USED(from)) { 230f9fbec18Smcpowers s_mp_setz(DIGITS(to) + USED(from), ALLOC(to) - USED(from)); 231f9fbec18Smcpowers s_mp_copy(DIGITS(from), DIGITS(to), USED(from)); 232f9fbec18Smcpowers 233f9fbec18Smcpowers } else { 234f9fbec18Smcpowers if((tmp = s_mp_alloc(ALLOC(from), sizeof(mp_digit), FLAG(from))) == NULL) 235f9fbec18Smcpowers return MP_MEM; 236f9fbec18Smcpowers 237f9fbec18Smcpowers s_mp_copy(DIGITS(from), tmp, USED(from)); 238f9fbec18Smcpowers 239f9fbec18Smcpowers if(DIGITS(to) != NULL) { 240f9fbec18Smcpowers #if MP_CRYPTO 241f9fbec18Smcpowers s_mp_setz(DIGITS(to), ALLOC(to)); 242f9fbec18Smcpowers #endif 243f9fbec18Smcpowers s_mp_free(DIGITS(to), ALLOC(to)); 244f9fbec18Smcpowers } 245f9fbec18Smcpowers 246f9fbec18Smcpowers DIGITS(to) = tmp; 247f9fbec18Smcpowers ALLOC(to) = ALLOC(from); 248f9fbec18Smcpowers } 249f9fbec18Smcpowers 250f9fbec18Smcpowers /* Copy the precision and sign from the original */ 251f9fbec18Smcpowers USED(to) = USED(from); 252f9fbec18Smcpowers SIGN(to) = SIGN(from); 253*f2ba9e96SDina K Nimeh FLAG(to) = FLAG(from); 254f9fbec18Smcpowers } /* end copy */ 255f9fbec18Smcpowers 256f9fbec18Smcpowers return MP_OKAY; 257f9fbec18Smcpowers 258f9fbec18Smcpowers } /* end mp_copy() */ 259f9fbec18Smcpowers 260f9fbec18Smcpowers /* }}} */ 261f9fbec18Smcpowers 262f9fbec18Smcpowers /* {{{ mp_exch(mp1, mp2) */ 263f9fbec18Smcpowers 264f9fbec18Smcpowers /* 265f9fbec18Smcpowers mp_exch(mp1, mp2) 266f9fbec18Smcpowers 267f9fbec18Smcpowers Exchange mp1 and mp2 without allocating any intermediate memory 268f9fbec18Smcpowers (well, unless you count the stack space needed for this call and the 269f9fbec18Smcpowers locals it creates...). This cannot fail. 270f9fbec18Smcpowers */ 271f9fbec18Smcpowers 272f9fbec18Smcpowers void mp_exch(mp_int *mp1, mp_int *mp2) 273f9fbec18Smcpowers { 274f9fbec18Smcpowers #if MP_ARGCHK == 2 275f9fbec18Smcpowers assert(mp1 != NULL && mp2 != NULL); 276f9fbec18Smcpowers #else 277f9fbec18Smcpowers if(mp1 == NULL || mp2 == NULL) 278f9fbec18Smcpowers return; 279f9fbec18Smcpowers #endif 280f9fbec18Smcpowers 281f9fbec18Smcpowers s_mp_exch(mp1, mp2); 282f9fbec18Smcpowers 283f9fbec18Smcpowers } /* end mp_exch() */ 284f9fbec18Smcpowers 285f9fbec18Smcpowers /* }}} */ 286f9fbec18Smcpowers 287f9fbec18Smcpowers /* {{{ mp_clear(mp) */ 288f9fbec18Smcpowers 289f9fbec18Smcpowers /* 290f9fbec18Smcpowers mp_clear(mp) 291f9fbec18Smcpowers 292f9fbec18Smcpowers Release the storage used by an mp_int, and void its fields so that 293f9fbec18Smcpowers if someone calls mp_clear() again for the same int later, we won't 294f9fbec18Smcpowers get tollchocked. 295f9fbec18Smcpowers */ 296f9fbec18Smcpowers 297f9fbec18Smcpowers void mp_clear(mp_int *mp) 298f9fbec18Smcpowers { 299f9fbec18Smcpowers if(mp == NULL) 300f9fbec18Smcpowers return; 301f9fbec18Smcpowers 302f9fbec18Smcpowers if(DIGITS(mp) != NULL) { 303f9fbec18Smcpowers #if MP_CRYPTO 304f9fbec18Smcpowers s_mp_setz(DIGITS(mp), ALLOC(mp)); 305f9fbec18Smcpowers #endif 306f9fbec18Smcpowers s_mp_free(DIGITS(mp), ALLOC(mp)); 307f9fbec18Smcpowers DIGITS(mp) = NULL; 308f9fbec18Smcpowers } 309f9fbec18Smcpowers 310f9fbec18Smcpowers USED(mp) = 0; 311f9fbec18Smcpowers ALLOC(mp) = 0; 312f9fbec18Smcpowers 313f9fbec18Smcpowers } /* end mp_clear() */ 314f9fbec18Smcpowers 315f9fbec18Smcpowers /* }}} */ 316f9fbec18Smcpowers 317f9fbec18Smcpowers /* {{{ mp_zero(mp) */ 318f9fbec18Smcpowers 319f9fbec18Smcpowers /* 320f9fbec18Smcpowers mp_zero(mp) 321f9fbec18Smcpowers 322f9fbec18Smcpowers Set mp to zero. Does not change the allocated size of the structure, 323f9fbec18Smcpowers and therefore cannot fail (except on a bad argument, which we ignore) 324f9fbec18Smcpowers */ 325f9fbec18Smcpowers void mp_zero(mp_int *mp) 326f9fbec18Smcpowers { 327f9fbec18Smcpowers if(mp == NULL) 328f9fbec18Smcpowers return; 329f9fbec18Smcpowers 330f9fbec18Smcpowers s_mp_setz(DIGITS(mp), ALLOC(mp)); 331f9fbec18Smcpowers USED(mp) = 1; 332f9fbec18Smcpowers SIGN(mp) = ZPOS; 333f9fbec18Smcpowers 334f9fbec18Smcpowers } /* end mp_zero() */ 335f9fbec18Smcpowers 336f9fbec18Smcpowers /* }}} */ 337f9fbec18Smcpowers 338f9fbec18Smcpowers /* {{{ mp_set(mp, d) */ 339f9fbec18Smcpowers 340f9fbec18Smcpowers void mp_set(mp_int *mp, mp_digit d) 341f9fbec18Smcpowers { 342f9fbec18Smcpowers if(mp == NULL) 343f9fbec18Smcpowers return; 344f9fbec18Smcpowers 345f9fbec18Smcpowers mp_zero(mp); 346f9fbec18Smcpowers DIGIT(mp, 0) = d; 347f9fbec18Smcpowers 348f9fbec18Smcpowers } /* end mp_set() */ 349f9fbec18Smcpowers 350f9fbec18Smcpowers /* }}} */ 351f9fbec18Smcpowers 352f9fbec18Smcpowers /* {{{ mp_set_int(mp, z) */ 353f9fbec18Smcpowers 354f9fbec18Smcpowers mp_err mp_set_int(mp_int *mp, long z) 355f9fbec18Smcpowers { 356f9fbec18Smcpowers int ix; 357f9fbec18Smcpowers unsigned long v = labs(z); 358f9fbec18Smcpowers mp_err res; 359f9fbec18Smcpowers 360f9fbec18Smcpowers ARGCHK(mp != NULL, MP_BADARG); 361f9fbec18Smcpowers 362f9fbec18Smcpowers mp_zero(mp); 363f9fbec18Smcpowers if(z == 0) 364f9fbec18Smcpowers return MP_OKAY; /* shortcut for zero */ 365f9fbec18Smcpowers 366f9fbec18Smcpowers if (sizeof v <= sizeof(mp_digit)) { 367f9fbec18Smcpowers DIGIT(mp,0) = v; 368f9fbec18Smcpowers } else { 369f9fbec18Smcpowers for (ix = sizeof(long) - 1; ix >= 0; ix--) { 370f9fbec18Smcpowers if ((res = s_mp_mul_d(mp, (UCHAR_MAX + 1))) != MP_OKAY) 371f9fbec18Smcpowers return res; 372f9fbec18Smcpowers 373f9fbec18Smcpowers res = s_mp_add_d(mp, (mp_digit)((v >> (ix * CHAR_BIT)) & UCHAR_MAX)); 374f9fbec18Smcpowers if (res != MP_OKAY) 375f9fbec18Smcpowers return res; 376f9fbec18Smcpowers } 377f9fbec18Smcpowers } 378f9fbec18Smcpowers if(z < 0) 379f9fbec18Smcpowers SIGN(mp) = NEG; 380f9fbec18Smcpowers 381f9fbec18Smcpowers return MP_OKAY; 382f9fbec18Smcpowers 383f9fbec18Smcpowers } /* end mp_set_int() */ 384f9fbec18Smcpowers 385f9fbec18Smcpowers /* }}} */ 386f9fbec18Smcpowers 387f9fbec18Smcpowers /* {{{ mp_set_ulong(mp, z) */ 388f9fbec18Smcpowers 389f9fbec18Smcpowers mp_err mp_set_ulong(mp_int *mp, unsigned long z) 390f9fbec18Smcpowers { 391f9fbec18Smcpowers int ix; 392f9fbec18Smcpowers mp_err res; 393f9fbec18Smcpowers 394f9fbec18Smcpowers ARGCHK(mp != NULL, MP_BADARG); 395f9fbec18Smcpowers 396f9fbec18Smcpowers mp_zero(mp); 397f9fbec18Smcpowers if(z == 0) 398f9fbec18Smcpowers return MP_OKAY; /* shortcut for zero */ 399f9fbec18Smcpowers 400f9fbec18Smcpowers if (sizeof z <= sizeof(mp_digit)) { 401f9fbec18Smcpowers DIGIT(mp,0) = z; 402f9fbec18Smcpowers } else { 403f9fbec18Smcpowers for (ix = sizeof(long) - 1; ix >= 0; ix--) { 404f9fbec18Smcpowers if ((res = s_mp_mul_d(mp, (UCHAR_MAX + 1))) != MP_OKAY) 405f9fbec18Smcpowers return res; 406f9fbec18Smcpowers 407f9fbec18Smcpowers res = s_mp_add_d(mp, (mp_digit)((z >> (ix * CHAR_BIT)) & UCHAR_MAX)); 408f9fbec18Smcpowers if (res != MP_OKAY) 409f9fbec18Smcpowers return res; 410f9fbec18Smcpowers } 411f9fbec18Smcpowers } 412f9fbec18Smcpowers return MP_OKAY; 413f9fbec18Smcpowers } /* end mp_set_ulong() */ 414f9fbec18Smcpowers 415f9fbec18Smcpowers /* }}} */ 416f9fbec18Smcpowers 417f9fbec18Smcpowers /*------------------------------------------------------------------------*/ 418f9fbec18Smcpowers /* {{{ Digit arithmetic */ 419f9fbec18Smcpowers 420f9fbec18Smcpowers /* {{{ mp_add_d(a, d, b) */ 421f9fbec18Smcpowers 422f9fbec18Smcpowers /* 423f9fbec18Smcpowers mp_add_d(a, d, b) 424f9fbec18Smcpowers 425f9fbec18Smcpowers Compute the sum b = a + d, for a single digit d. Respects the sign of 426f9fbec18Smcpowers its primary addend (single digits are unsigned anyway). 427f9fbec18Smcpowers */ 428f9fbec18Smcpowers 429f9fbec18Smcpowers mp_err mp_add_d(const mp_int *a, mp_digit d, mp_int *b) 430f9fbec18Smcpowers { 431f9fbec18Smcpowers mp_int tmp; 432f9fbec18Smcpowers mp_err res; 433f9fbec18Smcpowers 434f9fbec18Smcpowers ARGCHK(a != NULL && b != NULL, MP_BADARG); 435f9fbec18Smcpowers 436f9fbec18Smcpowers if((res = mp_init_copy(&tmp, a)) != MP_OKAY) 437f9fbec18Smcpowers return res; 438f9fbec18Smcpowers 439f9fbec18Smcpowers if(SIGN(&tmp) == ZPOS) { 440f9fbec18Smcpowers if((res = s_mp_add_d(&tmp, d)) != MP_OKAY) 441f9fbec18Smcpowers goto CLEANUP; 442f9fbec18Smcpowers } else if(s_mp_cmp_d(&tmp, d) >= 0) { 443f9fbec18Smcpowers if((res = s_mp_sub_d(&tmp, d)) != MP_OKAY) 444f9fbec18Smcpowers goto CLEANUP; 445f9fbec18Smcpowers } else { 446f9fbec18Smcpowers mp_neg(&tmp, &tmp); 447f9fbec18Smcpowers 448f9fbec18Smcpowers DIGIT(&tmp, 0) = d - DIGIT(&tmp, 0); 449f9fbec18Smcpowers } 450f9fbec18Smcpowers 451f9fbec18Smcpowers if(s_mp_cmp_d(&tmp, 0) == 0) 452f9fbec18Smcpowers SIGN(&tmp) = ZPOS; 453f9fbec18Smcpowers 454f9fbec18Smcpowers s_mp_exch(&tmp, b); 455f9fbec18Smcpowers 456f9fbec18Smcpowers CLEANUP: 457f9fbec18Smcpowers mp_clear(&tmp); 458f9fbec18Smcpowers return res; 459f9fbec18Smcpowers 460f9fbec18Smcpowers } /* end mp_add_d() */ 461f9fbec18Smcpowers 462f9fbec18Smcpowers /* }}} */ 463f9fbec18Smcpowers 464f9fbec18Smcpowers /* {{{ mp_sub_d(a, d, b) */ 465f9fbec18Smcpowers 466f9fbec18Smcpowers /* 467f9fbec18Smcpowers mp_sub_d(a, d, b) 468f9fbec18Smcpowers 469f9fbec18Smcpowers Compute the difference b = a - d, for a single digit d. Respects the 470f9fbec18Smcpowers sign of its subtrahend (single digits are unsigned anyway). 471f9fbec18Smcpowers */ 472f9fbec18Smcpowers 473f9fbec18Smcpowers mp_err mp_sub_d(const mp_int *a, mp_digit d, mp_int *b) 474f9fbec18Smcpowers { 475f9fbec18Smcpowers mp_int tmp; 476f9fbec18Smcpowers mp_err res; 477f9fbec18Smcpowers 478f9fbec18Smcpowers ARGCHK(a != NULL && b != NULL, MP_BADARG); 479f9fbec18Smcpowers 480f9fbec18Smcpowers if((res = mp_init_copy(&tmp, a)) != MP_OKAY) 481f9fbec18Smcpowers return res; 482f9fbec18Smcpowers 483f9fbec18Smcpowers if(SIGN(&tmp) == NEG) { 484f9fbec18Smcpowers if((res = s_mp_add_d(&tmp, d)) != MP_OKAY) 485f9fbec18Smcpowers goto CLEANUP; 486f9fbec18Smcpowers } else if(s_mp_cmp_d(&tmp, d) >= 0) { 487f9fbec18Smcpowers if((res = s_mp_sub_d(&tmp, d)) != MP_OKAY) 488f9fbec18Smcpowers goto CLEANUP; 489f9fbec18Smcpowers } else { 490f9fbec18Smcpowers mp_neg(&tmp, &tmp); 491f9fbec18Smcpowers 492f9fbec18Smcpowers DIGIT(&tmp, 0) = d - DIGIT(&tmp, 0); 493f9fbec18Smcpowers SIGN(&tmp) = NEG; 494f9fbec18Smcpowers } 495f9fbec18Smcpowers 496f9fbec18Smcpowers if(s_mp_cmp_d(&tmp, 0) == 0) 497f9fbec18Smcpowers SIGN(&tmp) = ZPOS; 498f9fbec18Smcpowers 499f9fbec18Smcpowers s_mp_exch(&tmp, b); 500f9fbec18Smcpowers 501f9fbec18Smcpowers CLEANUP: 502f9fbec18Smcpowers mp_clear(&tmp); 503f9fbec18Smcpowers return res; 504f9fbec18Smcpowers 505f9fbec18Smcpowers } /* end mp_sub_d() */ 506f9fbec18Smcpowers 507f9fbec18Smcpowers /* }}} */ 508f9fbec18Smcpowers 509f9fbec18Smcpowers /* {{{ mp_mul_d(a, d, b) */ 510f9fbec18Smcpowers 511f9fbec18Smcpowers /* 512f9fbec18Smcpowers mp_mul_d(a, d, b) 513f9fbec18Smcpowers 514f9fbec18Smcpowers Compute the product b = a * d, for a single digit d. Respects the sign 515f9fbec18Smcpowers of its multiplicand (single digits are unsigned anyway) 516f9fbec18Smcpowers */ 517f9fbec18Smcpowers 518f9fbec18Smcpowers mp_err mp_mul_d(const mp_int *a, mp_digit d, mp_int *b) 519f9fbec18Smcpowers { 520f9fbec18Smcpowers mp_err res; 521f9fbec18Smcpowers 522f9fbec18Smcpowers ARGCHK(a != NULL && b != NULL, MP_BADARG); 523f9fbec18Smcpowers 524f9fbec18Smcpowers if(d == 0) { 525f9fbec18Smcpowers mp_zero(b); 526f9fbec18Smcpowers return MP_OKAY; 527f9fbec18Smcpowers } 528f9fbec18Smcpowers 529f9fbec18Smcpowers if((res = mp_copy(a, b)) != MP_OKAY) 530f9fbec18Smcpowers return res; 531f9fbec18Smcpowers 532f9fbec18Smcpowers res = s_mp_mul_d(b, d); 533f9fbec18Smcpowers 534f9fbec18Smcpowers return res; 535f9fbec18Smcpowers 536f9fbec18Smcpowers } /* end mp_mul_d() */ 537f9fbec18Smcpowers 538f9fbec18Smcpowers /* }}} */ 539f9fbec18Smcpowers 540f9fbec18Smcpowers /* {{{ mp_mul_2(a, c) */ 541f9fbec18Smcpowers 542f9fbec18Smcpowers mp_err mp_mul_2(const mp_int *a, mp_int *c) 543f9fbec18Smcpowers { 544f9fbec18Smcpowers mp_err res; 545f9fbec18Smcpowers 546f9fbec18Smcpowers ARGCHK(a != NULL && c != NULL, MP_BADARG); 547f9fbec18Smcpowers 548f9fbec18Smcpowers if((res = mp_copy(a, c)) != MP_OKAY) 549f9fbec18Smcpowers return res; 550f9fbec18Smcpowers 551f9fbec18Smcpowers return s_mp_mul_2(c); 552f9fbec18Smcpowers 553f9fbec18Smcpowers } /* end mp_mul_2() */ 554f9fbec18Smcpowers 555f9fbec18Smcpowers /* }}} */ 556f9fbec18Smcpowers 557f9fbec18Smcpowers /* {{{ mp_div_d(a, d, q, r) */ 558f9fbec18Smcpowers 559f9fbec18Smcpowers /* 560f9fbec18Smcpowers mp_div_d(a, d, q, r) 561f9fbec18Smcpowers 562f9fbec18Smcpowers Compute the quotient q = a / d and remainder r = a mod d, for a 563f9fbec18Smcpowers single digit d. Respects the sign of its divisor (single digits are 564f9fbec18Smcpowers unsigned anyway). 565f9fbec18Smcpowers */ 566f9fbec18Smcpowers 567f9fbec18Smcpowers mp_err mp_div_d(const mp_int *a, mp_digit d, mp_int *q, mp_digit *r) 568f9fbec18Smcpowers { 569f9fbec18Smcpowers mp_err res; 570f9fbec18Smcpowers mp_int qp; 571f9fbec18Smcpowers mp_digit rem; 572f9fbec18Smcpowers int pow; 573f9fbec18Smcpowers 574f9fbec18Smcpowers ARGCHK(a != NULL, MP_BADARG); 575f9fbec18Smcpowers 576f9fbec18Smcpowers if(d == 0) 577f9fbec18Smcpowers return MP_RANGE; 578f9fbec18Smcpowers 579f9fbec18Smcpowers /* Shortcut for powers of two ... */ 580f9fbec18Smcpowers if((pow = s_mp_ispow2d(d)) >= 0) { 581f9fbec18Smcpowers mp_digit mask; 582f9fbec18Smcpowers 583f9fbec18Smcpowers mask = ((mp_digit)1 << pow) - 1; 584f9fbec18Smcpowers rem = DIGIT(a, 0) & mask; 585f9fbec18Smcpowers 586f9fbec18Smcpowers if(q) { 587f9fbec18Smcpowers mp_copy(a, q); 588f9fbec18Smcpowers s_mp_div_2d(q, pow); 589f9fbec18Smcpowers } 590f9fbec18Smcpowers 591f9fbec18Smcpowers if(r) 592f9fbec18Smcpowers *r = rem; 593f9fbec18Smcpowers 594f9fbec18Smcpowers return MP_OKAY; 595f9fbec18Smcpowers } 596f9fbec18Smcpowers 597f9fbec18Smcpowers if((res = mp_init_copy(&qp, a)) != MP_OKAY) 598f9fbec18Smcpowers return res; 599f9fbec18Smcpowers 600f9fbec18Smcpowers res = s_mp_div_d(&qp, d, &rem); 601f9fbec18Smcpowers 602f9fbec18Smcpowers if(s_mp_cmp_d(&qp, 0) == 0) 603f9fbec18Smcpowers SIGN(q) = ZPOS; 604f9fbec18Smcpowers 605f9fbec18Smcpowers if(r) 606f9fbec18Smcpowers *r = rem; 607f9fbec18Smcpowers 608f9fbec18Smcpowers if(q) 609f9fbec18Smcpowers s_mp_exch(&qp, q); 610f9fbec18Smcpowers 611f9fbec18Smcpowers mp_clear(&qp); 612f9fbec18Smcpowers return res; 613f9fbec18Smcpowers 614f9fbec18Smcpowers } /* end mp_div_d() */ 615f9fbec18Smcpowers 616f9fbec18Smcpowers /* }}} */ 617f9fbec18Smcpowers 618f9fbec18Smcpowers /* {{{ mp_div_2(a, c) */ 619f9fbec18Smcpowers 620f9fbec18Smcpowers /* 621f9fbec18Smcpowers mp_div_2(a, c) 622f9fbec18Smcpowers 623f9fbec18Smcpowers Compute c = a / 2, disregarding the remainder. 624f9fbec18Smcpowers */ 625f9fbec18Smcpowers 626f9fbec18Smcpowers mp_err mp_div_2(const mp_int *a, mp_int *c) 627f9fbec18Smcpowers { 628f9fbec18Smcpowers mp_err res; 629f9fbec18Smcpowers 630f9fbec18Smcpowers ARGCHK(a != NULL && c != NULL, MP_BADARG); 631f9fbec18Smcpowers 632f9fbec18Smcpowers if((res = mp_copy(a, c)) != MP_OKAY) 633f9fbec18Smcpowers return res; 634f9fbec18Smcpowers 635f9fbec18Smcpowers s_mp_div_2(c); 636f9fbec18Smcpowers 637f9fbec18Smcpowers return MP_OKAY; 638f9fbec18Smcpowers 639f9fbec18Smcpowers } /* end mp_div_2() */ 640f9fbec18Smcpowers 641f9fbec18Smcpowers /* }}} */ 642f9fbec18Smcpowers 643f9fbec18Smcpowers /* {{{ mp_expt_d(a, d, b) */ 644f9fbec18Smcpowers 645f9fbec18Smcpowers mp_err mp_expt_d(const mp_int *a, mp_digit d, mp_int *c) 646f9fbec18Smcpowers { 647f9fbec18Smcpowers mp_int s, x; 648f9fbec18Smcpowers mp_err res; 649f9fbec18Smcpowers 650f9fbec18Smcpowers ARGCHK(a != NULL && c != NULL, MP_BADARG); 651f9fbec18Smcpowers 652f9fbec18Smcpowers if((res = mp_init(&s, FLAG(a))) != MP_OKAY) 653f9fbec18Smcpowers return res; 654f9fbec18Smcpowers if((res = mp_init_copy(&x, a)) != MP_OKAY) 655f9fbec18Smcpowers goto X; 656f9fbec18Smcpowers 657f9fbec18Smcpowers DIGIT(&s, 0) = 1; 658f9fbec18Smcpowers 659f9fbec18Smcpowers while(d != 0) { 660f9fbec18Smcpowers if(d & 1) { 661f9fbec18Smcpowers if((res = s_mp_mul(&s, &x)) != MP_OKAY) 662f9fbec18Smcpowers goto CLEANUP; 663f9fbec18Smcpowers } 664f9fbec18Smcpowers 665f9fbec18Smcpowers d /= 2; 666f9fbec18Smcpowers 667f9fbec18Smcpowers if((res = s_mp_sqr(&x)) != MP_OKAY) 668f9fbec18Smcpowers goto CLEANUP; 669f9fbec18Smcpowers } 670f9fbec18Smcpowers 671f9fbec18Smcpowers s_mp_exch(&s, c); 672f9fbec18Smcpowers 673f9fbec18Smcpowers CLEANUP: 674f9fbec18Smcpowers mp_clear(&x); 675f9fbec18Smcpowers X: 676f9fbec18Smcpowers mp_clear(&s); 677f9fbec18Smcpowers 678f9fbec18Smcpowers return res; 679f9fbec18Smcpowers 680f9fbec18Smcpowers } /* end mp_expt_d() */ 681f9fbec18Smcpowers 682f9fbec18Smcpowers /* }}} */ 683f9fbec18Smcpowers 684f9fbec18Smcpowers /* }}} */ 685f9fbec18Smcpowers 686f9fbec18Smcpowers /*------------------------------------------------------------------------*/ 687f9fbec18Smcpowers /* {{{ Full arithmetic */ 688f9fbec18Smcpowers 689f9fbec18Smcpowers /* {{{ mp_abs(a, b) */ 690f9fbec18Smcpowers 691f9fbec18Smcpowers /* 692f9fbec18Smcpowers mp_abs(a, b) 693f9fbec18Smcpowers 694f9fbec18Smcpowers Compute b = |a|. 'a' and 'b' may be identical. 695f9fbec18Smcpowers */ 696f9fbec18Smcpowers 697f9fbec18Smcpowers mp_err mp_abs(const mp_int *a, mp_int *b) 698f9fbec18Smcpowers { 699f9fbec18Smcpowers mp_err res; 700f9fbec18Smcpowers 701f9fbec18Smcpowers ARGCHK(a != NULL && b != NULL, MP_BADARG); 702f9fbec18Smcpowers 703f9fbec18Smcpowers if((res = mp_copy(a, b)) != MP_OKAY) 704f9fbec18Smcpowers return res; 705f9fbec18Smcpowers 706f9fbec18Smcpowers SIGN(b) = ZPOS; 707f9fbec18Smcpowers 708f9fbec18Smcpowers return MP_OKAY; 709f9fbec18Smcpowers 710f9fbec18Smcpowers } /* end mp_abs() */ 711f9fbec18Smcpowers 712f9fbec18Smcpowers /* }}} */ 713f9fbec18Smcpowers 714f9fbec18Smcpowers /* {{{ mp_neg(a, b) */ 715f9fbec18Smcpowers 716f9fbec18Smcpowers /* 717f9fbec18Smcpowers mp_neg(a, b) 718f9fbec18Smcpowers 719f9fbec18Smcpowers Compute b = -a. 'a' and 'b' may be identical. 720f9fbec18Smcpowers */ 721f9fbec18Smcpowers 722f9fbec18Smcpowers mp_err mp_neg(const mp_int *a, mp_int *b) 723f9fbec18Smcpowers { 724f9fbec18Smcpowers mp_err res; 725f9fbec18Smcpowers 726f9fbec18Smcpowers ARGCHK(a != NULL && b != NULL, MP_BADARG); 727f9fbec18Smcpowers 728f9fbec18Smcpowers if((res = mp_copy(a, b)) != MP_OKAY) 729f9fbec18Smcpowers return res; 730f9fbec18Smcpowers 731f9fbec18Smcpowers if(s_mp_cmp_d(b, 0) == MP_EQ) 732f9fbec18Smcpowers SIGN(b) = ZPOS; 733f9fbec18Smcpowers else 734f9fbec18Smcpowers SIGN(b) = (SIGN(b) == NEG) ? ZPOS : NEG; 735f9fbec18Smcpowers 736f9fbec18Smcpowers return MP_OKAY; 737f9fbec18Smcpowers 738f9fbec18Smcpowers } /* end mp_neg() */ 739f9fbec18Smcpowers 740f9fbec18Smcpowers /* }}} */ 741f9fbec18Smcpowers 742f9fbec18Smcpowers /* {{{ mp_add(a, b, c) */ 743f9fbec18Smcpowers 744f9fbec18Smcpowers /* 745f9fbec18Smcpowers mp_add(a, b, c) 746f9fbec18Smcpowers 747f9fbec18Smcpowers Compute c = a + b. All parameters may be identical. 748f9fbec18Smcpowers */ 749f9fbec18Smcpowers 750f9fbec18Smcpowers mp_err mp_add(const mp_int *a, const mp_int *b, mp_int *c) 751f9fbec18Smcpowers { 752f9fbec18Smcpowers mp_err res; 753f9fbec18Smcpowers 754f9fbec18Smcpowers ARGCHK(a != NULL && b != NULL && c != NULL, MP_BADARG); 755f9fbec18Smcpowers 756f9fbec18Smcpowers if(SIGN(a) == SIGN(b)) { /* same sign: add values, keep sign */ 757f9fbec18Smcpowers MP_CHECKOK( s_mp_add_3arg(a, b, c) ); 758f9fbec18Smcpowers } else if(s_mp_cmp(a, b) >= 0) { /* different sign: |a| >= |b| */ 759f9fbec18Smcpowers MP_CHECKOK( s_mp_sub_3arg(a, b, c) ); 760f9fbec18Smcpowers } else { /* different sign: |a| < |b| */ 761f9fbec18Smcpowers MP_CHECKOK( s_mp_sub_3arg(b, a, c) ); 762f9fbec18Smcpowers } 763f9fbec18Smcpowers 764f9fbec18Smcpowers if (s_mp_cmp_d(c, 0) == MP_EQ) 765f9fbec18Smcpowers SIGN(c) = ZPOS; 766f9fbec18Smcpowers 767f9fbec18Smcpowers CLEANUP: 768f9fbec18Smcpowers return res; 769f9fbec18Smcpowers 770f9fbec18Smcpowers } /* end mp_add() */ 771f9fbec18Smcpowers 772f9fbec18Smcpowers /* }}} */ 773f9fbec18Smcpowers 774f9fbec18Smcpowers /* {{{ mp_sub(a, b, c) */ 775f9fbec18Smcpowers 776f9fbec18Smcpowers /* 777f9fbec18Smcpowers mp_sub(a, b, c) 778f9fbec18Smcpowers 779f9fbec18Smcpowers Compute c = a - b. All parameters may be identical. 780f9fbec18Smcpowers */ 781f9fbec18Smcpowers 782f9fbec18Smcpowers mp_err mp_sub(const mp_int *a, const mp_int *b, mp_int *c) 783f9fbec18Smcpowers { 784f9fbec18Smcpowers mp_err res; 785f9fbec18Smcpowers int magDiff; 786f9fbec18Smcpowers 787f9fbec18Smcpowers ARGCHK(a != NULL && b != NULL && c != NULL, MP_BADARG); 788f9fbec18Smcpowers 789f9fbec18Smcpowers if (a == b) { 790f9fbec18Smcpowers mp_zero(c); 791f9fbec18Smcpowers return MP_OKAY; 792f9fbec18Smcpowers } 793f9fbec18Smcpowers 794f9fbec18Smcpowers if (MP_SIGN(a) != MP_SIGN(b)) { 795f9fbec18Smcpowers MP_CHECKOK( s_mp_add_3arg(a, b, c) ); 796f9fbec18Smcpowers } else if (!(magDiff = s_mp_cmp(a, b))) { 797f9fbec18Smcpowers mp_zero(c); 798f9fbec18Smcpowers res = MP_OKAY; 799f9fbec18Smcpowers } else if (magDiff > 0) { 800f9fbec18Smcpowers MP_CHECKOK( s_mp_sub_3arg(a, b, c) ); 801f9fbec18Smcpowers } else { 802f9fbec18Smcpowers MP_CHECKOK( s_mp_sub_3arg(b, a, c) ); 803f9fbec18Smcpowers MP_SIGN(c) = !MP_SIGN(a); 804f9fbec18Smcpowers } 805f9fbec18Smcpowers 806f9fbec18Smcpowers if (s_mp_cmp_d(c, 0) == MP_EQ) 807f9fbec18Smcpowers MP_SIGN(c) = MP_ZPOS; 808f9fbec18Smcpowers 809f9fbec18Smcpowers CLEANUP: 810f9fbec18Smcpowers return res; 811f9fbec18Smcpowers 812f9fbec18Smcpowers } /* end mp_sub() */ 813f9fbec18Smcpowers 814f9fbec18Smcpowers /* }}} */ 815f9fbec18Smcpowers 816f9fbec18Smcpowers /* {{{ mp_mul(a, b, c) */ 817f9fbec18Smcpowers 818f9fbec18Smcpowers /* 819f9fbec18Smcpowers mp_mul(a, b, c) 820f9fbec18Smcpowers 821f9fbec18Smcpowers Compute c = a * b. All parameters may be identical. 822f9fbec18Smcpowers */ 823f9fbec18Smcpowers mp_err mp_mul(const mp_int *a, const mp_int *b, mp_int * c) 824f9fbec18Smcpowers { 825f9fbec18Smcpowers mp_digit *pb; 826f9fbec18Smcpowers mp_int tmp; 827f9fbec18Smcpowers mp_err res; 828f9fbec18Smcpowers mp_size ib; 829f9fbec18Smcpowers mp_size useda, usedb; 830f9fbec18Smcpowers 831f9fbec18Smcpowers ARGCHK(a != NULL && b != NULL && c != NULL, MP_BADARG); 832f9fbec18Smcpowers 833f9fbec18Smcpowers if (a == c) { 834f9fbec18Smcpowers if ((res = mp_init_copy(&tmp, a)) != MP_OKAY) 835f9fbec18Smcpowers return res; 836f9fbec18Smcpowers if (a == b) 837f9fbec18Smcpowers b = &tmp; 838f9fbec18Smcpowers a = &tmp; 839f9fbec18Smcpowers } else if (b == c) { 840f9fbec18Smcpowers if ((res = mp_init_copy(&tmp, b)) != MP_OKAY) 841f9fbec18Smcpowers return res; 842f9fbec18Smcpowers b = &tmp; 843f9fbec18Smcpowers } else { 844f9fbec18Smcpowers MP_DIGITS(&tmp) = 0; 845f9fbec18Smcpowers } 846f9fbec18Smcpowers 847f9fbec18Smcpowers if (MP_USED(a) < MP_USED(b)) { 848f9fbec18Smcpowers const mp_int *xch = b; /* switch a and b, to do fewer outer loops */ 849f9fbec18Smcpowers b = a; 850f9fbec18Smcpowers a = xch; 851f9fbec18Smcpowers } 852f9fbec18Smcpowers 853f9fbec18Smcpowers MP_USED(c) = 1; MP_DIGIT(c, 0) = 0; 854f9fbec18Smcpowers if((res = s_mp_pad(c, USED(a) + USED(b))) != MP_OKAY) 855f9fbec18Smcpowers goto CLEANUP; 856f9fbec18Smcpowers 857f9fbec18Smcpowers #ifdef NSS_USE_COMBA 858f9fbec18Smcpowers if ((MP_USED(a) == MP_USED(b)) && IS_POWER_OF_2(MP_USED(b))) { 859f9fbec18Smcpowers if (MP_USED(a) == 4) { 860f9fbec18Smcpowers s_mp_mul_comba_4(a, b, c); 861f9fbec18Smcpowers goto CLEANUP; 862f9fbec18Smcpowers } 863f9fbec18Smcpowers if (MP_USED(a) == 8) { 864f9fbec18Smcpowers s_mp_mul_comba_8(a, b, c); 865f9fbec18Smcpowers goto CLEANUP; 866f9fbec18Smcpowers } 867f9fbec18Smcpowers if (MP_USED(a) == 16) { 868f9fbec18Smcpowers s_mp_mul_comba_16(a, b, c); 869f9fbec18Smcpowers goto CLEANUP; 870f9fbec18Smcpowers } 871f9fbec18Smcpowers if (MP_USED(a) == 32) { 872f9fbec18Smcpowers s_mp_mul_comba_32(a, b, c); 873f9fbec18Smcpowers goto CLEANUP; 874f9fbec18Smcpowers } 875f9fbec18Smcpowers } 876f9fbec18Smcpowers #endif 877f9fbec18Smcpowers 878f9fbec18Smcpowers pb = MP_DIGITS(b); 879f9fbec18Smcpowers s_mpv_mul_d(MP_DIGITS(a), MP_USED(a), *pb++, MP_DIGITS(c)); 880f9fbec18Smcpowers 881f9fbec18Smcpowers /* Outer loop: Digits of b */ 882f9fbec18Smcpowers useda = MP_USED(a); 883f9fbec18Smcpowers usedb = MP_USED(b); 884f9fbec18Smcpowers for (ib = 1; ib < usedb; ib++) { 885f9fbec18Smcpowers mp_digit b_i = *pb++; 886f9fbec18Smcpowers 887f9fbec18Smcpowers /* Inner product: Digits of a */ 888f9fbec18Smcpowers if (b_i) 889f9fbec18Smcpowers s_mpv_mul_d_add(MP_DIGITS(a), useda, b_i, MP_DIGITS(c) + ib); 890f9fbec18Smcpowers else 891f9fbec18Smcpowers MP_DIGIT(c, ib + useda) = b_i; 892f9fbec18Smcpowers } 893f9fbec18Smcpowers 894f9fbec18Smcpowers s_mp_clamp(c); 895f9fbec18Smcpowers 896f9fbec18Smcpowers if(SIGN(a) == SIGN(b) || s_mp_cmp_d(c, 0) == MP_EQ) 897f9fbec18Smcpowers SIGN(c) = ZPOS; 898f9fbec18Smcpowers else 899f9fbec18Smcpowers SIGN(c) = NEG; 900f9fbec18Smcpowers 901f9fbec18Smcpowers CLEANUP: 902f9fbec18Smcpowers mp_clear(&tmp); 903f9fbec18Smcpowers return res; 904f9fbec18Smcpowers } /* end mp_mul() */ 905f9fbec18Smcpowers 906f9fbec18Smcpowers /* }}} */ 907f9fbec18Smcpowers 908f9fbec18Smcpowers /* {{{ mp_sqr(a, sqr) */ 909f9fbec18Smcpowers 910f9fbec18Smcpowers #if MP_SQUARE 911f9fbec18Smcpowers /* 912f9fbec18Smcpowers Computes the square of a. This can be done more 913f9fbec18Smcpowers efficiently than a general multiplication, because many of the 914f9fbec18Smcpowers computation steps are redundant when squaring. The inner product 915f9fbec18Smcpowers step is a bit more complicated, but we save a fair number of 916f9fbec18Smcpowers iterations of the multiplication loop. 917f9fbec18Smcpowers */ 918f9fbec18Smcpowers 919f9fbec18Smcpowers /* sqr = a^2; Caller provides both a and tmp; */ 920f9fbec18Smcpowers mp_err mp_sqr(const mp_int *a, mp_int *sqr) 921f9fbec18Smcpowers { 922f9fbec18Smcpowers mp_digit *pa; 923f9fbec18Smcpowers mp_digit d; 924f9fbec18Smcpowers mp_err res; 925f9fbec18Smcpowers mp_size ix; 926f9fbec18Smcpowers mp_int tmp; 927f9fbec18Smcpowers int count; 928f9fbec18Smcpowers 929f9fbec18Smcpowers ARGCHK(a != NULL && sqr != NULL, MP_BADARG); 930f9fbec18Smcpowers 931f9fbec18Smcpowers if (a == sqr) { 932f9fbec18Smcpowers if((res = mp_init_copy(&tmp, a)) != MP_OKAY) 933f9fbec18Smcpowers return res; 934f9fbec18Smcpowers a = &tmp; 935f9fbec18Smcpowers } else { 936f9fbec18Smcpowers DIGITS(&tmp) = 0; 937f9fbec18Smcpowers res = MP_OKAY; 938f9fbec18Smcpowers } 939f9fbec18Smcpowers 940f9fbec18Smcpowers ix = 2 * MP_USED(a); 941f9fbec18Smcpowers if (ix > MP_ALLOC(sqr)) { 942f9fbec18Smcpowers MP_USED(sqr) = 1; 943f9fbec18Smcpowers MP_CHECKOK( s_mp_grow(sqr, ix) ); 944f9fbec18Smcpowers } 945f9fbec18Smcpowers MP_USED(sqr) = ix; 946f9fbec18Smcpowers MP_DIGIT(sqr, 0) = 0; 947f9fbec18Smcpowers 948f9fbec18Smcpowers #ifdef NSS_USE_COMBA 949f9fbec18Smcpowers if (IS_POWER_OF_2(MP_USED(a))) { 950f9fbec18Smcpowers if (MP_USED(a) == 4) { 951f9fbec18Smcpowers s_mp_sqr_comba_4(a, sqr); 952f9fbec18Smcpowers goto CLEANUP; 953f9fbec18Smcpowers } 954f9fbec18Smcpowers if (MP_USED(a) == 8) { 955f9fbec18Smcpowers s_mp_sqr_comba_8(a, sqr); 956f9fbec18Smcpowers goto CLEANUP; 957f9fbec18Smcpowers } 958f9fbec18Smcpowers if (MP_USED(a) == 16) { 959f9fbec18Smcpowers s_mp_sqr_comba_16(a, sqr); 960f9fbec18Smcpowers goto CLEANUP; 961f9fbec18Smcpowers } 962f9fbec18Smcpowers if (MP_USED(a) == 32) { 963f9fbec18Smcpowers s_mp_sqr_comba_32(a, sqr); 964f9fbec18Smcpowers goto CLEANUP; 965f9fbec18Smcpowers } 966f9fbec18Smcpowers } 967f9fbec18Smcpowers #endif 968f9fbec18Smcpowers 969f9fbec18Smcpowers pa = MP_DIGITS(a); 970f9fbec18Smcpowers count = MP_USED(a) - 1; 971f9fbec18Smcpowers if (count > 0) { 972f9fbec18Smcpowers d = *pa++; 973f9fbec18Smcpowers s_mpv_mul_d(pa, count, d, MP_DIGITS(sqr) + 1); 974f9fbec18Smcpowers for (ix = 3; --count > 0; ix += 2) { 975f9fbec18Smcpowers d = *pa++; 976f9fbec18Smcpowers s_mpv_mul_d_add(pa, count, d, MP_DIGITS(sqr) + ix); 977f9fbec18Smcpowers } /* for(ix ...) */ 978f9fbec18Smcpowers MP_DIGIT(sqr, MP_USED(sqr)-1) = 0; /* above loop stopped short of this. */ 979f9fbec18Smcpowers 980f9fbec18Smcpowers /* now sqr *= 2 */ 981f9fbec18Smcpowers s_mp_mul_2(sqr); 982f9fbec18Smcpowers } else { 983f9fbec18Smcpowers MP_DIGIT(sqr, 1) = 0; 984f9fbec18Smcpowers } 985f9fbec18Smcpowers 986f9fbec18Smcpowers /* now add the squares of the digits of a to sqr. */ 987f9fbec18Smcpowers s_mpv_sqr_add_prop(MP_DIGITS(a), MP_USED(a), MP_DIGITS(sqr)); 988f9fbec18Smcpowers 989f9fbec18Smcpowers SIGN(sqr) = ZPOS; 990f9fbec18Smcpowers s_mp_clamp(sqr); 991f9fbec18Smcpowers 992f9fbec18Smcpowers CLEANUP: 993f9fbec18Smcpowers mp_clear(&tmp); 994f9fbec18Smcpowers return res; 995f9fbec18Smcpowers 996f9fbec18Smcpowers } /* end mp_sqr() */ 997f9fbec18Smcpowers #endif 998f9fbec18Smcpowers 999f9fbec18Smcpowers /* }}} */ 1000f9fbec18Smcpowers 1001f9fbec18Smcpowers /* {{{ mp_div(a, b, q, r) */ 1002f9fbec18Smcpowers 1003f9fbec18Smcpowers /* 1004f9fbec18Smcpowers mp_div(a, b, q, r) 1005f9fbec18Smcpowers 1006f9fbec18Smcpowers Compute q = a / b and r = a mod b. Input parameters may be re-used 1007f9fbec18Smcpowers as output parameters. If q or r is NULL, that portion of the 1008f9fbec18Smcpowers computation will be discarded (although it will still be computed) 1009f9fbec18Smcpowers */ 1010f9fbec18Smcpowers mp_err mp_div(const mp_int *a, const mp_int *b, mp_int *q, mp_int *r) 1011f9fbec18Smcpowers { 1012f9fbec18Smcpowers mp_err res; 1013f9fbec18Smcpowers mp_int *pQ, *pR; 1014f9fbec18Smcpowers mp_int qtmp, rtmp, btmp; 1015f9fbec18Smcpowers int cmp; 1016f9fbec18Smcpowers mp_sign signA; 1017f9fbec18Smcpowers mp_sign signB; 1018f9fbec18Smcpowers 1019f9fbec18Smcpowers ARGCHK(a != NULL && b != NULL, MP_BADARG); 1020f9fbec18Smcpowers 1021f9fbec18Smcpowers signA = MP_SIGN(a); 1022f9fbec18Smcpowers signB = MP_SIGN(b); 1023f9fbec18Smcpowers 1024f9fbec18Smcpowers if(mp_cmp_z(b) == MP_EQ) 1025f9fbec18Smcpowers return MP_RANGE; 1026f9fbec18Smcpowers 1027f9fbec18Smcpowers DIGITS(&qtmp) = 0; 1028f9fbec18Smcpowers DIGITS(&rtmp) = 0; 1029f9fbec18Smcpowers DIGITS(&btmp) = 0; 1030f9fbec18Smcpowers 1031f9fbec18Smcpowers /* Set up some temporaries... */ 1032f9fbec18Smcpowers if (!r || r == a || r == b) { 1033f9fbec18Smcpowers MP_CHECKOK( mp_init_copy(&rtmp, a) ); 1034f9fbec18Smcpowers pR = &rtmp; 1035f9fbec18Smcpowers } else { 1036f9fbec18Smcpowers MP_CHECKOK( mp_copy(a, r) ); 1037f9fbec18Smcpowers pR = r; 1038f9fbec18Smcpowers } 1039f9fbec18Smcpowers 1040f9fbec18Smcpowers if (!q || q == a || q == b) { 1041f9fbec18Smcpowers MP_CHECKOK( mp_init_size(&qtmp, MP_USED(a), FLAG(a)) ); 1042f9fbec18Smcpowers pQ = &qtmp; 1043f9fbec18Smcpowers } else { 1044f9fbec18Smcpowers MP_CHECKOK( s_mp_pad(q, MP_USED(a)) ); 1045f9fbec18Smcpowers pQ = q; 1046f9fbec18Smcpowers mp_zero(pQ); 1047f9fbec18Smcpowers } 1048f9fbec18Smcpowers 1049f9fbec18Smcpowers /* 1050f9fbec18Smcpowers If |a| <= |b|, we can compute the solution without division; 1051f9fbec18Smcpowers otherwise, we actually do the work required. 1052f9fbec18Smcpowers */ 1053f9fbec18Smcpowers if ((cmp = s_mp_cmp(a, b)) <= 0) { 1054f9fbec18Smcpowers if (cmp) { 1055f9fbec18Smcpowers /* r was set to a above. */ 1056f9fbec18Smcpowers mp_zero(pQ); 1057f9fbec18Smcpowers } else { 1058f9fbec18Smcpowers mp_set(pQ, 1); 1059f9fbec18Smcpowers mp_zero(pR); 1060f9fbec18Smcpowers } 1061f9fbec18Smcpowers } else { 1062f9fbec18Smcpowers MP_CHECKOK( mp_init_copy(&btmp, b) ); 1063f9fbec18Smcpowers MP_CHECKOK( s_mp_div(pR, &btmp, pQ) ); 1064f9fbec18Smcpowers } 1065f9fbec18Smcpowers 1066f9fbec18Smcpowers /* Compute the signs for the output */ 1067f9fbec18Smcpowers MP_SIGN(pR) = signA; /* Sr = Sa */ 1068f9fbec18Smcpowers /* Sq = ZPOS if Sa == Sb */ /* Sq = NEG if Sa != Sb */ 1069f9fbec18Smcpowers MP_SIGN(pQ) = (signA == signB) ? ZPOS : NEG; 1070f9fbec18Smcpowers 1071f9fbec18Smcpowers if(s_mp_cmp_d(pQ, 0) == MP_EQ) 1072f9fbec18Smcpowers SIGN(pQ) = ZPOS; 1073f9fbec18Smcpowers if(s_mp_cmp_d(pR, 0) == MP_EQ) 1074f9fbec18Smcpowers SIGN(pR) = ZPOS; 1075f9fbec18Smcpowers 1076f9fbec18Smcpowers /* Copy output, if it is needed */ 1077f9fbec18Smcpowers if(q && q != pQ) 1078f9fbec18Smcpowers s_mp_exch(pQ, q); 1079f9fbec18Smcpowers 1080f9fbec18Smcpowers if(r && r != pR) 1081f9fbec18Smcpowers s_mp_exch(pR, r); 1082f9fbec18Smcpowers 1083f9fbec18Smcpowers CLEANUP: 1084f9fbec18Smcpowers mp_clear(&btmp); 1085f9fbec18Smcpowers mp_clear(&rtmp); 1086f9fbec18Smcpowers mp_clear(&qtmp); 1087f9fbec18Smcpowers 1088f9fbec18Smcpowers return res; 1089f9fbec18Smcpowers 1090f9fbec18Smcpowers } /* end mp_div() */ 1091f9fbec18Smcpowers 1092f9fbec18Smcpowers /* }}} */ 1093f9fbec18Smcpowers 1094f9fbec18Smcpowers /* {{{ mp_div_2d(a, d, q, r) */ 1095f9fbec18Smcpowers 1096f9fbec18Smcpowers mp_err mp_div_2d(const mp_int *a, mp_digit d, mp_int *q, mp_int *r) 1097f9fbec18Smcpowers { 1098f9fbec18Smcpowers mp_err res; 1099f9fbec18Smcpowers 1100f9fbec18Smcpowers ARGCHK(a != NULL, MP_BADARG); 1101f9fbec18Smcpowers 1102f9fbec18Smcpowers if(q) { 1103f9fbec18Smcpowers if((res = mp_copy(a, q)) != MP_OKAY) 1104f9fbec18Smcpowers return res; 1105f9fbec18Smcpowers } 1106f9fbec18Smcpowers if(r) { 1107f9fbec18Smcpowers if((res = mp_copy(a, r)) != MP_OKAY) 1108f9fbec18Smcpowers return res; 1109f9fbec18Smcpowers } 1110f9fbec18Smcpowers if(q) { 1111f9fbec18Smcpowers s_mp_div_2d(q, d); 1112f9fbec18Smcpowers } 1113f9fbec18Smcpowers if(r) { 1114f9fbec18Smcpowers s_mp_mod_2d(r, d); 1115f9fbec18Smcpowers } 1116f9fbec18Smcpowers 1117f9fbec18Smcpowers return MP_OKAY; 1118f9fbec18Smcpowers 1119f9fbec18Smcpowers } /* end mp_div_2d() */ 1120f9fbec18Smcpowers 1121f9fbec18Smcpowers /* }}} */ 1122f9fbec18Smcpowers 1123f9fbec18Smcpowers /* {{{ mp_expt(a, b, c) */ 1124f9fbec18Smcpowers 1125f9fbec18Smcpowers /* 1126f9fbec18Smcpowers mp_expt(a, b, c) 1127f9fbec18Smcpowers 1128f9fbec18Smcpowers Compute c = a ** b, that is, raise a to the b power. Uses a 1129f9fbec18Smcpowers standard iterative square-and-multiply technique. 1130f9fbec18Smcpowers */ 1131f9fbec18Smcpowers 1132f9fbec18Smcpowers mp_err mp_expt(mp_int *a, mp_int *b, mp_int *c) 1133f9fbec18Smcpowers { 1134f9fbec18Smcpowers mp_int s, x; 1135f9fbec18Smcpowers mp_err res; 1136f9fbec18Smcpowers mp_digit d; 1137f9fbec18Smcpowers int dig, bit; 1138f9fbec18Smcpowers 1139f9fbec18Smcpowers ARGCHK(a != NULL && b != NULL && c != NULL, MP_BADARG); 1140f9fbec18Smcpowers 1141f9fbec18Smcpowers if(mp_cmp_z(b) < 0) 1142f9fbec18Smcpowers return MP_RANGE; 1143f9fbec18Smcpowers 1144f9fbec18Smcpowers if((res = mp_init(&s, FLAG(a))) != MP_OKAY) 1145f9fbec18Smcpowers return res; 1146f9fbec18Smcpowers 1147f9fbec18Smcpowers mp_set(&s, 1); 1148f9fbec18Smcpowers 1149f9fbec18Smcpowers if((res = mp_init_copy(&x, a)) != MP_OKAY) 1150f9fbec18Smcpowers goto X; 1151f9fbec18Smcpowers 1152f9fbec18Smcpowers /* Loop over low-order digits in ascending order */ 1153f9fbec18Smcpowers for(dig = 0; dig < (USED(b) - 1); dig++) { 1154f9fbec18Smcpowers d = DIGIT(b, dig); 1155f9fbec18Smcpowers 1156f9fbec18Smcpowers /* Loop over bits of each non-maximal digit */ 1157f9fbec18Smcpowers for(bit = 0; bit < DIGIT_BIT; bit++) { 1158f9fbec18Smcpowers if(d & 1) { 1159f9fbec18Smcpowers if((res = s_mp_mul(&s, &x)) != MP_OKAY) 1160f9fbec18Smcpowers goto CLEANUP; 1161f9fbec18Smcpowers } 1162f9fbec18Smcpowers 1163f9fbec18Smcpowers d >>= 1; 1164f9fbec18Smcpowers 1165f9fbec18Smcpowers if((res = s_mp_sqr(&x)) != MP_OKAY) 1166f9fbec18Smcpowers goto CLEANUP; 1167f9fbec18Smcpowers } 1168f9fbec18Smcpowers } 1169f9fbec18Smcpowers 1170f9fbec18Smcpowers /* Consider now the last digit... */ 1171f9fbec18Smcpowers d = DIGIT(b, dig); 1172f9fbec18Smcpowers 1173f9fbec18Smcpowers while(d) { 1174f9fbec18Smcpowers if(d & 1) { 1175f9fbec18Smcpowers if((res = s_mp_mul(&s, &x)) != MP_OKAY) 1176f9fbec18Smcpowers goto CLEANUP; 1177f9fbec18Smcpowers } 1178f9fbec18Smcpowers 1179f9fbec18Smcpowers d >>= 1; 1180f9fbec18Smcpowers 1181f9fbec18Smcpowers if((res = s_mp_sqr(&x)) != MP_OKAY) 1182f9fbec18Smcpowers goto CLEANUP; 1183f9fbec18Smcpowers } 1184f9fbec18Smcpowers 1185f9fbec18Smcpowers if(mp_iseven(b)) 1186f9fbec18Smcpowers SIGN(&s) = SIGN(a); 1187f9fbec18Smcpowers 1188f9fbec18Smcpowers res = mp_copy(&s, c); 1189f9fbec18Smcpowers 1190f9fbec18Smcpowers CLEANUP: 1191f9fbec18Smcpowers mp_clear(&x); 1192f9fbec18Smcpowers X: 1193f9fbec18Smcpowers mp_clear(&s); 1194f9fbec18Smcpowers 1195f9fbec18Smcpowers return res; 1196f9fbec18Smcpowers 1197f9fbec18Smcpowers } /* end mp_expt() */ 1198f9fbec18Smcpowers 1199f9fbec18Smcpowers /* }}} */ 1200f9fbec18Smcpowers 1201f9fbec18Smcpowers /* {{{ mp_2expt(a, k) */ 1202f9fbec18Smcpowers 1203f9fbec18Smcpowers /* Compute a = 2^k */ 1204f9fbec18Smcpowers 1205f9fbec18Smcpowers mp_err mp_2expt(mp_int *a, mp_digit k) 1206f9fbec18Smcpowers { 1207f9fbec18Smcpowers ARGCHK(a != NULL, MP_BADARG); 1208f9fbec18Smcpowers 1209f9fbec18Smcpowers return s_mp_2expt(a, k); 1210f9fbec18Smcpowers 1211f9fbec18Smcpowers } /* end mp_2expt() */ 1212f9fbec18Smcpowers 1213f9fbec18Smcpowers /* }}} */ 1214f9fbec18Smcpowers 1215f9fbec18Smcpowers /* {{{ mp_mod(a, m, c) */ 1216f9fbec18Smcpowers 1217f9fbec18Smcpowers /* 1218f9fbec18Smcpowers mp_mod(a, m, c) 1219f9fbec18Smcpowers 1220f9fbec18Smcpowers Compute c = a (mod m). Result will always be 0 <= c < m. 1221f9fbec18Smcpowers */ 1222f9fbec18Smcpowers 1223f9fbec18Smcpowers mp_err mp_mod(const mp_int *a, const mp_int *m, mp_int *c) 1224f9fbec18Smcpowers { 1225f9fbec18Smcpowers mp_err res; 1226f9fbec18Smcpowers int mag; 1227f9fbec18Smcpowers 1228f9fbec18Smcpowers ARGCHK(a != NULL && m != NULL && c != NULL, MP_BADARG); 1229f9fbec18Smcpowers 1230f9fbec18Smcpowers if(SIGN(m) == NEG) 1231f9fbec18Smcpowers return MP_RANGE; 1232f9fbec18Smcpowers 1233f9fbec18Smcpowers /* 1234f9fbec18Smcpowers If |a| > m, we need to divide to get the remainder and take the 1235f9fbec18Smcpowers absolute value. 1236f9fbec18Smcpowers 1237f9fbec18Smcpowers If |a| < m, we don't need to do any division, just copy and adjust 1238f9fbec18Smcpowers the sign (if a is negative). 1239f9fbec18Smcpowers 1240f9fbec18Smcpowers If |a| == m, we can simply set the result to zero. 1241f9fbec18Smcpowers 1242f9fbec18Smcpowers This order is intended to minimize the average path length of the 1243f9fbec18Smcpowers comparison chain on common workloads -- the most frequent cases are 1244f9fbec18Smcpowers that |a| != m, so we do those first. 1245f9fbec18Smcpowers */ 1246f9fbec18Smcpowers if((mag = s_mp_cmp(a, m)) > 0) { 1247f9fbec18Smcpowers if((res = mp_div(a, m, NULL, c)) != MP_OKAY) 1248f9fbec18Smcpowers return res; 1249f9fbec18Smcpowers 1250f9fbec18Smcpowers if(SIGN(c) == NEG) { 1251f9fbec18Smcpowers if((res = mp_add(c, m, c)) != MP_OKAY) 1252f9fbec18Smcpowers return res; 1253f9fbec18Smcpowers } 1254f9fbec18Smcpowers 1255f9fbec18Smcpowers } else if(mag < 0) { 1256f9fbec18Smcpowers if((res = mp_copy(a, c)) != MP_OKAY) 1257f9fbec18Smcpowers return res; 1258f9fbec18Smcpowers 1259f9fbec18Smcpowers if(mp_cmp_z(a) < 0) { 1260f9fbec18Smcpowers if((res = mp_add(c, m, c)) != MP_OKAY) 1261f9fbec18Smcpowers return res; 1262f9fbec18Smcpowers 1263f9fbec18Smcpowers } 1264f9fbec18Smcpowers 1265f9fbec18Smcpowers } else { 1266f9fbec18Smcpowers mp_zero(c); 1267f9fbec18Smcpowers 1268f9fbec18Smcpowers } 1269f9fbec18Smcpowers 1270f9fbec18Smcpowers return MP_OKAY; 1271f9fbec18Smcpowers 1272f9fbec18Smcpowers } /* end mp_mod() */ 1273f9fbec18Smcpowers 1274f9fbec18Smcpowers /* }}} */ 1275f9fbec18Smcpowers 1276f9fbec18Smcpowers /* {{{ mp_mod_d(a, d, c) */ 1277f9fbec18Smcpowers 1278f9fbec18Smcpowers /* 1279f9fbec18Smcpowers mp_mod_d(a, d, c) 1280f9fbec18Smcpowers 1281f9fbec18Smcpowers Compute c = a (mod d). Result will always be 0 <= c < d 1282f9fbec18Smcpowers */ 1283f9fbec18Smcpowers mp_err mp_mod_d(const mp_int *a, mp_digit d, mp_digit *c) 1284f9fbec18Smcpowers { 1285f9fbec18Smcpowers mp_err res; 1286f9fbec18Smcpowers mp_digit rem; 1287f9fbec18Smcpowers 1288f9fbec18Smcpowers ARGCHK(a != NULL && c != NULL, MP_BADARG); 1289f9fbec18Smcpowers 1290f9fbec18Smcpowers if(s_mp_cmp_d(a, d) > 0) { 1291f9fbec18Smcpowers if((res = mp_div_d(a, d, NULL, &rem)) != MP_OKAY) 1292f9fbec18Smcpowers return res; 1293f9fbec18Smcpowers 1294f9fbec18Smcpowers } else { 1295f9fbec18Smcpowers if(SIGN(a) == NEG) 1296f9fbec18Smcpowers rem = d - DIGIT(a, 0); 1297f9fbec18Smcpowers else 1298f9fbec18Smcpowers rem = DIGIT(a, 0); 1299f9fbec18Smcpowers } 1300f9fbec18Smcpowers 1301f9fbec18Smcpowers if(c) 1302f9fbec18Smcpowers *c = rem; 1303f9fbec18Smcpowers 1304f9fbec18Smcpowers return MP_OKAY; 1305f9fbec18Smcpowers 1306f9fbec18Smcpowers } /* end mp_mod_d() */ 1307f9fbec18Smcpowers 1308f9fbec18Smcpowers /* }}} */ 1309f9fbec18Smcpowers 1310f9fbec18Smcpowers /* {{{ mp_sqrt(a, b) */ 1311f9fbec18Smcpowers 1312f9fbec18Smcpowers /* 1313f9fbec18Smcpowers mp_sqrt(a, b) 1314f9fbec18Smcpowers 1315f9fbec18Smcpowers Compute the integer square root of a, and store the result in b. 1316f9fbec18Smcpowers Uses an integer-arithmetic version of Newton's iterative linear 1317f9fbec18Smcpowers approximation technique to determine this value; the result has the 1318f9fbec18Smcpowers following two properties: 1319f9fbec18Smcpowers 1320f9fbec18Smcpowers b^2 <= a 1321f9fbec18Smcpowers (b+1)^2 >= a 1322f9fbec18Smcpowers 1323f9fbec18Smcpowers It is a range error to pass a negative value. 1324f9fbec18Smcpowers */ 1325f9fbec18Smcpowers mp_err mp_sqrt(const mp_int *a, mp_int *b) 1326f9fbec18Smcpowers { 1327f9fbec18Smcpowers mp_int x, t; 1328f9fbec18Smcpowers mp_err res; 1329f9fbec18Smcpowers mp_size used; 1330f9fbec18Smcpowers 1331f9fbec18Smcpowers ARGCHK(a != NULL && b != NULL, MP_BADARG); 1332f9fbec18Smcpowers 1333f9fbec18Smcpowers /* Cannot take square root of a negative value */ 1334f9fbec18Smcpowers if(SIGN(a) == NEG) 1335f9fbec18Smcpowers return MP_RANGE; 1336f9fbec18Smcpowers 1337f9fbec18Smcpowers /* Special cases for zero and one, trivial */ 1338f9fbec18Smcpowers if(mp_cmp_d(a, 1) <= 0) 1339f9fbec18Smcpowers return mp_copy(a, b); 1340f9fbec18Smcpowers 1341f9fbec18Smcpowers /* Initialize the temporaries we'll use below */ 1342f9fbec18Smcpowers if((res = mp_init_size(&t, USED(a), FLAG(a))) != MP_OKAY) 1343f9fbec18Smcpowers return res; 1344f9fbec18Smcpowers 1345f9fbec18Smcpowers /* Compute an initial guess for the iteration as a itself */ 1346f9fbec18Smcpowers if((res = mp_init_copy(&x, a)) != MP_OKAY) 1347f9fbec18Smcpowers goto X; 1348f9fbec18Smcpowers 1349f9fbec18Smcpowers used = MP_USED(&x); 1350f9fbec18Smcpowers if (used > 1) { 1351f9fbec18Smcpowers s_mp_rshd(&x, used / 2); 1352f9fbec18Smcpowers } 1353f9fbec18Smcpowers 1354f9fbec18Smcpowers for(;;) { 1355f9fbec18Smcpowers /* t = (x * x) - a */ 1356f9fbec18Smcpowers mp_copy(&x, &t); /* can't fail, t is big enough for original x */ 1357f9fbec18Smcpowers if((res = mp_sqr(&t, &t)) != MP_OKAY || 1358f9fbec18Smcpowers (res = mp_sub(&t, a, &t)) != MP_OKAY) 1359f9fbec18Smcpowers goto CLEANUP; 1360f9fbec18Smcpowers 1361f9fbec18Smcpowers /* t = t / 2x */ 1362f9fbec18Smcpowers s_mp_mul_2(&x); 1363f9fbec18Smcpowers if((res = mp_div(&t, &x, &t, NULL)) != MP_OKAY) 1364f9fbec18Smcpowers goto CLEANUP; 1365f9fbec18Smcpowers s_mp_div_2(&x); 1366f9fbec18Smcpowers 1367f9fbec18Smcpowers /* Terminate the loop, if the quotient is zero */ 1368f9fbec18Smcpowers if(mp_cmp_z(&t) == MP_EQ) 1369f9fbec18Smcpowers break; 1370f9fbec18Smcpowers 1371f9fbec18Smcpowers /* x = x - t */ 1372f9fbec18Smcpowers if((res = mp_sub(&x, &t, &x)) != MP_OKAY) 1373f9fbec18Smcpowers goto CLEANUP; 1374f9fbec18Smcpowers 1375f9fbec18Smcpowers } 1376f9fbec18Smcpowers 1377f9fbec18Smcpowers /* Copy result to output parameter */ 1378f9fbec18Smcpowers mp_sub_d(&x, 1, &x); 1379f9fbec18Smcpowers s_mp_exch(&x, b); 1380f9fbec18Smcpowers 1381f9fbec18Smcpowers CLEANUP: 1382f9fbec18Smcpowers mp_clear(&x); 1383f9fbec18Smcpowers X: 1384f9fbec18Smcpowers mp_clear(&t); 1385f9fbec18Smcpowers 1386f9fbec18Smcpowers return res; 1387f9fbec18Smcpowers 1388f9fbec18Smcpowers } /* end mp_sqrt() */ 1389f9fbec18Smcpowers 1390f9fbec18Smcpowers /* }}} */ 1391f9fbec18Smcpowers 1392f9fbec18Smcpowers /* }}} */ 1393f9fbec18Smcpowers 1394f9fbec18Smcpowers /*------------------------------------------------------------------------*/ 1395f9fbec18Smcpowers /* {{{ Modular arithmetic */ 1396f9fbec18Smcpowers 1397f9fbec18Smcpowers #if MP_MODARITH 1398f9fbec18Smcpowers /* {{{ mp_addmod(a, b, m, c) */ 1399f9fbec18Smcpowers 1400f9fbec18Smcpowers /* 1401f9fbec18Smcpowers mp_addmod(a, b, m, c) 1402f9fbec18Smcpowers 1403f9fbec18Smcpowers Compute c = (a + b) mod m 1404f9fbec18Smcpowers */ 1405f9fbec18Smcpowers 1406f9fbec18Smcpowers mp_err mp_addmod(const mp_int *a, const mp_int *b, const mp_int *m, mp_int *c) 1407f9fbec18Smcpowers { 1408f9fbec18Smcpowers mp_err res; 1409f9fbec18Smcpowers 1410f9fbec18Smcpowers ARGCHK(a != NULL && b != NULL && m != NULL && c != NULL, MP_BADARG); 1411f9fbec18Smcpowers 1412f9fbec18Smcpowers if((res = mp_add(a, b, c)) != MP_OKAY) 1413f9fbec18Smcpowers return res; 1414f9fbec18Smcpowers if((res = mp_mod(c, m, c)) != MP_OKAY) 1415f9fbec18Smcpowers return res; 1416f9fbec18Smcpowers 1417f9fbec18Smcpowers return MP_OKAY; 1418f9fbec18Smcpowers 1419f9fbec18Smcpowers } 1420f9fbec18Smcpowers 1421f9fbec18Smcpowers /* }}} */ 1422f9fbec18Smcpowers 1423f9fbec18Smcpowers /* {{{ mp_submod(a, b, m, c) */ 1424f9fbec18Smcpowers 1425f9fbec18Smcpowers /* 1426f9fbec18Smcpowers mp_submod(a, b, m, c) 1427f9fbec18Smcpowers 1428f9fbec18Smcpowers Compute c = (a - b) mod m 1429f9fbec18Smcpowers */ 1430f9fbec18Smcpowers 1431f9fbec18Smcpowers mp_err mp_submod(const mp_int *a, const mp_int *b, const mp_int *m, mp_int *c) 1432f9fbec18Smcpowers { 1433f9fbec18Smcpowers mp_err res; 1434f9fbec18Smcpowers 1435f9fbec18Smcpowers ARGCHK(a != NULL && b != NULL && m != NULL && c != NULL, MP_BADARG); 1436f9fbec18Smcpowers 1437f9fbec18Smcpowers if((res = mp_sub(a, b, c)) != MP_OKAY) 1438f9fbec18Smcpowers return res; 1439f9fbec18Smcpowers if((res = mp_mod(c, m, c)) != MP_OKAY) 1440f9fbec18Smcpowers return res; 1441f9fbec18Smcpowers 1442f9fbec18Smcpowers return MP_OKAY; 1443f9fbec18Smcpowers 1444f9fbec18Smcpowers } 1445f9fbec18Smcpowers 1446f9fbec18Smcpowers /* }}} */ 1447f9fbec18Smcpowers 1448f9fbec18Smcpowers /* {{{ mp_mulmod(a, b, m, c) */ 1449f9fbec18Smcpowers 1450f9fbec18Smcpowers /* 1451f9fbec18Smcpowers mp_mulmod(a, b, m, c) 1452f9fbec18Smcpowers 1453f9fbec18Smcpowers Compute c = (a * b) mod m 1454f9fbec18Smcpowers */ 1455f9fbec18Smcpowers 1456f9fbec18Smcpowers mp_err mp_mulmod(const mp_int *a, const mp_int *b, const mp_int *m, mp_int *c) 1457f9fbec18Smcpowers { 1458f9fbec18Smcpowers mp_err res; 1459f9fbec18Smcpowers 1460f9fbec18Smcpowers ARGCHK(a != NULL && b != NULL && m != NULL && c != NULL, MP_BADARG); 1461f9fbec18Smcpowers 1462f9fbec18Smcpowers if((res = mp_mul(a, b, c)) != MP_OKAY) 1463f9fbec18Smcpowers return res; 1464f9fbec18Smcpowers if((res = mp_mod(c, m, c)) != MP_OKAY) 1465f9fbec18Smcpowers return res; 1466f9fbec18Smcpowers 1467f9fbec18Smcpowers return MP_OKAY; 1468f9fbec18Smcpowers 1469f9fbec18Smcpowers } 1470f9fbec18Smcpowers 1471f9fbec18Smcpowers /* }}} */ 1472f9fbec18Smcpowers 1473f9fbec18Smcpowers /* {{{ mp_sqrmod(a, m, c) */ 1474f9fbec18Smcpowers 1475f9fbec18Smcpowers #if MP_SQUARE 1476f9fbec18Smcpowers mp_err mp_sqrmod(const mp_int *a, const mp_int *m, mp_int *c) 1477f9fbec18Smcpowers { 1478f9fbec18Smcpowers mp_err res; 1479f9fbec18Smcpowers 1480f9fbec18Smcpowers ARGCHK(a != NULL && m != NULL && c != NULL, MP_BADARG); 1481f9fbec18Smcpowers 1482f9fbec18Smcpowers if((res = mp_sqr(a, c)) != MP_OKAY) 1483f9fbec18Smcpowers return res; 1484f9fbec18Smcpowers if((res = mp_mod(c, m, c)) != MP_OKAY) 1485f9fbec18Smcpowers return res; 1486f9fbec18Smcpowers 1487f9fbec18Smcpowers return MP_OKAY; 1488f9fbec18Smcpowers 1489f9fbec18Smcpowers } /* end mp_sqrmod() */ 1490f9fbec18Smcpowers #endif 1491f9fbec18Smcpowers 1492f9fbec18Smcpowers /* }}} */ 1493f9fbec18Smcpowers 1494f9fbec18Smcpowers /* {{{ s_mp_exptmod(a, b, m, c) */ 1495f9fbec18Smcpowers 1496f9fbec18Smcpowers /* 1497f9fbec18Smcpowers s_mp_exptmod(a, b, m, c) 1498f9fbec18Smcpowers 1499f9fbec18Smcpowers Compute c = (a ** b) mod m. Uses a standard square-and-multiply 1500f9fbec18Smcpowers method with modular reductions at each step. (This is basically the 1501f9fbec18Smcpowers same code as mp_expt(), except for the addition of the reductions) 1502f9fbec18Smcpowers 1503f9fbec18Smcpowers The modular reductions are done using Barrett's algorithm (see 1504f9fbec18Smcpowers s_mp_reduce() below for details) 1505f9fbec18Smcpowers */ 1506f9fbec18Smcpowers 1507f9fbec18Smcpowers mp_err s_mp_exptmod(const mp_int *a, const mp_int *b, const mp_int *m, mp_int *c) 1508f9fbec18Smcpowers { 1509f9fbec18Smcpowers mp_int s, x, mu; 1510f9fbec18Smcpowers mp_err res; 1511f9fbec18Smcpowers mp_digit d; 1512f9fbec18Smcpowers int dig, bit; 1513f9fbec18Smcpowers 1514f9fbec18Smcpowers ARGCHK(a != NULL && b != NULL && c != NULL, MP_BADARG); 1515f9fbec18Smcpowers 1516f9fbec18Smcpowers if(mp_cmp_z(b) < 0 || mp_cmp_z(m) <= 0) 1517f9fbec18Smcpowers return MP_RANGE; 1518f9fbec18Smcpowers 1519f9fbec18Smcpowers if((res = mp_init(&s, FLAG(a))) != MP_OKAY) 1520f9fbec18Smcpowers return res; 1521f9fbec18Smcpowers if((res = mp_init_copy(&x, a)) != MP_OKAY || 1522f9fbec18Smcpowers (res = mp_mod(&x, m, &x)) != MP_OKAY) 1523f9fbec18Smcpowers goto X; 1524f9fbec18Smcpowers if((res = mp_init(&mu, FLAG(a))) != MP_OKAY) 1525f9fbec18Smcpowers goto MU; 1526f9fbec18Smcpowers 1527f9fbec18Smcpowers mp_set(&s, 1); 1528f9fbec18Smcpowers 1529f9fbec18Smcpowers /* mu = b^2k / m */ 1530f9fbec18Smcpowers s_mp_add_d(&mu, 1); 1531f9fbec18Smcpowers s_mp_lshd(&mu, 2 * USED(m)); 1532f9fbec18Smcpowers if((res = mp_div(&mu, m, &mu, NULL)) != MP_OKAY) 1533f9fbec18Smcpowers goto CLEANUP; 1534f9fbec18Smcpowers 1535f9fbec18Smcpowers /* Loop over digits of b in ascending order, except highest order */ 1536f9fbec18Smcpowers for(dig = 0; dig < (USED(b) - 1); dig++) { 1537f9fbec18Smcpowers d = DIGIT(b, dig); 1538f9fbec18Smcpowers 1539f9fbec18Smcpowers /* Loop over the bits of the lower-order digits */ 1540f9fbec18Smcpowers for(bit = 0; bit < DIGIT_BIT; bit++) { 1541f9fbec18Smcpowers if(d & 1) { 1542f9fbec18Smcpowers if((res = s_mp_mul(&s, &x)) != MP_OKAY) 1543f9fbec18Smcpowers goto CLEANUP; 1544f9fbec18Smcpowers if((res = s_mp_reduce(&s, m, &mu)) != MP_OKAY) 1545f9fbec18Smcpowers goto CLEANUP; 1546f9fbec18Smcpowers } 1547f9fbec18Smcpowers 1548f9fbec18Smcpowers d >>= 1; 1549f9fbec18Smcpowers 1550f9fbec18Smcpowers if((res = s_mp_sqr(&x)) != MP_OKAY) 1551f9fbec18Smcpowers goto CLEANUP; 1552f9fbec18Smcpowers if((res = s_mp_reduce(&x, m, &mu)) != MP_OKAY) 1553f9fbec18Smcpowers goto CLEANUP; 1554f9fbec18Smcpowers } 1555f9fbec18Smcpowers } 1556f9fbec18Smcpowers 1557f9fbec18Smcpowers /* Now do the last digit... */ 1558f9fbec18Smcpowers d = DIGIT(b, dig); 1559f9fbec18Smcpowers 1560f9fbec18Smcpowers while(d) { 1561f9fbec18Smcpowers if(d & 1) { 1562f9fbec18Smcpowers if((res = s_mp_mul(&s, &x)) != MP_OKAY) 1563f9fbec18Smcpowers goto CLEANUP; 1564f9fbec18Smcpowers if((res = s_mp_reduce(&s, m, &mu)) != MP_OKAY) 1565f9fbec18Smcpowers goto CLEANUP; 1566f9fbec18Smcpowers } 1567f9fbec18Smcpowers 1568f9fbec18Smcpowers d >>= 1; 1569f9fbec18Smcpowers 1570f9fbec18Smcpowers if((res = s_mp_sqr(&x)) != MP_OKAY) 1571f9fbec18Smcpowers goto CLEANUP; 1572f9fbec18Smcpowers if((res = s_mp_reduce(&x, m, &mu)) != MP_OKAY) 1573f9fbec18Smcpowers goto CLEANUP; 1574f9fbec18Smcpowers } 1575f9fbec18Smcpowers 1576f9fbec18Smcpowers s_mp_exch(&s, c); 1577f9fbec18Smcpowers 1578f9fbec18Smcpowers CLEANUP: 1579f9fbec18Smcpowers mp_clear(&mu); 1580f9fbec18Smcpowers MU: 1581f9fbec18Smcpowers mp_clear(&x); 1582f9fbec18Smcpowers X: 1583f9fbec18Smcpowers mp_clear(&s); 1584f9fbec18Smcpowers 1585f9fbec18Smcpowers return res; 1586f9fbec18Smcpowers 1587f9fbec18Smcpowers } /* end s_mp_exptmod() */ 1588f9fbec18Smcpowers 1589f9fbec18Smcpowers /* }}} */ 1590f9fbec18Smcpowers 1591f9fbec18Smcpowers /* {{{ mp_exptmod_d(a, d, m, c) */ 1592f9fbec18Smcpowers 1593f9fbec18Smcpowers mp_err mp_exptmod_d(const mp_int *a, mp_digit d, const mp_int *m, mp_int *c) 1594f9fbec18Smcpowers { 1595f9fbec18Smcpowers mp_int s, x; 1596f9fbec18Smcpowers mp_err res; 1597f9fbec18Smcpowers 1598f9fbec18Smcpowers ARGCHK(a != NULL && c != NULL, MP_BADARG); 1599f9fbec18Smcpowers 1600f9fbec18Smcpowers if((res = mp_init(&s, FLAG(a))) != MP_OKAY) 1601f9fbec18Smcpowers return res; 1602f9fbec18Smcpowers if((res = mp_init_copy(&x, a)) != MP_OKAY) 1603f9fbec18Smcpowers goto X; 1604f9fbec18Smcpowers 1605f9fbec18Smcpowers mp_set(&s, 1); 1606f9fbec18Smcpowers 1607f9fbec18Smcpowers while(d != 0) { 1608f9fbec18Smcpowers if(d & 1) { 1609f9fbec18Smcpowers if((res = s_mp_mul(&s, &x)) != MP_OKAY || 1610f9fbec18Smcpowers (res = mp_mod(&s, m, &s)) != MP_OKAY) 1611f9fbec18Smcpowers goto CLEANUP; 1612f9fbec18Smcpowers } 1613f9fbec18Smcpowers 1614f9fbec18Smcpowers d /= 2; 1615f9fbec18Smcpowers 1616f9fbec18Smcpowers if((res = s_mp_sqr(&x)) != MP_OKAY || 1617f9fbec18Smcpowers (res = mp_mod(&x, m, &x)) != MP_OKAY) 1618f9fbec18Smcpowers goto CLEANUP; 1619f9fbec18Smcpowers } 1620f9fbec18Smcpowers 1621f9fbec18Smcpowers s_mp_exch(&s, c); 1622f9fbec18Smcpowers 1623f9fbec18Smcpowers CLEANUP: 1624f9fbec18Smcpowers mp_clear(&x); 1625f9fbec18Smcpowers X: 1626f9fbec18Smcpowers mp_clear(&s); 1627f9fbec18Smcpowers 1628f9fbec18Smcpowers return res; 1629f9fbec18Smcpowers 1630f9fbec18Smcpowers } /* end mp_exptmod_d() */ 1631f9fbec18Smcpowers 1632f9fbec18Smcpowers /* }}} */ 1633f9fbec18Smcpowers #endif /* if MP_MODARITH */ 1634f9fbec18Smcpowers 1635f9fbec18Smcpowers /* }}} */ 1636f9fbec18Smcpowers 1637f9fbec18Smcpowers /*------------------------------------------------------------------------*/ 1638f9fbec18Smcpowers /* {{{ Comparison functions */ 1639f9fbec18Smcpowers 1640f9fbec18Smcpowers /* {{{ mp_cmp_z(a) */ 1641f9fbec18Smcpowers 1642f9fbec18Smcpowers /* 1643f9fbec18Smcpowers mp_cmp_z(a) 1644f9fbec18Smcpowers 1645f9fbec18Smcpowers Compare a <=> 0. Returns <0 if a<0, 0 if a=0, >0 if a>0. 1646f9fbec18Smcpowers */ 1647f9fbec18Smcpowers 1648f9fbec18Smcpowers int mp_cmp_z(const mp_int *a) 1649f9fbec18Smcpowers { 1650f9fbec18Smcpowers if(SIGN(a) == NEG) 1651f9fbec18Smcpowers return MP_LT; 1652f9fbec18Smcpowers else if(USED(a) == 1 && DIGIT(a, 0) == 0) 1653f9fbec18Smcpowers return MP_EQ; 1654f9fbec18Smcpowers else 1655f9fbec18Smcpowers return MP_GT; 1656f9fbec18Smcpowers 1657f9fbec18Smcpowers } /* end mp_cmp_z() */ 1658f9fbec18Smcpowers 1659f9fbec18Smcpowers /* }}} */ 1660f9fbec18Smcpowers 1661f9fbec18Smcpowers /* {{{ mp_cmp_d(a, d) */ 1662f9fbec18Smcpowers 1663f9fbec18Smcpowers /* 1664f9fbec18Smcpowers mp_cmp_d(a, d) 1665f9fbec18Smcpowers 1666f9fbec18Smcpowers Compare a <=> d. Returns <0 if a<d, 0 if a=d, >0 if a>d 1667f9fbec18Smcpowers */ 1668f9fbec18Smcpowers 1669f9fbec18Smcpowers int mp_cmp_d(const mp_int *a, mp_digit d) 1670f9fbec18Smcpowers { 1671f9fbec18Smcpowers ARGCHK(a != NULL, MP_EQ); 1672f9fbec18Smcpowers 1673f9fbec18Smcpowers if(SIGN(a) == NEG) 1674f9fbec18Smcpowers return MP_LT; 1675f9fbec18Smcpowers 1676f9fbec18Smcpowers return s_mp_cmp_d(a, d); 1677f9fbec18Smcpowers 1678f9fbec18Smcpowers } /* end mp_cmp_d() */ 1679f9fbec18Smcpowers 1680f9fbec18Smcpowers /* }}} */ 1681f9fbec18Smcpowers 1682f9fbec18Smcpowers /* {{{ mp_cmp(a, b) */ 1683f9fbec18Smcpowers 1684f9fbec18Smcpowers int mp_cmp(const mp_int *a, const mp_int *b) 1685f9fbec18Smcpowers { 1686f9fbec18Smcpowers ARGCHK(a != NULL && b != NULL, MP_EQ); 1687f9fbec18Smcpowers 1688f9fbec18Smcpowers if(SIGN(a) == SIGN(b)) { 1689f9fbec18Smcpowers int mag; 1690f9fbec18Smcpowers 1691f9fbec18Smcpowers if((mag = s_mp_cmp(a, b)) == MP_EQ) 1692f9fbec18Smcpowers return MP_EQ; 1693f9fbec18Smcpowers 1694f9fbec18Smcpowers if(SIGN(a) == ZPOS) 1695f9fbec18Smcpowers return mag; 1696f9fbec18Smcpowers else 1697f9fbec18Smcpowers return -mag; 1698f9fbec18Smcpowers 1699f9fbec18Smcpowers } else if(SIGN(a) == ZPOS) { 1700f9fbec18Smcpowers return MP_GT; 1701f9fbec18Smcpowers } else { 1702f9fbec18Smcpowers return MP_LT; 1703f9fbec18Smcpowers } 1704f9fbec18Smcpowers 1705f9fbec18Smcpowers } /* end mp_cmp() */ 1706f9fbec18Smcpowers 1707f9fbec18Smcpowers /* }}} */ 1708f9fbec18Smcpowers 1709f9fbec18Smcpowers /* {{{ mp_cmp_mag(a, b) */ 1710f9fbec18Smcpowers 1711f9fbec18Smcpowers /* 1712f9fbec18Smcpowers mp_cmp_mag(a, b) 1713f9fbec18Smcpowers 1714f9fbec18Smcpowers Compares |a| <=> |b|, and returns an appropriate comparison result 1715f9fbec18Smcpowers */ 1716f9fbec18Smcpowers 1717f9fbec18Smcpowers int mp_cmp_mag(mp_int *a, mp_int *b) 1718f9fbec18Smcpowers { 1719f9fbec18Smcpowers ARGCHK(a != NULL && b != NULL, MP_EQ); 1720f9fbec18Smcpowers 1721f9fbec18Smcpowers return s_mp_cmp(a, b); 1722f9fbec18Smcpowers 1723f9fbec18Smcpowers } /* end mp_cmp_mag() */ 1724f9fbec18Smcpowers 1725f9fbec18Smcpowers /* }}} */ 1726f9fbec18Smcpowers 1727f9fbec18Smcpowers /* {{{ mp_cmp_int(a, z, kmflag) */ 1728f9fbec18Smcpowers 1729f9fbec18Smcpowers /* 1730f9fbec18Smcpowers This just converts z to an mp_int, and uses the existing comparison 1731f9fbec18Smcpowers routines. This is sort of inefficient, but it's not clear to me how 1732f9fbec18Smcpowers frequently this wil get used anyway. For small positive constants, 1733f9fbec18Smcpowers you can always use mp_cmp_d(), and for zero, there is mp_cmp_z(). 1734f9fbec18Smcpowers */ 1735f9fbec18Smcpowers int mp_cmp_int(const mp_int *a, long z, int kmflag) 1736f9fbec18Smcpowers { 1737f9fbec18Smcpowers mp_int tmp; 1738f9fbec18Smcpowers int out; 1739f9fbec18Smcpowers 1740f9fbec18Smcpowers ARGCHK(a != NULL, MP_EQ); 1741f9fbec18Smcpowers 1742f9fbec18Smcpowers mp_init(&tmp, kmflag); mp_set_int(&tmp, z); 1743f9fbec18Smcpowers out = mp_cmp(a, &tmp); 1744f9fbec18Smcpowers mp_clear(&tmp); 1745f9fbec18Smcpowers 1746f9fbec18Smcpowers return out; 1747f9fbec18Smcpowers 1748f9fbec18Smcpowers } /* end mp_cmp_int() */ 1749f9fbec18Smcpowers 1750f9fbec18Smcpowers /* }}} */ 1751f9fbec18Smcpowers 1752f9fbec18Smcpowers /* {{{ mp_isodd(a) */ 1753f9fbec18Smcpowers 1754f9fbec18Smcpowers /* 1755f9fbec18Smcpowers mp_isodd(a) 1756f9fbec18Smcpowers 1757f9fbec18Smcpowers Returns a true (non-zero) value if a is odd, false (zero) otherwise. 1758f9fbec18Smcpowers */ 1759f9fbec18Smcpowers int mp_isodd(const mp_int *a) 1760f9fbec18Smcpowers { 1761f9fbec18Smcpowers ARGCHK(a != NULL, 0); 1762f9fbec18Smcpowers 1763f9fbec18Smcpowers return (int)(DIGIT(a, 0) & 1); 1764f9fbec18Smcpowers 1765f9fbec18Smcpowers } /* end mp_isodd() */ 1766f9fbec18Smcpowers 1767f9fbec18Smcpowers /* }}} */ 1768f9fbec18Smcpowers 1769f9fbec18Smcpowers /* {{{ mp_iseven(a) */ 1770f9fbec18Smcpowers 1771f9fbec18Smcpowers int mp_iseven(const mp_int *a) 1772f9fbec18Smcpowers { 1773f9fbec18Smcpowers return !mp_isodd(a); 1774f9fbec18Smcpowers 1775f9fbec18Smcpowers } /* end mp_iseven() */ 1776f9fbec18Smcpowers 1777f9fbec18Smcpowers /* }}} */ 1778f9fbec18Smcpowers 1779f9fbec18Smcpowers /* }}} */ 1780f9fbec18Smcpowers 1781f9fbec18Smcpowers /*------------------------------------------------------------------------*/ 1782f9fbec18Smcpowers /* {{{ Number theoretic functions */ 1783f9fbec18Smcpowers 1784f9fbec18Smcpowers #if MP_NUMTH 1785f9fbec18Smcpowers /* {{{ mp_gcd(a, b, c) */ 1786f9fbec18Smcpowers 1787f9fbec18Smcpowers /* 1788f9fbec18Smcpowers Like the old mp_gcd() function, except computes the GCD using the 1789f9fbec18Smcpowers binary algorithm due to Josef Stein in 1961 (via Knuth). 1790f9fbec18Smcpowers */ 1791f9fbec18Smcpowers mp_err mp_gcd(mp_int *a, mp_int *b, mp_int *c) 1792f9fbec18Smcpowers { 1793f9fbec18Smcpowers mp_err res; 1794f9fbec18Smcpowers mp_int u, v, t; 1795f9fbec18Smcpowers mp_size k = 0; 1796f9fbec18Smcpowers 1797f9fbec18Smcpowers ARGCHK(a != NULL && b != NULL && c != NULL, MP_BADARG); 1798f9fbec18Smcpowers 1799f9fbec18Smcpowers if(mp_cmp_z(a) == MP_EQ && mp_cmp_z(b) == MP_EQ) 1800f9fbec18Smcpowers return MP_RANGE; 1801f9fbec18Smcpowers if(mp_cmp_z(a) == MP_EQ) { 1802f9fbec18Smcpowers return mp_copy(b, c); 1803f9fbec18Smcpowers } else if(mp_cmp_z(b) == MP_EQ) { 1804f9fbec18Smcpowers return mp_copy(a, c); 1805f9fbec18Smcpowers } 1806f9fbec18Smcpowers 1807f9fbec18Smcpowers if((res = mp_init(&t, FLAG(a))) != MP_OKAY) 1808f9fbec18Smcpowers return res; 1809f9fbec18Smcpowers if((res = mp_init_copy(&u, a)) != MP_OKAY) 1810f9fbec18Smcpowers goto U; 1811f9fbec18Smcpowers if((res = mp_init_copy(&v, b)) != MP_OKAY) 1812f9fbec18Smcpowers goto V; 1813f9fbec18Smcpowers 1814f9fbec18Smcpowers SIGN(&u) = ZPOS; 1815f9fbec18Smcpowers SIGN(&v) = ZPOS; 1816f9fbec18Smcpowers 1817f9fbec18Smcpowers /* Divide out common factors of 2 until at least 1 of a, b is even */ 1818f9fbec18Smcpowers while(mp_iseven(&u) && mp_iseven(&v)) { 1819f9fbec18Smcpowers s_mp_div_2(&u); 1820f9fbec18Smcpowers s_mp_div_2(&v); 1821f9fbec18Smcpowers ++k; 1822f9fbec18Smcpowers } 1823f9fbec18Smcpowers 1824f9fbec18Smcpowers /* Initialize t */ 1825f9fbec18Smcpowers if(mp_isodd(&u)) { 1826f9fbec18Smcpowers if((res = mp_copy(&v, &t)) != MP_OKAY) 1827f9fbec18Smcpowers goto CLEANUP; 1828f9fbec18Smcpowers 1829f9fbec18Smcpowers /* t = -v */ 1830f9fbec18Smcpowers if(SIGN(&v) == ZPOS) 1831f9fbec18Smcpowers SIGN(&t) = NEG; 1832f9fbec18Smcpowers else 1833f9fbec18Smcpowers SIGN(&t) = ZPOS; 1834f9fbec18Smcpowers 1835f9fbec18Smcpowers } else { 1836f9fbec18Smcpowers if((res = mp_copy(&u, &t)) != MP_OKAY) 1837f9fbec18Smcpowers goto CLEANUP; 1838f9fbec18Smcpowers 1839f9fbec18Smcpowers } 1840f9fbec18Smcpowers 1841f9fbec18Smcpowers for(;;) { 1842f9fbec18Smcpowers while(mp_iseven(&t)) { 1843f9fbec18Smcpowers s_mp_div_2(&t); 1844f9fbec18Smcpowers } 1845f9fbec18Smcpowers 1846f9fbec18Smcpowers if(mp_cmp_z(&t) == MP_GT) { 1847f9fbec18Smcpowers if((res = mp_copy(&t, &u)) != MP_OKAY) 1848f9fbec18Smcpowers goto CLEANUP; 1849f9fbec18Smcpowers 1850f9fbec18Smcpowers } else { 1851f9fbec18Smcpowers if((res = mp_copy(&t, &v)) != MP_OKAY) 1852f9fbec18Smcpowers goto CLEANUP; 1853f9fbec18Smcpowers 1854f9fbec18Smcpowers /* v = -t */ 1855f9fbec18Smcpowers if(SIGN(&t) == ZPOS) 1856f9fbec18Smcpowers SIGN(&v) = NEG; 1857f9fbec18Smcpowers else 1858f9fbec18Smcpowers SIGN(&v) = ZPOS; 1859f9fbec18Smcpowers } 1860f9fbec18Smcpowers 1861f9fbec18Smcpowers if((res = mp_sub(&u, &v, &t)) != MP_OKAY) 1862f9fbec18Smcpowers goto CLEANUP; 1863f9fbec18Smcpowers 1864f9fbec18Smcpowers if(s_mp_cmp_d(&t, 0) == MP_EQ) 1865f9fbec18Smcpowers break; 1866f9fbec18Smcpowers } 1867f9fbec18Smcpowers 1868f9fbec18Smcpowers s_mp_2expt(&v, k); /* v = 2^k */ 1869f9fbec18Smcpowers res = mp_mul(&u, &v, c); /* c = u * v */ 1870f9fbec18Smcpowers 1871f9fbec18Smcpowers CLEANUP: 1872f9fbec18Smcpowers mp_clear(&v); 1873f9fbec18Smcpowers V: 1874f9fbec18Smcpowers mp_clear(&u); 1875f9fbec18Smcpowers U: 1876f9fbec18Smcpowers mp_clear(&t); 1877f9fbec18Smcpowers 1878f9fbec18Smcpowers return res; 1879f9fbec18Smcpowers 1880f9fbec18Smcpowers } /* end mp_gcd() */ 1881f9fbec18Smcpowers 1882f9fbec18Smcpowers /* }}} */ 1883f9fbec18Smcpowers 1884f9fbec18Smcpowers /* {{{ mp_lcm(a, b, c) */ 1885f9fbec18Smcpowers 1886f9fbec18Smcpowers /* We compute the least common multiple using the rule: 1887f9fbec18Smcpowers 1888f9fbec18Smcpowers ab = [a, b](a, b) 1889f9fbec18Smcpowers 1890f9fbec18Smcpowers ... by computing the product, and dividing out the gcd. 1891f9fbec18Smcpowers */ 1892f9fbec18Smcpowers 1893f9fbec18Smcpowers mp_err mp_lcm(mp_int *a, mp_int *b, mp_int *c) 1894f9fbec18Smcpowers { 1895f9fbec18Smcpowers mp_int gcd, prod; 1896f9fbec18Smcpowers mp_err res; 1897f9fbec18Smcpowers 1898f9fbec18Smcpowers ARGCHK(a != NULL && b != NULL && c != NULL, MP_BADARG); 1899f9fbec18Smcpowers 1900f9fbec18Smcpowers /* Set up temporaries */ 1901f9fbec18Smcpowers if((res = mp_init(&gcd, FLAG(a))) != MP_OKAY) 1902f9fbec18Smcpowers return res; 1903f9fbec18Smcpowers if((res = mp_init(&prod, FLAG(a))) != MP_OKAY) 1904f9fbec18Smcpowers goto GCD; 1905f9fbec18Smcpowers 1906f9fbec18Smcpowers if((res = mp_mul(a, b, &prod)) != MP_OKAY) 1907f9fbec18Smcpowers goto CLEANUP; 1908f9fbec18Smcpowers if((res = mp_gcd(a, b, &gcd)) != MP_OKAY) 1909f9fbec18Smcpowers goto CLEANUP; 1910f9fbec18Smcpowers 1911f9fbec18Smcpowers res = mp_div(&prod, &gcd, c, NULL); 1912f9fbec18Smcpowers 1913f9fbec18Smcpowers CLEANUP: 1914f9fbec18Smcpowers mp_clear(&prod); 1915f9fbec18Smcpowers GCD: 1916f9fbec18Smcpowers mp_clear(&gcd); 1917f9fbec18Smcpowers 1918f9fbec18Smcpowers return res; 1919f9fbec18Smcpowers 1920f9fbec18Smcpowers } /* end mp_lcm() */ 1921f9fbec18Smcpowers 1922f9fbec18Smcpowers /* }}} */ 1923f9fbec18Smcpowers 1924f9fbec18Smcpowers /* {{{ mp_xgcd(a, b, g, x, y) */ 1925f9fbec18Smcpowers 1926f9fbec18Smcpowers /* 1927f9fbec18Smcpowers mp_xgcd(a, b, g, x, y) 1928f9fbec18Smcpowers 1929f9fbec18Smcpowers Compute g = (a, b) and values x and y satisfying Bezout's identity 1930f9fbec18Smcpowers (that is, ax + by = g). This uses the binary extended GCD algorithm 1931f9fbec18Smcpowers based on the Stein algorithm used for mp_gcd() 1932f9fbec18Smcpowers See algorithm 14.61 in Handbook of Applied Cryptogrpahy. 1933f9fbec18Smcpowers */ 1934f9fbec18Smcpowers 1935f9fbec18Smcpowers mp_err mp_xgcd(const mp_int *a, const mp_int *b, mp_int *g, mp_int *x, mp_int *y) 1936f9fbec18Smcpowers { 1937f9fbec18Smcpowers mp_int gx, xc, yc, u, v, A, B, C, D; 1938f9fbec18Smcpowers mp_int *clean[9]; 1939f9fbec18Smcpowers mp_err res; 1940f9fbec18Smcpowers int last = -1; 1941f9fbec18Smcpowers 1942f9fbec18Smcpowers if(mp_cmp_z(b) == 0) 1943f9fbec18Smcpowers return MP_RANGE; 1944f9fbec18Smcpowers 1945f9fbec18Smcpowers /* Initialize all these variables we need */ 1946f9fbec18Smcpowers MP_CHECKOK( mp_init(&u, FLAG(a)) ); 1947f9fbec18Smcpowers clean[++last] = &u; 1948f9fbec18Smcpowers MP_CHECKOK( mp_init(&v, FLAG(a)) ); 1949f9fbec18Smcpowers clean[++last] = &v; 1950f9fbec18Smcpowers MP_CHECKOK( mp_init(&gx, FLAG(a)) ); 1951f9fbec18Smcpowers clean[++last] = &gx; 1952f9fbec18Smcpowers MP_CHECKOK( mp_init(&A, FLAG(a)) ); 1953f9fbec18Smcpowers clean[++last] = &A; 1954f9fbec18Smcpowers MP_CHECKOK( mp_init(&B, FLAG(a)) ); 1955f9fbec18Smcpowers clean[++last] = &B; 1956f9fbec18Smcpowers MP_CHECKOK( mp_init(&C, FLAG(a)) ); 1957f9fbec18Smcpowers clean[++last] = &C; 1958f9fbec18Smcpowers MP_CHECKOK( mp_init(&D, FLAG(a)) ); 1959f9fbec18Smcpowers clean[++last] = &D; 1960f9fbec18Smcpowers MP_CHECKOK( mp_init_copy(&xc, a) ); 1961f9fbec18Smcpowers clean[++last] = &xc; 1962f9fbec18Smcpowers mp_abs(&xc, &xc); 1963f9fbec18Smcpowers MP_CHECKOK( mp_init_copy(&yc, b) ); 1964f9fbec18Smcpowers clean[++last] = &yc; 1965f9fbec18Smcpowers mp_abs(&yc, &yc); 1966f9fbec18Smcpowers 1967f9fbec18Smcpowers mp_set(&gx, 1); 1968f9fbec18Smcpowers 1969f9fbec18Smcpowers /* Divide by two until at least one of them is odd */ 1970f9fbec18Smcpowers while(mp_iseven(&xc) && mp_iseven(&yc)) { 1971f9fbec18Smcpowers mp_size nx = mp_trailing_zeros(&xc); 1972f9fbec18Smcpowers mp_size ny = mp_trailing_zeros(&yc); 1973f9fbec18Smcpowers mp_size n = MP_MIN(nx, ny); 1974f9fbec18Smcpowers s_mp_div_2d(&xc,n); 1975f9fbec18Smcpowers s_mp_div_2d(&yc,n); 1976f9fbec18Smcpowers MP_CHECKOK( s_mp_mul_2d(&gx,n) ); 1977f9fbec18Smcpowers } 1978f9fbec18Smcpowers 1979f9fbec18Smcpowers mp_copy(&xc, &u); 1980f9fbec18Smcpowers mp_copy(&yc, &v); 1981f9fbec18Smcpowers mp_set(&A, 1); mp_set(&D, 1); 1982f9fbec18Smcpowers 1983f9fbec18Smcpowers /* Loop through binary GCD algorithm */ 1984f9fbec18Smcpowers do { 1985f9fbec18Smcpowers while(mp_iseven(&u)) { 1986f9fbec18Smcpowers s_mp_div_2(&u); 1987f9fbec18Smcpowers 1988f9fbec18Smcpowers if(mp_iseven(&A) && mp_iseven(&B)) { 1989f9fbec18Smcpowers s_mp_div_2(&A); s_mp_div_2(&B); 1990f9fbec18Smcpowers } else { 1991f9fbec18Smcpowers MP_CHECKOK( mp_add(&A, &yc, &A) ); 1992f9fbec18Smcpowers s_mp_div_2(&A); 1993f9fbec18Smcpowers MP_CHECKOK( mp_sub(&B, &xc, &B) ); 1994f9fbec18Smcpowers s_mp_div_2(&B); 1995f9fbec18Smcpowers } 1996f9fbec18Smcpowers } 1997f9fbec18Smcpowers 1998f9fbec18Smcpowers while(mp_iseven(&v)) { 1999f9fbec18Smcpowers s_mp_div_2(&v); 2000f9fbec18Smcpowers 2001f9fbec18Smcpowers if(mp_iseven(&C) && mp_iseven(&D)) { 2002f9fbec18Smcpowers s_mp_div_2(&C); s_mp_div_2(&D); 2003f9fbec18Smcpowers } else { 2004f9fbec18Smcpowers MP_CHECKOK( mp_add(&C, &yc, &C) ); 2005f9fbec18Smcpowers s_mp_div_2(&C); 2006f9fbec18Smcpowers MP_CHECKOK( mp_sub(&D, &xc, &D) ); 2007f9fbec18Smcpowers s_mp_div_2(&D); 2008f9fbec18Smcpowers } 2009f9fbec18Smcpowers } 2010f9fbec18Smcpowers 2011f9fbec18Smcpowers if(mp_cmp(&u, &v) >= 0) { 2012f9fbec18Smcpowers MP_CHECKOK( mp_sub(&u, &v, &u) ); 2013f9fbec18Smcpowers MP_CHECKOK( mp_sub(&A, &C, &A) ); 2014f9fbec18Smcpowers MP_CHECKOK( mp_sub(&B, &D, &B) ); 2015f9fbec18Smcpowers } else { 2016f9fbec18Smcpowers MP_CHECKOK( mp_sub(&v, &u, &v) ); 2017f9fbec18Smcpowers MP_CHECKOK( mp_sub(&C, &A, &C) ); 2018f9fbec18Smcpowers MP_CHECKOK( mp_sub(&D, &B, &D) ); 2019f9fbec18Smcpowers } 2020f9fbec18Smcpowers } while (mp_cmp_z(&u) != 0); 2021f9fbec18Smcpowers 2022f9fbec18Smcpowers /* copy results to output */ 2023f9fbec18Smcpowers if(x) 2024f9fbec18Smcpowers MP_CHECKOK( mp_copy(&C, x) ); 2025f9fbec18Smcpowers 2026f9fbec18Smcpowers if(y) 2027f9fbec18Smcpowers MP_CHECKOK( mp_copy(&D, y) ); 2028f9fbec18Smcpowers 2029f9fbec18Smcpowers if(g) 2030f9fbec18Smcpowers MP_CHECKOK( mp_mul(&gx, &v, g) ); 2031f9fbec18Smcpowers 2032f9fbec18Smcpowers CLEANUP: 2033f9fbec18Smcpowers while(last >= 0) 2034f9fbec18Smcpowers mp_clear(clean[last--]); 2035f9fbec18Smcpowers 2036f9fbec18Smcpowers return res; 2037f9fbec18Smcpowers 2038f9fbec18Smcpowers } /* end mp_xgcd() */ 2039f9fbec18Smcpowers 2040f9fbec18Smcpowers /* }}} */ 2041f9fbec18Smcpowers 2042f9fbec18Smcpowers mp_size mp_trailing_zeros(const mp_int *mp) 2043f9fbec18Smcpowers { 2044f9fbec18Smcpowers mp_digit d; 2045f9fbec18Smcpowers mp_size n = 0; 2046f9fbec18Smcpowers int ix; 2047f9fbec18Smcpowers 2048f9fbec18Smcpowers if (!mp || !MP_DIGITS(mp) || !mp_cmp_z(mp)) 2049f9fbec18Smcpowers return n; 2050f9fbec18Smcpowers 2051f9fbec18Smcpowers for (ix = 0; !(d = MP_DIGIT(mp,ix)) && (ix < MP_USED(mp)); ++ix) 2052f9fbec18Smcpowers n += MP_DIGIT_BIT; 2053f9fbec18Smcpowers if (!d) 2054f9fbec18Smcpowers return 0; /* shouldn't happen, but ... */ 2055f9fbec18Smcpowers #if !defined(MP_USE_UINT_DIGIT) 2056f9fbec18Smcpowers if (!(d & 0xffffffffU)) { 2057f9fbec18Smcpowers d >>= 32; 2058f9fbec18Smcpowers n += 32; 2059f9fbec18Smcpowers } 2060f9fbec18Smcpowers #endif 2061f9fbec18Smcpowers if (!(d & 0xffffU)) { 2062f9fbec18Smcpowers d >>= 16; 2063f9fbec18Smcpowers n += 16; 2064f9fbec18Smcpowers } 2065f9fbec18Smcpowers if (!(d & 0xffU)) { 2066f9fbec18Smcpowers d >>= 8; 2067f9fbec18Smcpowers n += 8; 2068f9fbec18Smcpowers } 2069f9fbec18Smcpowers if (!(d & 0xfU)) { 2070f9fbec18Smcpowers d >>= 4; 2071f9fbec18Smcpowers n += 4; 2072f9fbec18Smcpowers } 2073f9fbec18Smcpowers if (!(d & 0x3U)) { 2074f9fbec18Smcpowers d >>= 2; 2075f9fbec18Smcpowers n += 2; 2076f9fbec18Smcpowers } 2077f9fbec18Smcpowers if (!(d & 0x1U)) { 2078f9fbec18Smcpowers d >>= 1; 2079f9fbec18Smcpowers n += 1; 2080f9fbec18Smcpowers } 2081f9fbec18Smcpowers #if MP_ARGCHK == 2 2082f9fbec18Smcpowers assert(0 != (d & 1)); 2083f9fbec18Smcpowers #endif 2084f9fbec18Smcpowers return n; 2085f9fbec18Smcpowers } 2086f9fbec18Smcpowers 2087f9fbec18Smcpowers /* Given a and prime p, computes c and k such that a*c == 2**k (mod p). 2088f9fbec18Smcpowers ** Returns k (positive) or error (negative). 2089f9fbec18Smcpowers ** This technique from the paper "Fast Modular Reciprocals" (unpublished) 2090f9fbec18Smcpowers ** by Richard Schroeppel (a.k.a. Captain Nemo). 2091f9fbec18Smcpowers */ 2092f9fbec18Smcpowers mp_err s_mp_almost_inverse(const mp_int *a, const mp_int *p, mp_int *c) 2093f9fbec18Smcpowers { 2094f9fbec18Smcpowers mp_err res; 2095f9fbec18Smcpowers mp_err k = 0; 2096f9fbec18Smcpowers mp_int d, f, g; 2097f9fbec18Smcpowers 2098f9fbec18Smcpowers ARGCHK(a && p && c, MP_BADARG); 2099f9fbec18Smcpowers 2100f9fbec18Smcpowers MP_DIGITS(&d) = 0; 2101f9fbec18Smcpowers MP_DIGITS(&f) = 0; 2102f9fbec18Smcpowers MP_DIGITS(&g) = 0; 2103f9fbec18Smcpowers MP_CHECKOK( mp_init(&d, FLAG(a)) ); 2104f9fbec18Smcpowers MP_CHECKOK( mp_init_copy(&f, a) ); /* f = a */ 2105f9fbec18Smcpowers MP_CHECKOK( mp_init_copy(&g, p) ); /* g = p */ 2106f9fbec18Smcpowers 2107f9fbec18Smcpowers mp_set(c, 1); 2108f9fbec18Smcpowers mp_zero(&d); 2109f9fbec18Smcpowers 2110f9fbec18Smcpowers if (mp_cmp_z(&f) == 0) { 2111f9fbec18Smcpowers res = MP_UNDEF; 2112f9fbec18Smcpowers } else 2113f9fbec18Smcpowers for (;;) { 2114f9fbec18Smcpowers int diff_sign; 2115f9fbec18Smcpowers while (mp_iseven(&f)) { 2116f9fbec18Smcpowers mp_size n = mp_trailing_zeros(&f); 2117f9fbec18Smcpowers if (!n) { 2118f9fbec18Smcpowers res = MP_UNDEF; 2119f9fbec18Smcpowers goto CLEANUP; 2120f9fbec18Smcpowers } 2121f9fbec18Smcpowers s_mp_div_2d(&f, n); 2122f9fbec18Smcpowers MP_CHECKOK( s_mp_mul_2d(&d, n) ); 2123f9fbec18Smcpowers k += n; 2124f9fbec18Smcpowers } 2125f9fbec18Smcpowers if (mp_cmp_d(&f, 1) == MP_EQ) { /* f == 1 */ 2126f9fbec18Smcpowers res = k; 2127f9fbec18Smcpowers break; 2128f9fbec18Smcpowers } 2129f9fbec18Smcpowers diff_sign = mp_cmp(&f, &g); 2130f9fbec18Smcpowers if (diff_sign < 0) { /* f < g */ 2131f9fbec18Smcpowers s_mp_exch(&f, &g); 2132f9fbec18Smcpowers s_mp_exch(c, &d); 2133f9fbec18Smcpowers } else if (diff_sign == 0) { /* f == g */ 2134f9fbec18Smcpowers res = MP_UNDEF; /* a and p are not relatively prime */ 2135f9fbec18Smcpowers break; 2136f9fbec18Smcpowers } 2137f9fbec18Smcpowers if ((MP_DIGIT(&f,0) % 4) == (MP_DIGIT(&g,0) % 4)) { 2138f9fbec18Smcpowers MP_CHECKOK( mp_sub(&f, &g, &f) ); /* f = f - g */ 2139f9fbec18Smcpowers MP_CHECKOK( mp_sub(c, &d, c) ); /* c = c - d */ 2140f9fbec18Smcpowers } else { 2141f9fbec18Smcpowers MP_CHECKOK( mp_add(&f, &g, &f) ); /* f = f + g */ 2142f9fbec18Smcpowers MP_CHECKOK( mp_add(c, &d, c) ); /* c = c + d */ 2143f9fbec18Smcpowers } 2144f9fbec18Smcpowers } 2145f9fbec18Smcpowers if (res >= 0) { 2146f9fbec18Smcpowers while (MP_SIGN(c) != MP_ZPOS) { 2147f9fbec18Smcpowers MP_CHECKOK( mp_add(c, p, c) ); 2148f9fbec18Smcpowers } 2149f9fbec18Smcpowers res = k; 2150f9fbec18Smcpowers } 2151f9fbec18Smcpowers 2152f9fbec18Smcpowers CLEANUP: 2153f9fbec18Smcpowers mp_clear(&d); 2154f9fbec18Smcpowers mp_clear(&f); 2155f9fbec18Smcpowers mp_clear(&g); 2156f9fbec18Smcpowers return res; 2157f9fbec18Smcpowers } 2158f9fbec18Smcpowers 2159f9fbec18Smcpowers /* Compute T = (P ** -1) mod MP_RADIX. Also works for 16-bit mp_digits. 2160f9fbec18Smcpowers ** This technique from the paper "Fast Modular Reciprocals" (unpublished) 2161f9fbec18Smcpowers ** by Richard Schroeppel (a.k.a. Captain Nemo). 2162f9fbec18Smcpowers */ 2163f9fbec18Smcpowers mp_digit s_mp_invmod_radix(mp_digit P) 2164f9fbec18Smcpowers { 2165f9fbec18Smcpowers mp_digit T = P; 2166f9fbec18Smcpowers T *= 2 - (P * T); 2167f9fbec18Smcpowers T *= 2 - (P * T); 2168f9fbec18Smcpowers T *= 2 - (P * T); 2169f9fbec18Smcpowers T *= 2 - (P * T); 2170f9fbec18Smcpowers #if !defined(MP_USE_UINT_DIGIT) 2171f9fbec18Smcpowers T *= 2 - (P * T); 2172f9fbec18Smcpowers T *= 2 - (P * T); 2173f9fbec18Smcpowers #endif 2174f9fbec18Smcpowers return T; 2175f9fbec18Smcpowers } 2176f9fbec18Smcpowers 2177f9fbec18Smcpowers /* Given c, k, and prime p, where a*c == 2**k (mod p), 2178f9fbec18Smcpowers ** Compute x = (a ** -1) mod p. This is similar to Montgomery reduction. 2179f9fbec18Smcpowers ** This technique from the paper "Fast Modular Reciprocals" (unpublished) 2180f9fbec18Smcpowers ** by Richard Schroeppel (a.k.a. Captain Nemo). 2181f9fbec18Smcpowers */ 2182f9fbec18Smcpowers mp_err s_mp_fixup_reciprocal(const mp_int *c, const mp_int *p, int k, mp_int *x) 2183f9fbec18Smcpowers { 2184f9fbec18Smcpowers int k_orig = k; 2185f9fbec18Smcpowers mp_digit r; 2186f9fbec18Smcpowers mp_size ix; 2187f9fbec18Smcpowers mp_err res; 2188f9fbec18Smcpowers 2189f9fbec18Smcpowers if (mp_cmp_z(c) < 0) { /* c < 0 */ 2190f9fbec18Smcpowers MP_CHECKOK( mp_add(c, p, x) ); /* x = c + p */ 2191f9fbec18Smcpowers } else { 2192f9fbec18Smcpowers MP_CHECKOK( mp_copy(c, x) ); /* x = c */ 2193f9fbec18Smcpowers } 2194f9fbec18Smcpowers 2195f9fbec18Smcpowers /* make sure x is large enough */ 2196f9fbec18Smcpowers ix = MP_HOWMANY(k, MP_DIGIT_BIT) + MP_USED(p) + 1; 2197f9fbec18Smcpowers ix = MP_MAX(ix, MP_USED(x)); 2198f9fbec18Smcpowers MP_CHECKOK( s_mp_pad(x, ix) ); 2199f9fbec18Smcpowers 2200f9fbec18Smcpowers r = 0 - s_mp_invmod_radix(MP_DIGIT(p,0)); 2201f9fbec18Smcpowers 2202f9fbec18Smcpowers for (ix = 0; k > 0; ix++) { 2203f9fbec18Smcpowers int j = MP_MIN(k, MP_DIGIT_BIT); 2204f9fbec18Smcpowers mp_digit v = r * MP_DIGIT(x, ix); 2205f9fbec18Smcpowers if (j < MP_DIGIT_BIT) { 2206f9fbec18Smcpowers v &= ((mp_digit)1 << j) - 1; /* v = v mod (2 ** j) */ 2207f9fbec18Smcpowers } 2208f9fbec18Smcpowers s_mp_mul_d_add_offset(p, v, x, ix); /* x += p * v * (RADIX ** ix) */ 2209f9fbec18Smcpowers k -= j; 2210f9fbec18Smcpowers } 2211f9fbec18Smcpowers s_mp_clamp(x); 2212f9fbec18Smcpowers s_mp_div_2d(x, k_orig); 2213f9fbec18Smcpowers res = MP_OKAY; 2214f9fbec18Smcpowers 2215f9fbec18Smcpowers CLEANUP: 2216f9fbec18Smcpowers return res; 2217f9fbec18Smcpowers } 2218f9fbec18Smcpowers 2219f9fbec18Smcpowers /* compute mod inverse using Schroeppel's method, only if m is odd */ 2220f9fbec18Smcpowers mp_err s_mp_invmod_odd_m(const mp_int *a, const mp_int *m, mp_int *c) 2221f9fbec18Smcpowers { 2222f9fbec18Smcpowers int k; 2223f9fbec18Smcpowers mp_err res; 2224f9fbec18Smcpowers mp_int x; 2225f9fbec18Smcpowers 2226f9fbec18Smcpowers ARGCHK(a && m && c, MP_BADARG); 2227f9fbec18Smcpowers 2228f9fbec18Smcpowers if(mp_cmp_z(a) == 0 || mp_cmp_z(m) == 0) 2229f9fbec18Smcpowers return MP_RANGE; 2230f9fbec18Smcpowers if (mp_iseven(m)) 2231f9fbec18Smcpowers return MP_UNDEF; 2232f9fbec18Smcpowers 2233f9fbec18Smcpowers MP_DIGITS(&x) = 0; 2234f9fbec18Smcpowers 2235f9fbec18Smcpowers if (a == c) { 2236f9fbec18Smcpowers if ((res = mp_init_copy(&x, a)) != MP_OKAY) 2237f9fbec18Smcpowers return res; 2238f9fbec18Smcpowers if (a == m) 2239f9fbec18Smcpowers m = &x; 2240f9fbec18Smcpowers a = &x; 2241f9fbec18Smcpowers } else if (m == c) { 2242f9fbec18Smcpowers if ((res = mp_init_copy(&x, m)) != MP_OKAY) 2243f9fbec18Smcpowers return res; 2244f9fbec18Smcpowers m = &x; 2245f9fbec18Smcpowers } else { 2246f9fbec18Smcpowers MP_DIGITS(&x) = 0; 2247f9fbec18Smcpowers } 2248f9fbec18Smcpowers 2249f9fbec18Smcpowers MP_CHECKOK( s_mp_almost_inverse(a, m, c) ); 2250f9fbec18Smcpowers k = res; 2251f9fbec18Smcpowers MP_CHECKOK( s_mp_fixup_reciprocal(c, m, k, c) ); 2252f9fbec18Smcpowers CLEANUP: 2253f9fbec18Smcpowers mp_clear(&x); 2254f9fbec18Smcpowers return res; 2255f9fbec18Smcpowers } 2256f9fbec18Smcpowers 2257f9fbec18Smcpowers /* Known good algorithm for computing modular inverse. But slow. */ 2258f9fbec18Smcpowers mp_err mp_invmod_xgcd(const mp_int *a, const mp_int *m, mp_int *c) 2259f9fbec18Smcpowers { 2260f9fbec18Smcpowers mp_int g, x; 2261f9fbec18Smcpowers mp_err res; 2262f9fbec18Smcpowers 2263f9fbec18Smcpowers ARGCHK(a && m && c, MP_BADARG); 2264f9fbec18Smcpowers 2265f9fbec18Smcpowers if(mp_cmp_z(a) == 0 || mp_cmp_z(m) == 0) 2266f9fbec18Smcpowers return MP_RANGE; 2267f9fbec18Smcpowers 2268f9fbec18Smcpowers MP_DIGITS(&g) = 0; 2269f9fbec18Smcpowers MP_DIGITS(&x) = 0; 2270f9fbec18Smcpowers MP_CHECKOK( mp_init(&x, FLAG(a)) ); 2271f9fbec18Smcpowers MP_CHECKOK( mp_init(&g, FLAG(a)) ); 2272f9fbec18Smcpowers 2273f9fbec18Smcpowers MP_CHECKOK( mp_xgcd(a, m, &g, &x, NULL) ); 2274f9fbec18Smcpowers 2275f9fbec18Smcpowers if (mp_cmp_d(&g, 1) != MP_EQ) { 2276f9fbec18Smcpowers res = MP_UNDEF; 2277f9fbec18Smcpowers goto CLEANUP; 2278f9fbec18Smcpowers } 2279f9fbec18Smcpowers 2280f9fbec18Smcpowers res = mp_mod(&x, m, c); 2281f9fbec18Smcpowers SIGN(c) = SIGN(a); 2282f9fbec18Smcpowers 2283f9fbec18Smcpowers CLEANUP: 2284f9fbec18Smcpowers mp_clear(&x); 2285f9fbec18Smcpowers mp_clear(&g); 2286f9fbec18Smcpowers 2287f9fbec18Smcpowers return res; 2288f9fbec18Smcpowers } 2289f9fbec18Smcpowers 2290f9fbec18Smcpowers /* modular inverse where modulus is 2**k. */ 2291f9fbec18Smcpowers /* c = a**-1 mod 2**k */ 2292f9fbec18Smcpowers mp_err s_mp_invmod_2d(const mp_int *a, mp_size k, mp_int *c) 2293f9fbec18Smcpowers { 2294f9fbec18Smcpowers mp_err res; 2295f9fbec18Smcpowers mp_size ix = k + 4; 2296f9fbec18Smcpowers mp_int t0, t1, val, tmp, two2k; 2297f9fbec18Smcpowers 2298f9fbec18Smcpowers static const mp_digit d2 = 2; 2299f9fbec18Smcpowers static const mp_int two = { 0, MP_ZPOS, 1, 1, (mp_digit *)&d2 }; 2300f9fbec18Smcpowers 2301f9fbec18Smcpowers if (mp_iseven(a)) 2302f9fbec18Smcpowers return MP_UNDEF; 2303f9fbec18Smcpowers if (k <= MP_DIGIT_BIT) { 2304f9fbec18Smcpowers mp_digit i = s_mp_invmod_radix(MP_DIGIT(a,0)); 2305f9fbec18Smcpowers if (k < MP_DIGIT_BIT) 2306f9fbec18Smcpowers i &= ((mp_digit)1 << k) - (mp_digit)1; 2307f9fbec18Smcpowers mp_set(c, i); 2308f9fbec18Smcpowers return MP_OKAY; 2309f9fbec18Smcpowers } 2310f9fbec18Smcpowers MP_DIGITS(&t0) = 0; 2311f9fbec18Smcpowers MP_DIGITS(&t1) = 0; 2312f9fbec18Smcpowers MP_DIGITS(&val) = 0; 2313f9fbec18Smcpowers MP_DIGITS(&tmp) = 0; 2314f9fbec18Smcpowers MP_DIGITS(&two2k) = 0; 2315f9fbec18Smcpowers MP_CHECKOK( mp_init_copy(&val, a) ); 2316f9fbec18Smcpowers s_mp_mod_2d(&val, k); 2317f9fbec18Smcpowers MP_CHECKOK( mp_init_copy(&t0, &val) ); 2318f9fbec18Smcpowers MP_CHECKOK( mp_init_copy(&t1, &t0) ); 2319f9fbec18Smcpowers MP_CHECKOK( mp_init(&tmp, FLAG(a)) ); 2320f9fbec18Smcpowers MP_CHECKOK( mp_init(&two2k, FLAG(a)) ); 2321f9fbec18Smcpowers MP_CHECKOK( s_mp_2expt(&two2k, k) ); 2322f9fbec18Smcpowers do { 2323f9fbec18Smcpowers MP_CHECKOK( mp_mul(&val, &t1, &tmp) ); 2324f9fbec18Smcpowers MP_CHECKOK( mp_sub(&two, &tmp, &tmp) ); 2325f9fbec18Smcpowers MP_CHECKOK( mp_mul(&t1, &tmp, &t1) ); 2326f9fbec18Smcpowers s_mp_mod_2d(&t1, k); 2327f9fbec18Smcpowers while (MP_SIGN(&t1) != MP_ZPOS) { 2328f9fbec18Smcpowers MP_CHECKOK( mp_add(&t1, &two2k, &t1) ); 2329f9fbec18Smcpowers } 2330f9fbec18Smcpowers if (mp_cmp(&t1, &t0) == MP_EQ) 2331f9fbec18Smcpowers break; 2332f9fbec18Smcpowers MP_CHECKOK( mp_copy(&t1, &t0) ); 2333f9fbec18Smcpowers } while (--ix > 0); 2334f9fbec18Smcpowers if (!ix) { 2335f9fbec18Smcpowers res = MP_UNDEF; 2336f9fbec18Smcpowers } else { 2337f9fbec18Smcpowers mp_exch(c, &t1); 2338f9fbec18Smcpowers } 2339f9fbec18Smcpowers 2340f9fbec18Smcpowers CLEANUP: 2341f9fbec18Smcpowers mp_clear(&t0); 2342f9fbec18Smcpowers mp_clear(&t1); 2343f9fbec18Smcpowers mp_clear(&val); 2344f9fbec18Smcpowers mp_clear(&tmp); 2345f9fbec18Smcpowers mp_clear(&two2k); 2346f9fbec18Smcpowers return res; 2347f9fbec18Smcpowers } 2348f9fbec18Smcpowers 2349f9fbec18Smcpowers mp_err s_mp_invmod_even_m(const mp_int *a, const mp_int *m, mp_int *c) 2350f9fbec18Smcpowers { 2351f9fbec18Smcpowers mp_err res; 2352f9fbec18Smcpowers mp_size k; 2353f9fbec18Smcpowers mp_int oddFactor, evenFactor; /* factors of the modulus */ 2354f9fbec18Smcpowers mp_int oddPart, evenPart; /* parts to combine via CRT. */ 2355f9fbec18Smcpowers mp_int C2, tmp1, tmp2; 2356f9fbec18Smcpowers 2357f9fbec18Smcpowers /*static const mp_digit d1 = 1; */ 2358f9fbec18Smcpowers /*static const mp_int one = { MP_ZPOS, 1, 1, (mp_digit *)&d1 }; */ 2359f9fbec18Smcpowers 2360f9fbec18Smcpowers if ((res = s_mp_ispow2(m)) >= 0) { 2361f9fbec18Smcpowers k = res; 2362f9fbec18Smcpowers return s_mp_invmod_2d(a, k, c); 2363f9fbec18Smcpowers } 2364f9fbec18Smcpowers MP_DIGITS(&oddFactor) = 0; 2365f9fbec18Smcpowers MP_DIGITS(&evenFactor) = 0; 2366f9fbec18Smcpowers MP_DIGITS(&oddPart) = 0; 2367f9fbec18Smcpowers MP_DIGITS(&evenPart) = 0; 2368f9fbec18Smcpowers MP_DIGITS(&C2) = 0; 2369f9fbec18Smcpowers MP_DIGITS(&tmp1) = 0; 2370f9fbec18Smcpowers MP_DIGITS(&tmp2) = 0; 2371f9fbec18Smcpowers 2372f9fbec18Smcpowers MP_CHECKOK( mp_init_copy(&oddFactor, m) ); /* oddFactor = m */ 2373f9fbec18Smcpowers MP_CHECKOK( mp_init(&evenFactor, FLAG(m)) ); 2374f9fbec18Smcpowers MP_CHECKOK( mp_init(&oddPart, FLAG(m)) ); 2375f9fbec18Smcpowers MP_CHECKOK( mp_init(&evenPart, FLAG(m)) ); 2376f9fbec18Smcpowers MP_CHECKOK( mp_init(&C2, FLAG(m)) ); 2377f9fbec18Smcpowers MP_CHECKOK( mp_init(&tmp1, FLAG(m)) ); 2378f9fbec18Smcpowers MP_CHECKOK( mp_init(&tmp2, FLAG(m)) ); 2379f9fbec18Smcpowers 2380f9fbec18Smcpowers k = mp_trailing_zeros(m); 2381f9fbec18Smcpowers s_mp_div_2d(&oddFactor, k); 2382f9fbec18Smcpowers MP_CHECKOK( s_mp_2expt(&evenFactor, k) ); 2383f9fbec18Smcpowers 2384f9fbec18Smcpowers /* compute a**-1 mod oddFactor. */ 2385f9fbec18Smcpowers MP_CHECKOK( s_mp_invmod_odd_m(a, &oddFactor, &oddPart) ); 2386f9fbec18Smcpowers /* compute a**-1 mod evenFactor, where evenFactor == 2**k. */ 2387f9fbec18Smcpowers MP_CHECKOK( s_mp_invmod_2d( a, k, &evenPart) ); 2388f9fbec18Smcpowers 2389f9fbec18Smcpowers /* Use Chinese Remainer theorem to compute a**-1 mod m. */ 2390f9fbec18Smcpowers /* let m1 = oddFactor, v1 = oddPart, 2391f9fbec18Smcpowers * let m2 = evenFactor, v2 = evenPart. 2392f9fbec18Smcpowers */ 2393f9fbec18Smcpowers 2394f9fbec18Smcpowers /* Compute C2 = m1**-1 mod m2. */ 2395f9fbec18Smcpowers MP_CHECKOK( s_mp_invmod_2d(&oddFactor, k, &C2) ); 2396f9fbec18Smcpowers 2397f9fbec18Smcpowers /* compute u = (v2 - v1)*C2 mod m2 */ 2398f9fbec18Smcpowers MP_CHECKOK( mp_sub(&evenPart, &oddPart, &tmp1) ); 2399f9fbec18Smcpowers MP_CHECKOK( mp_mul(&tmp1, &C2, &tmp2) ); 2400f9fbec18Smcpowers s_mp_mod_2d(&tmp2, k); 2401f9fbec18Smcpowers while (MP_SIGN(&tmp2) != MP_ZPOS) { 2402f9fbec18Smcpowers MP_CHECKOK( mp_add(&tmp2, &evenFactor, &tmp2) ); 2403f9fbec18Smcpowers } 2404f9fbec18Smcpowers 2405f9fbec18Smcpowers /* compute answer = v1 + u*m1 */ 2406f9fbec18Smcpowers MP_CHECKOK( mp_mul(&tmp2, &oddFactor, c) ); 2407f9fbec18Smcpowers MP_CHECKOK( mp_add(&oddPart, c, c) ); 2408f9fbec18Smcpowers /* not sure this is necessary, but it's low cost if not. */ 2409f9fbec18Smcpowers MP_CHECKOK( mp_mod(c, m, c) ); 2410f9fbec18Smcpowers 2411f9fbec18Smcpowers CLEANUP: 2412f9fbec18Smcpowers mp_clear(&oddFactor); 2413f9fbec18Smcpowers mp_clear(&evenFactor); 2414f9fbec18Smcpowers mp_clear(&oddPart); 2415f9fbec18Smcpowers mp_clear(&evenPart); 2416f9fbec18Smcpowers mp_clear(&C2); 2417f9fbec18Smcpowers mp_clear(&tmp1); 2418f9fbec18Smcpowers mp_clear(&tmp2); 2419f9fbec18Smcpowers return res; 2420f9fbec18Smcpowers } 2421f9fbec18Smcpowers 2422f9fbec18Smcpowers 2423f9fbec18Smcpowers /* {{{ mp_invmod(a, m, c) */ 2424f9fbec18Smcpowers 2425f9fbec18Smcpowers /* 2426f9fbec18Smcpowers mp_invmod(a, m, c) 2427f9fbec18Smcpowers 2428f9fbec18Smcpowers Compute c = a^-1 (mod m), if there is an inverse for a (mod m). 2429f9fbec18Smcpowers This is equivalent to the question of whether (a, m) = 1. If not, 2430f9fbec18Smcpowers MP_UNDEF is returned, and there is no inverse. 2431f9fbec18Smcpowers */ 2432f9fbec18Smcpowers 2433f9fbec18Smcpowers mp_err mp_invmod(const mp_int *a, const mp_int *m, mp_int *c) 2434f9fbec18Smcpowers { 2435f9fbec18Smcpowers 2436f9fbec18Smcpowers ARGCHK(a && m && c, MP_BADARG); 2437f9fbec18Smcpowers 2438f9fbec18Smcpowers if(mp_cmp_z(a) == 0 || mp_cmp_z(m) == 0) 2439f9fbec18Smcpowers return MP_RANGE; 2440f9fbec18Smcpowers 2441f9fbec18Smcpowers if (mp_isodd(m)) { 2442f9fbec18Smcpowers return s_mp_invmod_odd_m(a, m, c); 2443f9fbec18Smcpowers } 2444f9fbec18Smcpowers if (mp_iseven(a)) 2445f9fbec18Smcpowers return MP_UNDEF; /* not invertable */ 2446f9fbec18Smcpowers 2447f9fbec18Smcpowers return s_mp_invmod_even_m(a, m, c); 2448f9fbec18Smcpowers 2449f9fbec18Smcpowers } /* end mp_invmod() */ 2450f9fbec18Smcpowers 2451f9fbec18Smcpowers /* }}} */ 2452f9fbec18Smcpowers #endif /* if MP_NUMTH */ 2453f9fbec18Smcpowers 2454f9fbec18Smcpowers /* }}} */ 2455f9fbec18Smcpowers 2456f9fbec18Smcpowers /*------------------------------------------------------------------------*/ 2457f9fbec18Smcpowers /* {{{ mp_print(mp, ofp) */ 2458f9fbec18Smcpowers 2459f9fbec18Smcpowers #if MP_IOFUNC 2460f9fbec18Smcpowers /* 2461f9fbec18Smcpowers mp_print(mp, ofp) 2462f9fbec18Smcpowers 2463f9fbec18Smcpowers Print a textual representation of the given mp_int on the output 2464f9fbec18Smcpowers stream 'ofp'. Output is generated using the internal radix. 2465f9fbec18Smcpowers */ 2466f9fbec18Smcpowers 2467f9fbec18Smcpowers void mp_print(mp_int *mp, FILE *ofp) 2468f9fbec18Smcpowers { 2469f9fbec18Smcpowers int ix; 2470f9fbec18Smcpowers 2471f9fbec18Smcpowers if(mp == NULL || ofp == NULL) 2472f9fbec18Smcpowers return; 2473f9fbec18Smcpowers 2474f9fbec18Smcpowers fputc((SIGN(mp) == NEG) ? '-' : '+', ofp); 2475f9fbec18Smcpowers 2476f9fbec18Smcpowers for(ix = USED(mp) - 1; ix >= 0; ix--) { 2477f9fbec18Smcpowers fprintf(ofp, DIGIT_FMT, DIGIT(mp, ix)); 2478f9fbec18Smcpowers } 2479f9fbec18Smcpowers 2480f9fbec18Smcpowers } /* end mp_print() */ 2481f9fbec18Smcpowers 2482f9fbec18Smcpowers #endif /* if MP_IOFUNC */ 2483f9fbec18Smcpowers 2484f9fbec18Smcpowers /* }}} */ 2485f9fbec18Smcpowers 2486f9fbec18Smcpowers /*------------------------------------------------------------------------*/ 2487f9fbec18Smcpowers /* {{{ More I/O Functions */ 2488f9fbec18Smcpowers 2489f9fbec18Smcpowers /* {{{ mp_read_raw(mp, str, len) */ 2490f9fbec18Smcpowers 2491f9fbec18Smcpowers /* 2492f9fbec18Smcpowers mp_read_raw(mp, str, len) 2493f9fbec18Smcpowers 2494f9fbec18Smcpowers Read in a raw value (base 256) into the given mp_int 2495f9fbec18Smcpowers */ 2496f9fbec18Smcpowers 2497f9fbec18Smcpowers mp_err mp_read_raw(mp_int *mp, char *str, int len) 2498f9fbec18Smcpowers { 2499f9fbec18Smcpowers int ix; 2500f9fbec18Smcpowers mp_err res; 2501f9fbec18Smcpowers unsigned char *ustr = (unsigned char *)str; 2502f9fbec18Smcpowers 2503f9fbec18Smcpowers ARGCHK(mp != NULL && str != NULL && len > 0, MP_BADARG); 2504f9fbec18Smcpowers 2505f9fbec18Smcpowers mp_zero(mp); 2506f9fbec18Smcpowers 2507f9fbec18Smcpowers /* Get sign from first byte */ 2508f9fbec18Smcpowers if(ustr[0]) 2509f9fbec18Smcpowers SIGN(mp) = NEG; 2510f9fbec18Smcpowers else 2511f9fbec18Smcpowers SIGN(mp) = ZPOS; 2512f9fbec18Smcpowers 2513f9fbec18Smcpowers /* Read the rest of the digits */ 2514f9fbec18Smcpowers for(ix = 1; ix < len; ix++) { 2515f9fbec18Smcpowers if((res = mp_mul_d(mp, 256, mp)) != MP_OKAY) 2516f9fbec18Smcpowers return res; 2517f9fbec18Smcpowers if((res = mp_add_d(mp, ustr[ix], mp)) != MP_OKAY) 2518f9fbec18Smcpowers return res; 2519f9fbec18Smcpowers } 2520f9fbec18Smcpowers 2521f9fbec18Smcpowers return MP_OKAY; 2522f9fbec18Smcpowers 2523f9fbec18Smcpowers } /* end mp_read_raw() */ 2524f9fbec18Smcpowers 2525f9fbec18Smcpowers /* }}} */ 2526f9fbec18Smcpowers 2527f9fbec18Smcpowers /* {{{ mp_raw_size(mp) */ 2528f9fbec18Smcpowers 2529f9fbec18Smcpowers int mp_raw_size(mp_int *mp) 2530f9fbec18Smcpowers { 2531f9fbec18Smcpowers ARGCHK(mp != NULL, 0); 2532f9fbec18Smcpowers 2533f9fbec18Smcpowers return (USED(mp) * sizeof(mp_digit)) + 1; 2534f9fbec18Smcpowers 2535f9fbec18Smcpowers } /* end mp_raw_size() */ 2536f9fbec18Smcpowers 2537f9fbec18Smcpowers /* }}} */ 2538f9fbec18Smcpowers 2539f9fbec18Smcpowers /* {{{ mp_toraw(mp, str) */ 2540f9fbec18Smcpowers 2541f9fbec18Smcpowers mp_err mp_toraw(mp_int *mp, char *str) 2542f9fbec18Smcpowers { 2543f9fbec18Smcpowers int ix, jx, pos = 1; 2544f9fbec18Smcpowers 2545f9fbec18Smcpowers ARGCHK(mp != NULL && str != NULL, MP_BADARG); 2546f9fbec18Smcpowers 2547f9fbec18Smcpowers str[0] = (char)SIGN(mp); 2548f9fbec18Smcpowers 2549f9fbec18Smcpowers /* Iterate over each digit... */ 2550f9fbec18Smcpowers for(ix = USED(mp) - 1; ix >= 0; ix--) { 2551f9fbec18Smcpowers mp_digit d = DIGIT(mp, ix); 2552f9fbec18Smcpowers 2553f9fbec18Smcpowers /* Unpack digit bytes, high order first */ 2554f9fbec18Smcpowers for(jx = sizeof(mp_digit) - 1; jx >= 0; jx--) { 2555f9fbec18Smcpowers str[pos++] = (char)(d >> (jx * CHAR_BIT)); 2556f9fbec18Smcpowers } 2557f9fbec18Smcpowers } 2558f9fbec18Smcpowers 2559f9fbec18Smcpowers return MP_OKAY; 2560f9fbec18Smcpowers 2561f9fbec18Smcpowers } /* end mp_toraw() */ 2562f9fbec18Smcpowers 2563f9fbec18Smcpowers /* }}} */ 2564f9fbec18Smcpowers 2565f9fbec18Smcpowers /* {{{ mp_read_radix(mp, str, radix) */ 2566f9fbec18Smcpowers 2567f9fbec18Smcpowers /* 2568f9fbec18Smcpowers mp_read_radix(mp, str, radix) 2569f9fbec18Smcpowers 2570f9fbec18Smcpowers Read an integer from the given string, and set mp to the resulting 2571f9fbec18Smcpowers value. The input is presumed to be in base 10. Leading non-digit 2572f9fbec18Smcpowers characters are ignored, and the function reads until a non-digit 2573f9fbec18Smcpowers character or the end of the string. 2574f9fbec18Smcpowers */ 2575f9fbec18Smcpowers 2576f9fbec18Smcpowers mp_err mp_read_radix(mp_int *mp, const char *str, int radix) 2577f9fbec18Smcpowers { 2578f9fbec18Smcpowers int ix = 0, val = 0; 2579f9fbec18Smcpowers mp_err res; 2580f9fbec18Smcpowers mp_sign sig = ZPOS; 2581f9fbec18Smcpowers 2582f9fbec18Smcpowers ARGCHK(mp != NULL && str != NULL && radix >= 2 && radix <= MAX_RADIX, 2583f9fbec18Smcpowers MP_BADARG); 2584f9fbec18Smcpowers 2585f9fbec18Smcpowers mp_zero(mp); 2586f9fbec18Smcpowers 2587f9fbec18Smcpowers /* Skip leading non-digit characters until a digit or '-' or '+' */ 2588f9fbec18Smcpowers while(str[ix] && 2589f9fbec18Smcpowers (s_mp_tovalue(str[ix], radix) < 0) && 2590f9fbec18Smcpowers str[ix] != '-' && 2591f9fbec18Smcpowers str[ix] != '+') { 2592f9fbec18Smcpowers ++ix; 2593f9fbec18Smcpowers } 2594f9fbec18Smcpowers 2595f9fbec18Smcpowers if(str[ix] == '-') { 2596f9fbec18Smcpowers sig = NEG; 2597f9fbec18Smcpowers ++ix; 2598f9fbec18Smcpowers } else if(str[ix] == '+') { 2599f9fbec18Smcpowers sig = ZPOS; /* this is the default anyway... */ 2600f9fbec18Smcpowers ++ix; 2601f9fbec18Smcpowers } 2602f9fbec18Smcpowers 2603f9fbec18Smcpowers while((val = s_mp_tovalue(str[ix], radix)) >= 0) { 2604f9fbec18Smcpowers if((res = s_mp_mul_d(mp, radix)) != MP_OKAY) 2605f9fbec18Smcpowers return res; 2606f9fbec18Smcpowers if((res = s_mp_add_d(mp, val)) != MP_OKAY) 2607f9fbec18Smcpowers return res; 2608f9fbec18Smcpowers ++ix; 2609f9fbec18Smcpowers } 2610f9fbec18Smcpowers 2611f9fbec18Smcpowers if(s_mp_cmp_d(mp, 0) == MP_EQ) 2612f9fbec18Smcpowers SIGN(mp) = ZPOS; 2613f9fbec18Smcpowers else 2614f9fbec18Smcpowers SIGN(mp) = sig; 2615f9fbec18Smcpowers 2616f9fbec18Smcpowers return MP_OKAY; 2617f9fbec18Smcpowers 2618f9fbec18Smcpowers } /* end mp_read_radix() */ 2619f9fbec18Smcpowers 2620f9fbec18Smcpowers mp_err mp_read_variable_radix(mp_int *a, const char * str, int default_radix) 2621f9fbec18Smcpowers { 2622f9fbec18Smcpowers int radix = default_radix; 2623f9fbec18Smcpowers int cx; 2624f9fbec18Smcpowers mp_sign sig = ZPOS; 2625f9fbec18Smcpowers mp_err res; 2626f9fbec18Smcpowers 2627f9fbec18Smcpowers /* Skip leading non-digit characters until a digit or '-' or '+' */ 2628f9fbec18Smcpowers while ((cx = *str) != 0 && 2629f9fbec18Smcpowers (s_mp_tovalue(cx, radix) < 0) && 2630f9fbec18Smcpowers cx != '-' && 2631f9fbec18Smcpowers cx != '+') { 2632f9fbec18Smcpowers ++str; 2633f9fbec18Smcpowers } 2634f9fbec18Smcpowers 2635f9fbec18Smcpowers if (cx == '-') { 2636f9fbec18Smcpowers sig = NEG; 2637f9fbec18Smcpowers ++str; 2638f9fbec18Smcpowers } else if (cx == '+') { 2639f9fbec18Smcpowers sig = ZPOS; /* this is the default anyway... */ 2640f9fbec18Smcpowers ++str; 2641f9fbec18Smcpowers } 2642f9fbec18Smcpowers 2643f9fbec18Smcpowers if (str[0] == '0') { 2644f9fbec18Smcpowers if ((str[1] | 0x20) == 'x') { 2645f9fbec18Smcpowers radix = 16; 2646f9fbec18Smcpowers str += 2; 2647f9fbec18Smcpowers } else { 2648f9fbec18Smcpowers radix = 8; 2649f9fbec18Smcpowers str++; 2650f9fbec18Smcpowers } 2651f9fbec18Smcpowers } 2652f9fbec18Smcpowers res = mp_read_radix(a, str, radix); 2653f9fbec18Smcpowers if (res == MP_OKAY) { 2654f9fbec18Smcpowers MP_SIGN(a) = (s_mp_cmp_d(a, 0) == MP_EQ) ? ZPOS : sig; 2655f9fbec18Smcpowers } 2656f9fbec18Smcpowers return res; 2657f9fbec18Smcpowers } 2658f9fbec18Smcpowers 2659f9fbec18Smcpowers /* }}} */ 2660f9fbec18Smcpowers 2661f9fbec18Smcpowers /* {{{ mp_radix_size(mp, radix) */ 2662f9fbec18Smcpowers 2663f9fbec18Smcpowers int mp_radix_size(mp_int *mp, int radix) 2664f9fbec18Smcpowers { 2665f9fbec18Smcpowers int bits; 2666f9fbec18Smcpowers 2667f9fbec18Smcpowers if(!mp || radix < 2 || radix > MAX_RADIX) 2668f9fbec18Smcpowers return 0; 2669f9fbec18Smcpowers 2670f9fbec18Smcpowers bits = USED(mp) * DIGIT_BIT - 1; 2671f9fbec18Smcpowers 2672f9fbec18Smcpowers return s_mp_outlen(bits, radix); 2673f9fbec18Smcpowers 2674f9fbec18Smcpowers } /* end mp_radix_size() */ 2675f9fbec18Smcpowers 2676f9fbec18Smcpowers /* }}} */ 2677f9fbec18Smcpowers 2678f9fbec18Smcpowers /* {{{ mp_toradix(mp, str, radix) */ 2679f9fbec18Smcpowers 2680f9fbec18Smcpowers mp_err mp_toradix(mp_int *mp, char *str, int radix) 2681f9fbec18Smcpowers { 2682f9fbec18Smcpowers int ix, pos = 0; 2683f9fbec18Smcpowers 2684f9fbec18Smcpowers ARGCHK(mp != NULL && str != NULL, MP_BADARG); 2685f9fbec18Smcpowers ARGCHK(radix > 1 && radix <= MAX_RADIX, MP_RANGE); 2686f9fbec18Smcpowers 2687f9fbec18Smcpowers if(mp_cmp_z(mp) == MP_EQ) { 2688f9fbec18Smcpowers str[0] = '0'; 2689f9fbec18Smcpowers str[1] = '\0'; 2690f9fbec18Smcpowers } else { 2691f9fbec18Smcpowers mp_err res; 2692f9fbec18Smcpowers mp_int tmp; 2693f9fbec18Smcpowers mp_sign sgn; 2694f9fbec18Smcpowers mp_digit rem, rdx = (mp_digit)radix; 2695f9fbec18Smcpowers char ch; 2696f9fbec18Smcpowers 2697f9fbec18Smcpowers if((res = mp_init_copy(&tmp, mp)) != MP_OKAY) 2698f9fbec18Smcpowers return res; 2699f9fbec18Smcpowers 2700f9fbec18Smcpowers /* Save sign for later, and take absolute value */ 2701f9fbec18Smcpowers sgn = SIGN(&tmp); SIGN(&tmp) = ZPOS; 2702f9fbec18Smcpowers 2703f9fbec18Smcpowers /* Generate output digits in reverse order */ 2704f9fbec18Smcpowers while(mp_cmp_z(&tmp) != 0) { 2705f9fbec18Smcpowers if((res = mp_div_d(&tmp, rdx, &tmp, &rem)) != MP_OKAY) { 2706f9fbec18Smcpowers mp_clear(&tmp); 2707f9fbec18Smcpowers return res; 2708f9fbec18Smcpowers } 2709f9fbec18Smcpowers 2710f9fbec18Smcpowers /* Generate digits, use capital letters */ 2711f9fbec18Smcpowers ch = s_mp_todigit(rem, radix, 0); 2712f9fbec18Smcpowers 2713f9fbec18Smcpowers str[pos++] = ch; 2714f9fbec18Smcpowers } 2715f9fbec18Smcpowers 2716f9fbec18Smcpowers /* Add - sign if original value was negative */ 2717f9fbec18Smcpowers if(sgn == NEG) 2718f9fbec18Smcpowers str[pos++] = '-'; 2719f9fbec18Smcpowers 2720f9fbec18Smcpowers /* Add trailing NUL to end the string */ 2721f9fbec18Smcpowers str[pos--] = '\0'; 2722f9fbec18Smcpowers 2723f9fbec18Smcpowers /* Reverse the digits and sign indicator */ 2724f9fbec18Smcpowers ix = 0; 2725f9fbec18Smcpowers while(ix < pos) { 2726f9fbec18Smcpowers char tmp = str[ix]; 2727f9fbec18Smcpowers 2728f9fbec18Smcpowers str[ix] = str[pos]; 2729f9fbec18Smcpowers str[pos] = tmp; 2730f9fbec18Smcpowers ++ix; 2731f9fbec18Smcpowers --pos; 2732f9fbec18Smcpowers } 2733f9fbec18Smcpowers 2734f9fbec18Smcpowers mp_clear(&tmp); 2735f9fbec18Smcpowers } 2736f9fbec18Smcpowers 2737f9fbec18Smcpowers return MP_OKAY; 2738f9fbec18Smcpowers 2739f9fbec18Smcpowers } /* end mp_toradix() */ 2740f9fbec18Smcpowers 2741f9fbec18Smcpowers /* }}} */ 2742f9fbec18Smcpowers 2743f9fbec18Smcpowers /* {{{ mp_tovalue(ch, r) */ 2744f9fbec18Smcpowers 2745f9fbec18Smcpowers int mp_tovalue(char ch, int r) 2746f9fbec18Smcpowers { 2747f9fbec18Smcpowers return s_mp_tovalue(ch, r); 2748f9fbec18Smcpowers 2749f9fbec18Smcpowers } /* end mp_tovalue() */ 2750f9fbec18Smcpowers 2751f9fbec18Smcpowers /* }}} */ 2752f9fbec18Smcpowers 2753f9fbec18Smcpowers /* }}} */ 2754f9fbec18Smcpowers 2755f9fbec18Smcpowers /* {{{ mp_strerror(ec) */ 2756f9fbec18Smcpowers 2757f9fbec18Smcpowers /* 2758f9fbec18Smcpowers mp_strerror(ec) 2759f9fbec18Smcpowers 2760f9fbec18Smcpowers Return a string describing the meaning of error code 'ec'. The 2761f9fbec18Smcpowers string returned is allocated in static memory, so the caller should 2762f9fbec18Smcpowers not attempt to modify or free the memory associated with this 2763f9fbec18Smcpowers string. 2764f9fbec18Smcpowers */ 2765f9fbec18Smcpowers const char *mp_strerror(mp_err ec) 2766f9fbec18Smcpowers { 2767f9fbec18Smcpowers int aec = (ec < 0) ? -ec : ec; 2768f9fbec18Smcpowers 2769f9fbec18Smcpowers /* Code values are negative, so the senses of these comparisons 2770f9fbec18Smcpowers are accurate */ 2771f9fbec18Smcpowers if(ec < MP_LAST_CODE || ec > MP_OKAY) { 2772f9fbec18Smcpowers return mp_err_string[0]; /* unknown error code */ 2773f9fbec18Smcpowers } else { 2774f9fbec18Smcpowers return mp_err_string[aec + 1]; 2775f9fbec18Smcpowers } 2776f9fbec18Smcpowers 2777f9fbec18Smcpowers } /* end mp_strerror() */ 2778f9fbec18Smcpowers 2779f9fbec18Smcpowers /* }}} */ 2780f9fbec18Smcpowers 2781f9fbec18Smcpowers /*========================================================================*/ 2782f9fbec18Smcpowers /*------------------------------------------------------------------------*/ 2783f9fbec18Smcpowers /* Static function definitions (internal use only) */ 2784f9fbec18Smcpowers 2785f9fbec18Smcpowers /* {{{ Memory management */ 2786f9fbec18Smcpowers 2787f9fbec18Smcpowers /* {{{ s_mp_grow(mp, min) */ 2788f9fbec18Smcpowers 2789f9fbec18Smcpowers /* Make sure there are at least 'min' digits allocated to mp */ 2790f9fbec18Smcpowers mp_err s_mp_grow(mp_int *mp, mp_size min) 2791f9fbec18Smcpowers { 2792f9fbec18Smcpowers if(min > ALLOC(mp)) { 2793f9fbec18Smcpowers mp_digit *tmp; 2794f9fbec18Smcpowers 2795f9fbec18Smcpowers /* Set min to next nearest default precision block size */ 2796f9fbec18Smcpowers min = MP_ROUNDUP(min, s_mp_defprec); 2797f9fbec18Smcpowers 2798f9fbec18Smcpowers if((tmp = s_mp_alloc(min, sizeof(mp_digit), FLAG(mp))) == NULL) 2799f9fbec18Smcpowers return MP_MEM; 2800f9fbec18Smcpowers 2801f9fbec18Smcpowers s_mp_copy(DIGITS(mp), tmp, USED(mp)); 2802f9fbec18Smcpowers 2803f9fbec18Smcpowers #if MP_CRYPTO 2804f9fbec18Smcpowers s_mp_setz(DIGITS(mp), ALLOC(mp)); 2805f9fbec18Smcpowers #endif 2806f9fbec18Smcpowers s_mp_free(DIGITS(mp), ALLOC(mp)); 2807f9fbec18Smcpowers DIGITS(mp) = tmp; 2808f9fbec18Smcpowers ALLOC(mp) = min; 2809f9fbec18Smcpowers } 2810f9fbec18Smcpowers 2811f9fbec18Smcpowers return MP_OKAY; 2812f9fbec18Smcpowers 2813f9fbec18Smcpowers } /* end s_mp_grow() */ 2814f9fbec18Smcpowers 2815f9fbec18Smcpowers /* }}} */ 2816f9fbec18Smcpowers 2817f9fbec18Smcpowers /* {{{ s_mp_pad(mp, min) */ 2818f9fbec18Smcpowers 2819f9fbec18Smcpowers /* Make sure the used size of mp is at least 'min', growing if needed */ 2820f9fbec18Smcpowers mp_err s_mp_pad(mp_int *mp, mp_size min) 2821f9fbec18Smcpowers { 2822f9fbec18Smcpowers if(min > USED(mp)) { 2823f9fbec18Smcpowers mp_err res; 2824f9fbec18Smcpowers 2825f9fbec18Smcpowers /* Make sure there is room to increase precision */ 2826f9fbec18Smcpowers if (min > ALLOC(mp)) { 2827f9fbec18Smcpowers if ((res = s_mp_grow(mp, min)) != MP_OKAY) 2828f9fbec18Smcpowers return res; 2829f9fbec18Smcpowers } else { 2830f9fbec18Smcpowers s_mp_setz(DIGITS(mp) + USED(mp), min - USED(mp)); 2831f9fbec18Smcpowers } 2832f9fbec18Smcpowers 2833f9fbec18Smcpowers /* Increase precision; should already be 0-filled */ 2834f9fbec18Smcpowers USED(mp) = min; 2835f9fbec18Smcpowers } 2836f9fbec18Smcpowers 2837f9fbec18Smcpowers return MP_OKAY; 2838f9fbec18Smcpowers 2839f9fbec18Smcpowers } /* end s_mp_pad() */ 2840f9fbec18Smcpowers 2841f9fbec18Smcpowers /* }}} */ 2842f9fbec18Smcpowers 2843f9fbec18Smcpowers /* {{{ s_mp_setz(dp, count) */ 2844f9fbec18Smcpowers 2845f9fbec18Smcpowers #if MP_MACRO == 0 2846f9fbec18Smcpowers /* Set 'count' digits pointed to by dp to be zeroes */ 2847f9fbec18Smcpowers void s_mp_setz(mp_digit *dp, mp_size count) 2848f9fbec18Smcpowers { 2849f9fbec18Smcpowers #if MP_MEMSET == 0 2850f9fbec18Smcpowers int ix; 2851f9fbec18Smcpowers 2852f9fbec18Smcpowers for(ix = 0; ix < count; ix++) 2853f9fbec18Smcpowers dp[ix] = 0; 2854f9fbec18Smcpowers #else 2855f9fbec18Smcpowers memset(dp, 0, count * sizeof(mp_digit)); 2856f9fbec18Smcpowers #endif 2857f9fbec18Smcpowers 2858f9fbec18Smcpowers } /* end s_mp_setz() */ 2859f9fbec18Smcpowers #endif 2860f9fbec18Smcpowers 2861f9fbec18Smcpowers /* }}} */ 2862f9fbec18Smcpowers 2863f9fbec18Smcpowers /* {{{ s_mp_copy(sp, dp, count) */ 2864f9fbec18Smcpowers 2865f9fbec18Smcpowers #if MP_MACRO == 0 2866f9fbec18Smcpowers /* Copy 'count' digits from sp to dp */ 2867f9fbec18Smcpowers void s_mp_copy(const mp_digit *sp, mp_digit *dp, mp_size count) 2868f9fbec18Smcpowers { 2869f9fbec18Smcpowers #if MP_MEMCPY == 0 2870f9fbec18Smcpowers int ix; 2871f9fbec18Smcpowers 2872f9fbec18Smcpowers for(ix = 0; ix < count; ix++) 2873f9fbec18Smcpowers dp[ix] = sp[ix]; 2874f9fbec18Smcpowers #else 2875f9fbec18Smcpowers memcpy(dp, sp, count * sizeof(mp_digit)); 2876f9fbec18Smcpowers #endif 2877f9fbec18Smcpowers 2878f9fbec18Smcpowers } /* end s_mp_copy() */ 2879f9fbec18Smcpowers #endif 2880f9fbec18Smcpowers 2881f9fbec18Smcpowers /* }}} */ 2882f9fbec18Smcpowers 2883f9fbec18Smcpowers /* {{{ s_mp_alloc(nb, ni, kmflag) */ 2884f9fbec18Smcpowers 2885f9fbec18Smcpowers #if MP_MACRO == 0 2886f9fbec18Smcpowers /* Allocate ni records of nb bytes each, and return a pointer to that */ 2887f9fbec18Smcpowers void *s_mp_alloc(size_t nb, size_t ni, int kmflag) 2888f9fbec18Smcpowers { 2889f9fbec18Smcpowers ++mp_allocs; 2890f9fbec18Smcpowers #ifdef _KERNEL 2891*f2ba9e96SDina K Nimeh return kmem_zalloc(nb * ni, kmflag); 2892f9fbec18Smcpowers #else 2893f9fbec18Smcpowers return calloc(nb, ni); 2894f9fbec18Smcpowers #endif 2895f9fbec18Smcpowers 2896f9fbec18Smcpowers } /* end s_mp_alloc() */ 2897f9fbec18Smcpowers #endif 2898f9fbec18Smcpowers 2899f9fbec18Smcpowers /* }}} */ 2900f9fbec18Smcpowers 2901f9fbec18Smcpowers /* {{{ s_mp_free(ptr) */ 2902f9fbec18Smcpowers 2903f9fbec18Smcpowers #if MP_MACRO == 0 2904f9fbec18Smcpowers /* Free the memory pointed to by ptr */ 2905f9fbec18Smcpowers void s_mp_free(void *ptr, mp_size alloc) 2906f9fbec18Smcpowers { 2907f9fbec18Smcpowers if(ptr) { 2908f9fbec18Smcpowers ++mp_frees; 2909f9fbec18Smcpowers #ifdef _KERNEL 2910f9fbec18Smcpowers kmem_free(ptr, alloc * sizeof (mp_digit)); 2911f9fbec18Smcpowers #else 2912f9fbec18Smcpowers free(ptr); 2913f9fbec18Smcpowers #endif 2914f9fbec18Smcpowers } 2915f9fbec18Smcpowers } /* end s_mp_free() */ 2916f9fbec18Smcpowers #endif 2917f9fbec18Smcpowers 2918f9fbec18Smcpowers /* }}} */ 2919f9fbec18Smcpowers 2920f9fbec18Smcpowers /* {{{ s_mp_clamp(mp) */ 2921f9fbec18Smcpowers 2922f9fbec18Smcpowers #if MP_MACRO == 0 2923f9fbec18Smcpowers /* Remove leading zeroes from the given value */ 2924f9fbec18Smcpowers void s_mp_clamp(mp_int *mp) 2925f9fbec18Smcpowers { 2926f9fbec18Smcpowers mp_size used = MP_USED(mp); 2927f9fbec18Smcpowers while (used > 1 && DIGIT(mp, used - 1) == 0) 2928f9fbec18Smcpowers --used; 2929f9fbec18Smcpowers MP_USED(mp) = used; 2930f9fbec18Smcpowers } /* end s_mp_clamp() */ 2931f9fbec18Smcpowers #endif 2932f9fbec18Smcpowers 2933f9fbec18Smcpowers /* }}} */ 2934f9fbec18Smcpowers 2935f9fbec18Smcpowers /* {{{ s_mp_exch(a, b) */ 2936f9fbec18Smcpowers 2937f9fbec18Smcpowers /* Exchange the data for a and b; (b, a) = (a, b) */ 2938f9fbec18Smcpowers void s_mp_exch(mp_int *a, mp_int *b) 2939f9fbec18Smcpowers { 2940f9fbec18Smcpowers mp_int tmp; 2941f9fbec18Smcpowers 2942f9fbec18Smcpowers tmp = *a; 2943f9fbec18Smcpowers *a = *b; 2944f9fbec18Smcpowers *b = tmp; 2945f9fbec18Smcpowers 2946f9fbec18Smcpowers } /* end s_mp_exch() */ 2947f9fbec18Smcpowers 2948f9fbec18Smcpowers /* }}} */ 2949f9fbec18Smcpowers 2950f9fbec18Smcpowers /* }}} */ 2951f9fbec18Smcpowers 2952f9fbec18Smcpowers /* {{{ Arithmetic helpers */ 2953f9fbec18Smcpowers 2954f9fbec18Smcpowers /* {{{ s_mp_lshd(mp, p) */ 2955f9fbec18Smcpowers 2956f9fbec18Smcpowers /* 2957f9fbec18Smcpowers Shift mp leftward by p digits, growing if needed, and zero-filling 2958f9fbec18Smcpowers the in-shifted digits at the right end. This is a convenient 2959f9fbec18Smcpowers alternative to multiplication by powers of the radix 2960f9fbec18Smcpowers The value of USED(mp) must already have been set to the value for 2961f9fbec18Smcpowers the shifted result. 2962f9fbec18Smcpowers */ 2963f9fbec18Smcpowers 2964f9fbec18Smcpowers mp_err s_mp_lshd(mp_int *mp, mp_size p) 2965f9fbec18Smcpowers { 2966f9fbec18Smcpowers mp_err res; 2967f9fbec18Smcpowers mp_size pos; 2968f9fbec18Smcpowers int ix; 2969f9fbec18Smcpowers 2970f9fbec18Smcpowers if(p == 0) 2971f9fbec18Smcpowers return MP_OKAY; 2972f9fbec18Smcpowers 2973f9fbec18Smcpowers if (MP_USED(mp) == 1 && MP_DIGIT(mp, 0) == 0) 2974f9fbec18Smcpowers return MP_OKAY; 2975f9fbec18Smcpowers 2976f9fbec18Smcpowers if((res = s_mp_pad(mp, USED(mp) + p)) != MP_OKAY) 2977f9fbec18Smcpowers return res; 2978f9fbec18Smcpowers 2979f9fbec18Smcpowers pos = USED(mp) - 1; 2980f9fbec18Smcpowers 2981f9fbec18Smcpowers /* Shift all the significant figures over as needed */ 2982f9fbec18Smcpowers for(ix = pos - p; ix >= 0; ix--) 2983f9fbec18Smcpowers DIGIT(mp, ix + p) = DIGIT(mp, ix); 2984f9fbec18Smcpowers 2985f9fbec18Smcpowers /* Fill the bottom digits with zeroes */ 2986f9fbec18Smcpowers for(ix = 0; ix < p; ix++) 2987f9fbec18Smcpowers DIGIT(mp, ix) = 0; 2988f9fbec18Smcpowers 2989f9fbec18Smcpowers return MP_OKAY; 2990f9fbec18Smcpowers 2991f9fbec18Smcpowers } /* end s_mp_lshd() */ 2992f9fbec18Smcpowers 2993f9fbec18Smcpowers /* }}} */ 2994f9fbec18Smcpowers 2995f9fbec18Smcpowers /* {{{ s_mp_mul_2d(mp, d) */ 2996f9fbec18Smcpowers 2997f9fbec18Smcpowers /* 2998f9fbec18Smcpowers Multiply the integer by 2^d, where d is a number of bits. This 2999f9fbec18Smcpowers amounts to a bitwise shift of the value. 3000f9fbec18Smcpowers */ 3001f9fbec18Smcpowers mp_err s_mp_mul_2d(mp_int *mp, mp_digit d) 3002f9fbec18Smcpowers { 3003f9fbec18Smcpowers mp_err res; 3004f9fbec18Smcpowers mp_digit dshift, bshift; 3005f9fbec18Smcpowers mp_digit mask; 3006f9fbec18Smcpowers 3007f9fbec18Smcpowers ARGCHK(mp != NULL, MP_BADARG); 3008f9fbec18Smcpowers 3009f9fbec18Smcpowers dshift = d / MP_DIGIT_BIT; 3010f9fbec18Smcpowers bshift = d % MP_DIGIT_BIT; 3011f9fbec18Smcpowers /* bits to be shifted out of the top word */ 3012f9fbec18Smcpowers mask = ((mp_digit)~0 << (MP_DIGIT_BIT - bshift)); 3013f9fbec18Smcpowers mask &= MP_DIGIT(mp, MP_USED(mp) - 1); 3014f9fbec18Smcpowers 3015f9fbec18Smcpowers if (MP_OKAY != (res = s_mp_pad(mp, MP_USED(mp) + dshift + (mask != 0) ))) 3016f9fbec18Smcpowers return res; 3017f9fbec18Smcpowers 3018f9fbec18Smcpowers if (dshift && MP_OKAY != (res = s_mp_lshd(mp, dshift))) 3019f9fbec18Smcpowers return res; 3020f9fbec18Smcpowers 3021f9fbec18Smcpowers if (bshift) { 3022f9fbec18Smcpowers mp_digit *pa = MP_DIGITS(mp); 3023f9fbec18Smcpowers mp_digit *alim = pa + MP_USED(mp); 3024f9fbec18Smcpowers mp_digit prev = 0; 3025f9fbec18Smcpowers 3026f9fbec18Smcpowers for (pa += dshift; pa < alim; ) { 3027f9fbec18Smcpowers mp_digit x = *pa; 3028f9fbec18Smcpowers *pa++ = (x << bshift) | prev; 3029f9fbec18Smcpowers prev = x >> (DIGIT_BIT - bshift); 3030f9fbec18Smcpowers } 3031f9fbec18Smcpowers } 3032f9fbec18Smcpowers 3033f9fbec18Smcpowers s_mp_clamp(mp); 3034f9fbec18Smcpowers return MP_OKAY; 3035f9fbec18Smcpowers } /* end s_mp_mul_2d() */ 3036f9fbec18Smcpowers 3037f9fbec18Smcpowers /* {{{ s_mp_rshd(mp, p) */ 3038f9fbec18Smcpowers 3039f9fbec18Smcpowers /* 3040f9fbec18Smcpowers Shift mp rightward by p digits. Maintains the invariant that 3041f9fbec18Smcpowers digits above the precision are all zero. Digits shifted off the 3042f9fbec18Smcpowers end are lost. Cannot fail. 3043f9fbec18Smcpowers */ 3044f9fbec18Smcpowers 3045f9fbec18Smcpowers void s_mp_rshd(mp_int *mp, mp_size p) 3046f9fbec18Smcpowers { 3047f9fbec18Smcpowers mp_size ix; 3048f9fbec18Smcpowers mp_digit *src, *dst; 3049f9fbec18Smcpowers 3050f9fbec18Smcpowers if(p == 0) 3051f9fbec18Smcpowers return; 3052f9fbec18Smcpowers 3053f9fbec18Smcpowers /* Shortcut when all digits are to be shifted off */ 3054f9fbec18Smcpowers if(p >= USED(mp)) { 3055f9fbec18Smcpowers s_mp_setz(DIGITS(mp), ALLOC(mp)); 3056f9fbec18Smcpowers USED(mp) = 1; 3057f9fbec18Smcpowers SIGN(mp) = ZPOS; 3058f9fbec18Smcpowers return; 3059f9fbec18Smcpowers } 3060f9fbec18Smcpowers 3061f9fbec18Smcpowers /* Shift all the significant figures over as needed */ 3062f9fbec18Smcpowers dst = MP_DIGITS(mp); 3063f9fbec18Smcpowers src = dst + p; 3064f9fbec18Smcpowers for (ix = USED(mp) - p; ix > 0; ix--) 3065f9fbec18Smcpowers *dst++ = *src++; 3066f9fbec18Smcpowers 3067f9fbec18Smcpowers MP_USED(mp) -= p; 3068f9fbec18Smcpowers /* Fill the top digits with zeroes */ 3069f9fbec18Smcpowers while (p-- > 0) 3070f9fbec18Smcpowers *dst++ = 0; 3071f9fbec18Smcpowers 3072f9fbec18Smcpowers #if 0 3073f9fbec18Smcpowers /* Strip off any leading zeroes */ 3074f9fbec18Smcpowers s_mp_clamp(mp); 3075f9fbec18Smcpowers #endif 3076f9fbec18Smcpowers 3077f9fbec18Smcpowers } /* end s_mp_rshd() */ 3078f9fbec18Smcpowers 3079f9fbec18Smcpowers /* }}} */ 3080f9fbec18Smcpowers 3081f9fbec18Smcpowers /* {{{ s_mp_div_2(mp) */ 3082f9fbec18Smcpowers 3083f9fbec18Smcpowers /* Divide by two -- take advantage of radix properties to do it fast */ 3084f9fbec18Smcpowers void s_mp_div_2(mp_int *mp) 3085f9fbec18Smcpowers { 3086f9fbec18Smcpowers s_mp_div_2d(mp, 1); 3087f9fbec18Smcpowers 3088f9fbec18Smcpowers } /* end s_mp_div_2() */ 3089f9fbec18Smcpowers 3090f9fbec18Smcpowers /* }}} */ 3091f9fbec18Smcpowers 3092f9fbec18Smcpowers /* {{{ s_mp_mul_2(mp) */ 3093f9fbec18Smcpowers 3094f9fbec18Smcpowers mp_err s_mp_mul_2(mp_int *mp) 3095f9fbec18Smcpowers { 3096f9fbec18Smcpowers mp_digit *pd; 3097f9fbec18Smcpowers int ix, used; 3098f9fbec18Smcpowers mp_digit kin = 0; 3099f9fbec18Smcpowers 3100f9fbec18Smcpowers /* Shift digits leftward by 1 bit */ 3101f9fbec18Smcpowers used = MP_USED(mp); 3102f9fbec18Smcpowers pd = MP_DIGITS(mp); 3103f9fbec18Smcpowers for (ix = 0; ix < used; ix++) { 3104f9fbec18Smcpowers mp_digit d = *pd; 3105f9fbec18Smcpowers *pd++ = (d << 1) | kin; 3106f9fbec18Smcpowers kin = (d >> (DIGIT_BIT - 1)); 3107f9fbec18Smcpowers } 3108f9fbec18Smcpowers 3109f9fbec18Smcpowers /* Deal with rollover from last digit */ 3110f9fbec18Smcpowers if (kin) { 3111f9fbec18Smcpowers if (ix >= ALLOC(mp)) { 3112f9fbec18Smcpowers mp_err res; 3113f9fbec18Smcpowers if((res = s_mp_grow(mp, ALLOC(mp) + 1)) != MP_OKAY) 3114f9fbec18Smcpowers return res; 3115f9fbec18Smcpowers } 3116f9fbec18Smcpowers 3117f9fbec18Smcpowers DIGIT(mp, ix) = kin; 3118f9fbec18Smcpowers USED(mp) += 1; 3119f9fbec18Smcpowers } 3120f9fbec18Smcpowers 3121f9fbec18Smcpowers return MP_OKAY; 3122f9fbec18Smcpowers 3123f9fbec18Smcpowers } /* end s_mp_mul_2() */ 3124f9fbec18Smcpowers 3125f9fbec18Smcpowers /* }}} */ 3126f9fbec18Smcpowers 3127f9fbec18Smcpowers /* {{{ s_mp_mod_2d(mp, d) */ 3128f9fbec18Smcpowers 3129f9fbec18Smcpowers /* 3130f9fbec18Smcpowers Remainder the integer by 2^d, where d is a number of bits. This 3131f9fbec18Smcpowers amounts to a bitwise AND of the value, and does not require the full 3132f9fbec18Smcpowers division code 3133f9fbec18Smcpowers */ 3134f9fbec18Smcpowers void s_mp_mod_2d(mp_int *mp, mp_digit d) 3135f9fbec18Smcpowers { 3136f9fbec18Smcpowers mp_size ndig = (d / DIGIT_BIT), nbit = (d % DIGIT_BIT); 3137f9fbec18Smcpowers mp_size ix; 3138f9fbec18Smcpowers mp_digit dmask; 3139f9fbec18Smcpowers 3140f9fbec18Smcpowers if(ndig >= USED(mp)) 3141f9fbec18Smcpowers return; 3142f9fbec18Smcpowers 3143f9fbec18Smcpowers /* Flush all the bits above 2^d in its digit */ 3144f9fbec18Smcpowers dmask = ((mp_digit)1 << nbit) - 1; 3145f9fbec18Smcpowers DIGIT(mp, ndig) &= dmask; 3146f9fbec18Smcpowers 3147f9fbec18Smcpowers /* Flush all digits above the one with 2^d in it */ 3148f9fbec18Smcpowers for(ix = ndig + 1; ix < USED(mp); ix++) 3149f9fbec18Smcpowers DIGIT(mp, ix) = 0; 3150f9fbec18Smcpowers 3151f9fbec18Smcpowers s_mp_clamp(mp); 3152f9fbec18Smcpowers 3153f9fbec18Smcpowers } /* end s_mp_mod_2d() */ 3154f9fbec18Smcpowers 3155f9fbec18Smcpowers /* }}} */ 3156f9fbec18Smcpowers 3157f9fbec18Smcpowers /* {{{ s_mp_div_2d(mp, d) */ 3158f9fbec18Smcpowers 3159f9fbec18Smcpowers /* 3160f9fbec18Smcpowers Divide the integer by 2^d, where d is a number of bits. This 3161f9fbec18Smcpowers amounts to a bitwise shift of the value, and does not require the 3162f9fbec18Smcpowers full division code (used in Barrett reduction, see below) 3163f9fbec18Smcpowers */ 3164f9fbec18Smcpowers void s_mp_div_2d(mp_int *mp, mp_digit d) 3165f9fbec18Smcpowers { 3166f9fbec18Smcpowers int ix; 3167f9fbec18Smcpowers mp_digit save, next, mask; 3168f9fbec18Smcpowers 3169f9fbec18Smcpowers s_mp_rshd(mp, d / DIGIT_BIT); 3170f9fbec18Smcpowers d %= DIGIT_BIT; 3171f9fbec18Smcpowers if (d) { 3172f9fbec18Smcpowers mask = ((mp_digit)1 << d) - 1; 3173f9fbec18Smcpowers save = 0; 3174f9fbec18Smcpowers for(ix = USED(mp) - 1; ix >= 0; ix--) { 3175f9fbec18Smcpowers next = DIGIT(mp, ix) & mask; 3176f9fbec18Smcpowers DIGIT(mp, ix) = (DIGIT(mp, ix) >> d) | (save << (DIGIT_BIT - d)); 3177f9fbec18Smcpowers save = next; 3178f9fbec18Smcpowers } 3179f9fbec18Smcpowers } 3180f9fbec18Smcpowers s_mp_clamp(mp); 3181f9fbec18Smcpowers 3182f9fbec18Smcpowers } /* end s_mp_div_2d() */ 3183f9fbec18Smcpowers 3184f9fbec18Smcpowers /* }}} */ 3185f9fbec18Smcpowers 3186f9fbec18Smcpowers /* {{{ s_mp_norm(a, b, *d) */ 3187f9fbec18Smcpowers 3188f9fbec18Smcpowers /* 3189f9fbec18Smcpowers s_mp_norm(a, b, *d) 3190f9fbec18Smcpowers 3191f9fbec18Smcpowers Normalize a and b for division, where b is the divisor. In order 3192f9fbec18Smcpowers that we might make good guesses for quotient digits, we want the 3193f9fbec18Smcpowers leading digit of b to be at least half the radix, which we 3194f9fbec18Smcpowers accomplish by multiplying a and b by a power of 2. The exponent 3195f9fbec18Smcpowers (shift count) is placed in *pd, so that the remainder can be shifted 3196f9fbec18Smcpowers back at the end of the division process. 3197f9fbec18Smcpowers */ 3198f9fbec18Smcpowers 3199f9fbec18Smcpowers mp_err s_mp_norm(mp_int *a, mp_int *b, mp_digit *pd) 3200f9fbec18Smcpowers { 3201f9fbec18Smcpowers mp_digit d; 3202f9fbec18Smcpowers mp_digit mask; 3203f9fbec18Smcpowers mp_digit b_msd; 3204f9fbec18Smcpowers mp_err res = MP_OKAY; 3205f9fbec18Smcpowers 3206f9fbec18Smcpowers d = 0; 3207f9fbec18Smcpowers mask = DIGIT_MAX & ~(DIGIT_MAX >> 1); /* mask is msb of digit */ 3208f9fbec18Smcpowers b_msd = DIGIT(b, USED(b) - 1); 3209f9fbec18Smcpowers while (!(b_msd & mask)) { 3210f9fbec18Smcpowers b_msd <<= 1; 3211f9fbec18Smcpowers ++d; 3212f9fbec18Smcpowers } 3213f9fbec18Smcpowers 3214f9fbec18Smcpowers if (d) { 3215f9fbec18Smcpowers MP_CHECKOK( s_mp_mul_2d(a, d) ); 3216f9fbec18Smcpowers MP_CHECKOK( s_mp_mul_2d(b, d) ); 3217f9fbec18Smcpowers } 3218f9fbec18Smcpowers 3219f9fbec18Smcpowers *pd = d; 3220f9fbec18Smcpowers CLEANUP: 3221f9fbec18Smcpowers return res; 3222f9fbec18Smcpowers 3223f9fbec18Smcpowers } /* end s_mp_norm() */ 3224f9fbec18Smcpowers 3225f9fbec18Smcpowers /* }}} */ 3226f9fbec18Smcpowers 3227f9fbec18Smcpowers /* }}} */ 3228f9fbec18Smcpowers 3229f9fbec18Smcpowers /* {{{ Primitive digit arithmetic */ 3230f9fbec18Smcpowers 3231f9fbec18Smcpowers /* {{{ s_mp_add_d(mp, d) */ 3232f9fbec18Smcpowers 3233f9fbec18Smcpowers /* Add d to |mp| in place */ 3234f9fbec18Smcpowers mp_err s_mp_add_d(mp_int *mp, mp_digit d) /* unsigned digit addition */ 3235f9fbec18Smcpowers { 3236f9fbec18Smcpowers #if !defined(MP_NO_MP_WORD) && !defined(MP_NO_ADD_WORD) 3237f9fbec18Smcpowers mp_word w, k = 0; 3238f9fbec18Smcpowers mp_size ix = 1; 3239f9fbec18Smcpowers 3240f9fbec18Smcpowers w = (mp_word)DIGIT(mp, 0) + d; 3241f9fbec18Smcpowers DIGIT(mp, 0) = ACCUM(w); 3242f9fbec18Smcpowers k = CARRYOUT(w); 3243f9fbec18Smcpowers 3244f9fbec18Smcpowers while(ix < USED(mp) && k) { 3245f9fbec18Smcpowers w = (mp_word)DIGIT(mp, ix) + k; 3246f9fbec18Smcpowers DIGIT(mp, ix) = ACCUM(w); 3247f9fbec18Smcpowers k = CARRYOUT(w); 3248f9fbec18Smcpowers ++ix; 3249f9fbec18Smcpowers } 3250f9fbec18Smcpowers 3251f9fbec18Smcpowers if(k != 0) { 3252f9fbec18Smcpowers mp_err res; 3253f9fbec18Smcpowers 3254f9fbec18Smcpowers if((res = s_mp_pad(mp, USED(mp) + 1)) != MP_OKAY) 3255f9fbec18Smcpowers return res; 3256f9fbec18Smcpowers 3257f9fbec18Smcpowers DIGIT(mp, ix) = (mp_digit)k; 3258f9fbec18Smcpowers } 3259f9fbec18Smcpowers 3260f9fbec18Smcpowers return MP_OKAY; 3261f9fbec18Smcpowers #else 3262f9fbec18Smcpowers mp_digit * pmp = MP_DIGITS(mp); 3263f9fbec18Smcpowers mp_digit sum, mp_i, carry = 0; 3264f9fbec18Smcpowers mp_err res = MP_OKAY; 3265f9fbec18Smcpowers int used = (int)MP_USED(mp); 3266f9fbec18Smcpowers 3267f9fbec18Smcpowers mp_i = *pmp; 3268f9fbec18Smcpowers *pmp++ = sum = d + mp_i; 3269f9fbec18Smcpowers carry = (sum < d); 3270f9fbec18Smcpowers while (carry && --used > 0) { 3271f9fbec18Smcpowers mp_i = *pmp; 3272f9fbec18Smcpowers *pmp++ = sum = carry + mp_i; 3273f9fbec18Smcpowers carry = !sum; 3274f9fbec18Smcpowers } 3275f9fbec18Smcpowers if (carry && !used) { 3276f9fbec18Smcpowers /* mp is growing */ 3277f9fbec18Smcpowers used = MP_USED(mp); 3278f9fbec18Smcpowers MP_CHECKOK( s_mp_pad(mp, used + 1) ); 3279f9fbec18Smcpowers MP_DIGIT(mp, used) = carry; 3280f9fbec18Smcpowers } 3281f9fbec18Smcpowers CLEANUP: 3282f9fbec18Smcpowers return res; 3283f9fbec18Smcpowers #endif 3284f9fbec18Smcpowers } /* end s_mp_add_d() */ 3285f9fbec18Smcpowers 3286f9fbec18Smcpowers /* }}} */ 3287f9fbec18Smcpowers 3288f9fbec18Smcpowers /* {{{ s_mp_sub_d(mp, d) */ 3289f9fbec18Smcpowers 3290f9fbec18Smcpowers /* Subtract d from |mp| in place, assumes |mp| > d */ 3291f9fbec18Smcpowers mp_err s_mp_sub_d(mp_int *mp, mp_digit d) /* unsigned digit subtract */ 3292f9fbec18Smcpowers { 3293f9fbec18Smcpowers #if !defined(MP_NO_MP_WORD) && !defined(MP_NO_SUB_WORD) 3294f9fbec18Smcpowers mp_word w, b = 0; 3295f9fbec18Smcpowers mp_size ix = 1; 3296f9fbec18Smcpowers 3297f9fbec18Smcpowers /* Compute initial subtraction */ 3298f9fbec18Smcpowers w = (RADIX + (mp_word)DIGIT(mp, 0)) - d; 3299f9fbec18Smcpowers b = CARRYOUT(w) ? 0 : 1; 3300f9fbec18Smcpowers DIGIT(mp, 0) = ACCUM(w); 3301f9fbec18Smcpowers 3302f9fbec18Smcpowers /* Propagate borrows leftward */ 3303f9fbec18Smcpowers while(b && ix < USED(mp)) { 3304f9fbec18Smcpowers w = (RADIX + (mp_word)DIGIT(mp, ix)) - b; 3305f9fbec18Smcpowers b = CARRYOUT(w) ? 0 : 1; 3306f9fbec18Smcpowers DIGIT(mp, ix) = ACCUM(w); 3307f9fbec18Smcpowers ++ix; 3308f9fbec18Smcpowers } 3309f9fbec18Smcpowers 3310f9fbec18Smcpowers /* Remove leading zeroes */ 3311f9fbec18Smcpowers s_mp_clamp(mp); 3312f9fbec18Smcpowers 3313f9fbec18Smcpowers /* If we have a borrow out, it's a violation of the input invariant */ 3314f9fbec18Smcpowers if(b) 3315f9fbec18Smcpowers return MP_RANGE; 3316f9fbec18Smcpowers else 3317f9fbec18Smcpowers return MP_OKAY; 3318f9fbec18Smcpowers #else 3319f9fbec18Smcpowers mp_digit *pmp = MP_DIGITS(mp); 3320f9fbec18Smcpowers mp_digit mp_i, diff, borrow; 3321f9fbec18Smcpowers mp_size used = MP_USED(mp); 3322f9fbec18Smcpowers 3323f9fbec18Smcpowers mp_i = *pmp; 3324f9fbec18Smcpowers *pmp++ = diff = mp_i - d; 3325f9fbec18Smcpowers borrow = (diff > mp_i); 3326f9fbec18Smcpowers while (borrow && --used) { 3327f9fbec18Smcpowers mp_i = *pmp; 3328f9fbec18Smcpowers *pmp++ = diff = mp_i - borrow; 3329f9fbec18Smcpowers borrow = (diff > mp_i); 3330f9fbec18Smcpowers } 3331f9fbec18Smcpowers s_mp_clamp(mp); 3332f9fbec18Smcpowers return (borrow && !used) ? MP_RANGE : MP_OKAY; 3333f9fbec18Smcpowers #endif 3334f9fbec18Smcpowers } /* end s_mp_sub_d() */ 3335f9fbec18Smcpowers 3336f9fbec18Smcpowers /* }}} */ 3337f9fbec18Smcpowers 3338f9fbec18Smcpowers /* {{{ s_mp_mul_d(a, d) */ 3339f9fbec18Smcpowers 3340f9fbec18Smcpowers /* Compute a = a * d, single digit multiplication */ 3341f9fbec18Smcpowers mp_err s_mp_mul_d(mp_int *a, mp_digit d) 3342f9fbec18Smcpowers { 3343f9fbec18Smcpowers mp_err res; 3344f9fbec18Smcpowers mp_size used; 3345f9fbec18Smcpowers int pow; 3346f9fbec18Smcpowers 3347f9fbec18Smcpowers if (!d) { 3348f9fbec18Smcpowers mp_zero(a); 3349f9fbec18Smcpowers return MP_OKAY; 3350f9fbec18Smcpowers } 3351f9fbec18Smcpowers if (d == 1) 3352f9fbec18Smcpowers return MP_OKAY; 3353f9fbec18Smcpowers if (0 <= (pow = s_mp_ispow2d(d))) { 3354f9fbec18Smcpowers return s_mp_mul_2d(a, (mp_digit)pow); 3355f9fbec18Smcpowers } 3356f9fbec18Smcpowers 3357f9fbec18Smcpowers used = MP_USED(a); 3358f9fbec18Smcpowers MP_CHECKOK( s_mp_pad(a, used + 1) ); 3359f9fbec18Smcpowers 3360f9fbec18Smcpowers s_mpv_mul_d(MP_DIGITS(a), used, d, MP_DIGITS(a)); 3361f9fbec18Smcpowers 3362f9fbec18Smcpowers s_mp_clamp(a); 3363f9fbec18Smcpowers 3364f9fbec18Smcpowers CLEANUP: 3365f9fbec18Smcpowers return res; 3366f9fbec18Smcpowers 3367f9fbec18Smcpowers } /* end s_mp_mul_d() */ 3368f9fbec18Smcpowers 3369f9fbec18Smcpowers /* }}} */ 3370f9fbec18Smcpowers 3371f9fbec18Smcpowers /* {{{ s_mp_div_d(mp, d, r) */ 3372f9fbec18Smcpowers 3373f9fbec18Smcpowers /* 3374f9fbec18Smcpowers s_mp_div_d(mp, d, r) 3375f9fbec18Smcpowers 3376f9fbec18Smcpowers Compute the quotient mp = mp / d and remainder r = mp mod d, for a 3377f9fbec18Smcpowers single digit d. If r is null, the remainder will be discarded. 3378f9fbec18Smcpowers */ 3379f9fbec18Smcpowers 3380f9fbec18Smcpowers mp_err s_mp_div_d(mp_int *mp, mp_digit d, mp_digit *r) 3381f9fbec18Smcpowers { 3382f9fbec18Smcpowers #if !defined(MP_NO_MP_WORD) && !defined(MP_NO_DIV_WORD) 3383f9fbec18Smcpowers mp_word w = 0, q; 3384f9fbec18Smcpowers #else 3385f9fbec18Smcpowers mp_digit w, q; 3386f9fbec18Smcpowers #endif 3387f9fbec18Smcpowers int ix; 3388f9fbec18Smcpowers mp_err res; 3389f9fbec18Smcpowers mp_int quot; 3390f9fbec18Smcpowers mp_int rem; 3391f9fbec18Smcpowers 3392f9fbec18Smcpowers if(d == 0) 3393f9fbec18Smcpowers return MP_RANGE; 3394f9fbec18Smcpowers if (d == 1) { 3395f9fbec18Smcpowers if (r) 3396f9fbec18Smcpowers *r = 0; 3397f9fbec18Smcpowers return MP_OKAY; 3398f9fbec18Smcpowers } 3399f9fbec18Smcpowers /* could check for power of 2 here, but mp_div_d does that. */ 3400f9fbec18Smcpowers if (MP_USED(mp) == 1) { 3401f9fbec18Smcpowers mp_digit n = MP_DIGIT(mp,0); 3402f9fbec18Smcpowers mp_digit rem; 3403f9fbec18Smcpowers 3404f9fbec18Smcpowers q = n / d; 3405f9fbec18Smcpowers rem = n % d; 3406f9fbec18Smcpowers MP_DIGIT(mp,0) = q; 3407f9fbec18Smcpowers if (r) 3408f9fbec18Smcpowers *r = rem; 3409f9fbec18Smcpowers return MP_OKAY; 3410f9fbec18Smcpowers } 3411f9fbec18Smcpowers 3412f9fbec18Smcpowers MP_DIGITS(&rem) = 0; 3413f9fbec18Smcpowers MP_DIGITS(") = 0; 3414f9fbec18Smcpowers /* Make room for the quotient */ 3415f9fbec18Smcpowers MP_CHECKOK( mp_init_size(", USED(mp), FLAG(mp)) ); 3416f9fbec18Smcpowers 3417f9fbec18Smcpowers #if !defined(MP_NO_MP_WORD) && !defined(MP_NO_DIV_WORD) 3418f9fbec18Smcpowers for(ix = USED(mp) - 1; ix >= 0; ix--) { 3419f9fbec18Smcpowers w = (w << DIGIT_BIT) | DIGIT(mp, ix); 3420f9fbec18Smcpowers 3421f9fbec18Smcpowers if(w >= d) { 3422f9fbec18Smcpowers q = w / d; 3423f9fbec18Smcpowers w = w % d; 3424f9fbec18Smcpowers } else { 3425f9fbec18Smcpowers q = 0; 3426f9fbec18Smcpowers } 3427f9fbec18Smcpowers 3428f9fbec18Smcpowers s_mp_lshd(", 1); 3429f9fbec18Smcpowers DIGIT(", 0) = (mp_digit)q; 3430f9fbec18Smcpowers } 3431f9fbec18Smcpowers #else 3432f9fbec18Smcpowers { 3433f9fbec18Smcpowers mp_digit p; 3434f9fbec18Smcpowers #if !defined(MP_ASSEMBLY_DIV_2DX1D) 3435f9fbec18Smcpowers mp_digit norm; 3436f9fbec18Smcpowers #endif 3437f9fbec18Smcpowers 3438f9fbec18Smcpowers MP_CHECKOK( mp_init_copy(&rem, mp) ); 3439f9fbec18Smcpowers 3440f9fbec18Smcpowers #if !defined(MP_ASSEMBLY_DIV_2DX1D) 3441f9fbec18Smcpowers MP_DIGIT(", 0) = d; 3442f9fbec18Smcpowers MP_CHECKOK( s_mp_norm(&rem, ", &norm) ); 3443f9fbec18Smcpowers if (norm) 3444f9fbec18Smcpowers d <<= norm; 3445f9fbec18Smcpowers MP_DIGIT(", 0) = 0; 3446f9fbec18Smcpowers #endif 3447f9fbec18Smcpowers 3448f9fbec18Smcpowers p = 0; 3449f9fbec18Smcpowers for (ix = USED(&rem) - 1; ix >= 0; ix--) { 3450f9fbec18Smcpowers w = DIGIT(&rem, ix); 3451f9fbec18Smcpowers 3452f9fbec18Smcpowers if (p) { 3453f9fbec18Smcpowers MP_CHECKOK( s_mpv_div_2dx1d(p, w, d, &q, &w) ); 3454f9fbec18Smcpowers } else if (w >= d) { 3455f9fbec18Smcpowers q = w / d; 3456f9fbec18Smcpowers w = w % d; 3457f9fbec18Smcpowers } else { 3458f9fbec18Smcpowers q = 0; 3459f9fbec18Smcpowers } 3460f9fbec18Smcpowers 3461f9fbec18Smcpowers MP_CHECKOK( s_mp_lshd(", 1) ); 3462f9fbec18Smcpowers DIGIT(", 0) = q; 3463f9fbec18Smcpowers p = w; 3464f9fbec18Smcpowers } 3465f9fbec18Smcpowers #if !defined(MP_ASSEMBLY_DIV_2DX1D) 3466f9fbec18Smcpowers if (norm) 3467f9fbec18Smcpowers w >>= norm; 3468f9fbec18Smcpowers #endif 3469f9fbec18Smcpowers } 3470f9fbec18Smcpowers #endif 3471f9fbec18Smcpowers 3472f9fbec18Smcpowers /* Deliver the remainder, if desired */ 3473f9fbec18Smcpowers if(r) 3474f9fbec18Smcpowers *r = (mp_digit)w; 3475f9fbec18Smcpowers 3476f9fbec18Smcpowers s_mp_clamp("); 3477f9fbec18Smcpowers mp_exch(", mp); 3478f9fbec18Smcpowers CLEANUP: 3479f9fbec18Smcpowers mp_clear("); 3480f9fbec18Smcpowers mp_clear(&rem); 3481f9fbec18Smcpowers 3482f9fbec18Smcpowers return res; 3483f9fbec18Smcpowers } /* end s_mp_div_d() */ 3484f9fbec18Smcpowers 3485f9fbec18Smcpowers /* }}} */ 3486f9fbec18Smcpowers 3487f9fbec18Smcpowers 3488f9fbec18Smcpowers /* }}} */ 3489f9fbec18Smcpowers 3490f9fbec18Smcpowers /* {{{ Primitive full arithmetic */ 3491f9fbec18Smcpowers 3492f9fbec18Smcpowers /* {{{ s_mp_add(a, b) */ 3493f9fbec18Smcpowers 3494f9fbec18Smcpowers /* Compute a = |a| + |b| */ 3495f9fbec18Smcpowers mp_err s_mp_add(mp_int *a, const mp_int *b) /* magnitude addition */ 3496f9fbec18Smcpowers { 3497f9fbec18Smcpowers #if !defined(MP_NO_MP_WORD) && !defined(MP_NO_ADD_WORD) 3498f9fbec18Smcpowers mp_word w = 0; 3499f9fbec18Smcpowers #else 3500f9fbec18Smcpowers mp_digit d, sum, carry = 0; 3501f9fbec18Smcpowers #endif 3502f9fbec18Smcpowers mp_digit *pa, *pb; 3503f9fbec18Smcpowers mp_size ix; 3504f9fbec18Smcpowers mp_size used; 3505f9fbec18Smcpowers mp_err res; 3506f9fbec18Smcpowers 3507f9fbec18Smcpowers /* Make sure a has enough precision for the output value */ 3508f9fbec18Smcpowers if((USED(b) > USED(a)) && (res = s_mp_pad(a, USED(b))) != MP_OKAY) 3509f9fbec18Smcpowers return res; 3510f9fbec18Smcpowers 3511f9fbec18Smcpowers /* 3512f9fbec18Smcpowers Add up all digits up to the precision of b. If b had initially 3513f9fbec18Smcpowers the same precision as a, or greater, we took care of it by the 3514f9fbec18Smcpowers padding step above, so there is no problem. If b had initially 3515f9fbec18Smcpowers less precision, we'll have to make sure the carry out is duly 3516f9fbec18Smcpowers propagated upward among the higher-order digits of the sum. 3517f9fbec18Smcpowers */ 3518f9fbec18Smcpowers pa = MP_DIGITS(a); 3519f9fbec18Smcpowers pb = MP_DIGITS(b); 3520f9fbec18Smcpowers used = MP_USED(b); 3521f9fbec18Smcpowers for(ix = 0; ix < used; ix++) { 3522f9fbec18Smcpowers #if !defined(MP_NO_MP_WORD) && !defined(MP_NO_ADD_WORD) 3523f9fbec18Smcpowers w = w + *pa + *pb++; 3524f9fbec18Smcpowers *pa++ = ACCUM(w); 3525f9fbec18Smcpowers w = CARRYOUT(w); 3526f9fbec18Smcpowers #else 3527f9fbec18Smcpowers d = *pa; 3528f9fbec18Smcpowers sum = d + *pb++; 3529f9fbec18Smcpowers d = (sum < d); /* detect overflow */ 3530f9fbec18Smcpowers *pa++ = sum += carry; 3531f9fbec18Smcpowers carry = d + (sum < carry); /* detect overflow */ 3532f9fbec18Smcpowers #endif 3533f9fbec18Smcpowers } 3534f9fbec18Smcpowers 3535f9fbec18Smcpowers /* If we run out of 'b' digits before we're actually done, make 3536f9fbec18Smcpowers sure the carries get propagated upward... 3537f9fbec18Smcpowers */ 3538f9fbec18Smcpowers used = MP_USED(a); 3539f9fbec18Smcpowers #if !defined(MP_NO_MP_WORD) && !defined(MP_NO_ADD_WORD) 3540f9fbec18Smcpowers while (w && ix < used) { 3541f9fbec18Smcpowers w = w + *pa; 3542f9fbec18Smcpowers *pa++ = ACCUM(w); 3543f9fbec18Smcpowers w = CARRYOUT(w); 3544f9fbec18Smcpowers ++ix; 3545f9fbec18Smcpowers } 3546f9fbec18Smcpowers #else 3547f9fbec18Smcpowers while (carry && ix < used) { 3548f9fbec18Smcpowers sum = carry + *pa; 3549f9fbec18Smcpowers *pa++ = sum; 3550f9fbec18Smcpowers carry = !sum; 3551f9fbec18Smcpowers ++ix; 3552f9fbec18Smcpowers } 3553f9fbec18Smcpowers #endif 3554f9fbec18Smcpowers 3555f9fbec18Smcpowers /* If there's an overall carry out, increase precision and include 3556f9fbec18Smcpowers it. We could have done this initially, but why touch the memory 3557f9fbec18Smcpowers allocator unless we're sure we have to? 3558f9fbec18Smcpowers */ 3559f9fbec18Smcpowers #if !defined(MP_NO_MP_WORD) && !defined(MP_NO_ADD_WORD) 3560f9fbec18Smcpowers if (w) { 3561f9fbec18Smcpowers if((res = s_mp_pad(a, used + 1)) != MP_OKAY) 3562f9fbec18Smcpowers return res; 3563f9fbec18Smcpowers 3564f9fbec18Smcpowers DIGIT(a, ix) = (mp_digit)w; 3565f9fbec18Smcpowers } 3566f9fbec18Smcpowers #else 3567f9fbec18Smcpowers if (carry) { 3568f9fbec18Smcpowers if((res = s_mp_pad(a, used + 1)) != MP_OKAY) 3569f9fbec18Smcpowers return res; 3570f9fbec18Smcpowers 3571f9fbec18Smcpowers DIGIT(a, used) = carry; 3572f9fbec18Smcpowers } 3573f9fbec18Smcpowers #endif 3574f9fbec18Smcpowers 3575f9fbec18Smcpowers return MP_OKAY; 3576f9fbec18Smcpowers } /* end s_mp_add() */ 3577f9fbec18Smcpowers 3578f9fbec18Smcpowers /* }}} */ 3579f9fbec18Smcpowers 3580f9fbec18Smcpowers /* Compute c = |a| + |b| */ /* magnitude addition */ 3581f9fbec18Smcpowers mp_err s_mp_add_3arg(const mp_int *a, const mp_int *b, mp_int *c) 3582f9fbec18Smcpowers { 3583f9fbec18Smcpowers mp_digit *pa, *pb, *pc; 3584f9fbec18Smcpowers #if !defined(MP_NO_MP_WORD) && !defined(MP_NO_ADD_WORD) 3585f9fbec18Smcpowers mp_word w = 0; 3586f9fbec18Smcpowers #else 3587f9fbec18Smcpowers mp_digit sum, carry = 0, d; 3588f9fbec18Smcpowers #endif 3589f9fbec18Smcpowers mp_size ix; 3590f9fbec18Smcpowers mp_size used; 3591f9fbec18Smcpowers mp_err res; 3592f9fbec18Smcpowers 3593f9fbec18Smcpowers MP_SIGN(c) = MP_SIGN(a); 3594f9fbec18Smcpowers if (MP_USED(a) < MP_USED(b)) { 3595f9fbec18Smcpowers const mp_int *xch = a; 3596f9fbec18Smcpowers a = b; 3597f9fbec18Smcpowers b = xch; 3598f9fbec18Smcpowers } 3599f9fbec18Smcpowers 3600f9fbec18Smcpowers /* Make sure a has enough precision for the output value */ 3601f9fbec18Smcpowers if (MP_OKAY != (res = s_mp_pad(c, MP_USED(a)))) 3602f9fbec18Smcpowers return res; 3603f9fbec18Smcpowers 3604f9fbec18Smcpowers /* 3605f9fbec18Smcpowers Add up all digits up to the precision of b. If b had initially 3606f9fbec18Smcpowers the same precision as a, or greater, we took care of it by the 3607f9fbec18Smcpowers exchange step above, so there is no problem. If b had initially 3608f9fbec18Smcpowers less precision, we'll have to make sure the carry out is duly 3609f9fbec18Smcpowers propagated upward among the higher-order digits of the sum. 3610f9fbec18Smcpowers */ 3611f9fbec18Smcpowers pa = MP_DIGITS(a); 3612f9fbec18Smcpowers pb = MP_DIGITS(b); 3613f9fbec18Smcpowers pc = MP_DIGITS(c); 3614f9fbec18Smcpowers used = MP_USED(b); 3615f9fbec18Smcpowers for (ix = 0; ix < used; ix++) { 3616f9fbec18Smcpowers #if !defined(MP_NO_MP_WORD) && !defined(MP_NO_ADD_WORD) 3617f9fbec18Smcpowers w = w + *pa++ + *pb++; 3618f9fbec18Smcpowers *pc++ = ACCUM(w); 3619f9fbec18Smcpowers w = CARRYOUT(w); 3620f9fbec18Smcpowers #else 3621f9fbec18Smcpowers d = *pa++; 3622f9fbec18Smcpowers sum = d + *pb++; 3623f9fbec18Smcpowers d = (sum < d); /* detect overflow */ 3624f9fbec18Smcpowers *pc++ = sum += carry; 3625f9fbec18Smcpowers carry = d + (sum < carry); /* detect overflow */ 3626f9fbec18Smcpowers #endif 3627f9fbec18Smcpowers } 3628f9fbec18Smcpowers 3629f9fbec18Smcpowers /* If we run out of 'b' digits before we're actually done, make 3630f9fbec18Smcpowers sure the carries get propagated upward... 3631f9fbec18Smcpowers */ 3632f9fbec18Smcpowers for (used = MP_USED(a); ix < used; ++ix) { 3633f9fbec18Smcpowers #if !defined(MP_NO_MP_WORD) && !defined(MP_NO_ADD_WORD) 3634f9fbec18Smcpowers w = w + *pa++; 3635f9fbec18Smcpowers *pc++ = ACCUM(w); 3636f9fbec18Smcpowers w = CARRYOUT(w); 3637f9fbec18Smcpowers #else 3638f9fbec18Smcpowers *pc++ = sum = carry + *pa++; 3639f9fbec18Smcpowers carry = (sum < carry); 3640f9fbec18Smcpowers #endif 3641f9fbec18Smcpowers } 3642f9fbec18Smcpowers 3643f9fbec18Smcpowers /* If there's an overall carry out, increase precision and include 3644f9fbec18Smcpowers it. We could have done this initially, but why touch the memory 3645f9fbec18Smcpowers allocator unless we're sure we have to? 3646f9fbec18Smcpowers */ 3647f9fbec18Smcpowers #if !defined(MP_NO_MP_WORD) && !defined(MP_NO_ADD_WORD) 3648f9fbec18Smcpowers if (w) { 3649f9fbec18Smcpowers if((res = s_mp_pad(c, used + 1)) != MP_OKAY) 3650f9fbec18Smcpowers return res; 3651f9fbec18Smcpowers 3652f9fbec18Smcpowers DIGIT(c, used) = (mp_digit)w; 3653f9fbec18Smcpowers ++used; 3654f9fbec18Smcpowers } 3655f9fbec18Smcpowers #else 3656f9fbec18Smcpowers if (carry) { 3657f9fbec18Smcpowers if((res = s_mp_pad(c, used + 1)) != MP_OKAY) 3658f9fbec18Smcpowers return res; 3659f9fbec18Smcpowers 3660f9fbec18Smcpowers DIGIT(c, used) = carry; 3661f9fbec18Smcpowers ++used; 3662f9fbec18Smcpowers } 3663f9fbec18Smcpowers #endif 3664f9fbec18Smcpowers MP_USED(c) = used; 3665f9fbec18Smcpowers return MP_OKAY; 3666f9fbec18Smcpowers } 3667f9fbec18Smcpowers /* {{{ s_mp_add_offset(a, b, offset) */ 3668f9fbec18Smcpowers 3669f9fbec18Smcpowers /* Compute a = |a| + ( |b| * (RADIX ** offset) ) */ 3670f9fbec18Smcpowers mp_err s_mp_add_offset(mp_int *a, mp_int *b, mp_size offset) 3671f9fbec18Smcpowers { 3672f9fbec18Smcpowers #if !defined(MP_NO_MP_WORD) && !defined(MP_NO_ADD_WORD) 3673f9fbec18Smcpowers mp_word w, k = 0; 3674f9fbec18Smcpowers #else 3675f9fbec18Smcpowers mp_digit d, sum, carry = 0; 3676f9fbec18Smcpowers #endif 3677f9fbec18Smcpowers mp_size ib; 3678f9fbec18Smcpowers mp_size ia; 3679f9fbec18Smcpowers mp_size lim; 3680f9fbec18Smcpowers mp_err res; 3681f9fbec18Smcpowers 3682f9fbec18Smcpowers /* Make sure a has enough precision for the output value */ 3683f9fbec18Smcpowers lim = MP_USED(b) + offset; 3684f9fbec18Smcpowers if((lim > USED(a)) && (res = s_mp_pad(a, lim)) != MP_OKAY) 3685f9fbec18Smcpowers return res; 3686f9fbec18Smcpowers 3687f9fbec18Smcpowers /* 3688f9fbec18Smcpowers Add up all digits up to the precision of b. If b had initially 3689f9fbec18Smcpowers the same precision as a, or greater, we took care of it by the 3690f9fbec18Smcpowers padding step above, so there is no problem. If b had initially 3691f9fbec18Smcpowers less precision, we'll have to make sure the carry out is duly 3692f9fbec18Smcpowers propagated upward among the higher-order digits of the sum. 3693f9fbec18Smcpowers */ 3694f9fbec18Smcpowers lim = USED(b); 3695f9fbec18Smcpowers for(ib = 0, ia = offset; ib < lim; ib++, ia++) { 3696f9fbec18Smcpowers #if !defined(MP_NO_MP_WORD) && !defined(MP_NO_ADD_WORD) 3697f9fbec18Smcpowers w = (mp_word)DIGIT(a, ia) + DIGIT(b, ib) + k; 3698f9fbec18Smcpowers DIGIT(a, ia) = ACCUM(w); 3699f9fbec18Smcpowers k = CARRYOUT(w); 3700f9fbec18Smcpowers #else 3701f9fbec18Smcpowers d = MP_DIGIT(a, ia); 3702f9fbec18Smcpowers sum = d + MP_DIGIT(b, ib); 3703f9fbec18Smcpowers d = (sum < d); 3704f9fbec18Smcpowers MP_DIGIT(a,ia) = sum += carry; 3705f9fbec18Smcpowers carry = d + (sum < carry); 3706f9fbec18Smcpowers #endif 3707f9fbec18Smcpowers } 3708f9fbec18Smcpowers 3709f9fbec18Smcpowers /* If we run out of 'b' digits before we're actually done, make 3710f9fbec18Smcpowers sure the carries get propagated upward... 3711f9fbec18Smcpowers */ 3712f9fbec18Smcpowers #if !defined(MP_NO_MP_WORD) && !defined(MP_NO_ADD_WORD) 3713f9fbec18Smcpowers for (lim = MP_USED(a); k && (ia < lim); ++ia) { 3714f9fbec18Smcpowers w = (mp_word)DIGIT(a, ia) + k; 3715f9fbec18Smcpowers DIGIT(a, ia) = ACCUM(w); 3716f9fbec18Smcpowers k = CARRYOUT(w); 3717f9fbec18Smcpowers } 3718f9fbec18Smcpowers #else 3719f9fbec18Smcpowers for (lim = MP_USED(a); carry && (ia < lim); ++ia) { 3720f9fbec18Smcpowers d = MP_DIGIT(a, ia); 3721f9fbec18Smcpowers MP_DIGIT(a,ia) = sum = d + carry; 3722f9fbec18Smcpowers carry = (sum < d); 3723f9fbec18Smcpowers } 3724f9fbec18Smcpowers #endif 3725f9fbec18Smcpowers 3726f9fbec18Smcpowers /* If there's an overall carry out, increase precision and include 3727f9fbec18Smcpowers it. We could have done this initially, but why touch the memory 3728f9fbec18Smcpowers allocator unless we're sure we have to? 3729f9fbec18Smcpowers */ 3730f9fbec18Smcpowers #if !defined(MP_NO_MP_WORD) && !defined(MP_NO_ADD_WORD) 3731f9fbec18Smcpowers if(k) { 3732f9fbec18Smcpowers if((res = s_mp_pad(a, USED(a) + 1)) != MP_OKAY) 3733f9fbec18Smcpowers return res; 3734f9fbec18Smcpowers 3735f9fbec18Smcpowers DIGIT(a, ia) = (mp_digit)k; 3736f9fbec18Smcpowers } 3737f9fbec18Smcpowers #else 3738f9fbec18Smcpowers if (carry) { 3739f9fbec18Smcpowers if((res = s_mp_pad(a, lim + 1)) != MP_OKAY) 3740f9fbec18Smcpowers return res; 3741f9fbec18Smcpowers 3742f9fbec18Smcpowers DIGIT(a, lim) = carry; 3743f9fbec18Smcpowers } 3744f9fbec18Smcpowers #endif 3745f9fbec18Smcpowers s_mp_clamp(a); 3746f9fbec18Smcpowers 3747f9fbec18Smcpowers return MP_OKAY; 3748f9fbec18Smcpowers 3749f9fbec18Smcpowers } /* end s_mp_add_offset() */ 3750f9fbec18Smcpowers 3751f9fbec18Smcpowers /* }}} */ 3752f9fbec18Smcpowers 3753f9fbec18Smcpowers /* {{{ s_mp_sub(a, b) */ 3754f9fbec18Smcpowers 3755f9fbec18Smcpowers /* Compute a = |a| - |b|, assumes |a| >= |b| */ 3756f9fbec18Smcpowers mp_err s_mp_sub(mp_int *a, const mp_int *b) /* magnitude subtract */ 3757f9fbec18Smcpowers { 3758f9fbec18Smcpowers mp_digit *pa, *pb, *limit; 3759f9fbec18Smcpowers #if !defined(MP_NO_MP_WORD) && !defined(MP_NO_SUB_WORD) 3760f9fbec18Smcpowers mp_sword w = 0; 3761f9fbec18Smcpowers #else 3762f9fbec18Smcpowers mp_digit d, diff, borrow = 0; 3763f9fbec18Smcpowers #endif 3764f9fbec18Smcpowers 3765f9fbec18Smcpowers /* 3766f9fbec18Smcpowers Subtract and propagate borrow. Up to the precision of b, this 3767f9fbec18Smcpowers accounts for the digits of b; after that, we just make sure the 3768f9fbec18Smcpowers carries get to the right place. This saves having to pad b out to 3769f9fbec18Smcpowers the precision of a just to make the loops work right... 3770f9fbec18Smcpowers */ 3771f9fbec18Smcpowers pa = MP_DIGITS(a); 3772f9fbec18Smcpowers pb = MP_DIGITS(b); 3773f9fbec18Smcpowers limit = pb + MP_USED(b); 3774f9fbec18Smcpowers while (pb < limit) { 3775f9fbec18Smcpowers #if !defined(MP_NO_MP_WORD) && !defined(MP_NO_SUB_WORD) 3776f9fbec18Smcpowers w = w + *pa - *pb++; 3777f9fbec18Smcpowers *pa++ = ACCUM(w); 3778f9fbec18Smcpowers w >>= MP_DIGIT_BIT; 3779f9fbec18Smcpowers #else 3780f9fbec18Smcpowers d = *pa; 3781f9fbec18Smcpowers diff = d - *pb++; 3782f9fbec18Smcpowers d = (diff > d); /* detect borrow */ 3783f9fbec18Smcpowers if (borrow && --diff == MP_DIGIT_MAX) 3784f9fbec18Smcpowers ++d; 3785f9fbec18Smcpowers *pa++ = diff; 3786f9fbec18Smcpowers borrow = d; 3787f9fbec18Smcpowers #endif 3788f9fbec18Smcpowers } 3789f9fbec18Smcpowers limit = MP_DIGITS(a) + MP_USED(a); 3790f9fbec18Smcpowers #if !defined(MP_NO_MP_WORD) && !defined(MP_NO_SUB_WORD) 3791f9fbec18Smcpowers while (w && pa < limit) { 3792f9fbec18Smcpowers w = w + *pa; 3793f9fbec18Smcpowers *pa++ = ACCUM(w); 3794f9fbec18Smcpowers w >>= MP_DIGIT_BIT; 3795f9fbec18Smcpowers } 3796f9fbec18Smcpowers #else 3797f9fbec18Smcpowers while (borrow && pa < limit) { 3798f9fbec18Smcpowers d = *pa; 3799f9fbec18Smcpowers *pa++ = diff = d - borrow; 3800f9fbec18Smcpowers borrow = (diff > d); 3801f9fbec18Smcpowers } 3802f9fbec18Smcpowers #endif 3803f9fbec18Smcpowers 3804f9fbec18Smcpowers /* Clobber any leading zeroes we created */ 3805f9fbec18Smcpowers s_mp_clamp(a); 3806f9fbec18Smcpowers 3807f9fbec18Smcpowers /* 3808f9fbec18Smcpowers If there was a borrow out, then |b| > |a| in violation 3809f9fbec18Smcpowers of our input invariant. We've already done the work, 3810f9fbec18Smcpowers but we'll at least complain about it... 3811f9fbec18Smcpowers */ 3812f9fbec18Smcpowers #if !defined(MP_NO_MP_WORD) && !defined(MP_NO_SUB_WORD) 3813f9fbec18Smcpowers return w ? MP_RANGE : MP_OKAY; 3814f9fbec18Smcpowers #else 3815f9fbec18Smcpowers return borrow ? MP_RANGE : MP_OKAY; 3816f9fbec18Smcpowers #endif 3817f9fbec18Smcpowers } /* end s_mp_sub() */ 3818f9fbec18Smcpowers 3819f9fbec18Smcpowers /* }}} */ 3820f9fbec18Smcpowers 3821f9fbec18Smcpowers /* Compute c = |a| - |b|, assumes |a| >= |b| */ /* magnitude subtract */ 3822f9fbec18Smcpowers mp_err s_mp_sub_3arg(const mp_int *a, const mp_int *b, mp_int *c) 3823f9fbec18Smcpowers { 3824f9fbec18Smcpowers mp_digit *pa, *pb, *pc; 3825f9fbec18Smcpowers #if !defined(MP_NO_MP_WORD) && !defined(MP_NO_SUB_WORD) 3826f9fbec18Smcpowers mp_sword w = 0; 3827f9fbec18Smcpowers #else 3828f9fbec18Smcpowers mp_digit d, diff, borrow = 0; 3829f9fbec18Smcpowers #endif 3830f9fbec18Smcpowers int ix, limit; 3831f9fbec18Smcpowers mp_err res; 3832f9fbec18Smcpowers 3833f9fbec18Smcpowers MP_SIGN(c) = MP_SIGN(a); 3834f9fbec18Smcpowers 3835f9fbec18Smcpowers /* Make sure a has enough precision for the output value */ 3836f9fbec18Smcpowers if (MP_OKAY != (res = s_mp_pad(c, MP_USED(a)))) 3837f9fbec18Smcpowers return res; 3838f9fbec18Smcpowers 3839f9fbec18Smcpowers /* 3840f9fbec18Smcpowers Subtract and propagate borrow. Up to the precision of b, this 3841f9fbec18Smcpowers accounts for the digits of b; after that, we just make sure the 3842f9fbec18Smcpowers carries get to the right place. This saves having to pad b out to 3843f9fbec18Smcpowers the precision of a just to make the loops work right... 3844f9fbec18Smcpowers */ 3845f9fbec18Smcpowers pa = MP_DIGITS(a); 3846f9fbec18Smcpowers pb = MP_DIGITS(b); 3847f9fbec18Smcpowers pc = MP_DIGITS(c); 3848f9fbec18Smcpowers limit = MP_USED(b); 3849f9fbec18Smcpowers for (ix = 0; ix < limit; ++ix) { 3850f9fbec18Smcpowers #if !defined(MP_NO_MP_WORD) && !defined(MP_NO_SUB_WORD) 3851f9fbec18Smcpowers w = w + *pa++ - *pb++; 3852f9fbec18Smcpowers *pc++ = ACCUM(w); 3853f9fbec18Smcpowers w >>= MP_DIGIT_BIT; 3854f9fbec18Smcpowers #else 3855f9fbec18Smcpowers d = *pa++; 3856f9fbec18Smcpowers diff = d - *pb++; 3857f9fbec18Smcpowers d = (diff > d); 3858f9fbec18Smcpowers if (borrow && --diff == MP_DIGIT_MAX) 3859f9fbec18Smcpowers ++d; 3860f9fbec18Smcpowers *pc++ = diff; 3861f9fbec18Smcpowers borrow = d; 3862f9fbec18Smcpowers #endif 3863f9fbec18Smcpowers } 3864f9fbec18Smcpowers for (limit = MP_USED(a); ix < limit; ++ix) { 3865f9fbec18Smcpowers #if !defined(MP_NO_MP_WORD) && !defined(MP_NO_SUB_WORD) 3866f9fbec18Smcpowers w = w + *pa++; 3867f9fbec18Smcpowers *pc++ = ACCUM(w); 3868f9fbec18Smcpowers w >>= MP_DIGIT_BIT; 3869f9fbec18Smcpowers #else 3870f9fbec18Smcpowers d = *pa++; 3871f9fbec18Smcpowers *pc++ = diff = d - borrow; 3872f9fbec18Smcpowers borrow = (diff > d); 3873f9fbec18Smcpowers #endif 3874f9fbec18Smcpowers } 3875f9fbec18Smcpowers 3876f9fbec18Smcpowers /* Clobber any leading zeroes we created */ 3877f9fbec18Smcpowers MP_USED(c) = ix; 3878f9fbec18Smcpowers s_mp_clamp(c); 3879f9fbec18Smcpowers 3880f9fbec18Smcpowers /* 3881f9fbec18Smcpowers If there was a borrow out, then |b| > |a| in violation 3882f9fbec18Smcpowers of our input invariant. We've already done the work, 3883f9fbec18Smcpowers but we'll at least complain about it... 3884f9fbec18Smcpowers */ 3885f9fbec18Smcpowers #if !defined(MP_NO_MP_WORD) && !defined(MP_NO_SUB_WORD) 3886f9fbec18Smcpowers return w ? MP_RANGE : MP_OKAY; 3887f9fbec18Smcpowers #else 3888f9fbec18Smcpowers return borrow ? MP_RANGE : MP_OKAY; 3889f9fbec18Smcpowers #endif 3890f9fbec18Smcpowers } 3891f9fbec18Smcpowers /* {{{ s_mp_mul(a, b) */ 3892f9fbec18Smcpowers 3893f9fbec18Smcpowers /* Compute a = |a| * |b| */ 3894f9fbec18Smcpowers mp_err s_mp_mul(mp_int *a, const mp_int *b) 3895f9fbec18Smcpowers { 3896f9fbec18Smcpowers return mp_mul(a, b, a); 3897f9fbec18Smcpowers } /* end s_mp_mul() */ 3898f9fbec18Smcpowers 3899f9fbec18Smcpowers /* }}} */ 3900f9fbec18Smcpowers 3901f9fbec18Smcpowers #if defined(MP_USE_UINT_DIGIT) && defined(MP_USE_LONG_LONG_MULTIPLY) 3902f9fbec18Smcpowers /* This trick works on Sparc V8 CPUs with the Workshop compilers. */ 3903f9fbec18Smcpowers #define MP_MUL_DxD(a, b, Phi, Plo) \ 3904f9fbec18Smcpowers { unsigned long long product = (unsigned long long)a * b; \ 3905f9fbec18Smcpowers Plo = (mp_digit)product; \ 3906f9fbec18Smcpowers Phi = (mp_digit)(product >> MP_DIGIT_BIT); } 3907f9fbec18Smcpowers #elif defined(OSF1) 3908f9fbec18Smcpowers #define MP_MUL_DxD(a, b, Phi, Plo) \ 3909f9fbec18Smcpowers { Plo = asm ("mulq %a0, %a1, %v0", a, b);\ 3910f9fbec18Smcpowers Phi = asm ("umulh %a0, %a1, %v0", a, b); } 3911f9fbec18Smcpowers #else 3912f9fbec18Smcpowers #define MP_MUL_DxD(a, b, Phi, Plo) \ 3913f9fbec18Smcpowers { mp_digit a0b1, a1b0; \ 3914f9fbec18Smcpowers Plo = (a & MP_HALF_DIGIT_MAX) * (b & MP_HALF_DIGIT_MAX); \ 3915f9fbec18Smcpowers Phi = (a >> MP_HALF_DIGIT_BIT) * (b >> MP_HALF_DIGIT_BIT); \ 3916f9fbec18Smcpowers a0b1 = (a & MP_HALF_DIGIT_MAX) * (b >> MP_HALF_DIGIT_BIT); \ 3917f9fbec18Smcpowers a1b0 = (a >> MP_HALF_DIGIT_BIT) * (b & MP_HALF_DIGIT_MAX); \ 3918f9fbec18Smcpowers a1b0 += a0b1; \ 3919f9fbec18Smcpowers Phi += a1b0 >> MP_HALF_DIGIT_BIT; \ 3920f9fbec18Smcpowers if (a1b0 < a0b1) \ 3921f9fbec18Smcpowers Phi += MP_HALF_RADIX; \ 3922f9fbec18Smcpowers a1b0 <<= MP_HALF_DIGIT_BIT; \ 3923f9fbec18Smcpowers Plo += a1b0; \ 3924f9fbec18Smcpowers if (Plo < a1b0) \ 3925f9fbec18Smcpowers ++Phi; \ 3926f9fbec18Smcpowers } 3927f9fbec18Smcpowers #endif 3928f9fbec18Smcpowers 3929f9fbec18Smcpowers #if !defined(MP_ASSEMBLY_MULTIPLY) 3930f9fbec18Smcpowers /* c = a * b */ 3931f9fbec18Smcpowers void s_mpv_mul_d(const mp_digit *a, mp_size a_len, mp_digit b, mp_digit *c) 3932f9fbec18Smcpowers { 3933f9fbec18Smcpowers #if !defined(MP_NO_MP_WORD) && !defined(MP_NO_MUL_WORD) 3934f9fbec18Smcpowers mp_digit d = 0; 3935f9fbec18Smcpowers 3936f9fbec18Smcpowers /* Inner product: Digits of a */ 3937f9fbec18Smcpowers while (a_len--) { 3938f9fbec18Smcpowers mp_word w = ((mp_word)b * *a++) + d; 3939f9fbec18Smcpowers *c++ = ACCUM(w); 3940f9fbec18Smcpowers d = CARRYOUT(w); 3941f9fbec18Smcpowers } 3942f9fbec18Smcpowers *c = d; 3943f9fbec18Smcpowers #else 3944f9fbec18Smcpowers mp_digit carry = 0; 3945f9fbec18Smcpowers while (a_len--) { 3946f9fbec18Smcpowers mp_digit a_i = *a++; 3947f9fbec18Smcpowers mp_digit a0b0, a1b1; 3948f9fbec18Smcpowers 3949f9fbec18Smcpowers MP_MUL_DxD(a_i, b, a1b1, a0b0); 3950f9fbec18Smcpowers 3951f9fbec18Smcpowers a0b0 += carry; 3952f9fbec18Smcpowers if (a0b0 < carry) 3953f9fbec18Smcpowers ++a1b1; 3954f9fbec18Smcpowers *c++ = a0b0; 3955f9fbec18Smcpowers carry = a1b1; 3956f9fbec18Smcpowers } 3957f9fbec18Smcpowers *c = carry; 3958f9fbec18Smcpowers #endif 3959f9fbec18Smcpowers } 3960f9fbec18Smcpowers 3961f9fbec18Smcpowers /* c += a * b */ 3962f9fbec18Smcpowers void s_mpv_mul_d_add(const mp_digit *a, mp_size a_len, mp_digit b, 3963f9fbec18Smcpowers mp_digit *c) 3964f9fbec18Smcpowers { 3965f9fbec18Smcpowers #if !defined(MP_NO_MP_WORD) && !defined(MP_NO_MUL_WORD) 3966f9fbec18Smcpowers mp_digit d = 0; 3967f9fbec18Smcpowers 3968f9fbec18Smcpowers /* Inner product: Digits of a */ 3969f9fbec18Smcpowers while (a_len--) { 3970f9fbec18Smcpowers mp_word w = ((mp_word)b * *a++) + *c + d; 3971f9fbec18Smcpowers *c++ = ACCUM(w); 3972f9fbec18Smcpowers d = CARRYOUT(w); 3973f9fbec18Smcpowers } 3974f9fbec18Smcpowers *c = d; 3975f9fbec18Smcpowers #else 3976f9fbec18Smcpowers mp_digit carry = 0; 3977f9fbec18Smcpowers while (a_len--) { 3978f9fbec18Smcpowers mp_digit a_i = *a++; 3979f9fbec18Smcpowers mp_digit a0b0, a1b1; 3980f9fbec18Smcpowers 3981f9fbec18Smcpowers MP_MUL_DxD(a_i, b, a1b1, a0b0); 3982f9fbec18Smcpowers 3983f9fbec18Smcpowers a0b0 += carry; 3984f9fbec18Smcpowers if (a0b0 < carry) 3985f9fbec18Smcpowers ++a1b1; 3986f9fbec18Smcpowers a0b0 += a_i = *c; 3987f9fbec18Smcpowers if (a0b0 < a_i) 3988f9fbec18Smcpowers ++a1b1; 3989f9fbec18Smcpowers *c++ = a0b0; 3990f9fbec18Smcpowers carry = a1b1; 3991f9fbec18Smcpowers } 3992f9fbec18Smcpowers *c = carry; 3993f9fbec18Smcpowers #endif 3994f9fbec18Smcpowers } 3995f9fbec18Smcpowers 3996f9fbec18Smcpowers /* Presently, this is only used by the Montgomery arithmetic code. */ 3997f9fbec18Smcpowers /* c += a * b */ 3998f9fbec18Smcpowers void s_mpv_mul_d_add_prop(const mp_digit *a, mp_size a_len, mp_digit b, mp_digit *c) 3999f9fbec18Smcpowers { 4000f9fbec18Smcpowers #if !defined(MP_NO_MP_WORD) && !defined(MP_NO_MUL_WORD) 4001f9fbec18Smcpowers mp_digit d = 0; 4002f9fbec18Smcpowers 4003f9fbec18Smcpowers /* Inner product: Digits of a */ 4004f9fbec18Smcpowers while (a_len--) { 4005f9fbec18Smcpowers mp_word w = ((mp_word)b * *a++) + *c + d; 4006f9fbec18Smcpowers *c++ = ACCUM(w); 4007f9fbec18Smcpowers d = CARRYOUT(w); 4008f9fbec18Smcpowers } 4009f9fbec18Smcpowers 4010f9fbec18Smcpowers while (d) { 4011f9fbec18Smcpowers mp_word w = (mp_word)*c + d; 4012f9fbec18Smcpowers *c++ = ACCUM(w); 4013f9fbec18Smcpowers d = CARRYOUT(w); 4014f9fbec18Smcpowers } 4015f9fbec18Smcpowers #else 4016f9fbec18Smcpowers mp_digit carry = 0; 4017f9fbec18Smcpowers while (a_len--) { 4018f9fbec18Smcpowers mp_digit a_i = *a++; 4019f9fbec18Smcpowers mp_digit a0b0, a1b1; 4020f9fbec18Smcpowers 4021f9fbec18Smcpowers MP_MUL_DxD(a_i, b, a1b1, a0b0); 4022f9fbec18Smcpowers 4023f9fbec18Smcpowers a0b0 += carry; 4024f9fbec18Smcpowers if (a0b0 < carry) 4025f9fbec18Smcpowers ++a1b1; 4026f9fbec18Smcpowers 4027f9fbec18Smcpowers a0b0 += a_i = *c; 4028f9fbec18Smcpowers if (a0b0 < a_i) 4029f9fbec18Smcpowers ++a1b1; 4030f9fbec18Smcpowers 4031f9fbec18Smcpowers *c++ = a0b0; 4032f9fbec18Smcpowers carry = a1b1; 4033f9fbec18Smcpowers } 4034f9fbec18Smcpowers while (carry) { 4035f9fbec18Smcpowers mp_digit c_i = *c; 4036f9fbec18Smcpowers carry += c_i; 4037f9fbec18Smcpowers *c++ = carry; 4038f9fbec18Smcpowers carry = carry < c_i; 4039f9fbec18Smcpowers } 4040f9fbec18Smcpowers #endif 4041f9fbec18Smcpowers } 4042f9fbec18Smcpowers #endif 4043f9fbec18Smcpowers 4044f9fbec18Smcpowers #if defined(MP_USE_UINT_DIGIT) && defined(MP_USE_LONG_LONG_MULTIPLY) 4045f9fbec18Smcpowers /* This trick works on Sparc V8 CPUs with the Workshop compilers. */ 4046f9fbec18Smcpowers #define MP_SQR_D(a, Phi, Plo) \ 4047f9fbec18Smcpowers { unsigned long long square = (unsigned long long)a * a; \ 4048f9fbec18Smcpowers Plo = (mp_digit)square; \ 4049f9fbec18Smcpowers Phi = (mp_digit)(square >> MP_DIGIT_BIT); } 4050f9fbec18Smcpowers #elif defined(OSF1) 4051f9fbec18Smcpowers #define MP_SQR_D(a, Phi, Plo) \ 4052f9fbec18Smcpowers { Plo = asm ("mulq %a0, %a0, %v0", a);\ 4053f9fbec18Smcpowers Phi = asm ("umulh %a0, %a0, %v0", a); } 4054f9fbec18Smcpowers #else 4055f9fbec18Smcpowers #define MP_SQR_D(a, Phi, Plo) \ 4056f9fbec18Smcpowers { mp_digit Pmid; \ 4057f9fbec18Smcpowers Plo = (a & MP_HALF_DIGIT_MAX) * (a & MP_HALF_DIGIT_MAX); \ 4058f9fbec18Smcpowers Phi = (a >> MP_HALF_DIGIT_BIT) * (a >> MP_HALF_DIGIT_BIT); \ 4059f9fbec18Smcpowers Pmid = (a & MP_HALF_DIGIT_MAX) * (a >> MP_HALF_DIGIT_BIT); \ 4060f9fbec18Smcpowers Phi += Pmid >> (MP_HALF_DIGIT_BIT - 1); \ 4061f9fbec18Smcpowers Pmid <<= (MP_HALF_DIGIT_BIT + 1); \ 4062f9fbec18Smcpowers Plo += Pmid; \ 4063f9fbec18Smcpowers if (Plo < Pmid) \ 4064f9fbec18Smcpowers ++Phi; \ 4065f9fbec18Smcpowers } 4066f9fbec18Smcpowers #endif 4067f9fbec18Smcpowers 4068f9fbec18Smcpowers #if !defined(MP_ASSEMBLY_SQUARE) 4069f9fbec18Smcpowers /* Add the squares of the digits of a to the digits of b. */ 4070f9fbec18Smcpowers void s_mpv_sqr_add_prop(const mp_digit *pa, mp_size a_len, mp_digit *ps) 4071f9fbec18Smcpowers { 4072f9fbec18Smcpowers #if !defined(MP_NO_MP_WORD) && !defined(MP_NO_MUL_WORD) 4073f9fbec18Smcpowers mp_word w; 4074f9fbec18Smcpowers mp_digit d; 4075f9fbec18Smcpowers mp_size ix; 4076f9fbec18Smcpowers 4077f9fbec18Smcpowers w = 0; 4078f9fbec18Smcpowers #define ADD_SQUARE(n) \ 4079f9fbec18Smcpowers d = pa[n]; \ 4080f9fbec18Smcpowers w += (d * (mp_word)d) + ps[2*n]; \ 4081f9fbec18Smcpowers ps[2*n] = ACCUM(w); \ 4082f9fbec18Smcpowers w = (w >> DIGIT_BIT) + ps[2*n+1]; \ 4083f9fbec18Smcpowers ps[2*n+1] = ACCUM(w); \ 4084f9fbec18Smcpowers w = (w >> DIGIT_BIT) 4085f9fbec18Smcpowers 4086f9fbec18Smcpowers for (ix = a_len; ix >= 4; ix -= 4) { 4087f9fbec18Smcpowers ADD_SQUARE(0); 4088f9fbec18Smcpowers ADD_SQUARE(1); 4089f9fbec18Smcpowers ADD_SQUARE(2); 4090f9fbec18Smcpowers ADD_SQUARE(3); 4091f9fbec18Smcpowers pa += 4; 4092f9fbec18Smcpowers ps += 8; 4093f9fbec18Smcpowers } 4094f9fbec18Smcpowers if (ix) { 4095f9fbec18Smcpowers ps += 2*ix; 4096f9fbec18Smcpowers pa += ix; 4097f9fbec18Smcpowers switch (ix) { 4098f9fbec18Smcpowers case 3: ADD_SQUARE(-3); /* FALLTHRU */ 4099f9fbec18Smcpowers case 2: ADD_SQUARE(-2); /* FALLTHRU */ 4100f9fbec18Smcpowers case 1: ADD_SQUARE(-1); /* FALLTHRU */ 4101f9fbec18Smcpowers case 0: break; 4102f9fbec18Smcpowers } 4103f9fbec18Smcpowers } 4104f9fbec18Smcpowers while (w) { 4105f9fbec18Smcpowers w += *ps; 4106f9fbec18Smcpowers *ps++ = ACCUM(w); 4107f9fbec18Smcpowers w = (w >> DIGIT_BIT); 4108f9fbec18Smcpowers } 4109f9fbec18Smcpowers #else 4110f9fbec18Smcpowers mp_digit carry = 0; 4111f9fbec18Smcpowers while (a_len--) { 4112f9fbec18Smcpowers mp_digit a_i = *pa++; 4113f9fbec18Smcpowers mp_digit a0a0, a1a1; 4114f9fbec18Smcpowers 4115f9fbec18Smcpowers MP_SQR_D(a_i, a1a1, a0a0); 4116f9fbec18Smcpowers 4117f9fbec18Smcpowers /* here a1a1 and a0a0 constitute a_i ** 2 */ 4118f9fbec18Smcpowers a0a0 += carry; 4119f9fbec18Smcpowers if (a0a0 < carry) 4120f9fbec18Smcpowers ++a1a1; 4121f9fbec18Smcpowers 4122f9fbec18Smcpowers /* now add to ps */ 4123f9fbec18Smcpowers a0a0 += a_i = *ps; 4124f9fbec18Smcpowers if (a0a0 < a_i) 4125f9fbec18Smcpowers ++a1a1; 4126f9fbec18Smcpowers *ps++ = a0a0; 4127f9fbec18Smcpowers a1a1 += a_i = *ps; 4128f9fbec18Smcpowers carry = (a1a1 < a_i); 4129f9fbec18Smcpowers *ps++ = a1a1; 4130f9fbec18Smcpowers } 4131f9fbec18Smcpowers while (carry) { 4132f9fbec18Smcpowers mp_digit s_i = *ps; 4133f9fbec18Smcpowers carry += s_i; 4134f9fbec18Smcpowers *ps++ = carry; 4135f9fbec18Smcpowers carry = carry < s_i; 4136f9fbec18Smcpowers } 4137f9fbec18Smcpowers #endif 4138f9fbec18Smcpowers } 4139f9fbec18Smcpowers #endif 4140f9fbec18Smcpowers 4141f9fbec18Smcpowers #if (defined(MP_NO_MP_WORD) || defined(MP_NO_DIV_WORD)) \ 4142f9fbec18Smcpowers && !defined(MP_ASSEMBLY_DIV_2DX1D) 4143f9fbec18Smcpowers /* 4144f9fbec18Smcpowers ** Divide 64-bit (Nhi,Nlo) by 32-bit divisor, which must be normalized 4145f9fbec18Smcpowers ** so its high bit is 1. This code is from NSPR. 4146f9fbec18Smcpowers */ 4147f9fbec18Smcpowers mp_err s_mpv_div_2dx1d(mp_digit Nhi, mp_digit Nlo, mp_digit divisor, 4148f9fbec18Smcpowers mp_digit *qp, mp_digit *rp) 4149f9fbec18Smcpowers { 4150f9fbec18Smcpowers mp_digit d1, d0, q1, q0; 4151f9fbec18Smcpowers mp_digit r1, r0, m; 4152f9fbec18Smcpowers 4153f9fbec18Smcpowers d1 = divisor >> MP_HALF_DIGIT_BIT; 4154f9fbec18Smcpowers d0 = divisor & MP_HALF_DIGIT_MAX; 4155f9fbec18Smcpowers r1 = Nhi % d1; 4156f9fbec18Smcpowers q1 = Nhi / d1; 4157f9fbec18Smcpowers m = q1 * d0; 4158f9fbec18Smcpowers r1 = (r1 << MP_HALF_DIGIT_BIT) | (Nlo >> MP_HALF_DIGIT_BIT); 4159f9fbec18Smcpowers if (r1 < m) { 4160f9fbec18Smcpowers q1--, r1 += divisor; 4161f9fbec18Smcpowers if (r1 >= divisor && r1 < m) { 4162f9fbec18Smcpowers q1--, r1 += divisor; 4163f9fbec18Smcpowers } 4164f9fbec18Smcpowers } 4165f9fbec18Smcpowers r1 -= m; 4166f9fbec18Smcpowers r0 = r1 % d1; 4167f9fbec18Smcpowers q0 = r1 / d1; 4168f9fbec18Smcpowers m = q0 * d0; 4169f9fbec18Smcpowers r0 = (r0 << MP_HALF_DIGIT_BIT) | (Nlo & MP_HALF_DIGIT_MAX); 4170f9fbec18Smcpowers if (r0 < m) { 4171f9fbec18Smcpowers q0--, r0 += divisor; 4172f9fbec18Smcpowers if (r0 >= divisor && r0 < m) { 4173f9fbec18Smcpowers q0--, r0 += divisor; 4174f9fbec18Smcpowers } 4175f9fbec18Smcpowers } 4176f9fbec18Smcpowers if (qp) 4177f9fbec18Smcpowers *qp = (q1 << MP_HALF_DIGIT_BIT) | q0; 4178f9fbec18Smcpowers if (rp) 4179f9fbec18Smcpowers *rp = r0 - m; 4180f9fbec18Smcpowers return MP_OKAY; 4181f9fbec18Smcpowers } 4182f9fbec18Smcpowers #endif 4183f9fbec18Smcpowers 4184f9fbec18Smcpowers #if MP_SQUARE 4185f9fbec18Smcpowers /* {{{ s_mp_sqr(a) */ 4186f9fbec18Smcpowers 4187f9fbec18Smcpowers mp_err s_mp_sqr(mp_int *a) 4188f9fbec18Smcpowers { 4189f9fbec18Smcpowers mp_err res; 4190f9fbec18Smcpowers mp_int tmp; 4191f9fbec18Smcpowers 4192f9fbec18Smcpowers if((res = mp_init_size(&tmp, 2 * USED(a), FLAG(a))) != MP_OKAY) 4193f9fbec18Smcpowers return res; 4194f9fbec18Smcpowers res = mp_sqr(a, &tmp); 4195f9fbec18Smcpowers if (res == MP_OKAY) { 4196f9fbec18Smcpowers s_mp_exch(&tmp, a); 4197f9fbec18Smcpowers } 4198f9fbec18Smcpowers mp_clear(&tmp); 4199f9fbec18Smcpowers return res; 4200f9fbec18Smcpowers } 4201f9fbec18Smcpowers 4202f9fbec18Smcpowers /* }}} */ 4203f9fbec18Smcpowers #endif 4204f9fbec18Smcpowers 4205f9fbec18Smcpowers /* {{{ s_mp_div(a, b) */ 4206f9fbec18Smcpowers 4207f9fbec18Smcpowers /* 4208f9fbec18Smcpowers s_mp_div(a, b) 4209f9fbec18Smcpowers 4210f9fbec18Smcpowers Compute a = a / b and b = a mod b. Assumes b > a. 4211f9fbec18Smcpowers */ 4212f9fbec18Smcpowers 4213f9fbec18Smcpowers mp_err s_mp_div(mp_int *rem, /* i: dividend, o: remainder */ 4214f9fbec18Smcpowers mp_int *div, /* i: divisor */ 4215f9fbec18Smcpowers mp_int *quot) /* i: 0; o: quotient */ 4216f9fbec18Smcpowers { 4217f9fbec18Smcpowers mp_int part, t; 4218f9fbec18Smcpowers #if !defined(MP_NO_MP_WORD) && !defined(MP_NO_DIV_WORD) 4219f9fbec18Smcpowers mp_word q_msd; 4220f9fbec18Smcpowers #else 4221f9fbec18Smcpowers mp_digit q_msd; 4222f9fbec18Smcpowers #endif 4223f9fbec18Smcpowers mp_err res; 4224f9fbec18Smcpowers mp_digit d; 4225f9fbec18Smcpowers mp_digit div_msd; 4226f9fbec18Smcpowers int ix; 4227f9fbec18Smcpowers 4228f9fbec18Smcpowers if(mp_cmp_z(div) == 0) 4229f9fbec18Smcpowers return MP_RANGE; 4230f9fbec18Smcpowers 4231f9fbec18Smcpowers /* Shortcut if divisor is power of two */ 4232f9fbec18Smcpowers if((ix = s_mp_ispow2(div)) >= 0) { 4233f9fbec18Smcpowers MP_CHECKOK( mp_copy(rem, quot) ); 4234f9fbec18Smcpowers s_mp_div_2d(quot, (mp_digit)ix); 4235f9fbec18Smcpowers s_mp_mod_2d(rem, (mp_digit)ix); 4236f9fbec18Smcpowers 4237f9fbec18Smcpowers return MP_OKAY; 4238f9fbec18Smcpowers } 4239f9fbec18Smcpowers 4240f9fbec18Smcpowers DIGITS(&t) = 0; 4241f9fbec18Smcpowers MP_SIGN(rem) = ZPOS; 4242f9fbec18Smcpowers MP_SIGN(div) = ZPOS; 4243f9fbec18Smcpowers 4244f9fbec18Smcpowers /* A working temporary for division */ 4245f9fbec18Smcpowers MP_CHECKOK( mp_init_size(&t, MP_ALLOC(rem), FLAG(rem))); 4246f9fbec18Smcpowers 4247f9fbec18Smcpowers /* Normalize to optimize guessing */ 4248f9fbec18Smcpowers MP_CHECKOK( s_mp_norm(rem, div, &d) ); 4249f9fbec18Smcpowers 4250f9fbec18Smcpowers part = *rem; 4251f9fbec18Smcpowers 4252f9fbec18Smcpowers /* Perform the division itself...woo! */ 4253f9fbec18Smcpowers MP_USED(quot) = MP_ALLOC(quot); 4254f9fbec18Smcpowers 4255f9fbec18Smcpowers /* Find a partial substring of rem which is at least div */ 4256f9fbec18Smcpowers /* If we didn't find one, we're finished dividing */ 4257f9fbec18Smcpowers while (MP_USED(rem) > MP_USED(div) || s_mp_cmp(rem, div) >= 0) { 4258f9fbec18Smcpowers int i; 4259f9fbec18Smcpowers int unusedRem; 4260f9fbec18Smcpowers 4261f9fbec18Smcpowers unusedRem = MP_USED(rem) - MP_USED(div); 4262f9fbec18Smcpowers MP_DIGITS(&part) = MP_DIGITS(rem) + unusedRem; 4263f9fbec18Smcpowers MP_ALLOC(&part) = MP_ALLOC(rem) - unusedRem; 4264f9fbec18Smcpowers MP_USED(&part) = MP_USED(div); 4265f9fbec18Smcpowers if (s_mp_cmp(&part, div) < 0) { 4266f9fbec18Smcpowers -- unusedRem; 4267f9fbec18Smcpowers #if MP_ARGCHK == 2 4268f9fbec18Smcpowers assert(unusedRem >= 0); 4269f9fbec18Smcpowers #endif 4270f9fbec18Smcpowers -- MP_DIGITS(&part); 4271f9fbec18Smcpowers ++ MP_USED(&part); 4272f9fbec18Smcpowers ++ MP_ALLOC(&part); 4273f9fbec18Smcpowers } 4274f9fbec18Smcpowers 4275f9fbec18Smcpowers /* Compute a guess for the next quotient digit */ 4276f9fbec18Smcpowers q_msd = MP_DIGIT(&part, MP_USED(&part) - 1); 4277f9fbec18Smcpowers div_msd = MP_DIGIT(div, MP_USED(div) - 1); 4278f9fbec18Smcpowers if (q_msd >= div_msd) { 4279f9fbec18Smcpowers q_msd = 1; 4280f9fbec18Smcpowers } else if (MP_USED(&part) > 1) { 4281f9fbec18Smcpowers #if !defined(MP_NO_MP_WORD) && !defined(MP_NO_DIV_WORD) 4282f9fbec18Smcpowers q_msd = (q_msd << MP_DIGIT_BIT) | MP_DIGIT(&part, MP_USED(&part) - 2); 4283f9fbec18Smcpowers q_msd /= div_msd; 4284f9fbec18Smcpowers if (q_msd == RADIX) 4285f9fbec18Smcpowers --q_msd; 4286f9fbec18Smcpowers #else 4287f9fbec18Smcpowers mp_digit r; 4288f9fbec18Smcpowers MP_CHECKOK( s_mpv_div_2dx1d(q_msd, MP_DIGIT(&part, MP_USED(&part) - 2), 4289f9fbec18Smcpowers div_msd, &q_msd, &r) ); 4290f9fbec18Smcpowers #endif 4291f9fbec18Smcpowers } else { 4292f9fbec18Smcpowers q_msd = 0; 4293f9fbec18Smcpowers } 4294f9fbec18Smcpowers #if MP_ARGCHK == 2 4295f9fbec18Smcpowers assert(q_msd > 0); /* This case should never occur any more. */ 4296f9fbec18Smcpowers #endif 4297f9fbec18Smcpowers if (q_msd <= 0) 4298f9fbec18Smcpowers break; 4299f9fbec18Smcpowers 4300f9fbec18Smcpowers /* See what that multiplies out to */ 4301f9fbec18Smcpowers mp_copy(div, &t); 4302f9fbec18Smcpowers MP_CHECKOK( s_mp_mul_d(&t, (mp_digit)q_msd) ); 4303f9fbec18Smcpowers 4304f9fbec18Smcpowers /* 4305f9fbec18Smcpowers If it's too big, back it off. We should not have to do this 4306f9fbec18Smcpowers more than once, or, in rare cases, twice. Knuth describes a 4307f9fbec18Smcpowers method by which this could be reduced to a maximum of once, but 4308f9fbec18Smcpowers I didn't implement that here. 4309f9fbec18Smcpowers * When using s_mpv_div_2dx1d, we may have to do this 3 times. 4310f9fbec18Smcpowers */ 4311f9fbec18Smcpowers for (i = 4; s_mp_cmp(&t, &part) > 0 && i > 0; --i) { 4312f9fbec18Smcpowers --q_msd; 4313f9fbec18Smcpowers s_mp_sub(&t, div); /* t -= div */ 4314f9fbec18Smcpowers } 4315f9fbec18Smcpowers if (i < 0) { 4316f9fbec18Smcpowers res = MP_RANGE; 4317f9fbec18Smcpowers goto CLEANUP; 4318f9fbec18Smcpowers } 4319f9fbec18Smcpowers 4320f9fbec18Smcpowers /* At this point, q_msd should be the right next digit */ 4321f9fbec18Smcpowers MP_CHECKOK( s_mp_sub(&part, &t) ); /* part -= t */ 4322f9fbec18Smcpowers s_mp_clamp(rem); 4323f9fbec18Smcpowers 4324f9fbec18Smcpowers /* 4325f9fbec18Smcpowers Include the digit in the quotient. We allocated enough memory 4326f9fbec18Smcpowers for any quotient we could ever possibly get, so we should not 4327f9fbec18Smcpowers have to check for failures here 4328f9fbec18Smcpowers */ 4329f9fbec18Smcpowers MP_DIGIT(quot, unusedRem) = (mp_digit)q_msd; 4330f9fbec18Smcpowers } 4331f9fbec18Smcpowers 4332f9fbec18Smcpowers /* Denormalize remainder */ 4333f9fbec18Smcpowers if (d) { 4334f9fbec18Smcpowers s_mp_div_2d(rem, d); 4335f9fbec18Smcpowers } 4336f9fbec18Smcpowers 4337f9fbec18Smcpowers s_mp_clamp(quot); 4338f9fbec18Smcpowers 4339f9fbec18Smcpowers CLEANUP: 4340f9fbec18Smcpowers mp_clear(&t); 4341f9fbec18Smcpowers 4342f9fbec18Smcpowers return res; 4343f9fbec18Smcpowers 4344f9fbec18Smcpowers } /* end s_mp_div() */ 4345f9fbec18Smcpowers 4346f9fbec18Smcpowers 4347f9fbec18Smcpowers /* }}} */ 4348f9fbec18Smcpowers 4349f9fbec18Smcpowers /* {{{ s_mp_2expt(a, k) */ 4350f9fbec18Smcpowers 4351f9fbec18Smcpowers mp_err s_mp_2expt(mp_int *a, mp_digit k) 4352f9fbec18Smcpowers { 4353f9fbec18Smcpowers mp_err res; 4354f9fbec18Smcpowers mp_size dig, bit; 4355f9fbec18Smcpowers 4356f9fbec18Smcpowers dig = k / DIGIT_BIT; 4357f9fbec18Smcpowers bit = k % DIGIT_BIT; 4358f9fbec18Smcpowers 4359f9fbec18Smcpowers mp_zero(a); 4360f9fbec18Smcpowers if((res = s_mp_pad(a, dig + 1)) != MP_OKAY) 4361f9fbec18Smcpowers return res; 4362f9fbec18Smcpowers 4363f9fbec18Smcpowers DIGIT(a, dig) |= ((mp_digit)1 << bit); 4364f9fbec18Smcpowers 4365f9fbec18Smcpowers return MP_OKAY; 4366f9fbec18Smcpowers 4367f9fbec18Smcpowers } /* end s_mp_2expt() */ 4368f9fbec18Smcpowers 4369f9fbec18Smcpowers /* }}} */ 4370f9fbec18Smcpowers 4371f9fbec18Smcpowers /* {{{ s_mp_reduce(x, m, mu) */ 4372f9fbec18Smcpowers 4373f9fbec18Smcpowers /* 4374f9fbec18Smcpowers Compute Barrett reduction, x (mod m), given a precomputed value for 4375f9fbec18Smcpowers mu = b^2k / m, where b = RADIX and k = #digits(m). This should be 4376f9fbec18Smcpowers faster than straight division, when many reductions by the same 4377f9fbec18Smcpowers value of m are required (such as in modular exponentiation). This 4378f9fbec18Smcpowers can nearly halve the time required to do modular exponentiation, 4379f9fbec18Smcpowers as compared to using the full integer divide to reduce. 4380f9fbec18Smcpowers 4381f9fbec18Smcpowers This algorithm was derived from the _Handbook of Applied 4382f9fbec18Smcpowers Cryptography_ by Menezes, Oorschot and VanStone, Ch. 14, 4383f9fbec18Smcpowers pp. 603-604. 4384f9fbec18Smcpowers */ 4385f9fbec18Smcpowers 4386f9fbec18Smcpowers mp_err s_mp_reduce(mp_int *x, const mp_int *m, const mp_int *mu) 4387f9fbec18Smcpowers { 4388f9fbec18Smcpowers mp_int q; 4389f9fbec18Smcpowers mp_err res; 4390f9fbec18Smcpowers 4391f9fbec18Smcpowers if((res = mp_init_copy(&q, x)) != MP_OKAY) 4392f9fbec18Smcpowers return res; 4393f9fbec18Smcpowers 4394f9fbec18Smcpowers s_mp_rshd(&q, USED(m) - 1); /* q1 = x / b^(k-1) */ 4395f9fbec18Smcpowers s_mp_mul(&q, mu); /* q2 = q1 * mu */ 4396f9fbec18Smcpowers s_mp_rshd(&q, USED(m) + 1); /* q3 = q2 / b^(k+1) */ 4397f9fbec18Smcpowers 4398f9fbec18Smcpowers /* x = x mod b^(k+1), quick (no division) */ 4399f9fbec18Smcpowers s_mp_mod_2d(x, DIGIT_BIT * (USED(m) + 1)); 4400f9fbec18Smcpowers 4401f9fbec18Smcpowers /* q = q * m mod b^(k+1), quick (no division) */ 4402f9fbec18Smcpowers s_mp_mul(&q, m); 4403f9fbec18Smcpowers s_mp_mod_2d(&q, DIGIT_BIT * (USED(m) + 1)); 4404f9fbec18Smcpowers 4405f9fbec18Smcpowers /* x = x - q */ 4406f9fbec18Smcpowers if((res = mp_sub(x, &q, x)) != MP_OKAY) 4407f9fbec18Smcpowers goto CLEANUP; 4408f9fbec18Smcpowers 4409f9fbec18Smcpowers /* If x < 0, add b^(k+1) to it */ 4410f9fbec18Smcpowers if(mp_cmp_z(x) < 0) { 4411f9fbec18Smcpowers mp_set(&q, 1); 4412f9fbec18Smcpowers if((res = s_mp_lshd(&q, USED(m) + 1)) != MP_OKAY) 4413f9fbec18Smcpowers goto CLEANUP; 4414f9fbec18Smcpowers if((res = mp_add(x, &q, x)) != MP_OKAY) 4415f9fbec18Smcpowers goto CLEANUP; 4416f9fbec18Smcpowers } 4417f9fbec18Smcpowers 4418f9fbec18Smcpowers /* Back off if it's too big */ 4419f9fbec18Smcpowers while(mp_cmp(x, m) >= 0) { 4420f9fbec18Smcpowers if((res = s_mp_sub(x, m)) != MP_OKAY) 4421f9fbec18Smcpowers break; 4422f9fbec18Smcpowers } 4423f9fbec18Smcpowers 4424f9fbec18Smcpowers CLEANUP: 4425f9fbec18Smcpowers mp_clear(&q); 4426f9fbec18Smcpowers 4427f9fbec18Smcpowers return res; 4428f9fbec18Smcpowers 4429f9fbec18Smcpowers } /* end s_mp_reduce() */ 4430f9fbec18Smcpowers 4431f9fbec18Smcpowers /* }}} */ 4432f9fbec18Smcpowers 4433f9fbec18Smcpowers /* }}} */ 4434f9fbec18Smcpowers 4435f9fbec18Smcpowers /* {{{ Primitive comparisons */ 4436f9fbec18Smcpowers 4437f9fbec18Smcpowers /* {{{ s_mp_cmp(a, b) */ 4438f9fbec18Smcpowers 4439f9fbec18Smcpowers /* Compare |a| <=> |b|, return 0 if equal, <0 if a<b, >0 if a>b */ 4440f9fbec18Smcpowers int s_mp_cmp(const mp_int *a, const mp_int *b) 4441f9fbec18Smcpowers { 4442f9fbec18Smcpowers mp_size used_a = MP_USED(a); 4443f9fbec18Smcpowers { 4444f9fbec18Smcpowers mp_size used_b = MP_USED(b); 4445f9fbec18Smcpowers 4446f9fbec18Smcpowers if (used_a > used_b) 4447f9fbec18Smcpowers goto IS_GT; 4448f9fbec18Smcpowers if (used_a < used_b) 4449f9fbec18Smcpowers goto IS_LT; 4450f9fbec18Smcpowers } 4451f9fbec18Smcpowers { 4452f9fbec18Smcpowers mp_digit *pa, *pb; 4453f9fbec18Smcpowers mp_digit da = 0, db = 0; 4454f9fbec18Smcpowers 4455f9fbec18Smcpowers #define CMP_AB(n) if ((da = pa[n]) != (db = pb[n])) goto done 4456f9fbec18Smcpowers 4457f9fbec18Smcpowers pa = MP_DIGITS(a) + used_a; 4458f9fbec18Smcpowers pb = MP_DIGITS(b) + used_a; 4459f9fbec18Smcpowers while (used_a >= 4) { 4460f9fbec18Smcpowers pa -= 4; 4461f9fbec18Smcpowers pb -= 4; 4462f9fbec18Smcpowers used_a -= 4; 4463f9fbec18Smcpowers CMP_AB(3); 4464f9fbec18Smcpowers CMP_AB(2); 4465f9fbec18Smcpowers CMP_AB(1); 4466f9fbec18Smcpowers CMP_AB(0); 4467f9fbec18Smcpowers } 4468f9fbec18Smcpowers while (used_a-- > 0 && ((da = *--pa) == (db = *--pb))) 4469f9fbec18Smcpowers /* do nothing */; 4470f9fbec18Smcpowers done: 4471f9fbec18Smcpowers if (da > db) 4472f9fbec18Smcpowers goto IS_GT; 4473f9fbec18Smcpowers if (da < db) 4474f9fbec18Smcpowers goto IS_LT; 4475f9fbec18Smcpowers } 4476f9fbec18Smcpowers return MP_EQ; 4477f9fbec18Smcpowers IS_LT: 4478f9fbec18Smcpowers return MP_LT; 4479f9fbec18Smcpowers IS_GT: 4480f9fbec18Smcpowers return MP_GT; 4481f9fbec18Smcpowers } /* end s_mp_cmp() */ 4482f9fbec18Smcpowers 4483f9fbec18Smcpowers /* }}} */ 4484f9fbec18Smcpowers 4485f9fbec18Smcpowers /* {{{ s_mp_cmp_d(a, d) */ 4486f9fbec18Smcpowers 4487f9fbec18Smcpowers /* Compare |a| <=> d, return 0 if equal, <0 if a<d, >0 if a>d */ 4488f9fbec18Smcpowers int s_mp_cmp_d(const mp_int *a, mp_digit d) 4489f9fbec18Smcpowers { 4490f9fbec18Smcpowers if(USED(a) > 1) 4491f9fbec18Smcpowers return MP_GT; 4492f9fbec18Smcpowers 4493f9fbec18Smcpowers if(DIGIT(a, 0) < d) 4494f9fbec18Smcpowers return MP_LT; 4495f9fbec18Smcpowers else if(DIGIT(a, 0) > d) 4496f9fbec18Smcpowers return MP_GT; 4497f9fbec18Smcpowers else 4498f9fbec18Smcpowers return MP_EQ; 4499f9fbec18Smcpowers 4500f9fbec18Smcpowers } /* end s_mp_cmp_d() */ 4501f9fbec18Smcpowers 4502f9fbec18Smcpowers /* }}} */ 4503f9fbec18Smcpowers 4504f9fbec18Smcpowers /* {{{ s_mp_ispow2(v) */ 4505f9fbec18Smcpowers 4506f9fbec18Smcpowers /* 4507f9fbec18Smcpowers Returns -1 if the value is not a power of two; otherwise, it returns 4508f9fbec18Smcpowers k such that v = 2^k, i.e. lg(v). 4509f9fbec18Smcpowers */ 4510f9fbec18Smcpowers int s_mp_ispow2(const mp_int *v) 4511f9fbec18Smcpowers { 4512f9fbec18Smcpowers mp_digit d; 4513f9fbec18Smcpowers int extra = 0, ix; 4514f9fbec18Smcpowers 4515f9fbec18Smcpowers ix = MP_USED(v) - 1; 4516f9fbec18Smcpowers d = MP_DIGIT(v, ix); /* most significant digit of v */ 4517f9fbec18Smcpowers 4518f9fbec18Smcpowers extra = s_mp_ispow2d(d); 4519f9fbec18Smcpowers if (extra < 0 || ix == 0) 4520f9fbec18Smcpowers return extra; 4521f9fbec18Smcpowers 4522f9fbec18Smcpowers while (--ix >= 0) { 4523f9fbec18Smcpowers if (DIGIT(v, ix) != 0) 4524f9fbec18Smcpowers return -1; /* not a power of two */ 4525f9fbec18Smcpowers extra += MP_DIGIT_BIT; 4526f9fbec18Smcpowers } 4527f9fbec18Smcpowers 4528f9fbec18Smcpowers return extra; 4529f9fbec18Smcpowers 4530f9fbec18Smcpowers } /* end s_mp_ispow2() */ 4531f9fbec18Smcpowers 4532f9fbec18Smcpowers /* }}} */ 4533f9fbec18Smcpowers 4534f9fbec18Smcpowers /* {{{ s_mp_ispow2d(d) */ 4535f9fbec18Smcpowers 4536f9fbec18Smcpowers int s_mp_ispow2d(mp_digit d) 4537f9fbec18Smcpowers { 4538f9fbec18Smcpowers if ((d != 0) && ((d & (d-1)) == 0)) { /* d is a power of 2 */ 4539f9fbec18Smcpowers int pow = 0; 4540f9fbec18Smcpowers #if defined (MP_USE_UINT_DIGIT) 4541f9fbec18Smcpowers if (d & 0xffff0000U) 4542f9fbec18Smcpowers pow += 16; 4543f9fbec18Smcpowers if (d & 0xff00ff00U) 4544f9fbec18Smcpowers pow += 8; 4545f9fbec18Smcpowers if (d & 0xf0f0f0f0U) 4546f9fbec18Smcpowers pow += 4; 4547f9fbec18Smcpowers if (d & 0xccccccccU) 4548f9fbec18Smcpowers pow += 2; 4549f9fbec18Smcpowers if (d & 0xaaaaaaaaU) 4550f9fbec18Smcpowers pow += 1; 4551f9fbec18Smcpowers #elif defined(MP_USE_LONG_LONG_DIGIT) 4552f9fbec18Smcpowers if (d & 0xffffffff00000000ULL) 4553f9fbec18Smcpowers pow += 32; 4554f9fbec18Smcpowers if (d & 0xffff0000ffff0000ULL) 4555f9fbec18Smcpowers pow += 16; 4556f9fbec18Smcpowers if (d & 0xff00ff00ff00ff00ULL) 4557f9fbec18Smcpowers pow += 8; 4558f9fbec18Smcpowers if (d & 0xf0f0f0f0f0f0f0f0ULL) 4559f9fbec18Smcpowers pow += 4; 4560f9fbec18Smcpowers if (d & 0xccccccccccccccccULL) 4561f9fbec18Smcpowers pow += 2; 4562f9fbec18Smcpowers if (d & 0xaaaaaaaaaaaaaaaaULL) 4563f9fbec18Smcpowers pow += 1; 4564f9fbec18Smcpowers #elif defined(MP_USE_LONG_DIGIT) 4565f9fbec18Smcpowers if (d & 0xffffffff00000000UL) 4566f9fbec18Smcpowers pow += 32; 4567f9fbec18Smcpowers if (d & 0xffff0000ffff0000UL) 4568f9fbec18Smcpowers pow += 16; 4569f9fbec18Smcpowers if (d & 0xff00ff00ff00ff00UL) 4570f9fbec18Smcpowers pow += 8; 4571f9fbec18Smcpowers if (d & 0xf0f0f0f0f0f0f0f0UL) 4572f9fbec18Smcpowers pow += 4; 4573f9fbec18Smcpowers if (d & 0xccccccccccccccccUL) 4574f9fbec18Smcpowers pow += 2; 4575f9fbec18Smcpowers if (d & 0xaaaaaaaaaaaaaaaaUL) 4576f9fbec18Smcpowers pow += 1; 4577f9fbec18Smcpowers #else 4578f9fbec18Smcpowers #error "unknown type for mp_digit" 4579f9fbec18Smcpowers #endif 4580f9fbec18Smcpowers return pow; 4581f9fbec18Smcpowers } 4582f9fbec18Smcpowers return -1; 4583f9fbec18Smcpowers 4584f9fbec18Smcpowers } /* end s_mp_ispow2d() */ 4585f9fbec18Smcpowers 4586f9fbec18Smcpowers /* }}} */ 4587f9fbec18Smcpowers 4588f9fbec18Smcpowers /* }}} */ 4589f9fbec18Smcpowers 4590f9fbec18Smcpowers /* {{{ Primitive I/O helpers */ 4591f9fbec18Smcpowers 4592f9fbec18Smcpowers /* {{{ s_mp_tovalue(ch, r) */ 4593f9fbec18Smcpowers 4594f9fbec18Smcpowers /* 4595f9fbec18Smcpowers Convert the given character to its digit value, in the given radix. 4596f9fbec18Smcpowers If the given character is not understood in the given radix, -1 is 4597f9fbec18Smcpowers returned. Otherwise the digit's numeric value is returned. 4598f9fbec18Smcpowers 4599f9fbec18Smcpowers The results will be odd if you use a radix < 2 or > 62, you are 4600f9fbec18Smcpowers expected to know what you're up to. 4601f9fbec18Smcpowers */ 4602f9fbec18Smcpowers int s_mp_tovalue(char ch, int r) 4603f9fbec18Smcpowers { 4604f9fbec18Smcpowers int val, xch; 4605f9fbec18Smcpowers 4606f9fbec18Smcpowers if(r > 36) 4607f9fbec18Smcpowers xch = ch; 4608f9fbec18Smcpowers else 4609f9fbec18Smcpowers xch = toupper(ch); 4610f9fbec18Smcpowers 4611f9fbec18Smcpowers if(isdigit(xch)) 4612f9fbec18Smcpowers val = xch - '0'; 4613f9fbec18Smcpowers else if(isupper(xch)) 4614f9fbec18Smcpowers val = xch - 'A' + 10; 4615f9fbec18Smcpowers else if(islower(xch)) 4616f9fbec18Smcpowers val = xch - 'a' + 36; 4617f9fbec18Smcpowers else if(xch == '+') 4618f9fbec18Smcpowers val = 62; 4619f9fbec18Smcpowers else if(xch == '/') 4620f9fbec18Smcpowers val = 63; 4621f9fbec18Smcpowers else 4622f9fbec18Smcpowers return -1; 4623f9fbec18Smcpowers 4624f9fbec18Smcpowers if(val < 0 || val >= r) 4625f9fbec18Smcpowers return -1; 4626f9fbec18Smcpowers 4627f9fbec18Smcpowers return val; 4628f9fbec18Smcpowers 4629f9fbec18Smcpowers } /* end s_mp_tovalue() */ 4630f9fbec18Smcpowers 4631f9fbec18Smcpowers /* }}} */ 4632f9fbec18Smcpowers 4633f9fbec18Smcpowers /* {{{ s_mp_todigit(val, r, low) */ 4634f9fbec18Smcpowers 4635f9fbec18Smcpowers /* 4636f9fbec18Smcpowers Convert val to a radix-r digit, if possible. If val is out of range 4637f9fbec18Smcpowers for r, returns zero. Otherwise, returns an ASCII character denoting 4638f9fbec18Smcpowers the value in the given radix. 4639f9fbec18Smcpowers 4640f9fbec18Smcpowers The results may be odd if you use a radix < 2 or > 64, you are 4641f9fbec18Smcpowers expected to know what you're doing. 4642f9fbec18Smcpowers */ 4643f9fbec18Smcpowers 4644f9fbec18Smcpowers char s_mp_todigit(mp_digit val, int r, int low) 4645f9fbec18Smcpowers { 4646f9fbec18Smcpowers char ch; 4647f9fbec18Smcpowers 4648f9fbec18Smcpowers if(val >= r) 4649f9fbec18Smcpowers return 0; 4650f9fbec18Smcpowers 4651f9fbec18Smcpowers ch = s_dmap_1[val]; 4652f9fbec18Smcpowers 4653f9fbec18Smcpowers if(r <= 36 && low) 4654f9fbec18Smcpowers ch = tolower(ch); 4655f9fbec18Smcpowers 4656f9fbec18Smcpowers return ch; 4657f9fbec18Smcpowers 4658f9fbec18Smcpowers } /* end s_mp_todigit() */ 4659f9fbec18Smcpowers 4660f9fbec18Smcpowers /* }}} */ 4661f9fbec18Smcpowers 4662f9fbec18Smcpowers /* {{{ s_mp_outlen(bits, radix) */ 4663f9fbec18Smcpowers 4664f9fbec18Smcpowers /* 4665f9fbec18Smcpowers Return an estimate for how long a string is needed to hold a radix 4666f9fbec18Smcpowers r representation of a number with 'bits' significant bits, plus an 4667f9fbec18Smcpowers extra for a zero terminator (assuming C style strings here) 4668f9fbec18Smcpowers */ 4669f9fbec18Smcpowers int s_mp_outlen(int bits, int r) 4670f9fbec18Smcpowers { 4671f9fbec18Smcpowers return (int)((double)bits * LOG_V_2(r) + 1.5) + 1; 4672f9fbec18Smcpowers 4673f9fbec18Smcpowers } /* end s_mp_outlen() */ 4674f9fbec18Smcpowers 4675f9fbec18Smcpowers /* }}} */ 4676f9fbec18Smcpowers 4677f9fbec18Smcpowers /* }}} */ 4678f9fbec18Smcpowers 4679f9fbec18Smcpowers /* {{{ mp_read_unsigned_octets(mp, str, len) */ 4680f9fbec18Smcpowers /* mp_read_unsigned_octets(mp, str, len) 4681f9fbec18Smcpowers Read in a raw value (base 256) into the given mp_int 4682f9fbec18Smcpowers No sign bit, number is positive. Leading zeros ignored. 4683f9fbec18Smcpowers */ 4684f9fbec18Smcpowers 4685f9fbec18Smcpowers mp_err 4686f9fbec18Smcpowers mp_read_unsigned_octets(mp_int *mp, const unsigned char *str, mp_size len) 4687f9fbec18Smcpowers { 4688f9fbec18Smcpowers int count; 4689f9fbec18Smcpowers mp_err res; 4690f9fbec18Smcpowers mp_digit d; 4691f9fbec18Smcpowers 4692f9fbec18Smcpowers ARGCHK(mp != NULL && str != NULL && len > 0, MP_BADARG); 4693f9fbec18Smcpowers 4694f9fbec18Smcpowers mp_zero(mp); 4695f9fbec18Smcpowers 4696f9fbec18Smcpowers count = len % sizeof(mp_digit); 4697f9fbec18Smcpowers if (count) { 4698f9fbec18Smcpowers for (d = 0; count-- > 0; --len) { 4699f9fbec18Smcpowers d = (d << 8) | *str++; 4700f9fbec18Smcpowers } 4701f9fbec18Smcpowers MP_DIGIT(mp, 0) = d; 4702f9fbec18Smcpowers } 4703f9fbec18Smcpowers 4704f9fbec18Smcpowers /* Read the rest of the digits */ 4705f9fbec18Smcpowers for(; len > 0; len -= sizeof(mp_digit)) { 4706f9fbec18Smcpowers for (d = 0, count = sizeof(mp_digit); count > 0; --count) { 4707f9fbec18Smcpowers d = (d << 8) | *str++; 4708f9fbec18Smcpowers } 4709f9fbec18Smcpowers if (MP_EQ == mp_cmp_z(mp)) { 4710f9fbec18Smcpowers if (!d) 4711f9fbec18Smcpowers continue; 4712f9fbec18Smcpowers } else { 4713f9fbec18Smcpowers if((res = s_mp_lshd(mp, 1)) != MP_OKAY) 4714f9fbec18Smcpowers return res; 4715f9fbec18Smcpowers } 4716f9fbec18Smcpowers MP_DIGIT(mp, 0) = d; 4717f9fbec18Smcpowers } 4718f9fbec18Smcpowers return MP_OKAY; 4719f9fbec18Smcpowers } /* end mp_read_unsigned_octets() */ 4720f9fbec18Smcpowers /* }}} */ 4721f9fbec18Smcpowers 4722f9fbec18Smcpowers /* {{{ mp_unsigned_octet_size(mp) */ 4723f9fbec18Smcpowers int 4724f9fbec18Smcpowers mp_unsigned_octet_size(const mp_int *mp) 4725f9fbec18Smcpowers { 4726f9fbec18Smcpowers int bytes; 4727f9fbec18Smcpowers int ix; 4728f9fbec18Smcpowers mp_digit d = 0; 4729f9fbec18Smcpowers 4730f9fbec18Smcpowers ARGCHK(mp != NULL, MP_BADARG); 4731f9fbec18Smcpowers ARGCHK(MP_ZPOS == SIGN(mp), MP_BADARG); 4732f9fbec18Smcpowers 4733f9fbec18Smcpowers bytes = (USED(mp) * sizeof(mp_digit)); 4734f9fbec18Smcpowers 4735f9fbec18Smcpowers /* subtract leading zeros. */ 4736f9fbec18Smcpowers /* Iterate over each digit... */ 4737f9fbec18Smcpowers for(ix = USED(mp) - 1; ix >= 0; ix--) { 4738f9fbec18Smcpowers d = DIGIT(mp, ix); 4739f9fbec18Smcpowers if (d) 4740f9fbec18Smcpowers break; 4741f9fbec18Smcpowers bytes -= sizeof(d); 4742f9fbec18Smcpowers } 4743f9fbec18Smcpowers if (!bytes) 4744f9fbec18Smcpowers return 1; 4745f9fbec18Smcpowers 4746f9fbec18Smcpowers /* Have MSD, check digit bytes, high order first */ 4747f9fbec18Smcpowers for(ix = sizeof(mp_digit) - 1; ix >= 0; ix--) { 4748f9fbec18Smcpowers unsigned char x = (unsigned char)(d >> (ix * CHAR_BIT)); 4749f9fbec18Smcpowers if (x) 4750f9fbec18Smcpowers break; 4751f9fbec18Smcpowers --bytes; 4752f9fbec18Smcpowers } 4753f9fbec18Smcpowers return bytes; 4754f9fbec18Smcpowers } /* end mp_unsigned_octet_size() */ 4755f9fbec18Smcpowers /* }}} */ 4756f9fbec18Smcpowers 4757f9fbec18Smcpowers /* {{{ mp_to_unsigned_octets(mp, str) */ 4758f9fbec18Smcpowers /* output a buffer of big endian octets no longer than specified. */ 4759f9fbec18Smcpowers mp_err 4760f9fbec18Smcpowers mp_to_unsigned_octets(const mp_int *mp, unsigned char *str, mp_size maxlen) 4761f9fbec18Smcpowers { 4762f9fbec18Smcpowers int ix, pos = 0; 4763f9fbec18Smcpowers int bytes; 4764f9fbec18Smcpowers 4765f9fbec18Smcpowers ARGCHK(mp != NULL && str != NULL && !SIGN(mp), MP_BADARG); 4766f9fbec18Smcpowers 4767f9fbec18Smcpowers bytes = mp_unsigned_octet_size(mp); 4768f9fbec18Smcpowers ARGCHK(bytes <= maxlen, MP_BADARG); 4769f9fbec18Smcpowers 4770f9fbec18Smcpowers /* Iterate over each digit... */ 4771f9fbec18Smcpowers for(ix = USED(mp) - 1; ix >= 0; ix--) { 4772f9fbec18Smcpowers mp_digit d = DIGIT(mp, ix); 4773f9fbec18Smcpowers int jx; 4774f9fbec18Smcpowers 4775f9fbec18Smcpowers /* Unpack digit bytes, high order first */ 4776f9fbec18Smcpowers for(jx = sizeof(mp_digit) - 1; jx >= 0; jx--) { 4777f9fbec18Smcpowers unsigned char x = (unsigned char)(d >> (jx * CHAR_BIT)); 4778f9fbec18Smcpowers if (!pos && !x) /* suppress leading zeros */ 4779f9fbec18Smcpowers continue; 4780f9fbec18Smcpowers str[pos++] = x; 4781f9fbec18Smcpowers } 4782f9fbec18Smcpowers } 4783f9fbec18Smcpowers if (!pos) 4784f9fbec18Smcpowers str[pos++] = 0; 4785f9fbec18Smcpowers return pos; 4786f9fbec18Smcpowers } /* end mp_to_unsigned_octets() */ 4787f9fbec18Smcpowers /* }}} */ 4788f9fbec18Smcpowers 4789f9fbec18Smcpowers /* {{{ mp_to_signed_octets(mp, str) */ 4790f9fbec18Smcpowers /* output a buffer of big endian octets no longer than specified. */ 4791f9fbec18Smcpowers mp_err 4792f9fbec18Smcpowers mp_to_signed_octets(const mp_int *mp, unsigned char *str, mp_size maxlen) 4793f9fbec18Smcpowers { 4794f9fbec18Smcpowers int ix, pos = 0; 4795f9fbec18Smcpowers int bytes; 4796f9fbec18Smcpowers 4797f9fbec18Smcpowers ARGCHK(mp != NULL && str != NULL && !SIGN(mp), MP_BADARG); 4798f9fbec18Smcpowers 4799f9fbec18Smcpowers bytes = mp_unsigned_octet_size(mp); 4800f9fbec18Smcpowers ARGCHK(bytes <= maxlen, MP_BADARG); 4801f9fbec18Smcpowers 4802f9fbec18Smcpowers /* Iterate over each digit... */ 4803f9fbec18Smcpowers for(ix = USED(mp) - 1; ix >= 0; ix--) { 4804f9fbec18Smcpowers mp_digit d = DIGIT(mp, ix); 4805f9fbec18Smcpowers int jx; 4806f9fbec18Smcpowers 4807f9fbec18Smcpowers /* Unpack digit bytes, high order first */ 4808f9fbec18Smcpowers for(jx = sizeof(mp_digit) - 1; jx >= 0; jx--) { 4809f9fbec18Smcpowers unsigned char x = (unsigned char)(d >> (jx * CHAR_BIT)); 4810f9fbec18Smcpowers if (!pos) { 4811f9fbec18Smcpowers if (!x) /* suppress leading zeros */ 4812f9fbec18Smcpowers continue; 4813f9fbec18Smcpowers if (x & 0x80) { /* add one leading zero to make output positive. */ 4814f9fbec18Smcpowers ARGCHK(bytes + 1 <= maxlen, MP_BADARG); 4815f9fbec18Smcpowers if (bytes + 1 > maxlen) 4816f9fbec18Smcpowers return MP_BADARG; 4817f9fbec18Smcpowers str[pos++] = 0; 4818f9fbec18Smcpowers } 4819f9fbec18Smcpowers } 4820f9fbec18Smcpowers str[pos++] = x; 4821f9fbec18Smcpowers } 4822f9fbec18Smcpowers } 4823f9fbec18Smcpowers if (!pos) 4824f9fbec18Smcpowers str[pos++] = 0; 4825f9fbec18Smcpowers return pos; 4826f9fbec18Smcpowers } /* end mp_to_signed_octets() */ 4827f9fbec18Smcpowers /* }}} */ 4828f9fbec18Smcpowers 4829f9fbec18Smcpowers /* {{{ mp_to_fixlen_octets(mp, str) */ 4830f9fbec18Smcpowers /* output a buffer of big endian octets exactly as long as requested. */ 4831f9fbec18Smcpowers mp_err 4832f9fbec18Smcpowers mp_to_fixlen_octets(const mp_int *mp, unsigned char *str, mp_size length) 4833f9fbec18Smcpowers { 4834f9fbec18Smcpowers int ix, pos = 0; 4835f9fbec18Smcpowers int bytes; 4836f9fbec18Smcpowers 4837f9fbec18Smcpowers ARGCHK(mp != NULL && str != NULL && !SIGN(mp), MP_BADARG); 4838f9fbec18Smcpowers 4839f9fbec18Smcpowers bytes = mp_unsigned_octet_size(mp); 4840f9fbec18Smcpowers ARGCHK(bytes <= length, MP_BADARG); 4841f9fbec18Smcpowers 4842f9fbec18Smcpowers /* place any needed leading zeros */ 4843f9fbec18Smcpowers for (;length > bytes; --length) { 4844f9fbec18Smcpowers *str++ = 0; 4845f9fbec18Smcpowers } 4846f9fbec18Smcpowers 4847f9fbec18Smcpowers /* Iterate over each digit... */ 4848f9fbec18Smcpowers for(ix = USED(mp) - 1; ix >= 0; ix--) { 4849f9fbec18Smcpowers mp_digit d = DIGIT(mp, ix); 4850f9fbec18Smcpowers int jx; 4851f9fbec18Smcpowers 4852f9fbec18Smcpowers /* Unpack digit bytes, high order first */ 4853f9fbec18Smcpowers for(jx = sizeof(mp_digit) - 1; jx >= 0; jx--) { 4854f9fbec18Smcpowers unsigned char x = (unsigned char)(d >> (jx * CHAR_BIT)); 4855f9fbec18Smcpowers if (!pos && !x) /* suppress leading zeros */ 4856f9fbec18Smcpowers continue; 4857f9fbec18Smcpowers str[pos++] = x; 4858f9fbec18Smcpowers } 4859f9fbec18Smcpowers } 4860f9fbec18Smcpowers if (!pos) 4861f9fbec18Smcpowers str[pos++] = 0; 4862f9fbec18Smcpowers return MP_OKAY; 4863f9fbec18Smcpowers } /* end mp_to_fixlen_octets() */ 4864f9fbec18Smcpowers /* }}} */ 4865f9fbec18Smcpowers 4866f9fbec18Smcpowers 4867f9fbec18Smcpowers /*------------------------------------------------------------------------*/ 4868f9fbec18Smcpowers /* HERE THERE BE DRAGONS */ 4869*f2ba9e96SDina K Nimeh /* END CSTYLED */ 4870