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